Skip to content

Commit 34018e0

Browse files
committed
feat(search): refine search logic and improve UI/UX
This commit optimizes the GitHub repository search query construction and enhances the search interface with better navigation and clear actions. - **feat(search)**: Added `OnClearClick` action to allow users to quickly clear the search query. - **refactor(search)**: Simplified `buildSearchQuery` in `SearchRepositoryImpl` by removing `platformHints`, relying on general metadata instead of specific repository topics for platform filtering. - **fix(search)**: Updated `SearchViewModel` to accurately reflect the local repository count in the `totalCount` state. - **ui(search)**: Replaced the back navigation button with a clear icon inside the search `TextField`. - **ui(search)**: Replaced the standard `Button` with `GithubStoreButton` for the search retry action. - **ui(search)**: Adjusted spacing, padding, and layout constraints in `SearchRoot` for a more consistent visual experience. - **chore**: Updated `LazyRow` items to use `SearchPlatform.entries` directly and added necessary experimental annotations.
1 parent 64be347 commit 34018e0

4 files changed

Lines changed: 43 additions & 37 deletions

File tree

feature/search/data/src/commonMain/kotlin/zed/rainxch/search/data/repository/SearchRepositoryImpl.kt

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ class SearchRepositoryImpl(
7474
return@channelFlow
7575
}
7676

77-
val searchQuery = buildSearchQuery(query, searchPlatform, language)
77+
val searchQuery = buildSearchQuery(query, language)
7878
val (sort, order) = sortBy.toGithubParams()
7979

8080
try {
@@ -195,7 +195,6 @@ class SearchRepositoryImpl(
195195

196196
private fun buildSearchQuery(
197197
userQuery: String,
198-
searchPlatform: SearchPlatform,
199198
language: ProgrammingLanguage
200199
): String {
201200
val clean = userQuery.trim()
@@ -207,21 +206,13 @@ class SearchRepositoryImpl(
207206
val scope = " in:name,description"
208207
val common = " archived:false fork:true"
209208

210-
val platformHints = when (searchPlatform) {
211-
SearchPlatform.All -> ""
212-
SearchPlatform.Android -> " topic:android"
213-
SearchPlatform.Windows -> " topic:windows"
214-
SearchPlatform.Macos -> " topic:macos"
215-
SearchPlatform.Linux -> " topic:linux"
216-
}
217-
218209
val languageFilter = if (language != ProgrammingLanguage.All && language.queryValue != null) {
219210
" language:${language.queryValue}"
220211
} else {
221212
""
222213
}
223214

224-
return ("$q$scope$common" + platformHints + languageFilter).trim()
215+
return ("$q$scope$common" + languageFilter).trim()
225216
}
226217

227218
private fun assetMatchesPlatform(nameRaw: String, platform: SearchPlatform): Boolean {

feature/search/presentation/src/commonMain/kotlin/zed/rainxch/search/presentation/SearchAction.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ sealed interface SearchAction {
1515
data object OnSearchImeClick : SearchAction
1616
data object OnNavigateBackClick : SearchAction
1717
data object LoadMore : SearchAction
18+
data object OnClearClick : SearchAction
1819
data object Retry : SearchAction
1920
data object OnToggleLanguageSheetVisibility : SearchAction
2021
}

feature/search/presentation/src/commonMain/kotlin/zed/rainxch/search/presentation/SearchRoot.kt

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package zed.rainxch.search.presentation
22

3+
import androidx.compose.foundation.ExperimentalFoundationApi
34
import androidx.compose.foundation.layout.Arrangement
45
import androidx.compose.foundation.layout.Box
56
import androidx.compose.foundation.layout.Column
@@ -23,11 +24,10 @@ import androidx.compose.foundation.shape.CircleShape
2324
import androidx.compose.foundation.text.KeyboardActions
2425
import androidx.compose.foundation.text.KeyboardOptions
2526
import androidx.compose.material.icons.Icons
26-
import androidx.compose.material.icons.automirrored.filled.ArrowBack
27+
import androidx.compose.material.icons.filled.Clear
2728
import androidx.compose.material.icons.filled.Close
2829
import androidx.compose.material.icons.filled.Search
2930
import androidx.compose.material.icons.outlined.KeyboardArrowDown
30-
import androidx.compose.material3.Button
3131
import androidx.compose.material3.CircularProgressIndicator
3232
import androidx.compose.material3.CircularWavyProgressIndicator
3333
import androidx.compose.material3.ExperimentalMaterial3Api
@@ -48,6 +48,7 @@ import androidx.compose.runtime.remember
4848
import androidx.compose.runtime.rememberUpdatedState
4949
import androidx.compose.ui.Alignment
5050
import androidx.compose.ui.Modifier
51+
import androidx.compose.ui.draw.clip
5152
import androidx.compose.ui.focus.FocusRequester
5253
import androidx.compose.ui.focus.focusRequester
5354
import androidx.compose.ui.graphics.Color
@@ -64,6 +65,7 @@ import org.jetbrains.compose.resources.stringResource
6465
import org.jetbrains.compose.ui.tooling.preview.Preview
6566
import org.koin.compose.viewmodel.koinViewModel
6667
import zed.rainxch.core.domain.model.GithubRepoSummary
68+
import zed.rainxch.core.presentation.components.GithubStoreButton
6769
import zed.rainxch.core.presentation.components.RepositoryCard
6870
import zed.rainxch.core.presentation.locals.LocalBottomNavigationLiquid
6971
import zed.rainxch.core.presentation.theme.GithubStoreTheme
@@ -204,14 +206,14 @@ fun SearchScreen(
204206
modifier = Modifier
205207
.fillMaxSize()
206208
.padding(innerPadding)
207-
.padding(horizontal = 8.dp)
209+
.padding(horizontal = 16.dp)
208210
) {
209211
LazyRow(
210212
modifier = Modifier.fillMaxWidth(),
211213
horizontalArrangement = Arrangement.spacedBy(8.dp),
212214
verticalAlignment = Alignment.CenterVertically
213215
) {
214-
items(SearchPlatform.entries.toList()) { sortBy ->
216+
items(SearchPlatform.entries) { sortBy ->
215217
FilterChip(
216218
selected = state.selectedSearchPlatform == sortBy,
217219
label = {
@@ -229,11 +231,9 @@ fun SearchScreen(
229231
}
230232
}
231233

232-
Spacer(Modifier.height(4.dp))
233-
234234
Row(
235235
modifier = Modifier.fillMaxWidth(),
236-
horizontalArrangement = Arrangement.spacedBy(8.dp),
236+
horizontalArrangement = Arrangement.spacedBy(6.dp),
237237
verticalAlignment = Alignment.CenterVertically
238238
) {
239239
Text(
@@ -284,7 +284,7 @@ fun SearchScreen(
284284
}
285285
}
286286

287-
Spacer(Modifier.height(12.dp))
287+
Spacer(Modifier.height(6.dp))
288288

289289
if (state.totalCount != null) {
290290
Text(
@@ -296,7 +296,7 @@ fun SearchScreen(
296296
color = MaterialTheme.colorScheme.outline,
297297
modifier = Modifier
298298
.fillMaxWidth()
299-
.padding(bottom = 8.dp)
299+
.padding(bottom = 6.dp)
300300
)
301301
}
302302

@@ -322,11 +322,12 @@ fun SearchScreen(
322322

323323
Spacer(Modifier.height(8.dp))
324324

325-
Button(onClick = { onAction(SearchAction.Retry) }) {
326-
Text(
327-
text = stringResource(Res.string.retry)
328-
)
329-
}
325+
GithubStoreButton(
326+
text = stringResource(Res.string.retry),
327+
onClick = {
328+
onAction(SearchAction.Retry)
329+
}
330+
)
330331
}
331332
}
332333
}
@@ -381,7 +382,7 @@ fun SearchScreen(
381382
}
382383
}
383384

384-
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
385+
@OptIn(ExperimentalMaterial3ExpressiveApi::class, ExperimentalFoundationApi::class)
385386
@Composable
386387
private fun SearchTopbar(
387388
onAction: (SearchAction) -> Unit,
@@ -396,16 +397,6 @@ private fun SearchTopbar(
396397
verticalAlignment = Alignment.CenterVertically,
397398
horizontalArrangement = Arrangement.spacedBy(8.dp)
398399
) {
399-
IconButton(
400-
onClick = { onAction(SearchAction.OnNavigateBackClick) }
401-
) {
402-
Icon(
403-
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
404-
contentDescription = stringResource(Res.string.navigate_back),
405-
modifier = Modifier.size(24.dp)
406-
)
407-
}
408-
409400
TextField(
410401
value = state.query,
411402
onValueChange = { value ->
@@ -418,6 +409,21 @@ private fun SearchTopbar(
418409
modifier = Modifier.size(20.dp)
419410
)
420411
},
412+
trailingIcon = {
413+
IconButton(
414+
onClick = {
415+
onAction(SearchAction.OnClearClick)
416+
},
417+
modifier = Modifier
418+
.size(20.dp)
419+
.clip(CircleShape)
420+
) {
421+
Icon(
422+
imageVector = Icons.Default.Clear,
423+
contentDescription = null
424+
)
425+
}
426+
},
421427
placeholder = {
422428
Text(
423429
text = stringResource(Res.string.search_repositories_hint),

feature/search/presentation/src/commonMain/kotlin/zed/rainxch/search/presentation/SearchViewModel.kt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ class SearchViewModel(
226226
currentState.copy(
227227
repositories = allRepos,
228228
hasMorePages = paginatedRepos.hasMore,
229-
totalCount = paginatedRepos.totalCount ?: currentState.totalCount,
229+
totalCount = _state.value.repositories.size,
230230
errorMessage = if (allRepos.isEmpty() && !paginatedRepos.hasMore) {
231231
getString(Res.string.no_repositories_found)
232232
} else null
@@ -359,6 +359,14 @@ class SearchViewModel(
359359
performSearch(isInitial = true)
360360
}
361361

362+
SearchAction.OnClearClick -> {
363+
_state.update {
364+
it.copy(
365+
query = ""
366+
)
367+
}
368+
}
369+
362370
is SearchAction.OnRepositoryClick -> {
363371
/* Handled in composable */
364372
}

0 commit comments

Comments
 (0)