added artists to library and ui

This commit is contained in:
Moritz Weber 2020-08-08 19:02:03 +02:00
parent e09c83c09d
commit f8a7136472
19 changed files with 502 additions and 115 deletions

View file

@ -1,7 +1,7 @@
import 'package:equatable/equatable.dart';
class Artist extends Equatable {
const Artist(this.name);
const Artist({this.name});
final String name;

View file

@ -2,11 +2,13 @@ import 'package:dartz/dartz.dart';
import '../../core/error/failures.dart';
import '../entities/album.dart';
import '../entities/artist.dart';
import '../entities/song.dart';
abstract class MusicDataRepository {
Future<Either<Failure, List<Song>>> getSongs();
Future<Either<Failure, List<Song>>> getSongsFromAlbum(Album album);
Future<Either<Failure, List<Album>>> getAlbums();
Future<Either<Failure, List<Artist>>> getArtists();
Future<void> updateDatabase();
}

View file

@ -0,0 +1,55 @@
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:provider/provider.dart';
import '../../domain/entities/artist.dart';
import '../state/music_data_store.dart';
class ArtistsPage extends StatefulWidget {
const ArtistsPage({Key key}) : super(key: key);
@override
_ArtistsPageState createState() => _ArtistsPageState();
}
class _ArtistsPageState extends State<ArtistsPage>
with AutomaticKeepAliveClientMixin {
@override
Widget build(BuildContext context) {
print('ArtistsPage.build');
final MusicDataStore musicDataStore = Provider.of<MusicDataStore>(context);
super.build(context);
return Observer(builder: (_) {
print('ArtistsPage.build -> Observer.builder');
final bool isFetching = musicDataStore.isFetchingArtists;
if (isFetching) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const <Widget>[
CircularProgressIndicator(),
Text('Loading items...'),
],
);
} else {
final List<Artist> artists = musicDataStore.artists;
return ListView.separated(
itemCount: artists.length,
itemBuilder: (_, int index) {
final Artist artist = artists[index];
return ListTile(
title: Text(artist.name),
);
},
separatorBuilder: (BuildContext context, int index) => const Divider(
height: 4.0,
),
);
}
});
}
@override
bool get wantKeepAlive => true;
}

