Merge tag '3.1.2'

Added alt text for better accessibility
Improved theme
Fixed user timelines
Added remove users from list
This commit is contained in:
Mariotaku Lee 2016-03-30 21:52:17 +08:00
commit 84b5748e2c
78 changed files with 1190 additions and 466 deletions

View File

@ -4,13 +4,13 @@ import org.mariotaku.twidere.api.twitter.api.PrivateActivityResources;
import org.mariotaku.twidere.api.twitter.api.PrivateDirectMessagesResources;
import org.mariotaku.twidere.api.twitter.api.PrivateFriendsFollowersResources;
import org.mariotaku.twidere.api.twitter.api.PrivateScheduleResources;
import org.mariotaku.twidere.api.twitter.api.PrivateTimelinesResources;
import org.mariotaku.twidere.api.twitter.api.PrivateTimelineResources;
import org.mariotaku.twidere.api.twitter.api.PrivateTweetResources;
/**
* Created by mariotaku on 16/3/4.
*/
public interface TwitterPrivate extends PrivateActivityResources, PrivateTweetResources,
PrivateTimelinesResources, PrivateFriendsFollowersResources, PrivateDirectMessagesResources,
PrivateTimelineResources, PrivateFriendsFollowersResources, PrivateDirectMessagesResources,
PrivateScheduleResources {
}

View File

