kopia lustrzana https://github.com/ryukoposting/Signal-Android
Add basic animations to conversation list.
rodzic
b8dc541fc5
commit
c4164b17a2
|
@ -0,0 +1,16 @@
|
||||||
|
package org.thoughtcrime.securesms.components.recyclerview;
|
||||||
|
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.DefaultItemAnimator;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
public class ConversationListItemAnimator extends DefaultItemAnimator {
|
||||||
|
|
||||||
|
public ConversationListItemAnimator() {
|
||||||
|
setSupportsChangeAnimations(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public boolean animateRemove(RecyclerView.ViewHolder holder) {
|
||||||
|
return super.animateRemove(holder);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,26 +0,0 @@
|
||||||
package org.thoughtcrime.securesms.components.recyclerview;
|
|
||||||
|
|
||||||
|
|
||||||
import androidx.recyclerview.widget.DefaultItemAnimator;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
|
|
||||||
public class DeleteItemAnimator extends DefaultItemAnimator {
|
|
||||||
|
|
||||||
public DeleteItemAnimator() {
|
|
||||||
setSupportsChangeAnimations(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean animateAdd(RecyclerView.ViewHolder viewHolder) {
|
|
||||||
dispatchAddFinished(viewHolder);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean animateMove(RecyclerView.ViewHolder viewHolder, int fromX, int fromY, int toX, int toY) {
|
|
||||||
dispatchMoveFinished(viewHolder);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -57,8 +57,6 @@ class ConversationListAdapter extends ListAdapter<Conversation, RecyclerView.Vie
|
||||||
|
|
||||||
this.glideRequests = glideRequests;
|
this.glideRequests = glideRequests;
|
||||||
this.onConversationClickListener = onConversationClickListener;
|
this.onConversationClickListener = onConversationClickListener;
|
||||||
|
|
||||||
this.setHasStableIds(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -171,23 +169,6 @@ class ConversationListAdapter extends ListAdapter<Conversation, RecyclerView.Vie
|
||||||
return super.getItem(position);
|
return super.getItem(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getItemId(int position) {
|
|
||||||
Conversation item = getItem(position);
|
|
||||||
|
|
||||||
if (item == null) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (item.getType()) {
|
|
||||||
case THREAD: return item.getThreadRecord().getThreadId();
|
|
||||||
case PINNED_HEADER: return -1;
|
|
||||||
case UNPINNED_HEADER: return -2;
|
|
||||||
case ARCHIVED_FOOTER: return -3;
|
|
||||||
default: throw new AssertionError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPagingController(@Nullable PagingController pagingController) {
|
public void setPagingController(@Nullable PagingController pagingController) {
|
||||||
this.pagingController = pagingController;
|
this.pagingController = pagingController;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ import android.content.res.Resources;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
|
import android.graphics.drawable.ColorDrawable;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
|
@ -89,7 +90,7 @@ import org.thoughtcrime.securesms.components.UnreadPaymentsView;
|
||||||
import org.thoughtcrime.securesms.components.menu.ActionItem;
|
import org.thoughtcrime.securesms.components.menu.ActionItem;
|
||||||
import org.thoughtcrime.securesms.components.menu.SignalBottomActionBar;
|
import org.thoughtcrime.securesms.components.menu.SignalBottomActionBar;
|
||||||
import org.thoughtcrime.securesms.components.menu.SignalContextMenu;
|
import org.thoughtcrime.securesms.components.menu.SignalContextMenu;
|
||||||
import org.thoughtcrime.securesms.components.recyclerview.DeleteItemAnimator;
|
import org.thoughtcrime.securesms.components.recyclerview.ConversationListItemAnimator;
|
||||||
import org.thoughtcrime.securesms.components.registration.PulsingFloatingActionButton;
|
import org.thoughtcrime.securesms.components.registration.PulsingFloatingActionButton;
|
||||||
import org.thoughtcrime.securesms.components.reminder.DozeReminder;
|
import org.thoughtcrime.securesms.components.reminder.DozeReminder;
|
||||||
import org.thoughtcrime.securesms.components.reminder.ExpiredBuildReminder;
|
import org.thoughtcrime.securesms.components.reminder.ExpiredBuildReminder;
|
||||||
|
@ -270,7 +271,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
||||||
cameraFab.show();
|
cameraFab.show();
|
||||||
|
|
||||||
list.setLayoutManager(new LinearLayoutManager(requireActivity()));
|
list.setLayoutManager(new LinearLayoutManager(requireActivity()));
|
||||||
list.setItemAnimator(new DeleteItemAnimator());
|
list.setItemAnimator(new ConversationListItemAnimator());
|
||||||
list.addOnScrollListener(new ScrollListener());
|
list.addOnScrollListener(new ScrollListener());
|
||||||
|
|
||||||
snapToTopDataObserver = new SnapToTopDataObserver(list);
|
snapToTopDataObserver = new SnapToTopDataObserver(list);
|
||||||
|
@ -638,7 +639,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
||||||
|
|
||||||
viewModel.getSearchResult().observe(getViewLifecycleOwner(), this::onSearchResultChanged);
|
viewModel.getSearchResult().observe(getViewLifecycleOwner(), this::onSearchResultChanged);
|
||||||
viewModel.getMegaphone().observe(getViewLifecycleOwner(), this::onMegaphoneChanged);
|
viewModel.getMegaphone().observe(getViewLifecycleOwner(), this::onMegaphoneChanged);
|
||||||
viewModel.getConversationList().observe(getViewLifecycleOwner(), this::onSubmitList);
|
viewModel.getConversationList().observe(getViewLifecycleOwner(), this::onConversationListChanged);
|
||||||
viewModel.hasNoConversations().observe(getViewLifecycleOwner(), this::updateEmptyState);
|
viewModel.hasNoConversations().observe(getViewLifecycleOwner(), this::updateEmptyState);
|
||||||
viewModel.getPipeState().observe(getViewLifecycleOwner(), this::updateProxyStatus);
|
viewModel.getPipeState().observe(getViewLifecycleOwner(), this::updateProxyStatus);
|
||||||
|
|
||||||
|
@ -655,6 +656,17 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
||||||
viewModel.getUnreadPaymentsLiveData().observe(getViewLifecycleOwner(), this::onUnreadPaymentsChanged);
|
viewModel.getUnreadPaymentsLiveData().observe(getViewLifecycleOwner(), this::onUnreadPaymentsChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onConversationListChanged(@NonNull List<Conversation> conversations) {
|
||||||
|
LinearLayoutManager layoutManager = (LinearLayoutManager) list.getLayoutManager();
|
||||||
|
int firstVisibleItem = layoutManager != null ? layoutManager.findFirstCompletelyVisibleItemPosition() : -1;
|
||||||
|
|
||||||
|
defaultAdapter.submitList(conversations, () -> {
|
||||||
|
if (firstVisibleItem == 0) {
|
||||||
|
list.scrollToPosition(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void onUnreadPaymentsChanged(@NonNull Optional<UnreadPayments> unreadPayments) {
|
private void onUnreadPaymentsChanged(@NonNull Optional<UnreadPayments> unreadPayments) {
|
||||||
if (unreadPayments.isPresent()) {
|
if (unreadPayments.isPresent()) {
|
||||||
paymentNotificationView.get().setListener(new PaymentNotificationListener(unreadPayments.get()));
|
paymentNotificationView.get().setListener(new PaymentNotificationListener(unreadPayments.get()));
|
||||||
|
@ -1336,8 +1348,9 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
||||||
|
|
||||||
private class ArchiveListenerCallback extends ItemTouchHelper.SimpleCallback {
|
private class ArchiveListenerCallback extends ItemTouchHelper.SimpleCallback {
|
||||||
|
|
||||||
private static final int ARCHIVE_SWIPE_START_COLOR = 0xFF28782A;
|
private static final int ARCHIVE_SWIPE_START_COLOR = 0xFF28782A;
|
||||||
private static final int ARCHIVE_SWIPE_END_COLOR = 0xFF329635;
|
private static final int ARCHIVE_SWIPE_END_COLOR = 0xFF329635;
|
||||||
|
private static final float MIN_ICON_SCALE = 0.75f;
|
||||||
|
|
||||||
ArchiveListenerCallback() {
|
ArchiveListenerCallback() {
|
||||||
super(0, ItemTouchHelper.RIGHT);
|
super(0, ItemTouchHelper.RIGHT);
|
||||||
|
@ -1392,11 +1405,11 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
||||||
|
|
||||||
float scale;
|
float scale;
|
||||||
if (dX < scaleStartPoint) {
|
if (dX < scaleStartPoint) {
|
||||||
scale = 0.5f;
|
scale = MIN_ICON_SCALE;
|
||||||
} else if (dX > scaleEndPoint) {
|
} else if (dX > scaleEndPoint) {
|
||||||
scale = 1f;
|
scale = 1f;
|
||||||
} else {
|
} else {
|
||||||
scale = Math.min(1f, 0.5f + ((dX - scaleStartPoint) / (scaleEndPoint - scaleStartPoint)) * (1f - 0.5f));
|
scale = Math.min(1f, MIN_ICON_SCALE + ((dX - scaleStartPoint) / (scaleEndPoint - scaleStartPoint)) * (1f - MIN_ICON_SCALE));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dX > 0) {
|
if (dX > 0) {
|
||||||
|
|
Ładowanie…
Reference in New Issue