@ng-native/expo 0.0.1 → 0.1.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.
Files changed (156) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +413 -1
  3. package/dist/app-info.d.ts +58 -0
  4. package/dist/app-info.js +71 -0
  5. package/dist/app-info.js.map +1 -0
  6. package/dist/apple-sign-in-button.d.ts +16 -0
  7. package/dist/apple-sign-in-button.js +55 -0
  8. package/dist/apple-sign-in-button.js.map +1 -0
  9. package/dist/apple-sign-in.d.ts +68 -0
  10. package/dist/apple-sign-in.js +120 -0
  11. package/dist/apple-sign-in.js.map +1 -0
  12. package/dist/assets.d.ts +24 -0
  13. package/dist/assets.js +47 -0
  14. package/dist/assets.js.map +1 -0
  15. package/dist/background-task.d.ts +66 -0
  16. package/dist/background-task.js +82 -0
  17. package/dist/background-task.js.map +1 -0
  18. package/dist/battery.d.ts +46 -0
  19. package/dist/battery.js +76 -0
  20. package/dist/battery.js.map +1 -0
  21. package/dist/biometrics.d.ts +45 -0
  22. package/dist/biometrics.js +53 -0
  23. package/dist/biometrics.js.map +1 -0
  24. package/dist/brightness.d.ts +38 -0
  25. package/dist/brightness.js +81 -0
  26. package/dist/brightness.js.map +1 -0
  27. package/dist/browser.d.ts +42 -0
  28. package/dist/browser.js +42 -0
  29. package/dist/browser.js.map +1 -0
  30. package/dist/camera.d.ts +48 -0
  31. package/dist/camera.js +59 -0
  32. package/dist/camera.js.map +1 -0
  33. package/dist/clipboard.d.ts +43 -0
  34. package/dist/clipboard.js +60 -0
  35. package/dist/clipboard.js.map +1 -0
  36. package/dist/community-views.d.ts +14 -0
  37. package/dist/community-views.js +76 -0
  38. package/dist/community-views.js.map +1 -0
  39. package/dist/crypto.d.ts +56 -0
  40. package/dist/crypto.js +84 -0
  41. package/dist/crypto.js.map +1 -0
  42. package/dist/database.d.ts +47 -0
  43. package/dist/database.js +108 -0
  44. package/dist/database.js.map +1 -0
  45. package/dist/document-picker.d.ts +34 -0
  46. package/dist/document-picker.js +40 -0
  47. package/dist/document-picker.js.map +1 -0
  48. package/dist/dom-component.d.ts +87 -0
  49. package/dist/dom-component.js +139 -0
  50. package/dist/dom-component.js.map +1 -0
  51. package/dist/expo-image.d.ts +33 -0
  52. package/dist/expo-image.js +57 -0
  53. package/dist/expo-image.js.map +1 -0
  54. package/dist/expo-ui-components.d.ts +327 -0
  55. package/dist/expo-ui-components.js +707 -0
  56. package/dist/expo-ui-components.js.map +1 -0
  57. package/dist/expo-ui.d.ts +46 -0
  58. package/dist/expo-ui.js +128 -0
  59. package/dist/expo-ui.js.map +1 -0
  60. package/dist/file-system.d.ts +63 -0
  61. package/dist/file-system.js +67 -0
  62. package/dist/file-system.js.map +1 -0
  63. package/dist/fonts.d.ts +90 -0
  64. package/dist/fonts.js +118 -0
  65. package/dist/fonts.js.map +1 -0
  66. package/dist/glass.d.ts +33 -0
  67. package/dist/glass.js +72 -0
  68. package/dist/glass.js.map +1 -0
  69. package/dist/haptics.d.ts +49 -0
  70. package/dist/haptics.js +64 -0
  71. package/dist/haptics.js.map +1 -0
  72. package/dist/image-editor.d.ts +62 -0
  73. package/dist/image-editor.js +101 -0
  74. package/dist/image-editor.js.map +1 -0
  75. package/dist/image-picker.d.ts +49 -0
  76. package/dist/image-picker.js +58 -0
  77. package/dist/image-picker.js.map +1 -0
  78. package/dist/index.d.ts +20 -0
  79. package/dist/index.js +21 -0
  80. package/dist/index.js.map +1 -0
  81. package/dist/keep-awake.d.ts +39 -0
  82. package/dist/keep-awake.js +80 -0
  83. package/dist/keep-awake.js.map +1 -0
  84. package/dist/language-model.d.ts +129 -0
  85. package/dist/language-model.js +225 -0
  86. package/dist/language-model.js.map +1 -0
  87. package/dist/locale.d.ts +51 -0
  88. package/dist/locale.js +78 -0
  89. package/dist/locale.js.map +1 -0
  90. package/dist/location.d.ts +68 -0
  91. package/dist/location.js +83 -0
  92. package/dist/location.js.map +1 -0
  93. package/dist/map-view.d.ts +203 -0
  94. package/dist/map-view.js +184 -0
  95. package/dist/map-view.js.map +1 -0
  96. package/dist/media-library.d.ts +103 -0
  97. package/dist/media-library.js +160 -0
  98. package/dist/media-library.js.map +1 -0
  99. package/dist/native-state.d.ts +22 -0
  100. package/dist/native-state.js +43 -0
  101. package/dist/native-state.js.map +1 -0
  102. package/dist/native.d.ts +42 -0
  103. package/dist/native.js +73 -0
  104. package/dist/native.js.map +1 -0
  105. package/dist/network.d.ts +35 -0
  106. package/dist/network.js +60 -0
  107. package/dist/network.js.map +1 -0
  108. package/dist/notifications.d.ts +175 -0
  109. package/dist/notifications.js +296 -0
  110. package/dist/notifications.js.map +1 -0
  111. package/dist/observed.d.ts +37 -0
  112. package/dist/observed.js +55 -0
  113. package/dist/observed.js.map +1 -0
  114. package/dist/orientation.d.ts +35 -0
  115. package/dist/orientation.js +78 -0
  116. package/dist/orientation.js.map +1 -0
  117. package/dist/permissions.d.ts +54 -0
  118. package/dist/permissions.js +72 -0
  119. package/dist/permissions.js.map +1 -0
  120. package/dist/player.d.ts +92 -0
  121. package/dist/player.js +141 -0
  122. package/dist/player.js.map +1 -0
  123. package/dist/register-expo-view.d.ts +55 -0
  124. package/dist/register-expo-view.js +110 -0
  125. package/dist/register-expo-view.js.map +1 -0
  126. package/dist/screen-capture.d.ts +58 -0
  127. package/dist/screen-capture.js +78 -0
  128. package/dist/screen-capture.js.map +1 -0
  129. package/dist/segmented-control.d.ts +32 -0
  130. package/dist/segmented-control.js +55 -0
  131. package/dist/segmented-control.js.map +1 -0
  132. package/dist/sensors.d.ts +85 -0
  133. package/dist/sensors.js +115 -0
  134. package/dist/sensors.js.map +1 -0
  135. package/dist/splash-screen.d.ts +73 -0
  136. package/dist/splash-screen.js +115 -0
  137. package/dist/splash-screen.js.map +1 -0
  138. package/dist/store-review.d.ts +43 -0
  139. package/dist/store-review.js +52 -0
  140. package/dist/store-review.js.map +1 -0
  141. package/dist/store.d.ts +108 -0
  142. package/dist/store.js +247 -0
  143. package/dist/store.js.map +1 -0
  144. package/dist/symbol.d.ts +36 -0
  145. package/dist/symbol.js +69 -0
  146. package/dist/symbol.js.map +1 -0
  147. package/dist/tracking.d.ts +45 -0
  148. package/dist/tracking.js +54 -0
  149. package/dist/tracking.js.map +1 -0
  150. package/dist/transforms.d.ts +2 -0
  151. package/dist/transforms.js +13 -0
  152. package/dist/transforms.js.map +1 -0
  153. package/dist/updates.d.ts +61 -0
  154. package/dist/updates.js +97 -0
  155. package/dist/updates.js.map +1 -0
  156. package/package.json +397 -3
