Register done

pull/28/head
root 2 years ago
parent d8cf5ed01e
commit ffc8e24ea3

File diff suppressed because it is too large Load Diff

@ -1,30 +1,30 @@
# This file tracks properties of this Flutter project. # This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc. # Used by Flutter tool to assess capabilities and perform upgrades etc.
# #
# This file should be version controlled. # This file should be version controlled.
version: version:
revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
channel: stable channel: stable
project_type: app project_type: app
# Tracks metadata for the flutter migrate command # Tracks metadata for the flutter migrate command
migration: migration:
platforms: platforms:
- platform: root - platform: root
create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
- platform: android - platform: android
create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
# User provided section # User provided section
# List of Local paths (relative to this file) that should be # List of Local paths (relative to this file) that should be
# ignored by the migrate tool. # ignored by the migrate tool.
# #
# Files that are not part of the templates will be ignored by default. # Files that are not part of the templates will be ignored by default.
unmanaged_files: unmanaged_files:
- 'lib/main.dart' - 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj' - 'ios/Runner.xcodeproj/project.pbxproj'

@ -1,78 +1,78 @@
def localProperties = new Properties() def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties') def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) { if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader -> localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader) localProperties.load(reader)
} }
} }
def flutterRoot = localProperties.getProperty('flutter.sdk') def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) { if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
} }
def flutterVersionCode = localProperties.getProperty('flutter.versionCode') def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) { if (flutterVersionCode == null) {
flutterVersionCode = '1' flutterVersionCode = '1'
} }
def flutterVersionName = localProperties.getProperty('flutter.versionName') def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) { if (flutterVersionName == null) {
flutterVersionName = '1.0' flutterVersionName = '1.0'
} }
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android { android {
namespace "com.example.justmusic" namespace "com.example.justmusic"
compileSdkVersion 33 compileSdkVersion 33
ndkVersion flutter.ndkVersion ndkVersion flutter.ndkVersion
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8
} }
kotlinOptions { kotlinOptions {
jvmTarget = '1.8' jvmTarget = '1.8'
} }
sourceSets { sourceSets {
main.java.srcDirs += 'src/main/kotlin' main.java.srcDirs += 'src/main/kotlin'
} }
defaultConfig { defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.justmusic" applicationId "com.example.justmusic"
// You can update the following values to match your application needs. // You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion 19 minSdkVersion 19
targetSdkVersion flutter.targetSdkVersion targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName
} }
buildTypes { buildTypes {
release { release {
// TODO: Add your own signing config for the release build. // TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works. // Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug signingConfig signingConfigs.debug
} }
} }
} }
flutter { flutter {
source '../..' source '../..'
} }
dependencies { dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation(platform("com.google.firebase:firebase-bom:32.2.0")) implementation(platform("com.google.firebase:firebase-bom:32.2.0"))
implementation 'com.google.firebase:firebase-analytics-ktx' implementation 'com.google.firebase:firebase-analytics-ktx'
} }
apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.gms.google-services'

@ -1,46 +1,46 @@
{ {
"project_info": { "project_info": {
"project_number": "994903990520", "project_number": "994903990520",
"project_id": "justmusic-435d5", "project_id": "justmusic-435d5",
"storage_bucket": "justmusic-435d5.appspot.com" "storage_bucket": "justmusic-435d5.appspot.com"
}, },
"client": [ "client": [
{ {
"client_info": { "client_info": {
"mobilesdk_app_id": "1:994903990520:android:02a445b6561bf2820a9b0d", "mobilesdk_app_id": "1:994903990520:android:02a445b6561bf2820a9b0d",
"android_client_info": { "android_client_info": {
"package_name": "com.example.justmusic" "package_name": "com.example.justmusic"
} }
}, },
"oauth_client": [ "oauth_client": [
{ {
"client_id": "994903990520-rdk6ldrmbi71ddqt84qfhtuficm7ngon.apps.googleusercontent.com", "client_id": "994903990520-rdk6ldrmbi71ddqt84qfhtuficm7ngon.apps.googleusercontent.com",
"client_type": 3 "client_type": 3
} }
], ],
"api_key": [ "api_key": [
{ {
"current_key": "AIzaSyCjkofl0nvfzQqRZPv_-H99WoyYa7O660g" "current_key": "AIzaSyCjkofl0nvfzQqRZPv_-H99WoyYa7O660g"
} }
], ],
"services": { "services": {
"appinvite_service": { "appinvite_service": {
"other_platform_oauth_client": [ "other_platform_oauth_client": [
{ {
"client_id": "994903990520-9jsnq9ipdn7smk7tlbdd20i7j6sl3jcd.apps.googleusercontent.com", "client_id": "994903990520-9jsnq9ipdn7smk7tlbdd20i7j6sl3jcd.apps.googleusercontent.com",
"client_type": 3 "client_type": 3
}, },
{ {
"client_id": "994903990520-n6jd98ena56kb1tvtrd67tvb5et3nfbf.apps.googleusercontent.com", "client_id": "994903990520-n6jd98ena56kb1tvtrd67tvb5et3nfbf.apps.googleusercontent.com",
"client_type": 2, "client_type": 2,
"ios_info": { "ios_info": {
"bundle_id": "com.example.justmusic" "bundle_id": "com.example.justmusic"
} }
} }
] ]
} }
} }
} }
], ],
"configuration_version": "1" "configuration_version": "1"
} }

@ -1,7 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically, <!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc. to allow setting breakpoints, to provide hot reload, etc.
--> -->
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
</manifest> </manifest>

@ -1,33 +1,33 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application <application
android:label="justmusic" android:label="justmusic"
android:name="${applicationName}" android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"> android:icon="@mipmap/ic_launcher">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"
android:launchMode="singleTop" android:launchMode="singleTop"
android:theme="@style/LaunchTheme" android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true" android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as <!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. --> to determine the Window background behind the Flutter UI. -->
<meta-data <meta-data
android:name="io.flutter.embedding.android.NormalTheme" android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme" android:resource="@style/NormalTheme"
/> />
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter> </intent-filter>
</activity> </activity>
<!-- Don't delete the meta-data below. <!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java --> This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data <meta-data
android:name="flutterEmbedding" android:name="flutterEmbedding"
android:value="2" /> android:value="2" />
</application> </application>
</manifest> </manifest>

@ -1,25 +1,25 @@
// Generated file. // Generated file.
// //
// If you wish to remove Flutter's multidex support, delete this entire file. // If you wish to remove Flutter's multidex support, delete this entire file.
// //
// Modifications to this file should be done in a copy under a different name // Modifications to this file should be done in a copy under a different name
// as this file may be regenerated. // as this file may be regenerated.
package io.flutter.app; package io.flutter.app;
import android.app.Application; import android.app.Application;
import android.content.Context; import android.content.Context;
import androidx.annotation.CallSuper; import androidx.annotation.CallSuper;
import androidx.multidex.MultiDex; import androidx.multidex.MultiDex;
/** /**
* Extension of {@link android.app.Application}, adding multidex support. * Extension of {@link android.app.Application}, adding multidex support.
*/ */
public class FlutterMultiDexApplication extends Application { public class FlutterMultiDexApplication extends Application {
@Override @Override
@CallSuper @CallSuper
protected void attachBaseContext(Context base) { protected void attachBaseContext(Context base) {
super.attachBaseContext(base); super.attachBaseContext(base);
MultiDex.install(this); MultiDex.install(this);
} }
} }

@ -1,7 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically, <!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc. to allow setting breakpoints, to provide hot reload, etc.
--> -->
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
</manifest> </manifest>

@ -1,37 +1,37 @@
buildscript { buildscript {
ext.kotlin_version = '1.7.10' ext.kotlin_version = '1.7.10'
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:7.3.0' classpath 'com.android.tools.build:gradle:7.3.0'
classpath 'com.google.gms:google-services:4.3.15' classpath 'com.google.gms:google-services:4.3.15'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
} }
} }
allprojects { allprojects {
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
} }
} }
rootProject.buildDir = '../build' rootProject.buildDir = '../build'
subprojects { subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}" project.buildDir = "${rootProject.buildDir}/${project.name}"
} }
subprojects { subprojects {
project.evaluationDependsOn(':app') project.evaluationDependsOn(':app')
} }
tasks.register("clean", Delete) { tasks.register("clean", Delete) {
delete rootProject.buildDir delete rootProject.buildDir
} }

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip

@ -1,34 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>CLIENT_ID</key> <key>CLIENT_ID</key>
<string>994903990520-n6jd98ena56kb1tvtrd67tvb5et3nfbf.apps.googleusercontent.com</string> <string>994903990520-n6jd98ena56kb1tvtrd67tvb5et3nfbf.apps.googleusercontent.com</string>
<key>REVERSED_CLIENT_ID</key> <key>REVERSED_CLIENT_ID</key>
<string>com.googleusercontent.apps.994903990520-n6jd98ena56kb1tvtrd67tvb5et3nfbf</string> <string>com.googleusercontent.apps.994903990520-n6jd98ena56kb1tvtrd67tvb5et3nfbf</string>
<key>API_KEY</key> <key>API_KEY</key>
<string>AIzaSyBbYqsR6t7JTi8_XFNEHd43IRuKlYGeI3U</string> <string>AIzaSyBbYqsR6t7JTi8_XFNEHd43IRuKlYGeI3U</string>
<key>GCM_SENDER_ID</key> <key>GCM_SENDER_ID</key>
<string>994903990520</string> <string>994903990520</string>
<key>PLIST_VERSION</key> <key>PLIST_VERSION</key>
<string>1</string> <string>1</string>
<key>BUNDLE_ID</key> <key>BUNDLE_ID</key>
<string>com.example.justmusic</string> <string>com.example.justmusic</string>
<key>PROJECT_ID</key> <key>PROJECT_ID</key>
<string>justmusic-435d5</string> <string>justmusic-435d5</string>
<key>STORAGE_BUCKET</key> <key>STORAGE_BUCKET</key>
<string>justmusic-435d5.appspot.com</string> <string>justmusic-435d5.appspot.com</string>
<key>IS_ADS_ENABLED</key> <key>IS_ADS_ENABLED</key>
<false></false> <false></false>
<key>IS_ANALYTICS_ENABLED</key> <key>IS_ANALYTICS_ENABLED</key>
<false></false> <false></false>
<key>IS_APPINVITE_ENABLED</key> <key>IS_APPINVITE_ENABLED</key>
<true></true> <true></true>
<key>IS_GCM_ENABLED</key> <key>IS_GCM_ENABLED</key>
<true></true> <true></true>
<key>IS_SIGNIN_ENABLED</key> <key>IS_SIGNIN_ENABLED</key>
<true></true> <true></true>
<key>GOOGLE_APP_ID</key> <key>GOOGLE_APP_ID</key>
<string>1:994903990520:ios:93188f32e320babe0a9b0d</string> <string>1:994903990520:ios:93188f32e320babe0a9b0d</string>
</dict> </dict>
</plist> </plist>

@ -1,7 +1,7 @@
{ {
"file_generated_by": "FlutterFire CLI", "file_generated_by": "FlutterFire CLI",
"purpose": "FirebaseAppID & ProjectID for this Firebase app in this directory", "purpose": "FirebaseAppID & ProjectID for this Firebase app in this directory",
"GOOGLE_APP_ID": "1:994903990520:ios:93188f32e320babe0a9b0d", "GOOGLE_APP_ID": "1:994903990520:ios:93188f32e320babe0a9b0d",
"FIREBASE_PROJECT_ID": "justmusic-435d5", "FIREBASE_PROJECT_ID": "justmusic-435d5",
"GCM_SENDER_ID": "994903990520" "GCM_SENDER_ID": "994903990520"
} }

@ -1,68 +1,68 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
class LoginButton extends StatefulWidget { class LoginButton extends StatefulWidget {
final Function callback; final Function callback;
const LoginButton({Key? key, required this.callback}) : super(key: key); const LoginButton({Key? key, required this.callback}) : super(key: key);
@override @override
State<LoginButton> createState() => _LoginButtonState(); State<LoginButton> createState() => _LoginButtonState();
} }
class _LoginButtonState extends State<LoginButton> { class _LoginButtonState extends State<LoginButton> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ElevatedButton( return ElevatedButton(
onPressed: () { onPressed: () {
widget.callback(); widget.callback();
}, },
style: ButtonStyle( style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Color(0xFF1C1C1C)), backgroundColor: MaterialStateProperty.all(Color(0xFF1C1C1C)),
overlayColor: overlayColor:
MaterialStateProperty.all(Color(0xffD3C2FF).withOpacity(0.2)), MaterialStateProperty.all(Color(0xffD3C2FF).withOpacity(0.2)),
shape: MaterialStateProperty.all(RoundedRectangleBorder( shape: MaterialStateProperty.all(RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18), borderRadius: BorderRadius.circular(18),
)), )),
padding: MaterialStateProperty.all(EdgeInsets.all(0.0)), padding: MaterialStateProperty.all(EdgeInsets.all(0.0)),
), ),
child: Ink( child: Ink(
decoration: BoxDecoration( decoration: BoxDecoration(
gradient: RadialGradient( gradient: RadialGradient(
center: Alignment(0, 3), center: Alignment(0, 3),
focalRadius: 10, focalRadius: 10,
radius: 2.5, radius: 2.5,
stops: <double>[0.4, 1.0], stops: <double>[0.4, 1.0],
colors: [Color(0xff9E78FF), Color(0xff633AF4)], colors: [Color(0xff9E78FF), Color(0xff633AF4)],
), ),
borderRadius: BorderRadius.circular(18.0), borderRadius: BorderRadius.circular(18.0),
border: Border.all( border: Border.all(
color: Color(0xff1C1C1C), color: Color(0xff1C1C1C),
width: 5, width: 5,
), ),
), ),
child: Container( child: Container(
padding: EdgeInsets.only(top: 20.h, bottom: 20.h), padding: EdgeInsets.only(top: 20.h, bottom: 20.h),
constraints: BoxConstraints(maxWidth: 600, minHeight: 50), constraints: BoxConstraints(maxWidth: 600, minHeight: 50),
decoration: BoxDecoration( decoration: BoxDecoration(
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: Color(0xff7E56F9).withOpacity(0.23), color: Color(0xff7E56F9).withOpacity(0.23),
spreadRadius: 4, spreadRadius: 4,
blurRadius: 40, blurRadius: 40,
offset: Offset(0, 3), // changes position of shadow offset: Offset(0, 3), // changes position of shadow
), ),
], ],
), ),
alignment: Alignment.center, alignment: Alignment.center,
child: Text( child: Text(
"Se connecter", "Se connecter",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle(color: Colors.white, fontSize: 18), style: TextStyle(color: Colors.white, fontSize: 18),
), ),
), ),
), ),
); );
} }
} }

