From b884d67fbddcc3446c380c6a48c715cf9eb70b9c Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 26 May 2022 14:20:51 +0200 Subject: [PATCH] Fix some crashes --- .../android/activities/LoginActivity.java | 69 ++++----- .../android/activities/SettingsActivity.java | 6 + .../activities/WebviewConnectActivity.java | 75 ++++++---- .../android/client/entities/api/Account.java | 5 +- .../android/client/entities/app/Account.java | 23 +-- .../ui/fragment/login/FragmentLoginMain.java | 136 +++++++++--------- .../timeline/FragmentMastodonContext.java | 5 +- .../main/res/layout/fragment_login_main.xml | 7 + app/src/main/res/values/strings.xml | 1 + 9 files changed, 174 insertions(+), 153 deletions(-) diff --git a/app/src/main/java/app/fedilab/android/activities/LoginActivity.java b/app/src/main/java/app/fedilab/android/activities/LoginActivity.java index 15a4b12e0..e790cf491 100644 --- a/app/src/main/java/app/fedilab/android/activities/LoginActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/LoginActivity.java @@ -14,27 +14,22 @@ package app.fedilab.android.activities; * You should have received a copy of the GNU General Public License along with Fedilab; if not, * see . */ -import static app.fedilab.android.BaseMainActivity.admin; import static app.fedilab.android.BaseMainActivity.api; import static app.fedilab.android.BaseMainActivity.client_id; import static app.fedilab.android.BaseMainActivity.client_secret; import static app.fedilab.android.BaseMainActivity.currentInstance; import static app.fedilab.android.BaseMainActivity.software; -import static app.fedilab.android.helper.Helper.PREF_USER_TOKEN; import static app.fedilab.android.helper.MastodonHelper.REDIRECT_CONTENT_WEB; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; import android.view.Menu; import android.view.MenuItem; import android.widget.FrameLayout; import android.widget.Toast; import androidx.lifecycle.ViewModelProvider; -import androidx.navigation.fragment.NavHostFragment; import androidx.preference.PreferenceManager; import org.jetbrains.annotations.NotNull; @@ -44,12 +39,11 @@ import java.util.regex.Matcher; import app.fedilab.android.BaseMainActivity; import app.fedilab.android.R; import app.fedilab.android.client.entities.app.Account; -import app.fedilab.android.client.entities.app.WellKnownNodeinfo; -import app.fedilab.android.exception.DBException; import app.fedilab.android.helper.Helper; import app.fedilab.android.helper.ThemeHelper; import app.fedilab.android.ui.fragment.login.FragmentLoginMain; import app.fedilab.android.viewmodel.mastodon.AccountsVM; +import app.fedilab.android.viewmodel.mastodon.AdminVM; import app.fedilab.android.viewmodel.mastodon.OauthVM; import es.dmoral.toasty.Toasty; @@ -58,10 +52,7 @@ public class LoginActivity extends BaseActivity { private final int PICK_IMPORT = 5557; - private String oldSearch; - private String autofilledInstance; - private WellKnownNodeinfo.NodeInfo nodeInfo; - private NavHostFragment host; + private boolean requestedAdmin; @Override protected void onCreate(Bundle savedInstanceState) { @@ -71,14 +62,7 @@ public class LoginActivity extends BaseActivity { setContentView(new FrameLayout(this)); Helper.addFragment(getSupportFragmentManager(), android.R.id.content, new FragmentLoginMain(), null, null, null); - - Bundle b = getIntent().getExtras(); - if (b != null) { - autofilledInstance = b.getString("instance", null); - admin = b.getBoolean("admin", false); - } - - + requestedAdmin = false; //The activity handles a redirect URI, it will extract token code and will proceed to authentication //That happens when the user wants to use an external browser if (getIntent() != null && getIntent().getData() != null && getIntent().getData().toString().contains(REDIRECT_CONTENT_WEB + "?code=")) { @@ -93,7 +77,8 @@ public class LoginActivity extends BaseActivity { //We are dealing with a Mastodon API if (api == Account.API.MASTODON) { //API call to get the user token - oauthVM.createToken(currentInstance, "authorization_code", client_id, client_secret, Helper.REDIRECT_CONTENT_WEB, Helper.OAUTH_SCOPES, code) + String scope = requestedAdmin ? Helper.OAUTH_SCOPES_ADMIN : Helper.OAUTH_SCOPES; + oauthVM.createToken(currentInstance, "authorization_code", client_id, client_secret, Helper.REDIRECT_CONTENT_WEB, scope, code) .observe(LoginActivity.this, tokenObj -> { Account account = new Account(); account.client_id = BaseMainActivity.client_id; @@ -106,37 +91,31 @@ public class LoginActivity extends BaseActivity { AccountsVM accountsVM = new ViewModelProvider(LoginActivity.this).get(AccountsVM.class); accountsVM.getConnectedAccount(currentInstance, account.token).observe(LoginActivity.this, mastodonAccount -> { account.mastodon_account = mastodonAccount; - new Thread(() -> { - try { - account.user_id = mastodonAccount.id; - //update the database - new Account(LoginActivity.this).insertOrUpdate(account); - - BaseMainActivity.currentToken = account.token; - BaseMainActivity.currentUserID = account.user_id; - api = Account.API.MASTODON; - SharedPreferences.Editor editor = sharedpreferences.edit(); - editor.putString(PREF_USER_TOKEN, account.token); - editor.commit(); - //The user is now aut - //The user is now authenticated, it will be redirected to MainActivity - Handler mainHandler = new Handler(Looper.getMainLooper()); - Runnable myRunnable = () -> { - Intent mainActivity = new Intent(LoginActivity.this, MainActivity.class); - startActivity(mainActivity); - finish(); - }; - mainHandler.post(myRunnable); - } catch (DBException e) { - e.printStackTrace(); - } - }).start(); + account.user_id = mastodonAccount.id; + //We check if user have really moderator rights + if (requestedAdmin) { + AdminVM adminVM = new ViewModelProvider(LoginActivity.this).get(AdminVM.class); + adminVM.getAccount(account.instance, account.token, account.user_id).observe(LoginActivity.this, adminAccount -> { + account.mastodon_account.admin = adminAccount != null; + WebviewConnectActivity.proceedLogin(LoginActivity.this, account); + }); + } else { + WebviewConnectActivity.proceedLogin(LoginActivity.this, account); + } }); }); } } } + public boolean requestedAdmin() { + return requestedAdmin; + } + + public boolean setAdmin(boolean askAdmin) { + return requestedAdmin = askAdmin; + } + @Override protected void onResume() { super.onResume(); diff --git a/app/src/main/java/app/fedilab/android/activities/SettingsActivity.java b/app/src/main/java/app/fedilab/android/activities/SettingsActivity.java index f481f8f63..fdb46aca3 100644 --- a/app/src/main/java/app/fedilab/android/activities/SettingsActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/SettingsActivity.java @@ -17,6 +17,7 @@ package app.fedilab.android.activities; import android.graphics.drawable.ColorDrawable; import android.os.Bundle; import android.view.MenuItem; +import android.view.View; import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; @@ -68,6 +69,11 @@ public class SettingsActivity extends BaseActivity { binding.setTheming.setOnClickListener(v -> displaySettings(SettingsEnum.THEMING)); binding.setAdministration.setOnClickListener(v -> displaySettings(SettingsEnum.ADMINISTRATION)); binding.setLanguage.setOnClickListener(v -> displaySettings(SettingsEnum.LANGUAGE)); + if (MainActivity.accountWeakReference.get().mastodon_account.admin) { + binding.setAdministration.setVisibility(View.VISIBLE); + } else { + binding.setAdministration.setVisibility(View.GONE); + } } public void displaySettings(SettingsEnum settingsEnum) { diff --git a/app/src/main/java/app/fedilab/android/activities/WebviewConnectActivity.java b/app/src/main/java/app/fedilab/android/activities/WebviewConnectActivity.java index e5d5863c0..590d74ca8 100644 --- a/app/src/main/java/app/fedilab/android/activities/WebviewConnectActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/WebviewConnectActivity.java @@ -22,6 +22,7 @@ import static app.fedilab.android.BaseMainActivity.software; import static app.fedilab.android.helper.Helper.PREF_USER_TOKEN; import android.annotation.SuppressLint; +import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; @@ -30,6 +31,7 @@ import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Looper; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -59,6 +61,7 @@ import app.fedilab.android.exception.DBException; import app.fedilab.android.helper.Helper; import app.fedilab.android.helper.ThemeHelper; import app.fedilab.android.viewmodel.mastodon.AccountsVM; +import app.fedilab.android.viewmodel.mastodon.AdminVM; import app.fedilab.android.viewmodel.mastodon.OauthVM; @@ -68,6 +71,7 @@ public class WebviewConnectActivity extends BaseActivity { private ActivityWebviewConnectBinding binding; private AlertDialog alert; private String login_url; + private boolean requestedAdmin; @SuppressWarnings("deprecation") public static void clearCookies(Context context) { @@ -86,6 +90,34 @@ public class WebviewConnectActivity extends BaseActivity { } } + @SuppressLint("ApplySharedPref") + public static void proceedLogin(Activity activity, Account account) { + new Thread(() -> { + try { + //update the database + Log.v(Helper.TAG, "account.mastodon_account.admin: " + account.mastodon_account.admin); + new Account(activity).insertOrUpdate(account); + Handler mainHandler = new Handler(Looper.getMainLooper()); + BaseMainActivity.currentToken = account.token; + BaseMainActivity.currentUserID = account.user_id; + api = Account.API.MASTODON; + SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(activity); + SharedPreferences.Editor editor = sharedpreferences.edit(); + editor.putString(PREF_USER_TOKEN, account.token); + editor.commit(); + //The user is now authenticated, it will be redirected to MainActivity + Runnable myRunnable = () -> { + Intent mainActivity = new Intent(activity, MainActivity.class); + activity.startActivity(mainActivity); + activity.finish(); + }; + mainHandler.post(myRunnable); + } catch (DBException e) { + e.printStackTrace(); + } + }).start(); + } + @SuppressLint("SetJavaScriptEnabled") public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -99,7 +131,10 @@ public class WebviewConnectActivity extends BaseActivity { Bundle b = getIntent().getExtras(); if (b != null) { login_url = b.getString("login_url"); + requestedAdmin = b.getBoolean("requestedAdmin", false); + } + Log.v(Helper.TAG, "requestedAdmin: " + requestedAdmin); if (login_url == null) finish(); ActionBar actionBar = getSupportActionBar(); @@ -190,7 +225,8 @@ public class WebviewConnectActivity extends BaseActivity { String code = matcher.group(1); OauthVM oauthVM = new ViewModelProvider(WebviewConnectActivity.this).get(OauthVM.class); //API call to get the user token - oauthVM.createToken(currentInstance, "authorization_code", BaseMainActivity.client_id, BaseMainActivity.client_secret, Helper.REDIRECT_CONTENT_WEB, Helper.OAUTH_SCOPES, code) + String scope = requestedAdmin ? Helper.OAUTH_SCOPES_ADMIN : Helper.OAUTH_SCOPES; + oauthVM.createToken(currentInstance, "authorization_code", BaseMainActivity.client_id, BaseMainActivity.client_secret, Helper.REDIRECT_CONTENT_WEB, scope, code) .observe(WebviewConnectActivity.this, tokenObj -> { Account account = new Account(); account.client_id = BaseMainActivity.client_id; @@ -204,29 +240,20 @@ public class WebviewConnectActivity extends BaseActivity { accountsVM.getConnectedAccount(currentInstance, account.token).observe(WebviewConnectActivity.this, mastodonAccount -> { account.mastodon_account = mastodonAccount; account.user_id = mastodonAccount.id; - new Thread(() -> { - try { - //update the database - new Account(WebviewConnectActivity.this).insertOrUpdate(account); - Handler mainHandler = new Handler(Looper.getMainLooper()); - BaseMainActivity.currentToken = account.token; - BaseMainActivity.currentUserID = account.user_id; - api = Account.API.MASTODON; - SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(WebviewConnectActivity.this); - SharedPreferences.Editor editor = sharedpreferences.edit(); - editor.putString(PREF_USER_TOKEN, account.token); - editor.commit(); - //The user is now authenticated, it will be redirected to MainActivity - Runnable myRunnable = () -> { - Intent mainActivity = new Intent(WebviewConnectActivity.this, MainActivity.class); - startActivity(mainActivity); - finish(); - }; - mainHandler.post(myRunnable); - } catch (DBException e) { - e.printStackTrace(); - } - }).start(); + //We check if user have really moderator rights + if (requestedAdmin) { + AdminVM adminVM = new ViewModelProvider(WebviewConnectActivity.this).get(AdminVM.class); + Log.v(Helper.TAG, " account.instance: " + account.instance); + Log.v(Helper.TAG, " account.token: " + account.token); + Log.v(Helper.TAG, " account.user_id: " + account.user_id); + adminVM.getAccount(account.instance, account.token, account.user_id).observe(WebviewConnectActivity.this, adminAccount -> { + Log.v(Helper.TAG, "adminAccount: " + adminAccount); + account.mastodon_account.admin = adminAccount != null; + proceedLogin(WebviewConnectActivity.this, account); + }); + } else { + proceedLogin(WebviewConnectActivity.this, account); + } }); }); return true; diff --git a/app/src/main/java/app/fedilab/android/client/entities/api/Account.java b/app/src/main/java/app/fedilab/android/client/entities/api/Account.java index 9bd447856..fb389ce4d 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/api/Account.java +++ b/app/src/main/java/app/fedilab/android/client/entities/api/Account.java @@ -73,14 +73,15 @@ public class Account implements Serializable { public Date mute_expires_at; @SerializedName("moved") public Account moved; - + //Local var + @SerializedName("admin") + public boolean admin; //Some extra spannable element - They will be filled automatically when fetching the account public transient Spannable span_display_name; public transient Spannable span_note; public transient RelationShip relationShip; - public static class AccountParams implements Serializable { @SerializedName("discoverable") public boolean discoverable; diff --git a/app/src/main/java/app/fedilab/android/client/entities/app/Account.java b/app/src/main/java/app/fedilab/android/client/entities/app/Account.java index ab5dc9004..b0b710104 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/app/Account.java +++ b/app/src/main/java/app/fedilab/android/client/entities/app/Account.java @@ -431,29 +431,34 @@ public class Account implements Serializable { account.updated_at = Helper.stringToDate(context, c.getString(c.getColumnIndexOrThrow(Sqlite.COL_UPDATED_AT))); account.software = c.getString(c.getColumnIndexOrThrow(Sqlite.COL_SOFTWARE)); String apiStr = c.getString(c.getColumnIndexOrThrow(Sqlite.COL_API)); - API api = null; + API api; switch (apiStr) { case "MASTODON": api = API.MASTODON; break; - case "PEERTUBE": - api = API.PEERTUBE; + case "FRIENDICA": + api = API.FRIENDICA; break; case "PIXELFED": api = API.PIXELFED; break; + case "PLEROMA": + api = API.PLEROMA; + break; + default: + api = API.UNKNOWN; + break; } account.api = api; - if (api == API.MASTODON) { - account.mastodon_account = restoreAccountFromString(c.getString(c.getColumnIndexOrThrow(Sqlite.COL_ACCOUNT))); - } - + account.mastodon_account = restoreAccountFromString(c.getString(c.getColumnIndexOrThrow(Sqlite.COL_ACCOUNT))); return account; } public enum API { MASTODON, - PEERTUBE, - PIXELFED + FRIENDICA, + PLEROMA, + PIXELFED, + UNKNOWN } } diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/login/FragmentLoginMain.java b/app/src/main/java/app/fedilab/android/ui/fragment/login/FragmentLoginMain.java index 0b03d571b..770f36657 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/login/FragmentLoginMain.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/login/FragmentLoginMain.java @@ -14,7 +14,6 @@ package app.fedilab.android.ui.fragment.login; * You should have received a copy of the GNU General Public License along with Fedilab; if not, * see . */ -import static app.fedilab.android.BaseMainActivity.admin; import static app.fedilab.android.BaseMainActivity.api; import static app.fedilab.android.BaseMainActivity.client_id; import static app.fedilab.android.BaseMainActivity.client_secret; @@ -48,6 +47,7 @@ import java.net.URLEncoder; import app.fedilab.android.BaseMainActivity; import app.fedilab.android.R; +import app.fedilab.android.activities.LoginActivity; import app.fedilab.android.activities.ProxyActivity; import app.fedilab.android.activities.WebviewConnectActivity; import app.fedilab.android.client.entities.app.Account; @@ -62,7 +62,6 @@ import es.dmoral.toasty.Toasty; public class FragmentLoginMain extends Fragment { - private static boolean client_id_for_webview = false; private FragmentLoginMainBinding binding; private boolean searchInstanceRunning = false; private String oldSearch; @@ -77,6 +76,7 @@ public class FragmentLoginMain extends Fragment { binding.menuIcon.setOnClickListener(this::showMenu); binding.loginInstance.setOnItemClickListener((parent, view, position, id) -> oldSearch = parent.getItemAtPosition(position).toString().trim()); + binding.adminScope.setOnCheckedChangeListener((compoundButton, checked) -> ((LoginActivity) requireActivity()).setAdmin(checked)); binding.loginInstance.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { @@ -144,29 +144,25 @@ public class FragmentLoginMain extends Fragment { NodeInfoVM nodeInfoVM = new ViewModelProvider(requireActivity()).get(NodeInfoVM.class); nodeInfoVM.getNodeInfo(binding.loginInstance.getText().toString()).observe(requireActivity(), nodeInfo -> { binding.continueButton.setEnabled(true); - if (nodeInfo != null && nodeInfo.software != null) { - BaseMainActivity.software = nodeInfo.software.name.toUpperCase(); - if (nodeInfo.software.name.toUpperCase().trim().equals("PLEROMA") || nodeInfo.software.name.toUpperCase().trim().equals("MASTODON") || nodeInfo.software.name.toUpperCase().trim().equals("PIXELFED")) { - client_id_for_webview = true; + BaseMainActivity.software = nodeInfo.software.name.toUpperCase(); + switch (nodeInfo.software.name.toUpperCase().trim()) { + case "MASTODON": api = Account.API.MASTODON; - retrievesClientId(currentInstance); - } else { - client_id_for_webview = false; - if (nodeInfo.software.name.equals("PEERTUBE")) { - Toasty.error(requireActivity(), "Peertube is currently not supported", Toasty.LENGTH_LONG).show(); - } else if (nodeInfo.software.name.equals("GNU")) { - Toasty.error(requireActivity(), "GNU is currently not supported", Toasty.LENGTH_LONG).show(); - } else { //Fallback to Mastodon - client_id_for_webview = true; - api = Account.API.MASTODON; - retrievesClientId(currentInstance); - } - } - } else { //Fallback to Mastodon - client_id_for_webview = true; - api = Account.API.MASTODON; - retrievesClientId(currentInstance); + break; + case "FRIENDICA": + api = Account.API.FRIENDICA; + break; + case "PIXELFED": + api = Account.API.PIXELFED; + break; + case "PLEROMA": + api = Account.API.PLEROMA; + break; + default: + api = Account.API.UNKNOWN; + break; } + retrievesClientId(currentInstance); }); }); return root; @@ -217,57 +213,53 @@ public class FragmentLoginMain extends Fragment { } private void retrievesClientId(String instance) { - if (client_id_for_webview) { - if (!instance.startsWith("http://") && !instance.startsWith("https://")) { - instance = "https://" + instance; - } - String host = instance; - try { - URL url = new URL(instance); - host = url.getHost(); - } catch (MalformedURLException e) { - e.printStackTrace(); - } - - try { - currentInstance = URLEncoder.encode(host, "utf-8"); - } catch (UnsupportedEncodingException e) { - Toasty.error(requireActivity(), getString(R.string.client_error), Toast.LENGTH_LONG).show(); - } - if (api == Account.API.MASTODON) { - String scopes = Helper.OAUTH_SCOPES; - if (admin) { - scopes = Helper.OAUTH_SCOPES_ADMIN; - } - AppsVM appsVM = new ViewModelProvider(requireActivity()).get(AppsVM.class); - appsVM.createApp(currentInstance, getString(R.string.app_name), - client_id_for_webview ? Helper.REDIRECT_CONTENT_WEB : Helper.REDIRECT_CONTENT, - scopes, - Helper.WEBSITE_VALUE - ).observe(requireActivity(), app -> { - client_id = app.client_id; - client_secret = app.client_secret; - String redirectUrl = MastodonHelper.authorizeURL(currentInstance, client_id, admin); - SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(requireActivity()); - boolean embedded_browser = sharedpreferences.getBoolean(getString(R.string.SET_EMBEDDED_BROWSER), true); - if (embedded_browser) { - Intent i = new Intent(requireActivity(), WebviewConnectActivity.class); - i.putExtra("login_url", redirectUrl); - startActivity(i); - requireActivity().finish(); - } else { - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.setData(Uri.parse(redirectUrl)); - try { - startActivity(intent); - } catch (Exception e) { - Toasty.error(requireActivity(), getString(R.string.toast_error), Toast.LENGTH_LONG).show(); - } + if (!instance.startsWith("http://") && !instance.startsWith("https://")) { + instance = "https://" + instance; + } + String host = instance; + try { + URL url = new URL(instance); + host = url.getHost(); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + try { + currentInstance = URLEncoder.encode(host, "utf-8"); + } catch (UnsupportedEncodingException e) { + Toasty.error(requireActivity(), getString(R.string.client_error), Toast.LENGTH_LONG).show(); + } + if (api == Account.API.MASTODON) { + String scopes = binding.adminScope.isChecked() ? Helper.OAUTH_SCOPES_ADMIN : Helper.OAUTH_SCOPES; + AppsVM appsVM = new ViewModelProvider(requireActivity()).get(AppsVM.class); + appsVM.createApp(currentInstance, getString(R.string.app_name), + Helper.REDIRECT_CONTENT_WEB, + scopes, + Helper.WEBSITE_VALUE + ).observe(requireActivity(), app -> { + client_id = app.client_id; + client_secret = app.client_secret; + String redirectUrl = MastodonHelper.authorizeURL(currentInstance, client_id, binding.adminScope.isChecked()); + SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(requireActivity()); + boolean embedded_browser = sharedpreferences.getBoolean(getString(R.string.SET_EMBEDDED_BROWSER), true); + if (embedded_browser) { + Intent i = new Intent(requireActivity(), WebviewConnectActivity.class); + i.putExtra("login_url", redirectUrl); + i.putExtra("requestedAdmin", binding.adminScope.isChecked()); + startActivity(i); + requireActivity().finish(); + } else { + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.setData(Uri.parse(redirectUrl)); + try { + startActivity(intent); + } catch (Exception e) { + Toasty.error(requireActivity(), getString(R.string.toast_error), Toast.LENGTH_LONG).show(); } - }); - } + + } + }); } } } \ No newline at end of file diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonContext.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonContext.java index c33c1fbb1..f7a83cddb 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonContext.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonContext.java @@ -60,6 +60,7 @@ public class FragmentMastodonContext extends Fragment { private StatusesVM statusesVM; private List statuses; private StatusAdapter statusAdapter; + private RecyclerViewThreadLines recyclerViewThreadLines; //Handle actions that can be done in other fragments private final BroadcastReceiver receive_action = new BroadcastReceiver() { @Override @@ -252,7 +253,8 @@ public class FragmentMastodonContext extends Fragment { } } List threadDecorationInfo = getThreadDecorationInfo(context, focusedStatus.id); - binding.recyclerView.addItemDecoration(new RecyclerViewThreadLines(requireContext(), threadDecorationInfo)); + recyclerViewThreadLines = new RecyclerViewThreadLines(requireContext(), threadDecorationInfo); + binding.recyclerView.addItemDecoration(recyclerViewThreadLines); binding.swipeContainer.setRefreshing(false); binding.recyclerView.scrollToPosition(statusPosition); } @@ -260,6 +262,7 @@ public class FragmentMastodonContext extends Fragment { @Override public void onDestroyView() { binding.recyclerView.setAdapter(null); + binding.recyclerView.removeItemDecoration(recyclerViewThreadLines); statusAdapter = null; binding = null; LocalBroadcastManager.getInstance(requireActivity()).unregisterReceiver(receive_action); diff --git a/app/src/main/res/layout/fragment_login_main.xml b/app/src/main/res/layout/fragment_login_main.xml index 082fb85a9..ebbcb6d4d 100644 --- a/app/src/main/res/layout/fragment_login_main.xml +++ b/app/src/main/res/layout/fragment_login_main.xml @@ -49,6 +49,13 @@ android:inputType="textWebEmailAddress" android:singleLine="true" /> + + Top bar menu "Also favourited by: " Also boosted by: + I am a moderator