11package cz.frantisekmasa.wfrp_master.common.encounters
22
3- import androidx.compose.foundation.Image
43import androidx.compose.foundation.background
54import androidx.compose.foundation.clickable
5+ import androidx.compose.foundation.layout.Arrangement
66import androidx.compose.foundation.layout.Column
77import androidx.compose.foundation.layout.Row
88import androidx.compose.foundation.layout.fillMaxHeight
99import androidx.compose.foundation.layout.fillMaxSize
1010import androidx.compose.foundation.layout.fillMaxWidth
11- import androidx.compose.foundation.layout.padding
12- import androidx.compose.foundation.layout.size
11+ import androidx.compose.foundation.layout.height
12+ import androidx.compose.foundation.lazy.LazyColumn
13+ import androidx.compose.foundation.lazy.items
1314import androidx.compose.foundation.rememberScrollState
1415import androidx.compose.foundation.verticalScroll
15- import androidx.compose.material.Card
16+ import androidx.compose.material.Divider
1617import androidx.compose.material.FloatingActionButton
1718import androidx.compose.material.Icon
19+ import androidx.compose.material.ListItem
1820import androidx.compose.material.MaterialTheme
1921import androidx.compose.material.Scaffold
22+ import androidx.compose.material.Surface
2023import androidx.compose.material.Text
2124import androidx.compose.material.TopAppBar
2225import androidx.compose.material.icons.Icons
2326import androidx.compose.material.icons.rounded.Add
27+ import androidx.compose.material.icons.rounded.Done
28+ import androidx.compose.material.icons.rounded.DragIndicator
2429import androidx.compose.runtime.Composable
2530import androidx.compose.runtime.getValue
2631import androidx.compose.runtime.mutableStateOf
32+ import androidx.compose.runtime.remember
2733import androidx.compose.runtime.saveable.rememberSaveable
2834import androidx.compose.runtime.setValue
29- import androidx.compose.ui.Alignment
3035import androidx.compose.ui.Modifier
31- import androidx.compose.ui.graphics.ColorFilter
32- import androidx.compose.ui.text.style.TextAlign
36+ import androidx.compose.ui.graphics.Color
3337import androidx.compose.ui.unit.dp
3438import cafe.adriel.voyager.core.screen.Screen
3539import cafe.adriel.voyager.navigator.LocalNavigator
3640import cafe.adriel.voyager.navigator.currentOrThrow
3741import cz.frantisekmasa.wfrp_master.common.core.domain.identifiers.EncounterId
3842import cz.frantisekmasa.wfrp_master.common.core.domain.party.PartyId
3943import cz.frantisekmasa.wfrp_master.common.core.shared.Resources
40- import cz.frantisekmasa.wfrp_master.common.core.shared.drawableResource
4144import cz.frantisekmasa.wfrp_master.common.core.ui.buttons.HamburgerButton
4245import cz.frantisekmasa.wfrp_master.common.core.ui.flow.collectWithLifecycle
46+ import cz.frantisekmasa.wfrp_master.common.core.ui.forms.CheckboxWithText
4347import cz.frantisekmasa.wfrp_master.common.core.ui.primitives.DraggableListFor
4448import cz.frantisekmasa.wfrp_master.common.core.ui.primitives.EmptyUI
4549import cz.frantisekmasa.wfrp_master.common.core.ui.primitives.FullScreenProgress
46- import cz.frantisekmasa.wfrp_master.common.core.ui.primitives.Spacing
50+ import cz.frantisekmasa.wfrp_master.common.core.ui.primitives.ItemIcon
4751import cz.frantisekmasa.wfrp_master.common.core.ui.primitives.VisualOnlyIconDescription
4852import cz.frantisekmasa.wfrp_master.common.core.ui.primitives.rememberScreenModel
53+ import cz.frantisekmasa.wfrp_master.common.core.ui.scaffolding.FilterBar
4954import cz.frantisekmasa.wfrp_master.common.encounters.domain.Encounter
5055import cz.frantisekmasa.wfrp_master.common.localization.LocalStrings
5156
@@ -56,7 +61,14 @@ class EncountersScreen(
5661 @Composable
5762 override fun Content () {
5863 val screenModel: EncountersScreenModel = rememberScreenModel(arg = partyId)
59- val encounters = screenModel.encounters.collectWithLifecycle(null ).value
64+
65+ var showCompleted by rememberSaveable { mutableStateOf(false ) }
66+
67+ val encounters = (
68+ if (showCompleted)
69+ screenModel.allEncounters
70+ else screenModel.notCompletedEncounters
71+ ).collectWithLifecycle(null ).value
6072
6173 if (encounters == null ) {
6274 FullScreenProgress ()
@@ -89,11 +101,33 @@ class EncountersScreen(
89101
90102 val navigator = LocalNavigator .currentOrThrow
91103
92- EncounterList (
93- encounters,
94- screenModel,
95- onClick = { navigator.push(EncounterDetailScreen (EncounterId (partyId, it.id))) },
96- )
104+ Column {
105+ FilterBar {
106+ Row (
107+ modifier = Modifier .fillMaxWidth(),
108+ horizontalArrangement = Arrangement .Center ,
109+ ) {
110+ CheckboxWithText (
111+ checked = showCompleted,
112+ text = LocalStrings .current.encounters.buttonShowCompleted,
113+ onCheckedChange = { showCompleted = ! showCompleted },
114+ )
115+ }
116+ }
117+
118+ val onClick: (Encounter ) -> Unit = {
119+ navigator.push(EncounterDetailScreen (EncounterId (partyId, it.id)))
120+ }
121+ if (showCompleted) {
122+ AllEncountersList (encounters, onClick)
123+ } else {
124+ ActiveEncounterList (
125+ encounters,
126+ screenModel,
127+ onClick = onClick,
128+ )
129+ }
130+ }
97131 }
98132 }
99133}
@@ -106,10 +140,63 @@ private fun AddEncounterButton(onCreateEncounterRequest: () -> Unit) {
106140}
107141
108142@Composable
109- private fun EncounterList (
143+ private fun AllEncountersList (encounters : List <Encounter >, onClick : (Encounter ) -> Unit ) {
144+ LazyColumn {
145+ items(encounters) { encounter ->
146+ EncounterItem (
147+ encounter,
148+ onClick,
149+ draggable = false ,
150+ )
151+ }
152+ }
153+ }
154+
155+ @Composable
156+ fun EncounterItem (
157+ encounter : Encounter ,
158+ onClick : (Encounter ) -> Unit ,
159+ draggable : Boolean ,
160+ ) {
161+ Column {
162+ ListItem (
163+ modifier = Modifier .clickable { onClick(encounter) },
164+ icon = {
165+ if (draggable) {
166+ Icon (
167+ Icons .Rounded .DragIndicator ,
168+ VisualOnlyIconDescription ,
169+ modifier = Modifier .height(
170+ with (ItemIcon .Size .Small ) { dimensions + padding * 2 }
171+ )
172+ )
173+ }
174+ },
175+ text = {
176+ Text (encounter.name)
177+ },
178+ secondaryText = {
179+ val npcCount = remember(encounter.characters) { encounter.characters.values.sum() }
180+ Text (" $npcCount ${LocalStrings .current.npcs.titlePlural} " )
181+ },
182+ trailing = {
183+ if (encounter.completed) {
184+ Icon (
185+ Icons .Rounded .Done ,
186+ contentDescription = LocalStrings .current.encounters.labelCompleted,
187+ )
188+ }
189+ }
190+ )
191+ Divider ()
192+ }
193+ }
194+
195+ @Composable
196+ private fun ActiveEncounterList (
110197 encounters : List <Encounter >,
111198 screenModel : EncountersScreenModel ,
112- onClick : (Encounter ) -> Unit
199+ onClick : (Encounter ) -> Unit ,
113200) {
114201 if (encounters.isEmpty()) {
115202 val strings = LocalStrings .current.encounters
@@ -122,50 +209,32 @@ private fun EncounterList(
122209 return
123210 }
124211
125- val icon = drawableResource(Resources .Drawable .Encounter )
126- val iconSize = 28 .dp
127-
128212 Column (
129213 Modifier
130214 .background(MaterialTheme .colors.background)
131215 .fillMaxSize()
132- .verticalScroll(rememberScrollState())
133- .padding(Spacing .bodyPaddingWithFab),
134- horizontalAlignment = Alignment .CenterHorizontally ,
216+ .verticalScroll(rememberScrollState()),
135217 ) {
136218 DraggableListFor (
137219 encounters,
138220 modifier = Modifier .fillMaxHeight(),
139- itemSpacing = Spacing .small,
140221 onReorder = {
141222 screenModel.reorderEncounters(
142223 it.mapIndexed { index, encounter -> encounter.id to index }.toMap()
143224 )
144225 },
145226 ) { _, encounter, isDragged ->
146- Card (
147- elevation = if (isDragged) 6 .dp else 2 .dp,
148- modifier = Modifier
149- .fillMaxWidth()
150- .clickable { onClick(encounter) }
227+ Surface (
228+ color = if (isDragged)
229+ MaterialTheme .colors.surface
230+ else Color . Transparent ,
231+ elevation = if (isDragged) 1 .dp else 0 .dp,
151232 ) {
152- Row (
153- Modifier .padding(12 .dp),
154- verticalAlignment = Alignment .CenterVertically
155- ) {
156- Image (
157- icon,
158- VisualOnlyIconDescription ,
159- Modifier .size(iconSize),
160- colorFilter = ColorFilter .tint(MaterialTheme .colors.onSurface)
161- )
162- Text (
163- encounter.name,
164- modifier = Modifier .padding(start = 8 .dp),
165- textAlign = TextAlign .Center ,
166- style = MaterialTheme .typography.body1
167- )
168- }
233+ EncounterItem (
234+ encounter,
235+ onClick = onClick,
236+ draggable = true ,
237+ )
169238 }
170239 }
171240 }
0 commit comments