Improve responsiveness of archive animations, other swipe tweaks.

fork-5.53.8
Greyson Parrelli 2021-11-09 10:08:51 -05:00 zatwierdzone przez Alex Hart
rodzic 8c45600365
commit 6499ed4637
5 zmienionych plików z 91 dodań i 17 usunięć

Wyświetl plik

@ -125,6 +125,7 @@ public class ConversationListArchiveFragment extends ConversationListFragment im
@Override
protected void onItemSwiped(long threadId, int unreadCount) {
archiveDecoration.onArchiveStarted();
itemAnimator.enable();
new SnackbarAsyncTask<Long>(getViewLifecycleOwner().getLifecycle(),
requireView(),

Wyświetl plik

@ -157,6 +157,7 @@ import org.thoughtcrime.securesms.util.views.Stub;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.websocket.WebSocketConnectionState;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@ -214,6 +215,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode
private SignalBottomActionBar bottomActionBar;
protected ConversationListArchiveItemDecoration archiveDecoration;
protected ConversationListItemAnimator itemAnimator;
private Stopwatch startupStopwatch;
public static ConversationListFragment newInstance() {
@ -272,9 +274,10 @@ public class ConversationListFragment extends MainFragment implements ActionMode
cameraFab.show();
archiveDecoration = new ConversationListArchiveItemDecoration(new ColorDrawable(getResources().getColor(R.color.conversation_list_archive_background_end)));
itemAnimator = new ConversationListItemAnimator();
list.setLayoutManager(new LinearLayoutManager(requireActivity()));
list.setItemAnimator(new ConversationListItemAnimator());
list.setItemAnimator(itemAnimator);
list.addOnScrollListener(new ScrollListener());
list.addItemDecoration(archiveDecoration);
@ -1276,6 +1279,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode
@SuppressLint("StaticFieldLeak")
protected void onItemSwiped(long threadId, int unreadCount) {
archiveDecoration.onArchiveStarted();
itemAnimator.enable();
new SnackbarAsyncTask<Long>(getViewLifecycleOwner().getLifecycle(),
requireView(),
@ -1315,7 +1319,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode
ApplicationDependencies.getMessageNotifier().updateNotification(context);
}
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, threadId);
}.executeOnExecutor(SignalExecutors.BOUNDED, threadId);
}
private class PaymentNotificationListener implements UnreadPaymentsView.Listener {
@ -1358,14 +1362,18 @@ public class ConversationListFragment extends MainFragment implements ActionMode
private class ArchiveListenerCallback extends ItemTouchHelper.SimpleCallback {
private static final long SWIPE_ANIMATION_DURATION = 175;
private static final float MIN_ICON_SCALE = 0.85f;
private static final float MAX_ICON_SCALE = 1f;
private final int archiveColorStart;
private final int archiveColorEnd;
private WeakReference<RecyclerView.ViewHolder> lastTouched;
ArchiveListenerCallback(@ColorInt int archiveColorStart, @ColorInt int archiveColorEnd) {
super(0, ItemTouchHelper.RIGHT);
super(0, ItemTouchHelper.END);
this.archiveColorStart = archiveColorStart;
this.archiveColorEnd = archiveColorEnd;
}
@ -1389,13 +1397,33 @@ public class ConversationListFragment extends MainFragment implements ActionMode
return 0;
}
lastTouched = new WeakReference<>(viewHolder);
return super.getSwipeDirs(recyclerView, viewHolder);
}
@SuppressLint("StaticFieldLeak")
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
if (viewHolder.itemView instanceof ConversationListItemInboxZero) return;
if (lastTouched != null) {
Log.w(TAG, "Falling back to slower onSwiped() event.");
onTrueSwipe(viewHolder);
lastTouched = null;
}
}
@Override
public long getAnimationDuration(@NonNull RecyclerView recyclerView, int animationType, float animateDx, float animateDy) {
if (animationType == ItemTouchHelper.ANIMATION_TYPE_SWIPE_SUCCESS && lastTouched != null && lastTouched.get() != null) {
onTrueSwipe(lastTouched.get());
lastTouched = null;
} else if (animationType == ItemTouchHelper.ANIMATION_TYPE_SWIPE_CANCEL) {
lastTouched = null;
}
return SWIPE_ANIMATION_DURATION;
}
private void onTrueSwipe(RecyclerView.ViewHolder viewHolder) {
final long threadId = ((ConversationListItem)viewHolder.itemView).getThreadId();
final int unreadCount = ((ConversationListItem)viewHolder.itemView).getUnreadCount();
@ -1409,24 +1437,26 @@ public class ConversationListFragment extends MainFragment implements ActionMode
boolean isCurrentlyActive)
{
if (viewHolder.itemView instanceof ConversationListItemInboxZero) return;
float absoluteDx = Math.abs(dX);
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
Resources resources = getResources();
View itemView = viewHolder.itemView;
float percentDx = Math.abs(dX) / viewHolder.itemView.getWidth();
float percentDx = absoluteDx / viewHolder.itemView.getWidth();
int color = ArgbEvaluatorCompat.getInstance().evaluate(Math.min(1f, percentDx * (1 / 0.25f)), archiveColorStart, archiveColorEnd);
float scaleStartPoint = DimensionUnit.DP.toPixels(48f);
float scaleEndPoint = DimensionUnit.DP.toPixels(96f);
float scale;
if (dX < scaleStartPoint) {
if (absoluteDx < scaleStartPoint) {
scale = MIN_ICON_SCALE;
} else if (dX > scaleEndPoint) {
} else if (absoluteDx > scaleEndPoint) {
scale = MAX_ICON_SCALE;
} else {
scale = Math.min(MAX_ICON_SCALE, MIN_ICON_SCALE + ((dX - scaleStartPoint) / (scaleEndPoint - scaleStartPoint)) * (MAX_ICON_SCALE - MIN_ICON_SCALE));
scale = Math.min(MAX_ICON_SCALE, MIN_ICON_SCALE + ((absoluteDx - scaleStartPoint) / (scaleEndPoint - scaleStartPoint)) * (MAX_ICON_SCALE - MIN_ICON_SCALE));
}
if (dX > 0) {
if (absoluteDx > 0) {
if (archiveDrawable == null) {
archiveDrawable = Objects.requireNonNull(AppCompatResources.getDrawable(requireContext(), getArchiveIconRes()));
archiveDrawable.setColorFilter(new SimpleColorFilter(Color.WHITE));
@ -1441,8 +1471,13 @@ public class ConversationListFragment extends MainFragment implements ActionMode
float gutter = resources.getDimension(R.dimen.dsl_settings_gutter);
float extra = resources.getDimension(R.dimen.conversation_list_fragment_archive_padding);
canvas.translate(itemView.getLeft() + gutter + extra,
itemView.getTop() + (itemView.getBottom() - itemView.getTop() - archiveDrawable.getIntrinsicHeight()) / 2f);
if (ViewUtil.isLtr(requireContext())) {
canvas.translate(itemView.getLeft() + gutter + extra,
itemView.getTop() + (itemView.getBottom() - itemView.getTop() - archiveDrawable.getIntrinsicHeight()) / 2f);
} else {
canvas.translate(itemView.getRight() - gutter - extra,
itemView.getTop() + (itemView.getBottom() - itemView.getTop() - archiveDrawable.getIntrinsicHeight()) / 2f);
}
canvas.scale(scale, scale, archiveDrawable.getIntrinsicWidth() / 2f, archiveDrawable.getIntrinsicHeight() / 2f);
@ -1450,7 +1485,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode
canvas.restore();
ViewCompat.setElevation(viewHolder.itemView, DimensionUnit.DP.toPixels(4f));
} else if (dX == 0) {
} else if (absoluteDx == 0) {
ViewCompat.setElevation(viewHolder.itemView, DimensionUnit.DP.toPixels(0f));
}
@ -1464,6 +1499,8 @@ public class ConversationListFragment extends MainFragment implements ActionMode
public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
ViewCompat.setElevation(viewHolder.itemView, 0);
lastTouched = null;
itemAnimator.postDisable(requireView().getHandler());
}
}

Wyświetl plik

@ -1,16 +1,42 @@
package org.thoughtcrime.securesms.conversationlist;
import android.os.Handler;
import androidx.annotation.MainThread;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.RecyclerView;
import org.signal.core.util.logging.Log;
public class ConversationListItemAnimator extends DefaultItemAnimator {
private static final String TAG = Log.tag(ConversationListItemAnimator.class);
private static final long ANIMATION_DURATION = 200;
private boolean shouldDisable;
public ConversationListItemAnimator() {
setSupportsChangeAnimations(false);
}
@Override public boolean animateRemove(RecyclerView.ViewHolder holder) {
return super.animateRemove(holder);
@MainThread
public void enable() {
setMoveDuration(ANIMATION_DURATION);
shouldDisable = false;
}
/**
* We need to reasonable ensure that the animation has started before we disable things here, so we add a slight delay.
*/
@MainThread
public void postDisable(Handler handler) {
shouldDisable = true;
handler.postDelayed(() -> {
if (shouldDisable) {
setMoveDuration(0);
} else {
Log.w(TAG, "Disable was canceled by an enable.");
}
}, 50);
}
}

Wyświetl plik

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
<solid android:color="@color/signal_background_primary"/>
<corners
android:topRightRadius="8dp"
android:bottomRightRadius="8dp"/>
<padding android:bottom="5dp" android:left="5dp" android:right="5dp" android:top="5dp"/>
</shape>

Wyświetl plik

@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
<solid android:color="@color/signal_background_primary"/>
<corners android:radius="8dp"/>
<corners
android:topLeftRadius="8dp"
android:bottomLeftRadius="8dp"/>
<padding android:bottom="5dp" android:left="5dp" android:right="5dp" android:top="5dp"/>
</shape>