This commit is contained in:
austinried
2023-04-28 09:24:51 +09:00
parent 35b037f66c
commit f0f812e66a
402 changed files with 34368 additions and 62769 deletions

143
lib/state/audio.dart Normal file
View File

@@ -0,0 +1,143 @@
import 'package:audio_service/audio_service.dart';
import 'package:drift/drift.dart' show Value;
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import '../database/database.dart';
import '../models/music.dart';
import '../models/support.dart';
import '../services/audio_service.dart';
import 'settings.dart';
part 'audio.g.dart';
@Riverpod(keepAlive: true)
Stream<MediaItem?> mediaItem(MediaItemRef ref) async* {
final audio = ref.watch(audioControlProvider);
await for (var item in audio.mediaItem) {
yield item;
}
}
@Riverpod(keepAlive: true)
MediaItemData? mediaItemData(MediaItemDataRef ref) {
return ref.watch(mediaItemProvider.select(
(value) => value.valueOrNull?.data,
));
}
@Riverpod(keepAlive: true)
Stream<Song?> mediaItemSong(MediaItemSongRef ref) {
final db = ref.watch(databaseProvider);
final sourceId = ref.watch(sourceIdProvider);
final id = ref.watch(mediaItemProvider.select(
(value) => value.valueOrNull?.id,
));
return db.songById(sourceId, id ?? '').watchSingleOrNull();
}
@Riverpod(keepAlive: true)
Stream<PlaybackState> playbackState(PlaybackStateRef ref) async* {
final audio = ref.watch(audioControlProvider);
await for (var state in audio.playbackState) {
yield state;
}
}
@Riverpod(keepAlive: true)
Stream<QueueMode> queueMode(QueueModeRef ref) async* {
final audio = ref.watch(audioControlProvider);
await for (var state in audio.queueMode) {
yield state;
}
}
@Riverpod(keepAlive: true)
Stream<List<MediaItem>> queue(QueueRef ref) async* {
final audio = ref.watch(audioControlProvider);
await for (var queue in audio.queue) {
yield queue;
}
}
@Riverpod(keepAlive: true)
Stream<List<int>?> shuffleIndicies(ShuffleIndiciesRef ref) async* {
final audio = ref.watch(audioControlProvider);
await for (var indicies in audio.shuffleIndicies) {
yield indicies;
}
}
@riverpod
Stream<Duration> positionStream(PositionStreamRef ref) async* {
final audio = ref.watch(audioControlProvider);
await for (var state in audio.position) {
yield state;
}
}
@riverpod
bool playing(PlayingRef ref) {
return ref.watch(playbackStateProvider.select(
(value) => value.valueOrNull?.playing ?? false,
));
}
@riverpod
AudioProcessingState? processingState(ProcessingStateRef ref) {
return ref.watch(playbackStateProvider.select(
(value) => value.valueOrNull?.processingState,
));
}
@riverpod
int position(PositionRef ref) {
return ref.watch(positionStreamProvider.select(
(value) => value.valueOrNull?.inSeconds ?? 0,
));
}
@riverpod
int duration(DurationRef ref) {
return ref.watch(mediaItemProvider.select(
(value) => value.valueOrNull?.duration?.inSeconds ?? 0,
));
}
@Riverpod(keepAlive: true)
AudioServiceShuffleMode? shuffleMode(ShuffleModeRef ref) {
return ref.watch(playbackStateProvider.select(
(value) => value.valueOrNull?.shuffleMode,
));
}
@Riverpod(keepAlive: true)
AudioServiceRepeatMode repeatMode(RepeatModeRef ref) {
return ref.watch(playbackStateProvider.select(
(value) => value.valueOrNull?.repeatMode ?? AudioServiceRepeatMode.none,
));
}
@Riverpod(keepAlive: true)
class LastAudioStateService extends _$LastAudioStateService {
@override
Future<void> build() async {
final db = ref.watch(databaseProvider);
final queueMode = ref.watch(queueModeProvider).valueOrNull;
final shuffleIndicies = ref.watch(shuffleIndiciesProvider).valueOrNull;
final repeat = ref.watch(repeatModeProvider);
await db.saveLastAudioState(LastAudioStateCompanion.insert(
id: const Value(1),
queueMode: queueMode ?? QueueMode.user,
shuffleIndicies: Value(shuffleIndicies?.lock),
repeat: {
AudioServiceRepeatMode.none: RepeatMode.none,
AudioServiceRepeatMode.all: RepeatMode.all,
AudioServiceRepeatMode.group: RepeatMode.all,
AudioServiceRepeatMode.one: RepeatMode.one,
}[repeat]!,
));
}
}

229
lib/state/audio.g.dart Normal file
View File

