@robono/messaging-react-native 0.1.0 → 0.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/CHANGELOG.md +65 -0
- package/README.md +160 -8
- package/SBOM.spdx.json +1985 -209
- package/dist/account.d.ts +15 -0
- package/dist/account.js +27 -0
- package/dist/call-message.js +7 -1
- package/dist/calling.js +5 -9
- package/dist/conversation-details.d.ts +24 -0
- package/dist/conversation-details.js +83 -0
- package/dist/emoji-text.d.ts +2 -0
- package/dist/emoji-text.js +8 -0
- package/dist/expo-download.d.ts +3 -0
- package/dist/expo-download.js +43 -0
- package/dist/expo-history.d.ts +3 -0
- package/dist/expo-history.js +59 -0
- package/dist/expo-media.d.ts +1 -0
- package/dist/expo-media.js +69 -43
- package/dist/expo-messenger.d.ts +35 -0
- package/dist/expo-messenger.js +39 -0
- package/dist/expo-notifications.d.ts +31 -0
- package/dist/expo-notifications.js +92 -0
- package/dist/expo-outbox.d.ts +13 -0
- package/dist/expo-outbox.js +82 -0
- package/dist/expo-privacy.d.ts +4 -0
- package/dist/expo-privacy.js +7 -0
- package/dist/expo-saved.d.ts +24 -0
- package/dist/expo-saved.js +76 -0
- package/dist/expo-screen.d.ts +42 -0
- package/dist/expo-screen.js +557 -0
- package/dist/expo-social.d.ts +3 -0
- package/dist/expo-social.js +21 -0
- package/dist/expo-thumbnails.d.ts +9 -0
- package/dist/expo-thumbnails.js +68 -0
- package/dist/expo.d.ts +2 -36
- package/dist/expo.js +2 -429
- package/dist/extras-lifecycle.d.ts +2 -0
- package/dist/extras-lifecycle.js +27 -0
- package/dist/extras.d.ts +49 -0
- package/dist/extras.js +49 -0
- package/dist/forward.d.ts +13 -0
- package/dist/forward.js +62 -0
- package/dist/group-editor.d.ts +18 -0
- package/dist/group-editor.js +98 -0
- package/dist/header-calls.d.ts +18 -0
- package/dist/header-calls.js +45 -0
- package/dist/icons.d.ts +1 -1
- package/dist/inbox-search.d.ts +11 -0
- package/dist/inbox-search.js +42 -0
- package/dist/inbox.d.ts +19 -0
- package/dist/inbox.js +52 -0
- package/dist/index.d.ts +76 -3
- package/dist/index.js +648 -167
- package/dist/media-controller.d.ts +21 -0
- package/dist/media-controller.js +157 -3
- package/dist/media-readiness.d.ts +1 -1
- package/dist/media-ui.d.ts +27 -5
- package/dist/media-ui.js +95 -29
- package/dist/message-links.d.ts +5 -0
- package/dist/message-links.js +30 -0
- package/dist/message-menu.d.ts +28 -0
- package/dist/message-menu.js +24 -0
- package/dist/message-order.d.ts +7 -0
- package/dist/message-order.js +27 -0
- package/dist/messenger-video-view.d.ts +8 -0
- package/dist/messenger-video-view.js +46 -0
- package/dist/native-outbox.d.ts +55 -0
- package/dist/native-outbox.js +53 -0
- package/dist/photo-gesture.d.ts +20 -0
- package/dist/photo-gesture.js +52 -0
- package/dist/pollVoteQueue.d.ts +3 -0
- package/dist/pollVoteQueue.js +29 -0
- package/dist/polls.d.ts +7 -2
- package/dist/polls.js +89 -20
- package/dist/popup.d.ts +51 -0
- package/dist/popup.js +73 -0
- package/dist/quick-send.d.ts +15 -0
- package/dist/quick-send.js +26 -0
- package/dist/recent-media.js +1 -0
- package/dist/safety.d.ts +10 -1
- package/dist/safety.js +29 -8
- package/dist/saved.d.ts +10 -0
- package/dist/saved.js +51 -0
- package/dist/search.d.ts +9 -0
- package/dist/search.js +59 -0
- package/dist/social.d.ts +25 -0
- package/dist/social.js +31 -0
- package/dist/translation-settings.d.ts +12 -0
- package/dist/translation-settings.js +16 -0
- package/dist/use-quote-gesture.d.ts +5 -1
- package/dist/use-quote-gesture.js +35 -17
- package/dist/visual/RobonoIcon.js +2 -1
- package/dist/visual/WeatherArtwork.d.ts +9 -0
- package/dist/visual/WeatherArtwork.js +43 -0
- package/dist/visual/weather-artwork.d.ts +17 -0
- package/dist/visual/weather-artwork.js +86 -0
- package/dist/visual/weather-conditions.d.ts +5 -0
- package/dist/visual/weather-conditions.js +2 -0
- package/dist/voice-composer.js +2 -2
- package/dist/voice-waveform.d.ts +2 -0
- package/dist/voice-waveform.js +21 -0
- package/package.json +41 -5
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
// Generated by scripts/design/generate-icons.mjs from the approved Robono artwork.
|
|
3
3
|
import React, { useId } from 'react';
|
|
4
|
+
import { Platform } from 'react-native';
|
|
4
5
|
import Svg, { Path, Circle, Rect, Ellipse, Line, G, Defs, Mask } from 'react-native-svg';
|
|
5
6
|
import { iconPaths } from './icon-paths.js';
|
|
6
7
|
import { iconNodes, iconNames } from './icon-nodes.js';
|
|
@@ -14,7 +15,7 @@ function draw(node, index, prefix, color) {
|
|
|
14
15
|
}
|
|
15
16
|
export function RobonoIcon({ name, size = 24, color = '#F7F7F7', ...props }) {
|
|
16
17
|
const prefix = 'robono' + useId().replace(/[^a-zA-Z0-9]/g, '') + '-';
|
|
17
|
-
return _jsx(Svg, { width: size, height: size, viewBox: "0 0 32 32", color: color, accessible: false, ...props, children: iconNodes[iconNames[name]]?.map((node, i) => draw(node, i, prefix, color)) });
|
|
18
|
+
return _jsx(Svg, { width: size, height: size, viewBox: "0 0 32 32", color: color, ...(Platform.OS === 'web' ? { 'aria-hidden': true } : { accessible: false }), ...props, children: iconNodes[iconNames[name]]?.map((node, i) => draw(node, i, prefix, color)) });
|
|
18
19
|
}
|
|
19
20
|
RobonoIcon.glyphMap = iconPaths;
|
|
20
21
|
export default RobonoIcon;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
/** Original conventional artwork, composed from conditions; identical on iOS and Android. */
|
|
3
|
+
export default function WeatherArtwork({ code, isDay, cloud, windKph, size }: {
|
|
4
|
+
code?: number;
|
|
5
|
+
isDay?: boolean;
|
|
6
|
+
cloud?: number | null;
|
|
7
|
+
windKph?: number | null;
|
|
8
|
+
size?: number;
|
|
9
|
+
}): React.JSX.Element;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import Svg, { Circle, G, Path } from "react-native-svg";
|
|
3
|
+
import { weatherScene } from "./weather-artwork.js";
|
|
4
|
+
const ink = "#52677f", blue = "#2674bd", amber = "#b86a08";
|
|
5
|
+
function Sun() {
|
|
6
|
+
return _jsxs(G, { stroke: amber, strokeWidth: 3.5, strokeLinecap: "round", children: [_jsx(Circle, { cx: 32, cy: 32, r: 13, fill: "#df9b36" }), _jsx(Path, { d: "M32 5v7M32 52v7M5 32h7M52 32h7M13 13l5 5M46 46l5 5M13 51l5-5M46 18l5-5" })] });
|
|
7
|
+
}
|
|
8
|
+
function Moon() {
|
|
9
|
+
return _jsx(Path, { d: "M43 9C20 6 8 26 17 43c8 16 31 17 41 0-20 6-35-16-15-34Z", fill: "#9ba7c7", stroke: "#59698f", strokeWidth: 3.5, strokeLinejoin: "round" });
|
|
10
|
+
}
|
|
11
|
+
function Cloud({ dark = false }) {
|
|
12
|
+
return _jsx(Path, { d: "M14 46C0 44 1 26 15 25c1-19 28-22 34-3 17-1 20 24 3 24Z", fill: dark ? "#8594a6" : "#dce4ec", stroke: ink, strokeWidth: 3.5, strokeLinejoin: "round" });
|
|
13
|
+
}
|
|
14
|
+
function Wind() {
|
|
15
|
+
return _jsx(G, { fill: "none", stroke: ink, strokeWidth: 4, strokeLinecap: "round", children: _jsx(Path, { d: "M5 24h31c14 0 14-19 3-19-6 0-9 5-8 9M9 35h42c13 0 13 21 1 21-6 0-9-4-9-8M3 46h23" }) });
|
|
16
|
+
}
|
|
17
|
+
function Flake({ x, y, size = 10 }) {
|
|
18
|
+
return _jsx(G, { transform: `translate(${x} ${y}) scale(${size / 10})`, stroke: blue, strokeWidth: 2.8, strokeLinecap: "round", children: _jsx(Path, { d: "M0-9V9M-8-4.5l16 9M-8 4.5l16-9" }) });
|
|
19
|
+
}
|
|
20
|
+
function Drop({ x, y, small = false }) {
|
|
21
|
+
return _jsx(Path, { transform: `translate(${x} ${y}) scale(${small ? .65 : 1})`, d: "M0-9C-2-5-6 0-6 3a6 6 0 0 0 12 0C6 0 2-5 0-9Z", fill: blue });
|
|
22
|
+
}
|
|
23
|
+
/** Original conventional artwork, composed from conditions; identical on iOS and Android. */
|
|
24
|
+
export default function WeatherArtwork({ code, isDay = true, cloud, windKph, size = 32 }) {
|
|
25
|
+
const scene = weatherScene(code, cloud, windKph);
|
|
26
|
+
if (!scene)
|
|
27
|
+
return _jsxs(Svg, { width: size, height: size, viewBox: "0 0 64 64", accessible: false, children: [_jsx(Circle, { cx: 32, cy: 32, r: 23, fill: "none", stroke: ink, strokeWidth: 4 }), _jsx(Path, { d: "M22 32h20", stroke: ink, strokeWidth: 4, strokeLinecap: "round" })] });
|
|
28
|
+
const detail = !!(scene.precipitation || scene.atmosphere || scene.windy || scene.thunder || scene.freezing);
|
|
29
|
+
const hasSky = scene.sky !== "none";
|
|
30
|
+
const precipitation = scene.precipitation;
|
|
31
|
+
const count = scene.intensity === 3 ? 3 : 2;
|
|
32
|
+
const mixed = precipitation === "sleet";
|
|
33
|
+
const particles = Array.from({ length: count }, (_, i) => {
|
|
34
|
+
const x = count === 3 ? 12 + i * 20 : 18 + i * 28;
|
|
35
|
+
const y = count === 3 && i === 1 ? 42 : 49;
|
|
36
|
+
if (precipitation === "snow" || (mixed && i === 1))
|
|
37
|
+
return _jsx(Flake, { x: x, y: y, size: count === 3 ? 8 : 10 }, i);
|
|
38
|
+
if (precipitation === "ice")
|
|
39
|
+
return _jsx(Path, { d: `M${x} ${y - 7}l7 7-7 7-7-7Z`, fill: "#cce7f3", stroke: blue, strokeWidth: 3 }, i);
|
|
40
|
+
return _jsx(Drop, { x: x, y: y, small: precipitation === "drizzle" }, i);
|
|
41
|
+
});
|
|
42
|
+
return _jsxs(Svg, { width: size, height: size, viewBox: "0 0 64 64", accessible: false, children: [(scene.sky === "clear" || scene.sky === "partial") && _jsx(G, { transform: detail || scene.sky === "partial" ? "translate(0 -1) scale(.68)" : undefined, children: isDay ? _jsx(Sun, {}) : _jsx(Moon, {}) }), (scene.sky === "cloud" || scene.sky === "partial") && _jsx(G, { transform: detail ? "translate(17 0) scale(.72)" : scene.sky === "partial" ? "translate(15 14) scale(.75)" : "translate(1 3) scale(.95)", children: _jsx(Cloud, { dark: scene.intensity === 3 || scene.thunder }) }), scene.windy && _jsx(G, { transform: precipitation || scene.atmosphere ? "translate(0 -1) scale(.63)" : hasSky ? "translate(17 24) scale(.72)" : "translate(0 0)", children: _jsx(Wind, {}) }), precipitation && _jsx(G, { transform: scene.thunder || scene.freezing ? "translate(-1 22) scale(.63)" : !hasSky && !scene.windy ? "translate(0 -10)" : undefined, children: particles }), scene.atmosphere && _jsx(G, { children: ["dust", "sand", "haze"].includes(scene.atmosphere) ? _jsxs(G, { fill: scene.atmosphere === "haze" ? ink : "#996b36", children: [[[8, 43], [20, 51], [32, 39], [44, 52], [56, 41], [32, 59]].map(([x, y], i) => _jsx(Circle, { cx: x, cy: y, r: scene.intensity === 3 ? 3.8 : 2.8 }, i)), !scene.windy && _jsx(Path, { d: "M7 33q12-12 24 0t26 0", fill: "none", stroke: scene.atmosphere === "haze" ? ink : "#996b36", strokeWidth: 3.5, strokeLinecap: "round" })] }) : _jsx(G, { fill: "none", stroke: ink, strokeWidth: scene.intensity === 3 ? 5 : 3.5, strokeLinecap: "round", children: scene.atmosphere === "smoke" || scene.atmosphere === "smog" ? _jsx(Path, { d: "M15 56c-15-18 15-19 4-35M32 57c-14-20 19-23 5-44M49 57c-10-14 14-19 4-31" }) : _jsx(Path, { d: "M7 24h17m8 0h25M4 35h38m8 0h10M9 46h15m8 0h23" }) }) }), scene.freezing && _jsxs(G, { transform: "translate(45 22)", children: [_jsx(Path, { d: "M0-10v17m0-17a3 3 0 0 1 6 0v17a7 7 0 1 1-6 0", fill: "#e1f2fa", stroke: blue, strokeWidth: 2.5 }), _jsx(Path, { d: "M3-5v18", stroke: blue, strokeWidth: 3, strokeLinecap: "round" })] }), scene.thunder && _jsx(Path, { d: "M39 26 29 43h10l-5 18 22-27H44l6-8Z", fill: "#df9b36", stroke: "#925510", strokeWidth: 2.5, strokeLinejoin: "round" })] });
|
|
43
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** WeatherAPI condition codes. Composition uses actual conditions, never rain probability. */
|
|
2
|
+
export type WeatherScene = {
|
|
3
|
+
sky: "clear" | "partial" | "cloud" | "none";
|
|
4
|
+
precipitation?: "rain" | "drizzle" | "snow" | "sleet" | "ice";
|
|
5
|
+
intensity?: 1 | 2 | 3;
|
|
6
|
+
freezing?: boolean;
|
|
7
|
+
thunder?: boolean;
|
|
8
|
+
windy?: boolean;
|
|
9
|
+
atmosphere?: "mist" | "fog" | "haze" | "dust" | "sand" | "smoke" | "smog";
|
|
10
|
+
};
|
|
11
|
+
export declare const WEATHER_SCENES: Record<number, WeatherScene>;
|
|
12
|
+
export declare function weatherScene(code?: number, cloud?: number | null, windKph?: number | null): WeatherScene | null;
|
|
13
|
+
/** One precipitation row. Mixed/ice conditions have no separate provider probability. */
|
|
14
|
+
export declare function precipitationMetric(code: number, rain: number | null, snow: number | null): {
|
|
15
|
+
label: string;
|
|
16
|
+
chance: number | null;
|
|
17
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
export const WEATHER_SCENES = {
|
|
2
|
+
1000: { sky: "clear" }, 1003: { sky: "partial" },
|
|
3
|
+
1006: { sky: "cloud" }, 1009: { sky: "cloud", intensity: 3 },
|
|
4
|
+
1012: { sky: "clear", atmosphere: "haze" },
|
|
5
|
+
1015: { sky: "clear", atmosphere: "dust" },
|
|
6
|
+
1018: { sky: "none", atmosphere: "dust", windy: true },
|
|
7
|
+
1021: { sky: "none", atmosphere: "dust", windy: true, intensity: 3 },
|
|
8
|
+
1024: { sky: "none", atmosphere: "sand", windy: true },
|
|
9
|
+
1027: { sky: "none", atmosphere: "sand", windy: true, intensity: 3 },
|
|
10
|
+
1030: { sky: "none", atmosphere: "mist" },
|
|
11
|
+
1033: { sky: "none", atmosphere: "smoke" },
|
|
12
|
+
1036: { sky: "clear", atmosphere: "smoke" },
|
|
13
|
+
1039: { sky: "none", atmosphere: "smog" },
|
|
14
|
+
1042: { sky: "none", atmosphere: "smog", intensity: 3 },
|
|
15
|
+
1045: { sky: "none", atmosphere: "dust" },
|
|
16
|
+
1048: { sky: "none", atmosphere: "dust" },
|
|
17
|
+
1063: { sky: "clear", precipitation: "rain", intensity: 1 },
|
|
18
|
+
1066: { sky: "clear", precipitation: "snow", intensity: 1 },
|
|
19
|
+
1069: { sky: "clear", precipitation: "sleet", intensity: 1 },
|
|
20
|
+
1072: { sky: "clear", precipitation: "drizzle", freezing: true },
|
|
21
|
+
1087: { sky: "cloud", thunder: true },
|
|
22
|
+
1114: { sky: "none", precipitation: "snow", windy: true },
|
|
23
|
+
1117: { sky: "none", precipitation: "snow", windy: true, intensity: 3 },
|
|
24
|
+
1135: { sky: "none", atmosphere: "fog" },
|
|
25
|
+
1147: { sky: "none", atmosphere: "fog", freezing: true },
|
|
26
|
+
1150: { sky: "clear", precipitation: "drizzle", intensity: 1 },
|
|
27
|
+
1153: { sky: "none", precipitation: "drizzle", intensity: 1 },
|
|
28
|
+
1168: { sky: "none", precipitation: "drizzle", freezing: true },
|
|
29
|
+
1171: { sky: "none", precipitation: "drizzle", freezing: true, intensity: 3 },
|
|
30
|
+
1180: { sky: "clear", precipitation: "rain", intensity: 1 },
|
|
31
|
+
1183: { sky: "none", precipitation: "rain", intensity: 1 },
|
|
32
|
+
1186: { sky: "clear", precipitation: "rain", intensity: 2 },
|
|
33
|
+
1189: { sky: "none", precipitation: "rain", intensity: 2 },
|
|
34
|
+
1192: { sky: "clear", precipitation: "rain", intensity: 3 },
|
|
35
|
+
1195: { sky: "none", precipitation: "rain", intensity: 3 },
|
|
36
|
+
1198: { sky: "none", precipitation: "rain", freezing: true, intensity: 1 },
|
|
37
|
+
1201: { sky: "none", precipitation: "rain", freezing: true, intensity: 3 },
|
|
38
|
+
1204: { sky: "none", precipitation: "sleet", intensity: 1 },
|
|
39
|
+
1207: { sky: "none", precipitation: "sleet", intensity: 3 },
|
|
40
|
+
1210: { sky: "clear", precipitation: "snow", intensity: 1 },
|
|
41
|
+
1213: { sky: "none", precipitation: "snow", intensity: 1 },
|
|
42
|
+
1216: { sky: "clear", precipitation: "snow", intensity: 2 },
|
|
43
|
+
1219: { sky: "none", precipitation: "snow", intensity: 2 },
|
|
44
|
+
1222: { sky: "clear", precipitation: "snow", intensity: 3 },
|
|
45
|
+
1225: { sky: "none", precipitation: "snow", intensity: 3 },
|
|
46
|
+
1237: { sky: "none", precipitation: "ice" },
|
|
47
|
+
1240: { sky: "clear", precipitation: "rain", intensity: 1 },
|
|
48
|
+
1243: { sky: "clear", precipitation: "rain", intensity: 2 },
|
|
49
|
+
1246: { sky: "clear", precipitation: "rain", intensity: 3 },
|
|
50
|
+
1249: { sky: "clear", precipitation: "sleet", intensity: 1 },
|
|
51
|
+
1252: { sky: "clear", precipitation: "sleet", intensity: 3 },
|
|
52
|
+
1255: { sky: "clear", precipitation: "snow", intensity: 1 },
|
|
53
|
+
1258: { sky: "clear", precipitation: "snow", intensity: 3 },
|
|
54
|
+
1261: { sky: "clear", precipitation: "ice", intensity: 1 },
|
|
55
|
+
1264: { sky: "clear", precipitation: "ice", intensity: 3 },
|
|
56
|
+
1273: { sky: "clear", precipitation: "rain", thunder: true, intensity: 1 },
|
|
57
|
+
1276: { sky: "cloud", precipitation: "rain", thunder: true, intensity: 3 },
|
|
58
|
+
1279: { sky: "clear", precipitation: "snow", thunder: true, intensity: 1 },
|
|
59
|
+
1282: { sky: "cloud", precipitation: "snow", thunder: true, intensity: 3 },
|
|
60
|
+
};
|
|
61
|
+
export function weatherScene(code, cloud, windKph) {
|
|
62
|
+
const base = code === undefined ? undefined : WEATHER_SCENES[code];
|
|
63
|
+
if (!base)
|
|
64
|
+
return null;
|
|
65
|
+
const scene = { ...base };
|
|
66
|
+
// Keep blowing snow/obscuration prominent. Do not add a decorative cloud to every condition.
|
|
67
|
+
if ((scene.precipitation || scene.thunder) && !base.windy && cloud != null && Number.isFinite(cloud) && cloud >= 0 && cloud <= 100) {
|
|
68
|
+
scene.sky = cloud <= 25 ? "clear" : cloud < 75 ? "partial" : "cloud";
|
|
69
|
+
}
|
|
70
|
+
// Visual fresh-breeze threshold, not a weather warning. Canonical km/h in all locales.
|
|
71
|
+
scene.windy = !!scene.windy || (windKph != null && Number.isFinite(windKph) && windKph >= 32);
|
|
72
|
+
return scene;
|
|
73
|
+
}
|
|
74
|
+
/** One precipitation row. Mixed/ice conditions have no separate provider probability. */
|
|
75
|
+
export function precipitationMetric(code, rain, snow) {
|
|
76
|
+
const kind = WEATHER_SCENES[code]?.precipitation;
|
|
77
|
+
if (kind === "snow")
|
|
78
|
+
return { label: "Snow", chance: snow };
|
|
79
|
+
if (kind === "sleet")
|
|
80
|
+
return { label: "Sleet", chance: null };
|
|
81
|
+
if (kind === "ice")
|
|
82
|
+
return { label: "Ice pellets", chance: null };
|
|
83
|
+
if (kind === "rain" || kind === "drizzle")
|
|
84
|
+
return { label: "Rain", chance: rain };
|
|
85
|
+
return snow !== null && snow > (rain ?? 0) ? { label: "Snow", chance: snow } : { label: "Rain", chance: rain };
|
|
86
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// Generated from Messenger by scripts/design/generate-messaging-weather.mjs.
|
|
2
|
+
export const weatherConditions = [{ "code": 1000, "day": "Sunny", "night": "Clear" }, { "code": 1003, "day": "Partly cloudy", "night": "Partly cloudy" }, { "code": 1006, "day": "Cloudy", "night": "Cloudy" }, { "code": 1009, "day": "Overcast", "night": "Overcast" }, { "code": 1012, "day": "Haze", "night": "Haze" }, { "code": 1015, "day": "Dust haze", "night": "Dust haze" }, { "code": 1018, "day": "Blowing dust", "night": "Blowing dust" }, { "code": 1021, "day": "Dust storm", "night": "Dust storm" }, { "code": 1024, "day": "Sandstorm", "night": "Sandstorm" }, { "code": 1027, "day": "Severe sandstorm", "night": "Severe sandstorm" }, { "code": 1030, "day": "Mist", "night": "Mist" }, { "code": 1033, "day": "Smoke", "night": "Smoke" }, { "code": 1036, "day": "Smoky haze", "night": "Smoky haze" }, { "code": 1039, "day": "Smog", "night": "Smog" }, { "code": 1042, "day": "Severe smog", "night": "Severe smog" }, { "code": 1045, "day": "Saharan dust", "night": "Saharan dust" }, { "code": 1048, "day": "Dust", "night": "Dust" }, { "code": 1063, "day": "Patchy rain possible", "night": "Patchy rain possible" }, { "code": 1066, "day": "Patchy snow possible", "night": "Patchy snow possible" }, { "code": 1069, "day": "Patchy sleet possible", "night": "Patchy sleet possible" }, { "code": 1072, "day": "Patchy freezing drizzle possible", "night": "Patchy freezing drizzle possible" }, { "code": 1087, "day": "Thundery outbreaks possible", "night": "Thundery outbreaks possible" }, { "code": 1114, "day": "Blowing snow", "night": "Blowing snow" }, { "code": 1117, "day": "Blizzard", "night": "Blizzard" }, { "code": 1135, "day": "Fog", "night": "Fog" }, { "code": 1147, "day": "Freezing fog", "night": "Freezing fog" }, { "code": 1150, "day": "Patchy light drizzle", "night": "Patchy light drizzle" }, { "code": 1153, "day": "Light drizzle", "night": "Light drizzle" }, { "code": 1168, "day": "Freezing drizzle", "night": "Freezing drizzle" }, { "code": 1171, "day": "Heavy freezing drizzle", "night": "Heavy freezing drizzle" }, { "code": 1180, "day": "Patchy light rain", "night": "Patchy light rain" }, { "code": 1183, "day": "Light rain", "night": "Light rain" }, { "code": 1186, "day": "Moderate rain at times", "night": "Moderate rain at times" }, { "code": 1189, "day": "Moderate rain", "night": "Moderate rain" }, { "code": 1192, "day": "Heavy rain at times", "night": "Heavy rain at times" }, { "code": 1195, "day": "Heavy rain", "night": "Heavy rain" }, { "code": 1198, "day": "Light freezing rain", "night": "Light freezing rain" }, { "code": 1201, "day": "Moderate or heavy freezing rain", "night": "Moderate or heavy freezing rain" }, { "code": 1204, "day": "Light sleet", "night": "Light sleet" }, { "code": 1207, "day": "Moderate or heavy sleet", "night": "Moderate or heavy sleet" }, { "code": 1210, "day": "Patchy light snow", "night": "Patchy light snow" }, { "code": 1213, "day": "Light snow", "night": "Light snow" }, { "code": 1216, "day": "Patchy moderate snow", "night": "Patchy moderate snow" }, { "code": 1219, "day": "Moderate snow", "night": "Moderate snow" }, { "code": 1222, "day": "Patchy heavy snow", "night": "Patchy heavy snow" }, { "code": 1225, "day": "Heavy snow", "night": "Heavy snow" }, { "code": 1237, "day": "Ice pellets", "night": "Ice pellets" }, { "code": 1240, "day": "Light rain shower", "night": "Light rain shower" }, { "code": 1243, "day": "Moderate or heavy rain shower", "night": "Moderate or heavy rain shower" }, { "code": 1246, "day": "Torrential rain shower", "night": "Torrential rain shower" }, { "code": 1249, "day": "Light sleet showers", "night": "Light sleet showers" }, { "code": 1252, "day": "Moderate or heavy sleet showers", "night": "Moderate or heavy sleet showers" }, { "code": 1255, "day": "Light snow showers", "night": "Light snow showers" }, { "code": 1258, "day": "Moderate or heavy snow showers", "night": "Moderate or heavy snow showers" }, { "code": 1261, "day": "Light showers of ice pellets", "night": "Light showers of ice pellets" }, { "code": 1264, "day": "Moderate or heavy showers of ice pellets", "night": "Moderate or heavy showers of ice pellets" }, { "code": 1273, "day": "Patchy light rain with thunder", "night": "Patchy light rain with thunder" }, { "code": 1276, "day": "Moderate or heavy rain with thunder", "night": "Moderate or heavy rain with thunder" }, { "code": 1279, "day": "Patchy light snow with thunder", "night": "Patchy light snow with thunder" }, { "code": 1282, "day": "Moderate or heavy snow with thunder", "night": "Moderate or heavy snow with thunder" }];
|
package/dist/voice-composer.js
CHANGED
|
@@ -10,11 +10,11 @@ export function VoiceMessageComposer({ appearance, maxSeconds, busy, onRecord, a
|
|
|
10
10
|
const canSend = !!review && (phase === 'review' || phase === 'failed') && !!onSend;
|
|
11
11
|
if (renderTextComposer && !recording && phase !== 'preparing' && phase !== 'uploading')
|
|
12
12
|
return _jsxs(View, { style: { gap: 4 }, children: [renderAttachments ? renderAttachments(review, waiting) : review && _jsx(View, { style: { paddingHorizontal: 8, paddingTop: 4 }, children: review }), renderTextComposer({ sendVoice: canSend ? onSend : undefined, hasVoice: !!review, blocked: waiting }), !!error && _jsxs(View, { style: { flexDirection: 'row', alignItems: 'center', gap: 8, paddingHorizontal: 8 }, children: [_jsx(Text, { accessibilityRole: "alert", style: { color: c.foreground, fontSize: 12, flex: 1 }, children: error }), onRemove && _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: "Cancel recording", onPress: onRemove, style: { padding: 8 }, children: _jsx(MessageIcon, { name: "close", color: c.foreground, size: 18 }) })] })] });
|
|
13
|
-
return _jsxs(View, { testID: "voice-only-composer", style: { gap: 5 }, children: [renderAttachments?.(review, waiting || recording), _jsxs(View, { style: { flexDirection: 'row', alignItems: 'flex-end', gap: 4 }, children: [_jsxs(View, { style: { flex: 1, minWidth: 0, minHeight: 44, borderRadius: 22, borderWidth: 1, borderColor: c.secondary + '20', backgroundColor: c.incoming, flexDirection: 'row', alignItems: 'center', overflow: 'hidden' }, children: [!recording && !review && !waiting && actions, review && !renderAttachments ? _jsx(View, { style: { flex: 1, minWidth: 0, paddingLeft: 10 }, children: review }) : recording ? _jsxs(View, { style: { flex: 1, minWidth: 0, flexDirection: 'row', alignItems: 'center', gap: 6, paddingLeft: 10 }, children: [_jsx(Text, { style: { fontSize: 11, fontWeight: '800', color: c.incomingText, fontVariant: ['tabular-nums'] }, children: duration(Math.floor(elapsedMs / 1000) * 1000) }), _jsx(Waveform, { samples: waveform, color: c.accent }), _jsx(Text, { style: { fontSize: 11, fontWeight: '800', color: c.incomingText, fontVariant: ['tabular-nums'] }, children: duration(maxSeconds * 1000) })] }) : _jsx(View, { style: { flex: 1, minWidth: 0, paddingHorizontal: 12 }, children: _jsx(Text, { style: { color: c.secondary, fontSize: 14, fontWeight: '800' }, children: waiting ? (phase === 'uploading' ? 'Sending…' : 'Preparing…') : `Voice up to ${maxSeconds}s` }) }), _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: recording ? 'Stop recording' : 'Voice message', disabled: waiting || !!review || phase === 'failed', onPress: recording ? onStop : onRecord, style: { width: 42, height: 44, alignItems: 'center', justifyContent: 'center', opacity: (waiting || !!review || phase === 'failed') ? .45 : 1 }, children: waiting ? _jsx(ActivityIndicator, { size: "small", color: c.accent }) : _jsx(MessageIcon, { name: "mic", color: recording ? '#c94040' : c.accent, size: 23 }) })] }), _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: canSend ? 'Send voice message' : 'Send unavailable', accessibilityState: { disabled: !canSend }, disabled: !canSend, onPress: onSend, style: { width: 44, height: 44, alignItems: 'center', justifyContent: 'center', opacity: canSend ? 1 : .4 }, children: _jsx(MessageIcon, { name: "send", color: c.accent, size: 24 }) })] }), !!error && _jsxs(View, { style: { flexDirection: 'row', alignItems: 'center', gap: 8, paddingHorizontal: 8 }, children: [_jsx(Text, { accessibilityRole: "alert", style: { color: c.foreground, fontSize: 12, flex: 1 }, children: error }), onRemove && _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: "Cancel recording", onPress: onRemove, style: { padding: 8 }, children: _jsx(MessageIcon, { name: "close", color: c.foreground, size: 18 }) })] })] });
|
|
13
|
+
return _jsxs(View, { testID: "voice-only-composer", style: { gap: 5 }, children: [renderAttachments?.(review, waiting || recording), _jsxs(View, { style: { flexDirection: 'row', alignItems: 'flex-end', gap: 4 }, children: [_jsxs(View, { style: { flex: 1, minWidth: 0, minHeight: 44, borderRadius: 22, borderWidth: 1, borderColor: c.secondary + '20', backgroundColor: c.incoming, flexDirection: 'row', alignItems: 'center', overflow: 'hidden' }, children: [!recording && !review && !waiting && actions, review && !renderAttachments ? _jsx(View, { style: { flex: 1, minWidth: 0, paddingLeft: 10 }, children: review }) : recording ? _jsxs(View, { style: { flex: 1, minWidth: 0, flexDirection: 'row', alignItems: 'center', gap: 6, paddingLeft: 10 }, children: [_jsx(Text, { style: { fontSize: 11, fontWeight: '800', color: c.incomingText, fontVariant: ['tabular-nums'] }, children: duration(Math.floor(elapsedMs / 1000) * 1000) }), appearance.showWaveform !== false ? _jsx(Waveform, { samples: waveform, color: c.accent }) : _jsx(View, { style: { flex: 1 } }), _jsx(Text, { style: { fontSize: 11, fontWeight: '800', color: c.incomingText, fontVariant: ['tabular-nums'] }, children: duration(maxSeconds * 1000) })] }) : _jsx(View, { style: { flex: 1, minWidth: 0, paddingHorizontal: 12 }, children: _jsx(Text, { style: { color: c.secondary, fontSize: 14, fontWeight: '800' }, children: waiting ? (phase === 'uploading' ? 'Sending…' : 'Preparing…') : `Voice up to ${maxSeconds}s` }) }), _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: recording ? 'Stop recording' : 'Voice message', disabled: waiting || !!review || phase === 'failed', onPress: recording ? onStop : onRecord, style: { width: 42, height: 44, alignItems: 'center', justifyContent: 'center', opacity: (waiting || !!review || phase === 'failed') ? .45 : 1 }, children: waiting ? _jsx(ActivityIndicator, { size: "small", color: c.accent }) : _jsx(MessageIcon, { name: "mic", color: recording ? '#c94040' : c.accent, size: 23 }) })] }), _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: canSend ? 'Send voice message' : 'Send unavailable', accessibilityState: { disabled: !canSend }, disabled: !canSend, onPress: onSend, style: { width: 44, height: 44, alignItems: 'center', justifyContent: 'center', opacity: canSend ? 1 : .4 }, children: _jsx(MessageIcon, { name: "send", color: c.accent, size: 24 }) })] }), !!error && _jsxs(View, { style: { flexDirection: 'row', alignItems: 'center', gap: 8, paddingHorizontal: 8 }, children: [_jsx(Text, { accessibilityRole: "alert", style: { color: c.foreground, fontSize: 12, flex: 1 }, children: error }), onRemove && _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: "Cancel recording", onPress: onRemove, style: { padding: 8 }, children: _jsx(MessageIcon, { name: "close", color: c.foreground, size: 18 }) })] })] });
|
|
14
14
|
}
|
|
15
15
|
export function VoiceDraftPlayback({ appearance, playing, positionMs = 0, durationMs = 0, waveform, onToggle, onRemove, disabled = false, error, compact = false }) {
|
|
16
16
|
const c = appearance.colors;
|
|
17
17
|
if (compact)
|
|
18
18
|
return _jsxs(View, { style: { width: 88, height: 84, paddingTop: 8, paddingRight: 10 }, children: [_jsxs(View, { style: { width: 76, height: 76, borderRadius: 9, borderWidth: 1, borderColor: c.secondary + '40', backgroundColor: c.background, alignItems: 'center', justifyContent: 'center', gap: 2 }, children: [_jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: playing ? 'Pause recorded voice message' : 'Play recorded voice message', disabled: disabled, onPress: onToggle, style: { width: 44, height: 38, alignItems: 'center', justifyContent: 'center' }, children: _jsx(View, { style: { width: 28, height: 28, borderRadius: 14, backgroundColor: c.accent, alignItems: 'center', justifyContent: 'center' }, children: _jsx(MessageIcon, { name: playing ? 'pause' : 'play', color: "#fff", size: 18 }) }) }), _jsx(Text, { style: { fontSize: 10, fontWeight: '800', color: c.foreground }, children: duration(positionMs >= durationMs ? durationMs : durationMs - positionMs) })] }), _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: "Remove voice message", disabled: disabled, onPress: onRemove, style: { position: 'absolute', right: 0, top: 0, width: 30, height: 30, alignItems: 'center', justifyContent: 'center' }, children: _jsx(View, { style: { width: 22, height: 22, borderRadius: 11, backgroundColor: c.foreground, alignItems: 'center', justifyContent: 'center' }, children: _jsx(MessageIcon, { name: "close", color: c.background, size: 14 }) }) }), !!error && _jsx(Text, { accessibilityRole: "alert", style: { color: c.foreground, fontSize: 11 }, children: error })] });
|
|
19
|
-
return _jsxs(View, { style: { flex: 1, minWidth: 0, gap: 3 }, children: [_jsxs(View, { style: { flexDirection: 'row', alignItems: 'center', gap: 7, minHeight: 44 }, children: [_jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: playing ? 'Pause recorded voice message' : 'Play recorded voice message', disabled: disabled, onPress: onToggle, style: { width: 32, height: 32, borderRadius: 16, backgroundColor: c.accent, alignItems: 'center', justifyContent: 'center' }, children: _jsx(MessageIcon, { name: playing ? 'pause' : 'play', color: "#fff", size: 17 }) }), _jsx(Waveform, { samples: waveform, color: c.accent }), _jsx(Text, { style: { fontSize: 12, fontWeight: '800', color: c.incomingText, fontVariant: ['tabular-nums'] }, children: duration(positionMs >= durationMs ? durationMs : durationMs - positionMs) }), _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: "Remove voice message", disabled: disabled, onPress: onRemove, style: { width: 30, height: 44, alignItems: 'center', justifyContent: 'center' }, children: _jsx(MessageIcon, { name: "close", color: c.incomingText, size: 16 }) })] }), !!error && _jsxs(View, { style: { flexDirection: 'row', alignItems: 'center', gap: 8, paddingHorizontal: 8 }, children: [_jsx(Text, { accessibilityRole: "alert", style: { color: c.foreground, fontSize: 12, flex: 1 }, children: error }), onRemove && _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: "Cancel recording", onPress: onRemove, style: { padding: 8 }, children: _jsx(MessageIcon, { name: "close", color: c.foreground, size: 18 }) })] })] });
|
|
19
|
+
return _jsxs(View, { style: { flex: 1, minWidth: 0, gap: 3 }, children: [_jsxs(View, { style: { flexDirection: 'row', alignItems: 'center', gap: 7, minHeight: 44 }, children: [_jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: playing ? 'Pause recorded voice message' : 'Play recorded voice message', disabled: disabled, onPress: onToggle, style: { width: 32, height: 32, borderRadius: 16, backgroundColor: c.accent, alignItems: 'center', justifyContent: 'center' }, children: _jsx(MessageIcon, { name: playing ? 'pause' : 'play', color: "#fff", size: 17 }) }), appearance.showWaveform !== false ? _jsx(Waveform, { samples: waveform, color: c.accent }) : _jsx(View, { style: { flex: 1 } }), _jsx(Text, { style: { fontSize: 12, fontWeight: '800', color: c.incomingText, fontVariant: ['tabular-nums'] }, children: duration(positionMs >= durationMs ? durationMs : durationMs - positionMs) }), _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: "Remove voice message", disabled: disabled, onPress: onRemove, style: { width: 30, height: 44, alignItems: 'center', justifyContent: 'center' }, children: _jsx(MessageIcon, { name: "close", color: c.incomingText, size: 16 }) })] }), !!error && _jsxs(View, { style: { flexDirection: 'row', alignItems: 'center', gap: 8, paddingHorizontal: 8 }, children: [_jsx(Text, { accessibilityRole: "alert", style: { color: c.foreground, fontSize: 12, flex: 1 }, children: error }), onRemove && _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: "Cancel recording", onPress: onRemove, style: { padding: 8 }, children: _jsx(MessageIcon, { name: "close", color: c.foreground, size: 18 }) })] })] });
|
|
20
20
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Messenger playback display normalization; never changes the stored recording. */
|
|
2
|
+
export function messengerVoiceWaveform(value, durationMs) {
|
|
3
|
+
const count = 32, valid = value?.slice(0, 80);
|
|
4
|
+
if (valid?.length && valid.every(n => Number.isFinite(n) && n >= 0)) {
|
|
5
|
+
const levels = valid.map(n => Math.min(1, n));
|
|
6
|
+
const sampled = Array.from({ length: count }, (_, i) => {
|
|
7
|
+
if (levels.length >= count) {
|
|
8
|
+
const start = Math.floor(i / count * levels.length), end = Math.max(start + 1, Math.floor((i + 1) / count * levels.length));
|
|
9
|
+
return Math.max(...levels.slice(start, end));
|
|
10
|
+
}
|
|
11
|
+
const p = i / (count - 1) * (levels.length - 1), a = Math.floor(p), b = Math.ceil(p);
|
|
12
|
+
return levels[a] + (levels[b] - levels[a]) * (p - a);
|
|
13
|
+
});
|
|
14
|
+
const peak = Math.max(...sampled);
|
|
15
|
+
if (peak > .001)
|
|
16
|
+
return sampled.map(n => n <= .001 ? .035 : Math.max(.055, Math.min(1, Math.pow(n / peak, .72))));
|
|
17
|
+
}
|
|
18
|
+
// Same visual fallback as Messenger for older recordings without waveform data.
|
|
19
|
+
const factor = Math.max(.75, Math.min((durationMs || 2200) / 2800, 1.35));
|
|
20
|
+
return Array.from({ length: count }, (_, i) => Math.max(.08, Math.min(.9, Math.sin(Math.PI * i / (count - 1)) * (.38 + .34 * Math.sin((i + 1) * 1.73 * factor) + .18 * Math.sin((i + 3) * .67)))));
|
|
21
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@robono/messaging-react-native",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"description": "Optional, composable direct and group messaging screens for Robono.",
|
|
@@ -28,7 +28,15 @@
|
|
|
28
28
|
"import": "./dist/expo-calling.js"
|
|
29
29
|
},
|
|
30
30
|
"./app.plugin": "./app.plugin.cjs",
|
|
31
|
-
"./app.plugin.cjs": "./app.plugin.cjs"
|
|
31
|
+
"./app.plugin.cjs": "./app.plugin.cjs",
|
|
32
|
+
"./expo-privacy": {
|
|
33
|
+
"types": "./dist/expo-privacy.d.ts",
|
|
34
|
+
"import": "./dist/expo-privacy.js"
|
|
35
|
+
},
|
|
36
|
+
"./expo-notifications": {
|
|
37
|
+
"types": "./dist/expo-notifications.d.ts",
|
|
38
|
+
"import": "./dist/expo-notifications.js"
|
|
39
|
+
}
|
|
32
40
|
},
|
|
33
41
|
"files": [
|
|
34
42
|
"dist",
|
|
@@ -45,19 +53,26 @@
|
|
|
45
53
|
"prepack": "npm run build && node ../../scripts/generate-sdk-file-sbom.mjs"
|
|
46
54
|
},
|
|
47
55
|
"peerDependencies": {
|
|
48
|
-
"@robono/messaging": "^0.
|
|
56
|
+
"@robono/messaging": "^0.3.0",
|
|
49
57
|
"react": ">=18.2 <20",
|
|
50
58
|
"react-native": ">=0.76 <1",
|
|
51
59
|
"expo-audio": ">=55 <57",
|
|
52
60
|
"expo-image-picker": ">=55 <57",
|
|
53
61
|
"expo-document-picker": ">=55 <57",
|
|
54
|
-
"expo-file-system": ">=55 <57",
|
|
62
|
+
"expo-file-system": ">=55.0.5 <57",
|
|
55
63
|
"expo-sharing": ">=55 <57",
|
|
56
64
|
"expo-video": ">=55 <57",
|
|
57
65
|
"expo-crypto": ">=55 <57",
|
|
58
66
|
"react-native-safe-area-context": ">=5 <6",
|
|
59
67
|
"react-native-svg": ">=15 <16",
|
|
60
|
-
"@robono/calling-react-native": "^0.3.0"
|
|
68
|
+
"@robono/calling-react-native": "^0.3.0",
|
|
69
|
+
"expo-clipboard": ">=8 <57",
|
|
70
|
+
"expo-image-manipulator": ">=14 <57",
|
|
71
|
+
"expo-video-thumbnails": ">=14 <57",
|
|
72
|
+
"react-native-webview": ">=13 <14",
|
|
73
|
+
"expo-blur": ">=55 <57",
|
|
74
|
+
"expo-notifications": ">=55 <57",
|
|
75
|
+
"expo-secure-store": ">=55 <57"
|
|
61
76
|
},
|
|
62
77
|
"license": "SEE LICENSE IN LICENSE",
|
|
63
78
|
"peerDependenciesMeta": {
|
|
@@ -87,6 +102,27 @@
|
|
|
87
102
|
},
|
|
88
103
|
"@robono/calling-react-native": {
|
|
89
104
|
"optional": true
|
|
105
|
+
},
|
|
106
|
+
"expo-clipboard": {
|
|
107
|
+
"optional": true
|
|
108
|
+
},
|
|
109
|
+
"expo-image-manipulator": {
|
|
110
|
+
"optional": true
|
|
111
|
+
},
|
|
112
|
+
"expo-video-thumbnails": {
|
|
113
|
+
"optional": true
|
|
114
|
+
},
|
|
115
|
+
"react-native-webview": {
|
|
116
|
+
"optional": true
|
|
117
|
+
},
|
|
118
|
+
"expo-blur": {
|
|
119
|
+
"optional": true
|
|
120
|
+
},
|
|
121
|
+
"expo-notifications": {
|
|
122
|
+
"optional": true
|
|
123
|
+
},
|
|
124
|
+
"expo-secure-store": {
|
|
125
|
+
"optional": true
|
|
90
126
|
}
|
|
91
127
|
},
|
|
92
128
|
"author": {
|