This commit is contained in:
Pavol Franek 2020-03-04 16:27:48 +01:00
parent 046f0323d1
commit c3ab1f9330
6 changed files with 99 additions and 140 deletions

View File

@ -0,0 +1,7 @@
package com.simplemobiletools.clock.extensions
import android.util.Log
import com.simplemobiletools.clock.BuildConfig
fun <A> A.log(tag: String) = apply { if (BuildConfig.DEBUG) Log.wtf(tag, this.toString()) }
fun <A> A.log(first: String, tag: String) = apply { if (BuildConfig.DEBUG) Log.wtf(tag, first) }

View File

@ -1,5 +1,7 @@
package com.simplemobiletools.clock.extensions package com.simplemobiletools.clock.extensions
import android.text.format.DateFormat
import java.util.*
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
fun Long.formatStopwatchTime(useLongerMSFormat: Boolean): String { fun Long.formatStopwatchTime(useLongerMSFormat: Boolean): String {
@ -27,3 +29,10 @@ fun Long.formatStopwatchTime(useLongerMSFormat: Boolean): String {
} }
} }
} }
fun Long.timestampFormat(format: String = "dd. MM. yyyy"): String {
val calendar = Calendar.getInstance(Locale.getDefault())
calendar.timeInMillis = this
return DateFormat.format(format, calendar).toString()
}

View File

