kopia lustrzana https://github.com/ryukoposting/Signal-Android
Add basic story search support.
rodzic
1049f8bd2f
commit
e8c10cd550
|
@ -120,6 +120,7 @@ import org.thoughtcrime.securesms.jobs.ServiceOutageDetectionJob;
|
||||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||||
import org.thoughtcrime.securesms.lock.v2.CreateKbsPinActivity;
|
import org.thoughtcrime.securesms.lock.v2.CreateKbsPinActivity;
|
||||||
import org.thoughtcrime.securesms.main.Material3OnScrollHelperBinder;
|
import org.thoughtcrime.securesms.main.Material3OnScrollHelperBinder;
|
||||||
|
import org.thoughtcrime.securesms.main.SearchBinder;
|
||||||
import org.thoughtcrime.securesms.mediasend.v2.MediaSelectionActivity;
|
import org.thoughtcrime.securesms.mediasend.v2.MediaSelectionActivity;
|
||||||
import org.thoughtcrime.securesms.megaphone.Megaphone;
|
import org.thoughtcrime.securesms.megaphone.Megaphone;
|
||||||
import org.thoughtcrime.securesms.megaphone.MegaphoneActionController;
|
import org.thoughtcrime.securesms.megaphone.MegaphoneActionController;
|
||||||
|
@ -299,7 +300,6 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
||||||
initializeViewModel();
|
initializeViewModel();
|
||||||
initializeListAdapters();
|
initializeListAdapters();
|
||||||
initializeTypingObserver();
|
initializeTypingObserver();
|
||||||
initializeSearchListener();
|
|
||||||
initializeVoiceNotePlayer();
|
initializeVoiceNotePlayer();
|
||||||
|
|
||||||
RatingManager.showRatingDialogIfNecessary(requireContext());
|
RatingManager.showRatingDialogIfNecessary(requireContext());
|
||||||
|
@ -362,6 +362,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
|
||||||
|
initializeSearchListener();
|
||||||
updateReminders();
|
updateReminders();
|
||||||
EventBus.getDefault().register(this);
|
EventBus.getDefault().register(this);
|
||||||
itemAnimator.disable();
|
itemAnimator.disable();
|
||||||
|
@ -434,6 +435,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
||||||
public void onPause() {
|
public void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
|
|
||||||
|
requireCallback().getSearchAction().setOnClickListener(null);
|
||||||
fab.stopPulse();
|
fab.stopPulse();
|
||||||
cameraFab.stopPulse();
|
cameraFab.stopPulse();
|
||||||
EventBus.getDefault().unregister(this);
|
EventBus.getDefault().unregister(this);
|
||||||
|
@ -617,8 +619,6 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
||||||
requireCallback().getSearchAction().setOnClickListener(v -> {
|
requireCallback().getSearchAction().setOnClickListener(v -> {
|
||||||
fadeOutButtonsAndMegaphone(250);
|
fadeOutButtonsAndMegaphone(250);
|
||||||
requireCallback().onSearchOpened();
|
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() {
|
requireCallback().getSearchToolbar().get().setListener(new Material3SearchToolbar.Listener() {
|
||||||
@Override
|
@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 Toolbar getToolbar();
|
||||||
|
|
||||||
@NonNull ImageView getSearchAction();
|
|
||||||
|
|
||||||
@NonNull Stub<Material3SearchToolbar> getSearchToolbar();
|
|
||||||
|
|
||||||
@NonNull View getUnreadPaymentsDot();
|
@NonNull View getUnreadPaymentsDot();
|
||||||
|
|
||||||
@NonNull Stub<Toolbar> getBasicToolbar();
|
@NonNull Stub<Toolbar> getBasicToolbar();
|
||||||
|
@ -1685,10 +1681,6 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
||||||
|
|
||||||
void updateProxyStatus(@NonNull WebSocketConnectionState state);
|
void updateProxyStatus(@NonNull WebSocketConnectionState state);
|
||||||
|
|
||||||
void onSearchOpened();
|
|
||||||
|
|
||||||
void onSearchClosed();
|
|
||||||
|
|
||||||
void onMultiSelectStarted();
|
void onMultiSelectStarted();
|
||||||
|
|
||||||
void onMultiSelectFinished();
|
void onMultiSelectFinished();
|
||||||
|
|
|
@ -172,7 +172,7 @@ class MainActivityListHostFragment : Fragment(R.layout.main_activity_list_host_f
|
||||||
|
|
||||||
private fun presentToolbarForStoriesLandingFragment() {
|
private fun presentToolbarForStoriesLandingFragment() {
|
||||||
_toolbar.visible = true
|
_toolbar.visible = true
|
||||||
_searchAction.visible = false
|
_searchAction.visible = true
|
||||||
if (_basicToolbar.resolved()) {
|
if (_basicToolbar.resolved()) {
|
||||||
_basicToolbar.get().visible = false
|
_basicToolbar.get().visible = false
|
||||||
}
|
}
|
||||||
|
@ -213,6 +213,7 @@ class MainActivityListHostFragment : Fragment(R.layout.main_activity_list_host_f
|
||||||
override fun onSearchOpened() {
|
override fun onSearchOpened() {
|
||||||
conversationListTabsViewModel.onSearchOpened()
|
conversationListTabsViewModel.onSearchOpened()
|
||||||
_searchToolbar.get().clearText()
|
_searchToolbar.get().clearText()
|
||||||
|
_searchToolbar.get().display(_searchAction.x + (_searchAction.width / 2.0f), _searchAction.y + (_searchAction.height / 2.0f))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSearchClosed() {
|
override fun onSearchClosed() {
|
||||||
|
|
|
@ -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<Material3SearchToolbar>
|
||||||
|
|
||||||
|
fun onSearchOpened()
|
||||||
|
|
||||||
|
fun onSearchClosed()
|
||||||
|
}
|
|
@ -23,6 +23,7 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||||
import io.reactivex.rxjava3.core.Single
|
import io.reactivex.rxjava3.core.Single
|
||||||
import io.reactivex.rxjava3.kotlin.subscribeBy
|
import io.reactivex.rxjava3.kotlin.subscribeBy
|
||||||
import org.thoughtcrime.securesms.R
|
import org.thoughtcrime.securesms.R
|
||||||
|
import org.thoughtcrime.securesms.components.Material3SearchToolbar
|
||||||
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
|
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
|
||||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
|
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
|
||||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
|
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.MediaMmsMessageRecord
|
||||||
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
|
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
|
||||||
import org.thoughtcrime.securesms.main.Material3OnScrollHelperBinder
|
import org.thoughtcrime.securesms.main.Material3OnScrollHelperBinder
|
||||||
|
import org.thoughtcrime.securesms.main.SearchBinder
|
||||||
import org.thoughtcrime.securesms.mediasend.v2.MediaSelectionActivity
|
import org.thoughtcrime.securesms.mediasend.v2.MediaSelectionActivity
|
||||||
import org.thoughtcrime.securesms.permissions.Permissions
|
import org.thoughtcrime.securesms.permissions.Permissions
|
||||||
import org.thoughtcrime.securesms.safety.SafetyNumberBottomSheet
|
import org.thoughtcrime.securesms.safety.SafetyNumberBottomSheet
|
||||||
|
@ -88,6 +90,30 @@ class StoriesLandingFragment : DSLSettingsFragment(layoutId = R.layout.stories_l
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
viewModel.isTransitioningToAnotherScreen = false
|
viewModel.isTransitioningToAnotherScreen = false
|
||||||
|
initializeSearchAction()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
requireListener<SearchBinder>().getSearchAction().setOnClickListener(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initializeSearchAction() {
|
||||||
|
val searchBinder = requireListener<SearchBinder>()
|
||||||
|
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) {
|
override fun bindAdapter(adapter: MappingAdapter) {
|
||||||
|
@ -160,7 +186,16 @@ class StoriesLandingFragment : DSLSettingsFragment(layoutId = R.layout.stories_l
|
||||||
|
|
||||||
private fun getConfiguration(state: StoriesLandingState): DSLConfiguration {
|
private fun getConfiguration(state: StoriesLandingState): DSLConfiguration {
|
||||||
return configure {
|
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)
|
createStoryLandingItem(it)
|
||||||
}.partition {
|
}.partition {
|
||||||
!it.data.isHidden
|
!it.data.isHidden
|
||||||
|
|
|
@ -4,7 +4,8 @@ data class StoriesLandingState(
|
||||||
val storiesLandingItems: List<StoriesLandingItemData> = emptyList(),
|
val storiesLandingItems: List<StoriesLandingItemData> = emptyList(),
|
||||||
val displayMyStoryItem: Boolean = false,
|
val displayMyStoryItem: Boolean = false,
|
||||||
val isHiddenContentVisible: Boolean = false,
|
val isHiddenContentVisible: Boolean = false,
|
||||||
val loadingState: LoadingState = LoadingState.INIT
|
val loadingState: LoadingState = LoadingState.INIT,
|
||||||
|
val searchQuery: String = ""
|
||||||
) {
|
) {
|
||||||
enum class LoadingState {
|
enum class LoadingState {
|
||||||
INIT,
|
INIT,
|
||||||
|
|
|
@ -54,6 +54,10 @@ class StoriesLandingViewModel(private val storiesLandingRepository: StoriesLandi
|
||||||
.map { it.storyRecipient.id }
|
.map { it.storyRecipient.id }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setSearchQuery(query: String) {
|
||||||
|
store.update { it.copy(searchQuery = query) }
|
||||||
|
}
|
||||||
|
|
||||||
class Factory(private val storiesLandingRepository: StoriesLandingRepository) : ViewModelProvider.Factory {
|
class Factory(private val storiesLandingRepository: StoriesLandingRepository) : ViewModelProvider.Factory {
|
||||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||||
return modelClass.cast(StoriesLandingViewModel(storiesLandingRepository)) as T
|
return modelClass.cast(StoriesLandingViewModel(storiesLandingRepository)) as T
|
||||||
|
|
Ładowanie…
Reference in New Issue