Removed use of coroutines and using `ensureBackgroundThreadWithResult`
This commit is contained in:
parent
58953f2b22
commit
d7fa3ca4dc
|
@ -44,9 +44,11 @@ class MainActivity : SimpleActivity() {
|
|||
setupTabs()
|
||||
updateWidgets()
|
||||
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
if (getEnabledAlarms().isEmpty()) {
|
||||
rescheduleEnabledAlarms()
|
||||
getEnabledAlarms { enabledAlarms ->
|
||||
if (enabledAlarms.isNullOrEmpty()) {
|
||||
ensureBackgroundThread {
|
||||
rescheduleEnabledAlarms()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue