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
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()
}

View file

@ -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
// }

View file

@ -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()

View file

@ -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"

View file

@ -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<TimerWorker>().setInitialDelay(delay, TimeUnit.MILLISECONDS).build().also {
OneTimeWorkRequestBuilder<TimerWorker>().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()
}
}