library_architecture_mvvm_modify 0.0.3 copy "library_architecture_mvvm_modify: ^0.0.3" to clipboard
library_architecture_mvvm_modify: ^0.0.3 copied to clipboard

MVVM Modify for Dart but you can also port to another language

Logo Library Architecture MVVM Modify


Overview #

The library is implemented according to the principles of SOLID, and is an example of a clean architecture

Library Architecture MVVM Modify

Examples #

Examples taken for processing from library BLoC.

In the first five examples (Counter,Infinite List,Firebase Login,Github Search,Weather), the file and directory names are all uppercase, but this is not correct, as there are filesystems that are case sensitive, and therefore it is necessary to create .dart files only with lowercase

Applications Todo, program files and directories are written in lowercase, and is also the main example because, the documentation is written based on this example

Documentation #

Documentation based on the Todo app example Todo

Architecture Components #

  • ModelQThereIsStateViewModel

The class that provides the state of the model and the stream can be called IStreamModel, through the as modifier to refer to your class

class NoteQThereIsStateViewModel<T extends Note,Y extends ListNote<T>> 
        extends BaseModelQThereIsStateViewModel<T,Y>
{
  NoteQThereIsStateViewModel(super.iInitializedStreamModel);

  T? get getNote {
    return getModel;
  }

  Y? get getListNote {
    return getListModel;
  }

  Y? get getListNoteUsingCloneListNoteForSuccess {
    return getListModel?.cloneListNoteForSuccess() as Y?;
  }

  set setNote(T note) {
    setModel = note;
  }

  set setListNoteUsingCloneListNoteForSuccess(Y listNote) {
    setListModel = listNote.cloneListNoteForSuccess() as Y?;
  }
}
  • IInitializedStreamModel
///  This class is designed to initialize "StreamModel" and if you need to change the implementation of "StreamModel"
///  you can write another class with this initializer, and later change it in the "ModelQNamedServiceViewModel"
///  component in the constructor to another class
class InitializedStreamNote
    implements IInitializedStreamModel<Note,ListNote>
{
  @override
  IStreamModel<Note,ListNote>? initializedStreamModel() {
    return RXStreamModel<Note,ListNote>(Note.getNoteForSuccess,ListNote.getListNoteForSuccess);
  }
}
  • IStreamModel
