diff --git a/app/src/main/java/org/nuclearfog/twidda/activities/TweetActivity.java b/app/src/main/java/org/nuclearfog/twidda/activities/TweetActivity.java index ea24929c..69e50924 100644 --- a/app/src/main/java/org/nuclearfog/twidda/activities/TweetActivity.java +++ b/app/src/main/java/org/nuclearfog/twidda/activities/TweetActivity.java @@ -552,18 +552,27 @@ public class TweetActivity extends AppCompatActivity implements OnClickListener, } else { sensitive_media.setVisibility(GONE); } - if (tweetUpdate.getMediaType().equals(Tweet.MIME_NONE)) { - mediaButton.setVisibility(GONE); - } else { - mediaButton.setVisibility(VISIBLE); - if (tweetUpdate.getMediaType().equals(Tweet.MIME_PHOTO)) { + AppStyles.setDrawableColor(mediaButton, settings.getIconColor()); + switch(tweetUpdate.getMediaType()) { + case Tweet.MIME_PHOTO: + mediaButton.setVisibility(VISIBLE); mediaButton.setImageResource(R.drawable.image); - } else if (tweetUpdate.getMediaType().equals(Tweet.MIME_VIDEO)) { + break; + + case Tweet.MIME_VIDEO: + mediaButton.setVisibility(VISIBLE); mediaButton.setImageResource(R.drawable.video); - } else { + break; + + case Tweet.MIME_ANGIF: + mediaButton.setVisibility(VISIBLE); mediaButton.setImageResource(R.drawable.gif); - } - AppStyles.setDrawableColor(mediaButton, settings.getIconColor()); + break; + + default: + mediaButton.setVisibility(GONE); + mediaButton.setImageResource(0); + break; } if (settings.imagesEnabled() && !author.getImageUrl().isEmpty()) { String pbLink = author.getImageUrl(); diff --git a/app/src/main/java/org/nuclearfog/twidda/activities/TweetEditor.java b/app/src/main/java/org/nuclearfog/twidda/activities/TweetEditor.java index b81c509e..09733a51 100644 --- a/app/src/main/java/org/nuclearfog/twidda/activities/TweetEditor.java +++ b/app/src/main/java/org/nuclearfog/twidda/activities/TweetEditor.java @@ -311,6 +311,7 @@ public class TweetEditor extends MediaActivity implements OnClickListener, OnPro * called after sending tweet */ public void onSuccess() { + loadingCircle.dismiss(); Toast.makeText(this, R.string.info_tweet_sent, LENGTH_LONG).show(); finish(); } diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/TweetLoader.java b/app/src/main/java/org/nuclearfog/twidda/backend/TweetLoader.java index c157e9ad..899513a6 100644 --- a/app/src/main/java/org/nuclearfog/twidda/backend/TweetLoader.java +++ b/app/src/main/java/org/nuclearfog/twidda/backend/TweetLoader.java @@ -4,8 +4,11 @@ import android.os.AsyncTask; import androidx.annotation.Nullable; +import org.nuclearfog.twidda.backend.api.Twitter; +import org.nuclearfog.twidda.backend.api.TwitterException; import org.nuclearfog.twidda.backend.apiold.EngineException; import org.nuclearfog.twidda.backend.apiold.TwitterEngine; +import org.nuclearfog.twidda.backend.utils.ErrorHandler.TwitterError; import org.nuclearfog.twidda.model.Tweet; import org.nuclearfog.twidda.database.AppDatabase; import org.nuclearfog.twidda.fragments.TweetFragment; @@ -64,28 +67,31 @@ public class TweetLoader extends AsyncTask> { } @Nullable - private EngineException twException; - private final WeakReference callback; - private final TwitterEngine mTwitter; - private final AppDatabase db; + private TwitterError twException; + private WeakReference callback; + private TwitterEngine mTwitter; + private Twitter twitter; + private AppDatabase db; - private final ListType listType; - private final String search; - private final long id; + private ListType listType; + private String search; + private long id; private int pos; /** - * @param callback callback to update tweet data + * @param fragment callback to update tweet data * @param listType type of tweet list to load * @param id ID, depending on what list type should be loaded * @param search search string if any * @param pos index of the list where tweets should be inserted */ - public TweetLoader(TweetFragment callback, ListType listType, long id, String search, int pos) { + public TweetLoader(TweetFragment fragment, ListType listType, long id, String search, int pos) { super(); - this.callback = new WeakReference<>(callback); - db = new AppDatabase(callback.getContext()); - mTwitter = TwitterEngine.getInstance(callback.getContext()); + this.callback = new WeakReference<>(fragment); + db = new AppDatabase(fragment.getContext()); + mTwitter = TwitterEngine.getInstance(fragment.getContext()); + twitter = Twitter.get(fragment.getContext()); + this.listType = listType; this.search = search; this.id = id; @@ -104,14 +110,14 @@ public class TweetLoader extends AsyncTask> { if (sinceId == 0 && maxId == 0) { tweets = db.getHomeTimeline(); if (tweets.isEmpty()) { - tweets = mTwitter.getHome(sinceId, maxId); + tweets = twitter.getHomeTimeline(sinceId, maxId); db.storeHomeTimeline(tweets); } } else if (sinceId > 0) { - tweets = mTwitter.getHome(sinceId, maxId); + tweets = twitter.getHomeTimeline(sinceId, maxId); db.storeHomeTimeline(tweets); } else if (maxId > 1) { - tweets = mTwitter.getHome(sinceId, maxId); + tweets = twitter.getHomeTimeline(sinceId, maxId); } break; @@ -119,14 +125,14 @@ public class TweetLoader extends AsyncTask> { if (sinceId == 0 && maxId == 0) { tweets = db.getMentions(); if (tweets.isEmpty()) { - tweets = mTwitter.getMention(sinceId, maxId); + tweets = twitter.getMentionTimeline(sinceId, maxId); db.storeMentions(tweets); } } else if (sinceId > 0) { - tweets = mTwitter.getMention(sinceId, maxId); + tweets = twitter.getMentionTimeline(sinceId, maxId); db.storeMentions(tweets); } else if (maxId > 1) { - tweets = mTwitter.getMention(sinceId, maxId); + tweets = twitter.getMentionTimeline(sinceId, maxId); } break; @@ -135,17 +141,17 @@ public class TweetLoader extends AsyncTask> { if (sinceId == 0 && maxId == 0) { tweets = db.getUserTweets(id); if (tweets.isEmpty()) { - tweets = mTwitter.getUserTweets(id, 0, maxId); + tweets = twitter.getUserTimeline(id, 0, maxId); db.storeUserTweets(tweets); } } else if (sinceId > 0) { - tweets = mTwitter.getUserTweets(id, sinceId, maxId); + tweets = twitter.getUserTimeline(id, sinceId, maxId); db.storeUserTweets(tweets); } else if (maxId > 1) { - tweets = mTwitter.getUserTweets(id, sinceId, maxId); + tweets = twitter.getUserTimeline(id, sinceId, maxId); } } else if (search != null) { - tweets = mTwitter.getUserTweets(search, sinceId, maxId); + tweets = twitter.getUserTimeline(search, sinceId, maxId); } break; @@ -154,18 +160,18 @@ public class TweetLoader extends AsyncTask> { if (sinceId == 0 && maxId == 0) { tweets = db.getUserFavorites(id); if (tweets.isEmpty()) { - tweets = mTwitter.getUserFavs(id, 0, maxId); + tweets = twitter.getUserFavorits(id, 0, maxId); db.storeUserFavs(tweets, id); } } else if (sinceId > 0) { - tweets = mTwitter.getUserFavs(id, 0, maxId); + tweets = twitter.getUserFavorits(id, 0, maxId); db.storeUserFavs(tweets, id); pos = CLEAR_LIST; // set flag to clear previous data } else if (maxId > 1) { - tweets = mTwitter.getUserFavs(id, sinceId, maxId); + tweets = twitter.getUserFavorits(id, sinceId, maxId); } } else if (search != null) { - tweets = mTwitter.getUserFavs(search, sinceId, maxId); + tweets = twitter.getUserFavorits(search, sinceId, maxId); } break; @@ -200,8 +206,10 @@ public class TweetLoader extends AsyncTask> { tweets = mTwitter.getListTweets(id, sinceId, maxId); break; } - } catch (EngineException twException) { - this.twException = twException; + } catch (TwitterException e) { + this.twException = e; + } catch (EngineException e) { + this.twException = e; } catch (Exception err) { err.printStackTrace(); } diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/api/TweetV1.java b/app/src/main/java/org/nuclearfog/twidda/backend/api/TweetV1.java index a5fc0229..7b935fd9 100644 --- a/app/src/main/java/org/nuclearfog/twidda/backend/api/TweetV1.java +++ b/app/src/main/java/org/nuclearfog/twidda/backend/api/TweetV1.java @@ -33,53 +33,55 @@ class TweetV1 implements Tweet { private long timestamp; private String source; private Tweet embeddedTweet; - private String replyName; private long replyUserId; private long replyId; private long retweetId; private int retweetCount; private int favoriteCount; - private String[] mediaUrls; - private String userMentions; - private String mediaType; private boolean isSensitive; private boolean isRetweeted; private boolean isFavorited; - private String location; - private String coordinates; + private String userMentions = ""; + private String location = ""; + private String replyName = ""; + private String coordinates = ""; + private String[] mediaUrls = {}; + private String mediaType = ""; TweetV1(JSONObject json, long twitterId) throws JSONException{ id = json.optLong("id"); text = json.optString("full_text"); - timestamp = StringTools.getTime(json.optString("created_at")); replyId = json.optLong("in_reply_to_status_id", -1); replyUserId = json.optLong("in_reply_to_status_id", -1); - location = json.optString("place"); - replyName = '@' + json.optString("in_reply_to_screen_name"); retweetCount = json.optInt("retweet_count"); favoriteCount = json.optInt("favorite_count"); isFavorited = json.optBoolean("favorited"); isRetweeted = json.optBoolean("retweeted"); isSensitive = json.optBoolean("possibly_sensitive"); + timestamp = StringTools.getTime(json.optString("created_at")); source = StringTools.getSource(json.optString("source")); + String location = json.optString("place"); + String replyName = json.optString("in_reply_to_screen_name"); - JSONObject userJson = json.getJSONObject("user"); - JSONObject tweetJson = json.optJSONObject("quoted_status"); - JSONObject retweetJson = json.optJSONObject("current_user_retweet"); + JSONObject user = json.getJSONObject("user"); + JSONObject quoted_tweet = json.optJSONObject("quoted_status"); + JSONObject user_retweet = json.optJSONObject("current_user_retweet"); JSONObject entities = json.optJSONObject("entities"); JSONObject extEntities = json.optJSONObject("extended_entities"); JSONObject geo = json.optJSONObject("geo"); - author = new UserV1(userJson, twitterId); - if (location.equals("null")) - location = ""; + author = new UserV1(user, twitterId); + if (!location.equals("null")) + this.location = location; + if (!replyName.equals("null")) + this.replyName = replyName; if (geo != null) coordinates = geo.optString("coordinates"); - if (retweetJson != null) - retweetId = retweetJson.optLong("id"); - if (tweetJson != null) - embeddedTweet = new TweetV1(tweetJson, twitterId); + if (user_retweet != null) + retweetId = user_retweet.optLong("id"); + if (quoted_tweet != null) + embeddedTweet = new TweetV1(quoted_tweet, twitterId); if (entities != null) addURLs(entities); if (extEntities != null) { @@ -261,7 +263,7 @@ class TweetV1 implements Tweet { /** * expand URLs int the tweet text * - * @param entities json object with url information + * @param entities json object with tweet entities */ private void addURLs(@NonNull JSONObject entities) { try { @@ -285,18 +287,24 @@ class TweetV1 implements Tweet { /** * get mentioned user's screen name + * + * @param extEntities JSON object with extended entities */ - private void addUserMentions(JSONObject json) { + private void addUserMentions(JSONObject extEntities) { StringBuilder buf = new StringBuilder(); if (!replyName.isEmpty()) { buf.append(replyName).append(' '); } - JSONArray mentions = json.optJSONArray("user_mentions"); + JSONArray mentions = extEntities.optJSONArray("user_mentions"); if (mentions != null && mentions.length() > 0) { for (int pos = 0 ; pos < mentions.length() ; pos++){ JSONObject mention = mentions.optJSONObject(pos); if (mention != null) { - buf.append('@').append(mention.optString("screen_name")).append(' '); + long mentionedUserId = mention.optLong("id"); + String mentionedUsername = mention.optString("screen_name"); + if (mentionedUserId != author.getId() && !mentionedUsername.isEmpty()) { + buf.append('@').append(mentionedUsername).append(' '); + } } } } diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/api/Twitter.java b/app/src/main/java/org/nuclearfog/twidda/backend/api/Twitter.java index 42df307d..58a50de5 100644 --- a/app/src/main/java/org/nuclearfog/twidda/backend/api/Twitter.java +++ b/app/src/main/java/org/nuclearfog/twidda/backend/api/Twitter.java @@ -18,7 +18,8 @@ import org.nuclearfog.twidda.database.GlobalSettings; import java.io.IOException; import java.security.KeyStore; -import java.util.Arrays; +import java.util.ArrayList; +import java.util.List; import java.util.Set; import java.util.TreeSet; @@ -55,11 +56,12 @@ public class Twitter { private static final String BLOCK_LIST = API + "1.1/blocks/list.json"; private static final String MUTES_LIST = API + "1.1/mutes/users/list.json"; private static final String SHOW_TWEET = API + "1.1/statuses/show.json"; + private static final String SHOW_HOME = API + "1.1/statuses/home_timeline.json"; + private static final String SHOW_MENTIONS = API + "1.1/statuses/mentions_timeline.json"; + private static final String SHOW_USER_TL = API + "1.1/statuses/user_timeline.json"; + private static final String SHOW_USER_FAV = API + "1.1/favorites/list.json"; public static final String REQUEST_URL = AUTHENTICATE + "?oauth_token="; - - private static final String SKIP_STAT = "skip_status=true"; - private static Twitter instance; private OkHttpClient client; @@ -105,7 +107,7 @@ public class Twitter { */ public String getRequestToken() throws TwitterException { try { - Response response = post(REQUEST_TOKEN); + Response response = post(REQUEST_TOKEN, new ArrayList<>(1)); if (response.code() == 200 && response.body() != null) { String res = response.body().string(); Uri uri = Uri.parse(AUTHENTICATE + "?" + res); @@ -125,9 +127,10 @@ public class Twitter { */ public User login(String oauth_token, String pin) throws TwitterException { try { - String paramPin = "oauth_verifier=" + pin; - String paramToken = "oauth_token=" + oauth_token; - Response response = post(OAUTH_VERIFIER, paramPin, paramToken); + List params = new ArrayList<>(3); + params.add("oauth_verifier=" + pin); + params.add("oauth_token=" + oauth_token); + Response response = post(OAUTH_VERIFIER, params); if (response.code() == 200 && response.body() != null) { String res = response.body().string(); // extrect tokens from link @@ -152,7 +155,7 @@ public class Twitter { */ public User getCredentials() throws TwitterException { try { - Response response = get(CREDENTIALS); + Response response = get(CREDENTIALS, new ArrayList<>(1)); if (response.body() != null) { JSONObject json = new JSONObject(response.body().string()); if (response.code() == 200) { @@ -177,9 +180,9 @@ public class Twitter { * @return user information */ public User showUser(long id) throws TwitterException { - String param = "user_id=" + id; - String extra = "include_entities=true"; - return showUser(param, extra); + List params = new ArrayList<>(3); + params.add("user_id=" + id); + return showUser(params); } /** @@ -189,9 +192,9 @@ public class Twitter { * @return user information */ public User showUser(String name) throws TwitterException { - String param = "screen_name=" + name; - String extra = "include_entities=true"; - return showUser(param, extra); + List params = new ArrayList<>(3); + params.add("screen_name=" + name); + return showUser(params); } /** @@ -202,10 +205,10 @@ public class Twitter { * @return list of users */ public Users getFollowing(long userId, long cursor) throws TwitterException { - String paramId = "user_id=" + userId; - String paramCsr = "cursor=" + cursor; - String paramCnt = "count=" + settings.getListSize(); - return getUsers1(USER_FOLLOWING, paramId, paramCsr, paramCnt, SKIP_STAT); + List params = new ArrayList<>(5); + params.add("user_id=" + userId); + params.add("cursor=" + cursor); + return getUsers1(USER_FOLLOWING, params); } /** @@ -216,10 +219,10 @@ public class Twitter { * @return list of users */ public Users getFollower(long userId, long cursor) throws TwitterException { - String paramId = "user_id=" + userId; - String paramCsr = "cursor=" + cursor; - String paramCnt = "count=" + settings.getListSize(); - return getUsers1(USER_FOLLOWER, paramId, paramCsr, paramCnt, SKIP_STAT); + List params = new ArrayList<>(5); + params.add("user_id=" + userId); + params.add("cursor=" + cursor); + return getUsers1(USER_FOLLOWER, params); } /** @@ -230,10 +233,10 @@ public class Twitter { * @return list of users */ public Users getListMember(long listId, long cursor) throws TwitterException { - String paramId = "list_id=" + listId; - String paramCsr = "cursor=" + cursor; - String paramCnt = "count=" + settings.getListSize(); - return getUsers1(USER_LIST_MEMBER, paramId, paramCsr, paramCnt, SKIP_STAT); + List params = new ArrayList<>(5); + params.add("list_id=" + listId); + params.add("cursor=" + cursor); + return getUsers1(USER_LIST_MEMBER, params); } /** @@ -244,10 +247,10 @@ public class Twitter { * @return list of users */ public Users getListSubscriber(long listId, long cursor) throws TwitterException { - String paramId = "list_id=" + listId; - String paramCsr = "cursor=" + cursor; - String paramCnt = "count=" + settings.getListSize(); - return getUsers1(USER_LIST_SUBSCRIBER, paramId, paramCsr, paramCnt, SKIP_STAT); + List params = new ArrayList<>(5); + params.add("list_id=" + listId); + params.add("cursor=" + cursor); + return getUsers1(USER_LIST_SUBSCRIBER, params); } /** @@ -257,8 +260,9 @@ public class Twitter { * @return list of users */ public Users getBlockedUsers(long cursor) throws TwitterException { - String paramCsr = "cursor=" + cursor; - return getUsers1(BLOCK_LIST, paramCsr, SKIP_STAT); + List params = new ArrayList<>(4); + params.add("cursor=" + cursor); + return getUsers1(BLOCK_LIST, params); } /** @@ -268,8 +272,9 @@ public class Twitter { * @return list of users */ public Users getMutedUsers(long cursor) throws TwitterException { - String paramCsr = "cursor=" + cursor; - return getUsers1(MUTES_LIST, paramCsr, SKIP_STAT); + List params = new ArrayList<>(4); + params.add("cursor=" + cursor); + return getUsers1(MUTES_LIST, params); } /** @@ -305,15 +310,16 @@ public class Twitter { // search endpoint only supports pages parameter long currentPage = page > 0 ? page : 1; long nextPage = currentPage + 1; - String paramQuery = "q=" + search; - String paramPage = "page=" + currentPage; - String paramCnt = "count=" + settings.getListSize(); + List params = new ArrayList<>(4); + params.add("q=" + search); + params.add("page=" + currentPage); + params.add("count=" + settings.getListSize()); try { - Response response = get(USER_SEARCH, paramQuery, paramPage, paramCnt); + Response response = get(USER_SEARCH, params); if (response.body() != null) { - JSONArray array = new JSONArray(response.body().string()); if (response.code() == 200) { + JSONArray array = new JSONArray(response.body().string()); if (array.length() < 20) nextPage = 0; Users users = new Users(currentPage - 1, nextPage); @@ -334,9 +340,13 @@ public class Twitter { } } return users; + } else { + JSONObject result = new JSONObject(response.body().string()); + throw new TwitterException(result); } + } else { + throw new TwitterException(response); } - throw new TwitterException(response); } catch (IOException err) { throw new TwitterException(err); } catch (JSONException err) { @@ -344,15 +354,121 @@ public class Twitter { } } + /** + * show current user's home timeline + * + * @param minId get tweets with ID above the min ID + * @param maxId get tweets with ID under the max ID + * @return list of tweets + */ + public List getHomeTimeline(long minId, long maxId) throws TwitterException { + List params = new ArrayList<>(5); + if (minId > 0) + params.add("since_id=" + minId); + if (maxId > 0) + params.add("max_id=" + maxId); + return getTweets1(SHOW_HOME, params); + } + + /** + * show current user's home timeline + * + * @param minId get tweets with ID above the min ID + * @param maxId get tweets with ID under the max ID + * @return list of tweets + */ + public List getMentionTimeline(long minId, long maxId) throws TwitterException { + List params = new ArrayList<>(5); + if (minId > 0) + params.add("since_id=" + minId); + if (maxId > 1) + params.add("max_id=" + maxId); + return getTweets1(SHOW_MENTIONS, params); + } + + /** + * show the timeline of an user + * + * @param userId ID of the user + * @param minId get tweets with ID above the min ID + * @param maxId get tweets with ID under the max ID + * @return list of tweets + */ + public List getUserTimeline(long userId, long minId, long maxId) throws TwitterException { + List params = new ArrayList<>(6); + if (minId > 0) + params.add("since_id=" + minId); + if (maxId > 1) + params.add("max_id=" + maxId); + params.add("user_id=" + userId); + return getTweets1(SHOW_USER_TL, params); + } + + /** + * show the timeline of an user + * + * @param screen_name screen name of the user (without '@') + * @param minId get tweets with ID above the min ID + * @param maxId get tweets with ID under the max ID + * @return list of tweets + */ + public List getUserTimeline(String screen_name, long minId, long maxId) throws TwitterException { + List params = new ArrayList<>(6); + if (minId > 0) + params.add("since_id=" + minId); + if (maxId > 1) + params.add("max_id=" + maxId); + params.add("screen_name=" + screen_name); + return getTweets1(SHOW_USER_TL, params); + } + + /** + * show the favorite tweets of an user + * + * @param userId ID of the user + * @param minId get tweets with ID above the min ID + * @param maxId get tweets with ID under the max ID + * @return list of tweets + */ + public List getUserFavorits(long userId, long minId, long maxId) throws TwitterException { + List params = new ArrayList<>(6); + if (minId > 0) + params.add("since_id=" + minId); + if (maxId > 1) + params.add("max_id=" + maxId); + params.add("user_id=" + userId); + return getTweets1(SHOW_USER_FAV, params); + } + + /** + * show the favorite tweets of an user + * + * @param screen_name screen name of the user (without '@') + * @param minId get tweets with ID above the min ID + * @param maxId get tweets with ID under the max ID + * @return list of tweets + */ + public List getUserFavorits(String screen_name, long minId, long maxId) throws TwitterException { + List params = new ArrayList<>(6); + if (minId > 0) + params.add("since_id=" + minId); + if (maxId > 1) + params.add("max_id=" + maxId); + params.add("screen_name=" + screen_name); + return getTweets1(SHOW_USER_FAV, params); + } + /** * lookup tweet by ID * @param id tweet ID * @return tweet information */ public Tweet showTweet(long id) throws TwitterException { + List params = new ArrayList<>(3); + params.add("id=" + id); + params.add(TweetV1.EXT_MODE); try { - String paramId = "id=" + id; - Response response = get(SHOW_TWEET, paramId, TweetV1.EXT_MODE); + Response response = get(SHOW_TWEET, params); if (response.body() != null) { JSONObject json = new JSONObject(response.body().string()); if (response.code() == 200) { @@ -376,8 +492,9 @@ public class Twitter { * @param params additional parameter added to request * @return user information */ - private User showUser(String... params) throws TwitterException { + private User showUser(List params) throws TwitterException { try { + params.add(UserV1.INCLUDE_ENTITIES); Response response = get(USER_LOOKUP, params); if (response.body() != null) { JSONObject json = new JSONObject(response.body().string()); @@ -396,6 +513,40 @@ public class Twitter { } } + /** + * get tweets using an endpoint + * + * @param endpoint endpoint url to fetch the tweets + * @param params additional parameters + * @return list of tweets + */ + private List getTweets1(String endpoint, List params) throws TwitterException { + try { + params.add(TweetV1.EXT_MODE); + params.add("count=" + settings.getListSize()); + Response response = get(endpoint, params); + if (response.body() != null) { + if (response.code() == 200) { + JSONArray array = new JSONArray(response.body().string()); + long homeId = settings.getCurrentUserId(); + List tweets = new ArrayList<>(array.length() + 1); + for (int i = 0; i < array.length(); i++) + tweets.add(new TweetV1(array.getJSONObject(i), homeId)); + return tweets; + } else { + JSONObject json = new JSONObject(response.body().string()); + throw new TwitterException(json); + } + } else { + throw new TwitterException(response); + } + } catch (IOException err) { + throw new TwitterException(err); + } catch (JSONException err) { + throw new TwitterException(err); + } + } + /** * create a list of users using API v 1.1 * @@ -403,21 +554,28 @@ public class Twitter { * @param params additional parameters * @return user list */ - private Users getUsers1(String endpoint, String... params) throws TwitterException { + private Users getUsers1(String endpoint, List params) throws TwitterException { try { + params.add("count=" + settings.getListSize()); + params.add(UserV1.SKIP_STAT); Response response = get(endpoint, params); if (response.body() != null) { JSONObject json = new JSONObject(response.body().string()); if (response.code() == 200) { - JSONArray array = json.getJSONArray("users"); - long prevCursor = json.getLong("previous_cursor"); - long nextCursor = json.getLong("next_cursor"); - Users users = new Users(prevCursor, nextCursor); - long homeId = settings.getCurrentUserId(); - for (int i = 0; i < array.length(); i++) { - users.add(new UserV1(array.getJSONObject(i), homeId)); + if (json.has("users")) { + JSONArray array = json.getJSONArray("users"); + long prevCursor = json.getLong("previous_cursor"); + long nextCursor = json.getLong("next_cursor"); + Users users = new Users(prevCursor, nextCursor); + long homeId = settings.getCurrentUserId(); + for (int i = 0; i < array.length(); i++) { + users.add(new UserV1(array.getJSONObject(i), homeId)); + } + return users; + } else { + // return empty list + return new Users(); } - return users; } else { throw new TwitterException(json); } @@ -439,17 +597,24 @@ public class Twitter { */ private Users getUsers2(String endpoint) throws TwitterException { try { - Response response = get(endpoint, UserV2.PARAMS); + List params = new ArrayList<>(2); + params.add(UserV2.PARAMS); + Response response = get(endpoint, params); if (response.body() != null) { JSONObject json = new JSONObject(response.body().string()); if (response.code() == 200) { - JSONArray array = json.getJSONArray("data"); - Users users = new Users(); - long homeId = settings.getCurrentUserId(); - for (int i = 0; i < array.length(); i++) { - users.add(new UserV2(array.getJSONObject(i), homeId)); + if (json.has("data")) { + JSONArray array = json.getJSONArray("data"); + Users users = new Users(); + long homeId = settings.getCurrentUserId(); + for (int i = 0; i < array.length(); i++) { + users.add(new UserV2(array.getJSONObject(i), homeId)); + } + return users; + } else { + // return empty list + return new Users(); } - return users; } else { throw new TwitterException(json); } @@ -469,7 +634,7 @@ public class Twitter { * @param endpoint endpoint url * @return http resonse */ - private Response post(String endpoint, String... params) throws IOException { + private Response post(String endpoint, List params) throws IOException { String authHeader = buildHeader("POST", endpoint, params); String url = appendParams(endpoint, params); RequestBody body = RequestBody.create(MediaType.parse("text/plain"), ""); @@ -483,7 +648,7 @@ public class Twitter { * @param endpoint endpoint url * @return http response */ - private Response get(String endpoint, String... params) throws IOException { + private Response get(String endpoint, List params) throws IOException { String authHeader = buildHeader("GET", endpoint, params); String url = appendParams(endpoint, params); Request request = new Request.Builder().url(url).addHeader("Authorization", authHeader).get().build(); @@ -498,7 +663,7 @@ public class Twitter { * @param params parameter to add to signature * @return header string */ - private String buildHeader(String method, String endpoint, String... params) { + private String buildHeader(String method, String endpoint, List params) { String timeStamp = StringTools.getTimestamp(); String random = StringTools.getRandomString(); String signkey = tokens.getConsumerSec() + "&"; @@ -513,7 +678,7 @@ public class Twitter { sortedParams.add("oauth_timestamp=" + timeStamp); sortedParams.add("oauth_version=" + OAUTH); // add custom parameters - sortedParams.addAll(Arrays.asList(params)); + sortedParams.addAll(params); // only add tokens if there is no login process if (!REQUEST_TOKEN.equals(endpoint) && !OAUTH_VERIFIER.equals(endpoint)) { @@ -549,8 +714,8 @@ public class Twitter { * @param params parameters * @return url with parameters */ - private String appendParams(String url, String[] params) { - if (params.length > 0) { + private String appendParams(String url, List params) { + if (!params.isEmpty()) { StringBuilder result = new StringBuilder(url); result.append('?'); for (String param : params) diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/api/UserV1.java b/app/src/main/java/org/nuclearfog/twidda/backend/api/UserV1.java index e45b8803..81e5d483 100644 --- a/app/src/main/java/org/nuclearfog/twidda/backend/api/UserV1.java +++ b/app/src/main/java/org/nuclearfog/twidda/backend/api/UserV1.java @@ -15,6 +15,9 @@ import org.nuclearfog.twidda.model.User; */ class UserV1 implements User { + static final String SKIP_STAT = "skip_status=true"; + static final String INCLUDE_ENTITIES = "include_entities=true"; + private long userID; private long created; private String username; diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/utils/StringTools.java b/app/src/main/java/org/nuclearfog/twidda/backend/utils/StringTools.java index b7b61c76..1dc1e16b 100644 --- a/app/src/main/java/org/nuclearfog/twidda/backend/utils/StringTools.java +++ b/app/src/main/java/org/nuclearfog/twidda/backend/utils/StringTools.java @@ -147,7 +147,7 @@ public final class StringTools { */ public static int calculateIndexOffset(String text, int limit) { int offset = 0; - for (int c = 0; c < limit - 1; c++) { + for (int c = 0; c < limit - 1 && c < text.length(); c++) { // determine if a pair of chars represent an emoji if (Character.isSurrogatePair(text.charAt(c), text.charAt(c + 1))) { offset++; diff --git a/app/src/main/java/org/nuclearfog/twidda/fragments/TweetFragment.java b/app/src/main/java/org/nuclearfog/twidda/fragments/TweetFragment.java index b6c7c66c..f0f5eb52 100644 --- a/app/src/main/java/org/nuclearfog/twidda/fragments/TweetFragment.java +++ b/app/src/main/java/org/nuclearfog/twidda/fragments/TweetFragment.java @@ -226,7 +226,7 @@ public class TweetFragment extends ListFragment implements TweetClickListener { * * @param error Twitter exception */ - public void onError(@Nullable EngineException error) { + public void onError(@Nullable ErrorHandler.TwitterError error) { ErrorHandler.handleFailure(requireContext(), error); adapter.disableLoading(); setRefresh(false);