From 61de7ca6e3b2f163d68c54facf178c28059dc0e6 Mon Sep 17 00:00:00 2001 From: Fan <732388462@qq.com> Date: Sun, 19 May 2024 16:25:21 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81=E7=BB=93?= =?UTF-8?q?=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 13 +- .../ui/HyperCeilerTabActivity.java | 152 ++++++++++++ .../ui/base/HyperCeilerTabBaseActivity.java | 108 ++++++++ .../ui/base/NavigationActivity.java | 14 -- .../hyperceiler/ui/page/ContentFragment.java | 231 ++++++++++++++++++ .../ui/page/DraggableViewPager.java | 49 ++++ .../ui/page/FragmentPagerAdapter.java | 159 ++++++++++++ .../hyperceiler/ui/page/TabViewModel.java | 27 ++ app/src/main/res/drawable/ic_reboot_small.xml | 12 +- app/src/main/res/layout/fragment_content.xml | 27 ++ app/src/main/res/menu/bottom_nav_menu.xml | 25 ++ app/src/main/res/values/themes.xml | 31 +++ 12 files changed, 830 insertions(+), 18 deletions(-) create mode 100644 app/src/main/java/com/sevtinge/hyperceiler/ui/HyperCeilerTabActivity.java create mode 100644 app/src/main/java/com/sevtinge/hyperceiler/ui/base/HyperCeilerTabBaseActivity.java create mode 100644 app/src/main/java/com/sevtinge/hyperceiler/ui/page/ContentFragment.java create mode 100644 app/src/main/java/com/sevtinge/hyperceiler/ui/page/DraggableViewPager.java create mode 100644 app/src/main/java/com/sevtinge/hyperceiler/ui/page/FragmentPagerAdapter.java create mode 100644 app/src/main/java/com/sevtinge/hyperceiler/ui/page/TabViewModel.java create mode 100644 app/src/main/res/layout/fragment_content.xml create mode 100644 app/src/main/res/menu/bottom_nav_menu.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c8d469377b..0d3700c672 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -67,6 +67,17 @@ android:requestLegacyExternalStorage="true" android:supportsRtl="true" android:theme="@style/AppTheme"> + + + + + + + + diff --git a/app/src/main/java/com/sevtinge/hyperceiler/ui/HyperCeilerTabActivity.java b/app/src/main/java/com/sevtinge/hyperceiler/ui/HyperCeilerTabActivity.java new file mode 100644 index 0000000000..2069b3d800 --- /dev/null +++ b/app/src/main/java/com/sevtinge/hyperceiler/ui/HyperCeilerTabActivity.java @@ -0,0 +1,152 @@ +package com.sevtinge.hyperceiler.ui; + +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.os.Handler; + +import androidx.annotation.Nullable; + +import com.sevtinge.hyperceiler.R; +import com.sevtinge.hyperceiler.callback.IResult; +import com.sevtinge.hyperceiler.prefs.PreferenceHeader; +import com.sevtinge.hyperceiler.safe.CrashData; +import com.sevtinge.hyperceiler.ui.base.HyperCeilerTabBaseActivity; +import com.sevtinge.hyperceiler.utils.BackupUtils; +import com.sevtinge.hyperceiler.utils.Helpers; +import com.sevtinge.hyperceiler.utils.LanguageHelper; +import com.sevtinge.hyperceiler.utils.PropUtils; +import com.sevtinge.hyperceiler.utils.ThreadPoolManager; +import com.sevtinge.hyperceiler.utils.api.ProjectApi; +import com.sevtinge.hyperceiler.utils.prefs.PrefsUtils; +import com.sevtinge.hyperceiler.utils.search.SearchHelper; +import com.sevtinge.hyperceiler.utils.shell.ShellInit; + +import java.util.ArrayList; + +import fan.appcompat.app.AlertDialog; + +public class HyperCeilerTabActivity extends HyperCeilerTabBaseActivity implements IResult { + + private Handler handler; + private Context context; + + private ArrayList appCrash = new ArrayList<>(); + + @Override + protected void onCreate(Bundle bundle) { + SharedPreferences mPrefs = PrefsUtils.mSharedPreferences; + int count = Integer.parseInt(mPrefs.getString("prefs_key_settings_app_language", "-1")); + if (count != -1) { + LanguageHelper.setIndexLanguage(this, count, false); + } + handler = new Handler(this.getMainLooper()); + context = this; + int def = Integer.parseInt(PrefsUtils.mSharedPreferences.getString("prefs_key_log_level", "3")); + super.onCreate(bundle); + new Thread(() -> SearchHelper.getAllMods(this, bundle != null)).start(); + Helpers.checkXposedActivateState(this); + ShellInit.init(this); + PropUtils.setProp("persist.hyperceiler.log.level", ProjectApi.isCanary() ? (def != 3 && def != 4 ? 3 : def) : def); + appCrash = CrashData.toPkgList(); + handler.postDelayed(() -> { + if (haveCrashReport()) { + new AlertDialog.Builder(this) + .setTitle(R.string.safe_mode_later_title) + .setMessage(appCrash.toString() + " " + getString(R.string.safe_mode_later_desc)) + .setHapticFeedbackEnabled(true) + .setCancelable(false) + .setPositiveButton(R.string.safe_mode_cancel, (dialog, which) -> { + ShellInit.getShell().run("setprop persist.hyperceiler.crash.report \"\"").sync(); + dialog.dismiss(); + }) + .setNegativeButton(R.string.safe_mode_ok, (dialog, which) -> dialog.dismiss()) + .show(); + } + }, 600); + } + + @Override + public void error(String reason) { + handler.post(() -> new AlertDialog.Builder(context) + .setCancelable(false) + .setTitle(getResources().getString(R.string.tip)) + .setMessage(getResources().getString(R.string.root)) + .setHapticFeedbackEnabled(true) + .setPositiveButton(android.R.string.ok, null) + .show()); + } + + private boolean haveCrashReport() { + return !appCrash.isEmpty(); + } + + @Override + public void onDestroy() { + ShellInit.destroy(); + ThreadPoolManager.shutdown(); + PreferenceHeader.mUninstallApp.clear(); + PreferenceHeader.mDisableOrHiddenApp.clear(); + super.onDestroy(); + } + + public void test() { + /*boolean ls = shellExec.append("ls").sync().isResult(); + AndroidLogUtils.LogI(ITAG.TAG, "ls: " + ls); + AndroidLogUtils.LogI(ITAG.TAG, shellExec.getOutPut().toString() + shellExec.getError().toString()); + boolean f = shellExec.append("for i in $(seq 1 500); do echo $i; done").isResult(); + AndroidLogUtils.LogI(ITAG.TAG, "for: " + f); + AndroidLogUtils.LogI(ITAG.TAG, shellExec.getOutPut().toString()); + boolean k = shellExec.append("for i in $(seq 1 500); do echo $i; done").sync().isResult(); + AndroidLogUtils.LogI(ITAG.TAG, "fork: " + k); + AndroidLogUtils.LogI(ITAG.TAG, shellExec.getOutPut().toString());*/ + } + + private void requestCta() { + /*if (!CtaUtils.isCtaEnabled(this)) { + CtaUtils.showCtaDialog(this, REQUEST_CODE); + }*/ + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + requestCta(); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (data == null) return; + try { + AlertDialog.Builder alert = new AlertDialog.Builder(this); + switch (requestCode) { + case BackupUtils.CREATE_DOCUMENT_CODE -> { + BackupUtils.handleCreateDocument(this, data.getData()); + alert.setTitle(R.string.backup_success); + } + case BackupUtils.OPEN_DOCUMENT_CODE -> { + BackupUtils.handleReadDocument(this, data.getData()); + alert.setTitle(R.string.rest_success); + } + default -> { + return; + } + } + alert.setPositiveButton(android.R.string.ok, (dialog, which) -> { + }); + alert.show(); + } catch (Exception e) { + AlertDialog.Builder alert = new AlertDialog.Builder(this); + switch (requestCode) { + case BackupUtils.CREATE_DOCUMENT_CODE -> alert.setTitle(R.string.backup_failed); + case BackupUtils.OPEN_DOCUMENT_CODE -> alert.setTitle(R.string.rest_failed); + } + alert.setMessage(e.toString()); + alert.setPositiveButton(android.R.string.ok, (dialog, which) -> { + }); + alert.show(); + } + } +} diff --git a/app/src/main/java/com/sevtinge/hyperceiler/ui/base/HyperCeilerTabBaseActivity.java b/app/src/main/java/com/sevtinge/hyperceiler/ui/base/HyperCeilerTabBaseActivity.java new file mode 100644 index 0000000000..9b0ca1bb48 --- /dev/null +++ b/app/src/main/java/com/sevtinge/hyperceiler/ui/base/HyperCeilerTabBaseActivity.java @@ -0,0 +1,108 @@ +package com.sevtinge.hyperceiler.ui.base; + +import android.os.Bundle; + +import androidx.annotation.NonNull; + +import com.sevtinge.hyperceiler.R; +import com.sevtinge.hyperceiler.ui.SubSettings; +import com.sevtinge.hyperceiler.ui.page.ContentFragment; +import com.sevtinge.hyperceiler.utils.SettingLauncherHelper; + +import fan.appcompat.app.Fragment; +import fan.navigator.Navigator; +import fan.navigator.NavigatorStrategy; +import fan.navigator.app.NavigatorActivity; +import fan.navigator.navigatorinfo.NavigatorInfoProvider; +import fan.navigator.navigatorinfo.UpdateFragmentNavInfo; +import fan.preference.Preference; +import fan.preference.PreferenceFragment; +import fan.preference.core.PreferenceFragmentCompat; + +public class HyperCeilerTabBaseActivity extends NavigatorActivity + implements PreferenceFragment.OnPreferenceStartFragmentCallback { + + @Override + public int getBottomTabMenu() { + return R.menu.bottom_nav_menu; + } + + @Override + public NavigatorInfoProvider getBottomTabMenuNavInfoProvider() { + Bundle bundle = new Bundle(); + return i -> { + if (i == 1000) { + bundle.putInt("page", 0); + } else if (i == 1001) { + bundle.putInt("page", 1); + } else if (i == 1002) { + bundle.putInt("page", 2); + } else { + return null; + } + return new UpdateFragmentNavInfo(i, getDefaultContentFragment(), bundle); + }; + } + + @Override + public Class getDefaultContentFragment() { + return ContentFragment.class; + } + + @Override + public int getNavigationOptionMenu() { + return 0; + } + + @Override + public Bundle getNavigatorInitArgs() { + NavigatorStrategy navigatorStrategy = new NavigatorStrategy(); + navigatorStrategy.setLargeMode(Navigator.Mode.C); + Bundle bundle = new Bundle(); + bundle.putParcelable("miuix:navigatorStrategy", navigatorStrategy); + return bundle; + } + + @Override + public void onCreateOtherNavigation(Navigator navigator, Bundle bundle) { + + } + + @Override + public void onCreatePrimaryNavigation(Navigator navigator, Bundle bundle) { + UpdateFragmentNavInfo updateFragmentNavInfoToHome = getUpdateFragmentNavInfoToHome(); + UpdateFragmentNavInfo updateFragmentNavInfoToSettings = updateFragmentNavInfoToSettings(); + UpdateFragmentNavInfo updateFragmentNavInfoToClock = getUpdateFragmentNavInfoToAbout(); + newLabel(getString(R.string.home), updateFragmentNavInfoToHome); + newLabel(getString(R.string.settings), updateFragmentNavInfoToSettings); + newLabel(getString(R.string.about), updateFragmentNavInfoToClock); + navigator.navigate(updateFragmentNavInfoToHome); + } + + private UpdateFragmentNavInfo getUpdateFragmentNavInfoToHome() { + Bundle bundle = new Bundle(); + bundle.putInt("page", 0); + return new UpdateFragmentNavInfo(1000, getDefaultContentFragment(), bundle); + } + + private UpdateFragmentNavInfo updateFragmentNavInfoToSettings() { + Bundle bundle = new Bundle(); + bundle.putInt("page", 1); + return new UpdateFragmentNavInfo(1001, getDefaultContentFragment(), bundle); + } + + private UpdateFragmentNavInfo getUpdateFragmentNavInfoToAbout() { + Bundle bundle = new Bundle(); + bundle.putInt("page", 2); + return new UpdateFragmentNavInfo(1002, getDefaultContentFragment(), bundle); + } + + @Override + public boolean onPreferenceStartFragment(@NonNull PreferenceFragmentCompat preferenceFragmentCompat, @NonNull Preference preference) { + Bundle args = null; + String mFragmentName = preference.getFragment(); + String mTitle = preference.getTitle().toString(); + SettingLauncherHelper.onStartSettingsForArguments(this, SubSettings.class, mFragmentName, args, mTitle); + return true; + } +} diff --git a/app/src/main/java/com/sevtinge/hyperceiler/ui/base/NavigationActivity.java b/app/src/main/java/com/sevtinge/hyperceiler/ui/base/NavigationActivity.java index 05b74683c0..039b807124 100644 --- a/app/src/main/java/com/sevtinge/hyperceiler/ui/base/NavigationActivity.java +++ b/app/src/main/java/com/sevtinge/hyperceiler/ui/base/NavigationActivity.java @@ -259,18 +259,4 @@ public boolean onPreferenceStartFragment(@NonNull PreferenceFragmentCompat prefe mProxy.onStartSettingsForArguments(SubSettings.class, preference, false); return true; } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.menu_main, menu); - return super.onCreateOptionsMenu(menu); - } - - @Override - public boolean onOptionsItemSelected(@NonNull MenuItem item) { - if (item.getItemId() == R.id.restart) { - DialogHelper.showRestartDialog(this); - } - return super.onOptionsItemSelected(item); - } } diff --git a/app/src/main/java/com/sevtinge/hyperceiler/ui/page/ContentFragment.java b/app/src/main/java/com/sevtinge/hyperceiler/ui/page/ContentFragment.java new file mode 100644 index 0000000000..bbd18ff43f --- /dev/null +++ b/app/src/main/java/com/sevtinge/hyperceiler/ui/page/ContentFragment.java @@ -0,0 +1,231 @@ +package com.sevtinge.hyperceiler.ui.page; + +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.viewpager.widget.ViewPager; + +import com.sevtinge.hyperceiler.R; +import com.sevtinge.hyperceiler.utils.DialogHelper; + +import fan.appcompat.app.ActionBar; +import fan.appcompat.app.Fragment; +import fan.navigator.Navigator; +import fan.navigator.NavigatorFragmentListener; +import fan.navigator.navigatorinfo.UpdateFragmentNavInfo; +import fan.nestedheader.widget.NestedHeaderLayout; + +public class ContentFragment extends Fragment implements NavigatorFragmentListener { + + private static final String TAG = "ContentFragment"; + public static final String ARG_PAGE = "page"; + public static String mCurrTab = "HOME"; + private ActionBar mActionBar; + private NestedHeaderLayout mNestedHeaderLayout; + private DraggableViewPager mViewPager; + private FragmentPagerAdapter mViewPagerAdapter; + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setThemeRes(R.style.TabNavigatorContentFragmentTheme); + } + + @Override + public View onInflateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_content, container, false); + } + + @Override + public void onUpdateArguments(Bundle args) { + super.onUpdateArguments(args); + if (mViewPager != null) { + int position = args.getInt(ARG_PAGE, mViewPager.getCurrentItem()); + mViewPager.setCurrentItem(position, mViewPager.isDraggable()); + } + } + + @Override + public void onNavigatorModeChanged(Navigator.Mode mode, Navigator.Mode mode2) { + if (getView() != null) { + Navigator.get(this); + mViewPager.setDraggable(true); + invalidateOptionsMenu(); + } + } + + @Override + public void onViewInflated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewInflated(view, savedInstanceState); + setCorrectNestedScrollMotionEventEnabled(true); + mNestedHeaderLayout = view.findViewById(R.id.nested_header); + mViewPager = view.findViewById(R.id.viewpager); + registerCoordinateScrollView(mNestedHeaderLayout); + Navigator.get(this).setTabSelectListener((menuItem, info) -> { + int position = 0; + switch (info.getNavigationId()) { + case 1000 -> position = 0; + case 1001 -> position = 1; + case 1002 -> position = 2; + } + mViewPager.setCurrentItem(position, mViewPager.isDraggable()); + return true; + }); + setupViewPager(); + } + + private void setupViewPager() { + mActionBar = getActionBar(); + mActionBar.setResizable(true); + mActionBar.setDisplayShowCustomEnabled(false); + mActionBar.setDisplayShowTitleEnabled(true); + mActionBar.setDisplayHomeAsUpEnabled(false); + Navigator navigator = Navigator.get(this); + mViewPager.setDraggable(false); + mViewPagerAdapter = new FragmentPagerAdapter(getAppCompatActivity(), getChildFragmentManager(), mCurrTab); + mViewPager.setOffscreenPageLimit(4); + mViewPager.setAdapter(mViewPagerAdapter); + if (getArguments() != null && getArguments().containsKey(ARG_PAGE)) { + int item = getArguments().getInt(ARG_PAGE); + mViewPager.setCurrentItem(item); + if (navigator != null && navigator.getBottomTabMenu().size() > 0) { + navigator.getBottomTabMenu().getItem(item).setChecked(true); + } + setupHyperOSViewPager(item); + } + + mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { + String leftTab; + float offSet = 1.0f; + boolean isHandUp = false; + boolean isHandScroll = false; + boolean isPageChanged; + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + if (isHandScroll || (isHandUp && !isPageChanged)) { + String tabAt = TabViewModel.getTabAt(position); + leftTab = tabAt; + if (tabAt.equals(mCurrTab)) { + offSet = 1.0f - positionOffset; + } else if (position == TabViewModel.getTabPosition(mCurrTab) - 1) { + offSet = positionOffset; + } else { + offSet = 0.5f; + } + if (offSet < 0.5f) { + offSet = 0.5f; + } + } + } + + @Override + public void onPageSelected(int position) { + String tabAt = TabViewModel.getTabAt(position); + navigator.selectTab(position); + setupHyperOSViewPager(position); + handleFragmentChange(mCurrTab, tabAt); + offSet = 1.0f; + mCurrTab = tabAt; + selectNavigationItem(position); + } + + @Override + public void onPageScrollStateChanged(int state) { + if (state == 1) { + isPageChanged = false; + isHandScroll = true; + isHandUp = false; + } else if (state == 2) { + isHandScroll = false; + isHandUp = true; + } else { + isHandScroll = false; + isHandUp = false; + } + } + }); + } + + private void setupHyperOSViewPager(int position) { + if (mActionBar != null) { + if (position == 0) { + mActionBar.setTitle(R.string.home); + } else if (position == 1) { + mActionBar.setTitle(R.string.settings); + } else { + mActionBar.setTitle(R.string.about); + } + } + } + + public void selectNavigationItem(int position) { + switch (mCurrTab) { + case "HOME" -> navigateToHome(); + case "SETTINGS" -> navigateToSettings(); + case "ABOUT" -> navigateToAbout(); + default -> {} + } + } + + public void handleFragmentChange(String oldTab, String newTab) { + Log.d(TAG, "handleFragmentChange: oldTab: " + oldTab + "newTab: " + newTab); + if (newTab != null && oldTab != null && !newTab.equals(oldTab)) { + androidx.fragment.app.Fragment oldFragment = mViewPagerAdapter.getFragment(oldTab, false); + Log.d(TAG, "oldFragment: " + oldFragment); + androidx.fragment.app.Fragment newFragment = mViewPagerAdapter.getFragment(newTab, false); + Log.d(TAG, "newFragment: " + newFragment); + } + } + + public void navigateToHome() { + Navigator.get(this).navigate(getUpdateFragmentNavInfoToHome()); + } + + public void navigateToSettings() { + Navigator.get(this).navigate(getUpdateFragmentNavInfoToSettings()); + } + + public void navigateToAbout() { + Navigator.get(this).navigate(getUpdateFragmentNavInfoToAbout()); + } + + private UpdateFragmentNavInfo getUpdateFragmentNavInfoToHome() { + Bundle args = new Bundle(); + args.putInt(ARG_PAGE, 0); + return new UpdateFragmentNavInfo(1000, getClass(), args); + } + + private UpdateFragmentNavInfo getUpdateFragmentNavInfoToSettings() { + Bundle args = new Bundle(); + args.putInt(ARG_PAGE, 1); + return new UpdateFragmentNavInfo(1001, getClass(), args); + } + + private UpdateFragmentNavInfo getUpdateFragmentNavInfoToAbout() { + Bundle args = new Bundle(); + args.putInt(ARG_PAGE, 2); + return new UpdateFragmentNavInfo(1002, getClass(), args); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_main, menu); + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(@NonNull MenuItem item) { + if (item.getItemId() == R.id.restart) { + DialogHelper.showRestartDialog(requireContext()); + } + return super.onOptionsItemSelected(item); + } +} diff --git a/app/src/main/java/com/sevtinge/hyperceiler/ui/page/DraggableViewPager.java b/app/src/main/java/com/sevtinge/hyperceiler/ui/page/DraggableViewPager.java new file mode 100644 index 0000000000..35c016bea1 --- /dev/null +++ b/app/src/main/java/com/sevtinge/hyperceiler/ui/page/DraggableViewPager.java @@ -0,0 +1,49 @@ +package com.sevtinge.hyperceiler.ui.page; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +public class DraggableViewPager extends androidx.viewpager.widget.ViewPager { + + private boolean mCanDrag = false; + + public DraggableViewPager(@NonNull Context context) { + super(context); + } + + public DraggableViewPager(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + public boolean isDraggable() { + return mCanDrag; + } + + public void setDraggable(boolean isDrag) { + mCanDrag = isDrag; + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + try { + return mCanDrag ? super.onInterceptTouchEvent(ev) : false; + } catch (IllegalArgumentException e) { + e.printStackTrace(); + return false; + } + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + try { + return mCanDrag ? super.onInterceptTouchEvent(ev) : false; + } catch (IllegalArgumentException e) { + e.printStackTrace(); + return false; + } + } +} diff --git a/app/src/main/java/com/sevtinge/hyperceiler/ui/page/FragmentPagerAdapter.java b/app/src/main/java/com/sevtinge/hyperceiler/ui/page/FragmentPagerAdapter.java new file mode 100644 index 0000000000..5ba04682ee --- /dev/null +++ b/app/src/main/java/com/sevtinge/hyperceiler/ui/page/FragmentPagerAdapter.java @@ -0,0 +1,159 @@ +package com.sevtinge.hyperceiler.ui.page; + +import android.util.ArrayMap; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; +import androidx.viewpager.widget.PagerAdapter; + +import com.sevtinge.hyperceiler.ui.fragment.MainFragment; +import com.sevtinge.hyperceiler.ui.fragment.base.AboutFragment; +import com.sevtinge.hyperceiler.ui.fragment.base.settings.ModuleSettingsFragment; + +import java.util.Map; + +import fan.appcompat.app.AppCompatActivity; + +public class FragmentPagerAdapter extends PagerAdapter { + + private static final String TAG = "DynamicFragmentPagerAdapter"; + + private String mCurrTab; + private int mFragmentSize; + private AppCompatActivity mActivity; + private FragmentManager mFragmentManager; + private Fragment mCurrentPrimaryItem = null; + private FragmentTransaction mCurTransaction = null; + private final Map mFragmentCache; + + + public FragmentPagerAdapter(AppCompatActivity activity, FragmentManager fragmentManager, String tag) { + Log.d(TAG, "init, currTab: " + tag); + mCurrTab = tag; + mActivity = activity; + mFragmentManager = fragmentManager; + mFragmentCache = new ArrayMap(getCount()); + addFragment("HOME", MainFragment.class); + addFragment("SETTINGS", ModuleSettingsFragment.class); + addFragment("ABOUT", AboutFragment.class); + mFragmentSize = 3; + } + + private String getTabAt(int position) { + return TabViewModel.getTabAt(position); + } + + public void addFragment(String tag, Class clazz) { + mFragmentCache.put(tag, new FragmentInfo(tag, clazz, false)); + } + + public Fragment getFragment(String tag, boolean z) { + FragmentInfo fragmentInfo = mFragmentCache.get(tag); + if (fragmentInfo.fragment == null) { + fragmentInfo.fragment = mFragmentManager.findFragmentByTag(fragmentInfo.tag); + } + if (z && fragmentInfo.fragment == null) { + fragmentInfo.fragment = Fragment.instantiate(mActivity, fragmentInfo.clazz.getName()); + } + return fragmentInfo.fragment; + } + + private Fragment getNewFragment(String tag) { + return Fragment.instantiate(mActivity, mFragmentCache.get(tag).clazz.getName()); + } + + @NonNull + @Override + public Object instantiateItem(@NonNull ViewGroup container, int position) { + String tabAt = getTabAt(position); + if (mCurTransaction == null) { + mCurTransaction = mFragmentManager.beginTransaction(); + } + Fragment fragment = getFragment(tabAt, true); + if (fragment.getFragmentManager() != null) { + mCurTransaction.attach(fragment); + } else { + mCurTransaction.add(container.getId(), fragment, tabAt); + } + if (fragment != mCurrentPrimaryItem) { + fragment.setMenuVisibility(false); + fragment.setUserVisibleHint(false); + } + return fragment; + } + + @Override + public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { + if (mCurTransaction == null) { + mCurTransaction = mFragmentManager.beginTransaction(); + } + mCurTransaction.detach((Fragment) object); + } + + @Override + public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) { + Fragment fragment = (Fragment) object; + if (fragment != mCurrentPrimaryItem) { + if (mCurrentPrimaryItem != null) { + mCurrentPrimaryItem.setMenuVisibility(false); + mCurrentPrimaryItem.setUserVisibleHint(false); + } + if (fragment != null) { + fragment.setMenuVisibility(true); + fragment.setUserVisibleHint(true); + } + mCurrentPrimaryItem = fragment; + } + } + + @Override + public void finishUpdate(@NonNull ViewGroup container) { + if (mActivity != null && !mActivity.isDestroyed() && mCurTransaction != null) { + mCurTransaction.commitAllowingStateLoss(); + mCurTransaction = null; + if (!mFragmentManager.isDestroyed()) { + mFragmentManager.executePendingTransactions(); + } + } + } + + @Override + public int getCount() { + return mFragmentSize; + } + + @Override + public int getItemPosition(@NonNull Object object) { + for (int i = 0; i < getCount(); i++) { + if (object == mFragmentCache.get(getTabAt(i)).fragment) { + return i; + } + } + return -2; + } + + @Override + public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { + return ((Fragment) object).getView() == view; + } + + public class FragmentInfo { + + String tag; + boolean lazyInit; + Fragment fragment = null; + Class clazz; + + FragmentInfo(String tag, Class clazz, boolean lazyInit) { + this.tag = tag; + this.clazz = clazz; + this.lazyInit = lazyInit; + } + } + +} diff --git a/app/src/main/java/com/sevtinge/hyperceiler/ui/page/TabViewModel.java b/app/src/main/java/com/sevtinge/hyperceiler/ui/page/TabViewModel.java new file mode 100644 index 0000000000..06cb828586 --- /dev/null +++ b/app/src/main/java/com/sevtinge/hyperceiler/ui/page/TabViewModel.java @@ -0,0 +1,27 @@ +package com.sevtinge.hyperceiler.ui.page; + +public class TabViewModel { + public static final String TAB_HOME = "HOME"; + public static final String TAB_SETTINGS = "SETTINGS"; + public static final String TAB_ABOUT = "ABOUT"; + public static final String[] TABS = {TAB_HOME, TAB_SETTINGS, TAB_ABOUT}; + + public static String getTabAt(int position) { + return TABS[position]; + } + + public static String getTab(int position) { + if (position < 0) return null; + if (position >= TABS.length) return null; + return TABS[position]; + } + + public static int getTabPosition(String tab) { + for (int i = 0; i < TABS.length; i++) { + if (getTabAt(i).equals(tab)) { + return i; + } + } + return 0; + } +} diff --git a/app/src/main/res/drawable/ic_reboot_small.xml b/app/src/main/res/drawable/ic_reboot_small.xml index 42648737fc..e1a12c9fff 100644 --- a/app/src/main/res/drawable/ic_reboot_small.xml +++ b/app/src/main/res/drawable/ic_reboot_small.xml @@ -1,9 +1,15 @@ - + + android:viewportHeight="1024" + app:actionIconDisabledAlpha="0.3" + app:actionIconNormalAlpha="0.8" + app:actionIconPressedAlpha="0.5"> - + diff --git a/app/src/main/res/layout/fragment_content.xml b/app/src/main/res/layout/fragment_content.xml new file mode 100644 index 0000000000..137ae305be --- /dev/null +++ b/app/src/main/res/layout/fragment_content.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/menu/bottom_nav_menu.xml b/app/src/main/res/menu/bottom_nav_menu.xml new file mode 100644 index 0000000000..66b199d96b --- /dev/null +++ b/app/src/main/res/menu/bottom_nav_menu.xml @@ -0,0 +1,25 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index c38fd22980..6090651332 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -49,4 +49,35 @@ @layout/miuix_preference_widget_seekbar + + + + + + \ No newline at end of file