diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLocationMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLocationMessageViewHolder.kt index 8be30ca94..b55017140 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLocationMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLocationMessageViewHolder.kt @@ -4,6 +4,8 @@ * @author Mario Danic * @author Marcel Hibbe * @author Andy Scherzinger + * @author Tim Krüger + * Copyright (C) 2021 Tim Krüger * Copyright (C) 2021 Andy Scherzinger * Copyright (C) 2021 Marcel Hibbe * Copyright (C) 2017-2018 Mario Danic @@ -48,6 +50,7 @@ import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication import com.nextcloud.talk.databinding.ItemCustomIncomingLocationMessageBinding import com.nextcloud.talk.models.json.chat.ChatMessage +import com.nextcloud.talk.ui.bottom.sheet.ProfileBottomSheet import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.DisplayUtils import com.nextcloud.talk.utils.preferences.AppPreferences @@ -56,8 +59,8 @@ import java.net.URLEncoder import javax.inject.Inject @AutoInjector(NextcloudTalkApplication::class) -class IncomingLocationMessageViewHolder(incomingView: View) : MessageHolders -.IncomingTextMessageViewHolder(incomingView) { +class IncomingLocationMessageViewHolder(incomingView: View, payload: Any) : MessageHolders +.IncomingTextMessageViewHolder(incomingView, payload) { private val binding: ItemCustomIncomingLocationMessageBinding = ItemCustomIncomingLocationMessageBinding.bind(itemView) @@ -102,6 +105,9 @@ class IncomingLocationMessageViewHolder(incomingView: View) : MessageHolders val author: String = message.actorDisplayName if (!TextUtils.isEmpty(author)) { binding.messageAuthor.text = author + binding.messageUserAvatar.setOnClickListener { + (payload as? ProfileBottomSheet)?.showFor(message.actorId, itemView.context) + } } else { binding.messageAuthor.setText(R.string.nc_nick_guest) } diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingPreviewMessageViewHolder.java b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingPreviewMessageViewHolder.java index 1a974ac67..e1d06575e 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingPreviewMessageViewHolder.java +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingPreviewMessageViewHolder.java @@ -2,6 +2,8 @@ * Nextcloud Talk application * * @author Andy Scherzinger + * @author Tim Krüger + * Copyright (C) 2021 Tim Krüger * Copyright (C) 2021 Andy Scherzinger * * This program is free software: you can redistribute it and/or modify @@ -31,8 +33,8 @@ import androidx.emoji.widget.EmojiTextView; public class IncomingPreviewMessageViewHolder extends MagicPreviewMessageViewHolder { private final ItemCustomIncomingPreviewMessageBinding binding; - public IncomingPreviewMessageViewHolder(View itemView) { - super(itemView); + public IncomingPreviewMessageViewHolder(View itemView, Object payload) { + super(itemView, payload); binding = ItemCustomIncomingPreviewMessageBinding.bind(itemView); } diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt index 870a0951f..f03b19839 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt @@ -4,6 +4,8 @@ * @author Mario Danic * @author Marcel Hibbe * @author Andy Scherzinger + * @author Tim Krüger + * Copyright (C) 2021 Tim Krüger * Copyright (C) 2021 Andy Scherzinger * Copyright (C) 2021 Marcel Hibbe * Copyright (C) 2017-2018 Mario Danic @@ -46,6 +48,7 @@ import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication import com.nextcloud.talk.databinding.ItemCustomIncomingVoiceMessageBinding import com.nextcloud.talk.models.json.chat.ChatMessage +import com.nextcloud.talk.ui.bottom.sheet.ProfileBottomSheet import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.DisplayUtils import com.nextcloud.talk.utils.preferences.AppPreferences @@ -54,8 +57,8 @@ import java.util.concurrent.ExecutionException import javax.inject.Inject @AutoInjector(NextcloudTalkApplication::class) -class IncomingVoiceMessageViewHolder(incomingView: View) : MessageHolders -.IncomingTextMessageViewHolder(incomingView) { +class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) : MessageHolders +.IncomingTextMessageViewHolder(incomingView, payload) { private val binding: ItemCustomIncomingVoiceMessageBinding = ItemCustomIncomingVoiceMessageBinding.bind(itemView) @@ -192,6 +195,9 @@ class IncomingVoiceMessageViewHolder(incomingView: View) : MessageHolders val author: String = message.actorDisplayName if (!TextUtils.isEmpty(author)) { binding.messageAuthor.text = author + binding.messageUserAvatar.setOnClickListener { + (payload as? ProfileBottomSheet)?.showFor(message.actorId, itemView.context) + } } else { binding.messageAuthor.setText(R.string.nc_nick_guest) } diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicIncomingTextMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicIncomingTextMessageViewHolder.kt index 80023f38c..37c713449 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicIncomingTextMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicIncomingTextMessageViewHolder.kt @@ -3,6 +3,8 @@ * * @author Mario Danic * @author Andy Scherzinger + * @author Tim Krüger + * Copyright (C) 2021 Tim Krüger * Copyright (C) 2021 Andy Scherzinger * Copyright (C) 2017-2018 Mario Danic * @@ -44,6 +46,7 @@ import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication import com.nextcloud.talk.databinding.ItemCustomIncomingTextMessageBinding import com.nextcloud.talk.models.json.chat.ChatMessage +import com.nextcloud.talk.ui.bottom.sheet.ProfileBottomSheet import com.nextcloud.talk.ui.recyclerview.MessageSwipeCallback import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.DisplayUtils @@ -53,8 +56,8 @@ import com.stfalcon.chatkit.messages.MessageHolders import javax.inject.Inject @AutoInjector(NextcloudTalkApplication::class) -class MagicIncomingTextMessageViewHolder(itemView: View) : MessageHolders -.IncomingTextMessageViewHolder(itemView) { +class MagicIncomingTextMessageViewHolder(itemView: View, payload: Any) : MessageHolders +.IncomingTextMessageViewHolder(itemView, payload) { private val binding: ItemCustomIncomingTextMessageBinding = ItemCustomIncomingTextMessageBinding.bind(itemView) @@ -72,6 +75,9 @@ class MagicIncomingTextMessageViewHolder(itemView: View) : MessageHolders val author: String = message.actorDisplayName if (!TextUtils.isEmpty(author)) { binding.messageAuthor.text = author + binding.messageUserAvatar.setOnClickListener { + (payload as? ProfileBottomSheet)?.showFor(message.actorId, itemView.context) + } } else { binding.messageAuthor.setText(R.string.nc_nick_guest) } diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicPreviewMessageViewHolder.java b/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicPreviewMessageViewHolder.java index 5cc616ad3..703a59e84 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicPreviewMessageViewHolder.java +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicPreviewMessageViewHolder.java @@ -4,6 +4,8 @@ * @author Mario Danic * @author Marcel Hibbe * @author Andy Scherzinger + * @author Tim Krüger + * Copyright (C) 2021 Tim Krüger * Copyright (C) 2021 Andy Scherzinger * Copyright (C) 2021 Marcel Hibbe * Copyright (C) 2017-2018 Mario Danic @@ -54,6 +56,7 @@ import com.nextcloud.talk.jobs.DownloadFileToCacheWorker; import com.nextcloud.talk.models.database.CapabilitiesUtil; import com.nextcloud.talk.models.database.UserEntity; import com.nextcloud.talk.models.json.chat.ChatMessage; +import com.nextcloud.talk.ui.bottom.sheet.ProfileBottomSheet; import com.nextcloud.talk.utils.AccountUtils; import com.nextcloud.talk.utils.DisplayUtils; import com.nextcloud.talk.utils.DrawableUtils; @@ -110,8 +113,8 @@ public abstract class MagicPreviewMessageViewHolder extends MessageHolders.Incom View clickView; - public MagicPreviewMessageViewHolder(View itemView) { - super(itemView); + public MagicPreviewMessageViewHolder(View itemView, Object payload) { + super(itemView, payload); NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this); } @@ -128,6 +131,11 @@ public abstract class MagicPreviewMessageViewHolder extends MessageHolders.Incom } } else { userAvatar.setVisibility(View.VISIBLE); + userAvatar.setOnClickListener(v -> { + if (payload instanceof ProfileBottomSheet){ + ((ProfileBottomSheet) payload).showFor(message.actorId, v.getContext()); + } + }); if (ACTOR_TYPE_BOTS.equals(message.actorType) && ACTOR_ID_CHANGELOG.equals(message.actorId)) { if (context != null) { diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingPreviewMessageViewHolder.java b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingPreviewMessageViewHolder.java index b91aa5ba5..14ba39cee 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingPreviewMessageViewHolder.java +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingPreviewMessageViewHolder.java @@ -2,6 +2,8 @@ * Nextcloud Talk application * * @author Andy Scherzinger + * @author Tim Krüger + * Copyright (C) 2021 Tim Krüger * Copyright (C) 2021 Andy Scherzinger * * This program is free software: you can redistribute it and/or modify @@ -32,7 +34,7 @@ public class OutcomingPreviewMessageViewHolder extends MagicPreviewMessageViewHo private final ItemCustomOutcomingPreviewMessageBinding binding; public OutcomingPreviewMessageViewHolder(View itemView) { - super(itemView); + super(itemView, null); binding = ItemCustomOutcomingPreviewMessageBinding.bind(itemView); } 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 334c95f71..79b25739b 100644 --- a/app/src/main/java/com/nextcloud/talk/api/NcApi.java +++ b/app/src/main/java/com/nextcloud/talk/api/NcApi.java @@ -31,6 +31,7 @@ import com.nextcloud.talk.models.json.conversations.RoomOverall; import com.nextcloud.talk.models.json.conversations.RoomsOverall; import com.nextcloud.talk.models.json.generic.GenericOverall; import com.nextcloud.talk.models.json.generic.Status; +import com.nextcloud.talk.models.json.hovercard.HoverCardOverall; import com.nextcloud.talk.models.json.mention.MentionOverall; import com.nextcloud.talk.models.json.notifications.NotificationOverall; import com.nextcloud.talk.models.json.participants.AddParticipantOverall; @@ -425,4 +426,7 @@ public interface NcApi { @POST Observable notificationCalls(@Header("Authorization") String authorization, @Url String url, @Field("level") Integer level); + + @GET + Observable hoverCard(@Header("Authorization") String authorization, @Url String url); } 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 fa3e50144..cd18dc807 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt +++ b/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt @@ -132,6 +132,7 @@ import com.nextcloud.talk.models.json.conversations.RoomsOverall import com.nextcloud.talk.models.json.generic.GenericOverall import com.nextcloud.talk.models.json.mention.Mention import com.nextcloud.talk.presenters.MentionAutocompletePresenter +import com.nextcloud.talk.ui.bottom.sheet.ProfileBottomSheet import com.nextcloud.talk.ui.dialog.AttachmentDialog import com.nextcloud.talk.ui.recyclerview.MessageSwipeActions import com.nextcloud.talk.ui.recyclerview.MessageSwipeCallback @@ -427,9 +428,12 @@ class ChatController(args: Bundle) : adapterWasNull = true val messageHolders = MessageHolders() + val profileBottomSheet = ProfileBottomSheet(ncApi!!, conversationUser!!, router) + messageHolders.setIncomingTextConfig( MagicIncomingTextMessageViewHolder::class.java, - R.layout.item_custom_incoming_text_message + R.layout.item_custom_incoming_text_message, + profileBottomSheet ) messageHolders.setOutcomingTextConfig( MagicOutcomingTextMessageViewHolder::class.java, @@ -438,7 +442,8 @@ class ChatController(args: Bundle) : messageHolders.setIncomingImageConfig( IncomingPreviewMessageViewHolder::class.java, - R.layout.item_custom_incoming_preview_message + R.layout.item_custom_incoming_preview_message, + profileBottomSheet ) messageHolders.setOutcomingImageConfig( @@ -460,14 +465,17 @@ class ChatController(args: Bundle) : MagicUnreadNoticeMessageViewHolder::class.java, R.layout.item_date_header, MagicUnreadNoticeMessageViewHolder::class.java, - R.layout.item_date_header, this + R.layout.item_date_header, + this ) messageHolders.registerContentType( CONTENT_TYPE_LOCATION, IncomingLocationMessageViewHolder::class.java, + profileBottomSheet, R.layout.item_custom_incoming_location_message, OutcomingLocationMessageViewHolder::class.java, + null, R.layout.item_custom_outcoming_location_message, this ) @@ -475,8 +483,10 @@ class ChatController(args: Bundle) : messageHolders.registerContentType( CONTENT_TYPE_VOICE_MESSAGE, IncomingVoiceMessageViewHolder::class.java, + profileBottomSheet, R.layout.item_custom_incoming_voice_message, OutcomingVoiceMessageViewHolder::class.java, + null, R.layout.item_custom_outcoming_voice_message, this ) @@ -2178,7 +2188,7 @@ class ChatController(args: Bundle) : bundle.putBoolean(BundleKeys.KEY_FORWARD_MSG_FLAG, true) bundle.putString(BundleKeys.KEY_FORWARD_MSG_TEXT, message?.text) bundle.putString(BundleKeys.KEY_FORWARD_HIDE_SOURCE_ROOM, roomId) - getRouter().pushController( + router.pushController( RouterTransaction.with(ConversationsListController(bundle)) .pushChangeHandler(HorizontalChangeHandler()) .popChangeHandler(HorizontalChangeHandler()) diff --git a/app/src/main/java/com/nextcloud/talk/models/json/hovercard/HoverCard.java b/app/src/main/java/com/nextcloud/talk/models/json/hovercard/HoverCard.java new file mode 100644 index 000000000..9a98cd870 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/models/json/hovercard/HoverCard.java @@ -0,0 +1,96 @@ +/* + * + * Nextcloud Talk application + * + * @author Tim Krüger + * Copyright (C) 2021 Tim Krüger + * + * 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.models.json.hovercard; + +import com.bluelinelabs.logansquare.annotation.JsonField; +import com.bluelinelabs.logansquare.annotation.JsonObject; + +import org.parceler.Parcel; + +import java.util.List; +import java.util.Objects; + +@Parcel +@JsonObject +public class HoverCard { + + @JsonField(name = "userId") + public String userId; + + @JsonField(name = "displayName") + public String displayName; + + @JsonField(name = "actions") + public List actions; + + + public String getUserId() { + return this.userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getDisplayName() { + return displayName; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + public List getActions() { + return actions; + } + + public void setActions(List actions) { + this.actions = actions; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + HoverCard hoverCard = (HoverCard) o; + return Objects.equals(userId, hoverCard.userId) && + Objects.equals(displayName, hoverCard.displayName) && + Objects.equals(actions, hoverCard.actions); + } + + @Override + public int hashCode() { + return Objects.hash(userId, displayName, actions); + } + + @Override + public String toString() { + return "HoverCard{" + + "userId='" + userId + '\'' + + ", displayName='" + displayName + '\'' + + ", actions=" + actions + + '}'; + } +} diff --git a/app/src/main/java/com/nextcloud/talk/models/json/hovercard/HoverCardAction.java b/app/src/main/java/com/nextcloud/talk/models/json/hovercard/HoverCardAction.java new file mode 100644 index 000000000..4153ef8e1 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/models/json/hovercard/HoverCardAction.java @@ -0,0 +1,107 @@ +/* + * + * Nextcloud Talk application + * + * @author Tim Krüger + * Copyright (C) 2021 Tim Krüger + * + * 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.models.json.hovercard; + +import com.bluelinelabs.logansquare.annotation.JsonField; +import com.bluelinelabs.logansquare.annotation.JsonObject; + +import org.parceler.Parcel; + +import java.util.Objects; + +@Parcel +@JsonObject +public class HoverCardAction { + + @JsonField(name = "title") + public String title; + + @JsonField(name = "icon") + public String icon; + + @JsonField(name = "hyperlink") + public String hyperlink; + + @JsonField(name = "appId") + public String appId; + + public String getTitle() { + return this.title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getIcon() { + return icon; + } + + public void setIcon(String icon) { + this.icon = icon; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getHyperlink() { + return hyperlink; + } + + public void setHyperlink(String hyperlink) { + this.hyperlink = hyperlink; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + HoverCardAction that = (HoverCardAction) o; + return Objects.equals(title, that.title) && + Objects.equals(icon, that.icon) && + Objects.equals(hyperlink, that.hyperlink) && + Objects.equals(appId, that.appId); + } + + @Override + public int hashCode() { + return Objects.hash(title, icon, hyperlink, appId); + } + + @Override + public String toString() { + return "HoverCardAction{" + + "title='" + title + '\'' + + ", icon='" + icon + '\'' + + ", hyper='" + hyperlink + '\'' + + ", appId='" + appId + '\'' + + '}'; + } +} diff --git a/app/src/main/java/com/nextcloud/talk/models/json/hovercard/HoverCardOCS.java b/app/src/main/java/com/nextcloud/talk/models/json/hovercard/HoverCardOCS.java new file mode 100644 index 000000000..cafc659a4 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/models/json/hovercard/HoverCardOCS.java @@ -0,0 +1,69 @@ +/* + * + * Nextcloud Talk application + * + * @author Tim Krüger + * Copyright (C) 2021 Tim Krüger + * + * 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.models.json.hovercard; + +import com.bluelinelabs.logansquare.annotation.JsonField; +import com.bluelinelabs.logansquare.annotation.JsonObject; +import com.nextcloud.talk.models.json.generic.GenericOCS; + +import java.util.Objects; + +@JsonObject +public class HoverCardOCS extends GenericOCS { + @JsonField(name = "data") + public HoverCard data; + + public HoverCard getData() { + return this.data; + } + + public void setData(HoverCard data) { + this.data = data; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + if (!super.equals(o)) { + return false; + } + HoverCardOCS that = (HoverCardOCS) o; + return Objects.equals(data, that.data); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), data); + } + + @Override + public String toString() { + return "HoverCardOCS{" + + "data=" + data + + '}'; + } + +} diff --git a/app/src/main/java/com/nextcloud/talk/models/json/hovercard/HoverCardOverall.java b/app/src/main/java/com/nextcloud/talk/models/json/hovercard/HoverCardOverall.java new file mode 100644 index 000000000..c73bebe94 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/models/json/hovercard/HoverCardOverall.java @@ -0,0 +1,64 @@ +/* + * + * Nextcloud Talk application + * + * @author Tim Krüger + * Copyright (C) 2021 Tim Krüger + * + * 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.models.json.hovercard; + +import com.bluelinelabs.logansquare.annotation.JsonField; +import com.bluelinelabs.logansquare.annotation.JsonObject; + +import java.util.Objects; + +@JsonObject +public class HoverCardOverall { + @JsonField(name = "ocs") + public HoverCardOCS ocs; + + public HoverCardOCS getOcs() { + return this.ocs; + } + + public void setOcs(HoverCardOCS ocs) { + this.ocs = ocs; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + HoverCardOverall that = (HoverCardOverall) o; + return Objects.equals(ocs, that.ocs); + } + + @Override + public int hashCode() { + return Objects.hash(ocs); + } + + @Override + public String toString() { + return "HoverCardOverall{" + + "ocs=" + ocs + + '}'; + } +} diff --git a/app/src/main/java/com/nextcloud/talk/ui/bottom/sheet/ProfileBottomSheet.kt b/app/src/main/java/com/nextcloud/talk/ui/bottom/sheet/ProfileBottomSheet.kt new file mode 100644 index 000000000..d9ed5bb59 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/ui/bottom/sheet/ProfileBottomSheet.kt @@ -0,0 +1,217 @@ +/* + * + * Nextcloud Talk application + * + * @author Tim Krüger + * Copyright (C) 2021 Tim Krüger + * + * 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.ui.bottom.sheet + +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import android.util.Log +import com.afollestad.materialdialogs.LayoutMode +import com.afollestad.materialdialogs.MaterialDialog +import com.afollestad.materialdialogs.bottomsheets.BottomSheet +import com.bluelinelabs.conductor.Router +import com.nextcloud.talk.R +import com.nextcloud.talk.api.NcApi +import com.nextcloud.talk.controllers.bottomsheet.items.BasicListItemWithImage +import com.nextcloud.talk.controllers.bottomsheet.items.listItemsWithImage +import com.nextcloud.talk.models.database.UserEntity +import com.nextcloud.talk.models.json.conversations.RoomOverall +import com.nextcloud.talk.models.json.hovercard.HoverCardAction +import com.nextcloud.talk.models.json.hovercard.HoverCardOverall +import com.nextcloud.talk.ui.bottom.sheet.ProfileBottomSheet.AllowedAppIds.EMAIL +import com.nextcloud.talk.ui.bottom.sheet.ProfileBottomSheet.AllowedAppIds.PROFILE +import com.nextcloud.talk.ui.bottom.sheet.ProfileBottomSheet.AllowedAppIds.SPREED +import com.nextcloud.talk.utils.ApiUtils +import com.nextcloud.talk.utils.ConductorRemapping +import com.nextcloud.talk.utils.bundle.BundleKeys +import io.reactivex.Observer +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.Schedulers +import org.parceler.Parcels + +private const val TAG = "ProfileBottomSheet" + +class ProfileBottomSheet(val ncApi: NcApi, val userEntity: UserEntity, val router: Router) { + + private val allowedAppIds = listOf(SPREED.stringValue, PROFILE.stringValue, EMAIL.stringValue) + + fun showFor(user: String, context: Context) { + + ncApi.hoverCard( + ApiUtils.getCredentials(userEntity.username, userEntity.token), + ApiUtils.getUrlForHoverCard(userEntity.baseUrl, user) + ).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : io.reactivex.Observer { + override fun onSubscribe(d: Disposable) { + } + + override fun onNext(hoverCardOverall: HoverCardOverall) { + bottomSheet(hoverCardOverall.ocs.data.actions, hoverCardOverall.ocs.data.displayName, user, context) + } + + override fun onError(e: Throwable) { + Log.e(TAG, "Failed to get hover card for user $user", e) + } + + override fun onComplete() { + } + }) + } + + private fun bottomSheet(actions: List, displayName: String, userId: String, context: Context) { + + val filteredActions = actions.filter { allowedAppIds.contains(it.appId) } + val items = filteredActions.map { configureActionListItem(it) } + + MaterialDialog(context, BottomSheet(LayoutMode.WRAP_CONTENT)).show { + cornerRadius(res = R.dimen.corner_radius) + + title(text = displayName) + listItemsWithImage(items = items) { _, index, _ -> + + val action = filteredActions[index] + + when (AllowedAppIds.createFor(action)) { + PROFILE -> openProfile(action.hyperlink, context) + EMAIL -> composeEmail(action.title, context) + SPREED -> talkTo(userId) + } + } + } + } + + private fun configureActionListItem(action: HoverCardAction): BasicListItemWithImage { + + val drawable = when (AllowedAppIds.createFor(action)) { + PROFILE -> R.drawable.ic_user + EMAIL -> R.drawable.ic_email + SPREED -> R.drawable.ic_talk + } + + return BasicListItemWithImage( + drawable, + action.title + ) + } + + private fun talkTo(userId: String) { + + val apiVersion = + ApiUtils.getConversationApiVersion(userEntity, intArrayOf(ApiUtils.APIv4, 1)) + val retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom( + apiVersion, + userEntity.baseUrl, + "1", + null, + userId, + null + ) + val credentials = ApiUtils.getCredentials(userEntity.username, userEntity.token) + ncApi!!.createRoom( + credentials, + retrofitBucket.getUrl(), retrofitBucket.getQueryMap() + ) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : Observer { + override fun onSubscribe(d: Disposable) { + // unused atm + } + + override fun onNext(roomOverall: RoomOverall) { + val bundle = Bundle() + bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, userEntity) + bundle.putString(BundleKeys.KEY_ROOM_TOKEN, roomOverall.getOcs().getData().getToken()) + bundle.putString(BundleKeys.KEY_ROOM_ID, roomOverall.getOcs().getData().getRoomId()) + + // FIXME once APIv2+ is used only, the createRoom already returns all the data + ncApi!!.getRoom( + credentials, + ApiUtils.getUrlForRoom( + apiVersion, userEntity.baseUrl, + roomOverall.getOcs().getData().getToken() + ) + ) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : Observer { + override fun onSubscribe(d: Disposable) { + // unused atm + } + + override fun onNext(roomOverall: RoomOverall) { + bundle.putParcelable( + BundleKeys.KEY_ACTIVE_CONVERSATION, + Parcels.wrap(roomOverall.getOcs().getData()) + ) + ConductorRemapping.remapChatController( + router, userEntity.id, + roomOverall.getOcs().getData().getToken(), bundle, true + ) + } + + override fun onError(e: Throwable) { + Log.e(TAG, e.message, e) + } + + override fun onComplete() { + // unused atm + } + }) + } + + override fun onError(e: Throwable) { + Log.e(TAG, e.message, e) + } + + override fun onComplete() { + // unused atm + } + }) + } + + private fun composeEmail(address: String, context: Context) { + val addresses = arrayListOf(address) + val intent = Intent(Intent.ACTION_SENDTO).apply { + data = Uri.parse("mailto:") // only email apps should handle this + putExtra(Intent.EXTRA_EMAIL, addresses) + } + context.startActivity(intent) + } + + private fun openProfile(hyperlink: String, context: Context) { + val webpage: Uri = Uri.parse(hyperlink) + val intent = Intent(Intent.ACTION_VIEW, webpage) + context.startActivity(intent) + } + + enum class AllowedAppIds(val stringValue: String) { + SPREED("spreed"), + PROFILE("profile"), + EMAIL("email"); + + companion object { + fun createFor(action: HoverCardAction): AllowedAppIds = valueOf(action.appId.uppercase()) + } + } +} diff --git a/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java b/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java index 2a0687a14..7bc3ee1ea 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java +++ b/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java @@ -400,4 +400,7 @@ public class ApiUtils { public static String getUrlToSendLocation(int version, String baseUrl, String roomToken) { return getUrlForChat(version, baseUrl, roomToken) + "/share"; } + + public static String getUrlForHoverCard(String baseUrl, String userId) { return baseUrl + ocsApiVersion + + "/hovercard/v1/" + userId; } } diff --git a/app/src/main/res/drawable/ic_talk.xml b/app/src/main/res/drawable/ic_talk.xml new file mode 100644 index 000000000..c479856dc --- /dev/null +++ b/app/src/main/res/drawable/ic_talk.xml @@ -0,0 +1,12 @@ + + + +