diff --git a/app/build.gradle b/app/build.gradle index 8bc8082..1fc49c6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,8 +10,8 @@ android { applicationId "com.fox2code.mmm" minSdk 21 targetSdk 30 - versionCode 6 - versionName "0.1.2" + versionCode 7 + versionName "0.2.0-pre1" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } @@ -51,7 +51,7 @@ dependencies { // UI implementation 'androidx.appcompat:appcompat:1.3.1' implementation 'androidx.preference:preference:1.1.1' - implementation 'androidx.constraintlayout:constraintlayout:2.1.1' + implementation 'androidx.constraintlayout:constraintlayout:2.1.2' implementation 'androidx.recyclerview:recyclerview:1.2.1' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' implementation 'com.google.android.material:material:1.4.0' diff --git a/app/src/main/java/com/fox2code/mmm/ActionButtonType.java b/app/src/main/java/com/fox2code/mmm/ActionButtonType.java index 97c9928..2e7171a 100644 --- a/app/src/main/java/com/fox2code/mmm/ActionButtonType.java +++ b/app/src/main/java/com/fox2code/mmm/ActionButtonType.java @@ -36,7 +36,8 @@ public enum ActionButtonType { @Override public void update(ImageButton button, ModuleHolder moduleHolder) { int icon = moduleHolder.hasUpdate() ? - R.drawable.ic_baseline_update_24 : R.drawable.ic_baseline_download_24; + R.drawable.ic_baseline_update_24 : + R.drawable.ic_baseline_system_update_24; button.setImageResource(icon); } diff --git a/app/src/main/java/com/fox2code/mmm/AppUpdateManager.java b/app/src/main/java/com/fox2code/mmm/AppUpdateManager.java new file mode 100644 index 0000000..cdb7dea --- /dev/null +++ b/app/src/main/java/com/fox2code/mmm/AppUpdateManager.java @@ -0,0 +1,104 @@ +package com.fox2code.mmm; + +import android.util.Log; + +import com.fox2code.mmm.utils.Http; + +import org.json.JSONArray; +import org.json.JSONObject; + +import java.nio.charset.StandardCharsets; + +// See https://docs.github.com/en/rest/reference/repos#releases +public class AppUpdateManager { + private static final String TAG = "AppUpdateManager"; + private static final AppUpdateManager INSTANCE = new AppUpdateManager(); + private static final String RELEASES_API_URL = + "https://api.github.com/repos/Fox2Code/FoxMagiskModuleManager/releases"; + + public static AppUpdateManager getAppUpdateManager() { + return INSTANCE; + } + + private final Object updateLock = new Object(); + private String latestRelease; + private String latestPreRelease; + private long lastChecked; + private boolean preReleaseNewer; + + private AppUpdateManager() { + this.latestRelease = MainApplication.getBootSharedPreferences() + .getString("updater_latest_release", BuildConfig.VERSION_NAME); + this.latestPreRelease = MainApplication.getBootSharedPreferences() + .getString("updater_latest_pre_release", BuildConfig.VERSION_NAME); + this.lastChecked = 0; + this.preReleaseNewer = true; + } + + // Return true if should show a notification + public boolean checkUpdate(boolean force) { + if (this.peekShouldUpdate()) + return true; + long lastChecked = this.lastChecked; + if (!force && lastChecked != 0 && + // Avoid spam calls by putting a 10 seconds timer + lastChecked < System.currentTimeMillis() - 10000L) + return false; + synchronized (this.updateLock) { + if (lastChecked != this.lastChecked) + return this.peekShouldUpdate(); + boolean preReleaseNewer = true; + try { + JSONArray releases = new JSONArray(new String(Http.doHttpGet( + RELEASES_API_URL, false), StandardCharsets.UTF_8)); + String latestRelease = null, latestPreRelease = null; + for (int i = releases.length() - 1; i > 0; i--) { + JSONObject release = releases.getJSONObject(i); + // Skip invalid entries + if (release.getBoolean("draft")) continue; + boolean preRelease = release.getBoolean("prerelease"); + String version = release.getString("tag_name"); + if (version.startsWith("v")) + version = version.substring(1); + if (preRelease) { + latestPreRelease = version; + } else { + latestRelease = version; + if (latestPreRelease == null) + preReleaseNewer = false; + } + if (latestRelease != null && latestPreRelease != null) { + break; // We read everything we needed to read. + } + } + if (latestRelease != null) + this.latestRelease = latestRelease; + if (latestPreRelease != null) { + this.latestPreRelease = latestPreRelease; + this.preReleaseNewer = preReleaseNewer; + } else if (!preReleaseNewer) { + this.latestPreRelease = ""; + this.preReleaseNewer = false; + } + Log.d(TAG, "Latest release: " + latestRelease); + Log.d(TAG, "Latest pre-release: " + latestPreRelease); + Log.d(TAG, "Latest pre-release newer: " + preReleaseNewer); + this.lastChecked = System.currentTimeMillis(); + } catch (Exception ioe) { + Log.e("AppUpdateManager", "Failed to check releases", ioe); + } + } + return this.peekShouldUpdate(); + } + + public boolean peekShouldUpdate() { + return !(BuildConfig.VERSION_NAME.equals(this.latestRelease) || + (this.preReleaseNewer && + BuildConfig.VERSION_NAME.equals(this.latestPreRelease))); + } + + public boolean peekHasUpdate() { + return !BuildConfig.VERSION_NAME.equals(this.preReleaseNewer ? + this.latestPreRelease : this.latestRelease); + } +} diff --git a/app/src/main/java/com/fox2code/mmm/MainActivity.java b/app/src/main/java/com/fox2code/mmm/MainActivity.java index 662d222..79ccbc3 100644 --- a/app/src/main/java/com/fox2code/mmm/MainActivity.java +++ b/app/src/main/java/com/fox2code/mmm/MainActivity.java @@ -123,6 +123,8 @@ public class MainActivity extends CompatActivity implements SwipeRefreshLayout.O }); if (!RepoManager.getINSTANCE().hasConnectivity()) moduleViewListBuilder.addNotification(NotificationType.NO_INTERNET); + else if (AppUpdateManager.getAppUpdateManager().checkUpdate(true)) + moduleViewListBuilder.addNotification(NotificationType.UPDATE_AVAILABLE); moduleViewListBuilder.appendRemoteModules(); moduleViewListBuilder.applyTo(moduleList, moduleViewAdapter); Log.i(TAG, "Finished app opening state!"); @@ -180,6 +182,8 @@ public class MainActivity extends CompatActivity implements SwipeRefreshLayout.O moduleViewListBuilder.addNotification(NotificationType.SHOWCASE_MODE); if (!RepoManager.getINSTANCE().hasConnectivity()) moduleViewListBuilder.addNotification(NotificationType.NO_INTERNET); + else if (AppUpdateManager.getAppUpdateManager().checkUpdate(true)) + moduleViewListBuilder.addNotification(NotificationType.UPDATE_AVAILABLE); moduleViewListBuilder.appendRemoteModules(); Log.i(TAG, "Common Before applyTo"); moduleViewListBuilder.applyTo(moduleList, moduleViewAdapter); diff --git a/app/src/main/java/com/fox2code/mmm/MainApplication.java b/app/src/main/java/com/fox2code/mmm/MainApplication.java index 1d201c1..82a290e 100644 --- a/app/src/main/java/com/fox2code/mmm/MainApplication.java +++ b/app/src/main/java/com/fox2code/mmm/MainApplication.java @@ -15,6 +15,7 @@ import androidx.annotation.StyleRes; import androidx.appcompat.view.ContextThemeWrapper; import com.fox2code.mmm.compat.CompatActivity; +import com.fox2code.mmm.compat.CompatThemeWrapper; import com.fox2code.mmm.installer.InstallerInitializer; import com.fox2code.mmm.utils.GMSProviderInstaller; import com.fox2code.mmm.utils.Http; @@ -84,6 +85,10 @@ public class MainApplication extends Application implements CompatActivity.Appli return getSharedPreferences().getBoolean("pref_show_incompatible", false); } + public static boolean isForceEnglish() { + return getSharedPreferences().getBoolean("pref_force_english", false); + } + public static boolean isForceDarkTerminal() { return getSharedPreferences().getBoolean("pref_force_dark_terminal", false); } @@ -137,16 +142,19 @@ public class MainApplication extends Application implements CompatActivity.Appli @StyleRes private int managerThemeResId = R.style.Theme_MagiskModuleManager; - private ContextThemeWrapper markwonThemeContext; + private Boolean nightModeOverride = null; + private CompatThemeWrapper markwonThemeContext; private Markwon markwon; public Markwon getMarkwon() { if (this.markwon != null) return this.markwon; - ContextThemeWrapper contextThemeWrapper = this.markwonThemeContext; - if (contextThemeWrapper == null) + CompatThemeWrapper contextThemeWrapper = this.markwonThemeContext; + if (contextThemeWrapper == null) { contextThemeWrapper = this.markwonThemeContext = - new ContextThemeWrapper(this, this.managerThemeResId); + new CompatThemeWrapper(this, this.managerThemeResId); + contextThemeWrapper.setForceEnglish(isForceEnglish()); + } Markwon markwon = Markwon.builder(contextThemeWrapper).usePlugin(HtmlPlugin.create()) .usePlugin(SyntaxHighlightPlugin.create( new Prism4j(new Prism4jGrammarLocator()), new Prism4jSwitchTheme())) @@ -155,6 +163,10 @@ public class MainApplication extends Application implements CompatActivity.Appli return this.markwon = markwon; } + public CompatThemeWrapper getMarkwonThemeContext() { + return markwonThemeContext; + } + private class Prism4jSwitchTheme implements Prism4jTheme { private final Prism4jTheme light = new Prism4jThemeDefault(Color.TRANSPARENT); private final Prism4jTheme dark = new Prism4jThemeDarkula(Color.TRANSPARENT); @@ -180,10 +192,22 @@ public class MainApplication extends Application implements CompatActivity.Appli } } + @SuppressLint("NonConstantResourceId") public void setManagerThemeResId(@StyleRes int resId) { this.managerThemeResId = resId; - if (this.markwonThemeContext != null) + switch (this.managerThemeResId) { + case R.style.Theme_MagiskModuleManager: + this.nightModeOverride = null; + case R.style.Theme_MagiskModuleManager_Light: + this.nightModeOverride = Boolean.FALSE; + case R.style.Theme_MagiskModuleManager_Dark: + this.nightModeOverride = Boolean.TRUE; + default: + } + if (this.markwonThemeContext != null) { + this.markwonThemeContext.setNightModeOverride(this.nightModeOverride); this.markwonThemeContext.setTheme(resId); + } this.markwon = null; } @@ -250,11 +274,15 @@ public class MainApplication extends Application implements CompatActivity.Appli @Override public void onCreateCompatActivity(CompatActivity compatActivity) { + compatActivity.setNightModeOverride(this.nightModeOverride); + compatActivity.setForceEnglish(isForceEnglish()); compatActivity.setTheme(this.managerThemeResId); } @Override public void onRefreshUI(CompatActivity compatActivity) { + compatActivity.setNightModeOverride(this.nightModeOverride); + compatActivity.setForceEnglish(isForceEnglish()); compatActivity.setThemeRecreate(this.managerThemeResId); } diff --git a/app/src/main/java/com/fox2code/mmm/ModuleHolder.java b/app/src/main/java/com/fox2code/mmm/ModuleHolder.java index b0b6a97..b0db661 100644 --- a/app/src/main/java/com/fox2code/mmm/ModuleHolder.java +++ b/app/src/main/java/com/fox2code/mmm/ModuleHolder.java @@ -83,6 +83,10 @@ public final class ModuleHolder implements Comparable { return timeStamp <= 0 ? "" : MainApplication.formatTime(timeStamp); } + public String getRepoName() { + if (this.repoModule == null) return ""; + return this.repoModule.repoName; + } public boolean hasFlag(int flag) { return this.moduleInfo != null && this.moduleInfo.hasFlag(flag); diff --git a/app/src/main/java/com/fox2code/mmm/ModuleViewAdapter.java b/app/src/main/java/com/fox2code/mmm/ModuleViewAdapter.java index d2cee1a..c16ec5d 100644 --- a/app/src/main/java/com/fox2code/mmm/ModuleViewAdapter.java +++ b/app/src/main/java/com/fox2code/mmm/ModuleViewAdapter.java @@ -15,11 +15,13 @@ import android.widget.TextView; import androidx.annotation.ColorInt; import androidx.annotation.ColorRes; import androidx.annotation.NonNull; +import androidx.annotation.StringRes; import androidx.cardview.widget.CardView; import androidx.recyclerview.widget.RecyclerView; import com.fox2code.mmm.manager.ModuleInfo; import com.fox2code.mmm.manager.ModuleManager; +import com.fox2code.mmm.repo.RepoModule; import com.google.android.material.switchmaterial.SwitchMaterial; import com.topjohnwu.superuser.internal.UiThreadHandler; @@ -142,6 +144,11 @@ public final class ModuleViewAdapter extends RecyclerView.Adapter { + IntentHelper.openUrl(v.getContext(), + "https://github.com/Fox2Code/FoxMagiskModuleManager/releases"); + }, false) { + @Override + public boolean shouldRemove() { + return !AppUpdateManager.getAppUpdateManager().peekShouldUpdate(); + } + }, INSTALL_FROM_STORAGE(R.string.install_from_storage, R.drawable.ic_baseline_storage_24, R.attr.colorBackgroundFloating, R.attr.colorOnBackground, v -> { CompatActivity compatActivity = CompatActivity.getCompatActivity(v); diff --git a/app/src/main/java/com/fox2code/mmm/compat/CompatActivity.java b/app/src/main/java/com/fox2code/mmm/compat/CompatActivity.java index 037b650..74b6cea 100644 --- a/app/src/main/java/com/fox2code/mmm/compat/CompatActivity.java +++ b/app/src/main/java/com/fox2code/mmm/compat/CompatActivity.java @@ -21,10 +21,11 @@ import androidx.fragment.app.Fragment; import com.fox2code.mmm.Constants; import com.fox2code.mmm.R; +import java.util.Locale; import java.util.Objects; /** - * I will probably outsource this to a separate library + * I will probably outsource this to a separate library later */ public class CompatActivity extends AppCompatActivity { public static final int INTENT_ACTIVITY_REQUEST_CODE = 0x01000000; @@ -38,6 +39,7 @@ public class CompatActivity extends AppCompatActivity { } }; + private final CompatConfigHelper compatConfigHelper = new CompatConfigHelper(this); private CompatActivity.OnActivityResultCallback onActivityResultCallback; private CompatActivity.OnBackPressedCallback onBackPressedCallback; private MenuItem.OnMenuItemClickListener menuClickListener; @@ -45,7 +47,10 @@ public class CompatActivity extends AppCompatActivity { private boolean onCreateCalled = false; private boolean isRefreshUi = false; private int drawableResId; - MenuItem menuItem; + private MenuItem menuItem; + // CompatConfigHelper + private boolean forceEnglish; + private Boolean nightModeOverride; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { @@ -55,6 +60,8 @@ public class CompatActivity extends AppCompatActivity { } super.onCreate(savedInstanceState); this.onCreateCalled = true; + this.checkResourcesOverrides( + this.forceEnglish, this.nightModeOverride); } @Override @@ -88,6 +95,8 @@ public class CompatActivity extends AppCompatActivity { } finally { this.isRefreshUi = false; } + this.checkResourcesOverrides( + this.forceEnglish, this.nightModeOverride); } } @@ -128,6 +137,7 @@ public class CompatActivity extends AppCompatActivity { this.menuItem.setOnMenuItemClickListener(this.menuClickListener); this.menuItem.setIcon(this.drawableResId); this.menuItem.setEnabled(true); + this.menuItem.setVisible(true); } } @@ -138,6 +148,7 @@ public class CompatActivity extends AppCompatActivity { this.menuItem.setOnMenuItemClickListener(null); this.menuItem.setIcon(null); this.menuItem.setEnabled(false); + this.menuItem.setVisible(false); } } @@ -161,12 +172,16 @@ public class CompatActivity extends AppCompatActivity { @Override protected void onApplyThemeResource(Resources.Theme theme, int resid, boolean first) { - super.onApplyThemeResource(theme, resid, first); if (resid != 0 && this.setThemeDynamic == resid) { + super.onApplyThemeResource(theme, resid, first); Activity parent = this.getParent(); (parent == null ? this : parent).recreate(); super.overridePendingTransition( android.R.anim.fade_in, android.R.anim.fade_out); + } else { + this.compatConfigHelper.checkResourcesOverrides(theme, + this.forceEnglish, this.nightModeOverride); + super.onApplyThemeResource(theme, resid, first); } } @@ -199,6 +214,7 @@ public class CompatActivity extends AppCompatActivity { this.menuItem.setOnMenuItemClickListener(this.menuClickListener); this.menuItem.setIcon(this.drawableResId); this.menuItem.setEnabled(true); + this.menuItem.setVisible(true); } return super.onCreateOptionsMenu(menu); } @@ -224,6 +240,27 @@ public class CompatActivity extends AppCompatActivity { } } + public void setForceEnglish(boolean forceEnglish) { + if (this.forceEnglish == forceEnglish) return; + this.forceEnglish = forceEnglish; + this.checkResourcesOverrides(forceEnglish, this.nightModeOverride); + } + + public void setNightModeOverride(Boolean nightModeOverride) { + if (this.nightModeOverride == nightModeOverride) return; + this.nightModeOverride = nightModeOverride; + this.checkResourcesOverrides(this.forceEnglish, nightModeOverride); + } + + private void checkResourcesOverrides(boolean forceEnglish,Boolean nightModeOverride) { + if (this.isRefreshUi || !this.onCreateCalled) return; // Wait before reload + this.compatConfigHelper.checkResourcesOverrides(forceEnglish, nightModeOverride); + } + + public Locale getUserLocale() { + return this.compatConfigHelper.getUserLocale(); + } + public static CompatActivity getCompatActivity(View view) { return getCompatActivity(view.getContext()); } diff --git a/app/src/main/java/com/fox2code/mmm/compat/CompatConfigHelper.java b/app/src/main/java/com/fox2code/mmm/compat/CompatConfigHelper.java new file mode 100644 index 0000000..86ab063 --- /dev/null +++ b/app/src/main/java/com/fox2code/mmm/compat/CompatConfigHelper.java @@ -0,0 +1,76 @@ +package com.fox2code.mmm.compat; + +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.os.Build; +import android.os.LocaleList; + +import java.util.Locale; + +/** + * I will probably outsource this to a separate library later + */ +final class CompatConfigHelper { + // ENGLISH like this is an unnatural local, as it doesn't precise the country + // All english locales settable by the user precise the country (Ex: en-US) + private static final Locale english = Locale.ENGLISH; + + private final Context context; + private Locale userLocale; + + CompatConfigHelper(Context context) { + this.context = context; + } + + void checkResourcesOverrides(boolean forceEnglish, + Boolean nightModeOverride) { + this.checkResourcesOverrides( + this.context.getTheme(), + forceEnglish, nightModeOverride); + } + + void checkResourcesOverrides(Resources.Theme theme, boolean forceEnglish, + Boolean nightModeOverride) { + final Resources res = theme.getResources(); + final Configuration conf = res.getConfiguration(); + Locale current = conf.locale; + boolean didChange = false; + if (forceEnglish != current.equals(english)) { + didChange = true; + if (forceEnglish) { + this.userLocale = conf.locale; + conf.locale = english; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + conf.setLocales(LocaleList.getEmptyLocaleList()); + } + } else { + conf.locale = this.userLocale; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + conf.setLocales(LocaleList.getAdjustedDefault()); + } + } + } + int nightMode = conf.uiMode & Configuration.UI_MODE_NIGHT_MASK; + int sysNightMode = Resources.getSystem() + .getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; + if (nightModeOverride == null ? sysNightMode != nightMode : + nightMode != (nightModeOverride ? + Configuration.UI_MODE_NIGHT_YES : Configuration.UI_MODE_NIGHT_NO)) { + didChange = true; + nightMode = nightModeOverride == null ? sysNightMode : nightModeOverride ? + Configuration.UI_MODE_NIGHT_YES : Configuration.UI_MODE_NIGHT_NO; + conf.uiMode = nightMode | (conf.uiMode & ~Configuration.UI_MODE_NIGHT_MASK); + } + if (didChange) { + res.updateConfiguration(conf, null); + if (!forceEnglish) this.userLocale = null; + } + } + + public Locale getUserLocale() { + // Only use cached value if force english + Locale locale = this.context.getResources().getConfiguration().locale; + return english.equals(locale) ? this.userLocale : locale; + } +} diff --git a/app/src/main/java/com/fox2code/mmm/compat/CompatThemeWrapper.java b/app/src/main/java/com/fox2code/mmm/compat/CompatThemeWrapper.java new file mode 100644 index 0000000..abaf7c6 --- /dev/null +++ b/app/src/main/java/com/fox2code/mmm/compat/CompatThemeWrapper.java @@ -0,0 +1,56 @@ +package com.fox2code.mmm.compat; + +import android.app.Activity; +import android.content.Context; +import android.content.res.Resources; + +import androidx.annotation.StyleRes; +import androidx.appcompat.view.ContextThemeWrapper; + +/** + * I will probably outsource this to a separate library later + */ +public class CompatThemeWrapper extends ContextThemeWrapper { + private final CompatConfigHelper compatConfigHelper = new CompatConfigHelper(this); + private boolean canReload; + // CompatConfigHelper + private boolean forceEnglish; + private Boolean nightModeOverride; + + public CompatThemeWrapper(Context base, @StyleRes int themeResId) { + super(base, themeResId); + this.canReload = true; + this.checkResourcesOverrides( + this.forceEnglish, this.nightModeOverride); + } + + @Override + protected void onApplyThemeResource(Resources.Theme theme, int resid, boolean first) { + boolean couldReload = this.canReload; + if (couldReload) this.canReload = false; + this.compatConfigHelper.checkResourcesOverrides(theme, + this.forceEnglish, this.nightModeOverride); + super.onApplyThemeResource(theme, resid, first); + if (couldReload) this.canReload = true; + // In case value change while reload, should have no effect + this.compatConfigHelper.checkResourcesOverrides(theme, + this.forceEnglish, this.nightModeOverride); + } + + public void setForceEnglish(boolean forceEnglish) { + if (this.forceEnglish == forceEnglish) return; + this.forceEnglish = forceEnglish; + this.checkResourcesOverrides(forceEnglish, this.nightModeOverride); + } + + public void setNightModeOverride(Boolean nightModeOverride) { + if (this.nightModeOverride == nightModeOverride) return; + this.nightModeOverride = nightModeOverride; + this.checkResourcesOverrides(this.forceEnglish, nightModeOverride); + } + + private void checkResourcesOverrides(boolean forceEnglish,Boolean nightModeOverride) { + if (!this.canReload) return; // Do not reload during theme reload + this.compatConfigHelper.checkResourcesOverrides(forceEnglish, nightModeOverride); + } +} diff --git a/app/src/main/java/com/fox2code/mmm/repo/RepoData.java b/app/src/main/java/com/fox2code/mmm/repo/RepoData.java index 1b90620..1b290f2 100644 --- a/app/src/main/java/com/fox2code/mmm/repo/RepoData.java +++ b/app/src/main/java/com/fox2code/mmm/repo/RepoData.java @@ -54,7 +54,9 @@ public class RepoData { List populate(JSONObject jsonObject) throws JSONException { List newModules = new ArrayList<>(); synchronized (this.populateLock) { - String name = jsonObject.getString("name"); + String name = jsonObject.getString("name").trim(); + String nameForModules = name.endsWith(" (Official)") ? + name.substring(0, name.length() - 11) : name; long lastUpdate = jsonObject.getLong("last_update"); for (RepoModule repoModule : this.moduleHashMap.values()) { repoModule.processed = false; @@ -80,6 +82,7 @@ public class RepoData { } } repoModule.processed = true; + repoModule.repoName = nameForModules; repoModule.lastUpdated = moduleLastUpdate; repoModule.notesUrl = moduleNotesUrl; repoModule.propUrl = modulePropsUrl; diff --git a/app/src/main/java/com/fox2code/mmm/repo/RepoModule.java b/app/src/main/java/com/fox2code/mmm/repo/RepoModule.java index cf3e5b5..db00f2f 100644 --- a/app/src/main/java/com/fox2code/mmm/repo/RepoModule.java +++ b/app/src/main/java/com/fox2code/mmm/repo/RepoModule.java @@ -5,6 +5,7 @@ import com.fox2code.mmm.manager.ModuleInfo; public class RepoModule { public final ModuleInfo moduleInfo; public final String id; + public String repoName; public long lastUpdated; public String propUrl; public String zipUrl; diff --git a/app/src/main/java/com/fox2code/mmm/settings/SettingsActivity.java b/app/src/main/java/com/fox2code/mmm/settings/SettingsActivity.java index cf22fa5..27e0779 100644 --- a/app/src/main/java/com/fox2code/mmm/settings/SettingsActivity.java +++ b/app/src/main/java/com/fox2code/mmm/settings/SettingsActivity.java @@ -9,12 +9,15 @@ import androidx.fragment.app.FragmentTransaction; import androidx.preference.ListPreference; import androidx.preference.Preference; import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.SwitchPreference; +import com.fox2code.mmm.AppUpdateManager; import com.fox2code.mmm.BuildConfig; import com.fox2code.mmm.Constants; import com.fox2code.mmm.MainApplication; import com.fox2code.mmm.R; import com.fox2code.mmm.compat.CompatActivity; +import com.fox2code.mmm.compat.CompatThemeWrapper; import com.fox2code.mmm.installer.InstallerInitializer; import com.fox2code.mmm.repo.RepoData; import com.fox2code.mmm.repo.RepoManager; @@ -31,8 +34,8 @@ public class SettingsActivity extends CompatActivity { super.onCreate(savedInstanceState); this.setDisplayHomeAsUpEnabled(true); setContentView(R.layout.settings_activity); + setTitle(R.string.app_name); if (savedInstanceState == null) { - setTitle(R.string.app_name); getSupportFragmentManager() .beginTransaction() .replace(R.id.settings, new SettingsFragment()) @@ -73,6 +76,16 @@ public class SettingsActivity extends CompatActivity { CompatActivity.getCompatActivity(this).setThemeRecreate(themeResId); return true; }); + Preference forceEnglish = findPreference("pref_force_english"); + forceEnglish.setOnPreferenceChangeListener((preference, newValue) -> { + CompatThemeWrapper compatThemeWrapper = + MainApplication.getINSTANCE().getMarkwonThemeContext(); + if (compatThemeWrapper != null) { + compatThemeWrapper.setForceEnglish( + Boolean.parseBoolean(String.valueOf(newValue))); + } + return true; + }); if ("dark".equals(themePreference.getValue())) { findPreference("pref_force_dark_terminal").setEnabled(false); } @@ -88,6 +101,14 @@ public class SettingsActivity extends CompatActivity { final LibsBuilder libsBuilder = new LibsBuilder() .withFields(R.string.class.getFields()).withShowLoadingProgress(false) .withLicenseShown(true).withAboutMinimalDesign(false); + Preference update = findPreference("pref_update"); + update.setVisible(AppUpdateManager.getAppUpdateManager().peekHasUpdate()); + update.setOnPreferenceClickListener(p -> { + devModeStep = 0; + IntentHelper.openUrl(p.getContext(), + "https://github.com/Fox2Code/FoxMagiskModuleManager/releases"); + return true; + }); findPreference("pref_source_code").setOnPreferenceClickListener(p -> { if (devModeStep == 2 && (BuildConfig.DEBUG || !MainApplication.isDeveloper())) { devModeStep = 0; @@ -97,7 +118,8 @@ public class SettingsActivity extends CompatActivity { R.string.dev_mode_enabled, Toast.LENGTH_SHORT).show(); return true; } - IntentHelper.openUrl(p.getContext(), "https://github.com/Fox2Code/FoxMagiskModuleManager"); + IntentHelper.openUrl(p.getContext(), + "https://github.com/Fox2Code/FoxMagiskModuleManager"); return true; }); findPreference("pref_show_licenses").setOnPreferenceClickListener(p -> { diff --git a/app/src/main/res/drawable/ic_baseline_language_24.xml b/app/src/main/res/drawable/ic_baseline_language_24.xml new file mode 100644 index 0000000..3f70646 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_language_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_system_update_24.xml b/app/src/main/res/drawable/ic_baseline_system_update_24.xml new file mode 100644 index 0000000..c6f3370 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_system_update_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/menu/compat_menu.xml b/app/src/main/res/menu/compat_menu.xml index ac26373..1d7317a 100644 --- a/app/src/main/res/menu/compat_menu.xml +++ b/app/src/main/res/menu/compat_menu.xml @@ -2,6 +2,7 @@ 無法連線到網路 設定活動 + + 最後更新: + 鎖定模式 鎖定模式阻止管理器對模塊進行操作 @@ -35,8 +38,8 @@ 所選模塊的格式無效或檔案損毀 本機安裝 原始碼 - 最後更新: Magisk 內置模塊 + Substratum 內置模塊 終端強制深色模式 您當前的檔案管理員無法使用 遠程安裝 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8729f3a..800da52 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -6,11 +6,18 @@ Updatable Installed Online Repo - The application is in showcase mode + The application is in lockdown mode Failed to download file. Modules took too long to boot, consider disabling some modules Fail to connect to the internet SettingsActivity + Application update available + Update + + + Last update: + Repo: + by @@ -36,8 +43,8 @@ The selected module is in an invalid format Local install Source code - Last update: Magisk builtin module + Substratum builtin module Force dark mode terminal Your current file picker failed to give access to the file. Remote install @@ -45,7 +52,8 @@ Use magisk module install command During test it caused problems to the module install error diagnosis tool, - so I hid this option behind dev-mode, enable this at your own risk! + so I hid this option behind developer mode, enable this at your own risk! Developer mode enabled + Force English language \ 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 aa9e3a8..16f662f 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -79,6 +79,4 @@