/// This class provides access to the model and stream, and resides in the "ModelQThereIsStateModel" class.
/// This class must be implemented, and in the implemented class,
/// the model and stream controllers must be a field and change state if necessary
class RXStreamModel<T extends BaseModel,Y extends BaseListModel<T>>
    implements IStreamModel<T,Y>
{
  final StreamController<T>? _streamControllerForModel;
  final StreamController<Y>? _streamControllerForListModel;
  T? _model;
  Y? _listModel;
  StreamSubscription<T>? _streamSubscriptionForModel;
  StreamSubscription<Y>? _streamSubscriptionForListModel;

  RXStreamModel(this._model,this._listModel)
      : _streamControllerForModel = BehaviorSubject<T>.seeded(_model!),
        _streamControllerForListModel = BehaviorSubject<Y>.seeded(_listModel!);

  @override
  void dispose() {
    _streamSubscriptionForModel?.cancel();
    _streamSubscriptionForListModel?.cancel();
    if(!_streamControllerForModel!.isClosed) {
      _streamControllerForModel?.close();
    }
    if(!_streamControllerForListModel!.isClosed) {
      _streamControllerForListModel?.close();
    }
  }

  @override
  Stream<T?> get getStreamModel => _streamControllerForModel!.stream;

  @override
  Stream<Y?> get getStreamListModel => _streamControllerForListModel!.stream;

  @override
  T? get getModel => _model;

  @override
  Y? get getListModel => _listModel;

  @override
  set setModel(T? model) {
    _model = model;
  }

  @override
  set setListModel(Y? listModel) {
    _listModel = listModel;
  }

  @override
  void notifyStreamModel() {
    if(!_streamControllerForModel!.hasListener) {
      throw LocalException(this,EnumGuiltyForLocalException.developer,"stream has no listener");
    }
    if(_streamControllerForModel!.isClosed) {
      throw LocalException(this,EnumGuiltyForLocalException.developer,"stream closed");
    }
    _streamControllerForModel
        ?.sink
        .add(_model!);
  }

  @override
  void notifyStreamListModel() {
    if(!_streamControllerForListModel!.hasListener) {
      throw LocalException(this,EnumGuiltyForLocalException.developer,"stream has no listener");
    }
    if(_streamControllerForListModel!.isClosed) {
      throw LocalException(this,EnumGuiltyForLocalException.developer,"stream closed");
    }
    _streamControllerForListModel
        ?.sink
        .add(_listModel!);
  }

  void listensStreamModel(
      Function(T event) callback)
  {
    _streamSubscriptionForModel = _streamControllerForModel
        !.stream
        .listen((event) {
          callback(event);
        });
  }

  void listensStreamListModel(
      Function(Y event) callback)
  {
    _streamSubscriptionForListModel = _streamControllerForListModel
        !.stream
        .listen((event) {
          callback(event);
        });
  }

  void resumeStreamSubscriptionForModel() {
    if(!_streamSubscriptionForModel!.isPaused) {
      return;
    }
    _streamSubscriptionForModel?.resume();
  }

  void resumeStreamSubscriptionForListModel() {
    if(!_streamSubscriptionForListModel!.isPaused) {
      return;
    }
    _streamSubscriptionForListModel?.resume();
  }

  void pauseStreamSubscriptionForModel() {
    if(_streamSubscriptionForModel!.isPaused) {
      return;
    }
    _streamSubscriptionForModel?.pause();
  }

  void pauseStreamSubscriptionForListModel() {
    if(_streamSubscriptionForListModel!.isPaused) {
      return;
    }
    _streamSubscriptionForListModel?.pause();
  }
}
  • ModelQNamedServiceViewModel

NoteQSqfliteServiceViewModelUsingGetListNP:

/// This class is necessary for accessing the database,
/// the network (DataSource) and also before accessing the database, the network,
/// check the data and calculate if necessary in (FBDS),
/// also if there is a Stream in the Service,
/// it can pass it for control to the "ModelQThereIsStateViewModel" class if it is necessary
class NoteQSqfliteServiceViewModelUsingGetListNP<T extends Note,Y extends ListNote<T>>
    extends BaseModelQNamedServiceViewModel<T,Y>
    implements GetListModelFromNamedServiceNPDataSource<Y>
{
  @protected
  final sqfliteService = SqfliteService();

  Future<Y?> getListNoteFromSqfliteServiceNP() {
    return super.getListModelFromNamedServiceNP();
  }

  @nonVirtual
  @override
  Object? get modelQNamedServiceDataSource => this;

  @protected
  @override
  Future<Y?> getListModelFromNamedServiceNPDS()
  async {
    try {
      final database = await sqfliteService.getDatabase;
      final listMap = await database
          ?.rawQuery('SELECT * FROM ${SqfliteService.constTableNote}');
      return getListNoteFromListMap(listMap);
    } catch(e) {
      return getListNoteFromBaseException(LocalException(this,EnumGuiltyForLocalException.device,e.toString()));
    }
  }

  @protected
  Y? getListNoteFromListMap(List<Map<String,dynamic>>? listMap) {
    if(listMap?.isEmpty ?? true) {
      return ListNote.success(<Note>[]) as Y?;
    }
    final listNote = listMap
        ?.map((e) => Note.fromMapForSqflite(e))
        .toList();
    return ListNote.success(listNote) as Y?;
  }

  @protected
  Y? getListNoteFromBaseException(BaseException? baseException) {
    return ListNote.exception(baseException!) as Y?;
  }
}

