-
Notifications
You must be signed in to change notification settings - Fork 226
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
Fix: Sleep timer stops podcast after given time #3377
Conversation
Generated by 🚫 Danger |
📲 You can test the changes from this Pull Request in 📱 Mobile by scanning the QR code below to install the corresponding build.
📲 You can test the changes from this Pull Request in 🚗 Automotive by scanning the QR code below to install the corresponding build.
📲 You can test the changes from this Pull Request in ⌚ Wear by scanning the QR code below to install the corresponding build.
|
sleepTimer.stateFlow | ||
.map { it } | ||
.distinctUntilChanged() | ||
.flowOn(Dispatchers.IO) | ||
.onEach { state -> | ||
onSleepTimerStateChange(state) | ||
} | ||
.catch { throwable -> | ||
Timber.e(throwable, "Error observing SleepTimer state") | ||
} | ||
.launchIn(this) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking to observe the sleep timer changes by using sleeptimer.stateFlow.collect {}
instead, but searching for the best approach I found this one.
The collect { }
is suspending, which means it will block the current coroutine until the flow is canceled.
private fun shouldRestartSleepEndOfEpisode( | ||
diffTime: Duration, | ||
currentEpisodeUuid: String, | ||
isSleepEndOfEpisodeRunning: Boolean, | ||
) = diffTime < MIN_TIME_TO_RESTART_SLEEP_TIMER_IN_MINUTES && !sleepTimerHistory.lastEpisodeUuidAutomaticEnded.isNullOrEmpty() && currentEpisodeUuid != sleepTimerHistory.lastEpisodeUuidAutomaticEnded && !isSleepEndOfEpisodeRunning | ||
|
||
private fun shouldRestartSleepEndOfChapter(diffTime: Duration, isSleepEndOfChapterRunning: Boolean) = diffTime < MIN_TIME_TO_RESTART_SLEEP_TIMER_IN_MINUTES && !isSleepEndOfChapterRunning && sleepTimerHistory.lastSleepAfterEndOfChapterTime != null | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did not change the logic of these functions. I just moved them to the bottom of the class since they are both private
sleepTimerHistory = sleepTimerHistory.copy( | ||
lastEpisodeUuidAutomaticEnded = uuid, | ||
lastTimeSleepTimeHasFinished = System.currentTimeMillis().milliseconds, | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The change here is that now we have the sleepTimerHistory
, instead of having separated variables like lastEpisodeUuidAutomaticEnded
and lastTimeSleepTimeHasFinished
sleepTimerHistory = sleepTimerHistory.copy( | ||
lastSleepAfterEndOfChapterTime = time, | ||
lastTimeSleepTimeHasFinished = time, | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The change here is that now we have the sleepTimerHistory
, instead of having separated variables like lastSleepAfterEndOfChapterTime
and lastTimeSleepTimeHasFinished
LogBuffer.i(TAG, "Added extra time: $minutes") | ||
createAlarm(time.timeInMillis) | ||
|
||
LogBuffer.i(TAG, "Added extra time: $newTimeLeft") | ||
} | ||
|
||
fun restartTimerIfIsRunning(onSuccess: () -> Unit): Duration? { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I simplified this method by removing all the callbacks since we now have the state within sleep timer
Can I make a small suggestion, |
...epositories/src/main/java/au/com/shiftyjelly/pocketcasts/repositories/playback/SleepTimer.kt
Outdated
Show resolved
Hide resolved
@@ -2329,9 +2267,6 @@ open class PlaybackManager @Inject constructor( | |||
if (isPlaying()) { | |||
statsManager.addTotalListeningTime(UPDATE_TIMER_POLL_TIME) | |||
} | |||
if (playbackStateRelay.blockingFirst().isSleepTimerRunning && !isSleepAfterEpisodeEnabled()) { // Does not apply to end of episode sleep time | |||
setupFadeOutWhenFinishingSleepTimer() | |||
} | |||
verifySleepTimeForEndOfChapter() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could be wrong but would it be better to move the sleep timer logic and state into the SleepTimer class. Changing the code to something like the following:
verifySleepTimeForEndOfChapter() | |
val playbackState = playbackStateRelay.blockingFirst() | |
if (sleepTimer.shouldPause(playbackState = playbackState)) { | |
pause(sourceView = SourceView.AUTO_PAUSE) | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@geekygecko I like this suggestion and I was trying to push this refactor today, but I am facing with more issues because the PlaybackManager.setupUpdateTimer
(the place we also verify end of chapter) using RxJava and some methods of this end of chapter code uses Coroutine.
Could we move this refactor to other PR? It would make easier to test and also development. Every refactoring I am doing I need to smoke test the whole sleep timer just because there are a lot of changes here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I have approved the PR. Feel free to do any refactoring in another PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No worries. I created this issue for this refactor #3384
...epositories/src/main/java/au/com/shiftyjelly/pocketcasts/repositories/playback/SleepTimer.kt
Outdated
Show resolved
Hide resolved
...epositories/src/main/java/au/com/shiftyjelly/pocketcasts/repositories/playback/SleepTimer.kt
Outdated
Show resolved
Hide resolved
Thank you for your suggestion, @CookieyedCodes . I can't not address anything new here and I would also need to check with our designs first, but I will share with them |
No bothers, just a suggestion 😉 |
Description
Fixes: #3355
Fixes: #2219
Testing Instructions
We need to regression test the whole sleep timer feature. I am going to describe all scenarios we should cover, but feel free to try more in case I miss anything.
Sleep Timer for X minutes
Sleep Timer for end of episodes
Sleep Timer for end of chapter
Auto Restart Sleep Timer
Restarting timer
Not restarting timer
SleepTimer.MIN_TIME_TO_RESTART_SLEEP_TIMER_IN_MINUTES
to 1 so you don't need to wait for 5 minutesAuto Restart Sleep Timer toggle disabled
Auto Restart Sleep Timer
toggleShake device to Restart
Restarting timer after shaking phone in foreground
Sleep timer restarted after device shake
messageRestarting timer after shaking phone in background
Sleep timer restarted after device shake
messageDo not restart timer after shaking phone
Shake to Restart Sleep Timer
toggleChecklist
./gradlew spotlessApply
to automatically apply formatting/linting)modules/services/localization/src/main/res/values/strings.xml