A Flutter boilerplate example which logins to a REST server with i18n, theming, persistence and state management.
-
State management by Flutter Mediator Persistence , a super easy state management package with built in persistence capability by using shared_preferences.
-
i18n by Flutter_i18n
-
REST api by http, a composable, Future-based library for making HTTP requests.
-
REST server at reqres.in, login with account:
eve.holt@reqres.in
, password iscityslicka
.
dependencies:
flutter_i18n: ^0.22.3
flutter_mediator_persistence: ^1.0.1
http:
# ...
flutter:
# ...
assets:
- assets/flutter_i18n/
Step 2. Import these packages in main.dart
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:flutter_i18n/loaders/decoders/json_decode_strategy.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_mediator_persistence/mediator.dart';
Future<void> main() async {
await initGlobalPersist();
runApp(
globalHost(child: MyApp()),
);
}
Step 4. Import var.dart in the pages (with show/hide)
import '/var.dart' show locale;
import '/var.dart' hide locale;
Step 1. Declare the persistent watched variable in var.dart
//* Declare the persistent watched variable with `defaultVal.globalPersist('key')`
final themeIdx = 1.globalPersist('themeIdx');
Step 2. Prepare the themeData
in theme.dart
Step 3. Create consume widget in main.dart
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
//* Create a widget with `globalConsume` or `watchedVar.consume`
//* to register the watched variable to the host to rebuild it when updating.
//* `watchedVar.consume()` is a helper function to
//* `touch()` itself first and then `globalConsume`.
return themeIdx.consume( // create consume widget
() => MaterialApp(
// ...
theme: themeData(themeIdx.value), // set the themeData
Step 4. Implement a update function (in var.dart)
/// Change the theme, by ThememData `int` [idx]
void changeTheme(int idx) {
idx = idx.clamp(0, 1);
if (idx != themeIdx.value) {
themeIdx.value = idx; // will rebuild the registered consume widget
}
}
Step 1-1. Declare the persistent watched variable in var.dart
const DefaultLocale = 'en';
//* Declare the persistent watched variable with `defaultVal.globalPersist('key')`
final locale = DefaultLocale.globalPersist('locale');
Step 1-2 (optional). Write a String extension for i18n (in var.dart).
extension StringI18n on String {
/// String extension for i18n.
String i18n(BuildContext context) {
return FlutterI18n.translate(context, this);
}
/// String extension for i18n and `locale.consume` the widget
/// to create consume widget for the state management.
Widget ci18n(BuildContext context, {TextStyle? style}) {
return locale.consume(
() => Text(FlutterI18n.translate(context, this), style: style),
);
}
}
Step 2. Prepare the locale files in assets/flutter_i18n/
Step 3. Create consume widget that needs to do i18n (in lib/pages/locale_page.dart).
locale.consume(() => Text('${'app.hello'.i18n(context)} ')),
Or use the ci18n
extension (in lib/pages/login_page.dart).
'login.title'.ci18n(
context,
style: Theme.of(context).textTheme.headline2,
),
Step 4. Implement a update function (in var.dart)
/// Change the locale, by `String`[countryCode]
Future<void> changeLocale(BuildContext context, String countryCode) async {
if (countryCode != locale.value) {
final loc = Locale(countryCode);
await FlutterI18n.refresh(context, loc);
//* Step4: Make an update to the watched variable.
//* The persistent watched variable will update the persistent value automatically.
locale.value = countryCode; // will rebuild the registered consume widget
}
}
//* Declare the persistent watched variable with `defaultVal.globalPersist('key')`
final scrollOffset = 0.0.globalPersist('ScrollOffsetDemo');
class _ScrollPageState extends State<ScrollPage> {
//* Initialize the scroll offset with the persistent value.
final _scrollController =
ScrollController(initialScrollOffset: scrollOffset.value);
@override
void initState() {
_scrollController.addListener(() {
//* Make an update to the watched variable.
scrollOffset.value = _scrollController.offset;
});
super.initState();
}
class CustomAppBar extends StatelessWidget {
const CustomAppBar({required this.header, Key? key}) : super(key: key);
final Widget header;
@override
Widget build(BuildContext context) {
//* Step3: Create a consume widget with
//* `globalConsume` or `watchedVar.consume` to register the
//* watched variable to the host to rebuild it when updating.
return globalConsume(
() => Container(
// ...
color: Colors.black
.withOpacity((scrollOffset.value / 350).clamp(0, 1).toDouble()),
child: header,
),
);
}
}