@glassly/engine 0.3.5-beta.792 → 0.3.5-beta.795

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.
Files changed (35) hide show
  1. package/build/engine.d.ts +1 -0
  2. package/build/engine.d.ts.map +1 -1
  3. package/build/facades/miniapps.d.ts +2 -0
  4. package/build/facades/miniapps.d.ts.map +1 -1
  5. package/build/facades/miniapps.js +2 -0
  6. package/build/facades/miniapps.js.map +1 -1
  7. package/build/generated/releaseMetadata.js +3 -3
  8. package/build/generated/releaseMetadata.js.map +1 -1
  9. package/build/services/AppRegistry.d.ts +4 -1
  10. package/build/services/AppRegistry.d.ts.map +1 -1
  11. package/build/services/AppRegistry.js +16 -2
  12. package/build/services/AppRegistry.js.map +1 -1
  13. package/build/services/LocalMiniappRuntime.d.ts +2 -0
  14. package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
  15. package/build/services/LocalMiniappRuntime.js +22 -2
  16. package/build/services/LocalMiniappRuntime.js.map +1 -1
  17. package/build/services/manifestActions.d.ts +4 -2
  18. package/build/services/manifestActions.d.ts.map +1 -1
  19. package/build/services/manifestActions.js +8 -3
  20. package/build/services/manifestActions.js.map +1 -1
  21. package/build/stores/apps.d.ts +6 -0
  22. package/build/stores/apps.d.ts.map +1 -1
  23. package/build/stores/apps.js +16 -1
  24. package/build/stores/apps.js.map +1 -1
  25. package/build/types/applet.d.ts +3 -1
  26. package/build/types/applet.d.ts.map +1 -1
  27. package/build/types/applet.js.map +1 -1
  28. package/package.json +7 -7
  29. package/src/facades/miniapps.ts +3 -0
  30. package/src/generated/releaseMetadata.ts +3 -3
  31. package/src/services/AppRegistry.ts +18 -3
  32. package/src/services/LocalMiniappRuntime.ts +24 -2
  33. package/src/services/manifestActions.ts +8 -3
  34. package/src/stores/apps.ts +23 -1
  35. package/src/types/applet.ts +3 -1
@@ -22,7 +22,7 @@ import {unzip} from "react-native-zip-archive"
22
22
  import semver from "semver"
23
23
  import {AsyncResult, Result, result as Res} from "typesafe-ts"
24
24
 
25
- import type {AppletPermission, AppPermissionType, AppletType, ClientApp} from "../types/applet"
25
+ import type {AppletPermission, AppPermissionType, AppletType, ClientApp, DeclaredWidget} from "../types/applet"
26
26
  import {HardwareRequirement, HardwareRequirementLevel, HardwareType} from "../types"
27
27
  import {configuredDevHost} from "../utils/configuredDevHost"
28
28
  import {storage} from "../utils/storage/storage"
