removed some AbsTask implementations

This commit is contained in:
Mariotaku Lee 2017-11-12 10:51:33 +08:00
parent 9321bb1cc6
commit 67c086b545
No known key found for this signature in database
GPG Key ID: 15C10F89D7C33535
7 changed files with 95 additions and 338 deletions

View File

@ -52,7 +52,6 @@ import nl.komponents.kovenant.task
import nl.komponents.kovenant.then import nl.komponents.kovenant.then
import nl.komponents.kovenant.ui.alwaysUi import nl.komponents.kovenant.ui.alwaysUi
import nl.komponents.kovenant.ui.successUi import nl.komponents.kovenant.ui.successUi
import org.mariotaku.abstask.library.TaskStarter
import org.mariotaku.chameleon.Chameleon import org.mariotaku.chameleon.Chameleon
import org.mariotaku.chameleon.ChameleonUtils import org.mariotaku.chameleon.ChameleonUtils
import org.mariotaku.kpreferences.get import org.mariotaku.kpreferences.get
@ -93,7 +92,6 @@ import org.mariotaku.twidere.promise.ConversationPromises
import org.mariotaku.twidere.promise.MessagePromises import org.mariotaku.twidere.promise.MessagePromises
import org.mariotaku.twidere.provider.TwidereDataStore.Messages.Conversations import org.mariotaku.twidere.provider.TwidereDataStore.Messages.Conversations
import org.mariotaku.twidere.task.status.UpdateStatusTask import org.mariotaku.twidere.task.status.UpdateStatusTask
import org.mariotaku.twidere.task.twitter.message.AddParticipantsTask
import org.mariotaku.twidere.util.IntentUtils import org.mariotaku.twidere.util.IntentUtils
import org.mariotaku.twidere.view.holder.SimpleUserViewHolder import org.mariotaku.twidere.view.holder.SimpleUserViewHolder
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
@ -318,15 +316,13 @@ class MessageConversationInfoFragment : BaseFragment(), IToolBarSupportFragment,
private fun performAddParticipant(user: ParcelableUser) { private fun performAddParticipant(user: ParcelableUser) {
ProgressDialogFragment.show(childFragmentManager, "add_participant_progress") ProgressDialogFragment.show(childFragmentManager, "add_participant_progress")
val weakThis = WeakReference(this) val weakThis by weak(this)
val task = AddParticipantsTask(context, accountKey, conversationId, listOf(user)) ConversationPromises.getInstance(context).addParticipants(accountKey,
task.callback = callback@ { succeed -> conversationId, listOf(user)).alwaysUi {
val f = weakThis.get() ?: return@callback weakThis?.dismissDialogThen("add_participant_progress") {
f.dismissDialogThen("add_participant_progress") {
loaderManager.restartLoader(0, null, this) loaderManager.restartLoader(0, null, this)
} }
} }
TaskStarter.execute(task)
} }
private fun performSetNotificationDisabled(disabled: Boolean) { private fun performSetNotificationDisabled(disabled: Boolean) {

View File

@ -24,13 +24,20 @@ import android.app.Application
import android.content.Context import android.content.Context
import nl.komponents.kovenant.Promise import nl.komponents.kovenant.Promise
import nl.komponents.kovenant.task import nl.komponents.kovenant.task
import org.mariotaku.ktextension.mapToArray
import org.mariotaku.microblog.library.MicroBlog import org.mariotaku.microblog.library.MicroBlog
import org.mariotaku.microblog.library.MicroBlogException
import org.mariotaku.twidere.R
import org.mariotaku.twidere.annotation.AccountType import org.mariotaku.twidere.annotation.AccountType
import org.mariotaku.twidere.exception.AccountNotFoundException import org.mariotaku.twidere.exception.AccountNotFoundException
import org.mariotaku.twidere.extension.getDetailsOrThrow
import org.mariotaku.twidere.extension.model.addParticipants
import org.mariotaku.twidere.extension.model.isOfficial import org.mariotaku.twidere.extension.model.isOfficial
import org.mariotaku.twidere.extension.model.newMicroBlogInstance import org.mariotaku.twidere.extension.model.newMicroBlogInstance
import org.mariotaku.twidere.extension.model.notificationDisabled import org.mariotaku.twidere.extension.model.notificationDisabled
import org.mariotaku.twidere.model.AccountDetails import org.mariotaku.twidere.model.AccountDetails
import org.mariotaku.twidere.model.ParcelableMessageConversation
import org.mariotaku.twidere.model.ParcelableUser
import org.mariotaku.twidere.model.UserKey import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.model.util.AccountUtils import org.mariotaku.twidere.model.util.AccountUtils
import org.mariotaku.twidere.task.twitter.message.GetMessagesTask import org.mariotaku.twidere.task.twitter.message.GetMessagesTask
@ -39,6 +46,8 @@ import org.mariotaku.twidere.util.SingletonHolder
class ConversationPromises private constructor(private val application: Application) { class ConversationPromises private constructor(private val application: Application) {
private val profileImageSize: String = application.getString(R.string.profile_image_size)
fun setNotificationDisabled(accountKey: UserKey, conversationId: String, fun setNotificationDisabled(accountKey: UserKey, conversationId: String,
notificationDisabled: Boolean): Promise<Boolean, Exception> = task { notificationDisabled: Boolean): Promise<Boolean, Exception> = task {
val account = AccountUtils.getAccountDetails(AccountManager.get(application), val account = AccountUtils.getAccountDetails(AccountManager.get(application),
@ -48,6 +57,44 @@ class ConversationPromises private constructor(private val application: Applicat
return@task true return@task true
} }
fun addParticipants(accountKey: UserKey, conversationId: String,
participants: Collection<ParcelableUser>): Promise<Boolean, Exception> = task {
val account = AccountManager.get(application).getDetailsOrThrow(accountKey, true)
val conversation = DataStoreUtils.findMessageConversation(application, accountKey, conversationId)
if (conversation != null && conversation.is_temp) {
val addData = GetMessagesTask.DatabaseUpdateData(listOf(conversation), emptyList())
conversation.addParticipants(participants)
GetMessagesTask.storeMessages(application, addData, account, showNotification = false)
return@task true
}
val addData = requestAddParticipants(account, conversationId, conversation, participants)
GetMessagesTask.storeMessages(application, addData, account, showNotification = false)
return@task true
}
private fun requestAddParticipants(account: AccountDetails, conversationId: String,
conversation: ParcelableMessageConversation?, participants: Collection<ParcelableUser>):
GetMessagesTask.DatabaseUpdateData {
when (account.type) {
AccountType.TWITTER -> {
if (account.isOfficial(application)) {
val microBlog = account.newMicroBlogInstance(application, cls = MicroBlog::class.java)
val ids = participants.mapToArray { it.key.id }
val response = microBlog.addParticipants(conversationId, ids)
if (conversation != null) {
conversation.addParticipants(participants)
return GetMessagesTask.DatabaseUpdateData(listOf(conversation), emptyList())
}
return GetMessagesTask.createDatabaseUpdateData(application, account, response,
profileImageSize)
}
}
}
throw MicroBlogException("Adding participants is not supported")
}
private fun requestSetNotificationDisabled(account: AccountDetails, private fun requestSetNotificationDisabled(account: AccountDetails,
conversationId: String, notificationDisabled: Boolean): conversationId: String, notificationDisabled: Boolean):
GetMessagesTask.DatabaseUpdateData { GetMessagesTask.DatabaseUpdateData {

View File

@ -28,10 +28,14 @@ import com.squareup.otto.Bus
import nl.komponents.kovenant.Promise import nl.komponents.kovenant.Promise
import nl.komponents.kovenant.task import nl.komponents.kovenant.task
import nl.komponents.kovenant.ui.successUi import nl.komponents.kovenant.ui.successUi
import org.mariotaku.ktextension.forEachRow
import org.mariotaku.library.objectcursor.ObjectCursor
import org.mariotaku.microblog.library.MicroBlog import org.mariotaku.microblog.library.MicroBlog
import org.mariotaku.microblog.library.MicroBlogException import org.mariotaku.microblog.library.MicroBlogException
import org.mariotaku.sqliteqb.library.Columns
import org.mariotaku.sqliteqb.library.Expression import org.mariotaku.sqliteqb.library.Expression
import org.mariotaku.sqliteqb.library.OrderBy import org.mariotaku.sqliteqb.library.OrderBy
import org.mariotaku.sqliteqb.library.Table
import org.mariotaku.twidere.annotation.AccountType import org.mariotaku.twidere.annotation.AccountType
import org.mariotaku.twidere.extension.getDetailsOrThrow import org.mariotaku.twidere.extension.getDetailsOrThrow
import org.mariotaku.twidere.extension.model.isOfficial import org.mariotaku.twidere.extension.model.isOfficial
@ -47,11 +51,9 @@ import org.mariotaku.twidere.model.event.UnreadCountUpdatedEvent
import org.mariotaku.twidere.model.message.conversation.TwitterOfficialConversationExtras import org.mariotaku.twidere.model.message.conversation.TwitterOfficialConversationExtras
import org.mariotaku.twidere.provider.TwidereDataStore.Messages import org.mariotaku.twidere.provider.TwidereDataStore.Messages
import org.mariotaku.twidere.task.twitter.message.SendMessageTask import org.mariotaku.twidere.task.twitter.message.SendMessageTask
import org.mariotaku.twidere.util.DataStoreUtils import org.mariotaku.twidere.util.*
import org.mariotaku.twidere.util.SingletonHolder
import org.mariotaku.twidere.util.content.ContentResolverUtils import org.mariotaku.twidere.util.content.ContentResolverUtils
import org.mariotaku.twidere.util.dagger.GeneralComponent import org.mariotaku.twidere.util.dagger.GeneralComponent
import org.mariotaku.twidere.util.updateItems
import javax.inject.Inject import javax.inject.Inject
class MessagePromises private constructor(private val application: Application) { class MessagePromises private constructor(private val application: Application) {
@ -130,7 +132,7 @@ class MessagePromises private constructor(private val application: Application)
val microBlog = account.newMicroBlogInstance(application, cls = MicroBlog::class.java) val microBlog = account.newMicroBlogInstance(application, cls = MicroBlog::class.java)
val conversation = DataStoreUtils.findMessageConversation(application, accountKey, conversationId) val conversation = DataStoreUtils.findMessageConversation(application, accountKey, conversationId)
val lastReadEvent = conversation?.let { val lastReadEvent = conversation?.let {
return@let performMarkRead(microBlog, account, conversation) return@let performMarkRead(account, conversation)
} ?: return@task false } ?: return@task false
updateLocalLastRead(application.contentResolver, accountKey, conversationId, lastReadEvent) updateLocalLastRead(application.contentResolver, accountKey, conversationId, lastReadEvent)
return@task true return@task true
@ -138,6 +140,39 @@ class MessagePromises private constructor(private val application: Application)
bus.post(UnreadCountUpdatedEvent(-1)) bus.post(UnreadCountUpdatedEvent(-1))
} }
fun batchMarkRead(accountKey: UserKey, markTimestampBefore: Long): Promise<Boolean, Exception> = task {
val cr = application.contentResolver
val projection = (Messages.Conversations.COLUMNS + Messages.Conversations.UNREAD_COUNT).map {
TwidereQueryBuilder.mapConversationsProjection(it)
}.toTypedArray()
val unreadWhere = Expression.greaterThan(Columns.Column(Table(Messages.Conversations.TABLE_NAME),
Messages.Conversations.LAST_READ_TIMESTAMP), markTimestampBefore)
val unreadHaving = Expression.greaterThan(Messages.Conversations.UNREAD_COUNT, 0)
val cRef = cr.getUnreadMessagesEntriesCursorReference(projection, arrayOf(accountKey),
unreadWhere, null, unreadHaving, null) ?: return@task false
val account = AccountManager.get(application).getDetailsOrThrow(accountKey, true)
cRef.use { (cur) ->
val indices = ObjectCursor.indicesFrom(cur, ParcelableMessageConversation::class.java)
cur.forEachRow { c, _ ->
val conversation = indices.newObject(c)
try {
val lastReadEvent = performMarkRead(account, conversation) ?: return@forEachRow false
updateLocalLastRead(cr, account.key, conversation.id,
lastReadEvent)
return@forEachRow true
} catch (e: MicroBlogException) {
return@forEachRow false
}
}
}
return@task true
}.successUi {
bus.post(UnreadCountUpdatedEvent(-1))
}
private fun clearMessagesSync(account: AccountDetails, conversationId: String): Boolean { private fun clearMessagesSync(account: AccountDetails, conversationId: String): Boolean {
val messagesWhere = Expression.and(Expression.equalsArgs(Messages.ACCOUNT_KEY), val messagesWhere = Expression.and(Expression.equalsArgs(Messages.ACCOUNT_KEY),
Expression.equalsArgs(Messages.CONVERSATION_ID)).sql Expression.equalsArgs(Messages.CONVERSATION_ID)).sql
@ -206,11 +241,11 @@ class MessagePromises private constructor(private val application: Application)
} }
@Throws(MicroBlogException::class) @Throws(MicroBlogException::class)
internal fun performMarkRead(microBlog: MicroBlog, account: AccountDetails, private fun performMarkRead(account: AccountDetails, conversation: ParcelableMessageConversation): Pair<String, Long>? {
conversation: ParcelableMessageConversation): Pair<String, Long>? {
val cr = application.contentResolver val cr = application.contentResolver
when (account.type) { when (account.type) {
AccountType.TWITTER -> { AccountType.TWITTER -> {
val microBlog = account.newMicroBlogInstance(application, cls = MicroBlog::class.java)
if (account.isOfficial(application)) { if (account.isOfficial(application)) {
val event = (conversation.conversation_extras as? TwitterOfficialConversationExtras)?.maxReadEvent ?: run { val event = (conversation.conversation_extras as? TwitterOfficialConversationExtras)?.maxReadEvent ?: run {
val message = cr.findRecentMessage(account.key, conversation.id) ?: return null val message = cr.findRecentMessage(account.key, conversation.id) ?: return null
@ -230,7 +265,7 @@ class MessagePromises private constructor(private val application: Application)
return Pair(message.id, message.timestamp) return Pair(message.id, message.timestamp)
} }
internal fun updateLocalLastRead(cr: ContentResolver, accountKey: UserKey, private fun updateLocalLastRead(cr: ContentResolver, accountKey: UserKey,
conversationId: String, lastRead: Pair<String, Long>) { conversationId: String, lastRead: Pair<String, Long>) {
val values = ContentValues() val values = ContentValues()
values.put(Messages.Conversations.LAST_READ_ID, lastRead.first) values.put(Messages.Conversations.LAST_READ_ID, lastRead.first)

View File

@ -22,7 +22,6 @@ package org.mariotaku.twidere.receiver
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import org.mariotaku.abstask.library.TaskStarter
import org.mariotaku.kpreferences.set import org.mariotaku.kpreferences.set
import org.mariotaku.ktextension.toLongOr import org.mariotaku.ktextension.toLongOr
import org.mariotaku.twidere.TwidereConstants.* import org.mariotaku.twidere.TwidereConstants.*
@ -31,7 +30,7 @@ import org.mariotaku.twidere.annotation.ReadPositionTag
import org.mariotaku.twidere.constant.IntentConstants.BROADCAST_NOTIFICATION_DELETED import org.mariotaku.twidere.constant.IntentConstants.BROADCAST_NOTIFICATION_DELETED
import org.mariotaku.twidere.constant.promotionsEnabledKey import org.mariotaku.twidere.constant.promotionsEnabledKey
import org.mariotaku.twidere.model.UserKey import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.task.twitter.message.BatchMarkMessageReadTask import org.mariotaku.twidere.promise.MessagePromises
import org.mariotaku.twidere.util.Utils import org.mariotaku.twidere.util.Utils
import org.mariotaku.twidere.util.dagger.DependencyHolder import org.mariotaku.twidere.util.dagger.DependencyHolder
@ -77,9 +76,8 @@ class NotificationReceiver : BroadcastReceiver() {
NotificationType.DIRECT_MESSAGES -> { NotificationType.DIRECT_MESSAGES -> {
if (accountKey == null) return if (accountKey == null) return
val appContext = context.applicationContext val appContext = context.applicationContext
val task = BatchMarkMessageReadTask(appContext, accountKey, MessagePromises.getInstance(appContext).batchMarkRead(accountKey,
paramReadPosition.toLongOr(-1L)) paramReadPosition.toLongOr(-1L))
TaskStarter.execute(task)
} }
} }
} }

View File

@ -1,97 +0,0 @@
/*
* 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.task.twitter.message
import android.accounts.AccountManager
import android.content.Context
import org.mariotaku.ktextension.mapToArray
import org.mariotaku.microblog.library.MicroBlog
import org.mariotaku.microblog.library.MicroBlogException
import org.mariotaku.twidere.R
import org.mariotaku.twidere.annotation.AccountType
import org.mariotaku.twidere.extension.getDetailsOrThrow
import org.mariotaku.twidere.extension.model.addParticipants
import org.mariotaku.twidere.extension.model.isOfficial
import org.mariotaku.twidere.extension.model.newMicroBlogInstance
import org.mariotaku.twidere.model.AccountDetails
import org.mariotaku.twidere.model.ParcelableMessageConversation
import org.mariotaku.twidere.model.ParcelableUser
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.task.ExceptionHandlingAbstractTask
import org.mariotaku.twidere.util.DataStoreUtils
/**
* Created by mariotaku on 2017/2/25.
*/
class AddParticipantsTask(
context: Context,
val accountKey: UserKey,
val conversationId: String,
val participants: Collection<ParcelableUser>
) : ExceptionHandlingAbstractTask<Unit?, Boolean, MicroBlogException, ((Boolean) -> Unit)?>(context) {
private val profileImageSize: String = context.getString(R.string.profile_image_size)
override val exceptionClass = MicroBlogException::class.java
override fun onExecute(params: Unit?): Boolean {
val account = AccountManager.get(context).getDetailsOrThrow(accountKey, true)
val conversation = DataStoreUtils.findMessageConversation(context, accountKey, conversationId)
if (conversation != null && conversation.is_temp) {
val addData = GetMessagesTask.DatabaseUpdateData(listOf(conversation), emptyList())
conversation.addParticipants(participants)
GetMessagesTask.storeMessages(context, addData, account, showNotification = false)
// Don't finish too fast
Thread.sleep(300L)
return true
}
val addData = requestAddParticipants(account, conversation)
GetMessagesTask.storeMessages(context, addData, account, showNotification = false)
return true
}
override fun afterExecute(callback: ((Boolean) -> Unit)?, result: Boolean?, exception: MicroBlogException?) {
callback?.invoke(result ?: false)
}
private fun requestAddParticipants(account: AccountDetails, conversation: ParcelableMessageConversation?):
GetMessagesTask.DatabaseUpdateData {
when (account.type) {
AccountType.TWITTER -> {
if (account.isOfficial(context)) {
val microBlog = account.newMicroBlogInstance(context, cls = MicroBlog::class.java)
val ids = participants.mapToArray { it.key.id }
val response = microBlog.addParticipants(conversationId, ids)
if (conversation != null) {
conversation.addParticipants(participants)
return GetMessagesTask.DatabaseUpdateData(listOf(conversation), emptyList())
}
return GetMessagesTask.createDatabaseUpdateData(context, account, response,
profileImageSize)
}
}
}
throw MicroBlogException("Adding participants is not supported")
}
}

View File

@ -1,89 +0,0 @@
/*
* 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.task.twitter.message
import android.accounts.AccountManager
import android.content.Context
import org.mariotaku.ktextension.forEachRow
import org.mariotaku.library.objectcursor.ObjectCursor
import org.mariotaku.microblog.library.MicroBlog
import org.mariotaku.microblog.library.MicroBlogException
import org.mariotaku.sqliteqb.library.Columns
import org.mariotaku.sqliteqb.library.Expression
import org.mariotaku.sqliteqb.library.Table
import org.mariotaku.twidere.extension.model.newMicroBlogInstance
import org.mariotaku.twidere.model.ParcelableMessageConversation
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.model.event.UnreadCountUpdatedEvent
import org.mariotaku.twidere.model.util.AccountUtils
import org.mariotaku.twidere.provider.TwidereDataStore.Messages.Conversations
import org.mariotaku.twidere.task.ExceptionHandlingAbstractTask
import org.mariotaku.twidere.util.TwidereQueryBuilder
import org.mariotaku.twidere.util.getUnreadMessagesEntriesCursorReference
/**
* Created by mariotaku on 2017/2/16.
*/
class BatchMarkMessageReadTask(
context: Context,
val accountKey: UserKey,
val markTimestampBefore: Long
) : ExceptionHandlingAbstractTask<Unit?, Boolean, MicroBlogException, Unit?>(context) {
override val exceptionClass = MicroBlogException::class.java
override fun onExecute(params: Unit?): Boolean {
val cr = context.contentResolver
val projection = (Conversations.COLUMNS + Conversations.UNREAD_COUNT).map {
TwidereQueryBuilder.mapConversationsProjection(it)
}.toTypedArray()
val unreadWhere = Expression.greaterThan(Columns.Column(Table(Conversations.TABLE_NAME),
Conversations.LAST_READ_TIMESTAMP), markTimestampBefore)
val unreadHaving = Expression.greaterThan(Conversations.UNREAD_COUNT, 0)
val cRef = cr.getUnreadMessagesEntriesCursorReference(projection, arrayOf(accountKey),
unreadWhere, null, unreadHaving, null) ?: return false
val account = AccountUtils.getAccountDetails(AccountManager.get(context), accountKey, true) ?:
throw MicroBlogException("No account")
val microBlog = account.newMicroBlogInstance(context, cls = MicroBlog::class.java)
cRef.use { (cur) ->
val indices = ObjectCursor.indicesFrom(cur, ParcelableMessageConversation::class.java)
cur.forEachRow { c, _ ->
val conversation = indices.newObject(c)
try {
val lastReadEvent = MarkMessageReadTask.performMarkRead(context, microBlog,
account, conversation) ?: return@forEachRow false
MarkMessageReadTask.updateLocalLastRead(cr, account.key, conversation.id,
lastReadEvent)
return@forEachRow true
} catch (e: MicroBlogException) {
return@forEachRow false
}
}
}
return true
}
override fun onSucceed(callback: Unit?, result: Boolean) {
bus.post(UnreadCountUpdatedEvent(-1))
}
}

View File

@ -1,133 +0,0 @@
/*
* 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.task.twitter.message
import android.accounts.AccountManager
import android.content.ContentResolver
import android.content.ContentValues
import android.content.Context
import org.mariotaku.microblog.library.MicroBlog
import org.mariotaku.microblog.library.MicroBlogException
import org.mariotaku.sqliteqb.library.Expression
import org.mariotaku.sqliteqb.library.OrderBy
import org.mariotaku.twidere.annotation.AccountType
import org.mariotaku.twidere.extension.model.isOfficial
import org.mariotaku.twidere.extension.model.newMicroBlogInstance
import org.mariotaku.twidere.extension.model.timestamp
import org.mariotaku.twidere.extension.queryOne
import org.mariotaku.twidere.model.AccountDetails
import org.mariotaku.twidere.model.ParcelableMessage
import org.mariotaku.twidere.model.ParcelableMessageConversation
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.model.event.UnreadCountUpdatedEvent
import org.mariotaku.twidere.model.message.conversation.TwitterOfficialConversationExtras
import org.mariotaku.twidere.model.util.AccountUtils
import org.mariotaku.twidere.provider.TwidereDataStore.Messages
import org.mariotaku.twidere.provider.TwidereDataStore.Messages.Conversations
import org.mariotaku.twidere.task.ExceptionHandlingAbstractTask
import org.mariotaku.twidere.task.twitter.message.SendMessageTask.Companion.TEMP_CONVERSATION_ID_PREFIX
import org.mariotaku.twidere.util.DataStoreUtils
/**
* Created by mariotaku on 2017/2/16.
*/
class MarkMessageReadTask(
context: Context,
val accountKey: UserKey,
val conversationId: String
) : ExceptionHandlingAbstractTask<Unit?, Boolean, MicroBlogException, Unit?>(context) {
override val exceptionClass = MicroBlogException::class.java
override fun onExecute(params: Unit?): Boolean {
if (conversationId.startsWith(TEMP_CONVERSATION_ID_PREFIX)) return true
val account = AccountUtils.getAccountDetails(AccountManager.get(context), accountKey, true) ?:
throw MicroBlogException("No account")
val microBlog = account.newMicroBlogInstance(context, cls = MicroBlog::class.java)
val conversation = DataStoreUtils.findMessageConversation(context, accountKey, conversationId)
val lastReadEvent = conversation?.let {
return@let performMarkRead(context, microBlog, account, conversation)
} ?: return false
updateLocalLastRead(context.contentResolver, accountKey, conversationId, lastReadEvent)
return true
}
override fun onSucceed(callback: Unit?, result: Boolean) {
bus.post(UnreadCountUpdatedEvent(-1))
}
companion object {
@Throws(MicroBlogException::class)
internal fun performMarkRead(context: Context, microBlog: MicroBlog, account: AccountDetails,
conversation: ParcelableMessageConversation): Pair<String, Long>? {
val cr = context.contentResolver
when (account.type) {
AccountType.TWITTER -> {
if (account.isOfficial(context)) {
val event = (conversation.conversation_extras as? TwitterOfficialConversationExtras)?.maxReadEvent ?: run {
val message = cr.findRecentMessage(account.key, conversation.id) ?: return null
return@run Pair(message.id, message.timestamp)
}
if (conversation.last_read_timestamp > event.second) {
// Local is newer, ignore network request
return event
}
if (microBlog.markDmRead(conversation.id, event.first).isSuccessful) {
return event
}
}
}
}
val message = cr.findRecentMessage(account.key, conversation.id) ?: return null
return Pair(message.id, message.timestamp)
}
internal fun updateLocalLastRead(cr: ContentResolver, accountKey: UserKey,
conversationId: String, lastRead: Pair<String, Long>) {
val values = ContentValues()
values.put(Conversations.LAST_READ_ID, lastRead.first)
values.put(Conversations.LAST_READ_TIMESTAMP, lastRead.second)
val updateWhere = Expression.and(Expression.equalsArgs(Conversations.ACCOUNT_KEY),
Expression.equalsArgs(Conversations.CONVERSATION_ID),
Expression.lesserThan(Conversations.LAST_READ_TIMESTAMP, lastRead.second)).sql
val updateWhereArgs = arrayOf(accountKey.toString(), conversationId)
cr.update(Conversations.CONTENT_URI, values, updateWhere, updateWhereArgs)
}
private fun ContentResolver.findRecentMessage(accountKey: UserKey, conversationId: String): ParcelableMessage? {
val where = Expression.and(Expression.equalsArgs(Messages.ACCOUNT_KEY),
Expression.equalsArgs(Messages.CONVERSATION_ID)).sql
val whereArgs = arrayOf(accountKey.toString(), conversationId)
return queryOne(Messages.CONTENT_URI, Messages.COLUMNS, where, whereArgs,
OrderBy(Messages.LOCAL_TIMESTAMP, false).sql, ParcelableMessage::class.java)
}
private val TwitterOfficialConversationExtras.maxReadEvent: Pair<String, Long>?
get() {
val id = maxEntryId ?: return null
if (maxEntryTimestamp < 0) return null
return Pair(id, maxEntryTimestamp)
}
}
}