diff options
Diffstat (limited to 'android/app')
| -rw-r--r-- | android/app/src/main/java/org/terst/doot/widget/data/WidgetRepository.kt | 16 | ||||
| -rw-r--r-- | android/app/src/main/java/org/terst/doot/widget/ui/TaskDetailActivity.kt | 70 |
2 files changed, 84 insertions, 2 deletions
diff --git a/android/app/src/main/java/org/terst/doot/widget/data/WidgetRepository.kt b/android/app/src/main/java/org/terst/doot/widget/data/WidgetRepository.kt index 6f3d2b2..a54910d 100644 --- a/android/app/src/main/java/org/terst/doot/widget/data/WidgetRepository.kt +++ b/android/app/src/main/java/org/terst/doot/widget/data/WidgetRepository.kt @@ -43,6 +43,22 @@ class WidgetRepository( } } + /** POSTs a due-date update to /api/widget/reschedule. */ + suspend fun reschedule(id: String, source: String, dateISO: String): Result<Unit> = + withContext(Dispatchers.IO) { + val body = """{"id":"$id","source":"$source","date":"$dateISO"}""" + .toRequestBody("application/json".toMediaType()) + val request = Request.Builder() + .url("$serverUrl/api/widget/reschedule") + .header("Authorization", "Bearer $token") + .post(body) + .build() + runCatching { + val response = client.newCall(request).execute() + check(response.isSuccessful) { "HTTP ${response.code}" } + } + } + /** POSTs a task completion to /api/widget/complete. */ suspend fun complete(context: Context, id: String, source: String): Result<Unit> = withContext(Dispatchers.IO) { diff --git a/android/app/src/main/java/org/terst/doot/widget/ui/TaskDetailActivity.kt b/android/app/src/main/java/org/terst/doot/widget/ui/TaskDetailActivity.kt index 2a42871..0dac1cc 100644 --- a/android/app/src/main/java/org/terst/doot/widget/ui/TaskDetailActivity.kt +++ b/android/app/src/main/java/org/terst/doot/widget/ui/TaskDetailActivity.kt @@ -7,13 +7,23 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.* -import androidx.compose.runtime.Composable +import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.glance.appwidget.updateAll +import androidx.lifecycle.lifecycleScope +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.launch +import okhttp3.OkHttpClient +import org.terst.doot.widget.data.Keys +import org.terst.doot.widget.data.WidgetRepository +import org.terst.doot.widget.data.dataStore import org.terst.doot.widget.work.CompleteWorker +import java.util.Calendar +import java.util.TimeZone class TaskDetailActivity : ComponentActivity() { @@ -35,6 +45,19 @@ class TaskDetailActivity : ComponentActivity() { CompleteWorker.enqueue(this, id, source) finish() }, + onReschedule = { dateISO -> + lifecycleScope.launch { + val prefs = this@TaskDetailActivity.dataStore.data.first() + val url = prefs[Keys.SERVER_URL]?.trimEnd('/') ?: return@launch + val token = prefs[Keys.TOKEN] ?: return@launch + val repo = WidgetRepository(OkHttpClient(), url, token) + repo.reschedule(id, source, dateISO).onSuccess { + repo.fetchAndPersist(this@TaskDetailActivity) + DootWidget().updateAll(this@TaskDetailActivity) + finish() + } + } + }, onDismiss = ::finish ) } @@ -56,8 +79,40 @@ fun TaskDetailSheet( source: String, completable: Boolean, onComplete: () -> Unit, + onReschedule: (String) -> Unit, onDismiss: () -> Unit ) { + var showDatePicker by remember { mutableStateOf(false) } + val datePickerState = rememberDatePickerState( + initialSelectedDateMillis = System.currentTimeMillis() + ) + + if (showDatePicker) { + DatePickerDialog( + onDismissRequest = { showDatePicker = false }, + confirmButton = { + TextButton(onClick = { + datePickerState.selectedDateMillis?.let { millis -> + val cal = Calendar.getInstance(TimeZone.getTimeZone("UTC")) + cal.timeInMillis = millis + val dateISO = "%04d-%02d-%02d".format( + cal.get(Calendar.YEAR), + cal.get(Calendar.MONTH) + 1, + cal.get(Calendar.DAY_OF_MONTH) + ) + onReschedule(dateISO) + } + showDatePicker = false + }) { Text("Set date") } + }, + dismissButton = { + TextButton(onClick = { showDatePicker = false }) { Text("Cancel") } + } + ) { + DatePicker(state = datePickerState) + } + } + ModalBottomSheet( onDismissRequest = onDismiss, sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true), @@ -94,7 +149,7 @@ fun TaskDetailSheet( modifier = Modifier.weight(1f) ) } - Spacer(Modifier.height(24.dp)) + Spacer(Modifier.height(20.dp)) if (completable) { Button( onClick = onComplete, @@ -103,6 +158,17 @@ fun TaskDetailSheet( ) { Text("Mark Complete", fontSize = 15.sp) } + Spacer(Modifier.height(8.dp)) + } + if (source == "doot") { + OutlinedButton( + onClick = { showDatePicker = true }, + modifier = Modifier.fillMaxWidth(), + colors = ButtonDefaults.outlinedButtonColors(contentColor = Color.White), + border = androidx.compose.foundation.BorderStroke(1.dp, Color.White.copy(alpha = 0.3f)) + ) { + Text("Reschedule", fontSize = 15.sp) + } } Spacer(Modifier.height(20.dp)) } |
