From c6081cc281746583c1d66d2e72d4bb42b52e6264 Mon Sep 17 00:00:00 2001 From: adanski Date: Sat, 25 Nov 2023 00:55:12 +0100 Subject: [PATCH] Add possibility to enter Client ID/API Key during login --- app/build.gradle | 2 +- app/src/main/AndroidManifest.xml | 2 +- .../infinityforreddit/AppModule.java | 8 +- .../RedditDataRoomDatabase.java | 1 + .../infinityforreddit/account/Account.java | 14 ++- .../activities/LoginActivity.java | 105 +++++++++++++----- .../asynctasks/ParseAndInsertNewAccount.java | 5 +- .../asynctasks/SwitchAccount.java | 2 + .../infinityforreddit/utils/APIUtils.java | 6 +- app/src/main/res/layout/activity_login.xml | 50 +++++++-- app/src/main/res/values/strings.xml | 3 + 11 files changed, 151 insertions(+), 47 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index dc3be473fd..c419d038e8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -6,7 +6,7 @@ android { compileSdk 33 defaultConfig { applicationId "ml.docilealligator.infinityforreddit" - minSdk 21 + minSdk 26 targetSdk 33 versionCode 143 versionName "6.5.0-beta1" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 48b8c415f0..8a67b01342 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -26,7 +26,7 @@ CREATOR = new Creator() { @@ -56,11 +59,12 @@ public Account[] newArray(int size) { @Ignore public static Account getAnonymousAccount() { - return new Account("-", null, null, null, null, null, 0, false); + return new Account("-", null, null, null, null, null, 0, false, "NONE"); } public Account(@NonNull String accountName, String accessToken, String refreshToken, String code, - String profileImageUrl, String bannerImageUrl, int karma, boolean isCurrentUser) { + String profileImageUrl, String bannerImageUrl, int karma, boolean isCurrentUser, + String clientId) { this.accountName = accountName; this.accessToken = accessToken; this.refreshToken = refreshToken; @@ -69,6 +73,7 @@ public Account(@NonNull String accountName, String accessToken, String refreshTo this.bannerImageUrl = bannerImageUrl; this.karma = karma; this.isCurrentUser = isCurrentUser; + this.clientId = clientId; } @NonNull @@ -108,6 +113,10 @@ public boolean isCurrentUser() { return isCurrentUser; } + public String getClientId() { + return clientId; + } + @Override public int describeContents() { return 0; @@ -123,5 +132,6 @@ public void writeToParcel(Parcel dest, int flags) { dest.writeString(refreshToken); dest.writeString(code); dest.writeByte((byte) (isCurrentUser ? 1 : 0)); + dest.writeString(clientId); } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/LoginActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/LoginActivity.java index 7b1cb7cc8f..34c15a7201 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/LoginActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/LoginActivity.java @@ -3,6 +3,7 @@ import android.app.Activity; import android.content.Intent; import android.content.SharedPreferences; +import android.content.res.ColorStateList; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.net.Uri; @@ -14,9 +15,12 @@ import android.view.InflateException; import android.view.MenuItem; import android.view.View; +import android.view.inputmethod.InputMethodManager; import android.webkit.CookieManager; import android.webkit.WebView; import android.webkit.WebViewClient; +import android.widget.Button; +import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; @@ -75,6 +79,12 @@ public class LoginActivity extends BaseActivity { WebView webView; @BindView(R.id.fab_login_activity) FloatingActionButton fab; + @BindView(R.id.client_id_info) + TextView clientIdInfoTextView; + @BindView(R.id.client_id_input) + EditText clientIdInputEditText; + @BindView(R.id.client_id_apply) + Button clientApplyButton; @Inject @Named("no_oauth") Retrofit mRetrofit; @@ -150,9 +160,63 @@ protected void onCreate(Bundle savedInstanceState) { webView.getSettings().setJavaScriptEnabled(true); webView.getSettings().setDomStorageEnabled(enableDom); + String clientId = mCurrentAccountSharedPreferences.getString(APIUtils.CLIENT_ID_KEY, "NONE"); + if (!clientId.isBlank() && !clientId.equals("NONE")) { + clientApplyButton.setText("Update"); + clientIdInfoTextView.setText(R.string.login_activity_input_client_id_update); + clientIdInputEditText.setText(clientId); + loadLoginWebview(clientId); + } + + clientApplyButton.setOnClickListener(view -> { + view.setClickable(false); + InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); + inputMethodManager.hideSoftInputFromWindow(view.getApplicationWindowToken(), 0); + + String cId = clientIdInputEditText.getText().toString(); + + if (cId.isBlank()) { + Toast.makeText(LoginActivity.this, "Please enter a Client ID/API Key first", Toast.LENGTH_LONG).show(); + view.setClickable(true); + return; + } + mCurrentAccountSharedPreferences.edit().putString(APIUtils.CLIENT_ID_KEY, cId).apply(); + APIUtils.CLIENT_ID = cId; + view.setClickable(true); + loadLoginWebview(cId); + }); + + if (!isAgreeToUserAgreement) { + TextView messageTextView = new TextView(this); + int padding = (int) Utils.convertDpToPixel(24, this); + messageTextView.setPaddingRelative(padding, padding, padding, padding); + SpannableString message = new SpannableString(getString(R.string.user_agreement_message, "https://www.redditinc.com/policies/user-agreement-september-12-2021", "https://docile-alligator.github.io")); + Linkify.addLinks(message, Linkify.WEB_URLS); + messageTextView.setMovementMethod(BetterLinkMovementMethod.newInstance().setOnLinkClickListener(new BetterLinkMovementMethod.OnLinkClickListener() { + @Override + public boolean onClick(TextView textView, String url) { + Intent intent = new Intent(LoginActivity.this, LinkResolverActivity.class); + intent.setData(Uri.parse(url)); + startActivity(intent); + return true; + } + })); + messageTextView.setLinkTextColor(getResources().getColor(R.color.colorAccent)); + messageTextView.setText(message); + new MaterialAlertDialogBuilder(this, R.style.MaterialAlertDialogTheme) + .setTitle(getString(R.string.user_agreement_dialog_title)) + .setView(messageTextView) + .setPositiveButton(R.string.agree, (dialogInterface, i) -> isAgreeToUserAgreement = true) + .setNegativeButton(R.string.do_not_agree, (dialogInterface, i) -> finish()) + .setCancelable(false) + .show(); + } + } + + void loadLoginWebview(String clientId) { Uri baseUri = Uri.parse(APIUtils.OAUTH_URL); Uri.Builder uriBuilder = baseUri.buildUpon(); - uriBuilder.appendQueryParameter(APIUtils.CLIENT_ID_KEY, APIUtils.CLIENT_ID); + uriBuilder.appendQueryParameter(APIUtils.CLIENT_ID_KEY, clientId); uriBuilder.appendQueryParameter(APIUtils.RESPONSE_TYPE_KEY, APIUtils.RESPONSE_TYPE); uriBuilder.appendQueryParameter(APIUtils.STATE_KEY, APIUtils.STATE); uriBuilder.appendQueryParameter(APIUtils.REDIRECT_URI_KEY, APIUtils.REDIRECT_URI); @@ -201,15 +265,19 @@ public void onResponse(@NonNull Call call, @NonNull Response res @Override public void onFetchMyInfoSuccess(String name, String profileImageUrl, String bannerImageUrl, int karma) { mCurrentAccountSharedPreferences.edit().putString(SharedPreferencesUtils.ACCESS_TOKEN, accessToken) + .putString(APIUtils.CLIENT_ID_KEY, clientId) .putString(SharedPreferencesUtils.ACCOUNT_NAME, name) .putString(SharedPreferencesUtils.ACCOUNT_IMAGE_URL, profileImageUrl).apply(); + APIUtils.CLIENT_ID = clientId; + APIUtils.USER_AGENT = APIUtils.USER_AGENT.replaceFirst("/u/.*\\)", "/u/" + name + ")"); ParseAndInsertNewAccount.parseAndInsertNewAccount(mExecutor, new Handler(), name, accessToken, refreshToken, profileImageUrl, bannerImageUrl, karma, authCode, mRedditDataRoomDatabase.accountDao(), () -> { Intent resultIntent = new Intent(); setResult(Activity.RESULT_OK, resultIntent); finish(); - }); + }, + clientId); } @Override @@ -222,7 +290,7 @@ public void onFetchMyInfoFailed(boolean parseFailed) { finish(); } - }); + }); } catch (JSONException e) { e.printStackTrace(); Toast.makeText(LoginActivity.this, R.string.parse_json_response_error, Toast.LENGTH_SHORT).show(); @@ -266,32 +334,6 @@ public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); } }); - - if (!isAgreeToUserAgreement) { - TextView messageTextView = new TextView(this); - int padding = (int) Utils.convertDpToPixel(24, this); - messageTextView.setPaddingRelative(padding, padding, padding, padding); - SpannableString message = new SpannableString(getString(R.string.user_agreement_message, "https://www.redditinc.com/policies/user-agreement", "https://docile-alligator.github.io")); - Linkify.addLinks(message, Linkify.WEB_URLS); - messageTextView.setMovementMethod(BetterLinkMovementMethod.newInstance().setOnLinkClickListener(new BetterLinkMovementMethod.OnLinkClickListener() { - @Override - public boolean onClick(TextView textView, String url) { - Intent intent = new Intent(LoginActivity.this, LinkResolverActivity.class); - intent.setData(Uri.parse(url)); - startActivity(intent); - return true; - } - })); - messageTextView.setLinkTextColor(getResources().getColor(R.color.colorAccent)); - messageTextView.setText(message); - new MaterialAlertDialogBuilder(this, R.style.MaterialAlertDialogTheme) - .setTitle(getString(R.string.user_agreement_dialog_title)) - .setView(messageTextView) - .setPositiveButton(R.string.agree, (dialogInterface, i) -> isAgreeToUserAgreement = true) - .setNegativeButton(R.string.do_not_agree, (dialogInterface, i) -> finish()) - .setCancelable(false) - .show(); - } } @Override @@ -322,6 +364,11 @@ protected void applyCustomTheme() { if (typeface != null) { twoFAInfoTextView.setTypeface(typeface); } + clientIdInfoTextView.setTextColor(mCustomThemeWrapper.getPrimaryTextColor()); + clientIdInputEditText.setTextColor(mCustomThemeWrapper.getPrimaryTextColor()); + clientApplyButton.setBackgroundTintList(ColorStateList.valueOf(customThemeWrapper.getColorAccent())); + clientApplyButton.setTextColor(mCustomThemeWrapper.getButtonTextColor()); + } @Override diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/asynctasks/ParseAndInsertNewAccount.java b/app/src/main/java/ml/docilealligator/infinityforreddit/asynctasks/ParseAndInsertNewAccount.java index b742f983e3..fd20f9a5cc 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/asynctasks/ParseAndInsertNewAccount.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/asynctasks/ParseAndInsertNewAccount.java @@ -12,10 +12,11 @@ public class ParseAndInsertNewAccount { public static void parseAndInsertNewAccount(Executor executor, Handler handler, String username, String accessToken, String refreshToken, String profileImageUrl, String bannerImageUrl, int karma, String code, AccountDao accountDao, - ParseAndInsertAccountListener parseAndInsertAccountListener) { + ParseAndInsertAccountListener parseAndInsertAccountListener, + String clientId) { executor.execute(() -> { Account account = new Account(username, accessToken, refreshToken, code, profileImageUrl, - bannerImageUrl, karma, true); + bannerImageUrl, karma, true, clientId); accountDao.markAllAccountsNonCurrent(); accountDao.insert(account); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/asynctasks/SwitchAccount.java b/app/src/main/java/ml/docilealligator/infinityforreddit/asynctasks/SwitchAccount.java index f54439737e..0893805453 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/asynctasks/SwitchAccount.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/asynctasks/SwitchAccount.java @@ -7,6 +7,7 @@ import ml.docilealligator.infinityforreddit.account.Account; import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase; +import ml.docilealligator.infinityforreddit.utils.APIUtils; import ml.docilealligator.infinityforreddit.utils.SharedPreferencesUtils; public class SwitchAccount { @@ -22,6 +23,7 @@ public static void switchAccount(RedditDataRoomDatabase redditDataRoomDatabase, .putString(SharedPreferencesUtils.ACCESS_TOKEN, account.getAccessToken()) .putString(SharedPreferencesUtils.ACCOUNT_NAME, account.getAccountName()) .putString(SharedPreferencesUtils.ACCOUNT_IMAGE_URL, account.getProfileImageUrl()).apply(); + APIUtils.USER_AGENT = APIUtils.USER_AGENT.replaceFirst("/u/.*\\)", "/u/" + account.getAccountName() + ")"); handler.post(() -> switchAccountListener.switched(account)); }); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/utils/APIUtils.java b/app/src/main/java/ml/docilealligator/infinityforreddit/utils/APIUtils.java index 3d4638457d..43f6d6a6a4 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/utils/APIUtils.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/utils/APIUtils.java @@ -27,7 +27,7 @@ public class APIUtils { public static final String CLIENT_ID_KEY = "client_id"; public static final String CLIENT_SECRET_KEY = "client_secret"; - public static final String CLIENT_ID = "NOe2iKrPPzwscA"; + public static volatile String CLIENT_ID = "NONE"; public static final String IMGUR_CLIENT_ID = "Client-ID cc671794e0ab397"; public static final String REDGIFS_CLIENT_ID = "1828d0bcc93-15ac-bde6-0005-d2ecbe8daab3"; public static final String REDGIFS_CLIENT_SECRET = "TJBlw7jRXW65NAGgFBtgZHu97WlzRXHYybK81sZ9dLM="; @@ -36,7 +36,7 @@ public class APIUtils { public static final String STATE_KEY = "state"; public static final String STATE = "23ro8xlxvzp4asqd"; public static final String REDIRECT_URI_KEY = "redirect_uri"; - public static final String REDIRECT_URI = "infinity://localhost"; + public static final String REDIRECT_URI = "http://localhost:4321"; public static final String DURATION_KEY = "duration"; public static final String DURATION = "permanent"; public static final String SCOPE_KEY = "scope"; @@ -46,7 +46,7 @@ public class APIUtils { public static final String AUTHORIZATION_KEY = "Authorization"; public static final String AUTHORIZATION_BASE = "bearer "; public static final String USER_AGENT_KEY = "User-Agent"; - public static final String USER_AGENT = "android:ml.docilealligator.infinityforreddit:v6.2.5 (by /u/Hostilenemy)"; + public static volatile String USER_AGENT = "android:infinity-personal:v6.5.0 (by /u/deleted)"; public static final String GRANT_TYPE_KEY = "grant_type"; public static final String GRANT_TYPE_REFRESH_TOKEN = "refresh_token"; diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index 4c4d3e9f99..b5deeffab4 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -2,9 +2,9 @@ + app:navigationIcon="?attr/homeAsUpIndicator" + app:popupTheme="@style/AppTheme.PopupOverlay" /> @@ -33,11 +33,45 @@ android:id="@+id/two_fa_infO_text_view_login_activity" android:layout_width="match_parent" android:layout_height="wrap_content" - android:padding="16dp" - android:drawablePadding="32dp" + android:drawablePadding="6dp" + android:fontFamily="?attr/font_family" + android:padding="6dp" android:text="@string/login_activity_2fa_prompt" - android:textSize="?attr/font_default" - android:fontFamily="?attr/font_family" /> + android:textSize="?attr/font_default" /> + + + + + + + + +