11package com.cornellappdev.uplift.ui.screens.profile
22
3+ import androidx.compose.animation.AnimatedContent
34import androidx.compose.foundation.background
45import androidx.compose.foundation.border
56import androidx.compose.foundation.clickable
@@ -13,18 +14,22 @@ import androidx.compose.foundation.layout.fillMaxWidth
1314import androidx.compose.foundation.layout.height
1415import androidx.compose.foundation.layout.padding
1516import androidx.compose.foundation.layout.size
17+ import androidx.compose.foundation.layout.statusBarsPadding
1618import androidx.compose.foundation.layout.width
1719import androidx.compose.foundation.lazy.LazyColumn
1820import androidx.compose.foundation.lazy.grid.GridCells
1921import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
22+ import androidx.compose.foundation.lazy.items
2023import androidx.compose.foundation.lazy.itemsIndexed
2124import androidx.compose.foundation.shape.CircleShape
2225import androidx.compose.material3.HorizontalDivider
2326import androidx.compose.material3.Icon
27+ import androidx.compose.material3.IconButton
2428import androidx.compose.material3.Text
2529import androidx.compose.runtime.Composable
2630import androidx.compose.runtime.collectAsState
2731import androidx.compose.runtime.getValue
32+ import androidx.compose.runtime.mutableIntStateOf
2833import androidx.compose.runtime.mutableStateOf
2934import androidx.compose.runtime.remember
3035import androidx.compose.runtime.setValue
@@ -63,7 +68,7 @@ fun WorkoutHistoryScreen(
6368 viewModel : ProfileViewModel = hiltViewModel(),
6469 onBack : () -> Unit
6570) {
66- val uiState by viewModel.uiStateFlow.collectAsState ()
71+ val uiState = viewModel.collectUiStateValue ()
6772 WorkoutHistoryScreenContent (uiState = uiState, onBack = onBack)
6873}
6974
@@ -72,7 +77,7 @@ fun WorkoutHistoryScreenContent(
7277 uiState : ProfileUiState ,
7378 onBack : () -> Unit
7479) {
75- var selectedTab by remember { mutableStateOf (0 ) }
80+ var selectedTab by remember { mutableIntStateOf (0 ) }
7681
7782 Column (
7883 modifier = Modifier
@@ -92,9 +97,11 @@ fun WorkoutHistoryScreenContent(
9297 EmptyHistorySection ()
9398 }
9499 } else {
95- when (selectedTab) {
96- 0 -> WorkoutHistoryCalendarView (historyItems = uiState.historyItems)
97- 1 -> WorkoutHistoryListView (historyItems = uiState.historyItems)
100+ AnimatedContent (targetState = selectedTab, label = " historyTabContent" ) { tab ->
101+ when (tab) {
102+ 0 -> WorkoutHistoryCalendarView (historyItems = uiState.historyItems)
103+ 1 -> WorkoutHistoryListView (historyItems = uiState.historyItems)
104+ }
98105 }
99106 }
100107 }
@@ -106,18 +113,23 @@ private fun WorkoutHistoryHeader(onBack: () -> Unit) {
106113 modifier = Modifier
107114 .fillMaxWidth()
108115 .background(LIGHT_GRAY )
116+ .statusBarsPadding()
109117 .padding(horizontal = 16 .dp, vertical = 12 .dp),
110118 verticalAlignment = Alignment .CenterVertically ,
111119 horizontalArrangement = Arrangement .SpaceBetween
112120 ) {
113- Icon (
114- painter = painterResource(id = R .drawable.ic_back_arrow),
115- contentDescription = " Back" ,
116- modifier = Modifier
117- .size(24 .dp)
118- .clickable { onBack() },
119- tint = PRIMARY_BLACK
120- )
121+ IconButton (
122+ onClick = { onBack() },
123+ ) {
124+ Icon (
125+ painter = painterResource(id = R .drawable.ic_back_arrow),
126+ contentDescription = " Back" ,
127+ modifier = Modifier
128+ .size(24 .dp),
129+ tint = PRIMARY_BLACK
130+ )
131+ }
132+
121133 Text (
122134 text = " History" ,
123135 fontFamily = montserratFamily,
@@ -130,14 +142,42 @@ private fun WorkoutHistoryHeader(onBack: () -> Unit) {
130142 }
131143}
132144
145+ private sealed class HistoryListItem {
146+ data class Header (val month : String ) : HistoryListItem()
147+ data class Workout (
148+ val item : HistoryItem ,
149+ val showDivider : Boolean
150+ ) : HistoryListItem()
151+ data class SpacerItem (val month : String ) : HistoryListItem()
152+ }
153+
133154@Composable
134155private fun WorkoutHistoryListView (historyItems : List <HistoryItem >) {
135156 val groupedItems = remember(historyItems) {
136- historyItems.groupBy {
137- val date = Instant .ofEpochMilli(it.timestamp)
138- .atZone(ZoneId .systemDefault())
139- .toLocalDate()
140- date.format(DateTimeFormatter .ofPattern(" MMMM yyyy" , Locale .US ))
157+ historyItems
158+ .sortedByDescending { it.timestamp }
159+ .groupBy { historyItem ->
160+ Instant .ofEpochMilli(historyItem.timestamp)
161+ .atZone(ZoneId .systemDefault())
162+ .toLocalDate()
163+ .format(DateTimeFormatter .ofPattern(" MMMM yyyy" , Locale .US ))
164+ }
165+ }
166+
167+ val listItems = remember(groupedItems) {
168+ buildList {
169+ groupedItems.forEach { (month, items) ->
170+ add(HistoryListItem .Header (month))
171+ items.forEachIndexed { index, item ->
172+ add(
173+ HistoryListItem .Workout (
174+ item = item,
175+ showDivider = index < items.lastIndex
176+ )
177+ )
178+ }
179+ add(HistoryListItem .SpacerItem (month))
180+ }
141181 }
142182 }
143183
@@ -146,28 +186,46 @@ private fun WorkoutHistoryListView(historyItems: List<HistoryItem>) {
146186 .fillMaxSize()
147187 .padding(horizontal = 16 .dp),
148188 ) {
149- item { Spacer (modifier = Modifier .height(8 .dp)) }
189+ item(key = " top_spacer" ) {
190+ Spacer (modifier = Modifier .height(8 .dp))
191+ }
150192
151- groupedItems.forEach { (month, items) ->
152- item {
153- Text (
154- text = month,
155- fontFamily = montserratFamily,
156- fontSize = 12 .sp,
157- fontWeight = FontWeight .Bold ,
158- color = Color .Black ,
159- modifier = Modifier .padding(top = 8 .dp)
160- )
193+ items(
194+ items = listItems,
195+ key = { listItem ->
196+ when (listItem) {
197+ is HistoryListItem .Header -> " header_${listItem.month} "
198+ is HistoryListItem .Workout -> " workout_${listItem.item.timestamp} "
199+ is HistoryListItem .SpacerItem -> " spacer_${listItem.month} "
200+ }
161201 }
162- itemsIndexed(items) { index, item ->
163- HistoryItemRow (historyItem = item)
164- if (index < items.size - 1 ) {
165- HorizontalDivider (color = GRAY01 , thickness = 1 .dp)
202+ ) { listItem ->
203+ when (listItem) {
204+ is HistoryListItem .Header -> {
205+ Text (
206+ text = listItem.month,
207+ fontFamily = montserratFamily,
208+ fontSize = 12 .sp,
209+ fontWeight = FontWeight .Bold ,
210+ color = Color .Black ,
211+ modifier = Modifier .padding(top = 8 .dp)
212+ )
213+ }
214+
215+ is HistoryListItem .Workout -> {
216+ Column {
217+ HistoryItemRow (historyItem = listItem.item)
218+ if (listItem.showDivider) {
219+ HorizontalDivider (color = GRAY01 , thickness = 1 .dp)
220+ }
221+ }
222+ }
223+
224+ is HistoryListItem .SpacerItem -> {
225+ Spacer (modifier = Modifier .height(24 .dp))
166226 }
167227 }
168- item { Spacer (modifier = Modifier .height(24 .dp)) }
169228 }
170-
171229 }
172230}
173231
@@ -191,7 +249,10 @@ private fun WorkoutHistoryCalendarView(historyItems: List<HistoryItem>) {
191249 // Month Selector
192250 Row (
193251 modifier = Modifier .fillMaxWidth(),
194- horizontalArrangement = Arrangement .Center ,
252+ horizontalArrangement = Arrangement .spacedBy(
253+ 24 .dp,
254+ Alignment .CenterHorizontally
255+ ),
195256 verticalAlignment = Alignment .CenterVertically
196257 ) {
197258 Icon (
@@ -202,7 +263,6 @@ private fun WorkoutHistoryCalendarView(historyItems: List<HistoryItem>) {
202263 .clickable { currentMonth = currentMonth.minusMonths(1 ) },
203264 tint = PRIMARY_BLACK
204265 )
205- Spacer (modifier = Modifier .width(24 .dp))
206266 Text (
207267 text = currentMonth.format(DateTimeFormatter .ofPattern(" MMM yyyy" , Locale .US )),
208268 fontFamily = montserratFamily,
@@ -212,7 +272,6 @@ private fun WorkoutHistoryCalendarView(historyItems: List<HistoryItem>) {
212272 modifier = Modifier .width(100 .dp),
213273 textAlign = TextAlign .Center
214274 )
215- Spacer (modifier = Modifier .width(24 .dp))
216275 Icon (
217276 painter = painterResource(id = R .drawable.ic_advance_month),
218277 contentDescription = " Next Month" ,
0 commit comments