From 5804a7fb706b58bd2cc96982eb35dcb70838da26 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 18 Jun 2022 12:00:27 +0200 Subject: [PATCH] Fix null pointer when reference to account is destroyed --- .../app/fedilab/android/BaseMainActivity.java | 18 ++- .../android/activities/ComposeActivity.java | 7 +- .../android/activities/ContextActivity.java | 7 +- .../activities/CustomSharingActivity.java | 3 +- .../android/activities/DraftActivity.java | 5 +- .../activities/EditProfileActivity.java | 38 ++--- .../android/activities/HashTagActivity.java | 3 +- .../android/activities/ProfileActivity.java | 2 +- .../android/activities/ScheduledActivity.java | 4 +- .../android/activities/SettingsActivity.java | 3 +- .../app/fedilab/android/helper/Helper.java | 146 ++++++++++------- .../fedilab/android/helper/MediaHelper.java | 3 +- .../android/helper/PinnedTimelineHelper.java | 3 +- .../android/helper/SpannableHelper.java | 7 +- .../android/ui/drawer/ComposeAdapter.java | 8 +- .../android/ui/drawer/StatusAdapter.java | 16 +- .../settings/FragmentThemingSettings.java | 3 +- .../timeline/FragmentMastodonTimeline.java | 148 +++++++++++++----- .../fragment/timeline/FragmentScheduled.java | 4 +- .../android/viewmodel/mastodon/ReorderVM.java | 5 +- .../android/viewmodel/mastodon/TopBarVM.java | 4 +- 21 files changed, 264 insertions(+), 173 deletions(-) diff --git a/app/src/main/java/app/fedilab/android/BaseMainActivity.java b/app/src/main/java/app/fedilab/android/BaseMainActivity.java index 811fa5f0..350545ae 100644 --- a/app/src/main/java/app/fedilab/android/BaseMainActivity.java +++ b/app/src/main/java/app/fedilab/android/BaseMainActivity.java @@ -18,6 +18,7 @@ import static app.fedilab.android.BaseMainActivity.status.DISCONNECTED; import static app.fedilab.android.BaseMainActivity.status.UNKNOWN; import static app.fedilab.android.helper.Helper.PREF_USER_TOKEN; import static app.fedilab.android.helper.Helper.deleteDir; +import static app.fedilab.android.helper.Helper.getCurrentAccount; import android.annotation.SuppressLint; import android.content.BroadcastReceiver; @@ -73,7 +74,6 @@ import com.google.android.material.snackbar.Snackbar; import com.jaredrummler.cyanea.Cyanea; import java.io.File; -import java.lang.ref.WeakReference; import java.util.HashMap; import java.util.List; import java.util.regex.Pattern; @@ -135,7 +135,6 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt public static HashMap> emojis = new HashMap<>(); public static Account.API api; public static boolean admin; - public static WeakReference accountWeakReference; public static status networkAvailable = UNKNOWN; public static Instance instanceInfo; public static List mainFilters; @@ -654,7 +653,6 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt regex_local = sharedpreferences.getString(getString(R.string.SET_FILTER_REGEX_LOCAL) + currentUserID + currentInstance, null); regex_public = sharedpreferences.getString(getString(R.string.SET_FILTER_REGEX_PUBLIC) + currentUserID + currentInstance, null); show_art_nsfw = sharedpreferences.getBoolean(getString(R.string.SET_ART_WITH_NSFW) + currentUserID + currentInstance, false); - accountWeakReference = new WeakReference<>(account); binding.profilePicture.setOnClickListener(v -> binding.drawerLayout.openDrawer(GravityCompat.START)); Helper.loadPP(binding.profilePicture, account); headerMainBinding.accountAcc.setText(String.format("%s@%s", account.mastodon_account.username, account.instance)); @@ -682,8 +680,18 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt .observe(BaseMainActivity.this, filters -> mainFilters = filters); new ViewModelProvider(BaseMainActivity.this).get(AccountsVM.class).getConnectedAccount(currentInstance, currentToken) .observe(BaseMainActivity.this, account1 -> { - - BaseMainActivity.accountWeakReference.get().mastodon_account = account1; + //Initialize static var + getCurrentAccount(BaseMainActivity.this); + //Set the Mastodon account + Helper.setMastodonAccount(account1); + new Thread(() -> { + try { + //Update account in db + new Account(BaseMainActivity.this).insertOrUpdate(getCurrentAccount(BaseMainActivity.this)); + } catch (DBException e) { + e.printStackTrace(); + } + }).start(); }); //Update pinned timelines new ViewModelProvider(BaseMainActivity.this).get(TopBarVM.class).getDBPinned() diff --git a/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java b/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java index 525bbd66..59c32c49 100644 --- a/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java @@ -189,7 +189,7 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana statusDraft.statusDraftList = statuses; } if (account == null) { - account = BaseMainActivity.accountWeakReference.get(); + account = Helper.getCurrentAccount(ComposeActivity.this); } if (account == null) { Toasty.error(ComposeActivity.this, getString(R.string.toast_error), Toasty.LENGTH_SHORT).show(); @@ -267,7 +267,7 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana //We change order for mentions //At first place the account that has been mentioned if it's not our statusDraftList.get(0).mentions = new ArrayList<>(); - if (!statusReply.account.acct.equalsIgnoreCase(MainActivity.accountWeakReference.get().mastodon_account.acct)) { + if (!statusReply.account.acct.equalsIgnoreCase(Helper.getCurrentAccount(ComposeActivity.this).mastodon_account.acct)) { Mention mention = new Mention(); mention.acct = "@" + statusReply.account.acct; mention.url = statusReply.account.url; @@ -278,7 +278,7 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana //There are other mentions to if (statusReply.mentions != null && statusReply.mentions.size() > 0) { for (Mention mentionTmp : statusReply.mentions) { - if (!mentionTmp.acct.equalsIgnoreCase(statusReply.account.acct) && !mentionTmp.acct.equalsIgnoreCase(MainActivity.accountWeakReference.get().mastodon_account.acct)) { + if (!mentionTmp.acct.equalsIgnoreCase(statusReply.account.acct) && !mentionTmp.acct.equalsIgnoreCase(Helper.getCurrentAccount(ComposeActivity.this).mastodon_account.acct)) { statusDraftList.get(0).mentions.add(mentionTmp); } } @@ -292,6 +292,7 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana for (Mention mentionTmp : statusDraftList.get(0).mentions) { if (mentionTmp.acct.equalsIgnoreCase(mentionBooster.acct)) { present = true; + break; } } if (!present) { diff --git a/app/src/main/java/app/fedilab/android/activities/ContextActivity.java b/app/src/main/java/app/fedilab/android/activities/ContextActivity.java index f2d12e1a..809e9875 100644 --- a/app/src/main/java/app/fedilab/android/activities/ContextActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/ContextActivity.java @@ -33,7 +33,6 @@ import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; import androidx.preference.PreferenceManager; -import app.fedilab.android.BaseMainActivity; import app.fedilab.android.R; import app.fedilab.android.client.entities.api.Status; import app.fedilab.android.client.entities.app.QuickLoad; @@ -85,9 +84,7 @@ public class ContextActivity extends BaseActivity { finish(); return; } - if (BaseMainActivity.accountWeakReference.get() != null) { - MastodonHelper.loadPPMastodon(binding.profilePicture, BaseMainActivity.accountWeakReference.get().mastodon_account); - } + MastodonHelper.loadPPMastodon(binding.profilePicture, Helper.getCurrentAccount(ContextActivity.this).mastodon_account); Bundle bundle = new Bundle(); new Thread(() -> { focusedStatus = SpannableHelper.convertStatus(getApplication().getApplicationContext(), focusedStatus); @@ -109,7 +106,7 @@ public class ContextActivity extends BaseActivity { new Thread(() -> { try { new StatusCache(getApplication()).updateIfExists(statusCache); - new QuickLoad(getApplication().getApplicationContext()).updateStatus(MainActivity.accountWeakReference.get(), status); + new QuickLoad(getApplication().getApplicationContext()).updateStatus(Helper.getCurrentAccount(ContextActivity.this), status); Handler mainHandler = new Handler(Looper.getMainLooper()); //Update UI Runnable myRunnable = () -> sendAction(ContextActivity.this, Helper.ARG_STATUS_ACTION, status, null); diff --git a/app/src/main/java/app/fedilab/android/activities/CustomSharingActivity.java b/app/src/main/java/app/fedilab/android/activities/CustomSharingActivity.java index de2fcf3c..58a0f3a5 100644 --- a/app/src/main/java/app/fedilab/android/activities/CustomSharingActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/CustomSharingActivity.java @@ -30,7 +30,6 @@ import androidx.preference.PreferenceManager; import java.util.List; import java.util.Set; -import app.fedilab.android.BaseMainActivity; import app.fedilab.android.R; import app.fedilab.android.client.entities.api.Attachment; import app.fedilab.android.client.entities.api.Emoji; @@ -100,7 +99,7 @@ public class CustomSharingActivity extends BaseActivity implements OnCustomShari bundle_thumbnailurl = status.account.avatar; } if (!bundle_creator.contains("@")) { - bundle_creator = bundle_creator + "@" + BaseMainActivity.accountWeakReference.get().instance; + bundle_creator = bundle_creator + "@" + Helper.getCurrentAccount(CustomSharingActivity.this).instance; } binding.setCustomSharingTitle.setEllipsize(TextUtils.TruncateAt.END); diff --git a/app/src/main/java/app/fedilab/android/activities/DraftActivity.java b/app/src/main/java/app/fedilab/android/activities/DraftActivity.java index fe24fdb1..15121580 100644 --- a/app/src/main/java/app/fedilab/android/activities/DraftActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/DraftActivity.java @@ -34,7 +34,6 @@ import java.io.File; import java.util.ArrayList; import java.util.List; -import app.fedilab.android.BaseMainActivity; import app.fedilab.android.R; import app.fedilab.android.client.entities.api.Attachment; import app.fedilab.android.client.entities.api.Status; @@ -81,7 +80,7 @@ public class DraftActivity extends BaseActivity implements StatusDraftAdapter.Dr getSupportActionBar().setDisplayShowHomeEnabled(true); } timelinesVM = new ViewModelProvider(DraftActivity.this).get(TimelinesVM.class); - timelinesVM.getDrafts(BaseMainActivity.accountWeakReference.get()) + timelinesVM.getDrafts(Helper.getCurrentAccount(DraftActivity.this)) .observe(DraftActivity.this, this::initializeDraftView); } @@ -177,7 +176,7 @@ public class DraftActivity extends BaseActivity implements StatusDraftAdapter.Dr super.onResume(); //We need to check if drafts changed (ie when coming back from the compose activity) if (statusDrafts != null && timelinesVM != null) { - timelinesVM.getDrafts(BaseMainActivity.accountWeakReference.get()) + timelinesVM.getDrafts(Helper.getCurrentAccount(DraftActivity.this)) .observe(DraftActivity.this, this::updateDrafts); } } diff --git a/app/src/main/java/app/fedilab/android/activities/EditProfileActivity.java b/app/src/main/java/app/fedilab/android/activities/EditProfileActivity.java index 31231758..1a851108 100644 --- a/app/src/main/java/app/fedilab/android/activities/EditProfileActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/EditProfileActivity.java @@ -74,7 +74,7 @@ public class EditProfileActivity extends BaseActivity { new ViewModelProvider(EditProfileActivity.this).get(AccountsVM.class).getConnectedAccount(BaseMainActivity.currentInstance, BaseMainActivity.currentToken) .observe(EditProfileActivity.this, account -> { if (account != null) { - BaseMainActivity.accountWeakReference.get().mastodon_account = account; + Helper.getCurrentAccount(EditProfileActivity.this).mastodon_account = account; initializeView(); } else { Helper.sendToastMessage(getApplication(), Helper.RECEIVE_TOAST_TYPE_ERROR, getString(R.string.toast_error)); @@ -86,20 +86,20 @@ public class EditProfileActivity extends BaseActivity { @SuppressWarnings("deprecation") private void initializeView() { //Hydrate values - MastodonHelper.loadProfileMediaMastodon(binding.bannerPp, BaseMainActivity.accountWeakReference.get().mastodon_account, MastodonHelper.MediaAccountType.HEADER); - MastodonHelper.loadPPMastodon(binding.accountPp, BaseMainActivity.accountWeakReference.get().mastodon_account); - binding.displayName.setText(BaseMainActivity.accountWeakReference.get().mastodon_account.display_name); - binding.acct.setText(String.format(Locale.getDefault(), "%s@%s", BaseMainActivity.accountWeakReference.get().mastodon_account.acct, BaseMainActivity.currentInstance)); + MastodonHelper.loadProfileMediaMastodon(binding.bannerPp, Helper.getCurrentAccount(EditProfileActivity.this).mastodon_account, MastodonHelper.MediaAccountType.HEADER); + MastodonHelper.loadPPMastodon(binding.accountPp, Helper.getCurrentAccount(EditProfileActivity.this).mastodon_account); + binding.displayName.setText(Helper.getCurrentAccount(EditProfileActivity.this).mastodon_account.display_name); + binding.acct.setText(String.format(Locale.getDefault(), "%s@%s", Helper.getCurrentAccount(EditProfileActivity.this).mastodon_account.acct, BaseMainActivity.currentInstance)); String bio; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) - bio = Html.fromHtml(BaseMainActivity.accountWeakReference.get().mastodon_account.note, Html.FROM_HTML_MODE_LEGACY).toString(); + bio = Html.fromHtml(Helper.getCurrentAccount(EditProfileActivity.this).mastodon_account.note, Html.FROM_HTML_MODE_LEGACY).toString(); else - bio = Html.fromHtml(BaseMainActivity.accountWeakReference.get().mastodon_account.note).toString(); + bio = Html.fromHtml(Helper.getCurrentAccount(EditProfileActivity.this).mastodon_account.note).toString(); binding.bio.setText(bio); - binding.sensitive.setChecked(BaseMainActivity.accountWeakReference.get().mastodon_account.source.sensitive); - binding.bot.setChecked(BaseMainActivity.accountWeakReference.get().mastodon_account.bot); - binding.discoverable.setChecked(BaseMainActivity.accountWeakReference.get().mastodon_account.discoverable); - switch (BaseMainActivity.accountWeakReference.get().mastodon_account.source.privacy) { + binding.sensitive.setChecked(Helper.getCurrentAccount(EditProfileActivity.this).mastodon_account.source.sensitive); + binding.bot.setChecked(Helper.getCurrentAccount(EditProfileActivity.this).mastodon_account.bot); + binding.discoverable.setChecked(Helper.getCurrentAccount(EditProfileActivity.this).mastodon_account.discoverable); + switch (Helper.getCurrentAccount(EditProfileActivity.this).mastodon_account.source.privacy) { case "public": binding.visibilityPublic.setChecked(true); break; @@ -113,12 +113,12 @@ public class EditProfileActivity extends BaseActivity { binding.visibilityDirect.setChecked(true); break; } - if (BaseMainActivity.accountWeakReference.get().mastodon_account.locked) { + if (Helper.getCurrentAccount(EditProfileActivity.this).mastodon_account.locked) { binding.locked.setChecked(true); } else { binding.unlocked.setChecked(true); } - List fields = BaseMainActivity.accountWeakReference.get().mastodon_account.fields; + List fields = Helper.getCurrentAccount(EditProfileActivity.this).mastodon_account.fields; if (fields != null && fields.size() > 0) { for (Field field : fields) { AccountFieldItemBinding fieldItemBinding = AccountFieldItemBinding.inflate(getLayoutInflater()); @@ -194,11 +194,11 @@ public class EditProfileActivity extends BaseActivity { if (account != null) { sendBroadCast(account); binding.avatarProgress.setVisibility(View.GONE); - BaseMainActivity.accountWeakReference.get().mastodon_account = account; + Helper.getCurrentAccount(EditProfileActivity.this).mastodon_account = account; Helper.recreateMainActivity(EditProfileActivity.this); new Thread(() -> { try { - new app.fedilab.android.client.entities.app.Account(EditProfileActivity.this).insertOrUpdate(BaseMainActivity.accountWeakReference.get()); + new app.fedilab.android.client.entities.app.Account(EditProfileActivity.this).insertOrUpdate(Helper.getCurrentAccount(EditProfileActivity.this)); } catch (DBException e) { e.printStackTrace(); } @@ -219,10 +219,10 @@ public class EditProfileActivity extends BaseActivity { if (account != null) { sendBroadCast(account); binding.headerProgress.setVisibility(View.GONE); - BaseMainActivity.accountWeakReference.get().mastodon_account = account; + Helper.getCurrentAccount(EditProfileActivity.this).mastodon_account = account; new Thread(() -> { try { - new app.fedilab.android.client.entities.app.Account(EditProfileActivity.this).insertOrUpdate(BaseMainActivity.accountWeakReference.get()); + new app.fedilab.android.client.entities.app.Account(EditProfileActivity.this).insertOrUpdate(Helper.getCurrentAccount(EditProfileActivity.this)); } catch (DBException e) { e.printStackTrace(); } @@ -313,10 +313,10 @@ public class EditProfileActivity extends BaseActivity { ) .observe(EditProfileActivity.this, account -> { if (account != null) { - BaseMainActivity.accountWeakReference.get().mastodon_account = account; + Helper.getCurrentAccount(EditProfileActivity.this).mastodon_account = account; new Thread(() -> { try { - new app.fedilab.android.client.entities.app.Account(EditProfileActivity.this).insertOrUpdate(BaseMainActivity.accountWeakReference.get()); + new app.fedilab.android.client.entities.app.Account(EditProfileActivity.this).insertOrUpdate(Helper.getCurrentAccount(EditProfileActivity.this)); sendBroadCast(account); } catch (DBException e) { e.printStackTrace(); diff --git a/app/src/main/java/app/fedilab/android/activities/HashTagActivity.java b/app/src/main/java/app/fedilab/android/activities/HashTagActivity.java index c75af410..a39dd857 100644 --- a/app/src/main/java/app/fedilab/android/activities/HashTagActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/HashTagActivity.java @@ -31,7 +31,6 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager; import java.util.ArrayList; import java.util.List; -import app.fedilab.android.BaseMainActivity; import app.fedilab.android.R; import app.fedilab.android.client.entities.api.Status; import app.fedilab.android.client.entities.app.Pinned; @@ -108,7 +107,7 @@ public class HashTagActivity extends BaseActivity { } else if (item.getItemId() == R.id.action_add_timeline) { new Thread(() -> { try { - Pinned pinned = new Pinned(HashTagActivity.this).getPinned(BaseMainActivity.accountWeakReference.get()); + Pinned pinned = new Pinned(HashTagActivity.this).getPinned(Helper.getCurrentAccount(HashTagActivity.this)); boolean canBeAdded = true; boolean update = true; if (pinned == null) { diff --git a/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java b/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java index a0de0994..0f8ab11a 100644 --- a/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java @@ -541,7 +541,7 @@ public class ProfileActivity extends BaseActivity { private void updateAccount() { //The value for account is from same server so id can be used - if (BaseMainActivity.accountWeakReference.get() != null && account.id.equals(BaseMainActivity.accountWeakReference.get().user_id)) { + if (account.id.equals(Helper.getCurrentAccount(ProfileActivity.this).user_id)) { binding.accountFollow.setVisibility(View.GONE); binding.headerEditProfile.setVisibility(View.VISIBLE); binding.headerEditProfile.bringToFront(); diff --git a/app/src/main/java/app/fedilab/android/activities/ScheduledActivity.java b/app/src/main/java/app/fedilab/android/activities/ScheduledActivity.java index 3e1d917a..685bcd1d 100644 --- a/app/src/main/java/app/fedilab/android/activities/ScheduledActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/ScheduledActivity.java @@ -24,9 +24,9 @@ import androidx.core.content.ContextCompat; import com.google.android.material.tabs.TabLayout; -import app.fedilab.android.BaseMainActivity; import app.fedilab.android.R; import app.fedilab.android.databinding.ActivityScheduledBinding; +import app.fedilab.android.helper.Helper; import app.fedilab.android.helper.MastodonHelper; import app.fedilab.android.helper.ThemeHelper; import app.fedilab.android.ui.pageadapter.FedilabScheduledPageAdapter; @@ -53,7 +53,7 @@ public class ScheduledActivity extends BaseActivity { getSupportActionBar().setDisplayShowHomeEnabled(true); } - MastodonHelper.loadPPMastodon(binding.profilePicture, BaseMainActivity.accountWeakReference.get().mastodon_account); + MastodonHelper.loadPPMastodon(binding.profilePicture, Helper.getCurrentAccount(ScheduledActivity.this).mastodon_account); binding.title.setText(R.string.scheduled); binding.scheduleTablayout.addTab(binding.scheduleTablayout.newTab().setText(getString(R.string.toots_server))); binding.scheduleTablayout.addTab(binding.scheduleTablayout.newTab().setText(getString(R.string.toots_client))); 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 af9f268a..291d7bd0 100644 --- a/app/src/main/java/app/fedilab/android/activities/SettingsActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/SettingsActivity.java @@ -31,6 +31,7 @@ import java.util.Locale; import app.fedilab.android.R; import app.fedilab.android.databinding.ActivitySettingsBinding; +import app.fedilab.android.helper.Helper; import app.fedilab.android.helper.ThemeHelper; import app.fedilab.android.ui.fragment.settings.FragmentComposeSettings; import app.fedilab.android.ui.fragment.settings.FragmentInterfaceSettings; @@ -68,7 +69,7 @@ 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().admin) { + if (Helper.getCurrentAccount(SettingsActivity.this).admin) { binding.setAdministration.setVisibility(View.VISIBLE); } else { binding.setAdministration.setVisibility(View.GONE); diff --git a/app/src/main/java/app/fedilab/android/helper/Helper.java b/app/src/main/java/app/fedilab/android/helper/Helper.java index 27e25d2e..68971a9c 100644 --- a/app/src/main/java/app/fedilab/android/helper/Helper.java +++ b/app/src/main/java/app/fedilab/android/helper/Helper.java @@ -119,6 +119,7 @@ import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Random; +import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -1546,66 +1547,7 @@ public class Helper { void onAttachmentCopied(Attachment attachment); } - public static class CacheTask { - private final WeakReference contextReference; - private float cacheSize; - - public CacheTask(Context context) { - contextReference = new WeakReference<>(context); - doInBackground(); - } - - protected void doInBackground() { - new Thread(() -> { - long sizeCache = cacheSize(contextReference.get().getCacheDir().getParentFile()); - cacheSize = 0; - if (sizeCache > 0) { - cacheSize = (float) sizeCache / 1000000.0f; - } - Handler mainHandler = new Handler(Looper.getMainLooper()); - Runnable myRunnable = () -> { - AlertDialog.Builder builder = new AlertDialog.Builder(contextReference.get(), Helper.dialogStyle()); - LayoutInflater inflater = ((BaseMainActivity) contextReference.get()).getLayoutInflater(); - View dialogView = inflater.inflate(R.layout.popup_cache, new LinearLayout(contextReference.get()), false); - TextView message = dialogView.findViewById(R.id.message); - message.setText(contextReference.get().getString(R.string.cache_message, String.format("%s %s", String.format(Locale.getDefault(), "%.2f", cacheSize), contextReference.get().getString(R.string.cache_units)))); - builder.setView(dialogView); - builder.setTitle(R.string.cache_title); - - final SwitchCompat clean_all = dialogView.findViewById(R.id.clean_all); - final float finalCacheSize = cacheSize; - builder - .setPositiveButton(R.string.clear, (dialog, which) -> new Thread(() -> { - try { - String path = Objects.requireNonNull(contextReference.get().getCacheDir().getParentFile()).getPath(); - File dir = new File(path); - if (dir.isDirectory()) { - deleteDir(dir); - } - if (clean_all.isChecked()) { - new QuickLoad(contextReference.get()).deleteForAllAccount(); - new StatusCache(contextReference.get()).deleteForAllAccount(); - } else { - new QuickLoad(contextReference.get()).deleteForAccount(MainActivity.accountWeakReference.get()); - new StatusCache(contextReference.get()).deleteForAccount(MainActivity.accountWeakReference.get()); - } - Handler mainHandler2 = new Handler(Looper.getMainLooper()); - Runnable myRunnable2 = () -> { - Toasty.success(contextReference.get(), contextReference.get().getString(R.string.toast_cache_clear, String.format("%s %s", String.format(Locale.getDefault(), "%.2f", finalCacheSize), contextReference.get().getString(R.string.cache_units))), Toast.LENGTH_LONG).show(); - dialog.dismiss(); - }; - mainHandler2.post(myRunnable2); - } catch (Exception ignored) { - } - }).start()) - .setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss()) - .setIcon(android.R.drawable.ic_dialog_alert) - .show(); - }; - mainHandler.post(myRunnable); - }).start(); - } - } + private static WeakReference currentAccount; public static void transfertIfExist(Context context) { @@ -1667,4 +1609,88 @@ public class Helper { }); } + public static String generateString() { + String uuid = UUID.randomUUID().toString(); + return "@fedilab_fetch_more_" + uuid; + } + + public static void setMastodonAccount(app.fedilab.android.client.entities.api.Account mastodon_account) { + if (currentAccount != null) { + currentAccount.get().mastodon_account = mastodon_account; + } + } + + public static Account getCurrentAccount(Context context) { + if (currentAccount == null || currentAccount.get() == null || currentAccount.get().mastodon_account == null) { + try { + Account account = new Account(context).getUniqAccount(MainActivity.currentUserID, MainActivity.currentInstance); + currentAccount = new WeakReference<>(account); + currentAccount.get().mastodon_account = account.mastodon_account; + } catch (DBException e) { + e.printStackTrace(); + } + } + return currentAccount.get(); + } + + public static class CacheTask { + private final WeakReference contextReference; + private float cacheSize; + + public CacheTask(Context context) { + contextReference = new WeakReference<>(context); + doInBackground(); + } + + protected void doInBackground() { + new Thread(() -> { + long sizeCache = cacheSize(contextReference.get().getCacheDir().getParentFile()); + cacheSize = 0; + if (sizeCache > 0) { + cacheSize = (float) sizeCache / 1000000.0f; + } + Handler mainHandler = new Handler(Looper.getMainLooper()); + Runnable myRunnable = () -> { + AlertDialog.Builder builder = new AlertDialog.Builder(contextReference.get(), Helper.dialogStyle()); + LayoutInflater inflater = ((BaseMainActivity) contextReference.get()).getLayoutInflater(); + View dialogView = inflater.inflate(R.layout.popup_cache, new LinearLayout(contextReference.get()), false); + TextView message = dialogView.findViewById(R.id.message); + message.setText(contextReference.get().getString(R.string.cache_message, String.format("%s %s", String.format(Locale.getDefault(), "%.2f", cacheSize), contextReference.get().getString(R.string.cache_units)))); + builder.setView(dialogView); + builder.setTitle(R.string.cache_title); + + final SwitchCompat clean_all = dialogView.findViewById(R.id.clean_all); + final float finalCacheSize = cacheSize; + builder + .setPositiveButton(R.string.clear, (dialog, which) -> new Thread(() -> { + try { + String path = Objects.requireNonNull(contextReference.get().getCacheDir().getParentFile()).getPath(); + File dir = new File(path); + if (dir.isDirectory()) { + deleteDir(dir); + } + if (clean_all.isChecked()) { + new QuickLoad(contextReference.get()).deleteForAllAccount(); + new StatusCache(contextReference.get()).deleteForAllAccount(); + } else { + new QuickLoad(contextReference.get()).deleteForAccount(getCurrentAccount(contextReference.get())); + new StatusCache(contextReference.get()).deleteForAccount(getCurrentAccount(contextReference.get())); + } + Handler mainHandler2 = new Handler(Looper.getMainLooper()); + Runnable myRunnable2 = () -> { + Toasty.success(contextReference.get(), contextReference.get().getString(R.string.toast_cache_clear, String.format("%s %s", String.format(Locale.getDefault(), "%.2f", finalCacheSize), contextReference.get().getString(R.string.cache_units))), Toast.LENGTH_LONG).show(); + dialog.dismiss(); + }; + mainHandler2.post(myRunnable2); + } catch (Exception ignored) { + } + }).start()) + .setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss()) + .setIcon(android.R.drawable.ic_dialog_alert) + .show(); + }; + mainHandler.post(myRunnable); + }).start(); + } + } } diff --git a/app/src/main/java/app/fedilab/android/helper/MediaHelper.java b/app/src/main/java/app/fedilab/android/helper/MediaHelper.java index 8cb298d5..1f93a004 100644 --- a/app/src/main/java/app/fedilab/android/helper/MediaHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/MediaHelper.java @@ -61,7 +61,6 @@ import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.atomic.AtomicInteger; -import app.fedilab.android.BaseMainActivity; import app.fedilab.android.BuildConfig; import app.fedilab.android.R; import app.fedilab.android.activities.ComposeActivity; @@ -163,7 +162,7 @@ public class MediaHelper { Uri uri = Uri.fromFile(backupFile); intent.setDataAndType(uri, mime); if (!share) { - notify_user(context, Helper.NOTIFICATION_MEDIA, BaseMainActivity.accountWeakReference.get(), intent, BitmapFactory.decodeResource(context.getResources(), + notify_user(context, Helper.NOTIFICATION_MEDIA, Helper.getCurrentAccount(context), intent, BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher), Helper.NotifType.STORE, context.getString(R.string.save_over), context.getString(R.string.download_from, fileName)); Toasty.success(context, context.getString(R.string.save_over), Toasty.LENGTH_LONG).show(); } else { diff --git a/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java b/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java index 4f5f0a86..c7abba16 100644 --- a/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java @@ -43,7 +43,6 @@ import java.util.List; import app.fedilab.android.BaseMainActivity; import app.fedilab.android.R; -import app.fedilab.android.activities.MainActivity; import app.fedilab.android.client.entities.api.MastodonList; import app.fedilab.android.client.entities.app.BottomMenu; import app.fedilab.android.client.entities.app.Pinned; @@ -262,7 +261,7 @@ public class PinnedTimelineHelper { int toRemove = 0; try { //If some menu items have been hidden we should not create tab for them - bottomMenuDb = new BottomMenu(context).getAllBottomMenu(MainActivity.accountWeakReference.get()); + bottomMenuDb = new BottomMenu(context).getAllBottomMenu(Helper.getCurrentAccount(context)); if (bottomMenuDb != null) { List menuItemList = bottomMenuDb.bottom_menu; if (menuItemList != null) { diff --git a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java index 1dd94a4e..10964b16 100644 --- a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java @@ -73,7 +73,6 @@ import javax.net.ssl.HttpsURLConnection; import app.fedilab.android.R; import app.fedilab.android.activities.ContextActivity; import app.fedilab.android.activities.HashTagActivity; -import app.fedilab.android.activities.MainActivity; import app.fedilab.android.activities.ProfileActivity; import app.fedilab.android.client.entities.api.Account; import app.fedilab.android.client.entities.api.Announcement; @@ -380,7 +379,7 @@ public class SpannableHelper { Matcher matcherLink = link.matcher(url); if (matcherLink.find() && !url.contains("medium.com")) { if (matcherLink.group(3) != null && Objects.requireNonNull(matcherLink.group(3)).length() > 0) { //It's a toot - CrossActionHelper.fetchRemoteStatus(context, MainActivity.accountWeakReference.get(), url, new CrossActionHelper.Callback() { + CrossActionHelper.fetchRemoteStatus(context, Helper.getCurrentAccount(context), url, new CrossActionHelper.Callback() { @Override public void federatedStatus(Status status) { Intent intent = new Intent(context, ContextActivity.class); @@ -395,7 +394,7 @@ public class SpannableHelper { } }); } else {//It's an account - CrossActionHelper.fetchRemoteAccount(context, MainActivity.accountWeakReference.get(), status.account, new CrossActionHelper.Callback() { + CrossActionHelper.fetchRemoteAccount(context, Helper.getCurrentAccount(context), status.account, new CrossActionHelper.Callback() { @Override public void federatedStatus(Status status) { @@ -844,7 +843,7 @@ public class SpannableHelper { Matcher matcherLink = link.matcher(url); if (matcherLink.find() && !url.contains("medium.com")) { if (matcherLink.group(3) != null && Objects.requireNonNull(matcherLink.group(3)).length() > 0) { //It's a toot - CrossActionHelper.fetchRemoteStatus(context, MainActivity.accountWeakReference.get(), url, new CrossActionHelper.Callback() { + CrossActionHelper.fetchRemoteStatus(context, Helper.getCurrentAccount(context), url, new CrossActionHelper.Callback() { @Override public void federatedStatus(Status status) { Intent intent = new Intent(context, ContextActivity.class); diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java index 272ce173..3e18dab8 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java @@ -421,8 +421,8 @@ public class ComposeAdapter extends RecyclerView.Adapter attachmentList = statusList.get(position).media_attachments; if (attachmentList != null && attachmentList.size() > 0) { holder.binding.sensitiveMedia.setVisibility(View.VISIBLE); - holder.binding.sensitiveMedia.setChecked(BaseMainActivity.accountWeakReference.get().mastodon_account.source.sensitive); - statusList.get(position).sensitive = BaseMainActivity.accountWeakReference.get().mastodon_account.source.sensitive; + holder.binding.sensitiveMedia.setChecked(Helper.getCurrentAccount(context).mastodon_account.source.sensitive); + statusList.get(position).sensitive = Helper.getCurrentAccount(context).mastodon_account.source.sensitive; holder.binding.sensitiveMedia.setOnCheckedChangeListener((buttonView, isChecked) -> statusList.get(position).sensitive = isChecked); int mediaPosition = 0; for (Attachment attachment : attachmentList) { @@ -1070,8 +1070,8 @@ public class ComposeAdapter extends RecyclerView.Adapter 0) { statusDraft.visibility = statusList.get(position - 1).visibility; - } else if (BaseMainActivity.accountWeakReference.get().mastodon_account != null && BaseMainActivity.accountWeakReference.get().mastodon_account.source != null) { - statusDraft.visibility = BaseMainActivity.accountWeakReference.get().mastodon_account.source.privacy; + } else if (Helper.getCurrentAccount(context).mastodon_account != null && Helper.getCurrentAccount(context).mastodon_account.source != null) { + statusDraft.visibility = Helper.getCurrentAccount(context).mastodon_account.source.privacy; } else { statusDraft.visibility = "public"; } diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java index 091f2a94..ca77e0b6 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java @@ -1806,24 +1806,20 @@ public class StatusAdapter extends RecyclerView.Adapter }); } else if (viewHolder.getItemViewType() == STATUS_FETCH_MORE) { StatusViewHolder holder = (StatusViewHolder) viewHolder; - if (status.isFetchMoreHidden) { - holder.bindingFetchMore.fetchMore.setVisibility(View.GONE); - } else { - holder.bindingFetchMore.fetchMore.setVisibility(View.VISIBLE); - } + holder.bindingFetchMore.fetchMore.setEnabled(!status.isFetchMoreHidden); holder.bindingFetchMore.fetchMore.setOnClickListener(v -> { - //We hide the button - status.isFetchMoreHidden = true; - notifyItemChanged(position); if (position + 1 < statusList.size()) { - fetchMoreCallBack.onClick(statusList.get(position + 1).id); + //We hide the button + status.isFetchMoreHidden = true; + notifyItemChanged(position); + fetchMoreCallBack.onClick(statusList.get(position + 1).id, status.id); } }); } } public interface FetchMoreCallBack { - void onClick(String min_id); + void onClick(String min_id, String fetchmoreId); } @Override diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/settings/FragmentThemingSettings.java b/app/src/main/java/app/fedilab/android/ui/fragment/settings/FragmentThemingSettings.java index ad07bd7a..234161c9 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/settings/FragmentThemingSettings.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/settings/FragmentThemingSettings.java @@ -59,7 +59,6 @@ import java.util.Date; import java.util.LinkedHashMap; import java.util.List; -import app.fedilab.android.BaseMainActivity; import app.fedilab.android.R; import app.fedilab.android.activities.ComposeActivity; import app.fedilab.android.databinding.PopupStatusThemeBinding; @@ -571,7 +570,7 @@ public class FragmentThemingSettings extends PreferenceFragmentCompat implements Uri uri = Uri.parse("file://" + fullPath); intentOpen.setDataAndType(uri, "text/csv"); String title = getString(R.string.data_export_theme); - Helper.notify_user(getActivity(), Helper.NOTIFICATION_THEMING, BaseMainActivity.accountWeakReference.get(), intentOpen, BitmapFactory.decodeResource(requireActivity().getResources(), + Helper.notify_user(getActivity(), Helper.NOTIFICATION_THEMING, Helper.getCurrentAccount(requireActivity()), intentOpen, BitmapFactory.decodeResource(requireActivity().getResources(), R.mipmap.ic_launcher), Helper.NotifType.BACKUP, title, message); } catch (Exception e) { e.printStackTrace(); diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java index 4421f04d..ec95db9b 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java @@ -58,7 +58,6 @@ import app.fedilab.android.helper.SpannableHelper; import app.fedilab.android.helper.ThemeHelper; import app.fedilab.android.ui.drawer.StatusAdapter; import app.fedilab.android.viewmodel.mastodon.AccountsVM; -import app.fedilab.android.viewmodel.mastodon.AnnouncementsVM; import app.fedilab.android.viewmodel.mastodon.SearchVM; import app.fedilab.android.viewmodel.mastodon.TimelinesVM; @@ -71,7 +70,6 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. private FragmentPaginationBinding binding; private TimelinesVM timelinesVM; private AccountsVM accountsVM; - private AnnouncementsVM announcementsVM; private boolean flagLoading; private List statuses; private String search, searchCache; @@ -239,7 +237,6 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. timelinesVM = new ViewModelProvider(FragmentMastodonTimeline.this).get(viewModelKey, TimelinesVM.class); accountsVM = new ViewModelProvider(FragmentMastodonTimeline.this).get(viewModelKey, AccountsVM.class); - announcementsVM = new ViewModelProvider(FragmentMastodonTimeline.this).get(viewModelKey, AnnouncementsVM.class); binding.loader.setVisibility(View.VISIBLE); binding.recyclerView.setVisibility(View.GONE); @@ -375,6 +372,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. if (binding == null) { return; } + int currentPosition = mLayoutManager.findFirstVisibleItemPosition(); binding.swipeContainer.setRefreshing(false); binding.loadingNextElements.setVisibility(View.GONE); flagLoading = false; @@ -396,35 +394,46 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. fetched_statuses.statuses = mediaStatuses; } //Update the timeline with new statuses - updateStatusListWith(fetched_statuses.statuses, fetchingMissing); - if (fetched_statuses.pagination.max_id == null) { - flagLoading = true; - } else if (max_id == null || fetched_statuses.pagination.max_id.compareTo(max_id) < 0) { - max_id = fetched_statuses.pagination.max_id; + int inserted = updateStatusListWith(fetched_statuses.statuses, fetchingMissing); + if (fetchingMissing) { + binding.recyclerView.scrollToPosition(currentPosition + inserted); } - if (min_id == null || (fetched_statuses.pagination.min_id != null && fetched_statuses.pagination.min_id.compareTo(min_id) > 0)) { - min_id = fetched_statuses.pagination.min_id; + if (!fetchingMissing) { + if (fetched_statuses.pagination.max_id == null) { + flagLoading = true; + } else if (max_id == null || fetched_statuses.pagination.max_id.compareTo(max_id) < 0) { + max_id = fetched_statuses.pagination.max_id; + } + if (min_id == null || (fetched_statuses.pagination.min_id != null && fetched_statuses.pagination.min_id.compareTo(min_id) > 0)) { + min_id = fetched_statuses.pagination.min_id; + } } } else if (direction == DIRECTION.BOTTOM) { flagLoading = true; } } - private void updateStatusListWith(List statusListReceived, boolean fetchingMissing) { + private int updateStatusListWith(List statusListReceived, boolean fetchingMissing) { + int numberInserted = 0; if (statusListReceived != null && statusListReceived.size() > 0) { int insertedPosition = STATUS_PRESENT; for (Status statusReceived : statusListReceived) { insertedPosition = insertStatus(statusReceived); + if (insertedPosition != STATUS_PRESENT && insertedPosition != STATUS_AT_THE_BOTTOM) { + numberInserted++; + } } //If there were no overlap for top status if (fetchingMissing && insertedPosition != STATUS_PRESENT && insertedPosition != STATUS_AT_THE_BOTTOM && this.statuses.size() > insertedPosition) { Status statusFetchMore = new Status(); statusFetchMore.isFetchMore = true; + statusFetchMore.id = Helper.generateString(); int insertAt = insertedPosition + 1; this.statuses.add(insertAt, statusFetchMore); statusAdapter.notifyItemInserted(insertAt); } } + return numberInserted; } private int insertStatus(Status statusReceived) { @@ -432,8 +441,12 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. return STATUS_PRESENT; } int position = 0; + //We loop through messages already in the timeline for (Status statusAlreadyPresent : this.statuses) { + //We compare the date of each status and we only add status having a date greater than the another, it is inserted at this position + //Pinned messages are ignored because their date can be older if (statusAlreadyPresent.created_at != null && statusReceived.created_at != null && statusReceived.created_at.after(statusAlreadyPresent.created_at) && !statusAlreadyPresent.pinned) { + //We add the status to a list of id - thus we know it is already in the timeline idOfAddedStatuses.add(statusReceived.id); this.statuses.add(position, statusReceived); statusAdapter.notifyItemInserted(position); @@ -443,6 +456,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. } //Statuses added at the bottom, we flag them by position = -2 for not dealing with them and fetch more if (position == this.statuses.size()) { + //We add the status to a list of id - thus we know it is already in the timeline idOfAddedStatuses.add(statusReceived.id); this.statuses.add(position, statusReceived); statusAdapter.notifyItemInserted(position); @@ -552,13 +566,19 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. .observe(getViewLifecycleOwner(), this::initializeStatusesCommonView); } else if (direction == DIRECTION.BOTTOM) { timelinesVM.getPublic(BaseMainActivity.currentToken, BaseMainActivity.currentInstance, true, false, false, max_id, null, null, MastodonHelper.statusesPerCall(requireActivity())) - .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, fetchingMissing)); + .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false)); } else if (direction == DIRECTION.TOP) { timelinesVM.getPublic(BaseMainActivity.currentToken, BaseMainActivity.currentInstance, true, false, false, null, null, fetchingMissing ? min_id_fetch_more : min_id, MastodonHelper.statusesPerCall(requireActivity())) .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.TOP, fetchingMissing)); } else if (direction == DIRECTION.REFRESH) { timelinesVM.getPublic(BaseMainActivity.currentToken, BaseMainActivity.currentInstance, true, false, false, null, null, null, MastodonHelper.statusesPerCall(requireActivity())) - .observe(getViewLifecycleOwner(), statusesTop -> dealWithPagination(statusesTop, DIRECTION.REFRESH, fetchingMissing)); + .observe(getViewLifecycleOwner(), statusesRefresh -> { + if (statusAdapter != null) { + dealWithPagination(statusesRefresh, DIRECTION.REFRESH, true); + } else { + initializeStatusesCommonView(statusesRefresh); + } + }); } } else if (timelineType == Timeline.TimeLineEnum.PUBLIC) { //PUBLIC TIMELINE if (direction == null) { @@ -566,13 +586,19 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. .observe(getViewLifecycleOwner(), this::initializeStatusesCommonView); } else if (direction == DIRECTION.BOTTOM) { timelinesVM.getPublic(BaseMainActivity.currentToken, BaseMainActivity.currentInstance, false, true, false, max_id, null, null, MastodonHelper.statusesPerCall(requireActivity())) - .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, fetchingMissing)); + .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false)); } else if (direction == DIRECTION.TOP) { timelinesVM.getPublic(BaseMainActivity.currentToken, BaseMainActivity.currentInstance, false, true, false, null, null, fetchingMissing ? min_id_fetch_more : min_id, MastodonHelper.statusesPerCall(requireActivity())) .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.TOP, fetchingMissing)); } else if (direction == DIRECTION.REFRESH) { timelinesVM.getPublic(BaseMainActivity.currentToken, BaseMainActivity.currentInstance, false, true, false, null, null, null, MastodonHelper.statusesPerCall(requireActivity())) - .observe(getViewLifecycleOwner(), statusesTop -> dealWithPagination(statusesTop, DIRECTION.REFRESH, fetchingMissing)); + .observe(getViewLifecycleOwner(), statusesRefresh -> { + if (statusAdapter != null) { + dealWithPagination(statusesRefresh, DIRECTION.REFRESH, true); + } else { + initializeStatusesCommonView(statusesRefresh); + } + }); } } else if (timelineType == Timeline.TimeLineEnum.REMOTE) { //REMOTE TIMELINE if (direction == null) { @@ -580,13 +606,19 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. .observe(getViewLifecycleOwner(), this::initializeStatusesCommonView); } else if (direction == DIRECTION.BOTTOM) { timelinesVM.getPublic(null, remoteInstance, true, false, false, max_id, null, null, MastodonHelper.statusesPerCall(requireActivity())) - .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, fetchingMissing)); + .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false)); } else if (direction == DIRECTION.TOP) { timelinesVM.getPublic(null, remoteInstance, true, false, false, null, null, fetchingMissing ? min_id_fetch_more : min_id, MastodonHelper.statusesPerCall(requireActivity())) .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.TOP, fetchingMissing)); } else if (direction == DIRECTION.REFRESH) { timelinesVM.getPublic(null, remoteInstance, true, false, false, null, null, null, MastodonHelper.statusesPerCall(requireActivity())) - .observe(getViewLifecycleOwner(), statusesTop -> dealWithPagination(statusesTop, DIRECTION.REFRESH, fetchingMissing)); + .observe(getViewLifecycleOwner(), statusesRefresh -> { + if (statusAdapter != null) { + dealWithPagination(statusesRefresh, DIRECTION.REFRESH, true); + } else { + initializeStatusesCommonView(statusesRefresh); + } + }); } } else if (timelineType == Timeline.TimeLineEnum.LIST) { //LIST TIMELINE if (direction == null) { @@ -594,13 +626,19 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. .observe(getViewLifecycleOwner(), this::initializeStatusesCommonView); } else if (direction == DIRECTION.BOTTOM) { timelinesVM.getList(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, list_id, max_id, null, null, MastodonHelper.statusesPerCall(requireActivity())) - .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, fetchingMissing)); + .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false)); } else if (direction == DIRECTION.TOP) { timelinesVM.getList(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, list_id, null, null, fetchingMissing ? min_id_fetch_more : min_id, MastodonHelper.statusesPerCall(requireActivity())) .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.TOP, fetchingMissing)); } else if (direction == DIRECTION.REFRESH) { timelinesVM.getList(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, list_id, null, null, null, MastodonHelper.statusesPerCall(requireActivity())) - .observe(getViewLifecycleOwner(), statusesTop -> dealWithPagination(statusesTop, DIRECTION.REFRESH, fetchingMissing)); + .observe(getViewLifecycleOwner(), statusesRefresh -> { + if (statusAdapter != null) { + dealWithPagination(statusesRefresh, DIRECTION.REFRESH, true); + } else { + initializeStatusesCommonView(statusesRefresh); + } + }); } } else if (timelineType == Timeline.TimeLineEnum.TAG || timelineType == Timeline.TimeLineEnum.ART) { //TAG TIMELINE if (tagTimeline == null) { @@ -612,13 +650,19 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. .observe(getViewLifecycleOwner(), this::initializeStatusesCommonView); } else if (direction == DIRECTION.BOTTOM) { timelinesVM.getHashTag(BaseMainActivity.currentToken, BaseMainActivity.currentInstance, tagTimeline.name, false, tagTimeline.isART, tagTimeline.all, tagTimeline.any, tagTimeline.none, max_id, null, null, MastodonHelper.statusesPerCall(requireActivity())) - .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, fetchingMissing)); + .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false)); } else if (direction == DIRECTION.TOP) { timelinesVM.getHashTag(BaseMainActivity.currentToken, BaseMainActivity.currentInstance, tagTimeline.name, false, tagTimeline.isART, tagTimeline.all, tagTimeline.any, tagTimeline.none, null, null, fetchingMissing ? min_id_fetch_more : min_id, MastodonHelper.statusesPerCall(requireActivity())) .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.TOP, fetchingMissing)); } else if (direction == DIRECTION.REFRESH) { timelinesVM.getHashTag(BaseMainActivity.currentToken, BaseMainActivity.currentInstance, tagTimeline.name, false, tagTimeline.isART, tagTimeline.all, tagTimeline.any, tagTimeline.none, null, null, null, MastodonHelper.statusesPerCall(requireActivity())) - .observe(getViewLifecycleOwner(), statusesTop -> dealWithPagination(statusesTop, DIRECTION.REFRESH, fetchingMissing)); + .observe(getViewLifecycleOwner(), statusesRefresh -> { + if (statusAdapter != null) { + dealWithPagination(statusesRefresh, DIRECTION.REFRESH, true); + } else { + initializeStatusesCommonView(statusesRefresh); + } + }); } } else if (timelineType == Timeline.TimeLineEnum.ACCOUNT_TIMELINE) { //PROFILE TIMELINES if (direction == null) { @@ -746,35 +790,48 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. timelinesVM.getHomeCache(BaseMainActivity.currentInstance, BaseMainActivity.currentUserID, max_id, null, null) .observe(getViewLifecycleOwner(), statusesBottomCache -> { if (statusesBottomCache != null && statusesBottomCache.statuses != null && statusesBottomCache.statuses.size() > 0) { - dealWithPagination(statusesBottomCache, DIRECTION.BOTTOM, fetchingMissing); + dealWithPagination(statusesBottomCache, DIRECTION.BOTTOM, false); } else { // If not, we fetch remotely - timelinesVM.getHome(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, fetchingMissing, max_id, null, null, MastodonHelper.statusesPerCall(requireActivity()), false) - .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, fetchingMissing)); + timelinesVM.getHome(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, false, max_id, null, null, MastodonHelper.statusesPerCall(requireActivity()), false) + .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false)); } }); } else { timelinesVM.getHomeCache(BaseMainActivity.currentInstance, BaseMainActivity.currentUserID, max_id, null, null) - .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, fetchingMissing)); + .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false)); } } else if (direction == DIRECTION.TOP) { - if (networkAvailable == BaseMainActivity.status.CONNECTED) { - timelinesVM.getHomeCache(BaseMainActivity.currentInstance, BaseMainActivity.currentUserID, null, fetchingMissing ? min_id_fetch_more : min_id, null) - .observe(getViewLifecycleOwner(), statusesTopCache -> { - if (statusesTopCache != null && statusesTopCache.statuses != null && statusesTopCache.statuses.size() > 0) { - dealWithPagination(statusesTopCache, DIRECTION.TOP, fetchingMissing); - } else { - timelinesVM.getHome(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, fetchingMissing, null, null, fetchingMissing ? min_id_fetch_more : min_id, MastodonHelper.statusesPerCall(requireActivity()), false) - .observe(getViewLifecycleOwner(), statusesTop -> dealWithPagination(statusesTop, DIRECTION.TOP, fetchingMissing)); - } - }); + if (!fetchingMissing) { + if (networkAvailable == BaseMainActivity.status.CONNECTED) { + timelinesVM.getHomeCache(BaseMainActivity.currentInstance, BaseMainActivity.currentUserID, null, min_id, null) + .observe(getViewLifecycleOwner(), statusesTopCache -> { + if (statusesTopCache != null && statusesTopCache.statuses != null && statusesTopCache.statuses.size() > 0) { + dealWithPagination(statusesTopCache, DIRECTION.TOP, false); + } else { + timelinesVM.getHome(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, false, null, null, min_id, MastodonHelper.statusesPerCall(requireActivity()), false) + .observe(getViewLifecycleOwner(), statusesTop -> dealWithPagination(statusesTop, DIRECTION.TOP, false)); + } + }); + } else { + timelinesVM.getHomeCache(BaseMainActivity.currentInstance, BaseMainActivity.currentUserID, null, min_id, null) + .observe(getViewLifecycleOwner(), statusesTop -> dealWithPagination(statusesTop, DIRECTION.TOP, false)); + } } else { - timelinesVM.getHomeCache(BaseMainActivity.currentInstance, BaseMainActivity.currentUserID, null, fetchingMissing ? min_id_fetch_more : min_id, null) - .observe(getViewLifecycleOwner(), statusesTop -> dealWithPagination(statusesTop, DIRECTION.TOP, fetchingMissing)); + timelinesVM.getHome(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, true, null, null, min_id_fetch_more, MastodonHelper.statusesPerCall(requireActivity()), false) + .observe(getViewLifecycleOwner(), statusesTop -> dealWithPagination(statusesTop, DIRECTION.TOP, true)); } + } else if (direction == DIRECTION.REFRESH) { timelinesVM.getHome(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, fetchingMissing, null, null, null, MastodonHelper.statusesPerCall(requireActivity()), false) - .observe(getViewLifecycleOwner(), statusesTop -> dealWithPagination(statusesTop, DIRECTION.REFRESH, fetchingMissing)); + .observe(getViewLifecycleOwner(), statusRefresh -> { + if (statusAdapter != null) { + dealWithPagination(statusRefresh, DIRECTION.REFRESH, fetchingMissing); + } else { + initializeStatusesCommonView(statusRefresh); + } + } + ); } } @@ -789,9 +846,22 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. } @Override - public void onClick(String min_id) { + public void onClick(String min_id, String id) { //Fetch more has been pressed min_id_fetch_more = min_id; + Status status = null; + int position = 0; + for (Status currentStatus : this.statuses) { + if (currentStatus.id.compareTo(id) == 0) { + status = currentStatus; + break; + } + position++; + } + if (status != null) { + this.statuses.remove(position); + statusAdapter.notifyItemRemoved(position); + } route(DIRECTION.TOP, true); } diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentScheduled.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentScheduled.java index 7475f03c..5d1b1798 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentScheduled.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentScheduled.java @@ -80,7 +80,7 @@ public class FragmentScheduled extends Fragment implements StatusScheduledAdapte } else if (type == Timeline.TimeLineEnum.SCHEDULED_TOOT_CLIENT) { new Thread(() -> { try { - List scheduledDrafts = new StatusDraft(requireActivity()).geStatusDraftScheduledList(BaseMainActivity.accountWeakReference.get()); + List scheduledDrafts = new StatusDraft(requireActivity()).geStatusDraftScheduledList(Helper.getCurrentAccount(requireActivity())); Handler mainHandler = new Handler(Looper.getMainLooper()); binding.loader.setVisibility(View.GONE); Runnable myRunnable = () -> { @@ -105,7 +105,7 @@ public class FragmentScheduled extends Fragment implements StatusScheduledAdapte } else if (type == Timeline.TimeLineEnum.SCHEDULED_BOOST) { new Thread(() -> { try { - List scheduledBoosts = new ScheduledBoost(requireActivity()).getScheduled(BaseMainActivity.accountWeakReference.get()); + List scheduledBoosts = new ScheduledBoost(requireActivity()).getScheduled(Helper.getCurrentAccount(requireActivity())); Handler mainHandler = new Handler(Looper.getMainLooper()); Runnable myRunnable = () -> { binding.loader.setVisibility(View.GONE); diff --git a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/ReorderVM.java b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/ReorderVM.java index 2c391f2f..05387752 100644 --- a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/ReorderVM.java +++ b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/ReorderVM.java @@ -26,7 +26,6 @@ import androidx.lifecycle.MutableLiveData; import java.util.ArrayList; import java.util.concurrent.TimeUnit; -import app.fedilab.android.BaseMainActivity; import app.fedilab.android.client.endpoints.MastodonSearchService; import app.fedilab.android.client.entities.api.Results; import app.fedilab.android.client.entities.app.BottomMenu; @@ -69,7 +68,7 @@ public class ReorderVM extends AndroidViewModel { new Thread(() -> { Pinned pinned = null; try { - pinned = new Pinned(getApplication().getApplicationContext()).getAllPinned(BaseMainActivity.accountWeakReference.get()); + pinned = new Pinned(getApplication().getApplicationContext()).getAllPinned(Helper.getCurrentAccount(getApplication().getApplicationContext())); } catch (DBException e) { e.printStackTrace(); } @@ -87,7 +86,7 @@ public class ReorderVM extends AndroidViewModel { new Thread(() -> { BottomMenu bottomMenu = null; try { - bottomMenu = new BottomMenu(getApplication().getApplicationContext()).getAllBottomMenu(BaseMainActivity.accountWeakReference.get()); + bottomMenu = new BottomMenu(getApplication().getApplicationContext()).getAllBottomMenu(Helper.getCurrentAccount(getApplication().getApplicationContext())); } catch (DBException e) { e.printStackTrace(); } diff --git a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TopBarVM.java b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TopBarVM.java index 776c4ce2..0ae8c3ab 100644 --- a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TopBarVM.java +++ b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TopBarVM.java @@ -23,9 +23,9 @@ import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; -import app.fedilab.android.BaseMainActivity; import app.fedilab.android.client.entities.app.Pinned; import app.fedilab.android.exception.DBException; +import app.fedilab.android.helper.Helper; public class TopBarVM extends AndroidViewModel { @@ -42,7 +42,7 @@ public class TopBarVM extends AndroidViewModel { Handler mainHandler = new Handler(Looper.getMainLooper()); Pinned pinnedTimeline = null; try { - pinnedTimeline = pinned.getPinned(BaseMainActivity.accountWeakReference.get()); + pinnedTimeline = pinned.getPinned(Helper.getCurrentAccount(getApplication().getApplicationContext())); } catch (DBException e) { e.printStackTrace(); }