diff --git a/build.gradle b/build.gradle index 4b8510dd3..fcfd20002 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ buildscript { maven { url 'https://plugins.gradle.org/m2/' } } dependencies { - classpath 'com.github.ben-manes:gradle-versions-plugin:0.12.0' + classpath 'com.github.ben-manes:gradle-versions-plugin:0.13.0' classpath 'com.android.tools.build:gradle:2.1.3' classpath 'com.google.gms:google-services:3.0.0' classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' diff --git a/twidere.component.common/build.gradle b/twidere.component.common/build.gradle index 046653798..ff680eb00 100644 --- a/twidere.component.common/build.gradle +++ b/twidere.component.common/build.gradle @@ -41,8 +41,8 @@ dependencies { apt 'com.github.mariotaku.ObjectCursor:processor:0.9.9' compile 'com.android.support:support-annotations:24.2.0' compile 'com.bluelinelabs:logansquare:1.3.7' - compile 'com.github.mariotaku.RestFu:library:0.9.32' - compile 'com.github.mariotaku.RestFu:oauth:0.9.32' + compile 'com.github.mariotaku.RestFu:library:0.9.33' + compile 'com.github.mariotaku.RestFu:oauth:0.9.33' compile 'com.hannesdorfmann.parcelableplease:annotation:1.0.2' compile 'com.github.mariotaku.ObjectCursor:core:0.9.9' compile 'com.github.mariotaku.CommonsLibrary:objectcursor:0.9.8' diff --git a/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/api/FriendsFollowersResources.java b/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/api/FriendsFollowersResources.java index c5ede861a..0efa56f6f 100644 --- a/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/api/FriendsFollowersResources.java +++ b/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/api/FriendsFollowersResources.java @@ -19,13 +19,6 @@ package org.mariotaku.microblog.library.twitter.api; -import org.mariotaku.restfu.annotation.method.GET; -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.Queries; -import org.mariotaku.restfu.annotation.param.Query; -import org.mariotaku.restfu.http.BodyType; import org.mariotaku.microblog.library.MicroBlogException; import org.mariotaku.microblog.library.twitter.model.Friendship; import org.mariotaku.microblog.library.twitter.model.FriendshipUpdate; @@ -35,6 +28,14 @@ import org.mariotaku.microblog.library.twitter.model.Paging; import org.mariotaku.microblog.library.twitter.model.Relationship; import org.mariotaku.microblog.library.twitter.model.ResponseList; import org.mariotaku.microblog.library.twitter.model.User; +import org.mariotaku.microblog.library.twitter.template.UserAnnotationTemplate; +import org.mariotaku.restfu.annotation.method.GET; +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.Queries; +import org.mariotaku.restfu.annotation.param.Query; +import org.mariotaku.restfu.http.BodyType; @SuppressWarnings("RedundantThrows") @Queries({@KeyValue(key = "include_entities", valueKey = "include_entities")}) @@ -42,26 +43,32 @@ public interface FriendsFollowersResources { @POST("/friendships/create.json") @BodyType(BodyType.FORM) + @Queries(template = UserAnnotationTemplate.class) User createFriendship(@Param("user_id") String userId) throws MicroBlogException; @POST("/friendships/create.json") @BodyType(BodyType.FORM) + @Queries(template = UserAnnotationTemplate.class) User createFriendship(@Param("user_id") String userId, @Param("follow") boolean follow) throws MicroBlogException; @POST("/friendships/create.json") @BodyType(BodyType.FORM) + @Queries(template = UserAnnotationTemplate.class) User createFriendshipByScreenName(@Param("screen_name") String screenName) throws MicroBlogException; @POST("/friendships/create.json") @BodyType(BodyType.FORM) + @Queries(template = UserAnnotationTemplate.class) User createFriendshipByScreenName(@Param("screen_name") String screenName, @Param("follow") boolean follow) throws MicroBlogException; @POST("/friendships/destroy.json") @BodyType(BodyType.FORM) + @Queries(template = UserAnnotationTemplate.class) User destroyFriendship(@Param("user_id") String userId) throws MicroBlogException; @POST("/friendships/destroy.json") @BodyType(BodyType.FORM) + @Queries(template = UserAnnotationTemplate.class) User destroyFriendshipByScreenName(@Param("screen_name") String screenName) throws MicroBlogException; @GET("/followers/ids.json") diff --git a/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/api/ListResources.java b/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/api/ListResources.java index a0f12f19b..96d3a5061 100644 --- a/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/api/ListResources.java +++ b/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/api/ListResources.java @@ -19,13 +19,6 @@ package org.mariotaku.microblog.library.twitter.api; -import org.mariotaku.microblog.library.twitter.template.StatusAnnotationTemplate; -import org.mariotaku.restfu.annotation.method.GET; -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.Queries; -import org.mariotaku.restfu.annotation.param.Query; import org.mariotaku.microblog.library.MicroBlogException; import org.mariotaku.microblog.library.twitter.model.PageableResponseList; import org.mariotaku.microblog.library.twitter.model.Paging; @@ -34,6 +27,13 @@ import org.mariotaku.microblog.library.twitter.model.Status; import org.mariotaku.microblog.library.twitter.model.User; import org.mariotaku.microblog.library.twitter.model.UserList; import org.mariotaku.microblog.library.twitter.model.UserListUpdate; +import org.mariotaku.microblog.library.twitter.template.StatusAnnotationTemplate; +import org.mariotaku.microblog.library.twitter.template.UserAnnotationTemplate; +import org.mariotaku.restfu.annotation.method.GET; +import org.mariotaku.restfu.annotation.method.POST; +import org.mariotaku.restfu.annotation.param.Param; +import org.mariotaku.restfu.annotation.param.Queries; +import org.mariotaku.restfu.annotation.param.Query; public interface ListResources { @POST("/lists/members/create.json") @@ -73,15 +73,18 @@ public interface ListResources { UserList destroyUserListSubscription(@Param("list_id") String listId) throws MicroBlogException; @GET("/lists/members.json") + @Queries(template = UserAnnotationTemplate.class) PageableResponseList getUserListMembers(@Query("list_id") String listId, @Query Paging paging) throws MicroBlogException; @GET("/lists/members.json") + @Queries(template = UserAnnotationTemplate.class) PageableResponseList getUserListMembers(@Query("slug") String slug, @Query("owner_id") String ownerId, @Query Paging paging) throws MicroBlogException; @GET("/lists/members.json") + @Queries(template = UserAnnotationTemplate.class) PageableResponseList getUserListMembersByScreenName(@Query("slug") String slug, @Query("owner_screen_name") String ownerScreenName, @Query Paging paging) throws MicroBlogException; @@ -130,13 +133,16 @@ public interface ListResources { throws MicroBlogException; @GET("/lists/subscribers.json") + @Queries(template = UserAnnotationTemplate.class) PageableResponseList getUserListSubscribers(@Query("list_id") String listId, @Query Paging paging) throws MicroBlogException; @GET("/lists/subscribers.json") + @Queries(template = UserAnnotationTemplate.class) PageableResponseList getUserListSubscribers(@Query("list_id") String slug, @Query("owner_id") String ownerId, @Query Paging paging) throws MicroBlogException; @GET("/lists/subscribers.json") + @Queries(template = UserAnnotationTemplate.class) PageableResponseList getUserListSubscribersByScreenName(@Query("list_id") String slug, @Query("owner_screen_name") String ownerScreenName, @Query Paging paging) throws MicroBlogException; diff --git a/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/api/UsersResources.java b/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/api/UsersResources.java index bacf66dd6..12ec3af89 100644 --- a/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/api/UsersResources.java +++ b/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/api/UsersResources.java @@ -19,14 +19,6 @@ package org.mariotaku.microblog.library.twitter.api; -import org.mariotaku.restfu.annotation.method.GET; -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.Queries; -import org.mariotaku.restfu.annotation.param.Query; -import org.mariotaku.restfu.http.BodyType; -import org.mariotaku.restfu.http.mime.FileBody; import org.mariotaku.microblog.library.MicroBlogException; import org.mariotaku.microblog.library.twitter.model.AccountSettings; import org.mariotaku.microblog.library.twitter.model.Category; @@ -38,11 +30,17 @@ import org.mariotaku.microblog.library.twitter.model.ResponseCode; import org.mariotaku.microblog.library.twitter.model.ResponseList; import org.mariotaku.microblog.library.twitter.model.SettingsUpdate; import org.mariotaku.microblog.library.twitter.model.User; +import org.mariotaku.microblog.library.twitter.template.UserAnnotationTemplate; +import org.mariotaku.restfu.annotation.method.GET; +import org.mariotaku.restfu.annotation.method.POST; +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.restfu.http.mime.FileBody; @SuppressWarnings("RedundantThrows") -@Queries({@KeyValue(key = "include_entities", valueKey = "include_entities"), - @KeyValue(key = "include_cards", valueKey = "include_cards"), - @KeyValue(key = "cards_platform", valueKey = "cards_platform")}) +@Queries(template = UserAnnotationTemplate.class) public interface UsersResources { @POST("/blocks/create.json") diff --git a/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/model/SettingsUpdate.java b/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/model/SettingsUpdate.java index 8d3239253..20bfcde6c 100644 --- a/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/model/SettingsUpdate.java +++ b/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/model/SettingsUpdate.java @@ -70,4 +70,12 @@ public class SettingsUpdate extends SimpleValueMap { put("screen_name", screenName); } + public void setUniversalQualityFiltering(boolean enabled) { + put("universal_quality_filtering", enabled ? "enabled" : "disabled"); + } + + public void setSmartMute(boolean enabled) { + put("smart_mute", enabled ? "enabled" : "disabled"); + } + } diff --git a/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/model/UniversalSearchQuery.java b/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/model/UniversalSearchQuery.java index 6b758cbfb..f7376d694 100644 --- a/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/model/UniversalSearchQuery.java +++ b/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/model/UniversalSearchQuery.java @@ -19,6 +19,9 @@ package org.mariotaku.microblog.library.twitter.model; +import android.support.annotation.StringDef; + +import org.mariotaku.microblog.library.twitter.util.InternalArrayUtil; import org.mariotaku.restfu.http.SimpleValueMap; /** @@ -39,6 +42,49 @@ public class UniversalSearchQuery extends SimpleValueMap { } public void setModules(String[] modules) { - put("modules", modules); + put("modules", InternalArrayUtil.join(modules, ",")); + } + + public void setFilter(@Filter String filter) { + put("filter", filter); + } + + public void setResultType(@ResultType String resultType) { + put("result_type", resultType); + } + + public void setNear(GeoLocation location) { + put("near", location.getLatitude() + "," + location.getLongitude()); + } + + @StringDef({Filter.IMAGES, Filter.VIDEOS, Filter.PERISCOPE, Filter.NEWS}) + public @interface Filter { + String IMAGES = "images"; + String VIDEOS = "videos"; + String PERISCOPE = "periscope"; + String NEWS = "news"; + } + + @StringDef({Module.TWEET, Module.USER_GALLERY, Module.NEWS, Module.MEDIA_GALLERY, + Module.SUGGESTION, Module.EVENT, Module.TWEET_GALLERY, Module.FOLLOWS_TWEET_GALLERY, + Module.NEARBY_TWEET_GALLERY, Module.SUMMARY, Module.EVENT_SUMMARY}) + public @interface Module { + String TWEET = "tweet"; + String USER_GALLERY = "user_gallery"; + String NEWS = "news"; + String MEDIA_GALLERY = "media_gallery"; + String SUGGESTION = "suggestion"; + String EVENT = "event"; + String TWEET_GALLERY = "tweet_gallery"; + String FOLLOWS_TWEET_GALLERY = "follows_tweet_gallery"; + String NEARBY_TWEET_GALLERY = "nearby_tweet_gallery"; + String SUMMARY = "summary"; + String EVENT_SUMMARY = "event_summary"; + } + + @StringDef({ResultType.RECENT, ResultType.FOLLOWS}) + public @interface ResultType { + String RECENT = "recent"; + String FOLLOWS = "follows"; } } diff --git a/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/model/UniversalSearchResult.java b/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/model/UniversalSearchResult.java index 905865cd0..50d8dbede 100644 --- a/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/model/UniversalSearchResult.java +++ b/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/model/UniversalSearchResult.java @@ -19,8 +19,18 @@ package org.mariotaku.microblog.library.twitter.model; +import android.support.annotation.StringDef; + import com.bluelinelabs.logansquare.annotation.JsonField; import com.bluelinelabs.logansquare.annotation.JsonObject; +import com.bluelinelabs.logansquare.typeconverters.TypeConverter; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; /** * Created by mariotaku on 15/10/21. @@ -46,6 +56,21 @@ public class UniversalSearchResult { StatusModule status; @JsonField(name = "user_gallery") UserGalleryModule userGallery; + @JsonField(name = "suggestion") + SuggestionModule suggestion; + + public StatusModule getStatus() { + return status; + } + + public UserGalleryModule getUserGallery() { + return userGallery; + } + + public SuggestionModule getSuggestion() { + return suggestion; + } + } @JsonObject @@ -68,30 +93,34 @@ public class UniversalSearchResult { @JsonField(name = "social_context") SocialContext socialContext; - @JsonField(name = "result_type") - String resultType; - @JsonField(name = "auto_expand") boolean autoExpand; + @JsonField(name = "result_type") + @ModuleMetadata.ResultType + String resultType; + public SocialContext getSocialContext() { return socialContext; } - public String getResultType() { - return resultType; - } - public boolean isAutoExpand() { return autoExpand; } + @ModuleMetadata.ResultType + public final String getResultType() { + return resultType; + } + @JsonObject public static class SocialContext { @JsonField(name = "following") boolean following; @JsonField(name = "followed_by") boolean followedBy; + @JsonField(name = "related_users") + RelatedUsers relatedUsers; public boolean isFollowing() { return following; @@ -100,6 +129,37 @@ public class UniversalSearchResult { public boolean isFollowedBy() { return followedBy; } + + public RelatedUsers getRelatedUsers() { + return relatedUsers; + } + + @JsonObject + public static class RelatedUsers { + + @JsonField(name = "follow_and_follow") + FollowAndFollow followAndFollow; + + @JsonObject + public static class FollowAndFollow { + @JsonField(name = "users") + MiniUser[] users; + @JsonField(name = "num_more_users") + int numMoreUsers; + } + + @JsonObject + public static class MiniUser { + @JsonField(name = "id_string") + String id; + @JsonField(name = "name") + String name; + @JsonField(name = "screen_name") + String screenName; + + } + + } } } } @@ -126,10 +186,100 @@ public class UniversalSearchResult { } } + @JsonObject + public static class SuggestionModule { + @JsonField(name = "metadata") + ModuleMetadata metadata; + @JsonField(name = "data") + SuggestionData data; + + public ModuleMetadata getMetadata() { + return metadata; + } + + public SuggestionData getData() { + return data; + } + + @JsonObject + public static class SuggestionData { + @JsonField(name = "suggestion_type") + String suggestionType; + @JsonField(name = "suggestions") + Suggestion[] suggestions; + + public String getSuggestionType() { + return suggestionType; + } + + public Suggestion[] getSuggestions() { + return suggestions; + } + + @JsonObject + public static class Suggestion { + @JsonField(name = "query") + String query; + + @JsonField(name = "indices", typeConverter = Index.ArrayConverter.class) + Index[] indices; + + public String getQuery() { + return query; + } + + public static class Index { + int start; + int end; + + public static class ArrayConverter implements TypeConverter { + @Override + public Index[] parse(JsonParser jsonParser) throws IOException { + if (jsonParser.getCurrentToken() == null) { + jsonParser.nextToken(); + } + if (jsonParser.getCurrentToken() != JsonToken.START_ARRAY) { + jsonParser.skipChildren(); + return null; + } + List list = new ArrayList<>(); + while (jsonParser.nextToken() != JsonToken.END_ARRAY) { + Index index = new Index(); + index.start = jsonParser.nextIntValue(-1); + index.end = jsonParser.nextIntValue(-1); + list.add(index); + } + return list.toArray(new Index[list.size()]); + } + + @Override + public void serialize(Index[] indices, String fieldName, + boolean writeFieldNameForObject, + JsonGenerator jsonGenerator) throws IOException { + if (writeFieldNameForObject) { + jsonGenerator.writeFieldName(fieldName); + } + if (indices == null) { + jsonGenerator.writeNull(); + } else { + jsonGenerator.writeStartArray(); + for (Index index : indices) { + jsonGenerator.writeNumber(index.start); + jsonGenerator.writeNumber(index.end); + } + jsonGenerator.writeEndArray(); + } + } + } + } + } + } + } + @JsonObject public static class UserModule { @JsonField(name = "metadata") - Object metadata; + ModuleMetadata metadata; @JsonField(name = "data") User data; @@ -141,11 +291,6 @@ public class UniversalSearchResult { return data; } - @JsonObject - public static class Metadata { - @JsonField(name = "result_type") - String resultType; - } } @JsonObject @@ -157,4 +302,23 @@ public class UniversalSearchResult { return cursor; } } + + @JsonObject + public static class ModuleMetadata { + @JsonField(name = "result_type") + @ResultType + String resultType; + + @ResultType + public final String getResultType() { + return resultType; + } + + @StringDef({ResultType.NORMAL, ResultType.TOP}) + public @interface ResultType { + String NORMAL = "normal"; + String TOP = "top"; + } + } + } diff --git a/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/template/StatusAnnotationTemplate.java b/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/template/StatusAnnotationTemplate.java index 3633ce805..d1516d01e 100644 --- a/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/template/StatusAnnotationTemplate.java +++ b/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/template/StatusAnnotationTemplate.java @@ -15,7 +15,9 @@ import org.mariotaku.restfu.annotation.param.Queries; @KeyValue(key = "include_descendent_reply_count", valueKey = "include_descendent_reply_count"), @KeyValue(key = "include_ext_alt_text", valueKey = "include_ext_alt_text"), @KeyValue(key = "tweet_mode", valueKey = "tweet_mode"), - @KeyValue(key = "model_version", valueKey = "model_version") + @KeyValue(key = "model_version", valueKey = "model_version"), + @KeyValue(key = "include_blocking", value = "true"), + @KeyValue(key = "include_blocked_by", value = "true") }) public class StatusAnnotationTemplate { } diff --git a/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/template/UserAnnotationTemplate.java b/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/template/UserAnnotationTemplate.java new file mode 100644 index 000000000..2df84ecff --- /dev/null +++ b/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/template/UserAnnotationTemplate.java @@ -0,0 +1,15 @@ +package org.mariotaku.microblog.library.twitter.template; + +import org.mariotaku.restfu.annotation.param.KeyValue; +import org.mariotaku.restfu.annotation.param.Queries; + +/** + * Created by mariotaku on 16/8/20. + */ +@Queries({@KeyValue(key = "include_entities", valueKey = "include_entities"), + @KeyValue(key = "include_cards", valueKey = "include_cards"), + @KeyValue(key = "cards_platform", valueKey = "cards_platform"), + @KeyValue(key = "include_blocking", value = "true"), + @KeyValue(key = "include_blocked_by", value = "true")}) +public class UserAnnotationTemplate { +} diff --git a/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/util/InternalArrayUtil.java b/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/util/InternalArrayUtil.java new file mode 100644 index 000000000..9c4c9c74b --- /dev/null +++ b/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/util/InternalArrayUtil.java @@ -0,0 +1,19 @@ +package org.mariotaku.microblog.library.twitter.util; + +/** + * Created by mariotaku on 16/8/20. + */ +public class InternalArrayUtil { + + public static String join(Object[] array, String separator) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < array.length; i++) { + if (i != 0) { + sb.append(separator); + } + sb.append(array[i]); + } + return sb.toString(); + } + +} diff --git a/twidere/build.gradle b/twidere/build.gradle index 2d37a326b..2012a47c6 100644 --- a/twidere/build.gradle +++ b/twidere/build.gradle @@ -21,7 +21,7 @@ buildscript { dependencies { // START Non-FOSS component - classpath 'io.fabric.tools:gradle:1.21.5' + classpath 'io.fabric.tools:gradle:1.21.7' // END Non-FOSS component classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" @@ -90,7 +90,7 @@ dependencies { // wearApp project(':twidere.wear') kapt 'com.bluelinelabs:logansquare-compiler:1.3.7' kapt 'com.hannesdorfmann.parcelableplease:processor:1.0.2' - kapt 'com.google.dagger:dagger-compiler:2.1' + kapt 'com.google.dagger:dagger-compiler:2.6' kapt 'com.github.mariotaku.ObjectCursor:processor:0.9.9' compile('com.github.mariotaku:app-theme-engine:1efc6237e1@aar') { @@ -105,11 +105,11 @@ dependencies { googleCompile 'com.google.android.gms:play-services-maps:9.4.0' googleCompile 'com.google.android.gms:play-services-auth:9.4.0' googleCompile 'com.google.maps.android:android-maps-utils:0.4.3' - googleCompile('com.crashlytics.sdk.android:crashlytics:2.5.5@aar') { transitive = true } + googleCompile('com.crashlytics.sdk.android:crashlytics:2.6.2@aar') { transitive = true } googleCompile ':YouTubeAndroidPlayerApi:1.2.2@jar' // END Non-FOSS component - fdroidCompile 'org.osmdroid:osmdroid-android:5.1' + fdroidCompile 'org.osmdroid:osmdroid-android:5.2' debugCompile 'com.facebook.stetho:stetho:1.3.1' debugCompile 'com.facebook.stetho:stetho-okhttp3:1.3.1' @@ -155,13 +155,13 @@ dependencies { compile 'com.github.mariotaku:PickNCrop:0.9.4' compile 'com.github.mariotaku.RestFu:library:0.9.33' compile 'com.github.mariotaku.RestFu:okhttp3:0.9.33' - compile 'com.squareup.okhttp3:okhttp:3.2.0' + compile 'com.squareup.okhttp3:okhttp:3.4.1' compile 'com.lnikkila:extendedtouchview:0.1.0' - compile 'com.google.dagger:dagger:2.1' - compile 'org.attoparser:attoparser:1.4.0.RELEASE' + compile 'com.google.dagger:dagger:2.6' + compile 'org.attoparser:attoparser:2.0.0.RELEASE' compile 'com.github.mariotaku.MediaViewerLibrary:base:0.9.17' compile 'com.github.mariotaku.MediaViewerLibrary:subsample-image-view:0.9.17' - compile 'com.github.mariotaku.SQLiteQB:library:0.9.6' + compile 'com.github.mariotaku.SQLiteQB:library:0.9.7' compile 'com.github.mariotaku.ObjectCursor:core:0.9.9' compile 'com.github.mariotaku:MultiValueSwitch:0.9.7' compile 'com.github.mariotaku:AbstractTask:0.9.4' diff --git a/twidere/src/main/java/org/mariotaku/twidere/activity/BrowserSignInActivity.java b/twidere/src/main/java/org/mariotaku/twidere/activity/BrowserSignInActivity.java index 45ff955a6..c7d8fc13f 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/activity/BrowserSignInActivity.java +++ b/twidere/src/main/java/org/mariotaku/twidere/activity/BrowserSignInActivity.java @@ -36,7 +36,7 @@ import android.webkit.WebSettings; import android.webkit.WebView; import android.widget.Toast; -import org.attoparser.AttoParseException; +import org.attoparser.ParseException; import org.mariotaku.microblog.library.MicroBlogException; import org.mariotaku.microblog.library.twitter.TwitterOAuth; import org.mariotaku.restfu.http.Authorization; @@ -135,7 +135,7 @@ public class BrowserSignInActivity extends BaseActivity { OAuthPasswordAuthenticator.OAuthPinData data = new OAuthPasswordAuthenticator.OAuthPinData(); OAuthPasswordAuthenticator.Companion.readOAuthPINFromHtml(new StringReader(html), data); return data.getOauthPin(); - } catch (final AttoParseException | IOException e) { + } catch (final ParseException | IOException e) { Log.w(LOGTAG, e); } return null; diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/HtmlSpanBuilder.java b/twidere/src/main/java/org/mariotaku/twidere/util/HtmlSpanBuilder.java index fd00290df..ca0a4ec8f 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/util/HtmlSpanBuilder.java +++ b/twidere/src/main/java/org/mariotaku/twidere/util/HtmlSpanBuilder.java @@ -27,12 +27,10 @@ import android.text.style.StyleSpan; import android.text.style.URLSpan; import org.apache.commons.lang3.StringUtils; -import org.attoparser.AttoParseException; -import org.attoparser.IAttoParser; -import org.attoparser.markup.MarkupAttoParser; -import org.attoparser.markup.html.AbstractStandardNonValidatingHtmlAttoHandler; -import org.attoparser.markup.html.HtmlParsingConfiguration; -import org.attoparser.markup.html.elements.IHtmlElement; +import org.attoparser.ParseException; +import org.attoparser.config.ParseConfiguration; +import org.attoparser.simple.AbstractSimpleMarkupHandler; +import org.attoparser.simple.SimpleMarkupParser; import java.util.ArrayList; import java.util.List; @@ -44,18 +42,17 @@ import java.util.Map; */ public class HtmlSpanBuilder { - private static final IAttoParser PARSER = new MarkupAttoParser(); + private static final SimpleMarkupParser PARSER = new SimpleMarkupParser(ParseConfiguration.htmlConfiguration()); private HtmlSpanBuilder() { } - public static Spannable fromHtml(String html) throws ParseException { - final HtmlParsingConfiguration conf = new HtmlParsingConfiguration(); - final HtmlSpanHandler handler = new HtmlSpanHandler(conf); + public static Spannable fromHtml(String html) throws HtmlParseException { + final HtmlSpanHandler handler = new HtmlSpanHandler(); try { PARSER.parse(html, handler); - } catch (AttoParseException e) { - throw new ParseException(e); + } catch (ParseException e) { + throw new HtmlParseException(e); } return handler.getText(); } @@ -63,7 +60,7 @@ public class HtmlSpanBuilder { public static CharSequence fromHtml(String html, CharSequence fallback) { try { return fromHtml(html); - } catch (ParseException e) { + } catch (HtmlParseException e) { return fallback; } } @@ -106,20 +103,20 @@ public class HtmlSpanBuilder { return -1; } - public static class ParseException extends RuntimeException { - public ParseException() { + public static class HtmlParseException extends RuntimeException { + public HtmlParseException() { super(); } - public ParseException(String detailMessage) { + public HtmlParseException(String detailMessage) { super(detailMessage); } - public ParseException(String detailMessage, Throwable throwable) { + public HtmlParseException(String detailMessage, Throwable throwable) { super(detailMessage, throwable); } - public ParseException(Throwable throwable) { + public HtmlParseException(Throwable throwable) { super(throwable); } } @@ -140,23 +137,22 @@ public class HtmlSpanBuilder { } } - static class HtmlSpanHandler extends AbstractStandardNonValidatingHtmlAttoHandler { + static class HtmlSpanHandler extends AbstractSimpleMarkupHandler { private final SpannableStringBuilder sb; List tagInfo; - public HtmlSpanHandler(HtmlParsingConfiguration conf) { - super(conf); + public HtmlSpanHandler() { sb = new SpannableStringBuilder(); tagInfo = new ArrayList<>(); } @Override - public void handleText(char[] buffer, int offset, int len, int line, int col) throws AttoParseException { + public void handleText(char[] buffer, int offset, int len, int line, int col) { sb.append(HtmlEscapeHelper.unescape(new String(buffer, offset, len))); } @Override - public void handleHtmlCloseElement(IHtmlElement element, String elementName, int line, int col) throws AttoParseException { + public void handleCloseElement(String elementName, int line, int col) { final int lastIndex = lastIndexOfTag(tagInfo, elementName); if (lastIndex != -1) { TagInfo info = tagInfo.get(lastIndex); @@ -166,7 +162,7 @@ public class HtmlSpanBuilder { } @Override - public void handleHtmlOpenElement(IHtmlElement element, String elementName, Map attributes, int line, int col) throws AttoParseException { + public void handleOpenElement(String elementName, Map attributes, int line, int col) { tagInfo.add(new TagInfo(sb.length(), elementName, attributes)); } diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/AbsContentRecyclerViewFragment.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/AbsContentRecyclerViewFragment.kt index 91b2dbc33..1e7a11c66 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/AbsContentRecyclerViewFragment.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/AbsContentRecyclerViewFragment.kt @@ -78,8 +78,10 @@ abstract class AbsContentRecyclerViewFragment get() { val args = arguments @@ -197,7 +141,7 @@ abstract class CursorStatusesFragment : AbsStatusesFragment() { reloadStatuses() } } - cr!!.registerContentObserver(Accounts.CONTENT_URI, true, contentObserver!!) + cr.registerContentObserver(Accounts.CONTENT_URI, true, contentObserver!!) cr.registerContentObserver(Filters.CONTENT_URI, true, contentObserver!!) updateRefreshState() reloadStatuses() @@ -215,7 +159,7 @@ abstract class CursorStatusesFragment : AbsStatusesFragment() { } override fun onStop() { - contentResolver?.unregisterContentObserver(contentObserver!!) + contentResolver.unregisterContentObserver(contentObserver!!) super.onStop() } @@ -299,7 +243,6 @@ abstract class CursorStatusesFragment : AbsStatusesFragment() { return DataStoreUtils.getNewestStatusIds(context, contentUri, accountKeys) } - override fun setUserVisibleHint(isVisibleToUser: Boolean) { super.setUserVisibleHint(isVisibleToUser) val context = context @@ -310,6 +253,7 @@ abstract class CursorStatusesFragment : AbsStatusesFragment() { } } + protected fun getOldestStatusIds(accountKeys: Array): Array? { val context = context ?: return null return DataStoreUtils.getOldestStatusIds(context, contentUri, accountKeys) @@ -321,4 +265,60 @@ abstract class CursorStatusesFragment : AbsStatusesFragment() { protected abstract fun updateRefreshState() + protected inner class CursorStatusesBusCallback { + + @Subscribe + fun notifyGetStatusesTaskChanged(event: GetStatusesTaskEvent) { + if (event.uri != contentUri) return + refreshing = event.running + if (!event.running) { + setLoadMoreIndicatorPosition(ILoadMoreSupportAdapter.NONE) + refreshEnabled = true + showContentOrError() + } + } + + + @Subscribe + fun notifyFavoriteTask(event: FavoriteTaskEvent) { + if (event.isSucceeded) { + val status = event.status + val data = adapterData + if (status == null || data == null || data.isEmpty()) return + val adapter = adapter as ParcelableStatusesAdapter + val firstVisiblePosition = layoutManager!!.findFirstVisibleItemPosition() + val lastVisiblePosition = layoutManager!!.findLastVisibleItemPosition() + val startIndex = adapter.statusStartIndex + for (i in firstVisiblePosition..lastVisiblePosition) { + if (status.account_key == adapter.getAccountKey(i) && status.id == adapter.getStatusId(i)) { + if (data is MutableList) { + data[i - startIndex] = status + } + return + } + } + adapter.notifyDataSetChanged() + } + } + + @Subscribe + fun notifyStatusDestroyed(event: StatusDestroyedEvent) { + } + + @Subscribe + fun notifyStatusListChanged(event: StatusListChangedEvent) { + adapter!!.notifyDataSetChanged() + } + + @Subscribe + fun notifyStatusRetweeted(event: StatusRetweetedEvent) { + } + + @Subscribe + fun notifyAccountChanged(event: AccountChangedEvent) { + + } + + } + } diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/DirectMessagesFragment.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/DirectMessagesFragment.kt index e8f1f38f9..800259e06 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/DirectMessagesFragment.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/DirectMessagesFragment.kt @@ -179,10 +179,6 @@ class DirectMessagesFragment : AbsContentListRecyclerViewFragment?, - line: Int, col: Int) { - handleHtmlOpenElement(element, elementName, attributes, line, col) - handleHtmlCloseElement(element, elementName, line, col) + override fun handleStandaloneElement(elementName: String?, attributes: MutableMap?, minimized: Boolean, line: Int, col: Int) { + handleOpenElement(elementName, attributes, line, col) + handleCloseElement(elementName, line, col) } - override fun handleHtmlOpenElement(element: IHtmlElement?, elementName: String?, - attributes: Map?, line: Int, col: Int) { + override fun handleOpenElement(elementName: String?, attributes: MutableMap?, line: Int, col: Int) { when (elementName) { "form" -> { if (attributes != null && "oauth_form" == attributes["id"]) { @@ -181,7 +175,7 @@ class OAuthPasswordAuthenticator( } } - override fun handleHtmlCloseElement(element: IHtmlElement?, elementName: String?, line: Int, col: Int) { + override fun handleCloseElement(elementName: String?, line: Int, col: Int) { if ("form" == elementName) { isOAuthFormOpened = false } @@ -216,19 +210,18 @@ class OAuthPasswordAuthenticator( authorizeResultBuilder.headers(requestHeaders) authorizeResultBuilder.body(authorizationResultBody) response = client.newCall(authorizeResultBuilder.build()).execute() - val conf = HtmlParsingConfiguration() - val handler = object : AbstractStandardNonValidatingHtmlAttoHandler(conf) { + val handler = object : AbstractSimpleMarkupHandler() { internal var isOAuthPinDivOpened: Boolean = false internal var isChallengeFormOpened: Boolean = false - override fun handleHtmlStandaloneElement(element: IHtmlElement?, minimized: Boolean, - elementName: String?, attributes: Map?, - line: Int, col: Int) { - handleHtmlOpenElement(element, elementName, attributes, line, col) - handleHtmlCloseElement(element, elementName, line, col) + override fun handleStandaloneElement(elementName: String?, + attributes: MutableMap?, + minimized: Boolean, line: Int, col: Int) { + handleOpenElement(elementName, attributes, line, col) + handleCloseElement(elementName, line, col) } - override fun handleHtmlCloseElement(element: IHtmlElement?, elementName: String?, line: Int, col: Int) { + override fun handleCloseElement(elementName: String?, line: Int, col: Int) { when (elementName) { "div" -> { isOAuthPinDivOpened = false @@ -239,8 +232,8 @@ class OAuthPasswordAuthenticator( } } - override fun handleHtmlOpenElement(element: IHtmlElement?, elementName: String?, - attributes: Map?, line: Int, col: Int) { + override fun handleOpenElement(elementName: String?, + attributes: Map?, line: Int, col: Int) { when (elementName) { "div" -> { if (attributes != null && "oauth_pin" == attributes["id"]) { @@ -295,7 +288,7 @@ class OAuthPasswordAuthenticator( } } - @Throws(AttoParseException::class) + @Throws(ParseException::class) override fun handleText(buffer: CharArray?, offset: Int, len: Int, line: Int, col: Int) { if (isOAuthPinDivOpened) { val s = String(buffer!!, offset, len) @@ -307,7 +300,7 @@ class OAuthPasswordAuthenticator( } PARSER.parse(SimpleBody.reader(response!!.body), handler) return data - } catch (e: AttoParseException) { + } catch (e: ParseException) { throw AuthenticationException("Malformed HTML", e) } finally { Utils.closeSilently(response) @@ -335,7 +328,7 @@ class OAuthPasswordAuthenticator( throw AuthenticationException() } return data - } catch (e: AttoParseException) { + } catch (e: ParseException) { throw AuthenticationException("Malformed HTML", e) } finally { Utils.closeSilently(response) @@ -458,22 +451,20 @@ class OAuthPasswordAuthenticator( companion object { - private val PARSER = MarkupAttoParser() + private val PARSER = SimpleMarkupParser(ParseConfiguration.htmlConfiguration()) - @Throws(AttoParseException::class, IOException::class) + @Throws(ParseException::class, IOException::class) fun readOAuthPINFromHtml(reader: Reader, data: OAuthPinData) { - val conf = HtmlParsingConfiguration() - val handler = object : AbstractStandardNonValidatingHtmlAttoHandler(conf) { + val handler = object : AbstractSimpleMarkupHandler() { internal var isOAuthPinDivOpened: Boolean = false - - override fun handleHtmlStandaloneElement(element: IHtmlElement?, minimized: Boolean, - elementName: String?, attributes: Map?, - line: Int, col: Int) { - handleHtmlOpenElement(element, elementName, attributes, line, col) - handleHtmlCloseElement(element, elementName, line, col) + override fun handleStandaloneElement(elementName: String?, + attributes: MutableMap?, + minimized: Boolean, line: Int, col: Int) { + handleOpenElement(elementName, attributes, line, col) + handleCloseElement(elementName, line, col) } - override fun handleHtmlOpenElement(element: IHtmlElement?, elementName: String?, attributes: Map?, line: Int, col: Int) { + override fun handleOpenElement(elementName: String?, attributes: Map?, line: Int, col: Int) { when (elementName) { "div" -> { if (attributes != null && "oauth_pin" == attributes["id"]) { @@ -483,7 +474,7 @@ class OAuthPasswordAuthenticator( } } - override fun handleHtmlCloseElement(element: IHtmlElement?, elementName: String?, line: Int, col: Int) { + override fun handleCloseElement(elementName: String?, line: Int, col: Int) { if ("div" == elementName) { isOAuthPinDivOpened = false }