@peers-app/peers-ui 0.7.40 → 0.8.1

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 (39) hide show
  1. package/dist/command-palette/command-palette.d.ts +2 -2
  2. package/dist/command-palette/command-palette.js +3 -7
  3. package/dist/components/group-switcher.d.ts +2 -1
  4. package/dist/components/group-switcher.js +7 -6
  5. package/dist/globals.d.ts +1 -1
  6. package/dist/screens/contacts/contact-list.js +4 -1
  7. package/dist/screens/contacts/index.d.ts +2 -0
  8. package/dist/screens/contacts/index.js +2 -0
  9. package/dist/screens/contacts/user-connect.d.ts +2 -0
  10. package/dist/screens/contacts/user-connect.js +312 -0
  11. package/dist/screens/network-viewer/device-details-modal.js +44 -0
  12. package/dist/screens/network-viewer/group-details-modal.js +80 -2
  13. package/dist/screens/network-viewer/network-viewer.js +36 -16
  14. package/dist/screens/settings/settings-page.js +13 -7
  15. package/dist/screens/setup-user.js +8 -6
  16. package/dist/system-apps/index.d.ts +1 -0
  17. package/dist/system-apps/index.js +10 -1
  18. package/dist/system-apps/mobile-settings.app.d.ts +2 -0
  19. package/dist/system-apps/mobile-settings.app.js +8 -0
  20. package/dist/tabs-layout/tabs-layout.js +60 -38
  21. package/dist/tabs-layout/tabs-state.d.ts +10 -4
  22. package/dist/tabs-layout/tabs-state.js +41 -4
  23. package/dist/ui-router/ui-loader.js +45 -12
  24. package/package.json +3 -3
  25. package/src/command-palette/command-palette.ts +4 -8
  26. package/src/components/group-switcher.tsx +12 -8
  27. package/src/screens/contacts/contact-list.tsx +4 -0
  28. package/src/screens/contacts/index.ts +3 -1
  29. package/src/screens/contacts/user-connect.tsx +452 -0
  30. package/src/screens/network-viewer/device-details-modal.tsx +55 -0
  31. package/src/screens/network-viewer/group-details-modal.tsx +144 -1
  32. package/src/screens/network-viewer/network-viewer.tsx +36 -29
  33. package/src/screens/settings/settings-page.tsx +17 -9
  34. package/src/screens/setup-user.tsx +9 -6
  35. package/src/system-apps/index.ts +9 -0
  36. package/src/system-apps/mobile-settings.app.ts +8 -0
  37. package/src/tabs-layout/tabs-layout.tsx +108 -82
  38. package/src/tabs-layout/tabs-state.ts +54 -5
  39. package/src/ui-router/ui-loader.tsx +50 -11
@@ -1,4 +1,4 @@
1
- import { groupDeviceVar, groupUserVar, IAppNav, IPackage, newid } from "@peers-app/peers-sdk";
1
+ import { groupDeviceVar, groupUserVar, IAppNav, IPackage, newid, observable, Observable } from "@peers-app/peers-sdk";
2
2
  import { _mainContentPath } from "../globals";
3
3
  import { systemPackage } from "../system-apps";
4
4
  import { allPackages } from "../ui-router/routes-loader";
@@ -19,19 +19,68 @@ export const launcherApp: TabState = {
19
19
  iconClassName: 'bi-grid-3x3-gap',
20
20
  };
21
21
 
