diff --git a/lib/presentation/pages/currently_playing.dart b/lib/presentation/pages/currently_playing.dart index a937576..e92965c 100644 --- a/lib/presentation/pages/currently_playing.dart +++ b/lib/presentation/pages/currently_playing.dart @@ -6,6 +6,7 @@ import 'package:provider/provider.dart'; import '../../domain/entities/song.dart'; import '../state/audio_store.dart'; import '../widgets/album_art.dart'; +import '../widgets/album_background.dart'; import '../widgets/next_indicator.dart'; import '../widgets/playback_control.dart'; import '../widgets/song_customization_buttons.dart'; @@ -31,54 +32,57 @@ class CurrentlyPlayingPage extends StatelessWidget { _log.info('Observer.build'); final Song song = audioStore.currentSong; - return Padding( - padding: const EdgeInsets.only( - left: 12.0, - right: 12.0, - top: 8.0, - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - IconButton( - icon: const Icon(Icons.expand_more), - onPressed: () { - Navigator.pop(context); - }, - ), - IconButton( - icon: const Icon(Icons.more_vert), - onPressed: () {}, - ) - ], - mainAxisAlignment: MainAxisAlignment.spaceBetween, - ), - const Spacer(), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: AlbumArt( - song: song, + return AlbumBackground( + song: song, + child: Padding( + padding: const EdgeInsets.only( + left: 12.0, + right: 12.0, + top: 8.0, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + IconButton( + icon: const Icon(Icons.expand_more), + onPressed: () { + Navigator.pop(context); + }, + ), + IconButton( + icon: const Icon(Icons.more_vert), + onPressed: () {}, + ) + ], + mainAxisAlignment: MainAxisAlignment.spaceBetween, ), - ), - const Spacer( - flex: 4, - ), - const SongCustomizationButtons(), - const Spacer( - flex: 3, - ), - const TimeProgressIndicator(), - const Spacer( - flex: 3, - ), - const PlaybackControl(), - const Spacer(), - NextIndicator( - onTapAction: openQueue, - ), - ], + const Spacer(), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: AlbumArt( + song: song, + ), + ), + const Spacer( + flex: 4, + ), + const SongCustomizationButtons(), + const Spacer( + flex: 3, + ), + const TimeProgressIndicator(), + const Spacer( + flex: 3, + ), + const PlaybackControl(), + const Spacer(), + NextIndicator( + onTapAction: openQueue, + ), + ], + ), ), ); }, diff --git a/lib/presentation/pages/home_page.dart b/lib/presentation/pages/home_page.dart index 3a4cd98..32932f8 100644 --- a/lib/presentation/pages/home_page.dart +++ b/lib/presentation/pages/home_page.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; +import '../widgets/header.dart'; import '../widgets/highlight.dart'; import '../widgets/shuffle_all_button.dart'; @@ -15,14 +16,18 @@ class _HomePageState extends State { Widget build(BuildContext context) { print('HomePage.build'); return SafeArea( - child: Column( - children: [ - const Highlight(), - const ShuffleAllButton( - verticalPad: 10.0, - horizontalPad: 12.0, - ), - ], + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 20.0), + child: Column( + children: [ + const Header(), + const Highlight(), + const ShuffleAllButton( + verticalPad: 10.0, + horizontalPad: 0.0, + ), + ], + ), ), ); } diff --git a/lib/presentation/state/navigation_store.dart b/lib/presentation/state/navigation_store.dart index b90e4b0..d8b99b3 100644 --- a/lib/presentation/state/navigation_store.dart +++ b/lib/presentation/state/navigation_store.dart @@ -9,7 +9,7 @@ class NavigationStore extends _NavigationStore with _$NavigationStore { abstract class _NavigationStore with Store { _NavigationStore(); - @observable int navIndex = 1; + @observable int navIndex = 0; @action void setNavIndex(int i) { diff --git a/lib/presentation/theming.dart b/lib/presentation/theming.dart index 4d8507d..800614f 100644 --- a/lib/presentation/theming.dart +++ b/lib/presentation/theming.dart @@ -23,11 +23,31 @@ ThemeData theme() => ThemeData( scaffoldBackgroundColor: DARK2, // https://api.flutter.dev/flutter/material/TextTheme-class.html textTheme: const TextTheme( - headline1: TextStyle(fontSize: 28.0, fontWeight: FontWeight.w900, color: LIGHT1), - headline2: TextStyle(fontSize: 24.0, fontWeight: FontWeight.w900, color: Colors.white), - headline3: TextStyle(fontSize: 20.0, fontWeight: FontWeight.w900, color: Colors.white), - headline4: TextStyle(fontSize: 18.0, fontWeight: FontWeight.w600, color: Colors.white), - headline5: TextStyle(fontSize: 18.0, fontWeight: FontWeight.w400, color: Colors.white70), + headline1: TextStyle( + fontSize: 28.0, + fontWeight: FontWeight.w900, + color: LIGHT1, + ), + headline2: TextStyle( + fontSize: 24.0, + fontWeight: FontWeight.w900, + color: Colors.white, + ), + headline3: TextStyle( + fontSize: 20.0, + fontWeight: FontWeight.w900, + color: Colors.white, + ), + headline4: TextStyle( + fontSize: 18.0, + fontWeight: FontWeight.w600, + color: Colors.white, + ), + headline5: TextStyle( + fontSize: 18.0, + fontWeight: FontWeight.w400, + color: Colors.white70, + ), headline6: TextStyle(fontSize: 18.0), ), tabBarTheme: const TabBarTheme( @@ -38,3 +58,28 @@ ThemeData theme() => ThemeData( ), cardColor: DARK3, ); + +const TextStyle TEXT_HEADER = TextStyle( + fontSize: 18.0, + fontWeight: FontWeight.bold, +); + +const TextStyle TEXT_BIG = TextStyle( + fontSize: 22.0, + fontWeight: FontWeight.bold, +); + +const TextStyle TEXT_SUBTITLE = TextStyle( + fontSize: 18.0, + fontWeight: FontWeight.w300, +); + +const TextStyle TEXT_SMALL_HEADLINE = TextStyle( + fontSize: 12.0, + fontWeight: FontWeight.normal, +); + +const TextStyle TEXT_SMALL_SUBTITLE = TextStyle( + fontSize: 12.0, + fontWeight: FontWeight.w300, +); \ No newline at end of file diff --git a/lib/presentation/widgets/album_art.dart b/lib/presentation/widgets/album_art.dart index 613c94c..27f26c4 100644 --- a/lib/presentation/widgets/album_art.dart +++ b/lib/presentation/widgets/album_art.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:mucke/presentation/theming.dart'; import '../../domain/entities/song.dart'; import '../utils.dart'; @@ -13,7 +14,7 @@ class AlbumArt extends StatelessWidget { return AspectRatio( aspectRatio: 1.0, child: Card( - elevation: 2.0, + elevation: 6.0, clipBehavior: Clip.antiAlias, margin: const EdgeInsets.all(0), shape: RoundedRectangleBorder( @@ -29,22 +30,18 @@ class AlbumArt extends StatelessWidget { bottom: 0, left: 0, right: 0, - height: 250, + height: 140, child: Container( decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ - Color(0x00555555), - Color(0x77333333), - Color(0xCC111111), - Color(0xEE000000) + Color(0x00000000), + Color(0xCC000000) ], stops: [ 0.0, - 0.6, - 0.8, 1.0 ]), ), @@ -60,24 +57,13 @@ class AlbumArt extends StatelessWidget { children: [ Text( song.title, - style: Theme.of(context).textTheme.headline6, - ), - Container( - height: 4.0, + style: TEXT_BIG, ), Text( song.artist, - style: const TextStyle( - color: Colors.white70, - ), - ), - Text( - song.album, - style: const TextStyle( - fontWeight: FontWeight.w300, - color: Colors.white70, - ), + style: TEXT_SUBTITLE.copyWith(color: Colors.white70), ), + ], ), ), diff --git a/lib/presentation/widgets/album_background.dart b/lib/presentation/widgets/album_background.dart new file mode 100644 index 0000000..fa11776 --- /dev/null +++ b/lib/presentation/widgets/album_background.dart @@ -0,0 +1,34 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; + +import '../../domain/entities/song.dart'; +import '../utils.dart'; + +class AlbumBackground extends StatelessWidget { + const AlbumBackground({Key key, this.child, this.song}) : super(key: key); + + final Widget child; + final Song song; + + @override + Widget build(BuildContext context) { + return Container( + width: double.infinity, + height: double.infinity, + decoration: BoxDecoration( + image: DecorationImage( + image: getAlbumImage(song.albumArtPath), + fit: BoxFit.cover, + ), + ), + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 64.0, sigmaY: 64.0), + child: Container( + child: child, + color: Colors.black.withOpacity(0.2), + ), + ), + ); + } +} diff --git a/lib/presentation/widgets/header.dart b/lib/presentation/widgets/header.dart new file mode 100644 index 0000000..3018673 --- /dev/null +++ b/lib/presentation/widgets/header.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; +import 'package:mucke/presentation/theming.dart'; + +class Header extends StatelessWidget { + const Header({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Row( + children: const [ + Text('Home', style: TEXT_HEADER), + IconButton( + icon: Icon(Icons.more_vert), + onPressed: null, + ), + ], + mainAxisAlignment: MainAxisAlignment.spaceBetween, + ); + } +} diff --git a/lib/presentation/widgets/highlight.dart b/lib/presentation/widgets/highlight.dart index 8e818b6..8c8aae9 100644 --- a/lib/presentation/widgets/highlight.dart +++ b/lib/presentation/widgets/highlight.dart @@ -1,95 +1,79 @@ import 'package:flutter/material.dart'; +import '../theming.dart'; + class Highlight extends StatelessWidget { const Highlight({Key key}) : super(key: key); @override Widget build(BuildContext context) { return Container( - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 10.0, - horizontal: 12.0, - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only(bottom: 6.0), - child: Text( - 'Album of the Day', - style: Theme.of(context).textTheme.headline3, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + flex: 10, + child: AspectRatio( + aspectRatio: 1, + child: Card( + elevation: 2.0, + clipBehavior: Clip.antiAlias, + margin: const EdgeInsets.all(0), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0), + ), + child: const Image( + image: AssetImage('assets/no_cover.png'), + fit: BoxFit.cover, + ), + ), + ), ), - ), - Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Expanded( - flex: 1, - child: AspectRatio( - aspectRatio: 1, - child: Card( - elevation: 2.0, - clipBehavior: Clip.antiAlias, - margin: const EdgeInsets.all(0), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(6.0), + Expanded( + flex: 23, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Album of the Day'.toUpperCase(), + style: TEXT_SMALL_HEADLINE, ), - child: const Image( - image: AssetImage('assets/no_cover.png'), - fit: BoxFit.cover, + Container(height: 6.0), + Text( + 'All Our Gods Have Abandoned Us', + style: Theme.of(context).textTheme.headline4, + maxLines: 2, + overflow: TextOverflow.ellipsis, ), - ), + Text( + 'Architects', + style: TEXT_SMALL_SUBTITLE, + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + ], ), ), - Expanded( - flex: 2, - child: AspectRatio( - aspectRatio: 2 / 1, - child: Padding( - padding: const EdgeInsets.only( - left: 8.0, right: 8.0, top: 0.0, bottom: 1.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - mainAxisSize: MainAxisSize.max, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'All Our Gods Have Abandoned Us', - style: Theme.of(context).textTheme.headline4, - maxLines: 2, - overflow: TextOverflow.ellipsis - ), - Text( - 'Architects', - style: Theme.of(context).textTheme.headline5, - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - const Spacer(), - Container( - height: 36.0, - child: OutlineButton.icon( - onPressed: () {}, - icon: const Icon(Icons.play_arrow), - label: const Text('PLAY'), - borderSide: BorderSide( - color: Theme.of(context).accentColor), - padding: const EdgeInsets.all(0), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(6.0), - ), - ), - ), - ], - ), - ), - ), + ), + IconButton( + padding: EdgeInsets.zero, + icon: Icon( + Icons.play_circle_fill_rounded, + size: 48.0, ), - ], - ) - ], - ), + iconSize: 48.0, + onPressed: () {}, + ), + ], + ) + ], ), ); } diff --git a/lib/presentation/widgets/shuffle_all_button.dart b/lib/presentation/widgets/shuffle_all_button.dart index 91cb10e..a6bf8e8 100644 --- a/lib/presentation/widgets/shuffle_all_button.dart +++ b/lib/presentation/widgets/shuffle_all_button.dart @@ -27,7 +27,7 @@ class ShuffleAllButton extends StatelessWidget { color: Theme.of(context).accentColor, highlightColor: Theme.of(context).highlightColor, shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(6.0), + borderRadius: BorderRadius.circular(24.0), ), ), ),