diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index cee39ab..cf1cc60 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -29,6 +29,15 @@
+
+
+
+
+
+
+
+
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index 44dfe48..9baefb2 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -29,6 +29,7 @@
????
CFBundleVersion
$(FLUTTER_BUILD_NUMBER)
+
CFBundleURLTypes
@@ -49,6 +50,23 @@
fbapi
fb-messenger-share-api
+
+
+ CFBundleURLTypes
+
+
+ CFBundleTypeRole
+ Editor
+ CFBundleURLName
+
+ CFBundleURLSchemes
+
+
+ example
+
+
+
+
LSRequiresIPhoneOS
UILaunchStoryboardName
diff --git a/lib/authentication_with_facebook/infrastructure/facebook_auth_repository.dart b/lib/authentication_with_facebook/infrastructure/facebook_auth_repository.dart
index 1a05cc1..72c2717 100644
--- a/lib/authentication_with_facebook/infrastructure/facebook_auth_repository.dart
+++ b/lib/authentication_with_facebook/infrastructure/facebook_auth_repository.dart
@@ -35,7 +35,7 @@ class FacebookAuthenticationRepository implements IFacebookRepositoryFacade {
if (user == null) {
return left(const AuthFailure.userNotFound());
}
-
+
return right(UserDTO.fromFirebase(user).toDomain());
} on SocketException catch (e) {
return left(AuthFailure.fromErrorMessage(e.message));
diff --git a/lib/authentication_with_twitter/application/twitter_authentication/twitter_authentication_bloc.dart b/lib/authentication_with_twitter/application/twitter_authentication/twitter_authentication_bloc.dart
new file mode 100644
index 0000000..f038bd1
--- /dev/null
+++ b/lib/authentication_with_twitter/application/twitter_authentication/twitter_authentication_bloc.dart
@@ -0,0 +1,49 @@
+import 'package:bloc/bloc.dart';
+import 'package:dartz/dartz.dart';
+import 'package:fpb/authentication_with_twitter/domain/i_twitter_repository_facade.dart';
+import 'package:fpb/core/domain/user.dart';
+import 'package:fpb/core/failures/auth_failure.dart';
+import 'package:freezed_annotation/freezed_annotation.dart';
+
+part 'twitter_authentication_event.dart';
+part 'twitter_authentication_state.dart';
+part 'twitter_authentication_bloc.freezed.dart';
+
+class TwitterAuthenticationBloc
+ extends Bloc {
+ TwitterAuthenticationBloc({required this.authenticationRepository})
+ : super(TwitterAuthenticationState.initial()) {
+ on(_onTwitterSignInPressed);
+ on(_onTwitterSignOutPressed);
+ }
+
+ final ITwitterRepositoryFacade authenticationRepository;
+
+ Future _onTwitterSignInPressed(
+ TwitterSignIn event,
+ Emitter emit,
+ ) async {
+ emit(state.copyWith(isLoading: true));
+ final failureOrUser = await authenticationRepository.signInWithTwitter();
+ failureOrUser.fold(
+ (failure) => emit(TwitterAuthenticationState(
+ failureOrUser: left(failure), isLoading: false)),
+ (user) => emit(TwitterAuthenticationState(
+ isLoading: false, failureOrUser: right(user))),
+ );
+ }
+
+ Future _onTwitterSignOutPressed(
+ TwitterSignOut event,
+ Emitter emit,
+ ) async {
+ emit(state.copyWith(isLoading: true));
+ final failureOrUnit = await authenticationRepository.signOut();
+ failureOrUnit.fold(
+ (failure) => emit(TwitterAuthenticationState(
+ failureOrUser: left(failure), isLoading: false)),
+ (unit) => emit(TwitterAuthenticationState(
+ isLoading: false, failureOrUser: right(User.empty))),
+ );
+ }
+}
diff --git a/lib/authentication_with_twitter/application/twitter_authentication/twitter_authentication_bloc.freezed.dart b/lib/authentication_with_twitter/application/twitter_authentication/twitter_authentication_bloc.freezed.dart
new file mode 100644
index 0000000..0b23c80
--- /dev/null
+++ b/lib/authentication_with_twitter/application/twitter_authentication/twitter_authentication_bloc.freezed.dart
@@ -0,0 +1,555 @@
+// coverage:ignore-file
+// GENERATED CODE - DO NOT MODIFY BY HAND
+// ignore_for_file: type=lint
+// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target
+
+part of 'twitter_authentication_bloc.dart';
+
+// **************************************************************************
+// FreezedGenerator
+// **************************************************************************
+
+T _$identity(T value) => value;
+
+final _privateConstructorUsedError = UnsupportedError(
+ 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
+
+/// @nodoc
+mixin _$TwitterAuthenticationEvent {
+ @optionalTypeArgs
+ TResult when({
+ required TResult Function() started,
+ required TResult Function() signIn,
+ required TResult Function() signOut,
+ }) =>
+ throw _privateConstructorUsedError;
+ @optionalTypeArgs
+ TResult? whenOrNull({
+ TResult? Function()? started,
+ TResult? Function()? signIn,
+ TResult? Function()? signOut,
+ }) =>
+ throw _privateConstructorUsedError;
+ @optionalTypeArgs
+ TResult maybeWhen({
+ TResult Function()? started,
+ TResult Function()? signIn,
+ TResult Function()? signOut,
+ required TResult orElse(),
+ }) =>
+ throw _privateConstructorUsedError;
+ @optionalTypeArgs
+ TResult map({
+ required TResult Function(_Started value) started,
+ required TResult Function(TwitterSignIn value) signIn,
+ required TResult Function(TwitterSignOut value) signOut,
+ }) =>
+ throw _privateConstructorUsedError;
+ @optionalTypeArgs
+ TResult? mapOrNull({
+ TResult? Function(_Started value)? started,
+ TResult? Function(TwitterSignIn value)? signIn,
+ TResult? Function(TwitterSignOut value)? signOut,
+ }) =>
+ throw _privateConstructorUsedError;
+ @optionalTypeArgs
+ TResult maybeMap({
+ TResult Function(_Started value)? started,
+ TResult Function(TwitterSignIn value)? signIn,
+ TResult Function(TwitterSignOut value)? signOut,
+ required TResult orElse(),
+ }) =>
+ throw _privateConstructorUsedError;
+}
+
+/// @nodoc
+abstract class $TwitterAuthenticationEventCopyWith<$Res> {
+ factory $TwitterAuthenticationEventCopyWith(TwitterAuthenticationEvent value,
+ $Res Function(TwitterAuthenticationEvent) then) =
+ _$TwitterAuthenticationEventCopyWithImpl<$Res,
+ TwitterAuthenticationEvent>;
+}
+
+/// @nodoc
+class _$TwitterAuthenticationEventCopyWithImpl<$Res,
+ $Val extends TwitterAuthenticationEvent>
+ implements $TwitterAuthenticationEventCopyWith<$Res> {
+ _$TwitterAuthenticationEventCopyWithImpl(this._value, this._then);
+
+ // ignore: unused_field
+ final $Val _value;
+ // ignore: unused_field
+ final $Res Function($Val) _then;
+}
+
+/// @nodoc
+abstract class _$$_StartedCopyWith<$Res> {
+ factory _$$_StartedCopyWith(
+ _$_Started value, $Res Function(_$_Started) then) =
+ __$$_StartedCopyWithImpl<$Res>;
+}
+
+/// @nodoc
+class __$$_StartedCopyWithImpl<$Res>
+ extends _$TwitterAuthenticationEventCopyWithImpl<$Res, _$_Started>
+ implements _$$_StartedCopyWith<$Res> {
+ __$$_StartedCopyWithImpl(_$_Started _value, $Res Function(_$_Started) _then)
+ : super(_value, _then);
+}
+
+/// @nodoc
+
+class _$_Started implements _Started {
+ const _$_Started();
+
+ @override
+ String toString() {
+ return 'TwitterAuthenticationEvent.started()';
+ }
+
+ @override
+ bool operator ==(dynamic other) {
+ return identical(this, other) ||
+ (other.runtimeType == runtimeType && other is _$_Started);
+ }
+
+ @override
+ int get hashCode => runtimeType.hashCode;
+
+ @override
+ @optionalTypeArgs
+ TResult when({
+ required TResult Function() started,
+ required TResult Function() signIn,
+ required TResult Function() signOut,
+ }) {
+ return started();
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult? whenOrNull({
+ TResult? Function()? started,
+ TResult? Function()? signIn,
+ TResult? Function()? signOut,
+ }) {
+ return started?.call();
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult maybeWhen({
+ TResult Function()? started,
+ TResult Function()? signIn,
+ TResult Function()? signOut,
+ required TResult orElse(),
+ }) {
+ if (started != null) {
+ return started();
+ }
+ return orElse();
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult map({
+ required TResult Function(_Started value) started,
+ required TResult Function(TwitterSignIn value) signIn,
+ required TResult Function(TwitterSignOut value) signOut,
+ }) {
+ return started(this);
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult? mapOrNull({
+ TResult? Function(_Started value)? started,
+ TResult? Function(TwitterSignIn value)? signIn,
+ TResult? Function(TwitterSignOut value)? signOut,
+ }) {
+ return started?.call(this);
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult maybeMap({
+ TResult Function(_Started value)? started,
+ TResult Function(TwitterSignIn value)? signIn,
+ TResult Function(TwitterSignOut value)? signOut,
+ required TResult orElse(),
+ }) {
+ if (started != null) {
+ return started(this);
+ }
+ return orElse();
+ }
+}
+
+abstract class _Started implements TwitterAuthenticationEvent {
+ const factory _Started() = _$_Started;
+}
+
+/// @nodoc
+abstract class _$$TwitterSignInCopyWith<$Res> {
+ factory _$$TwitterSignInCopyWith(
+ _$TwitterSignIn value, $Res Function(_$TwitterSignIn) then) =
+ __$$TwitterSignInCopyWithImpl<$Res>;
+}
+
+/// @nodoc
+class __$$TwitterSignInCopyWithImpl<$Res>
+ extends _$TwitterAuthenticationEventCopyWithImpl<$Res, _$TwitterSignIn>
+ implements _$$TwitterSignInCopyWith<$Res> {
+ __$$TwitterSignInCopyWithImpl(
+ _$TwitterSignIn _value, $Res Function(_$TwitterSignIn) _then)
+ : super(_value, _then);
+}
+
+/// @nodoc
+
+class _$TwitterSignIn implements TwitterSignIn {
+ _$TwitterSignIn();
+
+ @override
+ String toString() {
+ return 'TwitterAuthenticationEvent.signIn()';
+ }
+
+ @override
+ bool operator ==(dynamic other) {
+ return identical(this, other) ||
+ (other.runtimeType == runtimeType && other is _$TwitterSignIn);
+ }
+
+ @override
+ int get hashCode => runtimeType.hashCode;
+
+ @override
+ @optionalTypeArgs
+ TResult when({
+ required TResult Function() started,
+ required TResult Function() signIn,
+ required TResult Function() signOut,
+ }) {
+ return signIn();
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult? whenOrNull({
+ TResult? Function()? started,
+ TResult? Function()? signIn,
+ TResult? Function()? signOut,
+ }) {
+ return signIn?.call();
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult maybeWhen({
+ TResult Function()? started,
+ TResult Function()? signIn,
+ TResult Function()? signOut,
+ required TResult orElse(),
+ }) {
+ if (signIn != null) {
+ return signIn();
+ }
+ return orElse();
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult map({
+ required TResult Function(_Started value) started,
+ required TResult Function(TwitterSignIn value) signIn,
+ required TResult Function(TwitterSignOut value) signOut,
+ }) {
+ return signIn(this);
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult? mapOrNull({
+ TResult? Function(_Started value)? started,
+ TResult? Function(TwitterSignIn value)? signIn,
+ TResult? Function(TwitterSignOut value)? signOut,
+ }) {
+ return signIn?.call(this);
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult maybeMap({
+ TResult Function(_Started value)? started,
+ TResult Function(TwitterSignIn value)? signIn,
+ TResult Function(TwitterSignOut value)? signOut,
+ required TResult orElse(),
+ }) {
+ if (signIn != null) {
+ return signIn(this);
+ }
+ return orElse();
+ }
+}
+
+abstract class TwitterSignIn implements TwitterAuthenticationEvent {
+ factory TwitterSignIn() = _$TwitterSignIn;
+}
+
+/// @nodoc
+abstract class _$$TwitterSignOutCopyWith<$Res> {
+ factory _$$TwitterSignOutCopyWith(
+ _$TwitterSignOut value, $Res Function(_$TwitterSignOut) then) =
+ __$$TwitterSignOutCopyWithImpl<$Res>;
+}
+
+/// @nodoc
+class __$$TwitterSignOutCopyWithImpl<$Res>
+ extends _$TwitterAuthenticationEventCopyWithImpl<$Res, _$TwitterSignOut>
+ implements _$$TwitterSignOutCopyWith<$Res> {
+ __$$TwitterSignOutCopyWithImpl(
+ _$TwitterSignOut _value, $Res Function(_$TwitterSignOut) _then)
+ : super(_value, _then);
+}
+
+/// @nodoc
+
+class _$TwitterSignOut implements TwitterSignOut {
+ _$TwitterSignOut();
+
+ @override
+ String toString() {
+ return 'TwitterAuthenticationEvent.signOut()';
+ }
+
+ @override
+ bool operator ==(dynamic other) {
+ return identical(this, other) ||
+ (other.runtimeType == runtimeType && other is _$TwitterSignOut);
+ }
+
+ @override
+ int get hashCode => runtimeType.hashCode;
+
+ @override
+ @optionalTypeArgs
+ TResult when({
+ required TResult Function() started,
+ required TResult Function() signIn,
+ required TResult Function() signOut,
+ }) {
+ return signOut();
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult? whenOrNull({
+ TResult? Function()? started,
+ TResult? Function()? signIn,
+ TResult? Function()? signOut,
+ }) {
+ return signOut?.call();
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult maybeWhen({
+ TResult Function()? started,
+ TResult Function()? signIn,
+ TResult Function()? signOut,
+ required TResult orElse(),
+ }) {
+ if (signOut != null) {
+ return signOut();
+ }
+ return orElse();
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult map({
+ required TResult Function(_Started value) started,
+ required TResult Function(TwitterSignIn value) signIn,
+ required TResult Function(TwitterSignOut value) signOut,
+ }) {
+ return signOut(this);
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult? mapOrNull({
+ TResult? Function(_Started value)? started,
+ TResult? Function(TwitterSignIn value)? signIn,
+ TResult? Function(TwitterSignOut value)? signOut,
+ }) {
+ return signOut?.call(this);
+ }
+
+ @override
+ @optionalTypeArgs
+ TResult maybeMap({
+ TResult Function(_Started value)? started,
+ TResult Function(TwitterSignIn value)? signIn,
+ TResult Function(TwitterSignOut value)? signOut,
+ required TResult orElse(),
+ }) {
+ if (signOut != null) {
+ return signOut(this);
+ }
+ return orElse();
+ }
+}
+
+abstract class TwitterSignOut implements TwitterAuthenticationEvent {
+ factory TwitterSignOut() = _$TwitterSignOut;
+}
+
+/// @nodoc
+mixin _$TwitterAuthenticationState {
+ bool get isLoading => throw _privateConstructorUsedError;
+ Either get failureOrUser =>
+ throw _privateConstructorUsedError;
+
+ @JsonKey(ignore: true)
+ $TwitterAuthenticationStateCopyWith
+ get copyWith => throw _privateConstructorUsedError;
+}
+
+/// @nodoc
+abstract class $TwitterAuthenticationStateCopyWith<$Res> {
+ factory $TwitterAuthenticationStateCopyWith(TwitterAuthenticationState value,
+ $Res Function(TwitterAuthenticationState) then) =
+ _$TwitterAuthenticationStateCopyWithImpl<$Res,
+ TwitterAuthenticationState>;
+ @useResult
+ $Res call({bool isLoading, Either failureOrUser});
+}
+
+/// @nodoc
+class _$TwitterAuthenticationStateCopyWithImpl<$Res,
+ $Val extends TwitterAuthenticationState>
+ implements $TwitterAuthenticationStateCopyWith<$Res> {
+ _$TwitterAuthenticationStateCopyWithImpl(this._value, this._then);
+
+ // ignore: unused_field
+ final $Val _value;
+ // ignore: unused_field
+ final $Res Function($Val) _then;
+
+ @pragma('vm:prefer-inline')
+ @override
+ $Res call({
+ Object? isLoading = null,
+ Object? failureOrUser = null,
+ }) {
+ return _then(_value.copyWith(
+ isLoading: null == isLoading
+ ? _value.isLoading
+ : isLoading // ignore: cast_nullable_to_non_nullable
+ as bool,
+ failureOrUser: null == failureOrUser
+ ? _value.failureOrUser
+ : failureOrUser // ignore: cast_nullable_to_non_nullable
+ as Either,
+ ) as $Val);
+ }
+}
+
+/// @nodoc
+abstract class _$$_TwitterAuthenticationStateCopyWith<$Res>
+ implements $TwitterAuthenticationStateCopyWith<$Res> {
+ factory _$$_TwitterAuthenticationStateCopyWith(
+ _$_TwitterAuthenticationState value,
+ $Res Function(_$_TwitterAuthenticationState) then) =
+ __$$_TwitterAuthenticationStateCopyWithImpl<$Res>;
+ @override
+ @useResult
+ $Res call({bool isLoading, Either failureOrUser});
+}
+
+/// @nodoc
+class __$$_TwitterAuthenticationStateCopyWithImpl<$Res>
+ extends _$TwitterAuthenticationStateCopyWithImpl<$Res,
+ _$_TwitterAuthenticationState>
+ implements _$$_TwitterAuthenticationStateCopyWith<$Res> {
+ __$$_TwitterAuthenticationStateCopyWithImpl(
+ _$_TwitterAuthenticationState _value,
+ $Res Function(_$_TwitterAuthenticationState) _then)
+ : super(_value, _then);
+
+ @pragma('vm:prefer-inline')
+ @override
+ $Res call({
+ Object? isLoading = null,
+ Object? failureOrUser = null,
+ }) {
+ return _then(_$_TwitterAuthenticationState(
+ isLoading: null == isLoading
+ ? _value.isLoading
+ : isLoading // ignore: cast_nullable_to_non_nullable
+ as bool,
+ failureOrUser: null == failureOrUser
+ ? _value.failureOrUser
+ : failureOrUser // ignore: cast_nullable_to_non_nullable
+ as Either,
+ ));
+ }
+}
+
+/// @nodoc
+
+class _$_TwitterAuthenticationState implements _TwitterAuthenticationState {
+ const _$_TwitterAuthenticationState(
+ {this.isLoading = false, this.failureOrUser = const Right(User.empty)});
+
+ @override
+ @JsonKey()
+ final bool isLoading;
+ @override
+ @JsonKey()
+ final Either failureOrUser;
+
+ @override
+ String toString() {
+ return 'TwitterAuthenticationState(isLoading: $isLoading, failureOrUser: $failureOrUser)';
+ }
+
+ @override
+ bool operator ==(dynamic other) {
+ return identical(this, other) ||
+ (other.runtimeType == runtimeType &&
+ other is _$_TwitterAuthenticationState &&
+ (identical(other.isLoading, isLoading) ||
+ other.isLoading == isLoading) &&
+ (identical(other.failureOrUser, failureOrUser) ||
+ other.failureOrUser == failureOrUser));
+ }
+
+ @override
+ int get hashCode => Object.hash(runtimeType, isLoading, failureOrUser);
+
+ @JsonKey(ignore: true)
+ @override
+ @pragma('vm:prefer-inline')
+ _$$_TwitterAuthenticationStateCopyWith<_$_TwitterAuthenticationState>
+ get copyWith => __$$_TwitterAuthenticationStateCopyWithImpl<
+ _$_TwitterAuthenticationState>(this, _$identity);
+}
+
+abstract class _TwitterAuthenticationState
+ implements TwitterAuthenticationState {
+ const factory _TwitterAuthenticationState(
+ {final bool isLoading,
+ final Either failureOrUser}) =
+ _$_TwitterAuthenticationState;
+
+ @override
+ bool get isLoading;
+ @override
+ Either get failureOrUser;
+ @override
+ @JsonKey(ignore: true)
+ _$$_TwitterAuthenticationStateCopyWith<_$_TwitterAuthenticationState>
+ get copyWith => throw _privateConstructorUsedError;
+}
diff --git a/lib/authentication_with_twitter/application/twitter_authentication/twitter_authentication_event.dart b/lib/authentication_with_twitter/application/twitter_authentication/twitter_authentication_event.dart
new file mode 100644
index 0000000..436e721
--- /dev/null
+++ b/lib/authentication_with_twitter/application/twitter_authentication/twitter_authentication_event.dart
@@ -0,0 +1,8 @@
+part of 'twitter_authentication_bloc.dart';
+
+@freezed
+class TwitterAuthenticationEvent with _$TwitterAuthenticationEvent {
+ const factory TwitterAuthenticationEvent.started() = _Started;
+ factory TwitterAuthenticationEvent.signIn() = TwitterSignIn;
+ factory TwitterAuthenticationEvent.signOut() = TwitterSignOut;
+}
diff --git a/lib/authentication_with_twitter/application/twitter_authentication/twitter_authentication_state.dart b/lib/authentication_with_twitter/application/twitter_authentication/twitter_authentication_state.dart
new file mode 100644
index 0000000..61e49fa
--- /dev/null
+++ b/lib/authentication_with_twitter/application/twitter_authentication/twitter_authentication_state.dart
@@ -0,0 +1,13 @@
+// ignore_for_file: inference_failure_on_instance_creation
+
+part of 'twitter_authentication_bloc.dart';
+
+@freezed
+class TwitterAuthenticationState with _$TwitterAuthenticationState {
+ const factory TwitterAuthenticationState({
+ @Default(false) bool isLoading,
+ @Default(Right(User.empty)) Either failureOrUser,
+ }) = _TwitterAuthenticationState;
+
+ factory TwitterAuthenticationState.initial() => TwitterAuthenticationState();
+}
diff --git a/lib/authentication_with_twitter/domain/i_twitter_repository_facade.dart b/lib/authentication_with_twitter/domain/i_twitter_repository_facade.dart
new file mode 100644
index 0000000..3f30531
--- /dev/null
+++ b/lib/authentication_with_twitter/domain/i_twitter_repository_facade.dart
@@ -0,0 +1,8 @@
+import 'package:dartz/dartz.dart';
+import 'package:fpb/core/domain/user.dart';
+import 'package:fpb/core/failures/auth_failure.dart';
+
+abstract class ITwitterRepositoryFacade {
+ Future> signInWithTwitter();
+ Future> signOut();
+}
diff --git a/lib/authentication_with_twitter/infrastructure/twitter_auth_repository.dart b/lib/authentication_with_twitter/infrastructure/twitter_auth_repository.dart
new file mode 100644
index 0000000..6bba13a
--- /dev/null
+++ b/lib/authentication_with_twitter/infrastructure/twitter_auth_repository.dart
@@ -0,0 +1,77 @@
+import 'dart:io';
+
+import 'package:dartz/dartz.dart';
+import 'package:firebase_auth/firebase_auth.dart' hide User;
+import 'package:flutter/services.dart';
+import 'package:fpb/authentication_with_twitter/domain/i_twitter_repository_facade.dart';
+import 'package:fpb/core/domain/user.dart';
+import 'package:fpb/core/failures/auth_failure.dart';
+import 'package:fpb/core/infrastructure/user.dto.dart';
+import 'package:injectable/injectable.dart';
+import 'package:twitter_login/twitter_login.dart';
+
+@LazySingleton(as: ITwitterRepositoryFacade)
+class TwitterAuthenticationRepository implements ITwitterRepositoryFacade {
+ final FirebaseAuth _firebaseAuth;
+
+ TwitterAuthenticationRepository(this._firebaseAuth);
+
+ @override
+ Future> signInWithTwitter() async {
+ try {
+ // Create a TwitterLogin instance
+ final twitterLogin = new TwitterLogin(
+ apiKey: '',
+ apiSecretKey: ' ',
+ redirectURI: '://');
+
+ // Trigger the sign-in flow
+ final authResult = await twitterLogin.login();
+
+ // Create a credential from the access token
+ final twitterAuthCredential = TwitterAuthProvider.credential(
+ accessToken: authResult.authToken!,
+ secret: authResult.authTokenSecret!,
+ );
+
+ final userCredential =
+ await _firebaseAuth.signInWithCredential(twitterAuthCredential);
+
+ final user = userCredential.user;
+
+ if (user == null) {
+ return left(const AuthFailure.userNotFound());
+ }
+
+ return right(UserDTO.fromFirebase(user).toDomain());
+ } on SocketException catch (e) {
+ return left(AuthFailure.fromErrorMessage(e.message));
+ } on PlatformException catch (e) {
+ return left(AuthFailure.fromErrorMessage(e.code));
+ } on FirebaseAuthException catch (e) {
+ return left(AuthFailure.fromErrorMessage(e.code));
+ } on FirebaseException catch (e) {
+ return left(AuthFailure.fromErrorMessage(e.code));
+ }
+ }
+
+ @override
+ Future> signOut() async {
+ try {
+ await Future.wait([
+ _firebaseAuth.signOut(),
+ // _facebookAuth.logOut(),
+ ]);
+
+ return right(unit);
+ } on SocketException catch (e) {
+ return left(AuthFailure.fromErrorMessage(e.message));
+ } on PlatformException catch (e) {
+ return left(AuthFailure.fromErrorMessage(e.code));
+ } on FirebaseAuthException catch (e) {
+ return left(AuthFailure.fromErrorMessage(e.code));
+ } on FirebaseException catch (e) {
+ return left(AuthFailure.fromErrorMessage(e.code));
+ }
+ }
+}
diff --git a/lib/injection.config.dart b/lib/injection.config.dart
index 41bc4d3..3c8ba1d 100644
--- a/lib/injection.config.dart
+++ b/lib/injection.config.dart
@@ -13,49 +13,53 @@ import 'package:firebase_auth/firebase_auth.dart' as _i7;
import 'package:firebase_core/firebase_core.dart' as _i6;
import 'package:flutter_facebook_auth/flutter_facebook_auth.dart' as _i5;
import 'package:fpb/authentication_mock_without_backend/application/bloc/authentication_bloc.dart'
- as _i17;
+ as _i19;
import 'package:fpb/authentication_mock_without_backend/infrastructure/authentication_mock_module_injection.dart'
- as _i30;
+ as _i32;
import 'package:fpb/authentication_with_facebook/application/facebook_auth_bloc.dart'
- as _i19;
+ as _i21;
import 'package:fpb/authentication_with_facebook/domain/i_facebook_repository_facade.dart'
as _i10;
import 'package:fpb/authentication_with_facebook/infrastructure/facebook_auth_repository.dart'
as _i11;
import 'package:fpb/authentication_with_facebook/infrastructure/facebook_authentication_injectable_module.dart'
- as _i32;
+ as _i34;
import 'package:fpb/authentication_with_firebase/application/bloc/auth_bloc.dart'
- as _i24;
+ as _i26;
import 'package:fpb/authentication_with_firebase/domain/i_auth_facade.dart'
- as _i21;
+ as _i23;
import 'package:fpb/authentication_with_firebase/infrastructure/firebase_auth_facade_impl.dart'
- as _i22;
+ as _i24;
import 'package:fpb/authentication_with_firebase/infrastructure/firebase_auth_injectable_module.dart'
- as _i31;
+ as _i33;
import 'package:fpb/authentication_with_google/application/google_auth_bloc/google_sign_in_bloc.dart'
- as _i20;
+ as _i22;
import 'package:fpb/authentication_with_google/domain/i_google_repository_facade.dart'
as _i12;
import 'package:fpb/authentication_with_google/infrastructure/google_authentication_injectable_module.dart'
- as _i28;
+ as _i30;
import 'package:fpb/authentication_with_google/infrastructure/google_authentication_repository.dart'
as _i13;
+import 'package:fpb/authentication_with_twitter/domain/i_twitter_repository_facade.dart'
+ as _i14;
+import 'package:fpb/authentication_with_twitter/infrastructure/twitter_auth_repository.dart'
+ as _i15;
import 'package:fpb/core/application/email_password_bloc/email_password_bloc.dart'
- as _i25;
-import 'package:fpb/core/application/internet_and_time_bloc/internet_and_time_bloc.dart'
as _i27;
-import 'package:fpb/core/infrastructure/core_injectable_module.dart' as _i29;
-import 'package:fpb/core/settings/app_settings_helper.dart' as _i23;
-import 'package:fpb/core/settings/cached.dart' as _i18;
+import 'package:fpb/core/application/internet_and_time_bloc/internet_and_time_bloc.dart'
+ as _i29;
+import 'package:fpb/core/infrastructure/core_injectable_module.dart' as _i31;
+import 'package:fpb/core/settings/app_settings_helper.dart' as _i25;
+import 'package:fpb/core/settings/cached.dart' as _i20;
import 'package:fpb/home/application/home_view_bloc/home_view_bloc.dart'
- as _i26;
+ as _i28;
import 'package:get_it/get_it.dart' as _i1;
import 'package:google_sign_in/google_sign_in.dart' as _i9;
import 'package:injectable/injectable.dart' as _i2;
-import 'package:ntp/ntp.dart' as _i14;
-import 'package:shared_preferences/shared_preferences.dart' as _i15;
+import 'package:ntp/ntp.dart' as _i16;
+import 'package:shared_preferences/shared_preferences.dart' as _i17;
import 'package:user_repository/user_repository.dart'
- as _i16; // ignore_for_file: unnecessary_lambdas
+ as _i18; // ignore_for_file: unnecessary_lambdas
// ignore_for_file: lines_longer_than_80_chars
extension GetItInjectableX on _i1.GetIt {
@@ -103,51 +107,53 @@ extension GetItInjectableX on _i1.GetIt {
gh<_i9.GoogleSignIn>(),
gh<_i7.FirebaseAuth>(),
));
- gh.lazySingleton<_i14.NTP>(() => coreInjectableModule.ntp);
- await gh.factoryAsync<_i15.SharedPreferences>(
+ gh.lazySingleton<_i14.ITwitterRepositoryFacade>(
+ () => _i15.TwitterAuthenticationRepository(gh<_i7.FirebaseAuth>()));
+ gh.lazySingleton<_i16.NTP>(() => coreInjectableModule.ntp);
+ await gh.factoryAsync<_i17.SharedPreferences>(
() => firebaseAuthInjectableModule.sharePreferences,
preResolve: true,
);
- gh.singleton<_i16.UserRepository>(
+ gh.singleton<_i18.UserRepository>(
authenticationMockModuleInjection.userRepository);
- gh.factory<_i17.AuthenticationBloc>(() => _i17.AuthenticationBloc(
+ gh.factory<_i19.AuthenticationBloc>(() => _i19.AuthenticationBloc(
authenticationRepository: gh<_i3.AuthenticationRepository>(),
- userRepository: gh<_i16.UserRepository>(),
+ userRepository: gh<_i18.UserRepository>(),
));
- gh.singleton<_i18.Cached>(_i18.Cached(gh<_i15.SharedPreferences>()));
- gh.factory<_i19.FacebookAuthBloc>(() => _i19.FacebookAuthBloc(
+ gh.singleton<_i20.Cached>(_i20.Cached(gh<_i17.SharedPreferences>()));
+ gh.factory<_i21.FacebookAuthBloc>(() => _i21.FacebookAuthBloc(
authenticationRepository: gh<_i10.IFacebookRepositoryFacade>()));
- gh.factory<_i20.GoogleSignInBloc>(() => _i20.GoogleSignInBloc(
+ gh.factory<_i22.GoogleSignInBloc>(() => _i22.GoogleSignInBloc(
authenticationRepository: gh<_i12.IGoogleRepositoryFacade>()));
- gh.lazySingleton<_i21.IAuthFacade>(() => _i22.FirebaseAuthFacade(
+ gh.lazySingleton<_i23.IAuthFacade>(() => _i24.FirebaseAuthFacade(
gh<_i7.FirebaseAuth>(),
- gh<_i18.Cached>(),
+ gh<_i20.Cached>(),
));
- gh.lazySingleton<_i23.AppSettingsHelper>(() => _i23.AppSettingsHelper(
- gh<_i18.Cached>(),
+ gh.lazySingleton<_i25.AppSettingsHelper>(() => _i25.AppSettingsHelper(
+ gh<_i20.Cached>(),
gh<_i4.Connectivity>(),
));
- gh.factory<_i24.AuthBloc>(() => _i24.AuthBloc(gh<_i21.IAuthFacade>()));
- gh.singleton<_i25.EmailPasswordBloc>(_i25.EmailPasswordBloc(
- authenticationRepository: gh<_i21.IAuthFacade>()));
- gh.factory<_i26.HomeViewBloc>(
- () => _i26.HomeViewBloc(gh<_i23.AppSettingsHelper>()));
- gh.factory<_i27.InternetAndTimeBloc>(
- () => _i27.InternetAndTimeBloc(gh<_i23.AppSettingsHelper>()));
+ gh.factory<_i26.AuthBloc>(() => _i26.AuthBloc(gh<_i23.IAuthFacade>()));
+ gh.singleton<_i27.EmailPasswordBloc>(_i27.EmailPasswordBloc(
+ authenticationRepository: gh<_i23.IAuthFacade>()));
+ gh.factory<_i28.HomeViewBloc>(
+ () => _i28.HomeViewBloc(gh<_i25.AppSettingsHelper>()));
+ gh.factory<_i29.InternetAndTimeBloc>(
+ () => _i29.InternetAndTimeBloc(gh<_i25.AppSettingsHelper>()));
return this;
}
}
class _$GoogleAuthenticationInjectableModule
- extends _i28.GoogleAuthenticationInjectableModule {}
+ extends _i30.GoogleAuthenticationInjectableModule {}
-class _$CoreInjectableModule extends _i29.CoreInjectableModule {}
+class _$CoreInjectableModule extends _i31.CoreInjectableModule {}
class _$AuthenticationMockModuleInjection
- extends _i30.AuthenticationMockModuleInjection {}
+ extends _i32.AuthenticationMockModuleInjection {}
class _$FirebaseAuthInjectableModule
- extends _i31.FirebaseAuthInjectableModule {}
+ extends _i33.FirebaseAuthInjectableModule {}
class _$FacebookAuthenticationInjectableModule
- extends _i32.FacebookAuthenticationInjectableModule {}
+ extends _i34.FacebookAuthenticationInjectableModule {}
diff --git a/lib/onboarding/view/widgets/alternative_auth.dart b/lib/onboarding/view/widgets/alternative_auth.dart
index 2d87d4d..7d96daa 100644
--- a/lib/onboarding/view/widgets/alternative_auth.dart
+++ b/lib/onboarding/view/widgets/alternative_auth.dart
@@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:fpb/assets/fpb_svg.dart';
import 'package:fpb/authentication_with_facebook/application/facebook_auth_bloc.dart';
import 'package:fpb/authentication_with_google/application/google_auth_bloc/google_sign_in_bloc.dart';
+import 'package:fpb/authentication_with_twitter/application/twitter_authentication/twitter_authentication_bloc.dart';
import 'package:fpb/core/presentation/widget/icon_login.dart';
class AlternativeAuth extends StatelessWidget {
@@ -35,7 +36,11 @@ class AlternativeAuth extends StatelessWidget {
IconLogin(
svg: SvgNames.twitter,
box: box,
- onTap: () {},
+ onTap: () {
+ context
+ .read()
+ .add(TwitterAuthenticationEvent.signIn());
+ },
),
IconLogin(
svg: SvgNames.apple,
diff --git a/lib/sign_in/view/sign_in_page.dart b/lib/sign_in/view/sign_in_page.dart
index dec4f9b..e27a3c9 100644
--- a/lib/sign_in/view/sign_in_page.dart
+++ b/lib/sign_in/view/sign_in_page.dart
@@ -10,6 +10,7 @@ import 'package:fpb/authenticate_with_biometrics/application/bloc/biometric_auth
import 'package:fpb/authentication_with_facebook/application/facebook_auth_bloc.dart';
import 'package:fpb/authentication_with_google/application/google_auth_bloc/google_sign_in_bloc.dart';
import 'package:fpb/authentication_with_google/view/loading_indicator.dart';
+import 'package:fpb/authentication_with_twitter/application/twitter_authentication/twitter_authentication_bloc.dart';
import 'package:fpb/core/application/email_password_bloc/email_password_bloc.dart';
import 'package:fpb/core/presentation/extension/extensions.dart';
import 'package:fpb/core/shared/helpers/is_keyboard_visible.dart';
@@ -37,6 +38,9 @@ class SignInScreen extends StatelessWidget {
BlocProvider(
create: (context) => getIt(),
),
+ BlocProvider(
+ create: (context) => getIt(),
+ ),
BlocProvider(
create: (context) => getIt(),
),
diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift
index 4a243f5..1774575 100644
--- a/macos/Flutter/GeneratedPluginRegistrant.swift
+++ b/macos/Flutter/GeneratedPluginRegistrant.swift
@@ -13,6 +13,7 @@ import firebase_core
import flutter_secure_storage_macos
import path_provider_foundation
import shared_preferences_foundation
+import twitter_login
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FLTFirebaseFirestorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseFirestorePlugin"))
@@ -23,4 +24,5 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
+ TwitterLoginPlugin.register(with: registry.registrar(forPlugin: "TwitterLoginPlugin"))
}
diff --git a/pubspec.yaml b/pubspec.yaml
index a9a5515..b4e8a3b 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -46,6 +46,7 @@ dependencies:
google_fonts: ^4.0.3
local_auth: ^2.1.3
flutter_facebook_auth: ^5.0.7
+ twitter_login: ^4.3.1
dev_dependencies:
widgetbook_generator: