Skip to content

Commit 3012f31

Browse files
committed
Refine parsing logic in TypeaheadLoaderScreen to support comma-delimited identifiers and remove legacy commented-out code. Introduce a new "Countries 29Lang" dataset by adding country.tsv and updating SearchScreen to include a corresponding loading option. Adjust selection logic in SearchScreen to accommodate the expanded list of demo sources.
1 parent 1779149 commit 3012f31

6 files changed

Lines changed: 222 additions & 75 deletions

File tree

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ across thousands of movie descriptions works just as naturally as searching for
1818
yields a normalized similarity score in `[0.0, 1.0]` while gracefully handling skipped characters, swapped letters,
1919
and phonetic typos.
2020

21-
> **[Try the Live Demo](https://typeahead-service-942294408844.europe-west1.run.app)** — See the engine in action. Load a dataset, start typing (even with typos), and watch results update in real time as data is still being indexed.
21+
> **[Try the Live Demo](https://typeahead-demo.smartcoding.app)** — See the engine in action. Load a dataset, start typing (even with typos), and watch results update in real time as data is still being indexed.
2222
2323
---
2424

‎typeahead-demo/src/commonMain/kotlin/app/smartcoding/typeahead_demo/SearchScreen.kt‎

Lines changed: 26 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -18,61 +18,20 @@
1818

1919
package app.smartcoding.typeahead_demo
2020

21-
import androidx.compose.animation.AnimatedVisibility
22-
import androidx.compose.animation.animateContentSize
21+
import androidx.compose.animation.*
2322
import androidx.compose.animation.core.animateFloatAsState
24-
import androidx.compose.animation.expandVertically
25-
import androidx.compose.animation.fadeIn
26-
import androidx.compose.animation.fadeOut
27-
import androidx.compose.animation.shrinkVertically
2823
import androidx.compose.foundation.clickable
29-
import androidx.compose.foundation.layout.Arrangement
30-
import androidx.compose.foundation.layout.Column
31-
import androidx.compose.foundation.layout.PaddingValues
32-
import androidx.compose.foundation.layout.Row
33-
import androidx.compose.foundation.layout.Spacer
34-
import androidx.compose.foundation.layout.fillMaxSize
35-
import androidx.compose.foundation.layout.fillMaxWidth
36-
import androidx.compose.foundation.layout.padding
37-
import androidx.compose.foundation.layout.size
24+
import androidx.compose.foundation.layout.*
3825
import androidx.compose.foundation.lazy.LazyColumn
3926
import androidx.compose.foundation.lazy.items
4027
import androidx.compose.foundation.lazy.rememberLazyListState
4128
import androidx.compose.material.icons.Icons
42-
import androidx.compose.material.icons.filled.Clear
43-
import androidx.compose.material.icons.filled.ExpandMore
44-
import androidx.compose.material.icons.filled.Info
45-
import androidx.compose.material.icons.filled.Search
46-
import androidx.compose.material.icons.filled.Stop
47-
import androidx.compose.material3.CenterAlignedTopAppBar
48-
import androidx.compose.material3.ExpandedFullScreenSearchBar
49-
import androidx.compose.material3.ExperimentalMaterial3Api
50-
import androidx.compose.material3.Icon
51-
import androidx.compose.material3.IconButton
52-
import androidx.compose.material3.LinearProgressIndicator
53-
import androidx.compose.material3.ListItem
54-
import androidx.compose.material3.ListItemDefaults
55-
import androidx.compose.material3.MaterialTheme
29+
import androidx.compose.material.icons.automirrored.filled.ArrowBack
30+
import androidx.compose.material.icons.filled.*
31+
import androidx.compose.material3.*
5632
import androidx.compose.material3.MaterialTheme.colorScheme
57-
import androidx.compose.material3.OutlinedCard
58-
import androidx.compose.material3.Scaffold
59-
import androidx.compose.material3.SearchBar
6033
import androidx.compose.material3.SearchBarDefaults.InputField
61-
import androidx.compose.material3.SearchBarValue
62-
import androidx.compose.material3.SegmentedButton
63-
import androidx.compose.material3.SegmentedButtonDefaults
64-
import androidx.compose.material3.SingleChoiceSegmentedButtonRow
65-
import androidx.compose.material3.Text
66-
import androidx.compose.material3.rememberSearchBarState
67-
import androidx.compose.runtime.Composable
68-
import androidx.compose.runtime.LaunchedEffect
69-
import androidx.compose.runtime.collectAsState
70-
import androidx.compose.runtime.getValue
71-
import androidx.compose.runtime.key
72-
import androidx.compose.runtime.mutableStateOf
73-
import androidx.compose.runtime.remember
74-
import androidx.compose.runtime.rememberCoroutineScope
75-
import androidx.compose.runtime.setValue
34+
import androidx.compose.runtime.*
7635
import androidx.compose.ui.Alignment
7736
import androidx.compose.ui.Modifier
7837
import androidx.compose.ui.draw.rotate
@@ -90,7 +49,7 @@ fun SearchScreen(
9049
val results by viewModel.results.collectAsState()
9150

9251
var selectedIndex by remember { mutableStateOf(-1) }
93-
val options = listOf("Movies 86k", "Import File").withIndex().toList()
52+
val options = listOf("Countries", "Movies", "Import File").withIndex().toList()
9453

9554
val listState = rememberLazyListState()
9655
val searchBarState = rememberSearchBarState()
@@ -117,12 +76,22 @@ fun SearchScreen(
11776
searchBarState = searchBarState,
11877
onSearch = { scope.launch { searchBarState.animateToCollapsed() } },
11978
placeholder = { Text(searchBarPlaceholder) },
120-
leadingIcon = { Icon(Icons.Default.Search, contentDescription = null) },
79+
leadingIcon = {
80+
if (searchBarState.currentValue == SearchBarValue.Expanded)
81+
IconButton(onClick = {
82+
scope.launch { searchBarState.animateToCollapsed() }
83+
}) {
84+
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null)
85+
}
86+
else {
87+
Icon(Icons.Default.Search, contentDescription = null)
88+
}
89+
90+
},
12191
trailingIcon = {
12292
if (viewModel.queryState.text.isNotEmpty()) {
12393
IconButton(onClick = {
12494
viewModel.clearSearch()
125-
scope.launch { searchBarState.animateToCollapsed() }
12695
}) {
12796
Icon(Icons.Default.Clear, contentDescription = null)
12897
}
@@ -217,11 +186,16 @@ fun SearchScreen(
217186
selectedIndex = index
218187
when (index) {
219188
0 -> viewModel.loadSource(
220-
streamDemoFile("/movies.txt"),
189+
streamDemoFile("/country.tsv"),
221190
expectedLines = 86_000
222191
)
223192

224-
1 -> pickLocalFileAndStream { viewModel.loadSource(it) }
193+
1 -> viewModel.loadSource(
194+
streamDemoFile("/movies.tsv"),
195+
expectedLines = 194
196+
)
197+
198+
2 -> pickLocalFileAndStream { viewModel.loadSource(it) }
225199
}
226200
},
227201
selected = index == selectedIndex,

‎typeahead-demo/src/commonMain/kotlin/app/smartcoding/typeahead_demo/SearchViewModel.kt‎

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import androidx.compose.runtime.setValue
2525
import androidx.compose.runtime.snapshotFlow
2626
import androidx.lifecycle.ViewModel
2727
import androidx.lifecycle.viewModelScope
28-
import io.github.karloti.typeahead.TypeaheadResult
2928
import io.github.karloti.typeahead.TypeaheadSearchEngine
3029
import kotlinx.collections.immutable.toImmutableList
3130
import kotlinx.coroutines.Dispatchers
@@ -56,10 +55,6 @@ class SearchViewModel(
5655
val results: StateFlow<List<Pair<Pair<String, String>, Float>>> =
5756
engine.storeResults ?: MutableStateFlow(emptyList())
5857

59-
// val storeResults: StateFlow<List<Pair<Pair<String, String>, Float>>>? = engine.storeResults
60-
// val results: StateFlow<List<TypeaheadResult>> = engine.results
61-
62-
6358
private var loadJob: Job? = null
6459

6560
init {

‎typeahead-demo/src/commonMain/kotlin/app/smartcoding/typeahead_demo/TypeaheadLoaderScreen.kt‎

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ suspend fun Flow<String>.parse(
3535

3636
typeaheadSearchEngine.addAll(this@parse) { line ->
3737
if (line.isNotBlank()) {
38-
val idStr = line.takeWhile { !it.isWhitespace() }
38+
val idStr = line.takeWhile { !it.isWhitespace() && it != ',' }
3939
if (idStr.isNotEmpty()) {
4040
val title = line.drop(idStr.length + 1).trim()
4141
loadedLinesCount.incrementAndFetch().let {
@@ -46,22 +46,6 @@ suspend fun Flow<String>.parse(
4646
} else "" to ""
4747
}
4848
isFinished()
49-
50-
51-
/*
52-
collect { line ->
53-
if (line.isNotBlank()) {
54-
val idStr = line.takeWhile { it.isDigit() }
55-
if (idStr.isNotEmpty()) {
56-
val title = line.drop(idStr.length + 1).trim()
57-
typeaheadSearchEngine.add(idStr.toInt() to title)
58-
loadedLinesCount++
59-
if (loadedLinesCount % 1000 == 0) loadedLinesCount(loadedLinesCount)
60-
}
61-
}
62-
}
63-
*/
64-
6549
loadedLinesCount(loadedLinesCount.load())
6650
isFinished()
6751
}

0 commit comments

Comments
 (0)