Last active
January 7, 2025 13:07
-
-
Save sheerazam/0b52f51633f994941593627ee4405206 to your computer and use it in GitHub Desktop.
Flutter MVI
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// Try running this code using DartPad: https://dartpad.dev/531149f182c1c2e340652281e4ca01ec | |
import 'package:flutter/material.dart'; | |
import 'package:provider/provider.dart'; | |
/// Model | |
class AppState { | |
final int counter; | |
final bool isLoading; | |
final String? error; | |
AppState({ | |
required this.counter, | |
this.isLoading = false, | |
this.error, | |
}); | |
AppState copyWith({ | |
int? counter, | |
bool? isLoading, | |
String? error, | |
}) { | |
return AppState( | |
counter: counter ?? this.counter, | |
isLoading: isLoading ?? this.isLoading, | |
error: error, | |
); | |
} | |
} | |
/// View Model | |
class AppViewModel extends ChangeNotifier { | |
AppState _state = AppState(counter: 0); | |
AppState get state => _state; | |
IncrementCounterUseCase incUseCase = IncrementCounterUseCase(); | |
DecrementCounterUseCase decUseCase = DecrementCounterUseCase(); | |
void incrementCounter() { | |
var updatedCounter = incUseCase.updateCounter(_state.counter); | |
_state = _state.copyWith(counter: updatedCounter); | |
notifyListeners(); | |
} | |
void decrementCounter() { | |
var updatedCounter = decUseCase.updateCounter(_state.counter); | |
_state = _state.copyWith(counter: updatedCounter); | |
notifyListeners(); | |
} | |
} | |
class IncrementCounterUseCase { | |
int updateCounter(int counter) { | |
return counter + 1; | |
} | |
} | |
class DecrementCounterUseCase { | |
int updateCounter(int counter) { | |
return counter - 1; | |
} | |
} | |
/// View | |
class AppView extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar( | |
title: Text('Flutter MVI Example'), | |
), | |
body: Center( | |
// Note: Consumer widget of Provider State Management | |
child: Consumer<AppViewModel>( | |
builder: (context, viewModel, child) { | |
return Column( | |
mainAxisAlignment: MainAxisAlignment.center, | |
children: [ | |
if (viewModel.state.isLoading) | |
CircularProgressIndicator() | |
else if (viewModel.state.error != null) | |
Text('Error: ${viewModel.state.error}') | |
else | |
Text( | |
'Counter: ${viewModel.state.counter}', | |
style: TextStyle(fontSize: 24), | |
), | |
SizedBox(height: 20), | |
Row( | |
mainAxisAlignment: MainAxisAlignment.center, | |
children: [ | |
ElevatedButton( | |
onPressed: () => viewModel.incrementCounter(), | |
child: Text('Increment'), | |
), | |
SizedBox(width: 10), | |
ElevatedButton( | |
onPressed: () => viewModel.decrementCounter(), | |
child: Text('Decrement'), | |
), | |
], | |
), | |
], | |
); | |
}, | |
), | |
), | |
); | |
} | |
} | |
/// main function | |
void main() { | |
runApp( | |
// Note: Provider widget of Provider State Management | |
ChangeNotifierProvider( | |
create: (context) => AppViewModel(), | |
child: MyApp(), | |
), | |
); | |
} | |
class MyApp extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
home: AppView(), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment