@umituz/react-native-design-system 4.23.101 → 4.23.102

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-design-system",
3
- "version": "4.23.101",
3
+ "version": "4.23.102",
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",
@@ -106,7 +106,7 @@ export type {
106
106
  CreateMultimediaCardData,
107
107
  } from "./domain/entities/MediaAttachments";
108
108
 
109
- // Media Hooks
109
+ // Media Attachment Hooks
110
110
  export { useMediaUpload } from "./presentation/hooks/useMediaUpload";
111
111
  export { useMediaGeneration } from "./presentation/hooks/useMediaGeneration";
112
112
  export { useMediaValidation } from "./presentation/hooks/useMediaValidation";
@@ -117,3 +117,6 @@ export type {
117
117
  UseMediaValidationResult,
118
118
  UseMultimediaFlashcardResult,
119
119
  } from "./presentation/hooks/multimedia.types";
120
+
121
+ // Media Attachment Services
122
+ export { MultimediaFlashcardService } from "./infrastructure/services/MultimediaFlashcardService";
@@ -5,7 +5,7 @@
5
5
  */
6
6
 
7
7
  import * as ImagePicker from "expo-image-picker";
8
- import { MediaLibraryPermission } from "../../domain/entities/MediaAttachments";
8
+ import { MediaLibraryPermission } from "../../domain/entities/Media";
9
9
  import { mapPermissionStatus } from "./mediaPickerMappers";
10
10
 
