From 3121cd9adefbbb3f89eae0ee6fcccd57e1179e9d Mon Sep 17 00:00:00 2001 From: bjoern Date: Mon, 29 Aug 2022 13:56:06 +0200 Subject: [PATCH] simplify contact list (#2374) * simplify contact list this also disables "fast scrolling" for the contact list; the "fast scrolling" code is too much bound to the bubbles and a-z to be preserved without much effort. however, "fast scrolling" seems to be much less important with a list sorted by "last seen". there is also the rough idea to raise minimal-origin of contact list, this would make the list much smaller (), otoh, not sure if #2411 is a thing for list sorted by "last seen". also the other lists (chatlist, archive, blocked) may become quite huge as well and do never have "fast scrolling". in case it is really needed again, however, we should go for the implementation available in RecyclerView since some time: * less padding as the A-Z decorations do not longer need space * remove unused contact_selection_recyclerview_header --- .../recycler_view_fast_scroller_bubble.xml | 9 - .../recycler_view_fast_scroller_bubble.xml | 9 - .../recycler_view_fast_scroller_handle.xml | 17 -- .../contact_selection_list_fragment.xml | 7 - res/layout/contact_selection_list_item.xml | 6 +- .../contact_selection_recyclerview_header.xml | 9 - res/layout/recycler_view_fast_scroller.xml | 24 -- .../ContactSelectionListFragment.java | 34 --- .../components/RecyclerViewFastScroller.java | 213 ------------------ .../contacts/ContactSelectionListAdapter.java | 49 ---- .../contacts/ContactSelectionListItem.java | 1 - 11 files changed, 2 insertions(+), 376 deletions(-) delete mode 100644 res/drawable-v12/recycler_view_fast_scroller_bubble.xml delete mode 100644 res/drawable/recycler_view_fast_scroller_bubble.xml delete mode 100644 res/drawable/recycler_view_fast_scroller_handle.xml delete mode 100644 res/layout/contact_selection_recyclerview_header.xml delete mode 100644 res/layout/recycler_view_fast_scroller.xml delete mode 100644 src/org/thoughtcrime/securesms/components/RecyclerViewFastScroller.java diff --git a/res/drawable-v12/recycler_view_fast_scroller_bubble.xml b/res/drawable-v12/recycler_view_fast_scroller_bubble.xml deleted file mode 100644 index f135c5c6d..000000000 --- a/res/drawable-v12/recycler_view_fast_scroller_bubble.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/res/drawable/recycler_view_fast_scroller_bubble.xml b/res/drawable/recycler_view_fast_scroller_bubble.xml deleted file mode 100644 index 417f6e4bc..000000000 --- a/res/drawable/recycler_view_fast_scroller_bubble.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/res/drawable/recycler_view_fast_scroller_handle.xml b/res/drawable/recycler_view_fast_scroller_handle.xml deleted file mode 100644 index fa2ca8a58..000000000 --- a/res/drawable/recycler_view_fast_scroller_handle.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/res/layout/contact_selection_list_fragment.xml b/res/layout/contact_selection_list_fragment.xml index 0ed121989..01bbf06ba 100644 --- a/res/layout/contact_selection_list_fragment.xml +++ b/res/layout/contact_selection_list_fragment.xml @@ -22,11 +22,4 @@ android:textSize="20sp" tools:text="No contacts." /> - - diff --git a/res/layout/contact_selection_list_item.xml b/res/layout/contact_selection_list_item.xml index 8f5a1afdd..bb4aee0bf 100644 --- a/res/layout/contact_selection_list_item.xml +++ b/res/layout/contact_selection_list_item.xml @@ -8,10 +8,8 @@ android:gravity="center_vertical" android:focusable="true" android:background="?attr/conversation_list_item_background" - android:paddingLeft="48dp" - android:paddingStart="48dp" - android:paddingRight="24dp" - android:paddingEnd="24dp"> + android:paddingLeft="24dp" + android:paddingRight="24dp"> - diff --git a/res/layout/recycler_view_fast_scroller.xml b/res/layout/recycler_view_fast_scroller.xml deleted file mode 100644 index 2edd24c13..000000000 --- a/res/layout/recycler_view_fast_scroller.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/ContactSelectionListFragment.java b/src/org/thoughtcrime/securesms/ContactSelectionListFragment.java index 51e675421..4c0791403 100644 --- a/src/org/thoughtcrime/securesms/ContactSelectionListFragment.java +++ b/src/org/thoughtcrime/securesms/ContactSelectionListFragment.java @@ -20,7 +20,6 @@ package org.thoughtcrime.securesms; import android.Manifest; import android.annotation.SuppressLint; import android.content.Intent; -import android.content.res.Configuration; import android.content.res.TypedArray; import android.graphics.Color; import android.os.AsyncTask; @@ -44,14 +43,12 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; import android.widget.Toast; import com.b44t.messenger.DcContact; import com.b44t.messenger.DcContext; import com.b44t.messenger.DcEvent; -import org.thoughtcrime.securesms.components.RecyclerViewFastScroller; import org.thoughtcrime.securesms.connect.DcContactsLoader; import org.thoughtcrime.securesms.connect.DcEventCenter; import org.thoughtcrime.securesms.connect.DcHelper; @@ -60,7 +57,6 @@ import org.thoughtcrime.securesms.contacts.ContactSelectionListAdapter; import org.thoughtcrime.securesms.contacts.ContactSelectionListItem; import org.thoughtcrime.securesms.mms.GlideApp; import org.thoughtcrime.securesms.permissions.Permissions; -import org.thoughtcrime.securesms.util.StickyHeaderDecoration; import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.ViewUtil; @@ -95,8 +91,6 @@ public class ContactSelectionListFragment extends Fragment private OnContactSelectedListener onContactSelectedListener; private String cursorFilter; private RecyclerView recyclerView; - private StickyHeaderDecoration listDecoration; - private RecyclerViewFastScroller fastScroller; private ActionMode actionMode; private ActionMode.Callback actionModeCallback; @@ -131,7 +125,6 @@ public class ContactSelectionListFragment extends Fragment View view = inflater.inflate(R.layout.contact_selection_list_fragment, container, false); recyclerView = ViewUtil.findById(view, R.id.recycler_view); - fastScroller = ViewUtil.findById(view, R.id.fast_scroller); recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); actionModeCallback = new ActionMode.Callback() { @Override @@ -183,12 +176,6 @@ public class ContactSelectionListFragment extends Fragment return view; } - @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - listDecoration.onConfigurationChanged(newConfig); - } - private void handleSelectAll() { getContactSelectionListAdapter().selectAll(); updateActionModeTitle(); @@ -286,8 +273,6 @@ public class ContactSelectionListFragment extends Fragment selectedContacts.addAll(preselectedContacts); } recyclerView.setAdapter(adapter); - listDecoration = new StickyHeaderDecoration(adapter, true, true); - recyclerView.addItemDecoration(listDecoration); } public void setQueryFilter(String filter) { @@ -295,18 +280,6 @@ public class ContactSelectionListFragment extends Fragment this.getLoaderManager().restartLoader(0, null, this); } - public void resetQueryFilter() { - setQueryFilter(null); - } - - public void reset() { - selectedContacts.clear(); - - if (!isDetached() && !isRemoving() && getActivity() != null && !getActivity().isFinishing()) { - getLoaderManager().restartLoader(0, null, this); - } - } - @Override public Loader onCreateLoader(int id, Bundle args) { boolean addCreateGroupLinks = isFromShareActivity() || isRelayingMessageContent(getActivity()) ? false : !isMulti(); @@ -320,18 +293,11 @@ public class ContactSelectionListFragment extends Fragment @Override public void onLoadFinished(Loader loader, DcContactsLoader.Ret data) { ((ContactSelectionListAdapter) recyclerView.getAdapter()).changeData(data); - boolean useFastScroller = (recyclerView.getAdapter().getItemCount() > 20); - recyclerView.setVerticalScrollBarEnabled(!useFastScroller); - if (useFastScroller) { - fastScroller.setVisibility(View.VISIBLE); - fastScroller.setRecyclerView(recyclerView); - } } @Override public void onLoaderReset(Loader loader) { ((ContactSelectionListAdapter) recyclerView.getAdapter()).changeData(null); - fastScroller.setVisibility(View.GONE); } @SuppressLint("StaticFieldLeak") diff --git a/src/org/thoughtcrime/securesms/components/RecyclerViewFastScroller.java b/src/org/thoughtcrime/securesms/components/RecyclerViewFastScroller.java deleted file mode 100644 index 1de7fcdd7..000000000 --- a/src/org/thoughtcrime/securesms/components/RecyclerViewFastScroller.java +++ /dev/null @@ -1,213 +0,0 @@ -/** - * Modified version of - * https://github.com/AndroidDeveloperLB/LollipopContactsRecyclerViewFastScroller - * - * Their license: - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thoughtcrime.securesms.components; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ObjectAnimator; -import android.annotation.TargetApi; -import android.content.Context; -import android.os.Build.VERSION; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewTreeObserver; -import android.widget.LinearLayout; -import android.widget.TextView; - -import org.thoughtcrime.securesms.R; -import org.thoughtcrime.securesms.util.Util; -import org.thoughtcrime.securesms.util.ViewUtil; - -public class RecyclerViewFastScroller extends LinearLayout { - private static final int BUBBLE_ANIMATION_DURATION = 100; - private static final int TRACK_SNAP_RANGE = 5; - - private @NonNull TextView bubble; - private @NonNull View handle; - private @Nullable RecyclerView recyclerView; - - private int height; - private ObjectAnimator currentAnimator; - - private final RecyclerView.OnScrollListener onScrollListener = new RecyclerView.OnScrollListener() { - @Override - public void onScrolled(final RecyclerView recyclerView, final int dx, final int dy) { - if (handle.isSelected()) return; - final int offset = recyclerView.computeVerticalScrollOffset(); - final int range = recyclerView.computeVerticalScrollRange(); - final int extent = recyclerView.computeVerticalScrollExtent(); - final int offsetRange = Math.max(range - extent, 1); - setBubbleAndHandlePosition((float) Util.clamp(offset, 0, offsetRange) / offsetRange); - } - }; - - public interface FastScrollAdapter { - CharSequence getBubbleText(int pos); - } - - public RecyclerViewFastScroller(final Context context) { - this(context, null); - } - - public RecyclerViewFastScroller(final Context context, final AttributeSet attrs) { - super(context, attrs); - setOrientation(HORIZONTAL); - setClipChildren(false); - setScrollContainer(true); - inflate(context, R.layout.recycler_view_fast_scroller, this); - bubble = ViewUtil.findById(this, R.id.fastscroller_bubble); - handle = ViewUtil.findById(this, R.id.fastscroller_handle); - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - height = h; - } - - @Override - @TargetApi(11) - public boolean onTouchEvent(@NonNull MotionEvent event) { - final int action = event.getAction(); - switch (action) { - case MotionEvent.ACTION_DOWN: - if (event.getX() < ViewUtil.getX(handle) - handle.getPaddingLeft() || - event.getY() < ViewUtil.getY(handle) - handle.getPaddingTop() || - event.getY() > ViewUtil.getY(handle) + handle.getHeight() + handle.getPaddingBottom()) - { - return false; - } - if (currentAnimator != null) { - currentAnimator.cancel(); - } - if (bubble.getVisibility() != VISIBLE) { - showBubble(); - } - handle.setSelected(true); - case MotionEvent.ACTION_MOVE: - final float y = event.getY(); - setBubbleAndHandlePosition(y / height); - setRecyclerViewPosition(y); - return true; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - handle.setSelected(false); - hideBubble(); - return true; - } - return super.onTouchEvent(event); - } - - public void setRecyclerView(final @NonNull RecyclerView recyclerView) { - if (this.recyclerView != null) { - this.recyclerView.removeOnScrollListener(onScrollListener); - } - this.recyclerView = recyclerView; - recyclerView.addOnScrollListener(onScrollListener); - recyclerView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { - @Override - public boolean onPreDraw() { - recyclerView.getViewTreeObserver().removeOnPreDrawListener(this); - if (handle.isSelected()) return true; - final int verticalScrollOffset = recyclerView.computeVerticalScrollOffset(); - final int verticalScrollRange = recyclerView.computeVerticalScrollRange(); - float proportion = (float)verticalScrollOffset / ((float)verticalScrollRange - height); - setBubbleAndHandlePosition(height * proportion); - return true; - } - }); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - if (recyclerView != null) - recyclerView.removeOnScrollListener(onScrollListener); - } - - private void setRecyclerViewPosition(float y) { - if (recyclerView != null) { - final int itemCount = recyclerView.getAdapter().getItemCount(); - float proportion; - if (ViewUtil.getY(handle) == 0) { - proportion = 0f; - } else if (ViewUtil.getY(handle) + handle.getHeight() >= height - TRACK_SNAP_RANGE) { - proportion = 1f; - } else { - proportion = y / (float)height; - } - - final int targetPos = Util.clamp((int)(proportion * (float)itemCount), 0, itemCount - 1); - ((LinearLayoutManager) recyclerView.getLayoutManager()).scrollToPositionWithOffset(targetPos, 0); - final CharSequence bubbleText = ((FastScrollAdapter) recyclerView.getAdapter()).getBubbleText(targetPos); - bubble.setText(bubbleText); - } - } - - private void setBubbleAndHandlePosition(float y) { - final int handleHeight = handle.getHeight(); - final int bubbleHeight = bubble.getHeight(); - final int handleY = Util.clamp((int)((height - handleHeight) * y), 0, height - handleHeight); - ViewUtil.setY(handle, handleY); - ViewUtil.setY(bubble, Util.clamp(handleY - bubbleHeight - bubble.getPaddingBottom() + handleHeight, - 0, - height - bubbleHeight)); - } - - @TargetApi(11) - private void showBubble() { - bubble.setVisibility(VISIBLE); - if (VERSION.SDK_INT >= 11) { - if (currentAnimator != null) currentAnimator.cancel(); - currentAnimator = ObjectAnimator.ofFloat(bubble, "alpha", 0f, 1f).setDuration(BUBBLE_ANIMATION_DURATION); - currentAnimator.start(); - } - } - - @TargetApi(11) - private void hideBubble() { - if (VERSION.SDK_INT >= 11) { - if (currentAnimator != null) currentAnimator.cancel(); - currentAnimator = ObjectAnimator.ofFloat(bubble, "alpha", 1f, 0f).setDuration(BUBBLE_ANIMATION_DURATION); - currentAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - super.onAnimationEnd(animation); - bubble.setVisibility(INVISIBLE); - currentAnimator = null; - } - - @Override - public void onAnimationCancel(Animator animation) { - super.onAnimationCancel(animation); - bubble.setVisibility(INVISIBLE); - currentAnimator = null; - } - }); - currentAnimator.start(); - } else { - bubble.setVisibility(INVISIBLE); - } - } -} diff --git a/src/org/thoughtcrime/securesms/contacts/ContactSelectionListAdapter.java b/src/org/thoughtcrime/securesms/contacts/ContactSelectionListAdapter.java index 3d1e761bd..053513fc3 100644 --- a/src/org/thoughtcrime/securesms/contacts/ContactSelectionListAdapter.java +++ b/src/org/thoughtcrime/securesms/contacts/ContactSelectionListAdapter.java @@ -32,14 +32,10 @@ import com.b44t.messenger.DcContact; import com.b44t.messenger.DcContext; import org.thoughtcrime.securesms.R; -import org.thoughtcrime.securesms.components.RecyclerViewFastScroller.FastScrollAdapter; import org.thoughtcrime.securesms.connect.DcContactsLoader; import org.thoughtcrime.securesms.connect.DcHelper; -import org.thoughtcrime.securesms.contacts.ContactSelectionListAdapter.HeaderViewHolder; import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.util.LRUCache; -import org.thoughtcrime.securesms.util.StickyHeaderDecoration.StickyHeaderAdapter; -import org.thoughtcrime.securesms.util.Util; import java.lang.ref.SoftReference; import java.util.Collections; @@ -53,8 +49,6 @@ import java.util.Set; * @author Jake McGinty */ public class ContactSelectionListAdapter extends RecyclerView.Adapter - implements FastScrollAdapter, - StickyHeaderAdapter { private final static String TAG = ContactSelectionListAdapter.class.getSimpleName(); @@ -243,12 +237,6 @@ public class ContactSelectionListAdapter extends RecyclerView.Adapter } } - static class HeaderViewHolder extends RecyclerView.ViewHolder { - HeaderViewHolder(View itemView) { - super(itemView); - } - } - public ContactSelectionListAdapter(@NonNull Context context, @NonNull GlideRequests glideRequests, @Nullable ItemClickListener clickListener, @@ -328,11 +316,6 @@ public class ContactSelectionListAdapter extends RecyclerView.Adapter return VIEW_TYPE_CONTACT; } - @Override - public CharSequence getBubbleText(int position) { - return getHeaderString(position); - } - public Set getSelectedContacts() { return selectedContacts; } @@ -347,38 +330,6 @@ public class ContactSelectionListAdapter extends RecyclerView.Adapter void onItemLongClick(ContactSelectionListItem view); } - @Override - public long getHeaderId(int position) { - if (position < 0 || position >= getItemCount()) { - return -1; - } - - return Util.hashCode(getHeaderString(position)); - } - - private @NonNull String getHeaderString(int position) { - DcContact dcContact = getContact(position); - String name = dcContact.getDisplayName(); - if (!TextUtils.isEmpty(name)) { - String firstChar = name.trim().substring(0, 1).toUpperCase(); - if (Character.isLetterOrDigit(firstChar.codePointAt(0))) { - return firstChar; - } - } - return ""; - } - - @Override - public HeaderViewHolder onCreateHeaderViewHolder(ViewGroup parent) { - return new HeaderViewHolder(LayoutInflater.from(context).inflate(R.layout.contact_selection_recyclerview_header, parent, false)); - } - - @Override - public void onBindHeaderViewHolder(HeaderViewHolder viewHolder, int position) { - ((TextView)viewHolder.itemView).setText(getHeaderString(position)); - } - - public void changeData(DcContactsLoader.Ret loaderRet) { this.dcContactList = loaderRet==null? new int[0] : loaderRet.ids; this.query = loaderRet==null? null : loaderRet.query; diff --git a/src/org/thoughtcrime/securesms/contacts/ContactSelectionListItem.java b/src/org/thoughtcrime/securesms/contacts/ContactSelectionListItem.java index b660f493e..3d0cd3891 100644 --- a/src/org/thoughtcrime/securesms/contacts/ContactSelectionListItem.java +++ b/src/org/thoughtcrime/securesms/contacts/ContactSelectionListItem.java @@ -12,7 +12,6 @@ import com.b44t.messenger.DcContact; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.components.AvatarView; -import org.thoughtcrime.securesms.connect.DcHelper; import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;