added initial mastodon implementation, code cleanup, renamed classes and methods, strings update

This commit is contained in:
nuclearfog 2022-11-20 12:02:47 +01:00
parent aea55068af
commit 67d83ca93e
No known key found for this signature in database
GPG Key ID: 03488A185C476379
27 changed files with 864 additions and 381 deletions

View File

@ -7,6 +7,7 @@ import org.nuclearfog.twidda.backend.update.MediaUpdate;
import org.nuclearfog.twidda.backend.update.ProfileUpdate; import org.nuclearfog.twidda.backend.update.ProfileUpdate;
import org.nuclearfog.twidda.backend.update.StatusUpdate; import org.nuclearfog.twidda.backend.update.StatusUpdate;
import org.nuclearfog.twidda.backend.update.UserListUpdate; import org.nuclearfog.twidda.backend.update.UserListUpdate;
import org.nuclearfog.twidda.model.Account;
import org.nuclearfog.twidda.model.Location; import org.nuclearfog.twidda.model.Location;
import org.nuclearfog.twidda.model.Metrics; import org.nuclearfog.twidda.model.Metrics;
import org.nuclearfog.twidda.model.Relation; import org.nuclearfog.twidda.model.Relation;
@ -24,6 +25,21 @@ import java.util.List;
* @author nuclearfog * @author nuclearfog
*/ */
public interface Connection { public interface Connection {
/**
* create authorisation link to open the login page of the social network
*
* @param paramsStr see javadoc of the implementations
* @return authorisation link to open in a browser
*/
String getAuthorisationLink(String... paramsStr) throws ConnectionException;
/**
* @param paramsStr see javadoc of the implementations
* @return account information of the created login
*/
Account loginApp(String... paramsStr) throws ConnectionException;
/** /**
* lookup user and return user information * lookup user and return user information
* *

View File

@ -2,6 +2,7 @@ package org.nuclearfog.twidda.backend.api;
import android.content.Context; import android.content.Context;
import org.nuclearfog.twidda.backend.api.mastodon.Mastodon;
import org.nuclearfog.twidda.backend.api.twitter.Twitter; import org.nuclearfog.twidda.backend.api.twitter.Twitter;
import org.nuclearfog.twidda.database.GlobalSettings; import org.nuclearfog.twidda.database.GlobalSettings;
import org.nuclearfog.twidda.database.GlobalSettings.OnSettingsChangeListener; import org.nuclearfog.twidda.database.GlobalSettings.OnSettingsChangeListener;
@ -20,10 +21,15 @@ public class ConnectionManager {
public static final int SELECT_AUTO = 0; public static final int SELECT_AUTO = 0;
/** /**
* force using Twitter connection * select Twitter connection
*/ */
public static final int SELECT_TWITTER = 1; public static final int SELECT_TWITTER = 1;
/**
* select Mastodon connection
*/
public static final int SELECT_MASTODON = 2;
private static Connection connection; private static Connection connection;
private static boolean notifySettingsChange = false; private static boolean notifySettingsChange = false;
@ -54,9 +60,13 @@ public class ConnectionManager {
if (select == SELECT_TWITTER) { if (select == SELECT_TWITTER) {
connection = new Twitter(context); connection = new Twitter(context);
} }
// create Mastodon isntance
else if (select == SELECT_MASTODON) {
connection = new Mastodon(context);
}
// select automatically // select automatically
else { else {
if (settings.getApiId() == Account.API_TWITTER) { if (settings.getLogin().getApiType() == Account.API_TWITTER) {
connection = new Twitter(context); connection = new Twitter(context);
} else { } else {
throw new RuntimeException("no connection selected!"); throw new RuntimeException("no connection selected!");

View File

@ -0,0 +1,363 @@
package org.nuclearfog.twidda.backend.api.mastodon;
import android.content.Context;
import org.nuclearfog.twidda.backend.api.Connection;
import org.nuclearfog.twidda.backend.lists.Messages;
import org.nuclearfog.twidda.backend.lists.UserLists;
import org.nuclearfog.twidda.backend.lists.Users;
import org.nuclearfog.twidda.backend.update.MediaUpdate;
import org.nuclearfog.twidda.backend.update.ProfileUpdate;
import org.nuclearfog.twidda.backend.update.StatusUpdate;
import org.nuclearfog.twidda.backend.update.UserListUpdate;
import org.nuclearfog.twidda.backend.utils.ConnectionBuilder;
import org.nuclearfog.twidda.database.GlobalSettings;
import org.nuclearfog.twidda.model.Account;
import org.nuclearfog.twidda.model.Location;
import org.nuclearfog.twidda.model.Metrics;
import org.nuclearfog.twidda.model.Relation;
import org.nuclearfog.twidda.model.Status;
import org.nuclearfog.twidda.model.Trend;
import org.nuclearfog.twidda.model.User;
import org.nuclearfog.twidda.model.UserList;
import java.io.InputStream;
import java.util.List;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
/**
* Implementation of the Mastodon API
*
* @author nuclearfog
*/
public class Mastodon implements Connection {
MediaType mediaType = MediaType.parse("text/plain");
private GlobalSettings settings;
private OkHttpClient client;
public Mastodon(Context context) {
settings = GlobalSettings.getInstance(context);
client = ConnectionBuilder.create(context, 0);
}
public String getAuthorisationLink(String... paramsStr) throws MastodonException {
return "";
}
public Account loginApp(String... paramsStr) throws MastodonException {
return null;
}
@Override
public User showUser(long id) throws MastodonException {
return null;
}
@Override
public User showUser(String name) throws MastodonException {
return null;
}
@Override
public Users searchUsers(String search, long page) throws MastodonException {
return null;
}
@Override
public Users getRepostingUsers(long id) throws MastodonException {
return null;
}
@Override
public Users getFavoritingUsers(long id) throws MastodonException {
return null;
}
@Override
public Users getFollowing(long id, long cursor) throws MastodonException {
return null;
}
@Override
public Users getFollower(long id, long cursor) throws MastodonException {
return null;
}
@Override
public Users getListMember(long id, long cursor) throws MastodonException {
return null;
}
@Override
public Users getListSubscriber(long id, long cursor) throws MastodonException {
return null;
}
@Override
public Users getBlockedUsers(long cursor) throws MastodonException {
return null;
}
@Override
public Users getMutedUsers(long cursor) throws MastodonException {
return null;
}
@Override
public Users getIncomingFollowRequests(long cursor) throws MastodonException {
return null;
}
@Override
public Users getOutgoingFollowRequests(long cursor) throws MastodonException {
return null;
}
@Override
public Relation getUserRelationship(long id) throws MastodonException {
return null;
}
@Override
public User followUser(long id) throws MastodonException {
return null;
}
@Override
public User unfollowUser(long id) throws MastodonException {
return null;
}
@Override
public User blockUser(long id) throws MastodonException {
return null;
}
@Override
public User blockUser(String name) throws MastodonException {
return null;
}
@Override
public User unblockUser(long id) throws MastodonException {
return null;
}
@Override
public User muteUser(long id) throws MastodonException {
return null;
}
@Override
public User muteUser(String name) throws MastodonException {
return null;
}
@Override
public User unmuteUser(long id) throws MastodonException {
return null;
}
@Override
public List<Status> searchStatuses(String search, long minId, long maxId) throws MastodonException {
return null;
}
@Override
public List<Trend> getTrends(int id) throws MastodonException {
return null;
}
@Override
public List<Location> getLocations() throws MastodonException {
return null;
}
@Override
public List<Status> getHomeTimeline(long minId, long maxId) throws MastodonException {
return null;
}
@Override
public List<Status> getMentionTimeline(long minId, long maxId) throws MastodonException {
return null;
}
@Override
public List<Status> getUserTimeline(long id, long minId, long maxId) throws MastodonException {
return null;
}
@Override
public List<Status> getUserTimeline(String name, long minId, long maxId) throws MastodonException {
return null;
}
@Override
public List<Status> getUserFavorits(long id, long minId, long maxId) throws MastodonException {
return null;
}
@Override
public List<Status> getUserFavorits(String name, long minId, long maxId) throws MastodonException {
return null;
}
@Override
public List<Status> getUserlistStatuses(long id, long minId, long maxId) throws MastodonException {
return null;
}
@Override
public List<Status> getStatusReplies(String name, long id, long minId, long maxId) throws MastodonException {
return null;
}
@Override
public Status showStatus(long id) throws MastodonException {
return null;
}
@Override
public Status favoriteStatus(long id) throws MastodonException {
return null;
}
@Override
public Status unfavoriteStatus(long id) throws MastodonException {
return null;
}
@Override
public Status repostStatus(long id) throws MastodonException {
return null;
}
@Override
public Status removeRepost(long id) throws MastodonException {
return null;
}
@Override
public void hideReply(long id, boolean hide) throws MastodonException {
}
@Override
public void deleteStatus(long id) throws MastodonException {
}
@Override
public void uploadStatus(StatusUpdate update, long[] mediaIds) throws MastodonException {
}
@Override
public UserList createUserlist(UserListUpdate update) throws MastodonException {
return null;
}
@Override
public UserList updateUserlist(UserListUpdate update) throws MastodonException {
return null;
}
@Override
public UserList getUserlist(long id) throws MastodonException {
return null;
}
@Override
public UserList followUserlist(long id) throws MastodonException {
return null;
}
@Override
public UserList unfollowUserlist(long id) throws MastodonException {
return null;
}
@Override
public UserList deleteUserlist(long id) throws MastodonException {
return null;
}
@Override
public UserLists getUserlistOwnerships(long id, String name, long cursor) throws MastodonException {
return null;
}
@Override
public UserLists getUserlistMemberships(long id, String name, long cursor) throws MastodonException {
return null;
}
@Override
public void addUserToList(long id, String name) throws MastodonException {
}
@Override
public void removeUserFromList(long id, String name) throws MastodonException {
}
@Override
public void sendDirectmessage(long id, String message, long mediaId) throws MastodonException {
}
@Override
public void deleteDirectmessage(long id) throws MastodonException {
}
@Override
public Messages getDirectmessages(String cursor) throws MastodonException {
return null;
}
@Override
public Metrics getStatusMetrics(long id) throws MastodonException {
return null;
}
@Override
public List<Long> getIdBlocklist() throws MastodonException {
return null;
}
@Override
public MediaUpdate downloadImage(String link) throws MastodonException {
return null;
}
@Override
public User updateProfile(ProfileUpdate update) throws MastodonException {
return null;
}
@Override
public void updateProfileImage(InputStream inputStream) throws MastodonException {
}
@Override
public void updateBannerImage(InputStream inputStream) throws MastodonException {
}
@Override
public long uploadMedia(MediaUpdate mediaUpdate) throws MastodonException {
return 0;
}
}

View File

@ -0,0 +1,30 @@
package org.nuclearfog.twidda.backend.api.mastodon;
import org.nuclearfog.twidda.backend.api.ConnectionException;
/**
* custom exception used by {@link Mastodon} class
*
* @author nuclearfog
*/
public class MastodonException extends ConnectionException {
private static final long serialVersionUID = 3077198050626279691L;
public MastodonException(Exception e) {
super(e);
}
@Override
public int getErrorCode() {
return 0;
}
@Override
public int getTimeToWait() {
return 0;
}
}

View File

@ -0,0 +1,87 @@
package org.nuclearfog.twidda.backend.api.mastodon.impl;
import androidx.annotation.Nullable;
import org.nuclearfog.twidda.model.Account;
import org.nuclearfog.twidda.model.User;
/**
* implementation of a mastodon account
*
* @author nuclearfog
*/
public class MastodonAccount implements Account {
private long id;
private long createdAt;
private String hostname;
private String bearer;
private String client_id, client_secret;
private User user;
public MastodonAccount() {
}
@Override
public long getId() {
return id;
}
@Override
public long getLoginDate() {
return createdAt;
}
@Nullable
@Override
public User getUser() {
return user;
}
@Override
public String getConsumerToken() {
return client_id;
}
@Override
public String getConsumerSecret() {
return client_secret;
}
@Override
public String getOauthToken() {
return "";
}
@Override
public String getOauthSecret() {
return "";
}
@Override
public String getBearerToken() {
return bearer;
}
@Override
public String getHostname() {
return hostname;
}
@Override
public int getApiType() {
return API_MASTODON;
}
}

View File

@ -60,7 +60,7 @@ public class Tokens {
*/ */
public String getConsumerKey(boolean forceDefault) { public String getConsumerKey(boolean forceDefault) {
if (settings.isCustomApiSet() && !forceDefault) if (settings.isCustomApiSet() && !forceDefault)
return settings.getConsumerKey(); return settings.getLogin().getConsumerToken();
return CONSUMER_TOKEN; return CONSUMER_TOKEN;
} }
@ -72,7 +72,7 @@ public class Tokens {
*/ */
public String getConsumerSecret(boolean forceDefault) { public String getConsumerSecret(boolean forceDefault) {
if (settings.isCustomApiSet() && !forceDefault) if (settings.isCustomApiSet() && !forceDefault)
return settings.getConsumerSecret(); return settings.getLogin().getConsumerSecret();
return TOKEN_SECRET; return TOKEN_SECRET;
} }
} }

View File

@ -11,13 +11,13 @@ import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.nuclearfog.twidda.BuildConfig; import org.nuclearfog.twidda.BuildConfig;
import org.nuclearfog.twidda.backend.api.Connection; import org.nuclearfog.twidda.backend.api.Connection;
import org.nuclearfog.twidda.backend.api.twitter.impl.AccountV1;
import org.nuclearfog.twidda.backend.api.twitter.impl.LocationV1; import org.nuclearfog.twidda.backend.api.twitter.impl.LocationV1;
import org.nuclearfog.twidda.backend.api.twitter.impl.MessageV1; import org.nuclearfog.twidda.backend.api.twitter.impl.MessageV1;
import org.nuclearfog.twidda.backend.api.twitter.impl.MetricsV2; import org.nuclearfog.twidda.backend.api.twitter.impl.MetricsV2;
import org.nuclearfog.twidda.backend.api.twitter.impl.RelationV1; import org.nuclearfog.twidda.backend.api.twitter.impl.RelationV1;
import org.nuclearfog.twidda.backend.api.twitter.impl.TrendV1; import org.nuclearfog.twidda.backend.api.twitter.impl.TrendV1;
import org.nuclearfog.twidda.backend.api.twitter.impl.TweetV1; import org.nuclearfog.twidda.backend.api.twitter.impl.TweetV1;
import org.nuclearfog.twidda.backend.api.twitter.impl.TwitterAccount;
import org.nuclearfog.twidda.backend.api.twitter.impl.UserListV1; import org.nuclearfog.twidda.backend.api.twitter.impl.UserListV1;
import org.nuclearfog.twidda.backend.api.twitter.impl.UserV1; import org.nuclearfog.twidda.backend.api.twitter.impl.UserV1;
import org.nuclearfog.twidda.backend.api.twitter.impl.UserV2; import org.nuclearfog.twidda.backend.api.twitter.impl.UserV2;
@ -184,17 +184,17 @@ public class Twitter implements Connection {
} }
/** /**
* request temporary access token to pass it to the Twitter login page * create authorisation link
* *
* @param consumerKey API key or empty to use default * @param params optional string parameters containing oauth token, token secret
* @param consumerSecret API secret or empty to use default
* @return a temporary oauth token created by Twitter * @return a temporary oauth token created by Twitter
*/ */
public String getRequestToken(String consumerKey, String consumerSecret) throws TwitterException { @Override
public String getAuthorisationLink(String... params) throws TwitterException {
try { try {
Response response; Response response;
if (consumerKey != null && !consumerKey.isEmpty() && consumerSecret != null && !consumerSecret.isEmpty()) if (params.length == 2)
response = post(REQUEST_TOKEN, new ArrayList<>(), consumerKey, consumerSecret); response = post(REQUEST_TOKEN, new ArrayList<>(), params[0], params[1]);
else else
response = post(REQUEST_TOKEN, new ArrayList<>(), tokens.getConsumerKey(true), tokens.getConsumerSecret(true)); response = post(REQUEST_TOKEN, new ArrayList<>(), tokens.getConsumerKey(true), tokens.getConsumerSecret(true));
ResponseBody body = response.body(); ResponseBody body = response.body();
@ -202,7 +202,8 @@ public class Twitter implements Connection {
String res = body.string(); String res = body.string();
// extract oauth_token from url // extract oauth_token from url
Uri uri = Uri.parse(AUTHENTICATE + "?" + res); Uri uri = Uri.parse(AUTHENTICATE + "?" + res);
return uri.getQueryParameter("oauth_token"); String requestToken = uri.getQueryParameter("oauth_token");
return Twitter.AUTHENTICATE + "?oauth_token=" + requestToken;
} }
throw new TwitterException(response); throw new TwitterException(response);
} catch (IOException e) { } catch (IOException e) {
@ -213,18 +214,18 @@ public class Twitter implements Connection {
/** /**
* login to twitter using pin and add store access tokens * login to twitter using pin and add store access tokens
* *
* @param tempOauthToken temporary oauth token * @param paramsStr parameters (oauth pin & authorisation link required, oauth token, token secret optional)
* @param pin pin from the login website
* @param consumerKeys API keys or empty to use default
*/ */
public Account login(String tempOauthToken, String pin, String... consumerKeys) throws TwitterException { @Override
public Account loginApp(String... paramsStr) throws TwitterException {
try { try {
List<String> params = new ArrayList<>(); List<String> params = new ArrayList<>();
params.add("oauth_verifier=" + pin); String oauthToken = Uri.parse(paramsStr[0]).getQueryParameter("oauth_token");
params.add("oauth_token=" + tempOauthToken); params.add("oauth_verifier=" + paramsStr[1]);
params.add("oauth_token=" + oauthToken);
Response response; Response response;
if (consumerKeys.length == 2) if (paramsStr.length == 4)
response = post(OAUTH_VERIFIER, params, consumerKeys[0], consumerKeys[1]); response = post(OAUTH_VERIFIER, params, paramsStr[2], paramsStr[3]);
else else
response = post(OAUTH_VERIFIER, params, tokens.getConsumerKey(true), tokens.getConsumerSecret(true)); response = post(OAUTH_VERIFIER, params, tokens.getConsumerKey(true), tokens.getConsumerSecret(true));
ResponseBody body = response.body(); ResponseBody body = response.body();
@ -232,26 +233,20 @@ public class Twitter implements Connection {
// extract tokens from link // extract tokens from link
String res = body.string(); String res = body.string();
Uri uri = Uri.parse(OAUTH_VERIFIER + "?" + res); Uri uri = Uri.parse(OAUTH_VERIFIER + "?" + res);
String oauthToken = uri.getQueryParameter("oauth_token"); oauthToken = uri.getQueryParameter("oauth_token");
String tokenSecret = uri.getQueryParameter("oauth_token_secret"); String tokenSecret = uri.getQueryParameter("oauth_token_secret");
// check if login works // check if login works
User user; User user;
Account account; Account account;
if (consumerKeys.length == 2) { // use custom API keys if (paramsStr.length == 4) { // use custom API keys
user = getCredentials(consumerKeys[0], consumerKeys[1], oauthToken, tokenSecret); user = getCredentials(paramsStr[2], paramsStr[3], oauthToken, tokenSecret);
account = new AccountV1(oauthToken, tokenSecret, consumerKeys[0], consumerKeys[1], user); account = new TwitterAccount(oauthToken, tokenSecret, paramsStr[2], paramsStr[3], user);
settings.setCustomAPI(consumerKeys[0], consumerKeys[1]);
} else { // use default API keys } else { // use default API keys
user = getCredentials(tokens.getConsumerKey(true), tokens.getConsumerSecret(true), oauthToken, tokenSecret); user = getCredentials(tokens.getConsumerKey(true), tokens.getConsumerSecret(true), oauthToken, tokenSecret);
account = new AccountV1(oauthToken, tokenSecret, user); account = new TwitterAccount(oauthToken, tokenSecret, user);
settings.removeCustomAPI();
} }
// save login credentials // save login credentials
settings.setAccessToken(oauthToken); settings.setLogin(account, false);
settings.setTokenSecret(tokenSecret);
settings.setUserId(user.getId());
settings.setLogin(true);
return account; return account;
} }
throw new TwitterException(response); throw new TwitterException(response);
@ -400,7 +395,7 @@ public class Twitter implements Connection {
@Override @Override
public Relation getUserRelationship(long id) throws TwitterException { public Relation getUserRelationship(long id) throws TwitterException {
List<String> params = new ArrayList<>(); List<String> params = new ArrayList<>();
params.add("source_id=" + settings.getCurrentUserId()); params.add("source_id=" + settings.getLogin().getId());
params.add("target_id=" + id); params.add("target_id=" + id);
try { try {
Response response = get(RELATION, params); Response response = get(RELATION, params);
@ -1037,7 +1032,8 @@ public class Twitter implements Connection {
params.add("command=STATUS"); params.add("command=STATUS");
params.add("media_id=" + mediaId); params.add("media_id=" + mediaId);
// poll media processing information frequently // poll media processing information frequently
do { do
{
response = get(MEDIA_UPLOAD, params); response = get(MEDIA_UPLOAD, params);
body = response.body(); body = response.body();
if (response.code() < 200 || response.code() >= 300 || body == null) if (response.code() < 200 || response.code() >= 300 || body == null)
@ -1172,7 +1168,7 @@ public class Twitter implements Connection {
array = new JSONObject(body.string()).getJSONArray("statuses"); array = new JSONObject(body.string()).getJSONArray("statuses");
else else
array = new JSONArray(body.string()); array = new JSONArray(body.string());
long homeId = settings.getCurrentUserId(); long homeId = settings.getLogin().getId();
List<Status> tweets = new ArrayList<>(array.length() + 1); List<Status> tweets = new ArrayList<>(array.length() + 1);
for (int i = 0; i < array.length(); i++) { for (int i = 0; i < array.length(); i++) {
try { try {
@ -1211,8 +1207,7 @@ public class Twitter implements Connection {
ResponseBody body = response.body(); ResponseBody body = response.body();
if (body != null && response.code() == 200) { if (body != null && response.code() == 200) {
JSONObject json = new JSONObject(body.string()); JSONObject json = new JSONObject(body.string());
long currentId = settings.getCurrentUserId(); TweetV1 result = new TweetV1(json, settings.getLogin().getId());
TweetV1 result = new TweetV1(json, currentId);
// fix: embedded tweet information doesn't match with the parent tweet // fix: embedded tweet information doesn't match with the parent tweet
// re-downloading embedded tweet information // re-downloading embedded tweet information
if (result.getEmbeddedStatus() != null) { if (result.getEmbeddedStatus() != null) {
@ -1304,7 +1299,7 @@ public class Twitter implements Connection {
long prevCursor = Long.parseLong(json.optString("previous_cursor_str", "0")); long prevCursor = Long.parseLong(json.optString("previous_cursor_str", "0"));
long nextCursor = Long.parseLong(json.optString("next_cursor_str", "0")); long nextCursor = Long.parseLong(json.optString("next_cursor_str", "0"));
Users users = new Users(prevCursor, nextCursor); Users users = new Users(prevCursor, nextCursor);
long homeId = settings.getCurrentUserId(); long homeId = settings.getLogin().getId();
for (int i = 0; i < array.length(); i++) { for (int i = 0; i < array.length(); i++) {
try { try {
users.add(new UserV1(array.getJSONObject(i), homeId)); users.add(new UserV1(array.getJSONObject(i), homeId));
@ -1340,7 +1335,7 @@ public class Twitter implements Connection {
// check if result is not empty // check if result is not empty
if (json.has("data")) { if (json.has("data")) {
JSONArray array = json.getJSONArray("data"); JSONArray array = json.getJSONArray("data");
long homeId = settings.getCurrentUserId(); long homeId = settings.getLogin().getId();
for (int i = 0; i < array.length(); i++) { for (int i = 0; i < array.length(); i++) {
try { try {
users.add(new UserV2(array.getJSONObject(i), homeId)); users.add(new UserV2(array.getJSONObject(i), homeId));
@ -1378,8 +1373,7 @@ public class Twitter implements Connection {
ResponseBody body = response.body(); ResponseBody body = response.body();
if (body != null && response.code() == 200) { if (body != null && response.code() == 200) {
JSONObject json = new JSONObject(body.string()); JSONObject json = new JSONObject(body.string());
long currentId = settings.getCurrentUserId(); return new UserV1(json, settings.getLogin().getId());
return new UserV1(json, currentId);
} }
throw new TwitterException(response); throw new TwitterException(response);
} catch (IOException | JSONException err) { } catch (IOException | JSONException err) {
@ -1404,8 +1398,7 @@ public class Twitter implements Connection {
ResponseBody body = response.body(); ResponseBody body = response.body();
if (body != null && response.code() == 200) { if (body != null && response.code() == 200) {
JSONObject json = new JSONObject(body.string()); JSONObject json = new JSONObject(body.string());
long currentId = settings.getCurrentUserId(); return new UserListV1(json, settings.getLogin().getId());
return new UserListV1(json, currentId);
} }
throw new TwitterException(response); throw new TwitterException(response);
} catch (IOException | JSONException err) { } catch (IOException | JSONException err) {
@ -1440,7 +1433,7 @@ public class Twitter implements Connection {
array = new JSONArray(bodyStr); array = new JSONArray(bodyStr);
result = new UserLists(0L, 0L); result = new UserLists(0L, 0L);
} }
long currentId = settings.getCurrentUserId(); long currentId = settings.getLogin().getId();
for (int pos = 0; pos < array.length(); pos++) { for (int pos = 0; pos < array.length(); pos++) {
try { try {
result.add(new UserListV1(array.getJSONObject(pos), currentId)); result.add(new UserListV1(array.getJSONObject(pos), currentId));
@ -1689,8 +1682,8 @@ public class Twitter implements Connection {
oauthToken = keys[2]; oauthToken = keys[2];
tokenSecret = keys[3]; tokenSecret = keys[3];
} else { } else {
oauthToken = settings.getAccessToken(); oauthToken = settings.getLogin().getOauthToken();
tokenSecret = settings.getTokenSecret(); tokenSecret = settings.getLogin().getOauthSecret();
} }
String signkey = consumerSecret + "&"; String signkey = consumerSecret + "&";
// init default parameters // init default parameters

View File

@ -201,6 +201,12 @@ public class TweetV1 implements Status {
return favoriteCount; return favoriteCount;
} }
@Override
public int getReplyCount() {
// not implemented in API V1.1
return 0;
}
@NonNull @NonNull
@Override @Override
public Uri[] getMediaUris() { public Uri[] getMediaUris() {

View File

@ -9,12 +9,12 @@ import org.nuclearfog.twidda.model.User;
* *
* @author nuclearfog * @author nuclearfog
*/ */
public class AccountV1 implements Account { public class TwitterAccount implements Account {
private long date; private long date;
private String oauthToken, tokenSecret; private String oauthToken, oauthSecret;
private String apiKey, apiSec; private String consumerToken, consumerSecret;
private User user; private User user;
@ -23,66 +23,81 @@ public class AccountV1 implements Account {
* @param tokenSecret oauth token secret * @param tokenSecret oauth token secret
* @param user user information * @param user user information
*/ */
public AccountV1(String oauthToken, String tokenSecret, User user) { public TwitterAccount(String oauthToken, String tokenSecret, User user) {
this(oauthToken, tokenSecret, "", "", user); this(oauthToken, tokenSecret, "", "", user);
} }
/** /**
* @param apiKey API consumer token * @param consumerToken API consumer token
* @param apiSec API consumer secret * @param consumerSecret API consumer secret
* @param oauthToken oauth access token * @param oauthToken oauth access token
* @param tokenSecret oauth token secret * @param tokenSecret oauth token secret
* @param user user information * @param user user information
*/ */
public AccountV1(String oauthToken, String tokenSecret, String apiKey, String apiSec, User user) { public TwitterAccount(String oauthToken, String tokenSecret, String consumerToken, String consumerSecret, User user) {
this.oauthToken = oauthToken; this.oauthToken = oauthToken;
this.tokenSecret = tokenSecret; this.oauthSecret = tokenSecret;
this.apiKey = apiKey; this.consumerToken = consumerToken;
this.apiSec = apiSec; this.consumerSecret = consumerSecret;
this.user = user; this.user = user;
date = System.currentTimeMillis(); date = System.currentTimeMillis();
} }
@Override @Override
public long getId() { public long getId() {
return user.getId(); return user.getId();
} }
@Override @Override
public long getLoginDate() { public long getLoginDate() {
return date; return date;
} }
@Override @Override
public User getUser() { public User getUser() {
return user; return user;
} }
@Override
public String getApiKey() {
return apiKey;
}
@Override @Override
public String getApiSecret() { public String getConsumerToken() {
return apiSec; return consumerToken;
} }
@Override @Override
public String getAccessToken() { public String getConsumerSecret() {
return consumerSecret;
}
@Override
public String getOauthToken() {
return oauthToken; return oauthToken;
} }
@Override @Override
public String getTokenSecret() { public String getOauthSecret() {
return tokenSecret; return oauthSecret;
} }
@Override
public String getBearerToken() {
return "";
}
@Override @Override
public String getHostname() { public String getHostname() {
return Twitter.API; return Twitter.API;
} }
@Override @Override
public int getApiType() { public int getApiType() {
return Account.API_TWITTER; return Account.API_TWITTER;

View File

@ -7,7 +7,6 @@ import androidx.annotation.Nullable;
import org.nuclearfog.twidda.backend.api.Connection; import org.nuclearfog.twidda.backend.api.Connection;
import org.nuclearfog.twidda.backend.api.ConnectionException; import org.nuclearfog.twidda.backend.api.ConnectionException;
import org.nuclearfog.twidda.backend.api.ConnectionManager; import org.nuclearfog.twidda.backend.api.ConnectionManager;
import org.nuclearfog.twidda.backend.api.twitter.Twitter;
import org.nuclearfog.twidda.database.AccountDatabase; import org.nuclearfog.twidda.database.AccountDatabase;
import org.nuclearfog.twidda.database.AppDatabase; import org.nuclearfog.twidda.database.AppDatabase;
import org.nuclearfog.twidda.model.Account; import org.nuclearfog.twidda.model.Account;
@ -26,12 +25,12 @@ public class LoginAction extends AsyncTask<String, Void, String> {
/** /**
* request login page * request login page
*/ */
public static final int MODE_REQUEST = 1; public static final int MODE_TWITTER_REQUEST = 1;
/** /**
* login with pin and ans save auth keys * login with pin and ans save auth keys
*/ */
public static final int MODE_LOGIN = 2; public static final int MODE_TWITTER_LOGIN = 2;
private WeakReference<LoginActivity> weakRef; private WeakReference<LoginActivity> weakRef;
private AccountDatabase accountDB; private AccountDatabase accountDB;
@ -63,28 +62,21 @@ public class LoginAction extends AsyncTask<String, Void, String> {
@Override @Override
protected String doInBackground(String... param) { protected String doInBackground(String... param) {
if (connection instanceof Twitter) { try {
try { switch (mode) {
Twitter twitter = (Twitter) connection; case MODE_TWITTER_REQUEST:
switch (mode) { return connection.getAuthorisationLink(param);
case MODE_REQUEST:
return twitter.getRequestToken(param[0], param[1]);
case MODE_LOGIN: case MODE_TWITTER_LOGIN:
// login with pin and access token // login with pin and access token
Account account; Account account = connection.loginApp(param);
if (param.length == 4) // save new user information
account = twitter.login(param[0], param[1], param[2], param[3]); database.saveUser(account.getUser());
else accountDB.saveLogin(account);
account = twitter.login(param[0], param[1]); return "";
// save new user information
database.saveUser(account.getUser());
accountDB.saveLogin(account);
return "";
}
} catch (ConnectionException exception) {
this.exception = exception;
} }
} catch (ConnectionException exception) {
this.exception = exception;
} }
return null; return null;
} }

View File

@ -53,12 +53,12 @@ public class AccountDatabase {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put(AccountTable.ID, account.getId()); values.put(AccountTable.ID, account.getId());
values.put(AccountTable.ACCESS_TOKEN, account.getAccessToken()); values.put(AccountTable.ACCESS_TOKEN, account.getOauthToken());
values.put(AccountTable.TOKEN_SECRET, account.getTokenSecret()); values.put(AccountTable.TOKEN_SECRET, account.getOauthSecret());
values.put(AccountTable.DATE, account.getLoginDate()); values.put(AccountTable.DATE, account.getLoginDate());
values.put(AccountTable.HOSTNAME, account.getHostname()); values.put(AccountTable.HOSTNAME, account.getHostname());
values.put(AccountTable.CLIENT_ID, account.getApiKey()); values.put(AccountTable.CLIENT_ID, account.getConsumerToken());
values.put(AccountTable.CLIENT_SECRET, account.getApiSecret()); values.put(AccountTable.CLIENT_SECRET, account.getConsumerSecret());
values.put(AccountTable.API, account.getApiType()); values.put(AccountTable.API, account.getApiType());
SQLiteDatabase db = dataHelper.getDatabase(); SQLiteDatabase db = dataHelper.getDatabase();
@ -80,7 +80,8 @@ public class AccountDatabase {
Cursor cursor = db.query(AccountTable.NAME, AccountImpl.COLUMNS, null, null, null, null, SORT_BY_CREATION); Cursor cursor = db.query(AccountTable.NAME, AccountImpl.COLUMNS, null, null, null, null, SORT_BY_CREATION);
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
result.ensureCapacity(cursor.getCount()); result.ensureCapacity(cursor.getCount());
do { do
{
AccountImpl account = new AccountImpl(cursor); AccountImpl account = new AccountImpl(cursor);
account.addUser(database.getUser(account.getId())); account.addUser(database.getUser(account.getId()));
result.add(account); result.add(account);

View File

@ -238,7 +238,7 @@ public class AppDatabase {
public AppDatabase(Context context) { public AppDatabase(Context context) {
adapter = DatabaseAdapter.getInstance(context); adapter = DatabaseAdapter.getInstance(context);
GlobalSettings settings = GlobalSettings.getInstance(context); GlobalSettings settings = GlobalSettings.getInstance(context);
homeId = settings.getCurrentUserId(); homeId = settings.getLogin().getId();
limit = settings.getListSize(); limit = settings.getListSize();
} }
@ -377,7 +377,8 @@ public class AppDatabase {
List<Status> result = new LinkedList<>(); List<Status> result = new LinkedList<>();
Cursor cursor = db.rawQuery(HOME_QUERY, args); Cursor cursor = db.rawQuery(HOME_QUERY, args);
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
do { do
{
Status status = getStatus(cursor); Status status = getStatus(cursor);
result.add(status); result.add(status);
} while (cursor.moveToNext()); } while (cursor.moveToNext());
@ -399,7 +400,8 @@ public class AppDatabase {
List<Status> result = new LinkedList<>(); List<Status> result = new LinkedList<>();
Cursor cursor = db.rawQuery(MENTION_QUERY, args); Cursor cursor = db.rawQuery(MENTION_QUERY, args);
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
do { do
{
Status status = getStatus(cursor); Status status = getStatus(cursor);
result.add(status); result.add(status);
} while (cursor.moveToNext()); } while (cursor.moveToNext());
@ -422,7 +424,8 @@ public class AppDatabase {
List<Status> result = new LinkedList<>(); List<Status> result = new LinkedList<>();
Cursor cursor = db.rawQuery(USER_STATUS_QUERY, args); Cursor cursor = db.rawQuery(USER_STATUS_QUERY, args);
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
do { do
{
Status status = getStatus(cursor); Status status = getStatus(cursor);
result.add(status); result.add(status);
} while (cursor.moveToNext()); } while (cursor.moveToNext());
@ -445,7 +448,8 @@ public class AppDatabase {
List<Status> result = new LinkedList<>(); List<Status> result = new LinkedList<>();
Cursor cursor = db.rawQuery(USERFAVORIT_QUERY, args); Cursor cursor = db.rawQuery(USERFAVORIT_QUERY, args);
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
do { do
{
Status status = getStatus(cursor); Status status = getStatus(cursor);
result.add(status); result.add(status);
} while (cursor.moveToNext()); } while (cursor.moveToNext());
@ -500,7 +504,8 @@ public class AppDatabase {
List<Status> result = new LinkedList<>(); List<Status> result = new LinkedList<>();
Cursor cursor = db.rawQuery(REPLY_QUERY, args); Cursor cursor = db.rawQuery(REPLY_QUERY, args);
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
do { do
{
Status status = getStatus(cursor); Status status = getStatus(cursor);
result.add(status); result.add(status);
} while (cursor.moveToNext()); } while (cursor.moveToNext());
@ -604,7 +609,8 @@ public class AppDatabase {
Cursor cursor = db.query(TrendTable.NAME, TrendImpl.COLUMNS, TREND_SELECT, args, null, null, TREND_ORDER); Cursor cursor = db.query(TrendTable.NAME, TrendImpl.COLUMNS, TREND_SELECT, args, null, null, TREND_ORDER);
List<Trend> trends = new LinkedList<>(); List<Trend> trends = new LinkedList<>();
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
do { do
{
trends.add(new TrendImpl(cursor)); trends.add(new TrendImpl(cursor));
} while (cursor.moveToNext()); } while (cursor.moveToNext());
} }
@ -625,7 +631,8 @@ public class AppDatabase {
Map<Long, User> userCache = new TreeMap<>(); Map<Long, User> userCache = new TreeMap<>();
Cursor cursor = db.rawQuery(MESSAGE_QUERY, args); Cursor cursor = db.rawQuery(MESSAGE_QUERY, args);
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
do { do
{
User sender, receiver; User sender, receiver;
MessageImpl message = new MessageImpl(cursor); MessageImpl message = new MessageImpl(cursor);
if (userCache.containsKey(message.getSenderId())) { if (userCache.containsKey(message.getSenderId())) {

View File

@ -19,7 +19,7 @@ public class DatabaseAdapter {
/** /**
* database version * database version
*/ */
private static final int DB_VERSION = 7; private static final int DB_VERSION = 8;
/** /**
* database file name * database file name
@ -61,6 +61,7 @@ public class DatabaseAdapter {
+ StatusTable.MEDIA + " TEXT," + StatusTable.MEDIA + " TEXT,"
+ StatusTable.REPOST + " INTEGER," + StatusTable.REPOST + " INTEGER,"
+ StatusTable.FAVORITE + " INTEGER," + StatusTable.FAVORITE + " INTEGER,"
+ StatusTable.REPLY + " INTEGER,"
+ StatusTable.SOURCE + " TEXT," + StatusTable.SOURCE + " TEXT,"
+ StatusTable.PLACE + " TEXT," + StatusTable.PLACE + " TEXT,"
+ StatusTable.COORDINATE + " TEXT," + StatusTable.COORDINATE + " TEXT,"
@ -184,6 +185,11 @@ public class DatabaseAdapter {
*/ */
private static final String UPDATE_ADD_API_ID = "ALTER TABLE " + AccountTable.NAME + " ADD " + AccountTable.API + " INTEGER;"; private static final String UPDATE_ADD_API_ID = "ALTER TABLE " + AccountTable.NAME + " ADD " + AccountTable.API + " INTEGER;";
/**
* update account table to add API client secret
*/
private static final String UPDATE_ADD_REPLY_COUNT = "ALTER TABLE " + StatusTable.NAME + " ADD " + StatusTable.REPLY + " INTEGER;";
/** /**
* singleton instance * singleton instance
*/ */
@ -271,8 +277,12 @@ public class DatabaseAdapter {
db.execSQL(UPDATE_ADD_CLIENT_SEC); db.execSQL(UPDATE_ADD_CLIENT_SEC);
db.setVersion(6); db.setVersion(6);
} }
if (db.getVersion() < DB_VERSION) { if (db.getVersion() < 7) {
db.execSQL(UPDATE_ADD_API_ID); db.execSQL(UPDATE_ADD_API_ID);
db.setVersion(7);
}
if (db.getVersion() < DB_VERSION) {
db.execSQL(UPDATE_ADD_REPLY_COUNT);
db.setVersion(DB_VERSION); db.setVersion(DB_VERSION);
} }
} }
@ -392,6 +402,11 @@ public class DatabaseAdapter {
*/ */
String FAVORITE = "favorite"; String FAVORITE = "favorite";
/**
* reply count
*/
String REPLY = "reply";
/** /**
* timestamp of the status * timestamp of the status
*/ */

View File

@ -52,7 +52,7 @@ public class FilterDatabase {
* @param ids list of user IDs * @param ids list of user IDs
*/ */
public void setFilteredUserIds(List<Long> ids) { public void setFilteredUserIds(List<Long> ids) {
long homeId = settings.getCurrentUserId(); long homeId = settings.getLogin().getId();
String[] args = {Long.toString(homeId)}; String[] args = {Long.toString(homeId)};
SQLiteDatabase db = getDbWrite(); SQLiteDatabase db = getDbWrite();
@ -72,13 +72,14 @@ public class FilterDatabase {
* @return a set of user IDs * @return a set of user IDs
*/ */
public Set<Long> getFilteredUserIds() { public Set<Long> getFilteredUserIds() {
String[] args = {Long.toString(settings.getCurrentUserId())}; String[] args = {Long.toString(settings.getLogin().getId())};
SQLiteDatabase db = getDbRead(); SQLiteDatabase db = getDbRead();
Cursor cursor = db.query(UserExcludeTable.NAME, LIST_ID_COL, LIST_SELECT, args, null, null, null, null); Cursor cursor = db.query(UserExcludeTable.NAME, LIST_ID_COL, LIST_SELECT, args, null, null, null, null);
Set<Long> result = new TreeSet<>(); Set<Long> result = new TreeSet<>();
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
do { do
{
long id = cursor.getLong(0); long id = cursor.getLong(0);
result.add(id); result.add(id);
} while (cursor.moveToNext()); } while (cursor.moveToNext());
@ -96,7 +97,7 @@ public class FilterDatabase {
SQLiteDatabase db = getDbWrite(); SQLiteDatabase db = getDbWrite();
ContentValues column = new ContentValues(2); ContentValues column = new ContentValues(2);
column.put(UserExcludeTable.ID, userId); column.put(UserExcludeTable.ID, userId);
column.put(UserExcludeTable.OWNER, settings.getCurrentUserId()); column.put(UserExcludeTable.OWNER, settings.getLogin().getId());
db.insert(UserExcludeTable.NAME, null, column); db.insert(UserExcludeTable.NAME, null, column);
commit(db); commit(db);
} }
@ -107,7 +108,7 @@ public class FilterDatabase {
* @param userId ID of the user * @param userId ID of the user
*/ */
public void removeUser(long userId) { public void removeUser(long userId) {
String[] args = {Long.toString(settings.getCurrentUserId()), Long.toString(userId)}; String[] args = {Long.toString(settings.getLogin().getId()), Long.toString(userId)};
SQLiteDatabase db = getDbWrite(); SQLiteDatabase db = getDbWrite();
db.delete(UserExcludeTable.NAME, COLUMN_SELECT, args); db.delete(UserExcludeTable.NAME, COLUMN_SELECT, args);
commit(db); commit(db);

View File

@ -14,7 +14,9 @@ import android.graphics.Color;
import android.graphics.Typeface; import android.graphics.Typeface;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.nuclearfog.twidda.database.impl.AccountImpl;
import org.nuclearfog.twidda.database.impl.LocationImpl; import org.nuclearfog.twidda.database.impl.LocationImpl;
import org.nuclearfog.twidda.model.Account; import org.nuclearfog.twidda.model.Account;
import org.nuclearfog.twidda.model.Location; import org.nuclearfog.twidda.model.Location;
@ -116,16 +118,18 @@ public class GlobalSettings {
private static final String ENABLE_LIKE = "like_enable"; private static final String ENABLE_LIKE = "like_enable";
private static final String ENABLE_TWITTER_ALT = "twitter_alt_set"; private static final String ENABLE_TWITTER_ALT = "twitter_alt_set";
private static final String FILTER_RESULTS = "filter_results"; private static final String FILTER_RESULTS = "filter_results";
private static final String CUSTOM_CONSUMER_KEY_SET = "custom_api_keys"; private static final String CUSTOM_CONSUMER_KEYS = "custom_api_keys";
private static final String CUSTOM_CONSUMER_KEY_1 = "api_key1"; private static final String CONSUMER_TOKEN = "api_key1";
private static final String CUSTOM_CONSUMER_KEY_2 = "api_key2"; private static final String CONSUMER_SECRET = "api_key2";
private static final String BEARER_TOKEN = "bearer";
private static final String CURRENT_API = "current_api_id"; private static final String CURRENT_API = "current_api_id";
private static final String HOSTNAME = "mastodon_host";
// login specific preference names // login specific preference names
private static final String LOGGED_IN = "login"; private static final String LOGGED_IN = "login";
private static final String CURRENT_ID = "userID"; private static final String CURRENT_ID = "userID";
private static final String CURRENT_AUTH_KEY1 = "key1"; private static final String OAUTH_TOKEN = "key1";
private static final String CURRENT_AUTH_KEY2 = "key2"; private static final String OAUTH_SECRET = "key2";
// file name of the preferences // file name of the preferences
private static final String APP_SETTINGS = "settings"; private static final String APP_SETTINGS = "settings";
@ -146,12 +150,13 @@ public class GlobalSettings {
private static final int DEFAULT_FW_ICON_COLOR = Color.CYAN; private static final int DEFAULT_FW_ICON_COLOR = Color.CYAN;
private static final int DEFAULT_LOCATION_ID = 1; private static final int DEFAULT_LOCATION_ID = 1;
private static final String DEFAULT_LOCATION_NAME = "Worldwide"; private static final String DEFAULT_LOCATION_NAME = "Worldwide";
private static final String DEFAULT_MASTODON_HOST = "https://mastodon.social";
private SharedPreferences settings; private SharedPreferences settings;
private Location location; private Location location;
private String api_key1, api_key2; private Account account;
private String auth_key1, auth_key2;
private String proxyHost, proxyPort; private String proxyHost, proxyPort;
private String proxyUser, proxyPass; private String proxyUser, proxyPass;
private boolean loadImage; private boolean loadImage;
@ -181,8 +186,6 @@ public class GlobalSettings {
private int indexFont; private int indexFont;
private int indexScale; private int indexScale;
private int listSize; private int listSize;
private int apiId;
private long userId;
private List<OnSettingsChangeListener> settingsChangeListeners = new LinkedList<>(); private List<OnSettingsChangeListener> settingsChangeListeners = new LinkedList<>();
@ -751,9 +754,9 @@ public class GlobalSettings {
} }
/** /**
* set Twitter alternative link * enable alternative service to open tweet links (nitter.net)
* *
* @param enable true to enable alternative link * @param enable true to enable alternative service
*/ */
public void setTwitterAlt(boolean enable) { public void setTwitterAlt(boolean enable) {
twitterAlt = enable; twitterAlt = enable;
@ -764,7 +767,7 @@ public class GlobalSettings {
} }
/** /**
* get hostname of the Twitter service to use * get hostname to open tweet links
* *
* @return custom host domain name if alternative is set, otherwise default Twitter host * @return custom host domain name if alternative is set, otherwise default Twitter host
*/ */
@ -950,154 +953,6 @@ public class GlobalSettings {
return loggedIn; return loggedIn;
} }
/**
* set app login status
*
* @param login true if current user is logged in successfully
*/
public void setLogin(boolean login) {
loggedIn = login;
Editor e = settings.edit();
e.putBoolean(LOGGED_IN, login);
e.apply();
}
/**
* return access token of the current user
*
* @return first access token
*/
public String getAccessToken() {
return auth_key1;
}
/**
* set access token of the current user
*
* @param token first access token
*/
public void setAccessToken(String token) {
this.auth_key1 = token;
Editor e = settings.edit();
e.putString(CURRENT_AUTH_KEY1, token);
e.apply();
}
/**
* return second access token of the current user
*
* @return first access token
*/
public String getTokenSecret() {
return auth_key2;
}
/**
* set second access token of the current user
*
* @param token first access token
*/
public void setTokenSecret(String token) {
this.auth_key2 = token;
Editor e = settings.edit();
e.putString(CURRENT_AUTH_KEY2, token);
e.apply();
}
/**
* get Consumer keys
*
* @return key string
*/
public String getConsumerKey() {
return api_key1;
}
/**
* get consumer key secret
*
* @return key string
*/
public String getConsumerSecret() {
return api_key2;
}
/**
* set ID of the current used API
*
* @param apiId Id to identify current used API
*/
public void setApiId(int apiId) {
this.apiId = apiId;
Editor e = settings.edit();
e.putInt(CURRENT_API, apiId);
e.apply();
}
/**
* get current API ID
*
* @return API ID
*/
public int getApiId() {
return apiId;
}
/**
* get current users ID
*
* @return User ID
*/
public long getCurrentUserId() {
return userId;
}
/**
* set current user ID
*
* @param userId current user ID
*/
public void setUserId(long userId) {
this.userId = userId;
Editor e = settings.edit();
e.putLong(CURRENT_ID, userId);
e.apply();
}
/**
* sets custom API consumer keys
*
* @param key1 consumer key
* @param key2 consumer key secret
*/
public void setCustomAPI(String key1, String key2) {
customAPIKey = true;
this.api_key1 = key1;
this.api_key2 = key2;
Editor e = settings.edit();
e.putBoolean(CUSTOM_CONSUMER_KEY_SET, true);
e.putString(CUSTOM_CONSUMER_KEY_1, key1);
e.putString(CUSTOM_CONSUMER_KEY_2, key2);
e.apply();
}
/**
* remove all API keys
*/
public void removeCustomAPI() {
customAPIKey = false;
this.api_key1 = "";
this.api_key2 = "";
Editor e = settings.edit();
e.remove(CUSTOM_CONSUMER_KEY_SET);
e.remove(CUSTOM_CONSUMER_KEY_1);
e.remove(CUSTOM_CONSUMER_KEY_2);
e.apply();
}
/** /**
* check if custom API consumer keys are set * check if custom API consumer keys are set
* *
@ -1108,22 +963,56 @@ public class GlobalSettings {
} }
/** /**
* clear user specific settings * get login information
*
* @return current account
*/ */
public void logout() { public Account getLogin() {
loggedIn = false; return account;
auth_key1 = "";
auth_key2 = "";
userId = 0;
Editor e = settings.edit();
e.remove(LOGGED_IN);
e.remove(CURRENT_AUTH_KEY1);
e.remove(CURRENT_AUTH_KEY2);
e.remove(CURRENT_ID);
e.apply();
notifySettingsChange();
} }
/**
* save login information
*
* @param account account information
* @param notify true to notify that settings changed
*/
public void setLogin(@Nullable Account account, boolean notify) {
Editor e = settings.edit();
if (account == null) {
loggedIn = false;
customAPIKey = false;
e.remove(LOGGED_IN);
e.remove(CUSTOM_CONSUMER_KEYS);
e.remove(CURRENT_ID);
e.remove(OAUTH_TOKEN);
e.remove(OAUTH_SECRET);
e.remove(CONSUMER_TOKEN);
e.remove(CONSUMER_SECRET);
e.remove(BEARER_TOKEN);
e.remove(HOSTNAME);
} else {
this.account = account;
loggedIn = true;
customAPIKey = !account.getConsumerToken().isEmpty() && !account.getConsumerToken().isEmpty();
e.putBoolean(LOGGED_IN, true);
e.putBoolean(CUSTOM_CONSUMER_KEYS, customAPIKey);
e.putLong(CURRENT_ID, account.getId());
e.putString(OAUTH_TOKEN, account.getOauthToken());
e.putString(OAUTH_SECRET, account.getOauthSecret());
e.putString(CONSUMER_TOKEN, account.getConsumerToken());
e.putString(CONSUMER_SECRET, account.getConsumerSecret());
e.putString(BEARER_TOKEN, account.getBearerToken());
e.putString(HOSTNAME, account.getHostname());
}
e.apply();
if (notify) {
notifySettingsChange();
}
}
/** /**
* register settings listener * register settings listener
* changes like new proxy settings requires re initialization * changes like new proxy settings requires re initialization
@ -1163,7 +1052,6 @@ public class GlobalSettings {
indexFont = settings.getInt(INDEX_FONT, DEFAULT_FONT_INDEX); indexFont = settings.getInt(INDEX_FONT, DEFAULT_FONT_INDEX);
indexScale = settings.getInt(INDEX_SCALE, DEFAULT_SCALE_INDEX); indexScale = settings.getInt(INDEX_SCALE, DEFAULT_SCALE_INDEX);
listSize = settings.getInt(LIST_SIZE, DEFAULT_LIST_SIZE); listSize = settings.getInt(LIST_SIZE, DEFAULT_LIST_SIZE);
apiId = settings.getInt(CURRENT_API, Account.API_TWITTER);
isProxyEnabled = settings.getBoolean(PROXY_SET, false); isProxyEnabled = settings.getBoolean(PROXY_SET, false);
isProxyAuthSet = settings.getBoolean(AUTH_SET, false); isProxyAuthSet = settings.getBoolean(AUTH_SET, false);
ignoreProxyWarning = settings.getBoolean(PROXY_IGNORE, false); ignoreProxyWarning = settings.getBoolean(PROXY_IGNORE, false);
@ -1176,22 +1064,26 @@ public class GlobalSettings {
linkPreview = settings.getBoolean(LINK_PREVIEW, false); linkPreview = settings.getBoolean(LINK_PREVIEW, false);
filterResults = settings.getBoolean(FILTER_RESULTS, true); filterResults = settings.getBoolean(FILTER_RESULTS, true);
enableLike = settings.getBoolean(ENABLE_LIKE, false); enableLike = settings.getBoolean(ENABLE_LIKE, false);
customAPIKey = settings.getBoolean(CUSTOM_CONSUMER_KEY_SET, false); customAPIKey = settings.getBoolean(CUSTOM_CONSUMER_KEYS, false);
twitterAlt = settings.getBoolean(ENABLE_TWITTER_ALT, false); twitterAlt = settings.getBoolean(ENABLE_TWITTER_ALT, false);
proxyHost = settings.getString(PROXY_ADDR, ""); proxyHost = settings.getString(PROXY_ADDR, "");
proxyPort = settings.getString(PROXY_PORT, ""); proxyPort = settings.getString(PROXY_PORT, "");
proxyUser = settings.getString(PROXY_USER, ""); proxyUser = settings.getString(PROXY_USER, "");
proxyPass = settings.getString(PROXY_PASS, ""); proxyPass = settings.getString(PROXY_PASS, "");
api_key1 = settings.getString(CUSTOM_CONSUMER_KEY_1, "");
api_key2 = settings.getString(CUSTOM_CONSUMER_KEY_2, "");
String place = settings.getString(TREND_LOC, DEFAULT_LOCATION_NAME); String place = settings.getString(TREND_LOC, DEFAULT_LOCATION_NAME);
int woeId = settings.getInt(TREND_ID, DEFAULT_LOCATION_ID); int woeId = settings.getInt(TREND_ID, DEFAULT_LOCATION_ID);
location = new LocationImpl(place, woeId); location = new LocationImpl(place, woeId);
// user specific settings // login informations
auth_key1 = settings.getString(CURRENT_AUTH_KEY1, ""); String oauthToken = settings.getString(OAUTH_TOKEN, "");
auth_key2 = settings.getString(CURRENT_AUTH_KEY2, ""); String oauthSecret = settings.getString(OAUTH_SECRET, "");
userId = settings.getLong(CURRENT_ID, 0); String consumerToken = settings.getString(CONSUMER_TOKEN, "");
String consumerSecret = settings.getString(CONSUMER_SECRET, "");
String bearerToken = settings.getString(BEARER_TOKEN, "");
String hostname = settings.getString(HOSTNAME, DEFAULT_MASTODON_HOST);
int apiId = settings.getInt(CURRENT_API, Account.API_TWITTER);
long userId = settings.getLong(CURRENT_ID, 0);
account = new AccountImpl(userId, oauthToken, oauthSecret, consumerToken, consumerSecret, bearerToken, hostname, apiId);
} }
/** /**

View File

@ -34,11 +34,26 @@ public class AccountImpl implements Account {
private long loginDate; private long loginDate;
private int apiType; private int apiType;
private String accessToken, tokenSecret; private String accessToken, tokenSecret;
private String apiKey, apiSecret; private String consumerToken, consumerSecret;
private String bearerToken;
private String host; private String host;
private User user; private User user;
/**
*
*/
public AccountImpl(long userId, String accessToken, String tokenSecret, String consumerToken, String consumerSecret, String bearerToken, String host, int apiType) {
this.userId = userId;
this.accessToken = accessToken;
this.tokenSecret = tokenSecret;
this.consumerToken = consumerToken;
this.consumerSecret = consumerSecret;
this.bearerToken = bearerToken;
this.host = host;
this.apiType = apiType;
}
/** /**
* @param cursor database cursor using this {@link #COLUMNS} * @param cursor database cursor using this {@link #COLUMNS}
*/ */
@ -47,8 +62,8 @@ public class AccountImpl implements Account {
loginDate = cursor.getLong(1); loginDate = cursor.getLong(1);
accessToken = cursor.getString(2); accessToken = cursor.getString(2);
tokenSecret = cursor.getString(3); tokenSecret = cursor.getString(3);
apiKey = cursor.getString(4); consumerToken = cursor.getString(4);
apiSecret = cursor.getString(5); consumerSecret = cursor.getString(5);
host = cursor.getString(6); host = cursor.getString(6);
apiType = cursor.getInt(7); apiType = cursor.getInt(7);
} }
@ -74,29 +89,35 @@ public class AccountImpl implements Account {
@Override @Override
public String getApiKey() { public String getConsumerToken() {
return apiKey; return consumerToken;
} }
@Override @Override
public String getApiSecret() { public String getConsumerSecret() {
return apiSecret; return consumerSecret;
} }
@Override @Override
public String getAccessToken() { public String getOauthToken() {
return accessToken; return accessToken;
} }
@Override @Override
public String getTokenSecret() { public String getOauthSecret() {
return tokenSecret; return tokenSecret;
} }
@Override
public String getBearerToken() {
return bearerToken;
}
@Override @Override
public String getHostname() { public String getHostname() {
return host; return host;

View File

@ -43,6 +43,7 @@ public class StatusImpl implements Status {
private User author; private User author;
private int repostCount; private int repostCount;
private int favoriteCount; private int favoriteCount;
private int replyCount;
private int mediaType; private int mediaType;
private String locationName; private String locationName;
private String locationCoordinates; private String locationCoordinates;
@ -56,13 +57,17 @@ public class StatusImpl implements Status {
private boolean sensitive; private boolean sensitive;
private boolean isHidden; private boolean isHidden;
/**
* @param cursor database cursor
* @param currentUserId user ID of the current login
*/
public StatusImpl(Cursor cursor, long currentUserId) { public StatusImpl(Cursor cursor, long currentUserId) {
author = new UserImpl(cursor, currentUserId); author = new UserImpl(cursor, currentUserId);
time = cursor.getLong(cursor.getColumnIndexOrThrow(DatabaseAdapter.StatusTable.SINCE)); time = cursor.getLong(cursor.getColumnIndexOrThrow(DatabaseAdapter.StatusTable.SINCE));
text = cursor.getString(cursor.getColumnIndexOrThrow(DatabaseAdapter.StatusTable.TEXT)); text = cursor.getString(cursor.getColumnIndexOrThrow(DatabaseAdapter.StatusTable.TEXT));
repostCount = cursor.getInt(cursor.getColumnIndexOrThrow(DatabaseAdapter.StatusTable.REPOST)); repostCount = cursor.getInt(cursor.getColumnIndexOrThrow(DatabaseAdapter.StatusTable.REPOST));
favoriteCount = cursor.getInt(cursor.getColumnIndexOrThrow(DatabaseAdapter.StatusTable.FAVORITE)); favoriteCount = cursor.getInt(cursor.getColumnIndexOrThrow(DatabaseAdapter.StatusTable.FAVORITE));
replyCount = cursor.getInt(cursor.getColumnIndexOrThrow(DatabaseAdapter.StatusTable.REPLY));
id = cursor.getLong(cursor.getColumnIndexOrThrow(DatabaseAdapter.StatusTable.ID)); id = cursor.getLong(cursor.getColumnIndexOrThrow(DatabaseAdapter.StatusTable.ID));
replyName = cursor.getString(cursor.getColumnIndexOrThrow(DatabaseAdapter.StatusTable.REPLYNAME)); replyName = cursor.getString(cursor.getColumnIndexOrThrow(DatabaseAdapter.StatusTable.REPLYNAME));
replyID = cursor.getLong(cursor.getColumnIndexOrThrow(DatabaseAdapter.StatusTable.REPLYSTATUS)); replyID = cursor.getLong(cursor.getColumnIndexOrThrow(DatabaseAdapter.StatusTable.REPLYSTATUS));
@ -93,67 +98,86 @@ public class StatusImpl implements Status {
} }
} }
@Override @Override
public long getId() { public long getId() {
return id; return id;
} }
@Override @Override
public String getText() { public String getText() {
return text; return text;
} }
@Override @Override
public User getAuthor() { public User getAuthor() {
return author; return author;
} }
@Override @Override
public long getTimestamp() { public long getTimestamp() {
return time; return time;
} }
@Override @Override
public String getSource() { public String getSource() {
return source; return source;
} }
@Nullable @Nullable
@Override @Override
public Status getEmbeddedStatus() { public Status getEmbeddedStatus() {
return embedded; return embedded;
} }
@Override @Override
public String getReplyName() { public String getReplyName() {
return replyName; return replyName;
} }
@Override @Override
public long getRepliedUserId() { public long getRepliedUserId() {
return replyUserId; return replyUserId;
} }
@Override @Override
public long getRepliedStatusId() { public long getRepliedStatusId() {
return replyID; return replyID;
} }
@Override @Override
public long getRepostId() { public long getRepostId() {
return myRepostId; return myRepostId;
} }
@Override @Override
public int getRepostCount() { public int getRepostCount() {
return repostCount; return repostCount;
} }
@Override @Override
public int getFavoriteCount() { public int getFavoriteCount() {
return favoriteCount; return favoriteCount;
} }
@Override
public int getReplyCount() {
return replyCount;
}
@NonNull @NonNull
@Override @Override
public Uri[] getMediaUris() { public Uri[] getMediaUris() {
@ -163,46 +187,55 @@ public class StatusImpl implements Status {
return result; return result;
} }
@Override @Override
public String getUserMentions() { public String getUserMentions() {
return userMentions; return userMentions;
} }
@Override @Override
public int getMediaType() { public int getMediaType() {
return mediaType; return mediaType;
} }
@Override @Override
public boolean isSensitive() { public boolean isSensitive() {
return sensitive; return sensitive;
} }
@Override @Override
public boolean isReposted() { public boolean isReposted() {
return reposted; return reposted;
} }
@Override @Override
public boolean isFavorited() { public boolean isFavorited() {
return favorited; return favorited;
} }
@Override @Override
public String getLocationName() { public String getLocationName() {
return locationName; return locationName;
} }
@Override @Override
public String getLocationCoordinates() { public String getLocationCoordinates() {
return locationCoordinates; return locationCoordinates;
} }
@Override @Override
public boolean isHidden() { public boolean isHidden() {
return isHidden; return isHidden;
} }
@Override @Override
public boolean equals(@Nullable Object obj) { public boolean equals(@Nullable Object obj) {
if (!(obj instanceof Status)) if (!(obj instanceof Status))
@ -210,6 +243,7 @@ public class StatusImpl implements Status {
return ((Status) obj).getId() == id; return ((Status) obj).getId() == id;
} }
@NonNull @NonNull
@Override @Override
public String toString() { public String toString() {

View File

@ -15,6 +15,11 @@ public interface Account {
*/ */
int API_TWITTER = 1; int API_TWITTER = 1;
/**
* API ID used for Mastodon accounts
*/
int API_MASTODON = 2;
/** /**
* @return ID of the account (user ID) * @return ID of the account (user ID)
*/ */
@ -34,22 +39,27 @@ public interface Account {
/** /**
* @return API key assosiated with an account * @return API key assosiated with an account
*/ */
String getApiKey(); String getConsumerToken();
/** /**
* @return API secret key associated with an account * @return API secret key associated with an account
*/ */
String getApiSecret(); String getConsumerSecret();
/** /**
* @return first access token of the user * @return oauth token
*/ */
String getAccessToken(); String getOauthToken();
/** /**
* @return second access token of the user * @return oauth secret
*/ */
String getTokenSecret(); String getOauthSecret();
/**
* @return bearer token
*/
String getBearerToken();
/** /**
* @return hostname of the social network * @return hostname of the social network

View File

@ -95,6 +95,11 @@ public interface Status extends Serializable {
*/ */
int getFavoriteCount(); int getFavoriteCount();
/**
* @return number of replies
*/
int getReplyCount();
/** /**
* @return media links (up to 4) to images and videos * @return media links (up to 4) to images and videos
*/ */

View File

@ -36,7 +36,6 @@ import org.nuclearfog.twidda.R;
import org.nuclearfog.twidda.adapter.NetworkAdapter; import org.nuclearfog.twidda.adapter.NetworkAdapter;
import org.nuclearfog.twidda.backend.api.ConnectionException; import org.nuclearfog.twidda.backend.api.ConnectionException;
import org.nuclearfog.twidda.backend.api.twitter.Tokens; import org.nuclearfog.twidda.backend.api.twitter.Tokens;
import org.nuclearfog.twidda.backend.api.twitter.Twitter;
import org.nuclearfog.twidda.backend.async.LoginAction; import org.nuclearfog.twidda.backend.async.LoginAction;
import org.nuclearfog.twidda.backend.utils.AppStyles; import org.nuclearfog.twidda.backend.utils.AppStyles;
import org.nuclearfog.twidda.backend.utils.ErrorHandler; import org.nuclearfog.twidda.backend.utils.ErrorHandler;
@ -83,7 +82,7 @@ public class LoginActivity extends AppCompatActivity implements OnClickListener,
private ViewGroup root; private ViewGroup root;
@Nullable @Nullable
private String requestToken; private String link;
private int hostSelected = SELECTOR_TWITTER; private int hostSelected = SELECTOR_TWITTER;
@ -122,8 +121,8 @@ public class LoginActivity extends AppCompatActivity implements OnClickListener,
switchLabel.setVisibility(View.GONE); switchLabel.setVisibility(View.GONE);
} }
apiSwitch.setCheckedImmediately(true); apiSwitch.setCheckedImmediately(true);
apiKey1.setText(settings.getConsumerKey()); apiKey1.setText(settings.getLogin().getConsumerToken());
apiKey2.setText(settings.getConsumerSecret()); apiKey2.setText(settings.getLogin().getConsumerToken());
} else { } else {
apiKey1.setVisibility(View.INVISIBLE); apiKey1.setVisibility(View.INVISIBLE);
apiKey2.setVisibility(View.INVISIBLE); apiKey2.setVisibility(View.INVISIBLE);
@ -199,7 +198,7 @@ public class LoginActivity extends AppCompatActivity implements OnClickListener,
// get login request token // get login request token
if (v.getId() == R.id.login_get_link) { if (v.getId() == R.id.login_get_link) {
if (hostSelected == SELECTOR_TWITTER) { if (hostSelected == SELECTOR_TWITTER) {
if (requestToken == null) { if (link == null) {
// check if input is ok // check if input is ok
if (apiSwitch.isChecked() && (apiKey1.length() == 0 || apiKey2.length() == 0)) { if (apiSwitch.isChecked() && (apiKey1.length() == 0 || apiKey2.length() == 0)) {
if (apiKey1.length() == 0) { if (apiKey1.length() == 0) {
@ -214,14 +213,14 @@ public class LoginActivity extends AppCompatActivity implements OnClickListener,
String apiTxt1 = apiKey1.getText().toString(); String apiTxt1 = apiKey1.getText().toString();
String apiTxt2 = apiKey2.getText().toString(); String apiTxt2 = apiKey2.getText().toString();
Toast.makeText(this, R.string.info_open_twitter_login, LENGTH_LONG).show(); Toast.makeText(this, R.string.info_open_twitter_login, LENGTH_LONG).show();
loginAsync = new LoginAction(this, LoginAction.MODE_REQUEST, hostSelected); loginAsync = new LoginAction(this, LoginAction.MODE_TWITTER_REQUEST, hostSelected);
loginAsync.execute(apiTxt1, apiTxt2); loginAsync.execute(apiTxt1, apiTxt2);
} }
// use system keys // use system keys
else if (Tokens.USE_DEFAULT_KEYS) { else if (Tokens.USE_DEFAULT_KEYS) {
Toast.makeText(this, R.string.info_open_twitter_login, LENGTH_LONG).show(); Toast.makeText(this, R.string.info_open_twitter_login, LENGTH_LONG).show();
loginAsync = new LoginAction(this, LoginAction.MODE_REQUEST, hostSelected); loginAsync = new LoginAction(this, LoginAction.MODE_TWITTER_REQUEST, hostSelected);
loginAsync.execute(null, null); loginAsync.execute();
} }
} else { } else {
// re-use request token // re-use request token
@ -233,7 +232,7 @@ public class LoginActivity extends AppCompatActivity implements OnClickListener,
else if (v.getId() == R.id.login_verifier) { else if (v.getId() == R.id.login_verifier) {
if (hostSelected == SELECTOR_TWITTER) { if (hostSelected == SELECTOR_TWITTER) {
// check if user clicked on PIN button // check if user clicked on PIN button
if (requestToken == null) { if (link == null) {
Toast.makeText(this, R.string.info_get_link, LENGTH_LONG).show(); Toast.makeText(this, R.string.info_get_link, LENGTH_LONG).show();
} }
// check if input is ok // check if input is ok
@ -252,13 +251,13 @@ public class LoginActivity extends AppCompatActivity implements OnClickListener,
else { else {
String twitterPin = pinInput.getText().toString(); String twitterPin = pinInput.getText().toString();
Toast.makeText(this, R.string.info_login_to_twitter, LENGTH_LONG).show(); Toast.makeText(this, R.string.info_login_to_twitter, LENGTH_LONG).show();
loginAsync = new LoginAction(this, LoginAction.MODE_LOGIN, hostSelected); loginAsync = new LoginAction(this, LoginAction.MODE_TWITTER_LOGIN, hostSelected);
if (apiSwitch.isChecked()) { if (apiSwitch.isChecked()) {
String apiTxt1 = apiKey1.getText().toString(); String apiTxt1 = apiKey1.getText().toString();
String apiTxt2 = apiKey2.getText().toString(); String apiTxt2 = apiKey2.getText().toString();
loginAsync.execute(requestToken, twitterPin, apiTxt1, apiTxt2); loginAsync.execute(link, twitterPin, apiTxt1, apiTxt2);
} else { } else {
loginAsync.execute(requestToken, twitterPin); loginAsync.execute(link, twitterPin);
} }
} }
} }
@ -277,7 +276,7 @@ public class LoginActivity extends AppCompatActivity implements OnClickListener,
apiKey2.setVisibility(View.INVISIBLE); apiKey2.setVisibility(View.INVISIBLE);
} }
// reset request token // reset request token
requestToken = null; link = null;
} }
} }
@ -299,13 +298,13 @@ public class LoginActivity extends AppCompatActivity implements OnClickListener,
*/ */
public void onSuccess(int mode, String result) { public void onSuccess(int mode, String result) {
switch (mode) { switch (mode) {
case LoginAction.MODE_LOGIN: case LoginAction.MODE_TWITTER_LOGIN:
setResult(RETURN_LOGIN_SUCCESSFUL); setResult(RETURN_LOGIN_SUCCESSFUL);
finish(); finish();
break; break;
case LoginAction.MODE_REQUEST: case LoginAction.MODE_TWITTER_REQUEST:
requestToken = result; link = result;
connect(); connect();
break; break;
} }
@ -322,7 +321,6 @@ public class LoginActivity extends AppCompatActivity implements OnClickListener,
* open login page * open login page
*/ */
private void connect() { private void connect() {
String link = Twitter.AUTHENTICATE + "?oauth_token=" + requestToken;
Intent loginIntent = new Intent(ACTION_VIEW, Uri.parse(link)); Intent loginIntent = new Intent(ACTION_VIEW, Uri.parse(link));
try { try {
startActivity(loginIntent); startActivity(loginIntent);

View File

@ -230,7 +230,7 @@ public class MainActivity extends AppCompatActivity implements OnTabSelectedList
// open home profile // open home profile
if (item.getItemId() == R.id.menu_profile) { if (item.getItemId() == R.id.menu_profile) {
Intent user = new Intent(this, ProfileActivity.class); Intent user = new Intent(this, ProfileActivity.class);
user.putExtra(KEY_PROFILE_ID, settings.getCurrentUserId()); user.putExtra(KEY_PROFILE_ID, settings.getLogin().getId());
startActivity(user); startActivity(user);
} }
// open status editor // open status editor

View File

@ -302,10 +302,10 @@ public class SettingsActivity extends AppCompatActivity implements OnClickListen
public void onConfirm(int type, boolean rememberChoice) { public void onConfirm(int type, boolean rememberChoice) {
// confirm log out // confirm log out
if (type == ConfirmDialog.APP_LOG_OUT) { if (type == ConfirmDialog.APP_LOG_OUT) {
settings.logout();
// remove account from database // remove account from database
AccountDatabase accountDB = new AccountDatabase(this); AccountDatabase accountDB = new AccountDatabase(this);
accountDB.removeLogin(settings.getCurrentUserId()); accountDB.removeLogin(settings.getLogin().getId());
settings.setLogin(null, true);
setResult(RETURN_APP_LOGOUT); setResult(RETURN_APP_LOGOUT);
finish(); finish();
} }

View File

@ -304,8 +304,7 @@ public class StatusActivity extends AppCompatActivity implements OnClickListener
if (status.getEmbeddedStatus() != null) { if (status.getEmbeddedStatus() != null) {
status = status.getEmbeddedStatus(); status = status.getEmbeddedStatus();
} }
if (status.getRepliedUserId() == settings.getCurrentUserId() if (status.getRepliedUserId() == settings.getLogin().getId() && status.getAuthor().getId() != settings.getLogin().getId()) {
&& status.getAuthor().getId() != settings.getCurrentUserId()) {
optHide.setVisible(true); optHide.setVisible(true);
if (hidden) { if (hidden) {
optHide.setTitle(R.string.menu_tweet_unhide); optHide.setTitle(R.string.menu_tweet_unhide);

View File

@ -84,7 +84,7 @@ public class UserlistsActivity extends AppCompatActivity implements TabLayout.On
long ownerId = getIntent().getLongExtra(KEY_USERLIST_OWNER_ID, -1); long ownerId = getIntent().getLongExtra(KEY_USERLIST_OWNER_ID, -1);
String ownerName = getIntent().getStringExtra(KEY_USERLIST_OWNER_NAME); String ownerName = getIntent().getStringExtra(KEY_USERLIST_OWNER_NAME);
isHome = ownerId == settings.getCurrentUserId(); isHome = ownerId == settings.getLogin().getId();
adapter.setupListPage(ownerId, ownerName); adapter.setupListPage(ownerId, ownerName);
AppStyles.setTabIcons(tabLayout, settings, R.array.userlist_tab_icons); AppStyles.setTabIcons(tabLayout, settings, R.array.userlist_tab_icons);
} }

View File

@ -85,19 +85,7 @@ public class AccountFragment extends ListFragment implements OnAccountClickListe
@Override @Override
public void onAccountClick(Account account) { public void onAccountClick(Account account) {
// set new account settings.setLogin(account, false);
settings.setUserId(account.getId());
// setup Twitter account
if (account.getApiType() == Account.API_TWITTER) {
settings.setAccessToken(account.getAccessToken());
settings.setTokenSecret(account.getTokenSecret());
settings.setApiId(account.getApiType());
if (!account.getApiKey().isEmpty() && !account.getApiSecret().isEmpty()) {
settings.setCustomAPI(account.getApiKey(), account.getApiSecret());
} else {
settings.removeCustomAPI();
}
}
if (account.getUser() != null) { if (account.getUser() != null) {
String message = getString(R.string.info_account_selected, account.getUser().getScreenname()); String message = getString(R.string.info_account_selected, account.getUser().getScreenname());
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show(); Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show();

View File

@ -12,7 +12,7 @@
<string name="title_settings">Einstellungen</string> <string name="title_settings">Einstellungen</string>
<string name="settings_image">Bilder laden</string> <string name="settings_image">Bilder laden</string>
<string name="settings_clear_data">Daten löschen</string> <string name="settings_clear_data">Daten löschen</string>
<string name="toolbar_userlist_retweet">Tweet retweetet von</string> <string name="toolbar_userlist_retweet">Status geteilt von</string>
<string name="settings_background">Hintergrund</string> <string name="settings_background">Hintergrund</string>
<string name="confirm_delete_tweet">Tweet löschen?</string> <string name="confirm_delete_tweet">Tweet löschen?</string>
<string name="error_enter_pin">PIN eingeben!</string> <string name="error_enter_pin">PIN eingeben!</string>
@ -78,10 +78,10 @@
<string name="error_not_authorized">Keine Berechtigung!</string> <string name="error_not_authorized">Keine Berechtigung!</string>
<string name="error_file_format">Dateiformat nicht unterstützt!</string> <string name="error_file_format">Dateiformat nicht unterstützt!</string>
<string name="settings_enable_ans_load">Tweet-Replies automatisch laden</string> <string name="settings_enable_ans_load">Tweet-Replies automatisch laden</string>
<string name="info_tweet_retweeted">Tweet retweeted!</string> <string name="info_tweet_retweeted">Status reposted!</string>
<string name="info_tweet_unretweeted">Retweet entfernt!</string> <string name="info_tweet_unretweeted">Repost entfernt!</string>
<string name="info_tweet_favored">Tweet favorisiert!</string> <string name="info_tweet_favored">Status favorisiert!</string>
<string name="info_tweet_unfavored">tweet aus den favoriten entfernt!</string> <string name="info_tweet_unfavored">Status aus den Favoriten entfernt!</string>
<string name="proxy_port">Port</string> <string name="proxy_port">Port</string>
<string name="settings_connections">Verbindungseinsellungen</string> <string name="settings_connections">Verbindungseinsellungen</string>
<string name="login_verifier">Login</string> <string name="login_verifier">Login</string>
@ -187,7 +187,7 @@
<string name="confirm_remove_account">Account aus der Liste entfernen?</string> <string name="confirm_remove_account">Account aus der Liste entfernen?</string>
<string name="menu_select_account">Account auswählen</string> <string name="menu_select_account">Account auswählen</string>
<string name="menu_add_account">Account hinzufügen</string> <string name="menu_add_account">Account hinzufügen</string>
<string name="settings_rt_icon_color">Retweet</string> <string name="settings_rt_icon_color">Repost</string>
<string name="settings_follow_req_color">Anfrage Icon</string> <string name="settings_follow_req_color">Anfrage Icon</string>
<string name="settings_follow_color">Follow Icon</string> <string name="settings_follow_color">Follow Icon</string>
<string name="settings_enable_toolbar_overlap">Kompakte Profilansicht</string> <string name="settings_enable_toolbar_overlap">Kompakte Profilansicht</string>

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <resources>
<!--app/repository dependent strings--> <!--app/repository dependent strings-->
<string name="app_name" translatable="false">Shitter</string> <string name="app_name" translatable="false">Shitter</string>
<string name="settings_info_link" translatable="false">https://github.com/nuclearfog/Shitter</string> <string name="settings_info_link" translatable="false">https://github.com/nuclearfog/Shitter</string>
@ -23,12 +22,12 @@
<string name="error_wrong_connection_settings">wrong connection settings! Discarc changes?</string> <string name="error_wrong_connection_settings">wrong connection settings! Discarc changes?</string>
<string name="info_get_link">please open twitter login page first to get the PIN</string> <string name="info_get_link">please open twitter login page first to get the PIN</string>
<string name="info_gps_attached">GPS position added</string> <string name="info_gps_attached">GPS position added</string>
<string name="info_tweet_retweeted">retweeted</string> <string name="info_tweet_retweeted">reposted</string>
<string name="info_tweet_unretweeted">Retweet removed</string> <string name="info_tweet_unretweeted">Repost removed</string>
<string name="info_tweet_favored">Tweet added to favorites</string> <string name="info_tweet_favored">Status added to favorites</string>
<string name="info_tweet_unfavored">Tweet removed from favorites</string> <string name="info_tweet_unfavored">Status removed from favorites</string>
<string name="info_tweet_liked">Tweet liked</string> <string name="info_tweet_liked">Status liked</string>
<string name="info_tweet_unliked">Tweet unliked</string> <string name="info_tweet_unliked">Status unliked</string>
<string name="info_reply_hidden">Reply is hidden</string> <string name="info_reply_hidden">Reply is hidden</string>
<string name="info_reply_unhidden">Reply is visible</string> <string name="info_reply_unhidden">Reply is visible</string>
<string name="info_user_muted">User muted</string> <string name="info_user_muted">User muted</string>
@ -43,23 +42,23 @@
<string name="info_unfollowed">unfollowed</string> <string name="info_unfollowed">unfollowed</string>
<string name="info_user_blocked">blocked</string> <string name="info_user_blocked">blocked</string>
<string name="info_user_unblocked">unblocked</string> <string name="info_user_unblocked">unblocked</string>
<string name="info_tweet_removed">Tweet removed</string> <string name="info_tweet_removed">Status removed</string>
<string name="info_tweet_sent">Tweet sent</string> <string name="info_tweet_sent">Status shared</string>
<string name="info_location_pending">requesting location, please wait</string> <string name="info_location_pending">requesting location, please wait</string>
<string name="info_refreshing_exclude_list">refreshing exclude list</string> <string name="info_refreshing_exclude_list">refreshing exclude list</string>
<string name="info_exclude_list_updated">exclude list updated!</string> <string name="info_exclude_list_updated">exclude list updated!</string>
<string name="info_permission_read">Read permission needed to access images and videos.</string> <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_location">Location permission only needed to attach location to a status</string>
<string name="info_permission_write">Write permission used to store images.</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_restart_app_on_change">restarting required to apply changes</string>
<string name="info_tweet_text_copied">Tweet text copied</string> <string name="info_tweet_text_copied">Status text copied</string>
<string name="info_tweet_location_copied">Location coordinates copied</string> <string name="info_tweet_location_copied">Location coordinates copied</string>
<string name="info_tweet_medialink_copied">Media link copied</string> <string name="info_tweet_medialink_copied">Media link copied</string>
<string name="info_account_selected">%1$s selected</string> <string name="info_account_selected">%1$s selected</string>
<string name="info_error">Error</string> <string name="info_error">Error</string>
<!-- toast messages for error information --> <!-- toast messages for error information -->
<string name="error_empty_tweet">Empty tweet!</string> <string name="error_empty_tweet">Empty status!</string>
<string name="error_dm">enter username or message!</string> <string name="error_dm">enter username or message!</string>
<string name="error_not_found">not found!</string> <string name="error_not_found">not found!</string>
<string name="error_enter_pin">enter PIN!</string> <string name="error_enter_pin">enter PIN!</string>
@ -79,12 +78,12 @@
<string name="error_empty_name">Empty user name!</string> <string name="error_empty_name">Empty user name!</string>
<string name="error_user_not_found">User not found!</string> <string name="error_user_not_found">User not found!</string>
<string name="error_accesstoken">Invalid access! Please re-login!</string> <string name="error_accesstoken">Invalid access! Please re-login!</string>
<string name="error_status_length">Tweet is too long!</string> <string name="error_status_length">Status is too long!</string>
<string name="error_duplicate_status">Duplicate Tweet!</string> <string name="error_duplicate_status">Duplicate Status!</string>
<string name="error_dm_length">Directmessage is too long!</string> <string name="error_dm_length">Directmessage is too long!</string>
<string name="error_list_title_empty">Empty list title!</string> <string name="error_list_title_empty">Empty list title!</string>
<string name="error_username_format">Wrong username format!</string> <string name="error_username_format">Wrong username format!</string>
<string name="error_cant_reply_to_tweet">You can\'t reply to this Tweet!</string> <string name="error_cant_reply_to_tweet">You can\'t reply to this status!</string>
<string name="error_corrupt_api_key">Error, corrupt API key!</string> <string name="error_corrupt_api_key">Error, corrupt API key!</string>
<string name="error_acc_update">Account update failed! Please check your input!</string> <string name="error_acc_update">Account update failed! Please check your input!</string>
<string name="error_api_access_denied">Error, API access denied! Please check your API Keys.</string> <string name="error_api_access_denied">Error, API access denied! Please check your API Keys.</string>
@ -100,9 +99,9 @@
<string name="error_empty_token">token key missing!</string> <string name="error_empty_token">token key missing!</string>
<!-- menu icon strings --> <!-- menu icon strings -->
<string name="menu_tweet">write Tweet</string> <string name="menu_tweet">write status</string>
<string name="menu_open_home_profile">open Profile</string> <string name="menu_open_home_profile">open Profile</string>
<string name="menu_open_twitter_search">Twitter Search</string> <string name="menu_open_twitter_search">Search</string>
<string name="menu_open_settings">Settings</string> <string name="menu_open_settings">Settings</string>
<string name="menu_create_list">create Userlist</string> <string name="menu_create_list">create Userlist</string>
<string name="menu_write_message">Directmessage</string> <string name="menu_write_message">Directmessage</string>
@ -155,12 +154,12 @@
<string name="login_pin">enter PIN</string> <string name="login_pin">enter PIN</string>
<string name="login_key_enable">add keys</string> <string name="login_key_enable">add keys</string>
<string name="login_verifier">login</string> <string name="login_verifier">login</string>
<string name="popup_tweet_hint" translatable="false">Tweet</string> <string name="popup_tweet_hint">Status</string>
<string name="title_settings">Settings</string> <string name="title_settings">Settings</string>
<string name="title_metrics">Tweet metrics</string> <string name="title_metrics">Status metrics</string>
<string name="userlist_following" translatable="false">Following</string> <string name="userlist_following" translatable="false">Following</string>
<string name="userlist_follower" translatable="false">Follower</string> <string name="userlist_follower" translatable="false">Follower</string>
<string name="toolbar_userlist_retweet">Tweet retweeted by</string> <string name="toolbar_userlist_retweet">Status reposted by</string>
<string name="settings_color_settings">Color settings</string> <string name="settings_color_settings">Color settings</string>
<string name="settings_background">Background</string> <string name="settings_background">Background</string>
<string name="settings_text">Text</string> <string name="settings_text">Text</string>
@ -169,7 +168,7 @@
<string name="settings_icon_color">Icons</string> <string name="settings_icon_color">Icons</string>
<string name="settings_color_like">Like</string> <string name="settings_color_like">Like</string>
<string name="settings_color_fav">Favorite</string> <string name="settings_color_fav">Favorite</string>
<string name="settings_enable_indicators">show additional Tweet information</string> <string name="settings_enable_indicators">show additional status information</string>
<string name="highlight">Highlight</string> <string name="highlight">Highlight</string>
<string name="settings_list_size">List size</string> <string name="settings_list_size">List size</string>
<string name="settings_enable_like">use \'Like\' instead of Favorite</string> <string name="settings_enable_like">use \'Like\' instead of Favorite</string>
@ -179,7 +178,7 @@
<string name="register_link">get code</string> <string name="register_link">get code</string>
<string name="settings_image">enable images</string> <string name="settings_image">enable images</string>
<string name="settings_clear_data">clear app data</string> <string name="settings_clear_data">clear app data</string>
<string name="confirm_delete_tweet">delete tweet?</string> <string name="confirm_delete_tweet">delete status?</string>
<string name="confirm_delete_database">clear app data?</string> <string name="confirm_delete_database">clear app data?</string>
<string name="tweet_sent_from">"sent from: "</string> <string name="tweet_sent_from">"sent from: "</string>
<string name="directmessage">Directmessage</string> <string name="directmessage">Directmessage</string>
@ -193,10 +192,10 @@
<string name="confirm_unfollow">unfollow user?</string> <string name="confirm_unfollow">unfollow user?</string>
<string name="confirm_block">block user?</string> <string name="confirm_block">block user?</string>
<string name="confirm_log_lout">log out?</string> <string name="confirm_log_lout">log out?</string>
<string name="confirm_cancel_tweet">discard tweet?</string> <string name="confirm_cancel_tweet">discard changes?</string>
<string name="image_preview">Image preview</string> <string name="image_preview">Image preview</string>
<string name="tweet_add_image">add new image</string> <string name="tweet_add_image">add new image</string>
<string name="send_tweet">share Tweet</string> <string name="send_tweet">share status</string>
<string name="tweet_close">close editor</string> <string name="tweet_close">close editor</string>
<string name="profile_link">Link</string> <string name="profile_link">Link</string>
<string name="close_dm">close directmessage</string> <string name="close_dm">close directmessage</string>
@ -205,7 +204,7 @@
<string name="confirm_discard">discard changes?</string> <string name="confirm_discard">discard changes?</string>
<string name="user_data">User data</string> <string name="user_data">User data</string>
<string name="follows_you">follows you</string> <string name="follows_you">follows you</string>
<string name="settings_enable_ans_load">load Tweet replies automatically</string> <string name="settings_enable_ans_load">load status replies automatically</string>
<string name="settings_connections">Connection settings</string> <string name="settings_connections">Connection settings</string>
<string name="settings_hint_proxy_ip">enter IP address</string> <string name="settings_hint_proxy_ip">enter IP address</string>
<string name="proxy_port">Port</string> <string name="proxy_port">Port</string>
@ -224,7 +223,8 @@
<string name="confirm_delete_list">delete userlist?</string> <string name="confirm_delete_list">delete userlist?</string>
<string name="confirm_delete_message">delete message?</string> <string name="confirm_delete_message">delete message?</string>
<string name="confirm_unfollow_list">unfollow list?</string> <string name="confirm_unfollow_list">unfollow list?</string>
<string name="trend_range">Tweets</string> <string name="trend_range_tweets">Tweets</string>
<string name="trend_range">Posts</string>
<string name="enter_username">enter username</string> <string name="enter_username">enter username</string>
<string name="profile_banner">Banner Image</string> <string name="profile_banner">Banner Image</string>
<string name="editprofile_add_banner">add banner</string> <string name="editprofile_add_banner">add banner</string>
@ -261,7 +261,7 @@
<string name="button_forward">Fast forward</string> <string name="button_forward">Fast forward</string>
<string name="button_play_pause">Pause/Play</string> <string name="button_play_pause">Pause/Play</string>
<string name="button_share">share link</string> <string name="button_share">share link</string>
<string name="settings_rt_icon_color">Retweet</string> <string name="settings_rt_icon_color">Reposts</string>
<string name="settings_follow_req_color">Follow request</string> <string name="settings_follow_req_color">Follow request</string>
<string name="settings_follow_color">Following icon</string> <string name="settings_follow_color">Following icon</string>
<string name="account_page" translatable="false">Accounts</string> <string name="account_page" translatable="false">Accounts</string>
@ -270,8 +270,8 @@
<string name="dialog_warning_videoview">videoplayer does not support proxy! Continue without proxy connection?</string> <string name="dialog_warning_videoview">videoplayer does not support proxy! Continue without proxy connection?</string>
<string name="account_user_id_prefix" translatable="false">User ID:</string> <string name="account_user_id_prefix" translatable="false">User ID:</string>
<string name="account_user_unnamed">\'unnamed\'</string> <string name="account_user_unnamed">\'unnamed\'</string>
<string name="toolbar_tweet_favoriter">User favoriting this tweet</string> <string name="toolbar_tweet_favoriter">User favoriting this status</string>
<string name="toolbar_tweet_liker">User liking this tweet</string> <string name="toolbar_tweet_liker">User liking this status</string>
<string name="time_now">now</string> <string name="time_now">now</string>
<string name="confirm_open_link">open in browser</string> <string name="confirm_open_link">open in browser</string>