diff --git a/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt index 68b0e14e1d..c28561b109 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt @@ -268,7 +268,7 @@ class ConversationsListActivity : if (adapter == null) { adapter = FlexibleAdapter(conversationItems, this, true) } else { - binding.loadingContent?.visibility = View.GONE + binding.loadingContent.visibility = View.GONE } adapter!!.addListener(this) prepareViews() @@ -373,6 +373,9 @@ class ConversationsListActivity : lifecycleScope.launch { conversationsListViewModel.getRoomsFlow .onEach { list -> + // Refreshes conversation messages in the background asynchronously + list.refreshMessages() + // Update Conversations conversationItems.clear() conversationItemsWithHeader.clear() @@ -446,6 +449,34 @@ class ConversationsListActivity : updateFilterConversationButtonColor() } + private fun List.refreshMessages() { + val previous = conversationItems.associate { + (it as ConversationItem) + val unreadMessages = it.model.unreadMessages + val roomToken = it.model.token + Pair(roomToken, unreadMessages) + } + + val current = this.associateWith { model -> + val unreadMessages = model.unreadMessages + unreadMessages + } + + val result = current.map { (model, unreadMessages) -> + val previousUnreadMessages = previous[model.token] // Check if this conversation exists in last list + previousUnreadMessages?.let { + Pair(model, unreadMessages - previousUnreadMessages) + } + }.filterNotNull() + + val url = userManager.currentUser.blockingGet().baseUrl!! + for (pair in result) { + if (pair.second > 0) { + conversationsListViewModel.updateRoomMessages(pair.first, pair.second, credentials!!, url) + } + } + } + private fun filter(conversation: ConversationModel): Boolean { var result = true for ((k, v) in filterState) { @@ -674,7 +705,7 @@ class ConversationsListActivity : if (!hasFilterEnabled()) filterableConversationItems = searchableConversationItems adapter!!.updateDataSet(filterableConversationItems, false) adapter!!.showAllHeaders() - binding.swipeRefreshLayoutView?.isEnabled = false + binding.swipeRefreshLayoutView.isEnabled = false searchBehaviorSubject.onNext(true) return true } @@ -688,9 +719,9 @@ class ConversationsListActivity : // cancel any pending searches searchHelper!!.cancelSearch() } - binding.swipeRefreshLayoutView?.isRefreshing = false + binding.swipeRefreshLayoutView.isRefreshing = false searchBehaviorSubject.onNext(false) - binding.swipeRefreshLayoutView?.isEnabled = true + binding.swipeRefreshLayoutView.isEnabled = true searchView!!.onActionViewCollapsed() binding.conversationListAppbar.stateListAnimator = AnimatorInflater.loadStateListAnimator( @@ -703,7 +734,7 @@ class ConversationsListActivity : viewThemeUtils.platform.resetStatusBar(this@ConversationsListActivity) } - val layoutManager = binding.recyclerView?.layoutManager as SmoothScrollLinearLayoutManager? + val layoutManager = binding.recyclerView.layoutManager as SmoothScrollLinearLayoutManager? layoutManager?.scrollToPositionWithOffset(0, 0) return true } @@ -797,18 +828,18 @@ class ConversationsListActivity : private fun initOverallLayout(isConversationListNotEmpty: Boolean) { if (isConversationListNotEmpty) { - if (binding.emptyLayout?.visibility != View.GONE) { - binding.emptyLayout?.visibility = View.GONE + if (binding.emptyLayout.visibility != View.GONE) { + binding.emptyLayout.visibility = View.GONE } - if (binding.swipeRefreshLayoutView?.visibility != View.VISIBLE) { - binding.swipeRefreshLayoutView?.visibility = View.VISIBLE + if (binding.swipeRefreshLayoutView.visibility != View.VISIBLE) { + binding.swipeRefreshLayoutView.visibility = View.VISIBLE } } else { - if (binding.emptyLayout?.visibility != View.VISIBLE) { - binding.emptyLayout?.visibility = View.VISIBLE + if (binding.emptyLayout.visibility != View.VISIBLE) { + binding.emptyLayout.visibility = View.VISIBLE } - if (binding.swipeRefreshLayoutView?.visibility != View.GONE) { - binding.swipeRefreshLayoutView?.visibility = View.GONE + if (binding.swipeRefreshLayoutView.visibility != View.GONE) { + binding.swipeRefreshLayoutView.visibility = View.GONE } } } @@ -988,24 +1019,24 @@ class ConversationsListActivity : } } }) - binding.recyclerView?.setOnTouchListener { v: View, _: MotionEvent? -> + binding.recyclerView.setOnTouchListener { v: View, _: MotionEvent? -> if (!isDestroyed) { val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager imm.hideSoftInputFromWindow(v.windowToken, 0) } false } - binding.swipeRefreshLayoutView?.setOnRefreshListener { + binding.swipeRefreshLayoutView.setOnRefreshListener { fetchRooms() fetchPendingInvitations() } - binding.swipeRefreshLayoutView?.let { viewThemeUtils.androidx.themeSwipeRefreshLayout(it) } - binding.emptyLayout?.setOnClickListener { showNewConversationsScreen() } - binding.floatingActionButton?.setOnClickListener { + binding.swipeRefreshLayoutView.let { viewThemeUtils.androidx.themeSwipeRefreshLayout(it) } + binding.emptyLayout.setOnClickListener { showNewConversationsScreen() } + binding.floatingActionButton.setOnClickListener { run(context) showNewConversationsScreen() } - binding.floatingActionButton?.let { viewThemeUtils.material.themeFAB(it) } + binding.floatingActionButton.let { viewThemeUtils.material.themeFAB(it) } binding.switchAccountButton.setOnClickListener { if (resources != null && resources!!.getBoolean(R.bool.multiaccount_support)) { @@ -1177,7 +1208,7 @@ class ConversationsListActivity : @SuppressLint("CheckResult") // handled by helper private fun startMessageSearch(search: String?) { - binding.swipeRefreshLayoutView?.isRefreshing = true + binding.swipeRefreshLayoutView.isRefreshing = true searchHelper?.startMessageSearch(search!!) ?.subscribeOn(Schedulers.io()) ?.observeOn(AndroidSchedulers.mainThread()) @@ -1423,8 +1454,8 @@ class ConversationsListActivity : filesToShare?.forEach { UploadAndShareFilesWorker.upload( it, - selectedConversation!!.token!!, - selectedConversation!!.displayName!!, + selectedConversation!!.token, + selectedConversation!!.displayName, null ) } @@ -1832,15 +1863,15 @@ class ConversationsListActivity : } // add unified search result at the end of the list adapter!!.addItems(adapter!!.mainItemCount + adapter!!.scrollableHeaders.size, adapterItems) - binding.recyclerView?.scrollToPosition(0) + binding.recyclerView.scrollToPosition(0) } } - binding.swipeRefreshLayoutView?.isRefreshing = false + binding.swipeRefreshLayoutView.isRefreshing = false } private fun onMessageSearchError(throwable: Throwable) { handleHttpExceptions(throwable) - binding.swipeRefreshLayoutView?.isRefreshing = false + binding.swipeRefreshLayoutView.isRefreshing = false showErrorDialog() } diff --git a/app/src/main/java/com/nextcloud/talk/conversationlist/viewmodels/ConversationsListViewModel.kt b/app/src/main/java/com/nextcloud/talk/conversationlist/viewmodels/ConversationsListViewModel.kt index f70cf134a0..c6c599afd6 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationlist/viewmodels/ConversationsListViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationlist/viewmodels/ConversationsListViewModel.kt @@ -10,9 +10,11 @@ import android.util.Log import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel +import com.nextcloud.talk.chat.data.ChatMessageRepository import com.nextcloud.talk.conversationlist.data.OfflineConversationsRepository import com.nextcloud.talk.invitation.data.InvitationsModel import com.nextcloud.talk.invitation.data.InvitationsRepository +import com.nextcloud.talk.models.domain.ConversationModel import com.nextcloud.talk.users.UserManager import io.reactivex.Observer import io.reactivex.android.schedulers.AndroidSchedulers @@ -24,6 +26,7 @@ import javax.inject.Inject class ConversationsListViewModel @Inject constructor( private val repository: OfflineConversationsRepository, + private val chatRepository: ChatMessageRepository, var userManager: UserManager ) : ViewModel() { @@ -84,6 +87,10 @@ class ConversationsListViewModel @Inject constructor( repository.getRooms() } + fun updateRoomMessages(model: ConversationModel, limit: Int, credentials: String, baseUrl: String) { + // TODO need to edit fetch init messages to include a limit this is rough + } + inner class FederatedInvitationsObserver : Observer { override fun onSubscribe(d: Disposable) { // unused atm