diff --git a/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/api/PrivateDirectMessagesResources.java b/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/api/PrivateDirectMessagesResources.java index 14fcc31b1..72d12b55f 100644 --- a/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/api/PrivateDirectMessagesResources.java +++ b/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/api/PrivateDirectMessagesResources.java @@ -23,6 +23,7 @@ package org.mariotaku.microblog.library.twitter.api; import org.mariotaku.microblog.library.MicroBlogException; import org.mariotaku.microblog.library.twitter.model.ConversationTimeline; +import org.mariotaku.microblog.library.twitter.model.DMResponse; import org.mariotaku.microblog.library.twitter.model.NewDm; import org.mariotaku.microblog.library.twitter.model.Paging; import org.mariotaku.microblog.library.twitter.model.ResponseCode; @@ -46,11 +47,7 @@ public interface PrivateDirectMessagesResources extends PrivateResources { ResponseCode destroyDirectMessagesConversation(@Path("conversation_id") String conversationId) throws MicroBlogException; @POST("/dm/new.json") - ResponseCode sendDm(@Param NewDm newDm) throws MicroBlogException; - - @POST("/dm/conversation/{account_id}-{user_id}/delete.json") - @BodyType(BodyType.FORM) - ResponseCode destroyDirectMessagesConversation(@Path("account_id") String accountId, @Path("user_id") String userId) throws MicroBlogException; + DMResponse sendDm(@Param NewDm newDm) throws MicroBlogException; @GET("/dm/user_inbox.json") UserInbox getUserInbox(@Query Paging paging) throws MicroBlogException; diff --git a/twidere.component.common/src/main/java/org/mariotaku/twidere/model/ParcelableNewMessage.java b/twidere.component.common/src/main/java/org/mariotaku/twidere/model/ParcelableNewMessage.java new file mode 100644 index 000000000..b92809164 --- /dev/null +++ b/twidere.component.common/src/main/java/org/mariotaku/twidere/model/ParcelableNewMessage.java @@ -0,0 +1,83 @@ +/* + * Twidere - Twitter client for Android + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.mariotaku.twidere.model; + +import android.os.Parcel; +import android.os.Parcelable; + +import com.bluelinelabs.logansquare.annotation.JsonField; +import com.bluelinelabs.logansquare.annotation.JsonObject; +import com.hannesdorfmann.parcelableplease.annotation.ParcelablePlease; +import com.hannesdorfmann.parcelableplease.annotation.ParcelableThisPlease; + +/** + * Created by mariotaku on 2017/2/14. + */ +@ParcelablePlease +@JsonObject +public class ParcelableNewMessage implements Parcelable { + + @JsonField(name = "account") + @ParcelableThisPlease + public AccountDetails account; + @JsonField(name = "conversation_id") + @ParcelableThisPlease + public String conversation_id; + @JsonField(name = "recipient_id") + @ParcelableThisPlease + public String recipient_id; + @JsonField(name = "text") + @ParcelableThisPlease + public String text; + @JsonField(name = "media") + @ParcelableThisPlease + public ParcelableMediaUpdate[] media; + @JsonField(name = "draft_unique_id") + @ParcelableThisPlease + public String draft_unique_id; + @JsonField(name = "draft_action") + @ParcelableThisPlease + @Draft.Action + public String draft_action; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + ParcelableNewMessageParcelablePlease.writeToParcel(this, dest, flags); + } + + public static final Creator CREATOR = new Creator() { + public ParcelableNewMessage createFromParcel(Parcel source) { + ParcelableNewMessage target = new ParcelableNewMessage(); + ParcelableNewMessageParcelablePlease.readFromParcel(target, source); + return target; + } + + public ParcelableNewMessage[] newArray(int size) { + return new ParcelableNewMessage[size]; + } + }; +} diff --git a/twidere.component.common/src/main/java/org/mariotaku/twidere/model/ParcelableStatusUpdate.java b/twidere.component.common/src/main/java/org/mariotaku/twidere/model/ParcelableStatusUpdate.java index 1d5097636..5081a325f 100644 --- a/twidere.component.common/src/main/java/org/mariotaku/twidere/model/ParcelableStatusUpdate.java +++ b/twidere.component.common/src/main/java/org/mariotaku/twidere/model/ParcelableStatusUpdate.java @@ -68,6 +68,10 @@ public class ParcelableStatusUpdate implements Parcelable { @JsonField(name = "draft_unique_id") @ParcelableThisPlease public String draft_unique_id; + @JsonField(name = "draft_action") + @ParcelableThisPlease + @Draft.Action + public String draft_action; public ParcelableStatusUpdate() { } diff --git a/twidere.component.common/src/main/java/org/mariotaku/twidere/model/draft/SendDirectMessageActionExtras.java b/twidere.component.common/src/main/java/org/mariotaku/twidere/model/draft/SendDirectMessageActionExtras.java index cd0f8c016..8766e4d64 100644 --- a/twidere.component.common/src/main/java/org/mariotaku/twidere/model/draft/SendDirectMessageActionExtras.java +++ b/twidere.component.common/src/main/java/org/mariotaku/twidere/model/draft/SendDirectMessageActionExtras.java @@ -37,6 +37,9 @@ public class SendDirectMessageActionExtras implements ActionExtras { @ParcelableThisPlease @JsonField(name = "recipient_id") String recipientId; + @ParcelableThisPlease + @JsonField(name = "conversation_id") + String conversationId; public String getRecipientId() { return recipientId; @@ -46,6 +49,14 @@ public class SendDirectMessageActionExtras implements ActionExtras { this.recipientId = recipientId; } + public String getConversationId() { + return conversationId; + } + + public void setConversationId(final String conversationId) { + this.conversationId = conversationId; + } + @Override public int describeContents() { return 0; diff --git a/twidere/src/main/kotlin/org/mariotaku/ktextension/BundleExtensions.kt b/twidere/src/main/kotlin/org/mariotaku/ktextension/BundleExtensions.kt index 8c8485af2..7a78ced2a 100644 --- a/twidere/src/main/kotlin/org/mariotaku/ktextension/BundleExtensions.kt +++ b/twidere/src/main/kotlin/org/mariotaku/ktextension/BundleExtensions.kt @@ -3,10 +3,6 @@ package org.mariotaku.ktextension import android.os.Bundle import android.os.Parcelable -/** - * Created by mariotaku on 16/8/18. - */ - inline fun Bundle(action: Bundle.() -> Unit): Bundle { val bundle = Bundle() action(bundle) diff --git a/twidere/src/main/kotlin/org/mariotaku/ktextension/IntentExtensions.kt b/twidere/src/main/kotlin/org/mariotaku/ktextension/IntentExtensions.kt new file mode 100644 index 000000000..7ec83067d --- /dev/null +++ b/twidere/src/main/kotlin/org/mariotaku/ktextension/IntentExtensions.kt @@ -0,0 +1,27 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2017 Mariotaku Lee + * + * 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 . + */ + +package org.mariotaku.ktextension + +import android.content.Intent +import android.os.Parcelable + +fun Intent.getTypedArrayExtra(key: String, creator: Parcelable.Creator): Array { + return getParcelableArrayExtra(key).toTypedArray(creator) +} \ No newline at end of file diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/MessagesConversationAdapter.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/MessagesConversationAdapter.kt index 3aef3709b..72c18944b 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/MessagesConversationAdapter.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/MessagesConversationAdapter.kt @@ -33,6 +33,7 @@ import org.mariotaku.twidere.constant.nameFirstKey import org.mariotaku.twidere.extension.model.timestamp import org.mariotaku.twidere.model.* import org.mariotaku.twidere.model.ParcelableMessage.MessageType +import org.mariotaku.twidere.util.DirectMessageOnLinkClickHandler import org.mariotaku.twidere.util.MediaLoadingHandler import org.mariotaku.twidere.util.TwidereLinkify import org.mariotaku.twidere.view.holder.message.AbsMessageViewHolder @@ -50,7 +51,7 @@ class MessagesConversationAdapter(context: Context) : LoadMoreSupportAdapter? = null diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/constant/PreferenceKeys.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/constant/PreferenceKeys.kt index 1868aa5f8..e78bc9a78 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/constant/PreferenceKeys.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/constant/PreferenceKeys.kt @@ -66,6 +66,7 @@ val mediaPreloadOnWifiOnlyKey = KBooleanKey(KEY_PRELOAD_WIFI_ONLY, true) val autoRefreshCompatibilityModeKey = KBooleanKey("auto_refresh_compatibility_mode", Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) val floatingDetailedContentsKey = KBooleanKey("floating_detailed_contents", true) val localTrendsWoeIdKey = KIntKey(KEY_LOCAL_TRENDS_WOEID, 1) +val phishingLinksWaringKey = KBooleanKey(KEY_PHISHING_LINK_WARNING, true) object themeBackgroundAlphaKey : KSimpleKey(KEY_THEME_BACKGROUND_ALPHA, 0xFF) { override fun read(preferences: SharedPreferences): Int { diff --git a/twidere/src/main/kotlin/ParcelableStatusUpdateUtils.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/model/util/ParcelableStatusUpdateUtils.kt similarity index 79% rename from twidere/src/main/kotlin/ParcelableStatusUpdateUtils.kt rename to twidere/src/main/kotlin/org/mariotaku/twidere/model/util/ParcelableStatusUpdateUtils.kt index 3e4fdae0b..182d9dbbe 100644 --- a/twidere/src/main/kotlin/ParcelableStatusUpdateUtils.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/model/util/ParcelableStatusUpdateUtils.kt @@ -2,9 +2,8 @@ package org.mariotaku.twidere.model.util import android.accounts.AccountManager import android.content.Context +import org.mariotaku.ktextension.convert import org.mariotaku.twidere.extension.model.unique_id_non_null - -import org.mariotaku.twidere.model.AccountDetails import org.mariotaku.twidere.model.Draft import org.mariotaku.twidere.model.ParcelableStatusUpdate import org.mariotaku.twidere.model.draft.UpdateStatusActionExtras @@ -16,11 +15,9 @@ object ParcelableStatusUpdateUtils { fun fromDraftItem(context: Context, draft: Draft): ParcelableStatusUpdate { val statusUpdate = ParcelableStatusUpdate() - if (draft.account_keys != null) { - statusUpdate.accounts = AccountUtils.getAllAccountDetails(AccountManager.get(context), draft.account_keys!!, true) - } else { - statusUpdate.accounts = arrayOfNulls(0) - } + statusUpdate.accounts = draft.account_keys?.convert { + AccountUtils.getAllAccountDetails(AccountManager.get(context), it, true) + } ?: emptyArray() statusUpdate.text = draft.text statusUpdate.location = draft.location statusUpdate.media = draft.media @@ -31,6 +28,7 @@ object ParcelableStatusUpdateUtils { statusUpdate.display_coordinates = extra.displayCoordinates statusUpdate.attachment_url = extra.attachmentUrl } + statusUpdate.draft_action = draft.action_type statusUpdate.draft_unique_id = draft.unique_id_non_null return statusUpdate } diff --git a/twidere/src/main/kotlin/CardPreviewPreference.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/preference/CardPreviewPreference.kt similarity index 100% rename from twidere/src/main/kotlin/CardPreviewPreference.kt rename to twidere/src/main/kotlin/org/mariotaku/twidere/preference/CardPreviewPreference.kt diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/service/LengthyOperationsService.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/service/LengthyOperationsService.kt index fdd69551a..72f63f6f5 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/service/LengthyOperationsService.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/service/LengthyOperationsService.kt @@ -19,6 +19,7 @@ package org.mariotaku.twidere.service +import android.accounts.AccountManager import android.annotation.SuppressLint import android.app.Notification import android.app.Service @@ -42,10 +43,7 @@ import nl.komponents.kovenant.task import nl.komponents.kovenant.ui.successUi import org.mariotaku.abstask.library.AbstractTask import org.mariotaku.abstask.library.ManualTaskStarter -import org.mariotaku.ktextension.configure -import org.mariotaku.ktextension.toLong -import org.mariotaku.ktextension.toTypedArray -import org.mariotaku.ktextension.useCursor +import org.mariotaku.ktextension.* import org.mariotaku.microblog.library.MicroBlogException import org.mariotaku.microblog.library.twitter.TwitterUpload import org.mariotaku.microblog.library.twitter.model.MediaUploadResponse @@ -59,13 +57,13 @@ import org.mariotaku.twidere.TwidereConstants.* import org.mariotaku.twidere.model.* import org.mariotaku.twidere.model.draft.SendDirectMessageActionExtras import org.mariotaku.twidere.model.draft.StatusObjectExtras +import org.mariotaku.twidere.model.util.AccountUtils import org.mariotaku.twidere.model.util.ParcelableStatusUpdateUtils import org.mariotaku.twidere.provider.TwidereDataStore.Drafts import org.mariotaku.twidere.task.CreateFavoriteTask import org.mariotaku.twidere.task.RetweetStatusTask import org.mariotaku.twidere.task.SendMessageTask import org.mariotaku.twidere.task.twitter.UpdateStatusTask -import org.mariotaku.twidere.util.ContentValuesCreator import org.mariotaku.twidere.util.NotificationManagerWrapper import org.mariotaku.twidere.util.Utils import org.mariotaku.twidere.util.deleteDrafts @@ -132,13 +130,21 @@ class LengthyOperationsService : BaseIntentService("lengthy_operations") { when (draft.action_type) { Draft.Action.UPDATE_STATUS_COMPAT_1, Draft.Action.UPDATE_STATUS_COMPAT_2, Draft.Action.UPDATE_STATUS, Draft.Action.REPLY, Draft.Action.QUOTE -> { - updateStatuses(draft.action_type, ParcelableStatusUpdateUtils.fromDraftItem(this, draft)) + updateStatuses(ParcelableStatusUpdateUtils.fromDraftItem(this, draft)) } Draft.Action.SEND_DIRECT_MESSAGE_COMPAT, Draft.Action.SEND_DIRECT_MESSAGE -> { - val recipientId = (draft.action_extras as? SendDirectMessageActionExtras)?.recipientId ?: return - val accountKey = draft.account_keys?.firstOrNull() ?: return - val imageUri = draft.media.firstOrNull()?.uri - sendMessage(accountKey, recipientId, draft.text, imageUri) + val extras = draft.action_extras as? SendDirectMessageActionExtras ?: return + val message = ParcelableNewMessage().apply { + this.account = draft.account_keys?.firstOrNull()?.convert { key -> + val am = AccountManager.get(this@LengthyOperationsService) + return@convert AccountUtils.getAccountDetails(am, key, true) + } + this.text = draft.text + this.media = draft.media + this.recipient_id = extras.recipientId + this.conversation_id = extras.conversationId + } + sendMessage(message) } Draft.Action.FAVORITE -> { performStatusAction(draft) { accountKey, status -> @@ -167,22 +173,18 @@ class LengthyOperationsService : BaseIntentService("lengthy_operations") { } private fun handleSendDirectMessageIntent(intent: Intent) { - val accountId = intent.getParcelableExtra(EXTRA_ACCOUNT_KEY) - val recipientId = intent.getStringExtra(EXTRA_RECIPIENT_ID) - val text = intent.getStringExtra(EXTRA_TEXT) - val imageUri = intent.getStringExtra(EXTRA_IMAGE_URI) - if (accountId == null || recipientId == null || text == null) return - sendMessage(accountId, recipientId, text, imageUri) + val message = intent.getParcelableExtra(EXTRA_MESSAGE) ?: return + sendMessage(message) } - private fun sendMessage(accountId: UserKey, recipientId: String, text: String, imageUri: String?) { + private fun sendMessage(message: ParcelableNewMessage) { val title = getString(R.string.sending_direct_message) val builder = Builder(this) builder.setSmallIcon(R.drawable.ic_stat_send) builder.setProgress(100, 0, true) builder.setTicker(title) builder.setContentTitle(title) - builder.setContentText(text) + builder.setContentText(message.text) builder.setCategory(NotificationCompat.CATEGORY_PROGRESS) builder.setOngoing(true) val notification = builder.build() @@ -192,12 +194,18 @@ class LengthyOperationsService : BaseIntentService("lengthy_operations") { val result = ManualTaskStarter.invokeExecute(task) invokeAfterExecute(task, result) - val resolver = contentResolver if (result.hasData()) { showOkMessage(R.string.message_direct_message_sent, false) } else { - val values = ContentValuesCreator.createMessageDraft(accountId, recipientId, text, imageUri) - resolver.insert(Drafts.CONTENT_URI, values) + UpdateStatusTask.saveDraft(this, Draft.Action.SEND_DIRECT_MESSAGE) { + account_keys = arrayOf(message.account.key) + text = message.text + media = message.media + action_extras = SendDirectMessageActionExtras().apply { + recipientId = message.recipient_id + conversationId = message.conversation_id + } + } showErrorMessage(R.string.action_sending_direct_message, result.exception, true) } stopForeground(false) @@ -216,10 +224,11 @@ class LengthyOperationsService : BaseIntentService("lengthy_operations") { return @Draft.Action val actionType = intent.getStringExtra(EXTRA_ACTION) - updateStatuses(actionType, *statuses) + statuses.forEach { it.draft_action = actionType } + updateStatuses(*statuses) } - private fun updateStatuses(@Draft.Action actionType: String, vararg statuses: ParcelableStatusUpdate) { + private fun updateStatuses(vararg statuses: ParcelableStatusUpdate) { val context = this val builder = Builder(context) startForeground(NOTIFICATION_ID_UPDATE_STATUS, updateUpdateStatusNotification(context, @@ -289,7 +298,7 @@ class LengthyOperationsService : BaseIntentService("lengthy_operations") { } }) task.callback = this - task.params = Pair(actionType, item) + task.params = item invokeBeforeExecute(task) val result = ManualTaskStarter.invokeExecute(task) @@ -387,7 +396,7 @@ class LengthyOperationsService : BaseIntentService("lengthy_operations") { } internal class MessageMediaUploadListener(private val context: Context, private val manager: NotificationManagerWrapper, - builder: NotificationCompat.Builder, private val message: String) : ReadListener { + builder: NotificationCompat.Builder, private val message: String) : ReadListener { var percent: Int = 0 @@ -411,8 +420,8 @@ class LengthyOperationsService : BaseIntentService("lengthy_operations") { private val BULK_SIZE = (128 * 1024).toLong() // 128KiB private fun updateSendDirectMessageNotification(context: Context, - builder: NotificationCompat.Builder, - progress: Int, message: String?): Notification { + builder: NotificationCompat.Builder, + progress: Int, message: String?): Notification { builder.setContentTitle(context.getString(R.string.sending_direct_message)) if (message != null) { builder.setContentText(message) @@ -424,9 +433,9 @@ class LengthyOperationsService : BaseIntentService("lengthy_operations") { } private fun updateUpdateStatusNotification(context: Context, - builder: NotificationCompat.Builder, - progress: Int, - status: ParcelableStatusUpdate?): Notification { + builder: NotificationCompat.Builder, + progress: Int, + status: ParcelableStatusUpdate?): Notification { builder.setContentTitle(context.getString(R.string.updating_status_notification)) if (status != null) { builder.setContentText(status.text) @@ -438,7 +447,7 @@ class LengthyOperationsService : BaseIntentService("lengthy_operations") { } fun updateStatusesAsync(context: Context, @Draft.Action action: String, - vararg statuses: ParcelableStatusUpdate) { + vararg statuses: ParcelableStatusUpdate) { val intent = Intent(context, LengthyOperationsService::class.java) intent.action = INTENT_ACTION_UPDATE_STATUS intent.putExtra(EXTRA_STATUSES, statuses) diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/task/GetMessagesTask.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/task/GetMessagesTask.kt index 511552dcd..4595f07ab 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/task/GetMessagesTask.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/task/GetMessagesTask.kt @@ -50,7 +50,7 @@ class GetMessagesTask( } catch (e: MicroBlogException) { return@forEachIndexed } - storeMessages(messages, details) + storeMessages(context, messages, details) } } @@ -59,7 +59,7 @@ class GetMessagesTask( bus.post(GetMessagesTaskEvent(Messages.CONTENT_URI, false, null)) } - private fun getMessages(microBlog: MicroBlog, details: AccountDetails, param: RefreshMessagesTaskParam, index: Int): GetMessagesData { + private fun getMessages(microBlog: MicroBlog, details: AccountDetails, param: RefreshMessagesTaskParam, index: Int): DatabaseUpdateData { when (details.type) { AccountType.FANFOU -> { // Use fanfou DM api @@ -77,25 +77,25 @@ class GetMessagesTask( } private fun getTwitterOfficialMessages(microBlog: MicroBlog, details: AccountDetails, - param: RefreshMessagesTaskParam, index: Int): GetMessagesData { + param: RefreshMessagesTaskParam, index: Int): DatabaseUpdateData { val conversationId = param.conversationId if (conversationId == null) { return getTwitterOfficialUserInbox(microBlog, details, param, index) } else { - return GetMessagesData(emptyList(), emptyList()) + return DatabaseUpdateData(emptyList(), emptyList()) } } - private fun getFanfouMessages(microBlog: MicroBlog, details: AccountDetails, param: RefreshMessagesTaskParam, index: Int): GetMessagesData { + 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) } else { - return GetMessagesData(emptyList(), emptyList()) + return DatabaseUpdateData(emptyList(), emptyList()) } } - private fun getDefaultMessages(microBlog: MicroBlog, details: AccountDetails, param: RefreshMessagesTaskParam, index: Int): GetMessagesData { + 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 @@ -137,7 +137,7 @@ class GetMessagesTask( conversationIds.add(ParcelableMessageUtils.outgoingConversationId(it.senderId, it.recipientId)) } - conversations.addLocalConversations(accountKey, conversationIds) + conversations.addLocalConversations(context, accountKey, conversationIds) received.forEachIndexed { i, dm -> val message = ParcelableMessageUtils.fromMessage(accountKey, dm, false, @@ -151,7 +151,7 @@ class GetMessagesTask( insertMessages.add(message) conversations.addConversation(message.conversation_id, details, message, setOf(dm.sender, dm.recipient)) } - return GetMessagesData(conversations.values, insertMessages) + return DatabaseUpdateData(conversations.values, insertMessages) } private fun getTwitterOfficialConversation(microBlog: MicroBlog, details: AccountDetails, @@ -159,8 +159,7 @@ class GetMessagesTask( } - private fun getTwitterOfficialUserInbox(microBlog: MicroBlog, details: AccountDetails, param: RefreshMessagesTaskParam, index: Int): GetMessagesData { - val accountKey = details.key + 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) { @@ -173,64 +172,11 @@ class GetMessagesTask( }).userInbox } - val respConversations = response.conversations.orEmpty() - val respEntries = response.entries.orEmpty() - val respUsers = response.users.orEmpty() - - val conversations = hashMapOf() - - respConversations.keys.let { - conversations.addLocalConversations(accountKey, it) - } - val messages = ArrayList() - val messageDeletionsMap = HashMap>() - val conversationDeletions = ArrayList() - respEntries.mapNotNullTo(messages) { entry -> - when { - entry.messageDelete != null -> { - val list = messageDeletionsMap.getOrPut(entry.messageDelete.conversationId) { ArrayList() } - entry.messageDelete.messages?.forEach { - list.add(it.messageId) - } - return@mapNotNullTo null - } - entry.removeConversation != null -> { - conversationDeletions.add(entry.removeConversation.conversationId) - return@mapNotNullTo null - } - else -> { - return@mapNotNullTo ParcelableMessageUtils.fromEntry(accountKey, entry, respUsers) - } - } - } - val messagesMap = messages.groupBy(ParcelableMessage::conversation_id) - for ((k, v) in respConversations) { - val message = messagesMap[k]?.maxBy(ParcelableMessage::message_timestamp) ?: continue - val participants = respUsers.filterKeys { userId -> - v.participants.any { it.userId == userId } - }.values - val conversationType = when (v.type?.toUpperCase(Locale.US)) { - DMResponse.Conversation.Type.ONE_TO_ONE -> ConversationType.ONE_TO_ONE - DMResponse.Conversation.Type.GROUP_DM -> ConversationType.GROUP - else -> ConversationType.ONE_TO_ONE - } - val conversation = conversations.addConversation(k, details, message, participants, - conversationType) - conversation.conversation_name = v.name - conversation.conversation_avatar = v.avatarImageHttps - conversation.request_cursor = response.cursor - conversation.conversation_extras_type = ParcelableMessageConversation.ExtrasType.TWITTER_OFFICIAL - conversation.conversation_extras = TwitterOfficialConversationExtras().apply { - this.minEntryId = v.minEntryId - this.maxEntryId = v.maxEntryId - this.status = v.status - } - } - return GetMessagesData(conversations.values, messages, conversationDeletions, - messageDeletionsMap, response.cursor) + return createDatabaseUpdateData(context, details, response) } - private fun getFanfouConversations(microBlog: MicroBlog, details: AccountDetails, param: RefreshMessagesTaskParam, index: Int): GetMessagesData { + + 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) @@ -244,7 +190,7 @@ class GetMessagesTask( val conversationIds = hashSetOf() result.mapTo(conversationIds) { "${accountKey.id}-${it.otherId}" } - conversations.addLocalConversations(accountKey, conversationIds) + conversations.addLocalConversations(context, accountKey, conversationIds) result.forEachIndexed { i, item -> val dm = item.dm // Sender is our self, treat as outgoing message @@ -254,116 +200,10 @@ class GetMessagesTask( setOf(dm.sender, dm.recipient)) mc.request_cursor = "page:$page" } - return GetMessagesData(conversations.values, emptyList()) + return DatabaseUpdateData(conversations.values, emptyList()) } - @SuppressLint("Recycle") - private fun MutableMap.addLocalConversations(accountKey: UserKey, conversationIds: Set) { - val where = Expression.and(Expression.inArgs(Conversations.CONVERSATION_ID, conversationIds.size), - Expression.equalsArgs(Conversations.ACCOUNT_KEY)).sql - val whereArgs = conversationIds.toTypedArray() + accountKey.toString() - return context.contentResolver.query(Conversations.CONTENT_URI, Conversations.COLUMNS, - where, whereArgs, null).useCursor { cur -> - val indices = ParcelableMessageConversationCursorIndices(cur) - cur.moveToFirst() - while (!cur.isAfterLast) { - val conversationId = cur.getString(indices.id) - val timestamp = cur.getLong(indices.local_timestamp) - val conversation = this[conversationId] ?: run { - val obj = indices.newObject(cur) - this[conversationId] = obj - return@run obj - } - if (timestamp > conversation.local_timestamp) { - this[conversationId] = indices.newObject(cur) - } - indices.newObject(cur) - cur.moveToNext() - } - } - } - - private fun ParcelableMessageConversation.addParticipant( - accountKey: UserKey, - user: User - ) { - val userKey = UserKeyUtils.fromUser(user) - val participants = this.participants - if (participants == null) { - this.participants = arrayOf(ParcelableUserUtils.fromUser(user, accountKey)) - } else { - val index = participants.indexOfFirst { it.key == userKey } - if (index >= 0) { - participants[index] = ParcelableUserUtils.fromUser(user, accountKey) - } else { - this.participants = participants + ParcelableUserUtils.fromUser(user, accountKey) - } - } - } - - private fun MutableMap.addConversation( - conversationId: String, - details: AccountDetails, - message: ParcelableMessage, - users: Collection, - conversationType: String = ConversationType.ONE_TO_ONE - ): ParcelableMessageConversation { - val conversation = this[conversationId] ?: run { - val obj = ParcelableMessageConversation() - obj.id = conversationId - obj.conversation_type = conversationType - obj.applyFrom(message, details) - this[conversationId] = obj - return@run obj - } - if (message.timestamp > conversation.timestamp) { - conversation.applyFrom(message, details) - } - users.forEach { user -> - conversation.addParticipant(details.key, user) - } - return conversation - } - - private fun storeMessages(data: GetMessagesData, details: AccountDetails) { - val resolver = context.contentResolver - val conversationsValues = data.conversations.map { - val values = ParcelableMessageConversationValuesCreator.create(it) - if (it._id > 0) { - values.put(Conversations._ID, it._id) - } - return@map values - } - val messagesValues = data.messages.map(ParcelableMessageValuesCreator::create) - - for ((conversationId, messageIds) in data.deleteMessages) { - val where = Expression.and(Expression.equalsArgs(Messages.ACCOUNT_KEY), - Expression.equalsArgs(Messages.CONVERSATION_ID)).sql - val whereArgs = arrayOf(details.key.toString(), conversationId) - ContentResolverUtils.bulkDelete(resolver, Messages.CONTENT_URI, Messages.MESSAGE_ID, - false, messageIds, where, whereArgs) - } - - val accountWhere = Expression.equalsArgs(Messages.ACCOUNT_KEY).sql - val accountWhereArgs = arrayOf(details.key.toString()) - - ContentResolverUtils.bulkDelete(resolver, Conversations.CONTENT_URI, Conversations.CONVERSATION_ID, - false, data.deleteConversations, accountWhere, accountWhereArgs) - ContentResolverUtils.bulkDelete(resolver, Messages.CONTENT_URI, Messages.CONVERSATION_ID, - false, data.deleteConversations, accountWhere, accountWhereArgs) - - ContentResolverUtils.bulkInsert(resolver, Conversations.CONTENT_URI, conversationsValues) - ContentResolverUtils.bulkInsert(resolver, Messages.CONTENT_URI, messagesValues) - - if (data.conversationRequestCursor != null) { - resolver.update(Conversations.CONTENT_URI, ContentValues().apply { - put(Conversations.REQUEST_CURSOR, data.conversationRequestCursor) - }, accountWhere, accountWhereArgs) - } - } - - - data class GetMessagesData( + data class DatabaseUpdateData( val conversations: Collection, val messages: Collection, val deleteConversations: List = emptyList(), @@ -462,5 +302,175 @@ class GetMessagesTask( get() = getAccountKeys() } + + companion object { + + fun createDatabaseUpdateData(context: Context, account: AccountDetails, + response: DMResponse): DatabaseUpdateData { + val respConversations = response.conversations.orEmpty() + val respEntries = response.entries.orEmpty() + val respUsers = response.users.orEmpty() + + val conversations = hashMapOf() + + respConversations.keys.let { + conversations.addLocalConversations(context, account.key, it) + } + val messages = ArrayList() + val messageDeletionsMap = HashMap>() + val conversationDeletions = ArrayList() + respEntries.mapNotNullTo(messages) { entry -> + when { + entry.messageDelete != null -> { + val list = messageDeletionsMap.getOrPut(entry.messageDelete.conversationId) { ArrayList() } + entry.messageDelete.messages?.forEach { + list.add(it.messageId) + } + return@mapNotNullTo null + } + entry.removeConversation != null -> { + conversationDeletions.add(entry.removeConversation.conversationId) + return@mapNotNullTo null + } + else -> { + return@mapNotNullTo ParcelableMessageUtils.fromEntry(account.key, entry, respUsers) + } + } + } + val messagesMap = messages.groupBy(ParcelableMessage::conversation_id) + for ((k, v) in respConversations) { + val message = messagesMap[k]?.maxBy(ParcelableMessage::message_timestamp) ?: continue + val participants = respUsers.filterKeys { userId -> + v.participants.any { it.userId == userId } + }.values + val conversationType = when (v.type?.toUpperCase(Locale.US)) { + DMResponse.Conversation.Type.ONE_TO_ONE -> ConversationType.ONE_TO_ONE + DMResponse.Conversation.Type.GROUP_DM -> ConversationType.GROUP + else -> ConversationType.ONE_TO_ONE + } + val conversation = conversations.addConversation(k, account, message, participants, + conversationType) + conversation.conversation_name = v.name + conversation.conversation_avatar = v.avatarImageHttps + conversation.request_cursor = response.cursor + conversation.conversation_extras_type = ParcelableMessageConversation.ExtrasType.TWITTER_OFFICIAL + conversation.conversation_extras = TwitterOfficialConversationExtras().apply { + this.minEntryId = v.minEntryId + this.maxEntryId = v.maxEntryId + this.status = v.status + } + } + return DatabaseUpdateData(conversations.values, messages, conversationDeletions, + messageDeletionsMap, response.cursor) + } + + fun storeMessages(context: Context, data: DatabaseUpdateData, details: AccountDetails) { + val resolver = context.contentResolver + val conversationsValues = data.conversations.map { + val values = ParcelableMessageConversationValuesCreator.create(it) + if (it._id > 0) { + values.put(Conversations._ID, it._id) + } + return@map values + } + val messagesValues = data.messages.map(ParcelableMessageValuesCreator::create) + + for ((conversationId, messageIds) in data.deleteMessages) { + val where = Expression.and(Expression.equalsArgs(Messages.ACCOUNT_KEY), + Expression.equalsArgs(Messages.CONVERSATION_ID)).sql + val whereArgs = arrayOf(details.key.toString(), conversationId) + ContentResolverUtils.bulkDelete(resolver, Messages.CONTENT_URI, Messages.MESSAGE_ID, + false, messageIds, where, whereArgs) + } + + val accountWhere = Expression.equalsArgs(Messages.ACCOUNT_KEY).sql + val accountWhereArgs = arrayOf(details.key.toString()) + + ContentResolverUtils.bulkDelete(resolver, Conversations.CONTENT_URI, Conversations.CONVERSATION_ID, + false, data.deleteConversations, accountWhere, accountWhereArgs) + ContentResolverUtils.bulkDelete(resolver, Messages.CONTENT_URI, Messages.CONVERSATION_ID, + false, data.deleteConversations, accountWhere, accountWhereArgs) + + ContentResolverUtils.bulkInsert(resolver, Conversations.CONTENT_URI, conversationsValues) + ContentResolverUtils.bulkInsert(resolver, Messages.CONTENT_URI, messagesValues) + + if (data.conversationRequestCursor != null) { + resolver.update(Conversations.CONTENT_URI, ContentValues().apply { + put(Conversations.REQUEST_CURSOR, data.conversationRequestCursor) + }, accountWhere, accountWhereArgs) + } + } + + + @SuppressLint("Recycle") + fun MutableMap.addLocalConversations(context: Context, + accountKey: UserKey, conversationIds: Set) { + val where = Expression.and(Expression.inArgs(Conversations.CONVERSATION_ID, conversationIds.size), + Expression.equalsArgs(Conversations.ACCOUNT_KEY)).sql + val whereArgs = conversationIds.toTypedArray() + accountKey.toString() + return context.contentResolver.query(Conversations.CONTENT_URI, Conversations.COLUMNS, + where, whereArgs, null).useCursor { cur -> + val indices = ParcelableMessageConversationCursorIndices(cur) + cur.moveToFirst() + while (!cur.isAfterLast) { + val conversationId = cur.getString(indices.id) + val timestamp = cur.getLong(indices.local_timestamp) + val conversation = this[conversationId] ?: run { + val obj = indices.newObject(cur) + this[conversationId] = obj + return@run obj + } + if (timestamp > conversation.local_timestamp) { + this[conversationId] = indices.newObject(cur) + } + indices.newObject(cur) + cur.moveToNext() + } + } + } + + private fun ParcelableMessageConversation.addParticipant( + accountKey: UserKey, + user: User + ) { + val userKey = UserKeyUtils.fromUser(user) + val participants = this.participants + if (participants == null) { + this.participants = arrayOf(ParcelableUserUtils.fromUser(user, accountKey)) + } else { + val index = participants.indexOfFirst { it.key == userKey } + if (index >= 0) { + participants[index] = ParcelableUserUtils.fromUser(user, accountKey) + } else { + this.participants = participants + ParcelableUserUtils.fromUser(user, accountKey) + } + } + } + + fun MutableMap.addConversation( + conversationId: String, + details: AccountDetails, + message: ParcelableMessage, + users: Collection, + conversationType: String = ConversationType.ONE_TO_ONE + ): ParcelableMessageConversation { + val conversation = this[conversationId] ?: run { + val obj = ParcelableMessageConversation() + obj.id = conversationId + obj.conversation_type = conversationType + obj.applyFrom(message, details) + this[conversationId] = obj + return@run obj + } + if (message.timestamp > conversation.timestamp) { + conversation.applyFrom(message, details) + } + users.forEach { user -> + conversation.addParticipant(details.key, user) + } + return conversation + } + + } } diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/task/SendMessageTask.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/task/SendMessageTask.kt index d283295df..d6d91cad5 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/task/SendMessageTask.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/task/SendMessageTask.kt @@ -1,17 +1,72 @@ package org.mariotaku.twidere.task import android.content.Context -import org.mariotaku.twidere.model.ParcelableMessage -import org.mariotaku.twidere.model.SingleResponse +import org.mariotaku.microblog.library.MicroBlog +import org.mariotaku.microblog.library.MicroBlogException +import org.mariotaku.microblog.library.twitter.model.DirectMessage +import org.mariotaku.microblog.library.twitter.model.NewDm +import org.mariotaku.twidere.annotation.AccountType +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.ParcelableNewMessage +import org.mariotaku.twidere.model.util.ParcelableMessageUtils +import org.mariotaku.twidere.task.GetMessagesTask.Companion.addConversation +import org.mariotaku.twidere.task.GetMessagesTask.Companion.addLocalConversations /** * Created by mariotaku on 2017/2/8. */ class SendMessageTask( context: Context -) : BaseAbstractTask, Unit>(context) { - override fun doLongOperation(params: Unit?): SingleResponse { - return SingleResponse(UnsupportedOperationException()) +) : ExceptionHandlingAbstractTask(context) { + override fun onExecute(params: ParcelableNewMessage) { + val account = params.account + val microBlog = account.newMicroBlogInstance(context, cls = MicroBlog::class.java) + val updateData = requestSendMessage(microBlog, account, params) + GetMessagesTask.storeMessages(context, updateData, account) } + fun requestSendMessage(microBlog: MicroBlog, account: AccountDetails, message: ParcelableNewMessage): GetMessagesTask.DatabaseUpdateData { + when (account.type) { + AccountType.TWITTER -> { + if (account.isOfficial(context)) { + return sendTwitterOfficialDM(microBlog, account, message) + } + } + AccountType.FANFOU -> { + return sendFanfouDM(microBlog, account, message) + } + } + return sendDefaultDM(microBlog, account, message) + } + + private fun sendTwitterOfficialDM(microBlog: MicroBlog, account: AccountDetails, message: ParcelableNewMessage): GetMessagesTask.DatabaseUpdateData { + val response = microBlog.sendDm(NewDm().apply { + setConversationId(message.conversation_id) + setText(message.text) + }) + return GetMessagesTask.createDatabaseUpdateData(context, account, response) + } + + private fun sendFanfouDM(microBlog: MicroBlog, account: AccountDetails, message: ParcelableNewMessage): GetMessagesTask.DatabaseUpdateData { + val response = microBlog.sendFanfouDirectMessage(message.recipient_id, message.text) + return createDatabaseUpdateData(account, response) + } + + private fun sendDefaultDM(microBlog: MicroBlog, account: AccountDetails, message: ParcelableNewMessage): GetMessagesTask.DatabaseUpdateData { + val response = microBlog.sendDirectMessage(message.recipient_id, message.text) + return createDatabaseUpdateData(account, response) + } + + private fun createDatabaseUpdateData(details: AccountDetails, dm: DirectMessage): GetMessagesTask.DatabaseUpdateData { + val accountKey = details.key + val conversationIds = setOf(ParcelableMessageUtils.outgoingConversationId(dm.senderId, dm.recipientId)) + val conversations = hashMapOf() + conversations.addLocalConversations(context, accountKey, conversationIds) + val message = ParcelableMessageUtils.fromMessage(accountKey, dm, true) + conversations.addConversation(message.conversation_id, details, message, setOf(dm.sender, dm.recipient)) + return GetMessagesTask.DatabaseUpdateData(conversations.values, listOf(message)) + } } \ No newline at end of file diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/UpdateStatusTask.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/UpdateStatusTask.kt index 542d218c3..84a887628 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/UpdateStatusTask.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/UpdateStatusTask.kt @@ -62,14 +62,14 @@ import java.util.concurrent.TimeUnit class UpdateStatusTask( context: Context, internal val stateCallback: UpdateStatusTask.StateCallback -) : BaseAbstractTask, UpdateStatusTask.UpdateStatusResult, Any?>(context) { +) : BaseAbstractTask(context) { - override fun doLongOperation(params: Pair): UpdateStatusResult { - val draftId = saveDraft(params.first, params.second) + override fun doLongOperation(params: ParcelableStatusUpdate): UpdateStatusResult { + val draftId = saveDraft(params) microBlogWrapper.addSendingDraftId(draftId) try { - val result = doUpdateStatus(params.second, draftId) - deleteOrUpdateDraft(params.second, result, draftId) + val result = doUpdateStatus(params, draftId) + deleteOrUpdateDraft(params, result, draftId) return result } catch (e: UpdateStatusException) { return UpdateStatusResult(e, draftId) @@ -85,16 +85,17 @@ class UpdateStatusTask( override fun afterExecute(handler: Any?, result: UpdateStatusResult) { stateCallback.afterExecute(result) if (params != null) { - logUpdateStatus(params.first, params.second, result) + logUpdateStatus(params, result) } } - private fun logUpdateStatus(actionType: String, statusUpdate: ParcelableStatusUpdate, result: UpdateStatusResult) { + private fun logUpdateStatus(statusUpdate: ParcelableStatusUpdate, result: UpdateStatusResult) { val mediaType = statusUpdate.media?.firstOrNull()?.type ?: ParcelableMedia.Type.UNKNOWN val hasLocation = statusUpdate.location != null val preciseLocation = statusUpdate.display_coordinates - Analyzer.log(UpdateStatus(result.accountTypes.firstOrNull(), actionType, mediaType, - hasLocation, preciseLocation, result.succeed, result.exceptions.firstOrNull() ?: result.exception)) + Analyzer.log(UpdateStatus(result.accountTypes.firstOrNull(), statusUpdate.draft_action, + mediaType, hasLocation, preciseLocation, result.succeed, + result.exceptions.firstOrNull() ?: result.exception)) } @Throws(UpdateStatusException::class) @@ -151,8 +152,8 @@ class UpdateStatusTask( @Throws(UploadException::class) private fun uploadMedia(uploader: MediaUploaderInterface?, - update: ParcelableStatusUpdate, - pendingUpdate: PendingStatusUpdate) { + update: ParcelableStatusUpdate, + pendingUpdate: PendingStatusUpdate) { stateCallback.onStartUploadingMedia() if (uploader == null) { uploadMediaWithDefaultProvider(update, pendingUpdate) @@ -163,8 +164,8 @@ class UpdateStatusTask( @Throws(UploadException::class) private fun uploadMediaWithExtension(uploader: MediaUploaderInterface, - update: ParcelableStatusUpdate, - pending: PendingStatusUpdate) { + update: ParcelableStatusUpdate, + pending: PendingStatusUpdate) { uploader.waitForService() val media: Array try { @@ -201,8 +202,8 @@ class UpdateStatusTask( @Throws(UpdateStatusException::class) private fun shortenStatus(shortener: StatusShortenerInterface?, - update: ParcelableStatusUpdate, - pending: PendingStatusUpdate) { + update: ParcelableStatusUpdate, + pending: PendingStatusUpdate) { if (shortener == null) return stateCallback.onShorteningStatus() val sharedShortened = HashMap() @@ -280,8 +281,8 @@ class UpdateStatusTask( @Throws(MicroBlogException::class, UploadException::class) private fun fanfouUpdateStatusWithPhoto(microBlog: MicroBlog, statusUpdate: ParcelableStatusUpdate, - pendingUpdate: PendingStatusUpdate, overrideText: String, - sizeLimit: SizeLimit, updateIndex: Int): Status { + pendingUpdate: PendingStatusUpdate, overrideText: String, + sizeLimit: SizeLimit, updateIndex: Int): Status { if (statusUpdate.media.size > 1) { throw MicroBlogException(context.getString(R.string.error_too_many_photos_fanfou)) } @@ -353,8 +354,8 @@ class UpdateStatusTask( @Throws(MicroBlogException::class) private fun twitterUpdateStatus(microBlog: MicroBlog, statusUpdate: ParcelableStatusUpdate, - pendingUpdate: PendingStatusUpdate, overrideText: String, - index: Int): Status { + pendingUpdate: PendingStatusUpdate, overrideText: String, + index: Int): Status { val status = StatusUpdate(overrideText) if (statusUpdate.in_reply_to_status != null) { status.inReplyToStatusId(statusUpdate.in_reply_to_status.id) @@ -500,7 +501,7 @@ class UpdateStatusTask( @Throws(IOException::class, MicroBlogException::class) private fun uploadMediaChucked(upload: TwitterUpload, body: Body, - ownerIds: Array): MediaUploadResponse { + ownerIds: Array): MediaUploadResponse { val mediaType = body.contentType().contentType val length = body.length() val stream = body.stream() @@ -550,11 +551,10 @@ class UpdateStatusTask( } } - private fun saveDraft(@Draft.Action draftAction: String?, statusUpdate: ParcelableStatusUpdate): Long { - return saveDraft(context, draftAction) { + private fun saveDraft(statusUpdate: ParcelableStatusUpdate): Long { + return saveDraft(context, statusUpdate.draft_action ?: Draft.Action.UPDATE_STATUS) { this.unique_id = statusUpdate.draft_unique_id ?: UUID.randomUUID().toString() this.account_keys = statusUpdate.accounts.map { it.key }.toTypedArray() - this.action_type = draftAction ?: Draft.Action.UPDATE_STATUS this.text = statusUpdate.text this.location = statusUpdate.location this.media = statusUpdate.media @@ -907,7 +907,7 @@ class UpdateStatusTask( val deleteAlways: List? ) - fun saveDraft(context: Context, @Draft.Action action: String?, config: Draft.() -> Unit): Long { + fun saveDraft(context: Context, @Draft.Action action: String, config: Draft.() -> Unit): Long { val draft = Draft() draft.action_type = action draft.timestamp = System.currentTimeMillis() diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/util/AsyncTwitterWrapper.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/util/AsyncTwitterWrapper.kt index 0a909ec40..0cebacc90 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/util/AsyncTwitterWrapper.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/util/AsyncTwitterWrapper.kt @@ -649,55 +649,6 @@ class AsyncTwitterWrapper( } - - internal inner class DestroyMessageConversationTask(private val mAccountKey: UserKey, private val mUserId: String) : ManagedAsyncTask>(context) { - - private fun deleteMessages(accountKey: UserKey, userId: String) { - val whereArgs = arrayOf(accountKey.toString(), userId) - resolver.delete(DirectMessages.Inbox.CONTENT_URI, Expression.and( - Expression.equalsArgs(AccountSupportColumns.ACCOUNT_KEY), - Expression.equalsArgs(Inbox.SENDER_ID) - ).sql, whereArgs) - resolver.delete(DirectMessages.Outbox.CONTENT_URI, Expression.and( - Expression.equalsArgs(AccountSupportColumns.ACCOUNT_KEY), - Expression.equalsArgs(Outbox.RECIPIENT_ID) - ).sql, whereArgs) - } - - private fun isMessageNotFound(e: Exception?): Boolean { - if (e !is MicroBlogException) return false - return e.errorCode == ErrorInfo.PAGE_NOT_FOUND || e.statusCode == HttpResponseCode.NOT_FOUND - } - - override fun doInBackground(vararg args: Any): SingleResponse { - val microBlog = MicroBlogAPIFactory.getInstance(context, mAccountKey) ?: return SingleResponse(MicroBlogException("No account")) - try { - microBlog.destroyDirectMessagesConversation(mAccountKey.id, mUserId) - deleteMessages(mAccountKey, mUserId) - return SingleResponse(true) - } catch (e: MicroBlogException) { - if (isMessageNotFound(e)) { - deleteMessages(mAccountKey, mUserId) - } - return SingleResponse(e) - } - - } - - - override fun onPostExecute(result: SingleResponse) { - super.onPostExecute(result) - if (result.hasData() || isMessageNotFound(result.exception)) { - Utils.showInfoMessage(context, R.string.message_direct_message_deleted, false) - } else { - Utils.showErrorMessage(context, R.string.action_deleting, result.exception, true) - } - } - - - } - - internal inner class DestroySavedSearchTask( context: Context, private val accountKey: UserKey, diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/util/DirectMessageOnLinkClickHandler.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/util/DirectMessageOnLinkClickHandler.kt index f3f1a55e0..69caaa3ac 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/util/DirectMessageOnLinkClickHandler.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/util/DirectMessageOnLinkClickHandler.kt @@ -20,18 +20,19 @@ package org.mariotaku.twidere.util import android.content.Context +import android.content.SharedPreferences import android.net.Uri import android.os.Bundle import android.support.v4.app.FragmentActivity -import org.mariotaku.twidere.TwidereConstants.SHARED_PREFERENCES_NAME +import org.mariotaku.kpreferences.get import org.mariotaku.twidere.constant.IntentConstants.EXTRA_URI -import org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_PHISHING_LINK_WARNING +import org.mariotaku.twidere.constant.phishingLinksWaringKey import org.mariotaku.twidere.fragment.PhishingLinkWarningDialogFragment class DirectMessageOnLinkClickHandler( context: Context, manager: MultiSelectManager?, - preferences: SharedPreferencesWrapper + preferences: SharedPreferences ) : OnLinkClickHandler(context, manager, preferences) { override val isPrivateData: Boolean @@ -43,8 +44,7 @@ class DirectMessageOnLinkClickHandler( super.openLink(link) return } - val prefs = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE) - if (context is FragmentActivity && prefs.getBoolean(KEY_PHISHING_LINK_WARNING, true)) { + if (context is FragmentActivity && preferences[phishingLinksWaringKey]) { val fm = context.supportFragmentManager val fragment = PhishingLinkWarningDialogFragment() val args = Bundle() diff --git a/twidere/src/main/res/layout/list_item_message_conversation_text.xml b/twidere/src/main/res/layout/list_item_message_conversation_text.xml index 9c56ca20a..e026109ff 100644 --- a/twidere/src/main/res/layout/list_item_message_conversation_text.xml +++ b/twidere/src/main/res/layout/list_item_message_conversation_text.xml @@ -62,11 +62,10 @@ app:caretWidth="@dimen/element_spacing_normal" app:cornerRadius="2dp"> - - - +