Merge pull request #207 from esensar/feature/105-sleep-timer

Add sleep timer
This commit is contained in:
Tibor Kaputa 2023-09-06 22:05:35 +02:00 committed by GitHub
commit 3924b33ebb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
54 changed files with 520 additions and 51 deletions

View File

@ -76,7 +76,7 @@ android {
} }
dependencies { dependencies {
implementation 'com.github.SimpleMobileTools:Simple-Commons:7c1e5b5777' implementation 'com.github.SimpleMobileTools:Simple-Commons:73d78e5cd3'
implementation 'org.greenrobot:eventbus:3.3.1' implementation 'org.greenrobot:eventbus:3.3.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
} }

View File

@ -10,6 +10,7 @@
<uses-permission android:name="android.permission.FLASHLIGHT" /> <uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission <uses-permission
android:name="android.permission.USE_FINGERPRINT" android:name="android.permission.USE_FINGERPRINT"
tools:node="remove" /> tools:node="remove" />
@ -132,6 +133,9 @@
android:resource="@xml/widget_bright_display" /> android:resource="@xml/widget_bright_display" />
</receiver> </receiver>
<receiver android:name=".helpers.ShutDownReceiver"
android:exported="false" />
<service <service
android:name=".helpers.FlashlightTileService" android:name=".helpers.FlashlightTileService"
android:exported="true" android:exported="true"

View File

