more entropy
Algunas comprobaciones han fallado
Build & Publish APK Release / build (push) Failing after 7m16s
Algunas comprobaciones han fallado
Build & Publish APK Release / build (push) Failing after 7m16s
Signed-off-by: ale <ale@manalejandro.com>
Este commit está contenido en:
@@ -7,12 +7,19 @@ import androidx.activity.enableEdgeToEdge
|
|||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import androidx.work.*
|
import androidx.work.*
|
||||||
|
import com.manalejandro.motivame.data.Task
|
||||||
|
import com.manalejandro.motivame.data.TaskRepository
|
||||||
import com.manalejandro.motivame.ui.screens.AddTaskScreen
|
import com.manalejandro.motivame.ui.screens.AddTaskScreen
|
||||||
import com.manalejandro.motivame.ui.screens.MainScreen
|
import com.manalejandro.motivame.ui.screens.MainScreen
|
||||||
import com.manalejandro.motivame.ui.screens.SettingsScreen
|
import com.manalejandro.motivame.ui.screens.SettingsScreen
|
||||||
import com.manalejandro.motivame.ui.theme.MotivameTheme
|
import com.manalejandro.motivame.ui.theme.MotivameTheme
|
||||||
import com.manalejandro.motivame.ui.viewmodel.TaskViewModel
|
import com.manalejandro.motivame.ui.viewmodel.TaskViewModel
|
||||||
import com.manalejandro.motivame.worker.DailyReminderWorker
|
import com.manalejandro.motivame.worker.DailyReminderWorker
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import java.util.Calendar
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
@@ -20,57 +27,129 @@ class MainActivity : ComponentActivity() {
|
|||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
|
|
||||||
// Configurar recordatorios diarios
|
// Programar recordatorios para todas las tareas activas
|
||||||
setupDailyReminders()
|
scheduleAllReminders()
|
||||||
|
|
||||||
setContent {
|
setContent {
|
||||||
MotivameTheme {
|
MotivameTheme {
|
||||||
MotivameApp()
|
MotivameApp(onRescheduleReminders = { scheduleAllReminders() })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupDailyReminders() {
|
/**
|
||||||
val constraints = Constraints.Builder()
|
* Cancela todos los workers anteriores y programa nuevos recordatorios
|
||||||
.setRequiredNetworkType(NetworkType.NOT_REQUIRED)
|
* para cada tarea activa, distribuyendo los avisos entre las 9:00 y las 21:00.
|
||||||
|
*/
|
||||||
|
fun scheduleAllReminders() {
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
val repository = TaskRepository(applicationContext)
|
||||||
|
val tasks = repository.tasks.first()
|
||||||
|
val notificationEnabled = repository.notificationEnabled.first()
|
||||||
|
|
||||||
|
// Cancelar todos los workers existentes de recordatorios de tareas
|
||||||
|
WorkManager.getInstance(applicationContext)
|
||||||
|
.cancelAllWorkByTag("task_reminder")
|
||||||
|
|
||||||
|
if (!notificationEnabled) return@launch
|
||||||
|
|
||||||
|
tasks.filter { it.isActive }.forEach { task ->
|
||||||
|
scheduleRemindersForTask(task)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun scheduleRemindersForTask(task: Task) {
|
||||||
|
val reminders = task.dailyReminders.coerceIn(1, 10)
|
||||||
|
val cycleDays = task.repeatEveryDays.coerceIn(1, 30)
|
||||||
|
val workManager = WorkManager.getInstance(applicationContext)
|
||||||
|
|
||||||
|
// Ventana de notificaciones: 9:00 a 21:00 (12 horas = 720 minutos)
|
||||||
|
val windowStartHour = 9
|
||||||
|
val windowEndHour = 21
|
||||||
|
val windowMinutes = (windowEndHour - windowStartHour) * 60 // 720 min
|
||||||
|
|
||||||
|
// Distribuir los N avisos a lo largo del ciclo de 'cycleDays' días,
|
||||||
|
// repartidos uniformemente para que no coincidan todos el mismo día.
|
||||||
|
// Cada aviso cae en un día y hora distintos dentro del ciclo.
|
||||||
|
val totalSlots = cycleDays // un aviso por día máximo
|
||||||
|
val step = totalSlots.toDouble() / reminders // paso fraccionario entre avisos
|
||||||
|
|
||||||
|
for (i in 0 until reminders) {
|
||||||
|
// Día dentro del ciclo (0-based), distribuido uniformemente
|
||||||
|
val slotIndex = (i * step).toInt()
|
||||||
|
val dayOffset = slotIndex % cycleDays
|
||||||
|
|
||||||
|
// Hora dentro de la ventana: distribuida para que los avisos del mismo día
|
||||||
|
// no se solapen, o usando posición i para variar la hora entre días
|
||||||
|
val offsetMinutes = if (reminders == 1) {
|
||||||
|
windowMinutes / 2 // Al mediodía si solo hay 1 aviso
|
||||||
|
} else {
|
||||||
|
((windowMinutes * i) / reminders).coerceIn(0, windowMinutes - 30)
|
||||||
|
}
|
||||||
|
|
||||||
|
val targetHour = windowStartHour + offsetMinutes / 60
|
||||||
|
val targetMinute = offsetMinutes % 60
|
||||||
|
|
||||||
|
val delayMs = calculateDelayToTimeWithDayOffset(targetHour, targetMinute, dayOffset)
|
||||||
|
|
||||||
|
val inputData = workDataOf(DailyReminderWorker.KEY_TASK_ID to task.id)
|
||||||
|
|
||||||
|
val workRequest = OneTimeWorkRequestBuilder<DailyReminderWorker>()
|
||||||
|
.setInitialDelay(delayMs, TimeUnit.MILLISECONDS)
|
||||||
|
.setInputData(inputData)
|
||||||
|
.addTag("task_reminder")
|
||||||
|
.addTag("task_${task.id}")
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
val dailyWorkRequest = PeriodicWorkRequestBuilder<DailyReminderWorker>(
|
workManager.enqueue(workRequest)
|
||||||
1, TimeUnit.DAYS
|
}
|
||||||
)
|
|
||||||
.setConstraints(constraints)
|
|
||||||
.setInitialDelay(calculateInitialDelay(), TimeUnit.MILLISECONDS)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
WorkManager.getInstance(applicationContext).enqueueUniquePeriodicWork(
|
|
||||||
"daily_reminder",
|
|
||||||
ExistingPeriodicWorkPolicy.KEEP,
|
|
||||||
dailyWorkRequest
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun calculateInitialDelay(): Long {
|
/**
|
||||||
val currentTime = System.currentTimeMillis()
|
* Calcula el retardo en milisegundos hasta la próxima ocurrencia de la hora indicada.
|
||||||
val calendar = java.util.Calendar.getInstance().apply {
|
*/
|
||||||
timeInMillis = currentTime
|
private fun calculateDelayToTime(hour: Int, minute: Int): Long =
|
||||||
set(java.util.Calendar.HOUR_OF_DAY, 9) // 9 AM
|
calculateDelayToTimeWithDayOffset(hour, minute, 0)
|
||||||
set(java.util.Calendar.MINUTE, 0)
|
|
||||||
set(java.util.Calendar.SECOND, 0)
|
/**
|
||||||
|
* Calcula el retardo hasta la hora indicada más un desplazamiento de días.
|
||||||
|
* Si la hora ya pasó hoy, se mueve al día siguiente antes de aplicar el offset.
|
||||||
|
*/
|
||||||
|
private fun calculateDelayToTimeWithDayOffset(hour: Int, minute: Int, dayOffset: Int): Long {
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
|
val calendar = Calendar.getInstance().apply {
|
||||||
|
timeInMillis = now
|
||||||
|
set(Calendar.HOUR_OF_DAY, hour)
|
||||||
|
set(Calendar.MINUTE, minute)
|
||||||
|
set(Calendar.SECOND, 0)
|
||||||
|
set(Calendar.MILLISECOND, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (calendar.timeInMillis <= currentTime) {
|
// Si ya pasó esa hora hoy, mover a mañana antes de aplicar el offset
|
||||||
calendar.add(java.util.Calendar.DAY_OF_YEAR, 1)
|
if (calendar.timeInMillis <= now) {
|
||||||
|
calendar.add(Calendar.DAY_OF_YEAR, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return calendar.timeInMillis - currentTime
|
// Aplicar el offset de días adicionales
|
||||||
|
if (dayOffset > 0) {
|
||||||
|
calendar.add(Calendar.DAY_OF_YEAR, dayOffset)
|
||||||
|
}
|
||||||
|
|
||||||
|
return calendar.timeInMillis - now
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MotivameApp() {
|
fun MotivameApp(onRescheduleReminders: () -> Unit = {}) {
|
||||||
val viewModel: TaskViewModel = viewModel()
|
val viewModel: TaskViewModel = viewModel()
|
||||||
var currentScreen by remember { mutableStateOf("main") }
|
var currentScreen by remember { mutableStateOf("main") }
|
||||||
|
|
||||||
|
// Registrar callback para reprogramar avisos cuando cambian las tareas
|
||||||
|
LaunchedEffect(viewModel) {
|
||||||
|
viewModel.onRescheduleReminders = onRescheduleReminders
|
||||||
|
}
|
||||||
|
|
||||||
when (currentScreen) {
|
when (currentScreen) {
|
||||||
"main" -> MainScreen(
|
"main" -> MainScreen(
|
||||||
viewModel = viewModel,
|
viewModel = viewModel,
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ data class Task(
|
|||||||
val title: String,
|
val title: String,
|
||||||
val goals: List<String>,
|
val goals: List<String>,
|
||||||
val isActive: Boolean = true,
|
val isActive: Boolean = true,
|
||||||
val createdAt: Long = System.currentTimeMillis()
|
val createdAt: Long = System.currentTimeMillis(),
|
||||||
|
val dailyReminders: Int = 3, // Número de avisos por día (entre 9:00 y 21:00)
|
||||||
|
val repeatEveryDays: Int = 3 // Cada cuántos días se repite el ciclo de avisos
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -119,6 +119,8 @@ class TaskRepository(private val context: Context) {
|
|||||||
put("goals", JSONArray(task.goals))
|
put("goals", JSONArray(task.goals))
|
||||||
put("isActive", task.isActive)
|
put("isActive", task.isActive)
|
||||||
put("createdAt", task.createdAt)
|
put("createdAt", task.createdAt)
|
||||||
|
put("dailyReminders", task.dailyReminders)
|
||||||
|
put("repeatEveryDays", task.repeatEveryDays)
|
||||||
}
|
}
|
||||||
jsonArray.put(jsonObject)
|
jsonArray.put(jsonObject)
|
||||||
}
|
}
|
||||||
@@ -140,7 +142,9 @@ class TaskRepository(private val context: Context) {
|
|||||||
title = jsonObject.getString("title"),
|
title = jsonObject.getString("title"),
|
||||||
goals = goals,
|
goals = goals,
|
||||||
isActive = jsonObject.getBoolean("isActive"),
|
isActive = jsonObject.getBoolean("isActive"),
|
||||||
createdAt = jsonObject.getLong("createdAt")
|
createdAt = jsonObject.getLong("createdAt"),
|
||||||
|
dailyReminders = if (jsonObject.has("dailyReminders")) jsonObject.getInt("dailyReminders") else 3,
|
||||||
|
repeatEveryDays = if (jsonObject.has("repeatEveryDays")) jsonObject.getInt("repeatEveryDays") else 3
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.manalejandro.motivame.ui.screens
|
package com.manalejandro.motivame.ui.screens
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
@@ -26,6 +25,8 @@ fun AddTaskScreen(
|
|||||||
var taskTitle by remember { mutableStateOf("") }
|
var taskTitle by remember { mutableStateOf("") }
|
||||||
var currentGoal by remember { mutableStateOf("") }
|
var currentGoal by remember { mutableStateOf("") }
|
||||||
var goals by remember { mutableStateOf(listOf<String>()) }
|
var goals by remember { mutableStateOf(listOf<String>()) }
|
||||||
|
var dailyReminders by remember { mutableStateOf(3) }
|
||||||
|
var repeatEveryDays by remember { mutableStateOf(3) }
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
@@ -181,6 +182,166 @@ fun AddTaskScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
Card(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp)
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "🔔 Avisos diarios",
|
||||||
|
style = MaterialTheme.typography.titleMedium,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
color = MaterialTheme.colorScheme.primary
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
|
Text(
|
||||||
|
text = "Número de recordatorios entre las 9:00 y las 21:00",
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
IconButton(
|
||||||
|
onClick = { if (dailyReminders > 1) dailyReminders-- },
|
||||||
|
enabled = dailyReminders > 1
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.KeyboardArrowDown,
|
||||||
|
contentDescription = "Reducir",
|
||||||
|
tint = if (dailyReminders > 1) MaterialTheme.colorScheme.primary
|
||||||
|
else MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||||
|
Text(
|
||||||
|
text = "$dailyReminders",
|
||||||
|
style = MaterialTheme.typography.headlineMedium,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
color = MaterialTheme.colorScheme.primary
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = if (dailyReminders == 1) "aviso" else "avisos",
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
IconButton(
|
||||||
|
onClick = { if (dailyReminders < 10) dailyReminders++ },
|
||||||
|
enabled = dailyReminders < 10
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.KeyboardArrowUp,
|
||||||
|
contentDescription = "Aumentar",
|
||||||
|
tint = if (dailyReminders < 10) MaterialTheme.colorScheme.primary
|
||||||
|
else MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dailyReminders > 1) {
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
val intervalMinutes = 720 / (dailyReminders - 1)
|
||||||
|
Text(
|
||||||
|
text = "⏱️ Un aviso cada ${formatInterval(intervalMinutes)} aprox.",
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
Card(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp)
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "📅 Cada cuántos días",
|
||||||
|
style = MaterialTheme.typography.titleMedium,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
color = MaterialTheme.colorScheme.primary
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
|
Text(
|
||||||
|
text = "Intervalo de días entre cada ciclo de avisos",
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
IconButton(
|
||||||
|
onClick = { if (repeatEveryDays > 1) repeatEveryDays-- },
|
||||||
|
enabled = repeatEveryDays > 1
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.KeyboardArrowDown,
|
||||||
|
contentDescription = "Reducir días",
|
||||||
|
tint = if (repeatEveryDays > 1) MaterialTheme.colorScheme.primary
|
||||||
|
else MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||||
|
Text(
|
||||||
|
text = "$repeatEveryDays",
|
||||||
|
style = MaterialTheme.typography.headlineMedium,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
color = MaterialTheme.colorScheme.primary
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = if (repeatEveryDays == 1) "día" else "días",
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
IconButton(
|
||||||
|
onClick = { if (repeatEveryDays < 30) repeatEveryDays++ },
|
||||||
|
enabled = repeatEveryDays < 30
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.KeyboardArrowUp,
|
||||||
|
contentDescription = "Aumentar días",
|
||||||
|
tint = if (repeatEveryDays < 30) MaterialTheme.colorScheme.primary
|
||||||
|
else MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
Text(
|
||||||
|
text = if (repeatEveryDays == 1) "🔁 Avisos todos los días"
|
||||||
|
else "🔁 Avisos cada $repeatEveryDays días, repartidos para no coincidir",
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
item {
|
item {
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
Button(
|
Button(
|
||||||
@@ -189,7 +350,9 @@ fun AddTaskScreen(
|
|||||||
val newTask = Task(
|
val newTask = Task(
|
||||||
title = taskTitle.trim(),
|
title = taskTitle.trim(),
|
||||||
goals = goals,
|
goals = goals,
|
||||||
isActive = true
|
isActive = true,
|
||||||
|
dailyReminders = dailyReminders,
|
||||||
|
repeatEveryDays = repeatEveryDays
|
||||||
)
|
)
|
||||||
viewModel.addTask(newTask)
|
viewModel.addTask(newTask)
|
||||||
onNavigateBack()
|
onNavigateBack()
|
||||||
@@ -214,6 +377,12 @@ fun AddTaskScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun formatInterval(minutes: Int): String {
|
||||||
|
return if (minutes >= 60) {
|
||||||
|
val h = minutes / 60
|
||||||
|
val m = minutes % 60
|
||||||
|
if (m == 0) "${h}h" else "${h}h ${m}min"
|
||||||
|
} else {
|
||||||
|
"${minutes}min"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ class TaskViewModel(application: Application) : AndroidViewModel(application) {
|
|||||||
private val _soundEnabled = MutableStateFlow(true)
|
private val _soundEnabled = MutableStateFlow(true)
|
||||||
val soundEnabled: StateFlow<Boolean> = _soundEnabled.asStateFlow()
|
val soundEnabled: StateFlow<Boolean> = _soundEnabled.asStateFlow()
|
||||||
|
|
||||||
|
/** Callback que se invoca tras cualquier cambio en las tareas para reprogramar avisos */
|
||||||
|
var onRescheduleReminders: (() -> Unit)? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
loadTasks()
|
loadTasks()
|
||||||
loadSettings()
|
loadSettings()
|
||||||
@@ -52,18 +55,21 @@ class TaskViewModel(application: Application) : AndroidViewModel(application) {
|
|||||||
fun addTask(task: Task) {
|
fun addTask(task: Task) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
repository.addTask(task)
|
repository.addTask(task)
|
||||||
|
onRescheduleReminders?.invoke()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateTask(task: Task) {
|
fun updateTask(task: Task) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
repository.updateTask(task)
|
repository.updateTask(task)
|
||||||
|
onRescheduleReminders?.invoke()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deleteTask(taskId: String) {
|
fun deleteTask(taskId: String) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
repository.deleteTask(taskId)
|
repository.deleteTask(taskId)
|
||||||
|
onRescheduleReminders?.invoke()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,6 +77,7 @@ class TaskViewModel(application: Application) : AndroidViewModel(application) {
|
|||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
repository.setNotificationEnabled(enabled)
|
repository.setNotificationEnabled(enabled)
|
||||||
_notificationEnabled.value = enabled
|
_notificationEnabled.value = enabled
|
||||||
|
onRescheduleReminders?.invoke()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,16 +12,30 @@ class DailyReminderWorker(
|
|||||||
params: WorkerParameters
|
params: WorkerParameters
|
||||||
) : CoroutineWorker(context, params) {
|
) : CoroutineWorker(context, params) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val KEY_TASK_ID = "task_id"
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun doWork(): Result {
|
override suspend fun doWork(): Result {
|
||||||
val repository = TaskRepository(applicationContext)
|
val repository = TaskRepository(applicationContext)
|
||||||
val notificationHelper = NotificationHelper(applicationContext)
|
val notificationHelper = NotificationHelper(applicationContext)
|
||||||
|
|
||||||
val tasks = repository.tasks.first()
|
|
||||||
val notificationEnabled = repository.notificationEnabled.first()
|
val notificationEnabled = repository.notificationEnabled.first()
|
||||||
val soundEnabled = repository.soundEnabled.first()
|
if (!notificationEnabled) return Result.success()
|
||||||
|
|
||||||
if (notificationEnabled && tasks.isNotEmpty()) {
|
val soundEnabled = repository.soundEnabled.first()
|
||||||
notificationHelper.sendMotivationalReminder(tasks, soundEnabled)
|
val taskId = inputData.getString(KEY_TASK_ID)
|
||||||
|
|
||||||
|
val tasks = repository.tasks.first()
|
||||||
|
|
||||||
|
val taskToNotify = if (taskId != null) {
|
||||||
|
tasks.firstOrNull { it.id == taskId && it.isActive }
|
||||||
|
} else {
|
||||||
|
tasks.firstOrNull { it.isActive }
|
||||||
|
}
|
||||||
|
|
||||||
|
taskToNotify?.let {
|
||||||
|
notificationHelper.sendTaskReminder(it, soundEnabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result.success()
|
return Result.success()
|
||||||
|
|||||||
Referencia en una nueva incidencia
Block a user