implementing new dm conversation
This commit is contained in:
parent
5922873e4c
commit
9c7a62f447
|
@ -140,6 +140,14 @@ public class ParcelableMessageConversation implements Parcelable {
|
|||
@CursorField(value = Conversations.REQUEST_CURSOR)
|
||||
public String request_cursor;
|
||||
|
||||
/**
|
||||
* True if this is a temporary conversation, i.e. Created by user but haven't send any message
|
||||
* yet.
|
||||
*/
|
||||
@JsonField(name = "is_temp")
|
||||
@CursorField(value = Conversations.IS_TEMP)
|
||||
public boolean is_temp;
|
||||
|
||||
@JsonField(name = "message_extras")
|
||||
@ParcelableNoThanks
|
||||
ParcelableMessage.InternalExtras internalMessageExtras;
|
||||
|
@ -191,6 +199,7 @@ public class ParcelableMessageConversation implements Parcelable {
|
|||
", recipient_key=" + recipient_key +
|
||||
", is_outgoing=" + is_outgoing +
|
||||
", request_cursor='" + request_cursor + '\'' +
|
||||
", is_temp=" + is_temp +
|
||||
", internalMessageExtras=" + internalMessageExtras +
|
||||
", internalConversationExtras=" + internalConversationExtras +
|
||||
'}';
|
||||
|
|
|
@ -29,6 +29,8 @@ import com.bluelinelabs.logansquare.annotation.JsonObject;
|
|||
import com.hannesdorfmann.parcelableplease.annotation.ParcelablePlease;
|
||||
import com.hannesdorfmann.parcelableplease.annotation.ParcelableThisPlease;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/2/14.
|
||||
*/
|
||||
|
@ -58,6 +60,23 @@ public class ParcelableNewMessage implements Parcelable {
|
|||
@ParcelableThisPlease
|
||||
@Draft.Action
|
||||
public String draft_action;
|
||||
@JsonField(name = "is_temp_conversation")
|
||||
@ParcelableThisPlease
|
||||
public boolean is_temp_conversation;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ParcelableNewMessage{" +
|
||||
"account=" + account +
|
||||
", conversation_id='" + conversation_id + '\'' +
|
||||
", recipient_ids=" + Arrays.toString(recipient_ids) +
|
||||
", text='" + text + '\'' +
|
||||
", media=" + Arrays.toString(media) +
|
||||
", draft_unique_id='" + draft_unique_id + '\'' +
|
||||
", draft_action='" + draft_action + '\'' +
|
||||
", is_temp_conversation=" + is_temp_conversation +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
|
|
|
@ -398,6 +398,7 @@ public interface TwidereDataStore {
|
|||
String RECIPIENT_KEY = "recipient_key";
|
||||
String REQUEST_CURSOR = "request_cursor";
|
||||
String IS_OUTGOING = "is_outgoing";
|
||||
String IS_TEMP = "is_temp";
|
||||
String CONVERSATION_EXTRAS = "conversation_extras";
|
||||
String CONVERSATION_EXTRAS_TYPE = "conversation_extras_type";
|
||||
|
||||
|
|
|
@ -56,6 +56,8 @@ android {
|
|||
}
|
||||
buildTypes {
|
||||
debug {
|
||||
minifyEnabled false
|
||||
shrinkResources false
|
||||
resValue("bool", "debug", "true")
|
||||
}
|
||||
release {
|
||||
|
|
|
@ -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 = 175;
|
||||
int DATABASES_VERSION = 176;
|
||||
|
||||
int EXTRA_FEATURES_NOTICE_VERSION = 0;
|
||||
|
||||
|
|
|
@ -42,6 +42,9 @@ public class DefaultFeatures {
|
|||
@JsonField(name = "twitter_direct_message_media_limit")
|
||||
long twitterDirectMessageMediaLimit = 1;
|
||||
|
||||
@JsonField(name = "twitter_direct_message_max_participants")
|
||||
long twitterDirectMessageMaxParticipants = 20;
|
||||
|
||||
public boolean isMediaLinkCountsInStatus() {
|
||||
return mediaLinkCountsInStatus;
|
||||
}
|
||||
|
@ -58,6 +61,10 @@ public class DefaultFeatures {
|
|||
return twitterDirectMessageMediaLimit;
|
||||
}
|
||||
|
||||
public long getTwitterDirectMessageMaxParticipants() {
|
||||
return twitterDirectMessageMaxParticipants;
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
public boolean loadRemoteSettings(RestHttpClient client) throws IOException {
|
||||
HttpRequest request = new HttpRequest.Builder().method(GET.METHOD).url(REMOTE_SETTINGS_URL).build();
|
||||
|
|
|
@ -97,7 +97,7 @@ class UserSelectorActivity : BaseActivity(), OnItemClickListener, LoaderManager.
|
|||
if (!fromCache) {
|
||||
showProgress()
|
||||
}
|
||||
return CacheUserSearchLoader(this, accountKey, query, fromCache, true)
|
||||
return CacheUserSearchLoader(this, accountKey, query, !fromCache, true, true)
|
||||
}
|
||||
|
||||
override fun onLoaderReset(loader: Loader<List<ParcelableUser>>) {
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
package org.mariotaku.twidere.fragment.message
|
||||
|
||||
import android.accounts.AccountManager
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Paint
|
||||
import android.graphics.RectF
|
||||
|
@ -30,22 +31,28 @@ import android.text.Editable
|
|||
import android.text.Spannable
|
||||
import android.text.TextUtils
|
||||
import android.text.style.ReplacementSpan
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.*
|
||||
import kotlinx.android.synthetic.main.fragment_messages_conversation_new.*
|
||||
import org.mariotaku.kpreferences.get
|
||||
import org.mariotaku.ktextension.Bundle
|
||||
import org.mariotaku.ktextension.set
|
||||
import org.mariotaku.ktextension.setItemAvailability
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.adapter.SelectableUsersAdapter
|
||||
import org.mariotaku.twidere.constant.IntentConstants.*
|
||||
import org.mariotaku.twidere.constant.nameFirstKey
|
||||
import org.mariotaku.twidere.extension.model.isOfficial
|
||||
import org.mariotaku.twidere.fragment.BaseFragment
|
||||
import org.mariotaku.twidere.loader.CacheUserSearchLoader
|
||||
import org.mariotaku.twidere.model.ParcelableMessageConversation
|
||||
import org.mariotaku.twidere.model.ParcelableMessageConversation.ConversationType
|
||||
import org.mariotaku.twidere.model.ParcelableMessageConversationValuesCreator
|
||||
import org.mariotaku.twidere.model.ParcelableUser
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
import org.mariotaku.twidere.model.util.AccountUtils
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Messages.Conversations
|
||||
import org.mariotaku.twidere.text.MarkForDeleteSpan
|
||||
import org.mariotaku.twidere.util.IntentUtils
|
||||
import org.mariotaku.twidere.util.view.SimpleTextWatcher
|
||||
|
||||
/**
|
||||
|
@ -53,13 +60,24 @@ import org.mariotaku.twidere.util.view.SimpleTextWatcher
|
|||
*/
|
||||
class MessageNewConversationFragment : BaseFragment(), LoaderCallbacks<List<ParcelableUser>?> {
|
||||
|
||||
private val accountKey: UserKey get() = arguments.getParcelable(EXTRA_ACCOUNT_KEY)
|
||||
private val accountKey by lazy { arguments.getParcelable<UserKey>(EXTRA_ACCOUNT_KEY) }
|
||||
private val account by lazy {
|
||||
AccountUtils.getAccountDetails(AccountManager.get(context), accountKey, true)
|
||||
}
|
||||
|
||||
private val selectedRecipients: List<ParcelableUser>
|
||||
get() {
|
||||
val text = editParticipants.editableText ?: return emptyList()
|
||||
return text.getSpans(0, text.length, ParticipantSpan::class.java).map(ParticipantSpan::user)
|
||||
}
|
||||
|
||||
private var loaderInitialized: Boolean = false
|
||||
|
||||
private lateinit var usersAdapter: SelectableUsersAdapter
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
setHasOptionsMenu(true)
|
||||
usersAdapter = SelectableUsersAdapter(context)
|
||||
recyclerView.adapter = usersAdapter
|
||||
recyclerView.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
|
||||
|
@ -92,6 +110,7 @@ class MessageNewConversationFragment : BaseFragment(), LoaderCallbacks<List<Parc
|
|||
s.removeSpan(span)
|
||||
s.setSpan(MarkForDeleteSpan(), deleteStart, deleteEnd,
|
||||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
updateCheckState()
|
||||
}
|
||||
}
|
||||
val spaceNextStart = run {
|
||||
|
@ -156,7 +175,7 @@ class MessageNewConversationFragment : BaseFragment(), LoaderCallbacks<List<Parc
|
|||
val query = args.getString(EXTRA_QUERY)
|
||||
val fromCache = args.getBoolean(EXTRA_FROM_CACHE)
|
||||
val fromUser = args.getBoolean(EXTRA_FROM_USER)
|
||||
return CacheUserSearchLoader(context, accountKey, query, fromCache, fromUser)
|
||||
return CacheUserSearchLoader(context, accountKey, query, !fromCache, true, fromUser)
|
||||
}
|
||||
|
||||
override fun onLoaderReset(loader: Loader<List<ParcelableUser>?>) {
|
||||
|
@ -168,6 +187,55 @@ class MessageNewConversationFragment : BaseFragment(), LoaderCallbacks<List<Parc
|
|||
updateCheckState()
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
inflater.inflate(R.menu.menu_messages_conversation_new, menu)
|
||||
}
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||
menu.setItemAvailability(R.id.create_conversation, selectedRecipients.isNotEmpty())
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.create_conversation -> {
|
||||
createConversation()
|
||||
return true
|
||||
}
|
||||
}
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
private fun createConversation() {
|
||||
val account = this.account ?: return
|
||||
val selected = this.selectedRecipients
|
||||
if (selected.isEmpty()) return
|
||||
val maxParticipants = if (account.isOfficial(context)) {
|
||||
defaultFeatures.twitterDirectMessageMaxParticipants
|
||||
} else {
|
||||
1
|
||||
}
|
||||
if (selected.size > maxParticipants) {
|
||||
editParticipants.error = getString(R.string.error_message_message_too_many_participants)
|
||||
return
|
||||
}
|
||||
val conversation = ParcelableMessageConversation()
|
||||
conversation.account_color = account.color
|
||||
conversation.account_key = account.key
|
||||
conversation.id = "twidere:temp:${System.currentTimeMillis()}"
|
||||
conversation.local_timestamp = System.currentTimeMillis()
|
||||
conversation.conversation_type = if (selected.size > 1) {
|
||||
ConversationType.ONE_TO_ONE
|
||||
} else {
|
||||
ConversationType.GROUP
|
||||
}
|
||||
conversation.participants = (selected + account.user).toTypedArray()
|
||||
conversation.is_temp = true
|
||||
val values = ParcelableMessageConversationValuesCreator.create(conversation)
|
||||
context.contentResolver.insert(Conversations.CONTENT_URI, values)
|
||||
activity.startActivity(IntentUtils.messageConversation(accountKey, conversation.id))
|
||||
activity.finish()
|
||||
}
|
||||
|
||||
private fun updateCheckState() {
|
||||
val selected = selectedRecipients
|
||||
usersAdapter.clearCheckState()
|
||||
|
@ -175,6 +243,7 @@ class MessageNewConversationFragment : BaseFragment(), LoaderCallbacks<List<Parc
|
|||
usersAdapter.setCheckState(user.key, true)
|
||||
}
|
||||
usersAdapter.notifyDataSetChanged()
|
||||
activity?.supportInvalidateOptionsMenu()
|
||||
}
|
||||
|
||||
private fun searchUser(query: String, fromCache: Boolean) {
|
||||
|
@ -194,11 +263,6 @@ class MessageNewConversationFragment : BaseFragment(), LoaderCallbacks<List<Parc
|
|||
}
|
||||
}
|
||||
|
||||
private val selectedRecipients: List<ParcelableUser>
|
||||
get() {
|
||||
val text = editParticipants.editableText ?: return emptyList()
|
||||
return text.getSpans(0, text.length, ParticipantSpan::class.java).map(ParticipantSpan::user)
|
||||
}
|
||||
|
||||
class PendingQuerySpan
|
||||
|
||||
|
|
|
@ -37,11 +37,13 @@ import kotlinx.android.synthetic.main.fragment_messages_conversation.*
|
|||
import org.mariotaku.abstask.library.TaskStarter
|
||||
import org.mariotaku.kpreferences.get
|
||||
import org.mariotaku.ktextension.empty
|
||||
import org.mariotaku.ktextension.set
|
||||
import org.mariotaku.pickncrop.library.MediaPickerActivity
|
||||
import org.mariotaku.sqliteqb.library.Expression
|
||||
import org.mariotaku.sqliteqb.library.OrderBy
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.TwidereConstants.REQUEST_PICK_MEDIA
|
||||
import org.mariotaku.twidere.activity.LinkHandlerActivity
|
||||
import org.mariotaku.twidere.activity.ThemedMediaPickerActivity
|
||||
import org.mariotaku.twidere.adapter.MediaPreviewAdapter
|
||||
import org.mariotaku.twidere.adapter.MessagesConversationAdapter
|
||||
|
@ -56,6 +58,7 @@ import org.mariotaku.twidere.loader.ObjectCursorLoader
|
|||
import org.mariotaku.twidere.model.*
|
||||
import org.mariotaku.twidere.model.ParcelableMessageConversation.ConversationType
|
||||
import org.mariotaku.twidere.model.event.GetMessagesTaskEvent
|
||||
import org.mariotaku.twidere.model.event.SendMessageTaskEvent
|
||||
import org.mariotaku.twidere.model.util.AccountUtils
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Messages
|
||||
import org.mariotaku.twidere.service.LengthyOperationsService
|
||||
|
@ -252,6 +255,19 @@ class MessagesConversationFragment : AbsContentListRecyclerViewFragment<Messages
|
|||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onSendMessageTaskEvent(event: SendMessageTaskEvent) {
|
||||
if (event.success || event.accountKey != accountKey || event.conversationId != conversationId) {
|
||||
return
|
||||
}
|
||||
val newConversationId = event.newConversationId ?: return
|
||||
arguments[EXTRA_CONVERSATION_ID] = newConversationId
|
||||
if (activity is LinkHandlerActivity) {
|
||||
activity.intent = IntentUtils.messageConversation(accountKey, newConversationId)
|
||||
}
|
||||
loaderManager.restartLoader(0, null, this)
|
||||
}
|
||||
|
||||
private fun performSendMessage() {
|
||||
val conversation = adapter.conversation ?: return
|
||||
val conversationAccount = this.account ?: return
|
||||
|
|
|
@ -89,7 +89,8 @@ class MessagesEntriesFragment : AbsContentListRecyclerViewFragment<MessagesEntri
|
|||
loader.selection = Expression.inArgs(Conversations.ACCOUNT_KEY, accountKeys.size).sql
|
||||
loader.selectionArgs = accountKeys.toStringArray()
|
||||
loader.projection = Conversations.COLUMNS
|
||||
loader.sortOrder = OrderBy(Conversations.SORT_ID, false).sql
|
||||
loader.sortOrder = OrderBy(arrayOf(Conversations.LOCAL_TIMESTAMP,
|
||||
Conversations.SORT_ID), booleanArrayOf(false, false)).sql
|
||||
return loader
|
||||
}
|
||||
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
package org.mariotaku.twidere.loader
|
||||
|
||||
import android.content.Context
|
||||
import android.text.TextUtils
|
||||
import org.mariotaku.microblog.library.MicroBlog
|
||||
import org.mariotaku.microblog.library.twitter.model.User
|
||||
import org.mariotaku.sqliteqb.library.Columns
|
||||
import org.mariotaku.sqliteqb.library.Expression
|
||||
import org.mariotaku.sqliteqb.library.OrderBy
|
||||
import org.mariotaku.twidere.model.AccountDetails
|
||||
import org.mariotaku.twidere.model.ParcelableUser
|
||||
import org.mariotaku.twidere.model.ParcelableUserCursorIndices
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.CachedUsers
|
||||
import org.mariotaku.twidere.util.UserColorNameManager
|
||||
import org.mariotaku.twidere.util.Utils
|
||||
import org.mariotaku.twidere.util.dagger.GeneralComponentHelper
|
||||
import java.text.Collator
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -19,6 +21,7 @@ class CacheUserSearchLoader(
|
|||
context: Context,
|
||||
accountKey: UserKey,
|
||||
query: String,
|
||||
private val fromNetwork: Boolean,
|
||||
private val fromCache: Boolean,
|
||||
fromUser: Boolean
|
||||
) : UserSearchLoader(context, accountKey, query, 0, null, fromUser) {
|
||||
|
@ -29,31 +32,35 @@ class CacheUserSearchLoader(
|
|||
GeneralComponentHelper.build(context).inject(this)
|
||||
}
|
||||
|
||||
override fun loadInBackground(): List<ParcelableUser> {
|
||||
if (TextUtils.isEmpty(query)) return emptyList()
|
||||
if (fromCache) {
|
||||
val cachedList = ArrayList<ParcelableUser>()
|
||||
val queryEscaped = query.replace("_", "^_")
|
||||
val nicknameKeys = Utils.getMatchedNicknameKeys(query, userColorNameManager)
|
||||
val selection = Expression.or(Expression.likeRaw(Columns.Column(TwidereDataStore.CachedUsers.SCREEN_NAME), "?||'%'", "^"),
|
||||
Expression.likeRaw(Columns.Column(TwidereDataStore.CachedUsers.NAME), "?||'%'", "^"),
|
||||
Expression.inArgs(Columns.Column(TwidereDataStore.CachedUsers.USER_KEY), nicknameKeys.size))
|
||||
val selectionArgs = arrayOf(queryEscaped, queryEscaped, *nicknameKeys)
|
||||
val order = arrayOf(TwidereDataStore.CachedUsers.LAST_SEEN, TwidereDataStore.CachedUsers.SCREEN_NAME, TwidereDataStore.CachedUsers.NAME)
|
||||
val ascending = booleanArrayOf(false, true, true)
|
||||
val orderBy = OrderBy(order, ascending)
|
||||
val c = context.contentResolver.query(TwidereDataStore.CachedUsers.CONTENT_URI,
|
||||
TwidereDataStore.CachedUsers.BASIC_COLUMNS, selection?.sql,
|
||||
selectionArgs, orderBy.sql)!!
|
||||
val i = ParcelableUserCursorIndices(c)
|
||||
c.moveToFirst()
|
||||
while (!c.isAfterLast) {
|
||||
cachedList.add(i.newObject(c))
|
||||
c.moveToNext()
|
||||
override fun getUsers(twitter: MicroBlog, details: AccountDetails): List<User> {
|
||||
if (query.isEmpty() || !fromNetwork) return emptyList()
|
||||
return super.getUsers(twitter, details)
|
||||
}
|
||||
|
||||
override fun processUsersData(list: MutableList<ParcelableUser>) {
|
||||
if (query.isEmpty() || !fromCache) return
|
||||
val queryEscaped = query.replace("_", "^_")
|
||||
val nicknameKeys = Utils.getMatchedNicknameKeys(query, userColorNameManager)
|
||||
val selection = Expression.or(Expression.likeRaw(Columns.Column(CachedUsers.SCREEN_NAME), "?||'%'", "^"),
|
||||
Expression.likeRaw(Columns.Column(CachedUsers.NAME), "?||'%'", "^"),
|
||||
Expression.inArgs(Columns.Column(CachedUsers.USER_KEY), nicknameKeys.size))
|
||||
val selectionArgs = arrayOf(queryEscaped, queryEscaped, *nicknameKeys)
|
||||
val c = context.contentResolver.query(CachedUsers.CONTENT_URI, CachedUsers.BASIC_COLUMNS,
|
||||
selection.sql, selectionArgs, null)!!
|
||||
val i = ParcelableUserCursorIndices(c)
|
||||
c.moveToFirst()
|
||||
while (!c.isAfterLast) {
|
||||
if (list.none { it.key.toString() == c.getString(i.key) }) {
|
||||
list.add(i.newObject(c))
|
||||
}
|
||||
c.close()
|
||||
return cachedList
|
||||
c.moveToNext()
|
||||
}
|
||||
return super.loadInBackground()
|
||||
c.close()
|
||||
val collator = Collator.getInstance()
|
||||
list.sortWith(Comparator { l, r ->
|
||||
val compare = collator.compare(l.name, r.name)
|
||||
if (compare != 0) return@Comparator compare
|
||||
return@Comparator l.screen_name.compareTo(r.screen_name)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -69,7 +69,7 @@ abstract class MicroBlogAPIUsersLoader(
|
|||
data.add(item)
|
||||
pos++
|
||||
}
|
||||
Collections.sort(data)
|
||||
processUsersData(data)
|
||||
return ListResponse.getListInstance(data)
|
||||
}
|
||||
|
||||
|
@ -79,4 +79,8 @@ abstract class MicroBlogAPIUsersLoader(
|
|||
|
||||
@Throws(MicroBlogException::class)
|
||||
protected abstract fun getUsers(twitter: MicroBlog, details: AccountDetails): List<User>
|
||||
|
||||
protected open fun processUsersData(list: MutableList<ParcelableUser>) {
|
||||
Collections.sort(data)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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.model.event
|
||||
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/2/16.
|
||||
*/
|
||||
data class SendMessageTaskEvent(
|
||||
val accountKey: UserKey,
|
||||
val conversationId: String?,
|
||||
val newConversationId: String?,
|
||||
val success: Boolean
|
||||
)
|
|
@ -329,9 +329,7 @@ class GetMessagesTask(
|
|||
|
||||
val conversations = hashMapOf<String, ParcelableMessageConversation>()
|
||||
|
||||
respConversations.keys.let {
|
||||
conversations.addLocalConversations(context, account.key, it)
|
||||
}
|
||||
conversations.addLocalConversations(context, account.key, respConversations.keys)
|
||||
val messages = ArrayList<ParcelableMessage>()
|
||||
val messageDeletionsMap = HashMap<String, ArrayList<String>>()
|
||||
val conversationDeletions = ArrayList<String>()
|
||||
|
|
|
@ -27,13 +27,16 @@ import org.mariotaku.microblog.library.twitter.TwitterUpload
|
|||
import org.mariotaku.microblog.library.twitter.model.DirectMessage
|
||||
import org.mariotaku.microblog.library.twitter.model.NewDm
|
||||
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.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.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.GetMessagesTask
|
||||
import org.mariotaku.twidere.task.GetMessagesTask.Companion.addConversation
|
||||
|
@ -45,15 +48,33 @@ import org.mariotaku.twidere.task.twitter.UpdateStatusTask
|
|||
*/
|
||||
class SendMessageTask(
|
||||
context: Context
|
||||
) : ExceptionHandlingAbstractTask<ParcelableNewMessage, Unit, MicroBlogException, Unit>(context) {
|
||||
override fun onExecute(params: ParcelableNewMessage) {
|
||||
) : ExceptionHandlingAbstractTask<ParcelableNewMessage, SendMessageTask.SendMessageResult, MicroBlogException, Unit>(context) {
|
||||
|
||||
override fun onExecute(params: ParcelableNewMessage): SendMessageResult {
|
||||
val account = params.account
|
||||
val microBlog = account.newMicroBlogInstance(context, cls = MicroBlog::class.java)
|
||||
val updateData = requestSendMessage(microBlog, account, params)
|
||||
if (params.is_temp_conversation && params.conversation_id != null) {
|
||||
val deleteTempWhere = Expression.and(Expression.equalsArgs(Conversations.ACCOUNT_KEY),
|
||||
Expression.equalsArgs(Conversations.CONVERSATION_ID)).sql
|
||||
val deleteTempWhereArgs = arrayOf(account.key.toString(), params.conversation_id)
|
||||
context.contentResolver.delete(Conversations.CONTENT_URI, deleteTempWhere,
|
||||
deleteTempWhereArgs)
|
||||
}
|
||||
GetMessagesTask.storeMessages(context, updateData, account)
|
||||
return SendMessageResult(updateData.conversations.map { it.id })
|
||||
}
|
||||
|
||||
fun requestSendMessage(microBlog: MicroBlog, account: AccountDetails, message: ParcelableNewMessage): GetMessagesTask.DatabaseUpdateData {
|
||||
override fun onException(callback: Unit?, exception: MicroBlogException) {
|
||||
bus.post(SendMessageTaskEvent(params.account.key, params.conversation_id, null, false))
|
||||
}
|
||||
|
||||
override fun onSucceed(callback: Unit?, result: SendMessageResult) {
|
||||
bus.post(SendMessageTaskEvent(params.account.key, params.conversation_id,
|
||||
result.conversationIds.singleOrNull(), true))
|
||||
}
|
||||
|
||||
private fun requestSendMessage(microBlog: MicroBlog, account: AccountDetails, message: ParcelableNewMessage): GetMessagesTask.DatabaseUpdateData {
|
||||
when (account.type) {
|
||||
AccountType.TWITTER -> {
|
||||
if (account.isOfficial(context)) {
|
||||
|
@ -71,9 +92,11 @@ class SendMessageTask(
|
|||
var deleteOnSuccess: List<UpdateStatusTask.MediaDeletionItem>? = null
|
||||
var deleteAlways: List<UpdateStatusTask.MediaDeletionItem>? = null
|
||||
val response = try {
|
||||
val newDm = NewDm()
|
||||
val conversationId = message.conversation_id
|
||||
if (conversationId != null) {
|
||||
val tempConversation = message.is_temp_conversation
|
||||
|
||||
val newDm = NewDm()
|
||||
if (!tempConversation && conversationId != null) {
|
||||
newDm.setConversationId(conversationId)
|
||||
} else {
|
||||
newDm.setRecipientIds(message.recipient_ids)
|
||||
|
@ -118,4 +141,8 @@ class SendMessageTask(
|
|||
conversations.addConversation(message.conversation_id, details, message, setOf(dm.sender, dm.recipient))
|
||||
return GetMessagesTask.DatabaseUpdateData(conversations.values, listOf(message))
|
||||
}
|
||||
|
||||
class SendMessageResult(var conversationIds: List<String>) {
|
||||
|
||||
}
|
||||
}
|
|
@ -228,6 +228,10 @@ object IntentUtils {
|
|||
}
|
||||
|
||||
fun openMessageConversation(context: Context, accountKey: UserKey, conversationId: String) {
|
||||
context.startActivity(messageConversation(accountKey, conversationId))
|
||||
}
|
||||
|
||||
fun messageConversation(accountKey: UserKey, conversationId: String): Intent {
|
||||
val builder = Uri.Builder()
|
||||
builder.scheme(SCHEME_TWIDERE)
|
||||
builder.authority(AUTHORITY_MESSAGES)
|
||||
|
@ -236,7 +240,7 @@ object IntentUtils {
|
|||
builder.appendQueryParameter(QUERY_PARAM_CONVERSATION_ID, conversationId)
|
||||
val intent = Intent(Intent.ACTION_VIEW, builder.build())
|
||||
intent.`package` = BuildConfig.APPLICATION_ID
|
||||
context.startActivity(intent)
|
||||
return intent
|
||||
}
|
||||
|
||||
fun messageConversationInfo(accountKey: UserKey, conversationId: String): Intent {
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ 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/>.
|
||||
-->
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/create_conversation"
|
||||
android:icon="@drawable/ic_action_confirm"
|
||||
android:title="@string/action_create_conversation"
|
||||
app:showAsAction="always"/>
|
||||
</menu>
|
|
@ -25,6 +25,7 @@
|
|||
<string name="action_center">Center</string>
|
||||
<string name="action_clear">Clear</string>
|
||||
<string name="action_compose">Compose</string>
|
||||
<string name="action_create_conversation">Create conversation</string>
|
||||
<string name="action_creating_list">creating list</string>
|
||||
<!-- [verb] Action for deleting a file or a twitter object like tweet-->
|
||||
<string name="action_delete">Delete</string>
|
||||
|
@ -428,6 +429,7 @@
|
|||
<string name="error_message_media_upload_failed">Media upload failed.</string>
|
||||
<string name="error_message_media_uploader_not_found">Media uploader not found, maybe it was uninstalled.</string>
|
||||
<string name="error_message_message_too_long">Message too long</string>
|
||||
<string name="error_message_message_too_many_participants">Too many participants</string>
|
||||
<string name="error_message_no_content">No content</string>
|
||||
<string
|
||||
name="error_message_rate_limit">Twitter\'s rate limit exceeded, please retry <xliff:g id="time">%s</xliff:g>
|
||||
|
|
Loading…
Reference in New Issue