Giter Club home page Giter Club logo

flutter-ddd-firebase-course's Introduction

Domain-Driven Design + Firebase Flutter Course

The whole accompanying tutorial series is available at ๐Ÿ‘‰ this link ๐Ÿ‘ˆ.

Find more tutorials on resocoder.com


DDD Architecture Proposal




Reso Coder
Be prepared for real app development

flutter-ddd-firebase-course's People

Contributors

resodev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

flutter-ddd-firebase-course's Issues

Error getting notes

I'm getting an error in the watchAll method because the mapping is not working.

It's seems to be something related with the kt_dart package.

The exception is "type 'DartList' is not a subtype of type 'KtList'" when I call to the method: toImmutableList()

I used the latest version (0.8.0) and the same like this repository: ^0.7.0+1

Any idea about the error?

Thanks in advance.

The getter 'key' was called on null.

โ•โ•โ•โ•โ•โ•โ•โ• Exception caught by widgets library โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
The following NoSuchMethodError was thrown building Builder(dirty):
The getter 'key' was called on null.
Receiver: null
Tried calling: key

[Question] SignInFormBloc.mapEventToState() issue

Hi, I'm facing with next error:

error: The type 'Stream' implied by the 'yield' expression must be assignable to Stream<Null>

and it's appearing for every state.copyWith() call
image

Any thoughts on it?
I'm on Flutter v1.13.6 and Dart v2.8.0

state.copyWith not overriding properties

Hi I have been trying to find out the problem for a whole two days and I still haven't found what the problem is
When writing the property_form_bloc with initialNote the state does not update no matter what I do here's the code

`class PropertyFormBloc extends Bloc<PropertyFormEvent, PropertyFormState> {
final IPropertyFacade _propertyFacade;
PropertyFormBloc(this._propertyFacade) : super(PropertyFormState.initial());

@OverRide
Stream mapEventToState(
PropertyFormEvent event,
) async* {
yield* event.map(
initialized: (e) async* {
e.initialPropertyOption.fold(
() => state,
(initialProperty) => state.copyWith(
isEditing: true,
property: initialProperty
)
);
print("current state is now $state");
},
nameChanged: (e) async* {
print("name changed ${e.name}");
yield state.copyWith(
property: state.property.copyWith(name: PropertyName(e.name)),
saveFailureOrSuccessOption: none()
);
},
descriptionEvent: (e) async* {
yield state.copyWith(
property: state.property.copyWith(description: e.description),
saveFailureOrSuccessOption: none()
);
},
saved: (e) async* {
Either<ClassFailure, String> failureOrSuccess;

      yield state.copyWith(
          isSaving: true,
          saveFailureOrSuccessOption: none()
      );
      if(state.property.name.isValid() && state.property.description.length > 5) {
        failureOrSuccess = state.isEditing ?
          await _propertyFacade.updateProperty(state.property)
            : await _propertyFacade.createProperty(state.property);
      }

      yield state.copyWith(
        isSaving: false,
        showErrorMessages: true,
        saveFailureOrSuccessOption: optionOf(failureOrSuccess)
      );
    }
);

}
}`
Am I missing something? When I log out the initial property in this case it logs out the initialPropertyOption but is unable to update the state. Any answer is welcome

Where to initialize Firebase app

In lastest version of firebase, it's required to call await Firebase.initializeApp(); before using any function of Firebase. So where should we put this line of code?

Bloc To Bloc Communication

How can I achieve bloc to bloc communication between note watcher bloc and note form bloc if I want to get a form value from the form and use it in the repository to filter notes on firestore?

Here is my implementation:
Its the same as you have done it here, its just the names that are different. When I listen on the bloc, I am not getting anything, its not getting called. Any comment will be appreciated.

import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:dartz/dartz.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:injectable/injectable.dart';
import 'package:kt_dart/collection.dart';
import 'package:meta/meta.dart';
import 'package:tola/application/trips/booking_form/booking_form_bloc.dart';
import 'package:tola/domain/trips/i_trip_repository.dart';
import 'package:tola/domain/trips/trip.dart';
import 'package:tola/domain/trips/trip_failure.dart';

part 'trip_watcher_event.dart';

part 'trip_watcher_state.dart';

part 'trip_watcher_bloc.freezed.dart';

