@streamplace/components 0.8.17 → 0.8.18
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/dist/components/mobile-player/video-async.native.d.ts.map +1 -1
- package/dist/components/mobile-player/video-async.native.js +1 -1
- package/dist/components/mobile-player/video-async.native.js.map +1 -1
- package/dist/components/ui/menu.d.ts +14 -0
- package/dist/components/ui/menu.d.ts.map +1 -1
- package/dist/components/ui/menu.js +81 -2
- package/dist/components/ui/menu.js.map +1 -1
- package/dist/components/ui/text.d.ts +1 -1
- package/dist/lib/theme/atoms.d.ts +7 -7
- package/dist/lib/theme/theme.d.ts +1 -1
- package/dist/lib/theme/tokens.d.ts +1 -1
- package/dist/lib/theme/tokens.js +1 -1
- package/dist/livestream-provider/index.d.ts +2 -1
- package/dist/livestream-provider/index.d.ts.map +1 -1
- package/dist/livestream-provider/index.js +4 -2
- package/dist/livestream-provider/index.js.map +1 -1
- package/dist/livestream-provider/websocket.d.ts.map +1 -1
- package/dist/livestream-provider/websocket.js +15 -1
- package/dist/livestream-provider/websocket.js.map +1 -1
- package/dist/livestream-store/livestream-state.d.ts +2 -0
- package/dist/livestream-store/livestream-state.d.ts.map +1 -1
- package/dist/livestream-store/livestream-store.d.ts +1 -0
- package/dist/livestream-store/livestream-store.d.ts.map +1 -1
- package/dist/livestream-store/livestream-store.js +5 -1
- package/dist/livestream-store/livestream-store.js.map +1 -1
- package/dist/livestream-store/websocket-consumer.d.ts.map +1 -1
- package/dist/livestream-store/websocket-consumer.js +97 -75
- package/dist/livestream-store/websocket-consumer.js.map +1 -1
- package/locales/en-US/common.ftl +16 -0
- package/locales/en-US/settings.ftl +13 -0
- package/locales/es-ES/common.ftl +16 -0
- package/locales/es-ES/settings.ftl +1 -1
- package/locales/fr-FR/common.ftl +16 -0
- package/locales/pt-BR/common.ftl +16 -0
- package/locales/pt-BR/settings.ftl +1 -1
- package/locales/zh-Hant/common.ftl +16 -0
- package/node-compile-cache/v22.15.0-x64-efe9a9df-0/37be0eec +0 -0
- package/package.json +2 -2
- package/src/components/mobile-player/video-async.native.tsx +2 -1
- package/src/components/ui/menu.tsx +180 -3
- package/src/lib/theme/tokens.ts +1 -1
- package/src/livestream-provider/index.tsx +5 -1
- package/src/livestream-provider/websocket.tsx +15 -1
- package/src/livestream-store/livestream-state.tsx +2 -0
- package/src/livestream-store/livestream-store.tsx +5 -0
- package/src/livestream-store/websocket-consumer.tsx +95 -73
|
@@ -9,87 +9,109 @@ const problems_1 = require("./problems");
|
|
|
9
9
|
const MAX_RECENT_SEGMENTS = 10;
|
|
10
10
|
const handleWebSocketMessages = (state, messages) => {
|
|
11
11
|
for (let message of messages) {
|
|
12
|
-
if (
|
|
13
|
-
const newLivestream = message;
|
|
14
|
-
const oldLivestream = state.livestream;
|
|
15
|
-
// check if this is actually new
|
|
16
|
-
if (!oldLivestream || oldLivestream.uri !== newLivestream.uri) {
|
|
17
|
-
const streamTitle = newLivestream.record.title || "something cool!";
|
|
18
|
-
const systemMessage = system_messages_1.SystemMessages.streamStart(streamTitle);
|
|
19
|
-
// set proper times
|
|
20
|
-
systemMessage.indexedAt = newLivestream.indexedAt;
|
|
21
|
-
systemMessage.record.createdAt = newLivestream.record.createdAt;
|
|
22
|
-
state = (0, chat_1.reduceChat)(state, [systemMessage], []);
|
|
23
|
-
}
|
|
24
|
-
state = {
|
|
25
|
-
...state,
|
|
26
|
-
livestream: newLivestream,
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
else if (streamplace_1.PlaceStreamLivestream.isViewerCount(message)) {
|
|
30
|
-
message = message;
|
|
12
|
+
if (message.$type === "place.stream.error") {
|
|
31
13
|
state = {
|
|
32
14
|
...state,
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
cid: message.cid,
|
|
42
|
-
author: message.author,
|
|
43
|
-
record: message.record,
|
|
44
|
-
indexedAt: message.indexedAt,
|
|
45
|
-
chatProfile: message.chatProfile,
|
|
46
|
-
replyTo: message.replyTo,
|
|
47
|
-
deleted: message.deleted,
|
|
15
|
+
problems: [
|
|
16
|
+
...state.problems,
|
|
17
|
+
{
|
|
18
|
+
code: message.code,
|
|
19
|
+
message: message.message,
|
|
20
|
+
severity: "error",
|
|
21
|
+
},
|
|
22
|
+
],
|
|
48
23
|
};
|
|
49
|
-
state = (0, chat_1.reduceChat)(state, [hydrated], [], []);
|
|
50
24
|
}
|
|
51
|
-
else
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
25
|
+
else {
|
|
26
|
+
if (!state.websocketConnected) {
|
|
27
|
+
state = {
|
|
28
|
+
...state,
|
|
29
|
+
websocketConnected: true,
|
|
30
|
+
};
|
|
56
31
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
32
|
+
if (streamplace_1.PlaceStreamLivestream.isLivestreamView(message)) {
|
|
33
|
+
const newLivestream = message;
|
|
34
|
+
const oldLivestream = state.livestream;
|
|
35
|
+
// check if this is actually new
|
|
36
|
+
if (!oldLivestream || oldLivestream.uri !== newLivestream.uri) {
|
|
37
|
+
const streamTitle = newLivestream.record.title || "something cool!";
|
|
38
|
+
const systemMessage = system_messages_1.SystemMessages.streamStart(streamTitle);
|
|
39
|
+
// set proper times
|
|
40
|
+
systemMessage.indexedAt = newLivestream.indexedAt;
|
|
41
|
+
systemMessage.record.createdAt = newLivestream.record.createdAt;
|
|
42
|
+
state = (0, chat_1.reduceChat)(state, [systemMessage], []);
|
|
43
|
+
}
|
|
44
|
+
state = {
|
|
45
|
+
...state,
|
|
46
|
+
livestream: newLivestream,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
else if (streamplace_1.PlaceStreamLivestream.isViewerCount(message)) {
|
|
50
|
+
message = message;
|
|
51
|
+
state = {
|
|
52
|
+
...state,
|
|
53
|
+
viewers: message.count,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
else if (streamplace_1.PlaceStreamChatDefs.isMessageView(message)) {
|
|
57
|
+
message = message;
|
|
58
|
+
// Explicitly map MessageView to MessageViewHydrated
|
|
59
|
+
const hydrated = {
|
|
60
|
+
uri: message.uri,
|
|
61
|
+
cid: message.cid,
|
|
62
|
+
author: message.author,
|
|
63
|
+
record: message.record,
|
|
64
|
+
indexedAt: message.indexedAt,
|
|
65
|
+
chatProfile: message.chatProfile,
|
|
66
|
+
replyTo: message.replyTo,
|
|
67
|
+
deleted: message.deleted,
|
|
68
|
+
};
|
|
69
|
+
state = (0, chat_1.reduceChat)(state, [hydrated], [], []);
|
|
70
|
+
}
|
|
71
|
+
else if (streamplace_1.PlaceStreamSegment.isRecord(message)) {
|
|
72
|
+
const newRecentSegments = [...state.recentSegments];
|
|
73
|
+
newRecentSegments.unshift(message);
|
|
74
|
+
if (newRecentSegments.length > MAX_RECENT_SEGMENTS) {
|
|
75
|
+
newRecentSegments.pop();
|
|
76
|
+
}
|
|
77
|
+
state = {
|
|
78
|
+
...state,
|
|
79
|
+
segment: message,
|
|
80
|
+
recentSegments: newRecentSegments,
|
|
81
|
+
problems: (0, problems_1.findProblems)(newRecentSegments),
|
|
82
|
+
hasReceivedSegment: true,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
else if (streamplace_1.PlaceStreamDefs.isBlockView(message)) {
|
|
86
|
+
const block = message;
|
|
87
|
+
state = (0, chat_1.reduceChat)(state, [], [block], []);
|
|
88
|
+
}
|
|
89
|
+
else if (streamplace_1.PlaceStreamDefs.isRenditions(message)) {
|
|
90
|
+
message = message;
|
|
91
|
+
state = {
|
|
92
|
+
...state,
|
|
93
|
+
renditions: message.renditions,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
else if (api_1.AppBskyActorDefs.isProfileViewBasic(message)) {
|
|
97
|
+
state = {
|
|
98
|
+
...state,
|
|
99
|
+
profile: message,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
else if (streamplace_1.PlaceStreamChatGate.isRecord(message)) {
|
|
103
|
+
const hideRecord = message;
|
|
104
|
+
const hiddenMessageUri = hideRecord.hiddenMessage;
|
|
105
|
+
const newPendingHides = [...state.pendingHides];
|
|
106
|
+
if (!newPendingHides.includes(hiddenMessageUri)) {
|
|
107
|
+
newPendingHides.push(hiddenMessageUri);
|
|
108
|
+
}
|
|
109
|
+
state = {
|
|
110
|
+
...state,
|
|
111
|
+
pendingHides: newPendingHides,
|
|
112
|
+
};
|
|
113
|
+
state = (0, chat_1.reduceChat)(state, [], [], [hiddenMessageUri]);
|
|
87
114
|
}
|
|
88
|
-
state = {
|
|
89
|
-
...state,
|
|
90
|
-
pendingHides: newPendingHides,
|
|
91
|
-
};
|
|
92
|
-
state = (0, chat_1.reduceChat)(state, [], [], [hiddenMessageUri]);
|
|
93
115
|
}
|
|
94
116
|
}
|
|
95
117
|
return (0, chat_1.reduceChat)(state, [], [], []);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"websocket-consumer.js","sourceRoot":"","sources":["../../src/livestream-store/websocket-consumer.tsx"],"names":[],"mappings":";;;AAAA,sCAAgD;AAChD,6CASqB;AACrB,4DAAwD;AACxD,iCAAoC;AAEpC,yCAA0C;AAE1C,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAExB,MAAM,uBAAuB,GAAG,CACrC,KAAsB,EACtB,QAAe,EACE,EAAE;IACnB,KAAK,IAAI,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC7B,IAAI,mCAAqB,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"websocket-consumer.js","sourceRoot":"","sources":["../../src/livestream-store/websocket-consumer.tsx"],"names":[],"mappings":"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"}
|
package/locales/en-US/common.ftl
CHANGED
|
@@ -44,3 +44,19 @@ notification-count = { $count ->
|
|
|
44
44
|
[1] One notification
|
|
45
45
|
*[other] { $count } notifications
|
|
46
46
|
}
|
|
47
|
+
|
|
48
|
+
## Offline User
|
|
49
|
+
user-offline = user is offline
|
|
50
|
+
user-offline-message = { $source ->
|
|
51
|
+
[streamer] Looks like <1>@{ $handle } is offline</1>, but they recommend checking out:
|
|
52
|
+
*[default] Looks like <1>@{ $handle } is offline</1>, but we recommend checking out:
|
|
53
|
+
}
|
|
54
|
+
user-offline-no-recommendations =
|
|
55
|
+
Looks like <1>@{ $handle } is offline</1> right now.
|
|
56
|
+
Check back later.
|
|
57
|
+
streaming-title = streaming { $title }
|
|
58
|
+
viewer-count = { $count ->
|
|
59
|
+
[0] 0 viewers
|
|
60
|
+
[1] 1 viewer
|
|
61
|
+
*[other] { $count } viewers
|
|
62
|
+
}
|
|
@@ -80,6 +80,19 @@ keys-count = { $count ->
|
|
|
80
80
|
*[other] { $count } keys
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
## Recommendations
|
|
84
|
+
recommendations = Recommendations
|
|
85
|
+
manage-recommendations = Manage Recommendations
|
|
86
|
+
recommendations-to-others = Recommendations to Others
|
|
87
|
+
recommendations-description = Share up to 8 streamers you recommend to your viewers
|
|
88
|
+
no-recommendations-yet = No recommendations configured yet
|
|
89
|
+
add-recommendation = Add Recommendation
|
|
90
|
+
streamer-did = Streamer DID
|
|
91
|
+
recommendations-count = { $count ->
|
|
92
|
+
[one] { $count } recommendation
|
|
93
|
+
*[other] { $count } recommendations
|
|
94
|
+
}
|
|
95
|
+
|
|
83
96
|
## Webhook Management
|
|
84
97
|
webhooks = Webhooks
|
|
85
98
|
webhook-integrations = Webhook Integrations
|
package/locales/es-ES/common.ftl
CHANGED
|
@@ -44,3 +44,19 @@ notification-count = { $count ->
|
|
|
44
44
|
[1] Una notificación
|
|
45
45
|
*[other] { $count } notificaciones
|
|
46
46
|
}
|
|
47
|
+
|
|
48
|
+
## Offline User
|
|
49
|
+
user-offline = usuario desconectado
|
|
50
|
+
user-offline-message = { $source ->
|
|
51
|
+
[streamer] Parece que <1>@{ $handle } está desconectado</1>, pero ellos recomiendan ver:
|
|
52
|
+
*[default] Parece que <1>@{ $handle } está desconectado</1>, pero te recomendamos ver:
|
|
53
|
+
}
|
|
54
|
+
user-offline-no-recommendations =
|
|
55
|
+
Parece que <1>@{ $handle } está desconectado</1> ahora mismo.
|
|
56
|
+
Vuelve más tarde.
|
|
57
|
+
streaming-title = transmitiendo { $title }
|
|
58
|
+
viewer-count = { $count ->
|
|
59
|
+
[0] 0 espectadores
|
|
60
|
+
[1] 1 espectador
|
|
61
|
+
*[other] { $count } espectadores
|
|
62
|
+
}
|
|
@@ -113,7 +113,7 @@ key-manager = Gestor de Claves
|
|
|
113
113
|
manage-keys = Gestionar Claves
|
|
114
114
|
your-stream-pubkeys = Tus Claves Públicas de Transmisión
|
|
115
115
|
no-keys = No hay claves configuradas
|
|
116
|
-
pubkey-description = Las claves públicas se emparejan con claves de transmisión (usadas en software de
|
|
116
|
+
pubkey-description = Las claves públicas se emparejan con claves de transmisión (usadas en software de transmitiendo) para firmar y verificar tu transmisión
|
|
117
117
|
|
|
118
118
|
keys-count = { $count ->
|
|
119
119
|
[one] { $count } clave
|
package/locales/fr-FR/common.ftl
CHANGED
|
@@ -44,3 +44,19 @@ notification-count = { $count ->
|
|
|
44
44
|
[1] Une notification
|
|
45
45
|
*[other] { $count } notifications
|
|
46
46
|
}
|
|
47
|
+
|
|
48
|
+
## Offline User
|
|
49
|
+
user-offline = utilisateur hors ligne
|
|
50
|
+
user-offline-message = { $source ->
|
|
51
|
+
[streamer] On dirait que <1>@{ $handle } est hors ligne</1>, mais ils recommandent de regarder :
|
|
52
|
+
*[default] On dirait que <1>@{ $handle } est hors ligne</1>, mais nous recommandons de regarder :
|
|
53
|
+
}
|
|
54
|
+
user-offline-no-recommendations =
|
|
55
|
+
On dirait que <1>@{ $handle } est hors ligne</1> maintenant.
|
|
56
|
+
Revenez plus tard.
|
|
57
|
+
streaming-title = diffusion de { $title }
|
|
58
|
+
viewer-count = { $count ->
|
|
59
|
+
[0] 0 spectateurs
|
|
60
|
+
[1] 1 spectateur
|
|
61
|
+
*[other] { $count } spectateurs
|
|
62
|
+
}
|
package/locales/pt-BR/common.ftl
CHANGED
|
@@ -44,3 +44,19 @@ notification-count = { $count ->
|
|
|
44
44
|
[1] Uma notificação
|
|
45
45
|
*[other] { $count } notificações
|
|
46
46
|
}
|
|
47
|
+
|
|
48
|
+
## Offline User
|
|
49
|
+
user-offline = usuário offline
|
|
50
|
+
user-offline-message = { $source ->
|
|
51
|
+
[streamer] Parece que <1>@{ $handle } está offline</1>, mas eles recomendam assistir:
|
|
52
|
+
*[default] Parece que <1>@{ $handle } está offline</1>, mas recomendamos assistir:
|
|
53
|
+
}
|
|
54
|
+
user-offline-no-recommendations =
|
|
55
|
+
Parece que <1>@{ $handle } está offline</1> agora.
|
|
56
|
+
Volte mais tarde.
|
|
57
|
+
streaming-title = transmitindo { $title }
|
|
58
|
+
viewer-count = { $count ->
|
|
59
|
+
[0] 0 espectadores
|
|
60
|
+
[1] 1 espectador
|
|
61
|
+
*[other] { $count } espectadores
|
|
62
|
+
}
|
|
@@ -111,7 +111,7 @@ key-manager = Gerenciador de Chaves
|
|
|
111
111
|
manage-keys = Gerenciar Chaves
|
|
112
112
|
your-stream-pubkeys = Suas Chaves Públicas de Transmissão
|
|
113
113
|
no-keys = Nenhuma chave configurada
|
|
114
|
-
pubkey-description = Chaves públicas são emparelhadas com chaves de transmissão (usadas em software de
|
|
114
|
+
pubkey-description = Chaves públicas são emparelhadas com chaves de transmissão (usadas em software de transmitindo) para assinar e verificar sua transmissão
|
|
115
115
|
|
|
116
116
|
keys-count = { $count ->
|
|
117
117
|
[one] { $count } chave
|
|
@@ -44,3 +44,19 @@ notification-count = { $count ->
|
|
|
44
44
|
[1] 一則通知
|
|
45
45
|
*[other] { $count } 則通知
|
|
46
46
|
}
|
|
47
|
+
|
|
48
|
+
## Offline User
|
|
49
|
+
user-offline = 使用者離線
|
|
50
|
+
user-offline-message = { $source ->
|
|
51
|
+
[streamer] 看起來 <1>@{ $handle } 離線</1> 了,但他們推薦觀看:
|
|
52
|
+
*[default] 看起來 <1>@{ $handle } 離線</1> 了,但我們推薦觀看:
|
|
53
|
+
}
|
|
54
|
+
user-offline-no-recommendations =
|
|
55
|
+
看起來 <1>@{ $handle } 離線</1> 了。
|
|
56
|
+
請稍後再來看看。
|
|
57
|
+
streaming-title = 正在直播 { $title }
|
|
58
|
+
viewer-count = { $count ->
|
|
59
|
+
[0] 0 位觀眾
|
|
60
|
+
[1] 1 位觀眾
|
|
61
|
+
*[other] { $count } 位觀眾
|
|
62
|
+
}
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@streamplace/components",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.18",
|
|
4
4
|
"description": "Streamplace React (Native) Components",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "src/index.tsx",
|
|
@@ -78,5 +78,5 @@
|
|
|
78
78
|
"i18n:watch": "nodemon --watch 'locales/**/*.ftl' --exec 'node scripts/compile-translations.js'",
|
|
79
79
|
"i18n:extract": "i18next-cli extract && node scripts/migrate-i18n.js"
|
|
80
80
|
},
|
|
81
|
-
"gitHead": "
|
|
81
|
+
"gitHead": "d9cde37cadad4b378cbdc00c640edcaa4717b005"
|
|
82
82
|
}
|
|
@@ -414,7 +414,8 @@ export function NativeIngestPlayer(props?: {
|
|
|
414
414
|
variant="secondary"
|
|
415
415
|
>
|
|
416
416
|
<View style={[layout.flex.row, gap.all[1]]}>
|
|
417
|
-
<Text>Open Settings</Text>
|
|
417
|
+
<Text>Open Settings</Text>
|
|
418
|
+
<ArrowRight color="white" size="18" />
|
|
418
419
|
</View>
|
|
419
420
|
</Button>
|
|
420
421
|
)}
|
|
@@ -1,5 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
Children,
|
|
3
|
+
cloneElement,
|
|
4
|
+
forwardRef,
|
|
5
|
+
isValidElement,
|
|
6
|
+
ReactNode,
|
|
7
|
+
} from "react";
|
|
8
|
+
import { Animated, Platform, View, ViewStyle } from "react-native";
|
|
9
|
+
import { Gesture, GestureDetector } from "react-native-gesture-handler";
|
|
10
|
+
import {
|
|
11
|
+
runOnJS,
|
|
12
|
+
useAnimatedStyle,
|
|
13
|
+
useSharedValue,
|
|
14
|
+
withSpring,
|
|
15
|
+
} from "react-native-reanimated";
|
|
3
16
|
import {
|
|
4
17
|
a,
|
|
5
18
|
borderRadius,
|
|
@@ -64,11 +77,114 @@ export interface MenuItemProps {
|
|
|
64
77
|
disabled?: boolean;
|
|
65
78
|
style?: ViewStyle;
|
|
66
79
|
onPress?: () => void;
|
|
80
|
+
draggable?: boolean;
|
|
81
|
+
dragHandle?: ReactNode;
|
|
82
|
+
_dragIndex?: number;
|
|
83
|
+
_dragTotalItems?: number;
|
|
84
|
+
_onDragMove?: (fromIndex: number, toIndex: number) => void;
|
|
85
|
+
_onDragEnd?: (fromIndex: number, toIndex: number) => void;
|
|
67
86
|
}
|
|
68
87
|
|
|
69
88
|
export const MenuItem = forwardRef<View, MenuItemProps>(
|
|
70
|
-
(
|
|
89
|
+
(
|
|
90
|
+
{
|
|
91
|
+
children,
|
|
92
|
+
disabled,
|
|
93
|
+
style,
|
|
94
|
+
draggable,
|
|
95
|
+
dragHandle,
|
|
96
|
+
_dragIndex,
|
|
97
|
+
_dragTotalItems,
|
|
98
|
+
_onDragMove,
|
|
99
|
+
_onDragEnd,
|
|
100
|
+
},
|
|
101
|
+
ref,
|
|
102
|
+
) => {
|
|
71
103
|
const { theme } = useTheme();
|
|
104
|
+
|
|
105
|
+
if (
|
|
106
|
+
draggable &&
|
|
107
|
+
_dragIndex !== undefined &&
|
|
108
|
+
_dragTotalItems !== undefined &&
|
|
109
|
+
_onDragMove &&
|
|
110
|
+
_onDragEnd
|
|
111
|
+
) {
|
|
112
|
+
const translateY = useSharedValue(0);
|
|
113
|
+
const isDragging = useSharedValue(false);
|
|
114
|
+
const ITEM_HEIGHT = 60;
|
|
115
|
+
|
|
116
|
+
const panGesture = Gesture.Pan()
|
|
117
|
+
.onStart(() => {
|
|
118
|
+
isDragging.value = true;
|
|
119
|
+
})
|
|
120
|
+
.onUpdate((event) => {
|
|
121
|
+
translateY.value = event.translationY;
|
|
122
|
+
|
|
123
|
+
const newIndex = Math.round(
|
|
124
|
+
_dragIndex + translateY.value / ITEM_HEIGHT,
|
|
125
|
+
);
|
|
126
|
+
const clampedIndex = Math.max(
|
|
127
|
+
0,
|
|
128
|
+
Math.min(_dragTotalItems - 1, newIndex),
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
if (clampedIndex !== _dragIndex) {
|
|
132
|
+
runOnJS(_onDragMove)(_dragIndex, clampedIndex);
|
|
133
|
+
}
|
|
134
|
+
})
|
|
135
|
+
.onEnd(() => {
|
|
136
|
+
const newIndex = Math.round(
|
|
137
|
+
_dragIndex + translateY.value / ITEM_HEIGHT,
|
|
138
|
+
);
|
|
139
|
+
const clampedIndex = Math.max(
|
|
140
|
+
0,
|
|
141
|
+
Math.min(_dragTotalItems - 1, newIndex),
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
runOnJS(_onDragEnd)(_dragIndex, clampedIndex);
|
|
145
|
+
|
|
146
|
+
translateY.value = withSpring(0);
|
|
147
|
+
isDragging.value = false;
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
const animatedStyle = useAnimatedStyle(() => ({
|
|
151
|
+
transform: [{ translateY: translateY.value }],
|
|
152
|
+
zIndex: isDragging.value ? 100 : 1,
|
|
153
|
+
opacity: isDragging.value ? 0.8 : 1,
|
|
154
|
+
}));
|
|
155
|
+
|
|
156
|
+
return (
|
|
157
|
+
<Animated.View style={animatedStyle}>
|
|
158
|
+
<View
|
|
159
|
+
ref={ref}
|
|
160
|
+
style={[
|
|
161
|
+
a.layout.flex.row,
|
|
162
|
+
a.layout.flex.alignCenter,
|
|
163
|
+
a.radius.all.sm,
|
|
164
|
+
py[1],
|
|
165
|
+
pl[3],
|
|
166
|
+
pr[2],
|
|
167
|
+
disabled && { opacity: 0.5 },
|
|
168
|
+
style,
|
|
169
|
+
]}
|
|
170
|
+
>
|
|
171
|
+
{dragHandle && (
|
|
172
|
+
<GestureDetector gesture={panGesture}>
|
|
173
|
+
<View style={{ marginRight: 8 }}>{dragHandle}</View>
|
|
174
|
+
</GestureDetector>
|
|
175
|
+
)}
|
|
176
|
+
{typeof children === "string" ? (
|
|
177
|
+
<Text style={{ color: theme.colors.popoverForeground }}>
|
|
178
|
+
{children}
|
|
179
|
+
</Text>
|
|
180
|
+
) : (
|
|
181
|
+
children
|
|
182
|
+
)}
|
|
183
|
+
</View>
|
|
184
|
+
</Animated.View>
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
|
|
72
188
|
return (
|
|
73
189
|
<View
|
|
74
190
|
ref={ref}
|
|
@@ -169,3 +285,64 @@ export const MenuInfo = forwardRef<View, MenuInfoProps>(
|
|
|
169
285
|
);
|
|
170
286
|
},
|
|
171
287
|
);
|
|
288
|
+
|
|
289
|
+
export interface MenuDraggableGroupProps {
|
|
290
|
+
children: ReactNode;
|
|
291
|
+
onMove: (fromIndex: number, toIndex: number) => void;
|
|
292
|
+
onDragEnd: (fromIndex: number, toIndex: number) => void;
|
|
293
|
+
dragHandle?: ReactNode;
|
|
294
|
+
style?: ViewStyle;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
export const MenuDraggableGroup = forwardRef<View, MenuDraggableGroupProps>(
|
|
298
|
+
({ children, onMove, onDragEnd, dragHandle, style }, ref) => {
|
|
299
|
+
const { theme } = useTheme();
|
|
300
|
+
|
|
301
|
+
const childrenArray = Children.toArray(children);
|
|
302
|
+
const draggableItems = childrenArray.filter(
|
|
303
|
+
(child) =>
|
|
304
|
+
isValidElement(child) &&
|
|
305
|
+
(child.type === MenuItem || child.type === MenuSeparator),
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
let itemIndex = 0;
|
|
309
|
+
const enhancedChildren = Children.map(children, (child) => {
|
|
310
|
+
if (isValidElement(child)) {
|
|
311
|
+
if (child.type === MenuItem) {
|
|
312
|
+
const currentIndex = itemIndex;
|
|
313
|
+
itemIndex++;
|
|
314
|
+
|
|
315
|
+
return cloneElement(child, {
|
|
316
|
+
draggable: true,
|
|
317
|
+
dragHandle: dragHandle || child.props.dragHandle,
|
|
318
|
+
_dragIndex: currentIndex,
|
|
319
|
+
_dragTotalItems: draggableItems.filter(
|
|
320
|
+
(c) => isValidElement(c) && c.type === MenuItem,
|
|
321
|
+
).length,
|
|
322
|
+
_onDragMove: onMove,
|
|
323
|
+
_onDragEnd: onDragEnd,
|
|
324
|
+
} as any);
|
|
325
|
+
}
|
|
326
|
+
if (child.type === MenuSeparator) {
|
|
327
|
+
return child;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
return child;
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
return (
|
|
334
|
+
<View
|
|
335
|
+
ref={ref}
|
|
336
|
+
style={[
|
|
337
|
+
{ backgroundColor: theme.colors.muted + "c0" },
|
|
338
|
+
Platform.OS === "web" ? [px[1], py[1]] : p[1],
|
|
339
|
+
gap.all[1],
|
|
340
|
+
{ borderRadius: borderRadius.lg },
|
|
341
|
+
style,
|
|
342
|
+
]}
|
|
343
|
+
>
|
|
344
|
+
{enhancedChildren}
|
|
345
|
+
</View>
|
|
346
|
+
);
|
|
347
|
+
},
|
|
348
|
+
);
|
package/src/lib/theme/tokens.ts
CHANGED
|
@@ -5,9 +5,11 @@ import { useLivestreamWebsocket } from "./websocket";
|
|
|
5
5
|
export function LivestreamProvider({
|
|
6
6
|
children,
|
|
7
7
|
src,
|
|
8
|
+
ignoreOuterContext = false,
|
|
8
9
|
}: {
|
|
9
10
|
children: React.ReactNode;
|
|
10
11
|
src: string;
|
|
12
|
+
ignoreOuterContext?: boolean;
|
|
11
13
|
}) {
|
|
12
14
|
const context = useContext(LivestreamContext);
|
|
13
15
|
const store = useRef(makeLivestreamStore()).current;
|
|
@@ -15,7 +17,9 @@ export function LivestreamProvider({
|
|
|
15
17
|
// this is ok, there's use cases for having one in another
|
|
16
18
|
// like having a player component that's independently usable
|
|
17
19
|
// but can also be embedded within an entire livestream page
|
|
18
|
-
|
|
20
|
+
if (!ignoreOuterContext) {
|
|
21
|
+
return <>{children}</>;
|
|
22
|
+
}
|
|
19
23
|
}
|
|
20
24
|
(window as any).livestreamStore = store;
|
|
21
25
|
return (
|
|
@@ -12,17 +12,30 @@ export function useLivestreamWebsocket(src: string) {
|
|
|
12
12
|
|
|
13
13
|
const ref = useRef<any[]>([]);
|
|
14
14
|
const handle = useRef<NodeJS.Timeout | null>(null);
|
|
15
|
+
const hasReceivedMessage = useRef(false);
|
|
16
|
+
const hasErrored = useRef(false);
|
|
15
17
|
|
|
16
18
|
const { readyState } = useWebSocket(`${wsUrl}/api/websocket/${src}`, {
|
|
17
19
|
reconnectInterval: 1000,
|
|
18
|
-
shouldReconnect: () =>
|
|
20
|
+
shouldReconnect: () => !hasErrored.current,
|
|
19
21
|
|
|
20
22
|
onOpen: () => {
|
|
21
23
|
ref.current = [];
|
|
24
|
+
hasReceivedMessage.current = false;
|
|
22
25
|
},
|
|
23
26
|
|
|
24
27
|
onError: (e) => {
|
|
25
28
|
console.log("onError", e);
|
|
29
|
+
if (!hasReceivedMessage.current) {
|
|
30
|
+
hasErrored.current = true;
|
|
31
|
+
handleWebSocketMessages([
|
|
32
|
+
{
|
|
33
|
+
$type: "place.stream.error",
|
|
34
|
+
code: "user_not_found",
|
|
35
|
+
message: "this stream doesn't exist or is unavailable",
|
|
36
|
+
},
|
|
37
|
+
]);
|
|
38
|
+
}
|
|
26
39
|
},
|
|
27
40
|
|
|
28
41
|
// spamming the redux store with messages causes a zillion re-renders,
|
|
@@ -30,6 +43,7 @@ export function useLivestreamWebsocket(src: string) {
|
|
|
30
43
|
onMessage: (msg) => {
|
|
31
44
|
try {
|
|
32
45
|
const data = JSON.parse(msg.data);
|
|
46
|
+
hasReceivedMessage.current = true;
|
|
33
47
|
ref.current.push(data);
|
|
34
48
|
if (handle.current) {
|
|
35
49
|
return;
|
|
@@ -21,6 +21,8 @@ export interface LivestreamState {
|
|
|
21
21
|
replyToMessage: ChatMessageViewHydrated | null;
|
|
22
22
|
streamKey: string | null;
|
|
23
23
|
setStreamKey: (key: string | null) => void;
|
|
24
|
+
websocketConnected: boolean;
|
|
25
|
+
hasReceivedSegment: boolean;
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
export interface LivestreamProblem {
|