From 4a1d36edfae944ce678d65a7afa3029c850e0493 Mon Sep 17 00:00:00 2001 From: D Date: Sat, 20 Mar 2021 16:31:19 +0530 Subject: [PATCH 1/2] Added image picker --- android/app/src/main/AndroidManifest.xml | 2 + ios/Runner/Info.plist | 4 + lib/screens/profile_screen.dart | 117 +++++++++------ lib/services/user_db_services.dart | 11 ++ lib/services/user_info_services.dart | 6 + lib/widgets/header.dart | 38 ++--- .../signup_form_additional_details.dart | 14 ++ pubspec.lock | 135 +++++++++++++++++- pubspec.yaml | 3 + 9 files changed, 267 insertions(+), 63 deletions(-) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 1af2befef7..7805d4c420 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -8,6 +8,8 @@ diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index a508656d4a..ee2ba91b95 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -2,6 +2,10 @@ + + NSPhotoLibraryUsageDescription + Access gallery to pick image + CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable diff --git a/lib/screens/profile_screen.dart b/lib/screens/profile_screen.dart index 84f911654b..f3ba472a58 100644 --- a/lib/screens/profile_screen.dart +++ b/lib/screens/profile_screen.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:class_manager/constants.dart'; import 'package:class_manager/models/users.dart'; import 'package:class_manager/screens/onboarding_page.dart'; @@ -6,8 +8,11 @@ import 'package:class_manager/services/facebookAuthentication.dart'; import 'package:class_manager/services/googleAuthentication.dart'; import 'package:class_manager/services/user_info_services.dart'; import 'package:firebase_auth/firebase_auth.dart'; +import 'package:firebase_storage/firebase_storage.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:path/path.dart' as Path; class ProfileScreen extends StatefulWidget { @override @@ -15,16 +20,55 @@ class ProfileScreen extends StatefulWidget { } class _ProfileScreenState extends State { + ImagePicker _imagePicker = ImagePicker(); + Reference _storageReference = FirebaseStorage.instance.ref(); + + void getImage() async { + PickedFile image = await _imagePicker.getImage(source: ImageSource.gallery); + + if (image == null) { + return; + } + + String imagePath = image.path; + + File file = File(imagePath); + + uploadPictures(file); + } + + uploadPictures(File image) async { + // uploads picture(s) to storage and return it's URL + final Reference ref = + _storageReference.child('${Path.basename(image.path)}}'); + + final UploadTask uploadTask = ref.putFile(image); + // final TaskSnapshot storageTaskSnapshot = + String pictureUrl; + await uploadTask.then((taskSnapshot) async { + pictureUrl = await taskSnapshot.ref.getDownloadURL(); + }); + + final userInfoProvider = + Provider.of(context, listen: false); + + Users currentUser = userInfoProvider.user; + currentUser.profilePictureUrl = pictureUrl; + + userInfoProvider.setUser(currentUser); + + userInfoProvider.upateProfilePictureUrl(); + + // return pictureUrl; + } + @override Widget build(BuildContext context) { final FirebaseAuth firebaseAuth = FirebaseAuth.instance; final User userData = firebaseAuth.currentUser; return Scaffold( - backgroundColor: Theme - .of(context) - .backgroundColor - .withOpacity(0.8), + backgroundColor: Theme.of(context).backgroundColor.withOpacity(0.8), body: SingleChildScrollView( physics: AlwaysScrollableScrollPhysics(parent: BouncingScrollPhysics()), child: Consumer( @@ -36,17 +80,12 @@ class _ProfileScreenState extends State { children: [ Column( children: [ - SizedBox(height: 0.15 * MediaQuery - .of(context) - .size - .height), + SizedBox(height: 0.15 * MediaQuery.of(context).size.height), Container( margin: EdgeInsets.fromLTRB(15, 15, 15, 60), padding: EdgeInsets.all(30), decoration: BoxDecoration( - color: Theme - .of(context) - .primaryColor, + color: Theme.of(context).primaryColor, borderRadius: BorderRadius.only( topLeft: Radius.circular(40), topRight: Radius.circular(40), @@ -139,8 +178,9 @@ class _ProfileScreenState extends State { // For Sign Out from Google Auth or Facebook Auth, Back to the On Boarding Page Navigator.pushAndRemoveUntil( context, - MaterialPageRoute(builder: (_) => OnboardingPage()), - (Route route) => false, + MaterialPageRoute( + builder: (_) => OnboardingPage()), + (Route route) => false, ); } } @@ -151,18 +191,10 @@ class _ProfileScreenState extends State { horizontal: 20, vertical: 10), shape: StadiumBorder(), color: Colors.transparent, - hoverColor: Theme - .of(context) - .primaryColor, - splashColor: Theme - .of(context) - .primaryColor, - focusColor: Theme - .of(context) - .primaryColor, - highlightColor: Theme - .of(context) - .primaryColor, + hoverColor: Theme.of(context).primaryColor, + splashColor: Theme.of(context).primaryColor, + focusColor: Theme.of(context).primaryColor, + highlightColor: Theme.of(context).primaryColor, child: Text( "Log out", style: TextStyle( @@ -178,35 +210,28 @@ class _ProfileScreenState extends State { ], ), Positioned( - top: 0.1 * MediaQuery - .of(context) - .size - .height, + top: 0.1 * MediaQuery.of(context).size.height, child: CircleAvatar( radius: profilePictureDiameter / 2, - backgroundImage: - AssetImage("assets/images/profile_pic.jpg"), + backgroundImage: _user.profilePictureUrl.isEmpty + ? AssetImage("assets/images/profile_pic.jpg") + : NetworkImage(_user.profilePictureUrl), backgroundColor: Colors.transparent, - foregroundColor: Theme - .of(context) - .backgroundColor, + foregroundColor: Theme.of(context).backgroundColor, ), ), Positioned( - top: 0.1 * MediaQuery - .of(context) - .size - .height + + top: 0.1 * MediaQuery.of(context).size.height + profilePictureDiameter - 35, - left: (MediaQuery - .of(context) - .size - .width / 2) + 25, - child: Icon( - Icons.camera_alt, - size: profilePictureDiameter * 0.25, - color: Colors.white, + left: (MediaQuery.of(context).size.width / 2) + 25, + child: IconButton( + icon: Icon( + Icons.camera_alt, + size: profilePictureDiameter * 0.25, + color: Colors.white, + ), + onPressed: getImage, ), ), ], diff --git a/lib/services/user_db_services.dart b/lib/services/user_db_services.dart index e238803775..55d05f24c0 100644 --- a/lib/services/user_db_services.dart +++ b/lib/services/user_db_services.dart @@ -23,6 +23,17 @@ class UserDBServices { .set(_user.toJson(), SetOptions(merge: true)); } + static Future updateProfilePictureUrl( + String uid, String profilePictureUrl) async { + FirebaseFirestore firestoreDB = FirebaseFirestore.instance; + + await firestoreDB.collection(usersCollection).doc(uid).update( + { + 'profilePictureUrl': profilePictureUrl, + }, + ); + } + // Fetches User Data from Collection static Future fetchUserData(BuildContext context) async { FirebaseFirestore firestoreDB = FirebaseFirestore.instance; diff --git a/lib/services/user_info_services.dart b/lib/services/user_info_services.dart index c2969e125b..6680da83f6 100644 --- a/lib/services/user_info_services.dart +++ b/lib/services/user_info_services.dart @@ -22,6 +22,12 @@ class UserInfoServices extends ChangeNotifier { notifyListeners(); } + Future upateProfilePictureUrl() async { + await UserDBServices.updateProfilePictureUrl( + _user.uid, _user.profilePictureUrl); + // notifyListeners(); + } + void setUser(Users _usr) { this._user = _usr; this.hasData = true; diff --git a/lib/widgets/header.dart b/lib/widgets/header.dart index 24caf5322f..ddc4f69370 100644 --- a/lib/widgets/header.dart +++ b/lib/widgets/header.dart @@ -16,25 +16,31 @@ class Header extends StatelessWidget { height: 70.0, ), Consumer( - builder: (ctx, _userInfo, _) => FittedBox( - fit: BoxFit.fitWidth, - child: Text( - "Hello, " + - (_userInfo.hasData - ? _userInfo.user.name.split(" ")[0] - : "Sir"), - style: TextStyle( - color: Colors.white, - fontSize: 25.0, - fontWeight: FontWeight.bold, + builder: (ctx, _userInfo, _) => Row( + children: [ + FittedBox( + fit: BoxFit.fitWidth, + child: Text( + "Hello, " + + (_userInfo.hasData + ? _userInfo.user.name.split(" ")[0] + : "Sir"), + style: TextStyle( + color: Colors.white, + fontSize: 25.0, + fontWeight: FontWeight.bold, + ), + ), ), - ), + CircleAvatar( + radius: 25.0, + backgroundImage: _userInfo.user.profilePictureUrl.isEmpty + ? AssetImage("assets/images/profile_pic.jpg") + : NetworkImage(_userInfo.user.profilePictureUrl), + ), + ], ), ), - CircleAvatar( - radius: 25.0, - backgroundImage: AssetImage("assets/images/profile_pic.jpg"), - ), ], ), ); diff --git a/lib/widgets/signup_form_additional_details.dart b/lib/widgets/signup_form_additional_details.dart index 44b81397a2..9fb29e3825 100644 --- a/lib/widgets/signup_form_additional_details.dart +++ b/lib/widgets/signup_form_additional_details.dart @@ -3,6 +3,7 @@ import 'package:class_manager/screens/login_page.dart'; import 'package:class_manager/services/googleAuthentication.dart'; import 'package:class_manager/services/user_info_services.dart'; import 'package:class_manager/widgets/auth_input_form_field.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:fluttertoast/fluttertoast.dart'; @@ -31,6 +32,17 @@ class _SignUpFormAdditionalDetailsState ), ); + FirebaseFirestore _firebaseFirestore = FirebaseFirestore.instance; + + void getData() async { + var qs = await _firebaseFirestore.collection('users').get(); + qs.docs.forEach( + (qds) { + print(qds.data()); + }, + ); + } + @override void initState() { super.initState(); @@ -43,6 +55,8 @@ class _SignUpFormAdditionalDetailsState _year = new TextEditingController(); _age = new TextEditingController(); _formKey = new GlobalKey(); + + getData(); } @override diff --git a/pubspec.lock b/pubspec.lock index 23ad7bdfc1..7045806c07 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -113,6 +113,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.0" + ffi: + dependency: transitive + description: + name: ffi + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + file: + dependency: transitive + description: + name: file + url: "https://pub.dartlang.org" + source: hosted + version: "6.1.0" firebase_auth: dependency: "direct main" description: @@ -155,6 +169,27 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.2.1+3" + firebase_storage: + dependency: "direct main" + description: + name: firebase_storage + url: "https://pub.dartlang.org" + source: hosted + version: "7.0.0" + firebase_storage_platform_interface: + dependency: transitive + description: + name: firebase_storage_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.4" + firebase_storage_web: + dependency: transitive + description: + name: firebase_storage_web + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.1+3" flutter: dependency: "direct main" description: flutter @@ -181,6 +216,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.8.1" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.11" flutter_svg: dependency: "direct main" description: @@ -226,6 +268,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.9.2" + http: + dependency: transitive + description: + name: http + url: "https://pub.dartlang.org" + source: hosted + version: "0.12.2" http_parser: dependency: transitive description: @@ -240,6 +289,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.19" + image_picker: + dependency: "direct main" + description: + name: image_picker + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.7+22" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.6" intl: dependency: "direct main" description: @@ -296,6 +359,48 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.1.4" + path_provider: + dependency: "direct main" + description: + name: path_provider + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + path_provider_macos: + dependency: transitive + description: + name: path_provider_macos + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + pedantic: + dependency: transitive + description: + name: pedantic + url: "https://pub.dartlang.org" + source: hosted + version: "1.11.0" petitparser: dependency: transitive description: @@ -303,6 +408,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.1.0" + platform: + dependency: transitive + description: + name: platform + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" plugin_platform_interface: dependency: transitive description: @@ -310,6 +422,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.3" + process: + dependency: transitive + description: + name: process + url: "https://pub.dartlang.org" + source: hosted + version: "4.1.0" provider: dependency: "direct main" description: @@ -385,6 +504,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + win32: + dependency: transitive + description: + name: win32 + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.4" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.0" xml: dependency: transitive description: @@ -400,5 +533,5 @@ packages: source: hosted version: "2.2.1" sdks: - dart: ">=2.12.0-0.0 <3.0.0" + dart: ">=2.12.0 <3.0.0" flutter: ">=1.24.0-10.1.pre" diff --git a/pubspec.yaml b/pubspec.yaml index 802bd03d0d..27d02e6b9a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -23,6 +23,9 @@ dependencies: email_validator: '^1.0.0' google_sign_in: flutter_facebook_login: + image_picker: + firebase_storage: + path_provider: dev_dependencies: flutter_test: From 862aa47a53dafab28f333e6f3cc5f1d4faeab2cc Mon Sep 17 00:00:00 2001 From: D Date: Thu, 25 Mar 2021 14:55:35 +0530 Subject: [PATCH 2/2] Resolved conflicts --- android/settings_aar.gradle | 1 + lib/screens/profile_screen.dart | 16 ++++------ lib/widgets/header.dart | 31 +++---------------- .../signup_form_additional_details.dart | 12 ------- pubspec.lock | 18 ++--------- 5 files changed, 13 insertions(+), 65 deletions(-) create mode 100644 android/settings_aar.gradle diff --git a/android/settings_aar.gradle b/android/settings_aar.gradle new file mode 100644 index 0000000000..e7b4def49c --- /dev/null +++ b/android/settings_aar.gradle @@ -0,0 +1 @@ +include ':app' diff --git a/lib/screens/profile_screen.dart b/lib/screens/profile_screen.dart index f3ba472a58..f51f0190c4 100644 --- a/lib/screens/profile_screen.dart +++ b/lib/screens/profile_screen.dart @@ -21,7 +21,7 @@ class ProfileScreen extends StatefulWidget { class _ProfileScreenState extends State { ImagePicker _imagePicker = ImagePicker(); - Reference _storageReference = FirebaseStorage.instance.ref(); + StorageReference _storageReference = FirebaseStorage.instance.ref(); void getImage() async { PickedFile image = await _imagePicker.getImage(source: ImageSource.gallery); @@ -39,15 +39,13 @@ class _ProfileScreenState extends State { uploadPictures(File image) async { // uploads picture(s) to storage and return it's URL - final Reference ref = + final StorageReference ref = _storageReference.child('${Path.basename(image.path)}}'); - final UploadTask uploadTask = ref.putFile(image); - // final TaskSnapshot storageTaskSnapshot = - String pictureUrl; - await uploadTask.then((taskSnapshot) async { - pictureUrl = await taskSnapshot.ref.getDownloadURL(); - }); + final StorageUploadTask uploadTask = ref.putFile(image); + + UploadTaskSnapshot uploadTaskSnapshot = await uploadTask.future; + String pictureUrl = uploadTaskSnapshot.downloadUrl.toString(); final userInfoProvider = Provider.of(context, listen: false); @@ -58,8 +56,6 @@ class _ProfileScreenState extends State { userInfoProvider.setUser(currentUser); userInfoProvider.upateProfilePictureUrl(); - - // return pictureUrl; } @override diff --git a/lib/widgets/header.dart b/lib/widgets/header.dart index a484978b39..722ee916a5 100644 --- a/lib/widgets/header.dart +++ b/lib/widgets/header.dart @@ -8,16 +8,15 @@ class Header extends StatelessWidget { Widget build(BuildContext context) { return Padding( padding: EdgeInsets.fromLTRB(30.0, 50.0, 30.0, 30.0), - child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ Flexible( - child:SvgPicture.asset( - "assets/icons/grad_cap.svg", - height: 70.0, - ), + child: SvgPicture.asset( + "assets/icons/grad_cap.svg", + height: 70.0, ), + ), Consumer( builder: (ctx, _userInfo, _) => Row( children: [ @@ -34,25 +33,7 @@ class Header extends StatelessWidget { fontWeight: FontWeight.bold, ), ), - ), - Flexible( - child:Consumer( - builder: (ctx, _userInfo, _) => FittedBox( - fit: BoxFit.fitWidth, - child: Text( - "Hello, " + - (_userInfo.hasData - ? _userInfo.user.name.split(" ")[0] - : "Sir"), - style: TextStyle( - color: Colors.white, - fontSize: 25.0, - fontWeight: FontWeight.bold, ), - ), - ), - ), - ), CircleAvatar( radius: 25.0, backgroundImage: _userInfo.user.profilePictureUrl.isEmpty @@ -62,10 +43,6 @@ class Header extends StatelessWidget { ], ), ), - CircleAvatar( - radius: 25.0, - backgroundImage: AssetImage("assets/images/profile_pic.jpg"), - ), ], ), ); diff --git a/lib/widgets/signup_form_additional_details.dart b/lib/widgets/signup_form_additional_details.dart index 3cc1e4dd7e..d17ad0facf 100644 --- a/lib/widgets/signup_form_additional_details.dart +++ b/lib/widgets/signup_form_additional_details.dart @@ -45,17 +45,6 @@ class _SignUpFormAdditionalDetailsState _collegeList.add('Not in the list'); } - // FirebaseFirestore _firebaseFirestore = FirebaseFirestore.instance; - -// void getData() async { -// var qs = await _firebaseFirestore.collection('users').get(); -// qs.docs.forEach( -// (qds) { -// print(qds.data()); -// }, -// ); -// } - @override void initState() { super.initState(); @@ -68,7 +57,6 @@ class _SignUpFormAdditionalDetailsState _age = new TextEditingController(); _formKey = new GlobalKey(); - // getData(); fetchColleges = getData(); } diff --git a/pubspec.lock b/pubspec.lock index 285659346c..0c77c3e1b0 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -168,21 +168,7 @@ packages: name: firebase_storage url: "https://pub.dartlang.org" source: hosted - version: "7.0.0" - firebase_storage_platform_interface: - dependency: transitive - description: - name: firebase_storage_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.4" - firebase_storage_web: - dependency: transitive - description: - name: firebase_storage_web - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.1+3" + version: "0.3.2" flutter: dependency: "direct main" description: flutter @@ -534,4 +520,4 @@ packages: version: "3.1.0" sdks: dart: ">=2.12.0 <3.0.0" - flutter: ">=1.24.0-10.1.pre" + flutter: ">=1.24.0-7.0"