diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar new file mode 100755 index 0000000000000000000000000000000000000000..13372aef5e24af05341d49695ee84e5f9b594659 Binary files /dev/null and b/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/android/gradlew b/android/gradlew new file mode 100755 index 0000000000000000000000000000000000000000..9d82f78915133e1c35a6ea51252590fb38efac2f --- /dev/null +++ b/android/gradlew @@ -0,0 +1,160 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/android/gradlew.bat b/android/gradlew.bat new file mode 100755 index 0000000000000000000000000000000000000000..8a0b282aa6885fb573c106b3551f7275c5f17e8e --- /dev/null +++ b/android/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/android/local.properties b/android/local.properties new file mode 100644 index 0000000000000000000000000000000000000000..90b2b71fc5fa757606928093d102fb697252ab1a --- /dev/null +++ b/android/local.properties @@ -0,0 +1,5 @@ +sdk.dir=/Users/Erik/Library/Android/sdk +flutter.sdk=/opt/homebrew/Caskroom/flutter/3.3.9/flutter +flutter.buildMode=debug +flutter.versionName=1.0.0 +flutter.versionCode=1 \ No newline at end of file diff --git a/lib/classification/CustomSearchDelegate.dart b/lib/classification/CustomSearchDelegate.dart index 8fdb5bf7b91cd4bb51380ab8ee3f3f8281544ace..5a1ab2549cc4658cf4e5b0d86717edc93d552578 100644 --- a/lib/classification/CustomSearchDelegate.dart +++ b/lib/classification/CustomSearchDelegate.dart @@ -2,6 +2,8 @@ import 'package:flutter/material.dart'; import '../firebase.dart'; +//Suchleiste mit den Vorschlägen aller Genres aus Spotify + class CustomSearchDelegate extends SearchDelegate<String>{ String colorText; CustomSearchDelegate(this.colorText); diff --git a/lib/classification/classification.dart b/lib/classification/classification.dart index 0483f2533556ac02890b4f2e07f1582a75de3dd5..693ad65bbc930ce3e4f109bbe57fb638b39108a6 100644 --- a/lib/classification/classification.dart +++ b/lib/classification/classification.dart @@ -5,25 +5,29 @@ import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_custom_clippers/flutter_custom_clippers.dart'; import '../main.dart'; +import '../widgets/MusicPlayerState.dart'; import 'CustomSearchDelegate.dart'; import '../homepage.dart'; +import 'package:google_fonts/google_fonts.dart'; + +/* +Klasse & Screen zur Klassifizierung der Farben zu den Genres. +Es gibt eine graue Default Seite wenn keine Farbe ausgewählt ist. +Wenn eine Farbe ausgewählt wird, kann man das Genre dazu auswählen. +Die Klassifizierung wird dann in der Datenbank aktualisiert + */ class ClassificationPage extends StatefulWidget { const ClassificationPage({Key? key}) : super(key: key); @override State<StatefulWidget> createState() => _ClassificationPageState(); - } class _ClassificationPageState extends State<ClassificationPage> { final String id = (FirebaseAuth.instance.currentUser?.uid.toString())!+'_genres'; - - Color _ambientBackgroundColor = Colors.grey.withOpacity(0.5); - Color _ambientHeader = Colors.white; - String genreValue = ''; bool _redSelected = false; @@ -47,35 +51,54 @@ class _ClassificationPageState extends State<ClassificationPage> { return Scaffold( resizeToAvoidBottomInset: false, body: Container( + color: _ambientBackgroundColor, child: Column( children: [ - ClipPath( - clipper: WaveClipperTwo(flip: true), - child: Container( - height: 140, - color: _ambientBackgroundColor, - child: Center( - child: Text( - 'Ambient!', - style: TextStyle( - fontSize: 40.0, color: _ambientHeader), - ), - ),),), - Expanded( - child: ListView( + const SizedBox(height: 40,), + SizedBox( height: 50, width: 300, + child: Text('Ambient!', + style: + GoogleFonts.cabin( + fontSize: 40.0, color: Colors.white.withOpacity(0.85)),),), + const SizedBox(height: 20,), + SizedBox( + height: 80, + width: 300, + child : Text('Select the genre that fits to the emotion of each color', + style: + GoogleFonts.cabin( + fontSize: 20.0, color: Colors.white.withOpacity(0.85),),),), + + + Expanded( + child: Container( + height: 50, + decoration: BoxDecoration( + color: Color(0xffffffff), + borderRadius: BorderRadius.only(topLeft: Radius.circular(50),topRight: Radius.circular(50)), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.5), + spreadRadius: 5, + blurRadius: 7, + offset: Offset(0, 3), + ), + ],), + child: ListView( children: <Widget>[ - const SizedBox(height: 20,), GestureDetector( - onTap: (){ + onTap: () async { + + if(!_redSelected){closeAll(); setState(() => _redSelected = true); } else{closeAll();} _ambientBackgroundColor = Colors.red; if (!_redSelected){_ambientBackgroundColor = Colors.grey.withOpacity(0.5);}}, child: Container( child: _redSelected ? - selectedColor("Red", Colors.red, Colors.white.withOpacity(0.7), + selectedColor("Red", Colors.red, Colors.white.withOpacity(0.9), "rock","latin", "blues", - 'Starke Emotionen, Liebe, Energie') : noSelection("Red") + 'Strong emotions, love, energie') : noSelection("Red") ) ,), const SizedBox(height: 20,), @@ -87,8 +110,8 @@ class _ClassificationPageState extends State<ClassificationPage> { if (!_orangeSelected){_ambientBackgroundColor = Colors.grey.withOpacity(0.5);}}, child: Container( child: _orangeSelected ? - selectedColor("Orange", Colors.orange, Colors.white.withOpacity(0.7), - "soul", "jazz", "Orange 3", 'Wärme, Energie, Herbst') : noSelection("Orange") + selectedColor("Orange", Colors.orange, Colors.white.withOpacity(0.9), + "soul", "jazz", "indie-pop", 'warmth, energie, fall') : noSelection("Orange") ) ,), const SizedBox(height: 20,), @@ -101,7 +124,7 @@ class _ClassificationPageState extends State<ClassificationPage> { child: Container( child: _yellowSelected ? selectedColor("Yellow", Colors.yellow, Colors.white, - "pop", "funk", "country", 'Freude, Optimismus, Wärme') : noSelection("Yellow") + "pop", "funk", "country", 'happiness, optimism, warmth') : noSelection("Yellow") ) ,), const SizedBox(height: 20,), @@ -113,8 +136,8 @@ class _ClassificationPageState extends State<ClassificationPage> { if (!_greenSelected){_ambientBackgroundColor = Colors.grey.withOpacity(0.5);}}, child: Container( child: _greenSelected ? - selectedColor("Green", Colors.green, Colors.white.withOpacity(0.7), - "ambient", "classical", "new-age", 'Ruhe, Wachstum, Natur') : noSelection("Green") + selectedColor("Green", Colors.green, Colors.white.withOpacity(0.9), + "ambient", "classical", "new-age", 'calmness, growth, nature') : noSelection("Green") ) ,), const SizedBox(height: 20,), @@ -122,12 +145,12 @@ class _ClassificationPageState extends State<ClassificationPage> { onTap: (){ if(!_whiteSelected){closeAll(); setState(() => _whiteSelected = true); } else{closeAll();} - _ambientBackgroundColor = Colors.white60; + _ambientBackgroundColor = Colors.grey.withOpacity(0.5); if (!_whiteSelected){_ambientBackgroundColor = Colors.grey.withOpacity(0.5);}}, child: Container( child: _whiteSelected ? - selectedColor("White", Colors.white60, Colors.grey, - "classical", "ambient", "piano", 'Reinheit, Frieden, Gelassenheit') : noSelection("White") + selectedColor("White", Colors.white, Colors.grey.withOpacity(0.7), + "classical", "ambient", "piano", 'calmness, peace, serenity') : noSelection("White") ) ,), const SizedBox(height: 20,), @@ -139,8 +162,8 @@ class _ClassificationPageState extends State<ClassificationPage> { if (!_blueSelected){_ambientBackgroundColor = Colors.grey.withOpacity(0.5);}}, child: Container( child: _blueSelected ? - selectedColor( "Blue", Colors.blue, Colors.white.withOpacity(0.7), - "blues", "rainy-day", "indie-pop", 'Ruhe, Gelassenheit, Traurigkeit') : noSelection("Blue") + selectedColor( "Blue", Colors.blue, Colors.white.withOpacity(0.9), + "blues", "rainy-day", "indie-pop", 'calm, Gelassenheit, sadness') : noSelection("Blue") ) ,), const SizedBox(height: 20,), @@ -153,8 +176,8 @@ class _ClassificationPageState extends State<ClassificationPage> { child: Container( child: _pinkSelected ? selectedColor( - "Pink", Colors.pink, Colors.white.withOpacity(0.7), - "pop", "k-pop", "r-n-b", 'Romantik, Anmut, Nostalgie') : noSelection("Pink") + "Pink", Colors.pink, Colors.white.withOpacity(0.9), + "pop", "k-pop", "r-n-b", 'romance, charm, nostalgia') : noSelection("Pink") ) ,), const SizedBox(height: 20,), @@ -166,8 +189,8 @@ class _ClassificationPageState extends State<ClassificationPage> { if (!_purpleSelected){_ambientBackgroundColor = Colors.grey.withOpacity(0.5);}}, child: Container( child: _purpleSelected ? - selectedColor("Purple", Colors.purple, Colors.white.withOpacity(0.7), - "rock", "classical", "hip-hop", 'Luxus, Spiritualität, Ambition') : noSelection("Purple") + selectedColor("Purple", Colors.purple, Colors.white.withOpacity(0.9), + "rock", "classical", "hip-hop", 'luxury, spirituality, ambition') : noSelection("Purple") ) ,), const SizedBox(height: 20,), @@ -179,8 +202,8 @@ class _ClassificationPageState extends State<ClassificationPage> { if (!_brownSelected){_ambientBackgroundColor = Colors.grey.withOpacity(0.5);}}, child: Container( child: _brownSelected ? - selectedColor("Brown", Colors.brown, Colors.white.withOpacity(0.7), - "country", "Brown2", "Brown3", 'info') : noSelection("Brown") + selectedColor("Brown", Colors.brown, Colors.white.withOpacity(0.9), + "country", "folk", "reggae", 'warmth, security, nostalgia, calm') : noSelection("Brown") ) ,), const SizedBox(height: 20,), @@ -188,29 +211,33 @@ class _ClassificationPageState extends State<ClassificationPage> { onTap: () { if(!_blackSelected){closeAll(); setState(() => _blackSelected = true); } else{closeAll();} - _ambientBackgroundColor = Colors.black54; + _ambientBackgroundColor = Colors.black87; if (!_blackSelected){_ambientBackgroundColor = Colors.grey.withOpacity(0.5);}}, child: Container( child: _blackSelected ? - selectedColor("Black", Colors.black54, Colors.white.withOpacity(0.7), "Black1", "Black2", "Black3", 'info') : noSelection("Black") + selectedColor("Black", Colors.black87, Colors.white.withOpacity(0.7), + "metal", "classical", "rock", 'melancholy, power, noble') : noSelection("Black") ) ,), const SizedBox(height: 20,), - SizedBox( - width: 100, + Align( + alignment: Alignment.center, + child: Container( + width: 200, height: 40, child : StreamBuilder( + //Es wird in der Datenbank geprüft, ob zu allen Farben ein Genre ausgewählt wurde stream: FirebaseFirestore.instance.collection('classification').doc(id).snapshots(), builder: (BuildContext context, AsyncSnapshot snapshot) { return ElevatedButton( - style:ButtonStyle(backgroundColor: MaterialStatePropertyAll<Color>(Colors.white.withOpacity(0.9))), + style:ButtonStyle( + backgroundColor: MaterialStatePropertyAll<Color>(Colors.white.withOpacity(0.9))), child: const Text( - "Save", - style: TextStyle(color: Colors.indigo, fontWeight: FontWeight.bold),), + "Save", style: TextStyle(color: Colors.indigo, fontWeight: FontWeight.bold),), onPressed: () { print(changeFirebase().checkIfEverythingSelected(snapshot).toString()); if (changeFirebase().checkIfEverythingSelected(snapshot)) { - Navigator.push(context, MaterialPageRoute(builder: (context) => HUD())); + Navigator.push(context, MaterialPageRoute(builder: (context)=>MusicPlayerState(child: const HUD()))); } else{ setState(() { @@ -218,7 +245,7 @@ class _ClassificationPageState extends State<ClassificationPage> { }); } }); - })), + }))), Container( child: _errorText ? const Text('Not everything is selected!', @@ -226,10 +253,8 @@ class _ClassificationPageState extends State<ClassificationPage> { style: TextStyle( fontSize: 20, color: Colors.red),) : null ), - SizedBox(height: 40,) - ]), - ), - ] + const SizedBox(height: 40,) + ]),),)] ) )); } @@ -240,89 +265,76 @@ class _ClassificationPageState extends State<ClassificationPage> { style: TextStyle(fontSize: 20, color: Colors.red) ); } + //wenn die Farbe nicht ausgewählt ist, wird kein Genre-Auswahl dargestellt und die Farben sind grau - Column noSelection(String colorText) { - return Column( - children: [ - Row( + Align noSelection(String colorText) { + return Align( + alignment: Alignment.center, + child:Container( + width: 320, + decoration: BoxDecoration( + color: Colors.transparent, + border: Border.all( + color: Colors.grey.shade300, width: 1), + borderRadius: BorderRadius.circular(10),), + child: Column( + children: [ + SizedBox(height: 50,), + Row( children: [ - const SizedBox(width: 30, height: 50), + const SizedBox(width: 25), Text(colorText, - style: const TextStyle(fontSize: 30, color: Colors.grey)), - ] - ), - Align( - alignment: Alignment.center, - child: Row( - children: [ - const SizedBox(width: 30), - Container( - width: 340, - decoration: BoxDecoration( - color: Colors.transparent, - border: Border.all( - color: Colors.grey, - width: 1), - borderRadius: BorderRadius.circular(10), - ), - child: StreamBuilder( + style: GoogleFonts.cabin(fontSize: 20.0, color: Colors.grey.shade400,)),]), + Row( + children: [ + const SizedBox(width: 25), + StreamBuilder( stream: FirebaseFirestore.instance.collection('classification').doc(id).snapshots(), builder: (BuildContext context, AsyncSnapshot snapshot){ if (snapshot.connectionState == ConnectionState.waiting) { return const Center( - child: CircularProgressIndicator(), - ); - } - return - Text(changeFirebase().checkForNull(snapshot.data.data()[colorText]), textAlign: TextAlign.center, - style: const TextStyle(fontSize: 20, color: Colors.grey),); - } - ) - ) - ] - ) - ) - ]); -} + child: CircularProgressIndicator(),);} + return Text(changeFirebase().checkForNull(snapshot.data.data()[colorText]), textAlign: TextAlign.center, + style: GoogleFonts.cabin(fontSize: 40.0, color: Colors.grey.shade400,),); + }),]), + SizedBox(height: 5,)])));} - Column selectedColor(String colorText, Color color, Color textColor, String rec1, String rec2, String rec3, String infoText) { - return Column( - children: [ - Row( - children: [ - const SizedBox(width: 30, height: 50), - Text(colorText, style: TextStyle(fontSize: 30, color: color)), - IconButton(onPressed:(){ - _showMyDialog(colorText, infoText); - }, - alignment: Alignment.centerRight, - icon: Icon( Icons.info_outline, color: color), - ), - ],), - selectedGenre(colorText, color, textColor, rec1, rec2, rec3), - ]); - } - Align selectedGenre(String colorText, Color color, Color textColor, String rec1, String rec2, - String rec3) { + //Wenn eine Farbe ausgewählt wird, werden die Farben entsprechend angepasst + //Und man kann ein Genre zu dieser Farbe auswählen + Align selectedColor(String colorText, Color color, Color textColor, String rec1, String rec2, String rec3, String infoText) { return Align( - alignment: Alignment.center, - child: Column( - children: [ - Row( - children: [ - const SizedBox(width: 30), - Container( - width: 340, - decoration: BoxDecoration( - color: Colors.transparent, - border: Border.all( - color: color, - width: 1), - borderRadius: BorderRadius.circular(10), - ), - child: - StreamBuilder( + alignment: Alignment.center, + child:Container( + width: 320, + decoration: BoxDecoration( + color: color, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.4), + blurRadius: 10.0, + spreadRadius: 2.0, + offset: const Offset(0.0, 0.0),)]), + child: Column( + children: [ + Align( + alignment: Alignment.topRight, + child : IconButton(onPressed:(){ + _showMyDialog(colorText, infoText);}, + alignment: Alignment.centerRight, + icon: Icon( Icons.info_outline, color: textColor.withOpacity(0.7), size: 35,),), + ), + SizedBox(height: 0,), + Row( + children: [ + const SizedBox(width: 25), + Text(colorText, + style: GoogleFonts.cabin(fontSize: 20.0, color: textColor,)),]), + Row( + children: [ + const SizedBox(width: 25), + StreamBuilder( stream: FirebaseFirestore.instance.collection('classification').doc(id).snapshots(), builder: (BuildContext context, AsyncSnapshot snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { @@ -332,29 +344,10 @@ class _ClassificationPageState extends State<ClassificationPage> { } return Text(changeFirebase().checkForNull(snapshot.data.data()[colorText]), textAlign: TextAlign.center, - style: TextStyle(color: color, fontSize: 20),); + style: GoogleFonts.cabin(fontSize: 40.0, color: textColor),); } - ), - ) ] - ), - const SizedBox(height: 30), - Container( - width: 340, - // alignment: Alignment.center, - decoration: BoxDecoration( - color: color, - borderRadius: BorderRadius.circular(10), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - blurRadius: 10.0, - spreadRadius: 2.0, - offset: const Offset(0.0, 0.0), - ) - ], - ), - child: Column( - children: [ + ),]), + const SizedBox(height: 20,), Container( width: 290, @@ -402,17 +395,14 @@ class _ClassificationPageState extends State<ClassificationPage> { ), const SizedBox(height: 50,) ] - ) - ] - ) - - ) - ])); - } + )]))); + } GestureDetector recommendationLabel(String colorText, String rec, Color textColor) { return GestureDetector( - onTap: () => changeFirebase().updateColorGenre(colorText, rec), + onTap: () { + changeFirebase().updateColorGenre(colorText, rec); + closeAll();}, child:Container( child: Row( children: [ @@ -430,12 +420,11 @@ class _ClassificationPageState extends State<ClassificationPage> { style: TextStyle(fontSize: 20, color: textColor) ), ) - )] - ) - ), + )])), ); } + //Info Dialog zur Erklärung der Farben-Emotionen Future<void> _showMyDialog(String colorText, String infoText) { return showDialog<void>( context: context, @@ -447,8 +436,7 @@ class _ClassificationPageState extends State<ClassificationPage> { child: ListBody( children: <Widget>[ Text(infoText), - ], - ), + ],), ), actions: <Widget>[ TextButton( @@ -475,4 +463,5 @@ class _ClassificationPageState extends State<ClassificationPage> { }); _ambientBackgroundColor = Colors.grey.withOpacity(0.5); } + } diff --git a/lib/classification/color_widgets.dart b/lib/classification/color_widgets.dart deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/lib/firebase.dart b/lib/firebase.dart index 88fe12c0851b94e62c4d3db9594a722fe9ddf505..68cabf5593204abf42fbdacdf51dd3a9f63f121b 100644 --- a/lib/firebase.dart +++ b/lib/firebase.dart @@ -36,40 +36,40 @@ class changeFirebase{ return true; } - String getGenreByHex(String code){ + Future<String> getGenreByHex(String code) async { switch (code){ case 'FF0000': - return getGenreByColor('Red'); - case 'FF8800': - return getGenreByColor('Orange'); + return await getGenreByColor('Red'); + case 'FFA500': + return await getGenreByColor('Orange'); case 'FFFF00': return getGenreByColor('Yellow'); - case 'FF8800': + case '00FF00': return getGenreByColor('Green'); case 'FFFFFF': return getGenreByColor('White'); case '0000FF': return getGenreByColor('Blue'); - case 'FFC0CB': + case 'FF46FD': return getGenreByColor('Pink'); - case 'A020F0': + case '7F45D8': return getGenreByColor('Purple'); - case '964B00': + case '67402D': return getGenreByColor('Brown'); case '000000': return getGenreByColor('Black'); } - return ''; + return 'nothing'; } - String getGenreByColor(String color){ + + Future<String> getGenreByColor(String color) async { String genre = ''; - FutureBuilder<DocumentSnapshot>( - future: FirebaseFirestore.instance.collection('classification').doc(id).get(), - builder: (BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot){ - genre = snapshot.data![color]; - return const SizedBox(); - }); - return genre; + await FirebaseFirestore.instance.collection('classification').doc(id).get().then((snapshot) async { + genre = await snapshot.data()![color]; + return genre; + }); + return genre; } + } \ No newline at end of file diff --git a/lib/homepage.dart b/lib/homepage.dart index 5968b60a7bf7e9003e9d1dbdab48f63d25722c7c..68f8585d6c8f5ea45b874046c772e96f12dfc4bb 100644 --- a/lib/homepage.dart +++ b/lib/homepage.dart @@ -8,19 +8,18 @@ import 'package:flutter/services.dart'; import 'package:spotify_sdk/models/connection_status.dart'; import 'package:spotify_sdk/models/track.dart'; import 'package:spotify_sdk/spotify_sdk.dart'; -import 'dart:developer' as developer; import 'main.dart'; -void printErr(String msg) { - developer.log(msg); -} - +///After Login/Registration thr routing will bring you to this page +///This page will render the main MusicPlayer class HomePage extends StatelessWidget { final pageController; const HomePage({super.key, this.pageController}); + /// the root of the page will be rendered if the connection status changes or + /// a function emits in the rebuildStream @override Widget build(BuildContext context) { return StreamBuilder<ConnectionStatus>( @@ -38,6 +37,9 @@ class HomePage extends StatelessWidget { ); } + /// builds PlayerStateWidget if the app is connected to Spotify, + /// otherwise it will display a connection button, that will initiate + /// the connection to the local spotify app on click Widget player(BuildContext context) { return Stack(children: [ Center( @@ -82,6 +84,8 @@ class HomePage extends StatelessWidget { ]); } + /// The PlayerStateWidget builds the ControlButtons and the SongInfo, which + /// contains the SongTitle, AlbumTitle and AlbumImage Widget _buildPlayerStateWidget(BuildContext context) { Track? track; if (MusicPlayerState.of(context).playerState == null) { @@ -115,50 +119,10 @@ class HomePage extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ - MusicPlayerState.of(context).connected - ? Center( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - MusicPlayerState.of(context).albumImage != null - ? Padding( - padding: const EdgeInsets.only(top: 30), - child: DropShadowImage( - image: Image( - image: MusicPlayerState.of(context) - .albumImage! - .image, - width: 250, - height: 250, - ), - offset: Offset(10, 10), - scale: 1, - blurRadius: 10, - borderRadius: 20, - ), - ) - : MusicPlayerState.of(context).spotifyImageWidget(), - Container( - alignment: Alignment.topCenter, - padding: const EdgeInsets.all(2), - child: Column(children: [ - Padding( - padding: const EdgeInsets.only(top: 20), - child: Text(track.name, - style: const TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.bold, - color: Colors.black)), - ), - Padding( - padding: const EdgeInsets.only(top: 1), - child: Text(track.album.name), - ), - ])) - ], - ), - ) - : const Text('Connect to see an image...'), + StreamBuilder<void>( + stream: MusicPlayerState.of(context).playStatedStream.stream, + builder: (context, _) => SongInfo(), + ), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[ @@ -168,8 +132,8 @@ class HomePage extends StatelessWidget { padding: EdgeInsets.zero, child: Icon(Icons.skip_previous_outlined)), onPressed: () { - skipPrevious; - MusicPlayerState.of(context).rebuildStream.sink.add(null); + var state = MusicPlayerState.of(context); + SpotifySdk.skipPrevious().then((value) => state.updatePlayerState()); }), StreamBuilder<void>( stream: MusicPlayerState.of(context).playStatedStream.stream, @@ -181,8 +145,8 @@ class HomePage extends StatelessWidget { padding: EdgeInsets.zero, child: Icon(Icons.skip_next_outlined)), onPressed: () { - skipNext(); - MusicPlayerState.of(context).rebuildStream.sink.add(null); + var state = MusicPlayerState.of(context); + SpotifySdk.skipNext().then((value) => state.updatePlayerState()); }), ], ), @@ -253,6 +217,7 @@ class HomePage extends StatelessWidget { } } + Future<void> checkIfAppIsActive(BuildContext context) async { try { @@ -271,9 +236,10 @@ class HomePage extends StatelessWidget { void setStatus(String code, {String? message}) { var text = message ?? ''; - printErr(text); + print(text); } + //build snack bar that can be call for input feedback void buildSnackbar(BuildContext context) { final snackBar = SnackBar( content: Text(MusicPlayerState.of(context).connected @@ -284,6 +250,73 @@ class HomePage extends StatelessWidget { } } +/// renders album image, song and album title +class SongInfo extends StatelessWidget{ + const SongInfo({ + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + Track? track; + if (MusicPlayerState.of(context).playerState == null) { + return const Text("PlayState is Null"); + } else { + track = MusicPlayerState.of(context).playerState!.track; + } + if (MusicPlayerState.of(context).connected && track != null){ + return Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + MusicPlayerState.of(context).albumImage != null + ? Padding( + padding: const EdgeInsets.only(top: 1), + child: DropShadowImage( + image: Image( + image: MusicPlayerState.of(context) + .albumImage! + .image, + width: 300, + height: 300, + ), + offset: const Offset(10, 10), + scale: 1, + blurRadius: 10, + borderRadius: 20, + ), + ) + : MusicPlayerState.of(context).spotifyImageWidget(MusicPlayerState.of(context).currentTrackImageUri!), + Container( + alignment: Alignment.topCenter, + padding: const EdgeInsets.all(2), + child: Column(children: [ + Padding( + padding: const EdgeInsets.only(top: 20), + child: Text(track.name, + style: const TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.bold, + color: Colors.black)), + ), + Padding( + padding: const EdgeInsets.only(top: 1), + child: Text(track.album.name), + ), + ])) + ], + ), + ); + } else { + return const Text('Connect to see an image...'); + } + } + +} + +/// contains the play and pause button +/// on click the the PlayerStateStream will be called and rebuild this buttons +/// and the spotifySdk change the PlayerSate from the local spotify app class ControlButtons extends StatelessWidget { const ControlButtons({ Key? key, diff --git a/lib/loginRegister/login.dart b/lib/loginRegister/login.dart index 11f3f81aca9cca631b5294e4bc6589a8c1684495..d728d04b1d8da57317979b846f301b093271f178 100644 --- a/lib/loginRegister/login.dart +++ b/lib/loginRegister/login.dart @@ -1,14 +1,21 @@ import 'package:ambient/classification/classification.dart'; import 'package:ambient/loginRegister/registration.dart'; import 'package:ambient/loginRegister/widgets.dart'; +import 'package:ambient/widgets/MusicPlayerState.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; import 'package:page_transition/page_transition.dart'; +import 'package:google_fonts/google_fonts.dart'; import '../homepage.dart'; import '../main.dart'; +/* +Klasse zum Einloggen +Die Daten werden aus der Datenbank geholt +Entsprechende Fehlermeldungen werden abgefangen + */ class LoginPage extends StatefulWidget { const LoginPage({Key? key}) : super(key: key); @@ -29,7 +36,7 @@ class _LoginPageState extends State<LoginPage> { return Stack( children: <Widget>[ - Image.asset("assets/ambientL.jpeg", + Image.asset("ambientL.jpeg", alignment: Alignment.centerLeft, height: MediaQuery.of(context).size.height, width: MediaQuery.of(context).size.width,), @@ -47,10 +54,11 @@ class _LoginPageState extends State<LoginPage> { child : Column( children:[ SizedBox(height: 80,), - const Expanded( + Expanded( child: Text( 'Ambient!', - style: TextStyle(fontSize: 50.0, color: Colors.white), + style: GoogleFonts.cabin( + fontSize: 50.0, color: Colors.white,), ),), Expanded( child: Column( @@ -62,9 +70,9 @@ class _LoginPageState extends State<LoginPage> { keyboardType: TextInputType.name, decoration: const InputDecoration( prefixIcon: Icon(Icons.person, color: Colors.white), - hintText: 'Username', + hintText: 'E-Mail', hintStyle: TextStyle(color: Colors.white), - labelText: 'Username', + labelText: 'E-Mail', labelStyle: TextStyle(color: Colors.white), ), ),), @@ -89,15 +97,17 @@ class _LoginPageState extends State<LoginPage> { style: TextStyle(color: Colors.red),) : const SizedBox(), loginRegisterButton(context, true, (){ + //Todo undo comment FirebaseAuth.instance.signInWithEmailAndPassword( email: _emailTextController.text, password: _passwordTextController.text).then((value) { - Navigator.push(context, MaterialPageRoute(builder: (context)=>const HUD())); + Navigator.push(context, MaterialPageRoute(builder: (context)=>const ClassificationPage())); }).onError((error, stackTrace){ setState(() { _wrongInput = true; }); }); + Navigator.push(context, MaterialPageRoute(builder: (context)=>MusicPlayerState(child: const HUD()))); }), registrationPage(), diff --git a/lib/loginRegister/registration.dart b/lib/loginRegister/registration.dart index 9820b239fd0371a35ea386eb22ab034dac437542..71175fe9b6949a86e86fe0d5ce554bb63943ba37 100644 --- a/lib/loginRegister/registration.dart +++ b/lib/loginRegister/registration.dart @@ -4,10 +4,15 @@ import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; import '../classification/classification.dart'; - import 'package:ambient/loginRegister/login.dart'; import 'package:page_transition/page_transition.dart'; +import 'package:google_fonts/google_fonts.dart'; +/* +Klasse zum Registrieren +Die User Daten werden in die Firebase Datenbank gespeichert +Fehlermeldungen beim Registrieren werden abgefangen + */ class RegistrationPage extends StatefulWidget { const RegistrationPage({Key? key}) : super(key: key); @@ -41,19 +46,19 @@ class _RegistrationPage extends State<RegistrationPage> { Scaffold( backgroundColor: Colors.transparent, - body: Center( child :Container( - decoration: const BoxDecoration( + decoration: BoxDecoration( ), child: SizedBox(width: 250, height: 600, child : Column( children:[ SizedBox(height: 40,), - const Expanded( + Expanded( child: Text( 'Ambient!', - style: TextStyle(fontSize: 60.0, color: Colors.white), + style: GoogleFonts.cabin( + fontSize: 50.0, color: Colors.white,) ),), Expanded( @@ -111,25 +116,27 @@ class _RegistrationPage extends State<RegistrationPage> { ), loginRegisterButton(context, false, () { - try{ FirebaseAuth.instance.createUserWithEmailAndPassword( email: _emailTextController.text, password: _passwordTextController.text).then((value){ createSetUp(); print ("Created new account"); Navigator.push(context, MaterialPageRoute(builder: (context)=>ClassificationPage())); - });} - on FirebaseAuthException catch(e){ - if(e.code == 'ERROR_EMAIL_ALREADY_IN_USE'){ + }).onError((error, stackTrace){ + String e = error.toString(); + print('Error 1 ' + error.toString()); + + if(error.toString().contains('email-already-in-use')){ + print("Email already in use"); setState(() { _infoText = 'Email already in use'; }); } - if(e.code == 'weak-password'){ + else if(error.toString().contains('weak-password')){ setState(() { _infoText = 'weak Password'; });} - if(e.code == 'invalid-email'){ + else if(error.toString().contains('invalid-email')){ setState(() { _infoText = 'invalid email'; });} @@ -139,7 +146,7 @@ class _RegistrationPage extends State<RegistrationPage> { }); } - }; + }); }), SizedBox(height: 20), loginPage(), @@ -177,13 +184,10 @@ class _RegistrationPage extends State<RegistrationPage> { ); } - Future addDisplayName() async{ - FirebaseAuth.instance.currentUser?.updateDisplayName(_usernameTextController.text); - } - + //Beim Anlegen eines Accounts werden auch die Farben angelegt, + //damit der User später die Genres zuordnen kann Future createSetUp() async{ - //final String id = '${FirebaseAuth.instance.currentUser?.uid.toString()}_genres'; final String id = (FirebaseAuth.instance.currentUser?.uid.toString())!+'_genres'; final user = FirebaseFirestore.instance.collection('classification').doc(id); @@ -200,6 +204,7 @@ class _RegistrationPage extends State<RegistrationPage> { 'Brown' : null, 'Black' : null, }; + print('set up'); await user.set(json); } } \ No newline at end of file diff --git a/lib/loginRegister/widgets.dart b/lib/loginRegister/widgets.dart index c7e00475e5f9d17cb1ee4d8a5be85ac2d7c4a5a4..64e4db31380ca0bbb906bc24e73bf1225f400743 100644 --- a/lib/loginRegister/widgets.dart +++ b/lib/loginRegister/widgets.dart @@ -3,6 +3,8 @@ import 'package:flutter/material.dart'; import 'login.dart'; +//Widgets für den Login/Registrations Screen + Container loginRegisterButton( BuildContext context, bool isLogin, Function onTap) { return Container( @@ -71,7 +73,6 @@ Container signOutButton( //textWidth height: 10, child: Text( - text, style: const TextStyle( color: Colors.red), diff --git a/lib/main.dart b/lib/main.dart index 1f59c283e2959bf4e8deb86aef7a92f4a93372ba..c0e21e1bdcfd367fe798369dc732b8494b39cd35 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,5 @@ import 'dart:io'; +import 'package:ambient/loginRegister/registration.dart'; import 'package:ambient/searchpage.dart'; import 'package:ambient/widgets/MusicPlayerState.dart'; import 'package:ambient/widgets/navbars.dart'; @@ -6,6 +7,7 @@ import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:google_fonts/google_fonts.dart'; import 'package:spotify_sdk/models/player_state.dart'; import 'package:spotify_sdk/models/track.dart'; import 'package:spotify_sdk/spotify_sdk.dart'; @@ -13,9 +15,11 @@ import 'package:spotify_sdk/spotify_sdk.dart'; import 'homepage.dart'; import 'moodpage.dart'; + Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp; + //loads config file for late usage await dotenv.load(fileName: '.env'); runApp(const MyApp()); } @@ -26,11 +30,14 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( + theme: ThemeData(fontFamily: "GoogleFonts"), debugShowCheckedModeBanner: false, - home: MusicPlayerState( - child: const HUD(), - //Todo change HUD() => RegistrationPage() - ), + home: RegistrationPage(), + /** + * moin + * test123@test.com + * moin + */ ); } } @@ -48,6 +55,9 @@ Moods selectedMoodAsEnum = Moods.sad; bool musicCangable = true; +/// Renders a static Top-/BottomBar +/// further pages will be loaded in the body of the material app +/// and can be switched via PageViewWidget class HUD extends StatefulWidget { const HUD({super.key}); @@ -116,6 +126,8 @@ class _HUDState extends State<HUD> { } } +/// Renders a player control bar above the bottom bar. +/// It contains a the AlbumImage and a button to player/pause the track class MusicBar extends StatelessWidget { MusicBar({ Key? key, @@ -134,12 +146,10 @@ class MusicBar extends StatelessWidget { return const Center( child: Text('PlayState or track is Null'), ); - } else { - MusicPlayerState.of(context).currentTrackImageUri = track!.imageUri; } return Container( height: 80, - color: Colors.grey, + color: primaryContainer, child: Row( children: [ MusicPlayerState.of(context).albumImage!, @@ -153,7 +163,7 @@ class MusicBar extends StatelessWidget { child: Column(children: [ Padding( padding: const EdgeInsets.only(bottom: 5, top: 5), - child: Text(track.name, + child: Text(track!.name, style: const TextStyle( fontSize: 16.0, fontWeight: FontWeight.bold, @@ -187,6 +197,5 @@ Color ligten(Color color, [double amount = .1]) { final hsl = HSLColor.fromColor(color); final hslLight = hsl.withLightness((hsl.lightness + amount).clamp(0.0, 1.0)); - return hslLight.toColor(); } \ No newline at end of file diff --git a/lib/widgets/musicPlayerState.dart b/lib/widgets/musicPlayerState.dart index 31333884def47dae24dcc37d067af44aa281ce30..b44da80747c6903a9a39bb51df086e12f1b2c894 100644 --- a/lib/widgets/musicPlayerState.dart +++ b/lib/widgets/musicPlayerState.dart @@ -7,7 +7,9 @@ import 'package:spotify_sdk/models/image_uri.dart'; import 'package:spotify_sdk/models/player_state.dart'; import 'package:spotify_sdk/spotify_sdk.dart'; - +/// InheritedWidget that holds the state of your MusicPlayer +/// the rebuild stream builds the hole body +/// the playStatedStream only rebuild the Image, SongInfo and the ControlsButtons class MusicPlayerState extends InheritedWidget { MusicPlayerState({super.key, required super.child}); @@ -19,7 +21,6 @@ class MusicPlayerState extends InheritedWidget { late ImageUri? currentTrackImageUri; Image? albumImage; - static MusicPlayerState? maybeOf(BuildContext context) => context.dependOnInheritedWidgetOfExactType<MusicPlayerState>(); @@ -29,19 +30,19 @@ class MusicPlayerState extends InheritedWidget { return result!; } - void setLoading(bool loading){ + void setLoading(bool loading) { this.loading = loading; rebuildStream.sink.add(null); } + /// will be called on PlayStateChange + /// load new Imag e void updatePlayerState() async { playerState = await getPlayerState(); - currentTrackImageUri = playerState?.track?.imageUri; - spotifyImageWidget(); - //rebuildStream.sink.add(null); - playStatedStream.sink.add(null); + loadAlbumImage().then((value) => playStatedStream.sink.add(null)); } + ///disconnect your app from your local spotify app Future<void> disconnect() async { try { setLoading(true); @@ -57,6 +58,10 @@ class MusicPlayerState extends InheritedWidget { } } + /// establish connection to local spotify app + /// connection data will be loaded in main from dotenv.env + /// if connection successful + /// connection will be set to true and loading to false Future<bool> connectToSpotifyRemote() async { try { setLoading(true); @@ -66,7 +71,7 @@ class MusicPlayerState extends InheritedWidget { setStatus(result ? 'connect to spotify successful' : 'connect to spotify failed'); - if(result){ + if (result) { playerState = await getPlayerState(); setLoading(false); } @@ -81,11 +86,10 @@ class MusicPlayerState extends InheritedWidget { return connected; } - Widget spotifyImageWidget() { + Widget spotifyImageWidget(ImageUri imageUri) { return FutureBuilder( future: SpotifySdk.getImage( - - imageUri: currentTrackImageUri!, + imageUri: imageUri, dimension: ImageDimension.large, ), builder: (BuildContext context, AsyncSnapshot<Uint8List?> snapshot) { @@ -111,11 +115,22 @@ class MusicPlayerState extends InheritedWidget { } + ///loads the Album image via spotify.sdk and saves the image in MusicPlayState + ///for global access + Future<void> loadAlbumImage() async { + currentTrackImageUri = playerState?.track?.imageUri; + albumImage = Image.memory((await SpotifySdk.getImage( + imageUri: currentTrackImageUri!, + dimension: ImageDimension.large, + ))!); + } + void setStatus(String code, {String? message}) { var text = message ?? ''; print(text); } + //get PlayState from local spotify app Future<PlayerState?> getPlayerState() async { try { return await SpotifySdk.getPlayerState(); @@ -125,7 +140,7 @@ class MusicPlayerState extends InheritedWidget { setStatus('not implemented'); } } - + @override bool updateShouldNotify(covariant MusicPlayerState oldWidget) { return loading != oldWidget.loading && connected != oldWidget.connected; diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 6683932708b343a842114a6330c73c7f44e49c1a..48668ea0e7f66b8a8e57fcb54c5cdc784c4f3c74 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -10,7 +10,7 @@ import cloud_firestore import firebase_auth import firebase_core import just_audio -import path_provider_macos +import path_provider_foundation func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin")) diff --git a/pubspec.lock b/pubspec.lock index 97bb2f5237bd081a2f782e7f6484b9179bc7a90b..75ef778b5787050f5c8211703aa7a63b7e4e10cd 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -49,7 +49,7 @@ packages: name: cloud_firestore url: "https://pub.dartlang.org" source: hosted - version: "4.3.1" + version: "4.3.0" cloud_firestore_platform_interface: dependency: transitive description: @@ -63,7 +63,7 @@ packages: name: cloud_firestore_web url: "https://pub.dartlang.org" source: hosted - version: "3.2.1" + version: "3.2.0" collection: dependency: transitive description: @@ -84,7 +84,7 @@ packages: name: cross_file url: "https://pub.dartlang.org" source: hosted - version: "0.3.3+2" + version: "0.3.3+4" crypto: dependency: transitive description: @@ -140,28 +140,28 @@ packages: name: file_picker url: "https://pub.dartlang.org" source: hosted - version: "5.2.4" + version: "5.2.5" firebase_auth: dependency: "direct main" description: name: firebase_auth url: "https://pub.dartlang.org" source: hosted - version: "4.2.4" + version: "4.2.3" firebase_auth_platform_interface: dependency: transitive description: name: firebase_auth_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "6.11.7" + version: "6.11.6" firebase_auth_web: dependency: transitive description: name: firebase_auth_web url: "https://pub.dartlang.org" source: hosted - version: "5.2.4" + version: "5.2.3" firebase_core: dependency: "direct main" description: @@ -233,6 +233,13 @@ packages: description: flutter source: sdk version: "0.0.0" + google_fonts: + dependency: "direct main" + description: + name: google_fonts + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.3" google_nav_bar: dependency: "direct main" description: @@ -260,14 +267,14 @@ packages: name: image_picker url: "https://pub.dartlang.org" source: hosted - version: "0.8.6" + version: "0.8.6+1" image_picker_android: dependency: transitive description: name: image_picker_android url: "https://pub.dartlang.org" source: hosted - version: "0.8.5+4" + version: "0.8.5+5" image_picker_for_web: dependency: transitive description: @@ -281,7 +288,7 @@ packages: name: image_picker_ios url: "https://pub.dartlang.org" source: hosted - version: "0.8.6+4" + version: "0.8.6+6" image_picker_platform_interface: dependency: transitive description: @@ -309,7 +316,7 @@ packages: name: json_annotation url: "https://pub.dartlang.org" source: hosted - version: "4.7.0" + version: "4.8.0" just_audio: dependency: "direct main" description: @@ -400,7 +407,7 @@ packages: name: path_provider url: "https://pub.dartlang.org" source: hosted - version: "2.0.11" + version: "2.0.12" path_provider_android: dependency: transitive description: @@ -408,13 +415,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.22" - path_provider_ios: + path_provider_foundation: dependency: transitive description: - name: path_provider_ios + name: path_provider_foundation url: "https://pub.dartlang.org" source: hosted - version: "2.0.11" + version: "2.1.1" path_provider_linux: dependency: transitive description: @@ -422,13 +429,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.7" - path_provider_macos: - dependency: transitive - description: - name: path_provider_macos - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.6" path_provider_platform_interface: dependency: transitive description: @@ -524,7 +524,7 @@ packages: name: synchronized url: "https://pub.dartlang.org" source: hosted - version: "3.0.0+3" + version: "3.0.1" term_glyph: dependency: transitive description: @@ -573,7 +573,7 @@ packages: name: xdg_directories url: "https://pub.dartlang.org" source: hosted - version: "0.2.0+2" + version: "0.2.0+3" sdks: dart: ">=2.18.5 <3.0.0" flutter: ">=3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 37c2862e53014cd8a426a89fba0d207ead48df2c..49f8d232a83c78a33b2f0e064734911e972e0ab3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -51,6 +51,7 @@ dependencies: flutter_dotenv: ^5.0.2 drop_shadow_image: ^0.9.1 flutter_color_models: ^1.3.3+2 + google_fonts: ^2.1.0 dev_dependencies: flutter_test: @@ -81,6 +82,8 @@ flutter: - assets/ambientR.jpeg # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg + - ambientL.jpeg + - ambientR.jpeg # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware