@oxyhq/services 22.5.0 → 22.6.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/lib/commonjs/index.js +1 -1
- package/lib/commonjs/ui/client.js +1 -1
- package/lib/commonjs/ui/components/FontLoader.js +18 -145
- package/lib/commonjs/ui/components/FontLoader.js.map +1 -1
- package/lib/commonjs/ui/components/FontLoader.native.js +88 -0
- package/lib/commonjs/ui/components/FontLoader.native.js.map +1 -0
- package/lib/commonjs/ui/components/OxyProvider.js +1 -1
- package/lib/commonjs/ui/components/fileManagement/FileDetailsModal.js +16 -27
- package/lib/commonjs/ui/components/fileManagement/FileDetailsModal.js.map +1 -1
- package/lib/commonjs/ui/components/fileManagement/UploadPreview.js.map +1 -1
- package/lib/commonjs/ui/components/fileManagement/styles.js +1 -225
- package/lib/commonjs/ui/components/fileManagement/styles.js.map +1 -1
- package/lib/commonjs/ui/context/hooks/useAuthOperations.js +5 -2
- package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -1
- package/lib/commonjs/ui/context/useOxyAccountGraph.js +7 -0
- package/lib/commonjs/ui/context/useOxyAccountGraph.js.map +1 -1
- package/lib/commonjs/ui/hooks/queries/useAccountQueries.js +10 -4
- package/lib/commonjs/ui/hooks/queries/useAccountQueries.js.map +1 -1
- package/lib/commonjs/ui/hooks/queries/userCache.js +33 -9
- package/lib/commonjs/ui/hooks/queries/userCache.js.map +1 -1
- package/lib/commonjs/ui/hooks/useAvatarPicker.js +23 -8
- package/lib/commonjs/ui/hooks/useAvatarPicker.js.map +1 -1
- package/lib/commonjs/ui/hooks/useFileDownloadUrl.js +7 -21
- package/lib/commonjs/ui/hooks/useFileDownloadUrl.js.map +1 -1
- package/lib/commonjs/ui/hooks/useResolvedFileUrls.js +163 -0
- package/lib/commonjs/ui/hooks/useResolvedFileUrls.js.map +1 -0
- package/lib/commonjs/ui/index.js +1 -1
- package/lib/commonjs/ui/screens/FileManagementScreen.js +51 -22
- package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/fileManagement/PhotoPickerSection.js +216 -203
- package/lib/commonjs/ui/screens/fileManagement/PhotoPickerSection.js.map +1 -1
- package/lib/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.js +26 -9
- package/lib/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.js.map +1 -1
- package/lib/commonjs/ui/screens/fileManagement/photoGridLayout.js +44 -0
- package/lib/commonjs/ui/screens/fileManagement/photoGridLayout.js.map +1 -0
- package/lib/commonjs/ui/session/tokenTransport.js +21 -10
- package/lib/commonjs/ui/session/tokenTransport.js.map +1 -1
- package/lib/commonjs/ui/utils/fileManagement.js +0 -40
- package/lib/commonjs/ui/utils/fileManagement.js.map +1 -1
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/ui/client.js +1 -1
- package/lib/module/ui/client.js.map +1 -1
- package/lib/module/ui/components/FontLoader.js +18 -146
- package/lib/module/ui/components/FontLoader.js.map +1 -1
- package/lib/module/ui/components/FontLoader.native.js +83 -0
- package/lib/module/ui/components/FontLoader.native.js.map +1 -0
- package/lib/module/ui/components/OxyProvider.js +1 -1
- package/lib/module/ui/components/OxyProvider.js.map +1 -1
- package/lib/module/ui/components/fileManagement/FileDetailsModal.js +16 -27
- package/lib/module/ui/components/fileManagement/FileDetailsModal.js.map +1 -1
- package/lib/module/ui/components/fileManagement/UploadPreview.js.map +1 -1
- package/lib/module/ui/components/fileManagement/styles.js +0 -224
- package/lib/module/ui/components/fileManagement/styles.js.map +1 -1
- package/lib/module/ui/context/hooks/useAuthOperations.js +5 -2
- package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -1
- package/lib/module/ui/context/useOxyAccountGraph.js +7 -0
- package/lib/module/ui/context/useOxyAccountGraph.js.map +1 -1
- package/lib/module/ui/hooks/queries/useAccountQueries.js +10 -4
- package/lib/module/ui/hooks/queries/useAccountQueries.js.map +1 -1
- package/lib/module/ui/hooks/queries/userCache.js +33 -9
- package/lib/module/ui/hooks/queries/userCache.js.map +1 -1
- package/lib/module/ui/hooks/useAvatarPicker.js +23 -8
- package/lib/module/ui/hooks/useAvatarPicker.js.map +1 -1
- package/lib/module/ui/hooks/useFileDownloadUrl.js +7 -21
- package/lib/module/ui/hooks/useFileDownloadUrl.js.map +1 -1
- package/lib/module/ui/hooks/useResolvedFileUrls.js +157 -0
- package/lib/module/ui/hooks/useResolvedFileUrls.js.map +1 -0
- package/lib/module/ui/index.js +1 -1
- package/lib/module/ui/index.js.map +1 -1
- package/lib/module/ui/screens/FileManagementScreen.js +52 -23
- package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/module/ui/screens/fileManagement/PhotoPickerSection.js +218 -205
- package/lib/module/ui/screens/fileManagement/PhotoPickerSection.js.map +1 -1
- package/lib/module/ui/screens/fileManagement/hooks/useFileUploadState.js +26 -9
- package/lib/module/ui/screens/fileManagement/hooks/useFileUploadState.js.map +1 -1
- package/lib/module/ui/screens/fileManagement/photoGridLayout.js +39 -0
- package/lib/module/ui/screens/fileManagement/photoGridLayout.js.map +1 -0
- package/lib/module/ui/session/tokenTransport.js +21 -10
- package/lib/module/ui/session/tokenTransport.js.map +1 -1
- package/lib/module/ui/utils/fileManagement.js +0 -39
- package/lib/module/ui/utils/fileManagement.js.map +1 -1
- package/lib/typescript/commonjs/ui/components/FontLoader.d.ts +14 -5
- package/lib/typescript/commonjs/ui/components/FontLoader.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/FontLoader.native.d.ts +13 -0
- package/lib/typescript/commonjs/ui/components/FontLoader.native.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/fileManagement/FileDetailsModal.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/fileManagement/styles.d.ts +0 -218
- package/lib/typescript/commonjs/ui/components/fileManagement/styles.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/useOxyAccountGraph.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/queries/useAccountQueries.d.ts +9 -0
- package/lib/typescript/commonjs/ui/hooks/queries/useAccountQueries.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/queries/userCache.d.ts +3 -0
- package/lib/typescript/commonjs/ui/hooks/queries/userCache.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useAvatarPicker.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useFileDownloadUrl.d.ts +3 -2
- package/lib/typescript/commonjs/ui/hooks/useFileDownloadUrl.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useResolvedFileUrls.d.ts +48 -0
- package/lib/typescript/commonjs/ui/hooks/useResolvedFileUrls.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/screens/FileManagementScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/fileManagement/PhotoPickerSection.d.ts +1 -1
- package/lib/typescript/commonjs/ui/screens/fileManagement/PhotoPickerSection.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/fileManagement/photoGridLayout.d.ts +37 -0
- package/lib/typescript/commonjs/ui/screens/fileManagement/photoGridLayout.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/session/tokenTransport.d.ts +15 -8
- package/lib/typescript/commonjs/ui/session/tokenTransport.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/utils/fileManagement.d.ts +4 -11
- package/lib/typescript/commonjs/ui/utils/fileManagement.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +1 -1
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/ui/client.d.ts +1 -1
- package/lib/typescript/module/ui/client.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/FontLoader.d.ts +14 -5
- package/lib/typescript/module/ui/components/FontLoader.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/FontLoader.native.d.ts +13 -0
- package/lib/typescript/module/ui/components/FontLoader.native.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/fileManagement/FileDetailsModal.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/fileManagement/styles.d.ts +0 -218
- package/lib/typescript/module/ui/components/fileManagement/styles.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/useOxyAccountGraph.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/queries/useAccountQueries.d.ts +9 -0
- package/lib/typescript/module/ui/hooks/queries/useAccountQueries.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/queries/userCache.d.ts +3 -0
- package/lib/typescript/module/ui/hooks/queries/userCache.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useAvatarPicker.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useFileDownloadUrl.d.ts +3 -2
- package/lib/typescript/module/ui/hooks/useFileDownloadUrl.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useResolvedFileUrls.d.ts +48 -0
- package/lib/typescript/module/ui/hooks/useResolvedFileUrls.d.ts.map +1 -0
- package/lib/typescript/module/ui/index.d.ts +1 -1
- package/lib/typescript/module/ui/index.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/FileManagementScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/fileManagement/PhotoPickerSection.d.ts +1 -1
- package/lib/typescript/module/ui/screens/fileManagement/PhotoPickerSection.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/fileManagement/hooks/useFileUploadState.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/fileManagement/photoGridLayout.d.ts +37 -0
- package/lib/typescript/module/ui/screens/fileManagement/photoGridLayout.d.ts.map +1 -0
- package/lib/typescript/module/ui/session/tokenTransport.d.ts +15 -8
- package/lib/typescript/module/ui/session/tokenTransport.d.ts.map +1 -1
- package/lib/typescript/module/ui/utils/fileManagement.d.ts +4 -11
- package/lib/typescript/module/ui/utils/fileManagement.d.ts.map +1 -1
- package/package.json +5 -10
- package/src/ui/components/FontLoader.native.tsx +88 -0
- package/src/ui/components/FontLoader.tsx +16 -151
- package/src/ui/components/fileManagement/FileDetailsModal.tsx +17 -18
- package/src/ui/components/fileManagement/UploadPreview.tsx +1 -1
- package/src/ui/components/fileManagement/styles.ts +0 -225
- package/src/ui/context/hooks/useAuthOperations.ts +5 -2
- package/src/ui/context/useOxyAccountGraph.ts +5 -0
- package/src/ui/hooks/queries/__tests__/userCache.test.ts +29 -0
- package/src/ui/hooks/queries/useAccountQueries.ts +10 -4
- package/src/ui/hooks/queries/userCache.ts +31 -8
- package/src/ui/hooks/useAvatarPicker.ts +27 -7
- package/src/ui/hooks/useFileDownloadUrl.ts +7 -23
- package/src/ui/hooks/useResolvedFileUrls.ts +170 -0
- package/src/ui/screens/FileManagementScreen.tsx +55 -27
- package/src/ui/screens/__tests__/photoGridLayout.test.ts +57 -0
- package/src/ui/screens/fileManagement/PhotoPickerSection.tsx +215 -213
- package/src/ui/screens/fileManagement/hooks/useFileUploadState.ts +27 -3
- package/src/ui/screens/fileManagement/photoGridLayout.ts +45 -0
- package/src/ui/session/__tests__/tokenTransport.test.ts +25 -10
- package/src/ui/session/tokenTransport.ts +21 -10
- package/src/ui/utils/fileManagement.ts +3 -46
- package/lib/typescript/types/expo-vector-icons.d.ts +0 -22
- package/src/types/expo-vector-icons.d.ts +0 -22
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
import { useState, useEffect } from 'react';
|
|
3
|
+
import * as Font from 'expo-font';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Get the Inter font sources for native environments.
|
|
7
|
+
* Loads all static Inter weights bundled with this package.
|
|
8
|
+
*/
|
|
9
|
+
const getInterFonts = () => {
|
|
10
|
+
try {
|
|
11
|
+
return {
|
|
12
|
+
'Inter-Light': require('../../assets/fonts/Inter/Inter_18pt-Light.ttf'),
|
|
13
|
+
'Inter-Regular': require('../../assets/fonts/Inter/Inter_18pt-Regular.ttf'),
|
|
14
|
+
'Inter-Medium': require('../../assets/fonts/Inter/Inter_18pt-Medium.ttf'),
|
|
15
|
+
'Inter-SemiBold': require('../../assets/fonts/Inter/Inter_18pt-SemiBold.ttf'),
|
|
16
|
+
'Inter-Bold': require('../../assets/fonts/Inter/Inter_18pt-Bold.ttf'),
|
|
17
|
+
'Inter-ExtraBold': require('../../assets/fonts/Inter/Inter_18pt-ExtraBold.ttf'),
|
|
18
|
+
'Inter-Black': require('../../assets/fonts/Inter/Inter_18pt-Black.ttf'),
|
|
19
|
+
};
|
|
20
|
+
} catch (error) {
|
|
21
|
+
if (__DEV__) {
|
|
22
|
+
console.warn('Failed to load Inter fonts:', error);
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* FontLoader — loads custom fonts in the background while rendering children
|
|
30
|
+
* immediately with system fonts as fallback until the custom fonts are ready.
|
|
31
|
+
*/
|
|
32
|
+
export const FontLoader = ({
|
|
33
|
+
children,
|
|
34
|
+
}: {
|
|
35
|
+
children: React.ReactNode;
|
|
36
|
+
}) => {
|
|
37
|
+
const [fontState, setFontState] = useState<'loading' | 'loaded' | 'error'>('loading');
|
|
38
|
+
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
const loadFonts = async () => {
|
|
41
|
+
try {
|
|
42
|
+
const interFonts = getInterFonts();
|
|
43
|
+
|
|
44
|
+
if (!interFonts) {
|
|
45
|
+
throw new Error('Inter font files not found');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
await Font.loadAsync(interFonts);
|
|
49
|
+
setFontState('loaded');
|
|
50
|
+
} catch (error) {
|
|
51
|
+
if (__DEV__) {
|
|
52
|
+
console.error('Error loading fonts:', error);
|
|
53
|
+
}
|
|
54
|
+
setFontState('error');
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
loadFonts();
|
|
59
|
+
}, []);
|
|
60
|
+
|
|
61
|
+
if (fontState === 'error' && __DEV__) {
|
|
62
|
+
console.warn('Fonts failed to load. Using system fonts instead.');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return <>{children}</>;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Setup fonts for applications consuming this package on native.
|
|
70
|
+
*/
|
|
71
|
+
export const setupFonts = async (): Promise<boolean> => {
|
|
72
|
+
try {
|
|
73
|
+
const interFonts = getInterFonts();
|
|
74
|
+
|
|
75
|
+
if (!interFonts) {
|
|
76
|
+
throw new Error('Inter font files not found');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
await Font.loadAsync(interFonts);
|
|
80
|
+
return true;
|
|
81
|
+
} catch (error: unknown) {
|
|
82
|
+
if (__DEV__) {
|
|
83
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
84
|
+
console.warn('Error setting up fonts:', errorMessage);
|
|
85
|
+
}
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
@@ -1,162 +1,27 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
|
-
import { useState, useEffect } from 'react';
|
|
3
|
-
import { Platform } from 'react-native';
|
|
4
|
-
import * as Font from 'expo-font';
|
|
5
2
|
|
|
6
3
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
'Inter-Bold': require('../../assets/fonts/Inter/Inter_18pt-Bold.ttf'),
|
|
20
|
-
'Inter-ExtraBold': require('../../assets/fonts/Inter/Inter_18pt-ExtraBold.ttf'),
|
|
21
|
-
'Inter-Black': require('../../assets/fonts/Inter/Inter_18pt-Black.ttf'),
|
|
22
|
-
};
|
|
23
|
-
} catch (error) {
|
|
24
|
-
if (__DEV__) {
|
|
25
|
-
console.warn('Failed to load Inter fonts:', error);
|
|
26
|
-
}
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* FontLoader component that loads custom fonts in the background while rendering children immediately
|
|
33
|
-
* This works in both the package development and when consumed as an npm package
|
|
34
|
-
* Children render immediately with system fonts as fallback until custom fonts are loaded
|
|
4
|
+
* Font loading — clean default (web, SSR, and any bundler that does not pick a
|
|
5
|
+
* platform variant).
|
|
6
|
+
*
|
|
7
|
+
* Web fonts are Bloom's job: `applyFontFaces()` in `@oxyhq/bloom` injects the
|
|
8
|
+
* Inter / BlomusModernus / Geist Mono `@font-face` rules as self-contained
|
|
9
|
+
* base64 data URLs, so there is nothing for this package to load off native.
|
|
10
|
+
* The real implementation lives in `FontLoader.native.tsx`.
|
|
11
|
+
*
|
|
12
|
+
* Keeping this module free of `expo-font` is load-bearing, not incidental:
|
|
13
|
+
* `expo-font/build/serverContext.web.js` imports `node:async_hooks`, which
|
|
14
|
+
* every browser bundler externalizes. A top-level `expo-font` import here
|
|
15
|
+
* therefore throws at module-evaluation time on web and React never mounts.
|
|
35
16
|
*/
|
|
36
17
|
export const FontLoader = ({
|
|
37
18
|
children,
|
|
38
19
|
}: {
|
|
39
20
|
children: React.ReactNode;
|
|
40
|
-
}) => {
|
|
41
|
-
const [fontState, setFontState] = useState<'loading' | 'loaded' | 'error'>('loading');
|
|
42
|
-
|
|
43
|
-
useEffect(() => {
|
|
44
|
-
const loadFonts = async () => {
|
|
45
|
-
try {
|
|
46
|
-
// Get all the font weights
|
|
47
|
-
const interFonts = getInterFonts();
|
|
48
|
-
|
|
49
|
-
if (!interFonts) {
|
|
50
|
-
throw new Error('Inter font files not found');
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Load all the static Inter fonts with their respective weights
|
|
54
|
-
await Font.loadAsync(interFonts);
|
|
55
|
-
|
|
56
|
-
setFontState('loaded');
|
|
57
|
-
} catch (error) {
|
|
58
|
-
if (__DEV__) {
|
|
59
|
-
console.error('Error loading fonts:', error);
|
|
60
|
-
}
|
|
61
|
-
setFontState('error');
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
loadFonts();
|
|
66
|
-
}, []);
|
|
67
|
-
|
|
68
|
-
// Always render children immediately - fonts will load in background
|
|
69
|
-
// If fonts aren't loaded yet, the app will use system fonts as fallback
|
|
70
|
-
if (fontState === 'error' && __DEV__) {
|
|
71
|
-
console.warn('Fonts failed to load. Using system fonts instead.');
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Render children immediately, even while fonts are loading
|
|
75
|
-
// Fonts will apply when they're ready, otherwise system fonts are used
|
|
76
|
-
return <>{children}</>;
|
|
77
|
-
};
|
|
21
|
+
}) => <>{children}</>;
|
|
78
22
|
|
|
79
23
|
/**
|
|
80
|
-
*
|
|
81
|
-
*
|
|
24
|
+
* No-op off native. Returns `true` because setup genuinely succeeded — there is
|
|
25
|
+
* simply nothing to do here — so callers do not log a spurious failure.
|
|
82
26
|
*/
|
|
83
|
-
export const setupFonts = async () =>
|
|
84
|
-
try {
|
|
85
|
-
const interFonts = getInterFonts();
|
|
86
|
-
|
|
87
|
-
if (!interFonts) {
|
|
88
|
-
throw new Error('Inter font files not found');
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (Platform.OS === 'web') {
|
|
92
|
-
// For web platform, dynamically inject CSS to load the fonts
|
|
93
|
-
if (typeof document !== 'undefined') {
|
|
94
|
-
// Create a style element
|
|
95
|
-
const style = document.createElement('style');
|
|
96
|
-
|
|
97
|
-
// Define @font-face rules for each font weight
|
|
98
|
-
const fontFaceRules = `
|
|
99
|
-
@font-face {
|
|
100
|
-
font-family: 'Inter';
|
|
101
|
-
src: url(${interFonts['Inter-Light']}) format('truetype');
|
|
102
|
-
font-weight: 300;
|
|
103
|
-
font-style: normal;
|
|
104
|
-
}
|
|
105
|
-
@font-face {
|
|
106
|
-
font-family: 'Inter';
|
|
107
|
-
src: url(${interFonts['Inter-Regular']}) format('truetype');
|
|
108
|
-
font-weight: 400;
|
|
109
|
-
font-style: normal;
|
|
110
|
-
}
|
|
111
|
-
@font-face {
|
|
112
|
-
font-family: 'Inter';
|
|
113
|
-
src: url(${interFonts['Inter-Medium']}) format('truetype');
|
|
114
|
-
font-weight: 500;
|
|
115
|
-
font-style: normal;
|
|
116
|
-
}
|
|
117
|
-
@font-face {
|
|
118
|
-
font-family: 'Inter';
|
|
119
|
-
src: url(${interFonts['Inter-SemiBold']}) format('truetype');
|
|
120
|
-
font-weight: 600;
|
|
121
|
-
font-style: normal;
|
|
122
|
-
}
|
|
123
|
-
@font-face {
|
|
124
|
-
font-family: 'Inter';
|
|
125
|
-
src: url(${interFonts['Inter-Bold']}) format('truetype');
|
|
126
|
-
font-weight: 700;
|
|
127
|
-
font-style: normal;
|
|
128
|
-
}
|
|
129
|
-
@font-face {
|
|
130
|
-
font-family: 'Inter';
|
|
131
|
-
src: url(${interFonts['Inter-ExtraBold']}) format('truetype');
|
|
132
|
-
font-weight: 800;
|
|
133
|
-
font-style: normal;
|
|
134
|
-
}
|
|
135
|
-
@font-face {
|
|
136
|
-
font-family: 'Inter';
|
|
137
|
-
src: url(${interFonts['Inter-Black']}) format('truetype');
|
|
138
|
-
font-weight: 900;
|
|
139
|
-
font-style: normal;
|
|
140
|
-
}
|
|
141
|
-
`;
|
|
142
|
-
|
|
143
|
-
style.textContent = fontFaceRules;
|
|
144
|
-
document.head.appendChild(style);
|
|
145
|
-
if (__DEV__) {
|
|
146
|
-
console.info('All Inter web fonts have been dynamically loaded');
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
} else {
|
|
150
|
-
// Attempt to load the fonts anyway (this works if the consumer has linked the assets)
|
|
151
|
-
await Font.loadAsync(interFonts);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
return true;
|
|
155
|
-
} catch (error: unknown) {
|
|
156
|
-
if (__DEV__) {
|
|
157
|
-
const errorMessage = error instanceof Error ? (error instanceof Error ? error.message : null) : String(error);
|
|
158
|
-
console.warn('Error setting up fonts:', errorMessage);
|
|
159
|
-
}
|
|
160
|
-
return false;
|
|
161
|
-
}
|
|
162
|
-
};
|
|
27
|
+
export const setupFonts = async (): Promise<boolean> => true;
|
|
@@ -5,7 +5,6 @@ import { Dialog, type DialogControlProps } from '@oxyhq/bloom';
|
|
|
5
5
|
import { useTheme } from '@oxyhq/bloom/theme';
|
|
6
6
|
import type { FileMetadata } from '@oxyhq/core';
|
|
7
7
|
import { formatFileSize, getFileIcon } from '../../utils/fileManagement';
|
|
8
|
-
import { fileManagementStyles } from './styles';
|
|
9
8
|
|
|
10
9
|
interface FileDetailsModalProps {
|
|
11
10
|
control: DialogControlProps;
|
|
@@ -56,53 +55,53 @@ export const FileDetailsModal: React.FC<FileDetailsModalProps> = ({
|
|
|
56
55
|
label="File Details"
|
|
57
56
|
actions={actions}
|
|
58
57
|
>
|
|
59
|
-
<View className="bg-secondary border-border"
|
|
60
|
-
<View
|
|
58
|
+
<View className="bg-secondary border-border p-[18px] rounded-[14px] border items-center">
|
|
59
|
+
<View className="mb-space-16">
|
|
61
60
|
<Ionicons
|
|
62
|
-
name={getFileIcon(file.contentType)
|
|
61
|
+
name={getFileIcon(file.contentType)}
|
|
63
62
|
size={64}
|
|
64
63
|
color={colors.primary}
|
|
65
64
|
/>
|
|
66
65
|
</View>
|
|
67
66
|
|
|
68
|
-
<Text className="text-text"
|
|
67
|
+
<Text className="text-text text-[20px] font-bold text-center mb-space-24">
|
|
69
68
|
{file.filename}
|
|
70
69
|
</Text>
|
|
71
70
|
|
|
72
|
-
<View
|
|
73
|
-
<View
|
|
74
|
-
<Text className="text-text-secondary"
|
|
71
|
+
<View className="w-full mb-space-32">
|
|
72
|
+
<View className="flex-row justify-between items-start mb-space-12 flex-wrap">
|
|
73
|
+
<Text className="text-text-secondary text-[16px] font-medium flex-1 min-w-[100px]">
|
|
75
74
|
Size:
|
|
76
75
|
</Text>
|
|
77
|
-
<Text className="text-text"
|
|
76
|
+
<Text className="text-text text-[16px] flex-[2] text-right">
|
|
78
77
|
{formatFileSize(file.length)}
|
|
79
78
|
</Text>
|
|
80
79
|
</View>
|
|
81
80
|
|
|
82
|
-
<View
|
|
83
|
-
<Text className="text-text-secondary"
|
|
81
|
+
<View className="flex-row justify-between items-start mb-space-12 flex-wrap">
|
|
82
|
+
<Text className="text-text-secondary text-[16px] font-medium flex-1 min-w-[100px]">
|
|
84
83
|
Type:
|
|
85
84
|
</Text>
|
|
86
|
-
<Text className="text-text"
|
|
85
|
+
<Text className="text-text text-[16px] flex-[2] text-right">
|
|
87
86
|
{file.contentType}
|
|
88
87
|
</Text>
|
|
89
88
|
</View>
|
|
90
89
|
|
|
91
|
-
<View
|
|
92
|
-
<Text className="text-text-secondary"
|
|
90
|
+
<View className="flex-row justify-between items-start mb-space-12 flex-wrap">
|
|
91
|
+
<Text className="text-text-secondary text-[16px] font-medium flex-1 min-w-[100px]">
|
|
93
92
|
Uploaded:
|
|
94
93
|
</Text>
|
|
95
|
-
<Text className="text-text"
|
|
94
|
+
<Text className="text-text text-[16px] flex-[2] text-right">
|
|
96
95
|
{new Date(file.uploadDate).toLocaleString()}
|
|
97
96
|
</Text>
|
|
98
97
|
</View>
|
|
99
98
|
|
|
100
99
|
{file.metadata?.description && (
|
|
101
|
-
<View
|
|
102
|
-
<Text className="text-text-secondary"
|
|
100
|
+
<View className="flex-row justify-between items-start mb-space-12 flex-wrap">
|
|
101
|
+
<Text className="text-text-secondary text-[16px] font-medium flex-1 min-w-[100px]">
|
|
103
102
|
Description:
|
|
104
103
|
</Text>
|
|
105
|
-
<Text className="text-text"
|
|
104
|
+
<Text className="text-text text-[16px] flex-[2] text-right">
|
|
106
105
|
{file.metadata.description}
|
|
107
106
|
</Text>
|
|
108
107
|
</View>
|
|
@@ -70,7 +70,7 @@ const UploadPreviewContent: React.FC<{
|
|
|
70
70
|
) : (
|
|
71
71
|
<View style={[fileManagementStyles.uploadPreviewIconContainer, { backgroundColor: colors.backgroundSecondary }]}>
|
|
72
72
|
<Ionicons
|
|
73
|
-
name={getFileIcon(pendingFile.type)
|
|
73
|
+
name={getFileIcon(pendingFile.type)}
|
|
74
74
|
size={32}
|
|
75
75
|
color={colors.primary}
|
|
76
76
|
/>
|
|
@@ -382,43 +382,6 @@ export const fileManagementStyles = StyleSheet.create({
|
|
|
382
382
|
flex: 1,
|
|
383
383
|
padding: 16,
|
|
384
384
|
},
|
|
385
|
-
fileDetailCard: {
|
|
386
|
-
padding: 18,
|
|
387
|
-
borderRadius: 14,
|
|
388
|
-
borderWidth: 1,
|
|
389
|
-
alignItems: 'center',
|
|
390
|
-
},
|
|
391
|
-
fileDetailIcon: {
|
|
392
|
-
marginBottom: 16,
|
|
393
|
-
},
|
|
394
|
-
fileDetailName: {
|
|
395
|
-
fontSize: 20,
|
|
396
|
-
fontWeight: 'bold',
|
|
397
|
-
textAlign: 'center',
|
|
398
|
-
marginBottom: 24,
|
|
399
|
-
},
|
|
400
|
-
fileDetailInfo: {
|
|
401
|
-
width: '100%',
|
|
402
|
-
marginBottom: 32,
|
|
403
|
-
},
|
|
404
|
-
detailRow: {
|
|
405
|
-
flexDirection: 'row',
|
|
406
|
-
justifyContent: 'space-between',
|
|
407
|
-
alignItems: 'flex-start',
|
|
408
|
-
marginBottom: 12,
|
|
409
|
-
flexWrap: 'wrap',
|
|
410
|
-
},
|
|
411
|
-
detailLabel: {
|
|
412
|
-
fontSize: 16,
|
|
413
|
-
fontWeight: '500',
|
|
414
|
-
flex: 1,
|
|
415
|
-
minWidth: 100,
|
|
416
|
-
},
|
|
417
|
-
detailValue: {
|
|
418
|
-
fontSize: 16,
|
|
419
|
-
flex: 2,
|
|
420
|
-
textAlign: 'right',
|
|
421
|
-
},
|
|
422
385
|
modalActions: {
|
|
423
386
|
flexDirection: 'row',
|
|
424
387
|
gap: 12,
|
|
@@ -858,191 +821,3 @@ export const fileManagementStyles = StyleSheet.create({
|
|
|
858
821
|
borderRadius: 8,
|
|
859
822
|
},
|
|
860
823
|
});
|
|
861
|
-
|
|
862
|
-
/**
|
|
863
|
-
* Styles for the dedicated photo picker view used when `selectMode + image-only`
|
|
864
|
-
* is active (e.g. the avatar picker context). This view is intentionally
|
|
865
|
-
* flagship-grade: black backdrop, translucent header, edge-to-edge grid.
|
|
866
|
-
*
|
|
867
|
-
* Kept in a separate StyleSheet so the rest of `fileManagementStyles` does not
|
|
868
|
-
* carry a black-background bias when used elsewhere.
|
|
869
|
-
*/
|
|
870
|
-
export const photoPickerStyles = StyleSheet.create({
|
|
871
|
-
root: {
|
|
872
|
-
flex: 1,
|
|
873
|
-
backgroundColor: '#000000',
|
|
874
|
-
},
|
|
875
|
-
headerSpacer: {
|
|
876
|
-
// Reserved for the absolute header so content does not sit underneath it.
|
|
877
|
-
backgroundColor: '#000000',
|
|
878
|
-
},
|
|
879
|
-
header: {
|
|
880
|
-
position: 'absolute',
|
|
881
|
-
top: 0,
|
|
882
|
-
left: 0,
|
|
883
|
-
right: 0,
|
|
884
|
-
backgroundColor: 'rgba(0,0,0,0.92)',
|
|
885
|
-
flexDirection: 'row',
|
|
886
|
-
alignItems: 'center',
|
|
887
|
-
justifyContent: 'space-between',
|
|
888
|
-
paddingHorizontal: 12,
|
|
889
|
-
zIndex: 30,
|
|
890
|
-
},
|
|
891
|
-
headerRow: {
|
|
892
|
-
flexDirection: 'row',
|
|
893
|
-
alignItems: 'center',
|
|
894
|
-
justifyContent: 'space-between',
|
|
895
|
-
width: '100%',
|
|
896
|
-
// Material 3 top app bar height — leaves a generous tap target for
|
|
897
|
-
// the Cancel / Upload pills without crowding the title.
|
|
898
|
-
height: 56,
|
|
899
|
-
},
|
|
900
|
-
headerSide: {
|
|
901
|
-
flexBasis: 0,
|
|
902
|
-
flexGrow: 1,
|
|
903
|
-
flexDirection: 'row',
|
|
904
|
-
alignItems: 'center',
|
|
905
|
-
},
|
|
906
|
-
headerSideRight: {
|
|
907
|
-
justifyContent: 'flex-end',
|
|
908
|
-
},
|
|
909
|
-
headerSideLeft: {
|
|
910
|
-
justifyContent: 'flex-start',
|
|
911
|
-
},
|
|
912
|
-
headerTitle: {
|
|
913
|
-
fontSize: 17,
|
|
914
|
-
fontWeight: '600',
|
|
915
|
-
color: '#FFFFFF',
|
|
916
|
-
letterSpacing: -0.2,
|
|
917
|
-
textAlign: 'center',
|
|
918
|
-
},
|
|
919
|
-
headerCancel: {
|
|
920
|
-
paddingHorizontal: 6,
|
|
921
|
-
paddingVertical: 8,
|
|
922
|
-
minHeight: 36,
|
|
923
|
-
minWidth: 44,
|
|
924
|
-
justifyContent: 'center',
|
|
925
|
-
},
|
|
926
|
-
headerCancelText: {
|
|
927
|
-
fontSize: 17,
|
|
928
|
-
fontWeight: '500',
|
|
929
|
-
color: '#FFFFFF',
|
|
930
|
-
},
|
|
931
|
-
headerPrimaryPill: {
|
|
932
|
-
flexDirection: 'row',
|
|
933
|
-
alignItems: 'center',
|
|
934
|
-
gap: 6,
|
|
935
|
-
paddingHorizontal: 14,
|
|
936
|
-
paddingVertical: 8,
|
|
937
|
-
borderRadius: 999,
|
|
938
|
-
minHeight: 36,
|
|
939
|
-
},
|
|
940
|
-
headerPrimaryPillIconOnly: {
|
|
941
|
-
paddingHorizontal: 8,
|
|
942
|
-
width: 36,
|
|
943
|
-
justifyContent: 'center',
|
|
944
|
-
},
|
|
945
|
-
headerPrimaryText: {
|
|
946
|
-
color: '#FFFFFF',
|
|
947
|
-
fontSize: 15,
|
|
948
|
-
fontWeight: '600',
|
|
949
|
-
},
|
|
950
|
-
headerProgressBarTrack: {
|
|
951
|
-
position: 'absolute',
|
|
952
|
-
left: 0,
|
|
953
|
-
right: 0,
|
|
954
|
-
bottom: 0,
|
|
955
|
-
height: 2,
|
|
956
|
-
backgroundColor: 'rgba(255,255,255,0.12)',
|
|
957
|
-
},
|
|
958
|
-
headerProgressBarFill: {
|
|
959
|
-
height: '100%',
|
|
960
|
-
},
|
|
961
|
-
grid: {
|
|
962
|
-
flex: 1,
|
|
963
|
-
},
|
|
964
|
-
gridContent: {
|
|
965
|
-
// Top inset is set dynamically (header height + safe area).
|
|
966
|
-
paddingBottom: 24,
|
|
967
|
-
},
|
|
968
|
-
cellWrapper: {
|
|
969
|
-
position: 'relative',
|
|
970
|
-
// width/height set dynamically per device
|
|
971
|
-
},
|
|
972
|
-
cellInner: {
|
|
973
|
-
flex: 1,
|
|
974
|
-
borderRadius: 8,
|
|
975
|
-
overflow: 'hidden',
|
|
976
|
-
backgroundColor: '#111111',
|
|
977
|
-
},
|
|
978
|
-
cellImage: {
|
|
979
|
-
width: '100%',
|
|
980
|
-
height: '100%',
|
|
981
|
-
},
|
|
982
|
-
cellRing: {
|
|
983
|
-
position: 'absolute',
|
|
984
|
-
top: 0,
|
|
985
|
-
left: 0,
|
|
986
|
-
right: 0,
|
|
987
|
-
bottom: 0,
|
|
988
|
-
borderRadius: 8,
|
|
989
|
-
borderWidth: 3,
|
|
990
|
-
},
|
|
991
|
-
cellDim: {
|
|
992
|
-
opacity: 0.6,
|
|
993
|
-
},
|
|
994
|
-
cellBadge: {
|
|
995
|
-
position: 'absolute',
|
|
996
|
-
top: 6,
|
|
997
|
-
right: 6,
|
|
998
|
-
minWidth: 22,
|
|
999
|
-
height: 22,
|
|
1000
|
-
paddingHorizontal: 6,
|
|
1001
|
-
borderRadius: 11,
|
|
1002
|
-
alignItems: 'center',
|
|
1003
|
-
justifyContent: 'center',
|
|
1004
|
-
},
|
|
1005
|
-
cellBadgeText: {
|
|
1006
|
-
color: '#FFFFFF',
|
|
1007
|
-
fontSize: 12,
|
|
1008
|
-
fontWeight: '700',
|
|
1009
|
-
lineHeight: 14,
|
|
1010
|
-
},
|
|
1011
|
-
empty: {
|
|
1012
|
-
flex: 1,
|
|
1013
|
-
alignItems: 'center',
|
|
1014
|
-
justifyContent: 'center',
|
|
1015
|
-
paddingHorizontal: 32,
|
|
1016
|
-
},
|
|
1017
|
-
emptyIconWrap: {
|
|
1018
|
-
opacity: 0.3,
|
|
1019
|
-
marginBottom: 16,
|
|
1020
|
-
},
|
|
1021
|
-
emptyTitle: {
|
|
1022
|
-
fontSize: 17,
|
|
1023
|
-
fontWeight: '600',
|
|
1024
|
-
textAlign: 'center',
|
|
1025
|
-
marginBottom: 6,
|
|
1026
|
-
},
|
|
1027
|
-
emptySubtitle: {
|
|
1028
|
-
fontSize: 14,
|
|
1029
|
-
fontWeight: '400',
|
|
1030
|
-
textAlign: 'center',
|
|
1031
|
-
opacity: 0.7,
|
|
1032
|
-
marginBottom: 24,
|
|
1033
|
-
},
|
|
1034
|
-
emptyCta: {
|
|
1035
|
-
flexDirection: 'row',
|
|
1036
|
-
alignItems: 'center',
|
|
1037
|
-
gap: 8,
|
|
1038
|
-
paddingHorizontal: 22,
|
|
1039
|
-
paddingVertical: 12,
|
|
1040
|
-
borderRadius: 999,
|
|
1041
|
-
},
|
|
1042
|
-
emptyCtaText: {
|
|
1043
|
-
color: '#FFFFFF',
|
|
1044
|
-
fontSize: 15,
|
|
1045
|
-
fontWeight: '600',
|
|
1046
|
-
},
|
|
1047
|
-
});
|
|
1048
|
-
|
|
@@ -170,8 +170,11 @@ export const useAuthOperations = ({
|
|
|
170
170
|
logger?.('Failed to register sign-in into device session set', registrationError);
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
-
//
|
|
174
|
-
|
|
173
|
+
// Hydrate the full user from the bearer (`GET /users/me`) — `verifyChallenge`
|
|
174
|
+
// has already planted the access token for this session, so the bearer IS
|
|
175
|
+
// the session identity. Avoids a second, session-id-keyed source of truth
|
|
176
|
+
// (`GET /session/user/:sessionId`) that can disagree with the bearer.
|
|
177
|
+
fullUser = await oxyServices.getCurrentUser();
|
|
175
178
|
|
|
176
179
|
// Fetch device sessions
|
|
177
180
|
let allDeviceSessions: ClientSession[] = [];
|
|
@@ -5,6 +5,7 @@ import { logger as loggerUtil } from '@oxyhq/core';
|
|
|
5
5
|
import { useAuthStore } from '../stores/authStore';
|
|
6
6
|
import { isUnauthorizedStatus } from './oxyContextHelpers';
|
|
7
7
|
import { resetSessionScopedStores } from '../stores/resetSessionScopedStores';
|
|
8
|
+
import { ASSET_DOWNLOAD_URLS_QUERY_KEY } from '../hooks/useResolvedFileUrls';
|
|
8
9
|
import type { CommitInput } from './oxyContextTypes';
|
|
9
10
|
|
|
10
11
|
interface UseOxyAccountGraphParams {
|
|
@@ -63,6 +64,10 @@ export function useOxyAccountGraph({
|
|
|
63
64
|
|
|
64
65
|
const runPostAccountSwitchSideEffects = useCallback(async (): Promise<void> => {
|
|
65
66
|
resetSessionScopedStores();
|
|
67
|
+
// Scoped media tokens are per-viewer — drop any cached URLs immediately so
|
|
68
|
+
// `keepPreviousData`-style placeholders cannot flash the prior account's
|
|
69
|
+
// private thumbnails while the new bearer mint lands.
|
|
70
|
+
queryClient.removeQueries({ queryKey: [ASSET_DOWNLOAD_URLS_QUERY_KEY] });
|
|
66
71
|
await refreshAccounts();
|
|
67
72
|
queryClient.invalidateQueries();
|
|
68
73
|
}, [refreshAccounts, queryClient]);
|
|
@@ -268,6 +268,35 @@ describe('upsertCachedUser — keys & viewer scoping', () => {
|
|
|
268
268
|
expect(readByUsername(qc, 'alice', 'viewerB')).toBeUndefined();
|
|
269
269
|
});
|
|
270
270
|
|
|
271
|
+
it('never stores viewer-relative relationship on the viewer-independent by-id key', () => {
|
|
272
|
+
const qc = makeClient();
|
|
273
|
+
upsertCachedUser(
|
|
274
|
+
qc,
|
|
275
|
+
{ id: 'u1', username: 'alice', relationship: { isFollowing: true, followsYou: true } },
|
|
276
|
+
'viewerA',
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
expect(readById(qc, 'u1')?.relationship).toBeUndefined();
|
|
280
|
+
expect(readByUsername(qc, 'alice', 'viewerA')?.relationship).toEqual({
|
|
281
|
+
isFollowing: true,
|
|
282
|
+
followsYou: true,
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
it('strips a stale relationship from an existing by-id entry on merge', () => {
|
|
287
|
+
const qc = makeClient();
|
|
288
|
+
qc.setQueryData(queryKeys.users.detail('u1'), {
|
|
289
|
+
id: 'u1',
|
|
290
|
+
username: 'alice',
|
|
291
|
+
relationship: { isFollowing: true, followsYou: true },
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
upsertCachedUser(qc, { id: 'u1', username: 'alice', avatar: 'file_a' }, 'viewerA');
|
|
295
|
+
|
|
296
|
+
expect(readById(qc, 'u1')?.relationship).toBeUndefined();
|
|
297
|
+
expect(readById(qc, 'u1')?.avatar).toBe('file_a');
|
|
298
|
+
});
|
|
299
|
+
|
|
271
300
|
it('is case-insensitive on username (byUsername normalization)', () => {
|
|
272
301
|
const qc = makeClient();
|
|
273
302
|
upsertCachedUser(qc, { id: 'u1', username: 'AlIcE' }, 'v1');
|