From d453773a1df31065ec38d5b7ae378e2776ab045e Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Fri, 18 Feb 2022 15:49:21 +0100 Subject: [PATCH] show user statuses in conversation info (wip) Signed-off-by: Marcel Hibbe --- .../firebase/MagicFirebaseMessagingService.kt | 2 +- .../talk/activities/CallActivity.java | 2 +- .../activities/CallNotificationActivity.java | 2 +- .../items/MentionAutocompleteItem.java | 8 +- .../talk/adapters/items/UserItem.java | 134 ++++++++++------- .../java/com/nextcloud/talk/api/NcApi.java | 3 +- .../talk/controllers/ContactsController.java | 1 + .../controllers/ConversationInfoController.kt | 24 ++-- .../models/json/participants/Participant.java | 9 ++ .../rv_item_conversation_info_participant.xml | 136 +++++++++++------- ...rv_item_conversation_with_last_message.xml | 3 +- 11 files changed, 206 insertions(+), 118 deletions(-) diff --git a/app/src/gplay/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.kt b/app/src/gplay/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.kt index ea55052db..87facd860 100644 --- a/app/src/gplay/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.kt +++ b/app/src/gplay/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.kt @@ -272,7 +272,7 @@ class MagicFirebaseMessagingService : FirebaseMessagingService() { apiVersion, signatureVerification.userEntity.baseUrl, decryptedPushMessage.id - ) + ), null ) .repeatWhen { completed -> completed.zipWith(Observable.range(1, 12), { _, i -> i }) diff --git a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java index 36f6b9c69..f9ec0ff3b 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java @@ -1755,7 +1755,7 @@ public class CallActivity extends CallBaseActivity { Log.d(TAG, "getPeersForCall"); int apiVersion = ApiUtils.getCallApiVersion(conversationUser, new int[]{ApiUtils.APIv4, 1}); - ncApi.getPeersForCall(credentials, ApiUtils.getUrlForCall(apiVersion, baseUrl, roomToken)) + ncApi.getPeersForCall(credentials, ApiUtils.getUrlForCall(apiVersion, baseUrl, roomToken), null) .subscribeOn(Schedulers.io()) .subscribe(new Observer() { @Override diff --git a/app/src/main/java/com/nextcloud/talk/activities/CallNotificationActivity.java b/app/src/main/java/com/nextcloud/talk/activities/CallNotificationActivity.java index dc3dc0889..97b29f915 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallNotificationActivity.java +++ b/app/src/main/java/com/nextcloud/talk/activities/CallNotificationActivity.java @@ -215,7 +215,7 @@ public class CallNotificationActivity extends CallBaseActivity { int apiVersion = ApiUtils.getCallApiVersion(userBeingCalled, new int[]{ApiUtils.APIv4, 1}); ncApi.getPeersForCall(credentials, ApiUtils.getUrlForCall(apiVersion, userBeingCalled.getBaseUrl(), - currentConversation.getToken())) + currentConversation.getToken()), null) .subscribeOn(Schedulers.io()) .repeatWhen(completed -> completed.zipWith(Observable.range(1, 12), (n, i) -> i) .flatMap(retryCount -> Observable.timer(5, TimeUnit.SECONDS)) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.java b/app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.java index 2d1fec291..5cf654130 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.java +++ b/app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.java @@ -135,7 +135,7 @@ public class MentionAutocompleteItem extends AbstractFlexibleItem implements - ISectionable, IFilterable { + ISectionable, IFilterable { + private Context context; private Participant participant; private UserEntity userEntity; private GenericTextHeaderItem header; public boolean isOnline = true; - public UserItem(Participant participant, UserEntity userEntity, GenericTextHeaderItem genericTextHeaderItem) { + public UserItem(Context activityContext, + Participant participant, + UserEntity userEntity, + GenericTextHeaderItem genericTextHeaderItem) { + this.context = activityContext; this.participant = participant; this.userEntity = userEntity; this.header = genericTextHeaderItem; @@ -72,7 +79,7 @@ public class UserItem extends AbstractFlexibleItem if (o instanceof UserItem) { UserItem inItem = (UserItem) o; return participant.getActorType() == inItem.getModel().getActorType() && - participant.getActorId().equals(inItem.getModel().getActorId()); + participant.getActorId().equals(inItem.getModel().getActorId()); } return false; } @@ -112,7 +119,7 @@ public class UserItem extends AbstractFlexibleItem @Override public void bindViewHolder(FlexibleAdapter adapter, UserItemViewHolder holder, int position, List payloads) { - holder.simpleDraweeView.setController(null); + holder.participantAvatar.setController(null); if (holder.checkedImageView != null) { if (participant.isSelected()) { @@ -122,69 +129,88 @@ public class UserItem extends AbstractFlexibleItem } } + if (participant.status != null && participant.status.equals(StatusType.DND.getString())) { + setOnlineStateIcon(holder, R.drawable.ic_user_status_dnd_with_border); + } else if (participant.statusIcon != null && !participant.statusIcon.isEmpty()) { + holder.participantOnlineStateImage.setVisibility(View.GONE); + holder.participantEmoji.setVisibility(View.VISIBLE); + holder.participantEmoji.setText(participant.statusIcon); + } else if (participant.status != null && participant.status.equals(StatusType.AWAY.getString())) { + setOnlineStateIcon(holder, R.drawable.ic_user_status_away_with_border); + } else if (participant.status != null && participant.status.equals(StatusType.ONLINE.getString())) { + setOnlineStateIcon(holder, R.drawable.online_status_with_border); + } else { + holder.participantEmoji.setVisibility(View.GONE); + holder.participantOnlineStateImage.setVisibility(View.GONE); + } + + if (participant.statusMessage != null) { + holder.statusMessage.setText(participant.statusMessage); + } + if (!isOnline) { holder.contactDisplayName.setTextColor(ResourcesCompat.getColor( - holder.contactDisplayName.getContext().getResources(), - R.color.medium_emphasis_text, - null) - ); - holder.simpleDraweeView.setAlpha(0.38f); + holder.contactDisplayName.getContext().getResources(), + R.color.medium_emphasis_text, + null) + ); + holder.participantAvatar.setAlpha(0.38f); } else { holder.contactDisplayName.setTextColor(ResourcesCompat.getColor( - holder.contactDisplayName.getContext().getResources(), - R.color.high_emphasis_text, - null) - ); - holder.simpleDraweeView.setAlpha(1.0f); + holder.contactDisplayName.getContext().getResources(), + R.color.high_emphasis_text, + null) + ); + holder.participantAvatar.setAlpha(1.0f); } if (adapter.hasFilter()) { FlexibleUtils.highlightText(holder.contactDisplayName, participant.getDisplayName(), - String.valueOf(adapter.getFilter(String.class)), NextcloudTalkApplication.Companion.getSharedApplication() - .getResources().getColor(R.color.colorPrimary)); + String.valueOf(adapter.getFilter(String.class)), NextcloudTalkApplication.Companion.getSharedApplication() + .getResources().getColor(R.color.colorPrimary)); } holder.contactDisplayName.setText(participant.getDisplayName()); if (TextUtils.isEmpty(participant.getDisplayName()) && - (participant.getType().equals(Participant.ParticipantType.GUEST) || participant.getType().equals(Participant.ParticipantType.USER_FOLLOWING_LINK))) { + (participant.getType().equals(Participant.ParticipantType.GUEST) || participant.getType().equals(Participant.ParticipantType.USER_FOLLOWING_LINK))) { holder.contactDisplayName.setText(NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_guest)); } if (participant.getActorType() == Participant.ActorType.GROUPS || - "groups".equals(participant.getSource()) || - participant.getActorType() == Participant.ActorType.CIRCLES || - "circles".equals(participant.getSource())) { - holder.simpleDraweeView.setImageResource(R.drawable.ic_circular_group); + "groups".equals(participant.getSource()) || + participant.getActorType() == Participant.ActorType.CIRCLES || + "circles".equals(participant.getSource())) { + holder.participantAvatar.setImageResource(R.drawable.ic_circular_group); } else if (participant.getActorType() == Participant.ActorType.EMAILS) { - holder.simpleDraweeView.setImageResource(R.drawable.ic_circular_mail); + holder.participantAvatar.setImageResource(R.drawable.ic_circular_mail); } else if (participant.getActorType() == Participant.ActorType.GUESTS || - Participant.ParticipantType.GUEST.equals(participant.getType()) || - Participant.ParticipantType.GUEST_MODERATOR.equals(participant.getType())) { + Participant.ParticipantType.GUEST.equals(participant.getType()) || + Participant.ParticipantType.GUEST_MODERATOR.equals(participant.getType())) { String displayName = NextcloudTalkApplication.Companion.getSharedApplication() - .getResources().getString(R.string.nc_guest); + .getResources().getString(R.string.nc_guest); if (!TextUtils.isEmpty(participant.getDisplayName())) { displayName = participant.getDisplayName(); } DraweeController draweeController = Fresco.newDraweeControllerBuilder() - .setOldController(holder.simpleDraweeView.getController()) - .setAutoPlayAnimations(true) - .setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithNameForGuests(userEntity.getBaseUrl(), - displayName, R.dimen.avatar_size), null)) - .build(); - holder.simpleDraweeView.setController(draweeController); + .setOldController(holder.participantAvatar.getController()) + .setAutoPlayAnimations(true) + .setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithNameForGuests(userEntity.getBaseUrl(), + displayName, R.dimen.avatar_size), null)) + .build(); + holder.participantAvatar.setController(draweeController); } else if (participant.getActorType() == Participant.ActorType.USERS || participant.getSource().equals("users")) { DraweeController draweeController = Fresco.newDraweeControllerBuilder() - .setOldController(holder.simpleDraweeView.getController()) - .setAutoPlayAnimations(true) - .setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(), - participant.getActorId(), R.dimen.avatar_size), null)) - .build(); - holder.simpleDraweeView.setController(draweeController); + .setOldController(holder.participantAvatar.getController()) + .setAutoPlayAnimations(true) + .setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(), + participant.getActorId(), R.dimen.avatar_size), null)) + .build(); + holder.participantAvatar.setController(draweeController); } Resources resources = NextcloudTalkApplication.Companion.getSharedApplication().getResources(); @@ -195,17 +221,17 @@ public class UserItem extends AbstractFlexibleItem holder.videoCallIconView.setImageResource(R.drawable.ic_call_grey_600_24dp); holder.videoCallIconView.setVisibility(View.VISIBLE); holder.videoCallIconView.setContentDescription( - resources.getString(R.string.nc_call_state_with_phone, participant.displayName)); + resources.getString(R.string.nc_call_state_with_phone, participant.displayName)); } else if ((inCallFlag & InCallFlags.WITH_VIDEO) > 0) { holder.videoCallIconView.setImageResource(R.drawable.ic_videocam_grey_600_24dp); holder.videoCallIconView.setVisibility(View.VISIBLE); holder.videoCallIconView.setContentDescription( - resources.getString(R.string.nc_call_state_with_video, participant.displayName)); + resources.getString(R.string.nc_call_state_with_video, participant.displayName)); } else if (inCallFlag > InCallFlags.DISCONNECTED) { holder.videoCallIconView.setImageResource(R.drawable.ic_mic_grey_600_24dp); holder.videoCallIconView.setVisibility(View.VISIBLE); holder.videoCallIconView.setContentDescription( - resources.getString(R.string.nc_call_state_in_call, participant.displayName)); + resources.getString(R.string.nc_call_state_in_call, participant.displayName)); } else { holder.videoCallIconView.setVisibility(View.GONE); } @@ -250,11 +276,17 @@ public class UserItem extends AbstractFlexibleItem } } + private void setOnlineStateIcon(UserItem.UserItemViewHolder holder, int icon) { + holder.participantEmoji.setVisibility(View.GONE); + holder.participantOnlineStateImage.setVisibility(View.VISIBLE); + holder.participantOnlineStateImage.setImageDrawable(ContextCompat.getDrawable(context, icon)); + } + @Override public boolean filter(String constraint) { return participant.getDisplayName() != null && - (Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL).matcher(participant.getDisplayName().trim()).find() || - Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL).matcher(participant.getActorId().trim()).find()); + (Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL).matcher(participant.getDisplayName().trim()).find() || + Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL).matcher(participant.getActorId().trim()).find()); } @Override @@ -271,8 +303,8 @@ public class UserItem extends AbstractFlexibleItem @BindView(R.id.name_text) public EmojiTextView contactDisplayName; - @BindView(R.id.simple_drawee_view) - public SimpleDraweeView simpleDraweeView; + @BindView(R.id.conversation_info_participant_avatar) + public SimpleDraweeView participantAvatar; @Nullable @BindView(R.id.secondary_text) public EmojiTextView contactMentionId; @@ -282,6 +314,12 @@ public class UserItem extends AbstractFlexibleItem @Nullable @BindView(R.id.checkedImageView) ImageView checkedImageView; + @BindView(R.id.conversation_info_participant_emoji) + com.vanniktech.emoji.EmojiEditText participantEmoji; + @BindView(R.id.conversation_info_participant_online_state) + ImageView participantOnlineStateImage; + @BindView(R.id.conversation_info_status_message) + EmojiTextView statusMessage; /** * Default constructor. diff --git a/app/src/main/java/com/nextcloud/talk/api/NcApi.java b/app/src/main/java/com/nextcloud/talk/api/NcApi.java index 5a2384d70..688416959 100644 --- a/app/src/main/java/com/nextcloud/talk/api/NcApi.java +++ b/app/src/main/java/com/nextcloud/talk/api/NcApi.java @@ -187,7 +187,8 @@ public interface NcApi { Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /call/callToken */ @GET - Observable getPeersForCall(@Header("Authorization") String authorization, @Url String url); + Observable getPeersForCall(@Header("Authorization") String authorization, @Url String url, + @QueryMap Map fields); @FormUrlEncoded @POST diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ContactsController.java b/app/src/main/java/com/nextcloud/talk/controllers/ContactsController.java index 3adbb0903..1ca545dfc 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ContactsController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/ContactsController.java @@ -551,6 +551,7 @@ public class ContactsController extends BaseController implements SearchView.OnQ } UserItem newContactItem = new UserItem( + getApplicationContext(), participant, currentUser, userHeaderItems.get(headerTitle) diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ConversationInfoController.kt b/app/src/main/java/com/nextcloud/talk/controllers/ConversationInfoController.kt index 37ab07ee8..b1de2d208 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ConversationInfoController.kt +++ b/app/src/main/java/com/nextcloud/talk/controllers/ConversationInfoController.kt @@ -88,6 +88,7 @@ import org.greenrobot.eventbus.ThreadMode import java.util.Calendar import java.util.Collections import java.util.Comparator +import java.util.HashMap import java.util.Locale import javax.inject.Inject @@ -120,7 +121,7 @@ class ConversationInfoController(args: Bundle) : private var conversation: Conversation? = null private var adapter: FlexibleAdapter? = null - private var recyclerViewItems: MutableList = ArrayList() + private var userItems: MutableList = ArrayList() private var saveStateHandler: LovelySaveStateHandler? = null @@ -362,7 +363,7 @@ class ConversationInfoController(args: Bundle) : private fun setupAdapter() { if (activity != null) { if (adapter == null) { - adapter = FlexibleAdapter(recyclerViewItems, activity, true) + adapter = FlexibleAdapter(userItems, activity, true) } val layoutManager = SmoothScrollLinearLayoutManager(activity) @@ -378,12 +379,12 @@ class ConversationInfoController(args: Bundle) : var userItem: UserItem var participant: Participant - recyclerViewItems = ArrayList() + userItems = ArrayList() var ownUserItem: UserItem? = null for (i in participants.indices) { participant = participants[i] - userItem = UserItem(participant, conversationUser, null) + userItem = UserItem(context, participant, conversationUser, null) if (participant.sessionId != null) { userItem.isOnline = !participant.sessionId.equals("0") } else { @@ -395,20 +396,20 @@ class ConversationInfoController(args: Bundle) : ownUserItem.model.sessionId = "-1" ownUserItem.isOnline = true } else { - recyclerViewItems.add(userItem) + userItems.add(userItem) } } - Collections.sort(recyclerViewItems, UserItemComparator()) + Collections.sort(userItems, UserItemComparator()) if (ownUserItem != null) { - recyclerViewItems.add(0, ownUserItem) + userItems.add(0, ownUserItem) } setupAdapter() binding.participantsListCategory.visibility = View.VISIBLE - adapter!!.updateDataSet(recyclerViewItems) + adapter!!.updateDataSet(userItems) } override val title: String @@ -426,9 +427,12 @@ class ConversationInfoController(args: Bundle) : apiVersion = ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.APIv4, 1)) } + val fieldMap = HashMap() + fieldMap["includeStatus"] = true + ncApi?.getPeersForCall( credentials, - ApiUtils.getUrlForParticipants(apiVersion, conversationUser!!.baseUrl, conversationToken) + ApiUtils.getUrlForParticipants(apiVersion, conversationUser!!.baseUrl, conversationToken), fieldMap ) ?.subscribeOn(Schedulers.io()) ?.observeOn(AndroidSchedulers.mainThread()) @@ -462,7 +466,7 @@ class ConversationInfoController(args: Bundle) : val bundle = Bundle() val existingParticipantsId = arrayListOf() - for (userItem in recyclerViewItems) { + for (userItem in userItems) { if (userItem.model.getActorType() == USERS) { existingParticipantsId.add(userItem.model.getActorId()) } diff --git a/app/src/main/java/com/nextcloud/talk/models/json/participants/Participant.java b/app/src/main/java/com/nextcloud/talk/models/json/participants/Participant.java index 36dbaa482..9465e0936 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/participants/Participant.java +++ b/app/src/main/java/com/nextcloud/talk/models/json/participants/Participant.java @@ -78,6 +78,15 @@ public class Participant { @JsonField(name = "inCall") public Object inCall; + @JsonField(name = "status") + public String status; + + @JsonField(name = "statusIcon") + public String statusIcon; + + @JsonField(name = "statusMessage") + public String statusMessage; + public String source; public boolean selected; diff --git a/app/src/main/res/layout/rv_item_conversation_info_participant.xml b/app/src/main/res/layout/rv_item_conversation_info_participant.xml index d179479c5..82e0db12d 100644 --- a/app/src/main/res/layout/rv_item_conversation_info_participant.xml +++ b/app/src/main/res/layout/rv_item_conversation_info_participant.xml @@ -18,67 +18,103 @@ ~ along with this program. If not, see . --> - + android:layout_height="@dimen/item_height"> + + + + + + + + + + + + - - - - - - - - - + diff --git a/app/src/main/res/layout/rv_item_conversation_with_last_message.xml b/app/src/main/res/layout/rv_item_conversation_with_last_message.xml index 7a3c05001..4f16aef4d 100644 --- a/app/src/main/res/layout/rv_item_conversation_with_last_message.xml +++ b/app/src/main/res/layout/rv_item_conversation_with_last_message.xml @@ -43,8 +43,7 @@ android:layout_width="@dimen/small_item_height" android:layout_height="@dimen/small_item_height" android:contentDescription="@null" - app:roundAsCircle="true" - tools:src="@drawable/ic_call_black_24dp" /> + app:roundAsCircle="true" />