@buivietphi/skill-mobile-mt 2.0.0

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.
@@ -0,0 +1,304 @@
1
+ # Flutter — Production Patterns
2
+
3
+ > Battle-tested patterns from production Flutter apps.
4
+ > State: Riverpod (standard)
5
+ > DI: get_it + injectable
6
+ > Networking: Dio + Retrofit, or http
7
+ > Navigation: GoRouter
8
+
9
+ ---
10
+
11
+ ## Clean Architecture
12
+
13
+ ```
14
+ lib/
15
+ ├── main.dart # Entry: Firebase init, Hive init, ProviderScope
16
+ ├── app/
17
+ │ ├── app.dart # MaterialApp.router
18
+ │ ├── router.dart # GoRouter config
19
+ │ └── theme/
20
+ ├── features/
21
+ │ ├── auth/
22
+ │ │ ├── domain/ # Entities + use cases + repository interfaces
23
+ │ │ ├── data/ # Repository impl, API client, DTOs, mappers
24
+ │ │ ├── presentation/ # Screens + widgets
25
+ │ │ └── providers/ # Riverpod providers
26
+ │ └── [feature]/
27
+ │ └── ... (same structure)
28
+ ├── shared/
29
+ │ ├── widgets/ # Reusable UI
30
+ │ ├── extensions/
31
+ │ └── utils/
32
+ └── core/
33
+ ├── network/ # Dio client setup, interceptors
34
+ ├── storage/ # Hive + SharedPrefs + flutter_secure_storage
35
+ ├── di/ # get_it + injectable setup
36
+ └── constants/
37
+ ```
38
+
39
+ ### Dependency Rule
40
+ ```
41
+ presentation/ → domain/ ← data/
42
+
43
+ Presentation depends on Domain. Data depends on Domain.
44
+ Domain depends on NOTHING.
45
+ Never import data/ from presentation/ directly.
46
+ Use cases call repository interfaces (defined in domain/).
47
+ Data layer provides implementations.
48
+ ```
49
+
50
+ ## State Management (Riverpod)
51
+
52
+ ```dart
53
+ // domain/usecases/get_products.dart
54
+ class GetProducts {
55
+ final ProductRepository repository;
56
+ GetProducts(this.repository);
57
+ Future<List<Product>> call() => repository.getProducts();
58
+ }
59
+
60
+ // features/product/providers/product_providers.dart
61
+ @riverpod
62
+ class ProductList extends _$ProductList {
63
+ @override
64
+ FutureOr<List<Product>> build() async {
65
+ final repo = ref.read(productRepositoryProvider);
66
+ return repo.getProducts();
67
+ }
68
+
69
+ Future<void> refresh() async {
70
+ state = const AsyncLoading();
71
+ state = await AsyncValue.guard(() async {
72
+ final repo = ref.read(productRepositoryProvider);
73
+ return repo.getProducts();
74
+ });
75
+ }
76
+ }
77
+
78
+ // features/product/presentation/product_screen.dart
79
+ class ProductScreen extends ConsumerWidget {
80
+ const ProductScreen({super.key});
81
+
82
+ @override
83
+ Widget build(BuildContext context, WidgetRef ref) {
84
+ final products = ref.watch(productListProvider);
85
+ return products.when(
86
+ data: (list) => list.isEmpty
87
+ ? const EmptyState()
88
+ : ListView.builder(
89
+ itemCount: list.length,
90
+ itemBuilder: (_, i) => ProductCard(product: list[i]),
91
+ ),
92
+ loading: () => const Center(child: CircularProgressIndicator()),
93
+ error: (e, _) => ErrorState(onRetry: () => ref.invalidate(productListProvider)),
94
+ );
95
+ }
96
+ }
97
+ ```
98
+
99
+ ## Dependency Injection (get_it + injectable)
100
+
101
+ ```dart
102
+ // core/di/injection.dart
103
+ import 'package:get_it/get_it.dart';
104
+ import 'package:injectable/injectable.dart';
105
+
106
+ final getIt = GetIt.instance;
107
+
108
+ @InjectableInit()
109
+ void configureDependencies() => getIt.init();
110
+
111
+ // Usage: annotate classes
112
+ @injectable
113
+ class AuthRepository {
114
+ final ApiClient _client;
115
+ AuthRepository(this._client);
116
+ }
117
+ ```
118
+
119
+ ## Navigation (GoRouter)
120
+
121
+ ```dart
122
+ final router = GoRouter(
123
+ redirect: (context, state) {
124
+ final isAuth = authNotifier.isAuthenticated;
125
+ final isAuthRoute = state.matchedLocation.startsWith('/auth');
126
+ if (!isAuth && !isAuthRoute) return '/auth/login';
127
+ if (isAuth && isAuthRoute) return '/';
128
+ return null;
129
+ },
130
+ routes: [
131
+ ShellRoute(
132
+ builder: (_, __, child) => MainScaffold(child: child),
133
+ routes: [
134
+ GoRoute(path: '/', builder: (_, __) => const HomeScreen()),
135
+ GoRoute(path: '/profile', builder: (_, __) => const ProfileScreen()),
136
+ ],
137
+ ),
138
+ GoRoute(path: '/auth/login', builder: (_, __) => const LoginScreen()),
139
+ ],
140
+ );
141
+ ```
142
+
143
+ ## Networking
144
+
145
+ ### Dio + Retrofit
146
+
147
+ ```dart
148
+ @RestApi(baseUrl: ApiConstants.baseUrl)
149
+ abstract class ApiClient {
150
+ factory ApiClient(Dio dio) = _ApiClient;
151
+
152
+ @GET('/products')
153
+ Future<ApiResponse<List<ProductDto>>> getProducts();
154
+
155
+ @POST('/auth/login')
156
+ Future<ApiResponse<AuthDto>> login(@Body() LoginInput input);
157
+ }
158
+
159
+ // Dio setup with interceptors
160
+ final dio = Dio(BaseOptions(
161
+ baseUrl: ApiConstants.baseUrl,
162
+ connectTimeout: const Duration(seconds: 15),
163
+ ))
164
+ ..interceptors.addAll([
165
+ AuthInterceptor(secureStorage),
166
+ PrettyDioLogger(requestBody: true, responseBody: true),
167
+ RetryInterceptor(dio: dio, retries: 2),
168
+ ]);
169
+ ```
170
+
171
+ ### HTTP (simpler pattern)
172
+
173
+ ```dart
174
+ final response = await http.get(
175
+ Uri.parse('$baseUrl/endpoint'),
176
+ headers: {'Authorization': 'Bearer $token'},
177
+ );
178
+ ```
179
+
180
+ ## Local Storage
181
+
182
+ ```dart
183
+ // Hive (structured data)
184
+ await Hive.initFlutter();
185
+ Hive.registerAdapter(UserAdapter());
186
+ final box = await Hive.openBox<User>('users');
187
+
188
+ // Floor (Room-like SQL)
189
+ @dao
190
+ abstract class ProductDao {
191
+ @Query('SELECT * FROM products')
192
+ Future<List<ProductEntity>> getAll();
193
+
194
+ @Insert(onConflict: OnConflictStrategy.replace)
195
+ Future<void> insertAll(List<ProductEntity> products);
196
+ }
197
+
198
+ // SharedPreferences (simple key-value)
199
+ final prefs = await SharedPreferences.getInstance();
200
+
201
+ // flutter_secure_storage (tokens)
202
+ final storage = const FlutterSecureStorage();
203
+ await storage.write(key: 'token', value: token);
204
+ ```
205
+
206
+ ## Firebase
207
+
208
+ ```dart
209
+ // Firebase init in main.dart
210
+ await Firebase.initializeApp();
211
+ await FirebaseMessaging.instance.requestPermission();
212
+
213
+ // Firestore
214
+ final doc = await FirebaseFirestore.instance.collection('users').doc(uid).get();
215
+
216
+ // FCM push
217
+ FirebaseMessaging.onMessage.listen((message) {
218
+ // Handle foreground notification
219
+ });
220
+ ```
221
+
222
+ ## Key Libraries
223
+
224
+ | Purpose | Library |
225
+ |---------|---------|
226
+ | State | flutter_riverpod |
227
+ | DI | get_it + injectable |
228
+ | HTTP | dio + retrofit |
229
+ | HTTP | http |
230
+ | DB | floor |
231
+ | DB | hive |
232
+ | Router | go_router |
233
+ | UI | flutter_screenutil |
234
+ | Anim | flutter_animate |
235
+ | Auth | local_auth (biometric) |
236
+ | Crypto | encrypt, crypto |
237
+ | Forms | formz |
238
+ | Func | dartz (Either, Option) |
239
+ | Models | freezed_annotation |
240
+ | Firebase | firebase_core, messaging, firestore |
241
+ | Image | cached_network_image |
242
+
243
+ ## Dart 3.x Patterns
244
+
245
+ ```dart
246
+ // Sealed classes — exhaustive pattern matching (replaces abstract + subclasses)
247
+ sealed class AuthState {}
248
+ class Authenticated extends AuthState { final User user; Authenticated(this.user); }
249
+ class Unauthenticated extends AuthState {}
250
+ class Loading extends AuthState {}
251
+
252
+ // Usage — compiler enforces all cases are handled
253
+ Widget build() => switch (authState) {
254
+ Authenticated(:final user) => HomeScreen(user: user),
255
+ Unauthenticated() => LoginScreen(),
256
+ Loading() => const CircularProgressIndicator(),
257
+ };
258
+
259
+ // Records — lightweight tuples with named fields (Dart 3.0)
260
+ (String name, int age) getUser() => ('Alice', 30);
261
+ final (name, age) = getUser();
262
+
263
+ // Pattern matching in if/switch
264
+ if (response case {'status': 'ok', 'data': final data}) {
265
+ processData(data);
266
+ }
267
+
268
+ // Riverpod + sealed class = clean state
269
+ @riverpod
270
+ class AuthNotifier extends _$AuthNotifier {
271
+ @override
272
+ AuthState build() => Unauthenticated();
273
+
274
+ Future<void> login(String email, String password) async {
275
+ state = Loading();
276
+ state = switch (await _repo.login(email, password)) {
277
+ Ok(:final value) => Authenticated(value),
278
+ Err(:final error) => Unauthenticated(), // or a separate Error state
279
+ };
280
+ }
281
+ }
282
+ ```
283
+
284
+ ## Impeller (Flutter 3.10+)
285
+
286
+ ```
287
+ Impeller is Flutter's new rendering engine — enabled by default on iOS.
288
+ Android: opt-in via AndroidManifest.xml
289
+
290
+ Benefits:
291
+ - Eliminates shader compilation jank (the "jank on first frame" problem)
292
+ - Consistent 60/120fps even on first run
293
+
294
+ Enable on Android:
295
+ <meta-data android:name="io.flutter.embedding.android.EnableImpeller" android:value="true" />
296
+
297
+ Test: flutter run --enable-impeller
298
+ ```
299
+
300
+ ---
301
+
302
+ > Standard: Riverpod + get_it/injectable + Clean Architecture.
303
+ > Dio/Retrofit for complex APIs. Floor for offline-first. Firebase for push/analytics.
304
+ > Dart 3.x: sealed classes + records for type-safe state.
@@ -0,0 +1,295 @@
1
+ # Humanizer — Mobile Copy & Text
2
+
3
+ > Invoke with: @humanizer-mobile
4
+ > Use for: app store descriptions, release notes, error messages, onboarding copy, push notifications, UI labels
5
+
6
+ ---
7
+
8
+ ## What this does
9
+
10
+ Removes AI-generated writing patterns from mobile app text. Makes copy sound like a real person wrote it — not a language model.
11
+
12
+ **Rule:** Sterile, voiceless writing is just as obvious as slop.
13
+
14
+ ---
15
+
16
+ ## The 24 AI Patterns to Kill
17
+
18
+ ### Content
19
+ | Pattern | Example | Fix |
20
+ |---------|---------|-----|
21
+ | Inflated significance | "This significantly enhances the overall user experience" | "Checkout is now 3 steps instead of 7" |
22
+ | Notability inflation | "A powerful, robust, feature-rich solution" | Just describe what it does |
23
+ | Promotional language | "Seamlessly integrates with your workflow" | "Connects to Slack and Notion" |
24
+ | Superficial -ing analysis | "By leveraging cutting-edge technology..." | State what the tech actually does |
25
+
26
+ ### Language
27
+ | Pattern | Example | Fix |
28
+ |---------|---------|-----|
29
+ | Copula avoidance | "The app, being designed for..." | "The app works for..." |
30
+ | Negative parallelism | "Not only fast, but also reliable, and furthermore secure" | Pick the one that matters most |
31
+ | Rule of three | "Simple, powerful, and intuitive" | Say which one is actually true |
32
+ | Elegant variation | "application... software... platform... tool..." | Pick one word and use it |
33
+
34
+ ### Style
35
+ | Pattern | Example | Fix |
36
+ |---------|---------|-----|
37
+ | Em dash overuse | "Our app — designed for professionals — helps you..." | Rewrite the sentence |
38
+ | Unnecessary bold | "This **feature** allows **users** to **manage** their **tasks**" | Bold nothing or bold the one key thing |
39
+ | Inline headers mid-paragraph | "**Key features:** The app includes..." | Just write the features |
40
+ | Emoji decoration | "🚀 Fast • 💪 Powerful • ✨ Beautiful" | Use 0 or 1 emoji max, never as decoration |
41
+
42
+ ### Communication (chatbot artifacts)
43
+ | Pattern | Example | Fix |
44
+ |---------|---------|-----|
45
+ | "I hope this helps" | Any form of it | Delete |
46
+ | "Feel free to..." | "Feel free to reach out" | "Contact us" |
47
+ | "Please note that" | "Please note that this feature requires..." | "This feature requires..." |
48
+ | Knowledge cutoff disclaimer | "As of my last update..." | Never use in app copy |
49
+ | "Delve into" | "Delve into your analytics" | "Check your analytics" |
50
+ | "Leverage" | "Leverage our AI" | "Use our AI" |
51
+ | "Streamline" | "Streamline your workflow" | Say what actually gets faster |
52
+ | "Robust" | "A robust solution" | Say what makes it strong |
53
+ | "Seamlessly" | "Seamlessly integrates" | "Works with" or just remove |
54
+ | "Intuitive" | "Intuitive interface" | Show don't tell — describe the UX |
55
+ | "Comprehensive" | "Comprehensive dashboard" | Say what's in the dashboard |
56
+
57
+ ---
58
+
59
+ ## Mobile-Specific Rewrites
60
+
61
+ ### App Store Description
62
+
63
+ ```
64
+ ❌ AI:
65
+ TaskFlow is a powerful, comprehensive task management application that seamlessly
66
+ integrates with your existing workflow. By leveraging cutting-edge AI technology,
67
+ it significantly enhances productivity and streamlines your daily operations.
68
+
69
+ ✅ Human:
70
+ TaskFlow keeps your team's work in one place. Add tasks, assign them, set
71
+ deadlines — everything syncs in real time. Works with Slack, Google Calendar,
72
+ and Notion.
73
+ ```
74
+
75
+ ### Release Notes
76
+
77
+ ```
78
+ ❌ AI:
79
+ Version 2.1.0 introduces significant enhancements to the overall user experience,
80
+ including robust improvements to performance and reliability.
81
+
82
+ ✅ Human:
83
+ 2.1.0
84
+ - Faster load times on older Android devices (was 4s, now 1.2s)
85
+ - Fixed crash when opening notifications while offline
86
+ - Dark mode now remembers your setting between sessions
87
+ ```
88
+
89
+ ### Error Messages
90
+
91
+ ```
92
+ ❌ AI:
93
+ We apologize for the inconvenience. An unexpected error has occurred while
94
+ processing your request. Please try again later.
95
+
96
+ ✅ Human:
97
+ Couldn't save your changes — no internet connection.
98
+ [Try again] [Save for later]
99
+ ```
100
+
101
+ ### Onboarding Copy
102
+
103
+ ```
104
+ ❌ AI:
105
+ Welcome to our powerful platform! By leveraging our intuitive interface,
106
+ you'll be able to seamlessly manage all your tasks efficiently.
107
+
108
+ ✅ Human:
109
+ Where do you want to start?
110
+ [Import from Trello] [Start from scratch] [Use a template]
111
+ ```
112
+
113
+ ### Push Notifications
114
+
115
+ ```
116
+ ❌ AI:
117
+ You have received a new message from a team member regarding an important update.
118
+
119
+ ✅ Human:
120
+ Alex commented on "Landing page redesign"
121
+ ```
122
+
123
+ ### Empty States
124
+
125
+ ```
126
+ ❌ AI:
127
+ No items found. Get started by creating your first item to begin
128
+ leveraging the full power of the platform.
129
+
130
+ ✅ Human:
131
+ No tasks yet.
132
+ [Add your first task]
133
+ ```
134
+
135
+ ---
136
+
137
+ ## Two-Pass Process
138
+
139
+ ### Pass 1 — Rewrite
140
+ 1. Find all patterns from the table above
141
+ 2. Replace each with direct, specific language
142
+ 3. Remove filler words: "overall", "various", "multiple", "utilize", "leverage"
143
+ 4. Cut sentence length by 30%
144
+
145
+ ### Pass 2 — Anti-AI Audit
146
+ Ask: *"What makes this obviously AI-generated?"*
147
+ - Does it make a claim without evidence? → Add a number or cut the claim
148
+ - Does it use an adjective where a verb would work? → Use the verb
149
+ - Could this describe any app in the category? → Make it specific to THIS app
150
+ - Would a person actually say this out loud? → If no, rewrite it
151
+
152
+ ---
153
+
154
+ ## Mobile Copy Principles
155
+
156
+ ```
157
+ 1. SPECIFIC BEATS VAGUE
158
+ ❌ "significantly faster"
159
+ ✅ "loads in under 1 second"
160
+
161
+ 2. VERBS BEAT ADJECTIVES
162
+ ❌ "intuitive navigation"
163
+ ✅ "swipe left to archive"
164
+
165
+ 3. SHORT SENTENCES FOR MOBILE
166
+ Max 12 words for notifications
167
+ Max 2 sentences for error messages
168
+ Max 3 sentences for onboarding screens
169
+
170
+ 4. SHOW DON'T TELL
171
+ ❌ "powerful search"
172
+ ✅ "search by name, tag, due date, or assignee"
173
+
174
+ 5. USER BENEFIT, NOT FEATURE
175
+ ❌ "real-time sync enabled"
176
+ ✅ "your team sees changes instantly"
177
+ ```
178
+
179
+ ---
180
+
181
+ ## App Store Character Limits
182
+
183
+ ```
184
+ iOS App Store:
185
+ Title: 30 chars → short, keyword-rich, no taglines
186
+ Subtitle: 30 chars → 1 benefit, not a repeat of title
187
+ Description: 4000 chars → first 3 lines show before "More", make them count
188
+ Keywords: 100 chars → comma-separated, no spaces, no repeats from title
189
+ What's New: 4000 chars → bullet points, plain language, no marketing
190
+
191
+ Google Play:
192
+ Title: 30 chars
193
+ Short desc: 80 chars → shows in search results
194
+ Full desc: 4000 chars
195
+ What's New: 500 chars
196
+ ```
197
+
198
+ ```
199
+ ❌ Title: "TaskFlow - Ultimate Productivity & Task Management Solution"
200
+ ✅ Title: "TaskFlow: Team Tasks & Projects"
201
+
202
+ ❌ Subtitle: "The most powerful way to manage your workflow seamlessly"
203
+ ✅ Subtitle: "Shared tasks with real-time sync"
204
+
205
+ ❌ What's New: "This update introduces significant improvements to the overall
206
+ user experience with enhanced performance and reliability."
207
+ ✅ What's New:
208
+ • Fixed crash on iPhone 14 when swiping between projects
209
+ • Dark mode now loads instantly instead of flashing white
210
+ • Added swipe-to-complete on task cards
211
+ ```
212
+
213
+ ---
214
+
215
+ ## Permission Request Copy
216
+
217
+ ```
218
+ ❌ AI default (iOS):
219
+ "[App] Would Like to Access Your Camera"
220
+ (No context, user taps Don't Allow)
221
+
222
+ ✅ Custom NSCameraUsageDescription:
223
+ "To scan receipts and attach photos to expenses"
224
+
225
+ ❌ "Notifications" permission with no context
226
+
227
+ ✅ Request at the right moment + explain:
228
+ "Get notified when teammates comment on your tasks"
229
+ [Allow] [Not now]
230
+ ```
231
+
232
+ Common permission descriptions:
233
+ | Permission | Bad | Good |
234
+ |------------|-----|------|
235
+ | Camera | "Access camera" | "Scan QR codes to join a workspace" |
236
+ | Location | "Use your location" | "Show nearby team members on the map" |
237
+ | Contacts | "Access contacts" | "Invite teammates by name instead of email" |
238
+ | Notifications | "Send notifications" | "Alert you when your order ships" |
239
+ | Microphone | "Access microphone" | "Record voice notes on tasks" |
240
+
241
+ ---
242
+
243
+ ## Rating Prompt Copy
244
+
245
+ ```
246
+ ❌ AI default:
247
+ "Are you enjoying [App Name]? Rate us 5 stars!"
248
+
249
+ ✅ Human — ask a real question first:
250
+ "Is [App] helping you get things done?"
251
+ [Yes!] [Not really]
252
+
253
+ If Yes → "Mind leaving a review? It helps us a lot."
254
+ [Sure] [Maybe later]
255
+ If No → "What's getting in the way?"
256
+ [Give feedback]
257
+ ```
258
+
259
+ ---
260
+
261
+ ## Subscription & Paywall Copy
262
+
263
+ ```
264
+ ❌ AI:
265
+ "Unlock the full potential of our comprehensive premium features
266
+ to seamlessly enhance your productivity experience."
267
+
268
+ ✅ Human — state what unlocks:
269
+ "Go Pro
270
+ • Unlimited projects (free plan: 3)
271
+ • Team sharing
272
+ • Priority support"
273
+ [Start 7-day free trial]
274
+ [See what's included]
275
+
276
+ ❌ CTA: "Subscribe Now" / "Upgrade Today" / "Get Premium"
277
+ ✅ CTA: "Start free trial" / "Unlock [specific feature]" / "Try Pro free"
278
+
279
+ ❌ After trial ends: "Your trial has expired. Please subscribe to continue."
280
+ ✅ "Your free trial ended. Pick a plan to keep your 12 projects."
281
+ ```
282
+
283
+ ---
284
+
285
+ ## Word Blacklist (delete on sight)
286
+
287
+ ```
288
+ seamlessly / robust / powerful / comprehensive / intuitive / streamline /
289
+ leverage / utilize / cutting-edge / state-of-the-art / innovative /
290
+ revolutionary / game-changing / transformative / holistic / synergy /
291
+ delve / Furthermore / Additionally / Moreover / In conclusion /
292
+ It is worth noting / Please note that / Feel free to /
293
+ experience the difference / take your [X] to the next level /
294
+ designed with you in mind / your one-stop solution
295
+ ```