22
- // Global persistent variables for tab state
23
- export const activeTabs = groupDeviceVar<TabState[]>('activeTabs', {
22
+ // Persistent vars for storage (write-only, no subscription to avoid oscillation)
23
+ const _persistentActiveTabs = groupDeviceVar<TabState[]>('activeTabs', {
24
24
  defaultValue: [launcherApp],
25
25
  });
26
26
 
27
- export const activeTabId = groupDeviceVar<string>('activeTabId', {
27
+ const _persistentActiveTabId = groupDeviceVar<string>('activeTabId', {
28
28
  defaultValue: 'launcher',
29
29
  });
30
30
 
31
- export const recentlyUsedApps = groupUserVar<string[]>('recentlyUsedApps', {
31
+ const _persistentRecentlyUsedApps = groupUserVar<string[]>('recentlyUsedApps', {
32
32
  defaultValue: [],
33
33
  });
34
34
 
35
+ // In-memory observables for UI state (loaded once, then write-through to persistent vars)
36
+ export const activeTabs: Observable<TabState[]> & { loadingPromise: Promise<void> } = (() => {
37
+ const obs = observable<TabState[]>([launcherApp]);
38
+
39
+ // Write-through to persistent var on change
40
+ obs.subscribe(value => {
41
+ _persistentActiveTabs(value);
42
+ });
43
+
44
+ // Load initial value once
45
+ const loadingPromise = _persistentActiveTabs.loadingPromise.then(() => {
46
+ obs(_persistentActiveTabs());
47
+ });
48
+
49
+ return Object.assign(obs, { loadingPromise });
50
+ })();
51
+
52
+ export const activeTabId: Observable<string> & { loadingPromise: Promise<void> } = (() => {
53
+ const obs = observable<string>('launcher');
54
+
55
+ // Write-through to persistent var on change
56
+ obs.subscribe(value => {
57
+ _persistentActiveTabId(value);
58
+ });
59
+
60
+ // Load initial value once
61
+ const loadingPromise = _persistentActiveTabId.loadingPromise.then(() => {
62
+ obs(_persistentActiveTabId());
63
+ });
64
+
65
+ return Object.assign(obs, { loadingPromise });
66
+ })();
67
+
68
+ export const recentlyUsedApps: Observable<string[]> & { loadingPromise: Promise<void> } = (() => {
69
+ const obs = observable<string[]>([]);
70
+
71
+ // Write-through to persistent var on change
72
+ obs.subscribe(value => {
73
+ _persistentRecentlyUsedApps(value);
74
+ });
75
+
76
+ // Load initial value once
77
+ const loadingPromise = _persistentRecentlyUsedApps.loadingPromise.then(() => {
78
+ obs(_persistentRecentlyUsedApps());
79
+ });
80
+
81
+ return Object.assign(obs, { loadingPromise });
82
+ })();
83
+
35
84
  export const initializedTabs = new Set<string>();
36
85
 
37
86
  export function goToTabPath(path: string) {
@@ -221,26 +221,65 @@ const UILoader = (args: { peersUIId: string, props: Record<string, any> }) => {
221
221
  }
222
222
 
223
223
  const uiLoadingPromises: Record<string, Promise<any>> = {};
224
+
225
+ // Check if we're running in a React Native WebView (has injectUIBundle available)
226
+ const isReactNativeWebView = typeof (window as any).ReactNativeWebView !== 'undefined';
227
+
224
228
  function loadUIBundle(pkg: IPackage, forceRefresh?: boolean) {
225
229
  // Dynamically import the bundle
226
230
  let importPromise: Promise<any> = uiLoadingPromises[pkg.packageId];
227
231
  if (!importPromise || forceRefresh) {
232
+ const sTime = Date.now();
228
233
  console.log(`loading ui bundle for ${pkg.name}`);
229
234
  importPromise = new Promise<void>(async (resolve, reject) => {
230
235
  try {
231
- let bundleCode = '';
232
- if (pkg.uiBundleFileId) {
233
- bundleCode = await rpcServerCalls.getFileContents(pkg.uiBundleFileId);
236
+ if (!pkg.uiBundleFileId) {
237
+ resolve();
238
+ return;
234
239
  }
235
- if (bundleCode) {
236
- const exportUIs = (peerUIs: IPeersPackageUIs) => {
237
- // TODO maybe add packageId that this came from
238
- peerUIs?.uis?.forEach(ui => {
239
- peersUIs[ui.peersUIId] = ui;
240
- });
240
+
241
+ // Use fast injection path for React Native WebView
242
+ if (isReactNativeWebView && rpcServerCalls.injectUIBundle) {
243
+ // Set up listeners for bundle load completion
244
+ const _window = window as any;
245
+ _window.__peersUIs = _window.__peersUIs || {};
246
+
247
+ const loadPromise = new Promise<void>((resolveLoad, rejectLoad) => {
248
+ const fileId = pkg.uiBundleFileId!;
249
+
250
+ _window.__peersUIBundleLoaded = (loadedFileId: string) => {
251
+ if (loadedFileId === fileId) {
252
+ // Copy loaded UIs to our local registry
253
+ Object.keys(_window.__peersUIs || {}).forEach(peersUIId => {
254
+ peersUIs[peersUIId] = _window.__peersUIs[peersUIId];
255
+ });
256
+ resolveLoad();
257
+ }
258
+ };
259
+
260
+ _window.__peersUIBundleError = (errorFileId: string, errorMsg: string) => {
261
+ if (errorFileId === fileId) {
262
+ rejectLoad(new Error(errorMsg));
263
+ }
264
+ };
265
+ });
266
+
267
+ await rpcServerCalls.injectUIBundle(pkg.uiBundleFileId);
268
+ await loadPromise;
269
+ console.log(`finished loading ui bundle for ${pkg.name}: ${(Date.now() - sTime).toFixed(0)}ms`);
270
+ } else {
271
+ // Fallback: use postMessage-based getFileContents (slower for large bundles)
272
+ let bundleCode = await rpcServerCalls.getFileContents(pkg.uiBundleFileId);
273
+ if (bundleCode) {
274
+ const exportUIs = (peerUIs: IPeersPackageUIs) => {
275
+ peerUIs?.uis?.forEach(ui => {
276
+ peersUIs[ui.peersUIId] = ui;
277
+ });
278
+ }
279
+ const bundleFunction = new Function('exportUIs', bundleCode);
280
+ await bundleFunction(exportUIs);
241
281
  }
242
- const bundleFunction = new Function('exportUIs', bundleCode);
243
- await bundleFunction(exportUIs);
282
+ console.log(`finished loading ui bundle for ${pkg.name}: ${(Date.now() - sTime).toFixed(0)}ms, ${(bundleCode.length/1000).toFixed(0)} KB`);
244
283
  }
245
284
  resolve();
246
285
  } catch (err) {