Skip to content

Commit

Permalink
feat(filter): adds filtering for set (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
kikin81 authored Dec 23, 2024
1 parent e747613 commit 0c4eca7
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 11 deletions.
10 changes: 10 additions & 0 deletions .idea/inspectionProfiles/Project_Default.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ dependencies {
implementation(libs.androidx.compose.google.fonts)
implementation(libs.androidx.compose.navigation)
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.material.icons)
implementation(libs.androidx.material3)
implementation(libs.androidx.ui)
implementation(libs.androidx.ui.graphics)
Expand Down
13 changes: 11 additions & 2 deletions app/src/main/java/us/kikin/android/ptp/cards/CardsFilterType.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@

package us.kikin.android.ptp.cards

enum class CardsFilterType {
ALL_CARDS,
import androidx.annotation.StringRes
import us.kikin.android.ptp.R

enum class CardsFilterType(
val setId: String,
@StringRes val titleResId: Int,
) {
All("All", R.string.card_list_filter_all),
GeneticApex("Genetic Apex (A1)", R.string.card_list_filter_genetic_apex),
PromoA("Promo-A", R.string.card_list_filter_promo_a),
MythicalIslands("Mythical Island (A1a)", R.string.card_list_filter_mythical_islands),
}
85 changes: 84 additions & 1 deletion app/src/main/java/us/kikin/android/ptp/cards/CardsScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,37 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.text.input.TextFieldLineLimits
import androidx.compose.foundation.text.input.rememberTextFieldState
import androidx.compose.foundation.text.input.setTextAndPlaceCursorAtEnd
import androidx.compose.material3.Card as MaterialCard
import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuAnchorType
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.nestedscroll.nestedScroll
Expand Down Expand Up @@ -78,6 +91,9 @@ fun CardsScreen(
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() },
) {
val scaffoldBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
val sheetState = rememberModalBottomSheetState()
val scope = rememberCoroutineScope()
var showBottomSheet by remember { mutableStateOf(false) }
AppTheme {
Scaffold(
modifier = modifier
Expand All @@ -94,7 +110,7 @@ fun CardsScreen(
)
},
actions = {
IconButton(onClick = { /*TODO*/ }) {
IconButton(onClick = { showBottomSheet = true }) {
Icon(
imageVector = PtpIcons.Rounded.FilterList,
contentDescription = stringResource(R.string.card_list_filters),
Expand Down Expand Up @@ -123,6 +139,20 @@ fun CardsScreen(
viewModel.snackbarMessageShown()
}
}

if (showBottomSheet) {
ModalBottomSheet(
onDismissRequest = {
showBottomSheet = false
},
sheetState = sheetState,
) {
FilterContent(
currentFilter = uiState.filter,
viewModel::setFiltering,
)
}
}
}
}
}
Expand All @@ -149,6 +179,59 @@ private fun CardsContent(
}
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun FilterContent(
currentFilter: CardsFilterType,
onFilterChange: (CardsFilterType) -> Unit,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 24.dp),
) {
// dropdown for set?
val options = CardsFilterType.entries
var expanded by remember { mutableStateOf(false) }
val textFieldState = rememberTextFieldState(currentFilter.name)
ExposedDropdownMenuBox(
expanded = expanded,
onExpandedChange = { expanded = it },
modifier = Modifier.fillMaxWidth(),
) {
TextField(
modifier = Modifier
.menuAnchor(ExposedDropdownMenuAnchorType.PrimaryNotEditable)
.fillMaxWidth(),
state = textFieldState,
readOnly = true,
lineLimits = TextFieldLineLimits.SingleLine,
label = {
Text("Set")
},
)
ExposedDropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false },
) {
options.forEach { option ->
val label = stringResource(option.titleResId)
DropdownMenuItem(
text = { Text(label, style = MaterialTheme.typography.bodyLarge) },
onClick = {
textFieldState.setTextAndPlaceCursorAtEnd(label)
expanded = false
onFilterChange(option)
},
contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding,
)
}
}
}
}
}

