Dart and Flutter
Section titled “Dart and Flutter”NAHPU follows standard Dart style guidelines. Use dart format and keep changes consistent with nearby code.
- Use
snake_case.dartfor file names. - Use
PascalCasefor classes and widgets. - Prefer
constconstructors whenever possible. - Prefer
finalfor variables assigned once. - Keep screens as thin UI wrappers.
- Put business logic in
lib/services/. - Put reusable UI in
lib/screens/shared/. - Keep
buildmethods side-effect free. - Guard async UI updates with
context.mounted. - Use theme values instead of hard-coded colors when styling UI.
// Preferredconst Text('Hello, NAHPU!');
// AvoidText('Hello, NAHPU!');Riverpod
Section titled “Riverpod”Use Riverpod providers for state. For database-backed state, prefer AsyncNotifierProvider because it represents loading, error, and data states explicitly.
@riverpodclass SpecimenListNotifier extends _$SpecimenListNotifier { @override Future<List<Specimen>> build() async { return ref.read(databaseProvider).getAllSpecimens(); }
Future<void> addSpecimen(Specimen specimen) async { state = const AsyncLoading(); state = await AsyncValue.guard(() async { await ref.read(databaseProvider).insertSpecimen(specimen); return ref.read(databaseProvider).getAllSpecimens(); }); }}Handle async states explicitly in widgets.
final specimens = ref.watch(specimenListNotifierProvider);
return specimens.when( data: (data) => SpecimenListView(specimens: data), loading: () => const CircularProgressIndicator(), error: (error, _) => Text('Error: $error'),);Prefer ConsumerWidget or ConsumerStatefulWidget over passing WidgetRef through constructors. Use ref.watch when UI should rebuild. Use ref.read inside callbacks where no rebuild is needed.
Rust wrapper code
Section titled “Rust wrapper code”The app's Rust code is a bridge wrapper. Core Rust behavior should live in the NAHPU API crates.
- Use
snake_casefor functions and variables. - Use
PascalCasefor types, traits, and enums. - Use
SCREAMING_SNAKE_CASEfor constants. - Prefer
Result<T, E>over panics. - Use
?, pattern matching, and references instead of unnecessary clones. - Avoid
.unwrap()unless it is justified by a local invariant. - Put public methods first in
implblocks and private helpers last. - Document public bridge-facing functions with
///.
pub fn parse_specimen(data: &str) -> Result<Specimen, ParseError> { data.parse()}Add focused tests close to the behavior you changed. The Data import and export pages contain workflow-specific round-trip, compatibility, archive, migration, and PDF test checklists.
- Use service tests for import/export, persistence, validation, and migrations. Follow the Persistence data page for storage ownership, schema and migration rules, and mapping expectations.
- Use widget tests for UI regressions.
- Run integration tests for startup, navigation, IO, or bridge changes.
flutter testflutter analyzepython scripts.py frb --check