Skip to content

Commit 96da16f

Browse files
committed
Convert Post view to a regular fragment instead of dialog.
Added global fragment animations too
1 parent 3bbafc6 commit 96da16f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1427
-1350
lines changed

app/src/main/java/awais/instagrabber/activities/MainActivity.java

+25-8
Original file line numberDiff line numberDiff line change
@@ -651,7 +651,11 @@ private void showProfileView(@NonNull final IntentModel intentModel) {
651651
if (navController == null) return;
652652
final Bundle bundle = new Bundle();
653653
bundle.putString("username", "@" + username);
654-
navController.navigate(R.id.action_global_profileFragment, bundle);
654+
try {
655+
navController.navigate(R.id.action_global_profileFragment, bundle);
656+
} catch (Exception e) {
657+
Log.e(TAG, "showProfileView: ", e);
658+
}
655659
}
656660

657661
private void showPostView(@NonNull final IntentModel intentModel) {
@@ -664,11 +668,16 @@ private void showPostView(@NonNull final IntentModel intentModel) {
664668
alertDialog.show();
665669
new PostFetcher(shortCode, feedModel -> {
666670
if (feedModel != null) {
667-
final PostViewV2Fragment fragment = PostViewV2Fragment
668-
.builder(feedModel)
669-
.build();
670-
fragment.setOnShowListener(dialog -> alertDialog.dismiss());
671-
fragment.show(getSupportFragmentManager(), "post_view");
671+
if (currentNavControllerLiveData == null) return;
672+
final NavController navController = currentNavControllerLiveData.getValue();
673+
if (navController == null) return;
674+
final Bundle bundle = new Bundle();
675+
bundle.putSerializable(PostViewV2Fragment.ARG_MEDIA, feedModel);
676+
try {
677+
navController.navigate(R.id.action_global_post_view, bundle);
678+
} catch (Exception e) {
679+
Log.e(TAG, "showPostView: ", e);
680+
}
672681
return;
673682
}
674683
Toast.makeText(getApplicationContext(), R.string.post_not_found, Toast.LENGTH_SHORT).show();
@@ -724,11 +733,19 @@ public BottomNavigationView getBottomNavView() {
724733
}
725734

726735
public void setCollapsingView(@NonNull final View view) {
727-
binding.collapsingToolbarLayout.addView(view, 0);
736+
try {
737+
binding.collapsingToolbarLayout.addView(view, 0);
738+
} catch (Exception e) {
739+
Log.e(TAG, "setCollapsingView: ", e);
740+
}
728741
}
729742

730743
public void removeCollapsingView(@NonNull final View view) {
731-
binding.collapsingToolbarLayout.removeView(view);
744+
try {
745+
binding.collapsingToolbarLayout.removeView(view);
746+
} catch (Exception e) {
747+
Log.e(TAG, "removeCollapsingView: ", e);
748+
}
732749
}
733750

734751
public void setToolbar(final Toolbar toolbar) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package awais.instagrabber.customviews;
2+
3+
import android.content.Context;
4+
import android.os.Bundle;
5+
6+
import androidx.annotation.NonNull;
7+
import androidx.annotation.Nullable;
8+
import androidx.fragment.app.FragmentManager;
9+
import androidx.navigation.NavDestination;
10+
import androidx.navigation.NavOptions;
11+
import androidx.navigation.Navigator;
12+
import androidx.navigation.fragment.FragmentNavigator;
13+
14+
import awais.instagrabber.R;
15+
16+
@Navigator.Name("fragment")
17+
public class FragmentNavigatorWithDefaultAnimations extends FragmentNavigator {
18+
19+
private final NavOptions emptyNavOptions = new NavOptions.Builder().build();
20+
// private final NavOptions defaultNavOptions = new NavOptions.Builder()
21+
// .setEnterAnim(R.animator.nav_default_enter_anim)
22+
// .setExitAnim(R.animator.nav_default_exit_anim)
23+
// .setPopEnterAnim(R.animator.nav_default_pop_enter_anim)
24+
// .setPopExitAnim(R.animator.nav_default_pop_exit_anim)
25+
// .build();
26+
27+
private final NavOptions defaultNavOptions = new NavOptions.Builder()
28+
.setEnterAnim(R.anim.slide_in_right)
29+
.setExitAnim(R.anim.slide_out_left)
30+
.setPopEnterAnim(android.R.anim.slide_in_left)
31+
.setPopExitAnim(android.R.anim.slide_out_right)
32+
.build();
33+
34+
public FragmentNavigatorWithDefaultAnimations(@NonNull final Context context,
35+
@NonNull final FragmentManager manager,
36+
final int containerId) {
37+
super(context, manager, containerId);
38+
}
39+
40+
@Nullable
41+
@Override
42+
public NavDestination navigate(@NonNull final Destination destination,
43+
@Nullable final Bundle args,
44+
@Nullable final NavOptions navOptions,
45+
@Nullable final Navigator.Extras navigatorExtras) {
46+
// this will try to fill in empty animations with defaults when no shared element transitions are set
47+
// https://developer.android.com/guide/navigation/navigation-animate-transitions#shared-element
48+
final boolean shouldUseTransitionsInstead = navigatorExtras != null;
49+
final NavOptions navOptions1 = shouldUseTransitionsInstead ? navOptions : fillEmptyAnimationsWithDefaults(navOptions);
50+
return super.navigate(destination, args, navOptions1, navigatorExtras);
51+
}
52+
53+
private NavOptions fillEmptyAnimationsWithDefaults(@Nullable final NavOptions navOptions) {
54+
if (navOptions == null) {
55+
return defaultNavOptions;
56+
}
57+
return copyNavOptionsWithDefaultAnimations(navOptions);
58+
}
59+
60+
@NonNull
61+
private NavOptions copyNavOptionsWithDefaultAnimations(@NonNull final NavOptions navOptions) {
62+
return new NavOptions.Builder()
63+
.setLaunchSingleTop(navOptions.shouldLaunchSingleTop())
64+
.setPopUpTo(navOptions.getPopUpTo(), navOptions.isPopUpToInclusive())
65+
.setEnterAnim(navOptions.getEnterAnim() == emptyNavOptions.getEnterAnim()
66+
? defaultNavOptions.getEnterAnim() : navOptions.getEnterAnim())
67+
.setExitAnim(navOptions.getExitAnim() == emptyNavOptions.getExitAnim()
68+
? defaultNavOptions.getExitAnim() : navOptions.getExitAnim())
69+
.setPopEnterAnim(navOptions.getPopEnterAnim() == emptyNavOptions.getPopEnterAnim()
70+
? defaultNavOptions.getPopEnterAnim() : navOptions.getPopEnterAnim())
71+
.setPopExitAnim(navOptions.getPopExitAnim() == emptyNavOptions.getPopExitAnim()
72+
? defaultNavOptions.getPopExitAnim() : navOptions.getPopExitAnim())
73+
.build();
74+
}
75+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package awais.instagrabber.customviews;
2+
3+
import android.os.Bundle;
4+
5+
import androidx.annotation.NavigationRes;
6+
import androidx.annotation.NonNull;
7+
import androidx.annotation.Nullable;
8+
import androidx.navigation.NavController;
9+
import androidx.navigation.Navigator;
10+
import androidx.navigation.fragment.FragmentNavigator;
11+
import androidx.navigation.fragment.NavHostFragment;
12+
13+
public class NavHostFragmentWithDefaultAnimations extends NavHostFragment {
14+
private static final String KEY_GRAPH_ID = "android-support-nav:fragment:graphId";
15+
private static final String KEY_START_DESTINATION_ARGS =
16+
"android-support-nav:fragment:startDestinationArgs";
17+
private static final String KEY_NAV_CONTROLLER_STATE =
18+
"android-support-nav:fragment:navControllerState";
19+
private static final String KEY_DEFAULT_NAV_HOST = "android-support-nav:fragment:defaultHost";
20+
21+
@NonNull
22+
public static NavHostFragment create(@NavigationRes int graphResId) {
23+
return create(graphResId, null);
24+
}
25+
26+
@NonNull
27+
public static NavHostFragment create(@NavigationRes int graphResId,
28+
@Nullable Bundle startDestinationArgs) {
29+
Bundle b = null;
30+
if (graphResId != 0) {
31+
b = new Bundle();
32+
b.putInt(KEY_GRAPH_ID, graphResId);
33+
}
34+
if (startDestinationArgs != null) {
35+
if (b == null) {
36+
b = new Bundle();
37+
}
38+
b.putBundle(KEY_START_DESTINATION_ARGS, startDestinationArgs);
39+
}
40+
41+
final NavHostFragmentWithDefaultAnimations result = new NavHostFragmentWithDefaultAnimations();
42+
if (b != null) {
43+
result.setArguments(b);
44+
}
45+
return result;
46+
}
47+
48+
@NonNull
49+
@Override
50+
protected Navigator<? extends FragmentNavigator.Destination> createFragmentNavigator() {
51+
return new FragmentNavigatorWithDefaultAnimations(requireContext(), getChildFragmentManager(), getId());
52+
}
53+
54+
@Override
55+
protected void onCreateNavController(@NonNull final NavController navController) {
56+
super.onCreateNavController(navController);
57+
navController.getNavigatorProvider()
58+
.addNavigator(new FragmentNavigatorWithDefaultAnimations(requireContext(), getChildFragmentManager(), getId()));
59+
}
60+
}

app/src/main/java/awais/instagrabber/customviews/PostsRecyclerView.java

+17-12
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import android.content.Context;
44
import android.util.AttributeSet;
55
import android.util.Log;
6+
import android.view.View;
7+
import android.view.ViewGroup;
68

79
import androidx.annotation.NonNull;
810
import androidx.annotation.Nullable;
@@ -25,6 +27,7 @@
2527
import java.util.Arrays;
2628
import java.util.Collections;
2729
import java.util.List;
30+
import java.util.function.Function;
2831

2932
import awais.instagrabber.adapters.FeedAdapterV2;
3033
import awais.instagrabber.customviews.helpers.GridSpacingItemDecoration;
@@ -60,14 +63,17 @@ public class PostsRecyclerView extends RecyclerView {
6063
private FeedAdapterV2.FeedItemCallback feedItemCallback;
6164
private boolean shouldScrollToTop;
6265
private FeedAdapterV2.SelectionModeCallback selectionModeCallback;
66+
private Function<ViewGroup, View> headerViewCreator;
67+
private Function<View, Void> headerBinder;
68+
private boolean refresh = true;
6369

6470
private final List<FetchStatusChangeListener> fetchStatusChangeListeners = new ArrayList<>();
6571

6672
private final FetchListener<List<Media>> fetchListener = new FetchListener<List<Media>>() {
6773
@Override
6874
public void onResult(final List<Media> result) {
69-
final int currentPage = lazyLoader.getCurrentPage();
70-
if (currentPage == 0) {
75+
if (refresh) {
76+
refresh = false;
7177
mediaViewModel.getList().postValue(result);
7278
shouldScrollToTop = true;
7379
dispatchFetchStatus();
@@ -198,21 +204,19 @@ private void initSelf() {
198204
Log.e(TAG, "initSelf: ", e);
199205
}
200206
if (mediaViewModel == null) return;
201-
mediaViewModel.getList().observe(lifeCycleOwner, list -> {
202-
if (list.size() <= 0) return;
203-
feedAdapter.submitList(list, () -> {
204-
// postDelayed(this::fetchMoreIfPossible, 1000);
205-
if (!shouldScrollToTop) return;
206-
smoothScrollToPosition(0);
207-
shouldScrollToTop = false;
208-
});
209-
});
207+
mediaViewModel.getList().observe(lifeCycleOwner, list -> feedAdapter.submitList(list, () -> {
208+
// postDelayed(this::fetchMoreIfPossible, 1000);
209+
if (!shouldScrollToTop) return;
210+
shouldScrollToTop = false;
211+
post(() -> smoothScrollToPosition(0));
212+
}));
210213
postFetcher = new PostFetcher(postFetchService, fetchListener);
211214
if (layoutPreferences.getHasGap()) {
212215
addItemDecoration(gridSpacingItemDecoration);
213216
}
214217
setHasFixedSize(true);
215218
setNestedScrollingEnabled(true);
219+
setItemAnimator(null);
216220
lazyLoader = new RecyclerLazyLoaderAtEdge(layoutManager, (page) -> {
217221
if (postFetcher.hasMore()) {
218222
postFetcher.fetch();
@@ -316,11 +320,12 @@ private void updateLayout() {
316320
}
317321

318322
public void refresh() {
323+
refresh = true;
319324
if (lazyLoader != null) {
320325
lazyLoader.resetState();
321326
}
322327
if (postFetcher != null) {
323-
mediaViewModel.getList().postValue(Collections.emptyList());
328+
// mediaViewModel.getList().postValue(Collections.emptyList());
324329
postFetcher.reset();
325330
postFetcher.fetch();
326331
}

app/src/main/java/awais/instagrabber/customviews/drawee/ZoomableDraweeView.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ public void setIsLongpressEnabled(boolean enabled) {
228228

229229
public void setZoomingEnabled(boolean zoomingEnabled) {
230230
mZoomingEnabled = zoomingEnabled;
231-
mZoomableController.setEnabled(false);
231+
mZoomableController.setEnabled(zoomingEnabled);
232232
}
233233

234234
/**

app/src/main/java/awais/instagrabber/customviews/helpers/GridSpacingItemDecoration.java

+15-4
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,33 @@
77
import androidx.recyclerview.widget.RecyclerView;
88

99
public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {
10-
private final int spacing;
10+
private final int halfSpace;
11+
12+
private boolean hasHeader;
1113

1214
public GridSpacingItemDecoration(int spacing) {
13-
this.spacing = spacing;
15+
halfSpace = spacing / 2;
1416
}
1517

1618
@Override
1719
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
18-
final int halfSpace = spacing / 2;
20+
if (hasHeader && parent.getChildAdapterPosition(view) == 0) {
21+
outRect.bottom = halfSpace;
22+
outRect.left = -halfSpace;
23+
outRect.right = -halfSpace;
24+
return;
25+
}
1926
if (parent.getPaddingLeft() != halfSpace) {
20-
parent.setPadding(halfSpace, halfSpace, halfSpace, halfSpace);
27+
parent.setPadding(halfSpace, hasHeader ? 0 : halfSpace, halfSpace, halfSpace);
2128
parent.setClipToPadding(false);
2229
}
2330
outRect.top = halfSpace;
2431
outRect.bottom = halfSpace;
2532
outRect.left = halfSpace;
2633
outRect.right = halfSpace;
2734
}
35+
36+
public void setHasHeader(final boolean hasHeader) {
37+
this.hasHeader = hasHeader;
38+
}
2839
}

0 commit comments

Comments
 (0)