@capgo/capacitor-updater 8.47.9 → 8.47.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.
@@ -2519,7 +2519,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
2519
2519
  }
2520
2520
 
2521
2521
  final BundleInfo previewFallbackBundle = this.implementation.getPreviewFallbackBundle();
2522
- this.endPreviewSession();
2522
+ this.endPreviewSession(true);
2523
2523
  final BundleInfo restoredNextBundle = this.implementation.getNextBundle();
2524
2524
  this.deletePreviewBundleIfUnused(previewBundle, previewFallbackBundle, restoredNextBundle);
2525
2525
  return true;
@@ -17,8 +17,8 @@ public class ShakeDetector implements SensorEventListener {
17
17
  void onShakeDetected();
18
18
  }
19
19
 
20
- private static final float SHAKE_THRESHOLD = 12.0f; // Acceleration threshold for shake detection
21
- private static final int SHAKE_TIMEOUT = 500; // Minimum time between shake events (ms)
20
+ private static final float SHAKE_THRESHOLD = 16.0f; // Acceleration threshold for shake detection
21
+ private static final int SHAKE_TIMEOUT = 1000; // Minimum time between shake events (ms)
22
22
 
23
23
  private Listener listener;
24
24
  private SensorManager sensorManager;
@@ -34,7 +34,7 @@ public class ShakeDetector implements SensorEventListener {
34
34
  this.accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
35
35
 
36
36
  if (accelerometer != null) {
37
- sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_GAME);
37
+ sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_UI);
38
38
  }
39
39
  }
40
40
 
@@ -1229,7 +1229,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
1229
1229
  }
1230
1230
 
1231
1231
  let previewFallbackBundle = self.implementation.getPreviewFallbackBundle()
1232
- self.endPreviewSession()
1232
+ self.endPreviewSession(keepPreviewGuard: true)
1233
1233
  let restoredNextBundle = self.implementation.getNextBundle()
1234
1234
  self.deletePreviewBundleIfUnused(previewBundle, previewFallbackBundle: previewFallbackBundle, restoredNextBundle: restoredNextBundle)
1235
1235
  return true
@@ -1382,9 +1382,9 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
1382
1382
 
1383
1383
  private func endPreviewSession(keepPreviewGuard: Bool = false) {
1384
1384
  let previousShakeMenuEnabled = UserDefaults.standard.object(forKey: self.previewPreviousShakeMenuDefaultsKey) as? Bool
1385
- ?? getConfig().getBoolean("shakeMenu", false)
1385
+ ?? self.getBooleanConfig("shakeMenu", defaultValue: false)
1386
1386
  let previousShakeChannelSelectorEnabled = UserDefaults.standard.object(forKey: self.previewPreviousShakeChannelSelectorDefaultsKey) as? Bool
1387
- ?? getConfig().getBoolean("allowShakeChannelSelector", false)
1387
+ ?? self.getBooleanConfig("allowShakeChannelSelector", defaultValue: false)
1388
1388
  self.restorePreviewPreviousNextBundle()
1389
1389
  self.restorePreviewPreviousAppId()
1390
1390
  self.restorePreviewPreviousDefaultChannel()
@@ -1419,11 +1419,25 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
1419
1419
  self.isLeavingPreviewForIncomingLink = false
1420
1420
  self.implementation.previewSession = false
1421
1421
  self.hidePreviewTransitionLoader(reason: "preview-session-disabled")
1422
- self.shakeMenuEnabled = getConfig().getBoolean("shakeMenu", false)
1423
- self.shakeChannelSelectorEnabled = getConfig().getBoolean("allowShakeChannelSelector", false)
1422
+ self.shakeMenuEnabled = self.getBooleanConfig("shakeMenu", defaultValue: false)
1423
+ self.shakeChannelSelectorEnabled = self.getBooleanConfig("allowShakeChannelSelector", defaultValue: false)
1424
1424
  self.clearPreviewSessionPreferences()
1425
1425
  }
1426
1426
 
1427
+ private func getBooleanConfig(_ key: String, defaultValue: Bool) -> Bool {
1428
+ guard self.bridge != nil else {
1429
+ return defaultValue
1430
+ }
1431
+ return getConfig().getBoolean(key, defaultValue)
1432
+ }
1433
+
1434
+ private func getStringConfig(_ key: String, defaultValue: String) -> String {
1435
+ guard self.bridge != nil else {
1436
+ return defaultValue
1437
+ }
1438
+ return getConfig().getString(key, defaultValue) ?? defaultValue
1439
+ }
1440
+
1427
1441
  private func clearPreviewSessionPreferences() {
1428
1442
  _ = self.implementation.setPreviewFallbackBundle(fallback: nil)
1429
1443
  UserDefaults.standard.removeObject(forKey: self.previewSessionDefaultsKey)
@@ -1449,7 +1463,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
1449
1463
  }
1450
1464
 
1451
1465
  private func restorePreviewPreviousDefaultChannel() {
1452
- let configDefaultChannel = self.getConfig().getString("defaultChannel", "")!
1466
+ let configDefaultChannel = self.getStringConfig("defaultChannel", defaultValue: "")
1453
1467
  let hadPreviousDefaultChannel = UserDefaults.standard.object(forKey: self.previewPreviousDefaultChannelWasSetDefaultsKey) as? Bool ?? false
1454
1468
 
1455
1469
  guard hadPreviousDefaultChannel,
@@ -1636,8 +1650,8 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
1636
1650
  self.previewSessionAlertPending = false
1637
1651
  self.isLeavingPreviewForIncomingLink = false
1638
1652
  self.implementation.previewSession = false
1639
- self.shakeMenuEnabled = getConfig().getBoolean("shakeMenu", false)
1640
- self.shakeChannelSelectorEnabled = getConfig().getBoolean("allowShakeChannelSelector", false)
1653
+ self.shakeMenuEnabled = self.getBooleanConfig("shakeMenu", defaultValue: false)
1654
+ self.shakeChannelSelectorEnabled = self.getBooleanConfig("allowShakeChannelSelector", defaultValue: false)
1641
1655
  self.restorePreviewPreviousAppId()
1642
1656
  self.restorePreviewPreviousDefaultChannel()
1643
1657
  _ = self.implementation.setPreviewFallbackBundle(fallback: nil)
@@ -7,6 +7,9 @@
7
7
  import UIKit
8
8
  import Capacitor
9
9
 
10
+ private var lastShakeMenuShownAt: TimeInterval = 0
11
+ private let shakeMenuCooldownSeconds: TimeInterval = 1.2
12
+
10
13
  extension UIApplication {
11
14
  // swiftlint:disable:next line_length
12
15
  public class func topViewController(_ base: UIViewController? = UIApplication.shared.windows.first?.rootViewController) -> UIViewController? {
@@ -43,25 +46,38 @@ extension UIWindow {
43
46
  return
44
47
  }
45
48
 
49
+ let now = Date().timeIntervalSince1970
50
+ guard now - lastShakeMenuShownAt >= shakeMenuCooldownSeconds else {
51
+ plugin.logger.info("Shake menu ignored because cooldown is active")
52
+ return
53
+ }
54
+
46
55
  if canShowPreviewMenu {
47
- showDefaultMenu(plugin: plugin, bridge: bridge)
56
+ if showDefaultMenu(plugin: plugin, bridge: bridge) {
57
+ lastShakeMenuShownAt = now
58
+ }
48
59
  } else {
49
- showChannelSelector(plugin: plugin, bridge: bridge)
60
+ if showChannelSelector(plugin: plugin, bridge: bridge) {
61
+ lastShakeMenuShownAt = now
62
+ }
50
63
  }
51
64
  }
52
65
  }
53
66
 
54
- private func showDefaultMenu(plugin: CapacitorUpdaterPlugin, bridge: CAPBridgeProtocol) {
67
+ @discardableResult
68
+ private func showDefaultMenu(plugin: CapacitorUpdaterPlugin, bridge: CAPBridgeProtocol) -> Bool {
55
69
  // Prevent multiple alerts from showing
56
- if let topVC = UIApplication.topViewController(),
57
- topVC.isKind(of: UIAlertController.self) {
70
+ guard let topVC = UIApplication.topViewController() else {
71
+ return false
72
+ }
73
+ if topVC.isKind(of: UIAlertController.self) {
58
74
  plugin.logger.info("UIAlertController is already presented")
59
- return
75
+ return false
60
76
  }
61
77
 
62
78
  guard plugin.hasActivePreviewSession() else {
63
79
  plugin.logger.info("Shake preview menu ignored because no preview session is active")
64
- return
80
+ return false
65
81
  }
66
82
 
67
83
  let appName = Bundle.main.infoDictionary?["CFBundleDisplayName"] as? String ?? "App"
@@ -96,7 +112,7 @@ extension UIWindow {
96
112
  if plugin.shakeChannelSelectorEnabled {
97
113
  alertShake.addAction(UIAlertAction(title: "Switch channel", style: .default) { _ in
98
114
  let showSelector = {
99
- self.showChannelSelector(plugin: plugin, bridge: bridge)
115
+ _ = self.showChannelSelector(plugin: plugin, bridge: bridge)
100
116
  }
101
117
 
102
118
  if let presenter = alertShake.presentingViewController {
@@ -110,10 +126,9 @@ extension UIWindow {
110
126
  alertShake.addAction(UIAlertAction(title: cancelButtonTitle, style: .default))
111
127
 
112
128
  DispatchQueue.main.async {
113
- if let topVC = UIApplication.topViewController() {
114
- topVC.present(alertShake, animated: true)
115
- }
129
+ topVC.present(alertShake, animated: true)
116
130
  }
131
+ return true
117
132
  }
118
133
 
119
134
  private func showConfiguredDefaultMenu(plugin: CapacitorUpdaterPlugin, bridge: CAPBridgeProtocol) {
@@ -179,12 +194,15 @@ extension UIWindow {
179
194
  }
180
195
  }
181
196
 
182
- private func showChannelSelector(plugin: CapacitorUpdaterPlugin, bridge: CAPBridgeProtocol) {
197
+ @discardableResult
198
+ private func showChannelSelector(plugin: CapacitorUpdaterPlugin, bridge: CAPBridgeProtocol) -> Bool {
183
199
  // Prevent multiple alerts from showing
184
- if let topVC = UIApplication.topViewController(),
185
- topVC.isKind(of: UIAlertController.self) {
200
+ guard let topVC = UIApplication.topViewController() else {
201
+ return false
202
+ }
203
+ if topVC.isKind(of: UIAlertController.self) {
186
204
  plugin.logger.info("UIAlertController is already presented")
187
- return
205
+ return false
188
206
  }
189
207
 
190
208
  let updater = plugin.implementation
@@ -208,28 +226,27 @@ extension UIWindow {
208
226
  })
209
227
 
210
228
  DispatchQueue.main.async {
211
- if let topVC = UIApplication.topViewController() {
212
- topVC.present(loadingAlert, animated: true) {
213
- // Fetch channels in background
214
- DispatchQueue.global(qos: .userInitiated).async {
215
- let result = updater.listChannels()
229
+ topVC.present(loadingAlert, animated: true) {
230
+ // Fetch channels in background
231
+ DispatchQueue.global(qos: .userInitiated).async {
232
+ let result = updater.listChannels()
216
233
 
217
- DispatchQueue.main.async {
218
- loadingAlert.dismiss(animated: true) {
219
- guard !didCancel else { return }
220
- if !result.error.isEmpty {
221
- self.showError(message: "Failed to load channels: \(result.error)", plugin: plugin)
222
- } else if result.channels.isEmpty {
223
- self.showError(message: "No channels available for self-assignment", plugin: plugin)
224
- } else {
225
- self.presentChannelPicker(channels: result.channels, plugin: plugin, bridge: bridge)
226
- }
234
+ DispatchQueue.main.async {
235
+ loadingAlert.dismiss(animated: true) {
236
+ guard !didCancel else { return }
237
+ if !result.error.isEmpty {
238
+ self.showError(message: "Failed to load channels: \(result.error)", plugin: plugin)
239
+ } else if result.channels.isEmpty {
240
+ self.showError(message: "No channels available for self-assignment", plugin: plugin)
241
+ } else {
242
+ self.presentChannelPicker(channels: result.channels, plugin: plugin, bridge: bridge)
227
243
  }
228
244
  }
229
245
  }
230
246
  }
231
247
  }
232
248
  }
249
+ return true
233
250
  }
234
251
 
235
252
  private func presentChannelPicker(channels: [[String: Any]], plugin: CapacitorUpdaterPlugin, bridge: CAPBridgeProtocol) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/capacitor-updater",
3
- "version": "8.47.9",
3
+ "version": "8.47.10",
4
4
  "license": "MPL-2.0",
5
5
  "description": "Live update for capacitor apps",
6
6
  "main": "dist/plugin.cjs.js",