mirror of https://github.com/KokaKiwi/BarInsta
248 lines
13 KiB
Java
248 lines
13 KiB
Java
package awais.instagrabber.utils;
|
|
|
|
import android.annotation.SuppressLint;
|
|
import android.content.Intent;
|
|
import android.util.Log;
|
|
import android.util.SparseArray;
|
|
|
|
import androidx.annotation.NonNull;
|
|
import androidx.fragment.app.Fragment;
|
|
import androidx.fragment.app.FragmentManager;
|
|
import androidx.fragment.app.FragmentTransaction;
|
|
import androidx.lifecycle.LiveData;
|
|
import androidx.lifecycle.MutableLiveData;
|
|
import androidx.navigation.NavController;
|
|
import androidx.navigation.NavDestination;
|
|
import androidx.navigation.NavGraph;
|
|
import androidx.navigation.fragment.NavHostFragment;
|
|
|
|
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;
|
|
|
|
/**
|
|
* This is a Java rewrite of <a href="https://github.com/android/architecture-components-samples/blob/master/NavigationAdvancedSample/app/src/main/java/com/example/android/navigationadvancedsample/NavigationExtensions.kt">NavigationExtensions</a>
|
|
* from architecture-components-samples. Some modifications have been done, check git history.
|
|
*/
|
|
public class NavigationExtensions {
|
|
private static final String TAG = NavigationExtensions.class.getSimpleName();
|
|
private static String selectedItemTag;
|
|
private static boolean isOnFirstFragment;
|
|
|
|
@NonNull
|
|
public static LiveData<NavController> setupWithNavController(@NonNull final BottomNavigationView bottomNavigationView,
|
|
@NonNull List<Integer> navGraphIds,
|
|
@NonNull final FragmentManager fragmentManager,
|
|
final int containerId,
|
|
@NonNull Intent intent,
|
|
final int firstFragmentGraphIndex) {
|
|
final SparseArray<String> graphIdToTagMap = new SparseArray<>();
|
|
final MutableLiveData<NavController> selectedNavController = new MutableLiveData<>();
|
|
int firstFragmentGraphId = 0;
|
|
for (int i = 0; i < navGraphIds.size(); i++) {
|
|
final int navGraphId = navGraphIds.get(i);
|
|
final String fragmentTag = getFragmentTag(navGraphId);
|
|
final NavHostFragment navHostFragment = obtainNavHostFragment(fragmentManager, fragmentTag, navGraphId, containerId);
|
|
final NavController navController = navHostFragment.getNavController();
|
|
final int graphId = navController.getGraph().getId();
|
|
if (i == firstFragmentGraphIndex) {
|
|
firstFragmentGraphId = graphId;
|
|
}
|
|
graphIdToTagMap.put(graphId, fragmentTag);
|
|
if (bottomNavigationView.getSelectedItemId() == graphId) {
|
|
selectedNavController.setValue(navHostFragment.getNavController());
|
|
attachNavHostFragment(fragmentManager, navHostFragment, i == firstFragmentGraphIndex);
|
|
} else {
|
|
detachNavHostFragment(fragmentManager, navHostFragment);
|
|
}
|
|
}
|
|
selectedItemTag = graphIdToTagMap.get(bottomNavigationView.getSelectedItemId());
|
|
final String firstFragmentTag = graphIdToTagMap.get(firstFragmentGraphId);
|
|
isOnFirstFragment = selectedItemTag != null && selectedItemTag.equals(firstFragmentTag);
|
|
bottomNavigationView.setOnNavigationItemSelectedListener(item -> {
|
|
if (fragmentManager.isStateSaved()) {
|
|
return false;
|
|
}
|
|
String newlySelectedItemTag = graphIdToTagMap.get(item.getItemId());
|
|
String tag = selectedItemTag;
|
|
if (tag != null && !tag.equals(newlySelectedItemTag)) {
|
|
fragmentManager.popBackStack(firstFragmentTag, FragmentManager.POP_BACK_STACK_INCLUSIVE);
|
|
Fragment fragment = fragmentManager.findFragmentByTag(newlySelectedItemTag);
|
|
if (fragment == null) {
|
|
return false;
|
|
// throw new RuntimeException("null cannot be cast to non-null NavHostFragment");
|
|
}
|
|
final NavHostFragment selectedFragment = (NavHostFragment) fragment;
|
|
if (firstFragmentTag != null && !firstFragmentTag.equals(newlySelectedItemTag)) {
|
|
FragmentTransaction fragmentTransaction = fragmentManager
|
|
.beginTransaction()
|
|
.setCustomAnimations(
|
|
R.anim.nav_default_enter_anim,
|
|
R.anim.nav_default_exit_anim,
|
|
R.anim.nav_default_pop_enter_anim,
|
|
R.anim.nav_default_pop_exit_anim
|
|
)
|
|
.attach(selectedFragment)
|
|
.setPrimaryNavigationFragment(selectedFragment);
|
|
for (int i = 0; i < graphIdToTagMap.size(); i++) {
|
|
final int key = graphIdToTagMap.keyAt(i);
|
|
final String fragmentTagForId = graphIdToTagMap.get(key);
|
|
if (!fragmentTagForId.equals(newlySelectedItemTag)) {
|
|
final Fragment fragmentByTag = fragmentManager.findFragmentByTag(firstFragmentTag);
|
|
if (fragmentByTag == null) {
|
|
continue;
|
|
}
|
|
fragmentTransaction.detach(fragmentByTag);
|
|
}
|
|
}
|
|
fragmentTransaction.addToBackStack(firstFragmentTag)
|
|
.setReorderingAllowed(true)
|
|
.commit();
|
|
}
|
|
selectedItemTag = newlySelectedItemTag;
|
|
isOnFirstFragment = selectedItemTag.equals(firstFragmentTag);
|
|
selectedNavController.setValue(selectedFragment.getNavController());
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
setupItemReselected(bottomNavigationView, graphIdToTagMap, fragmentManager);
|
|
setupDeepLinks(bottomNavigationView, navGraphIds, fragmentManager, containerId, intent);
|
|
final int finalFirstFragmentGraphId = firstFragmentGraphId;
|
|
fragmentManager.addOnBackStackChangedListener(() -> {
|
|
if (!isOnFirstFragment) {
|
|
if (firstFragmentTag == null) {
|
|
return;
|
|
}
|
|
if (!isOnBackStack(fragmentManager, firstFragmentTag)) {
|
|
bottomNavigationView.setSelectedItemId(finalFirstFragmentGraphId);
|
|
}
|
|
}
|
|
|
|
final NavController navController = selectedNavController.getValue();
|
|
if (navController != null && navController.getCurrentDestination() == null) {
|
|
final NavGraph navControllerGraph = navController.getGraph();
|
|
navController.navigate(navControllerGraph.getId());
|
|
}
|
|
});
|
|
return selectedNavController;
|
|
}
|
|
|
|
private static NavHostFragment obtainNavHostFragment(final FragmentManager fragmentManager,
|
|
final String fragmentTag,
|
|
final int navGraphId,
|
|
final int containerId) {
|
|
final NavHostFragment existingFragment = (NavHostFragment) fragmentManager.findFragmentByTag(fragmentTag);
|
|
if (existingFragment != null) {
|
|
return existingFragment;
|
|
}
|
|
final NavHostFragment navHostFragment = NavHostFragmentWithDefaultAnimations.create(navGraphId);
|
|
fragmentManager.beginTransaction()
|
|
.setReorderingAllowed(true)
|
|
.add(containerId, navHostFragment, fragmentTag)
|
|
.commitNow();
|
|
return navHostFragment;
|
|
}
|
|
|
|
private static void attachNavHostFragment(final FragmentManager fragmentManager,
|
|
final NavHostFragment navHostFragment,
|
|
final boolean isPrimaryNavFragment) {
|
|
final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction()
|
|
.attach(navHostFragment);
|
|
if (isPrimaryNavFragment) {
|
|
fragmentTransaction.setPrimaryNavigationFragment(navHostFragment);
|
|
}
|
|
fragmentTransaction.commitNow();
|
|
}
|
|
|
|
private static void detachNavHostFragment(final FragmentManager fragmentManager, final NavHostFragment navHostFragment) {
|
|
fragmentManager.beginTransaction()
|
|
.detach(navHostFragment)
|
|
.commitNow();
|
|
}
|
|
|
|
@SuppressLint("RestrictedApi")
|
|
private static void setupItemReselected(final BottomNavigationView bottomNavigationView,
|
|
final SparseArray<String> graphIdToTagMap,
|
|
final FragmentManager fragmentManager) {
|
|
bottomNavigationView.setOnNavigationItemReselectedListener(item -> {
|
|
final String newlySelectedItemTag = graphIdToTagMap.get(item.getItemId());
|
|
final Fragment fragmentByTag = fragmentManager.findFragmentByTag(newlySelectedItemTag);
|
|
if (fragmentByTag == null) {
|
|
return;
|
|
}
|
|
final NavHostFragment selectedFragment = (NavHostFragment) fragmentByTag;
|
|
final NavController navController = selectedFragment.getNavController();
|
|
final NavGraph navControllerGraph = navController.getGraph();
|
|
final NavDestination currentDestination = navController.getCurrentDestination();
|
|
final int startDestination = navControllerGraph.getStartDestination();
|
|
int backStackSize = navController.getBackStack().size();
|
|
if (currentDestination != null && backStackSize == 2 && currentDestination.getId() == startDestination) {
|
|
// scroll to top
|
|
final List<Fragment> fragments = selectedFragment.getChildFragmentManager().getFragments();
|
|
if (fragments.isEmpty()) return;
|
|
final Fragment fragment = fragments.get(0);
|
|
if (fragment instanceof FeedFragment) {
|
|
((FeedFragment) fragment).scrollToTop();
|
|
}
|
|
return;
|
|
}
|
|
final boolean popped = navController.popBackStack(startDestination, false);
|
|
backStackSize = navController.getBackStack().size();
|
|
if (!popped || backStackSize > 2) {
|
|
try {
|
|
// try loop pop
|
|
do {
|
|
navController.popBackStack();
|
|
backStackSize = navController.getBackStack().size();
|
|
} while (backStackSize > 2);
|
|
} catch (Exception e) {
|
|
Log.e(TAG, "setupItemReselected: ", e);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
private static void setupDeepLinks(final BottomNavigationView bottomNavigationView,
|
|
final List<Integer> navGraphIds,
|
|
final FragmentManager fragmentManager,
|
|
final int containerId,
|
|
final Intent intent) {
|
|
for (int i = 0; i < navGraphIds.size(); i++) {
|
|
final int navGraphId = navGraphIds.get(i);
|
|
final String fragmentTag = getFragmentTag(navGraphId);
|
|
final NavHostFragment navHostFragment = obtainNavHostFragment(fragmentManager, fragmentTag, navGraphId, containerId);
|
|
if (navHostFragment.getNavController().handleDeepLink(intent)) {
|
|
final int selectedItemId = bottomNavigationView.getSelectedItemId();
|
|
NavController navController = navHostFragment.getNavController();
|
|
NavGraph graph = navController.getGraph();
|
|
if (selectedItemId != graph.getId()) {
|
|
navController = navHostFragment.getNavController();
|
|
graph = navController.getGraph();
|
|
bottomNavigationView.setSelectedItemId(graph.getId());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static boolean isOnBackStack(final FragmentManager fragmentManager, final String backStackName) {
|
|
int backStackCount = fragmentManager.getBackStackEntryCount();
|
|
for (int i = 0; i < backStackCount; i++) {
|
|
final FragmentManager.BackStackEntry backStackEntry = fragmentManager.getBackStackEntryAt(i);
|
|
final String name = backStackEntry.getName();
|
|
if (name != null && name.equals(backStackName)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private static String getFragmentTag(final int index) {
|
|
return "bottomNavigation#" + index;
|
|
}
|
|
}
|