NoteQSqfliteServiceViewModelUsingInsertParameterNote:

class NoteQSqfliteServiceViewModelUsingInsertParameterNote<T extends Note,Y extends ListNote<T>>
    extends BaseModelQNamedServiceViewModel<T,Y>
    implements InsertModelToNamedServiceParameterNamedDataSource<int,T>
{
  @protected
  final sqfliteService = SqfliteService();

  Future<Result<int>?> insertNoteToSqfliteServiceParameterNoteUsingFBDS(T parameter) {
    return super.insertModelToNamedServiceParameterNamedUsingFBDS<int,T>(
        InsertNoteToSqfliteServiceParameterNoteFBDSUsingInsertParameterNote<T>(),
        parameter);
  }

  @nonVirtual
  @override
  Object? get modelQNamedServiceDataSource => this;

  @protected
  @override
  Future<Result<int>?> insertModelToNamedServiceParameterNamedDS(T? parameter)
  async {
    try {
      final database = await sqfliteService.getDatabase;
      final result = await database?.insert(
          SqfliteService.constTableNote,
          parameter!.toMapForSqflite(),
          conflictAlgorithm: ConflictAlgorithm.replace);
      return Result<int>.success(result);
    } catch(e) {
      return Result<int>.exception(LocalException(this,EnumGuiltyForLocalException.device,e.toString()));
    }
  }
}
  • NamedService
class SqfliteService {
  static const constTableNote = "Note";
  static Database? _database;

  Future<Database?> get getDatabase async {
    if(_database != null) {
      return _database;
    }
    final databasesPath = await getDatabasesPath();
    final path = join(databasesPath, 'todo.db');
    _database = await openDatabase(path, version: 1,
        onCreate: (Database db, int version) async {
          await db.execute('CREATE TABLE $constTableNote ('
              'id INTEGER PRIMARY KEY, '
              '${Note.constParameterUuIdForSqflite} TEXT NOT NULL, '
              '${Note.constParameterNameForSqflite} TEXT NOT NULL, '
              '${Note.constParameterDescriptionForSqflite} TEXT NOT NULL, '
              '${Note.constParameterIsCompletedForSqflite} INTEGER NOT NULL)');
        });
    return _database;
  }
}
  • IModelQNamedServiceDataSource

GetListModelFromNamedServiceNPDataSource:

/// This class is necessary to access the database or the network,
/// as it is a DataSource, and such classes as "ModelQNamedServiceViewModel" implement "DataSource"
/// for the main purpose and minimize the code, since inside the "BaseModelQNamedServiceModel"
/// there are references to the "DataSource" classes, and manipulate DataSource and FBDS classes
abstract class GetListModelFromNamedServiceNPDataSource<T extends BaseListModel> {
  Future<T?> getListModelFromNamedServiceNPDS();
}

InsertModelToNamedServiceParameterNamedDataSource:

/// This class is necessary to access the database or the network,
/// as it is a DataSource, and such classes as "ModelQNamedServiceViewModel" implement "DataSource"
/// for the main purpose and minimize the code, since inside the "BaseModelQNamedServiceModel"
/// there are references to the "DataSource" classes, and manipulate DataSource and FBDS classes
abstract class InsertModelToNamedServiceParameterNamedDataSource<T extends Object,Y extends Object> {
  Future<Result<T>?> insertModelToNamedServiceParameterNamedDS(Y? parameter);
}
  • FBDS
