@shaykec/app-agent 1.0.9 → 1.0.11

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.
Files changed (202) hide show
  1. package/.claude/agents/catalog-analyzer.md +57 -0
  2. package/.claude/skills/android-customizer/SKILL.md +23 -10
  3. package/.claude/skills/bug-fixer/SKILL.md +59 -0
  4. package/.claude/skills/catalog-analyzer/SKILL.md +96 -0
  5. package/.claude/skills/customization-planner/SKILL.md +44 -5
  6. package/.claude/skills/design-selector/SKILL.md +3 -1
  7. package/.claude/skills/design-system/SKILL.md +1 -1
  8. package/.claude/skills/exploratory-tester/SKILL.md +82 -0
  9. package/.claude/skills/ios-customizer/SKILL.md +29 -8
  10. package/.claude/skills/module-integrator/SKILL.md +1 -1
  11. package/.claude/skills/react-native-customizer/SKILL.md +22 -10
  12. package/.claude/skills/test-planner/SKILL.md +72 -0
  13. package/.cursor/agents/README.md +3 -1
  14. package/.cursor/agents/catalog-analyzer.md +83 -0
  15. package/.cursor/rules/safety-guardrails.mdc +1 -1
  16. package/.cursor/rules/workflow.mdc +52 -18
  17. package/.cursor/skills/android-customizer/SKILL.md +43 -19
  18. package/.cursor/skills/bug-fixer/SKILL.md +189 -0
  19. package/.cursor/skills/catalog-analyzer/SKILL.md +222 -0
  20. package/.cursor/skills/customization-planner/SKILL.md +55 -8
  21. package/.cursor/skills/design-selector/SKILL.md +6 -5
  22. package/.cursor/skills/design-system/SKILL.md +8 -7
  23. package/.cursor/skills/exploratory-tester/SKILL.md +223 -0
  24. package/.cursor/skills/ios-customizer/SKILL.md +47 -12
  25. package/.cursor/skills/module-integrator/SKILL.md +2 -2
  26. package/.cursor/skills/output-validator/SKILL.md +1 -1
  27. package/.cursor/skills/react-native-customizer/SKILL.md +46 -16
  28. package/.cursor/skills/test-planner/SKILL.md +199 -0
  29. package/.cursor/skills/web-analyzer/SKILL.md +310 -0
  30. package/.cursor/skills/web-crawler/SKILL.md +252 -0
  31. package/AGENTS.md +32 -11
  32. package/CLAUDE.md +78 -33
  33. package/README.md +77 -11
  34. package/designs/DESIGN_CATALOG.md +17 -15
  35. package/designs/DESIGN_PRINCIPLES.md +53 -0
  36. package/designs/brands/accessible-high-contrast.md +14 -0
  37. package/designs/brands/corporate-professional.md +14 -0
  38. package/designs/brands/dark-luxe.md +14 -0
  39. package/designs/brands/kids-playful.md +14 -0
  40. package/designs/brands/medical-clinical.md +14 -0
  41. package/designs/brands/modern-minimal.md +14 -0
  42. package/designs/brands/nature-organic.md +14 -0
  43. package/designs/brands/neo-brutalist.md +14 -0
  44. package/designs/brands/retro-vintage.md +14 -0
  45. package/designs/brands/soft-gradient.md +14 -0
  46. package/designs/brands/sport-athletic.md +14 -0
  47. package/designs/brands/tech-dynamic.md +14 -0
  48. package/designs/brands/vibrant-playful.md +14 -0
  49. package/dist/cli.d.ts +4 -2
  50. package/dist/cli.d.ts.map +1 -1
  51. package/dist/cli.js +123 -11
  52. package/dist/cli.js.map +1 -1
  53. package/dist/config.d.ts +8 -1
  54. package/dist/config.d.ts.map +1 -1
  55. package/dist/config.js +6 -1
  56. package/dist/config.js.map +1 -1
  57. package/dist/engines/claude-engine.d.ts.map +1 -1
  58. package/dist/engines/claude-engine.js +16 -4
  59. package/dist/engines/claude-engine.js.map +1 -1
  60. package/dist/engines/types.d.ts +1 -1
  61. package/dist/engines/types.d.ts.map +1 -1
  62. package/dist/engines/types.js +31 -2
  63. package/dist/engines/types.js.map +1 -1
  64. package/dist/github.d.ts +3 -0
  65. package/dist/github.d.ts.map +1 -1
  66. package/dist/github.js +47 -4
  67. package/dist/github.js.map +1 -1
  68. package/dist/index.js +294 -16
  69. package/dist/index.js.map +1 -1
  70. package/dist/prompt-builder.d.ts +17 -1
  71. package/dist/prompt-builder.d.ts.map +1 -1
  72. package/dist/prompt-builder.js +272 -1
  73. package/dist/prompt-builder.js.map +1 -1
  74. package/dist/validator.d.ts +7 -2
  75. package/dist/validator.d.ts.map +1 -1
  76. package/dist/validator.js +61 -41
  77. package/dist/validator.js.map +1 -1
  78. package/dist/workspace.js +2 -2
  79. package/dist/workspace.js.map +1 -1
  80. package/package.json +2 -4
  81. package/prompts/agent-prompt.md +35 -18
  82. package/prompts/deep-test-agent-prompt.md +122 -0
  83. package/prompts/fix-agent-prompt.md +90 -0
  84. package/prompts/quick-agent-prompt.md +32 -2
  85. package/prompts/scratch-agent-prompt.md +5 -8
  86. package/prompts/web-clone-agent-prompt.md +179 -0
  87. package/templates/android/BookTemplate/app/src/main/kotlin/com/appship/book/core/animation/AnimatedTransitionsModifiers.kt +188 -0
  88. package/templates/android/ChatTemplate/app/src/main/kotlin/com/appship/chat/core/animation/AnimatedTransitionsModifiers.kt +188 -0
  89. package/templates/android/ChatTemplate/app/src/main/kotlin/com/appship/chat/features/conversations/ConversationsScreen.kt +1 -1
  90. package/templates/android/DashTemplate/app/src/main/kotlin/com/appship/dash/core/animation/AnimatedTransitionsModifiers.kt +188 -0
  91. package/templates/android/DashTemplate/app/src/main/kotlin/com/appship/dash/features/navigation/MainScreen.kt +1 -0
  92. package/templates/android/FamilyTemplate/app/src/main/java/com/appship/family/core/animation/AnimatedTransitionsModifiers.kt +188 -0
  93. package/templates/android/FamilyTemplate/app/src/main/java/com/appship/family/features/navigation/MainNavigation.kt +5 -1
  94. package/templates/android/FinanceTemplate/app/src/main/kotlin/com/appship/finance/core/animation/AnimatedTransitionsModifiers.kt +188 -0
  95. package/templates/android/GameTemplate/app/src/main/kotlin/com/appship/game/core/animation/AnimatedTransitionsModifiers.kt +188 -0
  96. package/templates/android/GameTemplate/app/src/main/kotlin/com/appship/game/core/animation/MotionPreferencesScreen.kt +3 -3
  97. package/templates/android/GameTemplate/app/src/main/kotlin/com/appship/game/features/navigation/Navigation.kt +1 -1
  98. package/templates/android/GameTemplate/app/src/main/kotlin/com/appship/game/features/settings/SettingsScreen.kt +1 -1
  99. package/templates/android/HealthTemplate/app/src/main/kotlin/com/appship/health/core/animation/AnimatedTransitionsModifiers.kt +188 -0
  100. package/templates/android/LearnTemplate/app/src/main/kotlin/com/appship/learn/core/animation/AnimatedTransitionsModifiers.kt +188 -0
  101. package/templates/android/MapTemplate/app/src/main/kotlin/com/appship/map/core/animation/AnimatedTransitionsModifiers.kt +188 -0
  102. package/templates/android/MediaTemplate/app/src/main/kotlin/com/appship/media/core/animation/AnimatedTransitionsModifiers.kt +188 -0
  103. package/templates/android/MediaTemplate/app/src/main/kotlin/com/appship/media/features/settings/SettingsScreen.kt +3 -2
  104. package/templates/android/ReferenceTemplate/app/src/main/kotlin/com/appship/reference/core/animation/AnimatedTransitionsModifiers.kt +188 -0
  105. package/templates/android/ReferenceTemplate/app/src/main/kotlin/com/appship/reference/features/settings/SettingsScreen.kt +1 -1
  106. package/templates/android/ShopTemplate/app/src/main/kotlin/com/appship/shop/core/animation/AnimatedTransitionsModifiers.kt +188 -0
  107. package/templates/android/ShopTemplate/app/src/main/kotlin/com/appship/shop/features/cart/CartScreen.kt +3 -2
  108. package/templates/android/Skeleton/app/src/main/kotlin/com/appship/skeleton/core/animation/AnimatedTransitionsModifiers.kt +188 -0
  109. package/templates/android/Skeleton/tests/03_detail_screen.yaml +1 -1
  110. package/templates/android/Skeleton/tests/04_favorites.yaml +1 -1
  111. package/templates/android/Skeleton/tests/08_full_e2e.yaml +7 -1
  112. package/templates/android/SocialTemplate/app/src/main/kotlin/com/appship/social/core/animation/AnimatedTransitionsModifiers.kt +188 -0
  113. package/templates/android/TaskTemplate/app/src/main/kotlin/com/appship/task/core/animation/AnimatedTransitionsModifiers.kt +188 -0
  114. package/templates/android/TaskTemplate/app/src/main/kotlin/com/appship/task/features/settings/SettingsScreen.kt +3 -2
  115. package/templates/android/TrackTemplate/app/src/main/kotlin/com/appship/track/core/animation/AnimatedTransitionsModifiers.kt +188 -0
  116. package/templates/ios/BookTemplate/BookTemplate/Core/Animation/AnimatedTransitionsView.swift +201 -0
  117. package/templates/ios/ChatTemplate/ChatTemplate/Core/Animation/AnimatedTransitionsView.swift +201 -0
  118. package/templates/ios/DashTemplate/DashTemplate/App/AppConfig.swift +1 -0
  119. package/templates/ios/DashTemplate/DashTemplate/Core/Animation/AnimatedTransitionsView.swift +201 -0
  120. package/templates/ios/DashTemplate/DashTemplate/Core/Strings.swift +13 -0
  121. package/templates/ios/DashTemplate/DashTemplate.xcodeproj/project.pbxproj +32 -20
  122. package/templates/ios/FamilyTemplate/FamilyTemplate/Core/Animation/AnimatedTransitionsView.swift +201 -0
  123. package/templates/ios/FinanceTemplate/FinanceTemplate/Core/Animation/AnimatedTransitionsView.swift +201 -0
  124. package/templates/ios/FinanceTemplate/FinanceTemplate/Core/Strings.swift +42 -0
  125. package/templates/ios/FinanceTemplate/FinanceTemplate.xcodeproj/project.pbxproj +36 -30
  126. package/templates/ios/GameTemplate/GameTemplate/Core/Animation/AnimatedTransitionsView.swift +201 -0
  127. package/templates/ios/HealthTemplate/HealthTemplate/Core/Animation/AnimatedTransitionsView.swift +201 -0
  128. package/templates/ios/LearnTemplate/LearnTemplate/Core/Animation/AnimatedTransitionsView.swift +201 -0
  129. package/templates/ios/MapTemplate/MapTemplate/Core/Animation/AnimatedTransitionsView.swift +201 -0
  130. package/templates/ios/MediaTemplate/MediaTemplate/Core/Animation/AnimatedTransitionsView.swift +201 -0
  131. package/templates/ios/ReferenceTemplate/ReferenceTemplate/Core/Animation/AnimatedTransitionsView.swift +201 -0
  132. package/templates/ios/ReferenceTemplate/ReferenceTemplate/Core/Strings.swift +12 -0
  133. package/templates/ios/ReferenceTemplate/ReferenceTemplate/Features/SkeletonLoading/SkeletonLoadingView.swift +2 -37
  134. package/templates/ios/ShopTemplate/ShopTemplate/Core/Animation/AnimatedTransitionsView.swift +201 -0
  135. package/templates/ios/Skeleton/Skeleton/Core/Animation/AnimatedTransitionsView.swift +201 -0
  136. package/templates/ios/Skeleton/tests/08_full_e2e.yaml +4 -0
  137. package/templates/ios/SocialTemplate/SocialTemplate/Core/Animation/AnimatedTransitionsView.swift +201 -0
  138. package/templates/ios/TaskTemplate/TaskTemplate/Core/Animation/AnimatedTransitionsView.swift +201 -0
  139. package/templates/ios/TrackTemplate/TrackTemplate/Core/Animation/AnimatedTransitionsView.swift +201 -0
  140. package/templates/react-native/BookTemplate/src/animation/useAnimatedList.ts +219 -2
  141. package/templates/react-native/BookTemplate/src/animation/useMotionPreferences.ts +23 -9
  142. package/templates/react-native/BookTemplate/src/screens/Profile/ProfileScreen.tsx +1 -1
  143. package/templates/react-native/ChatTemplate/src/animation/useAnimatedList.ts +219 -2
  144. package/templates/react-native/ChatTemplate/src/animation/useMotionPreferences.ts +23 -9
  145. package/templates/react-native/ChatTemplate/src/screens/Profile/ProfileScreen.tsx +1 -1
  146. package/templates/react-native/DashTemplate/src/animation/useAnimatedList.ts +219 -2
  147. package/templates/react-native/DashTemplate/src/animation/useMotionPreferences.ts +23 -9
  148. package/templates/react-native/DashTemplate/src/screens/Profile/ProfileScreen.tsx +1 -1
  149. package/templates/react-native/FamilyTemplate/src/animation/useAnimatedList.ts +219 -2
  150. package/templates/react-native/FamilyTemplate/src/animation/useMotionPreferences.ts +23 -9
  151. package/templates/react-native/FamilyTemplate/src/screens/Profile/ProfileScreen.tsx +1 -1
  152. package/templates/react-native/FinanceTemplate/src/animation/useAnimatedList.ts +219 -2
  153. package/templates/react-native/FinanceTemplate/src/animation/useMotionPreferences.ts +23 -9
  154. package/templates/react-native/FinanceTemplate/src/screens/Profile/ProfileScreen.tsx +1 -1
  155. package/templates/react-native/GameTemplate/src/animation/useAnimatedList.ts +219 -2
  156. package/templates/react-native/GameTemplate/src/animation/useMotionPreferences.ts +23 -9
  157. package/templates/react-native/GameTemplate/src/screens/GameDetail/GameDetailScreen.tsx +2 -1
  158. package/templates/react-native/GameTemplate/src/screens/Profile/ProfileScreen.tsx +1 -1
  159. package/templates/react-native/HealthTemplate/src/animation/useAnimatedList.ts +219 -2
  160. package/templates/react-native/HealthTemplate/src/animation/useMotionPreferences.ts +23 -9
  161. package/templates/react-native/HealthTemplate/src/screens/Profile/ProfileScreen.tsx +1 -1
  162. package/templates/react-native/HealthTemplate/src/screens/WorkoutDetail/WorkoutDetailScreen.tsx +1 -1
  163. package/templates/react-native/LearnTemplate/src/animation/useAnimatedList.ts +219 -2
  164. package/templates/react-native/LearnTemplate/src/animation/useMotionPreferences.ts +23 -9
  165. package/templates/react-native/LearnTemplate/src/screens/Profile/ProfileScreen.tsx +1 -1
  166. package/templates/react-native/MapTemplate/src/animation/useAnimatedList.ts +219 -2
  167. package/templates/react-native/MapTemplate/src/animation/useMotionPreferences.ts +23 -9
  168. package/templates/react-native/MapTemplate/src/screens/Map/MapScreen.tsx +14 -0
  169. package/templates/react-native/MapTemplate/src/screens/Profile/ProfileScreen.tsx +1 -1
  170. package/templates/react-native/MediaTemplate/src/animation/useAnimatedList.ts +219 -2
  171. package/templates/react-native/MediaTemplate/src/animation/useMotionPreferences.ts +23 -9
  172. package/templates/react-native/MediaTemplate/src/screens/PlaylistDetail/PlaylistDetailScreen.tsx +1 -1
  173. package/templates/react-native/MediaTemplate/src/screens/Profile/ProfileScreen.tsx +1 -1
  174. package/templates/react-native/ReferenceTemplate/src/animation/useAnimatedList.ts +219 -2
  175. package/templates/react-native/ReferenceTemplate/src/animation/useMotionPreferences.ts +23 -9
  176. package/templates/react-native/ReferenceTemplate/src/screens/Settings/SettingsScreen.tsx +1 -1
  177. package/templates/react-native/ShopTemplate/src/animation/useAnimatedList.ts +219 -2
  178. package/templates/react-native/ShopTemplate/src/animation/useMotionPreferences.ts +23 -9
  179. package/templates/react-native/ShopTemplate/src/screens/Profile/ProfileScreen.tsx +1 -1
  180. package/templates/react-native/Skeleton/TESTING_MANIFEST.md +1 -1
  181. package/templates/react-native/Skeleton/src/animation/useAnimatedList.ts +219 -2
  182. package/templates/react-native/Skeleton/src/animation/useMotionPreferences.ts +23 -9
  183. package/templates/react-native/Skeleton/src/screens/Profile/ProfileScreen.tsx +1 -1
  184. package/templates/react-native/Skeleton/tests/07_profile.yaml +3 -2
  185. package/templates/react-native/Skeleton/tests/08_full_e2e.yaml +12 -1
  186. package/templates/react-native/SocialTemplate/src/animation/useAnimatedList.ts +219 -2
  187. package/templates/react-native/SocialTemplate/src/animation/useMotionPreferences.ts +23 -9
  188. package/templates/react-native/SocialTemplate/src/screens/Feed/FeedScreen.tsx +1 -0
  189. package/templates/react-native/SocialTemplate/src/screens/Profile/ProfileScreen.tsx +1 -1
  190. package/templates/react-native/TaskTemplate/src/animation/useAnimatedList.ts +219 -2
  191. package/templates/react-native/TaskTemplate/src/animation/useMotionPreferences.ts +23 -9
  192. package/templates/react-native/TaskTemplate/src/screens/Profile/ProfileScreen.tsx +1 -1
  193. package/templates/react-native/TrackTemplate/src/animation/useAnimatedList.ts +219 -2
  194. package/templates/react-native/TrackTemplate/src/animation/useMotionPreferences.ts +23 -9
  195. package/templates/react-native/TrackTemplate/src/screens/Settings/SettingsScreen.tsx +1 -1
  196. package/templates/shared/ios/AnimatedTransitions/AnimatedTransitionsView.swift +233 -93
  197. package/.claude/agents/template-selector.md +0 -39
  198. package/.claude/skills/module-selector/SKILL.md +0 -81
  199. package/.claude/skills/template-selector/SKILL.md +0 -44
  200. package/.cursor/agents/template-selector.md +0 -52
  201. package/.cursor/skills/module-selector/SKILL.md +0 -135
  202. package/.cursor/skills/template-selector/SKILL.md +0 -123
@@ -57,6 +57,155 @@ struct BounceScaleModifier: ViewModifier {
57
57
  }
58
58
  }
59
59
 
60
+ // MARK: - Scale on Press Modifier
61
+ /// Applies scale-down + spring-back animation when pressed (like a button press).
62
+ struct ScaleOnPressModifier: ViewModifier {
63
+ @State private var isPressed = false
64
+
65
+ func body(content: Content) -> some View {
66
+ content
67
+ .scaleEffect(isPressed ? 0.95 : 1.0)
68
+ .animation(.spring(response: 0.3, dampingFraction: 0.7), value: isPressed)
69
+ .simultaneousGesture(
70
+ DragGesture(minimumDistance: 0)
71
+ .onChanged { _ in isPressed = true }
72
+ .onEnded { _ in isPressed = false }
73
+ )
74
+ }
75
+ }
76
+
77
+ // MARK: - Haptic Feedback Modifier
78
+ /// Triggers haptic feedback on tap.
79
+ struct HapticFeedbackModifier: ViewModifier {
80
+ let style: UIImpactFeedbackGenerator.FeedbackStyle
81
+
82
+ func body(content: Content) -> some View {
83
+ content
84
+ .onTapGesture {
85
+ UIImpactFeedbackGenerator(style: style).impactOccurred()
86
+ }
87
+ }
88
+ }
89
+
90
+ // MARK: - Slide and Fade Modifier
91
+ /// Applies a slide-from-side + fade-in animation on appear.
92
+ struct SlideAndFadeModifier: ViewModifier {
93
+ let delay: Double
94
+ @State private var isVisible = false
95
+
96
+ func body(content: Content) -> some View {
97
+ content
98
+ .opacity(isVisible ? 1 : 0)
99
+ .offset(x: isVisible ? 0 : 20)
100
+ .motionAware(animation: .spring(response: 0.5, dampingFraction: 0.8).delay(delay))
101
+ .onAppear {
102
+ isVisible = true
103
+ }
104
+ }
105
+ }
106
+
107
+ // MARK: - Card Shadow Modifier
108
+ /// Applies a subtle colored shadow to cards and elevated surfaces.
109
+ struct CardShadowModifier: ViewModifier {
110
+ let color: Color
111
+ let radius: CGFloat
112
+ let y: CGFloat
113
+
114
+ func body(content: Content) -> some View {
115
+ content
116
+ .shadow(color: color.opacity(0.08), radius: radius, x: 0, y: y)
117
+ .shadow(color: Color.black.opacity(0.04), radius: radius / 2, x: 0, y: y / 2)
118
+ }
119
+ }
120
+
121
+ // MARK: - Elevated Shadow Modifier
122
+ /// Applies a deeper shadow for FABs and floating elements.
123
+ struct ElevatedShadowModifier: ViewModifier {
124
+ let color: Color
125
+
126
+ func body(content: Content) -> some View {
127
+ content
128
+ .shadow(color: color.opacity(0.12), radius: 16, x: 0, y: 8)
129
+ .shadow(color: Color.black.opacity(0.06), radius: 8, x: 0, y: 4)
130
+ }
131
+ }
132
+
133
+ // MARK: - Shimmer Modifier
134
+ /// Applies a shimmer/skeleton-loading gradient overlay for loading states.
135
+ struct ShimmerModifier: ViewModifier {
136
+ @State private var isAnimating = false
137
+
138
+ func body(content: Content) -> some View {
139
+ content
140
+ .overlay(
141
+ GeometryReader { geometry in
142
+ if isAnimating {
143
+ LinearGradient(
144
+ colors: [
145
+ Color.clear,
146
+ Color.white.opacity(0.3),
147
+ Color.clear
148
+ ],
149
+ startPoint: .leading,
150
+ endPoint: .trailing
151
+ )
152
+ .offset(x: isAnimating ? geometry.size.width : -geometry.size.width)
153
+ .animation(
154
+ Animation.linear(duration: 1.5)
155
+ .repeatForever(autoreverses: false),
156
+ value: isAnimating
157
+ )
158
+ }
159
+ }
160
+ )
161
+ .clipped()
162
+ .onAppear {
163
+ isAnimating = true
164
+ }
165
+ }
166
+ }
167
+
168
+ // MARK: - Pulse Modifier
169
+ /// Applies a repeating scale pulse effect (e.g., for notifications, active indicators).
170
+ struct PulseModifier: ViewModifier {
171
+ let intensity: CGFloat
172
+ @State private var scale: CGFloat = 1.0
173
+
174
+ func body(content: Content) -> some View {
175
+ content
176
+ .scaleEffect(scale)
177
+ .onAppear {
178
+ withAnimation(
179
+ .easeInOut(duration: 1.0)
180
+ .repeatForever(autoreverses: true)
181
+ ) {
182
+ scale = 1.0 + intensity
183
+ }
184
+ }
185
+ }
186
+ }
187
+
188
+ // MARK: - Heart Bounce Modifier
189
+ /// Applies a scale-up bounce then return when toggled (e.g., favorite/like buttons).
190
+ struct HeartBounceModifier: ViewModifier {
191
+ let isActive: Bool
192
+ @State private var scale: CGFloat = 1.0
193
+
194
+ func body(content: Content) -> some View {
195
+ content
196
+ .scaleEffect(scale)
197
+ .motionAware(animation: .spring(response: 0.3, dampingFraction: 0.5))
198
+ .onChange(of: isActive) { _, newValue in
199
+ if newValue {
200
+ scale = 1.3
201
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
202
+ scale = 1.0
203
+ }
204
+ }
205
+ }
206
+ }
207
+ }
208
+
60
209
  // MARK: - View Extensions
