mirror of
https://github.com/SimpleMobileTools/Simple-Clock.git
synced 2025-06-05 22:19:17 +02:00
Removed use of coroutines and using ensureBackgroundThreadWithResult
This commit is contained in:
@ -44,9 +44,11 @@ class MainActivity : SimpleActivity() {
|
|||||||
setupTabs()
|
setupTabs()
|
||||||
updateWidgets()
|
updateWidgets()
|
||||||
|
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
getEnabledAlarms { enabledAlarms ->
|
||||||
if (getEnabledAlarms().isEmpty()) {
|
if (enabledAlarms.isNullOrEmpty()) {
|
||||||
rescheduleEnabledAlarms()
|
ensureBackgroundThread {
|
||||||
|
rescheduleEnabledAlarms()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -270,41 +270,58 @@ fun Context.formatTo12HourFormat(showSeconds: Boolean, hours: Int, minutes: Int,
|
|||||||
return "${formatTime(showSeconds, false, newHours, minutes, seconds)} $appendable"
|
return "${formatTime(showSeconds, false, newHours, minutes, seconds)} $appendable"
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun Context.getClosestEnabledAlarmString(): String = withContext(Dispatchers.IO) {
|
fun Context.getClosestEnabledAlarmString(result: (String) -> Unit) {
|
||||||
val nextAlarmList = getEnabledAlarms()
|
getEnabledAlarms { enabledAlarms ->
|
||||||
.mapNotNull { getTimeUntilNextAlarm(it.timeInMinutes, it.days) }
|
if (enabledAlarms == null) {
|
||||||
|
result.invoke("")
|
||||||
if (nextAlarmList.isEmpty()) {
|
return@getEnabledAlarms
|
||||||
return@withContext ""
|
|
||||||
}
|
|
||||||
|
|
||||||
var closestAlarmTime = Int.MAX_VALUE
|
|
||||||
nextAlarmList.forEach { time ->
|
|
||||||
if (time < closestAlarmTime) {
|
|
||||||
closestAlarmTime = time
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (closestAlarmTime == Int.MAX_VALUE) {
|
val nextAlarmList = enabledAlarms
|
||||||
return@withContext ""
|
.mapNotNull { getTimeUntilNextAlarm(it.timeInMinutes, it.days) }
|
||||||
}
|
|
||||||
|
|
||||||
val calendar = Calendar.getInstance().apply { firstDayOfWeek = Calendar.MONDAY }
|
if (nextAlarmList.isEmpty()) {
|
||||||
calendar.add(Calendar.MINUTE, closestAlarmTime)
|
result.invoke("")
|
||||||
val dayOfWeekIndex = (calendar.get(Calendar.DAY_OF_WEEK) + 5) % 7
|
}
|
||||||
val dayOfWeek = resources.getStringArray(R.array.week_days_short)[dayOfWeekIndex]
|
|
||||||
val pattern = if (DateFormat.is24HourFormat(this@getClosestEnabledAlarmString)) {
|
|
||||||
"HH:mm"
|
|
||||||
} else {
|
|
||||||
"h:mm a"
|
|
||||||
}
|
|
||||||
|
|
||||||
val formattedTime = SimpleDateFormat(pattern, Locale.getDefault()).format(calendar.time)
|
var closestAlarmTime = Int.MAX_VALUE
|
||||||
return@withContext "$dayOfWeek $formattedTime"
|
nextAlarmList.forEach { time ->
|
||||||
|
if (time < closestAlarmTime) {
|
||||||
|
closestAlarmTime = time
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (closestAlarmTime == Int.MAX_VALUE) {
|
||||||
|
result.invoke("")
|
||||||
|
}
|
||||||
|
|
||||||
|
val calendar = Calendar.getInstance().apply { firstDayOfWeek = Calendar.MONDAY }
|
||||||
|
calendar.add(Calendar.MINUTE, closestAlarmTime)
|
||||||
|
val dayOfWeekIndex = (calendar.get(Calendar.DAY_OF_WEEK) + 5) % 7
|
||||||
|
val dayOfWeek = resources.getStringArray(R.array.week_days_short)[dayOfWeekIndex]
|
||||||
|
val pattern = if (DateFormat.is24HourFormat(this)) {
|
||||||
|
"HH:mm"
|
||||||
|
} else {
|
||||||
|
"h:mm a"
|
||||||
|
}
|
||||||
|
|
||||||
|
val formattedTime = SimpleDateFormat(pattern, Locale.getDefault()).format(calendar.time)
|
||||||
|
result.invoke("$dayOfWeek $formattedTime")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun Context.getEnabledAlarms(): List<Alarm> = withContext(Dispatchers.IO) {
|
fun Context.getEnabledAlarms(enabledAlarms: (List<Alarm>?) -> Unit) {
|
||||||
return@withContext dbHelper.getEnabledAlarms()
|
ensureBackgroundThreadWithResult(
|
||||||
|
task = {
|
||||||
|
dbHelper.getEnabledAlarms()
|
||||||
|
},
|
||||||
|
callback = { alarms ->
|
||||||
|
enabledAlarms.invoke(alarms)
|
||||||
|
},
|
||||||
|
onError = {
|
||||||
|
enabledAlarms.invoke(null)
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.rescheduleEnabledAlarms() {
|
fun Context.rescheduleEnabledAlarms() {
|
||||||
|
@ -21,6 +21,7 @@ import com.simplemobiletools.commons.extensions.getProperTextColor
|
|||||||
import com.simplemobiletools.commons.extensions.toast
|
import com.simplemobiletools.commons.extensions.toast
|
||||||
import com.simplemobiletools.commons.extensions.updateTextColors
|
import com.simplemobiletools.commons.extensions.updateTextColors
|
||||||
import com.simplemobiletools.commons.helpers.SORT_BY_DATE_CREATED
|
import com.simplemobiletools.commons.helpers.SORT_BY_DATE_CREATED
|
||||||
|
import com.simplemobiletools.commons.helpers.ensureBackgroundThread
|
||||||
import com.simplemobiletools.commons.models.AlarmSound
|
import com.simplemobiletools.commons.models.AlarmSound
|
||||||
import kotlinx.android.synthetic.main.fragment_alarm.view.*
|
import kotlinx.android.synthetic.main.fragment_alarm.view.*
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@ -91,12 +92,14 @@ class AlarmFragment : Fragment(), ToggleAlarmInterface {
|
|||||||
it.timeInMinutes
|
it.timeInMinutes
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
context?.getEnabledAlarms { enabledAlarms ->
|
||||||
if (context?.getEnabledAlarms()?.isEmpty() == true) {
|
if (enabledAlarms.isNullOrEmpty()) {
|
||||||
alarms.forEach {
|
alarms.forEach {
|
||||||
if (it.days == TODAY_BIT && it.isEnabled && it.timeInMinutes <= getCurrentDayMinutes()) {
|
if (it.days == TODAY_BIT && it.isEnabled && it.timeInMinutes <= getCurrentDayMinutes()) {
|
||||||
it.isEnabled = false
|
it.isEnabled = false
|
||||||
context?.dbHelper?.updateAlarmEnabledState(it.id, false)
|
ensureBackgroundThread {
|
||||||
|
context?.dbHelper?.updateAlarmEnabledState(it.id, false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ import android.view.LayoutInflater
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import com.simplemobiletools.clock.R
|
import com.simplemobiletools.clock.R
|
||||||
import com.simplemobiletools.clock.activities.SimpleActivity
|
import com.simplemobiletools.clock.activities.SimpleActivity
|
||||||
import com.simplemobiletools.clock.adapters.TimeZonesAdapter
|
import com.simplemobiletools.clock.adapters.TimeZonesAdapter
|
||||||
@ -19,10 +18,7 @@ import com.simplemobiletools.clock.models.MyTimeZone
|
|||||||
import com.simplemobiletools.commons.extensions.beVisibleIf
|
import com.simplemobiletools.commons.extensions.beVisibleIf
|
||||||
import com.simplemobiletools.commons.extensions.getProperTextColor
|
import com.simplemobiletools.commons.extensions.getProperTextColor
|
||||||
import com.simplemobiletools.commons.extensions.updateTextColors
|
import com.simplemobiletools.commons.extensions.updateTextColors
|
||||||
import kotlinx.android.synthetic.main.fragment_clock.*
|
|
||||||
import kotlinx.android.synthetic.main.fragment_clock.view.*
|
import kotlinx.android.synthetic.main.fragment_clock.view.*
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class ClockFragment : Fragment() {
|
class ClockFragment : Fragment() {
|
||||||
@ -116,8 +112,7 @@ class ClockFragment : Fragment() {
|
|||||||
|
|
||||||
fun updateAlarm() {
|
fun updateAlarm() {
|
||||||
view.apply {
|
view.apply {
|
||||||
lifecycleScope.launch {
|
requireContext().getClosestEnabledAlarmString { nextAlarm ->
|
||||||
val nextAlarm = requireContext().getClosestEnabledAlarmString()
|
|
||||||
clock_alarm.beVisibleIf(nextAlarm.isNotEmpty())
|
clock_alarm.beVisibleIf(nextAlarm.isNotEmpty())
|
||||||
clock_alarm.text = nextAlarm
|
clock_alarm.text = nextAlarm
|
||||||
clock_alarm.colorCompoundDrawable(requireContext().getProperTextColor())
|
clock_alarm.colorCompoundDrawable(requireContext().getProperTextColor())
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
package com.simplemobiletools.clock.helpers
|
package com.simplemobiletools.clock.helpers
|
||||||
|
|
||||||
import android.content.BroadcastReceiver
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
import com.simplemobiletools.clock.models.MyTimeZone
|
import com.simplemobiletools.clock.models.MyTimeZone
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import com.simplemobiletools.commons.helpers.isOnMainThread
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.SupervisorJob
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.coroutines.CoroutineContext
|
import java.util.concurrent.Callable
|
||||||
|
import java.util.concurrent.Executors
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
|
|
||||||
// shared preferences
|
// shared preferences
|
||||||
@ -243,16 +242,39 @@ fun getTimeDifferenceInMinutes(currentTimeInMinutes: Int, alarmTimeInMinutes: In
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun BroadcastReceiver.goAsync(
|
/**
|
||||||
context: CoroutineContext = (Dispatchers.Main.immediate + SupervisorJob()),
|
* Runs tasks that you want on a background thread and returns the result or error
|
||||||
block: suspend CoroutineScope.() -> Unit
|
* @param task: Callable to add code that should execute on a background thread
|
||||||
|
* @param callback: Gives back the result from the task after it has completed executing on the Main thread
|
||||||
|
* @param onError: Gives the error thrown if any by the Callable on the Main thread
|
||||||
|
*/
|
||||||
|
fun <T> ensureBackgroundThreadWithResult(
|
||||||
|
task: Callable<T>,
|
||||||
|
callback: (T) -> Unit,
|
||||||
|
onError: ((Throwable) -> Unit)? = null
|
||||||
) {
|
) {
|
||||||
val pendingResult = goAsync()
|
val executor = if (isOnMainThread()) {
|
||||||
CoroutineScope(SupervisorJob()).launch(context) {
|
Executors.newSingleThreadExecutor()
|
||||||
|
} else {
|
||||||
|
Executors.newFixedThreadPool(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
val handler = Handler(Looper.getMainLooper())
|
||||||
|
|
||||||
|
val future = executor.submit(task)
|
||||||
|
|
||||||
|
executor.submit {
|
||||||
try {
|
try {
|
||||||
block()
|
val result = future.get()
|
||||||
|
handler.post {
|
||||||
|
callback(result)
|
||||||
|
}
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
handler.post {
|
||||||
|
onError?.invoke(t)
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
pendingResult.finish()
|
executor.shutdown()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,17 +42,10 @@ class MyDigitalTimeWidgetProvider : AppWidgetProvider() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun updateTexts(context: Context, views: RemoteViews) {
|
private fun updateTexts(context: Context, views: RemoteViews) {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
context.getClosestEnabledAlarmString { nextAlarm ->
|
||||||
try {
|
views.apply {
|
||||||
val nextAlarm = context.getClosestEnabledAlarmString()
|
setText(R.id.widget_next_alarm, nextAlarm)
|
||||||
withContext(Dispatchers.Main.immediate) {
|
setVisibleIf(R.id.widget_alarm_holder, nextAlarm.isNotEmpty())
|
||||||
views.apply {
|
|
||||||
setText(R.id.widget_next_alarm, nextAlarm)
|
|
||||||
setVisibleIf(R.id.widget_alarm_holder, nextAlarm.isNotEmpty())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
cancel()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,45 +14,49 @@ import com.simplemobiletools.clock.extensions.getOpenAlarmTabIntent
|
|||||||
import com.simplemobiletools.clock.helpers.ALARM_ID
|
import com.simplemobiletools.clock.helpers.ALARM_ID
|
||||||
import com.simplemobiletools.clock.helpers.EARLY_ALARM_DISMISSAL_CHANNEL_ID
|
import com.simplemobiletools.clock.helpers.EARLY_ALARM_DISMISSAL_CHANNEL_ID
|
||||||
import com.simplemobiletools.clock.helpers.EARLY_ALARM_NOTIF_ID
|
import com.simplemobiletools.clock.helpers.EARLY_ALARM_NOTIF_ID
|
||||||
import com.simplemobiletools.clock.helpers.goAsync
|
|
||||||
import com.simplemobiletools.commons.helpers.isOreoPlus
|
import com.simplemobiletools.commons.helpers.isOreoPlus
|
||||||
|
|
||||||
class EarlyAlarmDismissalReceiver : BroadcastReceiver() {
|
class EarlyAlarmDismissalReceiver : BroadcastReceiver() {
|
||||||
|
|
||||||
override fun onReceive(context: Context, intent: Intent) = goAsync {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
val alarmId = intent.getIntExtra(ALARM_ID, -1)
|
val alarmId = intent.getIntExtra(ALARM_ID, -1)
|
||||||
if (alarmId == -1) {
|
if (alarmId == -1) {
|
||||||
return@goAsync
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
triggerEarlyDismissalNotification(context, alarmId)
|
triggerEarlyDismissalNotification(context, alarmId)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun triggerEarlyDismissalNotification(context: Context, alarmId: Int) {
|
private fun triggerEarlyDismissalNotification(context: Context, alarmId: Int) {
|
||||||
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
context.getClosestEnabledAlarmString { alarmString ->
|
||||||
if (isOreoPlus()) {
|
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
NotificationChannel(EARLY_ALARM_DISMISSAL_CHANNEL_ID, context.getString(R.string.early_alarm_dismissal), NotificationManager.IMPORTANCE_DEFAULT).apply {
|
if (isOreoPlus()) {
|
||||||
setBypassDnd(true)
|
NotificationChannel(
|
||||||
setSound(null, null)
|
EARLY_ALARM_DISMISSAL_CHANNEL_ID,
|
||||||
notificationManager.createNotificationChannel(this)
|
context.getString(R.string.early_alarm_dismissal),
|
||||||
|
NotificationManager.IMPORTANCE_DEFAULT
|
||||||
|
).apply {
|
||||||
|
setBypassDnd(true)
|
||||||
|
setSound(null, null)
|
||||||
|
notificationManager.createNotificationChannel(this)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
val dismissIntent = context.getDismissAlarmPendingIntent(alarmId, EARLY_ALARM_NOTIF_ID)
|
||||||
|
val contentIntent = context.getOpenAlarmTabIntent()
|
||||||
|
val notification = NotificationCompat.Builder(context)
|
||||||
|
.setContentTitle(context.getString(R.string.upcoming_alarm))
|
||||||
|
.setContentText(alarmString)
|
||||||
|
.setSmallIcon(R.drawable.ic_alarm_vector)
|
||||||
|
.setPriority(Notification.PRIORITY_LOW)
|
||||||
|
.addAction(0, context.getString(R.string.dismiss), dismissIntent)
|
||||||
|
.setContentIntent(contentIntent)
|
||||||
|
.setSound(null)
|
||||||
|
.setAutoCancel(true)
|
||||||
|
.setChannelId(EARLY_ALARM_DISMISSAL_CHANNEL_ID)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
notificationManager.notify(EARLY_ALARM_NOTIF_ID, notification)
|
||||||
}
|
}
|
||||||
|
|
||||||
val dismissIntent = context.getDismissAlarmPendingIntent(alarmId, EARLY_ALARM_NOTIF_ID)
|
|
||||||
val contentIntent = context.getOpenAlarmTabIntent()
|
|
||||||
val notification = NotificationCompat.Builder(context)
|
|
||||||
.setContentTitle(context.getString(R.string.upcoming_alarm))
|
|
||||||
.setContentText(context.getClosestEnabledAlarmString())
|
|
||||||
.setSmallIcon(R.drawable.ic_alarm_vector)
|
|
||||||
.setPriority(Notification.PRIORITY_LOW)
|
|
||||||
.addAction(0, context.getString(R.string.dismiss), dismissIntent)
|
|
||||||
.setContentIntent(contentIntent)
|
|
||||||
.setSound(null)
|
|
||||||
.setAutoCancel(true)
|
|
||||||
.setChannelId(EARLY_ALARM_DISMISSAL_CHANNEL_ID)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
notificationManager.notify(EARLY_ALARM_NOTIF_ID, notification)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user