/// This class is designed to validate the model and calculate it before passing it to the data source method.
/// There are 3 generic types:
/// 1 generic type returns the correct result and must match the returned generic data source.
/// 2 generic type, sends the main parameter, which will be passed to the data source, after processing in fbds.
/// 3 generic type, sends additional data for verification and calculation, they are optional, and null can be assigned there
/// An example of a class name in a real project: InsertMovieToSqfliteServiceParameterMovieFBDSUsingInsertParameterMovie
/// ParameterMovie - with a parameter for insert
/// Using - is specified because it is also specified in the ModelQNamedServiceViewModel file name, and this binds fbds to this object, by file name.
/// This is done so as not to get confused where and which fbds is used
class InsertNoteToSqfliteServiceParameterNoteFBDSUsingInsertParameterNote<T extends Note>
    extends InsertModelToNamedServiceParameterNamedFBDS<int,T,Object>
{
  static const constIsEmptyByTrimParameterName = "constIsEmptyByTrimParameterName";

  @override
  Result<int>? insertModelToNamedServiceParameterNamed(T? parameter, Object? parameterForFBDS) {
    if(parameter?.isEmptyByTrimParameterName() ?? true) {
      return Result<int>.exceptionForFBDS(LocalException.whereTheUserIsGuilty(this,constIsEmptyByTrimParameterName));
    }
    return Result<int>.successForFBDS();
  }
}
  • NamedViewListViewModel

/// This class is required in order to call the "ModelQNamedServiceViewModel" and "ModelQThereIsStateViewModel" classes
class AddNoteViewListViewModel
    extends BaseNamedViewListViewModel
{
  // ModelQThereIsStateViewModel
  final _stringsQThereIsStateViewModelForTitle =
  StringsQThereIsStateViewModel(InitializedStreamStrings());
  final _stringsQThereIsStateViewModelForDescription =
  StringsQThereIsStateViewModel(InitializedStreamStrings());

  // ModelQNamedServiceViewModel
  final _noteQSqfliteServiceViewModelUsingInsertParameterNote =
  NoteQSqfliteServiceViewModelUsingInsertParameterNote();

  // NamedWidgetListViewModel
  late final NoteFabWidgetListViewModel noteFabWidgetListViewModel;
  late final TitleTextFormFieldWidgetListViewModel titleTextFormFieldWidgetListViewModel;
  late final DescriptionTextFormFieldWidgetListViewModel descriptionTextFormFieldWidgetListViewModel;

  AddNoteViewListViewModel() {
    noteFabWidgetListViewModel = NoteFabWidgetListViewModel(
        _stringsQThereIsStateViewModelForTitle,
        _stringsQThereIsStateViewModelForDescription,
        _noteQSqfliteServiceViewModelUsingInsertParameterNote);
    titleTextFormFieldWidgetListViewModel = TitleTextFormFieldWidgetListViewModel(
        _stringsQThereIsStateViewModelForTitle);
    descriptionTextFormFieldWidgetListViewModel = DescriptionTextFormFieldWidgetListViewModel(
        _stringsQThereIsStateViewModelForDescription);
  }

  @override
  void dispose() {
    _stringsQThereIsStateViewModelForTitle.dispose();
    _stringsQThereIsStateViewModelForDescription.dispose();
  }

  Future<void> notifyStreamStringsByStringsAndInGeneralZeroTask()
  async {
    await Future.delayed(const Duration(milliseconds: 100));
    _stringsQThereIsStateViewModelForTitle
        .notifyStreamStrings();
    _stringsQThereIsStateViewModelForDescription
        .notifyStreamStrings();
  }
}
  • NamedWidgetListViewModel

NoteFabWidgetListViewModel:

class NoteFabWidgetListViewModel {
  @protected
  final StringsQThereIsStateViewModel stringsQThereIsStateViewModelForTitle;
  @protected
  final StringsQThereIsStateViewModel stringsQThereIsStateViewModelForDescription;
  @protected
  final NoteQSqfliteServiceViewModelUsingInsertParameterNote noteQSqfliteServiceViewModelUsingInsertParameterNote;

  NoteFabWidgetListViewModel(
      this.stringsQThereIsStateViewModelForTitle,
      this.stringsQThereIsStateViewModelForDescription,
      this.noteQSqfliteServiceViewModelUsingInsertParameterNote);