@ -1,100 +1,100 @@
import 'package:flutter/Material.dart'; import 'package:flutter/Material.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:justmusic/components/play_button_component.dart'; import 'package:justmusic/components/play_button_component.dart';
import 'package:text_scroll/text_scroll.dart'; import 'package:text_scroll/text_scroll.dart';
import '../model/Music.dart'; import '../model/Music.dart';
class MusicListComponent extends StatelessWidget { class MusicListComponent extends StatelessWidget {
final Music music; final Music music;
const MusicListComponent({ const MusicListComponent({
Key? key, Key? key,
required this.music, required this.music,
}) : super(key: key); }) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
padding: const EdgeInsets.only(bottom: 14), padding: const EdgeInsets.only(bottom: 14),
child: Row( child: Row(
children: [ children: [
LayoutBuilder( LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) { builder: (BuildContext context, BoxConstraints constraints) {
if (music.cover != null) { if (music.cover != null) {
return ClipRRect( return ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(5)), borderRadius: BorderRadius.all(Radius.circular(5)),
child: music.cover != null child: music.cover != null
? FadeInImage.assetNetwork( ? FadeInImage.assetNetwork(
height: 60, height: 60,
width: 60, width: 60,
fit: BoxFit.cover, fit: BoxFit.cover,
placeholder: "assets/images/loadingPlaceholder.gif", placeholder: "assets/images/loadingPlaceholder.gif",
image: music.cover!) image: music.cover!)
: Container( : Container(
height: 60, height: 60,
width: 60, width: 60,
color: Colors.grey, color: Colors.grey,
), ),
); );
} else { } else {
return Image( return Image(
image: AssetImage("assets/images/exemple_cover.png"), image: AssetImage("assets/images/exemple_cover.png"),
height: 60, height: 60,
width: 60, width: 60,
); );
} }
}), }),
const SizedBox( const SizedBox(
width: 10, width: 10,
), ),
Expanded( Expanded(
flex: 10, flex: 10,
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Row( Row(
children: [ children: [
Flexible( Flexible(
flex: 8, flex: 8,
child: ScrollConfiguration( child: ScrollConfiguration(
behavior: behavior:
ScrollBehavior().copyWith(scrollbars: false), ScrollBehavior().copyWith(scrollbars: false),
child: TextScroll( child: TextScroll(
music.title ?? "Unknown", music.title ?? "Unknown",
style: GoogleFonts.plusJakartaSans( style: GoogleFonts.plusJakartaSans(
fontSize: 16, fontSize: 16,
color: Colors.white, color: Colors.white,
fontWeight: FontWeight.w700), fontWeight: FontWeight.w700),
mode: TextScrollMode.endless, mode: TextScrollMode.endless,
pauseBetween: Duration(milliseconds: 2500), pauseBetween: Duration(milliseconds: 2500),
velocity: Velocity(pixelsPerSecond: Offset(30, 0)), velocity: Velocity(pixelsPerSecond: Offset(30, 0)),
intervalSpaces: 10, intervalSpaces: 10,
), ),
)), )),
Icon( Icon(
Icons.explicit, Icons.explicit,
color: Colors.grey.withOpacity(0.7), color: Colors.grey.withOpacity(0.7),
size: 17, size: 17,
), ),
], ],
), ),
ScrollConfiguration( ScrollConfiguration(
behavior: ScrollBehavior().copyWith(scrollbars: false), behavior: ScrollBehavior().copyWith(scrollbars: false),
child: Text( child: Text(
music.artists.first.name ?? "Unknown", music.artists.first.name ?? "Unknown",
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: GoogleFonts.plusJakartaSans( style: GoogleFonts.plusJakartaSans(
color: Colors.grey, fontWeight: FontWeight.w400), color: Colors.grey, fontWeight: FontWeight.w400),
)) ))
], ],
), ),
), ),
Spacer(), Spacer(),
PlayButtonComponent( PlayButtonComponent(
urlPreview: music.previewUrl, urlPreview: music.previewUrl,
) )
], ],
), ),
); );
} }
} }

@ -1,72 +1,72 @@
import 'package:audioplayers/audioplayers.dart'; import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/Material.dart'; import 'package:flutter/Material.dart';
import 'package:flutter_animated_play_button/flutter_animated_play_button.dart'; import 'package:flutter_animated_play_button/flutter_animated_play_button.dart';
import 'package:ionicons/ionicons.dart'; import 'package:ionicons/ionicons.dart';
class PlayButtonComponent extends StatefulWidget { class PlayButtonComponent extends StatefulWidget {
final String? urlPreview; final String? urlPreview;
const PlayButtonComponent({Key? key, required this.urlPreview}) const PlayButtonComponent({Key? key, required this.urlPreview})
: super(key: key); : super(key: key);
@override @override
State<PlayButtonComponent> createState() => _PlayButtonComponentState(); State<PlayButtonComponent> createState() => _PlayButtonComponentState();
} }
class _PlayButtonComponentState extends State<PlayButtonComponent> { class _PlayButtonComponentState extends State<PlayButtonComponent> {
bool isPlaying = true; bool isPlaying = true;
final player = AudioPlayer(); final player = AudioPlayer();
void switchStatePlaying() { void switchStatePlaying() {
setState(() { setState(() {
isPlaying = !isPlaying; isPlaying = !isPlaying;
}); });
stopSong(); stopSong();
} }
@override @override
void initState() { void initState() {
player.onPlayerComplete.listen((event) { player.onPlayerComplete.listen((event) {
switchStatePlaying(); switchStatePlaying();
}); });
super.initState(); super.initState();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (!isPlaying) { if (!isPlaying) {
playSong(); playSong();
} else {} } else {}
return isPlaying return isPlaying
? GestureDetector( ? GestureDetector(
onTap: switchStatePlaying, onTap: switchStatePlaying,
child: Container( child: Container(
width: 30, width: 30,
height: 30, height: 30,
child: Icon( child: Icon(
Ionicons.play_circle_outline, Ionicons.play_circle_outline,
color: Colors.grey.withOpacity(0.3), color: Colors.grey.withOpacity(0.3),
size: 30, size: 30,
)), )),
) )
: GestureDetector( : GestureDetector(
onTap: switchStatePlaying, onTap: switchStatePlaying,
child: Container( child: Container(
width: 30, width: 30,
height: 30, height: 30,
child: AnimatedPlayButton( child: AnimatedPlayButton(
stopped: false, stopped: false,
color: Colors.grey.withOpacity(0.3), color: Colors.grey.withOpacity(0.3),
onPressed: () {}, onPressed: () {},
), ),
)); ));
} }
Future<void> playSong() async { Future<void> playSong() async {
if (widget.urlPreview != null) { if (widget.urlPreview != null) {
await player.play(UrlSource(widget.urlPreview ?? "")); await player.play(UrlSource(widget.urlPreview ?? ""));
} }
} }
Future<void> stopSong() async { Future<void> stopSong() async {
await player.stop(); await player.stop();
} }
} }

@ -1,76 +1,76 @@
// File generated by FlutterFire CLI. // File generated by FlutterFire CLI.
// ignore_for_file: lines_longer_than_80_chars, avoid_classes_with_only_static_members // 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:firebase_core/firebase_core.dart' show FirebaseOptions;
import 'package:flutter/foundation.dart' import 'package:flutter/foundation.dart'
show defaultTargetPlatform, kIsWeb, TargetPlatform; show defaultTargetPlatform, kIsWeb, TargetPlatform;
/// Default [FirebaseOptions] for use with your Firebase apps. /// Default [FirebaseOptions] for use with your Firebase apps.
/// ///
/// Example: /// Example:
/// ```dart /// ```dart
/// import 'firebase_options.dart'; /// import 'firebase_options.dart';
/// // ... /// // ...
/// await Firebase.initializeApp( /// await Firebase.initializeApp(
/// options: DefaultFirebaseOptions.currentPlatform, /// options: DefaultFirebaseOptions.currentPlatform,
/// ); /// );
/// ``` /// ```
class DefaultFirebaseOptions { class DefaultFirebaseOptions {
static FirebaseOptions get currentPlatform { static FirebaseOptions get currentPlatform {
if (kIsWeb) { if (kIsWeb) {
return web; return web;
} }
switch (defaultTargetPlatform) { switch (defaultTargetPlatform) {
case TargetPlatform.android: case TargetPlatform.android:
return android; return android;
case TargetPlatform.iOS: case TargetPlatform.iOS:
return ios; return ios;
case TargetPlatform.macOS: case TargetPlatform.macOS:
throw UnsupportedError( throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for macos - ' 'DefaultFirebaseOptions have not been configured for macos - '
'you can reconfigure this by running the FlutterFire CLI again.', 'you can reconfigure this by running the FlutterFire CLI again.',
); );
case TargetPlatform.windows: case TargetPlatform.windows:
throw UnsupportedError( throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for windows - ' 'DefaultFirebaseOptions have not been configured for windows - '
'you can reconfigure this by running the FlutterFire CLI again.', 'you can reconfigure this by running the FlutterFire CLI again.',
); );
case TargetPlatform.linux: case TargetPlatform.linux:
throw UnsupportedError( throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for linux - ' 'DefaultFirebaseOptions have not been configured for linux - '
'you can reconfigure this by running the FlutterFire CLI again.', 'you can reconfigure this by running the FlutterFire CLI again.',
); );
default: default:
throw UnsupportedError( throw UnsupportedError(
'DefaultFirebaseOptions are not supported for this platform.', 'DefaultFirebaseOptions are not supported for this platform.',
); );
} }
} }
static const FirebaseOptions web = FirebaseOptions( static const FirebaseOptions web = FirebaseOptions(
apiKey: 'AIzaSyBv-Sba07nFFhctn6c3ARyvi9RfYwEKoNA', apiKey: 'AIzaSyBv-Sba07nFFhctn6c3ARyvi9RfYwEKoNA',
appId: '1:994903990520:web:724c75003432ddbc0a9b0d', appId: '1:994903990520:web:724c75003432ddbc0a9b0d',
messagingSenderId: '994903990520', messagingSenderId: '994903990520',
projectId: 'justmusic-435d5', projectId: 'justmusic-435d5',
authDomain: 'justmusic-435d5.firebaseapp.com', authDomain: 'justmusic-435d5.firebaseapp.com',
storageBucket: 'justmusic-435d5.appspot.com', storageBucket: 'justmusic-435d5.appspot.com',
measurementId: 'G-D4YRLXK9TQ', measurementId: 'G-D4YRLXK9TQ',
); );
static const FirebaseOptions android = FirebaseOptions( static const FirebaseOptions android = FirebaseOptions(
apiKey: 'AIzaSyCjkofl0nvfzQqRZPv_-H99WoyYa7O660g', apiKey: 'AIzaSyCjkofl0nvfzQqRZPv_-H99WoyYa7O660g',
appId: '1:994903990520:android:02a445b6561bf2820a9b0d', appId: '1:994903990520:android:02a445b6561bf2820a9b0d',
messagingSenderId: '994903990520', messagingSenderId: '994903990520',
projectId: 'justmusic-435d5', projectId: 'justmusic-435d5',
storageBucket: 'justmusic-435d5.appspot.com', storageBucket: 'justmusic-435d5.appspot.com',
); );
static const FirebaseOptions ios = FirebaseOptions( static const FirebaseOptions ios = FirebaseOptions(
apiKey: 'AIzaSyBbYqsR6t7JTi8_XFNEHd43IRuKlYGeI3U', apiKey: 'AIzaSyBbYqsR6t7JTi8_XFNEHd43IRuKlYGeI3U',
appId: '1:994903990520:ios:93188f32e320babe0a9b0d', appId: '1:994903990520:ios:93188f32e320babe0a9b0d',
messagingSenderId: '994903990520', messagingSenderId: '994903990520',
projectId: 'justmusic-435d5', projectId: 'justmusic-435d5',
storageBucket: 'justmusic-435d5.appspot.com', storageBucket: 'justmusic-435d5.appspot.com',
iosClientId: '994903990520-n6jd98ena56kb1tvtrd67tvb5et3nfbf.apps.googleusercontent.com', iosClientId: '994903990520-n6jd98ena56kb1tvtrd67tvb5et3nfbf.apps.googleusercontent.com',
iosBundleId: 'com.example.justmusic', iosBundleId: 'com.example.justmusic',
); );
} }

@ -1,68 +1,68 @@
import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:justmusic/screens/explanations_screen.dart'; import 'package:justmusic/screens/explanations_screen.dart';
import 'package:justmusic/screens/feed_screen.dart'; import 'package:justmusic/screens/feed_screen.dart';
import 'package:justmusic/screens/login_screen.dart'; import 'package:justmusic/screens/login_screen.dart';
import 'package:justmusic/screens/post_screen.dart'; import 'package:justmusic/screens/post_screen.dart';
import 'package:justmusic/screens/profile_screen.dart'; import 'package:justmusic/screens/profile_screen.dart';
import 'package:justmusic/screens/registration_screen.dart'; import 'package:justmusic/screens/registration_screen.dart';
import 'package:justmusic/screens/welcome_screen.dart'; import 'package:justmusic/screens/welcome_screen.dart';
import 'package:justmusic/view_model/MusicViewModel.dart'; import 'package:justmusic/view_model/MusicViewModel.dart';
import 'package:justmusic/view_model/UserViewModel.dart'; import 'package:justmusic/view_model/UserViewModel.dart';
import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart'; import 'firebase_options.dart';
Future<void> main() async { Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp( await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform, options: DefaultFirebaseOptions.currentPlatform,
); );
runApp(const MyApp()); runApp(const MyApp());
} }
class MyApp extends StatelessWidget { class MyApp extends StatelessWidget {
// ugly as fuck // ugly as fuck
static FirebaseFirestore db = FirebaseFirestore.instance; static FirebaseFirestore db = FirebaseFirestore.instance;
static UserViewModel userViewModel = UserViewModel(); static UserViewModel userViewModel = UserViewModel();
static MusicViewModel musicViewModel = MusicViewModel(); static MusicViewModel musicViewModel = MusicViewModel();
const MyApp({super.key}); const MyApp({super.key});
// This widget is the root of your application. // This widget is the root of your application.
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky); SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
Paint.enableDithering = true; Paint.enableDithering = true;
return ScreenUtilInit( return ScreenUtilInit(
builder: (context, child) { builder: (context, child) {
return MaterialApp( return MaterialApp(
routes: { routes: {
'/welcome': (context) => WellcomeScreen(), '/welcome': (context) => WellcomeScreen(),
'/feed': (context) => FeedScreen(), '/feed': (context) => FeedScreen(),
'/login': (context) => LoginScreen(), '/login': (context) => LoginScreen(),
'/register': (context) => RegistrationScreen(), '/register': (context) => RegistrationScreen(),
'/post': (context) => PostScreen(), '/post': (context) => PostScreen(),
'/profile': (context) => ProfileScreen(), '/profile': (context) => ProfileScreen(),
'/explanation': (context) => ExplanationsScreen(), '/explanation': (context) => ExplanationsScreen(),
}, },
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,
theme: ThemeData( theme: ThemeData(
// This is the theme of your application. // This is the theme of your application.
// //
// Try running your application with "flutter run". You'll see the // Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try // application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke // changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run", // "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE). // or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application // Notice that the counter didn't reset back to zero; the application
// is not restarted. // is not restarted.
primarySwatch: Colors.blue, primarySwatch: Colors.blue,
), ),
home: WellcomeScreen()); home: WellcomeScreen());
}, },
designSize: Size(390, 844), designSize: Size(390, 844),
); );
} }
} }

@ -1,61 +1,61 @@
import 'Artist.dart'; import 'Artist.dart';
class Music { class Music {
final String _id; final String _id;
String? _title; String? _title;
String? _cover; String? _cover;
String? _previewUrl; String? _previewUrl;
DateTime? _date; DateTime? _date;
double? _duration; double? _duration;
bool _explicit = false; bool _explicit = false;
List<Artist> _artists; List<Artist> _artists;
// Constructor // Constructor
Music(this._id, this._title, this._cover, this._previewUrl, this._date, Music(this._id, this._title, this._cover, this._previewUrl, this._date,
this._duration, this._explicit, this._artists); this._duration, this._explicit, this._artists);
//Getters and setters //Getters and setters
String? get id => _id; String? get id => _id;
String? get title => _title; String? get title => _title;
set title(String? value) { set title(String? value) {
_title = value; _title = value;
} }
String? get cover => _cover; String? get cover => _cover;
set cover(String? value) { set cover(String? value) {
_cover = value; _cover = value;
} }
String? get previewUrl => _previewUrl; String? get previewUrl => _previewUrl;
set previewUrl(String? value) { set previewUrl(String? value) {
_previewUrl = value; _previewUrl = value;
} }
DateTime? get date => _date; DateTime? get date => _date;
set date(DateTime? value) { set date(DateTime? value) {
_date = value; _date = value;
} }
double? get duration => _duration; double? get duration => _duration;
set duration(double? value) { set duration(double? value) {
_duration = value; _duration = value;
} }
bool get explicit => _explicit; bool get explicit => _explicit;
set explicit(bool value) { set explicit(bool value) {
_explicit = value; _explicit = value;
} }
List<Artist> get artists => _artists; List<Artist> get artists => _artists;
set artists(List<Artist> value) { set artists(List<Artist> value) {
_artists = value; _artists = value;
} }
} }

@ -1,60 +1,60 @@
class User { class User {
final String _id; final String _id;
String _pseudo; String _pseudo;
String _country; String _country;
String _mail; String _mail;
String _pp; String _pp;
int _followers; int _followers;
int _capsules; int _capsules;
int _followed; int _followed;
List<User> friends = []; List<User> friends = [];
// Constructor // Constructor
User(this._id, this._pseudo, this._country, this._mail, this._pp, User(this._id, this._pseudo, this._country, this._mail, this._pp,
this._followers, this._capsules, this._followed, this.friends); this._followers, this._capsules, this._followed, this.friends);
//Getters and setters //Getters and setters
String get id => _id; String get id => _id;
String get pseudo => _pseudo; String get pseudo => _pseudo;
set pseudo(String value) { set pseudo(String value) {
_pseudo = value; _pseudo = value;
} }
String get country => _country; String get country => _country;
set country(String value) { set country(String value) {
_country = value; _country = value;
} }
String get mail => _mail; String get mail => _mail;
set mail(String value) { set mail(String value) {
_mail = value; _mail = value;
} }
String get pp => _pp; String get pp => _pp;
set pp(String value) { set pp(String value) {
_pp = value; _pp = value;
} }
int get capsules => _capsules; int get capsules => _capsules;
set capsules(int value) { set capsules(int value) {
_capsules = value; _capsules = value;
} }
int get followed => _followed; int get followed => _followed;
set followed(int value) { set followed(int value) {
_followed = value; _followed = value;
} }
int get followers => _followers; int get followers => _followers;
set followers(int value) { set followers(int value) {
_followers = value; _followers = value;
} }
} }

@ -1,31 +1,31 @@
import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:justmusic/model/User.dart'; import 'package:justmusic/model/User.dart';
class UserMapper { class UserMapper {
static User toModel(DocumentSnapshot<Map<String, dynamic>> snapshot, static User toModel(DocumentSnapshot<Map<String, dynamic>> snapshot,
SnapshotOptions? options) { SnapshotOptions? options) {
final data = snapshot.data(); final data = snapshot.data();
return User( return User(
data?["uid"] ?? "", data?["uid"] ?? "",
data?["pseudo"] ?? "", data?["pseudo"] ?? "",
data?["country"] ?? "", data?["country"] ?? "",
data?["mail"] ?? "", data?["mail"] ?? "",
data?["profilePicture"] ?? "", data?["profilePicture"] ?? "",
data?["followers"] ?? 0, data?["followers"] ?? 0,
data?["nbCapsules"] ?? 0, data?["nbCapsules"] ?? 0,
data?["followed"] ?? 0, data?["followed"] ?? 0,
data?['friends'] is List<User> ? List.from(data?['friends']) : []); data?['friends'] is List<User> ? List.from(data?['friends']) : []);
} }
/* /*
static Map<String, dynamic> toFirebase(User user) { static Map<String, dynamic> toFirebase(User user) {
return { return {
if (user.pseudo != null) "name": u, if (user.pseudo != null) "name": u,
if (user.country != null) "state": state, if (user.country != null) "state": state,
if (user.mail != null) "country": country, if (user.mail != null) "country": country,
if (user.pp != null) "capital": capital, if (user.pp != null) "capital": capital,
if (user.followers != null) "population": population, if (user.followers != null) "population": population,
if (user.capsules != null) "regions": regions, if (user.capsules != null) "regions": regions,
if () if ()
}; };
}*/ }*/
} }

@ -1,297 +1,297 @@
import 'package:circular_reveal_animation/circular_reveal_animation.dart'; import 'package:circular_reveal_animation/circular_reveal_animation.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import '../components/comment_component.dart'; import '../components/comment_component.dart';
import '../components/post_component.dart'; import '../components/post_component.dart';
import '../components/top_nav_bar_component.dart'; import '../components/top_nav_bar_component.dart';
import '../values/constants.dart'; import '../values/constants.dart';
class FeedScreen extends StatefulWidget { class FeedScreen extends StatefulWidget {
const FeedScreen({Key? key}) : super(key: key); const FeedScreen({Key? key}) : super(key: key);
@override @override
State<FeedScreen> createState() => _FeedScreenState(); State<FeedScreen> createState() => _FeedScreenState();
} }
class _FeedScreenState extends State<FeedScreen> class _FeedScreenState extends State<FeedScreen>
with SingleTickerProviderStateMixin { with SingleTickerProviderStateMixin {
late AnimationController animationController; late AnimationController animationController;
late Animation<double> animation; late Animation<double> animation;
late List<PostComponent> friendFeed; late List<PostComponent> friendFeed;
late List<PostComponent> discoveryFeed; late List<PostComponent> discoveryFeed;
late List<PostComponent> displayFeed; late List<PostComponent> displayFeed;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
friendFeed = [ friendFeed = [
PostComponent( PostComponent(
callback: openDetailPost, callback: openDetailPost,
), ),
PostComponent( PostComponent(
callback: openDetailPost, callback: openDetailPost,
), ),
PostComponent( PostComponent(
callback: openDetailPost, callback: openDetailPost,
), ),
]; ];
discoveryFeed = [ discoveryFeed = [
PostComponent(callback: openDetailPost), PostComponent(callback: openDetailPost),
]; ];
displayFeed = friendFeed; displayFeed = friendFeed;
animationController = AnimationController( animationController = AnimationController(
vsync: this, vsync: this,
duration: Duration(milliseconds: 400), duration: Duration(milliseconds: 400),
); );
animation = CurvedAnimation( animation = CurvedAnimation(
parent: animationController, parent: animationController,
curve: Curves.easeInOutSine, curve: Curves.easeInOutSine,
); );
animationController.forward(); animationController.forward();
} }
Future<void> resetFullScreen() async { Future<void> resetFullScreen() async {
await SystemChannels.platform.invokeMethod<void>( await SystemChannels.platform.invokeMethod<void>(
'SystemChrome.restoreSystemUIOverlays', 'SystemChrome.restoreSystemUIOverlays',
); );
} }
void changeFeed(bool choice) { void changeFeed(bool choice) {
// Mettez ici le code pour l'action que vous souhaitez effectuer avec le paramètre // Mettez ici le code pour l'action que vous souhaitez effectuer avec le paramètre
if (choice) { if (choice) {
setState(() { setState(() {
animationController.reset(); animationController.reset();
displayFeed = friendFeed; displayFeed = friendFeed;
animationController.forward(); animationController.forward();
}); });
} else { } else {
setState(() { setState(() {
animationController.reset(); animationController.reset();
displayFeed = discoveryFeed; displayFeed = discoveryFeed;
animationController.forward(); animationController.forward();
}); });
} }
} }
void openDetailPost() { void openDetailPost() {
showModalBottomSheet( showModalBottomSheet(
backgroundColor: bgModal, backgroundColor: bgModal,
elevation: 1, elevation: 1,
constraints: const BoxConstraints( constraints: const BoxConstraints(
maxWidth: 600, maxWidth: 600,
), ),
isScrollControlled: true, isScrollControlled: true,
context: context, context: context,
shape: const RoundedRectangleBorder( shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only( borderRadius: BorderRadius.only(
topLeft: Radius.circular(20), topRight: Radius.circular(20))), topLeft: Radius.circular(20), topRight: Radius.circular(20))),
builder: ((context) { builder: ((context) {
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
FocusScopeNode currentFocus = FocusScope.of(context); FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus) { if (!currentFocus.hasPrimaryFocus) {
currentFocus.unfocus(); currentFocus.unfocus();
resetFullScreen(); resetFullScreen();
} }
}, },
child: Container( child: Container(
height: 720.h, height: 720.h,
margin: const EdgeInsets.only(top: 10), margin: const EdgeInsets.only(top: 10),
child: Column( child: Column(
children: [ children: [
Align( Align(
child: Container( child: Container(
width: 60, width: 60,
height: 5, height: 5,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white.withOpacity(0.3), color: Colors.white.withOpacity(0.3),
borderRadius: BorderRadius.circular(20))), borderRadius: BorderRadius.circular(20))),
), ),
const SizedBox( const SizedBox(
height: 20, height: 20,
), ),
Expanded( Expanded(
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.only( borderRadius: BorderRadius.only(
topRight: Radius.circular(15), topRight: Radius.circular(15),
topLeft: Radius.circular(15)), topLeft: Radius.circular(15)),
child: Padding( child: Padding(
padding: EdgeInsets.only( padding: EdgeInsets.only(
left: defaultPadding, right: defaultPadding), left: defaultPadding, right: defaultPadding),
child: SingleChildScrollView( child: SingleChildScrollView(
child: Wrap( child: Wrap(
// to apply margin in the main axis of the wrap // to apply margin in the main axis of the wrap
runSpacing: 10, runSpacing: 10,
children: [ children: [
PostComponent( PostComponent(
callback: null, callback: null,
), ),
Container(height: 10), Container(height: 10),
Align( Align(
child: RichText( child: RichText(
text: TextSpan( text: TextSpan(
text: "3", text: "3",
style: GoogleFonts.plusJakartaSans( style: GoogleFonts.plusJakartaSans(
color: Colors.white, color: Colors.white,
fontWeight: FontWeight.w600), fontWeight: FontWeight.w600),
children: [ children: [
TextSpan( TextSpan(
text: " commentaires", text: " commentaires",
style: GoogleFonts.plusJakartaSans( style: GoogleFonts.plusJakartaSans(
color: Colors.white, color: Colors.white,
fontWeight: FontWeight.w300), fontWeight: FontWeight.w300),
) )
])), ])),
), ),
SizedBox(height: 20), SizedBox(height: 20),
CommentComponent(), CommentComponent(),
CommentComponent(), CommentComponent(),
CommentComponent(), CommentComponent(),
Container(height: 10), Container(height: 10),
], ],
), ),
), ),
), ),
), ),
), ),
Padding( Padding(
padding: EdgeInsets.only( padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom), bottom: MediaQuery.of(context).viewInsets.bottom),
child: Container( child: Container(
height: 70, height: 70,
width: double.infinity, width: double.infinity,
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border( border: Border(
top: BorderSide(color: grayColor, width: 2)), top: BorderSide(color: grayColor, width: 2)),
color: textFieldMessage), color: textFieldMessage),
child: Center( child: Center(
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20), padding: const EdgeInsets.symmetric(horizontal: 20),
child: Row( child: Row(
children: [ children: [
ClipOval( ClipOval(
child: SizedBox.fromSize( child: SizedBox.fromSize(
// Image radius // Image radius
child: const Image( child: const Image(
image: AssetImage( image: AssetImage(
"assets/images/exemple_profile.png"), "assets/images/exemple_profile.png"),
width: 45, width: 45,
), ),
), ),
), ),
SizedBox( SizedBox(
width: 10, width: 10,
), ),
Expanded( Expanded(
child: TextField( child: TextField(
keyboardAppearance: Brightness.dark, keyboardAppearance: Brightness.dark,
cursorColor: primaryColor, cursorColor: primaryColor,
keyboardType: TextInputType.emailAddress, keyboardType: TextInputType.emailAddress,
style: GoogleFonts.plusJakartaSans( style: GoogleFonts.plusJakartaSans(
color: Colors.white), color: Colors.white),
decoration: InputDecoration( decoration: InputDecoration(
suffixIcon: Icon( suffixIcon: Icon(
Icons.send, Icons.send,
color: grayText, color: grayText,
size: 20, size: 20,
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderSide: BorderSide( borderSide: BorderSide(
width: 1, color: grayText), width: 1, color: grayText),
borderRadius: BorderRadius.all( borderRadius: BorderRadius.all(
Radius.circular(100))), Radius.circular(100))),
contentPadding: EdgeInsets.only( contentPadding: EdgeInsets.only(
top: 0, top: 0,
bottom: 0, bottom: 0,
left: 20, left: 20,
right: 20), right: 20),
fillColor: bgModal, fillColor: bgModal,
filled: true, filled: true,
focusColor: focusColor:
Color.fromRGBO(255, 255, 255, 0.30), Color.fromRGBO(255, 255, 255, 0.30),
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderSide: BorderSide( borderSide: BorderSide(
width: 1, color: grayText), width: 1, color: grayText),
borderRadius: BorderRadius.all( borderRadius: BorderRadius.all(
Radius.circular(100))), Radius.circular(100))),
hintText: 'Ajoutez une réponse...', hintText: 'Ajoutez une réponse...',
hintStyle: GoogleFonts.plusJakartaSans( hintStyle: GoogleFonts.plusJakartaSans(
color: grayText)), color: grayText)),
), ),
) )
], ],
), ),
), ),
)), )),
), ),
], ],
), ),
), ),
); );
}), }),
); );
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
resizeToAvoidBottomInset: true, resizeToAvoidBottomInset: true,
backgroundColor: bgColor, backgroundColor: bgColor,
body: Stack( body: Stack(
children: [ children: [
CircularRevealAnimation( CircularRevealAnimation(
animation: animation, animation: animation,
centerOffset: Offset(30.w, -100), centerOffset: Offset(30.w, -100),
child: SingleChildScrollView( child: SingleChildScrollView(
child: SizedBox( child: SizedBox(
width: double.infinity, width: double.infinity,
child: Align( child: Align(
child: ConstrainedBox( child: ConstrainedBox(
constraints: BoxConstraints(maxWidth: 600), constraints: BoxConstraints(maxWidth: 600),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: defaultPadding), horizontal: defaultPadding),
child: Container( child: Container(
width: double.infinity, width: double.infinity,
child: Padding( child: Padding(
padding: EdgeInsets.only(top: 100.h), padding: EdgeInsets.only(top: 100.h),
child: SingleChildScrollView( child: SingleChildScrollView(
child: Wrap( child: Wrap(
runSpacing: 60, runSpacing: 60,
children: displayFeed, children: displayFeed,
), ),
)), )),
), ),
), ),
), ),
)), )),
), ),
), ),
IgnorePointer( IgnorePointer(
child: Container( child: Container(
height: 240.h, height: 240.h,
decoration: BoxDecoration( decoration: BoxDecoration(
gradient: LinearGradient(begin: Alignment.topRight, stops: [ gradient: LinearGradient(begin: Alignment.topRight, stops: [
0.3, 0.3,
1 1
], colors: [ ], colors: [
bgColor.withOpacity(0.9), bgColor.withOpacity(0.9),
bgColor.withOpacity(0) bgColor.withOpacity(0)
])), ])),
), ),
), ),
Align( Align(
alignment: Alignment.topCenter, alignment: Alignment.topCenter,
child: ConstrainedBox( child: ConstrainedBox(
constraints: BoxConstraints(maxWidth: 800), constraints: BoxConstraints(maxWidth: 800),
child: TopNavBarComponent(callback: changeFeed), child: TopNavBarComponent(callback: changeFeed),
), ),
), ),
], ],
), ),
); );
} }
} }