61
210
 
62
211
  extension View {
@@ -79,4 +228,56 @@ extension View {
79
228
  func bounceOnChange(isActive: Bool) -> some View {
80
229
  modifier(BounceScaleModifier(isActive: isActive))
81
230
  }
231
+
232
+ /// Applies scale-down press feedback to any tappable element.
233
+ /// Scales to 0.95 on press with spring return animation.
234
+ func scaleOnPress() -> some View {
235
+ modifier(ScaleOnPressModifier())
236
+ }
237
+
238
+ /// Triggers haptic feedback on tap.
239
+ /// - Parameter style: Feedback intensity (.light, .medium, .heavy)
240
+ func hapticFeedback(_ style: UIImpactFeedbackGenerator.FeedbackStyle = .light) -> some View {
241
+ modifier(HapticFeedbackModifier(style: style))
242
+ }
243
+
244
+ /// Applies a slide-from-side + fade-in animation on appear.
245
+ /// - Parameter delay: Delay before animation starts (default: 0)
246
+ func slideAndFade(delay: Double = 0) -> some View {
247
+ modifier(SlideAndFadeModifier(delay: delay))
248
+ }
249
+
250
+ /// Applies subtle colored shadow to cards and elevated surfaces.
251
+ /// Uses dual-shadow technique: primary-tinted shadow + neutral shadow for depth.
252
+ /// - Parameters:
253
+ /// - color: Shadow tint color (default: .primary)
254
+ /// - radius: Shadow blur radius (default: 8)
255
+ /// - y: Vertical offset (default: 4)
256
+ func cardShadow(color: Color = .primary, radius: CGFloat = 8, y: CGFloat = 4) -> some View {
257
+ modifier(CardShadowModifier(color: color, radius: radius, y: y))
258
+ }
259
+
260
+ /// Applies deeper shadow for floating elements (FABs, modals).
261
+ /// - Parameter color: Shadow tint color (default: .primary)
262
+ func elevatedShadow(color: Color = .primary) -> some View {
263
+ modifier(ElevatedShadowModifier(color: color))
264
+ }
265
+
266
+ /// Applies a shimmer loading overlay (e.g., for skeleton placeholder views).
267
+ func shimmer() -> some View {
268
+ modifier(ShimmerModifier())
269
+ }
270
+
271
+ /// Applies a repeating pulse animation (e.g., for notifications, live indicators).
272
+ /// - Parameter intensity: Scale increase per pulse (default: 0.05 = 5% bigger)
273
+ func pulse(intensity: CGFloat = 0.05) -> some View {
274
+ modifier(PulseModifier(intensity: intensity))
275
+ }
276
+
277
+ /// Applies a heart/like bounce effect when toggled active.
278
+ /// Scales up to 1.3x then springs back. Perfect for favorite buttons.
279
+ /// - Parameter isActive: Boolean that triggers the bounce when it becomes true
280
+ func heartBounce(isActive: Bool) -> some View {
281
+ modifier(HeartBounceModifier(isActive: isActive))
282
+ }
82
283
  }
@@ -57,6 +57,155 @@ struct BounceScaleModifier: ViewModifier {
57
57
  }
58
58
  }
