@capgo/capacitor-updater 7.43.3 → 7.50.1
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 +5 -2
- package/README.md +643 -115
- package/android/build.gradle +3 -3
- package/android/src/main/java/ee/forgr/capacitor_updater/AndroidAppExitReporter.java +92 -0
- package/android/src/main/java/ee/forgr/capacitor_updater/CapacitorUpdaterPlugin.java +3121 -353
- package/android/src/main/java/ee/forgr/capacitor_updater/CapgoUpdater.java +924 -290
- package/android/src/main/java/ee/forgr/capacitor_updater/DelayUpdateUtils.java +49 -13
- package/android/src/main/java/ee/forgr/capacitor_updater/DeviceIdHelper.java +45 -30
- package/android/src/main/java/ee/forgr/capacitor_updater/DownloadService.java +75 -32
- package/android/src/main/java/ee/forgr/capacitor_updater/DownloadWorkerManager.java +2 -0
- package/android/src/main/java/ee/forgr/capacitor_updater/ShakeDetector.java +3 -3
- package/android/src/main/java/ee/forgr/capacitor_updater/ShakeMenu.java +401 -27
- package/android/src/main/java/ee/forgr/capacitor_updater/ThreeFingerPinchDetector.java +323 -0
- package/dist/docs.json +1590 -196
- package/dist/esm/definitions.d.ts +755 -66
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.d.ts +11 -2
- package/dist/esm/web.js +59 -5
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +59 -5
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +59 -5
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/CapacitorUpdaterPlugin/AES.swift +0 -1
- package/ios/Sources/CapacitorUpdaterPlugin/AppHealthTracker.swift +82 -0
- package/ios/Sources/CapacitorUpdaterPlugin/BigInt.swift +0 -16
- package/ios/Sources/CapacitorUpdaterPlugin/BundleInfo.swift +2 -2
- package/ios/Sources/CapacitorUpdaterPlugin/BundleStatus.swift +78 -2
- package/ios/Sources/CapacitorUpdaterPlugin/CapacitorUpdaterPlugin.swift +2732 -417
- package/ios/Sources/CapacitorUpdaterPlugin/CapgoUpdater.swift +1191 -363
- package/ios/Sources/CapacitorUpdaterPlugin/CryptoCipher.swift +0 -1
- package/ios/Sources/CapacitorUpdaterPlugin/DelayUpdateUtils.swift +37 -16
- package/ios/Sources/CapacitorUpdaterPlugin/InternalUtils.swift +80 -1
- package/ios/Sources/CapacitorUpdaterPlugin/ShakeMenu.swift +438 -39
- package/ios/Sources/CapacitorUpdaterPlugin/WebViewStatsReporter.swift +276 -0
- package/package.json +24 -9
|
@@ -19,42 +19,78 @@ import android.widget.ListView;
|
|
|
19
19
|
import android.widget.ProgressBar;
|
|
20
20
|
import com.getcapacitor.Bridge;
|
|
21
21
|
import com.getcapacitor.BridgeActivity;
|
|
22
|
+
import com.getcapacitor.JSArray;
|
|
23
|
+
import com.getcapacitor.JSObject;
|
|
22
24
|
import java.util.ArrayList;
|
|
23
25
|
import java.util.List;
|
|
24
26
|
import java.util.Map;
|
|
25
27
|
import org.json.JSONArray;
|
|
28
|
+
import org.json.JSONObject;
|
|
26
29
|
|
|
27
|
-
public class ShakeMenu implements ShakeDetector.Listener {
|
|
30
|
+
public class ShakeMenu implements ShakeDetector.Listener, ThreeFingerPinchDetector.Listener {
|
|
31
|
+
|
|
32
|
+
private interface PreviewMenuAction {
|
|
33
|
+
boolean run();
|
|
34
|
+
}
|
|
28
35
|
|
|
29
36
|
private CapacitorUpdaterPlugin plugin;
|
|
30
37
|
private BridgeActivity activity;
|
|
31
38
|
private ShakeDetector shakeDetector;
|
|
39
|
+
private ThreeFingerPinchDetector pinchDetector;
|
|
32
40
|
private boolean isShowing = false;
|
|
33
41
|
private Logger logger;
|
|
42
|
+
private String gesture;
|
|
34
43
|
|
|
35
|
-
public ShakeMenu(CapacitorUpdaterPlugin plugin, BridgeActivity activity, Logger logger) {
|
|
44
|
+
public ShakeMenu(CapacitorUpdaterPlugin plugin, BridgeActivity activity, Logger logger, String gesture) {
|
|
36
45
|
this.plugin = plugin;
|
|
37
46
|
this.activity = activity;
|
|
38
47
|
this.logger = logger;
|
|
48
|
+
this.gesture = gesture;
|
|
49
|
+
|
|
50
|
+
if (CapacitorUpdaterPlugin.SHAKE_MENU_GESTURE_THREE_FINGER_PINCH.equals(gesture)) {
|
|
51
|
+
this.pinchDetector = new ThreeFingerPinchDetector(this, logger);
|
|
52
|
+
this.pinchDetector.start(activity);
|
|
53
|
+
} else {
|
|
54
|
+
SensorManager sensorManager = (SensorManager) activity.getSystemService(Activity.SENSOR_SERVICE);
|
|
55
|
+
this.shakeDetector = new ShakeDetector(this);
|
|
56
|
+
this.shakeDetector.start(sensorManager);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
39
59
|
|
|
40
|
-
|
|
41
|
-
this.
|
|
42
|
-
this.shakeDetector.start(sensorManager);
|
|
60
|
+
public boolean usesGesture(String gesture) {
|
|
61
|
+
return this.gesture != null && this.gesture.equals(gesture);
|
|
43
62
|
}
|
|
44
63
|
|
|
45
64
|
public void stop() {
|
|
46
65
|
if (shakeDetector != null) {
|
|
47
66
|
shakeDetector.stop();
|
|
48
67
|
}
|
|
68
|
+
if (pinchDetector != null) {
|
|
69
|
+
pinchDetector.stop();
|
|
70
|
+
}
|
|
49
71
|
}
|
|
50
72
|
|
|
51
73
|
@Override
|
|
52
74
|
public void onShakeDetected() {
|
|
53
|
-
|
|
75
|
+
onMenuGestureDetected("Shake");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@Override
|
|
79
|
+
public void onThreeFingerPinchDetected() {
|
|
80
|
+
onMenuGestureDetected("Three finger pinch");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private void onMenuGestureDetected(String gestureName) {
|
|
84
|
+
logger.info(gestureName + " detected");
|
|
54
85
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
86
|
+
boolean canShowPreviewMenu = Boolean.TRUE.equals(plugin.shakeMenuEnabled) && plugin.hasActivePreviewSession();
|
|
87
|
+
boolean canShowChannelSelector = Boolean.TRUE.equals(plugin.shakeChannelSelectorEnabled);
|
|
88
|
+
if (!canShowPreviewMenu && !canShowChannelSelector) {
|
|
89
|
+
if (Boolean.TRUE.equals(plugin.shakeMenuEnabled)) {
|
|
90
|
+
logger.info("Shake preview menu ignored because no preview session is active");
|
|
91
|
+
} else {
|
|
92
|
+
logger.info("Shake menu is disabled");
|
|
93
|
+
}
|
|
58
94
|
return;
|
|
59
95
|
}
|
|
60
96
|
|
|
@@ -66,15 +102,313 @@ public class ShakeMenu implements ShakeDetector.Listener {
|
|
|
66
102
|
|
|
67
103
|
isShowing = true;
|
|
68
104
|
|
|
69
|
-
|
|
70
|
-
if (plugin.shakeChannelSelectorEnabled) {
|
|
71
|
-
showChannelSelector();
|
|
72
|
-
} else {
|
|
105
|
+
if (canShowPreviewMenu) {
|
|
73
106
|
showDefaultMenu();
|
|
107
|
+
} else {
|
|
108
|
+
showChannelSelector();
|
|
74
109
|
}
|
|
75
110
|
}
|
|
76
111
|
|
|
77
112
|
private void showDefaultMenu() {
|
|
113
|
+
activity.runOnUiThread(() -> {
|
|
114
|
+
try {
|
|
115
|
+
if (!plugin.hasActivePreviewSession()) {
|
|
116
|
+
logger.info("Shake preview menu ignored because no preview session is active");
|
|
117
|
+
isShowing = false;
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (Boolean.TRUE.equals(plugin.shakeChannelSelectorEnabled)) {
|
|
121
|
+
showCombinedPreviewMenu();
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
String appName = activity.getPackageManager().getApplicationLabel(activity.getApplicationInfo()).toString();
|
|
125
|
+
String title = "Preview " + appName + " Menu";
|
|
126
|
+
String message = "Reload, switch, or leave the current preview.";
|
|
127
|
+
List<String> actions = new ArrayList<>();
|
|
128
|
+
actions.add("Reload preview");
|
|
129
|
+
if (plugin.previewMenuPreviews().length() > 0) {
|
|
130
|
+
actions.add("Switch preview");
|
|
131
|
+
}
|
|
132
|
+
actions.add("Leave test app");
|
|
133
|
+
final boolean[] openingNestedSelector = { false };
|
|
134
|
+
final boolean[] previewActionRunning = { false };
|
|
135
|
+
|
|
136
|
+
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
|
137
|
+
builder.setTitle(title);
|
|
138
|
+
builder.setMessage(message);
|
|
139
|
+
builder.setItems(actions.toArray(new String[0]), (dialogInterface, which) -> {
|
|
140
|
+
AlertDialog dialog = (AlertDialog) dialogInterface;
|
|
141
|
+
String action = actions.get(which);
|
|
142
|
+
if ("Reload preview".equals(action)) {
|
|
143
|
+
previewActionRunning[0] = true;
|
|
144
|
+
logger.info("Reloading webview");
|
|
145
|
+
runPreviewMenuAction(dialog, "Could not reload the test app.", "Error reloading test app: ", () ->
|
|
146
|
+
plugin.reloadPreviewSessionFromShakeMenu()
|
|
147
|
+
);
|
|
148
|
+
} else if ("Switch preview".equals(action)) {
|
|
149
|
+
openingNestedSelector[0] = true;
|
|
150
|
+
dialog.dismiss();
|
|
151
|
+
showPreviewSelector();
|
|
152
|
+
} else {
|
|
153
|
+
previewActionRunning[0] = true;
|
|
154
|
+
runPreviewMenuAction(dialog, "Could not leave the test app.", "Error leaving test app: ", () ->
|
|
155
|
+
plugin.leavePreviewSessionFromShakeMenu()
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// Cancel button
|
|
161
|
+
builder.setNegativeButton(
|
|
162
|
+
"Close menu",
|
|
163
|
+
new DialogInterface.OnClickListener() {
|
|
164
|
+
public void onClick(DialogInterface dialog, int id) {
|
|
165
|
+
logger.info("Shake menu cancelled");
|
|
166
|
+
dialog.dismiss();
|
|
167
|
+
isShowing = false;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
AlertDialog dialog = builder.create();
|
|
173
|
+
dialog.setOnDismissListener((dialogInterface) -> {
|
|
174
|
+
if (!openingNestedSelector[0] && !previewActionRunning[0]) {
|
|
175
|
+
isShowing = false;
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
dialog.show();
|
|
179
|
+
} catch (Exception e) {
|
|
180
|
+
logger.error("Error showing shake menu: " + e.getMessage());
|
|
181
|
+
isShowing = false;
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
private void showCombinedPreviewMenu() {
|
|
187
|
+
try {
|
|
188
|
+
String appName = activity.getPackageManager().getApplicationLabel(activity.getApplicationInfo()).toString();
|
|
189
|
+
String title = "Preview " + appName + " Menu";
|
|
190
|
+
String message = "Reload, switch, or leave the current preview.";
|
|
191
|
+
List<String> actions = new ArrayList<>();
|
|
192
|
+
actions.add("Reload preview");
|
|
193
|
+
if (plugin.previewMenuPreviews().length() > 0) {
|
|
194
|
+
actions.add("Switch preview");
|
|
195
|
+
}
|
|
196
|
+
actions.add("Leave test app");
|
|
197
|
+
actions.add("Switch channel");
|
|
198
|
+
final boolean[] openingNestedSelector = { false };
|
|
199
|
+
final boolean[] previewActionRunning = { false };
|
|
200
|
+
|
|
201
|
+
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
|
202
|
+
builder.setTitle(title);
|
|
203
|
+
builder.setMessage(message);
|
|
204
|
+
builder.setItems(actions.toArray(new String[0]), (dialogInterface, which) -> {
|
|
205
|
+
AlertDialog dialog = (AlertDialog) dialogInterface;
|
|
206
|
+
String action = actions.get(which);
|
|
207
|
+
if ("Reload preview".equals(action)) {
|
|
208
|
+
previewActionRunning[0] = true;
|
|
209
|
+
logger.info("Reloading webview");
|
|
210
|
+
runPreviewMenuAction(dialog, "Could not reload the test app.", "Error reloading test app: ", () ->
|
|
211
|
+
plugin.reloadPreviewSessionFromShakeMenu()
|
|
212
|
+
);
|
|
213
|
+
} else if ("Leave test app".equals(action)) {
|
|
214
|
+
previewActionRunning[0] = true;
|
|
215
|
+
runPreviewMenuAction(dialog, "Could not leave the test app.", "Error leaving test app: ", () ->
|
|
216
|
+
plugin.leavePreviewSessionFromShakeMenu()
|
|
217
|
+
);
|
|
218
|
+
} else if ("Switch preview".equals(action)) {
|
|
219
|
+
openingNestedSelector[0] = true;
|
|
220
|
+
dialog.dismiss();
|
|
221
|
+
showPreviewSelector();
|
|
222
|
+
} else {
|
|
223
|
+
openingNestedSelector[0] = true;
|
|
224
|
+
dialog.dismiss();
|
|
225
|
+
showChannelSelector();
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
builder.setNegativeButton("Close menu", (dialog, id) -> {
|
|
229
|
+
logger.info("Shake menu cancelled");
|
|
230
|
+
dialog.dismiss();
|
|
231
|
+
isShowing = false;
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
AlertDialog dialog = builder.create();
|
|
235
|
+
dialog.setOnDismissListener((dialogInterface) -> {
|
|
236
|
+
if (!openingNestedSelector[0] && !previewActionRunning[0]) {
|
|
237
|
+
isShowing = false;
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
dialog.show();
|
|
241
|
+
} catch (Exception e) {
|
|
242
|
+
logger.error("Error showing combined shake menu: " + e.getMessage());
|
|
243
|
+
isShowing = false;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
private void runPreviewMenuAction(AlertDialog dialog, String failureMessage, String errorPrefix, PreviewMenuAction action) {
|
|
248
|
+
new Thread(() -> {
|
|
249
|
+
try {
|
|
250
|
+
if (!action.run()) {
|
|
251
|
+
activity.runOnUiThread(() -> showError(failureMessage));
|
|
252
|
+
}
|
|
253
|
+
} catch (Exception e) {
|
|
254
|
+
logger.error(errorPrefix + e.getMessage());
|
|
255
|
+
activity.runOnUiThread(() -> showError(errorPrefix + e.getMessage()));
|
|
256
|
+
} finally {
|
|
257
|
+
activity.runOnUiThread(() -> {
|
|
258
|
+
dialog.dismiss();
|
|
259
|
+
isShowing = false;
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
}).start();
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
private void setPreviewMenuButtonsEnabled(AlertDialog dialog, boolean enabled) {
|
|
266
|
+
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(enabled);
|
|
267
|
+
dialog.getButton(AlertDialog.BUTTON_NEUTRAL).setEnabled(enabled);
|
|
268
|
+
dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setEnabled(enabled);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
private void showPreviewSelector() {
|
|
272
|
+
activity.runOnUiThread(() -> {
|
|
273
|
+
try {
|
|
274
|
+
JSArray previewsRaw = plugin.previewMenuPreviews();
|
|
275
|
+
List<JSObject> previews = new ArrayList<>();
|
|
276
|
+
for (int i = 0; i < previewsRaw.length(); i++) {
|
|
277
|
+
Object raw = previewsRaw.opt(i);
|
|
278
|
+
if (raw instanceof JSObject preview) {
|
|
279
|
+
previews.add(preview);
|
|
280
|
+
} else if (raw instanceof JSONObject json) {
|
|
281
|
+
previews.add(JSObject.fromJSONObject(json));
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (previews.isEmpty()) {
|
|
286
|
+
showError("No saved previews available on this device.");
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
presentPreviewPicker(previews);
|
|
291
|
+
} catch (Exception e) {
|
|
292
|
+
logger.error("Error showing preview selector: " + e.getMessage());
|
|
293
|
+
isShowing = false;
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
private String previewLabel(JSObject preview) {
|
|
299
|
+
String name = preview.optString("name", "");
|
|
300
|
+
JSObject bundle = preview.getJSObject("bundle");
|
|
301
|
+
String version = bundle == null ? "" : bundle.optString("version", "");
|
|
302
|
+
String label = !name.isEmpty() ? name : (!version.isEmpty() ? version : preview.optString("id", "Preview"));
|
|
303
|
+
if (preview.optBoolean("isActive", false)) {
|
|
304
|
+
label += " (current)";
|
|
305
|
+
}
|
|
306
|
+
return label;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
private void presentPreviewPicker(List<JSObject> previews) {
|
|
310
|
+
try {
|
|
311
|
+
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
|
312
|
+
builder.setTitle("Select Preview");
|
|
313
|
+
|
|
314
|
+
LinearLayout layout = new LinearLayout(activity);
|
|
315
|
+
layout.setOrientation(LinearLayout.VERTICAL);
|
|
316
|
+
int padding = dpToPx(16);
|
|
317
|
+
layout.setPadding(padding, padding, padding, padding);
|
|
318
|
+
|
|
319
|
+
EditText searchField = new EditText(activity);
|
|
320
|
+
searchField.setHint("Search previews...");
|
|
321
|
+
searchField.setSingleLine(true);
|
|
322
|
+
layout.addView(searchField);
|
|
323
|
+
|
|
324
|
+
final List<JSObject> displayedPreviews = new ArrayList<>();
|
|
325
|
+
displayedPreviews.addAll(previews.subList(0, Math.min(5, previews.size())));
|
|
326
|
+
final ArrayAdapter<String> adapter = new ArrayAdapter<>(
|
|
327
|
+
activity,
|
|
328
|
+
android.R.layout.simple_list_item_1,
|
|
329
|
+
previewLabels(displayedPreviews)
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
ListView listView = new ListView(activity);
|
|
333
|
+
listView.setAdapter(adapter);
|
|
334
|
+
LinearLayout.LayoutParams listParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, dpToPx(250));
|
|
335
|
+
listView.setLayoutParams(listParams);
|
|
336
|
+
layout.addView(listView);
|
|
337
|
+
|
|
338
|
+
builder.setView(layout);
|
|
339
|
+
builder.setNegativeButton("Cancel", (dialog, which) -> {
|
|
340
|
+
dialog.dismiss();
|
|
341
|
+
isShowing = false;
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
AlertDialog dialog = builder.create();
|
|
345
|
+
dialog.setOnDismissListener((d) -> isShowing = false);
|
|
346
|
+
|
|
347
|
+
searchField.addTextChangedListener(
|
|
348
|
+
new TextWatcher() {
|
|
349
|
+
@Override
|
|
350
|
+
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
|
|
351
|
+
|
|
352
|
+
@Override
|
|
353
|
+
public void onTextChanged(CharSequence s, int start, int before, int count) {}
|
|
354
|
+
|
|
355
|
+
@Override
|
|
356
|
+
public void afterTextChanged(Editable s) {
|
|
357
|
+
String query = s.toString().toLowerCase();
|
|
358
|
+
displayedPreviews.clear();
|
|
359
|
+
|
|
360
|
+
for (JSObject preview : previews) {
|
|
361
|
+
if (previewLabel(preview).toLowerCase().contains(query)) {
|
|
362
|
+
displayedPreviews.add(preview);
|
|
363
|
+
if (displayedPreviews.size() >= 5) break;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
adapter.clear();
|
|
368
|
+
adapter.addAll(previewLabels(displayedPreviews));
|
|
369
|
+
adapter.notifyDataSetChanged();
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
);
|
|
373
|
+
|
|
374
|
+
listView.setOnItemClickListener((parent, view, position, id) -> {
|
|
375
|
+
JSObject selectedPreview = displayedPreviews.get(position);
|
|
376
|
+
String previewId = selectedPreview.optString("id", "");
|
|
377
|
+
dialog.dismiss();
|
|
378
|
+
selectPreview(previewId);
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
dialog.show();
|
|
382
|
+
} catch (Exception e) {
|
|
383
|
+
logger.error("Error presenting preview picker: " + e.getMessage());
|
|
384
|
+
isShowing = false;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
private List<String> previewLabels(List<JSObject> previews) {
|
|
389
|
+
List<String> labels = new ArrayList<>();
|
|
390
|
+
for (JSObject preview : previews) {
|
|
391
|
+
labels.add(previewLabel(preview));
|
|
392
|
+
}
|
|
393
|
+
return labels;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
private void selectPreview(String previewId) {
|
|
397
|
+
new Thread(() -> {
|
|
398
|
+
try {
|
|
399
|
+
if (!plugin.setPreviewFromShakeMenu(previewId)) {
|
|
400
|
+
activity.runOnUiThread(() -> showError("Could not switch preview."));
|
|
401
|
+
}
|
|
402
|
+
} catch (Exception e) {
|
|
403
|
+
logger.error("Error switching preview: " + e.getMessage());
|
|
404
|
+
activity.runOnUiThread(() -> showError("Error switching preview: " + e.getMessage()));
|
|
405
|
+
} finally {
|
|
406
|
+
isShowing = false;
|
|
407
|
+
}
|
|
408
|
+
}).start();
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
private void showConfiguredDefaultMenu() {
|
|
78
412
|
activity.runOnUiThread(() -> {
|
|
79
413
|
try {
|
|
80
414
|
String appName = activity.getPackageManager().getApplicationLabel(activity.getApplicationInfo()).toString();
|
|
@@ -120,7 +454,6 @@ public class ShakeMenu implements ShakeDetector.Listener {
|
|
|
120
454
|
bridge.setServerAssetPath(path);
|
|
121
455
|
}
|
|
122
456
|
|
|
123
|
-
// Try to delete the current bundle
|
|
124
457
|
try {
|
|
125
458
|
updater.delete(current.getId());
|
|
126
459
|
} catch (Exception err) {
|
|
@@ -249,12 +582,7 @@ public class ShakeMenu implements ShakeDetector.Listener {
|
|
|
249
582
|
}
|
|
250
583
|
|
|
251
584
|
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
|
-
}
|
|
585
|
+
List<Map<String, Object>> channels = toChannelList(channelsRaw);
|
|
258
586
|
|
|
259
587
|
if (channels.isEmpty()) {
|
|
260
588
|
showError("No channels available for self-assignment");
|
|
@@ -264,8 +592,7 @@ public class ShakeMenu implements ShakeDetector.Listener {
|
|
|
264
592
|
presentChannelPicker(channels);
|
|
265
593
|
});
|
|
266
594
|
});
|
|
267
|
-
})
|
|
268
|
-
.start();
|
|
595
|
+
}).start();
|
|
269
596
|
} catch (Exception e) {
|
|
270
597
|
logger.error("Error showing channel selector: " + e.getMessage());
|
|
271
598
|
isShowing = false;
|
|
@@ -273,6 +600,27 @@ public class ShakeMenu implements ShakeDetector.Listener {
|
|
|
273
600
|
});
|
|
274
601
|
}
|
|
275
602
|
|
|
603
|
+
private List<Map<String, Object>> toChannelList(List<?> channelsRaw) {
|
|
604
|
+
List<Map<String, Object>> channels = new ArrayList<>();
|
|
605
|
+
for (Object item : channelsRaw) {
|
|
606
|
+
if (!(item instanceof Map<?, ?> rawMap)) {
|
|
607
|
+
continue;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
Map<String, Object> channel = new java.util.HashMap<>();
|
|
611
|
+
for (Map.Entry<?, ?> entry : rawMap.entrySet()) {
|
|
612
|
+
if (entry.getKey() instanceof String key) {
|
|
613
|
+
channel.put(key, entry.getValue());
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
if (!channel.isEmpty()) {
|
|
618
|
+
channels.add(channel);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
return channels;
|
|
622
|
+
}
|
|
623
|
+
|
|
276
624
|
private void presentChannelPicker(List<Map<String, Object>> channels) {
|
|
277
625
|
try {
|
|
278
626
|
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
|
@@ -385,6 +733,7 @@ public class ShakeMenu implements ShakeDetector.Listener {
|
|
|
385
733
|
new Thread(() -> {
|
|
386
734
|
final CapgoUpdater updater = plugin.implementation;
|
|
387
735
|
final Bridge bridge = activity.getBridge();
|
|
736
|
+
final String configDefaultChannel = plugin.getConfig().getString("defaultChannel", "");
|
|
388
737
|
|
|
389
738
|
// Set the channel - respect plugin's allowSetDefaultChannel config
|
|
390
739
|
updater.setChannel(
|
|
@@ -392,6 +741,7 @@ public class ShakeMenu implements ShakeDetector.Listener {
|
|
|
392
741
|
updater.editor,
|
|
393
742
|
"CapacitorUpdater.defaultChannel",
|
|
394
743
|
plugin.allowSetDefaultChannel,
|
|
744
|
+
configDefaultChannel,
|
|
395
745
|
(setRes) -> {
|
|
396
746
|
if (setRes == null) {
|
|
397
747
|
activity.runOnUiThread(() -> {
|
|
@@ -432,12 +782,37 @@ public class ShakeMenu implements ShakeDetector.Listener {
|
|
|
432
782
|
}
|
|
433
783
|
|
|
434
784
|
String latestError = getString(latestRes, "error");
|
|
785
|
+
String latestKind = getString(latestRes, "kind");
|
|
786
|
+
String latestMessage = getString(latestRes, "message");
|
|
787
|
+
|
|
788
|
+
String detail =
|
|
789
|
+
latestMessage != null && !latestMessage.isEmpty()
|
|
790
|
+
? latestMessage
|
|
791
|
+
: latestError != null && !latestError.isEmpty()
|
|
792
|
+
? latestError
|
|
793
|
+
: latestKind != null && !latestKind.isEmpty()
|
|
794
|
+
? latestKind
|
|
795
|
+
: "server did not provide a message";
|
|
435
796
|
|
|
436
797
|
// Handle update errors first (before "no new version" check)
|
|
437
|
-
if (
|
|
798
|
+
if (
|
|
799
|
+
"failed".equals(latestKind) ||
|
|
800
|
+
(latestError != null &&
|
|
801
|
+
!latestError.isEmpty() &&
|
|
802
|
+
!"up_to_date".equals(latestKind) &&
|
|
803
|
+
!"blocked".equals(latestKind))
|
|
804
|
+
) {
|
|
805
|
+
activity.runOnUiThread(() -> {
|
|
806
|
+
progressDialog.dismiss();
|
|
807
|
+
showError("Channel set to " + channelName + ". Update check failed: " + detail);
|
|
808
|
+
});
|
|
809
|
+
return;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
if ("blocked".equals(latestKind)) {
|
|
438
813
|
activity.runOnUiThread(() -> {
|
|
439
814
|
progressDialog.dismiss();
|
|
440
|
-
showError("Channel set to " + channelName + ". Update check
|
|
815
|
+
showError("Channel set to " + channelName + ". Update check blocked: " + detail);
|
|
441
816
|
});
|
|
442
817
|
return;
|
|
443
818
|
}
|
|
@@ -445,7 +820,7 @@ public class ShakeMenu implements ShakeDetector.Listener {
|
|
|
445
820
|
String latestUrl = getString(latestRes, "url");
|
|
446
821
|
|
|
447
822
|
// Check if there's an actual update available
|
|
448
|
-
if ("
|
|
823
|
+
if ("up_to_date".equals(latestKind) || latestUrl == null || latestUrl.isEmpty()) {
|
|
449
824
|
activity.runOnUiThread(() -> {
|
|
450
825
|
progressDialog.dismiss();
|
|
451
826
|
showSuccess("Channel set to " + channelName + ". Already on latest version.");
|
|
@@ -536,8 +911,7 @@ public class ShakeMenu implements ShakeDetector.Listener {
|
|
|
536
911
|
});
|
|
537
912
|
}
|
|
538
913
|
);
|
|
539
|
-
})
|
|
540
|
-
.start();
|
|
914
|
+
}).start();
|
|
541
915
|
} catch (Exception e) {
|
|
542
916
|
logger.error("Error selecting channel: " + e.getMessage());
|
|
543
917
|
isShowing = false;
|