Appearance
Part 1: Packages and Setup
This guide uses the same local-first mindset as Linkbox: local database first, background sync second, UI always reactive.
Install Packages First
yaml
dependencies:
flutter:
sdk: flutter
flutter_riverpod: ^2.6.1
riverpod_annotation: ^2.6.1
isar: ^3.1.0+1
isar_flutter_libs: ^3.1.0+1
path_provider: ^2.1.5
connectivity_plus: ^6.1.0
dio: ^5.7.0
uuid: ^4.5.1
intl: ^0.19.0
freezed_annotation: ^2.4.4
json_annotation: ^4.9.0
dev_dependencies:
build_runner: ^2.4.14
isar_generator: ^3.1.0+1
riverpod_generator: ^2.6.3
freezed: ^2.5.7
json_serializable: ^6.9.0Then run:
bash
flutter pub get
flutter pub run build_runner build --delete-conflicting-outputsBootstrap App (main.dart)
dart
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await initializeIsar();
runApp(
const ProviderScope(
child: ExpenseTrackerApp(),
),
);
}Initialize Isar Once
dart
late Isar isar;
Future<void> initializeIsar() async {
final dir = await getApplicationDocumentsDirectory();
isar = await Isar.open(
[ExpenseLocalSchema, SyncTaskLocalSchema],
directory: dir.path,
inspector: true,
);
}Why this setup works in production
- Isar gives fast local reads and writes.
- Riverpod gives predictable state and testability.
- Connectivity stream helps orchestrate sync timing.
- Code generation keeps models clean and typed.