react-native-impeller-platform 0.1.0 → 0.3.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.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-impeller-platform",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Out-of-tree React Native platform rendered with Flutter's Impeller engine",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"url": "git+https://github.com/blbaker/react-native-impeller-platform.git",
|
|
9
9
|
"directory": "package"
|
|
10
10
|
},
|
|
11
|
-
"homepage": "https://github.
|
|
11
|
+
"homepage": "https://blbaker.github.io/react-native-impeller-platform/",
|
|
12
12
|
"bugs": {
|
|
13
13
|
"url": "https://github.com/blbaker/react-native-impeller-platform/issues"
|
|
14
14
|
},
|
|
@@ -41,9 +41,9 @@
|
|
|
41
41
|
"react-native": ">=0.86.0"
|
|
42
42
|
},
|
|
43
43
|
"optionalDependencies": {
|
|
44
|
-
"@blbaker/react-native-impeller-platform-engine-darwin-arm64": "0.1
|
|
45
|
-
"@blbaker/react-native-impeller-platform-engine-linux-x64": "0.1
|
|
46
|
-
"@blbaker/react-native-impeller-platform-engine-win32-x64": "0.1
|
|
44
|
+
"@blbaker/react-native-impeller-platform-engine-darwin-arm64": "0.3.1",
|
|
45
|
+
"@blbaker/react-native-impeller-platform-engine-linux-x64": "0.3.1",
|
|
46
|
+
"@blbaker/react-native-impeller-platform-engine-win32-x64": "0.3.1"
|
|
47
47
|
},
|
|
48
48
|
"publishConfig": {
|
|
49
49
|
"access": "public"
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Types for react-native-impeller-platform/src/notifications.
|
|
2
|
+
|
|
3
|
+
export type PermissionStatus = 'granted' | 'denied' | 'unavailable' | 'error';
|
|
4
|
+
export type ShowStatus = 'shown' | 'denied' | 'unavailable' | 'error';
|
|
5
|
+
|
|
6
|
+
export interface PermissionResult {
|
|
7
|
+
status: PermissionStatus;
|
|
8
|
+
/** Present when status is not 'granted'. */
|
|
9
|
+
reason?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface ShowOptions<Data = unknown> {
|
|
13
|
+
title: string;
|
|
14
|
+
body?: string;
|
|
15
|
+
/** Showing an id that is already on screen replaces it. Generated when omitted. */
|
|
16
|
+
id?: string;
|
|
17
|
+
/** Any JSON-serialisable value. It comes back unchanged in the press event. */
|
|
18
|
+
data?: Data;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface ShowResult {
|
|
22
|
+
status: ShowStatus;
|
|
23
|
+
id: string;
|
|
24
|
+
reason?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface PressEvent<Data = unknown> {
|
|
28
|
+
id: string;
|
|
29
|
+
/** 'default': the user clicked the notification. */
|
|
30
|
+
action: string;
|
|
31
|
+
data: Data | null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface Subscription {
|
|
35
|
+
remove(): void;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const PRESS_EVENT: 'rniNotificationPress';
|
|
39
|
+
|
|
40
|
+
export function requestPermission(): Promise<PermissionResult>;
|
|
41
|
+
export function show<Data = unknown>(options: ShowOptions<Data>): Promise<ShowResult>;
|
|
42
|
+
export function onPress<Data = unknown>(
|
|
43
|
+
listener: (event: PressEvent<Data>) => void,
|
|
44
|
+
): Subscription;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// Desktop notifications, the JS half of the engine's Notifications module.
|
|
3
|
+
//
|
|
4
|
+
// requestPermission() -> Promise<{status, reason?}>
|
|
5
|
+
// show({title, body, id, data}) -> Promise<{status, id, reason?}>
|
|
6
|
+
// onPress(listener) -> {remove()}; listener gets {id, data, action}
|
|
7
|
+
//
|
|
8
|
+
// The engine owns the OS call (freedesktop D-Bus on Linux,
|
|
9
|
+
// UNUserNotificationCenter on macOS, toast notifications on Windows). This
|
|
10
|
+
// file owns the shape: argument checks, the JSON encoding of `data`, and the
|
|
11
|
+
// subscription. `data` goes to native as a JSON string and comes back on press
|
|
12
|
+
// unchanged, so native never has to understand it.
|
|
13
|
+
//
|
|
14
|
+
// Nothing here throws for a missing capability. An engine without the module
|
|
15
|
+
// (built before it existed, or running on a platform with no backend) answers
|
|
16
|
+
// {status: 'unavailable', reason}, the same answer the engine gives when the
|
|
17
|
+
// OS service is missing. Bad arguments are programmer errors and reject.
|
|
18
|
+
|
|
19
|
+
const {DeviceEventEmitter, TurboModuleRegistry} = require('react-native');
|
|
20
|
+
|
|
21
|
+
// get, not getEnforcing: a missing module must fail this feature, not the
|
|
22
|
+
// whole bundle at import time.
|
|
23
|
+
const Native = TurboModuleRegistry.get('Notifications');
|
|
24
|
+
|
|
25
|
+
// Emitted by the engine (ReactHost.cpp) when the user clicks a notification
|
|
26
|
+
// this app showed.
|
|
27
|
+
const PRESS_EVENT = 'rniNotificationPress';
|
|
28
|
+
|
|
29
|
+
const MISSING_REASON =
|
|
30
|
+
'this engine has no Notifications module (run `rn-impeller --list-modules` to check)';
|
|
31
|
+
|
|
32
|
+
let generated = 0;
|
|
33
|
+
|
|
34
|
+
async function requestPermission() {
|
|
35
|
+
if (Native == null) return {status: 'unavailable', reason: MISSING_REASON};
|
|
36
|
+
return Native.requestPermission();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function checkOptions(options) {
|
|
40
|
+
if (options == null || typeof options !== 'object') {
|
|
41
|
+
throw new TypeError('show() wants an options object {title, body, id, data}');
|
|
42
|
+
}
|
|
43
|
+
const {title, body = '', id} = options;
|
|
44
|
+
if (typeof title !== 'string' || title.length === 0) {
|
|
45
|
+
throw new TypeError('show(): title must be a non-empty string');
|
|
46
|
+
}
|
|
47
|
+
if (typeof body !== 'string') {
|
|
48
|
+
throw new TypeError('show(): body must be a string');
|
|
49
|
+
}
|
|
50
|
+
if (id != null && (typeof id !== 'string' || id.length === 0)) {
|
|
51
|
+
throw new TypeError('show(): id must be a non-empty string when given');
|
|
52
|
+
}
|
|
53
|
+
let dataJson;
|
|
54
|
+
try {
|
|
55
|
+
dataJson = JSON.stringify(options.data === undefined ? null : options.data);
|
|
56
|
+
} catch (error) {
|
|
57
|
+
throw new TypeError('show(): data must be JSON-serialisable: ' + error.message);
|
|
58
|
+
}
|
|
59
|
+
if (dataJson === undefined) {
|
|
60
|
+
// JSON.stringify returns undefined for a function or a symbol.
|
|
61
|
+
throw new TypeError('show(): data must be JSON-serialisable');
|
|
62
|
+
}
|
|
63
|
+
generated += 1;
|
|
64
|
+
return {title, body, id: id == null ? `rni-${Date.now()}-${generated}` : id, dataJson};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Showing an id that is already on screen replaces that notification.
|
|
68
|
+
async function show(options) {
|
|
69
|
+
const {title, body, id, dataJson} = checkOptions(options);
|
|
70
|
+
if (Native == null) return {status: 'unavailable', id, reason: MISSING_REASON};
|
|
71
|
+
const result = await Native.show(title, body, id, dataJson);
|
|
72
|
+
return {...result, id};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function decodeData(raw) {
|
|
76
|
+
if (typeof raw !== 'string') return null;
|
|
77
|
+
try {
|
|
78
|
+
return JSON.parse(raw);
|
|
79
|
+
} catch (error) {
|
|
80
|
+
// Native echoes exactly what show() encoded, so this only happens for a
|
|
81
|
+
// payload that did not come from this file. Report it as no data.
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function onPress(listener) {
|
|
87
|
+
if (typeof listener !== 'function') {
|
|
88
|
+
throw new TypeError('onPress() wants a function');
|
|
89
|
+
}
|
|
90
|
+
return DeviceEventEmitter.addListener(PRESS_EVENT, event => {
|
|
91
|
+
listener({id: event.id, action: event.action, data: decodeData(event.data)});
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
module.exports = {requestPermission, show, onPress, PRESS_EVENT};
|