currently playing page + localmusicfetcher fix

This commit is contained in:
Moritz Weber 2020-12-10 20:55:37 +01:00
parent 4139ab801d
commit 4f8cd4b9ee
12 changed files with 172 additions and 85 deletions

View file

@ -1,17 +1,14 @@
import 'dart:ui';
import 'package:audio_service/audio_service.dart'; import 'package:audio_service/audio_service.dart';
import 'package:device_info/device_info.dart';
import 'package:flutter_audio_query/flutter_audio_query.dart'; import 'package:flutter_audio_query/flutter_audio_query.dart';
import 'package:get_it/get_it.dart'; import 'package:get_it/get_it.dart';
import 'package:moor/isolate.dart';
import 'package:moor/moor.dart';
import 'package:mucke/system/audio/audio_handler.dart';
import 'domain/repositories/audio_repository.dart'; import 'domain/repositories/audio_repository.dart';
import 'domain/repositories/music_data_repository.dart'; import 'domain/repositories/music_data_repository.dart';
import 'presentation/state/audio_store.dart'; import 'presentation/state/audio_store.dart';
import 'presentation/state/music_data_store.dart'; import 'presentation/state/music_data_store.dart';
import 'presentation/state/navigation_store.dart'; import 'presentation/state/navigation_store.dart';
import 'system/audio/audio_handler.dart';
import 'system/audio/audio_manager.dart'; import 'system/audio/audio_manager.dart';
import 'system/audio/audio_manager_contract.dart'; import 'system/audio/audio_manager_contract.dart';
import 'system/datasources/local_music_fetcher.dart'; import 'system/datasources/local_music_fetcher.dart';
@ -71,6 +68,7 @@ Future<void> setupGetIt() async {
getIt.registerLazySingleton<LocalMusicFetcher>( getIt.registerLazySingleton<LocalMusicFetcher>(
() => LocalMusicFetcherImpl( () => LocalMusicFetcherImpl(
getIt(), getIt(),
getIt(),
), ),
); );
getIt.registerLazySingleton<AudioManager>(() => AudioManagerImpl(getIt())); getIt.registerLazySingleton<AudioManager>(() => AudioManagerImpl(getIt()));
@ -86,4 +84,6 @@ Future<void> setupGetIt() async {
// external // external
getIt.registerLazySingleton<FlutterAudioQuery>(() => FlutterAudioQuery()); getIt.registerLazySingleton<FlutterAudioQuery>(() => FlutterAudioQuery());
getIt.registerLazySingleton<DeviceInfoPlugin>(() => DeviceInfoPlugin());
} }

View file

@ -12,7 +12,6 @@ import 'presentation/pages/library_page.dart';
import 'presentation/pages/settings_page.dart'; import 'presentation/pages/settings_page.dart';
import 'presentation/state/navigation_store.dart'; import 'presentation/state/navigation_store.dart';
import 'presentation/theming.dart'; import 'presentation/theming.dart';
// import 'presentation/widgets/audio_service_widget.dart';
import 'presentation/widgets/injection_widget.dart'; import 'presentation/widgets/injection_widget.dart';
import 'presentation/widgets/navbar.dart'; import 'presentation/widgets/navbar.dart';

View file

@ -58,26 +58,47 @@ class CurrentlyPlayingPage extends StatelessWidget {
], ],
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
), ),
const Spacer(), const Spacer(
Padding( flex: 1,
padding: const EdgeInsets.symmetric(horizontal: 16.0), ),
child: AlbumArt( Expanded(
song: song, flex: 1000,
child: Center(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 8.0,
vertical: 0.0,
),
child: AlbumArt(
song: song,
),
),
), ),
), ),
const Spacer( const Spacer(
flex: 4, flex: 80,
),
const Padding(
padding: EdgeInsets.only(left: 2.0, right: 2.0, bottom: 10.0),
child: SongCustomizationButtons(),
), ),
const SongCustomizationButtons(),
const Spacer( const Spacer(
flex: 3, flex: 50,
),
const Padding(
padding: EdgeInsets.symmetric(horizontal: 16.0),
child: TimeProgressIndicator(),
), ),
const TimeProgressIndicator(),
const Spacer( const Spacer(
flex: 3, flex: 50,
),
const Padding(
padding: EdgeInsets.symmetric(horizontal: 2.0),
child: PlaybackControl(),
),
const Spacer(
flex: 40,
), ),
const PlaybackControl(),
const Spacer(),
NextIndicator( NextIndicator(
onTapAction: openQueue, onTapAction: openQueue,
), ),

View file

@ -22,9 +22,13 @@ class AlbumArt extends StatelessWidget {
), ),
child: Stack( child: Stack(
children: [ children: [
Image( Container(
image: getAlbumImage(song.albumArtPath), width: double.infinity,
fit: BoxFit.cover, height: double.infinity,
child: Image(
image: getAlbumImage(song.albumArtPath),
fit: BoxFit.cover,
),
), ),
Positioned( Positioned(
bottom: 0, bottom: 0,
@ -63,7 +67,6 @@ class AlbumArt extends StatelessWidget {
song.artist, song.artist,
style: TEXT_SUBTITLE.copyWith(color: Colors.white70), style: TEXT_SUBTITLE.copyWith(color: Colors.white70),
), ),
], ],
), ),
), ),

