mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-10-31 23:32:59 +00:00 
			
		
		
		
	Merge pull request #3281 from mauriciocolli/fix-main-screen-menu-creation
Temporary fix for main screen menu visibility
This commit is contained in:
		| @@ -0,0 +1,318 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright 2018 The Android Open Source Project | ||||||
|  |  * | ||||||
|  |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |  * you may not use this file except in compliance with the License. | ||||||
|  |  * You may obtain a copy of the License at | ||||||
|  |  * | ||||||
|  |  *      http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  * | ||||||
|  |  * Unless required by applicable law or agreed to in writing, software | ||||||
|  |  * distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |  * See the License for the specific language governing permissions and | ||||||
|  |  * limitations under the License. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package androidx.fragment.app; | ||||||
|  |  | ||||||
|  | import android.os.Bundle; | ||||||
|  | import android.os.Parcelable; | ||||||
|  | import android.util.Log; | ||||||
|  | import android.view.View; | ||||||
|  | import android.view.ViewGroup; | ||||||
|  |  | ||||||
|  | import androidx.annotation.IntDef; | ||||||
|  | import androidx.annotation.NonNull; | ||||||
|  | import androidx.annotation.Nullable; | ||||||
|  | import androidx.lifecycle.Lifecycle; | ||||||
|  | import androidx.viewpager.widget.PagerAdapter; | ||||||
|  |  | ||||||
|  | import java.lang.annotation.Retention; | ||||||
|  | import java.lang.annotation.RetentionPolicy; | ||||||
|  | import java.util.ArrayList; | ||||||
|  |  | ||||||
|  | // TODO: Replace this deprecated class with its ViewPager2 counterpart | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * This is a copy from {@link androidx.fragment.app.FragmentStatePagerAdapter}. | ||||||
|  |  * <p> | ||||||
|  |  * It includes a workaround to fix the menu visibility when the adapter is restored. | ||||||
|  |  * <p> | ||||||
|  |  * When restoring the state of this adapter, all the fragments' menu visibility were set to false, | ||||||
|  |  * effectively disabling the menu from the user until he switched pages or another event that triggered the | ||||||
|  |  * menu to be visible again happened. | ||||||
|  |  * <p> | ||||||
|  |  * <br><b>Check out the changes in:</b> | ||||||
|  |  * <ul> | ||||||
|  |  *     <li>{@link #saveState()}</li> | ||||||
|  |  *     <li>{@link #restoreState(Parcelable, ClassLoader)}</li> | ||||||
|  |  * </ul> | ||||||
|  |  */ | ||||||
|  | @SuppressWarnings("deprecation") | ||||||
|  | public abstract class FragmentStatePagerAdapterMenuWorkaround extends PagerAdapter { | ||||||
|  |     private static final String TAG = "FragmentStatePagerAdapt"; | ||||||
|  |     private static final boolean DEBUG = false; | ||||||
|  |  | ||||||
|  |     @Retention(RetentionPolicy.SOURCE) | ||||||
|  |     @IntDef({BEHAVIOR_SET_USER_VISIBLE_HINT, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT}) | ||||||
|  |     private @interface Behavior { } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Indicates that {@link Fragment#setUserVisibleHint(boolean)} will be called when the current | ||||||
|  |      * fragment changes. | ||||||
|  |      * | ||||||
|  |      * @deprecated This behavior relies on the deprecated | ||||||
|  |      * {@link Fragment#setUserVisibleHint(boolean)} API. Use | ||||||
|  |      * {@link #BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT} to switch to its replacement, | ||||||
|  |      * {@link FragmentTransaction#setMaxLifecycle}. | ||||||
|  |      * @see #FragmentStatePagerAdapterMenuWorkaround(FragmentManager, int) | ||||||
|  |      */ | ||||||
|  |     @Deprecated | ||||||
|  |     public static final int BEHAVIOR_SET_USER_VISIBLE_HINT = 0; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Indicates that only the current fragment will be in the {@link Lifecycle.State#RESUMED} | ||||||
|  |      * state. All other Fragments are capped at {@link Lifecycle.State#STARTED}. | ||||||
|  |      * | ||||||
|  |      * @see #FragmentStatePagerAdapterMenuWorkaround(FragmentManager, int) | ||||||
|  |      */ | ||||||
|  |     public static final int BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT = 1; | ||||||
|  |  | ||||||
|  |     private final FragmentManager mFragmentManager; | ||||||
|  |     private final int mBehavior; | ||||||
|  |     private FragmentTransaction mCurTransaction = null; | ||||||
|  |  | ||||||
|  |     private ArrayList<Fragment.SavedState> mSavedState = new ArrayList<Fragment.SavedState>(); | ||||||
|  |     private ArrayList<Fragment> mFragments = new ArrayList<Fragment>(); | ||||||
|  |     private Fragment mCurrentPrimaryItem = null; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Constructor for {@link FragmentStatePagerAdapterMenuWorkaround} that sets the fragment manager for the | ||||||
|  |      * adapter. This is the equivalent of calling | ||||||
|  |      * {@link #FragmentStatePagerAdapterMenuWorkaround(FragmentManager, int)} and passing in | ||||||
|  |      * {@link #BEHAVIOR_SET_USER_VISIBLE_HINT}. | ||||||
|  |      * | ||||||
|  |      * <p>Fragments will have {@link Fragment#setUserVisibleHint(boolean)} called whenever the | ||||||
|  |      * current Fragment changes.</p> | ||||||
|  |      * | ||||||
|  |      * @param fm fragment manager that will interact with this adapter | ||||||
|  |      * @deprecated use {@link #FragmentStatePagerAdapterMenuWorkaround(FragmentManager, int)} with | ||||||
|  |      * {@link #BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT} | ||||||
|  |      */ | ||||||
|  |     @Deprecated | ||||||
|  |     public FragmentStatePagerAdapterMenuWorkaround(@NonNull FragmentManager fm) { | ||||||
|  |         this(fm, BEHAVIOR_SET_USER_VISIBLE_HINT); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Constructor for {@link FragmentStatePagerAdapterMenuWorkaround}. | ||||||
|  |      * | ||||||
|  |      * If {@link #BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT} is passed in, then only the current | ||||||
|  |      * Fragment is in the {@link Lifecycle.State#RESUMED} state, while all other fragments are | ||||||
|  |      * capped at {@link Lifecycle.State#STARTED}. If {@link #BEHAVIOR_SET_USER_VISIBLE_HINT} is | ||||||
|  |      * passed, all fragments are in the {@link Lifecycle.State#RESUMED} state and there will be | ||||||
|  |      * callbacks to {@link Fragment#setUserVisibleHint(boolean)}. | ||||||
|  |      * | ||||||
|  |      * @param fm fragment manager that will interact with this adapter | ||||||
|  |      * @param behavior determines if only current fragments are in a resumed state | ||||||
|  |      */ | ||||||
|  |     public FragmentStatePagerAdapterMenuWorkaround(@NonNull FragmentManager fm, | ||||||
|  |                                      @Behavior int behavior) { | ||||||
|  |         mFragmentManager = fm; | ||||||
|  |         mBehavior = behavior; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Return the Fragment associated with a specified position. | ||||||
|  |      */ | ||||||
|  |     @NonNull | ||||||
|  |     public abstract Fragment getItem(int position); | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void startUpdate(@NonNull ViewGroup container) { | ||||||
|  |         if (container.getId() == View.NO_ID) { | ||||||
|  |             throw new IllegalStateException("ViewPager with adapter " + this | ||||||
|  |                     + " requires a view id"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @SuppressWarnings("deprecation") | ||||||
|  |     @NonNull | ||||||
|  |     @Override | ||||||
|  |     public Object instantiateItem(@NonNull ViewGroup container, int position) { | ||||||
|  |         // If we already have this item instantiated, there is nothing | ||||||
|  |         // to do.  This can happen when we are restoring the entire pager | ||||||
|  |         // from its saved state, where the fragment manager has already | ||||||
|  |         // taken care of restoring the fragments we previously had instantiated. | ||||||
|  |         if (mFragments.size() > position) { | ||||||
|  |             Fragment f = mFragments.get(position); | ||||||
|  |             if (f != null) { | ||||||
|  |                 return f; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (mCurTransaction == null) { | ||||||
|  |             mCurTransaction = mFragmentManager.beginTransaction(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         Fragment fragment = getItem(position); | ||||||
|  |         if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment); | ||||||
|  |         if (mSavedState.size() > position) { | ||||||
|  |             Fragment.SavedState fss = mSavedState.get(position); | ||||||
|  |             if (fss != null) { | ||||||
|  |                 fragment.setInitialSavedState(fss); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         while (mFragments.size() <= position) { | ||||||
|  |             mFragments.add(null); | ||||||
|  |         } | ||||||
|  |         fragment.setMenuVisibility(false); | ||||||
|  |         if (mBehavior == BEHAVIOR_SET_USER_VISIBLE_HINT) { | ||||||
|  |             fragment.setUserVisibleHint(false); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         mFragments.set(position, fragment); | ||||||
|  |         mCurTransaction.add(container.getId(), fragment); | ||||||
|  |  | ||||||
|  |         if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { | ||||||
|  |             mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.STARTED); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return fragment; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { | ||||||
|  |         Fragment fragment = (Fragment) object; | ||||||
|  |  | ||||||
|  |         if (mCurTransaction == null) { | ||||||
|  |             mCurTransaction = mFragmentManager.beginTransaction(); | ||||||
|  |         } | ||||||
|  |         if (DEBUG) Log.v(TAG, "Removing item #" + position + ": f=" + object | ||||||
|  |                 + " v=" + ((Fragment)object).getView()); | ||||||
|  |         while (mSavedState.size() <= position) { | ||||||
|  |             mSavedState.add(null); | ||||||
|  |         } | ||||||
|  |         mSavedState.set(position, fragment.isAdded() | ||||||
|  |                 ? mFragmentManager.saveFragmentInstanceState(fragment) : null); | ||||||
|  |         mFragments.set(position, null); | ||||||
|  |  | ||||||
|  |         mCurTransaction.remove(fragment); | ||||||
|  |         if (fragment == mCurrentPrimaryItem) { | ||||||
|  |             mCurrentPrimaryItem = null; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     @SuppressWarnings({"ReferenceEquality", "deprecation"}) | ||||||
|  |     public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) { | ||||||
|  |         Fragment fragment = (Fragment)object; | ||||||
|  |         if (fragment != mCurrentPrimaryItem) { | ||||||
|  |             if (mCurrentPrimaryItem != null) { | ||||||
|  |                 mCurrentPrimaryItem.setMenuVisibility(false); | ||||||
|  |                 if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { | ||||||
|  |                     if (mCurTransaction == null) { | ||||||
|  |                         mCurTransaction = mFragmentManager.beginTransaction(); | ||||||
|  |                     } | ||||||
|  |                     mCurTransaction.setMaxLifecycle(mCurrentPrimaryItem, Lifecycle.State.STARTED); | ||||||
|  |                 } else { | ||||||
|  |                     mCurrentPrimaryItem.setUserVisibleHint(false); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             fragment.setMenuVisibility(true); | ||||||
|  |             if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { | ||||||
|  |                 if (mCurTransaction == null) { | ||||||
|  |                     mCurTransaction = mFragmentManager.beginTransaction(); | ||||||
|  |                 } | ||||||
|  |                 mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.RESUMED); | ||||||
|  |             } else { | ||||||
|  |                 fragment.setUserVisibleHint(true); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             mCurrentPrimaryItem = fragment; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void finishUpdate(@NonNull ViewGroup container) { | ||||||
|  |         if (mCurTransaction != null) { | ||||||
|  |             mCurTransaction.commitNowAllowingStateLoss(); | ||||||
|  |             mCurTransaction = null; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { | ||||||
|  |         return ((Fragment)object).getView() == view; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||||||
|  |     private final String SELECTED_FRAGMENT = "selected_fragment"; | ||||||
|  |     //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     @Nullable | ||||||
|  |     public Parcelable saveState() { | ||||||
|  |         Bundle state = null; | ||||||
|  |         if (mSavedState.size() > 0) { | ||||||
|  |             state = new Bundle(); | ||||||
|  |             Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()]; | ||||||
|  |             mSavedState.toArray(fss); | ||||||
|  |             state.putParcelableArray("states", fss); | ||||||
|  |         } | ||||||
|  |         for (int i=0; i<mFragments.size(); i++) { | ||||||
|  |             Fragment f = mFragments.get(i); | ||||||
|  |             if (f != null && f.isAdded()) { | ||||||
|  |                 if (state == null) { | ||||||
|  |                     state = new Bundle(); | ||||||
|  |                 } | ||||||
|  |                 String key = "f" + i; | ||||||
|  |                 mFragmentManager.putFragment(state, key, f); | ||||||
|  |  | ||||||
|  |                 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||||||
|  |                 // Check if it's the same fragment instance | ||||||
|  |                 if (f == mCurrentPrimaryItem) { | ||||||
|  |                     state.putString(SELECTED_FRAGMENT, key); | ||||||
|  |                 } | ||||||
|  |                 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return state; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void restoreState(@Nullable Parcelable state, @Nullable ClassLoader loader) { | ||||||
|  |         if (state != null) { | ||||||
|  |             Bundle bundle = (Bundle)state; | ||||||
|  |             bundle.setClassLoader(loader); | ||||||
|  |             Parcelable[] fss = bundle.getParcelableArray("states"); | ||||||
|  |             mSavedState.clear(); | ||||||
|  |             mFragments.clear(); | ||||||
|  |             if (fss != null) { | ||||||
|  |                 for (int i=0; i<fss.length; i++) { | ||||||
|  |                     mSavedState.add((Fragment.SavedState)fss[i]); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             Iterable<String> keys = bundle.keySet(); | ||||||
|  |             for (String key: keys) { | ||||||
|  |                 if (key.startsWith("f")) { | ||||||
|  |                     int index = Integer.parseInt(key.substring(1)); | ||||||
|  |                     Fragment f = mFragmentManager.getFragment(bundle, key); | ||||||
|  |                     if (f != null) { | ||||||
|  |                         while (mFragments.size() <= index) { | ||||||
|  |                             mFragments.add(null); | ||||||
|  |                         } | ||||||
|  |                         //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||||||
|  |                         final boolean wasSelected = bundle.getString(SELECTED_FRAGMENT, "").equals(key); | ||||||
|  |                         f.setMenuVisibility(wasSelected); | ||||||
|  |                         //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||||||
|  |                         mFragments.set(index, f); | ||||||
|  |                     } else { | ||||||
|  |                         Log.w(TAG, "Bad fragment at key " + key); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -16,7 +16,7 @@ import androidx.appcompat.app.ActionBar; | |||||||
| import androidx.appcompat.app.AppCompatActivity; | import androidx.appcompat.app.AppCompatActivity; | ||||||
| import androidx.fragment.app.Fragment; | import androidx.fragment.app.Fragment; | ||||||
| import androidx.fragment.app.FragmentManager; | import androidx.fragment.app.FragmentManager; | ||||||
| import androidx.fragment.app.FragmentStatePagerAdapter; | import androidx.fragment.app.FragmentStatePagerAdapterMenuWorkaround; | ||||||
| import androidx.viewpager.widget.ViewPager; | import androidx.viewpager.widget.ViewPager; | ||||||
|  |  | ||||||
| import com.google.android.material.tabs.TabLayout; | import com.google.android.material.tabs.TabLayout; | ||||||
| @@ -185,7 +185,7 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte | |||||||
|         updateTitleForTab(tab.getPosition()); |         updateTitleForTab(tab.getPosition()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private static class SelectedTabsPagerAdapter extends FragmentStatePagerAdapter { |     private static class SelectedTabsPagerAdapter extends FragmentStatePagerAdapterMenuWorkaround { | ||||||
|         private final Context context; |         private final Context context; | ||||||
|         private final List<Tab> internalTabsList; |         private final List<Tab> internalTabsList; | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Tobias Groza
					Tobias Groza