-
Notifications
You must be signed in to change notification settings - Fork 1
feat : 컬렉션 작품 검색 및 선택 상태 통합 #948
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
bae83e9
213b0ba
638e968
5bf34e0
92c23be
1628f2e
c80f806
7eb46ca
d86f1c1
6cf4e41
6c244ab
670993a
ebf3927
3d639f1
ab2e40d
aa86bc4
19b8620
ad14c39
1771d69
ab96f58
75ed170
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||
| android:width="12dp" | ||
| android:height="12dp" | ||
| android:viewportWidth="12" | ||
| android:viewportHeight="12"> | ||
| <path | ||
| android:fillColor="#00000000" | ||
| android:pathData="M6,3L6,9M3,6L9,6" | ||
| android:strokeColor="#FFFFFF" | ||
| android:strokeLineCap="round" | ||
| android:strokeWidth="1" /> | ||
| </vector> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||
| android:width="12dp" | ||
| android:height="12dp" | ||
| android:viewportWidth="12" | ||
| android:viewportHeight="12"> | ||
| <path | ||
| android:fillColor="#00000000" | ||
| android:pathData="M3,3L9,9M9,3L3,9" | ||
| android:strokeColor="#FF675D" | ||
| android:strokeLineCap="round" | ||
| android:strokeWidth="1" /> | ||
| </vector> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| package com.into.websoso.data.novel | ||
|
|
||
| import androidx.paging.Pager | ||
| import androidx.paging.PagingConfig | ||
| import androidx.paging.PagingData | ||
| import com.into.websoso.data.novel.model.NovelSearchEntity | ||
| import kotlinx.coroutines.flow.Flow | ||
| import javax.inject.Inject | ||
|
|
||
| class NovelSearchRepository | ||
| @Inject | ||
| internal constructor( | ||
| private val api: NovelSearchApi, | ||
| ) { | ||
| fun searchNovels(query: String): Flow<PagingData<NovelSearchEntity>> = | ||
| Pager( | ||
| config = PagingConfig( | ||
| pageSize = PAGE_SIZE, | ||
| initialLoadSize = PAGE_SIZE, | ||
| enablePlaceholders = false, | ||
| ), | ||
| pagingSourceFactory = { | ||
| NovelSearchPagingSource( | ||
| query = query, | ||
| api = api, | ||
| ) | ||
| }, | ||
| ).flow | ||
|
|
||
| private companion object { | ||
| const val PAGE_SIZE = 20 | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,34 +1,24 @@ | ||
| package com.into.websoso.feature.collection | ||
|
|
||
| import androidx.compose.foundation.Image | ||
| import androidx.compose.foundation.background | ||
| import androidx.compose.foundation.layout.Arrangement | ||
| import androidx.compose.foundation.layout.Box | ||
| import androidx.compose.foundation.layout.Column | ||
| import androidx.compose.foundation.layout.PaddingValues | ||
| import androidx.compose.foundation.layout.Spacer | ||
| import androidx.compose.foundation.layout.fillMaxSize | ||
| import androidx.compose.foundation.layout.fillMaxWidth | ||
| import androidx.compose.foundation.layout.height | ||
| import androidx.compose.foundation.layout.padding | ||
| import androidx.compose.foundation.layout.size | ||
| import androidx.compose.foundation.layout.statusBarsPadding | ||
| import androidx.compose.foundation.lazy.grid.GridCells | ||
| import androidx.compose.foundation.lazy.grid.GridItemSpan | ||
| import androidx.compose.foundation.lazy.grid.LazyVerticalGrid | ||
| import androidx.compose.foundation.shape.RoundedCornerShape | ||
| import androidx.compose.material3.Button | ||
| import androidx.compose.material3.ButtonDefaults | ||
| import androidx.compose.material3.CircularProgressIndicator | ||
| import androidx.compose.material3.Text | ||
| import androidx.compose.runtime.Composable | ||
| import androidx.compose.runtime.LaunchedEffect | ||
| import androidx.compose.runtime.getValue | ||
| import androidx.compose.ui.Alignment | ||
| import androidx.compose.ui.Modifier | ||
| import androidx.compose.ui.res.painterResource | ||
| import androidx.compose.ui.res.stringResource | ||
| import androidx.compose.ui.text.style.TextAlign | ||
| import androidx.compose.ui.tooling.preview.Preview | ||
| import androidx.compose.ui.unit.dp | ||
| import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel | ||
|
|
@@ -37,39 +27,36 @@ import androidx.paging.LoadState | |
| import androidx.paging.PagingData | ||
| import androidx.paging.compose.LazyPagingItems | ||
| import androidx.paging.compose.collectAsLazyPagingItems | ||
| import com.into.websoso.core.designsystem.theme.Black | ||
| import com.into.websoso.core.designsystem.theme.Gray300 | ||
| import com.into.websoso.core.designsystem.theme.Primary100 | ||
| import com.into.websoso.core.designsystem.theme.WebsosoTheme | ||
| import com.into.websoso.core.designsystem.theme.White | ||
| import com.into.websoso.core.resource.R.drawable.img_load_fail | ||
| import com.into.websoso.core.resource.R.string.load_fail_description | ||
| import com.into.websoso.core.resource.R.string.load_fail_reload | ||
| import com.into.websoso.core.resource.R.string.load_fail_title | ||
| import com.into.websoso.core.resource.R.string.collection_create_add | ||
| import com.into.websoso.core.resource.R.string.library | ||
| import com.into.websoso.feature.collection.component.CollectionAppBar | ||
| import com.into.websoso.feature.collection.component.CollectionLibraryNovelItem | ||
| import com.into.websoso.feature.collection.component.CollectionNetworkError | ||
| import com.into.websoso.feature.collection.model.CollectionLibraryNovelUiModel | ||
| import com.into.websoso.feature.collection.model.CollectionSelectedNovel | ||
| import kotlinx.coroutines.flow.flowOf | ||
|
|
||
| @Composable | ||
| internal fun CollectionLibraryNovelSelectionRoute( | ||
| initialSelectedNovelIds: Set<Long>, | ||
| onAddClick: (Set<Long>) -> Unit, | ||
| initialSelectedNovels: List<CollectionSelectedNovel>, | ||
| onAddClick: (List<CollectionSelectedNovel>) -> Unit, | ||
| onNavigateBack: () -> Unit, | ||
| viewModel: CollectionLibraryNovelSelectionViewModel = hiltViewModel(), | ||
| ) { | ||
| val novels = viewModel.novels.collectAsLazyPagingItems() | ||
| val selectedNovelIds by viewModel.selectedNovelIds.collectAsStateWithLifecycle() | ||
| val selectedNovels by viewModel.selectedNovels.collectAsStateWithLifecycle() | ||
|
|
||
| LaunchedEffect(initialSelectedNovelIds) { | ||
| viewModel.setSelectedNovelIds(initialSelectedNovelIds) | ||
| LaunchedEffect(initialSelectedNovels) { | ||
| viewModel.setSelectedNovels(initialSelectedNovels) | ||
| } | ||
|
|
||
| CollectionLibraryNovelSelectionScreen( | ||
| novels = novels, | ||
| selectedNovelIds = selectedNovelIds, | ||
| selectedNovelIds = selectedNovels.mapTo(mutableSetOf()) { it.novelId }, | ||
| onNovelSelectionChange = viewModel::toggleNovelSelection, | ||
| onAddClick = { onAddClick(selectedNovelIds) }, | ||
| onAddClick = { onAddClick(selectedNovels) }, | ||
| onNavigateBack = onNavigateBack, | ||
| ) | ||
| } | ||
|
|
@@ -78,7 +65,7 @@ internal fun CollectionLibraryNovelSelectionRoute( | |
| internal fun CollectionLibraryNovelSelectionScreen( | ||
| novels: LazyPagingItems<CollectionLibraryNovelUiModel>, | ||
| selectedNovelIds: Set<Long>, | ||
| onNovelSelectionChange: (Long) -> Unit, | ||
| onNovelSelectionChange: (CollectionLibraryNovelUiModel) -> Unit, | ||
| onAddClick: () -> Unit, | ||
| onNavigateBack: () -> Unit, | ||
| modifier: Modifier = Modifier, | ||
|
|
@@ -90,8 +77,8 @@ internal fun CollectionLibraryNovelSelectionScreen( | |
| .statusBarsPadding(), | ||
| ) { | ||
| CollectionAppBar( | ||
| title = "서재", | ||
| actionLabel = "추가", | ||
| title = stringResource(library), | ||
| actionLabel = stringResource(collection_create_add), | ||
| onNavigateBack = onNavigateBack, | ||
| onActionClick = onAddClick, | ||
| isActionEnabled = selectedNovelIds.isNotEmpty(), | ||
|
|
@@ -108,44 +95,10 @@ internal fun CollectionLibraryNovelSelectionScreen( | |
|
|
||
| (novels.itemCount == 0 && novels.loadState.refresh is LoadState.Error) || | ||
| novels.loadState.append is LoadState.Error -> { | ||
| Column( | ||
| CollectionNetworkError( | ||
| onRetryClick = novels::retry, | ||
| modifier = Modifier.align(Alignment.Center), | ||
| horizontalAlignment = Alignment.CenterHorizontally, | ||
| ) { | ||
| Image( | ||
| painter = painterResource(img_load_fail), | ||
| contentDescription = null, | ||
| modifier = Modifier.size(width = 166.dp, height = 160.dp), | ||
| ) | ||
| Spacer(modifier = Modifier.height(40.dp)) | ||
| Text( | ||
| text = stringResource(load_fail_title), | ||
| color = Black, | ||
| style = WebsosoTheme.typography.title1, | ||
| textAlign = TextAlign.Center, | ||
| ) | ||
| Spacer(modifier = Modifier.height(10.dp)) | ||
| Text( | ||
| text = stringResource(load_fail_description), | ||
| color = Gray300, | ||
| style = WebsosoTheme.typography.body2, | ||
| textAlign = TextAlign.Center, | ||
| ) | ||
| Spacer(modifier = Modifier.height(40.dp)) | ||
| Button( | ||
| onClick = novels::retry, | ||
| shape = RoundedCornerShape(8.dp), | ||
| colors = ButtonDefaults.buttonColors(containerColor = Primary100), | ||
| contentPadding = PaddingValues(horizontal = 38.dp, vertical = 14.dp), | ||
| elevation = null, | ||
| ) { | ||
| Text( | ||
| text = stringResource(load_fail_reload), | ||
| color = White, | ||
| style = WebsosoTheme.typography.label1, | ||
| ) | ||
| } | ||
| } | ||
| ) | ||
|
Comment on lines
+98
to
+101
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 다음 페이지 오류에서 기존 목록을 유지하세요.
전체 오류 화면은 항목이 없고 새로고침이 실패한 경우에만 표시하세요. 다음 페이지 오류는 목록 하단의 재시도 UI로 표시하세요. 🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| else -> { | ||
|
|
@@ -165,7 +118,7 @@ internal fun CollectionLibraryNovelSelectionScreen( | |
| CollectionLibraryNovelItem( | ||
| novel = novel, | ||
| isSelected = novel.novelId in selectedNovelIds, | ||
| onSelectionChange = { onNovelSelectionChange(novel.novelId) }, | ||
| onSelectionChange = { onNovelSelectionChange(novel) }, | ||
| ) | ||
| } | ||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.