Skip to content

Commit 237e036

Browse files
committed
[refactor]: String 추가 및 책 검색 화면 구현 완료 (#47)
1 parent 87ad17a commit 237e036

3 files changed

Lines changed: 206 additions & 9 deletions

File tree

Lines changed: 195 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,206 @@
11
package com.texthip.thip.ui.booksearch.screen
22

33
import androidx.compose.foundation.layout.Box
4+
import androidx.compose.foundation.layout.Column
5+
import androidx.compose.foundation.layout.Spacer
46
import androidx.compose.foundation.layout.fillMaxSize
5-
import androidx.compose.material3.Text
7+
import androidx.compose.foundation.layout.fillMaxWidth
8+
import androidx.compose.foundation.layout.height
9+
import androidx.compose.foundation.layout.padding
610
import androidx.compose.runtime.Composable
7-
import androidx.compose.ui.Alignment
11+
import androidx.compose.runtime.LaunchedEffect
12+
import androidx.compose.runtime.derivedStateOf
13+
import androidx.compose.runtime.getValue
14+
import androidx.compose.runtime.mutableStateOf
15+
import androidx.compose.runtime.remember
16+
import androidx.compose.runtime.saveable.rememberSaveable
17+
import androidx.compose.runtime.setValue
818
import androidx.compose.ui.Modifier
9-
import androidx.navigation.NavController
19+
import androidx.compose.ui.focus.FocusRequester
20+
import androidx.compose.ui.focus.focusRequester
21+
import androidx.compose.ui.platform.LocalFocusManager
22+
import androidx.compose.ui.res.stringResource
23+
import androidx.compose.ui.tooling.preview.Preview
24+
import androidx.compose.ui.unit.dp
25+
import androidx.navigation.NavHostController
26+
import com.texthip.thip.R
27+
import com.texthip.thip.ui.common.forms.SearchBookTextField
28+
import com.texthip.thip.ui.common.topappbar.DefaultTopAppBar
29+
import com.texthip.thip.ui.booksearch.component.BookEmptyResult
30+
import com.texthip.thip.ui.booksearch.component.BookFilteredSearchResult
31+
import com.texthip.thip.ui.booksearch.component.BookLiveSearchResult
32+
import com.texthip.thip.ui.booksearch.component.BookRecentSearch
33+
import com.texthip.thip.ui.booksearch.mock.BookData
34+
import com.texthip.thip.ui.theme.ThipTheme
1035

1136
@Composable
12-
fun BookSearchScreen(navController: NavController) {
37+
fun BookSearchScreen(
38+
modifier: Modifier = Modifier,
39+
navController: NavHostController? = null,
40+
bookList: List<BookData> = emptyList(),
41+
popularBooks: List<BookData> = emptyList()
42+
) {
43+
var recentSearches by rememberSaveable {
44+
mutableStateOf(listOf("asd", "qwe", "xcv", "dfggfd", "asdasd", "gfhjghj"))
45+
}
46+
var searchText by rememberSaveable { mutableStateOf("") }
47+
var isSearched by rememberSaveable { mutableStateOf(false) }
48+
val focusRequester = remember { FocusRequester() }
49+
val focusManager = LocalFocusManager.current
50+
51+
val liveFilteredBookList by remember(searchText) {
52+
derivedStateOf {
53+
if (searchText.isBlank()) emptyList() else
54+
bookList.filter { book ->
55+
book.title.contains(searchText, ignoreCase = true) ||
56+
book.author.contains(searchText, ignoreCase = true) ||
57+
book.publisher.contains(searchText, ignoreCase = true)
58+
}
59+
}
60+
}
61+
62+
val filteredBookList by remember(searchText, isSearched) {
63+
derivedStateOf {
64+
if (!isSearched) emptyList()
65+
else {
66+
bookList.filter { book ->
67+
searchText.isBlank() ||
68+
book.title.contains(searchText, ignoreCase = true) ||
69+
book.author.contains(searchText, ignoreCase = true) ||
70+
book.publisher.contains(searchText, ignoreCase = true)
71+
}
72+
}
73+
}
74+
}
75+
76+
LaunchedEffect(isSearched) {
77+
if (isSearched) {
78+
focusManager.clearFocus()
79+
}
80+
}
81+
1382
Box(
14-
modifier = Modifier.fillMaxSize(),
15-
contentAlignment = Alignment.Center
83+
modifier = modifier.fillMaxSize()
1684
) {
17-
Text(text = "Book Search Screen")
85+
Column(
86+
modifier = Modifier.fillMaxSize()
87+
) {
88+
DefaultTopAppBar(
89+
title = stringResource(R.string.book_search_topappbar),
90+
onLeftClick = {},
91+
)
92+
Column(
93+
modifier = Modifier
94+
.fillMaxSize()
95+
.padding(horizontal = 20.dp)
96+
) {
97+
Spacer(modifier = Modifier.height(16.dp))
98+
99+
SearchBookTextField(
100+
modifier = Modifier
101+
.fillMaxWidth()
102+
.focusRequester(focusRequester),
103+
hint = stringResource(R.string.book_search_hint),
104+
text = searchText,
105+
onValueChange = {
106+
searchText = it
107+
isSearched = false
108+
},
109+
onSearch = { query ->
110+
if (query.isNotBlank() && !recentSearches.contains(query)) {
111+
recentSearches = listOf(query) + recentSearches
112+
}
113+
isSearched = true
114+
}
115+
)
116+
Spacer(modifier = Modifier.height(16.dp))
117+
118+
when {
119+
searchText.isBlank() && !isSearched -> {
120+
BookRecentSearch(
121+
recentSearches = recentSearches,
122+
popularBooks = popularBooks,
123+
popularBookDate = "01.12", // TODO: 서버로 날짜를 받아 오게 수정
124+
onSearchClick = { keyword ->
125+
searchText = keyword
126+
isSearched = true
127+
},
128+
onRemove = { keyword ->
129+
recentSearches = recentSearches.filterNot { it == keyword }
130+
},
131+
onBookClick = { book ->
132+
// 책 클릭 시 처리
133+
}
134+
)
135+
}
136+
137+
searchText.isNotBlank() && !isSearched -> {
138+
if (liveFilteredBookList.isEmpty()) {
139+
BookEmptyResult(
140+
mainText = stringResource(R.string.book_no_search_result1),
141+
subText = stringResource(R.string.book_no_search_result2),
142+
onRequestBook = { /*책 요청 처리*/ }
143+
)
144+
} else {
145+
BookLiveSearchResult(
146+
bookList = liveFilteredBookList
147+
)
148+
}
149+
}
150+
151+
isSearched -> {
152+
BookFilteredSearchResult(
153+
resultCount = filteredBookList.size,
154+
bookList = filteredBookList,
155+
)
156+
}
157+
}
158+
}
159+
}
160+
}
161+
}
162+
163+
164+
@Preview(showBackground = true)
165+
@Composable
166+
fun PreviewBookSearchScreen_Default() {
167+
ThipTheme {
168+
BookSearchScreen(
169+
bookList = listOf(
170+
BookData("aaa", "리처드 도킨스", "을유문화사", R.drawable.bookcover_sample),
171+
BookData("abc", "마틴 셀리그만", "물푸레", R.drawable.bookcover_sample),
172+
BookData("abcd", "빅터 프랭클", "청림출판", R.drawable.bookcover_sample),
173+
BookData("abcde", "칼 융", "문학과지성사", R.drawable.bookcover_sample),
174+
BookData("abcdef", "에릭 프롬", "까치글방", R.drawable.bookcover_sample),
175+
BookData("abcedfg", "알베르 카뮈", "민음사", R.drawable.bookcover_sample),
176+
BookData("abcdefgh", "장 폴 사르트르", "문학동네", R.drawable.bookcover_sample),
177+
),
178+
popularBooks = listOf(
179+
BookData("단 한번의 삶", "리처드 도킨스", "을유문화사", R.drawable.bookcover_sample),
180+
BookData("사랑", "마틴 셀리그만", "물푸레", R.drawable.bookcover_sample),
181+
BookData("호모 사피엔스", "빅터 프랭클", "청림출판", R.drawable.bookcover_sample),
182+
BookData("코스모스 실버", "칼 융", "문학과지성사", R.drawable.bookcover_sample),
183+
BookData("오만과 편견", "에릭 프롬", "까치글방", R.drawable.bookcover_sample),
184+
)
185+
)
186+
}
187+
}
188+
189+
@Preview(showBackground = true)
190+
@Composable
191+
fun PreviewBookSearchScreen_EmptyPopular() {
192+
ThipTheme {
193+
BookSearchScreen(
194+
bookList = listOf(
195+
BookData("aaa", "리처드 도킨스", "을유문화사", R.drawable.bookcover_sample),
196+
BookData("abc", "마틴 셀리그만", "물푸레", R.drawable.bookcover_sample),
197+
BookData("abcd", "빅터 프랭클", "청림출판", R.drawable.bookcover_sample),
198+
BookData("abcde", "칼 융", "문학과지성사", R.drawable.bookcover_sample),
199+
BookData("abcdef", "에릭 프롬", "까치글방", R.drawable.bookcover_sample),
200+
BookData("abcedfg", "알베르 카뮈", "민음사", R.drawable.bookcover_sample),
201+
BookData("abcdefgh", "장 폴 사르트르", "문학동네", R.drawable.bookcover_sample),
202+
),
203+
popularBooks = emptyList()
204+
)
18205
}
19-
}
206+
}

app/src/main/java/com/texthip/thip/ui/navigator/MainNavHost.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ fun MainNavHost(navController: NavHostController) {
1414
NavHost(navController = navController, startDestination = Routes.Feed.route) {
1515
composable(Routes.Feed.route) { FeedScreen(navController) }
1616
composable(Routes.Group.route) { GroupScreen(navController) }
17-
composable(Routes.BookSearch.route) { BookSearchScreen(navController) }
17+
composable(Routes.BookSearch.route) { BookSearchScreen(navController = navController) }
1818
composable(Routes.MyPage.route) {
1919
MyPageScreen(
2020
navController,

app/src/main/res/values/strings.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,4 +255,14 @@
255255
<string name="group_myroom_error_comment1">참여 중인 모임방이 없어요</string>
256256
<string name="group_myroom_error_comment2">첫번째 모임방에 참여해보세요</string>
257257

258+
<!-- book search -->
259+
<string name="book_popular_search">가장 많이 검색된 책</string>
260+
<string name="book_search_topappbar">검색</string>
261+
<string name="book_search_hint">책 제목, 작가명을 검색해보세요.</string>
262+
<string name="book_no_search_result1">현재 등록된 책이 없어요.</string>
263+
<string name="book_no_search_result2">원하는 책을 신청해주세요!</string>
264+
<string name="book_search_date">%1$s. 기준</string>
265+
<string name="book_no_most_search_result_comment_1">아직 순위가 집계되지 않았어요.</string>
266+
<string name="book_no_most_search_result_comment_2">조금만 기다려주세요!</string>
267+
258268
</resources>

0 commit comments

Comments
 (0)