mirror of
https://github.com/KRTirtho/spotube.git
synced 2026-05-08 16:24:36 +00:00
feat: add playlist related providers
This commit is contained in:
parent
1d580e8b6a
commit
91c6ddbc2d
27
lib/models/spotify/recommendation_seeds.dart
Normal file
27
lib/models/spotify/recommendation_seeds.dart
Normal file
@ -0,0 +1,27 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'recommendation_seeds.freezed.dart';
|
||||
part 'recommendation_seeds.g.dart';
|
||||
|
||||
@freezed
|
||||
class RecommendationSeeds with _$RecommendationSeeds {
|
||||
factory RecommendationSeeds(
|
||||
num? acousticness,
|
||||
num? danceability,
|
||||
@JsonKey(name: "duration_ms") num? durationMs,
|
||||
num? energy,
|
||||
num? instrumentalness,
|
||||
num? key,
|
||||
num? liveness,
|
||||
num? loudness,
|
||||
num? mode,
|
||||
num? popularity,
|
||||
num? speechiness,
|
||||
num? tempo,
|
||||
@JsonKey(name: "time_signature") num? timeSignature,
|
||||
num? valence,
|
||||
) = _RecommendationSeeds;
|
||||
|
||||
factory RecommendationSeeds.fromJson(Map<String, dynamic> json) =>
|
||||
_$RecommendationSeedsFromJson(json);
|
||||
}
|
||||
446
lib/models/spotify/recommendation_seeds.freezed.dart
Normal file
446
lib/models/spotify/recommendation_seeds.freezed.dart
Normal file
@ -0,0 +1,446 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'recommendation_seeds.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
|
||||
|
||||
RecommendationSeeds _$RecommendationSeedsFromJson(Map<String, dynamic> json) {
|
||||
return _RecommendationSeeds.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$RecommendationSeeds {
|
||||
num? get acousticness => throw _privateConstructorUsedError;
|
||||
num? get danceability => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "duration_ms")
|
||||
num? get durationMs => throw _privateConstructorUsedError;
|
||||
num? get energy => throw _privateConstructorUsedError;
|
||||
num? get instrumentalness => throw _privateConstructorUsedError;
|
||||
num? get key => throw _privateConstructorUsedError;
|
||||
num? get liveness => throw _privateConstructorUsedError;
|
||||
num? get loudness => throw _privateConstructorUsedError;
|
||||
num? get mode => throw _privateConstructorUsedError;
|
||||
num? get popularity => throw _privateConstructorUsedError;
|
||||
num? get speechiness => throw _privateConstructorUsedError;
|
||||
num? get tempo => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "time_signature")
|
||||
num? get timeSignature => throw _privateConstructorUsedError;
|
||||
num? get valence => throw _privateConstructorUsedError;
|
||||
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
$RecommendationSeedsCopyWith<RecommendationSeeds> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $RecommendationSeedsCopyWith<$Res> {
|
||||
factory $RecommendationSeedsCopyWith(
|
||||
RecommendationSeeds value, $Res Function(RecommendationSeeds) then) =
|
||||
_$RecommendationSeedsCopyWithImpl<$Res, RecommendationSeeds>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{num? acousticness,
|
||||
num? danceability,
|
||||
@JsonKey(name: "duration_ms") num? durationMs,
|
||||
num? energy,
|
||||
num? instrumentalness,
|
||||
num? key,
|
||||
num? liveness,
|
||||
num? loudness,
|
||||
num? mode,
|
||||
num? popularity,
|
||||
num? speechiness,
|
||||
num? tempo,
|
||||
@JsonKey(name: "time_signature") num? timeSignature,
|
||||
num? valence});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$RecommendationSeedsCopyWithImpl<$Res, $Val extends RecommendationSeeds>
|
||||
implements $RecommendationSeedsCopyWith<$Res> {
|
||||
_$RecommendationSeedsCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? acousticness = freezed,
|
||||
Object? danceability = freezed,
|
||||
Object? durationMs = freezed,
|
||||
Object? energy = freezed,
|
||||
Object? instrumentalness = freezed,
|
||||
Object? key = freezed,
|
||||
Object? liveness = freezed,
|
||||
Object? loudness = freezed,
|
||||
Object? mode = freezed,
|
||||
Object? popularity = freezed,
|
||||
Object? speechiness = freezed,
|
||||
Object? tempo = freezed,
|
||||
Object? timeSignature = freezed,
|
||||
Object? valence = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
acousticness: freezed == acousticness
|
||||
? _value.acousticness
|
||||
: acousticness // ignore: cast_nullable_to_non_nullable
|
||||
as num?,
|
||||
danceability: freezed == danceability
|
||||
? _value.danceability
|
||||
: danceability // ignore: cast_nullable_to_non_nullable
|
||||
as num?,
|
||||
durationMs: freezed == durationMs
|
||||
? _value.durationMs
|
||||
: durationMs // ignore: cast_nullable_to_non_nullable
|
||||
as num?,
|
||||
energy: freezed == energy
|
||||
? _value.energy
|
||||
: energy // ignore: cast_nullable_to_non_nullable
|
||||
as num?,
|
||||
instrumentalness: freezed == instrumentalness
|
||||
? _value.instrumentalness
|
||||
: instrumentalness // ignore: cast_nullable_to_non_nullable
|
||||
as num?,
|
||||
key: freezed == key
|
||||
? _value.key
|
||||
: key // ignore: cast_nullable_to_non_nullable
|
||||
as num?,
|
||||
liveness: freezed == liveness
|
||||
? _value.liveness
|
||||
: liveness // ignore: cast_nullable_to_non_nullable
|
||||
as num?,
|
||||
loudness: freezed == loudness
|
||||
? _value.loudness
|
||||
: loudness // ignore: cast_nullable_to_non_nullable
|
||||
as num?,
|
||||
mode: freezed == mode
|
||||
? _value.mode
|
||||
: mode // ignore: cast_nullable_to_non_nullable
|
||||
as num?,
|
||||
popularity: freezed == popularity
|
||||
? _value.popularity
|
||||
: popularity // ignore: cast_nullable_to_non_nullable
|
||||
as num?,
|
||||
speechiness: freezed == speechiness
|
||||
? _value.speechiness
|
||||
: speechiness // ignore: cast_nullable_to_non_nullable
|
||||
as num?,
|
||||
tempo: freezed == tempo
|
||||
? _value.tempo
|
||||
: tempo // ignore: cast_nullable_to_non_nullable
|
||||
as num?,
|
||||
timeSignature: freezed == timeSignature
|
||||
? _value.timeSignature
|
||||
: timeSignature // ignore: cast_nullable_to_non_nullable
|
||||
as num?,
|
||||
valence: freezed == valence
|
||||
? _value.valence
|
||||
: valence // ignore: cast_nullable_to_non_nullable
|
||||
as num?,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$RecommendationSeedsImplCopyWith<$Res>
|
||||
implements $RecommendationSeedsCopyWith<$Res> {
|
||||
factory _$$RecommendationSeedsImplCopyWith(_$RecommendationSeedsImpl value,
|
||||
$Res Function(_$RecommendationSeedsImpl) then) =
|
||||
__$$RecommendationSeedsImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{num? acousticness,
|
||||
num? danceability,
|
||||
@JsonKey(name: "duration_ms") num? durationMs,
|
||||
num? energy,
|
||||
num? instrumentalness,
|
||||
num? key,
|
||||
num? liveness,
|
||||
num? loudness,
|
||||
num? mode,
|
||||
num? popularity,
|
||||
num? speechiness,
|
||||
num? tempo,
|
||||
@JsonKey(name: "time_signature") num? timeSignature,
|
||||
num? valence});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$RecommendationSeedsImplCopyWithImpl<$Res>
|
||||
extends _$RecommendationSeedsCopyWithImpl<$Res, _$RecommendationSeedsImpl>
|
||||
implements _$$RecommendationSeedsImplCopyWith<$Res> {
|
||||
__$$RecommendationSeedsImplCopyWithImpl(_$RecommendationSeedsImpl _value,
|
||||
$Res Function(_$RecommendationSeedsImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? acousticness = freezed,
|
||||
Object? danceability = freezed,
|
||||
Object? durationMs = freezed,
|
||||
Object? energy = freezed,
|
||||
Object? instrumentalness = freezed,
|
||||
Object? key = freezed,
|
||||
Object? liveness = freezed,
|
||||
Object? loudness = freezed,
|
||||
Object? mode = freezed,
|
||||
Object? popularity = freezed,
|
||||
Object? speechiness = freezed,
|
||||
Object? tempo = freezed,
|
||||
Object? timeSignature = freezed,
|
||||
Object? valence = freezed,
|
||||
}) {
|
||||
return _then(_$RecommendationSeedsImpl(
|
||||
freezed == acousticness
|
||||
? _value.acousticness
|
||||
: acousticness // ignore: cast_nullable_to_non_nullable
|
||||
as num?,
|
||||
freezed == danceability
|
||||
? _value.danceability
|
||||
: danceability // ignore: cast_nullable_to_non_nullable
|
||||
as num?,
|
||||
freezed == durationMs
|
||||
? _value.durationMs
|
||||
: durationMs // ignore: cast_nullable_to_non_nullable
|
||||
as num?,
|
||||
freezed == energy
|
||||
? _value.energy
|
||||
: energy // ignore: cast_nullable_to_non_nullable
|
||||
as num?,
|
||||
freezed == instrumentalness
|
||||
? _value.instrumentalness
|
||||
: instrumentalness // ignore: cast_nullable_to_non_nullable
|
||||
as num?,
|
||||
freezed == key
|
||||
? _value.key
|
||||
: key // ignore: cast_nullable_to_non_nullable
|
||||
as num?,
|
||||
freezed == liveness
|
||||
? _value.liveness
|
||||
: liveness // ignore: cast_nullable_to_non_nullable
|
||||
as num?,
|
||||
freezed == loudness
|
||||
? _value.loudness
|
||||
: loudness // ignore: cast_nullable_to_non_nullable
|
||||
as num?,
|
||||
freezed == mode
|
||||
? _value.mode
|
||||
: mode // ignore: cast_nullable_to_non_nullable
|
||||
as num?,
|
||||
freezed == popularity
|
||||
? _value.popularity
|
||||
: popularity // ignore: cast_nullable_to_non_nullable
|
||||
as num?,
|
||||
freezed == speechiness
|
||||
? _value.speechiness
|
||||
: speechiness // ignore: cast_nullable_to_non_nullable
|
||||
as num?,
|
||||
freezed == tempo
|
||||
? _value.tempo
|
||||
: tempo // ignore: cast_nullable_to_non_nullable
|
||||
as num?,
|
||||
freezed == timeSignature
|
||||
? _value.timeSignature
|
||||
: timeSignature // ignore: cast_nullable_to_non_nullable
|
||||
as num?,
|
||||
freezed == valence
|
||||
? _value.valence
|
||||
: valence // ignore: cast_nullable_to_non_nullable
|
||||
as num?,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$RecommendationSeedsImpl implements _RecommendationSeeds {
|
||||
_$RecommendationSeedsImpl(
|
||||
this.acousticness,
|
||||
this.danceability,
|
||||
@JsonKey(name: "duration_ms") this.durationMs,
|
||||
this.energy,
|
||||
this.instrumentalness,
|
||||
this.key,
|
||||
this.liveness,
|
||||
this.loudness,
|
||||
this.mode,
|
||||
this.popularity,
|
||||
this.speechiness,
|
||||
this.tempo,
|
||||
@JsonKey(name: "time_signature") this.timeSignature,
|
||||
this.valence);
|
||||
|
||||
factory _$RecommendationSeedsImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$RecommendationSeedsImplFromJson(json);
|
||||
|
||||
@override
|
||||
final num? acousticness;
|
||||
@override
|
||||
final num? danceability;
|
||||
@override
|
||||
@JsonKey(name: "duration_ms")
|
||||
final num? durationMs;
|
||||
@override
|
||||
final num? energy;
|
||||
@override
|
||||
final num? instrumentalness;
|
||||
@override
|
||||
final num? key;
|
||||
@override
|
||||
final num? liveness;
|
||||
@override
|
||||
final num? loudness;
|
||||
@override
|
||||
final num? mode;
|
||||
@override
|
||||
final num? popularity;
|
||||
@override
|
||||
final num? speechiness;
|
||||
@override
|
||||
final num? tempo;
|
||||
@override
|
||||
@JsonKey(name: "time_signature")
|
||||
final num? timeSignature;
|
||||
@override
|
||||
final num? valence;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'RecommendationSeeds(acousticness: $acousticness, danceability: $danceability, durationMs: $durationMs, energy: $energy, instrumentalness: $instrumentalness, key: $key, liveness: $liveness, loudness: $loudness, mode: $mode, popularity: $popularity, speechiness: $speechiness, tempo: $tempo, timeSignature: $timeSignature, valence: $valence)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$RecommendationSeedsImpl &&
|
||||
(identical(other.acousticness, acousticness) ||
|
||||
other.acousticness == acousticness) &&
|
||||
(identical(other.danceability, danceability) ||
|
||||
other.danceability == danceability) &&
|
||||
(identical(other.durationMs, durationMs) ||
|
||||
other.durationMs == durationMs) &&
|
||||
(identical(other.energy, energy) || other.energy == energy) &&
|
||||
(identical(other.instrumentalness, instrumentalness) ||
|
||||
other.instrumentalness == instrumentalness) &&
|
||||
(identical(other.key, key) || other.key == key) &&
|
||||
(identical(other.liveness, liveness) ||
|
||||
other.liveness == liveness) &&
|
||||
(identical(other.loudness, loudness) ||
|
||||
other.loudness == loudness) &&
|
||||
(identical(other.mode, mode) || other.mode == mode) &&
|
||||
(identical(other.popularity, popularity) ||
|
||||
other.popularity == popularity) &&
|
||||
(identical(other.speechiness, speechiness) ||
|
||||
other.speechiness == speechiness) &&
|
||||
(identical(other.tempo, tempo) || other.tempo == tempo) &&
|
||||
(identical(other.timeSignature, timeSignature) ||
|
||||
other.timeSignature == timeSignature) &&
|
||||
(identical(other.valence, valence) || other.valence == valence));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
acousticness,
|
||||
danceability,
|
||||
durationMs,
|
||||
energy,
|
||||
instrumentalness,
|
||||
key,
|
||||
liveness,
|
||||
loudness,
|
||||
mode,
|
||||
popularity,
|
||||
speechiness,
|
||||
tempo,
|
||||
timeSignature,
|
||||
valence);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$RecommendationSeedsImplCopyWith<_$RecommendationSeedsImpl> get copyWith =>
|
||||
__$$RecommendationSeedsImplCopyWithImpl<_$RecommendationSeedsImpl>(
|
||||
this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$RecommendationSeedsImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _RecommendationSeeds implements RecommendationSeeds {
|
||||
factory _RecommendationSeeds(
|
||||
final num? acousticness,
|
||||
final num? danceability,
|
||||
@JsonKey(name: "duration_ms") final num? durationMs,
|
||||
final num? energy,
|
||||
final num? instrumentalness,
|
||||
final num? key,
|
||||
final num? liveness,
|
||||
final num? loudness,
|
||||
final num? mode,
|
||||
final num? popularity,
|
||||
final num? speechiness,
|
||||
final num? tempo,
|
||||
@JsonKey(name: "time_signature") final num? timeSignature,
|
||||
final num? valence) = _$RecommendationSeedsImpl;
|
||||
|
||||
factory _RecommendationSeeds.fromJson(Map<String, dynamic> json) =
|
||||
_$RecommendationSeedsImpl.fromJson;
|
||||
|
||||
@override
|
||||
num? get acousticness;
|
||||
@override
|
||||
num? get danceability;
|
||||
@override
|
||||
@JsonKey(name: "duration_ms")
|
||||
num? get durationMs;
|
||||
@override
|
||||
num? get energy;
|
||||
@override
|
||||
num? get instrumentalness;
|
||||
@override
|
||||
num? get key;
|
||||
@override
|
||||
num? get liveness;
|
||||
@override
|
||||
num? get loudness;
|
||||
@override
|
||||
num? get mode;
|
||||
@override
|
||||
num? get popularity;
|
||||
@override
|
||||
num? get speechiness;
|
||||
@override
|
||||
num? get tempo;
|
||||
@override
|
||||
@JsonKey(name: "time_signature")
|
||||
num? get timeSignature;
|
||||
@override
|
||||
num? get valence;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$RecommendationSeedsImplCopyWith<_$RecommendationSeedsImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
45
lib/models/spotify/recommendation_seeds.g.dart
Normal file
45
lib/models/spotify/recommendation_seeds.g.dart
Normal file
@ -0,0 +1,45 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'recommendation_seeds.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$RecommendationSeedsImpl _$$RecommendationSeedsImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$RecommendationSeedsImpl(
|
||||
json['acousticness'] as num?,
|
||||
json['danceability'] as num?,
|
||||
json['duration_ms'] as num?,
|
||||
json['energy'] as num?,
|
||||
json['instrumentalness'] as num?,
|
||||
json['key'] as num?,
|
||||
json['liveness'] as num?,
|
||||
json['loudness'] as num?,
|
||||
json['mode'] as num?,
|
||||
json['popularity'] as num?,
|
||||
json['speechiness'] as num?,
|
||||
json['tempo'] as num?,
|
||||
json['time_signature'] as num?,
|
||||
json['valence'] as num?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$RecommendationSeedsImplToJson(
|
||||
_$RecommendationSeedsImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'acousticness': instance.acousticness,
|
||||
'danceability': instance.danceability,
|
||||
'duration_ms': instance.durationMs,
|
||||
'energy': instance.energy,
|
||||
'instrumentalness': instance.instrumentalness,
|
||||
'key': instance.key,
|
||||
'liveness': instance.liveness,
|
||||
'loudness': instance.loudness,
|
||||
'mode': instance.mode,
|
||||
'popularity': instance.popularity,
|
||||
'speechiness': instance.speechiness,
|
||||
'tempo': instance.tempo,
|
||||
'time_signature': instance.timeSignature,
|
||||
'valence': instance.valence,
|
||||
};
|
||||
81
lib/provider/spotify/playlist/favorite.dart
Normal file
81
lib/provider/spotify/playlist/favorite.dart
Normal file
@ -0,0 +1,81 @@
|
||||
part of '../spotify.dart';
|
||||
|
||||
class FavoritePlaylistsState extends PaginatedState<PlaylistSimple> {
|
||||
FavoritePlaylistsState({
|
||||
required super.items,
|
||||
required super.offset,
|
||||
required super.limit,
|
||||
required super.hasMore,
|
||||
});
|
||||
|
||||
@override
|
||||
FavoritePlaylistsState copyWith({
|
||||
List<PlaylistSimple>? items,
|
||||
int? offset,
|
||||
int? limit,
|
||||
bool? hasMore,
|
||||
}) {
|
||||
return FavoritePlaylistsState(
|
||||
items: items ?? this.items,
|
||||
offset: offset ?? this.offset,
|
||||
limit: limit ?? this.limit,
|
||||
hasMore: hasMore ?? this.hasMore,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class FavoritePlaylistsNotifier
|
||||
extends PaginatedAsyncNotifier<PlaylistSimple, FavoritePlaylistsState> {
|
||||
FavoritePlaylistsNotifier() : super();
|
||||
|
||||
@override
|
||||
fetch(int offset, int limit) async {
|
||||
final playlists = await spotify.playlists.me.getPage(
|
||||
limit,
|
||||
offset,
|
||||
);
|
||||
|
||||
return playlists.items?.toList() ?? [];
|
||||
}
|
||||
|
||||
@override
|
||||
build() async {
|
||||
ref.watch(spotifyProvider);
|
||||
final playlists = await fetch(0, 20);
|
||||
|
||||
return FavoritePlaylistsState(
|
||||
items: playlists,
|
||||
offset: 0,
|
||||
limit: 20,
|
||||
hasMore: playlists.length == 20,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
final favoritePlaylistsProvider =
|
||||
AsyncNotifierProvider<FavoritePlaylistsNotifier, FavoritePlaylistsState>(
|
||||
() => FavoritePlaylistsNotifier(),
|
||||
);
|
||||
|
||||
final allFavoritePlaylistsProvider = FutureProvider<List<PlaylistSimple>>(
|
||||
(ref) async {
|
||||
final spotify = ref.watch(spotifyProvider);
|
||||
return (await spotify.playlists.me.all()).toList();
|
||||
},
|
||||
);
|
||||
|
||||
final isFavoritePlaylistProvider = FutureProvider.family<bool, String>(
|
||||
(ref, id) async {
|
||||
final spotify = ref.watch(spotifyProvider);
|
||||
final me = ref.watch(meProvider);
|
||||
|
||||
if (me.value == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final follows =
|
||||
await spotify.playlists.followedByUsers(id, [me.value!.id!]);
|
||||
|
||||
return follows[me.value!.id!] ?? false;
|
||||
},
|
||||
);
|
||||
58
lib/provider/spotify/playlist/featured.dart
Normal file
58
lib/provider/spotify/playlist/featured.dart
Normal file
@ -0,0 +1,58 @@
|
||||
part of '../spotify.dart';
|
||||
|
||||
class FeaturedPlaylistsState extends PaginatedState<PlaylistSimple> {
|
||||
FeaturedPlaylistsState({
|
||||
required super.items,
|
||||
required super.offset,
|
||||
required super.limit,
|
||||
required super.hasMore,
|
||||
});
|
||||
|
||||
@override
|
||||
FeaturedPlaylistsState copyWith({
|
||||
List<PlaylistSimple>? items,
|
||||
int? offset,
|
||||
int? limit,
|
||||
bool? hasMore,
|
||||
}) {
|
||||
return FeaturedPlaylistsState(
|
||||
items: items ?? this.items,
|
||||
offset: offset ?? this.offset,
|
||||
limit: limit ?? this.limit,
|
||||
hasMore: hasMore ?? this.hasMore,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class FeaturedPlaylistsNotifier
|
||||
extends PaginatedAsyncNotifier<PlaylistSimple, FeaturedPlaylistsState> {
|
||||
FeaturedPlaylistsNotifier() : super();
|
||||
|
||||
@override
|
||||
fetch(int offset, int limit) async {
|
||||
final playlists = await spotify.playlists.featured.getPage(
|
||||
limit,
|
||||
offset,
|
||||
);
|
||||
|
||||
return playlists.items?.toList() ?? [];
|
||||
}
|
||||
|
||||
@override
|
||||
build() async {
|
||||
ref.watch(spotifyProvider);
|
||||
final playlists = await fetch(0, 20);
|
||||
|
||||
return FeaturedPlaylistsState(
|
||||
items: playlists,
|
||||
offset: 0,
|
||||
limit: 20,
|
||||
hasMore: playlists.length == 20,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
final featuredPlaylistsProvider =
|
||||
AsyncNotifierProvider<FeaturedPlaylistsNotifier, FeaturedPlaylistsState>(
|
||||
() => FeaturedPlaylistsNotifier(),
|
||||
);
|
||||
34
lib/provider/spotify/playlist/generate.dart
Normal file
34
lib/provider/spotify/playlist/generate.dart
Normal file
@ -0,0 +1,34 @@
|
||||
part of '../spotify.dart';
|
||||
|
||||
typedef GeneratePlaylistProviderInput = ({
|
||||
Iterable<String>? seedArtists,
|
||||
Iterable<String>? seedGenres,
|
||||
Iterable<String>? seedTracks,
|
||||
int limit,
|
||||
RecommendationSeeds? max,
|
||||
RecommendationSeeds? min,
|
||||
RecommendationSeeds? target,
|
||||
});
|
||||
|
||||
final generatePlaylistProvider =
|
||||
FutureProvider.family<List<TrackSimple>, GeneratePlaylistProviderInput>(
|
||||
(ref, input) async {
|
||||
final spotify = ref.watch(spotifyProvider);
|
||||
final market = ref.watch(
|
||||
userPreferencesProvider.select((s) => s.recommendationMarket),
|
||||
);
|
||||
|
||||
final recommendation = await spotify.recommendations.get(
|
||||
limit: input.limit,
|
||||
seedArtists: input.seedArtists?.toList(),
|
||||
seedGenres: input.seedGenres?.toList(),
|
||||
seedTracks: input.seedTracks?.toList(),
|
||||
market: market,
|
||||
max: input.max?.toJson().cast<String, num>(),
|
||||
min: input.min?.toJson().cast<String, num>(),
|
||||
target: input.target?.toJson().cast<String, num>(),
|
||||
);
|
||||
|
||||
return recommendation.tracks?.toList() ?? [];
|
||||
},
|
||||
);
|
||||
8
lib/provider/spotify/playlist/liked.dart
Normal file
8
lib/provider/spotify/playlist/liked.dart
Normal file
@ -0,0 +1,8 @@
|
||||
part of '../spotify.dart';
|
||||
|
||||
final likedTracksProvider = FutureProvider<List<Track>>((ref) async {
|
||||
final spotify = ref.watch(spotifyProvider);
|
||||
final savedTracked = await spotify.tracks.me.saved.all();
|
||||
|
||||
return savedTracked.map((e) => e.track!).toList();
|
||||
});
|
||||
8
lib/provider/spotify/playlist/playlist.dart
Normal file
8
lib/provider/spotify/playlist/playlist.dart
Normal file
@ -0,0 +1,8 @@
|
||||
part of '../spotify.dart';
|
||||
|
||||
final playlistProvider = FutureProvider.family<Playlist, String>(
|
||||
(ref, playlistId) async {
|
||||
final spotify = ref.watch(spotifyProvider);
|
||||
return spotify.playlists.get(playlistId);
|
||||
},
|
||||
);
|
||||
57
lib/provider/spotify/playlist/tracks.dart
Normal file
57
lib/provider/spotify/playlist/tracks.dart
Normal file
@ -0,0 +1,57 @@
|
||||
part of '../spotify.dart';
|
||||
|
||||
class PlaylistTracksState extends PaginatedState<Track> {
|
||||
PlaylistTracksState({
|
||||
required super.items,
|
||||
required super.offset,
|
||||
required super.limit,
|
||||
required super.hasMore,
|
||||
});
|
||||
|
||||
@override
|
||||
PlaylistTracksState copyWith({
|
||||
List<Track>? items,
|
||||
int? offset,
|
||||
int? limit,
|
||||
bool? hasMore,
|
||||
}) {
|
||||
return PlaylistTracksState(
|
||||
items: items ?? this.items,
|
||||
offset: offset ?? this.offset,
|
||||
limit: limit ?? this.limit,
|
||||
hasMore: hasMore ?? this.hasMore,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PlaylistTracksNotifier
|
||||
extends FamilyPaginatedAsyncNotifier<Track, PlaylistTracksState, String> {
|
||||
PlaylistTracksNotifier() : super();
|
||||
|
||||
@override
|
||||
fetch(arg, offset, limit) async {
|
||||
final tracks = await spotify.playlists
|
||||
.getTracksByPlaylistId(arg)
|
||||
.getPage(limit, offset);
|
||||
|
||||
return tracks.items?.toList() ?? <Track>[];
|
||||
}
|
||||
|
||||
@override
|
||||
build(arg) async {
|
||||
ref.watch(spotifyProvider);
|
||||
final tracks = await fetch(arg, 0, 20);
|
||||
|
||||
return PlaylistTracksState(
|
||||
items: tracks,
|
||||
offset: 0,
|
||||
limit: 20,
|
||||
hasMore: tracks.length == 20,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
final playlistTracksProvider = AsyncNotifierProviderFamily<
|
||||
PlaylistTracksNotifier, PlaylistTracksState, String>(
|
||||
() => PlaylistTracksNotifier(),
|
||||
);
|
||||
@ -12,6 +12,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:riverpod/src/async_notifier.dart';
|
||||
import 'package:spotube/extensions/map.dart';
|
||||
import 'package:spotube/models/lyrics.dart';
|
||||
import 'package:spotube/models/spotify/recommendation_seeds.dart';
|
||||
import 'package:spotube/provider/custom_spotify_endpoint_provider.dart';
|
||||
import 'package:spotube/provider/spotify_provider.dart';
|
||||
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
|
||||
@ -35,6 +36,15 @@ part 'category/playlists.dart';
|
||||
|
||||
part 'lyrics/synced.dart';
|
||||
|
||||
part 'playlist/favorite.dart';
|
||||
part 'playlist/playlist.dart';
|
||||
part 'playlist/liked.dart';
|
||||
part 'playlist/tracks.dart';
|
||||
part 'playlist/featured.dart';
|
||||
part 'playlist/generate.dart';
|
||||
|
||||
part 'user/me.dart';
|
||||
|
||||
part 'utils/mixin.dart';
|
||||
part 'utils/state.dart';
|
||||
part 'utils/provider.dart';
|
||||
|
||||
6
lib/provider/spotify/user/me.dart
Normal file
6
lib/provider/spotify/user/me.dart
Normal file
@ -0,0 +1,6 @@
|
||||
part of '../spotify.dart';
|
||||
|
||||
final meProvider = FutureProvider<User>((ref) async {
|
||||
final spotify = ref.watch(spotifyProvider);
|
||||
return spotify.me.get();
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user