59
59
 
60
+ // MARK: - Scale on Press Modifier
61
+ /// Applies scale-down + spring-back animation when pressed (like a button press).
62
+ struct ScaleOnPressModifier: ViewModifier {
63
+ @State private var isPressed = false
64
+
65
+ func body(content: Content) -> some View {
66
+ content
67
+ .scaleEffect(isPressed ? 0.95 : 1.0)
68
+ .animation(.spring(response: 0.3, dampingFraction: 0.7), value: isPressed)
69
+ .simultaneousGesture(
70
+ DragGesture(minimumDistance: 0)
71
+ .onChanged { _ in isPressed = true }
72
+ .onEnded { _ in isPressed = false }
73
+ )
74
+ }
75
+ }
76
+
77
+ // MARK: - Haptic Feedback Modifier
78
+ /// Triggers haptic feedback on tap.
79
+ struct HapticFeedbackModifier: ViewModifier {
80
+ let style: UIImpactFeedbackGenerator.FeedbackStyle
81
+
82
+ func body(content: Content) -> some View {
83
+ content
84
+ .onTapGesture {
85
+ UIImpactFeedbackGenerator(style: style).impactOccurred()
86
+ }
87
+ }
88
+ }
89
+
90
+ // MARK: - Slide and Fade Modifier
91
+ /// Applies a slide-from-side + fade-in animation on appear.
92
+ struct SlideAndFadeModifier: ViewModifier {
93
+ let delay: Double
94
+ @State private var isVisible = false
95
+
96
+ func body(content: Content) -> some View {
97
+ content
98
+ .opacity(isVisible ? 1 : 0)
99
+ .offset(x: isVisible ? 0 : 20)
100
+ .motionAware(animation: .spring(response: 0.5, dampingFraction: 0.8).delay(delay))
101
+ .onAppear {
102
+ isVisible = true
103
+ }
104
+ }
105
+ }
106
+
107
+ // MARK: - Card Shadow Modifier
108
+ /// Applies a subtle colored shadow to cards and elevated surfaces.
109
+ struct CardShadowModifier: ViewModifier {
110
+ let color: Color
111
+ let radius: CGFloat
112
+ let y: CGFloat
113
+
114
+ func body(content: Content) -> some View {
115
+ content
116
+ .shadow(color: color.opacity(0.08), radius: radius, x: 0, y: y)
117
+ .shadow(color: Color.black.opacity(0.04), radius: radius / 2, x: 0, y: y / 2)
118
+ }
119
+ }
120
+
121
+ // MARK: - Elevated Shadow Modifier
122
+ /// Applies a deeper shadow for FABs and floating elements.
123
+ struct ElevatedShadowModifier: ViewModifier {
124
+ let color: Color
125
+
126
+ func body(content: Content) -> some View {
127
+ content
128
+ .shadow(color: color.opacity(0.12), radius: 16, x: 0, y: 8)
129
+ .shadow(color: Color.black.opacity(0.06), radius: 8, x: 0, y: 4)
130
+ }
131
+ }
132
+
133
+ // MARK: - Shimmer Modifier
134
+ /// Applies a shimmer/skeleton-loading gradient overlay for loading states.
135
+ struct ShimmerModifier: ViewModifier {
136
+ @State private var isAnimating = false
137
+
138
+ func body(content: Content) -> some View {
139
+ content
140
+ .overlay(
141
+ GeometryReader { geometry in
142
+ if isAnimating {
143
+ LinearGradient(
144
+ colors: [
145
+ Color.clear,
146
+ Color.white.opacity(0.3),
147
+ Color.clear
148
+ ],
149
+ startPoint: .leading,
150
+ endPoint: .trailing
151
+ )
152
+ .offset(x: isAnimating ? geometry.size.width : -geometry.size.width)
153
+ .animation(
154
+ Animation.linear(duration: 1.5)
155
+ .repeatForever(autoreverses: false),
156
+ value: isAnimating
157
+ )
158
+ }
159
+ }
160
+ )
161
+ .clipped()
162
+ .onAppear {
163
+ isAnimating = true
164
+ }
165
+ }
166
+ }
167
+
168
+ // MARK: - Pulse Modifier
169
+ /// Applies a repeating scale pulse effect (e.g., for notifications, active indicators).
170
+ struct PulseModifier: ViewModifier {
171
+ let intensity: CGFloat
172
+ @State private var scale: CGFloat = 1.0
173
+
174
+ func body(content: Content) -> some View {
175
+ content
176
+ .scaleEffect(scale)
177
+ .onAppear {
178
+ withAnimation(
179
+ .easeInOut(duration: 1.0)
180
+ .repeatForever(autoreverses: true)
181
+ ) {
182
+ scale = 1.0 + intensity
183
+ }
184
+ }
185
+ }
186
+ }
187
+
188
+ // MARK: - Heart Bounce Modifier
189
+ /// Applies a scale-up bounce then return when toggled (e.g., favorite/like buttons).
190
+ struct HeartBounceModifier: ViewModifier {
191
+ let isActive: Bool
192
+ @State private var scale: CGFloat = 1.0
193
+
194
+ func body(content: Content) -> some View {
195
+ content
196
+ .scaleEffect(scale)
197
+ .motionAware(animation: .spring(response: 0.3, dampingFraction: 0.5))
198
+ .onChange(of: isActive) { _, newValue in
199
+ if newValue {
200
+ scale = 1.3
201
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
202
+ scale = 1.0
203
+ }
204
+ }
205
+ }
206
+ }
207
+ }
208
+
60
209
  // MARK: - View Extensions
61
210
 
62
211
  extension View {
@@ -79,4 +228,56 @@ extension View {
79
228
  func bounceOnChange(isActive: Bool) -> some View {
80
229
  modifier(BounceScaleModifier(isActive: isActive))
81
230
  }
231
+
232
+ /// Applies scale-down press feedback to any tappable element.
233
+ /// Scales to 0.95 on press with spring return animation.
234
+ func scaleOnPress() -> some View {
235
+ modifier(ScaleOnPressModifier())
236
+ }
237
+
238
+ /// Triggers haptic feedback on tap.
239
+ /// - Parameter style: Feedback intensity (.light, .medium, .heavy)
240
+ func hapticFeedback(_ style: UIImpactFeedbackGenerator.FeedbackStyle = .light) -> some View {
241
+ modifier(HapticFeedbackModifier(style: style))
242
+ }
243
+
244
+ /// Applies a slide-from-side + fade-in animation on appear.
245
+ /// - Parameter delay: Delay before animation starts (default: 0)
246
+ func slideAndFade(delay: Double = 0) -> some View {
247
+ modifier(SlideAndFadeModifier(delay: delay))
248
+ }
249
+
250
+ /// Applies subtle colored shadow to cards and elevated surfaces.
251
+ /// Uses dual-shadow technique: primary-tinted shadow + neutral shadow for depth.
252
+ /// - Parameters:
253
+ /// - color: Shadow tint color (default: .primary)
254
+ /// - radius: Shadow blur radius (default: 8)
255
+ /// - y: Vertical offset (default: 4)
256
+ func cardShadow(color: Color = .primary, radius: CGFloat = 8, y: CGFloat = 4) -> some View {
257
+ modifier(CardShadowModifier(color: color, radius: radius, y: y))
258
+ }
259
+
260
+ /// Applies deeper shadow for floating elements (FABs, modals).
261
+ /// - Parameter color: Shadow tint color (default: .primary)
262
+ func elevatedShadow(color: Color = .primary) -> some View {
263
+ modifier(ElevatedShadowModifier(color: color))
264
+ }
265
+
266
+ /// Applies a shimmer loading overlay (e.g., for skeleton placeholder views).
267
+ func shimmer() -> some View {
268
+ modifier(ShimmerModifier())
269
+ }
270
+
271
+ /// Applies a repeating pulse animation (e.g., for notifications, live indicators).
272
+ /// - Parameter intensity: Scale increase per pulse (default: 0.05 = 5% bigger)
273
+ func pulse(intensity: CGFloat = 0.05) -> some View {
274
+ modifier(PulseModifier(intensity: intensity))
275
+ }
276
+
277
+ /// Applies a heart/like bounce effect when toggled active.
278
+ /// Scales up to 1.3x then springs back. Perfect for favorite buttons.
279
+ /// - Parameter isActive: Boolean that triggers the bounce when it becomes true
280
+ func heartBounce(isActive: Bool) -> some View {
281
+ modifier(HeartBounceModifier(isActive: isActive))
282
+ }
82
283
  }
@@ -0,0 +1,42 @@
1
+ import Foundation
2
+
3
+ // PLACEHOLDER: Replace with domain-specific strings during customization.
4
+
5
+ enum Strings {
6
+ // MARK: - Empty States
7
+ enum EmptyStates {
8
+ // No Results
9
+ static let noResultsTitle = "No Results Found"
10
+ static func noResultsSubtitle(_ query: String) -> String {
11
+ "We couldn't find anything matching \"\(query)\""
12
+ }
13
+
14
+ // No Items (home/main list)
15
+ static let noItemsTitle = "Nothing Here Yet"
16
+ static let noItemsSubtitle = "Get started by adding your first item"
17
+ static let addItemButton = "Add Item"
18
+
19
+ // No Favorites
20
+ static let noFavoritesTitle = "No Favorites Yet"
21
+ static let noFavoritesSubtitle = "Items you favorite will appear here"
22
+ static let browseButton = "Browse"
23
+
24
+ // No Connection
25
+ static let noConnectionTitle = "No Internet Connection"
26
+ static let noConnectionSubtitle = "Please check your connection and try again"
27
+ static let retryButton = "Retry"
28
+ }
29
+
30
+ // MARK: - Motion Preferences
31
+ enum MotionPreferences {
32
+ static let animationLevel = "Animations"
33
+ static let description = "Controls how animations and transitions appear throughout the app. System Reduce Motion setting is always respected."
34
+ static let reduceMotionActive = "System Reduce Motion is enabled. Animations will be simplified."
35
+ static let intensityFull = "Full"
36
+ static let intensityReduced = "Reduced"
37
+ static let intensityOff = "Off"
38
+ static let fullDescription = "All animations and transitions enabled"
39
+ static let reducedDescription = "Simplified cross-fade transitions only"
40
+ static let offDescription = "No animations — instant state changes"
41
+ }
42
+ }
@@ -9,7 +9,10 @@
9
9
  /* Begin PBXBuildFile section */
10
10
  0030A6126AB53949A447E5A4 /* AddTransactionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D4087E872161E3965345839 /* AddTransactionView.swift */; };
11
11
  06262F6E375D62E5C83CB6E7 /* LocalStorageProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5CB4A0AF70D48234F8E319B /* LocalStorageProvider.swift */; };
12
+ 081B7BF598EE452C17C13248 /* MotionPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38C603496F4A6BF6925E5478 /* MotionPreferencesView.swift */; };
13
+ 099E5918A202176F7876BD8D /* MotionPreferencesService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 583FCC836FF458E31F3256C0 /* MotionPreferencesService.swift */; };
12
14
  0C2A1C677B50A41C657D6D88 /* Models.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0FCDE28B386F10576BE071C /* Models.swift */; };
15
+ 0E97036E016CA1FFFD217DD4 /* AnimatedTransitionsModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15193469E944502B83786EAD /* AnimatedTransitionsModels.swift */; };
13
16
  13AC5FDCD39B5109826858DC /* DataRepositoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B2A4C9064BF1A20305E2A78 /* DataRepositoryTests.swift */; };
14
17
  2D63116A37CE16D9EACFAECF /* BudgetsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 728C18F9384ABF099DDBE598 /* BudgetsView.swift */; };
15
18
  339B2018E800424FE60C5720 /* NetworkMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C5A7E7C81AF5E00E0A381BF /* NetworkMonitor.swift */; };
@@ -32,20 +35,17 @@
32
35
  A305D126DE0BABE62D437C80 /* AccountEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = F32E86E6C71160D4E183740A /* AccountEntity.swift */; };
33
36
  A686FF824C3467A163E8DB22 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FBA40139BF96E8F5D0451613 /* Assets.xcassets */; };
34
37
  A6C7FDC75029CE2B8014E9C5 /* GoalEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EF7EDEC9048C32A74D39CC /* GoalEntity.swift */; };
38
+ B5FCA0B1591F3636F297C4AD /* Strings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93749A5DBE5A340BF09D6295 /* Strings.swift */; };
39
+ C603AFB1EB99F9B054DA31F2 /* AnimatedTransitionsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA4C933669D854FCE33848C8 /* AnimatedTransitionsService.swift */; };
35
40
  C64812CB63135E8FE931EB90 /* TransactionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AD24420E8D94F3B7B252EC1 /* TransactionsView.swift */; };
36
41
  CFDFD5A345100A7E59E06003 /* LocalPersistence.swift in Sources */ = {isa = PBXBuildFile; fileRef = E73FB29D044A8414DC323190 /* LocalPersistence.swift */; };
37
42
  D8454AF6FD657C0C60CEAFD7 /* CategoryEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = D545536631A59F160A2C07C0 /* CategoryEntity.swift */; };
38
43
  D989823A63D5F0F1127638EE /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 415FA5F58F95CB679BE66E24 /* HomeView.swift */; };
39
44
  E7D118ABFBD92EAC4ACB817E /* BillEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA1C263945CBA4D7068C395 /* BillEntity.swift */; };
45
+ EE916674E2F0F9EBCC556C6D /* MotionPreferencesModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66301A39BDB01056CBD435F1 /* MotionPreferencesModels.swift */; };
40
46
  EEF019728CCB5CF689E24E96 /* DataRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA19A16CEE9A32C13776FC44 /* DataRepository.swift */; };
47
+ F2BD0B1F473FDCCC9C85DEE7 /* AnimatedTransitionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AF81BAFE40F3C3D2B1E5833 /* AnimatedTransitionsView.swift */; };
41
48
  FB159B101849018F8A40A6F1 /* EmptyStateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 326A8F3E2250136B4EFFA138 /* EmptyStateView.swift */; };
42
- 0011A7CEDB5A42A4A9FCCBE0 /* Strings.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC5EC469DD9D47F49EA72212 /* Strings.swift */; };
43
- FA7703E8EB784C2DB6295DEA /* AnimatedTransitionsModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9536F490EBC74A558D1628AD /* AnimatedTransitionsModels.swift */; };
44
- A70AF1ACCCF74265A66E111E /* AnimatedTransitionsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D7444EA4CA4436BB1AD120 /* AnimatedTransitionsService.swift */; };
45
- 49D845B6FEE846FDAFC1BF08 /* AnimatedTransitionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB844B30E17D49FDBBEF816F /* AnimatedTransitionsView.swift */; };
46
- 4D3826B044754313B2D61BA1 /* MotionPreferencesModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD2A62C23E2541C5944964CA /* MotionPreferencesModels.swift */; };
47
- 11E273AF32C6424384CF5476 /* MotionPreferencesService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B00ED63502346338D320F19 /* MotionPreferencesService.swift */; };
48
- F0A979C3513F41DAB0BECFF0 /* MotionPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9B93275A47A4B85BC823B33 /* MotionPreferencesView.swift */; };
49
49
  /* End PBXBuildFile section */
50
50
 
51
51
  /* Begin PBXContainerItemProxy section */
@@ -61,11 +61,13 @@
61
61
  /* Begin PBXFileReference section */
62
62
  04AED7EA6B55AADEFAE90802 /* FinanceTemplate.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = FinanceTemplate.app; sourceTree = BUILT_PRODUCTS_DIR; };
63
63
  150AF829A865D5A9EACC25BE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
64
+ 15193469E944502B83786EAD /* AnimatedTransitionsModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnimatedTransitionsModels.swift; sourceTree = "<group>"; };
64
65
  1C00F9B04A3A2E702DF93BEE /* CoreDataStack.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataStack.swift; sourceTree = "<group>"; };
66
+ 2AF81BAFE40F3C3D2B1E5833 /* AnimatedTransitionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnimatedTransitionsView.swift; sourceTree = "<group>"; };
65
67
  2B830C1208F1D61593CB4B29 /* GoalsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GoalsView.swift; sourceTree = "<group>"; };
66
68
  2BEF28E0E8F98C7F5D03BCBE /* BudgetEntity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BudgetEntity.swift; sourceTree = "<group>"; };
67
69
  326A8F3E2250136B4EFFA138 /* EmptyStateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyStateView.swift; sourceTree = "<group>"; };
68
- CC5EC469DD9D47F49EA72212 /* Strings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Strings.swift; sourceTree = "<group>"; };
70
+ 38C603496F4A6BF6925E5478 /* MotionPreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MotionPreferencesView.swift; sourceTree = "<group>"; };
69
71
  3A2CE72C76C692429FD8D128 /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = "<group>"; };
70
72
  415FA5F58F95CB679BE66E24 /* HomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = "<group>"; };
71
73
  46BEE8E0E968DB2CD24E1753 /* OfflineBanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OfflineBanner.swift; sourceTree = "<group>"; };
@@ -73,7 +75,9 @@
73
75
  4DA1404BAA55F4B0201F889A /* AppConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppConfig.swift; sourceTree = "<group>"; };
74
76
  4E1D6FE7CDDE464E6FA187C4 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
75
77
  5454AA7EB63BDE729C41E146 /* FinanceTemplateTests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = FinanceTemplateTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
78
+ 583FCC836FF458E31F3256C0 /* MotionPreferencesService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MotionPreferencesService.swift; sourceTree = "<group>"; };
76
79
  5D4087E872161E3965345839 /* AddTransactionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddTransactionView.swift; sourceTree = "<group>"; };
80
+ 66301A39BDB01056CBD435F1 /* MotionPreferencesModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MotionPreferencesModels.swift; sourceTree = "<group>"; };
77
81
  6AD24420E8D94F3B7B252EC1 /* TransactionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionsView.swift; sourceTree = "<group>"; };
78
82
  728C18F9384ABF099DDBE598 /* BudgetsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BudgetsView.swift; sourceTree = "<group>"; };
79
83
  75EF7EDEC9048C32A74D39CC /* GoalEntity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GoalEntity.swift; sourceTree = "<group>"; };
@@ -84,9 +88,11 @@
84
88
  86A2D418BE44E2AAD0CB5CBF /* MainTabView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTabView.swift; sourceTree = "<group>"; };
85
89
  8BA1C263945CBA4D7068C395 /* BillEntity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BillEntity.swift; sourceTree = "<group>"; };
86
90
  8C5A7E7C81AF5E00E0A381BF /* NetworkMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkMonitor.swift; sourceTree = "<group>"; };
91
+ 93749A5DBE5A340BF09D6295 /* Strings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Strings.swift; sourceTree = "<group>"; };
87
92
  960D99E887A6CF84FFD9C135 /* MockDataProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockDataProvider.swift; sourceTree = "<group>"; };
88
93
  AA19A16CEE9A32C13776FC44 /* DataRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataRepository.swift; sourceTree = "<group>"; };
89
94
  C9176647AD403B9E81B2C8F7 /* FinanceTemplateApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FinanceTemplateApp.swift; sourceTree = "<group>"; };
95
+ CA4C933669D854FCE33848C8 /* AnimatedTransitionsService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnimatedTransitionsService.swift; sourceTree = "<group>"; };
90
96
  D545536631A59F160A2C07C0 /* CategoryEntity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryEntity.swift; sourceTree = "<group>"; };
91
97
  E0FCDE28B386F10576BE071C /* Models.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Models.swift; sourceTree = "<group>"; };
92
98
  E2A5DC14F392BA60D307615A /* MockDataProviderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockDataProviderTests.swift; sourceTree = "<group>"; };
@@ -95,12 +101,6 @@
95
101
  F5CB4A0AF70D48234F8E319B /* LocalStorageProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalStorageProvider.swift; sourceTree = "<group>"; };
96
102
  FBA40139BF96E8F5D0451613 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97
103
  FE0C15DF4A0311371691BD07 /* InsightEntity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsightEntity.swift; sourceTree = "<group>"; };
98
- 9536F490EBC74A558D1628AD /* AnimatedTransitionsModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnimatedTransitionsModels.swift; sourceTree = "<group>"; };
99
- 09D7444EA4CA4436BB1AD120 /* AnimatedTransitionsService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnimatedTransitionsService.swift; sourceTree = "<group>"; };
100
- CB844B30E17D49FDBBEF816F /* AnimatedTransitionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnimatedTransitionsView.swift; sourceTree = "<group>"; };
101
- CD2A62C23E2541C5944964CA /* MotionPreferencesModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MotionPreferencesModels.swift; sourceTree = "<group>"; };
102
- 4B00ED63502346338D320F19 /* MotionPreferencesService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MotionPreferencesService.swift; sourceTree = "<group>"; };
103
- D9B93275A47A4B85BC823B33 /* MotionPreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MotionPreferencesView.swift; sourceTree = "<group>"; };
104
104
  /* End PBXFileReference section */