View file

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'albums_page.dart';
import 'artists_page.dart';
import 'songs_page.dart';
class LibraryTabContainer extends StatelessWidget {
@ -32,8 +33,8 @@ class LibraryTabContainer extends StatelessWidget {
const Expanded(
child: TabBarView(
children: <Widget>[
Center(
child: Text('Artists'),
ArtistsPage(
key: PageStorageKey('ArtistsPage'),
),
AlbumsPage(
key: PageStorageKey('AlbumsPage'),

View file

@ -16,8 +16,8 @@ class SettingsPage extends StatelessWidget {
Container(
height: 12.0,
),
Padding(
padding: const EdgeInsets.symmetric(
const Padding(
padding: EdgeInsets.symmetric(
horizontal: 16.0,
vertical: 4.0,
),
@ -32,13 +32,15 @@ class SettingsPage extends StatelessWidget {
ListTile(
title: const Text('Update library'),
subtitle: Observer(builder: (_) {
final bool isFetchingArtists = store.isFetchingArtists;
final bool isFetchingAlbums = store.isFetchingAlbums;
final bool isFetchingSongs = store.isFetchingSongs;
if (!isFetchingAlbums && !isFetchingSongs) {
if (!isFetchingArtists && !isFetchingAlbums && !isFetchingSongs) {
final int artistCount = store.artists.length;
final int albumCount = store.albums.length;
final int songCount = store.songs.length;
return Text('XX artists, $albumCount albums, $songCount songs');
return Text('$artistCount artists, $albumCount albums, $songCount songs');
}
return const Text('');
}),

View file

@ -6,7 +6,7 @@ part of 'audio_store.dart';
// StoreGenerator
// **************************************************************************
// ignore_for_file: non_constant_identifier_names, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic
// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic
mixin _$AudioStore on _AudioStore, Store {
final _$currentSongAtom = Atom(name: '_AudioStore.currentSong');

View file

@ -2,6 +2,7 @@ import 'package:meta/meta.dart';
import 'package:mobx/mobx.dart';
import '../../domain/entities/album.dart';
import '../../domain/entities/artist.dart';
import '../../domain/entities/song.dart';
import '../../domain/repositories/music_data_repository.dart';
@ -19,6 +20,11 @@ abstract class _MusicDataStore with Store {
bool _initialized = false;
@observable
ObservableList<Artist> artists = <Artist>[].asObservable();
@observable
bool isFetchingArtists = false;
@observable
ObservableList<Album> albums = <Album>[].asObservable();
@observable
@ -39,6 +45,7 @@ abstract class _MusicDataStore with Store {
void init() {
if (!_initialized) {
print('MusicDataStore.init');
fetchArtists();
fetchAlbums();
fetchSongs();
@ -57,6 +64,22 @@ abstract class _MusicDataStore with Store {
isUpdatingDatabase = false;
}
@action
Future<void> fetchArtists() async {
isFetchingArtists = true;
final result = await _musicDataRepository.getArtists();
result.fold(
(_) => artists = <Artist>[].asObservable(),
(artistList) {
artists.clear();
artists.addAll(artistList);
},
);
isFetchingArtists = false;
}
@action
Future<void> fetchAlbums() async {
isFetchingAlbums = true;

View file

@ -6,9 +6,40 @@ part of 'music_data_store.dart';
// StoreGenerator
// **************************************************************************
// ignore_for_file: non_constant_identifier_names, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic
// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic
mixin _$MusicDataStore on _MusicDataStore, Store {
final _$artistsAtom = Atom(name: '_MusicDataStore.artists');
@override
ObservableList<Artist> get artists {
_$artistsAtom.reportRead();
return super.artists;
}
@override
set artists(ObservableList<Artist> value) {
_$artistsAtom.reportWrite(value, super.artists, () {
super.artists = value;
});
}
final _$isFetchingArtistsAtom =
Atom(name: '_MusicDataStore.isFetchingArtists');
@override
bool get isFetchingArtists {
_$isFetchingArtistsAtom.reportRead();
return super.isFetchingArtists;
}
@override
set isFetchingArtists(bool value) {
_$isFetchingArtistsAtom.reportWrite(value, super.isFetchingArtists, () {
super.isFetchingArtists = value;
});
}
final _$albumsAtom = Atom(name: '_MusicDataStore.albums');
@override
@ -108,6 +139,13 @@ mixin _$MusicDataStore on _MusicDataStore, Store {
return _$updateDatabaseAsyncAction.run(() => super.updateDatabase());
}
final _$fetchArtistsAsyncAction = AsyncAction('_MusicDataStore.fetchArtists');
@override
Future<void> fetchArtists() {
return _$fetchArtistsAsyncAction.run(() => super.fetchArtists());
}
final _$fetchAlbumsAsyncAction = AsyncAction('_MusicDataStore.fetchAlbums');
@override
@ -148,6 +186,8 @@ mixin _$MusicDataStore on _MusicDataStore, Store {
@override
String toString() {
return '''
artists: ${artists},
isFetchingArtists: ${isFetchingArtists},
albums: ${albums},
isFetchingAlbums: ${isFetchingAlbums},
songs: ${songs},

View file

@ -6,7 +6,7 @@ part of 'navigation_store.dart';
// StoreGenerator
// **************************************************************************
// ignore_for_file: non_constant_identifier_names, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic
// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic
mixin _$NavigationStore on _NavigationStore, Store {
final _$navIndexAtom = Atom(name: '_NavigationStore.navIndex');

View file

@ -1,6 +1,7 @@
import 'package:flutter_audio_query/flutter_audio_query.dart';
import '../models/album_model.dart';
import '../models/artist_model.dart';
import '../models/song_model.dart';
import 'local_music_fetcher_contract.dart';
@ -9,6 +10,15 @@ class LocalMusicFetcherImpl implements LocalMusicFetcher {
final FlutterAudioQuery flutterAudioQuery;
@override
Future<List<ArtistModel>> getArtists() async {
final List<ArtistInfo> artistInfoList =
await flutterAudioQuery.getArtists();
return artistInfoList
.map((ArtistInfo artistInfo) => ArtistModel.fromArtistInfo(artistInfo))
.toList();
}
@override
Future<List<AlbumModel>> getAlbums() async {
final List<AlbumInfo> albumInfoList = await flutterAudioQuery.getAlbums();

View file

@ -1,7 +1,9 @@
import '../models/album_model.dart';
import '../models/artist_model.dart';
import '../models/song_model.dart';
abstract class LocalMusicFetcher {
Future<List<ArtistModel>> getArtists();
Future<List<AlbumModel>> getAlbums();
Future<List<SongModel>> getSongs();
}

View file

@ -8,6 +8,7 @@ import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
import '../models/album_model.dart';
import '../models/artist_model.dart';
import '../models/song_model.dart';
import 'music_data_source_contract.dart';
@ -15,6 +16,14 @@ part 'moor_music_data_source.g.dart';
const String MOOR_ISOLATE = 'MOOR_ISOLATE';
@DataClassName('MoorArtist')
class Artists extends Table {
TextColumn get name => text()();
@override
Set<Column> get primaryKey => {name};
}
@DataClassName('MoorAlbum')
class Albums extends Table {
IntColumn get id => integer().autoIncrement()();
@ -23,9 +32,6 @@ class Albums extends Table {
TextColumn get albumArtPath => text().nullable()();
IntColumn get year => integer().nullable()();
BoolColumn get present => boolean().withDefault(const Constant(true))();
@override
Set<Column> get primaryKey => {id};
}
@DataClassName('MoorSong')
@ -44,7 +50,7 @@ class Songs extends Table {
Set<Column> get primaryKey => {path};
}
@UseMoor(tables: [Albums, Songs])
@UseMoor(tables: [Artists, Albums, Songs])
class MoorMusicDataSource extends _$MoorMusicDataSource
implements MusicDataSource {
/// Use MoorMusicDataSource in main isolate only.
@ -190,6 +196,33 @@ class MoorMusicDataSource extends _$MoorMusicDataSource
Future<void> resetSongsPresentFlag() async {
update(songs).write(const SongsCompanion(present: Value(false)));
}
@override
Future<void> deleteAllArtists() async {
delete(artists).go();
}
@override
Future<int> insertArtist(ArtistModel artistModel) async {
return into(artists).insert(artistModel.toArtistsCompanion());
}
@override
Future<void> deleteAllAlbums() async {
delete(albums).go();
}
@override
Future<void> deleteAllSongs() async {
delete(songs).go();
}
@override
Future<List<ArtistModel>> getArtists() {
return select(artists).get().then((moorArtistList) => moorArtistList
.map((moorArtist) => ArtistModel.fromMoorArtist(moorArtist))
.toList());
}
}
LazyDatabase _openConnection() {

View file

@ -7,6 +7,154 @@ part of 'moor_music_data_source.dart';
// **************************************************************************
// ignore_for_file: unnecessary_brace_in_string_interps, unnecessary_this
class MoorArtist extends DataClass implements Insertable<MoorArtist> {
final String name;
MoorArtist({@required this.name});
factory MoorArtist.fromData(Map<String, dynamic> data, GeneratedDatabase db,
{String prefix}) {
final effectivePrefix = prefix ?? '';
final stringType = db.typeSystem.forDartType<String>();
return MoorArtist(
name: stringType.mapFromDatabaseResponse(data['${effectivePrefix}name']),
);
}
@override
Map<String, Expression> toColumns(bool nullToAbsent) {
final map = <String, Expression>{};
if (!nullToAbsent || name != null) {
map['name'] = Variable<String>(name);
}
return map;
}
ArtistsCompanion toCompanion(bool nullToAbsent) {
return ArtistsCompanion(
name: name == null && nullToAbsent ? const Value.absent() : Value(name),
);
}
factory MoorArtist.fromJson(Map<String, dynamic> json,
{ValueSerializer serializer}) {
serializer ??= moorRuntimeOptions.defaultSerializer;
return MoorArtist(
name: serializer.fromJson<String>(json['name']),
);
}
@override
Map<String, dynamic> toJson({ValueSerializer serializer}) {
serializer ??= moorRuntimeOptions.defaultSerializer;
return <String, dynamic>{
'name': serializer.toJson<String>(name),
};
}
MoorArtist copyWith({String name}) => MoorArtist(
name: name ?? this.name,
);
@override
String toString() {
return (StringBuffer('MoorArtist(')..write('name: $name')..write(')'))
.toString();
}
@override
int get hashCode => $mrjf(name.hashCode);
@override
bool operator ==(dynamic other) =>
identical(this, other) ||
(other is MoorArtist && other.name == this.name);
}
class ArtistsCompanion extends UpdateCompanion<MoorArtist> {
final Value<String> name;
const ArtistsCompanion({
this.name = const Value.absent(),
});
ArtistsCompanion.insert({
@required String name,
}) : name = Value(name);
static Insertable<MoorArtist> custom({
Expression<String> name,
}) {
return RawValuesInsertable({
if (name != null) 'name': name,
});
}
ArtistsCompanion copyWith({Value<String> name}) {
return ArtistsCompanion(
name: name ?? this.name,
);
}
@override
Map<String, Expression> toColumns(bool nullToAbsent) {
final map = <String, Expression>{};
if (name.present) {
map['name'] = Variable<String>(name.value);
}
return map;
}
@override
String toString() {
return (StringBuffer('ArtistsCompanion(')..write('name: $name')..write(')'))
.toString();
}
}
class $ArtistsTable extends Artists with TableInfo<$ArtistsTable, MoorArtist> {
final GeneratedDatabase _db;
final String _alias;
$ArtistsTable(this._db, [this._alias]);
final VerificationMeta _nameMeta = const VerificationMeta('name');
GeneratedTextColumn _name;
@override
GeneratedTextColumn get name => _name ??= _constructName();
GeneratedTextColumn _constructName() {
return GeneratedTextColumn(
'name',
$tableName,
false,
);
}
@override
List<GeneratedColumn> get $columns => [name];
@override
$ArtistsTable get asDslTable => this;
@override
String get $tableName => _alias ?? 'artists';
@override
final String actualTableName = 'artists';
@override
VerificationContext validateIntegrity(Insertable<MoorArtist> instance,
{bool isInserting = false}) {
final context = VerificationContext();
final data = instance.toColumns(true);
if (data.containsKey('name')) {
context.handle(
_nameMeta, name.isAcceptableOrUnknown(data['name'], _nameMeta));
} else if (isInserting) {
context.missing(_nameMeta);
}
return context;
}
@override
Set<GeneratedColumn> get $primaryKey => {name};
@override
MoorArtist map(Map<String, dynamic> data, {String tablePrefix}) {
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null;
return MoorArtist.fromData(data, _db, prefix: effectivePrefix);
}
@override
$ArtistsTable createAlias(String alias) {
return $ArtistsTable(_db, alias);
}
}
class MoorAlbum extends DataClass implements Insertable<MoorAlbum> {
final int id;
final String title;
@ -237,6 +385,19 @@ class AlbumsCompanion extends UpdateCompanion<MoorAlbum> {
}
return map;
}
@override
String toString() {
return (StringBuffer('AlbumsCompanion(')
..write('id: $id, ')
..write('title: $title, ')
..write('artist: $artist, ')
..write('albumArtPath: $albumArtPath, ')
..write('year: $year, ')
..write('present: $present')
..write(')'))
.toString();
}
}
class $AlbumsTable extends Albums with TableInfo<$AlbumsTable, MoorAlbum> {
@ -693,6 +854,22 @@ class SongsCompanion extends UpdateCompanion<MoorSong> {
}
return map;
}
@override
String toString() {
return (StringBuffer('SongsCompanion(')
..write('title: $title, ')
..write('albumTitle: $albumTitle, ')
..write('albumId: $albumId, ')
..write('artist: $artist, ')
..write('path: $path, ')
..write('duration: $duration, ')
..write('albumArtPath: $albumArtPath, ')
..write('trackNumber: $trackNumber, ')
..write('present: $present')
..write(')'))
.toString();
}
}
class $SongsTable extends Songs with TableInfo<$SongsTable, MoorSong> {
@ -904,6 +1081,8 @@ abstract class _$MoorMusicDataSource extends GeneratedDatabase {
_$MoorMusicDataSource(QueryExecutor e)
: super(SqlTypeSystem.defaultInstance, e);
_$MoorMusicDataSource.connect(DatabaseConnection c) : super.connect(c);
$ArtistsTable _artists;
$ArtistsTable get artists => _artists ??= $ArtistsTable(this);
$AlbumsTable _albums;
$AlbumsTable get albums => _albums ??= $AlbumsTable(this);
$SongsTable _songs;
@ -911,5 +1090,5 @@ abstract class _$MoorMusicDataSource extends GeneratedDatabase {
@override
Iterable<TableInfo> get allTables => allSchemaEntities.whereType<TableInfo>();
@override
List<DatabaseSchemaEntity> get allSchemaEntities => [albums, songs];
List<DatabaseSchemaEntity> get allSchemaEntities => [artists, albums, songs];
}

View file

@ -1,4 +1,5 @@
import '../models/album_model.dart';
import '../models/artist_model.dart';
import '../models/song_model.dart';
abstract class MusicDataSource {
@ -26,4 +27,12 @@ abstract class MusicDataSource {
String title, String album, String artist);
Future<void> flagSongPresent(SongModel songModel);
Future<void> removeNonpresentSongs();
Future<void> deleteAllArtists();
Future<int> insertArtist(ArtistModel artistModel);
Future<void> deleteAllAlbums();
Future<void> deleteAllSongs();
Future<List<ArtistModel>> getArtists();
}

View file

@ -0,0 +1,28 @@
import 'package:flutter_audio_query/flutter_audio_query.dart';
import 'package:meta/meta.dart';
import 'package:moor/moor.dart';
import '../../domain/entities/artist.dart';
import '../datasources/moor_music_data_source.dart';
class ArtistModel extends Artist {
const ArtistModel({
@required String name,
}) : super(
name: name,
);
factory ArtistModel.fromMoorArtist(MoorArtist moorArtist) => ArtistModel(
name: moorArtist.name,
);
factory ArtistModel.fromArtistInfo(ArtistInfo artistInfo) {
return ArtistModel(
name: artistInfo.name,
);
}
ArtistsCompanion toArtistsCompanion() => ArtistsCompanion(
name: Value(name),
);
}

View file

@ -38,7 +38,6 @@ class SongModel extends Song {
);
factory SongModel.fromSongInfo(SongInfo songInfo) {
final String trackNumber = songInfo.track;
final String duration = songInfo.duration;
return SongModel(
@ -49,7 +48,7 @@ class SongModel extends Song {
path: songInfo.filePath,
duration: duration == null ? null : int.parse(duration),
albumArtPath: songInfo.albumArtwork,
trackNumber: trackNumber == null ? null : int.parse(trackNumber),
trackNumber: _parseTrackNumber(songInfo.track),
);
}
@ -130,4 +129,19 @@ class SongModel extends Song {
'albumId': albumId,
'trackNumber': trackNumber,
});
static int _parseTrackNumber(String trackNumberString) {
int trackNumber;
if (trackNumberString == null) {
return null;
}
trackNumber = int.tryParse(trackNumberString);
if (trackNumber == null) {
if (trackNumberString.contains('/')) {
trackNumber = int.tryParse(trackNumberString.split('/')[0]);
}
}
return trackNumber;
}
}

View file

@ -3,11 +3,13 @@ import 'package:meta/meta.dart';
import '../../core/error/failures.dart';
import '../../domain/entities/album.dart';
import '../../domain/entities/artist.dart';
import '../../domain/entities/song.dart';
import '../../domain/repositories/music_data_repository.dart';
import '../datasources/local_music_fetcher_contract.dart';
import '../datasources/music_data_source_contract.dart';
import '../models/album_model.dart';
import '../models/artist_model.dart';
import '../models/song_model.dart';
class MusicDataRepositoryImpl implements MusicDataRepository {
@ -19,6 +21,12 @@ class MusicDataRepositoryImpl implements MusicDataRepository {
final LocalMusicFetcher localMusicFetcher;
final MusicDataSource musicDataSource;
@override
Future<Either<Failure, List<Artist>>> getArtists() async {
return musicDataSource.getArtists().then((List<ArtistModel> artists) =>
Right<Failure, List<ArtistModel>>(artists));
}
@override
Future<Either<Failure, List<Album>>> getAlbums() async {
return musicDataSource.getAlbums().then(
@ -39,43 +47,31 @@ class MusicDataRepositoryImpl implements MusicDataRepository {
@override
Future<void> updateDatabase() async {
final List<AlbumModel> albums = await localMusicFetcher.getAlbums();
await musicDataSource.deleteAllArtists();
final List<ArtistModel> artists = await localMusicFetcher.getArtists();
for (final ArtistModel artist in artists) {
await musicDataSource.insertArtist(artist);
}
await musicDataSource.deleteAllAlbums();
final List<AlbumModel> albums = await localMusicFetcher.getAlbums();
final Map<int, int> albumIdMap = {};
await musicDataSource.resetAlbumsPresentFlag();
for (final AlbumModel album in albums) {
final storedAlbum = await musicDataSource.getAlbumByTitleArtist(
album.title, album.artist);
if (storedAlbum != null) {
albumIdMap[album.id] = storedAlbum.id;
await musicDataSource.flagAlbumPresent(storedAlbum);
} else {
final int newAlbumId = await musicDataSource.insertAlbum(album);
albumIdMap[album.id] = newAlbumId;
}
final int newAlbumId = await musicDataSource.insertAlbum(album);
albumIdMap[album.id] = newAlbumId;
}
await musicDataSource.removeNonpresentAlbums();
await musicDataSource.deleteAllSongs();
final List<SongModel> songs = await localMusicFetcher.getSongs();
await musicDataSource.resetSongsPresentFlag();
for (final SongModel song in songs) {
SongModel storedSong = await musicDataSource.getSongByPath(song.path);
storedSong ??= await musicDataSource.getSongByTitleAlbumArtist(
song.title, song.album, song.artist);
if (storedSong != null) {
await musicDataSource.flagSongPresent(storedSong);
} else {
final SongModel songToInsert = song.copyWith(albumId: albumIdMap[song.albumId]);
final SongModel songToInsert =
song.copyWith(albumId: albumIdMap[song.albumId]);
// TODO: fails if albumId is null
await musicDataSource.insertSong(songToInsert);
}
// TODO: fails if albumId is null
await musicDataSource.insertSong(songToInsert);
}
await musicDataSource.removeNonpresentSongs();
}
}

View file

@ -7,28 +7,21 @@ packages:
name: _fe_analyzer_shared
url: "https://pub.dartlang.org"
source: hosted
version: "4.0.0"
version: "6.0.0"
analyzer:
dependency: transitive
description:
name: analyzer
url: "https://pub.dartlang.org"
source: hosted
version: "0.39.10"
analyzer_plugin_fork:
version: "0.39.14"
analyzer_plugin:
dependency: transitive
description:
name: analyzer_plugin_fork
name: analyzer_plugin
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.2"
archive:
dependency: transitive
description:
name: archive
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.13"
version: "0.3.0"
args:
dependency: transitive
description:
@ -42,7 +35,7 @@ packages:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.4.1"
version: "2.4.2"
audio_service:
dependency: "direct main"
description:
@ -84,14 +77,14 @@ packages:
name: build_resolvers
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.9"
version: "1.3.10"
build_runner:
dependency: "direct dev"
description:
name: build_runner
url: "https://pub.dartlang.org"
source: hosted
version: "1.10.0"
version: "1.10.1"
build_runner_core:
dependency: transitive
description:
@ -113,6 +106,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "7.1.0"
characters:
dependency: transitive
description:
name: characters
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
charcode:
dependency: transitive
description:
@ -147,14 +147,14 @@ packages:
name: code_builder
url: "https://pub.dartlang.org"
source: hosted
version: "3.3.0"
version: "3.4.0"
collection:
dependency: transitive
description:
name: collection
url: "https://pub.dartlang.org"
source: hosted
version: "1.14.12"
version: "1.14.13"
convert:
dependency: transitive
description:
@ -168,14 +168,14 @@ packages:
name: crypto
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.4"
version: "2.1.5"
csslib:
dependency: transitive
description:
name: csslib
url: "https://pub.dartlang.org"
source: hosted
version: "0.16.1"
version: "0.16.2"
dart_style:
dependency: transitive
description:
@ -196,7 +196,14 @@ packages:
name: equatable
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
version: "1.2.3"
fake_async:
dependency: transitive
description:
name: fake_async
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
ffi:
dependency: transitive
description:
@ -210,7 +217,7 @@ packages:
name: file
url: "https://pub.dartlang.org"
source: hosted
version: "5.1.0"
version: "5.2.1"
fixnum:
dependency: transitive
description:
@ -236,7 +243,7 @@ packages:
name: flutter_cache_manager
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
version: "1.4.1"
flutter_isolate:
dependency: transitive
description:
@ -250,7 +257,7 @@ packages:
name: flutter_mobx
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
version: "1.1.0+2"
flutter_test:
dependency: "direct dev"
description: flutter
@ -267,7 +274,7 @@ packages:
name: get_it
url: "https://pub.dartlang.org"
source: hosted
version: "4.0.2"
version: "4.0.4"
glob:
dependency: transitive
description:
@ -295,7 +302,7 @@ packages:
name: http
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.1"
version: "0.12.2"
http_multi_server:
dependency: transitive
description:
@ -310,13 +317,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.4"
image:
dependency: transitive
description:
name: image
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.12"
intl:
dependency: transitive
description:
@ -337,7 +337,7 @@ packages:
name: js
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.1+1"
version: "0.6.2"
json_annotation:
dependency: transitive
description:
@ -365,7 +365,7 @@ packages:
name: matcher
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.6"
version: "0.12.8"
meta:
dependency: transitive
description:
@ -386,14 +386,14 @@ packages:
name: mobx
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.1"
version: "1.2.1+2"
mobx_codegen:
dependency: "direct dev"
description:
name: mobx_codegen
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
version: "1.1.0+1"
mockito:
dependency: "direct main"
description:
@ -407,7 +407,7 @@ packages:
name: moor
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.0"
version: "3.3.1"
moor_ffi:
dependency: "direct main"
description:
@ -421,7 +421,7 @@ packages:
name: moor_generator
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.0"
version: "3.3.1"
nested:
dependency: transitive
description:
@ -456,21 +456,21 @@ packages:
name: path
url: "https://pub.dartlang.org"
source: hosted
version: "1.6.4"
version: "1.7.0"
path_provider:
dependency: "direct main"
description:
name: path_provider
url: "https://pub.dartlang.org"
source: hosted
version: "1.6.10"
version: "1.6.11"
path_provider_linux:
dependency: transitive
description:
name: path_provider_linux
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.1+1"
version: "0.0.1+2"
path_provider_macos:
dependency: transitive
description:
@ -492,13 +492,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.9.0"
petitparser:
dependency: transitive
description:
name: petitparser
url: "https://pub.dartlang.org"
source: hosted
version: "2.4.0"
platform:
dependency: transitive
description:
@ -533,7 +526,7 @@ packages:
name: provider
url: "https://pub.dartlang.org"
source: hosted
version: "4.1.2"
version: "4.3.2"
pub_semver:
dependency: transitive
description:
@ -575,7 +568,7 @@ packages:
name: shelf
url: "https://pub.dartlang.org"
source: hosted
version: "0.7.5"
version: "0.7.7"
shelf_web_socket:
dependency: transitive
description:
@ -594,7 +587,7 @@ packages:
name: source_gen
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.5"
version: "0.9.6"
source_span:
dependency: transitive
description:
@ -608,28 +601,35 @@ packages:
name: sqflite
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0+2"
version: "1.3.1"
sqflite_common:
dependency: transitive
description:
name: sqflite_common
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
version: "1.0.2+1"
sqlite3:
dependency: transitive
description:
name: sqlite3
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.4"
sqlparser:
dependency: transitive
description:
name: sqlparser
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.0"
version: "0.10.1"
stack_trace:
dependency: transitive
description:
name: stack_trace
url: "https://pub.dartlang.org"
source: hosted
version: "1.9.3"
version: "1.9.5"
stream_channel:
dependency: transitive
description:
@ -657,7 +657,7 @@ packages:
name: synchronized
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.0"
version: "2.2.0+2"
term_glyph:
dependency: transitive
description:
@ -671,7 +671,7 @@ packages:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.15"
version: "0.2.17"
timing:
dependency: transitive
description:
@ -685,14 +685,14 @@ packages:
name: typed_data
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.6"
version: "1.2.0"
uuid:
dependency: transitive
description:
name: uuid
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.4"
version: "2.2.0"
vector_math:
dependency: transitive
description:
@ -721,13 +721,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.0"
xml:
dependency: transitive
description:
name: xml
url: "https://pub.dartlang.org"
source: hosted
version: "3.6.1"
yaml:
dependency: transitive
description:
@ -736,5 +729,5 @@ packages:
source: hosted
version: "2.2.1"
sdks:
dart: ">=2.7.0 <3.0.0"
flutter: ">=1.16.0 <2.0.0"
dart: ">=2.9.0 <3.0.0"
flutter: ">=1.20.0 <2.0.0"

View file

@ -4,8 +4,8 @@ description: The frustration-free music player.
version: 1.0.0+1
environment:
sdk: ">=2.6.0 <3.0.0"
flutter: ">=1.12.0"
sdk: ">=2.9.0 <3.0.0"
flutter: ">=1.20.0"
dependencies:
flutter:
@ -34,7 +34,7 @@ dev_dependencies:
flutter_test:
sdk: flutter
moor_generator: ^3.0.0
build_runner:
build_runner: 1.10.1
mobx_codegen: ^1.0.3