-
Notifications
You must be signed in to change notification settings - Fork 0
Architecture
aiserrock edited this page Jul 8, 2026
·
1 revision
-
flutter_blocCubit per screen/feature, no rawBloc/events (exceptOnboardingBloc, a legacy holdout). - Screen state is (or embeds) a sealed
DataState<T>(lib/util/data_state.dart):DataLoading<T>,DataContent<T>,DataError<T>. Immutable,Equatable-based, exhaustiveswitch. -
DataStateBuilder<T>renders one ofloader/builder/errorBuilderfor a givenDataState<T>.DataStateConsumerwraps it in aBlocBuilderfor one-liner screens. -
safeEmit(lib/util/bloc_ext.dart, extension onCubit<S>) guardsemitafterawait: if the Cubit is alreadyclosed(screen popped mid-request), it's a no-op instead of throwingStateError. UsesafeEmitin every async Cubit method, never rawemitafter anawait. - Composite states use
copyWithon a state class holding multipleDataState<T>fields (e.g.animal,prescriptionsloaded independently) rather than oneDataStatefor the whole screen.
-
go_router, singleGoRouterbuilt bycreateAppRouter()(lib/navigation/app_router.dart) and registered as a singleton in DI — not a service/interface wrapper. -
AppRoutes(abstract final class) holds path string constants plus smallxPath(...)helpers for parameterized routes (path params/query params over passing raw objects where possible). - Complex non-primitive payloads go through
extra, encoded/decoded byAppExtraCodec(lib/navigation/extra_codec.dart,GoRouter.extraCodec). Primitives andList/Map<String, Object?>pass through as-is; anything else is swapped for a one-time token backed by an in-memory store, so the Inspector/devtools never try to serialize live objects (models, callbacks). Tokens are consumed exactly once on decode — don't rely onextrasurviving a rebuild/replay. - Screens returning a result use
context.push<T>()/context.pop(result); auth flow (login → pick shelter → root) navigates explicitly viago/pushrather than router redirects, since it's multi-step.
-
get_it+injectable, code-generated (di_container.config.dartvia@InjectableInit). -
initDi()(lib/di/di_container.dart) is awaited first thing inmain(), beforerunApp. It runs$initGetIt(env filter: prod unless annotated otherwise), then manually registers singletons that don't fit codegen: navigator/scaffold-messengerGlobalKeys and theGoRouterfromcreateAppRouter(). -
Cubits are never registered in
get_it. They're constructed directly and handed to aBlocProvider(create: (_) => XCubit(...))at the screen/route level, scoped to that widget's lifetime. - Services, repositories, Dio/Chopper clients, storage wrappers are
@injectable/@singleton/@module-annotated and pulled viagetIt<T>()or constructor injection into Cubits.
-
Chopper(HTTP client codegen) on top ofDio(actual transport, interceptors, timeouts). - All API models/clients under
lib/api/(openapi.swagger.dart,openapi.enums.swagger.dart,*.swagger.chopper.dart,*.swagger.g.dart) are generated byswagger_dart_code_generatorfrom an OpenAPI spec placed indoc/api/. Never hand-edit generated files. - The generator is currently
enabled: falseinbuild.yamlbecause no spec is checked intodoc/api/— generated output is committed as-is. Drop a spec indoc/api/and flip the flag to regenerate. - Hand-written DTOs (non-API) use
@JsonSerializablewith apart '<name>.g.dart';. -
Dioinstance is built inDioRegister(lib/service/client/dio_register.dart,@module, timeouts only); auth/header behavior lives in separate interceptors (auth_interceptor.dart,header_inteceptor.dart) andauth_client_register.dartwires the authenticated Chopper client.
-
flutter_secure_storagefor sensitive data (tokens), wrapped viaSecureStorageRegister(lib/service/secure_storage/,@module), a memoized singletonFlutterSecureStorage. iOSKeychainAccessibility.first_unlockexplicitly set; Android encrypts at rest by default. -
shared_preferencesfor plain app prefs, provided bySharedPreferenceRegister(@module,@preResolvesinceSharedPreferences.getInstance()is async) and consumed through a thin typed wrapper,PreferenceStorage(lib/service/shared_pref/preference_storage.dart) — e.g.isFirstLaunch. Don't reach forSharedPreferences/FlutterSecureStoragedirectly from feature code; go through thelib/service/wrapper.