@umituz/react-native-ai-generation-content 1.17.27 → 1.17.29

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-ai-generation-content",
3
- "version": "1.17.27",
3
+ "version": "1.17.29",
4
4
  "description": "Provider-agnostic AI generation orchestration for React Native",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -0,0 +1,122 @@
1
+ /**
2
+ * App Services Interface
3
+ * Defines contracts for app-specific services that package uses
4
+ * Apps implement these interfaces to provide their specific logic
5
+ */
6
+
7
+ /**
8
+ * Network service interface
9
+ * Handles network availability checks
10
+ */
11
+ export interface INetworkService {
12
+ /**
13
+ * Check if device is online
14
+ */
15
+ isOnline: () => boolean;
16
+
17
+ /**
18
+ * Require network connection - throws if offline
19
+ */
20
+ requireNetwork: () => void;
21
+ }
22
+
23
+ /**
24
+ * Credit service interface
25
+ * Handles credit operations (check, deduct, refund)
26
+ */
27
+ export interface ICreditService {
28
+ /**
29
+ * Check if user has enough credits
30
+ * @param cost - Required credit amount
31
+ * @returns true if has enough credits
32
+ */
33
+ checkCredits: (cost: number) => Promise<boolean>;
34
+
35
+ /**
36
+ * Deduct credits from user balance
37
+ * @param cost - Amount to deduct
38
+ */
39
+ deductCredits: (cost: number) => Promise<void>;
40
+
41
+ /**
42
+ * Refund credits on failure (non-user caused errors)
43
+ * @param amount - Amount to refund
44
+ * @param error - Original error (used to determine if refund is applicable)
45
+ */
46
+ refundCredits: (amount: number, error?: unknown) => Promise<void>;
47
+
48
+ /**
49
+ * Calculate credit cost for operation
50
+ * @param capability - Generation capability type
51
+ * @param metadata - Additional metadata for cost calculation
52
+ */
53
+ calculateCost: (
54
+ capability: string,
55
+ metadata?: Record<string, unknown>,
56
+ ) => number;
57
+ }
58
+
59
+ /**
60
+ * Paywall service interface
61
+ * Shows paywall UI when credits insufficient
62
+ */
63
+ export interface IPaywallService {
64
+ /**
65
+ * Show paywall to user
66
+ * @param requiredCredits - Credits needed for operation
67
+ */
68
+ showPaywall: (requiredCredits: number) => void;
69
+ }
70
+
71
+ /**
72
+ * Auth service interface
73
+ * Handles user authentication
74
+ */
75
+ export interface IAuthService {
76
+ /**
77
+ * Get current user ID
78
+ * @returns User ID or null if not authenticated
79
+ */
80
+ getUserId: () => string | null;
81
+
82
+ /**
83
+ * Check if user is authenticated
84
+ */
85
+ isAuthenticated: () => boolean;
86
+
87
+ /**
88
+ * Require authenticated user - throws if not authenticated
89
+ * @returns User ID
90
+ */
91
+ requireAuth: () => string;
92
+ }
93
+
94
+ /**
95
+ * Analytics service interface (optional)
96
+ * Tracks events for analytics
97
+ */
98
+ export interface IAnalyticsService {
99
+ /**
100
+ * Track an event
101
+ * @param event - Event name
102
+ * @param data - Event data
103
+ */
104
+ track: (event: string, data: Record<string, unknown>) => void;
105
+ }
106
+
107
+ /**
108
+ * Combined app services interface
109
+ * Apps implement this to provide all required services
110
+ */
111
+ export interface IAppServices {
112
+ readonly network: INetworkService;
113
+ readonly credits: ICreditService;
114
+ readonly paywall: IPaywallService;
115
+ readonly auth: IAuthService;
116
+ readonly analytics?: IAnalyticsService;
117
+ }
118
+
119
+ /**
120
+ * Partial app services for optional configuration
121
+ */
122
+ export type PartialAppServices = Partial<IAppServices>;
@@ -4,3 +4,4 @@
4
4
  */
5
5
 
6
6
  export * from "./ai-provider.interface";
7
+ export * from "./app-services.interface";
package/src/index.ts CHANGED
@@ -29,6 +29,14 @@ export type {
29
29
  VideoFeatureType,
30
30
  ImageFeatureInputData,
31
31
  VideoFeatureInputData,
32
+ // App Services Interfaces
33
+ INetworkService,
34
+ ICreditService,
35
+ IPaywallService,
36
+ IAuthService,
37
+ IAnalyticsService,
38
+ IAppServices,
39
+ PartialAppServices,
32
40
  } from "./domain/interfaces";
