1
0
mirror of https://github.com/avinal/nikki.git synced 2026-07-03 21:40:09 +05:30

Fix warnings, update deps, Metro-style task detail, comment counts

Warnings fixed:
- Removed unused imports (FieldMask, UpdateMemoRequest, LocalUriHandler,
  LocalPlatformContext, Composable in Color.kt)
- Removed unused Android color resources (old Material purple/teal)
- Replaced proguard-rules.pro with clean Compose/KMP config
- Fixed RelationDto to match actual API (memo/relatedMemo are objects)

Dependencies bumped:
- Ktor 3.4.3 → 3.5.0, Activity Compose 1.10.1 → 1.13.0
- Core KTX 1.16.0 → 1.18.0, SQLite 2.5.1 → 2.6.2
- WorkManager 2.11.1 → 2.11.2, JUnit 1.1.5 → 1.3.0, Espresso 3.5.1 → 3.7.0

Features:
- TaskDetailSheet converted to Metro AlertDialog style (no Material chips)
- MemoDetailScreen: edit button, created/updated timestamps at top
- Comment count shown on MemoCard header (computed from COMMENT relations)
- Explorer tag table: combined columns for memo count + task count per tag

Co-Authored-By: Claude Opus 4.6 (1M context)

Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
This commit is contained in:
2026-05-19 19:04:02 +05:30
parent 8c15660fce
commit 099ff25ed3
19 changed files with 209 additions and 179 deletions
+3
View File
@@ -22,3 +22,6 @@ local.properties
/kotlin-js-store
.kotlin/
composeApp/schemas/
index.html
script.js
styles.css
+3 -1
View File
@@ -1,6 +1,8 @@
<component name="ArtifactManager">
<artifact type="jar" name="composeApp">
<output-path>$PROJECT_DIR$/composeApp/build/libs</output-path>
<root id="archive" name="composeApp.jar" />
<root id="archive" name="composeApp.jar">
<element id="module-output" name="MemosApp.composeApp.androidMain" />
</root>
</artifact>
</component>
+14 -5
View File
@@ -5,11 +5,20 @@
# kotlinx.serialization
-keepattributes *Annotation*, InnerClasses
-dontnote kotlinx.serialization.AnnotationsKt
-keepclassmembers class kotlinx.serialization.json.** { *** Companion; }
-keepclasseswithmembers class kotlinx.serialization.json.** { kotlinx.serialization.KSerializer serializer(...); }
-keep,includedescriptorclasses class com.avinal.memos.**$$serializer { *; }
-keepclassmembers class com.avinal.memos.** { *** Companion; }
-keepclasseswithmembers class com.avinal.memos.** { kotlinx.serialization.KSerializer serializer(...); }
-keepclassmembers class kotlinx.serialization.json.** {
*** Companion;
}
-keepclasseswithmembers class kotlinx.serialization.json.** {
kotlinx.serialization.KSerializer serializer(...);
}
# Keep serializers generated for project model classes
-keepclassmembers class com.avinal.memos.** {
*** Companion;
}
-keepclasseswithmembers class com.avinal.memos.** {
kotlinx.serialization.KSerializer serializer(...);
}
# Room
-keep class * extends androidx.room.RoomDatabase
@@ -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>
@@ -3,7 +3,6 @@ package com.avinal.memos
import androidx.compose.runtime.Composable
import coil3.ImageLoader
import coil3.compose.setSingletonImageLoaderFactory
import coil3.compose.LocalPlatformContext
import coil3.network.ktor3.KtorNetworkFetcherFactory
import com.avinal.memos.ui.navigation.AppNavHost
import com.avinal.memos.ui.theme.MemosAppTheme
@@ -4,13 +4,11 @@ import com.avinal.memos.api.model.AttachmentDto
import com.avinal.memos.api.model.AttachmentRef
import com.avinal.memos.api.model.CreateAttachmentRequest
import com.avinal.memos.api.model.CreateMemoRequest
import com.avinal.memos.api.model.FieldMask
import com.avinal.memos.api.model.ListMemosResponse
import com.avinal.memos.api.model.MemoDto
import com.avinal.memos.api.model.ReactionDto
import com.avinal.memos.api.model.UpsertReactionRequest
import com.avinal.memos.api.model.UpdateMemoBody
import com.avinal.memos.api.model.UpdateMemoRequest
import com.avinal.memos.api.model.UserDto
import io.ktor.client.HttpClient
import io.ktor.client.call.body
@@ -27,6 +27,7 @@ fun MemoDto.toDomain(): Memo = Memo(
snippet = snippet,
attachments = attachments.map { it.toDomain() },
reactions = reactions.map { it.toDomain() },
commentCount = relations.count { it.type == "COMMENT" && it.relatedMemo.name == name },
)
fun AttachmentDto.toDomain(): Attachment = Attachment(
@@ -54,11 +54,17 @@ data class ReactionDto(
@Serializable
data class RelationDto(
val memo: String = "",
val relatedMemo: String = "",
val memo: RelationRefDto = RelationRefDto(),
val relatedMemo: RelationRefDto = RelationRefDto(),
val type: String = "",
)
@Serializable
data class RelationRefDto(
val name: String = "",
val snippet: String = "",
)
@Serializable
data class ListMemosResponse(
val memos: List<MemoDto> = emptyList(),
@@ -5,7 +5,7 @@ import androidx.room.RoomDatabase
import com.avinal.memos.db.dao.MemoDao
import com.avinal.memos.db.entity.MemoEntity
@Database(entities = [MemoEntity::class], version = 3)
@Database(entities = [MemoEntity::class], version = 4)
abstract class MemosDatabase : RoomDatabase() {
abstract fun memoDao(): MemoDao
}
@@ -48,6 +48,7 @@ fun MemoEntity.toDomain(): Memo = Memo(
snippet = snippet,
attachments = deserializeAttachments(attachmentsJson),
reactions = deserializeReactions(reactionsJson),
commentCount = commentCount,
)
fun Memo.toEntity(cachedAt: Long): MemoEntity = MemoEntity(
@@ -68,6 +69,7 @@ fun Memo.toEntity(cachedAt: Long): MemoEntity = MemoEntity(
snippet = snippet,
attachmentsJson = serializeAttachments(attachments),
reactionsJson = serializeReactions(reactions),
commentCount = commentCount,
cachedAt = cachedAt,
)
@@ -22,5 +22,6 @@ data class MemoEntity(
val snippet: String,
val attachmentsJson: String = "[]",
val reactionsJson: String = "[]",
val commentCount: Int = 0,
val cachedAt: Long,
)
@@ -20,6 +20,7 @@ data class Memo(
val snippet: String,
val attachments: List<Attachment> = emptyList(),
val reactions: List<Reaction> = emptyList(),
val commentCount: Int = 0,
)
data class Attachment(
@@ -24,7 +24,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.LinkAnnotation
import androidx.compose.ui.text.SpanStyle
@@ -125,6 +125,10 @@ fun MemoCard(
Spacer(Modifier.width(8.dp))
}
Text(formatAbsoluteDate(memo.displayTime), fontSize = 12.sp, color = subtleColor)
if (memo.commentCount > 0) {
Spacer(Modifier.width(8.dp))
Text("${memo.commentCount} comment${if (memo.commentCount > 1) "s" else ""}", fontSize = 12.sp, color = subtleColor)
}
}
Spacer(Modifier.height(8.dp))
@@ -341,17 +341,31 @@ private fun ExplorerPage(
}
if (allTags.isNotEmpty()) {
val tasksByTag = remember(memos) {
val parser = com.avinal.memos.parser.TaskParser
val allTasks = memos.flatMap { memo -> parser.extractTasks(memo.id, memo.content) }
allTasks.filter { !it.isCompleted }.groupBy { it.lists.firstOrNull() ?: "" }
}
Spacer(Modifier.height(20.dp))
Text("tags", fontSize = 19.sp, fontWeight = FontWeight.Light, color = textColor)
Spacer(Modifier.height(8.dp))
Row(modifier = Modifier.fillMaxWidth().padding(bottom = 4.dp)) {
Text("tag", fontSize = 11.sp, color = subtleColor.copy(alpha = 0.5f), modifier = Modifier.weight(1f))
Text("memos", fontSize = 11.sp, color = subtleColor.copy(alpha = 0.5f), modifier = Modifier.width(50.dp), textAlign = TextAlign.End)
Text("tasks", fontSize = 11.sp, color = subtleColor.copy(alpha = 0.5f), modifier = Modifier.width(50.dp), textAlign = TextAlign.End)
}
allTags.forEach { tag ->
val count = memos.count { it.tags.contains(tag) }
val memoCount = memos.count { it.tags.contains(tag) }
val taskCount = tasksByTag[tag]?.size ?: 0
Row(
modifier = Modifier.fillMaxWidth().clickable { onTagSelected(tag) }.padding(vertical = 6.dp),
horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier.fillMaxWidth().clickable { onTagSelected(tag) }.padding(vertical = 5.dp),
) {
Text("#$tag", fontSize = 14.sp, color = accent)
Text("$count", fontSize = 12.sp, color = subtleColor)
Text("#$tag", fontSize = 14.sp, color = accent, modifier = Modifier.weight(1f))
Text("$memoCount", fontSize = 13.sp, color = subtleColor, modifier = Modifier.width(50.dp), textAlign = TextAlign.End)
Text("$taskCount", fontSize = 13.sp, color = if (taskCount > 0) accent else subtleColor, modifier = Modifier.width(50.dp), textAlign = TextAlign.End)
}
}
}
@@ -12,45 +12,44 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.avinal.memos.AppDependencies
import com.avinal.memos.api.ApiResult
import com.avinal.memos.domain.Memo
import com.avinal.memos.api.model.toDomain
import com.avinal.memos.domain.Memo
import com.avinal.memos.ui.components.AttachmentGrid
import com.avinal.memos.ui.components.MarkdownText
import com.avinal.memos.ui.components.ReactionBar
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.input.ImeAction
import kotlinx.coroutines.launch
import com.avinal.memos.ui.theme.LocalAccentColor
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.datetime.TimeZone
import kotlinx.datetime.toLocalDateTime
@Composable
fun MemoDetailScreen(
@@ -65,6 +64,8 @@ fun MemoDetailScreen(
val isLoading by viewModel.isLoading.collectAsState()
val serverUrl by produceState("") { value = deps.tokenStore.serverUrl.first() ?: "" }
val accent = LocalAccentColor.current
val textColor = MaterialTheme.colorScheme.onBackground
val subtleColor = MaterialTheme.colorScheme.onSurfaceVariant
Column(
modifier = Modifier
@@ -72,14 +73,14 @@ fun MemoDetailScreen(
.background(MaterialTheme.colorScheme.background)
.statusBarsPadding(),
) {
Text(
"← back",
fontSize = 14.sp,
color = accent,
modifier = Modifier
.clickable(onClick = onBack)
.padding(start = 24.dp, top = 12.dp, bottom = 12.dp),
)
Row(
modifier = Modifier.fillMaxWidth().padding(start = 24.dp, end = 12.dp, top = 12.dp, bottom = 8.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
) {
Text("← back", fontSize = 14.sp, color = accent, modifier = Modifier.clickable(onClick = onBack))
Text("edit", fontSize = 14.sp, color = accent, modifier = Modifier.clickable(onClick = onEdit))
}
when {
isLoading && memo == null -> {
@@ -90,7 +91,7 @@ fun MemoDetailScreen(
memo == null -> {
Box(Modifier.fillMaxSize().padding(24.dp), contentAlignment = Alignment.Center) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text("could not load memo", fontSize = 15.sp)
Text("could not load memo", fontSize = 15.sp, color = textColor)
Spacer(Modifier.height(8.dp))
Text("retry", fontSize = 14.sp, color = accent, modifier = Modifier.clickable { viewModel.retry() })
}
@@ -103,13 +104,15 @@ fun MemoDetailScreen(
.verticalScroll(rememberScrollState())
.padding(start = 24.dp, end = 12.dp),
) {
Text(
memo!!.visibility.name.lowercase(),
fontSize = 12.sp,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) {
Text(memo!!.visibility.name.lowercase(), fontSize = 12.sp, color = subtleColor)
Text(formatDateTime(memo!!.createTime), fontSize = 12.sp, color = subtleColor)
if (memo!!.updateTime != memo!!.createTime) {
Text("edited ${formatDateTime(memo!!.updateTime)}", fontSize = 12.sp, color = subtleColor)
}
}
Spacer(Modifier.height(8.dp))
Spacer(Modifier.height(10.dp))
MarkdownText(
markdown = memo!!.content,
@@ -127,7 +130,7 @@ fun MemoDetailScreen(
}
Spacer(Modifier.height(20.dp))
CommentsSection(memoId = memoId, deps = deps, accent = accent)
CommentsSection(memoId = memoId, deps = deps, accent = accent, textColor = textColor, subtleColor = subtleColor)
Spacer(Modifier.height(24.dp))
}
@@ -136,14 +139,21 @@ fun MemoDetailScreen(
}
}
private val monthNames = listOf("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec")
private fun formatDateTime(instant: kotlin.time.Instant): String {
val local = instant.toLocalDateTime(TimeZone.currentSystemDefault())
return "${monthNames[local.month.ordinal]} ${local.day}, ${local.year}"
}
@Composable
private fun CommentsSection(
memoId: String,
deps: AppDependencies,
accent: Color,
textColor: Color,
subtleColor: Color,
) {
val textColor = MaterialTheme.colorScheme.onBackground
val subtleColor = MaterialTheme.colorScheme.onSurfaceVariant
var comments by remember { mutableStateOf<List<Memo>>(emptyList()) }
var commentText by remember { mutableStateOf("") }
var isLoading by remember { mutableStateOf(true) }
@@ -158,6 +168,18 @@ private fun CommentsSection(
isLoading = false
}
fun submitComment() {
if (commentText.isBlank()) return
val text = commentText
commentText = ""
scope.launch {
when (val result = deps.apiClient.createComment(memoId, text)) {
is ApiResult.Success -> comments = comments + result.data.toDomain()
else -> {}
}
}
}
Column {
Text("comments", fontSize = 19.sp, fontWeight = FontWeight.Light, color = textColor)
@@ -170,7 +192,10 @@ private fun CommentsSection(
} else {
comments.forEach { comment ->
Column(modifier = Modifier.padding(bottom = 12.dp)) {
Text(comment.creator, fontSize = 12.sp, color = subtleColor)
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
Text(comment.creator, fontSize = 12.sp, color = subtleColor)
Text(formatDateTime(comment.createTime), fontSize = 12.sp, color = subtleColor)
}
Spacer(Modifier.height(2.dp))
MarkdownText(markdown = comment.content)
}
@@ -179,10 +204,7 @@ private fun CommentsSection(
Spacer(Modifier.height(8.dp))
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = androidx.compose.ui.Alignment.CenterVertically,
) {
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
TextField(
value = commentText,
onValueChange = { commentText = it },
@@ -191,20 +213,7 @@ private fun CommentsSection(
singleLine = true,
textStyle = MaterialTheme.typography.bodyMedium.copy(color = textColor),
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Send),
keyboardActions = KeyboardActions(onSend = {
if (commentText.isNotBlank()) {
val text = commentText
commentText = ""
scope.launch {
when (val result = deps.apiClient.createComment(memoId, text)) {
is ApiResult.Success -> {
comments = comments + result.data.toDomain()
}
else -> {}
}
}
}
}),
keyboardActions = KeyboardActions(onSend = { submitComment() }),
colors = TextFieldDefaults.colors(
focusedContainerColor = Color.Transparent,
unfocusedContainerColor = Color.Transparent,
@@ -219,16 +228,7 @@ private fun CommentsSection(
fontWeight = FontWeight.SemiBold,
color = if (commentText.isNotBlank()) accent else subtleColor.copy(alpha = 0.3f),
modifier = Modifier
.then(if (commentText.isNotBlank()) Modifier.clickable {
val text = commentText
commentText = ""
scope.launch {
when (val result = deps.apiClient.createComment(memoId, text)) {
is ApiResult.Success -> { comments = comments + result.data.toDomain() }
else -> {}
}
}
} else Modifier)
.then(if (commentText.isNotBlank()) Modifier.clickable { submitComment() } else Modifier)
.padding(start = 8.dp),
)
}
@@ -1,5 +1,7 @@
package com.avinal.memos.ui.tasks
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
@@ -9,33 +11,25 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FilterChip
import androidx.compose.material3.HorizontalDivider
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.avinal.memos.domain.Task
import com.avinal.memos.parser.TaskParser
import com.avinal.memos.ui.theme.DuePurple
import com.avinal.memos.ui.theme.PriorityP1
import com.avinal.memos.ui.theme.PriorityP2
import com.avinal.memos.ui.theme.PriorityP3
import com.avinal.memos.ui.theme.LocalAccentColor
import kotlin.time.Clock
import kotlinx.datetime.DateTimeUnit
import kotlinx.datetime.LocalDate
import kotlinx.datetime.TimeZone
import kotlinx.datetime.plus
import kotlinx.datetime.todayIn
@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
@OptIn(ExperimentalLayoutApi::class)
@Composable
fun TaskDetailSheet(
task: Task,
@@ -43,83 +37,88 @@ fun TaskDetailSheet(
onUpdate: (Task, String) -> Unit,
onOpenMemo: (String) -> Unit,
) {
val sheetState = rememberModalBottomSheetState()
val accent = LocalAccentColor.current
val textColor = MaterialTheme.colorScheme.onBackground
val subtleColor = MaterialTheme.colorScheme.onSurfaceVariant
ModalBottomSheet(
AlertDialog(
onDismissRequest = onDismiss,
sheetState = sheetState,
) {
Column(
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp, vertical = 8.dp),
) {
Text(
text = task.text,
style = MaterialTheme.typography.titleMedium,
)
containerColor = MaterialTheme.colorScheme.surface,
title = null,
text = {
Column {
Text(task.text, fontSize = 17.sp, fontWeight = FontWeight.Medium, color = textColor)
Spacer(Modifier.height(16.dp))
Spacer(Modifier.height(16.dp))
Text("Due Date", style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSurfaceVariant)
Spacer(Modifier.height(4.dp))
FlowRow(horizontalArrangement = Arrangement.spacedBy(6.dp)) {
val today = Clock.System.todayIn(TimeZone.currentSystemDefault())
val dateOptions = listOf(
"Today" to today,
"Tomorrow" to today.plus(1, DateTimeUnit.DAY),
"Next week" to today.plus(7, DateTimeUnit.DAY),
"No date" to null,
Text("due date", fontSize = 13.sp, color = subtleColor)
Spacer(Modifier.height(6.dp))
FlowRow(horizontalArrangement = Arrangement.spacedBy(8.dp), verticalArrangement = Arrangement.spacedBy(6.dp)) {
val today = Clock.System.todayIn(TimeZone.currentSystemDefault())
listOf(
"today" to today,
"tomorrow" to today.plus(1, DateTimeUnit.DAY),
"next week" to today.plus(7, DateTimeUnit.DAY),
"no date" to null,
).forEach { (label, date) ->
val isSelected = task.dueDate == date
Text(
label,
fontSize = 14.sp,
color = if (isSelected) accent else textColor,
fontWeight = if (isSelected) FontWeight.SemiBold else FontWeight.Normal,
modifier = Modifier
.background(
if (isSelected) accent.copy(alpha = 0.1f) else MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.3f),
RoundedCornerShape(4.dp),
)
.clickable { onUpdate(task, TaskParser.reconstructLine(task.copy(dueDate = date))) }
.padding(horizontal = 10.dp, vertical = 6.dp),
)
}
}
Spacer(Modifier.height(14.dp))
Text("priority", fontSize = 13.sp, color = subtleColor)
Spacer(Modifier.height(6.dp))
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
listOf(null to "none", 1 to "p1", 2 to "p2", 3 to "p3").forEach { (p, label) ->
val isSelected = task.priority == p
Text(
label,
fontSize = 14.sp,
color = if (isSelected) accent else textColor,
fontWeight = if (isSelected) FontWeight.SemiBold else FontWeight.Normal,
modifier = Modifier
.background(
if (isSelected) accent.copy(alpha = 0.1f) else MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.3f),
RoundedCornerShape(4.dp),
)
.clickable { onUpdate(task, TaskParser.reconstructLine(task.copy(priority = p))) }
.padding(horizontal = 10.dp, vertical = 6.dp),
)
}
}
if (task.labels.isNotEmpty() || task.lists.isNotEmpty()) {
Spacer(Modifier.height(12.dp))
FlowRow(horizontalArrangement = Arrangement.spacedBy(6.dp)) {
task.labels.forEach { Text("@$it", fontSize = 13.sp, color = subtleColor) }
task.lists.forEach { Text("#$it", fontSize = 13.sp, color = accent) }
}
}
Spacer(Modifier.height(16.dp))
Text(
"open in memo",
fontSize = 15.sp,
color = accent,
modifier = Modifier.clickable { onOpenMemo(task.memoId) }.padding(vertical = 6.dp),
)
dateOptions.forEach { (label, date) ->
FilterChip(
selected = task.dueDate == date,
onClick = {
val updated = task.copy(dueDate = date)
onUpdate(task, TaskParser.reconstructLine(updated))
},
label = { Text(label) },
)
}
}
Spacer(Modifier.height(12.dp))
Text("Priority", style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSurfaceVariant)
Spacer(Modifier.height(4.dp))
Row(horizontalArrangement = Arrangement.spacedBy(6.dp)) {
val priorityOptions = listOf(null to "None", 1 to "P1", 2 to "P2", 3 to "P3")
priorityOptions.forEach { (p, label) ->
FilterChip(
selected = task.priority == p,
onClick = {
val updated = task.copy(priority = p)
onUpdate(task, TaskParser.reconstructLine(updated))
},
label = { Text(label) },
)
}
}
if (task.labels.isNotEmpty() || task.lists.isNotEmpty()) {
Spacer(Modifier.height(12.dp))
FlowRow(horizontalArrangement = Arrangement.spacedBy(6.dp)) {
task.labels.forEach { label ->
Text("@$label", style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant)
}
task.lists.forEach { list ->
Text("#$list", style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant)
}
}
}
Spacer(Modifier.height(16.dp))
HorizontalDivider()
Spacer(Modifier.height(8.dp))
TextButton(onClick = { onOpenMemo(task.memoId) }) {
Text("Open in memo")
}
Spacer(Modifier.height(16.dp))
}
}
},
confirmButton = {},
)
}
@@ -3,7 +3,6 @@ package com.avinal.memos.ui.theme
import androidx.compose.material3.ColorScheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.graphics.Color
+7 -7
View File
@@ -5,14 +5,14 @@ compose-multiplatform = "1.11.0"
ksp = "2.3.7"
# AndroidX
core-ktx = "1.16.0"
activity-compose = "1.10.1"
core-ktx = "1.18.0"
activity-compose = "1.13.0"
lifecycle = "2.10.0"
navigation = "2.9.2"
datastore = "1.2.1"
work = "2.11.1"
work = "2.11.2"
room = "2.8.4"
sqlite = "2.5.1"
sqlite = "2.6.2"
# Kotlin Multiplatform
kotlinx-coroutines = "1.11.0"
@@ -20,15 +20,15 @@ kotlinx-datetime = "0.8.0"
kotlinx-serialization = "1.11.0"
# Networking
ktor = "3.4.3"
ktor = "3.5.0"
# Image loading
coil = "3.4.0"
# Testing
junit = "4.13.2"
junit-android = "1.1.5"
espresso = "3.5.1"
junit-android = "1.3.0"
espresso = "3.7.0"
[libraries]
# AndroidX