diff --git a/app/src/main/java/awais/instagrabber/fragments/TopicPostsFragment.java b/app/src/main/java/awais/instagrabber/fragments/TopicPostsFragment.java deleted file mode 100644 index cd3ba776..00000000 --- a/app/src/main/java/awais/instagrabber/fragments/TopicPostsFragment.java +++ /dev/null @@ -1,393 +0,0 @@ -package awais.instagrabber.fragments; - -import android.animation.ArgbEvaluator; -import android.content.Context; -import android.graphics.Color; -import android.graphics.PorterDuff; -import android.graphics.drawable.Animatable; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.GradientDrawable; -import android.os.Bundle; -import android.os.Handler; -import android.util.Log; -import android.view.ActionMode; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; - -import androidx.activity.OnBackPressedCallback; -import androidx.activity.OnBackPressedDispatcher; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.coordinatorlayout.widget.CoordinatorLayout; -import androidx.core.graphics.ColorUtils; -import androidx.fragment.app.Fragment; -import androidx.navigation.NavDirections; -import androidx.navigation.fragment.NavHostFragment; -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; -import androidx.transition.ChangeBounds; -import androidx.transition.TransitionInflater; -import androidx.transition.TransitionSet; - -import com.facebook.drawee.backends.pipeline.Fresco; -import com.facebook.drawee.controller.BaseControllerListener; -import com.facebook.drawee.interfaces.DraweeController; -import com.facebook.imagepipeline.image.ImageInfo; -import com.google.common.collect.ImmutableList; - -import java.util.Set; - -import awais.instagrabber.R; -import awais.instagrabber.activities.MainActivity; -import awais.instagrabber.adapters.FeedAdapterV2; -import awais.instagrabber.asyncs.DiscoverPostFetchService; -import awais.instagrabber.customviews.PrimaryActionModeCallback; -import awais.instagrabber.databinding.FragmentTopicPostsBinding; -import awais.instagrabber.dialogs.PostsLayoutPreferencesDialogFragment; -import awais.instagrabber.models.PostsLayoutPreferences; -import awais.instagrabber.repositories.responses.Location; -import awais.instagrabber.repositories.responses.Media; -import awais.instagrabber.repositories.responses.User; -import awais.instagrabber.repositories.responses.discover.TopicCluster; -import awais.instagrabber.utils.AppExecutors; -import awais.instagrabber.utils.Constants; -import awais.instagrabber.utils.DownloadUtils; -import awais.instagrabber.utils.ResponseBodyUtils; -import awais.instagrabber.utils.Utils; -import awais.instagrabber.webservices.DiscoverService; - -public class TopicPostsFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener { - private static final String TAG = TopicPostsFragment.class.getSimpleName(); - - private MainActivity fragmentActivity; - private FragmentTopicPostsBinding binding; - private CoordinatorLayout root; - private boolean shouldRefresh = true; - private TopicCluster topicCluster; - private ActionMode actionMode; - private Set selectedFeedModels; - private PostsLayoutPreferences layoutPreferences = Utils.getPostsLayoutPreferences(Constants.PREF_TOPIC_POSTS_LAYOUT); - - private final OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(false) { - @Override - public void handleOnBackPressed() { - binding.posts.endSelection(); - } - }; - private final PrimaryActionModeCallback multiSelectAction = new PrimaryActionModeCallback( - R.menu.multi_select_download_menu, new PrimaryActionModeCallback.CallbacksHelper() { - @Override - public void onDestroy(final ActionMode mode) { - binding.posts.endSelection(); - } - - @Override - public boolean onActionItemClicked(final ActionMode mode, - final MenuItem item) { - if (item.getItemId() == R.id.action_download) { - if (TopicPostsFragment.this.selectedFeedModels == null) return false; - final Context context = getContext(); - if (context == null) return false; - DownloadUtils.download(context, ImmutableList.copyOf(TopicPostsFragment.this.selectedFeedModels)); - binding.posts.endSelection(); - return true; - } - return false; - } - }); - private final FeedAdapterV2.FeedItemCallback feedItemCallback = new FeedAdapterV2.FeedItemCallback() { - @Override - public void onPostClick(final Media feedModel) { - openPostDialog(feedModel, -1); - } - - @Override - public void onSliderClick(final Media feedModel, final int position) { - openPostDialog(feedModel, position); - } - - @Override - public void onCommentsClick(final Media feedModel) { - final User user = feedModel.getUser(); - if (user == null) return; - final NavDirections commentsAction = TopicPostsFragmentDirections.actionToComments( - feedModel.getCode(), - feedModel.getPk(), - user.getPk() - ); - NavHostFragment.findNavController(TopicPostsFragment.this).navigate(commentsAction); - } - - @Override - public void onDownloadClick(final Media feedModel, final int childPosition, final View popupLocation) { - final Context context = getContext(); - if (context == null) return; - DownloadUtils.showDownloadDialog(context, feedModel, childPosition, popupLocation); - } - - @Override - public void onHashtagClick(final String hashtag) { - final NavDirections action = TopicPostsFragmentDirections.actionToHashtag(hashtag); - NavHostFragment.findNavController(TopicPostsFragment.this).navigate(action); - } - - @Override - public void onLocationClick(final Media feedModel) { - final Location location = feedModel.getLocation(); - if (location == null) return; - final NavDirections action = TopicPostsFragmentDirections.actionToLocation(location.getPk()); - NavHostFragment.findNavController(TopicPostsFragment.this).navigate(action); - } - - @Override - public void onMentionClick(final String mention) { - navigateToProfile(mention.trim()); - } - - @Override - public void onNameClick(final Media feedModel) { - navigateToProfile("@" + feedModel.getUser().getUsername()); - } - - @Override - public void onProfilePicClick(final Media feedModel) { - final User user = feedModel.getUser(); - if (user == null) return; - navigateToProfile("@" + user.getUsername()); - } - - @Override - public void onURLClick(final String url) { - Utils.openURL(getContext(), url); - } - - @Override - public void onEmailClick(final String emailId) { - Utils.openEmailAddress(getContext(), emailId); - } - - private void openPostDialog(final Media feedModel, final int position) { - try { - final NavDirections action = TopicPostsFragmentDirections.actionToPost(feedModel, position); - NavHostFragment.findNavController(TopicPostsFragment.this).navigate(action); - } catch (Exception e) { - Log.e(TAG, "openPostDialog: ", e); - } - } - }; - private final FeedAdapterV2.SelectionModeCallback selectionModeCallback = new FeedAdapterV2.SelectionModeCallback() { - - @Override - public void onSelectionStart() { - if (!onBackPressedCallback.isEnabled()) { - final OnBackPressedDispatcher onBackPressedDispatcher = fragmentActivity.getOnBackPressedDispatcher(); - onBackPressedCallback.setEnabled(true); - onBackPressedDispatcher.addCallback(getViewLifecycleOwner(), onBackPressedCallback); - } - if (actionMode == null) { - actionMode = fragmentActivity.startActionMode(multiSelectAction); - } - } - - @Override - public void onSelectionChange(final Set selectedFeedModels) { - final String title = getString(R.string.number_selected, selectedFeedModels.size()); - if (actionMode != null) { - actionMode.setTitle(title); - } - TopicPostsFragment.this.selectedFeedModels = selectedFeedModels; - } - - @Override - public void onSelectionEnd() { - if (onBackPressedCallback.isEnabled()) { - onBackPressedCallback.setEnabled(false); - onBackPressedCallback.remove(); - } - if (actionMode != null) { - actionMode.finish(); - actionMode = null; - } - } - }; - - @Override - public void onCreate(@Nullable final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - fragmentActivity = (MainActivity) requireActivity(); - final Context context = getContext(); - if (context != null) { - final TransitionSet transitionSet = new TransitionSet(); - transitionSet.addTransition(new ChangeBounds()) - .addTransition(TransitionInflater.from(context).inflateTransition(android.R.transition.move)) - .setDuration(200); - setSharedElementEnterTransition(transitionSet); - } - postponeEnterTransition(); - setHasOptionsMenu(true); - } - - @Nullable - @Override - public View onCreateView(@NonNull final LayoutInflater inflater, - @Nullable final ViewGroup container, - @Nullable final Bundle savedInstanceState) { - if (root != null) { - shouldRefresh = false; - return root; - } - binding = FragmentTopicPostsBinding.inflate(inflater, container, false); - root = binding.getRoot(); - return root; - } - - @Override - public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) { - if (!shouldRefresh) return; - binding.swipeRefreshLayout.setOnRefreshListener(this); - init(); - shouldRefresh = false; - } - - @Override - public void onCreateOptionsMenu(@NonNull final Menu menu, @NonNull final MenuInflater inflater) { - inflater.inflate(R.menu.topic_posts_menu, menu); - } - - @Override - public boolean onOptionsItemSelected(@NonNull final MenuItem item) { - if (item.getItemId() == R.id.layout) { - showPostsLayoutPreferences(); - return true; - } - return super.onOptionsItemSelected(item); - } - - @Override - public void onResume() { - super.onResume(); - fragmentActivity.setToolbar(binding.toolbar, this); - } - - @Override - public void onRefresh() { - binding.posts.refresh(); - } - - @Override - public void onStop() { - super.onStop(); - fragmentActivity.resetToolbar(this); - } - - private void init() { - if (getArguments() == null) return; - final TopicPostsFragmentArgs fragmentArgs = TopicPostsFragmentArgs.fromBundle(getArguments()); - topicCluster = fragmentArgs.getTopicCluster(); - setupToolbar(fragmentArgs.getTitleColor(), fragmentArgs.getBackgroundColor()); - setupPosts(); - } - - private void setupToolbar(final int titleColor, final int backgroundColor) { - if (topicCluster == null) { - return; - } - binding.cover.setTransitionName("cover-" + topicCluster.getId()); - fragmentActivity.setToolbar(binding.toolbar, this); - binding.collapsingToolbarLayout.setTitle(topicCluster.getTitle()); - final int collapsedTitleTextColor = ColorUtils.setAlphaComponent(titleColor, 0xFF); - final int expandedTitleTextColor = ColorUtils.setAlphaComponent(titleColor, 0x99); - binding.collapsingToolbarLayout.setExpandedTitleColor(expandedTitleTextColor); - binding.collapsingToolbarLayout.setCollapsedTitleTextColor(collapsedTitleTextColor); - binding.collapsingToolbarLayout.setContentScrimColor(backgroundColor); - final Drawable navigationIcon = binding.toolbar.getNavigationIcon(); - final Drawable overflowIcon = binding.toolbar.getOverflowIcon(); - if (navigationIcon != null && overflowIcon != null) { - final Drawable navDrawable = navigationIcon.mutate(); - final Drawable overflowDrawable = overflowIcon.mutate(); - navDrawable.setAlpha(0xFF); - overflowDrawable.setAlpha(0xFF); - final ArgbEvaluator argbEvaluator = new ArgbEvaluator(); - binding.appBarLayout.addOnOffsetChangedListener((appBarLayout, verticalOffset) -> { - final int totalScrollRange = appBarLayout.getTotalScrollRange(); - final float current = totalScrollRange + verticalOffset; - final float fraction = current / totalScrollRange; - final int tempColor = (int) argbEvaluator.evaluate(fraction, collapsedTitleTextColor, expandedTitleTextColor); - navDrawable.setColorFilter(tempColor, PorterDuff.Mode.SRC_ATOP); - overflowDrawable.setColorFilter(tempColor, PorterDuff.Mode.SRC_ATOP); - - }); - } - final GradientDrawable gd = new GradientDrawable( - GradientDrawable.Orientation.TOP_BOTTOM, - new int[]{Color.TRANSPARENT, backgroundColor}); - binding.background.setBackground(gd); - setupCover(); - } - - private void setupCover() { - final String coverUrl = ResponseBodyUtils.getImageUrl(topicCluster.getCoverMedia()); - final DraweeController controller = Fresco - .newDraweeControllerBuilder() - .setOldController(binding.cover.getController()) - .setUri(coverUrl) - .setControllerListener(new BaseControllerListener() { - - @Override - public void onFailure(final String id, final Throwable throwable) { - super.onFailure(id, throwable); - startPostponedEnterTransition(); - } - - @Override - public void onFinalImageSet(final String id, - @Nullable final ImageInfo imageInfo, - @Nullable final Animatable animatable) { - startPostponedEnterTransition(); - } - }) - .build(); - binding.cover.setController(controller); - } - - private void setupPosts() { - final DiscoverService.TopicalExploreRequest topicalExploreRequest = new DiscoverService.TopicalExploreRequest(); - topicalExploreRequest.setClusterId(topicCluster.getId()); - binding.posts.setViewModelStoreOwner(this) - .setLifeCycleOwner(this) - .setPostFetchService(new DiscoverPostFetchService(topicalExploreRequest)) - .setLayoutPreferences(layoutPreferences) - .addFetchStatusChangeListener(fetching -> updateSwipeRefreshState()) - .setFeedItemCallback(feedItemCallback) - .setSelectionModeCallback(selectionModeCallback) - .init(); - binding.swipeRefreshLayout.setRefreshing(true); - } - - private void updateSwipeRefreshState() { - AppExecutors.INSTANCE.getMainThread().execute(() -> binding.swipeRefreshLayout.setRefreshing(binding.posts.isFetching()) - ); - } - - private void navigateToProfile(final String username) { - try { - final NavDirections action = TopicPostsFragmentDirections.actionToProfile().setUsername(username); - NavHostFragment.findNavController(this).navigate(action); - } catch (Exception e) { - Log.e(TAG, "navigateToProfile: ", e); - } - } - - private void showPostsLayoutPreferences() { - final PostsLayoutPreferencesDialogFragment fragment = new PostsLayoutPreferencesDialogFragment( - Constants.PREF_TOPIC_POSTS_LAYOUT, - preferences -> { - layoutPreferences = preferences; - new Handler().postDelayed(() -> binding.posts.setLayoutPreferences(preferences), 200); - }); - fragment.show(getChildFragmentManager(), "posts_layout_preferences"); - } -} diff --git a/app/src/main/java/awais/instagrabber/fragments/main/DiscoverFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/DiscoverFragment.java index 1f832c6b..49c0a5b7 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/DiscoverFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/DiscoverFragment.java @@ -1,75 +1,235 @@ package awais.instagrabber.fragments.main; +import android.content.Context; import android.os.Bundle; +import android.os.Handler; import android.util.Log; +import android.view.ActionMode; import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import android.widget.Toast; +import androidx.activity.OnBackPressedCallback; +import androidx.activity.OnBackPressedDispatcher; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.appcompat.app.AlertDialog; -import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.appcompat.app.ActionBar; import androidx.fragment.app.Fragment; -import androidx.lifecycle.ViewModelProvider; import androidx.navigation.NavDirections; -import androidx.navigation.fragment.FragmentNavigator; import androidx.navigation.fragment.NavHostFragment; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; -import java.util.Collections; -import java.util.List; +import com.google.common.collect.ImmutableList; + +import java.util.Set; import awais.instagrabber.R; import awais.instagrabber.activities.MainActivity; -import awais.instagrabber.adapters.DiscoverTopicsAdapter; -import awais.instagrabber.customviews.helpers.GridSpacingItemDecoration; +import awais.instagrabber.adapters.FeedAdapterV2; +import awais.instagrabber.asyncs.DiscoverPostFetchService; +import awais.instagrabber.customviews.PrimaryActionModeCallback; import awais.instagrabber.databinding.FragmentDiscoverBinding; +import awais.instagrabber.dialogs.PostsLayoutPreferencesDialogFragment; +import awais.instagrabber.models.PostsLayoutPreferences; +import awais.instagrabber.models.enums.PostItemType; +import awais.instagrabber.repositories.responses.Location; import awais.instagrabber.repositories.responses.Media; -import awais.instagrabber.repositories.responses.discover.TopicCluster; -import awais.instagrabber.repositories.responses.discover.TopicalExploreFeedResponse; +import awais.instagrabber.repositories.responses.User; import awais.instagrabber.utils.AppExecutors; -import awais.instagrabber.utils.CoroutineUtilsKt; +import awais.instagrabber.utils.Constants; +import awais.instagrabber.utils.CookieUtils; +import awais.instagrabber.utils.DownloadUtils; +import awais.instagrabber.utils.TextUtils; import awais.instagrabber.utils.Utils; -import awais.instagrabber.viewmodels.TopicClusterViewModel; import awais.instagrabber.webservices.DiscoverService; -import awais.instagrabber.webservices.MediaRepository; -import awais.instagrabber.webservices.ServiceCallback; -import kotlinx.coroutines.Dispatchers; + +import static awais.instagrabber.utils.Utils.settingsHelper; public class DiscoverFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener { private static final String TAG = "DiscoverFragment"; private MainActivity fragmentActivity; - private CoordinatorLayout root; + private SwipeRefreshLayout root; private FragmentDiscoverBinding binding; - private TopicClusterViewModel topicClusterViewModel; - private boolean shouldRefresh = true; - private DiscoverService discoverService; - private MediaRepository mediaRepository; + private ActionMode actionMode; + private boolean isLoggedIn, shouldRefresh = true; + private String keyword; + private Set selectedFeedModels; + private PostsLayoutPreferences layoutPreferences = Utils.getPostsLayoutPreferences(Constants.PREF_TOPIC_POSTS_LAYOUT); + + private final OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(false) { + @Override + public void handleOnBackPressed() { + binding.posts.endSelection(); + } + }; + private final PrimaryActionModeCallback multiSelectAction = new PrimaryActionModeCallback( + R.menu.multi_select_download_menu, + new PrimaryActionModeCallback.CallbacksHelper() { + @Override + public void onDestroy(final ActionMode mode) { + binding.posts.endSelection(); + } + + @Override + public boolean onActionItemClicked(final ActionMode mode, final MenuItem item) { + if (item.getItemId() == R.id.action_download) { + if (selectedFeedModels == null) return false; + final Context context = getContext(); + if (context == null) return false; + DownloadUtils.download(context, ImmutableList.copyOf(DiscoverFragment.this.selectedFeedModels)); + binding.posts.endSelection(); + } + return false; + } + }); + private final FeedAdapterV2.FeedItemCallback feedItemCallback = new FeedAdapterV2.FeedItemCallback() { + @Override + public void onPostClick(final Media feedModel) { + openPostDialog(feedModel, -1); + } + + @Override + public void onSliderClick(final Media feedModel, final int position) { + openPostDialog(feedModel, position); + } + + @Override + public void onCommentsClick(final Media feedModel) { + final User user = feedModel.getUser(); + if (user == null) return; + try { + final NavDirections commentsAction = ProfileFragmentDirections.actionToComments( + feedModel.getCode(), + feedModel.getPk(), + user.getPk() + ); + NavHostFragment.findNavController(DiscoverFragment.this).navigate(commentsAction); + } catch (Exception e) { + Log.e(TAG, "onCommentsClick: ", e); + } + } + + @Override + public void onDownloadClick(final Media feedModel, final int childPosition, final View popupLocation) { + final Context context = getContext(); + if (context == null) return; + DownloadUtils.showDownloadDialog(context, feedModel, childPosition, popupLocation); + } + + @Override + public void onHashtagClick(final String hashtag) { + try { + final NavDirections action = ProfileFragmentDirections.actionToHashtag(hashtag); + NavHostFragment.findNavController(DiscoverFragment.this).navigate(action); + } catch (Exception e) { + Log.e(TAG, "onHashtagClick: ", e); + } + } + + @Override + public void onLocationClick(final Media feedModel) { + final Location location = feedModel.getLocation(); + if (location == null) return; + try { + final NavDirections action = ProfileFragmentDirections.actionToLocation(location.getPk()); + NavHostFragment.findNavController(DiscoverFragment.this).navigate(action); + } catch (Exception e) { + Log.e(TAG, "onLocationClick: ", e); + } + } + + @Override + public void onMentionClick(final String mention) { + navigateToProfile(mention.trim()); + } + + @Override + public void onNameClick(final Media feedModel) { + navigateToProfile("@" + feedModel.getUser().getUsername()); + } + + @Override + public void onProfilePicClick(final Media feedModel) { + final User user = feedModel.getUser(); + if (user == null) return; + navigateToProfile("@" + user.getUsername()); + } + + @Override + public void onURLClick(final String url) { + Utils.openURL(getContext(), url); + } + + @Override + public void onEmailClick(final String emailId) { + Utils.openEmailAddress(getContext(), emailId); + } + + private void openPostDialog(final Media feedModel, final int position) { + try { + final NavDirections action = DiscoverFragmentDirections.actionToPost(feedModel, position); + NavHostFragment.findNavController(DiscoverFragment.this).navigate(action); + } catch (Exception e) { + Log.e(TAG, "openPostDialog: ", e); + } + } + }; + private final FeedAdapterV2.SelectionModeCallback selectionModeCallback = new FeedAdapterV2.SelectionModeCallback() { + + @Override + public void onSelectionStart() { + if (!onBackPressedCallback.isEnabled()) { + final OnBackPressedDispatcher onBackPressedDispatcher = fragmentActivity.getOnBackPressedDispatcher(); + onBackPressedCallback.setEnabled(true); + onBackPressedDispatcher.addCallback(getViewLifecycleOwner(), onBackPressedCallback); + } + if (actionMode == null) { + actionMode = fragmentActivity.startActionMode(multiSelectAction); + } + } + + @Override + public void onSelectionChange(final Set selectedFeedModels) { + final String title = getString(R.string.number_selected, selectedFeedModels.size()); + if (actionMode != null) { + actionMode.setTitle(title); + } + DiscoverFragment.this.selectedFeedModels = selectedFeedModels; + } + + @Override + public void onSelectionEnd() { + if (onBackPressedCallback.isEnabled()) { + onBackPressedCallback.setEnabled(false); + onBackPressedCallback.remove(); + } + if (actionMode != null) { + actionMode.finish(); + actionMode = null; + } + } + }; @Override public void onCreate(@Nullable final Bundle savedInstanceState) { super.onCreate(savedInstanceState); - fragmentActivity = (MainActivity) requireActivity(); - discoverService = DiscoverService.getInstance(); - // final String deviceUuid = Utils.settingsHelper.getString(Constants.DEVICE_UUID); - // final String cookie = Utils.settingsHelper.getString(Constants.COOKIE); - // final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie); - // final long userId = CookieUtils.getUserIdFromCookie(cookie); - mediaRepository = MediaRepository.Companion.getInstance(); + fragmentActivity = (MainActivity) getActivity(); + setHasOptionsMenu(true); } @Override - public View onCreateView(@NonNull final LayoutInflater inflater, - final ViewGroup container, - final Bundle savedInstanceState) { + public View onCreateView(@NonNull final LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable final Bundle savedInstanceState) { + final String cookie = settingsHelper.getString(Constants.COOKIE); + isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) > 0; if (root != null) { shouldRefresh = false; return root; } - binding = FragmentDiscoverBinding.inflate(inflater, container, false); + binding = FragmentDiscoverBinding.inflate(getLayoutInflater(), container, false); root = binding.getRoot(); return root; } @@ -82,92 +242,67 @@ public class DiscoverFragment extends Fragment implements SwipeRefreshLayout.OnR shouldRefresh = false; } - private void init() { - setupTopics(); - fetchTopics(); + @Override + public void onCreateOptionsMenu(@NonNull final Menu menu, @NonNull final MenuInflater inflater) { + inflater.inflate(R.menu.saved_viewer_menu, menu); + } + + @Override + public boolean onOptionsItemSelected(@NonNull final MenuItem item) { + if (item.getItemId() == R.id.layout) { + showPostsLayoutPreferences(); + return true; + } + return super.onOptionsItemSelected(item); } @Override public void onRefresh() { - fetchTopics(); + binding.posts.refresh(); } - public void setupTopics() { - topicClusterViewModel = new ViewModelProvider(fragmentActivity).get(TopicClusterViewModel.class); - binding.topicsRecyclerView.addItemDecoration(new GridSpacingItemDecoration(Utils.convertDpToPx(2))); - final DiscoverTopicsAdapter.OnTopicClickListener otcl = new DiscoverTopicsAdapter.OnTopicClickListener() { - public void onTopicClick(final TopicCluster topicCluster, final View cover, final int titleColor, final int backgroundColor) { - try { - final FragmentNavigator.Extras.Builder builder = new FragmentNavigator.Extras.Builder() - .addSharedElement(cover, "cover-" + topicCluster.getId()); - final NavDirections action = DiscoverFragmentDirections.actionToTopicPosts(topicCluster, titleColor, backgroundColor); - NavHostFragment.findNavController(DiscoverFragment.this).navigate(action, builder.build()); - } catch (Exception e) { - Log.e(TAG, "onTopicClick: ", e); - } - } - - public void onTopicLongClick(final Media coverMedia) { - final AlertDialog alertDialog = new AlertDialog.Builder(requireContext()) - .setCancelable(false) - .setView(R.layout.dialog_opening_post) - .create(); - alertDialog.show(); - final String pk = coverMedia.getPk(); - if (pk == null) return; - mediaRepository.fetch( - Long.parseLong(pk), - CoroutineUtilsKt.getContinuation((media, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> { - if (throwable != null) { - alertDialog.dismiss(); - try { - Toast.makeText(requireContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); - } catch (Throwable ignored) {} - return; - } - try { - final NavDirections action = DiscoverFragmentDirections.actionToPost(media, 0); - NavHostFragment.findNavController(DiscoverFragment.this).navigate(action); - alertDialog.dismiss(); - } catch (Exception e) { - Log.e(TAG, "onTopicLongClick: ", e); - } - }), Dispatchers.getIO()) - ); - } - }; - final DiscoverTopicsAdapter adapter = new DiscoverTopicsAdapter(otcl); - binding.topicsRecyclerView.setAdapter(adapter); - topicClusterViewModel.getList().observe(getViewLifecycleOwner(), adapter::submitList); + private void init() { + final Bundle arguments = getArguments(); + if (arguments == null) return; + final DiscoverFragmentArgs fragmentArgs = DiscoverFragmentArgs.fromBundle(arguments); + keyword = fragmentArgs.getKeyword(); + setupPosts(); } - private void fetchTopics() { + private void setupPosts() { + binding.posts.setViewModelStoreOwner(this) + .setLifeCycleOwner(this) + .setPostFetchService(new DiscoverPostFetchService(new DiscoverService.TopicalExploreRequest())) + .setLayoutPreferences(layoutPreferences) + .addFetchStatusChangeListener(fetching -> updateSwipeRefreshState()) + .setFeedItemCallback(feedItemCallback) + .setSelectionModeCallback(selectionModeCallback) + .init(); binding.swipeRefreshLayout.setRefreshing(true); - discoverService.topicalExplore(new DiscoverService.TopicalExploreRequest(), new ServiceCallback() { - @Override - public void onSuccess(final TopicalExploreFeedResponse result) { - if (result == null) return; - final List clusters = result.getClusters(); - if (clusters == null || result.getItems() == null) return; - binding.swipeRefreshLayout.setRefreshing(false); - if (clusters.size() == 1 && result.getItems().size() > 0) { - final TopicCluster cluster = clusters.get(0); - if (cluster.getCoverMedia() == null) { - cluster.setCoverMedia(result.getItems().get(0).getMedia()); - } - topicClusterViewModel.getList().postValue(Collections.singletonList(cluster)); - return; - } - if (clusters.size() > 1 || result.getItems().size() == 0) { - topicClusterViewModel.getList().postValue(clusters); - } - } - - @Override - public void onFailure(final Throwable t) { - Log.e(TAG, "onFailure", t); - binding.swipeRefreshLayout.setRefreshing(false); - } - }); } -} + + private void updateSwipeRefreshState() { + AppExecutors.INSTANCE.getMainThread().execute(() -> + binding.swipeRefreshLayout.setRefreshing(binding.posts.isFetching()) + ); + } + + private void navigateToProfile(final String username) { + try { + final NavDirections action = DiscoverFragmentDirections.actionToProfile().setUsername(username); + NavHostFragment.findNavController(this).navigate(action); + } catch (Exception e) { + Log.e(TAG, "navigateToProfile: ", e); + } + } + + private void showPostsLayoutPreferences() { + final PostsLayoutPreferencesDialogFragment fragment = new PostsLayoutPreferencesDialogFragment( + Constants.PREF_TOPIC_POSTS_LAYOUT, + preferences -> { + layoutPreferences = preferences; + new Handler().postDelayed(() -> binding.posts.setLayoutPreferences(preferences), 200); + }); + fragment.show(getChildFragmentManager(), "posts_layout_preferences"); + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_discover.xml b/app/src/main/res/layout/fragment_discover.xml index ff29514e..4b233deb 100644 --- a/app/src/main/res/layout/fragment_discover.xml +++ b/app/src/main/res/layout/fragment_discover.xml @@ -1,27 +1,16 @@ - + app:layout_behavior="@string/appbar_scrolling_view_behavior" + tools:context=".fragments.DiscoverFragment"> - - - - - \ No newline at end of file + android:clipToPadding="false" /> + diff --git a/app/src/main/res/navigation/discover_nav_graph.xml b/app/src/main/res/navigation/discover_nav_graph.xml index cd2c844e..5122cb8e 100644 --- a/app/src/main/res/navigation/discover_nav_graph.xml +++ b/app/src/main/res/navigation/discover_nav_graph.xml @@ -11,9 +11,27 @@ android:label="@string/title_discover" tools:layout="@layout/fragment_discover"> + + + android:id="@+id/action_to_comments" + app:destination="@id/commentsViewerFragment" /> + + + + + + - - - - - - - - - - - - - - - - - - -