opens existing conversation when participants are the same

This commit is contained in:
Mariotaku Lee 2017-02-26 12:46:19 +08:00
parent 5e4476c903
commit 2d070b11a6
No known key found for this signature in database
GPG Key ID: 15C10F89D7C33535
5 changed files with 68 additions and 5 deletions

View File

@ -21,6 +21,7 @@
package org.mariotaku.twidere.model; package org.mariotaku.twidere.model;
import android.content.ContentValues;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
@ -34,6 +35,7 @@ import com.hannesdorfmann.parcelableplease.annotation.ParcelableNoThanks;
import com.hannesdorfmann.parcelableplease.annotation.ParcelablePlease; import com.hannesdorfmann.parcelableplease.annotation.ParcelablePlease;
import org.mariotaku.commons.objectcursor.LoganSquareCursorFieldConverter; import org.mariotaku.commons.objectcursor.LoganSquareCursorFieldConverter;
import org.mariotaku.library.objectcursor.annotation.BeforeWriteContentValues;
import org.mariotaku.library.objectcursor.annotation.CursorField; import org.mariotaku.library.objectcursor.annotation.CursorField;
import org.mariotaku.library.objectcursor.annotation.CursorObject; import org.mariotaku.library.objectcursor.annotation.CursorObject;
import org.mariotaku.twidere.model.message.MessageExtras; import org.mariotaku.twidere.model.message.MessageExtras;
@ -42,9 +44,11 @@ import org.mariotaku.twidere.model.message.conversation.TwitterOfficialConversat
import org.mariotaku.twidere.model.util.ConversationExtrasConverter; import org.mariotaku.twidere.model.util.ConversationExtrasConverter;
import org.mariotaku.twidere.model.util.MessageExtrasConverter; import org.mariotaku.twidere.model.util.MessageExtrasConverter;
import org.mariotaku.twidere.model.util.UserKeyCursorFieldConverter; import org.mariotaku.twidere.model.util.UserKeyCursorFieldConverter;
import org.mariotaku.twidere.model.util.UserKeysCursorFieldConverter;
import org.mariotaku.twidere.provider.TwidereDataStore; import org.mariotaku.twidere.provider.TwidereDataStore;
import org.mariotaku.twidere.provider.TwidereDataStore.Messages.Conversations; import org.mariotaku.twidere.provider.TwidereDataStore.Messages.Conversations;
import java.io.IOException;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.util.Arrays; import java.util.Arrays;
@ -127,6 +131,13 @@ public class ParcelableMessageConversation implements Parcelable {
@CursorField(value = Conversations.PARTICIPANTS, converter = LoganSquareCursorFieldConverter.class) @CursorField(value = Conversations.PARTICIPANTS, converter = LoganSquareCursorFieldConverter.class)
public ParcelableUser[] participants; public ParcelableUser[] participants;
/**
* Keys are sorted for string comparison
*/
@JsonField(name = "participant_keys")
@CursorField(value = Conversations.PARTICIPANT_KEYS, converter = UserKeysCursorFieldConverter.class)
public UserKey[] participant_keys;
@JsonField(name = "sender_key") @JsonField(name = "sender_key")
@CursorField(value = Conversations.SENDER_KEY, converter = UserKeyCursorFieldConverter.class) @CursorField(value = Conversations.SENDER_KEY, converter = UserKeyCursorFieldConverter.class)
public UserKey sender_key; public UserKey sender_key;
@ -183,6 +194,7 @@ public class ParcelableMessageConversation implements Parcelable {
void beforeJsonSerialize() { void beforeJsonSerialize() {
internalMessageExtras = ParcelableMessage.InternalExtras.from(message_extras); internalMessageExtras = ParcelableMessage.InternalExtras.from(message_extras);
internalConversationExtras = InternalExtras.from(conversation_extras); internalConversationExtras = InternalExtras.from(conversation_extras);
prepareParticipantKeys();
} }
@ -196,6 +208,11 @@ public class ParcelableMessageConversation implements Parcelable {
} }
} }
@BeforeWriteContentValues
void beforeWriteContentValues(ContentValues values) throws IOException {
prepareParticipantKeys();
}
@Override @Override
public String toString() { public String toString() {
return "ParcelableMessageConversation{" + return "ParcelableMessageConversation{" +
@ -227,6 +244,19 @@ public class ParcelableMessageConversation implements Parcelable {
'}'; '}';
} }
private void prepareParticipantKeys() {
// Ensure keys are ordered
if (participants != null && participant_keys == null) {
participant_keys = new UserKey[participants.length];
for (int i = 0, j = participants.length; i < j; i++) {
participant_keys[i] = participants[i].key;
}
}
if (participant_keys != null) {
Arrays.sort(participant_keys);
}
}
@StringDef({ConversationType.ONE_TO_ONE, ConversationType.GROUP}) @StringDef({ConversationType.ONE_TO_ONE, ConversationType.GROUP})
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
public @interface ConversationType { public @interface ConversationType {

View File

@ -380,6 +380,7 @@ public interface TwidereDataStore {
String SPANS = "spans"; String SPANS = "spans";
String MESSAGE_EXTRAS = "message_extras"; String MESSAGE_EXTRAS = "message_extras";
String PARTICIPANTS = "participants"; String PARTICIPANTS = "participants";
String PARTICIPANT_KEYS = "participant_keys";
String SENDER_KEY = "sender_key"; String SENDER_KEY = "sender_key";
String RECIPIENT_KEY = "recipient_key"; String RECIPIENT_KEY = "recipient_key";
String REQUEST_CURSOR = "request_cursor"; String REQUEST_CURSOR = "request_cursor";

View File

@ -34,7 +34,7 @@ import static org.mariotaku.twidere.annotation.PreferenceType.STRING;
public interface Constants extends TwidereConstants { public interface Constants extends TwidereConstants {
String DATABASES_NAME = "twidere.sqlite"; String DATABASES_NAME = "twidere.sqlite";
int DATABASES_VERSION = 179; int DATABASES_VERSION = 180;
int EXTRA_FEATURES_NOTICE_VERSION = 0; int EXTRA_FEATURES_NOTICE_VERSION = 0;

View File

@ -20,10 +20,12 @@
package org.mariotaku.twidere.fragment.message package org.mariotaku.twidere.fragment.message
import android.accounts.AccountManager import android.accounts.AccountManager
import android.content.Context
import android.graphics.Canvas import android.graphics.Canvas
import android.graphics.Paint import android.graphics.Paint
import android.graphics.RectF import android.graphics.RectF
import android.os.Bundle import android.os.Bundle
import android.support.annotation.WorkerThread
import android.support.v4.app.LoaderManager.LoaderCallbacks import android.support.v4.app.LoaderManager.LoaderCallbacks
import android.support.v4.content.Loader import android.support.v4.content.Loader
import android.support.v7.widget.LinearLayoutManager import android.support.v7.widget.LinearLayoutManager
@ -37,6 +39,7 @@ import org.mariotaku.kpreferences.get
import org.mariotaku.ktextension.Bundle import org.mariotaku.ktextension.Bundle
import org.mariotaku.ktextension.set import org.mariotaku.ktextension.set
import org.mariotaku.ktextension.setItemAvailability import org.mariotaku.ktextension.setItemAvailability
import org.mariotaku.sqliteqb.library.Expression
import org.mariotaku.twidere.R import org.mariotaku.twidere.R
import org.mariotaku.twidere.adapter.SelectableUsersAdapter import org.mariotaku.twidere.adapter.SelectableUsersAdapter
import org.mariotaku.twidere.constant.IntentConstants.* import org.mariotaku.twidere.constant.IntentConstants.*
@ -44,11 +47,8 @@ import org.mariotaku.twidere.constant.nameFirstKey
import org.mariotaku.twidere.extension.model.isOfficial import org.mariotaku.twidere.extension.model.isOfficial
import org.mariotaku.twidere.fragment.BaseFragment import org.mariotaku.twidere.fragment.BaseFragment
import org.mariotaku.twidere.loader.CacheUserSearchLoader import org.mariotaku.twidere.loader.CacheUserSearchLoader
import org.mariotaku.twidere.model.ParcelableMessageConversation import org.mariotaku.twidere.model.*
import org.mariotaku.twidere.model.ParcelableMessageConversation.ConversationType 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.model.util.AccountUtils
import org.mariotaku.twidere.provider.TwidereDataStore.Messages.Conversations import org.mariotaku.twidere.provider.TwidereDataStore.Messages.Conversations
import org.mariotaku.twidere.task.twitter.message.SendMessageTask import org.mariotaku.twidere.task.twitter.message.SendMessageTask
@ -235,6 +235,17 @@ class MessageNewConversationFragment : BaseFragment(), LoaderCallbacks<List<Parc
} }
conversation.participants = (selected + account.user).toTypedArray() conversation.participants = (selected + account.user).toTypedArray()
conversation.is_temp = true conversation.is_temp = true
if (conversation.conversation_type == ConversationType.ONE_TO_ONE) {
val participantKeys = conversation.participants.map(ParcelableUser::key)
val existingConversation = findMessageConversation(context, accountKey, participantKeys)
if (existingConversation != null) {
activity.startActivity(IntentUtils.messageConversation(accountKey, existingConversation.id))
activity.finish()
return
}
}
val values = ParcelableMessageConversationValuesCreator.create(conversation) val values = ParcelableMessageConversationValuesCreator.create(conversation)
context.contentResolver.insert(Conversations.CONTENT_URI, values) context.contentResolver.insert(Conversations.CONTENT_URI, values)
activity.startActivity(IntentUtils.messageConversation(accountKey, conversation.id)) activity.startActivity(IntentUtils.messageConversation(accountKey, conversation.id))
@ -278,6 +289,25 @@ class MessageNewConversationFragment : BaseFragment(), LoaderCallbacks<List<Parc
} }
} }
@WorkerThread
fun findMessageConversation(context: Context, accountKey: UserKey,
participantKeys: Collection<UserKey>): ParcelableMessageConversation? {
val resolver = context.contentResolver
val where = Expression.and(Expression.equalsArgs(Conversations.ACCOUNT_KEY),
Expression.equalsArgs(Conversations.PARTICIPANT_KEYS)).sql
val whereArgs = arrayOf(accountKey.toString(), participantKeys.sorted().joinToString(","))
val cur = resolver.query(Conversations.CONTENT_URI, Conversations.COLUMNS, where, whereArgs, null) ?: return null
try {
if (cur.moveToFirst()) {
return ParcelableMessageConversationCursorIndices.fromCursor(cur)
}
} finally {
cur.close()
}
return null
}
internal class PerformSearchRequestRunnable(val query: String, fragment: MessageNewConversationFragment) : Runnable { internal class PerformSearchRequestRunnable(val query: String, fragment: MessageNewConversationFragment) : Runnable {
val fragmentRef = WeakReference(fragment) val fragmentRef = WeakReference(fragment)
override fun run() { override fun run() {
@ -322,4 +352,5 @@ class MessageNewConversationFragment : BaseFragment(), LoaderCallbacks<List<Parc
} }
} }
} }

View File

@ -523,6 +523,7 @@ class GetMessagesTask(
this.participants = participants + ParcelableUserUtils.fromUser(user, accountKey) this.participants = participants + ParcelableUserUtils.fromUser(user, accountKey)
} }
} }
this.participant_keys = this.participants.map(ParcelableUser::key).toTypedArray()
this.participants.sortBy(ParcelableUser::screen_name) this.participants.sortBy(ParcelableUser::screen_name)
} }