@Injectable
class TripWatcherBloc extends Bloc<TripWatcherEvent, TripWatcherState> {
TripWatcherBloc(this._tripRepository, this.bookingFormBloc)
: super(const TripWatcherState.initial()) {
bookingFormBlocBlocSubscription = bookingFormBloc.listen((state) {
print('booking form bloc here');
departureTown = state.destinationTownField.getOrCrash();
destinationTown = state.destinationTownField.getOrCrash();
passengerCount = state.passengersField.getOrCrash() as int;
travelDate = state.dateField.getOrCrash() as DateTime;
});
}

final ITripRepository _tripRepository;
final BookingFormBloc bookingFormBloc;

String departureTown;
String destinationTown;
int passengerCount;
DateTime travelDate;

StreamSubscription bookingFormBlocBlocSubscription;

@OverRide
Stream mapEventToState(
TripWatcherEvent event,
) async* {
yield* event.map(watchAllStarted: (e) async* {

  print(travelDate);

  _tripRepository
      .watchAll(
          destinationTown: destinationTown,
          departureTown: departureTown,
          passengerCount: passengerCount,
          travelDate: travelDate)
      .listen(
        (failureOrTrips) =>
            add(TripWatcherEvent.tripsReceived(failureOrTrips)),
      );
}, tripsReceived: (e) async* {
  yield e.failureOrTrips.fold((l) => TripWatcherState.loadFailure(l),
      (r) => TripWatcherState.loadSuccess(r));
});

}

@OverRide
Future close() {
bookingFormBlocBlocSubscription.cancel();
return super.close();
}
}

Exception caught by widgets library

โ•โ•โ•โ•โ•โ•โ•โ• Exception caught by widgets library โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
The following NoSuchMethodError was thrown building Builder(dirty):
The getter 'key' was called on null.
Receiver: null
Tried calling: key

import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:notes_firebase_ddd_course/application/auth/auth_bloc.dart';
import 'package:notes_firebase_ddd_course/injection.dart';
import 'package:notes_firebase_ddd_course/presentation/routes/router.gr.dart' as app_router;
import 'package:notes_firebase_ddd_course/presentation/sign_in/sign_in_page.dart';

class AppWidget extends StatelessWidget {
@OverRide
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider(
create: (context) =>
getIt()..add(const AuthEvent.authCheckRequested()),
)
],
child: MaterialApp(
title: 'Notes',
debugShowCheckedModeBanner: false,
builder: ExtendedNavigator.builder(router: app_router.Router()),
theme: ThemeData.light().copyWith(
primaryColor: Colors.green[800],
accentColor: Colors.blueAccent,
floatingActionButtonTheme: FloatingActionButtonThemeData(
backgroundColor: Colors.blue[900],
),
inputDecorationTheme: InputDecorationTheme(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
),
),
),
);
}
}

Unhandled Exception: type 'Freezed' is not a subtype of type 'ValueObject<String>' of 'other'

i am getting an error on the emailChanged event. when i type in the textformfield i get Unhandled Exception: type 'Freezed' is not a subtype of type 'ValueObject' of 'other'.

the error points me to the freezed bloc file, specifically:

