finished artist migration; icon for highlight

This commit is contained in:
Moritz Weber 2022-09-16 20:45:55 +02:00
parent 8e4ef48180
commit a3f335db71
10 changed files with 77 additions and 254 deletions

View file

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import '../theming.dart'; import '../theming.dart';
import '../widgets/highlight.dart'; import '../widgets/highlight.dart';
import '../widgets/highlight_artist.dart';
import '../widgets/shuffle_all_button.dart'; import '../widgets/shuffle_all_button.dart';
import '../widgets/smart_lists.dart'; import '../widgets/smart_lists.dart';
@ -35,6 +36,11 @@ class _HomePageState extends State<HomePage> {
padding: EdgeInsets.symmetric(horizontal: HORIZONTAL_PADDING), padding: EdgeInsets.symmetric(horizontal: HORIZONTAL_PADDING),
child: Highlight(), child: Highlight(),
), ),
const SizedBox(height: 12.0),
const Padding(
padding: EdgeInsets.symmetric(horizontal: HORIZONTAL_PADDING),
child: HighlightArtist(),
),
const Padding( const Padding(
padding: EdgeInsets.only( padding: EdgeInsets.only(
left: HORIZONTAL_PADDING, left: HORIZONTAL_PADDING,

View file

@ -3,11 +3,15 @@ import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:get_it/get_it.dart'; import 'package:get_it/get_it.dart';
import '../../domain/entities/artist.dart'; import '../../domain/entities/artist.dart';
import '../../domain/entities/shuffle_mode.dart';
import '../gradients.dart';
import '../pages/artist_details_page.dart'; import '../pages/artist_details_page.dart';
import '../state/audio_store.dart'; import '../state/audio_store.dart';
import '../state/music_data_store.dart'; import '../state/music_data_store.dart';
import '../state/navigation_store.dart'; import '../state/navigation_store.dart';
import '../theming.dart'; import '../theming.dart';
import 'play_shuffle_button.dart';
import 'playlist_cover.dart';
class HighlightArtist extends StatelessWidget { class HighlightArtist extends StatelessWidget {
const HighlightArtist({Key? key}) : super(key: key); const HighlightArtist({Key? key}) : super(key: key);
@ -50,24 +54,11 @@ class HighlightArtist extends StatelessWidget {
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: SizedBox( child: PlaylistCover(
width: 100.0, gradient: CUSTOM_GRADIENTS['kashmir']!,
child: AspectRatio( icon: Icons.person_rounded,
aspectRatio: 1, size: 100.0,
child: Container( circle: true,
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(2.0),
boxShadow: const [
BoxShadow(color: Colors.black54, blurRadius: 4, offset: Offset(0, 0), spreadRadius: -1),
],
),
// child: Image(
// image: getAlbumImage(artist.albumArtPath),
// fit: BoxFit.cover,
// ),
),
),
), ),
), ),
Expanded( Expanded(
@ -93,15 +84,12 @@ class HighlightArtist extends StatelessWidget {
), ),
), ),
), ),
IconButton( PlayShuffleButton(
icon: const Icon( onPressed: () => audioStore.shuffleArtist(artist),
Icons.play_circle_fill_rounded, size: 56.0,
size: 48.0, shuffleMode: ShuffleMode.plus,
),
iconSize: 48.0,
onPressed: () => {}, //audioStore.playArtist(artist),
splashRadius: 28.0,
), ),
const SizedBox(width: 4.0),
], ],
), ),
), ),

View file

@ -12,6 +12,7 @@ class PlayShuffleButton extends StatelessWidget {
this.shuffleMode, this.shuffleMode,
}) : super(key: key); }) : super(key: key);
/// Main icon size will be reduced by 8.
final double size; final double size;
final ShuffleMode? shuffleMode; final ShuffleMode? shuffleMode;
final Function onPressed; final Function onPressed;

View file