@ -4,15 +4,12 @@ import android.annotation.TargetApi
import android.app.Notification import android.app.Notification
import android.app.NotificationChannel import android.app.NotificationChannel
import android.app.NotificationManager import android.app.NotificationManager
import android.app.NotificationManager.IMPORTANCE_HIGH
import android.content.Context import android.content.Context
import android.content.Intent
import android.graphics.Color import android.graphics.Color
import android.media.AudioManager import android.media.AudioManager
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.CountDownTimer
import android.os.SystemClock
import android.util.Log import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@ -20,16 +17,16 @@ import android.view.ViewGroup
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope
import androidx.work.WorkInfo import androidx.work.WorkInfo
import androidx.work.WorkManager import androidx.work.WorkManager
import com.simplemobiletools.clock.R import com.simplemobiletools.clock.R
import com.simplemobiletools.clock.activities.ReminderActivity
import com.simplemobiletools.clock.activities.SimpleActivity import com.simplemobiletools.clock.activities.SimpleActivity
import com.simplemobiletools.clock.dialogs.MyTimePickerDialogDialog import com.simplemobiletools.clock.dialogs.MyTimePickerDialogDialog
import com.simplemobiletools.clock.extensions.* import com.simplemobiletools.clock.extensions.*
import com.simplemobiletools.clock.helpers.Config
import com.simplemobiletools.clock.helpers.PICK_AUDIO_FILE_INTENT_ID import com.simplemobiletools.clock.helpers.PICK_AUDIO_FILE_INTENT_ID
import com.simplemobiletools.clock.helpers.TIMER_NOTIF_ID import com.simplemobiletools.clock.helpers.TIMER_NOTIF_ID
import com.simplemobiletools.clock.workers.TIMER_WORKER_KEY
import com.simplemobiletools.clock.workers.cancelTimerWorker import com.simplemobiletools.clock.workers.cancelTimerWorker
import com.simplemobiletools.clock.workers.enqueueTimerWorker import com.simplemobiletools.clock.workers.enqueueTimerWorker
import com.simplemobiletools.clock.workers.timerRequestId import com.simplemobiletools.clock.workers.timerRequestId
@ -38,56 +35,35 @@ import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.ALARM_SOUND_TYPE_ALARM import com.simplemobiletools.commons.helpers.ALARM_SOUND_TYPE_ALARM
import com.simplemobiletools.commons.helpers.isOreoPlus import com.simplemobiletools.commons.helpers.isOreoPlus
import com.simplemobiletools.commons.models.AlarmSound import com.simplemobiletools.commons.models.AlarmSound
import kotlinx.android.synthetic.main.fragment_timer.*
import kotlinx.android.synthetic.main.fragment_timer.view.* import kotlinx.android.synthetic.main.fragment_timer.view.*
import kotlinx.android.synthetic.main.fragment_timer.view.timer_time
import kotlinx.coroutines.InternalCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
class TimerFragment : Fragment() { class TimerFragment : Fragment() {
private val UPDATE_INTERVAL = 1000L
private val WAS_RUNNING = "was_running"
private val CURRENT_TICKS = "current_ticks"
private val TOTAL_TICKS = "total_ticks"
private var isRunning = false
private var initialSecs = 0
private var totalTicks = 0
private var currentTicks = 0
lateinit var view: ViewGroup lateinit var view: ViewGroup
private var timer: CountDownTimer? = null
@InternalCoroutinesApi
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
val config = requiredActivity.config val config = requiredActivity.config
view = (inflater.inflate(R.layout.fragment_timer, container, false) as ViewGroup).apply { view = (inflater.inflate(R.layout.fragment_timer, container, false) as ViewGroup).apply {
timer_time.setOnClickListener { timer_time.setOnClickListener {
val selectedDuration = config.timerSeconds startTimer(config)
enqueueTimerWorker(TimeUnit.SECONDS.toMillis(selectedDuration.toLong()))
showNotification(selectedDuration.getFormattedDuration())
} }
timer_play_pause.setOnClickListener { timer_play_pause.setOnClickListener {
val selectedDuration = config.timerSeconds startTimer(config)
enqueueTimerWorker(TimeUnit.SECONDS.toMillis(selectedDuration.toLong()))
showNotification(selectedDuration.getFormattedDuration())
} }
timer_reset.setOnClickListener { timer_reset.setOnClickListener {
cancelTimerWorker() cancelTimerWorker()
requiredActivity.toast(R.string.timer_stopped)
} }
timer_initial_time.setOnClickListener { timer_initial_time.setOnClickListener {
MyTimePickerDialogDialog(activity as SimpleActivity, config.timerSeconds) { seconds -> MyTimePickerDialogDialog(activity as SimpleActivity, config.timerSeconds) { seconds ->
val timerSeconds = if (seconds <= 0) 10 else seconds val timerSeconds = if (seconds <= 0) 10 else seconds
config.timerSeconds = timerSeconds config.timerSeconds = timerSeconds
config.timerTimeStamp = System.currentTimeMillis() + timerSeconds
timer_initial_time.text = timerSeconds.getFormattedDuration() timer_initial_time.text = timerSeconds.getFormattedDuration()
} }
} }
@ -114,54 +90,55 @@ class TimerFragment : Fragment() {
context.checkAlarmsWithDeletedSoundUri(sound.uri) context.checkAlarmsWithDeletedSoundUri(sound.uri)
}) })
} }
WorkManager.getInstance(requiredActivity).getWorkInfosByTagLiveData(TIMER_WORKER_KEY).observe(requiredActivity, Observer { workInfo ->
workInfo.log("log")
val workerState = workInfo?.firstOrNull()?.state
when (workerState) {
WorkInfo.State.ENQUEUED -> {
timer?.cancel()
timer = object : CountDownTimer(config.timerSeconds.toLong().times(1000), 1000) {
override fun onTick(millisUntilFinished: Long) {
timer_time.text = millisUntilFinished.div(1000).toInt().getFormattedDuration()
} }
initialSecs = config.timerSeconds override fun onFinish() {}
}.start()
WorkManager.getInstance(activity!!).getWorkInfoByIdLiveData(timerRequestId)
.observe(this, Observer { workInfo ->
Log.e("test", workInfo.toString())
when (workInfo.state) {
WorkInfo.State.SUCCEEDED -> {
showNotification("-")
} }
WorkInfo.State.FAILED -> {}
WorkInfo.State.CANCELLED -> {} else -> {
else -> {} timer_time.text = 0.getFormattedDuration()
} }
}
updateIcons(workerState == WorkInfo.State.ENQUEUED)
timer_reset.beVisibleIf(workerState == WorkInfo.State.ENQUEUED)
}) })
val a = lifecycleScope.launch {
(config.timerSeconds downTo 0).asFlow().onEach { delay(1000) }.collect {
Log.e("test", it.toString())
timer_time.text = it.getFormattedDuration()
}
} }
return view return view
} }
private fun startTimer(config: Config) {
val selectedDuration = config.timerSeconds
val formattedTimestamp = config.timerTimeStamp.timestampFormat("HH:mm:ss")
enqueueTimerWorker(TimeUnit.SECONDS.toMillis(selectedDuration.toLong()))
showNotification("(${selectedDuration.getFormattedDuration()}) $formattedTimestamp")
}
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
setupViews() setupViews()
} }
override fun onSaveInstanceState(outState: Bundle) { override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState.apply { super.onSaveInstanceState(outState.apply {})
putBoolean(WAS_RUNNING, isRunning)
putInt(TOTAL_TICKS, totalTicks)
putInt(CURRENT_TICKS, currentTicks)
})
} }
override fun onViewStateRestored(savedInstanceState: Bundle?) { override fun onViewStateRestored(savedInstanceState: Bundle?) {
super.onViewStateRestored(savedInstanceState) super.onViewStateRestored(savedInstanceState)
savedInstanceState?.apply { savedInstanceState?.apply {}
isRunning = getBoolean(WAS_RUNNING, false)
totalTicks = getInt(TOTAL_TICKS, 0)
currentTicks = getInt(CURRENT_TICKS, 0)
}
} }
fun updateAlarmSound(alarmSound: AlarmSound) { fun updateAlarmSound(alarmSound: AlarmSound) {
@ -170,6 +147,10 @@ class TimerFragment : Fragment() {
view.timer_sound.text = alarmSound.title view.timer_sound.text = alarmSound.title
} }
// private val isRunning
// get(): Boolean =
// WorkManager.getInstance(requiredActivity).getWorkInfosByTagLiveData(TIMER_WORKER_KEY).value?.firstOrNull()?.state == WorkInfo.State.ENQUEUED
private fun setupViews() { private fun setupViews() {
val config = requiredActivity.config val config = requiredActivity.config
val textColor = config.textColor val textColor = config.textColor
@ -188,11 +169,9 @@ class TimerFragment : Fragment() {
timer_sound.text = config.timerSoundTitle timer_sound.text = config.timerSoundTitle
timer_sound.colorLeftDrawable(textColor) timer_sound.colorLeftDrawable(textColor)
} }
updateIcons()
} }
private fun updateIcons() { private fun updateIcons(isRunning: Boolean) {
val drawableId = if (isRunning) R.drawable.ic_pause_vector else R.drawable.ic_play_vector val drawableId = if (isRunning) R.drawable.ic_pause_vector else R.drawable.ic_play_vector
val iconColor = if (requiredActivity.getAdjustedPrimaryColor() == Color.WHITE) Color.BLACK else requiredActivity.config.textColor val iconColor = if (requiredActivity.getAdjustedPrimaryColor() == Color.WHITE) Color.BLACK else requiredActivity.config.textColor
view.timer_play_pause.setImageDrawable(resources.getColoredDrawableWithColor(drawableId, iconColor)) view.timer_play_pause.setImageDrawable(resources.getColoredDrawableWithColor(drawableId, iconColor))
@ -226,48 +205,3 @@ class TimerFragment : Fragment() {
notificationManager.notify(TIMER_NOTIF_ID, builder.build()) notificationManager.notify(TIMER_NOTIF_ID, builder.build())
} }
} }
// private fun resetTimer() {
// updateHandler.removeCallbacks(updateRunnable)
// isRunning = false
// currentTicks = 0
// totalTicks = 0
// initialSecs = context!!.config.timerSeconds
// updateDisplayedText()
// updateIcons()
// view.timer_reset.beGone()
// requiredActivity.hideTimerNotification()
// context!!.hideNotification(TIMER_NOTIF_ID)
// context?.toast(R.string.timer_stopped)
// }
// private fun updateDisplayedText(): Boolean {
// val diff = initialSecs - totalTicks
// var formattedDuration = Math.abs(diff).getFormattedDuration()
//
// if (diff < 0) {
// formattedDuration = "-$formattedDuration"
// if (!isForegrounded) {
// resetTimer()
// return false
// }
// }
//
// view.timer_time.text = formattedDuration
// if (diff == 0) {
// if (context?.isScreenOn() == true) {
// context!!.showTimerNotification(false)
// Handler().postDelayed({
// context?.hideTimerNotification()
// }, context?.config!!.timerMaxReminderSecs * 1000L)
// } else {
// Intent(context, ReminderActivity::class.java).apply {
// activity?.startActivity(this)
// }
// }
// } else if (diff > 0 && !isForegrounded && isRunning) {
// showNotification(formattedDuration)
// }
//
// return true
// }

