MessageSearchViewModel.kt 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. /*
  2. * Nextcloud Talk - Android Client
  3. *
  4. * SPDX-FileCopyrightText: 2022 Álvaro Brey <alvaro@alvarobrey.com>
  5. * SPDX-FileCopyrightText: 2022 Nextcloud GmbH
  6. * SPDX-License-Identifier: GPL-3.0-or-later
  7. */
  8. package com.nextcloud.talk.messagesearch
  9. import android.annotation.SuppressLint
  10. import android.util.Log
  11. import androidx.lifecycle.LiveData
  12. import androidx.lifecycle.MutableLiveData
  13. import androidx.lifecycle.ViewModel
  14. import com.nextcloud.talk.models.domain.SearchMessageEntry
  15. import com.nextcloud.talk.repositories.unifiedsearch.UnifiedSearchRepository
  16. import io.reactivex.android.schedulers.AndroidSchedulers
  17. import io.reactivex.schedulers.Schedulers
  18. import javax.inject.Inject
  19. /**
  20. * Install PlantUML plugin to render this state diagram
  21. * @startuml
  22. * hide empty description
  23. * [*] --> InitialState
  24. * InitialState --> LoadingState
  25. * LoadingState --> EmptyState
  26. * LoadingState --> LoadedState
  27. * LoadingState --> LoadingState
  28. * LoadedState --> LoadingState
  29. * EmptyState --> LoadingState
  30. * LoadingState --> ErrorState
  31. * ErrorState --> LoadingState
  32. * @enduml
  33. */
  34. class MessageSearchViewModel @Inject constructor(private val unifiedSearchRepository: UnifiedSearchRepository) :
  35. ViewModel() {
  36. sealed class ViewState
  37. object InitialState : ViewState()
  38. object LoadingState : ViewState()
  39. object EmptyState : ViewState()
  40. object ErrorState : ViewState()
  41. class LoadedState(val results: List<SearchMessageEntry>, val hasMore: Boolean) : ViewState()
  42. class FinishedState(val selectedMessageId: String) : ViewState()
  43. private lateinit var messageSearchHelper: MessageSearchHelper
  44. private val _state: MutableLiveData<ViewState> = MutableLiveData(InitialState)
  45. val state: LiveData<ViewState>
  46. get() = _state
  47. fun initialize(roomToken: String) {
  48. messageSearchHelper = MessageSearchHelper(unifiedSearchRepository, roomToken)
  49. }
  50. @SuppressLint("CheckResult") // handled by helper
  51. fun onQueryTextChange(newText: String) {
  52. if (newText.length >= MIN_CHARS_FOR_SEARCH) {
  53. _state.value = LoadingState
  54. messageSearchHelper.cancelSearch()
  55. messageSearchHelper.startMessageSearch(newText)
  56. .subscribeOn(Schedulers.io())
  57. .observeOn(AndroidSchedulers.mainThread())
  58. .subscribe(this::onReceiveResults, this::onError)
  59. }
  60. }
  61. @SuppressLint("CheckResult") // handled by helper
  62. fun loadMore() {
  63. _state.value = LoadingState
  64. messageSearchHelper.cancelSearch()
  65. messageSearchHelper.loadMore()
  66. ?.subscribeOn(Schedulers.io())
  67. ?.observeOn(AndroidSchedulers.mainThread())
  68. ?.subscribe(this::onReceiveResults)
  69. }
  70. private fun onReceiveResults(results: MessageSearchHelper.MessageSearchResults) {
  71. if (results.messages.isEmpty()) {
  72. _state.value = EmptyState
  73. } else {
  74. _state.value = LoadedState(results.messages, results.hasMore)
  75. }
  76. }
  77. private fun onError(throwable: Throwable) {
  78. Log.e(TAG, "onError:", throwable)
  79. messageSearchHelper.cancelSearch()
  80. _state.value = ErrorState
  81. }
  82. fun refresh(query: String?) {
  83. query?.let { onQueryTextChange(it) }
  84. }
  85. fun selectMessage(messageEntry: SearchMessageEntry) {
  86. _state.value = FinishedState(messageEntry.messageId!!)
  87. }
  88. companion object {
  89. private val TAG = MessageSearchViewModel::class.simpleName
  90. private const val MIN_CHARS_FOR_SEARCH = 2
  91. }
  92. }