kopia lustrzana https://github.com/ryukoposting/Signal-Android
Improve responsiveness of archive animations, other swipe tweaks.
rodzic
8c45600365
commit
6499ed4637
|
@ -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(),
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
Ładowanie…
Reference in New Issue