added initial v2 support, VideoView fix for pre-Lollipop, fixed memory leak, added option to show user favoriting a tweet, gradle update, added strings
This commit is contained in:
parent
086234944e
commit
1d0b1daae1
|
@ -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'
|
||||
|
|
|
@ -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<MediaViewer> 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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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<MediaViewer> 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();
|
||||
}
|
||||
}
|
|
@ -99,8 +99,7 @@ public class UserLoader extends AsyncTask<Long, Void, UserList> {
|
|||
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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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<User2> 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<User> convertUser2List(List<User2> users) throws TwitterException {
|
||||
long id = twitter.getId();
|
||||
ArrayList<User> 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
|
||||
*
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 <a href="https://gist.githubusercontent.com/fkrauthan/ac8624466a4dee4fd02f/raw/309efc30e31c96a932ab9d19bf4d73b286b00573/TLSSocketFactory.java"/>
|
||||
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -223,4 +223,7 @@
|
|||
<string name="info_tweet_liked">Tweet zu den Likes hinzugefügt</string>
|
||||
<string name="info_tweet_unliked">Tweet aus den Likes entfernt</string>
|
||||
<string name="app_info_icons">svg Icons von:</string>
|
||||
<string name="toolbar_tweet_favoriter">Tweet favorisiert von</string>
|
||||
<string name="toolbar_tweet_liker">Tweet gelikt von</string>
|
||||
<string name="error_forbidden_api_access">Diese API unterstützt nicht diese Aktion!</string>
|
||||
</resources>
|
|
@ -124,6 +124,8 @@
|
|||
<string name="confirm_remove_account">remove account from list?</string>
|
||||
<string name="account_user_id_prefix" translatable="false">User ID:</string>
|
||||
<string name="account_user_unnamed">\'unnamed\'</string>
|
||||
<string name="toolbar_tweet_favoriter">User favoriting this tweet</string>
|
||||
<string name="toolbar_tweet_liker">User liking this tweet</string>
|
||||
|
||||
<!-- toast messages to inform user -->
|
||||
<string name="info_user_removed">User removed from list</string>
|
||||
|
@ -163,6 +165,7 @@
|
|||
<string name="info_permission_read">Read permission needed to access images and videos.</string>
|
||||
<string name="info_permission_location">Location permission only needed to add location information to tweets.</string>
|
||||
<string name="info_permission_write">Write permission used to store images.</string>
|
||||
<string name="info_restart_app_on_change">restarting required to apply changes</string>
|
||||
<string name="info_error">Error</string>
|
||||
|
||||
<!-- toast messages for error information -->
|
||||
|
@ -205,6 +208,7 @@
|
|||
<string name="error_result_cancelled">Error, result cancelled!</string>
|
||||
<string name="error_twitter_search">Error, search query is too long or contains illegal characters!</string>
|
||||
<string name="error_not_defined">Not specified error!</string>
|
||||
<string name="error_forbidden_api_access">API does not support this operation!</string>
|
||||
|
||||
<!-- menu icon strings -->
|
||||
<string name="menu_tweet">write Tweet</string>
|
||||
|
@ -246,7 +250,6 @@
|
|||
<string name="dialog_button_ok">OK</string>
|
||||
<string name="dialog_link_image_preview">Link preview image</string>
|
||||
<string name="dialog_link_close">close link preview</string>
|
||||
<string name="info_restart_app_on_change">restarting required to apply changes</string>
|
||||
<string name="app_info_icons">svg icons from:</string>
|
||||
<string name="app_info_icons_links" translatable="false">www.svgrepo.com www.entypo.com</string>
|
||||
|
||||
|
|
Loading…
Reference in New Issue