@Composable
private fun CardsList(
cards: ImmutableList<Card>,
Expand Down
27 changes: 22 additions & 5 deletions app/src/main/java/us/kikin/android/ptp/cards/CardsViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ package us.kikin.android.ptp.cards
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.navigation.toRoute
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
Expand All @@ -31,13 +30,13 @@ import kotlinx.coroutines.flow.stateIn
import us.kikin.android.ptp.R
import us.kikin.android.ptp.data.Card
import us.kikin.android.ptp.data.CardRepository
import us.kikin.android.ptp.navigation.CardListDestination
import us.kikin.android.ptp.util.Async
import us.kikin.android.ptp.util.WhileUiSubscribed

data class CardsUiState(
val cards: List<Card> = emptyList(),
val isLoading: Boolean = false,
val filter: CardsFilterType = CardsFilterType.All,
val userMessage: Int? = null,
)

Expand All @@ -49,7 +48,8 @@ constructor(
private val savedStateHandle: SavedStateHandle,
) : ViewModel() {
private val _savedFilterType =
MutableStateFlow(savedStateHandle.toRoute<CardListDestination>().filterType)
savedStateHandle.getStateFlow(CARDS_FILTER_SAVED_STATE_KEY, CardsFilterType.All)
private val _filterUiInfo = _savedFilterType
private val _isLoading = MutableStateFlow(false)
private val _userMessage: MutableStateFlow<Int?> = MutableStateFlow(null)
private val _filteredCardsAsync =
Expand All @@ -61,10 +61,11 @@ constructor(

val uiState: StateFlow<CardsUiState> =
combine(
_filterUiInfo,
_isLoading,
_userMessage,
_filteredCardsAsync,
) { isLoading, userMessage, cardsAsync ->
) { filterUiInfo, isLoading, userMessage, cardsAsync ->
when (cardsAsync) {
Async.Loading -> {
CardsUiState(isLoading = true)
Expand All @@ -77,6 +78,7 @@ constructor(
is Async.Success -> {
CardsUiState(
cards = cardsAsync.data,
filter = filterUiInfo,
isLoading = isLoading,
userMessage = userMessage,
)
Expand All @@ -91,11 +93,26 @@ constructor(

private fun filterCards(cards: List<Card>, type: CardsFilterType): List<Card> {
return when (type) {
CardsFilterType.ALL_CARDS -> cards
CardsFilterType.All -> cards
CardsFilterType.GeneticApex -> cards.filter {
it.setDetails == CardsFilterType.GeneticApex.setId
}
CardsFilterType.PromoA -> cards.filter {
it.setDetails == CardsFilterType.PromoA.setId
}
CardsFilterType.MythicalIslands -> cards.filter {
it.setDetails == CardsFilterType.MythicalIslands.setId
}
}
}

fun snackbarMessageShown() {
_userMessage.value = null
}

fun setFiltering(requestType: CardsFilterType) {
savedStateHandle[CARDS_FILTER_SAVED_STATE_KEY] = requestType
}
}

const val CARDS_FILTER_SAVED_STATE_KEY = "CARDS_FILTER_SAVED_STATE_KEY"
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import us.kikin.android.ptp.cards.CardsFilterType

@Serializable
data class CardListDestination(
val filterType: CardsFilterType = CardsFilterType.ALL_CARDS,
val filterType: CardsFilterType = CardsFilterType.All,
val userMessage: Int? = null,
)

Expand Down
4 changes: 4 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@
<string name="loading_card_detail_error">Error while loading card detail</string>
<string name="card_detail_not_found">Card not found</string>
<string name="card_list_filters">Filters</string>
<string name="card_list_filter_all">All</string>
<string name="card_list_filter_genetic_apex">Genetic Apex</string>
<string name="card_list_filter_promo_a">Promo-A</string>
<string name="card_list_filter_mythical_islands">Mythical Islands</string>
</resources>
6 changes: 4 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ junitVersion = "1.2.1"
kotlin = "2.1.0"
ksp = "2.1.0-1.0.29"
lifecycle = "2.8.7"
material3 = "1.4.0-alpha05"
paging = "3.3.5"
room = "2.6.1"
timber = "5.0.1"
Expand All @@ -26,7 +27,8 @@ androidx-compose-google-fonts = { group = "androidx.compose.ui", name = "ui-text
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
androidx-material3 = { group = "androidx.compose.material3", name = "material3", version.ref = "material3" }
androidx-material-icons = { group = "androidx.compose.material", name = "material-icons-core" }
androidx-ui = { group = "androidx.compose.ui", name = "ui" }
androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
Expand Down Expand Up @@ -58,7 +60,7 @@ room = ["room-runtime", "room-ktx", "room-paging"]

[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
dependency-sorter = { id = "com.squareup.sort-dependencies", version = "0.13"}
dependency-sorter = { id = "com.squareup.sort-dependencies", version = "0.13" }
hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
Expand Down

0 comments on commit 0c4eca7

Please sign in to comment.