Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ interface ArticleAuthApi {
@Query("type") type: String?,
@Query("page") page: Int,
@Query("limit") limit: Int,
@Query("category") category: String?,
@Query("category") category: List<String>,
@Query("foundStatus") foundStatus: String?,
@Query("sort") sort: String?,
@Query("author") author: String?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class ArticleRemoteDataSource @Inject constructor(
type: String?,
page: Int,
limit: Int,
category: String?,
category: List<String>,
foundStatus: String?,
sort: String?,
author: String?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ data class LostAndFoundFilterParams(
val type: String? = null,
val page: Int = 1,
val limit: Int = 10,
val category: String = "ALL",
val category: List<String> = emptyList(),
val foundStatus: String = "ALL",
val sort: String = "LATEST",
val author: String = "ALL",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ enum class LostItemCategory(
"지갑" -> WALLET
"전자제품" -> ELECTRONIC_DEVICE
"기타" -> OTHER
else -> NONE
else -> OTHER
}
}

Expand All @@ -34,7 +34,7 @@ enum class LostItemCategory(
WALLET -> "지갑"
ELECTRONIC_DEVICE -> "전자제품"
OTHER -> "기타"
NONE -> ""
NONE -> "기타"
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ sealed class LostAndFoundNavType {

const val ARTICLE_ID = "articleId"
const val CHAT_ARTICLE_ID = "article_id"

const val LOST_OR_FOUND_TYPE = "lostOrFoundType"
const val CANCEL_REFRESH_LIST = "cancel_refresh_list"
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package `in`.koreatech.koin.feature.lostandfound.navigation

import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.composable
Expand All @@ -18,12 +22,44 @@ fun NavGraphBuilder.koinLostAndFoundGraph(
navController: NavController,
onBackPressed: () -> Unit
) {
val cancelRefreshList = { cancelRefresh: Boolean ->
navController.getBackStackEntry(LostAndFoundNavType.LostAndFoundListRoute)
?.savedStateHandle
?.let { handle ->
if (handle.get<Boolean>(CANCEL_REFRESH_LIST) != false) {
handle[CANCEL_REFRESH_LIST] = cancelRefresh
}
}
}

val navigateToList = { cancelRefresh: Boolean ->
cancelRefreshList(cancelRefresh)
navController.navigate(LostAndFoundNavType.LostAndFoundListRoute) {
popUpTo(navController.graph.startDestinationId) {
inclusive = false
}
launchSingleTop = true
}
}

val onBackPressed = {
cancelRefreshList(true)
onBackPressed()
}

composable<LostAndFoundNavType.LostAndFoundListRoute> { backStackEntry ->
val refreshFlow = backStackEntry.savedStateHandle.getStateFlow("refresh_list", false).collectAsStateWithLifecycle()
var isCancelRefresh by remember { mutableStateOf(false) }

LaunchedEffect(Unit) {
if (backStackEntry.savedStateHandle.contains(CANCEL_REFRESH_LIST)) {
isCancelRefresh = backStackEntry.savedStateHandle[CANCEL_REFRESH_LIST] ?: false
}
backStackEntry.savedStateHandle.remove<Boolean>(CANCEL_REFRESH_LIST)
}
val navigator = rememberNavigator()
val context = LocalContext.current
LostAndFoundList(
doRefresh = refreshFlow.value,
cancelRefresh = isCancelRefresh,
onTopbarBackClick = onBackPressed,
navigateArticleDetail = { articleId ->
navController.navigate(LostAndFoundNavType.LostAndFoundDetailRoute(articleId))
Expand All @@ -46,20 +82,11 @@ fun NavGraphBuilder.koinLostAndFoundGraph(
val navigator = rememberNavigator()
val context = LocalContext.current
LostAndFoundDetail(
refreshLostAndFoundList = {
navController.getBackStackEntry(LostAndFoundNavType.LostAndFoundListRoute)
?.savedStateHandle
?.set("refresh_list", true)
},
navigateToArticleList = {
navController.navigate(LostAndFoundNavType.LostAndFoundListRoute) {
popUpTo(navController.graph.startDestinationId) {
inclusive = false
}
launchSingleTop = true
}
},
navigateToArticleList = navigateToList,
onTopbarBackClick = onBackPressed,
refreshList = {
cancelRefreshList(false)
},
navigateToChatRoom = { articleId ->
val intent = navigator.navigateToChatRoom(context)
intent.putExtra(CHAT_ARTICLE_ID, articleId)
Expand Down Expand Up @@ -96,26 +123,15 @@ fun NavGraphBuilder.koinLostAndFoundGraph(
composable<LostAndFoundNavType.LostAndFoundWriteRoute> {
LostAndFoundWriteArticle(
onBackClick = onBackPressed,
onComplete = {
navController.navigate(LostAndFoundNavType.LostAndFoundListRoute) {
popUpTo(navController.graph.startDestinationId) {
inclusive = true
}
launchSingleTop = true
}
}
onComplete = { navigateToList(false) }
)
}

composable<LostAndFoundNavType.LostAndFoundModifyRoute> {
LostAndFoundModify(
onBackClick = onBackPressed,
onComplete = { articleId ->
navController.navigate(LostAndFoundNavType.LostAndFoundListRoute) {
popUpTo<LostAndFoundNavType.LostAndFoundDetailRoute> {
inclusive = true
}
}
navigateToList(false)
navController.navigate(LostAndFoundNavType.LostAndFoundDetailRoute(articleId))
}
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ import org.orbitmvi.orbit.compose.collectSideEffect
fun LostAndFoundDetail(
viewModel: LostAndFoundDetailViewModel = hiltViewModel(),
modifier: Modifier = Modifier,
navigateToArticleList: () -> Unit = {},
onTopbarBackClick: () -> Unit = {},
refreshLostAndFoundList: () -> Unit = {},
refreshList: () -> Unit = {},
navigateToArticleList: (cancelRefresh: Boolean) -> Unit = {},
navigateToRecentArticle: (articleId: Int) -> Unit = {},
navigateToChatRoom: (articleId: Int) -> Unit = {},
navigateToLogin: (articleId: Int) -> Unit = {},
Expand All @@ -64,7 +64,9 @@ fun LostAndFoundDetail(
topBar = {
KoinTopAppBar(
title = stringResource(R.string.lost_and_found),
onNavigationIconClick = onTopbarBackClick
onNavigationIconClick = {
onTopbarBackClick()
}
)
}
) { contentPadding ->
Expand All @@ -84,8 +86,8 @@ fun LostAndFoundDetail(
loggingLostOrFound
)
viewModel.setFound()
refreshList()
viewModel.setShowFoundDialog(false)
refreshLostAndFoundList()
},
onNegative = {
viewModel.setShowFoundDialog(false)
Expand Down Expand Up @@ -121,7 +123,7 @@ fun LostAndFoundDetail(
}

viewModel.collectSideEffect {
handleSideEffect(it, context, navigateToArticleList, refreshLostAndFoundList)
handleSideEffect(it, context, navigateToArticleList)
}

Column(
Expand All @@ -137,6 +139,14 @@ fun LostAndFoundDetail(
val enableRecentArticleHeight = remember(layoutHeightDp.value) {
mutableStateOf(screenHeightDp - (contentPadding.calculateTopPadding() + contentPadding.calculateBottomPadding()) - layoutHeightDp.value)
}

val itemHeightDp = 48.dp
val headerHeight = 54.dp
val finalRecentArticleHeight = remember(enableRecentArticleHeight.value) {
val availableHeight = enableRecentArticleHeight.value - headerHeight
val visibleItemCount = (availableHeight / itemHeightDp).toInt()
headerHeight + (itemHeightDp * (visibleItemCount + 0.65f))
}
Layout(
content = {
Column {
Expand Down Expand Up @@ -194,7 +204,7 @@ fun LostAndFoundDetail(
isAuthorWithdraw = uiState.isAuthorWithdraw,
isWriterAdmin = uiState.organization != null,
onArticleListClick = {
navigateToArticleList
navigateToArticleList(true)
},
onDeleteArticleClick = {
viewModel.deleteArticle()
Expand Down Expand Up @@ -240,8 +250,8 @@ fun LostAndFoundDetail(

RecentArticleList(
modifier = Modifier
.heightIn(min = 300.dp, max = screenHeightDp)
.height(enableRecentArticleHeight.value),
.heightIn(min = 275.dp, max = screenHeightDp)
.height(finalRecentArticleHeight),
recentArticles = recentArticles,
isLoadingMore = uiState.isLoadingMoreArticles,
hasMoreArticles = uiState.hasMoreArticles,
Expand All @@ -263,8 +273,7 @@ fun LostAndFoundDetail(
private fun handleSideEffect(
sideEffect: LostAndFoundDetailSideEffect,
context: Context,
navigateToArticleList: () -> Unit = {},
refreshLostAndFoundList: () -> Unit = {}
navigateToArticleList: (cancelRefresh: Boolean) -> Unit = {}
) {
when (sideEffect) {
is LostAndFoundDetailSideEffect.DeleteArticle -> {
Expand All @@ -273,8 +282,7 @@ private fun handleSideEffect(
context.getString(R.string.detail_delete_toast),
Toast.LENGTH_SHORT
).show()
refreshLostAndFoundList()
navigateToArticleList()
navigateToArticleList(false)
}

LostAndFoundDetailSideEffect.DeleteArticleFailed -> {
Expand All @@ -291,8 +299,7 @@ private fun handleSideEffect(
context.getString(R.string.detail_deleted_article),
Toast.LENGTH_SHORT
).show()
refreshLostAndFoundList()
navigateToArticleList()
navigateToArticleList(true)
}

LostAndFoundDetailSideEffect.UpdateFoundFail -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
Expand All @@ -38,11 +37,13 @@ import `in`.koreatech.koin.feature.lostandfound.ui.list.component.LostAndFoundFA
import `in`.koreatech.koin.feature.lostandfound.ui.list.component.LostAndFoundFABBottomSheet
import `in`.koreatech.koin.feature.lostandfound.ui.list.component.LostAndFoundFilterBottomSheet
import kotlinx.collections.immutable.toPersistentList
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.distinctUntilChanged
import org.orbitmvi.orbit.compose.collectAsState

@Composable
fun LostAndFoundList(
doRefresh: Boolean,
cancelRefresh: Boolean,
viewModel: LostAndFoundListViewModel = hiltViewModel(),
onTopbarBackClick: () -> Unit = {},
navigateToLogin: () -> Unit = {},
Expand All @@ -51,13 +52,18 @@ fun LostAndFoundList(
) {
val uiState by viewModel.collectAsState()

val refresh = remember(doRefresh) { mutableStateOf(doRefresh) }

LaunchedEffect(refresh) {
if (doRefresh) {
viewModel.fetchLostAndFoundItem()
refresh.value = false
}
LaunchedEffect(Unit, cancelRefresh) {
var cancelRefresh = cancelRefresh
snapshotFlow { uiState.searchQuery }
.debounce(SEARCH_DEBOUNCE_MS)
.distinctUntilChanged()
.collect {
if (cancelRefresh) {
cancelRefresh = false
} else {
viewModel.fetchLostAndFoundItem()
}
}
}

if (uiState.showFilterBottomSheet) {
Expand Down Expand Up @@ -220,3 +226,5 @@ fun LostAndFoundList(
}
}
}

const val SEARCH_DEBOUNCE_MS = 250L
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ data class LostAndFoundListState(
val isLoggedIn: Boolean = false,
val showFilterLoginDialog: Boolean = false,
val showWriteLoginDialog: Boolean = false,
val isFirstPageLoading: Boolean = false,
val isFirstPageLoading: Boolean = true,
val showFilterBottomSheet: Boolean = false,
val showWriteBottomSheet: Boolean = false,
val searchQuery: String = "",
val categoryFilterType: CategoryFilterType = CategoryFilterType.ALL,
val categoryFilterType: ImmutableList<CategoryFilterType> = persistentListOf(CategoryFilterType.ALL),
val lostOrFoundFilterType: LostOrFoundFilterType = LostOrFoundFilterType.ALL,
val foundFilterType: FoundFilterType = FoundFilterType.ALL,
val authorFilterType: AuthorFilterType = AuthorFilterType.ALL,
Expand Down
Loading