@ -7,15 +7,33 @@ class PlaylistCover extends StatelessWidget {
required this.gradient, required this.gradient,
required this.icon, required this.icon,
this.shadows = const <BoxShadow>[], this.shadows = const <BoxShadow>[],
this.circle = false,
}) : super(key: key); }) : super(key: key);
final double size; final double size;
final Gradient gradient; final Gradient gradient;
final IconData icon; final IconData icon;
final List<BoxShadow> shadows; final List<BoxShadow> shadows;
final bool circle;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
BoxDecoration deco;
if (circle) {
deco = BoxDecoration(
gradient: gradient,
shape: BoxShape.circle,
boxShadow: shadows,
);
} else {
deco = BoxDecoration(
gradient: gradient,
borderRadius: const BorderRadius.all(Radius.circular(8.0)),
boxShadow: shadows,
);
}
return SizedBox( return SizedBox(
width: size, width: size,
height: size, height: size,
@ -27,11 +45,7 @@ class PlaylistCover extends StatelessWidget {
size: size / 2.0, size: size / 2.0,
), ),
), ),
decoration: BoxDecoration( decoration: deco,
gradient: gradient,
borderRadius: const BorderRadius.all(Radius.circular(8.0)),
boxShadow: shadows,
),
), ),
); );
} }

View file

@ -13,7 +13,7 @@ import '../music_data_source_contract.dart';
part 'music_data_dao.g.dart'; part 'music_data_dao.g.dart';
@DriftAccessor( @DriftAccessor(
tables: [Albums, Artists, Songs, MoorAlbumOfDay, Playlists, PlaylistEntries, KeyValueEntries]) tables: [Albums, Artists, Songs, Playlists, PlaylistEntries, KeyValueEntries])
class MusicDataDao extends DatabaseAccessor<MoorDatabase> class MusicDataDao extends DatabaseAccessor<MoorDatabase>
with _$MusicDataDaoMixin with _$MusicDataDaoMixin
implements MusicDataSource { implements MusicDataSource {
@ -189,33 +189,36 @@ class MusicDataDao extends DatabaseAccessor<MoorDatabase>
@override @override
Future<AlbumOfDay?> getAlbumOfDay() async { Future<AlbumOfDay?> getAlbumOfDay() async {
final query = select(moorAlbumOfDay) final value = await (select(keyValueEntries)..where((tbl) => tbl.key.equals(ALBUM_OF_DAY)))
.join([innerJoin(albums, albums.id.equalsExp(moorAlbumOfDay.albumId))]); .getSingleOrNull()
.then((entry) => entry?.value);
return (query..limit(1)).getSingleOrNull().then( if (value == null) {
(result) { return null;
if (result == null) return null; }
return AlbumOfDay(
AlbumModel.fromMoor(result.readTable(albums)), final dict = jsonDecode(value) as Map;
DateTime.fromMillisecondsSinceEpoch(
result.readTable(moorAlbumOfDay).milliSecSinceEpoch, final int id = dict['id'] as int;
), final int millisecondsSinceEpoch = dict['date'] as int;
);
}, final AlbumModel? album = await (select(albums)..where((tbl) => tbl.id.equals(id)))
); .getSingleOrNull()
.then((value) => value == null ? null : AlbumModel.fromMoor(value));
if (album == null) return null;
return AlbumOfDay(album, DateTime.fromMillisecondsSinceEpoch(millisecondsSinceEpoch));
} }
@override @override
Future<void> setAlbumOfDay(AlbumOfDay albumOfDay) async { Future<void> setAlbumOfDay(AlbumOfDay albumOfDay) async {
transaction(() async { await into(keyValueEntries).insertOnConflictUpdate(
await delete(moorAlbumOfDay).go(); KeyValueEntriesCompanion(
await into(moorAlbumOfDay).insert( key: const Value(ALBUM_OF_DAY),
MoorAlbumOfDayCompanion( value: Value(albumOfDay.toJSON()),
albumId: Value(albumOfDay.albumModel.id), ),
milliSecSinceEpoch: Value(albumOfDay.date.millisecondsSinceEpoch), );
),
);
});
} }
@override @override
@ -228,11 +231,12 @@ class MusicDataDao extends DatabaseAccessor<MoorDatabase>
return null; return null;
} }
final dict = jsonDecode(value); final dict = jsonDecode(value) as Map;
final String name = dict['name'] as String;
final int id = dict['id'] as int;
final int millisecondsSinceEpoch = dict['date'] as int; final int millisecondsSinceEpoch = dict['date'] as int;
final ArtistModel? artist = await (select(artists)..where((tbl) => tbl.name.equals(name))) final ArtistModel? artist = await (select(artists)..where((tbl) => tbl.id.equals(id)))
.getSingleOrNull() .getSingleOrNull()
.then((value) => value == null ? null : ArtistModel.fromMoor(value)); .then((value) => value == null ? null : ArtistModel.fromMoor(value));
@ -246,7 +250,7 @@ class MusicDataDao extends DatabaseAccessor<MoorDatabase>
await into(keyValueEntries).insertOnConflictUpdate( await into(keyValueEntries).insertOnConflictUpdate(
KeyValueEntriesCompanion( KeyValueEntriesCompanion(
key: const Value(ARTIST_OF_DAY), key: const Value(ARTIST_OF_DAY),
value: Value(artistOfDay.toString()), value: Value(artistOfDay.toJSON()),
), ),
); );
} }

