draft freshen up albums page

This commit is contained in:
Frieder Hannenheim 2024-05-13 00:07:17 +02:00
parent a750a52e2e
commit cb2aadc658
5 changed files with 261 additions and 58 deletions

View file

@ -1,12 +1,16 @@
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:get_it/get_it.dart';
import 'package:mobx/mobx.dart';
import 'package:mobx/mobx.dart' as mobx;
import 'package:mucke/presentation/widgets/album_art_grid.dart';
import 'package:mucke/presentation/widgets/album_art_list.dart';
import '../../domain/entities/album.dart';
import '../state/music_data_store.dart';
import '../state/navigation_store.dart';
import '../widgets/album_art_list_tile.dart';
import 'album_details_page.dart';
class AlbumsPage extends StatefulWidget {
const AlbumsPage({Key? key}) : super(key: key);
@ -15,8 +19,11 @@ class AlbumsPage extends StatefulWidget {
_AlbumsPageState createState() => _AlbumsPageState();
}
class _AlbumsPageState extends State<AlbumsPage> with AutomaticKeepAliveClientMixin {
final ScrollController _scrollController = ScrollController();
class _AlbumsPageState extends State<AlbumsPage>
with AutomaticKeepAliveClientMixin {
final ScrollController scrollController = ScrollController();
final Observable<bool> showAlbumGrid = Observable(false);
final Observable<String> sortingMode = Observable('name');
@override
Widget build(BuildContext context) {
@ -28,33 +35,54 @@ class _AlbumsPageState extends State<AlbumsPage> with AutomaticKeepAliveClientMi
return Observer(builder: (_) {
print('AlbumsPage.build -> Observer.builder');
final List<Album> albums = store.albumStream.value ?? [];
return Scrollbar(
controller: _scrollController,
child: ListView.separated(
controller: _scrollController,
itemCount: albums.length,
itemBuilder: (_, int index) {
final Album album = albums[index];
return AlbumArtListTile(
title: album.title,
subtitle: album.artist,
albumArtPath: album.albumArtPath,
onTap: () {
navStore.push(
context,
MaterialPageRoute<Widget>(
builder: (BuildContext context) => AlbumDetailsPage(
album: album,
),
),
);
switch (sortingMode.value) {
case 'name':
break;
case 'artistName':
albums.sort((a,b) => a.artist.compareTo(b.artist));
break;
case 'random':
albums.shuffle(Random());
break;
}
return CustomScrollView(
slivers: [
SliverAppBar(
floating: true,
leading: IconButton(
onPressed: () {
showAlbumGrid.toggle();
},
);
},
separatorBuilder: (BuildContext context, int index) => const SizedBox(
height: 4.0,
icon: Icon(showAlbumGrid.value ? Icons.list : Icons.grid_view),
),
actions: [
DropdownButton(
value: sortingMode.value,
items: const [
DropdownMenuItem(value: 'name', child: Text('name')),
DropdownMenuItem(value: 'artistName', child: Text('artistName')),
DropdownMenuItem(value: 'random', child: Text('random')),
],
onChanged: (selectedValue) {
if (selectedValue != null)
mobx.Action(() {
sortingMode.value = selectedValue;
})();
},
)
],
),
),
if (showAlbumGrid.value)
AlbumArtGrid(
albums: albums,
scrollController: scrollController,
navStore: navStore)
else
AlbumArtList(
albums: albums,
scrollController: scrollController,
navStore: navStore),
],
);
});
}

View file

@ -0,0 +1,45 @@
import 'package:flutter/material.dart';
import 'package:mucke/presentation/pages/album_details_page.dart';
import 'package:mucke/presentation/state/navigation_store.dart';
import 'package:mucke/presentation/widgets/album_art_grid_tile.dart';
import '../../domain/entities/album.dart';
class AlbumArtGrid extends StatelessWidget {
const AlbumArtGrid({
Key? key,
required this.albums,
required this.scrollController,
required this.navStore,
}) : super(key: key);
final List<Album> albums;
final ScrollController scrollController;
final NavigationStore navStore;
@override
Widget build(BuildContext context) {
return SliverGrid.builder(
itemCount: albums.length,
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemBuilder: (_, int index) {
final Album album = albums[index];
return AlbumArtGridTile(
title: album.title,
subtitle: album.artist,
albumArtPath: album.albumArtPath,
onTap: () {
navStore.push(
context,
MaterialPageRoute<Widget>(
builder: (BuildContext context) => AlbumDetailsPage(
album: album,
),
),
);
});
},
);
}
}

View file

@ -0,0 +1,69 @@
import 'package:flutter/material.dart';
import '../theming.dart';
import '../utils.dart' as utils;
class AlbumArtGridTile extends StatelessWidget {
const AlbumArtGridTile({
Key? key,
required this.title,
required this.subtitle,
required this.onTap,
this.albumArtPath,
this.highlight = false,
}) : super(key: key);
final String title;
final String subtitle;
final String? albumArtPath;
final Function onTap;
final bool highlight;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => onTap(),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 0, horizontal: 20),
child: Column(
children: [
SizedBox(
width: 128,
height: 128,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4.0),
boxShadow: const [
BoxShadow(
color: Colors.black54,
blurRadius: 8,
offset: Offset(0, 2),
),
],
),
clipBehavior: Clip.antiAlias,
child: Image(
image: utils.getAlbumImage(albumArtPath),
fit: BoxFit.cover,
),
),
),
const Padding(padding: EdgeInsets.symmetric(vertical: 3, horizontal: 0)),
Text(
title,
style: const TextStyle(fontWeight: FontWeight.bold),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
Text(
subtitle,
style: TEXT_SMALL_SUBTITLE.copyWith(color: Colors.white),
maxLines: 1,
overflow: TextOverflow.ellipsis,
)
],
),
),
);
}
}

View file

@ -0,0 +1,37 @@
import 'package:flutter/material.dart';
import 'package:mucke/presentation/state/navigation_store.dart';
import '../../domain/entities/album.dart';
import 'album_art_list_tile.dart';
class AlbumArtList extends StatelessWidget {
const AlbumArtList({
Key? key,
required this.albums,
required this.scrollController,
required this.navStore,
}) : super(key: key);
final List<Album> albums;
final ScrollController scrollController;
final NavigationStore navStore;
@override
Widget build(BuildContext context) {
return SliverList.separated(
itemCount: albums.length,
itemBuilder: (_, int index) {
final Album album = albums[index];
return AlbumArtListTile(
title: album.title,
subtitle: album.artist,
albumArtPath: album.albumArtPath,
onTap: () {},
);
},
separatorBuilder: (BuildContext context, int index) => const SizedBox(
height: 4.0,
),
);
}
}

View file

@ -229,10 +229,10 @@ packages:
dependency: "direct main"
description:
name: collection
sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c"
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
url: "https://pub.dev"
source: hosted
version: "1.17.1"
version: "1.18.0"
convert:
dependency: transitive
description:
@ -245,10 +245,10 @@ packages:
dependency: transitive
description:
name: coverage
sha256: "2fb815080e44a09b85e0f2ca8a820b15053982b2e714b59267719e8a9ff17097"
sha256: "3945034e86ea203af7a056d98e98e42a5518fff200d6e8e6647e1886b07e936e"
url: "https://pub.dev"
source: hosted
version: "1.6.3"
version: "1.8.0"
cross_file:
dependency: transitive
description:
@ -505,10 +505,10 @@ packages:
dependency: "direct main"
description:
name: intl
sha256: a3715e3bc90294e971cb7dc063fbf3cd9ee0ebf8604ffeafabd9e6f16abbdbe6
sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
url: "https://pub.dev"
source: hosted
version: "0.18.0"
version: "0.18.1"
io:
dependency: transitive
description:
@ -557,6 +557,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.4.8"
leak_tracker:
dependency: transitive
description:
name: leak_tracker
sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa"
url: "https://pub.dev"
source: hosted
version: "10.0.0"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0
url: "https://pub.dev"
source: hosted
version: "2.0.1"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47
url: "https://pub.dev"
source: hosted
version: "2.0.1"
logging:
dependency: transitive
description:
@ -569,26 +593,26 @@ packages:
dependency: transitive
description:
name: matcher
sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb"
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
url: "https://pub.dev"
source: hosted
version: "0.12.15"
version: "0.12.16+1"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
url: "https://pub.dev"
source: hosted
version: "0.2.0"
version: "0.8.0"
meta:
dependency: transitive
description:
name: meta
sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
url: "https://pub.dev"
source: hosted
version: "1.9.1"
version: "1.11.0"
metadata_god:
dependency: "direct main"
description:
@ -690,10 +714,10 @@ packages:
dependency: "direct main"
description:
name: path
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
url: "https://pub.dev"
source: hosted
version: "1.8.3"
version: "1.9.0"
path_provider:
dependency: "direct main"
description:
@ -959,10 +983,10 @@ packages:
dependency: transitive
description:
name: source_span
sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://pub.dev"
source: hosted
version: "1.9.1"
version: "1.10.0"
sqflite:
dependency: transitive
description:
@ -1007,18 +1031,18 @@ packages:
dependency: transitive
description:
name: stack_trace
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
url: "https://pub.dev"
source: hosted
version: "1.11.0"
version: "1.11.1"
stream_channel:
dependency: transitive
description:
name: stream_channel
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
url: "https://pub.dev"
source: hosted
version: "2.1.1"
version: "2.1.2"
stream_transform:
dependency: transitive
description:
@ -1063,26 +1087,26 @@ packages:
dependency: "direct dev"
description:
name: test
sha256: "3dac9aecf2c3991d09b9cdde4f98ded7b30804a88a0d7e4e7e1678e78d6b97f4"
sha256: a1f7595805820fcc05e5c52e3a231aedd0b72972cb333e8c738a8b1239448b6f
url: "https://pub.dev"
source: hosted
version: "1.24.1"
version: "1.24.9"
test_api:
dependency: transitive
description:
name: test_api
sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
url: "https://pub.dev"
source: hosted
version: "0.5.1"
version: "0.6.1"
test_core:
dependency: transitive
description:
name: test_core
sha256: "5138dbffb77b2289ecb12b81c11ba46036590b72a64a7a90d6ffb880f1a29e93"
sha256: a757b14fc47507060a162cc2530d9a4a2f92f5100a952c7443b5cad5ef5b106a
url: "https://pub.dev"
source: hosted
version: "0.5.1"
version: "0.5.9"
text_scroll:
dependency: "direct main"
description:
@ -1167,10 +1191,10 @@ packages:
dependency: transitive
description:
name: vm_service
sha256: c538be99af830f478718b51630ec1b6bee5e74e52c8a802d328d9e71d35d2583
sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957
url: "https://pub.dev"
source: hosted
version: "11.10.0"
version: "13.0.0"
watcher:
dependency: transitive
description:
@ -1236,5 +1260,5 @@ packages:
source: hosted
version: "3.1.2"
sdks:
dart: ">=3.0.0 <4.0.0"
dart: ">=3.2.0-0 <4.0.0"
flutter: ">=3.7.0"