From 1d0b1daae118fe99eeac93218aec81324ee0ec62 Mon Sep 17 00:00:00 2001 From: nuclearfog Date: Tue, 21 Dec 2021 16:49:17 +0100 Subject: [PATCH] added initial v2 support, VideoView fix for pre-Lollipop, fixed memory leak, added option to show user favoriting a tweet, gradle update, added strings --- app/build.gradle | 4 +- .../twidda/activities/MediaViewer.java | 65 +++++++---------- .../twidda/activities/TweetActivity.java | 9 +++ .../twidda/activities/UserDetail.java | 25 +++++-- .../twidda/backend/SeekbarUpdater.java | 51 +++++++++++++ .../nuclearfog/twidda/backend/UserLoader.java | 3 +- .../backend/engine/EngineException.java | 73 +++++++++++-------- .../twidda/backend/engine/TwitterEngine.java | 43 ++++++++++- .../twidda/backend/model/Tweet.java | 2 +- .../nuclearfog/twidda/backend/model/User.java | 31 ++++---- .../twidda/backend/utils/ErrorHandler.java | 3 + .../backend/utils/TLSSocketFactory.java | 4 +- .../twidda/database/AppDatabase.java | 3 +- .../twidda/fragments/UserFragment.java | 1 - app/src/main/res/values-de-rDE/strings.xml | 3 + app/src/main/res/values/strings.xml | 5 +- 16 files changed, 220 insertions(+), 105 deletions(-) create mode 100644 app/src/main/java/org/nuclearfog/twidda/backend/SeekbarUpdater.java diff --git a/app/build.gradle b/app/build.gradle index 44e99faa..9a921259 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -6,7 +6,7 @@ plugins { android { compileSdkVersion 31 - buildToolsVersion '31.0.0' + buildToolsVersion '32.0.0' defaultConfig { applicationId 'org.nuclearfog.twidda' @@ -35,6 +35,7 @@ android { } packagingOptions { + exclude '**/twitter4j.properties.template' exclude '/META-INF/CHANGES' exclude '/META-INF/DEPENDENCIES' exclude '/META-INF/README.md' @@ -64,6 +65,7 @@ dependencies { implementation 'androidx.cardview:cardview:1.0.0' implementation 'org.twitter4j:twitter4j-core:4.0.7' + implementation 'com.github.takke:twitter4j-v2:1.0.3' //noinspection GradleDependency implementation 'com.squareup.picasso:picasso:2.8' implementation 'com.larswerkman:LicenseView:1.1' diff --git a/app/src/main/java/org/nuclearfog/twidda/activities/MediaViewer.java b/app/src/main/java/org/nuclearfog/twidda/activities/MediaViewer.java index 24ad0595..c3199ecb 100644 --- a/app/src/main/java/org/nuclearfog/twidda/activities/MediaViewer.java +++ b/app/src/main/java/org/nuclearfog/twidda/activities/MediaViewer.java @@ -1,18 +1,5 @@ package org.nuclearfog.twidda.activities; -import static android.media.MediaPlayer.MEDIA_ERROR_UNKNOWN; -import static android.media.MediaPlayer.MEDIA_INFO_BUFFERING_END; -import static android.media.MediaPlayer.MEDIA_INFO_BUFFERING_START; -import static android.media.MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START; -import static android.os.AsyncTask.Status.RUNNING; -import static android.view.MotionEvent.ACTION_DOWN; -import static android.view.MotionEvent.ACTION_UP; -import static android.view.View.GONE; -import static android.view.View.INVISIBLE; -import static android.view.View.VISIBLE; -import static android.widget.Toast.LENGTH_SHORT; -import static androidx.recyclerview.widget.LinearLayoutManager.HORIZONTAL; - import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; @@ -25,6 +12,7 @@ import android.media.MediaPlayer.OnErrorListener; import android.media.MediaPlayer.OnInfoListener; import android.media.MediaPlayer.OnPreparedListener; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.view.MotionEvent; import android.view.View; @@ -48,6 +36,7 @@ import org.nuclearfog.twidda.R; import org.nuclearfog.twidda.adapter.ImageAdapter; import org.nuclearfog.twidda.adapter.ImageAdapter.OnImageClickListener; import org.nuclearfog.twidda.backend.ImageLoader; +import org.nuclearfog.twidda.backend.SeekbarUpdater; import org.nuclearfog.twidda.backend.engine.EngineException; import org.nuclearfog.twidda.backend.holder.ImageHolder; import org.nuclearfog.twidda.backend.utils.AppStyles; @@ -56,10 +45,18 @@ import org.nuclearfog.twidda.backend.utils.StringTools; import org.nuclearfog.twidda.database.GlobalSettings; import org.nuclearfog.zoomview.ZoomView; -import java.lang.ref.WeakReference; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; +import static android.media.MediaPlayer.MEDIA_ERROR_UNKNOWN; +import static android.media.MediaPlayer.MEDIA_INFO_BUFFERING_END; +import static android.media.MediaPlayer.MEDIA_INFO_BUFFERING_START; +import static android.media.MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START; +import static android.os.AsyncTask.Status.RUNNING; +import static android.view.MotionEvent.ACTION_DOWN; +import static android.view.MotionEvent.ACTION_UP; +import static android.view.View.GONE; +import static android.view.View.INVISIBLE; +import static android.view.View.VISIBLE; +import static android.widget.Toast.LENGTH_SHORT; +import static androidx.recyclerview.widget.LinearLayoutManager.HORIZONTAL; /** * Media viewer activity for images and videos @@ -115,11 +112,9 @@ public class MediaViewer extends MediaActivity implements OnImageClickListener, IDLE } - private WeakReference updateEvent = new WeakReference<>(this); - @Nullable - private ScheduledExecutorService progressUpdate; @Nullable private ImageLoader imageAsync; + private SeekbarUpdater seekUpdate; private TextView duration, position; private ProgressBar loadingCircle; @@ -190,23 +185,15 @@ public class MediaViewer extends MediaActivity implements OnImageClickListener, case MEDIAVIEWER_VIDEO: controlPanel.setVisibility(VISIBLE); - if (!mediaLinks[0].startsWith("http")) + if (mediaLinks[0].startsWith("/")) share.setVisibility(GONE); // local image - final Runnable seekUpdate = new Runnable() { - public void run() { - if (updateEvent.get() != null) { - updateEvent.get().updateSeekBar(); - } - } - }; - progressUpdate = Executors.newScheduledThreadPool(1); - progressUpdate.scheduleWithFixedDelay(new Runnable() { - public void run() { - if (updateEvent.get() != null) { - updateEvent.get().runOnUiThread(seekUpdate); - } - } - }, PROGRESS_UPDATE, PROGRESS_UPDATE, TimeUnit.MILLISECONDS); + else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP && mediaLinks[0].startsWith("https://")) { + // for any reason VideoView ignores TLS 1.2 setup, so we have to use http:// instead + // todo find a solution to add TLS 1.2 support for pre lollipop devices + mediaLinks[0] = "http://" + mediaLinks[0].substring(8); + } + seekUpdate = new SeekbarUpdater(this, PROGRESS_UPDATE); + // fall through case MEDIAVIEWER_ANGIF: videoView.setVisibility(VISIBLE); videoView.setZOrderMediaOverlay(true); // disable black background @@ -243,8 +230,8 @@ public class MediaViewer extends MediaActivity implements OnImageClickListener, protected void onDestroy() { if (imageAsync != null && imageAsync.getStatus() == RUNNING) imageAsync.cancel(true); - if (progressUpdate != null) - progressUpdate.shutdown(); + if (seekUpdate != null) + seekUpdate.shutdown(); super.onDestroy(); } @@ -480,7 +467,7 @@ public class MediaViewer extends MediaActivity implements OnImageClickListener, /** * updates controller panel SeekBar */ - private void updateSeekBar() { + public void updateSeekBar() { int videoPos = video_progress.getProgress(); switch (playStat) { case PLAY: 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 9e5e0649..178a352e 100644 --- a/app/src/main/java/org/nuclearfog/twidda/activities/TweetActivity.java +++ b/app/src/main/java/org/nuclearfog/twidda/activities/TweetActivity.java @@ -14,6 +14,7 @@ import static org.nuclearfog.twidda.activities.TweetEditor.KEY_TWEETPOPUP_REPLYI import static org.nuclearfog.twidda.activities.TweetEditor.KEY_TWEETPOPUP_TEXT; import static org.nuclearfog.twidda.activities.UserDetail.KEY_USERDETAIL_ID; import static org.nuclearfog.twidda.activities.UserDetail.KEY_USERDETAIL_MODE; +import static org.nuclearfog.twidda.activities.UserDetail.USERLIST_FAVORIT; import static org.nuclearfog.twidda.activities.UserDetail.USERLIST_RETWEETS; import static org.nuclearfog.twidda.fragments.TweetFragment.INTENT_TWEET_REMOVED_ID; import static org.nuclearfog.twidda.fragments.TweetFragment.INTENT_TWEET_UPDATE_DATA; @@ -203,6 +204,7 @@ public class TweetActivity extends AppCompatActivity implements OnClickListener, replyName.setOnClickListener(this); ansButton.setOnClickListener(this); rtwButton.setOnClickListener(this); + favButton.setOnClickListener(this); rtwButton.setOnLongClickListener(this); favButton.setOnLongClickListener(this); profile_img.setOnClickListener(this); @@ -334,6 +336,13 @@ public class TweetActivity extends AppCompatActivity implements OnClickListener, userList.putExtra(KEY_USERDETAIL_MODE, USERLIST_RETWEETS); startActivity(userList); } + // show user favoriting this tweet + else if (v.getId() == R.id.tweet_favorite) { + Intent userList = new Intent(this, UserDetail.class); + userList.putExtra(KEY_USERDETAIL_ID, clickedTweet.getId()); + userList.putExtra(KEY_USERDETAIL_MODE, USERLIST_FAVORIT); + startActivity(userList); + } // open profile of the tweet author else if (v.getId() == R.id.tweet_profile) { Intent profile = new Intent(getApplicationContext(), UserProfile.class); diff --git a/app/src/main/java/org/nuclearfog/twidda/activities/UserDetail.java b/app/src/main/java/org/nuclearfog/twidda/activities/UserDetail.java index f684f1c8..df0fe8c1 100644 --- a/app/src/main/java/org/nuclearfog/twidda/activities/UserDetail.java +++ b/app/src/main/java/org/nuclearfog/twidda/activities/UserDetail.java @@ -15,11 +15,7 @@ import org.nuclearfog.twidda.backend.utils.AppStyles; import org.nuclearfog.twidda.database.GlobalSettings; import org.nuclearfog.twidda.fragments.UserFragment; -import static org.nuclearfog.twidda.fragments.UserFragment.KEY_FRAG_USER_ID; -import static org.nuclearfog.twidda.fragments.UserFragment.KEY_FRAG_USER_MODE; -import static org.nuclearfog.twidda.fragments.UserFragment.USER_FRAG_FOLLOWS; -import static org.nuclearfog.twidda.fragments.UserFragment.USER_FRAG_FRIENDS; -import static org.nuclearfog.twidda.fragments.UserFragment.USER_FRAG_RETWEET; +import static org.nuclearfog.twidda.fragments.UserFragment.*; /** * Activity to show a list of twitter users @@ -54,6 +50,12 @@ public class UserDetail extends AppCompatActivity { */ public static final int USERLIST_RETWEETS = 0x19F582E; + /** + * user favoriting/liking a tweet, requires tweet ID + */ + public static final int USERLIST_FAVORIT = 0x9bcc3f99; + + @Override protected void attachBaseContext(Context newBase) { super.attachBaseContext(AppStyles.setFontScale(newBase)); @@ -72,6 +74,7 @@ public class UserDetail extends AppCompatActivity { int mode = data.getIntExtra(KEY_USERDETAIL_MODE, 0); long id = data.getLongExtra(KEY_USERDETAIL_ID, -1); + GlobalSettings settings = GlobalSettings.getInstance(this); Bundle param = new Bundle(); switch (mode) { @@ -98,17 +101,23 @@ public class UserDetail extends AppCompatActivity { // set toolbar title toolbar.setTitle(R.string.toolbar_userlist_retweet); break; + + case USERLIST_FAVORIT: + // set fragment parameter + param.putLong(KEY_FRAG_USER_ID, id); + param.putInt(KEY_FRAG_USER_MODE, USER_FRAG_FAVORIT); + int title = settings.likeEnabled() ? R.string.toolbar_tweet_liker : R.string.toolbar_tweet_favoriter; + // set toolbar title + toolbar.setTitle(title); + break; } // insert fragment into view FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); fragmentTransaction.replace(R.id.fragment_container, UserFragment.class, param, ""); fragmentTransaction.commit(); - // set toolbar setSupportActionBar(toolbar); - // style activity - GlobalSettings settings = GlobalSettings.getInstance(this); AppStyles.setTheme(root, settings.getBackgroundColor()); } } \ No newline at end of file diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/SeekbarUpdater.java b/app/src/main/java/org/nuclearfog/twidda/backend/SeekbarUpdater.java new file mode 100644 index 00000000..d684990d --- /dev/null +++ b/app/src/main/java/org/nuclearfog/twidda/backend/SeekbarUpdater.java @@ -0,0 +1,51 @@ +package org.nuclearfog.twidda.backend; + +import org.nuclearfog.twidda.activities.MediaViewer; + +import java.lang.ref.WeakReference; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +/** + * This class updates {@link MediaViewer}'s Seekbar while playing a video + * + * @author nuclearfog + */ +public class SeekbarUpdater implements Runnable { + + private ScheduledExecutorService updater; + private WeakReference callback; + + private Runnable seekUpdate = new Runnable() { + public void run() { + MediaViewer mediaViewer = callback.get(); + if (mediaViewer != null) { + mediaViewer.updateSeekBar(); + } + } + }; + + + public SeekbarUpdater(MediaViewer callback, int milliseconds) { + this.callback = new WeakReference<>(callback); + updater = Executors.newScheduledThreadPool(1); + updater.scheduleWithFixedDelay(this, milliseconds, milliseconds, TimeUnit.MILLISECONDS); + } + + + @Override + public void run() { + MediaViewer mediaViewer = callback.get(); + if (mediaViewer != null) { + mediaViewer.runOnUiThread(seekUpdate); + } + } + + /** + * shutdown updater + */ + public void shutdown() { + updater.shutdown(); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/UserLoader.java b/app/src/main/java/org/nuclearfog/twidda/backend/UserLoader.java index 7592520c..16642faa 100644 --- a/app/src/main/java/org/nuclearfog/twidda/backend/UserLoader.java +++ b/app/src/main/java/org/nuclearfog/twidda/backend/UserLoader.java @@ -99,8 +99,7 @@ public class UserLoader extends AsyncTask { return mTwitter.getRetweeter(id, cursor); case FAVORIT: - // TODO not implemented in Twitter4J - break; + return mTwitter.getFavoriter(id, cursor); case SEARCH: return mTwitter.searchUsers(search, cursor); diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/engine/EngineException.java b/app/src/main/java/org/nuclearfog/twidda/backend/engine/EngineException.java index 0b92acab..f0e11807 100644 --- a/app/src/main/java/org/nuclearfog/twidda/backend/engine/EngineException.java +++ b/app/src/main/java/org/nuclearfog/twidda/backend/engine/EngineException.java @@ -12,36 +12,6 @@ import twitter4j.TwitterException; */ public class EngineException extends Exception { - public enum ErrorType { - RATE_LIMIT_EX, - USER_NOT_FOUND, - APP_SUSPENDED, - ACCESS_TOKEN_DEAD, - TWEET_CANT_REPLY, - RESOURCE_NOT_FOUND, - CANT_SEND_DM, - NOT_AUTHORIZED, - TWEET_TOO_LONG, - DUPLICATE_TWEET, - NO_DM_TO_USER, - DM_TOO_LONG, - TOKEN_EXPIRED, - NO_MEDIA_FOUND, - NO_LINK_DEFINED, - NO_CONNECTION, - IMAGE_NOT_LOADED, - REQUEST_CANCELLED, - ACCOUNT_UPDATE_FAILED, - ERROR_API_ACCESS_DENIED, - ERROR_NOT_DEFINED - } - - enum InternalErrorType { - FILENOTFOUND, - TOKENNOTSET, - BITMAP_FAILURE - } - private final ErrorType errorType; private String msg; private int retryAfter; @@ -129,6 +99,8 @@ public class EngineException extends Exception { default: if (error.getStatusCode() == 401) { errorType = ErrorType.NOT_AUTHORIZED; + } else if (error.getStatusCode() == 403) { + errorType = ErrorType.REQUEST_FORBIDDEN; } else if (error.getStatusCode() == 408) { errorType = ErrorType.REQUEST_CANCELLED; } else if (error.isCausedByNetworkIssue()) { @@ -146,7 +118,7 @@ public class EngineException extends Exception { } /** - * Constructor for non Twitter4J errors + * Constructor for app errors * * @param errorCode custom error code */ @@ -170,6 +142,7 @@ public class EngineException extends Exception { } } + @Override public String getMessage() { if (msg == null || msg.isEmpty()) @@ -195,7 +168,6 @@ public class EngineException extends Exception { return errorType == RESOURCE_NOT_FOUND || errorType == USER_NOT_FOUND; } - /** * return time to wait after unlock access in seconds * @@ -204,4 +176,41 @@ public class EngineException extends Exception { public int getTimeToWait() { return retryAfter; } + + /** + * enum of error types used by this class + */ + public enum ErrorType { + RATE_LIMIT_EX, + USER_NOT_FOUND, + APP_SUSPENDED, + ACCESS_TOKEN_DEAD, + TWEET_CANT_REPLY, + RESOURCE_NOT_FOUND, + CANT_SEND_DM, + NOT_AUTHORIZED, + TWEET_TOO_LONG, + DUPLICATE_TWEET, + NO_DM_TO_USER, + DM_TOO_LONG, + TOKEN_EXPIRED, + NO_MEDIA_FOUND, + NO_LINK_DEFINED, + NO_CONNECTION, + IMAGE_NOT_LOADED, + REQUEST_CANCELLED, + REQUEST_FORBIDDEN, + ACCOUNT_UPDATE_FAILED, + ERROR_API_ACCESS_DENIED, + ERROR_NOT_DEFINED + } + + /** + * error types only accessible by {@link TwitterEngine} + */ + enum InternalErrorType { + FILENOTFOUND, + TOKENNOTSET, + BITMAP_FAILURE + } } \ No newline at end of file diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/engine/TwitterEngine.java b/app/src/main/java/org/nuclearfog/twidda/backend/engine/TwitterEngine.java index 6b03001d..b5bb51e6 100644 --- a/app/src/main/java/org/nuclearfog/twidda/backend/engine/TwitterEngine.java +++ b/app/src/main/java/org/nuclearfog/twidda/backend/engine/TwitterEngine.java @@ -42,6 +42,7 @@ import twitter4j.DirectMessage; import twitter4j.DirectMessageList; import twitter4j.GeoLocation; import twitter4j.IDs; +import twitter4j.LikesExKt; import twitter4j.Location; import twitter4j.PagableResponseList; import twitter4j.Paging; @@ -53,6 +54,8 @@ import twitter4j.Twitter; import twitter4j.TwitterException; import twitter4j.TwitterFactory; import twitter4j.UploadedMedia; +import twitter4j.User2; +import twitter4j.UsersResponse; import twitter4j.auth.AccessToken; import twitter4j.auth.RequestToken; import twitter4j.conf.ConfigurationBuilder; @@ -847,7 +850,7 @@ public class TwitterEngine { * Get User who retweeted a Tweet * * @param tweetID Tweet ID - * @return List of users or empty list if no match + * @return List of users * @throws EngineException if Access is unavailable */ public UserList getRetweeter(long tweetID, long cursor) throws EngineException { @@ -867,6 +870,24 @@ public class TwitterEngine { } } + /** + * get user who liked a tweet + * + * @param tweetId Tweet ID + * @return list of users liking a tweet + * @throws EngineException if Access is unavailable + */ + public UserList getFavoriter(long tweetId, long cursor) throws EngineException { + try { + UsersResponse response = LikesExKt.getLikingUsers(twitter, tweetId, null, null, null); + List users = response.getUsers(); + UserList result = new UserList(cursor, 0); + result.addAll(convertUser2List(users)); + return result; + } catch (TwitterException err) { + throw new EngineException(err); + } + } /** * get list of Direct Messages @@ -1278,7 +1299,7 @@ public class TwitterEngine { } /** - * convert {@link twitter4j.User} to User List and filter excluded users + * convert {@link twitter4j.User} list to User List and filter excluded users * * @param users Twitter4J user List * @return User @@ -1295,6 +1316,24 @@ public class TwitterEngine { return result; } + /** + * convert {@link User2} list to user list + * + * @param users list of user from version 2 + * @return user list + */ + private List convertUser2List(List users) throws TwitterException { + long id = twitter.getId(); + ArrayList result = new ArrayList<>(); + result.ensureCapacity(users.size()); + for (User2 user : users) { + if (user.getPublicMetrics() != null) { + result.add(new User(user, user.getPublicMetrics(), id)); + } + } + return result; + } + /** * create paging for tweets * diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/model/Tweet.java b/app/src/main/java/org/nuclearfog/twidda/backend/model/Tweet.java index d1089c97..bdde4dd8 100644 --- a/app/src/main/java/org/nuclearfog/twidda/backend/model/Tweet.java +++ b/app/src/main/java/org/nuclearfog/twidda/backend/model/Tweet.java @@ -359,7 +359,7 @@ public class Tweet implements Serializable { private void setTweet(Status status, long twitterId) { tweetID = status.getId(); time = status.getCreatedAt().getTime(); - user = new User(status.getUser(), status.getUser().getId() == twitterId); + user = new User(status.getUser(), twitterId); replyID = status.getInReplyToStatusId(); replyUserId = status.getInReplyToUserId(); sensitiveMedia = status.isPossiblySensitive(); diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/model/User.java b/app/src/main/java/org/nuclearfog/twidda/backend/model/User.java index f76605c5..2822d893 100644 --- a/app/src/main/java/org/nuclearfog/twidda/backend/model/User.java +++ b/app/src/main/java/org/nuclearfog/twidda/backend/model/User.java @@ -5,6 +5,7 @@ import androidx.annotation.NonNull; import java.io.Serializable; import twitter4j.URLEntity; +import twitter4j.User2; /** * Container class for a twitter user @@ -38,19 +39,12 @@ public class User implements Serializable { private String profileImg = ""; private String bannerImg = ""; - /** - * @param user Twitter user - * @param twitterId ID of the current user - */ - public User(twitter4j.User user, long twitterId) { - this(user, user.getId() == twitterId); - } /** - * @param user Twitter user - * @param isCurrentUser true if user is the authenticated user + * @param user Twitter user + * @param twitterId ID of the current user */ - public User(twitter4j.User user, boolean isCurrentUser) { + public User(twitter4j.User user, long twitterId) { String bannerLink = user.getProfileBannerURL(); String bio = user.getDescription(); @@ -85,7 +79,16 @@ public class User implements Serializable { favorCount = user.getFavouritesCount(); isFollowReqSent = user.isFollowRequestSent(); hasDefaultImage = user.isDefaultProfileImage(); - this.isCurrentUser = isCurrentUser; + isCurrentUser = twitterId == userID; + } + + + public User(User2 user, User2.PublicMetrics metrics, long id) { + this(user.getId(), user.getUsername(), user.getName(), user.getProfileImageUrl(), + user.getDescription(), user.getLocation(), id, user.getVerified(), + user.getProtected(), false, true, "", "", user.getCreatedAt().getTime(), + metrics.getFollowingCount(), metrics.getFollowersCount(), + metrics.getTweetCount(), metrics.getListedCount()); } /** @@ -95,7 +98,7 @@ public class User implements Serializable { * @param profileImg profile image link * @param bio bio of the user * @param location location name - * @param isCurrentUser true if this user is the authenticated user + * @param currentId current ID of the user * @param isVerified true if user is verified * @param isLocked true if users profile is locked * @param isFollowReqSent true if authenticated user has sent a follow request @@ -108,7 +111,7 @@ public class User implements Serializable { * @param tweetCount number of tweets of the user * @param favorCount number of tweets favored by the user */ - public User(long userID, String username, String screenName, String profileImg, String bio, String location, boolean isCurrentUser, + public User(long userID, String username, String screenName, String profileImg, String bio, String location, long currentId, boolean isVerified, boolean isLocked, boolean isFollowReqSent, boolean hasDefaultImage, String link, String bannerImg, long created, int following, int follower, int tweetCount, int favorCount) { @@ -127,7 +130,6 @@ public class User implements Serializable { if (bannerImg != null) this.bannerImg = bannerImg; this.userID = userID; - this.isCurrentUser = isCurrentUser; this.isVerified = isVerified; this.isLocked = isLocked; this.created = created; @@ -137,6 +139,7 @@ public class User implements Serializable { this.favorCount = favorCount; this.isFollowReqSent = isFollowReqSent; this.hasDefaultImage = hasDefaultImage; + isCurrentUser = currentId == userID; } /** diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/utils/ErrorHandler.java b/app/src/main/java/org/nuclearfog/twidda/backend/utils/ErrorHandler.java index 01ae7f94..6ac660da 100644 --- a/app/src/main/java/org/nuclearfog/twidda/backend/utils/ErrorHandler.java +++ b/app/src/main/java/org/nuclearfog/twidda/backend/utils/ErrorHandler.java @@ -103,6 +103,9 @@ public final class ErrorHandler { case REQUEST_CANCELLED: return context.getString(R.string.error_result_cancelled); + case REQUEST_FORBIDDEN: + return context.getString(R.string.error_forbidden_api_access); + case APP_SUSPENDED: case ERROR_API_ACCESS_DENIED: GlobalSettings settings = GlobalSettings.getInstance(context); diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/utils/TLSSocketFactory.java b/app/src/main/java/org/nuclearfog/twidda/backend/utils/TLSSocketFactory.java index 9b96be08..8a8dbd83 100644 --- a/app/src/main/java/org/nuclearfog/twidda/backend/utils/TLSSocketFactory.java +++ b/app/src/main/java/org/nuclearfog/twidda/backend/utils/TLSSocketFactory.java @@ -15,7 +15,7 @@ import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; /** - * Enable Experimental TLS 1.2 support for devices lower than android 21 + * Enable Experimental TLS 1.2 support for pre-Lollipop devices * * @author fkrauthan * @see @@ -62,7 +62,7 @@ public class TLSSocketFactory extends SSLSocketFactory { * */ TLSSocketFactory() throws KeyManagementException, NoSuchAlgorithmException { - SSLContext context = SSLContext.getInstance("TLS"); + SSLContext context = SSLContext.getInstance(TLS_1_2); context.init(null, null, null); internalSSLSocketFactory = context.getSocketFactory(); } diff --git a/app/src/main/java/org/nuclearfog/twidda/database/AppDatabase.java b/app/src/main/java/org/nuclearfog/twidda/database/AppDatabase.java index f65b7088..436d2c34 100644 --- a/app/src/main/java/org/nuclearfog/twidda/database/AppDatabase.java +++ b/app/src/main/java/org/nuclearfog/twidda/database/AppDatabase.java @@ -754,12 +754,11 @@ public class AppDatabase { int tCount = cursor.getInt(cursor.getColumnIndexOrThrow(UserTable.TWEETS)); int fCount = cursor.getInt(cursor.getColumnIndexOrThrow(UserTable.FAVORS)); int userRegister = cursor.getInt(cursor.getColumnIndexOrThrow(UserRegisterTable.REGISTER)); - boolean isCurrentUser = homeId == userId; boolean isVerified = (userRegister & VER_MASK) != 0; boolean isLocked = (userRegister & LCK_MASK) != 0; boolean isReq = (userRegister & FRQ_MASK) != 0; boolean defaultImg = (userRegister & DEF_IMG) != 0; - return new User(userId, username, screenName, profileImg, bio, location, isCurrentUser, isVerified, + return new User(userId, username, screenName, profileImg, bio, location, homeId, isVerified, isLocked, isReq, defaultImg, link, banner, createdAt, following, follower, tCount, fCount); } diff --git a/app/src/main/java/org/nuclearfog/twidda/fragments/UserFragment.java b/app/src/main/java/org/nuclearfog/twidda/fragments/UserFragment.java index c16cc06a..cd6ad5da 100644 --- a/app/src/main/java/org/nuclearfog/twidda/fragments/UserFragment.java +++ b/app/src/main/java/org/nuclearfog/twidda/fragments/UserFragment.java @@ -80,7 +80,6 @@ public class UserFragment extends ListFragment implements UserClickListener, /** * configuration to get a list of users favoring a tweet - * todo implement this function if there is an API for it */ public static final int USER_FRAG_FAVORIT = 0xA7FB2BB4; diff --git a/app/src/main/res/values-de-rDE/strings.xml b/app/src/main/res/values-de-rDE/strings.xml index 5e67adee..5dbc2c86 100644 --- a/app/src/main/res/values-de-rDE/strings.xml +++ b/app/src/main/res/values-de-rDE/strings.xml @@ -223,4 +223,7 @@ Tweet zu den Likes hinzugefügt Tweet aus den Likes entfernt svg Icons von: + Tweet favorisiert von + Tweet gelikt von + Diese API unterstützt nicht diese Aktion! \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5fa9be57..a2f6531f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -124,6 +124,8 @@ remove account from list? User ID: \'unnamed\' + User favoriting this tweet + User liking this tweet User removed from list @@ -163,6 +165,7 @@ Read permission needed to access images and videos. Location permission only needed to add location information to tweets. Write permission used to store images. + restarting required to apply changes Error @@ -205,6 +208,7 @@ Error, result cancelled! Error, search query is too long or contains illegal characters! Not specified error! + API does not support this operation! write Tweet @@ -246,7 +250,6 @@ OK Link preview image close link preview - restarting required to apply changes svg icons from: www.svgrepo.com www.entypo.com