diff --git a/app/src/main/kotlin/org/akanework/gramophone/logic/GramophoneExtensions.kt b/app/src/main/kotlin/org/akanework/gramophone/logic/GramophoneExtensions.kt index ce7fd8ace..55a6c0059 100644 --- a/app/src/main/kotlin/org/akanework/gramophone/logic/GramophoneExtensions.kt +++ b/app/src/main/kotlin/org/akanework/gramophone/logic/GramophoneExtensions.kt @@ -164,13 +164,17 @@ fun View.fadInAnimation(duration: Long = 300, completion: (() -> Unit)? = null) inline fun Int.dpToPx(context: Context): Int = (this.toFloat() * context.resources.displayMetrics.density).toInt() -fun MediaController.getTimer(): Int = +fun MediaController.getTimer(): Int? = sendCustomCommand( SessionCommand(SERVICE_QUERY_TIMER, Bundle.EMPTY), Bundle.EMPTY - ).get().extras.getInt("duration") + ).get().extras.run { + if (containsKey("duration")) + getInt("duration") + else null + } -fun MediaController.hasTimer(): Boolean = getTimer() > 0 +fun MediaController.hasTimer(): Boolean = getTimer() != null fun MediaController.setTimer(value: Int) { sendCustomCommand( SessionCommand(SERVICE_SET_TIMER, Bundle.EMPTY).apply { diff --git a/app/src/main/kotlin/org/akanework/gramophone/logic/GramophonePlaybackService.kt b/app/src/main/kotlin/org/akanework/gramophone/logic/GramophonePlaybackService.kt index ff02a5068..eb0d0a56b 100644 --- a/app/src/main/kotlin/org/akanework/gramophone/logic/GramophonePlaybackService.kt +++ b/app/src/main/kotlin/org/akanework/gramophone/logic/GramophonePlaybackService.kt @@ -140,14 +140,14 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis private val timer: Runnable = Runnable { controller!!.pause() - timerDuration = 0 + timerDuration = null } - private var timerDuration = 0 + private var timerDuration: Long? = null set(value) { field = value - if (value > 0) { - handler.postDelayed(timer, value.toLong()) + if (value != null && value > 0) { + handler.postDelayed(timer, value - System.currentTimeMillis()) } else { handler.removeCallbacks(timer) } @@ -437,13 +437,17 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis SERVICE_SET_TIMER -> { // 0 = clear timer - timerDuration = customCommand.customExtras.getInt("duration") + customCommand.customExtras.getInt("duration").let { + timerDuration = if (it > 0) System.currentTimeMillis() + it else null + } SessionResult(SessionResult.RESULT_SUCCESS) } SERVICE_QUERY_TIMER -> { SessionResult(SessionResult.RESULT_SUCCESS).also { - it.extras.putInt("duration", timerDuration) + timerDuration?.let { td -> + it.extras.putInt("duration", (td - System.currentTimeMillis()).toInt()) + } } } diff --git a/app/src/main/kotlin/org/akanework/gramophone/ui/components/FullBottomSheet.kt b/app/src/main/kotlin/org/akanework/gramophone/ui/components/FullBottomSheet.kt index b81ffbdfe..355d09e68 100644 --- a/app/src/main/kotlin/org/akanework/gramophone/ui/components/FullBottomSheet.kt +++ b/app/src/main/kotlin/org/akanework/gramophone/ui/components/FullBottomSheet.kt @@ -8,6 +8,7 @@ import android.content.res.ColorStateList import android.graphics.Bitmap import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.TransitionDrawable +import android.text.format.DateFormat import android.util.AttributeSet import android.util.Size import android.view.Gravity @@ -20,6 +21,7 @@ import android.widget.ImageView import android.widget.SeekBar import android.widget.TextView import androidx.appcompat.content.res.AppCompatResources +import androidx.appcompat.widget.TooltipCompat import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.graphics.Insets import androidx.core.graphics.TypefaceCompat @@ -74,7 +76,6 @@ import org.akanework.gramophone.logic.getTimer import org.akanework.gramophone.logic.hasImagePermission import org.akanework.gramophone.logic.hasScopedStorageV1 import org.akanework.gramophone.logic.hasScopedStorageWithMediaTypes -import org.akanework.gramophone.logic.hasTimer import org.akanework.gramophone.logic.playOrPause import org.akanework.gramophone.logic.setTextAnimation import org.akanework.gramophone.logic.setTimer @@ -257,9 +258,7 @@ class FullBottomSheet(context: Context, attrs: AttributeSet?, defStyleAttr: Int, prefs.registerOnSharedPreferenceChangeListener(this) activity.controllerViewModel.customCommandListeners.addCallback(activity.lifecycle) { _, command, _ -> when (command.customAction) { - GramophonePlaybackService.SERVICE_TIMER_CHANGED -> { - bottomSheetTimerButton.isChecked = instance?.hasTimer() == true - } + GramophonePlaybackService.SERVICE_TIMER_CHANGED -> updateTimer() GramophonePlaybackService.SERVICE_GET_LYRICS -> { val parsedLyrics = instance?.getLyrics() @@ -335,9 +334,6 @@ class FullBottomSheet(context: Context, attrs: AttributeSet?, defStyleAttr: Int, val destinationTime: Int = picker.hour * 1000 * 3600 + picker.minute * 1000 * 60 instance?.setTimer(destinationTime) } - picker.addOnDismissListener { - bottomSheetTimerButton.isChecked = instance?.hasTimer() == true - } picker.show(activity.supportFragmentManager, "timer") } @@ -460,7 +456,7 @@ class FullBottomSheet(context: Context, attrs: AttributeSet?, defStyleAttr: Int, activity.controllerViewModel.addControllerCallback(activity.lifecycle) { _, _ -> firstTime = true instance?.addListener(this@FullBottomSheet) - bottomSheetTimerButton.isChecked = instance?.hasTimer() == true + updateTimer() onRepeatModeChanged(instance?.repeatMode ?: Player.REPEAT_MODE_OFF) onShuffleModeEnabledChanged(instance?.shuffleModeEnabled ?: false) onPlaybackStateChanged(instance?.playbackState ?: Player.STATE_IDLE) @@ -483,6 +479,16 @@ class FullBottomSheet(context: Context, attrs: AttributeSet?, defStyleAttr: Int, } } + private fun updateTimer() { + val t = instance?.getTimer() + bottomSheetTimerButton.isChecked = t != null + TooltipCompat.setTooltipText(bottomSheetTimerButton, + if (t != null) context.getString(R.string.timer_expiry, + DateFormat.getTimeFormat(context).format(System.currentTimeMillis() + t) + ) else context.getString(R.string.timer) + ) + } + override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { if (key == "color_accuracy" || key == "content_based_color") { if (DynamicColors.isDynamicColorAvailable() && diff --git a/app/src/main/res/layout-land/full_player.xml b/app/src/main/res/layout-land/full_player.xml index 7d3f55f82..db93910b8 100644 --- a/app/src/main/res/layout-land/full_player.xml +++ b/app/src/main/res/layout-land/full_player.xml @@ -349,6 +349,7 @@ android:insetRight="0dp" android:insetBottom="0dp" android:saveEnabled="false" + app:toggleCheckedStateOnClick="false" app:icon="@drawable/sl_check_timer" app:iconGravity="textStart" app:iconPadding="0dp" diff --git a/app/src/main/res/layout/full_player.xml b/app/src/main/res/layout/full_player.xml index 7fcac0b6f..e1262401c 100644 --- a/app/src/main/res/layout/full_player.xml +++ b/app/src/main/res/layout/full_player.xml @@ -356,6 +356,7 @@ android:insetBottom="0dp" android:saveEnabled="false" android:tooltipText="@string/timer" + app:toggleCheckedStateOnClick="false" app:icon="@drawable/sl_check_timer" app:iconGravity="textStart" app:iconPadding="0dp" diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9e73d9cdd..375400c6a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -183,4 +183,5 @@ Click here to open the app and continue playback Playback failed to resume Release date + Sleep timer will pause music at %s