mirror of
				https://github.com/SimpleMobileTools/Simple-Clock.git
				synced 2025-06-05 22:19:17 +02:00 
			
		
		
		
	wip
This commit is contained in:
		| @@ -54,6 +54,16 @@ android { | |||||||
|         checkReleaseBuilds false |         checkReleaseBuilds false | ||||||
|         abortOnError false |         abortOnError false | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     compileOptions { | ||||||
|  |         sourceCompatibility = 1.8 | ||||||
|  |         targetCompatibility = 1.8 | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     kotlinOptions { | ||||||
|  |         jvmTarget = "1.8" | ||||||
|  |         freeCompilerArgs = ["-XXLanguage:+NewInference"] | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| dependencies { | dependencies { | ||||||
| @@ -61,4 +71,8 @@ dependencies { | |||||||
|     implementation 'com.facebook.stetho:stetho:1.5.0' |     implementation 'com.facebook.stetho:stetho:1.5.0' | ||||||
|     implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta2' |     implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta2' | ||||||
|     implementation 'com.shawnlin:number-picker:2.4.6' |     implementation 'com.shawnlin:number-picker:2.4.6' | ||||||
|  |     implementation "androidx.preference:preference:1.1.0" | ||||||
|  |     implementation "androidx.work:work-runtime-ktx:2.3.2" | ||||||
|  |     implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3' | ||||||
|  |     implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.2.0' | ||||||
| } | } | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ import android.appwidget.AppWidgetManager | |||||||
| import android.content.ComponentName | import android.content.ComponentName | ||||||
| import android.content.Context | import android.content.Context | ||||||
| import android.content.Intent | import android.content.Intent | ||||||
|  | import android.content.SharedPreferences | ||||||
| import android.media.AudioAttributes | import android.media.AudioAttributes | ||||||
| import android.media.AudioManager | import android.media.AudioManager | ||||||
| import android.net.Uri | import android.net.Uri | ||||||
| @@ -15,6 +16,7 @@ import android.text.style.RelativeSizeSpan | |||||||
| import android.widget.Toast | import android.widget.Toast | ||||||
| import androidx.core.app.AlarmManagerCompat | import androidx.core.app.AlarmManagerCompat | ||||||
| import androidx.core.app.NotificationCompat | import androidx.core.app.NotificationCompat | ||||||
|  | import androidx.preference.PreferenceManager | ||||||
| import com.simplemobiletools.clock.R | import com.simplemobiletools.clock.R | ||||||
| import com.simplemobiletools.clock.activities.ReminderActivity | import com.simplemobiletools.clock.activities.ReminderActivity | ||||||
| import com.simplemobiletools.clock.activities.SnoozeReminderActivity | import com.simplemobiletools.clock.activities.SnoozeReminderActivity | ||||||
| @@ -382,3 +384,5 @@ fun Context.checkAlarmsWithDeletedSoundUri(uri: String) { | |||||||
|         dbHelper.updateAlarm(it) |         dbHelper.updateAlarm(it) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | val Context.preferences: SharedPreferences get() = PreferenceManager.getDefaultSharedPreferences(this) | ||||||
|   | |||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | package com.simplemobiletools.clock.extensions | ||||||
|  |  | ||||||
|  | import android.content.SharedPreferences | ||||||
|  | import androidx.fragment.app.Fragment | ||||||
|  | import androidx.fragment.app.FragmentActivity | ||||||
|  | import androidx.preference.PreferenceManager | ||||||
|  |  | ||||||
|  | val Fragment.requiredActivity: FragmentActivity get() = this.activity!! | ||||||
|  |  | ||||||
|  | val Fragment.preferences: SharedPreferences get() = PreferenceManager.getDefaultSharedPreferences(requiredActivity) | ||||||
| @@ -4,6 +4,7 @@ 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.content.Intent | ||||||
| import android.graphics.Color | import android.graphics.Color | ||||||
| @@ -12,11 +13,16 @@ import android.os.Build | |||||||
| import android.os.Bundle | import android.os.Bundle | ||||||
| import android.os.Handler | import android.os.Handler | ||||||
| import android.os.SystemClock | import android.os.SystemClock | ||||||
|  | import android.util.Log | ||||||
| import android.view.LayoutInflater | import android.view.LayoutInflater | ||||||
| import android.view.View | import android.view.View | ||||||
| import android.view.ViewGroup | 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.lifecycleScope | ||||||
|  | import androidx.work.WorkInfo | ||||||
|  | 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.ReminderActivity | ||||||
| import com.simplemobiletools.clock.activities.SimpleActivity | import com.simplemobiletools.clock.activities.SimpleActivity | ||||||
| @@ -24,53 +30,65 @@ import com.simplemobiletools.clock.dialogs.MyTimePickerDialogDialog | |||||||
| import com.simplemobiletools.clock.extensions.* | import com.simplemobiletools.clock.extensions.* | ||||||
| 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.cancelTimerWorker | ||||||
|  | import com.simplemobiletools.clock.workers.enqueueTimerWorker | ||||||
|  | import com.simplemobiletools.clock.workers.timerRequestId | ||||||
| import com.simplemobiletools.commons.dialogs.SelectAlarmSoundDialog | import com.simplemobiletools.commons.dialogs.SelectAlarmSoundDialog | ||||||
| import com.simplemobiletools.commons.extensions.* | 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 | ||||||
|  |  | ||||||
| class TimerFragment : Fragment() { | class TimerFragment : Fragment() { | ||||||
|  |  | ||||||
|     private val UPDATE_INTERVAL = 1000L |     private val UPDATE_INTERVAL = 1000L | ||||||
|     private val WAS_RUNNING = "was_running" |     private val WAS_RUNNING = "was_running" | ||||||
|     private val CURRENT_TICKS = "current_ticks" |     private val CURRENT_TICKS = "current_ticks" | ||||||
|     private val TOTAL_TICKS = "total_ticks" |     private val TOTAL_TICKS = "total_ticks" | ||||||
|  |  | ||||||
|     private var isRunning = false |     private var isRunning = false | ||||||
|     private var uptimeAtStart = 0L |  | ||||||
|     private var initialSecs = 0 |     private var initialSecs = 0 | ||||||
|     private var totalTicks = 0 |     private var totalTicks = 0 | ||||||
|     private var currentTicks = 0 |     private var currentTicks = 0 | ||||||
|     private var updateHandler = Handler() |  | ||||||
|     private var isForegrounded = true |  | ||||||
|  |  | ||||||
|     lateinit var view: ViewGroup |     lateinit var view: ViewGroup | ||||||
|  |  | ||||||
|  |     @InternalCoroutinesApi | ||||||
|     override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { |     override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { | ||||||
|         val config = context!!.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 { | ||||||
|                 togglePlayPause() |                 val selectedDuration = config.timerSeconds | ||||||
|  |                 enqueueTimerWorker(TimeUnit.SECONDS.toMillis(selectedDuration.toLong())) | ||||||
|  |                 showNotification(selectedDuration.getFormattedDuration()) | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             timer_play_pause.setOnClickListener { |             timer_play_pause.setOnClickListener { | ||||||
|                 togglePlayPause() |                 val selectedDuration = config.timerSeconds | ||||||
|  |                 enqueueTimerWorker(TimeUnit.SECONDS.toMillis(selectedDuration.toLong())) | ||||||
|  |                 showNotification(selectedDuration.getFormattedDuration()) | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             timer_reset.setOnClickListener { |             timer_reset.setOnClickListener { | ||||||
|                 context!!.hideTimerNotification() |                 cancelTimerWorker() | ||||||
|                 resetTimer() |  | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             timer_initial_time.setOnClickListener { |             timer_initial_time.setOnClickListener { | ||||||
|                 MyTimePickerDialogDialog(activity as SimpleActivity, config.timerSeconds) { |                 MyTimePickerDialogDialog(activity as SimpleActivity, config.timerSeconds) { seconds -> | ||||||
|                     val seconds = if (it <= 0) 10 else it |                     val timerSeconds = if (seconds <= 0) 10 else seconds | ||||||
|                     config.timerSeconds = seconds |                     config.timerSeconds = timerSeconds | ||||||
|                     timer_initial_time.text = seconds.getFormattedDuration() |                     timer_initial_time.text = timerSeconds.getFormattedDuration() | ||||||
|                     if (!isRunning) { |  | ||||||
|                         resetTimer() |  | ||||||
|                     } |  | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -81,28 +99,47 @@ class TimerFragment : Fragment() { | |||||||
|  |  | ||||||
|             timer_sound.setOnClickListener { |             timer_sound.setOnClickListener { | ||||||
|                 SelectAlarmSoundDialog(activity as SimpleActivity, config.timerSoundUri, AudioManager.STREAM_ALARM, PICK_AUDIO_FILE_INTENT_ID, |                 SelectAlarmSoundDialog(activity as SimpleActivity, config.timerSoundUri, AudioManager.STREAM_ALARM, PICK_AUDIO_FILE_INTENT_ID, | ||||||
|                         ALARM_SOUND_TYPE_ALARM, true, onAlarmPicked = { |                     ALARM_SOUND_TYPE_ALARM, true, | ||||||
|                     if (it != null) { |                     onAlarmPicked = { sound -> | ||||||
|                         updateAlarmSound(it) |                         if (sound != null) { | ||||||
|                     } |                             updateAlarmSound(sound) | ||||||
|                 }, onAlarmSoundDeleted = { |                         } | ||||||
|                     if (config.timerSoundUri == it.uri) { |                     }, | ||||||
|                         val defaultAlarm = context.getDefaultAlarmSound(ALARM_SOUND_TYPE_ALARM) |                     onAlarmSoundDeleted = { sound -> | ||||||
|                         updateAlarmSound(defaultAlarm) |                         if (config.timerSoundUri == sound.uri) { | ||||||
|                     } |                             val defaultAlarm = context.getDefaultAlarmSound(ALARM_SOUND_TYPE_ALARM) | ||||||
|                     context.checkAlarmsWithDeletedSoundUri(it.uri) |                             updateAlarmSound(defaultAlarm) | ||||||
|                 }) |                         } | ||||||
|  |  | ||||||
|  |                         context.checkAlarmsWithDeletedSoundUri(sound.uri) | ||||||
|  |                     }) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         initialSecs = config.timerSeconds |         initialSecs = config.timerSeconds | ||||||
|         updateDisplayedText() |  | ||||||
|         return view |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     override fun onStart() { |         WorkManager.getInstance(activity!!).getWorkInfoByIdLiveData(timerRequestId) | ||||||
|         super.onStart() |             .observe(this, Observer { workInfo -> | ||||||
|         isForegrounded = true |                 Log.e("test", workInfo.toString()) | ||||||
|  |  | ||||||
|  |                 when (workInfo.state) { | ||||||
|  |                     WorkInfo.State.SUCCEEDED -> { | ||||||
|  |                         showNotification("-") | ||||||
|  |                     } | ||||||
|  |                     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() | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return view | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     override fun onResume() { |     override fun onResume() { | ||||||
| @@ -110,28 +147,12 @@ class TimerFragment : Fragment() { | |||||||
|         setupViews() |         setupViews() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     override fun onStop() { |  | ||||||
|         super.onStop() |  | ||||||
|         isForegrounded = false |  | ||||||
|         context!!.hideNotification(TIMER_NOTIF_ID) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     override fun onDestroy() { |  | ||||||
|         super.onDestroy() |  | ||||||
|         if (isRunning && activity?.isChangingConfigurations == false) { |  | ||||||
|             context?.toast(R.string.timer_stopped) |  | ||||||
|         } |  | ||||||
|         isRunning = false |  | ||||||
|         updateHandler.removeCallbacks(updateRunnable) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     override fun onSaveInstanceState(outState: Bundle) { |     override fun onSaveInstanceState(outState: Bundle) { | ||||||
|         outState.apply { |         super.onSaveInstanceState(outState.apply { | ||||||
|             putBoolean(WAS_RUNNING, isRunning) |             putBoolean(WAS_RUNNING, isRunning) | ||||||
|             putInt(TOTAL_TICKS, totalTicks) |             putInt(TOTAL_TICKS, totalTicks) | ||||||
|             putInt(CURRENT_TICKS, currentTicks) |             putInt(CURRENT_TICKS, currentTicks) | ||||||
|         } |         }) | ||||||
|         super.onSaveInstanceState(outState) |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     override fun onViewStateRestored(savedInstanceState: Bundle?) { |     override fun onViewStateRestored(savedInstanceState: Bundle?) { | ||||||
| @@ -140,25 +161,21 @@ class TimerFragment : Fragment() { | |||||||
|             isRunning = getBoolean(WAS_RUNNING, false) |             isRunning = getBoolean(WAS_RUNNING, false) | ||||||
|             totalTicks = getInt(TOTAL_TICKS, 0) |             totalTicks = getInt(TOTAL_TICKS, 0) | ||||||
|             currentTicks = getInt(CURRENT_TICKS, 0) |             currentTicks = getInt(CURRENT_TICKS, 0) | ||||||
|  |  | ||||||
|             if (isRunning) { |  | ||||||
|                 uptimeAtStart = SystemClock.uptimeMillis() - currentTicks * UPDATE_INTERVAL |  | ||||||
|                 updateTimerState(false) |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fun updateAlarmSound(alarmSound: AlarmSound) { |     fun updateAlarmSound(alarmSound: AlarmSound) { | ||||||
|         context!!.config.timerSoundTitle = alarmSound.title |         requiredActivity.config.timerSoundTitle = alarmSound.title | ||||||
|         context!!.config.timerSoundUri = alarmSound.uri |         requiredActivity.config.timerSoundUri = alarmSound.uri | ||||||
|         view.timer_sound.text = alarmSound.title |         view.timer_sound.text = alarmSound.title | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private fun setupViews() { |     private fun setupViews() { | ||||||
|         val config = context!!.config |         val config = requiredActivity.config | ||||||
|         val textColor = config.textColor |         val textColor = config.textColor | ||||||
|  |  | ||||||
|         view.apply { |         view.apply { | ||||||
|             context!!.updateTextColors(timer_fragment) |             requiredActivity.updateTextColors(timer_fragment) | ||||||
|             timer_play_pause.background = resources.getColoredDrawableWithColor(R.drawable.circle_background_filled, context!!.getAdjustedPrimaryColor()) |             timer_play_pause.background = resources.getColoredDrawableWithColor(R.drawable.circle_background_filled, context!!.getAdjustedPrimaryColor()) | ||||||
|             timer_reset.applyColorFilter(textColor) |             timer_reset.applyColorFilter(textColor) | ||||||
|  |  | ||||||
| @@ -173,84 +190,19 @@ class TimerFragment : Fragment() { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         updateIcons() |         updateIcons() | ||||||
|         updateDisplayedText() |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private fun togglePlayPause() { |  | ||||||
|         isRunning = !isRunning |  | ||||||
|         updateTimerState(true) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private fun updateTimerState(setUptimeAtStart: Boolean) { |  | ||||||
|         updateIcons() |  | ||||||
|         context!!.hideTimerNotification() |  | ||||||
|  |  | ||||||
|         if (isRunning) { |  | ||||||
|             updateHandler.post(updateRunnable) |  | ||||||
|             view.timer_reset.beVisible() |  | ||||||
|             if (setUptimeAtStart) { |  | ||||||
|                 uptimeAtStart = SystemClock.uptimeMillis() |  | ||||||
|             } |  | ||||||
|         } else { |  | ||||||
|             updateHandler.removeCallbacksAndMessages(null) |  | ||||||
|             currentTicks = 0 |  | ||||||
|             totalTicks-- |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private fun updateIcons() { |     private fun updateIcons() { | ||||||
|         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 (context!!.getAdjustedPrimaryColor() == Color.WHITE) Color.BLACK else context!!.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)) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private fun resetTimer() { |  | ||||||
|         updateHandler.removeCallbacks(updateRunnable) |  | ||||||
|         isRunning = false |  | ||||||
|         currentTicks = 0 |  | ||||||
|         totalTicks = 0 |  | ||||||
|         initialSecs = context!!.config.timerSeconds |  | ||||||
|         updateDisplayedText() |  | ||||||
|         updateIcons() |  | ||||||
|         view.timer_reset.beGone() |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     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 |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @TargetApi(Build.VERSION_CODES.O) |     @TargetApi(Build.VERSION_CODES.O) | ||||||
|     private fun showNotification(formattedDuration: String) { |     private fun showNotification(formattedDuration: String) { | ||||||
|         val channelId = "simple_alarm_timer" |         val channelId = "simple_alarm_timer" | ||||||
|         val label = getString(R.string.timer) |         val label = getString(R.string.timer) | ||||||
|         val notificationManager = context!!.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager |         val notificationManager = requiredActivity.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager | ||||||
|         if (isOreoPlus()) { |         if (isOreoPlus()) { | ||||||
|             val importance = NotificationManager.IMPORTANCE_HIGH |             val importance = NotificationManager.IMPORTANCE_HIGH | ||||||
|             NotificationChannel(channelId, label, importance).apply { |             NotificationChannel(channelId, label, importance).apply { | ||||||
| @@ -260,29 +212,62 @@ class TimerFragment : Fragment() { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         val builder = NotificationCompat.Builder(context) |         val builder = NotificationCompat.Builder(context) | ||||||
|                 .setContentTitle(label) |             .setContentTitle(label) | ||||||
|                 .setContentText(formattedDuration) |             .setContentText(formattedDuration) | ||||||
|                 .setSmallIcon(R.drawable.ic_timer) |             .setSmallIcon(R.drawable.ic_timer) | ||||||
|                 .setContentIntent(context!!.getOpenTimerTabIntent()) |             .setContentIntent(context!!.getOpenTimerTabIntent()) | ||||||
|                 .setPriority(Notification.PRIORITY_HIGH) |             .setPriority(Notification.PRIORITY_HIGH) | ||||||
|                 .setSound(null) |             .setSound(null) | ||||||
|                 .setOngoing(true) |             .setOngoing(true) | ||||||
|                 .setAutoCancel(true) |             .setAutoCancel(true) | ||||||
|                 .setChannelId(channelId) |             .setChannelId(channelId) | ||||||
|  |  | ||||||
|         builder.setVisibility(Notification.VISIBILITY_PUBLIC) |         builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) | ||||||
|         notificationManager.notify(TIMER_NOTIF_ID, builder.build()) |         notificationManager.notify(TIMER_NOTIF_ID, builder.build()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private val updateRunnable = object : Runnable { |  | ||||||
|         override fun run() { |  | ||||||
|             if (isRunning) { |  | ||||||
|                 if (updateDisplayedText()) { |  | ||||||
|                     currentTicks++ |  | ||||||
|                     totalTicks++ |  | ||||||
|                     updateHandler.postAtTime(this, uptimeAtStart + currentTicks * UPDATE_INTERVAL) |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | //    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 | ||||||
|  | //    } | ||||||
|   | |||||||
| @@ -0,0 +1,41 @@ | |||||||
|  | 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 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" | ||||||
|  |  | ||||||
|  | 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())) | ||||||
|  |  | ||||||
|  | fun Fragment.cancelTimerWorker() = | ||||||
|  |     WorkManager.getInstance(requiredActivity).apply { | ||||||
|  |         timerRequestId.let(::cancelWorkById) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | 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 { | ||||||
|  |         saveTimerRequestId(it.id) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | class TimerWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) { | ||||||
|  |     override fun doWork(): Result = | ||||||
|  |         try { | ||||||
|  |             Result.success() | ||||||
|  |         } catch (exception: Exception) { | ||||||
|  |             Result.failure() | ||||||
|  |         } | ||||||
|  | } | ||||||
|  |  | ||||||
		Reference in New Issue
	
	Block a user
	 Pavol Franek
					Pavol Franek