ref: f7001336c32940112f2229735bd2b5135826b8ba
app/src/main/java/xyz/apiote/bimba/czwek/api/transitousJourney.kt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
// SPDX-FileCopyrightText: Adam Evyčędo // // SPDX-License-Identifier: GPL-3.0-or-later package xyz.apiote.bimba.czwek.api import android.content.Context import android.util.Log import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import okhttp3.OkHttpClient import xyz.apiote.bimba.czwek.R import xyz.apiote.bimba.czwek.api.transitous.api.RoutingApi import xyz.apiote.bimba.czwek.api.transitous.model.PedestrianProfile import xyz.apiote.bimba.czwek.repo.Colour import xyz.apiote.bimba.czwek.repo.CongestionLevel import xyz.apiote.bimba.czwek.repo.Event import xyz.apiote.bimba.czwek.repo.Journey import xyz.apiote.bimba.czwek.repo.JourneyParams import xyz.apiote.bimba.czwek.repo.Leg import xyz.apiote.bimba.czwek.repo.LineStub import xyz.apiote.bimba.czwek.repo.LineType import xyz.apiote.bimba.czwek.repo.OccupancyStatus import xyz.apiote.bimba.czwek.repo.Place import xyz.apiote.bimba.czwek.repo.Position import xyz.apiote.bimba.czwek.repo.TimeReference import xyz.apiote.bimba.czwek.repo.TrafficResponseException import xyz.apiote.bimba.czwek.repo.Vehicle import xyz.apiote.bimba.czwek.units.Metre import xyz.apiote.bimba.czwek.units.Mps import xyz.apiote.bimba.czwek.units.Second import java.time.Duration import java.time.ZoneId import java.time.ZonedDateTime suspend fun getJourney( from: Place, to: Place, params: JourneyParams, context: Context ): List<Journey> { if (!isNetworkAvailable(context)) { throw TrafficResponseException(0, "", Error(0, R.string.error_offline, R.drawable.error_net)) } return withContext(Dispatchers.IO) { Log.d("Journeys", "from: ${from.planString()}") Log.d("Journeys", "to: ${to.planString()}") Log.d( "Journeys", "params: $params; time: ${ ZonedDateTime.of(params.getSafeDate(), params.getSafeTime(), ZoneId.systemDefault()) .toOffsetDateTime() }" ) val client = OkHttpClient.Builder() .callTimeout(Duration.ofSeconds(60)) .readTimeout(Duration.ofSeconds(60)) .writeTimeout(Duration.ofSeconds(60)) .connectTimeout(Duration.ofSeconds(60)).build() val response = RoutingApi(client = client).plan( from.planString(), to.planString(), maxTransfers = null, maxTravelTime = null, time = ZonedDateTime.of(params.getSafeDate(), params.getSafeTime(), ZoneId.systemDefault()) .toOffsetDateTime(), arriveBy = params.timeReference == TimeReference.ARRIVE_BY, requireBikeTransport = params.bicycle, pedestrianProfile = if (params.wheelchairAccessible) PedestrianProfile.WHEELCHAIR else PedestrianProfile.FOOT, ) Log.d("Journeys", "${response.itineraries}") response.itineraries.map { val legs: List<Leg> = it.legs.map { Leg( Event( it.tripId ?: "", null, Time.fromOffsetTime(it.startTime, ZoneId.systemDefault()), 0u, it.realTime, Vehicle( it.tripId ?: "", Position(0.0, 0.0), 0u, Mps(0), LineStub( it.routeShortName ?: "", // TODO is it nullable, yes e.g. for transit LineType.fromTransitous2(it.mode), Colour.fromHex(it.routeColor) ), it.headsign ?: "", // TODO is it nullable, yes e.g. for transit CongestionLevel.UNKNOWN, OccupancyStatus.UNKNOWN ), boarding = 0xffu, alerts = emptyList(), exact = true, terminusArrival = false ), Event( it.tripId ?: "", Time.fromOffsetTime(it.endTime, ZoneId.systemDefault()), null, 0u, it.realTime, Vehicle( it.tripId ?: "", Position(0.0, 0.0), 0u, Mps(0), LineStub( it.routeShortName ?: "", // TODO is it nullable, yes e.g. for transit LineType.fromTransitous2(it.mode), Colour.fromHex(it.routeColor) ), it.headsign ?: "", // TODO is it nullable, yes e.g. for transit CongestionLevel.UNKNOWN, OccupancyStatus.UNKNOWN ), boarding = 0xffu, alerts = emptyList(), exact = true, terminusArrival = false ), Place(it.from), Place(it.to), it.agencyName, it.distance?.toDouble()?.let { Metre(it) }, Second(it.duration), (it.intermediateStops ?: emptyList()).map { Place(it) }, decode(it.legGeometry.points) /*it.rental, it.steps,*/ ) } Journey( it.startTime.atZoneSameInstant(ZoneId.systemDefault()), it.endTime.atZoneSameInstant( ZoneId.systemDefault() ), legs ) } } } /* The following piece of code © Google, Apache License, Version 2.0 from https://github.com/googlemaps/android-maps-utils/blob/main/library/src/main/java/com/google/maps/android/PolyUtil.java with changes to decode with precision 7 */ fun decode(encodedPath: String): MutableList<Position> { val len = encodedPath.length val path: MutableList<Position> = ArrayList<Position>() var index = 0 var lat = 0 var lng = 0 while (index < len) { var result = 1 var shift = 0 var b: Int do { b = encodedPath[index++].code - 63 - 1 result += b shl shift shift += 5 } while (b >= 0x1f) lat += if ((result and 1) != 0) (result shr 1).inv() else (result shr 1) result = 1 shift = 0 do { b = encodedPath[index++].code - 63 - 1 result += b shl shift shift += 5 } while (b >= 0x1f) lng += if ((result and 1) != 0) (result shr 1).inv() else (result shr 1) path.add(Position(lat * 1e-7, lng * 1e-7)) } return path } |