capacitor-plugin-playlist 0.9.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,21 +1,11 @@
1
1
  package org.dwbn.plugins.playlist
2
2
 
3
- import android.util.Log
4
- import com.getcapacitor.JSObject
5
3
  import org.json.JSONException
6
4
  import org.json.JSONObject
7
5
 
8
6
  class OnStatusCallback internal constructor(private val plugin: PlaylistPlugin) {
9
7
  fun onStatus(what: RmxAudioStatusMessage, trackId: String?, param: JSONObject?) {
10
- val data = JSObject()
11
- val detail = JSObject()
12
- detail.put("msgType", what.value)
13
- detail.put("trackId", trackId)
14
- detail.put("value", param)
15
- data.put("action", "status")
16
- data.put("status", detail)
17
- Log.v(TAG, "statusChanged:$data")
18
- plugin.emit("status", data)
8
+ plugin.emitStatus(what, trackId, param)
19
9
  }
20
10
 
21
11
  companion object {
@@ -26,9 +16,9 @@ class OnStatusCallback internal constructor(private val plugin: PlaylistPlugin)
26
16
  error.put("code", code)
27
17
  error.put("message", message ?: "")
28
18
  } catch (e: JSONException) {
29
- Log.e(TAG, "Exception while raising onStatus: ", e)
19
+ android.util.Log.e(TAG, "Exception while raising onStatus: ", e)
30
20
  }
31
21
  return error
32
22
  }
33
23
  }
34
- }
24
+ }
@@ -17,6 +17,7 @@ public class PlaylistPlugin : Plugin(), OnStatusReportListener {
17
17
  private var statusCallback: OnStatusCallback? = null
18
18
  private var audioPlayerImpl: RmxAudioPlayer? = null
19
19
  private var resetStreamOnPause = true
20
+ private var isWebViewActive = true
20
21
 
21
22
  override fun load() {
22
23
  audioPlayerImpl = RmxAudioPlayer(this, (this.context.applicationContext as App))
@@ -422,6 +423,19 @@ public class PlaylistPlugin : Plugin(), OnStatusReportListener {
422
423
  }
423
424
  }
424
425
 
426
+ override fun handleOnPause() {
427
+ super.handleOnPause()
428
+ isWebViewActive = false
429
+ }
430
+
431
+ override fun handleOnResume() {
432
+ super.handleOnResume()
433
+ isWebViewActive = true
434
+ Handler(Looper.getMainLooper()).post {
435
+ audioPlayerImpl?.emitPlaybackSnapshot()
436
+ }
437
+ }
438
+
425
439
  override fun handleOnDestroy() {
426
440
  Log.d(TAG, "Plugin destroy")
427
441
  super.handleOnDestroy()
@@ -474,7 +488,41 @@ public class PlaylistPlugin : Plugin(), OnStatusReportListener {
474
488
  return trackItems
475
489
  }
476
490
 
491
+ fun emitStatus(what: RmxAudioStatusMessage, trackId: String?, param: JSONObject?) {
492
+ if (!shouldEmitStatusToBridge(what, isWebViewActive)) {
493
+ return
494
+ }
495
+ val data = JSObject()
496
+ val detail = JSObject()
497
+ detail.put("msgType", what.value)
498
+ detail.put("trackId", trackId)
499
+ detail.put("value", param)
500
+ data.put("action", "status")
501
+ data.put("status", detail)
502
+ Log.v(TAG, "statusChanged:$data")
503
+ notifyListeners("status", data, shouldRetainStatusEvent(what))
504
+ }
505
+
506
+ /** @deprecated Use [emitStatus] so retain/gating policy is applied consistently. */
477
507
  fun emit(name: String, data: JSObject) {
478
508
  this.notifyListeners(name, data, true)
479
509
  }
510
+
511
+ companion object {
512
+ @JvmStatic
513
+ internal fun shouldEmitStatusToBridge(
514
+ what: RmxAudioStatusMessage,
515
+ isWebViewActive: Boolean
516
+ ): Boolean {
517
+ if (what == RmxAudioStatusMessage.RMXSTATUS_PLAYBACK_POSITION && !isWebViewActive) {
518
+ return false
519
+ }
520
+ return true
521
+ }
522
+
523
+ @JvmStatic
524
+ internal fun shouldRetainStatusEvent(what: RmxAudioStatusMessage): Boolean {
525
+ return what != RmxAudioStatusMessage.RMXSTATUS_PLAYBACK_POSITION
526
+ }
527
+ }
480
528
  }
@@ -482,4 +482,13 @@ public class RmxAudioPlayer implements PlaybackStatusListener<AudioTrack>,
482
482
  public float getLastKnownPositionSec() {
483
483
  return lastKnownHandoffPositionSec;
484
484
  }
485
+
486
+ public void emitPlaybackSnapshot() {
487
+ AudioTrack currentItem = playlistManager.getCurrentItem();
488
+ if (currentItem == null) {
489
+ return;
490
+ }
491
+ JSONObject trackStatus = getPlayerStatus(currentItem);
492
+ onStatus(RmxAudioStatusMessage.RMXSTATUS_PLAYBACK_POSITION, currentItem.getTrackId(), trackStatus);
493
+ }
485
494
  }
