@capgo/capacitor-updater 8.48.0 → 8.49.0
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/README.md +186 -8
- package/android/src/main/java/ee/forgr/capacitor_updater/CapacitorUpdaterPlugin.java +645 -111
- package/android/src/main/java/ee/forgr/capacitor_updater/ShakeMenu.java +203 -30
- package/android/src/main/java/ee/forgr/capacitor_updater/ThreeFingerPinchDetector.java +1 -1
- package/dist/docs.json +528 -17
- package/dist/esm/definitions.d.ts +228 -10
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.d.ts +7 -1
- package/dist/esm/web.js +24 -0
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +24 -0
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +24 -0
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/CapacitorUpdaterPlugin/CapacitorUpdaterPlugin.swift +538 -77
- package/ios/Sources/CapacitorUpdaterPlugin/ShakeMenu.swift +225 -16
- package/package.json +1 -1
|
@@ -19,10 +19,13 @@ 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
30
|
public class ShakeMenu implements ShakeDetector.Listener, ThreeFingerPinchDetector.Listener {
|
|
28
31
|
|
|
@@ -36,11 +39,13 @@ public class ShakeMenu implements ShakeDetector.Listener, ThreeFingerPinchDetect
|
|
|
36
39
|
private ThreeFingerPinchDetector pinchDetector;
|
|
37
40
|
private boolean isShowing = false;
|
|
38
41
|
private Logger logger;
|
|
42
|
+
private String gesture;
|
|
39
43
|
|
|
40
44
|
public ShakeMenu(CapacitorUpdaterPlugin plugin, BridgeActivity activity, Logger logger, String gesture) {
|
|
41
45
|
this.plugin = plugin;
|
|
42
46
|
this.activity = activity;
|
|
43
47
|
this.logger = logger;
|
|
48
|
+
this.gesture = gesture;
|
|
44
49
|
|
|
45
50
|
if (CapacitorUpdaterPlugin.SHAKE_MENU_GESTURE_THREE_FINGER_PINCH.equals(gesture)) {
|
|
46
51
|
this.pinchDetector = new ThreeFingerPinchDetector(this, logger);
|
|
@@ -52,6 +57,10 @@ public class ShakeMenu implements ShakeDetector.Listener, ThreeFingerPinchDetect
|
|
|
52
57
|
}
|
|
53
58
|
}
|
|
54
59
|
|
|
60
|
+
public boolean usesGesture(String gesture) {
|
|
61
|
+
return this.gesture != null && this.gesture.equals(gesture);
|
|
62
|
+
}
|
|
63
|
+
|
|
55
64
|
public void stop() {
|
|
56
65
|
if (shakeDetector != null) {
|
|
57
66
|
shakeDetector.stop();
|
|
@@ -114,21 +123,43 @@ public class ShakeMenu implements ShakeDetector.Listener, ThreeFingerPinchDetect
|
|
|
114
123
|
}
|
|
115
124
|
String appName = activity.getPackageManager().getApplicationLabel(activity.getApplicationInfo()).toString();
|
|
116
125
|
String title = "Preview " + appName + " Menu";
|
|
117
|
-
String message = "Reload
|
|
118
|
-
String
|
|
119
|
-
|
|
120
|
-
|
|
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 };
|
|
121
135
|
|
|
122
136
|
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
|
123
137
|
builder.setTitle(title);
|
|
124
138
|
builder.setMessage(message);
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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
|
+
});
|
|
128
159
|
|
|
129
160
|
// Cancel button
|
|
130
161
|
builder.setNegativeButton(
|
|
131
|
-
|
|
162
|
+
"Close menu",
|
|
132
163
|
new DialogInterface.OnClickListener() {
|
|
133
164
|
public void onClick(DialogInterface dialog, int id) {
|
|
134
165
|
logger.info("Shake menu cancelled");
|
|
@@ -139,21 +170,12 @@ public class ShakeMenu implements ShakeDetector.Listener, ThreeFingerPinchDetect
|
|
|
139
170
|
);
|
|
140
171
|
|
|
141
172
|
AlertDialog dialog = builder.create();
|
|
142
|
-
dialog.setOnDismissListener((dialogInterface) ->
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
runPreviewMenuAction(dialog, "Could not leave the test app.", "Error leaving test app: ", () ->
|
|
147
|
-
plugin.leavePreviewSessionFromShakeMenu()
|
|
148
|
-
);
|
|
149
|
-
});
|
|
150
|
-
dialog.getButton(AlertDialog.BUTTON_NEUTRAL).setOnClickListener((view) -> {
|
|
151
|
-
setPreviewMenuButtonsEnabled(dialog, false);
|
|
152
|
-
logger.info("Reloading webview");
|
|
153
|
-
runPreviewMenuAction(dialog, "Could not reload the test app.", "Error reloading test app: ", () ->
|
|
154
|
-
plugin.reloadPreviewSessionFromShakeMenu()
|
|
155
|
-
);
|
|
173
|
+
dialog.setOnDismissListener((dialogInterface) -> {
|
|
174
|
+
if (!openingNestedSelector[0] && !previewActionRunning[0]) {
|
|
175
|
+
isShowing = false;
|
|
176
|
+
}
|
|
156
177
|
});
|
|
178
|
+
dialog.show();
|
|
157
179
|
} catch (Exception e) {
|
|
158
180
|
logger.error("Error showing shake menu: " + e.getMessage());
|
|
159
181
|
isShowing = false;
|
|
@@ -165,29 +187,40 @@ public class ShakeMenu implements ShakeDetector.Listener, ThreeFingerPinchDetect
|
|
|
165
187
|
try {
|
|
166
188
|
String appName = activity.getPackageManager().getApplicationLabel(activity.getApplicationInfo()).toString();
|
|
167
189
|
String title = "Preview " + appName + " Menu";
|
|
168
|
-
String message = "Reload or leave the current preview
|
|
169
|
-
String
|
|
170
|
-
|
|
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 };
|
|
171
199
|
final boolean[] previewActionRunning = { false };
|
|
172
200
|
|
|
173
201
|
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
|
174
202
|
builder.setTitle(title);
|
|
175
203
|
builder.setMessage(message);
|
|
176
|
-
builder.setItems(actions, (dialogInterface, which) -> {
|
|
204
|
+
builder.setItems(actions.toArray(new String[0]), (dialogInterface, which) -> {
|
|
177
205
|
AlertDialog dialog = (AlertDialog) dialogInterface;
|
|
178
|
-
|
|
206
|
+
String action = actions.get(which);
|
|
207
|
+
if ("Reload preview".equals(action)) {
|
|
179
208
|
previewActionRunning[0] = true;
|
|
180
209
|
logger.info("Reloading webview");
|
|
181
210
|
runPreviewMenuAction(dialog, "Could not reload the test app.", "Error reloading test app: ", () ->
|
|
182
211
|
plugin.reloadPreviewSessionFromShakeMenu()
|
|
183
212
|
);
|
|
184
|
-
} else if (
|
|
213
|
+
} else if ("Leave test app".equals(action)) {
|
|
185
214
|
previewActionRunning[0] = true;
|
|
186
215
|
runPreviewMenuAction(dialog, "Could not leave the test app.", "Error leaving test app: ", () ->
|
|
187
216
|
plugin.leavePreviewSessionFromShakeMenu()
|
|
188
217
|
);
|
|
218
|
+
} else if ("Switch preview".equals(action)) {
|
|
219
|
+
openingNestedSelector[0] = true;
|
|
220
|
+
dialog.dismiss();
|
|
221
|
+
showPreviewSelector();
|
|
189
222
|
} else {
|
|
190
|
-
|
|
223
|
+
openingNestedSelector[0] = true;
|
|
191
224
|
dialog.dismiss();
|
|
192
225
|
showChannelSelector();
|
|
193
226
|
}
|
|
@@ -200,7 +233,7 @@ public class ShakeMenu implements ShakeDetector.Listener, ThreeFingerPinchDetect
|
|
|
200
233
|
|
|
201
234
|
AlertDialog dialog = builder.create();
|
|
202
235
|
dialog.setOnDismissListener((dialogInterface) -> {
|
|
203
|
-
if (!
|
|
236
|
+
if (!openingNestedSelector[0] && !previewActionRunning[0]) {
|
|
204
237
|
isShowing = false;
|
|
205
238
|
}
|
|
206
239
|
});
|
|
@@ -235,6 +268,146 @@ public class ShakeMenu implements ShakeDetector.Listener, ThreeFingerPinchDetect
|
|
|
235
268
|
dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setEnabled(enabled);
|
|
236
269
|
}
|
|
237
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
|
+
|
|
238
411
|
private void showConfiguredDefaultMenu() {
|
|
239
412
|
activity.runOnUiThread(() -> {
|
|
240
413
|
try {
|
|
@@ -19,7 +19,7 @@ public class ThreeFingerPinchDetector implements View.OnTouchListener {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
private static final int REQUIRED_POINTER_COUNT = 3;
|
|
22
|
-
private static final float MIN_SCALE_DELTA = 0.
|
|
22
|
+
private static final float MIN_SCALE_DELTA = 0.12f;
|
|
23
23
|
private static final long PINCH_TIMEOUT = 1000;
|
|
24
24
|
|
|
25
25
|
private final Listener listener;
|