feat: Add Jetpack Compose previews for UI components

This commit adds Jetpack Compose `@Preview` annotations to several UI components in the `ui:home` module. This allows developers to visualize these components in Android Studio without needing to run the full application.

Key changes:
- Added `@PreviewDevices` and `FlightsTheme` to `PassengersOptions.kt` and created a `PassengersOptionsPreview` composable function with sample data.
- Added `@PreviewDevices` and `FlightsTheme` to `DatePicker.kt` and created a `DatePickerPreview` composable function with sample data.
- Added `@PreviewDevices` and `FlightsTheme` to `SearchForm.kt` and created a `SearchFormPreview` composable function with sample airport and passenger data.
- Added `@PreviewDevices` and `FlightsTheme` to `AirportDropdown.kt` and created an `AirportDropdownPreview` composable function with sample airport data.
This commit is contained in:
2025-06-14 13:51:01 +02:00
parent 524a64a443
commit 5d9a56d71f
4 changed files with 226 additions and 0 deletions

View File

@ -15,6 +15,13 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import dev.adriankuta.flights.domain.types.AirportInfo import dev.adriankuta.flights.domain.types.AirportInfo
import dev.adriankuta.flights.domain.types.City
import dev.adriankuta.flights.domain.types.Coordinates
import dev.adriankuta.flights.domain.types.Country
import dev.adriankuta.flights.domain.types.MacCity
import dev.adriankuta.flights.domain.types.Region
import dev.adriankuta.flights.ui.designsystem.theme.FlightsTheme
import dev.adriankuta.flights.ui.designsystem.theme.PreviewDevices
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
@ -64,3 +71,75 @@ fun AirportDropdown(
} }
} }
} }
@OptIn(ExperimentalMaterial3Api::class)
@PreviewDevices
@Composable
@Suppress("LongMethod")
private fun AirportDropdownPreview() {
val sampleAirports = listOf(
AirportInfo(
code = "WAW",
name = "Warsaw Chopin",
seoName = "warsaw",
isBase = true,
timeZone = "Europe/Warsaw",
city = City(
code = "WAW",
name = "Warsaw",
),
macCity = MacCity(
macCode = "WAW",
),
region = Region(
code = "PL",
name = "Poland",
),
country = Country(
code = "PL",
name = "Poland",
currencyCode = "PLN",
),
coordinates = Coordinates(
latitude = 52.1657,
longitude = 20.9671,
),
),
AirportInfo(
code = "LHR",
name = "London Heathrow",
seoName = "london",
isBase = false,
timeZone = "Europe/London",
city = City(
code = "LON",
name = "London",
),
macCity = MacCity(
macCode = "LON",
),
region = Region(
code = "UK",
name = "United Kingdom",
),
country = Country(
code = "UK",
name = "United Kingdom",
currencyCode = "GBP",
),
coordinates = Coordinates(
latitude = 51.4700,
longitude = -0.4543,
),
),
)
FlightsTheme {
AirportDropdown(
label = "Departure Airport",
airports = sampleAirports,
selectedAirport = sampleAirports.first(),
onAirportSelect = {},
)
}
}

View File

@ -20,6 +20,8 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalFocusManager
import dev.adriankuta.flights.ui.designsystem.theme.FlightsTheme
import dev.adriankuta.flights.ui.designsystem.theme.PreviewDevices
import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
import java.time.Instant import java.time.Instant
@ -152,3 +154,19 @@ class FutureSelectableDates : SelectableDates {
return year >= now.year return year >= now.year
} }
} }
@OptIn(ExperimentalMaterial3Api::class)
@PreviewDevices
@Composable
private fun DatePickerPreview() {
val today = LocalDate.now()
val futureDate = today.plusDays(7) // A week from today
FlightsTheme {
DatePicker(
label = "Departure Date",
selectedDate = futureDate,
onDateSelect = {},
)
}
}

View File

