mirror of
https://github.com/SimpleMobileTools/Simple-Clock.git
synced 2025-06-05 22:19:17 +02:00
281 lines
12 KiB
Kotlin
281 lines
12 KiB
Kotlin
package com.simplemobiletools.clock.helpers
|
|
|
|
import android.os.Handler
|
|
import android.os.Looper
|
|
import com.simplemobiletools.clock.models.MyTimeZone
|
|
import com.simplemobiletools.commons.helpers.isOnMainThread
|
|
import java.util.*
|
|
import java.util.concurrent.Callable
|
|
import java.util.concurrent.Executors
|
|
import kotlin.math.pow
|
|
|
|
// shared preferences
|
|
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_VIBRATE = "timer_vibrate"
|
|
const val TIMER_SOUND_URI = "timer_sound_uri"
|
|
const val TIMER_SOUND_TITLE = "timer_sound_title"
|
|
const val TIMER_CHANNEL_ID = "timer_channel_id"
|
|
const val TIMER_LABEL = "timer_label"
|
|
const val TOGGLE_STOPWATCH = "toggle_stopwatch"
|
|
const val TIMER_MAX_REMINDER_SECS = "timer_max_reminder_secs"
|
|
const val ALARM_MAX_REMINDER_SECS = "alarm_max_reminder_secs"
|
|
const val ALARM_LAST_CONFIG = "alarm_last_config"
|
|
const val TIMER_LAST_CONFIG = "timer_last_config"
|
|
const val INCREASE_VOLUME_GRADUALLY = "increase_volume_gradually"
|
|
const val ALARMS_SORT_BY = "alarms_sort_by"
|
|
const val STOPWATCH_LAPS_SORT_BY = "stopwatch_laps_sort_by"
|
|
const val WAS_INITIAL_WIDGET_SET_UP = "was_initial_widget_set_up"
|
|
|
|
const val TABS_COUNT = 4
|
|
const val EDITED_TIME_ZONE_SEPARATOR = ":"
|
|
const val ALARM_ID = "alarm_id"
|
|
const val NOTIFICATION_ID = "notification_id"
|
|
const val DEFAULT_ALARM_MINUTES = 480
|
|
const val DEFAULT_MAX_ALARM_REMINDER_SECS = 300
|
|
const val DEFAULT_MAX_TIMER_REMINDER_SECS = 60
|
|
const val SIMPLE_PHONE = "Simple_Phone"
|
|
const val ALARM_NOTIFICATION_CHANNEL_ID = "Alarm_Channel"
|
|
const val EARLY_ALARM_DISMISSAL_CHANNEL_ID = "Early Alarm Dismissal"
|
|
|
|
const val OPEN_STOPWATCH_TAB_INTENT_ID = 9993
|
|
const val PICK_AUDIO_FILE_INTENT_ID = 9994
|
|
const val REMINDER_ACTIVITY_INTENT_ID = 9995
|
|
const val OPEN_ALARMS_TAB_INTENT_ID = 9996
|
|
const val OPEN_APP_INTENT_ID = 9997
|
|
const val ALARM_NOTIF_ID = 9998
|
|
const val TIMER_RUNNING_NOTIF_ID = 10000
|
|
const val STOPWATCH_RUNNING_NOTIF_ID = 10001
|
|
const val EARLY_ALARM_DISMISSAL_INTENT_ID = 10002
|
|
const val EARLY_ALARM_NOTIF_ID = 10003
|
|
|
|
const val OPEN_TAB = "open_tab"
|
|
const val TAB_CLOCK = 0
|
|
const val TAB_ALARM = 1
|
|
const val TAB_STOPWATCH = 2
|
|
const val TAB_TIMER = 3
|
|
const val TIMER_ID = "timer_id"
|
|
const val INVALID_TIMER_ID = -1
|
|
|
|
// stopwatch sorting
|
|
const val SORT_BY_LAP = 1
|
|
const val SORT_BY_LAP_TIME = 2
|
|
const val SORT_BY_TOTAL_TIME = 4
|
|
|
|
// alarm sorting
|
|
const val SORT_BY_CREATION_ORDER = 0
|
|
const val SORT_BY_ALARM_TIME = 1
|
|
const val SORT_BY_DATE_AND_TIME = 2
|
|
|
|
const val TODAY_BIT = -1
|
|
const val TOMORROW_BIT = -2
|
|
|
|
// stopwatch shortcut
|
|
const val STOPWATCH_SHORTCUT_ID = "stopwatch_shortcut_id"
|
|
const val STOPWATCH_TOGGLE_ACTION = "com.simplemobiletools.clock.TOGGLE_STOPWATCH"
|
|
|
|
fun getDefaultTimeZoneTitle(id: Int) = getAllTimeZones().firstOrNull { it.id == id }?.title ?: ""
|
|
|
|
fun getPassedSeconds(): Int {
|
|
val calendar = Calendar.getInstance()
|
|
val isDaylightSavingActive = TimeZone.getDefault().inDaylightTime(Date())
|
|
var offset = calendar.timeZone.rawOffset
|
|
if (isDaylightSavingActive) {
|
|
offset += TimeZone.getDefault().dstSavings
|
|
}
|
|
return ((calendar.timeInMillis + offset) / 1000).toInt()
|
|
}
|
|
|
|
fun formatTime(showSeconds: Boolean, use24HourFormat: Boolean, hours: Int, minutes: Int, seconds: Int): String {
|
|
val hoursFormat = if (use24HourFormat) "%02d" else "%01d"
|
|
var format = "$hoursFormat:%02d"
|
|
|
|
return if (showSeconds) {
|
|
format += ":%02d"
|
|
String.format(format, hours, minutes, seconds)
|
|
} else {
|
|
String.format(format, hours, minutes)
|
|
}
|
|
}
|
|
|
|
fun getTomorrowBit(): Int {
|
|
val calendar = Calendar.getInstance()
|
|
calendar.add(Calendar.DAY_OF_WEEK, 1)
|
|
val dayOfWeek = (calendar.get(Calendar.DAY_OF_WEEK) + 5) % 7
|
|
return 2.0.pow(dayOfWeek).toInt()
|
|
}
|
|
|
|
fun getCurrentDayMinutes(): Int {
|
|
val calendar = Calendar.getInstance()
|
|
return calendar.get(Calendar.HOUR_OF_DAY) * 60 + calendar.get(Calendar.MINUTE)
|
|
}
|
|
|
|
fun getAllTimeZones() = arrayListOf(
|
|
MyTimeZone(1, "GMT-11:00 Midway", "Pacific/Midway"),
|
|
MyTimeZone(2, "GMT-10:00 Honolulu", "Pacific/Honolulu"),
|
|
MyTimeZone(3, "GMT-09:00 Anchorage", "America/Anchorage"),
|
|
MyTimeZone(4, "GMT-08:00 Los Angeles", "America/Los_Angeles"),
|
|
MyTimeZone(5, "GMT-08:00 Tijuana", "America/Tijuana"),
|
|
MyTimeZone(6, "GMT-07:00 Phoenix", "America/Phoenix"),
|
|
MyTimeZone(7, "GMT-07:00 Chihuahua", "America/Chihuahua"),
|
|
MyTimeZone(8, "GMT-07:00 Denver", "America/Denver"),
|
|
MyTimeZone(9, "GMT-06:00 Costa Rica", "America/Costa_Rica"),
|
|
MyTimeZone(10, "GMT-06:00 Chicago", "America/Chicago"),
|
|
MyTimeZone(11, "GMT-06:00 Mexico City", "America/Mexico_City"),
|
|
MyTimeZone(12, "GMT-06:00 Regina", "America/Regina"),
|
|
MyTimeZone(13, "GMT-05:00 Bogota", "America/Bogota"),
|
|
MyTimeZone(14, "GMT-05:00 New York", "America/New_York"),
|
|
MyTimeZone(15, "GMT-04:00 Caracas", "America/Caracas"),
|
|
MyTimeZone(16, "GMT-04:00 Barbados", "America/Barbados"),
|
|
MyTimeZone(17, "GMT-04:00 Halifax", "America/Halifax"),
|
|
MyTimeZone(18, "GMT-04:00 Manaus", "America/Manaus"),
|
|
MyTimeZone(19, "GMT-03:30 St. John's", "America/St_Johns"),
|
|
MyTimeZone(20, "GMT-03:00 Santiago", "America/Santiago"),
|
|
MyTimeZone(21, "GMT-03:00 Recife", "America/Recife"),
|
|
MyTimeZone(22, "GMT-03:00 Sao Paulo", "America/Sao_Paulo"),
|
|
MyTimeZone(23, "GMT-03:00 Buenos Aires", "America/Buenos_Aires"),
|
|
MyTimeZone(24, "GMT-03:00 Nuuk", "America/Godthab"),
|
|
MyTimeZone(25, "GMT-03:00 Montevideo", "America/Montevideo"),
|
|
MyTimeZone(26, "GMT-02:00 South Georgia", "Atlantic/South_Georgia"),
|
|
MyTimeZone(27, "GMT-01:00 Azores", "Atlantic/Azores"),
|
|
MyTimeZone(28, "GMT-01:00 Cape Verde", "Atlantic/Cape_Verde"),
|
|
MyTimeZone(29, "GMT+00:00 Casablanca", "Africa/Casablanca"),
|
|
MyTimeZone(30, "GMT+00:00 Greenwich Mean Time", "Etc/Greenwich"),
|
|
MyTimeZone(31, "GMT+01:00 Amsterdam", "Europe/Amsterdam"),
|
|
MyTimeZone(32, "GMT+01:00 Belgrade", "Europe/Belgrade"),
|
|
MyTimeZone(33, "GMT+01:00 Brussels", "Europe/Brussels"),
|
|
MyTimeZone(34, "GMT+01:00 Madrid", "Europe/Madrid"),
|
|
MyTimeZone(35, "GMT+01:00 Sarajevo", "Europe/Sarajevo"),
|
|
MyTimeZone(36, "GMT+01:00 Brazzaville", "Africa/Brazzaville"),
|
|
MyTimeZone(37, "GMT+02:00 Windhoek", "Africa/Windhoek"),
|
|
MyTimeZone(38, "GMT+02:00 Amman", "Asia/Amman"),
|
|
MyTimeZone(39, "GMT+02:00 Athens", "Europe/Athens"),
|
|
MyTimeZone(40, "GMT+02:00 Istanbul", "Europe/Istanbul"),
|
|
MyTimeZone(41, "GMT+02:00 Beirut", "Asia/Beirut"),
|
|
MyTimeZone(42, "GMT+02:00 Cairo", "Africa/Cairo"),
|
|
MyTimeZone(43, "GMT+02:00 Helsinki", "Europe/Helsinki"),
|
|
MyTimeZone(44, "GMT+02:00 Jerusalem", "Asia/Jerusalem"),
|
|
MyTimeZone(45, "GMT+02:00 Harare", "Africa/Harare"),
|
|
MyTimeZone(46, "GMT+03:00 Minsk", "Europe/Minsk"),
|
|
MyTimeZone(47, "GMT+03:00 Baghdad", "Asia/Baghdad"),
|
|
MyTimeZone(48, "GMT+03:00 Moscow", "Europe/Moscow"),
|
|
MyTimeZone(49, "GMT+03:00 Kuwait", "Asia/Kuwait"),
|
|
MyTimeZone(50, "GMT+03:00 Nairobi", "Africa/Nairobi"),
|
|
MyTimeZone(51, "GMT+03:30 Tehran", "Asia/Tehran"),
|
|
MyTimeZone(52, "GMT+04:00 Baku", "Asia/Baku"),
|
|
MyTimeZone(53, "GMT+04:00 Tbilisi", "Asia/Tbilisi"),
|
|
MyTimeZone(54, "GMT+04:00 Yerevan", "Asia/Yerevan"),
|
|
MyTimeZone(55, "GMT+04:00 Dubai", "Asia/Dubai"),
|
|
MyTimeZone(56, "GMT+04:30 Kabul", "Asia/Kabul"),
|
|
MyTimeZone(57, "GMT+05:00 Karachi", "Asia/Karachi"),
|
|
MyTimeZone(58, "GMT+05:00 Oral", "Asia/Oral"),
|
|
MyTimeZone(59, "GMT+05:00 Yekaterinburg", "Asia/Yekaterinburg"),
|
|
MyTimeZone(60, "GMT+05:30 Kolkata", "Asia/Kolkata"),
|
|
MyTimeZone(61, "GMT+05:30 Colombo", "Asia/Colombo"),
|
|
MyTimeZone(62, "GMT+05:45 Kathmandu", "Asia/Kathmandu"),
|
|
MyTimeZone(63, "GMT+06:00 Almaty", "Asia/Almaty"),
|
|
MyTimeZone(64, "GMT+06:30 Rangoon", "Asia/Rangoon"),
|
|
MyTimeZone(65, "GMT+07:00 Krasnoyarsk", "Asia/Krasnoyarsk"),
|
|
MyTimeZone(66, "GMT+07:00 Bangkok", "Asia/Bangkok"),
|
|
MyTimeZone(67, "GMT+07:00 Jakarta", "Asia/Jakarta"),
|
|
MyTimeZone(68, "GMT+08:00 Shanghai", "Asia/Shanghai"),
|
|
MyTimeZone(69, "GMT+08:00 Hong Kong", "Asia/Hong_Kong"),
|
|
MyTimeZone(70, "GMT+08:00 Irkutsk", "Asia/Irkutsk"),
|
|
MyTimeZone(71, "GMT+08:00 Kuala Lumpur", "Asia/Kuala_Lumpur"),
|
|
MyTimeZone(72, "GMT+08:00 Perth", "Australia/Perth"),
|
|
MyTimeZone(73, "GMT+08:00 Taipei", "Asia/Taipei"),
|
|
MyTimeZone(74, "GMT+09:00 Seoul", "Asia/Seoul"),
|
|
MyTimeZone(75, "GMT+09:00 Tokyo", "Asia/Tokyo"),
|
|
MyTimeZone(76, "GMT+09:00 Yakutsk", "Asia/Yakutsk"),
|
|
MyTimeZone(77, "GMT+09:30 Darwin", "Australia/Darwin"),
|
|
MyTimeZone(78, "GMT+10:00 Brisbane", "Australia/Brisbane"),
|
|
MyTimeZone(79, "GMT+10:00 Vladivostok", "Asia/Vladivostok"),
|
|
MyTimeZone(80, "GMT+10:00 Guam", "Pacific/Guam"),
|
|
MyTimeZone(81, "GMT+10:00 Magadan", "Asia/Magadan"),
|
|
MyTimeZone(82, "GMT+10:30 Adelaide", "Australia/Adelaide"),
|
|
MyTimeZone(83, "GMT+11:00 Hobart", "Australia/Hobart"),
|
|
MyTimeZone(84, "GMT+11:00 Sydney", "Australia/Sydney"),
|
|
MyTimeZone(85, "GMT+11:00 Noumea", "Pacific/Noumea"),
|
|
MyTimeZone(86, "GMT+12:00 Majuro", "Pacific/Majuro"),
|
|
MyTimeZone(87, "GMT+12:00 Fiji", "Pacific/Fiji"),
|
|
MyTimeZone(88, "GMT+13:00 Auckland", "Pacific/Auckland"),
|
|
MyTimeZone(89, "GMT+13:00 Tongatapu", "Pacific/Tongatapu")
|
|
)
|
|
|
|
fun getTimeUntilNextAlarm(alarmTimeInMinutes: Int, days: Int): Int? {
|
|
val calendar = Calendar.getInstance()
|
|
calendar.firstDayOfWeek = Calendar.MONDAY
|
|
val currentTimeInMinutes = calendar.get(Calendar.HOUR_OF_DAY) * 60 + calendar.get(Calendar.MINUTE)
|
|
val currentDayOfWeek = calendar.get(Calendar.DAY_OF_WEEK) - Calendar.MONDAY
|
|
|
|
var minTimeDifferenceInMinutes = Int.MAX_VALUE
|
|
|
|
for (i in 0..6) {
|
|
val alarmDayOfWeek = (currentDayOfWeek + i) % 7
|
|
if (isAlarmEnabledForDay(alarmDayOfWeek, days)) {
|
|
val timeDifferenceInMinutes = getTimeDifferenceInMinutes(currentTimeInMinutes, alarmTimeInMinutes, i)
|
|
if (timeDifferenceInMinutes < minTimeDifferenceInMinutes) {
|
|
minTimeDifferenceInMinutes = timeDifferenceInMinutes
|
|
}
|
|
}
|
|
}
|
|
|
|
return if (minTimeDifferenceInMinutes != Int.MAX_VALUE) {
|
|
minTimeDifferenceInMinutes
|
|
} else {
|
|
null
|
|
}
|
|
}
|
|
|
|
fun isAlarmEnabledForDay(day: Int, alarmDays: Int): Boolean {
|
|
return ((alarmDays shr day) and 1) == 1
|
|
}
|
|
|
|
fun getTimeDifferenceInMinutes(currentTimeInMinutes: Int, alarmTimeInMinutes: Int, daysUntilAlarm: Int): Int {
|
|
val minutesInADay = 24 * 60
|
|
val minutesUntilAlarm = daysUntilAlarm * minutesInADay + alarmTimeInMinutes
|
|
return if (minutesUntilAlarm > currentTimeInMinutes) {
|
|
minutesUntilAlarm - currentTimeInMinutes
|
|
} else {
|
|
minutesInADay - (currentTimeInMinutes - minutesUntilAlarm)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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 executor = if (isOnMainThread()) {
|
|
Executors.newSingleThreadExecutor()
|
|
} else {
|
|
Executors.newFixedThreadPool(1)
|
|
}
|
|
|
|
val handler = Handler(Looper.getMainLooper())
|
|
|
|
val future = executor.submit(task)
|
|
|
|
executor.submit {
|
|
try {
|
|
val result = future.get()
|
|
handler.post {
|
|
callback(result)
|
|
}
|
|
} catch (t: Throwable) {
|
|
handler.post {
|
|
onError?.invoke(t)
|
|
}
|
|
} finally {
|
|
executor.shutdown()
|
|
}
|
|
}
|
|
}
|