parent
7522bf04eb
commit
f665318eb6
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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>
|
Loading…
Reference in New Issue