Skip to content

Commit

Permalink
feat(skip, skiptonext, skiptoprevious): add the ability to pass an in…
Browse files Browse the repository at this point in the history
…itial time when skipping

add an optional parameter to the skip* methods to allow passing an initial playback time

doublesymmetry#713 (comment)
  • Loading branch information
jspizziri committed Feb 25, 2022
1 parent d77a9c8 commit 0ef10df
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -370,25 +370,40 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
}

@ReactMethod
fun skip(index: Int, callback: Promise) {
fun skip(index: Int, initialTime: Float, callback: Promise) {
if (verifyServiceBoundOrReject(callback)) return

musicService.skip(index)

if (initialTime >= 0) {
musicService.seekTo(initialTime)
}

callback.resolve(null)
}

@ReactMethod
fun skipToNext(callback: Promise) {
fun skipToNext(initialTime: Float, callback: Promise) {
if (verifyServiceBoundOrReject(callback)) return
musicService.skipToNext()

if (initialTime >= 0) {
musicService.seekTo(initialTime)
}

callback.resolve(null)
}

@ReactMethod
fun skipToPrevious(callback: Promise) {
fun skipToPrevious(initialTime: Float, callback: Promise) {
if (verifyServiceBoundOrReject(callback)) return

musicService.skipToPrevious()

if (initialTime >= 0) {
musicService.seekTo(initialTime)
}

callback.resolve(null)
}

Expand Down Expand Up @@ -551,4 +566,4 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
companion object {
val TAG: String = MusicModule::class.java.simpleName
}
}
}
53 changes: 42 additions & 11 deletions ios/RNTrackPlayer/RNTrackPlayer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ public class RNTrackPlayer: RCTEventEmitter {
reject("player_not_initialized", "The player is not initialized. Call setupPlayer first.", nil)
return
}

print("Destroying player")
self.player.stop()
self.player.nowPlayingInfoController.clear()
Expand Down Expand Up @@ -356,7 +356,7 @@ public class RNTrackPlayer: RCTEventEmitter {
index = trackIndex.intValue
try? player.add(items: tracks, at: trackIndex.intValue)
}

resolve(index)
}

Expand Down Expand Up @@ -387,8 +387,13 @@ public class RNTrackPlayer: RCTEventEmitter {
resolve(NSNull())
}

