finished artist migration; icon for highlight
This commit is contained in:
parent
8e4ef48180
commit
a3f335db71
10 changed files with 77 additions and 254 deletions
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||
|
||||
import '../theming.dart';
|
||||
import '../widgets/highlight.dart';
|
||||
import '../widgets/highlight_artist.dart';
|
||||
import '../widgets/shuffle_all_button.dart';
|
||||
import '../widgets/smart_lists.dart';
|
||||
|
||||
|
@ -35,6 +36,11 @@ class _HomePageState extends State<HomePage> {
|
|||
padding: EdgeInsets.symmetric(horizontal: HORIZONTAL_PADDING),
|
||||
child: Highlight(),
|
||||
),
|
||||
const SizedBox(height: 12.0),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: HORIZONTAL_PADDING),
|
||||
child: HighlightArtist(),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: HORIZONTAL_PADDING,
|
||||
|
|
|
@ -3,11 +3,15 @@ import 'package:flutter_mobx/flutter_mobx.dart';
|
|||
import 'package:get_it/get_it.dart';
|
||||
|
||||
import '../../domain/entities/artist.dart';
|
||||
import '../../domain/entities/shuffle_mode.dart';
|
||||
import '../gradients.dart';
|
||||
import '../pages/artist_details_page.dart';
|
||||
import '../state/audio_store.dart';
|
||||
import '../state/music_data_store.dart';
|
||||
import '../state/navigation_store.dart';
|
||||
import '../theming.dart';
|
||||
import 'play_shuffle_button.dart';
|
||||
import 'playlist_cover.dart';
|
||||
|
||||
class HighlightArtist extends StatelessWidget {
|
||||
const HighlightArtist({Key? key}) : super(key: key);
|
||||
|
@ -50,24 +54,11 @@ class HighlightArtist extends StatelessWidget {
|
|||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: SizedBox(
|
||||
width: 100.0,
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1,
|
||||
child: Container(
|
||||
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,
|
||||
// ),
|
||||
),
|
||||
),
|
||||
child: PlaylistCover(
|
||||
gradient: CUSTOM_GRADIENTS['kashmir']!,
|
||||
icon: Icons.person_rounded,
|
||||
size: 100.0,
|
||||
circle: true,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
|
@ -93,15 +84,12 @@ class HighlightArtist extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
Icons.play_circle_fill_rounded,
|
||||
size: 48.0,
|
||||
),
|
||||
iconSize: 48.0,
|
||||
onPressed: () => {}, //audioStore.playArtist(artist),
|
||||
splashRadius: 28.0,
|
||||
PlayShuffleButton(
|
||||
onPressed: () => audioStore.shuffleArtist(artist),
|
||||
size: 56.0,
|
||||
shuffleMode: ShuffleMode.plus,
|
||||
),
|
||||
const SizedBox(width: 4.0),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -12,6 +12,7 @@ class PlayShuffleButton extends StatelessWidget {
|
|||
this.shuffleMode,
|
||||
}) : super(key: key);
|
||||
|
||||
/// Main icon size will be reduced by 8.
|
||||
final double size;
|
||||
final ShuffleMode? shuffleMode;
|
||||
final Function onPressed;
|
||||
|
|
|
@ -7,15 +7,33 @@ class PlaylistCover extends StatelessWidget {
|
|||
required this.gradient,
|
||||
required this.icon,
|
||||
this.shadows = const <BoxShadow>[],
|
||||
this.circle = false,
|
||||
}) : super(key: key);
|
||||
|
||||
final double size;
|
||||
final Gradient gradient;
|
||||
final IconData icon;
|
||||
final List<BoxShadow> shadows;
|
||||
final bool circle;
|
||||
|
||||
@override
|
||||
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(
|
||||
width: size,
|
||||
height: size,
|
||||
|
@ -27,11 +45,7 @@ class PlaylistCover extends StatelessWidget {
|
|||
size: size / 2.0,
|
||||
),
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
gradient: gradient,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(8.0)),
|
||||
boxShadow: shadows,
|
||||
),
|
||||
decoration: deco,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import '../music_data_source_contract.dart';
|
|||
part 'music_data_dao.g.dart';
|
||||
|
||||
@DriftAccessor(
|
||||
tables: [Albums, Artists, Songs, MoorAlbumOfDay, Playlists, PlaylistEntries, KeyValueEntries])
|
||||
tables: [Albums, Artists, Songs, Playlists, PlaylistEntries, KeyValueEntries])
|
||||
class MusicDataDao extends DatabaseAccessor<MoorDatabase>
|
||||
with _$MusicDataDaoMixin
|
||||
implements MusicDataSource {
|
||||
|
@ -189,33 +189,36 @@ class MusicDataDao extends DatabaseAccessor<MoorDatabase>
|
|||
|
||||
@override
|
||||
Future<AlbumOfDay?> getAlbumOfDay() async {
|
||||
final query = select(moorAlbumOfDay)
|
||||
.join([innerJoin(albums, albums.id.equalsExp(moorAlbumOfDay.albumId))]);
|
||||
final value = await (select(keyValueEntries)..where((tbl) => tbl.key.equals(ALBUM_OF_DAY)))
|
||||
.getSingleOrNull()
|
||||
.then((entry) => entry?.value);
|
||||
|
||||
return (query..limit(1)).getSingleOrNull().then(
|
||||
(result) {
|
||||
if (result == null) return null;
|
||||
return AlbumOfDay(
|
||||
AlbumModel.fromMoor(result.readTable(albums)),
|
||||
DateTime.fromMillisecondsSinceEpoch(
|
||||
result.readTable(moorAlbumOfDay).milliSecSinceEpoch,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final dict = jsonDecode(value) as Map;
|
||||
|
||||
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
|
||||
Future<void> setAlbumOfDay(AlbumOfDay albumOfDay) async {
|
||||
transaction(() async {
|
||||
await delete(moorAlbumOfDay).go();
|
||||
await into(moorAlbumOfDay).insert(
|
||||
MoorAlbumOfDayCompanion(
|
||||
albumId: Value(albumOfDay.albumModel.id),
|
||||
milliSecSinceEpoch: Value(albumOfDay.date.millisecondsSinceEpoch),
|
||||
),
|
||||
);
|
||||
});
|
||||
await into(keyValueEntries).insertOnConflictUpdate(
|
||||
KeyValueEntriesCompanion(
|
||||
key: const Value(ALBUM_OF_DAY),
|
||||
value: Value(albumOfDay.toJSON()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -228,11 +231,12 @@ class MusicDataDao extends DatabaseAccessor<MoorDatabase>
|
|||
return null;
|
||||
}
|
||||
|
||||
final dict = jsonDecode(value);
|
||||
final String name = dict['name'] as String;
|
||||
final dict = jsonDecode(value) as Map;
|
||||
|
||||
final int id = dict['id'] 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()
|
||||
.then((value) => value == null ? null : ArtistModel.fromMoor(value));
|
||||
|
||||
|
@ -246,7 +250,7 @@ class MusicDataDao extends DatabaseAccessor<MoorDatabase>
|
|||
await into(keyValueEntries).insertOnConflictUpdate(
|
||||
KeyValueEntriesCompanion(
|
||||
key: const Value(ARTIST_OF_DAY),
|
||||
value: Value(artistOfDay.toString()),
|
||||
value: Value(artistOfDay.toJSON()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ mixin _$MusicDataDaoMixin on DatabaseAccessor<MoorDatabase> {
|
|||
$AlbumsTable get albums => attachedDatabase.albums;
|
||||
$ArtistsTable get artists => attachedDatabase.artists;
|
||||
$SongsTable get songs => attachedDatabase.songs;
|
||||
$MoorAlbumOfDayTable get moorAlbumOfDay => attachedDatabase.moorAlbumOfDay;
|
||||
$PlaylistsTable get playlists => attachedDatabase.playlists;
|
||||
$PlaylistEntriesTable get playlistEntries => attachedDatabase.playlistEntries;
|
||||
$KeyValueEntriesTable get keyValueEntries => attachedDatabase.keyValueEntries;
|
||||
|
|
|
@ -104,14 +104,6 @@ class LibraryFolders extends Table {
|
|||
TextColumn get path => text()();
|
||||
}
|
||||
|
||||
class MoorAlbumOfDay extends Table {
|
||||
IntColumn get albumId => integer()();
|
||||
IntColumn get milliSecSinceEpoch => integer()();
|
||||
|
||||
@override
|
||||
Set<Column> get primaryKey => {albumId};
|
||||
}
|
||||
|
||||
@DataClassName('MoorSmartList')
|
||||
class SmartLists extends Table {
|
||||
IntColumn get id => integer().autoIncrement()();
|
||||
|
@ -168,7 +160,6 @@ class PlaylistEntries extends Table {
|
|||
QueueEntries,
|
||||
AvailableSongEntries,
|
||||
Songs,
|
||||
MoorAlbumOfDay,
|
||||
SmartLists,
|
||||
SmartListArtists,
|
||||
Playlists,
|
||||
|
@ -254,7 +245,6 @@ class MoorDatabase extends _$MoorDatabase {
|
|||
await m.alterTable(TableMigration(playlists));
|
||||
}
|
||||
if (from < 7) {
|
||||
await m.addColumn(artists, artists.id);
|
||||
await m.alterTable(
|
||||
TableMigration(artists, columnTransformer: {
|
||||
artists.id: artists.rowId,
|
||||
|
|
|
@ -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> {
|
||||
final int id;
|
||||
final String name;
|
||||
|
@ -3884,7 +3704,6 @@ abstract class _$MoorDatabase extends GeneratedDatabase {
|
|||
late final $AvailableSongEntriesTable availableSongEntries =
|
||||
$AvailableSongEntriesTable(this);
|
||||
late final $SongsTable songs = $SongsTable(this);
|
||||
late final $MoorAlbumOfDayTable moorAlbumOfDay = $MoorAlbumOfDayTable(this);
|
||||
late final $SmartListsTable smartLists = $SmartListsTable(this);
|
||||
late final $SmartListArtistsTable smartListArtists =
|
||||
$SmartListArtistsTable(this);
|
||||
|
@ -3908,7 +3727,6 @@ abstract class _$MoorDatabase extends GeneratedDatabase {
|
|||
queueEntries,
|
||||
availableSongEntries,
|
||||
songs,
|
||||
moorAlbumOfDay,
|
||||
smartLists,
|
||||
smartListArtists,
|
||||
playlists,
|
||||
|
|
|
@ -79,4 +79,8 @@ class AlbumOfDay {
|
|||
|
||||
final AlbumModel albumModel;
|
||||
final DateTime date;
|
||||
|
||||
String toJSON() {
|
||||
return '{"id": ${albumModel.id}, "date": ${date.millisecondsSinceEpoch}}';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,8 +34,7 @@ class ArtistOfDay {
|
|||
final ArtistModel artistModel;
|
||||
final DateTime date;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return '{"name": "${artistModel.name}", "date": ${date.millisecondsSinceEpoch}}';
|
||||
String toJSON() {
|
||||
return '{"id": ${artistModel.id}, "date": ${date.millisecondsSinceEpoch}}';
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue