From db066c6ba6e62c867511051e4e20ffe70e872db9 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 2 Nov 2022 18:37:29 +0100 Subject: [PATCH] Some fixes --- .../app/fedilab/android/BaseMainActivity.java | 238 +++++++++--------- .../client/entities/api/Notification.java | 30 ++- .../android/client/entities/api/Status.java | 14 +- .../app/fedilab/android/helper/Helper.java | 43 ++-- .../android/ui/drawer/ComposeAdapter.java | 4 +- .../ui/drawer/ConversationAdapter.java | 14 +- .../ui/drawer/NotificationAdapter.java | 12 +- .../android/ui/drawer/ReactionAdapter.java | 2 +- .../FragmentMastodonConversation.java | 16 +- .../FragmentMastodonNotification.java | 39 ++- .../timeline/FragmentMastodonTimeline.java | 101 ++++---- .../FragmentNotificationContainer.java | 2 +- .../ui/pageadapter/FedilabPageAdapter.java | 2 +- .../viewmodel/mastodon/NotificationsVM.java | 18 +- .../viewmodel/mastodon/TimelinesVM.java | 92 ++++--- 15 files changed, 290 insertions(+), 337 deletions(-) diff --git a/app/src/main/java/app/fedilab/android/BaseMainActivity.java b/app/src/main/java/app/fedilab/android/BaseMainActivity.java index eda886e2..640f16a2 100644 --- a/app/src/main/java/app/fedilab/android/BaseMainActivity.java +++ b/app/src/main/java/app/fedilab/android/BaseMainActivity.java @@ -164,8 +164,8 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt public static boolean show_boosts, show_replies, show_art_nsfw; public static String regex_home, regex_local, regex_public; public static BaseAccount currentAccount; + public static iconLauncher mLauncher = iconLauncher.BUBBLES; Fragment currentFragment; - private AppBarConfiguration mAppBarConfiguration; private ActivityMainBinding binding; private final BroadcastReceiver broadcast_error_message = new BroadcastReceiver() { @@ -195,8 +195,101 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt } } }; - - public static iconLauncher mLauncher = iconLauncher.BUBBLES; + private Pinned pinned; + private BottomMenu bottomMenu; + private final BroadcastReceiver broadcast_data = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + Bundle b = intent.getExtras(); + if (b != null) { + if (b.getBoolean(Helper.RECEIVE_REDRAW_TOPBAR, false)) { + List mastodonLists = (List) b.getSerializable(Helper.RECEIVE_MASTODON_LIST); + redrawPinned(mastodonLists); + } + if (b.getBoolean(Helper.RECEIVE_REDRAW_BOTTOM, false)) { + bottomMenu = new BottomMenu(BaseMainActivity.this).hydrate(currentAccount, binding.bottomNavView); + if (bottomMenu != null) { + //ManageClick on bottom menu items + if (binding.bottomNavView.findViewById(R.id.nav_home) != null) { + binding.bottomNavView.findViewById(R.id.nav_home).setOnLongClickListener(view -> { + int position = BottomMenu.getPosition(bottomMenu, R.id.nav_home); + if (position >= 0) { + manageFilters(position); + } + return false; + }); + } + if (binding.bottomNavView.findViewById(R.id.nav_local) != null) { + binding.bottomNavView.findViewById(R.id.nav_local).setOnLongClickListener(view -> { + int position = BottomMenu.getPosition(bottomMenu, R.id.nav_local); + if (position >= 0) { + manageFilters(position); + } + return false; + }); + } + if (binding.bottomNavView.findViewById(R.id.nav_public) != null) { + binding.bottomNavView.findViewById(R.id.nav_public).setOnLongClickListener(view -> { + int position = BottomMenu.getPosition(bottomMenu, R.id.nav_public); + if (position >= 0) { + manageFilters(position); + } + return false; + }); + } + binding.bottomNavView.setOnItemSelectedListener(item -> { + int itemId = item.getItemId(); + int position = BottomMenu.getPosition(bottomMenu, itemId); + if (position >= 0) { + if (binding.viewPager.getCurrentItem() == position) { + scrollToTop(); + } else { + binding.viewPager.setCurrentItem(position, false); + } + } + return true; + }); + } + } else if (b.getBoolean(Helper.RECEIVE_RECREATE_ACTIVITY, false)) { + Cyanea.getInstance().edit().apply().recreate(BaseMainActivity.this); + } else if (b.getBoolean(Helper.RECEIVE_NEW_MESSAGE, false)) { + Status statusSent = (Status) b.getSerializable(Helper.RECEIVE_STATUS_ACTION); + String statusEditId = b.getString(Helper.ARG_EDIT_STATUS_ID, null); + Snackbar.make(binding.displaySnackBar, getString(R.string.message_has_been_sent), Snackbar.LENGTH_LONG) + .setAction(getString(R.string.display), view -> { + Intent intentContext = new Intent(BaseMainActivity.this, ContextActivity.class); + intentContext.putExtra(Helper.ARG_STATUS, statusSent); + intentContext.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intentContext); + }) + .setTextColor(ThemeHelper.getAttColor(BaseMainActivity.this, R.attr.mTextColor)) + .setActionTextColor(ContextCompat.getColor(BaseMainActivity.this, R.color.cyanea_accent_reference)) + .setBackgroundTint(ContextCompat.getColor(BaseMainActivity.this, R.color.cyanea_primary_dark_reference)) + .show(); + //The message was edited, we need to update the timeline + if (statusEditId != null) { + //Update message in cache + new Thread(() -> { + StatusCache statusCache = new StatusCache(); + statusCache.instance = BaseMainActivity.currentInstance; + statusCache.user_id = BaseMainActivity.currentUserID; + statusCache.status = statusSent; + statusCache.status_id = statusEditId; + try { + new StatusCache(BaseMainActivity.this).updateIfExists(statusCache); + } catch (DBException e) { + e.printStackTrace(); + } + }).start(); + //Update timelines + sendAction(context, Helper.ARG_STATUS_UPDATED, statusSent, null); + } + } + } + } + }; + private NetworkStateReceiver networkStateReceiver; + private boolean headerMenuOpen; @Override protected void onCreate(Bundle savedInstanceState) { @@ -214,7 +307,6 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt } - mamageNewIntent(getIntent()); ThemeHelper.initiliazeColors(BaseMainActivity.this); filterFetched = false; @@ -660,102 +752,6 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt } } - private Pinned pinned; - private BottomMenu bottomMenu; - private final BroadcastReceiver broadcast_data = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - Bundle b = intent.getExtras(); - if (b != null) { - if (b.getBoolean(Helper.RECEIVE_REDRAW_TOPBAR, false)) { - List mastodonLists = (List) b.getSerializable(Helper.RECEIVE_MASTODON_LIST); - redrawPinned(mastodonLists); - } - if (b.getBoolean(Helper.RECEIVE_REDRAW_BOTTOM, false)) { - bottomMenu = new BottomMenu(BaseMainActivity.this).hydrate(currentAccount, binding.bottomNavView); - if (bottomMenu != null) { - //ManageClick on bottom menu items - if (binding.bottomNavView.findViewById(R.id.nav_home) != null) { - binding.bottomNavView.findViewById(R.id.nav_home).setOnLongClickListener(view -> { - int position = BottomMenu.getPosition(bottomMenu, R.id.nav_home); - if (position >= 0) { - manageFilters(position); - } - return false; - }); - } - if (binding.bottomNavView.findViewById(R.id.nav_local) != null) { - binding.bottomNavView.findViewById(R.id.nav_local).setOnLongClickListener(view -> { - int position = BottomMenu.getPosition(bottomMenu, R.id.nav_local); - if (position >= 0) { - manageFilters(position); - } - return false; - }); - } - if (binding.bottomNavView.findViewById(R.id.nav_public) != null) { - binding.bottomNavView.findViewById(R.id.nav_public).setOnLongClickListener(view -> { - int position = BottomMenu.getPosition(bottomMenu, R.id.nav_public); - if (position >= 0) { - manageFilters(position); - } - return false; - }); - } - binding.bottomNavView.setOnItemSelectedListener(item -> { - int itemId = item.getItemId(); - int position = BottomMenu.getPosition(bottomMenu, itemId); - if (position >= 0) { - if (binding.viewPager.getCurrentItem() == position) { - scrollToTop(); - } else { - binding.viewPager.setCurrentItem(position, false); - } - } - return true; - }); - } - } else if (b.getBoolean(Helper.RECEIVE_RECREATE_ACTIVITY, false)) { - Cyanea.getInstance().edit().apply().recreate(BaseMainActivity.this); - } else if (b.getBoolean(Helper.RECEIVE_NEW_MESSAGE, false)) { - Status statusSent = (Status) b.getSerializable(Helper.RECEIVE_STATUS_ACTION); - String statusEditId = b.getString(Helper.ARG_EDIT_STATUS_ID, null); - Snackbar.make(binding.displaySnackBar, getString(R.string.message_has_been_sent), Snackbar.LENGTH_LONG) - .setAction(getString(R.string.display), view -> { - Intent intentContext = new Intent(BaseMainActivity.this, ContextActivity.class); - intentContext.putExtra(Helper.ARG_STATUS, statusSent); - intentContext.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(intentContext); - }) - .setTextColor(ThemeHelper.getAttColor(BaseMainActivity.this, R.attr.mTextColor)) - .setActionTextColor(ContextCompat.getColor(BaseMainActivity.this, R.color.cyanea_accent_reference)) - .setBackgroundTint(ContextCompat.getColor(BaseMainActivity.this, R.color.cyanea_primary_dark_reference)) - .show(); - //The message was edited, we need to update the timeline - if (statusEditId != null) { - //Update message in cache - new Thread(() -> { - StatusCache statusCache = new StatusCache(); - statusCache.instance = BaseMainActivity.currentInstance; - statusCache.user_id = BaseMainActivity.currentUserID; - statusCache.status = statusSent; - statusCache.status_id = statusEditId; - try { - new StatusCache(BaseMainActivity.this).updateIfExists(statusCache); - } catch (DBException e) { - e.printStackTrace(); - } - }).start(); - //Update timelines - sendAction(context, Helper.ARG_STATUS_UPDATED, statusSent, null); - } - } - } - } - }; - private NetworkStateReceiver networkStateReceiver; - private boolean headerMenuOpen; - protected abstract void rateThisApp(); @Override @@ -987,16 +983,6 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt } - public enum iconLauncher { - BUBBLES, - FEDIVERSE, - HERO, - ATOM, - BRAINCRASH, - MASTALAB - } - - private void manageFilters(int position) { View view = binding.bottomNavView.findViewById(R.id.nav_home); boolean showExtendedFilter = true; @@ -1338,7 +1324,6 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt } } - public void redrawPinned(List mastodonLists) { int currentItem = binding.viewPager.getCurrentItem(); new ViewModelProvider(BaseMainActivity.this).get(TopBarVM.class).getDBPinned() @@ -1389,6 +1374,17 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt } } + @Override + public boolean onSupportNavigateUp() { + NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main); + //unselect all tag elements + for (PinnedTimeline pinnedTimeline : pinned.pinnedTimelines) { + pinnedTimeline.isSelected = false; + } + return NavigationUI.navigateUp(navController, mAppBarConfiguration) + || super.onSupportNavigateUp(); + } + /* @Override public boolean onCreateOptionsMenu(@NonNull Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. @@ -1418,17 +1414,6 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt return true; }*/ - @Override - public boolean onSupportNavigateUp() { - NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main); - //unselect all tag elements - for (PinnedTimeline pinnedTimeline : pinned.pinnedTimelines) { - pinnedTimeline.isSelected = false; - } - return NavigationUI.navigateUp(navController, mAppBarConfiguration) - || super.onSupportNavigateUp(); - } - @Override public void networkAvailable() { networkAvailable = status.CONNECTED; @@ -1439,6 +1424,15 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt networkAvailable = DISCONNECTED; } + public enum iconLauncher { + BUBBLES, + FEDIVERSE, + HERO, + ATOM, + BRAINCRASH, + MASTALAB + } + public enum status { UNKNOWN, diff --git a/app/src/main/java/app/fedilab/android/client/entities/api/Notification.java b/app/src/main/java/app/fedilab/android/client/entities/api/Notification.java index 4db1ae7f..89b29fba 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/api/Notification.java +++ b/app/src/main/java/app/fedilab/android/client/entities/api/Notification.java @@ -41,25 +41,9 @@ public class Notification { public boolean cached; public PositionFetchMore positionFetchMore = PositionFetchMore.BOTTOM; - - public enum PositionFetchMore { - TOP, - BOTTOM - } - - @Override - public boolean equals(@Nullable Object obj) { - boolean same = false; - if (obj instanceof Notification) { - same = this.id.equals(((Notification) obj).id); - } - return same; - } - public transient List relatedNotifications; public boolean isFetchMore; - /** * Serialized a list of Notification class * @@ -91,4 +75,18 @@ public class Notification { } } + @Override + public boolean equals(@Nullable Object obj) { + boolean same = false; + if (obj instanceof Notification) { + same = this.id.equals(((Notification) obj).id); + } + return same; + } + + public enum PositionFetchMore { + TOP, + BOTTOM + } + } diff --git a/app/src/main/java/app/fedilab/android/client/entities/api/Status.java b/app/src/main/java/app/fedilab/android/client/entities/api/Status.java index 8a40c782..963256bc 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/api/Status.java +++ b/app/src/main/java/app/fedilab/android/client/entities/api/Status.java @@ -113,12 +113,6 @@ public class Status implements Serializable, Cloneable { public transient boolean submitted = false; public transient boolean spoilerChecked = false; - - public enum PositionFetchMore { - TOP, - BOTTOM - } - @Override public boolean equals(@Nullable Object obj) { boolean same = false; @@ -127,12 +121,11 @@ public class Status implements Serializable, Cloneable { } return same; } - //Some extra spannable element - They will be filled automatically when fetching the status public synchronized Spannable getSpanContent(Context context, WeakReference viewWeakReference) { return SpannableHelper.convert(context, content, this, null, null, true, viewWeakReference); } - + //Some extra spannable element - They will be filled automatically when fetching the status public Spannable getSpanContentNitter() { return SpannableHelper.convertNitter(content); @@ -151,4 +144,9 @@ public class Status implements Serializable, Cloneable { return super.clone(); } + public enum PositionFetchMore { + TOP, + BOTTOM + } + } 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 a28d6d6f..f88f497d 100644 --- a/app/src/main/java/app/fedilab/android/helper/Helper.java +++ b/app/src/main/java/app/fedilab/android/helper/Helper.java @@ -376,6 +376,8 @@ public class Helper { }; public static int counter = 1; private static int notificationId = 1; + //Allow to store in shared preference first visible fragment when the app starts + private static String slugOfFirstFragment; static { LinkedHashMap aMap = new LinkedHashMap<>(); @@ -1855,6 +1857,24 @@ public class Helper { } } + public static String getSlugOfFirstFragment(Context context, String userId, String instance) { + if (slugOfFirstFragment != null) { + return slugOfFirstFragment; + } + SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context); + return sharedpreferences.getString(Helper.ARG_SLUG_OF_FIRST_FRAGMENT + userId + instance, Timeline.TimeLineEnum.HOME.getValue()); + } + + public static void setSlugOfFirstFragment(Context context, String slug, String userId, String instance) { + if (slug != null) { + SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context); + SharedPreferences.Editor editor = sharedpreferences.edit(); + slugOfFirstFragment = slug; + editor.putString(Helper.ARG_SLUG_OF_FIRST_FRAGMENT + userId + instance, slug); + editor.apply(); + } + } + //Enum that described actions to replace inside a toot content public enum PatternType { @@ -1876,30 +1896,7 @@ public class Helper { TOOT } - public interface OnAttachmentCopied { void onAttachmentCopied(Attachment attachment); } - - - //Allow to store in shared preference first visible fragment when the app starts - private static String slugOfFirstFragment; - - public static String getSlugOfFirstFragment(Context context, String userId, String instance) { - if (slugOfFirstFragment != null) { - return slugOfFirstFragment; - } - SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context); - return sharedpreferences.getString(Helper.ARG_SLUG_OF_FIRST_FRAGMENT + userId + instance, Timeline.TimeLineEnum.HOME.getValue()); - } - - public static void setSlugOfFirstFragment(Context context, String slug, String userId, String instance) { - if (slug != null) { - SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context); - SharedPreferences.Editor editor = sharedpreferences.edit(); - slugOfFirstFragment = slug; - editor.putString(Helper.ARG_SLUG_OF_FIRST_FRAGMENT + userId + instance, slug); - editor.apply(); - } - } } 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 92fb144c..c42f24e6 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 @@ -134,12 +134,12 @@ public class ComposeAdapter extends RecyclerView.Adapter emojisList = new ArrayList<>(); - private final String editMessageId; public ComposeAdapter(List statusList, int statusCount, BaseAccount account, app.fedilab.android.client.entities.api.Account mentionedAccount, String visibility, String editMessageId) { this.statusList = statusList; @@ -399,7 +399,7 @@ public class ComposeAdapter extends RecyclerView.Adapter(); } diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/ConversationAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/ConversationAdapter.java index 6b351a29..d3acef6c 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/ConversationAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/ConversationAdapter.java @@ -56,9 +56,9 @@ import app.fedilab.android.helper.MastodonHelper; public class ConversationAdapter extends RecyclerView.Adapter { private final List conversationList; + public FetchMoreCallBack fetchMoreCallBack; private Context context; private boolean isExpended = false; - public FetchMoreCallBack fetchMoreCallBack; public ConversationAdapter(List conversations) { if (conversations == null) { @@ -284,6 +284,12 @@ public class ConversationAdapter extends RecyclerView.Adapter reactions; private final String announcementId; - private Context context; private final boolean statusReaction; + private Context context; ReactionAdapter(String announcementId, List reactions, boolean statusReaction) { this.reactions = reactions; diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonConversation.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonConversation.java index 92ba891f..70891175 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonConversation.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonConversation.java @@ -39,7 +39,6 @@ import app.fedilab.android.BaseMainActivity; import app.fedilab.android.R; import app.fedilab.android.client.entities.api.Conversation; import app.fedilab.android.client.entities.api.Conversations; -import app.fedilab.android.client.entities.api.Pagination; import app.fedilab.android.client.entities.app.StatusCache; import app.fedilab.android.client.entities.app.Timeline; import app.fedilab.android.databinding.FragmentPaginationBinding; @@ -54,6 +53,7 @@ import app.fedilab.android.viewmodel.mastodon.TimelinesVM; public class FragmentMastodonConversation extends Fragment implements ConversationAdapter.FetchMoreCallBack { + public UpdateCounters update; private FragmentPaginationBinding binding; private TimelinesVM timelinesVM; private boolean flagLoading; @@ -61,10 +61,10 @@ public class FragmentMastodonConversation extends Fragment implements Conversati private String max_id, min_id, min_id_fetch_more, max_id_fetch_more; private ConversationAdapter conversationAdapter; private LinearLayoutManager mLayoutManager; - public UpdateCounters update; private boolean isViewInitialized; private Conversations initialConversations; + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { flagLoading = false; @@ -88,17 +88,7 @@ public class FragmentMastodonConversation extends Fragment implements Conversati super.onResume(); if (Timeline.TimeLineEnum.CONVERSATION.getValue().compareTo(Helper.getSlugOfFirstFragment(requireActivity(), currentUserID, currentInstance)) != 0 && !isViewInitialized) { isViewInitialized = true; - if (initialConversations != null && initialConversations.conversations != null && initialConversations.conversations.size() > 0) { - initializeConversationCommonView(initialConversations); - } else { - Conversations conversations = new Conversations(); - if (conversationList != null && conversationList.size() > 0) { - conversations.pagination = new Pagination(); - conversations.pagination.max_id = conversationList.get(conversationList.size() - 1).id; - conversations.pagination.min_id = conversationList.get(0).id; - } - initializeConversationCommonView(conversations); - } + initializeConversationCommonView(initialConversations); } } diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonNotification.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonNotification.java index 9526a251..92359ea0 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonNotification.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonNotification.java @@ -28,6 +28,7 @@ import android.view.View; import android.view.ViewGroup; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; import androidx.localbroadcastmanager.content.LocalBroadcastManager; @@ -45,7 +46,6 @@ import app.fedilab.android.BaseMainActivity; import app.fedilab.android.R; import app.fedilab.android.client.entities.api.Notification; import app.fedilab.android.client.entities.api.Notifications; -import app.fedilab.android.client.entities.api.Pagination; import app.fedilab.android.client.entities.api.Status; import app.fedilab.android.client.entities.app.StatusCache; import app.fedilab.android.client.entities.app.Timeline; @@ -67,9 +67,6 @@ public class FragmentMastodonNotification extends Fragment implements Notificati private boolean flagLoading; private List notificationList; private NotificationAdapter notificationAdapter; - private boolean isViewInitialized; - private Notifications initialNotifications; - private final BroadcastReceiver receive_action = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -93,6 +90,8 @@ public class FragmentMastodonNotification extends Fragment implements Notificati } } }; + private boolean isViewInitialized; + private Notifications initialNotifications; private String max_id, min_id, min_id_fetch_more, max_id_fetch_more; private LinearLayoutManager mLayoutManager; private NotificationTypeEnum notificationType; @@ -136,6 +135,18 @@ public class FragmentMastodonNotification extends Fragment implements Notificati return found ? position : -1; } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + notificationsVM = new ViewModelProvider(FragmentMastodonNotification.this).get(NotificationsVM.class); + binding.loader.setVisibility(View.VISIBLE); + binding.recyclerView.setVisibility(View.GONE); + max_id = null; + route(null, false); + } + + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -153,11 +164,7 @@ public class FragmentMastodonNotification extends Fragment implements Notificati binding.swipeContainer.setColorSchemeColors( c1, c1, c1 ); - notificationsVM = new ViewModelProvider(FragmentMastodonNotification.this).get(NotificationsVM.class); - binding.loader.setVisibility(View.VISIBLE); - binding.recyclerView.setVisibility(View.GONE); - max_id = null; - route(null, false); + LocalBroadcastManager.getInstance(requireActivity()).registerReceiver(receive_action, new IntentFilter(Helper.RECEIVE_STATUS_ACTION)); return root; } @@ -199,6 +206,7 @@ public class FragmentMastodonNotification extends Fragment implements Notificati } return excludeType; } + /** * Intialize the view for notifications * @@ -298,17 +306,7 @@ public class FragmentMastodonNotification extends Fragment implements Notificati super.onResume(); if (Timeline.TimeLineEnum.NOTIFICATION.getValue().compareTo(Helper.getSlugOfFirstFragment(requireActivity(), currentUserID, currentInstance)) != 0 && !isViewInitialized) { isViewInitialized = true; - if (initialNotifications != null && initialNotifications.notifications != null && initialNotifications.notifications.size() > 0) { - initializeNotificationView(initialNotifications); - } else { - Notifications notifications = new Notifications(); - if (notificationList != null && notificationList.size() > 0) { - notifications.pagination = new Pagination(); - notifications.pagination.max_id = notificationList.get(notificationList.size() - 1).id; - notifications.pagination.min_id = notificationList.get(0).id; - } - initializeNotificationView(notifications); - } + initializeNotificationView(initialNotifications); } } @@ -589,7 +587,6 @@ public class FragmentMastodonNotification extends Fragment implements Notificati } - @Override public void onDestroyView() { LocalBroadcastManager.getInstance(requireActivity()).unregisterReceiver(receive_action); 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 b98604fa..9b427b3a 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 @@ -32,6 +32,7 @@ import android.view.View; import android.view.ViewGroup; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; import androidx.localbroadcastmanager.content.LocalBroadcastManager; @@ -69,6 +70,7 @@ import es.dmoral.toasty.Toasty; public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.FetchMoreCallBack { + public UpdateCounters update; private FragmentPaginationBinding binding; private TimelinesVM timelinesVM; private AccountsVM accountsVM; @@ -79,10 +81,6 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. private StatusAdapter statusAdapter; private Timeline.TimeLineEnum timelineType; private List timelineStatuses; - public UpdateCounters update; - private boolean isViewInitialized; - private Statuses initialStatuses; - //Handle actions that can be done in other fragments private final BroadcastReceiver receive_action = new BroadcastReceiver() { @Override @@ -138,6 +136,8 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. } } }; + private boolean isViewInitialized; + private Statuses initialStatuses; private String list_id; private TagTimeline tagTimeline; private LinearLayoutManager mLayoutManager; @@ -157,17 +157,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. if (slug != null && slug.compareTo(Helper.getSlugOfFirstFragment(requireActivity(), currentUserID, currentInstance)) != 0 && !isViewInitialized) { isViewInitialized = true; - if (initialStatuses != null && initialStatuses.statuses != null && initialStatuses.statuses.size() > 0) { - initializeStatusesCommonView(initialStatuses); - } else { - Statuses statuses = new Statuses(); - if (timelineStatuses != null && timelineStatuses.size() > 0) { - statuses.pagination = new Pagination(); - statuses.pagination.max_id = timelineStatuses.get(timelineStatuses.size() - 1).id; - statuses.pagination.min_id = timelineStatuses.get(0).id; - } - initializeStatusesCommonView(statuses); - } + initializeStatusesCommonView(initialStatuses); } if (timelineStatuses != null && timelineStatuses.size() > 0) { route(DIRECTION.FETCH_NEW, true); @@ -219,6 +209,35 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. } } + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + timelinesVM = new ViewModelProvider(FragmentMastodonTimeline.this).get(viewModelKey, TimelinesVM.class); + accountsVM = new ViewModelProvider(FragmentMastodonTimeline.this).get(viewModelKey, AccountsVM.class); + + binding.loader.setVisibility(View.VISIBLE); + binding.recyclerView.setVisibility(View.GONE); + max_id = statusReport != null ? statusReport.id : null; + SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(requireActivity()); + rememberPosition = sharedpreferences.getBoolean(getString(R.string.SET_REMEMBER_POSITION), true); + //Inner marker are only for pinned timelines and main timelines, they have isViewInitialized set to false + if (max_id == null && !isViewInitialized && rememberPosition) { + max_id = sharedpreferences.getString(getString(R.string.SET_INNER_MARKER) + BaseMainActivity.currentUserID + BaseMainActivity.currentInstance + slug, null); + } + //Only fragment in main view pager should not have the view initialized + //AND Only the first fragment will initialize its view + if (!isViewInitialized) { + if (slug != null) { + isViewInitialized = slug.compareTo(Helper.getSlugOfFirstFragment(requireActivity(), currentUserID, currentInstance)) == 0; + } + } + + flagLoading = false; + + router(null); + } + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -273,8 +292,6 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. slug = timelineType != Timeline.TimeLineEnum.ART ? timelineType.getValue() + (ident != null ? "|" + ident : "") : Timeline.TimeLineEnum.TAG.getValue() + (ident != null ? "|" + ident : ""); } - SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(requireActivity()); - LocalBroadcastManager.getInstance(requireActivity()).registerReceiver(receive_action, new IntentFilter(Helper.RECEIVE_STATUS_ACTION)); binding = FragmentPaginationBinding.inflate(inflater, container, false); binding.getRoot().setBackgroundColor(ThemeHelper.getBackgroundColor(requireActivity())); @@ -285,28 +302,6 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. c1, c1, c1 ); - timelinesVM = new ViewModelProvider(FragmentMastodonTimeline.this).get(viewModelKey, TimelinesVM.class); - accountsVM = new ViewModelProvider(FragmentMastodonTimeline.this).get(viewModelKey, AccountsVM.class); - - binding.loader.setVisibility(View.VISIBLE); - binding.recyclerView.setVisibility(View.GONE); - max_id = statusReport != null ? statusReport.id : null; - - rememberPosition = sharedpreferences.getBoolean(getString(R.string.SET_REMEMBER_POSITION), true); - //Inner marker are only for pinned timelines and main timelines, they have isViewInitialized set to false - if (max_id == null && !isViewInitialized && rememberPosition) { - max_id = sharedpreferences.getString(getString(R.string.SET_INNER_MARKER) + BaseMainActivity.currentUserID + BaseMainActivity.currentInstance + slug, null); - } - //Only fragment in main view pager should not have the view initialized - //AND Only the first fragment will initialize its view - if (!isViewInitialized) { - if (slug != null) { - isViewInitialized = slug.compareTo(Helper.getSlugOfFirstFragment(requireActivity(), currentUserID, currentInstance)) == 0; - } - } - - flagLoading = false; - router(null); return binding.getRoot(); } @@ -693,9 +688,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. } private void getCachedStatus(DIRECTION direction, boolean fetchingMissing, TimelinesVM.TimelineParams timelineParams) { - if (getView() == null) { - return; - } + if (direction == null) { timelinesVM.getTimelineCache(timelineStatuses, timelineParams) .observe(getViewLifecycleOwner(), statusesCached -> { @@ -742,9 +735,6 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. } private void getLiveStatus(DIRECTION direction, boolean fetchingMissing, TimelinesVM.TimelineParams timelineParams, Status status) { - if (getView() == null) { - return; - } if (direction == null) { timelinesVM.getTimeline(timelineStatuses, timelineParams) @@ -770,16 +760,6 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. } } - - public enum DIRECTION { - TOP, - BOTTOM, - REFRESH, - SCROLL_TOP, - FETCH_NEW - } - - /** * Router for timelines * @@ -965,9 +945,6 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. } - - - /** * Refresh status in list */ @@ -990,6 +967,14 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. route(DIRECTION.BOTTOM, true, statusToUpdate); } + public enum DIRECTION { + TOP, + BOTTOM, + REFRESH, + SCROLL_TOP, + FETCH_NEW + } + public interface UpdateCounters { void onUpdate(int count, Timeline.TimeLineEnum type, String slug); } diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentNotificationContainer.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentNotificationContainer.java index 63717a8b..b243ae7d 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentNotificationContainer.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentNotificationContainer.java @@ -53,8 +53,8 @@ import es.dmoral.toasty.Toasty; public class FragmentNotificationContainer extends Fragment { - private FragmentNotificationContainerBinding binding; public static UpdateCounters update; + private FragmentNotificationContainerBinding binding; public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { diff --git a/app/src/main/java/app/fedilab/android/ui/pageadapter/FedilabPageAdapter.java b/app/src/main/java/app/fedilab/android/ui/pageadapter/FedilabPageAdapter.java index 4f1fe6b9..aada3c69 100644 --- a/app/src/main/java/app/fedilab/android/ui/pageadapter/FedilabPageAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/pageadapter/FedilabPageAdapter.java @@ -45,8 +45,8 @@ public class FedilabPageAdapter extends FragmentStatePagerAdapter { private final BottomMenu bottomMenu; private final int toRemove; private final boolean singleBar; - private Fragment mCurrentFragment; private final BaseMainActivity activity; + private Fragment mCurrentFragment; public FedilabPageAdapter(BaseMainActivity activity, FragmentManager fm, Pinned pinned, BottomMenu bottomMenu) { super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT); diff --git a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/NotificationsVM.java b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/NotificationsVM.java index ca3d7252..f385ad7f 100644 --- a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/NotificationsVM.java +++ b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/NotificationsVM.java @@ -64,15 +64,6 @@ public class NotificationsVM extends AndroidViewModel { super(application); } - private MastodonNotificationsService init(@NonNull String instance) { - Retrofit retrofit = new Retrofit.Builder() - .baseUrl("https://" + instance + "/api/v1/") - .addConverterFactory(GsonConverterFactory.create(Helper.getDateBuilder())) - .client(okHttpClient) - .build(); - return retrofit.create(MastodonNotificationsService.class); - } - private static void addFetchMoreNotifications(List notificationList, List timelineNotifications, TimelinesVM.TimelineParams timelineParams) throws DBException { if (notificationList != null && notificationList.size() > 0 && timelineNotifications != null && timelineNotifications.size() > 0) { if (timelineParams.direction == FragmentMastodonTimeline.DIRECTION.REFRESH || timelineParams.direction == FragmentMastodonTimeline.DIRECTION.SCROLL_TOP || timelineParams.direction == FragmentMastodonTimeline.DIRECTION.FETCH_NEW) { @@ -95,6 +86,15 @@ public class NotificationsVM extends AndroidViewModel { } } + private MastodonNotificationsService init(@NonNull String instance) { + Retrofit retrofit = new Retrofit.Builder() + .baseUrl("https://" + instance + "/api/v1/") + .addConverterFactory(GsonConverterFactory.create(Helper.getDateBuilder())) + .client(okHttpClient) + .build(); + return retrofit.create(MastodonNotificationsService.class); + } + /** * Get notifications for the authenticated account * diff --git a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java index c808a8e7..f65d5224 100644 --- a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java +++ b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java @@ -89,6 +89,50 @@ public class TimelinesVM extends AndroidViewModel { super(application); } + private static void addFetchMore(List statusList, List timelineStatuses, TimelineParams timelineParams) throws DBException { + if (statusList != null && statusList.size() > 0 && timelineStatuses != null && timelineStatuses.size() > 0) { + if (timelineParams.direction == FragmentMastodonTimeline.DIRECTION.REFRESH || timelineParams.direction == FragmentMastodonTimeline.DIRECTION.SCROLL_TOP || timelineParams.direction == FragmentMastodonTimeline.DIRECTION.FETCH_NEW) { + //When refreshing/scrolling to TOP, if last statuses fetched has a greater id from newest in cache, there is potential hole + if (statusList.get(statusList.size() - 1).id.compareToIgnoreCase(timelineStatuses.get(0).id) > 0) { + statusList.get(statusList.size() - 1).isFetchMore = true; + statusList.get(statusList.size() - 1).positionFetchMore = Status.PositionFetchMore.TOP; + } + } else if (timelineParams.direction == FragmentMastodonTimeline.DIRECTION.TOP && timelineParams.fetchingMissing) { + if (!timelineStatuses.contains(statusList.get(0))) { + statusList.get(0).isFetchMore = true; + statusList.get(0).positionFetchMore = Status.PositionFetchMore.BOTTOM; + } + } else if (timelineParams.direction == FragmentMastodonTimeline.DIRECTION.BOTTOM && timelineParams.fetchingMissing) { + if (!timelineStatuses.contains(statusList.get(statusList.size() - 1))) { + statusList.get(statusList.size() - 1).isFetchMore = true; + statusList.get(statusList.size() - 1).positionFetchMore = Status.PositionFetchMore.TOP; + } + } + } + } + + private static void addFetchMoreConversation(List conversationList, List timelineConversations, TimelineParams timelineParams) throws DBException { + if (conversationList != null && conversationList.size() > 0 && timelineConversations != null && timelineConversations.size() > 0) { + if (timelineParams.direction == FragmentMastodonTimeline.DIRECTION.REFRESH || timelineParams.direction == FragmentMastodonTimeline.DIRECTION.SCROLL_TOP || timelineParams.direction == FragmentMastodonTimeline.DIRECTION.FETCH_NEW) { + //When refreshing/scrolling to TOP, if last statuses fetched has a greater id from newest in cache, there is potential hole + if (conversationList.get(conversationList.size() - 1).id.compareToIgnoreCase(timelineConversations.get(0).id) > 0) { + conversationList.get(conversationList.size() - 1).isFetchMore = true; + conversationList.get(conversationList.size() - 1).positionFetchMore = Conversation.PositionFetchMore.TOP; + } + } else if (timelineParams.direction == FragmentMastodonTimeline.DIRECTION.TOP && timelineParams.fetchingMissing) { + if (!timelineConversations.contains(conversationList.get(0))) { + conversationList.get(0).isFetchMore = true; + conversationList.get(0).positionFetchMore = Conversation.PositionFetchMore.BOTTOM; + } + } else if (timelineParams.direction == FragmentMastodonTimeline.DIRECTION.BOTTOM && timelineParams.fetchingMissing) { + if (!timelineConversations.contains(conversationList.get(conversationList.size() - 1))) { + conversationList.get(conversationList.size() - 1).isFetchMore = true; + conversationList.get(conversationList.size() - 1).positionFetchMore = Conversation.PositionFetchMore.TOP; + } + } + } + } + private MastodonTimelinesService initInstanceOnly(String instance) { Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://" + instance) @@ -140,7 +184,6 @@ public class TimelinesVM extends AndroidViewModel { return statusListMutableLiveData; } - public LiveData> getTagsTrends(String token, @NonNull String instance) { MastodonTimelinesService mastodonTimelinesService = init(instance); tagListMutableLiveData = new MutableLiveData<>(); @@ -165,7 +208,6 @@ public class TimelinesVM extends AndroidViewModel { return tagListMutableLiveData; } - /** * Public timeline for Nitter * @@ -312,7 +354,6 @@ public class TimelinesVM extends AndroidViewModel { return statusesMutableLiveData; } - /** * Returns details for a peertube video * @@ -340,51 +381,6 @@ public class TimelinesVM extends AndroidViewModel { return peertubeVideoMutableLiveData; } - - private static void addFetchMore(List statusList, List timelineStatuses, TimelineParams timelineParams) throws DBException { - if (statusList != null && statusList.size() > 0 && timelineStatuses != null && timelineStatuses.size() > 0) { - if (timelineParams.direction == FragmentMastodonTimeline.DIRECTION.REFRESH || timelineParams.direction == FragmentMastodonTimeline.DIRECTION.SCROLL_TOP || timelineParams.direction == FragmentMastodonTimeline.DIRECTION.FETCH_NEW) { - //When refreshing/scrolling to TOP, if last statuses fetched has a greater id from newest in cache, there is potential hole - if (statusList.get(statusList.size() - 1).id.compareToIgnoreCase(timelineStatuses.get(0).id) > 0) { - statusList.get(statusList.size() - 1).isFetchMore = true; - statusList.get(statusList.size() - 1).positionFetchMore = Status.PositionFetchMore.TOP; - } - } else if (timelineParams.direction == FragmentMastodonTimeline.DIRECTION.TOP && timelineParams.fetchingMissing) { - if (!timelineStatuses.contains(statusList.get(0))) { - statusList.get(0).isFetchMore = true; - statusList.get(0).positionFetchMore = Status.PositionFetchMore.BOTTOM; - } - } else if (timelineParams.direction == FragmentMastodonTimeline.DIRECTION.BOTTOM && timelineParams.fetchingMissing) { - if (!timelineStatuses.contains(statusList.get(statusList.size() - 1))) { - statusList.get(statusList.size() - 1).isFetchMore = true; - statusList.get(statusList.size() - 1).positionFetchMore = Status.PositionFetchMore.TOP; - } - } - } - } - - private static void addFetchMoreConversation(List conversationList, List timelineConversations, TimelineParams timelineParams) throws DBException { - if (conversationList != null && conversationList.size() > 0 && timelineConversations != null && timelineConversations.size() > 0) { - if (timelineParams.direction == FragmentMastodonTimeline.DIRECTION.REFRESH || timelineParams.direction == FragmentMastodonTimeline.DIRECTION.SCROLL_TOP || timelineParams.direction == FragmentMastodonTimeline.DIRECTION.FETCH_NEW) { - //When refreshing/scrolling to TOP, if last statuses fetched has a greater id from newest in cache, there is potential hole - if (conversationList.get(conversationList.size() - 1).id.compareToIgnoreCase(timelineConversations.get(0).id) > 0) { - conversationList.get(conversationList.size() - 1).isFetchMore = true; - conversationList.get(conversationList.size() - 1).positionFetchMore = Conversation.PositionFetchMore.TOP; - } - } else if (timelineParams.direction == FragmentMastodonTimeline.DIRECTION.TOP && timelineParams.fetchingMissing) { - if (!timelineConversations.contains(conversationList.get(0))) { - conversationList.get(0).isFetchMore = true; - conversationList.get(0).positionFetchMore = Conversation.PositionFetchMore.BOTTOM; - } - } else if (timelineParams.direction == FragmentMastodonTimeline.DIRECTION.BOTTOM && timelineParams.fetchingMissing) { - if (!timelineConversations.contains(conversationList.get(conversationList.size() - 1))) { - conversationList.get(conversationList.size() - 1).isFetchMore = true; - conversationList.get(conversationList.size() - 1).positionFetchMore = Conversation.PositionFetchMore.TOP; - } - } - } - } - public LiveData getTimeline(List timelineStatuses, TimelineParams timelineParams) { statusesMutableLiveData = new MutableLiveData<>(); MastodonTimelinesService mastodonTimelinesService = init(timelineParams.instance);