@ -1,373 +1,373 @@
import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_signin_button/button_list.dart'; import 'package:flutter_signin_button/button_list.dart';
import 'package:flutter_signin_button/button_view.dart'; import 'package:flutter_signin_button/button_view.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:justmusic/main.dart'; import 'package:justmusic/main.dart';
import 'package:justmusic/values/constants.dart'; import 'package:justmusic/values/constants.dart';
import '../components/login_button.dart'; import '../components/login_button.dart';
class LoginScreen extends StatefulWidget { class LoginScreen extends StatefulWidget {
const LoginScreen({Key? key}) : super(key: key); const LoginScreen({Key? key}) : super(key: key);
@override @override
State<LoginScreen> createState() => _LoginScreenState(); State<LoginScreen> createState() => _LoginScreenState();
} }
class _LoginScreenState extends State<LoginScreen> { class _LoginScreenState extends State<LoginScreen> {
bool passenable = true; bool passenable = true;
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
final _userMailTextField = TextEditingController(); final _userMailTextField = TextEditingController();
final _passwordTextField = TextEditingController(); final _passwordTextField = TextEditingController();
handleLogin() async { handleLogin() async {
if (_formKey.currentState!.validate()) { if (_formKey.currentState!.validate()) {
try { try {
await MyApp.userViewModel await MyApp.userViewModel
.login(_userMailTextField.text, _passwordTextField.text); .login(_userMailTextField.text, _passwordTextField.text);
Navigator.pushNamed(context, '/explanation'); Navigator.pushNamed(context, '/feed');
} catch (e) { } catch (e) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
content: Text( content: Text(
e.toString() ?? "", e.toString() ?? "",
style: GoogleFonts.plusJakartaSans( style: GoogleFonts.plusJakartaSans(
color: Colors.white, color: Colors.white,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
fontSize: 20.h), fontSize: 20.h),
), ),
backgroundColor: Colors.red, backgroundColor: Colors.red,
), ),
); );
} }
} }
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GestureDetector( return GestureDetector(
onTap: () => FocusManager.instance.primaryFocus?.unfocus(), onTap: () => FocusManager.instance.primaryFocus?.unfocus(),
child: Scaffold( child: Scaffold(
resizeToAvoidBottomInset: false, resizeToAvoidBottomInset: false,
backgroundColor: bgColor, backgroundColor: bgColor,
body: Align( body: Align(
child: SizedBox( child: SizedBox(
height: double.infinity, height: double.infinity,
width: 600, width: 600,
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Expanded( Expanded(
child: Padding( child: Padding(
padding: EdgeInsets.only(left: 40, right: 40), padding: EdgeInsets.only(left: 40, right: 40),
child: Form( child: Form(
key: _formKey, key: _formKey,
child: Column( child: Column(
crossAxisAlignment: crossAxisAlignment:
CrossAxisAlignment.center, CrossAxisAlignment.center,
children: [ children: [
Flexible( Flexible(
flex: 4, flex: 4,
child: Padding( child: Padding(
padding: EdgeInsets.only(bottom: 60), padding: EdgeInsets.only(bottom: 60),
child: Column( child: Column(
mainAxisAlignment: mainAxisAlignment:
MainAxisAlignment.end, MainAxisAlignment.end,
children: [ children: [
Text( Text(
"Te revoilà!", "Te revoilà!",
style: style:
GoogleFonts.plusJakartaSans( GoogleFonts.plusJakartaSans(
color: Colors.white, color: Colors.white,
fontWeight: fontWeight:
FontWeight.w600, FontWeight.w600,
fontSize: 38.h), fontSize: 38.h),
), ),
SizedBox( SizedBox(
height: 10, height: 10,
), ),
SizedBox( SizedBox(
width: 230.w, width: 230.w,
child: Text( child: Text(
"Bon retour parmis nous tu nous as manqué!", "Bon retour parmis nous tu nous as manqué!",
style: GoogleFonts style: GoogleFonts
.plusJakartaSans( .plusJakartaSans(
color: Colors.white, color: Colors.white,
fontWeight: fontWeight:
FontWeight.w400, FontWeight.w400,
fontSize: 20.h), fontSize: 20.h),
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
), ),
], ],
), ),
), ),
), ),
Expanded( Expanded(
flex: 5, flex: 5,
child: Column( child: Column(
crossAxisAlignment: crossAxisAlignment:
CrossAxisAlignment.end, CrossAxisAlignment.end,
mainAxisAlignment: mainAxisAlignment:
MainAxisAlignment.center, MainAxisAlignment.center,
children: [ children: [
TextFormField( TextFormField(
controller: _userMailTextField, controller: _userMailTextField,
keyboardAppearance: keyboardAppearance:
Brightness.dark, Brightness.dark,
validator: (value) { validator: (value) {
if (value == null || if (value == null ||
value.isEmpty) { value.isEmpty) {
return 'entrez un email valide'; return 'entrez un email valide';
} }
return null; return null;
}, },
cursorColor: primaryColor, cursorColor: primaryColor,
keyboardType: keyboardType:
TextInputType.emailAddress, TextInputType.emailAddress,
style: style:
GoogleFonts.plusJakartaSans( GoogleFonts.plusJakartaSans(
color: primaryColor), color: primaryColor),
decoration: InputDecoration( decoration: InputDecoration(
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderSide: BorderSide( borderSide: BorderSide(
width: 1, width: 1,
color: color:
strokeTextField), strokeTextField),
borderRadius: BorderRadius.all( borderRadius: BorderRadius.all(
Radius.circular(10))), Radius.circular(10))),
prefix: const Padding( prefix: const Padding(
padding: EdgeInsets.only( padding: EdgeInsets.only(
left: 20.0)), left: 20.0)),
suffix: const Padding( suffix: const Padding(
padding: EdgeInsets.only( padding: EdgeInsets.only(
left: 20.0)), left: 20.0)),
fillColor: bgTextField, fillColor: bgTextField,
filled: true, filled: true,
errorStyle: TextStyle( errorStyle: TextStyle(
fontSize: 9, height: 0.3), fontSize: 9, height: 0.3),
focusColor: Color.fromRGBO( focusColor: Color.fromRGBO(
255, 255, 255, 0.30), 255, 255, 255, 0.30),
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderSide: borderSide:
BorderSide(width: 1, color: strokeTextField), BorderSide(width: 1, color: strokeTextField),
borderRadius: BorderRadius.all(Radius.circular(10))), borderRadius: BorderRadius.all(Radius.circular(10))),
hintText: 'Email', hintText: 'Email',
hintStyle: GoogleFonts.plusJakartaSans(color: strokeTextField)), hintStyle: GoogleFonts.plusJakartaSans(color: strokeTextField)),
), ),
SizedBox( SizedBox(
height: 18, height: 18,
), ),
TextFormField( TextFormField(
controller: _passwordTextField, controller: _passwordTextField,
keyboardAppearance: keyboardAppearance:
Brightness.dark, Brightness.dark,
obscureText: passenable, obscureText: passenable,
validator: (value) { validator: (value) {
if (value == null || if (value == null ||
value.isEmpty) { value.isEmpty) {
return 'entrez un mot de passe valide'; return 'entrez un mot de passe valide';
} }
return null; return null;
}, },
cursorColor: primaryColor, cursorColor: primaryColor,
style: style:
GoogleFonts.plusJakartaSans( GoogleFonts.plusJakartaSans(
color: primaryColor), color: primaryColor),
decoration: InputDecoration( decoration: InputDecoration(
focusedBorder: focusedBorder:
OutlineInputBorder( OutlineInputBorder(
borderSide: BorderSide( borderSide: BorderSide(
width: 1, width: 1,
color: color:
strokeTextField), strokeTextField),
borderRadius: borderRadius:
BorderRadius.all( BorderRadius.all(
Radius.circular( Radius.circular(
10))), 10))),
fillColor: bgTextField, fillColor: bgTextField,
filled: true, filled: true,
focusColor: Color.fromRGBO( focusColor: Color.fromRGBO(
255, 255, 255, 0.30), 255, 255, 255, 0.30),
enabledBorder: enabledBorder:
OutlineInputBorder( OutlineInputBorder(
borderSide: BorderSide( borderSide: BorderSide(
width: 1, width: 1,
color: color:
strokeTextField), strokeTextField),
borderRadius: borderRadius:
BorderRadius.all( BorderRadius.all(
Radius.circular( Radius.circular(
10))), 10))),
hintText: 'Mot de passe', hintText: 'Mot de passe',
hintStyle: hintStyle:
GoogleFonts.plusJakartaSans( GoogleFonts.plusJakartaSans(
color: strokeTextField), color: strokeTextField),
prefix: const Padding( prefix: const Padding(
padding: EdgeInsets.only( padding: EdgeInsets.only(
left: 20.0)), left: 20.0)),
suffixIcon: Container( suffixIcon: Container(
padding: EdgeInsets.only( padding: EdgeInsets.only(
right: 10), right: 10),
margin: EdgeInsets.all(5), margin: EdgeInsets.all(5),
height: 3, height: 3,
child: InkWell( child: InkWell(
onTap: () { onTap: () {
setState(() { setState(() {
if (passenable) { if (passenable) {
passenable = false; passenable = false;
} else { } else {
passenable = true; passenable = true;
} }
}); });
}, },
// Image tapped // Image tapped
splashColor: splashColor:
Colors.white10, Colors.white10,
// Splash color over image // Splash color over image
child: Image( child: Image(
image: passenable image: passenable
? AssetImage( ? AssetImage(
"assets/images/show_icon.png") "assets/images/show_icon.png")
: AssetImage( : AssetImage(
"assets/images/hide_icon.png"), "assets/images/hide_icon.png"),
height: 2, height: 2,
), ),
)), )),
errorStyle: TextStyle( errorStyle: TextStyle(
fontSize: 9, height: 0.3), fontSize: 9, height: 0.3),
), ),
), ),
Padding( Padding(
padding: EdgeInsets.only(top: 10), padding: EdgeInsets.only(top: 10),
child: Text( child: Text(
"Mot de passe oublié?", "Mot de passe oublié?",
style: style:
GoogleFonts.plusJakartaSans( GoogleFonts.plusJakartaSans(
color: Colors.white), color: Colors.white),
), ),
), ),
SizedBox( SizedBox(
height: defaultPadding, height: defaultPadding,
), ),
SizedBox( SizedBox(
width: 600, width: 600,
child: LoginButton( child: LoginButton(
callback: handleLogin, callback: handleLogin,
)), )),
Align( Align(
child: GestureDetector( child: GestureDetector(
onTap: () { onTap: () {
Navigator.pushNamed( Navigator.pushNamed(
context, '/register'); context, '/register');
}, },
child: Padding( child: Padding(
padding: padding:
EdgeInsets.only(top: 20), EdgeInsets.only(top: 20),
child: RichText( child: RichText(
textAlign: TextAlign.center, textAlign: TextAlign.center,
text: TextSpan( text: TextSpan(
text: text:
'Pas encore inscrit?', 'Pas encore inscrit?',
style: GoogleFonts style: GoogleFonts
.plusJakartaSans( .plusJakartaSans(
color: color:
Colors.white, Colors.white,
fontWeight: fontWeight:
FontWeight FontWeight
.w400, .w400,
fontSize: 15), fontSize: 15),
children: <TextSpan>[ children: <TextSpan>[
TextSpan( TextSpan(
text: " Sinscire", text: " Sinscire",
style: GoogleFonts style: GoogleFonts
.plusJakartaSans( .plusJakartaSans(
fontSize: fontSize:
15, 15,
fontWeight: fontWeight:
FontWeight FontWeight
.w400, .w400,
color: color:
primaryColor)), primaryColor)),
], ],
), ),
), ),
), ),
), ),
), ),
], ],
), ),
), ),
Expanded( Expanded(
flex: 3, flex: 3,
child: Padding( child: Padding(
padding: EdgeInsets.only(top: 20), padding: EdgeInsets.only(top: 20),
child: Column( child: Column(
mainAxisAlignment: mainAxisAlignment:
MainAxisAlignment.start, MainAxisAlignment.start,
crossAxisAlignment: crossAxisAlignment:
CrossAxisAlignment.center, CrossAxisAlignment.center,
children: [ children: [
ConstrainedBox( ConstrainedBox(
constraints: BoxConstraints( constraints: BoxConstraints(
maxWidth: 600), maxWidth: 600),
child: Row( child: Row(
mainAxisAlignment: mainAxisAlignment:
MainAxisAlignment MainAxisAlignment
.spaceEvenly, .spaceEvenly,
children: [ children: [
Expanded( Expanded(
child: Container( child: Container(
color: color:
Color(0xFF3D3D3D), Color(0xFF3D3D3D),
height: 1, height: 1,
), ),
), ),
Padding( Padding(
padding: const EdgeInsets padding: const EdgeInsets
.only( .only(
left: left:
defaultPadding, defaultPadding,
right: right:
defaultPadding), defaultPadding),
child: Text( child: Text(
'Ou', 'Ou',
style: GoogleFonts style: GoogleFonts
.plusJakartaSans( .plusJakartaSans(
color: Colors color: Colors
.white, .white,
fontWeight: fontWeight:
FontWeight FontWeight
.bold), .bold),
), ),
), ),
Expanded( Expanded(
child: Container( child: Container(
height: 1, height: 1,
color: color:
Color(0xFF3D3D3D), Color(0xFF3D3D3D),
)), )),
], ],
), ),
), ),
SizedBox( SizedBox(
height: defaultPadding), height: defaultPadding),
SignInButton( SignInButton(
Buttons.Google, Buttons.Google,
text: "Login with Google", text: "Login with Google",
onPressed: () {}, onPressed: () {},
), ),
], ],
), ),
)) ))
], ],
)))) ))))
], ],
)), )),
))); )));
} }
} }

