Chuyển đến nội dung chính

Bài đăng

Rive: interactive vector animation as a state machine

Rive: interactive vector animation as a state machine rive is useful because it focuses on artboards, state machines, inputs, and runtime performance. The important engineering move is to place the package behind a clear boundary, so your Flutter UI depends on a stable capability rather than a vendor-shaped API. What the library should own Keep package calls inside a named adapter or feature boundary. Make lifecycle, errors, and loading state part of a testable contract. Expose only the capability the app needs; hide implementation details from the whole tree. A focused starting point final controller = StateMachineController . fromArtboard ( artboard, 'LoginMachine' , ); if (controller != null ) { artboard. addController (controller); final success = controller. findInput < bool >( 'success' ); success ? .value = true ; } Production checklist Read the README and changelog for the exact version you pin. Add one test for life...
Các bài đăng gần đây

Pigeon: typed platform channels generated from one schema

Pigeon: typed platform channels generated from one schema pigeon is useful because it focuses on Dart/native codegen, API contracts, task queues, and versioning. The important engineering move is to place the package behind a clear boundary, so your Flutter UI depends on a stable capability rather than a vendor-shaped API. What the library should own Keep package calls inside a named adapter or feature boundary. Make lifecycle, errors, and loading state part of a testable contract. Expose only the capability the app needs; hide implementation details from the whole tree. A focused starting point @HostApi () abstract class SecureBiometrics { bool isAvailable (); @async bool authenticate ( String reason); } // dart run pigeon --input pigeons/biometrics.dart Production checklist Read the README and changelog for the exact version you pin. Add one test for lifecycle, failure, and app background/foreground behavior. Verify every platform your product suppo...

permission_handler: runtime permission flows you can explain

permission_handler: runtime permission flows you can explain permission_handler is useful because it focuses on status, rationale, settings fallback, and platform declarations. The important engineering move is to place the package behind a clear boundary, so your Flutter UI depends on a stable capability rather than a vendor-shaped API. What the library should own Keep package calls inside a named adapter or feature boundary. Make lifecycle, errors, and loading state part of a testable contract. Expose only the capability the app needs; hide implementation details from the whole tree. A focused starting point final status = await Permission .camera. request (); if (status.isGranted) { openCamera (); } else if (status.isPermanentlyDenied) { await openAppSettings (); } Production checklist Read the README and changelog for the exact version you pin. Add one test for lifecycle, failure, and app background/foreground behavior. Verify every platform your pro...

Patrol: integration tests that can leave the Flutter sandbox

Patrol: integration tests that can leave the Flutter sandbox patrol is useful because it focuses on native permissions, notifications, deep links, and device automation. The important engineering move is to place the package behind a clear boundary, so your Flutter UI depends on a stable capability rather than a vendor-shaped API. What the library should own Keep package calls inside a named adapter or feature boundary. Make lifecycle, errors, and loading state part of a testable contract. Expose only the capability the app needs; hide implementation details from the whole tree. A focused starting point patrolTest ( 'camera permission flow' , ($) async { await $. native . grantPermissionWhenInUse (); await $. pumpWidgetAndSettle ( const CameraApp ()); await $(#takePhoto). tap (); expect (find. byType ( PhotoPreview ), findsOneWidget); }); Production checklist Read the README and changelog for the exact version you pin. Add one test for lifecycle...

Mocktail: readable Dart mocks without generated files

Mocktail: readable Dart mocks without generated files mocktail is useful because it focuses on fakes, stubbing, verification, fallback values, and test boundaries. The important engineering move is to place the package behind a clear boundary, so your Flutter UI depends on a stable capability rather than a vendor-shaped API. What the library should own Keep package calls inside a named adapter or feature boundary. Make lifecycle, errors, and loading state part of a testable contract. Expose only the capability the app needs; hide implementation details from the whole tree. A focused starting point class MockUserApi extends Mock implements UserApi {} final api = MockUserApi (); when (() => api. fetchUser ( '42' )). thenAnswer ((_) async => user); final result = await repository. load ( '42' ); verify (() => api. fetchUser ( '42' )). called ( 1 ); Production checklist Read the README and changelog for the exact version yo...

Melos: make a Flutter monorepo a product boundary

Melos: make a Flutter monorepo a product boundary melos is useful because it focuses on workspace scripts, package graph, selective tests, and releases. The important engineering move is to place the package behind a clear boundary, so your Flutter UI depends on a stable capability rather than a vendor-shaped API. What the library should own Keep package calls inside a named adapter or feature boundary. Make lifecycle, errors, and loading state part of a testable contract. Expose only the capability the app needs; hide implementation details from the whole tree. A focused starting point name : flutter_workspace packages : - apps /** - packages/** scripts: analyze: melos exec -- flutter analyze test: melos exec --fail-fast -- flutter test changed: melos exec --since=main -- flutter test Production checklist Read the README and changelog for the exact version you pin. Add one test for lifecycle, failure, and app background/foreground behavior. Verify e...

local_auth: biometrics as a step-up, not a password store

local_auth: biometrics as a step-up, not a password store local_auth is useful because it focuses on device support, biometric prompts, fallback credentials, and failure UX. The important engineering move is to place the package behind a clear boundary, so your Flutter UI depends on a stable capability rather than a vendor-shaped API. What the library should own Keep package calls inside a named adapter or feature boundary. Make lifecycle, errors, and loading state part of a testable contract. Expose only the capability the app needs; hide implementation details from the whole tree. A focused starting point final auth = LocalAuthentication (); final supported = await auth. isDeviceSupported (); if (supported) { final ok = await auth. authenticate ( localizedReason : 'Unlock your saved account' , options : const AuthenticationOptions (biometricOnly : false ), ); if (ok) unlock (); } Production checklist Read the README and change...

just_audio: controllable audio with streams

just_audio: controllable audio with streams just_audio is useful because it focuses on queues, position streams, playlists, speed, and background integration. The important engineering move is to place the package behind a clear boundary, so your Flutter UI depends on a stable capability rather than a vendor-shaped API. What the library should own Keep package calls inside a named adapter or feature boundary. Make lifecycle, errors, and loading state part of a testable contract. Expose only the capability the app needs; hide implementation details from the whole tree. A focused starting point final player = AudioPlayer (); await player. setAudioSource ( ConcatenatingAudioSource (children : [ AudioSource . uri ( Uri . parse (trackUrl)), ]), ); player. play (); player.positionStream. listen (updateProgress); Production checklist Read the README and changelog for the exact version you pin. Add one test for lifecycle, failure, and app background/foreground...

json_serializable: boring JSON that survives refactors

json_serializable: boring JSON that survives refactors json_serializable is useful because it focuses on generated codecs, converters, checked mode, and API model boundaries. The important engineering move is to place the package behind a clear boundary, so your Flutter UI depends on a stable capability rather than a vendor-shaped API. What the library should own Keep package calls inside a named adapter or feature boundary. Make lifecycle, errors, and loading state part of a testable contract. Expose only the capability the app needs; hide implementation details from the whole tree. A focused starting point @JsonSerializable () class User { const User ({ required this .id, required this .displayName}); final String id; final String displayName; factory User . fromJson ( Map < String , dynamic > json) => _$UserFromJson (json); Map < String , dynamic > toJson () => _$UserToJson ( this ); } Production checklist Read the README ...

Isar: fast local objects with queryable indexes

Isar: fast local objects with queryable indexes isar is useful because it focuses on collections, indexes, transactions, and reactive watchers. The important engineering move is to place the package behind a clear boundary, so your Flutter UI depends on a stable capability rather than a vendor-shaped API. What the library should own Keep package calls inside a named adapter or feature boundary. Make lifecycle, errors, and loading state part of a testable contract. Expose only the capability the app needs; hide implementation details from the whole tree. A focused starting point @collection class Note { Id id = Isar .autoIncrement; late String title; @Index () late DateTime updatedAt; } await isar. writeTxn (() async { await isar.notes. put (note); }); Production checklist Read the README and changelog for the exact version you pin. Add one test for lifecycle, failure, and app background/foreground behavior. Verify every platform your produ...

intl: format locale-sensitive data deliberately

intl: format locale-sensitive data deliberately intl is useful because it focuses on dates, numbers, plurals, locale initialization, and testable formats. The important engineering move is to place the package behind a clear boundary, so your Flutter UI depends on a stable capability rather than a vendor-shaped API. What the library should own Keep package calls inside a named adapter or feature boundary. Make lifecycle, errors, and loading state part of a testable contract. Expose only the capability the app needs; hide implementation details from the whole tree. A focused starting point final amount = NumberFormat . currency ( locale : 'vi_VN' , symbol : '₫' , ). format ( 1250000 ); final date = DateFormat . yMMMMd ( 'en_US' ). format (order.createdAt); Production checklist Read the README and changelog for the exact version you pin. Add one test for lifecycle, failure, and app background/foreground behavior. Verify every platform...

image_picker: a small API over messy media sources

image_picker: a small API over messy media sources image_picker is useful because it focuses on camera/gallery intent, lost data recovery, compression, and permissions. The important engineering move is to place the package behind a clear boundary, so your Flutter UI depends on a stable capability rather than a vendor-shaped API. What the library should own Keep package calls inside a named adapter or feature boundary. Make lifecycle, errors, and loading state part of a testable contract. Expose only the capability the app needs; hide implementation details from the whole tree. A focused starting point final picker = ImagePicker (); final image = await picker. pickImage ( source : ImageSource .gallery, maxWidth : 2000 , imageQuality : 85 , ); if (image != null ) upload ( await image. readAsBytes ()); Production checklist Read the README and changelog for the exact version you pin. Add one test for lifecycle, failure, and app background/foreground b...

Golden Toolkit: visual regression with intent

Golden Toolkit: visual regression with intent golden_toolkit is useful because it focuses on device matrices, fonts, surface variants, and readable golden diffs. The important engineering move is to place the package behind a clear boundary, so your Flutter UI depends on a stable capability rather than a vendor-shaped API. What the library should own Keep package calls inside a named adapter or feature boundary. Make lifecycle, errors, and loading state part of a testable contract. Expose only the capability the app needs; hide implementation details from the whole tree. A focused starting point testGoldens ( 'profile variants' , (tester) async { await loadAppFonts (); await tester. pumpWidgetBuilder ( const ProfileCard ()); await screenMatchesGolden (tester, 'profile-card' ); }); Production checklist Read the README and changelog for the exact version you pin. Add one test for lifecycle, failure, and app background/foreground behavior. Ve...

go_router: URL-first navigation for Flutter

go_router: URL-first navigation for Flutter go_router is useful because it focuses on declarative routing, deep links, redirects, and ShellRoute. The important engineering move is to place the package behind a clear boundary, so your Flutter UI depends on a stable capability rather than a vendor-shaped API. What the library should own Keep package calls inside a named adapter or feature boundary. Make lifecycle, errors, and loading state part of a testable contract. Expose only the capability the app needs; hide implementation details from the whole tree. A focused starting point final router = GoRouter ( redirect : (context, state) => isSignedIn || state.uri.path == '/login' ? null : '/login' , routes : [ GoRoute (path : '/' , builder : (_, __) => const HomePage ()), GoRoute (path : '/orders/:id' , builder : (_, state) => OrderPage (id : state.pathParameters[ 'id' ] ! )),...

Brand refreshes without breaking mobile users — hướng dẫn Flutter

Rebrands are migrations. Stage them. Bài này chuyển quan sát đó thành một mô hình nhỏ để bạn có thể kiểm thử, đo lường và giữ cho code dễ bảo trì khi app lớn lên. Vấn đề cốt lõi Token stages, co-existing themes, and migration UX. Câu hỏi hữu ích không phải API hay pattern có đẹp riêng lẻ hay không, mà là state nằm ở đâu, boundary nào chịu trách nhiệm khi lỗi xảy ra, và người dùng phục hồi thế nào khi happy path biến mất. Mô hình thực tế Support old/new themes behind a flag for one release. Hãy bắt đầu bằng một owner rõ ràng cho behavior. Widget chỉ nên render và phát intent; IO, persistence, permission và retry nên nằm sau một interface nhỏ. Nhờ vậy bạn có seam để fake trong test và một chỗ ghi lại các dữ kiện cần theo dõi ở production. Trong app Flutter, boundary thường có dạng: Widget phát intent như load, submit, refresh hoặc retry. Controller hoặc use case validate intent rồi gọi boundary. Boundary trả về data có kiểu hoặc failure có kiểu, không trả string chỉ dành cho l...

User safety features: block, mute, and restrict — hướng dẫn Flutter

Safety controls must affect ranking, DMs, and pushes. Bài này chuyển quan sát đó thành một mô hình nhỏ để bạn có thể kiểm thử, đo lường và giữ cho code dễ bảo trì khi app lớn lên. Vấn đề cốt lõi Graph-level enforcement and push suppression. Câu hỏi hữu ích không phải API hay pattern có đẹp riêng lẻ hay không, mà là state nằm ở đâu, boundary nào chịu trách nhiệm khi lỗi xảy ra, và người dùng phục hồi thế nào khi happy path biến mất. Mô hình thực tế Partial blocks create harassment loopholes. Hãy bắt đầu bằng một owner rõ ràng cho behavior. Widget chỉ nên render và phát intent; IO, persistence, permission và retry nên nằm sau một interface nhỏ. Nhờ vậy bạn có seam để fake trong test và một chỗ ghi lại các dữ kiện cần theo dõi ở production. Trong app Flutter, boundary thường có dạng: Widget phát intent như load, submit, refresh hoặc retry. Controller hoặc use case validate intent rồi gọi boundary. Boundary trả về data có kiểu hoặc failure có kiểu, không trả string chỉ dành cho ...

Step-up authentication with biometrics for sensitive actions — hướng dẫn Flutter

Session age is not enough for destructive actions. Bài này chuyển quan sát đó thành một mô hình nhỏ để bạn có thể kiểm thử, đo lường và giữ cho code dễ bảo trì khi app lớn lên. Vấn đề cốt lõi Re-auth for payments, exports, and settings changes. Câu hỏi hữu ích không phải API hay pattern có đẹp riêng lẻ hay không, mà là state nằm ở đâu, boundary nào chịu trách nhiệm khi lỗi xảy ra, và người dùng phục hồi thế nào khi happy path biến mất. Mô hình thực tế Re-auth before export, payment, and account deletion. Hãy bắt đầu bằng một owner rõ ràng cho behavior. Widget chỉ nên render và phát intent; IO, persistence, permission và retry nên nằm sau một interface nhỏ. Nhờ vậy bạn có seam để fake trong test và một chỗ ghi lại các dữ kiện cần theo dõi ở production. Trong app Flutter, boundary thường có dạng: Widget phát intent như load, submit, refresh hoặc retry. Controller hoặc use case validate intent rồi gọi boundary. Boundary trả về data có kiểu hoặc failure có kiểu, không trả string...

Brand refreshes without breaking mobile users

Rebrands are migrations. Stage them. This article turns that observation into a small implementation model you can test, measure, and keep boring when the app grows. The problem in one sentence Token stages, co-existing themes, and migration UX. The useful question is not whether the API or pattern looks elegant in isolation. It is where state lives, which boundary owns failure, and how a user recovers when the happy path disappears. A practical model Support old/new themes behind a flag for one release. Start with one explicit owner for the behavior. Keep widgets responsible for rendering and user intent; keep IO, persistence, permissions, and retries behind a small interface. That gives you a seam for a fake in tests and a place to record the facts that matter in production. For a Flutter app, the boundary usually looks like this: The widget emits an intent such as load, submit, refresh, or retry. A controller or use case validates the intent and calls the boundary. The bo...