Skip to content

Instantly share code, notes, and snippets.

@MrModest
Last active April 7, 2024 10:53
Show Gist options
  • Save MrModest/9bdd7651cc62d240f3f5874473bf6e98 to your computer and use it in GitHub Desktop.
Save MrModest/9bdd7651cc62d240f3f5874473bf6e98 to your computer and use it in GitHub Desktop.
The model structure for potential trip planner app like 'tripit.com' or 'travelerbuddy.com'.
/*
The idea behind it to make something like 'TravelerBuddy', but simplier. Easy to write and easy to read.
Just to have a chronological plan of points of interests and all crucial parts of journey. Also, to have all crucial info handy.
Backend is as simple as a CRUD (if you aren't planned to implement multi-user/authorization support).
The most work is expected on Frondend side. It needs to provide a convenient and very specific form for each TripItem.
And also draw a "graph" like below.
No need to support autocompletion for Address. It's enought to support "open in Map" feature. So even no needs in having a build-in map view.
Since there's no much commons between trip items (as well as no joins between them),
it could make sense to use a NoSQL rather than have a ton of nullable columns in one RDS table.
10:00 -|- Leave the house
|
10:30 -|- Departure from bus station
|
11:30 -|- Arrival to BER airport
|
|
13:30 -|- Flight departure
...
*/
data class TimezonedDateTime ( // very important to store timezone since trips could be between timezones
val datetime: LocalDateTime,
val localTz: TimeZone
) {
fun toTz(val tz: TimeZone): LocalDateTime { // to show time according to the current timezone of the viewer
// ...
}
}
data class Trip( // simple container for trip items
val title: String,
val items: List<TripItem>
val start: TimezonedDateTime,
val end: TimezonedDateTime
)
data class DocumentLink(
val name: String,
val link: String // GoogleDrive Link, for example
)
data class TimelinePoint (
val name: String,
val time: TimezonedDatetime,
val address: Address
)
interface TripItem { // abstract entity to represent different type of components of the trip
val id: UUID,
val note: String, // markdown - to support reference links
val attachments: List<DocumentLink>,
val timelinePoints: List<TimelinePoint>
} // all these fields should be represented in any inherited classes, ommited just for simplisity
data class Person ( // could as participant of the trip as well as any involved person.
val name: String,
val contact: String,
val note: String
)
data class MapPoint(
val longitude: String,
val latitude: String
)
data class Address(
val country: String,
val city: String,
val address: String,
val mapPoint: MapPoint
) {
val None: Address = Address("None", "None", "None", MapPoint("0", "0"))
}
enum class AirportCode {
LEJ, AYT //, etc..
}
data class Airport(
val code: AirportCode,
val name: String,
val address: Address
)
data class AirportPoint(
val airport: Airport,
val terminal: String,
val gate: String,
val time: TimezonedDateTime,
)
data class Flight: TripItem (
val flightNumber: String,
val carrier: String,
val bookingCode: String,
val seat: String,
val passengers: List<Person>,
val departure: AirportPoint,
val arrival: AirportPoint
// (?) connected (next) flight with type `Flight`
// (?) return flight with type `Flight`
// similar for LongLandTransfer
) {
override val timelinePoints: List<TimelinePoint>
get = listOf(
TimelinePoint(
"Flight from [${departure.airport.code}]",
departure.time,
departure.airport.address
),
TimelinePoint(
"Flight to [${arrival.airport.code}]",
arrival.time,
arrival.airport.address
)
)
}
data class Hotel: TripItem (
val name: String,
val address: Address,
val reservationOn: Person, // the person who need to contact with hotel
val guests: List<Person>,
val numberOfRooms: Int,
val contacts: String // phone; email
val checkIn: TimezonedDateTime, // it's about planned time, not available from hotel
val checkOut: TimezonedDateTime // for example, hotel offers check out from 11:00, but you want to leave at 8:00. So here should be set 8:00.
) {
override val timelinePoints: List<TimelinePoint>
get = listOf(
TimelinePoint(
"Check-In [${name}]",
checkIn,
address
),
TimelinePoint(
"Check-Out [${name}]",
checkIn,
address
)
)
}
data class PublicTransportConnections( // BUS 165 -> S 45 -> RE 5(3345)
val time: TimezonedDateTime, // [{ time: "2024-01-10 09:00", decriptions: "BUS 165" }, { time: "2024-01-10 10:00", decriptions: "S 45" }, { time: "2024-01-10 11:30", decriptions: "RE 5(3345)" }]
val description: String,
val point: Address = Address.None // no need to bother filling it every time
)
data class PublicTransport: TripItem ( // includes all potential changes, so use only one item even if you need to change from bus to train and then to tram.
val startPoint: Address,
val endPoint: Address,
val departure: TimezonedDateTime, // could be approximate
val arrival: TimezonedDateTime, // could be approximate
val approximateDuration: String, // 1h 13 min
val connections: PublicTransportConnections[], // optional
) {
override val timelinePoints: List<TimelinePoint>
get = listOf(
TimelinePoint(
"Start commute to '${endPoint.address}' [${approximateDuration}]",
departure,
startPoint
),
*connections.map {
TimelinePoint(
it.description,
it.time,
it.point
)
},
TimelinePoint(
"End commute to '${endPoint.address}' [${approximateDuration}]",
arrival,
endPoint
)
)
}
enum class TransferType {
Bus, Train, Ferry
}
data class LongLandTransfer: TripItem ( // it's about long transfers by land like train or intercity buses. Somethings where punctuality is crucial
val transferType: TransferType,
val transferNumber: String,
val carrier: String,
val contacts: String,
val passengers: List<Person>
val pickUpTime: TimezonedDateTime,
val pickUpLocation: Address,
val dropOffTime: TimezonedDateTime,
val dropOffLocation: Address
) {
override val timelinePoints: List<TimelinePoint>
get = listOf(
TimelinePoint(
"[${carrier}] ${transferType} from ${pickUpLocation.address}",
pickUpTime,
pickUpLocation
),
TimelinePoint(
"[${carrier}] ${transferType} to ${dropOffLocation.address}",
dropOffTime,
dropOffLocation
)
)
}
data class GeneralPoint: TripItem ( // any point you want to mark on your journey map. For example, the very first and very last points of your trip.
val name: String,
val address: Address,
val beHereAt: TimezonedDateTime
) {
override val timelinePoints: List<TimelinePoint>
get = listOf(
TimelinePoint(
"Be at ${address.address}",
beHereAt,
address
)
)
}
data class ObservationEvent: TripItem ( // not related to us, but important to observe, like friend's flight
val name: String,
val startTime: TimezonedDateTime,
val endTime: TimezonedDateTime,
val address: Address?
) {
override val timelinePoints: List<TimelinePoint>
get = listOf(
TimelinePoint(
"Start [${name}]",
startTime,
address
),
TimelinePoint(
"End [${name}]",
endTime,
address
)
)
}
data class Visiting: TripItem ( // visiting friends or places
val description: String,
val startTime: TimezonedDateTime,
val endTime: TimezonedDateTime,
val address: Address
val persons: List<Person> // relevant if visiting someone, empty if no ther people involved
) {
override val timelinePoints: List<TimelinePoint>
get = listOf(
TimelinePoint(
"Start [${description}]",
startTime,
address
),
TimelinePoint(
"End [${description}]",
endTime,
address
)
)
}
@MrModest
Copy link
Author

MrModest commented Apr 7, 2024

Timeline design guildlines: https://experience.sap.com/fiori-design-android/timeline-view/

image

Instead of the month in the gray line, we can show timezone change warning
image

@MrModest
Copy link
Author

MrModest commented Apr 7, 2024

image

P.S.: Made in Lunacy

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment