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

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

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

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

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

@ -1,25 +1,25 @@
// Generated 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
// as this file may be regenerated.
package io.flutter.app;
import android.app.Application;
import android.content.Context;
import androidx.annotation.CallSuper;
import androidx.multidex.MultiDex;
/**
* Extension of {@link android.app.Application}, adding multidex support.
*/
public class FlutterMultiDexApplication extends Application {
@Override
@CallSuper
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
}
// Generated 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
// as this file may be regenerated.
package io.flutter.app;
import android.app.Application;
import android.content.Context;
import androidx.annotation.CallSuper;
import androidx.multidex.MultiDex;
/**
* Extension of {@link android.app.Application}, adding multidex support.
*/
public class FlutterMultiDexApplication extends Application {
@Override
@CallSuper
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
}

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

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

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

@ -1,34 +1,34 @@
<?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">
<plist version="1.0">
<dict>
<key>CLIENT_ID</key>
<string>994903990520-n6jd98ena56kb1tvtrd67tvb5et3nfbf.apps.googleusercontent.com</string>
<key>REVERSED_CLIENT_ID</key>
<string>com.googleusercontent.apps.994903990520-n6jd98ena56kb1tvtrd67tvb5et3nfbf</string>
<key>API_KEY</key>
<string>AIzaSyBbYqsR6t7JTi8_XFNEHd43IRuKlYGeI3U</string>
<key>GCM_SENDER_ID</key>
<string>994903990520</string>
<key>PLIST_VERSION</key>
<string>1</string>
<key>BUNDLE_ID</key>
<string>com.example.justmusic</string>
<key>PROJECT_ID</key>
<string>justmusic-435d5</string>
<key>STORAGE_BUCKET</key>
<string>justmusic-435d5.appspot.com</string>
<key>IS_ADS_ENABLED</key>
<false></false>
<key>IS_ANALYTICS_ENABLED</key>
<false></false>
<key>IS_APPINVITE_ENABLED</key>
<true></true>
<key>IS_GCM_ENABLED</key>
<true></true>
<key>IS_SIGNIN_ENABLED</key>
<true></true>
<key>GOOGLE_APP_ID</key>
<string>1:994903990520:ios:93188f32e320babe0a9b0d</string>
</dict>
<?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">
<plist version="1.0">
<dict>
<key>CLIENT_ID</key>
<string>994903990520-n6jd98ena56kb1tvtrd67tvb5et3nfbf.apps.googleusercontent.com</string>
<key>REVERSED_CLIENT_ID</key>
<string>com.googleusercontent.apps.994903990520-n6jd98ena56kb1tvtrd67tvb5et3nfbf</string>
<key>API_KEY</key>
<string>AIzaSyBbYqsR6t7JTi8_XFNEHd43IRuKlYGeI3U</string>
<key>GCM_SENDER_ID</key>
<string>994903990520</string>
<key>PLIST_VERSION</key>
<string>1</string>
<key>BUNDLE_ID</key>
<string>com.example.justmusic</string>
<key>PROJECT_ID</key>
<string>justmusic-435d5</string>
<key>STORAGE_BUCKET</key>
<string>justmusic-435d5.appspot.com</string>
<key>IS_ADS_ENABLED</key>
<false></false>
<key>IS_ANALYTICS_ENABLED</key>
<false></false>
<key>IS_APPINVITE_ENABLED</key>
<true></true>
<key>IS_GCM_ENABLED</key>
<true></true>
<key>IS_SIGNIN_ENABLED</key>
<true></true>
<key>GOOGLE_APP_ID</key>
<string>1:994903990520:ios:93188f32e320babe0a9b0d</string>
</dict>
</plist>

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

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

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

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

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

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

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

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

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

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

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

@ -1,408 +1,458 @@
import 'dart:ui';
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_signin_button/button_list.dart';
import 'package:flutter_signin_button/button_view.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:justmusic/values/constants.dart';
import '../components/login_button.dart';
class RegistrationScreen extends StatefulWidget {
const RegistrationScreen({Key? key}) : super(key: key);
@override
State<RegistrationScreen> createState() => _RegistrationScreenState();
}
class _RegistrationScreenState extends State<RegistrationScreen> {
bool passenable = true;
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: bgColor,
body: Stack(
children: [
SingleChildScrollView(
child: SizedBox(
width: double.infinity,
child: Column(
children: [
Padding(
padding: EdgeInsets.only(top: 100.h),
child: AutoSizeText(
"On a besoin de ça!",
style: GoogleFonts.plusJakartaSans(
color: Colors.white,
fontWeight: FontWeight.w600,
fontSize: 30.w),
maxLines: 1,
maxFontSize: 50,
overflow: TextOverflow.fade,
),
),
ConstrainedBox(
constraints: BoxConstraints(maxWidth: 600),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Padding(
padding:
EdgeInsets.symmetric(horizontal: defaultPadding),
child: Padding(
padding: EdgeInsets.only(bottom: 50.h),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
SizedBox(
height: 15.h,
),
SizedBox(
width: 230.h,
child: AutoSizeText(
"Promis cest rapide.",
style: GoogleFonts.plusJakartaSans(
color: Colors.white,
fontWeight: FontWeight.w400,
fontSize: 17.w),
maxFontSize: 20,
textAlign: TextAlign.center,
),
),
],
),
),
),
Padding(
padding: EdgeInsets.only(
bottom: 16.h,
left: defaultPadding,
right: defaultPadding),
child: TextFormField(
keyboardAppearance: Brightness.dark,
validator: (value) {
if (value == null || value.isEmpty) {
return 'TODO';
}
return null;
},
cursorColor: primaryColor,
keyboardType: TextInputType.emailAddress,
style: GoogleFonts.plusJakartaSans(
color: primaryColor, fontSize: 15),
decoration: InputDecoration(
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 1.sp, color: strokeTextField),
borderRadius: const BorderRadius.all(
Radius.circular(10))),
contentPadding: const EdgeInsets.only(
top: 0, bottom: 0, left: defaultPadding),
fillColor: bgTextField,
filled: true,
focusColor:
const Color.fromRGBO(255, 255, 255, 0.30),
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(
width: 1, color: strokeTextField),
borderRadius: BorderRadius.all(
Radius.circular(10))),
hintText: 'Pseudo',
hintStyle: GoogleFonts.plusJakartaSans(
color: strokeTextField)),
)),
Padding(
padding: EdgeInsets.only(
bottom: 16.h,
left: defaultPadding,
right: defaultPadding),
child: TextFormField(
keyboardAppearance: Brightness.dark,
validator: (value) {
if (value == null || value.isEmpty) {
return 'TODO';
}
return null;
},
cursorColor: primaryColor,
keyboardType: TextInputType.emailAddress,
style: GoogleFonts.plusJakartaSans(
color: primaryColor),
decoration: InputDecoration(
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 1, color: strokeTextField),
borderRadius: BorderRadius.all(
Radius.circular(10))),
contentPadding: EdgeInsets.only(
top: 0, bottom: 0, left: defaultPadding),
fillColor: bgTextField,
filled: true,
focusColor:
Color.fromRGBO(255, 255, 255, 0.30),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 1, color: strokeTextField),
borderRadius: BorderRadius.all(
Radius.circular(10))),
hintText: 'Email',
hintStyle: GoogleFonts.plusJakartaSans(
color: strokeTextField)),
)),
Padding(
padding: EdgeInsets.only(
bottom: 16.h,
left: defaultPadding,
right: defaultPadding),
child: TextFormField(
keyboardAppearance: Brightness.dark,
obscureText: passenable,
validator: (value) {
if (value == null || value.isEmpty) {
return 'TODO';
}
return null;
},
cursorColor: primaryColor,
keyboardType: TextInputType.emailAddress,
style: GoogleFonts.plusJakartaSans(
color: primaryColor),
decoration: InputDecoration(
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 1, color: strokeTextField),
borderRadius:
BorderRadius.all(Radius.circular(10))),
contentPadding: EdgeInsets.only(
top: 0, bottom: 0, left: defaultPadding),
fillColor: bgTextField,
filled: true,
focusColor: Color.fromRGBO(255, 255, 255, 0.30),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 1, color: strokeTextField),
borderRadius:
BorderRadius.all(Radius.circular(10))),
hintText: 'Mot de passe',
hintStyle: GoogleFonts.plusJakartaSans(
color: strokeTextField),
suffixIcon: Container(
padding: EdgeInsets.only(right: 10),
margin: EdgeInsets.all(5),
height: 3,
child: InkWell(
onTap: () {
setState(() {
if (passenable) {
passenable = false;
} else {
passenable = true;
}
});
}, // Image tapped
splashColor: Colors
.white10, // Splash color over image
child: Image(
image: passenable
? AssetImage(
"assets/images/show_icon.png")
: AssetImage(
"assets/images/hide_icon.png"),
height: 2,
),
)),
),
),
),
Padding(
padding: EdgeInsets.only(
bottom: 16.h,
left: defaultPadding,
right: defaultPadding),
child: TextFormField(
keyboardAppearance: Brightness.dark,
obscureText: passenable,
validator: (value) {
if (value == null || value.isEmpty) {
return 'TODO';
}
return null;
},
cursorColor: primaryColor,
keyboardType: TextInputType.emailAddress,
style: GoogleFonts.plusJakartaSans(
color: primaryColor),
decoration: InputDecoration(
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 1, color: strokeTextField),
borderRadius:
BorderRadius.all(Radius.circular(10))),
contentPadding: EdgeInsets.only(
top: 0, bottom: 0, left: defaultPadding),
fillColor: bgTextField,
filled: true,
focusColor: Color.fromRGBO(255, 255, 255, 0.30),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 1, color: strokeTextField),
borderRadius:
BorderRadius.all(Radius.circular(10))),
hintText: 'Confirmation du Mot de passe',
hintStyle: GoogleFonts.plusJakartaSans(
color: strokeTextField),
suffixIcon: Container(
padding: EdgeInsets.only(right: 10),
margin: EdgeInsets.all(5),
height: 3,
child: InkWell(
onTap: () {
setState(() {
if (passenable) {
passenable = false;
} else {
passenable = true;
}
});
}, // Image tapped
splashColor: Colors
.white10, // Splash color over image
child: Image(
image: passenable
? AssetImage(
"assets/images/show_icon.png")
: AssetImage(
"assets/images/hide_icon.png"),
height: 2,
),
)),
),
),
),
Padding(
padding:
EdgeInsets.symmetric(horizontal: defaultPadding),
child: SizedBox(
width: 600,
child: LoginButton(
callback: () {},
)),
),
Align(
child: GestureDetector(
onTap: () {
Navigator.pushNamed(context, '/login');
},
child: Padding(
padding: EdgeInsets.only(top: 20),
child: RichText(
textAlign: TextAlign.center,
text: TextSpan(
text: 'Tu as déjà un compte?',
style: GoogleFonts.plusJakartaSans(
color: Colors.white,
fontWeight: FontWeight.w400,
fontSize: 15),
children: <TextSpan>[
TextSpan(
text: " Connexion",
style: GoogleFonts.plusJakartaSans(
fontSize: 15,
fontWeight: FontWeight.w400,
color: primaryColor)),
],
),
),
),
),
),
],
)),
SizedBox(height: 50.h),
ConstrainedBox(
constraints: BoxConstraints(maxWidth: 600),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Expanded(
child: Container(
color: Color(0xFF3D3D3D),
height: 1,
),
),
Padding(
padding: const EdgeInsets.only(
left: defaultPadding, right: defaultPadding),
child: Text(
'Ou',
style: GoogleFonts.plusJakartaSans(
color: Colors.white, fontWeight: FontWeight.bold),
),
),
Expanded(
child: Container(
height: 1,
color: Color(0xFF3D3D3D),
)),
],
),
),
SizedBox(height: 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,
),
),
),
),
),
],
),
);
}
}
import 'dart:ui';
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_signin_button/button_list.dart';
import 'package:flutter_signin_button/button_view.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:justmusic/values/constants.dart';
import '../components/login_button.dart';
import '../main.dart';
class RegistrationScreen extends StatefulWidget {
const RegistrationScreen({Key? key}) : super(key: key);
@override
State<RegistrationScreen> createState() => _RegistrationScreenState();
}
class _RegistrationScreenState extends State<RegistrationScreen> {
bool passenable = true;
final _formKey = GlobalKey<FormState>();
final _userPseudoTextField = TextEditingController();
final _userMailTextField = TextEditingController();
final _passwordTextField = TextEditingController();
final _passwordConfirmTextField = TextEditingController();
handleRegister() async {
if (_formKey.currentState!.validate()) {
try {
await MyApp.userViewModel.register(_userPseudoTextField.text,
_passwordTextField.text, _userMailTextField.text);
Navigator.pushNamed(context, '/explanation');
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
e.toString() ?? "",
style: GoogleFonts.plusJakartaSans(
color: Colors.white,
fontWeight: FontWeight.w400,
fontSize: 20.h),
),
backgroundColor: Colors.red,
),
);
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: bgColor,
body: Form(
key: _formKey,
child: Stack(
children: [
SingleChildScrollView(
child: SizedBox(
width: double.infinity,
child: Column(
children: [
Padding(
padding: EdgeInsets.only(top: 100.h),
child: AutoSizeText(
"On a besoin de ça!",
style: GoogleFonts.plusJakartaSans(
color: Colors.white,
fontWeight: FontWeight.w600,
fontSize: 30.w),
maxLines: 1,
maxFontSize: 50,
overflow: TextOverflow.fade,
),
),
ConstrainedBox(
constraints: BoxConstraints(maxWidth: 600),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.symmetric(
horizontal: defaultPadding),
child: Padding(
padding: EdgeInsets.only(bottom: 50.h),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
SizedBox(
height: 15.h,
),
SizedBox(
width: 230.h,
child: AutoSizeText(
"Promis cest rapide.",
style: GoogleFonts.plusJakartaSans(
color: Colors.white,
fontWeight: FontWeight.w400,
fontSize: 17.w),
maxFontSize: 20,
textAlign: TextAlign.center,
),
),
],
),
),
),
Padding(
padding: EdgeInsets.only(
bottom: 16.h,
left: defaultPadding,
right: defaultPadding),
child: TextFormField(
controller: _userPseudoTextField,
keyboardAppearance: Brightness.dark,
validator: (value) {
if (value == null || value.isEmpty) {
return 'entrez un pseudo valide';
}
return null;
},
cursorColor: primaryColor,
keyboardType: TextInputType.emailAddress,
style: GoogleFonts.plusJakartaSans(
color: primaryColor, fontSize: 15),
decoration: InputDecoration(
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 1.sp,
color: strokeTextField),
borderRadius: const BorderRadius.all(
Radius.circular(10))),
prefix: const Padding(
padding: EdgeInsets.only(left: 20.0)),
suffix: const Padding(
padding: EdgeInsets.only(left: 20.0)),
fillColor: bgTextField,
filled: true,
focusColor: const Color.fromRGBO(
255, 255, 255, 0.30),
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(
width: 1, color: strokeTextField),
borderRadius: BorderRadius.all(
Radius.circular(10))),
hintText: 'Pseudo',
hintStyle: GoogleFonts.plusJakartaSans(
color: strokeTextField)),
)),
Padding(
padding: EdgeInsets.only(
bottom: 16.h,
left: defaultPadding,
right: defaultPadding),
child: TextFormField(
controller: _userMailTextField,
keyboardAppearance: Brightness.dark,
validator: (value) {
if (value == null || value.isEmpty) {
return 'entrez un email valide';
}
return null;
},
cursorColor: primaryColor,
keyboardType: TextInputType.emailAddress,
style: GoogleFonts.plusJakartaSans(
color: primaryColor),
decoration: InputDecoration(
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 1, color: strokeTextField),
borderRadius: BorderRadius.all(
Radius.circular(10))),
prefix: const Padding(
padding: EdgeInsets.only(left: 20.0)),
suffix: const Padding(
padding: EdgeInsets.only(left: 20.0)),
fillColor: bgTextField,
filled: true,
focusColor:
Color.fromRGBO(255, 255, 255, 0.30),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 1, color: strokeTextField),
borderRadius: BorderRadius.all(
Radius.circular(10))),
hintText: 'Email',
hintStyle: GoogleFonts.plusJakartaSans(
color: strokeTextField)),
)),
Padding(
padding: EdgeInsets.only(
bottom: 16.h,
left: defaultPadding,
right: defaultPadding),
child: TextFormField(
controller: _passwordTextField,
keyboardAppearance: Brightness.dark,
obscureText: passenable,
validator: (value) {
if (value == null || value.isEmpty) {
return 'entrez un mot de passe valide';
}
return null;
},
cursorColor: primaryColor,
style: GoogleFonts.plusJakartaSans(
color: primaryColor),
decoration: InputDecoration(
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 1, color: strokeTextField),
borderRadius:
BorderRadius.all(Radius.circular(10))),
prefix: const Padding(
padding: EdgeInsets.only(left: 20.0)),
suffix: const Padding(
padding: EdgeInsets.only(left: 20.0)),
fillColor: bgTextField,
filled: true,
focusColor: Color.fromRGBO(255, 255, 255, 0.30),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 1, color: strokeTextField),
borderRadius:
BorderRadius.all(Radius.circular(10))),
hintText: 'Mot de passe',
hintStyle: GoogleFonts.plusJakartaSans(
color: strokeTextField),
suffixIcon: Container(
padding: EdgeInsets.only(right: 10),
margin: EdgeInsets.all(5),
height: 3,
child: InkWell(
onTap: () {
setState(() {
if (passenable) {
passenable = false;
} else {
passenable = true;
}
});
},
// Image tapped
splashColor: Colors.white10,
// Splash color over image
child: Image(
image: passenable
? AssetImage(
"assets/images/show_icon.png")
: AssetImage(
"assets/images/hide_icon.png"),
height: 2,
),
)),
),
),
),
Padding(
padding: EdgeInsets.only(
bottom: 16.h,
left: defaultPadding,
right: defaultPadding),
child: TextFormField(
controller: _passwordConfirmTextField,
keyboardAppearance: Brightness.dark,
obscureText: passenable,
validator: (value) {
if (value == null || value.isEmpty) {
return 'entrez un mot de passe valide';
} else if (_passwordTextField.text != value) {
return 'les mots de passes ne sont pas identiques';
}
return null;
},
cursorColor: primaryColor,
keyboardType: TextInputType.emailAddress,
style: GoogleFonts.plusJakartaSans(
color: primaryColor),
decoration: InputDecoration(
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 1, color: strokeTextField),
borderRadius:
BorderRadius.all(Radius.circular(10))),
prefix: const Padding(
padding: EdgeInsets.only(left: 20.0)),
suffix: const Padding(
padding: EdgeInsets.only(left: 20.0)),
fillColor: bgTextField,
filled: true,
focusColor: Color.fromRGBO(255, 255, 255, 0.30),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 1, color: strokeTextField),
borderRadius:
BorderRadius.all(Radius.circular(10))),
hintText: 'Confirmation du Mot de passe',
hintStyle: GoogleFonts.plusJakartaSans(
color: strokeTextField),
suffixIcon: Container(
padding: EdgeInsets.only(right: 10),
margin: EdgeInsets.all(5),
height: 3,
child: InkWell(
onTap: () {
setState(() {
if (passenable) {
passenable = false;
} else {
passenable = true;
}
});
},
// Image tapped
splashColor: Colors.white10,
// Splash color over image
child: Image(
image: passenable
? AssetImage(
"assets/images/show_icon.png")
: AssetImage(
"assets/images/hide_icon.png"),
height: 2,
),
)),
),
),
),
Padding(
padding: EdgeInsets.symmetric(
horizontal: defaultPadding),
child: SizedBox(
width: 600,
child: LoginButton(
callback: handleRegister,
)),
),
Align(
child: GestureDetector(
onTap: () {
Navigator.pushNamed(context, '/login');
},
child: Padding(
padding: EdgeInsets.only(top: 20),
child: RichText(
textAlign: TextAlign.center,
text: TextSpan(
text: 'Tu as déjà un compte?',
style: GoogleFonts.plusJakartaSans(
color: Colors.white,
fontWeight: FontWeight.w400,
fontSize: 15),
children: <TextSpan>[
TextSpan(
text: " Connexion",
style: GoogleFonts.plusJakartaSans(
fontSize: 15,
fontWeight: FontWeight.w400,
color: primaryColor)),
],
),
),
),
),
),
],
)),
SizedBox(height: 50.h),
ConstrainedBox(
constraints: BoxConstraints(maxWidth: 600),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Expanded(
child: Container(
color: Color(0xFF3D3D3D),
height: 1,
),
),
Padding(
padding: const EdgeInsets.only(
left: defaultPadding, right: defaultPadding),
child: Text(
'Ou',
style: GoogleFonts.plusJakartaSans(
color: Colors.white,
fontWeight: FontWeight.bold),
),
),
Expanded(
child: Container(
height: 1,
color: Color(0xFF3D3D3D),
)),
],
),
),
SizedBox(height: 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:ui';
import 'package:flutter/Material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:justmusic/model/Music.dart';
import '../components/music_list_component.dart';
import '../values/constants.dart';
import '../main.dart';
class SearchSongScreen extends StatefulWidget {
const SearchSongScreen({Key? key}) : super(key: key);
@override
State<SearchSongScreen> createState() => _SearchSongScreenState();
}
class _SearchSongScreenState extends State<SearchSongScreen> {
final ScrollController _scrollController = ScrollController();
final TextEditingController _textEditingController = TextEditingController();
Future<void> resetFullScreen() async {
await SystemChannels.platform.invokeMethod<void>(
'SystemChrome.restoreSystemUIOverlays',
);
}
@override
void initState() {
super.initState();
_scrollController.addListener(_scrollListener);
}
Future<void> _scrollListener() async {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
filteredData.addAll(await MyApp.musicViewModel.getMusicsWithName(
_textEditingController.text,
limit: 10,
offset: filteredData.length));
setState(() {
filteredData = filteredData;
});
}
if (_scrollController.offset >=
_scrollController.position.maxScrollExtent &&
!_scrollController.position.outOfRange) {
setState(() {
//you can do anything here
});
}
if (_scrollController.offset <=
_scrollController.position.minScrollExtent &&
!_scrollController.position.outOfRange) {
setState(() {
Timer(Duration(milliseconds: 1), () => _scrollController.jumpTo(0));
});
}
}
List<Music> filteredData = [];
@override
Widget build(BuildContext context) {
double screenHeight = MediaQuery.of(context).size.height;
return GestureDetector(
onTap: () {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus) {
currentFocus.unfocus();
resetFullScreen();
}
},
child: BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 60.0,
sigmaY: 60.0,
),
child: Container(
color: bgAppBar.withOpacity(0.5),
height: screenHeight - 50,
padding: const EdgeInsets.only(top: 10),
child: Column(
children: [
Align(
child: Container(
width: 60,
height: 5,
decoration: BoxDecoration(
color: Color(0xFF3A3A3A).withOpacity(0.6),
borderRadius: BorderRadius.circular(20))),
),
const SizedBox(
height: 10,
),
Padding(
padding:
const EdgeInsets.only(bottom: 10, left: 20, right: 20),
child: SizedBox(
height: 40,
child: TextField(
controller: _textEditingController,
keyboardAppearance: Brightness.dark,
onEditingComplete: resetFullScreen,
onChanged: (value) async {
if (_textEditingController.text.isEmpty) {
} else if (value == " ") {
print("popular");
} else {
filteredData = await MyApp.musicViewModel
.getMusicsWithName(value);
setState(() {
filteredData = filteredData;
});
}
},
cursorColor: Colors.white,
keyboardType: TextInputType.text,
style: GoogleFonts.plusJakartaSans(color: grayText),
decoration: InputDecoration(
prefixIcon: const Icon(
Icons.search,
color: grayColor,
),
focusedBorder: const OutlineInputBorder(
borderSide:
BorderSide(width: 1, color: grayColor),
borderRadius:
BorderRadius.all(Radius.circular(10))),
contentPadding: const EdgeInsets.only(
top: 0,
bottom: 0,
left: defaultPadding,
right: defaultPadding),
fillColor: searchBarColor,
filled: true,
focusColor: grayText,
enabledBorder: const OutlineInputBorder(
borderSide:
BorderSide(width: 1, color: grayColor),
borderRadius:
BorderRadius.all(Radius.circular(10))),
hintText: 'Chercher un son',
hintStyle:
GoogleFonts.plusJakartaSans(color: grayColor)),
),
),
),
Flexible(
child: ScrollConfiguration(
behavior: ScrollBehavior().copyWith(scrollbars: true),
child: ListView.builder(
controller: _scrollController,
itemCount: filteredData.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: MusicListComponent(music: filteredData[index]),
);
}),
))
],
),
),
));
}
}
import 'dart:async';
import 'dart:ui';
import 'package:flutter/Material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:justmusic/model/Music.dart';
import '../components/music_list_component.dart';
import '../values/constants.dart';
import '../main.dart';
class SearchSongScreen extends StatefulWidget {
const SearchSongScreen({Key? key}) : super(key: key);
@override
State<SearchSongScreen> createState() => _SearchSongScreenState();
}
class _SearchSongScreenState extends State<SearchSongScreen> {
final ScrollController _scrollController = ScrollController();
final TextEditingController _textEditingController = TextEditingController();
Future<void> resetFullScreen() async {
await SystemChannels.platform.invokeMethod<void>(
'SystemChrome.restoreSystemUIOverlays',
);
}
@override
void initState() {
super.initState();
_scrollController.addListener(_scrollListener);
}
Future<void> _scrollListener() async {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
filteredData.addAll(await MyApp.musicViewModel.getMusicsWithName(
_textEditingController.text,
limit: 10,
offset: filteredData.length));
setState(() {
filteredData = filteredData;
});
}
if (_scrollController.offset >=
_scrollController.position.maxScrollExtent &&
!_scrollController.position.outOfRange) {
setState(() {
//you can do anything here
});
}
if (_scrollController.offset <=
_scrollController.position.minScrollExtent &&
!_scrollController.position.outOfRange) {
setState(() {
Timer(Duration(milliseconds: 1), () => _scrollController.jumpTo(0));
});
}
}
List<Music> filteredData = [];
@override
Widget build(BuildContext context) {
double screenHeight = MediaQuery.of(context).size.height;
return GestureDetector(
onTap: () {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus) {
currentFocus.unfocus();
resetFullScreen();
}
},
child: BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 60.0,
sigmaY: 60.0,
),
child: Container(
color: bgAppBar.withOpacity(0.5),
height: screenHeight - 50,
padding: const EdgeInsets.only(top: 10),
child: Column(
children: [
Align(
child: Container(
width: 60,
height: 5,
decoration: BoxDecoration(
color: Color(0xFF3A3A3A).withOpacity(0.6),
borderRadius: BorderRadius.circular(20))),
),
const SizedBox(
height: 10,
),
Padding(
padding:
const EdgeInsets.only(bottom: 10, left: 20, right: 20),
child: SizedBox(
height: 40,
child: TextField(
controller: _textEditingController,
keyboardAppearance: Brightness.dark,
onEditingComplete: resetFullScreen,
onChanged: (value) async {
if (_textEditingController.text.isEmpty) {
} else if (value == " ") {
print("popular");
} else {
filteredData = await MyApp.musicViewModel
.getMusicsWithName(value);
setState(() {
filteredData = filteredData;
});
}
},
cursorColor: Colors.white,
keyboardType: TextInputType.text,
style: GoogleFonts.plusJakartaSans(color: grayText),
decoration: InputDecoration(
prefixIcon: const Icon(
Icons.search,
color: grayColor,
),
focusedBorder: const OutlineInputBorder(
borderSide:
BorderSide(width: 1, color: grayColor),
borderRadius:
BorderRadius.all(Radius.circular(10))),
contentPadding: const EdgeInsets.only(
top: 0,
bottom: 0,
left: defaultPadding,
right: defaultPadding),
fillColor: searchBarColor,
filled: true,
focusColor: grayText,
enabledBorder: const OutlineInputBorder(
borderSide:
BorderSide(width: 1, color: grayColor),
borderRadius:
BorderRadius.all(Radius.circular(10))),
hintText: 'Chercher un son',
hintStyle:
GoogleFonts.plusJakartaSans(color: grayColor)),
),
),
),
Flexible(
child: ScrollConfiguration(
behavior: ScrollBehavior().copyWith(scrollbars: true),
child: ListView.builder(
controller: _scrollController,
itemCount: filteredData.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: MusicListComponent(music: filteredData[index]),
);
}),
))
],
),
),
));
}
}

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

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

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

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

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

File diff suppressed because it is too large Load Diff

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

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

Loading…
Cancel
Save