@ -1,408 +1,458 @@
import 'dart:ui'; import 'dart:ui';
import 'package:auto_size_text/auto_size_text.dart'; import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_signin_button/button_list.dart'; import 'package:flutter_signin_button/button_list.dart';
import 'package:flutter_signin_button/button_view.dart'; import 'package:flutter_signin_button/button_view.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:justmusic/values/constants.dart'; import 'package:justmusic/values/constants.dart';
import '../components/login_button.dart'; import '../components/login_button.dart';
import '../main.dart';
class RegistrationScreen extends StatefulWidget {
const RegistrationScreen({Key? key}) : super(key: key); class RegistrationScreen extends StatefulWidget {
const RegistrationScreen({Key? key}) : super(key: key);
@override
State<RegistrationScreen> createState() => _RegistrationScreenState(); @override
} State<RegistrationScreen> createState() => _RegistrationScreenState();
}
class _RegistrationScreenState extends State<RegistrationScreen> {
bool passenable = true; class _RegistrationScreenState extends State<RegistrationScreen> {
bool passenable = true;
@override final _formKey = GlobalKey<FormState>();
Widget build(BuildContext context) { final _userPseudoTextField = TextEditingController();
return Scaffold( final _userMailTextField = TextEditingController();
backgroundColor: bgColor, final _passwordTextField = TextEditingController();
body: Stack( final _passwordConfirmTextField = TextEditingController();
children: [
SingleChildScrollView( handleRegister() async {
child: SizedBox( if (_formKey.currentState!.validate()) {
width: double.infinity, try {
child: Column( await MyApp.userViewModel.register(_userPseudoTextField.text,
children: [ _passwordTextField.text, _userMailTextField.text);
Padding( Navigator.pushNamed(context, '/explanation');
padding: EdgeInsets.only(top: 100.h), } catch (e) {
child: AutoSizeText( ScaffoldMessenger.of(context).showSnackBar(
"On a besoin de ça!", SnackBar(
style: GoogleFonts.plusJakartaSans( content: Text(
color: Colors.white, e.toString() ?? "",
fontWeight: FontWeight.w600, style: GoogleFonts.plusJakartaSans(
fontSize: 30.w), color: Colors.white,
maxLines: 1, fontWeight: FontWeight.w400,
maxFontSize: 50, fontSize: 20.h),
overflow: TextOverflow.fade, ),
), backgroundColor: Colors.red,
), ),
ConstrainedBox( );
constraints: BoxConstraints(maxWidth: 600), }
child: Column( }
mainAxisAlignment: MainAxisAlignment.start, }
children: [
Padding( @override
padding: Widget build(BuildContext context) {
EdgeInsets.symmetric(horizontal: defaultPadding), return Scaffold(
child: Padding( backgroundColor: bgColor,
padding: EdgeInsets.only(bottom: 50.h), body: Form(
child: Column( key: _formKey,
mainAxisAlignment: MainAxisAlignment.end, child: Stack(
children: [ children: [
SizedBox( SingleChildScrollView(
height: 15.h, child: SizedBox(
), width: double.infinity,
SizedBox( child: Column(
width: 230.h, children: [
child: AutoSizeText( Padding(
"Promis cest rapide.", padding: EdgeInsets.only(top: 100.h),
style: GoogleFonts.plusJakartaSans( child: AutoSizeText(
color: Colors.white, "On a besoin de ça!",
fontWeight: FontWeight.w400, style: GoogleFonts.plusJakartaSans(
fontSize: 17.w), color: Colors.white,
maxFontSize: 20, fontWeight: FontWeight.w600,
textAlign: TextAlign.center, fontSize: 30.w),
), maxLines: 1,
), maxFontSize: 50,
], overflow: TextOverflow.fade,
), ),
), ),
), ConstrainedBox(
Padding( constraints: BoxConstraints(maxWidth: 600),
padding: EdgeInsets.only( child: Column(
bottom: 16.h, mainAxisAlignment: MainAxisAlignment.start,
left: defaultPadding, children: [
right: defaultPadding), Padding(
child: TextFormField( padding: EdgeInsets.symmetric(
keyboardAppearance: Brightness.dark, horizontal: defaultPadding),
validator: (value) { child: Padding(
if (value == null || value.isEmpty) { padding: EdgeInsets.only(bottom: 50.h),
return 'TODO'; child: Column(
} mainAxisAlignment: MainAxisAlignment.end,
return null; children: [
}, SizedBox(
cursorColor: primaryColor, height: 15.h,
keyboardType: TextInputType.emailAddress, ),
style: GoogleFonts.plusJakartaSans( SizedBox(
color: primaryColor, fontSize: 15), width: 230.h,
decoration: InputDecoration( child: AutoSizeText(
focusedBorder: OutlineInputBorder( "Promis cest rapide.",
borderSide: BorderSide( style: GoogleFonts.plusJakartaSans(
width: 1.sp, color: strokeTextField), color: Colors.white,
borderRadius: const BorderRadius.all( fontWeight: FontWeight.w400,
Radius.circular(10))), fontSize: 17.w),
contentPadding: const EdgeInsets.only( maxFontSize: 20,
top: 0, bottom: 0, left: defaultPadding), textAlign: TextAlign.center,
fillColor: bgTextField, ),
filled: true, ),
focusColor: ],
const Color.fromRGBO(255, 255, 255, 0.30), ),
enabledBorder: const OutlineInputBorder( ),
borderSide: BorderSide( ),
width: 1, color: strokeTextField), Padding(
borderRadius: BorderRadius.all( padding: EdgeInsets.only(
Radius.circular(10))), bottom: 16.h,
hintText: 'Pseudo', left: defaultPadding,
hintStyle: GoogleFonts.plusJakartaSans( right: defaultPadding),
color: strokeTextField)), child: TextFormField(
)), controller: _userPseudoTextField,
Padding( keyboardAppearance: Brightness.dark,
padding: EdgeInsets.only( validator: (value) {
bottom: 16.h, if (value == null || value.isEmpty) {
left: defaultPadding, return 'entrez un pseudo valide';
right: defaultPadding), }
child: TextFormField( return null;
keyboardAppearance: Brightness.dark, },
validator: (value) { cursorColor: primaryColor,
if (value == null || value.isEmpty) { keyboardType: TextInputType.emailAddress,
return 'TODO'; style: GoogleFonts.plusJakartaSans(
} color: primaryColor, fontSize: 15),
return null; decoration: InputDecoration(
}, focusedBorder: OutlineInputBorder(
cursorColor: primaryColor, borderSide: BorderSide(
keyboardType: TextInputType.emailAddress, width: 1.sp,
style: GoogleFonts.plusJakartaSans( color: strokeTextField),
color: primaryColor), borderRadius: const BorderRadius.all(
decoration: InputDecoration( Radius.circular(10))),
focusedBorder: OutlineInputBorder( prefix: const Padding(
borderSide: BorderSide( padding: EdgeInsets.only(left: 20.0)),
width: 1, color: strokeTextField), suffix: const Padding(
borderRadius: BorderRadius.all( padding: EdgeInsets.only(left: 20.0)),
Radius.circular(10))), fillColor: bgTextField,
contentPadding: EdgeInsets.only( filled: true,
top: 0, bottom: 0, left: defaultPadding), focusColor: const Color.fromRGBO(
fillColor: bgTextField, 255, 255, 255, 0.30),
filled: true, enabledBorder: const OutlineInputBorder(
focusColor: borderSide: BorderSide(
Color.fromRGBO(255, 255, 255, 0.30), width: 1, color: strokeTextField),
enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.all(
borderSide: BorderSide( Radius.circular(10))),
width: 1, color: strokeTextField), hintText: 'Pseudo',
borderRadius: BorderRadius.all( hintStyle: GoogleFonts.plusJakartaSans(
Radius.circular(10))), color: strokeTextField)),
hintText: 'Email', )),
hintStyle: GoogleFonts.plusJakartaSans( Padding(
color: strokeTextField)), padding: EdgeInsets.only(
)), bottom: 16.h,
Padding( left: defaultPadding,
padding: EdgeInsets.only( right: defaultPadding),
bottom: 16.h, child: TextFormField(
left: defaultPadding, controller: _userMailTextField,
right: defaultPadding), keyboardAppearance: Brightness.dark,
child: TextFormField( validator: (value) {
keyboardAppearance: Brightness.dark, if (value == null || value.isEmpty) {
obscureText: passenable, return 'entrez un email valide';
validator: (value) { }
if (value == null || value.isEmpty) { return null;
return 'TODO'; },
} cursorColor: primaryColor,
return null; keyboardType: TextInputType.emailAddress,
}, style: GoogleFonts.plusJakartaSans(
cursorColor: primaryColor, color: primaryColor),
keyboardType: TextInputType.emailAddress, decoration: InputDecoration(
style: GoogleFonts.plusJakartaSans( focusedBorder: OutlineInputBorder(
color: primaryColor), borderSide: BorderSide(
decoration: InputDecoration( width: 1, color: strokeTextField),
focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.all(
borderSide: BorderSide( Radius.circular(10))),
width: 1, color: strokeTextField), prefix: const Padding(
borderRadius: padding: EdgeInsets.only(left: 20.0)),
BorderRadius.all(Radius.circular(10))), suffix: const Padding(
contentPadding: EdgeInsets.only( padding: EdgeInsets.only(left: 20.0)),
top: 0, bottom: 0, left: defaultPadding), fillColor: bgTextField,
fillColor: bgTextField, filled: true,
filled: true, focusColor:
focusColor: Color.fromRGBO(255, 255, 255, 0.30), Color.fromRGBO(255, 255, 255, 0.30),
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderSide: BorderSide( borderSide: BorderSide(
width: 1, color: strokeTextField), width: 1, color: strokeTextField),
borderRadius: borderRadius: BorderRadius.all(
BorderRadius.all(Radius.circular(10))), Radius.circular(10))),
hintText: 'Mot de passe', hintText: 'Email',
hintStyle: GoogleFonts.plusJakartaSans( hintStyle: GoogleFonts.plusJakartaSans(
color: strokeTextField), color: strokeTextField)),
suffixIcon: Container( )),
padding: EdgeInsets.only(right: 10), Padding(
margin: EdgeInsets.all(5), padding: EdgeInsets.only(
height: 3, bottom: 16.h,
child: InkWell( left: defaultPadding,
onTap: () { right: defaultPadding),
setState(() { child: TextFormField(
if (passenable) { controller: _passwordTextField,
passenable = false; keyboardAppearance: Brightness.dark,
} else { obscureText: passenable,
passenable = true; validator: (value) {
} if (value == null || value.isEmpty) {
}); return 'entrez un mot de passe valide';
}, // Image tapped }
splashColor: Colors return null;
.white10, // Splash color over image },
child: Image( cursorColor: primaryColor,
image: passenable style: GoogleFonts.plusJakartaSans(
? AssetImage( color: primaryColor),
"assets/images/show_icon.png") decoration: InputDecoration(
: AssetImage( focusedBorder: OutlineInputBorder(
"assets/images/hide_icon.png"), borderSide: BorderSide(
height: 2, width: 1, color: strokeTextField),
), borderRadius:
)), BorderRadius.all(Radius.circular(10))),
), prefix: const Padding(
), padding: EdgeInsets.only(left: 20.0)),
), suffix: const Padding(
Padding( padding: EdgeInsets.only(left: 20.0)),
padding: EdgeInsets.only( fillColor: bgTextField,
bottom: 16.h, filled: true,
left: defaultPadding, focusColor: Color.fromRGBO(255, 255, 255, 0.30),
right: defaultPadding), enabledBorder: OutlineInputBorder(
child: TextFormField( borderSide: BorderSide(
keyboardAppearance: Brightness.dark, width: 1, color: strokeTextField),
obscureText: passenable, borderRadius:
validator: (value) { BorderRadius.all(Radius.circular(10))),
if (value == null || value.isEmpty) { hintText: 'Mot de passe',
return 'TODO'; hintStyle: GoogleFonts.plusJakartaSans(
} color: strokeTextField),
return null; suffixIcon: Container(
}, padding: EdgeInsets.only(right: 10),
cursorColor: primaryColor, margin: EdgeInsets.all(5),
keyboardType: TextInputType.emailAddress, height: 3,
style: GoogleFonts.plusJakartaSans( child: InkWell(
color: primaryColor), onTap: () {
decoration: InputDecoration( setState(() {
focusedBorder: OutlineInputBorder( if (passenable) {
borderSide: BorderSide( passenable = false;
width: 1, color: strokeTextField), } else {
borderRadius: passenable = true;
BorderRadius.all(Radius.circular(10))), }
contentPadding: EdgeInsets.only( });
top: 0, bottom: 0, left: defaultPadding), },
fillColor: bgTextField, // Image tapped
filled: true, splashColor: Colors.white10,
focusColor: Color.fromRGBO(255, 255, 255, 0.30), // Splash color over image
enabledBorder: OutlineInputBorder( child: Image(
borderSide: BorderSide( image: passenable
width: 1, color: strokeTextField), ? AssetImage(
borderRadius: "assets/images/show_icon.png")
BorderRadius.all(Radius.circular(10))), : AssetImage(
hintText: 'Confirmation du Mot de passe', "assets/images/hide_icon.png"),
hintStyle: GoogleFonts.plusJakartaSans( height: 2,
color: strokeTextField), ),
suffixIcon: Container( )),
padding: EdgeInsets.only(right: 10), ),
margin: EdgeInsets.all(5), ),
height: 3, ),
child: InkWell( Padding(
onTap: () { padding: EdgeInsets.only(
setState(() { bottom: 16.h,
if (passenable) { left: defaultPadding,
passenable = false; right: defaultPadding),
} else { child: TextFormField(
passenable = true; controller: _passwordConfirmTextField,
} keyboardAppearance: Brightness.dark,
}); obscureText: passenable,
}, // Image tapped validator: (value) {
splashColor: Colors if (value == null || value.isEmpty) {
.white10, // Splash color over image return 'entrez un mot de passe valide';
child: Image( } else if (_passwordTextField.text != value) {
image: passenable return 'les mots de passes ne sont pas identiques';
? AssetImage( }
"assets/images/show_icon.png") return null;
: AssetImage( },
"assets/images/hide_icon.png"), cursorColor: primaryColor,
height: 2, keyboardType: TextInputType.emailAddress,
), style: GoogleFonts.plusJakartaSans(
)), color: primaryColor),
), decoration: InputDecoration(
), focusedBorder: OutlineInputBorder(
), borderSide: BorderSide(
Padding( width: 1, color: strokeTextField),
padding: borderRadius:
EdgeInsets.symmetric(horizontal: defaultPadding), BorderRadius.all(Radius.circular(10))),
child: SizedBox( prefix: const Padding(
width: 600, padding: EdgeInsets.only(left: 20.0)),
child: LoginButton( suffix: const Padding(
callback: () {}, padding: EdgeInsets.only(left: 20.0)),
)), fillColor: bgTextField,
), filled: true,
Align( focusColor: Color.fromRGBO(255, 255, 255, 0.30),
child: GestureDetector( enabledBorder: OutlineInputBorder(
onTap: () { borderSide: BorderSide(
Navigator.pushNamed(context, '/login'); width: 1, color: strokeTextField),
}, borderRadius:
child: Padding( BorderRadius.all(Radius.circular(10))),
padding: EdgeInsets.only(top: 20), hintText: 'Confirmation du Mot de passe',
child: RichText( hintStyle: GoogleFonts.plusJakartaSans(
textAlign: TextAlign.center, color: strokeTextField),
text: TextSpan( suffixIcon: Container(
text: 'Tu as déjà un compte?', padding: EdgeInsets.only(right: 10),
style: GoogleFonts.plusJakartaSans( margin: EdgeInsets.all(5),
color: Colors.white, height: 3,
fontWeight: FontWeight.w400, child: InkWell(
fontSize: 15), onTap: () {
children: <TextSpan>[ setState(() {
TextSpan( if (passenable) {
text: " Connexion", passenable = false;
style: GoogleFonts.plusJakartaSans( } else {
fontSize: 15, passenable = true;
fontWeight: FontWeight.w400, }
color: primaryColor)), });
], },
), // Image tapped
), splashColor: Colors.white10,
), // Splash color over image
), child: Image(
), image: passenable
], ? AssetImage(
)), "assets/images/show_icon.png")
SizedBox(height: 50.h), : AssetImage(
ConstrainedBox( "assets/images/hide_icon.png"),
constraints: BoxConstraints(maxWidth: 600), height: 2,
child: Row( ),
mainAxisAlignment: MainAxisAlignment.spaceEvenly, )),
children: [ ),
Expanded( ),
child: Container( ),
color: Color(0xFF3D3D3D), Padding(
height: 1, padding: EdgeInsets.symmetric(
), horizontal: defaultPadding),
), child: SizedBox(
Padding( width: 600,
padding: const EdgeInsets.only( child: LoginButton(
left: defaultPadding, right: defaultPadding), callback: handleRegister,
child: Text( )),
'Ou', ),
style: GoogleFonts.plusJakartaSans( Align(
color: Colors.white, fontWeight: FontWeight.bold), child: GestureDetector(
), onTap: () {
), Navigator.pushNamed(context, '/login');
Expanded( },
child: Container( child: Padding(
height: 1, padding: EdgeInsets.only(top: 20),
color: Color(0xFF3D3D3D), child: RichText(
)), textAlign: TextAlign.center,
], text: TextSpan(
), text: 'Tu as déjà un compte?',
), style: GoogleFonts.plusJakartaSans(
SizedBox(height: 47.h), color: Colors.white,
ConstrainedBox( fontWeight: FontWeight.w400,
constraints: BoxConstraints(maxWidth: 540), fontSize: 15),
child: SizedBox( children: <TextSpan>[
width: 300.sp, TextSpan(
height: 50, text: " Connexion",
child: SignInButton( style: GoogleFonts.plusJakartaSans(
Buttons.Google, fontSize: 15,
text: "Login with Google", fontWeight: FontWeight.w400,
onPressed: () {}, color: primaryColor)),
shape: RoundedRectangleBorder( ],
borderRadius: BorderRadius.all(Radius.circular(20))), ),
), ),
), ),
), ),
], ),
), ],
)), )),
IgnorePointer( SizedBox(height: 50.h),
child: Container( ConstrainedBox(
height: 240.h, constraints: BoxConstraints(maxWidth: 600),
decoration: BoxDecoration( child: Row(
gradient: LinearGradient(begin: Alignment.topRight, stops: [ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
0, children: [
1 Expanded(
], colors: [ child: Container(
bgColor.withOpacity(1), color: Color(0xFF3D3D3D),
bgColor.withOpacity(0) height: 1,
])), ),
), ),
), Padding(
Align( padding: const EdgeInsets.only(
alignment: Alignment.topCenter, left: defaultPadding, right: defaultPadding),
child: ConstrainedBox( child: Text(
constraints: BoxConstraints(maxWidth: 800), 'Ou',
child: Padding( style: GoogleFonts.plusJakartaSans(
padding: EdgeInsets.only( color: Colors.white,
top: 45.h, left: defaultPadding, right: defaultPadding), fontWeight: FontWeight.bold),
child: ClipRRect( ),
borderRadius: BorderRadius.circular(10.0), ),
child: LinearProgressIndicator( Expanded(
minHeight: 5, child: Container(
value: 0.5, height: 1,
backgroundColor: grayColor, color: Color(0xFF3D3D3D),
color: primaryColor, )),
), ],
), ),
), ),
), SizedBox(height: 47.h),
), ConstrainedBox(
], constraints: BoxConstraints(maxWidth: 540),
), child: SizedBox(
); width: 300.sp,
} height: 50,
} child: SignInButton(
Buttons.Google,
text: "Login with Google",
onPressed: () {},
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.all(Radius.circular(20))),
),
),
),
],
),
)),
IgnorePointer(
child: Container(
height: 240.h,
decoration: BoxDecoration(
gradient: LinearGradient(begin: Alignment.topRight, stops: [
0,
1
], colors: [
bgColor.withOpacity(1),
bgColor.withOpacity(0)
])),
),
),
Align(
alignment: Alignment.topCenter,
child: ConstrainedBox(
constraints: BoxConstraints(maxWidth: 800),
child: Padding(
padding: EdgeInsets.only(
top: 45.h, left: defaultPadding, right: defaultPadding),
child: ClipRRect(
borderRadius: BorderRadius.circular(10.0),
child: LinearProgressIndicator(
minHeight: 5,
value: 0.5,
backgroundColor: grayColor,
color: primaryColor,
),
),
),
),
),
],
),
),
);
}
}

