@umituz/react-native-design-system 4.23.97 → 4.23.101
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/AtomicInput.tsx +0 -2
- package/src/atoms/button/AtomicButton.tsx +7 -0
- package/src/atoms/button/types/index.ts +4 -0
- package/src/atoms/input/hooks/useInputState.ts +3 -7
- package/src/haptics/infrastructure/services/HapticService.ts +1 -1
- package/src/media/domain/entities/{MultimediaFlashcardTypes.ts → MediaAttachments.ts} +13 -32
- package/src/media/index.ts +24 -23
- package/src/media/{presentation/hooks/useCardMediaGeneration.ts → infrastructure/hooks/useGenericMediaGeneration.ts} +77 -31
- package/src/media/infrastructure/services/MediaGenerationService.ts +1 -1
- package/src/media/infrastructure/services/MediaOptimizerService.ts +1 -1
- package/src/media/infrastructure/services/MediaUploadService.ts +1 -1
- package/src/media/infrastructure/services/MediaValidationService.ts +1 -1
- package/src/media/infrastructure/services/MultimediaFlashcardService.ts +1 -1
- package/src/media/infrastructure/utils/PermissionManager.ts +1 -1
- package/src/media/infrastructure/utils/media-collection-utils.ts +4 -2
- package/src/media/infrastructure/utils/mediaPickerMappers.ts +1 -1
- package/src/media/presentation/hooks/multimedia.types.ts +1 -1
- package/src/media/presentation/hooks/useCardMultimediaFlashcard.ts +4 -4
- package/src/media/presentation/hooks/useMedia.ts +2 -2
- package/src/media/presentation/hooks/useMediaGeneration.ts +5 -88
- package/src/media/presentation/hooks/useMediaUpload.ts +1 -1
- package/src/media/presentation/hooks/useMediaValidation.ts +1 -1
- package/src/media/presentation/hooks/useMultimediaFlashcard.ts +1 -1
- package/src/molecules/navigation/components/NavigationHeader.tsx +3 -3
- package/src/molecules/navigation/utils/AppNavigation.ts +3 -3
- package/src/offline/index.ts +1 -0
- package/src/offline/infrastructure/storage/OfflineConfigStore.ts +34 -0
- package/src/offline/presentation/hooks/useOffline.ts +8 -4
- package/src/storage/domain/utils/devUtils.ts +0 -24
- package/src/storage/index.ts +1 -1
- package/src/storage/infrastructure/adapters/StorageService.ts +5 -10
- package/src/storage/infrastructure/repositories/BaseStorageOperations.ts +5 -8
- package/src/storage/presentation/hooks/CacheStorageOperations.ts +5 -11
- package/src/storage/presentation/hooks/useStore.ts +13 -5
- package/src/utilities/sharing/presentation/hooks/useSharing.ts +3 -3
- package/src/layouts/ScreenLayout/ScreenLayout.example.tsx +0 -92
- package/src/media/domain/entities/CardMultimedia.types.README.md +0 -129
- package/src/media/domain/entities/CardMultimedia.types.ts +0 -120
- package/src/media/domain/entities/Media.README.md +0 -80
- package/src/media/domain/entities/MultimediaFlashcardTypes.README.md +0 -144
- package/src/media/domain/utils/MediaUtils.README.md +0 -178
- package/src/media/index.ts.README.md +0 -191
- package/src/media/infrastructure/services/CardMediaGenerationService.README.md +0 -99
- package/src/media/infrastructure/services/CardMediaGenerationService.ts +0 -101
- package/src/media/infrastructure/services/CardMediaOptimizerService.README.md +0 -167
- package/src/media/infrastructure/services/CardMediaOptimizerService.ts +0 -36
- package/src/media/infrastructure/services/CardMediaUploadService.README.md +0 -123
- package/src/media/infrastructure/services/CardMediaUploadService.ts +0 -62
- package/src/media/infrastructure/services/CardMediaValidationService.README.md +0 -134
- package/src/media/infrastructure/services/CardMediaValidationService.ts +0 -81
- package/src/media/infrastructure/services/CardMultimediaService.README.md +0 -176
- package/src/media/infrastructure/services/CardMultimediaService.ts +0 -98
- package/src/media/infrastructure/services/MediaGenerationService.README.md +0 -142
- package/src/media/infrastructure/services/MediaOptimizerService.README.md +0 -145
- package/src/media/infrastructure/services/MediaPickerService.README.md +0 -106
- package/src/media/infrastructure/services/MediaSaveService.README.md +0 -120
- package/src/media/infrastructure/services/MediaUploadService.README.md +0 -135
- package/src/media/infrastructure/services/MediaValidationService.README.md +0 -135
- package/src/media/infrastructure/services/MultimediaFlashcardService.README.md +0 -142
- package/src/media/infrastructure/utils/mediaHelpers.README.md +0 -96
- package/src/media/infrastructure/utils/mediaPickerMappers.README.md +0 -129
- package/src/media/presentation/hooks/card-multimedia.types.README.md +0 -177
- package/src/media/presentation/hooks/card-multimedia.types.ts +0 -53
- package/src/media/presentation/hooks/multimedia.types.README.md +0 -201
- package/src/media/presentation/hooks/useCardMediaGeneration.README.md +0 -164
- package/src/media/presentation/hooks/useCardMediaUpload.README.md +0 -153
- package/src/media/presentation/hooks/useCardMediaUpload.ts +0 -84
- package/src/media/presentation/hooks/useCardMediaValidation.README.md +0 -176
- package/src/media/presentation/hooks/useCardMediaValidation.ts +0 -101
- package/src/media/presentation/hooks/useCardMultimediaFlashcard.README.md +0 -158
- package/src/media/presentation/hooks/useMedia.README.md +0 -94
- package/src/media/presentation/hooks/useMediaGeneration.README.md +0 -118
- package/src/media/presentation/hooks/useMediaUpload.README.md +0 -108
- package/src/media/presentation/hooks/useMediaValidation.README.md +0 -134
- package/src/media/presentation/hooks/useMultimediaFlashcard.README.md +0 -141
- package/src/storage/domain/utils/__tests__/devUtils.test.ts +0 -97
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-design-system",
|
|
3
|
-
"version": "4.23.
|
|
3
|
+
"version": "4.23.101",
|
|
4
4
|
"description": "Universal design system for React Native apps - Consolidated package with atoms, molecules, organisms, theme, typography, responsive, safe area, exception, infinite scroll, UUID, image, timezone, offline, onboarding, and loading utilities",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -29,6 +29,9 @@ export const AtomicButton: React.FC<AtomicButtonProps> = React.memo(({
|
|
|
29
29
|
textStyle,
|
|
30
30
|
activeOpacity = 0.8,
|
|
31
31
|
testID,
|
|
32
|
+
accessibilityLabel,
|
|
33
|
+
accessibilityHint,
|
|
34
|
+
accessibilityRole = 'button',
|
|
32
35
|
}) => {
|
|
33
36
|
const tokens = useAppDesignTokens();
|
|
34
37
|
|
|
@@ -80,6 +83,10 @@ export const AtomicButton: React.FC<AtomicButtonProps> = React.memo(({
|
|
|
80
83
|
activeOpacity={activeOpacity}
|
|
81
84
|
disabled={isDisabled}
|
|
82
85
|
testID={testID}
|
|
86
|
+
accessibilityRole={accessibilityRole}
|
|
87
|
+
accessibilityLabel={accessibilityLabel || title || (typeof children === 'string' ? children : 'Button')}
|
|
88
|
+
accessibilityHint={accessibilityHint}
|
|
89
|
+
accessibilityState={{ disabled: isDisabled, busy: loading }}
|
|
83
90
|
>
|
|
84
91
|
{loading ? (
|
|
85
92
|
<AtomicSpinner
|
|
@@ -24,6 +24,10 @@ export interface AtomicButtonProps {
|
|
|
24
24
|
readonly textStyle?: StyleProp<TextStyle>;
|
|
25
25
|
readonly activeOpacity?: number;
|
|
26
26
|
readonly testID?: string;
|
|
27
|
+
// Accessibility props
|
|
28
|
+
readonly accessibilityLabel?: string;
|
|
29
|
+
readonly accessibilityHint?: string;
|
|
30
|
+
readonly accessibilityRole?: 'button' | 'link';
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
export interface ButtonSizeConfig {
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import { useState, useCallback, useEffect } from 'react';
|
|
1
|
+
import { useState, useCallback, useEffect, useMemo } from 'react';
|
|
2
2
|
|
|
3
3
|
interface UseInputStateProps {
|
|
4
4
|
value?: string;
|
|
5
5
|
onChangeText?: (text: string) => void;
|
|
6
6
|
secureTextEntry?: boolean;
|
|
7
|
-
showPasswordToggle?: boolean;
|
|
8
7
|
maxLength?: number;
|
|
9
|
-
showCharacterCount?: boolean;
|
|
10
8
|
}
|
|
11
9
|
|
|
12
10
|
interface UseInputStateReturn {
|
|
@@ -24,9 +22,7 @@ export const useInputState = ({
|
|
|
24
22
|
value = '',
|
|
25
23
|
onChangeText,
|
|
26
24
|
secureTextEntry = false,
|
|
27
|
-
showPasswordToggle: _showPasswordToggle = false,
|
|
28
25
|
maxLength,
|
|
29
|
-
showCharacterCount: _showCharacterCount = false,
|
|
30
26
|
}: UseInputStateProps = {}): UseInputStateReturn => {
|
|
31
27
|
const [localValue, setLocalValue] = useState(value);
|
|
32
28
|
const [isFocused, setIsFocused] = useState(false);
|
|
@@ -49,7 +45,7 @@ export const useInputState = ({
|
|
|
49
45
|
const characterCount = localValue.length;
|
|
50
46
|
const isAtMaxLength = maxLength ? characterCount >= maxLength : false;
|
|
51
47
|
|
|
52
|
-
return {
|
|
48
|
+
return useMemo(() => ({
|
|
53
49
|
localValue,
|
|
54
50
|
isFocused,
|
|
55
51
|
isPasswordVisible,
|
|
@@ -58,5 +54,5 @@ export const useInputState = ({
|
|
|
58
54
|
setIsFocused,
|
|
59
55
|
handleTextChange,
|
|
60
56
|
togglePasswordVisibility,
|
|
61
|
-
};
|
|
57
|
+
}), [localValue, isFocused, isPasswordVisible, characterCount, isAtMaxLength, handleTextChange, togglePasswordVisibility]);
|
|
62
58
|
};
|
|
@@ -15,7 +15,7 @@ import type { ImpactStyle, NotificationType, HapticPattern } from '../../domain/
|
|
|
15
15
|
* Log error in development mode only
|
|
16
16
|
*/
|
|
17
17
|
function logError(method: string, error: unknown): void {
|
|
18
|
-
if (
|
|
18
|
+
if (__DEV__) {
|
|
19
19
|
console.error(`[DesignSystem] HapticService.${method} error:`, error);
|
|
20
20
|
}
|
|
21
21
|
}
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Media Attachments Types
|
|
3
|
+
* Types for media attachments in flashcards and content
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
export type
|
|
6
|
+
export type MediaAttachmentType = "image" | "audio" | "video";
|
|
7
7
|
export type MediaPosition = "front" | "back" | "both";
|
|
8
8
|
|
|
9
9
|
export interface MediaAttachment {
|
|
10
10
|
id: string;
|
|
11
|
-
type:
|
|
11
|
+
type: MediaAttachmentType;
|
|
12
12
|
position: MediaPosition;
|
|
13
13
|
url: string;
|
|
14
14
|
localPath?: string;
|
|
15
15
|
filename: string;
|
|
16
16
|
fileSize: number;
|
|
17
17
|
mimeType: string;
|
|
18
|
-
duration?: number;
|
|
19
|
-
thumbnailUrl?: string;
|
|
18
|
+
duration?: number;
|
|
19
|
+
thumbnailUrl?: string;
|
|
20
20
|
caption?: string;
|
|
21
21
|
isDownloaded: boolean;
|
|
22
22
|
createdAt: string;
|
|
@@ -30,12 +30,11 @@ export interface MultimediaFlashcard {
|
|
|
30
30
|
tags: string[];
|
|
31
31
|
createdAt?: string;
|
|
32
32
|
updatedAt?: string;
|
|
33
|
-
// Extended properties for multimedia support
|
|
34
33
|
media: MediaAttachment[];
|
|
35
|
-
hasMedia: boolean;
|
|
36
|
-
mediaType:
|
|
37
|
-
isDownloaded: boolean;
|
|
38
|
-
estimatedSize: number;
|
|
34
|
+
hasMedia: boolean;
|
|
35
|
+
mediaType: MediaAttachmentType[];
|
|
36
|
+
isDownloaded: boolean;
|
|
37
|
+
estimatedSize: number;
|
|
39
38
|
}
|
|
40
39
|
|
|
41
40
|
export interface MediaGenerationRequest {
|
|
@@ -65,17 +64,17 @@ export interface MediaGenerationResult {
|
|
|
65
64
|
|
|
66
65
|
export interface MediaUploadProgress {
|
|
67
66
|
fileId: string;
|
|
68
|
-
progress: number;
|
|
67
|
+
progress: number;
|
|
69
68
|
status: "uploading" | "processing" | "completed" | "error";
|
|
70
69
|
error?: string;
|
|
71
70
|
url?: string;
|
|
72
71
|
}
|
|
73
72
|
|
|
74
73
|
export interface MediaCompressionOptions {
|
|
75
|
-
quality: number;
|
|
74
|
+
quality: number;
|
|
76
75
|
maxWidth?: number;
|
|
77
76
|
maxHeight?: number;
|
|
78
|
-
maxFileSize?: number;
|
|
77
|
+
maxFileSize?: number;
|
|
79
78
|
format?: "jpeg" | "png" | "webp";
|
|
80
79
|
}
|
|
81
80
|
|
|
@@ -100,21 +99,3 @@ export interface MediaValidation {
|
|
|
100
99
|
warnings: string[];
|
|
101
100
|
recommendations: string[];
|
|
102
101
|
}
|
|
103
|
-
|
|
104
|
-
export interface MultimediaFlashcardService {
|
|
105
|
-
uploadMedia(
|
|
106
|
-
file: MediaFile,
|
|
107
|
-
options?: MediaCompressionOptions,
|
|
108
|
-
): Promise<MediaAttachment>;
|
|
109
|
-
generateMedia(
|
|
110
|
-
request: MediaGenerationRequest,
|
|
111
|
-
): Promise<MediaGenerationResult>;
|
|
112
|
-
validateMedia(file: MediaFile): Promise<MediaValidation>;
|
|
113
|
-
optimizeMedia(
|
|
114
|
-
attachment: MediaAttachment,
|
|
115
|
-
options: MediaCompressionOptions,
|
|
116
|
-
): Promise<MediaAttachment>;
|
|
117
|
-
deleteMedia(attachmentId: string): Promise<void>;
|
|
118
|
-
getMediaUrl(attachmentId: string): Promise<string>;
|
|
119
|
-
downloadMedia(attachmentId: string): Promise<string>; // Returns local path
|
|
120
|
-
}
|
package/src/media/index.ts
CHANGED
|
@@ -91,28 +91,29 @@ export {
|
|
|
91
91
|
type SaveToGalleryResult,
|
|
92
92
|
} from "./infrastructure/utils/file-media-utils";
|
|
93
93
|
|
|
94
|
-
//
|
|
94
|
+
// Media Attachment Types (Clean, no aliases)
|
|
95
95
|
export type {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
96
|
+
MediaAttachmentType,
|
|
97
|
+
MediaPosition,
|
|
98
|
+
MediaAttachment,
|
|
99
|
+
MultimediaFlashcard,
|
|
100
|
+
MediaGenerationRequest,
|
|
101
|
+
MediaGenerationResult,
|
|
102
|
+
MediaUploadProgress,
|
|
103
|
+
MediaCompressionOptions,
|
|
104
|
+
MediaValidation,
|
|
105
|
+
MediaFile,
|
|
106
|
+
CreateMultimediaCardData,
|
|
107
|
+
} from "./domain/entities/MediaAttachments";
|
|
106
108
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
export {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
} from "./presentation/hooks/useCardMultimediaFlashcard";
|
|
109
|
+
// Media Hooks
|
|
110
|
+
export { useMediaUpload } from "./presentation/hooks/useMediaUpload";
|
|
111
|
+
export { useMediaGeneration } from "./presentation/hooks/useMediaGeneration";
|
|
112
|
+
export { useMediaValidation } from "./presentation/hooks/useMediaValidation";
|
|
113
|
+
export { useMultimediaFlashcard } from "./presentation/hooks/useMultimediaFlashcard";
|
|
114
|
+
export type {
|
|
115
|
+
UseMediaUploadResult,
|
|
116
|
+
UseMediaGenerationResult,
|
|
117
|
+
UseMediaValidationResult,
|
|
118
|
+
UseMultimediaFlashcardResult,
|
|
119
|
+
} from "./presentation/hooks/multimedia.types";
|
|
@@ -1,26 +1,75 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Generic Media Generation Hook
|
|
3
|
+
* Shared implementation for both Media and CardMedia generation
|
|
4
|
+
* Eliminates ~600 LOC duplication
|
|
4
5
|
*/
|
|
5
6
|
|
|
6
7
|
import { useState, useCallback } from "react";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
|
|
9
|
+
interface GenericMediaAttachment {
|
|
10
|
+
id: string;
|
|
11
|
+
type: string;
|
|
12
|
+
position: string;
|
|
13
|
+
url: string;
|
|
14
|
+
filename: string;
|
|
15
|
+
fileSize: number;
|
|
16
|
+
mimeType: string;
|
|
17
|
+
duration?: number;
|
|
18
|
+
thumbnailUrl?: string;
|
|
19
|
+
caption?: string;
|
|
20
|
+
isDownloaded: boolean;
|
|
21
|
+
createdAt: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface GenericMediaGenerationRequest {
|
|
25
|
+
type: "text_to_image" | "text_to_audio" | "image_search";
|
|
26
|
+
input: {
|
|
27
|
+
text?: string;
|
|
28
|
+
prompt?: string;
|
|
29
|
+
language?: string;
|
|
30
|
+
voice?: "male" | "female" | "neutral";
|
|
31
|
+
style?: "realistic" | "cartoon" | "artistic";
|
|
32
|
+
};
|
|
33
|
+
options: {
|
|
34
|
+
maxResults?: number;
|
|
35
|
+
quality?: "low" | "medium" | "high";
|
|
36
|
+
format?: "jpeg" | "png" | "mp3" | "wav";
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface GenericMediaGenerationResult<TAttachment> {
|
|
41
|
+
success: boolean;
|
|
42
|
+
attachments: TAttachment[];
|
|
43
|
+
creditsUsed: number;
|
|
44
|
+
processingTime: number;
|
|
45
|
+
error?: string;
|
|
46
|
+
requestId: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface UseGenericMediaGenerationResult<TAttachment, TRequest> {
|
|
50
|
+
generateMedia: (request: TRequest) => Promise<GenericMediaGenerationResult<TAttachment>>;
|
|
51
|
+
isGenerating: boolean;
|
|
52
|
+
generationResult: GenericMediaGenerationResult<TAttachment> | null;
|
|
53
|
+
error: string | null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Generic implementation of media generation logic
|
|
58
|
+
* Type-safe through attachment factory pattern
|
|
59
|
+
*/
|
|
60
|
+
export function useGenericMediaGeneration<
|
|
61
|
+
TAttachment extends GenericMediaAttachment,
|
|
62
|
+
TRequest extends GenericMediaGenerationRequest
|
|
63
|
+
>(
|
|
64
|
+
attachmentFactory: (baseAttachment: GenericMediaAttachment) => TAttachment
|
|
65
|
+
): UseGenericMediaGenerationResult<TAttachment, TRequest> {
|
|
15
66
|
const [isGenerating, setIsGenerating] = useState(false);
|
|
16
67
|
const [generationResult, setGenerationResult] =
|
|
17
|
-
useState<
|
|
68
|
+
useState<GenericMediaGenerationResult<TAttachment> | null>(null);
|
|
18
69
|
const [error, setError] = useState<string | null>(null);
|
|
19
70
|
|
|
20
71
|
const generateMedia = useCallback(
|
|
21
|
-
async (
|
|
22
|
-
request: CardMediaGenerationRequest,
|
|
23
|
-
): Promise<CardMediaGenerationResult> => {
|
|
72
|
+
async (request: TRequest): Promise<GenericMediaGenerationResult<TAttachment>> => {
|
|
24
73
|
try {
|
|
25
74
|
setIsGenerating(true);
|
|
26
75
|
setError(null);
|
|
@@ -28,18 +77,18 @@ export const useCardMediaGeneration = (): UseCardMediaGenerationResult => {
|
|
|
28
77
|
// Simulate generation
|
|
29
78
|
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
30
79
|
|
|
31
|
-
const
|
|
80
|
+
const baseAttachments: GenericMediaAttachment[] = [];
|
|
32
81
|
|
|
33
82
|
switch (request.type) {
|
|
34
83
|
case "text_to_image":
|
|
35
84
|
for (let i = 0; i < (request.options.maxResults || 1); i++) {
|
|
36
|
-
|
|
85
|
+
baseAttachments.push({
|
|
37
86
|
id: `ai_img_${Date.now()}_${i}`,
|
|
38
87
|
type: "image",
|
|
39
88
|
position: "both",
|
|
40
89
|
url: `https://picsum.photos/400/300?random=${Date.now() + i}`,
|
|
41
90
|
filename: `ai_generated_${i}.jpg`,
|
|
42
|
-
fileSize: 150000,
|
|
91
|
+
fileSize: 150000,
|
|
43
92
|
mimeType: "image/jpeg",
|
|
44
93
|
isDownloaded: false,
|
|
45
94
|
createdAt: new Date().toISOString(),
|
|
@@ -48,15 +97,15 @@ export const useCardMediaGeneration = (): UseCardMediaGenerationResult => {
|
|
|
48
97
|
break;
|
|
49
98
|
|
|
50
99
|
case "text_to_audio":
|
|
51
|
-
|
|
100
|
+
baseAttachments.push({
|
|
52
101
|
id: `ai_audio_${Date.now()}`,
|
|
53
102
|
type: "audio",
|
|
54
103
|
position: "back",
|
|
55
104
|
url: `https://example.com/audio_${Date.now()}.mp3`,
|
|
56
105
|
filename: `ai_generated_${Date.now()}.mp3`,
|
|
57
|
-
fileSize: 80000,
|
|
106
|
+
fileSize: 80000,
|
|
58
107
|
mimeType: "audio/mp3",
|
|
59
|
-
duration: 10,
|
|
108
|
+
duration: 10,
|
|
60
109
|
isDownloaded: false,
|
|
61
110
|
createdAt: new Date().toISOString(),
|
|
62
111
|
});
|
|
@@ -64,13 +113,13 @@ export const useCardMediaGeneration = (): UseCardMediaGenerationResult => {
|
|
|
64
113
|
|
|
65
114
|
case "image_search":
|
|
66
115
|
for (let i = 0; i < (request.options.maxResults || 5); i++) {
|
|
67
|
-
|
|
116
|
+
baseAttachments.push({
|
|
68
117
|
id: `search_img_${Date.now()}_${i}`,
|
|
69
118
|
type: "image",
|
|
70
119
|
position: "both",
|
|
71
120
|
url: `https://picsum.photos/400/300?random=${Date.now() + i}`,
|
|
72
121
|
filename: `search_result_${i}.jpg`,
|
|
73
|
-
fileSize: 120000,
|
|
122
|
+
fileSize: 120000,
|
|
74
123
|
mimeType: "image/jpeg",
|
|
75
124
|
isDownloaded: false,
|
|
76
125
|
createdAt: new Date().toISOString(),
|
|
@@ -79,15 +128,12 @@ export const useCardMediaGeneration = (): UseCardMediaGenerationResult => {
|
|
|
79
128
|
break;
|
|
80
129
|
}
|
|
81
130
|
|
|
82
|
-
const
|
|
131
|
+
const attachments = baseAttachments.map(attachmentFactory);
|
|
132
|
+
|
|
133
|
+
const result: GenericMediaGenerationResult<TAttachment> = {
|
|
83
134
|
success: true,
|
|
84
135
|
attachments,
|
|
85
|
-
creditsUsed:
|
|
86
|
-
request.type === "text_to_image"
|
|
87
|
-
? 5
|
|
88
|
-
: request.type === "text_to_audio"
|
|
89
|
-
? 3
|
|
90
|
-
: 2,
|
|
136
|
+
creditsUsed: request.type === "text_to_image" ? 5 : request.type === "text_to_audio" ? 3 : 2,
|
|
91
137
|
processingTime: 3000,
|
|
92
138
|
requestId: `req_${Date.now()}`,
|
|
93
139
|
};
|
|
@@ -112,7 +158,7 @@ export const useCardMediaGeneration = (): UseCardMediaGenerationResult => {
|
|
|
112
158
|
setIsGenerating(false);
|
|
113
159
|
}
|
|
114
160
|
},
|
|
115
|
-
[],
|
|
161
|
+
[attachmentFactory],
|
|
116
162
|
);
|
|
117
163
|
|
|
118
164
|
return {
|
|
@@ -121,4 +167,4 @@ export const useCardMediaGeneration = (): UseCardMediaGenerationResult => {
|
|
|
121
167
|
generationResult,
|
|
122
168
|
error,
|
|
123
169
|
};
|
|
124
|
-
}
|
|
170
|
+
}
|
|
@@ -7,7 +7,7 @@ import type {
|
|
|
7
7
|
MediaAttachment,
|
|
8
8
|
MediaCompressionOptions,
|
|
9
9
|
MediaFile,
|
|
10
|
-
} from "../../domain/entities/
|
|
10
|
+
} from "../../domain/entities/MediaAttachments";
|
|
11
11
|
import { generateThumbnail, getMediaDuration } from "../utils/file-media-utils";
|
|
12
12
|
import { getMediaTypeFromMime } from "../utils/mime-type-detector";
|
|
13
13
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { formatFileSize } from "../utils/media-collection-utils";
|
|
7
|
-
import type { MediaValidation, MediaFile } from "../../domain/entities/
|
|
7
|
+
import type { MediaValidation, MediaFile } from "../../domain/entities/MediaAttachments";
|
|
8
8
|
|
|
9
9
|
export class MediaValidationService {
|
|
10
10
|
/**
|
|
@@ -10,7 +10,7 @@ import type {
|
|
|
10
10
|
MediaGenerationResult,
|
|
11
11
|
MediaCompressionOptions,
|
|
12
12
|
MediaValidation,
|
|
13
|
-
} from "../../domain/entities/
|
|
13
|
+
} from "../../domain/entities/MediaAttachments";
|
|
14
14
|
import { MediaUploadService } from "./MediaUploadService";
|
|
15
15
|
import { MediaGenerationService } from "./MediaGenerationService";
|
|
16
16
|
import { MediaValidationService } from "./MediaValidationService";
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import * as ImagePicker from "expo-image-picker";
|
|
8
|
-
import { MediaLibraryPermission } from "../../domain/entities/
|
|
8
|
+
import { MediaLibraryPermission } from "../../domain/entities/MediaAttachments";
|
|
9
9
|
import { mapPermissionStatus } from "./mediaPickerMappers";
|
|
10
10
|
|
|
11
11
|
/**
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type { MediaAttachment } from "../../domain/entities/MediaAttachments";
|
|
2
|
+
|
|
3
|
+
// CardMediaAttachment is an alias of MediaAttachment
|
|
4
|
+
type CardMediaAttachment = MediaAttachment;
|
|
3
5
|
|
|
4
6
|
type MediaType = "image" | "audio" | "video";
|
|
5
7
|
|
|
@@ -13,7 +13,7 @@ import type {
|
|
|
13
13
|
MediaUploadProgress,
|
|
14
14
|
MultimediaFlashcard,
|
|
15
15
|
CreateMultimediaCardData,
|
|
16
|
-
} from "../../domain/entities/
|
|
16
|
+
} from "../../domain/entities/MediaAttachments";
|
|
17
17
|
|
|
18
18
|
export interface UseMediaUploadResult {
|
|
19
19
|
uploadMedia: (
|
|
@@ -7,10 +7,10 @@ import { useState, useCallback } from "react";
|
|
|
7
7
|
import { calculateTotalSize, extractMediaTypes } from "../../infrastructure/utils/media-collection-utils";
|
|
8
8
|
import type { UseCardMultimediaFlashcardResult } from "./card-multimedia.types";
|
|
9
9
|
import type {
|
|
10
|
-
CardMediaAttachment,
|
|
11
|
-
CardMultimediaFlashcard,
|
|
12
|
-
CreateCardMultimediaData,
|
|
13
|
-
} from "../../domain/entities/
|
|
10
|
+
MediaAttachment as CardMediaAttachment,
|
|
11
|
+
MultimediaFlashcard as CardMultimediaFlashcard,
|
|
12
|
+
CreateMultimediaCardData as CreateCardMultimediaData,
|
|
13
|
+
} from "../../domain/entities/MediaAttachments";
|
|
14
14
|
|
|
15
15
|
// Export individual hooks
|
|
16
16
|
export { useCardMediaUpload } from "./useCardMediaUpload";
|
|
@@ -12,8 +12,8 @@ import type {
|
|
|
12
12
|
MediaPickerOptions,
|
|
13
13
|
MediaPickerResult,
|
|
14
14
|
CameraOptions,
|
|
15
|
-
} from "../../domain/entities/
|
|
16
|
-
import { MediaLibraryPermission } from "../../domain/entities/
|
|
15
|
+
} from "../../domain/entities/MediaAttachments";
|
|
16
|
+
import { MediaLibraryPermission } from "../../domain/entities/MediaAttachments";
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* useMedia hook for complete media workflow
|
|
@@ -1,101 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Media Generation Hook
|
|
3
3
|
* Hook for generating media with AI
|
|
4
|
+
* Now a thin wrapper around useGenericMediaGeneration
|
|
4
5
|
*/
|
|
5
6
|
|
|
6
|
-
import {
|
|
7
|
+
import { useGenericMediaGeneration } from "../../infrastructure/hooks/useGenericMediaGeneration";
|
|
7
8
|
import type { UseMediaGenerationResult } from "./multimedia.types";
|
|
8
9
|
import type {
|
|
9
10
|
MediaAttachment,
|
|
10
11
|
MediaGenerationRequest,
|
|
11
|
-
|
|
12
|
-
} from "../../domain/entities/MultimediaFlashcardTypes";
|
|
12
|
+
} from "../../domain/entities/MediaAttachments";
|
|
13
13
|
|
|
14
14
|
export const useMediaGeneration = (): UseMediaGenerationResult => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
useState<MediaGenerationResult | null>(null);
|
|
18
|
-
const [error, setError] = useState<string | null>(null);
|
|
19
|
-
|
|
20
|
-
const generateMedia = useCallback(
|
|
21
|
-
async (request: MediaGenerationRequest): Promise<MediaGenerationResult> => {
|
|
22
|
-
try {
|
|
23
|
-
setIsGenerating(true);
|
|
24
|
-
setError(null);
|
|
25
|
-
|
|
26
|
-
// Simulate generation
|
|
27
|
-
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
28
|
-
|
|
29
|
-
const attachments: MediaAttachment[] = [];
|
|
30
|
-
|
|
31
|
-
switch (request.type) {
|
|
32
|
-
case "text_to_image":
|
|
33
|
-
for (let i = 0; i < (request.options.maxResults || 1); i++) {
|
|
34
|
-
attachments.push({
|
|
35
|
-
id: `ai_img_${Date.now()}_${i}`,
|
|
36
|
-
type: "image",
|
|
37
|
-
position: "both",
|
|
38
|
-
url: `https://picsum.photos/400/300?random=${Date.now() + i}`,
|
|
39
|
-
filename: `ai_generated_${i}.jpg`,
|
|
40
|
-
fileSize: 150000, // 150KB
|
|
41
|
-
mimeType: "image/jpeg",
|
|
42
|
-
isDownloaded: false,
|
|
43
|
-
createdAt: new Date().toISOString(),
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
break;
|
|
47
|
-
|
|
48
|
-
case "text_to_audio":
|
|
49
|
-
attachments.push({
|
|
50
|
-
id: `ai_audio_${Date.now()}`,
|
|
51
|
-
type: "audio",
|
|
52
|
-
position: "back",
|
|
53
|
-
url: `https://example.com/audio_${Date.now()}.mp3`,
|
|
54
|
-
filename: `ai_generated_${Date.now()}.mp3`,
|
|
55
|
-
fileSize: 80000, // 80KB
|
|
56
|
-
mimeType: "audio/mp3",
|
|
57
|
-
duration: 10, // 10 seconds
|
|
58
|
-
isDownloaded: false,
|
|
59
|
-
createdAt: new Date().toISOString(),
|
|
60
|
-
});
|
|
61
|
-
break;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const result: MediaGenerationResult = {
|
|
65
|
-
success: true,
|
|
66
|
-
attachments,
|
|
67
|
-
creditsUsed: request.type === "text_to_image" ? 5 : 3,
|
|
68
|
-
processingTime: 3000,
|
|
69
|
-
requestId: `req_${Date.now()}`,
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
setGenerationResult(result);
|
|
73
|
-
return result;
|
|
74
|
-
} catch (err) {
|
|
75
|
-
const errorMessage =
|
|
76
|
-
err instanceof Error ? err.message : "Generation failed";
|
|
77
|
-
setError(errorMessage);
|
|
78
|
-
setIsGenerating(false);
|
|
79
|
-
|
|
80
|
-
return {
|
|
81
|
-
success: false,
|
|
82
|
-
attachments: [],
|
|
83
|
-
creditsUsed: 0,
|
|
84
|
-
processingTime: 0,
|
|
85
|
-
error: errorMessage,
|
|
86
|
-
requestId: "",
|
|
87
|
-
};
|
|
88
|
-
} finally {
|
|
89
|
-
setIsGenerating(false);
|
|
90
|
-
}
|
|
91
|
-
},
|
|
92
|
-
[],
|
|
15
|
+
return useGenericMediaGeneration<MediaAttachment, MediaGenerationRequest>(
|
|
16
|
+
(baseAttachment) => baseAttachment as MediaAttachment
|
|
93
17
|
);
|
|
94
|
-
|
|
95
|
-
return {
|
|
96
|
-
generateMedia,
|
|
97
|
-
isGenerating,
|
|
98
|
-
generationResult,
|
|
99
|
-
error,
|
|
100
|
-
};
|
|
101
18
|
};
|
|
@@ -12,7 +12,7 @@ import type {
|
|
|
12
12
|
MediaCompressionOptions,
|
|
13
13
|
MediaFile,
|
|
14
14
|
MediaUploadProgress,
|
|
15
|
-
} from "../../domain/entities/
|
|
15
|
+
} from "../../domain/entities/MediaAttachments";
|
|
16
16
|
|
|
17
17
|
export const useMediaUpload = (): UseMediaUploadResult => {
|
|
18
18
|
const [isUploading, setIsUploading] = useState(false);
|