11
11
  /**
@@ -9,7 +9,7 @@ import {
9
9
  MediaType,
10
10
  type MediaAsset,
11
11
  type MediaPickerResult,
12
- } from "../../domain/entities/MediaAttachments";
12
+ } from "../../domain/entities/Media";
13
13
 
14
14
  /**
15
15
  * Map expo-image-picker permission status to MediaLibraryPermission
@@ -37,7 +37,7 @@ export class BaseStorageOperations {
37
37
  return failure(new StorageDeserializationError(key, parseError), defaultValue);
38
38
  }
39
39
  } catch (_error) {
40
- return failure(new StorageReadError(key, error), defaultValue);
40
+ return failure(new StorageReadError(key, _error), defaultValue);
41
41
  }
42
42
  }
43
43
 
@@ -56,7 +56,7 @@ export class BaseStorageOperations {
56
56
  await AsyncStorage.setItem(key, serialized);
57
57
  return success(value);
58
58
  } catch (_error) {
59
- return failure(new StorageWriteError(key, error));
59
+ return failure(new StorageWriteError(key, _error));
60
60
  }
61
61
  }
62
62
 
@@ -68,7 +68,7 @@ export class BaseStorageOperations {
68
68
  await AsyncStorage.removeItem(key);
69
69
  return success(undefined);
70
70
  } catch (_error) {
71
- return failure(new StorageDeleteError(key, error));
71
+ return failure(new StorageDeleteError(key, _error));
72
72
  }
73
73
  }
74
74
 
@@ -92,7 +92,7 @@ export class BaseStorageOperations {
92
92
  await AsyncStorage.clear();
93
93
  return success(undefined);
94
94
  } catch (_error) {
95
- return failure(new StorageDeleteError('ALL_KEYS', error));
95
+ return failure(new StorageDeleteError('ALL_KEYS', _error));
96
96
  }
97
97
  }
98
98
  }
@@ -1,101 +0,0 @@
1
- /**
2
- * Media Attachments Types
3
- * Types for media attachments in flashcards and content
4
- */
5
-
6
- export type MediaAttachmentType = "image" | "audio" | "video";
7
- export type MediaPosition = "front" | "back" | "both";
8
-
9
- export interface MediaAttachment {
10
- id: string;
11
- type: MediaAttachmentType;
12
- position: MediaPosition;
13
- url: string;
14
- localPath?: string;
15
- filename: string;
16
- fileSize: number;
17
- mimeType: string;
18
- duration?: number;
19
- thumbnailUrl?: string;
20
- caption?: string;
21
- isDownloaded: boolean;
22
- createdAt: string;
23
- }
24
-
25
- export interface MultimediaFlashcard {
26
- id: string;
27
- front: string;
28
- back: string;
29
- difficulty: "easy" | "medium" | "hard";
30
- tags: string[];
31
- createdAt?: string;
32
- updatedAt?: string;
33
- media: MediaAttachment[];
34
- hasMedia: boolean;
35
- mediaType: MediaAttachmentType[];
36
- isDownloaded: boolean;
37
- estimatedSize: number;
38
- }
39
-
40
- export interface MediaGenerationRequest {
41
- type: "text_to_image" | "text_to_audio" | "image_search";
42
- input: {
43
- text?: string;
44
- prompt?: string;
45
- language?: string;
46
- voice?: "male" | "female" | "neutral";
47
- style?: "realistic" | "cartoon" | "artistic";
48
- };
49
- options: {
50
- maxResults?: number;
51
- quality?: "low" | "medium" | "high";
52
- format?: "jpeg" | "png" | "mp3" | "wav";
53
- };
54
- }
55
-
56
- export interface MediaGenerationResult {
57
- success: boolean;
58
- attachments: MediaAttachment[];
59
- creditsUsed: number;
60
- processingTime: number;
61
- error?: string;
62
- requestId: string;
63
- }
64
-
65
- export interface MediaUploadProgress {
66
- fileId: string;
67
- progress: number;
68
- status: "uploading" | "processing" | "completed" | "error";
69
- error?: string;
70
- url?: string;
71
- }
72
-
73
- export interface MediaCompressionOptions {
74
- quality: number;
75
- maxWidth?: number;
76
- maxHeight?: number;
77
- maxFileSize?: number;
78
- format?: "jpeg" | "png" | "webp";
79
- }
80
-
81
- export interface MediaFile {
82
- name: string;
83
- type: string;
84
- size: number;
85
- uri?: string;
86
- }
87
-
88
- export interface CreateMultimediaCardData {
89
- front: string;
90
- back: string;
91
- difficulty?: "easy" | "medium" | "hard";
92
- tags?: string[];
93
- media?: MediaAttachment[];
94
- }
95
-
96
- export interface MediaValidation {
97
- isValid: boolean;
98
- errors: string[];
99
- warnings: string[];
100
- recommendations: string[];
101
- }
@@ -1,80 +0,0 @@
1
- /**
2
- * Media Generation Service
3
- * Handles AI media generation (text-to-image, text-to-audio)
4
- */
5
-
6
- import type {
7
- MediaAttachment,
8
- MediaGenerationRequest,
9
- MediaGenerationResult,
10
- MediaType,
11
- MediaPosition,
12
- } from "../../domain/entities/MediaAttachments";
13
-
14
- export class MediaGenerationService {
15
- /**
16
- * Generate media from AI (text-to-image, text-to-audio, etc.)
17
- */
18
- async generateMedia(
19
- request: MediaGenerationRequest,
20
- ): Promise<MediaGenerationResult> {
21
- try {
22
- const startTime = Date.now();
23
-
24
- // Simulate AI generation
25
- await new Promise((resolve) => setTimeout(resolve, 3000));
26
-
27
- const attachments: MediaAttachment[] = [];
28
-
29
- switch (request.type) {
30
- case "text_to_image":
31
- for (let i = 0; i < (request.options.maxResults || 1); i++) {
32
- attachments.push({
33
- id: `ai_img_${Date.now()}_${i}`,
34
- type: "image" as MediaType,
35
- position: "both" as MediaPosition,
36
- url: `https://picsum.photos/400/300?random=${Date.now() + i}`,
37
- filename: `ai_generated_${i}.jpg`,
38
- fileSize: 150000,
39
- mimeType: "image/jpeg",
40
- isDownloaded: false,
41
- createdAt: new Date().toISOString(),
42
- });
43
- }
44
- break;
45
-
46
- case "text_to_audio":
47
- attachments.push({
48
- id: `ai_audio_${Date.now()}`,
49
- type: "audio" as MediaType,
50
- position: "back" as MediaPosition,
51
- url: `https://example.com/audio_${Date.now()}.mp3`,
52
- filename: `ai_generated_${Date.now()}.mp3`,
53
- fileSize: 80000,
54
- mimeType: "audio/mp3",
55
- duration: 10,
56
- isDownloaded: false,
57
- createdAt: new Date().toISOString(),
58
- });
59
- break;
60
- }
61
-
62
- return {
63
- success: true,
64
- attachments,
65
- creditsUsed: request.type === "text_to_image" ? 5 : 3,
66
- processingTime: Date.now() - startTime,
67
- requestId: `req_${Date.now()}`,
68
- };
69
- } catch (error) {
70
- return {
71
- success: false,
72
- attachments: [],
73
- creditsUsed: 0,
74
- processingTime: 0,
75
- error: error instanceof Error ? error.message : "Unknown error",
76
- requestId: "",
77
- };
78
- }
79
- }
80
- }
@@ -1,32 +0,0 @@
1
- /**
2
- * Media Optimizer Service
3
- * Handles media optimization and deletion
4
- */
5
-
6
- import type {
7
- MediaAttachment,
8
- MediaCompressionOptions,
9
- } from "../../domain/entities/MediaAttachments";
10
-
11
- export class MediaOptimizerService {
12
- /**
13
- * Optimize media file
14
- */
15
- async optimizeMedia(
16
- attachment: MediaAttachment,
17
- options: MediaCompressionOptions,
18
- ): Promise<MediaAttachment> {
19
- return {
20
- ...attachment,
21
- fileSize: Math.floor(attachment.fileSize * options.quality),
22
- url: `${attachment.url}?optimized=true`,
23
- };
24
- }
25
-
26
- /**
27
- * Delete media attachment
28
- */
29
- async deleteMedia(_attachmentId: string): Promise<void> {
30
- // Mock implementation
31
- }
32
- }
@@ -1,157 +0,0 @@
1
- /**
2
- * Media Domain - Media Picker Service
3
- *
4
- * Service for picking images/videos using expo-image-picker.
5
- * Handles camera, gallery, and media library permissions.
6
- */
7
-
8
- import * as ImagePicker from "expo-image-picker";
9
- import type {
10
- MediaPickerOptions,
11
- MediaPickerResult,
12
- CameraOptions,
13
- } from "../../domain/entities/Media";
14
- import {
15
- MediaType,
16
- MediaValidationError,
17
- MEDIA_CONSTANTS,
18
- } from "../../domain/entities/Media";
19
- import {
20
- mapMediaType,
21
- mapPickerResult,
22
- } from "../utils/mediaPickerMappers";
23
- import { PermissionManager } from "../utils/PermissionManager";
24
- import { FileValidator } from "../../domain/utils/FileValidator";
25
-
26
- /**
27
- * Media picker service for selecting images/videos
28
- */
29
- export class MediaPickerService {
30
- static async launchCamera(
31
- options?: CameraOptions
32
- ): Promise<MediaPickerResult> {
33
- try {
34
- const permission = await PermissionManager.requestCameraPermission();
35
- if (!PermissionManager.isPermissionGranted(permission)) {
36
- return { canceled: true };
37
- }
38
-
39
- const result = await ImagePicker.launchCameraAsync({
40
- mediaTypes: ["images"],
41
- allowsEditing: options?.allowsEditing ?? false,
42
- aspect: options?.aspect,
43
- quality: options?.quality ?? MEDIA_CONSTANTS.DEFAULT_QUALITY,
44
- base64: options?.base64 ?? false,
45
- });
46
-
47
- return mapPickerResult(result);
48
- } catch {
49
- return { canceled: true };
50
- }
51
- }
52
-
53
- static async launchCameraForVideo(
54
- options?: CameraOptions
55
- ): Promise<MediaPickerResult> {
56
- try {
57
- const permission = await PermissionManager.requestCameraPermission();
58
- if (!PermissionManager.isPermissionGranted(permission)) {
59
- return { canceled: true };
60
- }
61
-
62
- const result = await ImagePicker.launchCameraAsync({
63
- mediaTypes: ["videos"],
64
- allowsEditing: options?.allowsEditing ?? false,
65
- quality: options?.quality ?? MEDIA_CONSTANTS.DEFAULT_QUALITY,
66
- videoMaxDuration: options?.videoMaxDuration,
67
- });
68
-
69
- return mapPickerResult(result);
70
- } catch {
71
- return { canceled: true };
72
- }
73
- }
74
-
75
- static async pickImage(
76
- options?: MediaPickerOptions
77
- ): Promise<MediaPickerResult> {
78
- try {
79
- const permission = await PermissionManager.requestMediaLibraryPermission();
80
- if (!PermissionManager.isPermissionGranted(permission)) {
81
- return {
82
- canceled: true,
83
- error: MediaValidationError.PERMISSION_DENIED,
84
- errorMessage: "Permission to access media library was denied",
85
- };
86
- }
87
-
88
- const result = await ImagePicker.launchImageLibraryAsync({
89
- mediaTypes: mapMediaType(options?.mediaTypes),
90
- allowsEditing: options?.allowsEditing ?? false,
91
- allowsMultipleSelection: options?.allowsMultipleSelection ?? false,
92
- aspect: options?.aspect,
93
- quality: options?.quality ?? MEDIA_CONSTANTS.DEFAULT_QUALITY,
94
- selectionLimit:
95
- options?.selectionLimit ?? MEDIA_CONSTANTS.DEFAULT_SELECTION_LIMIT,
96
- base64: options?.base64 ?? false,
97
- });
98
-
99
- const mappedResult = mapPickerResult(result);
100
-
101
- // Validate file size if not canceled and has assets
102
- if (!mappedResult.canceled && mappedResult.assets && mappedResult.assets.length > 0) {
103
- const validation = FileValidator.validateAssets(mappedResult.assets, {
104
- maxFileSizeMB: options?.maxFileSizeMB,
105
- });
106
-
107
- if (!validation.valid) {
108
- return {
109
- canceled: true,
110
- error: validation.error,
111
- errorMessage: validation.errorMessage,
112
- };
113
- }
114
- }
115
-
116
- return mappedResult;
117
- } catch {
118
- return { canceled: true };
119
- }
120
- }
121
-
122
- static async pickSingleImage(
123
- options?: Omit<MediaPickerOptions, "allowsMultipleSelection">
124
- ): Promise<MediaPickerResult> {
125
- return MediaPickerService.pickImage({
126
- ...options,
127
- allowsMultipleSelection: false,
128
- });
129
- }
130
-
131
- static async pickMultipleImages(
132
- options?: Omit<MediaPickerOptions, "allowsMultipleSelection">
133
- ): Promise<MediaPickerResult> {
134
- return MediaPickerService.pickImage({
135
- ...options,
136
- allowsMultipleSelection: true,
137
- });
138
- }
139
-
140
- static async pickVideo(
141
- options?: Omit<MediaPickerOptions, "mediaTypes">
142
- ): Promise<MediaPickerResult> {
143
- return MediaPickerService.pickImage({
144
- ...options,
145
- mediaTypes: MediaType.VIDEO,
146
- });
147
- }
148
-
149
- static async pickMedia(
150
- options?: MediaPickerOptions
151
- ): Promise<MediaPickerResult> {
152
- return MediaPickerService.pickImage({
153
- ...options,
154
- mediaTypes: MediaType.ALL,
155
- });
156
- }
157
- }
@@ -1,97 +0,0 @@
1
- /**
2
- * Media Save Service
3
- * Saves media to device storage using expo-file-system
4
- */
5
-
6
- import * as FileSystem from "expo-file-system";
7
- import { MediaLibraryPermission } from "../../domain/entities/Media";
8
-
9
- export interface SaveResult {
10
- success: boolean;
11
- path?: string;
12
- error?: string;
13
- }
14
-
15
- export interface SaveOptions {
16
- album?: string;
17
- }
18
-
19
- /**
20
- * Service for saving media to gallery
21
- */
22
- export class MediaSaveService {
23
- /**
24
- * Request media library write permission
25
- */
26
- static async requestPermission(): Promise<MediaLibraryPermission> {
27
- return MediaLibraryPermission.GRANTED;
28
- }
29
-
30
- /**
31
- * Get current permission status
32
- */
33
- static async getPermissionStatus(): Promise<MediaLibraryPermission> {
34
- return MediaLibraryPermission.GRANTED;
35
- }
36
-
37
- /**
38
- * Save image to gallery
39
- */
40
- static async saveImage(
41
- uri: string,
42
- options?: SaveOptions,
43
- ): Promise<SaveResult> {
44
- return MediaSaveService.saveToStorage(uri, "image", options);
45
- }
46
-
47
- /**
48
- * Save video to gallery
49
- */
50
- static async saveVideo(
51
- uri: string,
52
- options?: SaveOptions,
53
- ): Promise<SaveResult> {
54
- return MediaSaveService.saveToStorage(uri, "video", options);
55
- }
56
-
57
- /**
58
- * Save media (image or video) to storage
59
- */
60
- private static async saveToStorage(
61
- uri: string,
62
- mediaType: "image" | "video",
63
- _options?: SaveOptions,
64
- ): Promise<SaveResult> {
65
- try {
66
- const timestamp = Date.now();
67
- const extension = mediaType === "image" ? "jpg" : "mp4";
68
- const filename = `${mediaType}_${timestamp}.${extension}`;
69
-
70
- const directory = (FileSystem as { documentDirectory?: string | null }).documentDirectory;
71
- if (!directory) {
72
- return {
73
- success: false,
74
- error: "Document directory not available",
75
- };
76
- }
77
-
78
- const destination = `${directory}${filename}`;
79
-
80
- await FileSystem.copyAsync({
81
- from: uri,
82
- to: destination,
83
- });
84
-
85
- return {
86
- success: true,
87
- path: destination,
88
- };
89
- } catch (error) {
90
- const message = error instanceof Error ? error.message : "Unknown error";
91
- return {
92
- success: false,
93
- error: `Failed to save media: ${message}`,
94
- };
95
- }
96
- }
97
- }
@@ -1,60 +0,0 @@
1
- /**
2
- * Media Upload Service
3
- * Handles media upload, download, and URL operations
4
- */
5
-
6
- import type {
7
- MediaAttachment,
8
- MediaCompressionOptions,
9
- MediaFile,
10
- } from "../../domain/entities/MediaAttachments";
11
- import { generateThumbnail, getMediaDuration } from "../utils/file-media-utils";
12
- import { getMediaTypeFromMime } from "../utils/mime-type-detector";
13
-
14
- export class MediaUploadService {
15
- /**
16
- * Upload media file with optional compression
17
- */
18
- async uploadMedia(
19
- file: MediaFile,
20
- _options?: MediaCompressionOptions,
21
- ): Promise<MediaAttachment> {
22
- try {
23
- // Simulate upload process
24
- await new Promise((resolve) => setTimeout(resolve, 2000));
25
-
26
- const attachment: MediaAttachment = {
27
- id: `media_${Date.now()}`,
28
- type: getMediaTypeFromMime(file.type),
29
- position: "both",
30
- url: `https://storage.example.com/media/${Date.now()}_${file.name}`,
31
- filename: file.name,
32
- fileSize: file.size || 100000,
33
- mimeType: file.type,
34
- duration: await getMediaDuration(file),
35
- thumbnailUrl: generateThumbnail(file),
36
- caption: "",
37
- isDownloaded: true,
38
- createdAt: new Date().toISOString(),
39
- };
40
-
41
- return attachment;
42
- } catch (error) {
43
- throw new Error(`Failed to upload media: ${error}`);
44
- }
45
- }
46
-
47
- /**
48
- * Get media URL
49
- */
50
- async getMediaUrl(attachmentId: string): Promise<string> {
51
- return `https://storage.example.com/media/${attachmentId}`;
52
- }
53
-
54
- /**
55
- * Download media to local storage
56
- */
57
- async downloadMedia(attachmentId: string): Promise<string> {
58
- return `/local/storage/${attachmentId}`;
59
- }
60
- }
@@ -1,61 +0,0 @@
1
- /**
2
- * Media Validation Service
3
- * Handles media file validation before upload
4
- */
5
-
6
- import { formatFileSize } from "../utils/media-collection-utils";
7
- import type { MediaValidation, MediaFile } from "../../domain/entities/MediaAttachments";
8
-
9
- export class MediaValidationService {
10
- /**
11
- * Validate media file before upload
12
- */
13
- async validateMedia(file: MediaFile): Promise<MediaValidation> {
14
- try {
15
- const errors: string[] = [];
16
- const warnings: string[] = [];
17
- const recommendations: string[] = [];
18
-
19
- // File size validation
20
- const maxSize = 50 * 1024 * 1024; // 50MB
21
- if (file.size > maxSize) {
22
- errors.push(
23
- `File size (${formatFileSize(file.size)}) exceeds maximum allowed size (${formatFileSize(maxSize)})`,
24
- );
25
- } else if (file.size > 10 * 1024 * 1024) {
26
- warnings.push(`Large file size may impact performance`);
27
- recommendations.push("Consider compressing file");
28
- }
29
-
30
- // File type validation
31
- const supportedTypes = [
32
- "image/jpeg",
33
- "image/png",
34
- "image/webp",
35
- "audio/mp3",
36
- "audio/wav",
37
- "audio/m4a",
38
- "video/mp4",
39
- "video/mov",
40
- ];
41
-
42
- if (!supportedTypes.includes(file.type)) {
43
- errors.push(`Unsupported file type: ${file.type}`);
44
- }
45
-
46
- return {
47
- isValid: errors.length === 0,
48
- errors,
49
- warnings,
50
- recommendations,
51
- };
52
- } catch (error) {
53
- return {
54
- isValid: false,
55
- errors: [error instanceof Error ? error.message : "Validation failed"],
56
- warnings: [],
57
- recommendations: [],
58
- };
59
- }
60
- }
61
- }