  Future<void> insertNoteToSqfliteServiceParameterNoteUsingFBDSAndInGeneralOneTask(
      Function(String message) functionForException,
      Function() functionForSuccess)
  async {
    // 1
    final result = await noteQSqfliteServiceViewModelUsingInsertParameterNote
        .insertNoteToSqfliteServiceParameterNoteUsingFBDS(getNoteForInsertNoteToSqfliteServiceParameterNoteUsingFBDSAndInGeneralOneTask());
    if(result
        !.exceptionController
        .isNotEqualsNullParameterException())
    {
      functionForException(result
          .exceptionController
          .getMessageForViewParameterException ?? "");
      return;
    }
    functionForSuccess();
  }

  @protected
  Note getNoteForInsertNoteToSqfliteServiceParameterNoteUsingFBDSAndInGeneralOneTask() {
    return Note.success(
        stringsQThereIsStateViewModelForTitle.getStrings?.field,
        stringsQThereIsStateViewModelForDescription.getStrings?.field,
        false);
  }
}

TitleTextFormFieldWidgetListViewModel:

class TitleTextFormFieldWidgetListViewModel {
  @protected
  final StringsQThereIsStateViewModel stringsQThereIsStateViewModelForTitle;

  TitleTextFormFieldWidgetListViewModel(
      this.stringsQThereIsStateViewModelForTitle);

  Stream<Strings?>? get getStreamStrings {
    return stringsQThereIsStateViewModelForTitle.getStreamStrings;
  }

  void setFieldByStringsAndInGeneralZeroTask(String value) {
    stringsQThereIsStateViewModelForTitle
        .getStrings
        ?.field = value;
    stringsQThereIsStateViewModelForTitle
        .notifyStreamStrings();
  }
}

DescriptionTextFormFieldWidgetListViewModel:

class DescriptionTextFormFieldWidgetListViewModel {
  @protected
  final StringsQThereIsStateViewModel stringsQThereIsStateViewModelForDescription;

  DescriptionTextFormFieldWidgetListViewModel(
      this.stringsQThereIsStateViewModelForDescription);

  Stream<Strings?>? get getStreamStrings {
    return stringsQThereIsStateViewModelForDescription.getStreamStrings;
  }

  void setFieldByStringsAndInGeneralZeroTask(String value) {
    stringsQThereIsStateViewModelForDescription
        .getStrings
        ?.field = value;
    stringsQThereIsStateViewModelForDescription
        .notifyStreamStrings();
  }
}
  • NamedView

class AddNoteView
    extends StatefulWidget
{
  @override
  State<AddNoteView> createState() => _AddNoteViewState();
}

class _AddNoteViewState
    extends State<AddNoteView> 
{
  final _lo = AddNoteViewListViewModel();

  @override
  void initState() {
    super.initState();
  }

  @override
  void dispose() {
    _lo.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    _lo.notifyStreamStringsByStringsAndInGeneralZeroTask();
    final l10n = context.l10n;
    return Scaffold(
      appBar: AppBar(
        title: Text(l10n.editTodoAddAppBarTitle),
      ),
      floatingActionButton: NoteFabWidget(_lo.noteFabWidgetListViewModel),
      body: CupertinoScrollbar(
        child: SingleChildScrollView(
          child: Padding(
            padding: const EdgeInsets.all(16),
            child: Column(
              children: [
                TitleTextFormFieldWidget(_lo.titleTextFormFieldWidgetListViewModel),
                DescriptionTextFormFieldWidget(_lo.descriptionTextFormFieldWidgetListViewModel)
              ],
            ),
          ),
        ),
      ),
    );
  }
}
  • NamedWidget

NoteFabWidget:

