Comparar commits
2 Commits
| Autor | SHA1 | Fecha | |
|---|---|---|---|
|
16b7892e0a
|
|||
|
b3694fae56
|
@@ -37,6 +37,11 @@ android {
|
||||
buildFeatures {
|
||||
compose = true
|
||||
}
|
||||
lint {
|
||||
lintConfig = file("lint.xml")
|
||||
warningsAsErrors = false
|
||||
abortOnError = false
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
11
app/lint.xml
Archivo normal
11
app/lint.xml
Archivo normal
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<lint>
|
||||
<!-- Advertencias de versiones disponibles: se mantienen como info, no error -->
|
||||
<issue id="GradleDependency" severity="informational" />
|
||||
<issue id="NewerVersionAvailable" severity="informational" />
|
||||
<issue id="AndroidGradlePluginVersion" severity="informational" />
|
||||
|
||||
<!-- PluralsCandidate: las strings de resumen son intencionales (formato compacto) -->
|
||||
<issue id="PluralsCandidate" severity="informational" />
|
||||
</lint>
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.Motivame">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
@@ -42,6 +41,16 @@
|
||||
android:resource="@xml/motivame_widget_info" />
|
||||
</receiver>
|
||||
|
||||
<!-- Reprogramar recordatorios tras reinicio del dispositivo o actualización de la app -->
|
||||
<receiver
|
||||
android:name=".receiver.BootReceiver"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -9,7 +9,7 @@ import androidx.activity.enableEdgeToEdge
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.work.*
|
||||
import androidx.work.WorkManager
|
||||
import com.manalejandro.motivame.data.Task
|
||||
import com.manalejandro.motivame.data.TaskRepository
|
||||
import com.manalejandro.motivame.ui.screens.AddTaskScreen
|
||||
@@ -18,14 +18,11 @@ import com.manalejandro.motivame.ui.screens.SettingsScreen
|
||||
import com.manalejandro.motivame.ui.theme.MotivameTheme
|
||||
import com.manalejandro.motivame.ui.viewmodel.TaskViewModel
|
||||
import com.manalejandro.motivame.util.LocaleHelper
|
||||
import com.manalejandro.motivame.worker.DailyReminderWorker
|
||||
import com.manalejandro.motivame.worker.ReminderScheduler
|
||||
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 kotlin.random.Random
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
|
||||
@@ -55,112 +52,23 @@ class MainActivity : ComponentActivity() {
|
||||
|
||||
/**
|
||||
* Cancela todos los workers anteriores y programa nuevos recordatorios
|
||||
* para cada tarea activa, distribuyendo los avisos entre las 9:00 y las 21:00.
|
||||
* @param notificationsEnabled valor ya conocido, para evitar condición de carrera con DataStore.
|
||||
* Si es null, se lee del DataStore (solo al arrancar la app).
|
||||
* para cada tarea activa usando [ReminderScheduler].
|
||||
* @param notificationsEnabled valor ya conocido; si es null se lee de DataStore.
|
||||
*/
|
||||
fun scheduleAllReminders(notificationsEnabled: Boolean? = null) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val repository = TaskRepository(applicationContext)
|
||||
|
||||
// Cancelar todos los workers existentes de recordatorios de tareas
|
||||
WorkManager.getInstance(applicationContext)
|
||||
.cancelAllWorkByTag("task_reminder")
|
||||
|
||||
val enabled = notificationsEnabled ?: repository.notificationEnabled.first()
|
||||
if (!enabled) return@launch
|
||||
|
||||
if (!enabled) {
|
||||
WorkManager.getInstance(applicationContext).cancelAllWorkByTag("task_reminder")
|
||||
return@launch
|
||||
}
|
||||
val tasks = repository.tasks.first()
|
||||
tasks.filter { it.isActive }.forEach { task ->
|
||||
scheduleRemindersForTask(task)
|
||||
ReminderScheduler.scheduleAll(applicationContext, tasks)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 (720 minutos disponibles)
|
||||
val windowStartMinute = 9 * 60 // 540
|
||||
val windowEndMinute = 21 * 60 // 1260
|
||||
val windowSize = windowEndMinute - windowStartMinute // 720
|
||||
|
||||
// Distribuir los N avisos en días distintos dentro del ciclo.
|
||||
// Si reminders <= cycleDays cada aviso va a un día diferente;
|
||||
// si hay más avisos que días, se reparten de forma ciclica.
|
||||
val dayAssignments = (0 until reminders).map { i -> i % cycleDays }
|
||||
|
||||
// Generar horas aleatorias únicas (en minutos desde medianoche)
|
||||
// Para cada aviso elegimos un minuto al azar dentro de [540, 1260)
|
||||
// asegurándonos de que no coincida con ningún otro aviso ya asignado.
|
||||
val usedMinutes = mutableSetOf<Int>()
|
||||
val minuteAssignments = mutableListOf<Int>()
|
||||
|
||||
repeat(reminders) {
|
||||
var candidate: Int
|
||||
var attempts = 0
|
||||
do {
|
||||
candidate = windowStartMinute + Random.nextInt(windowSize)
|
||||
attempts++
|
||||
// Tras muchos intentos (espacio muy saturado) relajamos la condición
|
||||
// exigiendo sólo minutos distintos en el mismo día
|
||||
} while (usedMinutes.contains(candidate) && attempts < windowSize)
|
||||
usedMinutes.add(candidate)
|
||||
minuteAssignments.add(candidate)
|
||||
}
|
||||
|
||||
for (i in 0 until reminders) {
|
||||
val dayOffset = dayAssignments[i]
|
||||
val totalMinutes = minuteAssignments[i]
|
||||
val targetHour = totalMinutes / 60
|
||||
val targetMinute = totalMinutes % 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()
|
||||
|
||||
workManager.enqueue(workRequest)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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)
|
||||
}
|
||||
|
||||
// Si ya pasó esa hora hoy, mover a mañana antes de aplicar el offset
|
||||
if (calendar.timeInMillis <= now) {
|
||||
calendar.add(Calendar.DAY_OF_YEAR, 1)
|
||||
}
|
||||
|
||||
// Aplicar el offset de días adicionales
|
||||
if (dayOffset > 0) {
|
||||
calendar.add(Calendar.DAY_OF_YEAR, dayOffset)
|
||||
}
|
||||
|
||||
return calendar.timeInMillis - now
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MotivameApp(onRescheduleReminders: (Boolean) -> Unit = {}) {
|
||||
val viewModel: TaskViewModel = viewModel()
|
||||
|
||||
35
app/src/main/java/com/manalejandro/motivame/receiver/BootReceiver.kt
Archivo normal
35
app/src/main/java/com/manalejandro/motivame/receiver/BootReceiver.kt
Archivo normal
@@ -0,0 +1,35 @@
|
||||
package com.manalejandro.motivame.receiver
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import com.manalejandro.motivame.data.TaskRepository
|
||||
import com.manalejandro.motivame.worker.ReminderScheduler
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* Reprograma todos los recordatorios activos cuando el dispositivo arranca
|
||||
* o cuando se actualiza la app (acción MY_PACKAGE_REPLACED).
|
||||
*/
|
||||
class BootReceiver : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val action = intent.action ?: return
|
||||
if (action != Intent.ACTION_BOOT_COMPLETED &&
|
||||
action != Intent.ACTION_MY_PACKAGE_REPLACED
|
||||
) return
|
||||
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val repository = TaskRepository(context)
|
||||
val enabled = repository.notificationEnabled.first()
|
||||
if (!enabled) return@launch
|
||||
|
||||
val tasks = repository.tasks.first()
|
||||
ReminderScheduler.scheduleAll(context, tasks)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@ import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import androidx.core.net.toUri
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
@@ -361,7 +361,7 @@ fun SettingsScreen(
|
||||
color = MaterialTheme.colorScheme.onTertiaryContainer,
|
||||
textDecoration = TextDecoration.Underline,
|
||||
modifier = Modifier.clickable {
|
||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://manalejandro.com"))
|
||||
val intent = Intent(Intent.ACTION_VIEW, "https://manalejandro.com".toUri())
|
||||
context.startActivity(intent)
|
||||
}
|
||||
)
|
||||
@@ -391,7 +391,7 @@ fun SettingsScreen(
|
||||
color = MaterialTheme.colorScheme.onTertiaryContainer,
|
||||
textDecoration = TextDecoration.Underline,
|
||||
modifier = Modifier.clickable {
|
||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(githubUrl))
|
||||
val intent = Intent(Intent.ACTION_VIEW, githubUrl.toUri())
|
||||
context.startActivity(intent)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.manalejandro.motivame.util
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import java.util.Locale
|
||||
@@ -19,6 +20,7 @@ object LocaleHelper {
|
||||
Language("ko", "🇰🇷", "한국어")
|
||||
)
|
||||
|
||||
@SuppressLint("AppBundleLocaleChanges")
|
||||
fun applyLocale(context: Context, languageCode: String): Context {
|
||||
val locale = Locale(languageCode)
|
||||
Locale.setDefault(locale)
|
||||
|
||||
@@ -15,6 +15,9 @@ class DailyReminderWorker(
|
||||
|
||||
companion object {
|
||||
const val KEY_TASK_ID = "task_id"
|
||||
const val KEY_SCHEDULE_HOUR = "schedule_hour"
|
||||
const val KEY_SCHEDULE_MINUTE = "schedule_minute"
|
||||
const val KEY_CYCLE_DAYS = "cycle_days"
|
||||
}
|
||||
|
||||
override suspend fun doWork(): Result {
|
||||
@@ -37,6 +40,27 @@ class DailyReminderWorker(
|
||||
|
||||
taskToNotify?.let {
|
||||
notificationHelper.sendTaskReminder(it, soundEnabled)
|
||||
|
||||
// ✅ Auto-reprogramar este mismo aviso para el siguiente ciclo
|
||||
val hour = inputData.getInt(KEY_SCHEDULE_HOUR, -1)
|
||||
val minute = inputData.getInt(KEY_SCHEDULE_MINUTE, -1)
|
||||
val cycleDays = inputData.getInt(KEY_CYCLE_DAYS, it.repeatEveryDays)
|
||||
|
||||
if (hour >= 0 && minute >= 0) {
|
||||
// El siguiente disparo es exactamente [cycleDays] días después,
|
||||
// a la misma hora local — se calcula con dayOffset = 0 porque
|
||||
// la hora ya quedó en el futuro (hoy+cycleDays).
|
||||
val delayMs = ReminderScheduler.calculateDelay(hour, minute, cycleDays)
|
||||
ReminderScheduler.enqueueOne(
|
||||
context = applicationContext,
|
||||
taskId = it.id,
|
||||
hour = hour,
|
||||
minute = minute,
|
||||
cycleDays = cycleDays,
|
||||
dayOffset = 0,
|
||||
delayMs = delayMs
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Refrescar el widget con la meta actualizada
|
||||
@@ -45,4 +69,3 @@ class DailyReminderWorker(
|
||||
return Result.success()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
142
app/src/main/java/com/manalejandro/motivame/worker/ReminderScheduler.kt
Archivo normal
142
app/src/main/java/com/manalejandro/motivame/worker/ReminderScheduler.kt
Archivo normal
@@ -0,0 +1,142 @@
|
||||
package com.manalejandro.motivame.worker
|
||||
|
||||
import android.content.Context
|
||||
import androidx.work.OneTimeWorkRequestBuilder
|
||||
import androidx.work.WorkManager
|
||||
import androidx.work.workDataOf
|
||||
import com.manalejandro.motivame.data.Task
|
||||
import java.util.Calendar
|
||||
import java.util.TimeZone
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.random.Random
|
||||
|
||||
/**
|
||||
* Centraliza toda la lógica para programar/cancelar recordatorios con WorkManager.
|
||||
* Usa siempre la zona horaria local del dispositivo de forma explícita.
|
||||
*/
|
||||
object ReminderScheduler {
|
||||
|
||||
// Ventana de notificaciones: 9:00 a 21:00 (hora local)
|
||||
private const val WINDOW_START_MINUTE = 9 * 60 // 540
|
||||
private const val WINDOW_END_MINUTE = 21 * 60 // 1260
|
||||
private const val WINDOW_SIZE = WINDOW_END_MINUTE - WINDOW_START_MINUTE // 720
|
||||
|
||||
/** Encola un único recordatorio con los parámetros exactos dados. */
|
||||
fun enqueueOne(
|
||||
context: Context,
|
||||
taskId: String,
|
||||
hour: Int,
|
||||
minute: Int,
|
||||
cycleDays: Int,
|
||||
dayOffset: Int,
|
||||
delayMs: Long
|
||||
) {
|
||||
val inputData = workDataOf(
|
||||
DailyReminderWorker.KEY_TASK_ID to taskId,
|
||||
DailyReminderWorker.KEY_SCHEDULE_HOUR to hour,
|
||||
DailyReminderWorker.KEY_SCHEDULE_MINUTE to minute,
|
||||
DailyReminderWorker.KEY_CYCLE_DAYS to cycleDays
|
||||
)
|
||||
val workRequest = OneTimeWorkRequestBuilder<DailyReminderWorker>()
|
||||
.setInitialDelay(delayMs, TimeUnit.MILLISECONDS)
|
||||
.setInputData(inputData)
|
||||
.addTag("task_reminder")
|
||||
.addTag("task_$taskId")
|
||||
.build()
|
||||
WorkManager.getInstance(context).enqueue(workRequest)
|
||||
}
|
||||
|
||||
/** Cancela todos los workers existentes y programa nuevos para cada tarea activa. */
|
||||
fun scheduleAll(context: Context, tasks: List<Task>) {
|
||||
val workManager = WorkManager.getInstance(context)
|
||||
workManager.cancelAllWorkByTag("task_reminder")
|
||||
tasks.filter { it.isActive }.forEach { task ->
|
||||
scheduleForTask(context, task)
|
||||
}
|
||||
}
|
||||
|
||||
/** Programa todos los recordatorios para una tarea concreta. */
|
||||
fun scheduleForTask(context: Context, task: Task) {
|
||||
val reminders = task.dailyReminders.coerceIn(1, 10)
|
||||
val cycleDays = task.repeatEveryDays.coerceIn(1, 30)
|
||||
val workManager = WorkManager.getInstance(context)
|
||||
|
||||
// Distribuir N avisos en días del ciclo (uno por día si reminders ≤ cycleDays)
|
||||
val dayAssignments = (0 until reminders).map { i -> i % cycleDays }
|
||||
|
||||
// Generar horas aleatorias únicas dentro de la ventana [9:00, 21:00)
|
||||
val usedMinutes = mutableSetOf<Int>()
|
||||
val minuteAssignments = mutableListOf<Int>()
|
||||
repeat(reminders) {
|
||||
var candidate: Int
|
||||
var attempts = 0
|
||||
do {
|
||||
candidate = WINDOW_START_MINUTE + Random.nextInt(WINDOW_SIZE)
|
||||
attempts++
|
||||
} while (usedMinutes.contains(candidate) && attempts < WINDOW_SIZE)
|
||||
usedMinutes.add(candidate)
|
||||
minuteAssignments.add(candidate)
|
||||
}
|
||||
|
||||
for (i in 0 until reminders) {
|
||||
val dayOffset = dayAssignments[i]
|
||||
val totalMinutes = minuteAssignments[i]
|
||||
val targetHour = totalMinutes / 60
|
||||
val targetMinute = totalMinutes % 60
|
||||
|
||||
val delayMs = calculateDelay(targetHour, targetMinute, dayOffset)
|
||||
|
||||
val inputData = workDataOf(
|
||||
DailyReminderWorker.KEY_TASK_ID to task.id,
|
||||
DailyReminderWorker.KEY_SCHEDULE_HOUR to targetHour,
|
||||
DailyReminderWorker.KEY_SCHEDULE_MINUTE to targetMinute,
|
||||
DailyReminderWorker.KEY_CYCLE_DAYS to cycleDays
|
||||
)
|
||||
|
||||
val workRequest = OneTimeWorkRequestBuilder<DailyReminderWorker>()
|
||||
.setInitialDelay(delayMs, TimeUnit.MILLISECONDS)
|
||||
.setInputData(inputData)
|
||||
.addTag("task_reminder")
|
||||
.addTag("task_${task.id}")
|
||||
.build()
|
||||
|
||||
workManager.enqueue(workRequest)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calcula el retardo (ms) hasta la hora indicada en HORA LOCAL,
|
||||
* usando TimeZone.getDefault() de forma explícita para evitar
|
||||
* que el contexto del hilo de background use UTC u otra zona.
|
||||
*
|
||||
* Si la hora ya pasó hoy, se avanza al día siguiente y luego
|
||||
* se aplica el [dayOffset] adicional del ciclo.
|
||||
*/
|
||||
fun calculateDelay(hour: Int, minute: Int, dayOffset: Int): Long {
|
||||
val now = System.currentTimeMillis()
|
||||
|
||||
// ✅ Zona horaria local explícita — clave para que funcione
|
||||
// correctamente desde hilos de background y tras reinicio.
|
||||
val calendar = Calendar.getInstance(TimeZone.getDefault()).apply {
|
||||
timeInMillis = now
|
||||
set(Calendar.HOUR_OF_DAY, hour)
|
||||
set(Calendar.MINUTE, minute)
|
||||
set(Calendar.SECOND, 0)
|
||||
set(Calendar.MILLISECOND, 0)
|
||||
}
|
||||
|
||||
// Si esa hora ya pasó hoy, mover al día siguiente
|
||||
if (calendar.timeInMillis <= now) {
|
||||
calendar.add(Calendar.DAY_OF_YEAR, 1)
|
||||
}
|
||||
|
||||
// Desplazamiento adicional del ciclo
|
||||
if (dayOffset > 0) {
|
||||
calendar.add(Calendar.DAY_OF_YEAR, dayOffset)
|
||||
}
|
||||
|
||||
return calendar.timeInMillis - now
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,170 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#3DDC84"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,0L9,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,0L19,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,0L29,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,0L39,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,0L49,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,0L59,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,0L69,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,0L79,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M89,0L89,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M99,0L99,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,9L108,9"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,19L108,19"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,29L108,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,39L108,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,49L108,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,59L108,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,69L108,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,79L108,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,89L108,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,99L108,99"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,29L89,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,39L89,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,49L89,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,59L89,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,69L89,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,79L89,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,19L29,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,19L39,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,19L49,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,19L59,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,19L69,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,19L79,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
</vector>
|
||||
12
app/src/main/res/drawable/ic_launcher_monochrome.xml
Archivo normal
12
app/src/main/res/drawable/ic_launcher_monochrome.xml
Archivo normal
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<!-- Estrella de motivación - icono monocromo para Android 13+ -->
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M54,20 L59.5,40 L80,40 L63.5,52 L70,72 L54,60 L38,72 L44.5,52 L28,40 L48.5,40 Z" />
|
||||
</vector>
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
android:orientation="vertical"
|
||||
android:background="@drawable/widget_background"
|
||||
android:padding="16dp"
|
||||
android:clickable="true">
|
||||
android:clickable="true"
|
||||
android:focusable="true">
|
||||
|
||||
<!-- Cabecera: icono + nombre de la app -->
|
||||
<LinearLayout
|
||||
@@ -20,7 +21,7 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="⭐ Motívame"
|
||||
android:text="@string/widget_app_name"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold"
|
||||
@@ -30,9 +31,9 @@
|
||||
android:id="@+id/widget_status"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="●"
|
||||
android:text="@string/widget_status_indicator"
|
||||
android:textColor="#10B981"
|
||||
android:textSize="10sp" />
|
||||
android:textSize="11sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -41,7 +42,7 @@
|
||||
android:id="@+id/widget_task_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Tarea"
|
||||
android:text="@string/widget_task_default"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
@@ -55,7 +56,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:text="🎯 Meta"
|
||||
android:text="@string/widget_goal_default"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="13sp"
|
||||
android:alpha="0.85"
|
||||
@@ -67,9 +68,9 @@
|
||||
android:id="@+id/widget_hint"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Toca para abrir →"
|
||||
android:text="@string/widget_tap_to_open"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="10sp"
|
||||
android:textSize="11sp"
|
||||
android:alpha="0.55"
|
||||
android:gravity="end"
|
||||
android:layout_marginTop="4dp" />
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
android:orientation="vertical"
|
||||
android:background="@drawable/widget_background"
|
||||
android:padding="14dp"
|
||||
android:clickable="true">
|
||||
android:clickable="true"
|
||||
android:focusable="true">
|
||||
|
||||
<!-- Cabecera -->
|
||||
<LinearLayout
|
||||
@@ -21,7 +22,7 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="⭐ Motívame"
|
||||
android:text="@string/widget_app_name"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold"
|
||||
@@ -31,9 +32,9 @@
|
||||
android:id="@+id/widget_status"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="●"
|
||||
android:text="@string/widget_status_indicator"
|
||||
android:textColor="#10B981"
|
||||
android:textSize="10sp" />
|
||||
android:textSize="11sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Tarea 1 -->
|
||||
@@ -96,7 +97,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="10sp"
|
||||
android:textSize="11sp"
|
||||
android:alpha="0.6"
|
||||
android:layout_marginTop="3dp"
|
||||
android:visibility="gone" />
|
||||
@@ -162,7 +163,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="10sp"
|
||||
android:textSize="11sp"
|
||||
android:alpha="0.6"
|
||||
android:layout_marginTop="3dp"
|
||||
android:visibility="gone" />
|
||||
@@ -228,7 +229,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="10sp"
|
||||
android:textSize="11sp"
|
||||
android:alpha="0.6"
|
||||
android:layout_marginTop="3dp"
|
||||
android:visibility="gone" />
|
||||
@@ -240,7 +241,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="10sp"
|
||||
android:textSize="11sp"
|
||||
android:alpha="0.5"
|
||||
android:gravity="end" />
|
||||
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
android:orientation="vertical"
|
||||
android:background="@drawable/widget_background"
|
||||
android:padding="14dp"
|
||||
android:clickable="true">
|
||||
android:clickable="true"
|
||||
android:focusable="true">
|
||||
android:focusable="true">
|
||||
|
||||
<!-- Cabecera -->
|
||||
<LinearLayout
|
||||
@@ -21,7 +23,7 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="⭐ Motívame"
|
||||
android:text="@string/widget_app_name"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="11sp"
|
||||
android:textStyle="bold"
|
||||
@@ -31,9 +33,9 @@
|
||||
android:id="@+id/widget_status"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="●"
|
||||
android:text="@string/widget_status_indicator"
|
||||
android:textColor="#10B981"
|
||||
android:textSize="10sp" />
|
||||
android:textSize="11sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Tarea 1 -->
|
||||
@@ -154,7 +156,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="10sp"
|
||||
android:textSize="11sp"
|
||||
android:alpha="0.5"
|
||||
android:gravity="end" />
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
android:orientation="vertical"
|
||||
android:background="@drawable/widget_background"
|
||||
android:padding="12dp"
|
||||
android:clickable="true">
|
||||
android:clickable="true"
|
||||
android:focusable="true">
|
||||
|
||||
<!-- Cabecera -->
|
||||
<LinearLayout
|
||||
@@ -21,7 +22,7 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="⭐ Motívame"
|
||||
android:text="@string/widget_app_name"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="11sp"
|
||||
android:textStyle="bold"
|
||||
@@ -31,9 +32,9 @@
|
||||
android:id="@+id/widget_status"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="●"
|
||||
android:text="@string/widget_status_indicator"
|
||||
android:textColor="#10B981"
|
||||
android:textSize="10sp" />
|
||||
android:textSize="11sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Tarea 1 -->
|
||||
@@ -98,7 +99,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="10sp"
|
||||
android:textSize="11sp"
|
||||
android:alpha="0.5"
|
||||
android:gravity="end"
|
||||
android:layout_marginTop="4dp" />
|
||||
|
||||
@@ -2,4 +2,5 @@
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
<monochrome android:drawable="@drawable/ic_launcher_monochrome"/>
|
||||
</adaptive-icon>
|
||||
@@ -2,4 +2,5 @@
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
<monochrome android:drawable="@drawable/ic_launcher_monochrome"/>
|
||||
</adaptive-icon>
|
||||
@@ -10,7 +10,6 @@
|
||||
<string name="empty_state_subtitle">Füge deine erste Aufgabe und Ziele hinzu, um motiviert zu bleiben</string>
|
||||
<string name="goals_label">🎯 Ziele:</string>
|
||||
<string name="task_paused">⏸️ Pausiert</string>
|
||||
<string name="toggle_active_desc">Aufgabe aktivieren/pausieren</string>
|
||||
<string name="delete_task_desc">Löschen</string>
|
||||
<string name="delete_task_title">Aufgabe löschen</string>
|
||||
<string name="delete_task_confirm">Möchtest du \'%1$s\' wirklich löschen?</string>
|
||||
@@ -72,15 +71,17 @@
|
||||
|
||||
<string name="language_section">🌐 Sprache</string>
|
||||
<string name="language_desc">Wähle die Sprache der Anwendung</string>
|
||||
<string name="language_restart_hint">Die App wird neu gestartet, um die Sprache anzuwenden</string>
|
||||
|
||||
<string name="notification_default_message">Denke daran, diese Aufgabe abzuschließen!</string>
|
||||
<string name="notification_big_text">📝 Aufgabe: %1$s\n\n🎯 Denk daran: %2$s</string>
|
||||
|
||||
<!-- Widget -->
|
||||
<string name="widget_app_name">⭐ Motivier mich</string>
|
||||
<string name="widget_status_indicator">●</string>
|
||||
<string name="widget_task_default">Aufgabe</string>
|
||||
<string name="widget_goal_default">🎯 Ziel</string>
|
||||
<string name="widget_description">Zeigt deine aktive Aufgabe und ein motivierendes Ziel</string>
|
||||
<string name="widget_no_tasks">Keine aktiven Aufgaben.\nÖffne Motivier mich, um eine hinzuzufügen.</string>
|
||||
<string name="widget_tap_to_open">Tippen zum Öffnen →</string>
|
||||
<string name="widget_active">aktiv</string>
|
||||
</resources>
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
<string name="empty_state_subtitle">Add your first task and goals to stay motivated</string>
|
||||
<string name="goals_label">🎯 Goals:</string>
|
||||
<string name="task_paused">⏸️ Paused</string>
|
||||
<string name="toggle_active_desc">Toggle task active</string>
|
||||
<string name="delete_task_desc">Delete</string>
|
||||
<string name="delete_task_title">Delete task</string>
|
||||
<string name="delete_task_confirm">Are you sure you want to delete \'%1$s\'?</string>
|
||||
@@ -76,17 +75,20 @@
|
||||
<!-- Language selector -->
|
||||
<string name="language_section">🌐 Language</string>
|
||||
<string name="language_desc">Select the application language</string>
|
||||
<string name="language_restart_hint">The app will restart to apply the language</string>
|
||||
|
||||
<!-- Notifications -->
|
||||
<string name="notification_default_message">Remember to complete this task!</string>
|
||||
<string name="notification_big_text">📝 Task: %1$s\n\n🎯 Remember: %2$s</string>
|
||||
|
||||
<!-- Widget -->
|
||||
<!-- Widget -->
|
||||
<string name="widget_app_name">⭐ Motivate Me</string>
|
||||
<string name="widget_status_indicator">●</string>
|
||||
<string name="widget_task_default">Task</string>
|
||||
<string name="widget_goal_default">🎯 Goal</string>
|
||||
<string name="widget_description">Shows your active task and a motivational goal</string>
|
||||
<string name="widget_no_tasks">No active tasks.\nOpen Motivate Me to add one.</string>
|
||||
<string name="widget_tap_to_open">Tap to open →</string>
|
||||
<string name="widget_active">active</string>
|
||||
</resources>
|
||||
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
<string name="empty_state_subtitle">Ajoutez votre première tâche et vos objectifs pour rester motivé</string>
|
||||
<string name="goals_label">🎯 Objectifs :</string>
|
||||
<string name="task_paused">⏸️ En pause</string>
|
||||
<string name="toggle_active_desc">Activer/mettre en pause la tâche</string>
|
||||
<string name="delete_task_desc">Supprimer</string>
|
||||
<string name="delete_task_title">Supprimer la tâche</string>
|
||||
<string name="delete_task_confirm">Voulez-vous vraiment supprimer \'%1$s\' ?</string>
|
||||
@@ -72,15 +71,17 @@
|
||||
|
||||
<string name="language_section">🌐 Langue</string>
|
||||
<string name="language_desc">Sélectionnez la langue de l\'application</string>
|
||||
<string name="language_restart_hint">L\'app redémarrera pour appliquer la langue</string>
|
||||
|
||||
<string name="notification_default_message">N\'oubliez pas de terminer cette tâche !</string>
|
||||
<string name="notification_big_text">📝 Tâche : %1$s\n\n🎯 Rappel : %2$s</string>
|
||||
|
||||
<!-- Widget -->
|
||||
<string name="widget_app_name">⭐ Motivez-moi</string>
|
||||
<string name="widget_status_indicator">●</string>
|
||||
<string name="widget_task_default">Tâche</string>
|
||||
<string name="widget_goal_default">🎯 Objectif</string>
|
||||
<string name="widget_description">Affiche votre tâche active et un objectif motivationnel</string>
|
||||
<string name="widget_no_tasks">Aucune tâche active.\nOuvrez Motivez-moi pour en ajouter une.</string>
|
||||
<string name="widget_tap_to_open">Toucher pour ouvrir →</string>
|
||||
<string name="widget_active">active</string>
|
||||
</resources>
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
<string name="empty_state_subtitle">最初のタスクと目標を追加してモチベーションを維持しよう</string>
|
||||
<string name="goals_label">🎯 目標:</string>
|
||||
<string name="task_paused">⏸️ 一時停止中</string>
|
||||
<string name="toggle_active_desc">タスクの有効/一時停止を切り替え</string>
|
||||
<string name="delete_task_desc">削除</string>
|
||||
<string name="delete_task_title">タスクを削除</string>
|
||||
<string name="delete_task_confirm">\'%1$s\' を削除してもよろしいですか?</string>
|
||||
@@ -72,15 +71,17 @@
|
||||
|
||||
<string name="language_section">🌐 言語</string>
|
||||
<string name="language_desc">アプリケーションの言語を選択してください</string>
|
||||
<string name="language_restart_hint">言語を適用するためにアプリが再起動します</string>
|
||||
|
||||
<string name="notification_default_message">このタスクを完了することを忘れずに!</string>
|
||||
<string name="notification_big_text">📝 タスク:%1$s\n\n🎯 リマインダー:%2$s</string>
|
||||
|
||||
<!-- Widget -->
|
||||
<string name="widget_app_name">⭐ やる気アップ</string>
|
||||
<string name="widget_status_indicator">●</string>
|
||||
<string name="widget_task_default">タスク</string>
|
||||
<string name="widget_goal_default">🎯 目標</string>
|
||||
<string name="widget_description">アクティブなタスクとモチベーション目標を表示</string>
|
||||
<string name="widget_no_tasks">アクティブなタスクがありません。\nやる気アップを開いて追加してください。</string>
|
||||
<string name="widget_tap_to_open">タップして開く →</string>
|
||||
<string name="widget_active">アクティブ</string>
|
||||
</resources>
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
<string name="empty_state_subtitle">첫 번째 작업과 목표를 추가하여 동기를 유지하세요</string>
|
||||
<string name="goals_label">🎯 목표:</string>
|
||||
<string name="task_paused">⏸️ 일시 중지됨</string>
|
||||
<string name="toggle_active_desc">작업 활성화/일시 중지</string>
|
||||
<string name="delete_task_desc">삭제</string>
|
||||
<string name="delete_task_title">작업 삭제</string>
|
||||
<string name="delete_task_confirm">\'%1$s\'을(를) 정말 삭제하시겠습니까?</string>
|
||||
@@ -72,15 +71,17 @@
|
||||
|
||||
<string name="language_section">🌐 언어</string>
|
||||
<string name="language_desc">애플리케이션 언어를 선택하세요</string>
|
||||
<string name="language_restart_hint">언어 적용을 위해 앱이 재시작됩니다</string>
|
||||
|
||||
<string name="notification_default_message">이 작업을 완료하는 것을 잊지 마세요!</string>
|
||||
<string name="notification_big_text">📝 작업: %1$s\n\n🎯 알림: %2$s</string>
|
||||
|
||||
<!-- Widget -->
|
||||
<string name="widget_app_name">⭐ 동기부여</string>
|
||||
<string name="widget_status_indicator">●</string>
|
||||
<string name="widget_task_default">작업</string>
|
||||
<string name="widget_goal_default">🎯 목표</string>
|
||||
<string name="widget_description">활성 작업과 동기 부여 목표를 표시합니다</string>
|
||||
<string name="widget_no_tasks">활성 작업이 없습니다.\n동기부여 앱을 열어 추가하세요.</string>
|
||||
<string name="widget_tap_to_open">탭하여 열기 →</string>
|
||||
<string name="widget_active">활성</string>
|
||||
</resources>
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
<string name="empty_state_subtitle">Adicione sua primeira tarefa e metas para se manter motivado</string>
|
||||
<string name="goals_label">🎯 Metas:</string>
|
||||
<string name="task_paused">⏸️ Pausada</string>
|
||||
<string name="toggle_active_desc">Ativar/pausar tarefa</string>
|
||||
<string name="delete_task_desc">Excluir</string>
|
||||
<string name="delete_task_title">Excluir tarefa</string>
|
||||
<string name="delete_task_confirm">Tem certeza que deseja excluir \'%1$s\'?</string>
|
||||
@@ -72,15 +71,17 @@
|
||||
|
||||
<string name="language_section">🌐 Idioma</string>
|
||||
<string name="language_desc">Selecione o idioma do aplicativo</string>
|
||||
<string name="language_restart_hint">O app será reiniciado para aplicar o idioma</string>
|
||||
|
||||
<string name="notification_default_message">Lembre-se de completar esta tarefa!</string>
|
||||
<string name="notification_big_text">📝 Tarefa: %1$s\n\n🎯 Lembre-se: %2$s</string>
|
||||
|
||||
<!-- Widget -->
|
||||
<string name="widget_app_name">⭐ Motiva-me</string>
|
||||
<string name="widget_status_indicator">●</string>
|
||||
<string name="widget_task_default">Tarefa</string>
|
||||
<string name="widget_goal_default">🎯 Meta</string>
|
||||
<string name="widget_description">Mostra sua tarefa ativa e uma meta motivacional</string>
|
||||
<string name="widget_no_tasks">Sem tarefas ativas.\nAbra Motiva-me para adicionar uma.</string>
|
||||
<string name="widget_tap_to_open">Toque para abrir →</string>
|
||||
<string name="widget_active">ativa</string>
|
||||
</resources>
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
<string name="empty_state_subtitle">添加你的第一个任务和目标,保持动力</string>
|
||||
<string name="goals_label">🎯 目标:</string>
|
||||
<string name="task_paused">⏸️ 已暂停</string>
|
||||
<string name="toggle_active_desc">切换任务状态</string>
|
||||
<string name="delete_task_desc">删除</string>
|
||||
<string name="delete_task_title">删除任务</string>
|
||||
<string name="delete_task_confirm">确定要删除 \'%1$s\' 吗?</string>
|
||||
@@ -76,14 +75,19 @@
|
||||
<!-- Language selector -->
|
||||
<string name="language_section">🌐 语言</string>
|
||||
<string name="language_desc">选择应用程序语言</string>
|
||||
<string name="language_restart_hint">应用将重启以应用语言更改</string>
|
||||
|
||||
<!-- Notifications -->
|
||||
<string name="notification_default_message">记得完成这个任务!</string>
|
||||
<string name="notification_big_text">📝 任务:%1$s\n\n🎯 提醒:%2$s</string>
|
||||
|
||||
<!-- Widget -->
|
||||
<string name="widget_app_name">⭐ 激励我</string>
|
||||
<string name="widget_status_indicator">●</string>
|
||||
<string name="widget_task_default">任务</string>
|
||||
<string name="widget_goal_default">🎯 目标</string>
|
||||
<string name="widget_description">显示您的活跃任务和激励目标</string>
|
||||
<string name="widget_no_tasks">没有活跃任务。\n打开激励我来添加一个。</string>
|
||||
<string name="widget_tap_to_open">点击打开 →</string>
|
||||
<string name="widget_active">活跃</string>
|
||||
</resources>
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="purple_200">#FFBB86FC</color>
|
||||
<color name="purple_500">#FF6200EE</color>
|
||||
<color name="purple_700">#FF3700B3</color>
|
||||
<color name="teal_200">#FF03DAC5</color>
|
||||
<color name="teal_700">#FF018786</color>
|
||||
<color name="black">#FF000000</color>
|
||||
<color name="white">#FFFFFFFF</color>
|
||||
</resources>
|
||||
@@ -10,7 +10,6 @@
|
||||
<string name="empty_state_subtitle">Agrega tu primera tarea y metas para mantenerte motivado</string>
|
||||
<string name="goals_label">🎯 Metas:</string>
|
||||
<string name="task_paused">⏸️ Pausada</string>
|
||||
<string name="toggle_active_desc">Activar/pausar tarea</string>
|
||||
<string name="delete_task_desc">Eliminar</string>
|
||||
<string name="delete_task_title">Eliminar tarea</string>
|
||||
<string name="delete_task_confirm">¿Estás seguro de que quieres eliminar \'%1$s\'?</string>
|
||||
@@ -75,15 +74,17 @@
|
||||
<!-- Language selector -->
|
||||
<string name="language_section">🌐 Idioma</string>
|
||||
<string name="language_desc">Selecciona el idioma de la aplicación</string>
|
||||
<string name="language_restart_hint">La app se reiniciará para aplicar el idioma</string>
|
||||
|
||||
<!-- Notifications -->
|
||||
<string name="notification_default_message">¡Recuerda completar esta tarea!</string>
|
||||
<string name="notification_big_text">📝 Tarea: %1$s\n\n🎯 Recuerda: %2$s</string>
|
||||
|
||||
<!-- Widget -->
|
||||
<string name="widget_app_name">⭐ Motívame</string>
|
||||
<string name="widget_status_indicator">●</string>
|
||||
<string name="widget_task_default">Tarea</string>
|
||||
<string name="widget_goal_default">🎯 Meta</string>
|
||||
<string name="widget_description">Muestra tu tarea activa y una meta motivacional</string>
|
||||
<string name="widget_no_tasks">Sin tareas activas.\nAbre Motívame para añadir una.</string>
|
||||
<string name="widget_tap_to_open">Toca para abrir →</string>
|
||||
<string name="widget_active">activa</string>
|
||||
</resources>
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:minWidth="250dp"
|
||||
android:minHeight="110dp"
|
||||
android:targetCellWidth="3"
|
||||
@@ -9,5 +10,6 @@
|
||||
android:resizeMode="horizontal|vertical"
|
||||
android:widgetCategory="home_screen"
|
||||
android:description="@string/widget_description"
|
||||
android:previewLayout="@layout/widget_motivame" />
|
||||
android:previewLayout="@layout/widget_motivame"
|
||||
tools:ignore="UnusedAttribute" />
|
||||
|
||||
|
||||
Referencia en una nueva incidencia
Block a user