mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-24 06:00:49 +01:00
Merge pull request #1659 from nextcloud/feature/1644/avatar-hovercard
Avatar "hovercard"
This commit is contained in:
commit
6b13d0b818
@ -4,6 +4,8 @@
|
||||
* @author Mario Danic
|
||||
* @author Marcel Hibbe
|
||||
* @author Andy Scherzinger
|
||||
* @author Tim Krüger
|
||||
* Copyright (C) 2021 Tim Krüger <t@timkrueger.me>
|
||||
* Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
|
||||
* Copyright (C) 2021 Marcel Hibbe <dev@mhibbe.de>
|
||||
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||
@ -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<ChatMessage>(incomingView) {
|
||||
class IncomingLocationMessageViewHolder(incomingView: View, payload: Any) : MessageHolders
|
||||
.IncomingTextMessageViewHolder<ChatMessage>(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)
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
* Nextcloud Talk application
|
||||
*
|
||||
* @author Andy Scherzinger
|
||||
* @author Tim Krüger
|
||||
* Copyright (C) 2021 Tim Krüger <t@timkrueger.me>
|
||||
* Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,8 @@
|
||||
* @author Mario Danic
|
||||
* @author Marcel Hibbe
|
||||
* @author Andy Scherzinger
|
||||
* @author Tim Krüger
|
||||
* Copyright (C) 2021 Tim Krüger <t@timkrueger.me>
|
||||
* Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
|
||||
* Copyright (C) 2021 Marcel Hibbe <dev@mhibbe.de>
|
||||
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||
@ -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<ChatMessage>(incomingView) {
|
||||
class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) : MessageHolders
|
||||
.IncomingTextMessageViewHolder<ChatMessage>(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)
|
||||
}
|
||||
|
@ -3,6 +3,8 @@
|
||||
*
|
||||
* @author Mario Danic
|
||||
* @author Andy Scherzinger
|
||||
* @author Tim Krüger
|
||||
* Copyright (C) 2021 Tim Krüger <t@timkrueger.me>
|
||||
* Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
|
||||
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||
*
|
||||
@ -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<ChatMessage>(itemView) {
|
||||
class MagicIncomingTextMessageViewHolder(itemView: View, payload: Any) : MessageHolders
|
||||
.IncomingTextMessageViewHolder<ChatMessage>(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)
|
||||
}
|
||||
|
@ -4,6 +4,8 @@
|
||||
* @author Mario Danic
|
||||
* @author Marcel Hibbe
|
||||
* @author Andy Scherzinger
|
||||
* @author Tim Krüger
|
||||
* Copyright (C) 2021 Tim Krüger <t@timkrueger.me>
|
||||
* Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
|
||||
* Copyright (C) 2021 Marcel Hibbe <dev@mhibbe.de>
|
||||
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||
@ -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) {
|
||||
|
@ -2,6 +2,8 @@
|
||||
* Nextcloud Talk application
|
||||
*
|
||||
* @author Andy Scherzinger
|
||||
* @author Tim Krüger
|
||||
* Copyright (C) 2021 Tim Krüger <t@timkrueger.me>
|
||||
* Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
@ -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<GenericOverall> notificationCalls(@Header("Authorization") String authorization, @Url String url,
|
||||
@Field("level") Integer level);
|
||||
|
||||
@GET
|
||||
Observable<HoverCardOverall> hoverCard(@Header("Authorization") String authorization, @Url String url);
|
||||
}
|
||||
|
@ -68,32 +68,32 @@ public class DavUtils {
|
||||
public static final String PROPERTY_QUOTA_AVAILABLE_BYTES = "quota-available-bytes";
|
||||
|
||||
static Property.Name[] getAllPropSet() {
|
||||
List<Property.Name> propSet = new ArrayList<>();
|
||||
List<Property.Name> props = new ArrayList<>();
|
||||
|
||||
propSet.add(DisplayName.NAME);
|
||||
propSet.add(GetContentType.NAME);
|
||||
propSet.add(GetContentLength.NAME);
|
||||
propSet.add(GetContentType.NAME);
|
||||
propSet.add(GetContentLength.NAME);
|
||||
propSet.add(GetLastModified.NAME);
|
||||
propSet.add(CreationDate.NAME);
|
||||
propSet.add(GetETag.NAME);
|
||||
propSet.add(ResourceType.NAME);
|
||||
props.add(DisplayName.NAME);
|
||||
props.add(GetContentType.NAME);
|
||||
props.add(GetContentLength.NAME);
|
||||
props.add(GetContentType.NAME);
|
||||
props.add(GetContentLength.NAME);
|
||||
props.add(GetLastModified.NAME);
|
||||
props.add(CreationDate.NAME);
|
||||
props.add(GetETag.NAME);
|
||||
props.add(ResourceType.NAME);
|
||||
|
||||
propSet.add(NCPermission.NAME);
|
||||
propSet.add(OCId.NAME);
|
||||
propSet.add(OCSize.NAME);
|
||||
propSet.add(OCFavorite.NAME);
|
||||
propSet.add(new Property.Name(OC_NAMESPACE, EXTENDED_PROPERTY_OWNER_ID));
|
||||
propSet.add(new Property.Name(OC_NAMESPACE, EXTENDED_PROPERTY_OWNER_DISPLAY_NAME));
|
||||
propSet.add(new Property.Name(OC_NAMESPACE, EXTENDED_PROPERTY_UNREAD_COMMENTS));
|
||||
props.add(NCPermission.NAME);
|
||||
props.add(OCId.NAME);
|
||||
props.add(OCSize.NAME);
|
||||
props.add(OCFavorite.NAME);
|
||||
props.add(new Property.Name(OC_NAMESPACE, EXTENDED_PROPERTY_OWNER_ID));
|
||||
props.add(new Property.Name(OC_NAMESPACE, EXTENDED_PROPERTY_OWNER_DISPLAY_NAME));
|
||||
props.add(new Property.Name(OC_NAMESPACE, EXTENDED_PROPERTY_UNREAD_COMMENTS));
|
||||
|
||||
propSet.add(NCEncrypted.NAME);
|
||||
propSet.add(new Property.Name(NC_NAMESPACE, EXTENDED_PROPERTY_MOUNT_TYPE));
|
||||
propSet.add(NCPreview.NAME);
|
||||
propSet.add(new Property.Name(NC_NAMESPACE, EXTENDED_PROPERTY_NOTE));
|
||||
props.add(NCEncrypted.NAME);
|
||||
props.add(new Property.Name(NC_NAMESPACE, EXTENDED_PROPERTY_MOUNT_TYPE));
|
||||
props.add(NCPreview.NAME);
|
||||
props.add(new Property.Name(NC_NAMESPACE, EXTENDED_PROPERTY_NOTE));
|
||||
|
||||
return propSet.toArray(new Property.Name[0]);
|
||||
return props.toArray(new Property.Name[0]);
|
||||
}
|
||||
|
||||
public static void registerCustomFactories() {
|
||||
|
@ -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
|
||||
)
|
||||
@ -585,7 +595,7 @@ class ChatController(args: Bundle) :
|
||||
if (layoutManager!!.findFirstCompletelyVisibleItemPosition() < newMessagesCount) {
|
||||
newMessagesCount = 0
|
||||
|
||||
if (binding.popupBubbleView.isShown == true) {
|
||||
if (binding.popupBubbleView.isShown) {
|
||||
binding.popupBubbleView.hide()
|
||||
}
|
||||
}
|
||||
@ -640,7 +650,7 @@ class ChatController(args: Bundle) :
|
||||
}
|
||||
} catch (npe: NullPointerException) {
|
||||
// view binding can be null
|
||||
// since this is called asynchrously and UI might have been destroyed in the meantime
|
||||
// since this is called asynchronously and UI might have been destroyed in the meantime
|
||||
Log.i(TAG, "UI destroyed - view binding already gone")
|
||||
}
|
||||
}
|
||||
@ -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())
|
||||
|
@ -1007,8 +1007,14 @@ class ConversationInfoController(args: Bundle) :
|
||||
R.drawable.ic_lock_grey600_24px,
|
||||
context!!.getString(R.string.nc_attendee_pin, participant.attendeePin)
|
||||
),
|
||||
BasicListItemWithImage(R.drawable.ic_pencil_grey600_24dp, context!!.getString(R.string.nc_promote)),
|
||||
BasicListItemWithImage(R.drawable.ic_pencil_grey600_24dp, context!!.getString(R.string.nc_demote)),
|
||||
BasicListItemWithImage(
|
||||
R.drawable.ic_pencil_grey600_24dp,
|
||||
context!!.getString(R.string.nc_promote)
|
||||
),
|
||||
BasicListItemWithImage(
|
||||
R.drawable.ic_pencil_grey600_24dp,
|
||||
context!!.getString(R.string.nc_demote)
|
||||
),
|
||||
BasicListItemWithImage(
|
||||
R.drawable.ic_delete_grey600_24dp,
|
||||
context!!.getString(R.string.nc_remove_participant)
|
||||
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
*
|
||||
* Nextcloud Talk application
|
||||
*
|
||||
* @author Tim Krüger
|
||||
* 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.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<HoverCardAction> 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<HoverCardAction> getActions() {
|
||||
return actions;
|
||||
}
|
||||
|
||||
public void setActions(List<HoverCardAction> 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 +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
/*
|
||||
*
|
||||
* Nextcloud Talk application
|
||||
*
|
||||
* @author Tim Krüger
|
||||
* 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.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 + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
*
|
||||
* Nextcloud Talk application
|
||||
*
|
||||
* @author Tim Krüger
|
||||
* 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.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 +
|
||||
'}';
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
*
|
||||
* Nextcloud Talk application
|
||||
*
|
||||
* @author Tim Krüger
|
||||
* 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.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 +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -0,0 +1,217 @@
|
||||
/*
|
||||
*
|
||||
* Nextcloud Talk application
|
||||
*
|
||||
* @author Tim Krüger
|
||||
* 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.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<HoverCardOverall> {
|
||||
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<HoverCardAction>, 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<RoomOverall> {
|
||||
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<RoomOverall> {
|
||||
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())
|
||||
}
|
||||
}
|
||||
}
|
@ -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; }
|
||||
}
|
||||
|
12
app/src/main/res/drawable/ic_talk.xml
Normal file
12
app/src/main/res/drawable/ic_talk.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector android:autoMirrored="true"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="16"
|
||||
android:viewportWidth="16"
|
||||
android:width="24dp"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path
|
||||
android:fillColor="#757575"
|
||||
android:pathData="m7.9992,0.999a6.9993,6.9994 0,0 0,-6.9992 6.9996,6.9993 6.9994,0 0,0 6.9992,6.9994 6.9993,6.9994 0,0 0,3.6308 -1.024c0.8602,0.3418 2.7871,1.356 3.2457,0.9179 0.4792,-0.4577 -0.5626,-2.6116 -0.8124,-3.412a6.9993,6.9994 0,0 0,0.935 -3.4814,6.9993 6.9994,0 0,0 -6.9991,-6.9993zM8,3.6601a4.34,4.3401 0,0 1,4.34 4.3401,4.34 4.3401,0 0,1 -4.34,4.3398 4.34,4.3401 0,0 1,-4.34 -4.3398,4.34 4.3401,0 0,1 4.34,-4.3401z"
|
||||
android:strokeWidth=".14" />
|
||||
</vector>
|
Loading…
Reference in New Issue
Block a user