Skip to content

Commit 4f4276a

Browse files
committed
feat: bring back search again
1 parent b5aa312 commit 4f4276a

File tree

5 files changed

+147
-146
lines changed

5 files changed

+147
-146
lines changed

app/src/main/kotlin/day/vitayuzu/neodb/MainActivity.kt

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import androidx.compose.animation.ExperimentalSharedTransitionApi
1111
import androidx.compose.animation.SharedTransitionLayout
1212
import androidx.compose.animation.togetherWith
1313
import androidx.compose.material3.ExperimentalMaterial3Api
14+
import androidx.compose.material3.Surface
1415
import androidx.compose.runtime.Composable
1516
import androidx.compose.runtime.CompositionLocalProvider
1617
import androidx.compose.runtime.getValue
@@ -32,11 +33,12 @@ import dagger.hilt.android.AndroidEntryPoint
3233
import day.vitayuzu.neodb.data.AuthRepository
3334
import day.vitayuzu.neodb.data.NeoDBRepository
3435
import day.vitayuzu.neodb.data.UpdateRepository
35-
import day.vitayuzu.neodb.ui.component.SearchModal
3636
import day.vitayuzu.neodb.ui.page.detail.DetailPage
3737
import day.vitayuzu.neodb.ui.page.home.HomeScreen
3838
import day.vitayuzu.neodb.ui.page.library.LibraryPage
39+
import day.vitayuzu.neodb.ui.page.search.SearchPage
3940
import day.vitayuzu.neodb.ui.page.settings.SettingsPage
41+
import day.vitayuzu.neodb.ui.theme.MotionHorizontallyDirection
4042
import day.vitayuzu.neodb.ui.theme.NeoDBYouTheme
4143
import day.vitayuzu.neodb.ui.theme.sharedXAxisTransition
4244
import day.vitayuzu.neodb.util.AppNavigator
@@ -96,7 +98,11 @@ class MainActivity : ComponentActivity() {
9698
CompositionLocalProvider(
9799
LocalSharedTransitionScope provides SharedTransitionScopeProvider(this),
98100
) {
99-
MainNavDisplay()
101+
// This root surface is to make all transition have proper background.
102+
// Or when transition between screens with dark mode, user will see white background.
103+
Surface {
104+
MainNavDisplay()
105+
}
100106
}
101107
}
102108
}
@@ -147,8 +153,22 @@ private fun MainNavDisplay(modifier: Modifier = Modifier) {
147153
entry<Settings> {
148154
SettingsPage()
149155
}
150-
entry<AppNavigator.Search> {
151-
SearchModal()
156+
entry<AppNavigator.Search>(
157+
metadata = NavDisplay.transitionSpec {
158+
sharedXAxisTransition(
159+
MotionHorizontallyDirection.Forward,
160+
)
161+
} + NavDisplay.popTransitionSpec {
162+
sharedXAxisTransition(
163+
MotionHorizontallyDirection.Backward,
164+
)
165+
} + NavDisplay.predictivePopTransitionSpec {
166+
sharedXAxisTransition(
167+
MotionHorizontallyDirection.Backward,
168+
)
169+
},
170+
) {
171+
SearchPage()
152172
}
153173
entry<Detail> {
154174
DetailPage(it.type, it.uuid)

app/src/main/kotlin/day/vitayuzu/neodb/ui/component/SearchModal.kt

Lines changed: 0 additions & 142 deletions
This file was deleted.

app/src/main/kotlin/day/vitayuzu/neodb/ui/component/SharedFab.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ fun SharedFab(
1616
onClick: () -> Unit = {},
1717
content: @Composable () -> Unit,
1818
) {
19+
// FIXME: Disable animation between same Fab.
1920
val fabState =
2021
remember { MutableTransitionState(false).apply { targetState = true } }
2122
AnimatedVisibility(
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package day.vitayuzu.neodb.ui.page.search
2+
3+
import androidx.compose.foundation.layout.Column
4+
import androidx.compose.foundation.layout.fillMaxSize
5+
import androidx.compose.foundation.layout.fillMaxWidth
6+
import androidx.compose.foundation.layout.safeDrawingPadding
7+
import androidx.compose.foundation.lazy.LazyColumn
8+
import androidx.compose.foundation.lazy.items
9+
import androidx.compose.foundation.text.input.rememberTextFieldState
10+
import androidx.compose.material.icons.Icons
11+
import androidx.compose.material.icons.automirrored.filled.ArrowBack
12+
import androidx.compose.material.icons.filled.Search
13+
import androidx.compose.material3.ExperimentalMaterial3Api
14+
import androidx.compose.material3.Icon
15+
import androidx.compose.material3.IconButton
16+
import androidx.compose.material3.SearchBarDefaults
17+
import androidx.compose.material3.SearchBarValue
18+
import androidx.compose.material3.Surface
19+
import androidx.compose.material3.Text
20+
import androidx.compose.material3.rememberSearchBarState
21+
import androidx.compose.runtime.Composable
22+
import androidx.compose.runtime.LaunchedEffect
23+
import androidx.compose.runtime.rememberCoroutineScope
24+
import androidx.compose.runtime.snapshotFlow
25+
import androidx.compose.ui.Alignment
26+
import androidx.compose.ui.Modifier
27+
import androidx.compose.ui.res.stringResource
28+
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
29+
import day.vitayuzu.neodb.R
30+
import day.vitayuzu.neodb.ui.component.EntryMarkCard
31+
import kotlinx.coroutines.FlowPreview
32+
import kotlinx.coroutines.flow.collectLatest
33+
import kotlinx.coroutines.flow.debounce
34+
import kotlinx.coroutines.flow.filterNot
35+
import kotlinx.coroutines.launch
36+
37+
@OptIn(ExperimentalMaterial3Api::class, FlowPreview::class)
38+
@Composable
39+
fun SearchPage(modifier: Modifier = Modifier, viewModel: SearchViewModel = hiltViewModel()) {
40+
val state = rememberSearchBarState(SearchBarValue.Expanded)
41+
val textFieldState = rememberTextFieldState()
42+
val scope = rememberCoroutineScope()
43+
44+
Surface(modifier = modifier.fillMaxSize().safeDrawingPadding()) {
45+
Column(horizontalAlignment = Alignment.CenterHorizontally) {
46+
SearchBarDefaults.InputField(
47+
modifier = Modifier.safeDrawingPadding(),
48+
textFieldState = textFieldState,
49+
searchBarState = state,
50+
onSearch = {},
51+
placeholder = { Text(stringResource(R.string.textfield_search)) },
52+
leadingIcon = {
53+
if (state.targetValue == SearchBarValue.Collapsed) {
54+
Icon(
55+
imageVector = Icons.Default.Search,
56+
contentDescription = "Search",
57+
)
58+
} else {
59+
IconButton(
60+
onClick = { scope.launch { state.animateToCollapsed() } },
61+
) {
62+
Icon(
63+
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
64+
contentDescription = "Back",
65+
)
66+
}
67+
}
68+
},
69+
)
70+
71+
// Perform search request
72+
LaunchedEffect(textFieldState.text) {
73+
snapshotFlow { textFieldState.text }
74+
.debounce(500)
75+
.filterNot { it.isEmpty() }
76+
.collectLatest { query ->
77+
viewModel.onSearch(query.toString())
78+
}
79+
}
80+
81+
LazyColumn(
82+
horizontalAlignment = Alignment.CenterHorizontally,
83+
modifier = Modifier.fillMaxWidth(),
84+
) {
85+
items(viewModel.searchResult.toList(), key = { it.uuid }) {
86+
EntryMarkCard(entry = it, mark = null)
87+
}
88+
}
89+
}
90+
}
91+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package day.vitayuzu.neodb.ui.page.search
2+
3+
import androidx.compose.runtime.mutableStateListOf
4+
import androidx.lifecycle.ViewModel
5+
import androidx.lifecycle.viewModelScope
6+
import dagger.hilt.android.lifecycle.HiltViewModel
7+
import day.vitayuzu.neodb.data.NeoDBRepository
8+
import day.vitayuzu.neodb.ui.model.Entry
9+
import kotlinx.coroutines.flow.launchIn
10+
import kotlinx.coroutines.flow.map
11+
import kotlinx.coroutines.flow.onEach
12+
import javax.inject.Inject
13+
14+
@HiltViewModel
15+
class SearchViewModel @Inject constructor(val repository: NeoDBRepository) : ViewModel() {
16+
val searchResult = mutableStateListOf<Entry>()
17+
18+
private var previousQuery = ""
19+
20+
fun onSearch(query: String) {
21+
if (query == previousQuery) return
22+
previousQuery = query
23+
searchResult.clear()
24+
repository
25+
.searchWithKeyword(query)
26+
.map { result ->
27+
result.data.map { Entry(it) }
28+
}.onEach { searchResult.addAll(it) }
29+
.launchIn(viewModelScope)
30+
}
31+
}

0 commit comments

Comments
 (0)