improved status conversation load
This commit is contained in:
parent
48c7c5fa99
commit
7e577b5957
|
@ -20,7 +20,6 @@
|
||||||
package org.mariotaku.twidere.fragment
|
package org.mariotaku.twidere.fragment
|
||||||
|
|
||||||
import android.accounts.AccountManager
|
import android.accounts.AccountManager
|
||||||
import android.app.Activity
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
|
@ -310,7 +309,8 @@ abstract class AbsActivitiesFragment protected constructor() :
|
||||||
val accountIds = arrayOf(activity.account_key)
|
val accountIds = arrayOf(activity.account_key)
|
||||||
val maxIds = arrayOf(activity.min_position)
|
val maxIds = arrayOf(activity.min_position)
|
||||||
val maxSortIds = longArrayOf(activity.min_sort_position)
|
val maxSortIds = longArrayOf(activity.min_sort_position)
|
||||||
getActivities(BaseRefreshTaskParam(accountIds, maxIds, null, maxSortIds, null))
|
getActivities(BaseRefreshTaskParam(accountKeys = accountIds, maxIds = maxIds,
|
||||||
|
sinceIds = null, maxSortIds = maxSortIds, sinceSortIds = null))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMediaClick(holder: IStatusViewHolder, view: View, media: ParcelableMedia, position: Int) {
|
override fun onMediaClick(holder: IStatusViewHolder, view: View, media: ParcelableMedia, position: Int) {
|
||||||
|
|
|
@ -359,7 +359,8 @@ abstract class AbsStatusesFragment : AbsContentListRecyclerViewFragment<Parcelab
|
||||||
val accountIds = arrayOf(status.account_key)
|
val accountIds = arrayOf(status.account_key)
|
||||||
val maxIds = arrayOf<String?>(status.id)
|
val maxIds = arrayOf<String?>(status.id)
|
||||||
val maxSortIds = longArrayOf(status.sort_id)
|
val maxSortIds = longArrayOf(status.sort_id)
|
||||||
getStatuses(BaseRefreshTaskParam(accountIds, maxIds, null, maxSortIds, null))
|
getStatuses(BaseRefreshTaskParam(accountKeys = accountIds, maxIds = maxIds, sinceIds = null,
|
||||||
|
maxSortIds = maxSortIds, sinceSortIds = null))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMediaClick(holder: IStatusViewHolder, view: View, media: ParcelableMedia, statusPosition: Int) {
|
override fun onMediaClick(holder: IStatusViewHolder, view: View, media: ParcelableMedia, statusPosition: Int) {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import org.mariotaku.kpreferences.get
|
||||||
import org.mariotaku.sqliteqb.library.OrderBy
|
import org.mariotaku.sqliteqb.library.OrderBy
|
||||||
import org.mariotaku.twidere.R
|
import org.mariotaku.twidere.R
|
||||||
import org.mariotaku.twidere.adapter.MessagesEntriesAdapter
|
import org.mariotaku.twidere.adapter.MessagesEntriesAdapter
|
||||||
|
import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter
|
||||||
import org.mariotaku.twidere.constant.newDocumentApiKey
|
import org.mariotaku.twidere.constant.newDocumentApiKey
|
||||||
import org.mariotaku.twidere.extension.model.user
|
import org.mariotaku.twidere.extension.model.user
|
||||||
import org.mariotaku.twidere.loader.ObjectCursorLoader
|
import org.mariotaku.twidere.loader.ObjectCursorLoader
|
||||||
|
@ -35,6 +36,7 @@ class MessagesEntriesFragment : AbsContentListRecyclerViewFragment<MessagesEntri
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onActivityCreated(savedInstanceState)
|
||||||
adapter.listener = this
|
adapter.listener = this
|
||||||
|
adapter.loadMoreSupportedPosition = ILoadMoreSupportAdapter.END
|
||||||
loaderManager.initLoader(0, null, this)
|
loaderManager.initLoader(0, null, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,6 +72,10 @@ class MessagesEntriesFragment : AbsContentListRecyclerViewFragment<MessagesEntri
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onLoadMoreContents(position: Long) {
|
||||||
|
super.onLoadMoreContents(position)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onConversationClick(position: Int) {
|
override fun onConversationClick(position: Int) {
|
||||||
val conversation = adapter.getConversation(position) ?: return
|
val conversation = adapter.getConversation(position) ?: return
|
||||||
IntentUtils.openMessageConversation(context, conversation.account_key, conversation.id)
|
IntentUtils.openMessageConversation(context, conversation.account_key, conversation.id)
|
||||||
|
|
|
@ -155,7 +155,9 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
|
||||||
val loader = ConversationLoader(activity, status, sinceId, maxId, sinceSortId, maxSortId,
|
val loader = ConversationLoader(activity, status, sinceId, maxId, sinceSortId, maxSortId,
|
||||||
adapter.getData(), true, loadingMore)
|
adapter.getData(), true, loadingMore)
|
||||||
// Setting comparator to null lets statuses sort ascending
|
// Setting comparator to null lets statuses sort ascending
|
||||||
loader.comparator = null
|
loader.comparator = Comparator { l, r ->
|
||||||
|
(l.sort_id - r.sort_id).toInt()
|
||||||
|
}
|
||||||
return loader
|
return loader
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1503,7 +1505,7 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
|
||||||
override val lightFont: Boolean
|
override val lightFont: Boolean
|
||||||
override val mediaPreviewEnabled: Boolean
|
override val mediaPreviewEnabled: Boolean
|
||||||
override val sensitiveContentEnabled: Boolean
|
override val sensitiveContentEnabled: Boolean
|
||||||
private val mShowCardActions: Boolean
|
private val showCardActions: Boolean
|
||||||
override val useStarsForLikes: Boolean
|
override val useStarsForLikes: Boolean
|
||||||
private var mDetailMediaExpanded: Boolean = false
|
private var mDetailMediaExpanded: Boolean = false
|
||||||
|
|
||||||
|
@ -1533,8 +1535,8 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
|
||||||
private var data: List<ParcelableStatus>? = null
|
private var data: List<ParcelableStatus>? = null
|
||||||
private var replyError: CharSequence? = null
|
private var replyError: CharSequence? = null
|
||||||
private var conversationError: CharSequence? = null
|
private var conversationError: CharSequence? = null
|
||||||
private var mReplyStart: Int = 0
|
private var replyStart: Int = 0
|
||||||
private var mShowingActionCardPosition: Int = 0
|
private var showingActionCardPosition: Int = 0
|
||||||
|
|
||||||
init {
|
init {
|
||||||
setHasStableIds(true)
|
setHasStableIds(true)
|
||||||
|
@ -1555,7 +1557,7 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
|
||||||
linkHighlightingStyle = preferences[linkHighlightOptionKey]
|
linkHighlightingStyle = preferences[linkHighlightOptionKey]
|
||||||
mediaPreviewEnabled = preferences[mediaPreviewKey]
|
mediaPreviewEnabled = preferences[mediaPreviewKey]
|
||||||
sensitiveContentEnabled = preferences.getBoolean(SharedPreferenceConstants.KEY_DISPLAY_SENSITIVE_CONTENTS, false)
|
sensitiveContentEnabled = preferences.getBoolean(SharedPreferenceConstants.KEY_DISPLAY_SENSITIVE_CONTENTS, false)
|
||||||
mShowCardActions = !preferences[hideCardActionsKey]
|
showCardActions = !preferences[hideCardActionsKey]
|
||||||
useStarsForLikes = preferences[iWantMyStarsBackKey]
|
useStarsForLikes = preferences[iWantMyStarsBackKey]
|
||||||
val listener = StatusAdapterLinkClickHandler<List<ParcelableStatus>>(context, preferences)
|
val listener = StatusAdapterLinkClickHandler<List<ParcelableStatus>>(context, preferences)
|
||||||
listener.setAdapter(this)
|
listener.setAdapter(this)
|
||||||
|
@ -1570,9 +1572,9 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
|
||||||
return data!![position - getIndexStart(ITEM_IDX_CONVERSATION)]
|
return data!![position - getIndexStart(ITEM_IDX_CONVERSATION)]
|
||||||
}
|
}
|
||||||
ITEM_IDX_REPLY -> {
|
ITEM_IDX_REPLY -> {
|
||||||
if (data == null || mReplyStart < 0) return null
|
if (data == null || replyStart < 0) return null
|
||||||
return data!![position - getIndexStart(ITEM_IDX_CONVERSATION)
|
return data!![position - getIndexStart(ITEM_IDX_CONVERSATION)
|
||||||
- getTypeCount(ITEM_IDX_CONVERSATION) - getTypeCount(ITEM_IDX_STATUS) + mReplyStart]
|
- getTypeCount(ITEM_IDX_CONVERSATION) - getTypeCount(ITEM_IDX_STATUS) + replyStart]
|
||||||
}
|
}
|
||||||
ITEM_IDX_STATUS -> {
|
ITEM_IDX_STATUS -> {
|
||||||
return status
|
return status
|
||||||
|
@ -1622,15 +1624,15 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isCardActionsShown(position: Int): Boolean {
|
override fun isCardActionsShown(position: Int): Boolean {
|
||||||
if (position == RecyclerView.NO_POSITION) return mShowCardActions
|
if (position == RecyclerView.NO_POSITION) return showCardActions
|
||||||
return mShowCardActions || mShowingActionCardPosition == position
|
return showCardActions || showingActionCardPosition == position
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showCardActions(position: Int) {
|
override fun showCardActions(position: Int) {
|
||||||
if (mShowingActionCardPosition != RecyclerView.NO_POSITION) {
|
if (showingActionCardPosition != RecyclerView.NO_POSITION) {
|
||||||
notifyItemChanged(mShowingActionCardPosition)
|
notifyItemChanged(showingActionCardPosition)
|
||||||
}
|
}
|
||||||
mShowingActionCardPosition = position
|
showingActionCardPosition = position
|
||||||
if (position != RecyclerView.NO_POSITION) {
|
if (position != RecyclerView.NO_POSITION) {
|
||||||
notifyItemChanged(position)
|
notifyItemChanged(position)
|
||||||
}
|
}
|
||||||
|
@ -1638,12 +1640,12 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
|
||||||
|
|
||||||
override fun setData(data: List<ParcelableStatus>?): Boolean {
|
override fun setData(data: List<ParcelableStatus>?): Boolean {
|
||||||
val status = this.status ?: return false
|
val status = this.status ?: return false
|
||||||
val changed = !CompareUtils.objectEquals(data, data)
|
val changed = this.data != data
|
||||||
this.data = data
|
this.data = data
|
||||||
if (data == null || data.isEmpty()) {
|
if (data == null || data.isEmpty()) {
|
||||||
setTypeCount(ITEM_IDX_CONVERSATION, 0)
|
setTypeCount(ITEM_IDX_CONVERSATION, 0)
|
||||||
setTypeCount(ITEM_IDX_REPLY, 0)
|
setTypeCount(ITEM_IDX_REPLY, 0)
|
||||||
mReplyStart = -1
|
replyStart = -1
|
||||||
} else {
|
} else {
|
||||||
var sortId = status.sort_id
|
var sortId = status.sort_id
|
||||||
if (status.is_retweet) {
|
if (status.is_retweet) {
|
||||||
|
@ -1657,8 +1659,7 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
|
||||||
var conversationCount = 0
|
var conversationCount = 0
|
||||||
var replyCount = 0
|
var replyCount = 0
|
||||||
var replyStart = -1
|
var replyStart = -1
|
||||||
for (i in 0 until data.size) {
|
data.forEachIndexed { i, item ->
|
||||||
val item = data[i]
|
|
||||||
if (item.sort_id < sortId) {
|
if (item.sort_id < sortId) {
|
||||||
conversationCount++
|
conversationCount++
|
||||||
} else if (item.sort_id > sortId && status.id != item.id) {
|
} else if (item.sort_id > sortId && status.id != item.id) {
|
||||||
|
@ -1670,7 +1671,7 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
|
||||||
}
|
}
|
||||||
setTypeCount(ITEM_IDX_CONVERSATION, conversationCount)
|
setTypeCount(ITEM_IDX_CONVERSATION, conversationCount)
|
||||||
setTypeCount(ITEM_IDX_REPLY, replyCount)
|
setTypeCount(ITEM_IDX_REPLY, replyCount)
|
||||||
mReplyStart = replyStart
|
this.replyStart = replyStart
|
||||||
}
|
}
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
updateItemDecoration()
|
updateItemDecoration()
|
||||||
|
|
|
@ -7,15 +7,11 @@ open class BaseRefreshTaskParam(
|
||||||
override val accountKeys: Array<UserKey>,
|
override val accountKeys: Array<UserKey>,
|
||||||
override val maxIds: Array<String?>?,
|
override val maxIds: Array<String?>?,
|
||||||
override val sinceIds: Array<String?>?,
|
override val sinceIds: Array<String?>?,
|
||||||
|
override val cursors: Array<String?>? = null,
|
||||||
override val maxSortIds: LongArray? = null,
|
override val maxSortIds: LongArray? = null,
|
||||||
override val sinceSortIds: LongArray? = null
|
override val sinceSortIds: LongArray? = null
|
||||||
) : RefreshTaskParam {
|
) : RefreshTaskParam {
|
||||||
override var isLoadingMore: Boolean = false
|
override var isLoadingMore: Boolean = false
|
||||||
override var shouldAbort: Boolean = false
|
override var shouldAbort: Boolean = false
|
||||||
|
|
||||||
override val hasMaxIds: Boolean
|
|
||||||
get() = maxIds != null
|
|
||||||
|
|
||||||
override val hasSinceIds: Boolean
|
|
||||||
get() = sinceIds != null
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,13 +10,20 @@ interface RefreshTaskParam {
|
||||||
|
|
||||||
val sinceIds: Array<String?>?
|
val sinceIds: Array<String?>?
|
||||||
|
|
||||||
|
val cursors: Array<String?>?
|
||||||
|
|
||||||
val maxSortIds: LongArray?
|
val maxSortIds: LongArray?
|
||||||
|
|
||||||
val sinceSortIds: LongArray?
|
val sinceSortIds: LongArray?
|
||||||
|
|
||||||
val hasMaxIds: Boolean
|
val hasMaxIds: Boolean
|
||||||
|
get() = maxIds != null
|
||||||
|
|
||||||
val hasSinceIds: Boolean
|
val hasSinceIds: Boolean
|
||||||
|
get() = sinceIds != null
|
||||||
|
|
||||||
|
val hasCursors: Boolean
|
||||||
|
get() = cursors != null
|
||||||
|
|
||||||
val isLoadingMore: Boolean
|
val isLoadingMore: Boolean
|
||||||
|
|
||||||
|
|
|
@ -22,11 +22,8 @@ abstract class SimpleRefreshTaskParam : RefreshTaskParam {
|
||||||
override val sinceIds: Array<String?>?
|
override val sinceIds: Array<String?>?
|
||||||
get() = null
|
get() = null
|
||||||
|
|
||||||
override val hasMaxIds: Boolean
|
override val cursors: Array<String?>?
|
||||||
get() = maxIds != null
|
get() = null
|
||||||
|
|
||||||
override val hasSinceIds: Boolean
|
|
||||||
get() = sinceIds != null
|
|
||||||
|
|
||||||
override val sinceSortIds: LongArray?
|
override val sinceSortIds: LongArray?
|
||||||
get() = null
|
get() = null
|
||||||
|
|
|
@ -20,7 +20,6 @@ import org.mariotaku.twidere.model.util.AccountUtils.getAccountDetails
|
||||||
import org.mariotaku.twidere.model.util.ParcelableMessageUtils
|
import org.mariotaku.twidere.model.util.ParcelableMessageUtils
|
||||||
import org.mariotaku.twidere.model.util.ParcelableUserUtils
|
import org.mariotaku.twidere.model.util.ParcelableUserUtils
|
||||||
import org.mariotaku.twidere.model.util.UserKeyUtils
|
import org.mariotaku.twidere.model.util.UserKeyUtils
|
||||||
import org.mariotaku.twidere.provider.TwidereDataStore.AccountSupportColumns
|
|
||||||
import org.mariotaku.twidere.provider.TwidereDataStore.Messages
|
import org.mariotaku.twidere.provider.TwidereDataStore.Messages
|
||||||
import org.mariotaku.twidere.provider.TwidereDataStore.Messages.Conversations
|
import org.mariotaku.twidere.provider.TwidereDataStore.Messages.Conversations
|
||||||
import org.mariotaku.twidere.util.content.ContentResolverUtils
|
import org.mariotaku.twidere.util.content.ContentResolverUtils
|
||||||
|
@ -37,7 +36,7 @@ class GetMessagesTask(context: Context) : BaseAbstractTask<RefreshTaskParam, Uni
|
||||||
val details = getAccountDetails(am, accountKey, true) ?: return@forEachIndexed
|
val details = getAccountDetails(am, accountKey, true) ?: return@forEachIndexed
|
||||||
val microBlog = details.newMicroBlogInstance(context, true, cls = MicroBlog::class.java)
|
val microBlog = details.newMicroBlogInstance(context, true, cls = MicroBlog::class.java)
|
||||||
val messages = try {
|
val messages = try {
|
||||||
getMessages(microBlog, details)
|
getMessages(microBlog, details, param, i)
|
||||||
} catch (e: MicroBlogException) {
|
} catch (e: MicroBlogException) {
|
||||||
return@forEachIndexed
|
return@forEachIndexed
|
||||||
}
|
}
|
||||||
|
@ -49,7 +48,7 @@ class GetMessagesTask(context: Context) : BaseAbstractTask<RefreshTaskParam, Uni
|
||||||
callback?.invoke(true)
|
callback?.invoke(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getMessages(microBlog: MicroBlog, details: AccountDetails): GetMessagesData {
|
private fun getMessages(microBlog: MicroBlog, details: AccountDetails, param: RefreshTaskParam, index: Int): GetMessagesData {
|
||||||
when (details.type) {
|
when (details.type) {
|
||||||
AccountType.FANFOU -> {
|
AccountType.FANFOU -> {
|
||||||
// Use fanfou DM api
|
// Use fanfou DM api
|
||||||
|
@ -58,32 +57,37 @@ class GetMessagesTask(context: Context) : BaseAbstractTask<RefreshTaskParam, Uni
|
||||||
AccountType.TWITTER -> {
|
AccountType.TWITTER -> {
|
||||||
// Use official DM api
|
// Use official DM api
|
||||||
if (details.isOfficial(context)) {
|
if (details.isOfficial(context)) {
|
||||||
return getTwitterOfficialMessages(microBlog, details)
|
return getTwitterOfficialMessages(microBlog, details, param, index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Use default method
|
// Use default method
|
||||||
return getDefaultMessages(microBlog, details)
|
return getDefaultMessages(microBlog, details, param, index)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getFanfouMessages(microBlog: MicroBlog): GetMessagesData {
|
private fun getFanfouMessages(microBlog: MicroBlog): GetMessagesData {
|
||||||
return GetMessagesData(emptyList(), emptyList())
|
return GetMessagesData(emptyList(), emptyList())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getTwitterOfficialMessages(microBlog: MicroBlog, details: AccountDetails): GetMessagesData {
|
private fun getTwitterOfficialMessages(microBlog: MicroBlog, details: AccountDetails, param: RefreshTaskParam, index: Int): GetMessagesData {
|
||||||
return getDefaultMessages(microBlog, details)
|
return getDefaultMessages(microBlog, details, param, index)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getDefaultMessages(microBlog: MicroBlog, details: AccountDetails): GetMessagesData {
|
private fun getDefaultMessages(microBlog: MicroBlog, details: AccountDetails, param: RefreshTaskParam, index: Int): GetMessagesData {
|
||||||
val accountKey = details.key
|
val accountKey = details.key
|
||||||
val paging = Paging()
|
|
||||||
|
|
||||||
|
val received = microBlog.getDirectMessages(Paging().apply {
|
||||||
|
count(100)
|
||||||
|
})
|
||||||
|
val sent = microBlog.getSentDirectMessages(Paging().apply {
|
||||||
|
count(100)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
val insertMessages = arrayListOf<ParcelableMessage>()
|
val insertMessages = arrayListOf<ParcelableMessage>()
|
||||||
val conversations = hashMapOf<String, ParcelableMessageConversation>()
|
val conversations = hashMapOf<String, ParcelableMessageConversation>()
|
||||||
|
|
||||||
|
|
||||||
val received = microBlog.getDirectMessages(paging)
|
|
||||||
val sent = microBlog.getSentDirectMessages(paging)
|
|
||||||
|
|
||||||
val conversationIds = hashSetOf<String>()
|
val conversationIds = hashSetOf<String>()
|
||||||
received.forEach {
|
received.forEach {
|
||||||
conversationIds.add(ParcelableMessageUtils.incomingConversationId(it.senderId, it.recipientId))
|
conversationIds.add(ParcelableMessageUtils.incomingConversationId(it.senderId, it.recipientId))
|
||||||
|
@ -135,10 +139,6 @@ class GetMessagesTask(context: Context) : BaseAbstractTask<RefreshTaskParam, Uni
|
||||||
|
|
||||||
private fun storeMessages(data: GetMessagesData, details: AccountDetails) {
|
private fun storeMessages(data: GetMessagesData, details: AccountDetails) {
|
||||||
val resolver = context.contentResolver
|
val resolver = context.contentResolver
|
||||||
val where = Expression.equalsArgs(AccountSupportColumns.ACCOUNT_KEY).sql
|
|
||||||
val whereArgs = arrayOf(details.key.toString())
|
|
||||||
resolver.delete(Messages.CONTENT_URI, where, whereArgs)
|
|
||||||
resolver.delete(Conversations.CONTENT_URI, where, whereArgs)
|
|
||||||
val conversationsValues = data.conversations.map {
|
val conversationsValues = data.conversations.map {
|
||||||
val values = ParcelableMessageConversationValuesCreator.create(it)
|
val values = ParcelableMessageConversationValuesCreator.create(it)
|
||||||
if (it._id > 0) {
|
if (it._id > 0) {
|
||||||
|
|
Loading…
Reference in New Issue