View file

@ -22,11 +22,34 @@ class AlbumBackground extends StatelessWidget {
fit: BoxFit.cover, fit: BoxFit.cover,
), ),
), ),
child: BackdropFilter( child: Container(
filter: ImageFilter.blur(sigmaX: 64.0, sigmaY: 64.0), height: double.infinity,
child: Container( decoration: const BoxDecoration(
child: child, gradient: LinearGradient(
color: Colors.black.withOpacity(0.2), begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color(0x55000000),
Color(0x22FFFFFF),
Color(0x22FFFFFF),
Color(0x88000000),
Color(0xBB000000),
],
stops: [
0.0,
0.1,
0.5,
0.65,
1.0,
],
),
),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 96.0, sigmaY: 96.0),
child: Container(
child: child,
color: Colors.white.withOpacity(0.0),
),
), ),
), ),
); );

View file

@ -22,7 +22,7 @@ class NextIndicator extends StatelessWidget {
return GestureDetector( return GestureDetector(
onTap: () => onTapAction(context), onTap: () => onTapAction(context),
child: Padding( child: Padding(
padding: const EdgeInsets.all(10.0), padding: const EdgeInsets.only(top: 4.0, bottom: 8.0),
child: Center( child: Center(
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,

View file

@ -10,30 +10,27 @@ class PlaybackControl extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Padding( return Row(
padding: const EdgeInsets.symmetric(horizontal: 16.0), children: const [
child: Row( IconButton(
children: const [ icon: Icon(
IconButton( Icons.repeat,
icon: Icon( size: 20.0,
Icons.repeat, color: Colors.white10,
size: 20.0,
color: Colors.white10,
),
onPressed: null,
), ),
PreviousButton(iconSize: 32.0), onPressed: null,
PlayPauseButton( ),
circle: true, PreviousButton(iconSize: 32.0),
iconSize: 52.0, PlayPauseButton(
), circle: true,
NextButton(iconSize: 32.0), iconSize: 52.0,
ShuffleButton( ),
iconSize: 20.0, NextButton(iconSize: 32.0),
), ShuffleButton(
], iconSize: 20.0,
mainAxisAlignment: MainAxisAlignment.spaceBetween, ),
), ],
mainAxisAlignment: MainAxisAlignment.spaceBetween,
); );
} }
} }

View file

@ -25,14 +25,13 @@ class SongCustomizationButtons extends StatelessWidget {
IconButton( IconButton(
icon: Icon( icon: Icon(
Icons.link, Icons.link,
size: 20.0, // size: 20.0,
color: song.next == null ? Colors.white70 : LIGHT1, color: song.next == null ? Colors.white70 : LIGHT1,
), ),
iconSize: 20.0,
onPressed: () => musicDataStore.toggleNextSongLink(song), onPressed: () => musicDataStore.toggleNextSongLink(song),
), ),
Container( const Spacer(),
width: 40,
),
const IconButton( const IconButton(
icon: Icon( icon: Icon(
Icons.favorite, Icons.favorite,
@ -41,17 +40,14 @@ class SongCustomizationButtons extends StatelessWidget {
), ),
onPressed: null, onPressed: null,
), ),
Container( const Spacer(),
width: 40,
),
IconButton( IconButton(
icon: Icon( icon: Icon(
Icons.remove_circle_outline, Icons.remove_circle_outline,
size: 20.0, size: 20.0,
color: isBlocked ? RASPBERRY : Colors.white70, color: isBlocked ? RASPBERRY : Colors.white70,
), ),
onPressed: () => onPressed: () => musicDataStore.setSongBlocked(song, !isBlocked),
musicDataStore.setSongBlocked(song, !isBlocked),
), ),
], ],
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,

View file

@ -16,27 +16,44 @@ class TimeProgressIndicator extends StatelessWidget {
builder: (BuildContext context) { builder: (BuildContext context) {
final int duration = audioStore.currentSong?.duration ?? 1000; final int duration = audioStore.currentSong?.duration ?? 1000;
return Padding( return Row(
padding: const EdgeInsets.symmetric(horizontal: 16.0), children: [
child: Row( Container(
children: [ width: 48,
Text(msToTimeString(audioStore.currentPositionStream.value)), child: Text(
Container( msToTimeString(audioStore.currentPositionStream.value),
width: 10,
), ),
Expanded( ),
child: Container( Expanded(
child: LinearProgressIndicator(value: audioStore.currentPositionStream.value / duration), child: Container(
height: 3.0, width: double.infinity,
height: 3.0,
decoration: const BoxDecoration(
color: Colors.white10,
borderRadius: BorderRadius.all(Radius.circular(2)),
),
alignment: Alignment.centerLeft,
child: FractionallySizedBox(
widthFactor:
audioStore.currentPositionStream.value / duration,
heightFactor: 1.0,
child: Container(
height: double.infinity,
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(2)),
),
),
), ),
), ),
Container( ),
width: 10, Container(
), width: 48,
Text(msToTimeString(duration)), alignment: Alignment.centerRight,
], child: Text(msToTimeString(duration)),
mainAxisAlignment: MainAxisAlignment.spaceEvenly, ),
), ],
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
); );
}, },
); );

View file

@ -1,6 +1,7 @@
import 'dart:typed_data'; import 'dart:typed_data';
import 'dart:ui'; import 'dart:ui';
import 'package:device_info/device_info.dart';
import 'package:flutter_audio_query/flutter_audio_query.dart'; import 'package:flutter_audio_query/flutter_audio_query.dart';
import '../models/album_model.dart'; import '../models/album_model.dart';
@ -9,14 +10,22 @@ import '../models/song_model.dart';
import 'local_music_fetcher_contract.dart'; import 'local_music_fetcher_contract.dart';
class LocalMusicFetcherImpl implements LocalMusicFetcher { class LocalMusicFetcherImpl implements LocalMusicFetcher {
LocalMusicFetcherImpl(this.flutterAudioQuery); LocalMusicFetcherImpl(this._flutterAudioQuery, this._deviceInfo);
final FlutterAudioQuery flutterAudioQuery; final FlutterAudioQuery _flutterAudioQuery;
// CODESMELL: should probably encapsulate the deviceinfoplugin
final DeviceInfoPlugin _deviceInfo;
AndroidDeviceInfo _androidDeviceInfo;
Future<AndroidDeviceInfo> get androidDeviceInfo async {
_androidDeviceInfo ??= await _deviceInfo.androidInfo;
return _androidDeviceInfo;
}
@override @override
Future<List<ArtistModel>> getArtists() async { Future<List<ArtistModel>> getArtists() async {
final List<ArtistInfo> artistInfoList = final List<ArtistInfo> artistInfoList =
await flutterAudioQuery.getArtists(); await _flutterAudioQuery.getArtists();
return artistInfoList return artistInfoList
.map((ArtistInfo artistInfo) => ArtistModel.fromArtistInfo(artistInfo)) .map((ArtistInfo artistInfo) => ArtistModel.fromArtistInfo(artistInfo))
.toSet() .toSet()
@ -25,7 +34,7 @@ class LocalMusicFetcherImpl implements LocalMusicFetcher {
@override @override
Future<List<AlbumModel>> getAlbums() async { Future<List<AlbumModel>> getAlbums() async {
final List<AlbumInfo> albumInfoList = await flutterAudioQuery.getAlbums(); final List<AlbumInfo> albumInfoList = await _flutterAudioQuery.getAlbums();
return albumInfoList return albumInfoList
.map((AlbumInfo albumInfo) => AlbumModel.fromAlbumInfo(albumInfo)) .map((AlbumInfo albumInfo) => AlbumModel.fromAlbumInfo(albumInfo))
.toList(); .toList();
@ -33,7 +42,7 @@ class LocalMusicFetcherImpl implements LocalMusicFetcher {
@override @override
Future<List<SongModel>> getSongs() async { Future<List<SongModel>> getSongs() async {
final List<SongInfo> songInfoList = await flutterAudioQuery.getSongs(); final List<SongInfo> songInfoList = await _flutterAudioQuery.getSongs();
return songInfoList return songInfoList
.where((songInfo) => songInfo.isMusic) .where((songInfo) => songInfo.isMusic)
.map((SongInfo songInfo) => SongModel.fromSongInfo(songInfo)) .map((SongInfo songInfo) => SongModel.fromSongInfo(songInfo))
@ -42,7 +51,14 @@ class LocalMusicFetcherImpl implements LocalMusicFetcher {
@override @override
Future<Uint8List> getAlbumArtwork(int id) async { Future<Uint8List> getAlbumArtwork(int id) async {
return flutterAudioQuery.getArtwork( final info = await androidDeviceInfo;
type: ResourceType.ALBUM, id: id.toString(), size: const Size(500.0, 500.0)); if (info.version.sdkInt >= 29) {
return _flutterAudioQuery.getArtwork(
type: ResourceType.ALBUM,
id: id.toString(),
size: const Size(500.0, 500.0),
);
}
return Uint8List(0);
} }
} }

View file

@ -199,6 +199,20 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.9.2" version: "0.9.2"
device_info:
dependency: "direct main"
description:
name: device_info
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
device_info_platform_interface:
dependency: transitive
description:
name: device_info_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
equatable: equatable:
dependency: "direct main" dependency: "direct main"
description: description:

View file

@ -14,6 +14,7 @@ dependencies:
ref: one-isolate ref: one-isolate
audio_session: ^0.0.3 audio_session: ^0.0.3
dartz: ^0.9.1 dartz: ^0.9.1
device_info: ^1.0.0
equatable: ^1.1.0 equatable: ^1.1.0
flutter: flutter:
sdk: flutter sdk: flutter