33
41
 
34
42
  export {
@@ -85,6 +93,23 @@ export {
85
93
  getPromptRequiredModes,
86
94
  } from "./domain/constants/processing-modes.constants";
87
95
 
96
+ // =============================================================================
97
+ // INFRASTRUCTURE LAYER - App Services Configuration
98
+ // =============================================================================
99
+
100
+ export {
101
+ configureAppServices,
102
+ updateAppServices,
103
+ getAppServices,
104
+ isAppServicesConfigured,
105
+ resetAppServices,
106
+ getNetworkService,
107
+ getCreditService,
108
+ getPaywallService,
109
+ getAuthService,
110
+ getAnalyticsService,
111
+ } from "./infrastructure/config";
112
+
88
113
  // =============================================================================
89
114
  // INFRASTRUCTURE LAYER - Services
90
115
  // =============================================================================
@@ -250,6 +275,10 @@ export {
250
275
  FeatureHeader,
251
276
  // Photo Upload
252
277
  PhotoUploadCard,
278
+ // Selectors
279
+ StyleSelector,
280
+ AspectRatioSelector,
281
+ DurationSelector,
253
282
  } from "./presentation/components";
254
283
 
255
284
  export type {
@@ -289,6 +318,13 @@ export type {
289
318
  // Photo Upload
290
319
  PhotoUploadCardProps,
291
320
  PhotoUploadCardConfig,
321
+ // Selectors
322
+ StyleSelectorProps,
323
+ AspectRatioSelectorProps,
324
+ DurationSelectorProps,
325
+ StyleOption,
326
+ AspectRatioOption,
327
+ DurationValue,
292
328
  } from "./presentation/components";
293
329
 
294
330
  // =============================================================================
@@ -0,0 +1,122 @@
1
+ /**
2
+ * App Services Configuration
3
+ * Singleton for storing app-provided service implementations
4
+ */
5
+
6
+ import type { IAppServices, PartialAppServices } from "../../domain/interfaces/app-services.interface";
7
+
8
+ declare const __DEV__: boolean;
9
+
10
+ let appServices: IAppServices | null = null;
11
+
12
+ /**
13
+ * Default no-op implementations for optional services
14
+ */
15
+ const defaultAnalytics = {
16
+ track: () => {
17
+ // No-op by default
18
+ },
19
+ };
20
+
21
+ /**
22
+ * Configure app services
23
+ * Must be called before using any generation features
24
+ * @param services - App-specific service implementations
25
+ */
26
+ export function configureAppServices(services: IAppServices): void {
27
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
28
+ // eslint-disable-next-line no-console
29
+ console.log("[AppServices] Configuring app services");
30
+ }
31
+
32
+ appServices = {
33
+ ...services,
34
+ analytics: services.analytics || defaultAnalytics,
35
+ };
36
+ }
37
+
38
+ /**
39
+ * Update specific app services
40
+ * Useful for lazy initialization
41
+ * @param updates - Partial service updates
42
+ */
43
+ export function updateAppServices(updates: PartialAppServices): void {
44
+ if (!appServices) {
45
+ throw new Error(
46
+ "[AppServices] Must call configureAppServices before updateAppServices",
47
+ );
48
+ }
49
+
50
+ appServices = {
51
+ ...appServices,
52
+ ...updates,
53
+ };
54
+ }
55
+
56
+ /**
57
+ * Get configured app services
58
+ * @throws Error if services not configured
59
+ */
60
+ export function getAppServices(): IAppServices {
61
+ if (!appServices) {
62
+ throw new Error(
63
+ "[AppServices] App services not configured. Call configureAppServices first.",
64
+ );
65
+ }
66
+
67
+ return appServices;
68
+ }
69
+
70
+ /**
71
+ * Check if app services are configured
72
+ */
73
+ export function isAppServicesConfigured(): boolean {
74
+ return appServices !== null;
75
+ }
76
+
77
+ /**
78
+ * Reset app services (useful for testing)
79
+ */
80
+ export function resetAppServices(): void {
81
+ appServices = null;
82
+ }
83
+
84
+ /**
85
+ * Get network service
86
+ * @throws Error if not configured
87
+ */
88
+ export function getNetworkService(): IAppServices["network"] {
89
+ return getAppServices().network;
90
+ }
91
+
92
+ /**
93
+ * Get credit service
94
+ * @throws Error if not configured
95
+ */
96
+ export function getCreditService(): IAppServices["credits"] {
97
+ return getAppServices().credits;
98
+ }
99
+
100
+ /**
101
+ * Get paywall service
102
+ * @throws Error if not configured
103
+ */
104
+ export function getPaywallService(): IAppServices["paywall"] {
105
+ return getAppServices().paywall;
106
+ }
107
+
108
+ /**
109
+ * Get auth service
110
+ * @throws Error if not configured
111
+ */
112
+ export function getAuthService(): IAppServices["auth"] {
113
+ return getAppServices().auth;
114
+ }
115
+
116
+ /**
117
+ * Get analytics service
118
+ * @throws Error if not configured
119
+ */
120
+ export function getAnalyticsService(): IAppServices["analytics"] {
121
+ return getAppServices().analytics;
122
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Infrastructure Config Exports
3
+ */
4
+
5
+ export {
6
+ configureAppServices,
7
+ updateAppServices,
8
+ getAppServices,
9
+ isAppServicesConfigured,
10
+ resetAppServices,
11
+ getNetworkService,
12
+ getCreditService,
13
+ getPaywallService,
14
+ getAuthService,
15
+ getAnalyticsService,
16
+ } from "./app-services.config";
@@ -28,3 +28,4 @@ export * from "./buttons";
28
28
  export * from "./display";
29
29
  export * from "./headers";
30
30
  export * from "./PhotoUploadCard";
31
+ export * from "./selectors";
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Aspect Ratio Selector Component
3
+ * Generic, props-driven aspect ratio selection
4
+ */
5
+
6
+ import React from "react";
7
+ import { View, TouchableOpacity, StyleSheet } from "react-native";
8
+ import {
9
+ AtomicText,
10
+ AtomicIcon,
11
+ useAppDesignTokens,
12
+ } from "@umituz/react-native-design-system";
13
+ import type { AspectRatioOption } from "./types";
14
+
15
+ export interface AspectRatioSelectorProps {
16
+ ratios: AspectRatioOption[];
17
+ selectedRatio: "16:9" | "9:16" | "1:1";
18
+ onRatioSelect: (ratio: "16:9" | "9:16" | "1:1") => void;
19
+ title: string;
20
+ }
21
+
22
+ export const AspectRatioSelector: React.FC<AspectRatioSelectorProps> = ({
23
+ ratios,
24
+ selectedRatio,
25
+ onRatioSelect,
26
+ title,
27
+ }) => {
28
+ const tokens = useAppDesignTokens();
29
+
30
+ return (
31
+ <View style={componentStyles.section}>
32
+ <AtomicText
33
+ type="bodyMedium"
34
+ style={{
35
+ color: tokens.colors.textPrimary,
36
+ fontWeight: "600",
37
+ marginBottom: 12,
38
+ }}
39
+ >
40
+ {title}
41
+ </AtomicText>
42
+ <View style={componentStyles.aspectRatioGrid}>
43
+ {ratios.map((ratio) => (
44
+ <TouchableOpacity
45
+ key={ratio.id}
46
+ style={[
47
+ componentStyles.aspectRatioCard,
48
+ {
49
+ backgroundColor:
50
+ selectedRatio === ratio.id
51
+ ? tokens.colors.primary + "20"
52
+ : tokens.colors.surface,
53
+ borderColor:
54
+ selectedRatio === ratio.id
55
+ ? tokens.colors.primary
56
+ : tokens.colors.borderLight,
57
+ },
58
+ ]}
59
+ onPress={() => onRatioSelect(ratio.id)}
60
+ >
61
+ <AtomicIcon
62
+ name={ratio.icon as never}
63
+ size="lg"
64
+ color={selectedRatio === ratio.id ? "primary" : "secondary"}
65
+ />
66
+ <AtomicText
67
+ type="bodySmall"
68
+ style={{
69
+ color: tokens.colors.textPrimary,
70
+ fontWeight: selectedRatio === ratio.id ? "600" : "400",
71
+ marginTop: 8,
72
+ }}
73
+ >
74
+ {ratio.name}
75
+ </AtomicText>
76
+ <AtomicText
77
+ type="labelSmall"
78
+ style={{ color: tokens.colors.textSecondary, marginTop: 2 }}
79
+ >
80
+ {ratio.description}
81
+ </AtomicText>
82
+ </TouchableOpacity>
83
+ ))}
84
+ </View>
85
+ </View>
86
+ );
87
+ };
88
+
89
+ const componentStyles = StyleSheet.create({
90
+ section: {
91
+ padding: 16,
92
+ marginBottom: 8,
93
+ },
94
+ aspectRatioGrid: {
95
+ flexDirection: "row",
96
+ gap: 12,
97
+ },
98
+ aspectRatioCard: {
99
+ flex: 1,
100
+ padding: 16,
101
+ borderRadius: 12,
102
+ borderWidth: 2,
103
+ alignItems: "center",
104
+ },
105
+ });
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Duration Selector Component
3
+ * Generic, props-driven duration selection for video/audio generation
4
+ */
5
+
6
+ import React from "react";
7
+ import { View, TouchableOpacity, StyleSheet } from "react-native";
8
+ import {
9
+ AtomicText,
10
+ useAppDesignTokens,
11
+ } from "@umituz/react-native-design-system";
12
+ import type { DurationValue } from "./types";
13
+
14
+ export interface DurationSelectorProps<T extends DurationValue> {
15
+ duration: T;
16
+ durationOptions: readonly T[];
17
+ onDurationSelect: (duration: T) => void;
18
+ title: string;
19
+ formatLabel?: (duration: T) => string;
20
+ }
21
+
22
+ export function DurationSelector<T extends DurationValue>({
23
+ duration,
24
+ durationOptions,
25
+ onDurationSelect,
26
+ title,
27
+ formatLabel = (d) => `${d}s`,
28
+ }: DurationSelectorProps<T>): React.ReactElement {
29
+ const tokens = useAppDesignTokens();
30
+
31
+ return (
32
+ <View style={componentStyles.section}>
33
+ <AtomicText
34
+ type="bodyMedium"
35
+ style={{
36
+ color: tokens.colors.textPrimary,
37
+ fontWeight: "600",
38
+ marginBottom: 12,
39
+ }}
40
+ >
41
+ {title}
42
+ </AtomicText>
43
+ <View style={componentStyles.durationGrid}>
44
+ {durationOptions.map((sec) => (
45
+ <TouchableOpacity
46
+ key={sec}
47
+ style={[
48
+ componentStyles.durationButton,
49
+ {
50
+ backgroundColor:
51
+ duration === sec
52
+ ? tokens.colors.primary
53
+ : tokens.colors.surface,
54
+ borderColor:
55
+ duration === sec
56
+ ? tokens.colors.primary
57
+ : tokens.colors.borderLight,
58
+ },
59
+ ]}
60
+ onPress={() => onDurationSelect(sec)}
61
+ >
62
+ <AtomicText
63
+ type="bodyLarge"
64
+ style={{
65
+ color:
66
+ duration === sec
67
+ ? tokens.colors.textInverse
68
+ : tokens.colors.textPrimary,
69
+ fontWeight: duration === sec ? "700" : "400",
70
+ }}
71
+ >
72
+ {formatLabel(sec)}
73
+ </AtomicText>
74
+ </TouchableOpacity>
75
+ ))}
76
+ </View>
77
+ </View>
78
+ );
79
+ }
80
+
81
+ const componentStyles = StyleSheet.create({
82
+ section: {
83
+ padding: 16,
84
+ marginBottom: 8,
85
+ },
86
+ durationGrid: {
87
+ flexDirection: "row",
88
+ gap: 12,
89
+ },
90
+ durationButton: {
91
+ flex: 1,
92
+ paddingVertical: 20,
93
+ borderRadius: 12,
94
+ borderWidth: 2,
95
+ alignItems: "center",
96
+ justifyContent: "center",
97
+ },
98
+ });
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Style Selector Component
3
+ * Generic, props-driven style selection for AI generation
4
+ */
5
+
6
+ import React from "react";
7
+ import { View, ScrollView, TouchableOpacity, StyleSheet } from "react-native";
8
+ import {
9
+ AtomicText,
10
+ AtomicIcon,
11
+ useAppDesignTokens,
12
+ } from "@umituz/react-native-design-system";
13
+ import type { StyleOption } from "./types";
14
+
15
+ export interface StyleSelectorProps {
16
+ styles: StyleOption[];
17
+ selectedStyle: string;
18
+ onStyleSelect: (styleId: string) => void;
19
+ title: string;
20
+ }
21
+
22
+ export const StyleSelector: React.FC<StyleSelectorProps> = ({
23
+ styles,
24
+ selectedStyle,
25
+ onStyleSelect,
26
+ title,
27
+ }) => {
28
+ const tokens = useAppDesignTokens();
29
+
30
+ return (
31
+ <View style={componentStyles.section}>
32
+ <AtomicText
33
+ type="bodyMedium"
34
+ style={{
35
+ color: tokens.colors.textPrimary,
36
+ fontWeight: "600",
37
+ marginBottom: 12,
38
+ }}
39
+ >
40
+ {title}
41
+ </AtomicText>
42
+ <ScrollView
43
+ horizontal
44
+ showsHorizontalScrollIndicator={false}
45
+ style={componentStyles.stylesScroll}
46
+ >
47
+ {styles.map((style) => {
48
+ const isSelected = selectedStyle === style.id;
49
+
50
+ return (
51
+ <TouchableOpacity
52
+ key={style.id}
53
+ style={[
54
+ componentStyles.styleCard,
55
+ {
56
+ backgroundColor: isSelected
57
+ ? tokens.colors.primary
58
+ : tokens.colors.surface,
59
+ borderColor: isSelected
60
+ ? tokens.colors.primary
61
+ : tokens.colors.borderLight,
62
+ },
63
+ ]}
64
+ onPress={() => onStyleSelect(style.id)}
65
+ >
66
+ {style.thumbnail ? (
67
+ <AtomicText type="headlineLarge" style={{ marginBottom: 8 }}>
68
+ {style.thumbnail}
69
+ </AtomicText>
70
+ ) : style.icon ? (
71
+ <AtomicIcon
72
+ name={style.icon as never}
73
+ size="lg"
74
+ color={isSelected ? "primary" : "secondary"}
75
+ />
76
+ ) : null}
77
+ <AtomicText
78
+ type="bodySmall"
79
+ style={{
80
+ color: isSelected
81
+ ? tokens.colors.textInverse
82
+ : tokens.colors.textPrimary,
83
+ fontWeight: isSelected ? "600" : "400",
84
+ textAlign: "center",
85
+ }}
86
+ >
87
+ {style.name}
88
+ </AtomicText>
89
+ {style.description && (
90
+ <AtomicText
91
+ type="labelSmall"
92
+ style={{
93
+ color: isSelected
94
+ ? tokens.colors.textInverse
95
+ : tokens.colors.textSecondary,
96
+ opacity: isSelected ? 0.9 : 0.7,
97
+ textAlign: "center",
98
+ marginTop: 4,
99
+ }}
100
+ numberOfLines={2}
101
+ >
102
+ {style.description}
103
+ </AtomicText>
104
+ )}
105
+ </TouchableOpacity>
106
+ );
107
+ })}
108
+ </ScrollView>
109
+ </View>
110
+ );
111
+ };
112
+
113
+ const componentStyles = StyleSheet.create({
114
+ section: {
115
+ padding: 16,
116
+ marginBottom: 8,
117
+ },
118
+ stylesScroll: {
119
+ marginHorizontal: -16,
120
+ paddingHorizontal: 16,
121
+ },
122
+ styleCard: {
123
+ width: 120,
124
+ padding: 16,
125
+ borderRadius: 16,
126
+ borderWidth: 2,
127
+ marginRight: 12,
128
+ alignItems: "center",
129
+ minHeight: 140,
130
+ },
131
+ });
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Selector Components
3
+ * Generic, props-driven selection UI components
4
+ */
5
+
6
+ export { StyleSelector } from "./StyleSelector";
7
+ export { AspectRatioSelector } from "./AspectRatioSelector";
8
+ export { DurationSelector } from "./DurationSelector";
9
+
10
+ export type { StyleSelectorProps } from "./StyleSelector";
11
+ export type { AspectRatioSelectorProps } from "./AspectRatioSelector";
12
+ export type { DurationSelectorProps } from "./DurationSelector";
13
+
14
+ export type {
15
+ StyleOption,
16
+ AspectRatioOption,
17
+ DurationValue,
18
+ } from "./types";
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Selector Component Types
3
+ * Generic types for selector UI components
4
+ */
5
+
6
+ /**
7
+ * Style option for StyleSelector
8
+ * All fields are required - app provides translated values
9
+ */
10
+ export interface StyleOption {
11
+ id: string;
12
+ name: string;
13
+ description?: string;
14
+ thumbnail?: string;
15
+ icon?: string;
16
+ }
17
+
18
+ /**
19
+ * Aspect ratio option for AspectRatioSelector
20
+ * App provides translated name and description
21
+ */
22
+ export interface AspectRatioOption {
23
+ id: "16:9" | "9:16" | "1:1";
24
+ name: string;
25
+ icon: string;
26
+ description: string;
27
+ }
28
+
29
+ /**
30
+ * Duration value type (seconds)
31
+ */
32
+ export type DurationValue = number;