diff --git a/composeApp/src/commonMain/kotlin/com/avinal/memos/api/MemosApiClient.kt b/composeApp/src/commonMain/kotlin/com/avinal/memos/api/MemosApiClient.kt index 9058ed9..c711086 100644 --- a/composeApp/src/commonMain/kotlin/com/avinal/memos/api/MemosApiClient.kt +++ b/composeApp/src/commonMain/kotlin/com/avinal/memos/api/MemosApiClient.kt @@ -138,6 +138,13 @@ class MemosApiClient( }.body() } + suspend fun listArchivedMemos(): ApiResult = apiCall { + httpClient.get(url("/memos")) { + parameter("pageSize", 50) + parameter("filter", "state == \"ARCHIVED\"") + }.body() + } + suspend fun deleteMemo(id: String): ApiResult = apiCall { val response = httpClient.delete(url("/memos/$id")) if (!response.status.isSuccess()) { 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 3b026df..4ad6342 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 @@ -247,6 +247,14 @@ private fun ExplorerPage( ) } + Spacer(Modifier.height(12.dp)) + Text( + "view archived memos", + fontSize = 14.sp, + color = accent, + modifier = Modifier.clickable { /* navigate to archived */ }.padding(vertical = 4.dp), + ) + Spacer(Modifier.height(16.dp)) Row( 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 c6735d3..09205cd 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 @@ -349,7 +349,13 @@ fun MemoListScreen( ) } - if (memos.isEmpty() && !uiState.isRefreshing) { + if (uiState.isInitialLoading && memos.isEmpty()) { + item { + Box(Modifier.fillMaxWidth().padding(top = 48.dp), contentAlignment = Alignment.Center) { + androidx.compose.material3.CircularProgressIndicator(color = accent, strokeWidth = 2.dp) + } + } + } else if (memos.isEmpty() && !uiState.isRefreshing) { item { Box(Modifier.fillMaxWidth().padding(top = 48.dp), contentAlignment = Alignment.Center) { Text("no memos yet", fontSize = 15.sp, color = subtleColor) @@ -357,6 +363,15 @@ fun MemoListScreen( } } + if (uiState.error != null) { + item { + Text( + uiState.error!!, fontSize = 12.sp, color = MaterialTheme.colorScheme.error, + modifier = Modifier.padding(start = 24.dp, end = 12.dp, top = 4.dp, bottom = 4.dp), + ) + } + } + items(memos, key = { it.id }) { memo -> MemoCard( memo = memo, 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 aeb9ff2..be775c7 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 @@ -12,6 +12,7 @@ import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch @@ -22,6 +23,7 @@ data class MemoListUiState( val searchQuery: String = "", val isSearching: Boolean = false, val error: String? = null, + val isInitialLoading: Boolean = true, ) class MemoListViewModel(private val memoRepository: MemoRepository) : ViewModel() { @@ -32,6 +34,13 @@ class MemoListViewModel(private val memoRepository: MemoRepository) : ViewModel( private val _searchQuery = MutableStateFlow("") private var searchJob: Job? = null + init { + viewModelScope.launch { + memoRepository.observeMemos().first() + _uiState.update { it.copy(isInitialLoading = false) } + } + } + val memos: StateFlow> = combine( memoRepository.observeMemos(), _searchQuery,