Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor playOrResume #187

Merged
merged 4 commits into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 78 additions & 16 deletions lib/src/endpoints/player.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ class PlayerEndpoint extends _MeEndpointBase {
/// will be retrieved after setting the volume. Defaults to true.
Future<PlaybackState?> shuffle(bool state,
{String? deviceId, bool retrievePlaybackState = true}) async {
await _api._put('$_path/shuffle?' +
_buildQuery({'state': state, 'deviceId': deviceId}));
await _api._put('$_path/shuffle?${_buildQuery({
'state': state,
'deviceId': deviceId
})}');

return retrievePlaybackState ? playbackState() : null;
}
Expand All @@ -34,8 +36,8 @@ class PlayerEndpoint extends _MeEndpointBase {
/// Returns the current playback state, including progress, track
/// and active device.
Future<PlaybackState> playbackState([Market? market]) async {
var jsonString = await _api
._get('$_path?' + _buildQuery({'market': market?.name}));
var jsonString =
await _api._get('$_path?${_buildQuery({'market': market?.name})}');
final map = json.decode(jsonString);
return PlaybackState.fromJson(map);
}
Expand Down Expand Up @@ -87,6 +89,8 @@ class PlayerEndpoint extends _MeEndpointBase {
/// from the context's current track.
/// [retrievePlaybackState] is optional. If true, the current playback state
/// will be retrieved. Defaults to true.
@Deprecated(
"Use `startWithTracks()` or `startWithContext()` to start a new context and resume() instead")
Future<PlaybackState?> startOrResume(
{String? deviceId,
StartOrResumeOptions? options,
Expand All @@ -95,19 +99,74 @@ class PlayerEndpoint extends _MeEndpointBase {
var json = jsonEncode(body ?? '');

await _api._put(
'$_path/play?' + _buildQuery({'device_id': deviceId}), json);
'$_path/play?${_buildQuery({'device_id': deviceId})}', json);

return retrievePlaybackState ? playbackState() : null;
}

/// Start a new playback context with given [trackUris] and with given optional
/// [deviceId]. If not provided, the user's currently active device
/// is the target. Playback can also start at [positionMs], which is set to `0`
/// by default.
/// [retrievePlaybackState] is optional. If `true`, the current [PlaybackState]
/// will be retrieved. Default's to `true`.
///
/// Note: Before starting a new playback context check the [playbackState]
/// if necessary before [resume]ing, otherwise you overwrite the current
/// context.
Future<PlaybackState?> startWithTracks(List<String> trackUris,
{String? deviceId,
int positionMs = 0,
bool retrievePlaybackState = true}) async {
assert(trackUris.isNotEmpty, 'Cannot start playback with empty track uris');
assert(positionMs >= 0, 'Position must be greater than or equal to 0');

var options = StartOrResumeOptions(uris: trackUris, positionMs: positionMs);
return startOrResume(
deviceId: deviceId,
options: options,
retrievePlaybackState: retrievePlaybackState);
}

/// Start a new playback context (album, playlist) with given a [contextUri].
/// and given optional [deviceId]. If not provided, the user's currently active
/// device is the target. Set [Offset] to start playback at a specific point.
/// [retrievePlaybackState] is optional. If `true`, the current [PlaybackState]
/// will be retrieved. Default's to `true`.
///
/// Note: Before starting a new playback context check the [playbackState]
/// if necessary before [resume]ing, otherwise you overwrite the current
/// context.
Future<PlaybackState?> startWithContext(String contextUri,
{String? deviceId,
Offset? offset,
bool retrievePlaybackState = true}) async {
assert(
contextUri.isNotEmpty, 'Cannot start playback with empty context uri');
var options = StartOrResumeOptions(contextUri: contextUri, offset: offset);
return startOrResume(
deviceId: deviceId,
options: options,
retrievePlaybackState: retrievePlaybackState);
}

/// Resume current playback on the user's active device if not specifically
/// set with [deviceId].
/// [retrievePlaybackState] is optional. If `true`, the current [PlaybackState]
/// will be retrieved. Default's to `true`.
Future<PlaybackState?> resume(
{String? deviceId, bool retrievePlaybackState = true}) async =>
startOrResume(
deviceId: deviceId, retrievePlaybackState: retrievePlaybackState);

/// Pause playback on the user's account.
/// [deviceId] is optional. If not provided, the user's currently active device
/// is the target.
/// [retrievePlaybackState] is optional. If true, the current playback state
/// will be retrieved. Defaults to true.
Future<PlaybackState?> pause(
{String? deviceId, bool retrievePlaybackState = true}) async {
await _api._put('$_path/pause?' + _buildQuery({'device_id': deviceId}));
await _api._put('$_path/pause?${_buildQuery({'device_id': deviceId})}');

return retrievePlaybackState ? playbackState() : null;
}
Expand All @@ -119,7 +178,7 @@ class PlayerEndpoint extends _MeEndpointBase {
/// will be retrieved. Defaults to true.
Future<PlaybackState?> previous(
{String? deviceId, bool retrievePlaybackState = true}) async {
await _api._post('$_path/previous?' + _buildQuery({'device_id': deviceId}));
await _api._post('$_path/previous?${_buildQuery({'device_id': deviceId})}');

return retrievePlaybackState ? playbackState() : null;
}
Expand All @@ -131,7 +190,7 @@ class PlayerEndpoint extends _MeEndpointBase {
/// will be retrieved. Defaults to true.
Future<PlaybackState?> next(
{String? deviceId, bool retrievePlaybackState = true}) async {
await _api._post('$_path/next?' + _buildQuery({'device_id': deviceId}));
await _api._post('$_path/next?${_buildQuery({'device_id': deviceId})}');

return retrievePlaybackState ? playbackState() : null;
}
Expand All @@ -145,8 +204,10 @@ class PlayerEndpoint extends _MeEndpointBase {
Future<PlaybackState?> seek(int positionMs,
{String? deviceId, bool retrievePlaybackState = true}) async {
assert(positionMs >= 0, 'positionMs must be greater or equal to 0');
await _api._put('$_path/seek?' +
_buildQuery({'position_ms': positionMs, 'device_id': deviceId}));
await _api._put('$_path/seek?${_buildQuery({
'position_ms': positionMs,
'device_id': deviceId
})}');

return retrievePlaybackState ? playbackState() : null;
}
Expand All @@ -160,11 +221,10 @@ class PlayerEndpoint extends _MeEndpointBase {
/// will be retrieved. Defaults to true.
Future<PlaybackState?> repeat(RepeatState state,
{String? deviceId, bool retrievePlaybackState = true}) async {
await _api._put('$_path/repeat?' +
_buildQuery({
await _api._put('$_path/repeat?${_buildQuery({
'state': state.toString().split('.').last,
'device_id': deviceId
}));
})}');

return retrievePlaybackState ? playbackState() : null;
}
Expand All @@ -180,13 +240,15 @@ class PlayerEndpoint extends _MeEndpointBase {
{String? deviceId, bool retrievePlaybackState = true}) async {
assert(volumePercent >= 0 && volumePercent <= 100,
'Volume must be between 0 and 100');
await _api._put('$_path/volume?' +
_buildQuery({'volume_percent': volumePercent, 'device_id': deviceId}));
await _api._put('$_path/volume?${_buildQuery({
'volume_percent': volumePercent,
'device_id': deviceId
})}');

return retrievePlaybackState ? playbackState() : null;
}

/// Transfer playback to a new device and determine if
/// Transfer playback to a new device and determine if
/// it should start [play]ing. Default is `true`.
///
/// The `AuthorizationScope.connect.modifyPlaybackState` needs to be set.
Expand Down
4 changes: 2 additions & 2 deletions lib/src/models/_models.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 8 additions & 7 deletions lib/src/models/player.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ class PlaybackState extends Object {
PlayerContext? context;

/// Progress into the currently playing track. Can be `null`.
int? progress_ms;
@JsonKey(name: 'progress_ms')
int? progressMs;

/// The currently playing track. Can be `null`.
Track? item;
Expand All @@ -40,7 +41,7 @@ class PlaybackState extends Object {
@JsonKey(name: 'shuffle_state', defaultValue: false)
bool? isShuffling;

/// The repeat state. Can be [RepeatState.off], [RepeatState.track] or
/// The repeat state. Can be [RepeatState.off], [RepeatState.track] or
/// [RepeatState.context]
@JsonKey(name: 'repeat_state', defaultValue: RepeatState.off)
RepeatState? repeatState;
Expand All @@ -55,7 +56,8 @@ class PlayerContext extends Object {
_$PlayerContextFromJson(json);

/// The external_urls of the context, or `null` if not available.
ExternalUrls? external_urls;
@JsonKey(name: 'external_urls')
ExternalUrls? externalUrls;

/// The href of the context, or `null` if not available.
String? href;
Expand Down Expand Up @@ -125,7 +127,7 @@ class StartOrResumeOptions extends Object {

/// Optional. A JSON array of the Spotify track URIs to play.
///
/// Example:
/// Example:
/// ```json
/// [
/// "spotify:track:4iV5W9uYEdYUVa79Axb7Rh",
Expand All @@ -148,9 +150,8 @@ class StartOrResumeOptions extends Object {

Map<String, dynamic> toJson() => _$StartOrResumeOptionsToJson(this);

static Map<String, dynamic> _offsetToJson(Offset? offset) {
return offset?.toJson() ?? {};
}
static Map<String, dynamic> _offsetToJson(Offset? offset) =>
offset?.toJson() ?? {};
}

abstract class Offset {
Expand Down