diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 41ae4ce7f..2aa763474 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -172,6 +172,11 @@
android:name=".shareditems.activities.SharedItemsActivity"
android:theme="@style/AppTheme"/>
+
+
diff --git a/app/src/main/java/com/nextcloud/talk/adapters/items/MessageResultItem.kt b/app/src/main/java/com/nextcloud/talk/adapters/items/MessageResultItem.kt
index 725ed5e1c..bc7e25d23 100644
--- a/app/src/main/java/com/nextcloud/talk/adapters/items/MessageResultItem.kt
+++ b/app/src/main/java/com/nextcloud/talk/adapters/items/MessageResultItem.kt
@@ -42,7 +42,7 @@ data class MessageResultItem constructor(
private val context: Context,
private val currentUser: UserEntity,
val messageEntry: SearchMessageEntry,
- private val showHeader: Boolean
+ private val showHeader: Boolean = false
) :
AbstractFlexibleItem(),
IFilterable,
diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt b/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt
index 5fc0aa2a2..b0c561588 100644
--- a/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt
+++ b/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt
@@ -130,6 +130,7 @@ import com.nextcloud.talk.events.UserMentionClickEvent
import com.nextcloud.talk.events.WebSocketCommunicationEvent
import com.nextcloud.talk.jobs.DownloadFileToCacheWorker
import com.nextcloud.talk.jobs.UploadAndShareFilesWorker
+import com.nextcloud.talk.messagesearch.MessageSearchActivity
import com.nextcloud.talk.models.database.CapabilitiesUtil
import com.nextcloud.talk.models.database.UserEntity
import com.nextcloud.talk.models.json.chat.ChatMessage
@@ -1346,6 +1347,7 @@ class ChatController(args: Bundle) :
override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
if (resultCode != RESULT_OK) {
+ // TODO for message search, CANCELED is fine
Log.e(TAG, "resultCode for received intent was != ok")
return
}
@@ -1452,6 +1454,8 @@ class ChatController(args: Bundle) :
Log.e(javaClass.simpleName, "Something went wrong when trying to upload file", e)
}
}
+ } else if (requestCode == REQUEST_CODE_MESSAGE_SEARCH) {
+ TODO()
}
}
@@ -2469,28 +2473,32 @@ class ChatController(args: Bundle) :
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
- when (item.itemId) {
+ return when (item.itemId) {
android.R.id.home -> {
(activity as MainActivity).resetConversationsList()
- return true
+ true
}
R.id.conversation_video_call -> {
startACall(false, false)
- return true
+ true
}
R.id.conversation_voice_call -> {
startACall(true, false)
- return true
+ true
}
R.id.conversation_info -> {
showConversationInfoScreen()
- return true
+ true
}
R.id.shared_items -> {
showSharedItems()
- return true
+ true
}
- else -> return super.onOptionsItemSelected(item)
+ R.id.conversation_search -> {
+ startMessageSearch()
+ true
+ }
+ else -> super.onOptionsItemSelected(item)
}
}
@@ -2502,6 +2510,14 @@ class ChatController(args: Bundle) :
activity!!.startActivity(intent)
}
+ private fun startMessageSearch() {
+ val intent = Intent(activity, MessageSearchActivity::class.java)
+ intent.putExtra(KEY_CONVERSATION_NAME, currentConversation?.displayName)
+ intent.putExtra(KEY_ROOM_TOKEN, roomToken)
+ intent.putExtra(KEY_USER_ENTITY, conversationUser as Parcelable)
+ activity!!.startActivityForResult(intent, REQUEST_CODE_MESSAGE_SEARCH)
+ }
+
private fun handleSystemMessages(chatMessageList: List): List {
val chatMessageMap = chatMessageList.map { it.id to it }.toMap().toMutableMap()
val chatMessageIterator = chatMessageMap.iterator()
@@ -3087,6 +3103,7 @@ class ChatController(args: Bundle) :
private const val AGE_THREHOLD_FOR_DELETE_MESSAGE: Int = 21600000 // (6 hours in millis = 6 * 3600 * 1000)
private const val REQUEST_CODE_CHOOSE_FILE: Int = 555
private const val REQUEST_CODE_SELECT_CONTACT: Int = 666
+ private const val REQUEST_CODE_MESSAGE_SEARCH: Int = 777
private const val REQUEST_RECORD_AUDIO_PERMISSION = 222
private const val REQUEST_READ_CONTACT_PERMISSION = 234
private const val REQUEST_CAMERA_PERMISSION = 223
diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java b/app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java
index ec59e4833..c76341bf6 100644
--- a/app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java
+++ b/app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java
@@ -74,7 +74,7 @@ import com.nextcloud.talk.adapters.items.MessagesTextHeaderItem;
import com.nextcloud.talk.api.NcApi;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.controllers.base.BaseController;
-import com.nextcloud.talk.controllers.util.MessageSearchHelper;
+import com.nextcloud.talk.messagesearch.MessageSearchHelper;
import com.nextcloud.talk.events.ConversationsListFetchDataEvent;
import com.nextcloud.talk.events.EventStatus;
import com.nextcloud.talk.interfaces.ConversationMenuInterface;
diff --git a/app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt b/app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt
index d684db1b2..b0f7170d8 100644
--- a/app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt
+++ b/app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt
@@ -23,6 +23,7 @@ package com.nextcloud.talk.dagger.modules
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
+import com.nextcloud.talk.messagesearch.MessageSearchViewModel
import com.nextcloud.talk.shareditems.viewmodels.SharedItemsViewModel
import dagger.Binds
import dagger.MapKey
@@ -53,4 +54,9 @@ abstract class ViewModelModule {
@IntoMap
@ViewModelKey(SharedItemsViewModel::class)
abstract fun sharedItemsViewModel(viewModel: SharedItemsViewModel): ViewModel
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(MessageSearchViewModel::class)
+ abstract fun messageSearchViewModel(viewModel: MessageSearchViewModel): ViewModel
}
diff --git a/app/src/main/java/com/nextcloud/talk/messagesearch/MessageSearchActivity.kt b/app/src/main/java/com/nextcloud/talk/messagesearch/MessageSearchActivity.kt
new file mode 100644
index 000000000..5c84c292a
--- /dev/null
+++ b/app/src/main/java/com/nextcloud/talk/messagesearch/MessageSearchActivity.kt
@@ -0,0 +1,238 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Álvaro Brey
+ * Copyright (C) 2022 Álvaro Brey
+ * Copyright (C) 2022 Nextcloud GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package com.nextcloud.talk.messagesearch
+
+import android.app.Activity
+import android.os.Bundle
+import android.text.TextUtils
+import android.view.Menu
+import android.view.MenuItem
+import android.view.View
+import android.widget.Toast
+import androidx.appcompat.widget.SearchView
+import androidx.core.content.res.ResourcesCompat
+import androidx.lifecycle.ViewModelProvider
+import autodagger.AutoInjector
+import com.nextcloud.talk.R
+import com.nextcloud.talk.activities.BaseActivity
+import com.nextcloud.talk.adapters.items.LoadMoreResultsItem
+import com.nextcloud.talk.adapters.items.MessageResultItem
+import com.nextcloud.talk.application.NextcloudTalkApplication
+import com.nextcloud.talk.controllers.ConversationsListController
+import com.nextcloud.talk.databinding.ActivityMessageSearchBinding
+import com.nextcloud.talk.models.database.UserEntity
+import com.nextcloud.talk.utils.DisplayUtils
+import com.nextcloud.talk.utils.bundle.BundleKeys
+import com.nextcloud.talk.utils.rx.SearchViewObservable.Companion.observeSearchView
+import eu.davidea.flexibleadapter.FlexibleAdapter
+import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
+import eu.davidea.viewholders.FlexibleViewHolder
+import io.reactivex.Observable
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.disposables.Disposable
+import io.reactivex.schedulers.Schedulers
+import java.util.concurrent.TimeUnit
+import javax.inject.Inject
+
+@AutoInjector(NextcloudTalkApplication::class)
+class MessageSearchActivity : BaseActivity() {
+
+ @Inject
+ lateinit var viewModelFactory: ViewModelProvider.Factory
+
+ private lateinit var binding: ActivityMessageSearchBinding
+ private lateinit var searchView: SearchView
+
+ private lateinit var user: UserEntity
+
+ private lateinit var viewModel: MessageSearchViewModel
+
+ private var searchViewDisposable: Disposable? = null
+ private var adapter: FlexibleAdapter>? = null
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
+
+ binding = ActivityMessageSearchBinding.inflate(layoutInflater)
+ setupActionBar()
+ setupSystemColors()
+ setContentView(binding.root)
+
+ viewModel = ViewModelProvider(this, viewModelFactory)[MessageSearchViewModel::class.java]
+ user = intent.getParcelableExtra(BundleKeys.KEY_USER_ENTITY)!!
+ val roomToken = intent.getStringExtra(BundleKeys.KEY_ROOM_TOKEN)!!
+ viewModel.initialize(user, roomToken)
+ setupStateObserver()
+ }
+
+ private fun setupActionBar() {
+ setSupportActionBar(binding.messageSearchToolbar)
+ supportActionBar?.setDisplayHomeAsUpEnabled(true)
+ val conversationName = intent.getStringExtra(BundleKeys.KEY_CONVERSATION_NAME)
+ supportActionBar?.title = conversationName
+ }
+
+ private fun setupSystemColors() {
+ DisplayUtils.applyColorToStatusBar(
+ this,
+ ResourcesCompat.getColor(
+ resources, R.color.appbar, null
+ )
+ )
+ DisplayUtils.applyColorToNavigationBar(
+ this.window,
+ ResourcesCompat.getColor(resources, R.color.bg_default, null)
+ )
+ }
+
+ private fun setupStateObserver() {
+ viewModel.state.observe(this) { state ->
+ when (state) {
+ MessageSearchViewModel.EmptyState -> showEmpty()
+ MessageSearchViewModel.InitialState -> showInitial()
+ is MessageSearchViewModel.LoadedState -> showLoaded(state)
+ MessageSearchViewModel.LoadingState -> showLoading()
+ MessageSearchViewModel.ErrorState -> showError()
+ }
+ }
+ }
+
+ private fun showError() {
+ Toast.makeText(this, "Error while searching", Toast.LENGTH_SHORT).show()
+ }
+
+ private fun showLoading() {
+ // TODO
+ Toast.makeText(this, "LOADING", Toast.LENGTH_LONG).show()
+ }
+
+ private fun showLoaded(state: MessageSearchViewModel.LoadedState) {
+ binding.emptyContainer.emptyListView.visibility = View.GONE
+ binding.messageSearchRecycler.visibility = View.VISIBLE
+ setAdapterItems(state)
+ }
+
+ private fun setAdapterItems(state: MessageSearchViewModel.LoadedState) {
+ val loadMoreItems = if (state.hasMore) {
+ listOf(LoadMoreResultsItem)
+ } else {
+ emptyList()
+ }
+ val newItems =
+ state.results.map { MessageResultItem(this, user, it) } + loadMoreItems
+
+ if (adapter != null) {
+ adapter!!.updateDataSet(newItems)
+ } else {
+ createAdapter(newItems)
+ }
+ }
+
+ private fun createAdapter(items: List>) {
+ adapter = FlexibleAdapter(items)
+ binding.messageSearchRecycler.adapter = adapter
+ adapter!!.addListener(object : FlexibleAdapter.OnItemClickListener {
+ override fun onItemClick(view: View?, position: Int): Boolean {
+ val item = adapter!!.getItem(position)
+ if (item?.itemViewType == LoadMoreResultsItem.VIEW_TYPE) {
+ viewModel.loadMore()
+ }
+ return false
+ }
+ })
+ }
+
+ private fun showInitial() {
+ binding.messageSearchRecycler.visibility = View.GONE
+ binding.emptyContainer.emptyListViewHeadline.text = "Start typing to search..."
+ binding.emptyContainer.emptyListView.visibility = View.VISIBLE
+ }
+
+ private fun showEmpty() {
+ binding.messageSearchRecycler.visibility = View.GONE
+ binding.emptyContainer.emptyListViewHeadline.text = "No search results"
+ binding.emptyContainer.emptyListView.visibility = View.VISIBLE
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu?): Boolean {
+ menuInflater.inflate(R.menu.menu_search, menu)
+ return true
+ }
+
+ override fun onPrepareOptionsMenu(menu: Menu?): Boolean {
+ val menuItem = menu!!.findItem(R.id.action_search)
+ searchView = menuItem.actionView as SearchView
+ setupSearchView()
+ menuItem.setOnActionExpandListener(object : MenuItem.OnActionExpandListener {
+ override fun onMenuItemActionExpand(item: MenuItem?): Boolean {
+ searchView.requestFocus()
+ return true
+ }
+
+ override fun onMenuItemActionCollapse(item: MenuItem?): Boolean {
+ onBackPressed()
+ return false
+ }
+ })
+ menuItem.expandActionView()
+ return true
+ }
+
+ private fun setupSearchView() {
+ searchView.queryHint = getString(R.string.nc_search_hint)
+ searchViewDisposable = observeSearchView(searchView)
+ .debounce { query ->
+ when {
+ TextUtils.isEmpty(query) -> Observable.empty()
+ else -> Observable.timer(
+ ConversationsListController.SEARCH_DEBOUNCE_INTERVAL_MS.toLong(),
+ TimeUnit.MILLISECONDS
+ )
+ }
+ }
+ .distinctUntilChanged()
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe { newText -> viewModel.onQueryTextChange(newText) }
+ }
+
+ override fun onBackPressed() {
+ setResult(Activity.RESULT_CANCELED)
+ finish()
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ return when (item.itemId) {
+ android.R.id.home -> {
+ onBackPressed()
+ true
+ }
+ else -> super.onOptionsItemSelected(item)
+ }
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ searchViewDisposable?.dispose()
+ }
+}
diff --git a/app/src/main/java/com/nextcloud/talk/controllers/util/MessageSearchHelper.kt b/app/src/main/java/com/nextcloud/talk/messagesearch/MessageSearchHelper.kt
similarity index 77%
rename from app/src/main/java/com/nextcloud/talk/controllers/util/MessageSearchHelper.kt
rename to app/src/main/java/com/nextcloud/talk/messagesearch/MessageSearchHelper.kt
index 8a82398ec..0350a9f73 100644
--- a/app/src/main/java/com/nextcloud/talk/controllers/util/MessageSearchHelper.kt
+++ b/app/src/main/java/com/nextcloud/talk/messagesearch/MessageSearchHelper.kt
@@ -19,7 +19,7 @@
* along with this program. If not, see .
*/
-package com.nextcloud.talk.controllers.util
+package com.nextcloud.talk.messagesearch
import android.util.Log
import com.nextcloud.talk.models.database.UserEntity
@@ -28,9 +28,10 @@ import com.nextcloud.talk.repositories.unifiedsearch.UnifiedSearchRepository
import io.reactivex.Observable
import io.reactivex.disposables.Disposable
-class MessageSearchHelper(
+class MessageSearchHelper @JvmOverloads constructor(
private val user: UserEntity,
private val unifiedSearchRepository: UnifiedSearchRepository,
+ private val fromRoom: String? = null
) {
data class MessageSearchResults(val messages: List, val hasMore: Boolean)
@@ -58,7 +59,7 @@ class MessageSearchHelper(
private fun doSearch(search: String, cursor: Int = 0): Observable {
disposeIfPossible()
- return unifiedSearchRepository.searchMessages(user, search, cursor)
+ return searchCall(search, cursor)
.map { results ->
previousSearch = search
previousCursor = results.cursor
@@ -76,6 +77,29 @@ class MessageSearchHelper(
.doOnComplete(this::disposeIfPossible)
}
+ private fun searchCall(
+ search: String,
+ cursor: Int
+ ): Observable> {
+ return when {
+ fromRoom != null -> {
+ unifiedSearchRepository.searchInRoom(
+ userEntity = user,
+ roomToken = fromRoom,
+ searchTerm = search,
+ cursor = cursor
+ )
+ }
+ else -> {
+ unifiedSearchRepository.searchMessages(
+ userEntity = user,
+ searchTerm = search,
+ cursor = cursor
+ )
+ }
+ }
+ }
+
private fun resetCachedData() {
previousSearch = null
previousCursor = 0
diff --git a/app/src/main/java/com/nextcloud/talk/messagesearch/MessageSearchViewModel.kt b/app/src/main/java/com/nextcloud/talk/messagesearch/MessageSearchViewModel.kt
new file mode 100644
index 000000000..a7b0acd9e
--- /dev/null
+++ b/app/src/main/java/com/nextcloud/talk/messagesearch/MessageSearchViewModel.kt
@@ -0,0 +1,114 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Álvaro Brey
+ * Copyright (C) 2022 Álvaro Brey
+ * Copyright (C) 2022 Nextcloud GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package com.nextcloud.talk.messagesearch
+
+import android.annotation.SuppressLint
+import android.util.Log
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import com.nextcloud.talk.models.database.UserEntity
+import com.nextcloud.talk.models.domain.SearchMessageEntry
+import com.nextcloud.talk.repositories.unifiedsearch.UnifiedSearchRepository
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.disposables.Disposable
+import io.reactivex.schedulers.Schedulers
+import javax.inject.Inject
+
+/**
+ * Install PlantUML plugin to render this state diagram
+ * @startuml
+ * hide empty description
+ * [*] --> InitialState
+ * InitialState --> LoadingState
+ * LoadingState --> EmptyState
+ * LoadingState --> LoadedState
+ * LoadingState --> LoadingState
+ * LoadedState --> LoadingState
+ * EmptyState --> LoadingState
+ * LoadingState --> ErrorState
+ * ErrorState --> LoadingState
+ * @enduml
+ */
+class MessageSearchViewModel @Inject constructor(private val unifiedSearchRepository: UnifiedSearchRepository) :
+ ViewModel() {
+
+ sealed class ViewState
+ object InitialState : ViewState()
+ object LoadingState : ViewState()
+ object EmptyState : ViewState()
+ object ErrorState : ViewState()
+ class LoadedState(val results: List, val hasMore: Boolean) : ViewState()
+
+ private lateinit var messageSearchHelper: MessageSearchHelper
+
+ private val _state: MutableLiveData = MutableLiveData(InitialState)
+ val state: LiveData
+ get() = _state
+
+ private var searchDisposable: Disposable? = null
+
+ fun initialize(user: UserEntity, roomToken: String) {
+ messageSearchHelper = MessageSearchHelper(user, unifiedSearchRepository, roomToken)
+ }
+
+ @SuppressLint("CheckResult") // handled by helper
+ fun onQueryTextChange(newText: String) {
+ if (newText.length >= MIN_CHARS_FOR_SEARCH) {
+ _state.value = LoadingState
+ messageSearchHelper.cancelSearch()
+ messageSearchHelper.startMessageSearch(newText)
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(this::onReceiveResults, this::onError)
+ }
+ }
+
+ @SuppressLint("CheckResult") // handled by helper
+ fun loadMore() {
+ _state.value = LoadingState
+ messageSearchHelper.cancelSearch()
+ messageSearchHelper.loadMore()
+ ?.subscribeOn(Schedulers.io())
+ ?.observeOn(AndroidSchedulers.mainThread())
+ ?.subscribe(this::onReceiveResults)
+ }
+
+ private fun onReceiveResults(results: MessageSearchHelper.MessageSearchResults) {
+ if (results.messages.isEmpty()) {
+ _state.value = EmptyState
+ } else {
+ _state.value = LoadedState(results.messages, results.hasMore)
+ }
+ }
+
+ private fun onError(throwable: Throwable) {
+ Log.e(TAG, "onError:", throwable)
+ messageSearchHelper.cancelSearch()
+ _state.value = ErrorState
+ }
+
+ companion object {
+ private val TAG = MessageSearchViewModel::class.simpleName
+ private const val MIN_CHARS_FOR_SEARCH = 2
+ }
+}
diff --git a/app/src/main/java/com/nextcloud/talk/repositories/unifiedsearch/UnifiedSearchRepository.kt b/app/src/main/java/com/nextcloud/talk/repositories/unifiedsearch/UnifiedSearchRepository.kt
index 43a416395..4d91e1219 100644
--- a/app/src/main/java/com/nextcloud/talk/repositories/unifiedsearch/UnifiedSearchRepository.kt
+++ b/app/src/main/java/com/nextcloud/talk/repositories/unifiedsearch/UnifiedSearchRepository.kt
@@ -18,7 +18,13 @@ interface UnifiedSearchRepository {
limit: Int = DEFAULT_PAGE_SIZE
): Observable>
- fun searchInRoom(text: String, roomId: String): Observable>
+ fun searchInRoom(
+ userEntity: UserEntity,
+ roomToken: String,
+ searchTerm: String,
+ cursor: Int = 0,
+ limit: Int = DEFAULT_PAGE_SIZE
+ ): Observable>
companion object {
private const val DEFAULT_PAGE_SIZE = 5
diff --git a/app/src/main/java/com/nextcloud/talk/repositories/unifiedsearch/UnifiedSearchRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/repositories/unifiedsearch/UnifiedSearchRepositoryImpl.kt
index 430aca3d4..1f0d072c3 100644
--- a/app/src/main/java/com/nextcloud/talk/repositories/unifiedsearch/UnifiedSearchRepositoryImpl.kt
+++ b/app/src/main/java/com/nextcloud/talk/repositories/unifiedsearch/UnifiedSearchRepositoryImpl.kt
@@ -48,10 +48,26 @@ class UnifiedSearchRepositoryImpl(private val api: NcApi) : UnifiedSearchReposit
return apiObservable.map { mapToMessageResults(it.ocs?.data!!, searchTerm, limit) }
}
- override fun searchInRoom(text: String, roomId: String): Observable> {
- TODO()
+ override fun searchInRoom(
+ userEntity: UserEntity,
+ roomToken: String,
+ searchTerm: String,
+ cursor: Int,
+ limit: Int
+ ): Observable> {
+ val apiObservable = api.performUnifiedSearch(
+ ApiUtils.getCredentials(userEntity.username, userEntity.token),
+ ApiUtils.getUrlForUnifiedSearch(userEntity.baseUrl, PROVIDER_TALK_MESSAGE_CURRENT),
+ searchTerm,
+ fromUrlForRoom(roomToken),
+ limit,
+ cursor
+ )
+ return apiObservable.map { mapToMessageResults(it.ocs?.data!!, searchTerm, limit) }
}
+ private fun fromUrlForRoom(roomToken: String) = "/call/$roomToken"
+
companion object {
private const val PROVIDER_TALK_MESSAGE = "talk-message"
private const val PROVIDER_TALK_MESSAGE_CURRENT = "talk-message-current"
diff --git a/app/src/main/res/layout/activity_message_search.xml b/app/src/main/res/layout/activity_message_search.xml
new file mode 100644
index 000000000..5c7ddf74c
--- /dev/null
+++ b/app/src/main/res/layout/activity_message_search.xml
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/empty_list.xml b/app/src/main/res/layout/empty_list.xml
index 40ad3c2c7..f1cc5e8c5 100644
--- a/app/src/main/res/layout/empty_list.xml
+++ b/app/src/main/res/layout/empty_list.xml
@@ -20,6 +20,7 @@
License along with this program. If not, see .
-->
diff --git a/app/src/main/res/menu/menu_conversation.xml b/app/src/main/res/menu/menu_conversation.xml
index 28fea422b..7b923aea6 100644
--- a/app/src/main/res/menu/menu_conversation.xml
+++ b/app/src/main/res/menu/menu_conversation.xml
@@ -35,15 +35,22 @@
android:title="@string/nc_conversation_menu_video_call"
app:showAsAction="ifRoom" />
+
+
diff --git a/app/src/main/res/menu/menu_search.xml b/app/src/main/res/menu/menu_search.xml
new file mode 100644
index 000000000..dfb61e115
--- /dev/null
+++ b/app/src/main/res/menu/menu_search.xml
@@ -0,0 +1,30 @@
+
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 4beee18ec..cce6394d6 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -273,14 +273,14 @@
Do not disturb
Away
Invisible
- —
- 😃
- 👍
- 👎
- ❤️
- 😯
- 😢
- More emojis
+ —
+ 😃
+ 👍
+ 👎
+ ❤️
+ 😯
+ 😢
+ More emojis
Don\'t clear
Today
30 minutes
@@ -525,5 +525,6 @@
Call without notification
Messages
Load more results
+ Search…
diff --git a/app/src/test/java/com/nextcloud/talk/controllers/util/MessageSearchHelperTest.kt b/app/src/test/java/com/nextcloud/talk/messagesearch/MessageSearchHelperTest.kt
similarity index 99%
rename from app/src/test/java/com/nextcloud/talk/controllers/util/MessageSearchHelperTest.kt
rename to app/src/test/java/com/nextcloud/talk/messagesearch/MessageSearchHelperTest.kt
index 6099a8e10..4dd9a5560 100644
--- a/app/src/test/java/com/nextcloud/talk/controllers/util/MessageSearchHelperTest.kt
+++ b/app/src/test/java/com/nextcloud/talk/messagesearch/MessageSearchHelperTest.kt
@@ -19,7 +19,7 @@
* along with this program. If not, see .
*/
-package com.nextcloud.talk.controllers.util
+package com.nextcloud.talk.messagesearch
import com.nextcloud.talk.models.database.UserEntity
import com.nextcloud.talk.models.domain.SearchMessageEntry
diff --git a/app/src/test/java/com/nextcloud/talk/test/fakes/FakeUnifiedSearchRepository.kt b/app/src/test/java/com/nextcloud/talk/test/fakes/FakeUnifiedSearchRepository.kt
index cf2827934..2a216e69e 100644
--- a/app/src/test/java/com/nextcloud/talk/test/fakes/FakeUnifiedSearchRepository.kt
+++ b/app/src/test/java/com/nextcloud/talk/test/fakes/FakeUnifiedSearchRepository.kt
@@ -41,7 +41,14 @@ class FakeUnifiedSearchRepository : UnifiedSearchRepository {
return Observable.just(response)
}
- override fun searchInRoom(text: String, roomId: String): Observable> {
- TODO("Not yet implemented")
+ override fun searchInRoom(
+ userEntity: UserEntity,
+ roomToken: String,
+ searchTerm: String,
+ cursor: Int,
+ limit: Int
+ ): Observable> {
+ lastRequestedCursor = cursor
+ return Observable.just(response)
}
}