From 355e192e63cb9a9be8e8890531b2d692cd555537 Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Mon, 18 Jan 2021 06:59:33 +0530 Subject: [PATCH 01/19] Use view binding in SuggestionListAdapter. --- .../list/search/SuggestionListAdapter.java | 43 ++++++++----------- 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SuggestionListAdapter.java b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SuggestionListAdapter.java index d4bb4eebde8..139f6253473 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SuggestionListAdapter.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SuggestionListAdapter.java @@ -3,15 +3,14 @@ import android.content.Context; import android.content.res.TypedArray; import android.view.LayoutInflater; -import android.view.View; import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; import androidx.annotation.AttrRes; +import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import org.schabi.newpipe.R; +import org.schabi.newpipe.databinding.ItemSearchSuggestionBinding; import java.util.ArrayList; import java.util.List; @@ -50,28 +49,30 @@ public void setShowSuggestionHistory(final boolean v) { showSuggestionHistory = v; } + @NonNull @Override - public SuggestionItemHolder onCreateViewHolder(final ViewGroup parent, final int viewType) { - return new SuggestionItemHolder(LayoutInflater.from(context) - .inflate(R.layout.item_search_suggestion, parent, false)); + public SuggestionItemHolder onCreateViewHolder(@NonNull final ViewGroup parent, + final int viewType) { + return new SuggestionItemHolder(ItemSearchSuggestionBinding + .inflate(LayoutInflater.from(context), parent, false)); } @Override public void onBindViewHolder(final SuggestionItemHolder holder, final int position) { final SuggestionItem currentItem = getItem(position); holder.updateFrom(currentItem); - holder.queryView.setOnClickListener(v -> { + holder.binding.suggestionSearch.setOnClickListener(v -> { if (listener != null) { listener.onSuggestionItemSelected(currentItem); } }); - holder.queryView.setOnLongClickListener(v -> { + holder.binding.suggestionSearch.setOnLongClickListener(v -> { if (listener != null) { listener.onSuggestionItemLongClick(currentItem); } return true; }); - holder.insertView.setOnClickListener(v -> { + holder.binding.suggestionInsert.setOnClickListener(v -> { if (listener != null) { listener.onSuggestionItemInserted(currentItem); } @@ -100,25 +101,18 @@ public interface OnSuggestionItemSelected { } public static final class SuggestionItemHolder extends RecyclerView.ViewHolder { - private final TextView itemSuggestionQuery; - private final ImageView suggestionIcon; - private final View queryView; - private final View insertView; + private final ItemSearchSuggestionBinding binding; // Cache some ids, as they can potentially be constantly updated/recycled private final int historyResId; private final int searchResId; - private SuggestionItemHolder(final View rootView) { - super(rootView); - suggestionIcon = rootView.findViewById(R.id.item_suggestion_icon); - itemSuggestionQuery = rootView.findViewById(R.id.item_suggestion_query); + private SuggestionItemHolder(final ItemSearchSuggestionBinding binding) { + super(binding.getRoot()); + this.binding = binding; - queryView = rootView.findViewById(R.id.suggestion_search); - insertView = rootView.findViewById(R.id.suggestion_insert); - - historyResId = resolveResourceIdFromAttr(rootView.getContext(), R.attr.ic_history); - searchResId = resolveResourceIdFromAttr(rootView.getContext(), R.attr.ic_search); + historyResId = resolveResourceIdFromAttr(itemView.getContext(), R.attr.ic_history); + searchResId = resolveResourceIdFromAttr(itemView.getContext(), R.attr.ic_search); } private static int resolveResourceIdFromAttr(final Context context, @@ -130,8 +124,9 @@ private static int resolveResourceIdFromAttr(final Context context, } private void updateFrom(final SuggestionItem item) { - suggestionIcon.setImageResource(item.fromHistory ? historyResId : searchResId); - itemSuggestionQuery.setText(item.query); + binding.itemSuggestionIcon.setImageResource(item.fromHistory ? historyResId + : searchResId); + binding.itemSuggestionQuery.setText(item.query); } } } From c21d2cc1ae0a7fc667333c8b2817f1962b159914 Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Mon, 18 Jan 2021 07:05:47 +0530 Subject: [PATCH 02/19] Use view binding in StreamItemAdapter. --- .../newpipe/util/StreamItemAdapter.java | 37 ++++++++----------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/util/StreamItemAdapter.java b/app/src/main/java/org/schabi/newpipe/util/StreamItemAdapter.java index 9150b5c1a69..cd30ac037c3 100644 --- a/app/src/main/java/org/schabi/newpipe/util/StreamItemAdapter.java +++ b/app/src/main/java/org/schabi/newpipe/util/StreamItemAdapter.java @@ -6,12 +6,11 @@ import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; -import android.widget.ImageView; import android.widget.Spinner; -import android.widget.TextView; import org.schabi.newpipe.DownloaderImpl; import org.schabi.newpipe.R; +import org.schabi.newpipe.databinding.StreamQualityItemBinding; import org.schabi.newpipe.extractor.stream.AudioStream; import org.schabi.newpipe.extractor.stream.Stream; import org.schabi.newpipe.extractor.stream.SubtitlesStream; @@ -94,17 +93,13 @@ public View getView(final int position, final View convertView, final ViewGroup private View getCustomView(final int position, final View view, final ViewGroup parent, final boolean isDropdownItem) { - View convertView = view; - if (convertView == null) { - convertView = LayoutInflater.from(context).inflate( - R.layout.stream_quality_item, parent, false); + final StreamQualityItemBinding binding; + if (view == null) { + binding = StreamQualityItemBinding.inflate(LayoutInflater.from(context), parent, false); + } else { + binding = StreamQualityItemBinding.bind(view); } - final ImageView woSoundIconView = convertView.findViewById(R.id.wo_sound_icon); - final TextView formatNameView = convertView.findViewById(R.id.stream_format_name); - final TextView qualityView = convertView.findViewById(R.id.stream_quality); - final TextView sizeView = convertView.findViewById(R.id.stream_size); - final T stream = getItem(position); int woSoundIconVisibility = View.GONE; @@ -142,33 +137,33 @@ private View getCustomView(final int position, final View view, final ViewGroup if (secondary != null) { final long size = secondary.getSizeInBytes() + streamsWrapper.getSizeInBytes(position); - sizeView.setText(Utility.formatBytes(size)); + binding.streamSize.setText(Utility.formatBytes(size)); } else { - sizeView.setText(streamsWrapper.getFormattedSize(position)); + binding.streamSize.setText(streamsWrapper.getFormattedSize(position)); } - sizeView.setVisibility(View.VISIBLE); + binding.streamSize.setVisibility(View.VISIBLE); } else { - sizeView.setVisibility(View.GONE); + binding.streamSize.setVisibility(View.GONE); } if (stream instanceof SubtitlesStream) { - formatNameView.setText(((SubtitlesStream) stream).getLanguageTag()); + binding.streamFormatName.setText(((SubtitlesStream) stream).getLanguageTag()); } else { switch (stream.getFormat()) { case WEBMA_OPUS: // noinspection AndroidLintSetTextI18n - formatNameView.setText("opus"); + binding.streamFormatName.setText("opus"); break; default: - formatNameView.setText(stream.getFormat().getName()); + binding.streamFormatName.setText(stream.getFormat().getName()); break; } } - qualityView.setText(qualityString); - woSoundIconView.setVisibility(woSoundIconVisibility); + binding.streamQuality.setText(qualityString); + binding.woSoundIcon.setVisibility(woSoundIconVisibility); - return convertView; + return binding.getRoot(); } /** From 29bd32f33109b16cae9dcca897455b09e73bd0ba Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Mon, 18 Jan 2021 07:20:48 +0530 Subject: [PATCH 03/19] Use view binding in MissionsFragment and MissionAdapter. --- .../giga/ui/adapter/MissionAdapter.java | 24 +++++---- .../giga/ui/fragment/MissionsFragment.java | 51 +++++-------------- 2 files changed, 27 insertions(+), 48 deletions(-) diff --git a/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java b/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java index bea4b6f9420..997fa272853 100644 --- a/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java +++ b/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java @@ -40,6 +40,8 @@ import org.schabi.newpipe.BuildConfig; import org.schabi.newpipe.R; +import org.schabi.newpipe.databinding.ListEmptyViewBinding; +import org.schabi.newpipe.databinding.MissionsHeaderBinding; import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.report.ErrorInfo; @@ -113,7 +115,7 @@ public class MissionAdapter extends Adapter implements Handler.Callb private MenuItem mClear; private MenuItem mStartButton; private MenuItem mPauseButton; - private final View mEmptyMessage; + private final ListEmptyViewBinding mEmptyViewBinding; private RecoverHelper mRecover; private final View mView; private final ArrayList mHidden; @@ -124,7 +126,8 @@ public class MissionAdapter extends Adapter implements Handler.Callb private final CompositeDisposable compositeDisposable = new CompositeDisposable(); - public MissionAdapter(Context context, @NonNull DownloadManager downloadManager, View emptyMessage, View root) { + public MissionAdapter(@NonNull Context context, @NonNull DownloadManager downloadManager, + @NonNull ListEmptyViewBinding emptyViewBinding, @NonNull View root) { mContext = context; mDownloadManager = downloadManager; @@ -133,7 +136,7 @@ public MissionAdapter(Context context, @NonNull DownloadManager downloadManager, mHandler = new Handler(context.getMainLooper()); - mEmptyMessage = emptyMessage; + mEmptyViewBinding = emptyViewBinding; mIterator = downloadManager.getIterator(); @@ -153,7 +156,7 @@ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { switch (viewType) { case DownloadManager.SPECIAL_PENDING: case DownloadManager.SPECIAL_FINISHED: - return new ViewHolderHeader(mInflater.inflate(R.layout.missions_header, parent, false)); + return new ViewHolderHeader(MissionsHeaderBinding.inflate(mInflater, parent, false)); } return new ViewHolderItem(mInflater.inflate(mLayout, parent, false)); @@ -193,7 +196,7 @@ public void onBindViewHolder(@NonNull ViewHolder view, @SuppressLint("RecyclerVi if (mClear != null) mClear.setVisible(true); } - ((ViewHolderHeader) view).header.setText(str); + ((ViewHolderHeader) view).binding.itemName.setText(str); return; } @@ -776,7 +779,8 @@ public void setMasterButtons(MenuItem startButton, MenuItem pauseButton) { private void checkEmptyMessageVisibility() { int flag = mIterator.getOldListSize() > 0 ? View.GONE : View.VISIBLE; - if (mEmptyMessage.getVisibility() != flag) mEmptyMessage.setVisibility(flag); + if (mEmptyViewBinding.getRoot().getVisibility() != flag) + mEmptyViewBinding.getRoot().setVisibility(flag); } public void checkMasterButtonsVisibility() { @@ -993,11 +997,11 @@ private void resetSpeedMeasure() { } static class ViewHolderHeader extends RecyclerView.ViewHolder { - TextView header; + final MissionsHeaderBinding binding; - ViewHolderHeader(View view) { - super(view); - header = itemView.findViewById(R.id.item_name); + ViewHolderHeader(final MissionsHeaderBinding binding) { + super(binding.getRoot()); + this.binding = binding; } } diff --git a/app/src/main/java/us/shandian/giga/ui/fragment/MissionsFragment.java b/app/src/main/java/us/shandian/giga/ui/fragment/MissionsFragment.java index 3270b2b6f72..552ffa1e60c 100644 --- a/app/src/main/java/us/shandian/giga/ui/fragment/MissionsFragment.java +++ b/app/src/main/java/us/shandian/giga/ui/fragment/MissionsFragment.java @@ -23,11 +23,11 @@ import androidx.preference.PreferenceManager; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; import com.nononsenseapps.filepicker.Utils; import org.schabi.newpipe.R; +import org.schabi.newpipe.databinding.MissionsBinding; import org.schabi.newpipe.settings.NewPipeSettings; import org.schabi.newpipe.util.FilePickerActivityHelper; import org.schabi.newpipe.util.ThemeHelper; @@ -54,8 +54,8 @@ public class MissionsFragment extends Fragment { private MenuItem mStart = null; private MenuItem mPause = null; - private RecyclerView mList; - private View mEmpty; + private MissionsBinding mMissionsBinding; + private MissionAdapter mAdapter; private GridLayoutManager mGridManager; private LinearLayoutManager mLinearManager; @@ -73,7 +73,8 @@ public void onServiceConnected(ComponentName name, IBinder binder) { mBinder = (DownloadManagerBinder) binder; mBinder.clearDownloadNotifications(); - mAdapter = new MissionAdapter(mContext, mBinder.getDownloadManager(), mEmpty, getView()); + mAdapter = new MissionAdapter(mContext, mBinder.getDownloadManager(), + mMissionsBinding.listEmptyView, requireView()); mAdapter.setRecover(MissionsFragment.this::recoverMission); @@ -89,13 +90,11 @@ public void onServiceConnected(ComponentName name, IBinder binder) { public void onServiceDisconnected(ComponentName name) { // What to do? } - - }; @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View v = inflater.inflate(R.layout.missions, container, false); + mMissionsBinding = MissionsBinding.inflate(inflater, container, false); mPrefs = PreferenceManager.getDefaultSharedPreferences(requireActivity()); mLinear = mPrefs.getBoolean("linear", false); @@ -103,10 +102,6 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, // Bind the service mContext.bindService(new Intent(mContext, DownloadManagerService.class), mConnection, Context.BIND_AUTO_CREATE); - // Views - mEmpty = v.findViewById(R.id.list_empty_view); - mList = v.findViewById(R.id.mission_recycler); - // Init layouts managers mGridManager = new GridLayoutManager(getActivity(), SPAN_SIZE); mGridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @@ -125,38 +120,20 @@ public int getSpanSize(int position) { setHasOptionsMenu(true); - return v; + return mMissionsBinding.getRoot(); } - /** - * Added in API level 23. - */ @Override public void onAttach(@NonNull Context context) { super.onAttach(context); - // Bug: in api< 23 this is never called - // so mActivity=null - // so app crashes with null-pointer exception mContext = context; } - /** - * deprecated in API level 23, - * but must remain to allow compatibility with api<23 - */ - @SuppressWarnings("deprecation") - @Override - public void onAttach(@NonNull Activity activity) { - super.onAttach(activity); - - mContext = activity; - } - - @Override public void onDestroy() { super.onDestroy(); + if (mBinder == null || mAdapter == null) return; mBinder.removeMissionEventListener(mAdapter); @@ -166,6 +143,8 @@ public void onDestroy() { mBinder = null; mAdapter = null; + + mMissionsBinding = null; } @Override @@ -209,19 +188,15 @@ public boolean onOptionsItemSelected(MenuItem item) { } private void updateList() { - if (mLinear) { - mList.setLayoutManager(mLinearManager); - } else { - mList.setLayoutManager(mGridManager); - } + mMissionsBinding.missionRecycler.setLayoutManager(mLinear ? mLinearManager : mGridManager); // destroy all created views in the recycler - mList.setAdapter(null); + mMissionsBinding.missionRecycler.setAdapter(null); mAdapter.notifyDataSetChanged(); // re-attach the adapter in grid/lineal mode mAdapter.setLinear(mLinear); - mList.setAdapter(mAdapter); + mMissionsBinding.missionRecycler.setAdapter(mAdapter); if (mSwitch != null) { mSwitch.setIcon(ThemeHelper.resolveResourceIdFromAttr( From 2b417f61f6d0437f037f3efef420ac97eef159e5 Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Mon, 18 Jan 2021 07:24:03 +0530 Subject: [PATCH 04/19] Use view binding in PlaylistCreationDialog. --- .../local/dialog/PlaylistCreationDialog.java | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistCreationDialog.java b/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistCreationDialog.java index 4d19f0dd91f..73732ad3f56 100644 --- a/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistCreationDialog.java +++ b/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistCreationDialog.java @@ -2,24 +2,30 @@ import android.app.AlertDialog; import android.app.Dialog; +import android.content.DialogInterface; import android.os.Bundle; -import android.view.View; -import android.widget.EditText; +import android.view.LayoutInflater; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import org.jetbrains.annotations.NotNull; import org.schabi.newpipe.NewPipeDatabase; import org.schabi.newpipe.R; import org.schabi.newpipe.database.stream.model.StreamEntity; +import org.schabi.newpipe.databinding.DialogPlaylistNameBinding; import org.schabi.newpipe.local.playlist.LocalPlaylistManager; import java.util.List; import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; +import io.reactivex.rxjava3.disposables.Disposable; public final class PlaylistCreationDialog extends PlaylistDialog { + private DialogPlaylistNameBinding binding; + private Disposable disposable; + public static PlaylistCreationDialog newInstance(final List streams) { final PlaylistCreationDialog dialog = new PlaylistCreationDialog(); dialog.setInfo(streams); @@ -43,27 +49,35 @@ public Dialog onCreateDialog(@Nullable final Bundle savedInstanceState) { return super.onCreateDialog(savedInstanceState); } - final View dialogView = View.inflate(getContext(), R.layout.dialog_playlist_name, null); - final EditText nameInput = dialogView.findViewById(R.id.playlist_name); + binding = DialogPlaylistNameBinding.inflate(LayoutInflater.from(requireContext())); - final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(getContext()) + final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(requireContext()) .setTitle(R.string.create_playlist) - .setView(dialogView) + .setView(binding.getRoot()) .setCancelable(true) .setNegativeButton(R.string.cancel, null) .setPositiveButton(R.string.create, (dialogInterface, i) -> { - final String name = nameInput.getText().toString(); + final String name = binding.playlistName.getText().toString(); final LocalPlaylistManager playlistManager = - new LocalPlaylistManager(NewPipeDatabase.getInstance(getContext())); + new LocalPlaylistManager(NewPipeDatabase.getInstance(requireContext())); final Toast successToast = Toast.makeText(getActivity(), R.string.playlist_creation_success, Toast.LENGTH_SHORT); - playlistManager.createPlaylist(name, getStreams()) + disposable = playlistManager.createPlaylist(name, getStreams()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(longs -> successToast.show()); }); return dialogBuilder.create(); } + + @Override + public void onDismiss(@NonNull @NotNull DialogInterface dialog) { + super.onDismiss(dialog); + if (disposable != null) { + disposable.dispose(); + } + binding = null; + } } From a8e2a17a881f3dad1b4f7f46b9af8f34984f6426 Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Mon, 18 Jan 2021 07:29:32 +0530 Subject: [PATCH 05/19] Use view binding in AddTabDialog. --- .../newpipe/settings/tabs/AddTabDialog.java | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/settings/tabs/AddTabDialog.java b/app/src/main/java/org/schabi/newpipe/settings/tabs/AddTabDialog.java index 52e50fbbae5..087dd84e664 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/tabs/AddTabDialog.java +++ b/app/src/main/java/org/schabi/newpipe/settings/tabs/AddTabDialog.java @@ -7,13 +7,12 @@ import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; -import android.widget.TextView; import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; -import androidx.appcompat.widget.AppCompatImageView; import org.schabi.newpipe.R; +import org.schabi.newpipe.databinding.ListChooseTabsDialogBinding; import org.schabi.newpipe.util.ThemeHelper; public final class AddTabDialog { @@ -80,19 +79,19 @@ public long getItemId(final int position) { @Override public View getView(final int position, final View view, final ViewGroup parent) { - View convertView = view; - if (convertView == null) { - convertView = inflater.inflate(R.layout.list_choose_tabs_dialog, parent, false); + final ListChooseTabsDialogBinding binding; + if (view == null) { + binding = ListChooseTabsDialogBinding.inflate(inflater, parent, false); + } else { + binding = ListChooseTabsDialogBinding.bind(view); } final ChooseTabListItem item = getItem(position); - final AppCompatImageView tabIconView = convertView.findViewById(R.id.tabIcon); - final TextView tabNameView = convertView.findViewById(R.id.tabName); - tabIconView.setImageResource(item.itemIcon > 0 ? item.itemIcon : fallbackIcon); - tabNameView.setText(item.itemName); + binding.tabIcon.setImageResource(item.itemIcon > 0 ? item.itemIcon : fallbackIcon); + binding.tabName.setText(item.itemName); - return convertView; + return binding.getRoot(); } } } From d765fbab57c45f7c2d13d63ef13dc9a85e12cbf7 Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Mon, 18 Jan 2021 07:35:22 +0530 Subject: [PATCH 06/19] Use view binding in InfoItemDialog. --- .../newpipe/info_list/InfoItemDialog.java | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/info_list/InfoItemDialog.java b/app/src/main/java/org/schabi/newpipe/info_list/InfoItemDialog.java index 8f00e50fde7..330f5e8f211 100644 --- a/app/src/main/java/org/schabi/newpipe/info_list/InfoItemDialog.java +++ b/app/src/main/java/org/schabi/newpipe/info_list/InfoItemDialog.java @@ -3,13 +3,13 @@ import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; +import android.view.LayoutInflater; import android.view.View; -import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import org.schabi.newpipe.R; +import org.schabi.newpipe.databinding.DialogTitleBinding; import org.schabi.newpipe.extractor.stream.StreamInfoItem; public class InfoItemDialog { @@ -27,23 +27,21 @@ public InfoItemDialog(@NonNull final Activity activity, @NonNull final DialogInterface.OnClickListener actions, @NonNull final String title, @Nullable final String additionalDetail) { + final DialogTitleBinding binding = DialogTitleBinding + .inflate(LayoutInflater.from(activity)); + binding.getRoot().setSelected(true); - final View bannerView = View.inflate(activity, R.layout.dialog_title, null); - bannerView.setSelected(true); + binding.itemTitleView.setText(title); - final TextView titleView = bannerView.findViewById(R.id.itemTitleView); - titleView.setText(title); - - final TextView detailsView = bannerView.findViewById(R.id.itemAdditionalDetails); if (additionalDetail != null) { - detailsView.setText(additionalDetail); - detailsView.setVisibility(View.VISIBLE); + binding.itemAdditionalDetails.setText(additionalDetail); + binding.itemAdditionalDetails.setVisibility(View.VISIBLE); } else { - detailsView.setVisibility(View.GONE); + binding.itemAdditionalDetails.setVisibility(View.GONE); } dialog = new AlertDialog.Builder(activity) - .setCustomTitle(bannerView) + .setCustomTitle(binding.getRoot()) .setItems(commands, actions) .create(); } From 6aca797a21ee365bcc0ab6a07462273da8553c21 Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Mon, 18 Jan 2021 08:07:43 +0530 Subject: [PATCH 07/19] Use view binding in PlaybackParameterDialog. --- .../helper/PlaybackParameterDialog.java | 231 ++++++------------ 1 file changed, 80 insertions(+), 151 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java index a9a36e2f52a..e4d33887410 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java @@ -2,12 +2,11 @@ import android.app.Dialog; import android.content.Context; +import android.content.DialogInterface; import android.os.Bundle; import android.util.Log; -import android.view.View; -import android.widget.CheckBox; +import android.view.LayoutInflater; import android.widget.SeekBar; -import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -16,6 +15,7 @@ import androidx.preference.PreferenceManager; import org.schabi.newpipe.R; +import org.schabi.newpipe.databinding.DialogPlaybackParameterBinding; import org.schabi.newpipe.util.SliderStrategy; import static org.schabi.newpipe.player.Player.DEBUG; @@ -40,21 +40,14 @@ public class PlaybackParameterDialog extends DialogFragment { private static final double DEFAULT_STEP = STEP_TWENTY_FIVE_PERCENT_VALUE; private static final boolean DEFAULT_SKIP_SILENCE = false; - @NonNull private static final String TAG = "PlaybackParameterDialog"; - @NonNull private static final String INITIAL_TEMPO_KEY = "initial_tempo_key"; - @NonNull private static final String INITIAL_PITCH_KEY = "initial_pitch_key"; - @NonNull private static final String TEMPO_KEY = "tempo_key"; - @NonNull private static final String PITCH_KEY = "pitch_key"; - @NonNull private static final String STEP_SIZE_KEY = "step_size_key"; - @NonNull private final SliderStrategy strategy = new SliderStrategy.Quadratic( MINIMUM_PLAYBACK_VALUE, MAXIMUM_PLAYBACK_VALUE, /*centerAt=*/1.00f, /*sliderGranularity=*/10000); @@ -70,25 +63,7 @@ public class PlaybackParameterDialog extends DialogFragment { private double stepSize = DEFAULT_STEP; @Nullable - private SeekBar tempoSlider; - @Nullable - private TextView tempoCurrentText; - @Nullable - private TextView tempoStepDownText; - @Nullable - private TextView tempoStepUpText; - @Nullable - private SeekBar pitchSlider; - @Nullable - private TextView pitchCurrentText; - @Nullable - private TextView pitchStepDownText; - @Nullable - private TextView pitchStepUpText; - @Nullable - private CheckBox unhookingCheckbox; - @Nullable - private CheckBox skipSilenceCheckbox; + private DialogPlaybackParameterBinding binding; public static PlaybackParameterDialog newInstance(final double playbackTempo, final double playbackPitch, @@ -111,7 +86,7 @@ public static PlaybackParameterDialog newInstance(final double playbackTempo, //////////////////////////////////////////////////////////////////////////*/ @Override - public void onAttach(final Context context) { + public void onAttach(@NonNull final Context context) { super.onAttach(context); if (context instanceof Callback) { callback = (Callback) context; @@ -135,7 +110,7 @@ public void onCreate(@Nullable final Bundle savedInstanceState) { } @Override - public void onSaveInstanceState(final Bundle outState) { + public void onSaveInstanceState(@NonNull final Bundle outState) { super.onSaveInstanceState(outState); outState.putDouble(INITIAL_TEMPO_KEY, initialTempo); outState.putDouble(INITIAL_PITCH_KEY, initialPitch); @@ -153,12 +128,12 @@ public void onSaveInstanceState(final Bundle outState) { @Override public Dialog onCreateDialog(@Nullable final Bundle savedInstanceState) { assureCorrectAppLanguage(getContext()); - final View view = View.inflate(getContext(), R.layout.dialog_playback_parameter, null); - setupControlViews(view); + binding = DialogPlaybackParameterBinding.inflate(LayoutInflater.from(requireContext())); + setupControlViews(); final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(requireActivity()) .setTitle(R.string.playback_speed_control) - .setView(view) + .setView(binding.getRoot()) .setCancelable(true) .setNegativeButton(R.string.cancel, (dialogInterface, i) -> setPlaybackParameters(initialTempo, initialPitch, initialSkipSilence)) @@ -170,80 +145,57 @@ public Dialog onCreateDialog(@Nullable final Bundle savedInstanceState) { return dialogBuilder.create(); } + @Override + public void onDismiss(@NonNull final DialogInterface dialog) { + super.onDismiss(dialog); + binding = null; + } + /*////////////////////////////////////////////////////////////////////////// // Control Views //////////////////////////////////////////////////////////////////////////*/ - private void setupControlViews(@NonNull final View rootView) { - setupHookingControl(rootView); - setupSkipSilenceControl(rootView); + private void setupControlViews() { + setupHookingControl(); + setupSkipSilenceControl(); - setupTempoControl(rootView); - setupPitchControl(rootView); + setupTempoControl(); + setupPitchControl(); setStepSize(stepSize); - setupStepSizeSelector(rootView); + setupStepSizeSelector(); } - private void setupTempoControl(@NonNull final View rootView) { - tempoSlider = rootView.findViewById(R.id.tempoSeekbar); - final TextView tempoMinimumText = rootView.findViewById(R.id.tempoMinimumText); - final TextView tempoMaximumText = rootView.findViewById(R.id.tempoMaximumText); - tempoCurrentText = rootView.findViewById(R.id.tempoCurrentText); - tempoStepUpText = rootView.findViewById(R.id.tempoStepUp); - tempoStepDownText = rootView.findViewById(R.id.tempoStepDown); - - if (tempoCurrentText != null) { - tempoCurrentText.setText(PlayerHelper.formatSpeed(tempo)); - } - if (tempoMaximumText != null) { - tempoMaximumText.setText(PlayerHelper.formatSpeed(MAXIMUM_PLAYBACK_VALUE)); - } - if (tempoMinimumText != null) { - tempoMinimumText.setText(PlayerHelper.formatSpeed(MINIMUM_PLAYBACK_VALUE)); - } - - if (tempoSlider != null) { - tempoSlider.setMax(strategy.progressOf(MAXIMUM_PLAYBACK_VALUE)); - tempoSlider.setProgress(strategy.progressOf(tempo)); - tempoSlider.setOnSeekBarChangeListener(getOnTempoChangedListener()); + private void setupTempoControl() { + if (binding != null) { + binding.tempoCurrentText.setText(PlayerHelper.formatSpeed(tempo)); + binding.tempoMaximumText.setText(PlayerHelper.formatSpeed(MAXIMUM_PLAYBACK_VALUE)); + binding.tempoMinimumText.setText(PlayerHelper.formatSpeed(MINIMUM_PLAYBACK_VALUE)); + binding.tempoSeekbar.setMax(strategy.progressOf(MAXIMUM_PLAYBACK_VALUE)); + binding.tempoSeekbar.setProgress(strategy.progressOf(tempo)); + binding.tempoSeekbar.setOnSeekBarChangeListener(getOnTempoChangedListener()); } } - private void setupPitchControl(@NonNull final View rootView) { - pitchSlider = rootView.findViewById(R.id.pitchSeekbar); - final TextView pitchMinimumText = rootView.findViewById(R.id.pitchMinimumText); - final TextView pitchMaximumText = rootView.findViewById(R.id.pitchMaximumText); - pitchCurrentText = rootView.findViewById(R.id.pitchCurrentText); - pitchStepDownText = rootView.findViewById(R.id.pitchStepDown); - pitchStepUpText = rootView.findViewById(R.id.pitchStepUp); - - if (pitchCurrentText != null) { - pitchCurrentText.setText(PlayerHelper.formatPitch(pitch)); - } - if (pitchMaximumText != null) { - pitchMaximumText.setText(PlayerHelper.formatPitch(MAXIMUM_PLAYBACK_VALUE)); - } - if (pitchMinimumText != null) { - pitchMinimumText.setText(PlayerHelper.formatPitch(MINIMUM_PLAYBACK_VALUE)); - } - - if (pitchSlider != null) { - pitchSlider.setMax(strategy.progressOf(MAXIMUM_PLAYBACK_VALUE)); - pitchSlider.setProgress(strategy.progressOf(pitch)); - pitchSlider.setOnSeekBarChangeListener(getOnPitchChangedListener()); + private void setupPitchControl() { + if (binding != null) { + binding.pitchCurrentText.setText(PlayerHelper.formatPitch(pitch)); + binding.pitchMaximumText.setText(PlayerHelper.formatPitch(MAXIMUM_PLAYBACK_VALUE)); + binding.pitchMinimumText.setText(PlayerHelper.formatPitch(MINIMUM_PLAYBACK_VALUE)); + binding.pitchSeekbar.setMax(strategy.progressOf(MAXIMUM_PLAYBACK_VALUE)); + binding.pitchSeekbar.setProgress(strategy.progressOf(pitch)); + binding.pitchSeekbar.setOnSeekBarChangeListener(getOnPitchChangedListener()); } } - private void setupHookingControl(@NonNull final View rootView) { - unhookingCheckbox = rootView.findViewById(R.id.unhookCheckbox); - if (unhookingCheckbox != null) { + private void setupHookingControl() { + if (binding != null) { // restore whether pitch and tempo are unhooked or not - unhookingCheckbox.setChecked(PreferenceManager + binding.unhookCheckbox.setChecked(PreferenceManager .getDefaultSharedPreferences(requireContext()) .getBoolean(getString(R.string.playback_unhook_key), true)); - unhookingCheckbox.setOnCheckedChangeListener((compoundButton, isChecked) -> { + binding.unhookCheckbox.setOnCheckedChangeListener((compoundButton, isChecked) -> { // save whether pitch and tempo are unhooked or not PreferenceManager.getDefaultSharedPreferences(requireContext()) .edit() @@ -260,53 +212,36 @@ private void setupHookingControl(@NonNull final View rootView) { } } - private void setupSkipSilenceControl(@NonNull final View rootView) { - skipSilenceCheckbox = rootView.findViewById(R.id.skipSilenceCheckbox); - if (skipSilenceCheckbox != null) { - skipSilenceCheckbox.setChecked(initialSkipSilence); - skipSilenceCheckbox.setOnCheckedChangeListener((compoundButton, isChecked) -> + private void setupSkipSilenceControl() { + if (binding != null) { + binding.skipSilenceCheckbox.setChecked(initialSkipSilence); + binding.skipSilenceCheckbox.setOnCheckedChangeListener((compoundButton, isChecked) -> setCurrentPlaybackParameters()); } } - private void setupStepSizeSelector(@NonNull final View rootView) { - final TextView stepSizeOnePercentText = rootView.findViewById(R.id.stepSizeOnePercent); - final TextView stepSizeFivePercentText = rootView.findViewById(R.id.stepSizeFivePercent); - final TextView stepSizeTenPercentText = rootView.findViewById(R.id.stepSizeTenPercent); - final TextView stepSizeTwentyFivePercentText = rootView - .findViewById(R.id.stepSizeTwentyFivePercent); - final TextView stepSizeOneHundredPercentText = rootView - .findViewById(R.id.stepSizeOneHundredPercent); - - if (stepSizeOnePercentText != null) { - stepSizeOnePercentText.setText(getPercentString(STEP_ONE_PERCENT_VALUE)); - stepSizeOnePercentText + private void setupStepSizeSelector() { + if (binding != null) { + binding.stepSizeOnePercent.setText(getPercentString(STEP_ONE_PERCENT_VALUE)); + binding.stepSizeOnePercent .setOnClickListener(view -> setStepSize(STEP_ONE_PERCENT_VALUE)); - } - if (stepSizeFivePercentText != null) { - stepSizeFivePercentText.setText(getPercentString(STEP_FIVE_PERCENT_VALUE)); - stepSizeFivePercentText + binding.stepSizeFivePercent.setText(getPercentString(STEP_FIVE_PERCENT_VALUE)); + binding.stepSizeFivePercent .setOnClickListener(view -> setStepSize(STEP_FIVE_PERCENT_VALUE)); - } - if (stepSizeTenPercentText != null) { - stepSizeTenPercentText.setText(getPercentString(STEP_TEN_PERCENT_VALUE)); - stepSizeTenPercentText + binding.stepSizeTenPercent.setText(getPercentString(STEP_TEN_PERCENT_VALUE)); + binding.stepSizeTenPercent .setOnClickListener(view -> setStepSize(STEP_TEN_PERCENT_VALUE)); - } - if (stepSizeTwentyFivePercentText != null) { - stepSizeTwentyFivePercentText + binding.stepSizeTwentyFivePercent .setText(getPercentString(STEP_TWENTY_FIVE_PERCENT_VALUE)); - stepSizeTwentyFivePercentText + binding.stepSizeTwentyFivePercent .setOnClickListener(view -> setStepSize(STEP_TWENTY_FIVE_PERCENT_VALUE)); - } - if (stepSizeOneHundredPercentText != null) { - stepSizeOneHundredPercentText + binding.stepSizeOneHundredPercent .setText(getPercentString(STEP_ONE_HUNDRED_PERCENT_VALUE)); - stepSizeOneHundredPercentText + binding.stepSizeOneHundredPercent .setOnClickListener(view -> setStepSize(STEP_ONE_HUNDRED_PERCENT_VALUE)); } } @@ -314,33 +249,27 @@ private void setupStepSizeSelector(@NonNull final View rootView) { private void setStepSize(final double stepSize) { this.stepSize = stepSize; - if (tempoStepUpText != null) { - tempoStepUpText.setText(getStepUpPercentString(stepSize)); - tempoStepUpText.setOnClickListener(view -> { + if (binding != null) { + binding.tempoStepUp.setText(getStepUpPercentString(stepSize)); + binding.tempoStepUp.setOnClickListener(view -> { onTempoSliderUpdated(getCurrentTempo() + stepSize); setCurrentPlaybackParameters(); }); - } - if (tempoStepDownText != null) { - tempoStepDownText.setText(getStepDownPercentString(stepSize)); - tempoStepDownText.setOnClickListener(view -> { + binding.tempoStepDown.setText(getStepDownPercentString(stepSize)); + binding.tempoStepDown.setOnClickListener(view -> { onTempoSliderUpdated(getCurrentTempo() - stepSize); setCurrentPlaybackParameters(); }); - } - if (pitchStepUpText != null) { - pitchStepUpText.setText(getStepUpPercentString(stepSize)); - pitchStepUpText.setOnClickListener(view -> { + binding.pitchStepUp.setText(getStepUpPercentString(stepSize)); + binding.pitchStepUp.setOnClickListener(view -> { onPitchSliderUpdated(getCurrentPitch() + stepSize); setCurrentPlaybackParameters(); }); - } - if (pitchStepDownText != null) { - pitchStepDownText.setText(getStepDownPercentString(stepSize)); - pitchStepDownText.setOnClickListener(view -> { + binding.pitchStepDown.setText(getStepDownPercentString(stepSize)); + binding.pitchStepDown.setOnClickListener(view -> { onPitchSliderUpdated(getCurrentPitch() - stepSize); setCurrentPlaybackParameters(); }); @@ -400,10 +329,10 @@ public void onStopTrackingTouch(final SeekBar seekBar) { } private void onTempoSliderUpdated(final double newTempo) { - if (unhookingCheckbox == null) { + if (binding == null) { return; } - if (!unhookingCheckbox.isChecked()) { + if (!binding.unhookCheckbox.isChecked()) { setSliders(newTempo); } else { setTempoSlider(newTempo); @@ -411,10 +340,10 @@ private void onTempoSliderUpdated(final double newTempo) { } private void onPitchSliderUpdated(final double newPitch) { - if (unhookingCheckbox == null) { + if (binding == null) { return; } - if (!unhookingCheckbox.isChecked()) { + if (!binding.unhookCheckbox.isChecked()) { setSliders(newPitch); } else { setPitchSlider(newPitch); @@ -427,17 +356,17 @@ private void setSliders(final double newValue) { } private void setTempoSlider(final double newTempo) { - if (tempoSlider == null) { + if (binding == null) { return; } - tempoSlider.setProgress(strategy.progressOf(newTempo)); + binding.tempoSeekbar.setProgress(strategy.progressOf(newTempo)); } private void setPitchSlider(final double newPitch) { - if (pitchSlider == null) { + if (binding == null) { return; } - pitchSlider.setProgress(strategy.progressOf(newPitch)); + binding.pitchSeekbar.setProgress(strategy.progressOf(newPitch)); } /*////////////////////////////////////////////////////////////////////////// @@ -450,25 +379,25 @@ private void setCurrentPlaybackParameters() { private void setPlaybackParameters(final double newTempo, final double newPitch, final boolean skipSilence) { - if (callback != null && tempoCurrentText != null && pitchCurrentText != null) { + if (callback != null && binding != null) { if (DEBUG) { Log.d(TAG, "Setting playback parameters to " + "tempo=[" + newTempo + "], " + "pitch=[" + newPitch + "]"); } - tempoCurrentText.setText(PlayerHelper.formatSpeed(newTempo)); - pitchCurrentText.setText(PlayerHelper.formatPitch(newPitch)); + binding.tempoCurrentText.setText(PlayerHelper.formatSpeed(newTempo)); + binding.pitchCurrentText.setText(PlayerHelper.formatPitch(newPitch)); callback.onPlaybackParameterChanged((float) newTempo, (float) newPitch, skipSilence); } } private double getCurrentTempo() { - return tempoSlider == null ? tempo : strategy.valueOf(tempoSlider.getProgress()); + return binding == null ? tempo : strategy.valueOf(binding.tempoSeekbar.getProgress()); } private double getCurrentPitch() { - return pitchSlider == null ? pitch : strategy.valueOf(pitchSlider.getProgress()); + return binding == null ? pitch : strategy.valueOf(binding.pitchSeekbar.getProgress()); } private double getCurrentStepSize() { @@ -476,7 +405,7 @@ private double getCurrentStepSize() { } private boolean getCurrentSkipSilence() { - return skipSilenceCheckbox != null && skipSilenceCheckbox.isChecked(); + return binding != null && binding.skipSilenceCheckbox.isChecked(); } @NonNull From 9522fe46af294e5f6fb49f3800ee82cec615aef2 Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Mon, 18 Jan 2021 08:15:33 +0530 Subject: [PATCH 08/19] Use view binding in LocalPlaylistFragment. --- .../local/playlist/LocalPlaylistFragment.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java index 3137de9e6f7..8da2e2a94e8 100644 --- a/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java +++ b/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java @@ -13,7 +13,6 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import android.widget.EditText; import android.widget.Toast; import androidx.annotation.NonNull; @@ -32,6 +31,7 @@ import org.schabi.newpipe.database.playlist.PlaylistStreamEntry; import org.schabi.newpipe.database.stream.model.StreamEntity; import org.schabi.newpipe.database.stream.model.StreamStateEntity; +import org.schabi.newpipe.databinding.DialogPlaylistNameBinding; import org.schabi.newpipe.databinding.LocalPlaylistHeaderBinding; import org.schabi.newpipe.databinding.PlaylistControlBinding; import org.schabi.newpipe.extractor.stream.StreamInfoItem; @@ -531,18 +531,18 @@ private void createRenameDialog() { return; } - final View dialogView = View.inflate(getContext(), R.layout.dialog_playlist_name, null); - final EditText nameEdit = dialogView.findViewById(R.id.playlist_name); - nameEdit.setText(name); - nameEdit.setSelection(nameEdit.getText().length()); + final DialogPlaylistNameBinding binding = DialogPlaylistNameBinding + .inflate(LayoutInflater.from(requireContext())); + binding.playlistName.setText(name); + binding.playlistName.setSelection(binding.playlistName.getText().length()); final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(getContext()) .setTitle(R.string.rename_playlist) - .setView(dialogView) + .setView(binding.getRoot()) .setCancelable(true) .setNegativeButton(R.string.cancel, null) .setPositiveButton(R.string.rename, (dialogInterface, i) -> - changePlaylistName(nameEdit.getText().toString())); + changePlaylistName(binding.playlistName.getText().toString())); dialogBuilder.show(); } From 0d896ab14e2a615d30def95e3701683e0c74baa2 Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Mon, 18 Jan 2021 08:22:59 +0530 Subject: [PATCH 09/19] Use view binding in ChooseTabsFragment. --- .../settings/tabs/ChooseTabsFragment.java | 90 +++++++++---------- 1 file changed, 44 insertions(+), 46 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/settings/tabs/ChooseTabsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/tabs/ChooseTabsFragment.java index cbc47392b9f..a3e30434883 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/tabs/ChooseTabsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/tabs/ChooseTabsFragment.java @@ -1,8 +1,8 @@ package org.schabi.newpipe.settings.tabs; import android.annotation.SuppressLint; -import android.app.Dialog; import android.content.Context; +import android.content.DialogInterface; import android.os.Bundle; import android.view.LayoutInflater; import android.view.Menu; @@ -11,22 +11,19 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.content.res.AppCompatResources; -import androidx.appcompat.widget.AppCompatImageView; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import com.google.android.material.floatingactionbutton.FloatingActionButton; - import org.schabi.newpipe.R; +import org.schabi.newpipe.databinding.FragmentChooseTabsBinding; +import org.schabi.newpipe.databinding.ListChooseTabsBinding; import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.report.ErrorInfo; @@ -51,6 +48,8 @@ public class ChooseTabsFragment extends Fragment { private final List tabList = new ArrayList<>(); private ChooseTabsFragment.SelectedTabsAdapter selectedTabsAdapter; + private FragmentChooseTabsBinding binding; + /*////////////////////////////////////////////////////////////////////////// // Lifecycle //////////////////////////////////////////////////////////////////////////*/ @@ -75,17 +74,23 @@ public View onCreateView(@NonNull final LayoutInflater inflater, final ViewGroup public void onViewCreated(@NonNull final View rootView, @Nullable final Bundle savedInstanceState) { super.onViewCreated(rootView, savedInstanceState); + binding = FragmentChooseTabsBinding.bind(rootView); - initButton(rootView); + initButton(); - final RecyclerView listSelectedTabs = rootView.findViewById(R.id.selectedTabs); - listSelectedTabs.setLayoutManager(new LinearLayoutManager(requireContext())); + binding.selectedTabs.setLayoutManager(new LinearLayoutManager(requireContext())); final ItemTouchHelper itemTouchHelper = new ItemTouchHelper(getItemTouchCallback()); - itemTouchHelper.attachToRecyclerView(listSelectedTabs); + itemTouchHelper.attachToRecyclerView(binding.selectedTabs); selectedTabsAdapter = new SelectedTabsAdapter(requireContext(), itemTouchHelper); - listSelectedTabs.setAdapter(selectedTabsAdapter); + binding.selectedTabs.setAdapter(selectedTabsAdapter); + } + + @Override + public void onDestroy() { + super.onDestroy(); + binding = null; } @Override @@ -106,7 +111,8 @@ public void onPause() { //////////////////////////////////////////////////////////////////////////*/ @Override - public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { + public void onCreateOptionsMenu(@NonNull final Menu menu, + @NonNull final MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); final MenuItem restoreItem = menu.add(Menu.NONE, MENU_ITEM_RESTORE_ID, Menu.NONE, @@ -154,23 +160,20 @@ private void restoreDefaults() { .show(); } - private void initButton(final View rootView) { - final FloatingActionButton fab = rootView.findViewById(R.id.addTabsButton); - fab.setOnClickListener(v -> { + private void initButton() { + binding.addTabsButton.setOnClickListener(v -> { final ChooseTabListItem[] availableTabs = getAvailableTabs(requireContext()); if (availableTabs.length == 0) { - //Toast.makeText(requireContext(), "No available tabs", Toast.LENGTH_SHORT).show(); return; } - final Dialog.OnClickListener actionListener = (dialog, which) -> { + final DialogInterface.OnClickListener actionListener = (dialog, which) -> { final ChooseTabListItem selected = availableTabs[which]; addTab(selected.tabId); }; - new AddTabDialog(requireContext(), availableTabs, actionListener) - .show(); + new AddTabDialog(requireContext(), availableTabs, actionListener).show(); }); } @@ -195,13 +198,13 @@ private void addTab(final int tabId) { final SelectKioskFragment selectKioskFragment = new SelectKioskFragment(); selectKioskFragment.setOnSelectedListener((serviceId, kioskId, kioskName) -> addTab(new Tab.KioskTab(serviceId, kioskId))); - selectKioskFragment.show(requireFragmentManager(), "select_kiosk"); + selectKioskFragment.show(getParentFragmentManager(), "select_kiosk"); return; case CHANNEL: final SelectChannelFragment selectChannelFragment = new SelectChannelFragment(); selectChannelFragment.setOnSelectedListener((serviceId, url, name) -> addTab(new Tab.ChannelTab(serviceId, url, name))); - selectChannelFragment.show(requireFragmentManager(), "select_channel"); + selectChannelFragment.show(getParentFragmentManager(), "select_channel"); return; case PLAYLIST: final SelectPlaylistFragment selectPlaylistFragment = new SelectPlaylistFragment(); @@ -218,7 +221,7 @@ public void onRemotePlaylistSelected( addTab(new Tab.PlaylistTab(serviceId, url, name)); } }); - selectPlaylistFragment.show(requireFragmentManager(), "select_playlist"); + selectPlaylistFragment.show(getParentFragmentManager(), "select_playlist"); return; default: addTab(type.getTab()); @@ -281,7 +284,7 @@ private ItemTouchHelper.SimpleCallback getItemTouchCallback() { return new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.START | ItemTouchHelper.END) { @Override - public int interpolateOutOfBoundsScroll(final RecyclerView recyclerView, + public int interpolateOutOfBoundsScroll(@NonNull final RecyclerView recyclerView, final int viewSize, final int viewSizeOutOfBounds, final int totalSize, @@ -294,9 +297,9 @@ public int interpolateOutOfBoundsScroll(final RecyclerView recyclerView, } @Override - public boolean onMove(final RecyclerView recyclerView, - final RecyclerView.ViewHolder source, - final RecyclerView.ViewHolder target) { + public boolean onMove(@NonNull final RecyclerView recyclerView, + @NonNull final RecyclerView.ViewHolder source, + @NonNull final RecyclerView.ViewHolder target) { if (source.getItemViewType() != target.getItemViewType() || selectedTabsAdapter == null) { return false; @@ -319,7 +322,8 @@ public boolean isItemViewSwipeEnabled() { } @Override - public void onSwiped(final RecyclerView.ViewHolder viewHolder, final int swipeDir) { + public void onSwiped(@NonNull final RecyclerView.ViewHolder viewHolder, + final int swipeDir) { final int position = viewHolder.getAdapterPosition(); tabList.remove(position); selectedTabsAdapter.notifyItemRemoved(position); @@ -351,8 +355,8 @@ public void swapItems(final int fromPosition, final int toPosition) { @Override public ChooseTabsFragment.SelectedTabsAdapter.TabViewHolder onCreateViewHolder( @NonNull final ViewGroup parent, final int viewType) { - final View view = inflater.inflate(R.layout.list_choose_tabs, parent, false); - return new ChooseTabsFragment.SelectedTabsAdapter.TabViewHolder(view); + return new ChooseTabsFragment.SelectedTabsAdapter + .TabViewHolder(ListChooseTabsBinding.inflate(inflater, parent, false)); } @Override @@ -368,21 +372,16 @@ public int getItemCount() { } class TabViewHolder extends RecyclerView.ViewHolder { - private final AppCompatImageView tabIconView; - private final TextView tabNameView; - private final ImageView handle; - - TabViewHolder(final View itemView) { - super(itemView); + private final ListChooseTabsBinding binding; - tabNameView = itemView.findViewById(R.id.tabName); - tabIconView = itemView.findViewById(R.id.tabIcon); - handle = itemView.findViewById(R.id.handle); + TabViewHolder(final ListChooseTabsBinding binding) { + super(binding.getRoot()); + this.binding = binding; } @SuppressLint("ClickableViewAccessibility") void bind(final int position, final TabViewHolder holder) { - handle.setOnTouchListener(getOnTouchListener(holder)); + binding.handle.setOnTouchListener(getOnTouchListener(holder)); final Tab tab = tabList.get(position); final Tab.Type type = Tab.typeFrom(tab.getTabId()); @@ -419,18 +418,17 @@ void bind(final int position, final TabViewHolder holder) { break; } - tabNameView.setText(tabName); - tabIconView.setImageResource(tab.getTabIconRes(requireContext())); + binding.tabName.setText(tabName); + binding.tabIcon.setImageResource(tab.getTabIconRes(requireContext())); } @SuppressLint("ClickableViewAccessibility") private View.OnTouchListener getOnTouchListener(final RecyclerView.ViewHolder item) { return (view, motionEvent) -> { - if (motionEvent.getActionMasked() == MotionEvent.ACTION_DOWN) { - if (itemTouchHelper != null && getItemCount() > 1) { - itemTouchHelper.startDrag(item); - return true; - } + if (motionEvent.getActionMasked() == MotionEvent.ACTION_DOWN + && itemTouchHelper != null && getItemCount() > 1) { + itemTouchHelper.startDrag(item); + return true; } return false; }; From 7611f7a6e5256c347434e39956569d4385cdcfdc Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Mon, 18 Jan 2021 08:32:59 +0530 Subject: [PATCH 10/19] Use SubscriptionImportExportItemBinding in FeedImportExportItem. --- .../subscription/item/FeedImportExportItem.kt | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/local/subscription/item/FeedImportExportItem.kt b/app/src/main/java/org/schabi/newpipe/local/subscription/item/FeedImportExportItem.kt index afca7064f98..c16f02db89c 100644 --- a/app/src/main/java/org/schabi/newpipe/local/subscription/item/FeedImportExportItem.kt +++ b/app/src/main/java/org/schabi/newpipe/local/subscription/item/FeedImportExportItem.kt @@ -2,15 +2,15 @@ package org.schabi.newpipe.local.subscription.item import android.graphics.Color import android.graphics.PorterDuff +import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.ImageView -import android.widget.TextView import androidx.annotation.DrawableRes import com.xwray.groupie.viewbinding.BindableItem import com.xwray.groupie.viewbinding.GroupieViewHolder import org.schabi.newpipe.R import org.schabi.newpipe.databinding.FeedImportExportGroupBinding +import org.schabi.newpipe.databinding.SubscriptionImportExportItemBinding import org.schabi.newpipe.extractor.NewPipe import org.schabi.newpipe.extractor.exceptions.ExtractionException import org.schabi.newpipe.ktx.animateRotation @@ -71,16 +71,14 @@ class FeedImportExportItem( private var expandIconListener: CollapsibleView.StateListener? = null - private fun addItemView(title: String, @DrawableRes icon: Int, container: ViewGroup): View { - val itemRoot = View.inflate(container.context, R.layout.subscription_import_export_item, null) - val titleView = itemRoot.findViewById(android.R.id.text1) - val iconView = itemRoot.findViewById(android.R.id.icon1) - - titleView.text = title - iconView.setImageResource(icon) - - container.addView(itemRoot) - return itemRoot + private fun addItemView( + title: String, + @DrawableRes icon: Int, + container: ViewGroup + ) = SubscriptionImportExportItemBinding.inflate(LayoutInflater.from(container.context)).apply { + text1.text = title + icon1.setImageResource(icon) + container.addView(root) } private fun setupImportFromItems(listHolder: ViewGroup) { @@ -88,7 +86,7 @@ class FeedImportExportItem( listHolder.context.getString(R.string.previous_export), ThemeHelper.resolveResourceIdFromAttr(listHolder.context, R.attr.ic_backup), listHolder ) - previousBackupItem.setOnClickListener { onImportPreviousSelected() } + previousBackupItem.root.setOnClickListener { onImportPreviousSelected() } val iconColor = if (ThemeHelper.isLightThemeSelected(listHolder.context)) Color.BLACK else Color.WHITE val services = listHolder.context.resources.getStringArray(R.array.service_list) @@ -102,10 +100,9 @@ class FeedImportExportItem( if (supportedSources.isEmpty()) continue val itemView = addItemView(serviceName, ServiceHelper.getIcon(service.serviceId), listHolder) - val iconView = itemView.findViewById(android.R.id.icon1) - iconView.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN) + itemView.icon1.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN) - itemView.setOnClickListener { onImportFromServiceSelected(service.serviceId) } + itemView.root.setOnClickListener { onImportFromServiceSelected(service.serviceId) } } catch (e: ExtractionException) { throw RuntimeException("Services array contains an entry that it's not a valid service name ($serviceName)", e) } @@ -118,6 +115,6 @@ class FeedImportExportItem( ThemeHelper.resolveResourceIdFromAttr(listHolder.context, R.attr.ic_save), listHolder ) - previousBackupItem.setOnClickListener { onExportSelected() } + previousBackupItem.root.setOnClickListener { onExportSelected() } } } From 2174863df96f5c61290bdce3ac5d159cedca9e73 Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Mon, 18 Jan 2021 08:41:53 +0530 Subject: [PATCH 11/19] Use ToolbarSearchLayoutBinding in SearchFragment. --- .../fragments/list/search/SearchFragment.java | 139 +++++++++--------- 1 file changed, 69 insertions(+), 70 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java index 5273fd396df..0c490ad09c4 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java @@ -20,7 +20,6 @@ import android.view.animation.DecelerateInterpolator; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; -import android.widget.EditText; import android.widget.TextView; import androidx.annotation.NonNull; @@ -28,6 +27,7 @@ import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.widget.TooltipCompat; +import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import androidx.core.text.HtmlCompat; import androidx.preference.PreferenceManager; @@ -38,6 +38,7 @@ import org.schabi.newpipe.ReCaptchaActivity; import org.schabi.newpipe.database.history.model.SearchHistoryEntry; import org.schabi.newpipe.databinding.FragmentSearchBinding; +import org.schabi.newpipe.databinding.ToolbarSearchLayoutBinding; import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.ListExtractor; import org.schabi.newpipe.extractor.MetaInfo; @@ -157,16 +158,8 @@ public class SearchFragment extends BaseListFragment savedObjects) throws Exception @Override public void onSaveInstanceState(@NonNull final Bundle bundle) { - searchString = searchEditText != null - ? searchEditText.getText().toString() + searchString = searchLayoutBinding != null + ? searchLayoutBinding.toolbarSearchEditText.getText().toString() : searchString; super.onSaveInstanceState(bundle); } @@ -404,13 +393,15 @@ public void onSaveInstanceState(@NonNull final Bundle bundle) { @Override public void reloadContent() { if (!TextUtils.isEmpty(searchString) - || (searchEditText != null && !TextUtils.isEmpty(searchEditText.getText()))) { + || (searchLayoutBinding != null + && !TextUtils.isEmpty(searchLayoutBinding.toolbarSearchEditText.getText()))) { search(!TextUtils.isEmpty(searchString) ? searchString - : searchEditText.getText().toString(), this.contentFilter, ""); + : searchLayoutBinding.toolbarSearchEditText.getText().toString(), + contentFilter, ""); } else { - if (searchEditText != null) { - searchEditText.setText(""); + if (searchLayoutBinding != null) { + searchLayoutBinding.toolbarSearchEditText.setText(""); showKeyboardSearch(); } animate(errorPanelRoot, false, 200); @@ -496,21 +487,22 @@ private void showSearchOnStart() { + ", lastSearchedQuery → " + lastSearchedString); } - searchEditText.setText(searchString); - - if (TextUtils.isEmpty(searchString) || TextUtils.isEmpty(searchEditText.getText())) { - searchToolbarContainer.setTranslationX(100); - searchToolbarContainer.setAlpha(0.0f); - searchToolbarContainer.setVisibility(View.VISIBLE); - searchToolbarContainer.animate() + searchLayoutBinding.toolbarSearchEditText.setText(searchString); + + if (TextUtils.isEmpty(searchString) + || TextUtils.isEmpty(searchLayoutBinding.toolbarSearchEditText.getText())) { + searchLayoutBinding.getRoot().setTranslationX(100); + searchLayoutBinding.getRoot().setAlpha(0.0f); + searchLayoutBinding.getRoot().setVisibility(View.VISIBLE); + searchLayoutBinding.getRoot().animate() .translationX(0) .alpha(1.0f) .setDuration(200) .setInterpolator(new DecelerateInterpolator()).start(); } else { - searchToolbarContainer.setTranslationX(0); - searchToolbarContainer.setAlpha(1.0f); - searchToolbarContainer.setVisibility(View.VISIBLE); + searchLayoutBinding.getRoot().setTranslationX(0); + searchLayoutBinding.getRoot().setAlpha(1.0f); + searchLayoutBinding.getRoot().setVisibility(View.VISIBLE); } } @@ -518,25 +510,26 @@ private void initSearchListeners() { if (DEBUG) { Log.d(TAG, "initSearchListeners() called"); } - searchClear.setOnClickListener(v -> { + searchLayoutBinding.toolbarSearchClear.setOnClickListener(v -> { if (DEBUG) { Log.d(TAG, "onClick() called with: v = [" + v + "]"); } - if (TextUtils.isEmpty(searchEditText.getText())) { + if (TextUtils.isEmpty(searchLayoutBinding.toolbarSearchEditText.getText())) { NavigationHelper.gotoMainFragment(getFM()); return; } searchBinding.correctSuggestion.setVisibility(View.GONE); - searchEditText.setText(""); + searchLayoutBinding.toolbarSearchEditText.setText(""); suggestionListAdapter.setItems(new ArrayList<>()); showKeyboardSearch(); }); - TooltipCompat.setTooltipText(searchClear, getString(R.string.clear)); + TooltipCompat.setTooltipText(searchLayoutBinding.toolbarSearchClear, + getString(R.string.clear)); - searchEditText.setOnClickListener(v -> { + searchLayoutBinding.toolbarSearchEditText.setOnClickListener(v -> { if (DEBUG) { Log.d(TAG, "onClick() called with: v = [" + v + "]"); } @@ -548,7 +541,7 @@ private void initSearchListeners() { } }); - searchEditText.setOnFocusChangeListener((View v, boolean hasFocus) -> { + searchLayoutBinding.toolbarSearchEditText.setOnFocusChangeListener((v, hasFocus) -> { if (DEBUG) { Log.d(TAG, "onFocusChange() called with: " + "v = [" + v + "], hasFocus = [" + hasFocus + "]"); @@ -563,13 +556,14 @@ private void initSearchListeners() { @Override public void onSuggestionItemSelected(final SuggestionItem item) { search(item.query, new String[0], ""); - searchEditText.setText(item.query); + searchLayoutBinding.toolbarSearchEditText.setText(item.query); } @Override public void onSuggestionItemInserted(final SuggestionItem item) { - searchEditText.setText(item.query); - searchEditText.setSelection(searchEditText.getText().length()); + searchLayoutBinding.toolbarSearchEditText.setText(item.query); + searchLayoutBinding.toolbarSearchEditText + .setSelection(searchLayoutBinding.toolbarSearchEditText.getText().length()); } @Override @@ -581,7 +575,7 @@ public void onSuggestionItemLongClick(final SuggestionItem item) { }); if (textWatcher != null) { - searchEditText.removeTextChangedListener(textWatcher); + searchLayoutBinding.toolbarSearchEditText.removeTextChangedListener(textWatcher); } textWatcher = new TextWatcher() { @Override @@ -596,12 +590,13 @@ public void onTextChanged(final CharSequence s, final int start, @Override public void afterTextChanged(final Editable s) { - final String newText = searchEditText.getText().toString(); + final String newText = searchLayoutBinding.toolbarSearchEditText.getText() + .toString(); suggestionPublisher.onNext(newText); } }; - searchEditText.addTextChangedListener(textWatcher); - searchEditText.setOnEditorActionListener( + searchLayoutBinding.toolbarSearchEditText.addTextChangedListener(textWatcher); + searchLayoutBinding.toolbarSearchEditText.setOnEditorActionListener( (TextView v, int actionId, KeyEvent event) -> { if (DEBUG) { Log.d(TAG, "onEditorAction() called with: v = [" + v + "], " @@ -612,7 +607,8 @@ public void afterTextChanged(final Editable s) { } else if (event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER || event.getAction() == EditorInfo.IME_ACTION_SEARCH)) { - search(searchEditText.getText().toString(), new String[0], ""); + search(searchLayoutBinding.toolbarSearchEditText.getText().toString(), + new String[0], ""); return true; } return false; @@ -627,14 +623,14 @@ private void unsetSearchListeners() { if (DEBUG) { Log.d(TAG, "unsetSearchListeners() called"); } - searchClear.setOnClickListener(null); - searchClear.setOnLongClickListener(null); - searchEditText.setOnClickListener(null); - searchEditText.setOnFocusChangeListener(null); - searchEditText.setOnEditorActionListener(null); + searchLayoutBinding.toolbarSearchClear.setOnClickListener(null); + searchLayoutBinding.toolbarSearchClear.setOnLongClickListener(null); + searchLayoutBinding.toolbarSearchEditText.setOnClickListener(null); + searchLayoutBinding.toolbarSearchEditText.setOnFocusChangeListener(null); + searchLayoutBinding.toolbarSearchEditText.setOnEditorActionListener(null); if (textWatcher != null) { - searchEditText.removeTextChangedListener(textWatcher); + searchLayoutBinding.toolbarSearchEditText.removeTextChangedListener(textWatcher); } textWatcher = null; } @@ -661,14 +657,15 @@ private void showKeyboardSearch() { if (DEBUG) { Log.d(TAG, "showKeyboardSearch() called"); } - if (searchEditText == null) { + if (searchLayoutBinding == null) { return; } - if (searchEditText.requestFocus()) { + if (searchLayoutBinding.toolbarSearchEditText.requestFocus()) { final InputMethodManager imm = ContextCompat.getSystemService(activity, InputMethodManager.class); - imm.showSoftInput(searchEditText, InputMethodManager.SHOW_FORCED); + imm.showSoftInput(searchLayoutBinding.toolbarSearchEditText, + InputMethodManager.SHOW_FORCED); } } @@ -676,20 +673,20 @@ private void hideKeyboardSearch() { if (DEBUG) { Log.d(TAG, "hideKeyboardSearch() called"); } - if (searchEditText == null) { + if (searchLayoutBinding == null) { return; } final InputMethodManager imm = ContextCompat.getSystemService(activity, InputMethodManager.class); - imm.hideSoftInputFromWindow(searchEditText.getWindowToken(), + imm.hideSoftInputFromWindow(searchLayoutBinding.toolbarSearchEditText.getWindowToken(), InputMethodManager.RESULT_UNCHANGED_SHOWN); - searchEditText.clearFocus(); + searchLayoutBinding.toolbarSearchEditText.clearFocus(); } private void showDeleteSuggestionDialog(final SuggestionItem item) { - if (activity == null || historyRecordManager == null || searchEditText == null) { + if (activity == null || historyRecordManager == null || searchLayoutBinding == null) { return; } final String query = item.query; @@ -703,7 +700,8 @@ private void showDeleteSuggestionDialog(final SuggestionItem item) { .observeOn(AndroidSchedulers.mainThread()) .subscribe( howManyDeleted -> suggestionPublisher - .onNext(searchEditText.getText().toString()), + .onNext(searchLayoutBinding.toolbarSearchEditText + .getText().toString()), throwable -> showSnackBarError(throwable, UserAction.DELETE_FROM_HISTORY, "none", "Deleting item failed", R.string.general_error)); @@ -719,7 +717,7 @@ public boolean onBackPressed() { && !isLoading.get()) { hideSuggestionsPanel(); hideKeyboardSearch(); - searchEditText.setText(lastSearchedString); + searchLayoutBinding.toolbarSearchEditText.setText(lastSearchedString); return true; } return false; @@ -1002,8 +1000,8 @@ public void handleResult(@NonNull final SearchInfo result) { // List cannot be bundled without creating some containers metaInfo = new MetaInfo[result.getMetaInfo().size()]; metaInfo = result.getMetaInfo().toArray(metaInfo); - disposables.add(showMetaInfoInTextView(result.getMetaInfo(), metaInfoTextView, - metaInfoSeparator)); + disposables.add(showMetaInfoInTextView(result.getMetaInfo(), + searchBinding.searchMetaInfoTextView, searchBinding.searchMetaInfoSeparator)); handleSearchSuggestion(); @@ -1040,12 +1038,12 @@ private void handleSearchSuggestion() { searchBinding.correctSuggestion.setOnClickListener(v -> { searchBinding.correctSuggestion.setVisibility(View.GONE); search(searchSuggestion, contentFilter, sortFilter); - searchEditText.setText(searchSuggestion); + searchLayoutBinding.toolbarSearchEditText.setText(searchSuggestion); }); searchBinding.correctSuggestion.setOnLongClickListener(v -> { - searchEditText.setText(searchSuggestion); - searchEditText.setSelection(searchSuggestion.length()); + searchLayoutBinding.toolbarSearchEditText.setText(searchSuggestion); + searchLayoutBinding.toolbarSearchEditText.setSelection(searchSuggestion.length()); showKeyboardSearch(); return true; }); @@ -1112,7 +1110,8 @@ public void onSuggestionItemSwiped(@NonNull final RecyclerView.ViewHolder viewHo .observeOn(AndroidSchedulers.mainThread()) .subscribe( howManyDeleted -> suggestionPublisher - .onNext(searchEditText.getText().toString()), + .onNext(searchLayoutBinding.toolbarSearchEditText.getText() + .toString()), throwable -> showSnackBarError(throwable, UserAction.DELETE_FROM_HISTORY, "none", "Deleting item failed", R.string.general_error)); From aa631cd6d04b7f8614125e13821c32f78e2a69aa Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Mon, 18 Jan 2021 08:46:17 +0530 Subject: [PATCH 12/19] Use view binding in StreamSegmentItem. --- .../newpipe/info_list/StreamSegmentItem.kt | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/info_list/StreamSegmentItem.kt b/app/src/main/java/org/schabi/newpipe/info_list/StreamSegmentItem.kt index 798b9b287b7..d870022e967 100644 --- a/app/src/main/java/org/schabi/newpipe/info_list/StreamSegmentItem.kt +++ b/app/src/main/java/org/schabi/newpipe/info_list/StreamSegmentItem.kt @@ -1,11 +1,10 @@ package org.schabi.newpipe.info_list -import android.widget.ImageView -import android.widget.TextView +import android.view.View import com.nostra13.universalimageloader.core.ImageLoader -import com.xwray.groupie.GroupieViewHolder -import com.xwray.groupie.Item +import com.xwray.groupie.viewbinding.BindableItem import org.schabi.newpipe.R +import org.schabi.newpipe.databinding.ItemStreamSegmentBinding import org.schabi.newpipe.extractor.stream.StreamSegment import org.schabi.newpipe.util.ImageDisplayConstants import org.schabi.newpipe.util.Localization @@ -13,34 +12,34 @@ import org.schabi.newpipe.util.Localization class StreamSegmentItem( private val item: StreamSegment, private val onClick: StreamSegmentAdapter.StreamSegmentListener -) : Item() { - +) : BindableItem() { companion object { const val PAYLOAD_SELECT = 1 } var isSelected = false - override fun bind(viewHolder: GroupieViewHolder, position: Int) { + override fun initializeViewBinding(view: View) = ItemStreamSegmentBinding.bind(view) + + override fun bind(viewBinding: ItemStreamSegmentBinding, position: Int) { item.previewUrl?.let { ImageLoader.getInstance().displayImage( - it, viewHolder.root.findViewById(R.id.previewImage), + it, viewBinding.previewImage, ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS ) } - viewHolder.root.findViewById(R.id.textViewTitle).text = item.title - viewHolder.root.findViewById(R.id.textViewStartSeconds).text = - Localization.getDurationString(item.startTimeSeconds.toLong()) - viewHolder.root.setOnClickListener { onClick.onItemClick(this, item.startTimeSeconds) } - viewHolder.root.isSelected = isSelected + viewBinding.textViewTitle.text = item.title + viewBinding.textViewStartSeconds.text = Localization.getDurationString(item.startTimeSeconds.toLong()) + viewBinding.root.setOnClickListener { onClick.onItemClick(this, item.startTimeSeconds) } + viewBinding.root.isSelected = isSelected } - override fun bind(viewHolder: GroupieViewHolder, position: Int, payloads: MutableList) { + override fun bind(viewBinding: ItemStreamSegmentBinding, position: Int, payloads: MutableList) { if (payloads.contains(PAYLOAD_SELECT)) { - viewHolder.root.isSelected = isSelected + viewBinding.root.isSelected = isSelected return } - super.bind(viewHolder, position, payloads) + super.bind(viewBinding, position, payloads) } override fun getLayout() = R.layout.item_stream_segment From 8919580bf84cd861c59161ca1b44576aa03ee196 Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Mon, 18 Jan 2021 08:50:32 +0530 Subject: [PATCH 13/19] Add calls to 'metadataView' in Player. --- app/src/main/java/org/schabi/newpipe/player/Player.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/Player.java b/app/src/main/java/org/schabi/newpipe/player/Player.java index ba8e856df73..9c9c4c5a7d9 100644 --- a/app/src/main/java/org/schabi/newpipe/player/Player.java +++ b/app/src/main/java/org/schabi/newpipe/player/Player.java @@ -925,7 +925,7 @@ private void setupElementsVisibility() { binding.fullScreenButton.setVisibility(View.VISIBLE); binding.screenRotationButton.setVisibility(View.GONE); binding.resizeTextView.setVisibility(View.GONE); - binding.getRoot().findViewById(R.id.metadataView).setVisibility(View.GONE); + binding.metadataView.setVisibility(View.GONE); binding.queueButton.setVisibility(View.GONE); binding.segmentsButton.setVisibility(View.GONE); binding.moreOptionsButton.setVisibility(View.GONE); @@ -949,7 +949,7 @@ private void setupElementsVisibility() { binding.fullScreenButton.setVisibility(View.GONE); setupScreenRotationButton(); binding.resizeTextView.setVisibility(View.VISIBLE); - binding.getRoot().findViewById(R.id.metadataView).setVisibility(View.VISIBLE); + binding.metadataView.setVisibility(View.VISIBLE); binding.moreOptionsButton.setVisibility(View.VISIBLE); binding.topControls.setOrientation(LinearLayout.VERTICAL); binding.primaryControls.getLayoutParams().width From 611ba5669d779a93650882e65d71b7b4dcfea75a Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Mon, 18 Jan 2021 08:53:44 +0530 Subject: [PATCH 14/19] Use view binding in PlaylistAppendDialog. --- .../local/dialog/PlaylistAppendDialog.java | 24 +++++++++++-------- .../local/dialog/PlaylistCreationDialog.java | 3 +-- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistAppendDialog.java b/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistAppendDialog.java index 93e1141c7ff..b27e064f45f 100644 --- a/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistAppendDialog.java +++ b/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistAppendDialog.java @@ -10,13 +10,13 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; import org.schabi.newpipe.NewPipeDatabase; import org.schabi.newpipe.R; import org.schabi.newpipe.database.LocalItem; import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry; import org.schabi.newpipe.database.stream.model.StreamEntity; +import org.schabi.newpipe.databinding.DialogPlaylistsBinding; import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.local.LocalItemListAdapter; @@ -35,7 +35,7 @@ public final class PlaylistAppendDialog extends PlaylistDialog { private static final String TAG = PlaylistAppendDialog.class.getCanonicalName(); - private RecyclerView playlistRecyclerView; + private DialogPlaylistsBinding binding; private LocalItemListAdapter playlistAdapter; private final CompositeDisposable playlistDisposables = new CompositeDisposable(); @@ -96,6 +96,7 @@ public View onCreateView(@NonNull final LayoutInflater inflater, final ViewGroup @Override public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); + binding = DialogPlaylistsBinding.bind(view); final LocalPlaylistManager playlistManager = new LocalPlaylistManager(NewPipeDatabase.getInstance(requireContext())); @@ -112,12 +113,10 @@ public void selected(final LocalItem selectedItem) { } }); - playlistRecyclerView = view.findViewById(R.id.playlist_list); - playlistRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext())); - playlistRecyclerView.setAdapter(playlistAdapter); + binding.playlistList.setLayoutManager(new LinearLayoutManager(requireContext())); + binding.playlistList.setAdapter(playlistAdapter); - final View newPlaylistButton = view.findViewById(R.id.newPlaylist); - newPlaylistButton.setOnClickListener(ignored -> openCreatePlaylistDialog()); + binding.newPlaylist.setOnClickListener(ignored -> openCreatePlaylistDialog()); playlistDisposables.add(playlistManager.getPlaylists() .observeOn(AndroidSchedulers.mainThread()) @@ -128,6 +127,12 @@ public void selected(final LocalItem selectedItem) { // LifeCycle - Destruction //////////////////////////////////////////////////////////////////////////*/ + @Override + public void onDestroy() { + super.onDestroy(); + binding = null; + } + @Override public void onDestroyView() { super.onDestroyView(); @@ -137,7 +142,6 @@ public void onDestroyView() { } playlistDisposables.clear(); - playlistRecyclerView = null; playlistAdapter = null; } @@ -155,10 +159,10 @@ public void openCreatePlaylistDialog() { } private void onPlaylistsReceived(@NonNull final List playlists) { - if (playlistAdapter != null && playlistRecyclerView != null) { + if (playlistAdapter != null && binding != null) { playlistAdapter.clearStreamItemList(); playlistAdapter.addItems(playlists); - playlistRecyclerView.setVisibility(View.VISIBLE); + binding.playlistList.setVisibility(View.VISIBLE); } } diff --git a/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistCreationDialog.java b/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistCreationDialog.java index 73732ad3f56..ef9680c7720 100644 --- a/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistCreationDialog.java +++ b/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistCreationDialog.java @@ -10,7 +10,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import org.jetbrains.annotations.NotNull; import org.schabi.newpipe.NewPipeDatabase; import org.schabi.newpipe.R; import org.schabi.newpipe.database.stream.model.StreamEntity; @@ -73,7 +72,7 @@ public Dialog onCreateDialog(@Nullable final Bundle savedInstanceState) { } @Override - public void onDismiss(@NonNull @NotNull DialogInterface dialog) { + public void onDismiss(@NonNull final DialogInterface dialog) { super.onDismiss(dialog); if (disposable != null) { disposable.dispose(); From 42a910b5d29b86d67e6108770c7a700668bca1da Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Mon, 18 Jan 2021 08:56:26 +0530 Subject: [PATCH 15/19] Use view binding in BookmarkFragment. --- .../newpipe/local/bookmark/BookmarkFragment.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/local/bookmark/BookmarkFragment.java b/app/src/main/java/org/schabi/newpipe/local/bookmark/BookmarkFragment.java index ee77db89f19..4077171bb2a 100644 --- a/app/src/main/java/org/schabi/newpipe/local/bookmark/BookmarkFragment.java +++ b/app/src/main/java/org/schabi/newpipe/local/bookmark/BookmarkFragment.java @@ -8,7 +8,6 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.EditText; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -23,6 +22,7 @@ import org.schabi.newpipe.database.playlist.PlaylistLocalItem; import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry; import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity; +import org.schabi.newpipe.databinding.DialogBookmarkBinding; import org.schabi.newpipe.local.BaseLocalListFragment; import org.schabi.newpipe.local.playlist.LocalPlaylistManager; import org.schabi.newpipe.local.playlist.RemotePlaylistManager; @@ -265,14 +265,15 @@ private void showRemoteDeleteDialog(final PlaylistRemoteEntity item) { } private void showLocalDialog(final PlaylistMetadataEntry selectedItem) { - final View dialogView = View.inflate(getContext(), R.layout.dialog_bookmark, null); - final EditText editText = dialogView.findViewById(R.id.playlist_name_edit_text); - editText.setText(selectedItem.name); + final DialogBookmarkBinding binding = DialogBookmarkBinding + .inflate(LayoutInflater.from(requireContext())); + binding.playlistNameEditText.setText(selectedItem.name); final Builder builder = new AlertDialog.Builder(activity); - builder.setView(dialogView) + builder.setView(binding.getRoot()) .setPositiveButton(R.string.rename_playlist, (dialog, which) -> - changeLocalPlaylistName(selectedItem.uid, editText.getText().toString())) + changeLocalPlaylistName(selectedItem.uid, + binding.playlistNameEditText.getText().toString())) .setNegativeButton(R.string.cancel, null) .setNeutralButton(R.string.delete, (dialog, which) -> { showDeleteDialog(selectedItem.name, From 250b307753714a3aaccd0d87fd56defc49737411 Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Tue, 19 Jan 2021 06:35:08 +0530 Subject: [PATCH 16/19] Use view binding in PlayQueueItemHolder. --- .../org/schabi/newpipe/player/Player.java | 2 +- .../player/playqueue/PlayQueueAdapter.java | 21 ++++++++------ .../playqueue/PlayQueueItemBuilder.java | 25 +++++++++-------- .../player/playqueue/PlayQueueItemHolder.java | 28 ++++--------------- 4 files changed, 31 insertions(+), 45 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/Player.java b/app/src/main/java/org/schabi/newpipe/player/Player.java index 9c9c4c5a7d9..9860218e434 100644 --- a/app/src/main/java/org/schabi/newpipe/player/Player.java +++ b/app/src/main/java/org/schabi/newpipe/player/Player.java @@ -733,7 +733,7 @@ private void initPlayback(@NonNull final PlayQueue queue, if (playQueueAdapter != null) { playQueueAdapter.dispose(); } - playQueueAdapter = new PlayQueueAdapter(context, playQueue); + playQueueAdapter = new PlayQueueAdapter(playQueue); segmentAdapter = new StreamSegmentAdapter(getStreamSegmentListener()); simpleExoPlayer.setVolume(isMuted ? 0 : 1); diff --git a/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueueAdapter.java b/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueueAdapter.java index 462b9eb53db..faa871cc52b 100644 --- a/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueueAdapter.java +++ b/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueueAdapter.java @@ -1,6 +1,5 @@ package org.schabi.newpipe.player.playqueue; -import android.content.Context; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -9,7 +8,7 @@ import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; -import org.schabi.newpipe.R; +import org.schabi.newpipe.databinding.PlayQueueItemBinding; import org.schabi.newpipe.player.playqueue.events.AppendEvent; import org.schabi.newpipe.player.playqueue.events.ErrorEvent; import org.schabi.newpipe.player.playqueue.events.MoveEvent; @@ -60,12 +59,12 @@ public class PlayQueueAdapter extends RecyclerView.Adapter 0) { - holder.itemDurationView.setText(Localization.getDurationString(item.getDuration())); + holder.binding.itemDurationView + .setText(Localization.getDurationString(item.getDuration())); } else { - holder.itemDurationView.setVisibility(View.GONE); + holder.binding.itemDurationView.setVisibility(View.GONE); } - ImageLoader.getInstance().displayImage(item.getThumbnailUrl(), holder.itemThumbnailView, - ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS); + ImageLoader.getInstance().displayImage(item.getThumbnailUrl(), + holder.binding.itemThumbnailView, ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS); - holder.itemRoot.setOnClickListener(view -> { + holder.binding.itemRoot.setOnClickListener(view -> { if (onItemClickListener != null) { onItemClickListener.selected(item, view); } }); - holder.itemRoot.setOnLongClickListener(view -> { + holder.binding.itemRoot.setOnLongClickListener(view -> { if (onItemClickListener != null) { onItemClickListener.held(item, view); return true; @@ -52,7 +53,7 @@ public void buildStreamInfoItem(final PlayQueueItemHolder holder, final PlayQueu return false; }); - holder.itemHandle.setOnTouchListener(getOnTouchListener(holder)); + holder.binding.itemHandle.setOnTouchListener(getOnTouchListener(holder)); } private View.OnTouchListener getOnTouchListener(final PlayQueueItemHolder holder) { diff --git a/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueueItemHolder.java b/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueueItemHolder.java index c4641034359..cbe2d73487b 100644 --- a/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueueItemHolder.java +++ b/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueueItemHolder.java @@ -1,12 +1,8 @@ package org.schabi.newpipe.player.playqueue; -import android.view.View; -import android.widget.ImageView; -import android.widget.TextView; - import androidx.recyclerview.widget.RecyclerView; -import org.schabi.newpipe.R; +import org.schabi.newpipe.databinding.PlayQueueItemBinding; /** * Created by Christian Schabesberger on 01.08.16. @@ -33,24 +29,10 @@ */ public class PlayQueueItemHolder extends RecyclerView.ViewHolder { - public final TextView itemVideoTitleView; - public final TextView itemDurationView; - final TextView itemAdditionalDetailsView; - - final ImageView itemSelected; - public final ImageView itemThumbnailView; - final ImageView itemHandle; - - public final View itemRoot; + final PlayQueueItemBinding binding; - PlayQueueItemHolder(final View v) { - super(v); - itemRoot = v.findViewById(R.id.itemRoot); - itemVideoTitleView = v.findViewById(R.id.itemVideoTitleView); - itemDurationView = v.findViewById(R.id.itemDurationView); - itemAdditionalDetailsView = v.findViewById(R.id.itemAdditionalDetails); - itemSelected = v.findViewById(R.id.itemSelected); - itemThumbnailView = v.findViewById(R.id.itemThumbnailView); - itemHandle = v.findViewById(R.id.itemHandle); + PlayQueueItemHolder(final PlayQueueItemBinding binding) { + super(binding.getRoot()); + this.binding = binding; } } From 43fcc699c6a0808cc7a86c0bdf409f1580c21149 Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Fri, 22 Jan 2021 08:32:29 +0530 Subject: [PATCH 17/19] Use view binding in SelectPlaylistFragment. --- .../settings/SelectPlaylistFragment.java | 67 ++++++++----------- 1 file changed, 29 insertions(+), 38 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/settings/SelectPlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/settings/SelectPlaylistFragment.java index 16ccd0953e4..87b00729941 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/SelectPlaylistFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/SelectPlaylistFragment.java @@ -5,9 +5,6 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.ProgressBar; -import android.widget.TextView; import androidx.annotation.NonNull; import androidx.fragment.app.DialogFragment; @@ -24,6 +21,8 @@ import org.schabi.newpipe.database.playlist.PlaylistLocalItem; import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry; import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity; +import org.schabi.newpipe.databinding.ListPlaylistMiniItemBinding; +import org.schabi.newpipe.databinding.SelectPlaylistFragmentBinding; import org.schabi.newpipe.local.playlist.LocalPlaylistManager; import org.schabi.newpipe.local.playlist.RemotePlaylistManager; import org.schabi.newpipe.report.ErrorActivity; @@ -48,9 +47,8 @@ public class SelectPlaylistFragment extends DialogFragment { private OnSelectedListener onSelectedListener = null; - private ProgressBar progressBar; - private TextView emptyView; - private RecyclerView recyclerView; + private SelectPlaylistFragmentBinding binding; + private Disposable disposable = null; private List playlists = new Vector<>(); @@ -66,17 +64,14 @@ public void setOnSelectedListener(final OnSelectedListener listener) { @Override public View onCreateView(@NonNull final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) { - final View v = inflater.inflate(R.layout.select_playlist_fragment, container, false); - progressBar = v.findViewById(R.id.progressBar); - recyclerView = v.findViewById(R.id.items_list); - emptyView = v.findViewById(R.id.empty_state_view); + binding = SelectPlaylistFragmentBinding.inflate(inflater, container, false); - recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); + binding.itemsList.setLayoutManager(new LinearLayoutManager(getContext())); final SelectPlaylistAdapter playlistAdapter = new SelectPlaylistAdapter(); - recyclerView.setAdapter(playlistAdapter); + binding.itemsList.setAdapter(playlistAdapter); loadPlaylists(); - return v; + return binding.getRoot(); } @Override @@ -85,6 +80,7 @@ public void onDestroy() { if (disposable != null) { disposable.dispose(); } + binding = null; } /*////////////////////////////////////////////////////////////////////////// @@ -92,9 +88,9 @@ public void onDestroy() { //////////////////////////////////////////////////////////////////////////*/ private void loadPlaylists() { - progressBar.setVisibility(View.VISIBLE); - recyclerView.setVisibility(View.GONE); - emptyView.setVisibility(View.GONE); + binding.progressBar.setVisibility(View.VISIBLE); + binding.itemsList.setVisibility(View.GONE); + binding.emptyStateView.setVisibility(View.GONE); final AppDatabase database = NewPipeDatabase.getInstance(requireContext()); final LocalPlaylistManager localPlaylistManager = new LocalPlaylistManager(database); @@ -108,9 +104,9 @@ private void loadPlaylists() { private void displayPlaylists(final List newPlaylists) { playlists = newPlaylists; - progressBar.setVisibility(View.GONE); - emptyView.setVisibility(newPlaylists.isEmpty() ? View.VISIBLE : View.GONE); - recyclerView.setVisibility(newPlaylists.isEmpty() ? View.GONE : View.VISIBLE); + binding.progressBar.setVisibility(View.GONE); + binding.emptyStateView.setVisibility(newPlaylists.isEmpty() ? View.VISIBLE : View.GONE); + binding.itemsList.setVisibility(newPlaylists.isEmpty() ? View.GONE : View.VISIBLE); } protected void onError(final Throwable e) { @@ -153,11 +149,10 @@ private class SelectPlaylistAdapter extends RecyclerView.Adapter { @NonNull @Override - public SelectPlaylistItemHolder onCreateViewHolder(final ViewGroup parent, + public SelectPlaylistItemHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) { - final View item = LayoutInflater.from(parent.getContext()) - .inflate(R.layout.list_playlist_mini_item, parent, false); - return new SelectPlaylistItemHolder(item); + return new SelectPlaylistItemHolder(ListPlaylistMiniItemBinding + .inflate(LayoutInflater.from(parent.getContext()), parent, false)); } @Override @@ -168,17 +163,17 @@ public void onBindViewHolder(@NonNull final SelectPlaylistItemHolder holder, if (selectedItem instanceof PlaylistMetadataEntry) { final PlaylistMetadataEntry entry = ((PlaylistMetadataEntry) selectedItem); - holder.titleView.setText(entry.name); - holder.view.setOnClickListener(view -> clickedItem(position)); - imageLoader.displayImage(entry.thumbnailUrl, holder.thumbnailView, + holder.binding.itemTitleView.setText(entry.name); + holder.binding.getRoot().setOnClickListener(view -> clickedItem(position)); + imageLoader.displayImage(entry.thumbnailUrl, holder.binding.itemThumbnailView, DISPLAY_IMAGE_OPTIONS); } else if (selectedItem instanceof PlaylistRemoteEntity) { final PlaylistRemoteEntity entry = ((PlaylistRemoteEntity) selectedItem); - holder.titleView.setText(entry.getName()); - holder.view.setOnClickListener(view -> clickedItem(position)); - imageLoader.displayImage(entry.getThumbnailUrl(), holder.thumbnailView, + holder.binding.itemTitleView.setText(entry.getName()); + holder.binding.getRoot().setOnClickListener(view -> clickedItem(position)); + imageLoader.displayImage(entry.getThumbnailUrl(), holder.binding.itemThumbnailView, DISPLAY_IMAGE_OPTIONS); } } @@ -189,15 +184,11 @@ public int getItemCount() { } public class SelectPlaylistItemHolder extends RecyclerView.ViewHolder { - public final View view; - final ImageView thumbnailView; - final TextView titleView; - - SelectPlaylistItemHolder(final View v) { - super(v); - this.view = v; - thumbnailView = v.findViewById(R.id.itemThumbnailView); - titleView = v.findViewById(R.id.itemTitleView); + private final ListPlaylistMiniItemBinding binding; + + SelectPlaylistItemHolder(final ListPlaylistMiniItemBinding binding) { + super(binding.getRoot()); + this.binding = binding; } } } From 8caeab7eda5a9f86baed326f1a8e5841c19c5b05 Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Tue, 2 Feb 2021 05:34:44 +0530 Subject: [PATCH 18/19] Use view binding in PeertubeInstanceListFragment. --- .../PeertubeInstanceListFragment.java | 96 +++++++------------ 1 file changed, 35 insertions(+), 61 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/settings/PeertubeInstanceListFragment.java b/app/src/main/java/org/schabi/newpipe/settings/PeertubeInstanceListFragment.java index bd3cbf79d69..9fbbb94d230 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/PeertubeInstanceListFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/PeertubeInstanceListFragment.java @@ -13,28 +13,25 @@ import android.view.View; import android.view.ViewGroup; import android.widget.EditText; -import android.widget.ImageView; -import android.widget.ProgressBar; import android.widget.RadioButton; -import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.content.res.AppCompatResources; -import androidx.appcompat.widget.AppCompatImageView; import androidx.fragment.app.Fragment; import androidx.preference.PreferenceManager; import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.grack.nanojson.JsonStringWriter; import com.grack.nanojson.JsonWriter; import org.schabi.newpipe.R; +import org.schabi.newpipe.databinding.FragmentInstanceListBinding; +import org.schabi.newpipe.databinding.ItemInstanceBinding; import org.schabi.newpipe.extractor.services.peertube.PeertubeInstance; import org.schabi.newpipe.util.Constants; import org.schabi.newpipe.util.PeertubeHelper; @@ -58,10 +55,10 @@ public class PeertubeInstanceListFragment extends Fragment { private String savedInstanceListKey; private InstanceListAdapter instanceListAdapter; - private ProgressBar progressBar; + private FragmentInstanceListBinding binding; private SharedPreferences sharedPreferences; - private CompositeDisposable disposables = new CompositeDisposable(); + private final CompositeDisposable disposables = new CompositeDisposable(); /*////////////////////////////////////////////////////////////////////////// // Lifecycle @@ -90,26 +87,19 @@ public void onViewCreated(@NonNull final View rootView, @Nullable final Bundle savedInstanceState) { super.onViewCreated(rootView, savedInstanceState); - initViews(rootView); - } - - private void initViews(@NonNull final View rootView) { - final TextView instanceHelpTV = rootView.findViewById(R.id.instanceHelpTV); - instanceHelpTV.setText(getString(R.string.peertube_instance_url_help, + binding = FragmentInstanceListBinding.inflate(getLayoutInflater()); + binding.instanceHelpTV.setText(getString(R.string.peertube_instance_url_help, getString(R.string.peertube_instance_list_url))); - initButton(rootView); + binding.addInstanceButton.setOnClickListener(v -> showAddItemDialog(requireContext())); - final RecyclerView listInstances = rootView.findViewById(R.id.instances); - listInstances.setLayoutManager(new LinearLayoutManager(requireContext())); + binding.instances.setLayoutManager(new LinearLayoutManager(requireContext())); final ItemTouchHelper itemTouchHelper = new ItemTouchHelper(getItemTouchCallback()); - itemTouchHelper.attachToRecyclerView(listInstances); + itemTouchHelper.attachToRecyclerView(binding.instances); instanceListAdapter = new InstanceListAdapter(requireContext(), itemTouchHelper); - listInstances.setAdapter(instanceListAdapter); - - progressBar = rootView.findViewById(R.id.loading_progress_bar); + binding.instances.setAdapter(instanceListAdapter); } @Override @@ -128,10 +118,8 @@ public void onPause() { @Override public void onDestroy() { super.onDestroy(); - if (disposables != null) { - disposables.clear(); - } - disposables = null; + disposables.clear(); + binding = null; } /*////////////////////////////////////////////////////////////////////////// @@ -139,7 +127,8 @@ public void onDestroy() { //////////////////////////////////////////////////////////////////////////*/ @Override - public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { + public void onCreateOptionsMenu(@NonNull final Menu menu, + @NonNull final MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); final MenuItem restoreItem = menu @@ -201,12 +190,6 @@ private void restoreDefaults() { .show(); } - private void initButton(final View rootView) { - final FloatingActionButton fab = rootView.findViewById(R.id.addInstanceButton); - fab.setOnClickListener(v -> - showAddItemDialog(requireContext())); - } - private void showAddItemDialog(final Context c) { final EditText urlET = new EditText(c); urlET.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI); @@ -229,17 +212,17 @@ private void addInstance(final String url) { if (cleanUrl == null) { return; } - progressBar.setVisibility(View.VISIBLE); + binding.loadingProgressBar.setVisibility(View.VISIBLE); final Disposable disposable = Single.fromCallable(() -> { final PeertubeInstance instance = new PeertubeInstance(cleanUrl); instance.fetchInstanceMetaData(); return instance; }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) .subscribe((instance) -> { - progressBar.setVisibility(View.GONE); + binding.loadingProgressBar.setVisibility(View.GONE); add(instance); }, e -> { - progressBar.setVisibility(View.GONE); + binding.loadingProgressBar.setVisibility(View.GONE); Toast.makeText(getActivity(), R.string.peertube_instance_add_fail, Toast.LENGTH_SHORT).show(); }); @@ -361,8 +344,8 @@ public void swapItems(final int fromPosition, final int toPosition) { @Override public InstanceListAdapter.TabViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) { - final View view = inflater.inflate(R.layout.item_instance, parent, false); - return new InstanceListAdapter.TabViewHolder(view); + return new InstanceListAdapter.TabViewHolder(ItemInstanceBinding.inflate(inflater, + parent, false)); } @Override @@ -377,47 +360,38 @@ public int getItemCount() { } class TabViewHolder extends RecyclerView.ViewHolder { - private final AppCompatImageView instanceIconView; - private final TextView instanceNameView; - private final TextView instanceUrlView; - private final RadioButton instanceRB; - private final ImageView handle; - - TabViewHolder(final View itemView) { - super(itemView); - - instanceIconView = itemView.findViewById(R.id.instanceIcon); - instanceNameView = itemView.findViewById(R.id.instanceName); - instanceUrlView = itemView.findViewById(R.id.instanceUrl); - instanceRB = itemView.findViewById(R.id.selectInstanceRB); - handle = itemView.findViewById(R.id.handle); + private final ItemInstanceBinding binding; + + TabViewHolder(final ItemInstanceBinding binding) { + super(binding.getRoot()); + this.binding = binding; } @SuppressLint("ClickableViewAccessibility") void bind(final int position, final TabViewHolder holder) { - handle.setOnTouchListener(getOnTouchListener(holder)); + binding.handle.setOnTouchListener(getOnTouchListener(holder)); final PeertubeInstance instance = instanceList.get(position); - instanceNameView.setText(instance.getName()); - instanceUrlView.setText(instance.getUrl()); - instanceRB.setOnCheckedChangeListener(null); + binding.instanceName.setText(instance.getName()); + binding.instanceUrl.setText(instance.getUrl()); + binding.selectInstanceRB.setOnCheckedChangeListener(null); if (selectedInstance.getUrl().equals(instance.getUrl())) { - if (lastChecked != null && lastChecked != instanceRB) { + if (lastChecked != null && lastChecked != binding.selectInstanceRB) { lastChecked.setChecked(false); } - instanceRB.setChecked(true); - lastChecked = instanceRB; + binding.selectInstanceRB.setChecked(true); + lastChecked = binding.selectInstanceRB; } - instanceRB.setOnCheckedChangeListener((buttonView, isChecked) -> { + binding.selectInstanceRB.setOnCheckedChangeListener((buttonView, isChecked) -> { if (isChecked) { selectInstance(instance); - if (lastChecked != null && lastChecked != instanceRB) { + if (lastChecked != null && lastChecked != binding.selectInstanceRB) { lastChecked.setChecked(false); } - lastChecked = instanceRB; + lastChecked = binding.selectInstanceRB; } }); - instanceIconView.setImageResource(R.drawable.place_holder_peertube); + binding.instanceIcon.setImageResource(R.drawable.place_holder_peertube); } @SuppressLint("ClickableViewAccessibility") From c8edab0ff03fa5c5bcbdc82e0ca9f2ea0888a5af Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Tue, 2 Feb 2021 06:06:43 +0530 Subject: [PATCH 19/19] Set the Fragment view bindings to null after the CompositeDisposables have been cleared. --- .../newpipe/download/DownloadDialog.java | 9 ++---- .../fragments/detail/VideoDetailFragment.java | 29 +++++++++++-------- .../list/channel/ChannelFragment.java | 8 ++--- .../list/playlist/PlaylistFragment.java | 18 ++++-------- .../fragments/list/search/SearchFragment.java | 8 ++--- .../list/videos/RelatedVideosFragment.java | 9 ++---- .../local/playlist/LocalPlaylistFragment.java | 22 ++++---------- .../subscription/SubscriptionFragment.kt | 1 + .../PeertubeInstanceListFragment.java | 4 +-- 9 files changed, 41 insertions(+), 67 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java b/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java index 68bcf3cc1e2..1635ba63628 100644 --- a/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java +++ b/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java @@ -334,16 +334,11 @@ private void fetchStreamsSize() { })); } - @Override - public void onDestroy() { - super.onDestroy(); - disposables.clear(); - } - @Override public void onDestroyView() { - dialogBinding = null; super.onDestroyView(); + disposables.clear(); + dialogBinding = null; } /*////////////////////////////////////////////////////////////////////////// diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java index cb4cfb8b6bd..f96ddf37316 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java @@ -354,10 +354,26 @@ public void onStop() { } } + @Override + public void onDestroyView() { + super.onDestroyView(); + + if (positionSubscriber != null) { + positionSubscriber.dispose(); + } + if (currentWorker != null) { + currentWorker.dispose(); + } + disposables.clear(); + positionSubscriber = null; + currentWorker = null; + bottomSheetBehavior.setBottomSheetCallback(null); + binding = null; + } + @Override public void onDestroy() { super.onDestroy(); - binding = null; // Stop the service when user leaves the app with double back press // if video player is selected. Otherwise unbind @@ -372,17 +388,6 @@ public void onDestroy() { activity.unregisterReceiver(broadcastReceiver); activity.getContentResolver().unregisterContentObserver(settingsContentObserver); - if (positionSubscriber != null) { - positionSubscriber.dispose(); - } - if (currentWorker != null) { - currentWorker.dispose(); - } - disposables.clear(); - positionSubscriber = null; - currentWorker = null; - bottomSheetBehavior.setBottomSheetCallback(null); - if (activity.isFinishing()) { playQueue = null; currentInfo = null; diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java index 486777ff169..833bfbc9597 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java @@ -125,8 +125,8 @@ public void onViewCreated(@NonNull final View rootView, final Bundle savedInstan } @Override - public void onDestroy() { - super.onDestroy(); + public void onDestroyView() { + super.onDestroyView(); disposables.clear(); if (subscribeButtonMonitor != null) { subscribeButtonMonitor.dispose(); @@ -487,9 +487,7 @@ public void handleResult(@NonNull final ChannelInfo result) { } } - if (disposables != null) { - disposables.clear(); - } + disposables.clear(); if (subscribeButtonMonitor != null) { subscribeButtonMonitor.dispose(); } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java index 85dea83dcee..5bca4a82c95 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java @@ -65,7 +65,7 @@ import static org.schabi.newpipe.util.ThemeHelper.resolveResourceIdFromAttr; public class PlaylistFragment extends BaseListInfoFragment { - private CompositeDisposable disposables; + private final CompositeDisposable disposables = new CompositeDisposable(); private Subscription bookmarkReactor; private AtomicBoolean isBookmarkButtonReady; @@ -94,7 +94,6 @@ public static PlaylistFragment getInstance(final int serviceId, final String url @Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); - disposables = new CompositeDisposable(); isBookmarkButtonReady = new AtomicBoolean(false); remotePlaylistManager = new RemotePlaylistManager(NewPipeDatabase .getInstance(requireContext())); @@ -186,17 +185,15 @@ public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { @Override public void onDestroyView() { - headerBinding = null; - playlistControlBinding = null; - super.onDestroyView(); if (isBookmarkButtonReady != null) { isBookmarkButtonReady.set(false); } - if (disposables != null) { - disposables.clear(); - } + disposables.clear(); + headerBinding = null; + playlistControlBinding = null; + if (bookmarkReactor != null) { bookmarkReactor.cancel(); } @@ -208,11 +205,8 @@ public void onDestroyView() { public void onDestroy() { super.onDestroy(); - if (disposables != null) { - disposables.dispose(); - } + disposables.dispose(); - disposables = null; remotePlaylistManager = null; playlistEntity = null; isBookmarkButtonReady = null; diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java index 0c490ad09c4..7385696fce8 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java @@ -297,14 +297,8 @@ public void onDestroyView() { } unsetSearchListeners(); - searchBinding = null; - searchLayoutBinding = null; super.onDestroyView(); - } - @Override - public void onDestroy() { - super.onDestroy(); if (searchDisposable != null) { searchDisposable.dispose(); } @@ -312,6 +306,8 @@ public void onDestroy() { suggestionDisposable.dispose(); } disposables.clear(); + searchBinding = null; + searchLayoutBinding = null; } @Override diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java index 7afe6971699..e5ae4cd645d 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java @@ -63,16 +63,11 @@ public View onCreateView(@NonNull final LayoutInflater inflater, return inflater.inflate(R.layout.fragment_related_streams, container, false); } - @Override - public void onDestroy() { - super.onDestroy(); - disposables.clear(); - } - @Override public void onDestroyView() { - headerBinding = null; super.onDestroyView(); + disposables.clear(); + headerBinding = null; } @Override diff --git a/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java index 8da2e2a94e8..4de3c50c4e0 100644 --- a/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java +++ b/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java @@ -88,7 +88,7 @@ public class LocalPlaylistFragment extends BaseLocalListFragment debouncedSaveSignal; - private CompositeDisposable disposables; + private final CompositeDisposable disposables = new CompositeDisposable(); /* Has the playlist been fully loaded from db */ private AtomicBoolean isLoadingComplete; @@ -113,8 +113,6 @@ public void onCreate(final Bundle savedInstanceState) { playlistManager = new LocalPlaylistManager(NewPipeDatabase.getInstance(getContext())); debouncedSaveSignal = PublishSubject.create(); - disposables = new CompositeDisposable(); - isLoadingComplete = new AtomicBoolean(); isModified = new AtomicBoolean(); } @@ -219,9 +217,7 @@ public void hideLoading() { public void startLoading(final boolean forceLoad) { super.startLoading(forceLoad); - if (disposables != null) { - disposables.clear(); - } + disposables.clear(); disposables.add(getDebouncedSaver()); isLoadingComplete.set(false); @@ -267,17 +263,14 @@ public void onDestroyView() { playlistControlBinding.playlistCtrlPlayBgButton.setOnClickListener(null); playlistControlBinding.playlistCtrlPlayAllButton.setOnClickListener(null); playlistControlBinding.playlistCtrlPlayPopupButton.setOnClickListener(null); - - headerBinding = null; - playlistControlBinding = null; } if (databaseSubscription != null) { databaseSubscription.cancel(); } - if (disposables != null) { - disposables.clear(); - } + disposables.clear(); + headerBinding = null; + playlistControlBinding = null; databaseSubscription = null; itemTouchHelper = null; @@ -289,13 +282,10 @@ public void onDestroy() { if (debouncedSaveSignal != null) { debouncedSaveSignal.onComplete(); } - if (disposables != null) { - disposables.dispose(); - } + disposables.dispose(); debouncedSaveSignal = null; playlistManager = null; - disposables = null; isLoadingComplete = null; isModified = null; diff --git a/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionFragment.kt b/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionFragment.kt index b74288a340b..e7d63795025 100644 --- a/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionFragment.kt +++ b/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionFragment.kt @@ -144,6 +144,7 @@ class SubscriptionFragment : BaseStateFragment() { override fun onDestroy() { super.onDestroy() disposables.dispose() + _binding = null } // //////////////////////////////////////////////////////////////////////// diff --git a/app/src/main/java/org/schabi/newpipe/settings/PeertubeInstanceListFragment.java b/app/src/main/java/org/schabi/newpipe/settings/PeertubeInstanceListFragment.java index 9fbbb94d230..a1a903ac1bc 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/PeertubeInstanceListFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/PeertubeInstanceListFragment.java @@ -116,8 +116,8 @@ public void onPause() { } @Override - public void onDestroy() { - super.onDestroy(); + public void onDestroyView() { + super.onDestroyView(); disposables.clear(); binding = null; }