@OverRide
$Res call({
Object? emailAddress = freezed,
Object? password = freezed,
Object? isSubmitting = freezed,
Object? showErrorMessages = freezed,
Object? authFailureOrSuccessOption = freezed,
}) {
return then($_SignInFormState(
emailAddress: emailAddress == freezed
? _value.emailAddress
: emailAddress // ignore: cast_nullable_to_non_nullable
as EmailAddress,
password: password == freezed
? _value.password
: password // ignore: cast_nullable_to_non_nullable
as Password,

When i change the emailAddress: emailAddress == freezed
? _value.emailAddress into something like emailAddress: emailAddress == bool
? _value.emailAddress. the error changes to Unhandled Exception: type 'bool' is not a subtype of type 'ValueObject' of 'other'. is there something wrong with freezed??

NoteRepository.watchAll() hangs

I have a strange bug. In below code of the NoteBloc:

  • the NoteWatcherState.loadInProgress is fired.
  • I also see that the _noteRepository.watchAll function is executed.
  • But it stays in the NoteWatcherState.loadInProgress and doesn't continue.
  • There is no error at all.
  • All the Authentication code works by the way, and I could retrieve a document from firestore directly from the notes_overview_page.

I built the app two times from scratch following the tutorial. I tried to debug, but the debug simply ignores everything after this line: _noteStreamSubscription = _noteRepository.watchAll().listen(

Does anybody know what could cause this? I'm somehow stuck without any errors or debug capabilities.

NoteWatcherBloc

   yield* event.map(
      watchAllStarted: (e) async* {
        yield const NoteWatcherState.loadInProgress();
        await _noteStreamSubscription?.cancel();
        _noteStreamSubscription = _noteRepository.watchAll().listen( // <-- debug doesn't go into here and simply ignores it
              (failureOrNotes) =>
                  add(NoteWatcherEvent.notesReceived(failureOrNotes)), // <-- this is not executed, no idea why, no error.
            );
      },

NoteRepository

 @override
  Stream<Either<NoteFailure, KtList<Note>>> watchAll() async* {
    final userDoc = await _firestore.userDocument();

    print("Its listening"); // <-- I see that this is printed when i reload

    yield* userDoc.noteCollection // <-- no idea if this is actually done
      .orderBy('serverTimeStamp', descending: true)
      .snapshots()
      .map((snapshot) => right<NoteFailure, KtList<Note>>(
        snapshot.documents
          .map((doc) => NoteDto.fromFirestore(doc).toDomain())
          .toImmutableList(),
      )
    )
    .onErrorReturnWith((e) { // <-- no error here. 
      if(e is PlatformException && e.message.contains('PERMISSION_DENIED')) {
        print("platformexception");
        return left(const NoteFailure.insufficientPermission());
      } else {
        // log.error(e.toString())
        print("unexpected");
        return left(const NoteFailure.unexpected());
      }
    });
  }

Classes can only mix in mixins and classes.

Hi, I just finished the 4th video of the series, I am facing these problems and I cant quite find the solution, am I missing out something?
`
part of 'sign_in_form_bloc.dart';

@freezed
abstract class SignInFormState with _$SignInFormState {
const factory SignInFormState({
@required EmailAddress emailAddress,
@required Password password,
@required bool showErrorMessages,
@required bool isSubmitting,
@required Option<Either<AuthFailure, Unit>> authFailureOrSuccessOption,
}) = _SignInFormState;

factory SignInFormState.initial() => SignInFormState(
emailAddress: EmailAddress(''),
password: Password(''),
showErrorMessages: false,
isSubmitting: false,
authFailureOrSuccessOption: none(),
);
}

`

error: Classes can only mix in mixins and classes.
error: The name '_SignInFormState' isn't a type and can't be used in a redirected constructor.
Try redirecting to a different constructor.

Error on TodoItemDto factory

factory TodoItemDto.fromDomain(TodoItem todoItem) {
    return TodoItemDto(
      // getting error here
      id: todoItem.id.getOrCrash(),
      name: todoItem.name.getOrCrash(),
      done: todoItem.done,
    );
  }

The argument type 'dynamic' can't be assigned to the parameter type 'String'.

firebase_auth 0.18.0+1 (Current Lastest) Breaks on Firebase Auth Facade "getSignedInUser()" Method

  • Hello, Thanks for this video series of a clean arquitecture in flutter, I have an issue on

@override Future<Option<User>> getSignedInUser() => ...

  • When update to firebase 0.18.0+1 this method breaks

_firebaseAuth.currentUser().then((firebaseUser) => optionOf(firebaseUser?.toDomain()));

  • Because access to current user via currentUser () is now synchronous via currentUser in the new update.

new firebase_auth 0.18 beaking changes

as of update 0.18 there's been changes in the way user state is handled.
_firebaseAuth.CurrentUser() is no longer usable, CurrentUser is now just a getter.

/// Returns the current [User] if they are currently signed-in, or null if /// not. /// /// You should not use this getter to determine the users current state, /// instead use [authStateChanges], [idTokenChanges] or [userChanges] to /// subscribe to updates.

can you please, even if you're not willing to update the entire project, just tell me how to handle the "authStateChanges" stream
for example through the firebase authentication facade? and pass it down to states and firing events based on how we listen to it.

Json serialization with with deep class object Id and JsonKen(ignore:true)

I want to moving the code to Flutter 2.2
When I attempt to go on the note detail, I same the TodoListItem Id is null (but it is not null on firebase firestore), it happen when the TodoListItem Dto is in the toDomain method;
I got this error CastError (Null check operator used on a null value)
Anyone can help me ?

Issues with flutter inspector.

I am in the auth page and when I use flutter inspector it shows me the spash screen with the loader in the center.
This happens for every screen and when I use flutter inspector.

problem with auto_route package

When you upgraded flutter to version 1.22.0. It will be conflict between Router class in library 'package:flutter/src/widgets/router.dart' and the generated file 'router.gr.dart'.

If you are not using the Router class from 'package:flutter/src/widgets/router.dart' in the same file you can hide it while importing material package.

import 'package:flutter/material.dart' hide Router;

NoteFailure.unexpected: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'List<dynamic>' in type cast

Hi there,

first things first: A million thanks for the great tutorial.

I'm currently running into a bug that seems to affect this repository as well:

A call after login generates an unexpected error:
type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'List' in type cast

It seems that a feature in freezed is missing here?
rrousselGit/freezed#292

I cant figure out a clean way to solve this issue.... Maybe its also a completely different problem (:

How can I implement it with riverpod

Hello, @ResoDev I have been trying to implement it with riverpod instead of the bloc library.

How can I do that?

The state management is not working for me.

My state notifier code

class SignInStateNotifier extends StateNotifier<SignInFormStates> {
  SignInStateNotifier(this._authFacade) : super(SignInFormStates.initial());

  final IAuthFacade _authFacade;

  Stream<SignInFormStates> mapEventToState(SignInFormEvents events) async* {
    yield* events.map(emailChanged: (value) async* {
      yield state.copyWith(
        emailAddress: EmailAddress(value.email),
        authFailureOrSuccess: none(),
      );
    }, passwordChanged: (value) async* {
      state.copyWith(
        password: Password(value.password),
        authFailureOrSuccess: none(),
      );
    }, signInWithEmailAndPasswordPressed: (value) async* {
      Either<AuthFailure, Unit> failureOrSuccess;
      if (state.emailAddress.isValid() && state.password.isValid()) {
        yield state.copyWith(
          isSubmitting: true,
          authFailureOrSuccess: none(),
        );
        failureOrSuccess = await _authFacade.signInWithEmailAndPassword(
          emailAddress: state.emailAddress,
          password: state.password,
        );
      }
      yield state.copyWith(
        isSubmitting: false,
        showErrorMessage: true,
        authFailureOrSuccess: optionOf(failureOrSuccess),
      );
    });
  }
}

My Form Widget

Form(
              child: Column(
                children: [
                  TextFormField(
                    autovalidateMode: AutovalidateMode.onUserInteraction,
                    onChanged: (value) => state
                        .mapEventToState(SignInFormEvents.emailChanged(value)),
                    validator: (_) => state2.emailAddress.validatedObject.fold(
                            (l) => l.maybeMap(
                            orElse: () => null,
                            invalidEmail: (_) => "Invalid Email"),
                            (_) => null),
                  ),
                  FlatButton(
                      onPressed: () {
                        state.mapEventToState(SignInFormEvents
                            .signInWithEmailAndPasswordPressed());
                      },
                      child: Text("Hello World"))
                ],
              )
            );

What mistake have I made? Please give me a solution.

Thanks in advance.

Error-Causing Widget

file:///Users/dalestewart/Downloads/flutter-ddd-firebase-course-master/lib/presentation/core/app_widget.dart:20:14
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:notes_firebase_ddd_course/application/auth/auth_bloc.dart';
import 'package:notes_firebase_ddd_course/injection.dart';
import 'package:notes_firebase_ddd_course/presentation/routes/router.gr.dart' as app_router;
import 'package:notes_firebase_ddd_course/presentation/sign_in/sign_in_page.dart';

class AppWidget extends StatelessWidget {
@OverRide
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider(
create: (context) =>
getIt()..add(const AuthEvent.authCheckRequested()),
)
],
child: MaterialApp(
title: 'Notes',
debugShowCheckedModeBanner: false,
builder: ExtendedNavigator.builder(router: app_router.Router()),
theme: ThemeData.light().copyWith(
primaryColor: Colors.green[800],
accentColor: Colors.blueAccent,
floatingActionButtonTheme: FloatingActionButtonThemeData(
backgroundColor: Colors.blue[900],
),
inputDecorationTheme: InputDecorationTheme(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
),
),
),
);
}
}

auto_route breaking update from 0.6.2^

The ExtendedNavigator was fundamentally changed. The pushReplacementNamed method in ExtendedNavigator is now replace. Changes need to be made in the SplashScreen, SignInForm, and NotesOverviewPage.

Lot of issues with Flutter 2 Null Satefy

Hello,
I am struggling a lot since 1 week, to make the whole code compatible with Flutter null safety and new versions of packages. Can you please make a little video or write a little thing explaining how we can do that ? Thanks a lot Resocoder :-)

How To Access The Failed Value From Either?

A good description of the issue can be found here:

In the example below, we have:

  • Type: Either<RangedNumberValueFailuresAbstract<int>, int>
  • If No Error: right(number)
  • If Error: left(RangedNumberValueFailuresAbstract.invalidNumber(failedNumberValue: number))

If we need to access the failedNumberValue in (failedNumberValue: number), how would we do it?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.