@umituz/react-native-design-system 4.25.8 → 4.25.10
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/package.json +1 -1
- package/src/atoms/AtomicAvatar.tsx +0 -5
- package/src/atoms/AtomicInput.tsx +0 -2
- package/src/atoms/AtomicProgress.tsx +0 -5
- package/src/atoms/AtomicTextArea.tsx +0 -4
- package/src/atoms/card/AtomicCard.tsx +111 -54
- package/src/atoms/input/types.ts +0 -2
- package/src/atoms/skeleton/AtomicSkeleton.tsx +2 -2
- package/src/image/presentation/components/ImageGallery.tsx +16 -15
- package/src/image/presentation/components/editor/StickerPickerSheet.tsx +4 -7
- package/src/index.ts +5 -0
- package/src/layouts/ScreenHeader/ScreenHeader.tsx +0 -2
- package/src/loading/presentation/providers/LoadingProvider.tsx +13 -4
- package/src/molecules/SearchBar/SearchBar.tsx +0 -2
- package/src/molecules/SearchBar/SearchSuggestions.tsx +1 -1
- package/src/molecules/SearchBar/types.ts +0 -1
- package/src/molecules/StepHeader/StepHeader.tsx +1 -1
- package/src/molecules/avatar/Avatar.tsx +76 -71
- package/src/molecules/avatar/AvatarGroup.tsx +1 -1
- package/src/molecules/calendar/presentation/components/CalendarDayCell.tsx +2 -3
- package/src/molecules/calendar/presentation/components/CalendarWeekdayHeader.tsx +1 -1
- package/src/molecules/countdown/components/Countdown.tsx +14 -11
- package/src/molecules/info-grid/InfoGrid.tsx +2 -2
- package/src/onboarding/presentation/components/BackgroundImageCollage.tsx +2 -2
- package/src/onboarding/presentation/components/OnboardingBackground.tsx +63 -49
- package/src/onboarding/presentation/components/OnboardingSlide.tsx +2 -2
- package/src/theme/infrastructure/providers/DesignSystemProvider.tsx +3 -1
- package/src/gallery/gallery-download.service.ts +0 -69
- package/src/gallery/gallery-save.service.ts +0 -80
- package/src/gallery/index.ts +0 -3
- package/src/gallery/types.ts +0 -11
- package/src/image/domain/entities/EditorTypes.ts +0 -23
- package/src/image/domain/entities/editor/EditorConfigTypes.ts +0 -35
- package/src/image/domain/entities/editor/EditorElementTypes.ts +0 -60
- package/src/image/domain/entities/editor/EditorFilterTypes.ts +0 -9
- package/src/image/domain/entities/editor/EditorLayerTypes.ts +0 -34
- package/src/image/domain/entities/editor/EditorStateTypes.ts +0 -35
- package/src/image/domain/entities/editor/EditorToolTypes.ts +0 -33
- package/src/image/infrastructure/services/ImageEditorService.ts +0 -134
- package/src/image/infrastructure/utils/ImageAnalysisUtils.ts +0 -120
- package/src/image/infrastructure/utils/ImageEditorHistoryUtils.ts +0 -63
- package/src/image/infrastructure/utils/LayerManager.ts +0 -65
- package/src/media/infrastructure/hooks/useGenericMediaGeneration.ts +0 -170
- package/src/molecules/ConfirmationModal.tsx +0 -42
- package/src/molecules/calendar/infrastructure/storage/CalendarStore.types.ts +0 -64
- package/src/molecules/calendar/infrastructure/storage/CalendarStore.utils.ts +0 -56
- package/src/molecules/calendar/infrastructure/storage/EventActions.ts +0 -140
- package/src/molecules/calendar/infrastructure/storage/NavigationActions.ts +0 -118
- package/src/molecules/calendar/presentation/hooks/useCalendar.ts +0 -185
- package/src/molecules/confirmation-modal/index.ts +0 -7
- package/src/molecules/listitem/index.ts +0 -6
- package/src/molecules/navigation/components/index.ts +0 -4
- package/src/molecules/navigation/utils/NavigationTheme.ts +0 -21
- package/src/presentation/utils/variants/compound.ts +0 -34
- package/src/services/api/ApiClient.ts +0 -180
- package/src/services/api/index.ts +0 -9
- package/src/services/api/types/ApiTypes.ts +0 -50
- package/src/services/api/utils/requestBuilder.ts +0 -92
- package/src/services/api/utils/responseHandler.ts +0 -130
- package/src/storage/cache/index.ts +0 -28
- package/src/theme/core/tokens/BorderRadius.ts +0 -16
- package/src/utilities/clipboard/ClipboardUtils.ts +0 -67
- package/src/utilities/clipboard/index.ts +0 -5
- package/src/utilities/index.ts +0 -6
- package/src/utilities/sharing/domain/entities/Share.ts +0 -104
- package/src/utilities/sharing/domain/entities/SharingUtils.ts +0 -111
- package/src/utilities/sharing/index.ts +0 -33
- package/src/utilities/sharing/infrastructure/services/SharingService.ts +0 -165
- package/src/utilities/sharing/presentation/hooks/useSharing.ts +0 -116
- package/src/utils/colorMapper.ts +0 -193
- package/src/utils/errors/adapters/CacheErrorAdapter.ts +0 -68
- package/src/utils/errors/adapters/ImageErrorAdapter.ts +0 -91
- package/src/utils/errors/adapters/StorageErrorAdapter.ts +0 -107
- package/src/utils/formatHelper.ts +0 -16
- package/src/utils/formatters/dateFormatter.ts +0 -64
- package/src/utils/formatters/numberFormatter.ts +0 -130
- package/src/utils/index.ts +0 -16
- package/src/utils/styleComposer.ts +0 -94
- package/src/utils/validationHelper.ts +0 -16
- package/src/utils/validators/dataValidators.ts +0 -111
- package/src/utils/validators/numericValidators.ts +0 -106
- package/src/utils/validators/stringValidators.ts +0 -85
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Response Handler Utility
|
|
3
|
-
* Handles API responses and errors
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { ApiResponse, ApiError } from '../types/ApiTypes';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Parses fetch response to ApiResponse
|
|
10
|
-
*
|
|
11
|
-
* @param response - Fetch response
|
|
12
|
-
* @returns Parsed API response
|
|
13
|
-
*/
|
|
14
|
-
export async function parseResponse<T>(response: Response): Promise<ApiResponse<T>> {
|
|
15
|
-
const data = await parseResponseBody<T>(response);
|
|
16
|
-
|
|
17
|
-
return {
|
|
18
|
-
data,
|
|
19
|
-
status: response.status,
|
|
20
|
-
statusText: response.statusText,
|
|
21
|
-
headers: Object.fromEntries(response.headers.entries()),
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Parses response body based on content type
|
|
27
|
-
*
|
|
28
|
-
* @param response - Fetch response
|
|
29
|
-
* @returns Parsed body data
|
|
30
|
-
*/
|
|
31
|
-
async function parseResponseBody<T>(response: Response): Promise<T> {
|
|
32
|
-
const contentType = response.headers.get('Content-Type');
|
|
33
|
-
|
|
34
|
-
if (contentType?.includes('application/json')) {
|
|
35
|
-
const data = await response.json();
|
|
36
|
-
return data as T;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (contentType?.includes('text/')) {
|
|
40
|
-
const text = await response.text();
|
|
41
|
-
return text as unknown as T;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const blob = await response.blob();
|
|
45
|
-
return blob as unknown as T;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Handles HTTP error and converts to ApiError
|
|
50
|
-
*
|
|
51
|
-
* @param response - Fetch response
|
|
52
|
-
* @returns ApiError object
|
|
53
|
-
*/
|
|
54
|
-
export async function handleHttpError(response: Response): Promise<ApiError> {
|
|
55
|
-
let details: any;
|
|
56
|
-
|
|
57
|
-
try {
|
|
58
|
-
details = await response.json();
|
|
59
|
-
} catch {
|
|
60
|
-
details = await response.text();
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return {
|
|
64
|
-
message: details?.message || response.statusText || 'Request failed',
|
|
65
|
-
status: response.status,
|
|
66
|
-
code: details?.code,
|
|
67
|
-
details,
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Handles network error
|
|
73
|
-
*
|
|
74
|
-
* @param error - Error object
|
|
75
|
-
* @returns ApiError object
|
|
76
|
-
*/
|
|
77
|
-
export function handleNetworkError(error: unknown): ApiError {
|
|
78
|
-
if (error instanceof Error) {
|
|
79
|
-
return {
|
|
80
|
-
message: error.message || 'Network error',
|
|
81
|
-
details: error,
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return {
|
|
86
|
-
message: 'Unknown network error',
|
|
87
|
-
details: error,
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Checks if response is successful
|
|
93
|
-
*
|
|
94
|
-
* @param response - Fetch response
|
|
95
|
-
* @returns True if response is OK
|
|
96
|
-
*/
|
|
97
|
-
export function isSuccessfulResponse(response: Response): boolean {
|
|
98
|
-
return response.ok && response.status >= 200 && response.status < 300;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Creates timeout promise
|
|
103
|
-
*
|
|
104
|
-
* @param ms - Timeout in milliseconds
|
|
105
|
-
* @returns Promise that rejects after timeout
|
|
106
|
-
*/
|
|
107
|
-
export function createTimeoutPromise(ms: number): Promise<never> {
|
|
108
|
-
return new Promise((_, reject) => {
|
|
109
|
-
setTimeout(() => reject(new Error(`Request timeout after ${ms}ms`)), ms);
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Wraps fetch with timeout
|
|
115
|
-
*
|
|
116
|
-
* @param url - Request URL
|
|
117
|
-
* @param options - Fetch options
|
|
118
|
-
* @param timeout - Timeout in milliseconds
|
|
119
|
-
* @returns Fetch result with timeout
|
|
120
|
-
*/
|
|
121
|
-
export async function fetchWithTimeout(
|
|
122
|
-
url: string,
|
|
123
|
-
options: RequestInit,
|
|
124
|
-
timeout: number
|
|
125
|
-
): Promise<Response> {
|
|
126
|
-
return Promise.race([
|
|
127
|
-
fetch(url, options),
|
|
128
|
-
createTimeoutPromise(timeout),
|
|
129
|
-
]) as Promise<Response>;
|
|
130
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @umituz/react-native-cache
|
|
3
|
-
* In-memory caching utilities for React Native
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export { Cache } from './domain/Cache';
|
|
7
|
-
export { CacheManager, cacheManager } from './domain/CacheManager';
|
|
8
|
-
export { CacheStatsTracker } from './domain/CacheStatsTracker';
|
|
9
|
-
export { PatternMatcher } from './domain/PatternMatcher';
|
|
10
|
-
export { ErrorHandler, CacheError } from './domain/ErrorHandler';
|
|
11
|
-
export { TTLCache } from './infrastructure/TTLCache';
|
|
12
|
-
|
|
13
|
-
export type {
|
|
14
|
-
CacheEntry,
|
|
15
|
-
CacheConfig,
|
|
16
|
-
CacheStats,
|
|
17
|
-
EvictionStrategy,
|
|
18
|
-
} from './domain/types/Cache';
|
|
19
|
-
|
|
20
|
-
export type { EvictionStrategy as IEvictionStrategy } from './domain/strategies/EvictionStrategy';
|
|
21
|
-
|
|
22
|
-
export { LRUStrategy } from './domain/strategies/LRUStrategy';
|
|
23
|
-
export { LFUStrategy } from './domain/strategies/LFUStrategy';
|
|
24
|
-
export { FIFOStrategy } from './domain/strategies/FIFOStrategy';
|
|
25
|
-
export { TTLStrategy as TTLEvictionStrategy } from './domain/strategies/TTLStrategy';
|
|
26
|
-
|
|
27
|
-
export { useCache } from './presentation/useCache';
|
|
28
|
-
export { useCachedValue } from './presentation/useCachedValue';
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Border Radius Tokens
|
|
3
|
-
* Single Responsibility: Define border radius scale
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export const borderRadius = {
|
|
7
|
-
none: 0,
|
|
8
|
-
sm: 4,
|
|
9
|
-
md: 8,
|
|
10
|
-
lg: 12,
|
|
11
|
-
xl: 20,
|
|
12
|
-
xxl: 24,
|
|
13
|
-
full: 9999,
|
|
14
|
-
} as const;
|
|
15
|
-
|
|
16
|
-
export type BorderRadius = typeof borderRadius;
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Clipboard Utilities
|
|
3
|
-
*
|
|
4
|
-
* Simple wrapper around expo-clipboard for copy/paste functionality
|
|
5
|
-
*
|
|
6
|
-
* Usage:
|
|
7
|
-
* ```typescript
|
|
8
|
-
* import { ClipboardUtils } from '@umituz/react-native-design-system';
|
|
9
|
-
*
|
|
10
|
-
* // Copy text
|
|
11
|
-
* await ClipboardUtils.copyToClipboard('Hello World');
|
|
12
|
-
*
|
|
13
|
-
* // Paste text
|
|
14
|
-
* const text = await ClipboardUtils.getFromClipboard();
|
|
15
|
-
*
|
|
16
|
-
* // Check if clipboard has content
|
|
17
|
-
* const hasContent = await ClipboardUtils.hasContent();
|
|
18
|
-
* ```
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
import * as Clipboard from 'expo-clipboard';
|
|
22
|
-
|
|
23
|
-
export class ClipboardUtils {
|
|
24
|
-
/**
|
|
25
|
-
* Copy text to clipboard
|
|
26
|
-
*/
|
|
27
|
-
static async copyToClipboard(text: string): Promise<void> {
|
|
28
|
-
try {
|
|
29
|
-
await Clipboard.setStringAsync(text);
|
|
30
|
-
} catch (error) {
|
|
31
|
-
throw error;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Get text from clipboard
|
|
37
|
-
*/
|
|
38
|
-
static async getFromClipboard(): Promise<string> {
|
|
39
|
-
try {
|
|
40
|
-
return await Clipboard.getStringAsync();
|
|
41
|
-
} catch (error) {
|
|
42
|
-
throw error;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Check if clipboard has content
|
|
48
|
-
*/
|
|
49
|
-
static async hasContent(): Promise<boolean> {
|
|
50
|
-
try {
|
|
51
|
-
return await Clipboard.hasStringAsync();
|
|
52
|
-
} catch {
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Clear clipboard
|
|
59
|
-
*/
|
|
60
|
-
static async clear(): Promise<void> {
|
|
61
|
-
try {
|
|
62
|
-
await Clipboard.setStringAsync('');
|
|
63
|
-
} catch (error) {
|
|
64
|
-
throw error;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
package/src/utilities/index.ts
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sharing Domain - Core Entities
|
|
3
|
-
*
|
|
4
|
-
* This file defines core types and interfaces for sharing functionality.
|
|
5
|
-
* Handles system share sheet using expo-sharing.
|
|
6
|
-
*
|
|
7
|
-
* @domain sharing
|
|
8
|
-
* @layer domain/entities
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Share options for sharing content
|
|
13
|
-
*/
|
|
14
|
-
export interface ShareOptions {
|
|
15
|
-
/**
|
|
16
|
-
* Dialog title (Android only)
|
|
17
|
-
*/
|
|
18
|
-
dialogTitle?: string;
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* MIME type of the file being shared
|
|
22
|
-
*/
|
|
23
|
-
mimeType?: string;
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* UTI (Uniform Type Identifier) for the file (iOS only)
|
|
27
|
-
*/
|
|
28
|
-
UTI?: string;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Share result
|
|
33
|
-
*/
|
|
34
|
-
export interface ShareResult {
|
|
35
|
-
success: boolean;
|
|
36
|
-
error?: string;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Common MIME types for sharing
|
|
41
|
-
*/
|
|
42
|
-
export const MIME_TYPES = {
|
|
43
|
-
// Images
|
|
44
|
-
IMAGE_JPEG: 'image/jpeg',
|
|
45
|
-
IMAGE_PNG: 'image/png',
|
|
46
|
-
IMAGE_GIF: 'image/gif',
|
|
47
|
-
IMAGE_WEBP: 'image/webp',
|
|
48
|
-
|
|
49
|
-
// Videos
|
|
50
|
-
VIDEO_MP4: 'video/mp4',
|
|
51
|
-
VIDEO_QUICKTIME: 'video/quicktime',
|
|
52
|
-
VIDEO_AVI: 'video/avi',
|
|
53
|
-
|
|
54
|
-
// Audio
|
|
55
|
-
AUDIO_MP3: 'audio/mpeg',
|
|
56
|
-
AUDIO_WAV: 'audio/wav',
|
|
57
|
-
AUDIO_AAC: 'audio/aac',
|
|
58
|
-
|
|
59
|
-
// Documents
|
|
60
|
-
PDF: 'application/pdf',
|
|
61
|
-
TEXT: 'text/plain',
|
|
62
|
-
JSON: 'application/json',
|
|
63
|
-
ZIP: 'application/zip',
|
|
64
|
-
|
|
65
|
-
// Generic
|
|
66
|
-
OCTET_STREAM: 'application/octet-stream',
|
|
67
|
-
} as const;
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* iOS UTI (Uniform Type Identifiers)
|
|
71
|
-
*/
|
|
72
|
-
export const UTI_TYPES = {
|
|
73
|
-
// Images
|
|
74
|
-
IMAGE: 'public.image',
|
|
75
|
-
JPEG: 'public.jpeg',
|
|
76
|
-
PNG: 'public.png',
|
|
77
|
-
|
|
78
|
-
// Videos
|
|
79
|
-
VIDEO: 'public.video',
|
|
80
|
-
MOVIE: 'public.movie',
|
|
81
|
-
|
|
82
|
-
// Audio
|
|
83
|
-
AUDIO: 'public.audio',
|
|
84
|
-
MP3: 'public.mp3',
|
|
85
|
-
|
|
86
|
-
// Documents
|
|
87
|
-
PDF: 'com.adobe.pdf',
|
|
88
|
-
TEXT: 'public.text',
|
|
89
|
-
JSON: 'public.json',
|
|
90
|
-
|
|
91
|
-
// Generic
|
|
92
|
-
DATA: 'public.data',
|
|
93
|
-
CONTENT: 'public.content',
|
|
94
|
-
} as const;
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Sharing constants
|
|
98
|
-
*/
|
|
99
|
-
export const SHARING_CONSTANTS = {
|
|
100
|
-
DEFAULT_DIALOG_TITLE: 'Share',
|
|
101
|
-
DEFAULT_MIME_TYPE: MIME_TYPES.OCTET_STREAM,
|
|
102
|
-
} as const;
|
|
103
|
-
|
|
104
|
-
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sharing Utilities
|
|
3
|
-
* Helper functions for sharing functionality
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { MIME_TYPES, UTI_TYPES, SHARING_CONSTANTS, ShareOptions } from './Share';
|
|
7
|
-
|
|
8
|
-
export class SharingUtils {
|
|
9
|
-
/**
|
|
10
|
-
* Get MIME type from file extension
|
|
11
|
-
*/
|
|
12
|
-
static getMimeTypeFromExtension(filename: string): string {
|
|
13
|
-
const extension = filename.split('.').pop()?.toLowerCase();
|
|
14
|
-
|
|
15
|
-
switch (extension) {
|
|
16
|
-
// Images
|
|
17
|
-
case 'jpg':
|
|
18
|
-
case 'jpeg':
|
|
19
|
-
return MIME_TYPES.IMAGE_JPEG;
|
|
20
|
-
case 'png':
|
|
21
|
-
return MIME_TYPES.IMAGE_PNG;
|
|
22
|
-
case 'gif':
|
|
23
|
-
return MIME_TYPES.IMAGE_GIF;
|
|
24
|
-
case 'webp':
|
|
25
|
-
return MIME_TYPES.IMAGE_WEBP;
|
|
26
|
-
|
|
27
|
-
// Videos
|
|
28
|
-
case 'mp4':
|
|
29
|
-
return MIME_TYPES.VIDEO_MP4;
|
|
30
|
-
case 'mov':
|
|
31
|
-
return MIME_TYPES.VIDEO_QUICKTIME;
|
|
32
|
-
case 'avi':
|
|
33
|
-
return MIME_TYPES.VIDEO_AVI;
|
|
34
|
-
|
|
35
|
-
// Audio
|
|
36
|
-
case 'mp3':
|
|
37
|
-
return MIME_TYPES.AUDIO_MP3;
|
|
38
|
-
case 'wav':
|
|
39
|
-
return MIME_TYPES.AUDIO_WAV;
|
|
40
|
-
case 'aac':
|
|
41
|
-
return MIME_TYPES.AUDIO_AAC;
|
|
42
|
-
|
|
43
|
-
// Documents
|
|
44
|
-
case 'pdf':
|
|
45
|
-
return MIME_TYPES.PDF;
|
|
46
|
-
case 'txt':
|
|
47
|
-
return MIME_TYPES.TEXT;
|
|
48
|
-
case 'json':
|
|
49
|
-
return MIME_TYPES.JSON;
|
|
50
|
-
case 'zip':
|
|
51
|
-
return MIME_TYPES.ZIP;
|
|
52
|
-
|
|
53
|
-
default:
|
|
54
|
-
return MIME_TYPES.OCTET_STREAM;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Get UTI from file extension (iOS)
|
|
60
|
-
*/
|
|
61
|
-
static getUTIFromExtension(filename: string): string {
|
|
62
|
-
const extension = filename.split('.').pop()?.toLowerCase();
|
|
63
|
-
|
|
64
|
-
switch (extension) {
|
|
65
|
-
// Images
|
|
66
|
-
case 'jpg':
|
|
67
|
-
case 'jpeg':
|
|
68
|
-
return UTI_TYPES.JPEG;
|
|
69
|
-
case 'png':
|
|
70
|
-
return UTI_TYPES.PNG;
|
|
71
|
-
case 'gif':
|
|
72
|
-
case 'webp':
|
|
73
|
-
return UTI_TYPES.IMAGE;
|
|
74
|
-
|
|
75
|
-
// Videos
|
|
76
|
-
case 'mp4':
|
|
77
|
-
case 'mov':
|
|
78
|
-
case 'avi':
|
|
79
|
-
return UTI_TYPES.VIDEO;
|
|
80
|
-
|
|
81
|
-
// Audio
|
|
82
|
-
case 'mp3':
|
|
83
|
-
return UTI_TYPES.MP3;
|
|
84
|
-
case 'wav':
|
|
85
|
-
case 'aac':
|
|
86
|
-
return UTI_TYPES.AUDIO;
|
|
87
|
-
|
|
88
|
-
// Documents
|
|
89
|
-
case 'pdf':
|
|
90
|
-
return UTI_TYPES.PDF;
|
|
91
|
-
case 'txt':
|
|
92
|
-
return UTI_TYPES.TEXT;
|
|
93
|
-
case 'json':
|
|
94
|
-
return UTI_TYPES.JSON;
|
|
95
|
-
|
|
96
|
-
default:
|
|
97
|
-
return UTI_TYPES.DATA;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Prepare share options from filename
|
|
103
|
-
*/
|
|
104
|
-
static prepareShareOptions(filename: string, dialogTitle?: string): ShareOptions {
|
|
105
|
-
return {
|
|
106
|
-
dialogTitle: dialogTitle || SHARING_CONSTANTS.DEFAULT_DIALOG_TITLE,
|
|
107
|
-
mimeType: SharingUtils.getMimeTypeFromExtension(filename),
|
|
108
|
-
UTI: SharingUtils.getUTIFromExtension(filename),
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sharing Domain - Barrel Export
|
|
3
|
-
* Provides system share sheet functionality using expo-sharing.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// ============================================================================
|
|
7
|
-
// DOMAIN LAYER - ENTITIES
|
|
8
|
-
// ============================================================================
|
|
9
|
-
|
|
10
|
-
export type {
|
|
11
|
-
ShareOptions,
|
|
12
|
-
ShareResult,
|
|
13
|
-
} from './domain/entities/Share';
|
|
14
|
-
|
|
15
|
-
export {
|
|
16
|
-
MIME_TYPES,
|
|
17
|
-
UTI_TYPES,
|
|
18
|
-
SHARING_CONSTANTS,
|
|
19
|
-
} from './domain/entities/Share';
|
|
20
|
-
|
|
21
|
-
export { SharingUtils } from './domain/entities/SharingUtils';
|
|
22
|
-
|
|
23
|
-
// ============================================================================
|
|
24
|
-
// INFRASTRUCTURE LAYER - SERVICES
|
|
25
|
-
// ============================================================================
|
|
26
|
-
|
|
27
|
-
export { SharingService } from './infrastructure/services/SharingService';
|
|
28
|
-
|
|
29
|
-
// ============================================================================
|
|
30
|
-
// PRESENTATION LAYER - HOOKS
|
|
31
|
-
// ============================================================================
|
|
32
|
-
|
|
33
|
-
export { useSharing } from './presentation/hooks/useSharing';
|
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sharing Domain - Sharing Service
|
|
3
|
-
*
|
|
4
|
-
* Service for sharing files using expo-sharing.
|
|
5
|
-
* Provides abstraction layer for system share sheet.
|
|
6
|
-
*
|
|
7
|
-
* @domain sharing
|
|
8
|
-
* @layer infrastructure/services
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import * as Sharing from 'expo-sharing';
|
|
12
|
-
import { FileSystemService } from '../../../../filesystem';
|
|
13
|
-
import type { ShareOptions, ShareResult } from '../../domain/entities/Share';
|
|
14
|
-
import { SharingUtils } from '../../domain/entities/SharingUtils';
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Sharing service for sharing files via system share sheet
|
|
18
|
-
*/
|
|
19
|
-
export class SharingService {
|
|
20
|
-
/**
|
|
21
|
-
* Check if sharing is available on device
|
|
22
|
-
*/
|
|
23
|
-
static async isAvailable(): Promise<boolean> {
|
|
24
|
-
try {
|
|
25
|
-
return await Sharing.isAvailableAsync();
|
|
26
|
-
} catch {
|
|
27
|
-
return false;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Share a file via system share sheet
|
|
33
|
-
*
|
|
34
|
-
* @param uri - File URI to share (can be local or remote http/https)
|
|
35
|
-
* @param options - Share options (dialog title, MIME type, UTI)
|
|
36
|
-
* @returns ShareResult with success status
|
|
37
|
-
*
|
|
38
|
-
* USAGE:
|
|
39
|
-
* ```typescript
|
|
40
|
-
* // Basic share (local)
|
|
41
|
-
* await SharingService.shareFile('file:///path/to/image.jpg');
|
|
42
|
-
*
|
|
43
|
-
* // Remote file (will be downloaded)
|
|
44
|
-
* await SharingService.shareFile('https://example.com/image.jpg');
|
|
45
|
-
* ```
|
|
46
|
-
*/
|
|
47
|
-
static async shareFile(uri: string, options?: ShareOptions): Promise<ShareResult> {
|
|
48
|
-
try {
|
|
49
|
-
// Check availability
|
|
50
|
-
const available = await SharingService.isAvailable();
|
|
51
|
-
if (!available) {
|
|
52
|
-
return {
|
|
53
|
-
success: false,
|
|
54
|
-
error: 'Sharing is not available on this device',
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
let shareUri = uri;
|
|
59
|
-
|
|
60
|
-
// Handle remote URLs
|
|
61
|
-
if (uri.startsWith('http://') || uri.startsWith('https://')) {
|
|
62
|
-
try {
|
|
63
|
-
const filename = uri.split('/').pop()?.split('?')[0] || `share-${Date.now()}`;
|
|
64
|
-
// Ensure we have an extension if possible, or default to bin/jpg?
|
|
65
|
-
// Better to rely on what we have, or let the caller specify mimeType to infer extension?
|
|
66
|
-
// For now, nice and simple:
|
|
67
|
-
const localUri = FileSystemService.generateFilePath(filename);
|
|
68
|
-
const result = await FileSystemService.downloadFile(uri, localUri);
|
|
69
|
-
|
|
70
|
-
if (!result.success) {
|
|
71
|
-
return { success: false, error: result.error || 'Failed to download file' };
|
|
72
|
-
}
|
|
73
|
-
shareUri = result.uri!;
|
|
74
|
-
} catch (downloadError) {
|
|
75
|
-
return {
|
|
76
|
-
success: false,
|
|
77
|
-
error: downloadError instanceof Error ? downloadError.message : 'Failed to download file'
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Share file
|
|
83
|
-
await Sharing.shareAsync(shareUri, options);
|
|
84
|
-
|
|
85
|
-
return { success: true };
|
|
86
|
-
} catch (error) {
|
|
87
|
-
return {
|
|
88
|
-
success: false,
|
|
89
|
-
error: error instanceof Error ? error.message : 'Failed to share file',
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Share a file with automatic MIME type detection
|
|
96
|
-
*
|
|
97
|
-
* @param uri - File URI to share
|
|
98
|
-
* @param filename - Filename (used for MIME type detection)
|
|
99
|
-
* @param dialogTitle - Optional dialog title (Android)
|
|
100
|
-
* @returns ShareResult with success status
|
|
101
|
-
*
|
|
102
|
-
* USAGE:
|
|
103
|
-
* ```typescript
|
|
104
|
-
* // Auto-detect MIME type from filename
|
|
105
|
-
* await SharingService.shareWithAutoType(
|
|
106
|
-
* 'file:///path/to/file.jpg',
|
|
107
|
-
* 'photo.jpg',
|
|
108
|
-
* 'Share Photo'
|
|
109
|
-
* );
|
|
110
|
-
* ```
|
|
111
|
-
*/
|
|
112
|
-
static async shareWithAutoType(
|
|
113
|
-
uri: string,
|
|
114
|
-
filename: string,
|
|
115
|
-
dialogTitle?: string
|
|
116
|
-
): Promise<ShareResult> {
|
|
117
|
-
const options = SharingUtils.prepareShareOptions(filename, dialogTitle);
|
|
118
|
-
return await SharingService.shareFile(uri, options);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Share multiple files (if supported)
|
|
123
|
-
*
|
|
124
|
-
* NOTE: expo-sharing currently only supports sharing one file at a time.
|
|
125
|
-
* This method shares files sequentially.
|
|
126
|
-
*
|
|
127
|
-
* @param uris - Array of file URIs to share
|
|
128
|
-
* @param options - Share options
|
|
129
|
-
* @returns ShareResult with success status
|
|
130
|
-
*/
|
|
131
|
-
static async shareMultipleFiles(
|
|
132
|
-
uris: string[],
|
|
133
|
-
options?: ShareOptions
|
|
134
|
-
): Promise<ShareResult> {
|
|
135
|
-
try {
|
|
136
|
-
if (uris.length === 0) {
|
|
137
|
-
return {
|
|
138
|
-
success: false,
|
|
139
|
-
error: 'No files to share',
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// Check availability
|
|
144
|
-
const available = await SharingService.isAvailable();
|
|
145
|
-
if (!available) {
|
|
146
|
-
return {
|
|
147
|
-
success: false,
|
|
148
|
-
error: 'Sharing is not available on this device',
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// Share files sequentially
|
|
153
|
-
for (const uri of uris) {
|
|
154
|
-
await Sharing.shareAsync(uri, options);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
return { success: true };
|
|
158
|
-
} catch (error) {
|
|
159
|
-
return {
|
|
160
|
-
success: false,
|
|
161
|
-
error: error instanceof Error ? error.message : 'Failed to share files',
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|