@capgo/capacitor-updater 6.43.5 → 6.45.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Package.swift +1 -1
- package/README.md +149 -39
- package/android/build.gradle +3 -3
- package/android/src/main/java/ee/forgr/capacitor_updater/CapacitorUpdaterPlugin.java +534 -170
- package/android/src/main/java/ee/forgr/capacitor_updater/CapgoUpdater.java +151 -28
- package/android/src/main/java/ee/forgr/capacitor_updater/DownloadService.java +38 -13
- package/android/src/main/java/ee/forgr/capacitor_updater/ShakeMenu.java +49 -9
- package/dist/docs.json +290 -10
- package/dist/esm/definitions.d.ts +134 -22
- package/dist/esm/definitions.js.map +1 -1
- package/ios/Sources/CapacitorUpdaterPlugin/CapacitorUpdaterPlugin.swift +557 -134
- package/ios/Sources/CapacitorUpdaterPlugin/CapgoUpdater.swift +213 -50
- package/ios/Sources/CapacitorUpdaterPlugin/InternalUtils.swift +2 -0
- package/ios/Sources/CapacitorUpdaterPlugin/ShakeMenu.swift +20 -3
- package/package.json +5 -2
|
@@ -758,6 +758,20 @@ public class CapgoUpdater {
|
|
|
758
758
|
this.editor.commit();
|
|
759
759
|
}
|
|
760
760
|
|
|
761
|
+
static boolean shouldResetForForeignBundle(final String bundlePath, final boolean isBuiltin, final boolean hasStoredBundleInfo) {
|
|
762
|
+
return bundlePath != null && !bundlePath.trim().isEmpty() && !isBuiltin && !hasStoredBundleInfo;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
private boolean hasStoredBundleInfo(final String id) {
|
|
766
|
+
return (
|
|
767
|
+
id != null &&
|
|
768
|
+
!id.isEmpty() &&
|
|
769
|
+
!BundleInfo.ID_BUILTIN.equals(id) &&
|
|
770
|
+
!BundleInfo.VERSION_UNKNOWN.equals(id) &&
|
|
771
|
+
this.prefs.contains(id + INFO_SUFFIX)
|
|
772
|
+
);
|
|
773
|
+
}
|
|
774
|
+
|
|
761
775
|
public void downloadBackground(
|
|
762
776
|
final String url,
|
|
763
777
|
final String version,
|
|
@@ -977,6 +991,64 @@ public class CapgoUpdater {
|
|
|
977
991
|
return (bundle.isDirectory() && bundle.exists() && new File(bundle.getPath(), "/index.html").exists() && !bundleInfo.isDeleted());
|
|
978
992
|
}
|
|
979
993
|
|
|
994
|
+
static final class ResetState {
|
|
995
|
+
|
|
996
|
+
final String currentBundlePath;
|
|
997
|
+
final String fallbackBundleId;
|
|
998
|
+
final String nextBundleId;
|
|
999
|
+
|
|
1000
|
+
ResetState(final String currentBundlePath, final String fallbackBundleId, final String nextBundleId) {
|
|
1001
|
+
this.currentBundlePath = currentBundlePath;
|
|
1002
|
+
this.fallbackBundleId = fallbackBundleId;
|
|
1003
|
+
this.nextBundleId = nextBundleId;
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
ResetState captureResetState() {
|
|
1008
|
+
return new ResetState(
|
|
1009
|
+
this.getCurrentBundlePath(),
|
|
1010
|
+
this.prefs.getString(FALLBACK_VERSION, BundleInfo.ID_BUILTIN),
|
|
1011
|
+
this.prefs.getString(NEXT_VERSION, null)
|
|
1012
|
+
);
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
void restoreResetState(final ResetState state) {
|
|
1016
|
+
final String currentBundlePath = state.currentBundlePath == null || state.currentBundlePath.trim().isEmpty()
|
|
1017
|
+
? "public"
|
|
1018
|
+
: state.currentBundlePath;
|
|
1019
|
+
final String fallbackBundleId = state.fallbackBundleId == null || state.fallbackBundleId.isEmpty()
|
|
1020
|
+
? BundleInfo.ID_BUILTIN
|
|
1021
|
+
: state.fallbackBundleId;
|
|
1022
|
+
|
|
1023
|
+
this.editor.putString(this.CAP_SERVER_PATH, currentBundlePath);
|
|
1024
|
+
this.editor.putString(FALLBACK_VERSION, fallbackBundleId);
|
|
1025
|
+
if (state.nextBundleId == null || state.nextBundleId.isEmpty()) {
|
|
1026
|
+
this.editor.remove(NEXT_VERSION);
|
|
1027
|
+
} else {
|
|
1028
|
+
this.editor.putString(NEXT_VERSION, state.nextBundleId);
|
|
1029
|
+
}
|
|
1030
|
+
this.editor.commit();
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
void prepareResetStateForTransition() {
|
|
1034
|
+
this.setCurrentBundle(new File("public"));
|
|
1035
|
+
this.setFallbackBundle(null);
|
|
1036
|
+
this.setNextBundle(null);
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
void finalizeResetTransition(final String previousBundleName, final boolean internal) {
|
|
1040
|
+
if (this.activity != null) {
|
|
1041
|
+
DownloadWorkerManager.cancelAllDownloads(this.activity);
|
|
1042
|
+
}
|
|
1043
|
+
if (!internal) {
|
|
1044
|
+
this.sendStats("reset", this.getCurrentBundle().getVersionName(), previousBundleName);
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
boolean canSet(final BundleInfo bundle) {
|
|
1049
|
+
return bundle != null && (bundle.isBuiltin() || this.bundleExists(bundle.getId()));
|
|
1050
|
+
}
|
|
1051
|
+
|
|
980
1052
|
public Boolean set(final BundleInfo bundle) {
|
|
981
1053
|
return this.set(bundle.getId());
|
|
982
1054
|
}
|
|
@@ -1001,11 +1073,32 @@ public class CapgoUpdater {
|
|
|
1001
1073
|
return false;
|
|
1002
1074
|
}
|
|
1003
1075
|
|
|
1076
|
+
boolean stagePendingReload(final BundleInfo bundle) {
|
|
1077
|
+
if (bundle == null || bundle.isBuiltin() || !this.bundleExists(bundle.getId())) {
|
|
1078
|
+
return false;
|
|
1079
|
+
}
|
|
1080
|
+
this.setCurrentBundle(this.getBundleDirectory(bundle.getId()));
|
|
1081
|
+
return true;
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
void finalizePendingReload(final BundleInfo bundle, final String previousBundleName) {
|
|
1085
|
+
if (bundle == null || bundle.isBuiltin()) {
|
|
1086
|
+
return;
|
|
1087
|
+
}
|
|
1088
|
+
this.sendStats("set", bundle.getVersionName(), previousBundleName);
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1004
1091
|
public void autoReset() {
|
|
1005
1092
|
final BundleInfo currentBundle = this.getCurrentBundle();
|
|
1006
1093
|
if (!currentBundle.isBuiltin() && !this.bundleExists(currentBundle.getId())) {
|
|
1007
1094
|
logger.info("Folder at bundle path does not exist. Triggering reset.");
|
|
1008
1095
|
this.reset();
|
|
1096
|
+
return;
|
|
1097
|
+
}
|
|
1098
|
+
String bundlePath = this.prefs.getString(this.CAP_SERVER_PATH, null);
|
|
1099
|
+
if (shouldResetForForeignBundle(bundlePath, currentBundle.isBuiltin(), this.hasStoredBundleInfo(currentBundle.getId()))) {
|
|
1100
|
+
logger.info("Current bundle id is not one of the bundle ids stored by this plugin. Triggering reset.");
|
|
1101
|
+
this.reset();
|
|
1009
1102
|
}
|
|
1010
1103
|
}
|
|
1011
1104
|
|
|
@@ -1038,17 +1131,9 @@ public class CapgoUpdater {
|
|
|
1038
1131
|
|
|
1039
1132
|
public void reset(final boolean internal) {
|
|
1040
1133
|
logger.debug("reset: " + internal);
|
|
1041
|
-
|
|
1042
|
-
this.
|
|
1043
|
-
this.
|
|
1044
|
-
this.setNextBundle(null);
|
|
1045
|
-
// Cancel any ongoing downloads
|
|
1046
|
-
if (this.activity != null) {
|
|
1047
|
-
DownloadWorkerManager.cancelAllDownloads(this.activity);
|
|
1048
|
-
}
|
|
1049
|
-
if (!internal) {
|
|
1050
|
-
this.sendStats("reset", this.getCurrentBundle().getVersionName(), currentBundleName);
|
|
1051
|
-
}
|
|
1134
|
+
final String currentBundleName = this.getCurrentBundle().getVersionName();
|
|
1135
|
+
this.prepareResetStateForTransition();
|
|
1136
|
+
this.finalizeResetTransition(currentBundleName, internal);
|
|
1052
1137
|
}
|
|
1053
1138
|
|
|
1054
1139
|
private JSONObject createInfoObject() throws JSONException {
|
|
@@ -1144,6 +1229,7 @@ public class CapgoUpdater {
|
|
|
1144
1229
|
Map<String, Object> retError = new HashMap<>();
|
|
1145
1230
|
retError.put("message", "Request failed: " + e.getMessage());
|
|
1146
1231
|
retError.put("error", "network_error");
|
|
1232
|
+
retError.put("kind", "failed");
|
|
1147
1233
|
callback.callback(retError);
|
|
1148
1234
|
}
|
|
1149
1235
|
|
|
@@ -1151,11 +1237,46 @@ public class CapgoUpdater {
|
|
|
1151
1237
|
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
|
|
1152
1238
|
try (ResponseBody responseBody = response.body()) {
|
|
1153
1239
|
final int statusCode = response.code();
|
|
1240
|
+
final String responseData = responseBody != null ? responseBody.string() : "";
|
|
1241
|
+
JSONObject jsonResponse = null;
|
|
1242
|
+
if (!responseData.isEmpty()) {
|
|
1243
|
+
try {
|
|
1244
|
+
jsonResponse = new JSONObject(responseData);
|
|
1245
|
+
} catch (JSONException ignored) {
|
|
1246
|
+
// Non-JSON responses are handled as response or parse errors below.
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
if (jsonResponse != null && (jsonResponse.has("error") || jsonResponse.has("kind"))) {
|
|
1251
|
+
if (statusCode == 429) {
|
|
1252
|
+
checkAndHandleRateLimitResponse(response);
|
|
1253
|
+
}
|
|
1254
|
+
Map<String, Object> retError = new HashMap<>();
|
|
1255
|
+
if (jsonResponse.has("error") && !jsonResponse.isNull("error")) {
|
|
1256
|
+
retError.put("error", jsonResponse.getString("error"));
|
|
1257
|
+
}
|
|
1258
|
+
if (jsonResponse.has("kind") && !jsonResponse.isNull("kind")) {
|
|
1259
|
+
retError.put("kind", jsonResponse.getString("kind"));
|
|
1260
|
+
}
|
|
1261
|
+
if (jsonResponse.has("message") && !jsonResponse.isNull("message")) {
|
|
1262
|
+
retError.put("message", jsonResponse.getString("message"));
|
|
1263
|
+
} else {
|
|
1264
|
+
retError.put("message", "server did not provide a message");
|
|
1265
|
+
}
|
|
1266
|
+
if (jsonResponse.has("version") && !jsonResponse.isNull("version")) {
|
|
1267
|
+
retError.put("version", jsonResponse.getString("version"));
|
|
1268
|
+
}
|
|
1269
|
+
retError.put("statusCode", statusCode);
|
|
1270
|
+
callback.callback(retError);
|
|
1271
|
+
return;
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1154
1274
|
// Check for 429 rate limit
|
|
1155
1275
|
if (checkAndHandleRateLimitResponse(response)) {
|
|
1156
1276
|
Map<String, Object> retError = new HashMap<>();
|
|
1157
1277
|
retError.put("message", "Rate limit exceeded");
|
|
1158
1278
|
retError.put("error", "rate_limit_exceeded");
|
|
1279
|
+
retError.put("kind", "failed");
|
|
1159
1280
|
retError.put("statusCode", statusCode);
|
|
1160
1281
|
callback.callback(retError);
|
|
1161
1282
|
return;
|
|
@@ -1165,27 +1286,14 @@ public class CapgoUpdater {
|
|
|
1165
1286
|
Map<String, Object> retError = new HashMap<>();
|
|
1166
1287
|
retError.put("message", "Server error: " + response.code());
|
|
1167
1288
|
retError.put("error", "response_error");
|
|
1289
|
+
retError.put("kind", "failed");
|
|
1168
1290
|
retError.put("statusCode", statusCode);
|
|
1169
1291
|
callback.callback(retError);
|
|
1170
1292
|
return;
|
|
1171
1293
|
}
|
|
1172
1294
|
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
JSONObject jsonResponse = new JSONObject(responseData);
|
|
1176
|
-
|
|
1177
|
-
// Check for server-side errors first
|
|
1178
|
-
if (jsonResponse.has("error")) {
|
|
1179
|
-
Map<String, Object> retError = new HashMap<>();
|
|
1180
|
-
retError.put("error", jsonResponse.getString("error"));
|
|
1181
|
-
if (jsonResponse.has("message")) {
|
|
1182
|
-
retError.put("message", jsonResponse.getString("message"));
|
|
1183
|
-
} else {
|
|
1184
|
-
retError.put("message", "server did not provide a message");
|
|
1185
|
-
}
|
|
1186
|
-
retError.put("statusCode", statusCode);
|
|
1187
|
-
callback.callback(retError);
|
|
1188
|
-
return;
|
|
1295
|
+
if (jsonResponse == null) {
|
|
1296
|
+
throw new JSONException("Response is not a JSON object");
|
|
1189
1297
|
}
|
|
1190
1298
|
|
|
1191
1299
|
Map<String, Object> ret = new HashMap<>();
|
|
@@ -1207,6 +1315,7 @@ public class CapgoUpdater {
|
|
|
1207
1315
|
Map<String, Object> retError = new HashMap<>();
|
|
1208
1316
|
retError.put("message", "JSON parse error: " + e.getMessage());
|
|
1209
1317
|
retError.put("error", "parse_error");
|
|
1318
|
+
retError.put("kind", "failed");
|
|
1210
1319
|
callback.callback(retError);
|
|
1211
1320
|
}
|
|
1212
1321
|
}
|
|
@@ -1707,7 +1816,13 @@ public class CapgoUpdater {
|
|
|
1707
1816
|
}
|
|
1708
1817
|
BundleInfo result;
|
|
1709
1818
|
if (BundleInfo.ID_BUILTIN.equals(trueId)) {
|
|
1710
|
-
result = new BundleInfo(
|
|
1819
|
+
result = new BundleInfo(
|
|
1820
|
+
trueId,
|
|
1821
|
+
this.versionBuild == null || this.versionBuild.isEmpty() ? null : this.versionBuild,
|
|
1822
|
+
BundleStatus.SUCCESS,
|
|
1823
|
+
"",
|
|
1824
|
+
""
|
|
1825
|
+
);
|
|
1711
1826
|
} else if (BundleInfo.VERSION_UNKNOWN.equals(trueId)) {
|
|
1712
1827
|
result = new BundleInfo(trueId, null, BundleStatus.ERROR, "", "");
|
|
1713
1828
|
} else {
|
|
@@ -1812,6 +1927,7 @@ public class CapgoUpdater {
|
|
|
1812
1927
|
}
|
|
1813
1928
|
|
|
1814
1929
|
public boolean setNextBundle(final String next) {
|
|
1930
|
+
BundleInfo bundleToNotify = null;
|
|
1815
1931
|
if (next == null) {
|
|
1816
1932
|
this.editor.remove(NEXT_VERSION);
|
|
1817
1933
|
} else {
|
|
@@ -1821,8 +1937,15 @@ public class CapgoUpdater {
|
|
|
1821
1937
|
}
|
|
1822
1938
|
this.editor.putString(NEXT_VERSION, next);
|
|
1823
1939
|
this.setBundleStatus(next, BundleStatus.PENDING);
|
|
1940
|
+
bundleToNotify = newBundle;
|
|
1824
1941
|
}
|
|
1825
1942
|
this.editor.commit();
|
|
1943
|
+
if (bundleToNotify != null) {
|
|
1944
|
+
this.sendStats("set_next", bundleToNotify.getVersionName(), this.getCurrentBundle().getVersionName());
|
|
1945
|
+
final Map<String, Object> payload = new HashMap<>();
|
|
1946
|
+
payload.put("bundle", bundleToNotify.toJSONMap());
|
|
1947
|
+
this.notifyListeners("setNext", payload);
|
|
1948
|
+
}
|
|
1826
1949
|
return true;
|
|
1827
1950
|
}
|
|
1828
1951
|
|
|
@@ -91,27 +91,52 @@ public class DownloadService extends Worker {
|
|
|
91
91
|
.protocols(Arrays.asList(Protocol.HTTP_2, Protocol.HTTP_1_1))
|
|
92
92
|
.addInterceptor((chain) -> {
|
|
93
93
|
Request originalRequest = chain.request();
|
|
94
|
-
String userAgent =
|
|
95
|
-
"CapacitorUpdater/" +
|
|
96
|
-
(currentPluginVersion != null ? currentPluginVersion : "unknown") +
|
|
97
|
-
" (" +
|
|
98
|
-
(currentAppId != null ? currentAppId : "unknown") +
|
|
99
|
-
") android/" +
|
|
100
|
-
(currentVersionOs != null ? currentVersionOs : "unknown");
|
|
94
|
+
String userAgent = buildUserAgent(currentAppId, currentPluginVersion, currentVersionOs);
|
|
101
95
|
Request requestWithUserAgent = originalRequest.newBuilder().header("User-Agent", userAgent).build();
|
|
102
96
|
return chain.proceed(requestWithUserAgent);
|
|
103
97
|
})
|
|
104
98
|
.build();
|
|
105
99
|
}
|
|
106
100
|
|
|
101
|
+
static String buildUserAgent(String appId, String pluginVersion, String versionOs) {
|
|
102
|
+
return (
|
|
103
|
+
"CapacitorUpdater/" +
|
|
104
|
+
sanitizeUserAgentValue(pluginVersion) +
|
|
105
|
+
" (" +
|
|
106
|
+
sanitizeUserAgentValue(appId) +
|
|
107
|
+
") android/" +
|
|
108
|
+
sanitizeUserAgentValue(versionOs)
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private static String sanitizeUserAgentValue(String value) {
|
|
113
|
+
if (value == null || value.isEmpty()) {
|
|
114
|
+
return "unknown";
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
StringBuilder sanitized = new StringBuilder();
|
|
118
|
+
value
|
|
119
|
+
.codePoints()
|
|
120
|
+
.forEach((cp) -> {
|
|
121
|
+
boolean isVisibleAscii = cp >= 0x20 && cp <= 0x7E;
|
|
122
|
+
boolean isIso88591 = cp >= 0xA0 && cp <= 0xFF;
|
|
123
|
+
if (isVisibleAscii || isIso88591) {
|
|
124
|
+
sanitized.appendCodePoint(cp);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
String result = sanitized.toString().trim();
|
|
129
|
+
return result.isEmpty() ? "unknown" : result;
|
|
130
|
+
}
|
|
131
|
+
|
|
107
132
|
// Method to update User-Agent values
|
|
108
133
|
public static void updateUserAgent(String appId, String pluginVersion, String versionOs) {
|
|
109
|
-
currentAppId = appId
|
|
110
|
-
currentPluginVersion = pluginVersion
|
|
111
|
-
currentVersionOs = versionOs
|
|
112
|
-
logger
|
|
113
|
-
"Updated User-Agent:
|
|
114
|
-
|
|
134
|
+
currentAppId = sanitizeUserAgentValue(appId);
|
|
135
|
+
currentPluginVersion = sanitizeUserAgentValue(pluginVersion);
|
|
136
|
+
currentVersionOs = sanitizeUserAgentValue(versionOs);
|
|
137
|
+
if (logger != null) {
|
|
138
|
+
logger.debug("Updated User-Agent: " + buildUserAgent(currentAppId, currentPluginVersion, currentVersionOs));
|
|
139
|
+
}
|
|
115
140
|
}
|
|
116
141
|
|
|
117
142
|
public DownloadService(@NonNull Context context, @NonNull WorkerParameters params) {
|
|
@@ -249,12 +249,7 @@ public class ShakeMenu implements ShakeDetector.Listener {
|
|
|
249
249
|
}
|
|
250
250
|
|
|
251
251
|
List<?> channelsRaw = (List<?>) channelsObj;
|
|
252
|
-
List<Map<String, Object>> channels =
|
|
253
|
-
for (Object item : channelsRaw) {
|
|
254
|
-
if (item instanceof Map) {
|
|
255
|
-
channels.add((Map<String, Object>) item);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
252
|
+
List<Map<String, Object>> channels = toChannelList(channelsRaw);
|
|
258
253
|
|
|
259
254
|
if (channels.isEmpty()) {
|
|
260
255
|
showError("No channels available for self-assignment");
|
|
@@ -273,6 +268,27 @@ public class ShakeMenu implements ShakeDetector.Listener {
|
|
|
273
268
|
});
|
|
274
269
|
}
|
|
275
270
|
|
|
271
|
+
private List<Map<String, Object>> toChannelList(List<?> channelsRaw) {
|
|
272
|
+
List<Map<String, Object>> channels = new ArrayList<>();
|
|
273
|
+
for (Object item : channelsRaw) {
|
|
274
|
+
if (!(item instanceof Map<?, ?> rawMap)) {
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
Map<String, Object> channel = new java.util.HashMap<>();
|
|
279
|
+
for (Map.Entry<?, ?> entry : rawMap.entrySet()) {
|
|
280
|
+
if (entry.getKey() instanceof String key) {
|
|
281
|
+
channel.put(key, entry.getValue());
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (!channel.isEmpty()) {
|
|
286
|
+
channels.add(channel);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
return channels;
|
|
290
|
+
}
|
|
291
|
+
|
|
276
292
|
private void presentChannelPicker(List<Map<String, Object>> channels) {
|
|
277
293
|
try {
|
|
278
294
|
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
|
@@ -432,12 +448,36 @@ public class ShakeMenu implements ShakeDetector.Listener {
|
|
|
432
448
|
}
|
|
433
449
|
|
|
434
450
|
String latestError = getString(latestRes, "error");
|
|
451
|
+
String latestKind = getString(latestRes, "kind");
|
|
452
|
+
String latestMessage = getString(latestRes, "message");
|
|
453
|
+
|
|
454
|
+
String detail = latestMessage != null && !latestMessage.isEmpty()
|
|
455
|
+
? latestMessage
|
|
456
|
+
: latestError != null && !latestError.isEmpty()
|
|
457
|
+
? latestError
|
|
458
|
+
: latestKind != null && !latestKind.isEmpty()
|
|
459
|
+
? latestKind
|
|
460
|
+
: "server did not provide a message";
|
|
435
461
|
|
|
436
462
|
// Handle update errors first (before "no new version" check)
|
|
437
|
-
if (
|
|
463
|
+
if (
|
|
464
|
+
"failed".equals(latestKind) ||
|
|
465
|
+
(latestError != null &&
|
|
466
|
+
!latestError.isEmpty() &&
|
|
467
|
+
!"up_to_date".equals(latestKind) &&
|
|
468
|
+
!"blocked".equals(latestKind))
|
|
469
|
+
) {
|
|
470
|
+
activity.runOnUiThread(() -> {
|
|
471
|
+
progressDialog.dismiss();
|
|
472
|
+
showError("Channel set to " + channelName + ". Update check failed: " + detail);
|
|
473
|
+
});
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
if ("blocked".equals(latestKind)) {
|
|
438
478
|
activity.runOnUiThread(() -> {
|
|
439
479
|
progressDialog.dismiss();
|
|
440
|
-
showError("Channel set to " + channelName + ". Update check
|
|
480
|
+
showError("Channel set to " + channelName + ". Update check blocked: " + detail);
|
|
441
481
|
});
|
|
442
482
|
return;
|
|
443
483
|
}
|
|
@@ -445,7 +485,7 @@ public class ShakeMenu implements ShakeDetector.Listener {
|
|
|
445
485
|
String latestUrl = getString(latestRes, "url");
|
|
446
486
|
|
|
447
487
|
// Check if there's an actual update available
|
|
448
|
-
if ("
|
|
488
|
+
if ("up_to_date".equals(latestKind) || latestUrl == null || latestUrl.isEmpty()) {
|
|
449
489
|
activity.runOnUiThread(() -> {
|
|
450
490
|
progressDialog.dismiss();
|
|
451
491
|
showSuccess("Channel set to " + channelName + ". Already on latest version.");
|