@streamplace/components 0.7.35 → 0.8.3

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 (45) hide show
  1. package/dist/components/content-metadata/content-metadata-form.js +467 -0
  2. package/dist/components/content-metadata/content-rights.js +78 -0
  3. package/dist/components/content-metadata/content-warnings.js +68 -0
  4. package/dist/components/content-metadata/index.js +11 -0
  5. package/dist/components/mobile-player/player.js +4 -0
  6. package/dist/components/mobile-player/ui/report-modal.js +3 -2
  7. package/dist/components/ui/checkbox.js +87 -0
  8. package/dist/components/ui/dialog.js +188 -83
  9. package/dist/components/ui/primitives/input.js +13 -1
  10. package/dist/components/ui/primitives/modal.js +2 -2
  11. package/dist/components/ui/select.js +89 -0
  12. package/dist/components/ui/textarea.js +23 -4
  13. package/dist/components/ui/toast.js +464 -114
  14. package/dist/components/ui/tooltip.js +103 -0
  15. package/dist/index.js +2 -0
  16. package/dist/lib/metadata-constants.js +157 -0
  17. package/dist/lib/theme/theme.js +5 -3
  18. package/dist/streamplace-provider/index.js +14 -4
  19. package/dist/streamplace-store/content-metadata-actions.js +124 -0
  20. package/dist/streamplace-store/streamplace-store.js +22 -5
  21. package/dist/streamplace-store/user.js +67 -7
  22. package/node-compile-cache/v22.15.0-x64-efe9a9df-0/37be0eec +0 -0
  23. package/package.json +3 -3
  24. package/src/components/content-metadata/content-metadata-form.tsx +893 -0
  25. package/src/components/content-metadata/content-rights.tsx +104 -0
  26. package/src/components/content-metadata/content-warnings.tsx +100 -0
  27. package/src/components/content-metadata/index.tsx +10 -0
  28. package/src/components/mobile-player/player.tsx +5 -0
  29. package/src/components/mobile-player/ui/report-modal.tsx +13 -7
  30. package/src/components/ui/checkbox.tsx +147 -0
  31. package/src/components/ui/dialog.tsx +319 -99
  32. package/src/components/ui/primitives/input.tsx +19 -2
  33. package/src/components/ui/primitives/modal.tsx +4 -2
  34. package/src/components/ui/select.tsx +175 -0
  35. package/src/components/ui/textarea.tsx +47 -29
  36. package/src/components/ui/toast.tsx +785 -179
  37. package/src/components/ui/tooltip.tsx +131 -0
  38. package/src/index.tsx +3 -0
  39. package/src/lib/metadata-constants.ts +180 -0
  40. package/src/lib/theme/theme.tsx +10 -6
  41. package/src/streamplace-provider/index.tsx +20 -2
  42. package/src/streamplace-store/content-metadata-actions.tsx +145 -0
  43. package/src/streamplace-store/streamplace-store.tsx +41 -4
  44. package/src/streamplace-store/user.tsx +71 -7
  45. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,467 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ContentMetadataForm = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const jsx_runtime_1 = require("react/jsx-runtime");