@objc(skip:resolver:rejecter:)
public func skip(to trackIndex: NSNumber, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
@objc(skip:initialTime:resolver:rejecter:)
public func skip(
to trackIndex: NSNumber,
initialTime: Double,
resolve: RCTPromiseResolveBlock,
reject: RCTPromiseRejectBlock
) {
if !hasInitialized {
reject("player_not_initialized", "The player is not initialized. Call setupPlayer first.", nil)
return
Expand All @@ -401,34 +406,60 @@ public class RNTrackPlayer: RCTEventEmitter {

print("Skipping to track:", trackIndex)
try? player.jumpToItem(atIndex: trackIndex.intValue, playWhenReady: player.playerState == .playing)
resolve(NSNull())

// if an initialTime is passed the seek to it
if (initialTime >= 0) {
self.seek(to: initialTime, resolve: resolve, reject: reject)
} else {
resolve(NSNull())
}
}

@objc(skipToNext:rejecter:)
public func skipToNext(resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
@objc(skipToNext:resolver:rejecter:)
public func skipToNext(
initialTime: Double,
resolve: RCTPromiseResolveBlock,
reject: RCTPromiseRejectBlock
) {
if !hasInitialized {
reject("player_not_initialized", "The player is not initialized. Call setupPlayer first.", nil)
return
}

do {
try player.next()
resolve(NSNull())

// if an initialTime is passed the seek to it
if (initialTime >= 0) {
self.seek(to: initialTime, resolve: resolve, reject: reject)
} else {
resolve(NSNull())
}
} catch (_) {
reject("queue_exhausted", "There is no tracks left to play", nil)
}
}

@objc(skipToPrevious:rejecter:)
public func skipToPrevious(resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
@objc(skipToPrevious:resolver:rejecter:)
public func skipToPrevious(
initialTime: Double,
resolve: RCTPromiseResolveBlock,
reject: RCTPromiseRejectBlock
) {
if !hasInitialized {
reject("player_not_initialized", "The player is not initialized. Call setupPlayer first.", nil)
return
}

do {
try player.previous()
resolve(NSNull())

// if an initialTime is passed the seek to it
if (initialTime >= 0) {
self.seek(to: initialTime, resolve: resolve, reject: reject)
} else {
resolve(NSNull())
}
} catch (_) {
reject("no_previous_track", "There is no previous track", nil)
}
Expand Down
7 changes: 5 additions & 2 deletions ios/RNTrackPlayer/RNTrackPlayerBridge.m
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,16 @@ @interface RCT_EXTERN_REMAP_MODULE(TrackPlayerModule, RNTrackPlayer, NSObject)
rejecter:(RCTPromiseRejectBlock)reject);

RCT_EXTERN_METHOD(skip:(nonnull NSNumber *)trackIndex
initialTime:(double)initialTime
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject);

RCT_EXTERN_METHOD(skipToNext:(RCTPromiseResolveBlock)resolve
RCT_EXTERN_METHOD(skipToNext:(double)initialTime
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject);

RCT_EXTERN_METHOD(skipToPrevious:(RCTPromiseResolveBlock)resolve
RCT_EXTERN_METHOD(skipToPrevious:(double)initialTime
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject);

RCT_EXTERN_METHOD(reset:(RCTPromiseResolveBlock)resolve
Expand Down
23 changes: 16 additions & 7 deletions src/trackPlayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ function resolveImportedPath(path?: number | string) {
return resolveAssetSource(path) || path
}

// RN doesn't allow nullable NSNumbers so convert optional number parameters
// to a conventional default.
function optionalNumberToDefault(
num?: number,
defaultValue: number = -1,
): number {
return num === undefined ? defaultValue : num;
}

// MARK: - General API

async function setupPlayer(options: PlayerOptions = {}): Promise<void> {
Expand Down Expand Up @@ -74,7 +83,7 @@ async function add(tracks: Track | Track[], insertBeforeIndex?: number): Promise
}

// Note: we must be careful about passing nulls to non nullable parameters on Android.
return TrackPlayer.add(tracks, insertBeforeIndex === undefined ? -1 : insertBeforeIndex)
return TrackPlayer.add(tracks, optionalNumberToDefault(insertBeforeIndex))
}

async function remove(tracks: number | number[]): Promise<void> {
Expand All @@ -89,16 +98,16 @@ async function removeUpcomingTracks(): Promise<void> {
return TrackPlayer.removeUpcomingTracks()
}

async function skip(trackIndex: number): Promise<void> {
return TrackPlayer.skip(trackIndex)
async function skip(trackIndex: number, initialPosition?: number): Promise<void> {
return TrackPlayer.skip(trackIndex, optionalNumberToDefault(initialPosition))
}

async function skipToNext(): Promise<void> {
return TrackPlayer.skipToNext()
async function skipToNext(initialPosition?: number): Promise<void> {
return TrackPlayer.skipToNext(optionalNumberToDefault(initialPosition))
}

async function skipToPrevious(): Promise<void> {
return TrackPlayer.skipToPrevious()
async function skipToPrevious(initialPosition?: number): Promise<void> {
return TrackPlayer.skipToPrevious(optionalNumberToDefault(initialPosition))
}

// MARK: - Control Center / Notifications API
Expand Down
22 changes: 17 additions & 5 deletions windows/RNTrackPlayer/RNTrackPlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ void TrackPlayerModule::Destroy() noexcept
{
if (!manager)
return;

manager->SwitchPlayback(nullptr);
}

Expand Down Expand Up @@ -166,31 +166,43 @@ void TrackPlayerModule::Remove(JSValueArray arr, ReactPromise<JSValue> promise)
player->Remove(tracks, promise);
}

void TrackPlayerModule::Skip(const int trackId, ReactPromise<JSValue> promise) noexcept
void TrackPlayerModule::Skip(const int trackId, double initialTime, ReactPromise<JSValue> promise) noexcept
{
auto player = manager ? manager->GetPlayer() : nullptr;
if (Utils::CheckPlayback(player, promise))
return;

player->Skip(trackId, promise);

if (initialTime > 0) {
player->SeekTo(initialTime);
}
}

void TrackPlayerModule::SkipToNext(ReactPromise<JSValue> promise) noexcept
void TrackPlayerModule::SkipToNext(double initialTime, ReactPromise<JSValue> promise) noexcept
{
auto player = manager ? manager->GetPlayer() : nullptr;
if (Utils::CheckPlayback(player, promise))
return;

player->SkipToNext(promise);

if (initialTime > 0) {
player->SeekTo(initialTime);
}
}

void TrackPlayerModule::SkipToPrevious(ReactPromise<JSValue> promise) noexcept
void TrackPlayerModule::SkipToPrevious(double initialTime, ReactPromise<JSValue> promise) noexcept
{
auto player = manager ? manager->GetPlayer() : nullptr;
if (Utils::CheckPlayback(player, promise))
return;

player->SkipToPrevious(promise);

if (initialTime > 0) {
player->SeekTo(initialTime);
}
}

void TrackPlayerModule::GetQueue(ReactPromise<JSValue> promise) noexcept
Expand Down Expand Up @@ -224,7 +236,7 @@ void TrackPlayerModule::GetCurrentTrack(ReactPromise<JSValue> promise) noexcept
promise.Resolve(index);
} else {
promise.Resolve(nullptr);
}
}
}

void TrackPlayerModule::GetTrack(const int index, ReactPromise<JSValue> promise) noexcept
Expand Down
6 changes: 3 additions & 3 deletions windows/RNTrackPlayer/RNTrackPlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,13 @@ namespace winrt::RNTrackPlayer {
void Remove(JSValueArray arr, ReactPromise<JSValue> promise) noexcept;

REACT_METHOD(Skip, L"skip")
void Skip(const int trackId, ReactPromise<JSValue> promise) noexcept;
void Skip(const int trackId, double initialTime, ReactPromise<JSValue> promise) noexcept;

REACT_METHOD(SkipToNext, L"skipToNext")
void SkipToNext(ReactPromise<JSValue> promise) noexcept;
void SkipToNext(double initialTime, ReactPromise<JSValue> promise) noexcept;

REACT_METHOD(SkipToPrevious, L"skipToPrevious")
void SkipToPrevious(ReactPromise<JSValue> promise) noexcept;
void SkipToPrevious(double initialTime, ReactPromise<JSValue> promise) noexcept;

REACT_METHOD(GetQueue, L"getQueue")
void GetQueue(ReactPromise<JSValue> promise) noexcept;
Expand Down

0 comments on commit 0ef10df

Please sign in to comment.