supports participants leave/join event
This commit is contained in:
parent
59daca9025
commit
6fdd829ce0
|
@ -122,6 +122,10 @@ public class DMResponse implements Parcelable {
|
|||
Message joinConversation;
|
||||
@JsonField(name = "message")
|
||||
Message message;
|
||||
@JsonField(name = "participants_leave")
|
||||
Message participantsLeave;
|
||||
@JsonField(name = "participants_join")
|
||||
Message participantsJoin;
|
||||
|
||||
public Message getJoinConversation() {
|
||||
return joinConversation;
|
||||
|
@ -135,10 +139,21 @@ public class DMResponse implements Parcelable {
|
|||
return message;
|
||||
}
|
||||
|
||||
public Message getParticipantsLeave() {
|
||||
return participantsLeave;
|
||||
}
|
||||
|
||||
public Message getParticipantsJoin() {
|
||||
return participantsJoin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Entry{" +
|
||||
"message=" + message +
|
||||
"conversationCreate=" + conversationCreate +
|
||||
", joinConversation=" + joinConversation +
|
||||
", message=" + message +
|
||||
", participantsLeave=" + participantsLeave +
|
||||
'}';
|
||||
}
|
||||
|
||||
|
@ -161,6 +176,9 @@ public class DMResponse implements Parcelable {
|
|||
@JsonField(name = "request_id")
|
||||
String requestId;
|
||||
|
||||
@JsonField(name = "sender_id")
|
||||
String senderId;
|
||||
|
||||
@JsonField(name = "message_data")
|
||||
Data messageData;
|
||||
|
||||
|
@ -187,6 +205,10 @@ public class DMResponse implements Parcelable {
|
|||
return requestId;
|
||||
}
|
||||
|
||||
public String getSenderId() {
|
||||
return senderId;
|
||||
}
|
||||
|
||||
public Data getMessageData() {
|
||||
return messageData;
|
||||
}
|
||||
|
@ -240,9 +262,9 @@ public class DMResponse implements Parcelable {
|
|||
@JsonField(name = "time")
|
||||
long time;
|
||||
@JsonField(name = "sender_id")
|
||||
long senderId;
|
||||
String senderId;
|
||||
@JsonField(name = "recipient_id")
|
||||
long recipientId;
|
||||
String recipientId;
|
||||
@JsonField(name = "text")
|
||||
String text;
|
||||
@JsonField(name = "entities")
|
||||
|
@ -254,11 +276,11 @@ public class DMResponse implements Parcelable {
|
|||
return text;
|
||||
}
|
||||
|
||||
public long getRecipientId() {
|
||||
public String getRecipientId() {
|
||||
return recipientId;
|
||||
}
|
||||
|
||||
public long getSenderId() {
|
||||
public String getSenderId() {
|
||||
return senderId;
|
||||
}
|
||||
|
||||
|
@ -427,6 +449,26 @@ public class DMResponse implements Parcelable {
|
|||
@Type
|
||||
String type;
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public long getSortTimestamp() {
|
||||
return sortTimestamp;
|
||||
}
|
||||
|
||||
public long getSortEventId() {
|
||||
return sortEventId;
|
||||
}
|
||||
|
||||
public boolean isReadOnly() {
|
||||
return readOnly;
|
||||
}
|
||||
|
||||
public Participant[] getParticipants() {
|
||||
return participants;
|
||||
}
|
||||
|
@ -454,7 +496,7 @@ public class DMResponse implements Parcelable {
|
|||
@StringDef({Type.ONE_TO_ONE, Type.GROUP_DM})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface Type {
|
||||
String ONE_TO_ONE = "one_to_one", GROUP_DM = "group_dm";
|
||||
String ONE_TO_ONE = "ONE_TO_ONE", GROUP_DM = "GROUP_DM";
|
||||
}
|
||||
|
||||
@ParcelablePlease
|
||||
|
@ -462,12 +504,18 @@ public class DMResponse implements Parcelable {
|
|||
public static class Participant implements Parcelable {
|
||||
|
||||
@JsonField(name = "user_id")
|
||||
long userId;
|
||||
String userId;
|
||||
@JsonField(name = "join_time")
|
||||
long joinTime;
|
||||
|
||||
public long getUserId() {
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public long getJoinTime() {
|
||||
return joinTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
|
|
|
@ -152,10 +152,12 @@ public class ParcelableMessage {
|
|||
|
||||
|
||||
@StringDef({MessageType.TEXT, MessageType.STICKER, MessageType.CONVERSATION_CREATE,
|
||||
MessageType.JOIN_CONVERSATION})
|
||||
MessageType.JOIN_CONVERSATION, MessageType.PARTICIPANTS_LEAVE})
|
||||
public @interface MessageType {
|
||||
String CONVERSATION_CREATE = "conversation_create";
|
||||
String JOIN_CONVERSATION = "join_conversation";
|
||||
String PARTICIPANTS_LEAVE = "participants_leave";
|
||||
String PARTICIPANTS_JOIN = "participants_join";
|
||||
String TEXT = "text";
|
||||
String STICKER = "sticker";
|
||||
}
|
||||
|
|
|
@ -40,6 +40,10 @@ public abstract class MessageExtras implements Parcelable {
|
|||
switch (messageType) {
|
||||
case MessageType.STICKER:
|
||||
return LoganSquare.parse(json, StickerExtras.class);
|
||||
case MessageType.JOIN_CONVERSATION:
|
||||
case MessageType.PARTICIPANTS_LEAVE:
|
||||
case MessageType.PARTICIPANTS_JOIN:
|
||||
return LoganSquare.parse(json, UserArrayExtras.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.model.message;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.bluelinelabs.logansquare.annotation.JsonField;
|
||||
import com.bluelinelabs.logansquare.annotation.JsonObject;
|
||||
import com.hannesdorfmann.parcelableplease.annotation.ParcelablePlease;
|
||||
|
||||
import org.mariotaku.twidere.model.ParcelableUser;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/2/12.
|
||||
*/
|
||||
|
||||
@ParcelablePlease
|
||||
@JsonObject
|
||||
public class UserArrayExtras extends MessageExtras implements Parcelable {
|
||||
@JsonField(name = "users")
|
||||
ParcelableUser[] users;
|
||||
|
||||
public ParcelableUser[] getUsers() {
|
||||
return users;
|
||||
}
|
||||
|
||||
public void setUsers(final ParcelableUser[] users) {
|
||||
this.users = users;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
UserArrayExtrasParcelablePlease.writeToParcel(this, dest, flags);
|
||||
}
|
||||
|
||||
public static final Creator<UserArrayExtras> CREATOR = new Creator<UserArrayExtras>() {
|
||||
public UserArrayExtras createFromParcel(Parcel source) {
|
||||
UserArrayExtras target = new UserArrayExtras();
|
||||
UserArrayExtrasParcelablePlease.readFromParcel(target, source);
|
||||
return target;
|
||||
}
|
||||
|
||||
public UserArrayExtras[] newArray(int size) {
|
||||
return new UserArrayExtras[size];
|
||||
}
|
||||
};
|
||||
}
|
|
@ -29,14 +29,14 @@ import org.mariotaku.twidere.adapter.iface.IItemCountsAdapter
|
|||
import org.mariotaku.twidere.annotation.PreviewStyle
|
||||
import org.mariotaku.twidere.constant.linkHighlightOptionKey
|
||||
import org.mariotaku.twidere.constant.mediaPreviewStyleKey
|
||||
import org.mariotaku.twidere.constant.nameFirstKey
|
||||
import org.mariotaku.twidere.extension.model.timestamp
|
||||
import org.mariotaku.twidere.model.ItemCounts
|
||||
import org.mariotaku.twidere.model.ParcelableMessage
|
||||
import org.mariotaku.twidere.model.*
|
||||
import org.mariotaku.twidere.model.ParcelableMessage.MessageType
|
||||
import org.mariotaku.twidere.util.TwidereLinkify
|
||||
import org.mariotaku.twidere.view.holder.message.AbsMessageViewHolder
|
||||
import org.mariotaku.twidere.view.holder.message.ConversationCreateMessageViewHolder
|
||||
import org.mariotaku.twidere.view.holder.message.MessageViewHolder
|
||||
import org.mariotaku.twidere.view.holder.message.NoticeSummaryEventViewHolder
|
||||
import org.mariotaku.twidere.view.holder.message.StickerMessageViewHolder
|
||||
import java.util.*
|
||||
|
||||
|
@ -48,13 +48,13 @@ class MessagesConversationAdapter(context: Context) : LoadMoreSupportAdapter<Rec
|
|||
@PreviewStyle
|
||||
val mediaPreviewStyle: Int = preferences[mediaPreviewStyleKey]
|
||||
val linkHighlightingStyle: Int = preferences[linkHighlightOptionKey]
|
||||
val nameFirst: Boolean = preferences[nameFirstKey]
|
||||
val linkify: TwidereLinkify = TwidereLinkify(null)
|
||||
|
||||
var messages: List<ParcelableMessage>? = null
|
||||
set(value) {
|
||||
field = value
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
private set
|
||||
var conversation: ParcelableMessageConversation? = null
|
||||
private set
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
val inflater = LayoutInflater.from(parent.context)
|
||||
|
@ -67,9 +67,10 @@ class MessagesConversationAdapter(context: Context) : LoadMoreSupportAdapter<Rec
|
|||
val view = inflater.inflate(StickerMessageViewHolder.layoutResource, parent, false)
|
||||
return StickerMessageViewHolder(view, this)
|
||||
}
|
||||
ITEM_TYPE_CONVERSATION_CREATE -> {
|
||||
val view = inflater.inflate(ConversationCreateMessageViewHolder.layoutResource, parent, false)
|
||||
return ConversationCreateMessageViewHolder(view, this)
|
||||
ITEM_TYPE_CONVERSATION_CREATE, ITEM_TYPE_JOIN_CONVERSATION,
|
||||
ITEM_TYPE_PARTICIPANTS_LEAVE, ITEM_TYPE_PARTICIPANTS_JOIN -> {
|
||||
val view = inflater.inflate(NoticeSummaryEventViewHolder.layoutResource, parent, false)
|
||||
return NoticeSummaryEventViewHolder(view, this)
|
||||
}
|
||||
}
|
||||
throw UnsupportedOperationException()
|
||||
|
@ -77,7 +78,8 @@ class MessagesConversationAdapter(context: Context) : LoadMoreSupportAdapter<Rec
|
|||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
when (holder.itemViewType) {
|
||||
ITEM_TYPE_TEXT_MESSAGE, ITEM_TYPE_STICKER_MESSAGE, ITEM_TYPE_CONVERSATION_CREATE -> {
|
||||
ITEM_TYPE_TEXT_MESSAGE, ITEM_TYPE_STICKER_MESSAGE, ITEM_TYPE_CONVERSATION_CREATE,
|
||||
ITEM_TYPE_JOIN_CONVERSATION, ITEM_TYPE_PARTICIPANTS_LEAVE, ITEM_TYPE_PARTICIPANTS_JOIN -> {
|
||||
val message = getMessage(position)!!
|
||||
// Display date for oldest item
|
||||
var showDate = true
|
||||
|
@ -99,10 +101,6 @@ class MessagesConversationAdapter(context: Context) : LoadMoreSupportAdapter<Rec
|
|||
return itemCounts.itemCount
|
||||
}
|
||||
|
||||
fun getMessage(position: Int): ParcelableMessage? {
|
||||
return messages?.get(position - itemCounts.getItemStartPosition(0))
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
when (itemCounts.getItemCountIndex(position)) {
|
||||
ITEM_START_MESSAGE -> {
|
||||
|
@ -113,6 +111,15 @@ class MessagesConversationAdapter(context: Context) : LoadMoreSupportAdapter<Rec
|
|||
MessageType.CONVERSATION_CREATE -> {
|
||||
return ITEM_TYPE_CONVERSATION_CREATE
|
||||
}
|
||||
MessageType.JOIN_CONVERSATION -> {
|
||||
return ITEM_TYPE_JOIN_CONVERSATION
|
||||
}
|
||||
MessageType.PARTICIPANTS_LEAVE -> {
|
||||
return ITEM_TYPE_PARTICIPANTS_LEAVE
|
||||
}
|
||||
MessageType.PARTICIPANTS_JOIN -> {
|
||||
return ITEM_TYPE_PARTICIPANTS_JOIN
|
||||
}
|
||||
else -> return ITEM_TYPE_TEXT_MESSAGE
|
||||
}
|
||||
}
|
||||
|
@ -120,12 +127,30 @@ class MessagesConversationAdapter(context: Context) : LoadMoreSupportAdapter<Rec
|
|||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
fun getMessage(position: Int): ParcelableMessage? {
|
||||
return messages?.get(position - itemCounts.getItemStartPosition(0))
|
||||
}
|
||||
|
||||
fun findUser(key: UserKey): ParcelableUser? {
|
||||
return conversation?.participants?.firstOrNull { it.key == key }
|
||||
}
|
||||
|
||||
fun setData(conversation: ParcelableMessageConversation?, messages: List<ParcelableMessage>?) {
|
||||
this.conversation = conversation
|
||||
this.messages = messages
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val ITEM_START_MESSAGE = 0
|
||||
|
||||
const val ITEM_TYPE_TEXT_MESSAGE = 1
|
||||
const val ITEM_TYPE_STICKER_MESSAGE = 2
|
||||
const val ITEM_TYPE_CONVERSATION_CREATE = 3
|
||||
const val ITEM_TYPE_JOIN_CONVERSATION = 4
|
||||
const val ITEM_TYPE_PARTICIPANTS_LEAVE = 5
|
||||
const val ITEM_TYPE_PARTICIPANTS_JOIN = 6
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -4,8 +4,10 @@ import android.content.Context
|
|||
import android.support.v7.widget.RecyclerView
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import org.mariotaku.kpreferences.get
|
||||
import org.mariotaku.twidere.adapter.iface.IItemCountsAdapter
|
||||
import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter
|
||||
import org.mariotaku.twidere.constant.nameFirstKey
|
||||
import org.mariotaku.twidere.model.ItemCounts
|
||||
import org.mariotaku.twidere.model.ParcelableMessageConversation
|
||||
import org.mariotaku.twidere.view.holder.LoadIndicatorViewHolder
|
||||
|
@ -31,6 +33,8 @@ class MessagesEntriesAdapter(context: Context) : LoadMoreSupportAdapter<Recycler
|
|||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
val nameFirst: Boolean = preferences[nameFirstKey]
|
||||
|
||||
var listener: MessageConversationClickListener? = null
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
|
@ -87,4 +91,5 @@ class MessagesEntriesAdapter(context: Context) : LoadMoreSupportAdapter<Recycler
|
|||
const val ITEM_VIEW_TYPE_LOAD_INDICATOR = 2
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -4,12 +4,12 @@ import android.content.Context
|
|||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.model.AccountDetails
|
||||
import org.mariotaku.twidere.model.ParcelableMessage
|
||||
import org.mariotaku.twidere.model.ParcelableMessage.MessageType
|
||||
import org.mariotaku.twidere.model.ParcelableMessageConversation
|
||||
import org.mariotaku.twidere.model.ParcelableMessageConversation.ConversationType
|
||||
import org.mariotaku.twidere.model.ParcelableUser
|
||||
import org.mariotaku.twidere.util.UserColorNameManager
|
||||
|
||||
fun ParcelableMessageConversation.setFrom(message: ParcelableMessage, details: AccountDetails) {
|
||||
fun ParcelableMessageConversation.applyFrom(message: ParcelableMessage, details: AccountDetails) {
|
||||
account_key = details.key
|
||||
account_color = details.color
|
||||
message_type = message.message_type
|
||||
|
@ -39,13 +39,10 @@ fun ParcelableMessageConversation.getConversationName(context: Context): Pair<St
|
|||
}, null)
|
||||
}
|
||||
|
||||
fun ParcelableMessageConversation.getSummaryText(context: Context): String {
|
||||
when (message_type) {
|
||||
MessageType.STICKER -> {
|
||||
return context.getString(R.string.message_summary_type_sticker)
|
||||
}
|
||||
}
|
||||
return text_unescaped
|
||||
fun ParcelableMessageConversation.getSummaryText(context: Context, manager: UserColorNameManager,
|
||||
nameFirst: Boolean): CharSequence? {
|
||||
return getSummaryText(context, manager, nameFirst, message_type, extras, sender_key,
|
||||
text_unescaped, this)
|
||||
}
|
||||
|
||||
val ParcelableMessageConversation.user: ParcelableUser?
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
package org.mariotaku.twidere.extension.model
|
||||
|
||||
import android.content.Context
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.model.ParcelableMessage
|
||||
import org.mariotaku.twidere.model.ParcelableMessage.MessageType
|
||||
import org.mariotaku.twidere.model.ParcelableMessageConversation
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
import org.mariotaku.twidere.model.message.MessageExtras
|
||||
import org.mariotaku.twidere.model.message.UserArrayExtras
|
||||
import org.mariotaku.twidere.util.UserColorNameManager
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/2/9.
|
||||
|
@ -8,3 +16,53 @@ import org.mariotaku.twidere.model.ParcelableMessage
|
|||
|
||||
val ParcelableMessage.timestamp: Long
|
||||
get() = if (message_timestamp > 0) message_timestamp else local_timestamp
|
||||
|
||||
fun ParcelableMessage.getSummaryText(context: Context, manager: UserColorNameManager,
|
||||
conversation: ParcelableMessageConversation?, nameFirst: Boolean): CharSequence? {
|
||||
return getSummaryText(context, manager, nameFirst, message_type, extras, sender_key,
|
||||
text_unescaped, conversation)
|
||||
}
|
||||
|
||||
internal fun getSummaryText(context: Context, manager: UserColorNameManager, nameFirst: Boolean,
|
||||
messageType: String?, extras: MessageExtras?, senderKey: UserKey?, text: String?,
|
||||
conversation: ParcelableMessageConversation?): CharSequence? {
|
||||
when (messageType) {
|
||||
MessageType.STICKER -> {
|
||||
return context.getString(R.string.message_summary_type_sticker)
|
||||
}
|
||||
MessageType.JOIN_CONVERSATION -> {
|
||||
return context.getString(R.string.message_join_conversation)
|
||||
}
|
||||
MessageType.CONVERSATION_CREATE -> {
|
||||
return context.getString(R.string.message_conversation_created)
|
||||
}
|
||||
MessageType.PARTICIPANTS_JOIN -> {
|
||||
val users = (extras as UserArrayExtras).users
|
||||
val sender = conversation?.participants?.firstOrNull { senderKey == it.key }
|
||||
val res = context.resources
|
||||
val joinName = if (users.size == 1) {
|
||||
manager.getDisplayName(users[0], nameFirst)
|
||||
} else {
|
||||
res.getQuantityString(R.plurals.N_users, users.size, users.size)
|
||||
}
|
||||
if (sender != null) {
|
||||
return res.getString(R.string.message_format_participants_join_added,
|
||||
manager.getDisplayName(sender, nameFirst), joinName)
|
||||
} else {
|
||||
return res.getString(R.string.message_format_participants_join, joinName)
|
||||
}
|
||||
}
|
||||
MessageType.PARTICIPANTS_LEAVE -> {
|
||||
val users = (extras as UserArrayExtras).users
|
||||
val res = context.resources
|
||||
if (users.size == 1) {
|
||||
val displayName = manager.getDisplayName(users[0], nameFirst)
|
||||
return res.getString(R.string.message_format_participants_leave, displayName)
|
||||
} else {
|
||||
val usersName = res.getQuantityString(R.plurals.N_users, users.size, users.size)
|
||||
return res.getString(R.string.message_format_participants_leave, usersName)
|
||||
}
|
||||
}
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.mariotaku.twidere.fragment
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.LoaderManager
|
||||
import android.support.v4.content.Loader
|
||||
|
@ -17,9 +18,12 @@ import org.mariotaku.twidere.constant.IntentConstants.EXTRA_ACCOUNT_KEY
|
|||
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_CONVERSATION_ID
|
||||
import org.mariotaku.twidere.loader.ObjectCursorLoader
|
||||
import org.mariotaku.twidere.model.ParcelableMessage
|
||||
import org.mariotaku.twidere.model.ParcelableMessageConversation
|
||||
import org.mariotaku.twidere.model.ParcelableMessageCursorIndices
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Messages
|
||||
import org.mariotaku.twidere.util.DataStoreUtils
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
class MessagesConversationFragment : BaseFragment(), LoaderManager.LoaderCallbacks<List<ParcelableMessage>?> {
|
||||
private lateinit var adapter: MessagesConversationAdapter
|
||||
|
@ -40,22 +44,40 @@ class MessagesConversationFragment : BaseFragment(), LoaderManager.LoaderCallbac
|
|||
}
|
||||
|
||||
override fun onCreateLoader(id: Int, args: Bundle?): Loader<List<ParcelableMessage>?> {
|
||||
val loader = ObjectCursorLoader(context, ParcelableMessageCursorIndices::class.java)
|
||||
loader.uri = Messages.CONTENT_URI
|
||||
loader.projection = Messages.COLUMNS
|
||||
loader.selection = Expression.and(Expression.equalsArgs(Messages.ACCOUNT_KEY),
|
||||
Expression.equalsArgs(Messages.CONVERSATION_ID)).sql
|
||||
loader.selectionArgs = arrayOf(accountKey.toString(), conversationId)
|
||||
loader.sortOrder = OrderBy(Messages.SORT_ID, false).sql
|
||||
return loader
|
||||
return ConversationLoader(context, accountKey, conversationId)
|
||||
}
|
||||
|
||||
override fun onLoaderReset(loader: Loader<List<ParcelableMessage>?>) {
|
||||
adapter.messages = null
|
||||
adapter.setData(null, null)
|
||||
}
|
||||
|
||||
override fun onLoadFinished(loader: Loader<List<ParcelableMessage>?>, data: List<ParcelableMessage>?) {
|
||||
adapter.messages = data
|
||||
val conversation = (loader as? ConversationLoader)?.conversation
|
||||
adapter.setData(conversation, data)
|
||||
}
|
||||
|
||||
internal class ConversationLoader(
|
||||
context: Context,
|
||||
val accountKey: UserKey,
|
||||
val conversationId: String
|
||||
) : ObjectCursorLoader<ParcelableMessage>(context, ParcelableMessageCursorIndices::class.java) {
|
||||
|
||||
private val atomicConversation = AtomicReference<ParcelableMessageConversation?>()
|
||||
val conversation: ParcelableMessageConversation? get() = atomicConversation.get()
|
||||
|
||||
init {
|
||||
uri = Messages.CONTENT_URI
|
||||
projection = Messages.COLUMNS
|
||||
selection = Expression.and(Expression.equalsArgs(Messages.ACCOUNT_KEY),
|
||||
Expression.equalsArgs(Messages.CONVERSATION_ID)).sql
|
||||
selectionArgs = arrayOf(accountKey.toString(), conversationId)
|
||||
sortOrder = OrderBy(Messages.SORT_ID, false).sql
|
||||
}
|
||||
|
||||
override fun onLoadInBackground(): MutableList<ParcelableMessage> {
|
||||
atomicConversation.set(DataStoreUtils.findMessageConversation(context, accountKey, conversationId))
|
||||
return super.onLoadInBackground()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,12 +3,14 @@ package org.mariotaku.twidere.model.util
|
|||
import android.support.annotation.FloatRange
|
||||
import org.mariotaku.microblog.library.twitter.model.DMResponse
|
||||
import org.mariotaku.microblog.library.twitter.model.DirectMessage
|
||||
import org.mariotaku.microblog.library.twitter.model.User
|
||||
import org.mariotaku.twidere.model.ParcelableMedia
|
||||
import org.mariotaku.twidere.model.ParcelableMessage
|
||||
import org.mariotaku.twidere.model.ParcelableMessage.MessageType
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
import org.mariotaku.twidere.model.message.MessageExtras
|
||||
import org.mariotaku.twidere.model.message.StickerExtras
|
||||
import org.mariotaku.twidere.model.message.UserArrayExtras
|
||||
import org.mariotaku.twidere.util.InternalTwitterContentUtils
|
||||
|
||||
/**
|
||||
|
@ -18,7 +20,8 @@ object ParcelableMessageUtils {
|
|||
|
||||
fun fromMessage(accountKey: UserKey, message: DirectMessage, outgoing: Boolean,
|
||||
@FloatRange(from = 0.0, to = 1.0) sortIdAdj: Double = 0.0): ParcelableMessage {
|
||||
val result = message(accountKey, message, sortIdAdj)
|
||||
val result = ParcelableMessage()
|
||||
result.applyMessage(accountKey, message, sortIdAdj)
|
||||
result.is_outgoing = outgoing
|
||||
if (outgoing) {
|
||||
result.conversation_id = outgoingConversationId(message.senderId, message.recipientId)
|
||||
|
@ -28,7 +31,7 @@ object ParcelableMessageUtils {
|
|||
return result
|
||||
}
|
||||
|
||||
fun fromEntry(accountKey: UserKey, entry: DMResponse.Entry): ParcelableMessage? {
|
||||
fun fromEntry(accountKey: UserKey, entry: DMResponse.Entry, users: Map<String, User>): ParcelableMessage? {
|
||||
when {
|
||||
entry.message != null -> {
|
||||
return ParcelableMessage().apply { applyMessage(accountKey, entry.message) }
|
||||
|
@ -36,6 +39,21 @@ object ParcelableMessageUtils {
|
|||
entry.conversationCreate != null -> {
|
||||
return ParcelableMessage().apply { applyConversationCreate(accountKey, entry.conversationCreate) }
|
||||
}
|
||||
entry.joinConversation != null -> {
|
||||
return ParcelableMessage().apply {
|
||||
applyUsersEvent(accountKey, entry.joinConversation, users, MessageType.JOIN_CONVERSATION)
|
||||
}
|
||||
}
|
||||
entry.participantsLeave != null -> {
|
||||
return ParcelableMessage().apply {
|
||||
applyUsersEvent(accountKey, entry.participantsLeave, users, MessageType.PARTICIPANTS_LEAVE)
|
||||
}
|
||||
}
|
||||
entry.participantsJoin != null -> {
|
||||
return ParcelableMessage().apply {
|
||||
applyUsersEvent(accountKey, entry.participantsJoin, users, MessageType.PARTICIPANTS_JOIN)
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
@ -52,11 +70,6 @@ object ParcelableMessageUtils {
|
|||
this.commonEntry(accountKey, message)
|
||||
|
||||
val data = message.messageData
|
||||
|
||||
this.sender_key = UserKey(data.senderId.toString(), accountKey.host)
|
||||
this.recipient_key = UserKey(data.recipientId.toString(), accountKey.host)
|
||||
this.is_outgoing = this.sender_key == accountKey
|
||||
|
||||
val (type, extras, media) = typeAndExtras(data)
|
||||
val (text, spans) = InternalTwitterContentUtils.formatDirectMessageText(data)
|
||||
this.message_type = type
|
||||
|
@ -72,37 +85,59 @@ object ParcelableMessageUtils {
|
|||
this.is_outgoing = false
|
||||
}
|
||||
|
||||
private fun ParcelableMessage.applyUsersEvent(accountKey: UserKey,
|
||||
message: DMResponse.Entry.Message, users: Map<String, User>, @MessageType type: String) {
|
||||
this.commonEntry(accountKey, message)
|
||||
this.message_type = type
|
||||
this.extras = UserArrayExtras().apply {
|
||||
this.users = message.participants.mapNotNull {
|
||||
val user = users[it.userId] ?: return@mapNotNull null
|
||||
ParcelableUserUtils.fromUser(user, accountKey)
|
||||
}.toTypedArray()
|
||||
}
|
||||
this.is_outgoing = false
|
||||
}
|
||||
|
||||
private fun ParcelableMessage.commonEntry(accountKey: UserKey, message: DMResponse.Entry.Message) {
|
||||
val data = message.messageData
|
||||
this.sender_key = run {
|
||||
val senderId = data?.senderId ?: message.senderId ?: return@run null
|
||||
return@run UserKey(senderId, accountKey.host)
|
||||
}
|
||||
this.recipient_key = run {
|
||||
val recipientId = data?.recipientId ?: return@run null
|
||||
return@run UserKey(recipientId, accountKey.host)
|
||||
}
|
||||
this.account_key = accountKey
|
||||
this.id = message.id.toString()
|
||||
this.conversation_id = message.conversationId
|
||||
this.message_timestamp = message.time
|
||||
this.local_timestamp = this.message_timestamp
|
||||
this.sort_id = this.message_timestamp
|
||||
|
||||
this.is_outgoing = this.sender_key == accountKey
|
||||
}
|
||||
|
||||
private fun message(
|
||||
private fun ParcelableMessage.applyMessage(
|
||||
accountKey: UserKey,
|
||||
message: DirectMessage,
|
||||
@FloatRange(from = 0.0, to = 1.0) sortIdAdj: Double = 0.0
|
||||
): ParcelableMessage {
|
||||
val result = ParcelableMessage()
|
||||
result.account_key = accountKey
|
||||
result.id = message.id
|
||||
result.sender_key = UserKeyUtils.fromUser(message.sender)
|
||||
result.recipient_key = UserKeyUtils.fromUser(message.recipient)
|
||||
result.message_timestamp = message.createdAt.time
|
||||
result.local_timestamp = result.message_timestamp
|
||||
result.sort_id = result.message_timestamp + (499 * sortIdAdj).toLong()
|
||||
) {
|
||||
this.account_key = accountKey
|
||||
this.id = message.id
|
||||
this.sender_key = UserKeyUtils.fromUser(message.sender)
|
||||
this.recipient_key = UserKeyUtils.fromUser(message.recipient)
|
||||
this.message_timestamp = message.createdAt.time
|
||||
this.local_timestamp = this.message_timestamp
|
||||
this.sort_id = this.message_timestamp + (499 * sortIdAdj).toLong()
|
||||
|
||||
val (type, extras) = typeAndExtras(message)
|
||||
val (text, spans) = InternalTwitterContentUtils.formatDirectMessageText(message)
|
||||
result.message_type = type
|
||||
result.extras = extras
|
||||
result.text_unescaped = text
|
||||
result.spans = spans
|
||||
result.media = ParcelableMediaUtils.fromEntities(message)
|
||||
return result
|
||||
this.message_type = type
|
||||
this.extras = extras
|
||||
this.text_unescaped = text
|
||||
this.spans = spans
|
||||
this.media = ParcelableMediaUtils.fromEntities(message)
|
||||
}
|
||||
|
||||
private fun typeAndExtras(message: DirectMessage): Pair<String, MessageExtras?> {
|
||||
|
|
|
@ -7,13 +7,14 @@ import org.mariotaku.ktextension.toInt
|
|||
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.Paging
|
||||
import org.mariotaku.microblog.library.twitter.model.User
|
||||
import org.mariotaku.sqliteqb.library.Expression
|
||||
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.setFrom
|
||||
import org.mariotaku.twidere.extension.model.timestamp
|
||||
import org.mariotaku.twidere.model.*
|
||||
import org.mariotaku.twidere.model.ParcelableMessageConversation.ConversationType
|
||||
|
@ -27,6 +28,7 @@ import org.mariotaku.twidere.provider.TwidereDataStore.Messages
|
|||
import org.mariotaku.twidere.provider.TwidereDataStore.Messages.Conversations
|
||||
import org.mariotaku.twidere.util.DataStoreUtils
|
||||
import org.mariotaku.twidere.util.content.ContentResolverUtils
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/2/8.
|
||||
|
@ -86,14 +88,21 @@ class GetMessagesTask(
|
|||
|
||||
val conversationIds = inbox.conversations.keys
|
||||
conversations.addLocalConversations(accountKey, conversationIds)
|
||||
val messages = inbox.entries.mapNotNull { ParcelableMessageUtils.fromEntry(accountKey, it) }
|
||||
val messages = inbox.entries.mapNotNull {
|
||||
ParcelableMessageUtils.fromEntry(accountKey, it, inbox.users)
|
||||
}
|
||||
val messagesMap = messages.groupBy(ParcelableMessage::conversation_id)
|
||||
for ((k, v) in inbox.conversations) {
|
||||
val message = messagesMap[k]?.maxBy(ParcelableMessage::message_timestamp) ?: continue
|
||||
val participants = inbox.users.filterKeys { userId ->
|
||||
v.participants.any { it.userId.toString() == userId }
|
||||
v.participants.any { it.userId == userId }
|
||||
}.values
|
||||
conversations.addConversation(k, details, message, participants)
|
||||
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
|
||||
}
|
||||
conversations.addConversation(k, details, message, participants, conversationType)
|
||||
}
|
||||
return GetMessagesData(conversations.values, messages)
|
||||
}
|
||||
|
@ -256,22 +265,19 @@ class GetMessagesTask(
|
|||
conversationId: String,
|
||||
details: AccountDetails,
|
||||
message: ParcelableMessage,
|
||||
users: Collection<User>
|
||||
users: Collection<User>,
|
||||
conversationType: String = ConversationType.ONE_TO_ONE
|
||||
): ParcelableMessageConversation {
|
||||
val conversation = this[conversationId] ?: run {
|
||||
val obj = ParcelableMessageConversation()
|
||||
obj.id = conversationId
|
||||
if (users.size == 2) {
|
||||
obj.conversation_type = ConversationType.ONE_TO_ONE
|
||||
} else {
|
||||
obj.conversation_type = ConversationType.GROUP
|
||||
}
|
||||
obj.setFrom(message, details)
|
||||
obj.conversation_type = conversationType
|
||||
obj.applyFrom(message, details)
|
||||
this[conversationId] = obj
|
||||
return@run obj
|
||||
}
|
||||
if (message.timestamp > conversation.timestamp) {
|
||||
conversation.setFrom(message, details)
|
||||
conversation.applyFrom(message, details)
|
||||
}
|
||||
users.forEach { user ->
|
||||
conversation.addParticipant(details.key, user)
|
||||
|
|
|
@ -54,6 +54,7 @@ import org.mariotaku.twidere.model.util.AccountUtils
|
|||
import org.mariotaku.twidere.model.util.ParcelableStatusUtils
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.*
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Messages.Conversations
|
||||
import org.mariotaku.twidere.util.content.ContentResolverUtils
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
|
@ -65,7 +66,7 @@ object DataStoreUtils {
|
|||
|
||||
val STATUSES_URIS = arrayOf(Statuses.CONTENT_URI, CachedStatuses.CONTENT_URI)
|
||||
val CACHE_URIS = arrayOf(CachedUsers.CONTENT_URI, CachedStatuses.CONTENT_URI, CachedHashtags.CONTENT_URI, CachedTrends.Local.CONTENT_URI)
|
||||
val MESSAGES_URIS = arrayOf(Messages.CONTENT_URI, Messages.Conversations.CONTENT_URI)
|
||||
val MESSAGES_URIS = arrayOf(Messages.CONTENT_URI, Conversations.CONTENT_URI)
|
||||
val ACTIVITIES_URIS = arrayOf(Activities.AboutMe.CONTENT_URI)
|
||||
|
||||
private val CONTENT_PROVIDER_URI_MATCHER = UriMatcher(UriMatcher.NO_MATCH)
|
||||
|
@ -93,7 +94,7 @@ object DataStoreUtils {
|
|||
TABLE_ID_FILTERS_SUBSCRIPTIONS)
|
||||
CONTENT_PROVIDER_URI_MATCHER.addURI(TwidereDataStore.AUTHORITY, Messages.CONTENT_PATH,
|
||||
TABLE_ID_MESSAGES)
|
||||
CONTENT_PROVIDER_URI_MATCHER.addURI(TwidereDataStore.AUTHORITY, Messages.Conversations.CONTENT_PATH,
|
||||
CONTENT_PROVIDER_URI_MATCHER.addURI(TwidereDataStore.AUTHORITY, Conversations.CONTENT_PATH,
|
||||
TABLE_ID_MESSAGES_CONVERSATIONS)
|
||||
CONTENT_PROVIDER_URI_MATCHER.addURI(TwidereDataStore.AUTHORITY, CachedTrends.Local.CONTENT_PATH,
|
||||
TABLE_ID_TRENDS_LOCAL)
|
||||
|
@ -403,7 +404,7 @@ object DataStoreUtils {
|
|||
TABLE_ID_FILTERED_LINKS -> return Filters.Links.TABLE_NAME
|
||||
TABLE_ID_FILTERS_SUBSCRIPTIONS -> return Filters.Subscriptions.TABLE_NAME
|
||||
TABLE_ID_MESSAGES -> return Messages.TABLE_NAME
|
||||
TABLE_ID_MESSAGES_CONVERSATIONS -> return Messages.Conversations.TABLE_NAME
|
||||
TABLE_ID_MESSAGES_CONVERSATIONS -> return Conversations.TABLE_NAME
|
||||
TABLE_ID_TRENDS_LOCAL -> return CachedTrends.Local.TABLE_NAME
|
||||
TABLE_ID_TABS -> return Tabs.TABLE_NAME
|
||||
TABLE_ID_CACHED_STATUSES -> return CachedStatuses.TABLE_NAME
|
||||
|
@ -853,8 +854,6 @@ object DataStoreUtils {
|
|||
if (cur.count > 0 && cur.moveToFirst()) {
|
||||
status = ParcelableStatusCursorIndices.fromCursor(cur)
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
// Ignore
|
||||
} finally {
|
||||
cur.close()
|
||||
}
|
||||
|
@ -876,12 +875,25 @@ object DataStoreUtils {
|
|||
val resolver = context.contentResolver
|
||||
val status = ParcelableStatusUtils.fromStatus(result, accountKey, false)
|
||||
resolver.delete(CachedStatuses.CONTENT_URI, where, whereArgs)
|
||||
try {
|
||||
resolver.insert(CachedStatuses.CONTENT_URI, ParcelableStatusValuesCreator.create(status))
|
||||
} catch (e: IOException) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
return status
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
fun findMessageConversation(context: Context, accountKey: UserKey, conversationId: String): ParcelableMessageConversation? {
|
||||
val resolver = context.contentResolver
|
||||
val where = Expression.and(Expression.equalsArgs(Conversations.ACCOUNT_KEY),
|
||||
Expression.equalsArgs(Conversations.CONVERSATION_ID)).sql
|
||||
val whereArgs = arrayOf(accountKey.toString(), conversationId)
|
||||
val cur = resolver.query(Conversations.CONTENT_URI, Conversations.COLUMNS, where, whereArgs, null) ?: return null
|
||||
try {
|
||||
if (cur.count > 0 && cur.moveToFirst()) {
|
||||
return ParcelableMessageConversationCursorIndices.fromCursor(cur)
|
||||
}
|
||||
} finally {
|
||||
cur.close()
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -59,7 +59,8 @@ class MessageEntryViewHolder(itemView: View, val adapter: MessagesEntriesAdapter
|
|||
this.name.name = name
|
||||
this.name.screenName = secondaryName
|
||||
this.name.updateText(adapter.bidiFormatter)
|
||||
this.text.text = conversation.getSummaryText(itemView.context)
|
||||
this.text.text = conversation.getSummaryText(itemView.context, adapter.userColorNameManager,
|
||||
adapter.nameFirst)
|
||||
if (conversation.is_outgoing) {
|
||||
stateIndicator.visibility = View.VISIBLE
|
||||
stateIndicator.setImageResource(R.drawable.ic_activity_action_reply)
|
||||
|
|
|
@ -23,10 +23,11 @@ import android.view.View
|
|||
import kotlinx.android.synthetic.main.list_item_message_conversation_notice.view.*
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.adapter.MessagesConversationAdapter
|
||||
import org.mariotaku.twidere.extension.model.getSummaryText
|
||||
import org.mariotaku.twidere.model.ParcelableMessage
|
||||
import org.mariotaku.twidere.view.FixedTextView
|
||||
|
||||
class ConversationCreateMessageViewHolder(itemView: View, adapter: MessagesConversationAdapter) : AbsMessageViewHolder(itemView, adapter) {
|
||||
class NoticeSummaryEventViewHolder(itemView: View, adapter: MessagesConversationAdapter) : AbsMessageViewHolder(itemView, adapter) {
|
||||
override val messageContent: View = itemView
|
||||
override val date: FixedTextView by lazy { itemView.date }
|
||||
|
||||
|
@ -34,7 +35,8 @@ class ConversationCreateMessageViewHolder(itemView: View, adapter: MessagesConve
|
|||
|
||||
override fun display(message: ParcelableMessage, showDate: Boolean) {
|
||||
super.display(message, showDate)
|
||||
text.setText(R.string.message_conversation_created)
|
||||
text.text = message.getSummaryText(adapter.context, adapter.userColorNameManager,
|
||||
adapter.conversation, adapter.nameFirst)
|
||||
}
|
||||
|
||||
override fun setMessageContentGravity(view: View, outgoing: Boolean) {
|
||||
|
@ -44,5 +46,4 @@ class ConversationCreateMessageViewHolder(itemView: View, adapter: MessagesConve
|
|||
companion object {
|
||||
const val layoutResource = R.layout.list_item_message_conversation_notice
|
||||
}
|
||||
|
||||
}
|
|
@ -40,5 +40,6 @@
|
|||
android:id="@+id/text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="@dimen/element_spacing_normal"
|
||||
tools:text="Notice"/>
|
||||
</LinearLayout>
|
|
@ -669,6 +669,16 @@
|
|||
<string name="message_direct_message_deleted">Direct message deleted.</string>
|
||||
<string name="message_direct_message_sent">Direct message sent.</string>
|
||||
<string name="message_error_invalid_account">Some account data are corrupted, Twidere will remove those accounts to prevent crash.</string>
|
||||
<string name="message_format_participants_join">
|
||||
<xliff:g example="User" id="name">%1$s</xliff:g> joined</string>
|
||||
<string name="message_format_participants_join_added">
|
||||
<xliff:g example="Sender"
|
||||
id="sender">%1$s</xliff:g> added <xliff:g
|
||||
example="Recipient" id="recipient">%2$s</xliff:g>
|
||||
</string>
|
||||
<string name="message_format_participants_leave">
|
||||
<xliff:g example="User" id="name">%1$s</xliff:g> left</string>
|
||||
<string name="message_join_conversation">Joined conversation.</string>
|
||||
<string name="message_permission_request_compose_location">Twidere needs location permission for adding location to tweets.</string>
|
||||
<string name="message_permission_request_save_media">Twidere needs storage permission for saving media.</string>
|
||||
<string name="message_permission_request_share_media">Twidere needs storage permission for sharing media to some apps.</string>
|
||||
|
|
Loading…
Reference in New Issue