@@ -0,0 +1,56 @@
1
+ package org.dwbn.plugins.playlist
2
+
3
+ import org.junit.Assert.assertFalse
4
+ import org.junit.Assert.assertTrue
5
+ import org.junit.Test
6
+
7
+ class StatusBridgePolicyTest {
8
+
9
+ @Test
10
+ fun playbackPosition_isSuppressedWhenWebViewInactive() {
11
+ assertFalse(
12
+ PlaylistPlugin.shouldEmitStatusToBridge(
13
+ RmxAudioStatusMessage.RMXSTATUS_PLAYBACK_POSITION,
14
+ isWebViewActive = false
15
+ )
16
+ )
17
+ }
18
+
19
+ @Test
20
+ fun playbackPosition_isEmittedWhenWebViewActive() {
21
+ assertTrue(
22
+ PlaylistPlugin.shouldEmitStatusToBridge(
23
+ RmxAudioStatusMessage.RMXSTATUS_PLAYBACK_POSITION,
24
+ isWebViewActive = true
25
+ )
26
+ )
27
+ }
28
+
29
+ @Test
30
+ fun playing_isEmittedWhenWebViewInactive() {
31
+ assertTrue(
32
+ PlaylistPlugin.shouldEmitStatusToBridge(
33
+ RmxAudioStatusMessage.RMXSTATUS_PLAYING,
34
+ isWebViewActive = false
35
+ )
36
+ )
37
+ }
38
+
39
+ @Test
40
+ fun playbackPosition_isNotRetained() {
41
+ assertFalse(
42
+ PlaylistPlugin.shouldRetainStatusEvent(
43
+ RmxAudioStatusMessage.RMXSTATUS_PLAYBACK_POSITION
44
+ )
45
+ )
46
+ }
47
+
48
+ @Test
49
+ fun playing_isRetained() {
50
+ assertTrue(
51
+ PlaylistPlugin.shouldRetainStatusEvent(
52
+ RmxAudioStatusMessage.RMXSTATUS_PLAYING
53
+ )
54
+ )
55
+ }
56
+ }
@@ -198,8 +198,16 @@ public class PlaylistPlugin: CAPPlugin, StatusUpdater {
198
198
  call.resolve(["position": position])
199
199
  }
200
200
 
201
+ public override func handleApplicationWillResignActive(_ notification: Notification) {
202
+ audioPlayerImpl.setWebViewActive(false)
203
+ }
204
+
205
+ public override func handleApplicationDidBecomeActive(_ notification: Notification) {
206
+ audioPlayerImpl.setWebViewActive(true)
207
+ audioPlayerImpl.emitPlaybackSnapshot()
208
+ }
209
+
201
210
  // MARK: - StatusUpdater delegate
202
- // todo: calls to notifyListeners should be throttled
203
211
  func onStatus(_ data: [String: Any]) {
204
212
  notifyListeners("status", data: data)
205
213
  }
