From c3ab1f9330ff8827248340af1eaa4afe9cc54aea Mon Sep 17 00:00:00 2001
From: Pavol Franek <>
Date: Wed, 4 Mar 2020 16:27:48 +0100
Subject: [PATCH] wip 2
---
.../clock/extensions/Logs.kt | 7 +
.../clock/extensions/Long.kt | 9 +
.../clock/fragments/TimerFragment.kt | 194 ++++++------------
.../simplemobiletools/clock/helpers/Config.kt | 5 +
.../clock/helpers/Constants.kt | 1 +
.../clock/workers/timerWorker.kt | 23 ++-
6 files changed, 99 insertions(+), 140 deletions(-)
create mode 100644 app/src/main/kotlin/com/simplemobiletools/clock/extensions/Logs.kt
diff --git a/app/src/main/kotlin/com/simplemobiletools/clock/extensions/Logs.kt b/app/src/main/kotlin/com/simplemobiletools/clock/extensions/Logs.kt
new file mode 100644
index 00000000..4a662681
--- /dev/null
+++ b/app/src/main/kotlin/com/simplemobiletools/clock/extensions/Logs.kt
@@ -0,0 +1,7 @@
+package com.simplemobiletools.clock.extensions
+
+import android.util.Log
+import com.simplemobiletools.clock.BuildConfig
+
+fun A.log(tag: String) = apply { if (BuildConfig.DEBUG) Log.wtf(tag, this.toString()) }
+fun A.log(first: String, tag: String) = apply { if (BuildConfig.DEBUG) Log.wtf(tag, first) }
diff --git a/app/src/main/kotlin/com/simplemobiletools/clock/extensions/Long.kt b/app/src/main/kotlin/com/simplemobiletools/clock/extensions/Long.kt
index 2b29f682..e4eac62a 100644
--- a/app/src/main/kotlin/com/simplemobiletools/clock/extensions/Long.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/clock/extensions/Long.kt
@@ -1,5 +1,7 @@
package com.simplemobiletools.clock.extensions
+import android.text.format.DateFormat
+import java.util.*
import java.util.concurrent.TimeUnit
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()
+}
diff --git a/app/src/main/kotlin/com/simplemobiletools/clock/fragments/TimerFragment.kt b/app/src/main/kotlin/com/simplemobiletools/clock/fragments/TimerFragment.kt
index 1096b032..9447f4f8 100644
--- a/app/src/main/kotlin/com/simplemobiletools/clock/fragments/TimerFragment.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/clock/fragments/TimerFragment.kt
@@ -4,15 +4,12 @@ import android.annotation.TargetApi
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
-import android.app.NotificationManager.IMPORTANCE_HIGH
import android.content.Context
-import android.content.Intent
import android.graphics.Color
import android.media.AudioManager
import android.os.Build
import android.os.Bundle
-import android.os.Handler
-import android.os.SystemClock
+import android.os.CountDownTimer
import android.util.Log
import android.view.LayoutInflater
import android.view.View
@@ -20,16 +17,16 @@ import android.view.ViewGroup
import androidx.core.app.NotificationCompat
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
-import androidx.lifecycle.lifecycleScope
import androidx.work.WorkInfo
import androidx.work.WorkManager
import com.simplemobiletools.clock.R
-import com.simplemobiletools.clock.activities.ReminderActivity
import com.simplemobiletools.clock.activities.SimpleActivity
import com.simplemobiletools.clock.dialogs.MyTimePickerDialogDialog
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.TIMER_NOTIF_ID
+import com.simplemobiletools.clock.workers.TIMER_WORKER_KEY
import com.simplemobiletools.clock.workers.cancelTimerWorker
import com.simplemobiletools.clock.workers.enqueueTimerWorker
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.isOreoPlus
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.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
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
+ private var timer: CountDownTimer? = null
- @InternalCoroutinesApi
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
val config = requiredActivity.config
view = (inflater.inflate(R.layout.fragment_timer, container, false) as ViewGroup).apply {
timer_time.setOnClickListener {
- val selectedDuration = config.timerSeconds
- enqueueTimerWorker(TimeUnit.SECONDS.toMillis(selectedDuration.toLong()))
- showNotification(selectedDuration.getFormattedDuration())
+ startTimer(config)
}
timer_play_pause.setOnClickListener {
- val selectedDuration = config.timerSeconds
- enqueueTimerWorker(TimeUnit.SECONDS.toMillis(selectedDuration.toLong()))
- showNotification(selectedDuration.getFormattedDuration())
+ startTimer(config)
}
timer_reset.setOnClickListener {
cancelTimerWorker()
+ requiredActivity.toast(R.string.timer_stopped)
}
timer_initial_time.setOnClickListener {
MyTimePickerDialogDialog(activity as SimpleActivity, config.timerSeconds) { seconds ->
val timerSeconds = if (seconds <= 0) 10 else seconds
config.timerSeconds = timerSeconds
+ config.timerTimeStamp = System.currentTimeMillis() + timerSeconds
timer_initial_time.text = timerSeconds.getFormattedDuration()
}
}
@@ -99,69 +75,70 @@ class TimerFragment : Fragment() {
timer_sound.setOnClickListener {
SelectAlarmSoundDialog(activity as SimpleActivity, config.timerSoundUri, AudioManager.STREAM_ALARM, PICK_AUDIO_FILE_INTENT_ID,
- ALARM_SOUND_TYPE_ALARM, true,
- onAlarmPicked = { sound ->
- if (sound != null) {
- updateAlarmSound(sound)
- }
- },
- onAlarmSoundDeleted = { sound ->
- if (config.timerSoundUri == sound.uri) {
- val defaultAlarm = context.getDefaultAlarmSound(ALARM_SOUND_TYPE_ALARM)
- updateAlarmSound(defaultAlarm)
- }
+ ALARM_SOUND_TYPE_ALARM, true,
+ onAlarmPicked = { sound ->
+ if (sound != null) {
+ updateAlarmSound(sound)
+ }
+ },
+ onAlarmSoundDeleted = { sound ->
+ if (config.timerSoundUri == sound.uri) {
+ val defaultAlarm = context.getDefaultAlarmSound(ALARM_SOUND_TYPE_ALARM)
+ updateAlarmSound(defaultAlarm)
+ }
- context.checkAlarmsWithDeletedSoundUri(sound.uri)
- })
+ context.checkAlarmsWithDeletedSoundUri(sound.uri)
+ })
}
- }
- initialSecs = config.timerSeconds
+ WorkManager.getInstance(requiredActivity).getWorkInfosByTagLiveData(TIMER_WORKER_KEY).observe(requiredActivity, Observer { workInfo ->
+ workInfo.log("log")
- WorkManager.getInstance(activity!!).getWorkInfoByIdLiveData(timerRequestId)
- .observe(this, Observer { workInfo ->
- Log.e("test", workInfo.toString())
+ 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()
+ }
- when (workInfo.state) {
- WorkInfo.State.SUCCEEDED -> {
- showNotification("-")
+ override fun onFinish() {}
+ }.start()
}
- WorkInfo.State.FAILED -> {}
- WorkInfo.State.CANCELLED -> {}
- else -> {}
- }
- })
- val a = lifecycleScope.launch {
- (config.timerSeconds downTo 0).asFlow().onEach { delay(1000) }.collect {
- Log.e("test", it.toString())
- timer_time.text = it.getFormattedDuration()
- }
+ else -> {
+ timer_time.text = 0.getFormattedDuration()
+ }
+ }
+
+ updateIcons(workerState == WorkInfo.State.ENQUEUED)
+ timer_reset.beVisibleIf(workerState == WorkInfo.State.ENQUEUED)
+ })
}
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() {
super.onResume()
setupViews()
}
override fun onSaveInstanceState(outState: Bundle) {
- super.onSaveInstanceState(outState.apply {
- putBoolean(WAS_RUNNING, isRunning)
- putInt(TOTAL_TICKS, totalTicks)
- putInt(CURRENT_TICKS, currentTicks)
- })
+ super.onSaveInstanceState(outState.apply {})
}
override fun onViewStateRestored(savedInstanceState: Bundle?) {
super.onViewStateRestored(savedInstanceState)
- savedInstanceState?.apply {
- isRunning = getBoolean(WAS_RUNNING, false)
- totalTicks = getInt(TOTAL_TICKS, 0)
- currentTicks = getInt(CURRENT_TICKS, 0)
- }
+ savedInstanceState?.apply {}
}
fun updateAlarmSound(alarmSound: AlarmSound) {
@@ -170,6 +147,10 @@ class TimerFragment : Fragment() {
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() {
val config = requiredActivity.config
val textColor = config.textColor
@@ -188,11 +169,9 @@ class TimerFragment : Fragment() {
timer_sound.text = config.timerSoundTitle
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 iconColor = if (requiredActivity.getAdjustedPrimaryColor() == Color.WHITE) Color.BLACK else requiredActivity.config.textColor
view.timer_play_pause.setImageDrawable(resources.getColoredDrawableWithColor(drawableId, iconColor))
@@ -212,62 +191,17 @@ class TimerFragment : Fragment() {
}
val builder = NotificationCompat.Builder(context)
- .setContentTitle(label)
- .setContentText(formattedDuration)
- .setSmallIcon(R.drawable.ic_timer)
- .setContentIntent(context!!.getOpenTimerTabIntent())
- .setPriority(Notification.PRIORITY_HIGH)
- .setSound(null)
- .setOngoing(true)
- .setAutoCancel(true)
- .setChannelId(channelId)
+ .setContentTitle(label)
+ .setContentText(formattedDuration)
+ .setSmallIcon(R.drawable.ic_timer)
+ .setContentIntent(context!!.getOpenTimerTabIntent())
+ .setPriority(Notification.PRIORITY_HIGH)
+ .setSound(null)
+ .setOngoing(true)
+ .setAutoCancel(true)
+ .setChannelId(channelId)
builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
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
-// }
diff --git a/app/src/main/kotlin/com/simplemobiletools/clock/helpers/Config.kt b/app/src/main/kotlin/com/simplemobiletools/clock/helpers/Config.kt
index e0ebdcda..06f9ab40 100644
--- a/app/src/main/kotlin/com/simplemobiletools/clock/helpers/Config.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/clock/helpers/Config.kt
@@ -5,6 +5,7 @@ import com.simplemobiletools.commons.extensions.getDefaultAlarmTitle
import com.simplemobiletools.commons.extensions.getDefaultAlarmUri
import com.simplemobiletools.commons.helpers.ALARM_SOUND_TYPE_ALARM
import com.simplemobiletools.commons.helpers.BaseConfig
+import java.util.concurrent.TimeUnit
class Config(context: Context) : BaseConfig(context) {
companion object {
@@ -27,6 +28,10 @@ class Config(context: Context) : BaseConfig(context) {
get() = prefs.getInt(TIMER_SECONDS, 300)
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
get() = prefs.getBoolean(TIMER_VIBRATE, false)
set(timerVibrate) = prefs.edit().putBoolean(TIMER_VIBRATE, timerVibrate).apply()
diff --git a/app/src/main/kotlin/com/simplemobiletools/clock/helpers/Constants.kt b/app/src/main/kotlin/com/simplemobiletools/clock/helpers/Constants.kt
index 4f6ce6b8..613c4227 100644
--- a/app/src/main/kotlin/com/simplemobiletools/clock/helpers/Constants.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/clock/helpers/Constants.kt
@@ -8,6 +8,7 @@ const val SHOW_SECONDS = "show_seconds"
const val SELECTED_TIME_ZONES = "selected_time_zones"
const val EDITED_TIME_ZONE_TITLES = "edited_time_zone_titles"
const val TIMER_SECONDS = "timer_seconds"
+const val TIMER_TIMESTAMP = "timer_timetamp"
const val TIMER_VIBRATE = "timer_vibrate"
const val TIMER_SOUND_URI = "timer_sound_uri"
const val TIMER_SOUND_TITLE = "timer_sound_title"
diff --git a/app/src/main/kotlin/com/simplemobiletools/clock/workers/timerWorker.kt b/app/src/main/kotlin/com/simplemobiletools/clock/workers/timerWorker.kt
index 07bf2b75..c3bd62fa 100644
--- a/app/src/main/kotlin/com/simplemobiletools/clock/workers/timerWorker.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/clock/workers/timerWorker.kt
@@ -3,39 +3,42 @@ package com.simplemobiletools.clock.workers
import android.content.Context
import androidx.fragment.app.Fragment
import androidx.work.*
-import com.simplemobiletools.clock.extensions.preferences
-import com.simplemobiletools.clock.extensions.requiredActivity
+import com.simplemobiletools.clock.extensions.*
import java.util.*
import java.util.concurrent.TimeUnit
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) =
preferences.edit().putString(TIMER_REQUEST_ID, uuid.toString()).apply()
-val Fragment.timerRequestId: UUID get() =
- UUID.fromString(preferences.getString(TIMER_REQUEST_ID, UUID.randomUUID().toString()))
+val Fragment.timerRequestId: UUID? get() =
+ preferences.getString(TIMER_REQUEST_ID, UUID.randomUUID().toString())?.let { UUID.fromString(it) }
fun Fragment.cancelTimerWorker() =
- WorkManager.getInstance(requiredActivity).apply {
- timerRequestId.let(::cancelWorkById)
- }
+ WorkManager.getInstance(requiredActivity).cancelAllWorkByTag(TIMER_WORKER_KEY)
fun Fragment.enqueueTimerWorker(delay: Long) =
WorkManager.getInstance(requiredActivity).enqueueUniqueWork(TIMER_WORKER_KEY, ExistingWorkPolicy.REPLACE, timerRequest(delay))
private fun Fragment.timerRequest(delay: Long) =
- OneTimeWorkRequestBuilder().setInitialDelay(delay, TimeUnit.MILLISECONDS).build().also {
+ OneTimeWorkRequestBuilder().setInitialDelay(delay, TimeUnit.MILLISECONDS).addTag(TIMER_WORKER_KEY).build().also {
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 =
try {
+ context.showTimerNotification(false)
Result.success()
} catch (exception: Exception) {
Result.failure()
}
+
+ override fun onStopped() {
+ super.onStopped()
+ context.hideTimerNotification()
+ }
}