added date displaying for DM

improved DM time
This commit is contained in:
Mariotaku Lee 2017-02-11 14:50:17 +08:00
parent 7522bf04eb
commit f665318eb6
No known key found for this signature in database
GPG Key ID: 15C10F89D7C33535
12 changed files with 101 additions and 37 deletions

View File

@ -23,17 +23,20 @@ import android.content.Context
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.ViewGroup
import org.apache.commons.lang3.time.DateUtils
import org.mariotaku.twidere.adapter.iface.IItemCountsAdapter
import org.mariotaku.twidere.extension.model.timestamp
import org.mariotaku.twidere.model.ItemCounts
import org.mariotaku.twidere.model.ParcelableMessage
import org.mariotaku.twidere.model.ParcelableMessage.MessageType
import org.mariotaku.twidere.view.holder.message.AbsMessageViewHolder
import org.mariotaku.twidere.view.holder.message.MessageViewHolder
import org.mariotaku.twidere.view.holder.message.StickerMessageViewHolder
import java.util.*
class MessagesConversationAdapter(context: Context) : LoadMoreSupportAdapter<RecyclerView.ViewHolder>(context),
IItemCountsAdapter {
private val calendars = Pair(Calendar.getInstance(), Calendar.getInstance())
override val itemCounts: ItemCounts = ItemCounts(1)
var messages: List<ParcelableMessage>? = null
set(value) {
@ -59,14 +62,24 @@ 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 -> {
(holder as AbsMessageViewHolder).display(getMessage(position)!!)
val message = getMessage(position)!!
// Display date for oldest item
var showDate = true
// ... or if current message is > 1 day newer than previous one
if (position < itemCounts.getItemStartPosition(ITEM_START_MESSAGE)
+ itemCounts[ITEM_START_MESSAGE] - 1) {
calendars.first.timeInMillis = getMessage(position + 1)!!.timestamp
calendars.second.timeInMillis = message.timestamp
showDate = !DateUtils.isSameDay(calendars.first, calendars.second)
}
(holder as AbsMessageViewHolder).display(message, showDate)
}
}
}
override fun getItemCount(): Int {
itemCounts[0] = messages?.size ?: 0
itemCounts[ITEM_START_MESSAGE] = messages?.size ?: 0
return itemCounts.itemCount
}
@ -76,7 +89,7 @@ class MessagesConversationAdapter(context: Context) : LoadMoreSupportAdapter<Rec
override fun getItemViewType(position: Int): Int {
when (itemCounts.getItemCountIndex(position)) {
0 -> {
ITEM_START_MESSAGE -> {
when (getMessage(position)!!.message_type) {
MessageType.STICKER -> {
return ITEM_TYPE_STICKER_MESSAGE
@ -89,6 +102,8 @@ class MessagesConversationAdapter(context: Context) : LoadMoreSupportAdapter<Rec
}
companion object {
private const val ITEM_START_MESSAGE = 0
const val ITEM_TYPE_TEXT_MESSAGE = 1
const val ITEM_TYPE_STICKER_MESSAGE = 2
}

View File

@ -15,6 +15,7 @@ fun ParcelableMessageConversation.setFrom(message: ParcelableMessage, details: A
message_type = message.message_type
message_timestamp = message.message_timestamp
local_timestamp = message.local_timestamp
sort_id = message.sort_id
text_unescaped = message.text_unescaped
media = message.media
spans = message.spans

View File

@ -31,7 +31,7 @@ class MessagesConversationFragment : BaseFragment(), LoaderManager.LoaderCallbac
super.onActivityCreated(savedInstanceState)
adapter = MessagesConversationAdapter(context)
recyclerView.adapter = adapter
recyclerView.layoutManager = FixedLinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
recyclerView.layoutManager = FixedLinearLayoutManager(context, LinearLayoutManager.VERTICAL, true)
loaderManager.initLoader(0, null, this)
}
@ -46,7 +46,7 @@ class MessagesConversationFragment : BaseFragment(), LoaderManager.LoaderCallbac
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.LOCAL_TIMESTAMP, true).sql
loader.sortOrder = OrderBy(Messages.SORT_ID, false).sql
return loader
}

View File

@ -61,7 +61,7 @@ class MessagesEntriesFragment : AbsContentListRecyclerViewFragment<MessagesEntri
loader.selection = Expression.inArgs(Conversations.ACCOUNT_KEY, accountKeys.size).sql
loader.selectionArgs = accountKeys.toStringArray()
loader.projection = Conversations.COLUMNS
loader.sortOrder = OrderBy(Conversations.LOCAL_TIMESTAMP, false).sql
loader.sortOrder = OrderBy(Conversations.SORT_ID, false).sql
return loader
}

View File

@ -1,5 +1,6 @@
package org.mariotaku.twidere.model.util
import android.support.annotation.FloatRange
import org.mariotaku.microblog.library.twitter.model.DirectMessage
import org.mariotaku.twidere.model.ParcelableMessage
import org.mariotaku.twidere.model.UserKey
@ -11,15 +12,23 @@ import org.mariotaku.twidere.util.InternalTwitterContentUtils
* Created by mariotaku on 2017/2/9.
*/
object ParcelableMessageUtils {
fun incomingMessage(accountKey: UserKey, message: DirectMessage): ParcelableMessage {
val result = message(accountKey, message)
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)
return result
}
fun outgoingMessage(accountKey: UserKey, message: DirectMessage): ParcelableMessage {
val result = message(accountKey, message)
fun outgoingMessage(
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 = true
result.conversation_id = outgoingConversationId(message.senderId, message.recipientId)
return result
@ -33,7 +42,11 @@ object ParcelableMessageUtils {
return "$senderId-$recipientId"
}
private fun message(accountKey: UserKey, message: DirectMessage): ParcelableMessage {
private fun message(
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
@ -41,6 +54,7 @@ object ParcelableMessageUtils {
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()
val (type, extras) = typeAndExtras(accountKey, message)
val (text, spans) = InternalTwitterContentUtils.formatDirectMessageText(message)

View File

@ -31,8 +31,10 @@ import org.mariotaku.twidere.util.content.ContentResolverUtils
* Created by mariotaku on 2017/2/8.
*/
class GetMessagesTask(context: Context) : BaseAbstractTask<RefreshTaskParam, Unit, (Boolean) -> Unit>(context) {
override fun doLongOperation(param: RefreshTaskParam) {
class GetMessagesTask(
context: Context
) : BaseAbstractTask<GetMessagesTask.RefreshMessagesTaskParam, Unit, (Boolean) -> Unit>(context) {
override fun doLongOperation(param: RefreshMessagesTaskParam) {
val accountKeys = param.accountKeys
val am = AccountManager.get(context)
accountKeys.forEachIndexed { i, accountKey ->
@ -121,13 +123,13 @@ class GetMessagesTask(context: Context) : BaseAbstractTask<RefreshTaskParam, Uni
conversations.addLocalConversations(accountKey, conversationIds)
received.forEach { dm ->
val message = ParcelableMessageUtils.incomingMessage(accountKey, dm)
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)
}
sent.forEach { dm ->
val message = ParcelableMessageUtils.outgoingMessage(accountKey, dm)
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)
}
@ -225,7 +227,6 @@ class GetMessagesTask(context: Context) : BaseAbstractTask<RefreshTaskParam, Uni
getAccountKeys: () -> Array<UserKey>
) : RefreshMessagesTaskParam(context, getAccountKeys) {
override val sinceIds: Array<String?>?
get() {
val keys = accounts.map { account ->
@ -252,7 +253,6 @@ class GetMessagesTask(context: Context) : BaseAbstractTask<RefreshTaskParam, Uni
getAccountKeys: () -> Array<UserKey>
) : RefreshMessagesTaskParam(context, getAccountKeys) {
override val maxIds: Array<String?>?
get() {
val keys = accounts.map { account ->
@ -279,6 +279,11 @@ class GetMessagesTask(context: Context) : BaseAbstractTask<RefreshTaskParam, Uni
val getAccountKeys: () -> Array<UserKey>
) : SimpleRefreshTaskParam() {
/**
* If `conversationId` has value, load messages in conversationId
*/
open var conversationId: String? = null
protected val accounts: Array<AccountDetails?> by lazy {
AccountUtils.getAllAccountDetails(AccountManager.get(context), accountKeys, false)
}

View File

@ -240,7 +240,7 @@ class AsyncTwitterWrapper(
TaskStarter.execute<Any, Unit, Any>(task)
}
fun getMessagesAsync(param: RefreshTaskParam) {
fun getMessagesAsync(param: GetMessagesTask.RefreshMessagesTaskParam) {
val task = GetMessagesTask(context)
task.params = param
TaskStarter.execute(task)
@ -293,9 +293,7 @@ class AsyncTwitterWrapper(
})
}
if (preferences.getBoolean(SharedPreferenceConstants.KEY_HOME_REFRESH_DIRECT_MESSAGES)) {
getMessagesAsync(object : SimpleRefreshTaskParam() {
override val accountKeys: Array<UserKey> by lazy { action() }
})
getMessagesAsync(GetMessagesTask.RefreshMessagesTaskParam(context, action))
}
if (preferences.getBoolean(SharedPreferenceConstants.KEY_HOME_REFRESH_SAVED_SEARCHES)) {
getSavedSearchesAsync(action())

View File

@ -1,6 +1,5 @@
package org.mariotaku.twidere.util
import android.annotation.SuppressLint
import android.content.Context
import android.text.TextUtils.isEmpty
import okhttp3.ConnectionPool
@ -34,7 +33,6 @@ object HttpClientFactory {
DebugModeUtils.initForOkHttpClient(builder)
}
@SuppressLint("SSLCertificateSocketFactoryGetInsecure")
internal fun updateHttpClientConfiguration(builder: OkHttpClient.Builder,
conf: HttpClientConfiguration, dns: Dns,
connectionPool: ConnectionPool) {

View File

@ -29,7 +29,8 @@ import org.mariotaku.twidere.model.ParcelableMessage
*/
abstract class AbsMessageViewHolder(itemView: View, val adapter: MessagesConversationAdapter) : RecyclerView.ViewHolder(itemView) {
open fun display(message: ParcelableMessage) {
open fun display(message: ParcelableMessage, showDate: Boolean) {
}
}

View File

@ -20,8 +20,10 @@
package org.mariotaku.twidere.view.holder.message
import android.support.v4.view.GravityCompat
import android.text.format.DateUtils
import android.view.View
import android.widget.FrameLayout
import android.widget.LinearLayout
import kotlinx.android.synthetic.main.list_item_message_conversation_text.view.*
import org.mariotaku.ktextension.isNullOrEmpty
import org.mariotaku.messagebubbleview.library.MessageBubbleView
@ -36,16 +38,32 @@ import org.mariotaku.twidere.model.ParcelableMessage
class MessageViewHolder(itemView: View, adapter: MessagesConversationAdapter) : AbsMessageViewHolder(itemView, adapter) {
private val date by lazy { itemView.date }
private val text by lazy { itemView.text }
private val time by lazy { itemView.time }
private val mediaPreview by lazy { itemView.mediaPreview }
private val messageContent by lazy { itemView.messageContent }
override fun display(message: ParcelableMessage) {
super.display(message)
init {
val textSize = adapter.textSize
text.textSize = textSize
time.textSize = textSize * 0.8f
date.textSize = textSize * 0.9f
}
override fun display(message: ParcelableMessage, showDate: Boolean) {
super.display(message, showDate)
setOutgoingStatus(messageContent, message.is_outgoing)
text.text = message.text_unescaped
time.time = message.timestamp
if (showDate) {
date.visibility = View.VISIBLE
date.text = DateUtils.getRelativeTimeSpanString(message.timestamp, System.currentTimeMillis(),
DateUtils.DAY_IN_MILLIS, DateUtils.FORMAT_SHOW_DATE)
} else {
date.visibility = View.GONE
}
time.text = DateUtils.formatDateTime(adapter.context, message.timestamp,
DateUtils.FORMAT_SHOW_TIME)
if (message.media.isNullOrEmpty()) {
mediaPreview.visibility = View.GONE
} else {
@ -69,6 +87,9 @@ class MessageViewHolder(itemView: View, adapter: MessagesConversationAdapter) :
is FrameLayout.LayoutParams -> {
lp.gravity = if (outgoing) GravityCompat.END else GravityCompat.START
}
is LinearLayout.LayoutParams -> {
lp.gravity = if (outgoing) GravityCompat.END else GravityCompat.START
}
}
}
}

View File

@ -35,8 +35,8 @@ class StickerMessageViewHolder(itemView: View, adapter: MessagesConversationAdap
private val messageContent by lazy { itemView.messageContent }
private val stickerIcon by lazy { itemView.stickerIcon }
override fun display(message: ParcelableMessage) {
super.display(message)
override fun display(message: ParcelableMessage, showDate: Boolean) {
super.display(message, showDate)
MessageViewHolder.setMessageContentGravity(messageContent, message.is_outgoing)
val extras = message.extras as StickerExtras
adapter.mediaLoader.displayStickerImage(stickerIcon, extras.url)

View File

@ -17,14 +17,25 @@
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<FrameLayout
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="@dimen/element_spacing_normal">
<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.messagebubbleview.library.MessageBubbleView
android:id="@+id/messageContent"
android:layout_width="wrap_content"
@ -63,18 +74,18 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary"
android:textColor="?android:attr/textColorPrimary"
tools:text="@string/sample_status_text"/>
<org.mariotaku.twidere.view.ShortTimeView
<org.mariotaku.twidere.view.FixedTextView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/element_spacing_small"
android:textColor="?android:attr/textColorSecondary"
android:textColor="?android:attr/textColorTertiary"
tools:text="12:00"/>
</LinearLayout>
</RelativeLayout>
</org.mariotaku.messagebubbleview.library.MessageBubbleView>
</FrameLayout>
</LinearLayout>