@ -4,12 +4,17 @@ import android.content.pm.ActivityInfo
import android.graphics.drawable.ColorDrawable import android.graphics.drawable.ColorDrawable
import android.os.Bundle import android.os.Bundle
import android.view.WindowManager import android.view.WindowManager
import android.widget.RelativeLayout
import com.simplemobiletools.commons.dialogs.ColorPickerDialog import com.simplemobiletools.commons.dialogs.ColorPickerDialog
import com.simplemobiletools.commons.extensions.applyColorFilter import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.extensions.getContrastColor
import com.simplemobiletools.commons.extensions.viewBinding
import com.simplemobiletools.flashlight.databinding.ActivityBrightDisplayBinding import com.simplemobiletools.flashlight.databinding.ActivityBrightDisplayBinding
import com.simplemobiletools.flashlight.extensions.config import com.simplemobiletools.flashlight.extensions.config
import com.simplemobiletools.flashlight.helpers.stopSleepTimerCountDown
import com.simplemobiletools.flashlight.models.Events
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import kotlin.system.exitProcess
class BrightDisplayActivity : SimpleActivity() { class BrightDisplayActivity : SimpleActivity() {
private val binding by viewBinding(ActivityBrightDisplayBinding::inflate) private val binding by viewBinding(ActivityBrightDisplayBinding::inflate)
@ -45,6 +50,8 @@ class BrightDisplayActivity : SimpleActivity() {
} }
} }
} }
binding.sleepTimerStop.setOnClickListener { stopSleepTimer() }
} }
override fun onResume() { override fun onResume() {
@ -52,6 +59,8 @@ class BrightDisplayActivity : SimpleActivity() {
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
toggleBrightness(true) toggleBrightness(true)
requestedOrientation = if (config.forcePortraitMode) ActivityInfo.SCREEN_ORIENTATION_PORTRAIT else ActivityInfo.SCREEN_ORIENTATION_SENSOR requestedOrientation = if (config.forcePortraitMode) ActivityInfo.SCREEN_ORIENTATION_PORTRAIT else ActivityInfo.SCREEN_ORIENTATION_SENSOR
(binding.sleepTimerHolder.layoutParams as RelativeLayout.LayoutParams).bottomMargin = navigationBarHeight
} }
override fun onPause() { override fun onPause() {
@ -60,6 +69,16 @@ class BrightDisplayActivity : SimpleActivity() {
toggleBrightness(false) toggleBrightness(false)
} }
override fun onStart() {
super.onStart()
EventBus.getDefault().register(this)
}
override fun onStop() {
super.onStop()
EventBus.getDefault().unregister(this)
}
private fun setBackgroundColor(color: Int) { private fun setBackgroundColor(color: Int) {
binding.apply { binding.apply {
brightDisplay.background = ColorDrawable(color) brightDisplay.background = ColorDrawable(color)
@ -77,4 +96,19 @@ class BrightDisplayActivity : SimpleActivity() {
layout.screenBrightness = (if (increase) 1 else 0).toFloat() layout.screenBrightness = (if (increase) 1 else 0).toFloat()
window.attributes = layout window.attributes = layout
} }
private fun stopSleepTimer() {
binding.sleepTimerHolder.fadeOut()
stopSleepTimerCountDown()
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun sleepTimerChanged(event: Events.SleepTimerChanged) {
binding.sleepTimerValue.text = event.seconds.getFormattedDuration()
binding.sleepTimerHolder.beVisible()
if (event.seconds == 0) {
exitProcess(0)
}
}
} }

View File

@ -1,30 +1,33 @@
package com.simplemobiletools.flashlight.activities package com.simplemobiletools.flashlight.activities
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.AlarmManager
import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo
import android.content.pm.ShortcutInfo import android.content.pm.ShortcutInfo
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Icon import android.graphics.drawable.Icon
import android.graphics.drawable.LayerDrawable import android.graphics.drawable.LayerDrawable
import android.os.Bundle import android.os.Bundle
import android.view.WindowManager import android.view.WindowManager
import android.widget.ImageView import android.widget.ImageView
import com.simplemobiletools.commons.dialogs.PermissionRequiredDialog
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.LICENSE_EVENT_BUS import com.simplemobiletools.commons.helpers.*
import com.simplemobiletools.commons.helpers.PERMISSION_CAMERA
import com.simplemobiletools.commons.helpers.isNougatMR1Plus
import com.simplemobiletools.commons.helpers.isNougatPlus
import com.simplemobiletools.commons.models.FAQItem import com.simplemobiletools.commons.models.FAQItem
import com.simplemobiletools.commons.models.RadioItem
import com.simplemobiletools.flashlight.BuildConfig import com.simplemobiletools.flashlight.BuildConfig
import com.simplemobiletools.flashlight.R import com.simplemobiletools.flashlight.R
import com.simplemobiletools.flashlight.databinding.ActivityMainBinding import com.simplemobiletools.flashlight.databinding.ActivityMainBinding
import com.simplemobiletools.flashlight.dialogs.SleepTimerCustomDialog
import com.simplemobiletools.flashlight.extensions.config import com.simplemobiletools.flashlight.extensions.config
import com.simplemobiletools.flashlight.helpers.CameraTorchListener import com.simplemobiletools.flashlight.helpers.*
import com.simplemobiletools.flashlight.helpers.MIN_BRIGHTNESS_LEVEL
import com.simplemobiletools.flashlight.helpers.MyCameraImpl
import com.simplemobiletools.flashlight.models.Events import com.simplemobiletools.flashlight.models.Events
import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import java.util.* import java.util.*
class MainActivity : SimpleActivity() { class MainActivity : SimpleActivity() {
@ -74,6 +77,8 @@ class MainActivity : SimpleActivity() {
stroboscopeBtn.setOnClickListener { stroboscopeBtn.setOnClickListener {
toggleStroboscope(false) toggleStroboscope(false)
} }
sleepTimerStop.setOnClickListener { stopSleepTimer() }
} }
setupStroboscope() setupStroboscope()
@ -110,6 +115,9 @@ class MainActivity : SimpleActivity() {
} }
} }
binding.sleepTimerHolder.background = ColorDrawable(getProperBackgroundColor())
binding.sleepTimerStop.applyColorFilter(getProperTextColor())
requestedOrientation = if (config.forcePortraitMode) ActivityInfo.SCREEN_ORIENTATION_PORTRAIT else ActivityInfo.SCREEN_ORIENTATION_SENSOR requestedOrientation = if (config.forcePortraitMode) ActivityInfo.SCREEN_ORIENTATION_PORTRAIT else ActivityInfo.SCREEN_ORIENTATION_SENSOR
invalidateOptionsMenu() invalidateOptionsMenu()
@ -126,6 +134,11 @@ class MainActivity : SimpleActivity() {
super.onStart() super.onStart()
mBus!!.register(this) mBus!!.register(this)
if (config.sleepInTS == 0L) {
binding.sleepTimerHolder.beGone()
(getSystemService(Context.ALARM_SERVICE) as AlarmManager).cancel(getShutDownPendingIntent())
}
if (mCameraImpl == null) { if (mCameraImpl == null) {
setupCameraImpl() setupCameraImpl()
} }
@ -146,6 +159,7 @@ class MainActivity : SimpleActivity() {
when (menuItem.itemId) { when (menuItem.itemId) {
R.id.more_apps_from_us -> launchMoreAppsFromUsIntent() R.id.more_apps_from_us -> launchMoreAppsFromUsIntent()
R.id.settings -> launchSettings() R.id.settings -> launchSettings()
R.id.sleep_timer -> showSleepTimer()
R.id.about -> launchAbout() R.id.about -> launchAbout()
else -> return@setOnMenuItemClickListener false else -> return@setOnMenuItemClickListener false
} }
@ -279,6 +293,85 @@ class MainActivity : SimpleActivity() {
mCameraImpl = null mCameraImpl = null
} }
private fun showSleepTimer(force: Boolean = false) {
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
if (isSPlus() && !alarmManager.canScheduleExactAlarms() && !force) {
PermissionRequiredDialog(
this,
com.simplemobiletools.commons.R.string.allow_alarm_sleep_timer,
positiveActionCallback = { openRequestExactAlarmSettings(baseConfig.appId) },
negativeActionCallback = { showSleepTimer(true) }
)
return
}
val items = ArrayList(listOf(10, 30, 60, 5 * 60, 10 * 60, 30 * 60).map {
RadioItem(it, secondsToString(it))
})
if (items.none { it.id == config.lastSleepTimerSeconds }) {
items.add(RadioItem(config.lastSleepTimerSeconds, secondsToString(config.lastSleepTimerSeconds)))
}
items.sortBy { it.id }
items.add(RadioItem(-1, getString(R.string.custom)))
RadioGroupDialog(this, items, config.lastSleepTimerSeconds) {
if (it as Int == -1) {
SleepTimerCustomDialog(this) {
if (it > 0) {
pickedSleepTimer(it)
}
}
} else if (it > 0) {
pickedSleepTimer(it)
}
}
}
private fun secondsToString(seconds: Int): String {
val finalHours = seconds / 3600
val finalMinutes = (seconds / 60) % 60
val finalSeconds = seconds % 60
val parts = mutableListOf<String>()
if (finalHours != 0) {
parts.add(resources.getQuantityString(R.plurals.hours, finalHours, finalHours))
}
if (finalMinutes != 0) {
parts.add(resources.getQuantityString(R.plurals.minutes, finalMinutes, finalMinutes))
}
if (finalSeconds != 0) {
parts.add(resources.getQuantityString(R.plurals.seconds, finalSeconds, finalSeconds))
}
return parts.joinToString(separator = " ")
}
private fun pickedSleepTimer(seconds: Int) {
config.lastSleepTimerSeconds = seconds
config.sleepInTS = System.currentTimeMillis() + seconds * 1000
startSleepTimer()
}
private fun startSleepTimer() {
binding.sleepTimerHolder.fadeIn()
startSleepTimerCountDown()
}
private fun stopSleepTimer() {
binding.sleepTimerHolder.fadeOut()
stopSleepTimerCountDown()
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun sleepTimerChanged(event: Events.SleepTimerChanged) {
binding.sleepTimerValue.text = event.seconds.getFormattedDuration()
binding.sleepTimerHolder.beVisible()
if (event.seconds == 0) {
finish()
}
}
@Subscribe @Subscribe
fun stateChangedEvent(event: Events.StateChanged) { fun stateChangedEvent(event: Events.StateChanged) {
checkState(event.isEnabled) checkState(event.isEnabled)

View File

@ -0,0 +1,49 @@
package com.simplemobiletools.flashlight.dialogs
import android.app.Activity
import android.view.inputmethod.EditorInfo
import androidx.appcompat.app.AlertDialog
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.flashlight.R
import com.simplemobiletools.flashlight.databinding.DialogCustomSleepTimerPickerBinding
class SleepTimerCustomDialog(val activity: Activity, val callback: (seconds: Int) -> Unit) {
private var dialog: AlertDialog? = null
private val binding = DialogCustomSleepTimerPickerBinding.inflate(activity.layoutInflater)
init {
binding.dialogRadioView.check(R.id.dialog_radio_minutes)
binding.timerValue.setOnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_DONE) {
dialogConfirmed()
return@setOnEditorActionListener true
}
return@setOnEditorActionListener false
}
activity.getAlertDialogBuilder()
.setPositiveButton(R.string.ok) { _, _ -> dialogConfirmed() }
.setNegativeButton(R.string.cancel, null)
.apply {
activity.setupDialogStuff(binding.root, this, R.string.sleep_timer) { alertDialog ->
dialog = alertDialog
alertDialog.showKeyboard(binding.timerValue)
}
}
}
private fun dialogConfirmed() {
val value = binding.timerValue.value
val minutes = Integer.valueOf(value.ifEmpty { "0" })
val multiplier = getMultiplier(binding.dialogRadioView.checkedRadioButtonId)
callback(minutes * multiplier)
activity.hideKeyboard()
dialog?.dismiss()
}
private fun getMultiplier(id: Int) = when (id) {
R.id.dialog_radio_seconds -> 1
R.id.dialog_radio_minutes -> 60
else -> 60
}
}

View File

@ -44,4 +44,12 @@ class Config(context: Context) : BaseConfig(context) {
var brightnessLevel: Int var brightnessLevel: Int
get() = prefs.getInt(BRIGHTNESS_LEVEL, DEFAULT_BRIGHTNESS_LEVEL) get() = prefs.getInt(BRIGHTNESS_LEVEL, DEFAULT_BRIGHTNESS_LEVEL)
set(brightnessLevel) = prefs.edit().putInt(BRIGHTNESS_LEVEL, brightnessLevel).apply() set(brightnessLevel) = prefs.edit().putInt(BRIGHTNESS_LEVEL, brightnessLevel).apply()
var lastSleepTimerSeconds: Int
get() = prefs.getInt(LAST_SLEEP_TIMER_SECONDS, 30 * 60)
set(lastSleepTimerSeconds) = prefs.edit().putInt(LAST_SLEEP_TIMER_SECONDS, lastSleepTimerSeconds).apply()
var sleepInTS: Long
get() = prefs.getLong(SLEEP_IN_TS, 0)
set(sleepInTS) = prefs.edit().putLong(SLEEP_IN_TS, sleepInTS).apply()
} }

View File

@ -12,5 +12,7 @@ const val STROBOSCOPE_PROGRESS = "stroboscope_progress"
const val FORCE_PORTRAIT_MODE = "force_portrait_mode" const val FORCE_PORTRAIT_MODE = "force_portrait_mode"
const val SOS = "sos" const val SOS = "sos"
const val BRIGHTNESS_LEVEL = "brightness_level" const val BRIGHTNESS_LEVEL = "brightness_level"
const val LAST_SLEEP_TIMER_SECONDS = "last_sleep_timer_seconds"
const val SLEEP_IN_TS = "sleep_in_ts"
const val MIN_BRIGHTNESS_LEVEL = 1 const val MIN_BRIGHTNESS_LEVEL = 1
const val DEFAULT_BRIGHTNESS_LEVEL = -1 const val DEFAULT_BRIGHTNESS_LEVEL = -1

View File

@ -0,0 +1,12 @@
package com.simplemobiletools.flashlight.helpers
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import kotlin.system.exitProcess
class ShutDownReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
exitProcess(0)
}
}

View File

@ -0,0 +1,70 @@
package com.simplemobiletools.flashlight.helpers
import android.app.AlarmManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.CountDownTimer
import com.simplemobiletools.commons.helpers.isSPlus
import com.simplemobiletools.flashlight.extensions.config
import com.simplemobiletools.flashlight.models.Events
import org.greenrobot.eventbus.EventBus
import kotlin.system.exitProcess
private var isActive = false
private var sleepTimer: CountDownTimer? = null
internal fun Context.toggleSleepTimer() {
if (isActive) {
stopSleepTimerCountDown()
} else {
startSleepTimerCountDown()
}
}
internal fun Context.startSleepTimerCountDown() {
val millisInFuture = config.sleepInTS - System.currentTimeMillis() + 1000L
(getSystemService(Context.ALARM_SERVICE) as AlarmManager).apply {
if (!isSPlus() || canScheduleExactAlarms()) {
setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
config.sleepInTS,
getShutDownPendingIntent()
)
} else {
setAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
config.sleepInTS,
getShutDownPendingIntent()
)
}
}
sleepTimer?.cancel()
sleepTimer = object : CountDownTimer(millisInFuture, 1000) {
override fun onTick(millisUntilFinished: Long) {
val seconds = (millisUntilFinished / 1000).toInt()
EventBus.getDefault().post(Events.SleepTimerChanged(seconds))
}
override fun onFinish() {
config.sleepInTS = 0
EventBus.getDefault().post(Events.SleepTimerChanged(0))
stopSleepTimerCountDown()
exitProcess(0)
}
}
sleepTimer?.start()
isActive = true
}
internal fun Context.stopSleepTimerCountDown() {
(getSystemService(Context.ALARM_SERVICE) as AlarmManager).cancel(getShutDownPendingIntent())
sleepTimer?.cancel()
sleepTimer = null
isActive = false
config.sleepInTS = 0
}
internal fun Context.getShutDownPendingIntent() =
PendingIntent.getBroadcast(this, 0, Intent(this, ShutDownReceiver::class.java), PendingIntent.FLAG_IMMUTABLE)