@ -23,15 +23,15 @@ import org.mariotaku.restfu.annotation.method.POST;
import org.mariotaku.restfu.annotation.param.KeyValue;
import org.mariotaku.restfu.annotation.param.Param;
import org.mariotaku.restfu.annotation.param.Params;
import org.mariotaku.restfu.annotation.param.Raw;
import org.mariotaku.restfu.http.BodyType;
import org.mariotaku.restfu.http.mime.Body;
import org.mariotaku.restfu.http.mime.FileBody;
import org.mariotaku.twidere.api.twitter.model.MediaUploadResponse;
import org.mariotaku.twidere.api.twitter.model.NewMediaMetadata;
import org.mariotaku.twidere.api.twitter.model.ResponseCode;
import java.io.File;
@SuppressWarnings("RedundantThrows")
public interface TwitterUpload {
@POST("/media/upload.json")
@ -57,4 +57,7 @@ public interface TwitterUpload {
@POST("/media/upload.json")
@Params(@KeyValue(key = "command", value = "FINALIZE"))
MediaUploadResponse initUploadMedia(@Param("media_id") long mediaId) throws TwitterException;
@POST("/media/metadata/create.json")
ResponseCode createMetadata(@Raw NewMediaMetadata metadata) throws TwitterException;
}

View File

@ -56,17 +56,17 @@ public interface DirectMessagesResources {
@POST("/direct_messages/new.json")
@BodyType(BodyType.FORM)
DirectMessage sendDirectMessage(@Param("user_id") String userId, @Param("text") String text,
@Param("media_id") long mediaId) throws TwitterException;
@Param("media_id") String mediaId) throws TwitterException;
@POST("/direct_messages/new.json")
@BodyType(BodyType.FORM)
DirectMessage sendDirectMessageForScreenName(@Param("screen_name") String screenName, @Param("text") String text)
DirectMessage sendDirectMessageToScreenName(@Param("screen_name") String screenName, @Param("text") String text)
throws TwitterException;
@POST("/direct_messages/new.json")
@BodyType(BodyType.FORM)
DirectMessage sendDirectMessageForScreenName(@Param("screen_name") String screenName, @Param("text") String text,
@Param("media_id") long mediaId) throws TwitterException;
DirectMessage sendDirectMessageToScreenName(@Param("screen_name") String screenName, @Param("text") String text,
@Param("media_id") String mediaId) throws TwitterException;
@GET("/direct_messages/show.json")
DirectMessage showDirectMessage(@Query("id") String id) throws TwitterException;

View File

@ -25,7 +25,6 @@ import org.mariotaku.restfu.annotation.param.KeyValue;
import org.mariotaku.restfu.annotation.param.Param;
import org.mariotaku.restfu.annotation.param.Queries;
import org.mariotaku.restfu.annotation.param.Query;
import org.mariotaku.restfu.http.BodyType;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.model.Paging;
import org.mariotaku.twidere.api.twitter.model.ResponseList;
@ -38,7 +37,9 @@ import org.mariotaku.twidere.api.twitter.model.Status;
@KeyValue(key = "include_cards", valueKey = "include_cards"),
@KeyValue(key = "cards_platform", valueKey = "cards_platform"),
@KeyValue(key = "include_reply_count", valueKey = "include_reply_count"),
@KeyValue(key = "include_descendent_reply_count", valueKey = "include_descendent_reply_count")})
@KeyValue(key = "include_descendent_reply_count", valueKey = "include_descendent_reply_count"),
@KeyValue(key = "include_ext_alt_text", valueKey = "include_ext_alt_text")
})
public interface FavoritesResources {
@POST("/favorites/create.json")

View File

@ -36,43 +36,43 @@ import org.mariotaku.twidere.api.twitter.model.UserListUpdate;
public interface ListResources {
@POST("/lists/members/create.json")
UserList addUserListMember(@Query("list_id") long listId, @Query("user_id") long userId) throws TwitterException;
UserList addUserListMember(@Query("list_id") String listId, @Query("user_id") String userId) throws TwitterException;
@POST("/lists/members/create.json")
UserList addUserListMember(@Query("list_id") long listId, @Query("screen_name") String userScreenName) throws TwitterException;
UserList addUserListMemberByScreenName(@Query("list_id") String listId, @Query("screen_name") String userScreenName) throws TwitterException;
@POST("/lists/members/create_all.json")
UserList addUserListMembers(@Param("list_id") long listId, @Param(value = "user_id", arrayDelimiter = ',') long[] userIds) throws TwitterException;
UserList addUserListMembers(@Param("list_id") String listId, @Param(value = "user_id", arrayDelimiter = ',') String[] userIds) throws TwitterException;
@POST("/lists/members/create_all.json")
UserList addUserListMembers(@Param("list_id") long listId, @Param(value = "screen_name", arrayDelimiter = ',') String[] screenNames) throws TwitterException;
UserList addUserListMembersByScreenName(@Param("list_id") String listId, @Param(value = "screen_name", arrayDelimiter = ',') String[] screenNames) throws TwitterException;
@POST("/lists/create.json")
UserList createUserList(@Param UserListUpdate update) throws TwitterException;
@POST("/lists/subscribers/create.json")
UserList createUserListSubscription(@Param("list_id") long listId) throws TwitterException;
UserList createUserListSubscription(@Param("list_id") String listId) throws TwitterException;
@POST("/lists/members/destroy.json")
UserList deleteUserListMember(@Query("list_id") long listId, @Query("user_id") long userId) throws TwitterException;
UserList deleteUserListMember(@Query("list_id") String listId, @Query("user_id") String userId) throws TwitterException;
@POST("/lists/members/destroy.json")
UserList deleteUserListMember(@Query("list_id") long listId, @Param("screen_name") String screenName) throws TwitterException;
UserList deleteUserListMemberByScreenName(@Query("list_id") String listId, @Param("screen_name") String screenName) throws TwitterException;
@POST("/lists/members/destroy_all.json")
UserList deleteUserListMembers(@Param("list_id") long listId, @Param(value = "user_id", arrayDelimiter = ',') long[] userIds) throws TwitterException;
UserList deleteUserListMembers(@Param("list_id") String listId, @Param(value = "user_id", arrayDelimiter = ',') String[] userIds) throws TwitterException;
@POST("/lists/members/destroy_all.json")
UserList deleteUserListMembers(@Query("list_id") long listId, @Param(value = "screen_name", arrayDelimiter = ',') String[] screenNames) throws TwitterException;
UserList deleteUserListMembersByScreenName(@Query("list_id") String listId, @Param(value = "screen_name", arrayDelimiter = ',') String[] screenNames) throws TwitterException;
@POST("/lists/destroy.json")
UserList destroyUserList(@Param("list_id") long listId) throws TwitterException;
UserList destroyUserList(@Param("list_id") String listId) throws TwitterException;
@POST("/lists/subscribers/destroy.json")
UserList destroyUserListSubscription(@Param("list_id") long listId) throws TwitterException;
UserList destroyUserListSubscription(@Param("list_id") String listId) throws TwitterException;
@GET("/lists/members.json")
PageableResponseList<User> getUserListMembers(@Query("list_id") long listId, @Query Paging paging) throws TwitterException;
PageableResponseList<User> getUserListMembers(@Query("list_id") String listId, @Query Paging paging) throws TwitterException;
@GET("/lists/members.json")
PageableResponseList<User> getUserListMembers(@Query("slug") String slug,
@ -103,10 +103,10 @@ public interface ListResources {
PageableResponseList<UserList> getUserListOwnerships(@Query Paging paging) throws TwitterException;
@GET("/lists/ownerships.json")
PageableResponseList<UserList> getUserListOwnerships(@Query("user_id") long listMemberId, @Query Paging paging) throws TwitterException;
PageableResponseList<UserList> getUserListOwnerships(@Query("user_id") String listMemberId, @Query Paging paging) throws TwitterException;
@GET("/lists/ownerships.json")
PageableResponseList<UserList> getUserListOwnerships(@Query("screen_name") String listMemberScreenName, @Query Paging paging)
PageableResponseList<UserList> getUserListOwnershipsByScreenName(@Query("screen_name") String listMemberScreenName, @Query Paging paging)
throws TwitterException;
@GET("/lists/list.json")
@ -122,8 +122,10 @@ public interface ListResources {
@KeyValue(key = "include_cards", valueKey = "include_cards"),
@KeyValue(key = "cards_platform", valueKey = "cards_platform"),
@KeyValue(key = "include_reply_count", valueKey = "include_reply_count"),
@KeyValue(key = "include_descendent_reply_count", valueKey = "include_descendent_reply_count")})
ResponseList<Status> getUserListStatuses(@Query("list_id") long listId, @Query Paging paging) throws TwitterException;
@KeyValue(key = "include_descendent_reply_count", valueKey = "include_descendent_reply_count"),
@KeyValue(key = "include_ext_alt_text", valueKey = "include_ext_alt_text")
})
ResponseList<Status> getUserListStatuses(@Query("list_id") String listId, @Query Paging paging) throws TwitterException;
@GET("/lists/statuses.json")
@Queries({@KeyValue(key = "include_my_retweet", valueKey = "include_my_retweet"),
@ -132,7 +134,9 @@ public interface ListResources {
@KeyValue(key = "include_cards", valueKey = "include_cards"),
@KeyValue(key = "cards_platform", valueKey = "cards_platform"),
@KeyValue(key = "include_reply_count", valueKey = "include_reply_count"),
@KeyValue(key = "include_descendent_reply_count", valueKey = "include_descendent_reply_count")})
@KeyValue(key = "include_descendent_reply_count", valueKey = "include_descendent_reply_count"),
@KeyValue(key = "include_ext_alt_text", valueKey = "include_ext_alt_text")
})
ResponseList<Status> getUserListStatuses(@Query("slug") String slug, @Query("owner_id") long ownerId, @Query Paging paging) throws TwitterException;
@GET("/lists/statuses.json")
@ -142,12 +146,14 @@ public interface ListResources {
@KeyValue(key = "include_cards", valueKey = "include_cards"),
@KeyValue(key = "cards_platform", valueKey = "cards_platform"),
@KeyValue(key = "include_reply_count", valueKey = "include_reply_count"),
@KeyValue(key = "include_descendent_reply_count", valueKey = "include_descendent_reply_count")})
@KeyValue(key = "include_descendent_reply_count", valueKey = "include_descendent_reply_count"),
@KeyValue(key = "include_ext_alt_text", valueKey = "include_ext_alt_text")
})
ResponseList<Status> getUserListStatuses(@Query("slug") String slug, @Query("owner_screen_name") String ownerScreenName, @Query Paging paging)
throws TwitterException;
@GET("/lists/subscribers.json")
PageableResponseList<User> getUserListSubscribers(@Query("list_id") long listId, @Query Paging paging) throws TwitterException;
PageableResponseList<User> getUserListSubscribers(@Query("list_id") String listId, @Query Paging paging) throws TwitterException;
@GET("/lists/subscribers.json")
PageableResponseList<User> getUserListSubscribers(@Query("list_id") String slug, @Query("owner_id") String ownerId, @Query Paging paging)
@ -159,15 +165,15 @@ public interface ListResources {
@GET("/lists/subscriptions.json")
PageableResponseList<UserList> getUserListSubscriptions(@Query("screen_name") String listOwnerScreenName, long cursor)
PageableResponseList<UserList> getUserListSubscriptionsByScreenName(@Query("screen_name") String listOwnerScreenName, long cursor)
throws TwitterException;
@GET("/lists/subscriptions.json")
PageableResponseList<UserList> getUserListSubscriptions(@Query("user_id") long userId, long cursor)
PageableResponseList<UserList> getUserListSubscriptions(@Query("user_id") String userId, long cursor)
throws TwitterException;
@GET("/lists/show.json")
UserList showUserList(@Query("list_id") long listId) throws TwitterException;
UserList showUserList(@Query("list_id") String listId) throws TwitterException;
@GET("/lists/show.json")
UserList showUserList(@Query("slug") String slug, @Query("owner_id") String ownerId) throws TwitterException;
@ -176,5 +182,5 @@ public interface ListResources {
UserList showUserListByScrenName(@Query("slug") String slug, @Query("owner_screen_name") String ownerScreenName) throws TwitterException;
@POST("/lists/update.json")
UserList updateUserList(@Param("list_id") long listId, @Param UserListUpdate update) throws TwitterException;
UserList updateUserList(@Param("list_id") String listId, @Param UserListUpdate update) throws TwitterException;
}

View File

@ -35,8 +35,10 @@ import org.mariotaku.twidere.api.twitter.model.Status;
@KeyValue(key = "include_cards", valueKey = "include_cards"),
@KeyValue(key = "cards_platform", valueKey = "cards_platform"),
@KeyValue(key = "include_reply_count", valueKey = "include_reply_count"),
@KeyValue(key = "include_descendent_reply_count", valueKey = "include_descendent_reply_count")})
public interface PrivateTimelinesResources extends PrivateResources {
@KeyValue(key = "include_descendent_reply_count", valueKey = "include_descendent_reply_count"),
@KeyValue(key = "include_ext_alt_text", valueKey = "include_ext_alt_text")
})
public interface PrivateTimelineResources extends PrivateResources {
@GET("/statuses/media_timeline.json")
ResponseList<Status> getMediaTimeline(@Query("user_id") String userId, @Query Paging paging) throws TwitterException;

View File

@ -38,7 +38,9 @@ import org.mariotaku.twidere.api.twitter.model.TranslationResult;
@KeyValue(key = "include_cards", valueKey = "include_cards"),
@KeyValue(key = "cards_platform", valueKey = "cards_platform"),
@KeyValue(key = "include_reply_count", valueKey = "include_reply_count"),
@KeyValue(key = "include_descendent_reply_count", valueKey = "include_descendent_reply_count")})
@KeyValue(key = "include_descendent_reply_count", valueKey = "include_descendent_reply_count"),
@KeyValue(key = "include_ext_alt_text", valueKey = "include_ext_alt_text")
})
public interface PrivateTweetResources extends PrivateResources {
@GET("/statuses/{id}/activity/summary.json")

View File

@ -36,7 +36,9 @@ import org.mariotaku.twidere.api.twitter.model.Status;
@KeyValue(key = "include_cards", valueKey = "include_cards"),
@KeyValue(key = "cards_platform", valueKey = "cards_platform"),
@KeyValue(key = "include_reply_count", valueKey = "include_reply_count"),
@KeyValue(key = "include_descendent_reply_count", valueKey = "include_descendent_reply_count")})
@KeyValue(key = "include_descendent_reply_count", valueKey = "include_descendent_reply_count"),
@KeyValue(key = "include_ext_alt_text", valueKey = "include_ext_alt_text")
})
public interface TimelineResources {
@GET("/statuses/home_timeline.json")

View File

@ -40,7 +40,9 @@ import org.mariotaku.twidere.api.twitter.model.StatusUpdate;
@KeyValue(key = "include_cards", valueKey = "include_cards"),
@KeyValue(key = "cards_platform", valueKey = "cards_platform"),
@KeyValue(key = "include_reply_count", valueKey = "include_reply_count"),
@KeyValue(key = "include_descendent_reply_count", valueKey = "include_descendent_reply_count")})
@KeyValue(key = "include_descendent_reply_count", valueKey = "include_descendent_reply_count"),
@KeyValue(key = "include_ext_alt_text", valueKey = "include_ext_alt_text")
})
public interface TweetResources {
@POST("/statuses/destroy/{id}.json")
Status destroyStatus(@Path("id") String statusId) throws TwitterException;

View File

@ -30,12 +30,14 @@ public class Location {
@JsonField(name = "woeid")
int woeid;
@JsonField(name = "parentid")
int parentId;
@JsonField(name = "country")
String countryName;
@JsonField(name = "countryCode")
String countryCode;
@JsonField(name = "placeType")
PlaceTypeImpl placeType;
PlaceType placeType;
@JsonField(name = "name")
String name;
@JsonField(name = "url")
@ -45,6 +47,10 @@ public class Location {
return woeid;
}
public long getParentId() {
return parentId;
}
public String getCountryName() {
return countryName;
}
@ -53,7 +59,7 @@ public class Location {
return countryCode;
}
public PlaceTypeImpl getPlaceType() {
public PlaceType getPlaceType() {
return placeType;
}
@ -65,11 +71,27 @@ public class Location {
return url;
}
@JsonObject
public static class PlaceTypeImpl {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Location location = (Location) o;
return woeid == location.woeid;
}
@Override
public int hashCode() {
return woeid;
}
@JsonObject
public static class PlaceType {
@JsonField(name = "name")
String name;
@JsonField(name = "code")
int code;
@ -80,5 +102,13 @@ public class Location {
public String getName() {
return name;
}
@Override
public String toString() {
return "PlaceType{" +
"name='" + name + '\'' +
", code=" + code +
'}';
}
}
}

View File

@ -19,9 +19,14 @@
package org.mariotaku.twidere.api.twitter.model;
import android.support.annotation.IntDef;
import android.support.annotation.StringDef;
import com.bluelinelabs.logansquare.annotation.JsonField;
import com.bluelinelabs.logansquare.annotation.JsonObject;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@ -61,6 +66,8 @@ public class MediaEntity extends UrlEntity {
VideoInfo videoInfo;
@JsonField(name = "features")
HashMap<String, Feature> features;
@JsonField(name = "ext_alt_text")
String altText;
public Map<String, Feature> getFeatures() {
return features;
@ -78,14 +85,17 @@ public class MediaEntity extends UrlEntity {
return mediaUrlHttps;
}
@Override
public String getExpandedUrl() {
return expandedUrl;
}
@Override
public String getDisplayUrl() {
return displayUrl;
}
@Override
public String getUrl() {
return url;
}
@ -99,10 +109,12 @@ public class MediaEntity extends UrlEntity {
return sizes;
}
@Override
public int getEnd() {
return indices.getEnd();
}
@Override
public int getStart() {
return indices.getStart();
}
@ -111,6 +123,10 @@ public class MediaEntity extends UrlEntity {
return id;
}
public String getAltText() {
return altText;
}
@Override
public String toString() {
return "MediaEntity{" +
@ -253,6 +269,16 @@ public class MediaEntity extends UrlEntity {
}
}
@StringDef({Size.THUMB, Size.SMALL, Size.MEDIUM, Size.LARGE})
@Retention(RetentionPolicy.SOURCE)
public @interface SizeType {
}
@IntDef({Size.FIT, Size.CROP})
@Retention(RetentionPolicy.SOURCE)
public @interface ScaleType {
}
@JsonObject
public static class Size {

View File

@ -29,7 +29,7 @@ import com.bluelinelabs.logansquare.annotation.JsonObject;
public class MediaUploadResponse extends TwitterResponseObject implements TwitterResponse {
@JsonField(name = "media_id")
long mediaId;
String mediaId;
@JsonField(name = "size")
long size;
@JsonField(name = "image")
@ -37,7 +37,7 @@ public class MediaUploadResponse extends TwitterResponseObject implements Twitte
@JsonField(name = "video")
Video video;
public long getId() {
public String getId() {
return mediaId;
}

View File

@ -0,0 +1,53 @@
package org.mariotaku.twidere.api.twitter.model;
import com.bluelinelabs.logansquare.annotation.JsonField;
import com.bluelinelabs.logansquare.annotation.JsonObject;
/**
* Created by mariotaku on 16/3/30.
*/
@JsonObject
public class NewMediaMetadata {
@JsonField(name = "media_id")
String mediaId;
@JsonField(name = "alt_text")
AltText altText;
NewMediaMetadata() {
}
public NewMediaMetadata(String mediaId, String altText) {
this.mediaId = mediaId;
this.altText = new AltText(altText);
}
@Override
public String toString() {
return "NewMediaMetadata{" +
"mediaId='" + mediaId + '\'' +
", altText=" + altText +
'}';
}
@JsonObject
public static class AltText {
@JsonField(name = "text")
String text;
AltText() {
}
public AltText(String text) {
this.text = text;
}
@Override
public String toString() {
return "AltText{" +
"text='" + text + '\'' +
'}';
}
}
}

View File

@ -49,7 +49,7 @@ public class StatusUpdate extends SimpleValueMap {
put("long", location.getLongitude());
}
public void setMediaIds(final long... mediaIds) {
public void setMediaIds(final String... mediaIds) {
remove("media_ids");
if (mediaIds == null) return;
put("media_ids", RestFuUtils.toString(mediaIds, ','));
@ -79,7 +79,7 @@ public class StatusUpdate extends SimpleValueMap {
return this;
}
public StatusUpdate mediaIds(final long... mediaIds) {
public StatusUpdate mediaIds(final String... mediaIds) {
setMediaIds(mediaIds);
return this;
}

View File

@ -37,7 +37,7 @@ import java.util.Date;
@JsonObject
public class UserList extends TwitterResponseObject implements Comparable<UserList>, TwitterResponse {
@JsonField(name = "id")
long id;
String id;
@JsonField(name = "name")
String name;
@ -73,7 +73,7 @@ public class UserList extends TwitterResponseObject implements Comparable<UserLi
@JsonField(name = "user")
User user;
public long getId() {
public String getId() {
return id;
}
@ -125,10 +125,7 @@ public class UserList extends TwitterResponseObject implements Comparable<UserLi
@Override
public int compareTo(@NonNull UserList another) {
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;
return id.compareTo(another.id);
}
@Override

View File

@ -75,7 +75,6 @@ public interface IntentConstants {
String BROADCAST_NOTIFICATION_DELETED = INTENT_PACKAGE_PREFIX + "NOTIFICATION_DELETED";
String BROADCAST_USER_LIST_MEMBERS_DELETED = INTENT_PACKAGE_PREFIX + "USER_LIST_MEMBER_DELETED";
String BROADCAST_USER_LIST_MEMBERS_ADDED = INTENT_PACKAGE_PREFIX + "USER_LIST_MEMBER_ADDED";
String BROADCAST_REFRESH_HOME_TIMELINE = INTENT_PACKAGE_PREFIX + "REFRESH_HOME_TIMELINE";
String BROADCAST_REFRESH_NOTIFICATIONS = INTENT_PACKAGE_PREFIX + "REFRESH_NOTIFICATIONS";
String BROADCAST_REFRESH_DIRECT_MESSAGES = INTENT_PACKAGE_PREFIX + "REFRESH_DIRECT_MESSAGES";

View File

@ -274,8 +274,6 @@ public interface SharedPreferenceConstants {
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false)
String KEY_COMPACT_CARDS = "compact_cards";
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false)
String KEY_FORCE_USING_PRIVATE_APIS = "force_using_private_apis";
@Preference(type = STRING, hasDefault = true, defaultString = VALUE_COMPOSE_NOW_ACTION_COMPOSE)
String KEY_COMPOSE_NOW_ACTION = "compose_now_action";
String KEY_FALLBACK_TWITTER_LINK_HANDLER = "fallback_twitter_link_handler";

View File

@ -61,13 +61,19 @@ public class ParcelableMedia implements Parcelable {
@ParcelableThisPlease
@JsonField(name = "open_browser")
public boolean open_browser;
@ParcelableThisPlease
@JsonField(name = "alt_text")
public String alt_text;
public static final Creator<ParcelableMedia> CREATOR = new Creator<ParcelableMedia>() {
@Override
public ParcelableMedia createFromParcel(Parcel source) {
ParcelableMedia target = new ParcelableMedia();
ParcelableMediaParcelablePlease.readFromParcel(target, source);
return target;
}
@Override
public ParcelableMedia[] newArray(int size) {
return new ParcelableMedia[size];
}
@ -185,12 +191,14 @@ public class ParcelableMedia implements Parcelable {
@JsonField(name = "duration")
public long duration;
public static final Creator<VideoInfo> CREATOR = new Creator<VideoInfo>() {
@Override
public VideoInfo createFromParcel(Parcel source) {
VideoInfo target = new VideoInfo();
ParcelableMedia$VideoInfoParcelablePlease.readFromParcel(target, source);
return target;
}
@Override
public VideoInfo[] newArray(int size) {
return new VideoInfo[size];
}
@ -261,12 +269,14 @@ public class ParcelableMedia implements Parcelable {
@JsonField(name = "bitrate")
public long bitrate;
public static final Creator<Variant> CREATOR = new Creator<Variant>() {
@Override
public Variant createFromParcel(Parcel source) {
Variant target = new Variant();
ParcelableMedia$VideoInfo$VariantParcelablePlease.readFromParcel(target, source);
return target;
}
@Override
public Variant[] newArray(int size) {
return new Variant[size];
}

View File

@ -19,6 +19,9 @@ public class ParcelableMediaUpdate implements Parcelable {
@JsonField(name = "type")
public int type;
@JsonField(name = "alt_text")
public String alt_text;
public ParcelableMediaUpdate() {
}
@ -27,11 +30,6 @@ public class ParcelableMediaUpdate implements Parcelable {
this.type = type;
}
@Override
public String toString() {
return "ParcelableMediaUpdate{uri=" + uri + ", type=" + type + "}";
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
@ -40,7 +38,8 @@ public class ParcelableMediaUpdate implements Parcelable {
ParcelableMediaUpdate that = (ParcelableMediaUpdate) o;
if (type != that.type) return false;
return uri.equals(that.uri);
if (!uri.equals(that.uri)) return false;
return alt_text != null ? alt_text.equals(that.alt_text) : that.alt_text == null;
}
@ -48,9 +47,19 @@ public class ParcelableMediaUpdate implements Parcelable {
public int hashCode() {
int result = uri.hashCode();
result = 31 * result + type;
result = 31 * result + (alt_text != null ? alt_text.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "ParcelableMediaUpdate{" +
"uri='" + uri + '\'' +
", type=" + type +
", alt_text='" + alt_text + '\'' +
'}';
}
@Override
public int describeContents() {
return 0;
@ -62,12 +71,14 @@ public class ParcelableMediaUpdate implements Parcelable {
}
public static final Creator<ParcelableMediaUpdate> CREATOR = new Creator<ParcelableMediaUpdate>() {
@Override
public ParcelableMediaUpdate createFromParcel(Parcel source) {
ParcelableMediaUpdate target = new ParcelableMediaUpdate();
ParcelableMediaUpdateParcelablePlease.readFromParcel(target, source);
return target;
}
@Override
public ParcelableMediaUpdate[] newArray(int size) {
return new ParcelableMediaUpdate[size];
}

View File

@ -39,7 +39,7 @@ public class ParcelableUserList implements Parcelable, Comparable<ParcelableUser
public UserKey account_key;
@ParcelableThisPlease
@JsonField(name = "id")
public long id;
public String id;
@ParcelableThisPlease
@JsonField(name = "is_public")
public boolean is_public;
@ -93,33 +93,33 @@ public class ParcelableUserList implements Parcelable, Comparable<ParcelableUser
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ParcelableUserList that = (ParcelableUserList) o;
ParcelableUserList userList = (ParcelableUserList) o;
if (id != that.id) return false;
return account_key.equals(that.account_key);
if (!account_key.equals(userList.account_key)) return false;
return id.equals(userList.id);
}
@Override
public int hashCode() {
int result = account_key.hashCode();
result = 31 * result + (int) (id ^ (id >>> 32));
result = 31 * result + id.hashCode();
return result;
}
@Override
public String toString() {
return "ParcelableUserList{" +
"members_count=" + members_count +
", subscribers_count=" + subscribers_count +
", account_key=" + account_key +
", id=" + id +
", user_id=" + user_key +
", position=" + position +
"account_key=" + account_key +
", id='" + id + '\'' +
", is_public=" + is_public +
", is_following=" + is_following +
", description='" + description + '\'' +
", name='" + name + '\'' +
", position=" + position +
", members_count=" + members_count +
", subscribers_count=" + subscribers_count +
", user_key=" + user_key +
", user_screen_name='" + user_screen_name + '\'' +
", user_name='" + user_name + '\'' +
", user_profile_image_url='" + user_profile_image_url + '\'' +
@ -137,12 +137,14 @@ public class ParcelableUserList implements Parcelable, Comparable<ParcelableUser
}
public static final Creator<ParcelableUserList> CREATOR = new Creator<ParcelableUserList>() {
@Override
public ParcelableUserList createFromParcel(Parcel source) {
ParcelableUserList target = new ParcelableUserList();
ParcelableUserListParcelablePlease.readFromParcel(target, source);
return target;
}
@Override
public ParcelableUserList[] newArray(int size) {
return new ParcelableUserList[size];
}

View File

@ -21,8 +21,8 @@ android {
applicationId "org.mariotaku.twidere"
minSdkVersion 14
targetSdkVersion 23
versionCode 179
versionName "3.1.1.7"
versionCode 180
versionName "3.1.2"
multiDexEnabled true
generatedDensities = []

View File

@ -32,6 +32,7 @@ import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceFragmentCompat;
import android.support.v7.preference.PreferenceFragmentCompat.OnPreferenceDisplayDialogCallback;
import android.support.v7.view.menu.ActionMenuItemView;
import android.support.v7.widget.Toolbar;
import android.support.v7.widget.TwidereActionMenuView;
import android.util.AttributeSet;
import android.view.KeyEvent;
@ -39,7 +40,11 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import com.afollestad.appthemeengine.ATE;
import com.afollestad.appthemeengine.ATEActivity;
import com.afollestad.appthemeengine.Config;
import com.afollestad.appthemeengine.customizers.ATEStatusBarCustomizer;
import com.afollestad.appthemeengine.customizers.ATEToolbarCustomizer;
import com.squareup.otto.Bus;
import org.mariotaku.twidere.BuildConfig;
@ -73,7 +78,8 @@ import javax.inject.Inject;
@SuppressLint("Registered")
public class BaseActivity extends ATEActivity implements Constants, IExtendedActivity,
IThemedActivity, IAppCompatActivity, IControlBarActivity, OnFitSystemWindowsListener,
SystemWindowsInsetsCallback, KeyboardShortcutCallback, OnPreferenceDisplayDialogCallback {
SystemWindowsInsetsCallback, KeyboardShortcutCallback, OnPreferenceDisplayDialogCallback,
ATEToolbarCustomizer, ATEStatusBarCustomizer {
private static final String[] sClassPrefixList = {
"android.widget.",
@ -277,11 +283,6 @@ public class BaseActivity extends ATEActivity implements Constants, IExtendedAct
mCurrentThemeBackgroundAlpha = getThemeBackgroundAlpha();
mCurrentThemeBackgroundOption = getThemeBackgroundOption();
super.onApplyThemeResource(theme, resId, first);
}
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
final Window window = getWindow();
if (window != null && shouldApplyWindowBackground()) {
ThemeUtils.applyWindowBackground(this, window, getThemeBackgroundOption(),
@ -370,4 +371,26 @@ public class BaseActivity extends ATEActivity implements Constants, IExtendedAct
}
return false;
}
@Override
public int getStatusBarColor() {
return ATE.USE_DEFAULT;
}
@Override
public int getToolbarColor(@Nullable Toolbar toolbar) {
return ATE.USE_DEFAULT;
}
@Override
public int getLightStatusBarMode() {
//noinspection WrongConstant
return ThemeUtils.getLightStatusBarMode(Config.statusBarColor(this, getATEKey()));
}
@Override
public int getLightToolbarMode(@Nullable Toolbar toolbar) {
//noinspection WrongConstant
return ThemeUtils.getLightToolbarMode(Config.toolbarColor(this, getATEKey(), toolbar));
}
}

View File

@ -61,6 +61,7 @@ import org.mariotaku.twidere.model.tab.argument.TabArguments;
import org.mariotaku.twidere.model.tab.argument.TextQueryArguments;
import org.mariotaku.twidere.model.tab.argument.UserArguments;
import org.mariotaku.twidere.model.tab.argument.UserListArguments;
import org.mariotaku.twidere.model.tab.extra.TabExtras;
import org.mariotaku.twidere.util.CustomTabUtils;
import org.mariotaku.twidere.util.DataStoreUtils;
import org.mariotaku.twidere.util.InternalParseUtils;
@ -315,8 +316,7 @@ public class CustomTabEditorActivity extends BaseActivity implements OnClickList
mAccountsAdapter.add(ParcelableAccount.dummyCredentials());
}
final boolean officialKeyOnly = intent.getBooleanExtra(EXTRA_OFFICIAL_KEY_ONLY, false);
final boolean forcePrivateAPIs = intent.getBooleanExtra(KEY_FORCE_USING_PRIVATE_APIS, false);
mAccountsAdapter.addAll(DataStoreUtils.getCredentialsList(this, false, !forcePrivateAPIs && officialKeyOnly));
mAccountsAdapter.addAll(DataStoreUtils.getCredentialsList(this, false, officialKeyOnly));
mAccountsAdapter.setDummyItemText(R.string.activated_accounts);
switch (conf.getSecondaryFieldType()) {
case CustomTabConfiguration.FIELD_TYPE_USER: {
@ -350,7 +350,10 @@ public class CustomTabEditorActivity extends BaseActivity implements OnClickList
iconKey = intent.getStringExtra(EXTRA_ICON);
mEditTabName.setText(intent.getStringExtra(EXTRA_NAME));
if (savedInstanceState == null && intent.hasExtra(EXTRA_EXTRAS)) {
mExtrasBundle.putAll(InternalParseUtils.jsonToBundle(intent.getStringExtra(EXTRA_EXTRAS)));
TabExtras extras = CustomTabUtils.parseTabExtras(type, intent.getStringExtra(EXTRA_EXTRAS));
if (extras != null) {
extras.copyToBundle(mExtrasBundle);
}
}
}
final int selection = mTabIconsAdapter.getIconPosition(iconKey);

View File

@ -55,7 +55,6 @@ import org.mariotaku.twidere.fragment.CustomTabsFragment;
import org.mariotaku.twidere.fragment.ExtensionsListFragment;
import org.mariotaku.twidere.fragment.SettingsDetailsFragment;
import org.mariotaku.twidere.fragment.SupportBrowserFragment;
import org.mariotaku.twidere.preference.iface.IDialogPreference;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
import org.mariotaku.twidere.util.ThemeUtils;
@ -239,6 +238,7 @@ public class SettingsActivity extends BaseActivity implements OnItemClickListene
}
protected void openDetails(int position) {
if (isFinishing()) return;
final Entry entry = mEntriesAdapter.getItem(position);
if (!(entry instanceof PreferenceEntry)) return;
final PreferenceEntry pe = (PreferenceEntry) entry;

View File

@ -310,8 +310,8 @@ public final class DummyItemAdapter implements IStatusesAdapter<Object>,
}
@Override
public long getUserListId(int position) {
return 0;
public String getUserListId(int position) {
return null;
}
@Override

View File

@ -101,8 +101,8 @@ public class ParcelableUserListsAdapter extends LoadMoreSupportAdapter<RecyclerV
}
@Override
public long getUserListId(int position) {
if (position == getUserListsCount()) return -1;
public String getUserListId(int position) {
if (position == getUserListsCount()) return null;
return mData.get(position).id;
}
@ -193,8 +193,6 @@ public class ParcelableUserListsAdapter extends LoadMoreSupportAdapter<RecyclerV
int cardBackgroundColor) {
final View view;
view = inflater.inflate(R.layout.card_item_user_list_compact, parent, false);
final View itemContent = view.findViewById(R.id.item_content);
itemContent.setBackgroundColor(cardBackgroundColor);
final UserListViewHolder holder = new UserListViewHolder(adapter, view);
holder.setOnClickListeners();
holder.setupViewOptions();

View File

@ -236,8 +236,6 @@ public class ParcelableUsersAdapter extends LoadMoreSupportAdapter<RecyclerView.
LayoutInflater inflater, ViewGroup parent,
int cardBackgroundColor) {
final View view = inflater.inflate(R.layout.card_item_user_compact, parent, false);
final View itemContent = view.findViewById(R.id.item_content);
itemContent.setBackgroundColor(cardBackgroundColor);
final UserViewHolder holder = new UserViewHolder(adapter, view);
holder.setOnClickListeners();
holder.setupViewOptions();

View File

@ -48,7 +48,7 @@ public class SimpleParcelableUserListsAdapter extends BaseArrayAdapter<Parcelabl
@Override
public long getItemId(final int position) {
return getItem(position) != null ? getItem(position).id : -1;
return getItem(position) != null ? getItem(position).hashCode() : -1;
}
@Override
@ -80,13 +80,14 @@ public class SimpleParcelableUserListsAdapter extends BaseArrayAdapter<Parcelabl
return view;
}
public void setData(final List<ParcelableUserList> data, final boolean clear_old) {
if (clear_old) {
public void setData(final List<ParcelableUserList> data, final boolean clearOld) {
if (clearOld) {
clear();
}
if (data == null) return;
for (final ParcelableUserList user : data) {
if (clear_old || findItemPosition(user.id) < 0) {
//TODO improve compare
if (clearOld || findItemPosition(user.hashCode()) < 0) {
add(user);
}
}

View File

@ -33,7 +33,7 @@ public interface IUserListsAdapter<Data> extends IContentCardAdapter {
ParcelableUserList getUserList(int position);
long getUserListId(int position);
String getUserListId(int position);
int getUserListsCount();

View File

@ -26,8 +26,11 @@ import com.bluelinelabs.logansquare.JsonMapper;
import com.fasterxml.jackson.core.JsonParseException;
import org.mariotaku.restfu.RestConverter;
import org.mariotaku.restfu.http.ContentType;
import org.mariotaku.restfu.http.HttpResponse;
import org.mariotaku.restfu.http.mime.Body;
import org.mariotaku.restfu.http.mime.SimpleBody;
import org.mariotaku.restfu.http.mime.StringBody;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.auth.OAuthToken;
import org.mariotaku.twidere.api.twitter.model.ResponseCode;
@ -50,7 +53,6 @@ public class TwitterConverterFactory extends RestConverter.SimpleFactory<Twitter
sResponseConverters.put(ResponseCode.class, new ResponseCode.ResponseConverter());
sResponseConverters.put(OAuthToken.class, new OAuthToken.ResponseConverter());
// sBodyConverters.put(CardDataMap.class, new CardDataMap.BodyConverter());
}
@NonNull
@ -81,7 +83,7 @@ public class TwitterConverterFactory extends RestConverter.SimpleFactory<Twitter
} catch (LoganSquareMapperFinder.ClassLoaderDeadLockException e) {
throw new RestConverter.ConvertException(e);
}
return new JsonConverter(mapper);
return new JsonResponseConverter(mapper);
}
@Override
@ -90,7 +92,14 @@ public class TwitterConverterFactory extends RestConverter.SimpleFactory<Twitter
if (converter != null) {
return converter;
}
return super.forRequest(type);
if (SimpleBody.supports(type)) {
return new SimpleBodyConverter<>(type);
}
try {
return new JsonRequestConverter(LoganSquareMapperFinder.mapperFor(type));
} catch (LoganSquareMapperFinder.ClassLoaderDeadLockException e) {
throw new RestConverter.ConvertException(e);
}
}
public static class UnsupportedTypeException extends UnsupportedOperationException {
@ -99,10 +108,10 @@ public class TwitterConverterFactory extends RestConverter.SimpleFactory<Twitter
}
}
public static class JsonConverter implements RestConverter<HttpResponse, Object, TwitterException> {
public static class JsonResponseConverter implements RestConverter<HttpResponse, Object, TwitterException> {
private final JsonMapper<?> mapper;
public JsonConverter(JsonMapper<?> mapper) {
public JsonResponseConverter(JsonMapper<?> mapper) {
this.mapper = mapper;
}
@ -116,4 +125,17 @@ public class TwitterConverterFactory extends RestConverter.SimpleFactory<Twitter
}
}
public static class JsonRequestConverter implements RestConverter<Object, Body, TwitterException> {
private final JsonMapper<Object> mapper;
public JsonRequestConverter(JsonMapper<Object> mapper) {
this.mapper = mapper;
}
@Override
public Body convert(Object request) throws IOException, ConvertException, TwitterException {
return new StringBody(mapper.serialize(request), ContentType.parse("application/json"));
}
}
}

View File

@ -39,8 +39,11 @@ import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton;
import android.support.multidex.MultiDex;
import android.support.v4.content.ContextCompat;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatDelegate;
import android.support.v7.widget.ActionBarContextView;
import android.widget.ImageView;
import android.widget.TextView;
import com.afollestad.appthemeengine.ATE;
import com.afollestad.appthemeengine.Config;
@ -66,16 +69,17 @@ import org.mariotaku.twidere.util.content.TwidereSQLiteOpenHelper;
import org.mariotaku.twidere.util.dagger.DependencyHolder;
import org.mariotaku.twidere.util.net.TwidereDns;
import org.mariotaku.twidere.util.theme.ActionBarContextViewViewProcessor;
import org.mariotaku.twidere.util.theme.ExtendedSwipeRefreshLayoutViewProcessor;
import org.mariotaku.twidere.util.theme.FloatingActionButtonViewProcessor;
import org.mariotaku.twidere.util.theme.FontFamilyTagProcessor;
import org.mariotaku.twidere.util.theme.IconActionButtonTagProcessor;
import org.mariotaku.twidere.util.theme.ImageViewViewProcessor;
import org.mariotaku.twidere.util.theme.OptimalLinkColorTagProcessor;
import org.mariotaku.twidere.util.theme.ProfileImageViewViewProcessor;
import org.mariotaku.twidere.util.theme.ProgressWheelViewProcessor;
import org.mariotaku.twidere.util.theme.SwipeRefreshLayoutViewProcessor;
import org.mariotaku.twidere.util.theme.TabPagerIndicatorViewProcessor;
import org.mariotaku.twidere.util.theme.TextViewViewProcessor;
import org.mariotaku.twidere.util.theme.TimelineContentTextViewViewProcessor;
import org.mariotaku.twidere.view.ExtendedSwipeRefreshLayout;
import org.mariotaku.twidere.view.ProfileImageView;
import org.mariotaku.twidere.view.TabPagerIndicator;
import org.mariotaku.twidere.view.ThemedMultiValueSwitch;
@ -144,8 +148,10 @@ public class TwidereApplication extends Application implements Constants,
ATE.registerViewProcessor(TabPagerIndicator.class, new TabPagerIndicatorViewProcessor());
ATE.registerViewProcessor(FloatingActionButton.class, new FloatingActionButtonViewProcessor());
ATE.registerViewProcessor(ActionBarContextView.class, new ActionBarContextViewViewProcessor());
ATE.registerViewProcessor(ExtendedSwipeRefreshLayout.class, new ExtendedSwipeRefreshLayoutViewProcessor());
ATE.registerViewProcessor(SwipeRefreshLayout.class, new SwipeRefreshLayoutViewProcessor());
ATE.registerViewProcessor(TimelineContentTextView.class, new TimelineContentTextViewViewProcessor());
ATE.registerViewProcessor(TextView.class, new TextViewViewProcessor());
ATE.registerViewProcessor(ImageView.class, new ImageViewViewProcessor());
ATE.registerViewProcessor(ProgressWheel.class, new ProgressWheelViewProcessor());
ATE.registerViewProcessor(ProfileImageView.class, mProfileImageViewViewProcessor);
ATE.registerTagProcessor(OptimalLinkColorTagProcessor.TAG, new OptimalLinkColorTagProcessor());
@ -166,16 +172,17 @@ public class TwidereApplication extends Application implements Constants,
final int themeColor = preferences.getInt(KEY_THEME_COLOR, ContextCompat.getColor(this,
R.color.branding_color));
if (!ATE.config(this, VALUE_THEME_NAME_LIGHT).isConfigured()) {
//noinspection WrongConstant
ATE.config(this, VALUE_THEME_NAME_LIGHT)
.primaryColor(themeColor)
.accentColor(themeColor)
.accentColor(ThemeUtils.getOptimalAccentColor(themeColor))
.coloredActionBar(true)
.coloredStatusBar(true)
.commit();
}
if (!ATE.config(this, VALUE_THEME_NAME_DARK).isConfigured()) {
ATE.config(this, VALUE_THEME_NAME_DARK)
.accentColor(themeColor)
.accentColor(ThemeUtils.getOptimalAccentColor(themeColor))
.coloredActionBar(false)
.coloredStatusBar(true)
.statusBarColor(Color.BLACK)
@ -183,7 +190,7 @@ public class TwidereApplication extends Application implements Constants,
}
if (!ATE.config(this, null).isConfigured()) {
ATE.config(this, null)
.accentColor(themeColor)
.accentColor(ThemeUtils.getOptimalAccentColor(themeColor))
.coloredActionBar(false)
.coloredStatusBar(false)
.commit();
@ -347,20 +354,21 @@ public class TwidereApplication extends Application implements Constants,
case KEY_THEME_COLOR: {
final int themeColor = preferences.getInt(key, ContextCompat.getColor(this,
R.color.branding_color));
//noinspection WrongConstant
ATE.config(this, VALUE_THEME_NAME_LIGHT)
.primaryColor(themeColor)
.accentColor(themeColor)
.accentColor(ThemeUtils.getOptimalAccentColor(themeColor))
.coloredActionBar(true)
.coloredStatusBar(true)
.commit();
ATE.config(this, VALUE_THEME_NAME_DARK)
.accentColor(themeColor)
.accentColor(ThemeUtils.getOptimalAccentColor(themeColor))
.coloredActionBar(false)
.coloredStatusBar(true)
.statusBarColor(Color.BLACK)
.commit();
ATE.config(this, null)
.accentColor(themeColor)
.accentColor(ThemeUtils.getOptimalAccentColor(themeColor))
.coloredActionBar(false)
.coloredStatusBar(false)
.commit();

View File

@ -26,7 +26,7 @@ import android.graphics.Rect;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.Loader;
import android.support.v7.widget.LinearLayoutManager;
@ -47,6 +47,7 @@ import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.ParcelableStatusesAdapter;
import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter.IndicatorPosition;
import org.mariotaku.twidere.annotation.ReadPositionTag;
import org.mariotaku.twidere.constant.IntentConstants;
import org.mariotaku.twidere.graphic.like.LikeAnimationDrawable;
import org.mariotaku.twidere.loader.iface.IExtendedLoader;
import org.mariotaku.twidere.model.BaseRefreshTaskParam;
@ -349,6 +350,47 @@ public abstract class AbsStatusesFragment extends AbsContentListRecyclerViewFrag
// END HotMobi
}
@Override
public void onItemActionClick(RecyclerView.ViewHolder holder, int id, int position) {
final Context context = getContext();
if (context == null) return;
final ParcelableStatusesAdapter adapter = getAdapter();
final ParcelableStatus status = adapter.getStatus(position);
if (status == null) return;
handleStatusActionClick(context, getFragmentManager(), mTwitterWrapper,
(StatusViewHolder) holder, status, id);
}
public static void handleStatusActionClick(Context context, FragmentManager fm,
AsyncTwitterWrapper twitter, StatusViewHolder holder,
ParcelableStatus status, int id) {
if (status == null) return;
switch (id) {
case R.id.reply: {
final Intent intent = new Intent(IntentConstants.INTENT_ACTION_REPLY);
intent.setPackage(context.getPackageName());
intent.putExtra(IntentConstants.EXTRA_STATUS, status);
context.startActivity(intent);
break;
}
case R.id.retweet: {
RetweetQuoteDialogFragment.show(fm, status);
break;
}
case R.id.favorite: {
if (twitter == null) return;
if (status.is_favorite) {
twitter.destroyFavoriteAsync(status.account_key, status.id);
} else {
holder.playLikeAnimation(new DefaultOnLikedListener(twitter,
status));
}
break;
}
}
}
protected void saveReadPosition() {
final LinearLayoutManager layoutManager = getLayoutManager();
if (layoutManager != null) {
@ -363,38 +405,6 @@ public abstract class AbsStatusesFragment extends AbsContentListRecyclerViewFrag
@TimelineType
protected abstract String getTimelineType();
@Override
public void onItemActionClick(RecyclerView.ViewHolder holder, int id, int position) {
final ParcelableStatusesAdapter adapter = getAdapter();
final ParcelableStatus status = adapter.getStatus(position);
if (status == null) return;
final FragmentActivity activity = getActivity();
switch (id) {
case R.id.reply: {
final Intent intent = new Intent(INTENT_ACTION_REPLY);
intent.setPackage(activity.getPackageName());
intent.putExtra(EXTRA_STATUS, status);
activity.startActivity(intent);
break;
}
case R.id.retweet: {
RetweetQuoteDialogFragment.show(getFragmentManager(), status);
break;
}
case R.id.favorite: {
final AsyncTwitterWrapper twitter = mTwitterWrapper;
if (twitter == null) return;
if (status.is_favorite) {
twitter.destroyFavoriteAsync(status.account_key, status.id);
} else {
((StatusViewHolder) holder).playLikeAnimation(new DefaultOnLikedListener(twitter,
status));
}
break;
}
}
}
@Override
public void onStatusClick(IStatusViewHolder holder, int position) {
final ParcelableStatusesAdapter adapter = getAdapter();
@ -595,8 +605,8 @@ public abstract class AbsStatusesFragment extends AbsContentListRecyclerViewFrag
startActivity(chooser);
return true;
}
return MenuUtils.handleStatusClick(getActivity(), AbsStatusesFragment.this,
getFragmentManager(), mUserColorNameManager, mTwitterWrapper, status, item);
return MenuUtils.handleStatusClick(getActivity(), this, getFragmentManager(),
mUserColorNameManager, mTwitterWrapper, status, item);
}
private String getCurrentReadPositionTag() {

View File

@ -27,6 +27,7 @@ import android.support.v4.content.Loader;
import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter.IndicatorPosition;
import org.mariotaku.twidere.loader.CursorSupportUsersLoader;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.view.holder.UserViewHolder;
import java.util.List;
@ -99,4 +100,5 @@ public abstract class CursorSupportUsersListFragment extends ParcelableUsersFrag
@Override
protected abstract CursorSupportUsersLoader onCreateUsersLoader(final Context context, @NonNull final Bundle args, boolean fromUser);
}

View File

@ -30,6 +30,7 @@ import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
@ -51,6 +52,8 @@ import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import com.afollestad.appthemeengine.ATEActivity;
import com.afollestad.appthemeengine.Config;
import com.mobeta.android.dslv.DragSortListView;
import com.mobeta.android.dslv.DragSortListView.DropListener;
import com.mobeta.android.dslv.SimpleDragSortCursorAdapter;
@ -59,15 +62,14 @@ import org.mariotaku.sqliteqb.library.Columns.Column;
import org.mariotaku.sqliteqb.library.Expression;
import org.mariotaku.sqliteqb.library.RawItemArray;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.SettingsActivity;
import org.mariotaku.twidere.activity.CustomTabEditorActivity;
import org.mariotaku.twidere.activity.SettingsActivity;
import org.mariotaku.twidere.model.CustomTabConfiguration;
import org.mariotaku.twidere.model.CustomTabConfiguration.CustomTabConfigurationComparator;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.provider.TwidereDataStore.Tabs;
import org.mariotaku.twidere.util.DataStoreUtils;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.view.holder.TwoLineWithIconViewHolder;
import java.util.ArrayList;
@ -220,9 +222,8 @@ public class CustomTabsFragment extends BaseSupportFragment implements LoaderCal
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
inflater.inflate(R.menu.menu_custom_tabs, menu);
final Resources res = getResources();
final boolean hasOfficialKeyAccounts = Utils.hasAccountSignedWithOfficialKeys(getActivity());
final boolean forcePrivateAPI = mPreferences.getBoolean(KEY_FORCE_USING_PRIVATE_APIS, false);
final UserKey[] accountIds = DataStoreUtils.getAccountKeys(getActivity());
final FragmentActivity activity = getActivity();
final UserKey[] accountIds = DataStoreUtils.getAccountKeys(activity);
final MenuItem itemAdd = menu.findItem(R.id.add_submenu);
if (itemAdd != null && itemAdd.hasSubMenu()) {
final SubMenu subMenu = itemAdd.getSubMenu();
@ -238,16 +239,20 @@ public class CustomTabsFragment extends BaseSupportFragment implements LoaderCal
final boolean accountIdRequired = conf.getAccountRequirement() == CustomTabConfiguration.ACCOUNT_REQUIRED;
final Intent intent = new Intent(INTENT_ACTION_ADD_TAB);
intent.setClass(getActivity(), CustomTabEditorActivity.class);
intent.setClass(activity, CustomTabEditorActivity.class);
intent.putExtra(EXTRA_TYPE, type);
final MenuItem subItem = subMenu.add(conf.getDefaultTitle());
final boolean disabledByNoAccount = accountIdRequired && accountIds.length == 0;
final boolean disabledByDuplicateTab = conf.isSingleTab() && isTabAdded(getActivity(), type);
final boolean disabledByDuplicateTab = conf.isSingleTab() && isTabAdded(activity, type);
final boolean shouldDisable = disabledByDuplicateTab || disabledByNoAccount;
subItem.setVisible(!shouldDisable);
subItem.setEnabled(!shouldDisable);
final Drawable icon = ResourcesCompat.getDrawable(res, conf.getDefaultIcon(), null);
if (icon != null && activity instanceof ATEActivity) {
icon.mutate().setColorFilter(Config.textColorPrimary(activity,
((ATEActivity) activity).getATEKey()), Mode.SRC_ATOP);
}
subItem.setIcon(icon);
subItem.setIntent(intent);
}

View File

@ -20,7 +20,6 @@
package org.mariotaku.twidere.fragment;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.os.Bundle;
@ -59,8 +58,7 @@ public class DeleteUserListMembersDialogFragment extends BaseSupportDialogFragme
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final FragmentActivity activity = getActivity();
final Context context = activity;
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
final ParcelableUser[] users = getUsers();
final ParcelableUserList userList = getUserList();
if (users == null || userList == null) throw new NullPointerException();

View File

@ -1,6 +1,7 @@
package org.mariotaku.twidere.fragment;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.annotation.NonNull;
@ -9,7 +10,12 @@ import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import android.support.v7.widget.RecyclerView;
import android.view.ContextMenu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.DummyItemAdapter;
import org.mariotaku.twidere.adapter.VariousItemsAdapter;
import org.mariotaku.twidere.adapter.decorator.DividerItemDecoration;
@ -17,6 +23,11 @@ import org.mariotaku.twidere.adapter.iface.IUsersAdapter;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.util.IntentUtils;
import org.mariotaku.twidere.util.LinkCreator;
import org.mariotaku.twidere.util.MenuUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.view.ExtendedRecyclerView;
import org.mariotaku.twidere.view.holder.StatusViewHolder;
import org.mariotaku.twidere.view.holder.UserViewHolder;
import org.mariotaku.twidere.view.holder.iface.IStatusViewHolder;
@ -30,6 +41,7 @@ public class ItemsListFragment extends AbsContentListRecyclerViewFragment<Variou
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
registerForContextMenu(getRecyclerView());
getLoaderManager().initLoader(0, null, this);
setRefreshEnabled(false);
showContent();
@ -47,6 +59,24 @@ public class ItemsListFragment extends AbsContentListRecyclerViewFragment<Variou
if (status == null) return;
IntentUtils.openStatus(getContext(), status, null);
}
@Override
public void onItemActionClick(RecyclerView.ViewHolder holder, int id, int position) {
final Context context = getContext();
if (context == null) return;
final ParcelableStatus status = dummyItemAdapter.getStatus(position);
if (status == null) return;
AbsStatusesFragment.handleStatusActionClick(context, getFragmentManager(),
mTwitterWrapper, (StatusViewHolder) holder, status, id);
}
@Override
public void onItemMenuClick(RecyclerView.ViewHolder holder, View menuView, int position) {
if (getActivity() == null) return;
final View view = getLayoutManager().findViewByPosition(position);
if (view == null) return;
getRecyclerView().showContextMenuForChild(view);
}
});
dummyItemAdapter.setUserClickListener(new IUsersAdapter.SimpleUserClickListener() {
@Override
@ -120,6 +150,53 @@ public class ItemsListFragment extends AbsContentListRecyclerViewFragment<Variou
return false;
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
if (!getUserVisibleHint() || menuInfo == null) return;
final MenuInflater inflater = new MenuInflater(getContext());
final ExtendedRecyclerView.ContextMenuInfo contextMenuInfo =
(ExtendedRecyclerView.ContextMenuInfo) menuInfo;
final int position = contextMenuInfo.getPosition();
final VariousItemsAdapter adapter = getAdapter();
switch (adapter.getItemViewType(position)) {
case VariousItemsAdapter.VIEW_TYPE_STATUS: {
final DummyItemAdapter dummyAdapter = getAdapter().getDummyAdapter();
final ParcelableStatus status = dummyAdapter.getStatus(contextMenuInfo.getPosition());
if (status == null) break;
inflater.inflate(R.menu.action_status, menu);
MenuUtils.setupForStatus(getContext(), mPreferences, menu, status,
mTwitterWrapper);
break;
}
}
}
@Override
public boolean onContextItemSelected(MenuItem item) {
if (!getUserVisibleHint()) return false;
final ExtendedRecyclerView.ContextMenuInfo contextMenuInfo =
(ExtendedRecyclerView.ContextMenuInfo) item.getMenuInfo();
final int position = contextMenuInfo.getPosition();
final VariousItemsAdapter adapter = getAdapter();
switch (adapter.getItemViewType(position)) {
case VariousItemsAdapter.VIEW_TYPE_STATUS: {
final DummyItemAdapter dummyAdapter = adapter.getDummyAdapter();
final ParcelableStatus status = dummyAdapter.getStatus(position);
if (status == null) return false;
if (item.getItemId() == R.id.share) {
final Intent shareIntent = Utils.createStatusShareIntent(getActivity(), status);
final Intent chooser = Intent.createChooser(shareIntent, getString(R.string.share_status));
Utils.addCopyLinkIntent(getContext(), chooser, LinkCreator.getStatusWebLink(status));
startActivity(chooser);
return true;
}
return MenuUtils.handleStatusClick(getActivity(), this, getFragmentManager(),
mUserColorNameManager, mTwitterWrapper, status, item);
}
}
return false;
}
public static class ItemsLoader extends AsyncTaskLoader<List<?>> {
private final Bundle mArguments;

View File

@ -98,8 +98,6 @@ import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.model.Paging;
import org.mariotaku.twidere.api.twitter.model.Status;
import org.mariotaku.twidere.api.twitter.model.TranslationResult;
import org.mariotaku.twidere.constant.IntentConstants;
import org.mariotaku.twidere.fragment.AbsStatusesFragment.DefaultOnLikedListener;
import org.mariotaku.twidere.loader.ConversationLoader;
import org.mariotaku.twidere.loader.ParcelableStatusLoader;
import org.mariotaku.twidere.menu.support.FavoriteItemProvider;
@ -429,32 +427,8 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
@Override
public void onItemActionClick(ViewHolder holder, int id, int position) {
final ParcelableStatus status = mStatusAdapter.getStatus(position);
if (status == null) return;
switch (id) {
case R.id.reply: {
final Context context = getActivity();
final Intent intent = new Intent(IntentConstants.INTENT_ACTION_REPLY);
intent.setPackage(context.getPackageName());
intent.putExtra(IntentConstants.EXTRA_STATUS, status);
context.startActivity(intent);
break;
}
case R.id.retweet: {
RetweetQuoteDialogFragment.show(getFragmentManager(), status);
break;
}
case R.id.favorite: {
final AsyncTwitterWrapper twitter = mTwitterWrapper;
if (twitter == null) return;
if (status.is_favorite) {
twitter.destroyFavoriteAsync(status.account_key, status.id);
} else {
((StatusViewHolder) holder).playLikeAnimation(new DefaultOnLikedListener(twitter,
status));
}
break;
}
}
AbsStatusesFragment.handleStatusActionClick(getContext(), getFragmentManager(), mTwitterWrapper,
(StatusViewHolder) holder, status, id);
}
@Override

View File

@ -1556,7 +1556,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
ATEUtil.darkenColor(mPrimaryColorDark));
final Window window = activity.getWindow();
mTintedStatusFrameLayout.setStatusBarColor(statusBarColor);
ThemeUtils.setLightStatusBar(window, ATEUtil.isColorLight(statusBarColor));
ThemeUtils.setLightStatusBar(window, ThemeUtils.isLightColor(statusBarColor));
int stackedTabColor = mPrimaryColor;
@ -1583,7 +1583,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
final Drawable tabBackground = mPagerIndicator.getBackground();
((ColorDrawable) tabBackground).setColor(currentTabColor);
final boolean tabItemIsDark = ATEUtil.isColorLight(currentTabColor);
final boolean tabItemIsDark = ThemeUtils.isLightColor(currentTabColor);
if (mPreviousTabItemIsDark == 0 || (tabItemIsDark ? 1 : -1) != mPreviousTabItemIsDark) {
final int tabContrastColor = ThemeUtils.getColorDependent(currentTabColor);
@ -1597,11 +1597,11 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
}
mPagerIndicator.updateAppearance();
}
mPreviousTabItemIsDark = (tabItemIsDark ? 1 : -1);
mPreviousTabItemIsDark = tabItemIsDark ? 1 : -1;
final int currentActionBarColor = (Integer) sArgbEvaluator.evaluate(factor, mActionBarShadowColor,
stackedTabColor);
final boolean actionItemIsDark = ATEUtil.isColorLight(currentActionBarColor);
final boolean actionItemIsDark = ThemeUtils.isLightColor(currentActionBarColor);
if (mPreviousActionBarItemIsDark == 0 || (actionItemIsDark ? 1 : -1) != mPreviousActionBarItemIsDark) {
ThemeUtils.applyToolbarItemColor(activity, mToolbar, currentActionBarColor);
}

View File

@ -167,13 +167,13 @@ public class UserListFragment extends AbsToolbarTabPagesFragment implements OnCl
tabArgs.putParcelable(EXTRA_ACCOUNT_KEY, userList.account_key);
tabArgs.putParcelable(EXTRA_USER_KEY, userList.user_key);
tabArgs.putString(EXTRA_SCREEN_NAME, userList.user_screen_name);
tabArgs.putLong(EXTRA_LIST_ID, userList.id);
tabArgs.putString(EXTRA_LIST_ID, userList.id);
tabArgs.putString(EXTRA_LIST_NAME, userList.name);
} else {
tabArgs.putParcelable(EXTRA_ACCOUNT_KEY, args.getParcelable(EXTRA_ACCOUNT_KEY));
tabArgs.putParcelable(EXTRA_USER_KEY, args.getParcelable(EXTRA_USER_KEY));
tabArgs.putString(EXTRA_SCREEN_NAME, args.getString(EXTRA_SCREEN_NAME));
tabArgs.putLong(EXTRA_LIST_ID, args.getLong(EXTRA_LIST_ID, -1));
tabArgs.putString(EXTRA_LIST_ID, args.getString(EXTRA_LIST_ID));
tabArgs.putString(EXTRA_LIST_NAME, args.getString(EXTRA_LIST_NAME));
}
adapter.addTab(UserListTimelineFragment.class, tabArgs, getString(R.string.statuses), null, 0, null);
@ -181,7 +181,7 @@ public class UserListFragment extends AbsToolbarTabPagesFragment implements OnCl
adapter.addTab(UserListSubscribersFragment.class, tabArgs, getString(R.string.subscribers), null, 2, null);
}
private ParcelableUserList getUserList() {
public ParcelableUserList getUserList() {
return mUserList;
}
@ -266,7 +266,7 @@ public class UserListFragment extends AbsToolbarTabPagesFragment implements OnCl
args.putString(EXTRA_LIST_NAME, userList.name);
args.putString(EXTRA_DESCRIPTION, userList.description);
args.putBoolean(EXTRA_IS_PUBLIC, userList.is_public);
args.putLong(EXTRA_LIST_ID, userList.id);
args.putString(EXTRA_LIST_ID, userList.id);
final DialogFragment f = new EditUserListDialogFragment();
f.setArguments(args);
f.show(getFragmentManager(), "edit_user_list_details");
@ -325,7 +325,7 @@ public class UserListFragment extends AbsToolbarTabPagesFragment implements OnCl
public Loader<SingleResponse<ParcelableUserList>> onCreateLoader(final int id, final Bundle args) {
final UserKey accountKey = args.getParcelable(EXTRA_ACCOUNT_KEY);
final UserKey userKey = args.getParcelable(EXTRA_USER_KEY);
final long listId = args.getLong(EXTRA_LIST_ID, -1);
final String listId = args.getString(EXTRA_LIST_ID);
final String listName = args.getString(EXTRA_LIST_NAME);
final String screenName = args.getString(EXTRA_SCREEN_NAME);
final boolean omitIntentExtra = args.getBoolean(EXTRA_OMIT_INTENT_EXTRA, true);
@ -353,7 +353,7 @@ public class UserListFragment extends AbsToolbarTabPagesFragment implements OnCl
@Subscribe
public void onUserListUpdated(UserListUpdatedEvent event) {
if (mUserList == null) return;
if (event.getUserList().id == mUserList.id) {
if (TextUtils.equals(event.getUserList().id, mUserList.id)) {
getUserListInfo(true);
}
}
@ -361,7 +361,7 @@ public class UserListFragment extends AbsToolbarTabPagesFragment implements OnCl
@Subscribe
public void onUserListSubscriptionChanged(UserListSubscriptionEvent event) {
if (mUserList == null) return;
if (event.getUserList().id == mUserList.id) {
if (TextUtils.equals(event.getUserList().id, mUserList.id)) {
getUserListInfo(true);
}
}
@ -371,7 +371,7 @@ public class UserListFragment extends AbsToolbarTabPagesFragment implements OnCl
private String mName, mDescription;
private UserKey mAccountKey;
private long mListId;
private String mListId;
private boolean mIsPublic;
@Override
@ -403,7 +403,7 @@ public class UserListFragment extends AbsToolbarTabPagesFragment implements OnCl
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final Bundle bundle = savedInstanceState == null ? getArguments() : savedInstanceState;
mAccountKey = bundle != null ? bundle.<UserKey>getParcelable(EXTRA_ACCOUNT_KEY) : null;
mListId = bundle != null ? bundle.getLong(EXTRA_LIST_ID, -1) : -1;
mListId = bundle != null ? bundle.getString(EXTRA_LIST_ID) : null;
mName = bundle != null ? bundle.getString(EXTRA_LIST_NAME) : null;
mDescription = bundle != null ? bundle.getString(EXTRA_DESCRIPTION) : null;
mIsPublic = bundle == null || bundle.getBoolean(EXTRA_IS_PUBLIC, true);
@ -439,7 +439,7 @@ public class UserListFragment extends AbsToolbarTabPagesFragment implements OnCl
@Override
public void onSaveInstanceState(final Bundle outState) {
outState.putParcelable(EXTRA_ACCOUNT_KEY, mAccountKey);
outState.putLong(EXTRA_LIST_ID, mListId);
outState.putString(EXTRA_LIST_ID, mListId);
outState.putString(EXTRA_LIST_NAME, mName);
outState.putString(EXTRA_DESCRIPTION, mDescription);
outState.putBoolean(EXTRA_IS_PUBLIC, mIsPublic);
@ -454,12 +454,12 @@ public class UserListFragment extends AbsToolbarTabPagesFragment implements OnCl
private final Bundle mExtras;
private final UserKey mAccountKey;
private final UserKey mUserKey;
private final long mListId;
private final String mListId;
private final String mScreenName, mListName;
private ParcelableUserListLoader(final Context context, final boolean omitIntentExtra,
final Bundle extras, final UserKey accountKey,
final long listId, final String listName,
final String listId, final String listName,
final UserKey userKey, final String screenName) {
super(context);
mOmitIntentExtra = omitIntentExtra;
@ -482,7 +482,7 @@ public class UserListFragment extends AbsToolbarTabPagesFragment implements OnCl
if (twitter == null) return SingleResponse.getInstance();
try {
final UserList list;
if (mListId > 0) {
if (mListId != null) {
list = twitter.showUserList(mListId);
} else if (mUserKey != null) {
list = twitter.showUserList(mListName, mUserKey.getId());

View File

@ -19,42 +19,41 @@
package org.mariotaku.twidere.fragment;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.view.ContextMenu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import com.squareup.otto.Subscribe;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.ParcelableUsersAdapter;
import org.mariotaku.twidere.loader.CursorSupportUsersLoader;
import org.mariotaku.twidere.loader.UserListMembersLoader;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.ParcelableUserList;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.model.message.UserListMembersChangedEvent;
import org.mariotaku.twidere.model.util.ParcelableUserListUtils;
import org.mariotaku.twidere.view.ExtendedRecyclerView;
import org.mariotaku.twidere.view.holder.UserViewHolder;
import java.util.Arrays;
import java.util.List;
public class UserListMembersFragment extends CursorSupportUsersListFragment {
private ParcelableUserList mUserList;
private final BroadcastReceiver mStatusReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
if (getActivity() == null || !isAdded() || isDetached()) return;
final String action = intent.getAction();
if (BROADCAST_USER_LIST_MEMBERS_DELETED.equals(action)) {
final ParcelableUserList list = intent.getParcelableExtra(EXTRA_USER_LIST);
if (mUserList != null && list != null && list.id == mUserList.id) {
removeUsers(intent.getStringExtra(EXTRA_USER_IDS));
}
}
}
};
@Override
public CursorSupportUsersLoader onCreateUsersLoader(final Context context,
@NonNull final Bundle args, boolean fromUser) {
final long listId = args.getLong(EXTRA_LIST_ID, -1);
final UserKey accountId = args.getParcelable(EXTRA_ACCOUNT_KEY);
final String listId = args.getString(EXTRA_LIST_ID);
final UserKey userKey = args.getParcelable(EXTRA_USER_KEY);
final String screenName = args.getString(EXTRA_SCREEN_NAME);
final String listName = args.getString(EXTRA_LIST_NAME);
@ -67,32 +66,113 @@ public class UserListMembersFragment extends CursorSupportUsersListFragment {
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
final Bundle args = getArguments();
if (savedInstanceState != null) {
mUserList = savedInstanceState.getParcelable(EXTRA_USER_LIST);
} else if (args != null) {
mUserList = args.getParcelable(EXTRA_USER_LIST);
}
super.onActivityCreated(savedInstanceState);
registerForContextMenu(getRecyclerView());
}
@Override
public void onSaveInstanceState(final Bundle outState) {
outState.putParcelable(EXTRA_USER_LIST, mUserList);
outState.putParcelable(EXTRA_USER_LIST, getUserList());
super.onSaveInstanceState(outState);
}
@Override
public void onStart() {
super.onStart();
final IntentFilter filter = new IntentFilter(BROADCAST_USER_LIST_MEMBERS_DELETED);
registerReceiver(mStatusReceiver, filter);
mBus.register(this);
}
@Override
public void onStop() {
unregisterReceiver(mStatusReceiver);
mBus.unregister(this);
super.onStop();
}
@Override
public boolean onUserLongClick(UserViewHolder holder, int position) {
return getRecyclerView().showContextMenuForChild(holder.itemView);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
if (!getUserVisibleHint() || menuInfo == null) return;
final ParcelableUserList userList = getUserList();
if (userList == null) return;
final Bundle args = getArguments();
final UserKey accountId = args.getParcelable(EXTRA_ACCOUNT_KEY);
final UserKey userKey = args.getParcelable(EXTRA_USER_KEY);
if (accountId == null || !accountId.equals(userKey)) return;
final ParcelableUsersAdapter adapter = getAdapter();
final MenuInflater inflater = new MenuInflater(getContext());
final ExtendedRecyclerView.ContextMenuInfo contextMenuInfo =
(ExtendedRecyclerView.ContextMenuInfo) menuInfo;
inflater.inflate(R.menu.action_user_list_member, menu);
final ParcelableUser user = adapter.getUser(contextMenuInfo.getPosition());
menu.setHeaderTitle(mUserColorNameManager.getDisplayName(user, mPreferences.getBoolean(KEY_NAME_FIRST)));
}
@Override
public boolean onContextItemSelected(MenuItem item) {
if (!getUserVisibleHint()) return false;
final ParcelableUserList userList = getUserList();
if (userList == null) return false;
final ExtendedRecyclerView.ContextMenuInfo contextMenuInfo =
(ExtendedRecyclerView.ContextMenuInfo) item.getMenuInfo();
final ParcelableUser user = getAdapter().getUser(contextMenuInfo.getPosition());
if (user == null) return false;
switch (item.getItemId()) {
case R.id.delete_from_list: {
DeleteUserListMembersDialogFragment.show(getFragmentManager(), getUserList(), user);
return true;
}
}
return false;
}
public ParcelableUserList getUserList() {
Fragment parent = getParentFragment();
if (parent instanceof UserListFragment) {
return ((UserListFragment) parent).getUserList();
}
return null;
}
@Subscribe
public void onUserListMembersChanged(UserListMembersChangedEvent event) {
ParcelableUserList userList = event.getUserList();
final Bundle args = getArguments();
final UserKey accountId = args.getParcelable(EXTRA_ACCOUNT_KEY);
final String listId = args.getString(EXTRA_LIST_ID);
final UserKey userKey = args.getParcelable(EXTRA_USER_KEY);
final String screenName = args.getString(EXTRA_SCREEN_NAME);
final String listName = args.getString(EXTRA_LIST_NAME);
if (!ParcelableUserListUtils.check(userList, accountId, listId, userKey, screenName, listName)) {
return;
}
switch (event.getAction()) {
case UserListMembersChangedEvent.Action.ADDED: {
final ParcelableUsersAdapter adapter = getAdapter();
final List<ParcelableUser> newUsers = Arrays.asList(event.getUsers());
final List<ParcelableUser> users = adapter.getData();
users.removeAll(newUsers);
users.addAll(0, newUsers);
for (int i = 0, j = users.size(); i < j; i++) {
users.get(i).position = i;
}
adapter.notifyDataSetChanged();
break;
}
case UserListMembersChangedEvent.Action.REMOVED: {
final ParcelableUsersAdapter adapter = getAdapter();
final List<ParcelableUser> removedUsers = Arrays.asList(event.getUsers());
final List<ParcelableUser> users = adapter.getData();
users.removeAll(removedUsers);
for (int i = 0, j = users.size(); i < j; i++) {
users.get(i).position = i;
}
adapter.notifyDataSetChanged();
break;
}
}
}
}

View File

@ -31,7 +31,7 @@ public class UserListSubscribersFragment extends CursorSupportUsersListFragment
@Override
public CursorSupportUsersLoader onCreateUsersLoader(final Context context, @NonNull final Bundle args, boolean fromUser) {
final long listId = args.getLong(EXTRA_LIST_ID, -1);
final String listId = args.getString(EXTRA_LIST_ID);
final UserKey accountKey = args.getParcelable(EXTRA_ACCOUNT_KEY);
final UserKey userKey = args.getParcelable(EXTRA_USER_KEY);
final String screenName = args.getString(EXTRA_SCREEN_NAME);

View File

@ -52,7 +52,7 @@ public class UserListTimelineFragment extends ParcelableStatusesFragment {
final boolean fromUser) {
setRefreshing(true);
if (args == null) return null;
final long listId = args.getLong(EXTRA_LIST_ID, -1);
final String listId = args.getString(EXTRA_LIST_ID);
final UserKey accountKey = Utils.getAccountKey(context, args);
final String maxId = args.getString(EXTRA_MAX_ID);
final String sinceId = args.getString(EXTRA_SINCE_ID);
@ -71,14 +71,14 @@ public class UserListTimelineFragment extends ParcelableStatusesFragment {
final Bundle args = getArguments();
assert args != null;
final UserKey accountKey = Utils.getAccountKey(getContext(), args);
final long listId = args.getLong(EXTRA_LIST_ID, -1);
final String listId = args.getString(EXTRA_LIST_ID);
final UserKey userKey = args.getParcelable(EXTRA_USER_KEY);
final String screenName = args.getString(EXTRA_SCREEN_NAME);
final String listName = args.getString(EXTRA_LIST_NAME);
final List<String> result = new ArrayList<>();
result.add(AUTHORITY_USER_LIST_TIMELINE);
result.add("account=" + accountKey);
if (listId > 0) {
if (listId != null) {
result.add("list_id=" + listId);
} else if (listName != null) {
if (userKey != null) {
@ -100,9 +100,9 @@ public class UserListTimelineFragment extends ParcelableStatusesFragment {
final int tabPosition = args.getInt(EXTRA_TAB_POSITION, -1);
StringBuilder sb = new StringBuilder("user_list_");
if (tabPosition < 0) return null;
final long listId = args.getLong(EXTRA_LIST_ID, -1);
final String listId = args.getString(EXTRA_LIST_ID);
final String listName = args.getString(EXTRA_LIST_NAME);
if (listId > 0) {
if (listId != null) {
sb.append(listId);
} else if (listName != null) {
final UserKey userKey = args.getParcelable(EXTRA_USER_KEY);

View File

@ -114,7 +114,7 @@ public class UserListsFragment extends ParcelableUserListsFragment {
removeUserList(event.userList.id);
}
private void removeUserList(final long id) {
private void removeUserList(final String id) {
final ParcelableUserListsAdapter adapter = getAdapter();
// final int listsIdx = adapter.findItemPosition(id);
// if (listsIdx >= 0) {

View File

@ -167,11 +167,6 @@ public class UserMediaTimelineFragment extends AbsContentRecyclerViewFragment<St
}
@Override
public void onItemActionClick(RecyclerView.ViewHolder holder, int id, int position) {
}
@Override
public void onStatusClick(IStatusViewHolder holder, int position) {
IntentUtils.openStatus(getContext(), getAdapter().getStatus(position), null);
@ -183,12 +178,17 @@ public class UserMediaTimelineFragment extends AbsContentRecyclerViewFragment<St
}
@Override
public void onItemMenuClick(RecyclerView.ViewHolder holder, View menuView, int position) {
public void onUserProfileClick(IStatusViewHolder holder, int position) {
}
@Override
public void onUserProfileClick(IStatusViewHolder holder, int position) {
public void onItemActionClick(RecyclerView.ViewHolder holder, int id, int position) {
}
@Override
public void onItemMenuClick(RecyclerView.ViewHolder holder, View menuView, int position) {
}
}

View File

@ -0,0 +1,38 @@
package org.mariotaku.twidere.graphic;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
/**
* Created by mariotaku on 16/3/30.
*/
public class WindowBackgroundDrawable extends Drawable {
private final int color;
public WindowBackgroundDrawable(int color) {
this.color = color;
}
@Override
public void draw(Canvas canvas) {
canvas.drawColor(color);
}
@Override
public void setAlpha(int alpha) {
// No-op
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
// No-op
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
}

View File

@ -35,11 +35,11 @@ import java.util.List;
public class UserListMembersLoader extends CursorSupportUsersLoader {
private final long mListId;
private final String mListId;
private final UserKey mUserKey;
private final String mScreenName, mListName;
public UserListMembersLoader(final Context context, final UserKey accountKey, final long listId,
public UserListMembersLoader(final Context context, final UserKey accountKey, final String listId,
final UserKey userKey, final String screenName, final String listName,
final List<ParcelableUser> data, boolean fromUser) {
super(context, accountKey, data, fromUser);
@ -53,7 +53,7 @@ public class UserListMembersLoader extends CursorSupportUsersLoader {
@Override
public PageableResponseList<User> getCursoredUsers(@NonNull final Twitter twitter, @NonNull ParcelableCredentials credentials, @NonNull final Paging paging)
throws TwitterException {
if (mListId > 0)
if (mListId != null)
return twitter.getUserListMembers(mListId, paging);
else if (mUserKey != null)
return twitter.getUserListMembers(mListName.replace(' ', '-'), mUserKey.getId(), paging);

View File

@ -35,11 +35,11 @@ import java.util.List;
public class UserListSubscribersLoader extends CursorSupportUsersLoader {
private final long mListId;
private final String mListId;
private final UserKey mUserKey;
private final String mScreenName, mListName;
public UserListSubscribersLoader(final Context context, final UserKey accountKey, final long listId,
public UserListSubscribersLoader(final Context context, final UserKey accountKey, final String listId,
final UserKey userKey, final String screenName, final String listName,
final List<ParcelableUser> data, boolean fromUser) {
super(context, accountKey, data, fromUser);
@ -53,7 +53,7 @@ public class UserListSubscribersLoader extends CursorSupportUsersLoader {
@Override
public PageableResponseList<User> getCursoredUsers(@NonNull final Twitter twitter, @NonNull ParcelableCredentials credentials, @NonNull final Paging paging)
throws TwitterException {
if (mListId > 0)
if (mListId != null)
return twitter.getUserListSubscribers(mListId, paging);
else if (mUserKey != null)
return twitter.getUserListSubscribers(mListName.replace(' ', '-'), mUserKey.getId(), paging);

View File

@ -40,9 +40,9 @@ public class UserListTimelineLoader extends TwitterAPIStatusesLoader {
private final UserKey mUserKey;
private final String mScreenName, mListName;
private final long mListId;
private final String mListId;
public UserListTimelineLoader(final Context context, final UserKey accountKey, final long listId,
public UserListTimelineLoader(final Context context, final UserKey accountKey, final String listId,
final UserKey userKey, final String screenName, final String listName,
final String sinceId, final String maxId, final List<ParcelableStatus> data,
final String[] savedStatusesArgs, final int tabPosition, boolean fromUser, boolean loadingMore) {
@ -56,7 +56,7 @@ public class UserListTimelineLoader extends TwitterAPIStatusesLoader {
@NonNull
@Override
protected ResponseList<Status> getStatuses(@NonNull final Twitter twitter, @NonNull ParcelableCredentials credentials, @NonNull final Paging paging) throws TwitterException {
if (mListId > 0)
if (mListId != null)
return twitter.getUserListStatuses(mListId, paging);
else if (mListName == null)
throw new TwitterException("No list name or id given");

View File

@ -0,0 +1,49 @@
package org.mariotaku.twidere.model.message;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.ParcelableUserList;
/**
* Created by mariotaku on 16/3/30.
*/
public class UserListMembersChangedEvent {
@Action
private final int action;
@NonNull
private final ParcelableUserList userList;
@NonNull
private final ParcelableUser[] users;
public UserListMembersChangedEvent(@Action int action, @NonNull ParcelableUserList userList,
@NonNull ParcelableUser[] users) {
this.action = action;
this.userList = userList;
this.users = users;
}
@Action
public int getAction() {
return action;
}
@NonNull
public ParcelableUserList getUserList() {
return userList;
}
@NonNull
public ParcelableUser[] getUsers() {
return users;
}
@IntDef({Action.ADDED, Action.REMOVED})
public @interface Action {
int ADDED = 1;
int REMOVED = 2;
}
}

View File

@ -26,7 +26,7 @@ public class UserArguments extends TabArguments {
public void copyToBundle(@NonNull Bundle bundle) {
super.copyToBundle(bundle);
if (userKey == null) {
bundle.putParcelable(EXTRA_USER_ID, UserKey.valueOf(userId));
bundle.putParcelable(EXTRA_USER_KEY, UserKey.valueOf(userId));
} else {
bundle.putParcelable(EXTRA_USER_KEY, userKey);
}

View File

@ -12,20 +12,20 @@ import com.bluelinelabs.logansquare.annotation.JsonObject;
@JsonObject
public class UserListArguments extends TabArguments {
@JsonField(name = "list_id")
long listId;
String listId;
public long getListId() {
public String getListId() {
return listId;
}
public void setListId(long listId) {
public void setListId(String listId) {
this.listId = listId;
}
@Override
public void copyToBundle(@NonNull Bundle bundle) {
super.copyToBundle(bundle);
bundle.putLong(EXTRA_LIST_ID, listId);
bundle.putString(EXTRA_LIST_ID, listId);
}
@Override

View File

@ -1,5 +1,6 @@
package org.mariotaku.twidere.model.tab.extra;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@ -8,6 +9,8 @@ import com.bluelinelabs.logansquare.annotation.JsonObject;
import com.hannesdorfmann.parcelableplease.annotation.ParcelablePlease;
import com.hannesdorfmann.parcelableplease.annotation.ParcelableThisPlease;
import org.mariotaku.twidere.constant.IntentConstants;
/**
* Created by mariotaku on 16/3/6.
*/
@ -39,6 +42,13 @@ public class InteractionsTabExtras extends TabExtras implements Parcelable {
this.mentionsOnly = mentionsOnly;
}
@Override
public void copyToBundle(Bundle bundle) {
super.copyToBundle(bundle);
bundle.putBoolean(IntentConstants.EXTRA_MY_FOLLOWING_ONLY, myFollowingOnly);
bundle.putBoolean(IntentConstants.EXTRA_MENTIONS_ONLY, mentionsOnly);
}
@Override
public int describeContents() {
return 0;
@ -50,12 +60,14 @@ public class InteractionsTabExtras extends TabExtras implements Parcelable {
}
public static final Creator<InteractionsTabExtras> CREATOR = new Creator<InteractionsTabExtras>() {
@Override
public InteractionsTabExtras createFromParcel(Parcel source) {
InteractionsTabExtras target = new InteractionsTabExtras();
InteractionsTabExtrasParcelablePlease.readFromParcel(target, source);
return target;
}
@Override
public InteractionsTabExtras[] newArray(int size) {
return new InteractionsTabExtras[size];
}

View File

@ -1,6 +1,8 @@
package org.mariotaku.twidere.model.tab.extra;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.annotation.CallSuper;
import com.bluelinelabs.logansquare.annotation.JsonObject;
@ -9,4 +11,8 @@ import com.bluelinelabs.logansquare.annotation.JsonObject;
*/
@JsonObject
public abstract class TabExtras implements Parcelable {
@CallSuper
public void copyToBundle(Bundle bundle) {
}
}

View File

@ -71,6 +71,7 @@ public class ParcelableMediaUtils {
media.start = entity.getStart();
media.end = entity.getEnd();
media.type = ParcelableMediaUtils.getTypeInt(entity.getType());
media.alt_text = entity.getAltText();
final MediaEntity.Size size = entity.getSizes().get(MediaEntity.Size.LARGE);
if (size != null) {
media.width = size.getWidth();

View File

@ -1,5 +1,7 @@
package org.mariotaku.twidere.model.util;
import android.text.TextUtils;
import org.mariotaku.twidere.api.twitter.model.User;
import org.mariotaku.twidere.api.twitter.model.UserList;
import org.mariotaku.twidere.model.ParcelableUserList;
@ -42,4 +44,20 @@ public class ParcelableUserListUtils {
}
return result;
}
public static boolean check(ParcelableUserList userList, UserKey accountKey, String listId,
UserKey userKey, String screenName, String listName) {
if (!userList.account_key.equals(accountKey)) return false;
if (listId != null) {
return TextUtils.equals(listId, userList.id);
} else if (listName != null) {
if (!TextUtils.equals(listName, userList.name)) return false;
if (userKey != null) {
return userKey.equals(userList.user_key);
} else if (screenName != null) {
return TextUtils.equals(screenName, userList.user_screen_name);
}
}
return false;
}
}

View File

@ -19,42 +19,47 @@
package org.mariotaku.twidere.preference;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnClickListener;
import android.os.AsyncTask;
import android.support.annotation.Nullable;
import android.support.v4.util.LongSparseArray;
import android.support.v4.util.SimpleArrayMap;
import android.support.v7.app.AlertDialog;
import android.support.v7.preference.Preference;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.BaseExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.TextView;
import org.mariotaku.twidere.BuildConfig;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.api.twitter.Twitter;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.model.Location;
import org.mariotaku.twidere.api.twitter.model.ResponseList;
import org.mariotaku.twidere.util.TwitterAPIFactory;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
public class TrendsLocationPreference extends Preference implements Constants, OnClickListener {
private int mCheckedWoeId = 1;
public class TrendsLocationPreference extends Preference implements Constants {
private static final long EMPTY = 0;
private static final long WORLDWIDE = 1;
private final ExpandableTrendLocationsListAdapter mAdapter;
private GetAvailableTrendsTask mGetAvailableTrendsTask;
private final AvailableTrendsAdapter mAdapter;
private AlertDialog mDialog;
public TrendsLocationPreference(final Context context) {
@ -67,23 +72,11 @@ public class TrendsLocationPreference extends Preference implements Constants, O
public TrendsLocationPreference(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
mAdapter = new AvailableTrendsAdapter(context);
}
@Override
public void onClick(final DialogInterface dialog, final int which) {
final Location item = mAdapter.getItem(which);
if (item != null) {
persistInt(item.getWoeid());
}
if (mDialog != null && mDialog.isShowing()) {
mDialog.dismiss();
}
mAdapter = new ExpandableTrendLocationsListAdapter(context);
}
@Override
protected void onClick() {
mCheckedWoeId = getPersistedInt(1);
if (mGetAvailableTrendsTask != null) {
mGetAvailableTrendsTask.cancel(false);
}
@ -91,64 +84,178 @@ public class TrendsLocationPreference extends Preference implements Constants, O
mGetAvailableTrendsTask.execute();
}
private static class AvailableTrendsAdapter extends ArrayAdapter<Location> {
static class ExpandableTrendLocationsListAdapter extends BaseExpandableListAdapter {
private final Context mContext;
private final LayoutInflater mInflater;
@Nullable
SimpleArrayMap<Location, List<Location>> mData;
public AvailableTrendsAdapter(final Context context) {
super(context, android.R.layout.simple_list_item_single_choice);
mContext = context;
}
public int findItemPosition(final int woeid) {
final int count = getCount();
for (int i = 0; i < count; i++) {
final Location item = getItem(i);
if (item.getWoeid() == woeid) return i;
}
return -1;
public ExpandableTrendLocationsListAdapter(Context context) {
mInflater = LayoutInflater.from(context);
}
@Override
public View getView(final int position, final View convertView, final ViewGroup parent) {
final View view = super.getView(position, convertView, parent);
final TextView text = (TextView) (view instanceof TextView ? view : view.findViewById(android.R.id.text1));
final Location item = getItem(position);
if (item != null && text != null) {
text.setSingleLine();
text.setText(item.getName());
public int getGroupCount() {
if (mData == null) return 0;
return mData.size();
}
@Override
public int getChildrenCount(int groupPosition) {
if (mData == null) return 0;
return mData.valueAt(groupPosition).size();
}
@Override
public Location getGroup(int groupPosition) {
assert mData != null;
return mData.keyAt(groupPosition);
}
@Override
public Location getChild(int groupPosition, int childPosition) {
assert mData != null;
return mData.valueAt(groupPosition).get(childPosition);
}
@Override
public long getGroupId(int groupPosition) {
return getGroup(groupPosition).getWoeid();
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return getChild(groupPosition, childPosition).getWoeid();
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
View view;
if (convertView != null) {
view = convertView;
} else {
view = mInflater.inflate(android.R.layout.simple_expandable_list_item_1, parent, false);
}
((TextView) view.findViewById(android.R.id.text1)).setText(getGroup(groupPosition).getName());
return view;
}
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
View view;
if (convertView != null) {
view = convertView;
} else {
view = mInflater.inflate(android.R.layout.simple_list_item_1, parent, false);
}
final Location location = getChild(groupPosition, childPosition);
final TextView text1 = (TextView) view.findViewById(android.R.id.text1);
if (location.getParentId() == 1) {
text1.setText(R.string.location_countrywide);
} else {
text1.setText(location.getName());
}
return view;
}
public void setData(final List<Location> data) {
clear();
if (data != null) {
addAll(data);
}
sort(new LocationComparator(mContext));
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
public void setData(@Nullable SimpleArrayMap<Location, List<Location>> data) {
mData = data;
notifyDataSetChanged();
}
}
static class LocationsMap {
final LongSparseArray<List<Location>> map = new LongSparseArray<>();
final LongSparseArray<Location> parents = new LongSparseArray<>();
private final LocationComparator comparator;
LocationsMap(Locale locale) {
comparator = new LocationComparator(Collator.getInstance(locale));
}
void put(Location location) {
final long parentId = location.getParentId();
if (parentId == EMPTY || parentId == WORLDWIDE) {
putParent(location);
} else {
putChild(parentId, location);
}
}
void putParent(Location location) {
final long woeid = location.getWoeid();
parents.put(woeid, location);
final List<Location> list = getList(woeid);
// Don't add child for 'worldwide'
if (woeid != WORLDWIDE) {
addToList(list, location);
}
}
void putChild(long parentId, Location location) {
addToList(getList(parentId), location);
}
List<Location> getList(long parentId) {
List<Location> list = map.get(parentId);
if (list == null) {
list = new ArrayList<>();
map.put(parentId, list);
}
return list;
}
void addToList(List<Location> list, Location location) {
int loc = Collections.binarySearch(list, location, comparator);
if (loc < 0) {
list.add(-(loc + 1), location);
}
}
SimpleArrayMap<Location, List<Location>> pack() {
SimpleArrayMap<Location, List<Location>> result = new SimpleArrayMap<>(map.size());
for (int i = 0, j = map.size(); i < j; i++) {
Location parent = parents.get(map.keyAt(i));
if (parent == null) continue;
result.put(parent, map.valueAt(i));
}
return result;
}
}
private static class LocationComparator implements Comparator<Location> {
private final Collator mCollator;
private final Collator collator;
LocationComparator(final Context context) {
mCollator = Collator.getInstance(context.getResources().getConfiguration().locale);
public LocationComparator(Collator collator) {
this.collator = collator;
}
private boolean isCountryOrWorldwide(Location location) {
final long parentId = location.getParentId();
return parentId == 0 || parentId == 1;
}
@Override
public int compare(final Location object1, final Location object2) {
if (object1.getWoeid() == 1) return Integer.MIN_VALUE;
if (object2.getWoeid() == 1) return Integer.MAX_VALUE;
return mCollator.compare(object1.getName(), object2.getName());
public int compare(Location lhs, Location rhs) {
if (isCountryOrWorldwide(lhs)) return Integer.MIN_VALUE;
if (isCountryOrWorldwide(rhs)) return Integer.MAX_VALUE;
return collator.compare(lhs.getName(), rhs.getName());
}
}
class GetAvailableTrendsTask extends AsyncTask<Object, Object, ResponseList<Location>> implements OnCancelListener {
class GetAvailableTrendsTask extends AsyncTask<Object, Object, SimpleArrayMap<Location,
List<Location>>> implements OnCancelListener {
private final ProgressDialog mProgress;
public GetAvailableTrendsTask(final Context context) {
@ -161,19 +268,25 @@ public class TrendsLocationPreference extends Preference implements Constants, O
}
@Override
protected ResponseList<Location> doInBackground(final Object... args) {
protected SimpleArrayMap<Location, List<Location>> doInBackground(final Object... args) {
final Twitter twitter = TwitterAPIFactory.getDefaultTwitterInstance(getContext(), false);
if (twitter == null) return null;
try {
return twitter.getAvailableTrends();
LocationsMap map = new LocationsMap(Locale.getDefault());
for (Location location : twitter.getAvailableTrends()) {
map.put(location);
}
return map.pack();
} catch (final TwitterException e) {
Log.w(LOGTAG, e);
if (BuildConfig.DEBUG) {
Log.w(LOGTAG, e);
}
}
return null;
}
@Override
protected void onPostExecute(final ResponseList<Location> result) {
protected void onPostExecute(final SimpleArrayMap<Location, List<Location>> result) {
if (mProgress.isShowing()) {
mProgress.dismiss();
}
@ -181,14 +294,38 @@ public class TrendsLocationPreference extends Preference implements Constants, O
if (result == null) return;
final AlertDialog.Builder selectorBuilder = new AlertDialog.Builder(getContext());
selectorBuilder.setTitle(getTitle());
selectorBuilder.setSingleChoiceItems(mAdapter, mAdapter.findItemPosition(mCheckedWoeId),
TrendsLocationPreference.this);
selectorBuilder.setView(R.layout.dialog_trends_location_selector);
selectorBuilder.setNegativeButton(android.R.string.cancel, null);
mDialog = selectorBuilder.create();
final ListView lv = mDialog.getListView();
if (lv != null) {
lv.setFastScrollEnabled(true);
}
mDialog.setOnShowListener(new DialogInterface.OnShowListener() {
@Override
public void onShow(DialogInterface dialogInterface) {
final Dialog dialog = (Dialog) dialogInterface;
final ExpandableListView listView = (ExpandableListView) dialog.findViewById(R.id.expandable_list);
listView.setAdapter(mAdapter);
listView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
@Override
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
final Location group = mAdapter.getGroup(groupPosition);
if (group.getWoeid() == WORLDWIDE) {
persistInt(group.getWoeid());
dialog.dismiss();
return true;
}
return false;
}
});
listView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
final Location child = mAdapter.getChild(groupPosition, childPosition);
persistInt(child.getWoeid());
dialog.dismiss();
return true;
}
});
}
});
mDialog.show();
}

View File

@ -60,6 +60,7 @@ import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.TwitterUpload;
import org.mariotaku.twidere.api.twitter.model.ErrorInfo;
import org.mariotaku.twidere.api.twitter.model.MediaUploadResponse;
import org.mariotaku.twidere.api.twitter.model.NewMediaMetadata;
import org.mariotaku.twidere.api.twitter.model.Status;
import org.mariotaku.twidere.api.twitter.model.StatusUpdate;
import org.mariotaku.twidere.app.TwidereApplication;
@ -758,7 +759,7 @@ public class BackgroundOperationService extends IntentService implements Constan
if (upload == null) {
throw new UpdateStatusException("Twitter instance is null");
}
final long[] mediaIds = new long[statusUpdate.media.length];
final String[] mediaIds = new String[statusUpdate.media.length];
for (int i = 0, j = mediaIds.length; i < j; i++) {
final ParcelableMediaUpdate media = statusUpdate.media[i];
@ -767,6 +768,10 @@ public class BackgroundOperationService extends IntentService implements Constan
try {
body = getBodyFromMedia(resolver, builder, media, statusUpdate);
uploadResp = upload.uploadMedia(body);
if (!TextUtils.isEmpty(media.alt_text)) {
upload.createMetadata(new NewMediaMetadata(uploadResp.getId(),
media.alt_text));
}
} finally {
Utils.closeSilently(body);
}

View File

@ -75,6 +75,7 @@ import org.mariotaku.twidere.model.message.StatusListChangedEvent;
import org.mariotaku.twidere.model.message.StatusRetweetedEvent;
import org.mariotaku.twidere.model.message.UserListCreatedEvent;
import org.mariotaku.twidere.model.message.UserListDestroyedEvent;
import org.mariotaku.twidere.model.message.UserListMembersChangedEvent;
import org.mariotaku.twidere.model.message.UserListSubscriptionEvent;
import org.mariotaku.twidere.model.message.UserListUpdatedEvent;
import org.mariotaku.twidere.model.message.UsersBlockedEvent;
@ -158,7 +159,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
}
}
public int addUserListMembersAsync(final UserKey accountKey, final long listId, final ParcelableUser... users) {
public int addUserListMembersAsync(final UserKey accountKey, final String listId, @NonNull final ParcelableUser... users) {
final AddUserListMembersTask task = new AddUserListMembersTask(accountKey, listId, users);
return mAsyncTaskManager.add(task, true);
}
@ -225,12 +226,12 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
return mAsyncTaskManager.add(task, true);
}
public int createUserListSubscriptionAsync(final UserKey accountKey, final long listId) {
public int createUserListSubscriptionAsync(final UserKey accountKey, final String listId) {
final CreateUserListSubscriptionTask task = new CreateUserListSubscriptionTask(accountKey, listId);
return mAsyncTaskManager.add(task, true);
}
public int deleteUserListMembersAsync(final UserKey accountKey, final long listId, final ParcelableUser... users) {
public int deleteUserListMembersAsync(final UserKey accountKey, final String listId, final ParcelableUser... users) {
final DeleteUserListMembersTask task = new DeleteUserListMembersTask(accountKey, listId, users);
return mAsyncTaskManager.add(task, true);
}
@ -284,12 +285,12 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
return mAsyncTaskManager.add(task, true);
}
public int destroyUserListAsync(final UserKey accountKey, final long listId) {
public int destroyUserListAsync(final UserKey accountKey, final String listId) {
final DestroyUserListTask task = new DestroyUserListTask(mContext, accountKey, listId);
return mAsyncTaskManager.add(task, true);
}
public int destroyUserListSubscriptionAsync(final UserKey accountKey, final long listId) {
public int destroyUserListSubscriptionAsync(final UserKey accountKey, final String listId) {
final DestroyUserListSubscriptionTask task = new DestroyUserListSubscriptionTask(accountKey, listId);
return mAsyncTaskManager.add(task, true);
}
@ -470,7 +471,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
return 0;
}
public int updateUserListDetails(final UserKey accountKey, final long listId,
public int updateUserListDetails(final UserKey accountKey, final String listId,
final UserListUpdate update) {
final UpdateUserListDetailsTask task = new UpdateUserListDetailsTask(mContext, accountKey,
listId, update);
@ -602,26 +603,29 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
class AddUserListMembersTask extends ManagedAsyncTask<Object, Object, SingleResponse<ParcelableUserList>> {
private final UserKey mAccountKey;
private final long listId;
private final ParcelableUser[] users;
private final String mListId;
@NonNull
private final ParcelableUser[] mUsers;
public AddUserListMembersTask(final UserKey accountKey, final long listId, final ParcelableUser[] users) {
public AddUserListMembersTask(@NonNull final UserKey accountKey,
final String listId,
@NonNull final ParcelableUser[] users) {
super(mContext);
this.mAccountKey = accountKey;
this.listId = listId;
this.users = users;
this.mListId = listId;
this.mUsers = users;
}
@Override
protected SingleResponse<ParcelableUserList> doInBackground(final Object... params) {
final Twitter twitter = TwitterAPIFactory.getTwitterInstance(mContext, mAccountKey, false);
if (twitter == null || users == null) return SingleResponse.getInstance();
if (twitter == null) return SingleResponse.getInstance();
try {
final UserKey[] userIds = new UserKey[users.length];
for (int i = 0, j = users.length; i < j; i++) {
userIds[i] = users[i].key;
final UserKey[] userIds = new UserKey[mUsers.length];
for (int i = 0, j = mUsers.length; i < j; i++) {
userIds[i] = mUsers[i].key;
}
final UserList result = twitter.addUserListMembers(listId, UserKey.getIds(userIds));
final UserList result = twitter.addUserListMembers(mListId, UserKey.getIds(userIds));
final ParcelableUserList list = ParcelableUserListUtils.from(result, mAccountKey);
return SingleResponse.getInstance(list, null);
} catch (final TwitterException e) {
@ -631,28 +635,26 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
@Override
protected void onPostExecute(final SingleResponse<ParcelableUserList> result) {
final boolean succeed = result.hasData() && result.getData().id > 0;
final boolean succeed = result.hasData();
if (succeed) {
final String message;
if (users.length == 1) {
final ParcelableUser user = users[0];
if (mUsers.length == 1) {
final ParcelableUser user = mUsers[0];
final boolean nameFirst = mPreferences.getBoolean(KEY_NAME_FIRST);
final String displayName = mUserColorNameManager.getDisplayName(user.key, user.name,
user.screen_name, nameFirst);
message = mContext.getString(R.string.added_user_to_list, displayName, result.getData().name);
} else {
final Resources res = mContext.getResources();
message = res.getQuantityString(R.plurals.added_N_users_to_list, users.length, users.length,
message = res.getQuantityString(R.plurals.added_N_users_to_list, mUsers.length, mUsers.length,
result.getData().name);
}
Utils.showOkMessage(mContext, message, false);
} else {
Utils.showErrorMessage(mContext, R.string.action_adding_member, result.getException(), true);
}
final Intent intent = new Intent(BROADCAST_USER_LIST_MEMBERS_ADDED);
intent.putExtra(EXTRA_USER_LIST, result.getData());
intent.putExtra(EXTRA_USERS, users);
mContext.sendBroadcast(intent);
bus.post(new UserListMembersChangedEvent(UserListMembersChangedEvent.Action.ADDED,
result.getData(), mUsers));
super.onPostExecute(result);
}
@ -887,12 +889,12 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
class CreateUserListSubscriptionTask extends ManagedAsyncTask<Object, Object, SingleResponse<ParcelableUserList>> {
private final UserKey mAccountKey;
private final long listId;
private final String mListId;
public CreateUserListSubscriptionTask(final UserKey accountKey, final long listId) {
public CreateUserListSubscriptionTask(final UserKey accountKey, final String listId) {
super(mContext);
this.mAccountKey = accountKey;
this.listId = listId;
this.mListId = listId;
}
@Override
@ -900,7 +902,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
final Twitter twitter = TwitterAPIFactory.getTwitterInstance(mContext, mAccountKey, false);
if (twitter == null) return SingleResponse.getInstance();
try {
final UserList userList = twitter.createUserListSubscription(listId);
final UserList userList = twitter.createUserListSubscription(mListId);
final ParcelableUserList list = ParcelableUserListUtils.from(userList, mAccountKey);
return SingleResponse.getInstance(list);
} catch (final TwitterException e) {
@ -975,10 +977,10 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
class DeleteUserListMembersTask extends ManagedAsyncTask<Object, Object, SingleResponse<ParcelableUserList>> {
private final UserKey mAccountKey;
private final long mUserListId;
private final String mUserListId;
private final ParcelableUser[] users;
public DeleteUserListMembersTask(final UserKey accountKey, final long userListId, final ParcelableUser[] users) {
public DeleteUserListMembersTask(final UserKey accountKey, final String userListId, final ParcelableUser[] users) {
super(mContext);
mAccountKey = accountKey;
mUserListId = userListId;
@ -1004,7 +1006,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
@Override
protected void onPostExecute(final SingleResponse<ParcelableUserList> result) {
final boolean succeed = result.hasData() && result.getData().id > 0;
final boolean succeed = result.hasData();
final String message;
if (succeed) {
if (users.length == 1) {
@ -1019,11 +1021,9 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
message = res.getQuantityString(R.plurals.deleted_N_users_from_list, users.length, users.length,
result.getData().name);
}
bus.post(new UserListMembersChangedEvent(UserListMembersChangedEvent.Action.REMOVED,
result.getData(), users));
Utils.showInfoMessage(mContext, message, false);
final Intent intent = new Intent(BROADCAST_USER_LIST_MEMBERS_DELETED);
intent.putExtra(EXTRA_USER_LIST, result.getData());
intent.putExtra(EXTRA_USERS, users);
mContext.sendBroadcast(intent);
} else {
Utils.showErrorMessage(mContext, R.string.action_deleting, result.getException(), true);
}
@ -1342,9 +1342,9 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
class DestroyUserListSubscriptionTask extends ManagedAsyncTask<Object, Object, SingleResponse<ParcelableUserList>> {
private final UserKey mAccountKey;
private final long mListId;
private final String mListId;
public DestroyUserListSubscriptionTask(@NonNull final UserKey accountKey, final long listId) {
public DestroyUserListSubscriptionTask(@NonNull final UserKey accountKey, final String listId) {
super(mContext);
mAccountKey = accountKey;
mListId = listId;
@ -1383,9 +1383,9 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
static class DestroyUserListTask extends ManagedAsyncTask<Object, Object, SingleResponse<ParcelableUserList>> {
private final UserKey mAccountKey;
private final long mListId;
private final String mListId;
public DestroyUserListTask(Context context, final UserKey accountKey, final long listId) {
public DestroyUserListTask(Context context, final UserKey accountKey, final String listId) {
super(context);
mAccountKey = accountKey;
mListId = listId;
@ -1570,12 +1570,12 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
static class UpdateUserListDetailsTask extends ManagedAsyncTask<Object, Object, SingleResponse<ParcelableUserList>> {
private final UserKey mAccountKey;
private final long listId;
private final String listId;
private final UserListUpdate update;
private Context mContext;
public UpdateUserListDetailsTask(Context context, final UserKey accountKey,
final long listId, UserListUpdate update) {
final String listId, UserListUpdate update) {
super(context);
this.mAccountKey = accountKey;
this.listId = listId;

View File

@ -88,11 +88,11 @@ public class CustomTabUtils implements Constants {
if (BuildConfig.DEBUG) {
CUSTOM_TABS_CONFIGURATION_MAP.put(CustomTabType.DIRECT_MESSAGES, new CustomTabConfiguration(
DirectMessagesFragment.class, R.string.direct_messages, R.drawable.ic_action_message,
MessagesEntriesFragment.class, R.string.direct_messages, R.drawable.ic_action_message,
CustomTabConfiguration.ACCOUNT_OPTIONAL, CustomTabConfiguration.FIELD_TYPE_NONE, 2, false));
} else {
CUSTOM_TABS_CONFIGURATION_MAP.put(CustomTabType.DIRECT_MESSAGES, new CustomTabConfiguration(
MessagesEntriesFragment.class, R.string.direct_messages, R.drawable.ic_action_message,
DirectMessagesFragment.class, R.string.direct_messages, R.drawable.ic_action_message,
CustomTabConfiguration.ACCOUNT_OPTIONAL, CustomTabConfiguration.FIELD_TYPE_NONE, 2, false));
}

View File

@ -480,7 +480,8 @@ public class IntentUtils implements Constants {
}
public static void openUserListDetails(@NonNull final Context context,
@Nullable final UserKey accountKey, final long listId,
@Nullable final UserKey accountKey,
@Nullable final String listId,
@Nullable final UserKey userId,
@Nullable final String screenName, final String listName) {
final Uri.Builder builder = new Uri.Builder();
@ -489,8 +490,8 @@ public class IntentUtils implements Constants {
if (accountKey != null) {
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_KEY, accountKey.toString());
}
if (listId > 0) {
builder.appendQueryParameter(QUERY_PARAM_LIST_ID, String.valueOf(listId));
if (listId != null) {
builder.appendQueryParameter(QUERY_PARAM_LIST_ID, listId);
}
if (userId != null) {
builder.appendQueryParameter(QUERY_PARAM_USER_KEY, userId.toString());
@ -508,7 +509,7 @@ public class IntentUtils implements Constants {
public static void openUserListDetails(@NonNull final Context context,
@NonNull final ParcelableUserList userList) {
final UserKey userKey = userList.user_key;
final long listId = userList.id;
final String listId = userList.id;
final Bundle extras = new Bundle();
extras.putParcelable(EXTRA_USER_LIST, userList);
final Uri.Builder builder = new Uri.Builder();
@ -516,7 +517,7 @@ public class IntentUtils implements Constants {
builder.authority(AUTHORITY_USER_LIST);
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_KEY, userList.account_key.toString());
builder.appendQueryParameter(QUERY_PARAM_USER_KEY, userKey.toString());
builder.appendQueryParameter(QUERY_PARAM_LIST_ID, String.valueOf(listId));
builder.appendQueryParameter(QUERY_PARAM_LIST_ID, listId);
final Intent intent = new Intent(Intent.ACTION_VIEW, builder.build());
intent.setExtrasClassLoader(context.getClassLoader());
intent.putExtras(extras);

View File

@ -4,16 +4,11 @@ import android.os.Bundle;
import android.util.JsonWriter;
import android.util.Log;
import org.json.JSONException;
import org.json.JSONObject;
import org.mariotaku.restfu.RestFuUtils;
import org.mariotaku.twidere.TwidereConstants;
import org.mariotaku.twidere.constant.CompatibilityConstants;
import org.mariotaku.twidere.constant.IntentConstants;
import java.io.IOException;
import java.io.StringWriter;
import java.util.Iterator;
import java.util.Locale;
import java.util.Set;
@ -61,54 +56,6 @@ public class InternalParseUtils {
}
}
public static Bundle jsonToBundle(final String string) {
final Bundle bundle = new Bundle();
if (string == null) return bundle;
try {
final JSONObject json = new JSONObject(string);
final Iterator<?> it = json.keys();
while (it.hasNext()) {
final Object key_obj = it.next();
if (key_obj == null) {
continue;
}
final String key = key_obj.toString();
final Object value = json.get(key);
if (shouldUseString(key)) {
bundle.putString(key, json.optString(key));
} else if (shouldPutLong(key)) {
bundle.putLong(key, json.optLong(key));
} else if (value instanceof Boolean) {
bundle.putBoolean(key, json.optBoolean(key));
} else if (value instanceof Integer) {
bundle.putInt(key, json.optInt(key));
} else if (value instanceof Long) {
bundle.putLong(key, json.optLong(key));
} else if (value instanceof String) {
bundle.putString(key, json.optString(key));
} else {
Log.w(TwidereConstants.LOGTAG, "Unknown type " + value.getClass().getSimpleName() + " in arguments key " + key);
}
}
} catch (final JSONException | ClassCastException e) {
e.printStackTrace();
}
return bundle;
}
private static boolean shouldUseString(final String key) {
switch (key) {
case CompatibilityConstants.EXTRA_ACCOUNT_ID:
case CompatibilityConstants.EXTRA_USER_ID:
return true;
}
return IntentConstants.EXTRA_LIST_ID.equals(key);
}
private static boolean shouldPutLong(final String key) {
return IntentConstants.EXTRA_LIST_ID.equals(key);
}
public static String parsePrettyDecimal(double num, int decimalDigits) {
String result = String.format(Locale.US, "%." + decimalDigits + "f", num);
int dotIdx = result.lastIndexOf('.');

View File

@ -219,8 +219,7 @@ public class MenuUtils implements Constants {
if (translate != null) {
final boolean isOfficialKey = Utils.isOfficialCredentials(context, account);
final SharedPreferencesWrapper prefs = SharedPreferencesWrapper.getInstance(context, SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
final boolean forcePrivateApis = prefs.getBoolean(SharedPreferenceConstants.KEY_FORCE_USING_PRIVATE_APIS, false);
setMenuItemAvailability(menu, R.id.translate, forcePrivateApis || isOfficialKey);
setMenuItemAvailability(menu, R.id.translate, isOfficialKey);
}
menu.removeGroup(Constants.MENU_GROUP_STATUS_EXTENSION);
Utils.addIntentToMenuForExtension(context, menu, Constants.MENU_GROUP_STATUS_EXTENSION, IntentConstants.INTENT_ACTION_EXTENSION_OPEN_STATUS,

View File

@ -122,7 +122,7 @@ public class OnLinkClickHandler implements OnLinkClickListener, Constants {
if (mentionList.length != 2) {
break;
}
IntentUtils.openUserListDetails(context, accountKey, -1, null, mentionList[0],
IntentUtils.openUserListDetails(context, accountKey, null, null, mentionList[0],
mentionList[1]);
break;
}

View File

@ -34,6 +34,7 @@ import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.support.v4.graphics.ColorUtils;
import android.support.v7.app.AppCompatDelegate;
import android.support.v7.view.menu.ActionMenuItemView;
import android.support.v7.widget.ActionMenuView;
@ -50,12 +51,13 @@ import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;
import com.afollestad.appthemeengine.util.ATEUtil;
import com.afollestad.appthemeengine.Config;
import org.apache.commons.lang3.ArrayUtils;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.graphic.ActionIconDrawable;
import org.mariotaku.twidere.graphic.WindowBackgroundDrawable;
import org.mariotaku.twidere.graphic.iface.DoNotWrapDrawable;
import org.mariotaku.twidere.preference.ThemeBackgroundPreference;
import org.mariotaku.twidere.util.menu.TwidereMenuInfo;
@ -108,7 +110,7 @@ public class ThemeUtils implements Constants {
} else if (VALUE_THEME_BACKGROUND_SOLID.equals(option)) {
window.setBackgroundDrawable(new ColorDrawable(isLightTheme(context) ? Color.WHITE : Color.BLACK));
} else {
window.setBackgroundDrawable(getWindowBackgroundFromTheme(context));
window.setBackgroundDrawable(getWindowBackground(context));
}
}
@ -302,7 +304,7 @@ public class ThemeUtils implements Constants {
return Typeface.create(Typeface.DEFAULT, fontStyle);
}
public static Drawable getWindowBackgroundFromTheme(final Context context) {
public static Drawable getWindowBackground(final Context context) {
final TypedArray a = context.obtainStyledAttributes(new int[]{android.R.attr.windowBackground});
try {
return a.getDrawable(0);
@ -311,13 +313,27 @@ public class ThemeUtils implements Constants {
}
}
public static int getColorBackground(final Context context) {
final TypedArray a = context.obtainStyledAttributes(new int[]{android.R.attr.colorBackground});
try {
return a.getColor(0, Color.TRANSPARENT);
} finally {
a.recycle();
}
}
public static Drawable getWindowBackgroundFromThemeApplyAlpha(final Context context, final int alpha) {
final Drawable d = getWindowBackgroundFromTheme(context);
if (d == null) return null;
d.mutate();
d.setAlpha(TwidereMathUtils.clamp(alpha, ThemeBackgroundPreference.MIN_ALPHA,
ThemeBackgroundPreference.MAX_ALPHA));
return d;
int backgroundColor;
final Drawable d = getWindowBackground(context);
if (d instanceof ColorDrawable) {
backgroundColor = ((ColorDrawable) d).getColor();
} else {
backgroundColor = getColorBackground(context);
}
backgroundColor &= 0x00FFFFFF;
backgroundColor |= TwidereMathUtils.clamp(alpha, ThemeBackgroundPreference.MIN_ALPHA,
ThemeBackgroundPreference.MAX_ALPHA) << 24;
return new WindowBackgroundDrawable(backgroundColor);
}
public static boolean isLightTheme(final Context context) {
@ -421,7 +437,7 @@ public class ThemeUtils implements Constants {
public static int getActionIconColor(Context context, int backgroundColor) {
final int colorDark = ContextCompat.getColor(context, R.color.action_icon_dark);
final int colorLight = ContextCompat.getColor(context, R.color.action_icon_light);
return ATEUtil.isColorLight(backgroundColor) ? colorDark : colorLight;
return isLightColor(backgroundColor) ? colorDark : colorLight;
}
public static void setLightStatusBar(@NonNull Window window, boolean lightStatusBar) {
@ -581,9 +597,33 @@ public class ThemeUtils implements Constants {
}
public static int getColorDependent(int color) {
final boolean isDark = !ATEUtil.isColorLight(color);
final boolean isDark = !isLightColor(color);
return isDark ? Color.WHITE : Color.BLACK;
}
@Config.LightStatusBarMode
public static int getLightStatusBarMode(int statusBarColor) {
if (isLightColor(statusBarColor)) {
return Config.LIGHT_STATUS_BAR_ON;
}
return Config.LIGHT_STATUS_BAR_OFF;
}
@Config.LightToolbarMode
public static int getLightToolbarMode(int themeColor) {
if (isLightColor(themeColor)) {
return Config.LIGHT_TOOLBAR_ON;
}
return Config.LIGHT_TOOLBAR_OFF;
}
public static boolean isLightColor(int color) {
return ColorUtils.calculateLuminance(color) * 0xFF > ACCENT_COLOR_THRESHOLD;
}
public static int getOptimalAccentColor(int themeColor) {
return getOptimalAccentColor(themeColor, getContrastColor(themeColor, Color.BLACK,
Color.WHITE));
}
}

View File

@ -84,6 +84,7 @@ public class TwitterAPIFactory implements TwidereConstants {
sConstantPoll.put("full_text", "true");
sConstantPoll.put("model_version", "7");
sConstantPoll.put("skip_aggregation", "false");
sConstantPoll.put("include_ext_alt_text", "true");
}
@WorkerThread

View File

@ -640,7 +640,7 @@ public final class Utils implements Constants {
&& isEmpty(paramListId)) {
return null;
}
args.putLong(EXTRA_LIST_ID, NumberUtils.toLong(paramListId, -1));
args.putString(EXTRA_LIST_ID, paramListId);
args.putParcelable(EXTRA_USER_KEY, paramUserKey);
args.putString(EXTRA_SCREEN_NAME, paramScreenName);
args.putString(EXTRA_LIST_NAME, paramListName);
@ -691,7 +691,7 @@ public final class Utils implements Constants {
&& isEmpty(paramListId)) {
return null;
}
args.putLong(EXTRA_LIST_ID, NumberUtils.toLong(paramListId, -1));
args.putString(EXTRA_LIST_ID, paramListId);
args.putParcelable(EXTRA_USER_KEY, paramUserKey);
args.putString(EXTRA_SCREEN_NAME, paramScreenName);
args.putString(EXTRA_LIST_NAME, paramListName);
@ -706,7 +706,7 @@ public final class Utils implements Constants {
if ((isEmpty(paramListName) || isEmpty(paramScreenName) && paramUserKey == null)
&& isEmpty(paramListId))
return null;
args.putLong(EXTRA_LIST_ID, NumberUtils.toLong(paramListId, -1));
args.putString(EXTRA_LIST_ID, paramListId);
args.putParcelable(EXTRA_USER_KEY, paramUserKey);
args.putString(EXTRA_SCREEN_NAME, paramScreenName);
args.putString(EXTRA_LIST_NAME, paramListName);
@ -721,7 +721,7 @@ public final class Utils implements Constants {
if (isEmpty(paramListId)
&& (isEmpty(paramListName) || isEmpty(paramScreenName) && paramUserKey == null))
return null;
args.putLong(EXTRA_LIST_ID, NumberUtils.toLong(paramListId, -1));
args.putString(EXTRA_LIST_ID, paramListId);
args.putParcelable(EXTRA_USER_KEY, paramUserKey);
args.putString(EXTRA_SCREEN_NAME, paramScreenName);
args.putString(EXTRA_LIST_NAME, paramListName);

View File

@ -0,0 +1,27 @@
package org.mariotaku.twidere.util.theme;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.widget.ImageView;
import com.afollestad.appthemeengine.Config;
import com.afollestad.appthemeengine.viewprocessors.ViewProcessor;
import org.mariotaku.twidere.util.ThemeUtils;
/**
* Created by mariotaku on 16/3/30.
*/
public class ImageViewViewProcessor implements ViewProcessor<ImageView, Void> {
@Override
public void process(@NonNull Context context, @Nullable String key, @Nullable ImageView target, @Nullable Void extra) {
if (target == null) return;
switch (target.getId()) {
case android.support.v7.appcompat.R.id.action_mode_close_button: {
target.setColorFilter(ThemeUtils.getColorDependent(Config.toolbarColor(context, key, null)));
break;
}
}
}
}

View File

@ -2,18 +2,17 @@ package org.mariotaku.twidere.util.theme;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v4.widget.SwipeRefreshLayout;
import com.afollestad.appthemeengine.Config;
import com.afollestad.appthemeengine.viewprocessors.ViewProcessor;
import org.mariotaku.twidere.view.ExtendedSwipeRefreshLayout;
/**
* Created by mariotaku on 16/3/18.
*/
public class ExtendedSwipeRefreshLayoutViewProcessor implements ViewProcessor<ExtendedSwipeRefreshLayout, Object> {
public class SwipeRefreshLayoutViewProcessor implements ViewProcessor<SwipeRefreshLayout, Object> {
@Override
public void process(@NonNull Context context, String key, ExtendedSwipeRefreshLayout target, Object extra) {
public void process(@NonNull Context context, String key, SwipeRefreshLayout target, Object extra) {
target.setColorSchemeColors(Config.accentColor(context, key));
}
}

View File

@ -5,9 +5,9 @@ import android.graphics.Color;
import android.support.annotation.NonNull;
import com.afollestad.appthemeengine.Config;
import com.afollestad.appthemeengine.util.ATEUtil;
import com.afollestad.appthemeengine.viewprocessors.ViewProcessor;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.view.TabPagerIndicator;
/**
@ -17,7 +17,7 @@ public class TabPagerIndicatorViewProcessor implements ViewProcessor<TabPagerInd
@Override
public void process(@NonNull Context context, String key, TabPagerIndicator target, Object extra) {
final int primaryColor = Config.primaryColor(context, key);
final boolean isDark = !ATEUtil.isColorLight(primaryColor);
final boolean isDark = !ThemeUtils.isLightColor(primaryColor);
final int primaryColorDependent = isDark ? Color.WHITE : Color.BLACK;
target.setIconColor(primaryColorDependent);
target.setLabelColor(primaryColorDependent);

View File

@ -0,0 +1,72 @@
package org.mariotaku.twidere.util.theme;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.Editable;
import android.text.TextWatcher;
import android.widget.TextView;
import com.afollestad.appthemeengine.Config;
import com.afollestad.appthemeengine.viewprocessors.ViewProcessor;
import org.mariotaku.twidere.Constants;
/**
* Created by mariotaku on 16/3/30.
*/
public class TextViewViewProcessor implements ViewProcessor<TextView, Void>, Constants {
@Override
public void process(@NonNull final Context context, @Nullable final String key,
@Nullable final TextView target, @Nullable Void extra) {
if (target == null) return;
switch (target.getId()) {
case android.support.v7.appcompat.R.id.action_bar_title: {
if (VALUE_THEME_NAME_DARK.equals(key)) return;
target.addTextChangedListener(new SimpleTextWatcher() {
@Override
public void afterTextChanged(Editable s) {
if (Config.isLightToolbar(context, null, key, Config.toolbarColor(context, key, null))) {
target.setTextColor(Config.textColorPrimary(context, key));
} else {
target.setTextColor(Config.textColorPrimaryInverse(context, key));
}
}
});
break;
}
case android.support.v7.appcompat.R.id.action_bar_subtitle: {
if (VALUE_THEME_NAME_DARK.equals(key)) return;
target.addTextChangedListener(new SimpleTextWatcher() {
@Override
public void afterTextChanged(Editable s) {
if (Config.isLightToolbar(context, null, key, Config.toolbarColor(context, key, null))) {
target.setTextColor(Config.textColorSecondary(context, key));
} else {
target.setTextColor(Config.textColorSecondaryInverse(context, key));
}
}
});
break;
}
}
}
abstract static class SimpleTextWatcher implements TextWatcher {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
}
}
}

View File

@ -46,6 +46,7 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
/**
* Dynamic layout for media preview
* Created by mariotaku on 14/12/17.
*/
public class CardMediaContainer extends ViewGroup implements Constants {
@ -140,6 +141,11 @@ public class CardMediaContainer extends ViewGroup implements Constants {
if (imageView instanceof MediaPreviewImageView) {
((MediaPreviewImageView) imageView).setHasPlayIcon(ParcelableMediaUtils.hasPlayIcon(media.type));
}
if (TextUtils.isEmpty(media.alt_text)) {
child.setContentDescription(getContext().getString(R.string.media));
} else {
child.setContentDescription(media.alt_text);
}
child.setTag(media);
child.setVisibility(VISIBLE);
if (i == j - 1) {

View File

@ -91,7 +91,7 @@ public class ExtendedRecyclerView extends RecyclerView {
} else {
hScroll = 0f;
}
if ((vScroll != 0 || hScroll != 0)) {
if (vScroll != 0 || hScroll != 0) {
final float scrollFactor = getScrollFactorBackport();
float horizontalDirection = mMouseScrollDirectionDecider.getHorizontalDirection();
float verticalDirection = mMouseScrollDirectionDecider.getVerticalDirection();

View File

@ -76,7 +76,8 @@
android:layout_weight="0"
android:background="?actionBarItemBackground"
android:color="?menuIconColor"
android:src="@drawable/ic_action_search"/>
android:src="@drawable/ic_action_search"
tools:tint="?menuIconColor"/>
</LinearLayout>

View File

@ -94,15 +94,17 @@
android:ems="10"
android:singleLine="true"/>
<ImageButton
<org.mariotaku.twidere.view.IconActionButton
android:id="@+id/screen_name_confirm"
android:layout_width="@dimen/minimum_element_size"
android:layout_height="@dimen/minimum_element_size"
android:layout_weight="0"
android:background="?selectableItemBackground"
android:color="?menuIconColor"
android:contentDescription="@string/search"
android:onClick="onClick"
android:src="@android:drawable/ic_menu_search"/>
android:src="@drawable/ic_action_search"
tools:tint="?menuIconColor"/>
</LinearLayout>
</LinearLayout>

View File

@ -33,7 +33,8 @@
android:layout_alignTop="@+id/profile_images_container"
android:padding="@dimen/element_spacing_small"
android:scaleType="centerInside"
tools:src="@drawable/ic_indicator_retweet"/>
tools:src="@drawable/ic_indicator_retweet"
tools:tint="@color/highlight_retweet"/>
<Space
android:id="@+id/profile_image_space"
@ -62,7 +63,8 @@
android:layout_width="@dimen/profile_image_size_activity_small"
android:layout_height="@dimen/profile_image_size_activity_small"
android:layout_margin="2dp"
android:contentDescription="@string/profile_image"/>
android:contentDescription="@string/profile_image"
tools:src="@mipmap/ic_launcher"/>
<org.mariotaku.twidere.view.ProfileImageView
android:id="@+id/activity_profile_image_1"
@ -70,7 +72,8 @@
android:layout_width="@dimen/profile_image_size_activity_small"
android:layout_height="@dimen/profile_image_size_activity_small"
android:layout_margin="2dp"
android:contentDescription="@string/profile_image"/>
android:contentDescription="@string/profile_image"
tools:src="@mipmap/ic_launcher_hondajojo"/>
<org.mariotaku.twidere.view.ProfileImageView
android:id="@+id/activity_profile_image_2"
@ -78,7 +81,8 @@
android:layout_width="@dimen/profile_image_size_activity_small"
android:layout_height="@dimen/profile_image_size_activity_small"
android:layout_margin="2dp"
android:contentDescription="@string/profile_image"/>
android:contentDescription="@string/profile_image"
tools:src="@mipmap/ic_launcher"/>
<org.mariotaku.twidere.view.ProfileImageView
android:id="@+id/activity_profile_image_3"
@ -86,7 +90,8 @@
android:layout_width="@dimen/profile_image_size_activity_small"
android:layout_height="@dimen/profile_image_size_activity_small"
android:layout_margin="2dp"
android:contentDescription="@string/profile_image"/>
android:contentDescription="@string/profile_image"
tools:src="@mipmap/ic_launcher_hondajojo"/>
<org.mariotaku.twidere.view.ProfileImageView
android:id="@+id/activity_profile_image_4"
@ -94,7 +99,8 @@
android:layout_width="@dimen/profile_image_size_activity_small"
android:layout_height="@dimen/profile_image_size_activity_small"
android:layout_margin="2dp"
android:contentDescription="@string/profile_image"/>
android:contentDescription="@string/profile_image"
tools:src="@mipmap/ic_launcher"/>
<org.mariotaku.twidere.view.BadgeView
android:id="@+id/activity_profile_image_more_number"
@ -104,6 +110,7 @@
android:layout_margin="2dp"
android:gravity="center"
android:textColor="?android:attr/textColorPrimary"
tools:src="@mipmap/ic_launcher_hondajojo"
tools:text="11"/>
</LinearLayout>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ExpandableListView
android:id="@+id/expandable_list"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>

View File

@ -3,7 +3,7 @@
<item
android:id="@id/delete_from_list"
android:icon="@android:drawable/ic_menu_delete"
android:icon="@drawable/ic_action_delete"
android:title="@string/delete"/>
</menu>

View File

@ -785,4 +785,5 @@
<!-- GNU social group like https://quitter.se/group/qvitter -->
<string name="group">Group</string>
<string name="your_coarse_location">Your coarse location</string>
<string name="location_countrywide">Countrywide</string>
</resources>