mirror of
https://github.com/sudoxnym/habitica-android.git
synced 2026-07-30 10:40:37 +00:00
Improve chat handling
This commit is contained in:
parent
6e4994052b
commit
b1bc6c5a17
10 changed files with 130 additions and 28 deletions
|
|
@ -60,7 +60,6 @@ class SocialRepositoryImpl(localRepository: SocialLocalRepository, apiClient: Ap
|
|||
chatMessage
|
||||
}
|
||||
.toList()
|
||||
.doOnSuccess { localRepository.saveChatMessages(groupId, it) }
|
||||
}
|
||||
|
||||
override fun getGroupChat(groupId: String): Flowable<out List<ChatMessage>> {
|
||||
|
|
@ -94,7 +93,6 @@ class SocialRepositoryImpl(localRepository: SocialLocalRepository, apiClient: Ap
|
|||
val liked = chatMessage.userLikesMessage(userID)
|
||||
localRepository.likeMessage(chatMessage, userID, !liked)
|
||||
return apiClient.likeMessage(chatMessage.groupId ?: "", chatMessage.id)
|
||||
.doOnError { localRepository.likeMessage(chatMessage, userID, liked) }
|
||||
}
|
||||
|
||||
override fun deleteMessage(chatMessage: ChatMessage): Flowable<Void> {
|
||||
|
|
@ -111,11 +109,6 @@ class SocialRepositoryImpl(localRepository: SocialLocalRepository, apiClient: Ap
|
|||
postChatMessageResult.message.groupId = groupId
|
||||
postChatMessageResult
|
||||
}
|
||||
.doOnNext { postChatMessageResult ->
|
||||
if (postChatMessageResult != null) {
|
||||
localRepository.save(postChatMessageResult.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun postGroupChat(groupId: String, message: String): Flowable<PostChatMessageResult> {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
package com.habitrpg.android.habitica.models.inventory
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import com.habitrpg.android.habitica.models.BaseMainObject
|
||||
import com.habitrpg.android.habitica.models.BaseObject
|
||||
import io.realm.RealmModel
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.PrimaryKey
|
||||
|
||||
open class Equipment : RealmObject(), BaseObject {
|
||||
open class Equipment : RealmObject(), BaseMainObject {
|
||||
|
||||
var value: Double = 0.toDouble()
|
||||
var type: String? = ""
|
||||
|
|
@ -25,4 +27,11 @@ open class Equipment : RealmObject(), BaseObject {
|
|||
var twoHanded = false
|
||||
var mystery = ""
|
||||
var gearSet = ""
|
||||
|
||||
override val realmClass: Class<out RealmModel>
|
||||
get() = Equipment::class.java
|
||||
override val primaryIdentifier: String?
|
||||
get() = key
|
||||
override val primaryIdentifierName: String
|
||||
get() = "key"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,13 +2,15 @@ package com.habitrpg.android.habitica.models.members
|
|||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import com.habitrpg.android.habitica.models.Avatar
|
||||
import com.habitrpg.android.habitica.models.BaseMainObject
|
||||
import com.habitrpg.android.habitica.models.BaseObject
|
||||
import com.habitrpg.android.habitica.models.social.UserParty
|
||||
import com.habitrpg.android.habitica.models.user.*
|
||||
import io.realm.RealmModel
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.PrimaryKey
|
||||
|
||||
open class Member : RealmObject(), Avatar, BaseObject {
|
||||
open class Member : RealmObject(), Avatar, BaseMainObject {
|
||||
|
||||
@PrimaryKey
|
||||
@SerializedName("_id")
|
||||
|
|
@ -58,4 +60,10 @@ open class Member : RealmObject(), Avatar, BaseObject {
|
|||
|
||||
override val sleep: Boolean
|
||||
get() = preferences?.sleep ?: false
|
||||
override val realmClass: Class<out RealmModel>
|
||||
get() = Member::class.java
|
||||
override val primaryIdentifier: String?
|
||||
get() = id
|
||||
override val primaryIdentifierName: String
|
||||
get() = "id"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
package com.habitrpg.android.habitica.models.social
|
||||
|
||||
import com.habitrpg.android.habitica.models.BaseMainObject
|
||||
import com.habitrpg.android.habitica.models.BaseObject
|
||||
import com.habitrpg.android.habitica.models.tasks.TasksOrder
|
||||
import com.habitrpg.android.habitica.models.user.User
|
||||
import io.realm.RealmModel
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.Ignore
|
||||
import io.realm.annotations.PrimaryKey
|
||||
import java.util.*
|
||||
|
||||
open class Challenge : RealmObject(), BaseObject {
|
||||
open class Challenge : RealmObject(), BaseMainObject {
|
||||
|
||||
@PrimaryKey
|
||||
var id: String? = null
|
||||
|
|
@ -58,6 +60,13 @@ open class Challenge : RealmObject(), BaseObject {
|
|||
return map
|
||||
}
|
||||
|
||||
override val realmClass: Class<out RealmModel>
|
||||
get() = Challenge::class.java
|
||||
override val primaryIdentifier: String?
|
||||
get() = id
|
||||
override val primaryIdentifierName: String
|
||||
get() = "id"
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return if (other?.javaClass == Challenge::class.java && this.id != null) {
|
||||
this.id == (other as Challenge).id
|
||||
|
|
|
|||
|
|
@ -1,13 +1,49 @@
|
|||
package com.habitrpg.android.habitica.ui.adapter
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import com.habitrpg.android.habitica.models.BaseMainObject
|
||||
import com.habitrpg.android.habitica.models.BaseObject
|
||||
|
||||
abstract class BaseRecyclerViewAdapter<T, VH : RecyclerView.ViewHolder> : RecyclerView.Adapter<VH>() {
|
||||
|
||||
open class DiffCallback<T: BaseMainObject>(protected val oldList: List<BaseMainObject>, protected val newList: List<BaseMainObject>) :
|
||||
DiffUtil.Callback() {
|
||||
|
||||
override fun getOldListSize(): Int {
|
||||
return oldList.size
|
||||
}
|
||||
|
||||
override fun getNewListSize(): Int {
|
||||
return newList.size
|
||||
}
|
||||
|
||||
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
|
||||
return oldList[oldItemPosition].primaryIdentifier == newList[newItemPosition].primaryIdentifier
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
|
||||
val oldItem = oldList[oldItemPosition]
|
||||
val newItem = newList[newItemPosition]
|
||||
return oldItem == newItem
|
||||
}
|
||||
}
|
||||
|
||||
abstract class BaseRecyclerViewAdapter<T: BaseMainObject, VH: RecyclerView.ViewHolder> : RecyclerView.Adapter<VH>() {
|
||||
|
||||
open fun getDiffCallback(oldList: List<T>, newList: List<T>): DiffCallback<T>? {
|
||||
return null
|
||||
}
|
||||
|
||||
var data: List<T> = emptyList()
|
||||
set(value) {
|
||||
val diffCallback = getDiffCallback(data, value)
|
||||
field = value
|
||||
notifyDataSetChanged()
|
||||
if (diffCallback != null) {
|
||||
val diffResult = DiffUtil.calculateDiff(diffCallback)
|
||||
diffResult.dispatchUpdatesTo(this)
|
||||
} else {
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
|
|
|
|||
|
|
@ -7,14 +7,31 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.databinding.SystemChatMessageBinding
|
||||
import com.habitrpg.android.habitica.extensions.inflate
|
||||
import com.habitrpg.android.habitica.models.BaseMainObject
|
||||
import com.habitrpg.android.habitica.models.BaseObject
|
||||
import com.habitrpg.android.habitica.models.social.ChatMessage
|
||||
import com.habitrpg.android.habitica.models.user.User
|
||||
import com.habitrpg.android.habitica.ui.adapter.BaseRecyclerViewAdapter
|
||||
import com.habitrpg.android.habitica.ui.adapter.DiffCallback
|
||||
import com.habitrpg.android.habitica.ui.viewHolders.ChatRecyclerMessageViewHolder
|
||||
import io.reactivex.rxjava3.core.BackpressureStrategy
|
||||
import io.reactivex.rxjava3.core.Flowable
|
||||
import io.reactivex.rxjava3.subjects.PublishSubject
|
||||
|
||||
class ChatDiffCallback(oldList: List<BaseMainObject>, newList: List<BaseMainObject>) :
|
||||
DiffCallback<ChatMessage>(oldList, newList) {
|
||||
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
|
||||
return oldList[oldItemPosition].primaryIdentifier == newList[newItemPosition].primaryIdentifier
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
|
||||
val oldItem = oldList[oldItemPosition] as ChatMessage
|
||||
val newItem = newList[newItemPosition] as ChatMessage
|
||||
return oldItem.likeCount == newItem.likeCount && oldItem.id == newItem.id
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ChatRecyclerViewAdapter(user: User?, private val isTavern: Boolean) : BaseRecyclerViewAdapter<ChatMessage, RecyclerView.ViewHolder>() {
|
||||
internal var user = user
|
||||
set(value) {
|
||||
|
|
@ -31,6 +48,13 @@ class ChatRecyclerViewAdapter(user: User?, private val isTavern: Boolean) : Base
|
|||
private val replyMessageEvents = PublishSubject.create<String>()
|
||||
private val copyMessageEvents = PublishSubject.create<ChatMessage>()
|
||||
|
||||
override fun getDiffCallback(
|
||||
oldList: List<ChatMessage>,
|
||||
newList: List<ChatMessage>
|
||||
): DiffCallback<ChatMessage> {
|
||||
return ChatDiffCallback(oldList, newList)
|
||||
}
|
||||
|
||||
init {
|
||||
this.uuid = user?.id ?: ""
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ class InboxAdapter(private var user: User?, private var replyToUser: Member) : P
|
|||
private val NORMAL_MESSAGE = 1
|
||||
|
||||
private var expandedMessageId: String? = null
|
||||
private val likeMessageEvents = PublishSubject.create<ChatMessage>()
|
||||
private val userLabelClickEvents = PublishSubject.create<String>()
|
||||
private val deleteMessageEvents = PublishSubject.create<ChatMessage>()
|
||||
private val flagMessageEvents = PublishSubject.create<ChatMessage>()
|
||||
|
|
@ -64,7 +63,6 @@ class InboxAdapter(private var user: User?, private var replyToUser: Member) : P
|
|||
expandedMessageId == message.id
|
||||
)
|
||||
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) }
|
||||
|
|
|
|||
|
|
@ -95,7 +95,12 @@ class ChatFragment : BaseFragment<FragmentChatBinding>() {
|
|||
}
|
||||
})
|
||||
|
||||
viewModel?.getChatMessages()?.subscribe({ this.setChatMessages(it) }, RxErrorHandler.handleEmptyError())?.let { compositeSubscription.add(it) }
|
||||
viewModel?.chatmessages?.observe(
|
||||
viewLifecycleOwner,
|
||||
{
|
||||
setChatMessages(it)
|
||||
}
|
||||
)
|
||||
|
||||
binding?.chatBarView?.onCommunityGuidelinesAccepted = {
|
||||
viewModel?.updateUser("flags.communityGuidelinesAccepted", true)
|
||||
|
|
@ -204,7 +209,7 @@ class ChatFragment : BaseFragment<FragmentChatBinding>() {
|
|||
|
||||
private fun setChatMessages(chatMessages: List<ChatMessage>) {
|
||||
chatAdapter?.data = chatMessages
|
||||
viewModel?.socialRepository?.getUnmanagedCopy(chatMessages)?.let { binding?.chatBarView?.chatMessages = it }
|
||||
binding?.chatBarView?.chatMessages = chatMessages
|
||||
|
||||
viewModel?.gotNewMessages = true
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ class ChatRecyclerIntroViewHolder(itemView: View, replyToUUID: String) : ChatRec
|
|||
}
|
||||
}
|
||||
|
||||
class ChatRecyclerMessageViewHolder(itemView: View, private var userId: String, private val isTavern: Boolean) : ChatRecyclerViewHolder(itemView) {
|
||||
class ChatRecyclerMessageViewHolder(itemView: View, private var userId: String, private val isGroupChat: Boolean) : ChatRecyclerViewHolder(itemView) {
|
||||
val binding = ChatItemBinding.bind(itemView)
|
||||
|
||||
val context: Context = itemView.context
|
||||
|
|
@ -216,7 +216,7 @@ class ChatRecyclerMessageViewHolder(itemView: View, private var userId: String,
|
|||
}
|
||||
|
||||
private fun setLikeProperties() {
|
||||
binding.likeBackgroundLayout.visibility = if (isTavern) View.VISIBLE else View.INVISIBLE
|
||||
binding.likeBackgroundLayout.visibility = if (isGroupChat) View.VISIBLE else View.INVISIBLE
|
||||
@SuppressLint("SetTextI18n")
|
||||
binding.tvLikes.text = "+" + chatMessage?.likeCount
|
||||
|
||||
|
|
|
|||
|
|
@ -54,6 +54,13 @@ open class GroupViewModel(initializeComponent: Boolean) : BaseViewModel(initiali
|
|||
MutableLiveData<Boolean?>()
|
||||
}
|
||||
|
||||
private val _chatMessages: MutableLiveData<List<ChatMessage>> by lazy {
|
||||
MutableLiveData<List<ChatMessage>>(listOf())
|
||||
}
|
||||
val chatmessages: LiveData<List<ChatMessage>> by lazy {
|
||||
_chatMessages
|
||||
}
|
||||
|
||||
protected val groupIDSubject = BehaviorSubject.create<Optional<String>>()
|
||||
val groupIDFlowable: Flowable<Optional<String>> = groupIDSubject.toFlowable(BackpressureStrategy.BUFFER)
|
||||
var gotNewMessages: Boolean = false
|
||||
|
|
@ -143,12 +150,6 @@ open class GroupViewModel(initializeComponent: Boolean) : BaseViewModel(initiali
|
|||
)
|
||||
}
|
||||
|
||||
fun getChatMessages(): Flowable<List<ChatMessage>> {
|
||||
return groupIDFlowable
|
||||
.filterMapEmpty()
|
||||
.flatMap { socialRepository.getGroupChat(it) }
|
||||
}
|
||||
|
||||
fun retrieveGroup(function: (() -> Unit)?) {
|
||||
if (groupID?.isNotEmpty() == true) {
|
||||
disposable.add(
|
||||
|
|
@ -237,17 +238,35 @@ open class GroupViewModel(initializeComponent: Boolean) : BaseViewModel(initiali
|
|||
}
|
||||
|
||||
fun likeMessage(message: ChatMessage) {
|
||||
disposable.add(socialRepository.likeMessage(message).subscribe({ }, RxErrorHandler.handleEmptyError()))
|
||||
val index = _chatMessages.value?.indexOf(message) ?: return
|
||||
disposable.add(socialRepository.likeMessage(message).subscribe(
|
||||
{
|
||||
val list = _chatMessages.value?.toMutableList()
|
||||
list?.set(index, it)
|
||||
_chatMessages.postValue(list)
|
||||
}, RxErrorHandler.handleEmptyError()))
|
||||
}
|
||||
|
||||
fun deleteMessage(chatMessage: ChatMessage) {
|
||||
disposable.add(socialRepository.deleteMessage(chatMessage).subscribe({ }, RxErrorHandler.handleEmptyError()))
|
||||
val oldIndex = _chatMessages.value?.indexOf(chatMessage) ?: return
|
||||
val list = _chatMessages.value?.toMutableList()
|
||||
list?.remove(chatMessage)
|
||||
_chatMessages.postValue(list)
|
||||
disposable.add(socialRepository.deleteMessage(chatMessage).subscribe({
|
||||
}, {
|
||||
list?.add(oldIndex, chatMessage)
|
||||
_chatMessages.postValue(list)
|
||||
RxErrorHandler.reportError(it)
|
||||
}))
|
||||
}
|
||||
|
||||
fun postGroupChat(chatText: String, onComplete: () -> Unit, onError: () -> Unit) {
|
||||
groupIDSubject.value?.value?.let {
|
||||
socialRepository.postGroupChat(it, chatText).subscribe(
|
||||
groupIDSubject.value?.value?.let { groupID ->
|
||||
socialRepository.postGroupChat(groupID, chatText).subscribe(
|
||||
{
|
||||
val list = _chatMessages.value?.toMutableList()
|
||||
list?.add(0, it.message)
|
||||
_chatMessages.postValue(list)
|
||||
onComplete()
|
||||
},
|
||||
{ error ->
|
||||
|
|
@ -270,6 +289,7 @@ open class GroupViewModel(initializeComponent: Boolean) : BaseViewModel(initiali
|
|||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{
|
||||
_chatMessages.postValue(it)
|
||||
onComplete()
|
||||
},
|
||||
RxErrorHandler.handleEmptyError()
|
||||
|
|
|
|||
Loading…
Reference in a new issue