View file

@ -10,7 +10,6 @@ mixin _$MusicDataDaoMixin on DatabaseAccessor<MoorDatabase> {
$AlbumsTable get albums => attachedDatabase.albums; $AlbumsTable get albums => attachedDatabase.albums;
$ArtistsTable get artists => attachedDatabase.artists; $ArtistsTable get artists => attachedDatabase.artists;
$SongsTable get songs => attachedDatabase.songs; $SongsTable get songs => attachedDatabase.songs;
$MoorAlbumOfDayTable get moorAlbumOfDay => attachedDatabase.moorAlbumOfDay;
$PlaylistsTable get playlists => attachedDatabase.playlists; $PlaylistsTable get playlists => attachedDatabase.playlists;
$PlaylistEntriesTable get playlistEntries => attachedDatabase.playlistEntries; $PlaylistEntriesTable get playlistEntries => attachedDatabase.playlistEntries;
$KeyValueEntriesTable get keyValueEntries => attachedDatabase.keyValueEntries; $KeyValueEntriesTable get keyValueEntries => attachedDatabase.keyValueEntries;

View file

@ -104,14 +104,6 @@ class LibraryFolders extends Table {
TextColumn get path => text()(); TextColumn get path => text()();
} }
class MoorAlbumOfDay extends Table {
IntColumn get albumId => integer()();
IntColumn get milliSecSinceEpoch => integer()();
@override
Set<Column> get primaryKey => {albumId};
}
@DataClassName('MoorSmartList') @DataClassName('MoorSmartList')
class SmartLists extends Table { class SmartLists extends Table {
IntColumn get id => integer().autoIncrement()(); IntColumn get id => integer().autoIncrement()();
@ -168,7 +160,6 @@ class PlaylistEntries extends Table {
QueueEntries, QueueEntries,
AvailableSongEntries, AvailableSongEntries,
Songs, Songs,
MoorAlbumOfDay,
SmartLists, SmartLists,
SmartListArtists, SmartListArtists,
Playlists, Playlists,
@ -254,7 +245,6 @@ class MoorDatabase extends _$MoorDatabase {
await m.alterTable(TableMigration(playlists)); await m.alterTable(TableMigration(playlists));
} }
if (from < 7) { if (from < 7) {
await m.addColumn(artists, artists.id);
await m.alterTable( await m.alterTable(
TableMigration(artists, columnTransformer: { TableMigration(artists, columnTransformer: {
artists.id: artists.rowId, artists.id: artists.rowId,

View file

@ -2018,186 +2018,6 @@ class $SongsTable extends Songs with TableInfo<$SongsTable, MoorSong> {
} }
} }
class MoorAlbumOfDayData extends DataClass
implements Insertable<MoorAlbumOfDayData> {
final int albumId;
final int milliSecSinceEpoch;
MoorAlbumOfDayData({required this.albumId, required this.milliSecSinceEpoch});
factory MoorAlbumOfDayData.fromData(Map<String, dynamic> data,
{String? prefix}) {
final effectivePrefix = prefix ?? '';
return MoorAlbumOfDayData(
albumId: const IntType()
.mapFromDatabaseResponse(data['${effectivePrefix}album_id'])!,
milliSecSinceEpoch: const IntType().mapFromDatabaseResponse(
data['${effectivePrefix}milli_sec_since_epoch'])!,
);
}
@override
Map<String, Expression> toColumns(bool nullToAbsent) {
final map = <String, Expression>{};
map['album_id'] = Variable<int>(albumId);
map['milli_sec_since_epoch'] = Variable<int>(milliSecSinceEpoch);
return map;
}
MoorAlbumOfDayCompanion toCompanion(bool nullToAbsent) {
return MoorAlbumOfDayCompanion(
albumId: Value(albumId),
milliSecSinceEpoch: Value(milliSecSinceEpoch),
);
}
factory MoorAlbumOfDayData.fromJson(Map<String, dynamic> json,
{ValueSerializer? serializer}) {
serializer ??= driftRuntimeOptions.defaultSerializer;
return MoorAlbumOfDayData(
albumId: serializer.fromJson<int>(json['albumId']),
milliSecSinceEpoch: serializer.fromJson<int>(json['milliSecSinceEpoch']),
);
}
@override
Map<String, dynamic> toJson({ValueSerializer? serializer}) {
serializer ??= driftRuntimeOptions.defaultSerializer;
return <String, dynamic>{
'albumId': serializer.toJson<int>(albumId),
'milliSecSinceEpoch': serializer.toJson<int>(milliSecSinceEpoch),
};
}
MoorAlbumOfDayData copyWith({int? albumId, int? milliSecSinceEpoch}) =>
MoorAlbumOfDayData(
albumId: albumId ?? this.albumId,
milliSecSinceEpoch: milliSecSinceEpoch ?? this.milliSecSinceEpoch,
);
@override
String toString() {
return (StringBuffer('MoorAlbumOfDayData(')
..write('albumId: $albumId, ')
..write('milliSecSinceEpoch: $milliSecSinceEpoch')
..write(')'))
.toString();
}
@override
int get hashCode => Object.hash(albumId, milliSecSinceEpoch);
@override
bool operator ==(Object other) =>
identical(this, other) ||
(other is MoorAlbumOfDayData &&
other.albumId == this.albumId &&
other.milliSecSinceEpoch == this.milliSecSinceEpoch);
}
class MoorAlbumOfDayCompanion extends UpdateCompanion<MoorAlbumOfDayData> {
final Value<int> albumId;
final Value<int> milliSecSinceEpoch;
const MoorAlbumOfDayCompanion({
this.albumId = const Value.absent(),
this.milliSecSinceEpoch = const Value.absent(),
});
MoorAlbumOfDayCompanion.insert({
this.albumId = const Value.absent(),
required int milliSecSinceEpoch,
}) : milliSecSinceEpoch = Value(milliSecSinceEpoch);
static Insertable<MoorAlbumOfDayData> custom({
Expression<int>? albumId,
Expression<int>? milliSecSinceEpoch,
}) {
return RawValuesInsertable({
if (albumId != null) 'album_id': albumId,
if (milliSecSinceEpoch != null)
'milli_sec_since_epoch': milliSecSinceEpoch,
});
}
MoorAlbumOfDayCompanion copyWith(
{Value<int>? albumId, Value<int>? milliSecSinceEpoch}) {
return MoorAlbumOfDayCompanion(
albumId: albumId ?? this.albumId,
milliSecSinceEpoch: milliSecSinceEpoch ?? this.milliSecSinceEpoch,
);
}
@override
Map<String, Expression> toColumns(bool nullToAbsent) {
final map = <String, Expression>{};
if (albumId.present) {
map['album_id'] = Variable<int>(albumId.value);
}
if (milliSecSinceEpoch.present) {
map['milli_sec_since_epoch'] = Variable<int>(milliSecSinceEpoch.value);
}
return map;
}
@override
String toString() {
return (StringBuffer('MoorAlbumOfDayCompanion(')
..write('albumId: $albumId, ')
..write('milliSecSinceEpoch: $milliSecSinceEpoch')
..write(')'))
.toString();
}
}
class $MoorAlbumOfDayTable extends MoorAlbumOfDay
with TableInfo<$MoorAlbumOfDayTable, MoorAlbumOfDayData> {
@override
final GeneratedDatabase attachedDatabase;
final String? _alias;
$MoorAlbumOfDayTable(this.attachedDatabase, [this._alias]);
final VerificationMeta _albumIdMeta = const VerificationMeta('albumId');
@override
late final GeneratedColumn<int?> albumId = GeneratedColumn<int?>(
'album_id', aliasedName, false,
type: const IntType(), requiredDuringInsert: false);
final VerificationMeta _milliSecSinceEpochMeta =
const VerificationMeta('milliSecSinceEpoch');
@override
late final GeneratedColumn<int?> milliSecSinceEpoch = GeneratedColumn<int?>(
'milli_sec_since_epoch', aliasedName, false,
type: const IntType(), requiredDuringInsert: true);
@override
List<GeneratedColumn> get $columns => [albumId, milliSecSinceEpoch];
@override
String get aliasedName => _alias ?? 'moor_album_of_day';
@override
String get actualTableName => 'moor_album_of_day';
@override
VerificationContext validateIntegrity(Insertable<MoorAlbumOfDayData> instance,
{bool isInserting = false}) {
final context = VerificationContext();
final data = instance.toColumns(true);
if (data.containsKey('album_id')) {
context.handle(_albumIdMeta,
albumId.isAcceptableOrUnknown(data['album_id']!, _albumIdMeta));
}
if (data.containsKey('milli_sec_since_epoch')) {
context.handle(
_milliSecSinceEpochMeta,
milliSecSinceEpoch.isAcceptableOrUnknown(
data['milli_sec_since_epoch']!, _milliSecSinceEpochMeta));
} else if (isInserting) {
context.missing(_milliSecSinceEpochMeta);
}
return context;
}
@override
Set<GeneratedColumn> get $primaryKey => {albumId};
@override
MoorAlbumOfDayData map(Map<String, dynamic> data, {String? tablePrefix}) {
return MoorAlbumOfDayData.fromData(data,
prefix: tablePrefix != null ? '$tablePrefix.' : null);
}
@override
$MoorAlbumOfDayTable createAlias(String alias) {
return $MoorAlbumOfDayTable(attachedDatabase, alias);
}
}
class MoorSmartList extends DataClass implements Insertable<MoorSmartList> { class MoorSmartList extends DataClass implements Insertable<MoorSmartList> {
final int id; final int id;
final String name; final String name;
@ -3884,7 +3704,6 @@ abstract class _$MoorDatabase extends GeneratedDatabase {
late final $AvailableSongEntriesTable availableSongEntries = late final $AvailableSongEntriesTable availableSongEntries =
$AvailableSongEntriesTable(this); $AvailableSongEntriesTable(this);
late final $SongsTable songs = $SongsTable(this); late final $SongsTable songs = $SongsTable(this);
late final $MoorAlbumOfDayTable moorAlbumOfDay = $MoorAlbumOfDayTable(this);
late final $SmartListsTable smartLists = $SmartListsTable(this); late final $SmartListsTable smartLists = $SmartListsTable(this);
late final $SmartListArtistsTable smartListArtists = late final $SmartListArtistsTable smartListArtists =
$SmartListArtistsTable(this); $SmartListArtistsTable(this);
@ -3908,7 +3727,6 @@ abstract class _$MoorDatabase extends GeneratedDatabase {
queueEntries, queueEntries,
availableSongEntries, availableSongEntries,
songs, songs,
moorAlbumOfDay,
smartLists, smartLists,
smartListArtists, smartListArtists,
playlists, playlists,

View file

@ -79,4 +79,8 @@ class AlbumOfDay {
final AlbumModel albumModel; final AlbumModel albumModel;
final DateTime date; final DateTime date;
String toJSON() {
return '{"id": ${albumModel.id}, "date": ${date.millisecondsSinceEpoch}}';
}
} }

View file

@ -34,8 +34,7 @@ class ArtistOfDay {
final ArtistModel artistModel; final ArtistModel artistModel;
final DateTime date; final DateTime date;
@override String toJSON() {
String toString() { return '{"id": ${artistModel.id}, "date": ${date.millisecondsSinceEpoch}}';
return '{"name": "${artistModel.name}", "date": ${date.millisecondsSinceEpoch}}';
} }
} }