mirror of
https://github.com/TwidereProject/Twidere-Android
synced 2025-02-17 04:00:48 +01:00
fanfou support
This commit is contained in:
parent
2b6c3e5e71
commit
5b9b727b09
@ -254,4 +254,5 @@ public interface TwidereConstants extends SharedPreferenceConstants, IntentConst
|
||||
int TWITTER_MAX_IMAGE_HEIGHT = 2048;
|
||||
|
||||
String USER_TYPE_TWITTER_COM = "twitter.com";
|
||||
String USER_TYPE_FANFOU_COM = "fanfou.com";
|
||||
}
|
||||
|
@ -49,11 +49,11 @@ public interface TimelineResources {
|
||||
ResponseList<Status> getRetweetsOfMe(@Query Paging paging) throws TwitterException;
|
||||
|
||||
@GET("/statuses/user_timeline.json")
|
||||
ResponseList<Status> getUserTimeline(@Query("user_id") long userId, @Query Paging paging) throws TwitterException;
|
||||
ResponseList<Status> getUserTimeline(@Query("user_id") String userId, @Query Paging paging) throws TwitterException;
|
||||
|
||||
@GET("/statuses/user_timeline.json")
|
||||
ResponseList<Status> getUserTimeline(@Query Paging paging) throws TwitterException;
|
||||
|
||||
@GET("/statuses/user_timeline.json")
|
||||
ResponseList<Status> getUserTimeline(@Query("screen_name") String screenName, @Query Paging paging) throws TwitterException;
|
||||
ResponseList<Status> getUserTimelineByScreenName(@Query("screen_name") String screenName, @Query Paging paging) throws TwitterException;
|
||||
}
|
||||
|
@ -58,6 +58,14 @@ public class Activity$$JsonObjectMapper extends JsonMapper<Activity> {
|
||||
parseField(instance, fieldName, jsonParser);
|
||||
jsonParser.skipChildren();
|
||||
}
|
||||
try {
|
||||
instance.maxSortPosition = Long.parseLong(instance.maxPosition);
|
||||
instance.minSortPosition = Long.parseLong(instance.minPosition);
|
||||
} catch (NumberFormatException e) {
|
||||
final long time = instance.createdAt != null ? instance.createdAt.getTime() : -1;
|
||||
instance.maxSortPosition = time;
|
||||
instance.minSortPosition = time;
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
@ -77,9 +85,9 @@ public class Activity$$JsonObjectMapper extends JsonMapper<Activity> {
|
||||
throw new IOException(e);
|
||||
}
|
||||
} else if ("min_position".equals(fieldName)) {
|
||||
instance.minPosition = jsonParser.getValueAsLong(-1);
|
||||
instance.minPosition = jsonParser.getValueAsString();
|
||||
} else if ("max_position".equals(fieldName)) {
|
||||
instance.maxPosition = jsonParser.getValueAsLong(-1);
|
||||
instance.maxPosition = jsonParser.getValueAsString();
|
||||
} else if ("sources_size".equals(fieldName)) {
|
||||
instance.sourcesSize = jsonParser.getValueAsInt();
|
||||
} else if ("targets_size".equals(fieldName)) {
|
||||
|
@ -39,7 +39,8 @@ public class Activity extends TwitterResponseObject implements TwitterResponse,
|
||||
User[] targetObjectUsers;
|
||||
Status[] targetObjectStatuses, targetStatuses;
|
||||
UserList[] targetUserLists, targetObjectUserLists;
|
||||
long maxPosition, minPosition = -1;
|
||||
String maxPosition = null, minPosition = null;
|
||||
long maxSortPosition =-1, minSortPosition = -1;
|
||||
int targetObjectsSize, targetsSize, sourcesSize;
|
||||
|
||||
Activity() {
|
||||
@ -66,14 +67,22 @@ public class Activity extends TwitterResponseObject implements TwitterResponse,
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public long getMaxPosition() {
|
||||
public String getMaxPosition() {
|
||||
return maxPosition;
|
||||
}
|
||||
|
||||
public long getMinPosition() {
|
||||
public String getMinPosition() {
|
||||
return minPosition;
|
||||
}
|
||||
|
||||
public long getMaxSortPosition() {
|
||||
return maxSortPosition;
|
||||
}
|
||||
|
||||
public long getMinSortPosition() {
|
||||
return minSortPosition;
|
||||
}
|
||||
|
||||
public User[] getSources() {
|
||||
return sources;
|
||||
}
|
||||
@ -112,28 +121,33 @@ public class Activity extends TwitterResponseObject implements TwitterResponse,
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ActivityJSONImpl{" +
|
||||
"action=" + action +
|
||||
return "Activity{" +
|
||||
"action='" + action + '\'' +
|
||||
", rawAction='" + rawAction + '\'' +
|
||||
", createdAt=" + createdAt +
|
||||
", sources=" + Arrays.toString(sources) +
|
||||
", targetUsers=" + Arrays.toString(targetUsers) +
|
||||
", targetObjectUsers=" + Arrays.toString(targetObjectUsers) +
|
||||
", targetObjectStatuses=" + Arrays.toString(targetObjectStatuses) +
|
||||
", targetStatuses=" + Arrays.toString(targetStatuses) +
|
||||
", targetUserLists=" + Arrays.toString(targetUserLists) +
|
||||
", targetObjectUserLists=" + Arrays.toString(targetObjectUserLists) +
|
||||
", maxPosition=" + maxPosition +
|
||||
", minPosition=" + minPosition +
|
||||
", maxPosition='" + maxPosition + '\'' +
|
||||
", minPosition='" + minPosition + '\'' +
|
||||
", maxSortPosition=" + maxSortPosition +
|
||||
", minSortPosition=" + minSortPosition +
|
||||
", targetObjectsSize=" + targetObjectsSize +
|
||||
", targetsSize=" + targetsSize +
|
||||
", sourcesSize=" + sourcesSize +
|
||||
'}';
|
||||
"} " + super.toString();
|
||||
}
|
||||
|
||||
public static Activity fromMention(String twitterId, Status status) {
|
||||
final Activity activity = new Activity();
|
||||
|
||||
// TODO handle this -1 position case
|
||||
activity.maxPosition = activity.minPosition = -1;
|
||||
activity.maxPosition = activity.minPosition = null;
|
||||
activity.maxSortPosition = activity.minSortPosition = status.getSortId();
|
||||
activity.createdAt = status.getCreatedAt();
|
||||
|
||||
if (TextUtils.equals(status.getInReplyToUserId(), twitterId)) {
|
||||
|
@ -71,7 +71,10 @@ public class SavedSearch extends TwitterResponseObject implements Comparable<Sav
|
||||
|
||||
@Override
|
||||
public int compareTo(@NonNull SavedSearch another) {
|
||||
return (int) (id - another.id);
|
||||
final long diff = id - another.id;
|
||||
if (diff > Integer.MAX_VALUE) return Integer.MAX_VALUE;
|
||||
if (diff < Integer.MIN_VALUE) return Integer.MIN_VALUE;
|
||||
return (int) diff;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ package org.mariotaku.twidere.api.twitter.model;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.bluelinelabs.logansquare.annotation.JsonField;
|
||||
import com.bluelinelabs.logansquare.annotation.JsonObject;
|
||||
@ -47,7 +48,8 @@ public class Status extends TwitterResponseObject implements Comparable<Status>,
|
||||
@JsonField(name = "id")
|
||||
String id;
|
||||
|
||||
@JsonField(name = "raw_id")
|
||||
// Fanfou uses this key
|
||||
@JsonField(name = "rawid")
|
||||
long rawId = -1;
|
||||
|
||||
@JsonField(name = "text")
|
||||
@ -65,12 +67,15 @@ public class Status extends TwitterResponseObject implements Comparable<Status>,
|
||||
@JsonField(name = "extended_entities")
|
||||
Entities extendedEntities;
|
||||
|
||||
@Nullable
|
||||
@JsonField(name = "in_reply_to_status_id")
|
||||
String inReplyToStatusId;
|
||||
|
||||
@Nullable
|
||||
@JsonField(name = "in_reply_to_user_id")
|
||||
String inReplyToUserId;
|
||||
|
||||
@Nullable
|
||||
@JsonField(name = "in_reply_to_screen_name")
|
||||
String inReplyToScreenName;
|
||||
|
||||
@ -115,6 +120,9 @@ public class Status extends TwitterResponseObject implements Comparable<Status>,
|
||||
@JsonField(name = "quoted_status")
|
||||
Status quotedStatus;
|
||||
|
||||
@JsonField(name = "repost_status")
|
||||
Status repostStatus;
|
||||
|
||||
@JsonField(name = "card")
|
||||
CardEntity card;
|
||||
|
||||
@ -138,17 +146,18 @@ public class Status extends TwitterResponseObject implements Comparable<Status>,
|
||||
return user;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
public String getInReplyToScreenName() {
|
||||
return inReplyToScreenName;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
public String getInReplyToUserId() {
|
||||
return inReplyToUserId;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
public String getInReplyToStatusId() {
|
||||
return inReplyToStatusId;
|
||||
}
|
||||
@ -325,18 +334,10 @@ public class Status extends TwitterResponseObject implements Comparable<Status>,
|
||||
|
||||
@Override
|
||||
public int compareTo(@NonNull final Status that) {
|
||||
final int delta = createdAt.compareTo(that.createdAt);
|
||||
if (delta == 0) {
|
||||
if (rawId != -1) {
|
||||
return (int) (rawId - that.rawId);
|
||||
}
|
||||
try {
|
||||
return (int) (Long.parseLong(id) - Long.parseLong(that.id));
|
||||
} catch (NumberFormatException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
return delta;
|
||||
final long diff = getSortId() - that.getSortId();
|
||||
if (diff > Integer.MAX_VALUE) return Integer.MAX_VALUE;
|
||||
if (diff < Integer.MIN_VALUE) return Integer.MIN_VALUE;
|
||||
return (int) diff;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -394,6 +395,15 @@ public class Status extends TwitterResponseObject implements Comparable<Status>,
|
||||
@OnJsonParseComplete
|
||||
void onJsonParseComplete() throws IOException {
|
||||
if (id == null || text == null) throw new IOException("Malformed Status object");
|
||||
// Fix for fanfou
|
||||
if (TextUtils.isEmpty(inReplyToStatusId)) {
|
||||
inReplyToStatusId = null;
|
||||
inReplyToUserId = null;
|
||||
inReplyToScreenName = null;
|
||||
}
|
||||
if (quotedStatus == null && repostStatus != null) {
|
||||
quotedStatus = repostStatus;
|
||||
}
|
||||
}
|
||||
|
||||
public String getLang() {
|
||||
@ -410,7 +420,11 @@ public class Status extends TwitterResponseObject implements Comparable<Status>,
|
||||
sortId = rawId;
|
||||
if (sortId == -1) {
|
||||
// Try use long id
|
||||
sortId = Long.parseLong(id);
|
||||
try {
|
||||
sortId = Long.parseLong(id);
|
||||
} catch (NumberFormatException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
if (sortId == -1 && createdAt != null) {
|
||||
// Try use timestamp
|
||||
|
@ -144,6 +144,12 @@ public class User extends TwitterResponseObject implements Comparable<User> {
|
||||
@JsonField(name = "profile_image_url_https")
|
||||
String profileImageUrlHttps;
|
||||
|
||||
/**
|
||||
* Fanfou has this field
|
||||
*/
|
||||
@JsonField(name = "profile_image_url_large")
|
||||
String profileImageUrlLarge;
|
||||
|
||||
@JsonField(name = "profile_banner_url")
|
||||
String profileBannerUrl;
|
||||
|
||||
@ -363,11 +369,13 @@ public class User extends TwitterResponseObject implements Comparable<User> {
|
||||
return profileImageUrl;
|
||||
}
|
||||
|
||||
|
||||
public String getProfileImageUrlHttps() {
|
||||
return profileImageUrlHttps;
|
||||
}
|
||||
|
||||
public String getProfileImageUrlLarge() {
|
||||
return profileImageUrlLarge;
|
||||
}
|
||||
|
||||
public String getProfileLinkColor() {
|
||||
if (profileLinkColor != null) return profileLinkColor;
|
||||
|
@ -123,7 +123,10 @@ public class UserList extends TwitterResponseObject implements Comparable<UserLi
|
||||
|
||||
@Override
|
||||
public int compareTo(@NonNull UserList another) {
|
||||
return (int) (id - another.id);
|
||||
final long diff = id - another.id;
|
||||
if (diff > Integer.MAX_VALUE) return Integer.MAX_VALUE;
|
||||
if (diff < Integer.MIN_VALUE) return Integer.MIN_VALUE;
|
||||
return (int) diff;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -211,4 +211,5 @@ public interface IntentConstants {
|
||||
String EXTRA_CARD = "card";
|
||||
String EXTRA_IS_POSSIBLY_SENSITIVE = "is_possibly_sensitive";
|
||||
String EXTRA_REFERRAL = "referral";
|
||||
String EXTRA_LOADING_MORE = "loading_more";
|
||||
}
|
||||
|
@ -69,12 +69,19 @@ public class ParcelableActivity implements Comparable<ParcelableActivity>, Parce
|
||||
public long timestamp;
|
||||
@ParcelableThisPlease
|
||||
@JsonField(name = "max_position")
|
||||
@CursorField(value = Activities.MAX_POSITION)
|
||||
public long max_position;
|
||||
@CursorField(value = Activities.MAX_SORT_POSITION)
|
||||
public long max_sort_position;
|
||||
@ParcelableThisPlease
|
||||
@JsonField(name = "min_position")
|
||||
@CursorField(value = Activities.MIN_POSITION)
|
||||
public long min_position;
|
||||
@CursorField(value = Activities.MIN_SORT_POSITION)
|
||||
public long min_sort_position;
|
||||
@JsonField(name = "max_request_position")
|
||||
@CursorField(value = Activities.MAX_REQUEST_POSITION)
|
||||
public String max_position;
|
||||
@ParcelableThisPlease
|
||||
@JsonField(name = "min_request_position")
|
||||
@CursorField(value = Activities.MIN_REQUEST_POSITION)
|
||||
public String min_position;
|
||||
@ParcelableThisPlease
|
||||
@JsonField(name = "action")
|
||||
@CursorField(value = Activities.ACTION)
|
||||
@ -147,8 +154,10 @@ public class ParcelableActivity implements Comparable<ParcelableActivity>, Parce
|
||||
"_id=" + _id +
|
||||
", account_key=" + account_key +
|
||||
", timestamp=" + timestamp +
|
||||
", max_position=" + max_position +
|
||||
", min_position=" + min_position +
|
||||
", max_sort_position=" + max_sort_position +
|
||||
", min_sort_position=" + min_sort_position +
|
||||
", max_position='" + max_position + '\'' +
|
||||
", min_position='" + min_position + '\'' +
|
||||
", action='" + action + '\'' +
|
||||
", source_ids=" + Arrays.toString(source_ids) +
|
||||
", sources=" + Arrays.toString(sources) +
|
||||
@ -160,6 +169,7 @@ public class ParcelableActivity implements Comparable<ParcelableActivity>, Parce
|
||||
", target_object_users=" + Arrays.toString(target_object_users) +
|
||||
", is_gap=" + is_gap +
|
||||
", status_user_following=" + status_user_following +
|
||||
", account_color=" + account_color +
|
||||
", after_filtered_source_ids=" + Arrays.toString(after_filtered_source_ids) +
|
||||
", after_filtered_sources=" + Arrays.toString(after_filtered_sources) +
|
||||
'}';
|
||||
@ -167,7 +177,7 @@ public class ParcelableActivity implements Comparable<ParcelableActivity>, Parce
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return calculateHashCode(account_key, timestamp, max_position, min_position);
|
||||
return calculateHashCode(account_key, timestamp, max_sort_position, min_sort_position);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -182,7 +192,7 @@ public class ParcelableActivity implements Comparable<ParcelableActivity>, Parce
|
||||
public boolean equals(final Object that) {
|
||||
if (!(that instanceof ParcelableActivity)) return false;
|
||||
final ParcelableActivity activity = (ParcelableActivity) that;
|
||||
return max_position == activity.max_position && min_position == activity.min_position;
|
||||
return max_sort_position == activity.max_sort_position && min_sort_position == activity.min_sort_position;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -118,7 +118,9 @@ public class ParcelableDirectMessage implements Parcelable, Comparable<Parcelabl
|
||||
|
||||
@Override
|
||||
public int compareTo(@NonNull final ParcelableDirectMessage another) {
|
||||
final long diff = another.timestamp - timestamp;
|
||||
final long diff = timestamp - another.timestamp;
|
||||
if (diff > Integer.MAX_VALUE) return Integer.MAX_VALUE;
|
||||
if (diff < Integer.MIN_VALUE) return Integer.MIN_VALUE;
|
||||
return (int) diff;
|
||||
}
|
||||
|
||||
|
@ -316,11 +316,13 @@ public class ParcelableStatus implements Parcelable, Comparable<ParcelableStatus
|
||||
|
||||
@Override
|
||||
public int compareTo(@NonNull final ParcelableStatus another) {
|
||||
long timeDelta = timestamp - another.timestamp;
|
||||
if (timeDelta == 0) {
|
||||
return (int) (sort_id - another.sort_id);
|
||||
long diff = timestamp - another.timestamp;
|
||||
if (diff == 0) {
|
||||
diff = sort_id - another.sort_id;
|
||||
}
|
||||
return (int) timeDelta;
|
||||
if (diff > Integer.MAX_VALUE) return Integer.MAX_VALUE;
|
||||
if (diff < Integer.MIN_VALUE) return Integer.MIN_VALUE;
|
||||
return (int) diff;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -82,7 +82,10 @@ public class ParcelableUserList implements Parcelable, Comparable<ParcelableUser
|
||||
|
||||
@Override
|
||||
public int compareTo(@NonNull final ParcelableUserList another) {
|
||||
return (int) (position - another.position);
|
||||
final long diff = position - another.position;
|
||||
if (diff > Integer.MAX_VALUE) return Integer.MAX_VALUE;
|
||||
if (diff < Integer.MIN_VALUE) return Integer.MIN_VALUE;
|
||||
return (int) diff;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -122,24 +122,27 @@ public class UserKey implements Comparable<UserKey>, Parcelable {
|
||||
StringBuilder idBuilder = new StringBuilder(), hostBuilder = new StringBuilder();
|
||||
for (int i = 0, j = str.length(); i < j; i++) {
|
||||
final char ch = str.charAt(i);
|
||||
// accept all characters if is escaping
|
||||
if (!escaping) {
|
||||
if (ch == '\\') {
|
||||
escaping = true;
|
||||
} else if (ch == '@') {
|
||||
idFinished = true;
|
||||
} else if (ch == ',') {
|
||||
// end of item
|
||||
break;
|
||||
}
|
||||
boolean append = false;
|
||||
if (escaping) {
|
||||
// accept all characters if is escaping
|
||||
append = true;
|
||||
escaping = false;
|
||||
} else if (ch == '\\') {
|
||||
escaping = true;
|
||||
} else if (ch == '@') {
|
||||
idFinished = true;
|
||||
} else if (ch == ',') {
|
||||
// end of item, just jump out
|
||||
break;
|
||||
} else {
|
||||
append = true;
|
||||
}
|
||||
if (!isSpecialChar(ch) || !escaping) {
|
||||
if (append) {
|
||||
if (idFinished) {
|
||||
hostBuilder.append(ch);
|
||||
} else {
|
||||
idBuilder.append(ch);
|
||||
}
|
||||
escaping = false;
|
||||
}
|
||||
}
|
||||
if (hostBuilder.length() != 0) {
|
||||
|
@ -919,8 +919,11 @@ public interface TwidereDataStore {
|
||||
String STATUS_QUOTE_TEXT_HTML = "status_quote_text_html";
|
||||
String STATUS_USER_FOLLOWING = "status_user_following";
|
||||
String IS_GAP = "status_is_gap";
|
||||
String MIN_POSITION = "min_position";
|
||||
String MAX_POSITION = "max_position";
|
||||
String MIN_SORT_POSITION = "min_position";
|
||||
String MAX_SORT_POSITION = "max_position";
|
||||
;
|
||||
String MIN_REQUEST_POSITION = "min_request_position";
|
||||
String MAX_REQUEST_POSITION = "max_request_position";
|
||||
String SOURCES = "sources";
|
||||
String SOURCE_IDS = "source_ids";
|
||||
String TARGET_STATUSES = "target_statuses";
|
||||
@ -933,13 +936,15 @@ public interface TwidereDataStore {
|
||||
String[] COLUMNS = {_ID, ACCOUNT_KEY, ACTION, TIMESTAMP, STATUS_ID, STATUS_USER_ID,
|
||||
STATUS_RETWEETED_BY_USER_ID, STATUS_QUOTED_USER_ID, STATUS_SOURCE, STATUS_QUOTE_SOURCE,
|
||||
STATUS_TEXT_PLAIN, STATUS_QUOTE_TEXT_PLAIN, STATUS_TEXT_HTML, STATUS_QUOTE_TEXT_HTML,
|
||||
IS_GAP, MIN_POSITION, MAX_POSITION, SOURCES, SOURCE_IDS, TARGET_STATUSES, TARGET_USERS,
|
||||
IS_GAP, MIN_SORT_POSITION, MAX_SORT_POSITION, SOURCES, SOURCE_IDS, TARGET_STATUSES, TARGET_USERS,
|
||||
TARGET_USER_LISTS, TARGET_OBJECT_STATUSES, TARGET_OBJECT_USER_LISTS, TARGET_OBJECT_USERS,
|
||||
STATUS_RETWEET_ID, STATUS_USER_FOLLOWING, INSERTED_DATE};
|
||||
STATUS_RETWEET_ID, STATUS_USER_FOLLOWING, INSERTED_DATE, MIN_REQUEST_POSITION,
|
||||
MAX_REQUEST_POSITION};
|
||||
String[] TYPES = {TYPE_PRIMARY_KEY, TYPE_TEXT, TYPE_TEXT, TYPE_INT, TYPE_INT, TYPE_INT,
|
||||
TYPE_INT, TYPE_INT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT,
|
||||
TYPE_BOOLEAN, TYPE_INT, TYPE_INT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT,
|
||||
TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_INT, TYPE_BOOLEAN, INSERTED_DATE_TYPE};
|
||||
TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_INT, TYPE_BOOLEAN, INSERTED_DATE_TYPE, TYPE_TEXT,
|
||||
TYPE_TEXT};
|
||||
|
||||
String DEFAULT_SORT_ORDER = TIMESTAMP + " DESC";
|
||||
|
||||
|
@ -0,0 +1,24 @@
|
||||
package org.mariotaku.twidere.model;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 16/3/10.
|
||||
*/
|
||||
public class UserKeyLocalTest extends TestCase {
|
||||
|
||||
public void testToString() throws Exception {
|
||||
assertEquals("abc@twitter.com", new UserKey("abc", "twitter.com").toString());
|
||||
assertEquals("\\@user@twitter.com", new UserKey("@user", "twitter.com").toString());
|
||||
assertEquals("\\@u\\\\ser@twitter.com", new UserKey("@u\\ser", "twitter.com").toString());
|
||||
}
|
||||
|
||||
public void testValueOf() throws Exception {
|
||||
assertEquals(new UserKey("abc", "twitter.com"), UserKey.valueOf("abc@twitter.com"));
|
||||
assertEquals(new UserKey("abc@", "twitter.com"), UserKey.valueOf("abc\\@@twitter.com"));
|
||||
assertEquals(new UserKey("abc@", "twitter.com"), UserKey.valueOf("a\\bc\\@@twitter.com"));
|
||||
assertEquals(new UserKey("a\\bc@", "twitter.com"), UserKey.valueOf("a\\\\bc\\@@twitter.com"));
|
||||
assertEquals(new UserKey("abc", "twitter.com"), UserKey.valueOf("abc@twitter.com,def@twitter.com"));
|
||||
assertEquals(new UserKey("@abc", "twitter.com"), UserKey.valueOf("\\@abc@twitter.com,def@twitter.com"));
|
||||
}
|
||||
}
|
@ -12,10 +12,15 @@ public class UserKeyTest {
|
||||
@Test
|
||||
public void testToString() throws Exception {
|
||||
assertEquals("abc@twitter.com", new UserKey("abc", "twitter.com").toString());
|
||||
assertEquals("\\@user@twitter.com", new UserKey("@user", "twitter.com").toString());
|
||||
assertEquals("\\@u\\\\ser@twitter.com", new UserKey("@u\\ser", "twitter.com").toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValueOf() throws Exception {
|
||||
assertEquals(UserKey.valueOf("abc@twitter.com"), new UserKey("abc", "twitter.com"));
|
||||
assertEquals(new UserKey("abc", "twitter.com"), UserKey.valueOf("abc@twitter.com"));
|
||||
assertEquals(new UserKey("abc@", "twitter.com"), UserKey.valueOf("abc\\@@twitter.com"));
|
||||
assertEquals(new UserKey("abc@", "twitter.com"), UserKey.valueOf("a\\bc\\@@twitter.com"));
|
||||
assertEquals(new UserKey("a\\bc@", "twitter.com"), UserKey.valueOf("a\\\\bc\\@@twitter.com"));
|
||||
}
|
||||
}
|
@ -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 = 131;
|
||||
int DATABASES_VERSION = 132;
|
||||
|
||||
int MENU_GROUP_STATUS_EXTENSION = 10;
|
||||
int MENU_GROUP_COMPOSE_EXTENSION = 11;
|
||||
|
@ -567,7 +567,7 @@ public class SignInActivity extends BaseAppCompatActivity implements OnClickList
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Pair<String, String> detectAccountType(Twitter twitter) {
|
||||
private static Pair<String, String> detectAccountType(Twitter twitter, User user) {
|
||||
try {
|
||||
// Get StatusNet specific resource
|
||||
StatusNetConfig config = twitter.getStatusNetConfig();
|
||||
@ -593,6 +593,9 @@ public class SignInActivity extends BaseAppCompatActivity implements OnClickList
|
||||
} catch (TwitterException e) {
|
||||
// Ignore
|
||||
}
|
||||
if (UserKeyUtils.isFanfouUser(user)) {
|
||||
return Pair.create(ParcelableCredentials.ACCOUNT_TYPE_FANFOU, null);
|
||||
}
|
||||
return Pair.create(ParcelableCredentials.ACCOUNT_TYPE_TWITTER, null);
|
||||
}
|
||||
|
||||
@ -680,7 +683,7 @@ public class SignInActivity extends BaseAppCompatActivity implements OnClickList
|
||||
final int color = analyseUserProfileColor(user);
|
||||
return new SignInResponse(isUserLoggedIn(context, userId), auth, user,
|
||||
ParcelableCredentials.AUTH_TYPE_OAUTH, color, apiUrlFormat, sameOauthSigningUrl,
|
||||
noVersionSuffix, detectAccountType(twitter));
|
||||
noVersionSuffix, detectAccountType(twitter, user));
|
||||
} catch (final TwitterException e) {
|
||||
return new SignInResponse(false, false, e);
|
||||
}
|
||||
@ -802,7 +805,7 @@ public class SignInActivity extends BaseAppCompatActivity implements OnClickList
|
||||
if (userId == null) return new SignInResponse(false, false, null);
|
||||
final int color = analyseUserProfileColor(user);
|
||||
return new SignInResponse(isUserLoggedIn(activity, userId), username, password, user,
|
||||
color, apiUrlFormat, noVersionSuffix, detectAccountType(twitter));
|
||||
color, apiUrlFormat, noVersionSuffix, detectAccountType(twitter, user));
|
||||
}
|
||||
|
||||
|
||||
@ -818,7 +821,7 @@ public class SignInActivity extends BaseAppCompatActivity implements OnClickList
|
||||
if (userId == null) return new SignInResponse(false, false, null);
|
||||
final int color = analyseUserProfileColor(user);
|
||||
return new SignInResponse(isUserLoggedIn(activity, userId), user, color, apiUrlFormat,
|
||||
noVersionSuffix, detectAccountType(twitter));
|
||||
noVersionSuffix, detectAccountType(twitter, user));
|
||||
}
|
||||
|
||||
private SignInResponse getOAuthSignInResponse(SignInActivity activity, OAuthToken accessToken,
|
||||
@ -829,7 +832,7 @@ public class SignInActivity extends BaseAppCompatActivity implements OnClickList
|
||||
final User user = twitter.verifyCredentials();
|
||||
final int color = analyseUserProfileColor(user);
|
||||
return new SignInResponse(isUserLoggedIn(activity, userId), auth, user, authType, color,
|
||||
apiUrlFormat, sameOAuthSigningUrl, noVersionSuffix, detectAccountType(twitter));
|
||||
apiUrlFormat, sameOAuthSigningUrl, noVersionSuffix, detectAccountType(twitter, user));
|
||||
}
|
||||
|
||||
static class WrongBasicCredentialException extends AuthenticationException {
|
||||
|
@ -30,10 +30,12 @@ import com.mobeta.android.dslv.SimpleDragSortCursorAdapter;
|
||||
import org.mariotaku.twidere.Constants;
|
||||
import org.mariotaku.twidere.R;
|
||||
import org.mariotaku.twidere.adapter.iface.IBaseAdapter;
|
||||
import org.mariotaku.twidere.model.UserKey;
|
||||
import org.mariotaku.twidere.model.ParcelableAccount;
|
||||
import org.mariotaku.twidere.model.ParcelableAccountCursorIndices;
|
||||
import org.mariotaku.twidere.model.ParcelableUser;
|
||||
import org.mariotaku.twidere.model.UserKey;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Accounts;
|
||||
import org.mariotaku.twidere.util.JsonSerializer;
|
||||
import org.mariotaku.twidere.util.MediaLoaderWrapper;
|
||||
import org.mariotaku.twidere.util.dagger.GeneralComponentHelper;
|
||||
import org.mariotaku.twidere.view.holder.AccountViewHolder;
|
||||
@ -80,7 +82,14 @@ public class AccountsAdapter extends SimpleDragSortCursorAdapter implements Cons
|
||||
holder.screenName.setText(String.format("@%s", cursor.getString(mIndices.screen_name)));
|
||||
holder.setAccountColor(color);
|
||||
if (mDisplayProfileImage) {
|
||||
mImageLoader.displayProfileImage(holder.profileImage, cursor.getString(mIndices.profile_image_url));
|
||||
final ParcelableUser user = JsonSerializer.parse(cursor.getString(mIndices.account_user),
|
||||
ParcelableUser.class);
|
||||
if (user != null) {
|
||||
mImageLoader.displayProfileImage(holder.profileImage, user);
|
||||
} else {
|
||||
mImageLoader.displayProfileImage(holder.profileImage,
|
||||
cursor.getString(mIndices.profile_image_url));
|
||||
}
|
||||
} else {
|
||||
mImageLoader.cancelDisplayTask(holder.profileImage);
|
||||
}
|
||||
|
@ -58,8 +58,6 @@ import org.mariotaku.twidere.util.dagger.ApplicationModule;
|
||||
import org.mariotaku.twidere.util.dagger.DependencyHolder;
|
||||
import org.mariotaku.twidere.util.net.TwidereDns;
|
||||
|
||||
import static org.mariotaku.twidere.util.DataStoreUtils.initAccountColor;
|
||||
|
||||
public class TwidereApplication extends Application implements Constants,
|
||||
OnSharedPreferenceChangeListener {
|
||||
|
||||
@ -122,7 +120,6 @@ public class TwidereApplication extends Application implements Constants,
|
||||
initDebugMode();
|
||||
initBugReport();
|
||||
mHandler = new Handler();
|
||||
initAccountColor(this);
|
||||
|
||||
final PackageManager pm = getPackageManager();
|
||||
final ComponentName main = new ComponentName(this, MainActivity.class);
|
||||
|
@ -341,8 +341,9 @@ public abstract class AbsActivitiesFragment extends AbsContentListRecyclerViewFr
|
||||
final ParcelableActivitiesAdapter adapter = getAdapter();
|
||||
final ParcelableActivity activity = adapter.getActivity(position);
|
||||
final UserKey[] accountIds = {activity.account_key};
|
||||
final String[] maxIds = {String.valueOf(activity.min_position)};
|
||||
getActivities(new BaseRefreshTaskParam(accountIds, maxIds, null));
|
||||
final String[] maxIds = {activity.min_position};
|
||||
final long[] maxSortIds = {activity.min_sort_position};
|
||||
getActivities(new BaseRefreshTaskParam(accountIds, maxIds, null, maxSortIds, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -73,7 +73,6 @@ import org.mariotaku.twidere.view.holder.iface.IStatusViewHolder;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import edu.tsinghua.hotmobi.HotMobiLogger;
|
||||
@ -333,7 +332,8 @@ public abstract class AbsStatusesFragment extends AbsContentListRecyclerViewFrag
|
||||
if (status == null) return;
|
||||
final UserKey[] accountIds = {status.account_key};
|
||||
final String[] maxIds = {status.id};
|
||||
getStatuses(new BaseRefreshTaskParam(accountIds, maxIds, null));
|
||||
final long[] maxSortIds = {status.sort_id};
|
||||
getStatuses(new BaseRefreshTaskParam(accountIds, maxIds, null, maxSortIds, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -356,7 +356,8 @@ public abstract class AbsStatusesFragment extends AbsContentListRecyclerViewFrag
|
||||
}
|
||||
}
|
||||
|
||||
protected void onHasMoreDataChanged(boolean hasMoreData) {}
|
||||
protected void onHasMoreDataChanged(boolean hasMoreData) {
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@TimelineType
|
||||
@ -531,7 +532,7 @@ public abstract class AbsStatusesFragment extends AbsContentListRecyclerViewFrag
|
||||
protected abstract boolean hasMoreData(List<ParcelableStatus> data);
|
||||
|
||||
protected abstract Loader<List<ParcelableStatus>> onCreateStatusesLoader(final Context context, final Bundle args,
|
||||
final boolean fromUser);
|
||||
final boolean fromUser);
|
||||
|
||||
protected abstract void onLoadingFinished();
|
||||
|
||||
@ -555,7 +556,7 @@ public abstract class AbsStatusesFragment extends AbsContentListRecyclerViewFrag
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
|
||||
if (!getUserVisibleHint()) return;
|
||||
if (!getUserVisibleHint() || menuInfo == null) return;
|
||||
final ParcelableStatusesAdapter adapter = getAdapter();
|
||||
final MenuInflater inflater = new MenuInflater(getContext());
|
||||
final ExtendedRecyclerView.ContextMenuInfo contextMenuInfo =
|
||||
|
@ -44,8 +44,8 @@ import org.mariotaku.twidere.R;
|
||||
import org.mariotaku.twidere.activity.support.ColorPickerDialogActivity;
|
||||
import org.mariotaku.twidere.activity.support.SignInActivity;
|
||||
import org.mariotaku.twidere.adapter.AccountsAdapter;
|
||||
import org.mariotaku.twidere.model.UserKey;
|
||||
import org.mariotaku.twidere.model.ParcelableAccount;
|
||||
import org.mariotaku.twidere.model.UserKey;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.AccountSupportColumns;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Accounts;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages.Inbox;
|
||||
@ -151,9 +151,16 @@ public class AccountsManagerFragment extends BaseSupportFragment implements Load
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
final Context context = getContext();
|
||||
if (context == null) return;
|
||||
final ParcelableAccount account = mAdapter.getAccount(position);
|
||||
IntentUtils.openUserProfile(getActivity(), account.account_key, account.account_key.getId(),
|
||||
account.screen_name, null, true, UserFragment.Referral.SELF_PROFILE);
|
||||
if (account.account_user != null) {
|
||||
IntentUtils.openUserProfile(context, account.account_user, null, true,
|
||||
UserFragment.Referral.SELF_PROFILE);
|
||||
} else {
|
||||
IntentUtils.openUserProfile(context, account.account_key, account.account_key.getId(),
|
||||
account.screen_name, null, true, UserFragment.Referral.SELF_PROFILE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -42,12 +42,11 @@ import org.mariotaku.twidere.activity.support.HomeActivity;
|
||||
import org.mariotaku.twidere.adapter.ParcelableActivitiesAdapter;
|
||||
import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter.IndicatorPosition;
|
||||
import org.mariotaku.twidere.loader.support.ExtendedObjectCursorLoader;
|
||||
import org.mariotaku.twidere.model.UserKey;
|
||||
import org.mariotaku.twidere.model.BaseRefreshTaskParam;
|
||||
import org.mariotaku.twidere.model.ParcelableAccount;
|
||||
import org.mariotaku.twidere.model.ParcelableActivity;
|
||||
import org.mariotaku.twidere.model.ParcelableActivityCursorIndices;
|
||||
import org.mariotaku.twidere.model.RefreshTaskParam;
|
||||
import org.mariotaku.twidere.model.SimpleRefreshTaskParam;
|
||||
import org.mariotaku.twidere.model.UserKey;
|
||||
import org.mariotaku.twidere.model.message.AccountChangedEvent;
|
||||
import org.mariotaku.twidere.model.message.FavoriteTaskEvent;
|
||||
import org.mariotaku.twidere.model.message.GetActivitiesTaskEvent;
|
||||
@ -58,8 +57,6 @@ import org.mariotaku.twidere.model.util.ParcelableAccountUtils;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Accounts;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Activities;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Filters;
|
||||
import org.mariotaku.twidere.task.AbstractTask;
|
||||
import org.mariotaku.twidere.task.util.TaskStarter;
|
||||
import org.mariotaku.twidere.util.DataStoreUtils;
|
||||
import org.mariotaku.twidere.util.ErrorInfoStore;
|
||||
import org.mariotaku.twidere.util.TwidereArrayUtils;
|
||||
@ -195,41 +192,61 @@ public abstract class CursorActivitiesFragment extends AbsActivitiesFragment {
|
||||
if ((position & IndicatorPosition.START) != 0) return;
|
||||
super.onLoadMoreContents(position);
|
||||
if (position == 0) return;
|
||||
TaskStarter.execute(new AbstractTask<Object, RefreshTaskParam, CursorActivitiesFragment>() {
|
||||
getActivities(new SimpleRefreshTaskParam() {
|
||||
@NonNull
|
||||
@Override
|
||||
public RefreshTaskParam doLongOperation(Object o) {
|
||||
final UserKey[] accountKeys = getAccountKeys();
|
||||
final String[] maxIds = getOldestActivityIds(accountKeys);
|
||||
return new BaseRefreshTaskParam(accountKeys, maxIds, null);
|
||||
public UserKey[] getAccountKeysWorker() {
|
||||
return CursorActivitiesFragment.this.getAccountKeys();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String[] getMaxIds() {
|
||||
return getOldestActivityIds(getAccountKeys());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public long[] getMaxSortIds() {
|
||||
return DataStoreUtils.getOldestActivityMaxSortPositions(getActivity(),
|
||||
getContentUri(), getAccountKeys());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterExecute(CursorActivitiesFragment fragment, RefreshTaskParam result) {
|
||||
fragment.getActivities(result);
|
||||
public boolean hasMaxIds() {
|
||||
return true;
|
||||
}
|
||||
}.setResultHandler(this));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean triggerRefresh() {
|
||||
super.triggerRefresh();
|
||||
TaskStarter.execute(new AbstractTask<Object, RefreshTaskParam, CursorActivitiesFragment>() {
|
||||
getActivities(new SimpleRefreshTaskParam() {
|
||||
@NonNull
|
||||
@Override
|
||||
public RefreshTaskParam doLongOperation(Object o) {
|
||||
if (getActivity() == null) {
|
||||
return null;
|
||||
}
|
||||
final UserKey[] accountKeys = getAccountKeys();
|
||||
final String[] sinceIds = getNewestActivityIds(accountKeys);
|
||||
return new BaseRefreshTaskParam(accountKeys, sinceIds, null);
|
||||
public UserKey[] getAccountKeysWorker() {
|
||||
return CursorActivitiesFragment.this.getAccountKeys();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String[] getSinceIds() {
|
||||
return getNewestActivityIds(getAccountKeys());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public long[] getSinceSortIds() {
|
||||
return DataStoreUtils.getNewestActivityMaxSortPositions(getActivity(),
|
||||
getContentUri(), getAccountKeys());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterExecute(CursorActivitiesFragment fragment, RefreshTaskParam result) {
|
||||
if (result == null) return;
|
||||
fragment.getActivities(result);
|
||||
public boolean hasSinceIds() {
|
||||
return true;
|
||||
}
|
||||
}.setResultHandler(this));
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -43,11 +43,11 @@ import org.mariotaku.twidere.adapter.ListParcelableStatusesAdapter;
|
||||
import org.mariotaku.twidere.adapter.ParcelableStatusesAdapter;
|
||||
import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter.IndicatorPosition;
|
||||
import org.mariotaku.twidere.loader.support.ExtendedObjectCursorLoader;
|
||||
import org.mariotaku.twidere.model.UserKey;
|
||||
import org.mariotaku.twidere.model.ParcelableAccount;
|
||||
import org.mariotaku.twidere.model.ParcelableStatus;
|
||||
import org.mariotaku.twidere.model.ParcelableStatusCursorIndices;
|
||||
import org.mariotaku.twidere.model.SimpleRefreshTaskParam;
|
||||
import org.mariotaku.twidere.model.UserKey;
|
||||
import org.mariotaku.twidere.model.message.AccountChangedEvent;
|
||||
import org.mariotaku.twidere.model.message.FavoriteTaskEvent;
|
||||
import org.mariotaku.twidere.model.message.GetStatusesTaskEvent;
|
||||
@ -253,11 +253,12 @@ public abstract class CursorStatusesFragment extends AbsStatusesFragment {
|
||||
// Only supports load from end, skip START flag
|
||||
if ((position & IndicatorPosition.START) != 0) return;
|
||||
super.onLoadMoreContents(position);
|
||||
final Context context = getContext();
|
||||
if (position == 0) return;
|
||||
getStatuses(new SimpleRefreshTaskParam() {
|
||||
@NonNull
|
||||
@Override
|
||||
public UserKey[] getAccountKeys() {
|
||||
public UserKey[] getAccountKeysWorker() {
|
||||
return CursorStatusesFragment.this.getAccountKeys();
|
||||
}
|
||||
|
||||
@ -267,6 +268,13 @@ public abstract class CursorStatusesFragment extends AbsStatusesFragment {
|
||||
return getOldestStatusIds(getAccountKeys());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public long[] getMaxSortIds() {
|
||||
return DataStoreUtils.getOldestStatusSortIds(context, getContentUri(),
|
||||
getAccountKeys());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMaxIds() {
|
||||
return true;
|
||||
@ -277,10 +285,11 @@ public abstract class CursorStatusesFragment extends AbsStatusesFragment {
|
||||
@Override
|
||||
public boolean triggerRefresh() {
|
||||
super.triggerRefresh();
|
||||
final Context context = getContext();
|
||||
getStatuses(new SimpleRefreshTaskParam() {
|
||||
@NonNull
|
||||
@Override
|
||||
public UserKey[] getAccountKeys() {
|
||||
public UserKey[] getAccountKeysWorker() {
|
||||
return CursorStatusesFragment.this.getAccountKeys();
|
||||
}
|
||||
|
||||
@ -294,6 +303,13 @@ public abstract class CursorStatusesFragment extends AbsStatusesFragment {
|
||||
public String[] getSinceIds() {
|
||||
return getNewestStatusIds(getAccountKeys());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public long[] getSinceSortIds() {
|
||||
return DataStoreUtils.getNewestStatusSortIds(context, getContentUri(),
|
||||
getAccountKeys());
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
@ -94,6 +94,7 @@ public abstract class ParcelableStatusesFragment extends AbsStatusesFragment {
|
||||
if (mPage > 0) {
|
||||
args.putInt(EXTRA_PAGE, mPage);
|
||||
}
|
||||
args.putBoolean(EXTRA_LOADING_MORE, param.isLoadingMore());
|
||||
args.putBoolean(EXTRA_FROM_USER, true);
|
||||
getLoaderManager().restartLoader(0, args, this);
|
||||
return true;
|
||||
@ -149,12 +150,16 @@ public abstract class ParcelableStatusesFragment extends AbsStatusesFragment {
|
||||
super.onLoadMoreContents(position);
|
||||
if (position == 0) return;
|
||||
final ParcelableStatusesAdapter adapter = getAdapter();
|
||||
final ParcelableStatus status = adapter.getStatus(adapter.getStatusStartIndex() +
|
||||
adapter.getStatusCount() - 1);
|
||||
// Load the last item
|
||||
final int idx = adapter.getStatusStartIndex() + adapter.getStatusCount() - 1;
|
||||
if (idx < 0) return;
|
||||
final ParcelableStatus status = adapter.getStatus(idx);
|
||||
UserKey[] accountKeys = {status.account_key};
|
||||
final String[] maxIds = {status.id};
|
||||
mPage += mPageDelta;
|
||||
getStatuses(new BaseRefreshTaskParam(accountKeys, maxIds, null));
|
||||
final BaseRefreshTaskParam param = new BaseRefreshTaskParam(accountKeys, maxIds, null);
|
||||
param.setIsLoadingMore(true);
|
||||
getStatuses(param);
|
||||
}
|
||||
|
||||
public final void replaceStatus(final ParcelableStatus status) {
|
||||
|
@ -42,8 +42,9 @@ public class RetweetsOfMeFragment extends ParcelableStatusesFragment {
|
||||
final String maxId = args.getString(EXTRA_MAX_ID);
|
||||
final String sinceId = args.getString(EXTRA_SINCE_ID);
|
||||
final int tabPosition = args.getInt(EXTRA_TAB_POSITION, -1);
|
||||
final boolean loadingMore = args.getBoolean(EXTRA_LOADING_MORE, false);
|
||||
return new RetweetsOfMeLoader(context, accountKey, sinceId, maxId, getAdapterData(),
|
||||
getSavedStatusesFileArgs(), tabPosition, fromUser);
|
||||
getSavedStatusesFileArgs(), tabPosition, fromUser, loadingMore);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -222,10 +222,12 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
|
||||
final String sinceId = args.getString(EXTRA_SINCE_ID);
|
||||
final long maxSortId = args.getLong(EXTRA_MAX_SORT_ID);
|
||||
final long sinceSortId = args.getLong(EXTRA_SINCE_SORT_ID);
|
||||
final boolean loadingMore = args.getBoolean(EXTRA_LOADING_MORE, false);
|
||||
assert status != null;
|
||||
final ConversationLoader loader = new ConversationLoader(getActivity(), status, sinceId,
|
||||
maxId, sinceSortId, maxSortId, mStatusAdapter.getData(), true);
|
||||
loader.setComparator(ParcelableStatus.REVERSE_COMPARATOR);
|
||||
maxId, sinceSortId, maxSortId, mStatusAdapter.getData(), true, loadingMore);
|
||||
// Setting comparator to null lets statuses sort ascending
|
||||
loader.setComparator(null);
|
||||
return loader;
|
||||
}
|
||||
|
||||
|
@ -59,8 +59,10 @@ public class StatusesSearchFragment extends ParcelableStatusesFragment {
|
||||
final String query = args.getString(EXTRA_QUERY);
|
||||
final int tabPosition = args.getInt(EXTRA_TAB_POSITION, -1);
|
||||
final boolean makeGap = args.getBoolean(EXTRA_MAKE_GAP, true);
|
||||
final boolean loadingMore = args.getBoolean(EXTRA_LOADING_MORE, false);
|
||||
return new TweetSearchLoader(getActivity(), accountKey, query, sinceId, maxId, page,
|
||||
getAdapterData(), getSavedStatusesFileArgs(), tabPosition, fromUser, makeGap);
|
||||
getAdapterData(), getSavedStatusesFileArgs(), tabPosition, fromUser, makeGap,
|
||||
loadingMore);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -48,8 +48,9 @@ public class UserFavoritesFragment extends ParcelableStatusesFragment {
|
||||
final String userId = args.getString(EXTRA_USER_ID);
|
||||
final String screenName = args.getString(EXTRA_SCREEN_NAME);
|
||||
final int tabPosition = args.getInt(EXTRA_TAB_POSITION, -1);
|
||||
final boolean loadingMore = args.getBoolean(EXTRA_LOADING_MORE, false);
|
||||
return new UserFavoritesLoader(context, accountKey, userId, screenName, sinceId, maxId,
|
||||
getAdapterData(), getSavedStatusesFileArgs(), tabPosition, fromUser);
|
||||
getAdapterData(), getSavedStatusesFileArgs(), tabPosition, fromUser, loadingMore);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -58,8 +58,10 @@ public class UserListTimelineFragment extends ParcelableStatusesFragment {
|
||||
final String screenName = args.getString(EXTRA_SCREEN_NAME);
|
||||
final String listName = args.getString(EXTRA_LIST_NAME);
|
||||
final int tabPosition = args.getInt(EXTRA_TAB_POSITION, -1);
|
||||
final boolean loadingMore = args.getBoolean(EXTRA_LOADING_MORE, false);
|
||||
return new UserListTimelineLoader(getActivity(), accountKey, listId, userId, screenName,
|
||||
listName, sinceId, maxId, getAdapterData(), getSavedStatusesFileArgs(), tabPosition, fromUser);
|
||||
listName, sinceId, maxId, getAdapterData(), getSavedStatusesFileArgs(), tabPosition,
|
||||
fromUser, loadingMore);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -105,8 +105,9 @@ public class UserMediaTimelineFragment extends AbsContentRecyclerViewFragment<St
|
||||
final String screenName = args.getString(EXTRA_SCREEN_NAME);
|
||||
final int tabPosition = args.getInt(EXTRA_TAB_POSITION, -1);
|
||||
final boolean fromUser = args.getBoolean(EXTRA_FROM_USER);
|
||||
final boolean loadingMore = args.getBoolean(EXTRA_LOADING_MORE, false);
|
||||
return new MediaTimelineLoader(context, accountKey, userId, screenName, sinceId, maxId,
|
||||
getAdapter().getData(), null, tabPosition, fromUser);
|
||||
getAdapter().getData(), null, tabPosition, fromUser, loadingMore);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -46,8 +46,10 @@ public class UserMentionsFragment extends StatusesSearchFragment {
|
||||
final int page = args.getInt(EXTRA_PAGE, -1);
|
||||
final int tabPosition = args.getInt(EXTRA_TAB_POSITION, -1);
|
||||
final boolean makeGap = args.getBoolean(EXTRA_MAKE_GAP, true);
|
||||
final boolean loadingMore = args.getBoolean(EXTRA_LOADING_MORE, false);
|
||||
return new UserMentionsLoader(getActivity(), accountKey, screenName, maxId, sinceId, page,
|
||||
getAdapterData(), getSavedStatusesFileArgs(), tabPosition, fromUser, makeGap);
|
||||
getAdapterData(), getSavedStatusesFileArgs(), tabPosition, fromUser, makeGap,
|
||||
loadingMore);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -56,8 +56,9 @@ public class UserTimelineFragment extends ParcelableStatusesFragment {
|
||||
final String userId = args.getString(EXTRA_USER_ID);
|
||||
final String screenName = args.getString(EXTRA_SCREEN_NAME);
|
||||
final int tabPosition = args.getInt(EXTRA_TAB_POSITION, -1);
|
||||
final boolean loadingMore = args.getBoolean(EXTRA_LOADING_MORE, false);
|
||||
return new UserTimelineLoader(context, accountKey, userId, screenName, sinceId, maxId, data,
|
||||
getSavedStatusesFileArgs(), tabPosition, fromUser);
|
||||
getSavedStatusesFileArgs(), tabPosition, fromUser, loadingMore);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -52,8 +52,9 @@ public class ConversationLoader extends TwitterAPIStatusesLoader {
|
||||
public ConversationLoader(final Context context, @NonNull final ParcelableStatus status,
|
||||
final String sinceId, final String maxId,
|
||||
final long sinceSortId, final long maxSortId,
|
||||
final List<ParcelableStatus> data, final boolean fromUser) {
|
||||
super(context, status.account_key, sinceId, maxId, data, null, -1, fromUser);
|
||||
final List<ParcelableStatus> data, final boolean fromUser,
|
||||
final boolean loadingMore) {
|
||||
super(context, status.account_key, sinceId, maxId, data, null, -1, fromUser, loadingMore);
|
||||
mStatus = Nullables.assertNonNull(ParcelUtils.clone(status));
|
||||
mSinceSortId = sinceSortId;
|
||||
mMaxSortId = maxSortId;
|
||||
|
@ -55,8 +55,9 @@ public class MediaTimelineLoader extends TwitterAPIStatusesLoader {
|
||||
public MediaTimelineLoader(final Context context, final UserKey accountKey, final String userId,
|
||||
final String screenName, final String sinceId, final String maxId,
|
||||
final List<ParcelableStatus> data, final String[] savedStatusesArgs,
|
||||
final int tabPosition, final boolean fromUser) {
|
||||
super(context, accountKey, sinceId, maxId, data, savedStatusesArgs, tabPosition, fromUser);
|
||||
final int tabPosition, final boolean fromUser, boolean loadingMore) {
|
||||
super(context, accountKey, sinceId, maxId, data, savedStatusesArgs, tabPosition, fromUser,
|
||||
loadingMore);
|
||||
mUserId = userId;
|
||||
mUserScreenName = screenName;
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ import org.mariotaku.twidere.model.ParcelableStatus;
|
||||
import org.mariotaku.twidere.util.collection.NoDuplicatesArrayList;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public abstract class ParcelableStatusesLoader extends AsyncTaskLoader<List<ParcelableStatus>>
|
||||
implements Constants, IExtendedLoader {
|
||||
@ -39,7 +40,7 @@ public abstract class ParcelableStatusesLoader extends AsyncTaskLoader<List<Parc
|
||||
private final int mTabPosition;
|
||||
private boolean mFromUser;
|
||||
|
||||
public ParcelableStatusesLoader(final Context context, final List<ParcelableStatus> data,
|
||||
public ParcelableStatusesLoader(final Context context, @Nullable final List<ParcelableStatus> data,
|
||||
final int tabPosition, final boolean fromUser) {
|
||||
super(context);
|
||||
mFirstLoad = data == null;
|
||||
@ -71,7 +72,7 @@ public abstract class ParcelableStatusesLoader extends AsyncTaskLoader<List<Parc
|
||||
if (statuses == null || statuses.isEmpty()) return false;
|
||||
boolean result = false;
|
||||
for (int i = statuses.size() - 1; i >= 0; i--) {
|
||||
if (statuses.get(i).id == statusId) {
|
||||
if (TextUtils.equals(statuses.get(i).id, statusId)) {
|
||||
statuses.remove(i);
|
||||
result = true;
|
||||
}
|
||||
|
@ -42,8 +42,9 @@ public class RetweetsOfMeLoader extends TwitterAPIStatusesLoader {
|
||||
public RetweetsOfMeLoader(final Context context, final UserKey accountKey,
|
||||
final String sinceId, final String maxId,
|
||||
final List<ParcelableStatus> data, final String[] savedStatusesArgs,
|
||||
final int tabPosition, boolean fromUser) {
|
||||
super(context, accountKey, sinceId, maxId, data, savedStatusesArgs, tabPosition, fromUser);
|
||||
final int tabPosition, boolean fromUser, boolean loadingMore) {
|
||||
super(context, accountKey, sinceId, maxId, data, savedStatusesArgs, tabPosition, fromUser,
|
||||
loadingMore);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
@ -48,8 +48,9 @@ public class TweetSearchLoader extends TwitterAPIStatusesLoader {
|
||||
public TweetSearchLoader(final Context context, final UserKey accountKey, @Nullable final String query,
|
||||
final String sinceId, final String maxId, final int page,
|
||||
final List<ParcelableStatus> data, final String[] savedStatusesArgs,
|
||||
final int tabPosition, final boolean fromUser, final boolean makeGap) {
|
||||
super(context, accountKey, sinceId, maxId, data, savedStatusesArgs, tabPosition, fromUser);
|
||||
final int tabPosition, final boolean fromUser, final boolean makeGap,
|
||||
boolean loadingMore) {
|
||||
super(context, accountKey, sinceId, maxId, data, savedStatusesArgs, tabPosition, fromUser, loadingMore);
|
||||
mPage = page;
|
||||
mQuery = query;
|
||||
mGapEnabled = makeGap;
|
||||
|
@ -72,7 +72,9 @@ public abstract class TwitterAPIStatusesLoader extends ParcelableStatusesLoader
|
||||
private final String mMaxId, mSinceId;
|
||||
@Nullable
|
||||
private final Object[] mSavedStatusesFileArgs;
|
||||
private Comparator<ParcelableStatus> mComparator;
|
||||
private final boolean mLoadingMore;
|
||||
// Statuses sorted descending by default
|
||||
private Comparator<ParcelableStatus> mComparator = ParcelableStatus.REVERSE_COMPARATOR;
|
||||
@Inject
|
||||
DiskCache mFileCache;
|
||||
@Inject
|
||||
@ -81,15 +83,16 @@ public abstract class TwitterAPIStatusesLoader extends ParcelableStatusesLoader
|
||||
public TwitterAPIStatusesLoader(@NonNull final Context context,
|
||||
@Nullable final UserKey accountKey,
|
||||
final String sinceId, final String maxId,
|
||||
final List<ParcelableStatus> data,
|
||||
@Nullable final List<ParcelableStatus> data,
|
||||
@Nullable final String[] savedStatusesArgs,
|
||||
final int tabPosition, final boolean fromUser) {
|
||||
final int tabPosition, final boolean fromUser, boolean loadingMore) {
|
||||
super(context, data, tabPosition, fromUser);
|
||||
GeneralComponentHelper.build(context).inject(this);
|
||||
mAccountKey = accountKey;
|
||||
mMaxId = maxId;
|
||||
mSinceId = sinceId;
|
||||
mSavedStatusesFileArgs = savedStatusesArgs;
|
||||
mLoadingMore = loadingMore;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@ -163,7 +166,7 @@ public abstract class TwitterAPIStatusesLoader extends ParcelableStatusesLoader
|
||||
final boolean deletedOldGap = rowsDeleted > 0 && ArrayUtils.contains(statusIds, mMaxId);
|
||||
final boolean noRowsDeleted = rowsDeleted == 0;
|
||||
final boolean insertGap = minIdx != -1 && (noRowsDeleted || deletedOldGap) && !noItemsBefore
|
||||
&& statuses.size() >= loadItemLimit;
|
||||
&& statuses.size() >= loadItemLimit && !mLoadingMore;
|
||||
for (int i = 0, j = statuses.size(); i < j; i++) {
|
||||
final Status status = statuses.get(i);
|
||||
final ParcelableStatus item = ParcelableStatusUtils.fromStatus(status, mAccountKey,
|
||||
|
@ -43,8 +43,9 @@ public class UserFavoritesLoader extends TwitterAPIStatusesLoader {
|
||||
public UserFavoritesLoader(final Context context, final UserKey accountKey, final String userId,
|
||||
final String screenName, final String sinceId, final String maxId,
|
||||
final List<ParcelableStatus> data, final String[] savedStatusesArgs,
|
||||
final int tabPosition, boolean fromUser) {
|
||||
super(context, accountKey, sinceId, maxId, data, savedStatusesArgs, tabPosition, fromUser);
|
||||
final int tabPosition, boolean fromUser, boolean loadingMore) {
|
||||
super(context, accountKey, sinceId, maxId, data, savedStatusesArgs, tabPosition, fromUser,
|
||||
loadingMore);
|
||||
mUserId = userId;
|
||||
mUserScreenName = screenName;
|
||||
}
|
||||
|
@ -45,8 +45,8 @@ public class UserListTimelineLoader extends TwitterAPIStatusesLoader {
|
||||
public UserListTimelineLoader(final Context context, final UserKey accountKey, final long listId,
|
||||
final String userId, final String screenName, final String listName,
|
||||
final String sinceId, final String maxId, final List<ParcelableStatus> data,
|
||||
final String[] savedStatusesArgs, final int tabPosition, boolean fromUser) {
|
||||
super(context, accountKey, sinceId, maxId, data, savedStatusesArgs, tabPosition, fromUser);
|
||||
final String[] savedStatusesArgs, final int tabPosition, boolean fromUser, boolean loadingMore) {
|
||||
super(context, accountKey, sinceId, maxId, data, savedStatusesArgs, tabPosition, fromUser, loadingMore);
|
||||
mListId = listId;
|
||||
mUserId = userId;
|
||||
mScreenName = screenName;
|
||||
|
@ -35,9 +35,9 @@ public class UserMentionsLoader extends TweetSearchLoader {
|
||||
public UserMentionsLoader(final Context context, final UserKey accountId, final String screenName,
|
||||
final String maxId, final String sinceId, int page, final List<ParcelableStatus> data,
|
||||
final String[] savedStatusesArgs, final int tabPosition, boolean fromUser,
|
||||
boolean makeGap) {
|
||||
boolean makeGap, boolean loadingMore) {
|
||||
super(context, accountId, screenName, sinceId, maxId, page, data, savedStatusesArgs, tabPosition,
|
||||
fromUser, makeGap);
|
||||
fromUser, makeGap, loadingMore);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
@ -46,8 +46,8 @@ public class UserTimelineLoader extends TwitterAPIStatusesLoader {
|
||||
public UserTimelineLoader(final Context context, final UserKey accountId, final String userId,
|
||||
final String screenName, final String sinceId, final String maxId,
|
||||
final List<ParcelableStatus> data, final String[] savedStatusesArgs,
|
||||
final int tabPosition, boolean fromUser) {
|
||||
super(context, accountId, sinceId, maxId, data, savedStatusesArgs, tabPosition, fromUser);
|
||||
final int tabPosition, boolean fromUser, boolean loadingMore) {
|
||||
super(context, accountId, sinceId, maxId, data, savedStatusesArgs, tabPosition, fromUser, loadingMore);
|
||||
mUserId = userId;
|
||||
mUserScreenName = screenName;
|
||||
mIsMyTimeline = TextUtils.equals(accountId.getId(), userId);
|
||||
@ -59,7 +59,7 @@ public class UserTimelineLoader extends TwitterAPIStatusesLoader {
|
||||
if (mUserId != null)
|
||||
return twitter.getUserTimeline(mUserId, paging);
|
||||
else if (mUserScreenName != null)
|
||||
return twitter.getUserTimeline(mUserScreenName, paging);
|
||||
return twitter.getUserTimelineByScreenName(mUserScreenName, paging);
|
||||
else
|
||||
throw new TwitterException("Invalid user");
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ public class BaseRefreshTaskParam implements RefreshTaskParam {
|
||||
private final String[] sinceIds;
|
||||
private final long[] maxSortIds;
|
||||
private final long[] sinceSortIds;
|
||||
private boolean isLoadingMore;
|
||||
|
||||
public BaseRefreshTaskParam(UserKey[] accountKeys, String[] maxIds, String[] sinceIds) {
|
||||
this(accountKeys, maxIds, sinceIds, null, null);
|
||||
@ -55,12 +56,22 @@ public class BaseRefreshTaskParam implements RefreshTaskParam {
|
||||
return sinceIds != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long[] getMaxSortIds() {
|
||||
return maxSortIds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long[] getSinceSortIds() {
|
||||
return sinceSortIds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLoadingMore() {
|
||||
return isLoadingMore;
|
||||
}
|
||||
|
||||
public void setIsLoadingMore(boolean isLoadingMore) {
|
||||
this.isLoadingMore = isLoadingMore;
|
||||
}
|
||||
}
|
||||
|
@ -26,4 +26,6 @@ public interface RefreshTaskParam {
|
||||
|
||||
boolean hasSinceIds();
|
||||
|
||||
boolean isLoadingMore();
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package org.mariotaku.twidere.model;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
/**
|
||||
@ -7,6 +8,18 @@ import android.support.annotation.Nullable;
|
||||
*/
|
||||
public abstract class SimpleRefreshTaskParam implements RefreshTaskParam {
|
||||
|
||||
UserKey[] cached;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public final UserKey[] getAccountKeys() {
|
||||
if (cached != null) return cached;
|
||||
return cached = getAccountKeysWorker();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public abstract UserKey[] getAccountKeysWorker();
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String[] getMaxIds() {
|
||||
@ -40,4 +53,9 @@ public abstract class SimpleRefreshTaskParam implements RefreshTaskParam {
|
||||
public long[] getMaxSortIds() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLoadingMore() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -88,4 +88,17 @@ public class Tab {
|
||||
public void setExtras(TabExtras extras) {
|
||||
this.extras = extras;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Tab{" +
|
||||
"id=" + id +
|
||||
", name='" + name + '\'' +
|
||||
", icon='" + icon + '\'' +
|
||||
", type='" + type + '\'' +
|
||||
", position=" + position +
|
||||
", arguments=" + arguments +
|
||||
", extras=" + extras +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
@ -70,6 +70,8 @@ public class ParcelableActivityUtils {
|
||||
result.account_key = accountKey;
|
||||
result.timestamp = activity.getCreatedAt().getTime();
|
||||
result.action = activity.getAction();
|
||||
result.max_sort_position = activity.getMaxSortPosition();
|
||||
result.min_sort_position = activity.getMinSortPosition();
|
||||
result.max_position = activity.getMaxPosition();
|
||||
result.min_position = activity.getMinPosition();
|
||||
result.sources = ParcelableUserUtils.fromUsers(activity.getSources(), accountKey);
|
||||
|
@ -4,7 +4,6 @@ import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.apache.commons.lang3.math.NumberUtils;
|
||||
import org.mariotaku.twidere.api.statusnet.model.Attention;
|
||||
import org.mariotaku.twidere.api.twitter.model.Place;
|
||||
import org.mariotaku.twidere.api.twitter.model.Status;
|
||||
@ -40,26 +39,18 @@ public class ParcelableStatusUtils {
|
||||
result.is_gap = isGap;
|
||||
result.account_key = accountKey;
|
||||
result.id = orig.getId();
|
||||
result.sort_id = orig.getSortId();
|
||||
result.timestamp = getTime(orig.getCreatedAt());
|
||||
result.sort_id = orig.getRawId();
|
||||
if (result.sort_id == -1) {
|
||||
// Try use long id
|
||||
result.sort_id = NumberUtils.toLong(result.id, -1);
|
||||
}
|
||||
if (result.sort_id == -1) {
|
||||
// Try use timestamp
|
||||
result.sort_id = result.timestamp;
|
||||
}
|
||||
|
||||
result.extras = new ParcelableStatus.Extras();
|
||||
result.extras.external_url = orig.getExternalUrl();
|
||||
result.extras.support_entities = orig.getEntities() != null;
|
||||
|
||||
final Status retweetedStatus = orig.getRetweetedStatus();
|
||||
final User retweetUser = retweetedStatus != null ? orig.getUser() : null;
|
||||
result.is_retweet = orig.isRetweet();
|
||||
result.retweeted = orig.wasRetweeted();
|
||||
if (retweetedStatus != null) {
|
||||
final User retweetUser = orig.getUser();
|
||||
result.retweet_id = retweetedStatus.getId();
|
||||
result.retweet_timestamp = getTime(retweetedStatus.getCreatedAt());
|
||||
result.retweeted_by_user_id = UserKeyUtils.fromUser(retweetUser);
|
||||
@ -123,6 +114,9 @@ public class ParcelableStatusUtils {
|
||||
result.user_is_verified = user.isVerified();
|
||||
result.user_is_following = user.isFollowing();
|
||||
result.extras.user_profile_image_url_profile_size = user.getProfileImageUrlProfileSize();
|
||||
if (result.extras.user_profile_image_url_profile_size == null) {
|
||||
result.extras.user_profile_image_url_profile_size = user.getProfileImageUrlLarge();
|
||||
}
|
||||
result.text_html = InternalTwitterContentUtils.formatStatusText(status);
|
||||
result.media = ParcelableMediaUtils.fromStatus(status);
|
||||
result.text_plain = InternalTwitterContentUtils.unescapeTwitterStatusText(status.getText());
|
||||
@ -145,8 +139,10 @@ public class ParcelableStatusUtils {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static UserKey getInReplyToUserId(Status status, UserKey accountKey) {
|
||||
final String inReplyToUserId = status.getInReplyToUserId();
|
||||
if (inReplyToUserId == null) return null;
|
||||
final UserMentionEntity[] entities = status.getUserMentionEntities();
|
||||
if (entities != null) {
|
||||
for (final UserMentionEntity entity : entities) {
|
||||
|
@ -67,6 +67,9 @@ public class ParcelableUserUtils implements TwidereConstants {
|
||||
extras.statusnet_profile_url = user.getStatusnetProfileUrl();
|
||||
extras.profile_image_url_original = user.getProfileImageUrlOriginal();
|
||||
extras.profile_image_url_profile_size = user.getProfileImageUrlProfileSize();
|
||||
if (extras.profile_image_url_profile_size == null) {
|
||||
extras.profile_image_url_profile_size = user.getProfileImageUrlLarge();
|
||||
}
|
||||
extras.groups_count = user.getGroupsCount();
|
||||
obj.extras = extras;
|
||||
return obj;
|
||||
|
@ -56,9 +56,30 @@ public class UserKeyUtils {
|
||||
}
|
||||
|
||||
public static String getUserHost(User user) {
|
||||
if (isFanfouUser(user)) return TwidereConstants.USER_TYPE_FANFOU_COM;
|
||||
return getUserHost(user.getOstatusUri(), TwidereConstants.USER_TYPE_TWITTER_COM);
|
||||
}
|
||||
|
||||
public static boolean isFanfouUser(User user) {
|
||||
String url = user.getProfileImageUrlLarge();
|
||||
if (url != null && isFanfouHost(getUserHost(url, "twitter.com"))) {
|
||||
return true;
|
||||
}
|
||||
url = user.getProfileImageUrl();
|
||||
if (url != null && isFanfouHost(getUserHost(url, "twitter.com"))) {
|
||||
return true;
|
||||
}
|
||||
url = user.getProfileBackgroundImageUrl();
|
||||
if (url != null && isFanfouHost(getUserHost(url, "twitter.com"))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isFanfouHost(@NonNull String host) {
|
||||
return TextUtils.equals("fanfou.com", host) || host.endsWith(".fanfou.com");
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static String getUserHost(@Nullable String uri, @Nullable String def) {
|
||||
if (def == null) {
|
||||
|
@ -95,7 +95,7 @@ public class RefreshService extends Service implements Constants {
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public UserKey[] getAccountKeys() {
|
||||
public UserKey[] getAccountKeysWorker() {
|
||||
if (accountIds != null) return accountIds;
|
||||
final AccountPreferences[] prefs = AccountPreferences.getAccountPreferences(context,
|
||||
DataStoreUtils.getAccountKeys(context));
|
||||
@ -116,7 +116,7 @@ public class RefreshService extends Service implements Constants {
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public UserKey[] getAccountKeys() {
|
||||
public UserKey[] getAccountKeysWorker() {
|
||||
if (accountIds != null) return accountIds;
|
||||
final AccountPreferences[] prefs = AccountPreferences.getAccountPreferences(context,
|
||||
DataStoreUtils.getAccountKeys(context));
|
||||
@ -137,7 +137,7 @@ public class RefreshService extends Service implements Constants {
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public UserKey[] getAccountKeys() {
|
||||
public UserKey[] getAccountKeysWorker() {
|
||||
if (accountIds != null) return accountIds;
|
||||
final AccountPreferences[] prefs = AccountPreferences.getAccountPreferences(context,
|
||||
DataStoreUtils.getAccountKeys(context));
|
||||
|
@ -91,7 +91,6 @@ public abstract class GetActivitiesTask extends AbstractTask<RefreshTaskParam, O
|
||||
try {
|
||||
final ResponseList<Activity> activities = getActivities(twitter, accountKey, paging);
|
||||
storeActivities(cr, loadItemLimit, accountKey, noItemsBefore, activities);
|
||||
// if (saveReadPosition && TwitterAPIFactory.isOfficialTwitterInstance(context, twitter)) {
|
||||
if (saveReadPosition) {
|
||||
saveReadPosition(accountKey, twitter);
|
||||
}
|
||||
@ -124,14 +123,14 @@ public abstract class GetActivitiesTask extends AbstractTask<RefreshTaskParam, O
|
||||
final ParcelableActivity parcelableActivity = ParcelableActivityUtils.fromActivity(activity,
|
||||
accountKey, false);
|
||||
if (deleteBound[0] < 0) {
|
||||
deleteBound[0] = parcelableActivity.min_position;
|
||||
deleteBound[0] = parcelableActivity.min_sort_position;
|
||||
} else {
|
||||
deleteBound[0] = Math.min(deleteBound[0], parcelableActivity.min_position);
|
||||
deleteBound[0] = Math.min(deleteBound[0], parcelableActivity.min_sort_position);
|
||||
}
|
||||
if (deleteBound[1] < 0) {
|
||||
deleteBound[1] = parcelableActivity.max_position;
|
||||
deleteBound[1] = parcelableActivity.max_sort_position;
|
||||
} else {
|
||||
deleteBound[1] = Math.max(deleteBound[1], parcelableActivity.max_position);
|
||||
deleteBound[1] = Math.max(deleteBound[1], parcelableActivity.max_sort_position);
|
||||
}
|
||||
final ContentValues values = ContentValuesCreator.createActivity(parcelableActivity);
|
||||
values.put(Statuses.INSERTED_DATE, System.currentTimeMillis());
|
||||
@ -140,8 +139,8 @@ public abstract class GetActivitiesTask extends AbstractTask<RefreshTaskParam, O
|
||||
if (deleteBound[0] > 0 && deleteBound[1] > 0) {
|
||||
final Expression where = Expression.and(
|
||||
Expression.equalsArgs(Activities.ACCOUNT_KEY),
|
||||
Expression.greaterEqualsArgs(Activities.MIN_POSITION),
|
||||
Expression.lesserEqualsArgs(Activities.MAX_POSITION)
|
||||
Expression.greaterEqualsArgs(Activities.MIN_SORT_POSITION),
|
||||
Expression.lesserEqualsArgs(Activities.MAX_SORT_POSITION)
|
||||
);
|
||||
final String[] whereArgs = {accountKey.toString(), String.valueOf(deleteBound[0]),
|
||||
String.valueOf(deleteBound[1])};
|
||||
|
@ -390,7 +390,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public UserKey[] getAccountKeys() {
|
||||
public UserKey[] getAccountKeysWorker() {
|
||||
return closure.getAccountKeys();
|
||||
}
|
||||
|
||||
@ -404,7 +404,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
getActivitiesAboutMeAsync(new SimpleRefreshTaskParam() {
|
||||
@NonNull
|
||||
@Override
|
||||
public UserKey[] getAccountKeys() {
|
||||
public UserKey[] getAccountKeysWorker() {
|
||||
return closure.getAccountKeys();
|
||||
}
|
||||
|
||||
@ -418,14 +418,14 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
getReceivedDirectMessagesAsync(new SimpleRefreshTaskParam() {
|
||||
@NonNull
|
||||
@Override
|
||||
public UserKey[] getAccountKeys() {
|
||||
public UserKey[] getAccountKeysWorker() {
|
||||
return closure.getAccountKeys();
|
||||
}
|
||||
});
|
||||
getSentDirectMessagesAsync(new SimpleRefreshTaskParam() {
|
||||
@NonNull
|
||||
@Override
|
||||
public UserKey[] getAccountKeys() {
|
||||
public UserKey[] getAccountKeysWorker() {
|
||||
return closure.getAccountKeys();
|
||||
}
|
||||
});
|
||||
|
@ -83,7 +83,6 @@ import org.mariotaku.twidere.provider.TwidereDataStore.UnreadCounts;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@ -203,45 +202,76 @@ public class DataStoreUtils implements Constants {
|
||||
@NonNull
|
||||
public static String[] getNewestMessageIds(@NonNull final Context context, @NonNull final Uri uri,
|
||||
@NonNull final UserKey[] accountKeys) {
|
||||
return getLongFieldArray(context, uri, accountKeys, DirectMessages.ACCOUNT_KEY,
|
||||
return getStringFieldArray(context, uri, accountKeys, DirectMessages.ACCOUNT_KEY,
|
||||
DirectMessages.MESSAGE_ID, new OrderBy(SQLFunctions.MAX(DirectMessages.MESSAGE_TIMESTAMP)));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static String[] getNewestStatusIds(@NonNull final Context context, @NonNull final Uri uri,
|
||||
@NonNull final UserKey[] accountKeys) {
|
||||
return getLongFieldArray(context, uri, accountKeys, Statuses.ACCOUNT_KEY,
|
||||
return getStringFieldArray(context, uri, accountKeys, Statuses.ACCOUNT_KEY,
|
||||
Statuses.STATUS_ID, new OrderBy(SQLFunctions.MAX(Statuses.STATUS_TIMESTAMP)));
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
public static long[] getNewestStatusSortIds(@NonNull final Context context, @NonNull final Uri uri,
|
||||
@NonNull final UserKey[] accountKeys) {
|
||||
return getLongFieldArray(context, uri, accountKeys, Statuses.ACCOUNT_KEY,
|
||||
Statuses.SORT_ID, new OrderBy(SQLFunctions.MAX(Statuses.STATUS_TIMESTAMP)));
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
public static String[] getOldestMessageIds(@NonNull final Context context, @NonNull final Uri uri,
|
||||
@NonNull final UserKey[] accountKeys) {
|
||||
return getLongFieldArray(context, uri, accountKeys, DirectMessages.ACCOUNT_KEY,
|
||||
return getStringFieldArray(context, uri, accountKeys, DirectMessages.ACCOUNT_KEY,
|
||||
DirectMessages.MESSAGE_ID, new OrderBy(SQLFunctions.MIN(DirectMessages.MESSAGE_TIMESTAMP)));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static String[] getOldestStatusIds(@NonNull final Context context, @NonNull final Uri uri,
|
||||
@NonNull final UserKey[] accountKeys) {
|
||||
return getLongFieldArray(context, uri, accountKeys, Statuses.ACCOUNT_KEY,
|
||||
return getStringFieldArray(context, uri, accountKeys, Statuses.ACCOUNT_KEY,
|
||||
Statuses.STATUS_ID, new OrderBy(SQLFunctions.MIN(Statuses.STATUS_TIMESTAMP)));
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
public static long[] getOldestStatusSortIds(@NonNull final Context context, @NonNull final Uri uri,
|
||||
@NonNull final UserKey[] accountKeys) {
|
||||
return getLongFieldArray(context, uri, accountKeys, Statuses.ACCOUNT_KEY,
|
||||
Statuses.SORT_ID, new OrderBy(SQLFunctions.MIN(Statuses.STATUS_TIMESTAMP)));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static String[] getNewestActivityMaxPositions(final Context context, final Uri uri,
|
||||
final UserKey[] accountKeys) {
|
||||
return getLongFieldArray(context, uri, accountKeys, Activities.ACCOUNT_KEY,
|
||||
Activities.MAX_POSITION, new OrderBy(SQLFunctions.MAX(Activities.TIMESTAMP)));
|
||||
return getStringFieldArray(context, uri, accountKeys, Activities.ACCOUNT_KEY,
|
||||
Activities.MAX_REQUEST_POSITION, new OrderBy(SQLFunctions.MAX(Activities.TIMESTAMP)));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static String[] getOldestActivityMaxPositions(@NonNull final Context context,
|
||||
@NonNull final Uri uri,
|
||||
@NonNull final UserKey[] accountKeys) {
|
||||
return getStringFieldArray(context, uri, accountKeys, Activities.ACCOUNT_KEY,
|
||||
Activities.MAX_REQUEST_POSITION, new OrderBy(SQLFunctions.MIN(Activities.TIMESTAMP)));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static long[] getNewestActivityMaxSortPositions(final Context context, final Uri uri,
|
||||
final UserKey[] accountKeys) {
|
||||
return getLongFieldArray(context, uri, accountKeys, Activities.ACCOUNT_KEY,
|
||||
Activities.MAX_POSITION, new OrderBy(SQLFunctions.MIN(Activities.TIMESTAMP)));
|
||||
Activities.MAX_SORT_POSITION, new OrderBy(SQLFunctions.MAX(Activities.TIMESTAMP)));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static long[] getOldestActivityMaxSortPositions(@NonNull final Context context,
|
||||
@NonNull final Uri uri,
|
||||
@NonNull final UserKey[] accountKeys) {
|
||||
return getLongFieldArray(context, uri, accountKeys, Activities.ACCOUNT_KEY,
|
||||
Activities.MAX_SORT_POSITION, new OrderBy(SQLFunctions.MIN(Activities.TIMESTAMP)));
|
||||
}
|
||||
|
||||
public static int getStatusCount(final Context context, final Uri uri, final UserKey accountId) {
|
||||
@ -829,12 +859,46 @@ public class DataStoreUtils implements Constants {
|
||||
}
|
||||
|
||||
@NonNull
|
||||
static String[] getLongFieldArray(@NonNull Context context, @NonNull Uri uri,
|
||||
@NonNull UserKey[] keys, @NonNull String keyField,
|
||||
@NonNull String valueField, @Nullable OrderBy sortExpression) {
|
||||
static String[] getStringFieldArray(@NonNull Context context, @NonNull Uri uri,
|
||||
@NonNull UserKey[] keys, @NonNull String keyField,
|
||||
@NonNull String valueField, @Nullable OrderBy sortExpression) {
|
||||
return getFieldArray(context, uri, keys, keyField, valueField, sortExpression, new FieldArrayCreator<String[]>() {
|
||||
@Override
|
||||
public String[] newArray(int size) {
|
||||
return new String[size];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assign(String[] array, int arrayIdx, Cursor cur, int colIdx) {
|
||||
array[arrayIdx] = cur.getString(colIdx);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NonNull
|
||||
static long[] getLongFieldArray(@NonNull Context context, @NonNull Uri uri,
|
||||
@NonNull UserKey[] keys, @NonNull String keyField,
|
||||
@NonNull String valueField, @Nullable OrderBy sortExpression) {
|
||||
return getFieldArray(context, uri, keys, keyField, valueField, sortExpression, new FieldArrayCreator<long[]>() {
|
||||
@Override
|
||||
public long[] newArray(int size) {
|
||||
return new long[size];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assign(long[] array, int arrayIdx, Cursor cur, int colIdx) {
|
||||
array[arrayIdx] = cur.getLong(colIdx);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NonNull
|
||||
static <T> T getFieldArray(@NonNull Context context, @NonNull Uri uri,
|
||||
@NonNull UserKey[] keys, @NonNull String keyField,
|
||||
@NonNull String valueField, @Nullable OrderBy sortExpression,
|
||||
@NonNull FieldArrayCreator<T> creator) {
|
||||
final ContentResolver resolver = context.getContentResolver();
|
||||
final String[] messageIds = new String[keys.length];
|
||||
Arrays.fill(messageIds, -1);
|
||||
final T messageIds = creator.newArray(keys.length);
|
||||
final String[] selectionArgs = TwidereArrayUtils.toStringArray(keys);
|
||||
final SQLSelectQuery.Builder builder = SQLQueryBuilder.select(new Columns(keyField, valueField))
|
||||
.from(new Table(getTableNameByUri(uri)))
|
||||
@ -851,7 +915,7 @@ public class DataStoreUtils implements Constants {
|
||||
final UserKey accountKey = UserKey.valueOf(cur.getString(0));
|
||||
int idx = ArrayUtils.indexOf(keys, accountKey);
|
||||
if (idx < 0) continue;
|
||||
messageIds[idx] = cur.getString(1);
|
||||
creator.assign(messageIds, idx, cur, 1);
|
||||
}
|
||||
return messageIds;
|
||||
} finally {
|
||||
@ -859,6 +923,12 @@ public class DataStoreUtils implements Constants {
|
||||
}
|
||||
}
|
||||
|
||||
interface FieldArrayCreator<T> {
|
||||
T newArray(int size);
|
||||
|
||||
void assign(T array, int arrayIdx, Cursor cur, int colIdx);
|
||||
}
|
||||
|
||||
static int queryCount(@NonNull final Context context, @NonNull final Uri uri,
|
||||
@Nullable final String selection, @Nullable final String[] selectionArgs) {
|
||||
final ContentResolver resolver = context.getContentResolver();
|
||||
@ -1014,18 +1084,4 @@ public class DataStoreUtils implements Constants {
|
||||
position, followingOnly, accountIds);
|
||||
}
|
||||
|
||||
public static void initAccountColor(final Context context) {
|
||||
if (context == null) return;
|
||||
final Cursor cur = context.getContentResolver().query(Accounts.CONTENT_URI, new String[]{
|
||||
Accounts.ACCOUNT_KEY, Accounts.COLOR}, null, null, null);
|
||||
if (cur == null) return;
|
||||
final int id_idx = cur.getColumnIndex(Accounts.ACCOUNT_KEY), color_idx = cur.getColumnIndex(Accounts.COLOR);
|
||||
cur.moveToFirst();
|
||||
while (!cur.isAfterLast()) {
|
||||
// sAccountColors.put(cur.getLong(id_idx), cur.getInt(color_idx));
|
||||
// TODO
|
||||
cur.moveToNext();
|
||||
}
|
||||
cur.close();
|
||||
}
|
||||
}
|
||||
|
@ -33,10 +33,10 @@ import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer;
|
||||
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
|
||||
|
||||
import org.mariotaku.twidere.Constants;
|
||||
import org.mariotaku.twidere.model.UserKey;
|
||||
import org.mariotaku.twidere.model.ParcelableAccount;
|
||||
import org.mariotaku.twidere.model.ParcelableStatus;
|
||||
import org.mariotaku.twidere.model.ParcelableUser;
|
||||
import org.mariotaku.twidere.model.UserKey;
|
||||
import org.mariotaku.twidere.util.imageloader.OvalBitmapDisplayer;
|
||||
import org.mariotaku.twidere.util.media.MediaExtra;
|
||||
|
||||
@ -141,6 +141,8 @@ public class MediaLoaderWrapper implements Constants {
|
||||
public void displayOriginalProfileImage(final ImageView view, final ParcelableUser user) {
|
||||
if (user.extras != null && !TextUtils.isEmpty(user.extras.profile_image_url_original)) {
|
||||
displayProfileImage(view, user.extras.profile_image_url_original);
|
||||
} else if (user.extras != null && !TextUtils.isEmpty(user.extras.profile_image_url_profile_size)) {
|
||||
displayProfileImage(view, user.extras.profile_image_url_profile_size);
|
||||
} else {
|
||||
displayProfileImage(view, Utils.getOriginalTwitterProfileImage(user.profile_image_url));
|
||||
}
|
||||
|
@ -138,7 +138,7 @@ public class TwitterWrapper implements Constants {
|
||||
if (TextUtils.equals(user.getId(), id)) return user;
|
||||
}
|
||||
} else {
|
||||
final ResponseList<Status> timeline = twitter.getUserTimeline(screenName, paging);
|
||||
final ResponseList<Status> timeline = twitter.getUserTimelineByScreenName(screenName, paging);
|
||||
for (final Status status : timeline) {
|
||||
final User user = status.getUser();
|
||||
if (searchScreenName.equalsIgnoreCase(user.getScreenName()))
|
||||
|
@ -22,6 +22,7 @@ package org.mariotaku.twidere.view.holder;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Typeface;
|
||||
import android.support.annotation.UiThread;
|
||||
import android.support.v7.widget.RecyclerView.ViewHolder;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
@ -32,7 +33,6 @@ import org.mariotaku.twidere.R;
|
||||
import org.mariotaku.twidere.adapter.MessageEntriesAdapter;
|
||||
import org.mariotaku.twidere.model.UserKey;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages.ConversationEntries;
|
||||
import org.mariotaku.twidere.util.DataStoreUtils;
|
||||
import org.mariotaku.twidere.util.MediaLoaderWrapper;
|
||||
import org.mariotaku.twidere.util.UserColorNameManager;
|
||||
import org.mariotaku.twidere.view.NameView;
|
||||
@ -64,6 +64,7 @@ public class MessageEntryViewHolder extends ViewHolder implements OnClickListene
|
||||
profileImageView.setOnClickListener(this);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
public void displayMessage(Cursor cursor, boolean isUnread) {
|
||||
final Context context = adapter.getContext();
|
||||
final MediaLoaderWrapper loader = adapter.getMediaLoader();
|
||||
@ -90,7 +91,7 @@ public class MessageEntryViewHolder extends ViewHolder implements OnClickListene
|
||||
nameView.setTypeface(null, isUnread && !isOutgoing ? Typeface.BOLD : Typeface.NORMAL);
|
||||
textView.setTypeface(null, isUnread && !isOutgoing ? Typeface.BOLD : Typeface.NORMAL);
|
||||
if (adapter.shouldShowAccountsColor()) {
|
||||
content.drawEnd(DataStoreUtils.getAccountColor(context, accountKey));
|
||||
// FIXME draw account color
|
||||
} else {
|
||||
content.drawEnd();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user