fixed source file name
This commit is contained in:
parent
fda48b3b9e
commit
43a80bdb70
|
@ -37,6 +37,13 @@ public class NewDm extends SimpleValueMap {
|
|||
put("conversation_id", conversationId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Help you identify which is new message, this id will be attached in request result
|
||||
*/
|
||||
public void setRequestId(String requestId) {
|
||||
put("request_id", requestId);
|
||||
}
|
||||
|
||||
public void setRecipientIds(String[] recipientIds) {
|
||||
put("recipient_ids", InternalArrayUtil.join(recipientIds, ","));
|
||||
}
|
||||
|
|
|
@ -155,7 +155,6 @@ public interface TwidereConstants extends SharedPreferenceConstants, IntentConst
|
|||
String QUERY_PARAM_NEW_ITEMS_COUNT = "new_items_count";
|
||||
String QUERY_PARAM_CONVERSATION_ID = "conversation_id";
|
||||
String QUERY_PARAM_READ_POSITION = "param_read_position";
|
||||
String QUERY_PARAM_READ_POSITIONS = "param_read_positions";
|
||||
String QUERY_PARAM_LIMIT = "limit";
|
||||
String QUERY_PARAM_EXTRA = "extra";
|
||||
String QUERY_PARAM_TIMESTAMP = "timestamp";
|
||||
|
|
|
@ -142,6 +142,10 @@ public class ParcelableMessageConversation implements Parcelable {
|
|||
@CursorField(value = Conversations.REQUEST_CURSOR)
|
||||
public String request_cursor;
|
||||
|
||||
@JsonField(name = "last_read_id")
|
||||
@CursorField(value = Conversations.LAST_READ_ID)
|
||||
public String last_read_id;
|
||||
|
||||
/**
|
||||
* True if this is a temporary conversation, i.e. Created by user but haven't send any message
|
||||
* yet.
|
||||
|
|
|
@ -382,6 +382,7 @@ public interface TwidereDataStore {
|
|||
String SENDER_KEY = "sender_key";
|
||||
String RECIPIENT_KEY = "recipient_key";
|
||||
String REQUEST_CURSOR = "request_cursor";
|
||||
String LAST_READ_ID = "last_read_id";
|
||||
String IS_OUTGOING = "is_outgoing";
|
||||
String IS_TEMP = "is_temp";
|
||||
String CONVERSATION_EXTRAS = "conversation_extras";
|
||||
|
|
|
@ -34,7 +34,7 @@ import static org.mariotaku.twidere.annotation.PreferenceType.STRING;
|
|||
public interface Constants extends TwidereConstants {
|
||||
|
||||
String DATABASES_NAME = "twidere.sqlite";
|
||||
int DATABASES_VERSION = 176;
|
||||
int DATABASES_VERSION = 177;
|
||||
|
||||
int EXTRA_FEATURES_NOTICE_VERSION = 0;
|
||||
|
||||
|
|
|
@ -22,12 +22,11 @@ package org.mariotaku.twidere.extension
|
|||
import android.annotation.SuppressLint
|
||||
import android.content.ContentResolver
|
||||
import android.database.Cursor
|
||||
import android.net.Uri
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore
|
||||
|
||||
@SuppressLint("Recycle")
|
||||
fun ContentResolver.rawQuery(sql: String, selectionArgs: Array<String>?): Cursor {
|
||||
val rawUri = Uri.withAppendedPath(TwidereDataStore.CONTENT_URI_RAW_QUERY, sql)
|
||||
fun ContentResolver.rawQuery(sql: String, selectionArgs: Array<String>?): Cursor? {
|
||||
val rawUri = TwidereDataStore.CONTENT_URI_RAW_QUERY.buildUpon().appendPath(sql).build()
|
||||
return query(rawUri, null, null, selectionArgs, null)
|
||||
}
|
||||
|
||||
|
|
|
@ -541,7 +541,6 @@ class TwidereDataProvider : ContentProvider(), LazyLoadCallback {
|
|||
val prefs = AccountPreferences.getNotificationEnabledPreferences(context,
|
||||
DataStoreUtils.getAccountKeys(context))
|
||||
prefs.filter(AccountPreferences::isDirectMessagesNotificationEnabled).forEach {
|
||||
val pairs = readStateManager.getPositionPairs(CustomTabType.DIRECT_MESSAGES)
|
||||
// TODO show messages notifications
|
||||
}
|
||||
notifyUnreadCountChanged(NOTIFICATION_ID_DIRECT_MESSAGES)
|
||||
|
|
|
@ -64,23 +64,12 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||
}
|
||||
val manager = holder.readStateManager
|
||||
val paramReadPosition = uri.getQueryParameter(QUERY_PARAM_READ_POSITION)
|
||||
val paramReadPositions = uri.getQueryParameter(QUERY_PARAM_READ_POSITIONS)
|
||||
@ReadPositionTag
|
||||
val tag = getPositionTag(notificationType)
|
||||
|
||||
if (tag != null && !TextUtils.isEmpty(paramReadPosition)) {
|
||||
manager.setPosition(Utils.getReadPositionTagWithAccount(tag, accountKey),
|
||||
paramReadPosition.toLong(-1))
|
||||
} else if (!TextUtils.isEmpty(paramReadPositions)) {
|
||||
try {
|
||||
val pairs = StringLongPair.valuesOf(paramReadPositions)
|
||||
for (pair in pairs) {
|
||||
manager.setPosition(tag!!, pair.key, pair.value)
|
||||
}
|
||||
} catch (ignore: NumberFormatException) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,23 +24,31 @@ import android.content.ContentValues
|
|||
import android.content.Context
|
||||
import org.mariotaku.ktextension.toInt
|
||||
import org.mariotaku.ktextension.useCursor
|
||||
import org.mariotaku.microblog.library.MicroBlog
|
||||
import org.mariotaku.microblog.library.MicroBlogException
|
||||
import org.mariotaku.microblog.library.twitter.model.DMResponse
|
||||
import org.mariotaku.microblog.library.twitter.model.Paging
|
||||
import org.mariotaku.microblog.library.twitter.model.User
|
||||
import org.mariotaku.microblog.library.twitter.model.fixMedia
|
||||
import org.mariotaku.sqliteqb.library.Expression
|
||||
import org.mariotaku.twidere.annotation.AccountType
|
||||
import org.mariotaku.twidere.extension.model.applyFrom
|
||||
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.model.*
|
||||
import org.mariotaku.twidere.model.ParcelableMessageConversation.ConversationType
|
||||
import org.mariotaku.twidere.model.event.GetMessagesTaskEvent
|
||||
import org.mariotaku.twidere.model.message.conversation.TwitterOfficialConversationExtras
|
||||
import org.mariotaku.twidere.model.util.AccountUtils
|
||||
import org.mariotaku.twidere.model.util.AccountUtils.getAccountDetails
|
||||
import org.mariotaku.twidere.model.util.ParcelableMessageUtils
|
||||
import org.mariotaku.twidere.model.util.ParcelableUserUtils
|
||||
import org.mariotaku.twidere.model.util.UserKeyUtils
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Messages
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Messages.Conversations
|
||||
import org.mariotaku.twidere.task.BaseAbstractTask
|
||||
import org.mariotaku.twidere.util.DataStoreUtils
|
||||
import org.mariotaku.twidere.util.content.ContentResolverUtils
|
||||
import java.util.*
|
||||
|
||||
|
@ -56,10 +64,10 @@ class GetMessagesTask(
|
|||
val am = android.accounts.AccountManager.get(context)
|
||||
accountKeys.forEachIndexed { i, accountKey ->
|
||||
val details = getAccountDetails(am, accountKey, true) ?: return@forEachIndexed
|
||||
val microBlog = details.newMicroBlogInstance(context, true, cls = org.mariotaku.microblog.library.MicroBlog::class.java)
|
||||
val microBlog = details.newMicroBlogInstance(context, true, cls = MicroBlog::class.java)
|
||||
val messages = try {
|
||||
getMessages(microBlog, details, param, i)
|
||||
} catch (e: org.mariotaku.microblog.library.MicroBlogException) {
|
||||
} catch (e: MicroBlogException) {
|
||||
return@forEachIndexed
|
||||
}
|
||||
Companion.storeMessages(context, messages, details)
|
||||
|
@ -68,16 +76,16 @@ class GetMessagesTask(
|
|||
|
||||
override fun afterExecute(callback: ((Boolean) -> Unit)?, result: Unit) {
|
||||
callback?.invoke(true)
|
||||
bus.post(org.mariotaku.twidere.model.event.GetMessagesTaskEvent(Messages.CONTENT_URI, params?.taskTag, false, null))
|
||||
bus.post(GetMessagesTaskEvent(Messages.CONTENT_URI, params?.taskTag, false, null))
|
||||
}
|
||||
|
||||
private fun getMessages(microBlog: org.mariotaku.microblog.library.MicroBlog, details: AccountDetails, param: RefreshMessagesTaskParam, index: Int): DatabaseUpdateData {
|
||||
private fun getMessages(microBlog: MicroBlog, details: AccountDetails, param: RefreshMessagesTaskParam, index: Int): DatabaseUpdateData {
|
||||
when (details.type) {
|
||||
org.mariotaku.twidere.annotation.AccountType.FANFOU -> {
|
||||
AccountType.FANFOU -> {
|
||||
// Use fanfou DM api, disabled since it's conversation api is not suitable for paging
|
||||
// return getFanfouMessages(microBlog, details, param, index)
|
||||
}
|
||||
org.mariotaku.twidere.annotation.AccountType.TWITTER -> {
|
||||
AccountType.TWITTER -> {
|
||||
// Use official DM api
|
||||
if (details.isOfficial(context)) {
|
||||
return getTwitterOfficialMessages(microBlog, details, param, index)
|
||||
|
@ -88,7 +96,7 @@ class GetMessagesTask(
|
|||
return getDefaultMessages(microBlog, details, param, index)
|
||||
}
|
||||
|
||||
private fun getTwitterOfficialMessages(microBlog: org.mariotaku.microblog.library.MicroBlog, details: AccountDetails,
|
||||
private fun getTwitterOfficialMessages(microBlog: MicroBlog, details: AccountDetails,
|
||||
param: RefreshMessagesTaskParam, index: Int): DatabaseUpdateData {
|
||||
val conversationId = param.conversationId
|
||||
if (conversationId == null) {
|
||||
|
@ -98,7 +106,7 @@ class GetMessagesTask(
|
|||
}
|
||||
}
|
||||
|
||||
private fun getFanfouMessages(microBlog: org.mariotaku.microblog.library.MicroBlog, details: AccountDetails, param: RefreshMessagesTaskParam, index: Int): DatabaseUpdateData {
|
||||
private fun getFanfouMessages(microBlog: MicroBlog, details: AccountDetails, param: RefreshMessagesTaskParam, index: Int): DatabaseUpdateData {
|
||||
val conversationId = param.conversationId
|
||||
if (conversationId == null) {
|
||||
return getFanfouConversations(microBlog, details, param, index)
|
||||
|
@ -107,13 +115,13 @@ class GetMessagesTask(
|
|||
}
|
||||
}
|
||||
|
||||
private fun getDefaultMessages(microBlog: org.mariotaku.microblog.library.MicroBlog, details: AccountDetails, param: RefreshMessagesTaskParam, index: Int): DatabaseUpdateData {
|
||||
private fun getDefaultMessages(microBlog: MicroBlog, details: AccountDetails, param: RefreshMessagesTaskParam, index: Int): DatabaseUpdateData {
|
||||
val accountKey = details.key
|
||||
|
||||
val sinceIds = if (param.hasSinceIds) param.sinceIds else null
|
||||
val maxIds = if (param.hasMaxIds) param.maxIds else null
|
||||
|
||||
val received = microBlog.getDirectMessages(org.mariotaku.microblog.library.twitter.model.Paging().apply {
|
||||
val received = microBlog.getDirectMessages(Paging().apply {
|
||||
count(100)
|
||||
val maxId = maxIds?.get(index)
|
||||
val sinceId = sinceIds?.get(index)
|
||||
|
@ -124,7 +132,7 @@ class GetMessagesTask(
|
|||
sinceId(sinceId)
|
||||
}
|
||||
})
|
||||
val sent = microBlog.getSentDirectMessages(org.mariotaku.microblog.library.twitter.model.Paging().apply {
|
||||
val sent = microBlog.getSentDirectMessages(Paging().apply {
|
||||
count(100)
|
||||
val accountsCount = param.accountKeys.size
|
||||
val maxId = maxIds?.get(accountsCount + index)
|
||||
|
@ -143,22 +151,22 @@ class GetMessagesTask(
|
|||
|
||||
val conversationIds = hashSetOf<String>()
|
||||
received.forEach {
|
||||
conversationIds.add(org.mariotaku.twidere.model.util.ParcelableMessageUtils.incomingConversationId(it.senderId, it.recipientId))
|
||||
conversationIds.add(ParcelableMessageUtils.incomingConversationId(it.senderId, it.recipientId))
|
||||
}
|
||||
sent.forEach {
|
||||
conversationIds.add(org.mariotaku.twidere.model.util.ParcelableMessageUtils.outgoingConversationId(it.senderId, it.recipientId))
|
||||
conversationIds.add(ParcelableMessageUtils.outgoingConversationId(it.senderId, it.recipientId))
|
||||
}
|
||||
|
||||
conversations.addLocalConversations(context, accountKey, conversationIds)
|
||||
|
||||
received.forEachIndexed { i, dm ->
|
||||
val message = org.mariotaku.twidere.model.util.ParcelableMessageUtils.fromMessage(accountKey, dm, false,
|
||||
val message = ParcelableMessageUtils.fromMessage(accountKey, dm, false,
|
||||
1.0 - (i.toDouble() / received.size))
|
||||
insertMessages.add(message)
|
||||
conversations.addConversation(message.conversation_id, details, message, setOf(dm.sender, dm.recipient))
|
||||
}
|
||||
sent.forEachIndexed { i, dm ->
|
||||
val message = org.mariotaku.twidere.model.util.ParcelableMessageUtils.fromMessage(accountKey, dm, true,
|
||||
val message = ParcelableMessageUtils.fromMessage(accountKey, dm, true,
|
||||
1.0 - (i.toDouble() / sent.size))
|
||||
insertMessages.add(message)
|
||||
conversations.addConversation(message.conversation_id, details, message, setOf(dm.sender, dm.recipient))
|
||||
|
@ -166,10 +174,10 @@ class GetMessagesTask(
|
|||
return DatabaseUpdateData(conversations.values, insertMessages)
|
||||
}
|
||||
|
||||
private fun getTwitterOfficialConversation(microBlog: org.mariotaku.microblog.library.MicroBlog, details: AccountDetails,
|
||||
private fun getTwitterOfficialConversation(microBlog: MicroBlog, details: AccountDetails,
|
||||
conversationId: String, param: RefreshMessagesTaskParam, index: Int): DatabaseUpdateData {
|
||||
val maxId = param.maxIds?.get(index) ?: return DatabaseUpdateData(emptyList(), emptyList())
|
||||
val paging = org.mariotaku.microblog.library.twitter.model.Paging().apply {
|
||||
val paging = Paging().apply {
|
||||
maxId(maxId)
|
||||
}
|
||||
|
||||
|
@ -178,14 +186,14 @@ class GetMessagesTask(
|
|||
return Companion.createDatabaseUpdateData(context, details, response)
|
||||
}
|
||||
|
||||
private fun getTwitterOfficialUserInbox(microBlog: org.mariotaku.microblog.library.MicroBlog, details: AccountDetails,
|
||||
private fun getTwitterOfficialUserInbox(microBlog: MicroBlog, details: AccountDetails,
|
||||
param: RefreshMessagesTaskParam, index: Int): DatabaseUpdateData {
|
||||
val maxId = if (param.hasMaxIds) param.maxIds?.get(index) else null
|
||||
val cursor = if (param.hasCursors) param.cursors?.get(index) else null
|
||||
val response = if (cursor != null) {
|
||||
microBlog.getUserUpdates(cursor).userEvents
|
||||
} else {
|
||||
microBlog.getUserInbox(org.mariotaku.microblog.library.twitter.model.Paging().apply {
|
||||
microBlog.getUserInbox(Paging().apply {
|
||||
if (maxId != null) {
|
||||
maxId(maxId)
|
||||
}
|
||||
|
@ -196,11 +204,11 @@ class GetMessagesTask(
|
|||
}
|
||||
|
||||
|
||||
private fun getFanfouConversations(microBlog: org.mariotaku.microblog.library.MicroBlog, details: AccountDetails, param: RefreshMessagesTaskParam, index: Int): DatabaseUpdateData {
|
||||
private fun getFanfouConversations(microBlog: MicroBlog, details: AccountDetails, param: RefreshMessagesTaskParam, index: Int): DatabaseUpdateData {
|
||||
val accountKey = details.key
|
||||
val cursor = param.cursors?.get(index)
|
||||
val page = cursor?.substringAfter("page:").toInt(-1)
|
||||
val result = microBlog.getConversationList(org.mariotaku.microblog.library.twitter.model.Paging().apply {
|
||||
val result = microBlog.getConversationList(Paging().apply {
|
||||
count(60)
|
||||
if (page >= 0) {
|
||||
page(page)
|
||||
|
@ -214,7 +222,7 @@ class GetMessagesTask(
|
|||
result.forEachIndexed { i, item ->
|
||||
val dm = item.dm
|
||||
// Sender is our self, treat as outgoing message
|
||||
val message = org.mariotaku.twidere.model.util.ParcelableMessageUtils.fromMessage(accountKey, dm, dm.senderId == accountKey.id,
|
||||
val message = ParcelableMessageUtils.fromMessage(accountKey, dm, dm.senderId == accountKey.id,
|
||||
1.0 - (i.toDouble() / result.size))
|
||||
val mc = conversations.addConversation(message.conversation_id, details, message,
|
||||
setOf(dm.sender, dm.recipient))
|
||||
|
@ -237,9 +245,9 @@ class GetMessagesTask(
|
|||
|
||||
override val sinceIds: Array<String?>?
|
||||
get() {
|
||||
val incomingIds = org.mariotaku.twidere.util.DataStoreUtils.getNewestMessageIds(context, Messages.CONTENT_URI,
|
||||
val incomingIds = DataStoreUtils.getNewestMessageIds(context, Messages.CONTENT_URI,
|
||||
defaultKeys, false)
|
||||
val outgoingIds = org.mariotaku.twidere.util.DataStoreUtils.getNewestMessageIds(context, Messages.CONTENT_URI,
|
||||
val outgoingIds = DataStoreUtils.getNewestMessageIds(context, Messages.CONTENT_URI,
|
||||
defaultKeys, true)
|
||||
return incomingIds + outgoingIds
|
||||
}
|
||||
|
@ -247,7 +255,7 @@ class GetMessagesTask(
|
|||
override val cursors: Array<String?>?
|
||||
get() {
|
||||
val cursors = arrayOfNulls<String>(defaultKeys.size)
|
||||
val newestConversations = org.mariotaku.twidere.util.DataStoreUtils.getNewestConversations(context,
|
||||
val newestConversations = DataStoreUtils.getNewestConversations(context,
|
||||
Conversations.CONTENT_URI, twitterOfficialKeys)
|
||||
newestConversations.forEachIndexed { i, conversation ->
|
||||
cursors[i] = conversation?.request_cursor
|
||||
|
@ -265,11 +273,11 @@ class GetMessagesTask(
|
|||
) : RefreshMessagesTaskParam(context) {
|
||||
|
||||
override val maxIds: Array<String?>? by lazy {
|
||||
val incomingIds = org.mariotaku.twidere.util.DataStoreUtils.getOldestMessageIds(context, Messages.CONTENT_URI,
|
||||
val incomingIds = DataStoreUtils.getOldestMessageIds(context, Messages.CONTENT_URI,
|
||||
defaultKeys, false)
|
||||
val outgoingIds = org.mariotaku.twidere.util.DataStoreUtils.getOldestMessageIds(context, Messages.CONTENT_URI,
|
||||
val outgoingIds = DataStoreUtils.getOldestMessageIds(context, Messages.CONTENT_URI,
|
||||
defaultKeys, true)
|
||||
val oldestConversations = org.mariotaku.twidere.util.DataStoreUtils.getOldestConversations(context,
|
||||
val oldestConversations = DataStoreUtils.getOldestConversations(context,
|
||||
Conversations.CONTENT_URI, twitterOfficialKeys)
|
||||
oldestConversations.forEachIndexed { i, conversation ->
|
||||
val extras = conversation?.conversation_extras as? TwitterOfficialConversationExtras ?: return@forEachIndexed
|
||||
|
@ -305,13 +313,13 @@ class GetMessagesTask(
|
|||
var taskTag: String? = null
|
||||
|
||||
protected val accounts: Array<AccountDetails?> by lazy {
|
||||
org.mariotaku.twidere.model.util.AccountUtils.getAllAccountDetails(android.accounts.AccountManager.get(context), accountKeys, false)
|
||||
AccountUtils.getAllAccountDetails(android.accounts.AccountManager.get(context), accountKeys, false)
|
||||
}
|
||||
|
||||
protected val defaultKeys: Array<UserKey?>by lazy {
|
||||
return@lazy accounts.map { account ->
|
||||
account ?: return@map null
|
||||
if (account.isOfficial(context) || account.type == org.mariotaku.twidere.annotation.AccountType.FANFOU) {
|
||||
if (account.isOfficial(context) || account.type == AccountType.FANFOU) {
|
||||
return@map null
|
||||
}
|
||||
return@map account.key
|
||||
|
@ -358,7 +366,7 @@ class GetMessagesTask(
|
|||
return@mapNotNullTo null
|
||||
}
|
||||
else -> {
|
||||
return@mapNotNullTo org.mariotaku.twidere.model.util.ParcelableMessageUtils.fromEntry(account.key, entry, respUsers)
|
||||
return@mapNotNullTo ParcelableMessageUtils.fromEntry(account.key, entry, respUsers)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -379,6 +387,7 @@ class GetMessagesTask(
|
|||
conversation.conversation_avatar = v.avatarImageHttps
|
||||
conversation.request_cursor = response.cursor
|
||||
conversation.conversation_extras_type = ParcelableMessageConversation.ExtrasType.TWITTER_OFFICIAL
|
||||
conversation.last_read_id = v.lastReadEventId
|
||||
conversation.conversation_extras = TwitterOfficialConversationExtras().apply {
|
||||
this.minEntryId = v.minEntryId
|
||||
this.maxEntryId = v.maxEntryId
|
|
@ -38,10 +38,10 @@ import org.mariotaku.twidere.model.event.SendMessageTaskEvent
|
|||
import org.mariotaku.twidere.model.util.ParcelableMessageUtils
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Messages.Conversations
|
||||
import org.mariotaku.twidere.task.ExceptionHandlingAbstractTask
|
||||
import org.mariotaku.twidere.task.twitter.UpdateStatusTask
|
||||
import org.mariotaku.twidere.task.twitter.message.GetMessagesTask
|
||||
import org.mariotaku.twidere.task.twitter.message.GetMessagesTask.Companion.addConversation
|
||||
import org.mariotaku.twidere.task.twitter.message.GetMessagesTask.Companion.addLocalConversations
|
||||
import org.mariotaku.twidere.task.twitter.UpdateStatusTask
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/2/8.
|
||||
|
@ -88,7 +88,8 @@ class SendMessageTask(
|
|||
return sendDefaultDM(microBlog, account, message)
|
||||
}
|
||||
|
||||
private fun sendTwitterOfficialDM(microBlog: MicroBlog, account: AccountDetails, message: ParcelableNewMessage): GetMessagesTask.DatabaseUpdateData {
|
||||
private fun sendTwitterOfficialDM(microBlog: MicroBlog, account: AccountDetails,
|
||||
message: ParcelableNewMessage): GetMessagesTask.DatabaseUpdateData {
|
||||
var deleteOnSuccess: List<UpdateStatusTask.MediaDeletionItem>? = null
|
||||
var deleteAlways: List<UpdateStatusTask.MediaDeletionItem>? = null
|
||||
val sendResponse = try {
|
||||
|
|
|
@ -43,7 +43,6 @@ import org.mariotaku.twidere.constant.nameFirstKey
|
|||
import org.mariotaku.twidere.extension.rawQuery
|
||||
import org.mariotaku.twidere.model.*
|
||||
import org.mariotaku.twidere.model.util.ParcelableActivityUtils
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Activities
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Statuses
|
||||
import org.mariotaku.twidere.receiver.NotificationReceiver
|
||||
|
@ -65,6 +64,81 @@ class ContentNotificationManager(
|
|||
private var nameFirst: Boolean = false
|
||||
private var useStarForLikes: Boolean = false
|
||||
|
||||
fun showTimeline(pref: AccountPreferences, minPositionKey: Long) {
|
||||
val accountKey = pref.accountKey
|
||||
val resources = context.resources
|
||||
val nm = notificationManager
|
||||
val selection = Expression.and(Expression.equalsArgs(Statuses.ACCOUNT_KEY),
|
||||
Expression.greaterThan(Statuses.POSITION_KEY, minPositionKey))
|
||||
val filteredSelection = buildStatusFilterWhereClause(preferences, Statuses.TABLE_NAME,
|
||||
selection)
|
||||
val selectionArgs = arrayOf(accountKey.toString())
|
||||
val userProjection = arrayOf(Statuses.USER_KEY, Statuses.USER_NAME, Statuses.USER_SCREEN_NAME)
|
||||
val statusProjection = arrayOf(Statuses.POSITION_KEY)
|
||||
val statusCursor = context.contentResolver.query(Statuses.CONTENT_URI, statusProjection,
|
||||
filteredSelection.sql, selectionArgs, Statuses.DEFAULT_SORT_ORDER) ?: return
|
||||
|
||||
val userCursor = context.contentResolver.rawQuery(SQLQueryBuilder.select(Columns(*userProjection))
|
||||
.from(Table(Statuses.TABLE_NAME))
|
||||
.where(filteredSelection)
|
||||
.groupBy(Columns.Column(Statuses.USER_KEY))
|
||||
.orderBy(OrderBy(Statuses.DEFAULT_SORT_ORDER)).buildSQL(), selectionArgs) ?: return
|
||||
|
||||
try {
|
||||
val usersCount = userCursor.count
|
||||
val statusesCount = statusCursor.count
|
||||
if (statusesCount == 0 || usersCount == 0) return
|
||||
val statusIndices = ParcelableStatusCursorIndices(statusCursor)
|
||||
val userIndices = ParcelableStatusCursorIndices(userCursor)
|
||||
val positionKey = if (statusCursor.moveToFirst()) statusCursor.getLong(statusIndices.position_key) else -1L
|
||||
val notificationTitle = resources.getQuantityString(R.plurals.N_new_statuses,
|
||||
statusesCount, statusesCount)
|
||||
val notificationContent: String
|
||||
userCursor.moveToFirst()
|
||||
val displayName = userColorNameManager.getDisplayName(userCursor.getString(userIndices.user_key),
|
||||
userCursor.getString(userIndices.user_name), userCursor.getString(userIndices.user_screen_name),
|
||||
nameFirst)
|
||||
if (usersCount == 1) {
|
||||
notificationContent = context.getString(R.string.from_name, displayName)
|
||||
} else if (usersCount == 2) {
|
||||
userCursor.moveToPosition(1)
|
||||
val othersName = userColorNameManager.getDisplayName(userCursor.getString(userIndices.user_key),
|
||||
userCursor.getString(userIndices.user_name), userCursor.getString(userIndices.user_screen_name),
|
||||
nameFirst)
|
||||
notificationContent = resources.getString(R.string.from_name_and_name, displayName, othersName)
|
||||
} else {
|
||||
notificationContent = resources.getString(R.string.from_name_and_N_others, displayName, usersCount - 1)
|
||||
}
|
||||
|
||||
// Setup notification
|
||||
val builder = NotificationCompat.Builder(context)
|
||||
builder.setAutoCancel(true)
|
||||
builder.setSmallIcon(R.drawable.ic_stat_twitter)
|
||||
builder.setTicker(notificationTitle)
|
||||
builder.setContentTitle(notificationTitle)
|
||||
builder.setContentText(notificationContent)
|
||||
builder.setCategory(NotificationCompat.CATEGORY_SOCIAL)
|
||||
builder.setContentIntent(getContentIntent(context, CustomTabType.HOME_TIMELINE,
|
||||
NotificationType.HOME_TIMELINE, accountKey, positionKey))
|
||||
builder.setDeleteIntent(getMarkReadDeleteIntent(context, NotificationType.HOME_TIMELINE,
|
||||
accountKey, positionKey, false))
|
||||
builder.setNumber(statusesCount)
|
||||
builder.setCategory(NotificationCompat.CATEGORY_SOCIAL)
|
||||
applyNotificationPreferences(builder, pref, pref.homeTimelineNotificationType)
|
||||
try {
|
||||
nm.notify("home_" + accountKey, Utils.getNotificationId(NOTIFICATION_ID_HOME_TIMELINE, accountKey), builder.build())
|
||||
Utils.sendPebbleNotification(context, null, notificationContent)
|
||||
} catch (e: SecurityException) {
|
||||
// Silently ignore
|
||||
}
|
||||
|
||||
} finally {
|
||||
statusCursor.close()
|
||||
userCursor.close()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun showInteractions(pref: AccountPreferences, position: Long) {
|
||||
val cr = context.contentResolver
|
||||
val accountKey = pref.accountKey
|
||||
|
@ -163,12 +237,9 @@ class ContentNotificationManager(
|
|||
}
|
||||
val notificationId = Utils.getNotificationId(NOTIFICATION_ID_INTERACTIONS_TIMELINE, accountKey)
|
||||
notificationManager.notify("interactions", notificationId, builder.build())
|
||||
|
||||
Utils.sendPebbleNotification(context, context.resources.getString(R.string.interactions), pebbleNotificationStringBuilder.toString())
|
||||
|
||||
Utils.sendPebbleNotification(context, context.getString(R.string.interactions), pebbleNotificationStringBuilder.toString())
|
||||
}
|
||||
|
||||
|
||||
private fun applyNotificationPreferences(builder: NotificationCompat.Builder, pref: AccountPreferences, defaultFlags: Int) {
|
||||
var notificationDefaults = 0
|
||||
if (AccountPreferences.isNotificationHasLight(defaultFlags)) {
|
||||
|
@ -195,80 +266,6 @@ class ContentNotificationManager(
|
|||
return !activityTracker.isHomeActivityStarted
|
||||
}
|
||||
|
||||
fun showTimeline(pref: AccountPreferences, position: Long) {
|
||||
val accountKey = pref.accountKey
|
||||
val resources = context.resources
|
||||
val nm = notificationManager
|
||||
val selection = Expression.and(Expression.equalsArgs(Statuses.ACCOUNT_KEY),
|
||||
Expression.greaterThan(Statuses.POSITION_KEY, position))
|
||||
val filteredSelection = buildStatusFilterWhereClause(preferences,
|
||||
Statuses.TABLE_NAME, selection)
|
||||
val selectionArgs = arrayOf(accountKey.toString())
|
||||
val userProjection = arrayOf(Statuses.USER_KEY, Statuses.USER_NAME, Statuses.USER_SCREEN_NAME)
|
||||
val statusProjection = arrayOf(Statuses.POSITION_KEY)
|
||||
val statusCursor = context.contentResolver.query(Statuses.CONTENT_URI, statusProjection,
|
||||
filteredSelection.sql, selectionArgs, Statuses.DEFAULT_SORT_ORDER)
|
||||
|
||||
val userCursor = context.contentResolver.rawQuery(SQLQueryBuilder.select(Columns(*userProjection))
|
||||
.from(Table(Statuses.TABLE_NAME))
|
||||
.where(filteredSelection)
|
||||
.groupBy(Columns.Column(Statuses.USER_KEY))
|
||||
.orderBy(OrderBy(Statuses.DEFAULT_SORT_ORDER)).buildSQL(), selectionArgs)
|
||||
|
||||
try {
|
||||
val usersCount = userCursor.count
|
||||
val statusesCount = statusCursor.count
|
||||
if (statusesCount == 0 || usersCount == 0) return
|
||||
val statusIndices = ParcelableStatusCursorIndices(statusCursor)
|
||||
val userIndices = ParcelableStatusCursorIndices(userCursor)
|
||||
val positionKey = if (statusCursor.moveToFirst()) statusCursor.getLong(statusIndices.position_key) else -1L
|
||||
val notificationTitle = resources.getQuantityString(R.plurals.N_new_statuses,
|
||||
statusesCount, statusesCount)
|
||||
val notificationContent: String
|
||||
userCursor.moveToFirst()
|
||||
val displayName = userColorNameManager.getDisplayName(userCursor.getString(userIndices.user_key),
|
||||
userCursor.getString(userIndices.user_name), userCursor.getString(userIndices.user_screen_name),
|
||||
nameFirst)
|
||||
if (usersCount == 1) {
|
||||
notificationContent = context.getString(R.string.from_name, displayName)
|
||||
} else if (usersCount == 2) {
|
||||
userCursor.moveToPosition(1)
|
||||
val othersName = userColorNameManager.getDisplayName(userCursor.getString(userIndices.user_key),
|
||||
userCursor.getString(userIndices.user_name), userCursor.getString(userIndices.user_screen_name),
|
||||
nameFirst)
|
||||
notificationContent = resources.getString(R.string.from_name_and_name, displayName, othersName)
|
||||
} else {
|
||||
notificationContent = resources.getString(R.string.from_name_and_N_others, displayName, usersCount - 1)
|
||||
}
|
||||
|
||||
// Setup notification
|
||||
val builder = NotificationCompat.Builder(context)
|
||||
builder.setAutoCancel(true)
|
||||
builder.setSmallIcon(R.drawable.ic_stat_twitter)
|
||||
builder.setTicker(notificationTitle)
|
||||
builder.setContentTitle(notificationTitle)
|
||||
builder.setContentText(notificationContent)
|
||||
builder.setCategory(NotificationCompat.CATEGORY_SOCIAL)
|
||||
builder.setContentIntent(getContentIntent(context, CustomTabType.HOME_TIMELINE,
|
||||
NotificationType.HOME_TIMELINE, accountKey, positionKey))
|
||||
builder.setDeleteIntent(getMarkReadDeleteIntent(context, NotificationType.HOME_TIMELINE,
|
||||
accountKey, positionKey, false))
|
||||
builder.setNumber(statusesCount)
|
||||
builder.setCategory(NotificationCompat.CATEGORY_SOCIAL)
|
||||
applyNotificationPreferences(builder, pref, pref.homeTimelineNotificationType)
|
||||
try {
|
||||
nm.notify("home_" + accountKey, Utils.getNotificationId(NOTIFICATION_ID_HOME_TIMELINE, accountKey), builder.build())
|
||||
Utils.sendPebbleNotification(context, null, notificationContent)
|
||||
} catch (e: SecurityException) {
|
||||
// Silently ignore
|
||||
}
|
||||
|
||||
} finally {
|
||||
statusCursor.close()
|
||||
userCursor.close()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun getContentIntent(context: Context, @CustomTabType type: String,
|
||||
@NotificationType notificationType: String, accountKey: UserKey?, readPosition: Long): PendingIntent {
|
||||
|
@ -302,26 +299,6 @@ class ContentNotificationManager(
|
|||
useStarForLikes = preferences[iWantMyStarsBackKey]
|
||||
}
|
||||
|
||||
|
||||
private fun getMarkReadDeleteIntent(context: Context, @NotificationType notificationType: String,
|
||||
accountKey: UserKey?, positions: Array<StringLongPair>): PendingIntent {
|
||||
// Setup delete intent
|
||||
val intent = Intent(context, NotificationReceiver::class.java)
|
||||
val linkBuilder = Uri.Builder()
|
||||
linkBuilder.scheme(SCHEME_TWIDERE)
|
||||
linkBuilder.authority(AUTHORITY_INTERACTIONS)
|
||||
linkBuilder.appendPath(notificationType)
|
||||
if (accountKey != null) {
|
||||
linkBuilder.appendQueryParameter(QUERY_PARAM_ACCOUNT_KEY, accountKey.toString())
|
||||
}
|
||||
linkBuilder.appendQueryParameter(QUERY_PARAM_READ_POSITIONS, StringLongPair.toString(positions))
|
||||
linkBuilder.appendQueryParameter(QUERY_PARAM_TIMESTAMP, System.currentTimeMillis().toString())
|
||||
linkBuilder.appendQueryParameter(QUERY_PARAM_NOTIFICATION_TYPE, notificationType)
|
||||
intent.data = linkBuilder.build()
|
||||
return PendingIntent.getBroadcast(context, 0, intent, 0)
|
||||
}
|
||||
|
||||
|
||||
private fun getMarkReadDeleteIntent(context: Context, @NotificationType type: String,
|
||||
accountKey: UserKey?, position: Long,
|
||||
extraUserFollowing: Boolean): PendingIntent {
|
||||
|
|
|
@ -675,7 +675,7 @@ object DataStoreUtils {
|
|||
if (sortExpression != null) {
|
||||
builder.orderBy(sortExpression)
|
||||
}
|
||||
resolver.rawQuery(builder.buildSQL(), bindingArgs).useCursor { cur ->
|
||||
resolver.rawQuery(builder.buildSQL(), bindingArgs)?.useCursor { cur ->
|
||||
cur.moveToFirst()
|
||||
val colIdx = creator.newIndex(cur)
|
||||
while (!cur.isAfterLast) {
|
||||
|
|
|
@ -26,8 +26,6 @@ import org.mariotaku.twidere.TwidereConstants.TIMELINE_POSITIONS_PREFERENCES_NAM
|
|||
import org.mariotaku.twidere.annotation.CustomTabType
|
||||
import org.mariotaku.twidere.annotation.NotificationType
|
||||
import org.mariotaku.twidere.annotation.ReadPositionTag
|
||||
import org.mariotaku.twidere.model.StringLongPair
|
||||
import org.mariotaku.twidere.util.collection.CompactHashSet
|
||||
|
||||
class ReadStateManager(context: Context) {
|
||||
|
||||
|
@ -39,24 +37,6 @@ class ReadStateManager(context: Context) {
|
|||
return preferences.getLong(key, -1)
|
||||
}
|
||||
|
||||
fun getPositionPairs(key: String): Array<StringLongPair> {
|
||||
if (TextUtils.isEmpty(key)) return emptyArray()
|
||||
val set = preferences.getStringSet(key, null) ?: return emptyArray()
|
||||
try {
|
||||
return set.map { StringLongPair.valueOf(it) }.toTypedArray()
|
||||
} catch (e: NumberFormatException) {
|
||||
return emptyArray()
|
||||
}
|
||||
}
|
||||
|
||||
fun getPosition(key: String, keyId: String): Long {
|
||||
if (TextUtils.isEmpty(key)) return -1
|
||||
val set = preferences.getStringSet(key, null) ?: return -1
|
||||
val prefix = keyId + ":"
|
||||
val first = set.firstOrNull { it.startsWith(prefix) } ?: return -1
|
||||
return StringLongPair.valueOf(first).value
|
||||
}
|
||||
|
||||
fun registerOnSharedPreferenceChangeListener(listener: OnSharedPreferenceChangeListener) {
|
||||
preferences.registerOnSharedPreferenceChangeListener(listener)
|
||||
}
|
||||
|
@ -65,46 +45,7 @@ class ReadStateManager(context: Context) {
|
|||
preferences.unregisterOnSharedPreferenceChangeListener(listener)
|
||||
}
|
||||
|
||||
fun setPosition(key: String, keyId: String, position: Long, acceptOlder: Boolean = false): Boolean {
|
||||
if (TextUtils.isEmpty(key)) return false
|
||||
val set: MutableSet<String> = preferences.getStringSet(key, null) ?: CompactHashSet<String>()
|
||||
val prefix = keyId + ":"
|
||||
val keyValue: String? = set.firstOrNull { it.startsWith(prefix) }
|
||||
val pair: StringLongPair
|
||||
if (keyValue != null) {
|
||||
// Found value
|
||||
pair = StringLongPair.valueOf(keyValue)
|
||||
if (!acceptOlder && pair.value > position) return false
|
||||
set.remove(keyValue)
|
||||
pair.value = position
|
||||
} else {
|
||||
pair = StringLongPair(keyId, position)
|
||||
}
|
||||
set.add(pair.toString())
|
||||
val editor = preferences.edit()
|
||||
editor.putStringSet(key, set)
|
||||
editor.apply()
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
fun setPositionPairs(key: String, pairs: Array<StringLongPair>?): Boolean {
|
||||
if (TextUtils.isEmpty(key)) return false
|
||||
val editor = preferences.edit()
|
||||
if (pairs == null) {
|
||||
editor.remove(key)
|
||||
} else {
|
||||
val set = CompactHashSet<String>()
|
||||
for (pair in pairs) {
|
||||
set.add(pair.toString())
|
||||
}
|
||||
editor.putStringSet(key, set)
|
||||
}
|
||||
editor.apply()
|
||||
return true
|
||||
}
|
||||
|
||||
@JvmOverloads fun setPosition(key: String, position: Long, acceptOlder: Boolean = false): Boolean {
|
||||
fun setPosition(key: String, position: Long, acceptOlder: Boolean = false): Boolean {
|
||||
if (TextUtils.isEmpty(key) || !acceptOlder && getPosition(key) >= position) return false
|
||||
val editor = preferences.edit()
|
||||
editor.putLong(key, position)
|
||||
|
@ -112,10 +53,6 @@ class ReadStateManager(context: Context) {
|
|||
return true
|
||||
}
|
||||
|
||||
interface OnReadStateChangeListener {
|
||||
fun onReadStateChanged()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@ReadPositionTag
|
||||
|
|
|
@ -38,7 +38,7 @@ object FilterQueryBuilder {
|
|||
val query = FilterQueryBuilder.isFilteredQuery(userKey,
|
||||
textPlain, quotedTextPlain, spans, quotedSpans, source, quotedSource, retweetedByKey,
|
||||
quotedUserKey, true)
|
||||
val cur = cr.rawQuery(query.first, query.second)
|
||||
val cur = cr.rawQuery(query.first, query.second) ?: return false
|
||||
try {
|
||||
return cur.moveToFirst() && cur.getInt(0) != 0
|
||||
} finally {
|
||||
|
|
Loading…
Reference in New Issue