Skip to content

Commit

Permalink
Add star button to save trip on TimeTableScreen
Browse files Browse the repository at this point in the history
  • Loading branch information
ksharma-xyz committed Oct 31, 2024
1 parent 0680fb1 commit 8cbc12e
Show file tree
Hide file tree
Showing 10 changed files with 127 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ private fun PreviewFab() {
onClick = {},
) {
Image(
painter = painterResource(R.drawable.star),
painter = painterResource(R.drawable.star_outline),
contentDescription = null,
colorFilter = ColorFilter.tint(color = LocalContentColor.current),
modifier = Modifier.size(32.dp),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ private fun RoundIconButtonPreview() {
KrailTheme {
RoundIconButton(onClick = {}) {
Image(
imageVector = ImageVector.vectorResource(R.drawable.star),
imageVector = ImageVector.vectorResource(R.drawable.star_outline),
contentDescription = null,
colorFilter = ColorFilter.tint(LocalOnContentColor.current),
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,35 +1,57 @@
package xyz.ksharma.krail.design.system.components

import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import xyz.ksharma.krail.design.system.LocalContentColor
import xyz.ksharma.krail.design.system.LocalTextColor
import xyz.ksharma.krail.design.system.LocalTextStyle
import xyz.ksharma.krail.design.system.R
import xyz.ksharma.krail.design.system.preview.PreviewComponent
import xyz.ksharma.krail.design.system.theme.KrailTheme

@Composable
fun TitleBar(
title: @Composable () -> Unit,
modifier: Modifier = Modifier,
actions: @Composable (() -> Unit)? = null,
) {
Row(
modifier = modifier
.statusBarsPadding()
.fillMaxWidth()
.padding(vertical = 16.dp, horizontal = 16.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
) {
CompositionLocalProvider(
LocalTextColor provides KrailTheme.colors.onBackground,
LocalTextStyle provides KrailTheme.typography.headlineMedium,
) {
title()
Row(modifier = Modifier.weight(1f)) {
CompositionLocalProvider(
LocalTextColor provides KrailTheme.colors.onBackground,
LocalTextStyle provides KrailTheme.typography.headlineMedium,
) {
title()
}
}
actions?.let {
Row(modifier = Modifier.padding(start = 16.dp)) {
CompositionLocalProvider(
LocalContentColor provides KrailTheme.colors.onBackground,
) {
actions()
}
}
}
}
}
Expand All @@ -42,7 +64,28 @@ private fun TitleBarPreview() {
KrailTheme {
TitleBar(
title = {
Text(text = "Title")
Text(text = "Saved Trips Screen Title")
},
actions = {
Image(
painter = painterResource(id = R.drawable.star_outline),
contentDescription = null,
modifier = Modifier.size(24.dp),
colorFilter = ColorFilter.tint(LocalContentColor.current),
)
},
modifier = Modifier.background(color = KrailTheme.colors.background),
)
}
}

@PreviewComponent
@Composable
private fun TitleBarPreviewNoActions() {
KrailTheme {
TitleBar(
title = {
Text(text = "Saved Trips Screen Title")
},
modifier = Modifier.background(color = KrailTheme.colors.background),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFF"
android:fillColor="#FFFFFFFF"
android:pathData="M12,17.77L18.18,21.5L16.54,14.47L22,9.74L14.81,9.13L12,2.5L9.19,9.13L2,9.74L7.46,14.47L5.82,21.5L12,17.77Z" />
</vector>
10 changes: 10 additions & 0 deletions core/design-system/src/main/res/drawable/star_outline.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:strokeColor="#FFFFFFFF"
android:strokeWidth="1"
android:pathData="M12,17.77L18.18,21.5L16.54,14.47L22,9.74L14.81,9.13L12,2.5L9.19,9.13L2,9.74L7.46,14.47L5.82,21.5L12,17.77Z" />
</vector>
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ fun SavedTripCard(
contentAlignment = Alignment.Center,
) {
Image(
imageVector = ImageVector.vectorResource(DSR.drawable.star),
imageVector = ImageVector.vectorResource(DSR.drawable.star_filled),
contentDescription = "Save Trip",
colorFilter = ColorFilter.tint(
primaryTransportMode?.colorCode
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,15 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
Expand Down Expand Up @@ -94,15 +91,7 @@ fun SavedTripsScreen(
}

SearchStopRow(
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(
bottom = with(LocalDensity.current) {
WindowInsets.navigationBars
.getBottom(this)
.toDp()
},
),
modifier = Modifier.align(Alignment.BottomCenter),
fromStopItem = fromStopItem,
toStopItem = toStopItem,
fromButtonClick = fromButtonClick,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ object StopResultMapper {
selectedModes: Set<TransportMode> = TransportMode.values(),
): List<SearchStopState.StopResult> {
return locations.orEmpty().mapNotNull { location ->
val stopName = location.name ?: return@mapNotNull null // Skip if stop name is null
val stopName = location.disassembledName ?: return@mapNotNull null // Skip if stop name is null
val stopId = location.id ?: return@mapNotNull null // Skip if stop ID is null
val modes = location.productClasses.orEmpty()
.mapNotNull { productClass -> TransportMode.toTransportModeType(productClass) }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
package xyz.ksharma.krail.trip.planner.ui.timetable

import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
import xyz.ksharma.krail.design.system.LocalOnContentColor
import xyz.ksharma.krail.design.system.components.RoundIconButton
import xyz.ksharma.krail.design.system.components.Text
import xyz.ksharma.krail.design.system.components.TitleBar
import xyz.ksharma.krail.design.system.theme.KrailTheme
Expand All @@ -28,6 +34,7 @@ import xyz.ksharma.krail.trip.planner.ui.components.JourneyCardState
import xyz.ksharma.krail.trip.planner.ui.state.TransportModeLine
import xyz.ksharma.krail.trip.planner.ui.state.timetable.TimeTableState
import xyz.ksharma.krail.trip.planner.ui.state.timetable.TimeTableUiEvent
import xyz.ksharma.krail.design.system.R as DesignSystemR

@Composable
fun TimeTableScreen(
Expand All @@ -41,13 +48,38 @@ fun TimeTableScreen(
.fillMaxSize()
.background(color = KrailTheme.colors.background),
) {
TitleBar(title = {
Text(text = stringResource(R.string.time_table_screen_title))
})
TitleBar(
title = {
Text(text = stringResource(R.string.time_table_screen_title))
},
actions = {
RoundIconButton(
onClick = { onEvent(TimeTableUiEvent.SaveTripButtonClicked) },
) {
Image(
imageVector = ImageVector.vectorResource(
if (timeTableState.isTripSaved) {
DesignSystemR.drawable.star_filled
} else {
DesignSystemR.drawable.star_outline
},
),
contentDescription = null,
colorFilter = ColorFilter.tint(LocalOnContentColor.current),
)
}
},
)

timeTableState.trip?.let { trip ->

Column(modifier = Modifier.padding(horizontal = 16.dp)) {
Column(
modifier = Modifier
.padding(horizontal = 16.dp)
.padding(bottom = 20.dp)
.clip(
RoundedCornerShape(bottomStart = 16.dp, bottomEnd = 16.dp),
),
) {
Text(
text = trip.fromStopName,
style = KrailTheme.typography.titleMedium.copy(fontWeight = FontWeight.Normal),
Expand All @@ -66,18 +98,6 @@ fun TimeTableScreen(
Text("Loading...", modifier = Modifier.padding(horizontal = 16.dp))
}
} else if (timeTableState.journeyList.isNotEmpty()) {
item {
Text(
text = if (timeTableState.isTripSaved) "Trip Saved" else "Save Trip Button",
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 16.dp)
.clickable(
enabled = !timeTableState.isTripSaved,
) { onEvent(TimeTableUiEvent.SaveTripButtonClicked) },
)
}

items(timeTableState.journeyList) { journey ->
JourneyCardItem(
timeToDeparture = journey.timeText,
Expand Down Expand Up @@ -143,7 +163,8 @@ fun JourneyCardItem(
platformNumber = departureLocationNumber,
isWheelchairAccessible = false,
cardState = cardState,
transportModeList = transportModeLineList.map { it.transportMode }.toImmutableList(),
transportModeList = transportModeLineList.map { it.transportMode }
.toImmutableList(),
legList = legList,
onClick = onClick,
modifier = modifier,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
Expand All @@ -16,6 +17,8 @@ import kotlinx.coroutines.launch
import timber.log.Timber
import xyz.ksharma.krail.core.datetime.DateTimeHelper.calculateTimeDifferenceFromNow
import xyz.ksharma.krail.core.datetime.DateTimeHelper.toGenericFormattedTimeString
import xyz.ksharma.krail.di.AppDispatchers
import xyz.ksharma.krail.di.Dispatcher
import xyz.ksharma.krail.sandook.Sandook
import xyz.ksharma.krail.sandook.di.SandookFactory
import xyz.ksharma.krail.trip.planner.network.api.repository.TripPlanningRepository
Expand All @@ -31,6 +34,7 @@ import kotlin.time.Duration.Companion.seconds
class TimeTableViewModel @Inject constructor(
private val tripRepository: TripPlanningRepository,
sandookFactory: SandookFactory,
@Dispatcher(AppDispatchers.IO) private val ioDispatcher: CoroutineDispatcher,
) : ViewModel() {

private val sandook: Sandook = sandookFactory.create(SandookFactory.SandookKey.SAVED_TRIP)
Expand Down Expand Up @@ -69,13 +73,22 @@ class TimeTableViewModel @Inject constructor(

private fun onSaveTripButtonClicked() {
Timber.d("Save Trip Button Clicked")
tripInfo?.let { trip ->
Timber.d("Save Trip: $trip")
sandook.putString(key = trip.tripId, value = trip.toJsonString())
sandook.getString(key = trip.tripId)?.let { savedTrip ->
Timber.d("Saved Trip (Pref): ${Trip.fromJsonString(savedTrip)}")
viewModelScope.launch(ioDispatcher) {
tripInfo?.let { trip ->
Timber.d("Toggle Save Trip: $trip")
val savedTrip = sandook.getString(key = trip.tripId)
if (savedTrip != null) {
// Trip is already saved, so delete it
sandook.remove(key = trip.tripId)
Timber.d("Deleted Trip (Pref): ${Trip.fromJsonString(savedTrip)}")
updateUiState { copy(isTripSaved = false) }
} else {
// Trip is not saved, so save it
sandook.putString(key = trip.tripId, value = trip.toJsonString())
Timber.d("Saved Trip (Pref): $trip")
updateUiState { copy(isTripSaved = true) }
}
}
updateUiState { copy(isTripSaved = true) }
}
}

Expand All @@ -87,7 +100,8 @@ class TimeTableViewModel @Inject constructor(
private fun onLoadTimeTable(tripInfo: Trip) = with(tripInfo) {
Timber.d("loadTimeTable API Call- fromStopItem: $fromStopId, toStopItem: $toStopId")
this@TimeTableViewModel.tripInfo = this
updateUiState { copy(isLoading = true, trip = tripInfo) }
val savedTrip = sandook.getString(key = tripInfo.tripId)
updateUiState { copy(isLoading = true, trip = tripInfo, isTripSaved = savedTrip != null) }

viewModelScope.launch {
require(!(fromStopId.isEmpty() || toStopId.isEmpty())) { "Invalid Stop Ids" }
Expand Down

0 comments on commit 8cbc12e

Please sign in to comment.