I was studying with an AWS tutorial however, that tutorial is not null safety.
I'v tried to convert it, but is showing:
LateInitializationError: Field '_credentials#26120019' has not been initialized.
I think that "late" modifier is not initializing the variables when I try to get the values in verifyCode
Pleease, how can I fix the code below
enum AuthFlowStatus {login, signUp, verification, session}
class AuthState {
final AuthFlowStatus? authFlowStatus;
AuthState({this.authFlowStatus});
}
class AuthService {
final authStateController = StreamController<AuthState>();
late AuthCredentials _credentials;
void showSignUp() {
final state = AuthState(authFlowStatus: AuthFlowStatus.signUp);
authStateController.add(state);
}
void showLogin() {
final state = AuthState(authFlowStatus: AuthFlowStatus.login);
authStateController.add(state);
}
void loginWithCredentials(AuthCredentials credentials) async {
try {
final result = await Amplify.Auth.signIn(
username: credentials.username, password: credentials.password,
);
if (result.isSignedIn) {
final state = AuthState(authFlowStatus: AuthFlowStatus.session);
authStateController.add(state);
} else {
print('User could not be signed in');
}
} on AuthException catch (authError) {
print('Could not login - ${authError}');
}
}
void signUpWithCredentials(SignUpCredentials credentials) async {
try {
Map<CognitoUserAttributeKey, String> userAttributes = {
CognitoUserAttributeKey.email: credentials.email,
};
final result = await Amplify.Auth.signUp(
username: credentials.username,
password: credentials.password,
options: CognitoSignUpOptions(
userAttributes: userAttributes
),
);
if (result.isSignUpComplete) {
loginWithCredentials(credentials);
} else {
this._credentials = credentials;
}
final state = AuthState(authFlowStatus: AuthFlowStatus.verification);
authStateController.add(state);
} on AmplifyException catch (authError) {
print('Failed ro sign up - ${authError}');
}
}
void verifyCode(String verificationCode) async {
try {
final result = await Amplify.Auth.confirmSignUp(
username: _credentials.username,
confirmationCode: verificationCode,
);
if (result.isSignUpComplete) {
loginWithCredentials(_credentials);
} else {
//not implemented yet
}
} on AuthException catch (authError) {
print('Could not verify code - ${authError}');
}
}
}
Related
Event is getting called on button onPressed
BlocProvider.of<ProfileBloc>(context).add(FetchProfile());
I am very new to bloc state management, please help me with this issue.
version flutter_bloc: ^8.0.1, just wanna try if its possible with the newer version.
class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
AuthRepo authRepo;
#override
ProfileBloc(ProfileState initialState, {required this.authRepo})
: super(ProfileLoading()) {
on<FetchProfile>((event, emit) async {
return await fetchProfileEvent(event, emit);
});
}
Future<void> fetchProfileEvent(
FetchProfile event, Emitter<ProfileState> emit) async {
log("$event", name: "eventToState");
emit(ProfileLoading());
try {
await authRepo.getProfileCall().then(
(value) {
log("$value", name: 'FetchProfile');
if (value != 'failed') {
emit(ProfileLoaded(userData: userProfileModelFromJson(value)));
} else {
emit(ProfileLoaded(userData: null));
}
},
);
} catch (e) {
log("$e", name: "ProfileBloc : FetchProfile");
emit(ProfileError());
}
}
}
Try it like this:
class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
AuthRepo authRepo;
#override
ProfileBloc({required this.authRepo})
: super(ProfileLoading()) {
on<FetchProfile>(fetchProfileEvent);
}
Future<void> fetchProfileEvent(
FetchProfile event, Emitter<ProfileState> emit) async {
log("$event", name: "eventToState");
emit(ProfileLoading());
try {
final value = await authRepo.getProfileCall();
log("$value", name: 'FetchProfile');
if (value != 'failed') {
emit(ProfileLoaded(userData: userProfileModelFromJson(value)));
} else {
emit(ProfileLoaded(userData: null));
}
} catch (e) {
log("$e", name: "ProfileBloc : FetchProfile");
emit(ProfileError());
}
}
}
am learning api integration with bloc, these exception is been thrown when data is trying to fetch, for loadingstate i assigned a progressindicator then after that state when trying to get data,these exeption is been thrown ,pls helpenter image description here
as per the console i tried to change the data type to from double to num, still same exception
try {
_emitters.add(emitter);
await handler(event as E, emitter);
} catch (error, stackTrace) {
onError(error, stackTrace);
rethrow;
} finally {
onDone();
}
networkfile.dart
class Repository {
List<FakeStore> collections = [];
Future<List<FakeStore>?> getdata() async {
String url = 'https://fakestoreapi.com/products';
final data = await http.Client().get(Uri.parse(url));
if (data.statusCode != 200) {
return null;
} else {
Iterable values = jsonDecode(data.body);
for (var value in values) {
FakeStore fakeStore = FakeStore.fromJson(value);
collections.add(fakeStore);
}
return collections;
}
}
}
bloc.dart
class FakestoreBloc extends Bloc<FakestoreEvent, FakestoreState> {
final Repository repository;
FakestoreBloc({required this.repository}) : super(FakestoreInitialstate()) {
on<FakestoreEvent>((event, emit) async {
if (event is StorelaodEvent) {
emit(Fakestorelaodingstate());
List<FakeStore>? apiresult = await repository.getdata();
if (apiresult == null) {
emit(FAkestoreErrorstate());
} else {
emit(Fakestoreloadedstate(apiresult: apiresult));
}
}
});
}
}
I have a simple flutter code to retrieve some data from Firestore. the data is retireved correctly, however passing the data from the future function making the result always null. can you advise how to adapt the code to return the list?
that is the class where the actual query is happening:
class DatabaseManager {
final CollectionReference BusinessProfilesCollection =
FirebaseFirestore.instance.collection("BusinessProfilesCollection");
Future GetBusinessProfilesCollection() async {
List businessprofileslist = [];
try {
await BusinessProfilesCollection.get().then((QuerySnapshot) {
QuerySnapshot.docs.forEach((element) {
businessprofileslist.add(element.data());
print(businessprofileslist[0]);
});
});
} catch (e) {
print(e.toString());
return null;
}
}
}
here is the page where I am calling the function: (however the result is always null)
class _ProfilesListPageState extends State<ProfilesListPage> {
List businessprofileslist = [];
#override
void initState() {
super.initState();
fetchBusinessProfilesList();
}
fetchBusinessProfilesList() async {
dynamic result = await DatabaseManager().GetBusinessProfilesCollection();
print(result.toString());
if (result == null) {
print('enable to retieve');
} else {
print('success');
setState(() {
businessprofileslist = result;
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold();
}
}
You're not returning anything from GetBusinessProfilesCollection but null, so the result seems somewhat expected.
I guess you want to do:
class DatabaseManager {
final CollectionReference BusinessProfilesCollection =
FirebaseFirestore.instance.collection("BusinessProfilesCollection");
Future GetBusinessProfilesCollection() async {
List businessprofileslist = [];
try {
var QuerySnapshot = await BusinessProfilesCollection.get();
querySnapshot.docs.forEach((element) {
businessprofileslist.add(element.data());
});
return businessprofileslist;
} catch (e) {
print(e.toString());
return null;
}
}
}
Btw: returning null when the load fails, is just going to lead to a null pointer exception when you then do print(result.toString());. So I recommend not catching the error and just letting it bubble up. With that your code can be simplified to:
class DatabaseManager {
final CollectionReference BusinessProfilesCollection =
FirebaseFirestore.instance.collection("BusinessProfilesCollection");
Future GetBusinessProfilesCollection() async {
var QuerySnapshot = await BusinessProfilesCollection.get();
return querySnapshot.docs.map((element) => element.data());
}
}
You just need to return the list
return businessprofileslist;
CODE :
class DatabaseManager {
final CollectionReference BusinessProfilesCollection =
FirebaseFirestore.instance.collection("BusinessProfilesCollection");
Future GetBusinessProfilesCollection() async {
List businessprofileslist = [];
try {
await BusinessProfilesCollection.get().then((QuerySnapshot) {
QuerySnapshot.docs.forEach((element) {
businessprofileslist.add(element.data());
print(businessprofileslist[0]);
});
// you just need to return the list here after filling it up
return businessprofileslist;
});
} catch (e) {
print(e.toString());
return null;
}
}
}
Code with a little improvement:
class DatabaseManager {
final CollectionReference BusinessProfilesCollection =
FirebaseFirestore.instance.collection("BusinessProfilesCollection");
Future GetBusinessProfilesCollection() async {
await BusinessProfilesCollection.get().then((QuerySnapshot) {
QuerySnapshot.docs.map((doc) => doc.data()).toList();
});
}
}
Try that with calling the function in feching
fetchBusinessProfilesList()
async {
dynamic result ;
await DatabaseManager().GetBusinessProfilesCollection().then((value){
result=value;
print(result.toString());
if (result == null) {
print('enable to retieve');
} else {
print('success');
setState(() {
businessprofileslist = result;
});
}
});
}
How to transfer data from one screen to another using bloc and save , I would like to create a user profile where I have two screens, two steps to creating a profile. I created two blocs for each class, in one I have an avatar, city and name, in the other only description. I used an amplify and when I save the first screen and when I go to the second one, delete the data from the first screen. How do I save everything? without delete? after save second screen.
First screen:
class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
final DataRepository dataRepo;
final StorageRepository storageRepo;
final _picker = ImagePicker();
ProfileBloc(
{User? user,
required bool isCurrentUser,
required this.storageRepo,
required this.dataRepo})
: super(ProfileState(user: user, isCurrentUser: isCurrentUser)) {
// storageRepo
// .getUrlForFile(user!.avatarKey)
// .then((url) => add(ProvideImagePath(avatarPath: url)));
ImageUrlCache.instance
.getUrl(user!.avatarKey)
.then((url) => add(ProvideImagePath(avatarPath: url)));
}
#override
Stream<ProfileState> mapEventToState(ProfileEvent event) async* {
if (event is ChangeAvatarRequest) {
yield state.copyWith(isImageSourceActionSheetVisible: true);
} else if (event is OpenImagePicker) {
yield state.copyWith(isImageSourceActionSheetVisible: false);
try {
final selectedImage =
await _picker.pickImage(source: event.imageSource);
if (selectedImage == null) return;
final imageKey = await storageRepo.uploadFile(File(selectedImage.path));
final user = state.user!.copyWith(avatarKey: imageKey);
String? imageUrl;
await Future.wait<void>([
dataRepo.updateUser(user),
storageRepo.getUrlForFile(imageKey).then((value) => imageUrl = value)
]);
yield state.copyWith(avatarPath: imageUrl);
} catch (e) {
throw e;
}
} else if (event is ProvideImagePath) {
if (event.avatarPath != null)
yield state.copyWith(avatarPath: event.avatarPath);
} else if (event is ProfileCityChanged) {
yield state.copyWith(userCity: event.city);
} else if (event is ProfileNameChanged) {
yield state.copyWith(userName1: event.name);
} else if (event is SaveProfileChanges) {
// handle save changes
yield state.copyWith(formStatus: FormSubmitting());
final updatedUser2 =
state.user!.copyWith(city: state.userCity, name: state.userName1);
try {
await dataRepo.updateUser(updatedUser2);
print(updatedUser2);
yield state.copyWith(formStatus: SubmissionSuccess());
} on Exception catch (e) {
yield state.copyWith(formStatus: SubmissionFailed(e));
} catch (e) {
print(e);
}
}
}
}
Second screen:
class Profile2Bloc extends Bloc<Profile2Event, Profile2State> {
final DataRepository dataRepo;
// User? user;
// String ?get userCity => user!.city;
// String? get userName1 => user!.name;
Profile2Bloc(
{User? user, required bool isCurrentUser, required this.dataRepo})
: super(Profile2State(user: user, isCurrentUser: isCurrentUser));
#override
Stream<Profile2State> mapEventToState(Profile2Event event) async* {
if (event is ProfileDescriptionChanged) {
yield state.copyWith(userDescription: event.description);
} else if (event is SaveProfile2Changes) {
yield state.copyWith(formStatus: FormSubmitting());
final updatedUser =
state.user!.copyWith(description: state.userDescription);
try {
await dataRepo.updateUser(updatedUser);
print(updatedUser);
// print(userDescribe);
yield state.copyWith(formStatus: SubmissionSuccess());
} on Exception catch (e) {
yield state.copyWith(formStatus: SubmissionFailed(e));
} catch (e) {
print(e);
}
}
}
}
Data Repo:
Future<User> updateUser(User updatedUser) async {
try {
await Amplify.DataStore.save(updatedUser);
return updatedUser;
} catch (e) {
throw e;
}
}
I want to implement GraphQL client in my flutter app. For Dependency injection, I use GetIt library. But when I run the app, it says
'Invalid argument (Object of type HomeGraphQLService is not
registered inside GetIt. Did you forget to pass an instance name?
(Did you accidentally do GetIt sl=GetIt.instance(); instead of GetIt
sl=GetIt.instance;)): HomeGraphQLService'
.
It means GraphQL client did not instantiate somehow, although I registered it in my service locator
Session.dart
abstract class Session {
String getAccessToken();
}
SessionImpl.dart
class SessionImpl extends Session {
SharedPreferences sharedPref;
SessionImpl(SharedPreferences sharedPref) {
this.sharedPref = sharedPref;
}
#override
String getAccessToken() {
return sharedPref.getString('access_token') ?? "";
}
}
GraphQLClientGenerator.dart
class GraphQLClientGenerator {
Session session;
GraphQLClientGenerator(Session session) {
this.session = session;
}
GraphQLClient getClient() {
final HttpLink httpLink = HttpLink('https://xxx/graphql');
final AuthLink authLink = AuthLink(getToken: () async => 'Bearer ${_getAccessToken()}');
final Link link = authLink.concat(httpLink);
return GraphQLClient(link: link, cache: GraphQLCache(store: InMemoryStore()));
}
String _getAccessToken() {
return session.getAccessToken();
}
}
HomeRepository.dart
abstract class HomeRepository {
Future<List<Course>> getAllCourseOf(String className, String groupName);
}
HomeRepositoryImpl.dart
class HomeRepositoryImpl extends HomeRepository {
HomeGraphQLService homeGraphQLService;
HomeMapper homeMapper;
HomeRepositoryImpl(HomeGraphQLService homeGraphQLService, HomeMapper homeMapper) {
this.homeGraphQLService = homeGraphQLService;
this.homeMapper = homeMapper;
}
#override
Future<List<Course>> getAllCourseOf(String className, String groupName) async {
final response = await homeGraphQLService.getAllCourseOf(className, groupName);
return homeMapper.toCourses(response).where((course) => course.isAvailable);
}
}
HomeGraphQLService.dart
class HomeGraphQLService {
GraphQLClient graphQLClient;
HomeGraphQLService(GraphQLClient graphQLClient) {
this.graphQLClient = graphQLClient;
}
Future<SubjectResponse> getAllCourseOf(String className, String groupName) async {
try {
final response = await graphQLClient.query(getAllCourseQuery(className, groupName));
return SubjectResponse.fromJson((response.data));
} catch (e) {
return Future.error(e);
}
}
}
GraphQuery.dart
QueryOptions getAllCourseQuery(String className, String groupName) {
String query = """
query GetSubject($className: String, $groupName: String) {
subjects(class: $className, group: $groupName) {
code
display
insights {
coming_soon
purchased
}
}
}
""";
return QueryOptions(
document: gql(query),
variables: <String, dynamic>{
'className': className,
'groupName': groupName,
},
);
}
ServiceLocator.dart
final serviceLocator = GetIt.instance;
Future<void> initDependencies() async {
await _initSharedPref();
_initSession();
_initGraphQLClient();
_initGraphQLService();
_initMapper();
_initRepository();
}
Future<void> _initSharedPref() async {
SharedPreferences sharedPref = await SharedPreferences.getInstance();
serviceLocator.registerSingleton<SharedPreferences>(sharedPref);
}
void _initSession() {
serviceLocator.registerLazySingleton<Session>(()=>SessionImpl(serviceLocator()));
}
void _initGraphQLClient() {
serviceLocator.registerLazySingleton<GraphQLClient>(() => GraphQLClientGenerator(serviceLocator()).getClient());
}
void _initGraphQLService() {
serviceLocator.registerLazySingleton<HomeGraphQLService>(() => HomeGraphQLService(serviceLocator()));
}
void _initMapper() {
serviceLocator.registerLazySingleton<HomeMapper>(() => HomeMapper());
}
void _initRepository() {
serviceLocator.registerLazySingleton<HomeRepository>(() => HomeRepositoryImpl(serviceLocator(), serviceLocator()));
}
main.dart
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setPreferredOrientations(
[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown],
);
await initDependencies();
runApp(MyApp());
}
I cannot say where exactly it is happening because it is elsewhere in your code where you are accessing the GraphQLService, but the problem is definitely due to the lazy loading. The object has not been created and loaded by the locator before it is being accessed. Try updating ServiceLocator.dart to instantiate the classes during registration, like so:
void _initSession() {
serviceLocator.registerSingleton<Session>.(SessionImpl(serviceLocator()));
}
void _initGraphQLClient() {
serviceLocator.registerSingleton<GraphQLClient>(
GraphQLClientGenerator(serviceLocator()).getClient());
}
void _initGraphQLService() {
serviceLocator.registerSingleton<HomeGraphQLService>(
HomeGraphQLService(serviceLocator()));
}
void _initMapper() {
serviceLocator.registerSingleton<HomeMapper>(HomeMapper());
}
void _initRepository() {
serviceLocator.registerSingleton<HomeRepository>(
HomeRepositoryImpl(serviceLocator(), serviceLocator()));
}