diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a7cdee8..c42a35f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -51,14 +51,14 @@ android { } dependencies { - implementation("androidx.core:core-ktx:1.9.0") + implementation("androidx.core:core-ktx:1.12.0") implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2") - implementation("androidx.activity:activity-compose:1.8.0") + implementation("androidx.activity:activity-compose:1.8.1") implementation(platform("androidx.compose:compose-bom:2023.03.00")) implementation("androidx.compose.ui:ui") implementation("androidx.compose.ui:ui-graphics") implementation("androidx.compose.ui:ui-tooling-preview") - implementation("androidx.compose.material3:material3") + implementation("androidx.compose.material3:material3:1.1.2") implementation("androidx.core:core-ktx:1.12.0") implementation("androidx.work:work-runtime-ktx:2.8.1") diff --git a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/DataStore.kt b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/DataStore.kt index 22d3187..a078787 100644 --- a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/DataStore.kt +++ b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/DataStore.kt @@ -23,3 +23,7 @@ const val STATS_TOTAL_GOOD = "total_good" /** DataStore clef lié au nombre de questions mal répondu */ const val STATS_TOTAL_BAD = "total_bad" + +const val ENABLED = "enabled" +const val HOUR = "hour" +const val MINUTE = "minute" diff --git a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/MemoApplication.kt b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/MemoApplication.kt index 0ad4780..57b6e80 100644 --- a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/MemoApplication.kt +++ b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/MemoApplication.kt @@ -4,13 +4,8 @@ import android.app.Application import android.app.NotificationChannel import android.app.NotificationManager import android.content.Context -import android.content.pm.PackageManager import android.os.Build -import androidx.work.PeriodicWorkRequest -import androidx.work.WorkManager import fr.uparis.diamantkennel.memorisationapplication.data.QuestionsDB -import java.util.Calendar -import java.util.concurrent.TimeUnit const val CHANNEL_ID = "MY_CHANNEL_ID" @@ -20,10 +15,6 @@ class MemoApplication : Application() { override fun onCreate() { super.onCreate() createChannel(this) - - if (this.checkSelfPermission(android.Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED) { - schedule() - } } private fun createChannel(c: Context) { @@ -39,25 +30,4 @@ class MemoApplication : Application() { notificationManager.createNotificationChannel(channel) } } - - private fun schedule() { - val wm = WorkManager.getInstance(this) - wm.cancelAllWork() - wm.enqueue(request(10, 45)) - } - - private fun request(h: Int, m: Int): PeriodicWorkRequest { - val now = Calendar.getInstance() - val target = Calendar.getInstance().apply { - set(Calendar.HOUR_OF_DAY, h) - set(Calendar.MINUTE, m) - } - if (target.before(now)) - target.add(Calendar.DAY_OF_YEAR, 1) - val delta = target.timeInMillis - now.timeInMillis - - return PeriodicWorkRequest.Builder(RappelWorker::class.java, 1, TimeUnit.DAYS) - .setInitialDelay(delta, TimeUnit.MILLISECONDS) - .build() - } } diff --git a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/SettingsScreen.kt b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/SettingsScreen.kt index 9ed1951..8336144 100644 --- a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/SettingsScreen.kt +++ b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/SettingsScreen.kt @@ -1,6 +1,7 @@ package fr.uparis.diamantkennel.memorisationapplication import android.os.Build +import android.util.Log import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.RequiresApi @@ -15,10 +16,17 @@ import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Divider +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.FloatingActionButton +import androidx.compose.material3.Switch import androidx.compose.material3.Text +import androidx.compose.material3.TimeInput +import androidx.compose.material3.rememberTimePickerState import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -29,8 +37,11 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.lifecycle.viewmodel.compose.viewModel import fr.uparis.diamantkennel.memorisationapplication.ui.SettingsViewModel +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.runBlocking @RequiresApi(Build.VERSION_CODES.TIRAMISU) +@OptIn(ExperimentalMaterial3Api::class) @Composable fun SettingsScreen(padding: PaddingValues, model: SettingsViewModel = viewModel()) { val context = LocalContext.current @@ -38,6 +49,16 @@ fun SettingsScreen(padding: PaddingValues, model: SettingsViewModel = viewModel( var deletionDBRequest by model.deletionDB var cleanStatRequest by model.deletionStat var permissionNotif by model.gavePermissionNow + + val prefConfig = runBlocking { model.prefConfig.first() } + + val state = rememberTimePickerState( + initialHour = prefConfig.hour, + initialMinute = prefConfig.minute, + is24Hour = true + ) + var enabled by remember { mutableStateOf(prefConfig.enabled) } + model.checkPermission(context) val permissionLauncher = rememberLauncherForActivityResult( @@ -94,6 +115,25 @@ fun SettingsScreen(padding: PaddingValues, model: SettingsViewModel = viewModel( ) { Text(text = context.getString(R.string.permission_button)) } + + Column { + Row { + TimeInput(state = state) + Switch(enabled, { enabled = it }) + } + FloatingActionButton(onClick = { + val newConfig = TimeConfig( + enabled, + state.hour, + state.minute + ) + Log.d("Periodic", "config=$newConfig") + model.save(newConfig) + model.schedule(newConfig, context) + }) { + Text("On y va!") + } + } } } diff --git a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/TimeConfig.kt b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/TimeConfig.kt new file mode 100644 index 0000000..837ce13 --- /dev/null +++ b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/TimeConfig.kt @@ -0,0 +1,7 @@ +package fr.uparis.diamantkennel.memorisationapplication + +data class TimeConfig( + val enabled: Boolean = false, + val hour: Int = 8, + val minute: Int = 0 +) diff --git a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/SettingsViewModel.kt b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/SettingsViewModel.kt index a80e26b..8a5100b 100644 --- a/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/SettingsViewModel.kt +++ b/app/src/main/java/fr/uparis/diamantkennel/memorisationapplication/ui/SettingsViewModel.kt @@ -4,22 +4,33 @@ import android.app.Application import android.content.Context import android.content.pm.PackageManager import android.os.Build +import android.util.Log import androidx.activity.result.ActivityResultLauncher import androidx.annotation.RequiresApi import androidx.compose.runtime.mutableStateOf +import androidx.datastore.preferences.core.booleanPreferencesKey import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.intPreferencesKey import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.viewModelScope +import androidx.work.PeriodicWorkRequest +import androidx.work.WorkManager +import fr.uparis.diamantkennel.memorisationapplication.ENABLED +import fr.uparis.diamantkennel.memorisationapplication.HOUR +import fr.uparis.diamantkennel.memorisationapplication.MINUTE import fr.uparis.diamantkennel.memorisationapplication.MemoApplication +import fr.uparis.diamantkennel.memorisationapplication.RappelWorker import fr.uparis.diamantkennel.memorisationapplication.STATS_TOTAL_BAD import fr.uparis.diamantkennel.memorisationapplication.STATS_TOTAL_DONE import fr.uparis.diamantkennel.memorisationapplication.STATS_TOTAL_GOOD import fr.uparis.diamantkennel.memorisationapplication.STATS_TOTAL_TRIED +import fr.uparis.diamantkennel.memorisationapplication.TimeConfig import fr.uparis.diamantkennel.memorisationapplication.dataStore import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch +import java.util.Calendar +import java.util.concurrent.TimeUnit class SettingsViewModel(application: Application) : AndroidViewModel(application) { private val dao = (application as MemoApplication).database.memoDao() @@ -30,6 +41,10 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application private val statsKeyTotalGood = intPreferencesKey(STATS_TOTAL_GOOD) private val statsKeyTotalBad = intPreferencesKey(STATS_TOTAL_BAD) + private val KEY_E = booleanPreferencesKey(ENABLED) + private val KEY_H = intPreferencesKey(HOUR) + private val KEY_M = intPreferencesKey(MINUTE) + val statTotal = stats.data.map { it[statsKeyTotal] ?: 0 } val statTotalDone = stats.data.map { it[statsKeyTotalDone] ?: 0 } val statTotalGood = stats.data.map { it[statsKeyTotalGood] ?: 0 } @@ -77,4 +92,45 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application gavePermissionNow.value = context.checkSelfPermission(android.Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED } + + fun save(config: TimeConfig) { + viewModelScope.launch { + stats.edit { + it[KEY_E] = config.enabled + it[KEY_H] = config.hour + it[KEY_M] = config.minute + } + } + } + + val prefConfig = stats.data.map { + TimeConfig( + it[KEY_E] ?: false, + it[KEY_H] ?: 8, + it[KEY_M] ?: 0 + ) + } + + fun schedule(config: TimeConfig, context: Context) { + val wm = WorkManager.getInstance(context) + wm.cancelAllWork() + if (config.enabled) + wm.enqueue(request(config.hour, config.minute)) + } + + private fun request(h: Int, m: Int): PeriodicWorkRequest { + val now = Calendar.getInstance() + val target = Calendar.getInstance().apply { + set(Calendar.HOUR_OF_DAY, h) + set(Calendar.MINUTE, m) + } + if (target.before(now)) + target.add(Calendar.DAY_OF_YEAR, 1) + val delta = target.timeInMillis - now.timeInMillis + val request = PeriodicWorkRequest.Builder(RappelWorker::class.java, 1, TimeUnit.DAYS) + .setInitialDelay(delta, TimeUnit.MILLISECONDS) + .build() + Log.d("Periodic", "request: $request") + return request + } }