105
105
 
106
106
  /* Begin PBXGroup section */
@@ -108,8 +108,8 @@
108
108
  isa = PBXGroup;
109
109
  children = (
110
110
  326A8F3E2250136B4EFFA138 /* EmptyStateView.swift */,
111
- CC5EC469DD9D47F49EA72212 /* Strings.swift */,
112
- F5548A96E41143B9AE2B0475 /* Animation */,
111
+ 93749A5DBE5A340BF09D6295 /* Strings.swift */,
112
+ C4993DBC1783F06100452CA6 /* Animation */,
113
113
  3E1B31013348328C560DB6A6 /* Theme */,
114
114
  );
115
115
  path = Core;
@@ -234,6 +234,19 @@
234
234
  path = Components;
235
235
  sourceTree = "<group>";
236
236
  };
237
+ C4993DBC1783F06100452CA6 /* Animation */ = {
238
+ isa = PBXGroup;
239
+ children = (
240
+ 15193469E944502B83786EAD /* AnimatedTransitionsModels.swift */,
241
+ CA4C933669D854FCE33848C8 /* AnimatedTransitionsService.swift */,
242
+ 2AF81BAFE40F3C3D2B1E5833 /* AnimatedTransitionsView.swift */,
243
+ 66301A39BDB01056CBD435F1 /* MotionPreferencesModels.swift */,
244
+ 583FCC836FF458E31F3256C0 /* MotionPreferencesService.swift */,
245
+ 38C603496F4A6BF6925E5478 /* MotionPreferencesView.swift */,
246
+ );
247
+ path = Animation;
248
+ sourceTree = "<group>";
249
+ };
237
250
  D2B443E14BBBE3F725724EA3 /* LocalStorage */ = {
238
251
  isa = PBXGroup;
239
252
  children = (
@@ -299,19 +312,6 @@
299
312
  path = Home;
300
313
  sourceTree = "<group>";
301
314
  };
302
- F5548A96E41143B9AE2B0475 /* Animation */ = {
303
- isa = PBXGroup;
304
- children = (
305
- 9536F490EBC74A558D1628AD /* AnimatedTransitionsModels.swift */,
306
- 09D7444EA4CA4436BB1AD120 /* AnimatedTransitionsService.swift */,
307
- CB844B30E17D49FDBBEF816F /* AnimatedTransitionsView.swift */,
308
- CD2A62C23E2541C5944964CA /* MotionPreferencesModels.swift */,
309
- 4B00ED63502346338D320F19 /* MotionPreferencesService.swift */,
310
- D9B93275A47A4B85BC823B33 /* MotionPreferencesView.swift */,
311
- );
312
- path = Animation;
313
- sourceTree = "<group>";
314
- };
315
315
  /* End PBXGroup section */
316
316
 
317
317
  /* Begin PBXNativeTarget section */
@@ -398,6 +398,9 @@
398
398
  files = (
399
399
  A305D126DE0BABE62D437C80 /* AccountEntity.swift in Sources */,
400
400
  0030A6126AB53949A447E5A4 /* AddTransactionView.swift in Sources */,
401
+ 0E97036E016CA1FFFD217DD4 /* AnimatedTransitionsModels.swift in Sources */,
402
+ C603AFB1EB99F9B054DA31F2 /* AnimatedTransitionsService.swift in Sources */,
403
+ F2BD0B1F473FDCCC9C85DEE7 /* AnimatedTransitionsView.swift in Sources */,
401
404
  71CD22588C17F4482E662150 /* AppConfig.swift in Sources */,
402
405
  E7D118ABFBD92EAC4ACB817E /* BillEntity.swift in Sources */,
403
406
  4B1231A6F5DE03FF8E0E0A8A /* BudgetEntity.swift in Sources */,
@@ -409,7 +412,6 @@
409
412
  7D8CA62EA059158C74908B60 /* DataSourceResolver.swift in Sources */,
410
413
  FB159B101849018F8A40A6F1 /* EmptyStateView.swift in Sources */,
411
414
  58F7B061E2D219A0E8DA197B /* FinanceTemplateApp.swift in Sources */,
412
- 0011A7CEDB5A42A4A9FCCBE0 /* Strings.swift in Sources */,
413
415
  A6C7FDC75029CE2B8014E9C5 /* GoalEntity.swift in Sources */,
414
416
  37E80967377DD57E4F82DC8B /* GoalsView.swift in Sources */,
415
417
  D989823A63D5F0F1127638EE /* HomeView.swift in Sources */,
@@ -419,9 +421,13 @@
419
421
  95860BD08AF9C7391CAB2318 /* MainTabView.swift in Sources */,
420
422
  58F60CA041D3F2047251858B /* MockDataProvider.swift in Sources */,
421
423
  0C2A1C677B50A41C657D6D88 /* Models.swift in Sources */,
424
+ EE916674E2F0F9EBCC556C6D /* MotionPreferencesModels.swift in Sources */,
425
+ 099E5918A202176F7876BD8D /* MotionPreferencesService.swift in Sources */,
426
+ 081B7BF598EE452C17C13248 /* MotionPreferencesView.swift in Sources */,
422
427
  339B2018E800424FE60C5720 /* NetworkMonitor.swift in Sources */,
423
428
  3F3E5E170276B05545875BA0 /* OfflineBanner.swift in Sources */,
424
429
  8C33D08433A0A07CF32E722D /* SettingsView.swift in Sources */,
430
+ B5FCA0B1591F3636F297C4AD /* Strings.swift in Sources */,
425
431
  4179BAD8F353E1D5D1470B97 /* SyncManager.swift in Sources */,
426
432
  717E7677B9D7CEF8B3B77687 /* TransactionEntity.swift in Sources */,
427
433
  C64812CB63135E8FE931EB90 /* TransactionsView.swift in Sources */,