diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/data/BpLocationDataSource.kt b/client_taxi_driver/shared/src/commonMain/kotlin/data/BpLocationDataSource.kt index e22b3dea1..145b32a68 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/data/BpLocationDataSource.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/data/BpLocationDataSource.kt @@ -17,9 +17,8 @@ class BpLocationDataSource(private val locationTracker: LocationTracker) : IBpLo locationTracker.startTracking() return locationTracker.getLocationsFlow().map { Location( - lat = it.latitude, - lng = it.longitude, - addressName = "" + latitude = it.latitude, + longitude = it.longitude, ) } } catch (deniedAlways: DeniedAlwaysException) { diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/data/local/gateway/LocalConfigurationGateway.kt b/client_taxi_driver/shared/src/commonMain/kotlin/data/local/gateway/LocalConfigurationGateway.kt index 8ddd3f5da..35f0bcd74 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/data/local/gateway/LocalConfigurationGateway.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/data/local/gateway/LocalConfigurationGateway.kt @@ -51,6 +51,17 @@ class LocalConfigurationGateway(private val realm: Realm) : ILocalConfigurationG override suspend fun clearTokens() { realm.write { delete(query()) } } + override suspend fun saveTaxiId(taxiId: String) { + realm.write { + query("$ID == $CONFIGURATION_ID").first() + .find()?.taxiId = taxiId + } + } + + override suspend fun getTaxiId(): String { + return realm.query("$ID == $CONFIGURATION_ID").first() + .find()?.taxiId ?: "" + } override suspend fun saveKeepMeLoggedInFlag(isChecked: Boolean) { realm.write { diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/data/local/module/UserConfigurationCollection.kt b/client_taxi_driver/shared/src/commonMain/kotlin/data/local/module/UserConfigurationCollection.kt index ffea97821..045c99798 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/data/local/module/UserConfigurationCollection.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/data/local/module/UserConfigurationCollection.kt @@ -8,4 +8,5 @@ class UserConfigurationCollection : RealmObject { var refreshToken: String = "" var username: String = "" var isKeepMeLoggedInMeChecked: Boolean = false + var taxiId: String = "" } \ No newline at end of file diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/fakegateway/IdentityFakeGateway.kt b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/fakegateway/IdentityFakeGateway.kt index f570cae57..cfe7ae945 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/fakegateway/IdentityFakeGateway.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/fakegateway/IdentityFakeGateway.kt @@ -4,6 +4,8 @@ import domain.InvalidPasswordException import domain.InvalidUserNameException import domain.PermissionDenied import domain.entity.Session +import domain.entity.Taxi +import domain.entity.TaxiRequestPermission import domain.gateway.remote.IIdentityRemoteGateway class IdentityFakeGateway : IIdentityRemoteGateway { @@ -27,11 +29,13 @@ class IdentityFakeGateway : IIdentityRemoteGateway { return Pair("wertqyhgt", "qazswxza") } - override suspend fun createRequestPermission( - driverFullName: String, - driverEmail: String, - description: String - ) { + override suspend fun createRequestPermission(taxiRequestPermission: TaxiRequestPermission): Boolean { + TODO("Not yet implemented") } + override suspend fun getAllVehicles(): List { + TODO("Not yet implemented") + } + + } \ No newline at end of file diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/fakegateway/LocationFakeGateway.kt b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/fakegateway/LocationFakeGateway.kt index 87d8cb45d..c3d60ae57 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/fakegateway/LocationFakeGateway.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/fakegateway/LocationFakeGateway.kt @@ -7,18 +7,25 @@ import kotlinx.coroutines.flow.flow class LocationFakeGateway : ILocationGateway { + override suspend fun startTracking() { + TODO("Not yet implemented") + } + override suspend fun trackCurrentLocation() = flow { var lattiude = 30.044420 while (true) { lattiude += 0.00004 emit( Location( - lat = lattiude, - lng = 31.235712, - addressName = "Cairo, Egypt", + latitude = lattiude, + longitude = 31.235712, ) ) delay(2000) } } + + override suspend fun stopTracking() { + TODO("Not yet implemented") + } } \ No newline at end of file diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/fakegateway/OrderFakeGateway.kt b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/fakegateway/OrderFakeGateway.kt index c781901e8..b052259bf 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/fakegateway/OrderFakeGateway.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/fakegateway/OrderFakeGateway.kt @@ -2,28 +2,29 @@ package data.remote.fakegateway import data.remote.mapper.toEntity import data.remote.model.LocationDto -import data.remote.model.OrderDto -import domain.entity.Order +import data.remote.model.TaxiTripDto +import domain.entity.Trip import domain.gateway.IOrderGateway import kotlinx.coroutines.delay class OrderFakeGateway : IOrderGateway { - override suspend fun findingNewOrder(): Order { + override suspend fun findingNewOrder(): Trip { delay(4000) - return OrderDto( + return TaxiTripDto( id = "djsahdjadhjadjas45dsadas", - passengerId = "sjdadjsadsa-dsa4d8sa4dsa", - passengerName = "Cristiano Ronaldo", - pickUpAddress = LocationDto( - lat = 40.6790229, - lng = -73.8740306, - addressName = "45, Faisal St., Riyadh, KSA", + clientName = "Cristiano Ronaldo", + startPoint = LocationDto( + latitude = 40.6790229, + longitude = -73.8740306, ), - dropOffAddress = LocationDto( - lat = 30.8859508, - lng = 31.4453136, - addressName = "Nirmala,girsls HSS", + destination = LocationDto( + latitude = 30.8859508, + longitude = 31.4453136, ), + startPointAddress = "ooveofe", + destinationAddress = "h9viife", + price = 100.0, + tripStatus = 1, ).toEntity() } } \ No newline at end of file diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/gateway/BaseRemoteGateway.kt b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/gateway/BaseRemoteGateway.kt deleted file mode 100644 index e4259b154..000000000 --- a/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/gateway/BaseRemoteGateway.kt +++ /dev/null @@ -1,54 +0,0 @@ -package data.remote.gateway - -import data.remote.model.BaseResponse -import domain.InternetException -import domain.InvalidPasswordException -import domain.InvalidUserNameException -import domain.NoInternetException -import domain.UnknownErrorException -import io.ktor.client.HttpClient -import io.ktor.client.call.body -import io.ktor.client.plugins.ClientRequestException -import io.ktor.client.statement.HttpResponse - - -abstract class BaseRemoteGateway(val client: HttpClient) { - - protected suspend inline fun tryToExecute( - method: HttpClient.() -> HttpResponse - ): T { - try { - return client.method().body() - } catch (e: ClientRequestException) { - val errorMessages = e.response.body>().status?.errorMessages - errorMessages?.let { throwMatchingException(it) } - throw UnknownErrorException(e.message) - } catch (e: InternetException) { - throw NoInternetException() - } catch (e: Exception) { - throw UnknownErrorException(e.message.toString()) - } - } - - fun throwMatchingException(errorMessages: Map) { - when { - errorMessages.containsErrors(WRONG_PASSWORD) -> - throw InvalidPasswordException(errorMessages.getOrEmpty(WRONG_PASSWORD)) - - errorMessages.containsErrors(USER_NOT_EXIST) -> - throw InvalidUserNameException(errorMessages.getOrEmpty(USER_NOT_EXIST)) - - else -> throw UnknownErrorException("UnKnow Error") - } - } - - private fun Map.containsErrors(vararg errorCodes: String): Boolean = - keys.containsAll(errorCodes.toList()) - - private fun Map.getOrEmpty(key: String): String = get(key) ?: "" - - companion object { - const val WRONG_PASSWORD = "1013" - const val USER_NOT_EXIST = "1043" - } -} \ No newline at end of file diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/gateway/LocationRemoteGateway.kt b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/gateway/LocationRemoteGateway.kt deleted file mode 100644 index d314084f6..000000000 --- a/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/gateway/LocationRemoteGateway.kt +++ /dev/null @@ -1,12 +0,0 @@ -package data.remote.gateway - -import domain.dataSource.IBpLocationDataSource -import domain.gateway.ILocationGateway -import kotlinx.coroutines.flow.distinctUntilChanged - -class LocationRemoteGateway( - private val bpLocation: IBpLocationDataSource, -) : ILocationGateway { - override suspend fun trackCurrentLocation() = - bpLocation.getCurrentLocation().distinctUntilChanged() -} \ No newline at end of file diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/gateway/local/LocationRemoteGateway.kt b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/gateway/local/LocationRemoteGateway.kt new file mode 100644 index 000000000..f9ca94315 --- /dev/null +++ b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/gateway/local/LocationRemoteGateway.kt @@ -0,0 +1,37 @@ +package data.remote.gateway.local + +import data.service.ILocationService +import dev.icerock.moko.geo.LocationTracker +import dev.icerock.moko.permissions.DeniedAlwaysException +import domain.LocationPermissionDeniedException +import domain.entity.Location +import domain.gateway.ILocationGateway +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map + +class LocationRemoteGateway( + private val locationService: ILocationService, + private val locationTracker: LocationTracker +) : ILocationGateway { + +override suspend fun startTracking() { + try { + locationTracker.startTracking() + if (!locationService.isGPSEnabled()) { + locationService.openLocationSettings() + } + } catch (e: DeniedAlwaysException) { + throw LocationPermissionDeniedException(e.message) + } +} + + override suspend fun trackCurrentLocation(): Flow { + return locationTracker.getLocationsFlow().map { + Location(it.latitude, it.longitude) + } + } + + override suspend fun stopTracking() { + locationTracker.stopTracking() + } +} \ No newline at end of file diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/gateway/AuthorizationInterceptor.kt b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/gateway/remote/AuthorizationInterceptor.kt similarity index 97% rename from client_taxi_driver/shared/src/commonMain/kotlin/data/remote/gateway/AuthorizationInterceptor.kt rename to client_taxi_driver/shared/src/commonMain/kotlin/data/remote/gateway/remote/AuthorizationInterceptor.kt index 1fbc64cae..b70a45b00 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/gateway/AuthorizationInterceptor.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/gateway/remote/AuthorizationInterceptor.kt @@ -1,4 +1,4 @@ -package data.remote.gateway +package data.remote.gateway.remote import data.local.gateway.LocalConfigurationGateway import io.ktor.client.HttpClient diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/gateway/remote/BaseRemoteGateway.kt b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/gateway/remote/BaseRemoteGateway.kt new file mode 100644 index 000000000..52cb4ffe0 --- /dev/null +++ b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/gateway/remote/BaseRemoteGateway.kt @@ -0,0 +1,97 @@ +package data.remote.gateway.remote + +import data.remote.model.BaseResponse +import domain.AlreadyExistException +import domain.InvalidPasswordException +import domain.InvalidUserNameException +import domain.NoInternetException +import domain.SocketException +import domain.UnAuthorizedException +import domain.UnknownErrorException +import io.ktor.client.HttpClient +import io.ktor.client.call.body +import io.ktor.client.plugins.ClientRequestException +import io.ktor.client.plugins.websocket.receiveDeserialized +import io.ktor.client.plugins.websocket.sendSerialized +import io.ktor.client.plugins.websocket.wss +import io.ktor.client.statement.HttpResponse +import io.ktor.util.network.UnresolvedAddressException +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.flowOn + + +abstract class BaseRemoteGateway(val client: HttpClient) { + + protected suspend inline fun tryToExecute( + method: HttpClient.() -> HttpResponse, + ): T { + try { + return client.method().body() + } catch (e: ClientRequestException) { + val errorMessages = e.response.body>().status?.errorMessages + errorMessages?.let { throwMatchingException(it) } + throw UnknownErrorException(e.message) + } catch (e: UnresolvedAddressException) { + throw NoInternetException() + } catch (e: Exception) { + println("exception: $e") + throw UnknownErrorException(e.message.toString()) + } + } + suspend inline fun HttpClient.tryToExecuteWebSocket(path: String): Flow { + return flow { + wss(path = path) { + while (true) { + try { + emit(receiveDeserialized()) + } catch (e: Exception) { + throw SocketException(e.message.orEmpty()) + } + } + } + }.flowOn(Dispatchers.IO) + } + suspend inline fun HttpClient.tryToSendWebSocketData( + data: T, + path: String, + ) { + wss(path) { + try { + sendSerialized(data) + } catch (e: Exception) { + throw SocketException(e.message.orEmpty()) + } + } + } + + fun throwMatchingException(errorMessages: Map) { + when { + errorMessages.containsErrors(WRONG_PASSWORD) -> + throw InvalidPasswordException(errorMessages.getOrEmpty(WRONG_PASSWORD)) + + errorMessages.containsErrors(USER_NOT_EXIST) -> + throw InvalidUserNameException(errorMessages.getOrEmpty(USER_NOT_EXIST)) + errorMessages.containsErrors(ALREADY_EXIST) -> + throw AlreadyExistException(errorMessages.getOrEmpty(ALREADY_EXIST)) + + errorMessages.containsErrors(INVALID_PERMISSION) -> + throw UnAuthorizedException(errorMessages.getOrEmpty(INVALID_PERMISSION)) + } + } + + + private fun Map.containsErrors(vararg errorCodes: String): Boolean = + keys.containsAll(errorCodes.toList()) + + private fun Map.getOrEmpty(key: String): String = get(key) ?: "" + + companion object { + const val WRONG_PASSWORD = "1013" + const val USER_NOT_EXIST = "1043" + const val INVALID_PERMISSION = "1014" + const val ALREADY_EXIST = "3010" + } +} \ No newline at end of file diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/gateway/IdentityRemoteGateway.kt b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/gateway/remote/IdentityRemoteGateway.kt similarity index 65% rename from client_taxi_driver/shared/src/commonMain/kotlin/data/remote/gateway/IdentityRemoteGateway.kt rename to client_taxi_driver/shared/src/commonMain/kotlin/data/remote/gateway/remote/IdentityRemoteGateway.kt index 1929dafaa..09169d5f5 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/gateway/IdentityRemoteGateway.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/gateway/remote/IdentityRemoteGateway.kt @@ -1,14 +1,21 @@ -package data.remote.gateway +package data.remote.gateway.remote +import data.remote.mapper.toDto import data.remote.mapper.toEntity import data.remote.model.BaseResponse import data.remote.model.SessionDto +import data.remote.model.TaxiDto +import domain.entity.TaxiRequestPermission import data.remote.model.UserTokensDto import domain.InvalidCredentialsException import domain.entity.Session +import domain.entity.Taxi import domain.gateway.remote.IIdentityRemoteGateway import io.ktor.client.HttpClient import io.ktor.client.request.forms.submitForm +import io.ktor.client.request.get +import io.ktor.client.request.post +import io.ktor.client.request.setBody import io.ktor.client.request.url import io.ktor.http.Parameters @@ -44,10 +51,19 @@ class IdentityRemoteGateway(client: HttpClient) : IIdentityRemoteGateway, } override suspend fun createRequestPermission( - driverFullName: String, - driverEmail: String, - description: String, - ) { - // TODO: add create request permission end point when backend is done + taxiRequestPermission: TaxiRequestPermission + ): Boolean { + val result = tryToExecute> { + post("/restaurant-permission-request") { + setBody(taxiRequestPermission.toDto()) + } + }.value ?: throw Exception() + + return result + } + override suspend fun getAllVehicles(): List { + return tryToExecute>> { + get("taxis/belongs-to-delivery-driver") + }.value?.map { it.toEntity() } ?: throw Exception() } } \ No newline at end of file diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/gateway/remote/TripRemoteGateway.kt b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/gateway/remote/TripRemoteGateway.kt new file mode 100644 index 000000000..1c071c615 --- /dev/null +++ b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/gateway/remote/TripRemoteGateway.kt @@ -0,0 +1,48 @@ +package data.remote.gateway.remote + +import data.remote.mapper.toDto +import data.remote.mapper.toEntity +import data.remote.model.BaseResponse +import data.remote.model.LocationDto +import data.remote.model.TaxiTripDto +import data.remote.model.TripDto +import domain.NotFoundedException +import domain.entity.Location +import domain.entity.Trip +import domain.gateway.remote.ITripRemoteGateway +import io.ktor.client.HttpClient +import io.ktor.client.request.forms.submitForm +import io.ktor.http.HttpMethod +import io.ktor.http.Parameters +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map + +class TripRemoteGateway(client: HttpClient) : ITripRemoteGateway, + BaseRemoteGateway(client = client) { + + override suspend fun getTrips(): Flow { + val result= client.tryToExecuteWebSocket("/trip/incoming-taxi-rides") + .map { it.toEntity() } + return result + } + + override suspend fun sendLocation(location: Location, tripId: String) { + client.tryToSendWebSocketData( + path = "/location/sender/$tripId", + data = location.toDto() + ) + } + + override suspend fun updateTrip(tripId: String, taxiId: String) { + val result = tryToExecute> { + submitForm( + url = ("/trip/update/taxi-ride"), + formParameters = Parameters.build { + append("tripId", tripId) + append("taxiId", taxiId) + }, + block = { method = HttpMethod.Put } + ) + }.value ?: throw NotFoundedException() + } +} \ No newline at end of file diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/mapper/MapMapper.kt b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/mapper/MapMapper.kt index c5cc04820..4c773c21b 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/mapper/MapMapper.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/mapper/MapMapper.kt @@ -1,19 +1,25 @@ package data.remote.mapper import data.remote.model.LocationDto -import data.remote.model.OrderDto +import data.remote.model.TaxiTripDto import domain.entity.Location -import domain.entity.Order +import domain.entity.Trip -fun OrderDto.toEntity(): Order = Order( +fun TaxiTripDto.toEntity(): Trip = Trip( id = id ?: "", - passengerName = passengerName ?: "", - dropOffAddress = dropOffAddress.toEntity(), - pickUpAddress = pickUpAddress.toEntity(), + passengerName = this.clientName ?: "", + dropOffLocation = this.destination?.toEntity()?: Location(0.0, 0.0), + pickUpLocation = this.startPoint?.toEntity()?: Location(0.0, 0.0), + pickUpAddress = this.startPointAddress?:"", + dropOffAddress = this.destinationAddress?:"", ) fun LocationDto.toEntity(): Location = Location( - lat = lat ?: 0.0, - lng = lng ?: 0.0, - addressName = addressName ?: "", + latitude = this.latitude ?: 0.0, + longitude = this.longitude ?: 0.0, +) + +fun Location.toDto(): LocationDto = LocationDto( + latitude = this.latitude, + longitude = this.longitude, ) \ No newline at end of file diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/mapper/RequestPermissionMapper.kt b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/mapper/RequestPermissionMapper.kt new file mode 100644 index 000000000..7858f8e8a --- /dev/null +++ b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/mapper/RequestPermissionMapper.kt @@ -0,0 +1,17 @@ +package data.remote.mapper + +import data.remote.model.TaxiRequestPermissionDto +import domain.entity.TaxiRequestPermission + + +fun TaxiRequestPermission.toDto() = TaxiRequestPermissionDto( + driverFullName = driverFullName, + driverEmail = driverEmail, + description = description, +) + +fun TaxiRequestPermissionDto.toEntity() = TaxiRequestPermission( + driverFullName = driverFullName, + driverEmail = driverEmail, + description = description, +) \ No newline at end of file diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/mapper/TaxiMapper.kt b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/mapper/TaxiMapper.kt new file mode 100644 index 000000000..e944c64b2 --- /dev/null +++ b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/mapper/TaxiMapper.kt @@ -0,0 +1,35 @@ +package data.remote.mapper + +import data.remote.model.TaxiDto +import domain.entity.Taxi + +fun TaxiDto.toEntity(): Taxi { + return Taxi( + id = id?:"", + plateNumber = plateNumber, + color = color, + type = type, + driverId = driverId?:"", + driverUsername = driverUsername, + driverImage = driverImage?:"", + rate = rate?:0.0, + isAvailable = isAvailable?:false, + seats = seats?:0, + tripsCount = tripsCount?:0, + ) +} +fun Taxi.toDto(): TaxiDto { + return TaxiDto( + id = id, + plateNumber = plateNumber, + color = color, + type = type, + driverId = driverId, + driverUsername = driverUsername, + driverImage = driverImage, + rate = rate, + isAvailable = isAvailable, + seats = seats, + tripsCount = tripsCount, + ) +} \ No newline at end of file diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/model/LocationDto.kt b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/model/LocationDto.kt index 92aa4720b..3969d0417 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/model/LocationDto.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/model/LocationDto.kt @@ -1,7 +1,10 @@ package data.remote.model +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable data class LocationDto( - val lat: Double?, - val lng: Double?, - val addressName: String?, + @SerialName("latitude") val latitude: Double? = null, + @SerialName("longitude") val longitude: Double? = null ) \ No newline at end of file diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/model/OrderDto.kt b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/model/OrderDto.kt deleted file mode 100644 index b0fc21003..000000000 --- a/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/model/OrderDto.kt +++ /dev/null @@ -1,9 +0,0 @@ -package data.remote.model - -data class OrderDto( - val id: String?, - val passengerName: String?, - val passengerId: String?, - val pickUpAddress: LocationDto, - val dropOffAddress: LocationDto, -) diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/model/TaxiDto.kt b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/model/TaxiDto.kt new file mode 100644 index 000000000..b596ad66d --- /dev/null +++ b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/model/TaxiDto.kt @@ -0,0 +1,19 @@ +package data.remote.model + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class TaxiDto( + @SerialName("id") val id: String? = null, + @SerialName("plateNumber") val plateNumber: String, + @SerialName("color") val color: Long, + @SerialName("type") val type: String, + @SerialName("driverId") val driverId: String? = null, + @SerialName("driverUsername") val driverUsername: String, + @SerialName("driverImage") val driverImage: String? = null, + @SerialName("rate") val rate: Double? = null, + @SerialName("isAvailable") val isAvailable: Boolean = true, + @SerialName("seats") val seats: Int = 4, + @SerialName("tripsCount") val tripsCount: Int? = 0, +) \ No newline at end of file diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/model/TaxiRequestPermissionDto.kt b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/model/TaxiRequestPermissionDto.kt new file mode 100644 index 000000000..f42e1e214 --- /dev/null +++ b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/model/TaxiRequestPermissionDto.kt @@ -0,0 +1,12 @@ +package data.remote.model + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + + +@Serializable +data class TaxiRequestPermissionDto( + @SerialName("restaurantName") val driverFullName: String, + @SerialName("ownerEmail") val driverEmail: String, + @SerialName("cause") val description: String +) \ No newline at end of file diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/model/TaxiTripDto.kt b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/model/TaxiTripDto.kt new file mode 100644 index 000000000..8d015534a --- /dev/null +++ b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/model/TaxiTripDto.kt @@ -0,0 +1,15 @@ +package data.remote.model + +import kotlinx.serialization.Serializable + +@Serializable +data class TaxiTripDto( + val id: String, + val clientName: String, + val startPoint: LocationDto, + val destination: LocationDto, + val startPointAddress: String, + val destinationAddress: String, + val price: Double, + val tripStatus: Int +) diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/model/TripDto.kt b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/model/TripDto.kt new file mode 100644 index 000000000..28080da77 --- /dev/null +++ b/client_taxi_driver/shared/src/commonMain/kotlin/data/remote/model/TripDto.kt @@ -0,0 +1,26 @@ +package data.remote.model + +import kotlinx.serialization.Serializable + +@Serializable +data class TripDto( + val id: String? = null, + val taxiId: String? = null, + val driverId: String? = null, + val clientId: String? = null, + val orderId: String? = null, + val restaurantId: String? = null, + val taxiPlateNumber: String? = null, + val taxiDriverName: String? = null, + val taxiColor: Long? = null, + val startPoint: LocationDto? = null, + val destination: LocationDto? = null, + val startPointAddress: String? = null, + val destinationAddress: String? = null, + val rate: Double? = null, + val price: Double? = null, + val startDate: String? = null, + val endDate: String? = null, + val isATaxiTrip: Boolean? = null, + val tripStatus: Int = 0 +) \ No newline at end of file diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/di/GatewayModule.kt b/client_taxi_driver/shared/src/commonMain/kotlin/di/GatewayModule.kt index cafe2d030..581735525 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/di/GatewayModule.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/di/GatewayModule.kt @@ -2,12 +2,14 @@ package di import data.local.gateway.LocalConfigurationGateway import data.remote.fakegateway.OrderFakeGateway -import data.remote.gateway.IdentityRemoteGateway -import data.remote.gateway.LocationRemoteGateway +import data.remote.gateway.remote.IdentityRemoteGateway +import data.remote.gateway.local.LocationRemoteGateway +import data.remote.gateway.remote.TripRemoteGateway import domain.gateway.ILocationGateway import domain.gateway.IOrderGateway import domain.gateway.local.ILocalConfigurationGateway import domain.gateway.remote.IIdentityRemoteGateway +import domain.gateway.remote.ITripRemoteGateway import org.koin.core.module.dsl.bind import org.koin.core.module.dsl.singleOf import org.koin.dsl.module @@ -19,4 +21,5 @@ val GatewayModule = module { singleOf(::LocalConfigurationGateway) { bind() } singleOf(::OrderFakeGateway) { bind() } singleOf(::LocationRemoteGateway) { bind() } + singleOf(::TripRemoteGateway) {bind()} } \ No newline at end of file diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/di/NetworkModule.kt b/client_taxi_driver/shared/src/commonMain/kotlin/di/NetworkModule.kt index cd8d98eef..0b381c3a2 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/di/NetworkModule.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/di/NetworkModule.kt @@ -1,15 +1,19 @@ package di -import data.remote.gateway.intercept +import data.remote.gateway.remote.intercept import io.ktor.client.HttpClient -import io.ktor.client.engine.cio.CIO import io.ktor.client.plugins.contentnegotiation.ContentNegotiation import io.ktor.client.plugins.defaultRequest import io.ktor.client.plugins.logging.DEFAULT import io.ktor.client.plugins.logging.LogLevel import io.ktor.client.plugins.logging.Logger import io.ktor.client.plugins.logging.Logging +import io.ktor.client.plugins.websocket.WebSockets import io.ktor.client.request.header +import io.ktor.http.URLBuilder +import io.ktor.http.URLProtocol +import io.ktor.http.Url +import io.ktor.serialization.kotlinx.KotlinxWebsocketSerializationConverter import io.ktor.serialization.kotlinx.json.json import kotlinx.serialization.json.Json import org.koin.dsl.module @@ -23,6 +27,11 @@ val NetworkModule = module { install(Logging) { logger = Logger.DEFAULT level = LogLevel.ALL + logger = object : Logger { + override fun log(message: String) { + println("HTTP Client: $message") + } + } } defaultRequest { @@ -30,7 +39,17 @@ val NetworkModule = module { header("Accept-Language", "en") url(BASEURL) } - + install(WebSockets) { + contentConverter = KotlinxWebsocketSerializationConverter(Json) + val urlBuilder = URLBuilder( + protocol = URLProtocol.WSS, + host = "beep-beep-api-gateway-nap2u.ondigitalocean.app/", +// Local host = "192.168.1.100", +// Local port = 8080 + ) + Url(urlBuilder) + pingInterval = 10000 + } install(ContentNegotiation) { json( Json { @@ -45,4 +64,4 @@ val NetworkModule = module { client } } -private const val BASEURL = "https://beep-beep-api-gateway-nap2u.ondigitalocean.app" +private const val BASEURL = "https://beep-beep-api-gateway-nap2u.ondigitalocean.app/" diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/di/UseCaseModule.kt b/client_taxi_driver/shared/src/commonMain/kotlin/di/UseCaseModule.kt index bfdacd957..0e19ddc90 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/di/UseCaseModule.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/di/UseCaseModule.kt @@ -2,16 +2,16 @@ package di import domain.usecase.ILoginUserUseCase import domain.usecase.IManageLocationUseCase -import domain.usecase.IManageOrderUseCase +import domain.usecase.IManageTripUseCase import domain.usecase.LoginUserUseCase import domain.usecase.ManageLocationUseCase -import domain.usecase.ManageOrderUseCase +import domain.usecase.ManageTripUseCase import org.koin.core.module.dsl.bind import org.koin.core.module.dsl.singleOf import org.koin.dsl.module val UseCaseModule = module { singleOf(::LoginUserUseCase) { bind() } - singleOf(::ManageOrderUseCase) { bind() } + singleOf(::ManageTripUseCase) { bind() } singleOf(::ManageLocationUseCase) { bind() } } \ No newline at end of file diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/domain/ErrorType.kt b/client_taxi_driver/shared/src/commonMain/kotlin/domain/ErrorType.kt index d2b6168d9..365a430f5 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/domain/ErrorType.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/domain/ErrorType.kt @@ -9,7 +9,7 @@ class NoInternetException : InternetException("No internet connection") //region authorization open class AuthorizationException(message: String) : BpException(message) -class UnAuthorizedException : AuthorizationException("You have to login") +class UnAuthorizedException(message: String) : AuthorizationException(message) class PermissionDenied : AuthorizationException("You have to allow permission") //endregion @@ -26,6 +26,7 @@ class UnknownErrorException(message: String) : BpException(message) class InvalidCredentialsException(message: String) : BpException(message) class InvalidUserNameException(private val errorMessage: String) : BpException(errorMessage) +class AlreadyExistException(private val errorMessage: String) : BpException(errorMessage) class InvalidPasswordException(private val errorMessage: String) : BpException(errorMessage) @@ -33,4 +34,5 @@ class InvalidDriverNameException(private val errorMessage: String) : BpException class InvalidDriverEmailException(private val errorMessage: String) : BpException(errorMessage) -class InvalidDescriptionException(private val errorMessage: String) : BpException(errorMessage) \ No newline at end of file +class InvalidDescriptionException(private val errorMessage: String) : BpException(errorMessage) +class SocketException(private val errorMessage: String) : BpException(errorMessage) \ No newline at end of file diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/domain/entity/Location.kt b/client_taxi_driver/shared/src/commonMain/kotlin/domain/entity/Location.kt index 3ff4b717b..21dc56ea9 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/domain/entity/Location.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/domain/entity/Location.kt @@ -1,7 +1,6 @@ package domain.entity data class Location( - val lat: Double, - val lng: Double, - val addressName: String, + val latitude: Double, + val longitude: Double, ) diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/domain/entity/Order.kt b/client_taxi_driver/shared/src/commonMain/kotlin/domain/entity/Order.kt deleted file mode 100644 index dc0e80eff..000000000 --- a/client_taxi_driver/shared/src/commonMain/kotlin/domain/entity/Order.kt +++ /dev/null @@ -1,8 +0,0 @@ -package domain.entity - -data class Order( - val id: String, - val passengerName: String, - val pickUpAddress: Location, - val dropOffAddress: Location, -) diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/domain/entity/Taxi.kt b/client_taxi_driver/shared/src/commonMain/kotlin/domain/entity/Taxi.kt new file mode 100644 index 000000000..480d0631a --- /dev/null +++ b/client_taxi_driver/shared/src/commonMain/kotlin/domain/entity/Taxi.kt @@ -0,0 +1,15 @@ +package domain.entity + +data class Taxi( + val id: String, + val plateNumber: String, + val color: Long, + val type: String, + val driverId: String, + val driverUsername: String, + val driverImage: String, + val rate: Double, + val isAvailable: Boolean, + val seats: Int, + val tripsCount: Int, +) \ No newline at end of file diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/domain/entity/TaxiRequestPermission.kt b/client_taxi_driver/shared/src/commonMain/kotlin/domain/entity/TaxiRequestPermission.kt new file mode 100644 index 000000000..95139dc85 --- /dev/null +++ b/client_taxi_driver/shared/src/commonMain/kotlin/domain/entity/TaxiRequestPermission.kt @@ -0,0 +1,7 @@ +package domain.entity + +data class TaxiRequestPermission( + val driverFullName: String, + val driverEmail: String, + val description: String, +) \ No newline at end of file diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/domain/entity/Trip.kt b/client_taxi_driver/shared/src/commonMain/kotlin/domain/entity/Trip.kt new file mode 100644 index 000000000..33e3b4a7d --- /dev/null +++ b/client_taxi_driver/shared/src/commonMain/kotlin/domain/entity/Trip.kt @@ -0,0 +1,16 @@ +package domain.entity + +data class Trip( + val id: String, + val passengerName: String, + val pickUpLocation: Location, + val pickUpAddress: String, + val dropOffLocation: Location, + val dropOffAddress: String, +){ + enum class Status(val statusCode: Int){ + APPROVED(1), + RECEIVED(2), + FINISHED(3); + } +} \ No newline at end of file diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/domain/gateway/ILocationGateway.kt b/client_taxi_driver/shared/src/commonMain/kotlin/domain/gateway/ILocationGateway.kt index 58742e648..9133ee39f 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/domain/gateway/ILocationGateway.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/domain/gateway/ILocationGateway.kt @@ -4,5 +4,7 @@ import domain.entity.Location import kotlinx.coroutines.flow.Flow interface ILocationGateway { + suspend fun startTracking() suspend fun trackCurrentLocation(): Flow + suspend fun stopTracking() } \ No newline at end of file diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/domain/gateway/IOrderGateway.kt b/client_taxi_driver/shared/src/commonMain/kotlin/domain/gateway/IOrderGateway.kt index c272be265..e7e940e14 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/domain/gateway/IOrderGateway.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/domain/gateway/IOrderGateway.kt @@ -1,7 +1,7 @@ package domain.gateway -import domain.entity.Order +import domain.entity.Trip interface IOrderGateway { - suspend fun findingNewOrder(): Order + suspend fun findingNewOrder(): Trip } \ No newline at end of file diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/domain/gateway/local/ILocalConfigurationGateway.kt b/client_taxi_driver/shared/src/commonMain/kotlin/domain/gateway/local/ILocalConfigurationGateway.kt index 127256951..5dc363c38 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/domain/gateway/local/ILocalConfigurationGateway.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/domain/gateway/local/ILocalConfigurationGateway.kt @@ -10,6 +10,8 @@ interface ILocalConfigurationGateway { suspend fun saveKeepMeLoggedInFlag(isChecked: Boolean) suspend fun getKeepMeLoggedInFlag(): Boolean suspend fun clearTokens() + suspend fun saveTaxiId(taxiId: String) + suspend fun getTaxiId(): String suspend fun saveUserName(username: String) suspend fun getUsername(): String diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/domain/gateway/remote/IIdentityRemoteGateway.kt b/client_taxi_driver/shared/src/commonMain/kotlin/domain/gateway/remote/IIdentityRemoteGateway.kt index d1e7d9970..c67b488d4 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/domain/gateway/remote/IIdentityRemoteGateway.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/domain/gateway/remote/IIdentityRemoteGateway.kt @@ -1,6 +1,8 @@ package domain.gateway.remote +import domain.entity.TaxiRequestPermission import domain.entity.Session +import domain.entity.Taxi interface IIdentityRemoteGateway { @@ -10,10 +12,7 @@ interface IIdentityRemoteGateway { // the pair this fun return is suspend fun refreshAccessToken(refreshToken: String): Pair - suspend fun createRequestPermission( - driverFullName: String, - driverEmail: String, - description: String, - ) + suspend fun createRequestPermission(taxiRequestPermission: TaxiRequestPermission): Boolean + suspend fun getAllVehicles(): List } diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/domain/gateway/remote/ITripRemoteGateway.kt b/client_taxi_driver/shared/src/commonMain/kotlin/domain/gateway/remote/ITripRemoteGateway.kt new file mode 100644 index 000000000..bc848f620 --- /dev/null +++ b/client_taxi_driver/shared/src/commonMain/kotlin/domain/gateway/remote/ITripRemoteGateway.kt @@ -0,0 +1,12 @@ +package domain.gateway.remote + +import domain.entity.Location +import domain.entity.Trip +import kotlinx.coroutines.flow.Flow + + +interface ITripRemoteGateway { + suspend fun getTrips(): Flow + suspend fun sendLocation(location: Location, tripId: String) + suspend fun updateTrip(tripId: String,taxiId: String) +} \ No newline at end of file diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/domain/usecase/LoginUserUseCase.kt b/client_taxi_driver/shared/src/commonMain/kotlin/domain/usecase/LoginUserUseCase.kt index d07c33123..daddab6df 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/domain/usecase/LoginUserUseCase.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/domain/usecase/LoginUserUseCase.kt @@ -4,6 +4,7 @@ import domain.InvalidDriverEmailException import domain.InvalidDriverNameException import domain.InvalidPasswordException import domain.InvalidUserNameException +import domain.entity.TaxiRequestPermission import domain.gateway.local.ILocalConfigurationGateway import domain.gateway.remote.IIdentityRemoteGateway @@ -17,13 +18,10 @@ interface ILoginUserUseCase { suspend fun saveUsername(username: String) suspend fun getUsername(): String + suspend fun getKeepMeLoggedInFlag(): Boolean - suspend fun requestPermission( - driverFullName: String, - driverEmail: String, - description: String, - ) + suspend fun requestPermission(taxiRequestPermission: TaxiRequestPermission): Boolean } class LoginUserUseCase( @@ -41,6 +39,7 @@ class LoginUserUseCase( localGateWay.saveAccessToken(userTokens.accessToken) localGateWay.saveRefreshToken(userTokens.refreshToken) localGateWay.saveKeepMeLoggedInFlag(isKeepMeLoggedInChecked) + localGateWay.saveTaxiId(getTaxiId()) } override suspend fun saveUsername(username: String) { @@ -51,20 +50,20 @@ class LoginUserUseCase( return localGateWay.getUsername() } + override suspend fun getKeepMeLoggedInFlag(): Boolean { return localGateWay.getKeepMeLoggedInFlag() } - override suspend fun requestPermission( - driverFullName: String, driverEmail: String, description: String, - ) { - checkValidationPermissionFields(driverFullName, driverEmail) - - remoteGateway.createRequestPermission( - driverFullName, - driverEmail, - description + override suspend fun requestPermission(taxiRequestPermission: TaxiRequestPermission): Boolean { + checkValidationPermissionFields( + taxiRequestPermission.driverFullName, + taxiRequestPermission.driverEmail ) + return remoteGateway.createRequestPermission(taxiRequestPermission) + } + private suspend fun getTaxiId(): String { + return remoteGateway.getAllVehicles().first().id } diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/domain/usecase/ManageLocationUseCase.kt b/client_taxi_driver/shared/src/commonMain/kotlin/domain/usecase/ManageLocationUseCase.kt index 8a67dbee1..8ab64c3e2 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/domain/usecase/ManageLocationUseCase.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/domain/usecase/ManageLocationUseCase.kt @@ -1,18 +1,28 @@ package domain.usecase -import data.remote.gateway.LocationRemoteGateway +import data.remote.gateway.local.LocationRemoteGateway import domain.entity.Location import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.distinctUntilChanged interface IManageLocationUseCase { + suspend fun startTracking() suspend fun trackCurrentLocation(): Flow + suspend fun stopTracking() } class ManageLocationUseCase( private val locationGateway: LocationRemoteGateway, ) : IManageLocationUseCase { + + override suspend fun startTracking() { + locationGateway.startTracking() + } + + override suspend fun stopTracking() { + locationGateway.stopTracking() + } override suspend fun trackCurrentLocation() = locationGateway.trackCurrentLocation().distinctUntilChanged() } \ No newline at end of file diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/domain/usecase/ManageOrderUseCase.kt b/client_taxi_driver/shared/src/commonMain/kotlin/domain/usecase/ManageOrderUseCase.kt deleted file mode 100644 index 4e58ae32e..000000000 --- a/client_taxi_driver/shared/src/commonMain/kotlin/domain/usecase/ManageOrderUseCase.kt +++ /dev/null @@ -1,15 +0,0 @@ -package domain.usecase - -import data.remote.fakegateway.OrderFakeGateway -import domain.entity.Order - - -interface IManageOrderUseCase { - suspend fun foundNewOrder(): Order -} - -class ManageOrderUseCase( - private val mapGateway: OrderFakeGateway, -) : IManageOrderUseCase { - override suspend fun foundNewOrder() = mapGateway.findingNewOrder() -} \ No newline at end of file diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/domain/usecase/ManageTripUseCase.kt b/client_taxi_driver/shared/src/commonMain/kotlin/domain/usecase/ManageTripUseCase.kt new file mode 100644 index 000000000..3bb46b15f --- /dev/null +++ b/client_taxi_driver/shared/src/commonMain/kotlin/domain/usecase/ManageTripUseCase.kt @@ -0,0 +1,36 @@ +package domain.usecase + +import domain.entity.Location +import domain.entity.Trip +import domain.gateway.local.ILocalConfigurationGateway +import domain.gateway.remote.ITripRemoteGateway +import kotlinx.coroutines.flow.Flow + + +interface IManageTripUseCase { + suspend fun findNewTrip(): Flow + suspend fun updateTripLocation(location: Location, tripId: String) + suspend fun updateTripStatus(tripId: String) + suspend fun getTaxiId(): String +} + +class ManageTripUseCase( + private val tripGateway: ITripRemoteGateway, + private val localGateWay: ILocalConfigurationGateway +) : IManageTripUseCase { + override suspend fun findNewTrip(): Flow { + return tripGateway.getTrips() + } + override suspend fun updateTripLocation(location: Location, tripId: String) { + tripGateway.sendLocation(location = location, tripId = tripId) + } + + override suspend fun updateTripStatus(tripId: String) { + val taxiId = localGateWay.getTaxiId() + tripGateway.updateTrip(tripId,taxiId) + } + + override suspend fun getTaxiId(): String { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/presentation/base/BaseScreenModel.kt b/client_taxi_driver/shared/src/commonMain/kotlin/presentation/base/BaseScreenModel.kt index bd555ca3d..e174627f1 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/presentation/base/BaseScreenModel.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/presentation/base/BaseScreenModel.kt @@ -2,6 +2,7 @@ package presentation.base import cafe.adriel.voyager.core.model.ScreenModel import cafe.adriel.voyager.core.model.coroutineScope +import domain.AlreadyExistException import domain.InvalidCredentialsException import domain.InvalidDriverEmailException import domain.InvalidDriverNameException @@ -93,31 +94,14 @@ abstract class BaseScreenModel(initialState: S) : ScreenModel, KoinCompone is ServerSideException -> onError(ErrorState.ServerError) is UnAuthorizedException -> onError(ErrorState.UnAuthorized) is NotFoundedException -> onError(ErrorState.NotFound(exception.message.toString())) - is UnknownErrorException -> onError( - ErrorState.UnknownError( - exception.message.toString() - ) - ) - - is InvalidCredentialsException -> onError( - ErrorState.InvalidCredentials( - exception.message.toString() - ) - ) - + is UnknownErrorException -> onError(ErrorState.UnknownError(exception.message.toString())) + is InvalidCredentialsException -> onError(ErrorState.InvalidCredentials(exception.message.toString())) is InvalidUserNameException -> onError(ErrorState.InvalidUserName(exception.message.toString())) is InvalidPasswordException -> onError(ErrorState.InvalidPassword(exception.message.toString())) is InvalidDriverNameException -> onError(ErrorState.InvalidDriverName(exception.message.toString())) - is InvalidDriverEmailException -> onError( - ErrorState.InvalidDriverEmail( - exception.message.toString() - ) - ) - - is LocationPermissionDeniedAlwaysException -> onError( - ErrorState.LocationPermissionDenied(message = exception.message.toString()) - ) - + is InvalidDriverEmailException -> onError(ErrorState.InvalidDriverEmail(exception.message.toString())) + is LocationPermissionDeniedAlwaysException -> onError(ErrorState.LocationPermissionDenied(message = exception.message.toString())) + is AlreadyExistException -> onError(ErrorState.AlreadyExist(message = exception.message.toString())) is LocationPermissionDeniedException -> onError( ErrorState.LocationPermissionDenied(message = exception.message.toString()) ) diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/presentation/base/ErrorState.kt b/client_taxi_driver/shared/src/commonMain/kotlin/presentation/base/ErrorState.kt index a6781ed30..2a71517d4 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/presentation/base/ErrorState.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/presentation/base/ErrorState.kt @@ -9,6 +9,7 @@ sealed interface ErrorState { data class UnknownError(val errorMessage: String) : ErrorState data class NotFound(val errorMessage: String) : ErrorState data class LocationPermissionDenied(val message: String) : ErrorState + data class AlreadyExist(val message: String) : ErrorState data class InvalidUserName(val errorMessage: String) : ErrorState data class InvalidPassword(val errorMessage: String) : ErrorState data class InvalidDriverName(val errorMessage: String) : ErrorState diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/presentation/login/LoginScreenModel.kt b/client_taxi_driver/shared/src/commonMain/kotlin/presentation/login/LoginScreenModel.kt index 236476c78..da936551a 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/presentation/login/LoginScreenModel.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/presentation/login/LoginScreenModel.kt @@ -1,6 +1,7 @@ package presentation.login import cafe.adriel.voyager.core.model.coroutineScope +import domain.entity.TaxiRequestPermission import domain.usecase.ILoginUserUseCase import kotlinx.coroutines.delay import kotlinx.coroutines.launch @@ -157,14 +158,9 @@ class LoginScreenModel(private val loginUserUseCase: ILoginUserUseCase) : driverEmail: String, description: String ) { + val requestPermission = TaxiRequestPermission(driverFullName, driverEmail, description) tryToExecute( - { - loginUserUseCase.requestPermission( - driverFullName, - driverEmail, - description - ) - }, + { loginUserUseCase.requestPermission(requestPermission) }, { onAskForPermissionSuccess() }, ::onLoginFailed ) diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/presentation/main/MainScreen.kt b/client_taxi_driver/shared/src/commonMain/kotlin/presentation/main/MainScreen.kt index 7f985d8a3..a1c9019fc 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/presentation/main/MainScreen.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/presentation/main/MainScreen.kt @@ -16,6 +16,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.unit.dp import cafe.adriel.voyager.navigator.Navigator +import com.beepbeep.designSystem.ui.composable.BPSnackBar import com.beepbeep.designSystem.ui.composable.BpButton import com.beepbeep.designSystem.ui.theme.Theme import org.jetbrains.compose.resources.ExperimentalResourceApi @@ -23,6 +24,7 @@ import org.jetbrains.compose.resources.painterResource import presentation.base.BaseScreen import presentation.map.MapScreen import presentation.resources.Resources +import util.getNavigationBarPadding class MainScreen : BaseScreen() { @@ -73,17 +75,30 @@ class MainScreen : BpButton( title = Resources.strings.start, - onClick = listener::onCLickStart, + onClick = listener::onClickStart, modifier = Modifier.fillMaxWidth().padding(top = 24.dp, bottom = 22.dp) ) } } + BPSnackBar( + icon = painterResource(Resources.images.errorIcon), + iconBackgroundColor = Theme.colors.warningContainer, + iconTint = Theme.colors.warning, + isVisible = state.showSnackBar, + modifier = Modifier.padding(bottom = getNavigationBarPadding().calculateBottomPadding()) + .align(Alignment.BottomCenter) + ) { + Text( + text = Resources.strings.accessDeniedMessage, + style = Theme.typography.body.copy(color = Theme.colors.contentPrimary), + ) + } } } override fun onEffect(effect: MainUiEffect, navigator: Navigator) { when(effect){ - MainUiEffect.MainEffect -> navigator.push(MapScreen()) + MainUiEffect.Start -> navigator.push(MapScreen()) } } diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/presentation/main/MainScreenInteractionListener.kt b/client_taxi_driver/shared/src/commonMain/kotlin/presentation/main/MainScreenInteractionListener.kt index 1a6c2104c..4bda143cf 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/presentation/main/MainScreenInteractionListener.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/presentation/main/MainScreenInteractionListener.kt @@ -3,5 +3,5 @@ package presentation.main import presentation.base.BaseInteractionListener interface MainScreenInteractionListener : BaseInteractionListener { - fun onCLickStart() + fun onClickStart() } diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/presentation/main/MainScreenModel.kt b/client_taxi_driver/shared/src/commonMain/kotlin/presentation/main/MainScreenModel.kt index a63cb97b2..efa54278c 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/presentation/main/MainScreenModel.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/presentation/main/MainScreenModel.kt @@ -1,11 +1,42 @@ package presentation.main +import cafe.adriel.voyager.core.model.coroutineScope +import domain.usecase.IManageLocationUseCase +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch import presentation.base.BaseScreenModel +import presentation.base.ErrorState -class MainScreenModel: - BaseScreenModel(MainScreenUiState()), +class MainScreenModel( + private val location: IManageLocationUseCase, +): BaseScreenModel(MainScreenUiState()), MainScreenInteractionListener { - override fun onCLickStart() { - sendNewEffect(MainUiEffect.MainEffect) + + override fun onClickStart() { + tryToExecute( + function = location::startTracking, + onSuccess = { onSuccess() }, + onError = ::onError + ) + } + + private fun onSuccess() { + sendNewEffect(MainUiEffect.Start) + } + + private fun onError(error: ErrorState) { + when (error) { + ErrorState.LocationPermissionDenied("LocationPermissionDenied") -> showSnackBar() + else -> {} + } + } + private fun showSnackBar() { + coroutineScope.launch { + updateState { it.copy(showSnackBar = true) } + delay(4000) + updateState { it.copy(showSnackBar = false) } + } + } + } diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/presentation/main/MainScreenUiState.kt b/client_taxi_driver/shared/src/commonMain/kotlin/presentation/main/MainScreenUiState.kt index 16a3ae67d..bdebbab7f 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/presentation/main/MainScreenUiState.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/presentation/main/MainScreenUiState.kt @@ -1,5 +1,7 @@ package presentation.main data class MainScreenUiState( - val test: String = "" + val test: String = "", + val showSnackBar: Boolean = false, + val snackBarMessage: String = "" ) diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/presentation/main/MainUiEffect.kt b/client_taxi_driver/shared/src/commonMain/kotlin/presentation/main/MainUiEffect.kt index 0b21e6af3..2b05abd29 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/presentation/main/MainUiEffect.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/presentation/main/MainUiEffect.kt @@ -1,5 +1,5 @@ package presentation.main sealed interface MainUiEffect { - data object MainEffect : MainUiEffect + data object Start : MainUiEffect } diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/presentation/map/CalfMap.kt b/client_taxi_driver/shared/src/commonMain/kotlin/presentation/map/CalfMap.kt index bb40ad822..6c5826d98 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/presentation/map/CalfMap.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/presentation/map/CalfMap.kt @@ -26,14 +26,14 @@ fun CalfMapWebView( AnimatedVisibility(destination == null) { state.evaluateJavascript( - "createInfiniteLoopFunction(${currentLocation.lat},${currentLocation.lng})()", + "createInfiniteLoopFunction(${currentLocation.latitude},${currentLocation.longitude})()", null ) } LaunchedEffect(key1 = currentLocation) { destination?.let { location -> state.evaluateJavascript( - "getDirections(${currentLocation.lat},${currentLocation.lng},${location.lat},${location.lng})", + "getDirections(${currentLocation.latitude},${currentLocation.longitude},${location.latitude},${location.longitude})", null ) } diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/presentation/map/MapMapper.kt b/client_taxi_driver/shared/src/commonMain/kotlin/presentation/map/MapMapper.kt index e8b855d84..f85dd7dcc 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/presentation/map/MapMapper.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/presentation/map/MapMapper.kt @@ -1,30 +1,23 @@ package presentation.map import domain.entity.Location -import domain.entity.Order +import domain.entity.Trip -fun Order.toUiState() = OrderInfoUiState( +fun Trip.toUiState() = TripInfoUiState( + id = this.id, passengerName = passengerName, - dropOffAddress = LocationInfoUiState( - addressName = dropOffAddress.addressName, - lat = dropOffAddress.lat, - lng = dropOffAddress.lng, - ), - pickUpAddress = LocationInfoUiState( - addressName = pickUpAddress.addressName, - lat = pickUpAddress.lat, - lng = pickUpAddress.lng, - ), + dropOffLocation = dropOffLocation.toUiState(), + pickUpLocation = pickUpLocation.toUiState(), + dropOffAddress = dropOffAddress, + pickUpAddress = pickUpAddress ) fun Location.toUiState() = LocationInfoUiState( - lat = lat, - lng = lng, - addressName = addressName, + lat = latitude, + lng = longitude, ) fun LocationInfoUiState.toEntity(): Location = Location( - lat = lat, - lng = lng, - addressName = addressName, + latitude = lat, + longitude = lng, ) \ No newline at end of file diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/presentation/map/MapScreen.kt b/client_taxi_driver/shared/src/commonMain/kotlin/presentation/map/MapScreen.kt index 90ecfe951..1818ea742 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/presentation/map/MapScreen.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/presentation/map/MapScreen.kt @@ -49,6 +49,7 @@ class MapScreen : @Composable override fun onRender(state: MapScreenUiState, listener: MapScreenInteractionListener) { + Box( modifier = Modifier.fillMaxSize() ) { @@ -56,11 +57,11 @@ class MapScreen : modifier = Modifier, url = MAP_URL, currentLocation = state.currentLocation.toEntity(), - destination = state.orderInfoUiState.dropOffAddress?.toEntity(), + destination = state.tripInfoUiState.dropOffLocation?.toEntity(), ) BpAppBar( isBackIconVisible = false, - title = "${Resources.strings.mapScreenAppBarTitle}${state.userName}!" + title = "${Resources.strings.mapScreenAppBarTitle}${state.driverName}!" ) { Box( modifier = Modifier @@ -82,20 +83,17 @@ class MapScreen : } MapCardAnimation( modifier = Modifier.align(Alignment.BottomCenter), - visible = state.isLoading, - ) { - FindingRideCard() - } + visible = !state.isNewOrderFound && !state.isAcceptedOrder, + content = { FindingRideCard() } + ) MapCardAnimation( modifier = Modifier.align(Alignment.BottomCenter), visible = state.isNewOrderFound, ) { NewOrderCard( - modifier = Modifier.align( - Alignment.BottomCenter, - ), - state = state.orderInfoUiState, + modifier = Modifier.align(Alignment.BottomCenter,), + state = state.tripInfoUiState, listener = listener, ) } @@ -108,7 +106,7 @@ class MapScreen : modifier = Modifier.align( Alignment.BottomCenter, ), - state = state.orderInfoUiState, + state = state.tripInfoUiState, listener = listener, ) } @@ -203,7 +201,7 @@ class MapScreen : @Composable private fun NewOrderCard( modifier: Modifier = Modifier, - state: OrderInfoUiState, + state: TripInfoUiState, listener: MapScreenInteractionListener, ) { MapCard( @@ -230,7 +228,7 @@ class MapScreen : Text( modifier = Modifier.padding(start = 4.dp), - text = state.pickUpAddress?.addressName ?: "", + text = state.pickUpAddress, color = Theme.colors.contentSecondary, style = Theme.typography.body, ) @@ -256,7 +254,7 @@ class MapScreen : @Composable private fun OrderCard( modifier: Modifier = Modifier, - state: OrderInfoUiState, + state: TripInfoUiState, listener: MapScreenInteractionListener, ) { MapCard( @@ -281,7 +279,7 @@ class MapScreen : style = Theme.typography.caption, ) Text( - text = state.pickUpAddress?.addressName ?: "", + text = state.pickUpAddress, color = Theme.colors.contentPrimary, style = Theme.typography.body, ) @@ -301,7 +299,7 @@ class MapScreen : style = Theme.typography.caption, ) Text( - text = state.dropOffAddress?.addressName ?: "", + text = state.dropOffAddress, color = Theme.colors.contentPrimary, style = Theme.typography.body, ) diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/presentation/map/MapScreenModel.kt b/client_taxi_driver/shared/src/commonMain/kotlin/presentation/map/MapScreenModel.kt index 97c5921ed..35923dac7 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/presentation/map/MapScreenModel.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/presentation/map/MapScreenModel.kt @@ -2,9 +2,9 @@ package presentation.map import cafe.adriel.voyager.core.model.coroutineScope import domain.entity.Location -import domain.entity.Order +import domain.entity.Trip import domain.usecase.IManageLocationUseCase -import domain.usecase.IManageOrderUseCase +import domain.usecase.IManageTripUseCase import domain.usecase.LoginUserUseCase import kotlinx.coroutines.launch import presentation.base.BaseScreenModel @@ -12,21 +12,22 @@ import presentation.base.ErrorState class MapScreenModel( private val loginUserUseCase: LoginUserUseCase, - private val order: IManageOrderUseCase, + private val manageTrip: IManageTripUseCase, private val location: IManageLocationUseCase, ) : BaseScreenModel(MapScreenUiState()), MapScreenInteractionListener { init { - getLiveLocation() findingNewOrder() + getLiveLocation() getUserName() } private fun findingNewOrder() { - tryToExecute( - function = order::foundNewOrder, - onSuccess = ::onFoundNewOrderSuccess, + println("findingNewOrder") + tryToCollect( + function = manageTrip::findNewTrip, + onNewValue = ::onFoundNewOrderSuccess, onError = ::onError ) } @@ -36,24 +37,28 @@ class MapScreenModel( val username = loginUserUseCase.getUsername() updateState { it.copy( - userName = username, + driverName = username, ) } } + println("getUserName: ${state.value.driverName}") } - private fun onFoundNewOrderSuccess(order: Order) { + private fun onFoundNewOrderSuccess(order: Trip) { + println("onFoundNewOrderSuccess: $order") + println("state.value.tripInfoUiState:${state.value.tripInfoUiState}") updateState { it.copy( isLoading = false, isNewOrderFound = true, error = null, - orderInfoUiState = order.toUiState() + tripInfoUiState = order.toUiState() ) } } private fun onError(errorState: ErrorState) { + println("onEeeeeeeeeeeerror: $errorState") updateState { it.copy( isLoading = false, @@ -72,60 +77,78 @@ class MapScreenModel( } private fun onGetLiveLocationSuccess(location: Location) { - updateState { - it.copy( + updateState { mapScreenUiState -> + mapScreenUiState.copy( isLoading = true, error = null, currentLocation = location.toUiState() - ) + ).also { + if (it.isAcceptedOrder) { + sendLocationIfTripAccepted( + it.currentLocation.toEntity(), + it.tripInfoUiState.id + ) + } + } } } + private fun sendLocationIfTripAccepted(location: Location, tripId: String) { + tryToExecute( + function = { manageTrip.updateTripLocation(location, tripId) }, + onSuccess = { println("update trip location success") }, + onError = ::onError, + ) + } + override fun onClickAccept() { - updateState { - it.copy( - isLoading = false, - error = null, - isNewOrderFound = false, - isAcceptedOrder = true, + updateState { mapScreenUiState -> + mapScreenUiState.copy( + isLoading = false, error = null, + isNewOrderFound = false, isAcceptedOrder = true, ) } + updateTrip() } override fun onClickCancel() { updateState { it.copy( isLoading = true, + error = null, isNewOrderFound = false, isAcceptedOrder = false, - error = null, - orderInfoUiState = OrderInfoUiState() + tripInfoUiState = TripInfoUiState() ) } findingNewOrder() } override fun onClickArrived() { - updateState { - it.copy( - isLoading = false, - error = null, - orderInfoUiState = it.orderInfoUiState.copy( - isArrived = true - ) + updateState { it.copy(isLoading = false, error = null, + tripInfoUiState = it.tripInfoUiState.copy(isArrived = true) ) } + updateTrip() + } + + private fun updateTrip() { + println("///////////////////////trip ID:${state.value.tripInfoUiState.id}///////////////////////") + tryToExecute( + function = { manageTrip.updateTripStatus(state.value.tripInfoUiState.id) }, + onSuccess = { println("update trip success") }, + onError = ::onError + ) } override fun onClickDropOff() { updateState { it.copy( - isLoading = true, - isAcceptedOrder = false, - error = null, - orderInfoUiState = OrderInfoUiState() + isLoading = true, error = null, + isAcceptedOrder = false, tripInfoUiState = TripInfoUiState() ) } + updateTrip() findingNewOrder() } diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/presentation/map/MapScreenUiState.kt b/client_taxi_driver/shared/src/commonMain/kotlin/presentation/map/MapScreenUiState.kt index 3a37777f4..76dc3084c 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/presentation/map/MapScreenUiState.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/presentation/map/MapScreenUiState.kt @@ -3,24 +3,26 @@ package presentation.map import presentation.base.ErrorState data class MapScreenUiState( - val isLoading: Boolean = false, + val isLoading: Boolean = true, val error: ErrorState? = null, - val userName: String = "", + val driverName: String = "", val currentLocation: LocationInfoUiState = LocationInfoUiState(), val isNewOrderFound: Boolean = false, val isAcceptedOrder: Boolean = false, - val orderInfoUiState: OrderInfoUiState = OrderInfoUiState(), + val tripInfoUiState: TripInfoUiState = TripInfoUiState(), ) -data class OrderInfoUiState( +data class TripInfoUiState( + val id: String = "", val passengerName: String = "", - val pickUpAddress: LocationInfoUiState? = null, - val dropOffAddress: LocationInfoUiState? = null, + val pickUpLocation: LocationInfoUiState? = null, + val dropOffLocation: LocationInfoUiState? = null, + val pickUpAddress: String = "", + val dropOffAddress: String = "", val isArrived: Boolean = false, ) data class LocationInfoUiState( val lat: Double = 0.0, val lng: Double = 0.0, - val addressName: String = "", ) \ No newline at end of file diff --git a/client_taxi_driver/shared/src/commonMain/kotlin/presentation/resources/StringResources.kt b/client_taxi_driver/shared/src/commonMain/kotlin/presentation/resources/StringResources.kt index bfe7c192c..57b2216ef 100644 --- a/client_taxi_driver/shared/src/commonMain/kotlin/presentation/resources/StringResources.kt +++ b/client_taxi_driver/shared/src/commonMain/kotlin/presentation/resources/StringResources.kt @@ -31,4 +31,5 @@ data class StringResources( val pickUp: String = "Pick up", val dropOff: String = "Drop off", val close: String = "Close", -) + val accessDeniedMessage: String = "To continue, Please access location permission", + )