6
+ const react_1 = require("react");
7
+ const react_native_1 = require("react-native");
8
+ const metadata_constants_1 = require("../../lib/metadata-constants");
9
+ const content_metadata_actions_1 = require("../../streamplace-store/content-metadata-actions");
10
+ const streamplace_store_1 = require("../../streamplace-store/streamplace-store");
11
+ const xrpc_1 = require("../../streamplace-store/xrpc");
12
+ const zero = tslib_1.__importStar(require("../../ui"));
13
+ const button_1 = require("../ui/button");
14
+ const checkbox_1 = require("../ui/checkbox");
15
+ const input_1 = require("../ui/input");
16
+ const select_1 = require("../ui/select");
17
+ const text_1 = require("../ui/text");
18
+ const textarea_1 = require("../ui/textarea");
19
+ const toast_1 = require("../ui/toast");
20
+ const tooltip_1 = require("../ui/tooltip");
21
+ const { p, r, bg, borders, w, text, layout, gap, flex } = zero;
22
+ // ButtonSelector component (same as in livestream-panel)
23
+ const ButtonSelector = ({ values, selectedValue, setSelectedValue, disabledValues = [], style = [], }) => ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: [layout.flex.row, gap.all[1], ...style], children: values.map(({ label, value }) => ((0, jsx_runtime_1.jsx)(button_1.Button, { variant: selectedValue === value ? "primary" : "secondary", size: "pill", disabled: disabledValues.includes(value), onPress: () => setSelectedValue(value), style: [
24
+ r.md,
25
+ {
26
+ opacity: disabledValues.includes(value) ? 0.5 : 1,
27
+ },
28
+ ], children: (0, jsx_runtime_1.jsx)(text_1.Text, { style: [
29
+ selectedValue === value ? text.white : text.gray[300],
30
+ { fontSize: 14, fontWeight: "600" },
31
+ ], children: label }) }, value))) }));
32
+ exports.ContentMetadataForm = (0, react_1.forwardRef)(({ showUpdateButton = false, onMetadataChange, initialMetadata, style }, ref) => {
33
+ const pdsAgent = (0, xrpc_1.usePDSAgent)();
34
+ const did = (0, streamplace_store_1.useDID)();
35
+ const getContentMetadata = (0, content_metadata_actions_1.useGetContentMetadata)();
36
+ const saveContentMetadata = (0, content_metadata_actions_1.useSaveContentMetadata)();
37
+ const toast = (0, toast_1.useToast)();
38
+ // Local state for metadata
39
+ const [contentWarnings, setContentWarnings] = (0, react_1.useState)([]);
40
+ const [distributionPolicy, setDistributionPolicy] = (0, react_1.useState)({});
41
+ const [contentRights, setContentRights] = (0, react_1.useState)({});
42
+ const [selectedLicense, setSelectedLicense] = (0, react_1.useState)("");
43
+ const [customLicenseText, setCustomLicenseText] = (0, react_1.useState)("");
44
+ const [loading, setLoading] = (0, react_1.useState)(false);
45
+ const [hasMetadata, setHasMetadata] = (0, react_1.useState)(false);
46
+ // State for section toggles
47
+ const [activeSection, setActiveSection] = (0, react_1.useState)("contentWarnings");
48
+ const currentYear = new Date().getFullYear();
49
+ const getBroadcasterDID = (0, content_metadata_actions_1.useGetBroadcasterDID)();
50
+ (0, react_1.useEffect)(() => {
51
+ getBroadcasterDID();
52
+ }, [getBroadcasterDID]);
53
+ const broadcasterDID = (0, streamplace_store_1.useStreamplaceStore)((state) => state.broadcasterDID);
54
+ // Load existing metadata on mount or from initialMetadata prop
55
+ (0, react_1.useEffect)(() => {
56
+ if (initialMetadata) {
57
+ // Use provided initial metadata
58
+ if (initialMetadata.contentWarnings?.warnings) {
59
+ setContentWarnings(initialMetadata.contentWarnings.warnings);
60
+ }
61
+ if (initialMetadata.distributionPolicy) {
62
+ setDistributionPolicy(initialMetadata.distributionPolicy);
63
+ }
64
+ if (initialMetadata.contentRights) {
65
+ setContentRights(initialMetadata.contentRights);
66
+ setSelectedLicense(initialMetadata.contentRights.license || "");
67
+ }
68
+ return;
69
+ }
70
+ const loadMetadata = async () => {
71
+ if (!pdsAgent || !did)
72
+ return;
73
+ try {
74
+ const metadata = await getContentMetadata();
75
+ if (metadata?.record) {
76
+ setHasMetadata(true);
77
+ if (metadata.record.contentWarnings?.warnings) {
78
+ setContentWarnings(metadata.record.contentWarnings.warnings);
79
+ }
80
+ if (metadata.record.distributionPolicy) {
81
+ setDistributionPolicy(metadata.record.distributionPolicy);
82
+ }
83
+ if (metadata.record.contentRights) {
84
+ setContentRights(metadata.record.contentRights);
85
+ setSelectedLicense(metadata.record.contentRights.license || "");
86
+ }
87
+ }
88
+ }
89
+ catch (error) {
90
+ // No existing metadata is fine
91
+ console.log("No existing metadata found");
92
+ }
93
+ };
94
+ loadMetadata();
95
+ }, [pdsAgent, did, initialMetadata]);
96
+ const handleContentWarningChange = (0, react_1.useCallback)((warning, checked) => {
97
+ const newWarnings = checked
98
+ ? [...contentWarnings, warning]
99
+ : contentWarnings.filter((w) => w !== warning);
100
+ setContentWarnings(newWarnings);
101
+ if (onMetadataChange) {
102
+ onMetadataChange({
103
+ $type: "place.stream.metadata.configuration",
104
+ contentWarnings: { warnings: newWarnings },
105
+ distributionPolicy,
106
+ contentRights,
107
+ });
108
+ }
109
+ }, [contentWarnings, distributionPolicy, contentRights, onMetadataChange]);
110
+ // Notify parent component when metadata changes
111
+ (0, react_1.useEffect)(() => {
112
+ if (onMetadataChange) {
113
+ onMetadataChange({
114
+ $type: "place.stream.metadata.configuration",
115
+ contentWarnings: { warnings: contentWarnings },
116
+ distributionPolicy,
117
+ contentRights,
118
+ });
119
+ }
120
+ }, [contentWarnings, distributionPolicy, contentRights, onMetadataChange]);
121
+ // Handle distribution policy changes
122
+ const handleDistributionPolicyChange = (0, react_1.useCallback)(({ deleteAfter, allowedBroadcasters, }) => {
123
+ let newDistributionPolicy = {
124
+ ...distributionPolicy,
125
+ };
126
+ if (typeof deleteAfter === "string") {
127
+ let duration = parseInt(deleteAfter, 10);
128
+ if (isNaN(duration)) {
129
+ newDistributionPolicy.deleteAfter = undefined;
130
+ }
131
+ else {
132
+ if (isNaN(duration) || duration < 0) {
133
+ duration = -1;
134
+ }
135
+ newDistributionPolicy.deleteAfter =
136
+ duration === 0 ? undefined : duration;
137
+ }
138
+ }
139
+ if (typeof allowedBroadcasters === "string") {
140
+ newDistributionPolicy.allowedBroadcasters =
141
+ allowedBroadcasters.split("\n");
142
+ }
143
+ setDistributionPolicy(newDistributionPolicy);
144
+ if (onMetadataChange) {
145
+ onMetadataChange({
146
+ $type: "place.stream.metadata.configuration",
147
+ contentWarnings: { warnings: contentWarnings },
148
+ distributionPolicy: newDistributionPolicy,
149
+ contentRights,
150
+ });
151
+ }
152
+ }, [
153
+ contentWarnings,
154
+ contentRights,
155
+ onMetadataChange,
156
+ distributionPolicy,
157
+ setDistributionPolicy,
158
+ ]);
159
+ // Handle content rights changes
160
+ const handleContentRightsChange = (0, react_1.useCallback)((field, value) => {
161
+ const newRights = { ...contentRights, [field]: value };
162
+ setContentRights(newRights);
163
+ if (onMetadataChange) {
164
+ onMetadataChange({
165
+ $type: "place.stream.metadata.configuration",
166
+ contentWarnings: { warnings: contentWarnings },
167
+ distributionPolicy,
168
+ contentRights: newRights,
169
+ });
170
+ }
171
+ }, [contentWarnings, distributionPolicy, contentRights, onMetadataChange]);
172
+ const handleSave = (0, react_1.useCallback)(async () => {
173
+ setLoading(true);
174
+ try {
175
+ // Build the metadata object, only including non-empty fields
176
+ const metadata = {
177
+ $type: "place.stream.metadata.configuration",
178
+ };
179
+ // Only include contentWarnings if it has values
180
+ if (contentWarnings && contentWarnings.length > 0) {
181
+ metadata.contentWarnings = { warnings: contentWarnings };
182
+ }
183
+ // Only include contentRights if it has actual values
184
+ const rightsWithLicense = {
185
+ ...contentRights,
186
+ license: selectedLicense === "custom"
187
+ ? customLicenseText
188
+ : selectedLicense || undefined,
189
+ };
190
+ // Filter out empty values from contentRights and convert copyrightYear to number
191
+ const filteredRights = Object.fromEntries(Object.entries(rightsWithLicense)
192
+ .filter(([_, value]) => value !== undefined && value !== null && value !== "")
193
+ .map(([key, value]) => {
194
+ // Convert copyrightYear to integer as per lexicon
195
+ if (key === "copyrightYear" && typeof value === "string") {
196
+ const year = parseInt(value, 10);
197
+ return [key, isNaN(year) ? undefined : year];
198
+ }
199
+ return [key, value];
200
+ })
201
+ .filter(([_, value]) => value !== undefined));
202
+ if (Object.keys(filteredRights).length > 0) {
203
+ metadata.contentRights = filteredRights;
204
+ }
205
+ metadata.distributionPolicy = {
206
+ ...distributionPolicy,
207
+ };
208
+ if (distributionPolicy?.allowedBroadcasters) {
209
+ const filteredBs = distributionPolicy.allowedBroadcasters.filter((broadcaster) => broadcaster !== "");
210
+ metadata.distributionPolicy.allowedBroadcasters = filteredBs;
211
+ setDistributionPolicy({
212
+ ...distributionPolicy,
213
+ allowedBroadcasters: filteredBs,
214
+ });
215
+ }
216
+ await saveContentMetadata(metadata);
217
+ setHasMetadata(true);
218
+ // Show success toast
219
+ toast.show(hasMetadata ? "Content metadata updated" : "Content metadata created", "Your settings have been saved successfully");
220
+ }
221
+ catch (error) {
222
+ console.error("Failed to save metadata:", error);
223
+ // Show error toast
224
+ toast.show("Failed to save metadata", "Please try again later");
225
+ }
226
+ finally {
227
+ setLoading(false);
228
+ }
229
+ }, [
230
+ contentWarnings,
231
+ contentRights,
232
+ selectedLicense,
233
+ customLicenseText,
234
+ hasMetadata,
235
+ saveContentMetadata,
236
+ ]);
237
+ return ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: (0, jsx_runtime_1.jsx)(react_native_1.ScrollView, { ref: ref, style: [{ flex: 1 }, style], showsVerticalScrollIndicator: false, contentContainerStyle: { flexGrow: 1 }, children: (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [gap.all[8], w.percent[100], { alignItems: "stretch" }], children: [(0, jsx_runtime_1.jsx)(react_native_1.View, { style: [gap.all[4], w.percent[100]], children: (0, jsx_runtime_1.jsx)(ButtonSelector, { values: [
238
+ { label: "Content Warnings", value: "contentWarnings" },
239
+ { label: "Content Rights", value: "contentRights" },
240
+ { label: "Distribution", value: "distribution" },
241
+ ], selectedValue: activeSection, setSelectedValue: setActiveSection, style: [{ marginVertical: -2, flexDirection: "column" }] }) }), activeSection === "contentWarnings" && ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [gap.all[3], w.percent[100]], children: [(0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [
242
+ layout.flex.row,
243
+ layout.flex.alignCenter,
244
+ w.percent[100],
245
+ ], children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: [
246
+ text.neutral[300],
247
+ {
248
+ minWidth: 100,
249
+ textAlign: "left",
250
+ paddingBottom: 8,
251
+ fontSize: 14,
252
+ },
253
+ ], children: "Content Warnings" }), (0, jsx_runtime_1.jsx)(text_1.Text, { style: [text.gray[500], { fontSize: 12, paddingBottom: 8 }], children: "optional" })] }), (0, jsx_runtime_1.jsx)(react_native_1.View, { style: [gap.all[2], w.percent[100]], children: metadata_constants_1.CONTENT_WARNINGS.map((warning) => ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: [w.percent[100]], children: (0, jsx_runtime_1.jsx)(tooltip_1.Tooltip, { content: warning.description, position: "top", children: (0, jsx_runtime_1.jsx)(checkbox_1.Checkbox, { checked: contentWarnings.includes(warning.value), onCheckedChange: (checked) => handleContentWarningChange(warning.value, checked), label: warning.label, style: [{ fontSize: 12 }] }) }) }, warning.value))) })] })), activeSection === "contentRights" && ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [gap.all[3], w.percent[100]], children: [(0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [
254
+ layout.flex.row,
255
+ layout.flex.alignCenter,
256
+ w.percent[100],
257
+ ], children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: [
258
+ text.neutral[300],
259
+ {
260
+ minWidth: 100,
261
+ textAlign: "left",
262
+ paddingBottom: 8,
263
+ fontSize: 14,
264
+ },
265
+ ], children: "Content Rights" }), (0, jsx_runtime_1.jsx)(text_1.Text, { style: [text.gray[500], { fontSize: 12, paddingBottom: 8 }], children: "optional" })] }), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [gap.all[3], w.percent[100]], children: [(0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [
266
+ layout.flex.row,
267
+ layout.flex.alignCenter,
268
+ w.percent[100],
269
+ ], children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: [
270
+ text.neutral[300],
271
+ {
272
+ minWidth: 100,
273
+ textAlign: "left",
274
+ paddingBottom: 8,
275
+ fontSize: 14,
276
+ },
277
+ ], children: "Copyright Year" }), (0, jsx_runtime_1.jsx)(react_native_1.View, { style: [flex.values[1]], children: (0, jsx_runtime_1.jsx)(input_1.Input, { value: contentRights.copyrightYear?.toString() || "", onChange: (value) => handleContentRightsChange("copyrightYear", value), placeholder: currentYear.toString(), variant: "filled", inputStyle: [
278
+ p[3],
279
+ r.md,
280
+ bg.neutral[800],
281
+ text.white,
282
+ borders.width.thin,
283
+ borders.color.neutral[600],
284
+ w.percent[100],
285
+ ] }) })] }), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [
286
+ layout.flex.row,
287
+ layout.flex.alignCenter,
288
+ w.percent[100],
289
+ ], children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: [
290
+ text.neutral[300],
291
+ {
292
+ minWidth: 100,
293
+ textAlign: "left",
294
+ paddingBottom: 8,
295
+ fontSize: 14,
296
+ },
297
+ ], children: "License" }), (0, jsx_runtime_1.jsx)(react_native_1.View, { style: [flex.values[1]], children: (0, jsx_runtime_1.jsx)(select_1.Select, { value: selectedLicense, onValueChange: (value) => {
298
+ setSelectedLicense(value);
299
+ handleContentRightsChange("license", value === "custom" ? customLicenseText : value);
300
+ }, placeholder: "Select a license", items: metadata_constants_1.LICENSE_OPTIONS.map((opt) => ({
301
+ label: opt.label,
302
+ value: opt.value,
303
+ description: opt.description,
304
+ })), style: [
305
+ p[3],
306
+ r.md,
307
+ bg.neutral[800],
308
+ text.white,
309
+ borders.width.thin,
310
+ borders.color.neutral[600],
311
+ w.percent[100],
312
+ ] }) })] }), selectedLicense === "custom" && ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [
313
+ layout.flex.row,
314
+ layout.flex.alignCenter,
315
+ w.percent[100],
316
+ ], children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: [
317
+ text.neutral[300],
318
+ {
319
+ minWidth: 100,
320
+ textAlign: "left",
321
+ paddingBottom: 8,
322
+ fontSize: 14,
323
+ },
324
+ ], children: "Custom License" }), (0, jsx_runtime_1.jsx)(react_native_1.View, { style: [flex.values[1]], children: (0, jsx_runtime_1.jsx)(textarea_1.Textarea, { value: customLicenseText, onChangeText: (value) => {
325
+ setCustomLicenseText(value);
326
+ if (selectedLicense === "custom") {
327
+ handleContentRightsChange("license", value);
328
+ }
329
+ }, placeholder: "Enter your custom license terms...", style: [
330
+ p[3],
331
+ r.md,
332
+ bg.neutral[800],
333
+ text.white,
334
+ borders.width.thin,
335
+ borders.color.neutral[600],
336
+ w.percent[100],
337
+ ] }) })] })), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [
338
+ layout.flex.row,
339
+ layout.flex.alignCenter,
340
+ w.percent[100],
341
+ ], children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: [
342
+ text.neutral[300],
343
+ {
344
+ minWidth: 100,
345
+ textAlign: "left",
346
+ paddingBottom: 8,
347
+ fontSize: 14,
348
+ },
349
+ ], children: "Copyright Notice" }), (0, jsx_runtime_1.jsx)(react_native_1.View, { style: [flex.values[1]], children: (0, jsx_runtime_1.jsx)(textarea_1.Textarea, { value: contentRights.copyrightNotice || "", onChangeText: (value) => handleContentRightsChange("copyrightNotice", value), placeholder: "Enter your copyright notice...", style: [
350
+ p[3],
351
+ r.md,
352
+ bg.neutral[800],
353
+ text.white,
354
+ borders.width.thin,
355
+ borders.color.neutral[600],
356
+ w.percent[100],
357
+ ] }) })] }), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [
358
+ layout.flex.row,
359
+ layout.flex.alignCenter,
360
+ w.percent[100],
361
+ ], children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: [
362
+ text.neutral[300],
363
+ {
364
+ minWidth: 100,
365
+ textAlign: "left",
366
+ paddingBottom: 8,
367
+ fontSize: 14,
368
+ },
369
+ ], children: "Credit Line" }), (0, jsx_runtime_1.jsx)(react_native_1.View, { style: [flex.values[1]], children: (0, jsx_runtime_1.jsx)(textarea_1.Textarea, { value: contentRights.creditLine || "", onChangeText: (value) => handleContentRightsChange("creditLine", value), placeholder: "Enter your credit line...", style: [
370
+ p[3],
371
+ r.md,
372
+ bg.neutral[800],
373
+ text.white,
374
+ borders.width.thin,
375
+ borders.color.neutral[600],
376
+ w.percent[100],
377
+ ] }) })] })] })] })), activeSection === "distribution" && ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [gap.all[3], w.percent[100]], children: [(0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [
378
+ layout.flex.row,
379
+ layout.flex.alignCenter,
380
+ w.percent[100],
381
+ ], children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: [
382
+ text.neutral[300],
383
+ { minWidth: 100, textAlign: "left", paddingBottom: 8 },
384
+ ], children: "Distribution" }), (0, jsx_runtime_1.jsx)(text_1.Text, { style: [text.gray[500], { fontSize: 12, paddingBottom: 8 }], children: "optional" })] }), (0, jsx_runtime_1.jsx)(tooltip_1.Tooltip, { content: "Distribution of your content is unlimited, but they still have to respect the deleteAfter policy below.", position: "top", children: (0, jsx_runtime_1.jsx)(checkbox_1.Checkbox, { checked: distributionPolicy.allowedBroadcasters?.includes("*") ||
385
+ false, onCheckedChange: (checked) => handleDistributionPolicyChange({
386
+ allowedBroadcasters: checked
387
+ ? "*"
388
+ : broadcasterDID || "",
389
+ }), label: "Allow everyone to distribute your content", style: [{ fontSize: 12 }] }) }), !distributionPolicy.allowedBroadcasters?.includes("*") && ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: [gap.all[3], w.percent[100]], children: (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [
390
+ layout.flex.row,
391
+ layout.flex.alignCenter,
392
+ w.percent[100],
393
+ ], children: [(0, jsx_runtime_1.jsxs)(text_1.Text, { style: [
394
+ text.neutral[300],
395
+ {
396
+ minWidth: 100,
397
+ textAlign: "left",
398
+ paddingBottom: 8,
399
+ fontSize: 14,
400
+ },
401
+ ], children: ["Allowed", (0, jsx_runtime_1.jsx)("br", {}), "Broadcasters"] }), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [flex.values[1]], children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: [
402
+ text.gray[500],
403
+ { fontSize: 12, paddingBottom: 4 },
404
+ ], children: "Enter the did:webs of the broadcasters you want to allow to distribute your content, one per line." }), (0, jsx_runtime_1.jsx)(input_1.Input, { multiline: true, numberOfLines: 4, value: distributionPolicy.allowedBroadcasters?.join("\n") || "", onChange: (value) => {
405
+ handleDistributionPolicyChange({
406
+ allowedBroadcasters: value,
407
+ });
408
+ }, variant: "filled", inputStyle: [
409
+ p[3],
410
+ r.md,
411
+ bg.neutral[800],
412
+ text.white,
413
+ borders.width.thin,
414
+ borders.color.neutral[600],
415
+ w.percent[100],
416
+ ] })] })] }) })), (0, jsx_runtime_1.jsx)(tooltip_1.Tooltip, { content: "Anyone may archive your content indefinitely.", position: "top", children: (0, jsx_runtime_1.jsx)(checkbox_1.Checkbox, { checked: distributionPolicy.deleteAfter === -1, onCheckedChange: (checked) => {
417
+ if (checked) {
418
+ handleDistributionPolicyChange({
419
+ deleteAfter: "-1",
420
+ });
421
+ }
422
+ else {
423
+ handleDistributionPolicyChange({
424
+ deleteAfter: "300",
425
+ });
426
+ }
427
+ }, label: "Allow everyone to archive your content", style: [{ fontSize: 12 }] }) }), distributionPolicy.deleteAfter !== -1 && ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: [gap.all[3], w.percent[100]], children: (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [
428
+ layout.flex.row,
429
+ layout.flex.alignCenter,
430
+ w.percent[100],
431
+ ], children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: [
432
+ text.neutral[300],
433
+ {
434
+ minWidth: 100,
435
+ textAlign: "left",
436
+ paddingBottom: 8,
437
+ fontSize: 14,
438
+ },
439
+ ], children: "Delete After" }), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [flex.values[1]], children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: [
440
+ text.gray[500],
441
+ { fontSize: 12, paddingBottom: 4 },
442
+ ], children: "Duration in seconds (e.g., 300 for 5 minutes)" }), (0, jsx_runtime_1.jsx)(input_1.Input, { value: distributionPolicy.deleteAfter?.toString() || "", onChange: (value) => {
443
+ handleDistributionPolicyChange({
444
+ deleteAfter: value,
445
+ });
446
+ }, keyboardType: "numeric", variant: "filled", inputStyle: [
447
+ p[3],
448
+ r.md,
449
+ bg.neutral[800],
450
+ text.white,
451
+ borders.width.thin,
452
+ borders.color.neutral[600],
453
+ w.percent[100],
454
+ ] })] })] }) }))] })), (0, jsx_runtime_1.jsx)(react_native_1.View, { style: [layout.flex.center, w.percent[100]], children: (0, jsx_runtime_1.jsx)(button_1.Button, { onPress: handleSave, loading: loading, disabled: loading, style: [
455
+ bg.primary[500],
456
+ r.md,
457
+ gap.all[3],
458
+ { minWidth: 200 },
459
+ layout.flex.center,
460
+ { opacity: loading ? 0.5 : 1 },
461
+ ], children: (0, jsx_runtime_1.jsx)(text_1.Text, { style: [
462
+ text.white,
463
+ w.percent[100],
464
+ { fontSize: 16, fontWeight: "bold" },
465
+ ], children: hasMetadata ? "Update Metadata" : "Save Metadata" }) }) })] }) }) }));
466
+ });
467
+ exports.ContentMetadataForm.displayName = "ContentMetadataForm";
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ContentRights = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ const react_native_1 = require("react-native");
7
+ const metadata_constants_1 = require("../../lib/metadata-constants");
8
+ const theme_1 = require("../../lib/theme/theme");
9
+ const text_1 = require("../ui/text");
10
+ exports.ContentRights = (0, react_1.forwardRef)(({ contentRights }, ref) => {
11
+ const { theme } = (0, theme_1.useTheme)();
12
+ if (!contentRights || Object.keys(contentRights).length === 0) {
13
+ return null;
14
+ }
15
+ const styles = createStyles(theme);
16
+ const formatLicense = (license) => {
17
+ return metadata_constants_1.LICENSE_URL_LABELS[license] || license;
18
+ };
19
+ // Display rights in bottom metadata view
20
+ const elements = [];
21
+ // TODO: Map DID to handle creator
22
+ // if (contentRights.creator) {
23
+ // elements.push(`Creator: ${contentRights.creator}`);
24
+ // }
25
+ if (contentRights.copyrightYear) {
26
+ elements.push(`© ${contentRights.copyrightYear.toString()}`);
27
+ }
28
+ if (contentRights.license) {
29
+ elements.push(formatLicense(contentRights.license));
30
+ }
31
+ if (contentRights.copyrightNotice) {
32
+ elements.push(contentRights.copyrightNotice);
33
+ }
34
+ if (contentRights.creditLine) {
35
+ elements.push(contentRights.creditLine);
36
+ }
37
+ return ((0, jsx_runtime_1.jsx)(react_native_1.View, { ref: ref, style: styles.compactContainer, children: (0, jsx_runtime_1.jsx)(text_1.Text, { style: styles.compactText, children: elements.join(" • ") }) }));
38
+ });
39
+ exports.ContentRights.displayName = "ContentRights";
40
+ function createStyles(theme) {
41
+ return react_native_1.StyleSheet.create({
42
+ container: {
43
+ paddingVertical: theme.spacing[3],
44
+ },
45
+ title: {
46
+ fontSize: 14,
47
+ fontWeight: "600",
48
+ color: theme.colors.text,
49
+ marginBottom: theme.spacing[2],
50
+ },
51
+ content: {
52
+ gap: theme.spacing[2],
53
+ },
54
+ row: {
55
+ flexDirection: "row",
56
+ gap: theme.spacing[2],
57
+ },
58
+ label: {
59
+ fontSize: 13,
60
+ color: theme.colors.textMuted,
61
+ },
62
+ value: {
63
+ fontSize: 13,
64
+ color: theme.colors.text,
65
+ },
66
+ compactContainer: {
67
+ flexDirection: "row",
68
+ gap: theme.spacing[2],
69
+ flexWrap: "wrap",
70
+ marginTop: theme.spacing[1],
71
+ },
72
+ compactText: {
73
+ fontSize: 14,
74
+ fontWeight: "500",
75
+ color: theme.colors.text,
76
+ },
77
+ });
78
+ }
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ContentWarnings = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ const react_native_1 = require("react-native");
7
+ const metadata_constants_1 = require("../../lib/metadata-constants");
8
+ const theme_1 = require("../../lib/theme/theme");
9
+ const text_1 = require("../ui/text");
10
+ exports.ContentWarnings = (0, react_1.forwardRef)(({ warnings, compact = false }, ref) => {
11
+ const { theme } = (0, theme_1.useTheme)();
12
+ if (!warnings || warnings.length === 0) {
13
+ return null;
14
+ }
15
+ const styles = createStyles(theme, compact);
16
+ const getWarningLabel = (warning) => {
17
+ return metadata_constants_1.C2PA_WARNING_LABELS[warning] || warning;
18
+ };
19
+ if (compact) {
20
+ return ((0, jsx_runtime_1.jsx)(react_native_1.View, { ref: ref, style: styles.compactContainer, children: warnings.map((warning, index) => ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.compactWarning, children: (0, jsx_runtime_1.jsx)(text_1.Text, { style: styles.compactWarningText, children: getWarningLabel(warning) }) }, index))) }));
21
+ }
22
+ return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { ref: ref, style: styles.container, children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: styles.title, children: "Content Warnings" }), (0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.warningsContainer, children: warnings.map((warning, index) => ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.warning, children: (0, jsx_runtime_1.jsx)(text_1.Text, { style: styles.warningText, children: getWarningLabel(warning) }) }, index))) })] }));
23
+ });
24
+ exports.ContentWarnings.displayName = "ContentWarnings";
25
+ function createStyles(theme, compact) {
26
+ return react_native_1.StyleSheet.create({
27
+ container: {
28
+ flexDirection: "column",
29
+ gap: theme.spacing[2],
30
+ },
31
+ title: {
32
+ fontSize: 14,
33
+ fontWeight: "600",
34
+ color: theme.colors.text,
35
+ },
36
+ warningsContainer: {
37
+ flexDirection: "row",
38
+ flexWrap: "wrap",
39
+ gap: theme.spacing[2],
40
+ },
41
+ warning: {
42
+ backgroundColor: theme.colors.warning,
43
+ borderRadius: theme.borderRadius.md,
44
+ padding: theme.spacing[2],
45
+ },
46
+ warningText: {
47
+ color: theme.colors.warningForeground,
48
+ fontSize: 12,
49
+ fontWeight: "500",
50
+ },
51
+ compactContainer: {
52
+ flexDirection: "row",
53
+ flexWrap: "wrap",
54
+ gap: theme.spacing[1],
55
+ },
56
+ compactWarning: {
57
+ backgroundColor: theme.colors.warning,
58
+ borderRadius: theme.borderRadius.full,
59
+ paddingHorizontal: 10,
60
+ paddingVertical: 4,
61
+ },
62
+ compactWarningText: {
63
+ color: theme.colors.warningForeground,
64
+ fontSize: 14,
65
+ fontWeight: "600",
66
+ },
67
+ });
68
+ }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ContentWarnings = exports.ContentRights = exports.ContentMetadataForm = void 0;
4
+ // Main form component
5
+ var content_metadata_form_1 = require("./content-metadata-form");
6
+ Object.defineProperty(exports, "ContentMetadataForm", { enumerable: true, get: function () { return content_metadata_form_1.ContentMetadataForm; } });
7
+ // Display components
8
+ var content_rights_1 = require("./content-rights");
9
+ Object.defineProperty(exports, "ContentRights", { enumerable: true, get: function () { return content_rights_1.ContentRights; } });
10
+ var content_warnings_1 = require("./content-warnings");
11
+ Object.defineProperty(exports, "ContentWarnings", { enumerable: true, get: function () { return content_warnings_1.ContentWarnings; } });
@@ -18,12 +18,16 @@ function Player(props) {
18
18
  const setIngest = (0, player_store_1.usePlayerStore)((x) => x.setIngestConnectionState);
19
19
  const clearControlsTimeout = (0, player_store_1.usePlayerStore)((x) => x.clearControlsTimeout);
20
20
  const setReportingURL = (0, player_store_1.usePlayerStore)((x) => x.setReportingURL);
21
+ const setEmbedded = (0, player_store_1.usePlayerStore)((x) => x.setEmbedded);
21
22
  const reportModalOpen = (0, player_store_1.usePlayerStore)((x) => x.reportModalOpen);
22
23
  const setReportModalOpen = (0, player_store_1.usePlayerStore)((x) => x.setReportModalOpen);
23
24
  const reportSubject = (0, player_store_1.usePlayerStore)((x) => x.reportSubject);
24
25
  (0, react_1.useEffect)(() => {
25
26
  setReportingURL(props.reportingURL ?? null);
26
27
  }, [props.reportingURL]);
28
+ (0, react_1.useEffect)(() => {
29
+ setEmbedded(props.embedded ?? false);
30
+ }, [props.embedded]);
27
31
  // Will call back every few seconds to send health updates
28
32
  usePlayerStatus();
29
33
  (0, react_1.useEffect)(() => {