diff --git a/Sources/justMUSIC/android/app/google-services.json b/Sources/justMUSIC/android/app/google-services.json new file mode 100644 index 0000000..9fb09e0 --- /dev/null +++ b/Sources/justMUSIC/android/app/google-services.json @@ -0,0 +1,46 @@ +{ + "project_info": { + "project_number": "994903990520", + "project_id": "justmusic-435d5", + "storage_bucket": "justmusic-435d5.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:994903990520:android:02a445b6561bf2820a9b0d", + "android_client_info": { + "package_name": "com.example.justmusic" + } + }, + "oauth_client": [ + { + "client_id": "994903990520-rdk6ldrmbi71ddqt84qfhtuficm7ngon.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyCjkofl0nvfzQqRZPv_-H99WoyYa7O660g" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "994903990520-9jsnq9ipdn7smk7tlbdd20i7j6sl3jcd.apps.googleusercontent.com", + "client_type": 3 + }, + { + "client_id": "994903990520-n6jd98ena56kb1tvtrd67tvb5et3nfbf.apps.googleusercontent.com", + "client_type": 2, + "ios_info": { + "bundle_id": "com.example.justmusic" + } + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/Sources/justMUSIC/ios/Runner/GoogleService-Info.plist b/Sources/justMUSIC/ios/Runner/GoogleService-Info.plist new file mode 100644 index 0000000..cdb37d7 --- /dev/null +++ b/Sources/justMUSIC/ios/Runner/GoogleService-Info.plist @@ -0,0 +1,34 @@ + + + + + CLIENT_ID + 994903990520-n6jd98ena56kb1tvtrd67tvb5et3nfbf.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.994903990520-n6jd98ena56kb1tvtrd67tvb5et3nfbf + API_KEY + AIzaSyBbYqsR6t7JTi8_XFNEHd43IRuKlYGeI3U + GCM_SENDER_ID + 994903990520 + PLIST_VERSION + 1 + BUNDLE_ID + com.example.justmusic + PROJECT_ID + justmusic-435d5 + STORAGE_BUCKET + justmusic-435d5.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:994903990520:ios:93188f32e320babe0a9b0d + + \ No newline at end of file diff --git a/Sources/justMUSIC/ios/firebase_app_id_file.json b/Sources/justMUSIC/ios/firebase_app_id_file.json new file mode 100644 index 0000000..ef1bedc --- /dev/null +++ b/Sources/justMUSIC/ios/firebase_app_id_file.json @@ -0,0 +1,7 @@ +{ + "file_generated_by": "FlutterFire CLI", + "purpose": "FirebaseAppID & ProjectID for this Firebase app in this directory", + "GOOGLE_APP_ID": "1:994903990520:ios:93188f32e320babe0a9b0d", + "FIREBASE_PROJECT_ID": "justmusic-435d5", + "GCM_SENDER_ID": "994903990520" +} \ No newline at end of file diff --git a/Sources/justMUSIC/lib/components/login_button.dart b/Sources/justMUSIC/lib/components/login_button.dart index 3e41e8e..1d794dd 100644 --- a/Sources/justMUSIC/lib/components/login_button.dart +++ b/Sources/justMUSIC/lib/components/login_button.dart @@ -3,7 +3,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; class LoginButton extends StatefulWidget { - const LoginButton({Key? key}) : super(key: key); + final Function callback; + + const LoginButton({Key? key, required this.callback}) : super(key: key); @override State createState() => _LoginButtonState(); @@ -14,7 +16,7 @@ class _LoginButtonState extends State { Widget build(BuildContext context) { return ElevatedButton( onPressed: () { - Navigator.pushNamed(context, '/explanation'); + widget.callback(); }, style: ButtonStyle( backgroundColor: MaterialStateProperty.all(Color(0xFF1C1C1C)), diff --git a/Sources/justMUSIC/lib/firebase_options.dart b/Sources/justMUSIC/lib/firebase_options.dart new file mode 100644 index 0000000..bfc6ec0 --- /dev/null +++ b/Sources/justMUSIC/lib/firebase_options.dart @@ -0,0 +1,76 @@ +// File generated by FlutterFire CLI. +// ignore_for_file: lines_longer_than_80_chars, avoid_classes_with_only_static_members +import 'package:firebase_core/firebase_core.dart' show FirebaseOptions; +import 'package:flutter/foundation.dart' + show defaultTargetPlatform, kIsWeb, TargetPlatform; + +/// Default [FirebaseOptions] for use with your Firebase apps. +/// +/// Example: +/// ```dart +/// import 'firebase_options.dart'; +/// // ... +/// await Firebase.initializeApp( +/// options: DefaultFirebaseOptions.currentPlatform, +/// ); +/// ``` +class DefaultFirebaseOptions { + static FirebaseOptions get currentPlatform { + if (kIsWeb) { + return web; + } + switch (defaultTargetPlatform) { + case TargetPlatform.android: + return android; + case TargetPlatform.iOS: + return ios; + case TargetPlatform.macOS: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for macos - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + case TargetPlatform.windows: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for windows - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + case TargetPlatform.linux: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for linux - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + default: + throw UnsupportedError( + 'DefaultFirebaseOptions are not supported for this platform.', + ); + } + } + + static const FirebaseOptions web = FirebaseOptions( + apiKey: 'AIzaSyBv-Sba07nFFhctn6c3ARyvi9RfYwEKoNA', + appId: '1:994903990520:web:724c75003432ddbc0a9b0d', + messagingSenderId: '994903990520', + projectId: 'justmusic-435d5', + authDomain: 'justmusic-435d5.firebaseapp.com', + storageBucket: 'justmusic-435d5.appspot.com', + measurementId: 'G-D4YRLXK9TQ', + ); + + static const FirebaseOptions android = FirebaseOptions( + apiKey: 'AIzaSyCjkofl0nvfzQqRZPv_-H99WoyYa7O660g', + appId: '1:994903990520:android:02a445b6561bf2820a9b0d', + messagingSenderId: '994903990520', + projectId: 'justmusic-435d5', + storageBucket: 'justmusic-435d5.appspot.com', + ); + + static const FirebaseOptions ios = FirebaseOptions( + apiKey: 'AIzaSyBbYqsR6t7JTi8_XFNEHd43IRuKlYGeI3U', + appId: '1:994903990520:ios:93188f32e320babe0a9b0d', + messagingSenderId: '994903990520', + projectId: 'justmusic-435d5', + storageBucket: 'justmusic-435d5.appspot.com', + iosClientId: '994903990520-n6jd98ena56kb1tvtrd67tvb5et3nfbf.apps.googleusercontent.com', + iosBundleId: 'com.example.justmusic', + ); +} diff --git a/Sources/justMUSIC/lib/main.dart b/Sources/justMUSIC/lib/main.dart index 1203f32..283502a 100644 --- a/Sources/justMUSIC/lib/main.dart +++ b/Sources/justMUSIC/lib/main.dart @@ -1,3 +1,4 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; @@ -10,12 +11,20 @@ import 'package:justmusic/screens/registration_screen.dart'; import 'package:justmusic/screens/welcome_screen.dart'; import 'package:justmusic/view_model/MusicViewModel.dart'; import 'package:justmusic/view_model/UserViewModel.dart'; +import 'package:firebase_core/firebase_core.dart'; +import 'firebase_options.dart'; -void main() { +Future main() async { + WidgetsFlutterBinding.ensureInitialized(); + await Firebase.initializeApp( + options: DefaultFirebaseOptions.currentPlatform, + ); runApp(const MyApp()); } class MyApp extends StatelessWidget { + // ugly as fuck + static FirebaseFirestore db = FirebaseFirestore.instance; static UserViewModel userViewModel = UserViewModel(); static MusicViewModel musicViewModel = MusicViewModel(); @@ -51,7 +60,7 @@ class MyApp extends StatelessWidget { // is not restarted. primarySwatch: Colors.blue, ), - home: WellcomeScreen()); + home: LoginScreen()); }, designSize: Size(390, 844), ); diff --git a/Sources/justMUSIC/lib/model/User.dart b/Sources/justMUSIC/lib/model/User.dart index f601867..f53996b 100644 --- a/Sources/justMUSIC/lib/model/User.dart +++ b/Sources/justMUSIC/lib/model/User.dart @@ -1,5 +1,5 @@ class User { - final int _id; + final String _id; String _pseudo; String _country; String _mail; @@ -14,7 +14,7 @@ class User { this._followers, this._capsules, this._followed, this.friends); //Getters and setters - int get id => _id; + String get id => _id; String get pseudo => _pseudo; diff --git a/Sources/justMUSIC/lib/model/mapper/UserMapper.dart b/Sources/justMUSIC/lib/model/mapper/UserMapper.dart new file mode 100644 index 0000000..25a8900 --- /dev/null +++ b/Sources/justMUSIC/lib/model/mapper/UserMapper.dart @@ -0,0 +1,36 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:justmusic/model/User.dart'; +import 'package:firebase_auth/firebase_auth.dart' as firebase_auth; +import '../../main.dart'; + +class UserMapper { + static User? toModel(DocumentSnapshot>? snapshot, + SnapshotOptions? options) { + if (snapshot == null) { + return null; + } + final data = snapshot.data(); + return User( + data?["uid"], + data?["pseudo"], + data?["country"], + data?["mail"], + data?["profilePicture"], + data?["followers"] as int, + data?["nbCapsules"] as int, + data?["followed"] as int, + data?['friends'] is Iterable ? List.from(data?['friends']) : []); + } +/* + static Map toFirebase(User user) { + return { + if (user.pseudo != null) "name": u, + if (user.country != null) "state": state, + if (user.mail != null) "country": country, + if (user.pp != null) "capital": capital, + if (user.followers != null) "population": population, + if (user.capsules != null) "regions": regions, + if () + }; + }*/ +} diff --git a/Sources/justMUSIC/lib/screens/login_screen.dart b/Sources/justMUSIC/lib/screens/login_screen.dart index 778d76d..58b52f4 100644 --- a/Sources/justMUSIC/lib/screens/login_screen.dart +++ b/Sources/justMUSIC/lib/screens/login_screen.dart @@ -1,9 +1,11 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_signin_button/button_list.dart'; import 'package:flutter_signin_button/button_view.dart'; import 'package:google_fonts/google_fonts.dart'; +import 'package:justmusic/main.dart'; import 'package:justmusic/values/constants.dart'; import '../components/login_button.dart'; @@ -18,6 +20,32 @@ class LoginScreen extends StatefulWidget { class _LoginScreenState extends State { bool passenable = true; final _formKey = GlobalKey(); + final _userMailTextField = TextEditingController(); + final _passwordTextField = TextEditingController(); + + handleLogin() async { + if (_formKey.currentState!.validate()) { + try { + await MyApp.userViewModel + .login(_userMailTextField.text, _passwordTextField.text); + Navigator.pushNamed(context, '/explanation'); + } catch (e) { + print(e); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + e.toString(), + style: GoogleFonts.plusJakartaSans( + color: Colors.white, + fontWeight: FontWeight.w400, + fontSize: 20.h), + ), + backgroundColor: Colors.red, + ), + ); + } + } + } @override Widget build(BuildContext context) { @@ -26,684 +54,312 @@ class _LoginScreenState extends State { child: Scaffold( resizeToAvoidBottomInset: false, backgroundColor: bgColor, - body: LayoutBuilder( - builder: (context, constraints) { - if (constraints.maxHeight >= 740) { - return Align( - child: SizedBox( - height: double.infinity, - width: 600, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Expanded( - child: Padding( - padding: - EdgeInsets.only(left: 40, right: 40), - child: Form( - key: _formKey, + body: Align( + child: SizedBox( + height: double.infinity, + width: 600, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: Padding( + padding: EdgeInsets.only(left: 40, right: 40), + child: Form( + key: _formKey, + child: Column( + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Flexible( + flex: 5, + child: Padding( + padding: EdgeInsets.only(bottom: 60), + child: Column( + mainAxisAlignment: + MainAxisAlignment.end, + children: [ + Text( + "Te revoilà!", + style: + GoogleFonts.plusJakartaSans( + color: Colors.white, + fontWeight: + FontWeight.w600, + fontSize: 38.h), + ), + SizedBox( + height: 10, + ), + SizedBox( + width: 230.w, + child: Text( + "Bon retour parmis nous tu nous as manqué!", + style: GoogleFonts + .plusJakartaSans( + color: Colors.white, + fontWeight: + FontWeight.w400, + fontSize: 20.h), + textAlign: TextAlign.center, + ), + ), + ], + ), + ), + ), + Expanded( + flex: 4, child: Column( crossAxisAlignment: - CrossAxisAlignment.center, + CrossAxisAlignment.end, children: [ - Flexible( - flex: 5, - child: Padding( - padding: - EdgeInsets.only(bottom: 60), - child: Column( - mainAxisAlignment: - MainAxisAlignment.end, - children: [ - Text( - "Te revoilà!", - style: GoogleFonts - .plusJakartaSans( - color: - Colors.white, - fontWeight: - FontWeight - .w600, - fontSize: 38.h), - ), - SizedBox( - height: 10, - ), - SizedBox( - width: 230.w, - child: Text( - "Bon retour parmis nous tu nous as manqué!", - style: GoogleFonts - .plusJakartaSans( - color: Colors - .white, - fontWeight: - FontWeight - .w400, - fontSize: 20.h), - textAlign: - TextAlign.center, - ), - ), - ], - ), - ), + TextFormField( + controller: _userMailTextField, + keyboardAppearance: + Brightness.dark, + validator: (value) { + if (value == null || + value.isEmpty) { + return 'entrez un email valide'; + } + return null; + }, + cursorColor: primaryColor, + keyboardType: + TextInputType.emailAddress, + style: + GoogleFonts.plusJakartaSans( + color: primaryColor), + decoration: InputDecoration( + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + width: 1, + color: + strokeTextField), + borderRadius: BorderRadius.all( + Radius.circular(10))), + contentPadding: + EdgeInsets.only( + top: 0, + bottom: 0, + left: defaultPadding), + fillColor: bgTextField, + filled: true, + focusColor: Color.fromRGBO( + 255, 255, 255, 0.30), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + width: 1, + color: + strokeTextField), + borderRadius: BorderRadius.all( + Radius.circular(10))), + hintText: 'Email', + hintStyle: + GoogleFonts.plusJakartaSans(color: strokeTextField)), ), - Expanded( - flex: 4, - child: Column( - crossAxisAlignment: - CrossAxisAlignment.end, - children: [ - TextFormField( - keyboardAppearance: - Brightness.dark, - validator: (value) { - if (value == null || - value.isEmpty) { - return 'TODO'; - } - return null; - }, - cursorColor: primaryColor, - keyboardType: - TextInputType - .emailAddress, - style: GoogleFonts - .plusJakartaSans( - color: - primaryColor), - decoration: InputDecoration( - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - width: 1, - color: - strokeTextField), - borderRadius: - BorderRadius.all( - Radius.circular( - 10))), - contentPadding: - EdgeInsets.only( - top: 0, - bottom: 0, - left: - defaultPadding), - fillColor: - bgTextField, - filled: true, - focusColor: Color.fromRGBO( - 255, 255, 255, 0.30), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - width: 1, - color: - strokeTextField), - borderRadius: - BorderRadius.all(Radius.circular(10))), - hintText: 'Email', - hintStyle: GoogleFonts.plusJakartaSans(color: strokeTextField)), - ), - SizedBox( - height: 18, - ), - TextFormField( - keyboardAppearance: - Brightness.dark, - obscureText: passenable, - validator: (value) { - if (value == null || - value.isEmpty) { - return 'TODO'; - } - return null; + SizedBox( + height: 18, + ), + TextFormField( + controller: _passwordTextField, + keyboardAppearance: + Brightness.dark, + obscureText: passenable, + validator: (value) { + if (value == null || + value.isEmpty) { + return 'entrez un mot de passe valide'; + } + return null; + }, + cursorColor: primaryColor, + keyboardType: + TextInputType.emailAddress, + style: + GoogleFonts.plusJakartaSans( + color: primaryColor), + decoration: InputDecoration( + focusedBorder: + OutlineInputBorder( + borderSide: BorderSide( + width: 1, + color: + strokeTextField), + borderRadius: + BorderRadius.all( + Radius.circular( + 10))), + contentPadding: EdgeInsets.only( + top: 0, + bottom: 0, + left: defaultPadding), + fillColor: bgTextField, + filled: true, + focusColor: Color.fromRGBO( + 255, 255, 255, 0.30), + enabledBorder: + OutlineInputBorder( + borderSide: BorderSide( + width: 1, + color: + strokeTextField), + borderRadius: + BorderRadius.all( + Radius.circular( + 10))), + hintText: 'Mot de passe', + hintStyle: + GoogleFonts.plusJakartaSans( + color: strokeTextField), + suffixIcon: Container( + padding: EdgeInsets.only( + right: 10), + margin: EdgeInsets.all(5), + height: 3, + child: InkWell( + onTap: () { + setState(() { + if (passenable) { + passenable = false; + } else { + passenable = true; + } + }); }, - cursorColor: primaryColor, - keyboardType: - TextInputType - .emailAddress, - style: GoogleFonts - .plusJakartaSans( - color: - primaryColor), - decoration: - InputDecoration( - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - width: 1, - color: - strokeTextField), - borderRadius: - BorderRadius - .all(Radius - .circular( - 10))), - contentPadding: - EdgeInsets.only( - top: 0, - bottom: 0, - left: - defaultPadding), - fillColor: bgTextField, - filled: true, - focusColor: - Color.fromRGBO(255, - 255, 255, 0.30), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - width: 1, - color: - strokeTextField), - borderRadius: - BorderRadius - .all(Radius - .circular( - 10))), - hintText: - 'Mot de passe', - hintStyle: GoogleFonts - .plusJakartaSans( - color: - strokeTextField), - suffixIcon: Container( - padding: - EdgeInsets.only( - right: 10), - margin: - EdgeInsets.all( - 5), - height: 3, - child: InkWell( - onTap: () { - setState(() { - if (passenable) { - passenable = - false; - } else { - passenable = - true; - } - }); - }, // Image tapped - splashColor: Colors - .white10, // Splash color over image - child: Image( - image: passenable - ? AssetImage( - "assets/images/show_icon.png") - : AssetImage( - "assets/images/hide_icon.png"), - height: 2, - ), - )), + // Image tapped + splashColor: + Colors.white10, + // Splash color over image + child: Image( + image: passenable + ? AssetImage( + "assets/images/show_icon.png") + : AssetImage( + "assets/images/hide_icon.png"), + height: 2, ), - ), - Padding( - padding: EdgeInsets.only( - top: 10), - child: Text( - "Mot de passe oublié?", - style: GoogleFonts - .plusJakartaSans( - color: Colors - .white), - ), - ), - SizedBox( - height: defaultPadding, - ), - SizedBox( - width: 600, - child: LoginButton()), - ], + )), + ), + ), + Padding( + padding: EdgeInsets.only(top: 10), + child: Text( + "Mot de passe oublié?", + style: + GoogleFonts.plusJakartaSans( + color: Colors.white), + ), + ), + SizedBox( + height: defaultPadding, + ), + SizedBox( + width: 600, + child: LoginButton( + callback: handleLogin, )), - Expanded( - flex: 3, - child: Padding( - padding: - EdgeInsets.only(top: 20), - child: Column( + ], + ), + ), + Expanded( + flex: 3, + child: Padding( + padding: EdgeInsets.only(top: 20), + child: Column( + mainAxisAlignment: + MainAxisAlignment.start, + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + ConstrainedBox( + constraints: BoxConstraints( + maxWidth: 600), + child: Row( mainAxisAlignment: - MainAxisAlignment.start, - crossAxisAlignment: - CrossAxisAlignment - .center, + MainAxisAlignment + .spaceEvenly, children: [ - ConstrainedBox( - constraints: - BoxConstraints( - maxWidth: 600), - child: Row( - mainAxisAlignment: - MainAxisAlignment - .spaceEvenly, - children: [ - Expanded( - child: Container( - color: Color( - 0xFF3D3D3D), - height: 1, - ), - ), - Padding( - padding: const EdgeInsets - .only( - left: - defaultPadding, - right: - defaultPadding), - child: Text( - 'Ou', - style: GoogleFonts.plusJakartaSans( - color: Colors - .white, - fontWeight: - FontWeight - .bold), - ), - ), - Expanded( - child: - Container( - height: 1, - color: Color( - 0xFF3D3D3D), - )), - ], + Expanded( + child: Container( + color: + Color(0xFF3D3D3D), + height: 1, ), ), - SizedBox( - height: - defaultPadding), - SignInButton( - Buttons.Google, - text: - "Login with Google", - onPressed: () {}, - ), Padding( - padding: - EdgeInsets.only( - top: 20), - child: RichText( - textAlign: - TextAlign.center, - text: TextSpan( - text: - 'Pas encore inscrit?', - style: GoogleFonts - .plusJakartaSans( - color: Colors - .white, - fontWeight: - FontWeight - .w400, - fontSize: - 13), - children: < - TextSpan>[ - TextSpan( - text: - " S’inscire", - style: GoogleFonts.plusJakartaSans( - fontSize: - 13, - fontWeight: - FontWeight - .w400, - color: - primaryColor)), - ], - ), + padding: const EdgeInsets + .only( + left: + defaultPadding, + right: + defaultPadding), + child: Text( + 'Ou', + style: GoogleFonts + .plusJakartaSans( + color: Colors + .white, + fontWeight: + FontWeight + .bold), ), - ) + ), + Expanded( + child: Container( + height: 1, + color: + Color(0xFF3D3D3D), + )), ], ), - )) - ], - )))) - ], - )), - ); - } else { - return Align( - child: SizedBox( - height: double.infinity, - width: 600, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Expanded( - child: Padding( - padding: - EdgeInsets.only(left: 40, right: 40), - child: Form( - key: _formKey, - child: Column( - crossAxisAlignment: - CrossAxisAlignment.center, - children: [ - Flexible( - flex: 2, - child: Padding( - padding: - EdgeInsets.only(bottom: 30), - child: Column( - mainAxisAlignment: - MainAxisAlignment.end, - children: [ - Text( - "Te revoilà!", + ), + SizedBox( + height: defaultPadding), + SignInButton( + Buttons.Google, + text: "Login with Google", + onPressed: () {}, + ), + Padding( + padding: + EdgeInsets.only(top: 20), + child: RichText( + textAlign: TextAlign.center, + text: TextSpan( + text: + 'Pas encore inscrit?', style: GoogleFonts .plusJakartaSans( color: Colors.white, fontWeight: FontWeight - .w600, - fontSize: 38.h), - ), - SizedBox( - height: 10, - ), - SizedBox( - width: 230, - child: Text( - "Bon retour parmis nous tu nous as manqué!", - style: GoogleFonts - .plusJakartaSans( - color: Colors - .white, - fontWeight: - FontWeight - .w400, - fontSize: 20.h), - textAlign: - TextAlign.center, - ), - ), - ], - ), - ), - ), - Expanded( - flex: 4, - child: Column( - crossAxisAlignment: - CrossAxisAlignment.end, - children: [ - TextFormField( - keyboardAppearance: - Brightness.dark, - validator: (value) { - if (value == null || - value.isEmpty) { - return 'TODO'; - } - return null; - }, - cursorColor: primaryColor, - keyboardType: - TextInputType - .emailAddress, - style: GoogleFonts - .plusJakartaSans( - color: - primaryColor), - decoration: InputDecoration( - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - width: 1, - color: - strokeTextField), - borderRadius: - BorderRadius.all( - Radius.circular( - 10))), - contentPadding: - EdgeInsets.only( - top: 0, - bottom: 0, - left: - defaultPadding), - fillColor: - bgTextField, - filled: true, - focusColor: Color.fromRGBO( - 255, 255, 255, 0.30), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - width: 1, - color: - strokeTextField), - borderRadius: - BorderRadius.all(Radius.circular(10))), - hintText: 'Email', - hintStyle: GoogleFonts.plusJakartaSans(color: strokeTextField, fontSize: 15)), - ), - SizedBox( - height: 18, - ), - TextFormField( - keyboardAppearance: - Brightness.dark, - obscureText: passenable, - validator: (value) { - if (value == null || - value.isEmpty) { - return 'TODO'; - } - return null; - }, - cursorColor: primaryColor, - keyboardType: - TextInputType - .emailAddress, - style: GoogleFonts - .plusJakartaSans( - color: - primaryColor), - decoration: - InputDecoration( - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - width: 1, - color: - strokeTextField), - borderRadius: - BorderRadius - .all(Radius - .circular( - 10))), - contentPadding: - EdgeInsets.only( - top: 0, - bottom: 0, - left: - defaultPadding), - fillColor: bgTextField, - filled: true, - focusColor: - Color.fromRGBO(255, - 255, 255, 0.30), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - width: 1, - color: - strokeTextField), - borderRadius: - BorderRadius - .all(Radius - .circular( - 10))), - hintText: - 'Mot de passe', - hintStyle: GoogleFonts - .plusJakartaSans( - color: - strokeTextField), - suffixIcon: Container( - padding: - EdgeInsets.only( - right: 10), - margin: - EdgeInsets.all( - 5), - height: 3, - child: InkWell( - onTap: () { - setState(() { - if (passenable) { - passenable = - false; - } else { - passenable = - true; - } - }); - }, // Image tapped - splashColor: Colors - .white10, // Splash color over image - child: Image( - image: passenable - ? AssetImage( - "assets/images/show_icon.png") - : AssetImage( - "assets/images/hide_icon.png"), - height: 2, - ), - )), - ), - ), - Padding( - padding: EdgeInsets.only( - top: 10.h), - child: Text( - "Mot de passe oublié?", - style: GoogleFonts - .plusJakartaSans( - color: Colors - .white), - ), - ), - SizedBox( - height: defaultPadding, - ), - SizedBox( - width: 600, - child: LoginButton()), - ], - )), - Expanded( - flex: 3, - child: Padding( - padding: - EdgeInsets.only(top: 20), - child: Column( - mainAxisAlignment: - MainAxisAlignment.start, - crossAxisAlignment: - CrossAxisAlignment - .center, - children: [ - ConstrainedBox( - constraints: - BoxConstraints( - maxWidth: 600), - child: Row( - mainAxisAlignment: - MainAxisAlignment - .spaceEvenly, - children: [ - Expanded( - child: Container( - color: Color( - 0xFF3D3D3D), - height: 1, - ), - ), - Padding( - padding: const EdgeInsets - .only( - left: - defaultPadding, - right: - defaultPadding), - child: Text( - 'Ou', - style: GoogleFonts.plusJakartaSans( - color: Colors - .white, - fontWeight: - FontWeight - .bold), - ), - ), - Expanded( - child: - Container( - height: 1, - color: Color( - 0xFF3D3D3D), - )), - ], - ), - ), - SizedBox( - height: - defaultPadding), - SignInButton( - Buttons.Google, - text: - "Login with Google", - onPressed: () {}, - ), - Padding( - padding: - EdgeInsets.only( - top: 20), - child: RichText( - textAlign: - TextAlign.center, - text: TextSpan( - text: - 'Pas encore inscrit?', + .w400, + fontSize: 13), + children: [ + TextSpan( + text: " S’inscire", style: GoogleFonts .plusJakartaSans( - color: Colors - .white, + fontSize: + 13, fontWeight: FontWeight .w400, - fontSize: - 13), - children: < - TextSpan>[ - TextSpan( - text: - " S’inscire", - style: GoogleFonts.plusJakartaSans( - fontSize: - 13, - fontWeight: - FontWeight - .w400, - color: - primaryColor)), - ], - ), - ), - ) - ], + color: + primaryColor)), + ], + ), ), - )) - ], - )))) - ], - )), - ); - } - }, + ) + ], + ), + )) + ], + )))) + ], + )), ))); } } diff --git a/Sources/justMUSIC/lib/screens/registration_screen.dart b/Sources/justMUSIC/lib/screens/registration_screen.dart index 679fd11..ff62533 100644 --- a/Sources/justMUSIC/lib/screens/registration_screen.dart +++ b/Sources/justMUSIC/lib/screens/registration_screen.dart @@ -286,7 +286,11 @@ class _RegistrationScreenState extends State { Padding( padding: EdgeInsets.symmetric(horizontal: defaultPadding), - child: SizedBox(width: 600, child: LoginButton()), + child: SizedBox( + width: 600, + child: LoginButton( + callback: () {}, + )), ), ], )), diff --git a/Sources/justMUSIC/lib/service/AuthService.dart b/Sources/justMUSIC/lib/service/AuthService.dart new file mode 100644 index 0000000..0baefe0 --- /dev/null +++ b/Sources/justMUSIC/lib/service/AuthService.dart @@ -0,0 +1,57 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; + +import '../model/User.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import '../main.dart'; + +class AuthService { + register(String pseudo, String email, String password) async { + try { + final data = await FirebaseAuth.instance.createUserWithEmailAndPassword( + email: email, + password: password, + ); + + final user = { + "mail": email, + "pseudo": pseudo, + "phone_number": "", + "picture": + "https://media.licdn.com/dms/image/D4E03AQHvc_b89ogFtQ/profile-displayphoto-shrink_400_400/0/1665060931103?e=1695859200&v=beta&t=wVLbxqeokYiPJ13nJ3SMq97iZvcm3ra0ufWFZCSzhjg", + "friends": [] + }; + + MyApp.db + .collection("users") + .doc(data.user?.uid) + .set(user) + .then((value) => print("User Added")) + .catchError((error) => print("Failed to add user: $error")); + } on FirebaseAuthException catch (e) { + if (e.code == 'weak-password') { + throw ('The password provided is too weak.'); + } else if (e.code == 'email-already-in-use') { + throw ('The account already exists for that email.'); + } + } catch (e) { + throw (e); + } + } + + login(String email, String password) async { + try { + await FirebaseAuth.instance + .signInWithEmailAndPassword(email: email, password: password); + } on FirebaseAuthException catch (e) { + if (e.code == 'user-not-found') { + throw ('No user found for that email.'); + } else if (e.code == 'wrong-password') { + throw ('Wrong password provided for that user.'); + } + } + } + + void signOut() async { + await FirebaseAuth.instance.signOut(); + } +} diff --git a/Sources/justMUSIC/lib/service/UserService.dart b/Sources/justMUSIC/lib/service/UserService.dart new file mode 100644 index 0000000..b60cd92 --- /dev/null +++ b/Sources/justMUSIC/lib/service/UserService.dart @@ -0,0 +1,15 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; + +import '../model/User.dart'; +import '../main.dart'; + +class UserService { + acceptFriend(User user, String idFriend) { + MyApp.db.collection("users").doc(user.id).update({ + "friends": FieldValue.arrayUnion([idFriend]) + }); + MyApp.db.collection("users").doc(idFriend).update({ + "friends": FieldValue.arrayUnion([user.id]) + }); + } +} diff --git a/Sources/justMUSIC/lib/view_model/UserViewModel.dart b/Sources/justMUSIC/lib/view_model/UserViewModel.dart index 2aaa1fb..d4bbfa7 100644 --- a/Sources/justMUSIC/lib/view_model/UserViewModel.dart +++ b/Sources/justMUSIC/lib/view_model/UserViewModel.dart @@ -1,8 +1,14 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:firebase_auth/firebase_auth.dart' as firebase_auth; +import 'package:justmusic/service/AuthService.dart'; + import '../model/User.dart'; +import '../model/mapper/UserMapper.dart'; +import '../main.dart'; class UserViewModel { - User _userCurrent = User( - 1, "MelinaShow", "France", "test@gmail.com", "zezrzrzr", 5, 12, 114, []); + late User _userCurrent; + final AuthService _authService = AuthService(); User get userCurrent => _userCurrent; @@ -13,7 +19,41 @@ class UserViewModel { UserViewModel(); // Methods - User getUser(int id) { - throw new Error(); + Future getUser(String id) async { + final user = await MyApp.db.collection("users").doc(id).get(); + return UserMapper.toModel(user, null); + } + + login(String pseudo, String password) async { + await _authService.login(pseudo, password); + if (firebase_auth.FirebaseAuth.instance.currentUser == null) { + throw Exception("User login failed"); + } + final user = await MyApp.db + .collection("users") + .doc(firebase_auth.FirebaseAuth.instance.currentUser?.uid) + .get(); + User? data = UserMapper.toModel(user, null); + if (data == null) { + throw Exception("User login failed"); + } + _userCurrent = data; + } + + register(String pseudo, String password, String email) async { + _authService.register(pseudo, email, password); + final user = await MyApp.db + .collection("users") + .doc(firebase_auth.FirebaseAuth.instance.currentUser?.uid) + .get(); + User? data = UserMapper.toModel(user, null); + if (data == null) { + throw Exception("User register failed"); + } + _userCurrent = data; + } + + logout() { + _authService.signOut(); } } diff --git a/Sources/justMUSIC/pubspec.lock b/Sources/justMUSIC/pubspec.lock index 685a4a9..979c119 100644 --- a/Sources/justMUSIC/pubspec.lock +++ b/Sources/justMUSIC/pubspec.lock @@ -1,14 +1,22 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + _flutterfire_internals: + dependency: transitive + description: + name: _flutterfire_internals + sha256: "5dce45a06d386358334eb1689108db6455d90ceb0d75848d5f4819283d4ee2b8" + url: "https://pub.dev" + source: hosted + version: "1.3.4" async: dependency: transitive description: name: async - sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted - version: "2.10.0" + version: "2.11.0" audioplayers: dependency: "direct main" description: @@ -85,10 +93,10 @@ packages: dependency: transitive description: name: characters - sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.3.0" circular_reveal_animation: dependency: "direct main" description: @@ -105,14 +113,38 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.1" + cloud_firestore: + dependency: "direct main" + description: + name: cloud_firestore + sha256: f1a06ad4499ed9ab73703560d44893e6b9e66ce3923c9121f4ef3981c972057f + url: "https://pub.dev" + source: hosted + version: "4.8.4" + cloud_firestore_platform_interface: + dependency: transitive + description: + name: cloud_firestore_platform_interface + sha256: "86bd1865abbeb09a7d09da3e70364a09f894937270651fc611a1c6d6a9f7b02c" + url: "https://pub.dev" + source: hosted + version: "5.15.3" + cloud_firestore_web: + dependency: transitive + description: + name: cloud_firestore_web + sha256: ac2eeb2a7ab1928c3aacc30eed750fa839d6f620e112a5459e321df217be2f47 + url: "https://pub.dev" + source: hosted + version: "3.6.3" collection: dependency: transitive description: name: collection - sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.17.1" crypto: dependency: transitive description: @@ -161,6 +193,54 @@ packages: url: "https://pub.dev" source: hosted version: "6.1.4" + firebase_auth: + dependency: "direct main" + description: + name: firebase_auth + sha256: "49fd35ce06f2530dd460e5dc123235731cb61dd7c76b0af4b6e190404880d04d" + url: "https://pub.dev" + source: hosted + version: "4.7.2" + firebase_auth_platform_interface: + dependency: transitive + description: + name: firebase_auth_platform_interface + sha256: "817f3ceb84ef5e9adaaf50cf7a19255f6ffcdd12c6f9e9aa4cf00fc7f2eb3cfb" + url: "https://pub.dev" + source: hosted + version: "6.16.1" + firebase_auth_web: + dependency: transitive + description: + name: firebase_auth_web + sha256: e9044778287f1ff8f9f4cee7e247b03ec87bb8977e0e65ad27dc337e196132e8 + url: "https://pub.dev" + source: hosted + version: "5.6.2" + firebase_core: + dependency: "direct main" + description: + name: firebase_core + sha256: "2e9324f719e90200dc7d3c4f5d2abc26052f9f2b995d3b6626c47a0dfe1c8192" + url: "https://pub.dev" + source: hosted + version: "2.15.0" + firebase_core_platform_interface: + dependency: transitive + description: + name: firebase_core_platform_interface + sha256: b63e3be6c96ef5c33bdec1aab23c91eb00696f6452f0519401d640938c94cba2 + url: "https://pub.dev" + source: hosted + version: "4.8.0" + firebase_core_web: + dependency: transitive + description: + name: firebase_core_web + sha256: "0fd5c4b228de29b55fac38aed0d9e42514b3d3bd47675de52bf7f8fccaf922fa" + url: "https://pub.dev" + source: hosted + version: "2.6.0" flutter: dependency: "direct main" description: flutter @@ -268,10 +348,10 @@ packages: dependency: transitive description: name: js - sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 url: "https://pub.dev" source: hosted - version: "0.6.5" + version: "0.6.7" lints: dependency: transitive description: @@ -284,10 +364,10 @@ packages: dependency: transitive description: name: matcher - sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" url: "https://pub.dev" source: hosted - version: "0.12.13" + version: "0.12.15" material_color_utilities: dependency: transitive description: @@ -300,10 +380,10 @@ packages: dependency: transitive description: name: meta - sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.9.1" modal_bottom_sheet: dependency: "direct main" description: @@ -316,10 +396,10 @@ packages: dependency: transitive description: name: path - sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "1.8.3" path_provider: dependency: transitive description: @@ -449,10 +529,10 @@ packages: dependency: transitive description: name: test_api - sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb url: "https://pub.dev" source: hosted - version: "0.4.16" + version: "0.5.1" text_scroll: dependency: "direct main" description: @@ -518,5 +598,5 @@ packages: source: hosted version: "1.1.0" sdks: - dart: ">=2.18.2 <3.0.0" + dart: ">=3.0.0-0 <4.0.0" flutter: ">=3.3.0" diff --git a/Sources/justMUSIC/pubspec.yaml b/Sources/justMUSIC/pubspec.yaml index 1a52f91..9913d71 100644 --- a/Sources/justMUSIC/pubspec.yaml +++ b/Sources/justMUSIC/pubspec.yaml @@ -53,6 +53,9 @@ dependencies: audioplayers: ^4.1.0 ionicons: ^0.2.2 top_snackbar_flutter: ^3.1.0 + firebase_core: ^2.15.0 + firebase_auth: ^4.7.2 + cloud_firestore: ^4.8.4 dev_dependencies: flutter_test: