feat: Implement airport connection fetching and filtering

This commit introduces the functionality to fetch available flight connections for a selected origin airport and filter the destination airport list accordingly.

Key changes:
- Added `GetConnectionsForAirportUseCase` interface in `domain/stations` to define the contract for fetching airport connections.
- Implemented `GetConnectionsForAirportUseCaseImpl` in `model/repository` to fetch routes from the `RoutesService` and map them to domain `Airport` types.
- Created `AirportDomainMapper.kt` in `model/repository/mappers` to map `RouteResponse` and its nested types to domain `Airport` and `MacCity` types.
- Added a Hilt module `GetConnectionsForAirportUseCaseModule` to provide the implementation for `GetConnectionsForAirportUseCase`.
- Renamed `OriginAirportsUiState` to `AirportsUiState` in `StationsScreen.kt` and `StationsScreenViewModel.kt` for better generality.
- Updated `StationsScreenViewModel`:
    - Injected `GetConnectionsForAirportUseCase`.
    - Added `_availableDestinationsCodes` StateFlow to hold the codes of airports reachable from the selected origin.
    - Modified `airportsUiState` (previously `originAirportsUiState`) to take `filterDestinations` as a parameter and filter airports based on both search query and available destination codes.
    - Added `AirportInfo.toDepartureAirPort()` extension function.
- Updated `StationsScreen.kt` to use the renamed `AirportsUiState`.
This commit is contained in:
2025-06-16 00:29:57 +02:00
parent 504f798bd3
commit e8ac7c5596
6 changed files with 129 additions and 29 deletions

View File

@ -0,0 +1,19 @@
package dev.adriankuta.flights.model.repository.di
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import dev.adriankuta.flights.domain.stations.GetConnectionsForAirportUseCase
import dev.adriankuta.flights.model.repository.usecases.GetConnectionsForAirportUseCaseImpl
@Module
@InstallIn(SingletonComponent::class)
@Suppress("UnnecessaryAbstractClass")
internal abstract class GetConnectionsForAirportUseCaseModule {
@Binds
abstract fun bind(
getConnectionsForAirportUseCaseImpl: GetConnectionsForAirportUseCaseImpl,
): GetConnectionsForAirportUseCase
}

View File

@ -0,0 +1,35 @@
package dev.adriankuta.flights.model.repository.mappers
import dev.adriankuta.flights.domain.types.Airport
import dev.adriankuta.flights.domain.types.MacCity
import dev.adriankuta.model.data.api.entities.RouteResponse
fun RouteResponse.Airport.MacCity.toDomain(): MacCity? {
val macCode = macCode ?: return null
return MacCity(macCode = macCode)
}
fun RouteResponse.toDomain(): List<Airport> {
val departureAirportDomain = departureAirport?.let {
Airport.Departure(
code = it.code ?: return@let null,
name = it.name ?: return@let null,
macCity = departureAirport?.macCity?.toDomain(),
)
}
val arrivalAirportDomain = arrivalAirport?.let {
Airport.Arrival(
code = it.code ?: return@let null,
name = it.name ?: return@let null,
macCity = arrivalAirport?.macCity?.toDomain(),
)
}
val connectingAirportDomain = connectingAirport?.let {
Airport.Connecting(
code = it.code ?: return@let null,
name = it.name ?: return@let null,
macCity = connectingAirport?.macCity?.toDomain(),
)
}
return listOfNotNull(departureAirportDomain, arrivalAirportDomain, connectingAirportDomain)
}

View File

@ -0,0 +1,19 @@
package dev.adriankuta.flights.model.repository.usecases
import dev.adriankuta.flights.domain.stations.GetConnectionsForAirportUseCase
import dev.adriankuta.flights.domain.types.Airport
import dev.adriankuta.flights.model.repository.mappers.toDomain
import dev.adriankuta.model.data.api.RoutesService
import javax.inject.Inject
internal class GetConnectionsForAirportUseCaseImpl @Inject constructor(
private val routesService: RoutesService,
) : GetConnectionsForAirportUseCase {
override suspend fun invoke(airport: Airport): Set<Airport> {
val result = routesService.getRoutes(
languageCode = "pl",
departureAirportCode = airport.code,
)
return result.map { it.toDomain() }.flatten().toSet()
}
}