@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
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import { useState, useCallback } from "react";
|
|
7
7
|
import { formatFileSize } from "../../infrastructure/utils/media-collection-utils";
|
|
8
8
|
import type { UseMediaValidationResult } from "./multimedia.types";
|
|
9
|
-
import type { MediaValidation, MediaFile } from "../../domain/entities/
|
|
9
|
+
import type { MediaValidation, MediaFile } from "../../domain/entities/MediaAttachments";
|
|
10
10
|
|
|
11
11
|
export const useMediaValidation = (): UseMediaValidationResult => {
|
|
12
12
|
const [isValidating, setIsValidating] = useState(false);
|
|
@@ -10,7 +10,7 @@ import type {
|
|
|
10
10
|
MediaAttachment,
|
|
11
11
|
MultimediaFlashcard,
|
|
12
12
|
CreateMultimediaCardData,
|
|
13
|
-
} from "../../domain/entities/
|
|
13
|
+
} from "../../domain/entities/MediaAttachments";
|
|
14
14
|
|
|
15
15
|
// Export individual hooks
|
|
16
16
|
export { useMediaUpload } from "./useMediaUpload";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
2
|
import { View, StyleSheet, TouchableOpacity } from 'react-native';
|
|
3
3
|
import { AtomicText } from '../../../atoms';
|
|
4
4
|
import { AtomicIcon, useIconName } from '../../../atoms';
|
|
@@ -20,7 +20,7 @@ export const NavigationHeader: React.FC<NavigationHeaderProps> = ({
|
|
|
20
20
|
const insets = useSafeAreaInsets();
|
|
21
21
|
const arrowLeftIcon = useIconName('arrowLeft');
|
|
22
22
|
|
|
23
|
-
const styles = StyleSheet.create({
|
|
23
|
+
const styles = useMemo(() => StyleSheet.create({
|
|
24
24
|
container: {
|
|
25
25
|
paddingTop: insets.top,
|
|
26
26
|
paddingHorizontal: tokens.spacing.md,
|
|
@@ -45,7 +45,7 @@ export const NavigationHeader: React.FC<NavigationHeaderProps> = ({
|
|
|
45
45
|
flex: 1,
|
|
46
46
|
textAlign: 'left',
|
|
47
47
|
},
|
|
48
|
-
});
|
|
48
|
+
}), [tokens, insets]);
|
|
49
49
|
|
|
50
50
|
return (
|
|
51
51
|
<View style={styles.container}>
|
|
@@ -40,7 +40,7 @@ export const navigate = (name: string, params?: object): void => {
|
|
|
40
40
|
if (__DEV__) {
|
|
41
41
|
}
|
|
42
42
|
if (navigationRef?.isReady()) {
|
|
43
|
-
navigationRef.navigate(name
|
|
43
|
+
navigationRef.navigate(name, params);
|
|
44
44
|
}
|
|
45
45
|
};
|
|
46
46
|
|
|
@@ -54,10 +54,10 @@ export const navigateNested = (navigatorName: string, screenName: string, params
|
|
|
54
54
|
if (__DEV__) {
|
|
55
55
|
}
|
|
56
56
|
if (navigationRef?.isReady()) {
|
|
57
|
-
navigationRef.navigate(navigatorName
|
|
57
|
+
navigationRef.navigate(navigatorName, {
|
|
58
58
|
screen: screenName,
|
|
59
59
|
params,
|
|
60
|
-
}
|
|
60
|
+
});
|
|
61
61
|
}
|
|
62
62
|
};
|
|
63
63
|
|
package/src/offline/index.ts
CHANGED
|
@@ -14,6 +14,7 @@ export type {
|
|
|
14
14
|
|
|
15
15
|
// Store
|
|
16
16
|
export { useOfflineStore } from './infrastructure/storage/OfflineStore';
|
|
17
|
+
export { useOfflineConfigStore } from './infrastructure/storage/OfflineConfigStore';
|
|
17
18
|
|
|
18
19
|
// Hooks
|
|
19
20
|
export { useOffline, configureOffline } from './presentation/hooks/useOffline';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Offline Config Store
|
|
3
|
+
* Centralized configuration for offline functionality
|
|
4
|
+
* Replaces module-level mutable state with Zustand store
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { create } from 'zustand';
|
|
8
|
+
import type { OfflineConfig } from '../../types';
|
|
9
|
+
|
|
10
|
+
interface OfflineConfigStore {
|
|
11
|
+
config: OfflineConfig;
|
|
12
|
+
setConfig: (config: OfflineConfig) => void;
|
|
13
|
+
mergeConfig: (partialConfig: OfflineConfig) => void;
|
|
14
|
+
reset: () => void;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const useOfflineConfigStore = create<OfflineConfigStore>((set) => ({
|
|
18
|
+
config: {},
|
|
19
|
+
|
|
20
|
+
setConfig: (config) => set({ config }),
|
|
21
|
+
|
|
22
|
+
mergeConfig: (partialConfig) => set((state) => ({
|
|
23
|
+
config: { ...state.config, ...partialConfig }
|
|
24
|
+
})),
|
|
25
|
+
|
|
26
|
+
reset: () => set({ config: {} }),
|
|
27
|
+
}));
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Get current config (for non-React contexts)
|
|
31
|
+
*/
|
|
32
|
+
export const getOfflineConfig = (): OfflineConfig => {
|
|
33
|
+
return useOfflineConfigStore.getState().config;
|
|
34
|
+
};
|
|
@@ -10,6 +10,7 @@ import type { NetworkState as ExpoNetworkState } from 'expo-network';
|
|
|
10
10
|
import type { NetworkState, OfflineConfig } from '../../types';
|
|
11
11
|
import { useOfflineStore } from '../../infrastructure/storage/OfflineStore';
|
|
12
12
|
import { networkEvents } from '../../infrastructure/events/NetworkEvents';
|
|
13
|
+
import { useOfflineConfigStore } from '../../infrastructure/storage/OfflineConfigStore';
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Convert expo-network state to our internal format
|
|
@@ -21,14 +22,17 @@ const toNetworkState = (state: ExpoNetworkState): NetworkState => ({
|
|
|
21
22
|
details: null,
|
|
22
23
|
});
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Configure offline settings globally
|
|
27
|
+
* This is a facade over the config store for backward compatibility
|
|
28
|
+
*/
|
|
26
29
|
export const configureOffline = (config: OfflineConfig): void => {
|
|
27
|
-
|
|
30
|
+
useOfflineConfigStore.getState().setConfig(config);
|
|
28
31
|
};
|
|
29
32
|
|
|
30
33
|
export const useOffline = (config?: OfflineConfig) => {
|
|
31
34
|
const store = useOfflineStore();
|
|
35
|
+
const globalConfig = useOfflineConfigStore((state) => state.config);
|
|
32
36
|
const isInitialized = useRef(false);
|
|
33
37
|
const previousStateRef = useRef<NetworkState | null>(null);
|
|
34
38
|
const isMountedRef = useRef(true);
|
|
@@ -36,7 +40,7 @@ export const useOffline = (config?: OfflineConfig) => {
|
|
|
36
40
|
// Memoize merged config to prevent unnecessary effect re-runs
|
|
37
41
|
const mergedConfig = useMemo(
|
|
38
42
|
() => ({ ...globalConfig, ...config }),
|
|
39
|
-
[config]
|
|
43
|
+
[globalConfig, config]
|
|
40
44
|
);
|
|
41
45
|
|
|
42
46
|
const handleNetworkStateChange = useCallback((state: ExpoNetworkState) => {
|
|
@@ -9,27 +9,3 @@ export const isDev = (): boolean => {
|
|
|
9
9
|
return __DEV__;
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
-
/**
|
|
13
|
-
* Log warning in development mode only
|
|
14
|
-
* All logs are disabled
|
|
15
|
-
*/
|
|
16
|
-
export const devWarn = (_message: string, ..._args: unknown[]): void => {
|
|
17
|
-
// Disabled
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Log error in development mode only
|
|
22
|
-
* All logs are disabled
|
|
23
|
-
*/
|
|
24
|
-
export const devError = (_message: string, ..._args: unknown[]): void => {
|
|
25
|
-
// Disabled
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Log info in development mode only
|
|
30
|
-
* All logs are disabled
|
|
31
|
-
*/
|
|
32
|
-
export const devLog = (_message: string, ..._args: unknown[]): void => {
|
|
33
|
-
// Disabled
|
|
34
|
-
};
|
|
35
|
-
|
package/src/storage/index.ts
CHANGED
|
@@ -82,7 +82,7 @@ export { TIME_MS, DEFAULT_TTL, CACHE_VERSION } from './domain/constants/CacheDef
|
|
|
82
82
|
// DOMAIN LAYER - Development Utilities
|
|
83
83
|
// =============================================================================
|
|
84
84
|
|
|
85
|
-
export { isDev
|
|
85
|
+
export { isDev } from './domain/utils/devUtils';
|
|
86
86
|
|
|
87
87
|
// =============================================================================
|
|
88
88
|
// DOMAIN LAYER - Store Types
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
9
|
-
import { devWarn } from '../../domain/utils/devUtils';
|
|
10
9
|
import type { StateStorage } from '../../domain/types/Store';
|
|
11
10
|
|
|
12
11
|
/**
|
|
@@ -17,9 +16,7 @@ export const storageService: StateStorage = {
|
|
|
17
16
|
getItem: async (name: string): Promise<string | null> => {
|
|
18
17
|
try {
|
|
19
18
|
return await AsyncStorage.getItem(name);
|
|
20
|
-
} catch (
|
|
21
|
-
const errorMessage = `StorageService: Failed to get item "${name}"`;
|
|
22
|
-
devWarn(errorMessage, error);
|
|
19
|
+
} catch (_error) {
|
|
23
20
|
return null;
|
|
24
21
|
}
|
|
25
22
|
},
|
|
@@ -27,18 +24,16 @@ export const storageService: StateStorage = {
|
|
|
27
24
|
setItem: async (name: string, value: string): Promise<void> => {
|
|
28
25
|
try {
|
|
29
26
|
await AsyncStorage.setItem(name, value);
|
|
30
|
-
} catch (
|
|
31
|
-
|
|
32
|
-
devWarn(errorMessage, error);
|
|
27
|
+
} catch (_error) {
|
|
28
|
+
// Silent failure
|
|
33
29
|
}
|
|
34
30
|
},
|
|
35
31
|
|
|
36
32
|
removeItem: async (name: string): Promise<void> => {
|
|
37
33
|
try {
|
|
38
34
|
await AsyncStorage.removeItem(name);
|
|
39
|
-
} catch (
|
|
40
|
-
|
|
41
|
-
devWarn(errorMessage, error);
|
|
35
|
+
} catch (_error) {
|
|
36
|
+
// Silent failure
|
|
42
37
|
}
|
|
43
38
|
},
|
|
44
39
|
};
|
|
@@ -14,7 +14,6 @@ import {
|
|
|
14
14
|
StorageSerializationError,
|
|
15
15
|
StorageDeserializationError,
|
|
16
16
|
} from '../../domain/errors/StorageError';
|
|
17
|
-
import { devWarn } from '../../domain/utils/devUtils';
|
|
18
17
|
|
|
19
18
|
/**
|
|
20
19
|
* Base storage operations implementation
|
|
@@ -37,7 +36,7 @@ export class BaseStorageOperations {
|
|
|
37
36
|
} catch (parseError) {
|
|
38
37
|
return failure(new StorageDeserializationError(key, parseError), defaultValue);
|
|
39
38
|
}
|
|
40
|
-
} catch (
|
|
39
|
+
} catch (_error) {
|
|
41
40
|
return failure(new StorageReadError(key, error), defaultValue);
|
|
42
41
|
}
|
|
43
42
|
}
|
|
@@ -56,7 +55,7 @@ export class BaseStorageOperations {
|
|
|
56
55
|
|
|
57
56
|
await AsyncStorage.setItem(key, serialized);
|
|
58
57
|
return success(value);
|
|
59
|
-
} catch (
|
|
58
|
+
} catch (_error) {
|
|
60
59
|
return failure(new StorageWriteError(key, error));
|
|
61
60
|
}
|
|
62
61
|
}
|
|
@@ -68,7 +67,7 @@ export class BaseStorageOperations {
|
|
|
68
67
|
try {
|
|
69
68
|
await AsyncStorage.removeItem(key);
|
|
70
69
|
return success(undefined);
|
|
71
|
-
} catch (
|
|
70
|
+
} catch (_error) {
|
|
72
71
|
return failure(new StorageDeleteError(key, error));
|
|
73
72
|
}
|
|
74
73
|
}
|
|
@@ -80,9 +79,7 @@ export class BaseStorageOperations {
|
|
|
80
79
|
try {
|
|
81
80
|
const value = await AsyncStorage.getItem(key);
|
|
82
81
|
return value !== null;
|
|
83
|
-
} catch (
|
|
84
|
-
const errorMessage = `BaseStorageOperations: Failed to check if key "${key}" exists`;
|
|
85
|
-
devWarn(errorMessage, error);
|
|
82
|
+
} catch (_error) {
|
|
86
83
|
return false;
|
|
87
84
|
}
|
|
88
85
|
}
|
|
@@ -94,7 +91,7 @@ export class BaseStorageOperations {
|
|
|
94
91
|
try {
|
|
95
92
|
await AsyncStorage.clear();
|
|
96
93
|
return success(undefined);
|
|
97
|
-
} catch (
|
|
94
|
+
} catch (_error) {
|
|
98
95
|
return failure(new StorageDeleteError('ALL_KEYS', error));
|
|
99
96
|
}
|
|
100
97
|
}
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
import { storageRepository } from '../../infrastructure/repositories/AsyncStorageRepository';
|
|
8
8
|
import type { CachedValue } from '../../domain/entities/CachedValue';
|
|
9
9
|
import { createCachedValue } from '../../domain/entities/CachedValue';
|
|
10
|
-
import { devWarn } from '../../domain/utils/devUtils';
|
|
11
10
|
import { isValidCachedValue } from '../../domain/utils/ValidationUtils';
|
|
12
11
|
|
|
13
12
|
export interface CacheStorageOptions {
|
|
@@ -56,16 +55,11 @@ export class CacheStorageOperations {
|
|
|
56
55
|
return parsed as CachedValue<T>;
|
|
57
56
|
}
|
|
58
57
|
|
|
59
|
-
if (__DEV__) {
|
|
60
|
-
devWarn(`CacheStorageOperations: Invalid cached data structure for key "${key}"`);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
58
|
return null;
|
|
64
59
|
}
|
|
65
60
|
|
|
66
61
|
return null;
|
|
67
|
-
} catch (
|
|
68
|
-
devWarn(`CacheStorageOperations: Failed to load cache for key "${key}"`, error);
|
|
62
|
+
} catch (_error) {
|
|
69
63
|
return null;
|
|
70
64
|
}
|
|
71
65
|
}
|
|
@@ -85,8 +79,8 @@ export class CacheStorageOperations {
|
|
|
85
79
|
try {
|
|
86
80
|
const cached = createCachedValue(value, ttl || 0, version);
|
|
87
81
|
await storageRepository.setString(key, JSON.stringify(cached));
|
|
88
|
-
} catch (
|
|
89
|
-
|
|
82
|
+
} catch (_error) {
|
|
83
|
+
// Silent failure
|
|
90
84
|
}
|
|
91
85
|
}
|
|
92
86
|
|
|
@@ -98,8 +92,8 @@ export class CacheStorageOperations {
|
|
|
98
92
|
|
|
99
93
|
try {
|
|
100
94
|
await storageRepository.removeItem(key);
|
|
101
|
-
} catch (
|
|
102
|
-
|
|
95
|
+
} catch (_error) {
|
|
96
|
+
// Silent failure
|
|
103
97
|
}
|
|
104
98
|
}
|
|
105
99
|
}
|
|
@@ -3,14 +3,22 @@
|
|
|
3
3
|
* Helper for creating stores in components
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { useMemo
|
|
6
|
+
import { useMemo } from 'react';
|
|
7
7
|
import { createStore } from '../../domain/factories/StoreFactory';
|
|
8
8
|
import type { StoreConfig } from '../../domain/types/Store';
|
|
9
9
|
|
|
10
10
|
export function useStore<T extends object>(config: StoreConfig<T>) {
|
|
11
|
-
//
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
// Stabilize entire config to track all property changes
|
|
12
|
+
const stableConfig = useMemo(
|
|
13
|
+
() => config,
|
|
14
|
+
[
|
|
15
|
+
config.name,
|
|
16
|
+
config.version,
|
|
17
|
+
config.persist,
|
|
18
|
+
config.storage,
|
|
19
|
+
]
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
const store = useMemo(() => createStore(stableConfig), [stableConfig]);
|
|
15
23
|
return store;
|
|
16
24
|
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* @layer presentation/hooks
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { useState, useCallback, useEffect } from 'react';
|
|
11
|
+
import { useState, useCallback, useEffect, useMemo } from 'react';
|
|
12
12
|
import { SharingService } from '../../infrastructure/services/SharingService';
|
|
13
13
|
import type { ShareOptions } from '../../domain/entities/Share';
|
|
14
14
|
|
|
@@ -140,7 +140,7 @@ export const useSharing = () => {
|
|
|
140
140
|
[]
|
|
141
141
|
);
|
|
142
142
|
|
|
143
|
-
return {
|
|
143
|
+
return useMemo(() => ({
|
|
144
144
|
// Functions
|
|
145
145
|
share,
|
|
146
146
|
shareWithAutoType,
|
|
@@ -150,5 +150,5 @@ export const useSharing = () => {
|
|
|
150
150
|
isAvailable,
|
|
151
151
|
isSharing,
|
|
152
152
|
error,
|
|
153
|
-
};
|
|
153
|
+
}), [share, shareWithAutoType, shareMultiple, isAvailable, isSharing, error]);
|
|
154
154
|
};
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Enhanced ScreenLayout Example
|
|
3
|
-
*
|
|
4
|
-
* This demonstrates the recommended usage of ScreenLayout with SafeAreaProvider
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import React from 'react';
|
|
8
|
-
import { View, Text } from 'react-native';
|
|
9
|
-
import {
|
|
10
|
-
SafeAreaProvider,
|
|
11
|
-
ScreenLayout,
|
|
12
|
-
ScreenHeader,
|
|
13
|
-
AtomicButton,
|
|
14
|
-
AtomicText
|
|
15
|
-
} from '../../index';
|
|
16
|
-
|
|
17
|
-
// 1. Wrap your app root with SafeAreaProvider
|
|
18
|
-
export function App() {
|
|
19
|
-
return (
|
|
20
|
-
<SafeAreaProvider>
|
|
21
|
-
<View />
|
|
22
|
-
</SafeAreaProvider>
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// 2. Use ScreenLayout in your screens
|
|
27
|
-
export function HomeScreen() {
|
|
28
|
-
return (
|
|
29
|
-
<ScreenLayout
|
|
30
|
-
// Safe area edges - default is ['top']
|
|
31
|
-
edges={['top']}
|
|
32
|
-
// Enable scrolling - default is true
|
|
33
|
-
scrollable={true}
|
|
34
|
-
// Optional header
|
|
35
|
-
header={
|
|
36
|
-
<ScreenHeader
|
|
37
|
-
title="Home"
|
|
38
|
-
/>
|
|
39
|
-
}
|
|
40
|
-
// Optional footer
|
|
41
|
-
footer={
|
|
42
|
-
<View style={{ padding: 16 }}>
|
|
43
|
-
<AtomicButton onPress={() => console.log('Action')}>
|
|
44
|
-
Action Button
|
|
45
|
-
</AtomicButton>
|
|
46
|
-
</View>
|
|
47
|
-
}
|
|
48
|
-
>
|
|
49
|
-
<AtomicText type="headlineLarge">Welcome to Home</AtomicText>
|
|
50
|
-
<AtomicText type="bodyMedium">
|
|
51
|
-
This screen uses ScreenLayout with default safe area configuration.
|
|
52
|
-
</AtomicText>
|
|
53
|
-
</ScreenLayout>
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// 3. Modal screen example with different safe area edges
|
|
58
|
-
export function ModalScreen() {
|
|
59
|
-
return (
|
|
60
|
-
<ScreenLayout
|
|
61
|
-
// Full safe area for modals
|
|
62
|
-
edges={['top', 'bottom']}
|
|
63
|
-
scrollable={false}
|
|
64
|
-
>
|
|
65
|
-
<AtomicText type="headlineMedium">Modal Content</AtomicText>
|
|
66
|
-
</ScreenLayout>
|
|
67
|
-
);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// 4. Screen with custom scroll behavior
|
|
71
|
-
export function CustomScrollScreen() {
|
|
72
|
-
return (
|
|
73
|
-
<ScreenLayout scrollable={false}>
|
|
74
|
-
{/* Your custom scroll component */}
|
|
75
|
-
<View />
|
|
76
|
-
</ScreenLayout>
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// 5. Using safe area hooks directly
|
|
81
|
-
import { useContentSafeAreaPadding, useSafeAreaInsets } from '../../index';
|
|
82
|
-
|
|
83
|
-
export function CustomComponent() {
|
|
84
|
-
const insets = useSafeAreaInsets();
|
|
85
|
-
const { paddingBottom } = useContentSafeAreaPadding();
|
|
86
|
-
|
|
87
|
-
return (
|
|
88
|
-
<View style={{ paddingTop: insets.top, paddingBottom }}>
|
|
89
|
-
<Text>Custom Safe Area Usage</Text>
|
|
90
|
-
</View>
|
|
91
|
-
);
|
|
92
|
-
}
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
# CardMultimedia Types
|
|
2
|
-
|
|
3
|
-
## Purpose
|
|
4
|
-
Type definitions for flashcard-specific media operations. These types define the contract for media attachment, generation, and management within the card-based learning system.
|
|
5
|
-
|
|
6
|
-
## File Location
|
|
7
|
-
`src/domain/entities/CardMultimedia.types.ts`
|
|
8
|
-
|
|
9
|
-
## Strategy
|
|
10
|
-
- Define the contract for card-specific media operations
|
|
11
|
-
- Provide type-safe interfaces for flashcard media attachments
|
|
12
|
-
- Support AI-powered media generation for educational content
|
|
13
|
-
- Enable comprehensive media validation and optimization
|
|
14
|
-
- Maintain clear separation between card media and general media types
|
|
15
|
-
- Support upload progress tracking and compression
|
|
16
|
-
- Facilitate media download management for offline learning
|
|
17
|
-
|
|
18
|
-
## Forbidden
|
|
19
|
-
- **DO NOT** use these types for general-purpose media operations (use Multimedia types instead)
|
|
20
|
-
- **DO NOT** include UI components or presentation logic in type definitions
|
|
21
|
-
- **DO NOT** add business logic or implementation details to interfaces
|
|
22
|
-
- **DO NOT** create circular dependencies with other domain types
|
|
23
|
-
- **DO NOT** use `any` type or loose type definitions
|
|
24
|
-
- **DO NOT** modify existing type properties - extend interfaces for new features
|
|
25
|
-
- **DO NOT** assume specific storage backend or cloud provider
|
|
26
|
-
- **DO NOT** hardcode validation limits in type definitions
|
|
27
|
-
- **DO NOT** mix card media types with general multimedia types
|
|
28
|
-
|
|
29
|
-
## Rules
|
|
30
|
-
1. All card media types must be exported from this file
|
|
31
|
-
2. Type definitions must be framework-agnostic
|
|
32
|
-
3. Card media IDs must use "card_media_" prefix for uniqueness
|
|
33
|
-
4. Position types must explicitly define front/back/both placement
|
|
34
|
-
5. File size fields must use bytes as unit
|
|
35
|
-
6. Duration fields must use seconds as unit
|
|
36
|
-
7. Date fields must use ISO 8601 format
|
|
37
|
-
8. All generation requests must include input validation
|
|
38
|
-
9. Compression quality must be between 0.1 and 1.0
|
|
39
|
-
10. Upload progress must be tracked from 0-100
|
|
40
|
-
11. Validation results must separate errors, warnings, and recommendations
|
|
41
|
-
12. Service interfaces must return Promises for all async operations
|
|
42
|
-
13. Media type arrays must be automatically calculated, not manually set
|
|
43
|
-
14. Download status must be tracked per attachment
|
|
44
|
-
15. Estimated size must represent total of all attachments
|
|
45
|
-
|
|
46
|
-
## AI Agent Guidelines
|
|
47
|
-
|
|
48
|
-
When working with CardMultimedia types:
|
|
49
|
-
|
|
50
|
-
1. **Type Selection**: Use CardMediaAttachment for flashcard-specific media operations
|
|
51
|
-
2. **Generation Requests**: Always specify input parameters and options explicitly
|
|
52
|
-
3. **Validation**: Validate media files before upload and after generation
|
|
53
|
-
4. **Progress Tracking**: Monitor upload progress for user feedback
|
|
54
|
-
5. **Compression**: Apply compression options before upload to reduce bandwidth
|
|
55
|
-
6. **Download Management**: Check isDownloaded status before displaying media
|
|
56
|
-
7. **Position Logic**: Respect position field for front/back/both placement
|
|
57
|
-
8. **Size Estimation**: Calculate total size for all media before batch operations
|
|
58
|
-
9. **Error Handling**: Parse validation errors and warnings for user feedback
|
|
59
|
-
10. **Cost Tracking**: Monitor creditsUsed for AI generation operations
|
|
60
|
-
|
|
61
|
-
### Key Types Reference
|
|
62
|
-
|
|
63
|
-
- **CardMediaType**: "image" | "audio" | "video" - Media type classification for cards
|
|
64
|
-
- **CardMediaPosition**: "front" | "back" | "both" - Display placement on card faces
|
|
65
|
-
- **CardMediaAttachment**: Core interface for individual media items with metadata
|
|
66
|
-
- **CardMultimediaFlashcard**: Card entity with computed media properties
|
|
67
|
-
- **CardMediaGenerationRequest**: Input specification for AI media generation
|
|
68
|
-
- **CardMediaGenerationResult**: Output with cost tracking and performance metrics
|
|
69
|
-
- **CardMediaUploadProgress**: Real-time upload status tracking
|
|
70
|
-
- **CardMediaCompressionOptions**: Quality and size optimization settings
|
|
71
|
-
- **CardMediaValidation**: Comprehensive validation with recommendations
|
|
72
|
-
- **CardMultimediaFlashcardService**: Service interface for media operations
|
|
73
|
-
|
|
74
|
-
### Type Usage Patterns
|
|
75
|
-
|
|
76
|
-
1. **CardMediaAttachment**: Individual media item with position, URL, and metadata
|
|
77
|
-
2. **CardMultimediaFlashcard**: Card with computed properties (hasMedia, mediaType, isDownloaded)
|
|
78
|
-
3. **CardMediaGenerationRequest**: Three generation types (text_to_image, text_to_audio, image_search)
|
|
79
|
-
4. **CardMediaValidation**: Separate errors (blocking) from warnings and recommendations
|
|
80
|
-
|
|
81
|
-
### Validation Rules
|
|
82
|
-
|
|
83
|
-
1. Validate file size against upload limits before processing
|
|
84
|
-
2. Check MIME type matches CardMediaType
|
|
85
|
-
3. Ensure dimensions are within supported ranges
|
|
86
|
-
4. Verify URIs are properly formatted and accessible
|
|
87
|
-
5. Validate duration for audio/video files
|
|
88
|
-
6. Check compression quality is within 0.1-1.0 range
|
|
89
|
-
7. Ensure generation prompts are non-empty strings
|
|
90
|
-
8. Validate language codes for audio generation (e.g., "tr-TR", "en-US")
|
|
91
|
-
|
|
92
|
-
### Service Interface Guidelines
|
|
93
|
-
|
|
94
|
-
When implementing CardMultimediaFlashcardService:
|
|
95
|
-
|
|
96
|
-
1. **uploadMedia**: Accept file with optional compression, return attachment with URL
|
|
97
|
-
2. **generateMedia**: Process AI generation request, track credits and timing
|
|
98
|
-
3. **validateMedia**: Return comprehensive validation with errors, warnings, recommendations
|
|
99
|
-
4. **optimizeMedia**: Apply compression to existing attachment, preserve metadata
|
|
100
|
-
5. **deleteMedia**: Remove attachment and update card associations
|
|
101
|
-
6. **getMediaUrl**: Return accessible URL for downloaded or remote media
|
|
102
|
-
7. **downloadMedia**: Fetch remote media to local storage, update isDownloaded status
|
|
103
|
-
|
|
104
|
-
### Generation Type Specifics
|
|
105
|
-
|
|
106
|
-
1. **text_to_image**: Requires prompt, style (realistic/cartoon/artistic), quality, format
|
|
107
|
-
2. **text_to_audio**: Requires text, language, voice (male/female/neutral), format
|
|
108
|
-
3. **image_search**: Requires prompt, maxResults (no quality/format options)
|
|
109
|
-
|
|
110
|
-
### Position Logic
|
|
111
|
-
|
|
112
|
-
1. **front**: Media displayed only on card front face
|
|
113
|
-
2. **back**: Media displayed only on card back face
|
|
114
|
-
3. **both**: Media displayed on both card faces (e.g., background image)
|
|
115
|
-
|
|
116
|
-
### Download Management
|
|
117
|
-
|
|
118
|
-
1. Check isDownloaded before displaying media offline
|
|
119
|
-
2. Use localPath for offline access when available
|
|
120
|
-
3. Fall back to URL when media not downloaded
|
|
121
|
-
4. Track estimatedSize for storage management
|
|
122
|
-
5. Implement downloadMedia for offline caching
|
|
123
|
-
|
|
124
|
-
## Dependencies
|
|
125
|
-
|
|
126
|
-
- No external dependencies
|
|
127
|
-
- References domain types from Media.ts for base media concepts
|
|
128
|
-
- Must be usable by infrastructure and presentation layers without additional dependencies
|
|
129
|
-
- Service interfaces require async operation support
|