Architectural solution for Flutter apps Inspired from Bloc pattern
Features
More flexibility than Bloc pattern Simple to use Easy to test Easy to maintain
Getting started
in order to use this package fully you need to install the following packages:
sealed_class_annotations sealed_class_generator
Usage
create your model class like following:
import 'package:sealed_class_annotations/sealed_class_annotations.dart';
part 'signin_ui_state.sealed.dart';
@Sealed()
abstract class _SignInUIState {
void showContent(
bool isSignIn,
bool isLoading,
String? errorMessage,
);
}
@Sealed()
abstract class _SignInUIAction {
void showResetPasswordDialog();
}
then create your delegate class like following:
class SignInUiDelegate extends UIDelegate<SignInUIState, SignInUIAction> {
bool _isSignIn = true;
bool _isLoading = false;
SignInUiDelegate(this.authenticationApiHandler);
void init() {
_updateTheUi();
}
void tabSwitched(int index) {
_isSignIn = index == 0;
_updateTheUi();
}
void _updateTheUi({String? errorMessage}) {
add(
SignInUIState.showContent(
isSignIn: _isSignIn,
isLoading: _isLoading,
errorMessage: errorMessage,
),
);
}
void resetPasswordPressed() {
addAction(const SignInUIAction.showResetPasswordDialog());
}
Future<String> resetPassword(String email) {
return authenticationApiHandler.resetEmail(email);
}
void signInSignupButtonPressed({
required String email,
required String password,
}) {
_isLoading = true;
_updateTheUi();
if (_isSignIn) {
authenticationApiHandler
.signinViaEmail(
email: email,
password: password,
)
.then((value) {
_isLoading = false;
AppNavigation.openHome();
}).onError((error, stackTrace) {
debugPrint(error.toString());
_isLoading = false;
_updateTheUi(errorMessage: "login failed!");
});
} else {
authenticationApiHandler
.signupViaEmail(
email: email,
password: password,
)
.then((value) {
_isLoading = false;
AppNavigation.openHome();
}).onError((error, stackTrace) {
debugPrint(error.toString());
_isLoading = false;
_updateTheUi(errorMessage: "signup failed!");
});
}
}
}
And in your UI class you can use it like following:
@override
void initState() {
super.initState();
widget.delegate.init();
widget.delegate.uiActions().listen((event) {
event.when(
showResetPasswordDialog: () => // show reset password dialog widget,
);
});
}
@override
void dispose() {
_controller.dispose();
widget.delegate.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return widget.delegate.getBuilder(
builder: (uiState) => uiState.when(
showContent: (isSignIn, isLoading, errorMessage) =>
_buildContent(
isSignIn,
isLoading,
errorMessage,
).padding(horizontal: 16, vertical: 16),
),
)
}