diff --git a/composeApp/src/commonMain/kotlin/com/avinal/memos/AppDependencies.kt b/composeApp/src/commonMain/kotlin/com/avinal/memos/AppDependencies.kt index 2358341..b1a3510 100644 --- a/composeApp/src/commonMain/kotlin/com/avinal/memos/AppDependencies.kt +++ b/composeApp/src/commonMain/kotlin/com/avinal/memos/AppDependencies.kt @@ -39,8 +39,11 @@ class AppDependencies( val authRepository: AuthRepository by lazy { AuthRepository(apiClient, tokenStore) } val memoRepository: MemoRepository by lazy { MemoRepository(apiClient, database.memoDao()) } + private var initJob: kotlinx.coroutines.Job? = null + fun initialize() { - CoroutineScope(Dispatchers.IO).launch { + initJob?.cancel() + initJob = CoroutineScope(Dispatchers.IO).launch { launch { tokenStore.accessToken.collect { cachedToken = it } } launch { tokenStore.serverUrl.collect { cachedServerUrl = it } } } diff --git a/composeApp/src/commonMain/kotlin/com/avinal/memos/api/HttpClientFactory.kt b/composeApp/src/commonMain/kotlin/com/avinal/memos/api/HttpClientFactory.kt index 413eb5c..3992db7 100644 --- a/composeApp/src/commonMain/kotlin/com/avinal/memos/api/HttpClientFactory.kt +++ b/composeApp/src/commonMain/kotlin/com/avinal/memos/api/HttpClientFactory.kt @@ -19,6 +19,11 @@ object HttpClientFactory { encodeDefaults = true }) } + install(io.ktor.client.plugins.HttpTimeout) { + requestTimeoutMillis = 30_000 + connectTimeoutMillis = 15_000 + socketTimeoutMillis = 30_000 + } } client.plugin(HttpSend).intercept { request -> diff --git a/composeApp/src/commonMain/kotlin/com/avinal/memos/domain/MemoRepository.kt b/composeApp/src/commonMain/kotlin/com/avinal/memos/domain/MemoRepository.kt index d6fa0d2..c0e3a02 100644 --- a/composeApp/src/commonMain/kotlin/com/avinal/memos/domain/MemoRepository.kt +++ b/composeApp/src/commonMain/kotlin/com/avinal/memos/domain/MemoRepository.kt @@ -141,7 +141,13 @@ class MemoRepository( suspend fun reactToMemo(memoId: String, emoji: String): ApiResult { return when (apiClient.upsertReaction(memoId, emoji)) { is ApiResult.Success -> { - refreshMemos() + when (val memoResult = apiClient.getMemo(memoId)) { + is ApiResult.Success -> { + val memo = memoResult.data.toDomain() + memoDao.upsert(memo.toEntity(nowMillis())) + } + else -> {} + } ApiResult.Success(Unit) } is ApiResult.Error -> ApiResult.Error(0, "Failed to react") diff --git a/composeApp/src/commonMain/kotlin/com/avinal/memos/ui/memos/MainScreen.kt b/composeApp/src/commonMain/kotlin/com/avinal/memos/ui/memos/MainScreen.kt index 63bc120..3b026df 100644 --- a/composeApp/src/commonMain/kotlin/com/avinal/memos/ui/memos/MainScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/avinal/memos/ui/memos/MainScreen.kt @@ -276,7 +276,9 @@ private fun ExplorerPage( Spacer(Modifier.height(8.dp)) - val dayLabels = listOf("m", "t", "w", "t", "f", "s", "s") + val weekStartDay by deps.tokenStore.weekStartDay.collectAsState(initial = 0) + val baseDays = listOf("s", "m", "t", "w", "t", "f", "s") + val dayLabels = baseDays.drop(weekStartDay) + baseDays.take(weekStartDay) Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly) { dayLabels.forEach { day -> Text(day, fontSize = 11.sp, color = subtleColor.copy(alpha = 0.5f), modifier = Modifier.width(28.dp), textAlign = TextAlign.Center) @@ -284,13 +286,13 @@ private fun ExplorerPage( } Spacer(Modifier.height(4.dp)) - val firstDayOfWeek = remember(calYear, calMonthIdx) { + val firstDayOfWeek = remember(calYear, calMonthIdx, weekStartDay) { val month = calMonthIdx + 1 val y = if (month <= 2) calYear - 1 else calYear val m = if (month <= 2) month + 12 else month val h = (1 + (13 * (m + 1)) / 5 + y + y / 4 - y / 100 + y / 400) % 7 - val mondayBased = ((h + 5) % 7) - if (mondayBased < 0) mondayBased + 7 else mondayBased + val adjusted = ((h + 6 - weekStartDay) % 7) + if (adjusted < 0) adjusted + 7 else adjusted } val cells = buildList { diff --git a/composeApp/src/commonMain/kotlin/com/avinal/memos/ui/memos/MemoDetailViewModel.kt b/composeApp/src/commonMain/kotlin/com/avinal/memos/ui/memos/MemoDetailViewModel.kt index 2bffded..1ed3746 100644 --- a/composeApp/src/commonMain/kotlin/com/avinal/memos/ui/memos/MemoDetailViewModel.kt +++ b/composeApp/src/commonMain/kotlin/com/avinal/memos/ui/memos/MemoDetailViewModel.kt @@ -37,18 +37,11 @@ class MemoDetailViewModel( fun toggleTask(lineIndex: Int, checked: Boolean) { val current = memo.value ?: return - val lines = current.content.lines().toMutableList() - if (lineIndex !in lines.indices) return - - val line = lines[lineIndex] - lines[lineIndex] = if (checked) { - line.replaceFirst("- [ ]", "- [x]") - } else { - line.replaceFirst("- [x]", "- [ ]").replaceFirst("- [X]", "- [ ]") - } - + val tasks = com.avinal.memos.parser.TaskParser.extractTasks(memoId, current.content) + val task = tasks.find { it.lineIndex == lineIndex } ?: return viewModelScope.launch { - memoRepository.updateMemo(memoId, content = lines.joinToString("\n")) + val newContent = com.avinal.memos.parser.TaskParser.toggleTaskInContent(current.content, task) + if (newContent != current.content) memoRepository.updateMemo(memoId, content = newContent) } } diff --git a/composeApp/src/commonMain/kotlin/com/avinal/memos/ui/memos/MemoListScreen.kt b/composeApp/src/commonMain/kotlin/com/avinal/memos/ui/memos/MemoListScreen.kt index 60b8939..c6735d3 100644 --- a/composeApp/src/commonMain/kotlin/com/avinal/memos/ui/memos/MemoListScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/avinal/memos/ui/memos/MemoListScreen.kt @@ -100,7 +100,10 @@ fun MemoListScreen( val subtleColor = MaterialTheme.colorScheme.onSurfaceVariant var composeText by remember { mutableStateOf("") } - var composeVisibility by remember { mutableStateOf(MemoVisibility.PRIVATE) } + val defaultVis by produceState(MemoVisibility.PRIVATE) { + deps.tokenStore.defaultVisibility.first().let { value = MemoVisibility.fromApiString(it) } + } + var composeVisibility by remember(defaultVis) { mutableStateOf(defaultVis) } var showVisibilityPicker by remember { mutableStateOf(false) } var uploadedAttachmentNames by remember { mutableStateOf>(emptyList()) } var isUploading by remember { mutableStateOf(false) } diff --git a/composeApp/src/commonMain/kotlin/com/avinal/memos/ui/memos/MemoListViewModel.kt b/composeApp/src/commonMain/kotlin/com/avinal/memos/ui/memos/MemoListViewModel.kt index 1f33a75..aeb9ff2 100644 --- a/composeApp/src/commonMain/kotlin/com/avinal/memos/ui/memos/MemoListViewModel.kt +++ b/composeApp/src/commonMain/kotlin/com/avinal/memos/ui/memos/MemoListViewModel.kt @@ -106,15 +106,10 @@ class MemoListViewModel(private val memoRepository: MemoRepository) : ViewModel( fun toggleTask(memoId: String, lineIndex: Int, checked: Boolean) { viewModelScope.launch { val memo = memoRepository.getMemo(memoId) ?: return@launch - val lines = memo.content.lines().toMutableList() - if (lineIndex !in lines.indices) return@launch - val line = lines[lineIndex] - lines[lineIndex] = if (checked) { - line.replaceFirst("- [ ]", "- [x]") - } else { - line.replaceFirst("- [x]", "- [ ]").replaceFirst("- [X]", "- [ ]") - } - memoRepository.updateMemo(memoId, content = lines.joinToString("\n")) + val tasks = com.avinal.memos.parser.TaskParser.extractTasks(memoId, memo.content) + val task = tasks.find { it.lineIndex == lineIndex } ?: return@launch + val newContent = com.avinal.memos.parser.TaskParser.toggleTaskInContent(memo.content, task) + if (newContent != memo.content) memoRepository.updateMemo(memoId, content = newContent) } }