Skip to content

Commit 07da0a0

Browse files
committed
SearchBar is inside LazyColumn
- removed suggested search - removed custom theme function - fix coroutine issues in SearchModel
1 parent b6d07d1 commit 07da0a0

File tree

4 files changed

+104
-199
lines changed

4 files changed

+104
-199
lines changed

app/build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ android {
1414
minSdk = 21
1515
targetSdk = 36
1616

17-
versionCode = 46
18-
versionName = "1.0-46"
17+
versionCode = 47
18+
versionName = "1.0-47"
1919

2020
}
2121

app/src/main/java/jisho/MainActivity.kt

Lines changed: 102 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,16 @@ import androidx.compose.foundation.shape.RoundedCornerShape
2323
import androidx.compose.material3.HorizontalDivider
2424
import androidx.compose.material3.Icon
2525
import androidx.compose.material3.IconButton
26+
import androidx.compose.material3.MaterialTheme
2627
import androidx.compose.material3.Surface
2728
import androidx.compose.material3.Text
2829
import androidx.compose.material3.TextField
2930
import androidx.compose.material3.TextFieldDefaults
31+
import androidx.compose.material3.darkColorScheme
3032
import androidx.compose.runtime.Composable
3133
import androidx.compose.runtime.collectAsState
3234
import androidx.compose.runtime.getValue
35+
import androidx.compose.runtime.remember
3336
import androidx.compose.ui.Alignment
3437
import androidx.compose.ui.Modifier
3538
import androidx.compose.ui.graphics.Color
@@ -50,7 +53,6 @@ import androidx.compose.ui.unit.dp
5053
import androidx.compose.ui.unit.sp
5154
import androidx.lifecycle.ViewModel
5255
import androidx.lifecycle.viewModelScope
53-
import jisho.ui.theme.Theme
5456
import kotlinx.coroutines.Job
5557
import kotlinx.coroutines.flow.MutableStateFlow
5658
import kotlinx.coroutines.flow.StateFlow
@@ -63,19 +65,24 @@ class MainActivity : ComponentActivity() {
6365
super.onCreate(savedInstanceState)
6466
val searchModel: SearchModel by viewModels()
6567
setContent {
66-
Theme {
68+
MaterialTheme(
69+
colorScheme = darkColorScheme()
70+
) {
6771
Surface {
68-
Column(
69-
Modifier
72+
val results by searchModel.results.collectAsState(emptyList())
73+
LazyColumn(
74+
modifier = Modifier
7075
.fillMaxSize()
71-
.padding(WindowInsets.systemBars.asPaddingValues()), // @note on screen camera
72-
horizontalAlignment = Alignment.CenterHorizontally
76+
.padding(WindowInsets.systemBars.asPaddingValues())
7377
) {
74-
SearchBar(
75-
searchModel
76-
) { searchModel.search(it) }
77-
val results by searchModel.results.collectAsState(emptyList())
78-
if (results.isNotEmpty()) Results(results, searchModel)
78+
item {
79+
SearchBar(
80+
searchModel
81+
) { searchModel.search(it) }
82+
}
83+
items(results) { jishoData ->
84+
ItemColumn(jishoData, searchModel)
85+
}
7986
}
8087
}
8188
}
@@ -91,8 +98,8 @@ class MainActivity : ComponentActivity() {
9198
val iPos by searchModel.indicatorPos.collectAsState(0)
9299
TextField(
93100
value = TextFieldValue(text = search, selection = TextRange(iPos)),
94-
onValueChange = { newValue ->
95-
onValueChange(newValue.text)
101+
onValueChange = {
102+
onValueChange(it.text)
96103
},
97104
modifier = Modifier
98105
.fillMaxWidth()
@@ -138,122 +145,90 @@ class MainActivity : ComponentActivity() {
138145
}
139146

140147
@Composable
141-
fun Results(results: List<JishoData>, searchModel: SearchModel) {
142-
val search by searchModel.search.collectAsState()
143-
LazyColumn(
144-
modifier = Modifier
145-
.fillMaxSize()
146-
.padding(8.dp)
148+
fun ItemColumn(jishoData: JishoData, searchModel: SearchModel) {
149+
Column(
150+
horizontalAlignment = Alignment.CenterHorizontally
147151
) {
148-
item {
149-
if (search.all { it in 'a'..'z' || it in 'A'..'Z' } &&
150-
search.canEtoH()) {
151-
val annotatedString = buildAnnotatedString {
152-
append("Searched for ")
153-
withStyle(SpanStyle(fontWeight = FontWeight.Bold)) {
154-
append("${replaceEtoH(search)}.")
155-
}
156-
append(" You can also try a search for ")
157-
pushStringAnnotation(
158-
tag = "clickSearch",
159-
annotation = "\"$search\""
160-
)
161-
withStyle(SpanStyle(textDecoration = TextDecoration.Underline)) {
162-
append("\"$search\"")
163-
}
164-
pop()
165-
append(".")
166-
}
167-
var textLayoutResult: TextLayoutResult? = null
168-
Text(
169-
text = annotatedString,
170-
modifier = Modifier
171-
.pointerInput(annotatedString) {
172-
tapGesture(searchModel, annotatedString, textLayoutResult)
173-
}
174-
.padding(bottom = 18.dp),
175-
onTextLayout = { textLayoutResult = it },
176-
)
177-
}
152+
var japanese = jishoData.japanese.firstOrNull()
153+
Text(
154+
text = japanese?.let { if (it.word != null) it.reading else "" }.orEmpty(),
155+
fontSize = 16.sp
156+
)
157+
Text(
158+
text = japanese?.let { it.word ?: it.reading }.orEmpty(),
159+
fontSize = 32.sp
160+
)
161+
}
162+
Row(
163+
horizontalArrangement = Arrangement.spacedBy(6.dp)
164+
) {
165+
if (jishoData.isCommon) {
166+
wordTag("common word", Color(0xFF8abc83))
178167
}
179-
items(results) { word ->
180-
Column(
181-
horizontalAlignment = Alignment.CenterHorizontally
182-
) {
183-
var japanese = word.japanese.firstOrNull()
184-
Text(
185-
text = japanese?.let { if (it.word != null) it.reading else "" }.orEmpty(),
186-
fontSize = 16.sp
187-
)
188-
Text(
189-
text = japanese?.let { it.word ?: it.reading }.orEmpty(),
190-
fontSize = 32.sp
191-
)
192-
}
193-
Row(
194-
horizontalArrangement = Arrangement.spacedBy(6.dp)
195-
) {
196-
if (word.isCommon) {
197-
wordTag("common word", Color(0xFF8abc83))
168+
if (jishoData.jlpt.isNotEmpty()) {
169+
wordTag(
170+
jishoData.jlpt.firstOrNull().orEmpty().replace("-", " "),
171+
Color(0xFF909dc0)
172+
)
173+
}
174+
if (jishoData.tags.isNotEmpty()) {
175+
wordTag(
176+
"Wanikani level ${jishoData.tags.firstOrNull()?.lastOrNull().toString()}",
177+
Color(0xFF909dc0)
178+
)
179+
}
180+
}
181+
for ((index, sense) in jishoData.senses.withIndex()) {
182+
val annotatedString = remember(sense, index) {
183+
buildAnnotatedString {
184+
withStyle(
185+
SpanStyle(
186+
color = Color(0xFFAAAAAA),
187+
fontSize = 16.sp,
188+
fontWeight = FontWeight.Bold
189+
)
190+
) {
191+
append("${sense.partsOfSpeech.joinToString(", ") { it }}\n")
198192
}
199-
if (word.jlpt.isNotEmpty()) {
200-
wordTag(word.jlpt.firstOrNull().orEmpty(), Color(0xFF909dc0))
193+
withStyle(SpanStyle(color = Color(0xFF999999), fontSize = 18.sp)) {
194+
append("${index + 1}. ")
201195
}
202-
if (word.tags.isNotEmpty()) {
203-
wordTag(word.tags.firstOrNull().orEmpty(), Color(0xFF909dc0))
196+
sense.englishDefinitions.forEachIndexed { index, definition ->
197+
append(definition)
198+
if (index != sense.englishDefinitions.lastIndex) append("; ")
204199
}
205-
}
206-
for ((index, sense) in word.senses.withIndex()) {
207-
val annotatedString = buildAnnotatedString {
208-
withStyle(
209-
SpanStyle(
210-
color = Color(0xFFAAAAAA),
211-
fontSize = 16.sp,
212-
fontWeight = FontWeight.Bold
200+
withStyle(SpanStyle(color = Color(0xFFBBBBBB), fontSize = 16.sp)) {
201+
if (sense.seeAlso.isNotEmpty()) {
202+
append(" See also ")
203+
pushStringAnnotation(
204+
tag = "clickSearch",
205+
annotation = sense.seeAlso.firstOrNull().orEmpty()
213206
)
214-
) {
215-
append("${sense.partsOfSpeech.joinToString(", ") { it }}\n")
216-
}
217-
withStyle(SpanStyle(color = Color(0xFF999999), fontSize = 18.sp)) {
218-
append("${index + 1}. ")
219-
}
220-
sense.englishDefinitions.forEachIndexed { index, definition ->
221-
append(definition)
222-
if (index != sense.englishDefinitions.lastIndex) append("; ")
223-
}
224-
withStyle(SpanStyle(color = Color(0xFFBBBBBB), fontSize = 16.sp)) {
225-
if (sense.seeAlso.isNotEmpty()) {
226-
append(" See also ")
227-
pushStringAnnotation(
228-
tag = "clickSearch",
229-
annotation = sense.seeAlso.firstOrNull().orEmpty()
230-
)
231-
withStyle(SpanStyle(textDecoration = TextDecoration.Underline)) {
232-
append(sense.seeAlso.firstOrNull().orEmpty())
233-
}
234-
pop()
235-
}
236-
if (sense.info.isNotEmpty()) {
237-
if (sense.seeAlso.isNotEmpty()) append(',')
238-
append(" ${sense.info.firstOrNull().orEmpty()}")
207+
withStyle(SpanStyle(textDecoration = TextDecoration.Underline)) {
208+
append(sense.seeAlso.firstOrNull().orEmpty())
239209
}
210+
pop()
211+
}
212+
if (sense.info.isNotEmpty()) {
213+
if (sense.seeAlso.isNotEmpty()) append(',')
214+
append(" ${sense.info.firstOrNull().orEmpty()}")
240215
}
241216
}
242-
var textLayoutResult: TextLayoutResult? = null
243-
Text(
244-
text = annotatedString,
245-
modifier = Modifier
246-
.pointerInput(annotatedString) {
247-
tapGesture(searchModel, annotatedString, textLayoutResult)
248-
}
249-
.padding(10.dp),
250-
onTextLayout = { textLayoutResult = it },
251-
style = TextStyle(fontSize = 20.sp)
252-
)
253217
}
254-
HorizontalDivider()
255218
}
219+
var textLayoutResult: TextLayoutResult? = null
220+
Text(
221+
text = annotatedString,
222+
modifier = Modifier
223+
.pointerInput(Unit) {
224+
tapGesture(searchModel, annotatedString, textLayoutResult)
225+
}
226+
.padding(10.dp),
227+
onTextLayout = { textLayoutResult = it },
228+
style = TextStyle(fontSize = 20.sp)
229+
)
256230
}
231+
HorizontalDivider()
257232
}
258233

259234
@Composable
@@ -301,19 +276,25 @@ class MainActivity : ComponentActivity() {
301276

302277
class SearchModel : ViewModel() {
303278
private val _search = MutableStateFlow("")
304-
val search: StateFlow<String> get() = _search
279+
val search: StateFlow<String> = _search
305280

306281
private val _results = MutableStateFlow<List<JishoData>>(emptyList())
307-
val results: StateFlow<List<JishoData>> get() = _results
282+
val results: StateFlow<List<JishoData>> = _results
308283

309284
private var job: Job? = null
310285
fun search(query: String, page: Int = 1) {
311286
_search.value = query
312287
_indicatorPos.value = query.length
313288
job?.takeIf { it.isActive }?.cancel()
289+
if (query.isEmpty()) {
290+
_results.value = emptyList()
291+
return
292+
}
314293
job = viewModelScope.launch {
315294
try {
316-
search(query, page, { word ->
295+
val thisQuery = _search.value
296+
search(thisQuery, page, { word ->
297+
if (thisQuery != _search.value) throw CancellationException()
317298
_results.value = word.data
318299
})
319300
} catch (_: CancellationException) {
@@ -323,7 +304,7 @@ class MainActivity : ComponentActivity() {
323304
}
324305

325306
private val _indicatorPos = MutableStateFlow(0)
326-
val indicatorPos: StateFlow<Int> get() = _indicatorPos
307+
val indicatorPos: StateFlow<Int> = _indicatorPos
327308
fun updateIndicator(pos: Int) {
328309
_indicatorPos.value = pos
329310
}

app/src/main/java/jisho/string.kt

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

app/src/main/java/jisho/ui/theme/Theme.kt

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

0 commit comments

Comments
 (0)