View File

@ -5,6 +5,7 @@ import com.simplemobiletools.commons.extensions.getDefaultAlarmTitle
import com.simplemobiletools.commons.extensions.getDefaultAlarmUri import com.simplemobiletools.commons.extensions.getDefaultAlarmUri
import com.simplemobiletools.commons.helpers.ALARM_SOUND_TYPE_ALARM import com.simplemobiletools.commons.helpers.ALARM_SOUND_TYPE_ALARM
import com.simplemobiletools.commons.helpers.BaseConfig import com.simplemobiletools.commons.helpers.BaseConfig
import java.util.concurrent.TimeUnit
class Config(context: Context) : BaseConfig(context) { class Config(context: Context) : BaseConfig(context) {
companion object { companion object {
@ -27,6 +28,10 @@ class Config(context: Context) : BaseConfig(context) {
get() = prefs.getInt(TIMER_SECONDS, 300) get() = prefs.getInt(TIMER_SECONDS, 300)
set(lastTimerSeconds) = prefs.edit().putInt(TIMER_SECONDS, lastTimerSeconds).apply() set(lastTimerSeconds) = prefs.edit().putInt(TIMER_SECONDS, lastTimerSeconds).apply()
var timerTimeStamp: Long
get() = prefs.getLong(TIMER_TIMESTAMP, System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(timerSeconds.toLong()))
set(timestamp) = prefs.edit().putLong(TIMER_TIMESTAMP, timestamp).apply()
var timerVibrate: Boolean var timerVibrate: Boolean
get() = prefs.getBoolean(TIMER_VIBRATE, false) get() = prefs.getBoolean(TIMER_VIBRATE, false)
set(timerVibrate) = prefs.edit().putBoolean(TIMER_VIBRATE, timerVibrate).apply() set(timerVibrate) = prefs.edit().putBoolean(TIMER_VIBRATE, timerVibrate).apply()

View File

@ -8,6 +8,7 @@ const val SHOW_SECONDS = "show_seconds"
const val SELECTED_TIME_ZONES = "selected_time_zones" const val SELECTED_TIME_ZONES = "selected_time_zones"
const val EDITED_TIME_ZONE_TITLES = "edited_time_zone_titles" const val EDITED_TIME_ZONE_TITLES = "edited_time_zone_titles"
const val TIMER_SECONDS = "timer_seconds" const val TIMER_SECONDS = "timer_seconds"
const val TIMER_TIMESTAMP = "timer_timetamp"
const val TIMER_VIBRATE = "timer_vibrate" const val TIMER_VIBRATE = "timer_vibrate"
const val TIMER_SOUND_URI = "timer_sound_uri" const val TIMER_SOUND_URI = "timer_sound_uri"
const val TIMER_SOUND_TITLE = "timer_sound_title" const val TIMER_SOUND_TITLE = "timer_sound_title"

View File

@ -3,39 +3,42 @@ package com.simplemobiletools.clock.workers
import android.content.Context import android.content.Context
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.work.* import androidx.work.*
import com.simplemobiletools.clock.extensions.preferences import com.simplemobiletools.clock.extensions.*
import com.simplemobiletools.clock.extensions.requiredActivity
import java.util.* import java.util.*
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
private const val TIMER_REQUEST_ID = "TIMER_REQUEST_ID" private const val TIMER_REQUEST_ID = "TIMER_REQUEST_ID"
private const val TIMER_WORKER_KEY = "TIMER_WORKER_KEY" const val TIMER_WORKER_KEY = "TIMER_WORKER_KEY"
private fun Fragment.saveTimerRequestId(uuid: UUID) = private fun Fragment.saveTimerRequestId(uuid: UUID) =
preferences.edit().putString(TIMER_REQUEST_ID, uuid.toString()).apply() preferences.edit().putString(TIMER_REQUEST_ID, uuid.toString()).apply()
val Fragment.timerRequestId: UUID get() = val Fragment.timerRequestId: UUID? get() =
UUID.fromString(preferences.getString(TIMER_REQUEST_ID, UUID.randomUUID().toString())) preferences.getString(TIMER_REQUEST_ID, UUID.randomUUID().toString())?.let { UUID.fromString(it) }
fun Fragment.cancelTimerWorker() = fun Fragment.cancelTimerWorker() =
WorkManager.getInstance(requiredActivity).apply { WorkManager.getInstance(requiredActivity).cancelAllWorkByTag(TIMER_WORKER_KEY)
timerRequestId.let(::cancelWorkById)
}
fun Fragment.enqueueTimerWorker(delay: Long) = fun Fragment.enqueueTimerWorker(delay: Long) =
WorkManager.getInstance(requiredActivity).enqueueUniqueWork(TIMER_WORKER_KEY, ExistingWorkPolicy.REPLACE, timerRequest(delay)) WorkManager.getInstance(requiredActivity).enqueueUniqueWork(TIMER_WORKER_KEY, ExistingWorkPolicy.REPLACE, timerRequest(delay))
private fun Fragment.timerRequest(delay: Long) = private fun Fragment.timerRequest(delay: Long) =
OneTimeWorkRequestBuilder<TimerWorker>().setInitialDelay(delay, TimeUnit.MILLISECONDS).build().also { OneTimeWorkRequestBuilder<TimerWorker>().setInitialDelay(delay, TimeUnit.MILLISECONDS).addTag(TIMER_WORKER_KEY).build().also {
saveTimerRequestId(it.id) saveTimerRequestId(it.id)
} }
class TimerWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) { class TimerWorker(val context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {
override fun doWork(): Result = override fun doWork(): Result =
try { try {
context.showTimerNotification(false)
Result.success() Result.success()
} catch (exception: Exception) { } catch (exception: Exception) {
Result.failure() Result.failure()
} }
override fun onStopped() {
super.onStopped()
context.hideTimerNotification()
}
} }