fixed conversation display
This commit is contained in:
parent
6284e575e9
commit
f33ecab166
|
@ -116,9 +116,31 @@ public class DMResponse implements Parcelable {
|
|||
@JsonObject
|
||||
public static class Entry implements Parcelable {
|
||||
|
||||
@JsonField(name = "conversation_create")
|
||||
Message conversationCreate;
|
||||
@JsonField(name = "join_conversation")
|
||||
Message joinConversation;
|
||||
@JsonField(name = "message")
|
||||
Message message;
|
||||
|
||||
public Message getJoinConversation() {
|
||||
return joinConversation;
|
||||
}
|
||||
|
||||
public Message getConversationCreate() {
|
||||
return conversationCreate;
|
||||
}
|
||||
|
||||
public Message getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Entry{" +
|
||||
"message=" + message +
|
||||
'}';
|
||||
}
|
||||
|
||||
@ParcelablePlease
|
||||
@JsonObject
|
||||
|
@ -130,9 +152,25 @@ public class DMResponse implements Parcelable {
|
|||
@JsonField(name = "time")
|
||||
long time;
|
||||
|
||||
@JsonField(name = "affects_sort")
|
||||
boolean affectsSort;
|
||||
|
||||
@JsonField(name = "conversation_id")
|
||||
String conversationId;
|
||||
|
||||
@JsonField(name = "request_id")
|
||||
String requestId;
|
||||
|
||||
@JsonField(name = "message_data")
|
||||
Data messageData;
|
||||
|
||||
@JsonField(name = "participants")
|
||||
Conversation.Participant[] participants;
|
||||
|
||||
public boolean isAffectsSort() {
|
||||
return affectsSort;
|
||||
}
|
||||
|
||||
public String getConversationId() {
|
||||
return conversationId;
|
||||
}
|
||||
|
@ -145,8 +183,56 @@ public class DMResponse implements Parcelable {
|
|||
return time;
|
||||
}
|
||||
|
||||
public String getRequestId() {
|
||||
return requestId;
|
||||
}
|
||||
|
||||
public Data getMessageData() {
|
||||
return messageData;
|
||||
}
|
||||
|
||||
public Conversation.Participant[] getParticipants() {
|
||||
return participants;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Message{" +
|
||||
"affectsSort=" + affectsSort +
|
||||
", id=" + id +
|
||||
", time=" + time +
|
||||
", conversationId='" + conversationId + '\'' +
|
||||
", messageData=" + messageData +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
DMResponse$Entry$MessageParcelablePlease.writeToParcel(this, dest, flags);
|
||||
}
|
||||
|
||||
public static final Creator<Message> CREATOR = new Creator<Message>() {
|
||||
@Override
|
||||
public Message createFromParcel(Parcel source) {
|
||||
Message target = new Message();
|
||||
DMResponse$Entry$MessageParcelablePlease.readFromParcel(target, source);
|
||||
return target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message[] newArray(int size) {
|
||||
return new Message[size];
|
||||
}
|
||||
};
|
||||
|
||||
@ParcelablePlease
|
||||
@JsonObject
|
||||
public static class Data implements EntitySupport {
|
||||
public static class Data implements EntitySupport, Parcelable {
|
||||
|
||||
@JsonField(name = "id")
|
||||
long id;
|
||||
|
@ -216,40 +302,68 @@ public class DMResponse implements Parcelable {
|
|||
return id;
|
||||
}
|
||||
|
||||
@ParcelablePlease
|
||||
@JsonObject
|
||||
public static class Attachment {
|
||||
public static class Attachment implements Parcelable {
|
||||
@JsonField(name = "photo")
|
||||
MediaEntity photo;
|
||||
|
||||
public MediaEntity getPhoto() {
|
||||
return photo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Attachment{" +
|
||||
"photo=" + photo +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
DMResponse$Entry$MessageParcelablePlease.writeToParcel(this, dest, flags);
|
||||
}
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static final Creator<Message> CREATOR = new Creator<Message>() {
|
||||
@Override
|
||||
public Message createFromParcel(Parcel source) {
|
||||
Message target = new Message();
|
||||
DMResponse$Entry$MessageParcelablePlease.readFromParcel(target, source);
|
||||
return target;
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
DMResponse$Entry$Message$Data$AttachmentParcelablePlease.writeToParcel(this, dest, flags);
|
||||
}
|
||||
|
||||
public static final Creator<Attachment> CREATOR = new Creator<Attachment>() {
|
||||
public Attachment createFromParcel(Parcel source) {
|
||||
Attachment target = new Attachment();
|
||||
DMResponse$Entry$Message$Data$AttachmentParcelablePlease.readFromParcel(target, source);
|
||||
return target;
|
||||
}
|
||||
|
||||
public Attachment[] newArray(int size) {
|
||||
return new Attachment[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message[] newArray(int size) {
|
||||
return new Message[size];
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
DMResponse$Entry$Message$DataParcelablePlease.writeToParcel(this, dest, flags);
|
||||
}
|
||||
|
||||
public static final Creator<Data> CREATOR = new Creator<Data>() {
|
||||
public Data createFromParcel(Parcel source) {
|
||||
Data target = new Data();
|
||||
DMResponse$Entry$Message$DataParcelablePlease.readFromParcel(target, source);
|
||||
return target;
|
||||
}
|
||||
|
||||
public Data[] newArray(int size) {
|
||||
return new Data[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -153,6 +153,7 @@ public class ParcelableMessage {
|
|||
|
||||
@StringDef({MessageType.TEXT, MessageType.STICKER})
|
||||
public @interface MessageType {
|
||||
String CONVERSATION_CREATE = "conversation_create";
|
||||
String TEXT = "text";
|
||||
String STICKER = "sticker";
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import org.apache.commons.lang3.text.translate.CharSequenceTranslator;
|
|||
import org.apache.commons.lang3.text.translate.EntityArrays;
|
||||
import org.apache.commons.lang3.text.translate.LookupTranslator;
|
||||
import org.mariotaku.commons.text.CodePointArray;
|
||||
import org.mariotaku.microblog.library.twitter.model.DMResponse;
|
||||
import org.mariotaku.microblog.library.twitter.model.DirectMessage;
|
||||
import org.mariotaku.microblog.library.twitter.model.EntitySupport;
|
||||
import org.mariotaku.microblog.library.twitter.model.ExtendedEntitySupport;
|
||||
|
@ -42,20 +43,20 @@ public class InternalTwitterContentUtils {
|
|||
}
|
||||
|
||||
public static boolean isFiltered(final SQLiteDatabase database, final UserKey userKey,
|
||||
final String textPlain, final String quotedTextPlain,
|
||||
final SpanItem[] spans, final SpanItem[] quotedSpans,
|
||||
final String source, final String quotedSource,
|
||||
final UserKey retweetedById, final UserKey quotedUserId) {
|
||||
final String textPlain, final String quotedTextPlain,
|
||||
final SpanItem[] spans, final SpanItem[] quotedSpans,
|
||||
final String source, final String quotedSource,
|
||||
final UserKey retweetedById, final UserKey quotedUserId) {
|
||||
return isFiltered(database, userKey, textPlain, quotedTextPlain, spans, quotedSpans, source,
|
||||
quotedSource, retweetedById, quotedUserId, true);
|
||||
}
|
||||
|
||||
public static boolean isFiltered(final SQLiteDatabase database, final UserKey userKey,
|
||||
final String textPlain, final String quotedTextPlain,
|
||||
final SpanItem[] spans, final SpanItem[] quotedSpans,
|
||||
final String source, final String quotedSource,
|
||||
final UserKey retweetedByKey, final UserKey quotedUserKey,
|
||||
final boolean filterRts) {
|
||||
final String textPlain, final String quotedTextPlain,
|
||||
final SpanItem[] spans, final SpanItem[] quotedSpans,
|
||||
final String source, final String quotedSource,
|
||||
final UserKey retweetedByKey, final UserKey quotedUserKey,
|
||||
final boolean filterRts) {
|
||||
if (database == null) return false;
|
||||
if (textPlain == null && spans == null && userKey == null && source == null)
|
||||
return false;
|
||||
|
@ -163,7 +164,7 @@ public class InternalTwitterContentUtils {
|
|||
}
|
||||
|
||||
public static boolean isFiltered(final SQLiteDatabase database, final ParcelableStatus status,
|
||||
final boolean filterRTs) {
|
||||
final boolean filterRTs) {
|
||||
if (database == null || status == null) return false;
|
||||
return isFiltered(database, status.user_key, status.text_plain, status.quoted_text_plain,
|
||||
status.spans, status.quoted_spans, status.source, status.quoted_source,
|
||||
|
@ -223,6 +224,13 @@ public class InternalTwitterContentUtils {
|
|||
return builder.buildWithIndices();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Pair<String, SpanItem[]> formatDirectMessageText(@NonNull final DMResponse.Entry.Message.Data message) {
|
||||
final HtmlBuilder builder = new HtmlBuilder(message.getText(), false, true, false);
|
||||
parseEntities(builder, message);
|
||||
return builder.buildWithIndices();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static StatusTextWithIndices formatStatusTextWithIndices(@NonNull final Status status) {
|
||||
//TODO handle twitter video url
|
||||
|
|
|
@ -35,6 +35,7 @@ import org.mariotaku.twidere.model.ParcelableMessage
|
|||
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.StickerMessageViewHolder
|
||||
import java.util.*
|
||||
|
@ -66,13 +67,17 @@ 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)
|
||||
}
|
||||
}
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
when (holder.itemViewType) {
|
||||
ITEM_TYPE_TEXT_MESSAGE, ITEM_TYPE_STICKER_MESSAGE -> {
|
||||
ITEM_TYPE_TEXT_MESSAGE, ITEM_TYPE_STICKER_MESSAGE, ITEM_TYPE_CONVERSATION_CREATE -> {
|
||||
val message = getMessage(position)!!
|
||||
// Display date for oldest item
|
||||
var showDate = true
|
||||
|
@ -105,6 +110,9 @@ class MessagesConversationAdapter(context: Context) : LoadMoreSupportAdapter<Rec
|
|||
MessageType.STICKER -> {
|
||||
return ITEM_TYPE_STICKER_MESSAGE
|
||||
}
|
||||
MessageType.CONVERSATION_CREATE -> {
|
||||
return ITEM_TYPE_CONVERSATION_CREATE
|
||||
}
|
||||
else -> return ITEM_TYPE_TEXT_MESSAGE
|
||||
}
|
||||
}
|
||||
|
@ -117,6 +125,7 @@ class MessagesConversationAdapter(context: Context) : LoadMoreSupportAdapter<Rec
|
|||
|
||||
const val ITEM_TYPE_TEXT_MESSAGE = 1
|
||||
const val ITEM_TYPE_STICKER_MESSAGE = 2
|
||||
const val ITEM_TYPE_CONVERSATION_CREATE = 3
|
||||
}
|
||||
|
||||
}
|
|
@ -157,7 +157,7 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
|
|||
adapter.getData(), true, loadingMore)
|
||||
// Setting comparator to null lets statuses sort ascending
|
||||
loader.comparator = Comparator { l, r ->
|
||||
(l.sort_id - r.sort_id).toInt()
|
||||
(r.sort_id - l.sort_id).toInt()
|
||||
}
|
||||
return loader
|
||||
}
|
||||
|
@ -365,8 +365,8 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
|
|||
}
|
||||
|
||||
override fun handleKeyboardShortcutSingle(handler: KeyboardShortcutsHandler,
|
||||
keyCode: Int, event: KeyEvent,
|
||||
metaState: Int): Boolean {
|
||||
keyCode: Int, event: KeyEvent,
|
||||
metaState: Int): Boolean {
|
||||
if (!KeyboardShortcutsHandler.isValidForHotkey(keyCode, event)) return false
|
||||
val focusedChild = RecyclerViewUtils.findRecyclerViewChild(recyclerView, layoutManager.focusedChild)
|
||||
val position: Int
|
||||
|
@ -411,8 +411,8 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
|
|||
}
|
||||
|
||||
override fun handleKeyboardShortcutRepeat(handler: KeyboardShortcutsHandler,
|
||||
keyCode: Int, repeatCount: Int,
|
||||
event: KeyEvent, metaState: Int): Boolean {
|
||||
keyCode: Int, repeatCount: Int,
|
||||
event: KeyEvent, metaState: Int): Boolean {
|
||||
return navigationHelper.handleKeyboardShortcutRepeat(handler, keyCode,
|
||||
repeatCount, event, metaState)
|
||||
}
|
||||
|
@ -426,7 +426,7 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
|
|||
|
||||
|
||||
override fun onLoadFinished(loader: Loader<SingleResponse<ParcelableStatus>>,
|
||||
data: SingleResponse<ParcelableStatus>) {
|
||||
data: SingleResponse<ParcelableStatus>) {
|
||||
val activity = activity ?: return
|
||||
val status = data.data
|
||||
if (status != null) {
|
||||
|
@ -811,9 +811,9 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
|
|||
|
||||
@UiThread
|
||||
fun displayStatus(account: AccountDetails?,
|
||||
status: ParcelableStatus?,
|
||||
statusActivity: StatusActivity?,
|
||||
translation: TranslationResult?) {
|
||||
status: ParcelableStatus?,
|
||||
statusActivity: StatusActivity?,
|
||||
translation: TranslationResult?) {
|
||||
if (account == null || status == null) return
|
||||
val fragment = adapter.fragment
|
||||
val context = adapter.context
|
||||
|
@ -1445,7 +1445,7 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
|
|||
) : StatusLinkClickHandler(context, manager, preferences) {
|
||||
|
||||
override fun onLinkClick(link: String, orig: String?, accountKey: UserKey?,
|
||||
extraId: Long, type: Int, sensitive: Boolean, start: Int, end: Int): Boolean {
|
||||
extraId: Long, type: Int, sensitive: Boolean, start: Int, end: Int): Boolean {
|
||||
val current = getCurrentMedia(link, extraId.toInt())
|
||||
if (current != null && !current.open_browser) {
|
||||
expandOrOpenMedia(current)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
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.twidere.model.ParcelableMessage
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
|
@ -12,11 +13,21 @@ import org.mariotaku.twidere.util.InternalTwitterContentUtils
|
|||
* Created by mariotaku on 2017/2/9.
|
||||
*/
|
||||
object ParcelableMessageUtils {
|
||||
fun incomingMessage(
|
||||
accountKey: UserKey,
|
||||
message: DirectMessage,
|
||||
@FloatRange(from = 0.0, to = 1.0) sortIdAdj: Double = 0.0
|
||||
): ParcelableMessage {
|
||||
|
||||
fun fromEntry(accountKey: UserKey, entry: DMResponse.Entry): ParcelableMessage? {
|
||||
when {
|
||||
entry.message != null -> {
|
||||
return ParcelableMessage().apply { applyMessage(accountKey, entry.message) }
|
||||
}
|
||||
entry.conversationCreate != null -> {
|
||||
return ParcelableMessage().apply { applyConversationCreate(accountKey, entry.conversationCreate) }
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun incomingMessage(accountKey: UserKey, message: DirectMessage,
|
||||
@FloatRange(from = 0.0, to = 1.0) sortIdAdj: Double = 0.0): ParcelableMessage {
|
||||
val result = message(accountKey, message, sortIdAdj)
|
||||
result.is_outgoing = false
|
||||
result.conversation_id = incomingConversationId(message.senderId, message.recipientId)
|
||||
|
@ -42,6 +53,35 @@ object ParcelableMessageUtils {
|
|||
return "$senderId-$recipientId"
|
||||
}
|
||||
|
||||
private fun ParcelableMessage.applyMessage(accountKey: UserKey, message: DMResponse.Entry.Message) {
|
||||
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)
|
||||
val (text, spans) = InternalTwitterContentUtils.formatDirectMessageText(data)
|
||||
this.text_unescaped = text
|
||||
this.spans = spans
|
||||
|
||||
this.is_outgoing = this.sender_key == accountKey
|
||||
}
|
||||
|
||||
private fun ParcelableMessage.applyConversationCreate(accountKey: UserKey, message: DMResponse.Entry.Message) {
|
||||
this.commonEntry(accountKey, message)
|
||||
this.message_type = ParcelableMessage.MessageType.CONVERSATION_CREATE
|
||||
this.is_outgoing = false
|
||||
}
|
||||
|
||||
private fun ParcelableMessage.commonEntry(accountKey: UserKey, message: DMResponse.Entry.Message) {
|
||||
this.message_type = ParcelableMessage.MessageType.TEXT
|
||||
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
|
||||
}
|
||||
|
||||
private fun message(
|
||||
accountKey: UserKey,
|
||||
message: DirectMessage,
|
||||
|
|
|
@ -72,6 +72,32 @@ class GetMessagesTask(
|
|||
return getDefaultMessages(microBlog, details, param, index)
|
||||
}
|
||||
|
||||
private fun getTwitterOfficialMessages(microBlog: MicroBlog, details: AccountDetails, param: RefreshMessagesTaskParam, index: Int): GetMessagesData {
|
||||
val accountKey = details.key
|
||||
val cursor = param.cursors?.get(index)
|
||||
val page = cursor?.substringAfter("page:").toInt(-1)
|
||||
val inbox = microBlog.getUserInbox(Paging().apply {
|
||||
count(60)
|
||||
if (page >= 0) {
|
||||
page(page)
|
||||
}
|
||||
}).userInbox
|
||||
val conversations = hashMapOf<String, ParcelableMessageConversation>()
|
||||
|
||||
val conversationIds = inbox.conversations.keys
|
||||
conversations.addLocalConversations(accountKey, conversationIds)
|
||||
val messages = inbox.entries.mapNotNull { ParcelableMessageUtils.fromEntry(accountKey, it) }
|
||||
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 }
|
||||
}.values
|
||||
conversations.addConversation(k, details, message, participants)
|
||||
}
|
||||
return GetMessagesData(conversations.values, messages)
|
||||
}
|
||||
|
||||
private fun getFanfouMessages(microBlog: MicroBlog, details: AccountDetails, param: RefreshMessagesTaskParam, index: Int): GetMessagesData {
|
||||
val conversationId = param.conversationId
|
||||
if (conversationId == null) {
|
||||
|
@ -81,10 +107,6 @@ class GetMessagesTask(
|
|||
}
|
||||
}
|
||||
|
||||
private fun getTwitterOfficialMessages(microBlog: MicroBlog, details: AccountDetails, param: RefreshMessagesTaskParam, index: Int): GetMessagesData {
|
||||
return getDefaultMessages(microBlog, details, param, index)
|
||||
}
|
||||
|
||||
private fun getDefaultMessages(microBlog: MicroBlog, details: AccountDetails, param: RefreshMessagesTaskParam, index: Int): GetMessagesData {
|
||||
val accountKey = details.key
|
||||
|
||||
|
@ -132,12 +154,12 @@ class GetMessagesTask(
|
|||
received.forEachIndexed { i, dm ->
|
||||
val message = ParcelableMessageUtils.incomingMessage(accountKey, dm, 1.0 - (i.toDouble() / received.size))
|
||||
insertMessages.add(message)
|
||||
conversations.addConversation(details, message, dm.sender, dm.recipient)
|
||||
conversations.addConversation(message.conversation_id, details, message, setOf(dm.sender, dm.recipient))
|
||||
}
|
||||
sent.forEachIndexed { i, dm ->
|
||||
val message = ParcelableMessageUtils.outgoingMessage(accountKey, dm, 1.0 - (i.toDouble() / sent.size))
|
||||
insertMessages.add(message)
|
||||
conversations.addConversation(details, message, dm.sender, dm.recipient)
|
||||
conversations.addConversation(message.conversation_id, details, message, setOf(dm.sender, dm.recipient))
|
||||
}
|
||||
return GetMessagesData(conversations.values, insertMessages)
|
||||
}
|
||||
|
@ -165,7 +187,8 @@ class GetMessagesTask(
|
|||
} else {
|
||||
ParcelableMessageUtils.incomingMessage(accountKey, dm, 1.0 - (i.toDouble() / result.size))
|
||||
}
|
||||
val mc = conversations.addConversation(details, message, dm.sender, dm.recipient)
|
||||
val mc = conversations.addConversation(message.conversation_id, details, message,
|
||||
setOf(dm.sender, dm.recipient))
|
||||
mc.request_cursor = "page:$page"
|
||||
}
|
||||
return GetMessagesData(conversations.values, emptyList())
|
||||
|
@ -231,16 +254,21 @@ class GetMessagesTask(
|
|||
}
|
||||
|
||||
private fun MutableMap<String, ParcelableMessageConversation>.addConversation(
|
||||
conversationId: String,
|
||||
details: AccountDetails,
|
||||
message: ParcelableMessage,
|
||||
vararg users: User
|
||||
users: Collection<User>
|
||||
): ParcelableMessageConversation {
|
||||
val conversation = this[message.conversation_id] ?: run {
|
||||
val conversation = this[conversationId] ?: run {
|
||||
val obj = ParcelableMessageConversation()
|
||||
obj.id = message.conversation_id
|
||||
obj.conversation_type = ConversationType.ONE_TO_ONE
|
||||
obj.id = conversationId
|
||||
if (users.size == 2) {
|
||||
obj.conversation_type = ConversationType.ONE_TO_ONE
|
||||
} else {
|
||||
obj.conversation_type = ConversationType.GROUP
|
||||
}
|
||||
obj.setFrom(message, details)
|
||||
this[message.conversation_id] = obj
|
||||
this[conversationId] = obj
|
||||
return@run obj
|
||||
}
|
||||
if (message.timestamp > conversation.timestamp) {
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2017 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* 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 org.mariotaku.twidere.view.holder.message
|
||||
|
||||
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.model.ParcelableMessage
|
||||
import org.mariotaku.twidere.view.FixedTextView
|
||||
|
||||
class ConversationCreateMessageViewHolder(itemView: View, adapter: MessagesConversationAdapter) : AbsMessageViewHolder(itemView, adapter) {
|
||||
override val messageContent: View = itemView
|
||||
override val date: FixedTextView by lazy { itemView.date }
|
||||
|
||||
private val text by lazy { itemView.text }
|
||||
|
||||
override fun display(message: ParcelableMessage, showDate: Boolean) {
|
||||
super.display(message, showDate)
|
||||
text.setText(R.string.message_conversation_created)
|
||||
}
|
||||
|
||||
override fun setMessageContentGravity(view: View, outgoing: Boolean) {
|
||||
// No-op
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val layoutResource = R.layout.list_item_message_conversation_notice
|
||||
}
|
||||
|
||||
}
|
|
@ -71,12 +71,12 @@ class MessageEntryViewHolder(itemView: View, val adapter: MessagesEntriesAdapter
|
|||
if (user != null) {
|
||||
adapter.mediaLoader.displayProfileImage(profileImage, user)
|
||||
} else {
|
||||
adapter.mediaLoader.cancelDisplayTask(profileImage)
|
||||
adapter.mediaLoader.displayProfileImage(profileImage, null)
|
||||
// TODO display default profile image
|
||||
}
|
||||
} else {
|
||||
adapter.mediaLoader.cancelDisplayTask(profileImage)
|
||||
// TODO display default profile image
|
||||
profileImage.setImageResource(R.drawable.ic_profile_image_default_group)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Twidere - Twitter client for Android
|
||||
~
|
||||
~ Copyright (C) 2012-2017 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
~
|
||||
~ 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/>.
|
||||
-->
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
<org.mariotaku.twidere.view.FixedTextView
|
||||
android:id="@+id/date"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:padding="@dimen/element_spacing_normal"
|
||||
android:textAppearance="?android:textAppearanceSmall"
|
||||
android:textColor="?android:textColorTertiary"
|
||||
tools:text="Yesterday"/>
|
||||
|
||||
<org.mariotaku.twidere.view.FixedTextView
|
||||
android:id="@+id/text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
tools:text="Notice"/>
|
||||
</LinearLayout>
|
|
@ -665,6 +665,7 @@
|
|||
<string name="message_api_url_format_help">[DOMAIN]: Twitter API domain.\nExample: https://[DOMAIN].twitter.com/ will be replaced to https://api.twitter.com/.</string>
|
||||
<string name="message_auto_refresh_confirm">Enable auto refresh to get new tweets automatically?</string>
|
||||
<string name="message_blocked_user">Blocked <xliff:g id="user">%s</xliff:g>.</string>
|
||||
<string name="message_conversation_created">Conversation created.</string>
|
||||
<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>
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="48px" height="48px" viewBox="0 0 48 48" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="background: #1CDCF8;">
|
||||
<!-- Generator: Sketch 42 (36781) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>ic_profile_image_default_group-mdpi</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Miscellaneous" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="ic_profile_image_default_group-mdpi">
|
||||
<polygon id="Shape" fill="#1CDCF8" points="0 0 48 0 48 48 0 48"></polygon>
|
||||
<path d="M29.3333333,22.6666667 C31.5466667,22.6666667 33.32,20.88 33.32,18.6666667 C33.32,16.4533333 31.5466667,14.6666667 29.3333333,14.6666667 C27.12,14.6666667 25.3333333,16.4533333 25.3333333,18.6666667 C25.3333333,20.88 27.12,22.6666667 29.3333333,22.6666667 Z M18.6666667,22.6666667 C20.88,22.6666667 22.6533333,20.88 22.6533333,18.6666667 C22.6533333,16.4533333 20.88,14.6666667 18.6666667,14.6666667 C16.4533333,14.6666667 14.6666667,16.4533333 14.6666667,18.6666667 C14.6666667,20.88 16.4533333,22.6666667 18.6666667,22.6666667 Z M18.6666667,25.3333333 C15.56,25.3333333 9.33333333,26.8933333 9.33333333,30 L9.33333333,33.3333333 L28,33.3333333 L28,30 C28,26.8933333 21.7733333,25.3333333 18.6666667,25.3333333 Z M29.3333333,25.3333333 C28.9466667,25.3333333 28.5066667,25.36 28.04,25.4 C29.5866667,26.52 30.6666667,28.0266667 30.6666667,30 L30.6666667,33.3333333 L38.6666667,33.3333333 L38.6666667,30 C38.6666667,26.8933333 32.44,25.3333333 29.3333333,25.3333333 Z" id="Shape" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.7 KiB |
Loading…
Reference in New Issue