Skip to content

Commit

Permalink
feat: add option to change when the new day starts (#6)
Browse files Browse the repository at this point in the history
closes #5
  • Loading branch information
amrbashir authored Dec 10, 2024
1 parent eaa5ace commit d100983
Show file tree
Hide file tree
Showing 21 changed files with 260 additions and 95 deletions.
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
indent_size = 4
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
8 changes: 4 additions & 4 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
KEYSTORE_FILE_PATH=""
KEYSTORE_PASSWORD=""
KEY_ALIAS=""
KEY_PASSWORD=""
KEYSTORE_FILE_PATH=
KEYSTORE_PASSWORD=
KEY_ALIAS=
KEY_PASSWORD=
11 changes: 4 additions & 7 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
import java.io.FileInputStream
import java.util.Properties

plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
Expand All @@ -9,9 +6,9 @@ plugins {

android {
namespace = "me.amrbashir.hijriwidget"
compileSdk = 35
compileSdk = 35

defaultConfig {
defaultConfig {
applicationId = "me.amrbashir.hijriwidget"
minSdk = 26
targetSdk = 35
Expand All @@ -21,10 +18,10 @@ android {

signingConfigs {
create("config") {
keyAlias = System.getProperty("KEY_ALIAS")
keyPassword = System.getProperty("KEY_PASSWORD")
storeFile = rootProject.file(System.getProperty("KEYSTORE_FILE_PATH"))
storePassword = System.getProperty("KEYSTORE_PASSWORD")
keyAlias = System.getProperty("KEY_ALIAS")
keyPassword = System.getProperty("KEY_PASSWORD")
}
}

Expand Down
3 changes: 2 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<!-- <uses-permission android:name="android.permission.INTERNET" />-->
<!-- <uses-permission android:name="android.permission.INTERNET" />-->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<application
Expand Down Expand Up @@ -42,6 +42,7 @@
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
Expand Down
16 changes: 10 additions & 6 deletions app/src/main/kotlin/me/amrbashir/hijriwidget/HijriDate.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ val EN_MONTHS = arrayOf(
object HijriDate {
val today: MutableState<String> = mutableStateOf("")

fun load(lang: SupportedLanguage) {
this.today.value = todayForLang(lang)
fun load(lang: SupportedLanguage, dayStart: DayStart) {
this.today.value = todayForLang(lang, dayStart)
}

fun todayForLang(lang: SupportedLanguage): String {
fun todayForLang(lang: SupportedLanguage, dayStart: DayStart): String {
val calendar = Calendar.getInstance(ULocale("@calendar=islamic-umalqura"))
val day = calendar[Calendar.DAY_OF_MONTH].toString().convertNumbersToLang(lang)
val day = todayNumber(dayStart).toString().convertNumbersToLang(lang)
val month = when (lang) {
SupportedLanguage.English -> EN_MONTHS[calendar[Calendar.MONTH]]
else -> AR_MONTHS[calendar[Calendar.MONTH]]
Expand All @@ -55,8 +55,12 @@ object HijriDate {
return "$day $month $year"
}

fun todayNumber(): Int {
fun todayNumber(dayStart: DayStart): Int {
val calendar = Calendar.getInstance(ULocale("@calendar=islamic-umalqura"))
return calendar[Calendar.DAY_OF_MONTH]
val dayOfMonth = calendar[Calendar.DAY_OF_MONTH]
return if (
calendar[Calendar.HOUR_OF_DAY] >= dayStart.hour &&
calendar[Calendar.MINUTE] >= dayStart.minute
) dayOfMonth else dayOfMonth - 1
}
}
3 changes: 1 addition & 2 deletions app/src/main/kotlin/me/amrbashir/hijriwidget/Modifier.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,4 @@ import androidx.compose.ui.Modifier
inline fun Modifier.addIf(
condition: Boolean,
crossinline factory: Modifier.() -> Modifier
): Modifier =
if (condition) factory() else this
): Modifier = if (condition) factory() else this
29 changes: 26 additions & 3 deletions app/src/main/kotlin/me/amrbashir/hijriwidget/Preferences.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import java.time.LocalTime
import java.time.format.DateTimeFormatter

private const val PREF = "HijriWidgetPref"
private const val LANG_KEY = "LANG"
Expand All @@ -20,6 +22,8 @@ private const val CUSTOM_COLOR_KEY = "CUSTOM_COLOR"
private const val SHADOW_KEY = "SHADOW"
private const val IS_CUSTOM_TEXT_SIZE_KEY = "IS_CUSTOM_TEXT_SIZE"
private const val CUSTOM_TEXT_SIZE_KEY = "CUSTOM_TEXT_SIZE"
private const val DAY_START_HOUR_KEY = "DAY_START_HOUR"
private const val DAY_START_MINUTE_KEY = "DAY_START_MINUTE"

object Preferences {
val language: MutableState<SupportedLanguage> = mutableStateOf(Defaults.language)
Expand All @@ -29,23 +33,26 @@ object Preferences {
val isCustomTextSize: MutableState<Boolean> = mutableStateOf(Defaults.isCustomTextSize)
val customTextSize: MutableState<Float> = mutableFloatStateOf(Defaults.customTextSize)
val shadow: MutableState<Boolean> = mutableStateOf(Defaults.shadow)
val dayStart: MutableState<DayStart> = mutableStateOf(Defaults.dayStart)

@Suppress("ConstPropertyName")
object Defaults {
val language = SupportedLanguage.Arabic
val theme = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) SupportedTheme.Dynamic else SupportedTheme.System
val color = Color.White.toArgb()
const val isCustomTextSize= false
const val isCustomTextSize = false
const val customTextSize = 22F
const val shadow = true
val dayStart = DayStart(0, 0)
}

fun restoreDefaults(context: Context) {
this.language.value = Defaults.language
this.theme.value = Defaults.theme
this.isCustomTextSize.value= Defaults.isCustomTextSize
this.isCustomTextSize.value = Defaults.isCustomTextSize
this.customTextSize.value = Defaults.customTextSize
this.shadow.value = Defaults.shadow
this.dayStart.value = Defaults.dayStart
this.updateColor(context)
}

Expand All @@ -66,6 +73,11 @@ object Preferences {

this.customTextSize.value = sharedPreferences.getFloat(CUSTOM_TEXT_SIZE_KEY, 22F)

this.dayStart.value = DayStart(
sharedPreferences.getInt(DAY_START_HOUR_KEY, 0),
sharedPreferences.getInt(DAY_START_MINUTE_KEY, 0)
)

this.updateColor(context)
}

Expand All @@ -78,6 +90,8 @@ object Preferences {
putBoolean(SHADOW_KEY, this@Preferences.shadow.value)
putBoolean(IS_CUSTOM_TEXT_SIZE_KEY, this@Preferences.isCustomTextSize.value)
putFloat(CUSTOM_TEXT_SIZE_KEY, this@Preferences.customTextSize.value)
putInt(DAY_START_HOUR_KEY, this@Preferences.dayStart.value.hour)
putInt(DAY_START_MINUTE_KEY, this@Preferences.dayStart.value.minute)
commit()
}
}
Expand All @@ -100,7 +114,16 @@ object Preferences {
}
}

data class DayStart(val hour: Int, val minute: Int) {
override fun toString(): String {
val localTime = LocalTime.of(
hour, minute
)
return localTime.format(DateTimeFormatter.ofPattern("hh:mm a"))
}
}


fun Context.isDark(): Boolean {
return resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == UI_MODE_NIGHT_YES
}
}
20 changes: 20 additions & 0 deletions app/src/main/kotlin/me/amrbashir/hijriwidget/Worker.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package me.amrbashir.hijriwidget

import android.icu.util.Calendar

fun nextDayStartWorkerDelay(): Long {
val nextDayStart = Calendar.getInstance()
if (
nextDayStart[Calendar.HOUR_OF_DAY] >= Preferences.dayStart.value.hour &&
nextDayStart[Calendar.MINUTE] >= Preferences.dayStart.value.minute
) {
nextDayStart[Calendar.DAY_OF_MONTH] = nextDayStart[Calendar.DAY_OF_MONTH] + 1
}
nextDayStart[Calendar.HOUR_OF_DAY] = Preferences.dayStart.value.hour
nextDayStart[Calendar.MINUTE] = Preferences.dayStart.value.minute
nextDayStart[Calendar.SECOND] = 0

val now = Calendar.getInstance()

return nextDayStart.timeInMillis - now.timeInMillis
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
package me.amrbashir.hijriwidget.android

import android.app.Application
import me.amrbashir.hijriwidget.Preferences
import me.amrbashir.hijriwidget.preferences.HijriWidgetLauncherIconWorker
import me.amrbashir.hijriwidget.widget.HijriWidgetWorker

class HijriWidgetApp : Application() {

override fun onCreate() {
super.onCreate()
override fun onCreate() {
super.onCreate()

HijriWidgetLauncherIconWorker.setup24Periodic(this)
HijriWidgetWorker.setup24Periodic(this)
}
Preferences.load(this)
HijriWidgetLauncherIconWorker.setup24Periodic(this)
HijriWidgetWorker.setup24Periodic(this)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,21 @@ import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.icu.util.Calendar
import androidx.work.CoroutineWorker
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.PeriodicWorkRequest
import androidx.work.WorkManager
import androidx.work.WorkerParameters
import me.amrbashir.hijriwidget.BuildConfig
import me.amrbashir.hijriwidget.HijriDate
import me.amrbashir.hijriwidget.Preferences
import me.amrbashir.hijriwidget.nextDayStartWorkerDelay
import java.util.concurrent.TimeUnit

class HijriWidgetLauncherIconBroadCastReceiver : BroadcastReceiver() {
@SuppressLint("UnsafeProtectedBroadcastReceiver")
override fun onReceive(context: Context, intent: Intent?) {
Preferences.load(context)
HijriWidgetLauncherIconWorker.changeLauncherIcon(context)
HijriWidgetLauncherIconWorker.setup24Periodic(context)
}
Expand All @@ -29,18 +31,18 @@ class HijriWidgetLauncherIconWorker(
params: WorkerParameters
) : CoroutineWorker(appContext, params) {
override suspend fun doWork(): Result {
try {
changeLauncherIcon(this.applicationContext)
return Result.success()
} catch (e: Exception) {
e.printStackTrace()
return Result.retry()
}
try {
changeLauncherIcon(this.applicationContext)
return Result.success()
} catch (e: Exception) {
e.printStackTrace()
return Result.retry()
}
}

companion object {
fun changeLauncherIcon(context: Context) {
val today = HijriDate.todayNumber()
val today = HijriDate.todayNumber(Preferences.dayStart.value)

val packageManager = context.packageManager

Expand All @@ -65,25 +67,15 @@ class HijriWidgetLauncherIconWorker(
}
}

fun setup24Periodic(context: Context) {
val nextDayStart = Calendar.getInstance()
nextDayStart[Calendar.DAY_OF_MONTH] = nextDayStart[Calendar.DAY_OF_MONTH] + 1
nextDayStart[Calendar.HOUR_OF_DAY] = 0
nextDayStart[Calendar.MINUTE] = 0
nextDayStart[Calendar.SECOND] = 0

val now = Calendar.getInstance()

val delay = nextDayStart.timeInMillis - now.timeInMillis

fun setup24Periodic(context: Context, cancelAndRequeue: Boolean = false) {
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
"hijriWidgetLauncherIconWorker",
ExistingPeriodicWorkPolicy.KEEP,
if (cancelAndRequeue) ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE else ExistingPeriodicWorkPolicy.KEEP,
PeriodicWorkRequest.Builder(
HijriWidgetLauncherIconWorker::class.java,
24,
TimeUnit.HOURS
).setInitialDelay(delay, TimeUnit.MILLISECONDS).build()
).setInitialDelay(nextDayStartWorkerDelay(), TimeUnit.MILLISECONDS).build()
)
}
}
Expand Down
Loading

0 comments on commit d100983

Please sign in to comment.