diff --git a/android/app/build.gradle b/android/app/build.gradle index 069a1102..f3240f4d 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -13,8 +13,8 @@ android { applicationId "com.audiobookshelf.app" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 30 - versionName "0.9.14-beta" + versionCode 31 + versionName "0.9.15-beta" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" aaptOptions { // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. diff --git a/android/app/src/main/java/com/audiobookshelf/app/MainActivity.kt b/android/app/src/main/java/com/audiobookshelf/app/MainActivity.kt index d51827f9..dce50c76 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/MainActivity.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/MainActivity.kt @@ -123,8 +123,8 @@ class MainActivity : BridgeActivity() { storageHelper.onRequestPermissionsResult(requestCode, permissions, grantResults) } - override fun onUserInteraction() { - super.onUserInteraction() - Log.d(tag, "USER INTERACTION") - } +// override fun onUserInteraction() { +// super.onUserInteraction() +// Log.d(tag, "USER INTERACTION") +// } } diff --git a/android/app/src/main/java/com/audiobookshelf/app/MyNativeAudio.kt b/android/app/src/main/java/com/audiobookshelf/app/MyNativeAudio.kt index ac08489e..69b537de 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/MyNativeAudio.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/MyNativeAudio.kt @@ -37,8 +37,8 @@ class MyNativeAudio : Plugin() { jsobj.put("playWhenReady", playWhenReady) notifyListeners("onPrepareMedia", jsobj) } - override fun onSleepTimerEnded() { - emit("onSleepTimerEnded", true) + override fun onSleepTimerEnded(currentPosition:Long) { + emit("onSleepTimerEnded", currentPosition) } }) } @@ -209,10 +209,15 @@ class MyNativeAudio : Plugin() { @PluginMethod fun setSleepTimer(call: PluginCall) { - var sleepTimeout:Long = call.getString("timeout", "360000")!!.toLong() + var time:Long = call.getString("time", "360000")!!.toLong() + var isChapterTime:Boolean = call.getBoolean("isChapterTime", false) == true - playerNotificationService.setSleepTimer(sleepTimeout) - call.resolve() + Handler(Looper.getMainLooper()).post() { + var success:Boolean = playerNotificationService.setSleepTimer(time, isChapterTime) + val ret = JSObject() + ret.put("success", success) + call.resolve(ret) + } } @PluginMethod diff --git a/android/app/src/main/java/com/audiobookshelf/app/PlayerNotificationService.kt b/android/app/src/main/java/com/audiobookshelf/app/PlayerNotificationService.kt index 1ea52118..81bf3f8c 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/PlayerNotificationService.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/PlayerNotificationService.kt @@ -51,7 +51,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { fun onPlayingUpdate(isPlaying: Boolean) fun onMetadata(metadata: JSObject) fun onPrepare(audiobookId:String, playWhenReady:Boolean) - fun onSleepTimerEnded() + fun onSleepTimerEnded(currentPosition:Long) } private val tag = "PlayerService" @@ -86,6 +86,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { private var onSeekBack: Boolean = false private var sleepTimerTask:TimerTask? = null + private var sleepChapterTime:Long = 0L fun setCustomObjectListener(mylistener: MyCustomObjectListener) { listener = mylistener @@ -722,20 +723,45 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { } } - fun setSleepTimer(timeout:Long) { - Log.d(tag, "Setting Sleep Timer for $timeout") - + fun setSleepTimer(time:Long, isChapterTime:Boolean) : Boolean { + Log.d(tag, "Setting Sleep Timer for $time is chapter time $isChapterTime") sleepTimerTask?.cancel() - sleepTimerTask = Timer("SleepTimer",false).schedule(timeout) { - Log.d(tag, "Sleep Timer Done") - Handler(Looper.getMainLooper()).post() { - if (mPlayer.isPlaying) { - Log.d(tag, "Sleep Timer Pausing Player") - mPlayer.pause() + sleepChapterTime = 0L + + if (isChapterTime) { + // Validate time + if (mPlayer.isPlaying) { + if (mPlayer.currentPosition >= time) { + Log.d(tag, "Invalid setSleepTimer chapter time is already passed") + return false + } + } + + sleepChapterTime = time + sleepTimerTask = Timer("SleepTimer",false).schedule(0L, 1000L) { + Handler(Looper.getMainLooper()).post() { + if (mPlayer.isPlaying && mPlayer.currentPosition > sleepChapterTime) { + Log.d(tag, "Sleep Timer Pausing Player on Chapter") + mPlayer.pause() + + if (listener != null) listener.onSleepTimerEnded(mPlayer.currentPosition) + sleepTimerTask?.cancel() + } + } + } + } else { + sleepTimerTask = Timer("SleepTimer",false).schedule(time) { + Log.d(tag, "Sleep Timer Done") + Handler(Looper.getMainLooper()).post() { + if (mPlayer.isPlaying) { + Log.d(tag, "Sleep Timer Pausing Player") + mPlayer.pause() + } + if (listener != null) listener.onSleepTimerEnded(mPlayer.currentPosition) } - if (listener != null) listener.onSleepTimerEnded() } } + return true } fun getSleepTimerTime():Long? { @@ -748,6 +774,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { Log.d(tag, "Canceling Sleep Timer") sleepTimerTask?.cancel() sleepTimerTask = null + sleepChapterTime = 0L } } diff --git a/components/AudioPlayerMini.vue b/components/AudioPlayerMini.vue index 406cded2..34581fdf 100644 --- a/components/AudioPlayerMini.vue +++ b/components/AudioPlayerMini.vue @@ -33,7 +33,8 @@
-

{{ Math.ceil(sleepTimeoutCurrentTime / 1000 / 60) }}m

+

EOC

+

{{ Math.ceil(sleepTimeoutCurrentTime / 1000 / 60) }}m

@@ -65,7 +66,8 @@ export default { props: { loading: Boolean, sleepTimerRunning: Boolean, - sleepTimeoutCurrentTime: Number + sleepTimeoutCurrentTime: Number, + sleepTimerEndOfChapterTime: Number }, data() { return { diff --git a/components/app/StreamContainer.vue b/components/app/StreamContainer.vue index 832a4a06..b6129a80 100644 --- a/components/app/StreamContainer.vue +++ b/components/app/StreamContainer.vue @@ -15,11 +15,13 @@
- + + - + + @@ -41,8 +43,10 @@ export default { currentTime: 0, sleepTimeoutCurrentTime: 0, isSleepTimerRunning: false, + sleepTimerEndOfChapterTime: false, onSleepTimerEndedListener: null, - sleepInterval: null + sleepInterval: null, + currentEndOfChapterTime: 0 } }, watch: { @@ -124,12 +128,22 @@ export default { } }, methods: { - onSleepTimerEnded() { + onSleepTimerEnded({ value: currentPosition }) { this.isSleepTimerRunning = false if (this.sleepInterval) clearInterval(this.sleepInterval) + + if (currentPosition) { + console.log('Sleep Timer Ended Current Position: ' + currentPosition) + var currentTime = Math.floor(currentPosition / 1000) + this.updateTime(currentTime) + } }, showSleepTimer() { - this.getSleepTimerTime() + if (this.currentChapter) { + this.currentEndOfChapterTime = Math.floor(this.currentChapter.end) + } else { + this.currentEndOfChapterTime = 0 + } this.showSleepTimerModal = true }, async getSleepTimerTime() { @@ -140,15 +154,25 @@ export default { } return 0 }, - async selectSleepTimeout(timeout) { - console.log('Setting sleep timer', timeout) - await MyNativeAudio.setSleepTimer({ timeout: String(timeout) }) - this.setSleepTimeoutTimer(timeout) + async selectSleepTimeout({ time, isChapterTime }) { + console.log('Setting sleep timer', time, isChapterTime) + var res = await MyNativeAudio.setSleepTimer({ time: String(time), isChapterTime }) + if (!res.success) { + return this.$toast.error('Sleep timer did not set, invalid time') + } + if (isChapterTime) { + this.sleepTimerEndOfChapterTime = time + this.isSleepTimerRunning = true + } else { + this.sleepTimerEndOfChapterTime = 0 + this.setSleepTimeoutTimer(time) + } }, async cancelSleepTimer() { console.log('Canceling sleep timer') await MyNativeAudio.cancelSleepTimer() this.isSleepTimerRunning = false + this.sleepTimerEndOfChapterTime = 0 if (this.sleepInterval) clearInterval(this.sleepInterval) }, async syncSleepTimer() { diff --git a/components/modals/ChaptersModal.vue b/components/modals/ChaptersModal.vue index aec59afa..04560aa3 100644 --- a/components/modals/ChaptersModal.vue +++ b/components/modals/ChaptersModal.vue @@ -7,15 +7,17 @@
-
+
@@ -40,6 +42,11 @@ export default { data() { return {} }, + watch: { + value(newVal) { + this.$nextTick(this.scrollToChapter) + } + }, computed: { show: { get() { @@ -59,6 +66,19 @@ export default { methods: { clickedOption(chapter) { this.$emit('select', chapter) + }, + scrollToChapter() { + if (!this.currentChapterId) return + + var container = this.$refs.container + if (container) { + var currChapterEl = document.getElementById(`chapter-row-${this.currentChapterId}`) + if (currChapterEl) { + var offsetTop = currChapterEl.offsetTop + var containerHeight = container.clientHeight + container.scrollTo({ top: offsetTop - containerHeight / 2 }) + } + } } }, mounted() {} diff --git a/components/modals/SleepTimerModal.vue b/components/modals/SleepTimerModal.vue index aca0566a..b607a74d 100644 --- a/components/modals/SleepTimerModal.vue +++ b/components/modals/SleepTimerModal.vue @@ -10,15 +10,21 @@
    +
  • +
    + End of Chapter +
    +
-

{{ timeRemainingPretty }}

+

EOC: {{ endOfChapterTimePretty }}

+

{{ timeRemainingPretty }}

Cancel Timer
@@ -31,7 +37,9 @@ export default { props: { value: Boolean, currentTime: Number, - sleepTimerRunning: Boolean + sleepTimerRunning: Boolean, + currentEndOfChapterTime: Boolean, + endOfChapterTimeSet: Number }, data() { return {} @@ -50,13 +58,20 @@ export default { }, timeRemainingPretty() { return this.$secondsToTimestamp(this.currentTime / 1000) + }, + endOfChapterTimePretty() { + return this.$secondsToTimestamp(this.endOfChapterTimeSet / 1000) } }, methods: { + clickedChapterOption() { + this.show = false + this.$nextTick(() => this.$emit('change', { time: this.currentEndOfChapterTime * 1000, isChapterTime: true })) + }, clickedOption(timeoutMin) { var timeout = timeoutMin * 1000 * 60 this.show = false - this.$nextTick(() => this.$emit('change', timeout)) + this.$nextTick(() => this.$emit('change', { time: timeout, isChapterTime: false })) }, cancelSleepTimer() { this.$emit('cancel') diff --git a/package.json b/package.json index d2a09f6d..849a9a3d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "audiobookshelf-app", - "version": "v0.9.14-beta", + "version": "v0.9.15-beta", "author": "advplyr", "scripts": { "dev": "nuxt --hostname localhost --port 1337",