@streamplace/components 0.8.3 → 0.8.6
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/rotation-async.native.js +15 -0
- package/dist/components/mobile-player/rotation-lock.js +137 -0
- package/dist/components/ui/index.js +2 -0
- package/dist/hooks/useLivestreamInfo.js +1 -1
- package/dist/index.js +5 -1
- package/dist/streamplace-store/stream.js +11 -9
- package/node-compile-cache/v22.15.0-x64-efe9a9df-0/37be0eec +0 -0
- package/package.json +4 -2
- package/src/components/mobile-player/rotation-async.native.tsx +15 -0
- package/src/components/mobile-player/rotation-lock.tsx +200 -0
- package/src/components/ui/index.ts +2 -0
- package/src/hooks/useLivestreamInfo.ts +1 -1
- package/src/index.tsx +10 -0
- package/src/streamplace-store/stream.tsx +16 -10
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ScreenOrientation = exports.isRotationAvailable = void 0;
|
|
4
|
+
let ScreenOrientation = null;
|
|
5
|
+
exports.ScreenOrientation = ScreenOrientation;
|
|
6
|
+
try {
|
|
7
|
+
exports.ScreenOrientation = ScreenOrientation = require("expo-screen-orientation");
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
// expo-screen-orientation not available
|
|
11
|
+
if (__DEV__) {
|
|
12
|
+
console.warn("expo-screen-orientation not installed, rotation features disabled");
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.isRotationAvailable = ScreenOrientation != null;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useRotation = exports.RotationProvider = void 0;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const rotation_async_native_1 = require("./rotation-async.native");
|
|
7
|
+
const RotationContext = (0, react_1.createContext)(null);
|
|
8
|
+
const RotationProvider = ({ children, enabled = true, }) => {
|
|
9
|
+
const [isLocked, setIsLocked] = (0, react_1.useState)(false);
|
|
10
|
+
const [canRotate, setCanRotate] = (0, react_1.useState)(rotation_async_native_1.isRotationAvailable);
|
|
11
|
+
const [currentOrientation, setCurrentOrientation] = (0, react_1.useState)(rotation_async_native_1.ScreenOrientation?.Orientation.PORTRAIT_UP ?? 1);
|
|
12
|
+
// If module not available, provide disabled context
|
|
13
|
+
if (!rotation_async_native_1.isRotationAvailable || !rotation_async_native_1.ScreenOrientation) {
|
|
14
|
+
const disabledContextValue = {
|
|
15
|
+
currentOrientation: 1, // Orientation.PORTRAIT_UP
|
|
16
|
+
isLocked: false,
|
|
17
|
+
isActive: false,
|
|
18
|
+
rotateToLandscape: async () => { },
|
|
19
|
+
rotateToPortrait: async () => { },
|
|
20
|
+
toggleRotation: async () => { },
|
|
21
|
+
canRotate: false,
|
|
22
|
+
};
|
|
23
|
+
return ((0, jsx_runtime_1.jsx)(RotationContext.Provider, { value: disabledContextValue, children: children }));
|
|
24
|
+
}
|
|
25
|
+
// Manual rotation functions
|
|
26
|
+
const rotateToLandscape = async () => {
|
|
27
|
+
if (!enabled || !canRotate || !rotation_async_native_1.ScreenOrientation)
|
|
28
|
+
return;
|
|
29
|
+
try {
|
|
30
|
+
await rotation_async_native_1.ScreenOrientation.unlockAsync();
|
|
31
|
+
await rotation_async_native_1.ScreenOrientation.lockAsync(rotation_async_native_1.ScreenOrientation.OrientationLock.LANDSCAPE_RIGHT);
|
|
32
|
+
setIsLocked(true);
|
|
33
|
+
// set current orientation to landscape right
|
|
34
|
+
setCurrentOrientation(rotation_async_native_1.ScreenOrientation.Orientation.LANDSCAPE_RIGHT);
|
|
35
|
+
if (__DEV__) {
|
|
36
|
+
console.log("📲 Manual landscape");
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
console.warn("Failed to rotate to landscape:", error);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
const rotateToPortrait = async () => {
|
|
44
|
+
if (!enabled || !canRotate || !rotation_async_native_1.ScreenOrientation)
|
|
45
|
+
return;
|
|
46
|
+
try {
|
|
47
|
+
await rotation_async_native_1.ScreenOrientation.unlockAsync();
|
|
48
|
+
await rotation_async_native_1.ScreenOrientation.lockAsync(rotation_async_native_1.ScreenOrientation.OrientationLock.PORTRAIT_UP);
|
|
49
|
+
setIsLocked(true);
|
|
50
|
+
setCurrentOrientation(rotation_async_native_1.ScreenOrientation.Orientation.PORTRAIT_UP);
|
|
51
|
+
if (__DEV__) {
|
|
52
|
+
console.log("📲 Manual portrait");
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
console.warn("Failed to rotate to portrait:", error);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
const toggleRotation = async () => {
|
|
60
|
+
if (!rotation_async_native_1.ScreenOrientation)
|
|
61
|
+
return;
|
|
62
|
+
const isLandscape = currentOrientation === rotation_async_native_1.ScreenOrientation.Orientation.LANDSCAPE_LEFT ||
|
|
63
|
+
currentOrientation === rotation_async_native_1.ScreenOrientation.Orientation.LANDSCAPE_RIGHT;
|
|
64
|
+
if (__DEV__) {
|
|
65
|
+
console.log(`🔄 Toggle: current=${currentOrientation}, isLandscape=${isLandscape}`);
|
|
66
|
+
}
|
|
67
|
+
if (isLandscape) {
|
|
68
|
+
await rotateToPortrait();
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
await rotateToLandscape();
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
// Track orientation changes
|
|
75
|
+
(0, react_1.useEffect)(() => {
|
|
76
|
+
if (!enabled)
|
|
77
|
+
return;
|
|
78
|
+
const getCurrentOrientation = async () => {
|
|
79
|
+
if (!rotation_async_native_1.ScreenOrientation)
|
|
80
|
+
return;
|
|
81
|
+
try {
|
|
82
|
+
const orient = await rotation_async_native_1.ScreenOrientation.getOrientationAsync();
|
|
83
|
+
setCurrentOrientation(orient);
|
|
84
|
+
if (__DEV__) {
|
|
85
|
+
console.log(`📲 Orientation on load: ${orient}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
console.warn("Failed to get orientation:", error);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
getCurrentOrientation();
|
|
93
|
+
if (!rotation_async_native_1.ScreenOrientation)
|
|
94
|
+
return;
|
|
95
|
+
const subscription = rotation_async_native_1.ScreenOrientation.addOrientationChangeListener((event) => {
|
|
96
|
+
const newOrientation = event.orientationInfo.orientation;
|
|
97
|
+
setCurrentOrientation(newOrientation);
|
|
98
|
+
if (__DEV__) {
|
|
99
|
+
console.log(`🔄 Orientation: ${newOrientation} (locked: ${isLocked})`);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
return () => {
|
|
103
|
+
subscription?.remove();
|
|
104
|
+
if (rotation_async_native_1.ScreenOrientation) {
|
|
105
|
+
rotation_async_native_1.ScreenOrientation.removeOrientationChangeListeners();
|
|
106
|
+
rotation_async_native_1.ScreenOrientation.unlockAsync().catch(() => { });
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
}, [enabled]);
|
|
110
|
+
const contextValue = (0, react_1.useMemo)(() => ({
|
|
111
|
+
currentOrientation,
|
|
112
|
+
isLocked,
|
|
113
|
+
isActive: enabled,
|
|
114
|
+
rotateToLandscape,
|
|
115
|
+
rotateToPortrait,
|
|
116
|
+
toggleRotation,
|
|
117
|
+
canRotate,
|
|
118
|
+
}), [
|
|
119
|
+
currentOrientation,
|
|
120
|
+
isLocked,
|
|
121
|
+
enabled,
|
|
122
|
+
canRotate,
|
|
123
|
+
rotateToLandscape,
|
|
124
|
+
rotateToPortrait,
|
|
125
|
+
toggleRotation,
|
|
126
|
+
]);
|
|
127
|
+
return ((0, jsx_runtime_1.jsx)(RotationContext.Provider, { value: contextValue, children: children }));
|
|
128
|
+
};
|
|
129
|
+
exports.RotationProvider = RotationProvider;
|
|
130
|
+
const useRotation = () => {
|
|
131
|
+
const context = (0, react_1.useContext)(RotationContext);
|
|
132
|
+
if (!context) {
|
|
133
|
+
throw new Error("useRotation must be used within a RotationProvider");
|
|
134
|
+
}
|
|
135
|
+
return context;
|
|
136
|
+
};
|
|
137
|
+
exports.useRotation = useRotation;
|
|
@@ -9,6 +9,7 @@ tslib_1.__exportStar(require("./primitives/modal"), exports);
|
|
|
9
9
|
tslib_1.__exportStar(require("./primitives/text"), exports);
|
|
10
10
|
// Export styled components
|
|
11
11
|
tslib_1.__exportStar(require("./button"), exports);
|
|
12
|
+
tslib_1.__exportStar(require("./checkbox"), exports);
|
|
12
13
|
tslib_1.__exportStar(require("./dialog"), exports);
|
|
13
14
|
tslib_1.__exportStar(require("./dropdown"), exports);
|
|
14
15
|
tslib_1.__exportStar(require("./icons"), exports);
|
|
@@ -21,6 +22,7 @@ tslib_1.__exportStar(require("./slider"), exports);
|
|
|
21
22
|
tslib_1.__exportStar(require("./text"), exports);
|
|
22
23
|
tslib_1.__exportStar(require("./textarea"), exports);
|
|
23
24
|
tslib_1.__exportStar(require("./toast"), exports);
|
|
25
|
+
tslib_1.__exportStar(require("./tooltip"), exports);
|
|
24
26
|
tslib_1.__exportStar(require("./view"), exports);
|
|
25
27
|
// Component collections for easy importing
|
|
26
28
|
var button_1 = require("./primitives/button");
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.storage = exports.Dashboard = exports.VideoRetry = exports.zero = exports.ui = exports.PlayerUI = exports.Player = exports.usePlayerContext = exports.withPlayerProvider = exports.PlayerProvider = void 0;
|
|
3
|
+
exports.storage = exports.Dashboard = exports.useRotation = exports.RotationProvider = exports.VideoRetry = exports.zero = exports.ui = exports.PlayerUI = exports.Player = exports.usePlayerContext = exports.withPlayerProvider = exports.PlayerProvider = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
// barrel file :)
|
|
6
6
|
require("./crypto-polyfill");
|
|
@@ -29,6 +29,10 @@ tslib_1.__exportStar(require("./components/chat/system-message"), exports);
|
|
|
29
29
|
var video_retry_1 = require("./components/mobile-player/video-retry");
|
|
30
30
|
Object.defineProperty(exports, "VideoRetry", { enumerable: true, get: function () { return tslib_1.__importDefault(video_retry_1).default; } });
|
|
31
31
|
tslib_1.__exportStar(require("./lib/system-messages"), exports);
|
|
32
|
+
// Rotation lock system exports
|
|
33
|
+
var rotation_lock_1 = require("./components/mobile-player/rotation-lock");
|
|
34
|
+
Object.defineProperty(exports, "RotationProvider", { enumerable: true, get: function () { return rotation_lock_1.RotationProvider; } });
|
|
35
|
+
Object.defineProperty(exports, "useRotation", { enumerable: true, get: function () { return rotation_lock_1.useRotation; } });
|
|
32
36
|
tslib_1.__exportStar(require("./components/share/sharesheet"), exports);
|
|
33
37
|
tslib_1.__exportStar(require("./components/keep-awake"), exports);
|
|
34
38
|
// Dashboard components
|
|
@@ -96,21 +96,16 @@ function useCreateStreamRecord() {
|
|
|
96
96
|
let agent = (0, xrpc_1.usePDSAgent)();
|
|
97
97
|
let url = (0, streamplace_store_1.useUrl)();
|
|
98
98
|
const uploadThumbnail = useUploadThumbnail();
|
|
99
|
-
return async ({ title, customThumbnail, submitPost,
|
|
100
|
-
if (
|
|
99
|
+
return async ({ title, customThumbnail, submitPost, canonicalUrl, notificationSettings, }) => {
|
|
100
|
+
if (typeof submitPost !== "boolean") {
|
|
101
101
|
submitPost = true;
|
|
102
102
|
}
|
|
103
|
-
if (!customUrl) {
|
|
104
|
-
customUrl = null;
|
|
105
|
-
}
|
|
106
103
|
if (!agent) {
|
|
107
104
|
throw new Error("No PDS agent found");
|
|
108
105
|
}
|
|
109
106
|
if (!agent.did) {
|
|
110
107
|
throw new Error("No user DID found, assuming not logged in");
|
|
111
108
|
}
|
|
112
|
-
// Use customUrl if provided, otherwise fall back to the store URL
|
|
113
|
-
const finalUrl = customUrl || url;
|
|
114
109
|
const u = new URL(url);
|
|
115
110
|
let thumbnail = undefined;
|
|
116
111
|
if (customThumbnail) {
|
|
@@ -178,19 +173,26 @@ function useCreateStreamRecord() {
|
|
|
178
173
|
window.navigator) {
|
|
179
174
|
platVersion = (0, browser_1.getBrowserName)(window.navigator.userAgent);
|
|
180
175
|
}
|
|
176
|
+
const thisUrl = `${url}/${profile.data.handle}`;
|
|
177
|
+
if (!canonicalUrl) {
|
|
178
|
+
canonicalUrl = thisUrl;
|
|
179
|
+
}
|
|
181
180
|
const record = {
|
|
182
181
|
$type: "place.stream.livestream",
|
|
183
182
|
title: title,
|
|
184
|
-
url:
|
|
183
|
+
url: thisUrl,
|
|
185
184
|
createdAt: new Date().toISOString(),
|
|
186
185
|
// would match up with e.g. https://stream.place/iame.li
|
|
187
|
-
canonicalUrl:
|
|
186
|
+
canonicalUrl: canonicalUrl,
|
|
188
187
|
// user agent style string
|
|
189
188
|
// e.g. `@streamplace/components/0.1.0 (ios, 32.0)`
|
|
190
189
|
agent: `@streamplace/components/${package_json_1.default.version} (${platform}, ${platVersion})`,
|
|
191
190
|
post: newPost,
|
|
192
191
|
thumb: thumbnail,
|
|
193
192
|
};
|
|
193
|
+
if (notificationSettings) {
|
|
194
|
+
record.notificationSettings = notificationSettings;
|
|
195
|
+
}
|
|
194
196
|
await agent.com.atproto.repo.createRecord({
|
|
195
197
|
repo: agent.did,
|
|
196
198
|
collection: "place.stream.livestream",
|
|
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.6",
|
|
4
4
|
"description": "Streamplace React (Native) Components",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "src/index.tsx",
|
|
@@ -30,6 +30,8 @@
|
|
|
30
30
|
"@rn-primitives/slider": "^1.2.0",
|
|
31
31
|
"class-variance-authority": "^0.6.1",
|
|
32
32
|
"expo-keep-awake": "^14.0.0",
|
|
33
|
+
"expo-screen-orientation": "^9.0.7",
|
|
34
|
+
"expo-sensors": "^15.0.7",
|
|
33
35
|
"expo-sqlite": "~15.2.12",
|
|
34
36
|
"expo-video": "^2.0.0",
|
|
35
37
|
"hls.js": "^1.5.17",
|
|
@@ -54,5 +56,5 @@
|
|
|
54
56
|
"start": "tsc --watch --preserveWatchOutput",
|
|
55
57
|
"prepare": "tsc"
|
|
56
58
|
},
|
|
57
|
-
"gitHead": "
|
|
59
|
+
"gitHead": "a40860f005ba4da989cfe1a5c39d29fa3564fea6"
|
|
58
60
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
let ScreenOrientation: typeof import("expo-screen-orientation") | null = null;
|
|
2
|
+
|
|
3
|
+
try {
|
|
4
|
+
ScreenOrientation = require("expo-screen-orientation");
|
|
5
|
+
} catch {
|
|
6
|
+
// expo-screen-orientation not available
|
|
7
|
+
if (__DEV__) {
|
|
8
|
+
console.warn(
|
|
9
|
+
"expo-screen-orientation not installed, rotation features disabled",
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const isRotationAvailable = ScreenOrientation != null;
|
|
15
|
+
export { ScreenOrientation };
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import type { Orientation } from "expo-screen-orientation";
|
|
2
|
+
import React, {
|
|
3
|
+
createContext,
|
|
4
|
+
useContext,
|
|
5
|
+
useEffect,
|
|
6
|
+
useMemo,
|
|
7
|
+
useState,
|
|
8
|
+
} from "react";
|
|
9
|
+
import {
|
|
10
|
+
isRotationAvailable,
|
|
11
|
+
ScreenOrientation,
|
|
12
|
+
} from "./rotation-async.native";
|
|
13
|
+
|
|
14
|
+
export interface RotationContextValue {
|
|
15
|
+
currentOrientation: Orientation;
|
|
16
|
+
isLocked: boolean;
|
|
17
|
+
isActive: boolean;
|
|
18
|
+
rotateToLandscape: () => Promise<void>;
|
|
19
|
+
rotateToPortrait: () => Promise<void>;
|
|
20
|
+
toggleRotation: () => Promise<void>;
|
|
21
|
+
canRotate: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface RotationProviderProps {
|
|
25
|
+
children: React.ReactNode;
|
|
26
|
+
enabled?: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const RotationContext = createContext<RotationContextValue | null>(null);
|
|
30
|
+
|
|
31
|
+
export const RotationProvider: React.FC<RotationProviderProps> = ({
|
|
32
|
+
children,
|
|
33
|
+
enabled = true,
|
|
34
|
+
}) => {
|
|
35
|
+
const [isLocked, setIsLocked] = useState(false);
|
|
36
|
+
const [canRotate, setCanRotate] = useState(isRotationAvailable);
|
|
37
|
+
const [currentOrientation, setCurrentOrientation] = useState<Orientation>(
|
|
38
|
+
ScreenOrientation?.Orientation.PORTRAIT_UP ?? 1,
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
// If module not available, provide disabled context
|
|
42
|
+
if (!isRotationAvailable || !ScreenOrientation) {
|
|
43
|
+
const disabledContextValue: RotationContextValue = {
|
|
44
|
+
currentOrientation: 1, // Orientation.PORTRAIT_UP
|
|
45
|
+
isLocked: false,
|
|
46
|
+
isActive: false,
|
|
47
|
+
rotateToLandscape: async () => {},
|
|
48
|
+
rotateToPortrait: async () => {},
|
|
49
|
+
toggleRotation: async () => {},
|
|
50
|
+
canRotate: false,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<RotationContext.Provider value={disabledContextValue}>
|
|
55
|
+
{children}
|
|
56
|
+
</RotationContext.Provider>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Manual rotation functions
|
|
61
|
+
const rotateToLandscape = async () => {
|
|
62
|
+
if (!enabled || !canRotate || !ScreenOrientation) return;
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
await ScreenOrientation.unlockAsync();
|
|
66
|
+
await ScreenOrientation.lockAsync(
|
|
67
|
+
ScreenOrientation.OrientationLock.LANDSCAPE_RIGHT,
|
|
68
|
+
);
|
|
69
|
+
setIsLocked(true);
|
|
70
|
+
|
|
71
|
+
// set current orientation to landscape right
|
|
72
|
+
setCurrentOrientation(ScreenOrientation.Orientation.LANDSCAPE_RIGHT);
|
|
73
|
+
|
|
74
|
+
if (__DEV__) {
|
|
75
|
+
console.log("📲 Manual landscape");
|
|
76
|
+
}
|
|
77
|
+
} catch (error) {
|
|
78
|
+
console.warn("Failed to rotate to landscape:", error);
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const rotateToPortrait = async () => {
|
|
83
|
+
if (!enabled || !canRotate || !ScreenOrientation) return;
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
await ScreenOrientation.unlockAsync();
|
|
87
|
+
await ScreenOrientation.lockAsync(
|
|
88
|
+
ScreenOrientation.OrientationLock.PORTRAIT_UP,
|
|
89
|
+
);
|
|
90
|
+
setIsLocked(true);
|
|
91
|
+
|
|
92
|
+
setCurrentOrientation(ScreenOrientation.Orientation.PORTRAIT_UP);
|
|
93
|
+
|
|
94
|
+
if (__DEV__) {
|
|
95
|
+
console.log("📲 Manual portrait");
|
|
96
|
+
}
|
|
97
|
+
} catch (error) {
|
|
98
|
+
console.warn("Failed to rotate to portrait:", error);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const toggleRotation = async () => {
|
|
103
|
+
if (!ScreenOrientation) return;
|
|
104
|
+
|
|
105
|
+
const isLandscape =
|
|
106
|
+
currentOrientation === ScreenOrientation.Orientation.LANDSCAPE_LEFT ||
|
|
107
|
+
currentOrientation === ScreenOrientation.Orientation.LANDSCAPE_RIGHT;
|
|
108
|
+
|
|
109
|
+
if (__DEV__) {
|
|
110
|
+
console.log(
|
|
111
|
+
`🔄 Toggle: current=${currentOrientation}, isLandscape=${isLandscape}`,
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (isLandscape) {
|
|
116
|
+
await rotateToPortrait();
|
|
117
|
+
} else {
|
|
118
|
+
await rotateToLandscape();
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
// Track orientation changes
|
|
123
|
+
useEffect(() => {
|
|
124
|
+
if (!enabled) return;
|
|
125
|
+
|
|
126
|
+
const getCurrentOrientation = async () => {
|
|
127
|
+
if (!ScreenOrientation) return;
|
|
128
|
+
try {
|
|
129
|
+
const orient = await ScreenOrientation.getOrientationAsync();
|
|
130
|
+
setCurrentOrientation(orient);
|
|
131
|
+
|
|
132
|
+
if (__DEV__) {
|
|
133
|
+
console.log(`📲 Orientation on load: ${orient}`);
|
|
134
|
+
}
|
|
135
|
+
} catch (error) {
|
|
136
|
+
console.warn("Failed to get orientation:", error);
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
getCurrentOrientation();
|
|
141
|
+
|
|
142
|
+
if (!ScreenOrientation) return;
|
|
143
|
+
|
|
144
|
+
const subscription = ScreenOrientation.addOrientationChangeListener(
|
|
145
|
+
(event) => {
|
|
146
|
+
const newOrientation = event.orientationInfo.orientation;
|
|
147
|
+
setCurrentOrientation(newOrientation);
|
|
148
|
+
|
|
149
|
+
if (__DEV__) {
|
|
150
|
+
console.log(
|
|
151
|
+
`🔄 Orientation: ${newOrientation} (locked: ${isLocked})`,
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
return () => {
|
|
158
|
+
subscription?.remove();
|
|
159
|
+
if (ScreenOrientation) {
|
|
160
|
+
ScreenOrientation.removeOrientationChangeListeners();
|
|
161
|
+
ScreenOrientation.unlockAsync().catch(() => {});
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
}, [enabled]);
|
|
165
|
+
|
|
166
|
+
const contextValue = useMemo(
|
|
167
|
+
() => ({
|
|
168
|
+
currentOrientation,
|
|
169
|
+
isLocked,
|
|
170
|
+
isActive: enabled,
|
|
171
|
+
rotateToLandscape,
|
|
172
|
+
rotateToPortrait,
|
|
173
|
+
toggleRotation,
|
|
174
|
+
canRotate,
|
|
175
|
+
}),
|
|
176
|
+
[
|
|
177
|
+
currentOrientation,
|
|
178
|
+
isLocked,
|
|
179
|
+
enabled,
|
|
180
|
+
canRotate,
|
|
181
|
+
rotateToLandscape,
|
|
182
|
+
rotateToPortrait,
|
|
183
|
+
toggleRotation,
|
|
184
|
+
],
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
return (
|
|
188
|
+
<RotationContext.Provider value={contextValue}>
|
|
189
|
+
{children}
|
|
190
|
+
</RotationContext.Provider>
|
|
191
|
+
);
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
export const useRotation = (): RotationContextValue => {
|
|
195
|
+
const context = useContext(RotationContext);
|
|
196
|
+
if (!context) {
|
|
197
|
+
throw new Error("useRotation must be used within a RotationProvider");
|
|
198
|
+
}
|
|
199
|
+
return context;
|
|
200
|
+
};
|
|
@@ -6,6 +6,7 @@ export * from "./primitives/text";
|
|
|
6
6
|
|
|
7
7
|
// Export styled components
|
|
8
8
|
export * from "./button";
|
|
9
|
+
export * from "./checkbox";
|
|
9
10
|
export * from "./dialog";
|
|
10
11
|
export * from "./dropdown";
|
|
11
12
|
export * from "./icons";
|
|
@@ -18,6 +19,7 @@ export * from "./slider";
|
|
|
18
19
|
export * from "./text";
|
|
19
20
|
export * from "./textarea";
|
|
20
21
|
export * from "./toast";
|
|
22
|
+
export * from "./tooltip";
|
|
21
23
|
export * from "./view";
|
|
22
24
|
|
|
23
25
|
// Component collections for easy importing
|
package/src/index.tsx
CHANGED
|
@@ -33,6 +33,16 @@ export * from "./components/chat/system-message";
|
|
|
33
33
|
export { default as VideoRetry } from "./components/mobile-player/video-retry";
|
|
34
34
|
export * from "./lib/system-messages";
|
|
35
35
|
|
|
36
|
+
// Rotation lock system exports
|
|
37
|
+
export {
|
|
38
|
+
RotationProvider,
|
|
39
|
+
useRotation,
|
|
40
|
+
} from "./components/mobile-player/rotation-lock";
|
|
41
|
+
export type {
|
|
42
|
+
RotationContextValue,
|
|
43
|
+
RotationProviderProps,
|
|
44
|
+
} from "./components/mobile-player/rotation-lock";
|
|
45
|
+
|
|
36
46
|
export * from "./components/share/sharesheet";
|
|
37
47
|
|
|
38
48
|
export * from "./components/keep-awake";
|
|
@@ -131,19 +131,18 @@ export function useCreateStreamRecord() {
|
|
|
131
131
|
title,
|
|
132
132
|
customThumbnail,
|
|
133
133
|
submitPost,
|
|
134
|
-
|
|
134
|
+
canonicalUrl,
|
|
135
|
+
notificationSettings,
|
|
135
136
|
}: {
|
|
136
137
|
title: string;
|
|
137
138
|
customThumbnail?: Blob;
|
|
138
139
|
submitPost?: boolean;
|
|
139
|
-
|
|
140
|
+
canonicalUrl?: string;
|
|
141
|
+
notificationSettings?: PlaceStreamLivestream.NotificationSettings;
|
|
140
142
|
}) => {
|
|
141
|
-
if (
|
|
143
|
+
if (typeof submitPost !== "boolean") {
|
|
142
144
|
submitPost = true;
|
|
143
145
|
}
|
|
144
|
-
if (!customUrl) {
|
|
145
|
-
customUrl = null;
|
|
146
|
-
}
|
|
147
146
|
if (!agent) {
|
|
148
147
|
throw new Error("No PDS agent found");
|
|
149
148
|
}
|
|
@@ -152,8 +151,6 @@ export function useCreateStreamRecord() {
|
|
|
152
151
|
throw new Error("No user DID found, assuming not logged in");
|
|
153
152
|
}
|
|
154
153
|
|
|
155
|
-
// Use customUrl if provided, otherwise fall back to the store URL
|
|
156
|
-
const finalUrl = customUrl || url;
|
|
157
154
|
const u = new URL(url);
|
|
158
155
|
|
|
159
156
|
let thumbnail: BlobRef | undefined = undefined;
|
|
@@ -247,13 +244,18 @@ export function useCreateStreamRecord() {
|
|
|
247
244
|
platVersion = getBrowserName(window.navigator.userAgent);
|
|
248
245
|
}
|
|
249
246
|
|
|
247
|
+
const thisUrl = `${url}/${profile.data.handle}`;
|
|
248
|
+
if (!canonicalUrl) {
|
|
249
|
+
canonicalUrl = thisUrl;
|
|
250
|
+
}
|
|
251
|
+
|
|
250
252
|
const record: PlaceStreamLivestream.Record = {
|
|
251
253
|
$type: "place.stream.livestream",
|
|
252
254
|
title: title,
|
|
253
|
-
url:
|
|
255
|
+
url: thisUrl,
|
|
254
256
|
createdAt: new Date().toISOString(),
|
|
255
257
|
// would match up with e.g. https://stream.place/iame.li
|
|
256
|
-
canonicalUrl:
|
|
258
|
+
canonicalUrl: canonicalUrl,
|
|
257
259
|
// user agent style string
|
|
258
260
|
// e.g. `@streamplace/components/0.1.0 (ios, 32.0)`
|
|
259
261
|
agent: `@streamplace/components/${PackageJson.version} (${platform}, ${platVersion})`,
|
|
@@ -261,6 +263,10 @@ export function useCreateStreamRecord() {
|
|
|
261
263
|
thumb: thumbnail,
|
|
262
264
|
};
|
|
263
265
|
|
|
266
|
+
if (notificationSettings) {
|
|
267
|
+
record.notificationSettings = notificationSettings;
|
|
268
|
+
}
|
|
269
|
+
|
|
264
270
|
await agent.com.atproto.repo.createRecord({
|
|
265
271
|
repo: agent.did,
|
|
266
272
|
collection: "place.stream.livestream",
|