package/dist/native.js ADDED
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Reaching an Expo module without importing one.
3
+ *
4
+ * A static `import ... from 'expo-battery'` makes the file unloadable by Node, which is what used
5
+ * to force every service into two files: the behaviour somewhere the test suite could reach, and
6
+ * the binding somewhere it could not. A `require` inside a function has neither problem. Metro
7
+ * still resolves the string literal at build time, so the module is bundled exactly as before and
8
+ * an app that has not installed it still gets a build error rather than a surprise at runtime;
9
+ * Node never evaluates the call at all, because nothing in a test asks for the real platform.
10
+ *
11
+ * The `catch` is doing two jobs, and only one of them is Node. In an ESM test `require` is not
12
+ * defined, so calling it throws `ReferenceError` and the service goes inert - the same state as
13
+ * a device that has no such sensor. On a device the throw is a module that is present but not
14
+ * linked, which is the same answer for the same reason.
15
+ */
16
+ export function optional(load) {
17
+ try {
18
+ return load();
19
+ }
20
+ catch {
21
+ return null;
22
+ }
23
+ }
24
+ /**
25
+ * A module the app needs and does not have: the package is not installed, or it is and the app was
26
+ * not rebuilt since, so its native half is not in the binary. Development builds and Expo Go carry
27
+ * only the native modules they were built with.
28
+ */
29
+ export class MissingModuleError extends Error {
30
+ name = 'MissingModuleError';
31
+ /** The package, as it is installed: `expo-haptics`. */
32
+ module;
33
+ constructor(module, platform, cause) {
34
+ super(platform === 'web'
35
+ ? `${module} is not installed. Install it with "npx expo install ${module}", then restart the dev server.`
36
+ : `${module} is not in this build of the app. Install it with "npx expo install ${module}", ` +
37
+ `then rebuild the app ("npx expo run:${platform}", or a new EAS build): a development ` +
38
+ `build, and Expo Go, contain only the native modules they were built with.`, { cause });
39
+ this.module = module;
40
+ }
41
+ }
42
+ /** The platform the app is running on, or null in Node, where there is none to ask. */
43
+ function currentPlatform() {
44
+ return optional(() => require('react-native').Platform.OS);
45
+ }
46
+ /**
47
+ * The Expo module a service needs.
48
+ *
49
+ * Where the module exists for the platform the app is on, a module that is missing is a mistake
50
+ * the developer can fix, so this throws a `MissingModuleError` that says how - rather than leave a
51
+ * feature that silently does nothing. Anywhere it cannot exist - an iOS-only module on Android, the
52
+ * web, and Node, where a test runs with no platform at all - this answers null, and the service
53
+ * goes inert, as code shared across platforms needs it to.
54
+ *
55
+ * `load` answering null or undefined counts as missing too: `requireOptionalNativeModule` answers
56
+ * null rather than throwing.
57
+ */
58
+ export function expoModule(module, load, platforms = ['ios', 'android']) {
59
+ let failure;
60
+ try {
61
+ const loaded = load();
62
+ if (loaded != null)
63
+ return loaded;
64
+ }
65
+ catch (error) {
66
+ failure = error;
67
+ }
68
+ const platform = currentPlatform();
69
+ if (platform === null || !platforms.includes(platform))
70
+ return null;
71
+ throw new MissingModuleError(module, platform, failure);
72
+ }
73
+ //# sourceMappingURL=native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native.js","sourceRoot":"","sources":["../src/native.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,QAAQ,CAAI,IAAa;IACvC,IAAI,CAAC;QACH,OAAO,IAAI,EAAE,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAKD;;;;GAIG;AACH,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IACzB,IAAI,GAAG,oBAAoB,CAAC;IAC9C,uDAAuD;IAC9C,MAAM,CAAS;IAExB,YAAY,MAAc,EAAE,QAAwB,EAAE,KAAe;QACnE,KAAK,CACH,QAAQ,KAAK,KAAK;YAChB,CAAC,CAAC,GAAG,MAAM,wDAAwD,MAAM,iCAAiC;YAC1G,CAAC,CAAC,GAAG,MAAM,uEAAuE,MAAM,KAAK;gBACzF,uCAAuC,QAAQ,wCAAwC;gBACvF,2EAA2E,EACjF,EAAE,KAAK,EAAE,CACV,CAAC;QACF,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAED,uFAAuF;AACvF,SAAS,eAAe;IACtB,OAAO,QAAQ,CACb,GAAG,EAAE,CAAE,OAAO,CAAC,cAAc,CAAkC,CAAC,QAAQ,CAAC,EAAoB,CAC9F,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,UAAU,CACxB,MAAc,EACd,IAAgC,EAChC,YAAuC,CAAC,KAAK,EAAE,SAAS,CAAC;IAEzD,IAAI,OAAgB,CAAC;IACrB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,EAAE,CAAC;QACtB,IAAI,MAAM,IAAI,IAAI;YAAE,OAAO,MAAM,CAAC;IACpC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,GAAG,KAAK,CAAC;IAClB,CAAC;IACD,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAC;IACnC,IAAI,QAAQ,KAAK,IAAI,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IACpE,MAAM,IAAI,kBAAkB,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;AAC1D,CAAC","sourcesContent":["/**\n * Reaching an Expo module without importing one.\n *\n * A static `import ... from 'expo-battery'` makes the file unloadable by Node, which is what used\n * to force every service into two files: the behaviour somewhere the test suite could reach, and\n * the binding somewhere it could not. A `require` inside a function has neither problem. Metro\n * still resolves the string literal at build time, so the module is bundled exactly as before and\n * an app that has not installed it still gets a build error rather than a surprise at runtime;\n * Node never evaluates the call at all, because nothing in a test asks for the real platform.\n *\n * The `catch` is doing two jobs, and only one of them is Node. In an ESM test `require` is not\n * defined, so calling it throws `ReferenceError` and the service goes inert - the same state as\n * a device that has no such sensor. On a device the throw is a module that is present but not\n * linked, which is the same answer for the same reason.\n */\nexport function optional<T>(load: () => T): T | null {\n try {\n return load();\n } catch {\n return null;\n }\n}\n\n/** The platforms an Expo module is written for. */\nexport type ModulePlatform = 'ios' | 'android' | 'web';\n\n/**\n * A module the app needs and does not have: the package is not installed, or it is and the app was\n * not rebuilt since, so its native half is not in the binary. Development builds and Expo Go carry\n * only the native modules they were built with.\n */\nexport class MissingModuleError extends Error {\n override readonly name = 'MissingModuleError';\n /** The package, as it is installed: `expo-haptics`. */\n readonly module: string;\n\n constructor(module: string, platform: ModulePlatform, cause?: unknown) {\n super(\n platform === 'web'\n ? `${module} is not installed. Install it with \"npx expo install ${module}\", then restart the dev server.`\n : `${module} is not in this build of the app. Install it with \"npx expo install ${module}\", ` +\n `then rebuild the app (\"npx expo run:${platform}\", or a new EAS build): a development ` +\n `build, and Expo Go, contain only the native modules they were built with.`,\n { cause },\n );\n this.module = module;\n }\n}\n\n/** The platform the app is running on, or null in Node, where there is none to ask. */\nfunction currentPlatform(): ModulePlatform | null {\n return optional(\n () => (require('react-native') as { Platform: { OS: string } }).Platform.OS as ModulePlatform,\n );\n}\n\n/**\n * The Expo module a service needs.\n *\n * Where the module exists for the platform the app is on, a module that is missing is a mistake\n * the developer can fix, so this throws a `MissingModuleError` that says how - rather than leave a\n * feature that silently does nothing. Anywhere it cannot exist - an iOS-only module on Android, the\n * web, and Node, where a test runs with no platform at all - this answers null, and the service\n * goes inert, as code shared across platforms needs it to.\n *\n * `load` answering null or undefined counts as missing too: `requireOptionalNativeModule` answers\n * null rather than throwing.\n */\nexport function expoModule<T>(\n module: string,\n load: () => T | null | undefined,\n platforms: readonly ModulePlatform[] = ['ios', 'android'],\n): T | null {\n let failure: unknown;\n try {\n const loaded = load();\n if (loaded != null) return loaded;\n } catch (error) {\n failure = error;\n }\n const platform = currentPlatform();\n if (platform === null || !platforms.includes(platform)) return null;\n throw new MissingModuleError(module, platform, failure);\n}\n"]}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * `Network`, bound to `expo-network`.
3
+ *
4
+ * Whether the app can reach anything, which is not the same as whether it has a connection. A
5
+ * phone on a captive-portal wifi is connected and reachable by nothing; a phone in a lift has a
6
+ * connection type and no signal. `reachable` is the one worth branching on, and it is the one the
7
+ * platform is least sure about - it stays `null` until something has actually been reached.
8
+ */
9
+ import { InjectionToken, type Signal } from '@angular/core';
10
+ import { type Observed } from './observed.ts';
11
+ import * as i0 from "@angular/core";
12
+ export type ConnectionType = 'wifi' | 'cellular' | 'ethernet' | 'bluetooth' | 'vpn' | 'other' | 'none' | 'unknown';
13
+ export interface NetworkStatus {
14
+ readonly connected: boolean;
15
+ readonly type: ConnectionType;
16
+ /** Null while the platform has not established it, which is not the same as false. */
17
+ readonly reachable: boolean | null;
18
+ }
19
+ export declare const OFFLINE: NetworkStatus;
20
+ export declare class Network {
21
+ /** Overridden in a test to go offline without a network. */
22
+ static readonly SOURCE: InjectionToken<Observed<NetworkStatus> | null>;
23
+ readonly status: Signal<NetworkStatus>;
24
+ /** Whether there is a connection of any kind. Say what you mean: this is not reachability. */
25
+ readonly connected: Signal<boolean>;
26
+ /** What the connection is over, for a screen that offers to wait for wifi. */
27
+ readonly type: Signal<ConnectionType>;
28
+ /**
29
+ * Whether anything has actually been reached. Null until the platform knows, so a screen that
30
+ * shows an offline banner should treat null as "not yet" rather than as offline.
31
+ */
32
+ readonly reachable: Signal<boolean | null>;
33
+ static ɵfac: i0.ɵɵFactoryDeclaration<Network, never>;
34
+ static ɵprov: i0.ɵɵInjectableDeclaration<any>;
35
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * `Network`, bound to `expo-network`.
3
+ *
4
+ * Whether the app can reach anything, which is not the same as whether it has a connection. A
5
+ * phone on a captive-portal wifi is connected and reachable by nothing; a phone in a lift has a
6
+ * connection type and no signal. `reachable` is the one worth branching on, and it is the one the
7
+ * platform is least sure about - it stays `null` until something has actually been reached.
8
+ */
9
+ import { InjectionToken, Service, computed, inject } from '@angular/core';
10
+ import { observed, observedFrom } from "./observed.js";
11
+ import { expoModule } from "./native.js";
12
+ import * as i0 from "@angular/core";
13
+ export const OFFLINE = { connected: false, type: 'unknown', reachable: null };
14
+ const TYPES = {
15
+ NONE: 'none',
16
+ UNKNOWN: 'unknown',
17
+ WIFI: 'wifi',
18
+ CELLULAR: 'cellular',
19
+ BLUETOOTH: 'bluetooth',
20
+ ETHERNET: 'ethernet',
21
+ VPN: 'vpn',
22
+ OTHER: 'other',
23
+ };
24
+ export class Network {
25
+ /** Overridden in a test to go offline without a network. */
26
+ static SOURCE = new InjectionToken('angular-native.networkSource', {
27
+ factory: () => {
28
+ const expo = expoModule('expo-network', () => require('expo-network'));
29
+ if (!expo)
30
+ return null;
31
+ const read = (state) => ({
32
+ connected: state.isConnected ?? false,
33
+ type: TYPES[state.type ?? 'UNKNOWN'] ?? 'unknown',
34
+ // `undefined` means the platform has not established it; `null` is how that is said here,
35
+ // so a consumer cannot confuse "not yet" with "no".
36
+ reachable: state.isInternetReachable ?? null,
37
+ });
38
+ return observedFrom(async () => read(await expo.getNetworkStateAsync()), (listener) => expo.addNetworkStateListener((event) => listener(read(event))));
39
+ },
40
+ });
41
+ status = observed(inject(Network.SOURCE), OFFLINE);
42
+ /** Whether there is a connection of any kind. Say what you mean: this is not reachability. */
43
+ connected = computed(() => this.status().connected, /* @ts-ignore */
44
+ ...(ngDevMode ? [{ debugName: "connected" }] : /* istanbul ignore next */ []));
45
+ /** What the connection is over, for a screen that offers to wait for wifi. */
46
+ type = computed(() => this.status().type, /* @ts-ignore */
47
+ ...(ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []));
48
+ /**
49
+ * Whether anything has actually been reached. Null until the platform knows, so a screen that
50
+ * shows an offline banner should treat null as "not yet" rather than as offline.
51
+ */
52
+ reachable = computed(() => this.status().reachable, /* @ts-ignore */
53
+ ...(ngDevMode ? [{ debugName: "reachable" }] : /* istanbul ignore next */ []));
54
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: Network, deps: [], target: i0.ɵɵFactoryTarget.Service });
55
+ static ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.2.0", ngImport: i0, type: Network });
56
+ }
57
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: Network, decorators: [{
58
+ type: Service
59
+ }] });
60
+ //# sourceMappingURL=network.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"network.js","sourceRoot":"","sources":["../src/network.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAe,MAAM,eAAe,CAAC;AACvF,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAiB,MAAM,eAAe,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;;AAYzC,MAAM,CAAC,MAAM,OAAO,GAAkB,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AAE7F,MAAM,KAAK,GAAmC;IAC5C,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,MAAM;IACZ,QAAQ,EAAE,UAAU;IACpB,SAAS,EAAE,WAAW;IACtB,QAAQ,EAAE,UAAU;IACpB,GAAG,EAAE,KAAK;IACV,KAAK,EAAE,OAAO;CACf,CAAC;AAGF,MAAM,OAAO,OAAO;IAClB,4DAA4D;IAC5D,MAAM,CAAU,MAAM,GAAG,IAAI,cAAc,CACzC,8BAA8B,EAC9B;QACE,OAAO,EAAE,GAAG,EAAE;YACZ,MAAM,IAAI,GAAG,UAAU,CACrB,cAAc,EACd,GAAG,EAAE,CAAC,OAAO,CAAC,cAAc,CAAkC,CAC/D,CAAC;YACF,IAAI,CAAC,IAAI;gBAAE,OAAO,IAAI,CAAC;YAEvB,MAAM,IAAI,GAAG,CACX,KAAqF,EACtE,EAAE,CAAC,CAAC;gBACnB,SAAS,EAAE,KAAK,CAAC,WAAW,IAAI,KAAK;gBACrC,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI,IAAI,SAAS,CAAC,IAAI,SAAS;gBACjD,0FAA0F;gBAC1F,oDAAoD;gBACpD,SAAS,EAAE,KAAK,CAAC,mBAAmB,IAAI,IAAI;aAC7C,CAAC,CAAC;YAEH,OAAO,YAAY,CACjB,KAAK,IAAI,EAAE,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,oBAAoB,EAAE,CAAC,EACnD,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAC7E,CAAC;QACJ,CAAC;KACF,CACF,CAAC;IAEO,MAAM,GAA0B,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC;IAEnF,8FAA8F;IACrF,SAAS,GAAoB,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,SAAS;kFAAC,CAAC;IAE9E,8EAA8E;IACrE,IAAI,GAA2B,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI;6EAAC,CAAC;IAE3E;;;OAGG;IACM,SAAS,GAA2B,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,SAAS;kFAAC,CAAC;uGA1C1E,OAAO;wGAAP,OAAO;;2FAAP,OAAO;kBADnB,OAAO","sourcesContent":["/**\n * `Network`, bound to `expo-network`.\n *\n * Whether the app can reach anything, which is not the same as whether it has a connection. A\n * phone on a captive-portal wifi is connected and reachable by nothing; a phone in a lift has a\n * connection type and no signal. `reachable` is the one worth branching on, and it is the one the\n * platform is least sure about - it stays `null` until something has actually been reached.\n */\nimport { InjectionToken, Service, computed, inject, type Signal } from '@angular/core';\nimport { observed, observedFrom, type Observed } from './observed.ts';\nimport { expoModule } from './native.ts';\n\nexport type ConnectionType =\n 'wifi' | 'cellular' | 'ethernet' | 'bluetooth' | 'vpn' | 'other' | 'none' | 'unknown';\n\nexport interface NetworkStatus {\n readonly connected: boolean;\n readonly type: ConnectionType;\n /** Null while the platform has not established it, which is not the same as false. */\n readonly reachable: boolean | null;\n}\n\nexport const OFFLINE: NetworkStatus = { connected: false, type: 'unknown', reachable: null };\n\nconst TYPES: Record<string, ConnectionType> = {\n NONE: 'none',\n UNKNOWN: 'unknown',\n WIFI: 'wifi',\n CELLULAR: 'cellular',\n BLUETOOTH: 'bluetooth',\n ETHERNET: 'ethernet',\n VPN: 'vpn',\n OTHER: 'other',\n};\n\n@Service()\nexport class Network {\n /** Overridden in a test to go offline without a network. */\n static readonly SOURCE = new InjectionToken<Observed<NetworkStatus> | null>(\n 'angular-native.networkSource',\n {\n factory: () => {\n const expo = expoModule(\n 'expo-network',\n () => require('expo-network') as typeof import('expo-network'),\n );\n if (!expo) return null;\n\n const read = (\n state: import('expo-network').NetworkState | import('expo-network').NetworkStateEvent,\n ): NetworkStatus => ({\n connected: state.isConnected ?? false,\n type: TYPES[state.type ?? 'UNKNOWN'] ?? 'unknown',\n // `undefined` means the platform has not established it; `null` is how that is said here,\n // so a consumer cannot confuse \"not yet\" with \"no\".\n reachable: state.isInternetReachable ?? null,\n });\n\n return observedFrom(\n async () => read(await expo.getNetworkStateAsync()),\n (listener) => expo.addNetworkStateListener((event) => listener(read(event))),\n );\n },\n },\n );\n\n readonly status: Signal<NetworkStatus> = observed(inject(Network.SOURCE), OFFLINE);\n\n /** Whether there is a connection of any kind. Say what you mean: this is not reachability. */\n readonly connected: Signal<boolean> = computed(() => this.status().connected);\n\n /** What the connection is over, for a screen that offers to wait for wifi. */\n readonly type: Signal<ConnectionType> = computed(() => this.status().type);\n\n /**\n * Whether anything has actually been reached. Null until the platform knows, so a screen that\n * shows an offline banner should treat null as \"not yet\" rather than as offline.\n */\n readonly reachable: Signal<boolean | null> = computed(() => this.status().reachable);\n}\n"]}
@@ -0,0 +1,175 @@
1
+ /**
2
+ * `Notifications`, bound to `expo-notifications`: everything the module does, as one injectable
3
+ * service.
4
+ *
5
+ * ```ts
6
+ * import { Notifications, TriggerType } from '@ng-native/expo/notifications';
7
+ *
8
+ * private readonly notifications = inject(Notifications);
9
+ *
10
+ * async remind(): Promise<void> {
11
+ * if (!(await this.notifications.permission.ensure())) return;
12
+ * await this.notifications.schedule({
13
+ * content: { title: 'Time to stretch' },
14
+ * trigger: { type: TriggerType.DAILY, hour: 9, minute: 0 },
15
+ * });
16
+ * }
17
+ *
18
+ * constructor() {
19
+ * const tapped = this.notifications.take();
20
+ * if (tapped) this.router.navigateByUrl(routeFor(tapped));
21
+ * }
22
+ * ```
23
+ *
24
+ * The listeners are the part a hook used to be the only way to reach, and they are signals here.
25
+ * *Received* is a notification arriving while the app is in front; the app usually decides whether
26
+ * to show anything. *Responded* is the user having tapped one, which is a navigation instruction
27
+ * and must not be missed - including the one that launched the app, which arrived before anything
28
+ * was listening.
29
+ *
30
+ * The rest - permission, scheduling, what is on screen, the badge, Android's channels, the action
31
+ * buttons of categories, the foreground handler, push tokens and topics, background tasks - is the
32
+ * module's own functions under shorter names, with its own types. Without the module installed,
33
+ * or in a test that provides nothing, every query answers empty and every change does nothing.
34
+ * The push token methods ask for the permission first, since a token nobody can be shown anything
35
+ * with fails silently: the push simply never arrives.
36
+ */
37
+ import { InjectionToken, type Signal } from '@angular/core';
38
+ import type { DevicePushToken, Notification, NotificationResponse, SchedulableTriggerInputTypes } from 'expo-notifications';
39
+ import { Permission } from './permissions.ts';
40
+ import * as i0 from "@angular/core";
41
+ type Expo = typeof import('expo-notifications');
42
+ /**
43
+ * The module's functions this service calls. The real module is one; a test provides a fake that
44
+ * delivers notifications nobody sent.
45
+ */
46
+ export type NativeNotifications = Pick<Expo, 'addNotificationReceivedListener' | 'addNotificationResponseReceivedListener' | 'addNotificationsDroppedListener' | 'addPushTokenListener' | 'getLastNotificationResponseAsync' | 'clearLastNotificationResponseAsync' | 'getPermissionsAsync' | 'requestPermissionsAsync' | 'scheduleNotificationAsync' | 'cancelScheduledNotificationAsync' | 'cancelAllScheduledNotificationsAsync' | 'getAllScheduledNotificationsAsync' | 'getNextTriggerDateAsync' | 'getPresentedNotificationsAsync' | 'dismissNotificationAsync' | 'dismissAllNotificationsAsync' | 'getBadgeCountAsync' | 'setBadgeCountAsync' | 'getNotificationChannelsAsync' | 'getNotificationChannelAsync' | 'setNotificationChannelAsync' | 'deleteNotificationChannelAsync' | 'getNotificationChannelGroupsAsync' | 'getNotificationChannelGroupAsync' | 'setNotificationChannelGroupAsync' | 'deleteNotificationChannelGroupAsync' | 'getNotificationCategoriesAsync' | 'setNotificationCategoryAsync' | 'deleteNotificationCategoryAsync' | 'setNotificationHandler' | 'getExpoPushTokenAsync' | 'getDevicePushTokenAsync' | 'unregisterForNotificationsAsync' | 'setAutoServerRegistrationEnabledAsync' | 'subscribeToTopicAsync' | 'unsubscribeFromTopicAsync' | 'registerTaskAsync' | 'unregisterTaskAsync'>;
47
+ type Args<K extends keyof NativeNotifications> = Parameters<NativeNotifications[K]>;
48
+ /**
49
+ * The kinds of trigger a schedule takes, as `expo-notifications`' own enum. Importing the enum
50
+ * from the module loads the module, which a test in Node cannot; these are the same strings,
51
+ * typed as the enum, so `{ type: TriggerType.DAILY, hour: 9, minute: 0 }` is accepted either way.
52
+ */
53
+ export declare const TriggerType: typeof SchedulableTriggerInputTypes;
54
+ export declare class Notifications {
55
+ /** Overridden in a test to deliver a notification nobody sent. */
56
+ static readonly SOURCE: InjectionToken<NativeNotifications | null>;
57
+ private readonly native;
58
+ private readonly received;
59
+ private readonly responded;
60
+ private readonly rolled;
61
+ private readonly drops;
62
+ private readonly handled;
63
+ /**
64
+ * The permission to show notifications. `ensure()` asks only if it has not been answered; for
65
+ * iOS's finer options (provisional, critical alerts), use {@link requestPermission}.
66
+ */
67
+ readonly permission: Permission;
68
+ constructor();
69
+ /** The most recent notification that arrived while the app was in front. */
70
+ readonly latest: Signal<Notification | null>;
71
+ /**
72
+ * The most recent notification the user tapped, including the one that launched the app.
73
+ *
74
+ * A router usually wants `take()` instead: this stays set, so a screen that reacts to it will
75
+ * react again every time it is created.
76
+ */
77
+ readonly response: Signal<NotificationResponse | null>;
78
+ /**
79
+ * The response, once.
80
+ *
81
+ * Routing on a tap is a one-off, and the signal is not: an effect on it fires again whenever
82
+ * its component is recreated, which sends the user back to a screen they navigated away from.
83
+ */
84
+ take(): NotificationResponse | null;
85
+ /** Forgets the tap, here and in the module, so the next launch does not see it again. */
86
+ clearResponse(): Promise<void>;
87
+ /** How many times Android has reported notifications dropped. Zero on iOS. */
88
+ readonly dropped: Signal<number>;
89
+ /** Asks with iOS's finer options. The answer also updates {@link permission}. */
90
+ requestPermission(...options: Args<'requestPermissionsAsync'>): Promise<boolean>;
91
+ /** Schedules a local notification, or shows it now with a null trigger. Null without the module. */
92
+ schedule(...request: Args<'scheduleNotificationAsync'>): Promise<string | null>;
93
+ cancel(identifier: string): Promise<void>;
94
+ cancelAll(): Promise<void>;
95
+ /** Every local notification still waiting for its trigger. */
96
+ scheduled(): Promise<Awaited<ReturnType<Expo['getAllScheduledNotificationsAsync']>>>;
97
+ /** When a trigger would next fire, in milliseconds since the epoch; null if it never will. */
98
+ nextTriggerDate(...trigger: Args<'getNextTriggerDateAsync'>): Promise<number | null>;
99
+ /** The notifications in the notification centre that are the app's. */
100
+ presented(): Promise<Notification[]>;
101
+ dismiss(identifier: string): Promise<void>;
102
+ /** Clears every notification the app has on screen. A failure is ignored. */
103
+ dismissAll(): void;
104
+ badge(): Promise<number>;
105
+ /**
106
+ * iOS shows this on the icon; Android shows it where the launcher supports it. A failure is
107
+ * ignored.
108
+ */
109
+ setBadge(count: number): void;
110
+ /** Android's notification channels. Empty on iOS, which has none. */
111
+ channels(): Promise<Awaited<ReturnType<Expo['getNotificationChannelsAsync']>>>;
112
+ channel(identifier: string): Promise<Awaited<ReturnType<Expo['getNotificationChannelAsync']>>>;
113
+ /**
114
+ * Creates or updates an Android channel; a notification on Android 8 and later needs one to
115
+ * show at all. Null on iOS.
116
+ */
117
+ setChannel(...channel: Args<'setNotificationChannelAsync'>): Promise<Awaited<ReturnType<Expo['setNotificationChannelAsync']>>>;
118
+ deleteChannel(identifier: string): Promise<void>;
119
+ channelGroups(): Promise<Awaited<ReturnType<Expo['getNotificationChannelGroupsAsync']>>>;
120
+ channelGroup(identifier: string): Promise<Awaited<ReturnType<Expo['getNotificationChannelGroupAsync']>>>;
121
+ setChannelGroup(...group: Args<'setNotificationChannelGroupAsync'>): Promise<Awaited<ReturnType<Expo['setNotificationChannelGroupAsync']>>>;
122
+ deleteChannelGroup(identifier: string): Promise<void>;
123
+ /** The categories set: each a set of action buttons a notification opts into. */
124
+ categories(): Promise<Awaited<ReturnType<Expo['getNotificationCategoriesAsync']>>>;
125
+ /**
126
+ * Action buttons for notifications whose content names this category. A tap on one arrives as
127
+ * a response with the button's identifier, and the typed text as `userText` for a text input.
128
+ */
129
+ setCategory(...category: Args<'setNotificationCategoryAsync'>): Promise<Awaited<ReturnType<Expo['setNotificationCategoryAsync']>> | null>;
130
+ deleteCategory(identifier: string): Promise<boolean>;
131
+ /**
132
+ * What a notification that arrives while the app is in front does: shown, silent, with a sound
133
+ * or a badge. Without a handler, it is not shown. Null removes the handler.
134
+ */
135
+ setHandler(...handler: Args<'setNotificationHandler'>): void;
136
+ /**
137
+ * The token to hand a backend so it can send a push through Expo's service.
138
+ *
139
+ * Asks for the notification permission first - a token nobody can be shown anything with is not
140
+ * worth having. `projectId` defaults to the app's own EAS project; pass it explicitly for a bare
141
+ * workflow app, one still without EAS Build configured, or a token fetched outside
142
+ * `expo-notifications`' default resolution. Null without the permission or without the module.
143
+ */
144
+ getExpoPushToken(projectId?: string): Promise<string | null>;
145
+ /**
146
+ * The raw APNs (iOS) or FCM (Android) token, for a backend that talks to those services
147
+ * directly rather than through Expo's push service. Same permission and module rules as
148
+ * {@link getExpoPushToken}.
149
+ */
150
+ getDevicePushToken(): Promise<DevicePushToken | null>;
151
+ /**
152
+ * The device push token, each time the platform rolls it while the app is running.
153
+ *
154
+ * A rolled token is not the one a backend has on file, and sending to the old one fails
155
+ * silently - this is what tells an app to register the new one. Unset until a roll happens;
156
+ * most of an app's life this stays null.
157
+ */
158
+ readonly devicePushToken: Signal<DevicePushToken | null>;
159
+ /** Stops the device receiving pushes until a token is asked for again. */
160
+ unregister(): Promise<void>;
161
+ /** Whether Expo re-registers the device token with its push service by itself. */
162
+ setAutoServerRegistration(enabled: boolean): Promise<void>;
163
+ /** Android: receive pushes sent to an FCM topic. */
164
+ subscribeToTopic(topic: string): Promise<void>;
165
+ unsubscribeFromTopic(topic: string): Promise<void>;
166
+ /**
167
+ * Runs a task defined with `expo-task-manager` when a notification arrives in the background.
168
+ * The task itself is defined at the top level of `main.ts`, since it runs without the app.
169
+ */
170
+ registerTask(name: string): Promise<void>;
171
+ unregisterTask(name: string): Promise<void>;
172
+ static ɵfac: i0.ɵɵFactoryDeclaration<Notifications, never>;
173
+ static ɵprov: i0.ɵɵInjectableDeclaration<any>;
174
+ }
175
+ export {};