supports dm conversation load more and refresh
This commit is contained in:
parent
3842396f36
commit
57b3ed3346
|
@ -21,6 +21,13 @@
|
|||
|
||||
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.NewDm;
|
||||
import org.mariotaku.microblog.library.twitter.model.Paging;
|
||||
import org.mariotaku.microblog.library.twitter.model.ResponseCode;
|
||||
import org.mariotaku.microblog.library.twitter.model.UserEvents;
|
||||
import org.mariotaku.microblog.library.twitter.model.UserInbox;
|
||||
import org.mariotaku.restfu.annotation.method.GET;
|
||||
import org.mariotaku.restfu.annotation.method.POST;
|
||||
import org.mariotaku.restfu.annotation.param.KeyValue;
|
||||
|
@ -29,12 +36,6 @@ import org.mariotaku.restfu.annotation.param.Path;
|
|||
import org.mariotaku.restfu.annotation.param.Queries;
|
||||
import org.mariotaku.restfu.annotation.param.Query;
|
||||
import org.mariotaku.restfu.http.BodyType;
|
||||
import org.mariotaku.microblog.library.MicroBlogException;
|
||||
import org.mariotaku.microblog.library.twitter.model.ConversationTimeline;
|
||||
import org.mariotaku.microblog.library.twitter.model.NewDm;
|
||||
import org.mariotaku.microblog.library.twitter.model.Paging;
|
||||
import org.mariotaku.microblog.library.twitter.model.ResponseCode;
|
||||
import org.mariotaku.microblog.library.twitter.model.UserInbox;
|
||||
|
||||
|
||||
@Queries(@KeyValue(key = "include_groups", value = "true"))
|
||||
|
@ -54,6 +55,9 @@ public interface PrivateDirectMessagesResources extends PrivateResources {
|
|||
@GET("/dm/user_inbox.json")
|
||||
UserInbox getUserInbox(@Query Paging paging) throws MicroBlogException;
|
||||
|
||||
@GET("/dm/user_updates.json")
|
||||
UserEvents getUserUpdates(@Query("cursor") String cursor) throws MicroBlogException;
|
||||
|
||||
@GET("/dm/conversation/{conversation_id}.json")
|
||||
ConversationTimeline getUserInbox(@Path("conversation_id") String conversationId, @Query Paging paging) throws MicroBlogException;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ package org.mariotaku.microblog.library.twitter.model;
|
|||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.StringDef;
|
||||
|
||||
import com.bluelinelabs.logansquare.annotation.JsonField;
|
||||
|
@ -94,8 +95,8 @@ public class DMResponse implements Parcelable {
|
|||
return conversations;
|
||||
}
|
||||
|
||||
public User getUser(long userId) {
|
||||
return users.get(String.valueOf(userId));
|
||||
public User getUser(String userId) {
|
||||
return users.get(userId);
|
||||
}
|
||||
|
||||
public Conversation getConversation(String conversationId) {
|
||||
|
@ -129,6 +130,8 @@ public class DMResponse implements Parcelable {
|
|||
Message participantsJoin;
|
||||
@JsonField(name = "conversation_name_update")
|
||||
Message conversationNameUpdate;
|
||||
@JsonField(name = "conversation_read")
|
||||
Message conversationRead;
|
||||
|
||||
public Message getJoinConversation() {
|
||||
return joinConversation;
|
||||
|
@ -154,6 +157,10 @@ public class DMResponse implements Parcelable {
|
|||
return conversationNameUpdate;
|
||||
}
|
||||
|
||||
public Message getConversationRead() {
|
||||
return conversationRead;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Entry{" +
|
||||
|
@ -163,6 +170,7 @@ public class DMResponse implements Parcelable {
|
|||
", participantsLeave=" + participantsLeave +
|
||||
", participantsJoin=" + participantsJoin +
|
||||
", conversationNameUpdate=" + conversationNameUpdate +
|
||||
", conversationRead=" + conversationRead +
|
||||
'}';
|
||||
}
|
||||
|
||||
|
@ -455,11 +463,11 @@ public class DMResponse implements Parcelable {
|
|||
@JsonField(name = "conversation_id")
|
||||
String conversationId;
|
||||
@JsonField(name = "last_read_event_id")
|
||||
long lastReadEventId;
|
||||
String lastReadEventId;
|
||||
@JsonField(name = "max_entry_id")
|
||||
long maxEntryId;
|
||||
String maxEntryId;
|
||||
@JsonField(name = "min_entry_id")
|
||||
long minEntryId;
|
||||
String minEntryId;
|
||||
@JsonField(name = "notifications_disabled")
|
||||
boolean notificationsDisabled;
|
||||
@JsonField(name = "participants")
|
||||
|
@ -467,7 +475,7 @@ public class DMResponse implements Parcelable {
|
|||
@JsonField(name = "read_only")
|
||||
boolean readOnly;
|
||||
@JsonField(name = "sort_event_id")
|
||||
long sortEventId;
|
||||
String sortEventId;
|
||||
@JsonField(name = "sort_timestamp")
|
||||
long sortTimestamp;
|
||||
@JsonField(name = "status")
|
||||
|
@ -498,7 +506,7 @@ public class DMResponse implements Parcelable {
|
|||
return sortTimestamp;
|
||||
}
|
||||
|
||||
public long getSortEventId() {
|
||||
public String getSortEventId() {
|
||||
return sortEventId;
|
||||
}
|
||||
|
||||
|
@ -514,15 +522,15 @@ public class DMResponse implements Parcelable {
|
|||
return conversationId;
|
||||
}
|
||||
|
||||
public long getLastReadEventId() {
|
||||
public String getLastReadEventId() {
|
||||
return lastReadEventId;
|
||||
}
|
||||
|
||||
public long getMaxEntryId() {
|
||||
public String getMaxEntryId() {
|
||||
return maxEntryId;
|
||||
}
|
||||
|
||||
public long getMinEntryId() {
|
||||
public String getMinEntryId() {
|
||||
return minEntryId;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* 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.microblog.library.twitter.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;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/7/5.
|
||||
*/
|
||||
@ParcelablePlease
|
||||
@JsonObject
|
||||
public class UserEvents extends TwitterResponseObject implements Parcelable {
|
||||
|
||||
@JsonField(name = "user_events")
|
||||
DMResponse userEvents;
|
||||
|
||||
public DMResponse getUserEvents() {
|
||||
return userEvents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "UserEvents{" +
|
||||
"userEvents=" + userEvents +
|
||||
"} " + super.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
UserEventsParcelablePlease.writeToParcel(this, dest, flags);
|
||||
}
|
||||
|
||||
public static final Creator<UserEvents> CREATOR = new Creator<UserEvents>() {
|
||||
public UserEvents createFromParcel(Parcel source) {
|
||||
UserEvents target = new UserEvents();
|
||||
UserEventsParcelablePlease.readFromParcel(target, source);
|
||||
return target;
|
||||
}
|
||||
|
||||
public UserEvents[] newArray(int size) {
|
||||
return new UserEvents[size];
|
||||
}
|
||||
};
|
||||
}
|
|
@ -21,14 +21,19 @@
|
|||
|
||||
package org.mariotaku.microblog.library.twitter.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;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/7/5.
|
||||
*/
|
||||
@ParcelablePlease
|
||||
@JsonObject
|
||||
public class UserInbox extends TwitterResponseObject {
|
||||
public class UserInbox extends TwitterResponseObject implements Parcelable {
|
||||
|
||||
@JsonField(name = "user_inbox")
|
||||
DMResponse userInbox;
|
||||
|
@ -37,5 +42,32 @@ public class UserInbox extends TwitterResponseObject {
|
|||
return userInbox;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "UserInbox{" +
|
||||
"userInbox=" + userInbox +
|
||||
"} " + super.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
UserInboxParcelablePlease.writeToParcel(this, dest, flags);
|
||||
}
|
||||
|
||||
public static final Creator<UserInbox> CREATOR = new Creator<UserInbox>() {
|
||||
public UserInbox createFromParcel(Parcel source) {
|
||||
UserInbox target = new UserInbox();
|
||||
UserInboxParcelablePlease.readFromParcel(target, source);
|
||||
return target;
|
||||
}
|
||||
|
||||
public UserInbox[] newArray(int size) {
|
||||
return new UserInbox[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -33,7 +33,9 @@ import org.mariotaku.commons.objectcursor.LoganSquareCursorFieldConverter;
|
|||
import org.mariotaku.library.objectcursor.annotation.CursorField;
|
||||
import org.mariotaku.library.objectcursor.annotation.CursorObject;
|
||||
import org.mariotaku.twidere.model.message.MessageExtras;
|
||||
import org.mariotaku.twidere.model.message.NameUpdatedExtras;
|
||||
import org.mariotaku.twidere.model.message.StickerExtras;
|
||||
import org.mariotaku.twidere.model.message.UserArrayExtras;
|
||||
import org.mariotaku.twidere.model.util.MessageExtrasConverter;
|
||||
import org.mariotaku.twidere.model.util.UserKeyCursorFieldConverter;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore;
|
||||
|
@ -167,12 +169,20 @@ public class ParcelableMessage {
|
|||
static class InternalExtras {
|
||||
@JsonField(name = "sticker")
|
||||
StickerExtras sticker;
|
||||
@JsonField(name = "name_updated")
|
||||
NameUpdatedExtras nameUpdated;
|
||||
@JsonField(name = "user_array")
|
||||
UserArrayExtras userArray;
|
||||
|
||||
public static InternalExtras from(final MessageExtras extras) {
|
||||
if (extras == null) return null;
|
||||
InternalExtras result = new InternalExtras();
|
||||
if (extras instanceof StickerExtras) {
|
||||
result.sticker = (StickerExtras) extras;
|
||||
} else if (extras instanceof NameUpdatedExtras) {
|
||||
result.nameUpdated = (NameUpdatedExtras) extras;
|
||||
} else if (extras instanceof UserArrayExtras) {
|
||||
result.userArray = (UserArrayExtras) extras;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
@ -182,6 +192,10 @@ public class ParcelableMessage {
|
|||
public MessageExtras getExtras() {
|
||||
if (sticker != null) {
|
||||
return sticker;
|
||||
} else if (nameUpdated != null) {
|
||||
return nameUpdated;
|
||||
} else if (userArray != null) {
|
||||
return userArray;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -25,12 +25,17 @@ import android.support.annotation.StringDef;
|
|||
|
||||
import com.bluelinelabs.logansquare.annotation.JsonField;
|
||||
import com.bluelinelabs.logansquare.annotation.JsonObject;
|
||||
import com.bluelinelabs.logansquare.annotation.OnJsonParseComplete;
|
||||
import com.bluelinelabs.logansquare.annotation.OnPreJsonSerialize;
|
||||
import com.hannesdorfmann.parcelableplease.annotation.ParcelableNoThanks;
|
||||
|
||||
import org.mariotaku.commons.objectcursor.LoganSquareCursorFieldConverter;
|
||||
import org.mariotaku.library.objectcursor.annotation.CursorField;
|
||||
import org.mariotaku.library.objectcursor.annotation.CursorObject;
|
||||
import org.mariotaku.twidere.model.message.MessageExtras;
|
||||
import org.mariotaku.twidere.model.message.conversation.ConversationExtras;
|
||||
import org.mariotaku.twidere.model.message.conversation.TwitterOfficialConversationExtras;
|
||||
import org.mariotaku.twidere.model.util.ConversationExtrasConverter;
|
||||
import org.mariotaku.twidere.model.util.MessageExtrasConverter;
|
||||
import org.mariotaku.twidere.model.util.UserKeyCursorFieldConverter;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore;
|
||||
|
@ -96,13 +101,16 @@ public class ParcelableMessageConversation {
|
|||
@CursorField(value = Conversations.SPANS, converter = LoganSquareCursorFieldConverter.class)
|
||||
public SpanItem[] spans;
|
||||
|
||||
@JsonField(name = "extras")
|
||||
@CursorField(value = Conversations.EXTRAS, converter = MessageExtrasConverter.class)
|
||||
public MessageExtras extras;
|
||||
@CursorField(value = Conversations.MESSAGE_EXTRAS, converter = MessageExtrasConverter.class)
|
||||
public MessageExtras message_extras;
|
||||
|
||||
@JsonField(name = "extras")
|
||||
@ParcelableNoThanks
|
||||
ParcelableMessage.InternalExtras internalExtras;
|
||||
@JsonField(name = "conversation_extras_type")
|
||||
@CursorField(Conversations.CONVERSATION_EXTRAS_TYPE)
|
||||
public String conversation_extras_type;
|
||||
|
||||
@JsonField(name = "conversation_extras")
|
||||
@CursorField(value = Conversations.CONVERSATION_EXTRAS, converter = ConversationExtrasConverter.class)
|
||||
public ConversationExtras conversation_extras;
|
||||
|
||||
@JsonField(name = "participants")
|
||||
@CursorField(value = Conversations.PARTICIPANTS, converter = LoganSquareCursorFieldConverter.class)
|
||||
|
@ -124,6 +132,32 @@ public class ParcelableMessageConversation {
|
|||
@CursorField(value = Conversations.REQUEST_CURSOR)
|
||||
public String request_cursor;
|
||||
|
||||
@JsonField(name = "message_extras")
|
||||
@ParcelableNoThanks
|
||||
ParcelableMessage.InternalExtras internalMessageExtras;
|
||||
|
||||
@JsonField(name = "conversation_extras")
|
||||
@ParcelableNoThanks
|
||||
InternalExtras internalConversationExtras;
|
||||
|
||||
|
||||
@OnPreJsonSerialize
|
||||
void beforeJsonSerialize() {
|
||||
internalMessageExtras = ParcelableMessage.InternalExtras.from(message_extras);
|
||||
internalConversationExtras = InternalExtras.from(conversation_extras);
|
||||
}
|
||||
|
||||
|
||||
@OnJsonParseComplete
|
||||
void onJsonParseComplete() {
|
||||
if (internalMessageExtras != null) {
|
||||
message_extras = internalMessageExtras.getExtras();
|
||||
}
|
||||
if (internalConversationExtras != null) {
|
||||
conversation_extras = internalConversationExtras.getExtras();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ParcelableMessageConversation{" +
|
||||
|
@ -140,13 +174,16 @@ public class ParcelableMessageConversation {
|
|||
", text_unescaped='" + text_unescaped + '\'' +
|
||||
", media=" + Arrays.toString(media) +
|
||||
", spans=" + Arrays.toString(spans) +
|
||||
", extras=" + extras +
|
||||
", internalExtras=" + internalExtras +
|
||||
", message_extras=" + message_extras +
|
||||
", conversation_extras=" + conversation_extras +
|
||||
", participants=" + Arrays.toString(participants) +
|
||||
", extras_type='" + conversation_extras_type + '\'' +
|
||||
", sender_key=" + sender_key +
|
||||
", recipient_key=" + recipient_key +
|
||||
", is_outgoing=" + is_outgoing +
|
||||
", request_cursor='" + request_cursor + '\'' +
|
||||
", internalMessageExtras=" + internalMessageExtras +
|
||||
", internalConversationExtras=" + internalConversationExtras +
|
||||
'}';
|
||||
}
|
||||
|
||||
|
@ -156,4 +193,34 @@ public class ParcelableMessageConversation {
|
|||
String GROUP = "group";
|
||||
}
|
||||
|
||||
@StringDef({ExtrasType.FANFOU, ExtrasType.TWITTER_OFFICIAL})
|
||||
public @interface ExtrasType {
|
||||
String FANFOU = "fanfou";
|
||||
String TWITTER_OFFICIAL = "twitter_official";
|
||||
}
|
||||
|
||||
|
||||
@JsonObject
|
||||
static class InternalExtras {
|
||||
@JsonField(name = "twitter_official")
|
||||
TwitterOfficialConversationExtras twitterOfficial;
|
||||
|
||||
public static InternalExtras from(final ConversationExtras extras) {
|
||||
if (extras == null) return null;
|
||||
InternalExtras result = new InternalExtras();
|
||||
if (extras instanceof TwitterOfficialConversationExtras) {
|
||||
result.twitterOfficial = (TwitterOfficialConversationExtras) extras;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public ConversationExtras getExtras() {
|
||||
if (twitterOfficial != null) {
|
||||
return twitterOfficial;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
package org.mariotaku.twidere.model.message;
|
||||
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.bluelinelabs.logansquare.LoganSquare;
|
||||
import com.bluelinelabs.logansquare.annotation.JsonObject;
|
||||
|
@ -36,7 +38,8 @@ import java.io.IOException;
|
|||
|
||||
@JsonObject
|
||||
public abstract class MessageExtras implements Parcelable {
|
||||
public static MessageExtras parse(final String messageType, final String json) throws IOException {
|
||||
public static MessageExtras parse(@NonNull final String messageType, @Nullable final String json) throws IOException {
|
||||
if (json == null) return null;
|
||||
switch (messageType) {
|
||||
case MessageType.STICKER:
|
||||
return LoganSquare.parse(json, StickerExtras.class);
|
||||
|
|
|
@ -19,37 +19,30 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
package org.mariotaku.microblog.library.twitter.model;
|
||||
package org.mariotaku.twidere.model.message.conversation;
|
||||
|
||||
import com.bluelinelabs.logansquare.annotation.JsonField;
|
||||
import com.bluelinelabs.logansquare.annotation.JsonObject;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.bluelinelabs.logansquare.LoganSquare;
|
||||
|
||||
import org.mariotaku.twidere.model.ParcelableMessageConversation.ExtrasType;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 16/3/1.
|
||||
* Created by mariotaku on 2017/2/13.
|
||||
*/
|
||||
@JsonObject
|
||||
public class UserEventsResponse extends TwitterResponseObject {
|
||||
@JsonField(name = "user_events")
|
||||
UserEvents userEvents;
|
||||
|
||||
public UserEvents getUserEvents() {
|
||||
return userEvents;
|
||||
}
|
||||
|
||||
@JsonObject
|
||||
public static class UserEvents {
|
||||
@JsonField(name = "cursor")
|
||||
String cursor;
|
||||
@JsonField(name = "last_seen_event_id")
|
||||
long lastSeenEventId;
|
||||
|
||||
public String getCursor() {
|
||||
return cursor;
|
||||
}
|
||||
|
||||
public long getLastSeenEventId() {
|
||||
return lastSeenEventId;
|
||||
public abstract class ConversationExtras implements Parcelable {
|
||||
public static ConversationExtras parse(@NonNull final String extrasType, @Nullable final String json) throws IOException {
|
||||
if (json == null) return null;
|
||||
switch (extrasType) {
|
||||
case ExtrasType.TWITTER_OFFICIAL: {
|
||||
return LoganSquare.parse(json, TwitterOfficialConversationExtras.class);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* 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.message.conversation;
|
||||
|
||||
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 org.mariotaku.microblog.library.twitter.model.DMResponse;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/2/13.
|
||||
*/
|
||||
|
||||
@ParcelablePlease
|
||||
@JsonObject
|
||||
public class TwitterOfficialConversationExtras extends ConversationExtras implements Parcelable {
|
||||
@JsonField(name = "max_entry_id")
|
||||
String maxEntryId;
|
||||
@JsonField(name = "min_entry_id")
|
||||
String minEntryId;
|
||||
@JsonField(name = "status")
|
||||
@DMResponse.Status
|
||||
String status;
|
||||
|
||||
public String getMaxEntryId() {
|
||||
return maxEntryId;
|
||||
}
|
||||
|
||||
public void setMaxEntryId(final String maxEntryId) {
|
||||
this.maxEntryId = maxEntryId;
|
||||
}
|
||||
|
||||
public String getMinEntryId() {
|
||||
return minEntryId;
|
||||
}
|
||||
|
||||
public void setMinEntryId(final String minEntryId) {
|
||||
this.minEntryId = minEntryId;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(final String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
TwitterOfficialConversationExtrasParcelablePlease.writeToParcel(this, dest, flags);
|
||||
}
|
||||
|
||||
public static final Creator<TwitterOfficialConversationExtras> CREATOR = new Creator<TwitterOfficialConversationExtras>() {
|
||||
public TwitterOfficialConversationExtras createFromParcel(Parcel source) {
|
||||
TwitterOfficialConversationExtras target = new TwitterOfficialConversationExtras();
|
||||
TwitterOfficialConversationExtrasParcelablePlease.readFromParcel(target, source);
|
||||
return target;
|
||||
}
|
||||
|
||||
public TwitterOfficialConversationExtras[] newArray(int size) {
|
||||
return new TwitterOfficialConversationExtras[size];
|
||||
}
|
||||
};
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* 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.util;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.bluelinelabs.logansquare.LoganSquare;
|
||||
|
||||
import org.mariotaku.library.objectcursor.converter.CursorFieldConverter;
|
||||
import org.mariotaku.twidere.model.message.conversation.ConversationExtras;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Messages;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/2/9.
|
||||
*/
|
||||
public class ConversationExtrasConverter implements CursorFieldConverter<ConversationExtras> {
|
||||
@Override
|
||||
public ConversationExtras parseField(Cursor cursor, int columnIndex, ParameterizedType fieldType) throws IOException {
|
||||
final String extrasType = cursor.getString(cursor.getColumnIndex(Messages.Conversations.CONVERSATION_EXTRAS_TYPE));
|
||||
if (TextUtils.isEmpty(extrasType)) return null;
|
||||
return ConversationExtras.parse(extrasType, cursor.getString(columnIndex));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeField(ContentValues values, ConversationExtras object, String columnName, ParameterizedType fieldType) throws IOException {
|
||||
if (object == null) return;
|
||||
values.put(columnName, LoganSquare.serialize(object));
|
||||
}
|
||||
}
|
|
@ -391,18 +391,20 @@ public interface TwidereDataStore {
|
|||
String TEXT_UNESCAPED = "text_unescaped";
|
||||
String MEDIA = "media";
|
||||
String SPANS = "spans";
|
||||
String EXTRAS = "extras";
|
||||
String MESSAGE_EXTRAS = "message_extras";
|
||||
String PARTICIPANTS = "participants";
|
||||
String SENDER_KEY = "sender_key";
|
||||
String RECIPIENT_KEY = "recipient_key";
|
||||
String REQUEST_CURSOR = "request_cursor";
|
||||
String IS_OUTGOING = "is_outgoing";
|
||||
String CONVERSATION_EXTRAS = "conversation_extras";
|
||||
String CONVERSATION_EXTRAS_TYPE = "conversation_extras_type";
|
||||
|
||||
String[] COLUMNS = ParcelableMessageConversationTableInfo.COLUMNS;
|
||||
|
||||
String[] TYPES = ParcelableMessageConversationTableInfo.TYPES;
|
||||
|
||||
String TABLE_NAME = "messages_conversations";
|
||||
|
||||
String CONTENT_PATH = "messages/conversations";
|
||||
Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, CONTENT_PATH);
|
||||
}
|
||||
|
|
|
@ -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 = 171;
|
||||
int DATABASES_VERSION = 172;
|
||||
|
||||
int EXTRA_FEATURES_NOTICE_VERSION = 0;
|
||||
|
||||
|
|
|
@ -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.MediaLoadingHandler
|
||||
import org.mariotaku.twidere.util.TwidereLinkify
|
||||
import org.mariotaku.twidere.view.holder.message.AbsMessageViewHolder
|
||||
import org.mariotaku.twidere.view.holder.message.MessageViewHolder
|
||||
|
@ -50,6 +51,7 @@ class MessagesConversationAdapter(context: Context) : LoadMoreSupportAdapter<Rec
|
|||
val linkHighlightingStyle: Int = preferences[linkHighlightOptionKey]
|
||||
val nameFirst: Boolean = preferences[nameFirstKey]
|
||||
val linkify: TwidereLinkify = TwidereLinkify(null)
|
||||
val mediaLoadingHandler: MediaLoadingHandler = MediaLoadingHandler()
|
||||
|
||||
var messages: List<ParcelableMessage>? = null
|
||||
private set
|
||||
|
@ -140,5 +142,6 @@ class MessagesConversationAdapter(context: Context) : LoadMoreSupportAdapter<Rec
|
|||
const val ITEM_TYPE_NOTICE_MESSAGE = 3
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ fun ParcelableMessageConversation.applyFrom(message: ParcelableMessage, details:
|
|||
text_unescaped = message.text_unescaped
|
||||
media = message.media
|
||||
spans = message.spans
|
||||
extras = message.extras
|
||||
message_extras = message.extras
|
||||
sender_key = message.sender_key
|
||||
recipient_key = message.recipient_key
|
||||
is_outgoing = message.is_outgoing
|
||||
|
@ -43,7 +43,7 @@ fun ParcelableMessageConversation.getConversationName(context: Context,
|
|||
|
||||
fun ParcelableMessageConversation.getSummaryText(context: Context, manager: UserColorNameManager,
|
||||
nameFirst: Boolean): CharSequence? {
|
||||
return getSummaryText(context, manager, nameFirst, message_type, extras, sender_key,
|
||||
return getSummaryText(context, manager, nameFirst, message_type, message_extras, sender_key,
|
||||
text_unescaped, this)
|
||||
}
|
||||
|
||||
|
|
|
@ -92,8 +92,8 @@ object ParcelableMessageUtils {
|
|||
this.is_outgoing = false
|
||||
}
|
||||
|
||||
private fun ParcelableMessage.applyUsersEvent(accountKey: UserKey,
|
||||
message: DMResponse.Entry.Message, users: Map<String, User>, @MessageType type: String) {
|
||||
private fun ParcelableMessage.applyUsersEvent(accountKey: UserKey, message: DMResponse.Entry.Message,
|
||||
users: Map<String, User>, @MessageType type: String) {
|
||||
this.commonEntry(accountKey, message)
|
||||
this.message_type = type
|
||||
this.extras = UserArrayExtras().apply {
|
||||
|
@ -105,8 +105,8 @@ object ParcelableMessageUtils {
|
|||
this.is_outgoing = false
|
||||
}
|
||||
|
||||
private fun ParcelableMessage.applyNameUpdatedEvent(accountKey: UserKey,
|
||||
message: DMResponse.Entry.Message, users: Map<String, User>) {
|
||||
private fun ParcelableMessage.applyNameUpdatedEvent(accountKey: UserKey, message: DMResponse.Entry.Message,
|
||||
users: Map<String, User>) {
|
||||
this.commonEntry(accountKey, message)
|
||||
this.message_type = MessageType.CONVERSATION_NAME_UPDATE
|
||||
this.extras = NameUpdatedExtras().apply {
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.mariotaku.twidere.extension.model.timestamp
|
|||
import org.mariotaku.twidere.model.*
|
||||
import org.mariotaku.twidere.model.ParcelableMessageConversation.ConversationType
|
||||
import org.mariotaku.twidere.model.event.GetMessagesTaskEvent
|
||||
import org.mariotaku.twidere.model.message.conversation.TwitterOfficialConversationExtras
|
||||
import org.mariotaku.twidere.model.util.AccountUtils
|
||||
import org.mariotaku.twidere.model.util.AccountUtils.getAccountDetails
|
||||
import org.mariotaku.twidere.model.util.ParcelableMessageUtils
|
||||
|
@ -74,27 +75,43 @@ class GetMessagesTask(
|
|||
return getDefaultMessages(microBlog, details, param, index)
|
||||
}
|
||||
|
||||
private fun getTwitterOfficialMessages(microBlog: MicroBlog, details: AccountDetails, param: RefreshMessagesTaskParam, index: Int): GetMessagesData {
|
||||
private fun getTwitterOfficialMessages(microBlog: MicroBlog, details: AccountDetails,
|
||||
param: RefreshMessagesTaskParam, index: Int): GetMessagesData {
|
||||
if (param.conversationId != null) return GetMessagesData(emptyList(), emptyList())
|
||||
val accountKey = details.key
|
||||
val cursor = param.cursors?.get(index)
|
||||
val page = cursor?.substringAfter("page:").toInt(-1)
|
||||
val inbox = microBlog.getUserInbox(Paging().apply {
|
||||
count(60)
|
||||
if (page >= 0) {
|
||||
page(page)
|
||||
}
|
||||
}).userInbox
|
||||
val maxId = if (param.hasMaxIds) param.maxIds?.get(index) else null
|
||||
val cursor = if (param.hasCursors) param.cursors?.get(index) else null
|
||||
val response = if (cursor != null) {
|
||||
microBlog.getUserUpdates(cursor).userEvents
|
||||
} else {
|
||||
microBlog.getUserInbox(Paging().apply {
|
||||
if (maxId != null) {
|
||||
maxId(maxId)
|
||||
}
|
||||
}).userInbox
|
||||
}
|
||||
|
||||
|
||||
val respConversations = response.conversations
|
||||
val respEntries = response.entries
|
||||
val respUsers = response.users
|
||||
|
||||
if (respConversations == null || respEntries == null || respUsers == null) {
|
||||
return GetMessagesData(emptyList(), emptyList())
|
||||
}
|
||||
|
||||
val conversations = hashMapOf<String, ParcelableMessageConversation>()
|
||||
|
||||
val conversationIds = inbox.conversations.keys
|
||||
conversations.addLocalConversations(accountKey, conversationIds)
|
||||
val messages = inbox.entries.mapNotNull {
|
||||
ParcelableMessageUtils.fromEntry(accountKey, it, inbox.users)
|
||||
respConversations.keys.let {
|
||||
conversations.addLocalConversations(accountKey, it)
|
||||
}
|
||||
val messages = respEntries.mapNotNull {
|
||||
ParcelableMessageUtils.fromEntry(accountKey, it, respUsers)
|
||||
}
|
||||
val messagesMap = messages.groupBy(ParcelableMessage::conversation_id)
|
||||
for ((k, v) in inbox.conversations) {
|
||||
for ((k, v) in respConversations) {
|
||||
val message = messagesMap[k]?.maxBy(ParcelableMessage::message_timestamp) ?: continue
|
||||
val participants = inbox.users.filterKeys { userId ->
|
||||
val participants = respUsers.filterKeys { userId ->
|
||||
v.participants.any { it.userId == userId }
|
||||
}.values
|
||||
val conversationType = when (v.type?.toUpperCase(Locale.US)) {
|
||||
|
@ -105,6 +122,13 @@ class GetMessagesTask(
|
|||
val conversation = conversations.addConversation(k, details, message, participants,
|
||||
conversationType)
|
||||
conversation.conversation_name = v.name
|
||||
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)
|
||||
}
|
||||
|
@ -300,23 +324,27 @@ class GetMessagesTask(
|
|||
|
||||
override val sinceIds: Array<String?>?
|
||||
get() {
|
||||
val keys = accounts.map { account ->
|
||||
when (account?.type) {
|
||||
AccountType.FANFOU -> {
|
||||
return@map null
|
||||
}
|
||||
}
|
||||
return@map account?.key
|
||||
}.toTypedArray()
|
||||
val incomingIds = DataStoreUtils.getNewestMessageIds(context, Messages.CONTENT_URI,
|
||||
keys, false)
|
||||
defaultKeys, false)
|
||||
val outgoingIds = DataStoreUtils.getNewestMessageIds(context, Messages.CONTENT_URI,
|
||||
keys, true)
|
||||
defaultKeys, true)
|
||||
return incomingIds + outgoingIds
|
||||
}
|
||||
|
||||
override val cursors: Array<String?>?
|
||||
get() {
|
||||
val cursors = arrayOfNulls<String>(defaultKeys.size)
|
||||
val newestConversations = DataStoreUtils.getNewestConversations(context,
|
||||
Messages.Conversations.CONTENT_URI, twitterOfficialKeys)
|
||||
newestConversations.forEachIndexed { i, conversation ->
|
||||
cursors[i] = conversation?.request_cursor
|
||||
}
|
||||
return cursors
|
||||
}
|
||||
|
||||
override val hasSinceIds: Boolean = true
|
||||
override val hasMaxIds: Boolean = false
|
||||
override val hasCursors: Boolean = true
|
||||
}
|
||||
|
||||
class LoadMoreTaskParam(
|
||||
|
@ -324,22 +352,19 @@ class GetMessagesTask(
|
|||
getAccountKeys: () -> Array<UserKey>
|
||||
) : RefreshMessagesTaskParam(context, getAccountKeys) {
|
||||
|
||||
override val maxIds: Array<String?>?
|
||||
get() {
|
||||
val keys = accounts.map { account ->
|
||||
when (account?.type) {
|
||||
AccountType.FANFOU -> {
|
||||
return@map null
|
||||
}
|
||||
}
|
||||
return@map account?.key
|
||||
}.toTypedArray()
|
||||
val incomingIds = DataStoreUtils.getOldestMessageIds(context, Messages.CONTENT_URI,
|
||||
keys, false)
|
||||
val outgoingIds = DataStoreUtils.getOldestMessageIds(context, Messages.CONTENT_URI,
|
||||
keys, true)
|
||||
return incomingIds + outgoingIds
|
||||
override val maxIds: Array<String?>? by lazy {
|
||||
val incomingIds = DataStoreUtils.getOldestMessageIds(context, Messages.CONTENT_URI,
|
||||
defaultKeys, false)
|
||||
val outgoingIds = DataStoreUtils.getOldestMessageIds(context, Messages.CONTENT_URI,
|
||||
defaultKeys, true)
|
||||
val oldestConversations = DataStoreUtils.getOldestConversations(context,
|
||||
Messages.Conversations.CONTENT_URI, twitterOfficialKeys)
|
||||
oldestConversations.forEachIndexed { i, conversation ->
|
||||
val extras = conversation?.conversation_extras as? TwitterOfficialConversationExtras ?: return@forEachIndexed
|
||||
incomingIds[i] = extras.maxEntryId
|
||||
}
|
||||
return@lazy incomingIds + outgoingIds
|
||||
}
|
||||
|
||||
override val hasSinceIds: Boolean = false
|
||||
override val hasMaxIds: Boolean = true
|
||||
|
@ -359,6 +384,26 @@ class GetMessagesTask(
|
|||
AccountUtils.getAllAccountDetails(AccountManager.get(context), accountKeys, false)
|
||||
}
|
||||
|
||||
protected val defaultKeys: Array<UserKey?>by lazy {
|
||||
return@lazy accounts.map { account ->
|
||||
account ?: return@map null
|
||||
if (account.isOfficial(context) || account.type == AccountType.FANFOU) {
|
||||
return@map null
|
||||
}
|
||||
return@map account.key
|
||||
}.toTypedArray()
|
||||
}
|
||||
|
||||
protected val twitterOfficialKeys: Array<UserKey?> by lazy {
|
||||
return@lazy accounts.map { account ->
|
||||
account ?: return@map null
|
||||
if (!account.isOfficial(context)) {
|
||||
return@map null
|
||||
}
|
||||
return@map account.key
|
||||
}.toTypedArray()
|
||||
}
|
||||
|
||||
override final val accountKeys: Array<UserKey>
|
||||
get() = getAccountKeys()
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ import org.apache.commons.lang3.ArrayUtils
|
|||
import org.apache.commons.lang3.StringUtils
|
||||
import org.mariotaku.kpreferences.get
|
||||
import org.mariotaku.ktextension.useCursor
|
||||
import org.mariotaku.library.objectcursor.ObjectCursor
|
||||
import org.mariotaku.microblog.library.MicroBlogException
|
||||
import org.mariotaku.microblog.library.twitter.model.Activity
|
||||
import org.mariotaku.sqliteqb.library.*
|
||||
|
@ -173,11 +174,25 @@ object DataStoreUtils {
|
|||
}
|
||||
|
||||
fun getOldestMessageIds(context: Context, uri: Uri, accountKeys: Array<UserKey?>, outgoing: Boolean): Array<String?> {
|
||||
if (accountKeys.all { it == null }) return kotlin.arrayOfNulls(accountKeys.size)
|
||||
val having: Expression = Expression.equals(Messages.IS_OUTGOING, if (outgoing) 1 else 0)
|
||||
return getStringFieldArray(context, uri, accountKeys, Messages.ACCOUNT_KEY, Messages.MESSAGE_ID,
|
||||
OrderBy(SQLFunctions.MIN(Messages.LOCAL_TIMESTAMP)), having, null)
|
||||
}
|
||||
|
||||
fun getOldestConversations(context: Context, uri: Uri, accountKeys: Array<UserKey?>): Array<ParcelableMessageConversation?> {
|
||||
if (accountKeys.all { it == null }) return kotlin.arrayOfNulls(accountKeys.size)
|
||||
return getObjectFieldArray(context, uri, accountKeys, Conversations.ACCOUNT_KEY, Conversations.COLUMNS,
|
||||
OrderBy(SQLFunctions.MIN(Messages.LOCAL_TIMESTAMP)), null, null,
|
||||
::ParcelableMessageConversationCursorIndices, { arrayOfNulls<ParcelableMessageConversation>(it) })
|
||||
}
|
||||
|
||||
fun getNewestConversations(context: Context, uri: Uri, accountKeys: Array<UserKey?>): Array<ParcelableMessageConversation?> {
|
||||
if (accountKeys.all { it == null }) return kotlin.arrayOfNulls(accountKeys.size)
|
||||
return getObjectFieldArray(context, uri, accountKeys, Conversations.ACCOUNT_KEY, Conversations.COLUMNS,
|
||||
OrderBy(SQLFunctions.MAX(Messages.LOCAL_TIMESTAMP)), null, null,
|
||||
::ParcelableMessageConversationCursorIndices, { arrayOfNulls<ParcelableMessageConversation>(it) })
|
||||
}
|
||||
|
||||
fun getNewestStatusSortIds(context: Context, uri: Uri, accountKeys: Array<UserKey?>): LongArray {
|
||||
return getLongFieldArray(context, uri, accountKeys, Statuses.ACCOUNT_KEY, Statuses.SORT_ID,
|
||||
|
@ -595,32 +610,58 @@ object DataStoreUtils {
|
|||
return false
|
||||
}
|
||||
|
||||
private fun getStringFieldArray(context: Context, uri: Uri,
|
||||
keys: Array<UserKey?>, keyField: String,
|
||||
valueField: String, sortExpression: OrderBy?,
|
||||
extraHaving: Expression?, extraHavingArgs: Array<String>?): Array<String?> {
|
||||
return getFieldArray(context, uri, keys, keyField, valueField, sortExpression, extraHaving,
|
||||
extraHavingArgs, object : FieldArrayCreator<Array<String?>> {
|
||||
private fun <T> getObjectFieldArray(context: Context, uri: Uri, keys: Array<UserKey?>,
|
||||
keyField: String, valueFields: Array<String>, sortExpression: OrderBy?, extraHaving: Expression?,
|
||||
extraHavingArgs: Array<String>?, createIndices: (Cursor) -> ObjectCursor.CursorIndices<T>,
|
||||
createArray: (Int) -> Array<T?>): Array<T?> {
|
||||
return getFieldsArray(context, uri, keys, keyField, valueFields, sortExpression,
|
||||
extraHaving, extraHavingArgs, object : FieldArrayCreator<Array<T?>, ObjectCursor.CursorIndices<T>> {
|
||||
override fun newArray(size: Int): Array<T?> {
|
||||
return createArray(size)
|
||||
}
|
||||
|
||||
override fun newIndex(cur: Cursor): ObjectCursor.CursorIndices<T> {
|
||||
return createIndices(cur)
|
||||
}
|
||||
|
||||
override fun assign(array: Array<T?>, arrayIdx: Int, cur: Cursor, colIdx: ObjectCursor.CursorIndices<T>) {
|
||||
array[arrayIdx] = colIdx.newObject(cur)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun getStringFieldArray(context: Context, uri: Uri, keys: Array<UserKey?>,
|
||||
keyField: String, valueField: String, sortExpression: OrderBy?, extraHaving: Expression?,
|
||||
extraHavingArgs: Array<String>?): Array<String?> {
|
||||
return getFieldsArray(context, uri, keys, keyField, arrayOf(valueField), sortExpression,
|
||||
extraHaving, extraHavingArgs, object : FieldArrayCreator<Array<String?>, Int> {
|
||||
override fun newArray(size: Int): Array<String?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
|
||||
override fun newIndex(cur: Cursor): Int {
|
||||
return cur.getColumnIndex(valueField)
|
||||
}
|
||||
|
||||
override fun assign(array: Array<String?>, arrayIdx: Int, cur: Cursor, colIdx: Int) {
|
||||
array[arrayIdx] = cur.getString(colIdx)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun getLongFieldArray(context: Context, uri: Uri,
|
||||
keys: Array<UserKey?>, keyField: String,
|
||||
valueField: String, sortExpression: OrderBy?,
|
||||
extraHaving: Expression?, extraHavingArgs: Array<String>?): LongArray {
|
||||
return getFieldArray(context, uri, keys, keyField, valueField, sortExpression, extraHaving,
|
||||
extraHavingArgs, object : FieldArrayCreator<LongArray> {
|
||||
private fun getLongFieldArray(context: Context, uri: Uri, keys: Array<UserKey?>,
|
||||
keyField: String, valueField: String, sortExpression: OrderBy?, extraWhere: Expression?,
|
||||
extraWhereArgs: Array<String>?): LongArray {
|
||||
return getFieldsArray(context, uri, keys, keyField, arrayOf(valueField), sortExpression,
|
||||
extraWhere, extraWhereArgs, object : FieldArrayCreator<LongArray, Int> {
|
||||
override fun newArray(size: Int): LongArray {
|
||||
return LongArray(size)
|
||||
}
|
||||
|
||||
override fun newIndex(cur: Cursor): Int {
|
||||
return cur.getColumnIndex(valueField)
|
||||
}
|
||||
|
||||
override fun assign(array: LongArray, arrayIdx: Int, cur: Cursor, colIdx: Int) {
|
||||
array[arrayIdx] = cur.getLong(colIdx)
|
||||
}
|
||||
|
@ -628,12 +669,12 @@ object DataStoreUtils {
|
|||
}
|
||||
|
||||
@SuppressLint("Recycle")
|
||||
private fun <T> getFieldArray(
|
||||
private fun <T, I> getFieldsArray(
|
||||
context: Context, uri: Uri,
|
||||
keys: Array<UserKey?>, keyField: String,
|
||||
valueField: String, sortExpression: OrderBy?,
|
||||
valueFields: Array<String>, sortExpression: OrderBy?,
|
||||
extraWhere: Expression?, extraWhereArgs: Array<String>?,
|
||||
creator: FieldArrayCreator<T>
|
||||
creator: FieldArrayCreator<T, I>
|
||||
): T {
|
||||
val resolver = context.contentResolver
|
||||
val resultArray = creator.newArray(keys.size)
|
||||
|
@ -646,7 +687,7 @@ object DataStoreUtils {
|
|||
} else {
|
||||
bindingArgs = nonNullKeys
|
||||
}
|
||||
val builder = SQLQueryBuilder.select(Columns(keyField, valueField))
|
||||
val builder = SQLQueryBuilder.select(Columns(keyField, *valueFields))
|
||||
builder.from(Table(tableName))
|
||||
if (extraWhere != null) {
|
||||
builder.where(extraWhere)
|
||||
|
@ -659,13 +700,14 @@ object DataStoreUtils {
|
|||
val rawUri = Uri.withAppendedPath(TwidereDataStore.CONTENT_URI_RAW_QUERY, builder.buildSQL())
|
||||
resolver.query(rawUri, null, null, bindingArgs, null)?.useCursor { cur ->
|
||||
cur.moveToFirst()
|
||||
val colIdx = creator.newIndex(cur)
|
||||
while (!cur.isAfterLast) {
|
||||
val string = cur.getString(0)
|
||||
if (string != null) {
|
||||
val accountKey = UserKey.valueOf(string)
|
||||
val idx = ArrayUtils.indexOf(keys, accountKey)
|
||||
if (idx >= 0) {
|
||||
creator.assign(resultArray, idx, cur, 1)
|
||||
val keyString = cur.getString(cur.getColumnIndex(keyField))
|
||||
if (keyString != null) {
|
||||
val accountKey = UserKey.valueOf(keyString)
|
||||
val arrayIdx = ArrayUtils.indexOf(keys, accountKey)
|
||||
if (arrayIdx >= 0) {
|
||||
creator.assign(resultArray, arrayIdx, cur, colIdx)
|
||||
}
|
||||
}
|
||||
cur.moveToNext()
|
||||
|
@ -737,10 +779,12 @@ object DataStoreUtils {
|
|||
cursor.close()
|
||||
}
|
||||
|
||||
internal interface FieldArrayCreator<T> {
|
||||
internal interface FieldArrayCreator<T, I> {
|
||||
fun newArray(size: Int): T
|
||||
|
||||
fun assign(array: T, arrayIdx: Int, cur: Cursor, colIdx: Int)
|
||||
fun newIndex(cur: Cursor): I
|
||||
|
||||
fun assign(array: T, arrayIdx: Int, cur: Cursor, colIdx: I)
|
||||
}
|
||||
|
||||
fun queryCount(context: Context, uri: Uri,
|
||||
|
|
|
@ -105,7 +105,7 @@ class MessageViewHolder(itemView: View, adapter: MessagesConversationAdapter) :
|
|||
} else {
|
||||
mediaPreview.visibility = View.VISIBLE
|
||||
mediaPreview.displayMedia(adapter.mediaLoader, message.media, message.account_key,
|
||||
withCredentials = true)
|
||||
withCredentials = true, loadingHandler = adapter.mediaLoadingHandler)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue