flvm 0.0.2
flvm: ^0.0.2 copied to clipboard
flvm mvvm package extension
flvm based on Flutter Architecture case study and Compass App example.
Additionally added base classes to aviod boilerplate code and improved error handlings.
Basic usage #
Create a View Model:
class MyViewModel extends FlVm {
Don`t forget to call notifyListeners() when you need to deliver updated:
void increment() {
_counter++;
notifyListeners();
}
Inherit your widget state from FlVmState:
class _MyScreenState extends
FlVmWidget<MainScreen, MyViewModel> {
Bind your View Model:
@override
MyViewModel bindViewModel() => MyViewModel();
Use viewModelBuilder to listen for View Model updates:
viewModelBuilder<MainViewModel>(
builder: (context, vm) {
return Text(
'${vm.counter}',
style: Theme.of(context).textTheme.headlineMedium,
);
},
),
Advanced setup #
Error handling #
Additionally use can use onError function to handle errors you emit in View Model.
Add onError function to your widget state class:
void onError(Exception error) {
super.onError(error);
//show error dialog here
}
Call setError in your View Model to emit an error:
setError(Exception('Ooops...'));
Commands #
Create a new Command in your View Model:
late Command1 login;
...
login = Command1<void, (String username, String password)>(
_login,
onError: _onCommandError, //optional
);
Create body function for your Command:
Future<Result<void>> _login((String, String) credentials) async {
await Future.delayed(const Duration(milliseconds: 500));
return Result.ok(null);
}
Also you can set optional onError param to handle Command errors and deliver them to UI using setError:
onError: _onCommandError,
void _onCommandError(Exception error) {
setError(error);
}
In your Widget execute command where you need:
viewModel.login.execute((
_usernameController.text,
_passwordController.text,
));
Use commandBuilder to handle Command state in widget tree:
commandBuilder<void>(
command: viewModel.login,
builder: (context, command) {
return ElevatedButton(
onPressed: _onLogin,
child: command.running
? const CircularProgressIndicator()
: Text('LOGIN'),
);
},
),
Use listener to listen to command updates outside the widget tree:
@override
void onVmInitialized() {
super.onVmInitialized();
viewModel.login.addListener(_onLoginResult);
}
@override
void didUpdateWidget(covariant LoginScreen oldWidget) {
super.didUpdateWidget(oldWidget);
viewModel.login.updateListener(_onLoginResult);
}
@override
void dispose() {
super.dispose();
viewModel.login.removeListener(_onLoginResult);
}
void _onLoginResult() {
if (viewModel.login.isOk) {
viewModel.login.clearResult();
Navigator.of(
context,
).pushReplacement(MaterialPageRoute(builder: (context) => MainScreen()));
}
///on error do nothing
}