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.StatusUpdate;
import org.nuclearfog.twidda.backend.update.UserListUpdate;
import org.nuclearfog.twidda.model.Account;
import org.nuclearfog.twidda.model.Location;
import org.nuclearfog.twidda.model.Metrics;
import org.nuclearfog.twidda.model.Relation;
@ -24,6 +25,21 @@ import java.util.List;
* @author nuclearfog
*/
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
*

View File

@ -2,6 +2,7 @@ package org.nuclearfog.twidda.backend.api;
import android.content.Context;
import org.nuclearfog.twidda.backend.api.mastodon.Mastodon;
import org.nuclearfog.twidda.backend.api.twitter.Twitter;
import org.nuclearfog.twidda.database.GlobalSettings;
import org.nuclearfog.twidda.database.GlobalSettings.OnSettingsChangeListener;
@ -20,10 +21,15 @@ public class ConnectionManager {
public static final int SELECT_AUTO = 0;
/**
* force using Twitter connection
* select Twitter connection
*/
public static final int SELECT_TWITTER = 1;
/**
* select Mastodon connection
*/
public static final int SELECT_MASTODON = 2;
private static Connection connection;
private static boolean notifySettingsChange = false;
@ -54,9 +60,13 @@ public class ConnectionManager {
if (select == SELECT_TWITTER) {
connection = new Twitter(context);
}
// create Mastodon isntance
else if (select == SELECT_MASTODON) {
connection = new Mastodon(context);
}
// select automatically
else {
if (settings.getApiId() == Account.API_TWITTER) {
if (settings.getLogin().getApiType() == Account.API_TWITTER) {
connection = new Twitter(context);
} else {
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) {
if (settings.isCustomApiSet() && !forceDefault)
return settings.getConsumerKey();
return settings.getLogin().getConsumerToken();
return CONSUMER_TOKEN;
}
@ -72,7 +72,7 @@ public class Tokens {
*/
public String getConsumerSecret(boolean forceDefault) {
if (settings.isCustomApiSet() && !forceDefault)
return settings.getConsumerSecret();
return settings.getLogin().getConsumerSecret();
return TOKEN_SECRET;
}
}

View File

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

View File

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

View File

@ -9,12 +9,12 @@ import org.nuclearfog.twidda.model.User;
*
* @author nuclearfog
*/
public class AccountV1 implements Account {
public class TwitterAccount implements Account {
private long date;
private String oauthToken, tokenSecret;
private String apiKey, apiSec;
private String oauthToken, oauthSecret;
private String consumerToken, consumerSecret;
private User user;
@ -23,66 +23,81 @@ public class AccountV1 implements Account {
* @param tokenSecret oauth token secret
* @param user user information
*/
public AccountV1(String oauthToken, String tokenSecret, User user) {
public TwitterAccount(String oauthToken, String tokenSecret, User user) {
this(oauthToken, tokenSecret, "", "", user);
}
/**
* @param apiKey API consumer token
* @param apiSec API consumer secret
* @param oauthToken oauth access token
* @param tokenSecret oauth token secret
* @param user user information
* @param consumerToken API consumer token
* @param consumerSecret API consumer secret
* @param oauthToken oauth access token
* @param tokenSecret oauth token secret
* @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.tokenSecret = tokenSecret;
this.apiKey = apiKey;
this.apiSec = apiSec;
this.oauthSecret = tokenSecret;
this.consumerToken = consumerToken;
this.consumerSecret = consumerSecret;
this.user = user;
date = System.currentTimeMillis();
}
@Override
public long getId() {
return user.getId();
}
@Override
public long getLoginDate() {
return date;
}
@Override
public User getUser() {
return user;
}
@Override
public String getApiKey() {
return apiKey;
}
@Override
public String getApiSecret() {
return apiSec;
public String getConsumerToken() {
return consumerToken;
}
@Override
public String getAccessToken() {
public String getConsumerSecret() {
return consumerSecret;
}
@Override
public String getOauthToken() {
return oauthToken;
}
@Override
public String getTokenSecret() {
return tokenSecret;
public String getOauthSecret() {
return oauthSecret;
}
@Override
public String getBearerToken() {
return "";
}
@Override
public String getHostname() {
return Twitter.API;
}
@Override
public int getApiType() {
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.ConnectionException;
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.AppDatabase;
import org.nuclearfog.twidda.model.Account;
@ -26,12 +25,12 @@ public class LoginAction extends AsyncTask<String, Void, String> {
/**
* 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
*/
public static final int MODE_LOGIN = 2;
public static final int MODE_TWITTER_LOGIN = 2;
private WeakReference<LoginActivity> weakRef;
private AccountDatabase accountDB;
@ -63,28 +62,21 @@ public class LoginAction extends AsyncTask<String, Void, String> {
@Override
protected String doInBackground(String... param) {
if (connection instanceof Twitter) {
try {
Twitter twitter = (Twitter) connection;
switch (mode) {
case MODE_REQUEST:
return twitter.getRequestToken(param[0], param[1]);
try {
switch (mode) {
case MODE_TWITTER_REQUEST:
return connection.getAuthorisationLink(param);
case MODE_LOGIN:
// login with pin and access token
Account account;
if (param.length == 4)
account = twitter.login(param[0], param[1], param[2], param[3]);
else
account = twitter.login(param[0], param[1]);
// save new user information
database.saveUser(account.getUser());
accountDB.saveLogin(account);
return "";
}
} catch (ConnectionException exception) {
this.exception = exception;
case MODE_TWITTER_LOGIN:
// login with pin and access token
Account account = connection.loginApp(param);
// save new user information
database.saveUser(account.getUser());
accountDB.saveLogin(account);
return "";
}
} catch (ConnectionException exception) {
this.exception = exception;
}
return null;
}

View File

@ -53,12 +53,12 @@ public class AccountDatabase {
ContentValues values = new ContentValues();
values.put(AccountTable.ID, account.getId());
values.put(AccountTable.ACCESS_TOKEN, account.getAccessToken());
values.put(AccountTable.TOKEN_SECRET, account.getTokenSecret());
values.put(AccountTable.ACCESS_TOKEN, account.getOauthToken());
values.put(AccountTable.TOKEN_SECRET, account.getOauthSecret());
values.put(AccountTable.DATE, account.getLoginDate());
values.put(AccountTable.HOSTNAME, account.getHostname());
values.put(AccountTable.CLIENT_ID, account.getApiKey());
values.put(AccountTable.CLIENT_SECRET, account.getApiSecret());
values.put(AccountTable.CLIENT_ID, account.getConsumerToken());
values.put(AccountTable.CLIENT_SECRET, account.getConsumerSecret());
values.put(AccountTable.API, account.getApiType());
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);
if (cursor.moveToFirst()) {
result.ensureCapacity(cursor.getCount());
do {
do
{
AccountImpl account = new AccountImpl(cursor);
account.addUser(database.getUser(account.getId()));
result.add(account);

View File

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

View File

@ -19,7 +19,7 @@ public class DatabaseAdapter {
/**
* database version
*/
private static final int DB_VERSION = 7;
private static final int DB_VERSION = 8;
/**
* database file name
@ -61,6 +61,7 @@ public class DatabaseAdapter {
+ StatusTable.MEDIA + " TEXT,"
+ StatusTable.REPOST + " INTEGER,"
+ StatusTable.FAVORITE + " INTEGER,"
+ StatusTable.REPLY + " INTEGER,"
+ StatusTable.SOURCE + " TEXT,"
+ StatusTable.PLACE + " 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;";
/**
* 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
*/
@ -271,8 +277,12 @@ public class DatabaseAdapter {
db.execSQL(UPDATE_ADD_CLIENT_SEC);
db.setVersion(6);
}
if (db.getVersion() < DB_VERSION) {
if (db.getVersion() < 7) {
db.execSQL(UPDATE_ADD_API_ID);
db.setVersion(7);
}
if (db.getVersion() < DB_VERSION) {
db.execSQL(UPDATE_ADD_REPLY_COUNT);
db.setVersion(DB_VERSION);
}
}
@ -392,6 +402,11 @@ public class DatabaseAdapter {
*/
String FAVORITE = "favorite";
/**
* reply count
*/
String REPLY = "reply";
/**
* timestamp of the status
*/

View File

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

View File

@ -14,7 +14,9 @@ import android.graphics.Color;
import android.graphics.Typeface;
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.model.Account;
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_TWITTER_ALT = "twitter_alt_set";
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_KEY_1 = "api_key1";
private static final String CUSTOM_CONSUMER_KEY_2 = "api_key2";
private static final String CUSTOM_CONSUMER_KEYS = "custom_api_keys";
private static final String CONSUMER_TOKEN = "api_key1";
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 HOSTNAME = "mastodon_host";
// login specific preference names
private static final String LOGGED_IN = "login";
private static final String CURRENT_ID = "userID";
private static final String CURRENT_AUTH_KEY1 = "key1";
private static final String CURRENT_AUTH_KEY2 = "key2";
private static final String OAUTH_TOKEN = "key1";
private static final String OAUTH_SECRET = "key2";
// file name of the preferences
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_LOCATION_ID = 1;
private static final String DEFAULT_LOCATION_NAME = "Worldwide";
private static final String DEFAULT_MASTODON_HOST = "https://mastodon.social";
private SharedPreferences settings;
private Location location;
private String api_key1, api_key2;
private String auth_key1, auth_key2;
private Account account;
private String proxyHost, proxyPort;
private String proxyUser, proxyPass;
private boolean loadImage;
@ -181,8 +186,6 @@ public class GlobalSettings {
private int indexFont;
private int indexScale;
private int listSize;
private int apiId;
private long userId;
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) {
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
*/
@ -950,154 +953,6 @@ public class GlobalSettings {
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
*
@ -1108,22 +963,56 @@ public class GlobalSettings {
}
/**
* clear user specific settings
* get login information
*
* @return current account
*/
public void logout() {
loggedIn = false;
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();
public Account getLogin() {
return account;
}
/**
* 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
* changes like new proxy settings requires re initialization
@ -1163,7 +1052,6 @@ public class GlobalSettings {
indexFont = settings.getInt(INDEX_FONT, DEFAULT_FONT_INDEX);
indexScale = settings.getInt(INDEX_SCALE, DEFAULT_SCALE_INDEX);
listSize = settings.getInt(LIST_SIZE, DEFAULT_LIST_SIZE);
apiId = settings.getInt(CURRENT_API, Account.API_TWITTER);
isProxyEnabled = settings.getBoolean(PROXY_SET, false);
isProxyAuthSet = settings.getBoolean(AUTH_SET, false);
ignoreProxyWarning = settings.getBoolean(PROXY_IGNORE, false);
@ -1176,22 +1064,26 @@ public class GlobalSettings {
linkPreview = settings.getBoolean(LINK_PREVIEW, false);
filterResults = settings.getBoolean(FILTER_RESULTS, true);
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);
proxyHost = settings.getString(PROXY_ADDR, "");
proxyPort = settings.getString(PROXY_PORT, "");
proxyUser = settings.getString(PROXY_USER, "");
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);
int woeId = settings.getInt(TREND_ID, DEFAULT_LOCATION_ID);
location = new LocationImpl(place, woeId);
// user specific settings
auth_key1 = settings.getString(CURRENT_AUTH_KEY1, "");
auth_key2 = settings.getString(CURRENT_AUTH_KEY2, "");
userId = settings.getLong(CURRENT_ID, 0);
// login informations
String oauthToken = settings.getString(OAUTH_TOKEN, "");
String oauthSecret = settings.getString(OAUTH_SECRET, "");
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 int apiType;
private String accessToken, tokenSecret;
private String apiKey, apiSecret;
private String consumerToken, consumerSecret;
private String bearerToken;
private String host;
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}
*/
@ -47,8 +62,8 @@ public class AccountImpl implements Account {
loginDate = cursor.getLong(1);
accessToken = cursor.getString(2);
tokenSecret = cursor.getString(3);
apiKey = cursor.getString(4);
apiSecret = cursor.getString(5);
consumerToken = cursor.getString(4);
consumerSecret = cursor.getString(5);
host = cursor.getString(6);
apiType = cursor.getInt(7);
}
@ -74,29 +89,35 @@ public class AccountImpl implements Account {
@Override
public String getApiKey() {
return apiKey;
public String getConsumerToken() {
return consumerToken;
}
@Override
public String getApiSecret() {
return apiSecret;
public String getConsumerSecret() {
return consumerSecret;
}
@Override
public String getAccessToken() {
public String getOauthToken() {
return accessToken;
}
@Override
public String getTokenSecret() {
public String getOauthSecret() {
return tokenSecret;
}
@Override
public String getBearerToken() {
return bearerToken;
}
@Override
public String getHostname() {
return host;

View File

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

View File

@ -15,6 +15,11 @@ public interface Account {
*/
int API_TWITTER = 1;
/**
* API ID used for Mastodon accounts
*/
int API_MASTODON = 2;
/**
* @return ID of the account (user ID)
*/
@ -34,22 +39,27 @@ public interface Account {
/**
* @return API key assosiated with an account
*/
String getApiKey();
String getConsumerToken();
/**
* @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

View File

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

View File

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

View File

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

View File

@ -304,8 +304,7 @@ public class StatusActivity extends AppCompatActivity implements OnClickListener
if (status.getEmbeddedStatus() != null) {
status = status.getEmbeddedStatus();
}
if (status.getRepliedUserId() == settings.getCurrentUserId()
&& status.getAuthor().getId() != settings.getCurrentUserId()) {
if (status.getRepliedUserId() == settings.getLogin().getId() && status.getAuthor().getId() != settings.getLogin().getId()) {
optHide.setVisible(true);
if (hidden) {
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);
String ownerName = getIntent().getStringExtra(KEY_USERLIST_OWNER_NAME);
isHome = ownerId == settings.getCurrentUserId();
isHome = ownerId == settings.getLogin().getId();
adapter.setupListPage(ownerId, ownerName);
AppStyles.setTabIcons(tabLayout, settings, R.array.userlist_tab_icons);
}

View File

@ -85,19 +85,7 @@ public class AccountFragment extends ListFragment implements OnAccountClickListe
@Override
public void onAccountClick(Account account) {
// set new account
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();
}
}
settings.setLogin(account, false);
if (account.getUser() != null) {
String message = getString(R.string.info_account_selected, account.getUser().getScreenname());
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show();

View File

@ -12,7 +12,7 @@
<string name="title_settings">Einstellungen</string>
<string name="settings_image">Bilder laden</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="confirm_delete_tweet">Tweet löschen?</string>
<string name="error_enter_pin">PIN eingeben!</string>
@ -78,10 +78,10 @@
<string name="error_not_authorized">Keine Berechtigung!</string>
<string name="error_file_format">Dateiformat nicht unterstützt!</string>
<string name="settings_enable_ans_load">Tweet-Replies automatisch laden</string>
<string name="info_tweet_retweeted">Tweet retweeted!</string>
<string name="info_tweet_unretweeted">Retweet entfernt!</string>
<string name="info_tweet_favored">Tweet favorisiert!</string>
<string name="info_tweet_unfavored">tweet aus den favoriten entfernt!</string>
<string name="info_tweet_retweeted">Status reposted!</string>
<string name="info_tweet_unretweeted">Repost entfernt!</string>
<string name="info_tweet_favored">Status favorisiert!</string>
<string name="info_tweet_unfavored">Status aus den Favoriten entfernt!</string>
<string name="proxy_port">Port</string>
<string name="settings_connections">Verbindungseinsellungen</string>
<string name="login_verifier">Login</string>
@ -187,7 +187,7 @@
<string name="confirm_remove_account">Account aus der Liste entfernen?</string>
<string name="menu_select_account">Account auswählen</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_color">Follow Icon</string>
<string name="settings_enable_toolbar_overlap">Kompakte Profilansicht</string>

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<resources>
<!--app/repository dependent strings-->
<string name="app_name" translatable="false">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="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_tweet_retweeted">retweeted</string>
<string name="info_tweet_unretweeted">Retweet removed</string>
<string name="info_tweet_favored">Tweet added to favorites</string>
<string name="info_tweet_unfavored">Tweet removed from favorites</string>
<string name="info_tweet_liked">Tweet liked</string>
<string name="info_tweet_unliked">Tweet unliked</string>
<string name="info_tweet_retweeted">reposted</string>
<string name="info_tweet_unretweeted">Repost removed</string>
<string name="info_tweet_favored">Status added to favorites</string>
<string name="info_tweet_unfavored">Status removed from favorites</string>
<string name="info_tweet_liked">Status liked</string>
<string name="info_tweet_unliked">Status unliked</string>
<string name="info_reply_hidden">Reply is hidden</string>
<string name="info_reply_unhidden">Reply is visible</string>
<string name="info_user_muted">User muted</string>
@ -43,23 +42,23 @@
<string name="info_unfollowed">unfollowed</string>
<string name="info_user_blocked">blocked</string>
<string name="info_user_unblocked">unblocked</string>
<string name="info_tweet_removed">Tweet removed</string>
<string name="info_tweet_sent">Tweet sent</string>
<string name="info_tweet_removed">Status removed</string>
<string name="info_tweet_sent">Status shared</string>
<string name="info_location_pending">requesting location, please wait</string>
<string name="info_refreshing_exclude_list">refreshing exclude list</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_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_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_medialink_copied">Media link copied</string>
<string name="info_account_selected">%1$s selected</string>
<string name="info_error">Error</string>
<!-- 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_not_found">not found!</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_user_not_found">User not found!</string>
<string name="error_accesstoken">Invalid access! Please re-login!</string>
<string name="error_status_length">Tweet is too long!</string>
<string name="error_duplicate_status">Duplicate Tweet!</string>
<string name="error_status_length">Status is too long!</string>
<string name="error_duplicate_status">Duplicate Status!</string>
<string name="error_dm_length">Directmessage is too long!</string>
<string name="error_list_title_empty">Empty list title!</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_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>
@ -100,9 +99,9 @@
<string name="error_empty_token">token key missing!</string>
<!-- 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_twitter_search">Twitter Search</string>
<string name="menu_open_twitter_search">Search</string>
<string name="menu_open_settings">Settings</string>
<string name="menu_create_list">create Userlist</string>
<string name="menu_write_message">Directmessage</string>
@ -155,12 +154,12 @@
<string name="login_pin">enter PIN</string>
<string name="login_key_enable">add keys</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_metrics">Tweet metrics</string>
<string name="title_metrics">Status metrics</string>
<string name="userlist_following" translatable="false">Following</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_background">Background</string>
<string name="settings_text">Text</string>
@ -169,7 +168,7 @@
<string name="settings_icon_color">Icons</string>
<string name="settings_color_like">Like</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="settings_list_size">List size</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="settings_image">enable images</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="tweet_sent_from">"sent from: "</string>
<string name="directmessage">Directmessage</string>
@ -193,10 +192,10 @@
<string name="confirm_unfollow">unfollow user?</string>
<string name="confirm_block">block user?</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="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="profile_link">Link</string>
<string name="close_dm">close directmessage</string>
@ -205,7 +204,7 @@
<string name="confirm_discard">discard changes?</string>
<string name="user_data">User data</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_hint_proxy_ip">enter IP address</string>
<string name="proxy_port">Port</string>
@ -224,7 +223,8 @@
<string name="confirm_delete_list">delete userlist?</string>
<string name="confirm_delete_message">delete message?</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="profile_banner">Banner Image</string>
<string name="editprofile_add_banner">add banner</string>
@ -261,7 +261,7 @@
<string name="button_forward">Fast forward</string>
<string name="button_play_pause">Pause/Play</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_color">Following icon</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="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>
<string name="toolbar_tweet_favoriter">User favoriting this status</string>
<string name="toolbar_tweet_liker">User liking this status</string>
<string name="time_now">now</string>
<string name="confirm_open_link">open in browser</string>