-
-
Save MrModest/9bdd7651cc62d240f3f5874473bf6e98 to your computer and use it in GitHub Desktop.
/* | |
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 | |
) | |
) | |
} |
For sync, each item (and derivatives) should have 'syncData` property with following fields: createdDate, updatedDate, createdDeviceName, updatedDeviceName.
Keep an individual check-list per trip item. And then provide with one accumulated check-list.
For example, under the flight you can have "take passport" and "check hand luggage restrictions compliancy". But for a commute from airport to the hotel - "take discount voucher for airport rail express that I handed over from my friend".
And all 3 stuff user can see in one combined place as requirements before the trip starts
---
title: Antalya (Fethiye)
start:
date: 2024-02-02
timezone: UTC+1
end:
date: 2024-02-13
timezone: UTC+1
items:
- id: d70e08f8-6504-4400-a0d4-15f338f8a043
type: PublicTansport
note: Commute from Home to the hotel in Leipzig
attachments: []
metadata:
startPoint:
country: Germany
city: Berlin
address: Kastanienallee 21, 12500 Berlin
mapPoint:
longitude: '72.4544810685576'
latitude: '41.51634385867111'
endPoint:
country: Germany
city: Leipzig
address: Leipzig Hbf
mapPoint:
longitude: '92.4544810685576'
latitude: '93.51634385867111'
departure:
date: 2024-02-02
time: 19:45
timezone: UTC+1
arrival:
date: 2024-02-02
time: 22:43
timezone: UTC+1
approximateDuration: 1h 13 min
commuteDescription: BUS 165 -> S 45 -> RE 5(3345)
- id: ff6476ec-da38-4c74-9bb6-df33f2e382ff
type: Hotel
note: Hotel in Leipzig
attachments:
- name: Booking_1234.pdf
link: https://drive.google.com/path/to/file.pdf
metadata:
hotelName:
address:
country: Germany
city: Leipzig
address: Kastanstraße 42, 12211 Leipzig
mapPoint:
longitude: '62.4544456785576'
latitude: '33.51634444867111'
reservationOn:
name: Katrin Mustermann
contact: +49 177 1234567
note: sample note
guests:
- name: Katrin Mustermann
contact: +49 177 1234567
note: sample note
- name: Mark Mustermann
contact: +49 177 2345678
numberOfRooms: 1
checkIn:
date: 2024-02-02
time: 22:50
timezone: UTC+1
checkOut:
date: 2024-02-03
time: 15:00
timezone: UTC+1
Timeline design guildlines: https://experience.sap.com/fiori-design-android/timeline-view/
Instead of the month in the gray line, we can show timezone change warning

P.S.: Made in Lunacy
Idea: add expense array to all TripItems with 4 fields: amount, currency, category (food/transportation, etc.) and note.