craft-native 0.0.134 → 0.0.135

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.
@@ -418,6 +418,7 @@ class CraftBridge(
418
418
  appReview: true,
419
419
  flashlight: {{ENABLE_CAMERA}} && ${hasFlashlight()},
420
420
  speech: true,
421
+ brightness: true,
421
422
  openURL: true,
422
423
  vibrationPattern: true,
423
424
  appState: true,
@@ -687,6 +688,18 @@ class CraftBridge(
687
688
  return CraftAndroid.setKeepAwake(enabled);
688
689
  },
689
690
 
691
+ // Screen brightness, 0 to 1. resetBrightness hands the screen
692
+ // back to the system setting (auto-brightness included).
693
+ getBrightness: function() {
694
+ return Promise.resolve().then(function() { return CraftAndroid.getBrightness(); });
695
+ },
696
+ setBrightness: function(level) {
697
+ return Promise.resolve().then(function() { return CraftAndroid.setBrightness(Number(level)); });
698
+ },
699
+ resetBrightness: function() {
700
+ return Promise.resolve().then(function() { return CraftAndroid.resetBrightness(); });
701
+ },
702
+
690
703
  // Orientation Lock
691
704
  lockOrientation: function(orientation) {
692
705
  return CraftAndroid.lockOrientation(orientation);
@@ -3628,6 +3641,49 @@ class CraftBridge(
3628
3641
  )
3629
3642
  }
3630
3643
 
3644
+ // ==================== Screen Brightness ====================
3645
+ //
3646
+ // The window's own brightness override (WindowManager.LayoutParams
3647
+ // .screenBrightness): no permission, and it lasts only while this window
3648
+ // is in front, so leaving the app hands the screen back by itself.
3649
+ // resetBrightness releases it, which also gives auto-brightness back -
3650
+ // setting the old system level instead would freeze it there.
3651
+ @Volatile private var brightnessOverride: Float? = null
3652
+
3653
+ @JavascriptInterface
3654
+ fun getBrightness(): Double {
3655
+ brightnessOverride?.let { return it.toDouble() }
3656
+ return try {
3657
+ Settings.System.getInt(activity.contentResolver, Settings.System.SCREEN_BRIGHTNESS) / 255.0
3658
+ } catch (e: Exception) {
3659
+ 0.5
3660
+ }
3661
+ }
3662
+
3663
+ @JavascriptInterface
3664
+ fun setBrightness(level: Double): Double {
3665
+ if (!level.isFinite()) return getBrightness()
3666
+ val clamped = level.coerceIn(0.0, 1.0).toFloat()
3667
+ brightnessOverride = clamped
3668
+ activity.runOnUiThread {
3669
+ val params = activity.window.attributes
3670
+ params.screenBrightness = clamped
3671
+ activity.window.attributes = params
3672
+ }
3673
+ return clamped.toDouble()
3674
+ }
3675
+
3676
+ @JavascriptInterface
3677
+ fun resetBrightness(): Double {
3678
+ brightnessOverride = null
3679
+ activity.runOnUiThread {
3680
+ val params = activity.window.attributes
3681
+ params.screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE
3682
+ activity.window.attributes = params
3683
+ }
3684
+ return getBrightness()
3685
+ }
3686
+
3631
3687
  // ==================== Keep Awake ====================
3632
3688
 
3633
3689
  @JavascriptInterface
@@ -738,15 +738,19 @@ export interface SpeechOptions {
738
738
  /** Stop whatever is being said first. Defaults to true; false queues behind it. */
739
739
  interrupt?: boolean;
740
740
  }
741
- /**
742
- * Short spoken cues: "Rest, 15 seconds. Up next: Dead Bug".
743
- *
744
- * Inside a Craft app this is native text-to-speech, which ducks the person's
745
- * music rather than stopping it and, on iOS, plays with the silent switch on.
746
- * In a browser it falls back to the Web Speech API, which does neither, and
747
- * where there is no speech at all it answers `false` rather than throwing, so
748
- * a cue never breaks the flow around it.
749
- */
741
+ export declare const brightness: {
742
+ isAvailable(): boolean;
743
+ /** The screen's brightness, 0 to 1, or null where there is none to read. */
744
+ get(): Promise<number | null>;
745
+ /**
746
+ * Set the brightness, 0 to 1 (clamped). The first call since the last
747
+ * `restore()` remembers the person's own level to go back to. Resolves with
748
+ * the level the screen reports, or null off a phone.
749
+ */
750
+ set(level: number): Promise<number | null>;
751
+ /** Put the person's own brightness back. Safe to call when nothing was set. */
752
+ restore(): Promise<void>;
753
+ };
750
754
  export declare const speech: {
751
755
  isAvailable(): boolean;
752
756
  /**
@@ -1184,6 +1188,7 @@ declare const mobile: {
1184
1188
  lifecycle: typeof lifecycle;
1185
1189
  notifications: typeof notifications;
1186
1190
  keepAwake: typeof keepAwake;
1191
+ brightness: typeof brightness;
1187
1192
  speech: typeof speech;
1188
1193
  deepLinks: typeof deepLinks;
1189
1194
  network: typeof network;
package/dist/cli.js CHANGED
@@ -3303,7 +3303,7 @@ function pinCraftNativeDependency(packagePath, craftVersion) {
3303
3303
  `);
3304
3304
  }
3305
3305
  // package.json
3306
- var version = "0.0.134";
3306
+ var version = "0.0.135";
3307
3307
 
3308
3308
  // bin/cli.ts
3309
3309
  var spawnedFrom = process6.env[CRAFT_CLI_SPAWN_MARKER];
package/dist/index.cjs CHANGED
@@ -310,7 +310,7 @@ function craftBinaryNotFoundMessage(triedPath) {
310
310
  `);
311
311
  }
312
312
  // package.json
313
- var version = "0.0.134";
313
+ var version = "0.0.135";
314
314
 
315
315
  // src/sdk-version.ts
316
316
  var SDK_VERSION = version;
package/dist/index.js CHANGED
@@ -58,7 +58,7 @@ function craftBinaryNotFoundMessage(triedPath) {
58
58
  `);
59
59
  }
60
60
  // package.json
61
- var version = "0.0.134";
61
+ var version = "0.0.135";
62
62
 
63
63
  // src/sdk-version.ts
64
64
  var SDK_VERSION = version;
@@ -2140,6 +2140,15 @@ struct CraftWebView: UIViewRepresentable {
2140
2140
  } else {
2141
2141
  rejectCallback(callbackId, error: "Keep awake is disabled", code: "CAPABILITY_DISABLED")
2142
2142
  }
2143
+ // MARK: - Screen Brightness
2144
+ case "getBrightness":
2145
+ getBrightness(callbackId: callbackId)
2146
+ case "setBrightness":
2147
+ if let level = (body["level"] as? NSNumber)?.doubleValue, level.isFinite {
2148
+ setBrightness(level, callbackId: callbackId)
2149
+ } else {
2150
+ rejectCallback(callbackId, error: "setBrightness was called without the values it needs", code: "INVALID_ARGUMENT")
2151
+ }
2143
2152
  // MARK: - Orientation Lock
2144
2153
  case "lockOrientation":
2145
2154
  if config.enableOrientationLock {
@@ -3102,6 +3111,7 @@ struct CraftWebView: UIViewRepresentable {
3102
3111
  orientationLock: \(config.enableOrientationLock),
3103
3112
  deepLinks: \(config.enableDeepLinks),
3104
3113
  flashlight: true,
3114
+ brightness: true,
3105
3115
  speech: true,
3106
3116
  network: true,
3107
3117
  deviceInfo: true,
@@ -4041,6 +4051,25 @@ struct CraftWebView: UIViewRepresentable {
4041
4051
  });
4042
4052
  },
4043
4053
 
4054
+ // Screen brightness, 0 to 1. Each resolves with the level the
4055
+ // screen then reports.
4056
+ getBrightness: function() {
4057
+ var self = this;
4058
+ var id = 'cb_' + (++this._callbackId);
4059
+ window.webkit.messageHandlers.craft.postMessage({action: 'getBrightness', callbackId: id});
4060
+ return new Promise(function(resolve, reject) {
4061
+ self._callbacks[id] = {resolve: resolve, reject: reject};
4062
+ });
4063
+ },
4064
+ setBrightness: function(level) {
4065
+ var self = this;
4066
+ var id = 'cb_' + (++this._callbackId);
4067
+ window.webkit.messageHandlers.craft.postMessage({action: 'setBrightness', level: level, callbackId: id});
4068
+ return new Promise(function(resolve, reject) {
4069
+ self._callbacks[id] = {resolve: resolve, reject: reject};
4070
+ });
4071
+ },
4072
+
4044
4073
  // Speech synthesis. speak() settles when the utterance ends:
4045
4074
  // true when it was spoken, false when something stopped it.
4046
4075
  // No timeout, because a long sentence at a slow rate can
@@ -6236,6 +6265,25 @@ struct CraftWebView: UIViewRepresentable {
6236
6265
  }
6237
6266
  }
6238
6267
 
6268
+ // MARK: - Screen Brightness
6269
+ //
6270
+ // The device's backlight, 0 to 1. It is system-wide, not the app's:
6271
+ // a page that dims it reads it first and puts it back - when it is
6272
+ // done, and when the app leaves the foreground (@stacksjs/mobile's
6273
+ // screen API does both off the page's visibility).
6274
+ private func getBrightness(callbackId: String?) {
6275
+ DispatchQueue.main.async {
6276
+ self.resolveCallback(callbackId, result: Double(UIScreen.main.brightness))
6277
+ }
6278
+ }
6279
+
6280
+ private func setBrightness(_ level: Double, callbackId: String?) {
6281
+ DispatchQueue.main.async {
6282
+ UIScreen.main.brightness = CGFloat(min(max(level, 0), 1))
6283
+ self.resolveCallback(callbackId, result: Double(UIScreen.main.brightness))
6284
+ }
6285
+ }
6286
+
6239
6287
  // MARK: - Speech Synthesis
6240
6288
  //
6241
6289
  // Native rather than the page's own `speechSynthesis`, which in a
package/dist/mobile.js CHANGED
@@ -610,6 +610,64 @@ var speakingOnTheWeb = new Set;
610
610
  function speechRate(rate) {
611
611
  return typeof rate === "number" && Number.isFinite(rate) ? Math.min(Math.max(rate, 0.5), 2) : 1;
612
612
  }
613
+ var brightnessState = { original: null, wanted: null, unwatch: null };
614
+ function brightnessLevel(level) {
615
+ const value = Number(level);
616
+ return Number.isFinite(value) ? Math.min(1, Math.max(0, value)) : null;
617
+ }
618
+ async function putBrightnessBack(craft) {
619
+ if (typeof craft?.resetBrightness === "function")
620
+ await craft.resetBrightness();
621
+ else if (brightnessState.original !== null)
622
+ await craft.setBrightness(brightnessState.original);
623
+ }
624
+ function watchBrightnessVisibility() {
625
+ if (brightnessState.unwatch || typeof document === "undefined")
626
+ return;
627
+ const onVisibility = () => {
628
+ const craft = getCraftRoot();
629
+ if (!craft?.setBrightness || brightnessState.wanted === null)
630
+ return;
631
+ if (document.visibilityState === "hidden")
632
+ putBrightnessBack(craft).catch(() => {});
633
+ else
634
+ craft.setBrightness(brightnessState.wanted).catch(() => {});
635
+ };
636
+ document.addEventListener("visibilitychange", onVisibility);
637
+ brightnessState.unwatch = () => document.removeEventListener("visibilitychange", onVisibility);
638
+ }
639
+ var brightness = {
640
+ isAvailable() {
641
+ return typeof getCraftRoot()?.setBrightness === "function";
642
+ },
643
+ async get() {
644
+ const craft = getCraftRoot();
645
+ if (typeof craft?.getBrightness !== "function")
646
+ return null;
647
+ return brightnessLevel(await craft.getBrightness());
648
+ },
649
+ async set(level) {
650
+ const craft = getCraftRoot();
651
+ const wanted = brightnessLevel(level);
652
+ if (typeof craft?.setBrightness !== "function" || wanted === null)
653
+ return null;
654
+ if (brightnessState.wanted === null && typeof craft.getBrightness === "function")
655
+ brightnessState.original = brightnessLevel(await craft.getBrightness());
656
+ brightnessState.wanted = wanted;
657
+ watchBrightnessVisibility();
658
+ return brightnessLevel(await craft.setBrightness(wanted));
659
+ },
660
+ async restore() {
661
+ const craft = getCraftRoot();
662
+ const held = brightnessState.wanted !== null;
663
+ brightnessState.wanted = null;
664
+ brightnessState.unwatch?.();
665
+ brightnessState.unwatch = null;
666
+ if (held && typeof craft?.setBrightness === "function")
667
+ await putBrightnessBack(craft);
668
+ brightnessState.original = null;
669
+ }
670
+ };
613
671
  var speech = {
614
672
  isAvailable() {
615
673
  return Boolean(getCraftRoot()?.speech?.speak) || getWebSpeech() !== undefined;
@@ -1147,6 +1205,7 @@ export {
1147
1205
  chrome,
1148
1206
  camera,
1149
1207
  browser,
1208
+ brightness,
1150
1209
  bridgeNotification,
1151
1210
  biometrics,
1152
1211
  background,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "craft-native",
3
- "version": "0.0.134",
3
+ "version": "0.0.135",
4
4
  "type": "module",
5
5
  "description": "Build desktop apps with web languages - TypeScript SDK for Craft",
6
6
  "author": "Chris Breuer <chris@stacksjs.org>",