fixed participants after leave_conversation event

This commit is contained in:
Mariotaku Lee 2017-02-26 14:51:32 +08:00
parent f29e2f47c7
commit 09b033fb06
No known key found for this signature in database
GPG Key ID: 15C10F89D7C33535
5 changed files with 126 additions and 101 deletions

View File

@ -13,6 +13,7 @@ import org.mariotaku.twidere.model.message.conversation.DefaultConversationExtra
import org.mariotaku.twidere.model.message.conversation.TwitterOfficialConversationExtras
import org.mariotaku.twidere.util.MediaLoaderWrapper
import org.mariotaku.twidere.util.UserColorNameManager
import java.util.*
fun ParcelableMessageConversation.applyFrom(message: ParcelableMessage, details: AccountDetails) {
account_key = details.key
@ -34,46 +35,6 @@ fun ParcelableMessageConversation.applyFrom(message: ParcelableMessage, details:
val ParcelableMessageConversation.timestamp: Long
get() = if (message_timestamp > 0) message_timestamp else local_timestamp
fun ParcelableMessageConversation.getTitle(context: Context, manager: UserColorNameManager,
nameFirst: Boolean): Pair<String, String?> {
if (conversation_type == ConversationType.ONE_TO_ONE) {
val user = this.user ?: return Pair(context.getString(R.string.title_direct_messages), null)
return Pair(user.name, "@${user.screen_name}")
}
if (conversation_name != null) {
return Pair(conversation_name, null)
}
return Pair(participants.joinToString(separator = ", ") { manager.getDisplayName(it, nameFirst) }, null)
}
fun ParcelableMessageConversation.getSubtitle(context: Context): String? {
if (conversation_type == ConversationType.ONE_TO_ONE) {
val user = this.user ?: return null
return "@${user.screen_name}"
}
val resources = context.resources
return resources.getQuantityString(R.plurals.N_message_participants, participants.size,
participants.size)
}
fun ParcelableMessageConversation.getSummaryText(context: Context, manager: UserColorNameManager,
nameFirst: Boolean): CharSequence? {
return getSummaryText(context, manager, nameFirst, message_type, message_extras, sender_key,
text_unescaped, this)
}
fun ParcelableMessageConversation.displayAvatarTo(mediaLoader: MediaLoaderWrapper, view: ImageView) {
if (conversation_type == ConversationType.ONE_TO_ONE) {
val user = this.user
if (user != null) {
mediaLoader.displayProfileImage(view, user)
} else {
mediaLoader.displayProfileImage(view, null)
}
} else {
mediaLoader.displayGroupConversationAvatar(view, conversation_avatar)
}
}
val ParcelableMessageConversation.user: ParcelableUser?
get() {
@ -121,4 +82,66 @@ var ParcelableMessageConversation.notificationDisabled: Boolean
extras.notificationsDisabled = value
}
}
}
}
fun ParcelableMessageConversation.getTitle(context: Context, manager: UserColorNameManager,
nameFirst: Boolean): Pair<String, String?> {
if (conversation_type == ConversationType.ONE_TO_ONE) {
val user = this.user ?: return Pair(context.getString(R.string.title_direct_messages), null)
return Pair(user.name, "@${user.screen_name}")
}
if (conversation_name != null) {
return Pair(conversation_name, null)
}
return Pair(participants.joinToString(separator = ", ") { manager.getDisplayName(it, nameFirst) }, null)
}
fun ParcelableMessageConversation.getSubtitle(context: Context): String? {
if (conversation_type == ConversationType.ONE_TO_ONE) {
val user = this.user ?: return null
return "@${user.screen_name}"
}
val resources = context.resources
return resources.getQuantityString(R.plurals.N_message_participants, participants.size,
participants.size)
}
fun ParcelableMessageConversation.getSummaryText(context: Context, manager: UserColorNameManager,
nameFirst: Boolean): CharSequence? {
return getSummaryText(context, manager, nameFirst, message_type, message_extras, sender_key,
text_unescaped, this)
}
fun ParcelableMessageConversation.displayAvatarTo(mediaLoader: MediaLoaderWrapper, view: ImageView) {
if (conversation_type == ConversationType.ONE_TO_ONE) {
val user = this.user
if (user != null) {
mediaLoader.displayProfileImage(view, user)
} else {
mediaLoader.displayProfileImage(view, null)
}
} else {
mediaLoader.displayGroupConversationAvatar(view, conversation_avatar)
}
}
fun ParcelableMessageConversation.addParticipants(users: Collection<ParcelableUser>) {
val participants = this.participants
if (participants == null) {
this.participants = arrayOf(user)
} else {
val addingUsers = ArrayList<ParcelableUser>()
users.forEach { user ->
val index = participants.indexOfFirst { it.key == user.key }
if (index >= 0) {
participants[index] = user
} else {
addingUsers += user
}
}
this.participants += addingUsers
}
this.participant_keys = this.participants.map(ParcelableUser::key).toTypedArray()
this.participants.sortBy(ParcelableUser::screen_name)
}