class NoteFabWidget
    extends StatelessWidget
{
  @protected
  final NoteFabWidgetListViewModel lo;

  const NoteFabWidget(this.lo);

  @override
  Widget build(BuildContext context) {
    final l10n = context.l10n;
    final theme = Theme.of(context);
    final floatingActionButtonTheme = theme.floatingActionButtonTheme;
    final fabBackgroundColor = floatingActionButtonTheme.backgroundColor ??
        theme.colorScheme.secondary;
    return FloatingActionButton(
      tooltip: l10n.editTodoSaveButtonTooltip,
      shape: const ContinuousRectangleBorder(
        borderRadius: BorderRadius.all(Radius.circular(32)),
      ),
      backgroundColor:  fabBackgroundColor,
      onPressed: () => onPressed(context),
      child: buildChild(context)
    );
  }

  @protected
  void onPressed(BuildContext context) {
    lo.insertNoteToSqfliteServiceParameterNoteUsingFBDSAndInGeneralOneTask(
            (String message) => scaffoldFeatureControllerForException(context,message),
            () => Navigator.of(context).pop());
  }

  @protected
  Widget buildChild(BuildContext context) {
    return const Icon(Icons.check_rounded);
  }
}

TitleTextFormFieldWidget:

class TitleTextFormFieldWidget
    extends StatelessWidget
{
  @protected
  final TitleTextFormFieldWidgetListViewModel lo;

  const TitleTextFormFieldWidget(this.lo);

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<Strings?>(
        stream: lo.getStreamStrings,
        builder: (BuildContext context,AsyncSnapshot<Strings?> asyncSnapshot)
        {
          if(asyncSnapshot.data == null) {
            return Container();
          }
          final strings = asyncSnapshot.data;
          return TextFormField(
            initialValue: strings?.field,
            decoration: buildDecoration(context, strings),
            maxLength: maxLength(),
            inputFormatters: inputFormatters(),
            onChanged: (value) => onChanged(context,value));
        });
  }

  @protected
  InputDecoration buildDecoration(BuildContext context, Strings? strings) {
    final l10n = context.l10n;
    return InputDecoration(labelText: l10n.editTodoTitleLabel);
  }

  @protected
  int maxLength() {
    return 50;
  }

  @protected
  List<TextInputFormatter> inputFormatters() {
    return [
      LengthLimitingTextInputFormatter(50),
      FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9\s]')),
    ];
  }

  @protected
  void onChanged(BuildContext context,String value) {
    lo.setFieldByStringsAndInGeneralZeroTask(value);
  }
}

DescriptionTextFormFieldWidget:

class DescriptionTextFormFieldWidget
    extends StatelessWidget
{
  @protected
  final DescriptionTextFormFieldWidgetListViewModel lo;

  const DescriptionTextFormFieldWidget(this.lo);

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<Strings?>(
        stream: lo.getStreamStrings,
        builder: (BuildContext context,AsyncSnapshot<Strings?> asyncSnapshot)
        {
          if(asyncSnapshot.data == null) {
            return Container();
          }
          final strings = asyncSnapshot.data;
          return TextFormField(
              initialValue: strings?.field,
              decoration: buildDecoration(context, strings),
              maxLength: maxLength(),
              maxLines: maxLines(),
              inputFormatters: inputFormatters(),
              onChanged: (value) => onChanged(context,value));
        });
  }

  @protected
  InputDecoration buildDecoration(BuildContext context, Strings? strings) {
    final l10n = context.l10n;
    return InputDecoration(labelText: l10n.editTodoDescriptionLabel);
  }

  @protected
  int maxLength() {
    return 300;
  }

  @protected
  int maxLines() {
    return 7;
  }

  @protected
  List<TextInputFormatter> inputFormatters() {
    return [
      LengthLimitingTextInputFormatter(300),
    ];
  }

  @protected
  void onChanged(BuildContext context,String value) {
    lo.setFieldByStringsAndInGeneralZeroTask(value);
  }
}

Utility #

  • NamedException

This code is taken from another example, Firebase Login

