improve fetching of user statuses in conversation list

replace
/ocs/v2.php/apps/user_status/api/v1/statuses

with
"includeStatus=true"
when fetching conversations, see https://nextcloud-talk.readthedocs.io/en/latest/conversation/

fix #2478

Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This commit is contained in:
Marcel Hibbe 2022-10-13 11:54:51 +02:00
parent 5312bee14d
commit 871f798720
No known key found for this signature in database
GPG Key ID: C793F8B59F43CE7B
9 changed files with 35 additions and 144 deletions

View File

@ -564,7 +564,7 @@ public class CallActivity extends CallBaseActivity {
private void handleFromNotification() { private void handleFromNotification() {
int apiVersion = ApiUtils.getConversationApiVersion(conversationUser, new int[]{ApiUtils.APIv4, 1}); int apiVersion = ApiUtils.getConversationApiVersion(conversationUser, new int[]{ApiUtils.APIv4, 1});
ncApi.getRooms(credentials, ApiUtils.getUrlForRooms(apiVersion, baseUrl)) ncApi.getRooms(credentials, ApiUtils.getUrlForRooms(apiVersion, baseUrl), false)
.retry(3) .retry(3)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())

View File

@ -43,7 +43,6 @@ import com.nextcloud.talk.data.user.model.User;
import com.nextcloud.talk.databinding.RvItemConversationWithLastMessageBinding; import com.nextcloud.talk.databinding.RvItemConversationWithLastMessageBinding;
import com.nextcloud.talk.models.json.chat.ChatMessage; import com.nextcloud.talk.models.json.chat.ChatMessage;
import com.nextcloud.talk.models.json.conversations.Conversation; import com.nextcloud.talk.models.json.conversations.Conversation;
import com.nextcloud.talk.models.json.status.Status;
import com.nextcloud.talk.ui.StatusDrawable; import com.nextcloud.talk.ui.StatusDrawable;
import com.nextcloud.talk.ui.theme.ViewThemeUtils; import com.nextcloud.talk.ui.theme.ViewThemeUtils;
import com.nextcloud.talk.utils.ApiUtils; import com.nextcloud.talk.utils.ApiUtils;
@ -51,7 +50,6 @@ import com.nextcloud.talk.utils.DisplayUtils;
import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew; import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
@ -74,22 +72,20 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
private final User user; private final User user;
private final Context context; private final Context context;
private GenericTextHeaderItem header; private GenericTextHeaderItem header;
private final Status status;
private final ViewThemeUtils viewThemeUtils; private final ViewThemeUtils viewThemeUtils;
public ConversationItem(Conversation conversation, User user, Context activityContext, Status status, final ViewThemeUtils viewThemeUtils) { public ConversationItem(Conversation conversation, User user, Context activityContext, final ViewThemeUtils viewThemeUtils) {
this.conversation = conversation; this.conversation = conversation;
this.user = user; this.user = user;
this.context = activityContext; this.context = activityContext;
this.status = status;
this.viewThemeUtils = viewThemeUtils; this.viewThemeUtils = viewThemeUtils;
} }
public ConversationItem(Conversation conversation, User user, public ConversationItem(Conversation conversation, User user,
Context activityContext, GenericTextHeaderItem genericTextHeaderItem, Status status, Context activityContext, GenericTextHeaderItem genericTextHeaderItem,
final ViewThemeUtils viewThemeUtils) { final ViewThemeUtils viewThemeUtils) {
this(conversation, user, activityContext, status, viewThemeUtils); this(conversation, user, activityContext, viewThemeUtils);
this.header = genericTextHeaderItem; this.header = genericTextHeaderItem;
} }
@ -97,7 +93,7 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
public boolean equals(Object o) { public boolean equals(Object o) {
if (o instanceof ConversationItem) { if (o instanceof ConversationItem) {
ConversationItem inItem = (ConversationItem) o; ConversationItem inItem = (ConversationItem) o;
return conversation.equals(inItem.getModel()) && Objects.equals(status, inItem.status); return conversation.equals(inItem.getModel());
} }
return false; return false;
} }
@ -109,7 +105,7 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
@Override @Override
public int hashCode() { public int hashCode() {
int result = conversation.hashCode(); int result = conversation.hashCode();
result = 31 * result + (status != null ? status.hashCode() : 0); result = 31 * result;
return result; return result;
} }
@ -196,13 +192,13 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
holder.binding.favoriteConversationImageView.setVisibility(View.GONE); holder.binding.favoriteConversationImageView.setVisibility(View.GONE);
} }
if (status != null && Conversation.ConversationType.ROOM_SYSTEM != conversation.getType()) { if (conversation.getStatus() != null && Conversation.ConversationType.ROOM_SYSTEM != conversation.getType()) {
float size = DisplayUtils.convertDpToPixel(STATUS_SIZE_IN_DP, appContext); float size = DisplayUtils.convertDpToPixel(STATUS_SIZE_IN_DP, appContext);
holder.binding.userStatusImage.setVisibility(View.VISIBLE); holder.binding.userStatusImage.setVisibility(View.VISIBLE);
holder.binding.userStatusImage.setImageDrawable(new StatusDrawable( holder.binding.userStatusImage.setImageDrawable(new StatusDrawable(
status.getStatus(), conversation.getStatus(),
status.getIcon(), conversation.getStatusIcon(),
size, size,
context.getResources().getColor(R.color.bg_default), context.getResources().getColor(R.color.bg_default),
appContext)); appContext));

View File

@ -44,7 +44,6 @@ import com.nextcloud.talk.models.json.search.ContactsByNumberOverall;
import com.nextcloud.talk.models.json.signaling.SignalingOverall; import com.nextcloud.talk.models.json.signaling.SignalingOverall;
import com.nextcloud.talk.models.json.signaling.settings.SignalingSettingsOverall; import com.nextcloud.talk.models.json.signaling.settings.SignalingSettingsOverall;
import com.nextcloud.talk.models.json.status.StatusOverall; import com.nextcloud.talk.models.json.status.StatusOverall;
import com.nextcloud.talk.models.json.statuses.StatusesOverall;
import com.nextcloud.talk.models.json.unifiedsearch.UnifiedSearchOverall; import com.nextcloud.talk.models.json.unifiedsearch.UnifiedSearchOverall;
import com.nextcloud.talk.models.json.userprofile.UserProfileFieldsOverall; import com.nextcloud.talk.models.json.userprofile.UserProfileFieldsOverall;
import com.nextcloud.talk.models.json.userprofile.UserProfileOverall; import com.nextcloud.talk.models.json.userprofile.UserProfileOverall;
@ -101,7 +100,8 @@ public interface NcApi {
Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /room Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /room
*/ */
@GET @GET
Observable<RoomsOverall> getRooms(@Header("Authorization") String authorization, @Url String url); Observable<RoomsOverall> getRooms(@Header("Authorization") String authorization, @Url String url,
@Nullable @Query("includeStatus") Boolean includeStatus);
/* /*
Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /room/roomToken Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /room/roomToken
@ -518,9 +518,6 @@ public interface NcApi {
@Url String url, @Url String url,
@Field("statusType") String statusType); @Field("statusType") String statusType);
@GET
Observable<StatusesOverall> getUserStatuses(@Header("Authorization") String authorization, @Url String url);
@POST @POST
Observable<GenericOverall> sendReaction(@Header("Authorization") String authorization, @Url String url, Observable<GenericOverall> sendReaction(@Header("Authorization") String authorization, @Url String url,

View File

@ -423,7 +423,7 @@ class ChatController(args: Bundle) :
} }
Log.d(TAG, "handleFromNotification - getRooms - calling") Log.d(TAG, "handleFromNotification - getRooms - calling")
ncApi.getRooms(credentials, ApiUtils.getUrlForRooms(apiVersion, conversationUser?.baseUrl)) ncApi.getRooms(credentials, ApiUtils.getUrlForRooms(apiVersion, conversationUser?.baseUrl), false)
?.subscribeOn(Schedulers.io())?.observeOn(AndroidSchedulers.mainThread()) ?.subscribeOn(Schedulers.io())?.observeOn(AndroidSchedulers.mainThread())
?.subscribe(object : Observer<RoomsOverall> { ?.subscribe(object : Observer<RoomsOverall> {
override fun onSubscribe(d: Disposable) { override fun onSubscribe(d: Disposable) {

View File

@ -96,20 +96,18 @@ import com.nextcloud.talk.messagesearch.MessageSearchHelper
import com.nextcloud.talk.messagesearch.MessageSearchHelper.MessageSearchResults import com.nextcloud.talk.messagesearch.MessageSearchHelper.MessageSearchResults
import com.nextcloud.talk.models.json.conversations.Conversation import com.nextcloud.talk.models.json.conversations.Conversation
import com.nextcloud.talk.models.json.conversations.RoomsOverall import com.nextcloud.talk.models.json.conversations.RoomsOverall
import com.nextcloud.talk.models.json.status.Status
import com.nextcloud.talk.models.json.statuses.StatusesOverall
import com.nextcloud.talk.repositories.unifiedsearch.UnifiedSearchRepository import com.nextcloud.talk.repositories.unifiedsearch.UnifiedSearchRepository
import com.nextcloud.talk.ui.dialog.ChooseAccountDialogFragment import com.nextcloud.talk.ui.dialog.ChooseAccountDialogFragment
import com.nextcloud.talk.ui.dialog.ChooseAccountShareToDialogFragment import com.nextcloud.talk.ui.dialog.ChooseAccountShareToDialogFragment
import com.nextcloud.talk.ui.dialog.ConversationsListBottomDialog import com.nextcloud.talk.ui.dialog.ConversationsListBottomDialog
import com.nextcloud.talk.users.UserManager import com.nextcloud.talk.users.UserManager
import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.utils.ParticipantPermissions
import com.nextcloud.talk.utils.ClosedInterfaceImpl import com.nextcloud.talk.utils.ClosedInterfaceImpl
import com.nextcloud.talk.utils.ConductorRemapping.remapChatController import com.nextcloud.talk.utils.ConductorRemapping.remapChatController
import com.nextcloud.talk.utils.DisplayUtils import com.nextcloud.talk.utils.DisplayUtils
import com.nextcloud.talk.utils.FileUtils import com.nextcloud.talk.utils.FileUtils
import com.nextcloud.talk.utils.Mimetype import com.nextcloud.talk.utils.Mimetype
import com.nextcloud.talk.utils.ParticipantPermissions
import com.nextcloud.talk.utils.bundle.BundleKeys import com.nextcloud.talk.utils.bundle.BundleKeys
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ACTIVE_CONVERSATION import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ACTIVE_CONVERSATION
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_FORWARD_HIDE_SOURCE_ROOM import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_FORWARD_HIDE_SOURCE_ROOM
@ -131,7 +129,6 @@ import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.Observer
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
@ -198,7 +195,6 @@ class ConversationsListController(bundle: Bundle) :
private var layoutManager: SmoothScrollLinearLayoutManager? = null private var layoutManager: SmoothScrollLinearLayoutManager? = null
private val callHeaderItems = HashMap<String, GenericTextHeaderItem>() private val callHeaderItems = HashMap<String, GenericTextHeaderItem>()
private var conversationsListBottomDialog: ConversationsListBottomDialog? = null private var conversationsListBottomDialog: ConversationsListBottomDialog? = null
private val userStatuses = HashMap<String?, Status>()
private var searchHelper: MessageSearchHelper? = null private var searchHelper: MessageSearchHelper? = null
private var searchViewDisposable: Disposable? = null private var searchViewDisposable: Disposable? = null
@ -318,7 +314,7 @@ class ConversationsListController(bundle: Bundle) :
viewThemeUtils.material viewThemeUtils.material
.colorMaterialTextButton((activity as MainActivity?)!!.binding.switchAccountButton) .colorMaterialTextButton((activity as MainActivity?)!!.binding.switchAccountButton)
} }
fetchData() fetchRooms()
} }
} }
@ -493,39 +489,9 @@ class ConversationsListController(bundle: Bundle) :
searchItem!!.expandActionView() searchItem!!.expandActionView()
} }
fun fetchData() { fun fetchRooms() {
if (isUserStatusAvailable(userManager.currentUser.blockingGet())) { val includeStatus = isUserStatusAvailable(userManager.currentUser.blockingGet())
fetchUserStatusesAndRooms()
} else {
fetchRooms()
}
}
private fun fetchUserStatusesAndRooms() {
ncApi.getUserStatuses(credentials, ApiUtils.getUrlForUserStatuses(currentUser!!.baseUrl))
.subscribe(object : Observer<StatusesOverall> {
override fun onSubscribe(d: Disposable) {
// unused atm
}
override fun onNext(statusesOverall: StatusesOverall) {
for (status in statusesOverall.ocs!!.data!!) {
userStatuses[status.userId] = status
}
fetchRooms()
}
override fun onError(e: Throwable) {
Log.e(TAG, "failed to fetch user statuses", e)
fetchRooms()
}
override fun onComplete() {
// unused atm
}
})
}
private fun fetchRooms() {
dispose(null) dispose(null)
isRefreshing = true isRefreshing = true
conversationItems = ArrayList() conversationItems = ArrayList()
@ -538,7 +504,8 @@ class ConversationsListController(bundle: Bundle) :
ApiUtils.getUrlForRooms( ApiUtils.getUrlForRooms(
apiVersion, apiVersion,
currentUser!!.baseUrl currentUser!!.baseUrl
) ),
includeStatus
) )
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
@ -589,7 +556,6 @@ class ConversationsListController(bundle: Bundle) :
conversation, conversation,
currentUser, currentUser,
activity, activity,
userStatuses[conversation.name],
viewThemeUtils viewThemeUtils
) )
conversationItems.add(conversationItem) conversationItems.add(conversationItem)
@ -598,7 +564,6 @@ class ConversationsListController(bundle: Bundle) :
currentUser, currentUser,
activity, activity,
callHeaderItems[headerTitle], callHeaderItems[headerTitle],
userStatuses[conversation.name],
viewThemeUtils viewThemeUtils
) )
conversationItemsWithHeader.add(conversationItemWithHeader) conversationItemsWithHeader.add(conversationItemWithHeader)
@ -681,7 +646,6 @@ class ConversationsListController(bundle: Bundle) :
currentUser, currentUser,
activity, activity,
callHeaderItems[headerTitle], callHeaderItems[headerTitle],
userStatuses[conversation.name],
viewThemeUtils viewThemeUtils
) )
openConversationItems.add(conversationItem) openConversationItems.add(conversationItem)
@ -742,7 +706,7 @@ class ConversationsListController(bundle: Bundle) :
} }
false false
} }
binding.swipeRefreshLayoutView.setOnRefreshListener { fetchData() } binding.swipeRefreshLayoutView.setOnRefreshListener { fetchRooms() }
viewThemeUtils.androidx.themeSwipeRefreshLayout(binding.swipeRefreshLayoutView) viewThemeUtils.androidx.themeSwipeRefreshLayout(binding.swipeRefreshLayoutView)
binding.emptyLayout.setOnClickListener { showNewConversationsScreen() } binding.emptyLayout.setOnClickListener { showNewConversationsScreen() }
binding.floatingActionButton.setOnClickListener { binding.floatingActionButton.setOnClickListener {
@ -1182,7 +1146,7 @@ class ConversationsListController(bundle: Bundle) :
if (currentUser != null && eventStatus.userId == currentUser!!.id) { if (currentUser != null && eventStatus.userId == currentUser!!.id) {
when (eventStatus.eventType) { when (eventStatus.eventType) {
EventStatus.EventType.CONVERSATION_UPDATE -> if (eventStatus.isAllGood && !isRefreshing) { EventStatus.EventType.CONVERSATION_UPDATE -> if (eventStatus.isAllGood && !isRefreshing) {
fetchData() fetchRooms()
} }
else -> {} else -> {}
} }
@ -1191,7 +1155,7 @@ class ConversationsListController(bundle: Bundle) :
@Subscribe(threadMode = ThreadMode.MAIN) @Subscribe(threadMode = ThreadMode.MAIN)
fun onMessageEvent(conversationsListFetchDataEvent: ConversationsListFetchDataEvent?) { fun onMessageEvent(conversationsListFetchDataEvent: ConversationsListFetchDataEvent?) {
fetchData() fetchRooms()
Handler().postDelayed({ Handler().postDelayed({
if (conversationsListBottomDialog!!.isShowing) { if (conversationsListBottomDialog!!.isShowing) {
conversationsListBottomDialog!!.dismiss() conversationsListBottomDialog!!.dismiss()

View File

@ -127,7 +127,19 @@ data class Conversation(
var permissions: Int = 0, var permissions: Int = 0,
@JsonField(name = ["messageExpiration"]) @JsonField(name = ["messageExpiration"])
var messageExpiration: Int = 0 var messageExpiration: Int = 0,
@JsonField(name = ["status"])
var status: String? = null,
@JsonField(name = ["statusIcon"])
var statusIcon: String? = null,
@JsonField(name = ["statusMessage"])
var statusMessage: String? = null,
@JsonField(name = ["statusClearAt"])
var statusClearAt: Long? = 0
) : Parcelable { ) : Parcelable {
// This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject' // This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject'

View File

@ -1,41 +0,0 @@
/*
* Nextcloud Talk application
*
* @author Tim Krüger
* @author Andy Scherzinger
* Copyright (C) 2022 Andy Scherzinger <info@andy-scherzinger.de>
* Copyright (C) 2021 Tim Krüger <t@timkrueger.me>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.models.json.statuses
import android.os.Parcelable
import com.bluelinelabs.logansquare.annotation.JsonField
import com.bluelinelabs.logansquare.annotation.JsonObject
import com.nextcloud.talk.models.json.generic.GenericMeta
import com.nextcloud.talk.models.json.status.Status
import kotlinx.android.parcel.Parcelize
@Parcelize
@JsonObject
data class StatusesOCS(
@JsonField(name = ["meta"])
var meta: GenericMeta?,
@JsonField(name = ["data"])
var data: List<Status>?
) : Parcelable {
// This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject'
constructor() : this(null, null)
}

View File

@ -1,37 +0,0 @@
/*
* Nextcloud Talk application
*
* @author Tim Krüger
* @author Andy Scherzinger
* Copyright (C) 2022 Andy Scherzinger <info@andy-scherzinger.de>
* Copyright (C) 2021 Tim Krüger <t@timkrueger.me>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.models.json.statuses
import android.os.Parcelable
import com.bluelinelabs.logansquare.annotation.JsonField
import com.bluelinelabs.logansquare.annotation.JsonObject
import kotlinx.android.parcel.Parcelize
@Parcelize
@JsonObject
data class StatusesOverall(
@JsonField(name = ["ocs"])
var ocs: StatusesOCS?
) : Parcelable {
// This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject'
constructor() : this(null)
}

View File

@ -202,7 +202,7 @@ class ConversationsListBottomDialog(
.popChangeHandler(HorizontalChangeHandler()) .popChangeHandler(HorizontalChangeHandler())
) )
controller.fetchData() controller.fetchRooms()
} }
private fun executeEntryMenuController(operation: ConversationOperationEnum) { private fun executeEntryMenuController(operation: ConversationOperationEnum) {