mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-10-31 15:23:00 +00:00 
			
		
		
		
	Return ViewBinding instead of View in BaseListFragment's getListHeader() and getListFooter() methods.
This commit is contained in:
		| @@ -12,13 +12,16 @@ import android.view.MenuInflater; | |||||||
| import android.view.View; | import android.view.View; | ||||||
|  |  | ||||||
| import androidx.annotation.NonNull; | import androidx.annotation.NonNull; | ||||||
|  | import androidx.annotation.Nullable; | ||||||
| import androidx.appcompat.app.ActionBar; | import androidx.appcompat.app.ActionBar; | ||||||
| import androidx.appcompat.app.AppCompatActivity; | import androidx.appcompat.app.AppCompatActivity; | ||||||
| import androidx.preference.PreferenceManager; | import androidx.preference.PreferenceManager; | ||||||
| import androidx.recyclerview.widget.GridLayoutManager; | import androidx.recyclerview.widget.GridLayoutManager; | ||||||
| import androidx.recyclerview.widget.RecyclerView; | import androidx.recyclerview.widget.RecyclerView; | ||||||
|  | import androidx.viewbinding.ViewBinding; | ||||||
|  |  | ||||||
| import org.schabi.newpipe.R; | import org.schabi.newpipe.R; | ||||||
|  | import org.schabi.newpipe.databinding.PignateFooterBinding; | ||||||
| import org.schabi.newpipe.extractor.InfoItem; | import org.schabi.newpipe.extractor.InfoItem; | ||||||
| import org.schabi.newpipe.extractor.channel.ChannelInfoItem; | import org.schabi.newpipe.extractor.channel.ChannelInfoItem; | ||||||
| import org.schabi.newpipe.extractor.comments.CommentsInfoItem; | import org.schabi.newpipe.extractor.comments.CommentsInfoItem; | ||||||
| @@ -215,12 +218,13 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> | |||||||
|     // Init |     // Init | ||||||
|     //////////////////////////////////////////////////////////////////////////*/ |     //////////////////////////////////////////////////////////////////////////*/ | ||||||
|  |  | ||||||
|     protected View getListHeader() { |     @Nullable | ||||||
|  |     protected ViewBinding getListHeader() { | ||||||
|         return null; |         return null; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     protected View getListFooter() { |     protected ViewBinding getListFooter() { | ||||||
|         return activity.getLayoutInflater().inflate(R.layout.pignate_footer, itemsList, false); |         return PignateFooterBinding.inflate(activity.getLayoutInflater(), itemsList, false); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     protected RecyclerView.LayoutManager getListLayoutManager() { |     protected RecyclerView.LayoutManager getListLayoutManager() { | ||||||
| @@ -247,8 +251,12 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> | |||||||
|         itemsList.setLayoutManager(useGrid ? getGridLayoutManager() : getListLayoutManager()); |         itemsList.setLayoutManager(useGrid ? getGridLayoutManager() : getListLayoutManager()); | ||||||
|  |  | ||||||
|         infoListAdapter.setUseGridVariant(useGrid); |         infoListAdapter.setUseGridVariant(useGrid); | ||||||
|         infoListAdapter.setFooter(getListFooter()); |         infoListAdapter.setFooter(getListFooter().getRoot()); | ||||||
|         infoListAdapter.setHeader(getListHeader()); |  | ||||||
|  |         final ViewBinding listHeader = getListHeader(); | ||||||
|  |         if (listHeader != null) { | ||||||
|  |             infoListAdapter.setHeader(listHeader.getRoot()); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         itemsList.setAdapter(infoListAdapter); |         itemsList.setAdapter(infoListAdapter); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -14,8 +14,6 @@ import android.view.MenuItem; | |||||||
| import android.view.View; | import android.view.View; | ||||||
| import android.view.ViewGroup; | import android.view.ViewGroup; | ||||||
| import android.widget.Button; | import android.widget.Button; | ||||||
| import android.widget.ImageView; |  | ||||||
| import android.widget.LinearLayout; |  | ||||||
| import android.widget.TextView; | import android.widget.TextView; | ||||||
|  |  | ||||||
| import androidx.annotation.NonNull; | import androidx.annotation.NonNull; | ||||||
| @@ -23,11 +21,14 @@ import androidx.annotation.Nullable; | |||||||
| import androidx.appcompat.app.ActionBar; | import androidx.appcompat.app.ActionBar; | ||||||
| import androidx.appcompat.app.AppCompatActivity; | import androidx.appcompat.app.AppCompatActivity; | ||||||
| import androidx.core.content.ContextCompat; | import androidx.core.content.ContextCompat; | ||||||
|  | import androidx.viewbinding.ViewBinding; | ||||||
|  |  | ||||||
| import com.jakewharton.rxbinding4.view.RxView; | import com.jakewharton.rxbinding4.view.RxView; | ||||||
|  |  | ||||||
| import org.schabi.newpipe.R; | import org.schabi.newpipe.R; | ||||||
| import org.schabi.newpipe.database.subscription.SubscriptionEntity; | import org.schabi.newpipe.database.subscription.SubscriptionEntity; | ||||||
|  | import org.schabi.newpipe.databinding.ChannelHeaderBinding; | ||||||
|  | import org.schabi.newpipe.databinding.PlaylistControlBinding; | ||||||
| import org.schabi.newpipe.extractor.InfoItem; | import org.schabi.newpipe.extractor.InfoItem; | ||||||
| import org.schabi.newpipe.extractor.ListExtractor; | import org.schabi.newpipe.extractor.ListExtractor; | ||||||
| import org.schabi.newpipe.extractor.NewPipe; | import org.schabi.newpipe.extractor.NewPipe; | ||||||
| @@ -78,18 +79,10 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> | |||||||
|     //////////////////////////////////////////////////////////////////////////*/ |     //////////////////////////////////////////////////////////////////////////*/ | ||||||
|  |  | ||||||
|     private SubscriptionManager subscriptionManager; |     private SubscriptionManager subscriptionManager; | ||||||
|     private View headerRootLayout; |  | ||||||
|     private ImageView headerChannelBanner; |     private ChannelHeaderBinding headerBinding; | ||||||
|     private ImageView headerAvatarView; |     private PlaylistControlBinding playlistControlBinding; | ||||||
|     private TextView headerTitleView; |  | ||||||
|     private ImageView headerSubChannelAvatarView; |  | ||||||
|     private TextView headerSubChannelTitleView; |  | ||||||
|     private TextView headerSubscribersTextView; |  | ||||||
|     private Button headerSubscribeButton; |  | ||||||
|     private View playlistCtrl; |  | ||||||
|     private LinearLayout headerPlayAllButton; |  | ||||||
|     private LinearLayout headerPopupButton; |  | ||||||
|     private LinearLayout headerBackgroundButton; |  | ||||||
|     private MenuItem menuRssButton; |     private MenuItem menuRssButton; | ||||||
|     private TextView contentNotSupportedTextView; |     private TextView contentNotSupportedTextView; | ||||||
|     private TextView kaomojiTextView; |     private TextView kaomojiTextView; | ||||||
| @@ -140,45 +133,38 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> | |||||||
|     @Override |     @Override | ||||||
|     public void onDestroy() { |     public void onDestroy() { | ||||||
|         super.onDestroy(); |         super.onDestroy(); | ||||||
|         if (disposables != null) { |         disposables.clear(); | ||||||
|             disposables.clear(); |  | ||||||
|         } |  | ||||||
|         if (subscribeButtonMonitor != null) { |         if (subscribeButtonMonitor != null) { | ||||||
|             subscribeButtonMonitor.dispose(); |             subscribeButtonMonitor.dispose(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void onDestroyView() { | ||||||
|  |         headerBinding = null; | ||||||
|  |         playlistControlBinding = null; | ||||||
|  |         super.onDestroyView(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /*////////////////////////////////////////////////////////////////////////// |     /*////////////////////////////////////////////////////////////////////////// | ||||||
|     // Init |     // Init | ||||||
|     //////////////////////////////////////////////////////////////////////////*/ |     //////////////////////////////////////////////////////////////////////////*/ | ||||||
|  |  | ||||||
|     protected View getListHeader() { |     @Override | ||||||
|         headerRootLayout = activity.getLayoutInflater() |     protected ViewBinding getListHeader() { | ||||||
|                 .inflate(R.layout.channel_header, itemsList, false); |         headerBinding = ChannelHeaderBinding | ||||||
|         headerChannelBanner = headerRootLayout.findViewById(R.id.channel_banner_image); |                 .inflate(activity.getLayoutInflater(), itemsList, false); | ||||||
|         headerAvatarView = headerRootLayout.findViewById(R.id.channel_avatar_view); |         playlistControlBinding = headerBinding.playlistControl; | ||||||
|         headerTitleView = headerRootLayout.findViewById(R.id.channel_title_view); |  | ||||||
|         headerSubscribersTextView = headerRootLayout.findViewById(R.id.channel_subscriber_view); |  | ||||||
|         headerSubscribeButton = headerRootLayout.findViewById(R.id.channel_subscribe_button); |  | ||||||
|         playlistCtrl = headerRootLayout.findViewById(R.id.playlist_control); |  | ||||||
|         headerSubChannelAvatarView = |  | ||||||
|                 headerRootLayout.findViewById(R.id.sub_channel_avatar_view); |  | ||||||
|         headerSubChannelTitleView = |  | ||||||
|                 headerRootLayout.findViewById(R.id.sub_channel_title_view); |  | ||||||
|  |  | ||||||
|         headerPlayAllButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_all_button); |         return headerBinding; | ||||||
|         headerPopupButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_popup_button); |  | ||||||
|         headerBackgroundButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_bg_button); |  | ||||||
|  |  | ||||||
|         return headerRootLayout; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     protected void initListeners() { |     protected void initListeners() { | ||||||
|         super.initListeners(); |         super.initListeners(); | ||||||
|  |  | ||||||
|         headerSubChannelTitleView.setOnClickListener(this); |         headerBinding.subChannelTitleView.setOnClickListener(this); | ||||||
|         headerSubChannelAvatarView.setOnClickListener(this); |         headerBinding.subChannelAvatarView.setOnClickListener(this); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /*////////////////////////////////////////////////////////////////////////// |     /*////////////////////////////////////////////////////////////////////////// | ||||||
| @@ -241,7 +227,7 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> | |||||||
|  |  | ||||||
|     private void monitorSubscription(final ChannelInfo info) { |     private void monitorSubscription(final ChannelInfo info) { | ||||||
|         final Consumer<Throwable> onError = (Throwable throwable) -> { |         final Consumer<Throwable> onError = (Throwable throwable) -> { | ||||||
|             animateView(headerSubscribeButton, false, 100); |             animateView(headerBinding.channelSubscribeButton, false, 100); | ||||||
|             showSnackBarError(throwable, UserAction.SUBSCRIPTION, |             showSnackBarError(throwable, UserAction.SUBSCRIPTION, | ||||||
|                     NewPipe.getNameOfService(currentInfo.getServiceId()), |                     NewPipe.getNameOfService(currentInfo.getServiceId()), | ||||||
|                     "Get subscription status", 0); |                     "Get subscription status", 0); | ||||||
| @@ -351,15 +337,15 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> | |||||||
|                         info.getAvatarUrl(), |                         info.getAvatarUrl(), | ||||||
|                         info.getDescription(), |                         info.getDescription(), | ||||||
|                         info.getSubscriberCount()); |                         info.getSubscriberCount()); | ||||||
|                 subscribeButtonMonitor = monitorSubscribeButton(headerSubscribeButton, |                 subscribeButtonMonitor = monitorSubscribeButton( | ||||||
|                         mapOnSubscribe(channel, info)); |                         headerBinding.channelSubscribeButton, mapOnSubscribe(channel, info)); | ||||||
|             } else { |             } else { | ||||||
|                 if (DEBUG) { |                 if (DEBUG) { | ||||||
|                     Log.d(TAG, "Found subscription to this channel!"); |                     Log.d(TAG, "Found subscription to this channel!"); | ||||||
|                 } |                 } | ||||||
|                 final SubscriptionEntity subscription = subscriptionEntities.get(0); |                 final SubscriptionEntity subscription = subscriptionEntities.get(0); | ||||||
|                 subscribeButtonMonitor = monitorSubscribeButton(headerSubscribeButton, |                 subscribeButtonMonitor = monitorSubscribeButton( | ||||||
|                         mapOnUnsubscribe(subscription)); |                         headerBinding.channelSubscribeButton, mapOnUnsubscribe(subscription)); | ||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
| @@ -370,7 +356,8 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> | |||||||
|                     + "isSubscribed = [" + isSubscribed + "]"); |                     + "isSubscribed = [" + isSubscribed + "]"); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         final boolean isButtonVisible = headerSubscribeButton.getVisibility() == View.VISIBLE; |         final boolean isButtonVisible = headerBinding.channelSubscribeButton.getVisibility() | ||||||
|  |                 == View.VISIBLE; | ||||||
|         final int backgroundDuration = isButtonVisible ? 300 : 0; |         final int backgroundDuration = isButtonVisible ? 300 : 0; | ||||||
|         final int textDuration = isButtonVisible ? 200 : 0; |         final int textDuration = isButtonVisible ? 200 : 0; | ||||||
|  |  | ||||||
| @@ -382,18 +369,21 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> | |||||||
|         final int subscribedText = ContextCompat.getColor(activity, R.color.subscribed_text_color); |         final int subscribedText = ContextCompat.getColor(activity, R.color.subscribed_text_color); | ||||||
|  |  | ||||||
|         if (!isSubscribed) { |         if (!isSubscribed) { | ||||||
|             headerSubscribeButton.setText(R.string.subscribe_button_title); |             headerBinding.channelSubscribeButton.setText(R.string.subscribe_button_title); | ||||||
|             animateBackgroundColor(headerSubscribeButton, backgroundDuration, subscribedBackground, |             animateBackgroundColor(headerBinding.channelSubscribeButton, backgroundDuration, | ||||||
|                     subscribeBackground); |                     subscribedBackground, subscribeBackground); | ||||||
|             animateTextColor(headerSubscribeButton, textDuration, subscribedText, subscribeText); |             animateTextColor(headerBinding.channelSubscribeButton, textDuration, subscribedText, | ||||||
|  |                     subscribeText); | ||||||
|         } else { |         } else { | ||||||
|             headerSubscribeButton.setText(R.string.subscribed_button_title); |             headerBinding.channelSubscribeButton.setText(R.string.subscribed_button_title); | ||||||
|             animateBackgroundColor(headerSubscribeButton, backgroundDuration, subscribeBackground, |             animateBackgroundColor(headerBinding.channelSubscribeButton, backgroundDuration, | ||||||
|                     subscribedBackground); |                     subscribeBackground, subscribedBackground); | ||||||
|             animateTextColor(headerSubscribeButton, textDuration, subscribeText, subscribedText); |             animateTextColor(headerBinding.channelSubscribeButton, textDuration, subscribeText, | ||||||
|  |                     subscribedText); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         animateView(headerSubscribeButton, AnimationUtils.Type.LIGHT_SCALE_AND_ALPHA, true, 100); |         animateView(headerBinding.channelSubscribeButton, AnimationUtils.Type.LIGHT_SCALE_AND_ALPHA, | ||||||
|  |                 true, 100); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /*////////////////////////////////////////////////////////////////////////// |     /*////////////////////////////////////////////////////////////////////////// | ||||||
| @@ -446,48 +436,49 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> | |||||||
|     public void showLoading() { |     public void showLoading() { | ||||||
|         super.showLoading(); |         super.showLoading(); | ||||||
|  |  | ||||||
|         IMAGE_LOADER.cancelDisplayTask(headerChannelBanner); |         IMAGE_LOADER.cancelDisplayTask(headerBinding.channelBannerImage); | ||||||
|         IMAGE_LOADER.cancelDisplayTask(headerAvatarView); |         IMAGE_LOADER.cancelDisplayTask(headerBinding.channelAvatarView); | ||||||
|         IMAGE_LOADER.cancelDisplayTask(headerSubChannelAvatarView); |         IMAGE_LOADER.cancelDisplayTask(headerBinding.subChannelAvatarView); | ||||||
|         animateView(headerSubscribeButton, false, 100); |         animateView(headerBinding.channelSubscribeButton, false, 100); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void handleResult(@NonNull final ChannelInfo result) { |     public void handleResult(@NonNull final ChannelInfo result) { | ||||||
|         super.handleResult(result); |         super.handleResult(result); | ||||||
|  |  | ||||||
|         headerRootLayout.setVisibility(View.VISIBLE); |         headerBinding.getRoot().setVisibility(View.VISIBLE); | ||||||
|         IMAGE_LOADER.displayImage(result.getBannerUrl(), headerChannelBanner, |         IMAGE_LOADER.displayImage(result.getBannerUrl(), headerBinding.channelBannerImage, | ||||||
|                 ImageDisplayConstants.DISPLAY_BANNER_OPTIONS); |                 ImageDisplayConstants.DISPLAY_BANNER_OPTIONS); | ||||||
|         IMAGE_LOADER.displayImage(result.getAvatarUrl(), headerAvatarView, |         IMAGE_LOADER.displayImage(result.getAvatarUrl(), headerBinding.channelAvatarView, | ||||||
|                 ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS); |                 ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS); | ||||||
|         IMAGE_LOADER.displayImage(result.getParentChannelAvatarUrl(), headerSubChannelAvatarView, |         IMAGE_LOADER.displayImage(result.getParentChannelAvatarUrl(), | ||||||
|  |                 headerBinding.subChannelAvatarView, | ||||||
|                 ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS); |                 ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS); | ||||||
|  |  | ||||||
|         headerSubscribersTextView.setVisibility(View.VISIBLE); |         headerBinding.channelSubscriberView.setVisibility(View.VISIBLE); | ||||||
|         if (result.getSubscriberCount() >= 0) { |         if (result.getSubscriberCount() >= 0) { | ||||||
|             headerSubscribersTextView.setText(Localization |             headerBinding.channelSubscriberView.setText(Localization | ||||||
|                     .shortSubscriberCount(activity, result.getSubscriberCount())); |                     .shortSubscriberCount(activity, result.getSubscriberCount())); | ||||||
|         } else { |         } else { | ||||||
|             headerSubscribersTextView.setText(R.string.subscribers_count_not_available); |             headerBinding.channelSubscriberView.setText(R.string.subscribers_count_not_available); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (!TextUtils.isEmpty(currentInfo.getParentChannelName())) { |         if (!TextUtils.isEmpty(currentInfo.getParentChannelName())) { | ||||||
|             headerSubChannelTitleView.setText(String.format( |             headerBinding.subChannelTitleView.setText(String.format( | ||||||
|                             getString(R.string.channel_created_by), |                             getString(R.string.channel_created_by), | ||||||
|                             currentInfo.getParentChannelName()) |                             currentInfo.getParentChannelName()) | ||||||
|             ); |             ); | ||||||
|             headerSubChannelTitleView.setVisibility(View.VISIBLE); |             headerBinding.subChannelTitleView.setVisibility(View.VISIBLE); | ||||||
|             headerSubChannelAvatarView.setVisibility(View.VISIBLE); |             headerBinding.subChannelAvatarView.setVisibility(View.VISIBLE); | ||||||
|         } else { |         } else { | ||||||
|             headerSubChannelTitleView.setVisibility(View.GONE); |             headerBinding.subChannelTitleView.setVisibility(View.GONE); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (menuRssButton != null) { |         if (menuRssButton != null) { | ||||||
|             menuRssButton.setVisible(!TextUtils.isEmpty(result.getFeedUrl())); |             menuRssButton.setVisible(!TextUtils.isEmpty(result.getFeedUrl())); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         playlistCtrl.setVisibility(View.VISIBLE); |         playlistControlBinding.getRoot().setVisibility(View.VISIBLE); | ||||||
|  |  | ||||||
|         final List<Throwable> errors = new ArrayList<>(result.getErrors()); |         final List<Throwable> errors = new ArrayList<>(result.getErrors()); | ||||||
|         if (!errors.isEmpty()) { |         if (!errors.isEmpty()) { | ||||||
| @@ -516,19 +507,22 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> | |||||||
|         updateSubscription(result); |         updateSubscription(result); | ||||||
|         monitorSubscription(result); |         monitorSubscription(result); | ||||||
|  |  | ||||||
|         headerPlayAllButton.setOnClickListener(view -> NavigationHelper |         playlistControlBinding.playlistCtrlPlayAllButton | ||||||
|                 .playOnMainPlayer(activity, getPlayQueue())); |                 .setOnClickListener(view -> NavigationHelper | ||||||
|         headerPopupButton.setOnClickListener(view -> NavigationHelper |                         .playOnMainPlayer(activity, getPlayQueue())); | ||||||
|                 .playOnPopupPlayer(activity, getPlayQueue(), false)); |         playlistControlBinding.playlistCtrlPlayPopupButton | ||||||
|         headerBackgroundButton.setOnClickListener(view -> NavigationHelper |                 .setOnClickListener(view -> NavigationHelper | ||||||
|                 .playOnBackgroundPlayer(activity, getPlayQueue(), false)); |                         .playOnPopupPlayer(activity, getPlayQueue(), false)); | ||||||
|  |         playlistControlBinding.playlistCtrlPlayBgButton | ||||||
|  |                 .setOnClickListener(view -> NavigationHelper | ||||||
|  |                         .playOnBackgroundPlayer(activity, getPlayQueue(), false)); | ||||||
|  |  | ||||||
|         headerPopupButton.setOnLongClickListener(view -> { |         playlistControlBinding.playlistCtrlPlayPopupButton.setOnLongClickListener(view -> { | ||||||
|             NavigationHelper.enqueueOnPopupPlayer(activity, getPlayQueue(), true); |             NavigationHelper.enqueueOnPopupPlayer(activity, getPlayQueue(), true); | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         headerBackgroundButton.setOnLongClickListener(view -> { |         playlistControlBinding.playlistCtrlPlayBgButton.setOnLongClickListener(view -> { | ||||||
|             NavigationHelper.enqueueOnBackgroundPlayer(activity, getPlayQueue(), true); |             NavigationHelper.enqueueOnBackgroundPlayer(activity, getPlayQueue(), true); | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
| @@ -596,7 +590,7 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> | |||||||
|     public void setTitle(final String title) { |     public void setTitle(final String title) { | ||||||
|         super.setTitle(title); |         super.setTitle(title); | ||||||
|         if (!useAsFrontPage) { |         if (!useAsFrontPage) { | ||||||
|             headerTitleView.setText(title); |             headerBinding.channelTitleView.setText(title); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -11,18 +11,20 @@ import android.view.MenuInflater; | |||||||
| import android.view.MenuItem; | import android.view.MenuItem; | ||||||
| import android.view.View; | import android.view.View; | ||||||
| import android.view.ViewGroup; | import android.view.ViewGroup; | ||||||
| import android.widget.TextView; |  | ||||||
|  |  | ||||||
| import androidx.annotation.NonNull; | import androidx.annotation.NonNull; | ||||||
| import androidx.annotation.Nullable; | import androidx.annotation.Nullable; | ||||||
| import androidx.appcompat.app.AppCompatActivity; | import androidx.appcompat.app.AppCompatActivity; | ||||||
| import androidx.appcompat.content.res.AppCompatResources; | import androidx.appcompat.content.res.AppCompatResources; | ||||||
|  | import androidx.viewbinding.ViewBinding; | ||||||
|  |  | ||||||
| import org.reactivestreams.Subscriber; | import org.reactivestreams.Subscriber; | ||||||
| import org.reactivestreams.Subscription; | import org.reactivestreams.Subscription; | ||||||
| import org.schabi.newpipe.NewPipeDatabase; | import org.schabi.newpipe.NewPipeDatabase; | ||||||
| import org.schabi.newpipe.R; | import org.schabi.newpipe.R; | ||||||
| import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity; | import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity; | ||||||
|  | import org.schabi.newpipe.databinding.PlaylistControlBinding; | ||||||
|  | import org.schabi.newpipe.databinding.PlaylistHeaderBinding; | ||||||
| import org.schabi.newpipe.extractor.InfoItem; | import org.schabi.newpipe.extractor.InfoItem; | ||||||
| import org.schabi.newpipe.extractor.ListExtractor; | import org.schabi.newpipe.extractor.ListExtractor; | ||||||
| import org.schabi.newpipe.extractor.NewPipe; | import org.schabi.newpipe.extractor.NewPipe; | ||||||
| @@ -53,7 +55,6 @@ import java.util.Arrays; | |||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.concurrent.atomic.AtomicBoolean; | import java.util.concurrent.atomic.AtomicBoolean; | ||||||
|  |  | ||||||
| import de.hdodenhof.circleimageview.CircleImageView; |  | ||||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||||
| import io.reactivex.rxjava3.core.Flowable; | import io.reactivex.rxjava3.core.Flowable; | ||||||
| import io.reactivex.rxjava3.core.Single; | import io.reactivex.rxjava3.core.Single; | ||||||
| @@ -74,17 +75,8 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> { | |||||||
|     // Views |     // Views | ||||||
|     //////////////////////////////////////////////////////////////////////////*/ |     //////////////////////////////////////////////////////////////////////////*/ | ||||||
|  |  | ||||||
|     private View headerRootLayout; |     private PlaylistHeaderBinding headerBinding; | ||||||
|     private TextView headerTitleView; |     private PlaylistControlBinding playlistControlBinding; | ||||||
|     private View headerUploaderLayout; |  | ||||||
|     private TextView headerUploaderName; |  | ||||||
|     private CircleImageView headerUploaderAvatar; |  | ||||||
|     private TextView headerStreamCount; |  | ||||||
|     private View playlistCtrl; |  | ||||||
|  |  | ||||||
|     private View headerPlayAllButton; |  | ||||||
|     private View headerPopupButton; |  | ||||||
|     private View headerBackgroundButton; |  | ||||||
|  |  | ||||||
|     private MenuItem playlistBookmarkButton; |     private MenuItem playlistBookmarkButton; | ||||||
|  |  | ||||||
| @@ -119,22 +111,13 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> { | |||||||
|     // Init |     // Init | ||||||
|     //////////////////////////////////////////////////////////////////////////*/ |     //////////////////////////////////////////////////////////////////////////*/ | ||||||
|  |  | ||||||
|     protected View getListHeader() { |     @Override | ||||||
|         headerRootLayout = activity.getLayoutInflater() |     protected ViewBinding getListHeader() { | ||||||
|                 .inflate(R.layout.playlist_header, itemsList, false); |         headerBinding = PlaylistHeaderBinding | ||||||
|         headerTitleView = headerRootLayout.findViewById(R.id.playlist_title_view); |                 .inflate(activity.getLayoutInflater(), itemsList, false); | ||||||
|         headerUploaderLayout = headerRootLayout.findViewById(R.id.uploader_layout); |         playlistControlBinding = headerBinding.playlistControl; | ||||||
|         headerUploaderName = headerRootLayout.findViewById(R.id.uploader_name); |  | ||||||
|         headerUploaderAvatar = headerRootLayout.findViewById(R.id.uploader_avatar_view); |  | ||||||
|         headerStreamCount = headerRootLayout.findViewById(R.id.playlist_stream_count); |  | ||||||
|         playlistCtrl = headerRootLayout.findViewById(R.id.playlist_control); |  | ||||||
|  |  | ||||||
|         headerPlayAllButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_all_button); |         return headerBinding; | ||||||
|         headerPopupButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_popup_button); |  | ||||||
|         headerBackgroundButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_bg_button); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         return headerRootLayout; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @@ -203,6 +186,9 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> { | |||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void onDestroyView() { |     public void onDestroyView() { | ||||||
|  |         headerBinding = null; | ||||||
|  |         playlistControlBinding = null; | ||||||
|  |  | ||||||
|         super.onDestroyView(); |         super.onDestroyView(); | ||||||
|         if (isBookmarkButtonReady != null) { |         if (isBookmarkButtonReady != null) { | ||||||
|             isBookmarkButtonReady.set(false); |             isBookmarkButtonReady.set(false); | ||||||
| @@ -275,25 +261,25 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> { | |||||||
|     @Override |     @Override | ||||||
|     public void showLoading() { |     public void showLoading() { | ||||||
|         super.showLoading(); |         super.showLoading(); | ||||||
|         animateView(headerRootLayout, false, 200); |         animateView(headerBinding.getRoot(), false, 200); | ||||||
|         animateView(itemsList, false, 100); |         animateView(itemsList, false, 100); | ||||||
|  |  | ||||||
|         IMAGE_LOADER.cancelDisplayTask(headerUploaderAvatar); |         IMAGE_LOADER.cancelDisplayTask(headerBinding.uploaderAvatarView); | ||||||
|         animateView(headerUploaderLayout, false, 200); |         animateView(headerBinding.uploaderLayout, false, 200); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void handleResult(@NonNull final PlaylistInfo result) { |     public void handleResult(@NonNull final PlaylistInfo result) { | ||||||
|         super.handleResult(result); |         super.handleResult(result); | ||||||
|  |  | ||||||
|         animateView(headerRootLayout, true, 100); |         animateView(headerBinding.getRoot(), true, 100); | ||||||
|         animateView(headerUploaderLayout, true, 300); |         animateView(headerBinding.uploaderLayout, true, 300); | ||||||
|         headerUploaderLayout.setOnClickListener(null); |         headerBinding.uploaderLayout.setOnClickListener(null); | ||||||
|         // If we have an uploader put them into the UI |         // If we have an uploader put them into the UI | ||||||
|         if (!TextUtils.isEmpty(result.getUploaderName())) { |         if (!TextUtils.isEmpty(result.getUploaderName())) { | ||||||
|             headerUploaderName.setText(result.getUploaderName()); |             headerBinding.uploaderName.setText(result.getUploaderName()); | ||||||
|             if (!TextUtils.isEmpty(result.getUploaderUrl())) { |             if (!TextUtils.isEmpty(result.getUploaderUrl())) { | ||||||
|                 headerUploaderLayout.setOnClickListener(v -> { |                 headerBinding.uploaderLayout.setOnClickListener(v -> { | ||||||
|                     try { |                     try { | ||||||
|                         NavigationHelper.openChannelFragment(getFM(), result.getServiceId(), |                         NavigationHelper.openChannelFragment(getFM(), result.getServiceId(), | ||||||
|                                 result.getUploaderUrl(), result.getUploaderName()); |                                 result.getUploaderUrl(), result.getUploaderName()); | ||||||
| @@ -303,28 +289,29 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> { | |||||||
|                 }); |                 }); | ||||||
|             } |             } | ||||||
|         } else { // Otherwise say we have no uploader |         } else { // Otherwise say we have no uploader | ||||||
|             headerUploaderName.setText(R.string.playlist_no_uploader); |             headerBinding.uploaderName.setText(R.string.playlist_no_uploader); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         playlistCtrl.setVisibility(View.VISIBLE); |         playlistControlBinding.getRoot().setVisibility(View.VISIBLE); | ||||||
|  |  | ||||||
|         final String avatarUrl = result.getUploaderAvatarUrl(); |         final String avatarUrl = result.getUploaderAvatarUrl(); | ||||||
|         if (result.getServiceId() == ServiceList.YouTube.getServiceId() |         if (result.getServiceId() == ServiceList.YouTube.getServiceId() | ||||||
|                 && (YoutubeParsingHelper.isYoutubeMixId(result.getId()) |                 && (YoutubeParsingHelper.isYoutubeMixId(result.getId()) | ||||||
|                 || YoutubeParsingHelper.isYoutubeMusicMixId(result.getId()))) { |                 || YoutubeParsingHelper.isYoutubeMusicMixId(result.getId()))) { | ||||||
|             // this is an auto-generated playlist (e.g. Youtube mix), so a radio is shown |             // this is an auto-generated playlist (e.g. Youtube mix), so a radio is shown | ||||||
|             headerUploaderAvatar.setDisableCircularTransformation(true); |             headerBinding.uploaderAvatarView.setDisableCircularTransformation(true); | ||||||
|             headerUploaderAvatar.setBorderColor( |             headerBinding.uploaderAvatarView.setBorderColor( | ||||||
|                     getResources().getColor(R.color.transparent_background_color)); |                     getResources().getColor(R.color.transparent_background_color)); | ||||||
|             headerUploaderAvatar.setImageDrawable(AppCompatResources.getDrawable(requireContext(), |             headerBinding.uploaderAvatarView.setImageDrawable( | ||||||
|                     resolveResourceIdFromAttr(requireContext(), R.attr.ic_radio))); |                     AppCompatResources.getDrawable(requireContext(), | ||||||
|  |                     resolveResourceIdFromAttr(requireContext(), R.attr.ic_radio)) | ||||||
|  |             ); | ||||||
|         } else { |         } else { | ||||||
|             IMAGE_LOADER.displayImage(avatarUrl, headerUploaderAvatar, |             IMAGE_LOADER.displayImage(avatarUrl, headerBinding.uploaderAvatarView, | ||||||
|                     ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS); |                     ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         headerStreamCount.setText(Localization |         headerBinding.playlistStreamCount.setText(Localization | ||||||
|                 .localizeStreamCount(getContext(), result.getStreamCount())); |                 .localizeStreamCount(getContext(), result.getStreamCount())); | ||||||
|  |  | ||||||
|         if (!result.getErrors().isEmpty()) { |         if (!result.getErrors().isEmpty()) { | ||||||
| @@ -338,19 +325,19 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> { | |||||||
|                 .observeOn(AndroidSchedulers.mainThread()) |                 .observeOn(AndroidSchedulers.mainThread()) | ||||||
|                 .subscribe(getPlaylistBookmarkSubscriber()); |                 .subscribe(getPlaylistBookmarkSubscriber()); | ||||||
|  |  | ||||||
|         headerPlayAllButton.setOnClickListener(view -> |         playlistControlBinding.playlistCtrlPlayAllButton.setOnClickListener(view -> | ||||||
|                 NavigationHelper.playOnMainPlayer(activity, getPlayQueue())); |                 NavigationHelper.playOnMainPlayer(activity, getPlayQueue())); | ||||||
|         headerPopupButton.setOnClickListener(view -> |         playlistControlBinding.playlistCtrlPlayPopupButton.setOnClickListener(view -> | ||||||
|                 NavigationHelper.playOnPopupPlayer(activity, getPlayQueue(), false)); |                 NavigationHelper.playOnPopupPlayer(activity, getPlayQueue(), false)); | ||||||
|         headerBackgroundButton.setOnClickListener(view -> |         playlistControlBinding.playlistCtrlPlayBgButton.setOnClickListener(view -> | ||||||
|                 NavigationHelper.playOnBackgroundPlayer(activity, getPlayQueue(), false)); |                 NavigationHelper.playOnBackgroundPlayer(activity, getPlayQueue(), false)); | ||||||
|  |  | ||||||
|         headerPopupButton.setOnLongClickListener(view -> { |         playlistControlBinding.playlistCtrlPlayPopupButton.setOnLongClickListener(view -> { | ||||||
|             NavigationHelper.enqueueOnPopupPlayer(activity, getPlayQueue(), true); |             NavigationHelper.enqueueOnPopupPlayer(activity, getPlayQueue(), true); | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         headerBackgroundButton.setOnLongClickListener(view -> { |         playlistControlBinding.playlistCtrlPlayBgButton.setOnLongClickListener(view -> { | ||||||
|             NavigationHelper.enqueueOnBackgroundPlayer(activity, getPlayQueue(), true); |             NavigationHelper.enqueueOnBackgroundPlayer(activity, getPlayQueue(), true); | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
| @@ -459,7 +446,7 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> { | |||||||
|     @Override |     @Override | ||||||
|     public void setTitle(final String title) { |     public void setTitle(final String title) { | ||||||
|         super.setTitle(title); |         super.setTitle(title); | ||||||
|         headerTitleView.setText(title); |         headerBinding.playlistTitleView.setText(title); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private void onBookmarkClicked() { |     private void onBookmarkClicked() { | ||||||
|   | |||||||
| @@ -8,13 +8,14 @@ import android.view.Menu; | |||||||
| import android.view.MenuInflater; | import android.view.MenuInflater; | ||||||
| import android.view.View; | import android.view.View; | ||||||
| import android.view.ViewGroup; | import android.view.ViewGroup; | ||||||
| import android.widget.Switch; |  | ||||||
|  |  | ||||||
| import androidx.annotation.NonNull; | import androidx.annotation.NonNull; | ||||||
| import androidx.annotation.Nullable; | import androidx.annotation.Nullable; | ||||||
| import androidx.preference.PreferenceManager; | import androidx.preference.PreferenceManager; | ||||||
|  | import androidx.viewbinding.ViewBinding; | ||||||
|  |  | ||||||
| import org.schabi.newpipe.R; | import org.schabi.newpipe.R; | ||||||
|  | import org.schabi.newpipe.databinding.RelatedStreamsHeaderBinding; | ||||||
| import org.schabi.newpipe.extractor.ListExtractor; | import org.schabi.newpipe.extractor.ListExtractor; | ||||||
| import org.schabi.newpipe.extractor.NewPipe; | import org.schabi.newpipe.extractor.NewPipe; | ||||||
| import org.schabi.newpipe.extractor.stream.StreamInfo; | import org.schabi.newpipe.extractor.stream.StreamInfo; | ||||||
| @@ -38,8 +39,7 @@ public class RelatedVideosFragment extends BaseListInfoFragment<RelatedStreamInf | |||||||
|     // Views |     // Views | ||||||
|     //////////////////////////////////////////////////////////////////////////*/ |     //////////////////////////////////////////////////////////////////////////*/ | ||||||
|  |  | ||||||
|     private View headerRootLayout; |     private RelatedStreamsHeaderBinding headerBinding; | ||||||
|     private Switch autoplaySwitch; |  | ||||||
|  |  | ||||||
|     public static RelatedVideosFragment getInstance(final StreamInfo info) { |     public static RelatedVideosFragment getInstance(final StreamInfo info) { | ||||||
|         final RelatedVideosFragment instance = new RelatedVideosFragment(); |         final RelatedVideosFragment instance = new RelatedVideosFragment(); | ||||||
| @@ -66,25 +66,29 @@ public class RelatedVideosFragment extends BaseListInfoFragment<RelatedStreamInf | |||||||
|     @Override |     @Override | ||||||
|     public void onDestroy() { |     public void onDestroy() { | ||||||
|         super.onDestroy(); |         super.onDestroy(); | ||||||
|         if (disposables != null) { |         disposables.clear(); | ||||||
|             disposables.clear(); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     protected View getListHeader() { |     @Override | ||||||
|  |     public void onDestroyView() { | ||||||
|  |         headerBinding = null; | ||||||
|  |         super.onDestroyView(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     protected ViewBinding getListHeader() { | ||||||
|         if (relatedStreamInfo != null && relatedStreamInfo.getRelatedItems() != null) { |         if (relatedStreamInfo != null && relatedStreamInfo.getRelatedItems() != null) { | ||||||
|             headerRootLayout = activity.getLayoutInflater() |             headerBinding = RelatedStreamsHeaderBinding | ||||||
|                     .inflate(R.layout.related_streams_header, itemsList, false); |                     .inflate(activity.getLayoutInflater(), itemsList, false); | ||||||
|             autoplaySwitch = headerRootLayout.findViewById(R.id.autoplay_switch); |  | ||||||
|  |  | ||||||
|             final SharedPreferences pref = PreferenceManager |             final SharedPreferences pref = PreferenceManager | ||||||
|                     .getDefaultSharedPreferences(requireContext()); |                     .getDefaultSharedPreferences(requireContext()); | ||||||
|             final boolean autoplay = pref.getBoolean(getString(R.string.auto_queue_key), false); |             final boolean autoplay = pref.getBoolean(getString(R.string.auto_queue_key), false); | ||||||
|             autoplaySwitch.setChecked(autoplay); |             headerBinding.autoplaySwitch.setChecked(autoplay); | ||||||
|             autoplaySwitch.setOnCheckedChangeListener((compoundButton, b) -> |             headerBinding.autoplaySwitch.setOnCheckedChangeListener((compoundButton, b) -> | ||||||
|                     PreferenceManager.getDefaultSharedPreferences(requireContext()).edit() |                     PreferenceManager.getDefaultSharedPreferences(requireContext()).edit() | ||||||
|                             .putBoolean(getString(R.string.auto_queue_key), b).apply()); |                             .putBoolean(getString(R.string.auto_queue_key), b).apply()); | ||||||
|             return headerRootLayout; |             return headerBinding; | ||||||
|         } else { |         } else { | ||||||
|             return null; |             return null; | ||||||
|         } |         } | ||||||
| @@ -107,8 +111,8 @@ public class RelatedVideosFragment extends BaseListInfoFragment<RelatedStreamInf | |||||||
|     @Override |     @Override | ||||||
|     public void showLoading() { |     public void showLoading() { | ||||||
|         super.showLoading(); |         super.showLoading(); | ||||||
|         if (headerRootLayout != null) { |         if (headerBinding != null) { | ||||||
|             headerRootLayout.setVisibility(View.INVISIBLE); |             headerBinding.getRoot().setVisibility(View.INVISIBLE); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -116,8 +120,8 @@ public class RelatedVideosFragment extends BaseListInfoFragment<RelatedStreamInf | |||||||
|     public void handleResult(@NonNull final RelatedStreamInfo result) { |     public void handleResult(@NonNull final RelatedStreamInfo result) { | ||||||
|         super.handleResult(result); |         super.handleResult(result); | ||||||
|  |  | ||||||
|         if (headerRootLayout != null) { |         if (headerBinding != null) { | ||||||
|             headerRootLayout.setVisibility(View.VISIBLE); |             headerBinding.getRoot().setVisibility(View.VISIBLE); | ||||||
|         } |         } | ||||||
|         AnimationUtils.slideUp(getView(), 120, 96, 0.06f); |         AnimationUtils.slideUp(getView(), 120, 96, 0.06f); | ||||||
|  |  | ||||||
| @@ -126,9 +130,7 @@ public class RelatedVideosFragment extends BaseListInfoFragment<RelatedStreamInf | |||||||
|                     NewPipe.getNameOfService(result.getServiceId()), result.getUrl(), 0); |                     NewPipe.getNameOfService(result.getServiceId()), result.getUrl(), 0); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (disposables != null) { |         disposables.clear(); | ||||||
|             disposables.clear(); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @@ -202,8 +204,8 @@ public class RelatedVideosFragment extends BaseListInfoFragment<RelatedStreamInf | |||||||
|         final SharedPreferences pref = |         final SharedPreferences pref = | ||||||
|                 PreferenceManager.getDefaultSharedPreferences(requireContext()); |                 PreferenceManager.getDefaultSharedPreferences(requireContext()); | ||||||
|         final boolean autoplay = pref.getBoolean(getString(R.string.auto_queue_key), false); |         final boolean autoplay = pref.getBoolean(getString(R.string.auto_queue_key), false); | ||||||
|         if (autoplaySwitch != null) { |         if (headerBinding != null) { | ||||||
|             autoplaySwitch.setChecked(autoplay); |             headerBinding.autoplaySwitch.setChecked(autoplay); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -119,7 +119,10 @@ | |||||||
|         android:layout_height="wrap_content" |         android:layout_height="wrap_content" | ||||||
|         android:layout_below="@id/channel_metadata"> |         android:layout_below="@id/channel_metadata"> | ||||||
|  |  | ||||||
|         <include layout="@layout/playlist_control" /> |         <include | ||||||
|  |             android:id="@+id/playlist_control" | ||||||
|  |             layout="@layout/playlist_control" /> | ||||||
|  |  | ||||||
|     </LinearLayout> |     </LinearLayout> | ||||||
|  |  | ||||||
| </RelativeLayout> | </RelativeLayout> | ||||||
|   | |||||||
| @@ -83,7 +83,9 @@ | |||||||
|         android:layout_height="wrap_content" |         android:layout_height="wrap_content" | ||||||
|         android:layout_below="@id/playlist_meta"> |         android:layout_below="@id/playlist_meta"> | ||||||
|  |  | ||||||
|         <include layout="@layout/playlist_control" /> |         <include | ||||||
|  |             android:id="@+id/playlist_control" | ||||||
|  |             layout="@layout/playlist_control" /> | ||||||
|     </LinearLayout> |     </LinearLayout> | ||||||
|  |  | ||||||
| </RelativeLayout> | </RelativeLayout> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Isira Seneviratne
					Isira Seneviratne