class SignUpAndLogInWithEmailAndPasswordAndGoogleFailureException
    extends BaseException
{
  final String code;
  final String message;

  SignUpAndLogInWithEmailAndPasswordAndGoogleFailureException(
      Object thisClass,
      this.code,
      this.message) : super(thisClass,SignUpAndLogInWithEmailAndPasswordAndGoogleFailureException);

  factory SignUpAndLogInWithEmailAndPasswordAndGoogleFailureException.fromCodeForLogIn(
      Object thisClass,
      String code)
  {
    switch(code) {
      case 'invalid-email':
        return SignUpAndLogInWithEmailAndPasswordAndGoogleFailureException(
          thisClass,
          code,
          'Email is not valid or badly formatted.',
        );
      case 'user-disabled':
        return SignUpAndLogInWithEmailAndPasswordAndGoogleFailureException(
          thisClass,
          code,
          'This user has been disabled. Please contact support for help.',
        );
      case 'user-not-found':
        return SignUpAndLogInWithEmailAndPasswordAndGoogleFailureException(
          thisClass,
          code,
          'Email is not found, please create an account.',
        );
      case 'wrong-password':
        return SignUpAndLogInWithEmailAndPasswordAndGoogleFailureException(
          thisClass,
          code,
          'Incorrect password, please try again.',
        );
      default:
        return SignUpAndLogInWithEmailAndPasswordAndGoogleFailureException(
          thisClass,
            "unknown LogIn",
          "An unknown exception occurred."
        );
    }
  }

  factory SignUpAndLogInWithEmailAndPasswordAndGoogleFailureException.fromCodeForSignUp(
      Object thisClass,
      String code)
  {
    switch (code) {
      case 'invalid-email':
        return SignUpAndLogInWithEmailAndPasswordAndGoogleFailureException(
          thisClass,
          code,
          'Email is not valid or badly formatted.',
        );
      case 'user-disabled':
        return SignUpAndLogInWithEmailAndPasswordAndGoogleFailureException(
          thisClass,
          code,
          'This user has been disabled. Please contact support for help.',
        );
      case 'email-already-in-use':
        return SignUpAndLogInWithEmailAndPasswordAndGoogleFailureException(
          thisClass,
          code,
          'An account already exists for that email.',
        );
      case 'operation-not-allowed':
        return SignUpAndLogInWithEmailAndPasswordAndGoogleFailureException(
          thisClass,
          code,
          'Operation is not allowed.  Please contact support.',
        );
      case 'weak-password':
        return SignUpAndLogInWithEmailAndPasswordAndGoogleFailureException(
          thisClass,
          code,
          'Please enter a stronger password.',
        );
      default:
        return SignUpAndLogInWithEmailAndPasswordAndGoogleFailureException(
            thisClass,
            "unknown signUp",
            "An unknown exception occurred."
        );
    }
  }

  factory SignUpAndLogInWithEmailAndPasswordAndGoogleFailureException.fromCodeForGoogle(
      Object thisClass,
      String code)
  {
    switch(code) {
      case 'account-exists-with-different-credential':
        return SignUpAndLogInWithEmailAndPasswordAndGoogleFailureException(
          thisClass,
          code,
          'Account exists with different credentials.',
        );
      case 'invalid-credential':
        return SignUpAndLogInWithEmailAndPasswordAndGoogleFailureException(
          thisClass,
          code,
          'The credential received is malformed or has expired.',
        );
      case 'operation-not-allowed':
        return SignUpAndLogInWithEmailAndPasswordAndGoogleFailureException(
          thisClass,
          code,
          'Operation is not allowed.  Please contact support.',
        );
      case 'user-disabled':
        return SignUpAndLogInWithEmailAndPasswordAndGoogleFailureException(
          thisClass,
          code,
          'This user has been disabled. Please contact support for help.',
        );
      case 'user-not-found':
        return SignUpAndLogInWithEmailAndPasswordAndGoogleFailureException(
          thisClass,
          code,
          'Email is not found, please create an account.',
        );
      case 'wrong-password':
        return SignUpAndLogInWithEmailAndPasswordAndGoogleFailureException(
          thisClass,
          code,
          'Incorrect password, please try again.',
        );
      case 'invalid-verification-code':
        return SignUpAndLogInWithEmailAndPasswordAndGoogleFailureException(
          thisClass,
          code,
          'The credential verification code received is invalid.',
        );
      case 'invalid-verification-id':
        return SignUpAndLogInWithEmailAndPasswordAndGoogleFailureException(
          thisClass,
          code,
          'The credential verification ID received is invalid.',
        );
      default:
        return SignUpAndLogInWithEmailAndPasswordAndGoogleFailureException(
            thisClass,
            "unknown google",
            "An unknown exception occurred."
        );
    }
  }

  @override
  String get getMessageForView {
    return message;
  }

  @override
  String get exceptionInStringForDebugPrintException {
    return "Code: $code | "
        "Message: $message";
  }
}
  • NamedIterator