@ -1,169 +1,169 @@
import 'dart:async'; import 'dart:async';
import 'dart:ui'; import 'dart:ui';
import 'package:flutter/Material.dart'; import 'package:flutter/Material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:justmusic/model/Music.dart'; import 'package:justmusic/model/Music.dart';
import '../components/music_list_component.dart'; import '../components/music_list_component.dart';
import '../values/constants.dart'; import '../values/constants.dart';
import '../main.dart'; import '../main.dart';
class SearchSongScreen extends StatefulWidget { class SearchSongScreen extends StatefulWidget {
const SearchSongScreen({Key? key}) : super(key: key); const SearchSongScreen({Key? key}) : super(key: key);
@override @override
State<SearchSongScreen> createState() => _SearchSongScreenState(); State<SearchSongScreen> createState() => _SearchSongScreenState();
} }
class _SearchSongScreenState extends State<SearchSongScreen> { class _SearchSongScreenState extends State<SearchSongScreen> {
final ScrollController _scrollController = ScrollController(); final ScrollController _scrollController = ScrollController();
final TextEditingController _textEditingController = TextEditingController(); final TextEditingController _textEditingController = TextEditingController();
Future<void> resetFullScreen() async { Future<void> resetFullScreen() async {
await SystemChannels.platform.invokeMethod<void>( await SystemChannels.platform.invokeMethod<void>(
'SystemChrome.restoreSystemUIOverlays', 'SystemChrome.restoreSystemUIOverlays',
); );
} }
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_scrollController.addListener(_scrollListener); _scrollController.addListener(_scrollListener);
} }
Future<void> _scrollListener() async { Future<void> _scrollListener() async {
if (_scrollController.position.pixels == if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) { _scrollController.position.maxScrollExtent) {
filteredData.addAll(await MyApp.musicViewModel.getMusicsWithName( filteredData.addAll(await MyApp.musicViewModel.getMusicsWithName(
_textEditingController.text, _textEditingController.text,
limit: 10, limit: 10,
offset: filteredData.length)); offset: filteredData.length));
setState(() { setState(() {
filteredData = filteredData; filteredData = filteredData;
}); });
} }
if (_scrollController.offset >= if (_scrollController.offset >=
_scrollController.position.maxScrollExtent && _scrollController.position.maxScrollExtent &&
!_scrollController.position.outOfRange) { !_scrollController.position.outOfRange) {
setState(() { setState(() {
//you can do anything here //you can do anything here
}); });
} }
if (_scrollController.offset <= if (_scrollController.offset <=
_scrollController.position.minScrollExtent && _scrollController.position.minScrollExtent &&
!_scrollController.position.outOfRange) { !_scrollController.position.outOfRange) {
setState(() { setState(() {
Timer(Duration(milliseconds: 1), () => _scrollController.jumpTo(0)); Timer(Duration(milliseconds: 1), () => _scrollController.jumpTo(0));
}); });
} }
} }
List<Music> filteredData = []; List<Music> filteredData = [];
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
double screenHeight = MediaQuery.of(context).size.height; double screenHeight = MediaQuery.of(context).size.height;
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
FocusScopeNode currentFocus = FocusScope.of(context); FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus) { if (!currentFocus.hasPrimaryFocus) {
currentFocus.unfocus(); currentFocus.unfocus();
resetFullScreen(); resetFullScreen();
} }
}, },
child: BackdropFilter( child: BackdropFilter(
filter: ImageFilter.blur( filter: ImageFilter.blur(
sigmaX: 60.0, sigmaX: 60.0,
sigmaY: 60.0, sigmaY: 60.0,
), ),
child: Container( child: Container(
color: bgAppBar.withOpacity(0.5), color: bgAppBar.withOpacity(0.5),
height: screenHeight - 50, height: screenHeight - 50,
padding: const EdgeInsets.only(top: 10), padding: const EdgeInsets.only(top: 10),
child: Column( child: Column(
children: [ children: [
Align( Align(
child: Container( child: Container(
width: 60, width: 60,
height: 5, height: 5,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Color(0xFF3A3A3A).withOpacity(0.6), color: Color(0xFF3A3A3A).withOpacity(0.6),
borderRadius: BorderRadius.circular(20))), borderRadius: BorderRadius.circular(20))),
), ),
const SizedBox( const SizedBox(
height: 10, height: 10,
), ),
Padding( Padding(
padding: padding:
const EdgeInsets.only(bottom: 10, left: 20, right: 20), const EdgeInsets.only(bottom: 10, left: 20, right: 20),
child: SizedBox( child: SizedBox(
height: 40, height: 40,
child: TextField( child: TextField(
controller: _textEditingController, controller: _textEditingController,
keyboardAppearance: Brightness.dark, keyboardAppearance: Brightness.dark,
onEditingComplete: resetFullScreen, onEditingComplete: resetFullScreen,
onChanged: (value) async { onChanged: (value) async {
if (_textEditingController.text.isEmpty) { if (_textEditingController.text.isEmpty) {
} else if (value == " ") { } else if (value == " ") {
print("popular"); print("popular");
} else { } else {
filteredData = await MyApp.musicViewModel filteredData = await MyApp.musicViewModel
.getMusicsWithName(value); .getMusicsWithName(value);
setState(() { setState(() {
filteredData = filteredData; filteredData = filteredData;
}); });
} }
}, },
cursorColor: Colors.white, cursorColor: Colors.white,
keyboardType: TextInputType.text, keyboardType: TextInputType.text,
style: GoogleFonts.plusJakartaSans(color: grayText), style: GoogleFonts.plusJakartaSans(color: grayText),
decoration: InputDecoration( decoration: InputDecoration(
prefixIcon: const Icon( prefixIcon: const Icon(
Icons.search, Icons.search,
color: grayColor, color: grayColor,
), ),
focusedBorder: const OutlineInputBorder( focusedBorder: const OutlineInputBorder(
borderSide: borderSide:
BorderSide(width: 1, color: grayColor), BorderSide(width: 1, color: grayColor),
borderRadius: borderRadius:
BorderRadius.all(Radius.circular(10))), BorderRadius.all(Radius.circular(10))),
contentPadding: const EdgeInsets.only( contentPadding: const EdgeInsets.only(
top: 0, top: 0,
bottom: 0, bottom: 0,
left: defaultPadding, left: defaultPadding,
right: defaultPadding), right: defaultPadding),
fillColor: searchBarColor, fillColor: searchBarColor,
filled: true, filled: true,
focusColor: grayText, focusColor: grayText,
enabledBorder: const OutlineInputBorder( enabledBorder: const OutlineInputBorder(
borderSide: borderSide:
BorderSide(width: 1, color: grayColor), BorderSide(width: 1, color: grayColor),
borderRadius: borderRadius:
BorderRadius.all(Radius.circular(10))), BorderRadius.all(Radius.circular(10))),
hintText: 'Chercher un son', hintText: 'Chercher un son',
hintStyle: hintStyle:
GoogleFonts.plusJakartaSans(color: grayColor)), GoogleFonts.plusJakartaSans(color: grayColor)),
), ),
), ),
), ),
Flexible( Flexible(
child: ScrollConfiguration( child: ScrollConfiguration(
behavior: ScrollBehavior().copyWith(scrollbars: true), behavior: ScrollBehavior().copyWith(scrollbars: true),
child: ListView.builder( child: ListView.builder(
controller: _scrollController, controller: _scrollController,
itemCount: filteredData.length, itemCount: filteredData.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
return Padding( return Padding(
padding: const EdgeInsets.symmetric(horizontal: 20), padding: const EdgeInsets.symmetric(horizontal: 20),
child: MusicListComponent(music: filteredData[index]), child: MusicListComponent(music: filteredData[index]),
); );
}), }),
)) ))
], ],
), ),
), ),
)); ));
} }
} }

