diff --git a/app/build.gradle b/app/build.gradle
index 00107ffe..0d76bda3 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -9,8 +9,8 @@ android {
applicationId 'org.nuclearfog.twidda'
minSdkVersion 16
targetSdkVersion 30
- versionCode 30
- versionName '1.8.6'
+ versionCode 31
+ versionName '1.8.7'
// limiting language support for smaller APK size
resConfigs 'en', 'de-rDE'
vectorDrawables.useSupportLibrary true
diff --git a/app/src/main/java/org/nuclearfog/twidda/activity/AppSettings.java b/app/src/main/java/org/nuclearfog/twidda/activity/AppSettings.java
index 4de11556..3492d922 100644
--- a/app/src/main/java/org/nuclearfog/twidda/activity/AppSettings.java
+++ b/app/src/main/java/org/nuclearfog/twidda/activity/AppSettings.java
@@ -75,13 +75,14 @@ public class AppSettings extends AppCompatActivity implements OnClickListener, O
private LocationLoader locationAsync;
private LocationAdapter locationAdapter;
- private Dialog proxyDialog, databaseDialog, logoutDialog, color_dialog_selector;
- private EditText proxyAddr, proxyPort, proxyUser, proxyPass;
- private CompoundButton enableProxy, enableAuth, hqImage;
+ private Dialog connectDialog, databaseDialog, logoutDialog, color_dialog_selector;
+ private EditText proxyAddr, proxyPort, proxyUser, proxyPass, api_key1, api_key2;
+ private CompoundButton enableProxy, enableAuth, hqImage, enableAPI;
private SeekBar listSizeSelector;
private Spinner locationSpinner;
private TextView list_size;
private Button[] colorButtons;
+ private View layout_key, layout_proxy, layout_auth_en, layout_auth;
private View root;
private ColorMode mode = ColorMode.NONE;
@@ -103,12 +104,21 @@ public class AppSettings extends AppCompatActivity implements OnClickListener, O
enableProxy = findViewById(R.id.settings_enable_proxy);
enableAuth = findViewById(R.id.settings_enable_auth);
hqImage = findViewById(R.id.settings_image_hq);
+ enableAPI = findViewById(R.id.settings_set_custom_keys);
locationSpinner = findViewById(R.id.spinner_woeid);
- proxyAddr = findViewById(R.id.edit_proxyadress);
- proxyPort = findViewById(R.id.edit_proxyport);
+ proxyAddr = findViewById(R.id.edit_proxy_address);
+ proxyPort = findViewById(R.id.edit_proxy_port);
proxyUser = findViewById(R.id.edit_proxyuser);
proxyPass = findViewById(R.id.edit_proxypass);
+ api_key1 = findViewById(R.id.settings_custom_key1);
+ api_key2 = findViewById(R.id.settings_custom_key2);
list_size = findViewById(R.id.settings_list_size);
+
+ layout_proxy = findViewById(R.id.settings_layout_proxy);
+ layout_auth_en = findViewById(R.id.settings_layout_auth_enable);
+ layout_auth = findViewById(R.id.settings_layout_proxy_auth);
+ layout_key = findViewById(R.id.settings_layout_key);
+
root = findViewById(R.id.settings_layout);
TypedArray buttons = getResources().obtainTypedArray(R.array.color_button);
@@ -125,6 +135,14 @@ public class AppSettings extends AppCompatActivity implements OnClickListener, O
trend_card.setVisibility(GONE);
user_card.setVisibility(GONE);
}
+ if (!settings.isProxyEnabled()) {
+ layout_proxy.setVisibility(GONE);
+ layout_auth_en.setVisibility(GONE);
+ layout_auth.setVisibility(GONE);
+ }
+ if (!settings.isCustomApiSet()) {
+ layout_key.setVisibility(GONE);
+ }
locationAdapter = new LocationAdapter(settings);
locationAdapter.addTop(settings.getTrendLocation());
locationSpinner.setAdapter(locationAdapter);
@@ -138,19 +156,21 @@ public class AppSettings extends AppCompatActivity implements OnClickListener, O
setButtonColors();
toggleImg.setChecked(settings.getImageLoad());
toggleAns.setChecked(settings.getAnswerLoad());
+ enableAPI.setChecked(settings.isCustomApiSet());
proxyAddr.setText(settings.getProxyHost());
proxyPort.setText(settings.getProxyPort());
proxyUser.setText(settings.getProxyUser());
proxyPass.setText(settings.getProxyPass());
+ api_key1.setText(settings.getConsumerKey());
+ api_key2.setText(settings.getConsumerSecret());
list_size.setText(Integer.toString(settings.getListSize()));
listSizeSelector.setProgress(settings.getListSize() / 10 - 1);
enableProxy.setChecked(settings.isProxyEnabled());
enableAuth.setChecked(settings.isProxyAuthSet());
hqImage.setEnabled(settings.getImageLoad());
hqImage.setChecked(settings.getImageQuality());
- setProxySetupVisibility(settings.isProxyEnabled(), settings.isProxyAuthSet());
- proxyDialog = DialogBuilder.create(this, WRONG_PROXY, this);
+ connectDialog = DialogBuilder.create(this, WRONG_PROXY, this);
databaseDialog = DialogBuilder.create(this, DEL_DATABASE, this);
logoutDialog = DialogBuilder.create(this, LOGOUT_APP, this);
@@ -160,6 +180,7 @@ public class AppSettings extends AppCompatActivity implements OnClickListener, O
delButton.setOnClickListener(this);
toggleImg.setOnCheckedChangeListener(this);
toggleAns.setOnCheckedChangeListener(this);
+ enableAPI.setOnCheckedChangeListener(this);
enableProxy.setOnCheckedChangeListener(this);
enableAuth.setOnCheckedChangeListener(this);
hqImage.setOnCheckedChangeListener(this);
@@ -181,12 +202,12 @@ public class AppSettings extends AppCompatActivity implements OnClickListener, O
@Override
public void onBackPressed() {
- if (saveProxySettings()) {
+ if (saveConnectionSettings()) {
TwitterEngine.resetTwitter();
super.onBackPressed();
} else {
- if (!proxyDialog.isShowing()) {
- proxyDialog.show();
+ if (!connectDialog.isShowing()) {
+ connectDialog.show();
}
}
}
@@ -356,16 +377,35 @@ public class AppSettings extends AppCompatActivity implements OnClickListener, O
}
// enable proxy settings
else if (viewId == R.id.settings_enable_proxy) {
- setProxySetupVisibility(checked, checked & enableAuth.isChecked());
+ if (checked) {
+ layout_proxy.setVisibility(VISIBLE);
+ layout_auth_en.setVisibility(VISIBLE);
+ } else {
+ layout_proxy.setVisibility(GONE);
+ layout_auth_en.setVisibility(GONE);
+ enableAuth.setChecked(false);
+ }
}
//enable proxy authentication
else if (viewId == R.id.settings_enable_auth) {
- setProxySetupVisibility(true, checked);
+ if (checked) {
+ layout_auth.setVisibility(VISIBLE);
+ } else {
+ layout_auth.setVisibility(GONE);
+ }
}
// enable high quality images
else if (viewId == R.id.settings_image_hq) {
settings.setHighQualityImage(checked);
}
+ // enable custom API setup
+ else if (viewId == R.id.settings_set_custom_keys) {
+ if (checked) {
+ layout_key.setVisibility(VISIBLE);
+ } else {
+ layout_key.setVisibility(GONE);
+ }
+ }
}
@@ -463,28 +503,12 @@ public class AppSettings extends AppCompatActivity implements OnClickListener, O
}
}
- /**
- * set visibility of proxy layouts
- *
- * @param proxySetup visibility of proxy setup
- * @param proxyLogin visibility of proxy login
- */
- private void setProxySetupVisibility(boolean proxySetup, boolean proxyLogin) {
- int setupVisibility = proxySetup ? VISIBLE : GONE;
- int authVisibility = proxyLogin ? VISIBLE : GONE;
- proxyAddr.setVisibility(setupVisibility);
- proxyPort.setVisibility(setupVisibility);
- enableAuth.setVisibility(setupVisibility);
- proxyUser.setVisibility(authVisibility);
- proxyPass.setVisibility(authVisibility);
- }
-
/**
* check proxy settings and save them if they are correct
*
* @return true if settings are saved successfully
*/
- private boolean saveProxySettings() {
+ private boolean saveConnectionSettings() {
boolean checkPassed = true;
if (enableProxy.isChecked()) {
checkPassed = proxyAddr.length() > 0 && proxyPort.length() > 0;
@@ -515,6 +539,17 @@ public class AppSettings extends AppCompatActivity implements OnClickListener, O
} else {
settings.clearProxyServer();
}
+ if (enableAPI.isChecked()) {
+ if (api_key1.length() > 0 && api_key2.length() > 0) {
+ String key1 = api_key1.getText().toString();
+ String key2 = api_key2.getText().toString();
+ settings.setCustomAPI(key1, key2);
+ } else {
+ checkPassed = false;
+ }
+ } else {
+ settings.removeCustomAPI();
+ }
return checkPassed;
}
}
\ No newline at end of file
diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/engine/EngineException.java b/app/src/main/java/org/nuclearfog/twidda/backend/engine/EngineException.java
index 4888d536..ed4b2dda 100644
--- a/app/src/main/java/org/nuclearfog/twidda/backend/engine/EngineException.java
+++ b/app/src/main/java/org/nuclearfog/twidda/backend/engine/EngineException.java
@@ -29,6 +29,7 @@ public class EngineException extends Exception {
NO_CONNECTION,
IMAGE_NOT_LOADED,
ACCOUNT_UPDATE_FAILED,
+ ERROR_API_ACCESS_DENIED,
ERROR_NOT_DEFINED
}
@@ -104,6 +105,10 @@ public class EngineException extends Exception {
errorType = ErrorType.NO_DM_TO_USER;
break;
+ case 261:
+ errorType = ErrorType.ERROR_API_ACCESS_DENIED;
+ break;
+
case 354:
errorType = ErrorType.DM_TOO_LONG;
break;
diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/engine/TwitterEngine.java b/app/src/main/java/org/nuclearfog/twidda/backend/engine/TwitterEngine.java
index 6d2c017b..ec76dddf 100644
--- a/app/src/main/java/org/nuclearfog/twidda/backend/engine/TwitterEngine.java
+++ b/app/src/main/java/org/nuclearfog/twidda/backend/engine/TwitterEngine.java
@@ -73,8 +73,13 @@ public class TwitterEngine {
*/
private void initTwitter() {
ConfigurationBuilder builder = new ConfigurationBuilder();
- builder.setOAuthConsumerKey(Constants.TWITTER_CONSUMER_KEY);
- builder.setOAuthConsumerSecret(Constants.TWITTER_CONSUMER_SECRET);
+ if (settings.isCustomApiSet()) {
+ builder.setOAuthConsumerKey(settings.getConsumerKey());
+ builder.setOAuthConsumerSecret(settings.getConsumerSecret());
+ } else {
+ builder.setOAuthConsumerKey(Constants.TWITTER_CONSUMER_KEY);
+ builder.setOAuthConsumerSecret(Constants.TWITTER_CONSUMER_SECRET);
+ }
// Twitter4J has its own proxy settings
if (settings.isProxyEnabled()) {
builder.setHttpProxyHost(settings.getProxyHost());
diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/utils/DialogBuilder.java b/app/src/main/java/org/nuclearfog/twidda/backend/utils/DialogBuilder.java
index 32e0a618..11a1eeb6 100644
--- a/app/src/main/java/org/nuclearfog/twidda/backend/utils/DialogBuilder.java
+++ b/app/src/main/java/org/nuclearfog/twidda/backend/utils/DialogBuilder.java
@@ -60,9 +60,9 @@ public final class DialogBuilder {
case WRONG_PROXY:
title = R.string.info_error;
- message = R.string.error_wrong_proxy_settings;
- posButton = R.string.confirm_discard_button;
- negButton = R.string.dialog_button_cancel;
+ message = R.string.error_wrong_connection_settings;
+ posButton = R.string.dialog_button_cancel;
+ negButton = R.string.confirm_back;
break;
case DEL_DATABASE:
diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/utils/ErrorHandler.java b/app/src/main/java/org/nuclearfog/twidda/backend/utils/ErrorHandler.java
index 89867c90..7ee3ecc3 100644
--- a/app/src/main/java/org/nuclearfog/twidda/backend/utils/ErrorHandler.java
+++ b/app/src/main/java/org/nuclearfog/twidda/backend/utils/ErrorHandler.java
@@ -97,7 +97,7 @@ public final class ErrorHandler {
break;
case ACCESS_TOKEN_DEAD:
- Toast.makeText(context, R.string.error_cant_login, Toast.LENGTH_SHORT).show();
+ Toast.makeText(context, R.string.error_corrupt_api_key, Toast.LENGTH_SHORT).show();
break;
case TWEET_CANT_REPLY:
@@ -112,6 +112,10 @@ public final class ErrorHandler {
case ACCOUNT_UPDATE_FAILED:
Toast.makeText(context, R.string.error_acc_update, Toast.LENGTH_LONG).show();
break;
+
+ case ERROR_API_ACCESS_DENIED:
+ Toast.makeText(context, R.string.error_api_access_denied, Toast.LENGTH_LONG).show();
+ break;
}
} else {
Toast.makeText(context, R.string.error_not_defined, Toast.LENGTH_SHORT).show();
diff --git a/app/src/main/java/org/nuclearfog/twidda/database/GlobalSettings.java b/app/src/main/java/org/nuclearfog/twidda/database/GlobalSettings.java
index f6a11424..6e161b00 100644
--- a/app/src/main/java/org/nuclearfog/twidda/database/GlobalSettings.java
+++ b/app/src/main/java/org/nuclearfog/twidda/database/GlobalSettings.java
@@ -81,6 +81,9 @@ public class GlobalSettings {
private static final String PROXY_PASS = "proxy_pass";
private static final String TREND_LOC = "location";
private static final String TREND_ID = "world_id";
+ 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";
// file name of the preferences
private static final String APP_SETTINGS = "settings";
@@ -104,13 +107,15 @@ public class GlobalSettings {
private SharedPreferences settings;
private TrendLocation location;
- private String key1, key2;
+ private String api_key1, api_key2;
+ private String auth_key1, auth_key2;
private boolean loadImage;
private boolean hqImages;
private boolean loadAnswer;
private boolean loggedIn;
private boolean isProxyEnabled;
private boolean isProxyAuthSet;
+ private boolean isCustomAPIkeySet;
private int indexFont;
private int background_color;
private int font_color;
@@ -604,11 +609,29 @@ public class GlobalSettings {
*/
public String[] getCurrentUserAccessToken() {
String[] out = new String[2];
- out[0] = key1;
- out[1] = key2;
+ out[0] = auth_key1;
+ out[1] = auth_key2;
return out;
}
+ /**
+ * 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;
+ }
+
/**
* get current users ID
*
@@ -627,8 +650,8 @@ public class GlobalSettings {
*/
public void setConnection(String key1, String key2, long userId) {
loggedIn = true;
- this.key1 = key1;
- this.key2 = key2;
+ this.auth_key1 = key1;
+ this.auth_key2 = key2;
this.userId = userId;
Editor e = settings.edit();
@@ -639,6 +662,48 @@ public class GlobalSettings {
e.apply();
}
+ /**
+ * sets custom API consumer keys
+ *
+ * @param key1 consumer key
+ * @param key2 consumer key secret
+ */
+ public void setCustomAPI(String key1, String key2) {
+ isCustomAPIkeySet = 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() {
+ isCustomAPIkeySet = 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
+ *
+ * @return true if custom API keys are set
+ */
+ public boolean isCustomApiSet() {
+ return isCustomAPIkeySet;
+ }
+
/**
* Remove all user content from Shared Preferences
*/
@@ -663,8 +728,11 @@ public class GlobalSettings {
loadAnswer = settings.getBoolean(ANSWER_LOAD, DEFAULT_DATA_USAGE);
hqImages = settings.getBoolean(IMAGE_QUALITY, DEFAULT_DATA_USAGE);
loggedIn = settings.getBoolean(LOGGED_IN, false);
- key1 = settings.getString(AUTH_KEY1, "");
- key2 = settings.getString(AUTH_KEY2, "");
+ isCustomAPIkeySet = settings.getBoolean(CUSTOM_CONSUMER_KEY_SET, false);
+ api_key1 = settings.getString(CUSTOM_CONSUMER_KEY_1, "");
+ api_key2 = settings.getString(CUSTOM_CONSUMER_KEY_2, "");
+ auth_key1 = settings.getString(AUTH_KEY1, "");
+ auth_key2 = settings.getString(AUTH_KEY2, "");
userId = settings.getLong(USER_ID, 0);
isProxyEnabled = settings.getBoolean(PROXY_SET, false);
isProxyAuthSet = settings.getBoolean(AUTH_SET, false);
diff --git a/app/src/main/res/layout/page_settings.xml b/app/src/main/res/layout/page_settings.xml
index 24813787..a2504de5 100644
--- a/app/src/main/res/layout/page_settings.xml
+++ b/app/src/main/res/layout/page_settings.xml
@@ -399,14 +399,14 @@
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+ tools:ignore="Autofill" />
+ tools:ignore="Autofill" />
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+ tools:ignore="Autofill" />
+ tools:ignore="Autofill" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values-de-rDE/strings.xml b/app/src/main/res/values-de-rDE/strings.xml
index a71848a7..c062b181 100644
--- a/app/src/main/res/values-de-rDE/strings.xml
+++ b/app/src/main/res/values-de-rDE/strings.xml
@@ -87,7 +87,7 @@
Tweet favorisiert!
tweet aus den favoriten entfernt!
Port
- Proxy Einstellung
+ Verbindungseinsellungen
Login
Popup
PIN eingeben
@@ -132,8 +132,7 @@
Video kann nicht abgespielt werden!
Proxy aktivieren
Proxy Authentifizierung aktivieren
- Falsche Proxy Einstellungen
- verwerfen
+ Falsche Verbindung angegeben!
Link konnte nicht geöffnet werden!
Sensible Inhalte
TLS 1.2 wird nicht unterstützt. Die App wird möglicherweise nicht funktionieren!
@@ -182,8 +181,13 @@
Abbrechen
OK
Tweet ist nicht für Antworten freigegeben!
- App ist nicht eingeloggt, Bitte neu einloggen!
+ Fehler, API Schlüssel ist fehlerhaft!
Account Informationen konnten nicht aktualisiert werden! Bitte Eingaben überprüfen.
Kartenfarbe
Symbolfarbe
+ Consumer Key
+ Consumer Secret
+ Eigene API Schlüssel verwenden
+ Fehler, API Zugang wurde abgelehnt!
+ Zurück
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 5fe95bc1..dba1fdb6 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -48,11 +48,13 @@
User data
follows you
load Tweet replies automatically
- Proxy settings
+ Connection settings
enter IP address
Port
Username
Password
+ Consumer key
+ Consumer secret
https://github.com/nuclearfog/Shitter
mute user?
Profile of the list owner
@@ -77,7 +79,8 @@
save image
enable proxy
enable proxy authentication
- discard
+ setup custom API keys
+ back
Potentially sensitive content
3 steps to login
1.
@@ -107,7 +110,7 @@
login to Twitter
Please click the link below to login
Phone does not support TLS 1.2. App will probably not work!
- Wrong proxy settings
+ Wrong connection settings!
can\'t add video
get Twitter PIN from browser first. Please press the first button!
GPS position added
@@ -166,7 +169,7 @@
Empty list title!
Wrong username format!
You can\'t reply to this Tweet!
- can\'t login to Twitter, please Re-Login!
+ Error, corrupt API key!
Account update failed! Please check your input!
Not defined Error!
@@ -202,4 +205,5 @@
OK
Card color
Icon color
+ Error, API access denied!
\ No newline at end of file