diff --git a/lib/authentication/service/auth_provider.dart b/lib/authentication/service/auth_provider.dart index 3dc28202d..3f3c52f82 100644 --- a/lib/authentication/service/auth_provider.dart +++ b/lib/authentication/service/auth_provider.dart @@ -1,7 +1,9 @@ import 'dart:async'; +import 'dart:typed_data'; import 'package:acs_upb_mobile/authentication/model/user.dart'; import 'package:acs_upb_mobile/generated/l10n.dart'; +import 'package:acs_upb_mobile/resources/storage/storage_provider.dart'; import 'package:acs_upb_mobile/resources/validator.dart'; import 'package:acs_upb_mobile/widgets/toast.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; @@ -466,4 +468,23 @@ class AuthProvider with ChangeNotifier { return false; } } + + Future uploadProfilePicture( + Uint8List file, BuildContext context) async { + final result = await StorageProvider.uploadImage( + context, file, 'users/${_firebaseUser.uid}/picture.png'); + if (!result) { + if (file.length > 5 * 1024 * 1024) { + AppToast.show(S.of(context).errorPictureSizeToBig); + } else { + AppToast.show(S.of(context).errorSomethingWentWrong); + } + } + return result; + } + + Future getProfilePictureURL({BuildContext context}) { + return StorageProvider.findImageUrl( + context, 'users/${_firebaseUser.uid}/picture.png'); + } } diff --git a/lib/authentication/view/edit_profile_page.dart b/lib/authentication/view/edit_profile_page.dart index 68703bcbd..a16a9de16 100644 --- a/lib/authentication/view/edit_profile_page.dart +++ b/lib/authentication/view/edit_profile_page.dart @@ -1,18 +1,26 @@ +import 'dart:typed_data'; +import 'dart:ui'; + import 'package:acs_upb_mobile/authentication/model/user.dart'; import 'package:acs_upb_mobile/authentication/service/auth_provider.dart'; + import 'package:acs_upb_mobile/generated/l10n.dart'; import 'package:acs_upb_mobile/pages/filter/view/filter_dropdown.dart'; +import 'package:acs_upb_mobile/resources/storage/storage_provider.dart'; import 'package:acs_upb_mobile/resources/utils.dart'; import 'package:acs_upb_mobile/resources/validator.dart'; import 'package:acs_upb_mobile/widgets/button.dart'; +import 'package:acs_upb_mobile/widgets/circle_image.dart'; import 'package:acs_upb_mobile/widgets/dialog.dart'; import 'package:acs_upb_mobile/widgets/icon_text.dart'; import 'package:acs_upb_mobile/widgets/scaffold.dart'; import 'package:acs_upb_mobile/widgets/toast.dart'; import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:preferences/preference_title.dart'; import 'package:provider/provider.dart'; +import 'package:image/image.dart' as im; class EditProfilePage extends StatefulWidget { const EditProfilePage({Key key}) : super(key: key); @@ -29,6 +37,17 @@ class _EditProfilePageState extends State { final formKey = GlobalKey(); + Uint8List uploadedImage; + ImageProvider imageWidget; + + @override + void initState() { + super.initState(); + final authProvider = Provider.of(context, listen: false); + authProvider.getProfilePictureURL(context: context).then((value) => + setState(() => {if (value != null) imageWidget = NetworkImage(value)})); + } + AppDialog _changePasswordDialog(BuildContext context) { final newPasswordController = TextEditingController(); final oldPasswordController = TextEditingController(); @@ -203,6 +222,38 @@ class _EditProfilePageState extends State { ); } + Widget buildEditableAvatar(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(8), + child: GestureDetector( + child: CircleImage( + circleSize: 150, + image: imageWidget ?? + const AssetImage('assets/illustrations/undraw_profile_pic.png'), + enableOverlay: true, + overlayIcon: const Icon(Icons.edit)), + onTap: () async { + final Uint8List uploadedImage = + await StorageProvider.showImagePicker(); + setState(() { + if (uploadedImage != null) { + this.uploadedImage = uploadedImage; + imageWidget = MemoryImage(uploadedImage); + } else { + AppToast.show(S.of(context).errorImage); + } + }); + }, + ), + ); + } + + Future convertToPNG(Uint8List image) async { + final decodedImage = im.decodeImage(image); + return im.encodePng(im.copyResize(decodedImage, width: 500, height: 500), + level: 9); + } + @override Widget build(BuildContext context) { final authProvider = Provider.of(context); @@ -210,6 +261,7 @@ class _EditProfilePageState extends State { final User user = authProvider.currentUserFromCache; lastNameController.text = user.lastName; firstNameController.text = user.firstName; + Uint8List imageAsPNG; if (!authProvider.isVerifiedFromCache) { emailController.text = authProvider.email.split('@')[0]; } @@ -239,6 +291,14 @@ class _EditProfilePageState extends State { child: _changeEmailConfirmationDialog(context)) .then((value) => result = value ?? false); } + if (uploadedImage != null) { + imageAsPNG = await convertToPNG(uploadedImage); + result = await authProvider.uploadProfilePicture( + imageAsPNG, context); + if (result) { + AppToast.show(S.of(context).messagePictureUpdatedSuccess); + } + } if (result) { if (await authProvider.updateProfile( info: info, @@ -265,6 +325,7 @@ class _EditProfilePageState extends State { child: Container( child: ListView(children: [ AccountNotVerifiedWarning(), + buildEditableAvatar(context), PreferenceTitle( S.of(context).labelPersonalInformation, leftPadding: 0, diff --git a/lib/generated/intl/messages_en.dart b/lib/generated/intl/messages_en.dart index bd65473fd..d4cfe1604 100644 --- a/lib/generated/intl/messages_en.dart +++ b/lib/generated/intl/messages_en.dart @@ -83,6 +83,7 @@ class MessageLookup extends MessageLookupByLibrary { "errorEmailInUse" : MessageLookupByLibrary.simpleMessage("There is already an account associated with this e-mail address"), "errorEmailNotFound" : MessageLookupByLibrary.simpleMessage("An account associated with that e-mail could not be found. Please sign up instead."), "errorEventTypeCannotBeEmpty" : MessageLookupByLibrary.simpleMessage("Event type cannot be empty."), + "errorImage" : MessageLookupByLibrary.simpleMessage("The image could not be loaded."), "errorIncorrectPassword" : MessageLookupByLibrary.simpleMessage("The password you entered is incorrect."), "errorInvalidEmail" : MessageLookupByLibrary.simpleMessage("You need to provide a valid e-mail address."), "errorMissingFirstName" : MessageLookupByLibrary.simpleMessage("Please provide your first name(s)."), @@ -90,6 +91,7 @@ class MessageLookup extends MessageLookupByLibrary { "errorNoPassword" : MessageLookupByLibrary.simpleMessage("You need to provide a password."), "errorPasswordsDiffer" : MessageLookupByLibrary.simpleMessage("The two passwords differ."), "errorPermissionDenied" : MessageLookupByLibrary.simpleMessage("You do not have permission to do that."), + "errorPictureSizeToBig" : MessageLookupByLibrary.simpleMessage("Please select a picture that is less than 5MB."), "errorSomethingWentWrong" : MessageLookupByLibrary.simpleMessage("Something went wrong."), "errorTooManyRequests" : MessageLookupByLibrary.simpleMessage("There have been too many requests from this device."), "fileAcsBanner" : MessageLookupByLibrary.simpleMessage("assets/images/acs_banner_en.png"), @@ -182,6 +184,7 @@ class MessageLookup extends MessageLookupByLibrary { "messageNewUser" : MessageLookupByLibrary.simpleMessage("New user?"), "messageNoClassesYet" : MessageLookupByLibrary.simpleMessage("You have not added any classes yet."), "messageNotLoggedIn" : MessageLookupByLibrary.simpleMessage("You need to be logged in to perform this action."), + "messagePictureUpdatedSuccess" : MessageLookupByLibrary.simpleMessage("Profile picture updated successfully."), "messageRequestAlreadyExists" : MessageLookupByLibrary.simpleMessage("You have already submitted a request. If you want to add another one, please press \'Send\'."), "messageRequestHasBeenSent" : MessageLookupByLibrary.simpleMessage("The request has been sent succesfully."), "messageResetPassword" : MessageLookupByLibrary.simpleMessage("Enter your e-mai in order to receive instructions on how to reset your password."), diff --git a/lib/generated/intl/messages_ro.dart b/lib/generated/intl/messages_ro.dart index 9963f83c9..76cc454cf 100644 --- a/lib/generated/intl/messages_ro.dart +++ b/lib/generated/intl/messages_ro.dart @@ -83,6 +83,7 @@ class MessageLookup extends MessageLookupByLibrary { "errorEmailInUse" : MessageLookupByLibrary.simpleMessage("Există deja un cont asociat acestui e-mail."), "errorEmailNotFound" : MessageLookupByLibrary.simpleMessage("Nu am putut găsi un cont asociat cu adresa de mail. Vă rugăm să vă înregistrați."), "errorEventTypeCannotBeEmpty" : MessageLookupByLibrary.simpleMessage("Tipul de eveniment trebuie precizat."), + "errorImage" : MessageLookupByLibrary.simpleMessage("Imaginea nu putut fi încărcată."), "errorIncorrectPassword" : MessageLookupByLibrary.simpleMessage("Parola introdusă nu este corectă."), "errorInvalidEmail" : MessageLookupByLibrary.simpleMessage("Trebuie să introduceți un e-mail valid."), "errorMissingFirstName" : MessageLookupByLibrary.simpleMessage("Introduceți prenumele."), @@ -90,6 +91,7 @@ class MessageLookup extends MessageLookupByLibrary { "errorNoPassword" : MessageLookupByLibrary.simpleMessage("Trebuie să introduceți parola."), "errorPasswordsDiffer" : MessageLookupByLibrary.simpleMessage("Cele două parole diferă."), "errorPermissionDenied" : MessageLookupByLibrary.simpleMessage("Nu aveți suficiente permisiuni."), + "errorPictureSizeToBig" : MessageLookupByLibrary.simpleMessage("Selectați o fotografie care are mai puțin de 5MB."), "errorSomethingWentWrong" : MessageLookupByLibrary.simpleMessage("A apărut o problemă."), "errorTooManyRequests" : MessageLookupByLibrary.simpleMessage("Au fost trimise prea multe cereri de pe acest dispozitiv."), "fileAcsBanner" : MessageLookupByLibrary.simpleMessage("assets/images/acs_banner_ro.png"), @@ -182,6 +184,7 @@ class MessageLookup extends MessageLookupByLibrary { "messageNewUser" : MessageLookupByLibrary.simpleMessage("Utilizator nou?"), "messageNoClassesYet" : MessageLookupByLibrary.simpleMessage("Nu ați adăugat nici o materie încă."), "messageNotLoggedIn" : MessageLookupByLibrary.simpleMessage("Trebuie să fiți autentificat pentru a realiza această acțiune."), + "messagePictureUpdatedSuccess" : MessageLookupByLibrary.simpleMessage("Poza a fost actualizată cu succes."), "messageRequestAlreadyExists" : MessageLookupByLibrary.simpleMessage("Ați trimis deja o cerere. Daca doriți să adăugați una nouă, vă rugăm sa apasați \'Salvare\'."), "messageRequestHasBeenSent" : MessageLookupByLibrary.simpleMessage("Cererea a fost transmisă cu succes"), "messageResetPassword" : MessageLookupByLibrary.simpleMessage("Introduceți mail-ul pentru a primi instrucțiuni de resetare a parolei."), diff --git a/lib/generated/l10n.dart b/lib/generated/l10n.dart index da98d5ebc..bbb060e50 100644 --- a/lib/generated/l10n.dart +++ b/lib/generated/l10n.dart @@ -9,6 +9,8 @@ import 'intl/messages_all.dart'; // ************************************************************************** // ignore_for_file: non_constant_identifier_names, lines_longer_than_80_chars +// ignore_for_file: join_return_with_assignment, prefer_final_in_for_each +// ignore_for_file: avoid_redundant_argument_values class S { S(); @@ -1103,6 +1105,26 @@ class S { ); } + /// `Please select a picture that is less than 5MB.` + String get errorPictureSizeToBig { + return Intl.message( + 'Please select a picture that is less than 5MB.', + name: 'errorPictureSizeToBig', + desc: '', + args: [], + ); + } + + /// `The image could not be loaded.` + String get errorImage { + return Intl.message( + 'The image could not be loaded.', + name: 'errorImage', + desc: '', + args: [], + ); + } + /// `Request already exists` String get warningRequestExists { return Intl.message( @@ -2263,6 +2285,16 @@ class S { ); } + /// `Profile picture updated successfully.` + String get messagePictureUpdatedSuccess { + return Intl.message( + 'Profile picture updated successfully.', + name: 'messagePictureUpdatedSuccess', + desc: '', + args: [], + ); + } + /// `Please check your inbox for the password reset e-mail.` String get infoPasswordResetEmailSent { return Intl.message( diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index a95af7f6c..5772efe1a 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -112,6 +112,8 @@ "errorPermissionDenied": "You do not have permission to do that.", "errorEventTypeCannotBeEmpty": "Event type cannot be empty.", "errorClassCannotBeEmpty": "Class cannot be empty.", + "errorPictureSizeToBig": "Please select a picture that is less than 5MB.", + "errorImage": "The image could not be loaded.", "warningRequestExists": "Request already exists", "warningInternetConnection": "Please make sure you are connected to the internet.", @@ -237,6 +239,7 @@ "messageAgreePermissions": "I will only upload information that is correct and accurate, to the best of my knowledge. I understand that submitting erroneous or offensive information on purpose will lead to my editing permissions being permanently revoked.", "messageYouCanContribute": "You can contribute to the app data, but you first need to request permissions.", "messageThereAreNoEventsForSelected": "There are no events for the selected ", + "messagePictureUpdatedSuccess": "Profile picture updated successfully.", "infoPasswordResetEmailSent": "Please check your inbox for the password reset e-mail.", "infoRelevance": "Try to choose the most restrictive category.", diff --git a/lib/l10n/intl_ro.arb b/lib/l10n/intl_ro.arb index 3a82c930d..0ac373f5b 100644 --- a/lib/l10n/intl_ro.arb +++ b/lib/l10n/intl_ro.arb @@ -112,6 +112,8 @@ "errorPermissionDenied": "Nu aveți suficiente permisiuni.", "errorEventTypeCannotBeEmpty": "Tipul de eveniment trebuie precizat.", "errorClassCannotBeEmpty": "Materia trebuie precizată.", + "errorPictureSizeToBig": "Selectați o fotografie care are mai puțin de 5MB.", + "errorImage": "Imaginea nu putut fi încărcată.", "warningRequestExists": "O cerere deja există", "warningInternetConnection": "Asigurați-vă că sunteți conectat la internet.", @@ -120,7 +122,7 @@ "warningPasswordUppercase": "Parola trebuie să conțină cel putin o majusculă.", "warningPasswordLowercase": "Parola trebuie să conțină cel putin o minusculă.", "warningPasswordSpecialCharacters": "Parola trebuie să conțină cel puțin un simbol.", - "warningPasswordNumber" :"Parola trebuie să conțină cel puțin un număr.", + "warningPasswordNumber": "Parola trebuie să conțină cel puțin un număr.", "warningEmailInUse": "Există deja un cont asociat cu adresa {email}.", "warningUseProvider": "Folosiți {provider} pentru a vă conecta.", "warningTryAgainLater": "Încercați mai târziu.", @@ -197,7 +199,7 @@ "messageWelcomeSimple": "Bine ai venit!", "messageWelcomeName": "Bine ai venit, {name}!", - "messageNewUser":"Utilizator nou?", + "messageNewUser": "Utilizator nou?", "messageEmailNotVerified": "Contul nu este verificat.", "messageNotLoggedIn": "Trebuie să fiți autentificat pentru a realiza această acțiune.", "messageEmailNotVerifiedToPerformAction": "Contul trebuie să fie verificat pentru a realiza această acțiune.", @@ -237,6 +239,7 @@ "messageAgreePermissions": "Voi încărca doar informații corecte si precise. Înțeleg că încărcarea informațiilor eronate sau ofensatoare în mod intenționat va conduce la blocarea permisiunilor mele permanent.", "messageYouCanContribute": "Poți contribui la datele din aplicație, dar trebuie mai întâi să ceri permisiuni.", "messageThereAreNoEventsForSelected": "Nu există evenimente pentru selecția de ", + "messagePictureUpdatedSuccess": "Poza a fost actualizată cu succes.", "infoPasswordResetEmailSent": "Please check your inbox for the password reset e-mail.", "infoRelevance": "Încercați să selectați cea mai restrictivă categorie.", diff --git a/lib/pages/home/profile_card.dart b/lib/pages/home/profile_card.dart index dfe6deb6a..126127e8c 100644 --- a/lib/pages/home/profile_card.dart +++ b/lib/pages/home/profile_card.dart @@ -6,7 +6,25 @@ import 'package:acs_upb_mobile/resources/utils.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -class ProfileCard extends StatelessWidget { +class ProfileCard extends StatefulWidget { + @override + _ProfileCardState createState() => _ProfileCardState(); +} + +class _ProfileCardState extends State { + String profilePictureURL; + + @override + void initState() { + super.initState(); + final authProvider = Provider.of(context, listen: false); + authProvider + .getProfilePictureURL(context: context) + .then((value) => setState(() { + profilePictureURL = value; + })); + } + @override Widget build(BuildContext context) { final authProvider = Provider.of(context); @@ -28,14 +46,16 @@ class ProfileCard extends StatelessWidget { Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ - const Padding( - padding: EdgeInsets.symmetric(horizontal: 8), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), child: CircleAvatar( - radius: 40, - child: Image( - image: AssetImage( - 'assets/illustrations/undraw_profile_pic.png')), - ), + radius: 40, + backgroundImage: + user != null && profilePictureURL != null + ? NetworkImage(profilePictureURL) + : const AssetImage( + 'assets/illustrations/undraw_profile_pic.png', + )), ), Expanded( child: Padding( diff --git a/lib/resources/storage/mobile_storage.dart b/lib/resources/storage/mobile_storage.dart index f73152aa3..bcf719386 100644 --- a/lib/resources/storage/mobile_storage.dart +++ b/lib/resources/storage/mobile_storage.dart @@ -1,3 +1,6 @@ +import 'dart:typed_data'; + +import 'package:image_picker/image_picker.dart'; import 'package:firebase_storage/firebase_storage.dart'; import 'package:flutter/cupertino.dart'; @@ -11,4 +14,29 @@ class StorageProvider { return null; } } + + static Future uploadImage( + BuildContext context, Uint8List file, String ref) async { + try { + final StorageReference reference = + FirebaseStorage.instance.ref().child(ref); + bool result = false; + final StorageUploadTask uploadTask = reference.putData(file); + await uploadTask.onComplete.whenComplete(() => result = true).catchError( + (dynamic error) => + print('Mobile_Storage - StorageUploadTask - uploadImage $error')); + return result; + } catch (e) { + return false; + } + } + + static Future showImagePicker() async { + final pickedFile = await ImagePicker() + .getImage(source: ImageSource.gallery, maxHeight: 500, maxWidth: 500); + if (pickedFile == null) { + return null; + } + return pickedFile.readAsBytes(); + } } diff --git a/lib/resources/storage/unsupported_storage.dart b/lib/resources/storage/unsupported_storage.dart index ee7eb4365..989548fe2 100644 --- a/lib/resources/storage/unsupported_storage.dart +++ b/lib/resources/storage/unsupported_storage.dart @@ -1,3 +1,5 @@ +import 'dart:typed_data'; + import 'package:flutter/cupertino.dart'; class StorageProvider extends ChangeNotifier { @@ -5,4 +7,15 @@ class StorageProvider extends ChangeNotifier { final Error error = ArgumentError('Platform not found!'); throw error; } + + static Future uploadImage( + BuildContext context, Uint8List file, String ref) async { + final Error error = ArgumentError('Platform not found!'); + throw error; + } + + static Future showImagePicker() async { + final Error error = ArgumentError('Platform not found!'); + throw error; + } } diff --git a/lib/resources/storage/web_storage.dart b/lib/resources/storage/web_storage.dart index 8dab43322..3146beb31 100644 --- a/lib/resources/storage/web_storage.dart +++ b/lib/resources/storage/web_storage.dart @@ -1,3 +1,7 @@ +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:image_picker_web/image_picker_web.dart'; import 'package:firebase/firebase.dart'; import 'package:flutter/cupertino.dart'; @@ -10,4 +14,28 @@ class StorageProvider { return null; } } + + static Future uploadImage( + BuildContext context, Uint8List file, String ref) async { + try { + final StorageReference storageReference = storage().ref('').child(ref); + + bool result; + await storageReference + .put(file) + .future + .whenComplete(() => result = true) + .catchError((dynamic error) => + print('Web_Storage - StorageUploadTask - uploadImage $error')); + return result; + } catch (e) { + return false; + } + } + + static Future showImagePicker() async { + final Uint8List image = + await ImagePickerWeb.getImage(outputType: ImageType.bytes); + return image; + } } diff --git a/pubspec.lock b/pubspec.lock index 09b0ba9b2..44ba1ced1 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -456,7 +456,7 @@ packages: source: hosted version: "3.1.4" image: - dependency: transitive + dependency: "direct main" description: name: image url: "https://pub.dartlang.org" @@ -476,6 +476,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.1" + image_picker_web: + dependency: "direct main" + description: + name: image_picker_web + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.9" interval_time_picker: dependency: "direct main" description: @@ -545,7 +552,7 @@ packages: name: mockito url: "https://pub.dartlang.org" source: hosted - version: "4.1.2" + version: "4.1.3" nested: dependency: transitive description: @@ -615,7 +622,7 @@ packages: name: path_provider url: "https://pub.dartlang.org" source: hosted - version: "1.6.21" + version: "1.6.22" path_provider_linux: dependency: transitive description: @@ -900,14 +907,14 @@ packages: name: url_launcher url: "https://pub.dartlang.org" source: hosted - version: "5.7.5" + version: "5.7.8" url_launcher_linux: dependency: transitive description: name: url_launcher_linux url: "https://pub.dartlang.org" source: hosted - version: "0.0.1+1" + version: "0.0.1+3" url_launcher_macos: dependency: transitive description: @@ -928,7 +935,7 @@ packages: name: url_launcher_web url: "https://pub.dartlang.org" source: hosted - version: "0.1.4+1" + version: "0.1.5" url_launcher_windows: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index e2b8a5a54..717df9d33 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -13,7 +13,7 @@ description: A mobile application for students at ACS UPB. # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # # ACS UPB Mobile uses semantic versioning. You can read more in the CONTRIBUTING.md file. -version: 1.1.4+3 +version: 1.2.0+1 environment: sdk: ">=2.7.0 <3.0.0" @@ -103,6 +103,12 @@ dependencies: # Image importer image_picker: ^0.6.7+4 + # Web image importer + image_picker_web: ^1.0.9 + + # Image decoder + image: ^2.1.18 + # Web scraper web_scraper: ^0.0.6 diff --git a/test/authentication_test.dart b/test/authentication_test.dart index ce4e3a472..23e094dd0 100644 --- a/test/authentication_test.dart +++ b/test/authentication_test.dart @@ -61,6 +61,8 @@ void main() { .thenAnswer((realInvocation) => Future.value(false)); when(mockAuthProvider.currentUser).thenAnswer((_) => Future.value(null)); when(mockAuthProvider.isAnonymous).thenReturn(true); + when(mockAuthProvider.getProfilePictureURL(context: anyNamed('context'))) + .thenAnswer((realInvocation) => Future.value(null)); mockWebsiteProvider = MockWebsiteProvider(); // ignore: invalid_use_of_protected_member diff --git a/test/integration_test.dart b/test/integration_test.dart index 36e08e598..7d9e75802 100644 --- a/test/integration_test.dart +++ b/test/integration_test.dart @@ -147,6 +147,8 @@ void main() { when(mockWebsiteProvider.hasListeners).thenReturn(false); when(mockWebsiteProvider.deleteWebsite(any, context: anyNamed('context'))) .thenAnswer((realInvocation) => Future.value(true)); + when(mockAuthProvider.getProfilePictureURL(context: anyNamed('context'))) + .thenAnswer((realInvocation) => Future.value(null)); when(mockWebsiteProvider.fetchWebsites(any)) .thenAnswer((_) => Future.value([ Website( @@ -1428,7 +1430,6 @@ void main() { }); } }); - group('Edit Profile', () { setUp(() { when(mockAuthProvider.isVerifiedFromCache).thenReturn(false); @@ -1443,6 +1444,8 @@ void main() { when(mockAuthProvider.currentUserFromCache).thenReturn(User( uid: '1', firstName: 'John', lastName: 'Doe', permissionLevel: 3)); when(mockAuthProvider.email).thenReturn('john.doe@stud.acs.upb.ro'); + when(mockAuthProvider.getProfilePictureURL(context: anyNamed('context'))) + .thenAnswer((realInvocation) => Future.value(null)); }); for (final size in screenSizes) { diff --git a/test/settings_test.dart b/test/settings_test.dart index 4e8b909f0..9f533dd85 100644 --- a/test/settings_test.dart +++ b/test/settings_test.dart @@ -57,6 +57,8 @@ void main() { .thenAnswer((realInvocation) => Future.value(true)); when(mockAuthProvider.currentUser).thenAnswer((_) => Future.value(null)); when(mockAuthProvider.isAnonymous).thenReturn(true); + when(mockAuthProvider.getProfilePictureURL(context: anyNamed('context'))) + .thenAnswer((realInvocation) => Future.value(null)); mockWebsiteProvider = MockWebsiteProvider(); // ignore: invalid_use_of_protected_member