Skip to content
This repository was archived by the owner on May 4, 2023. It is now read-only.

Commit 88da4ba

Browse files
committed
Update 0.2.0-pre1
1 parent 1cd81e1 commit 88da4ba

21 files changed

+423
-25
lines changed

app/build.gradle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ android {
1010
applicationId "com.fox2code.mmm"
1111
minSdk 21
1212
targetSdk 30
13-
versionCode 6
14-
versionName "0.1.2"
13+
versionCode 7
14+
versionName "0.2.0-pre1"
1515

1616
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
1717
}
@@ -51,7 +51,7 @@ dependencies {
5151
// UI
5252
implementation 'androidx.appcompat:appcompat:1.3.1'
5353
implementation 'androidx.preference:preference:1.1.1'
54-
implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
54+
implementation 'androidx.constraintlayout:constraintlayout:2.1.2'
5555
implementation 'androidx.recyclerview:recyclerview:1.2.1'
5656
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
5757
implementation 'com.google.android.material:material:1.4.0'

app/src/main/java/com/fox2code/mmm/ActionButtonType.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ public boolean doActionLong(ImageButton button, ModuleHolder moduleHolder) {
3636
@Override
3737
public void update(ImageButton button, ModuleHolder moduleHolder) {
3838
int icon = moduleHolder.hasUpdate() ?
39-
R.drawable.ic_baseline_update_24 : R.drawable.ic_baseline_download_24;
39+
R.drawable.ic_baseline_update_24 :
40+
R.drawable.ic_baseline_system_update_24;
4041
button.setImageResource(icon);
4142
}
4243

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package com.fox2code.mmm;
2+
3+
import android.util.Log;
4+
5+
import com.fox2code.mmm.utils.Http;
6+
7+
import org.json.JSONArray;
8+
import org.json.JSONObject;
9+
10+
import java.nio.charset.StandardCharsets;
11+
12+
// See https://docs.github.com/en/rest/reference/repos#releases
13+
public class AppUpdateManager {
14+
private static final String TAG = "AppUpdateManager";
15+
private static final AppUpdateManager INSTANCE = new AppUpdateManager();
16+
private static final String RELEASES_API_URL =
17+
"https://api.github.com/repos/Fox2Code/FoxMagiskModuleManager/releases";
18+
19+
public static AppUpdateManager getAppUpdateManager() {
20+
return INSTANCE;
21+
}
22+
23+
private final Object updateLock = new Object();
24+
private String latestRelease;
25+
private String latestPreRelease;
26+
private long lastChecked;
27+
private boolean preReleaseNewer;
28+
29+
private AppUpdateManager() {
30+
this.latestRelease = MainApplication.getBootSharedPreferences()
31+
.getString("updater_latest_release", BuildConfig.VERSION_NAME);
32+
this.latestPreRelease = MainApplication.getBootSharedPreferences()
33+
.getString("updater_latest_pre_release", BuildConfig.VERSION_NAME);
34+
this.lastChecked = 0;
35+
this.preReleaseNewer = true;
36+
}
37+
38+
// Return true if should show a notification
39+
public boolean checkUpdate(boolean force) {
40+
if (this.peekShouldUpdate())
41+
return true;
42+
long lastChecked = this.lastChecked;
43+
if (!force && lastChecked != 0 &&
44+
// Avoid spam calls by putting a 10 seconds timer
45+
lastChecked < System.currentTimeMillis() - 10000L)
46+
return false;
47+
synchronized (this.updateLock) {
48+
if (lastChecked != this.lastChecked)
49+
return this.peekShouldUpdate();
50+
boolean preReleaseNewer = true;
51+
try {
52+
JSONArray releases = new JSONArray(new String(Http.doHttpGet(
53+
RELEASES_API_URL, false), StandardCharsets.UTF_8));
54+
String latestRelease = null, latestPreRelease = null;
55+
for (int i = releases.length() - 1; i > 0; i--) {
56+
JSONObject release = releases.getJSONObject(i);
57+
// Skip invalid entries
58+
if (release.getBoolean("draft")) continue;
59+
boolean preRelease = release.getBoolean("prerelease");
60+
String version = release.getString("tag_name");
61+
if (version.startsWith("v"))
62+
version = version.substring(1);
63+
if (preRelease) {
64+
latestPreRelease = version;
65+
} else {
66+
latestRelease = version;
67+
if (latestPreRelease == null)
68+
preReleaseNewer = false;
69+
}
70+
if (latestRelease != null && latestPreRelease != null) {
71+
break; // We read everything we needed to read.
72+
}
73+
}
74+
if (latestRelease != null)
75+
this.latestRelease = latestRelease;
76+
if (latestPreRelease != null) {
77+
this.latestPreRelease = latestPreRelease;
78+
this.preReleaseNewer = preReleaseNewer;
79+
} else if (!preReleaseNewer) {
80+
this.latestPreRelease = "";
81+
this.preReleaseNewer = false;
82+
}
83+
Log.d(TAG, "Latest release: " + latestRelease);
84+
Log.d(TAG, "Latest pre-release: " + latestPreRelease);
85+
Log.d(TAG, "Latest pre-release newer: " + preReleaseNewer);
86+
this.lastChecked = System.currentTimeMillis();
87+
} catch (Exception ioe) {
88+
Log.e("AppUpdateManager", "Failed to check releases", ioe);
89+
}
90+
}
91+
return this.peekShouldUpdate();
92+
}
93+
94+
public boolean peekShouldUpdate() {
95+
return !(BuildConfig.VERSION_NAME.equals(this.latestRelease) ||
96+
(this.preReleaseNewer &&
97+
BuildConfig.VERSION_NAME.equals(this.latestPreRelease)));
98+
}
99+
100+
public boolean peekHasUpdate() {
101+
return !BuildConfig.VERSION_NAME.equals(this.preReleaseNewer ?
102+
this.latestPreRelease : this.latestRelease);
103+
}
104+
}

app/src/main/java/com/fox2code/mmm/MainActivity.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ public void commonNext() {
123123
});
124124
if (!RepoManager.getINSTANCE().hasConnectivity())
125125
moduleViewListBuilder.addNotification(NotificationType.NO_INTERNET);
126+
else if (AppUpdateManager.getAppUpdateManager().checkUpdate(true))
127+
moduleViewListBuilder.addNotification(NotificationType.UPDATE_AVAILABLE);
126128
moduleViewListBuilder.appendRemoteModules();
127129
moduleViewListBuilder.applyTo(moduleList, moduleViewAdapter);
128130
Log.i(TAG, "Finished app opening state!");
@@ -180,6 +182,8 @@ public void commonNext() {
180182
moduleViewListBuilder.addNotification(NotificationType.SHOWCASE_MODE);
181183
if (!RepoManager.getINSTANCE().hasConnectivity())
182184
moduleViewListBuilder.addNotification(NotificationType.NO_INTERNET);
185+
else if (AppUpdateManager.getAppUpdateManager().checkUpdate(true))
186+
moduleViewListBuilder.addNotification(NotificationType.UPDATE_AVAILABLE);
183187
moduleViewListBuilder.appendRemoteModules();
184188
Log.i(TAG, "Common Before applyTo");
185189
moduleViewListBuilder.applyTo(moduleList, moduleViewAdapter);

app/src/main/java/com/fox2code/mmm/MainApplication.java

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import androidx.appcompat.view.ContextThemeWrapper;
1616

1717
import com.fox2code.mmm.compat.CompatActivity;
18+
import com.fox2code.mmm.compat.CompatThemeWrapper;
1819
import com.fox2code.mmm.installer.InstallerInitializer;
1920
import com.fox2code.mmm.utils.GMSProviderInstaller;
2021
import com.fox2code.mmm.utils.Http;
@@ -84,6 +85,10 @@ public static boolean isShowIncompatibleModules() {
8485
return getSharedPreferences().getBoolean("pref_show_incompatible", false);
8586
}
8687

88+
public static boolean isForceEnglish() {
89+
return getSharedPreferences().getBoolean("pref_force_english", false);
90+
}
91+
8792
public static boolean isForceDarkTerminal() {
8893
return getSharedPreferences().getBoolean("pref_force_dark_terminal", false);
8994
}
@@ -137,16 +142,19 @@ public static String formatTime(long timeStamp) {
137142

138143
@StyleRes
139144
private int managerThemeResId = R.style.Theme_MagiskModuleManager;
140-
private ContextThemeWrapper markwonThemeContext;
145+
private Boolean nightModeOverride = null;
146+
private CompatThemeWrapper markwonThemeContext;
141147
private Markwon markwon;
142148

143149
public Markwon getMarkwon() {
144150
if (this.markwon != null)
145151
return this.markwon;
146-
ContextThemeWrapper contextThemeWrapper = this.markwonThemeContext;
147-
if (contextThemeWrapper == null)
152+
CompatThemeWrapper contextThemeWrapper = this.markwonThemeContext;
153+
if (contextThemeWrapper == null) {
148154
contextThemeWrapper = this.markwonThemeContext =
149-
new ContextThemeWrapper(this, this.managerThemeResId);
155+
new CompatThemeWrapper(this, this.managerThemeResId);
156+
contextThemeWrapper.setForceEnglish(isForceEnglish());
157+
}
150158
Markwon markwon = Markwon.builder(contextThemeWrapper).usePlugin(HtmlPlugin.create())
151159
.usePlugin(SyntaxHighlightPlugin.create(
152160
new Prism4j(new Prism4jGrammarLocator()), new Prism4jSwitchTheme()))
@@ -155,6 +163,10 @@ public Markwon getMarkwon() {
155163
return this.markwon = markwon;
156164
}
157165

166+
public CompatThemeWrapper getMarkwonThemeContext() {
167+
return markwonThemeContext;
168+
}
169+
158170
private class Prism4jSwitchTheme implements Prism4jTheme {
159171
private final Prism4jTheme light = new Prism4jThemeDefault(Color.TRANSPARENT);
160172
private final Prism4jTheme dark = new Prism4jThemeDarkula(Color.TRANSPARENT);
@@ -180,10 +192,22 @@ public void apply(@NonNull String language, @NonNull Prism4j.Syntax syntax,
180192
}
181193
}
182194

195+
@SuppressLint("NonConstantResourceId")
183196
public void setManagerThemeResId(@StyleRes int resId) {
184197
this.managerThemeResId = resId;
185-
if (this.markwonThemeContext != null)
198+
switch (this.managerThemeResId) {
199+
case R.style.Theme_MagiskModuleManager:
200+
this.nightModeOverride = null;
201+
case R.style.Theme_MagiskModuleManager_Light:
202+
this.nightModeOverride = Boolean.FALSE;
203+
case R.style.Theme_MagiskModuleManager_Dark:
204+
this.nightModeOverride = Boolean.TRUE;
205+
default:
206+
}
207+
if (this.markwonThemeContext != null) {
208+
this.markwonThemeContext.setNightModeOverride(this.nightModeOverride);
186209
this.markwonThemeContext.setTheme(resId);
210+
}
187211
this.markwon = null;
188212
}
189213

@@ -250,11 +274,15 @@ public void onCreate() {
250274

251275
@Override
252276
public void onCreateCompatActivity(CompatActivity compatActivity) {
277+
compatActivity.setNightModeOverride(this.nightModeOverride);
278+
compatActivity.setForceEnglish(isForceEnglish());
253279
compatActivity.setTheme(this.managerThemeResId);
254280
}
255281

256282
@Override
257283
public void onRefreshUI(CompatActivity compatActivity) {
284+
compatActivity.setNightModeOverride(this.nightModeOverride);
285+
compatActivity.setForceEnglish(isForceEnglish());
258286
compatActivity.setThemeRecreate(this.managerThemeResId);
259287
}
260288

app/src/main/java/com/fox2code/mmm/ModuleHolder.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ public String getUpdateTimeText() {
8383
return timeStamp <= 0 ? "" :
8484
MainApplication.formatTime(timeStamp);
8585
}
86+
public String getRepoName() {
87+
if (this.repoModule == null) return "";
88+
return this.repoModule.repoName;
89+
}
8690

8791
public boolean hasFlag(int flag) {
8892
return this.moduleInfo != null && this.moduleInfo.hasFlag(flag);

app/src/main/java/com/fox2code/mmm/ModuleViewAdapter.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@
1515
import androidx.annotation.ColorInt;
1616
import androidx.annotation.ColorRes;
1717
import androidx.annotation.NonNull;
18+
import androidx.annotation.StringRes;
1819
import androidx.cardview.widget.CardView;
1920
import androidx.recyclerview.widget.RecyclerView;
2021

2122
import com.fox2code.mmm.manager.ModuleInfo;
2223
import com.fox2code.mmm.manager.ModuleManager;
24+
import com.fox2code.mmm.repo.RepoModule;
2325
import com.google.android.material.switchmaterial.SwitchMaterial;
2426
import com.topjohnwu.superuser.internal.UiThreadHandler;
2527

@@ -142,6 +144,11 @@ public ViewHolder(@NonNull View itemView) {
142144
this.initState = false;
143145
}
144146

147+
@NonNull
148+
public final String getString(@StringRes int resId) {
149+
return this.itemView.getContext().getString(resId);
150+
}
151+
145152
@SuppressLint("SetTextI18n")
146153
public boolean update(ModuleHolder moduleHolder) {
147154
this.initState = true;
@@ -170,16 +177,21 @@ public boolean update(ModuleHolder moduleHolder) {
170177

171178
ModuleInfo moduleInfo = moduleHolder.getMainModuleInfo();
172179
this.titleText.setText(moduleInfo.name);
173-
this.creditText.setText(moduleInfo.version + " by " + moduleInfo.author);
180+
this.creditText.setText(moduleInfo.version + " " +
181+
this.getString(R.string.module_by) + " " + moduleInfo.author);
174182
this.descriptionText.setText(moduleInfo.description);
175183
String updateText = moduleHolder.getUpdateTimeText();
176184
if (!updateText.isEmpty()) {
177185
this.updateText.setVisibility(View.VISIBLE);
178-
this.updateText.setText(this.updateText.getContext()
179-
.getString(R.string.last_updated) + " " + updateText);
186+
this.updateText.setText(
187+
this.getString(R.string.module_last_update) + " " + updateText + "\n" +
188+
this.getString(R.string.module_repo) + " " + moduleHolder.getRepoName());
180189
} else if (moduleHolder.moduleId.equals("hosts")) {
181190
this.updateText.setVisibility(View.VISIBLE);
182191
this.updateText.setText(R.string.magisk_builtin_module);
192+
} else if (moduleHolder.moduleId.equals("substratum")) {
193+
this.updateText.setVisibility(View.VISIBLE);
194+
this.updateText.setText(R.string.substratum_builtin_module);
183195
} else {
184196
this.updateText.setVisibility(View.GONE);
185197
}

app/src/main/java/com/fox2code/mmm/NotificationType.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ interface NotificationTypeCst {
2424
}
2525

2626
public enum NotificationType implements NotificationTypeCst {
27-
SHOWCASE_MODE(R.string.showcase_mode, R.drawable.ic_baseline_monitor_24,
27+
SHOWCASE_MODE(R.string.showcase_mode, R.drawable.ic_baseline_lock_24,
2828
R.attr.colorPrimary, R.attr.colorOnPrimary) {
2929
@Override
3030
public boolean shouldRemove() {
@@ -51,6 +51,16 @@ public boolean shouldRemove() {
5151
return RepoManager.getINSTANCE().hasConnectivity();
5252
}
5353
},
54+
UPDATE_AVAILABLE(R.string.app_update_available, R.drawable.ic_baseline_system_update_24,
55+
R.attr.colorPrimary, R.attr.colorOnPrimary, v -> {
56+
IntentHelper.openUrl(v.getContext(),
57+
"https://github.com/Fox2Code/FoxMagiskModuleManager/releases");
58+
}, false) {
59+
@Override
60+
public boolean shouldRemove() {
61+
return !AppUpdateManager.getAppUpdateManager().peekShouldUpdate();
62+
}
63+
},
5464
INSTALL_FROM_STORAGE(R.string.install_from_storage, R.drawable.ic_baseline_storage_24,
5565
R.attr.colorBackgroundFloating, R.attr.colorOnBackground, v -> {
5666
CompatActivity compatActivity = CompatActivity.getCompatActivity(v);

0 commit comments

Comments
 (0)