├── docs ├── banner.png ├── lokalise.png └── webhook_settings_1.png ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── automotive └── src │ ├── main │ ├── ic_launcher-playstore.png │ ├── ic_launcher_alt-playstore.png │ ├── ic_launcher_alt2-playstore.png │ ├── ic_launcher_club-playstore.png │ ├── res │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_abrp.png │ │ │ ├── ic_launcher_foreground.webp │ │ │ ├── ic_launcher_notification.png │ │ │ └── ic_launcher_foreground_dev.webp │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher_foreground.webp │ │ │ └── ic_launcher_foreground_dev.webp │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher_foreground.webp │ │ │ └── ic_launcher_foreground_dev.webp │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher_foreground.webp │ │ │ └── ic_launcher_foreground_dev.webp │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher_foreground.webp │ │ │ └── ic_launcher_foreground_dev.webp │ │ ├── drawable │ │ │ ├── pressed_foreground.xml │ │ │ ├── bg_multibutton.xml │ │ │ ├── bg_club.xml │ │ │ ├── ic_launcher_background.xml │ │ │ ├── bg_main_tile.xml │ │ │ ├── bg_action_bar.xml │ │ │ ├── bg_content.xml │ │ │ ├── club_thumb.xml │ │ │ ├── club_button.xml │ │ │ ├── ic_chevron_back.xml │ │ │ ├── ic_chevron_up.xml │ │ │ ├── ic_chevron_left.xml │ │ │ ├── ic_chevron_right.xml │ │ │ ├── ic_filter_active.xml │ │ │ ├── ic_arrow_diagonal.xml │ │ │ ├── ic_arrow_back.xml │ │ │ ├── ic_filter.xml │ │ │ ├── ic_battery.xml │ │ │ ├── ic_avg_consumption.xml │ │ │ ├── ic_close.xml │ │ │ ├── ic_kill.xml │ │ │ ├── ic_notification_phone.xml │ │ │ ├── ic_upload.xml │ │ │ ├── ic_marker_charge.xml │ │ │ ├── ic_send.xml │ │ │ ├── ic_marker_park.xml │ │ │ ├── ic_power.xml │ │ │ ├── ic_altitude.xml │ │ │ ├── ic_energy_large.xml │ │ │ ├── ic_login.xml │ │ │ ├── ic_copy.xml │ │ │ ├── ic_mail.xml │ │ │ ├── ic_checked_checkbox.xml │ │ │ ├── ic_notification_diagram.xml │ │ │ ├── ic_temperature.xml │ │ │ ├── ic_api.xml │ │ │ ├── ic_phone.xml │ │ │ ├── club_button_off.xml │ │ │ ├── ic_diagram.xml │ │ │ ├── ic_time.xml │ │ │ ├── ic_error.xml │ │ │ ├── ic_delete.xml │ │ │ ├── club_gradient_radial.xml │ │ │ ├── club_button_on.xml │ │ │ ├── ic_save.xml │ │ │ ├── ic_day.xml │ │ │ ├── ic_car_app_feedback.xml │ │ │ ├── ic_location_on.xml │ │ │ ├── ic_charger.xml │ │ │ ├── ic_reset.xml │ │ │ ├── ic_connected.xml │ │ │ ├── ic_link.xml │ │ │ ├── ic_history.xml │ │ │ ├── ic_distance.xml │ │ │ ├── ic_car.xml │ │ │ ├── ic_month.xml │ │ │ ├── ic_camera.xml │ │ │ ├── ic_construction.xml │ │ │ ├── ic_temperature_large.xml │ │ │ ├── ic_hand.xml │ │ │ ├── ic_checkmark.xml │ │ │ ├── ic_remaining_range.xml │ │ │ ├── ic_coffee.xml │ │ │ ├── ic_location_error.xml │ │ │ ├── ic_time_large.xml │ │ │ ├── ic_info.xml │ │ │ ├── ic_distance_large.xml │ │ │ ├── ic_list.xml │ │ │ ├── ic_speed.xml │ │ │ ├── ic_speed_large.xml │ │ │ ├── club_gradient.xml │ │ │ ├── ic_debug.xml │ │ │ ├── club_thumb_off.xml │ │ │ ├── club_thumb_on.xml │ │ │ ├── ic_help.xml │ │ │ ├── ic_performance.xml │ │ │ ├── ic_webhook.xml │ │ │ ├── ic_trip_start.xml │ │ │ └── ic_trip_charging_location.xml │ │ ├── anim │ │ │ ├── slide_in_left.xml │ │ │ ├── slide_out_left.xml │ │ │ ├── slide_in_up.xml │ │ │ ├── snackbar_up.xml │ │ │ ├── stay_still.xml │ │ │ ├── slide_in_right.xml │ │ │ ├── slide_out_down.xml │ │ │ ├── slide_out_right.xml │ │ │ └── snackbar_down.xml │ │ ├── color │ │ │ ├── switch_tint.xml │ │ │ ├── button_foreground.xml │ │ │ └── button_text.xml │ │ ├── mipmap-anydpi-v26 │ │ │ └── ic_launcher.xml │ │ ├── values │ │ │ ├── broadcast_actions.xml │ │ │ ├── dimens.xml │ │ │ └── themes.xml │ │ ├── layout │ │ │ ├── widget_fixed_switch.xml │ │ │ ├── activity_permissions.xml │ │ │ └── widget_multi_select.xml │ │ ├── values-sw700dp-land │ │ │ └── dimens.xml │ │ ├── values-sw1000dp │ │ │ └── dimens.xml │ │ └── values-w877dp │ │ │ └── styles.xml │ ├── ic_launcher_alt_dev-playstore.png │ ├── ic_launcher_alt2_dev-playstore.png │ ├── ic_launcher_club_dev-playstore.png │ ├── java │ │ └── com │ │ │ └── ixam97 │ │ │ └── carStatsViewer │ │ │ ├── database │ │ │ ├── tripData │ │ │ │ ├── PointMarkerType.kt │ │ │ │ ├── SessionMarkerType.kt │ │ │ │ ├── TripType.kt │ │ │ │ └── TripDataDatabase.kt │ │ │ └── log │ │ │ │ ├── LogDatabase.kt │ │ │ │ ├── LogEntry.kt │ │ │ │ └── LogDao.kt │ │ │ ├── ui │ │ │ ├── plot │ │ │ │ ├── enums │ │ │ │ │ ├── PlotDirection.kt │ │ │ │ │ ├── PlotLabelPosition.kt │ │ │ │ │ ├── PlotSessionGapRendering.kt │ │ │ │ │ ├── PlotDimensionSmoothingType.kt │ │ │ │ │ ├── PlotLineLabelFormat.kt │ │ │ │ │ ├── PlotHighlightMethod.kt │ │ │ │ │ ├── PlotDimensionY.kt │ │ │ │ │ ├── PlotDimensionX.kt │ │ │ │ │ ├── PlotMarkerType.kt │ │ │ │ │ └── PlotLineMarkerType.kt │ │ │ │ ├── objects │ │ │ │ │ ├── PlotPoint.kt │ │ │ │ │ ├── PlotRange.kt │ │ │ │ │ └── PlotLineConfiguration.kt │ │ │ │ └── graphics │ │ │ │ │ ├── PlotLinePaint.kt │ │ │ │ │ └── PlotMarkerPaint.kt │ │ │ └── views │ │ │ │ ├── MultiLineRowButtonWidget.kt │ │ │ │ └── FixedSwitchWidget.kt │ │ │ ├── utils │ │ │ ├── Exclude.kt │ │ │ ├── GetColorFromAttribute.kt │ │ │ ├── SetContentViewAndTheme.kt │ │ │ ├── FlowThrottle.kt │ │ │ ├── WatchdogState.kt │ │ │ ├── Ticker.kt │ │ │ ├── TimestampSynchronizer.kt │ │ │ ├── GetBitmapFromVectorDrawable.kt │ │ │ ├── Watchdog.kt │ │ │ ├── TimeTracker.kt │ │ │ └── ChangeLogCreator.kt │ │ │ ├── repository │ │ │ └── logSubmit │ │ │ │ ├── LogSubmitService.kt │ │ │ │ ├── LogSubmitApi.kt │ │ │ │ └── LogSubmit.kt │ │ │ ├── compose │ │ │ ├── theme │ │ │ │ ├── Shape.kt │ │ │ │ └── Color.kt │ │ │ ├── Event.kt │ │ │ ├── screens │ │ │ │ ├── settings │ │ │ │ │ ├── Changelog.kt │ │ │ │ │ ├── GeneralSettings.kt │ │ │ │ │ └── PrivacySettings.kt │ │ │ │ └── MapboxScreen.kt │ │ │ ├── components │ │ │ │ ├── CarIconButton.kt │ │ │ │ └── CarSwitchRow.kt │ │ │ ├── ComposeSettingsActivity.kt │ │ │ └── ComposeTripDetailsActivity.kt │ │ │ ├── liveDataApi │ │ │ ├── abrpLiveData │ │ │ │ ├── AbrpDataSet.kt │ │ │ │ └── AppPreferencesExt.kt │ │ │ └── http │ │ │ │ ├── HttpDataSet.kt │ │ │ │ ├── TextValidator.kt │ │ │ │ └── AppPreferencesExt.kt │ │ │ ├── dataProcessor │ │ │ ├── DrivingState.kt │ │ │ ├── IgnitionState.kt │ │ │ ├── StaticVehicleData.kt │ │ │ └── RealTimeData.kt │ │ │ ├── locationClient │ │ │ ├── LocationClient.kt │ │ │ └── ContextHasLocationPermission.kt │ │ │ ├── carPropertiesClient │ │ │ └── CarProperty.kt │ │ │ ├── appPreferences │ │ │ └── AppPreference.kt │ │ │ └── map │ │ │ └── MapboxInterface.kt │ └── AndroidManifest.xml │ ├── carapp │ ├── res │ │ ├── xml │ │ │ └── automotive_app_desc.xml │ │ ├── values │ │ │ └── strings.xml │ │ └── drawable │ │ │ ├── ic_car_app_minus.xml │ │ │ ├── ic_car_app_plus.xml │ │ │ ├── ic_car_app_menu.xml │ │ │ ├── ic_car_app_upgrade.xml │ │ │ ├── ic_car_app_altitude.xml │ │ │ ├── ic_car_app_tune.xml │ │ │ ├── ic_car_app_battery.xml │ │ │ ├── ic_car_app_check.xml │ │ │ ├── ic_car_app_reset.xml │ │ │ ├── ic_car_app_dashboard.xml │ │ │ ├── ic_car_app_history.xml │ │ │ ├── ic_car_app_canvas.xml │ │ │ ├── ic_car_app_status.xml │ │ │ ├── ic_car_app_debug.xml │ │ │ ├── ic_car_app_list.xml │ │ │ ├── ic_car_app_speed.xml │ │ │ └── ic_car_app_settings.xml │ └── java │ │ └── com │ │ └── ixam97 │ │ └── carStatsViewer │ │ └── carApp │ │ ├── renderer │ │ └── Renderer.kt │ │ ├── CarStatsViewerService.kt │ │ ├── DevNoticeScreen.kt │ │ ├── ChargingSessionDetailsScreen.kt │ │ ├── RealTimeDataScreen.kt │ │ ├── ConfirmResetScreen.kt │ │ ├── utils │ │ └── Utils.kt │ │ └── ConfirmDeleteTripScreen.kt │ ├── legacy │ └── res │ │ ├── mipmap-hdpi │ │ ├── ic_launcher_foreground.webp │ │ └── ic_launcher_foreground_dev.webp │ │ ├── mipmap-mdpi │ │ ├── ic_launcher_foreground.webp │ │ └── ic_launcher_foreground_dev.webp │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher_foreground.webp │ │ └── ic_launcher_foreground_dev.webp │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher_foreground.webp │ │ └── ic_launcher_foreground_dev.webp │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher_foreground.webp │ │ └── ic_launcher_foreground_dev.webp │ │ └── drawable │ │ └── ic_launcher_background.xml │ ├── mapboxdummy │ └── java │ │ └── com │ │ └── ixam97 │ │ └── carStatsViewer │ │ └── map │ │ └── Mapbox.kt │ ├── dev │ └── res │ │ ├── values │ │ ├── preferences_keys.xml │ │ └── strings.xml │ │ └── mipmap-anydpi-v26 │ │ └── ic_launcher.xml │ └── devCarapp │ ├── res │ └── values │ │ └── strings.xml │ └── AndroidManifest.xml ├── config └── libraries │ └── egm96.json ├── .github ├── workflows │ └── build.yml └── FUNDING.yml ├── .gitignore ├── LICENSE.md ├── settings.gradle ├── gradle.properties └── gradlew.bat /docs/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/docs/banner.png -------------------------------------------------------------------------------- /docs/lokalise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/docs/lokalise.png -------------------------------------------------------------------------------- /docs/webhook_settings_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/docs/webhook_settings_1.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /automotive/src/main/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/automotive/src/main/ic_launcher-playstore.png -------------------------------------------------------------------------------- /automotive/src/main/ic_launcher_alt-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/automotive/src/main/ic_launcher_alt-playstore.png -------------------------------------------------------------------------------- /automotive/src/main/ic_launcher_alt2-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/automotive/src/main/ic_launcher_alt2-playstore.png -------------------------------------------------------------------------------- /automotive/src/main/ic_launcher_club-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/automotive/src/main/ic_launcher_club-playstore.png -------------------------------------------------------------------------------- /automotive/src/main/res/mipmap-xxxhdpi/ic_abrp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/automotive/src/main/res/mipmap-xxxhdpi/ic_abrp.png -------------------------------------------------------------------------------- /automotive/src/main/ic_launcher_alt_dev-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/automotive/src/main/ic_launcher_alt_dev-playstore.png -------------------------------------------------------------------------------- /automotive/src/carapp/res/xml/automotive_app_desc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /automotive/src/main/ic_launcher_alt2_dev-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/automotive/src/main/ic_launcher_alt2_dev-playstore.png -------------------------------------------------------------------------------- /automotive/src/main/ic_launcher_club_dev-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/automotive/src/main/ic_launcher_club_dev-playstore.png -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/database/tripData/PointMarkerType.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.database.tripData 2 | 3 | object PointMarkerType { 4 | } -------------------------------------------------------------------------------- /automotive/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/automotive/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /automotive/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/automotive/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /automotive/src/legacy/res/mipmap-hdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/automotive/src/legacy/res/mipmap-hdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /automotive/src/legacy/res/mipmap-mdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/automotive/src/legacy/res/mipmap-mdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /automotive/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/automotive/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /automotive/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/automotive/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /automotive/src/legacy/res/mipmap-xhdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/automotive/src/legacy/res/mipmap-xhdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /automotive/src/legacy/res/mipmap-xxhdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/automotive/src/legacy/res/mipmap-xxhdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /automotive/src/legacy/res/mipmap-xxxhdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/automotive/src/legacy/res/mipmap-xxxhdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /automotive/src/main/res/mipmap-hdpi/ic_launcher_foreground_dev.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/automotive/src/main/res/mipmap-hdpi/ic_launcher_foreground_dev.webp -------------------------------------------------------------------------------- /automotive/src/main/res/mipmap-mdpi/ic_launcher_foreground_dev.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/automotive/src/main/res/mipmap-mdpi/ic_launcher_foreground_dev.webp -------------------------------------------------------------------------------- /automotive/src/main/res/mipmap-xhdpi/ic_launcher_foreground_dev.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/automotive/src/main/res/mipmap-xhdpi/ic_launcher_foreground_dev.webp -------------------------------------------------------------------------------- /automotive/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/automotive/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /automotive/src/main/res/mipmap-xxxhdpi/ic_launcher_notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/automotive/src/main/res/mipmap-xxxhdpi/ic_launcher_notification.png -------------------------------------------------------------------------------- /automotive/src/legacy/res/mipmap-hdpi/ic_launcher_foreground_dev.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/automotive/src/legacy/res/mipmap-hdpi/ic_launcher_foreground_dev.webp -------------------------------------------------------------------------------- /automotive/src/legacy/res/mipmap-mdpi/ic_launcher_foreground_dev.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/automotive/src/legacy/res/mipmap-mdpi/ic_launcher_foreground_dev.webp -------------------------------------------------------------------------------- /automotive/src/legacy/res/mipmap-xhdpi/ic_launcher_foreground_dev.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/automotive/src/legacy/res/mipmap-xhdpi/ic_launcher_foreground_dev.webp -------------------------------------------------------------------------------- /automotive/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_dev.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/automotive/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_dev.webp -------------------------------------------------------------------------------- /automotive/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_dev.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/automotive/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_dev.webp -------------------------------------------------------------------------------- /automotive/src/legacy/res/mipmap-xxhdpi/ic_launcher_foreground_dev.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/automotive/src/legacy/res/mipmap-xxhdpi/ic_launcher_foreground_dev.webp -------------------------------------------------------------------------------- /automotive/src/legacy/res/mipmap-xxxhdpi/ic_launcher_foreground_dev.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ixam97/CarStatsViewer/HEAD/automotive/src/legacy/res/mipmap-xxxhdpi/ic_launcher_foreground_dev.webp -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/ui/plot/enums/PlotDirection.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.ui.plot.enums 2 | 3 | enum class PlotDirection { 4 | LEFT_TO_RIGHT, RIGHT_TO_LEFT 5 | } -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/ui/plot/enums/PlotLabelPosition.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.ui.plot.enums 2 | 3 | enum class PlotLabelPosition { 4 | LEFT, RIGHT, NONE 5 | } -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/ui/plot/enums/PlotSessionGapRendering.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.ui.plot.enums 2 | 3 | enum class PlotSessionGapRendering { 4 | NONE, JOIN, CIRCLE, GAP 5 | } -------------------------------------------------------------------------------- /automotive/src/mapboxdummy/java/com/ixam97/carStatsViewer/map/Mapbox.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.map 2 | 3 | // This is a dummy class 4 | object Mapbox: MapboxInterface { 5 | override fun isDummy() = true 6 | } -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/ui/plot/enums/PlotDimensionSmoothingType.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.ui.plot.enums 2 | 3 | enum class PlotDimensionSmoothingType { 4 | VALUE, PERCENTAGE, PIXEL 5 | } -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/ui/plot/objects/PlotPoint.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.ui.plot.objects 2 | 3 | class PlotPoint( 4 | val x: Float, 5 | val y: PlotLineItem, 6 | val group: Any) -------------------------------------------------------------------------------- /automotive/src/dev/res/values/preferences_keys.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.ixam97.carStatsViewer_dev.preferences 4 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/database/tripData/SessionMarkerType.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.database.tripData 2 | 3 | object SessionMarkerType { 4 | const val PARK = 2 5 | const val CHARGE = 1 6 | } -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/ui/plot/enums/PlotLineLabelFormat.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.ui.plot.enums 2 | 3 | enum class PlotLineLabelFormat { 4 | NUMBER, FLOAT, PERCENTAGE, TIME, DISTANCE, ALTITUDE 5 | } -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/pressed_foreground.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /automotive/src/main/res/anim/slide_in_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /automotive/src/main/res/anim/slide_out_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/bg_multibutton.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /automotive/src/dev/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Car Stats Viewer (Dev) 4 | CSV (Dev) 5 | -------------------------------------------------------------------------------- /automotive/src/carapp/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Car Stats Viewer (Play Edition) 4 | CSV (Play) 5 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Jun 25 15:11:26 PDT 2020 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip 7 | -------------------------------------------------------------------------------- /automotive/src/devCarapp/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Car Stats Viewer (Play Edition, Dev) 4 | CSV (Play, Dev) 5 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/ui/plot/enums/PlotHighlightMethod.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.ui.plot.enums 2 | 3 | enum class PlotHighlightMethod { 4 | MIN, MAX, FIRST, LAST, AVG_BY_DIMENSION, AVG_BY_INDEX, AVG_BY_DISTANCE, AVG_BY_TIME, AVG_BY_STATE_OF_CHARGE, RAW, NONE 5 | } -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/utils/Exclude.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.utils 2 | 3 | import java.lang.annotation.Retention 4 | import java.lang.annotation.RetentionPolicy 5 | 6 | @Retention(RetentionPolicy.RUNTIME) 7 | @Target(AnnotationTarget.FIELD) 8 | annotation class Exclude -------------------------------------------------------------------------------- /automotive/src/main/res/color/switch_tint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /automotive/src/main/res/anim/slide_in_up.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | -------------------------------------------------------------------------------- /automotive/src/main/res/anim/snackbar_up.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | -------------------------------------------------------------------------------- /automotive/src/main/res/anim/stay_still.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/bg_club.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /automotive/src/main/res/anim/slide_in_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | -------------------------------------------------------------------------------- /automotive/src/main/res/anim/slide_out_down.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | -------------------------------------------------------------------------------- /automotive/src/main/res/anim/slide_out_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | -------------------------------------------------------------------------------- /automotive/src/main/res/anim/snackbar_down.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /automotive/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /automotive/src/dev/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/bg_main_tile.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/database/log/LogDatabase.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.database.log 2 | 3 | import androidx.room.Database 4 | import androidx.room.RoomDatabase 5 | 6 | @Database(entities = [LogEntry::class], version = 1) 7 | abstract class LogDatabase: RoomDatabase() { 8 | abstract fun logDao(): LogDao 9 | } 10 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/bg_action_bar.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/bg_content.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /config/libraries/egm96.json: -------------------------------------------------------------------------------- 1 | { 2 | "uniqueId": "com.github.matthiaszimmermann:EGM96", 3 | "developers": [ 4 | { 5 | "name" : "Matthias Zimmermann" 6 | } 7 | ], 8 | "artifactVersion": "master-SNAPSHOT", 9 | "description": "", 10 | "name": "EGM96", 11 | "licenses": [ 12 | "MIT" 13 | ], 14 | "website": "https://github.com/matthiaszimmermann/EGM96" 15 | } -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/club_thumb.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 9 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/repository/logSubmit/LogSubmitService.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.repository.logSubmit 2 | 3 | import android.app.Service 4 | import android.content.Intent 5 | import android.os.IBinder 6 | 7 | class LogSubmitService: Service() { 8 | 9 | override fun onBind(p0: Intent?): IBinder? { 10 | return null 11 | } 12 | 13 | } -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/club_button.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 9 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/ui/plot/objects/PlotRange.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.ui.plot.objects 2 | 3 | class PlotRange( 4 | val minNegative: Float? = null, 5 | val minPositive: Float? = null, 6 | val maxNegative: Float? = null, 7 | val maxPositive: Float? = null, 8 | val smoothAxis : Float? = null, 9 | val backgroundZero : Float? = null 10 | ) -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/utils/GetColorFromAttribute.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.utils 2 | 3 | import android.content.Context 4 | import android.util.TypedValue 5 | 6 | fun getColorFromAttribute(context: Context, attrId: Int): Int { 7 | val typedValue = TypedValue() 8 | context.theme.resolveAttribute(attrId, typedValue, true) 9 | return typedValue.data 10 | } -------------------------------------------------------------------------------- /automotive/src/carapp/res/drawable/ic_car_app_minus.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/database/log/LogEntry.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.database.log 2 | 3 | import androidx.room.Entity 4 | import androidx.room.PrimaryKey 5 | 6 | @Entity(tableName = "LogEntries") 7 | data class LogEntry ( 8 | @PrimaryKey(autoGenerate = true) var id: Int? = null, 9 | val epochTime: Long, 10 | val type: Int, 11 | val message: String 12 | ) 13 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/compose/theme/Shape.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.compose.theme 2 | 3 | import androidx.compose.foundation.shape.RoundedCornerShape 4 | import androidx.compose.material.Shapes 5 | import androidx.compose.ui.unit.dp 6 | 7 | val Shapes = Shapes( 8 | small = RoundedCornerShape(4.dp), 9 | medium = RoundedCornerShape(4.dp), 10 | large = RoundedCornerShape(0.dp) 11 | ) -------------------------------------------------------------------------------- /automotive/src/main/res/color/button_foreground.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_chevron_back.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/liveDataApi/abrpLiveData/AbrpDataSet.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.liveDataApi.abrpLiveData 2 | 3 | data class AbrpDataSet( 4 | val stateOfCharge: Int, 5 | val power: Float, 6 | val isCharging: Boolean, 7 | val speed: Float, 8 | val isParked: Boolean, 9 | val lat: Double?, 10 | val lon: Double?, 11 | val alt: Double?, 12 | val temp: Float 13 | ) 14 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/ui/plot/enums/PlotDimensionY.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.ui.plot.enums 2 | 3 | enum class PlotDimensionY { 4 | SPEED, DISTANCE, TIME, STATE_OF_CHARGE, ALTITUDE; 5 | 6 | companion object { 7 | val IndexMap = mapOf( 8 | 0 to null, 9 | 1 to SPEED, 10 | 2 to STATE_OF_CHARGE, 11 | 3 to ALTITUDE 12 | ) 13 | } 14 | } -------------------------------------------------------------------------------- /automotive/src/main/res/color/button_text.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 10 | 11 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/ui/plot/enums/PlotDimensionX.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.ui.plot.enums 2 | 3 | enum class PlotDimensionX { 4 | INDEX, DISTANCE, TIME, STATE_OF_CHARGE; 5 | 6 | fun toPlotDirection(): PlotDirection { 7 | return when (this) { 8 | TIME, STATE_OF_CHARGE -> PlotDirection.LEFT_TO_RIGHT 9 | else -> PlotDirection.RIGHT_TO_LEFT 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/dataProcessor/DrivingState.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.dataProcessor 2 | 3 | object DrivingState { 4 | const val UNKNOWN = -1 5 | const val PARKED = 0 6 | const val DRIVE = 1 7 | const val CHARGE = 2 8 | 9 | val nameMap = mapOf( 10 | UNKNOWN to "UNKNOWN", 11 | PARKED to "PARKED", 12 | DRIVE to "DRIVE", 13 | CHARGE to "CHARGE" 14 | ) 15 | } -------------------------------------------------------------------------------- /automotive/src/carapp/res/drawable/ic_car_app_plus.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/database/tripData/TripType.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.database.tripData 2 | 3 | object TripType { 4 | const val MANUAL = 1 5 | const val SINCE_CHARGE = 2 6 | const val AUTO = 3 7 | const val MONTH = 4 8 | 9 | val tripTypesNameMap = mapOf( 10 | MANUAL to "manual", 11 | AUTO to "auto", 12 | SINCE_CHARGE to "since charge", 13 | MONTH to "monthly" 14 | ) 15 | } -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/locationClient/LocationClient.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.locationClient 2 | 3 | import android.content.Context 4 | import android.location.Location 5 | import kotlinx.coroutines.flow.Flow 6 | 7 | interface LocationClient { 8 | fun getLocationUpdates(interval: Long, context: Context): Flow 9 | fun stopLocationUpdates() 10 | class LocationException(message: String): Exception(message) 11 | } -------------------------------------------------------------------------------- /automotive/src/carapp/res/drawable/ic_car_app_menu.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /automotive/src/legacy/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_chevron_up.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/ui/plot/enums/PlotMarkerType.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.ui.plot.enums 2 | 3 | enum class PlotMarkerType { 4 | CHARGE, PARK; 5 | 6 | fun getType(type: Int): PlotMarkerType = when (type) { 7 | 1 -> CHARGE 8 | 2 -> PARK 9 | else -> throw(Exception("Unknown marker type")) 10 | } 11 | 12 | fun getInt(type: PlotMarkerType): Int = when (type) { 13 | CHARGE -> 1 14 | PARK -> 2 15 | } 16 | } -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/utils/SetContentViewAndTheme.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.utils 2 | 3 | import android.app.Activity 4 | import android.view.View 5 | import com.ixam97.carStatsViewer.CarStatsViewer 6 | import com.ixam97.carStatsViewer.R 7 | 8 | /* 9 | fun setContentViewAndTheme(context: Activity, view: View) { 10 | if (CarStatsViewer.appPreferences.colorTheme > 0) context.setTheme(R.style.ColorTestTheme) 11 | context.setContentView(view) 12 | } 13 | */ -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/compose/Event.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.compose 2 | 3 | open class Event(private val content: T) { 4 | var wasConsumed = false 5 | private set 6 | 7 | fun peek() = content 8 | 9 | fun consume(): T? { 10 | return when (wasConsumed) { 11 | true -> null 12 | false -> { 13 | wasConsumed = true 14 | content 15 | } 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_chevron_left.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_chevron_right.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - '*' 7 | 8 | jobs: 9 | build: 10 | name: Build 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v2 15 | - name: set up JDK 17 16 | uses: actions/setup-java@v1 17 | with: 18 | java-version: 17 19 | 20 | - name: Make gradlew executable 21 | run: chmod +x ./gradlew 22 | 23 | - name: Build with Gradle 24 | run: ./gradlew build 25 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_filter_active.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_arrow_diagonal.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/carapp/res/drawable/ic_car_app_upgrade.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/utils/FlowThrottle.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.utils 2 | 3 | import kotlinx.coroutines.delay 4 | import kotlinx.coroutines.flow.Flow 5 | import kotlinx.coroutines.flow.conflate 6 | import kotlinx.coroutines.flow.flow 7 | 8 | fun Flow.throttle(periodMillis: Long): Flow { 9 | if (periodMillis < 0) return this 10 | return flow { 11 | conflate().collect { value -> 12 | emit(value) 13 | delay(periodMillis) 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_arrow_back.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_filter.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/ui/plot/enums/PlotLineMarkerType.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.ui.plot.enums 2 | 3 | enum class PlotLineMarkerType(val int: Int) { 4 | BEGIN_SESSION(1), END_SESSION(2), SINGLE_SESSION(3); 5 | 6 | companion object { 7 | fun getType(type: Int?): PlotLineMarkerType? = when (type) { 8 | 1 -> BEGIN_SESSION 9 | 2 -> END_SESSION 10 | 3 -> SINGLE_SESSION 11 | else -> null // throw(Exception("Unknown marker type")) 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_battery.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /automotive/src/carapp/res/drawable/ic_car_app_altitude.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_avg_consumption.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/utils/WatchdogState.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.utils 2 | 3 | data class WatchdogState( 4 | val locationState: Int = 0, 5 | val apiState: Map = mapOf(), 6 | val appErrorState: AppErrorState = AppErrorState() 7 | ) { 8 | companion object { 9 | const val DISABLED: Int = 0 10 | const val NOMINAL: Int = 1 11 | const val ERROR: Int = 2 12 | const val LIMITED: Int = 3 13 | 14 | data class AppErrorState( 15 | val errorMessage: String? = null 16 | ) 17 | } 18 | } -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_close.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_kill.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_notification_phone.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_upload.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_marker_charge.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/database/tripData/TripDataDatabase.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.database.tripData 2 | 3 | import androidx.room.Database 4 | import androidx.room.RoomDatabase 5 | 6 | @Database(entities = 7 | [ 8 | DrivingSession::class, 9 | DrivingPoint::class, 10 | ChargingSession::class, 11 | ChargingPoint::class, 12 | DrivingSessionPointCrossRef::class, 13 | DrivingChargingCrossRef::class, 14 | SessionMarker::class 15 | ], 16 | version = 6 17 | ) 18 | abstract class TripDataDatabase: RoomDatabase() { 19 | 20 | abstract fun tripDao(): TripDao 21 | } -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_send.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/locationClient/ContextHasLocationPermission.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.locationClient 2 | 3 | import android.content.Context 4 | import android.content.pm.PackageManager 5 | import androidx.core.content.ContextCompat 6 | 7 | fun Context.hasLocationPermission(): Boolean { 8 | return ContextCompat.checkSelfPermission( 9 | this, 10 | android.Manifest.permission.ACCESS_COARSE_LOCATION 11 | ) == PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission( 12 | this, 13 | android.Manifest.permission.ACCESS_FINE_LOCATION 14 | ) == PackageManager.PERMISSION_GRANTED 15 | } -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_marker_park.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /automotive/src/devCarapp/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_power.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /automotive/src/carapp/res/drawable/ic_car_app_tune.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/utils/Ticker.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.utils 2 | 3 | import kotlinx.coroutines.flow.flow 4 | 5 | object Ticker { 6 | fun tickerFlow(interval: Long) = flow { 7 | var startTime = System.currentTimeMillis() 8 | // var loops = 1L 9 | 10 | while (true) { 11 | while (true) { 12 | val currentTime = System.currentTimeMillis() 13 | if (currentTime >= (startTime + interval)) { 14 | startTime = currentTime 15 | break 16 | } 17 | } 18 | // loops ++ 19 | emit(Unit) 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_altitude.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_energy_large.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_login.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_copy.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # built application files 2 | *.apk 3 | *.ap_ 4 | *.aab 5 | 6 | # Mac files 7 | .DS_Store 8 | 9 | # files for the dex VM 10 | *.dex 11 | 12 | # Java class files 13 | *.class 14 | 15 | # generated files 16 | bin/ 17 | gen/ 18 | 19 | # Ignore gradle files 20 | .gradle/ 21 | build/ 22 | 23 | # Local configuration file (sdk path, etc) 24 | local.properties 25 | 26 | # Proguard folder generated by Eclipse 27 | proguard/ 28 | proguard-project.txt 29 | 30 | # Eclipse files 31 | .project 32 | .classpath 33 | .settings/ 34 | 35 | # Android Studio/IDEA 36 | *.iml 37 | .idea 38 | 39 | /automotive/release/ 40 | /automotive/dev/ 41 | credentials.xml 42 | /automotive/stable/ 43 | /automotive/debug/ 44 | /.kotlin/ 45 | -------------------------------------------------------------------------------- /automotive/src/carapp/res/drawable/ic_car_app_battery.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_mail.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_checked_checkbox.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /automotive/src/carapp/res/drawable/ic_car_app_check.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_notification_diagram.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_temperature.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_api.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/dataProcessor/IgnitionState.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.dataProcessor 2 | 3 | import android.car.VehicleIgnitionState 4 | 5 | object IgnitionState { 6 | const val UNDEFINED = VehicleIgnitionState.UNDEFINED 7 | const val LOCK = VehicleIgnitionState.LOCK 8 | const val OFF = VehicleIgnitionState.OFF 9 | const val ACC = VehicleIgnitionState.ACC 10 | const val ON = VehicleIgnitionState.ON 11 | const val START = VehicleIgnitionState.START 12 | 13 | val nameMap = mapOf( 14 | UNDEFINED to "Undefined", 15 | LOCK to "Locked", 16 | OFF to "Off", 17 | ACC to "Accessory", 18 | ON to "On", 19 | START to "Started" 20 | ) 21 | 22 | } -------------------------------------------------------------------------------- /automotive/src/carapp/java/com/ixam97/carStatsViewer/carApp/renderer/Renderer.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.carApp.renderer 2 | 3 | import android.graphics.Canvas 4 | import android.graphics.Rect 5 | 6 | 7 | interface Renderer { 8 | /** 9 | * Informs the renderer that it will receive [.renderFrame] calls. 10 | * 11 | * @param onChangeListener a runnable that will initiate a render pass in the controller 12 | */ 13 | fun enable(onChangeListener: Runnable) 14 | 15 | /** Informs the renderer that it will no longer receive [.renderFrame] calls. */ 16 | fun disable() 17 | 18 | /** Request that a frame should be drawn to the supplied canvas. */ 19 | fun renderFrame(canvas: Canvas, visibleArea: Rect?, stableArea: Rect?) 20 | } 21 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/ui/plot/graphics/PlotLinePaint.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.ui.plot.graphics 2 | 3 | import com.ixam97.carStatsViewer.ui.plot.enums.PlotDimensionY 4 | 5 | class PlotLinePaint( 6 | private val xAxis : PlotPaint, 7 | private val yAxisNormal : PlotPaint, 8 | private val yAxisAlternative : PlotPaint, 9 | private var useYAxisAlternative: () -> Boolean 10 | ) { 11 | fun bySecondaryDimension(secondaryDimension: PlotDimensionY?) : PlotPaint { 12 | return when { 13 | secondaryDimension != null -> when { 14 | useYAxisAlternative.invoke() -> yAxisAlternative 15 | else -> yAxisNormal 16 | } 17 | else -> xAxis 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_phone.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/club_button_off.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 13 | 14 | 15 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/dataProcessor/StaticVehicleData.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.dataProcessor 2 | 3 | import com.ixam97.carStatsViewer.utils.DistanceUnitEnum 4 | 5 | data class StaticVehicleData( 6 | val batteryCapacity: Float? = null, 7 | val vehicleMake: String? = null, 8 | val modelName: String? = null, 9 | val distanceUnit: DistanceUnitEnum? = null 10 | ) { 11 | fun isInitialized(): Boolean = 12 | isEssentialInitialized() && isOptionalInitialized() 13 | 14 | fun isEssentialInitialized(): Boolean = 15 | batteryCapacity != null 16 | 17 | fun isOptionalInitialized(): Boolean = 18 | vehicleMake != null 19 | && modelName != null 20 | && distanceUnit != null 21 | } 22 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_diagram.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_time.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_error.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/carapp/res/drawable/ic_car_app_reset.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_delete.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/repository/logSubmit/LogSubmitApi.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.repository.logSubmit 2 | 3 | import okhttp3.MultipartBody 4 | import retrofit2.Response 5 | import retrofit2.http.Body 6 | import retrofit2.http.Header 7 | import retrofit2.http.Headers 8 | import retrofit2.http.POST 9 | 10 | interface LogSubmitApi { 11 | 12 | @Headers("content-type: application/json") 13 | @POST("/CSVBackend/submitLog") 14 | suspend fun submitLog( 15 | @Header("x-api-key") apiKey: String, 16 | @Body body: LogSubmitBody 17 | ): Response 18 | 19 | @POST("/CSVBackend/imageUpload") 20 | suspend fun uploadImage( 21 | @Header("x-api-key") apiKey: String, 22 | @Body body: MultipartBody 23 | ): Response 24 | 25 | } -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/club_gradient_radial.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | 13 | 14 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /automotive/src/carapp/res/drawable/ic_car_app_dashboard.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/carapp/res/drawable/ic_car_app_history.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/utils/TimestampSynchronizer.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.utils 2 | 3 | class TimestampSynchronizer { 4 | /** 5 | * System time in millis and property timestamp in nanos associated with the same time. 6 | */ 7 | private var systemTime: Long = 0 8 | private var propertyTimestamp: Long = 0 9 | 10 | fun sync(referenceSystemTime: Long, referenceTimestamp: Long) { 11 | systemTime = referenceSystemTime 12 | propertyTimestamp = referenceTimestamp 13 | } 14 | 15 | fun getSystemTimeFromNanosTimestamp(timestamp: Long): Long { 16 | if (!isSynced()) throw Exception("TimestampSynchronizer has not been synced.") 17 | val nanosDelta = (timestamp - propertyTimestamp) / 1_000_000 18 | return systemTime + nanosDelta 19 | } 20 | 21 | fun isSynced() = systemTime > 0 && propertyTimestamp > 0 22 | } -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/club_button_on.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_save.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/carapp/res/drawable/ic_car_app_canvas.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 12 | polar: # Replace with a single Polar username 13 | buy_me_a_coffee: # Replace with a single Buy Me a Coffee username 14 | thanks_dev: # Replace with a single thanks.dev username 15 | custom: ['https://paypal.me/Ixam'] 16 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/liveDataApi/http/HttpDataSet.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.liveDataApi.http 2 | 3 | import com.ixam97.carStatsViewer.database.tripData.ChargingSession 4 | import com.ixam97.carStatsViewer.database.tripData.DrivingPoint 5 | 6 | data class HttpDataSet( 7 | val apiVersion: String = "2.1", 8 | val appVersion: String, 9 | val timestamp: Long, 10 | val speed: Float?, 11 | val power: Float?, 12 | val selectedGear: String, 13 | val ignitionState: String, 14 | val chargePortConnected: Boolean?, 15 | val batteryLevel: Float?, 16 | val stateOfCharge: Float?, 17 | val ambientTemperature: Float?, 18 | val lat: Float?, 19 | val lon: Float?, 20 | val alt: Float?, 21 | 22 | // ABRP debug 23 | val abrpPackage: String? = null, 24 | 25 | val drivingPoints: List? = null, 26 | val chargingSessions: List? = null 27 | ) 28 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_day.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/ui/plot/objects/PlotLineConfiguration.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.ui.plot.objects 2 | 3 | import com.ixam97.carStatsViewer.ui.plot.enums.PlotDimensionSmoothingType 4 | import com.ixam97.carStatsViewer.ui.plot.enums.PlotHighlightMethod 5 | import com.ixam97.carStatsViewer.ui.plot.enums.PlotLineLabelFormat 6 | import com.ixam97.carStatsViewer.ui.plot.enums.PlotSessionGapRendering 7 | 8 | class PlotLineConfiguration( 9 | internal val Range: PlotRange, 10 | var LabelFormat: PlotLineLabelFormat, 11 | var HighlightMethod: PlotHighlightMethod, 12 | var Unit: String, 13 | var Divider: Float = 1f, 14 | var UnitFactor: Float = 1f, 15 | var DimensionSmoothing: Float? = null, 16 | var DimensionSmoothingType: PlotDimensionSmoothingType? = null, 17 | var DimensionSmoothingHighlightMethod: PlotHighlightMethod? = null, 18 | var SessionGapRendering : PlotSessionGapRendering? = null 19 | ) -------------------------------------------------------------------------------- /automotive/src/carapp/java/com/ixam97/carStatsViewer/carApp/CarStatsViewerService.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.carApp 2 | 3 | import android.content.pm.ApplicationInfo 4 | import androidx.car.app.CarAppService 5 | import androidx.car.app.Session 6 | import androidx.car.app.SessionInfo 7 | import androidx.car.app.validation.HostValidator 8 | 9 | 10 | class CarStatsViewerService : CarAppService() { 11 | override fun onCreateSession(sessionInfo: SessionInfo): Session { 12 | return CarStatsViewerSession() 13 | } 14 | 15 | override fun createHostValidator(): HostValidator { 16 | return if (applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE != 0) { 17 | HostValidator.ALLOW_ALL_HOSTS_VALIDATOR 18 | } else { 19 | HostValidator.Builder(applicationContext) 20 | .addAllowedHosts(androidx.car.app.R.array.hosts_allowlist_sample) 21 | .build() 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/liveDataApi/http/TextValidator.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.liveDataApi.http 2 | 3 | import android.text.Editable 4 | import android.text.TextWatcher 5 | import android.widget.TextView 6 | 7 | // Adapted from https://stackoverflow.com/a/11838715 8 | abstract class TextValidator(private val textView: TextView) : TextWatcher { 9 | abstract fun validate(textView: TextView?, text: String?) 10 | override fun afterTextChanged(s: Editable) { 11 | val text = textView.text.toString() 12 | validate(textView, text) 13 | } 14 | 15 | override fun beforeTextChanged( 16 | s: CharSequence, 17 | start: Int, 18 | count: Int, 19 | after: Int 20 | ) { /* Don't care */ 21 | } 22 | 23 | override fun onTextChanged( 24 | s: CharSequence, 25 | start: Int, 26 | before: Int, 27 | count: Int 28 | ) { /* Don't care */ 29 | } 30 | } -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/compose/screens/settings/Changelog.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.compose.screens.settings 2 | 3 | import androidx.compose.foundation.layout.fillMaxSize 4 | import androidx.compose.runtime.Composable 5 | import androidx.compose.ui.Modifier 6 | import androidx.compose.ui.platform.LocalContext 7 | import com.ixam97.carStatsViewer.compose.DefaultColumnScrollbar 8 | import com.ixam97.carStatsViewer.compose.components.CarRow 9 | import com.ixam97.carStatsViewer.utils.ChangeLogCreator 10 | 11 | @Composable 12 | fun Changelog() { 13 | DefaultColumnScrollbar( 14 | modifier = Modifier 15 | .fillMaxSize() 16 | ) { 17 | val changelogMap = ChangeLogCreator.createChangelog(LocalContext.current) 18 | 19 | changelogMap.forEach { (version, changes) -> 20 | CarRow( 21 | title = version, 22 | text = changes 23 | ) 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/utils/GetBitmapFromVectorDrawable.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.utils 2 | 3 | import android.content.Context 4 | import android.graphics.Bitmap 5 | import android.graphics.Canvas 6 | import android.os.Build 7 | import androidx.core.content.ContextCompat 8 | import androidx.core.graphics.drawable.DrawableCompat 9 | 10 | 11 | fun getBitmapFromVectorDrawable(context: Context?, drawableId: Int): Bitmap { 12 | var drawable = ContextCompat.getDrawable(context!!, drawableId) 13 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { 14 | drawable = DrawableCompat.wrap(drawable!!).mutate() 15 | } 16 | 17 | val bitmap = Bitmap.createBitmap( 18 | drawable!!.intrinsicWidth, 19 | drawable.intrinsicHeight, Bitmap.Config.ARGB_8888 20 | ) 21 | val canvas = Canvas(bitmap) 22 | drawable.setBounds(0, 0, canvas.width, canvas.height) 23 | drawable.draw(canvas) 24 | 25 | return bitmap 26 | } -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_car_app_feedback.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_location_on.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_charger.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/repository/logSubmit/LogSubmit.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.repository.logSubmit 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class LogSubmitBody( 7 | val log: Map, 8 | val userID: String, 9 | val metadata: LogMetadata 10 | ) { 11 | @Serializable 12 | data class LogMetadata( 13 | val timestamp: Long, 14 | val brand: String, 15 | val model: String, 16 | val device: String, 17 | val appInfo: String, 18 | val cpuInfo: String 19 | ) 20 | } 21 | 22 | @Serializable 23 | data class AuthResponse( 24 | val authorized: String 25 | ) 26 | 27 | @Serializable 28 | data class LogSubmitStatus( 29 | val status: String, 30 | val message: String? 31 | ) 32 | 33 | @Serializable 34 | sealed interface LogSubmitState { 35 | @Serializable 36 | data object Success: LogSubmitState 37 | 38 | @Serializable 39 | data object Error: LogSubmitState 40 | } -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_reset.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_connected.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/main/res/values/broadcast_actions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_link.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /automotive/src/main/res/layout/widget_fixed_switch.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 14 | 19 | 23 | 24 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_history.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_distance.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /automotive/src/main/res/values-sw700dp-land/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 101dp 4 | 60dp 5 | 75dp 6 | 50dp 7 | 74dp 8 | 31sp 9 | 27sp 10 | 20sp 11 | 45sp 12 | 500 13 | 400 14 | 32sp 15 | 2dp 16 | 70dp 17 | 60dp 18 | 100sp 19 | 30sp 20 | 15dp 21 | 2dp 22 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_car.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/utils/Watchdog.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.utils 2 | 3 | import kotlinx.coroutines.CoroutineScope 4 | import kotlinx.coroutines.Dispatchers 5 | import kotlinx.coroutines.flow.MutableSharedFlow 6 | import kotlinx.coroutines.flow.MutableStateFlow 7 | import kotlinx.coroutines.flow.asSharedFlow 8 | import kotlinx.coroutines.flow.asStateFlow 9 | import kotlinx.coroutines.launch 10 | 11 | class Watchdog() { 12 | private val _watchdogStateFlow = MutableStateFlow(WatchdogState()) 13 | val watchdogStateFlow = _watchdogStateFlow.asStateFlow() 14 | private val _watchdogTriggerFlow = MutableSharedFlow(replay = 0) 15 | val watchdogTriggerFlow = _watchdogTriggerFlow.asSharedFlow() 16 | 17 | fun getCurrentWatchdogState() = watchdogStateFlow.value 18 | 19 | fun updateWatchdogState(watchdogState: WatchdogState) { 20 | _watchdogStateFlow.value = watchdogState 21 | } 22 | 23 | fun triggerWatchdog() { 24 | CoroutineScope(Dispatchers.Default).launch { 25 | _watchdogTriggerFlow.emit(Unit) 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_month.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /automotive/src/carapp/res/drawable/ic_car_app_status.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_camera.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-2023 Maximilian Goldschmidt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_construction.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/utils/TimeTracker.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.utils 2 | 3 | import java.util.Date 4 | 5 | /** 6 | * The TimeTracker is able to track a time span based on the Date-object. 7 | */ 8 | class TimeTracker { 9 | private var startDate: Date? = null 10 | private var timeSpan: Long = 0 11 | 12 | /** Start or resume time tracking */ 13 | fun start() { 14 | if (startDate == null) startDate = Date() 15 | } 16 | 17 | /** Stop time tracking */ 18 | fun stop() { 19 | startDate.let { 20 | if (it != null) timeSpan += (Date().time - it.time) 21 | } 22 | startDate = null 23 | } 24 | 25 | /** Reset tracked time to zero */ 26 | fun reset() { 27 | startDate = null 28 | timeSpan = 0L 29 | } 30 | 31 | /** Restore tracked time to defined base value */ 32 | fun restore(pTimeSpan: Long) { 33 | timeSpan = pTimeSpan 34 | } 35 | 36 | /** returns the current tracked time in milliseconds */ 37 | fun getTime(): Long { 38 | return timeSpan + (Date().time - (startDate?.time?: Date().time)) 39 | } 40 | } -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_temperature_large.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_hand.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /automotive/src/carapp/java/com/ixam97/carStatsViewer/carApp/DevNoticeScreen.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.carApp 2 | 3 | import androidx.car.app.CarContext 4 | import androidx.car.app.Screen 5 | import androidx.car.app.model.Action 6 | import androidx.car.app.model.LongMessageTemplate 7 | import androidx.car.app.model.ParkedOnlyOnClickListener 8 | import androidx.car.app.model.Template 9 | import com.ixam97.carStatsViewer.R 10 | 11 | class DevNoticeScreen(carContext: CarContext): Screen(carContext) { 12 | 13 | override fun onGetTemplate(): Template { 14 | return LongMessageTemplate.Builder(carContext.getString(R.string.car_app_dev_notice_message)).apply { 15 | setTitle(carContext.getString(R.string.car_app_dev_notice_title)) 16 | setHeaderAction(Action.APP_ICON) 17 | addAction(Action.Builder().apply { 18 | setTitle(carContext.getString(R.string.car_app_dev_notice_confirm)) 19 | setFlags(Action.FLAG_PRIMARY) 20 | setOnClickListener(ParkedOnlyOnClickListener.create { 21 | screenManager.pop() 22 | }) 23 | }.build()) 24 | }.build() 25 | } 26 | } -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | gradlePluginPortal() 6 | } 7 | } 8 | 9 | dependencyResolutionManagement { 10 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 11 | repositories { 12 | google() 13 | mavenCentral() 14 | maven { url 'https://jitpack.io' } 15 | if (useMapbox.toBoolean()) { 16 | maven { 17 | 18 | url = uri("https://api.mapbox.com/downloads/v2/releases/maven") 19 | // Do not change the username below. It should always be "mapbox" (not your username). 20 | credentials.username = "mapbox" 21 | // Use the secret token stored in local.properties (not tracked by git) as the password 22 | 23 | Properties properties = new Properties() 24 | properties.load(file("local.properties").newDataInputStream()) 25 | 26 | credentials.password = properties.getProperty("MAPBOX_DOWNLOADS_TOKEN") 27 | authentication { basic(BasicAuthentication) } 28 | } 29 | } 30 | } 31 | } 32 | 33 | include ':automotive' 34 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/compose/components/CarIconButton.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.compose.components 2 | 3 | import androidx.annotation.DrawableRes 4 | import androidx.compose.foundation.layout.padding 5 | import androidx.compose.foundation.layout.size 6 | import androidx.compose.material.Icon 7 | import androidx.compose.material.IconButton 8 | import androidx.compose.runtime.Composable 9 | import androidx.compose.ui.Modifier 10 | import androidx.compose.ui.graphics.Color 11 | import androidx.compose.ui.res.painterResource 12 | import androidx.compose.ui.unit.dp 13 | 14 | @Composable 15 | fun CarIconButton( 16 | modifier: Modifier = Modifier, 17 | onClick: () -> Unit, 18 | @DrawableRes iconResId: Int, 19 | tint: Color = Color.White, 20 | enabled: Boolean = true 21 | ) { 22 | IconButton( 23 | enabled = enabled, 24 | modifier = modifier 25 | .padding(10.dp) 26 | .size(70.dp), 27 | onClick = onClick 28 | ) { 29 | Icon( 30 | painterResource(id = iconResId), 31 | tint = tint.copy(alpha = if (enabled) 1f else 0.3f), 32 | contentDescription = null, 33 | ) 34 | } 35 | } -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_checkmark.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_remaining_range.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/ui/views/MultiLineRowButtonWidget.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.ui.views 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import android.view.View 6 | import android.widget.LinearLayout 7 | import android.widget.TextView 8 | import com.ixam97.carStatsViewer.R 9 | 10 | class MultiLineRowButtonWidget @JvmOverloads constructor( 11 | context: Context, 12 | attrs: AttributeSet? = null, 13 | defStyleAttr: Int = 0 14 | ): LinearLayout(context, attrs, defStyleAttr) { 15 | 16 | var topText = "" 17 | set(value) { 18 | field = value 19 | init() 20 | } 21 | var bottomText = "" 22 | set(value) { 23 | field = value 24 | init() 25 | } 26 | 27 | init { 28 | init() 29 | } 30 | 31 | private fun init() { 32 | this.removeAllViews() 33 | View.inflate(context, R.layout.widget_menu_row, this) 34 | val topTextView: TextView = findViewById(R.id.row_top_text) 35 | val bottomTextView: TextView = findViewById(R.id.distance_text) 36 | topTextView.text = topText 37 | bottomTextView.text = bottomText 38 | } 39 | } -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/liveDataApi/abrpLiveData/AppPreferencesExt.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.liveDataApi.abrpLiveData 2 | 3 | /** 4 | * This file extends the AppPreferences to contain keys used by the API implementation. The rest of 5 | * the app does not need to see them. 6 | */ 7 | 8 | import com.ixam97.carStatsViewer.appPreferences.AppPreference 9 | import com.ixam97.carStatsViewer.appPreferences.AppPreferences 10 | 11 | val AppPreferences.AbrpGenericToken: AppPreference 12 | get() = AppPreference("preference_abrp_generic_token", "", sharedPref) 13 | val AppPreferences.AbrpUseApi: AppPreference 14 | get() = AppPreference("preference_abrp_use", false, sharedPref) 15 | val AppPreferences.AbrpUseLocation: AppPreference 16 | get() = AppPreference("preference_abrp_location", true, sharedPref) 17 | 18 | var AppPreferences.abrpGenericToken: String get() = AbrpGenericToken.value; set(value) {AbrpGenericToken.value = value} 19 | var AppPreferences.abrpUseApi: Boolean get() = AbrpUseApi.value; set(value) {AbrpUseApi.value = value} 20 | var AppPreferences.abrpUseLocation: Boolean get() = AbrpUseLocation.value; set(value) {AbrpUseLocation.value = value} -------------------------------------------------------------------------------- /automotive/src/carapp/res/drawable/ic_car_app_debug.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_coffee.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_location_error.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/main/res/values-sw1000dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 101dp 4 | 80dp 5 | 100dp 6 | 45dp 7 | 74dp 8 | 31sp 9 | 27sp 10 | 23sp 11 | 20sp 12 | 47sp 13 | 500 14 | 400 15 | 32sp 16 | 2dp 17 | 70dp 18 | 60dp 19 | 115sp 20 | @dimen/std_font_size 21 | 0dp 22 | 2dp 23 | 8 24 | 6 25 | -------------------------------------------------------------------------------- /automotive/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 70dp 4 | 60dp 5 | 75dp 6 | 38dp 7 | 60dp 8 | 28sp 9 | 24sp 10 | 20sp 11 | 18sp 12 | 45sp 13 | 550 14 | 300 15 | 27sp 16 | 2dp 17 | 60dp 18 | 48dp 19 | 90sp 20 | 25sp 21 | 36dp 22 | 2dp 23 | 70dp 24 | 7 25 | 7 26 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_time_large.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/carapp/res/drawable/ic_car_app_list.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_info.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /automotive/src/carapp/res/drawable/ic_car_app_speed.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/ui/plot/graphics/PlotMarkerPaint.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.ui.plot.graphics 2 | 3 | import android.graphics.Color 4 | import android.graphics.Paint 5 | 6 | class PlotMarkerPaint( 7 | val Mark: Paint, 8 | val Label: Paint 9 | ){ 10 | companion object { 11 | fun byColor(color : Int, textSize: Float): PlotMarkerPaint { 12 | val basePaint = basePaint(textSize) 13 | 14 | val markerPaint = Paint(basePaint) 15 | markerPaint.strokeWidth = 2f 16 | markerPaint.color = Color.argb(64, Color.red(color), Color.green(color), Color.blue(color)) 17 | markerPaint.style = Paint.Style.FILL_AND_STROKE 18 | 19 | val labelPaint = Paint(basePaint) 20 | labelPaint.color = color 21 | labelPaint.textSize = textSize - 6f 22 | 23 | return PlotMarkerPaint(markerPaint, labelPaint) 24 | } 25 | 26 | fun basePaint(textSize: Float): Paint { 27 | // defines paint and canvas 28 | val basePaint = Paint() 29 | basePaint.color = Color.GRAY 30 | basePaint.isAntiAlias = true 31 | basePaint.strokeWidth = 1f 32 | basePaint.style = Paint.Style.FILL 33 | basePaint.strokeJoin = Paint.Join.ROUND 34 | basePaint.strokeCap = Paint.Cap.ROUND 35 | basePaint.textSize = textSize 36 | 37 | return basePaint 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/compose/theme/Color.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.compose.theme 2 | 3 | import androidx.compose.ui.graphics.Color 4 | 5 | val polestarOrange = Color(0xFFD96C00) 6 | val polestarSurface = Color(0xff1f1f1f)// Color(0xff090909) 7 | val volvoBlue = Color(0xFF2F6093) 8 | 9 | val disabledTextColor = Color(0xFF757575) 10 | val disabledOverlayColor = Color(0x8A000000) 11 | 12 | val darkBackground = Color(0xFF1B1B1B) 13 | val mainBackground = Color(0xFF1F1F1F) 14 | val headerBackground = Color(0xFF282A2D) 15 | val primaryButtonGray = Color(0xFF3E4146) 16 | val primaryGray = Color(0xFF7B858A) 17 | val secondaryGray = Color(0xFFA3B1B8) 18 | 19 | val newPolestarBackground = Color(0xFF141516) 20 | 21 | val clubBlueLight = Color(0xff60bcd5) 22 | val clubBlue = Color(0xff447ea6) 23 | val clubBlueDeep = Color(0xff0c4b5d) 24 | val clubBlueDark = Color(0xff161d39) 25 | val clubVioletLight = Color(0xff8480bd) 26 | val clubViolet = Color(0xff77347b) 27 | val clubVioletDark = Color(0xff2a1037) 28 | val clubLight = Color(0xffefefef) 29 | val clubMedium = Color(0xff707a83) 30 | val clubNightVariant = Color(0xff111922) 31 | val clubNight = Color(0xff0a0f14) 32 | val clubNightDarker = Color(0xff05080C) 33 | val clubHint = Color(0xfff7ea48) 34 | 35 | val badRed = Color(0xffEB1717) 36 | 37 | val slideUpBackground = Color(0xff090909) 38 | 39 | val conConnected = Color(0xFF2595FF) 40 | val conLimited = Color(0xFFFFBF00) 41 | val conError = badRed 42 | val conUnused = disabledTextColor -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app's APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | # Kotlin code style for this project: "official" or "obsolete": 21 | kotlin.code.style=official 22 | android.defaults.buildfeatures.buildconfig=true 23 | android.nonTransitiveRClass=false 24 | android.nonFinalResIds=false 25 | 26 | # Configure if Firebase and/or Mapbox should be used (Require some secrests) 27 | # See dcumentation: TODO 28 | useMapbox=false 29 | useFirebase=false 30 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/database/log/LogDao.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.database.log 2 | 3 | import androidx.room.Dao 4 | import androidx.room.Delete 5 | import androidx.room.Insert 6 | import androidx.room.Query 7 | 8 | @Dao 9 | interface LogDao { 10 | 11 | @Query("SELECT * FROM LogEntries ORDER BY epochTime ASC, id ASC") 12 | fun getAll(): List 13 | 14 | @Query("SELECT * FROM LogEntries WHERE type >= :logLevel ORDER BY epochTime ASC, id ASC") 15 | fun getLevel(logLevel: Int): List 16 | 17 | @Query("SELECT * FROM LogEntries WHERE type >= :logLevel ORDER BY epochTime DESC, id DESC LIMIT :length") 18 | // @Query("SELECT * FROM LogEntries WHERE type >= :logLevel LIMIT :length") 19 | fun getLevelAndLength(logLevel: Int, length: Int): List 20 | 21 | @Query("SELECT * FROM LogEntries WHERE epochTime BETWEEN :firstTime AND :lastTime ORDER BY epochTime ASC, id ASC") 22 | fun getTimeSpan(firstTime: Long, lastTime: Long): List 23 | 24 | fun getTimeSpan(timeSpan: Long): List { 25 | val lastTime = System.currentTimeMillis() 26 | val firstTime = lastTime - timeSpan 27 | return getTimeSpan(firstTime, lastTime) 28 | } 29 | 30 | @Insert 31 | fun insert(logEntry: LogEntry) 32 | 33 | @Delete 34 | fun delete(logEntry: LogEntry) 35 | 36 | @Query("DELETE FROM LogEntries") 37 | fun clear() 38 | 39 | @Query("DELETE FROM LogEntries WHERE epochTime < :timeLimit") 40 | fun trim(timeLimit: Long) 41 | } -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_distance_large.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_list.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | -------------------------------------------------------------------------------- /automotive/src/carapp/java/com/ixam97/carStatsViewer/carApp/ChargingSessionDetailsScreen.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.carApp 2 | 3 | import androidx.car.app.CarContext 4 | import androidx.car.app.Screen 5 | import androidx.car.app.model.Action 6 | import androidx.car.app.model.Header 7 | import androidx.car.app.model.Pane 8 | import androidx.car.app.model.PaneTemplate 9 | import androidx.car.app.model.Row 10 | import androidx.car.app.model.Template 11 | import androidx.lifecycle.DefaultLifecycleObserver 12 | import com.ixam97.carStatsViewer.database.tripData.ChargingSession 13 | import com.ixam97.carStatsViewer.utils.StringFormatters 14 | import java.util.Date 15 | 16 | class ChargingSessionDetailsScreen( 17 | carContext: CarContext, 18 | private val chargingSession: ChargingSession, 19 | private val chargingLocation: String? 20 | ): Screen(carContext), DefaultLifecycleObserver { 21 | 22 | init { 23 | lifecycle.addObserver(this) 24 | } 25 | 26 | override fun onGetTemplate(): Template { 27 | return chargingSessionDetailsTemplate() 28 | } 29 | 30 | private fun chargingSessionDetailsTemplate() = PaneTemplate.Builder( 31 | Pane.Builder().apply { 32 | addRow(Row.Builder().apply { 33 | setTitle(StringFormatters.getDateString(Date(chargingSession.start_epoch_time))) 34 | }.build()) 35 | }.build() 36 | ).apply { 37 | setHeader(Header.Builder().apply { 38 | setTitle("Charging Session") 39 | setStartHeaderAction(Action.BACK) 40 | }.build()) 41 | }.build() 42 | } -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_speed.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_speed_large.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/carapp/java/com/ixam97/carStatsViewer/carApp/RealTimeDataScreen.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.carApp 2 | 3 | import androidx.car.app.CarContext 4 | import androidx.car.app.Screen 5 | import androidx.car.app.model.Template 6 | import androidx.lifecycle.DefaultLifecycleObserver 7 | import androidx.lifecycle.LifecycleOwner 8 | import androidx.lifecycle.lifecycleScope 9 | import com.ixam97.carStatsViewer.CarStatsViewer 10 | import com.ixam97.carStatsViewer.utils.throttle 11 | import kotlinx.coroutines.launch 12 | 13 | class RealTimeDataScreen( 14 | carContext: CarContext, 15 | val session: CarStatsViewerSession 16 | ): Screen(carContext), DefaultLifecycleObserver { 17 | 18 | private val realTimeDataTemplate = RealTimeDataTemplate( 19 | carContext, 20 | session, 21 | backButton = true, 22 | navigationOnly = false 23 | ) { 24 | invalidate() 25 | } 26 | 27 | init { 28 | lifecycle.addObserver(this) 29 | lifecycleScope.launch { 30 | CarStatsViewer.dataProcessor.realTimeDataFlow.throttle(500).collect { 31 | if (session.carDataSurfaceCallback.isEnabled()) session.carDataSurfaceCallback.requestRenderFrame() 32 | } 33 | } 34 | } 35 | 36 | override fun onCreate(owner: LifecycleOwner) { 37 | session.carDataSurfaceCallback.resume() 38 | } 39 | 40 | override fun onGetTemplate(): Template { 41 | return realTimeDataTemplate.getTemplate() 42 | } 43 | 44 | override fun onDestroy(owner: LifecycleOwner) { 45 | session.carDataSurfaceCallback.pause() 46 | } 47 | } -------------------------------------------------------------------------------- /automotive/src/carapp/java/com/ixam97/carStatsViewer/carApp/ConfirmResetScreen.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.carApp 2 | 3 | import androidx.car.app.CarContext 4 | import androidx.car.app.Screen 5 | import androidx.car.app.model.Action 6 | import androidx.car.app.model.CarIcon 7 | import androidx.car.app.model.MessageTemplate 8 | import androidx.car.app.model.Template 9 | import androidx.core.graphics.drawable.IconCompat 10 | import com.ixam97.carStatsViewer.R 11 | 12 | class ConfirmResetScreen(carContext: CarContext) : Screen(carContext) { 13 | 14 | override fun onGetTemplate(): Template { 15 | return dialogTemplate() 16 | } 17 | 18 | private fun dialogTemplate() = MessageTemplate.Builder( 19 | carContext.getString(R.string.dialog_reset_message) 20 | ).apply { 21 | setHeaderAction(Action.BACK) 22 | setTitle(carContext.getString(R.string.dialog_reset_title)) 23 | setIcon(CarIcon.Builder(IconCompat.createWithResource(carContext, R.drawable.ic_reset)).build()) 24 | addAction(Action.Builder().apply { 25 | setTitle(carContext.getString(R.string.dialog_reset_confirm)) 26 | setFlags(Action.FLAG_PRIMARY) 27 | setOnClickListener { 28 | setResult(true) 29 | screenManager.pop() 30 | } 31 | }.build()) 32 | addAction(Action.Builder().apply { 33 | setTitle(carContext.getString(R.string.dialog_reset_cancel)) 34 | setOnClickListener { 35 | setResult(false) 36 | screenManager.pop() 37 | } 38 | }.build()) 39 | }.build() 40 | } -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/club_gradient.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | 18 | 21 | 24 | 27 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/carPropertiesClient/CarProperty.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.carPropertiesClient 2 | 3 | class CarProperty(val propertyId: Int) { 4 | 5 | private val startupTimestamp = System.nanoTime() 6 | private var lastTimestamp: Long = startupTimestamp 7 | 8 | /** Value of the Vehicle */ 9 | var value: Any? = null 10 | internal set(value) { 11 | lastValue = field 12 | field = value 13 | } 14 | 15 | var lastValue: Any? = null 16 | internal set 17 | 18 | /** Timestamp of the last time the value was changed in nanoseconds */ 19 | var timestamp: Long = startupTimestamp 20 | internal set(value) { 21 | lastTimestamp = field 22 | field = value 23 | } 24 | 25 | /** Time difference between value changes in nanoseconds */ 26 | val timeDelta: Long get() { 27 | if (lastTimestamp == 0L || lastTimestamp < startupTimestamp) return 0L 28 | return timestamp - lastTimestamp 29 | } 30 | 31 | /** Returns true if the value difference is null, therefore the value is the initial value */ 32 | val isInitialValue: Boolean get() = (valueDelta == null) 33 | 34 | /** Value difference since last value change */ 35 | val valueDelta: Any? 36 | get() { 37 | value.let { 38 | if (it == null || lastValue == null) return null 39 | if (it is Float) return (it - lastValue as Float) 40 | if (it is Int) return (it - lastValue as Int) 41 | if (it is Boolean) return !(lastValue as Boolean) 42 | } 43 | return null 44 | } 45 | } -------------------------------------------------------------------------------- /automotive/src/carapp/res/drawable/ic_car_app_settings.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/compose/ComposeSettingsActivity.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.compose 2 | 3 | import android.os.Bundle 4 | import androidx.activity.ComponentActivity 5 | import androidx.activity.compose.setContent 6 | import androidx.compose.runtime.collectAsState 7 | import androidx.lifecycle.viewmodel.compose.viewModel 8 | import com.ixam97.carStatsViewer.R 9 | import com.ixam97.carStatsViewer.compose.screens.SettingsScreen 10 | import com.ixam97.carStatsViewer.compose.theme.CarTheme 11 | 12 | class ComposeSettingsActivity: ComponentActivity() { 13 | 14 | private var reinitSates: () -> Unit = {} 15 | 16 | override fun onCreate(savedInstanceState: Bundle?) { 17 | super.onCreate(savedInstanceState) 18 | setTheme(R.style.AppTheme) 19 | 20 | val targetScreen: String? = if (intent.hasExtra("TargetRoute")) { 21 | intent.getStringExtra("TargetRoute") 22 | } else { 23 | null 24 | } 25 | 26 | setContent { 27 | val settingsViewModel: SettingsViewModel = viewModel() 28 | val themeSetting = settingsViewModel.themeSettingStateFLow.collectAsState() 29 | 30 | reinitSates = { settingsViewModel.initStates() } 31 | 32 | settingsViewModel.finishActivityLiveData.observe(this) { 33 | if (it.consume() == true) finish() 34 | } 35 | 36 | val brand = brandSelector(themeSetting.value) 37 | 38 | CarTheme(brand) { 39 | SettingsScreen(viewModel = settingsViewModel, targetRoute = targetScreen) 40 | } 41 | } 42 | } 43 | 44 | override fun onResume() { 45 | reinitSates.invoke() 46 | super.onResume() 47 | } 48 | } -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_debug.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/club_thumb_off.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | 18 | 21 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/club_thumb_on.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | 18 | 21 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/appPreferences/AppPreference.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.appPreferences 2 | 3 | import android.content.SharedPreferences 4 | import com.ixam97.carStatsViewer.ui.plot.enums.PlotDimensionX 5 | import com.ixam97.carStatsViewer.utils.DistanceUnitEnum 6 | 7 | class AppPreference( 8 | private val key: String, 9 | private val default: T, 10 | private val sharedPref: SharedPreferences) { 11 | 12 | var value: T 13 | get() { 14 | return when (default) { 15 | is Boolean -> sharedPref.getBoolean(key, default) as T 16 | is Int -> sharedPref.getInt(key, default) as T 17 | is Long -> sharedPref.getLong(key, default) as T 18 | is String -> sharedPref.getString(key, default) as T 19 | is PlotDimensionX -> PlotDimensionX.valueOf(sharedPref.getString(key, default.name)!!) as T 20 | is DistanceUnitEnum -> DistanceUnitEnum.valueOf(sharedPref.getString(key, default.name)!!) as T 21 | else -> default 22 | } 23 | } 24 | set(value) { 25 | when (default) { 26 | is Boolean -> sharedPref.edit().putBoolean(key, value as Boolean).apply() 27 | is Int -> sharedPref.edit().putInt(key, value as Int).apply() 28 | is Long -> sharedPref.edit().putLong(key, value as Long).apply() 29 | is String -> sharedPref.edit().putString(key, value as String).apply() 30 | is PlotDimensionX -> sharedPref.edit().putString(key, (value as PlotDimensionX).name).apply() 31 | is DistanceUnitEnum ->sharedPref.edit().putString(key, (value as DistanceUnitEnum).name).apply() 32 | //else -> 33 | } 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_help.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /automotive/src/carapp/java/com/ixam97/carStatsViewer/carApp/utils/Utils.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.carApp.utils 2 | 3 | import android.graphics.Bitmap 4 | import androidx.annotation.DrawableRes 5 | import androidx.car.app.CarContext 6 | import androidx.car.app.constraints.ConstraintManager 7 | import androidx.car.app.model.CarIcon 8 | import androidx.core.graphics.drawable.IconCompat 9 | import com.ixam97.carStatsViewer.R 10 | 11 | fun Bitmap.asCarIcon(): CarIcon = CarIcon.Builder(IconCompat.createWithBitmap(this)).build() 12 | 13 | fun CarContext.carIconFromRes(@DrawableRes resID: Int) = CarIcon.Builder(IconCompat.createWithResource(this, resID)).build() 14 | 15 | val CarContext.constraintManager 16 | get() = getCarService(CarContext.CONSTRAINT_SERVICE) as ConstraintManager 17 | 18 | fun CarContext.getContentLimit(id: Int) = if (carAppApiLevel >= 2) { 19 | constraintManager.getContentLimit(id) 20 | } else { 21 | when (id) { 22 | ConstraintManager.CONTENT_LIMIT_TYPE_GRID -> 6 23 | ConstraintManager.CONTENT_LIMIT_TYPE_LIST -> 6 24 | ConstraintManager.CONTENT_LIMIT_TYPE_PANE -> 4 25 | ConstraintManager.CONTENT_LIMIT_TYPE_PLACE_LIST -> 6 26 | ConstraintManager.CONTENT_LIMIT_TYPE_ROUTE_LIST -> 3 27 | else -> throw IllegalArgumentException("unknown limit ID") 28 | } 29 | } 30 | 31 | fun manualTripIcon(carContext: CarContext) = CarIcon.Builder(IconCompat.createWithResource(carContext, R.drawable.ic_hand)).build() 32 | fun sinceChargeTripIcon(carContext: CarContext) = CarIcon.Builder(IconCompat.createWithResource(carContext, R.drawable.ic_charger)).build() 33 | fun autoTripIcon(carContext: CarContext) = CarIcon.Builder(IconCompat.createWithResource(carContext, R.drawable.ic_day)).build() 34 | fun monthTripIcon(carContext: CarContext) = CarIcon.Builder(IconCompat.createWithResource(carContext, R.drawable.ic_month)).build() -------------------------------------------------------------------------------- /automotive/src/carapp/java/com/ixam97/carStatsViewer/carApp/ConfirmDeleteTripScreen.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.carApp 2 | 3 | import androidx.car.app.CarContext 4 | import androidx.car.app.Screen 5 | import androidx.car.app.model.Action 6 | import androidx.car.app.model.Header 7 | import androidx.car.app.model.MessageTemplate 8 | import androidx.car.app.model.Pane 9 | import androidx.car.app.model.PaneTemplate 10 | import androidx.car.app.model.Template 11 | import androidx.lifecycle.DefaultLifecycleObserver 12 | import com.ixam97.carStatsViewer.R 13 | import com.ixam97.carStatsViewer.carApp.utils.carIconFromRes 14 | 15 | class ConfirmDeleteTripScreen(carContext: CarContext): 16 | Screen(carContext), DefaultLifecycleObserver 17 | { 18 | init { 19 | lifecycle.addObserver(this) 20 | } 21 | 22 | override fun onGetTemplate(): Template { 23 | return confirmDeleteTripTemplate() 24 | } 25 | 26 | private fun confirmDeleteTripTemplate() = MessageTemplate.Builder( 27 | carContext.getString(R.string.history_dialog_delete_message) 28 | ).apply { 29 | setHeader(Header.Builder().apply { 30 | setTitle(carContext.getString(R.string.history_dialog_delete_title)) 31 | }.build()) 32 | setIcon(carContext.carIconFromRes(R.drawable.ic_delete)) 33 | addAction(Action.Builder().apply { 34 | setTitle(carContext.getString(R.string.history_dialog_delete_confirm)) 35 | setFlags(Action.FLAG_PRIMARY) 36 | setOnClickListener { 37 | setResult(true) 38 | screenManager.pop() 39 | } 40 | }.build()) 41 | addAction(Action.Builder().apply { 42 | setTitle(carContext.getString(R.string.dialog_reset_cancel)) 43 | setOnClickListener { 44 | setResult(false) 45 | screenManager.pop() 46 | } 47 | }.build()) 48 | }.build() 49 | } -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/compose/screens/settings/GeneralSettings.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.compose.screens.settings 2 | 3 | import androidx.compose.foundation.layout.fillMaxSize 4 | import androidx.compose.foundation.layout.padding 5 | import androidx.compose.material.Divider 6 | import androidx.compose.material.Text 7 | import androidx.compose.runtime.Composable 8 | import androidx.compose.ui.Modifier 9 | import androidx.compose.ui.res.stringResource 10 | import androidx.compose.ui.unit.dp 11 | import com.ixam97.carStatsViewer.R 12 | import com.ixam97.carStatsViewer.compose.DefaultColumnScrollbar 13 | import com.ixam97.carStatsViewer.compose.SettingsViewModel 14 | import com.ixam97.carStatsViewer.compose.components.CarSwitchRow 15 | 16 | @Composable 17 | fun GeneralSettings( 18 | viewModel: SettingsViewModel 19 | ) { 20 | DefaultColumnScrollbar( 21 | modifier = Modifier 22 | .fillMaxSize() 23 | ) { 24 | CarSwitchRow( 25 | switchState = viewModel.settingsState.autoAppStart, 26 | onClick = { viewModel.setAutoAppStart(it) } 27 | ) { 28 | Text(text = stringResource(id = R.string.settings_autostart)) 29 | } 30 | Divider(Modifier.padding(horizontal = 20.dp)) 31 | CarSwitchRow( 32 | switchState = viewModel.settingsState.phoneNotification, 33 | onClick = { viewModel.setPhoneNotification(it) } 34 | ) { 35 | Text(text = stringResource(id = R.string.settings_phone_reminder)) 36 | } 37 | Divider(Modifier.padding(horizontal = 20.dp)) 38 | CarSwitchRow( 39 | switchState = viewModel.settingsState.detailedNotifications, 40 | onClick = { viewModel.setDetailedNotifications(it) } 41 | ) { 42 | Text(text = stringResource(id = R.string.settings_notifications)) 43 | } 44 | Divider(Modifier.padding(horizontal = 20.dp)) 45 | } 46 | } -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/map/MapboxInterface.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.map 2 | 3 | import android.location.Geocoder 4 | import androidx.compose.foundation.layout.Box 5 | import androidx.compose.material.Text 6 | import androidx.compose.runtime.Composable 7 | import androidx.compose.ui.Alignment 8 | import androidx.compose.ui.Modifier 9 | import com.ixam97.carStatsViewer.CarStatsViewer 10 | import com.ixam97.carStatsViewer.database.tripData.DrivingSession 11 | import com.ixam97.carStatsViewer.utils.InAppLogger 12 | import java.util.Locale 13 | 14 | interface MapboxInterface { 15 | fun isDummy(): Boolean 16 | 17 | @Composable 18 | fun MapBoxContainer( 19 | modifier: Modifier, 20 | trip: DrivingSession?, 21 | chargingMarkerOnClick: ((id: Long) -> Unit) 22 | ) { 23 | Box ( 24 | modifier = modifier, 25 | contentAlignment = Alignment.Center 26 | ) { 27 | Text("No Mapbox API configured!") 28 | } 29 | 30 | } 31 | 32 | // Using the built in Android Geocoder 33 | suspend fun getAddress(lon: Double, lat: Double): String { 34 | if (!Geocoder.isPresent()) return ("%.6f, %.6f".format(lat, lon)) 35 | 36 | val geocoder = Geocoder(CarStatsViewer.appContext, Locale.getDefault()) 37 | val result = 38 | try { 39 | // Deprecated with API level 33, but not available in lower API levels. 40 | // Therefore suspend fun. TODO: Implement new function for API 33+ 41 | geocoder.getFromLocation(lat, lon, 1) 42 | } catch (e: Throwable) { 43 | InAppLogger.e("[Geo] Unable to get address from geocoder:") 44 | InAppLogger.e(e.stackTraceToString()) 45 | null 46 | } 47 | 48 | return if (!result.isNullOrEmpty()) { 49 | result[0].getAddressLine(0) 50 | } else { 51 | ("%.6f, %.6f".format(lat, lon)) 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/compose/components/CarSwitchRow.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.compose.components 2 | 3 | import androidx.compose.foundation.clickable 4 | import androidx.compose.foundation.layout.Box 5 | import androidx.compose.foundation.layout.Row 6 | import androidx.compose.foundation.layout.Spacer 7 | import androidx.compose.foundation.layout.heightIn 8 | import androidx.compose.foundation.layout.padding 9 | import androidx.compose.foundation.layout.size 10 | import androidx.compose.foundation.layout.widthIn 11 | import androidx.compose.material.Switch 12 | import androidx.compose.runtime.Composable 13 | import androidx.compose.ui.Alignment 14 | import androidx.compose.ui.Modifier 15 | import androidx.compose.ui.graphics.TransformOrigin 16 | import androidx.compose.ui.graphics.graphicsLayer 17 | import androidx.compose.ui.unit.dp 18 | 19 | @Composable 20 | fun CarSwitchRow( 21 | enabled: Boolean = true, 22 | switchState: Boolean, 23 | onClick: (newState: Boolean) -> Unit, 24 | content: @Composable (enabled: Boolean) -> Unit 25 | ) { 26 | Row( 27 | modifier = Modifier 28 | .heightIn(min = 100.dp) 29 | .clickable(enabled = enabled) { onClick(!switchState) } 30 | .padding(horizontal = 30.dp), 31 | verticalAlignment = Alignment.CenterVertically 32 | ) { 33 | content(enabled) 34 | Spacer(modifier = Modifier.weight(1f).widthIn(min = 20.dp)) 35 | Box( 36 | modifier = Modifier.size(80.dp), 37 | contentAlignment = Alignment.Center 38 | ) { 39 | Switch( 40 | modifier = Modifier 41 | // .scale(2f) 42 | .graphicsLayer( 43 | transformOrigin = TransformOrigin(1f,.5f), 44 | scaleX = 2f, 45 | scaleY = 2f), 46 | checked = switchState, 47 | onCheckedChange = null, 48 | enabled = enabled 49 | ) 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_performance.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /automotive/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_webhook.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/compose/ComposeTripDetailsActivity.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.compose 2 | 3 | import android.os.Bundle 4 | import androidx.activity.ComponentActivity 5 | import androidx.activity.compose.setContent 6 | import androidx.lifecycle.viewmodel.compose.viewModel 7 | import com.ixam97.carStatsViewer.CarStatsViewer 8 | import com.ixam97.carStatsViewer.R 9 | import com.ixam97.carStatsViewer.compose.screens.TripDetailsPortraitScreen 10 | import com.ixam97.carStatsViewer.compose.theme.CarTheme 11 | 12 | class ComposeTripDetailsActivity: ComponentActivity() { 13 | override fun onCreate(savedInstanceState: Bundle?) { 14 | super.onCreate(savedInstanceState) 15 | setTheme(R.style.AppTheme) 16 | 17 | if (!intent.hasExtra("SessionId")) { 18 | finish() 19 | } else { 20 | val sessionId = intent.getLongExtra("SessionId", 0) 21 | setContent { 22 | val viewModel: TripDetailsViewModel = viewModel() 23 | 24 | // val tripDetailsState = viewModel.tripDetailsState 25 | 26 | val brand = brandSelector(CarStatsViewer.appPreferences.colorTheme) 27 | 28 | CarTheme(brand) { 29 | TripDetailsPortraitScreen( 30 | viewModel = viewModel, 31 | sessionId = sessionId 32 | ) 33 | /* 34 | if (tripDetailsState.drivingSession != null) { 35 | TripDetailsPortraitScreen( 36 | viewModel = viewModel 37 | ) 38 | } else { 39 | viewModel.loadDrivingSession(sessionId) 40 | Box( 41 | modifier = Modifier 42 | .fillMaxSize(), 43 | contentAlignment = Alignment.Center 44 | ) { 45 | CircularProgressIndicator() 46 | } 47 | } 48 | 49 | */ 50 | } 51 | } 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /automotive/src/main/res/layout/activity_permissions.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 22 | 23 | 35 | 36 | 45 | -------------------------------------------------------------------------------- /automotive/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 30 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/compose/screens/settings/PrivacySettings.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.compose.screens.settings 2 | 3 | import androidx.compose.foundation.layout.fillMaxSize 4 | import androidx.compose.foundation.layout.padding 5 | import androidx.compose.material.Divider 6 | import androidx.compose.material.Text 7 | import androidx.compose.runtime.Composable 8 | import androidx.compose.ui.Modifier 9 | import androidx.compose.ui.platform.LocalContext 10 | import androidx.compose.ui.res.stringResource 11 | import androidx.compose.ui.unit.dp 12 | import com.ixam97.carStatsViewer.R 13 | import com.ixam97.carStatsViewer.compose.DefaultColumnScrollbar 14 | import com.ixam97.carStatsViewer.compose.SettingsViewModel 15 | import com.ixam97.carStatsViewer.compose.components.CarRow 16 | import com.ixam97.carStatsViewer.compose.components.CarSwitchRow 17 | 18 | @Composable 19 | fun PrivacySettings( 20 | viewModel: SettingsViewModel 21 | ) { 22 | val context = LocalContext.current 23 | DefaultColumnScrollbar( 24 | modifier = Modifier 25 | .fillMaxSize() 26 | ) { 27 | CarSwitchRow( 28 | switchState = viewModel.settingsState.locationTracking, 29 | onClick = { viewModel.setLocationTracking(it) } 30 | ) { 31 | Text(text = stringResource(id = R.string.settings_use_location)) 32 | } 33 | Divider(Modifier.padding(horizontal = 20.dp)) 34 | if (stringResource(R.string.useFirebase) == "true") { 35 | CarSwitchRow( 36 | switchState = viewModel.settingsState.analytics, 37 | onClick = { viewModel.setAnalytics(it) } 38 | ) { 39 | Text(text = stringResource(R.string.settings_analytics)) 40 | } 41 | } else { 42 | CarRow(title = stringResource(R.string.settings_firebase_note)) 43 | } 44 | Divider(modifier = Modifier.padding(horizontal = 24.dp)) 45 | CarRow( 46 | title = stringResource(R.string.settings_privacy), 47 | browsable = true, 48 | external = true, 49 | onClick = { viewModel.openPrivacyLink(context) } 50 | ) 51 | } 52 | } -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/liveDataApi/http/AppPreferencesExt.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.liveDataApi.http 2 | 3 | /** 4 | * This file extends the AppPreferences to contain keys used by the API implementation. The rest of 5 | * the app does not need to see them. 6 | */ 7 | 8 | import com.ixam97.carStatsViewer.appPreferences.AppPreference 9 | import com.ixam97.carStatsViewer.appPreferences.AppPreferences 10 | 11 | val AppPreferences.HTTPLiveDataURL: AppPreference 12 | get() = AppPreference("preference_http_live_data_url", "", sharedPref) 13 | 14 | val AppPreferences.HTTPLiveDataUsername: AppPreference 15 | get() = AppPreference("preference_http_live_data_username", "", sharedPref) 16 | 17 | val AppPreferences.HTTPLiveDataPassword: AppPreference 18 | get() = AppPreference("preference_http_live_data_password", "", sharedPref) 19 | 20 | val AppPreferences.HTTPLiveDataEnabled: AppPreference 21 | get() = AppPreference("preference_http_live_data_enables", false, sharedPref) 22 | 23 | val AppPreferences.HTTPLiveDataLocation: AppPreference 24 | get() = AppPreference("preference_http_live_data_location", true, sharedPref) 25 | 26 | val AppPreferences.HTTPLiveDataSendABRPDataset: AppPreference 27 | get() = AppPreference("preference_http_live_data_abrp", false, sharedPref) 28 | 29 | var AppPreferences.httpLiveDataURL: String get() = HTTPLiveDataURL.value; set(value) {HTTPLiveDataURL.value = value} 30 | var AppPreferences.httpLiveDataUsername: String get() = HTTPLiveDataUsername.value; set(value) {HTTPLiveDataUsername.value = value} 31 | var AppPreferences.httpLiveDataPassword: String get() = HTTPLiveDataPassword.value; set(value) {HTTPLiveDataPassword.value = value} 32 | var AppPreferences.httpLiveDataEnabled: Boolean get() = HTTPLiveDataEnabled.value; set(value) {HTTPLiveDataEnabled.value = value} 33 | var AppPreferences.httpLiveDataLocation: Boolean get() = HTTPLiveDataLocation.value; set(value) {HTTPLiveDataLocation.value = value} 34 | var AppPreferences.httpLiveDataSendABRPDataset: Boolean get() = HTTPLiveDataSendABRPDataset.value; set(value) {HTTPLiveDataSendABRPDataset.value = value} -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/utils/ChangeLogCreator.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.utils 2 | 3 | import android.content.Context 4 | import com.ixam97.carStatsViewer.R 5 | 6 | object ChangeLogCreator { 7 | 8 | private val versionRegex = Regex("\\[V]\\((.*)\\)") 9 | 10 | fun createChangelog(context: Context): Map { 11 | 12 | val changesList = context.resources.getStringArray(R.array.changes).toMutableList() 13 | val pendingChangesList = context.resources.getStringArray(R.array.pending_changes).toMutableList() 14 | 15 | pendingChangesList.toList().forEachIndexed { index, change -> 16 | if (change.contains(versionRegex)) { 17 | val match = versionRegex.find(change)!!.destructured.toList()[0] 18 | pendingChangesList[index] = "[V]($match (Pre-Release))" 19 | } 20 | } 21 | 22 | val versionsMap = mutableMapOf() 23 | 24 | var currentTitle = "" 25 | var currentChanges = "" 26 | 27 | changesList.addAll(pendingChangesList) 28 | 29 | changesList.reversed().forEachIndexed { index, change -> 30 | if (change.contains(versionRegex)) { 31 | if (index > 0) { 32 | versionsMap[currentTitle] = currentChanges 33 | } 34 | versionRegex.find(change)?.let { 35 | val destructedChange = it.destructured.toList() 36 | currentTitle = if (destructedChange.isNotEmpty()) it.destructured.toList()[0] else "UNKNOWN" 37 | } 38 | currentChanges = "" 39 | } else { 40 | if (currentChanges.isNotEmpty()) currentChanges += "\n" 41 | currentChanges += "● $change" 42 | if (index >= changesList.size -1) { 43 | versionsMap[currentTitle] = currentChanges 44 | } 45 | } 46 | } 47 | 48 | return versionsMap 49 | } 50 | 51 | private fun String.toPreReleaseVersion(): String { 52 | val original = this 53 | 54 | var preReleaseVersion: String = "" 55 | 56 | return preReleaseVersion 57 | } 58 | } -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/dataProcessor/RealTimeData.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.dataProcessor 2 | 3 | import android.car.VehicleGear 4 | import android.car.VehicleIgnitionState 5 | import android.os.Build 6 | 7 | data class RealTimeData( 8 | val speed: Float? = null, 9 | val power: Float? = null, 10 | val selectedGear: Int? = null, 11 | val ignitionState: Int? = null, 12 | val chargePortConnected: Boolean? = null, 13 | val batteryLevel: Float? = null, 14 | val stateOfCharge: Float? = null, 15 | val ambientTemperature: Float? = null, 16 | val lat: Float? = null, 17 | val lon: Float? = null, 18 | val alt: Float? = null 19 | ) { 20 | val drivingState: Int get() = getDriveState() 21 | val instConsumption: Float? get() = getInstCons() 22 | val optimizeDistraction: Boolean get() = speed != null && speed > 0.0 23 | 24 | fun isInitialized(): Boolean { 25 | return isEssentialInitialized() && isOptionalInitialized() 26 | } 27 | 28 | fun isOptionalInitialized(): Boolean { 29 | return ambientTemperature != null 30 | } 31 | 32 | fun isEssentialInitialized(): Boolean { 33 | return speed != null 34 | && (power != null || Build.DEVICE == "moose" || Build.DEVICE == "ihu_emulator") 35 | && selectedGear != null 36 | && ignitionState != null 37 | && chargePortConnected != null 38 | && batteryLevel != null 39 | && stateOfCharge != null 40 | } 41 | 42 | private fun getDriveState(): Int { 43 | return if (chargePortConnected == true) DrivingState.CHARGE 44 | else if (ignitionState == VehicleIgnitionState.START || (ignitionState == VehicleIgnitionState.ON && selectedGear == VehicleGear.GEAR_DRIVE)) DrivingState.DRIVE 45 | else if (ignitionState != VehicleIgnitionState.UNDEFINED && ignitionState != null) DrivingState.PARKED 46 | else DrivingState.UNKNOWN 47 | } 48 | 49 | private fun getInstCons(): Float? { 50 | if (power == null || speed == null) return null 51 | val instCons = (power / 1_000f) / (speed * 3.6f) 52 | return if (instCons.isFinite()) instCons else null 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/compose/screens/MapboxScreen.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.compose.screens 2 | 3 | import androidx.compose.foundation.layout.Column 4 | import androidx.compose.foundation.layout.fillMaxWidth 5 | import androidx.compose.foundation.layout.padding 6 | import androidx.compose.material.Text 7 | import androidx.compose.runtime.Composable 8 | import androidx.compose.runtime.LaunchedEffect 9 | import androidx.compose.runtime.getValue 10 | import androidx.compose.runtime.mutableStateOf 11 | import androidx.compose.runtime.remember 12 | import androidx.compose.runtime.setValue 13 | import androidx.compose.ui.Modifier 14 | import androidx.compose.ui.unit.dp 15 | import com.ixam97.carStatsViewer.CarStatsViewer 16 | import com.ixam97.carStatsViewer.map.Mapbox 17 | 18 | @Composable 19 | fun MapboxScreen() { 20 | 21 | val trip = CarStatsViewer.dataProcessor.selectedSessionData 22 | 23 | var startAddr by remember { mutableStateOf("Unknown") } 24 | var destAddr by remember { mutableStateOf("Unknown") } 25 | 26 | Column { 27 | Mapbox.MapBoxContainer( 28 | modifier = Modifier 29 | .fillMaxWidth() 30 | .weight(1f), 31 | trip = trip, 32 | chargingMarkerOnClick = {} 33 | ) 34 | Text( 35 | modifier = Modifier.padding(vertical = 10.dp, horizontal = 25.dp), 36 | text = "Start: $startAddr" 37 | ) 38 | Text( 39 | modifier = Modifier.padding(vertical = 10.dp, horizontal = 25.dp), 40 | text = "Destination: $destAddr" 41 | ) 42 | } 43 | 44 | LaunchedEffect(Unit) { 45 | if (trip != null) { 46 | if (!trip.drivingPoints.isNullOrEmpty()) { 47 | val coordinates = trip.drivingPoints!!.filter { it.lat != null } 48 | startAddr = Mapbox.getAddress( 49 | coordinates.first().lon!!.toDouble(), 50 | coordinates.first().lat!!.toDouble() 51 | ) 52 | destAddr = Mapbox.getAddress( 53 | coordinates.last().lon!!.toDouble(), 54 | coordinates.last().lat!!.toDouble() 55 | ) 56 | } 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /automotive/src/main/java/com/ixam97/carStatsViewer/ui/views/FixedSwitchWidget.kt: -------------------------------------------------------------------------------- 1 | package com.ixam97.carStatsViewer.ui.views 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import android.view.View 6 | import android.widget.LinearLayout 7 | import android.widget.Switch 8 | import android.widget.TextView 9 | import com.ixam97.carStatsViewer.R 10 | 11 | class FixedSwitchWidget @JvmOverloads constructor( 12 | context: Context, 13 | attrs: AttributeSet? = null, 14 | defStyleAttr: Int = 0 15 | ): LinearLayout(context, attrs, defStyleAttr) { 16 | 17 | private var clickListener: ClickListener? = null 18 | 19 | private var label: String = "" 20 | 21 | private lateinit var container: View 22 | private lateinit var switch: Switch 23 | private lateinit var labelView: TextView 24 | 25 | init { 26 | val attributes = context.obtainStyledAttributes(attrs, R.styleable.FixedSwitchWidget) 27 | try { 28 | label = attributes.getString(R.styleable.FixedSwitchWidget_text)?:"" 29 | } finally { 30 | attributes.recycle() 31 | } 32 | init() 33 | } 34 | 35 | private fun init() { 36 | this.removeAllViews() 37 | View.inflate(context, R.layout.widget_fixed_switch, this) 38 | 39 | labelView = findViewById(R.id.switch_label) 40 | container = findViewById(R.id.container) 41 | switch = findViewById(R.id.switch_switch) 42 | 43 | labelView.text = label 44 | 45 | container.setOnClickListener { 46 | switch.isChecked = !switch.isChecked 47 | clickListener?.onClick() 48 | } 49 | 50 | switch.setOnClickListener { 51 | clickListener?.onClick() 52 | } 53 | } 54 | 55 | var isChecked 56 | get() = switch.isChecked 57 | set(value) {switch.isChecked = value} 58 | 59 | var text: String 60 | get() = labelView.text.toString() 61 | set(value) { 62 | labelView.text = value 63 | label = value 64 | } 65 | 66 | fun interface ClickListener { 67 | fun onClick() 68 | } 69 | 70 | fun setSwitchClickListener(listener: ClickListener?) { 71 | clickListener = listener 72 | } 73 | 74 | } -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_trip_start.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 12 | 13 | 14 | 15 | 16 | 21 | 24 | 25 | 26 | 27 | 32 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /automotive/src/main/res/layout/widget_multi_select.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 14 | 21 | 28 | 35 | 43 | 44 | 45 | 51 | -------------------------------------------------------------------------------- /automotive/src/main/res/values-w877dp/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 21 | 31 | 41 | -------------------------------------------------------------------------------- /automotive/src/main/res/drawable/ic_trip_charging_location.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 12 | 13 | 14 | 15 | 16 | 21 | 24 | 25 | 26 | 27 | 33 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | --------------------------------------------------------------------------------