@umituz/react-native-mascot 1.0.3 → 1.0.4

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.
@@ -1,22 +1,23 @@
1
1
  /**
2
2
  * useMascot Hook
3
- * Main hook for mascot management
3
+ * Thin wrapper that delegates to MascotService
4
4
  */
5
5
 
6
6
  import { useCallback, useEffect, useState, useRef } from 'react';
7
- import { Mascot } from '../../domain/entities/Mascot';
7
+ import type { Mascot } from '../../domain/entities/Mascot';
8
8
  import type {
9
9
  MascotConfig,
10
10
  MascotMood,
11
11
  MascotAppearance,
12
12
  } from '../../domain/types/MascotTypes';
13
- import { MascotFactory } from '../../infrastructure/managers/MascotFactory';
14
- import { AnimationController } from '../../infrastructure/controllers/AnimationController';
15
13
  import type { AnimationOptions } from '../../domain/interfaces/IAnimationController';
14
+ import type { MascotService } from '../../application/services/MascotService';
15
+ import { DIContainer } from '../../infrastructure/di/Container';
16
+ import type { MascotTemplate } from '../../application/services/MascotService';
16
17
 
17
18
  export interface UseMascotOptions {
18
19
  config?: MascotConfig;
19
- template?: string;
20
+ template?: MascotTemplate;
20
21
  autoInitialize?: boolean;
21
22
  }
22
23
 
@@ -25,12 +26,18 @@ export interface UseMascotReturn {
25
26
  isReady: boolean;
26
27
  isPlaying: boolean;
27
28
  currentAnimation: string | null;
28
- initialize: (config: MascotConfig) => void;
29
- initializeFromTemplate: (template: string, customizations?: Partial<MascotConfig>) => void;
29
+ initialize: (config: MascotConfig) => Promise<void>;
30
+ fromTemplate: (template: MascotTemplate, customizations?: Partial<MascotConfig>) => Promise<void>;
30
31
  setMood: (mood: MascotMood) => void;
31
32
  setEnergy: (energy: number) => void;
33
+ setFriendliness: (friendliness: number) => void;
34
+ setPlayfulness: (playfulness: number) => void;
35
+ cheerUp: () => void;
36
+ boostEnergy: (amount: number) => void;
32
37
  playAnimation: (animationId: string, options?: AnimationOptions) => Promise<void>;
33
38
  stopAnimation: () => void;
39
+ pauseAnimation: () => void;
40
+ resumeAnimation: () => void;
34
41
  updateAppearance: (appearance: Partial<MascotAppearance>) => void;
35
42
  setBaseColor: (color: string) => void;
36
43
  setAccentColor: (color: string) => void;
@@ -46,179 +53,77 @@ export interface UseMascotReturn {
46
53
  }
47
54
 
48
55
  export function useMascot(options: UseMascotOptions = {}): UseMascotReturn {
49
- const {
50
- config: initialConfig,
51
- template: initialTemplate,
52
- autoInitialize = true,
53
- } = options;
54
-
55
- const [mascot, setMascot] = useState<Mascot | null>(null);
56
- const [isReady, setIsReady] = useState(false);
57
- const [isPlaying, setIsPlaying] = useState(false);
58
- const [currentAnimation, setCurrentAnimation] = useState<string | null>(null);
59
-
60
- const animationControllerRef = useRef<AnimationController | null>(null);
61
-
62
- // Initialize mascot
63
- const initialize = useCallback((config: MascotConfig) => {
64
- const newMascot = new Mascot(config);
65
- setMascot(newMascot);
66
- setIsReady(true);
67
- if (!animationControllerRef.current) {
68
- animationControllerRef.current = new AnimationController();
69
- }
70
- }, []);
71
-
72
- const initializeFromTemplate = useCallback((
73
- template: string,
74
- customizations?: Partial<MascotConfig>
75
- ) => {
76
- const newMascot = MascotFactory.createFromTemplate(
77
- template as 'friendly-bot' | 'cute-pet' | 'wise-owl' | 'pixel-hero',
78
- customizations
79
- );
80
- setMascot(newMascot);
81
- setIsReady(true);
82
- if (!animationControllerRef.current) {
83
- animationControllerRef.current = new AnimationController();
84
- }
85
- }, []);
86
-
87
- // Mood management
88
- const setMood = useCallback((mood: MascotMood) => {
89
- setMascot((prev) => {
90
- if (!prev) return null;
91
- prev.setMood(mood);
92
- return prev.clone();
93
- });
94
- }, []);
95
-
96
- const setEnergy = useCallback((energy: number) => {
97
- setMascot((prev) => {
98
- if (!prev) return null;
99
- prev.setEnergy(energy);
100
- return prev.clone();
56
+ const { config: initialConfig, template: initialTemplate, autoInitialize = true } = options;
57
+
58
+ const [state, setState] = useState(() => ({
59
+ mascot: null as Mascot | null,
60
+ isReady: false,
61
+ isPlaying: false,
62
+ currentAnimation: null as string | null,
63
+ }));
64
+
65
+ const serviceRef = useRef<MascotService | null>(null);
66
+
67
+ // Initialize service once
68
+ if (!serviceRef.current) {
69
+ const container = DIContainer.getInstance();
70
+ serviceRef.current = container.getMascotService();
71
+
72
+ // Subscribe to service changes
73
+ serviceRef.current.subscribe(() => {
74
+ const service = serviceRef.current!;
75
+ setState({
76
+ mascot: service.mascot,
77
+ isReady: service.isReady,
78
+ isPlaying: service.isPlaying,
79
+ currentAnimation: service.currentAnimation,
80
+ });
101
81
  });
102
- }, []);
103
-
104
- // Animation management
105
- const playAnimation = useCallback(async (animationId: string, options?: AnimationOptions) => {
106
- if (!mascot || !animationControllerRef.current) return;
107
-
108
- const animation = mascot.getAnimation(animationId);
109
- if (!animation) {
110
- console.warn(`Animation ${animationId} not found`);
111
- return;
112
- }
113
-
114
- setIsPlaying(true);
115
- setCurrentAnimation(animationId);
116
-
117
- if (animationControllerRef.current) {
118
- await animationControllerRef.current.play(animation, options);
119
- }
120
-
121
- setIsPlaying(false);
122
- setCurrentAnimation(null);
123
- }, [mascot]);
124
-
125
- const stopAnimation = useCallback(() => {
126
- if (animationControllerRef.current) {
127
- animationControllerRef.current.stop();
128
- }
129
- setIsPlaying(false);
130
- setCurrentAnimation(null);
131
- }, []);
82
+ }
132
83
 
133
- // Appearance management
134
- const updateAppearance = useCallback((appearance: Partial<MascotAppearance>) => {
135
- setMascot((prev) => {
136
- if (!prev) return null;
137
- prev.updateAppearance(appearance);
138
- return prev.clone();
139
- });
140
- }, []);
141
-
142
- const setBaseColor = useCallback((color: string) => {
143
- setMascot((prev) => {
144
- if (!prev) return null;
145
- prev.setBaseColor(color);
146
- return prev.clone();
147
- });
148
- }, []);
149
-
150
- const setAccentColor = useCallback((color: string) => {
151
- setMascot((prev) => {
152
- if (!prev) return null;
153
- prev.setAccentColor(color);
154
- return prev.clone();
155
- });
156
- }, []);
157
-
158
- const addAccessory = useCallback((accessory: {
159
- id: string;
160
- type: string;
161
- color?: string;
162
- position?: { x: number; y: number };
163
- }) => {
164
- setMascot((prev) => {
165
- if (!prev) return null;
166
- prev.addAccessory(accessory);
167
- return prev.clone();
168
- });
169
- }, []);
170
-
171
- const removeAccessory = useCallback((accessoryId: string) => {
172
- setMascot((prev) => {
173
- if (!prev) return null;
174
- prev.removeAccessory(accessoryId);
175
- return prev.clone();
176
- });
177
- }, []);
178
-
179
- // Visibility and position
180
- const setVisible = useCallback((visible: boolean) => {
181
- setMascot((prev) => {
182
- if (!prev) return null;
183
- prev.setVisible(visible);
184
- return prev.clone();
185
- });
186
- }, []);
187
-
188
- const setPosition = useCallback((position: { x: number; y: number }) => {
189
- setMascot((prev) => {
190
- if (!prev) return null;
191
- prev.setPosition(position);
192
- return prev.clone();
193
- });
194
- }, []);
84
+ const service = serviceRef.current;
195
85
 
196
- // Auto-initialize
86
+ // Auto-initialize
197
87
  useEffect(() => {
198
88
  if (autoInitialize && initialConfig) {
199
- initialize(initialConfig);
89
+ service.initialize(initialConfig);
200
90
  } else if (autoInitialize && initialTemplate) {
201
- initializeFromTemplate(initialTemplate);
91
+ service.fromTemplate(initialTemplate);
202
92
  }
203
- }, [autoInitialize, initialConfig, initialTemplate, initialize, initializeFromTemplate]);
93
+ }, [autoInitialize, initialConfig, initialTemplate]);
204
94
 
95
+ // ✅ All methods delegate to service - NO business logic!
205
96
  return {
206
- mascot,
207
- isReady,
208
- isPlaying,
209
- currentAnimation,
210
- initialize,
211
- initializeFromTemplate,
212
- setMood,
213
- setEnergy,
214
- playAnimation,
215
- stopAnimation,
216
- updateAppearance,
217
- setBaseColor,
218
- setAccentColor,
219
- addAccessory,
220
- removeAccessory,
221
- setVisible,
222
- setPosition,
97
+ ...state,
98
+ initialize: useCallback((config: MascotConfig) => service.initialize(config), [service]),
99
+ fromTemplate: useCallback(
100
+ (template: MascotTemplate, customizations?: Partial<MascotConfig>) =>
101
+ service.fromTemplate(template, customizations),
102
+ [service]
103
+ ),
104
+ setMood: useCallback((mood: MascotMood) => service.setMood(mood), [service]),
105
+ setEnergy: useCallback((energy: number) => service.setEnergy(energy), [service]),
106
+ setFriendliness: useCallback((friendliness: number) => service.setFriendliness(friendliness), [service]),
107
+ setPlayfulness: useCallback((playfulness: number) => service.setPlayfulness(playfulness), [service]),
108
+ cheerUp: useCallback(() => service.cheerUp(), [service]),
109
+ boostEnergy: useCallback((amount: number) => service.boostEnergy(amount), [service]),
110
+ playAnimation: useCallback(
111
+ (animationId: string, opts?: AnimationOptions) => service.playAnimation(animationId, opts),
112
+ [service]
113
+ ),
114
+ stopAnimation: useCallback(() => service.stopAnimation(), [service]),
115
+ pauseAnimation: useCallback(() => service.pauseAnimation(), [service]),
116
+ resumeAnimation: useCallback(() => service.resumeAnimation(), [service]),
117
+ updateAppearance: useCallback((appearance: Partial<MascotAppearance>) => service.updateAppearance(appearance), [service]),
118
+ setBaseColor: useCallback((color: string) => service.setBaseColor(color), [service]),
119
+ setAccentColor: useCallback((color: string) => service.setAccentColor(color), [service]),
120
+ addAccessory: useCallback(
121
+ (accessory: { id: string; type: string; color?: string; position?: { x: number; y: number } }) =>
122
+ service.addAccessory(accessory),
123
+ [service]
124
+ ),
125
+ removeAccessory: useCallback((accessoryId: string) => service.removeAccessory(accessoryId), [service]),
126
+ setVisible: useCallback((visible: boolean) => service.setVisible(visible), [service]),
127
+ setPosition: useCallback((position: { x: number; y: number }) => service.setPosition(position), [service]),
223
128
  };
224
129
  }
@@ -1,16 +1,16 @@
1
1
  /**
2
2
  * useMascotAnimation Hook
3
- * Advanced animation control with queue and sequencing
3
+ * Simplified - delegates to MascotService
4
4
  */
5
5
 
6
- import { useCallback, useRef, useState } from 'react';
6
+ import { useCallback, useState } from 'react';
7
7
  import type { Mascot } from '../../domain/entities/Mascot';
8
- import type { AnimationSpeed } from '../../domain/types/MascotTypes';
9
- import { AnimationController } from '../../infrastructure/controllers/AnimationController';
10
- import type { AnimationOptions } from '../../domain/interfaces/IAnimationController';
8
+ import type { AnimationSpeed, AnimationOptions } from '../../domain/types/MascotTypes';
9
+ import type { MascotService } from '../../application/services/MascotService';
10
+ import { DIContainer } from '../../infrastructure/di/Container';
11
11
 
12
12
  export interface UseMascotAnimationOptions {
13
- mascot: Mascot | null;
13
+ mascot?: Mascot | null;
14
14
  autoplay?: boolean;
15
15
  queue?: boolean;
16
16
  speed?: AnimationSpeed;
@@ -42,81 +42,47 @@ const SPEED_MULTIPLIERS: Record<AnimationSpeed, number> = {
42
42
  };
43
43
 
44
44
  export function useMascotAnimation(
45
- options: UseMascotAnimationOptions
45
+ options: UseMascotAnimationOptions = {}
46
46
  ): UseMascotAnimationReturn {
47
47
  const { mascot, speed = 'normal' } = options;
48
-
49
- const [isPlaying, setIsPlaying] = useState(false);
50
- const [currentAnimation, setCurrentAnimation] = useState<string | null>(null);
51
- const [progress, setProgress] = useState(0);
52
48
  const [queue, setQueue] = useState<string[]>([]);
53
49
 
54
- const animationControllerRef = useRef<AnimationController | null>(null);
55
- const isProcessingQueueRef = useRef(false);
56
-
57
- // Initialize animation controller
58
- if (!animationControllerRef.current) {
59
- animationControllerRef.current = new AnimationController();
60
- }
61
-
62
- // Setup progress tracking
63
- const animationController = animationControllerRef.current;
64
- animationController.on('progress', (data: unknown) => {
65
- const { progress: newProgress } = data as { progress: number };
66
- setProgress(newProgress);
67
- });
68
-
69
- const play = useCallback(async (animationId: string, options?: AnimationOptions) => {
70
- if (!mascot) {
71
- console.warn('Mascot not initialized');
72
- return;
73
- }
74
-
75
- const animation = mascot.getAnimation(animationId);
76
- if (!animation) {
77
- console.warn(`Animation ${animationId} not found`);
78
- return;
79
- }
80
-
81
- setIsPlaying(true);
82
- setCurrentAnimation(animationId);
83
-
84
- const speedMultiplier = SPEED_MULTIPLIERS[speed];
85
- const finalOptions: AnimationOptions = {
86
- ...options,
87
- speed: (options?.speed || 1) * speedMultiplier,
88
- };
89
-
90
- await animationController.play(animation, finalOptions);
91
-
92
- setIsPlaying(false);
93
- setCurrentAnimation(null);
94
- setProgress(0);
95
- }, [mascot, speed, animationController]);
50
+ const container = DIContainer.getInstance();
51
+ const service = container.getMascotService();
52
+
53
+ const play = useCallback(
54
+ async (animationId: string, options?: AnimationOptions) => {
55
+ const speedMultiplier = SPEED_MULTIPLIERS[speed];
56
+ const finalOptions: AnimationOptions = {
57
+ ...options,
58
+ speed: (options?.speed || 1) * speedMultiplier,
59
+ };
60
+ await service.playAnimation(animationId, finalOptions);
61
+ },
62
+ [service, speed]
63
+ );
96
64
 
97
65
  const pause = useCallback(() => {
98
- animationController.pause();
99
- }, [animationController]);
66
+ service.pauseAnimation();
67
+ }, [service]);
100
68
 
101
69
  const resume = useCallback(() => {
102
- animationController.resume();
103
- }, [animationController]);
70
+ service.resumeAnimation();
71
+ }, [service]);
104
72
 
