Bimba.git

ref: 8a26cf3ec1de289220ded47773a247143eaeafbe

app/src/main/java/xyz/apiote/bimba/czwek/repo/Departure.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
package xyz.apiote.bimba.czwek.repo

import android.content.Context
import android.text.format.DateUtils
import xyz.apiote.bimba.czwek.R
import xyz.apiote.bimba.czwek.api.AlertV1
import xyz.apiote.bimba.czwek.api.DepartureV1
import xyz.apiote.bimba.czwek.api.DepartureV2
import xyz.apiote.bimba.czwek.api.Time
import xyz.apiote.bimba.czwek.api.UnknownResourceVersion
import java.time.Instant
import java.time.ZoneId
import java.time.ZonedDateTime
import java.time.temporal.ChronoUnit

data class Alert(
	val header: String,
	val description: String,
	val url: String,
	val cause: ULong,  // todo [3.1] enum
	val effect: ULong  // todo [3.1] enum
) {
	constructor(a: AlertV1) : this(a.header, a.Description, a.Url, a.Cause, a.Effect)
}

data class StopDepartures(
	val departures: List<Departure>,
	val stop: Stop,
	val alerts: List<Alert>
)

data class Departure(
	val ID: String,
	val time: Time,
	val status: ULong,
	val isRealtime: Boolean,
	val vehicle: Vehicle,
	val boarding: UByte
) {

	constructor(d: DepartureV1) : this(
		d.ID,
		d.time,
		d.status,
		d.isRealtime,
		Vehicle(d.vehicle),
		d.boarding
	)

	constructor(d: DepartureV2) : this(
		d.ID,
		d.time,
		d.status,
		d.isRealtime,
		Vehicle(d.vehicle),
		d.boarding
	)

	fun statusText(context: Context?): String {
		val now = Instant.now().atZone(ZoneId.systemDefault())
		val departureTime = ZonedDateTime.of(
			now.year, now.monthValue, now.dayOfMonth,
			time.Hour.toInt(), time.Minute.toInt(), time.Second.toInt(), 0, ZoneId.of(time.Zone)
		).plus(time.DayOffset.toLong(), ChronoUnit.DAYS)
		return when (val r = status.toUInt()) {
			0u -> DateUtils.getRelativeTimeSpanString(
				departureTime.toEpochSecond() * 1000,
				now.toEpochSecond() * 1000,
				DateUtils.MINUTE_IN_MILLIS,
				DateUtils.FORMAT_ABBREV_RELATIVE
			).toString()

			1u -> context?.getString(R.string.departure_momentarily) ?: "momentarily"
			2u -> context?.getString(R.string.departure_now) ?: "now"
			3u -> context?.getString(R.string.departure_departed) ?: "departed"
			else -> throw UnknownResourceVersion("VehicleStatus/$r", 1u)
		}
	}

	fun timeString(context: Context): String {
		return if (isRealtime) {
			context.getString(
				R.string.at_time_realtime, time.Hour.toInt(), time.Minute.toInt(), time.Second.toInt()
			)
		} else {
			context.getString(R.string.at_time, time.Hour.toInt(), time.Minute.toInt())
		}
	}

	fun boardingText(context: Context): String {
		// todo [3.x] probably should take into account (on|off)-boarding only, on demand
		return when {
			boarding == (0b0000_0000).toUByte() -> context.getString(R.string.no_boarding)
			boarding.and(0b0011_0011u) == (0b0000_0001).toUByte() -> context.getString(R.string.on_boarding)
			boarding.and(0b0011_0011u) == (0b0001_0000).toUByte() -> context.getString(R.string.off_boarding)
			boarding.and(0b0011_0011u) == (0b0001_0001).toUByte() -> context.getString(R.string.boarding)
			else -> context.getString(R.string.on_demand)
		}
	}
}