From 00287ec7adf7ac231d9247331b30bd5d9a3ae25a Mon Sep 17 00:00:00 2001 From: Michael Angelo Reyes Date: Sat, 9 Aug 2025 01:56:12 +0800 Subject: [PATCH 1/6] [24369] - create a NonClickableInfoWindowAdapter and apply to markers that don't need adapters to be clicked --- .../tripkit/ui/map/CarParkPOILocation.kt | 4 +- .../tripkit/ui/map/FacilityPOILocation.kt | 4 +- .../skedgo/tripkit/ui/map/StopPOILocation.kt | 4 +- .../adapter/NonClickableInfoWindowAdapter.kt | 39 +++++++++++++++++++ .../tripkit/ui/map/home/TripKitMapFragment.kt | 17 +++++++- 5 files changed, 62 insertions(+), 6 deletions(-) create mode 100644 TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/map/adapter/NonClickableInfoWindowAdapter.kt diff --git a/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/map/CarParkPOILocation.kt b/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/map/CarParkPOILocation.kt index 27526cfe..22b5f439 100644 --- a/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/map/CarParkPOILocation.kt +++ b/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/map/CarParkPOILocation.kt @@ -7,7 +7,7 @@ import com.google.android.gms.maps.model.MarkerOptions import com.skedgo.tripkit.common.model.location.Location import com.skedgo.tripkit.parkingspots.models.Parking import com.skedgo.tripkit.ui.map.adapter.StopInfoWindowAdapter -import com.skedgo.tripkit.ui.map.adapter.ViewableInfoWindowAdapter +import com.skedgo.tripkit.ui.map.adapter.NonClickableInfoWindowAdapter import com.skedgo.tripkit.ui.model.PodLocation import com.skedgo.tripkit.ui.tracking.EventTracker import com.squareup.otto.Bus @@ -22,7 +22,7 @@ class CarParkPOILocation(val parking: Parking) : IMapPoiLocation { CreateMarkerForParking.execute(resources, parking) override fun getInfoWindowAdapter(context: Context): StopInfoWindowAdapter { - return ViewableInfoWindowAdapter(LayoutInflater.from(context)) + return NonClickableInfoWindowAdapter(LayoutInflater.from(context)) } diff --git a/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/map/FacilityPOILocation.kt b/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/map/FacilityPOILocation.kt index cda47ba1..0eaf9c30 100644 --- a/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/map/FacilityPOILocation.kt +++ b/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/map/FacilityPOILocation.kt @@ -7,7 +7,7 @@ import com.google.android.gms.maps.model.MarkerOptions import com.skedgo.tripkit.common.model.location.Location import com.skedgo.tripkit.data.database.locations.facility.FacilityLocationEntity import com.skedgo.tripkit.ui.map.adapter.StopInfoWindowAdapter -import com.skedgo.tripkit.ui.map.adapter.ViewableInfoWindowAdapter +import com.skedgo.tripkit.ui.map.adapter.NonClickableInfoWindowAdapter import com.skedgo.tripkit.ui.model.PodLocation import com.skedgo.tripkit.ui.tracking.EventTracker import com.squareup.otto.Bus @@ -24,7 +24,7 @@ class FacilityPOILocation( CreateMarkerFoFacility.execute(resources, facilityLocationEntity) override fun getInfoWindowAdapter(context: Context): StopInfoWindowAdapter { - return ViewableInfoWindowAdapter(LayoutInflater.from(context)) + return NonClickableInfoWindowAdapter(LayoutInflater.from(context)) } diff --git a/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/map/StopPOILocation.kt b/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/map/StopPOILocation.kt index f2237ca9..c74176f9 100644 --- a/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/map/StopPOILocation.kt +++ b/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/map/StopPOILocation.kt @@ -2,10 +2,12 @@ package com.skedgo.tripkit.ui.map import android.content.Context import android.content.res.Resources +import android.view.LayoutInflater import com.google.android.gms.maps.model.MarkerOptions import com.skedgo.tripkit.common.model.location.Location import com.skedgo.tripkit.common.model.stop.ScheduledStop import com.skedgo.tripkit.data.locations.StopsFetcher +import com.skedgo.tripkit.ui.map.adapter.NonClickableInfoWindowAdapter import com.skedgo.tripkit.ui.map.adapter.StopInfoWindowAdapter import com.skedgo.tripkit.ui.tracking.EventTracker import com.squareup.otto.Bus @@ -25,7 +27,7 @@ class StopPOILocation( } override fun getInfoWindowAdapter(context: Context): StopInfoWindowAdapter? { - return stopInfoWindowAdapter + return NonClickableInfoWindowAdapter(LayoutInflater.from(context)) } override fun toLocation(): Location { diff --git a/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/map/adapter/NonClickableInfoWindowAdapter.kt b/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/map/adapter/NonClickableInfoWindowAdapter.kt new file mode 100644 index 00000000..456b19b7 --- /dev/null +++ b/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/map/adapter/NonClickableInfoWindowAdapter.kt @@ -0,0 +1,39 @@ +package com.skedgo.tripkit.ui.map.adapter + +import android.view.LayoutInflater +import android.view.View +import com.google.android.gms.maps.model.Marker +import com.skedgo.tripkit.ui.map.SimpleCalloutView +import javax.inject.Inject + +class NonClickableInfoWindowAdapter @Inject constructor(private val inflater: LayoutInflater) : + StopInfoWindowAdapter { + private var view: SimpleCalloutView? = null + + override fun getInfoContents(marker: Marker): View { + if (view == null) { + view = SimpleCalloutView.create(inflater) + } + assert(view != null) + view!!.setTitle(marker.title) + view!!.setSnippet(marker.snippet) + // Explicitly hide the right image (arrow icon) for non-clickable POIs + view!!.setRightImage(0) // This will hide the image via ViewUtils.setImage + return view!! + } + + override fun windowInfoHeightInPixel(marker: Marker): Int { + return if (view != null) { + view!!.height + } else { + 0 + } + } + + override fun onInfoWindowClosed(marker: Marker) { + } + + override fun getInfoWindow(marker: Marker): View? { + return null + } +} diff --git a/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/map/home/TripKitMapFragment.kt b/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/map/home/TripKitMapFragment.kt index 9c18829c..0b42fe0e 100644 --- a/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/map/home/TripKitMapFragment.kt +++ b/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/map/home/TripKitMapFragment.kt @@ -44,8 +44,11 @@ import com.skedgo.tripkit.ui.TripKitUI import com.skedgo.tripkit.ui.core.addTo import com.skedgo.tripkit.ui.core.module.HomeMapFragmentModule import com.skedgo.tripkit.ui.data.toLocation +import com.skedgo.tripkit.ui.map.CarParkPOILocation +import com.skedgo.tripkit.ui.map.FacilityPOILocation import com.skedgo.tripkit.ui.map.GenericIMapPoiLocation import com.skedgo.tripkit.ui.map.IMapPoiLocation +import com.skedgo.tripkit.ui.map.StopPOILocation import com.skedgo.tripkit.ui.map.LocationEnhancedMapFragment import com.skedgo.tripkit.ui.map.MapCameraController import com.skedgo.tripkit.ui.map.MapMarkerUtils @@ -888,7 +891,7 @@ class TripKitMapFragment : LocationEnhancedMapFragment(), OnInfoWindowClickListe poiMarkers.setOnInfoWindowClickListener { marker: Marker -> if (onInfoWindowClickListener != null) { val poiLocation = marker.tag as IMapPoiLocation? - if (poiLocation != null) { + if (poiLocation != null && isPoiWindowAdapterClickable(poiLocation)) { onInfoWindowClickListener!!.onInfoWindowClick(poiLocation.toLocation()) } } @@ -947,6 +950,18 @@ class TripKitMapFragment : LocationEnhancedMapFragment(), OnInfoWindowClickListe map?.let { cameraController.moveToPolygonBounds(it, polygon) } } + /** + * Check if a POI location should be clickable based on its type + */ + private fun isPoiWindowAdapterClickable(poiLocation: IMapPoiLocation): Boolean { + return when (poiLocation) { + is StopPOILocation -> false + is CarParkPOILocation -> false + is FacilityPOILocation -> false + else -> true + } + } + companion object { private fun asMarkerIcon(mode: SelectionType): BitmapDescriptor { return if (mode === SelectionType.DEPARTURE) { From 47e9a5df6e622331da7b53d4b3a6b0b03a4fc948 Mon Sep 17 00:00:00 2001 From: Michael Angelo Reyes Date: Tue, 12 Aug 2025 14:20:37 +0800 Subject: [PATCH 2/6] [24391] - control the map markers for stops and map camera when timetable service details screen shows --- .../tripkit/ui/map/home/TripKitMapFragment.kt | 6 +- .../ui/timetables/TimetableMapContributor.kt | 75 +++++++++++++++++-- 2 files changed, 74 insertions(+), 7 deletions(-) diff --git a/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/map/home/TripKitMapFragment.kt b/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/map/home/TripKitMapFragment.kt index 0b42fe0e..dec8fe88 100644 --- a/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/map/home/TripKitMapFragment.kt +++ b/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/map/home/TripKitMapFragment.kt @@ -935,10 +935,14 @@ class TripKitMapFragment : LocationEnhancedMapFragment(), OnInfoWindowClickListe transportModes = it } - poiMarkers?.clear() viewModel.showMarkers.set(show) if (show) { + tripLocationMarkers?.showAll() + poiMarkers?.showAll() loadMarkers() + } else { + tripLocationMarkers?.hideAll() + poiMarkers?.hideAll() } } diff --git a/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/timetables/TimetableMapContributor.kt b/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/timetables/TimetableMapContributor.kt index 507fca8f..7a656e90 100644 --- a/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/timetables/TimetableMapContributor.kt +++ b/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/timetables/TimetableMapContributor.kt @@ -22,6 +22,7 @@ import com.google.android.gms.maps.model.Marker import com.google.android.gms.maps.model.MarkerOptions import com.google.android.gms.maps.model.Polyline import com.google.android.gms.maps.model.PolylineOptions +import com.skedgo.rxtry.printThrowableStackTrace import com.skedgo.rxtry.subscribeWithErrorHandling import com.skedgo.tripkit.common.model.stop.ScheduledStop import com.skedgo.tripkit.common.model.stop.ServiceStop @@ -155,12 +156,15 @@ class TimetableMapContributor(val fragment: Fragment) : TripKitMapContributor { val marker = map.addMarker(first) stopCodesToMarkerMap[second!!] = marker } + fitAllMapElementsToBounds() } ) - autoDisposable.add(viewModel.viewPort - .subscribeWithErrorHandling { coordinates: List? -> this.centerMapOver(map, coordinates) }) +// autoDisposable.add(viewModel.viewPort +// .subscribeWithErrorHandling { coordinates: List? -> +// this.centerMapOver(map, coordinates) } +// ) autoDisposable.add(viewModel.drawServiceLine .subscribeWithErrorHandling { polylineOptions: List -> @@ -179,10 +183,7 @@ class TimetableMapContributor(val fragment: Fragment) : TripKitMapContributor { } } - val bounds = builder.build() - val padding = 50 // Optional padding around the bounds - val cameraUpdate = CameraUpdateFactory.newLatLngBounds(bounds, padding) - map.animateCamera(cameraUpdate) + fitAllMapElementsToBounds() }) autoDisposable.add(viewModel.realtimeVehicle @@ -192,6 +193,7 @@ class TimetableMapContributor(val fragment: Fragment) : TripKitMapContributor { } else { setRealTimeVehicle(null) // Handle empty OptionalCompat } + fitAllMapElementsToBounds() }) } @@ -419,4 +421,65 @@ class TimetableMapContributor(val fragment: Fragment) : TripKitMapContributor { fun getMapPreviousPosition(): CameraPosition? { return previousCameraPosition } + + private fun fitAllMapElementsToBounds( + paddingPx: Int = 160, + includeRealtimeVehicle: Boolean = true, + singlePointZoom: Float = 16f + ) { + val map = googleMap ?: return + + val builder = LatLngBounds.Builder() + var count = 0 + var firstPoint: LatLng? = null + + // 1) All stop markers + for (marker in stopCodesToMarkerMap.values) { + val p = marker.position + builder.include(p) + if (count == 0) firstPoint = p + count++ + } + + // 2) All polyline points + for (poly in serviceLines) { + for (p in poly.points) { + builder.include(p) + if (count == 0) firstPoint = p + count++ + } + } + + // 3) Realtime vehicle marker + if (includeRealtimeVehicle) { + realTimeVehicleMarker?.position?.let { p -> + builder.include(p) + if (count == 0) firstPoint = p + count++ + } + } + + if (count == 0) return // nothing to show + + try { + if (count == 1) { + // Only one point -> just zoom to it + map.animateCamera(CameraUpdateFactory.newLatLngZoom(firstPoint!!, singlePointZoom)) + } else { + // Multiple points -> fit bounds + val bounds = builder.build() + try { + map.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, paddingPx)) + } catch (_: IllegalStateException) { + // Fallback if called before map has size; post to the view to retry + fragment.view?.post { + map.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, paddingPx)) + } + } + } + } catch (e: Exception) { + e.printThrowableStackTrace() + } + } + } \ No newline at end of file From ccdd83e4f282aee8cb2ba27d0e00b9945ad4463a Mon Sep 17 00:00:00 2001 From: Michael Angelo Reyes Date: Thu, 14 Aug 2025 16:43:36 +0800 Subject: [PATCH 3/6] [24388] - add manager to manage time format detection and apply checking and formatting across screens that uses date and time --- .../tripkit/ui/dialog/GenericListItem.kt | 24 +++++++ .../TKUIDateTimePickerDialogFragment.kt | 6 +- .../tripkit/ui/timetables/GetRealtimeText.kt | 5 +- .../options/RoutingTimeViewModelMapper.kt | 7 +- .../TripPreviewPagerItemViewModel.kt | 47 ++++++++++--- .../ui/tripresults/TripResultListFragment.kt | 23 +++++-- .../com/skedgo/tripkit/ui/utils/DateUtils.kt | 6 +- .../ui/utils/SystemTimeFormatManager.kt | 69 +++++++++++++++++++ .../skedgo/tripkit/ui/utils/TimeTagUtils.kt | 4 +- .../ui/utils/TripSegmentUIExtension.kt | 20 +++++- .../options/RoutingTimeViewModelMapperTest.kt | 17 ++++- 11 files changed, 203 insertions(+), 25 deletions(-) create mode 100644 TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/utils/SystemTimeFormatManager.kt diff --git a/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/dialog/GenericListItem.kt b/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/dialog/GenericListItem.kt index 18ce1688..8e5aab27 100644 --- a/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/dialog/GenericListItem.kt +++ b/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/dialog/GenericListItem.kt @@ -6,6 +6,9 @@ import com.skedgo.tripkit.booking.quickbooking.Rider import org.joda.time.format.ISODateTimeFormat import java.text.SimpleDateFormat import java.util.Locale +import android.content.Context +import java.util.Date +import com.skedgo.tripkit.ui.utils.SystemTimeFormatManager data class GenericListItem( val label: String, @@ -70,5 +73,26 @@ data class GenericListItem( return emptyList() } + + private fun formatTime(context: Context, timeInMillis: Long): String { + val fromSdf = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.UK) + val toSdfDate = SimpleDateFormat("MMM dd, yyyy", Locale.UK) + // Use SystemTimeFormatManager singleton instead of requiring Context parameter + val timePattern = SystemTimeFormatManager.getTimeFormatPatternWithAmPm() + val toSdfTime = SimpleDateFormat(timePattern, Locale.UK) + val fromDate = Date(timeInMillis) + return "${toSdfDate.format(fromDate)} ${toSdfTime.format(fromDate)}" + } + + private fun formatTimeRange(context: Context, startTimeInMillis: Long, endTimeInMillis: Long): String { + val fromSdf = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.UK) + val toSdfDate = SimpleDateFormat("MMM dd, yyyy", Locale.UK) + // Use SystemTimeFormatManager singleton instead of requiring Context parameter + val timePattern = SystemTimeFormatManager.getTimeFormatPatternWithAmPm() + val toSdfTime = SimpleDateFormat(timePattern, Locale.UK) + val startDate = Date(startTimeInMillis) + val endDate = Date(endTimeInMillis) + return "${toSdfDate.format(startDate)} ${toSdfTime.format(startDate)} - ${toSdfDate.format(endDate)} ${toSdfTime.format(endDate)}" + } } } \ No newline at end of file diff --git a/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/dialog/v2/datetimepicker/TKUIDateTimePickerDialogFragment.kt b/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/dialog/v2/datetimepicker/TKUIDateTimePickerDialogFragment.kt index 48899cb4..1bb6d282 100644 --- a/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/dialog/v2/datetimepicker/TKUIDateTimePickerDialogFragment.kt +++ b/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/dialog/v2/datetimepicker/TKUIDateTimePickerDialogFragment.kt @@ -19,6 +19,8 @@ import java.util.Calendar import java.util.Locale import java.util.TimeZone import java.util.concurrent.TimeUnit.MILLISECONDS +import android.text.format.DateFormat +import com.skedgo.tripkit.ui.utils.SystemTimeFormatManager class TKUIDateTimePickerDialogFragment : BaseDialog() { @@ -82,8 +84,8 @@ class TKUIDateTimePickerDialogFragment : BaseDialog() @@ -140,11 +144,7 @@ open class TripPreviewPagerItemViewModel : RxViewModel() { fromLocation.set(segment.from?.address ?: "") toLocation.set(segment.to?.address ?: "") - if (!DateUtils.isToday(segment.startTimeInSecs)) { - duration.set(segment.startDateTime.toString(DateTimeFormat.forPattern("MMMM dd HH:mm"))) - } else { - duration.set("Today ${segment.startDateTime.toString(DateTimeFormat.forPattern("HH:mm"))}") - } + updateDuration(segment) requestedPickUp.set("") requestedDropOff.set("") @@ -152,7 +152,9 @@ open class TripPreviewPagerItemViewModel : RxViewModel() { if ((segment.trip?.queryTime ?: 0L) > 0) { val queryDateTime = segment.trip?.queryDateTime val date = queryDateTime?.toString(DateTimeFormat.forPattern("MMM d, yyyy")) - val time = queryDateTime?.toString(DateTimeFormat.forPattern("h:mm aa")) + // Use system-aware time format instead of hardcoded "H:mm" + val timePattern = if (DateFormat.is24HourFormat(context)) "H:mm" else "h:mm a" + val time = queryDateTime?.toString(DateTimeFormat.forPattern(timePattern)) val label = String.format(context.getString(R.string.requested_time), date, time) if (segment.trip?.queryIsLeaveAfter == true) { requestedPickUp.set(label) @@ -165,13 +167,17 @@ open class TripPreviewPagerItemViewModel : RxViewModel() { val labelForStartDate = startDateTime.toDate().checkDateForStringLabel(context) val startDate = labelForStartDate ?: startDateTime.toString(DateTimeFormat.forPattern("MMM d, yyyy")) - val startTime = startDateTime.toString(DateTimeFormat.forPattern("h:mm aa")) + // Use system-aware time format instead of hardcoded "H:mm" + val startTimePattern = if (DateFormat.is24HourFormat(context)) "H:mm" else "h:mm a" + val startTime = startDateTime.toString(DateTimeFormat.forPattern(startTimePattern)) val endDateTime = segment.endDateTime val labelForEndDate = endDateTime.toDate().checkDateForStringLabel(context) val endDate = labelForEndDate ?: endDateTime.toString(DateTimeFormat.forPattern("MMM d, yyyy")) - val endTime = endDateTime.toString(DateTimeFormat.forPattern("h:mm aa")) + // Use system-aware time format instead of hardcoded "H:mm" + val endTimePattern = if (DateFormat.is24HourFormat(context)) "H:mm" else "h:mm a" + val endTime = endDateTime.toString(DateTimeFormat.forPattern(endTimePattern)) requestedPickUp.set("$startDate $startTime") requestedDropOff.set("$endDate $endTime") @@ -186,6 +192,27 @@ open class TripPreviewPagerItemViewModel : RxViewModel() { ) } + private fun updateDuration(segment: TripSegment) { + val now = DateTime.now() + val segmentDate = segment.startDateTime + val daysDiff = Days.daysBetween(now.toLocalDate(), segmentDate.toLocalDate()).days + + when { + daysDiff == 0 -> { + val timePattern = SystemTimeFormatManager.getTimeFormatPattern() + duration.set("Today ${segment.startDateTime.toString(DateTimeFormat.forPattern(timePattern))}") + } + daysDiff == 1 -> { + val timePattern = SystemTimeFormatManager.getTimeFormatPattern() + duration.set("Tomorrow ${segment.startDateTime.toString(DateTimeFormat.forPattern(timePattern))}") + } + else -> { + val timePattern = SystemTimeFormatManager.getTimeFormatPattern() + duration.set(segment.startDateTime.toString(DateTimeFormat.forPattern("MMMM dd $timePattern"))) + } + } + } + private fun fetchRegionAndSetupPickUpMessage(trip: Trip) { TripKitUI.getInstance().regionService().getRegionByLocationAsync(trip.from) .subscribeOn(Schedulers.io()) @@ -210,8 +237,10 @@ open class TripPreviewPagerItemViewModel : RxViewModel() { DateTimeFormat.forPattern("MMM d, yyyy") .withZone(DateTimeZone.forID(timeZone)) ) + + val timePattern = SystemTimeFormatManager.getTimeFormatPatternWithAmPm() val time = dateTime.toString( - DateTimeFormat.forPattern("h:mm aa") + DateTimeFormat.forPattern(timePattern) .withZone(DateTimeZone.forID(timeZone)) ) diff --git a/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/tripresults/TripResultListFragment.kt b/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/tripresults/TripResultListFragment.kt index 0a98eaa7..cc1ef585 100644 --- a/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/tripresults/TripResultListFragment.kt +++ b/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/tripresults/TripResultListFragment.kt @@ -46,13 +46,28 @@ import timber.log.Timber import java.util.* import java.util.concurrent.TimeUnit import javax.inject.Inject +import android.text.format.DateFormat +import com.skedgo.tripkit.ui.utils.SystemTimeFormatManager class TripResultListFragment : BaseTripKitFragment() { companion object { - const val DATE_TIME_FORMATTER_LEAVE_NOW = "HH:mm aa" - const val DATE_TIME_FORMATTER_LEAVE = "MMMM dd HH:mm aa" + private const val ARG_QUERY = "query" + private const val ARG_ACTION_BUTTON_HANDLER_FACTORY = "action_button_handler_factory" + private const val ARG_SHOW_CLOSE_BUTTON = "show_close_button" + private const val ARG_USER_MODES = "user_modes" + private const val ARG_BOOK_RIDE_HELP_CALLBACK = "book_ride_help_callback" + private const val ARG_TRIP_KIT_MAP_FRAGMENT = "trip_kit_map_fragment" + + // Use SystemTimeFormatManager singleton instead of requiring Context parameter + fun getDateTimeFormatterLeaveNow(): String { + return SystemTimeFormatManager.getTimeFormatPatternWithAmPm() + } + + fun getDateTimeFormatterLeave(): String { + return SystemTimeFormatManager.getDateTimeFormatPatternWithAmPm("MMMM dd") + } } /** @@ -224,9 +239,9 @@ class TripResultListFragment : BaseTripKitFragment() { timeTag?.let { val timezone: String? = region.timezone val dateFormatter = if (it.isLeaveNow) { - DATE_TIME_FORMATTER_LEAVE_NOW + getDateTimeFormatterLeaveNow() } else { - DATE_TIME_FORMATTER_LEAVE + getDateTimeFormatterLeave() } val dt = DateTime(timeTag.timeInMillis, DateTimeZone.forID(timezone)) val formatter = DateTimeFormat.forPattern(dateFormatter) diff --git a/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/utils/DateUtils.kt b/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/utils/DateUtils.kt index 501727de..dfd94d57 100644 --- a/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/utils/DateUtils.kt +++ b/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/utils/DateUtils.kt @@ -21,11 +21,13 @@ fun getDisplayDateFormatter(tz: DateTimeZone? = null): DateTimeFormatter { } fun getDisplayTimeFormatter(tz: DateTimeZone? = null): DateTimeFormatter { - return DateTimeFormat.forPattern("h:mm aa").withZone(tz) + val timePattern = SystemTimeFormatManager.getTimeFormatPatternWithAmPm() + return DateTimeFormat.forPattern(timePattern).withZone(tz) } fun getDisplayDateTimeFormatter(tz: DateTimeZone? = null): DateTimeFormatter { - return DateTimeFormat.forPattern("MMM dd, yyyy h:mm aa").withZone(tz) + val timePattern = SystemTimeFormatManager.getTimeFormatPatternWithAmPm() + return DateTimeFormat.forPattern("MMM dd, yyyy $timePattern").withZone(tz) } fun Date.checkDateForStringLabel(context: Context): String? { diff --git a/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/utils/SystemTimeFormatManager.kt b/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/utils/SystemTimeFormatManager.kt new file mode 100644 index 00000000..5d8af2e9 --- /dev/null +++ b/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/utils/SystemTimeFormatManager.kt @@ -0,0 +1,69 @@ +package com.skedgo.tripkit.ui.utils + +import android.content.Context +import android.text.format.DateFormat + +/** + * Singleton class to manage system time format detection. + * This eliminates the need to pass Context around to classes that don't have access to it. + */ +object SystemTimeFormatManager { + + private var applicationContext: Context? = null + + /** + * Initialize the manager with the Application context. + * Should be called in Application.onCreate() + */ + fun initialize(context: Context) { + applicationContext = context.applicationContext + } + + /** + * Check if the system is using 24-hour format. + * @return true if 24-hour format is enabled, false for 12-hour format + */ + fun is24HourFormat(): Boolean { + val context = applicationContext + return if (context != null) { + DateFormat.is24HourFormat(context) + } else { + // Default to 24-hour format if not initialized + true + } + } + + /** + * Get the appropriate time format pattern based on system settings. + * @return "H:mm" for 24-hour format, "h:mm a" for 12-hour format + */ + fun getTimeFormatPattern(): String { + return if (is24HourFormat()) "H:mm" else "h:mm a" + } + + /** + * Get the appropriate time format pattern with AM/PM indicator for 12-hour format. + * @return "H:mm" for 24-hour format, "h:mm aa" for 12-hour format + */ + fun getTimeFormatPatternWithAmPm(): String { + return if (is24HourFormat()) "H:mm" else "h:mm aa" + } + + /** + * Get a date-time format pattern with the appropriate time format. + * @param datePattern The date pattern (e.g., "MMM dd, yyyy") + * @return Combined date-time pattern with system-aware time format + */ + fun getDateTimeFormatPattern(datePattern: String): String { + return "$datePattern ${getTimeFormatPattern()}" + } + + /** + * Get a date-time format pattern with AM/PM indicator. + * @param datePattern The date pattern (e.g., "MMM dd, yyyy") + * @return Combined date-time pattern with system-aware time format and AM/PM + */ + fun getDateTimeFormatPatternWithAmPm(datePattern: String): String { + return "$datePattern ${getTimeFormatPatternWithAmPm()}" + } +} diff --git a/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/utils/TimeTagUtils.kt b/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/utils/TimeTagUtils.kt index 1bc7d3c6..2ba3d598 100644 --- a/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/utils/TimeTagUtils.kt +++ b/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/utils/TimeTagUtils.kt @@ -27,7 +27,9 @@ fun TimeTag.formatString(context: Context, timezone: String?): String { stringBuilder.append(prefix) stringBuilder.append(" ") val date = Date(millis) - val dateFormat = SimpleDateFormat("MMM dd, h:mm a", Locale.US) + + val timePattern = SystemTimeFormatManager.getTimeFormatPattern() + val dateFormat = SimpleDateFormat("MMM dd, $timePattern", Locale.US) dateFormat.timeZone = if (timezone != null) { TimeZone.getTimeZone(timezone) } else { diff --git a/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/utils/TripSegmentUIExtension.kt b/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/utils/TripSegmentUIExtension.kt index 4fca43ca..65f99333 100644 --- a/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/utils/TripSegmentUIExtension.kt +++ b/TripKitAndroidUI/src/main/java/com/skedgo/tripkit/ui/utils/TripSegmentUIExtension.kt @@ -24,6 +24,8 @@ import io.reactivex.Observable import io.reactivex.android.schedulers.AndroidSchedulers import org.joda.time.format.DateTimeFormat import timber.log.Timber +import android.text.format.DateFormat +import com.skedgo.tripkit.ui.utils.SystemTimeFormatManager fun TripSegment.getSegmentIconObservable( @@ -100,7 +102,8 @@ private fun TripSegment.shouldAttachAlertIconToSubtitle(): Boolean { } fun TripSegment.generateTripPreviewHeader(icon: Drawable): TripSegmentSummary { - val dateTimeFormatter = DateTimeFormat.forPattern("hh:mm a") + val timePattern = SystemTimeFormatManager.getTimeFormatPattern() + val dateTimeFormatter = DateTimeFormat.forPattern(timePattern) return TripSegmentSummary( id = this.segmentId, title = this.getTitle(), @@ -121,7 +124,8 @@ fun TripSegment.generateTripPreviewHeader( icon: Drawable, printTime: PrintTime ): TripSegmentSummary { - val dateTimeFormatter = DateTimeFormat.forPattern("hh:mm a") + val timePattern = SystemTimeFormatManager.getTimeFormatPattern() + val dateTimeFormatter = DateTimeFormat.forPattern(timePattern) return TripSegmentSummary( id = this.segmentId, title = this.getTitle(), @@ -200,4 +204,16 @@ private fun TripSegment.getTitle(): String { "" } } +} + +private fun TripSegment.getTimeText(context: Context): String { + val timePattern = SystemTimeFormatManager.getTimeFormatPattern() + val dateTimeFormatter = DateTimeFormat.forPattern(timePattern) + return startDateTime.toString(dateTimeFormatter) +} + +private fun TripSegment.getTimeRangeText(context: Context): String { + val timePattern = SystemTimeFormatManager.getTimeFormatPattern() + val dateTimeFormatter = DateTimeFormat.forPattern(timePattern) + return "${startDateTime.toString(dateTimeFormatter)} - ${endDateTime.toString(dateTimeFormatter)}" } \ No newline at end of file diff --git a/TripKitAndroidUI/src/test/java/com/skedgo/tripkit/ui/trip/options/RoutingTimeViewModelMapperTest.kt b/TripKitAndroidUI/src/test/java/com/skedgo/tripkit/ui/trip/options/RoutingTimeViewModelMapperTest.kt index 6a51339a..857e4eda 100644 --- a/TripKitAndroidUI/src/test/java/com/skedgo/tripkit/ui/trip/options/RoutingTimeViewModelMapperTest.kt +++ b/TripKitAndroidUI/src/test/java/com/skedgo/tripkit/ui/trip/options/RoutingTimeViewModelMapperTest.kt @@ -5,10 +5,12 @@ import com.skedgo.tripkit.ui.R import com.skedgo.tripkit.ui.trip.ArriveBy import com.skedgo.tripkit.ui.trip.LeaveAfter import com.skedgo.tripkit.ui.trip.Now +import com.skedgo.tripkit.ui.utils.SystemTimeFormatManager import io.mockk.every import io.mockk.mockk import io.reactivex.Single import io.reactivex.observers.TestObserver +import org.amshove.kluent.internal.assertEquals import org.joda.time.DateTime import org.joda.time.DateTimeZone import org.junit.Before @@ -60,9 +62,22 @@ class RoutingTimeViewModelMapperTest { testObserver.assertValue("Arrive $formattedTime") } + @Test + fun `should format leave after time correctly`() { + val dateTime = DateTime(2023, 1, 1, 14, 30, DateTimeZone.UTC) + val leaveAfter = LeaveAfter(dateTime) + + val result = mapper.toText(leaveAfter).blockingGet() + + assertEquals("Leave Jan 01, 2:30 PM", result) + } + // Helper function to match the ViewModel's formatting private fun DateTime.format(): String { - val simpleDateFormat = SimpleDateFormat("MMM dd, h:mm a", Locale.US) + // Use SystemTimeFormatManager singleton instead of requiring Context parameter + val timePattern = SystemTimeFormatManager.getTimeFormatPattern() + val datePattern = "MMM dd, $timePattern" + val simpleDateFormat = SimpleDateFormat(datePattern, Locale.US) simpleDateFormat.timeZone = zone.toTimeZone() return simpleDateFormat.format(Date(millis)) } From 79be7f1fa098921741ce9b2d4cd3b22bde2a0fc8 Mon Sep 17 00:00:00 2001 From: Michael Angelo Reyes Date: Sun, 24 Aug 2025 20:12:30 +0800 Subject: [PATCH 4/6] [24474] - disable name edit on Home and Work favorite items --- TripKitAndroidUI/src/main/res/values/colors.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TripKitAndroidUI/src/main/res/values/colors.xml b/TripKitAndroidUI/src/main/res/values/colors.xml index a218a030..ac51aae7 100644 --- a/TripKitAndroidUI/src/main/res/values/colors.xml +++ b/TripKitAndroidUI/src/main/res/values/colors.xml @@ -30,7 +30,7 @@ #1880e7 #3467CE - #303467CE + #703467CE #23B15E #6665B2 #9A579D From 339ea25bb02ccbf36d0149d7dfa59a5cefbc9ced Mon Sep 17 00:00:00 2001 From: Michael Angelo Reyes Date: Sun, 24 Aug 2025 21:34:01 +0800 Subject: [PATCH 5/6] [24474] - fix failing tests caused by recent bug fixes --- .../ui/timetables/GetRealtimeTextTest.kt | 11 ++++++++ .../options/RoutingTimeViewModelMapperTest.kt | 23 +++++++++++++++++ .../TripPreviewPagerItemViewModelTest.kt | 11 ++++++++ ...ernalActionTripPreviewItemViewModelTest.kt | 25 +++++++++++++++++++ 4 files changed, 70 insertions(+) diff --git a/TripKitAndroidUI/src/test/java/com/skedgo/tripkit/ui/timetables/GetRealtimeTextTest.kt b/TripKitAndroidUI/src/test/java/com/skedgo/tripkit/ui/timetables/GetRealtimeTextTest.kt index 747e83b0..7e4221ab 100644 --- a/TripKitAndroidUI/src/test/java/com/skedgo/tripkit/ui/timetables/GetRealtimeTextTest.kt +++ b/TripKitAndroidUI/src/test/java/com/skedgo/tripkit/ui/timetables/GetRealtimeTextTest.kt @@ -2,6 +2,7 @@ package com.skedgo.tripkit.ui.timetables import android.content.Context import android.content.res.Resources +import android.text.format.DateFormat import com.skedgo.tripkit.common.model.realtimealert.RealTimeStatus import com.skedgo.tripkit.datetime.PrintTime import com.skedgo.tripkit.routing.RealTimeVehicle @@ -9,9 +10,12 @@ import com.skedgo.tripkit.ui.R import com.skedgo.tripkit.ui.model.TimetableEntry import io.mockk.every import io.mockk.mockk +import io.mockk.mockkStatic +import io.mockk.unmockkStatic import org.joda.time.DateTime import org.joda.time.DateTimeZone import org.joda.time.tz.UTCProvider +import org.junit.After import org.junit.Assert.assertEquals import org.junit.Before import org.junit.BeforeClass @@ -35,11 +39,18 @@ class GetRealtimeTextTest { @Before fun setUp() { + mockkStatic(DateFormat::class) + every { DateFormat.is24HourFormat(any()) } returns true every { context.resources } returns resources every { resources.getBoolean(R.bool.is_right_to_left) } returns false // Mock getBoolean() getRealtimeText = GetRealtimeText(context, printTime) } + @After + fun tearDown() { + unmockkStatic(DateFormat::class) + } + @Test fun `should return scheduled time if real-time status is null`() { val service: TimetableEntry = mockk { diff --git a/TripKitAndroidUI/src/test/java/com/skedgo/tripkit/ui/trip/options/RoutingTimeViewModelMapperTest.kt b/TripKitAndroidUI/src/test/java/com/skedgo/tripkit/ui/trip/options/RoutingTimeViewModelMapperTest.kt index 857e4eda..11840cd7 100644 --- a/TripKitAndroidUI/src/test/java/com/skedgo/tripkit/ui/trip/options/RoutingTimeViewModelMapperTest.kt +++ b/TripKitAndroidUI/src/test/java/com/skedgo/tripkit/ui/trip/options/RoutingTimeViewModelMapperTest.kt @@ -1,6 +1,7 @@ package com.skedgo.tripkit.ui.trip.options import android.content.res.Resources +import android.text.format.DateFormat import com.skedgo.tripkit.ui.R import com.skedgo.tripkit.ui.trip.ArriveBy import com.skedgo.tripkit.ui.trip.LeaveAfter @@ -8,11 +9,16 @@ import com.skedgo.tripkit.ui.trip.Now import com.skedgo.tripkit.ui.utils.SystemTimeFormatManager import io.mockk.every import io.mockk.mockk +import io.mockk.mockkObject +import io.mockk.mockkStatic +import io.mockk.unmockkObject +import io.mockk.unmockkStatic import io.reactivex.Single import io.reactivex.observers.TestObserver import org.amshove.kluent.internal.assertEquals import org.joda.time.DateTime import org.joda.time.DateTimeZone +import org.junit.After import org.junit.Before import org.junit.Test import java.text.SimpleDateFormat @@ -25,8 +31,22 @@ class RoutingTimeViewModelMapperTest { @Before fun setUp() { + // Mock SystemTimeFormatManager + mockkObject(SystemTimeFormatManager) + every { SystemTimeFormatManager.getTimeFormatPattern() } returns "h:mm a" + + // Mock DateFormat.is24HourFormat for SystemTimeFormatManager internal usage + mockkStatic(DateFormat::class) + every { DateFormat.is24HourFormat(any()) } returns false + mapper = RoutingTimeViewModelMapper(resources) } + + @After + fun tearDown() { + unmockkObject(SystemTimeFormatManager) + unmockkStatic(DateFormat::class) + } @Test fun `toText returns correct text for Now`() { @@ -66,6 +86,9 @@ class RoutingTimeViewModelMapperTest { fun `should format leave after time correctly`() { val dateTime = DateTime(2023, 1, 1, 14, 30, DateTimeZone.UTC) val leaveAfter = LeaveAfter(dateTime) + + // Mock the string resource for "Leave" + every { resources.getString(R.string.leave) } returns "Leave" val result = mapper.toText(leaveAfter).blockingGet() diff --git a/TripKitAndroidUI/src/test/java/com/skedgo/tripkit/ui/trippreview/TripPreviewPagerItemViewModelTest.kt b/TripKitAndroidUI/src/test/java/com/skedgo/tripkit/ui/trippreview/TripPreviewPagerItemViewModelTest.kt index f58ae50f..396108d1 100644 --- a/TripKitAndroidUI/src/test/java/com/skedgo/tripkit/ui/trippreview/TripPreviewPagerItemViewModelTest.kt +++ b/TripKitAndroidUI/src/test/java/com/skedgo/tripkit/ui/trippreview/TripPreviewPagerItemViewModelTest.kt @@ -3,6 +3,7 @@ package com.skedgo.tripkit.ui.trippreview import android.content.Context import android.content.res.Resources import android.text.TextUtils +import android.text.format.DateFormat import androidx.arch.core.executor.testing.InstantTaskExecutorRule import androidx.core.content.ContextCompat import com.skedgo.tripkit.common.model.location.Location @@ -13,6 +14,7 @@ import com.skedgo.tripkit.routing.TripSegment import com.skedgo.tripkit.routing.endDateTime import com.skedgo.tripkit.routing.startDateTime import com.skedgo.tripkit.ui.base.MockKTest +import com.skedgo.tripkit.ui.utils.SystemTimeFormatManager import io.mockk.* import org.amshove.kluent.internal.assertEquals import org.joda.time.DateTime @@ -63,6 +65,13 @@ class TripPreviewPagerItemViewModelTest: MockKTest() { mockkStatic(TextUtils::class) every { TextUtils.isEmpty(any()) } answers { false } + mockkStatic(DateFormat::class) + every { DateFormat.is24HourFormat(any()) } returns false + + mockkObject(SystemTimeFormatManager) + every { SystemTimeFormatManager.getTimeFormatPattern() } returns "h:mm a" + every { SystemTimeFormatManager.getTimeFormatPatternWithAmPm() } returns "h:mm a" + mockkStatic("android.text.format.DateUtils") every { @@ -75,6 +84,8 @@ class TripPreviewPagerItemViewModelTest: MockKTest() { @After fun tearDown() { tearDownRx() + unmockkObject(SystemTimeFormatManager) + unmockkStatic(DateFormat::class) unmockkAll() } diff --git a/TripKitAndroidUI/src/test/java/com/skedgo/tripkit/ui/trippreview/external/ExternalActionTripPreviewItemViewModelTest.kt b/TripKitAndroidUI/src/test/java/com/skedgo/tripkit/ui/trippreview/external/ExternalActionTripPreviewItemViewModelTest.kt index 69d88900..4cb36c59 100644 --- a/TripKitAndroidUI/src/test/java/com/skedgo/tripkit/ui/trippreview/external/ExternalActionTripPreviewItemViewModelTest.kt +++ b/TripKitAndroidUI/src/test/java/com/skedgo/tripkit/ui/trippreview/external/ExternalActionTripPreviewItemViewModelTest.kt @@ -1,17 +1,23 @@ package com.skedgo.tripkit.ui.trippreview.external import android.content.Context +import android.text.format.DateFormat import android.webkit.URLUtil import androidx.arch.core.executor.testing.InstantTaskExecutorRule import com.skedgo.tripkit.common.model.booking.Booking import com.skedgo.tripkit.routing.TripSegment import com.skedgo.tripkit.ui.R import com.skedgo.tripkit.ui.trippreview.handleExternalAction +import com.skedgo.tripkit.ui.utils.SystemTimeFormatManager import io.mockk.every import io.mockk.mockk +import io.mockk.mockkObject import io.mockk.mockkStatic import io.mockk.slot +import io.mockk.unmockkObject +import io.mockk.unmockkStatic import org.joda.time.DateTimeZone +import org.junit.After import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Rule @@ -41,10 +47,21 @@ class ExternalActionTripPreviewItemViewModelTest { booking = mockBooking } + // Mock static classes mockkStatic(URLUtil::class) every { URLUtil.isNetworkUrl(any()) } returns true + mockkStatic(DateTimeZone::class) every { DateTimeZone.forID(any()) } answers { DateTimeZone.UTC } + + // Mock DateFormat.is24HourFormat to prevent NullPointerException + mockkStatic(DateFormat::class) + every { DateFormat.is24HourFormat(any()) } returns false + + // Mock SystemTimeFormatManager + mockkObject(SystemTimeFormatManager) + every { SystemTimeFormatManager.getTimeFormatPattern() } returns "h:mm a" + every { SystemTimeFormatManager.getTimeFormatPatternWithAmPm() } returns "h:mm a" viewModel = ExternalActionTripPreviewItemViewModel() @@ -61,6 +78,14 @@ class ExternalActionTripPreviewItemViewModelTest { every { mockContext.handleExternalAction(any()) } returns mockk(relaxed = true) } + @After + fun tearDown() { + unmockkStatic(URLUtil::class) + unmockkStatic(DateTimeZone::class) + unmockkStatic(DateFormat::class) + unmockkObject(SystemTimeFormatManager) + } + @Test fun `setSegment correctly populates items`() { every { mockSegment.timeZone } returns "Australia/Sydney" From 4c9ca871e3de855f751e428f7b1a691331b4052d Mon Sep 17 00:00:00 2001 From: Michael Angelo Reyes Date: Mon, 1 Sep 2025 14:35:10 +0800 Subject: [PATCH 6/6] [24474] - favorite rename fixes and db version updates --- .../1.json | 82 +------------- .../1.json | 100 ++++++++++++++++++ 2 files changed, 102 insertions(+), 80 deletions(-) create mode 100644 TripKitAndroidUI/schemas/com.skedgo.tripkit.ui.favorites.v2.data.local.FavoritesDatabase/1.json diff --git a/TripKitAndroidUI/schemas/com.skedgo.tripkit.ui.favorites.trips.FavoriteTripsDataBase/1.json b/TripKitAndroidUI/schemas/com.skedgo.tripkit.ui.favorites.trips.FavoriteTripsDataBase/1.json index 9224994a..b02090fd 100644 --- a/TripKitAndroidUI/schemas/com.skedgo.tripkit.ui.favorites.trips.FavoriteTripsDataBase/1.json +++ b/TripKitAndroidUI/schemas/com.skedgo.tripkit.ui.favorites.trips.FavoriteTripsDataBase/1.json @@ -2,7 +2,7 @@ "formatVersion": 1, "database": { "version": 1, - "identityHash": "d4ea3ff522f24116edfc1051b31df634", + "identityHash": "9709d743552e75caa23b4587bbdd1140", "entities": [ { "tableName": "favoriteTrips", @@ -47,90 +47,12 @@ }, "indices": [], "foreignKeys": [] - }, - { - "tableName": "waypoints", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`lat` REAL NOT NULL, `lng` REAL NOT NULL, `mode` TEXT, `modeTitle` TEXT, `order` INTEGER NOT NULL, `tripId` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`tripId`) REFERENCES `favoriteTrips`(`uuid`) ON UPDATE CASCADE ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "lat", - "columnName": "lat", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "lng", - "columnName": "lng", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "mode", - "columnName": "mode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "modeTitle", - "columnName": "modeTitle", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "order", - "columnName": "order", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "tripId", - "columnName": "tripId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": true, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_waypoints_tripId", - "unique": false, - "columnNames": [ - "tripId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_waypoints_tripId` ON `${TABLE_NAME}` (`tripId`)" - } - ], - "foreignKeys": [ - { - "table": "favoriteTrips", - "onDelete": "CASCADE", - "onUpdate": "CASCADE", - "columns": [ - "tripId" - ], - "referencedColumns": [ - "uuid" - ] - } - ] } ], "views": [], "setupQueries": [ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'd4ea3ff522f24116edfc1051b31df634')" + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '9709d743552e75caa23b4587bbdd1140')" ] } } \ No newline at end of file diff --git a/TripKitAndroidUI/schemas/com.skedgo.tripkit.ui.favorites.v2.data.local.FavoritesDatabase/1.json b/TripKitAndroidUI/schemas/com.skedgo.tripkit.ui.favorites.v2.data.local.FavoritesDatabase/1.json new file mode 100644 index 00000000..7465dd0e --- /dev/null +++ b/TripKitAndroidUI/schemas/com.skedgo.tripkit.ui.favorites.v2.data.local.FavoritesDatabase/1.json @@ -0,0 +1,100 @@ +{ + "formatVersion": 1, + "database": { + "version": 1, + "identityHash": "c1298b518303d6c4bc1800fcdeeb8437", + "entities": [ + { + "tableName": "favorites_v2", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uuid` TEXT NOT NULL, `name` TEXT NOT NULL, `type` TEXT NOT NULL, `order` INTEGER, `region` TEXT, `stopCode` TEXT, `filter` TEXT, `location` TEXT, `start` TEXT, `end` TEXT, `patterns` TEXT, `userId` TEXT, PRIMARY KEY(`uuid`))", + "fields": [ + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "order", + "columnName": "order", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "region", + "columnName": "region", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "stopCode", + "columnName": "stopCode", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "filter", + "columnName": "filter", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "location", + "columnName": "location", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "start", + "columnName": "start", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "end", + "columnName": "end", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "patterns", + "columnName": "patterns", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "uuid" + ] + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'c1298b518303d6c4bc1800fcdeeb8437')" + ] + } +} \ No newline at end of file