105
73
  const stop = useCallback(() => {
106
- animationController.stop();
107
- setIsPlaying(false);
108
- setCurrentAnimation(null);
109
- setProgress(0);
110
- }, [animationController]);
74
+ service.stopAnimation();
75
+ }, [service]);
111
76
 
112
- const setSpeed = useCallback((newSpeed: number) => {
113
- animationController.setSpeed(newSpeed);
114
- }, [animationController]);
77
+ const setSpeed = useCallback(() => {
78
+ // Speed is handled via options in play()
79
+ console.warn('setSpeed: Use play() with speed option instead');
80
+ }, []);
115
81
 
116
- const setProgressValue = useCallback((newProgress: number) => {
117
- animationController.setProgress(newProgress);
118
- setProgress(newProgress);
119
- }, [animationController]);
82
+ const setProgress = useCallback(() => {
83
+ // Progress tracking would need AnimationController reference
84
+ console.warn('setProgress: Not implemented in service layer yet');
85
+ }, []);
120
86
 
121
87
  const queueAnimation = useCallback((animationId: string) => {
122
88
  setQueue((prev) => [...prev, animationId]);
@@ -126,40 +92,34 @@ export function useMascotAnimation(
126
92
  setQueue([]);
127
93
  }, []);
128
94
 
129
- const playSequence = useCallback(async (animationIds: string[]) => {
130
- for (const animationId of animationIds) {
131
- await play(animationId);
132
- }
133
- }, [play]);
95
+ const playSequence = useCallback(
96
+ async (animationIds: string[]) => {
97
+ for (const animationId of animationIds) {
98
+ await play(animationId);
99
+ }
100
+ },
101
+ [play]
102
+ );
134
103
 
135
- // Process queue automatically
136
104
  const processQueue = useCallback(async () => {
137
- if (isProcessingQueueRef.current || queue.length === 0 || !mascot) {
138
- return;
139
- }
140
-
141
- isProcessingQueueRef.current = true;
142
-
143
105
  while (queue.length > 0) {
144
106
  const nextAnimation = queue[0];
145
107
  setQueue((prev) => prev.slice(1));
146
108
  await play(nextAnimation);
147
109
  }
148
-
149
- isProcessingQueueRef.current = false;
150
- }, [queue, mascot, play]);
110
+ }, [queue, play]);
151
111
 
152
112
  return {
153
- isPlaying,
154
- currentAnimation,
155
- progress,
113
+ isPlaying: service.isPlaying,
114
+ currentAnimation: service.currentAnimation,
115
+ progress: 0, // Would need AnimationController reference
156
116
  queue,
157
117
  play,
158
118
  pause,
159
119
  resume,
160
120
  stop,
161
121
  setSpeed,
162
- setProgress: setProgressValue,
122
+ setProgress,
163
123
  queueAnimation,
164
124
  clearQueue,
165
125
  playSequence,