@@ -0,0 +1,229 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'audio.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$mediaItemHash() => r'ca8b6768872f17355f756c95cf85278127b59444';
/// See also [mediaItem].
@ProviderFor(mediaItem)
final mediaItemProvider = StreamProvider<MediaItem?>.internal(
mediaItem,
name: r'mediaItemProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$mediaItemHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef MediaItemRef = StreamProviderRef<MediaItem?>;
String _$mediaItemDataHash() => r'8539c02682f0d33b584ea0437dd3774d9f321a2e';
/// See also [mediaItemData].
@ProviderFor(mediaItemData)
final mediaItemDataProvider = Provider<MediaItemData?>.internal(
mediaItemData,
name: r'mediaItemDataProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$mediaItemDataHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef MediaItemDataRef = ProviderRef<MediaItemData?>;
String _$mediaItemSongHash() => r'274f43470cd993f0a2bed3d3da22d7bd41b562f1';
/// See also [mediaItemSong].
@ProviderFor(mediaItemSong)
final mediaItemSongProvider = StreamProvider<Song?>.internal(
mediaItemSong,
name: r'mediaItemSongProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$mediaItemSongHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef MediaItemSongRef = StreamProviderRef<Song?>;
String _$playbackStateHash() => r'b4a9eb7f802fc8c92666c1318f789865140d6025';
/// See also [playbackState].
@ProviderFor(playbackState)
final playbackStateProvider = StreamProvider<PlaybackState>.internal(
playbackState,
name: r'playbackStateProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$playbackStateHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef PlaybackStateRef = StreamProviderRef<PlaybackState>;
String _$queueModeHash() => r'be0b1ff436c367e9be54c6d15fd8bac4f904fdec';
/// See also [queueMode].
@ProviderFor(queueMode)
final queueModeProvider = StreamProvider<QueueMode>.internal(
queueMode,
name: r'queueModeProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$queueModeHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef QueueModeRef = StreamProviderRef<QueueMode>;
String _$queueHash() => r'94d86c99382f56193a11baf3f13354eab6a39fa8';
/// See also [queue].
@ProviderFor(queue)
final queueProvider = StreamProvider<List<MediaItem>>.internal(
queue,
name: r'queueProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$queueHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef QueueRef = StreamProviderRef<List<MediaItem>>;
String _$shuffleIndiciesHash() => r'e5dc6879b2a7b7a501b58aace717ff36eff59995';
/// See also [shuffleIndicies].
@ProviderFor(shuffleIndicies)
final shuffleIndiciesProvider = StreamProvider<List<int>?>.internal(
shuffleIndicies,
name: r'shuffleIndiciesProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$shuffleIndiciesHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef ShuffleIndiciesRef = StreamProviderRef<List<int>?>;
String _$positionStreamHash() => r'5f1dc9d11e1bcce649ddb764525cc0dc79bfb6d8';
/// See also [positionStream].
@ProviderFor(positionStream)
final positionStreamProvider = AutoDisposeStreamProvider<Duration>.internal(
positionStream,
name: r'positionStreamProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$positionStreamHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef PositionStreamRef = AutoDisposeStreamProviderRef<Duration>;
String _$playingHash() => r'2a40fa275358918b243c8734bbe49bc9d7373f10';
/// See also [playing].
@ProviderFor(playing)
final playingProvider = AutoDisposeProvider<bool>.internal(
playing,
name: r'playingProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$playingHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef PlayingRef = AutoDisposeProviderRef<bool>;
String _$processingStateHash() => r'b9e59927b905384a0f1221b2adb9b681091c27d1';
/// See also [processingState].
@ProviderFor(processingState)
final processingStateProvider =
AutoDisposeProvider<AudioProcessingState?>.internal(
processingState,
name: r'processingStateProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$processingStateHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef ProcessingStateRef = AutoDisposeProviderRef<AudioProcessingState?>;
String _$positionHash() => r'bfc853fe9e46bf79522fa41374763a7e1c12e739';
/// See also [position].
@ProviderFor(position)
final positionProvider = AutoDisposeProvider<int>.internal(
position,
name: r'positionProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$positionHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef PositionRef = AutoDisposeProviderRef<int>;
String _$durationHash() => r'bf9eb316b8401401e5862384deb1a4c1134e6dd2';
/// See also [duration].
@ProviderFor(duration)
final durationProvider = AutoDisposeProvider<int>.internal(
duration,
name: r'durationProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$durationHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef DurationRef = AutoDisposeProviderRef<int>;
String _$shuffleModeHash() => r'fd26d81cb9bd5e0e1a7e9ccf1589c104d9a4eb3a';
/// See also [shuffleMode].
@ProviderFor(shuffleMode)
final shuffleModeProvider = Provider<AudioServiceShuffleMode?>.internal(
shuffleMode,
name: r'shuffleModeProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$shuffleModeHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef ShuffleModeRef = ProviderRef<AudioServiceShuffleMode?>;
String _$repeatModeHash() => r'346248bf08df65f1f69e4cb4b6ef192190d2910c';
/// See also [repeatMode].
@ProviderFor(repeatMode)
final repeatModeProvider = Provider<AudioServiceRepeatMode>.internal(
repeatMode,
name: r'repeatModeProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$repeatModeHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef RepeatModeRef = ProviderRef<AudioServiceRepeatMode>;
String _$lastAudioStateServiceHash() =>
r'4291b8d4a399f1b192277a3e8a93fbe7096fea32';
/// See also [LastAudioStateService].
@ProviderFor(LastAudioStateService)
final lastAudioStateServiceProvider =
AsyncNotifierProvider<LastAudioStateService, void>.internal(
LastAudioStateService.new,
name: r'lastAudioStateServiceProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$lastAudioStateServiceHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef _$LastAudioStateService = AsyncNotifier<void>;
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions

82
lib/state/init.dart Normal file
View File

@@ -0,0 +1,82 @@
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:path_provider/path_provider.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import '../app/app.dart';
import '../app/app_router.dart';
import '../app/pages/bottom_nav_page.dart';
import '../app/pages/library_page.dart';
import '../services/audio_service.dart';
import '../services/download_service.dart';
import '../services/settings_service.dart';
import 'audio.dart';
import 'settings.dart';
part 'init.g.dart';
@Riverpod(keepAlive: true)
FutureOr<Map<String, String>> env(EnvRef ref) async {
await dotenv.load();
return dotenv.env;
}
@Riverpod(keepAlive: true)
AppRouter router(RouterRef ref) {
return AppRouter();
}
@Riverpod(keepAlive: true)
FutureOr<Uri> placeholderImageUri(PlaceholderImageUriRef ref) async {
final byteData = await rootBundle.load('assets/placeholder.png');
final docsDir = await getApplicationDocumentsDirectory();
return (await File('${docsDir.path}/placeholder.png').writeAsBytes(byteData
.buffer
.asUint8List(byteData.offsetInBytes, byteData.lengthInBytes)))
.uri;
}
@Riverpod(keepAlive: true)
FutureOr<Uri> placeholderThumbImageUri(PlaceholderThumbImageUriRef ref) async {
final byteData = await rootBundle.load('assets/placeholder_thumb.png');
final docsDir = await getApplicationDocumentsDirectory();
return (await File('${docsDir.path}/placeholder_thumb.png').writeAsBytes(
byteData.buffer
.asUint8List(byteData.offsetInBytes, byteData.lengthInBytes)))
.uri;
}
@Riverpod(keepAlive: true)
FutureOr<PackageInfo> packageInfo(PackageInfoRef ref) async {
return await PackageInfo.fromPlatform();
}
@Riverpod(keepAlive: true)
FutureOr<void> init(InitRef ref) async {
ref.watch(routerProvider);
await ref.watch(envProvider.future);
await ref.read(packageInfoProvider.future);
await ref.watch(placeholderImageUriProvider.future);
await ref.watch(placeholderThumbImageUriProvider.future);
await ref.read(networkModeProvider.future);
await ref.read(maxBitrateProvider.future);
await ref.watch(settingsServiceProvider.notifier).init();
final audio = await ref.watch(audioControlInitProvider.future);
await audio.init();
ref.watch(lastAudioStateServiceProvider.notifier);
await ref.watch(downloadServiceProvider.notifier).init();
await ref.watch(lastPathProvider.notifier).init();
ref.watch(lastBottomNavStateServiceProvider.notifier);
ref.watch(lastLibraryStateServiceProvider.notifier);
await ref.watch(libraryListsProvider.notifier).init();
}

97
lib/state/init.g.dart Normal file
View File

@@ -0,0 +1,97 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'init.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$envHash() => r'183e2c6c10c5a9d3dfcaffca0f1723cd85d67a5c';
/// See also [env].
@ProviderFor(env)
final envProvider = FutureProvider<Map<String, String>>.internal(
env,
name: r'envProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$envHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef EnvRef = FutureProviderRef<Map<String, String>>;
String _$routerHash() => r'3f52af31948ac5942fe4167f84785572458eeacc';
/// See also [router].
@ProviderFor(router)
final routerProvider = Provider<AppRouter>.internal(
router,
name: r'routerProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$routerHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef RouterRef = ProviderRef<AppRouter>;
String _$placeholderImageUriHash() =>
r'129f37af640421ec12038d161a8b15a67536e570';
/// See also [placeholderImageUri].
@ProviderFor(placeholderImageUri)
final placeholderImageUriProvider = FutureProvider<Uri>.internal(
placeholderImageUri,
name: r'placeholderImageUriProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$placeholderImageUriHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef PlaceholderImageUriRef = FutureProviderRef<Uri>;
String _$placeholderThumbImageUriHash() =>
r'8136dd4bbb3dc57fb1e6aa8db556e58620c61c85';
/// See also [placeholderThumbImageUri].
@ProviderFor(placeholderThumbImageUri)
final placeholderThumbImageUriProvider = FutureProvider<Uri>.internal(
placeholderThumbImageUri,
name: r'placeholderThumbImageUriProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$placeholderThumbImageUriHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef PlaceholderThumbImageUriRef = FutureProviderRef<Uri>;
String _$packageInfoHash() => r'9a2956f08c2e98b92dd8cce49cb331a127c78670';
/// See also [packageInfo].
@ProviderFor(packageInfo)
final packageInfoProvider = FutureProvider<PackageInfo>.internal(
packageInfo,
name: r'packageInfoProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$packageInfoHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef PackageInfoRef = FutureProviderRef<PackageInfo>;
String _$initHash() => r'10e2945eb65f51e6a904a3811fa88e63771e5b19';
/// See also [init].
@ProviderFor(init)
final initProvider = FutureProvider<void>.internal(
init,
name: r'initProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$initHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef InitRef = FutureProviderRef<void>;
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions

152
lib/state/music.dart Normal file
View File

@@ -0,0 +1,152 @@
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import '../database/database.dart';
import '../models/music.dart';
import '../models/query.dart';
import '../models/support.dart';
import 'settings.dart';
part 'music.g.dart';
@riverpod
Stream<Artist> artist(ArtistRef ref, String id) {
final db = ref.watch(databaseProvider);
final sourceId = ref.watch(sourceIdProvider);
return db.artistById(sourceId, id).watchSingle();
}
@riverpod
Stream<Album> album(AlbumRef ref, String id) {
final db = ref.watch(databaseProvider);
final sourceId = ref.watch(sourceIdProvider);
return db.albumById(sourceId, id).watchSingle();
}
@riverpod
Stream<ListDownloadStatus> albumDownloadStatus(
AlbumDownloadStatusRef ref,
String id,
) {
final db = ref.watch(databaseProvider);
final sourceId = ref.watch(sourceIdProvider);
return db.albumDownloadStatus(sourceId, id).watchSingle();
}
@riverpod
Stream<ListDownloadStatus> playlistDownloadStatus(
PlaylistDownloadStatusRef ref,
String id,
) {
final db = ref.watch(databaseProvider);
final sourceId = ref.watch(sourceIdProvider);
return db.playlistDownloadStatus(sourceId, id).watchSingle();
}
@riverpod
Stream<Song> song(SongRef ref, String id) {
final db = ref.watch(databaseProvider);
final sourceId = ref.watch(sourceIdProvider);
return db.songById(sourceId, id).watchSingle();
}
@riverpod
Future<List<Song>> albumSongsList(
AlbumSongsListRef ref,
String id,
ListQuery opt,
) {
final db = ref.watch(databaseProvider);
final sourceId = ref.watch(sourceIdProvider);
return db.albumSongsList(SourceId(sourceId: sourceId, id: id), opt).get();
}
@riverpod
Future<List<Song>> songsByAlbumList(
SongsByAlbumListRef ref,
ListQuery opt,
) {
final db = ref.watch(databaseProvider);
final sourceId = ref.watch(sourceIdProvider);
return db.songsByAlbumList(sourceId, opt).get();
}
@riverpod
Stream<Playlist> playlist(PlaylistRef ref, String id) {
final db = ref.watch(databaseProvider);
final sourceId = ref.watch(sourceIdProvider);
return db.playlistById(sourceId, id).watchSingle();
}
@riverpod
Future<List<Song>> playlistSongsList(
PlaylistSongsListRef ref,
String id,
ListQuery opt,
) {
final db = ref.watch(databaseProvider);
final sourceId = ref.watch(sourceIdProvider);
return db.playlistSongsList(SourceId(sourceId: sourceId, id: id), opt).get();
}
@riverpod
Future<List<Album>> albumsInIds(AlbumsInIdsRef ref, IList<String> ids) {
final db = ref.watch(databaseProvider);
final sourceId = ref.watch(sourceIdProvider);
return db.albumsInIds(sourceId, ids.toList()).get();
}
@riverpod
Stream<IList<Album>> albumsByArtistId(AlbumsByArtistIdRef ref, String id) {
final db = ref.watch(databaseProvider);
final sourceId = ref.watch(sourceIdProvider);
return db
.albumsByArtistId(sourceId, id)
.watch()
.map((event) => event.toIList());
}
@riverpod
Stream<IList<String>> albumGenres(AlbumGenresRef ref, Pagination page) {
final db = ref.watch(databaseProvider);
final sourceId = ref.watch(sourceIdProvider);
return db
.albumGenres(sourceId, page.limit, page.offset)
.watch()
.map((event) => event.withNullsRemoved().toIList());
}
@riverpod
Stream<IList<Album>> albumsByGenre(
AlbumsByGenreRef ref,
String genre,
Pagination page,
) {
final db = ref.watch(databaseProvider);
final sourceId = ref.watch(sourceIdProvider);
return db
.albumsByGenre(sourceId, genre, page.limit, page.offset)
.watch()
.map((event) => event.toIList());
}
@riverpod
Stream<int> songsByGenreCount(SongsByGenreCountRef ref, String genre) {
final db = ref.watch(databaseProvider);
final sourceId = ref.watch(sourceIdProvider);
return db.songsByGenreCount(sourceId, genre).watchSingle();
}

1206
lib/state/music.g.dart Normal file

File diff suppressed because it is too large Load Diff

88
lib/state/settings.dart Normal file
View File

@@ -0,0 +1,88 @@
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import '../http/client.dart';
import '../models/settings.dart';
import '../services/settings_service.dart';
import '../sources/music_source.dart';
import '../sources/subsonic/source.dart';
part 'settings.g.dart';
@Riverpod(keepAlive: true)
MusicSource musicSource(MusicSourceRef ref) {
final settings = ref.watch(settingsServiceProvider.select(
(value) => value.activeSource,
)) as SubsonicSettings;
final streamFormat = ref.watch(settingsServiceProvider.select(
(value) => value.app.streamFormat,
));
final maxBitrate = ref.watch(maxBitrateProvider).requireValue;
final http = ref.watch(httpClientProvider);
return MusicSource(
SubsonicSource(
opt: settings,
http: http,
maxBitrate: maxBitrate,
streamFormat: streamFormat,
),
ref,
);
}
@Riverpod(keepAlive: true)
Stream<NetworkMode> networkMode(NetworkModeRef ref) async* {
await for (var state in Connectivity().onConnectivityChanged) {
switch (state) {
case ConnectivityResult.wifi:
case ConnectivityResult.ethernet:
yield NetworkMode.wifi;
break;
default:
yield NetworkMode.mobile;
break;
}
}
}
@Riverpod(keepAlive: true)
Future<int> maxBitrate(MaxBitrateRef ref) async {
final settings = ref.watch(settingsServiceProvider.select(
(value) => value.app,
));
final networkMode = ref.watch(networkModeProvider).requireValue;
return networkMode == NetworkMode.wifi
? settings.maxBitrateWifi
: settings.maxBitrateMobile;
}
@Riverpod(keepAlive: true)
int sourceId(SourceIdRef ref) {
return ref.watch(musicSourceProvider.select((value) => value.id));
}
@Riverpod(keepAlive: true)
class OfflineMode extends _$OfflineMode {
@override
bool build() {
return false;
}
Future<void> setMode(bool value) async {
final hasSource = ref.read(settingsServiceProvider.select(
(value) => value.activeSource != null,
));
if (!hasSource) return;
if (value == false && state == true) {
try {
await ref.read(musicSourceProvider).ping();
} catch (err) {
return;
}
}
state = value;
}
}

79
lib/state/settings.g.dart Normal file
View File

@@ -0,0 +1,79 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'settings.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$musicSourceHash() => r'466e2654eab8518c9e40c8c2c08a2ecb331b0a7f';
/// See also [musicSource].
@ProviderFor(musicSource)
final musicSourceProvider = Provider<MusicSource>.internal(
musicSource,
name: r'musicSourceProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$musicSourceHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef MusicSourceRef = ProviderRef<MusicSource>;
String _$networkModeHash() => r'813a60a454c6acaefbe3b56bf0152497ab18dcce';
/// See also [networkMode].
@ProviderFor(networkMode)
final networkModeProvider = StreamProvider<NetworkMode>.internal(
networkMode,
name: r'networkModeProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$networkModeHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef NetworkModeRef = StreamProviderRef<NetworkMode>;
String _$maxBitrateHash() => r'ec02d3ccbc9f3429acfc1b3f191cab791b1191e0';
/// See also [maxBitrate].
@ProviderFor(maxBitrate)
final maxBitrateProvider = FutureProvider<int>.internal(
maxBitrate,
name: r'maxBitrateProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$maxBitrateHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef MaxBitrateRef = FutureProviderRef<int>;
String _$sourceIdHash() => r'66ed4717b4a07548f5e25a42aeac2027aeab9b9c';
/// See also [sourceId].
@ProviderFor(sourceId)
final sourceIdProvider = Provider<int>.internal(
sourceId,
name: r'sourceIdProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$sourceIdHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef SourceIdRef = ProviderRef<int>;
String _$offlineModeHash() => r'b84cdece48d97c69e995fbaea97febb128cfc20a';
/// See also [OfflineMode].
@ProviderFor(OfflineMode)
final offlineModeProvider = NotifierProvider<OfflineMode, bool>.internal(
OfflineMode.new,
name: r'offlineModeProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$offlineModeHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef _$OfflineMode = Notifier<bool>;
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions

258
lib/state/theme.dart Normal file
View File

@@ -0,0 +1,258 @@
import 'dart:async';
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:palette_generator/palette_generator.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:worker_manager/worker_manager.dart';
import '../cache/image_cache.dart';
import '../models/support.dart';
import '../services/cache_service.dart';
import 'audio.dart';
import 'music.dart';
part 'theme.g.dart';
const kDarkBackgroundValue = 0.28;
const kDarkerBackgroundLightness = 0.13;
const kOnDarkerBackgroundLightness = 0.6;
PaletteColor? _rankedByLuminance(
List<PaletteColor?> colors, [
double minLuminance = 0.0,
double maxLuminance = 1.0,
]) {
for (var color in colors) {
if (color == null) {
continue;
}
final luminance = color.color.computeLuminance();
if (luminance >= minLuminance && luminance <= maxLuminance) {
return color;
}
}
return null;
}
PaletteColor? _rankedWithValue(double value, List<PaletteColor?> colors) {
for (var color in colors) {
if (color == null) {
continue;
}
final hsv = HSVColor.fromColor(color.color);
if (hsv.value > value) {
return PaletteColor(hsv.withValue(value).toColor(), 0);
}
}
return null;
}
@riverpod
ColorTheme _colorTheme(_ColorThemeRef ref, Palette palette) {
final base = ref.watch(baseThemeProvider);
final primary = _rankedByLuminance([
palette.dominantColor,
palette.vibrantColor,
palette.mutedColor,
palette.darkVibrantColor,
], 0.2);
final vibrant = _rankedByLuminance([
palette.vibrantColor,
palette.darkVibrantColor,
palette.dominantColor,
], 0.05);
final secondary = _rankedByLuminance([
palette.lightMutedColor,
palette.mutedColor,
palette.darkMutedColor,
]);
final background = _rankedWithValue(0.5, [
palette.vibrantColor,
palette.darkVibrantColor,
palette.darkMutedColor,
palette.dominantColor,
palette.mutedColor,
palette.lightVibrantColor,
palette.lightMutedColor,
]);
final colorScheme = ColorScheme.fromSeed(
brightness: Brightness.dark,
seedColor: background?.color ?? Colors.purple[800]!,
background: background?.color,
primaryContainer: primary?.color,
onPrimaryContainer: primary?.bodyTextColor,
secondaryContainer: secondary?.color,
onSecondaryContainer: secondary?.bodyTextColor,
surface: background?.color,
surfaceTint: vibrant?.color,
);
final hsv = HSVColor.fromColor(colorScheme.background);
final hsl = HSLColor.fromColor(colorScheme.background);
return base.copyWith(
theme: ThemeData(
colorScheme: colorScheme,
useMaterial3: base.theme.useMaterial3,
brightness: base.theme.brightness,
cardTheme: base.theme.cardTheme,
),
gradientHigh: colorScheme.background,
darkBackground: hsv.withValue(kDarkBackgroundValue).toColor(),
darkerBackground: hsl.withLightness(kDarkerBackgroundLightness).toColor(),
onDarkerBackground:
hsl.withLightness(kOnDarkerBackgroundLightness).toColor(),
);
}
@riverpod
ColorTheme baseTheme(BaseThemeRef ref) {
final theme = ThemeData(
useMaterial3: true,
colorSchemeSeed: Colors.purple[800],
brightness: Brightness.dark,
cardTheme: CardTheme(
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(2),
),
),
);
final hsv = HSVColor.fromColor(theme.colorScheme.background);
final hsl = HSLColor.fromColor(theme.colorScheme.background);
return ColorTheme(
theme: theme,
gradientHigh: theme.colorScheme.background,
gradientLow: HSLColor.fromColor(theme.colorScheme.background)
.withLightness(0.06)
.toColor(),
darkBackground: hsv.withValue(kDarkBackgroundValue).toColor(),
darkerBackground: hsl.withLightness(kDarkerBackgroundLightness).toColor(),
onDarkerBackground:
hsl.withLightness(kOnDarkerBackgroundLightness).toColor(),
);
}
@riverpod
FutureOr<Palette> albumArtPalette(
AlbumArtPaletteRef ref,
String id,
) async {
final album = await ref.watch(albumProvider(id).future);
final cache = ref.watch(cacheServiceProvider);
final info = cache.albumArt(album, thumbnail: true);
return Palette.fromPaletteGenerator(await _generateFromCache(info));
}
Future<PaletteGenerator> _generateFromCache(
UriCacheInfo cacheInfo,
) async {
var file = await cacheInfo.cacheManager.getSingleFile(
cacheInfo.uri.toString(),
key: cacheInfo.cacheKey,
);
final memoryImage = ResizeImage(
MemoryImage(await file.readAsBytes()),
height: 32,
width: 32,
);
final stream = memoryImage.resolve(const ImageConfiguration(
devicePixelRatio: 1.0,
));
Completer<ui.Image> imageCompleter = Completer<ui.Image>();
late ImageStreamListener listener;
listener = ImageStreamListener((ImageInfo info, bool synchronousCall) {
stream.removeListener(listener);
imageCompleter.complete(info.image);
});
stream.addListener(listener);
final image = await imageCompleter.future;
final byteData = (await image.toByteData())!;
final height = image.height;
final width = image.width;
return await Executor().execute(
arg1: byteData,
arg2: height,
arg3: width,
fun3: _computePalette,
);
}
Future<PaletteGenerator> _computePalette(
ByteData byteData,
int height,
int width,
TypeSendPort port,
) async {
return await PaletteGenerator.fromByteData(
EncodedImage(byteData, height: height, width: width),
);
}
@riverpod
FutureOr<Palette> playlistArtPalette(
PlaylistArtPaletteRef ref,
String id,
) async {
final playlist = await ref.watch(playlistProvider(id).future);
final cache = ref.watch(cacheServiceProvider);
final info = cache.playlistArt(playlist, thumbnail: true);
return Palette.fromPaletteGenerator(await _generateFromCache(info));
}
@riverpod
FutureOr<Palette> mediaItemPalette(MediaItemPaletteRef ref) async {
final item = ref.watch(mediaItemProvider).valueOrNull;
final itemData = ref.watch(mediaItemDataProvider);
final imageCache = ref.watch(imageCacheProvider);
if (item == null || item.artUri == null || itemData == null) {
return const Palette();
}
return Palette.fromPaletteGenerator(await _generateFromCache(
UriCacheInfo(
uri: item.artUri!,
cacheKey: itemData.artCache!.thumbnailArtCacheKey,
cacheManager: imageCache,
),
));
}
@riverpod
FutureOr<ColorTheme> mediaItemTheme(MediaItemThemeRef ref) async {
final palette = await ref.watch(mediaItemPaletteProvider.future);
return ref.watch(_colorThemeProvider(palette));
}
@riverpod
FutureOr<ColorTheme> albumArtTheme(AlbumArtThemeRef ref, String id) async {
final palette = await ref.watch(albumArtPaletteProvider(id).future);
return ref.watch(_colorThemeProvider(palette));
}
@riverpod
FutureOr<ColorTheme> playlistArtTheme(
PlaylistArtThemeRef ref,
String id,
) async {
final palette = await ref.watch(playlistArtPaletteProvider(id).future);
return ref.watch(_colorThemeProvider(palette));
}

485
lib/state/theme.g.dart Normal file
View File

@@ -0,0 +1,485 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'theme.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$colorThemeHash() => r'f5cc23cb5e2af379c02ae4b9756df72f9f6da5e6';
/// Copied from Dart SDK
class _SystemHash {
_SystemHash._();
static int combine(int hash, int value) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + value);
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
return hash ^ (hash >> 6);
}
static int finish(int hash) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
// ignore: parameter_assignments
hash = hash ^ (hash >> 11);
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
}
}
typedef _ColorThemeRef = AutoDisposeProviderRef<ColorTheme>;
/// See also [_colorTheme].
@ProviderFor(_colorTheme)
const _colorThemeProvider = _ColorThemeFamily();
/// See also [_colorTheme].
class _ColorThemeFamily extends Family<ColorTheme> {
/// See also [_colorTheme].
const _ColorThemeFamily();
/// See also [_colorTheme].
_ColorThemeProvider call(
Palette palette,
) {
return _ColorThemeProvider(
palette,
);
}
@override
_ColorThemeProvider getProviderOverride(
covariant _ColorThemeProvider provider,
) {
return call(
provider.palette,
);
}
static const Iterable<ProviderOrFamily>? _dependencies = null;
@override
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
@override
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
_allTransitiveDependencies;
@override
String? get name => r'_colorThemeProvider';
}
/// See also [_colorTheme].
class _ColorThemeProvider extends AutoDisposeProvider<ColorTheme> {
/// See also [_colorTheme].
_ColorThemeProvider(
this.palette,
) : super.internal(
(ref) => _colorTheme(
ref,
palette,
),
from: _colorThemeProvider,
name: r'_colorThemeProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$colorThemeHash,
dependencies: _ColorThemeFamily._dependencies,
allTransitiveDependencies:
_ColorThemeFamily._allTransitiveDependencies,
);
final Palette palette;
@override
bool operator ==(Object other) {
return other is _ColorThemeProvider && other.palette == palette;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, palette.hashCode);
return _SystemHash.finish(hash);
}
}
String _$baseThemeHash() => r'317a5ef77def208357a54b7938ef3d91666fce70';
/// See also [baseTheme].
@ProviderFor(baseTheme)
final baseThemeProvider = AutoDisposeProvider<ColorTheme>.internal(
baseTheme,
name: r'baseThemeProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$baseThemeHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef BaseThemeRef = AutoDisposeProviderRef<ColorTheme>;
String _$albumArtPaletteHash() => r'8130b954ee3c67f53207593d4ed3dfbffb00c95d';
typedef AlbumArtPaletteRef = AutoDisposeFutureProviderRef<Palette>;
/// See also [albumArtPalette].
@ProviderFor(albumArtPalette)
const albumArtPaletteProvider = AlbumArtPaletteFamily();
/// See also [albumArtPalette].
class AlbumArtPaletteFamily extends Family<AsyncValue<Palette>> {
/// See also [albumArtPalette].
const AlbumArtPaletteFamily();
/// See also [albumArtPalette].
AlbumArtPaletteProvider call(
String id,
) {
return AlbumArtPaletteProvider(
id,
);
}
@override
AlbumArtPaletteProvider getProviderOverride(
covariant AlbumArtPaletteProvider provider,
) {
return call(
provider.id,
);
}
static const Iterable<ProviderOrFamily>? _dependencies = null;
@override
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
@override
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
_allTransitiveDependencies;
@override
String? get name => r'albumArtPaletteProvider';
}
/// See also [albumArtPalette].
class AlbumArtPaletteProvider extends AutoDisposeFutureProvider<Palette> {
/// See also [albumArtPalette].
AlbumArtPaletteProvider(
this.id,
) : super.internal(
(ref) => albumArtPalette(
ref,
id,
),
from: albumArtPaletteProvider,
name: r'albumArtPaletteProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$albumArtPaletteHash,
dependencies: AlbumArtPaletteFamily._dependencies,
allTransitiveDependencies:
AlbumArtPaletteFamily._allTransitiveDependencies,
);
final String id;
@override
bool operator ==(Object other) {
return other is AlbumArtPaletteProvider && other.id == id;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, id.hashCode);
return _SystemHash.finish(hash);
}
}
String _$playlistArtPaletteHash() =>
r'6bc015688f354ea8d91dde86e2a7191ef1ef6496';
typedef PlaylistArtPaletteRef = AutoDisposeFutureProviderRef<Palette>;
/// See also [playlistArtPalette].
@ProviderFor(playlistArtPalette)
const playlistArtPaletteProvider = PlaylistArtPaletteFamily();
/// See also [playlistArtPalette].
class PlaylistArtPaletteFamily extends Family<AsyncValue<Palette>> {
/// See also [playlistArtPalette].
const PlaylistArtPaletteFamily();
/// See also [playlistArtPalette].
PlaylistArtPaletteProvider call(
String id,
) {
return PlaylistArtPaletteProvider(
id,
);
}
@override
PlaylistArtPaletteProvider getProviderOverride(
covariant PlaylistArtPaletteProvider provider,
) {
return call(
provider.id,
);
}
static const Iterable<ProviderOrFamily>? _dependencies = null;
@override
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
@override
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
_allTransitiveDependencies;
@override
String? get name => r'playlistArtPaletteProvider';
}
/// See also [playlistArtPalette].
class PlaylistArtPaletteProvider extends AutoDisposeFutureProvider<Palette> {
/// See also [playlistArtPalette].
PlaylistArtPaletteProvider(
this.id,
) : super.internal(
(ref) => playlistArtPalette(
ref,
id,
),
from: playlistArtPaletteProvider,
name: r'playlistArtPaletteProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$playlistArtPaletteHash,
dependencies: PlaylistArtPaletteFamily._dependencies,
allTransitiveDependencies:
PlaylistArtPaletteFamily._allTransitiveDependencies,
);
final String id;
@override
bool operator ==(Object other) {
return other is PlaylistArtPaletteProvider && other.id == id;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, id.hashCode);
return _SystemHash.finish(hash);
}
}
String _$mediaItemPaletteHash() => r'2f2744aa735c6056919197c283a367714d7e04e4';
/// See also [mediaItemPalette].
@ProviderFor(mediaItemPalette)
final mediaItemPaletteProvider = AutoDisposeFutureProvider<Palette>.internal(
mediaItemPalette,
name: r'mediaItemPaletteProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$mediaItemPaletteHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef MediaItemPaletteRef = AutoDisposeFutureProviderRef<Palette>;
String _$mediaItemThemeHash() => r'f43e6f86eeed7aef33fa8bd2695454a760f41afa';
/// See also [mediaItemTheme].
@ProviderFor(mediaItemTheme)
final mediaItemThemeProvider = AutoDisposeFutureProvider<ColorTheme>.internal(
mediaItemTheme,
name: r'mediaItemThemeProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$mediaItemThemeHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef MediaItemThemeRef = AutoDisposeFutureProviderRef<ColorTheme>;
String _$albumArtThemeHash() => r'd3ee71b2df856f1763ec925e158ae2e0f613b9e0';
typedef AlbumArtThemeRef = AutoDisposeFutureProviderRef<ColorTheme>;
/// See also [albumArtTheme].
@ProviderFor(albumArtTheme)
const albumArtThemeProvider = AlbumArtThemeFamily();
/// See also [albumArtTheme].
class AlbumArtThemeFamily extends Family<AsyncValue<ColorTheme>> {
/// See also [albumArtTheme].
const AlbumArtThemeFamily();
/// See also [albumArtTheme].
AlbumArtThemeProvider call(
String id,
) {
return AlbumArtThemeProvider(
id,
);
}
@override
AlbumArtThemeProvider getProviderOverride(
covariant AlbumArtThemeProvider provider,
) {
return call(
provider.id,
);
}
static const Iterable<ProviderOrFamily>? _dependencies = null;
@override
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
@override
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
_allTransitiveDependencies;
@override
String? get name => r'albumArtThemeProvider';
}
/// See also [albumArtTheme].
class AlbumArtThemeProvider extends AutoDisposeFutureProvider<ColorTheme> {
/// See also [albumArtTheme].
AlbumArtThemeProvider(
this.id,
) : super.internal(
(ref) => albumArtTheme(
ref,
id,
),
from: albumArtThemeProvider,
name: r'albumArtThemeProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$albumArtThemeHash,
dependencies: AlbumArtThemeFamily._dependencies,
allTransitiveDependencies:
AlbumArtThemeFamily._allTransitiveDependencies,
);
final String id;
@override
bool operator ==(Object other) {
return other is AlbumArtThemeProvider && other.id == id;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, id.hashCode);
return _SystemHash.finish(hash);
}
}
String _$playlistArtThemeHash() => r'1629552e1f3aa2a1e7d223ac1e078893042e5e3b';
typedef PlaylistArtThemeRef = AutoDisposeFutureProviderRef<ColorTheme>;
/// See also [playlistArtTheme].
@ProviderFor(playlistArtTheme)
const playlistArtThemeProvider = PlaylistArtThemeFamily();
/// See also [playlistArtTheme].
class PlaylistArtThemeFamily extends Family<AsyncValue<ColorTheme>> {
/// See also [playlistArtTheme].
const PlaylistArtThemeFamily();
/// See also [playlistArtTheme].
PlaylistArtThemeProvider call(
String id,
) {
return PlaylistArtThemeProvider(
id,
);
}
@override
PlaylistArtThemeProvider getProviderOverride(
covariant PlaylistArtThemeProvider provider,
) {
return call(
provider.id,
);
}
static const Iterable<ProviderOrFamily>? _dependencies = null;
@override
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
@override
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
_allTransitiveDependencies;
@override
String? get name => r'playlistArtThemeProvider';
}
/// See also [playlistArtTheme].
class PlaylistArtThemeProvider extends AutoDisposeFutureProvider<ColorTheme> {
/// See also [playlistArtTheme].
PlaylistArtThemeProvider(
this.id,
) : super.internal(
(ref) => playlistArtTheme(
ref,
id,
),
from: playlistArtThemeProvider,
name: r'playlistArtThemeProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$playlistArtThemeHash,
dependencies: PlaylistArtThemeFamily._dependencies,
allTransitiveDependencies:
PlaylistArtThemeFamily._allTransitiveDependencies,
);
final String id;
@override
bool operator ==(Object other) {
return other is PlaylistArtThemeProvider && other.id == id;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, id.hashCode);
return _SystemHash.finish(hash);
}
}
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions