Replace non-essential conversation list views with stubs.

This commit is contained in:
Greyson Parrelli 2020-12-20 10:56:54 -05:00 committed by Alan Evans
parent 1ced115b54
commit 8927971a19
8 changed files with 191 additions and 123 deletions

View file

@ -38,6 +38,7 @@ import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.registration.PulsingFloatingActionButton;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.util.task.SnackbarAsyncTask;
import org.thoughtcrime.securesms.util.views.Stub;
import java.util.Set;
@ -45,9 +46,10 @@ import java.util.Set;
public class ConversationListArchiveFragment extends ConversationListFragment implements ActionMode.Callback
{
private RecyclerView list;
private View emptyState;
private Stub<View> emptyState;
private PulsingFloatingActionButton fab;
private PulsingFloatingActionButton cameraFab;
private Stub<Toolbar> toolbar;
public static ConversationListArchiveFragment newInstance() {
return new ConversationListArchiveFragment();
@ -61,17 +63,18 @@ public class ConversationListArchiveFragment extends ConversationListFragment im
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
toolbar = new Stub<>(view.findViewById(R.id.toolbar_basic));
super.onViewCreated(view, savedInstanceState);
list = view.findViewById(R.id.list);
fab = view.findViewById(R.id.fab);
cameraFab = view.findViewById(R.id.camera_fab);
emptyState = view.findViewById(R.id.empty_state);
emptyState = new Stub<>(view.findViewById(R.id.empty_state));
((AppCompatActivity) requireActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
Toolbar toolbar = view.findViewById(R.id.toolbar_basic);
toolbar.setNavigationOnClickListener(v -> requireActivity().onBackPressed());
toolbar.setTitle(R.string.AndroidManifest_archived_conversations);
toolbar.get().setNavigationOnClickListener(v -> requireActivity().onBackPressed());
toolbar.get().setTitle(R.string.AndroidManifest_archived_conversations);
fab.hide();
cameraFab.hide();
@ -80,7 +83,10 @@ public class ConversationListArchiveFragment extends ConversationListFragment im
@Override
protected void onPostSubmitList() {
list.setVisibility(View.VISIBLE);
emptyState.setVisibility(View.GONE);
if (emptyState.resolved()) {
emptyState.get().setVisibility(View.GONE);
}
}
@Override
@ -89,8 +95,8 @@ public class ConversationListArchiveFragment extends ConversationListFragment im
}
@Override
protected int getToolbarRes() {
return R.id.toolbar_basic;
protected @NonNull Toolbar getToolbar(@NonNull View rootView) {
return toolbar.get();
}
@Override

View file

@ -103,7 +103,6 @@ import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.events.ReminderUpdateEvent;
import org.thoughtcrime.securesms.insights.InsightsLauncher;
import org.thoughtcrime.securesms.jobs.ServiceOutageDetectionJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.lock.v2.CreateKbsPinActivity;
import org.thoughtcrime.securesms.mediasend.MediaSendActivity;
import org.thoughtcrime.securesms.megaphone.Megaphone;
@ -128,6 +127,7 @@ import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.WindowUtil;
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
import org.thoughtcrime.securesms.util.task.SnackbarAsyncTask;
import org.thoughtcrime.securesms.util.views.Stub;
import org.whispersystems.libsignal.util.guava.Optional;
import java.util.Collections;
@ -162,13 +162,12 @@ public class ConversationListFragment extends MainFragment implements ActionMode
private ActionMode actionMode;
private RecyclerView list;
private ReminderView reminderView;
private View emptyState;
private ImageView emptyImage;
private Stub<ReminderView> reminderView;
private Stub<ViewGroup> emptyState;
private TextView searchEmptyState;
private PulsingFloatingActionButton fab;
private PulsingFloatingActionButton cameraFab;
private SearchToolbar searchToolbar;
private Stub<SearchToolbar> searchToolbar;
private ImageView searchAction;
private View toolbarShadow;
private ConversationListViewModel viewModel;
@ -176,7 +175,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode
private ConversationListAdapter defaultAdapter;
private ConversationListSearchAdapter searchAdapter;
private StickyHeaderDecoration searchAdapterDecoration;
private ViewGroup megaphoneContainer;
private Stub<ViewGroup> megaphoneContainer;
private SnapToTopDataObserver snapToTopDataObserver;
private Drawable archiveDrawable;
private LifecycleObserver visibilityLifecycleObserver;
@ -198,28 +197,24 @@ public class ConversationListFragment extends MainFragment implements ActionMode
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
reminderView = view.findViewById(R.id.reminder);
list = view.findViewById(R.id.list);
fab = view.findViewById(R.id.fab);
cameraFab = view.findViewById(R.id.camera_fab);
emptyState = view.findViewById(R.id.empty_state);
emptyImage = view.findViewById(R.id.empty);
searchEmptyState = view.findViewById(R.id.search_no_results);
searchToolbar = view.findViewById(R.id.search_toolbar);
searchAction = view.findViewById(R.id.search_action);
toolbarShadow = view.findViewById(R.id.conversation_list_toolbar_shadow);
megaphoneContainer = view.findViewById(R.id.megaphone_container);
reminderView = new Stub<>(view.findViewById(R.id.reminder));
emptyState = new Stub<>(view.findViewById(R.id.empty_state));
searchToolbar = new Stub<>(view.findViewById(R.id.search_toolbar));
megaphoneContainer = new Stub<>(view.findViewById(R.id.megaphone_container));
Toolbar toolbar = view.findViewById(getToolbarRes());
Toolbar toolbar = getToolbar(view);
toolbar.setVisibility(View.VISIBLE);
((AppCompatActivity) requireActivity()).setSupportActionBar(toolbar);
fab.show();
cameraFab.show();
reminderView.setOnDismissListener(this::updateReminders);
reminderView.setOnActionClickListener(this::onReminderAction);
list.setLayoutManager(new LinearLayoutManager(requireActivity()));
list.setItemAnimator(new DeleteItemAnimator());
list.addOnScrollListener(new ScrollListener());
@ -263,7 +258,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode
SimpleTask.run(getViewLifecycleOwner().getLifecycle(), Recipient::self, this::initializeProfileIcon);
if (!searchToolbar.isVisible() && list.getAdapter() != defaultAdapter) {
if ((!searchToolbar.resolved() || !searchToolbar.get().isVisible()) && list.getAdapter() != defaultAdapter) {
list.removeItemDecoration(searchAdapterDecoration);
setAdapter(defaultAdapter);
}
@ -329,10 +324,10 @@ public class ConversationListFragment extends MainFragment implements ActionMode
}
private boolean closeSearchIfOpen() {
if (searchToolbar.isVisible() || activeAdapter == searchAdapter) {
if ((searchToolbar.resolved() && searchToolbar.get().isVisible()) || activeAdapter == searchAdapter) {
list.removeItemDecoration(searchAdapterDecoration);
setAdapter(defaultAdapter);
searchToolbar.collapse();
searchToolbar.get().collapse();
return true;
}
@ -429,6 +424,11 @@ public class ConversationListFragment extends MainFragment implements ActionMode
dialogFragment.show(getChildFragmentManager(), "megaphone_dialog");
}
private void initializeReminderView() {
reminderView.get().setOnDismissListener(this::updateReminders);
reminderView.get().setOnActionClickListener(this::onReminderAction);
}
private void onReminderAction(@IdRes int reminderActionId) {
if (reminderActionId == R.id.reminder_action_update_now) {
PlayStoreUtil.openPlayStoreOrOurApkDownloadPage(requireContext());
@ -449,36 +449,36 @@ public class ConversationListFragment extends MainFragment implements ActionMode
private void initializeSearchListener() {
searchAction.setOnClickListener(v -> {
searchToolbar.display(searchAction.getX() + (searchAction.getWidth() / 2.0f),
searchAction.getY() + (searchAction.getHeight() / 2.0f));
});
searchToolbar.get().display(searchAction.getX() + (searchAction.getWidth() / 2.0f),
searchAction.getY() + (searchAction.getHeight() / 2.0f));
searchToolbar.setListener(new SearchToolbar.SearchListener() {
@Override
public void onSearchTextChange(String text) {
String trimmed = text.trim();
searchToolbar.get().setListener(new SearchToolbar.SearchListener() {
@Override
public void onSearchTextChange(String text) {
String trimmed = text.trim();
viewModel.updateQuery(trimmed);
viewModel.updateQuery(trimmed);
if (trimmed.length() > 0) {
if (activeAdapter != searchAdapter) {
setAdapter(searchAdapter);
list.removeItemDecoration(searchAdapterDecoration);
list.addItemDecoration(searchAdapterDecoration);
}
} else {
if (activeAdapter != defaultAdapter) {
list.removeItemDecoration(searchAdapterDecoration);
setAdapter(defaultAdapter);
if (trimmed.length() > 0) {
if (activeAdapter != searchAdapter) {
setAdapter(searchAdapter);
list.removeItemDecoration(searchAdapterDecoration);
list.addItemDecoration(searchAdapterDecoration);
}
} else {
if (activeAdapter != defaultAdapter) {
list.removeItemDecoration(searchAdapterDecoration);
setAdapter(defaultAdapter);
}
}
}
}
@Override
public void onSearchClosed() {
list.removeItemDecoration(searchAdapterDecoration);
setAdapter(defaultAdapter);
}
@Override
public void onSearchClosed() {
list.removeItemDecoration(searchAdapterDecoration);
setAdapter(defaultAdapter);
}
});
});
}
@ -557,20 +557,22 @@ public class ConversationListFragment extends MainFragment implements ActionMode
private void onMegaphoneChanged(@Nullable Megaphone megaphone) {
if (megaphone == null) {
megaphoneContainer.setVisibility(View.GONE);
megaphoneContainer.removeAllViews();
if (megaphoneContainer.resolved()) {
megaphoneContainer.get().setVisibility(View.GONE);
megaphoneContainer.get().removeAllViews();
}
return;
}
View view = MegaphoneViewBuilder.build(requireContext(), megaphone, this);
megaphoneContainer.removeAllViews();
megaphoneContainer.get().removeAllViews();
if (view != null) {
megaphoneContainer.addView(view);
megaphoneContainer.setVisibility(View.VISIBLE);
megaphoneContainer.get().addView(view);
megaphoneContainer.get().setVisibility(View.VISIBLE);
} else {
megaphoneContainer.setVisibility(View.GONE);
megaphoneContainer.get().setVisibility(View.GONE);
if (megaphone.getOnVisibleListener() != null) {
megaphone.getOnVisibleListener().onEvent(megaphone, this);
@ -608,9 +610,12 @@ public class ConversationListFragment extends MainFragment implements ActionMode
}
}, reminder -> {
if (reminder.isPresent() && getActivity() != null && !isRemoving()) {
reminderView.showReminder(reminder.get());
} else if (!reminder.isPresent()) {
reminderView.hide();
if (!reminderView.resolved()) {
initializeReminderView();
}
reminderView.get().showReminder(reminder.get());
} else if (reminderView.resolved() && !reminder.isPresent()) {
reminderView.get().hide();
}
});
}
@ -831,15 +836,20 @@ public class ConversationListFragment extends MainFragment implements ActionMode
if (isConversationEmpty) {
Log.i(TAG, "Received an empty data set.");
list.setVisibility(View.INVISIBLE);
emptyState.setVisibility(View.VISIBLE);
emptyImage.setImageResource(EMPTY_IMAGES[(int) (Math.random() * EMPTY_IMAGES.length)]);
emptyState.get().setVisibility(View.VISIBLE);
fab.startPulse(3 * 1000);
cameraFab.startPulse(3 * 1000);
ImageView emptyImage = emptyState.get().findViewById(R.id.empty);
emptyImage.setImageResource(EMPTY_IMAGES[(int) (Math.random() * EMPTY_IMAGES.length)]);
} else {
list.setVisibility(View.VISIBLE);
emptyState.setVisibility(View.GONE);
fab.stopPulse();
cameraFab.stopPulse();
if (emptyState.resolved()) {
emptyState.get().setVisibility(View.GONE);
}
}
}
@ -973,8 +983,8 @@ public class ConversationListFragment extends MainFragment implements ActionMode
}
}
protected @IdRes int getToolbarRes() {
return R.id.toolbar;
protected Toolbar getToolbar(@NonNull View rootView) {
return rootView.findViewById(R.id.toolbar);
}
protected @PluralsRes int getArchivedSnackbarTitleRes() {

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/toolbar_basic"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@null"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarStyle"
android:visibility="gone"
app:layout_constraintTop_toTopOf="parent"
app:titleTextAppearance="@style/TextSecure.TitleTextStyle" />

View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/empty_state"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:orientation="vertical"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/toolbar_barrier"
tools:visibility="visible">
<ImageView
android:id="@+id/empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
tools:src="@drawable/conversation_list_empty_state" />
<TextView
style="@style/Signal.Text.Body"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="32dp"
android:layout_marginBottom="20dp"
android:gravity="center"
android:text="@string/conversation_list_fragment__give_your_inbox_something_to_write_home_about_get_started_by_messaging_a_friend" />
</LinearLayout>

View file

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
@ -68,24 +69,19 @@
</org.thoughtcrime.securesms.util.views.DarkOverflowToolbar>
<androidx.appcompat.widget.Toolbar
<ViewStub
android:id="@+id/toolbar_basic"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@null"
android:layout="@layout/conversation_list_archive_toolbar"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarStyle"
android:visibility="gone"
app:layout_constraintTop_toTopOf="parent"
app:titleTextAppearance="@style/TextSecure.TitleTextStyle" />
app:layout_constraintTop_toTopOf="parent" />
<org.thoughtcrime.securesms.components.SearchToolbar
<ViewStub
android:id="@+id/search_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@null"
android:elevation="4dp"
android:visibility="invisible"
android:layout="@layout/conversation_list_search_toolbar"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.Barrier
@ -119,44 +115,22 @@
app:layout_constraintTop_toBottomOf="@id/toolbar_barrier"
tools:text="@string/SearchFragment_no_results" />
<LinearLayout
<ViewStub
android:id="@+id/empty_state"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout="@layout/conversation_list_empty_state"
android:layout_marginTop="32dp"
android:orientation="vertical"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/toolbar_barrier"
tools:visibility="visible">
app:layout_constraintTop_toBottomOf="@id/toolbar_barrier" />
<ImageView
android:id="@+id/empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
tools:src="@drawable/conversation_list_empty_state" />
<TextView
style="@style/Signal.Text.Body"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="32dp"
android:layout_marginBottom="20dp"
android:gravity="center"
android:text="@string/conversation_list_fragment__give_your_inbox_something_to_write_home_about_get_started_by_messaging_a_friend" />
</LinearLayout>
<org.thoughtcrime.securesms.components.reminder.ReminderView
<ViewStub
android:id="@+id/reminder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/toolbar_barrier"
tools:visibility="gone" />
android:layout="@layout/conversation_list_reminder_view"
app:layout_constraintTop_toBottomOf="@id/toolbar_barrier" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list"
@ -180,9 +154,12 @@
android:layout_width="0dp"
android:layout_height="500dp">
<androidx.constraintlayout.widget.ConstraintLayout
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="bottom|end"
android:gravity="end"
app:layout_behavior="org.thoughtcrime.securesms.util.views.SlideUpWithSnackbarBehavior">
<org.thoughtcrime.securesms.components.registration.PulsingFloatingActionButton
@ -190,45 +167,34 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
android:layout_marginEnd="16dp"
android:contentDescription="@string/conversation_list_fragment__open_camera_description"
android:focusable="true"
android:tint="@color/signal_icon_tint_secondary"
app:backgroundTint="@color/conversation_list_camera_button_background"
app:layout_constraintBottom_toTopOf="@id/fab"
app:layout_constraintEnd_toEndOf="@id/fab"
app:srcCompat="@drawable/ic_camera_solid_white_24" />
<org.thoughtcrime.securesms.components.registration.PulsingFloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:contentDescription="@string/conversation_list_fragment__fab_content_description"
android:focusable="true"
android:tint="@color/core_white"
app:layout_constraintBottom_toTopOf="@id/megaphone_container"
app:layout_constraintEnd_toEndOf="parent"
app:srcCompat="@drawable/ic_compose_solid_24"
app:backgroundTint="@color/core_ultramarine"/>
<androidx.cardview.widget.CardView
<ViewStub
android:id="@+id/megaphone_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout="@layout/conversation_list_megaphone_container"
android:layout_margin="8dp"
android:clipChildren="false"
android:clipToPadding="false"
android:visibility="gone"
app:cardBackgroundColor="@color/signal_background_secondary"
app:cardCornerRadius="8dp"
app:cardElevation="4dp"
app:cardPreventCornerOverlap="false"
app:cardUseCompatPadding="true"
app:contentPadding="0dp"
app:layout_constraintBottom_toBottomOf="parent"
tools:visibility="visible" />
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/megaphone_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
android:clipToPadding="false"
android:visibility="gone"
app:cardBackgroundColor="@color/signal_background_secondary"
app:cardCornerRadius="8dp"
app:cardElevation="4dp"
app:cardPreventCornerOverlap="false"
app:cardUseCompatPadding="true"
app:contentPadding="0dp"
app:layout_constraintBottom_toBottomOf="parent"
tools:visibility="visible" />

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<org.thoughtcrime.securesms.components.reminder.ReminderView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/reminder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/toolbar_barrier" />

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<org.thoughtcrime.securesms.components.SearchToolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/search_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@null"
android:elevation="4dp"
android:visibility="invisible"
app:layout_constraintTop_toTopOf="parent" />