Removed use of coroutines and using `ensureBackgroundThreadWithResult`

This commit is contained in:
Rawlin C 2023-07-07 23:43:35 +05:30
parent 58953f2b22
commit d7fa3ca4dc
7 changed files with 127 additions and 91 deletions

View File

@ -44,9 +44,11 @@ class MainActivity : SimpleActivity() {
setupTabs()
updateWidgets()
lifecycleScope.launch(Dispatchers.IO) {
if (getEnabledAlarms().isEmpty()) {
rescheduleEnabledAlarms()
getEnabledAlarms { enabledAlarms ->
if (enabledAlarms.isNullOrEmpty()) {
ensureBackgroundThread {
rescheduleEnabledAlarms()
}
}
}
}

View File

@ -270,41 +270,58 @@ fun Context.formatTo12HourFormat(showSeconds: Boolean, hours: Int, minutes: Int,
return "${formatTime(showSeconds, false, newHours, minutes, seconds)} $appendable"
}
suspend fun Context.getClosestEnabledAlarmString(): String = withContext(Dispatchers.IO) {
val nextAlarmList = getEnabledAlarms()
.mapNotNull { getTimeUntilNextAlarm(it.timeInMinutes, it.days) }
if (nextAlarmList.isEmpty()) {
return@withContext ""
}
var closestAlarmTime = Int.MAX_VALUE
nextAlarmList.forEach { time ->
if (time < closestAlarmTime) {
closestAlarmTime = time
fun Context.getClosestEnabledAlarmString(result: (String) -> Unit) {
getEnabledAlarms { enabledAlarms ->
if (enabledAlarms == null) {
result.invoke("")
return@getEnabledAlarms
}
}
if (closestAlarmTime == Int.MAX_VALUE) {
return@withContext ""
}
val nextAlarmList = enabledAlarms
.mapNotNull { getTimeUntilNextAlarm(it.timeInMinutes, it.days) }
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@getClosestEnabledAlarmString)) {
"HH:mm"
} else {
"h:mm a"
}
if (nextAlarmList.isEmpty()) {
result.invoke("")
}
val formattedTime = SimpleDateFormat(pattern, Locale.getDefault()).format(calendar.time)
return@withContext "$dayOfWeek $formattedTime"
var closestAlarmTime = Int.MAX_VALUE
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) {
return@withContext dbHelper.getEnabledAlarms()
fun Context.getEnabledAlarms(enabledAlarms: (List<Alarm>?) -> Unit) {
ensureBackgroundThreadWithResult(
task = {
dbHelper.getEnabledAlarms()
},
callback = { alarms ->
enabledAlarms.invoke(alarms)
},
onError = {
enabledAlarms.invoke(null)
}
)
}
fun Context.rescheduleEnabledAlarms() {

View File

@ -21,6 +21,7 @@ import com.simplemobiletools.commons.extensions.getProperTextColor
import com.simplemobiletools.commons.extensions.toast
import com.simplemobiletools.commons.extensions.updateTextColors
import com.simplemobiletools.commons.helpers.SORT_BY_DATE_CREATED
import com.simplemobiletools.commons.helpers.ensureBackgroundThread
import com.simplemobiletools.commons.models.AlarmSound
import kotlinx.android.synthetic.main.fragment_alarm.view.*
import kotlinx.coroutines.Dispatchers
@ -91,12 +92,14 @@ class AlarmFragment : Fragment(), ToggleAlarmInterface {
it.timeInMinutes
})
}
lifecycleScope.launch(Dispatchers.IO) {
if (context?.getEnabledAlarms()?.isEmpty() == true) {
context?.getEnabledAlarms { enabledAlarms ->
if (enabledAlarms.isNullOrEmpty()) {
alarms.forEach {
if (it.days == TODAY_BIT && it.isEnabled && it.timeInMinutes <= getCurrentDayMinutes()) {
it.isEnabled = false
context?.dbHelper?.updateAlarmEnabledState(it.id, false)
ensureBackgroundThread {
context?.dbHelper?.updateAlarmEnabledState(it.id, false)
}
}
}
}

View File

@ -7,7 +7,6 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import com.simplemobiletools.clock.R
import com.simplemobiletools.clock.activities.SimpleActivity
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.getProperTextColor
import com.simplemobiletools.commons.extensions.updateTextColors
import kotlinx.android.synthetic.main.fragment_clock.*
import kotlinx.android.synthetic.main.fragment_clock.view.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import java.util.*
class ClockFragment : Fragment() {
@ -116,8 +112,7 @@ class ClockFragment : Fragment() {
fun updateAlarm() {
view.apply {
lifecycleScope.launch {
val nextAlarm = requireContext().getClosestEnabledAlarmString()
requireContext().getClosestEnabledAlarmString { nextAlarm ->
clock_alarm.beVisibleIf(nextAlarm.isNotEmpty())
clock_alarm.text = nextAlarm
clock_alarm.colorCompoundDrawable(requireContext().getProperTextColor())

View File

@ -1,13 +1,12 @@
package com.simplemobiletools.clock.helpers
import android.content.BroadcastReceiver
import android.os.Handler
import android.os.Looper
import com.simplemobiletools.clock.models.MyTimeZone
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import com.simplemobiletools.commons.helpers.isOnMainThread
import java.util.*
import kotlin.coroutines.CoroutineContext
import java.util.concurrent.Callable
import java.util.concurrent.Executors
import kotlin.math.pow
// shared preferences
@ -243,16 +242,39 @@ fun getTimeDifferenceInMinutes(currentTimeInMinutes: Int, alarmTimeInMinutes: In
}
}
fun BroadcastReceiver.goAsync(
context: CoroutineContext = (Dispatchers.Main.immediate + SupervisorJob()),
block: suspend CoroutineScope.() -> Unit
/**
* Runs tasks that you want on a background thread and returns the result or error
* @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()
CoroutineScope(SupervisorJob()).launch(context) {
val executor = if (isOnMainThread()) {
Executors.newSingleThreadExecutor()
} else {
Executors.newFixedThreadPool(1)
}
val handler = Handler(Looper.getMainLooper())
val future = executor.submit(task)
executor.submit {
try {
block()
val result = future.get()
handler.post {
callback(result)
}
} catch (t: Throwable) {
handler.post {
onError?.invoke(t)
}
} finally {
pendingResult.finish()
executor.shutdown()
}
}
}

View File

@ -42,17 +42,10 @@ class MyDigitalTimeWidgetProvider : AppWidgetProvider() {
}
private fun updateTexts(context: Context, views: RemoteViews) {
CoroutineScope(Dispatchers.IO).launch {
try {
val nextAlarm = context.getClosestEnabledAlarmString()
withContext(Dispatchers.Main.immediate) {
views.apply {
setText(R.id.widget_next_alarm, nextAlarm)
setVisibleIf(R.id.widget_alarm_holder, nextAlarm.isNotEmpty())
}
}
} finally {
cancel()
context.getClosestEnabledAlarmString { nextAlarm ->
views.apply {
setText(R.id.widget_next_alarm, nextAlarm)
setVisibleIf(R.id.widget_alarm_holder, nextAlarm.isNotEmpty())
}
}
}

View File

@ -14,45 +14,49 @@ import com.simplemobiletools.clock.extensions.getOpenAlarmTabIntent
import com.simplemobiletools.clock.helpers.ALARM_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.goAsync
import com.simplemobiletools.commons.helpers.isOreoPlus
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)
if (alarmId == -1) {
return@goAsync
return
}
triggerEarlyDismissalNotification(context, alarmId)
}
private suspend fun triggerEarlyDismissalNotification(context: Context, alarmId: Int) {
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (isOreoPlus()) {
NotificationChannel(EARLY_ALARM_DISMISSAL_CHANNEL_ID, context.getString(R.string.early_alarm_dismissal), NotificationManager.IMPORTANCE_DEFAULT).apply {
setBypassDnd(true)
setSound(null, null)
notificationManager.createNotificationChannel(this)
private fun triggerEarlyDismissalNotification(context: Context, alarmId: Int) {
context.getClosestEnabledAlarmString { alarmString ->
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (isOreoPlus()) {
NotificationChannel(
EARLY_ALARM_DISMISSAL_CHANNEL_ID,
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)
}
}