diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java index 21269395a..6adfc50bf 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java @@ -120,6 +120,7 @@ import org.thoughtcrime.securesms.jobs.ServiceOutageDetectionJob; import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.lock.v2.CreateKbsPinActivity; import org.thoughtcrime.securesms.main.Material3OnScrollHelperBinder; +import org.thoughtcrime.securesms.main.SearchBinder; import org.thoughtcrime.securesms.mediasend.v2.MediaSelectionActivity; import org.thoughtcrime.securesms.megaphone.Megaphone; import org.thoughtcrime.securesms.megaphone.MegaphoneActionController; @@ -299,7 +300,6 @@ public class ConversationListFragment extends MainFragment implements ActionMode initializeViewModel(); initializeListAdapters(); initializeTypingObserver(); - initializeSearchListener(); initializeVoiceNotePlayer(); RatingManager.showRatingDialogIfNecessary(requireContext()); @@ -362,6 +362,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode public void onResume() { super.onResume(); + initializeSearchListener(); updateReminders(); EventBus.getDefault().register(this); itemAnimator.disable(); @@ -434,6 +435,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode public void onPause() { super.onPause(); + requireCallback().getSearchAction().setOnClickListener(null); fab.stopPulse(); cameraFab.stopPulse(); EventBus.getDefault().unregister(this); @@ -617,8 +619,6 @@ public class ConversationListFragment extends MainFragment implements ActionMode requireCallback().getSearchAction().setOnClickListener(v -> { fadeOutButtonsAndMegaphone(250); requireCallback().onSearchOpened(); - requireCallback().getSearchToolbar().get().display(requireCallback().getSearchAction().getX() + (requireCallback().getSearchAction().getWidth() / 2.0f), - requireCallback().getSearchAction().getY() + (requireCallback().getSearchAction().getHeight() / 2.0f)); requireCallback().getSearchToolbar().get().setListener(new Material3SearchToolbar.Listener() { @Override @@ -1670,13 +1670,9 @@ public class ConversationListFragment extends MainFragment implements ActionMode } } - public interface Callback extends Material3OnScrollHelperBinder { + public interface Callback extends Material3OnScrollHelperBinder, SearchBinder { @NonNull Toolbar getToolbar(); - @NonNull ImageView getSearchAction(); - - @NonNull Stub getSearchToolbar(); - @NonNull View getUnreadPaymentsDot(); @NonNull Stub getBasicToolbar(); @@ -1685,10 +1681,6 @@ public class ConversationListFragment extends MainFragment implements ActionMode void updateProxyStatus(@NonNull WebSocketConnectionState state); - void onSearchOpened(); - - void onSearchClosed(); - void onMultiSelectStarted(); void onMultiSelectFinished(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/main/MainActivityListHostFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/main/MainActivityListHostFragment.kt index 37de22091..fd223bded 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/main/MainActivityListHostFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/main/MainActivityListHostFragment.kt @@ -172,7 +172,7 @@ class MainActivityListHostFragment : Fragment(R.layout.main_activity_list_host_f private fun presentToolbarForStoriesLandingFragment() { _toolbar.visible = true - _searchAction.visible = false + _searchAction.visible = true if (_basicToolbar.resolved()) { _basicToolbar.get().visible = false } @@ -213,6 +213,7 @@ class MainActivityListHostFragment : Fragment(R.layout.main_activity_list_host_f override fun onSearchOpened() { conversationListTabsViewModel.onSearchOpened() _searchToolbar.get().clearText() + _searchToolbar.get().display(_searchAction.x + (_searchAction.width / 2.0f), _searchAction.y + (_searchAction.height / 2.0f)) } override fun onSearchClosed() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/main/SearchBinder.kt b/app/src/main/java/org/thoughtcrime/securesms/main/SearchBinder.kt new file mode 100644 index 000000000..c69317c2a --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/main/SearchBinder.kt @@ -0,0 +1,15 @@ +package org.thoughtcrime.securesms.main + +import android.widget.ImageView +import org.thoughtcrime.securesms.components.Material3SearchToolbar +import org.thoughtcrime.securesms.util.views.Stub + +interface SearchBinder { + fun getSearchAction(): ImageView + + fun getSearchToolbar(): Stub + + fun onSearchOpened() + + fun onSearchClosed() +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/landing/StoriesLandingFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/landing/StoriesLandingFragment.kt index 2107b6b92..bfbb54b66 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/landing/StoriesLandingFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/landing/StoriesLandingFragment.kt @@ -23,6 +23,7 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.core.Single import io.reactivex.rxjava3.kotlin.subscribeBy import org.thoughtcrime.securesms.R +import org.thoughtcrime.securesms.components.Material3SearchToolbar import org.thoughtcrime.securesms.components.settings.DSLConfiguration import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment import org.thoughtcrime.securesms.components.settings.DSLSettingsText @@ -33,6 +34,7 @@ import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectFor import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord import org.thoughtcrime.securesms.database.model.MmsMessageRecord import org.thoughtcrime.securesms.main.Material3OnScrollHelperBinder +import org.thoughtcrime.securesms.main.SearchBinder import org.thoughtcrime.securesms.mediasend.v2.MediaSelectionActivity import org.thoughtcrime.securesms.permissions.Permissions import org.thoughtcrime.securesms.safety.SafetyNumberBottomSheet @@ -88,6 +90,30 @@ class StoriesLandingFragment : DSLSettingsFragment(layoutId = R.layout.stories_l override fun onResume() { super.onResume() viewModel.isTransitioningToAnotherScreen = false + initializeSearchAction() + } + + override fun onPause() { + super.onPause() + requireListener().getSearchAction().setOnClickListener(null) + } + + private fun initializeSearchAction() { + val searchBinder = requireListener() + searchBinder.getSearchAction().setOnClickListener { + searchBinder.onSearchOpened() + + searchBinder.getSearchToolbar().get().listener = object : Material3SearchToolbar.Listener { + override fun onSearchTextChange(text: String) { + viewModel.setSearchQuery(text.trim()) + } + + override fun onSearchClosed() { + viewModel.setSearchQuery("") + searchBinder.onSearchClosed() + } + } + } } override fun bindAdapter(adapter: MappingAdapter) { @@ -160,7 +186,16 @@ class StoriesLandingFragment : DSLSettingsFragment(layoutId = R.layout.stories_l private fun getConfiguration(state: StoriesLandingState): DSLConfiguration { return configure { - val (stories, hidden) = state.storiesLandingItems.map { + val (stories, hidden) = state.storiesLandingItems.filter { + if (state.searchQuery.isNotEmpty()) { + val storyRecipientName = it.storyRecipient.getDisplayName(requireContext()) + val individualRecipientName = it.individualRecipient.getDisplayName(requireContext()) + + storyRecipientName.contains(state.searchQuery, ignoreCase = true) || individualRecipientName.contains(state.searchQuery, ignoreCase = true) + } else { + true + } + }.map { createStoryLandingItem(it) }.partition { !it.data.isHidden diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/landing/StoriesLandingState.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/landing/StoriesLandingState.kt index f82d9a1c7..79660606b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/landing/StoriesLandingState.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/landing/StoriesLandingState.kt @@ -4,7 +4,8 @@ data class StoriesLandingState( val storiesLandingItems: List = emptyList(), val displayMyStoryItem: Boolean = false, val isHiddenContentVisible: Boolean = false, - val loadingState: LoadingState = LoadingState.INIT + val loadingState: LoadingState = LoadingState.INIT, + val searchQuery: String = "" ) { enum class LoadingState { INIT, diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/landing/StoriesLandingViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/landing/StoriesLandingViewModel.kt index b21cde458..f2454a95d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/landing/StoriesLandingViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/landing/StoriesLandingViewModel.kt @@ -54,6 +54,10 @@ class StoriesLandingViewModel(private val storiesLandingRepository: StoriesLandi .map { it.storyRecipient.id } } + fun setSearchQuery(query: String) { + store.update { it.copy(searchQuery = query) } + } + class Factory(private val storiesLandingRepository: StoriesLandingRepository) : ViewModelProvider.Factory { override fun create(modelClass: Class): T { return modelClass.cast(StoriesLandingViewModel(storiesLandingRepository)) as T