@use-voltra/ios-client 2.1.1 → 2.3.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 +61 -8
- package/Voltra.podspec +1 -0
- package/build/commonjs/dynamic-widget/api.js +15 -0
- package/build/commonjs/dynamic-widget/api.js.map +1 -0
- package/build/commonjs/events.js +23 -0
- package/build/commonjs/events.js.map +1 -1
- package/build/commonjs/index.js +74 -7
- package/build/commonjs/index.js.map +1 -1
- package/build/commonjs/live-activity/api.js +3 -1
- package/build/commonjs/live-activity/api.js.map +1 -1
- package/build/commonjs/live-activity/dynamic-api.js +173 -0
- package/build/commonjs/live-activity/dynamic-api.js.map +1 -0
- package/build/commonjs/native/NativeVoltra.js.map +1 -1
- package/build/commonjs/utils/enableDynamicLiveActivityHotReload.js +47 -0
- package/build/commonjs/utils/enableDynamicLiveActivityHotReload.js.map +1 -0
- package/build/commonjs/utils/enableWidgetHotReload.js +8 -11
- package/build/commonjs/utils/enableWidgetHotReload.js.map +1 -1
- package/build/commonjs/utils/useUpdateOnHMR.js +3 -7
- package/build/commonjs/utils/useUpdateOnHMR.js.map +1 -1
- package/build/commonjs/widgets/server-credentials.js +9 -0
- package/build/commonjs/widgets/server-credentials.js.map +1 -1
- package/build/commonjs/widgets/server-update.js +78 -0
- package/build/commonjs/widgets/server-update.js.map +1 -0
- package/build/module/dynamic-widget/api.js +10 -0
- package/build/module/dynamic-widget/api.js.map +1 -0
- package/build/module/events.js +23 -0
- package/build/module/events.js.map +1 -1
- package/build/module/index.js +4 -0
- package/build/module/index.js.map +1 -1
- package/build/module/live-activity/api.js +2 -2
- package/build/module/live-activity/api.js.map +1 -1
- package/build/module/live-activity/dynamic-api.js +167 -0
- package/build/module/live-activity/dynamic-api.js.map +1 -0
- package/build/module/native/NativeVoltra.js.map +1 -1
- package/build/module/utils/enableDynamicLiveActivityHotReload.js +43 -0
- package/build/module/utils/enableDynamicLiveActivityHotReload.js.map +1 -0
- package/build/module/utils/enableWidgetHotReload.js +9 -11
- package/build/module/utils/enableWidgetHotReload.js.map +1 -1
- package/build/module/utils/useUpdateOnHMR.js +3 -7
- package/build/module/utils/useUpdateOnHMR.js.map +1 -1
- package/build/module/widgets/server-credentials.js +9 -0
- package/build/module/widgets/server-credentials.js.map +1 -1
- package/build/module/widgets/server-update.js +72 -0
- package/build/module/widgets/server-update.js.map +1 -0
- package/build/typescript/commonjs/dynamic-widget/api.d.ts +8 -0
- package/build/typescript/commonjs/dynamic-widget/api.d.ts.map +1 -0
- package/build/typescript/commonjs/events.d.ts +7 -0
- package/build/typescript/commonjs/events.d.ts.map +1 -1
- package/build/typescript/commonjs/index.d.ts +4 -0
- package/build/typescript/commonjs/index.d.ts.map +1 -1
- package/build/typescript/commonjs/live-activity/api.d.ts +7 -0
- package/build/typescript/commonjs/live-activity/api.d.ts.map +1 -1
- package/build/typescript/commonjs/live-activity/dynamic-api.d.ts +54 -0
- package/build/typescript/commonjs/live-activity/dynamic-api.d.ts.map +1 -0
- package/build/typescript/commonjs/native/NativeVoltra.d.ts +21 -0
- package/build/typescript/commonjs/native/NativeVoltra.d.ts.map +1 -1
- package/build/typescript/commonjs/types.d.ts +1 -1
- package/build/typescript/commonjs/types.d.ts.map +1 -1
- package/build/typescript/commonjs/utils/enableDynamicLiveActivityHotReload.d.ts +15 -0
- package/build/typescript/commonjs/utils/enableDynamicLiveActivityHotReload.d.ts.map +1 -0
- package/build/typescript/commonjs/utils/enableWidgetHotReload.d.ts +5 -7
- package/build/typescript/commonjs/utils/enableWidgetHotReload.d.ts.map +1 -1
- package/build/typescript/commonjs/utils/useUpdateOnHMR.d.ts +0 -3
- package/build/typescript/commonjs/utils/useUpdateOnHMR.d.ts.map +1 -1
- package/build/typescript/commonjs/widgets/server-credentials.d.ts +8 -0
- package/build/typescript/commonjs/widgets/server-credentials.d.ts.map +1 -1
- package/build/typescript/commonjs/widgets/server-update.d.ts +64 -0
- package/build/typescript/commonjs/widgets/server-update.d.ts.map +1 -0
- package/build/typescript/module/dynamic-widget/api.d.ts +8 -0
- package/build/typescript/module/dynamic-widget/api.d.ts.map +1 -0
- package/build/typescript/module/events.d.ts +7 -0
- package/build/typescript/module/events.d.ts.map +1 -1
- package/build/typescript/module/index.d.ts +4 -0
- package/build/typescript/module/index.d.ts.map +1 -1
- package/build/typescript/module/live-activity/api.d.ts +7 -0
- package/build/typescript/module/live-activity/api.d.ts.map +1 -1
- package/build/typescript/module/live-activity/dynamic-api.d.ts +54 -0
- package/build/typescript/module/live-activity/dynamic-api.d.ts.map +1 -0
- package/build/typescript/module/native/NativeVoltra.d.ts +21 -0
- package/build/typescript/module/native/NativeVoltra.d.ts.map +1 -1
- package/build/typescript/module/types.d.ts +1 -1
- package/build/typescript/module/types.d.ts.map +1 -1
- package/build/typescript/module/utils/enableDynamicLiveActivityHotReload.d.ts +15 -0
- package/build/typescript/module/utils/enableDynamicLiveActivityHotReload.d.ts.map +1 -0
- package/build/typescript/module/utils/enableWidgetHotReload.d.ts +5 -7
- package/build/typescript/module/utils/enableWidgetHotReload.d.ts.map +1 -1
- package/build/typescript/module/utils/useUpdateOnHMR.d.ts +0 -3
- package/build/typescript/module/utils/useUpdateOnHMR.d.ts.map +1 -1
- package/build/typescript/module/widgets/server-credentials.d.ts +8 -0
- package/build/typescript/module/widgets/server-credentials.d.ts.map +1 -1
- package/build/typescript/module/widgets/server-update.d.ts +64 -0
- package/build/typescript/module/widgets/server-update.d.ts.map +1 -0
- package/expo-plugin/build/cjs/constants.js +20 -1
- package/expo-plugin/build/cjs/constants.js.map +1 -1
- package/expo-plugin/build/cjs/index.js +9 -1
- package/expo-plugin/build/cjs/index.js.map +1 -1
- package/expo-plugin/build/cjs/ios/index.js +1 -0
- package/expo-plugin/build/cjs/ios/index.js.map +1 -1
- package/expo-plugin/build/cjs/ios/infoPlist.js +28 -5
- package/expo-plugin/build/cjs/ios/infoPlist.js.map +1 -1
- package/expo-plugin/build/cjs/ios/serverUpdate.js +25 -0
- package/expo-plugin/build/cjs/ios/serverUpdate.js.map +1 -0
- package/expo-plugin/build/cjs/ios-widget/clientRendered.js +4 -4
- package/expo-plugin/build/cjs/ios-widget/clientRendered.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/clientRenderedPrerender.js +5 -5
- package/expo-plugin/build/cjs/ios-widget/clientRenderedPrerender.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/dynamic-live-activity/swift.js +130 -0
- package/expo-plugin/build/cjs/ios-widget/dynamic-live-activity/swift.js.map +1 -0
- package/expo-plugin/build/cjs/ios-widget/files/index.js +9 -2
- package/expo-plugin/build/cjs/ios-widget/files/index.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/files/infoPlist.js +6 -3
- package/expo-plugin/build/cjs/ios-widget/files/infoPlist.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/files/manifest.js +24 -0
- package/expo-plugin/build/cjs/ios-widget/files/manifest.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/files/swift-utils.js +7 -0
- package/expo-plugin/build/cjs/ios-widget/files/swift-utils.js.map +1 -0
- package/expo-plugin/build/cjs/ios-widget/files/swift.js +56 -26
- package/expo-plugin/build/cjs/ios-widget/files/swift.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/index.js +9 -3
- package/expo-plugin/build/cjs/ios-widget/index.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/podfile.js +38 -12
- package/expo-plugin/build/cjs/ios-widget/podfile.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/widgetPlist.js +34 -22
- package/expo-plugin/build/cjs/ios-widget/widgetPlist.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/xcode/buildPhases.js +194 -118
- package/expo-plugin/build/cjs/ios-widget/xcode/buildPhases.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/xcode/configurationList.js +30 -22
- package/expo-plugin/build/cjs/ios-widget/xcode/configurationList.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/xcode/fileReferences.js +50 -0
- package/expo-plugin/build/cjs/ios-widget/xcode/fileReferences.js.map +1 -0
- package/expo-plugin/build/cjs/ios-widget/xcode/groups.js +45 -43
- package/expo-plugin/build/cjs/ios-widget/xcode/groups.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/xcode/index.js +93 -91
- package/expo-plugin/build/cjs/ios-widget/xcode/index.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/xcode/mainAppSettings.js +41 -39
- package/expo-plugin/build/cjs/ios-widget/xcode/mainAppSettings.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/xcode/productFile.js +2 -2
- package/expo-plugin/build/cjs/ios-widget/xcode/productFile.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/xcode/target.js +29 -63
- package/expo-plugin/build/cjs/ios-widget/xcode/target.js.map +1 -1
- package/expo-plugin/build/cjs/utils/urlScheme.js +36 -14
- package/expo-plugin/build/cjs/utils/urlScheme.js.map +1 -1
- package/expo-plugin/build/cjs/validation.js +54 -0
- package/expo-plugin/build/cjs/validation.js.map +1 -1
- package/expo-plugin/build/esm/constants.js +17 -0
- package/expo-plugin/build/esm/constants.js.map +1 -1
- package/expo-plugin/build/esm/index.js +9 -1
- package/expo-plugin/build/esm/index.js.map +1 -1
- package/expo-plugin/build/esm/ios/index.js +1 -0
- package/expo-plugin/build/esm/ios/index.js.map +1 -1
- package/expo-plugin/build/esm/ios/infoPlist.js +28 -5
- package/expo-plugin/build/esm/ios/infoPlist.js.map +1 -1
- package/expo-plugin/build/esm/ios/serverUpdate.js +21 -0
- package/expo-plugin/build/esm/ios/serverUpdate.js.map +1 -0
- package/expo-plugin/build/esm/ios-widget/clientRendered.js +5 -5
- package/expo-plugin/build/esm/ios-widget/clientRendered.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/clientRenderedPrerender.js +6 -6
- package/expo-plugin/build/esm/ios-widget/clientRenderedPrerender.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/dynamic-live-activity/swift.js +122 -0
- package/expo-plugin/build/esm/ios-widget/dynamic-live-activity/swift.js.map +1 -0
- package/expo-plugin/build/esm/ios-widget/files/index.js +10 -3
- package/expo-plugin/build/esm/ios-widget/files/index.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/files/infoPlist.js +6 -3
- package/expo-plugin/build/esm/ios-widget/files/infoPlist.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/files/manifest.js +23 -1
- package/expo-plugin/build/esm/ios-widget/files/manifest.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/files/swift-utils.js +4 -0
- package/expo-plugin/build/esm/ios-widget/files/swift-utils.js.map +1 -0
- package/expo-plugin/build/esm/ios-widget/files/swift.js +50 -20
- package/expo-plugin/build/esm/ios-widget/files/swift.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/index.js +9 -3
- package/expo-plugin/build/esm/ios-widget/index.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/podfile.js +36 -11
- package/expo-plugin/build/esm/ios-widget/podfile.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/widgetPlist.js +34 -22
- package/expo-plugin/build/esm/ios-widget/widgetPlist.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/xcode/buildPhases.js +194 -117
- package/expo-plugin/build/esm/ios-widget/xcode/buildPhases.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/xcode/configurationList.js +31 -22
- package/expo-plugin/build/esm/ios-widget/xcode/configurationList.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/xcode/fileReferences.js +45 -0
- package/expo-plugin/build/esm/ios-widget/xcode/fileReferences.js.map +1 -0
- package/expo-plugin/build/esm/ios-widget/xcode/groups.js +45 -42
- package/expo-plugin/build/esm/ios-widget/xcode/groups.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/xcode/index.js +97 -96
- package/expo-plugin/build/esm/ios-widget/xcode/index.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/xcode/mainAppSettings.js +41 -39
- package/expo-plugin/build/esm/ios-widget/xcode/mainAppSettings.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/xcode/productFile.js +3 -2
- package/expo-plugin/build/esm/ios-widget/xcode/productFile.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/xcode/target.js +28 -62
- package/expo-plugin/build/esm/ios-widget/xcode/target.js.map +1 -1
- package/expo-plugin/build/esm/utils/urlScheme.js +34 -14
- package/expo-plugin/build/esm/utils/urlScheme.js.map +1 -1
- package/expo-plugin/build/esm/validation.js +54 -1
- package/expo-plugin/build/esm/validation.js.map +1 -1
- package/expo-plugin/build/types/constants.d.ts +10 -1
- package/expo-plugin/build/types/constants.d.ts.map +1 -1
- package/expo-plugin/build/types/index.d.ts +1 -1
- package/expo-plugin/build/types/index.d.ts.map +1 -1
- package/expo-plugin/build/types/ios/index.d.ts +2 -0
- package/expo-plugin/build/types/ios/index.d.ts.map +1 -1
- package/expo-plugin/build/types/ios/infoPlist.d.ts +2 -0
- package/expo-plugin/build/types/ios/infoPlist.d.ts.map +1 -1
- package/expo-plugin/build/types/ios/serverUpdate.d.ts +11 -0
- package/expo-plugin/build/types/ios/serverUpdate.d.ts.map +1 -0
- package/expo-plugin/build/types/ios-widget/clientRendered.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/clientRenderedPrerender.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/dynamic-live-activity/swift.d.ts +7 -0
- package/expo-plugin/build/types/ios-widget/dynamic-live-activity/swift.d.ts.map +1 -0
- package/expo-plugin/build/types/ios-widget/files/index.d.ts +3 -1
- package/expo-plugin/build/types/ios-widget/files/index.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/files/infoPlist.d.ts +2 -1
- package/expo-plugin/build/types/ios-widget/files/infoPlist.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/files/manifest.d.ts +9 -2
- package/expo-plugin/build/types/ios-widget/files/manifest.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/files/swift-utils.d.ts +2 -0
- package/expo-plugin/build/types/ios-widget/files/swift-utils.d.ts.map +1 -0
- package/expo-plugin/build/types/ios-widget/files/swift.d.ts +6 -2
- package/expo-plugin/build/types/ios-widget/files/swift.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/index.d.ts +3 -1
- package/expo-plugin/build/types/ios-widget/index.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/podfile.d.ts +19 -1
- package/expo-plugin/build/types/ios-widget/podfile.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/widgetPlist.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/xcode/buildPhases.d.ts +6 -8
- package/expo-plugin/build/types/ios-widget/xcode/buildPhases.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/xcode/configurationList.d.ts +15 -10
- package/expo-plugin/build/types/ios-widget/xcode/configurationList.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/xcode/fileReferences.d.ts +16 -0
- package/expo-plugin/build/types/ios-widget/xcode/fileReferences.d.ts.map +1 -0
- package/expo-plugin/build/types/ios-widget/xcode/groups.d.ts +0 -4
- package/expo-plugin/build/types/ios-widget/xcode/groups.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/xcode/index.d.ts +23 -3
- package/expo-plugin/build/types/ios-widget/xcode/index.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/xcode/mainAppSettings.d.ts +16 -4
- package/expo-plugin/build/types/ios-widget/xcode/mainAppSettings.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/xcode/productFile.d.ts +0 -4
- package/expo-plugin/build/types/ios-widget/xcode/productFile.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/xcode/target.d.ts +11 -26
- package/expo-plugin/build/types/ios-widget/xcode/target.d.ts.map +1 -1
- package/expo-plugin/build/types/types.d.ts +23 -4
- package/expo-plugin/build/types/types.d.ts.map +1 -1
- package/expo-plugin/build/types/utils/urlScheme.d.ts +16 -0
- package/expo-plugin/build/types/utils/urlScheme.d.ts.map +1 -1
- package/expo-plugin/build/types/validation.d.ts +2 -1
- package/expo-plugin/build/types/validation.d.ts.map +1 -1
- package/expo-plugin/src/constants.ts +24 -1
- package/expo-plugin/src/index.ts +14 -1
- package/expo-plugin/src/ios/index.ts +3 -0
- package/expo-plugin/src/ios/infoPlist.ts +33 -5
- package/expo-plugin/src/ios/serverUpdate.ts +29 -0
- package/expo-plugin/src/ios-widget/clientRendered.ts +9 -5
- package/expo-plugin/src/ios-widget/clientRenderedPrerender.ts +11 -6
- package/expo-plugin/src/ios-widget/dynamic-live-activity/swift.ts +138 -0
- package/expo-plugin/src/ios-widget/files/index.ts +15 -4
- package/expo-plugin/src/ios-widget/files/infoPlist.ts +17 -3
- package/expo-plugin/src/ios-widget/files/manifest.ts +42 -2
- package/expo-plugin/src/ios-widget/files/swift-utils.ts +3 -0
- package/expo-plugin/src/ios-widget/files/swift.ts +69 -22
- package/expo-plugin/src/ios-widget/index.ts +13 -3
- package/expo-plugin/src/ios-widget/podfile.ts +46 -13
- package/expo-plugin/src/ios-widget/widgetPlist.ts +37 -23
- package/expo-plugin/src/ios-widget/xcode/__fixtures__/fresh.pbxproj +197 -0
- package/expo-plugin/src/ios-widget/xcode/__fixtures__/with-existing-extension.pbxproj +321 -0
- package/expo-plugin/src/ios-widget/xcode/__fixtures__/with-per-config-signing.pbxproj +203 -0
- package/expo-plugin/src/ios-widget/xcode/__snapshots__/applyXcodeChanges.node.test.ts.snap +363 -0
- package/expo-plugin/src/ios-widget/xcode/__tests__/pbxConsistency.ts +130 -0
- package/expo-plugin/src/ios-widget/xcode/buildPhases.ts +210 -164
- package/expo-plugin/src/ios-widget/xcode/configurationList.ts +52 -35
- package/expo-plugin/src/ios-widget/xcode/fileReferences.ts +51 -0
- package/expo-plugin/src/ios-widget/xcode/groups.ts +52 -54
- package/expo-plugin/src/ios-widget/xcode/index.ts +124 -119
- package/expo-plugin/src/ios-widget/xcode/mainAppSettings.ts +59 -54
- package/expo-plugin/src/ios-widget/xcode/productFile.ts +3 -2
- package/expo-plugin/src/ios-widget/xcode/target.ts +31 -83
- package/expo-plugin/src/types.ts +28 -4
- package/expo-plugin/src/utils/urlScheme.ts +47 -17
- package/expo-plugin/src/validation.ts +76 -1
- package/ios/Package.swift +39 -4
- package/ios/VoltraWidget.podspec +1 -0
- package/ios/app/NativeVoltra.mm +126 -7
- package/ios/app/VoltraLiveActivityManager.swift +30 -0
- package/ios/app/VoltraLiveActivityService.swift +77 -5
- package/ios/app/VoltraModule.swift +117 -1
- package/ios/app/VoltraModuleImpl.swift +116 -2
- package/ios/app/VoltraViewComponentView.mm +3 -3
- package/ios/app/VoltraWidgetService.swift +147 -12
- package/ios/app/dynamic-live-activity/VoltraDynamicLiveActivityService.swift +97 -0
- package/ios/app/dynamic-live-activity/VoltraLiveActivityChronology.swift +68 -0
- package/ios/shared/DynamicWidgetPropsCodec.swift +51 -0
- package/ios/shared/DynamicWidgetPropsStorage.swift +53 -0
- package/ios/shared/DynamicWidgetPropsStore.swift +117 -0
- package/ios/shared/DynamicWidgetRenderCoordinator.swift +31 -0
- package/ios/shared/DynamicWidgetServerUpdate/DynamicWidgetServerFetchResolver.swift +34 -0
- package/ios/shared/DynamicWidgetServerUpdate/DynamicWidgetServerProps.swift +55 -0
- package/ios/shared/DynamicWidgetServerUpdate/DynamicWidgetServerPropsStore.swift +146 -0
- package/ios/shared/DynamicWidgetServerUpdate/DynamicWidgetServerUpdateRunner.swift +193 -0
- package/ios/shared/DynamicWidgetUpdater.swift +30 -0
- package/ios/shared/ServerWidgetContentResolver.swift +60 -0
- package/ios/shared/ServerWidgetResponseStore.swift +25 -0
- package/ios/shared/ShortNames.swift +6 -0
- package/ios/shared/VoltraConfig.swift +41 -0
- package/ios/shared/VoltraConstants.swift +19 -0
- package/ios/shared/VoltraElement.swift +127 -43
- package/ios/shared/VoltraEventBus.swift +52 -7
- package/ios/shared/VoltraJSRenderer.swift +93 -23
- package/ios/shared/VoltraNode.swift +7 -111
- package/ios/shared/VoltraRefreshIntent.swift +1 -1
- package/ios/shared/VoltraWidgetDefaults.swift +9 -1
- package/ios/shared/VoltraWidgetKind.swift +41 -0
- package/ios/shared/VoltraWidgetServerFetcher.swift +52 -107
- package/ios/shared/WidgetServer/VoltraWidgetAppearance.swift +17 -0
- package/ios/shared/WidgetServer/VoltraWidgetServer.swift +138 -0
- package/ios/shared/WidgetServer/WidgetCanonicalConfiguration.swift +77 -0
- package/ios/shared/WidgetServer/WidgetScope.swift +55 -0
- package/ios/shared/WidgetServer/WidgetServerEtagStore.swift +55 -0
- package/ios/shared/WidgetServer/WidgetServerFetcher.swift +179 -0
- package/ios/shared/WidgetServer/WidgetServerRequestBuilder.swift +114 -0
- package/ios/shared/WidgetServer/WidgetServerSettingsCodec.swift +47 -0
- package/ios/shared/WidgetServer/WidgetServerSettingsResolver.swift +129 -0
- package/ios/shared/WidgetServer/WidgetServerSettingsStore.swift +170 -0
- package/ios/shared/WidgetServer/WidgetServerSettingsValidator.swift +73 -0
- package/ios/shared/WidgetServer/WidgetServerUpdateSettings.swift +123 -0
- package/ios/shared/WidgetServer/WidgetServerUpdateSettingsJson.swift +115 -0
- package/ios/shared/dynamic-live-activity/DynamicLiveActivityPropsCodec.swift +13 -0
- package/ios/shared/dynamic-live-activity/VoltraDynamicLiveActivityBundleSource.swift +156 -0
- package/ios/shared/dynamic-live-activity/VoltraDynamicLiveActivityObserver.swift +97 -0
- package/ios/shared/dynamic-live-activity/VoltraDynamicLiveActivityOperations.swift +105 -0
- package/ios/shared/dynamic-live-activity/VoltraDynamicLiveActivityPayloadValidator.swift +55 -0
- package/ios/shared/dynamic-live-activity/VoltraDynamicLiveActivityRegistry.swift +143 -0
- package/ios/shared/dynamic-live-activity/VoltraDynamicLiveActivityRenderFailureQueue.swift +158 -0
- package/ios/shared/dynamic-live-activity/VoltraDynamicLiveActivityRenderFailureReporter.swift +120 -0
- package/ios/shared/dynamic-live-activity/VoltraDynamicLiveActivityRenderer.swift +370 -0
- package/ios/shared/dynamic-live-activity/VoltraDynamicLiveActivityTypes.swift +87 -0
- package/ios/shared/dynamic-live-activity/VoltraLiveActivityOrder.swift +19 -0
- package/ios/target/VoltraClientWidgetRuntime.swift +60 -10
- package/ios/target/VoltraDynamicWidgetServerUpdateProvider.swift +204 -0
- package/ios/target/VoltraHomeWidget.swift +91 -92
- package/ios/target/VoltraWidget.swift +3 -1
- package/ios/ui/Extensions/VoltraNode+View.swift +113 -0
- package/ios/ui/Generated/Parameters/ChartParameters.swift +3 -0
- package/ios/ui/Helpers/VoltraDeepLinkResolver.swift +5 -3
- package/ios/ui/Helpers/VoltraProgressDriver.swift +6 -2
- package/ios/ui/Layout/VoltraFlexStackLayout.swift +9 -3
- package/ios/ui/Style/JSColorParser.swift +24 -8
- package/ios/ui/Style/JSGradientParser.swift +36 -12
- package/ios/ui/Style/JSStyleParser.swift +36 -12
- package/ios/ui/Style/LayoutStyle.swift +12 -4
- package/ios/ui/Views/VoltraChart.swift +160 -16
- package/ios/ui/Views/VoltraLinearGradient.swift +6 -2
- package/package.json +5 -5
- package/src/dynamic-widget/api.ts +25 -0
- package/src/events.ts +34 -0
- package/src/index.ts +23 -0
- package/src/live-activity/api.ts +2 -2
- package/src/live-activity/dynamic-api.ts +240 -0
- package/src/native/NativeVoltra.ts +22 -0
- package/src/types.ts +4 -0
- package/src/utils/enableDynamicLiveActivityHotReload.ts +50 -0
- package/src/utils/enableWidgetHotReload.ts +9 -16
- package/src/utils/useUpdateOnHMR.ts +3 -12
- package/src/widgets/server-credentials.ts +8 -0
- package/src/widgets/server-update.ts +84 -0
- /package/ios/shared/{VoltraKeychainHelper.swift → WidgetServer/VoltraKeychainHelper.swift} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as fs from 'fs'
|
|
2
2
|
import * as path from 'path'
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { createPrerenderWidgetModuleLoader, type WidgetModuleLoader } from '@use-voltra/expo-plugin'
|
|
5
5
|
|
|
6
6
|
import type { IOSWidgetConfig } from '../types'
|
|
7
7
|
|
|
@@ -30,7 +30,8 @@ let hasWarnedExperimental = false
|
|
|
30
30
|
|
|
31
31
|
/** Inspect every widget once and tag entry-backed widgets as Dynamic Widgets. */
|
|
32
32
|
export function detectClientRenderedWidgets(widgets: IOSWidgetConfig[], projectRoot: string): DetectedIOSWidget[] {
|
|
33
|
-
const
|
|
33
|
+
const loader = createPrerenderWidgetModuleLoader(projectRoot, 'ios')
|
|
34
|
+
const detected = widgets.map((widget) => detectSingleWidget(widget, projectRoot, loader))
|
|
34
35
|
|
|
35
36
|
if (!hasWarnedExperimental) {
|
|
36
37
|
const clientWidgetIds = detected.filter((widget) => widget.clientRendered).map((widget) => widget.id)
|
|
@@ -47,7 +48,11 @@ export function detectClientRenderedWidgets(widgets: IOSWidgetConfig[], projectR
|
|
|
47
48
|
return detected
|
|
48
49
|
}
|
|
49
50
|
|
|
50
|
-
function detectSingleWidget(
|
|
51
|
+
function detectSingleWidget(
|
|
52
|
+
widget: IOSWidgetConfig,
|
|
53
|
+
projectRoot: string,
|
|
54
|
+
loader: WidgetModuleLoader
|
|
55
|
+
): DetectedIOSWidget {
|
|
51
56
|
if (widget.entry === undefined) {
|
|
52
57
|
return {
|
|
53
58
|
...widget,
|
|
@@ -65,8 +70,7 @@ function detectSingleWidget(widget: IOSWidgetConfig, projectRoot: string): Detec
|
|
|
65
70
|
)
|
|
66
71
|
}
|
|
67
72
|
|
|
68
|
-
const
|
|
69
|
-
const widgetFn = widgetModule?.default ?? widgetModule
|
|
73
|
+
const widgetFn = loader.loadDefaultExport(sourcePath)
|
|
70
74
|
if (typeof widgetFn !== 'function') {
|
|
71
75
|
throw new Error(
|
|
72
76
|
`[voltra] Dynamic Widget "${widget.id}" at ${path.relative(
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
createPrerenderWidgetModuleLoader,
|
|
3
|
+
logger,
|
|
4
|
+
resolveInstalledPackageVersion,
|
|
5
|
+
type PrerenderedWidgetStates,
|
|
6
|
+
} from '@use-voltra/expo-plugin'
|
|
2
7
|
|
|
3
8
|
import type { DetectedIOSWidget } from './clientRendered'
|
|
4
9
|
|
|
@@ -31,7 +36,7 @@ const SINGLE_LOCALE_KEY = '__default'
|
|
|
31
36
|
* mirror `WidgetEnvironment` from packages/core/src/widget-environment.ts so the widget
|
|
32
37
|
* function sees the same shape it gets at runtime.
|
|
33
38
|
*/
|
|
34
|
-
function buildPlaceholderEnv(): Record<string, unknown> {
|
|
39
|
+
function buildPlaceholderEnv(voltraVersion: string): Record<string, unknown> {
|
|
35
40
|
return {
|
|
36
41
|
date: Date.now(),
|
|
37
42
|
widgetFamily: 'systemMedium',
|
|
@@ -44,7 +49,7 @@ function buildPlaceholderEnv(): Record<string, unknown> {
|
|
|
44
49
|
isDev: false,
|
|
45
50
|
metroUrl: null,
|
|
46
51
|
appVersion: 'unknown',
|
|
47
|
-
voltraVersion
|
|
52
|
+
voltraVersion,
|
|
48
53
|
},
|
|
49
54
|
}
|
|
50
55
|
}
|
|
@@ -75,12 +80,12 @@ export async function prerenderClientRenderedWidgets(
|
|
|
75
80
|
renderVoltraVariantToJson: (element: unknown) => unknown
|
|
76
81
|
}
|
|
77
82
|
|
|
78
|
-
const placeholderEnv = buildPlaceholderEnv()
|
|
83
|
+
const placeholderEnv = buildPlaceholderEnv(resolveInstalledPackageVersion(projectRoot, '@use-voltra/ios-client'))
|
|
84
|
+
const loader = createPrerenderWidgetModuleLoader(projectRoot, 'ios')
|
|
79
85
|
|
|
80
86
|
for (const widget of clientWidgets) {
|
|
81
87
|
try {
|
|
82
|
-
const
|
|
83
|
-
const widgetFn = widgetModule?.default ?? widgetModule
|
|
88
|
+
const widgetFn = loader.loadDefaultExport(widget.clientSourcePath)
|
|
84
89
|
if (typeof widgetFn !== 'function') {
|
|
85
90
|
throw new Error(
|
|
86
91
|
`Expected the entry module at ${widget.clientSourcePath} to default-export a function or component.`
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import dedent from 'dedent'
|
|
2
|
+
|
|
3
|
+
import { getDynamicLiveActivityAttributesType } from '@use-voltra/expo-plugin'
|
|
4
|
+
|
|
5
|
+
import type { IOSDynamicLiveActivityConfig } from '../../types'
|
|
6
|
+
import { escapeForSwiftStringLiteral } from '../files/swift-utils'
|
|
7
|
+
|
|
8
|
+
export function generateDynamicLiveActivityWidgetInstances(liveActivities: IOSDynamicLiveActivityConfig[]): string {
|
|
9
|
+
return sortedDefinitions(liveActivities)
|
|
10
|
+
.map((liveActivity) => `VoltraDynamicLiveActivity_${getDynamicLiveActivityAttributesType(liveActivity.id)}()`)
|
|
11
|
+
.join('\n ')
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Generates the Dynamic Live Activity types shared by the app and extension targets. */
|
|
15
|
+
export function generateDynamicLiveActivityTypesSwift(liveActivities: IOSDynamicLiveActivityConfig[]): string {
|
|
16
|
+
const definitions = sortedDefinitions(liveActivities)
|
|
17
|
+
const typeDefinitions = definitions.map(generateDynamicLiveActivitySwift).map(normalizeIndent).join('\n\n')
|
|
18
|
+
|
|
19
|
+
const header = dedent`
|
|
20
|
+
//
|
|
21
|
+
// VoltraDynamicLiveActivityTypes.swift
|
|
22
|
+
//
|
|
23
|
+
// Auto-generated by Voltra config plugin. Do not edit.
|
|
24
|
+
//
|
|
25
|
+
|
|
26
|
+
import ActivityKit
|
|
27
|
+
import Foundation
|
|
28
|
+
|
|
29
|
+
import VoltraRuntime
|
|
30
|
+
|
|
31
|
+
@objc(VoltraGeneratedDynamicLiveActivityRegistration)
|
|
32
|
+
public final class VoltraGeneratedDynamicLiveActivityRegistration: NSObject {
|
|
33
|
+
@objc public static func registerDefinitions() {
|
|
34
|
+
${definitions
|
|
35
|
+
.map(
|
|
36
|
+
(liveActivity) =>
|
|
37
|
+
` VoltraDynamicLiveActivityRegistry.shared.register(${getDynamicLiveActivityAttributesType(
|
|
38
|
+
liveActivity.id
|
|
39
|
+
)}.self)`
|
|
40
|
+
)
|
|
41
|
+
.join('\n')}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
`
|
|
46
|
+
return [header.trim(), typeDefinitions.trim()].filter(Boolean).join('\n\n')
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Generates extension-only ActivityConfiguration declarations for Dynamic Live Activities. */
|
|
50
|
+
export function generateDynamicLiveActivitiesSwift(liveActivities: IOSDynamicLiveActivityConfig[]): string {
|
|
51
|
+
const configurations = sortedDefinitions(liveActivities)
|
|
52
|
+
.map((liveActivity) => {
|
|
53
|
+
const attributesType = getDynamicLiveActivityAttributesType(liveActivity.id)
|
|
54
|
+
const definitionId = escapeForSwiftStringLiteral(liveActivity.id)
|
|
55
|
+
return dedent`
|
|
56
|
+
public struct VoltraDynamicLiveActivity_${attributesType}: Widget {
|
|
57
|
+
public init() {}
|
|
58
|
+
|
|
59
|
+
public var body: some WidgetConfiguration {
|
|
60
|
+
if #available(iOS 18.0, *) {
|
|
61
|
+
return adaptiveConfig()
|
|
62
|
+
} else {
|
|
63
|
+
return defaultConfig()
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@available(iOS 18.0, *)
|
|
68
|
+
private func adaptiveConfig() -> some WidgetConfiguration {
|
|
69
|
+
ActivityConfiguration(for: ${attributesType}.self) { context in
|
|
70
|
+
VoltraDynamicLiveActivityRenderer.lockScreen(definitionId: "${definitionId}", context: context)
|
|
71
|
+
} dynamicIsland: { context in
|
|
72
|
+
VoltraDynamicLiveActivityRenderer.dynamicIsland(definitionId: "${definitionId}", context: context)
|
|
73
|
+
}
|
|
74
|
+
.supplementalActivityFamilies([.small, .medium])
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
private func defaultConfig() -> some WidgetConfiguration {
|
|
78
|
+
ActivityConfiguration(for: ${attributesType}.self) { context in
|
|
79
|
+
VoltraDynamicLiveActivityRenderer.lockScreen(definitionId: "${definitionId}", context: context)
|
|
80
|
+
} dynamicIsland: { context in
|
|
81
|
+
VoltraDynamicLiveActivityRenderer.dynamicIsland(definitionId: "${definitionId}", context: context)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
`
|
|
86
|
+
})
|
|
87
|
+
.map(normalizeIndent)
|
|
88
|
+
.join('\n\n')
|
|
89
|
+
|
|
90
|
+
const header = dedent`
|
|
91
|
+
//
|
|
92
|
+
// VoltraDynamicLiveActivities.swift
|
|
93
|
+
//
|
|
94
|
+
// Auto-generated by Voltra config plugin. Do not edit.
|
|
95
|
+
//
|
|
96
|
+
|
|
97
|
+
import ActivityKit
|
|
98
|
+
import SwiftUI
|
|
99
|
+
import WidgetKit
|
|
100
|
+
import VoltraRuntime
|
|
101
|
+
|
|
102
|
+
`
|
|
103
|
+
return [header.trim(), configurations.trim()].filter(Boolean).join('\n\n')
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function generateDynamicLiveActivitySwift(liveActivity: IOSDynamicLiveActivityConfig): string {
|
|
107
|
+
const attributesType = getDynamicLiveActivityAttributesType(liveActivity.id)
|
|
108
|
+
const definitionId = escapeForSwiftStringLiteral(liveActivity.id)
|
|
109
|
+
|
|
110
|
+
return dedent`
|
|
111
|
+
public struct ${attributesType}: ActivityAttributes {
|
|
112
|
+
public typealias ContentState = VoltraDynamicLiveActivityContentState
|
|
113
|
+
|
|
114
|
+
public let name: String
|
|
115
|
+
public let deepLinkUrl: String?
|
|
116
|
+
|
|
117
|
+
public init(name: String, deepLinkUrl: String?) {
|
|
118
|
+
self.name = name
|
|
119
|
+
self.deepLinkUrl = deepLinkUrl
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
extension ${attributesType}: VoltraDynamicLiveActivityDefinition {
|
|
124
|
+
public static let definitionId = "${definitionId}"
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
`
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function sortedDefinitions(liveActivities: IOSDynamicLiveActivityConfig[]): IOSDynamicLiveActivityConfig[] {
|
|
131
|
+
return [...liveActivities].sort((left, right) => left.id.localeCompare(right.id))
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function normalizeIndent(source: string): string {
|
|
135
|
+
const lines = source.trim().split('\n')
|
|
136
|
+
const indent = Math.min(...lines.filter(Boolean).map((line) => line.match(/^\s*/)?.[0].length ?? 0))
|
|
137
|
+
return lines.map((line) => line.slice(indent)).join('\n')
|
|
138
|
+
}
|
|
@@ -2,20 +2,22 @@ import { ConfigPlugin, withDangerousMod } from '@expo/config-plugins'
|
|
|
2
2
|
import * as fs from 'fs'
|
|
3
3
|
import * as path from 'path'
|
|
4
4
|
|
|
5
|
-
import type { IOSWidgetConfig } from '../../types'
|
|
5
|
+
import type { IOSDynamicLiveActivityConfig, IOSWidgetConfig } from '../../types'
|
|
6
6
|
import { generateAssets } from './assets'
|
|
7
7
|
import { generateEntitlements } from './entitlements'
|
|
8
8
|
import { generateInfoPlist } from './infoPlist'
|
|
9
|
-
import { generateIOSDynamicWidgetsManifest } from './manifest'
|
|
9
|
+
import { generateIOSDynamicLiveActivitiesManifest, generateIOSDynamicWidgetsManifest } from './manifest'
|
|
10
10
|
import { generateSwiftFiles } from './swift'
|
|
11
11
|
|
|
12
12
|
export interface GenerateWidgetExtensionFilesProps {
|
|
13
13
|
targetName: string
|
|
14
14
|
widgets?: IOSWidgetConfig[]
|
|
15
|
+
liveActivities?: IOSDynamicLiveActivityConfig[]
|
|
15
16
|
groupIdentifier?: string
|
|
16
17
|
keychainGroup?: string
|
|
17
18
|
version: string
|
|
18
19
|
buildNumber: string
|
|
20
|
+
voltraVersion: string
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
/**
|
|
@@ -31,7 +33,8 @@ export interface GenerateWidgetExtensionFilesProps {
|
|
|
31
33
|
* This should run before configureXcodeProject so the files exist when Xcode project is configured.
|
|
32
34
|
*/
|
|
33
35
|
export const generateWidgetExtensionFiles: ConfigPlugin<GenerateWidgetExtensionFilesProps> = (config, props) => {
|
|
34
|
-
const { targetName, widgets, groupIdentifier, keychainGroup, version, buildNumber } =
|
|
36
|
+
const { targetName, widgets, liveActivities, groupIdentifier, keychainGroup, version, buildNumber, voltraVersion } =
|
|
37
|
+
props
|
|
35
38
|
|
|
36
39
|
return withDangerousMod(config, [
|
|
37
40
|
'ios',
|
|
@@ -49,7 +52,7 @@ export const generateWidgetExtensionFiles: ConfigPlugin<GenerateWidgetExtensionF
|
|
|
49
52
|
}
|
|
50
53
|
|
|
51
54
|
// Generate Info.plist
|
|
52
|
-
generateInfoPlist(targetPath, targetName, version, buildNumber)
|
|
55
|
+
generateInfoPlist(targetPath, targetName, version, buildNumber, voltraVersion)
|
|
53
56
|
|
|
54
57
|
// Generate Assets.xcassets and copy user images
|
|
55
58
|
generateAssets({ targetPath })
|
|
@@ -59,6 +62,7 @@ export const generateWidgetExtensionFiles: ConfigPlugin<GenerateWidgetExtensionF
|
|
|
59
62
|
targetPath,
|
|
60
63
|
projectRoot,
|
|
61
64
|
widgets,
|
|
65
|
+
liveActivities,
|
|
62
66
|
})
|
|
63
67
|
|
|
64
68
|
// Write the iOS-owned Dynamic Widgets manifest for Metro to consume later.
|
|
@@ -67,6 +71,13 @@ export const generateWidgetExtensionFiles: ConfigPlugin<GenerateWidgetExtensionF
|
|
|
67
71
|
widgets,
|
|
68
72
|
})
|
|
69
73
|
|
|
74
|
+
// Dynamic Live Activities have their own Metro manifest so their IDs may overlap with
|
|
75
|
+
// Dynamic Widgets and stale declarations never leak into a later prebuild.
|
|
76
|
+
generateIOSDynamicLiveActivitiesManifest({
|
|
77
|
+
projectRoot,
|
|
78
|
+
liveActivities,
|
|
79
|
+
})
|
|
80
|
+
|
|
70
81
|
// Generate entitlements file (may be empty if no groupIdentifier or keychainGroup)
|
|
71
82
|
generateEntitlements({
|
|
72
83
|
targetPath,
|
|
@@ -9,7 +9,12 @@ import { logger } from '@use-voltra/expo-plugin'
|
|
|
9
9
|
* This includes version information and the required WidgetKit extension point.
|
|
10
10
|
* Version keys are written directly to the plist following the Expo pattern.
|
|
11
11
|
*/
|
|
12
|
-
function generateInfoPlistContent(
|
|
12
|
+
function generateInfoPlistContent(
|
|
13
|
+
targetName: string,
|
|
14
|
+
version: string,
|
|
15
|
+
buildNumber: string,
|
|
16
|
+
voltraVersion: string
|
|
17
|
+
): string {
|
|
13
18
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
14
19
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
15
20
|
<plist version="1.0">
|
|
@@ -32,6 +37,8 @@ function generateInfoPlistContent(targetName: string, version: string, buildNumb
|
|
|
32
37
|
<string>${version}</string>
|
|
33
38
|
<key>CFBundleVersion</key>
|
|
34
39
|
<string>${buildNumber}</string>
|
|
40
|
+
<key>Voltra_Version</key>
|
|
41
|
+
<string>${voltraVersion}</string>
|
|
35
42
|
<key>NSExtension</key>
|
|
36
43
|
<dict>
|
|
37
44
|
<key>NSExtensionPointIdentifier</key>
|
|
@@ -49,9 +56,16 @@ function generateInfoPlistContent(targetName: string, version: string, buildNumb
|
|
|
49
56
|
* @param targetName - The widget extension target name (used for CFBundleDisplayName)
|
|
50
57
|
* @param version - The app version (CFBundleShortVersionString)
|
|
51
58
|
* @param buildNumber - The build number (CFBundleVersion)
|
|
59
|
+
* @param voltraVersion - The installed @use-voltra/ios-client package version
|
|
52
60
|
*/
|
|
53
|
-
export function generateInfoPlist(
|
|
61
|
+
export function generateInfoPlist(
|
|
62
|
+
targetPath: string,
|
|
63
|
+
targetName: string,
|
|
64
|
+
version: string,
|
|
65
|
+
buildNumber: string,
|
|
66
|
+
voltraVersion: string
|
|
67
|
+
): void {
|
|
54
68
|
const infoPlistPath = path.join(targetPath, 'Info.plist')
|
|
55
|
-
fs.writeFileSync(infoPlistPath, generateInfoPlistContent(targetName, version, buildNumber))
|
|
69
|
+
fs.writeFileSync(infoPlistPath, generateInfoPlistContent(targetName, version, buildNumber, voltraVersion))
|
|
56
70
|
logger.info('Generated Info.plist')
|
|
57
71
|
}
|
|
@@ -1,17 +1,28 @@
|
|
|
1
1
|
import * as fs from 'fs'
|
|
2
2
|
import * as path from 'path'
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
type DynamicLiveActivityManifest,
|
|
6
|
+
type DynamicWidgetManifest,
|
|
7
|
+
logger,
|
|
8
|
+
validateWidgetEntry,
|
|
9
|
+
} from '@use-voltra/expo-plugin'
|
|
5
10
|
|
|
6
|
-
import type { IOSWidgetConfig } from '../../types'
|
|
11
|
+
import type { IOSDynamicLiveActivityConfig, IOSWidgetConfig } from '../../types'
|
|
7
12
|
|
|
8
13
|
const MANIFEST_PATH = path.join('.voltra', 'manifest.ios.json')
|
|
14
|
+
const LIVE_ACTIVITIES_MANIFEST_PATH = path.join('.voltra', 'manifest.ios.live-activities.json')
|
|
9
15
|
|
|
10
16
|
export interface GenerateIOSDynamicWidgetsManifestOptions {
|
|
11
17
|
projectRoot: string
|
|
12
18
|
widgets?: IOSWidgetConfig[]
|
|
13
19
|
}
|
|
14
20
|
|
|
21
|
+
export interface GenerateIOSDynamicLiveActivitiesManifestOptions {
|
|
22
|
+
projectRoot: string
|
|
23
|
+
liveActivities?: IOSDynamicLiveActivityConfig[]
|
|
24
|
+
}
|
|
25
|
+
|
|
15
26
|
export function createIOSDynamicWidgetsManifest(
|
|
16
27
|
projectRoot: string,
|
|
17
28
|
widgets: IOSWidgetConfig[]
|
|
@@ -36,6 +47,22 @@ export function createIOSDynamicWidgetsManifest(
|
|
|
36
47
|
}
|
|
37
48
|
}
|
|
38
49
|
|
|
50
|
+
export function createIOSDynamicLiveActivitiesManifest(
|
|
51
|
+
projectRoot: string,
|
|
52
|
+
liveActivities: IOSDynamicLiveActivityConfig[]
|
|
53
|
+
): DynamicLiveActivityManifest {
|
|
54
|
+
return {
|
|
55
|
+
version: 1,
|
|
56
|
+
platform: 'ios',
|
|
57
|
+
liveActivities: [...liveActivities]
|
|
58
|
+
.sort((left, right) => left.id.localeCompare(right.id))
|
|
59
|
+
.map((liveActivity) => ({
|
|
60
|
+
id: liveActivity.id,
|
|
61
|
+
entry: validateWidgetEntry(liveActivity.entry, liveActivity.id, projectRoot),
|
|
62
|
+
})),
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
39
66
|
export function generateIOSDynamicWidgetsManifest(options: GenerateIOSDynamicWidgetsManifestOptions): void {
|
|
40
67
|
const { projectRoot, widgets } = options
|
|
41
68
|
const manifestPath = path.join(projectRoot, MANIFEST_PATH)
|
|
@@ -45,3 +72,16 @@ export function generateIOSDynamicWidgetsManifest(options: GenerateIOSDynamicWid
|
|
|
45
72
|
fs.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`)
|
|
46
73
|
logger.info(`Generated ${MANIFEST_PATH}`)
|
|
47
74
|
}
|
|
75
|
+
|
|
76
|
+
/** Writes the dedicated Dynamic Live Activity manifest on every prebuild, including when empty. */
|
|
77
|
+
export function generateIOSDynamicLiveActivitiesManifest(
|
|
78
|
+
options: GenerateIOSDynamicLiveActivitiesManifestOptions
|
|
79
|
+
): void {
|
|
80
|
+
const { projectRoot, liveActivities } = options
|
|
81
|
+
const manifestPath = path.join(projectRoot, LIVE_ACTIVITIES_MANIFEST_PATH)
|
|
82
|
+
const manifest = createIOSDynamicLiveActivitiesManifest(projectRoot, liveActivities ?? [])
|
|
83
|
+
|
|
84
|
+
fs.mkdirSync(path.dirname(manifestPath), { recursive: true })
|
|
85
|
+
fs.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`)
|
|
86
|
+
logger.info(`Generated ${LIVE_ACTIVITIES_MANIFEST_PATH}`)
|
|
87
|
+
}
|
|
@@ -11,16 +11,24 @@ import {
|
|
|
11
11
|
type WidgetLabel,
|
|
12
12
|
} from '@use-voltra/expo-plugin'
|
|
13
13
|
|
|
14
|
-
import { DEFAULT_WIDGET_FAMILIES, WIDGET_FAMILY_MAP } from '../../constants'
|
|
15
|
-
import type { IOSWidgetConfig } from '../../types'
|
|
14
|
+
import { DEFAULT_WIDGET_FAMILIES, WIDGET_FAMILY_MAP, widgetKind } from '../../constants'
|
|
15
|
+
import type { IOSDynamicLiveActivityConfig, IOSWidgetConfig } from '../../types'
|
|
16
16
|
import { VOLTRA_WIDGET_STRINGS_BASENAME } from '../../utils/fileDiscovery'
|
|
17
17
|
import { detectClientRenderedWidgets, type DetectedIOSWidget } from '../clientRendered'
|
|
18
18
|
import { prerenderClientRenderedWidgets } from '../clientRenderedPrerender'
|
|
19
|
+
import {
|
|
20
|
+
generateDynamicLiveActivitiesSwift,
|
|
21
|
+
generateDynamicLiveActivityTypesSwift,
|
|
22
|
+
generateDynamicLiveActivityWidgetInstances,
|
|
23
|
+
} from '../dynamic-live-activity/swift'
|
|
24
|
+
|
|
25
|
+
import { escapeForSwiftStringLiteral } from './swift-utils'
|
|
19
26
|
|
|
20
27
|
export interface GenerateSwiftFilesOptions {
|
|
21
28
|
targetPath: string
|
|
22
29
|
projectRoot: string
|
|
23
30
|
widgets?: IOSWidgetConfig[]
|
|
31
|
+
liveActivities?: IOSDynamicLiveActivityConfig[]
|
|
24
32
|
}
|
|
25
33
|
|
|
26
34
|
type RenderWidgetToString = (variants: unknown) => string
|
|
@@ -37,7 +45,7 @@ type RenderWidgetToString = (variants: unknown) => string
|
|
|
37
45
|
* - VoltraWidgetBundle.swift (widget bundle definition)
|
|
38
46
|
*/
|
|
39
47
|
export async function generateSwiftFiles(options: GenerateSwiftFilesOptions): Promise<void> {
|
|
40
|
-
const { targetPath, projectRoot, widgets } = options
|
|
48
|
+
const { targetPath, projectRoot, widgets, liveActivities } = options
|
|
41
49
|
|
|
42
50
|
// Dynamic import keeps the plugin CommonJS-compatible while resolving the current package entry.
|
|
43
51
|
const serverModuleId = '@use-voltra/ios/server'
|
|
@@ -59,7 +67,7 @@ export async function generateSwiftFiles(options: GenerateSwiftFilesOptions): Pr
|
|
|
59
67
|
// stringify). Both produce entries in the same map shape so
|
|
60
68
|
// VoltraWidgetInitialStates.swift can read either via the same lookup at runtime.
|
|
61
69
|
const serverWidgets = detectedWidgets.filter((w) => !w.clientRendered)
|
|
62
|
-
const serverStates = await prerenderWidgetState(serverWidgets, projectRoot, renderWidgetToString)
|
|
70
|
+
const serverStates = await prerenderWidgetState(serverWidgets, projectRoot, renderWidgetToString, 'ios')
|
|
63
71
|
const clientStates = await prerenderClientRenderedWidgets(detectedWidgets, projectRoot)
|
|
64
72
|
const prerenderedStates = new Map([...serverStates, ...clientStates])
|
|
65
73
|
|
|
@@ -76,12 +84,24 @@ export async function generateSwiftFiles(options: GenerateSwiftFilesOptions): Pr
|
|
|
76
84
|
|
|
77
85
|
// Generate the widget bundle Swift file
|
|
78
86
|
const widgetBundleContent =
|
|
79
|
-
detectedWidgets.length > 0
|
|
87
|
+
detectedWidgets.length > 0 || (liveActivities?.length ?? 0) > 0
|
|
88
|
+
? generateWidgetBundleSwift(detectedWidgets, liveActivities ?? [])
|
|
89
|
+
: generateDefaultWidgetBundleSwift()
|
|
80
90
|
|
|
81
91
|
const widgetBundlePath = path.join(targetPath, 'VoltraWidgetBundle.swift')
|
|
82
92
|
fs.writeFileSync(widgetBundlePath, widgetBundleContent)
|
|
83
93
|
|
|
84
94
|
logger.info(`Generated VoltraWidgetBundle.swift with ${widgets?.length ?? 0} home screen widgets`)
|
|
95
|
+
|
|
96
|
+
fs.writeFileSync(
|
|
97
|
+
path.join(targetPath, 'VoltraDynamicLiveActivityTypes.swift'),
|
|
98
|
+
generateDynamicLiveActivityTypesSwift(liveActivities ?? [])
|
|
99
|
+
)
|
|
100
|
+
fs.writeFileSync(
|
|
101
|
+
path.join(targetPath, 'VoltraDynamicLiveActivities.swift'),
|
|
102
|
+
generateDynamicLiveActivitiesSwift(liveActivities ?? [])
|
|
103
|
+
)
|
|
104
|
+
logger.info(`Generated Dynamic Live Activity Swift scaffolding with ${liveActivities?.length ?? 0} definition(s)`)
|
|
85
105
|
}
|
|
86
106
|
|
|
87
107
|
const GENERATED_INITIAL_STATE_LOCALE_HELPER = dedent`
|
|
@@ -155,10 +175,6 @@ const GENERATED_INITIAL_STATE_LOCALE_HELPER = dedent`
|
|
|
155
175
|
// https://developer.apple.com/documentation/foundation/localizedstringresource
|
|
156
176
|
// ============================================================================
|
|
157
177
|
|
|
158
|
-
function escapeForSwiftStringLiteral(s: string): string {
|
|
159
|
-
return s.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n').replace(/\r/g, '\\r')
|
|
160
|
-
}
|
|
161
|
-
|
|
162
178
|
function escapeDotStringsValue(s: string): string {
|
|
163
179
|
return escapeForSwiftStringLiteral(s)
|
|
164
180
|
}
|
|
@@ -285,6 +301,12 @@ function iosWidgetGalleryLabelSwiftExpr(
|
|
|
285
301
|
* - Dynamic Widget → `VoltraClientWidgetProvider` + `VoltraClientWidgetContentView`
|
|
286
302
|
* (the content view internally renders via VoltraHomeWidgetView so the UI layer is
|
|
287
303
|
* identical to the fallback state path — see VoltraClientWidgetRuntime.swift)
|
|
304
|
+
* - Dynamic Widget with a `serverUpdate` → `VoltraDynamicWidgetServerUpdateProvider`, which wraps
|
|
305
|
+
* the one above and adds the fetch, the commit and the schedule
|
|
306
|
+
*
|
|
307
|
+
* `entry` picks the render engine and `serverUpdate` picks where the data comes from, so the two
|
|
308
|
+
* keys together select one of four providers. Runtime code never asks "is this server-driven?" —
|
|
309
|
+
* the answer is baked in here, once, at generate time.
|
|
288
310
|
*/
|
|
289
311
|
function widgetUsesAppIntent(widget: DetectedIOSWidget): boolean {
|
|
290
312
|
return widget.clientRendered && !!widget.appIntent && widget.appIntent.parameters.length > 0
|
|
@@ -306,9 +328,13 @@ function generateWidgetStruct(widget: DetectedIOSWidget): string {
|
|
|
306
328
|
const displayNameExpr = iosWidgetGalleryLabelSwiftExpr(widget.id, 'displayName', widget.displayName)
|
|
307
329
|
const descriptionExpr = iosWidgetGalleryLabelSwiftExpr(widget.id, 'description', widget.description)
|
|
308
330
|
|
|
331
|
+
const clientProviderName = widget.serverUpdate
|
|
332
|
+
? 'VoltraDynamicWidgetServerUpdateProvider'
|
|
333
|
+
: 'VoltraClientWidgetProvider'
|
|
334
|
+
|
|
309
335
|
const providerAndContent = widget.clientRendered
|
|
310
336
|
? dedent`
|
|
311
|
-
provider:
|
|
337
|
+
provider: ${clientProviderName}(
|
|
312
338
|
widgetId: widgetId,
|
|
313
339
|
initialState: VoltraWidgetInitialStates.getInitialState(for: widgetId)
|
|
314
340
|
)
|
|
@@ -335,7 +361,7 @@ function generateWidgetStruct(widget: DetectedIOSWidget): string {
|
|
|
335
361
|
|
|
336
362
|
public var body: some WidgetConfiguration {
|
|
337
363
|
StaticConfiguration(
|
|
338
|
-
kind: "
|
|
364
|
+
kind: "${widgetKind(widget)}",
|
|
339
365
|
${providerAndContent}
|
|
340
366
|
.configurationDisplayName(${displayNameExpr})
|
|
341
367
|
.description(${descriptionExpr})
|
|
@@ -377,6 +403,18 @@ function generateClientAppIntentWidgetCode(widget: DetectedIOSWidget): string {
|
|
|
377
403
|
const initBody = params.map((p) => ` self.${p.name} = ${p.name}`).join('\n')
|
|
378
404
|
const configuredDict = dictLiteral(params.map((p) => `"${p.name}": configuration.${p.name}`))
|
|
379
405
|
const defaultDict = dictLiteral(params.map((p) => `"${p.name}": ${swiftDefault(p)}`))
|
|
406
|
+
// A server-driven Dynamic Widget fetches on every timeline request and schedules the next one
|
|
407
|
+
// from its resolved interval; a plain one has nothing to ask again for, so its policy is .never.
|
|
408
|
+
const appIntentTimelineBody = widget.serverUpdate
|
|
409
|
+
? dedent`
|
|
410
|
+
return await VoltraDynamicWidgetServerUpdateProvider.timeline(
|
|
411
|
+
widgetId: widgetId,
|
|
412
|
+
family: context.family,
|
|
413
|
+
configuration: ${configuredDict}
|
|
414
|
+
)`
|
|
415
|
+
: dedent`
|
|
416
|
+
let entry = await VoltraClientWidgetProvider.loadEntry(widgetId: widgetId, configuration: ${configuredDict})
|
|
417
|
+
return Timeline(entries: [entry], policy: .never)`
|
|
380
418
|
|
|
381
419
|
return dedent`
|
|
382
420
|
// MARK: - Client-rendered AppIntent widget: ${widget.id}
|
|
@@ -408,9 +446,8 @@ function generateClientAppIntentWidgetCode(widget: DetectedIOSWidget): string {
|
|
|
408
446
|
await VoltraClientWidgetProvider.loadEntry(widgetId: widgetId, configuration: ${configuredDict})
|
|
409
447
|
}
|
|
410
448
|
|
|
411
|
-
func timeline(for configuration: ${intentName}, in
|
|
412
|
-
|
|
413
|
-
return Timeline(entries: [entry], policy: .never)
|
|
449
|
+
func timeline(for configuration: ${intentName}, in context: Context) async -> Timeline<VoltraClientWidgetEntry> {
|
|
450
|
+
${appIntentTimelineBody}
|
|
414
451
|
}
|
|
415
452
|
}
|
|
416
453
|
|
|
@@ -422,7 +459,7 @@ function generateClientAppIntentWidgetCode(widget: DetectedIOSWidget): string {
|
|
|
422
459
|
|
|
423
460
|
public var body: some WidgetConfiguration {
|
|
424
461
|
AppIntentConfiguration(
|
|
425
|
-
kind: "
|
|
462
|
+
kind: "${widgetKind(widget)}",
|
|
426
463
|
intent: ${intentName}.self,
|
|
427
464
|
provider: ${providerName}()
|
|
428
465
|
) { entry in
|
|
@@ -443,7 +480,10 @@ function generateClientAppIntentWidgetCode(widget: DetectedIOSWidget): string {
|
|
|
443
480
|
/**
|
|
444
481
|
* Generates the VoltraWidgetBundle.swift file content with configured widgets
|
|
445
482
|
*/
|
|
446
|
-
function generateWidgetBundleSwift(
|
|
483
|
+
function generateWidgetBundleSwift(
|
|
484
|
+
widgets: DetectedIOSWidget[],
|
|
485
|
+
liveActivities: IOSDynamicLiveActivityConfig[] = []
|
|
486
|
+
): string {
|
|
447
487
|
// Generate widget structs
|
|
448
488
|
const widgetStructs = widgets.map((w) => generateWidgetStruct(w)).join('\n\n')
|
|
449
489
|
|
|
@@ -457,7 +497,12 @@ function generateWidgetBundleSwift(widgets: DetectedIOSWidget[]): string {
|
|
|
457
497
|
.map((w) => `VoltraWidget_${w.id}()`)
|
|
458
498
|
.join('\n ')}\n }`
|
|
459
499
|
: ''
|
|
460
|
-
const
|
|
500
|
+
const dynamicLiveActivityInstances = generateDynamicLiveActivityWidgetInstances(liveActivities)
|
|
501
|
+
const widgetInstances = [plainInstances, appIntentInstances, dynamicLiveActivityInstances]
|
|
502
|
+
.filter(Boolean)
|
|
503
|
+
.join('\n ')
|
|
504
|
+
const widgetSectionTitle =
|
|
505
|
+
liveActivities.length > 0 ? 'Home Screen Widgets and Dynamic Live Activities' : 'Home Screen Widgets'
|
|
461
506
|
|
|
462
507
|
const needsFoundation = widgets.some(widgetUsesGalleryLocalization)
|
|
463
508
|
const foundationImport = needsFoundation ? 'import Foundation\n' : ''
|
|
@@ -473,7 +518,7 @@ function generateWidgetBundleSwift(widgets: DetectedIOSWidget[]): string {
|
|
|
473
518
|
|
|
474
519
|
${foundationImport}${appIntentsImport}import SwiftUI
|
|
475
520
|
import WidgetKit
|
|
476
|
-
import
|
|
521
|
+
import VoltraRuntime
|
|
477
522
|
|
|
478
523
|
@main
|
|
479
524
|
struct VoltraWidgetBundle: WidgetBundle {
|
|
@@ -481,7 +526,7 @@ function generateWidgetBundleSwift(widgets: DetectedIOSWidget[]): string {
|
|
|
481
526
|
// Live Activity (with Watch/CarPlay support)
|
|
482
527
|
VoltraWidget()
|
|
483
528
|
|
|
484
|
-
//
|
|
529
|
+
// ${widgetSectionTitle}
|
|
485
530
|
${widgetInstances}
|
|
486
531
|
}
|
|
487
532
|
}
|
|
@@ -493,8 +538,8 @@ function generateWidgetBundleSwift(widgets: DetectedIOSWidget[]): string {
|
|
|
493
538
|
}
|
|
494
539
|
|
|
495
540
|
/**
|
|
496
|
-
* Generates the VoltraWidgetBundle.swift file content when no widgets
|
|
497
|
-
*
|
|
541
|
+
* Generates the VoltraWidgetBundle.swift file content when no Home Screen widgets or Dynamic
|
|
542
|
+
* Live Activities are configured. Keep this legacy output stable for existing projects.
|
|
498
543
|
*/
|
|
499
544
|
function generateDefaultWidgetBundleSwift(): string {
|
|
500
545
|
return dedent`
|
|
@@ -507,7 +552,7 @@ function generateDefaultWidgetBundleSwift(): string {
|
|
|
507
552
|
|
|
508
553
|
import SwiftUI
|
|
509
554
|
import WidgetKit
|
|
510
|
-
import
|
|
555
|
+
import VoltraRuntime // Import Voltra widgets
|
|
511
556
|
|
|
512
557
|
@main
|
|
513
558
|
struct VoltraWidgetBundle: WidgetBundle {
|
|
@@ -624,4 +669,6 @@ function getSwiftRawStringDelimiter(str: string): string {
|
|
|
624
669
|
export const __test__ = {
|
|
625
670
|
generateInitialStatesSwift,
|
|
626
671
|
generateWidgetBundleSwift,
|
|
672
|
+
generateDynamicLiveActivityTypesSwift,
|
|
673
|
+
generateDynamicLiveActivitiesSwift,
|
|
627
674
|
}
|