architecture 0.0.9 copy "architecture: ^0.0.9" to clipboard
architecture: ^0.0.9 copied to clipboard

An Architectural solution for Flutter

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),
        ),
        )
  }