View File

@ -8,4 +8,6 @@ class Events {
class StopStroboscope class StopStroboscope
class StopSOS class StopSOS
class SleepTimerChanged(val seconds: Int)
} }

View File

@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/bright_display_holder" android:id="@+id/bright_display_holder"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
@ -19,4 +21,71 @@
android:alpha="0.5" android:alpha="0.5"
android:text="@string/change_color" /> android:text="@string/change_color" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/sleep_timer_holder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/default_background_color"
android:clickable="true"
android:visibility="gone"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
tools:visibility="visible">
<ImageView
android:id="@+id/sleep_timer_divider_top"
android:layout_width="0dp"
android:layout_height="1px"
android:background="@color/divider_grey"
app:layout_constraintBottom_toTopOf="@+id/sleep_timer_stop"
app:layout_constraintEnd_toEndOf="@+id/sleep_timer_stop"
app:layout_constraintStart_toStartOf="@+id/sleep_timer_label" />
<ImageView
android:id="@+id/sleep_timer_divider_start"
android:layout_width="1px"
android:layout_height="0dp"
android:background="@color/divider_grey"
app:layout_constraintBottom_toBottomOf="@+id/sleep_timer_stop"
app:layout_constraintStart_toStartOf="@+id/sleep_timer_label"
app:layout_constraintTop_toTopOf="@+id/sleep_timer_stop" />
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/sleep_timer_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:paddingStart="@dimen/normal_margin"
android:paddingEnd="@dimen/normal_margin"
android:text="@string/sleep_timer"
android:textSize="@dimen/big_text_size"
app:layout_constraintBottom_toBottomOf="@+id/sleep_timer_stop"
app:layout_constraintEnd_toStartOf="@+id/sleep_timer_value"
app:layout_constraintTop_toTopOf="@+id/sleep_timer_stop" />
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/sleep_timer_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="00:00"
android:textSize="@dimen/big_text_size"
app:layout_constraintBottom_toBottomOf="@+id/sleep_timer_stop"
app:layout_constraintEnd_toStartOf="@+id/sleep_timer_stop"
app:layout_constraintTop_toTopOf="@+id/sleep_timer_stop"
tools:ignore="HardcodedText" />
<ImageView
android:id="@+id/sleep_timer_stop"
android:layout_width="@dimen/normal_icon_size"
android:layout_height="@dimen/normal_icon_size"
android:layout_marginStart="@dimen/tiny_margin"
android:layout_marginEnd="@dimen/tiny_margin"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="@dimen/medium_margin"
android:src="@drawable/ic_cross_vector"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</RelativeLayout> </RelativeLayout>

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main_coordinator" android:id="@+id/main_coordinator"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
@ -111,6 +112,72 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/stroboscope_btn" /> app:layout_constraintTop_toBottomOf="@+id/stroboscope_btn" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/sleep_timer_holder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/default_background_color"
android:clickable="true"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:visibility="visible">
<ImageView
android:id="@+id/sleep_timer_divider_top"
android:layout_width="0dp"
android:layout_height="1px"
android:background="@color/divider_grey"
app:layout_constraintBottom_toTopOf="@+id/sleep_timer_stop"
app:layout_constraintEnd_toEndOf="@+id/sleep_timer_stop"
app:layout_constraintStart_toStartOf="@+id/sleep_timer_label" />
<ImageView
android:id="@+id/sleep_timer_divider_start"
android:layout_width="1px"
android:layout_height="0dp"
android:background="@color/divider_grey"
app:layout_constraintBottom_toBottomOf="@+id/sleep_timer_stop"
app:layout_constraintStart_toStartOf="@+id/sleep_timer_label"
app:layout_constraintTop_toTopOf="@+id/sleep_timer_stop" />
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/sleep_timer_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:paddingStart="@dimen/normal_margin"
android:paddingEnd="@dimen/normal_margin"
android:text="@string/sleep_timer"
android:textSize="@dimen/big_text_size"
app:layout_constraintBottom_toBottomOf="@+id/sleep_timer_stop"
app:layout_constraintEnd_toStartOf="@+id/sleep_timer_value"
app:layout_constraintTop_toTopOf="@+id/sleep_timer_stop" />
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/sleep_timer_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="00:00"
android:textSize="@dimen/big_text_size"
app:layout_constraintBottom_toBottomOf="@+id/sleep_timer_stop"
app:layout_constraintEnd_toStartOf="@+id/sleep_timer_stop"
app:layout_constraintTop_toTopOf="@+id/sleep_timer_stop"
tools:ignore="HardcodedText" />
<ImageView
android:id="@+id/sleep_timer_stop"
android:layout_width="@dimen/normal_icon_size"
android:layout_height="@dimen/normal_icon_size"
android:layout_marginStart="@dimen/tiny_margin"
android:layout_marginEnd="@dimen/tiny_margin"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="@dimen/medium_margin"
android:src="@drawable/ic_cross_vector"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView> </androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/dialog_custom_sleep_timer_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin"
android:paddingRight="@dimen/activity_margin">
<com.simplemobiletools.commons.views.MyTextInputLayout
android:id="@+id/value_hint"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/value">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/timer_value"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/activity_margin"
android:digits="0123456789"
android:inputType="number"
android:maxLength="5"
android:singleLine="true"
android:textCursorDrawable="@null"
android:imeOptions="actionDone"
android:textSize="@dimen/normal_text_size" />
</com.simplemobiletools.commons.views.MyTextInputLayout>
<RadioGroup
android:id="@+id/dialog_radio_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/normal_margin">
<com.simplemobiletools.commons.views.MyCompatRadioButton
android:id="@+id/dialog_radio_minutes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/normal_margin"
android:paddingBottom="@dimen/normal_margin"
android:text="@string/minutes_raw" />
<com.simplemobiletools.commons.views.MyCompatRadioButton
android:id="@+id/dialog_radio_seconds"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/normal_margin"
android:paddingBottom="@dimen/normal_margin"
android:text="@string/seconds_raw" />
</RadioGroup>
</LinearLayout>

View File

@ -13,6 +13,10 @@
android:icon="@drawable/ic_info_vector" android:icon="@drawable/ic_info_vector"
android:title="@string/about" android:title="@string/about"
app:showAsAction="always" /> app:showAsAction="always" />
<item
android:id="@+id/sleep_timer"
android:title="@string/sleep_timer"
app:showAsAction="never" />
<item <item
android:id="@+id/more_apps_from_us" android:id="@+id/more_apps_from_us"
android:title="@string/more_apps_from_us" android:title="@string/more_apps_from_us"