@@ -28,6 +28,7 @@ final class RmxAudioPlayer: NSObject {
28
28
  private var isReplacingItems = false
29
29
  private var isWaitingToStartPlayback = false
30
30
  private var loop = false
31
+ private var isWebViewActive = true
31
32
 
32
33
  let avQueuePlayer = AVBidirectionalQueuePlayer(items: [])
33
34
 
@@ -1127,6 +1128,10 @@ final class RmxAudioPlayer: NSObject {
1127
1128
  }
1128
1129
 
1129
1130
  func onStatus(_ what: RmxAudioStatusMessage, trackId: String?, param: [String:Any]?) {
1131
+ if what == .rmxstatus_PLAYBACK_POSITION && !isWebViewActive {
1132
+ return
1133
+ }
1134
+
1130
1135
  var status: [String : Any] = [:]
1131
1136
  status["msgType"] = NSNumber(value: what.rawValue)
1132
1137
  // in the error case contains a dict with "code" and "message", otherwise a NSNumber
@@ -1217,4 +1222,21 @@ final class RmxAudioPlayer: NSObject {
1217
1222
  func getLastKnownPosition() -> Float {
1218
1223
  lastKnownHandoffPosition
1219
1224
  }
1225
+
1226
+ func setWebViewActive(_ active: Bool) {
1227
+ isWebViewActive = active
1228
+ }
1229
+
1230
+ func shouldEmitStatusToBridge(_ what: RmxAudioStatusMessage) -> Bool {
1231
+ if what == .rmxstatus_PLAYBACK_POSITION && !isWebViewActive {
1232
+ return false
1233
+ }
1234
+ return true
1235
+ }
1236
+
1237
+ func emitPlaybackSnapshot() {
1238
+ guard let playerItem = avQueuePlayer.currentAudioTrack else { return }
1239
+ let trackStatus = getStatusItem(playerItem)
1240
+ onStatus(.rmxstatus_PLAYBACK_POSITION, trackId: playerItem.trackId, param: trackStatus)
1241
+ }
1220
1242
  }
@@ -1,35 +1,23 @@
1
1
  import XCTest
2
- import Capacitor
3
2
  @testable import Plugin
4
3
 
5
4
  class PluginTests: XCTestCase {
6
5
 
7
- override func setUp() {
8
- super.setUp()
9
- // Put setup code here. This method is called before the invocation of each test method in the class.
6
+ func testPlaybackPositionSuppressedWhenWebViewInactive() {
7
+ let player = RmxAudioPlayer()
8
+ player.setWebViewActive(false)
9
+ XCTAssertFalse(player.shouldEmitStatusToBridge(.rmxstatus_PLAYBACK_POSITION))
10
10
  }
11
11
 
12
- override func tearDown() {
13
- // Put teardown code here. This method is called after the invocation of each test method in the class.
14
- super.tearDown()
12
+ func testPlaybackPositionEmittedWhenWebViewActive() {
13
+ let player = RmxAudioPlayer()
14
+ player.setWebViewActive(true)
15
+ XCTAssertTrue(player.shouldEmitStatusToBridge(.rmxstatus_PLAYBACK_POSITION))
15
16
  }
16
17
 
17
- func testEcho() {
18
- // This is an example of a functional test case for a plugin.
19
- // Use XCTAssert and related functions to verify your tests produce the correct results.
20
-
21
- let value = "Hello, World!"
22
- let plugin = MyPlugin()
23
-
24
- let call = CAPPluginCall(callbackId: "test", options: [
25
- "value": value
26
- ], success: { (result, _) in
27
- let resultValue = result!.data["value"] as? String
28
- XCTAssertEqual(value, resultValue)
29
- }, error: { (_) in
30
- XCTFail("Error shouldn't have been called")
31
- })
32
-
33
- plugin.echo(call!)
18
+ func testPlayingEmittedWhenWebViewInactive() {
19
+ let player = RmxAudioPlayer()
20
+ player.setWebViewActive(false)
21
+ XCTAssertTrue(player.shouldEmitStatusToBridge(.rmxstatus_PLAYING))
34
22
  }
35
23
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "capacitor-plugin-playlist",
3
- "version": "0.9.0",
3
+ "version": "0.9.1",
4
4
  "description": "Playlist ",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",
File without changes