Iterator to sort the list of models

class NoteIteratorForSortedParameterIsCompletedFalse<T extends Note>
    extends BaseIterator<T>
{
  @override
  T get current {
    T note = listModel![0];
    int iteration = 0;
    if(note.isCompleted == false) {
      listModel!.removeAt(iteration);
      return note;
    }
    for(int i = 1; i < listModel!.length; i++) {
      if(listModel![i].isCompleted == false) {
        note = listModel![i];
        iteration = i;
        break;
      }
    }
    listModel!.removeAt(iteration);
    return note;
  }

  @override
  bool moveNext() {
    if(listModel!.isEmpty) {
      return false;
    }
    for(Note note in listModel!) {
      if(note.isCompleted == false) {
        return true;
      }
    }
    return false;
  }

}
  • NamedStreamModel

RXStreamModel already described above, in paragraph ModelQThereIsStateViewModel\IStreamModel

  • These files are not created by the programmer in his project (I will describe for clarification)

  • IDispose
/// This class is necessary to release resources, and it is in such classes:
/// "BaseModelQThereIsStateViewModel", "BaseNamedViewListViewModel", "IStreamModel"
abstract class IDispose {
  void dispose();
}
  • ExceptionController
enum EnumWhatIsTheException {
  noException,
  localException,
  networkException,
  otherException
}

/// This class is needed to manage the exception and provide
/// the necessary information to the developer about the error.
class ExceptionController {
  final EnumWhatIsTheException? enumWhatIsTheException;
  final BaseException? _exception;

  ExceptionController.success()
      : enumWhatIsTheException = EnumWhatIsTheException.noException,
        _exception = null;

  ExceptionController.exception(this._exception)
      : enumWhatIsTheException = _exception is LocalException
      ? EnumWhatIsTheException.localException : _exception is NetworkException
      ? EnumWhatIsTheException.networkException : EnumWhatIsTheException.otherException;

  @nonVirtual
  String? get getMessageForViewParameterException {
    return _exception?.getMessageForView;
  }

  @nonVirtual
  bool isNotEqualsNullParameterException() {
    if(_exception == null) {
      return false;
    }
    return true;
  }
}
  • Result

/// This class is required to get success or exception
class Result<T extends Object> {
  final T? parameter;
  final ExceptionController exceptionController;

  Result.success(this.parameter)
      : exceptionController = ExceptionController.success();
  Result.exception(BaseException exception)
      : exceptionController = ExceptionController.exception(exception),
        parameter = null;
  Result.successForFBDS()
      : exceptionController = ExceptionController.success(),
        parameter = null;
  Result.exceptionForFBDS(LocalException exception)
      : exceptionController = ExceptionController.exception(exception),
        parameter = null;
}

1
likes
0
pub points
46%
popularity

Publisher

unverified uploader

MVVM Modify for Dart but you can also port to another language

Repository (GitHub)
View/report issues

Documentation

Documentation

License

unknown (LICENSE)

Dependencies

ansicolor, meta

More

Packages that depend on library_architecture_mvvm_modify