11package com.mrboomdev.awery.ui.routes
22
3+ import androidx.compose.foundation.ExperimentalFoundationApi
4+ import androidx.compose.foundation.clickable
5+ import androidx.compose.foundation.layout.Column
6+ import androidx.compose.foundation.layout.Row
7+ import androidx.compose.foundation.layout.WindowInsets
8+ import androidx.compose.foundation.layout.WindowInsetsSides
9+ import androidx.compose.foundation.layout.asPaddingValues
10+ import androidx.compose.foundation.layout.fillMaxWidth
11+ import androidx.compose.foundation.layout.only
12+ import androidx.compose.foundation.layout.padding
13+ import androidx.compose.foundation.layout.safeDrawing
14+ import androidx.compose.foundation.layout.size
15+ import androidx.compose.foundation.layout.windowInsetsPadding
16+ import androidx.compose.foundation.lazy.LazyColumn
17+ import androidx.compose.foundation.lazy.items
18+ import androidx.compose.foundation.text.BasicTextField
19+ import androidx.compose.foundation.text.input.TextFieldLineLimits
20+ import androidx.compose.foundation.text.input.TextFieldState
21+ import androidx.compose.material3.Icon
22+ import androidx.compose.material3.IconButton
23+ import androidx.compose.material3.MaterialTheme
24+ import androidx.compose.material3.Text
325import androidx.compose.runtime.Composable
26+ import androidx.compose.runtime.LaunchedEffect
27+ import androidx.compose.runtime.derivedStateOf
28+ import androidx.compose.runtime.getValue
29+ import androidx.compose.runtime.remember
30+ import androidx.compose.ui.Alignment
31+ import androidx.compose.ui.Modifier
32+ import androidx.compose.ui.focus.FocusRequester
33+ import androidx.compose.ui.focus.focusRequester
34+ import androidx.compose.ui.graphics.SolidColor
35+ import androidx.compose.ui.text.TextStyle
36+ import androidx.compose.ui.text.style.TextAlign
37+ import androidx.compose.ui.unit.dp
38+ import androidx.compose.ui.unit.sp
39+ import cafe.adriel.voyager.core.model.ScreenModel
40+ import cafe.adriel.voyager.core.model.rememberScreenModel
441import cafe.adriel.voyager.navigator.LocalNavigator
542import cafe.adriel.voyager.navigator.currentOrThrow
643import com.mrboomdev.awery.ext.data.Setting
7- import com.mrboomdev.awery.ui.screens.SearchScreen
44+ import com.mrboomdev.awery.generated.*
45+ import com.mrboomdev.awery.sources.ExtensionsManager
46+ import com.mrboomdev.awery.ui.utils.LocalToaster
847import kotlinx.serialization.Contextual
948import kotlinx.serialization.Serializable
49+ import org.jetbrains.compose.resources.painterResource
50+ import org.jetbrains.compose.resources.stringResource
1051
11- @Serializable
1252class SearchRoute (
53+ initialFilters : List <@Contextual Setting >? = null
54+ ): DefaultSearchRoute(initialFilters)
55+
56+ @Serializable
57+ open class DefaultSearchRoute (
1358 private val initialFilters : List <@Contextual Setting >? = null
1459): BaseRoute() {
60+ @OptIn(ExperimentalFoundationApi ::class )
1561 @Composable
1662 override fun Content () {
1763 val navigation = LocalNavigator .currentOrThrow
64+ val model = rememberScreenModel { SearchModel () }
65+ val queryFocusRequested = remember { FocusRequester () }
1866
19- SearchScreen (
20- onBack = { navigation.pop() },
21- initialFilters = initialFilters
22- )
67+ val foundSources by remember { derivedStateOf {
68+ ExtensionsManager .allSources.filter { source ->
69+ model.query.text.trim().let { text ->
70+ source.context.name?.contains(text) == true || source.context.id.contains(text)
71+ }
72+ }.sortedBy { it.context.name ? : it.context.id }
73+ } }
74+
75+ LaunchedEffect (true ) {
76+ queryFocusRequested.requestFocus()
77+ }
78+
79+ Column {
80+ Row (
81+ modifier = Modifier .windowInsetsPadding(
82+ WindowInsets .safeDrawing.only(
83+ WindowInsetsSides .Horizontal + WindowInsetsSides .Top
84+ )
85+ ),
86+ verticalAlignment = Alignment .CenterVertically
87+ ) {
88+ IconButton (
89+ onClick = { navigation.pop() }
90+ ) {
91+ Icon (
92+ modifier = Modifier
93+ .size(64 .dp)
94+ .padding(9 .dp),
95+ painter = painterResource(Res .drawable.ic_back),
96+ contentDescription = stringResource(Res .string.back)
97+ )
98+ }
99+
100+ BasicTextField (
101+ modifier = Modifier
102+ .focusRequester(queryFocusRequested)
103+ .padding(4 .dp)
104+ .fillMaxWidth(),
105+
106+ state = model.query,
107+ lineLimits = TextFieldLineLimits .SingleLine ,
108+ cursorBrush = SolidColor (MaterialTheme .colorScheme.onSurface),
109+
110+ textStyle = TextStyle (
111+ color = MaterialTheme .colorScheme.onSurface,
112+ fontSize = 16 .sp
113+ )
114+ )
115+ }
116+
117+ LazyColumn (
118+ modifier = Modifier .fillMaxWidth(),
119+ contentPadding = WindowInsets .safeDrawing.only(
120+ WindowInsetsSides .Horizontal + WindowInsetsSides .Bottom
121+ ).asPaddingValues()
122+ ) {
123+ items(
124+ items = foundSources,
125+ key = { it.context.manager.context.id + it.context.id }
126+ ) { source ->
127+ val toaster = LocalToaster .current
128+
129+ Row (
130+ modifier = Modifier
131+ .fillMaxWidth()
132+ .clickable {
133+ toaster.show(" This action isn't done yet!" )
134+ }.padding(8 .dp)
135+ .animateItemPlacement()
136+ ) {
137+ Text (
138+ style = MaterialTheme .typography.bodyLarge,
139+ text = source.context.name ? : source.context.id
140+ )
141+ }
142+ }
143+
144+ if (foundSources.isEmpty()) {
145+ item(" empty" ) {
146+ Column (
147+ modifier = Modifier
148+ .fillMaxWidth()
149+ .padding(32 .dp, 64 .dp)
150+ .animateItemPlacement(),
151+ horizontalAlignment = Alignment .CenterHorizontally
152+ ) {
153+ Text (
154+ style = MaterialTheme .typography.headlineSmall,
155+ text = stringResource(Res .string.nothing_found)
156+ )
157+
158+ Text (
159+ modifier = Modifier .padding(8 .dp),
160+ textAlign = TextAlign .Center ,
161+ text = stringResource(Res .string.no_media_found)
162+ )
163+ }
164+ }
165+ }
166+ }
167+ }
23168 }
169+ }
170+
171+ private class SearchModel : ScreenModel {
172+ val query = TextFieldState ()
24173}
0 commit comments