@@ -776,7 +776,7 @@ class AppRegistry {
776
776
 
777
777
  // Declared actions (for session.miniapps.list + invoke gating).
778
778
  const actions = normalizeManifestActions(manifest?.actions)
779
- const widgets = normalizeManifestWidgets(manifest?.widgets)
779
+ const widgets = withWidgetExpandChoices(lmaInfo.packageName, normalizeManifestWidgets(manifest?.widgets))
780
780
 
781
781
  // Dev miniapps live in the same lmas/ tree as installed ones, but
782
782
  // their version directory name starts with "dev-".
@@ -864,7 +864,9 @@ class AppRegistry {
864
864
  permissions,
865
865
  hardwareRequirements,
866
866
  actions: normalizeManifestActions(rec.actions),
867
- ...(normalizeManifestWidgets(rec.widgets).length > 0 ? {widgets: normalizeManifestWidgets(rec.widgets)} : {}),
867
+ ...(normalizeManifestWidgets(rec.widgets).length > 0
868
+ ? {widgets: withWidgetExpandChoices(rec.packageName, normalizeManifestWidgets(rec.widgets))}
869
+ : {}),
868
870
  isMiniappDev: true,
869
871
  devUrl: rec.devUrl,
870
872
  devPort: rec.devPort,
@@ -948,6 +950,19 @@ export function saveAlwaysOnOverride(packageName: string, status: boolean): void
948
950
  storage.save(`${packageName}_always_on`, status)
949
951
  }
950
952
 
953
+ /** Applies the wearer's tap-to-expand choice to each expandable widget; expansion is on until they turn it off. */
954
+ export function withWidgetExpandChoices(packageName: string, widgets: DeclaredWidget[]): DeclaredWidget[] {
955
+ return widgets.map((widget) => {
956
+ if (!widget.expandable) return widget
957
+ const res = storage.load<boolean>(`${packageName}_widget_expand_${widget.id}`)
958
+ return {...widget, expandOnTap: res.is_ok() ? res.value !== false : true}
959
+ })
960
+ }
961
+
962
+ export function saveWidgetExpandChoice(packageName: string, widgetId: string, expandOnTap: boolean): void {
963
+ storage.save(`${packageName}_widget_expand_${widgetId}`, expandOnTap)
964
+ }
965
+
951
966
  export function getLocalAppScreenshot(packageName: string): string | undefined {
952
967
  const key = `${packageName}_screenshot`
953
968
  const res = storage.load<string>(key)
@@ -1824,6 +1824,9 @@ class LocalMiniappRuntime {
1824
1824
  case MiniappRequestType.WIDGET_RESULT:
1825
1825
  this.handleWidgetResult(packageName, payload)
1826
1826
  break
1827
+ case MiniappRequestType.WIDGET_EXPANDABLE:
1828
+ this.handleWidgetExpandable(packageName, payload, requestId)
1829
+ break
1827
1830
  case MiniappRequestType.SYSTEM_EXIT:
1828
1831
  void this.handleSystemExit(packageName, requestId)
1829
1832
  break
@@ -6371,7 +6374,7 @@ class LocalMiniappRuntime {
6371
6374
  name: widget.name,
6372
6375
  sizes: widget.sizes,
6373
6376
  defaultSize: widget.defaultSize,
6374
- expandable: widget.expandable,
6377
+ expandable: widget.expandOnTap,
6375
6378
  running: app.running,
6376
6379
  compatible: app.compatibility?.isCompatible !== false,
6377
6380
  })
@@ -6580,6 +6583,25 @@ class LocalMiniappRuntime {
6580
6583
  }
6581
6584
  }
6582
6585
 
6586
+ /** Provider: read, or set with `expandable`, whether a tap expands one of its own `EX` widgets. */
6587
+ private handleWidgetExpandable(packageName: string, payload: Record<string, unknown>, requestId?: string): void {
6588
+ const widgetId = payload.widgetId as string | undefined
6589
+ const app = this.interopApps().find((a) => a.packageName === packageName)
6590
+ const widget = app && widgetId ? this.declaredWidget(app, widgetId) : undefined
6591
+ if (!widget?.expandable) {
6592
+ this.sendResult(packageName, requestId, false, undefined, {
6593
+ code: MiniappErrorCode.WIDGET_NOT_FOUND,
6594
+ message: `${packageName} has no widget "${widgetId ?? "(missing widgetId)"}" that lists EX`,
6595
+ })
6596
+ return
6597
+ }
6598
+ const expandable =
6599
+ typeof payload.expandable === "boolean"
6600
+ ? useAppStatusStore.getState().setWidgetExpand(packageName, widget.id, payload.expandable)
6601
+ : widget.expandOnTap
6602
+ this.sendResult(packageName, requestId, true, {expandable})
6603
+ }
6604
+
6583
6605
  /** Provider → host, one-shot: cache the frame for its view and push it to every host holding the widget. */
6584
6606
  private handleWidgetUpdate(providerPackageName: string, payload: Record<string, unknown>): void {
6585
6607
  const widgetId = payload.widgetId as string | undefined
@@ -6591,7 +6613,7 @@ class LocalMiniappRuntime {
6591
6613
  const view: WidgetView = payload.view === "expanded" ? "expanded" : "card"
6592
6614
  if (view === "expanded" && !widget.expandable) {
6593
6615
  console.warn(
6594
- `${LOG_TAG}: dropping expanded frame from ${providerPackageName}/${widgetId}: not declared expandable`,
6616
+ `${LOG_TAG}: dropping expanded frame from ${providerPackageName}/${widgetId}: it does not list EX`,
6595
6617
  )
6596
6618
  return
6597
6619
  }
@@ -84,9 +84,11 @@ const isWidgetSize = (value: unknown): value is DeclaredWidgetSize => (WIDGET_SI
84
84
 
85
85
  /**
86
86
  * Normalize manifest widgets for installed and dev-sideloaded bundles: an
87
- * entry without an id, a name or a usable size is dropped, repeats of a
87
+ * entry without an id, a name or a usable card size is dropped, repeats of a
88
88
  * size are folded, and a default size the widget does not offer becomes
89
- * its first size. Only `expandable: true` makes a widget expandable.
89
+ * its first size. Listing `EX` makes a widget expandable; it is not a card
90
+ * size. Taps expand it until the wearer turns that off (AppRegistry applies
91
+ * the choice).
90
92
  */
91
93
  export function normalizeManifestWidgets(raw: unknown): DeclaredWidget[] {
92
94
  if (!Array.isArray(raw)) return []
@@ -103,12 +105,15 @@ export function normalizeManifestWidgets(raw: unknown): DeclaredWidget[] {
103
105
  const sizes = Array.isArray(w.sizes) ? Array.from(new Set(w.sizes.filter(isWidgetSize))) : []
104
106
  if (sizes.length === 0) continue
105
107
  seen.add(w.id)
108
+ // `expandable: true` is how bundles from before `EX` said the same.
109
+ const expandable = (Array.isArray(w.sizes) && w.sizes.includes("EX")) || w.expandable === true
106
110
  out.push({
107
111
  id: w.id,
108
112
  name: w.name,
109
113
  sizes,
110
114
  defaultSize: isWidgetSize(w.defaultSize) && sizes.includes(w.defaultSize) ? w.defaultSize : sizes[0],
111
- expandable: w.expandable === true,
115
+ expandable,
116
+ expandOnTap: expandable,
112
117
  })
113
118
  }
114
119
  return out
@@ -19,7 +19,7 @@ import {DeviceTypes} from "../types/enums"
19
19
  import {getModelCapabilities} from "../types/hardware"
20
20
  import {HardwareCompatibility, type CompatibilityResult} from "../utils/hardware/hardware"
21
21
  import {storage} from "../utils/storage/storage"
22
- import appRegistry, {saveAlwaysOnOverride} from "../services/AppRegistry"
22
+ import appRegistry, {saveAlwaysOnOverride, saveWidgetExpandChoice} from "../services/AppRegistry"
23
23
  import localDisplayManager from "../services/LocalDisplayManager"
24
24
  import {islandNotifications} from "../services/NotificationsEmitter"
25
25
  import sttModelManager from "../services/STTModelManager"
@@ -103,6 +103,12 @@ interface AppStatusState {
103
103
  * off leaves it running. Persists the wearer's choice beside the hidden flag.
104
104
  */
105
105
  setAlwaysOn: (packageName: string, status: boolean) => Promise<void>
106
+ /**
107
+ * Whether a tap on one of the miniapp's dashboard widgets expands it to the
108
+ * full screen. Only widgets that list `EX` expand; false for the rest.
109
+ * Persists the choice and answers the setting now in force.
110
+ */
111
+ setWidgetExpand: (packageName: string, widgetId: string, expandOnTap: boolean) => boolean
106
112
  /** Replace the whole apps array. Hosts use this when their extra source changes. */
107
113
  setApps: (apps: ClientApp[]) => void
108
114
  }
@@ -587,6 +593,22 @@ export const useAppStatusStore = create<AppStatusState>((set, get) => ({
587
593
  if (status && !app.running) await get().start(app, {skipNavigation: true})
588
594
  },
589
595
 
596
+ setWidgetExpand: (packageName, widgetId, expandOnTap) => {
597
+ const app = get().apps.find((a) => a.packageName === packageName)
598
+ const widget = app?.widgets?.find((w) => w.id === widgetId)
599
+ if (!widget?.expandable) return false
600
+ if (widget.expandOnTap === expandOnTap) return expandOnTap
601
+ saveWidgetExpandChoice(packageName, widgetId, expandOnTap)
602
+ set((s) => ({
603
+ apps: s.apps.map((a) =>
604
+ a.packageName === packageName
605
+ ? {...a, widgets: a.widgets?.map((w) => (w.id === widgetId ? {...w, expandOnTap} : w))}
606
+ : a,
607
+ ),
608
+ }))
609
+ return expandOnTap
610
+ },
611
+
590
612
  setApps: (apps) => set({apps}),
591
613
  }))
592
614
 
@@ -97,8 +97,10 @@ export interface DeclaredWidget {
97
97
  name: string
98
98
  sizes: DeclaredWidgetSize[]
99
99
  defaultSize: DeclaredWidgetSize
100
- /** A tap on the selected widget expands it to the full screen instead of activating the card. */
100
+ /** Lists the `EX` size: a tap on the selected widget can expand it to the full screen. */
101
101
  expandable: boolean
102
+ /** A tap expands it rather than activating the card: expandable, and the wearer left expansion on. */
103
+ expandOnTap: boolean
102
104
  }
103
105
 
104
106
  export interface ClientApp extends AppletInterface {