status card databinding migration

This commit is contained in:
Mariotaku Lee 2018-09-03 11:39:57 +08:00
parent 8d1955995b
commit 567dce9702
No known key found for this signature in database
GPG Key ID: 15C10F89D7C33535
9 changed files with 133 additions and 67 deletions

View File

@ -6,7 +6,7 @@ buildscript {
maven { url 'https://plugins.gradle.org/m2/' }
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.3'
classpath 'com.android.tools.build:gradle:3.1.4'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}

View File

@ -29,7 +29,7 @@ public class DirectMessageEvent {
String id;
@JsonField(name = "created_timestamp")
long created_timestamp;
long createdTimestamp;
@JsonField(name = "type")
String type;
@ -46,6 +46,10 @@ public class DirectMessageEvent {
this.type = type;
}
public long getCreatedTimestamp() {
return createdTimestamp;
}
public MessageCreate getMessageCreate() {
return messageCreate;
}

View File

@ -0,0 +1,9 @@
package org.mariotaku.twidere.extension.databinding
import android.databinding.BindingAdapter
import android.view.View
@BindingAdapter("activated")
fun View.setActivatedBinding(activated: Boolean) {
isActivated = activated
}

View File

@ -1,6 +1,9 @@
@file:JvmName("ParcelableStatusExtensions")
package org.mariotaku.twidere.extension.model
import android.content.Context
import android.support.annotation.DrawableRes
import android.text.SpannableStringBuilder
import org.mariotaku.ktextension.addAllTo
import org.mariotaku.ktextension.appendTo
@ -10,15 +13,24 @@ import org.mariotaku.twidere.R
import org.mariotaku.twidere.TwidereConstants.USER_TYPE_FANFOU_COM
import org.mariotaku.twidere.model.*
import org.mariotaku.twidere.model.attachment.QuotedStatus
import org.mariotaku.twidere.task.CreateFavoriteTask
import org.mariotaku.twidere.task.DestroyFavoriteTask
import org.mariotaku.twidere.task.DestroyStatusTask
import org.mariotaku.twidere.task.RetweetStatusTask
import org.mariotaku.twidere.util.HtmlEscapeHelper
import org.mariotaku.twidere.util.UriUtils
import org.mariotaku.twidere.util.UserColorNameManager
import org.mariotaku.twidere.util.Utils
import org.mariotaku.twidere.view.ShortTimeView
inline val ParcelableStatus.originalId: String
get() = if (is_retweet) (retweet_id ?: id) else id
val ParcelableStatus.userTypeIcon: Int
@DrawableRes get() = Utils.getUserTypeIconRes(user_is_verified, user_is_protected)
val ParcelableStatus.media_type: Int
get() = attachment?.media?.firstOrNull()?.type ?: 0
@ -261,6 +273,19 @@ fun ParcelableStatus.generateDisplayInfo(context: Context): ParcelableStatus.Dis
return info
}
fun ParcelableStatus.retweetIconActivated(): Boolean {
return !DestroyStatusTask.isRunning(account_key, my_retweet_id) &&
(RetweetStatusTask.isRunning(account_key, id) ||
retweeted || account_key == retweeted_by_user_key ||
my_retweet_id != null)
}
fun ParcelableStatus.favoriteIconActivated(): Boolean {
return !DestroyFavoriteTask.isRunning(account_key, id) &&
(CreateFavoriteTask.isRunning(account_key, id) || is_favorite)
}
internal inline val String.plainText: String get() = HtmlEscapeHelper.toPlainText(this)
private fun parcelableUserMention(key: UserKey, name: String, screenName: String) = ParcelableUserMention().also {

View File

@ -6,6 +6,7 @@ import org.mariotaku.microblog.library.model.microblog.DMResponse.Entry.Message
import org.mariotaku.microblog.library.model.microblog.DMResponse.Entry.Message.Data
import org.mariotaku.microblog.library.model.microblog.DirectMessage
import org.mariotaku.microblog.library.model.microblog.User
import org.mariotaku.microblog.library.model.twitter.dm.DirectMessageEvent
import org.mariotaku.twidere.extension.model.api.addEntities
import org.mariotaku.twidere.extension.model.api.getEntityMedia
import org.mariotaku.twidere.extension.model.api.key
@ -17,6 +18,7 @@ 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.HtmlBuilder
import java.util.*
/**
* Created by mariotaku on 2017/2/9.
@ -36,6 +38,20 @@ object ParcelableMessageUtils {
return result
}
fun fromMessage(accountKey: UserKey, event: DirectMessageEvent, outgoing: Boolean,
@FloatRange(from = 0.0, to = 1.0) sortIdAdj: Double = 0.0): ParcelableMessage {
val result = ParcelableMessage()
val message = event.messageCreate
result.applyMessage(accountKey, event, sortIdAdj)
result.is_outgoing = outgoing
if (outgoing) {
result.conversation_id = outgoingConversationId(message.senderId, message.target.recipientId)
} else {
result.conversation_id = incomingConversationId(message.senderId, message.target.recipientId)
}
return result
}
fun fromEntry(accountKey: UserKey, accountType: String, entry: DMResponse.Entry,
users: Map<String, User>, profileImageSize: ModelCreationConfig = ModelCreationConfig.DEFAULT): ParcelableMessage? {
when {
@ -107,6 +123,16 @@ object ParcelableMessageUtils {
return builder.buildWithIndices()
}
private fun formatDirectMessageText(message: DirectMessageEvent.MessageCreate): Pair<String, Array<SpanItem>> {
var text: String? = message.messageData.text
if (text == null) {
text = ""
}
val builder = HtmlBuilder(text, false, true, false)
// builder.addEntities(message.messageData)
return builder.buildWithIndices()
}
private fun ParcelableMessage.applyConversationCreate(accountKey: UserKey, message: Message) {
this.commonEntry(accountKey, message)
this.message_type = MessageType.CONVERSATION_CREATE
@ -182,6 +208,32 @@ object ParcelableMessageUtils {
this.media = message.getEntityMedia()
}
private fun ParcelableMessage.applyMessage(
accountKey: UserKey,
event: DirectMessageEvent,
@FloatRange(from = 0.0, to = 1.0) sortIdAdj: Double = 0.0
) {
val message = event.messageCreate
this.account_key = accountKey
this.id = UUID.randomUUID().toString()
this.sender_key = UserKey(message.senderId, account_key.host)
this.recipient_key = UserKey(message.target.recipientId, account_key.host)
this.message_timestamp = event.createdTimestamp
this.local_timestamp = this.message_timestamp
this.sort_id = this.message_timestamp + (499 * sortIdAdj).toLong()
val (type, extras) = typeAndExtras(message)
val (text, spans) = formatDirectMessageText(message)
val messageMedia = message.messageData.attachment.media
this.message_type = type
this.extras = extras
this.text_unescaped = text
this.spans = spans
if (messageMedia != null) {
this.media = arrayOf(messageMedia.toParcelable())
}
}
private fun formatDirectMessageText(message: DirectMessage): Pair<String, Array<SpanItem>> {
val builder = HtmlBuilder(message.text, false, true, false)
builder.addEntities(message)
@ -197,6 +249,9 @@ object ParcelableMessageUtils {
}
return Pair(MessageType.TEXT, null)
}
private fun typeAndExtras(message: DirectMessageEvent.MessageCreate): Pair<String, MessageExtras?> {
return Pair(MessageType.TEXT, null)
}
private fun typeAndExtras(data: Data): Triple<String, MessageExtras?, Array<ParcelableMedia>?> {
val attachment = data.attachment ?: return Triple(MessageType.TEXT, null, null)

View File

@ -58,6 +58,7 @@ import org.mariotaku.twidere.provider.TwidereDataStore.Messages.Conversations
import org.mariotaku.twidere.singleton.BusSingleton
import org.mariotaku.twidere.task.BaseAbstractTask
import org.mariotaku.twidere.util.DataStoreUtils
import org.mariotaku.twidere.util.DebugLog
import org.mariotaku.twidere.util.UriUtils
import org.mariotaku.twidere.util.content.ContentResolverUtils
import java.util.*
@ -76,7 +77,8 @@ class GetMessagesTask(
val messages = try {
if (!details.hasDm) throw APINotSupportedException("DM", details.type)
getMessages(details, param, i)
} catch (e: MicroBlogException) {
} catch (e: Exception) {
DebugLog.w(tr = e)
return@forEachIndexed
}
storeMessages(context, messages, details, param.showNotification)
@ -103,10 +105,10 @@ class GetMessagesTask(
AccountType.TWITTER -> {
val twitter = details.newMicroBlogInstance(context, cls = Twitter::class.java)
// Use official DM api
// if (details.isOfficial(context)) {
// return getTwitterOfficialMessages(twitter, details, param, index)
// }
getTwitterMessages(twitter, details, param, index)
if (details.isOfficial(context)) {
return getTwitterOfficialMessages(twitter, details, param, index)
}
return getTwitterMessages(twitter, details, param, index)
}
}
// Use default method
@ -210,7 +212,7 @@ class GetMessagesTask(
val users = twitter.lookupUsers(events.flatMap {
val mc = it.messageCreate ?: return@flatMap emptyList<String>()
return@flatMap listOf(mc.senderId, mc.target.recipientId)
}.distinct().toTypedArray())
}.distinct().toTypedArray()).map { it.toParcelable(details) }
events.forEach { event ->
val msg = event.messageCreate
@ -220,8 +222,8 @@ class GetMessagesTask(
conversations.addLocalConversations(context, accountKey, conversationIds)
events.forEachIndexed { i, dm ->
// addConversationMessage(insertMessages, conversations, details, dm, i, events.size,
// false, profileImageSize, updateLastRead)
addConversationMessage(insertMessages, users, conversations, details, dm, i, events.size,
false, updateLastRead = updateLastRead)
}
return DatabaseUpdateData(conversations.values, insertMessages)
@ -618,15 +620,15 @@ class GetMessagesTask(
internal fun addConversationMessage(messages: MutableCollection<ParcelableMessage>,
conversations: MutableMap<String, ParcelableMessageConversation>,
details: AccountDetails, dm: DirectMessage, index: Int, size: Int,
outgoing: Boolean, profileImageSize: ModelCreationConfig = ModelCreationConfig.DEFAULT,
outgoing: Boolean, creationConfig: ModelCreationConfig = ModelCreationConfig.DEFAULT,
updateLastRead: Boolean) {
val accountKey = details.key
val accountType = details.type
val message = ParcelableMessageUtils.fromMessage(accountKey, dm, outgoing,
1.0 - (index.toDouble() / size))
messages.add(message)
val sender = dm.sender.toParcelable(accountKey, accountType, creationConfig = profileImageSize)
val recipient = dm.recipient.toParcelable(accountKey, accountType, creationConfig = profileImageSize)
val sender = dm.sender.toParcelable(details, creationConfig = creationConfig)
val recipient = dm.recipient.toParcelable(details, creationConfig = creationConfig)
val conversation = conversations.addConversation(message.conversation_id, details,
message, setOf(sender, recipient), updateLastRead = updateLastRead) ?: return
conversation.conversation_extras_type = ParcelableMessageConversation.ExtrasType.DEFAULT
@ -636,22 +638,23 @@ class GetMessagesTask(
}
internal fun addConversationMessage(messages: MutableCollection<ParcelableMessage>,
conversations: MutableMap<String, ParcelableMessageConversation>,
details: AccountDetails, dm: DirectMessageEvent.MessageCreate, index: Int, size: Int,
outgoing: Boolean, profileImageSize: String = "normal", updateLastRead: Boolean) {
users: List<ParcelableUser>, conversations: MutableMap<String, ParcelableMessageConversation>,
details: AccountDetails, event: DirectMessageEvent, index: Int, size: Int,
outgoing: Boolean, updateLastRead: Boolean) {
val accountKey = details.key
val accountType = details.type
// val message = ParcelableMessageUtils.fromMessage(accountKey, dm, outgoing,
// 1.0 - (index.toDouble() / size))
// messages.add(message)
// val sender = dm.sender.toParcelable(accountKey, accountType, profileImageSize = profileImageSize)
// val recipient = dm.recipient.toParcelable(accountKey, accountType, profileImageSize = profileImageSize)
// val conversation = conversations.addConversation(message.conversation_id, details,
// message, setOf(sender, recipient), updateLastRead = updateLastRead) ?: return
// conversation.conversation_extras_type = ParcelableMessageConversation.ExtrasType.DEFAULT
// if (conversation.conversation_extras == null) {
// conversation.conversation_extras = DefaultConversationExtras()
// }
val message = ParcelableMessageUtils.fromMessage(accountKey, event, outgoing,
1.0 - (index.toDouble() / size))
val dm = event.messageCreate
messages.add(message)
val sender = users.find { it.key.id == dm.senderId }
val recipient = users.find { it.key.id == dm.target.recipientId }
val conversation = conversations.addConversation(message.conversation_id, details,
message, setOf(sender, recipient).filterNotNull(), updateLastRead = updateLastRead)
?: return
conversation.conversation_extras_type = ParcelableMessageConversation.ExtrasType.DEFAULT
if (conversation.conversation_extras == null) {
conversation.conversation_extras = DefaultConversationExtras()
}
}
}

View File

@ -35,9 +35,7 @@ import org.mariotaku.twidere.R
import org.mariotaku.twidere.adapter.RecyclerPagerAdapter
import org.mariotaku.twidere.adapter.iface.IStatusesAdapter
import org.mariotaku.twidere.constant.SharedPreferenceConstants.VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE
import org.mariotaku.twidere.extension.model.applyTo
import org.mariotaku.twidere.extension.model.aspectRatio
import org.mariotaku.twidere.extension.model.contentDescription
import org.mariotaku.twidere.extension.model.*
import org.mariotaku.twidere.graphic.like.LikeAnimationDrawable
import org.mariotaku.twidere.model.ParcelableMedia
import org.mariotaku.twidere.model.ParcelableStatus
@ -112,8 +110,8 @@ class LargeMediaStatusViewHolder(private val adapter: IStatusesAdapter, itemView
}
textView.hideIfEmpty()
replyButton.isActivated = StatusViewHolder.isRetweetIconActivated(status)
favoriteButton.isActivated = StatusViewHolder.isFavoriteIconActivated(status)
replyButton.isActivated = status.retweetIconActivated()
favoriteButton.isActivated = status.favoriteIconActivated(status)
val aspectRatio = status.attachment?.media?.fold(Double.NaN) { acc, media ->
if (acc.isNaN()) return@fold media.aspectRatio

View File

@ -56,17 +56,12 @@ import org.mariotaku.twidere.model.ParcelableStatus
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.model.placeholder.PlaceholderObject
import org.mariotaku.twidere.singleton.BidiFormatterSingleton
import org.mariotaku.twidere.task.CreateFavoriteTask
import org.mariotaku.twidere.task.DestroyFavoriteTask
import org.mariotaku.twidere.task.DestroyStatusTask
import org.mariotaku.twidere.task.RetweetStatusTask
import org.mariotaku.twidere.text.TwidereClickableSpan
import org.mariotaku.twidere.text.style.PlaceholderLineSpan
import org.mariotaku.twidere.util.HtmlEscapeHelper.toPlainText
import org.mariotaku.twidere.util.HtmlSpanBuilder
import org.mariotaku.twidere.util.UriCreator
import org.mariotaku.twidere.util.UserColorNameManager
import org.mariotaku.twidere.util.Utils.getUserTypeIconRes
import org.mariotaku.twidere.view.ProfileImageView
import org.mariotaku.twidere.view.ShortTimeView
import org.mariotaku.twidere.view.holder.iface.IStatusViewHolder
@ -241,18 +236,6 @@ class StatusViewHolder(var adapter: IStatusesAdapter, val binding: ItemStatusBin
nameView.placeholder = false
if (adapter.profileImageEnabled) {
profileImageView.visibility = View.VISIBLE
profileTypeView.setImageResource(getUserTypeIconRes(status.user_is_verified, status.user_is_protected))
profileTypeView.visibility = View.VISIBLE
} else {
profileImageView.visibility = View.GONE
profileTypeView.setImageDrawable(null)
profileTypeView.visibility = View.GONE
}
if (adapter.showAccountsColor) {
itemContent.drawEnd(status.account_color)
} else {
@ -264,10 +247,6 @@ class StatusViewHolder(var adapter: IStatusesAdapter, val binding: ItemStatusBin
retweetButton.drawable?.mutate()
retweetButton.isActivated = isRetweetIconActivated(status)
favoriteButton.isActivated = isFavoriteIconActivated(status)
attachmentContainer.setVisible(attachmentHolder != null)
attachmentHolder?.display(status)
}
@ -504,18 +483,6 @@ class StatusViewHolder(var adapter: IStatusesAdapter, val binding: ItemStatusBin
appendCompat(" ", PlaceholderLineSpan(.5f), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
}
fun isRetweetIconActivated(status: ParcelableStatus): Boolean {
return !DestroyStatusTask.isRunning(status.account_key, status.my_retweet_id) &&
(RetweetStatusTask.isRunning(status.account_key, status.id) ||
status.retweeted || status.account_key == status.retweeted_by_user_key ||
status.my_retweet_id != null)
}
fun isFavoriteIconActivated(status: ParcelableStatus): Boolean {
return !DestroyFavoriteTask.isRunning(status.account_key, status.id) &&
(CreateFavoriteTask.isRunning(status.account_key, status.id) || status.is_favorite)
}
}
}

View File

@ -27,7 +27,7 @@
<import type="org.mariotaku.twidere.R" />
<import type="org.mariotaku.twidere.model.ParcelableStatus" />
<import type="org.mariotaku.twidere.extension.model.ParcelableStatusExtensions" />
<variable
name="status"
@ -94,6 +94,7 @@
android:layout_height="@dimen/icon_size_status_profile_image"
android:contentDescription="@{status.display.profileImageContentDescription}"
android:scaleType="centerCrop"
android:visibility="@{displayOption.profileImageEnabled ? View.VISIBLE : View.GONE}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/name"
bind:profileImage="@{status.user_profile_image_url}"
@ -106,6 +107,8 @@
android:layout_width="@dimen/icon_size_profile_type"
android:layout_height="@dimen/icon_size_profile_type"
android:scaleType="fitCenter"
android:src="@{ParcelableStatusExtensions.getUserTypeIcon(status)}"
android:visibility="@{displayOption.profileImageEnabled ? View.VISIBLE : View.GONE}"
app:layout_constraintBottom_toBottomOf="@+id/profileImage"
app:layout_constraintEnd_toEndOf="@+id/profileImage"
tools:src="@drawable/ic_user_type_verified"
@ -223,6 +226,7 @@
app:layout_constraintTop_toBottomOf="@+id/attachmentContainer"
app:srcCompat="@drawable/ic_action_retweet"
app:tint="@color/btn_tint_retweet_stateful"
bind:activated="@{ParcelableStatusExtensions.retweetIconActivated(status)}"
bind:pluralRes="@{R.plurals.N_retweets_abbrev}"
bind:properCount="@{status.retweet_count}"
bind:statusVisibility="@{status.extras.visibility}"
@ -248,6 +252,7 @@
app:layout_constraintTop_toBottomOf="@+id/attachmentContainer"
app:srcCompat="@drawable/ic_action_heart"
app:tint="@color/btn_tint_like_stateful"
bind:activated="@{ParcelableStatusExtensions.favoriteIconActivated(status)}"
bind:pluralRes="@{useFavorite ? R.plurals.N_favorites_abbrev : R.plurals.N_likes_abbrev}"
bind:properCount="@{status.favorite_count}"
bind:zeroRes="@{useFavorite ? R.string.action_favorite : R.string.action_like}"