@ -9,7 +9,10 @@ import androidx.compose.material3.VerticalDivider
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import dev.adriankuta.flights.ui.designsystem.theme.FlightsTheme
import dev.adriankuta.flights.ui.designsystem.theme.PreviewDevices
import dev.adriankuta.flights.ui.home.HomeUiState import dev.adriankuta.flights.ui.home.HomeUiState
import dev.adriankuta.flights.ui.home.PassengersState
import dev.adriankuta.flights.ui.sharedui.Counter import dev.adriankuta.flights.ui.sharedui.Counter
@Composable @Composable
@ -53,3 +56,31 @@ internal fun PassengersOptions(
) )
} }
} }
@PreviewDevices
@Composable
private fun PassengersOptionsPreview() {
val samplePassengersState = PassengersState(
adultCount = 2,
teenCount = 1,
childCount = 1,
)
val sampleUiState = HomeUiState.Success(
originAirports = emptyList(),
destinationAirports = emptyList(),
selectedOriginAirport = null,
selectedDestinationAirport = null,
selectedDate = java.time.LocalDate.now(),
passengers = samplePassengersState,
)
FlightsTheme {
PassengersOptions(
uiState = sampleUiState,
onAdultCountChange = {},
onTeenCountChange = {},
onChildCountChange = {},
)
}
}

View File

@ -10,7 +10,15 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import dev.adriankuta.flights.domain.types.AirportInfo import dev.adriankuta.flights.domain.types.AirportInfo
import dev.adriankuta.flights.domain.types.City
import dev.adriankuta.flights.domain.types.Coordinates
import dev.adriankuta.flights.domain.types.Country
import dev.adriankuta.flights.domain.types.MacCity
import dev.adriankuta.flights.domain.types.Region
import dev.adriankuta.flights.ui.designsystem.theme.FlightsTheme
import dev.adriankuta.flights.ui.designsystem.theme.PreviewDevices
import dev.adriankuta.flights.ui.home.HomeUiState import dev.adriankuta.flights.ui.home.HomeUiState
import dev.adriankuta.flights.ui.home.PassengersState
import java.time.LocalDate import java.time.LocalDate
@Composable @Composable
@ -74,3 +82,93 @@ internal fun SearchForm(
} }
} }
} }
@PreviewDevices
@Composable
@Suppress("LongMethod")
private fun SearchFormPreview() {
val sampleAirports = listOf(
AirportInfo(
code = "WAW",
name = "Warsaw Chopin",
seoName = "warsaw",
isBase = true,
timeZone = "Europe/Warsaw",
city = City(
code = "WAW",
name = "Warsaw",
),
macCity = MacCity(
macCode = "WAW",
),
region = Region(
code = "PL",
name = "Poland",
),
country = Country(
code = "PL",
name = "Poland",
currencyCode = "PLN",
),
coordinates = Coordinates(
latitude = 52.1657,
longitude = 20.9671,
),
),
AirportInfo(
code = "LHR",
name = "London Heathrow",
seoName = "london",
isBase = false,
timeZone = "Europe/London",
city = City(
code = "LON",
name = "London",
),
macCity = MacCity(
macCode = "LON",
),
region = Region(
code = "UK",
name = "United Kingdom",
),
country = Country(
code = "UK",
name = "United Kingdom",
currencyCode = "GBP",
),
coordinates = Coordinates(
latitude = 51.4700,
longitude = -0.4543,
),
),
)
val samplePassengersState = PassengersState(
adultCount = 2,
teenCount = 1,
childCount = 1,
)
val sampleUiState = HomeUiState.Success(
originAirports = sampleAirports,
destinationAirports = sampleAirports.drop(1),
selectedOriginAirport = sampleAirports.first(),
selectedDestinationAirport = sampleAirports.last(),
selectedDate = LocalDate.now().plusDays(7),
passengers = samplePassengersState,
)
FlightsTheme {
SearchForm(
uiState = sampleUiState,
onOriginAirportSelect = {},
onDestinationAirportSelect = {},
onDateSelect = {},
onAdultCountChange = {},
onTeenCountChange = {},
onChildCountChange = {},
onSearch = {},
)
}
}