From 96da16ff84b131c5a1f7653d4ae4c57885cebe51 Mon Sep 17 00:00:00 2001 From: Ammar Githam Date: Fri, 7 May 2021 20:34:31 +0900 Subject: [PATCH] Convert Post view to a regular fragment instead of dialog. Added global fragment animations too --- .../instagrabber/activities/MainActivity.java | 33 +- ...ragmentNavigatorWithDefaultAnimations.java | 75 ++ .../NavHostFragmentWithDefaultAnimations.java | 60 ++ .../customviews/PostsRecyclerView.java | 29 +- .../drawee/ZoomableDraweeView.java | 2 +- .../helpers/GridSpacingItemDecoration.java | 19 +- .../fragments/CollectionPostsFragment.java | 112 +-- .../fragments/HashTagFragment.java | 122 +-- .../fragments/LocationFragment.java | 52 +- .../NotificationsViewerFragment.java | 18 +- .../fragments/PostViewV2Fragment.java | 536 +++------- .../fragments/SavedViewerFragment.java | 19 +- .../fragments/StoryViewerFragment.java | 38 +- .../fragments/TopicPostsFragment.java | 21 +- .../DirectMessageThreadFragment.java | 26 +- .../fragments/main/FeedFragment.java | 50 +- .../fragments/main/ProfileFragment.java | 55 +- .../utils/NavigationExtensions.java | 3 +- .../java/awais/instagrabber/utils/Utils.java | 6 + .../interceptors/IgErrorsInterceptor.java | 1 + app/src/main/res/anim/slide_in_right.xml | 11 + app/src/main/res/anim/slide_left.xml | 13 +- app/src/main/res/anim/slide_out_left.xml | 11 + app/src/main/res/anim/slide_right.xml | 13 +- .../main/res/drawable/ic_round_edit_24.xml | 10 + .../main/res/drawable/shape_oval_light.xml | 2 +- app/src/main/res/layout/dialog_post_view.xml | 927 +++++++++--------- app/src/main/res/layout/fragment_feed.xml | 45 +- app/src/main/res/layout/fragment_hashtag.xml | 24 +- app/src/main/res/layout/fragment_location.xml | 24 +- app/src/main/res/layout/fragment_profile.xml | 37 +- app/src/main/res/layout/item_highlight.xml | 1 + .../res/layout/layout_exo_custom_controls.xml | 75 +- .../res/layout/layout_hashtag_details.xml | 3 +- .../res/layout/layout_location_details.xml | 35 +- .../res/layout/layout_profile_details.xml | 7 +- .../layout_video_player_with_thumbnail.xml | 18 +- .../main/res/menu/collection_posts_menu.xml | 8 +- .../navigation/direct_messages_nav_graph.xml | 18 +- .../res/navigation/discover_nav_graph.xml | 17 + .../main/res/navigation/feed_nav_graph.xml | 17 + .../main/res/navigation/hashtag_nav_graph.xml | 17 + .../res/navigation/location_nav_graph.xml | 17 + .../notification_viewer_nav_graph.xml | 17 + .../main/res/navigation/profile_nav_graph.xml | 21 +- .../main/res/navigation/saved_nav_graph.xml | 23 +- app/src/main/res/values/drawables.xml | 5 + app/src/main/res/xml/header_list_scene.xml | 32 + 48 files changed, 1401 insertions(+), 1324 deletions(-) create mode 100644 app/src/main/java/awais/instagrabber/customviews/FragmentNavigatorWithDefaultAnimations.java create mode 100644 app/src/main/java/awais/instagrabber/customviews/NavHostFragmentWithDefaultAnimations.java create mode 100644 app/src/main/res/anim/slide_in_right.xml create mode 100644 app/src/main/res/anim/slide_out_left.xml create mode 100644 app/src/main/res/drawable/ic_round_edit_24.xml create mode 100644 app/src/main/res/values/drawables.xml create mode 100644 app/src/main/res/xml/header_list_scene.xml diff --git a/app/src/main/java/awais/instagrabber/activities/MainActivity.java b/app/src/main/java/awais/instagrabber/activities/MainActivity.java index deeeb232..36e02a8a 100644 --- a/app/src/main/java/awais/instagrabber/activities/MainActivity.java +++ b/app/src/main/java/awais/instagrabber/activities/MainActivity.java @@ -651,7 +651,11 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage if (navController == null) return; final Bundle bundle = new Bundle(); bundle.putString("username", "@" + username); - navController.navigate(R.id.action_global_profileFragment, bundle); + try { + navController.navigate(R.id.action_global_profileFragment, bundle); + } catch (Exception e) { + Log.e(TAG, "showProfileView: ", e); + } } private void showPostView(@NonNull final IntentModel intentModel) { @@ -664,11 +668,16 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage alertDialog.show(); new PostFetcher(shortCode, feedModel -> { if (feedModel != null) { - final PostViewV2Fragment fragment = PostViewV2Fragment - .builder(feedModel) - .build(); - fragment.setOnShowListener(dialog -> alertDialog.dismiss()); - fragment.show(getSupportFragmentManager(), "post_view"); + if (currentNavControllerLiveData == null) return; + final NavController navController = currentNavControllerLiveData.getValue(); + if (navController == null) return; + final Bundle bundle = new Bundle(); + bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, feedModel); + try { + navController.navigate(R.id.action_global_post_view, bundle); + } catch (Exception e) { + Log.e(TAG, "showPostView: ", e); + } return; } Toast.makeText(getApplicationContext(), R.string.post_not_found, Toast.LENGTH_SHORT).show(); @@ -724,11 +733,19 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage } public void setCollapsingView(@NonNull final View view) { - binding.collapsingToolbarLayout.addView(view, 0); + try { + binding.collapsingToolbarLayout.addView(view, 0); + } catch (Exception e) { + Log.e(TAG, "setCollapsingView: ", e); + } } public void removeCollapsingView(@NonNull final View view) { - binding.collapsingToolbarLayout.removeView(view); + try { + binding.collapsingToolbarLayout.removeView(view); + } catch (Exception e) { + Log.e(TAG, "removeCollapsingView: ", e); + } } public void setToolbar(final Toolbar toolbar) { diff --git a/app/src/main/java/awais/instagrabber/customviews/FragmentNavigatorWithDefaultAnimations.java b/app/src/main/java/awais/instagrabber/customviews/FragmentNavigatorWithDefaultAnimations.java new file mode 100644 index 00000000..358e34d8 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/customviews/FragmentNavigatorWithDefaultAnimations.java @@ -0,0 +1,75 @@ +package awais.instagrabber.customviews; + +import android.content.Context; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.FragmentManager; +import androidx.navigation.NavDestination; +import androidx.navigation.NavOptions; +import androidx.navigation.Navigator; +import androidx.navigation.fragment.FragmentNavigator; + +import awais.instagrabber.R; + +@Navigator.Name("fragment") +public class FragmentNavigatorWithDefaultAnimations extends FragmentNavigator { + + private final NavOptions emptyNavOptions = new NavOptions.Builder().build(); + // private final NavOptions defaultNavOptions = new NavOptions.Builder() + // .setEnterAnim(R.animator.nav_default_enter_anim) + // .setExitAnim(R.animator.nav_default_exit_anim) + // .setPopEnterAnim(R.animator.nav_default_pop_enter_anim) + // .setPopExitAnim(R.animator.nav_default_pop_exit_anim) + // .build(); + + private final NavOptions defaultNavOptions = new NavOptions.Builder() + .setEnterAnim(R.anim.slide_in_right) + .setExitAnim(R.anim.slide_out_left) + .setPopEnterAnim(android.R.anim.slide_in_left) + .setPopExitAnim(android.R.anim.slide_out_right) + .build(); + + public FragmentNavigatorWithDefaultAnimations(@NonNull final Context context, + @NonNull final FragmentManager manager, + final int containerId) { + super(context, manager, containerId); + } + + @Nullable + @Override + public NavDestination navigate(@NonNull final Destination destination, + @Nullable final Bundle args, + @Nullable final NavOptions navOptions, + @Nullable final Navigator.Extras navigatorExtras) { + // this will try to fill in empty animations with defaults when no shared element transitions are set + // https://developer.android.com/guide/navigation/navigation-animate-transitions#shared-element + final boolean shouldUseTransitionsInstead = navigatorExtras != null; + final NavOptions navOptions1 = shouldUseTransitionsInstead ? navOptions : fillEmptyAnimationsWithDefaults(navOptions); + return super.navigate(destination, args, navOptions1, navigatorExtras); + } + + private NavOptions fillEmptyAnimationsWithDefaults(@Nullable final NavOptions navOptions) { + if (navOptions == null) { + return defaultNavOptions; + } + return copyNavOptionsWithDefaultAnimations(navOptions); + } + + @NonNull + private NavOptions copyNavOptionsWithDefaultAnimations(@NonNull final NavOptions navOptions) { + return new NavOptions.Builder() + .setLaunchSingleTop(navOptions.shouldLaunchSingleTop()) + .setPopUpTo(navOptions.getPopUpTo(), navOptions.isPopUpToInclusive()) + .setEnterAnim(navOptions.getEnterAnim() == emptyNavOptions.getEnterAnim() + ? defaultNavOptions.getEnterAnim() : navOptions.getEnterAnim()) + .setExitAnim(navOptions.getExitAnim() == emptyNavOptions.getExitAnim() + ? defaultNavOptions.getExitAnim() : navOptions.getExitAnim()) + .setPopEnterAnim(navOptions.getPopEnterAnim() == emptyNavOptions.getPopEnterAnim() + ? defaultNavOptions.getPopEnterAnim() : navOptions.getPopEnterAnim()) + .setPopExitAnim(navOptions.getPopExitAnim() == emptyNavOptions.getPopExitAnim() + ? defaultNavOptions.getPopExitAnim() : navOptions.getPopExitAnim()) + .build(); + } +} diff --git a/app/src/main/java/awais/instagrabber/customviews/NavHostFragmentWithDefaultAnimations.java b/app/src/main/java/awais/instagrabber/customviews/NavHostFragmentWithDefaultAnimations.java new file mode 100644 index 00000000..11621a6c --- /dev/null +++ b/app/src/main/java/awais/instagrabber/customviews/NavHostFragmentWithDefaultAnimations.java @@ -0,0 +1,60 @@ +package awais.instagrabber.customviews; + +import android.os.Bundle; + +import androidx.annotation.NavigationRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.navigation.NavController; +import androidx.navigation.Navigator; +import androidx.navigation.fragment.FragmentNavigator; +import androidx.navigation.fragment.NavHostFragment; + +public class NavHostFragmentWithDefaultAnimations extends NavHostFragment { + private static final String KEY_GRAPH_ID = "android-support-nav:fragment:graphId"; + private static final String KEY_START_DESTINATION_ARGS = + "android-support-nav:fragment:startDestinationArgs"; + private static final String KEY_NAV_CONTROLLER_STATE = + "android-support-nav:fragment:navControllerState"; + private static final String KEY_DEFAULT_NAV_HOST = "android-support-nav:fragment:defaultHost"; + + @NonNull + public static NavHostFragment create(@NavigationRes int graphResId) { + return create(graphResId, null); + } + + @NonNull + public static NavHostFragment create(@NavigationRes int graphResId, + @Nullable Bundle startDestinationArgs) { + Bundle b = null; + if (graphResId != 0) { + b = new Bundle(); + b.putInt(KEY_GRAPH_ID, graphResId); + } + if (startDestinationArgs != null) { + if (b == null) { + b = new Bundle(); + } + b.putBundle(KEY_START_DESTINATION_ARGS, startDestinationArgs); + } + + final NavHostFragmentWithDefaultAnimations result = new NavHostFragmentWithDefaultAnimations(); + if (b != null) { + result.setArguments(b); + } + return result; + } + + @NonNull + @Override + protected Navigator createFragmentNavigator() { + return new FragmentNavigatorWithDefaultAnimations(requireContext(), getChildFragmentManager(), getId()); + } + + @Override + protected void onCreateNavController(@NonNull final NavController navController) { + super.onCreateNavController(navController); + navController.getNavigatorProvider() + .addNavigator(new FragmentNavigatorWithDefaultAnimations(requireContext(), getChildFragmentManager(), getId())); + } +} diff --git a/app/src/main/java/awais/instagrabber/customviews/PostsRecyclerView.java b/app/src/main/java/awais/instagrabber/customviews/PostsRecyclerView.java index f01a5528..2e008a18 100644 --- a/app/src/main/java/awais/instagrabber/customviews/PostsRecyclerView.java +++ b/app/src/main/java/awais/instagrabber/customviews/PostsRecyclerView.java @@ -3,6 +3,8 @@ package awais.instagrabber.customviews; import android.content.Context; import android.util.AttributeSet; import android.util.Log; +import android.view.View; +import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -25,6 +27,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.function.Function; import awais.instagrabber.adapters.FeedAdapterV2; import awais.instagrabber.customviews.helpers.GridSpacingItemDecoration; @@ -60,14 +63,17 @@ public class PostsRecyclerView extends RecyclerView { private FeedAdapterV2.FeedItemCallback feedItemCallback; private boolean shouldScrollToTop; private FeedAdapterV2.SelectionModeCallback selectionModeCallback; + private Function headerViewCreator; + private Function headerBinder; + private boolean refresh = true; private final List fetchStatusChangeListeners = new ArrayList<>(); private final FetchListener> fetchListener = new FetchListener>() { @Override public void onResult(final List result) { - final int currentPage = lazyLoader.getCurrentPage(); - if (currentPage == 0) { + if (refresh) { + refresh = false; mediaViewModel.getList().postValue(result); shouldScrollToTop = true; dispatchFetchStatus(); @@ -198,21 +204,19 @@ public class PostsRecyclerView extends RecyclerView { Log.e(TAG, "initSelf: ", e); } if (mediaViewModel == null) return; - mediaViewModel.getList().observe(lifeCycleOwner, list -> { - if (list.size() <= 0) return; - feedAdapter.submitList(list, () -> { - // postDelayed(this::fetchMoreIfPossible, 1000); - if (!shouldScrollToTop) return; - smoothScrollToPosition(0); - shouldScrollToTop = false; - }); - }); + mediaViewModel.getList().observe(lifeCycleOwner, list -> feedAdapter.submitList(list, () -> { + // postDelayed(this::fetchMoreIfPossible, 1000); + if (!shouldScrollToTop) return; + shouldScrollToTop = false; + post(() -> smoothScrollToPosition(0)); + })); postFetcher = new PostFetcher(postFetchService, fetchListener); if (layoutPreferences.getHasGap()) { addItemDecoration(gridSpacingItemDecoration); } setHasFixedSize(true); setNestedScrollingEnabled(true); + setItemAnimator(null); lazyLoader = new RecyclerLazyLoaderAtEdge(layoutManager, (page) -> { if (postFetcher.hasMore()) { postFetcher.fetch(); @@ -316,11 +320,12 @@ public class PostsRecyclerView extends RecyclerView { } public void refresh() { + refresh = true; if (lazyLoader != null) { lazyLoader.resetState(); } if (postFetcher != null) { - mediaViewModel.getList().postValue(Collections.emptyList()); + // mediaViewModel.getList().postValue(Collections.emptyList()); postFetcher.reset(); postFetcher.fetch(); } diff --git a/app/src/main/java/awais/instagrabber/customviews/drawee/ZoomableDraweeView.java b/app/src/main/java/awais/instagrabber/customviews/drawee/ZoomableDraweeView.java index 5a7d55ad..d8b7b8f9 100644 --- a/app/src/main/java/awais/instagrabber/customviews/drawee/ZoomableDraweeView.java +++ b/app/src/main/java/awais/instagrabber/customviews/drawee/ZoomableDraweeView.java @@ -228,7 +228,7 @@ public class ZoomableDraweeView extends DraweeView public void setZoomingEnabled(boolean zoomingEnabled) { mZoomingEnabled = zoomingEnabled; - mZoomableController.setEnabled(false); + mZoomableController.setEnabled(zoomingEnabled); } /** diff --git a/app/src/main/java/awais/instagrabber/customviews/helpers/GridSpacingItemDecoration.java b/app/src/main/java/awais/instagrabber/customviews/helpers/GridSpacingItemDecoration.java index 81b4be92..f34c30f5 100755 --- a/app/src/main/java/awais/instagrabber/customviews/helpers/GridSpacingItemDecoration.java +++ b/app/src/main/java/awais/instagrabber/customviews/helpers/GridSpacingItemDecoration.java @@ -7,17 +7,24 @@ import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration { - private final int spacing; + private final int halfSpace; + + private boolean hasHeader; public GridSpacingItemDecoration(int spacing) { - this.spacing = spacing; + halfSpace = spacing / 2; } @Override public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { - final int halfSpace = spacing / 2; + if (hasHeader && parent.getChildAdapterPosition(view) == 0) { + outRect.bottom = halfSpace; + outRect.left = -halfSpace; + outRect.right = -halfSpace; + return; + } if (parent.getPaddingLeft() != halfSpace) { - parent.setPadding(halfSpace, halfSpace, halfSpace, halfSpace); + parent.setPadding(halfSpace, hasHeader ? 0 : halfSpace, halfSpace, halfSpace); parent.setClipToPadding(false); } outRect.top = halfSpace; @@ -25,4 +32,8 @@ public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration { outRect.left = halfSpace; outRect.right = halfSpace; } + + public void setHasHeader(final boolean hasHeader) { + this.hasHeader = hasHeader; + } } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/fragments/CollectionPostsFragment.java b/app/src/main/java/awais/instagrabber/fragments/CollectionPostsFragment.java index 9a850045..1ca49c15 100644 --- a/app/src/main/java/awais/instagrabber/fragments/CollectionPostsFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/CollectionPostsFragment.java @@ -190,16 +190,15 @@ public class CollectionPostsFragment extends Fragment implements SwipeRefreshLay final View profilePicView, final View mainPostImage, final int position) { - final PostViewV2Fragment.Builder builder = PostViewV2Fragment - .builder(feedModel); - if (position >= 0) { - builder.setPosition(position); + final NavController navController = NavHostFragment.findNavController(CollectionPostsFragment.this); + final Bundle bundle = new Bundle(); + bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, feedModel); + bundle.putInt(PostViewV2Fragment.ARG_SLIDER_POSITION, position); + try { + navController.navigate(R.id.action_global_post_view, bundle); + } catch (Exception e) { + Log.e(TAG, "openPostDialog: ", e); } - if (!layoutPreferences.isAnimationDisabled()) { - builder.setSharedProfilePicElement(profilePicView) - .setSharedMainPostElement(mainPostImage); - } - builder.build().show(getChildFragmentManager(), "post_view"); } }; private final FeedAdapterV2.SelectionModeCallback selectionModeCallback = new FeedAdapterV2.SelectionModeCallback() { @@ -243,8 +242,10 @@ public class CollectionPostsFragment extends Fragment implements SwipeRefreshLay super.onCreate(savedInstanceState); fragmentActivity = (MainActivity) requireActivity(); final TransitionSet transitionSet = new TransitionSet(); + final Context context = getContext(); + if (context == null) return; transitionSet.addTransition(new ChangeBounds()) - .addTransition(TransitionInflater.from(getContext()).inflateTransition(android.R.transition.move)) + .addTransition(TransitionInflater.from(context).inflateTransition(android.R.transition.move)) .setDuration(200); setSharedElementEnterTransition(transitionSet); postponeEnterTransition(); @@ -280,7 +281,8 @@ public class CollectionPostsFragment extends Fragment implements SwipeRefreshLay @Override public void onCreateOptionsMenu(@NonNull final Menu menu, @NonNull final MenuInflater inflater) { - inflater.inflate(R.menu.collection_posts_menu, menu); + // delaying to make toolbar resume animation smooth, otherwise lags + binding.getRoot().postDelayed(() -> inflater.inflate(R.menu.collection_posts_menu, menu), 500); } @Override @@ -288,62 +290,60 @@ public class CollectionPostsFragment extends Fragment implements SwipeRefreshLay if (item.getItemId() == R.id.layout) { showPostsLayoutPreferences(); return true; - } - else if (item.getItemId() == R.id.delete) { + } else if (item.getItemId() == R.id.delete) { final Context context = getContext(); + if (context == null) return false; new AlertDialog.Builder(context) .setTitle(R.string.delete_collection) .setMessage(R.string.delete_collection_note) - .setPositiveButton(R.string.confirm, (d, w) -> { - collectionService.deleteCollection( - savedCollection.getId(), - new ServiceCallback() { - @Override - public void onSuccess(final String result) { - SavedCollectionsFragment.pleaseRefresh = true; - NavHostFragment.findNavController(CollectionPostsFragment.this).navigateUp(); - } + .setPositiveButton(R.string.confirm, (d, w) -> collectionService.deleteCollection( + savedCollection.getId(), + new ServiceCallback() { + @Override + public void onSuccess(final String result) { + SavedCollectionsFragment.pleaseRefresh = true; + NavHostFragment.findNavController(CollectionPostsFragment.this).navigateUp(); + } - @Override - public void onFailure(final Throwable t) { - Log.e(TAG, "Error deleting collection", t); - try { - Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show(); - } - catch(final Throwable e) {} - } - }); - }) + @Override + public void onFailure(final Throwable t) { + Log.e(TAG, "Error deleting collection", t); + try { + final Context context = getContext(); + if (context == null) return; + Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show(); + } catch (final Throwable ignored) {} + } + })) .setNegativeButton(R.string.cancel, null) .show(); - } - else if (item.getItemId() == R.id.edit) { + } else if (item.getItemId() == R.id.edit) { final Context context = getContext(); + if (context == null) return false; final EditText input = new EditText(context); new AlertDialog.Builder(context) .setTitle(R.string.edit_collection) .setView(input) - .setPositiveButton(R.string.confirm, (d, w) -> { - collectionService.editCollectionName( - savedCollection.getId(), - input.getText().toString(), - new ServiceCallback() { - @Override - public void onSuccess(final String result) { - binding.collapsingToolbarLayout.setTitle(input.getText().toString()); - SavedCollectionsFragment.pleaseRefresh = true; - } + .setPositiveButton(R.string.confirm, (d, w) -> collectionService.editCollectionName( + savedCollection.getId(), + input.getText().toString(), + new ServiceCallback() { + @Override + public void onSuccess(final String result) { + binding.collapsingToolbarLayout.setTitle(input.getText().toString()); + SavedCollectionsFragment.pleaseRefresh = true; + } - @Override - public void onFailure(final Throwable t) { - Log.e(TAG, "Error editing collection", t); - try { - Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show(); - } - catch(final Throwable e) {} - } - }); - }) + @Override + public void onFailure(final Throwable t) { + Log.e(TAG, "Error editing collection", t); + try { + final Context context = getContext(); + if (context == null) return; + Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show(); + } catch (final Throwable ignored) {} + } + })) .setNegativeButton(R.string.cancel, null) .show(); } @@ -443,8 +443,8 @@ public class CollectionPostsFragment extends Fragment implements SwipeRefreshLay private void setupCover() { final String coverUrl = ResponseBodyUtils.getImageUrl(savedCollection.getCoverMedias() == null - ? savedCollection.getCoverMedia() - : savedCollection.getCoverMedias().get(0)); + ? savedCollection.getCoverMedia() + : savedCollection.getCoverMedias().get(0)); final DraweeController controller = Fresco .newDraweeControllerBuilder() .setOldController(binding.cover.getController()) diff --git a/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java b/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java index c620f4f2..d8ac1c2a 100644 --- a/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java @@ -1,5 +1,6 @@ package awais.instagrabber.fragments; +import android.annotation.SuppressLint; import android.content.Context; import android.content.pm.PackageManager; import android.graphics.Typeface; @@ -23,13 +24,14 @@ import androidx.activity.OnBackPressedDispatcher; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; -import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.constraintlayout.motion.widget.MotionLayout; +import androidx.constraintlayout.motion.widget.MotionScene; import androidx.core.content.PermissionChecker; import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; import androidx.navigation.NavController; import androidx.navigation.NavDirections; import androidx.navigation.fragment.NavHostFragment; +import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import com.google.android.material.snackbar.BaseTransientBottomBar; @@ -76,9 +78,6 @@ import static androidx.core.content.PermissionChecker.checkSelfPermission; import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION; import static awais.instagrabber.utils.Utils.settingsHelper; -//import awaisomereport.LogCollector; -//import static awais.instagrabber.utils.Utils.logCollector; - public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener { private static final String TAG = "HashTagFragment"; private static final int STORAGE_PERM_REQUEST_CODE = 8020; @@ -88,7 +87,7 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe private MainActivity fragmentActivity; private FragmentHashtagBinding binding; - private CoordinatorLayout root; + private MotionLayout root; private boolean shouldRefresh = true; private boolean hasStories = false; private boolean opening = false; @@ -227,17 +226,15 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe return; } opening = true; - final PostViewV2Fragment.Builder builder = PostViewV2Fragment.builder(feedModel); - if (position >= 0) { - builder.setPosition(position); + final NavController navController = NavHostFragment.findNavController(HashTagFragment.this); + final Bundle bundle = new Bundle(); + bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, feedModel); + bundle.putInt(PostViewV2Fragment.ARG_SLIDER_POSITION, position); + try { + navController.navigate(R.id.action_global_post_view, bundle); + } catch (Exception e) { + Log.e(TAG, "openPostDialog: ", e); } - if (!layoutPreferences.isAnimationDisabled()) { - builder.setSharedProfilePicElement(profilePicView) - .setSharedMainPostElement(mainPostImage); - } - final FragmentManager fragmentManager = getChildFragmentManager(); - if (fragmentManager.isDestroyed()) return; - builder.build().show(fragmentManager, "post_view"); opening = false; } }; @@ -307,13 +304,11 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe public View onCreateView(@NonNull final LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable final Bundle savedInstanceState) { if (root != null) { shouldRefresh = false; - fragmentActivity.setCollapsingView(hashtagDetailsBinding.getRoot()); return root; } binding = FragmentHashtagBinding.inflate(inflater, container, false); root = binding.getRoot(); - hashtagDetailsBinding = LayoutHashtagDetailsBinding.inflate(inflater, fragmentActivity.getCollapsingToolbarView(), false); - fragmentActivity.setCollapsingView(hashtagDetailsBinding.getRoot()); + hashtagDetailsBinding = binding.header; return root; } @@ -370,14 +365,6 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe } } - @Override - public void onDestroyView() { - super.onDestroyView(); - if (hashtagDetailsBinding != null) { - fragmentActivity.removeCollapsingView(hashtagDetailsBinding.getRoot()); - } - } - private void init() { if (getArguments() == null) return; final HashTagFragmentArgs fragmentArgs = HashTagFragmentArgs.fromBundle(getArguments()); @@ -402,6 +389,17 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe .setSelectionModeCallback(selectionModeCallback) .init(); binding.swipeRefreshLayout.setRefreshing(true); + binding.posts.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(@NonNull final RecyclerView recyclerView, final int dx, final int dy) { + super.onScrolled(recyclerView, dx, dy); + final boolean canScrollVertically = recyclerView.canScrollVertically(-1); + final MotionScene.Transition transition = root.getTransition(R.id.transition); + if (transition != null) { + transition.setEnable(!canScrollVertically); + } + } + }); } private void setHashtagDetails() { @@ -428,47 +426,49 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie); final long userId = CookieUtils.getUserIdFromCookie(cookie); final String deviceUuid = Utils.settingsHelper.getString(Constants.DEVICE_UUID); - if (csrfToken != null && userId != 0 && deviceUuid != null) { + if (csrfToken != null && userId != 0) { hashtagDetailsBinding.btnFollowTag.setClickable(false); - tagsService.changeFollow(hashtagModel.getFollowing() == FollowingType.FOLLOWING ? "unfollow" : "follow", - hashtag, - csrfToken, - userId, - deviceUuid, - new ServiceCallback() { - @Override - public void onSuccess(final Boolean result) { - hashtagDetailsBinding.btnFollowTag.setClickable(true); - if (!result) { - Log.e(TAG, "onSuccess: result is false"); - Snackbar.make(root, R.string.downloader_unknown_error, BaseTransientBottomBar.LENGTH_LONG) - .show(); - return; - } - hashtagDetailsBinding.btnFollowTag.setText(R.string.unfollow); - hashtagDetailsBinding.btnFollowTag.setChipIconResource(R.drawable.ic_outline_person_add_disabled_24); - } + tagsService.changeFollow( + hashtagModel.getFollowing() == FollowingType.FOLLOWING ? "unfollow" : "follow", + hashtag, + csrfToken, + userId, + deviceUuid, + new ServiceCallback() { + @Override + public void onSuccess(final Boolean result) { + hashtagDetailsBinding.btnFollowTag.setClickable(true); + if (!result) { + Log.e(TAG, "onSuccess: result is false"); + Snackbar.make(root, R.string.downloader_unknown_error, BaseTransientBottomBar.LENGTH_LONG) + .show(); + return; + } + hashtagDetailsBinding.btnFollowTag.setText(R.string.unfollow); + hashtagDetailsBinding.btnFollowTag.setChipIconResource(R.drawable.ic_outline_person_add_disabled_24); + } - @Override - public void onFailure(@NonNull final Throwable t) { - hashtagDetailsBinding.btnFollowTag.setClickable(true); - Log.e(TAG, "onFailure: ", t); - final String message = t.getMessage(); - Snackbar.make(root, - message != null ? message - : getString(R.string.downloader_unknown_error), - BaseTransientBottomBar.LENGTH_LONG) - .show(); - } - }); - return; + @Override + public void onFailure(@NonNull final Throwable t) { + hashtagDetailsBinding.btnFollowTag.setClickable(true); + Log.e(TAG, "onFailure: ", t); + final String message = t.getMessage(); + Snackbar.make( + root, + message != null ? message : getString(R.string.downloader_unknown_error), + BaseTransientBottomBar.LENGTH_LONG) + .show(); + } + }); } }); } else { hashtagDetailsBinding.btnFollowTag.setVisibility(View.GONE); } hashtagDetailsBinding.favChip.setVisibility(View.VISIBLE); - final FavoriteRepository favoriteRepository = FavoriteRepository.getInstance(FavoriteDataSource.getInstance(getContext())); + final Context context = getContext(); + if (context == null) return; + final FavoriteRepository favoriteRepository = FavoriteRepository.getInstance(FavoriteDataSource.getInstance(context)); favoriteRepository.getFavorite(hashtag, FavoriteType.HASHTAG, new RepositoryCallback() { @Override public void onSuccess(final Favorite result) { @@ -557,7 +557,7 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe } private void showSnackbar(final String message) { - final Snackbar snackbar = Snackbar.make(root, message, BaseTransientBottomBar.LENGTH_LONG); + @SuppressLint("ShowToast") final Snackbar snackbar = Snackbar.make(root, message, BaseTransientBottomBar.LENGTH_LONG); snackbar.setAction(R.string.ok, v1 -> snackbar.dismiss()) .setAnimationMode(BaseTransientBottomBar.ANIMATION_MODE_SLIDE) .setAnchorView(fragmentActivity.getBottomNavView()) diff --git a/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java b/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java index a1f14134..9f6da2c0 100644 --- a/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java @@ -22,13 +22,14 @@ import androidx.activity.OnBackPressedDispatcher; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; -import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.constraintlayout.motion.widget.MotionLayout; +import androidx.constraintlayout.motion.widget.MotionScene; import androidx.core.content.PermissionChecker; import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; import androidx.navigation.NavController; import androidx.navigation.NavDirections; import androidx.navigation.fragment.NavHostFragment; +import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import com.google.android.material.snackbar.BaseTransientBottomBar; @@ -73,9 +74,6 @@ import static androidx.core.content.PermissionChecker.checkSelfPermission; import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION; import static awais.instagrabber.utils.Utils.settingsHelper; -//import awaisomereport.LogCollector; -//import static awais.instagrabber.utils.Utils.logCollector; - public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener { private static final String TAG = "LocationFragment"; private static final int STORAGE_PERM_REQUEST_CODE = 8020; @@ -83,7 +81,7 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR private MainActivity fragmentActivity; private FragmentLocationBinding binding; - private CoordinatorLayout root; + private MotionLayout root; private boolean shouldRefresh = true; private boolean hasStories = false; private boolean opening = false; @@ -219,18 +217,15 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR return; } opening = true; - final PostViewV2Fragment.Builder builder = PostViewV2Fragment - .builder(feedModel); - if (position >= 0) { - builder.setPosition(position); + final NavController navController = NavHostFragment.findNavController(LocationFragment.this); + final Bundle bundle = new Bundle(); + bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, feedModel); + bundle.putInt(PostViewV2Fragment.ARG_SLIDER_POSITION, position); + try { + navController.navigate(R.id.action_global_post_view, bundle); + } catch (Exception e) { + Log.e(TAG, "openPostDialog: ", e); } - if (!layoutPreferences.isAnimationDisabled()) { - builder.setSharedProfilePicElement(profilePicView) - .setSharedMainPostElement(mainPostImage); - } - final FragmentManager fragmentManager = getChildFragmentManager(); - if (fragmentManager.isDestroyed()) return; - builder.build().show(fragmentManager, "post_view"); opening = false; } }; @@ -302,13 +297,11 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR @Nullable final Bundle savedInstanceState) { if (root != null) { shouldRefresh = false; - fragmentActivity.setCollapsingView(locationDetailsBinding.getRoot()); return root; } binding = FragmentLocationBinding.inflate(inflater, container, false); root = binding.getRoot(); - locationDetailsBinding = LayoutLocationDetailsBinding.inflate(inflater, fragmentActivity.getCollapsingToolbarView(), false); - fragmentActivity.setCollapsingView(locationDetailsBinding.getRoot()); + locationDetailsBinding = binding.header; return root; } @@ -365,14 +358,6 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR } } - @Override - public void onDestroyView() { - super.onDestroyView(); - if (locationDetailsBinding != null) { - fragmentActivity.removeCollapsingView(locationDetailsBinding.getRoot()); - } - } - private void init() { if (getArguments() == null) return; final LocationFragmentArgs fragmentArgs = LocationFragmentArgs.fromBundle(getArguments()); @@ -393,6 +378,17 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR .setSelectionModeCallback(selectionModeCallback) .init(); binding.swipeRefreshLayout.setRefreshing(true); + binding.posts.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(@NonNull final RecyclerView recyclerView, final int dx, final int dy) { + super.onScrolled(recyclerView, dx, dy); + final boolean canScrollVertically = recyclerView.canScrollVertically(-1); + final MotionScene.Transition transition = root.getTransition(R.id.transition); + if (transition != null) { + transition.setEnable(!canScrollVertically); + } + } + }); } private void fetchLocationModel() { diff --git a/app/src/main/java/awais/instagrabber/fragments/NotificationsViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/NotificationsViewerFragment.java index 880db291..c443652b 100644 --- a/app/src/main/java/awais/instagrabber/fragments/NotificationsViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/NotificationsViewerFragment.java @@ -20,6 +20,7 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.NotificationManagerCompat; import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; +import androidx.navigation.NavController; import androidx.navigation.NavDirections; import androidx.navigation.fragment.NavHostFragment; import androidx.recyclerview.widget.LinearLayoutManager; @@ -94,8 +95,8 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe final long mediaId = Long.parseLong(notificationImage.getId().split("_")[0]); if (model.getType() == NotificationType.RESPONDED_STORY) { final StoryViewerOptions options = StoryViewerOptions.forStory( - mediaId, - model.getArgs().getUsername()); + mediaId, + model.getArgs().getUsername()); final Bundle bundle = new Bundle(); bundle.putSerializable("options", options); NavHostFragment.findNavController(NotificationsViewerFragment.this).navigate(R.id.action_notifications_to_story, bundle); @@ -108,11 +109,14 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe mediaService.fetch(mediaId, new ServiceCallback() { @Override public void onSuccess(final Media feedModel) { - final PostViewV2Fragment fragment = PostViewV2Fragment - .builder(feedModel) - .build(); - fragment.setOnShowListener(dialog -> alertDialog.dismiss()); - fragment.show(getChildFragmentManager(), "post_view"); + final NavController navController = NavHostFragment.findNavController(NotificationsViewerFragment.this); + final Bundle bundle = new Bundle(); + bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, feedModel); + try { + navController.navigate(R.id.action_global_post_view, bundle); + } catch (Exception e) { + Log.e(TAG, "onSuccess: ", e); + } } @Override diff --git a/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java b/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java index 9f79871e..49768182 100644 --- a/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java @@ -1,50 +1,34 @@ package awais.instagrabber.fragments; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ObjectAnimator; -import android.animation.PropertyValuesHolder; -import android.animation.ValueAnimator; import android.annotation.SuppressLint; -import android.app.Dialog; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; -import android.graphics.Color; -import android.graphics.drawable.Animatable; -import android.graphics.drawable.ColorDrawable; +import android.content.res.ColorStateList; +import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; -import android.os.Handler; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.util.Log; import android.view.GestureDetector; -import android.view.Gravity; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; -import android.view.ViewTreeObserver; -import android.view.Window; -import android.view.WindowManager; -import android.widget.FrameLayout; -import android.widget.ScrollView; import android.widget.Toast; -import android.widget.ViewSwitcher; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.content.res.AppCompatResources; import androidx.appcompat.view.ContextThemeWrapper; import androidx.appcompat.widget.PopupMenu; -import androidx.constraintlayout.widget.ConstraintLayout; import androidx.core.content.PermissionChecker; +import androidx.core.util.Pair; import androidx.core.widget.NestedScrollView; -import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; @@ -58,11 +42,7 @@ import androidx.transition.TransitionManager; import androidx.viewpager2.widget.ViewPager2; import com.facebook.drawee.backends.pipeline.Fresco; -import com.facebook.drawee.controller.BaseControllerListener; -import com.facebook.drawee.drawable.ScalingUtils; -import com.facebook.drawee.generic.GenericDraweeHierarchy; import com.facebook.drawee.interfaces.DraweeController; -import com.facebook.imagepipeline.image.ImageInfo; import com.facebook.imagepipeline.request.ImageRequest; import com.facebook.imagepipeline.request.ImageRequestBuilder; import com.google.android.material.bottomsheet.BottomSheetBehavior; @@ -76,7 +56,6 @@ import awais.instagrabber.R; import awais.instagrabber.adapters.SliderCallbackAdapter; import awais.instagrabber.adapters.SliderItemsAdapter; import awais.instagrabber.adapters.viewholder.SliderVideoViewHolder; -import awais.instagrabber.customviews.SharedElementTransitionDialogFragment; import awais.instagrabber.customviews.VerticalImageSpan; import awais.instagrabber.customviews.VideoPlayerCallbackAdapter; import awais.instagrabber.customviews.VideoPlayerViewHelper; @@ -101,31 +80,28 @@ import awais.instagrabber.viewmodels.PostViewV2ViewModel; import static androidx.core.content.PermissionChecker.checkSelfPermission; import static awais.instagrabber.fragments.HashTagFragment.ARG_HASHTAG; import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION; +import static awais.instagrabber.utils.Utils.getAttrValue; import static awais.instagrabber.utils.Utils.settingsHelper; -public class PostViewV2Fragment extends SharedElementTransitionDialogFragment implements EditTextDialogFragment.EditTextDialogFragmentCallback { +public class PostViewV2Fragment extends Fragment implements EditTextDialogFragment.EditTextDialogFragmentCallback { private static final String TAG = "PostViewV2Fragment"; private static final int DETAILS_HIDE_DELAY_MILLIS = 2000; - private static final String ARG_MEDIA = "media"; - private static final String ARG_SLIDER_POSITION = "position"; + public static final String ARG_MEDIA = "media"; + public static final String ARG_SLIDER_POSITION = "position"; private static final int STORAGE_PERM_REQUEST_CODE = 8020; // private Media media; - private View sharedProfilePicElement; - private View sharedMainPostElement; private DialogPostViewBinding binding; // private MediaService mediaService; - private Context context; + // private Context context; private BottomSheetBehavior bottomSheetBehavior; private boolean detailsVisible = true; private boolean video; private VideoPlayerViewHelper videoPlayerViewHelper; private SliderItemsAdapter sliderItemsAdapter; // private boolean wasControlsVisible; - private boolean wasPaused; private int captionState = BottomSheetBehavior.STATE_HIDDEN; private int sliderPosition = -1; - private DialogInterface.OnShowListener onShowListener; private boolean hasBeenToggled = false; private PostViewV2ViewModel viewModel; private PopupMenu optionsPopup; @@ -151,51 +127,6 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im } }; - // private final VerticalDragHelper.OnVerticalDragListener onVerticalDragListener = new VerticalDragHelper.OnVerticalDragListener() { - // - // @Override - // public void onDrag(final float dY) { - // // allow the view to be draggable - // final ConstraintLayout v = binding.getRoot(); - // final float finalY = v.getY() + dY; - // animateY(v, finalY, 0, null); - // } - // - // @Override - // public void onDragEnd() { - // // animate and dismiss if user drags the view more that 30% of the view - // if (Math.abs(binding.getRoot().getY()) > Utils.displayMetrics.heightPixels * 0.25) { - // animateAndDismiss(binding.getRoot().getY() < 0 ? 1 : -1); - // return; - // } - // // animate back the view to proper position - // animateY(binding.getRoot(), 0, 200, null); - // } - // - // @Override - // public void onFling(final double flingVelocity) { - // // animate and dismiss if user flings up/down - // animateAndDismiss(flingVelocity > 0 ? 1 : -1); - // } - // - // private void animateAndDismiss(final int direction) { - // final int height = binding.getRoot().getHeight(); - // final int finalYDist = height + Utils.getStatusBarHeight(context); - // // less than 0 means up direction, else down - // final int finalY = direction > 0 ? -finalYDist : finalYDist; - // animateY(binding.getRoot(), finalY, 200, new AnimatorListenerAdapter() { - // @Override - // public void onAnimationEnd(final Animator animation) { - // dismiss(); - // } - // }); - // } - // }; - - public void setOnShowListener(final DialogInterface.OnShowListener onShowListener) { - this.onShowListener = onShowListener; - } - public void setOnDeleteListener(final OnDeleteListener onDeleteListener) { if (onDeleteListener == null) return; this.onDeleteListener = onDeleteListener; @@ -205,68 +136,12 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im void onDelete(); } - public static class Builder { - private final Media feedModel; - private View profilePicElement; - private View mainPostElement; - private int position; - - public Builder setSharedProfilePicElement(final View profilePicElement) { - this.profilePicElement = profilePicElement; - return this; - } - - @SuppressWarnings("UnusedReturnValue") - public Builder setSharedMainPostElement(final View mainPostElement) { - this.mainPostElement = mainPostElement; - return this; - } - - public Builder setPosition(final int position) { - this.position = position; - return this; - } - - public PostViewV2Fragment build() { - return PostViewV2Fragment.newInstance(feedModel, profilePicElement, mainPostElement, position); - } - - public Builder(final Media feedModel) { - this.feedModel = feedModel; - } - } - - private static PostViewV2Fragment newInstance(final Media feedModel, - final View profilePicElement, - final View mainPostElement, - final int position) { - final PostViewV2Fragment f = new PostViewV2Fragment(profilePicElement, mainPostElement); - final Bundle args = new Bundle(); - args.putSerializable(ARG_MEDIA, feedModel); - if (position >= 0) { - args.putInt(ARG_SLIDER_POSITION, position); - } - f.setArguments(args); - return f; - } - - public static Builder builder(final Media feedModel) { - return new Builder(feedModel); - } - // default constructor for fragment manager public PostViewV2Fragment() {} - private PostViewV2Fragment(final View sharedProfilePicElement, - final View sharedMainPostElement) { - this.sharedProfilePicElement = sharedProfilePicElement; - this.sharedMainPostElement = sharedMainPostElement; - } - @Override public void onCreate(@Nullable final Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setStyle(DialogFragment.STYLE_NO_FRAME, R.style.PostViewV2Style); viewModel = new ViewModelProvider(this).get(PostViewV2ViewModel.class); captionState = settingsHelper.getBoolean(Constants.SHOW_CAPTIONS) ? BottomSheetBehavior.STATE_COLLAPSED : BottomSheetBehavior.STATE_HIDDEN; @@ -278,58 +153,19 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im @Nullable final ViewGroup container, @Nullable final Bundle savedInstanceState) { binding = DialogPostViewBinding.inflate(inflater, container, false); - final ConstraintLayout root = binding.getRoot(); - final ViewTreeObserver.OnPreDrawListener preDrawListener = new ViewTreeObserver.OnPreDrawListener() { - @Override - public boolean onPreDraw() { - root.getViewTreeObserver().removeOnPreDrawListener(this); - return false; - } - }; - root.getViewTreeObserver().addOnPreDrawListener(preDrawListener); - return root; + return binding.getRoot(); } @Override public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) { + // postponeEnterTransition(); init(); } - @Override - public void onAttach(@NonNull final Context context) { - super.onAttach(context); - this.context = context; - } - - @Override - public void onStart() { - super.onStart(); - final Dialog dialog = getDialog(); - if (dialog == null) return; - final Window window = dialog.getWindow(); - if (window == null) return; - window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); - window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); - window.setDimAmount(0); - int width = ViewGroup.LayoutParams.MATCH_PARENT; - int height = ViewGroup.LayoutParams.MATCH_PARENT; - window.setLayout(width, height); - if (!wasPaused && (sharedProfilePicElement != null || sharedMainPostElement != null)) { - final ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder( - binding.getRoot().getBackground().mutate(), - PropertyValuesHolder.ofInt("alpha", 0, 255) - ); - addAnimator(animator); - } - if (onShowListener != null) { - onShowListener.onShow(dialog); - } - } - @Override public void onPause() { super.onPause(); - wasPaused = true; + // wasPaused = true; if (bottomSheetBehavior != null) { captionState = bottomSheetBehavior.getState(); } @@ -390,85 +226,12 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im } } - @Override - protected void onBeforeSharedElementAnimation(@NonNull final View startView, - @NonNull final View destView, - @NonNull final SharedElementTransitionDialogFragment.ViewBounds viewBounds) { - GenericDraweeHierarchy hierarchy = null; - if (destView == binding.postImage) { - hierarchy = binding.postImage.getHierarchy(); - } else if (destView == binding.videoPost.thumbnailParent) { - hierarchy = binding.videoPost.thumbnail.getHierarchy(); - } - if (hierarchy != null) { - final ScalingUtils.ScaleType scaleTypeTo = ScalingUtils.ScaleType.FIT_CENTER; - final ScalingUtils.InterpolatingScaleType scaleType = new ScalingUtils.InterpolatingScaleType( - ScalingUtils.ScaleType.CENTER_CROP, - scaleTypeTo, - viewBounds.getStartBounds(), - viewBounds.getDestBounds() - ); - hierarchy.setActualImageScaleType(scaleType); - final ValueAnimator animator = ValueAnimator.ofFloat(0, 1); - animator.setDuration(getAnimationDuration()); - animator.addUpdateListener(animation -> { - float fraction = (float) animation.getAnimatedValue(); - scaleType.setValue(fraction); - }); - final GenericDraweeHierarchy finalHierarchy = hierarchy; - animator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - finalHierarchy.setActualImageScaleType(scaleTypeTo); - destView.requestLayout(); - } - }); - addAnimator(animator); - } - } - - @Override - protected void onEndSharedElementAnimation(@NonNull final View startView, - @NonNull final View destView, - @NonNull final ViewBounds viewBounds) { - if (destView == binding.postImage) { - binding.postImage.setTranslationX(0); - binding.postImage.setTranslationY(0); - binding.postImage.setX(0); - binding.postImage.setY(0); - binding.postImage.setLayoutParams(new ConstraintLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT)); - binding.postImage.requestLayout(); - if (bottomSheetBehavior != null) { - bottomSheetBehavior.setState(captionState); - } - return; - } - if (destView == binding.sliderParent) { - binding.sliderParent.setLayoutParams(new ConstraintLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT)); - binding.sliderParent.requestLayout(); - if (bottomSheetBehavior != null) { - bottomSheetBehavior.setState(captionState); - } - return; - } - if (destView == binding.videoPost.thumbnailParent) { - final FrameLayout.LayoutParams params = new ViewSwitcher.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT); - params.gravity = Gravity.CENTER; - binding.videoPost.thumbnailParent.setLayoutParams(params); - binding.videoPost.thumbnailParent.requestLayout(); - if (bottomSheetBehavior != null) { - bottomSheetBehavior.setState(captionState); - } - } - } - @Override public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == STORAGE_PERM_REQUEST_CODE && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + final Context context = getContext(); + if (context == null) return; DownloadUtils.showDownloadDialog(context, viewModel.getMedia(), sliderPosition); } } @@ -476,17 +239,17 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im private void init() { final Bundle arguments = getArguments(); if (arguments == null) { - dismiss(); + // dismiss(); return; } final Serializable feedModelSerializable = arguments.getSerializable(ARG_MEDIA); if (feedModelSerializable == null) { Log.e(TAG, "onCreate: feedModelSerializable is null"); - dismiss(); + // dismiss(); return; } if (!(feedModelSerializable instanceof Media)) { - dismiss(); + // dismiss(); return; } final Media media = (Media) feedModelSerializable; @@ -494,11 +257,11 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im sliderPosition = arguments.getInt(ARG_SLIDER_POSITION, 0); } viewModel.setMedia(media); - if (!wasPaused && (sharedProfilePicElement != null || sharedMainPostElement != null)) { - binding.getRoot().getBackground().mutate().setAlpha(0); - } - setProfilePicSharedElement(); - setupCaptionBottomSheet(); + // if (!wasPaused && (sharedProfilePicElement != null || sharedMainPostElement != null)) { + // binding.getRoot().getBackground().mutate().setAlpha(0); + // } + // setProfilePicSharedElement(); + // setupCaptionBottomSheet(); setupCommonActions(); setObservers(); } @@ -506,10 +269,14 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im private void setObservers() { viewModel.getUser().observe(getViewLifecycleOwner(), user -> { if (user == null) { - binding.userDetailsGroup.setVisibility(View.GONE); + binding.profilePic.setVisibility(View.GONE); + binding.title.setVisibility(View.GONE); + binding.subtitle.setVisibility(View.GONE); return; } - binding.userDetailsGroup.setVisibility(View.VISIBLE); + binding.profilePic.setVisibility(View.VISIBLE); + binding.title.setVisibility(View.VISIBLE); + binding.subtitle.setVisibility(View.VISIBLE); binding.getRoot().post(() -> setupProfilePic(user)); binding.getRoot().post(() -> setupTitles(user)); }); @@ -563,30 +330,6 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im return safeCount; } - private void setupCaptionBottomSheet() { - bottomSheetBehavior = BottomSheetBehavior.from(binding.captionParent); - bottomSheetBehavior.setState(captionState); - bottomSheetBehavior.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { - @Override - public void onStateChanged(@NonNull final View bottomSheet, final int newState) {} - - @Override - public void onSlide(@NonNull final View bottomSheet, final float slideOffset) { - binding.captionParent.getBackground().mutate().setAlpha((int) (128 + (128 * (slideOffset < 0 ? 0 : slideOffset)))); - } - }); - if (sharedProfilePicElement == null || sharedMainPostElement == null) { - binding.getRoot().getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { - @Override - public void onGlobalLayout() { - binding.getRoot().getViewTreeObserver().removeOnGlobalLayoutListener(this); - if (bottomSheetBehavior == null) return; - bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED); - } - }); - } - } - private void setupCommonActions() { setupLike(); setupSave(); @@ -619,6 +362,8 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im } }); binding.comment.setOnLongClickListener(v -> { + final Context context = getContext(); + if (context == null) return false; Utils.displayToastAboveView(context, v, getString(R.string.comment)); return true; }); @@ -626,6 +371,8 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im private void setupDownload() { binding.download.setOnClickListener(v -> { + final Context context = getContext(); + if (context == null) return; if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) { DownloadUtils.showDownloadDialog(context, viewModel.getMedia(), sliderPosition); return; @@ -633,6 +380,8 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE); }); binding.download.setOnLongClickListener(v -> { + final Context context = getContext(); + if (context == null) return false; Utils.displayToastAboveView(context, v, getString(R.string.action_download)); return true; }); @@ -702,17 +451,21 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im private void setLikedResources(final boolean liked) { final int iconResource; final int tintResource; + final Context context = getContext(); + if (context == null) return; + final Resources resources = context.getResources(); + if (resources == null) return; if (liked) { iconResource = R.drawable.ic_like; - tintResource = R.color.red_600; + tintResource = resources.getColor(R.color.red_600); // textResId = R.string.unlike_without_count; } else { iconResource = R.drawable.ic_not_liked; - tintResource = R.color.white; + tintResource = getAttrValue(context, R.attr.colorPrimary); // textResId = R.string.like_without_count; } binding.like.setIconResource(iconResource); - binding.like.setIconTintResource(tintResource); + binding.like.setIconTint(ColorStateList.valueOf(tintResource)); } private void setupSave() { @@ -769,23 +522,21 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im private void setSavedResources(final boolean saved) { final int iconResource; final int tintResource; + final Context context = getContext(); + if (context == null) return; + final Resources resources = context.getResources(); + if (resources == null) return; if (saved) { iconResource = R.drawable.ic_class_24; - tintResource = R.color.blue_700; + tintResource = resources.getColor(R.color.blue_700); // textResId = R.string.saved; } else { iconResource = R.drawable.ic_outline_class_24; - tintResource = R.color.white; + tintResource = getAttrValue(context, R.attr.colorPrimary); // textResId = R.string.save; } binding.save.setIconResource(iconResource); - binding.save.setIconTintResource(tintResource); - } - - private void setProfilePicSharedElement() { - if (!wasPaused && sharedProfilePicElement != null) { - addSharedElement(sharedProfilePicElement, binding.profilePic); - } + binding.save.setIconTint(ColorStateList.valueOf(tintResource)); } private void setupProfilePic(final User user) { @@ -797,19 +548,6 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im final DraweeController controller = Fresco .newDraweeControllerBuilder() .setUri(uri) - .setControllerListener(new BaseControllerListener() { - @Override - public void onFailure(final String id, final Throwable throwable) { - startPostponedEnterTransition(); - } - - @Override - public void onFinalImageSet(final String id, - final ImageInfo imageInfo, - final Animatable animatable) { - startPostponedEnterTransition(); - } - }) .build(); binding.profilePic.setController(controller); binding.profilePic.setOnClickListener(v -> navigateToProfile("@" + user.getUsername())); @@ -821,7 +559,13 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im binding.subtitle.setVisibility(View.GONE); return; } - binding.subtitle.setText(user.getFullName()); + final String fullName = user.getFullName(); + if (TextUtils.isEmpty(fullName)) { + binding.subtitle.setVisibility(View.GONE); + } else { + binding.subtitle.setVisibility(View.VISIBLE); + binding.subtitle.setText(fullName); + } setUsername(user); binding.title.setOnClickListener(v -> navigateToProfile("@" + user.getUsername())); binding.subtitle.setOnClickListener(v -> navigateToProfile("@" + user.getUsername())); @@ -831,6 +575,8 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im final SpannableStringBuilder sb = new SpannableStringBuilder(user.getUsername()); final int drawableSize = Utils.convertDpToPx(24); if (user.isVerified()) { + final Context context = getContext(); + if (context == null) return; final Drawable verifiedDrawable = AppCompatResources.getDrawable(context, R.drawable.verified); VerticalImageSpan verifiedSpan = null; if (verifiedDrawable != null) { @@ -854,7 +600,6 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im if (caption == null || TextUtils.isEmpty(caption.getText())) { binding.caption.setVisibility(View.GONE); binding.translate.setVisibility(View.GONE); - binding.captionToggle.setVisibility(View.GONE); return; } final String postCaption = caption.getText(); @@ -872,35 +617,13 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im binding.caption.addOnEmailClickListener(autoLinkItem -> Utils.openEmailAddress(getContext(), autoLinkItem.getOriginalText().trim())); binding.caption.addOnURLClickListener(autoLinkItem -> Utils.openURL(getContext(), autoLinkItem.getOriginalText().trim())); binding.caption.setOnLongClickListener(v -> { + final Context context = getContext(); + if (context == null) return false; Utils.copyText(context, postCaption); return true; }); binding.caption.setText(postCaption); binding.translate.setOnClickListener(v -> handleTranslateCaptionResource(viewModel.translateCaption())); - binding.captionToggle.setOnClickListener(v -> { - if (bottomSheetBehavior == null) return; - switch (bottomSheetBehavior.getState()) { - case BottomSheetBehavior.STATE_HIDDEN: - binding.captionParent.fullScroll(ScrollView.FOCUS_UP); // reset scroll position - // if (binding.playerControls.getRoot().getVisibility() == View.VISIBLE) { - // hidePlayerControls(); - // } - bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED); - return; - case BottomSheetBehavior.STATE_COLLAPSED: - case BottomSheetBehavior.STATE_EXPANDED: - bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); - return; - case BottomSheetBehavior.STATE_DRAGGING: - case BottomSheetBehavior.STATE_HALF_EXPANDED: - case BottomSheetBehavior.STATE_SETTLING: - default: - } - }); - binding.captionToggle.setOnLongClickListener(v -> { - Utils.displayToastAboveView(context, v, getString(R.string.caption)); - return true; - }); } private void handleTranslateCaptionResource(@NonNull final LiveData> data) { @@ -953,6 +676,8 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im } binding.share.setVisibility(View.VISIBLE); binding.share.setOnLongClickListener(v -> { + final Context context = getContext(); + if (context == null) return false; Utils.displayToastAboveView(context, v, getString(R.string.share)); return true; }); @@ -962,6 +687,8 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im if (profileModel == null) return; final boolean isPrivate = profileModel.isPrivate(); if (isPrivate) { + final Context context = getContext(); + if (context == null) return; // is this necessary? Toast.makeText(context, R.string.share_private_post, Toast.LENGTH_LONG).show(); } @@ -996,15 +723,15 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im // binding.playerControls.getRoot().setVisibility(View.GONE); binding.mediaCounter.setVisibility(View.GONE); binding.postImage.setVisibility(View.VISIBLE); - if (!wasPaused && sharedMainPostElement != null) { - binding.postImage.getHierarchy().setActualImageScaleType(ScalingUtils.ScaleType.CENTER_CROP); - addSharedElement(sharedMainPostElement, binding.postImage); - } final Media media = viewModel.getMedia(); final String imageUrl = ResponseBodyUtils.getImageUrl(media); - if (TextUtils.isEmpty(imageUrl)) { - return; - } + if (TextUtils.isEmpty(imageUrl)) return; + final ViewGroup.LayoutParams layoutParams = binding.postImage.getLayoutParams(); + final Pair widthHeight = NumberUtils.calculateWidthHeight(media.getOriginalHeight(), + media.getOriginalWidth(), + (int) (Utils.displayMetrics.heightPixels * 0.8), + Utils.displayMetrics.widthPixels); + layoutParams.height = widthHeight.second; final ImageRequest requestBuilder = ImageRequestBuilder.newBuilderWithSource(Uri.parse(imageUrl)) .setLocalThumbnailPreviewsEnabled(true) .build(); @@ -1012,35 +739,22 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im .newDraweeControllerBuilder() .setLowResImageRequest(ImageRequest.fromUri(ResponseBodyUtils.getThumbUrl(media))) .setImageRequest(requestBuilder) - .setControllerListener(new BaseControllerListener() { - @Override - public void onFailure(final String id, final Throwable throwable) { - startPostponedEnterTransition(); - } - - @Override - public void onFinalImageSet(final String id, - final ImageInfo imageInfo, - final Animatable animatable) { - startPostponedEnterTransition(); - } - }) .build(); binding.postImage.setController(controller); // binding.postImage.setOnClickListener(v -> toggleDetails()); - final AnimatedZoomableController zoomableController = AnimatedZoomableController.newInstance(); + final AnimatedZoomableController zoomableController = (AnimatedZoomableController) binding.postImage.getZoomableController(); zoomableController.setMaxScaleFactor(3f); zoomableController.setGestureZoomEnabled(true); zoomableController.setEnabled(true); - binding.postImage.setZoomableController(zoomableController); + binding.postImage.setZoomingEnabled(true); binding.postImage.setTapListener(new GestureDetector.SimpleOnGestureListener() { @Override public boolean onSingleTapUp(final MotionEvent e) { - toggleDetails(); + // toggleDetails(); return true; } }); - binding.postImage.setAllowTouchInterceptionWhileZoomed(true); + // binding.postImage.setAllowTouchInterceptionWhileZoomed(true); // binding.postImage.setOnVerticalDragListener(onVerticalDragListener); } @@ -1052,9 +766,26 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im // binding.playerControls.getRoot().setVisibility(View.GONE); binding.sliderParent.setVisibility(View.VISIBLE); binding.mediaCounter.setVisibility(View.VISIBLE); - if (!wasPaused && sharedMainPostElement != null) { - addSharedElement(sharedMainPostElement, binding.sliderParent); - } + final Pair maxHW = media + .getCarouselMedia() + .stream() + .reduce(new Pair<>(0, 0), + (prev, m) -> { + final int height = m.getOriginalHeight() > prev.first ? m.getOriginalHeight() : prev.first; + final int width = m.getOriginalWidth() > prev.second ? m.getOriginalWidth() : prev.second; + return new Pair<>(height, width); + }, + (p1, p2) -> { + final int height = p1.first > p2.first ? p1.first : p2.first; + final int width = p1.second > p2.second ? p1.second : p2.second; + return new Pair<>(height, width); + }); + final ViewGroup.LayoutParams layoutParams = binding.sliderParent.getLayoutParams(); + final Pair widthHeight = NumberUtils.calculateWidthHeight(maxHW.first, + maxHW.second, + (int) (Utils.displayMetrics.heightPixels * 0.8), + Utils.displayMetrics.widthPixels); + layoutParams.height = widthHeight.second; final boolean hasVideo = media.getCarouselMedia() .stream() .anyMatch(postChild -> postChild.getMediaType() == MediaItemType.MEDIA_TYPE_VIDEO); @@ -1078,7 +809,7 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im @Override public void onItemClicked(final int position) { - toggleDetails(); + // toggleDetails(); } @Override @@ -1095,8 +826,8 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im final FragmentActivity activity = getActivity(); if (activity == null) return; Utils.disableKeepScreenOn(activity); - if (detailsVisible || hasBeenToggled) return; - toggleDetails(); + // if (detailsVisible || hasBeenToggled) return; + // toggleDetails(); } @Override @@ -1135,7 +866,7 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im final String text = (position + 1) + "/" + size; binding.mediaCounter.setText(text); final Media childMedia = media.getCarouselMedia().get(position); - final View view = binding.sliderParent.getChildAt(0); + // final View view = binding.sliderParent.getChildAt(0); // if (prevPosition != -1) { // if (view instanceof RecyclerView) { // final RecyclerView.ViewHolder viewHolder = ((RecyclerView) view).findViewHolderForAdapterPosition(prevPosition); @@ -1203,32 +934,17 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im binding.sliderParent.setVisibility(View.GONE); binding.mediaCounter.setVisibility(View.GONE); // binding.playerControls.getRoot().setVisibility(View.VISIBLE); - if (!wasPaused && sharedMainPostElement != null) { - final GenericDraweeHierarchy hierarchy = binding.videoPost.thumbnail.getHierarchy(); - hierarchy.setActualImageScaleType(ScalingUtils.ScaleType.CENTER_CROP); - addSharedElement(sharedMainPostElement, binding.videoPost.thumbnailParent); - } + final ViewGroup.LayoutParams layoutParams = binding.videoPost.root.getLayoutParams(); + final Pair widthHeight = NumberUtils.calculateWidthHeight(media.getOriginalHeight(), + media.getOriginalWidth(), + (int) (Utils.displayMetrics.heightPixels * 0.8), + Utils.displayMetrics.widthPixels); + layoutParams.height = widthHeight.second; binding.videoPost.root.setVisibility(View.VISIBLE); - // final VerticalDragHelper thumbnailVerticalDragHelper = new VerticalDragHelper(binding.videoPost.thumbnailParent); - // final VerticalDragHelper playerVerticalDragHelper = new VerticalDragHelper(binding.videoPost.playerView); - // thumbnailVerticalDragHelper.setOnVerticalDragListener(onVerticalDragListener); - // playerVerticalDragHelper.setOnVerticalDragListener(onVerticalDragListener); // enablePlayerControls(true); - // binding.videoPost.thumbnailParent.setOnTouchListener((v, event) -> { - // final boolean onDragTouch = thumbnailVerticalDragHelper.onDragTouch(event); - // if (onDragTouch) { - // return true; - // } - // return thumbnailVerticalDragHelper.onGestureTouchEvent(event); - // }); - // binding.videoPost.playerView.setOnTouchListener((v, event) -> { - // final boolean onDragTouch = playerVerticalDragHelper.onDragTouch(event); - // if (onDragTouch) { - // return true; - // } - // return playerVerticalDragHelper.onGestureTouchEvent(event); - // }); - binding.videoPost.playerView.setOnClickListener(v -> toggleDetails()); + // binding.videoPost.playerView.setOnClickListener(v -> toggleDetails()); + final Context context = getContext(); + if (context == null) return; final GestureDetector gestureDetector = new GestureDetector(context, videoPlayerViewGestureListener); binding.videoPost.playerView.setOnTouchListener((v, event) -> { gestureDetector.onTouchEvent(event); @@ -1258,9 +974,9 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im final FragmentActivity activity = getActivity(); if (activity == null) return; Utils.enabledKeepScreenOn(activity); - if (detailsVisible) { - new Handler().postDelayed(() -> toggleDetails(), DETAILS_HIDE_DELAY_MILLIS); - } + // if (detailsVisible) { + // new Handler().postDelayed(() -> toggleDetails(), DETAILS_HIDE_DELAY_MILLIS); + // } } @Override @@ -1318,10 +1034,10 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im // hidePlayerControls(); // } - private void hideCaption() { - if (bottomSheetBehavior == null) return; - bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); - } + // private void hideCaption() { + // if (bottomSheetBehavior == null) return; + // bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); + // } // private void showPlayerControls() { // hideCaption(); @@ -1400,6 +1116,8 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im private void createOptionsPopupMenu() { if (optionsPopup == null) { + final Context context = getContext(); + if (context == null) return; final ContextThemeWrapper themeWrapper = new ContextThemeWrapper(context, R.style.popupMenuStyle); optionsPopup = new PopupMenu(themeWrapper, binding.options); } else { @@ -1526,18 +1244,18 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im binding.profilePic.setVisibility(View.GONE); binding.title.setVisibility(View.GONE); binding.subtitle.setVisibility(View.GONE); - binding.topBg.setVisibility(View.GONE); + // binding.topBg.setVisibility(View.GONE); } if (media.getLocation() != null) { binding.location.setVisibility(View.GONE); } - binding.captionParent.setVisibility(View.GONE); + // binding.captionParent.setVisibility(View.GONE); binding.bottomBg.setVisibility(View.GONE); binding.likesCount.setVisibility(View.GONE); binding.commentsCount.setVisibility(View.GONE); binding.date.setVisibility(View.GONE); binding.comment.setVisibility(View.GONE); - binding.captionToggle.setVisibility(View.GONE); + // binding.captionToggle.setVisibility(View.GONE); // binding.playerControlsToggle.setVisibility(View.GONE); binding.like.setVisibility(View.GONE); binding.save.setVisibility(View.GONE); @@ -1559,7 +1277,7 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im binding.profilePic.setVisibility(View.VISIBLE); binding.title.setVisibility(View.VISIBLE); binding.subtitle.setVisibility(View.VISIBLE); - binding.topBg.setVisibility(View.VISIBLE); + // binding.topBg.setVisibility(View.VISIBLE); } if (media.getLocation() != null) { binding.location.setVisibility(View.VISIBLE); @@ -1568,8 +1286,8 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im if (viewModel.hasPk()) { binding.likesCount.setVisibility(View.VISIBLE); binding.date.setVisibility(View.VISIBLE); - binding.captionParent.setVisibility(View.VISIBLE); - binding.captionToggle.setVisibility(View.VISIBLE); + // binding.captionParent.setVisibility(View.VISIBLE); + // binding.captionToggle.setVisibility(View.VISIBLE); binding.share.setVisibility(View.VISIBLE); } if (viewModel.hasPk() && !viewModel.getMedia().isCommentsDisabled()) { @@ -1599,16 +1317,6 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im }); } - // private void animateY(final View v, - // final float finalY, - // final int duration, - // final AnimatorListenerAdapter listener) { - // v.animate() - // .y(finalY) - // .setDuration(duration) - // .setListener(listener).start(); - // } - private void navigateToProfile(final String username) { final NavController navController = getNavController(); if (navController == null) return; diff --git a/app/src/main/java/awais/instagrabber/fragments/SavedViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/SavedViewerFragment.java index b6ee5431..8ae5a963 100644 --- a/app/src/main/java/awais/instagrabber/fragments/SavedViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/SavedViewerFragment.java @@ -4,6 +4,7 @@ import android.content.Context; import android.content.pm.PackageManager; import android.os.Bundle; import android.os.Handler; +import android.util.Log; import android.view.ActionMode; import android.view.LayoutInflater; import android.view.Menu; @@ -50,6 +51,7 @@ import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION; import static awais.instagrabber.utils.Utils.settingsHelper; public final class SavedViewerFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener { + private static final String TAG = SavedViewerFragment.class.getSimpleName(); private static final int STORAGE_PERM_REQUEST_CODE = 8020; private static final int STORAGE_PERM_REQUEST_CODE_FOR_SELECTION = 8030; @@ -171,16 +173,15 @@ public final class SavedViewerFragment extends Fragment implements SwipeRefreshL final View profilePicView, final View mainPostImage, final int position) { - final PostViewV2Fragment.Builder builder = PostViewV2Fragment - .builder(feedModel); - if (position >= 0) { - builder.setPosition(position); + final NavController navController = NavHostFragment.findNavController(SavedViewerFragment.this); + final Bundle bundle = new Bundle(); + bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, feedModel); + bundle.putInt(PostViewV2Fragment.ARG_SLIDER_POSITION, position); + try { + navController.navigate(R.id.action_global_post_view, bundle); + } catch (Exception e) { + Log.e(TAG, "openPostDialog: ", e); } - if (!layoutPreferences.isAnimationDisabled()) { - builder.setSharedProfilePicElement(profilePicView) - .setSharedMainPostElement(mainPostImage); - } - builder.build().show(getChildFragmentManager(), "post_view"); } }; private final FeedAdapterV2.SelectionModeCallback selectionModeCallback = new FeedAdapterV2.SelectionModeCallback() { diff --git a/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java index a170a8a0..1372eb59 100644 --- a/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java @@ -35,6 +35,7 @@ import androidx.core.view.GestureDetectorCompat; import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModel; import androidx.lifecycle.ViewModelProvider; +import androidx.navigation.NavController; import androidx.navigation.NavDirections; import androidx.navigation.fragment.NavHostFragment; import androidx.recyclerview.widget.LinearLayoutManager; @@ -459,11 +460,14 @@ public class StoryViewerFragment extends Fragment { mediaService.fetch(Long.parseLong(mediaId), new ServiceCallback() { @Override public void onSuccess(final Media feedModel) { - final PostViewV2Fragment fragment = PostViewV2Fragment - .builder(feedModel) - .build(); - fragment.setOnShowListener(dialog -> alertDialog.dismiss()); - fragment.show(getChildFragmentManager(), "post_view"); + final NavController navController = NavHostFragment.findNavController(StoryViewerFragment.this); + final Bundle bundle = new Bundle(); + bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, feedModel); + try { + navController.navigate(R.id.action_global_post_view, bundle); + } catch (Exception e) { + Log.e(TAG, "openPostDialog: ", e); + } } @Override @@ -478,18 +482,18 @@ public class StoryViewerFragment extends Fragment { if (tag instanceof PollModel) { poll = (PollModel) tag; if (poll.getMyChoice() > -1) { - new AlertDialog.Builder(context).setTitle(R.string.voted_story_poll) - .setAdapter(new ArrayAdapter<>(context, android.R.layout.simple_list_item_1, - new String[]{ - (poll.getMyChoice() == 0 ? "√ " : "") + poll - .getLeftChoice() + " (" + poll - .getLeftCount() + ")", - (poll.getMyChoice() == 1 ? "√ " : "") + poll - .getRightChoice() + " (" + poll - .getRightCount() + ")" - }), null) - .setPositiveButton(R.string.ok, null) - .show(); + new AlertDialog.Builder(context) + .setTitle(R.string.voted_story_poll) + .setAdapter(new ArrayAdapter<>( + context, + android.R.layout.simple_list_item_1, + new String[]{ + (poll.getMyChoice() == 0 ? "√ " : "") + poll.getLeftChoice() + " (" + poll.getLeftCount() + ")", + (poll.getMyChoice() == 1 ? "√ " : "") + poll.getRightChoice() + " (" + poll.getRightCount() + ")" + }), + null) + .setPositiveButton(R.string.ok, null) + .show(); } else { new AlertDialog.Builder(context) .setTitle(poll.getQuestion()) diff --git a/app/src/main/java/awais/instagrabber/fragments/TopicPostsFragment.java b/app/src/main/java/awais/instagrabber/fragments/TopicPostsFragment.java index 9b680d64..76374891 100644 --- a/app/src/main/java/awais/instagrabber/fragments/TopicPostsFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/TopicPostsFragment.java @@ -10,6 +10,7 @@ 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; @@ -51,8 +52,8 @@ import awais.instagrabber.databinding.FragmentTopicPostsBinding; import awais.instagrabber.dialogs.PostsLayoutPreferencesDialogFragment; import awais.instagrabber.fragments.main.DiscoverFragmentDirections; import awais.instagrabber.models.PostsLayoutPreferences; -import awais.instagrabber.repositories.responses.discover.TopicCluster; import awais.instagrabber.repositories.responses.Media; +import awais.instagrabber.repositories.responses.discover.TopicCluster; import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.DownloadUtils; import awais.instagrabber.utils.ResponseBodyUtils; @@ -63,6 +64,7 @@ import static androidx.core.content.PermissionChecker.checkSelfPermission; import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION; public class TopicPostsFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener { + private static final String TAG = TopicPostsFragment.class.getSimpleName(); private static final int STORAGE_PERM_REQUEST_CODE = 8020; private static final int STORAGE_PERM_REQUEST_CODE_FOR_SELECTION = 8030; @@ -182,16 +184,15 @@ public class TopicPostsFragment extends Fragment implements SwipeRefreshLayout.O final View profilePicView, final View mainPostImage, final int position) { - final PostViewV2Fragment.Builder builder = PostViewV2Fragment - .builder(feedModel); - if (position >= 0) { - builder.setPosition(position); + final NavController navController = NavHostFragment.findNavController(TopicPostsFragment.this); + final Bundle bundle = new Bundle(); + bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, feedModel); + bundle.putInt(PostViewV2Fragment.ARG_SLIDER_POSITION, position); + try { + navController.navigate(R.id.action_global_post_view, bundle); + } catch (Exception e) { + Log.e(TAG, "openPostDialog: ", e); } - if (!layoutPreferences.isAnimationDisabled()) { - builder.setSharedProfilePicElement(profilePicView) - .setSharedMainPostElement(mainPostImage); - } - builder.build().show(getChildFragmentManager(), "post_view"); } }; private final FeedAdapterV2.SelectionModeCallback selectionModeCallback = new FeedAdapterV2.SelectionModeCallback() { diff --git a/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java b/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java index fde7950a..5a97fa73 100644 --- a/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java @@ -224,8 +224,14 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact } return; } - final PostViewV2Fragment.Builder builder = PostViewV2Fragment.builder(media); - builder.build().show(getChildFragmentManager(), "post_view"); + final NavController navController = NavHostFragment.findNavController(DirectMessageThreadFragment.this); + final Bundle bundle = new Bundle(); + bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, media); + try { + navController.navigate(R.id.action_global_post_view, bundle); + } catch (Exception e) { + Log.e(TAG, "openPostDialog: ", e); + } } @Override @@ -327,11 +333,13 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact final Bundle arguments = getArguments(); if (arguments == null) return; final DirectMessageThreadFragmentArgs fragmentArgs = DirectMessageThreadFragmentArgs.fromBundle(arguments); + final User currentUser = appStateViewModel.getCurrentUser(); + if (currentUser == null) return; final DirectThreadViewModelFactory viewModelFactory = new DirectThreadViewModelFactory( fragmentActivity.getApplication(), fragmentArgs.getThreadId(), fragmentArgs.getPending(), - appStateViewModel.getCurrentUser() + currentUser ); viewModel = new ViewModelProvider(this, viewModelFactory).get(DirectThreadViewModel.class); setHasOptionsMenu(true); @@ -386,7 +394,7 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact final DirectMessageThreadFragmentDirections.ActionThreadToSettings directions = DirectMessageThreadFragmentDirections .actionThreadToSettings(viewModel.getThreadId(), null); final Boolean pending = viewModel.isPending().getValue(); - directions.setPending(pending == null ? false : pending); + directions.setPending(pending != null && pending); NavHostFragment.findNavController(this).navigate(directions); return true; } @@ -414,14 +422,10 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact case SUCCESS: Toast.makeText(context, R.string.marked_as_seen, Toast.LENGTH_SHORT).show(); case LOADING: - if (item != null) { - item.setEnabled(false); - } + item.setEnabled(false); break; case ERROR: - if (item != null) { - item.setEnabled(true); - } + item.setEnabled(true); if (resource.message != null) { Snackbar.make(context, binding.getRoot(), resource.message, Snackbar.LENGTH_LONG).show(); return; @@ -1352,7 +1356,7 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE); } - @NonNull + @Nullable private User getUser(final long userId) { for (final User user : users) { if (userId != user.getPk()) continue; diff --git a/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java index 0ac6e566..ea54ceca 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java @@ -18,7 +18,8 @@ import androidx.activity.OnBackPressedCallback; import androidx.activity.OnBackPressedDispatcher; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.constraintlayout.motion.widget.MotionLayout; +import androidx.constraintlayout.motion.widget.MotionScene; import androidx.core.content.PermissionChecker; import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; @@ -29,7 +30,6 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; -import com.google.android.material.appbar.CollapsingToolbarLayout; import com.google.common.collect.ImmutableList; import java.util.List; @@ -64,7 +64,7 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre private static final int STORAGE_PERM_REQUEST_CODE_FOR_SELECTION = 8030; private MainActivity fragmentActivity; - private CoordinatorLayout root; + private MotionLayout root; private FragmentFeedBinding binding; private StoriesService storiesService; private boolean shouldRefresh = true; @@ -179,15 +179,21 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre final View profilePicView, final View mainPostImage, final int position) { - final PostViewV2Fragment.Builder builder = PostViewV2Fragment.builder(feedModel); - if (position >= 0) { - builder.setPosition(position); + // ViewCompat.setTransitionName(profilePicView, "profile_pic"); + // ViewCompat.setTransitionName(mainPostImage, "post_image"); + // final FragmentNavigator.Extras extras = new FragmentNavigator.Extras.Builder() + // .addSharedElement(profilePicView, "profile_pic") + // .addSharedElement(mainPostImage, "post_image") + // .build(); + final NavController navController = NavHostFragment.findNavController(FeedFragment.this); + final Bundle bundle = new Bundle(); + bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, feedModel); + bundle.putInt(PostViewV2Fragment.ARG_SLIDER_POSITION, position); + try { + navController.navigate(R.id.action_global_post_view, bundle); + } catch (Exception e) { + Log.e(TAG, "openPostDialog: ", e); } - if (!layoutPreferences.isAnimationDisabled()) { - builder.setSharedProfilePicElement(profilePicView) - .setSharedMainPostElement(mainPostImage); - } - builder.build().show(getChildFragmentManager(), "post_view"); } }; private final OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(false) { @@ -278,9 +284,6 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre final Bundle savedInstanceState) { if (root != null) { shouldRefresh = false; - if (storiesRecyclerView != null) { - fragmentActivity.setCollapsingView(storiesRecyclerView); - } return root; } binding = FragmentFeedBinding.inflate(inflater, container, false); @@ -381,6 +384,17 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre .setSelectionModeCallback(selectionModeCallback) .init(); binding.feedSwipeRefreshLayout.setRefreshing(true); + binding.feedRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(@NonNull final RecyclerView recyclerView, final int dx, final int dy) { + super.onScrolled(recyclerView, dx, dy); + final boolean canScrollVertically = recyclerView.canScrollVertically(-1); + final MotionScene.Transition transition = root.getTransition(R.id.transition); + if (transition != null) { + transition.setEnable(!canScrollVertically); + } + } + }); // if (shouldAutoPlay) { // videoAwareRecyclerScroller = new VideoAwareRecyclerScroller(); // binding.feedRecyclerView.addOnScrollListener(videoAwareRecyclerScroller); @@ -396,15 +410,9 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre feedStoriesViewModel = new ViewModelProvider(fragmentActivity).get(FeedStoriesViewModel.class); final Context context = getContext(); if (context == null) return; - storiesRecyclerView = new RecyclerView(context); - final CollapsingToolbarLayout.LayoutParams params = new CollapsingToolbarLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT); - params.setMargins(0, Utils.getActionBarHeight(context), 0, 0); - storiesRecyclerView.setLayoutParams(params); - storiesRecyclerView.setClipToPadding(false); + storiesRecyclerView = binding.header; storiesRecyclerView.setLayoutManager(new LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)); storiesRecyclerView.setAdapter(feedStoriesAdapter); - fragmentActivity.setCollapsingView(storiesRecyclerView); feedStoriesViewModel.getList().observe(getViewLifecycleOwner(), feedStoriesAdapter::submitList); fetchStories(); } diff --git a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java index 75802ac0..93f27ed4 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java @@ -27,7 +27,8 @@ import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.content.res.AppCompatResources; -import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.constraintlayout.motion.widget.MotionLayout; +import androidx.constraintlayout.motion.widget.MotionScene; import androidx.core.content.PermissionChecker; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; @@ -108,7 +109,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe private static final int STORAGE_PERM_REQUEST_CODE_FOR_SELECTION = 8030; private MainActivity fragmentActivity; - private CoordinatorLayout root; + private MotionLayout root; private FragmentProfileBinding binding; private boolean isLoggedIn; private String cookie; @@ -250,23 +251,15 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe final View profilePicView, final View mainPostImage, final int position) { - final PostViewV2Fragment.Builder builder = PostViewV2Fragment - .builder(feedModel); - if (position >= 0) { - builder.setPosition(position); + final NavController navController = NavHostFragment.findNavController(ProfileFragment.this); + final Bundle bundle = new Bundle(); + bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, feedModel); + bundle.putInt(PostViewV2Fragment.ARG_SLIDER_POSITION, position); + try { + navController.navigate(R.id.action_global_post_view, bundle); + } catch (Exception e) { + Log.e(TAG, "openPostDialog: ", e); } - if (!layoutPreferences.isAnimationDisabled()) { - builder.setSharedProfilePicElement(profilePicView) - .setSharedMainPostElement(mainPostImage); - } - final PostViewV2Fragment postViewV2Fragment = builder.build(); - postViewV2Fragment.setOnDeleteListener(() -> { - postViewV2Fragment.dismiss(); - binding.postsRecyclerView.refresh(); - }); - final FragmentManager fragmentManager = getChildFragmentManager(); - if (fragmentManager.isDestroyed() || fragmentManager.isStateSaved()) return; - postViewV2Fragment.show(fragmentManager, "post_view"); } }; private final FeedAdapterV2.SelectionModeCallback selectionModeCallback = new FeedAdapterV2.SelectionModeCallback() { @@ -345,7 +338,6 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe final boolean isSame = ("@" + profileModelUsername).equals(this.username); if (isSame) { setUsernameDelayed(); - fragmentActivity.setCollapsingView(profileDetailsBinding.getRoot()); shouldRefresh = false; return root; } @@ -357,14 +349,12 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe } } setUsernameDelayed(); - fragmentActivity.setCollapsingView(profileDetailsBinding.getRoot()); shouldRefresh = false; return root; } binding = FragmentProfileBinding.inflate(inflater, container, false); root = binding.getRoot(); - profileDetailsBinding = LayoutProfileDetailsBinding.inflate(inflater, fragmentActivity.getCollapsingToolbarView(), false); - fragmentActivity.setCollapsingView(profileDetailsBinding.getRoot()); + profileDetailsBinding = binding.header; return root; } @@ -554,14 +544,6 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe } } - @Override - public void onDestroyView() { - super.onDestroyView(); - if (profileDetailsBinding != null) { - fragmentActivity.removeCollapsingView(profileDetailsBinding.getRoot()); - } - } - @Override public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); @@ -589,7 +571,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe setUsernameDelayed(); } if (TextUtils.isEmpty(username) && !isLoggedIn) { - profileDetailsBinding.infoContainer.setVisibility(View.GONE); + binding.header.getRoot().setVisibility(View.GONE); binding.swipeRefreshLayout.setEnabled(false); binding.privatePage1.setImageResource(R.drawable.ic_outline_info_24); binding.privatePage2.setText(R.string.no_acc); @@ -1209,6 +1191,17 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe .setFeedItemCallback(feedItemCallback) .setSelectionModeCallback(selectionModeCallback) .init(); + binding.postsRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(@NonNull final RecyclerView recyclerView, final int dx, final int dy) { + super.onScrolled(recyclerView, dx, dy); + final boolean canScrollVertically = recyclerView.canScrollVertically(-1); + final MotionScene.Transition transition = root.getTransition(R.id.transition); + if (transition != null) { + transition.setEnable(!canScrollVertically); + } + } + }); binding.swipeRefreshLayout.setRefreshing(true); postsSetupDone = true; } diff --git a/app/src/main/java/awais/instagrabber/utils/NavigationExtensions.java b/app/src/main/java/awais/instagrabber/utils/NavigationExtensions.java index 7663a59b..a6bccbfd 100644 --- a/app/src/main/java/awais/instagrabber/utils/NavigationExtensions.java +++ b/app/src/main/java/awais/instagrabber/utils/NavigationExtensions.java @@ -21,6 +21,7 @@ import com.google.android.material.bottomnavigation.BottomNavigationView; import java.util.List; import awais.instagrabber.R; +import awais.instagrabber.customviews.NavHostFragmentWithDefaultAnimations; import awais.instagrabber.fragments.main.FeedFragment; /** @@ -139,7 +140,7 @@ public class NavigationExtensions { if (existingFragment != null) { return existingFragment; } - final NavHostFragment navHostFragment = NavHostFragment.create(navGraphId); + final NavHostFragment navHostFragment = NavHostFragmentWithDefaultAnimations.create(navGraphId); fragmentManager.beginTransaction() .setReorderingAllowed(true) .add(containerId, navHostFragment, fragmentTag) diff --git a/app/src/main/java/awais/instagrabber/utils/Utils.java b/app/src/main/java/awais/instagrabber/utils/Utils.java index 432a0e90..9647c2c5 100644 --- a/app/src/main/java/awais/instagrabber/utils/Utils.java +++ b/app/src/main/java/awais/instagrabber/utils/Utils.java @@ -288,6 +288,12 @@ public final class Utils { return outValue.data; } + public static int getAttrValue(@NonNull final Context context, final int attr) { + final TypedValue outValue = new TypedValue(); + context.getTheme().resolveAttribute(attr, outValue, true); + return outValue.data; + } + public static void transparentStatusBar(final Activity activity, final boolean enable, final boolean fullscreen) { diff --git a/app/src/main/java/awais/instagrabber/webservices/interceptors/IgErrorsInterceptor.java b/app/src/main/java/awais/instagrabber/webservices/interceptors/IgErrorsInterceptor.java index 104a9ad5..b0fab4d2 100644 --- a/app/src/main/java/awais/instagrabber/webservices/interceptors/IgErrorsInterceptor.java +++ b/app/src/main/java/awais/instagrabber/webservices/interceptors/IgErrorsInterceptor.java @@ -65,6 +65,7 @@ public class IgErrorsInterceptor implements Interceptor { if (body == null) return; try { final String bodyString = body.string(); + Log.d(TAG, "checkError: " + bodyString); final JSONObject jsonObject = new JSONObject(bodyString); String message = jsonObject.optString("message"); if (!TextUtils.isEmpty(message)) { diff --git a/app/src/main/res/anim/slide_in_right.xml b/app/src/main/res/anim/slide_in_right.xml new file mode 100644 index 00000000..5b01fc74 --- /dev/null +++ b/app/src/main/res/anim/slide_in_right.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/slide_left.xml b/app/src/main/res/anim/slide_left.xml index fa86a927..8808e776 100644 --- a/app/src/main/res/anim/slide_left.xml +++ b/app/src/main/res/anim/slide_left.xml @@ -1,10 +1,5 @@ - - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/anim/slide_out_left.xml b/app/src/main/res/anim/slide_out_left.xml new file mode 100644 index 00000000..964d042f --- /dev/null +++ b/app/src/main/res/anim/slide_out_left.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/slide_right.xml b/app/src/main/res/anim/slide_right.xml index d283f645..7c0373bc 100644 --- a/app/src/main/res/anim/slide_right.xml +++ b/app/src/main/res/anim/slide_right.xml @@ -1,10 +1,5 @@ - - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_round_edit_24.xml b/app/src/main/res/drawable/ic_round_edit_24.xml new file mode 100644 index 00000000..1599eed8 --- /dev/null +++ b/app/src/main/res/drawable/ic_round_edit_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/shape_oval_light.xml b/app/src/main/res/drawable/shape_oval_light.xml index 48b0b708..194d0b34 100644 --- a/app/src/main/res/drawable/shape_oval_light.xml +++ b/app/src/main/res/drawable/shape_oval_light.xml @@ -1,5 +1,5 @@ - + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_post_view.xml b/app/src/main/res/layout/dialog_post_view.xml index f843c15d..7778d7e5 100644 --- a/app/src/main/res/layout/dialog_post_view.xml +++ b/app/src/main/res/layout/dialog_post_view.xml @@ -1,477 +1,514 @@ - + android:layout_height="match_parent"> - + android:layout_height="wrap_content"> - - - - - - - - - - - - - - - - - - - - - - - + android:background="@null" + android:clickable="true" + android:focusable="true" + android:transitionName="post_image" + app:actualImageScaleType="fitCenter" + app:layout_constraintBottom_toTopOf="@id/bottom_bg_barrier" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/top_barrier" + tools:background="@mipmap/ic_launcher" + tools:layout_height="400dp" + tools:visibility="gone" /> - + - + - + + + + + + + + - - - - - - - - - - - - - - - + - + - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - + - + - + + + + + - + - + - + + + + + + + + + - + + + + + + + + - + + + + + - + + + + - + + + + + + + + + + + + - + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + - + - + - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_feed.xml b/app/src/main/res/layout/fragment_feed.xml index da5f341f..47ae11de 100644 --- a/app/src/main/res/layout/fragment_feed.xml +++ b/app/src/main/res/layout/fragment_feed.xml @@ -1,40 +1,39 @@ - + android:background="?attr/colorSurface" + app:layoutDescription="@xml/header_list_scene"> - - - - - - - - - - - - - - - - - + + android:layout_height="0dp" + android:clipToPadding="false" + app:layout_behavior="@string/appbar_scrolling_view_behavior" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toBottomOf="@id/header"> + android:paddingBottom="?attr/actionBarSize" + tools:listitem="@layout/item_feed_grid" /> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_hashtag.xml b/app/src/main/res/layout/fragment_hashtag.xml index 7bd26633..ad78e4c2 100644 --- a/app/src/main/res/layout/fragment_hashtag.xml +++ b/app/src/main/res/layout/fragment_hashtag.xml @@ -1,20 +1,32 @@ - + android:background="?attr/colorSurface" + app:layoutDescription="@xml/header_list_scene"> + + + android:layout_height="0dp" + app:layout_behavior="@string/appbar_scrolling_view_behavior" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toBottomOf="@id/header"> + android:clipToPadding="false" + android:paddingBottom="?attr/actionBarSize" /> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_location.xml b/app/src/main/res/layout/fragment_location.xml index 7bd26633..09f98c39 100644 --- a/app/src/main/res/layout/fragment_location.xml +++ b/app/src/main/res/layout/fragment_location.xml @@ -1,20 +1,32 @@ - + android:background="?attr/colorSurface" + app:layoutDescription="@xml/header_list_scene"> + + + android:layout_height="0dp" + app:layout_behavior="@string/appbar_scrolling_view_behavior" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toBottomOf="@id/header"> + android:clipToPadding="false" + android:paddingBottom="?attr/actionBarSize" /> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_profile.xml b/app/src/main/res/layout/fragment_profile.xml index 7a683ca9..efc1b3db 100644 --- a/app/src/main/res/layout/fragment_profile.xml +++ b/app/src/main/res/layout/fragment_profile.xml @@ -1,39 +1,34 @@ - + android:background="?attr/colorSurface" + app:layoutDescription="@xml/header_list_scene"> - - - - - - - - - - - - - - - - + + android:layout_height="0dp" + app:layout_behavior="@string/appbar_scrolling_view_behavior" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toBottomOf="@id/header"> @@ -62,4 +57,4 @@ android:text="@string/priv_acc" android:textAppearance="@style/TextAppearance.AppCompat.Large" /> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/item_highlight.xml b/app/src/main/res/layout/item_highlight.xml index 61269c9e..f71ccbb4 100755 --- a/app/src/main/res/layout/item_highlight.xml +++ b/app/src/main/res/layout/item_highlight.xml @@ -20,6 +20,7 @@ android:gravity="center" android:maxLines="1" android:padding="2dp" + android:scrollbars="none" android:singleLine="true" android:textColor="?attr/colorOnPrimarySurface" android:textStyle="bold" diff --git a/app/src/main/res/layout/layout_exo_custom_controls.xml b/app/src/main/res/layout/layout_exo_custom_controls.xml index 14fe87a7..9ad77784 100644 --- a/app/src/main/res/layout/layout_exo_custom_controls.xml +++ b/app/src/main/res/layout/layout_exo_custom_controls.xml @@ -4,8 +4,6 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> - - - - - - - + app:layout_constraintTop_toTopOf="@id/exo_position" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/layout_hashtag_details.xml b/app/src/main/res/layout/layout_hashtag_details.xml index 56ddc32e..7f947541 100644 --- a/app/src/main/res/layout/layout_hashtag_details.xml +++ b/app/src/main/res/layout/layout_hashtag_details.xml @@ -2,10 +2,9 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + @@ -86,8 +85,8 @@ android:id="@+id/locationBiography" android:layout_width="0dp" android:layout_height="wrap_content" - android:padding="8dp" android:background="?android:selectableItemBackground" + android:padding="8dp" android:textAppearance="@style/TextAppearance.AppCompat.Body1" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" diff --git a/app/src/main/res/layout/layout_profile_details.xml b/app/src/main/res/layout/layout_profile_details.xml index ea4df164..d7f5bdd8 100644 --- a/app/src/main/res/layout/layout_profile_details.xml +++ b/app/src/main/res/layout/layout_profile_details.xml @@ -2,10 +2,9 @@ + android:background="?toolbarColor"> + app:barrierDirection="bottom" + app:constraint_referenced_ids="mainPostCount, mainFollowers, mainFollowing" /> - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/menu/collection_posts_menu.xml b/app/src/main/res/menu/collection_posts_menu.xml index 5759b068..3ad2b822 100644 --- a/app/src/main/res/menu/collection_posts_menu.xml +++ b/app/src/main/res/menu/collection_posts_menu.xml @@ -4,15 +4,15 @@ + app:showAsAction="ifRoom" /> + app:showAsAction="ifRoom" /> + + + + + - + \ No newline at end of file diff --git a/app/src/main/res/navigation/discover_nav_graph.xml b/app/src/main/res/navigation/discover_nav_graph.xml index 2c2d0f08..ee13ef9b 100644 --- a/app/src/main/res/navigation/discover_nav_graph.xml +++ b/app/src/main/res/navigation/discover_nav_graph.xml @@ -99,6 +99,18 @@ android:id="@+id/action_global_search" app:destination="@id/searchFragment" /> + + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/feed_nav_graph.xml b/app/src/main/res/navigation/feed_nav_graph.xml index 19dec632..611c933f 100644 --- a/app/src/main/res/navigation/feed_nav_graph.xml +++ b/app/src/main/res/navigation/feed_nav_graph.xml @@ -110,6 +110,18 @@ android:id="@+id/action_global_search" app:destination="@id/searchFragment" /> + + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/hashtag_nav_graph.xml b/app/src/main/res/navigation/hashtag_nav_graph.xml index 7446c366..41c911c2 100644 --- a/app/src/main/res/navigation/hashtag_nav_graph.xml +++ b/app/src/main/res/navigation/hashtag_nav_graph.xml @@ -69,6 +69,18 @@ android:id="@+id/action_global_search" app:destination="@id/searchFragment" /> + + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/location_nav_graph.xml b/app/src/main/res/navigation/location_nav_graph.xml index 3761330f..4a2935a4 100644 --- a/app/src/main/res/navigation/location_nav_graph.xml +++ b/app/src/main/res/navigation/location_nav_graph.xml @@ -70,6 +70,18 @@ android:id="@+id/action_global_search" app:destination="@id/searchFragment" /> + + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/notification_viewer_nav_graph.xml b/app/src/main/res/navigation/notification_viewer_nav_graph.xml index 139795c1..b60bd3b8 100644 --- a/app/src/main/res/navigation/notification_viewer_nav_graph.xml +++ b/app/src/main/res/navigation/notification_viewer_nav_graph.xml @@ -72,6 +72,18 @@ app:argType="boolean" /> + + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/profile_nav_graph.xml b/app/src/main/res/navigation/profile_nav_graph.xml index 4bc8c444..e33e5c9b 100644 --- a/app/src/main/res/navigation/profile_nav_graph.xml +++ b/app/src/main/res/navigation/profile_nav_graph.xml @@ -86,6 +86,18 @@ app:destination="@id/storyViewerFragment" /> + + + + + + app:nullable="false" /> + \ No newline at end of file diff --git a/app/src/main/res/navigation/saved_nav_graph.xml b/app/src/main/res/navigation/saved_nav_graph.xml index 805a06e5..e30af1cc 100644 --- a/app/src/main/res/navigation/saved_nav_graph.xml +++ b/app/src/main/res/navigation/saved_nav_graph.xml @@ -64,15 +64,27 @@ app:nullable="false" /> + + + + + + tools:layout="@layout/fragment_saved_collections"> + android:defaultValue="false" + app:argType="boolean" /> @@ -93,4 +105,9 @@ android:name="backgroundColor" app:argType="integer" /> + \ No newline at end of file diff --git a/app/src/main/res/values/drawables.xml b/app/src/main/res/values/drawables.xml new file mode 100644 index 00000000..5df15b97 --- /dev/null +++ b/app/src/main/res/values/drawables.xml @@ -0,0 +1,5 @@ + + + @drawable/ic_play_arrow_24 + @drawable/ic_pause_24 + \ No newline at end of file diff --git a/app/src/main/res/xml/header_list_scene.xml b/app/src/main/res/xml/header_list_scene.xml new file mode 100644 index 00000000..389b7cb1 --- /dev/null +++ b/app/src/main/res/xml/header_list_scene.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + \ No newline at end of file