From 75b61675656ec0114c821e2d097691d88975eca5 Mon Sep 17 00:00:00 2001 From: Eyal Date: Sat, 22 Aug 2020 01:43:52 +0300 Subject: [PATCH] added the intro message. there is still a bug that on entering the chat dialog, and on refreshing, the chat scroll moves to the bottom instead of to the top --- .../res/layout/tavern_chat_intro_item.xml | 80 +++++++++++++++++++ .../adapter/social/ChatRecyclerViewAdapter.kt | 6 +- .../ui/adapter/social/InboxAdapter.kt | 54 ++++++++++--- .../social/InboxMessageListFragment.kt | 34 ++++---- .../ui/viewHolders/ChatRecyclerViewHolder.kt | 30 ++++++- 5 files changed, 172 insertions(+), 32 deletions(-) create mode 100644 Habitica/res/layout/tavern_chat_intro_item.xml diff --git a/Habitica/res/layout/tavern_chat_intro_item.xml b/Habitica/res/layout/tavern_chat_intro_item.xml new file mode 100644 index 000000000..10fbf184c --- /dev/null +++ b/Habitica/res/layout/tavern_chat_intro_item.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/ChatRecyclerViewAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/ChatRecyclerViewAdapter.kt index afb4dad1e..00bbe1e3e 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/ChatRecyclerViewAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/ChatRecyclerViewAdapter.kt @@ -9,7 +9,7 @@ import com.habitrpg.android.habitica.extensions.inflate import com.habitrpg.android.habitica.models.social.ChatMessage import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.ui.helpers.bindView -import com.habitrpg.android.habitica.ui.viewHolders.ChatRecyclerViewHolder +import com.habitrpg.android.habitica.ui.viewHolders.ChatRecyclerMessageViewHolder import io.reactivex.BackpressureStrategy import io.reactivex.Flowable import io.reactivex.subjects.PublishSubject @@ -40,7 +40,7 @@ class ChatRecyclerViewAdapter(data: OrderedRealmCollection?, autoUp return if (viewType == 0) { SystemChatMessageViewHolder(parent.inflate(R.layout.system_chat_message)) } else { - ChatRecyclerViewHolder(parent.inflate(R.layout.tavern_chat_item), uuid, isTavern) + ChatRecyclerMessageViewHolder(parent.inflate(R.layout.tavern_chat_item), uuid, isTavern) } } @@ -49,7 +49,7 @@ class ChatRecyclerViewAdapter(data: OrderedRealmCollection?, autoUp if (data[position].isSystemMessage) { (holder as? SystemChatMessageViewHolder)?.bind(data[position]) } else { - val chatHolder = holder as? ChatRecyclerViewHolder ?: return + val chatHolder = holder as? ChatRecyclerMessageViewHolder ?: return val message = data[position] chatHolder.bind(message, uuid, diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/InboxAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/InboxAdapter.kt index c14967dad..b14b872ee 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/InboxAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/InboxAdapter.kt @@ -8,11 +8,14 @@ import com.habitrpg.android.habitica.extensions.inflate import com.habitrpg.android.habitica.models.social.ChatMessage import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.ui.viewHolders.ChatRecyclerViewHolder +import com.habitrpg.android.habitica.ui.viewHolders.ChatRecyclerIntroViewHolder +import com.habitrpg.android.habitica.ui.viewHolders.ChatRecyclerMessageViewHolder import io.reactivex.BackpressureStrategy import io.reactivex.Flowable import io.reactivex.subjects.PublishSubject +import com.habitrpg.android.habitica.models.members.Member -class InboxAdapter(private var user: User?) : PagedListAdapter(DIFF_CALLBACK) { +class InboxAdapter(private var user: User?, private var replyToUser : Member) : PagedListAdapter(DIFF_CALLBACK) { private var expandedMessageId: String? = null private val likeMessageEvents = PublishSubject.create() @@ -22,24 +25,49 @@ class InboxAdapter(private var user: User?) : PagedListAdapter() private val copyMessageEvents = PublishSubject.create() - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChatRecyclerViewHolder { - return ChatRecyclerViewHolder(parent.inflate(R.layout.tavern_chat_item), user?.id ?: "", false) + override fun getItemViewType(position: Int): Int { + return when (position == super.getItemCount()) { + true -> 1 + false -> 0 + } } - override fun onBindViewHolder(holder: ChatRecyclerViewHolder, position: Int) { - val message = getItem(position) ?: return + override fun getItemCount(): Int { + return super.getItemCount() + 1 + } - holder.bind(message, + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChatRecyclerViewHolder { + return if (viewType == 1) ChatRecyclerIntroViewHolder(parent.inflate(R.layout.tavern_chat_intro_item), replyToUser.id!!) + else ChatRecyclerMessageViewHolder(parent.inflate(R.layout.tavern_chat_item), user?.id ?: "", false) + } + + fun getFirstMessage() : ChatMessage + { + var firstMessage = ChatMessage() + return firstMessage + } + override fun onBindViewHolder(holder: ChatRecyclerViewHolder, position: Int) { + val firstMessage : Boolean = getItemViewType(position) == 1 + if (firstMessage) { + val introHolder = holder as ChatRecyclerIntroViewHolder + introHolder.bind(replyToUser) + introHolder.onOpenProfile = { userLabelClickEvents.onNext(it) } + } + else { + val message : ChatMessage = getItem(position) ?: return + val messageHolder = holder as ChatRecyclerMessageViewHolder + messageHolder.bind(message, user?.id ?: "", user, expandedMessageId == message.id) - holder.onShouldExpand = { expandMessage(message.id, position) } - holder.onLikeMessage = { likeMessageEvents.onNext(it) } - holder.onOpenProfile = { userLabelClickEvents.onNext(it) } - holder.onReply = { replyMessageEvents.onNext(it) } - holder.onCopyMessage = { copyMessageEvents.onNext(it) } - holder.onFlagMessage = { flagMessageEvents.onNext(it) } - holder.onDeleteMessage = { deleteMessageEvents.onNext(it) } + messageHolder.onShouldExpand = { expandMessage(message.id, position) } + messageHolder.onLikeMessage = { likeMessageEvents.onNext(it) } + messageHolder.onOpenProfile = { userLabelClickEvents.onNext(it) } + messageHolder.onReply = { replyMessageEvents.onNext(it) } + messageHolder.onCopyMessage = { copyMessageEvents.onNext(it) } + messageHolder.onFlagMessage = { flagMessageEvents.onNext(it) } + messageHolder.onDeleteMessage = { deleteMessageEvents.onNext(it) } + } } fun getLikeMessageFlowable(): Flowable { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/InboxMessageListFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/InboxMessageListFragment.kt index 165aef00b..d4701b0fd 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/InboxMessageListFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/InboxMessageListFragment.kt @@ -68,21 +68,25 @@ class InboxMessageListFragment : BaseMainFragment(), androidx.swiperefreshlayout val layoutManager = androidx.recyclerview.widget.LinearLayoutManager(this.getActivity()) recyclerView.layoutManager = layoutManager - chatAdapter = InboxAdapter(user) - viewModel?.messages?.observe(this.viewLifecycleOwner, Observer { chatAdapter?.submitList(it) }) - viewModel?.getMemberData()?.observe(this.viewLifecycleOwner, Observer { - activity?.binding?.toolbarTitle?.text = it?.profile?.name - }) - recyclerView.adapter = chatAdapter - recyclerView.itemAnimator = SafeDefaultItemAnimator() - chatAdapter?.let { adapter -> - compositeSubscription.add(adapter.getUserLabelClickFlowable().subscribe(Consumer { - FullProfileActivity.open(it) - }, RxErrorHandler.handleEmptyError())) - compositeSubscription.add(adapter.getDeleteMessageFlowable().subscribe(Consumer { this.showDeleteConfirmationDialog(it) }, RxErrorHandler.handleEmptyError())) - compositeSubscription.add(adapter.getFlagMessageClickFlowable().subscribe(Consumer { this.showFlagConfirmationDialog(it) }, RxErrorHandler.handleEmptyError())) - compositeSubscription.add(adapter.getCopyMessageFlowable().subscribe(Consumer { this.copyMessageToClipboard(it) }, RxErrorHandler.handleEmptyError())) - } + compositeSubscription.add(apiClient.getMember(replyToUserUUID!!).subscribe( Consumer + { member -> + chatAdapter = InboxAdapter(user, member) + viewModel?.messages?.observe(this.viewLifecycleOwner, Observer { chatAdapter?.submitList(it) }) + + viewModel?.getMemberData()?.observe(this.viewLifecycleOwner, Observer { + activity?.binding?.toolbarTitle?.text = it?.profile?.name + }) + recyclerView.adapter = chatAdapter + recyclerView.itemAnimator = SafeDefaultItemAnimator() + chatAdapter?.let { adapter -> + compositeSubscription.add(adapter.getUserLabelClickFlowable().subscribe(Consumer { + FullProfileActivity.open(it) + }, RxErrorHandler.handleEmptyError())) + compositeSubscription.add(adapter.getDeleteMessageFlowable().subscribe(Consumer { this.showDeleteConfirmationDialog(it) }, RxErrorHandler.handleEmptyError())) + compositeSubscription.add(adapter.getFlagMessageClickFlowable().subscribe(Consumer { this.showFlagConfirmationDialog(it) }, RxErrorHandler.handleEmptyError())) + compositeSubscription.add(adapter.getCopyMessageFlowable().subscribe(Consumer { this.copyMessageToClipboard(it) }, RxErrorHandler.handleEmptyError())) + } + })) chatBarView.sendAction = { sendMessage(it) } chatBarView.maxChatLength = configManager.maxChatLength() diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/ChatRecyclerViewHolder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/ChatRecyclerViewHolder.kt index 03e98f73f..7038a6dab 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/ChatRecyclerViewHolder.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/ChatRecyclerViewHolder.kt @@ -28,8 +28,36 @@ import com.habitrpg.android.habitica.ui.views.social.UsernameLabel import io.reactivex.Maybe import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers +import com.habitrpg.android.habitica.models.members.Member -class ChatRecyclerViewHolder(itemView: View, private var userId: String, private val isTavern: Boolean) : RecyclerView.ViewHolder(itemView) { +open class ChatRecyclerViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + +} + +class ChatRecyclerIntroViewHolder(itemView: View, replyToUUID: String) : ChatRecyclerViewHolder(itemView) { + private val avatarView: AvatarView by bindView(R.id.avatar_view) + private val displayNameView: UsernameLabel by bindView(R.id.display_name_textview) + private val sublineTextView: TextView by bindView(R.id.subline_textview) + private val messageText: HabiticaEmojiTextView by bindView(R.id.message_text) + + var onOpenProfile: ((String) -> Unit)? = null + + init { + avatarView.setOnClickListener { onOpenProfile?.invoke(replyToUUID) } + displayNameView.setOnClickListener { onOpenProfile?.invoke(replyToUUID) } + sublineTextView.setOnClickListener { onOpenProfile?.invoke(replyToUUID) } + } + + fun bind(member: Member) { + avatarView.setAvatar(member) + displayNameView.username = member.displayName + displayNameView.tier = member.contributor?.level ?: 0 + sublineTextView.text = "@" + member.username + } +} + + +class ChatRecyclerMessageViewHolder(itemView: View, private var userId: String, private val isTavern: Boolean) : ChatRecyclerViewHolder(itemView) { private val messageWrapper: ViewGroup by bindView(R.id.message_wrapper) private val avatarView: AvatarView by bindView(R.id.avatar_view)