View File

@ -242,7 +242,7 @@ class MessageConversationInfoFragment : BaseFragment(), IToolBarSupportFragment,
private fun performAddParticipant(user: ParcelableUser) {
ProgressDialogFragment.show(childFragmentManager, "add_participant_progress")
val weakThis = WeakReference(this)
val task = AddParticipantsTask(context, accountKey, conversationId, arrayOf(user.key.id))
val task = AddParticipantsTask(context, accountKey, conversationId, listOf(user))
task.callback = callback@ { succeed ->
val f = weakThis.get() ?: return@callback
f.dismissAlertDialogThen("add_participant_progress") {}

View File

@ -24,12 +24,15 @@ import android.content.Context
import org.mariotaku.microblog.library.MicroBlog
import org.mariotaku.microblog.library.MicroBlogException
import org.mariotaku.twidere.annotation.AccountType
import org.mariotaku.twidere.extension.model.addParticipants
import org.mariotaku.twidere.extension.model.isOfficial
import org.mariotaku.twidere.extension.model.newMicroBlogInstance
import org.mariotaku.twidere.model.AccountDetails
import org.mariotaku.twidere.model.ParcelableUser
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.model.util.AccountUtils
import org.mariotaku.twidere.task.ExceptionHandlingAbstractTask
import org.mariotaku.twidere.util.DataStoreUtils
/**
* Created by mariotaku on 2017/2/25.
@ -39,14 +42,21 @@ class AddParticipantsTask(
context: Context,
val accountKey: UserKey,
val conversationId: String,
val participantIds: Array<String>
val participants: Collection<ParcelableUser>
) : ExceptionHandlingAbstractTask<Unit?, Boolean, MicroBlogException, ((Boolean) -> Unit)?>(context) {
override fun onExecute(params: Unit?): Boolean {
val account = AccountUtils.getAccountDetails(AccountManager.get(context), accountKey, true) ?:
throw MicroBlogException("No account")
val conversation = DataStoreUtils.findMessageConversation(context, accountKey, conversationId)
if (conversation != null && conversation.is_temp) {
val addData = GetMessagesTask.DatabaseUpdateData(listOf(conversation), emptyList())
conversation.addParticipants(participants)
GetMessagesTask.storeMessages(context, addData, account, showNotification = false)
return true
}
val microBlog = account.newMicroBlogInstance(context, cls = MicroBlog::class.java)
val addData = requestAddParticipants(microBlog, account)
GetMessagesTask.storeMessages(context, addData, account)
GetMessagesTask.storeMessages(context, addData, account, showNotification = false)
return true
}
@ -59,7 +69,8 @@ class AddParticipantsTask(
when (account.type) {
AccountType.TWITTER -> {
if (account.isOfficial(context)) {
val response = microBlog.addParticipants(conversationId, participantIds);
val ids = participants.map { it.key.id }.toTypedArray()
val response = microBlog.addParticipants(conversationId, ids)
return GetMessagesTask.createDatabaseUpdateData(context, account, response)
}
}

View File

@ -28,15 +28,12 @@ import org.mariotaku.ktextension.useCursor
import org.mariotaku.microblog.library.MicroBlog
import org.mariotaku.microblog.library.MicroBlogException
import org.mariotaku.microblog.library.twitter.model.DMResponse
import org.mariotaku.microblog.library.twitter.model.DirectMessage
import org.mariotaku.microblog.library.twitter.model.Paging
import org.mariotaku.microblog.library.twitter.model.User
import org.mariotaku.sqliteqb.library.Expression
import org.mariotaku.twidere.TwidereConstants.QUERY_PARAM_SHOW_NOTIFICATION
import org.mariotaku.twidere.annotation.AccountType
import org.mariotaku.twidere.extension.model.applyFrom
import org.mariotaku.twidere.extension.model.isOfficial
import org.mariotaku.twidere.extension.model.newMicroBlogInstance
import org.mariotaku.twidere.extension.model.timestamp
import org.mariotaku.twidere.extension.model.*
import org.mariotaku.twidere.model.*
import org.mariotaku.twidere.model.ParcelableMessageConversation.ConversationType
import org.mariotaku.twidere.model.event.GetMessagesTaskEvent
@ -46,7 +43,6 @@ import org.mariotaku.twidere.model.util.AccountUtils
import org.mariotaku.twidere.model.util.AccountUtils.getAccountDetails
import org.mariotaku.twidere.model.util.ParcelableMessageUtils
import org.mariotaku.twidere.model.util.ParcelableUserUtils
import org.mariotaku.twidere.model.util.UserKeyUtils
import org.mariotaku.twidere.provider.TwidereDataStore.Messages
import org.mariotaku.twidere.provider.TwidereDataStore.Messages.Conversations
import org.mariotaku.twidere.task.BaseAbstractTask
@ -163,30 +159,15 @@ class GetMessagesTask(
conversations.addLocalConversations(context, accountKey, conversationIds)
received.forEachIndexed { i, dm ->
val message = ParcelableMessageUtils.fromMessage(accountKey, dm, false,
1.0 - (i.toDouble() / received.size))
insertMessages.add(message)
val conversation = conversations.addConversation(message.conversation_id, details,
message, setOf(dm.sender, dm.recipient)) ?: return@forEachIndexed
conversation.conversation_extras_type = ParcelableMessageConversation.ExtrasType.DEFAULT
if (conversation.conversation_extras == null) {
conversation.conversation_extras = DefaultConversationExtras()
}
addConversationMessage(insertMessages, conversations, details, dm, i, received.size, false)
}
sent.forEachIndexed { i, dm ->
val message = ParcelableMessageUtils.fromMessage(accountKey, dm, true,
1.0 - (i.toDouble() / sent.size))
insertMessages.add(message)
val conversation = conversations.addConversation(message.conversation_id, details,
message, setOf(dm.sender, dm.recipient)) ?: return@forEachIndexed
conversation.conversation_extras_type = ParcelableMessageConversation.ExtrasType.DEFAULT
if (conversation.conversation_extras == null) {
conversation.conversation_extras = DefaultConversationExtras()
}
addConversationMessage(insertMessages, conversations, details, dm, i, sent.size, true)
}
return DatabaseUpdateData(conversations.values, insertMessages)
}
private fun getTwitterOfficialConversation(microBlog: MicroBlog, details: AccountDetails,
conversationId: String, param: RefreshMessagesTaskParam, index: Int): DatabaseUpdateData {
val maxId = param.maxIds?.get(index) ?: return DatabaseUpdateData(emptyList(), emptyList())
@ -235,8 +216,10 @@ class GetMessagesTask(
// Sender is our self, treat as outgoing message
val message = ParcelableMessageUtils.fromMessage(accountKey, dm, dm.senderId == accountKey.id,
1.0 - (i.toDouble() / result.size))
val sender = ParcelableUserUtils.fromUser(dm.sender, accountKey)
val recipient = ParcelableUserUtils.fromUser(dm.recipient, accountKey)
val mc = conversations.addConversation(message.conversation_id, details, message,
setOf(dm.sender, dm.recipient))
setOf(sender, recipient))
mc?.request_cursor = "page:$page"
}
return DatabaseUpdateData(conversations.values, emptyList())
@ -365,7 +348,7 @@ class GetMessagesTask(
val conversations = hashMapOf<String, ParcelableMessageConversation>()
conversations.addLocalConversations(context, account.key, respConversations.keys)
conversations.addLocalConversations(context, accountKey, respConversations.keys)
val messages = ArrayList<ParcelableMessage>()
val messageDeletionsMap = HashMap<String, ArrayList<String>>()
val conversationDeletions = ArrayList<String>()
@ -383,23 +366,27 @@ class GetMessagesTask(
return@mapNotNullTo null
}
else -> {
return@mapNotNullTo ParcelableMessageUtils.fromEntry(account.key, entry, respUsers)
return@mapNotNullTo ParcelableMessageUtils.fromEntry(accountKey, entry, respUsers)
}
}
}
val messagesMap = messages.groupBy(ParcelableMessage::conversation_id)
conversations.addLocalConversations(context, accountKey, messagesMap.keys)
for ((k, v) in respConversations) {
val recentMessage = messagesMap[k]?.maxBy(ParcelableMessage::message_timestamp)
val participants = respUsers.filterKeys { userId ->
v.participants.any { it.userId == userId }
}.values
}.values.map { ParcelableUserUtils.fromUser(it, accountKey) }
val conversationType = when (v.type?.toUpperCase(Locale.US)) {
DMResponse.Conversation.Type.ONE_TO_ONE -> ConversationType.ONE_TO_ONE
DMResponse.Conversation.Type.GROUP_DM -> ConversationType.GROUP
else -> ConversationType.ONE_TO_ONE
}
val conversation = conversations.addConversation(k, account, recentMessage, participants,
conversationType) ?: continue
false, conversationType) ?: continue
if (conversation.id in conversationDeletions) continue
conversation.conversation_name = v.name
conversation.conversation_avatar = v.avatarImageHttps
@ -482,9 +469,10 @@ class GetMessagesTask(
@SuppressLint("Recycle")
internal fun MutableMap<String, ParcelableMessageConversation>.addLocalConversations(context: Context,
accountKey: UserKey, conversationIds: Set<String>) {
val where = Expression.and(Expression.inArgs(Conversations.CONVERSATION_ID, conversationIds.size),
val newIds = conversationIds.filterNot { it in this.keys }
val where = Expression.and(Expression.inArgs(Conversations.CONVERSATION_ID, newIds.size),
Expression.equalsArgs(Conversations.ACCOUNT_KEY)).sql
val whereArgs = conversationIds.toTypedArray() + accountKey.toString()
val whereArgs = newIds.toTypedArray() + accountKey.toString()
return context.contentResolver.query(Conversations.CONTENT_URI, Conversations.COLUMNS,
where, whereArgs, null).useCursor { cur ->
val indices = ParcelableMessageConversationCursorIndices(cur)
@ -507,26 +495,6 @@ class GetMessagesTask(
}
private fun ParcelableMessageConversation.addParticipant(
accountKey: UserKey,
user: User
) {
val userKey = UserKeyUtils.fromUser(user)
val participants = this.participants
if (participants == null) {
this.participants = arrayOf(ParcelableUserUtils.fromUser(user, accountKey))
} else {
val index = participants.indexOfFirst { it.key == userKey }
if (index >= 0) {
participants[index] = ParcelableUserUtils.fromUser(user, accountKey)
} else {
this.participants = participants + ParcelableUserUtils.fromUser(user, accountKey)
}
}
this.participant_keys = this.participants.map(ParcelableUser::key).toTypedArray()
this.participants.sortBy(ParcelableUser::screen_name)
}
private fun Map<String, List<ParcelableMessage>>.findLastReadTimestamp(conversationId: String, lastReadEventId: String?): Long {
val longEventId = lastReadEventId.toLong(-1)
return this[conversationId]?.filter { message ->
@ -536,11 +504,12 @@ class GetMessagesTask(
}?.maxBy(ParcelableMessage::message_timestamp)?.message_timestamp ?: -1
}
internal fun MutableMap<String, ParcelableMessageConversation>.addConversation(
fun MutableMap<String, ParcelableMessageConversation>.addConversation(
conversationId: String,
details: AccountDetails,
message: ParcelableMessage?,
users: Collection<User>,
users: Collection<ParcelableUser>,
addUsers: Boolean = false,
conversationType: String = ConversationType.ONE_TO_ONE
): ParcelableMessageConversation? {
val conversation = this[conversationId] ?: run {
@ -555,12 +524,31 @@ class GetMessagesTask(
if (message != null && message.timestamp > conversation.timestamp) {
conversation.applyFrom(message, details)
}
users.forEach { user ->
conversation.addParticipant(details.key, user)
if (addUsers) {
conversation.addParticipants(users)
} else {
conversation.participants = users.toTypedArray()
conversation.participant_keys = users.map(ParcelableUser::key).toTypedArray()
}
return conversation
}
internal fun addConversationMessage(messages: MutableCollection<ParcelableMessage>,
conversations: MutableMap<String, ParcelableMessageConversation>,
details: AccountDetails, dm: DirectMessage, index: Int, size: Int, outgoing: Boolean) {
val accountKey = details.key
val message = ParcelableMessageUtils.fromMessage(accountKey, dm, outgoing,
1.0 - (index.toDouble() / size))
messages.add(message)
val sender = ParcelableUserUtils.fromUser(dm.sender, accountKey)
val recipient = ParcelableUserUtils.fromUser(dm.recipient, accountKey)
val conversation = conversations.addConversation(message.conversation_id, details,
message, setOf(sender, recipient)) ?: return
conversation.conversation_extras_type = ParcelableMessageConversation.ExtrasType.DEFAULT
if (conversation.conversation_extras == null) {
conversation.conversation_extras = DefaultConversationExtras()
}
}
}
}

View File

@ -35,6 +35,7 @@ import org.mariotaku.twidere.model.ParcelableMessageConversation
import org.mariotaku.twidere.model.ParcelableNewMessage
import org.mariotaku.twidere.model.event.SendMessageTaskEvent
import org.mariotaku.twidere.model.util.ParcelableMessageUtils
import org.mariotaku.twidere.model.util.ParcelableUserUtils
import org.mariotaku.twidere.provider.TwidereDataStore.Messages.Conversations
import org.mariotaku.twidere.task.ExceptionHandlingAbstractTask
import org.mariotaku.twidere.task.twitter.UpdateStatusTask
@ -142,7 +143,9 @@ class SendMessageTask(
val conversations = hashMapOf<String, ParcelableMessageConversation>()
conversations.addLocalConversations(context, accountKey, conversationIds)
val message = ParcelableMessageUtils.fromMessage(accountKey, dm, true)
conversations.addConversation(message.conversation_id, details, message, setOf(dm.sender, dm.recipient))
val sender = ParcelableUserUtils.fromUser(dm.sender, accountKey)
val recipient = ParcelableUserUtils.fromUser(dm.recipient, accountKey)
conversations.addConversation(message.conversation_id, details, message, setOf(sender, recipient), true)
return GetMessagesTask.DatabaseUpdateData(conversations.values, listOf(message))
}