@ -1,98 +1,98 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:justmusic/values/constants.dart'; import 'package:justmusic/values/constants.dart';
import '../components/join_button.dart'; import '../components/join_button.dart';
class WellcomeScreen extends StatelessWidget { class WellcomeScreen extends StatelessWidget {
const WellcomeScreen({Key? key}) : super(key: key); const WellcomeScreen({Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
body: Container( body: Container(
padding: EdgeInsets.all(defaultPadding), padding: EdgeInsets.all(defaultPadding),
width: double.infinity, width: double.infinity,
height: double.infinity, height: double.infinity,
decoration: const BoxDecoration( decoration: const BoxDecoration(
image: DecorationImage( image: DecorationImage(
image: AssetImage("assets/images/wellcome_background.png"), image: AssetImage("assets/images/wellcome_background.png"),
fit: BoxFit.cover, fit: BoxFit.cover,
), ),
), ),
child: Align( child: Align(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Expanded( Expanded(
flex: 10, flex: 10,
child: Padding( child: Padding(
padding: EdgeInsets.only(bottom: 100), padding: EdgeInsets.only(bottom: 100),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"Bienvenue sur,", "Bienvenue sur,",
style: GoogleFonts.plusJakartaSans( style: GoogleFonts.plusJakartaSans(
color: Colors.white, color: Colors.white,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontSize: 34), fontSize: 34),
), ),
Image( Image(
image: AssetImage("assets/images/logo.png"), image: AssetImage("assets/images/logo.png"),
width: 230, width: 230,
), ),
SizedBox( SizedBox(
height: 25, height: 25,
), ),
ConstrainedBox( ConstrainedBox(
constraints: BoxConstraints(maxWidth: 520), constraints: BoxConstraints(maxWidth: 520),
child: Text( child: Text(
"Explore les nouvelles découvertes musicales de tes amis, et partage leur ton mood.", "Explore les nouvelles découvertes musicales de tes amis, et partage leur ton mood.",
style: GoogleFonts.plusJakartaSans( style: GoogleFonts.plusJakartaSans(
color: Colors.white, color: Colors.white,
fontWeight: FontWeight.w200, fontWeight: FontWeight.w200,
fontSize: 15), fontSize: 15),
), ),
), ),
], ],
), ),
), ),
), ),
Expanded( Expanded(
flex: 3, flex: 3,
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
JoinButton(), JoinButton(),
SizedBox( SizedBox(
height: defaultPadding, height: defaultPadding,
), ),
GestureDetector( GestureDetector(
onTap: () { onTap: () {
Navigator.pushNamed(context, '/login'); Navigator.pushNamed(context, '/login');
}, },
child: Padding( child: Padding(
padding: const EdgeInsets.all(3.0), padding: const EdgeInsets.all(3.0),
child: Text( child: Text(
"Tu as déja un compte? Connexion", "Tu as déja un compte? Connexion",
style: GoogleFonts.plusJakartaSans( style: GoogleFonts.plusJakartaSans(
color: Colors.white, color: Colors.white,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
fontSize: 15), fontSize: 15),
), ),
), ),
), ),
], ],
), ),
), ),
], ],
), ),
) /* add child content here */, ) /* add child content here */,
), ),
); );
} }
} }

@ -1,59 +1,60 @@
import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_auth/firebase_auth.dart';
import '../main.dart'; import '../main.dart';
class AuthService { class AuthService {
register(String pseudo, String email, String password) async { register(String pseudo, String email, String password) async {
try { try {
final data = await FirebaseAuth.instance.createUserWithEmailAndPassword( final data = await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: email, email: email,
password: password, password: password,
); );
final user = <String, dynamic>{ final user = <String, dynamic>{
"mail": email, "mail": email,
"pseudo": pseudo, "pseudo": pseudo,
"phone_number": "", "phone_number": "",
"picture": "picture":
"https://media.licdn.com/dms/image/D4E03AQHvc_b89ogFtQ/profile-displayphoto-shrink_400_400/0/1665060931103?e=1695859200&v=beta&t=wVLbxqeokYiPJ13nJ3SMq97iZvcm3ra0ufWFZCSzhjg", "https://media.licdn.com/dms/image/D4E03AQHvc_b89ogFtQ/profile-displayphoto-shrink_400_400/0/1665060931103?e=1695859200&v=beta&t=wVLbxqeokYiPJ13nJ3SMq97iZvcm3ra0ufWFZCSzhjg",
"friends": [] "friends": []
}; };
MyApp.db MyApp.db
.collection("users") .collection("users")
.doc(data.user?.uid) .doc(data.user?.uid)
.set(user) .set(user)
.then((value) => print("User Added")) .then((value) => print("User Added"))
.catchError((error) => print("Failed to add user: $error")); .catchError((error) => print("Failed to add user: $error"));
} on FirebaseAuthException catch (e) { } on FirebaseAuthException catch (e) {
if (e.code == 'weak-password') { if (e.code == 'weak-password') {
throw ('The password provided is too weak.'); throw ('Mot de passe trop court');
} else if (e.code == 'email-already-in-use') { } else if (e.code == 'email-already-in-use') {
throw ('The account already exists for that email.'); throw ('Mail déjà utilisé');
} } else if (e.code == 'invalid-email') {
} catch (e) { throw ('Mauvais format de mail');
throw (e); }
} rethrow;
} }
}
login(String email, String password) async {
try { login(String email, String password) async {
await FirebaseAuth.instance try {
.signInWithEmailAndPassword(email: email, password: password); await FirebaseAuth.instance
} on FirebaseAuthException catch (e) { .signInWithEmailAndPassword(email: email, password: password);
if(e.code == 'user-not-found') { } on FirebaseAuthException catch (e) {
throw('Mail incorrect'); if (e.code == 'user-not-found') {
} else if(e.code == 'wrong-password') { throw ('Mail incorrect');
throw('Mot de passe incorrect'); } else if (e.code == 'wrong-password') {
} else if(e.code == 'invalid-email') { throw ('Mot de passe incorrect');
throw('Format de mail incorrect'); } else if (e.code == 'invalid-email') {
} else if(e.code == 'too-many-requests') { throw ('Format de mail incorrect');
throw('L\'accès à ce compte a été temporairement désactivé en raison de nombreuses tentatives de connexion infructueuses. Réessayer plus tard.'); } else if (e.code == 'too-many-requests') {
} throw ('L\'accès à ce compte a été temporairement désactivé en raison de nombreuses tentatives de connexion infructueuses. Réessayer plus tard.');
rethrow; }
} rethrow;
} }
}
void signOut() async {
await FirebaseAuth.instance.signOut(); void signOut() async {
} await FirebaseAuth.instance.signOut();
} }
}

@ -1,15 +1,15 @@
import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:cloud_firestore/cloud_firestore.dart';
import '../model/User.dart'; import '../model/User.dart';
import '../main.dart'; import '../main.dart';
class UserService { class UserService {
acceptFriend(User user, String idFriend) { acceptFriend(User user, String idFriend) {
MyApp.db.collection("users").doc(user.id).update({ MyApp.db.collection("users").doc(user.id).update({
"friends": FieldValue.arrayUnion([idFriend]) "friends": FieldValue.arrayUnion([idFriend])
}); });
MyApp.db.collection("users").doc(idFriend).update({ MyApp.db.collection("users").doc(idFriend).update({
"friends": FieldValue.arrayUnion([user.id]) "friends": FieldValue.arrayUnion([user.id])
}); });
} }
} }

@ -1,203 +1,203 @@
import 'dart:convert'; import 'dart:convert';
import 'package:justmusic/view_model/TokenSpotify.dart'; import 'package:justmusic/view_model/TokenSpotify.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import '../model/Artist.dart'; import '../model/Artist.dart';
import '../model/Music.dart'; import '../model/Music.dart';
class MusicViewModel { class MusicViewModel {
final String API_URL = "https://api.spotify.com/v1"; final String API_URL = "https://api.spotify.com/v1";
late TokenSpotify _token; late TokenSpotify _token;
MusicViewModel() { MusicViewModel() {
_token = new TokenSpotify(); _token = new TokenSpotify();
} }
// Methods // Methods
Future<Music> getMusic(String id) async { Future<Music> getMusic(String id) async {
var accessToken = await _token.getAccessToken(); var accessToken = await _token.getAccessToken();
var response = await http.get(Uri.parse('$API_URL/tracks/$id'), headers: { var response = await http.get(Uri.parse('$API_URL/tracks/$id'), headers: {
'Authorization': 'Bearer $accessToken', 'Authorization': 'Bearer $accessToken',
}); });
if (response.statusCode == 200) { if (response.statusCode == 200) {
final responseData = jsonDecode(response.body); final responseData = jsonDecode(response.body);
List<Artist> artists = List<Artist> artists =
List<Artist>.from(responseData['artists'].map((artist) { List<Artist>.from(responseData['artists'].map((artist) {
return Artist(artist['id'], artist['name'], ''); return Artist(artist['id'], artist['name'], '');
})); }));
return Music( return Music(
responseData['id'], responseData['id'],
responseData['name'], responseData['name'],
responseData['album']['images'][0]['url'], responseData['album']['images'][0]['url'],
responseData['preview_url'], responseData['preview_url'],
DateTime.parse(responseData['album']['release_date']), DateTime.parse(responseData['album']['release_date']),
responseData['duration_ms'] / 1000, responseData['duration_ms'] / 1000,
responseData['explicit'], responseData['explicit'],
artists); artists);
} else { } else {
throw Exception( throw Exception(
'Error retrieving music information : ${response.statusCode} ${response.reasonPhrase}'); 'Error retrieving music information : ${response.statusCode} ${response.reasonPhrase}');
} }
} }
List<Music> _getMusicsFromResponse(Map<String, dynamic> responseData) { List<Music> _getMusicsFromResponse(Map<String, dynamic> responseData) {
List<Music> musics = []; List<Music> musics = [];
List<dynamic> tracks = responseData['tracks']['items']; List<dynamic> tracks = responseData['tracks']['items'];
for (var track in tracks) { for (var track in tracks) {
List<Artist> artists = List<Artist>.from(track['artists'].map((artist) { List<Artist> artists = List<Artist>.from(track['artists'].map((artist) {
return Artist(artist['id'], artist['name'], ''); return Artist(artist['id'], artist['name'], '');
})); }));
musics.add(Music( musics.add(Music(
track['id'], track['id'],
track['name'], track['name'],
track['album']['images'][0]['url'], track['album']['images'][0]['url'],
track['preview_url'], track['preview_url'],
DateTime.now(), DateTime.now(),
track['duration_ms'] / 1000, track['duration_ms'] / 1000,
track['explicit'], track['explicit'],
artists)); artists));
} }
return musics; return musics;
} }
Future<List<Music>> getMusicsWithName(String name, Future<List<Music>> getMusicsWithName(String name,
{int limit = 20, int offset = 0, String market = "FR"}) async { {int limit = 20, int offset = 0, String market = "FR"}) async {
var accessToken = await _token.getAccessToken(); var accessToken = await _token.getAccessToken();
var response = await http.get( var response = await http.get(
Uri.parse( Uri.parse(
'$API_URL/search?q=track%3A$name&type=track&market=fr&limit=$limit&offset=$offset'), '$API_URL/search?q=track%3A$name&type=track&market=fr&limit=$limit&offset=$offset'),
headers: { headers: {
'Authorization': 'Bearer $accessToken', 'Authorization': 'Bearer $accessToken',
}); });
if (response.statusCode == 200) { if (response.statusCode == 200) {
Map<String, dynamic> responseData = jsonDecode(response.body); Map<String, dynamic> responseData = jsonDecode(response.body);
return _getMusicsFromResponse(responseData); return _getMusicsFromResponse(responseData);
} else { } else {
throw Exception( throw Exception(
'Error while retrieving music : ${response.statusCode} ${response.reasonPhrase}'); 'Error while retrieving music : ${response.statusCode} ${response.reasonPhrase}');
} }
} }
Future<List<Music>> getMusicsWithArtistName(String name, Future<List<Music>> getMusicsWithArtistName(String name,
{int limit = 20, int offset = 0, String market = "FR"}) async { {int limit = 20, int offset = 0, String market = "FR"}) async {
var accessToken = await _token.getAccessToken(); var accessToken = await _token.getAccessToken();
var response = await http.get( var response = await http.get(
Uri.parse( Uri.parse(
'$API_URL/search?q=artist%3A$name&type=track&market=fr&limit=$limit&offset=$offset'), '$API_URL/search?q=artist%3A$name&type=track&market=fr&limit=$limit&offset=$offset'),
headers: { headers: {
'Authorization': 'Bearer $accessToken', 'Authorization': 'Bearer $accessToken',
}); });
if (response.statusCode == 200) { if (response.statusCode == 200) {
Map<String, dynamic> responseData = jsonDecode(response.body); Map<String, dynamic> responseData = jsonDecode(response.body);
return _getMusicsFromResponse(responseData); return _getMusicsFromResponse(responseData);
} else { } else {
throw Exception( throw Exception(
'Error while retrieving music : ${response.statusCode} ${response.reasonPhrase}'); 'Error while retrieving music : ${response.statusCode} ${response.reasonPhrase}');
} }
} }
Future<Artist> getArtistWithName(String name, {String market = "FR"}) async { Future<Artist> getArtistWithName(String name, {String market = "FR"}) async {
var accessToken = await _token.getAccessToken(); var accessToken = await _token.getAccessToken();
var response = await http.get( var response = await http.get(
Uri.parse( Uri.parse(
'$API_URL/search?q=artist%3A$name&type=artist&market=$market'), '$API_URL/search?q=artist%3A$name&type=artist&market=$market'),
headers: { headers: {
'Authorization': 'Bearer $accessToken', 'Authorization': 'Bearer $accessToken',
}); });
if (response.statusCode == 200) { if (response.statusCode == 200) {
final responseData = jsonDecode(response.body); final responseData = jsonDecode(response.body);
List<Artist> artists = List<Artist> artists =
List<Artist>.from(responseData['artists']['items'].map((artist) { List<Artist>.from(responseData['artists']['items'].map((artist) {
String image = ''; String image = '';
if (!artist['images'].isEmpty) { if (!artist['images'].isEmpty) {
image = artist['images'][0]['url']; image = artist['images'][0]['url'];
} }
return Artist(artist['id'], artist['name'], image); return Artist(artist['id'], artist['name'], image);
})); }));
for (Artist a in artists) { for (Artist a in artists) {
if (a.name?.toLowerCase() == name.toLowerCase()) { if (a.name?.toLowerCase() == name.toLowerCase()) {
return a; return a;
} }
} }
throw Exception('Artist not found : ${name}'); throw Exception('Artist not found : ${name}');
} else { } else {
throw Exception( throw Exception(
'Error retrieving artist information : ${response.statusCode} ${response.reasonPhrase}'); 'Error retrieving artist information : ${response.statusCode} ${response.reasonPhrase}');
} }
} }
Future<List<Artist>> getArtistsWithName(String name, Future<List<Artist>> getArtistsWithName(String name,
{int limit = 20, int offset = 0, String market = "FR"}) async { {int limit = 20, int offset = 0, String market = "FR"}) async {
var accessToken = await _token.getAccessToken(); var accessToken = await _token.getAccessToken();
var response = await http.get( var response = await http.get(
Uri.parse( Uri.parse(
'$API_URL/search?q=artist%3A$name&type=artist&market=$market&limit=$limit&offset=$offset'), '$API_URL/search?q=artist%3A$name&type=artist&market=$market&limit=$limit&offset=$offset'),
headers: { headers: {
'Authorization': 'Bearer $accessToken', 'Authorization': 'Bearer $accessToken',
}); });
if (response.statusCode == 200) { if (response.statusCode == 200) {
final responseData = jsonDecode(response.body); final responseData = jsonDecode(response.body);
List<Artist> artists = List<Artist> artists =
List<Artist>.from(responseData['artists']['items'].map((artist) { List<Artist>.from(responseData['artists']['items'].map((artist) {
String image = ''; String image = '';
if (!artist['images'].isEmpty) { if (!artist['images'].isEmpty) {
image = artist['images'][0]['url']; image = artist['images'][0]['url'];
} }
return Artist(artist['id'], artist['name'], image); return Artist(artist['id'], artist['name'], image);
})); }));
return artists; return artists;
} else { } else {
throw Exception( throw Exception(
'Error while retrieving artist : ${response.statusCode} ${response.reasonPhrase}'); 'Error while retrieving artist : ${response.statusCode} ${response.reasonPhrase}');
} }
} }
Future<List<Music>> getTopMusicsWithArtistId(String id, Future<List<Music>> getTopMusicsWithArtistId(String id,
{String market = "FR"}) async { {String market = "FR"}) async {
var accessToken = await _token.getAccessToken(); var accessToken = await _token.getAccessToken();
var response = await http.get( var response = await http.get(
Uri.parse('$API_URL/artists/$id/top-tracks?market=$market'), Uri.parse('$API_URL/artists/$id/top-tracks?market=$market'),
headers: { headers: {
'Authorization': 'Bearer $accessToken', 'Authorization': 'Bearer $accessToken',
}); });
if (response.statusCode == 200) { if (response.statusCode == 200) {
Map<String, dynamic> responseData = jsonDecode(response.body); Map<String, dynamic> responseData = jsonDecode(response.body);
List<Music> musics = []; List<Music> musics = [];
List<dynamic> tracks = responseData['tracks']; List<dynamic> tracks = responseData['tracks'];
for (var track in tracks) { for (var track in tracks) {
List<Artist> artists = List<Artist>.from(track['artists'].map((artist) { List<Artist> artists = List<Artist>.from(track['artists'].map((artist) {
return Artist(artist['id'], artist['name'], ''); return Artist(artist['id'], artist['name'], '');
})); }));
musics.add(Music( musics.add(Music(
track['id'], track['id'],
track['name'], track['name'],
track['album']['images'][0]['url'], track['album']['images'][0]['url'],
track['preview_url'], track['preview_url'],
DateTime.now(), DateTime.now(),
track['duration_ms'] / 1000, track['duration_ms'] / 1000,
track['explicit'], track['explicit'],
artists)); artists));
} }
return musics; return musics;
} else { } else {
throw Exception( throw Exception(
'Error while retrieving music : ${response.statusCode} ${response.reasonPhrase}'); 'Error while retrieving music : ${response.statusCode} ${response.reasonPhrase}');
} }
} }
} }

@ -1,53 +1,57 @@
import 'package:firebase_auth/firebase_auth.dart' as firebase_auth; import 'package:firebase_auth/firebase_auth.dart' as firebase_auth;
import 'package:justmusic/service/AuthService.dart'; import 'package:justmusic/service/AuthService.dart';
import '../model/User.dart'; import '../model/User.dart';
import '../model/mapper/UserMapper.dart'; import '../model/mapper/UserMapper.dart';
import '../main.dart'; import '../main.dart';
class UserViewModel { class UserViewModel {
late User _userCurrent; late User _userCurrent;
final AuthService _authService = AuthService(); final AuthService _authService = AuthService();
User get userCurrent => _userCurrent; User get userCurrent => _userCurrent;
set userCurrent(User value) { set userCurrent(User value) {
_userCurrent = value; _userCurrent = value;
} // Constructor } // Constructor
UserViewModel(); UserViewModel();
// Methods // Methods
Future<User?> getUser(String id) async { Future<User?> getUser(String id) async {
final user = await MyApp.db.collection("users").doc(id).get(); final user = await MyApp.db.collection("users").doc(id).get();
return UserMapper.toModel(user, null); return UserMapper.toModel(user, null);
} }
login(String pseudo, String password) async { login(String pseudo, String password) async {
try { try {
await _authService.login(pseudo, password); await _authService.login(pseudo, password);
final user = await MyApp.db final user = await MyApp.db
.collection("users") .collection("users")
.doc(firebase_auth.FirebaseAuth.instance.currentUser?.uid) .doc(firebase_auth.FirebaseAuth.instance.currentUser?.uid)
.get(); .get();
User data = UserMapper.toModel(user, null); User data = UserMapper.toModel(user, null);
_userCurrent = data; _userCurrent = data;
} catch (e) { } catch (e) {
rethrow; rethrow;
} }
} }
register(String pseudo, String password, String email) async { register(String pseudo, String password, String email) async {
_authService.register(pseudo, email, password); try {
final user = await MyApp.db await _authService.register(pseudo, email, password);
.collection("users") final user = await MyApp.db
.doc(firebase_auth.FirebaseAuth.instance.currentUser?.uid) .collection("users")
.get(); .doc(firebase_auth.FirebaseAuth.instance.currentUser?.uid)
User? data = UserMapper.toModel(user, null); .get();
_userCurrent = data; User data = UserMapper.toModel(user, null);
} _userCurrent = data;
} catch (e) {
logout() { rethrow;
_authService.signOut(); }
} }
}
logout() {
_authService.signOut();
}
}

File diff suppressed because it is too large Load Diff

@ -1,111 +1,111 @@
name: justmusic name: justmusic
description: A new Flutter project. description: A new Flutter project.
# The following line prevents the package from being accidentally published to # The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages. # pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# The following defines the version and build number for your application. # The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43 # A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +. # followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter # Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively. # build by specifying --build-name and --build-number, respectively.
# In Android, build-name is used as versionName while build-number used as versionCode. # In Android, build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning # Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. # In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
# Read more about iOS versioning at # Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts # In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix. # of the product and file versions while build-number is used as the build suffix.
version: 1.0.0+1 version: 1.0.0+1
environment: environment:
sdk: '>=2.18.2 <3.0.0' sdk: '>=2.18.2 <3.0.0'
# Dependencies specify other packages that your package needs in order to work. # Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions # To automatically upgrade your package dependencies to the latest versions
# consider running `flutter pub upgrade --major-versions`. Alternatively, # consider running `flutter pub upgrade --major-versions`. Alternatively,
# dependencies can be manually updated by changing the version numbers below to # dependencies can be manually updated by changing the version numbers below to
# the latest version available on pub.dev. To see which dependencies have newer # the latest version available on pub.dev. To see which dependencies have newer
# versions available, run `flutter pub outdated`. # versions available, run `flutter pub outdated`.
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
http: ^0.13.5 http: ^0.13.5
# The following adds the Cupertino Icons font to your application. # The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons. # Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2 cupertino_icons: ^1.0.2
google_fonts: ^4.0.4 google_fonts: ^4.0.4
gradiantbutton: ^0.0.1 gradiantbutton: ^0.0.1
smooth_corner: ^1.1.0 smooth_corner: ^1.1.0
flutter_signin_button: ^2.0.0 flutter_signin_button: ^2.0.0
flutter_screenutil: ^5.7.0 flutter_screenutil: ^5.7.0
auto_size_text: ^3.0.0 auto_size_text: ^3.0.0
gradient_borders: ^1.0.0 gradient_borders: ^1.0.0
text_scroll: ^0.2.0 text_scroll: ^0.2.0
circular_reveal_animation: ^2.0.1 circular_reveal_animation: ^2.0.1
zoom_tap_animation: ^1.1.0 zoom_tap_animation: ^1.1.0
custom_draggable_widget: ^0.0.2 custom_draggable_widget: ^0.0.2
modal_bottom_sheet: ^2.1.2 modal_bottom_sheet: ^2.1.2
flutter_animated_play_button: ^0.3.0 flutter_animated_play_button: ^0.3.0
audioplayers: ^4.1.0 audioplayers: ^4.1.0
ionicons: ^0.2.2 ionicons: ^0.2.2
top_snackbar_flutter: ^3.1.0 top_snackbar_flutter: ^3.1.0
firebase_core: ^2.15.0 firebase_core: ^2.15.0
firebase_auth: ^4.7.2 firebase_auth: ^4.7.2
cloud_firestore: ^4.8.4 cloud_firestore: ^4.8.4
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
# The "flutter_lints" package below contains a set of recommended lints to # The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is # encourage good coding practices. The lint set provided by the package is
# activated in the `analysis_options.yaml` file located at the root of your # activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint # package. See that file for information about deactivating specific lint
# rules and activating additional ones. # rules and activating additional ones.
flutter_lints: ^2.0.0 flutter_lints: ^2.0.0
# For information on the generic Dart part of this file, see the # For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec # following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter packages. # The following section is specific to Flutter packages.
flutter: flutter:
# The following line ensures that the Material Icons font is # The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in # included with your application, so that you can use the icons in
# the material Icons class. # the material Icons class.
uses-material-design: true uses-material-design: true
# To add assets to your application, add an assets section, like this: # To add assets to your application, add an assets section, like this:
assets: assets:
- assets/images/ - assets/images/
- assets/ - assets/
# An image asset can refer to one or more resolution-specific "variants", see # An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware # https://flutter.dev/assets-and-images/#resolution-aware
# For details regarding adding assets from package dependencies, see # For details regarding adding assets from package dependencies, see
# https://flutter.dev/assets-and-images/#from-packages # https://flutter.dev/assets-and-images/#from-packages
# To add custom fonts to your application, add a fonts section here, # To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a # in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a # "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For # list giving the asset and other descriptors for the font. For
# example: # example:
# fonts: # fonts:
# - family: Schyler # - family: Schyler
# fonts: # fonts:
# - asset: fonts/Schyler-Regular.ttf # - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf # - asset: fonts/Schyler-Italic.ttf
# style: italic # style: italic
# - family: Trajan Pro # - family: Trajan Pro
# fonts: # fonts:
# - asset: fonts/TrajanPro.ttf # - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf # - asset: fonts/TrajanPro_Bold.ttf
# weight: 700 # weight: 700
# #
# For details regarding fonts from package dependencies, # For details regarding fonts from package dependencies,
# see https://flutter.dev/custom-fonts/#from-packages # see https://flutter.dev/custom-fonts/#from-packages

@ -1,60 +1,60 @@
import 'package:justmusic/model/Artist.dart'; import 'package:justmusic/model/Artist.dart';
import 'package:justmusic/model/Music.dart'; import 'package:justmusic/model/Music.dart';
import 'package:justmusic/view_model/MusicViewModel.dart'; import 'package:justmusic/view_model/MusicViewModel.dart';
Future<void> main() async { Future<void> main() async {
MusicViewModel musicVM = new MusicViewModel(); MusicViewModel musicVM = new MusicViewModel();
Music m = await musicVM.getMusic('295SxdR1DqunCNwd0U767w'); Music m = await musicVM.getMusic('295SxdR1DqunCNwd0U767w');
print("id : ${m.id.toString()}, cover : ${m.cover}, title : ${m.title}"); print("id : ${m.id.toString()}, cover : ${m.cover}, title : ${m.title}");
print("date : ${m.date.toString()}, preview : ${m.previewUrl}, duration : ${m.duration}, explicit : ${m.explicit}"); print("date : ${m.date.toString()}, preview : ${m.previewUrl}, duration : ${m.duration}, explicit : ${m.explicit}");
for (Artist a in m.artists) { for (Artist a in m.artists) {
print("id : ${a.id}, name : ${a.name}"); print("id : ${a.id}, name : ${a.name}");
} }
print('\nMusics :'); print('\nMusics :');
List<Music> musics = await musicVM.getMusicsWithName('Shavkat'); List<Music> musics = await musicVM.getMusicsWithName('Shavkat');
for (Music m in musics) { for (Music m in musics) {
print("id : ${m.id.toString()}, cover : ${m.cover}, title : ${m.title}"); print("id : ${m.id.toString()}, cover : ${m.cover}, title : ${m.title}");
print("date : ${m.date.toString()}, preview : ${m.previewUrl}, duration : ${m.duration}, explicit : ${m.explicit}"); print("date : ${m.date.toString()}, preview : ${m.previewUrl}, duration : ${m.duration}, explicit : ${m.explicit}");
for (Artist a in m.artists) { for (Artist a in m.artists) {
print("id : ${a.id}, name : ${a.name}"); print("id : ${a.id}, name : ${a.name}");
} }
} }
print('\nMusics With Artist:'); print('\nMusics With Artist:');
List<Music> musics2 = await musicVM.getMusicsWithArtistName('jul'); List<Music> musics2 = await musicVM.getMusicsWithArtistName('jul');
for (Music m in musics2) { for (Music m in musics2) {
print("id : ${m.id.toString()}, cover : ${m.cover}, title : ${m.title}"); print("id : ${m.id.toString()}, cover : ${m.cover}, title : ${m.title}");
print("date : ${m.date.toString()}, preview : ${m.previewUrl}, duration : ${m.duration}, explicit : ${m.explicit}"); print("date : ${m.date.toString()}, preview : ${m.previewUrl}, duration : ${m.duration}, explicit : ${m.explicit}");
for (Artist a in m.artists) { for (Artist a in m.artists) {
print("id : ${a.id}, name : ${a.name}"); print("id : ${a.id}, name : ${a.name}");
} }
} }
print('\nArtist with Name:'); print('\nArtist with Name:');
Artist a = await musicVM.getArtistWithName('jul'); Artist a = await musicVM.getArtistWithName('jul');
print("id : ${a.id}, name : ${a.name}, image : ${a.image}"); print("id : ${a.id}, name : ${a.name}, image : ${a.image}");
print('\nArtists with Name:'); print('\nArtists with Name:');
List<Artist> artists = await musicVM.getArtistsWithName('jul'); List<Artist> artists = await musicVM.getArtistsWithName('jul');
for (Artist a in artists) { for (Artist a in artists) {
print("id : ${a.id}, name : ${a.name}, image : ${a.image}"); print("id : ${a.id}, name : ${a.name}, image : ${a.image}");
} }
print('\nTop Musics :'); print('\nTop Musics :');
List<Music> topMusics = await musicVM.getTopMusicsWithArtistId('3NH8t45zOTqzlZgBvZRjvB'); List<Music> topMusics = await musicVM.getTopMusicsWithArtistId('3NH8t45zOTqzlZgBvZRjvB');
for (Music m in topMusics) { for (Music m in topMusics) {
print("id : ${m.id.toString()}, cover : ${m.cover}, title : ${m.title}"); print("id : ${m.id.toString()}, cover : ${m.cover}, title : ${m.title}");
print("date : ${m.date.toString()}, preview : ${m.previewUrl}, duration : ${m.duration}, explicit : ${m.explicit}"); print("date : ${m.date.toString()}, preview : ${m.previewUrl}, duration : ${m.duration}, explicit : ${m.explicit}");
for (Artist a in m.artists) { for (Artist a in m.artists) {
print("id : ${a.id}, name : ${a.name}"); print("id : ${a.id}, name : ${a.name}");
} }
} }
} }

Loading…
Cancel
Save