aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/core/constants/colors.dart21
-rw-r--r--lib/core/constants/constants.dart11
-rw-r--r--lib/core/constants/paths.dart914
-rw-r--r--lib/core/constants/val_client_helper.dart58
-rw-r--r--lib/core/constants/vss_path.dart58
-rw-r--r--lib/core/utils/helpers.dart17
-rw-r--r--lib/core/utils/widgets/back_button.dart16
-rw-r--r--lib/data/data_providers/app.dart25
-rw-r--r--lib/data/data_providers/app_provider.dart63
-rw-r--r--lib/data/data_providers/audio_notifier.dart25
-rw-r--r--lib/data/data_providers/datetime_notifier.dart14
-rw-r--r--lib/data/data_providers/hybrid_notifier.dart91
-rw-r--r--lib/data/data_providers/signal_notifier.dart14
-rw-r--r--lib/data/data_providers/units_notifier.dart13
-rw-r--r--lib/data/data_providers/users_notifier.dart49
-rw-r--r--lib/data/data_providers/vehicle_notifier.dart367
-rw-r--r--lib/data/data_providers/vss_provider.dart105
-rw-r--r--lib/data/models/audio.dart84
-rw-r--r--lib/data/models/connections_signals.dart92
-rw-r--r--lib/data/models/date_time.dart59
-rw-r--r--lib/data/models/hybrid.dart98
-rw-r--r--lib/data/models/units.dart45
-rw-r--r--lib/data/models/user.dart54
-rw-r--r--lib/data/models/users.dart64
-rw-r--r--lib/data/models/vehicle.dart233
-rw-r--r--lib/data/theme/theme.dart43
-rw-r--r--lib/export.dart101
-rw-r--r--lib/main.dart15
-rw-r--r--lib/presentation/common_widget/custom_bottom_bar.dart211
-rw-r--r--lib/presentation/common_widget/custom_title.dart103
-rw-r--r--lib/presentation/common_widget/custom_top_bar.dart106
-rw-r--r--lib/presentation/common_widget/fan_bar.dart188
-rw-r--r--lib/presentation/common_widget/generic_button.dart91
-rw-r--r--lib/presentation/common_widget/settings_top_bar.dart37
-rw-r--r--lib/presentation/common_widget/volume_and_fan_control.dart36
-rw-r--r--lib/presentation/common_widget/volume_bar.dart356
-rw-r--r--lib/presentation/custom_icons/custom_icons.dart76
-rw-r--r--lib/presentation/router/routes/routes.dart56
-rw-r--r--lib/presentation/routes/widget/page_widget.dart21
-rw-r--r--lib/presentation/screens/apps/apps.dart30
-rw-r--r--lib/presentation/screens/apps/apps_content.dart60
-rw-r--r--lib/presentation/screens/apps/widgets/app_button.dart61
-rw-r--r--lib/presentation/screens/clock/clock.dart145
-rw-r--r--lib/presentation/screens/dashboard/dashboard.dart33
-rw-r--r--lib/presentation/screens/dashboard/widgets/car_status.dart251
-rw-r--r--lib/presentation/screens/dashboard/widgets/child_lock.dart96
-rw-r--r--lib/presentation/screens/dashboard/widgets/circle_indicator.dart305
-rw-r--r--lib/presentation/screens/dashboard/widgets/custom_circle.dart107
-rw-r--r--lib/presentation/screens/dashboard/widgets/dashboard_content.dart108
-rw-r--r--lib/presentation/screens/dashboard/widgets/hybrid/hybrid.dart142
-rw-r--r--lib/presentation/screens/dashboard/widgets/hybrid_mode.dart30
-rw-r--r--lib/presentation/screens/dashboard/widgets/range.dart85
-rw-r--r--lib/presentation/screens/dashboard/widgets/temperature.dart143
-rw-r--r--lib/presentation/screens/home/home.dart71
-rw-r--r--lib/presentation/screens/home/widgets/custom_tile.dart50
-rw-r--r--lib/presentation/screens/hvac/hvac.dart45
-rw-r--r--lib/presentation/screens/hvac/hvac_content.dart249
-rw-r--r--lib/presentation/screens/hvac/widgets/climate_controls.dart80
-rw-r--r--lib/presentation/screens/hvac/widgets/fan_focus.dart116
-rw-r--r--lib/presentation/screens/hvac/widgets/fan_speed_controls.dart251
-rw-r--r--lib/presentation/screens/hvac/widgets/semi_circle_painter.dart109
-rw-r--r--lib/presentation/screens/hvac/widgets/temperature_control.dart255
-rw-r--r--lib/presentation/screens/media_player/fm_player.dart76
-rw-r--r--lib/presentation/screens/media_player/media_content.dart82
-rw-r--r--lib/presentation/screens/media_player/media_controls.dart413
-rw-r--r--lib/presentation/screens/media_player/media_player.dart99
-rw-r--r--lib/presentation/screens/media_player/my_media.dart0
-rw-r--r--lib/presentation/screens/media_player/play_list_table.dart154
-rw-r--r--lib/presentation/screens/media_player/player_navigation.dart80
-rw-r--r--lib/presentation/screens/media_player/segmented_buttons.dart82
-rw-r--r--lib/presentation/screens/media_player/widgets/gradient_progress_indicator.dart88
-rw-r--r--lib/presentation/screens/media_player/widgets/media_volume_bar.dart117
-rw-r--r--lib/presentation/screens/settings/settings.dart26
-rw-r--r--lib/presentation/screens/settings/settings_screens/audio_settings/audio_settings_screen.dart30
-rw-r--r--lib/presentation/screens/settings/settings_screens/audio_settings/widget/audio_content.dart41
-rw-r--r--lib/presentation/screens/settings/settings_screens/audio_settings/widget/slider_widgets.dart603
-rw-r--r--lib/presentation/screens/settings/settings_screens/bluetooth/bluetooth_screen.dart12
-rw-r--r--lib/presentation/screens/settings/settings_screens/bluetooth/widgets/bluetooth.dart12
-rw-r--r--lib/presentation/screens/settings/settings_screens/bluetooth/widgets/bluetooth_content.dart219
-rw-r--r--lib/presentation/screens/settings/settings_screens/date_time/date/date_screen.dart218
-rw-r--r--lib/presentation/screens/settings/settings_screens/date_time/date_time_screen.dart54
-rw-r--r--lib/presentation/screens/settings/settings_screens/date_time/time/time_screen.dart426
-rw-r--r--lib/presentation/screens/settings/settings_screens/profiles/profiles_screen.dart20
-rw-r--r--lib/presentation/screens/settings/settings_screens/profiles/widgets/new_profile_screen.dart252
-rw-r--r--lib/presentation/screens/settings/settings_screens/profiles/widgets/profiles_content.dart125
-rw-r--r--lib/presentation/screens/settings/settings_screens/units/distance/distance_unit_screen.dart120
-rw-r--r--lib/presentation/screens/settings/settings_screens/units/temperature/temperature_unit_screen.dart120
-rw-r--r--lib/presentation/screens/settings/settings_screens/units/units_screen.dart159
-rw-r--r--lib/presentation/screens/settings/settings_screens/version_info/version_info_screend.dart83
-rw-r--r--lib/presentation/screens/settings/settings_screens/wifi/widgets/wifi.dart12
-rw-r--r--lib/presentation/screens/settings/settings_screens/wifi/widgets/wifi_content.dart150
-rw-r--r--lib/presentation/screens/settings/settings_screens/wifi/wifi_screen.dart17
-rw-r--r--lib/presentation/screens/settings/settings_screens/wired/wired_screen.dart76
-rw-r--r--lib/presentation/screens/settings/widgets/settings_content.dart95
-rw-r--r--lib/presentation/screens/settings/widgets/settings_list_tile.dart234
-rw-r--r--lib/presentation/screens/splash/splash.dart26
-rw-r--r--lib/presentation/screens/splash/widget/splash_content.dart142
-rw-r--r--lib/presentation/screens/weather/hourly_forecast.dart152
-rw-r--r--lib/presentation/screens/weather/weather.dart91
99 files changed, 11558 insertions, 0 deletions
diff --git a/lib/core/constants/colors.dart b/lib/core/constants/colors.dart
new file mode 100644
index 0000000..9835029
--- /dev/null
+++ b/lib/core/constants/colors.dart
@@ -0,0 +1,21 @@
+import 'dart:ui';
+
+import '../../export.dart';
+
+class AGLDemoColors {
+ AGLDemoColors._();
+
+ static const lightGreyColor = Color(0XFFECEDF1);
+ static const periwinkleColor = Color(0XFFC1D8FF);
+ static const jordyBlueColor = Color(0XFF82B1FF);
+ static const neonBlueColor = Color(0XFF2962FF);
+ static const resolutionBlueColor = Color(0XFF1A237E);
+ static const lightRedColor = Color(0XFFEF9A9A);
+ static const yellowColor = Color(0XFFFFDE03);
+ static const greenColor = Color(0XFF69F0AE);
+ static const buttonFillEnabledColor = Color(0XFF1C2D92);
+ static const blueGlowFillColor = Color(0XFFB8D3FF);
+ static const backgroundInsetColor = Color(0XFF0C1039);
+ static const gradientBackgroundDarkColor = Color(0XFF0D113F);
+ static const redProgressStrokeColor = Color(0XFFFF3D00);
+}
diff --git a/lib/core/constants/constants.dart b/lib/core/constants/constants.dart
new file mode 100644
index 0000000..fe8d9f1
--- /dev/null
+++ b/lib/core/constants/constants.dart
@@ -0,0 +1,11 @@
+import '../../export.dart';
+
+const splashWarning =
+ 'Please use the IVI system responsibly while driving. Keep your attention on the road, and use voice commands or hands-free controls when interacting with the system. Distracted driving can lead to accidents and serious injury. Follow all traffic laws and drive safely.';
+const aglVeriosn = 'AGL 16.0.2 (pike)';
+const kernelVeriosn = 'Kernel: 5.10.41.-yocto-standard';
+const maxFuelLevel = 55.0;
+const maxSpeed = 240.0;
+const maxRpm = 8000;
+final GlobalKey<ScaffoldState> homeScaffoldKey = GlobalKey();
+
diff --git a/lib/core/constants/paths.dart b/lib/core/constants/paths.dart
new file mode 100644
index 0000000..c3afb99
--- /dev/null
+++ b/lib/core/constants/paths.dart
@@ -0,0 +1,914 @@
+
+
+List<String> signals = [
+ 'Vehicle.ADAS.ABS.IsEnabled',
+ 'Vehicle.ADAS.ABS.IsEngaged',
+ 'Vehicle.ADAS.ABS.IsError',
+ 'Vehicle.ADAS.ActiveAutonomyLevel',
+ 'Vehicle.ADAS.CruiseControl.IsActive',
+ 'Vehicle.ADAS.CruiseControl.IsEnabled',
+ 'Vehicle.ADAS.CruiseControl.IsError',
+ 'Vehicle.ADAS.CruiseControl.SpeedSet',
+ 'Vehicle.ADAS.DMS.IsEnabled',
+ 'Vehicle.ADAS.DMS.IsError',
+ 'Vehicle.ADAS.DMS.IsWarning',
+ 'Vehicle.ADAS.EBA.IsEnabled',
+ 'Vehicle.ADAS.EBA.IsEngaged',
+ 'Vehicle.ADAS.EBA.IsError',
+ 'Vehicle.ADAS.EBD.IsEnabled',
+ 'Vehicle.ADAS.EBD.IsEngaged',
+ 'Vehicle.ADAS.EBD.IsError',
+ 'Vehicle.ADAS.ESC.IsEnabled',
+ 'Vehicle.ADAS.ESC.IsEngaged',
+ 'Vehicle.ADAS.ESC.IsError',
+ 'Vehicle.ADAS.ESC.IsStrongCrossWindDetected',
+ 'Vehicle.ADAS.ESC.RoadFriction.LowerBound',
+ 'Vehicle.ADAS.ESC.RoadFriction.MostProbable',
+ 'Vehicle.ADAS.ESC.RoadFriction.UpperBound',
+ 'Vehicle.ADAS.LaneDepartureDetection.IsEnabled',
+ 'Vehicle.ADAS.LaneDepartureDetection.IsError',
+ 'Vehicle.ADAS.LaneDepartureDetection.IsWarning',
+ 'Vehicle.ADAS.ObstacleDetection.IsEnabled',
+ 'Vehicle.ADAS.ObstacleDetection.IsError',
+ 'Vehicle.ADAS.ObstacleDetection.IsWarning',
+ 'Vehicle.ADAS.PowerOptimizeLevel',
+ 'Vehicle.ADAS.SupportedAutonomyLevel',
+ 'Vehicle.ADAS.TCS.IsEnabled',
+ 'Vehicle.ADAS.TCS.IsEngaged',
+ 'Vehicle.ADAS.TCS.IsError',
+ 'Vehicle.Acceleration.Lateral',
+ 'Vehicle.Acceleration.Longitudinal',
+ 'Vehicle.Acceleration.Vertical',
+ 'Vehicle.AngularVelocity.Pitch',
+ 'Vehicle.AngularVelocity.Roll',
+ 'Vehicle.AngularVelocity.Yaw',
+ 'Vehicle.AverageSpeed',
+ 'Vehicle.Body.BodyType',
+ 'Vehicle.Body.Hood.IsOpen',
+ 'Vehicle.Body.Horn.IsActive',
+ 'Vehicle.Body.Lights.Backup.IsDefect',
+ 'Vehicle.Body.Lights.Backup.IsOn',
+ 'Vehicle.Body.Lights.Beam.High.IsDefect',
+ 'Vehicle.Body.Lights.Beam.High.IsOn',
+ 'Vehicle.Body.Lights.Beam.Low.IsDefect',
+ 'Vehicle.Body.Lights.Beam.Low.IsOn',
+ 'Vehicle.Body.Lights.Brake.IsActive',
+ 'Vehicle.Body.Lights.Brake.IsDefect',
+ 'Vehicle.Body.Lights.DirectionIndicator.Left.IsDefect',
+ 'Vehicle.Body.Lights.DirectionIndicator.Left.IsSignaling',
+ 'Vehicle.Body.Lights.DirectionIndicator.Right.IsDefect',
+ 'Vehicle.Body.Lights.DirectionIndicator.Right.IsSignaling',
+ 'Vehicle.Body.Lights.Fog.Front.IsDefect',
+ 'Vehicle.Body.Lights.Fog.Front.IsOn',
+ 'Vehicle.Body.Lights.Fog.Rear.IsDefect',
+ 'Vehicle.Body.Lights.Fog.Rear.IsOn',
+ 'Vehicle.Body.Lights.Hazard.IsDefect',
+ 'Vehicle.Body.Lights.Hazard.IsSignaling',
+ 'Vehicle.Body.Lights.IsHighBeamSwitchOn',
+ 'Vehicle.Body.Lights.LicensePlate.IsDefect',
+ 'Vehicle.Body.Lights.LicensePlate.IsOn',
+ 'Vehicle.Body.Lights.LightSwitch',
+ 'Vehicle.Body.Lights.Parking.IsDefect',
+ 'Vehicle.Body.Lights.Parking.IsOn',
+ 'Vehicle.Body.Lights.Running.IsDefect',
+ 'Vehicle.Body.Lights.Running.IsOn',
+ 'Vehicle.Body.Mirrors.DriverSide.IsHeatingOn',
+ 'Vehicle.Body.Mirrors.DriverSide.Pan',
+ 'Vehicle.Body.Mirrors.DriverSide.Tilt',
+ 'Vehicle.Body.Mirrors.PassengerSide.IsHeatingOn',
+ 'Vehicle.Body.Mirrors.PassengerSide.Pan',
+ 'Vehicle.Body.Mirrors.PassengerSide.Tilt',
+ 'Vehicle.Body.PowerOptimizeLevel',
+ 'Vehicle.Body.Raindetection.Intensity',
+ 'Vehicle.Body.RearMainSpoilerPosition',
+ 'Vehicle.Body.RefuelPosition',
+ 'Vehicle.Body.Trunk.Front.IsLightOn',
+ 'Vehicle.Body.Trunk.Front.IsLocked',
+ 'Vehicle.Body.Trunk.Front.IsOpen',
+ 'Vehicle.Body.Trunk.Rear.IsLightOn',
+ 'Vehicle.Body.Trunk.Rear.IsLocked',
+ 'Vehicle.Body.Trunk.Rear.IsOpen',
+ 'Vehicle.Body.Windshield.Front.IsHeatingOn',
+ 'Vehicle.Body.Windshield.Front.WasherFluid.IsLevelLow',
+ 'Vehicle.Body.Windshield.Front.WasherFluid.Level',
+ 'Vehicle.Body.Windshield.Front.Wiping.Intensity',
+ 'Vehicle.Body.Windshield.Front.Wiping.IsWipersWorn',
+ 'Vehicle.Body.Windshield.Front.Wiping.Mode',
+ 'Vehicle.Body.Windshield.Front.Wiping.System.ActualPosition',
+ 'Vehicle.Body.Windshield.Front.Wiping.System.DriveCurrent',
+ 'Vehicle.Body.Windshield.Front.Wiping.System.Frequency',
+ 'Vehicle.Body.Windshield.Front.Wiping.System.IsBlocked',
+ 'Vehicle.Body.Windshield.Front.Wiping.System.IsEndingWipeCycle',
+ 'Vehicle.Body.Windshield.Front.Wiping.System.IsOverheated',
+ 'Vehicle.Body.Windshield.Front.Wiping.System.IsPositionReached',
+ 'Vehicle.Body.Windshield.Front.Wiping.System.IsWiperError',
+ 'Vehicle.Body.Windshield.Front.Wiping.System.IsWiping',
+ 'Vehicle.Body.Windshield.Front.Wiping.System.Mode',
+ 'Vehicle.Body.Windshield.Front.Wiping.System.TargetPosition',
+ 'Vehicle.Body.Windshield.Front.Wiping.WiperWear',
+ 'Vehicle.Body.Windshield.Rear.IsHeatingOn',
+ 'Vehicle.Body.Windshield.Rear.WasherFluid.IsLevelLow',
+ 'Vehicle.Body.Windshield.Rear.WasherFluid.Level',
+ 'Vehicle.Body.Windshield.Rear.Wiping.Intensity',
+ 'Vehicle.Body.Windshield.Rear.Wiping.IsWipersWorn',
+ 'Vehicle.Body.Windshield.Rear.Wiping.Mode',
+ 'Vehicle.Body.Windshield.Rear.Wiping.System.ActualPosition',
+ 'Vehicle.Body.Windshield.Rear.Wiping.System.DriveCurrent',
+ 'Vehicle.Body.Windshield.Rear.Wiping.System.Frequency',
+ 'Vehicle.Body.Windshield.Rear.Wiping.System.IsBlocked',
+ 'Vehicle.Body.Windshield.Rear.Wiping.System.IsEndingWipeCycle',
+ 'Vehicle.Body.Windshield.Rear.Wiping.System.IsOverheated',
+ 'Vehicle.Body.Windshield.Rear.Wiping.System.IsPositionReached',
+ 'Vehicle.Body.Windshield.Rear.Wiping.System.IsWiperError',
+ 'Vehicle.Body.Windshield.Rear.Wiping.System.IsWiping',
+ 'Vehicle.Body.Windshield.Rear.Wiping.System.Mode',
+ 'Vehicle.Body.Windshield.Rear.Wiping.System.TargetPosition',
+ 'Vehicle.Body.Windshield.Rear.Wiping.WiperWear',
+ 'Vehicle.Cabin.Convertible.Status',
+ 'Vehicle.Cabin.Door.Row1.DriverSide.IsChildLockActive',
+ 'Vehicle.Cabin.Door.Row1.DriverSide.IsLocked',
+ 'Vehicle.Cabin.Door.Row1.DriverSide.IsOpen',
+ 'Vehicle.Cabin.Door.Row1.DriverSide.Shade.Position',
+ 'Vehicle.Cabin.Door.Row1.DriverSide.Shade.Switch',
+ 'Vehicle.Cabin.Door.Row1.DriverSide.Window.IsOpen',
+ 'Vehicle.Cabin.Door.Row1.DriverSide.Window.Position',
+ 'Vehicle.Cabin.Door.Row1.DriverSide.Window.Switch',
+ 'Vehicle.Cabin.Door.Row1.PassengerSide.IsChildLockActive',
+ 'Vehicle.Cabin.Door.Row1.PassengerSide.IsLocked',
+ 'Vehicle.Cabin.Door.Row1.PassengerSide.IsOpen',
+ 'Vehicle.Cabin.Door.Row1.PassengerSide.Shade.Position',
+ 'Vehicle.Cabin.Door.Row1.PassengerSide.Shade.Switch',
+ 'Vehicle.Cabin.Door.Row1.PassengerSide.Window.IsOpen',
+ 'Vehicle.Cabin.Door.Row1.PassengerSide.Window.Position',
+ 'Vehicle.Cabin.Door.Row1.PassengerSide.Window.Switch',
+ 'Vehicle.Cabin.Door.Row2.DriverSide.IsChildLockActive',
+ 'Vehicle.Cabin.Door.Row2.DriverSide.IsLocked',
+ 'Vehicle.Cabin.Door.Row2.DriverSide.IsOpen',
+ 'Vehicle.Cabin.Door.Row2.DriverSide.Shade.Position',
+ 'Vehicle.Cabin.Door.Row2.DriverSide.Shade.Switch',
+ 'Vehicle.Cabin.Door.Row2.DriverSide.Window.IsOpen',
+ 'Vehicle.Cabin.Door.Row2.DriverSide.Window.Position',
+ 'Vehicle.Cabin.Door.Row2.DriverSide.Window.Switch',
+ 'Vehicle.Cabin.Door.Row2.PassengerSide.IsChildLockActive',
+ 'Vehicle.Cabin.Door.Row2.PassengerSide.IsLocked',
+ 'Vehicle.Cabin.Door.Row2.PassengerSide.IsOpen',
+ 'Vehicle.Cabin.Door.Row2.PassengerSide.Shade.Position',
+ 'Vehicle.Cabin.Door.Row2.PassengerSide.Shade.Switch',
+ 'Vehicle.Cabin.Door.Row2.PassengerSide.Window.IsOpen',
+ 'Vehicle.Cabin.Door.Row2.PassengerSide.Window.Position',
+ 'Vehicle.Cabin.Door.Row2.PassengerSide.Window.Switch',
+ 'Vehicle.Cabin.DoorCount',
+ 'Vehicle.Cabin.DriverPosition',
+ 'Vehicle.Cabin.HVAC.AmbientAirTemperature',
+ 'Vehicle.Cabin.HVAC.IsAirConditioningActive',
+ 'Vehicle.Cabin.HVAC.IsFrontDefrosterActive',
+ 'Vehicle.Cabin.HVAC.IsRearDefrosterActive',
+ 'Vehicle.Cabin.HVAC.IsRecirculationActive',
+ 'Vehicle.Cabin.HVAC.PowerOptimizeLevel',
+ 'Vehicle.Cabin.HVAC.Station.Row1.Driver.AirDistribution',
+ 'Vehicle.Cabin.HVAC.Station.Row1.Driver.FanSpeed',
+ 'Vehicle.Cabin.HVAC.Station.Row1.Driver.Temperature',
+ 'Vehicle.Cabin.HVAC.Station.Row1.Passenger.AirDistribution',
+ 'Vehicle.Cabin.HVAC.Station.Row1.Passenger.FanSpeed',
+ 'Vehicle.Cabin.HVAC.Station.Row1.Passenger.Temperature',
+ 'Vehicle.Cabin.HVAC.Station.Row2.Driver.AirDistribution',
+ 'Vehicle.Cabin.HVAC.Station.Row2.Driver.FanSpeed',
+ 'Vehicle.Cabin.HVAC.Station.Row2.Driver.Temperature',
+ 'Vehicle.Cabin.HVAC.Station.Row2.Passenger.AirDistribution',
+ 'Vehicle.Cabin.HVAC.Station.Row2.Passenger.FanSpeed',
+ 'Vehicle.Cabin.HVAC.Station.Row2.Passenger.Temperature',
+ 'Vehicle.Cabin.HVAC.Station.Row3.Driver.AirDistribution',
+ 'Vehicle.Cabin.HVAC.Station.Row3.Driver.FanSpeed',
+ 'Vehicle.Cabin.HVAC.Station.Row3.Driver.Temperature',
+ 'Vehicle.Cabin.HVAC.Station.Row3.Passenger.AirDistribution',
+ 'Vehicle.Cabin.HVAC.Station.Row3.Passenger.FanSpeed',
+ 'Vehicle.Cabin.HVAC.Station.Row3.Passenger.Temperature',
+ 'Vehicle.Cabin.HVAC.Station.Row4.Driver.AirDistribution',
+ 'Vehicle.Cabin.HVAC.Station.Row4.Driver.FanSpeed',
+ 'Vehicle.Cabin.HVAC.Station.Row4.Driver.Temperature',
+ 'Vehicle.Cabin.HVAC.Station.Row4.Passenger.AirDistribution',
+ 'Vehicle.Cabin.HVAC.Station.Row4.Passenger.FanSpeed',
+ 'Vehicle.Cabin.HVAC.Station.Row4.Passenger.Temperature',
+ 'Vehicle.Cabin.Infotainment.HMI.Brightness',
+ 'Vehicle.Cabin.Infotainment.HMI.CurrentLanguage',
+ 'Vehicle.Cabin.Infotainment.HMI.DateFormat',
+ 'Vehicle.Cabin.Infotainment.HMI.DayNightMode',
+ 'Vehicle.Cabin.Infotainment.HMI.DisplayOffDuration',
+ 'Vehicle.Cabin.Infotainment.HMI.DistanceUnit',
+ 'Vehicle.Cabin.Infotainment.HMI.EVEconomyUnits',
+ 'Vehicle.Cabin.Infotainment.HMI.FontSize',
+ 'Vehicle.Cabin.Infotainment.HMI.FuelEconomyUnits',
+ 'Vehicle.Cabin.Infotainment.HMI.FuelVolumeUnit',
+ 'Vehicle.Cabin.Infotainment.HMI.IsScreenAlwaysOn',
+ 'Vehicle.Cabin.Infotainment.HMI.LastActionTime',
+ 'Vehicle.Cabin.Infotainment.HMI.TemperatureUnit',
+ 'Vehicle.Cabin.Infotainment.HMI.TimeFormat',
+ 'Vehicle.Cabin.Infotainment.HMI.TirePressureUnit',
+ 'Vehicle.Cabin.Infotainment.Media.Action',
+ 'Vehicle.Cabin.Infotainment.Media.DeclinedURI',
+ 'Vehicle.Cabin.Infotainment.Media.Played.Album',
+ 'Vehicle.Cabin.Infotainment.Media.Played.Artist',
+ 'Vehicle.Cabin.Infotainment.Media.Played.PlaybackRate',
+ 'Vehicle.Cabin.Infotainment.Media.Played.Source',
+ 'Vehicle.Cabin.Infotainment.Media.Played.Track',
+ 'Vehicle.Cabin.Infotainment.Media.Played.URI',
+ 'Vehicle.Cabin.Infotainment.Media.SelectedURI',
+ 'Vehicle.Cabin.Infotainment.Media.Volume',
+ 'Vehicle.Cabin.Infotainment.Navigation.DestinationSet.Latitude',
+ 'Vehicle.Cabin.Infotainment.Navigation.DestinationSet.Longitude',
+ 'Vehicle.Cabin.Infotainment.Navigation.GuidanceVoice',
+ 'Vehicle.Cabin.Infotainment.Navigation.Mute',
+ 'Vehicle.Cabin.Infotainment.Navigation.Volume',
+ 'Vehicle.Cabin.Infotainment.PowerOptimizeLevel',
+ 'Vehicle.Cabin.Infotainment.SmartphoneProjection.Active',
+ 'Vehicle.Cabin.Infotainment.SmartphoneProjection.Source',
+ 'Vehicle.Cabin.Infotainment.SmartphoneProjection.SupportedMode',
+ 'Vehicle.Cabin.IsWindowChildLockEngaged',
+ 'Vehicle.Cabin.Light.AmbientLight.Row1.DriverSide.Color',
+ 'Vehicle.Cabin.Light.AmbientLight.Row1.DriverSide.Intensity',
+ 'Vehicle.Cabin.Light.AmbientLight.Row1.DriverSide.IsLightOn',
+ 'Vehicle.Cabin.Light.AmbientLight.Row1.PassengerSide.Color',
+ 'Vehicle.Cabin.Light.AmbientLight.Row1.PassengerSide.Intensity',
+ 'Vehicle.Cabin.Light.AmbientLight.Row1.PassengerSide.IsLightOn',
+ 'Vehicle.Cabin.Light.AmbientLight.Row2.DriverSide.Color',
+ 'Vehicle.Cabin.Light.AmbientLight.Row2.DriverSide.Intensity',
+ 'Vehicle.Cabin.Light.AmbientLight.Row2.DriverSide.IsLightOn',
+ 'Vehicle.Cabin.Light.AmbientLight.Row2.PassengerSide.Color',
+ 'Vehicle.Cabin.Light.AmbientLight.Row2.PassengerSide.Intensity',
+ 'Vehicle.Cabin.Light.AmbientLight.Row2.PassengerSide.IsLightOn',
+ 'Vehicle.Cabin.Light.InteractiveLightBar.Color',
+ 'Vehicle.Cabin.Light.InteractiveLightBar.Effect',
+ 'Vehicle.Cabin.Light.InteractiveLightBar.Intensity',
+ 'Vehicle.Cabin.Light.InteractiveLightBar.IsLightOn',
+ 'Vehicle.Cabin.Light.IsDomeOn',
+ 'Vehicle.Cabin.Light.IsGloveBoxOn',
+ 'Vehicle.Cabin.Light.PerceivedAmbientLight',
+ 'Vehicle.Cabin.Light.Spotlight.Row1.DriverSide.Color',
+ 'Vehicle.Cabin.Light.Spotlight.Row1.DriverSide.Intensity',
+ 'Vehicle.Cabin.Light.Spotlight.Row1.DriverSide.IsLightOn',
+ 'Vehicle.Cabin.Light.Spotlight.Row1.PassengerSide.Color',
+ 'Vehicle.Cabin.Light.Spotlight.Row1.PassengerSide.Intensity',
+ 'Vehicle.Cabin.Light.Spotlight.Row1.PassengerSide.IsLightOn',
+ 'Vehicle.Cabin.Light.Spotlight.Row2.DriverSide.Color',
+ 'Vehicle.Cabin.Light.Spotlight.Row2.DriverSide.Intensity',
+ 'Vehicle.Cabin.Light.Spotlight.Row2.DriverSide.IsLightOn',
+ 'Vehicle.Cabin.Light.Spotlight.Row2.PassengerSide.Color',
+ 'Vehicle.Cabin.Light.Spotlight.Row2.PassengerSide.Intensity',
+ 'Vehicle.Cabin.Light.Spotlight.Row2.PassengerSide.IsLightOn',
+ 'Vehicle.Cabin.Light.Spotlight.Row3.DriverSide.Color',
+ 'Vehicle.Cabin.Light.Spotlight.Row3.DriverSide.Intensity',
+ 'Vehicle.Cabin.Light.Spotlight.Row3.DriverSide.IsLightOn',
+ 'Vehicle.Cabin.Light.Spotlight.Row3.PassengerSide.Color',
+ 'Vehicle.Cabin.Light.Spotlight.Row3.PassengerSide.Intensity',
+ 'Vehicle.Cabin.Light.Spotlight.Row3.PassengerSide.IsLightOn',
+ 'Vehicle.Cabin.Light.Spotlight.Row4.DriverSide.Color',
+ 'Vehicle.Cabin.Light.Spotlight.Row4.DriverSide.Intensity',
+ 'Vehicle.Cabin.Light.Spotlight.Row4.DriverSide.IsLightOn',
+ 'Vehicle.Cabin.Light.Spotlight.Row4.PassengerSide.Color',
+ 'Vehicle.Cabin.Light.Spotlight.Row4.PassengerSide.Intensity',
+ 'Vehicle.Cabin.Light.Spotlight.Row4.PassengerSide.IsLightOn',
+ 'Vehicle.Cabin.PowerOptimizeLevel',
+ 'Vehicle.Cabin.RearShade.Position',
+ 'Vehicle.Cabin.RearShade.Switch',
+ 'Vehicle.Cabin.RearviewMirror.DimmingLevel',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Airbag.IsDeployed',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Backrest.Lumbar.Height',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Backrest.Lumbar.Support',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Backrest.Recline',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Backrest.SideBolster.Support',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Headrest.Angle',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Headrest.Height',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Heating',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Height',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.IsBelted',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.IsOccupied',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Massage',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Occupant.Identifier.Issuer',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Occupant.Identifier.Subject',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Position',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Seating.Length',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Switch.Backrest.IsReclineBackwardEngaged',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Switch.Backrest.IsReclineForwardEngaged',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Switch.Backrest.Lumbar.IsDownEngaged',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Switch.Backrest.Lumbar.IsLessSupportEngaged',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Switch.Backrest.Lumbar.IsMoreSupportEngaged',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Switch.Backrest.Lumbar.IsUpEngaged',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Switch.Backrest.SideBolster.IsLessSupportEngaged',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Switch.Backrest.SideBolster.IsMoreSupportEngaged',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Switch.Headrest.IsBackwardEngaged',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Switch.Headrest.IsDownEngaged',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Switch.Headrest.IsForwardEngaged',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Switch.Headrest.IsUpEngaged',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Switch.IsBackwardEngaged',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Switch.IsCoolerEngaged',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Switch.IsDownEngaged',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Switch.IsForwardEngaged',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Switch.IsTiltBackwardEngaged',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Switch.IsTiltForwardEngaged',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Switch.IsUpEngaged',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Switch.IsWarmerEngaged',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Switch.Massage.IsDecreaseEngaged',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Switch.Massage.IsIncreaseEngaged',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Switch.Seating.IsBackwardEngaged',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Switch.Seating.IsForwardEngaged',
+ 'Vehicle.Cabin.Seat.Row1.DriverSide.Tilt',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Airbag.IsDeployed',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Backrest.Lumbar.Height',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Backrest.Lumbar.Support',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Backrest.Recline',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Backrest.SideBolster.Support',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Headrest.Angle',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Headrest.Height',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Heating',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Height',
+ 'Vehicle.Cabin.Seat.Row1.Middle.IsBelted',
+ 'Vehicle.Cabin.Seat.Row1.Middle.IsOccupied',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Massage',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Occupant.Identifier.Issuer',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Occupant.Identifier.Subject',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Position',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Seating.Length',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Switch.Backrest.IsReclineBackwardEngaged',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Switch.Backrest.IsReclineForwardEngaged',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Switch.Backrest.Lumbar.IsDownEngaged',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Switch.Backrest.Lumbar.IsLessSupportEngaged',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Switch.Backrest.Lumbar.IsMoreSupportEngaged',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Switch.Backrest.Lumbar.IsUpEngaged',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Switch.Backrest.SideBolster.IsLessSupportEngaged',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Switch.Backrest.SideBolster.IsMoreSupportEngaged',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Switch.Headrest.IsBackwardEngaged',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Switch.Headrest.IsDownEngaged',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Switch.Headrest.IsForwardEngaged',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Switch.Headrest.IsUpEngaged',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Switch.IsBackwardEngaged',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Switch.IsCoolerEngaged',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Switch.IsDownEngaged',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Switch.IsForwardEngaged',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Switch.IsTiltBackwardEngaged',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Switch.IsTiltForwardEngaged',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Switch.IsUpEngaged',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Switch.IsWarmerEngaged',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Switch.Massage.IsDecreaseEngaged',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Switch.Massage.IsIncreaseEngaged',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Switch.Seating.IsBackwardEngaged',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Switch.Seating.IsForwardEngaged',
+ 'Vehicle.Cabin.Seat.Row1.Middle.Tilt',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Airbag.IsDeployed',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Backrest.Lumbar.Height',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Backrest.Lumbar.Support',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Backrest.Recline',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Backrest.SideBolster.Support',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Headrest.Angle',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Headrest.Height',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Heating',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Height',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.IsBelted',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.IsOccupied',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Massage',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Occupant.Identifier.Issuer',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Occupant.Identifier.Subject',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Position',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Seating.Length',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.Backrest.IsReclineBackwardEngaged',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.Backrest.IsReclineForwardEngaged',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.Backrest.Lumbar.IsDownEngaged',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.Backrest.Lumbar.IsLessSupportEngaged',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.Backrest.Lumbar.IsMoreSupportEngaged',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.Backrest.Lumbar.IsUpEngaged',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.Backrest.SideBolster.',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.Backrest.SideBolster.',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.Headrest.IsBackwardEngaged',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.Headrest.IsDownEngaged',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.Headrest.IsForwardEngaged',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.Headrest.IsUpEngaged',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.IsBackwardEngaged',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.IsCoolerEngaged',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.IsDownEngaged',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.IsForwardEngaged',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.IsTiltBackwardEngaged',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.IsTiltForwardEngaged',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.IsUpEngaged',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.IsWarmerEngaged',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.Massage.IsDecreaseEngaged',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.Massage.IsIncreaseEngaged',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.Seating.IsBackwardEngaged',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Switch.Seating.IsForwardEngaged',
+ 'Vehicle.Cabin.Seat.Row1.PassengerSide.Tilt',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Airbag.IsDeployed',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Backrest.Lumbar.Height',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Backrest.Lumbar.Support',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Backrest.Recline',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Backrest.SideBolster.Support',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Headrest.Angle',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Headrest.Height',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Heating',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Height',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.IsBelted',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.IsOccupied',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Massage',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Occupant.Identifier.Issuer',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Occupant.Identifier.Subject',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Position',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Seating.Length',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Switch.Backrest.IsReclineBackwardEngaged',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Switch.Backrest.IsReclineForwardEngaged',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Switch.Backrest.Lumbar.IsDownEngaged',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Switch.Backrest.Lumbar.IsLessSupportEngaged',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Switch.Backrest.Lumbar.IsMoreSupportEngaged',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Switch.Backrest.Lumbar.IsUpEngaged',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Switch.Backrest.SideBolster.IsLessSupportEngaged',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Switch.Backrest.SideBolster.IsMoreSupportEngaged',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Switch.Headrest.IsBackwardEngaged',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Switch.Headrest.IsDownEngaged',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Switch.Headrest.IsForwardEngaged',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Switch.Headrest.IsUpEngaged',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Switch.IsBackwardEngaged',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Switch.IsCoolerEngaged',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Switch.IsDownEngaged',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Switch.IsForwardEngaged',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Switch.IsTiltBackwardEngaged',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Switch.IsTiltForwardEngaged',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Switch.IsUpEngaged',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Switch.IsWarmerEngaged',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Switch.Massage.IsDecreaseEngaged',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Switch.Massage.IsIncreaseEngaged',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Switch.Seating.IsBackwardEngaged',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Switch.Seating.IsForwardEngaged',
+ 'Vehicle.Cabin.Seat.Row2.DriverSide.Tilt',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Airbag.IsDeployed',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Backrest.Lumbar.Height',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Backrest.Lumbar.Support',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Backrest.Recline',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Backrest.SideBolster.Support',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Headrest.Angle',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Headrest.Height',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Heating',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Height',
+ 'Vehicle.Cabin.Seat.Row2.Middle.IsBelted',
+ 'Vehicle.Cabin.Seat.Row2.Middle.IsOccupied',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Massage',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Occupant.Identifier.Issuer',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Occupant.Identifier.Subject',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Position',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Seating.Length',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Switch.Backrest.IsReclineBackwardEngaged',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Switch.Backrest.IsReclineForwardEngaged',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Switch.Backrest.Lumbar.IsDownEngaged',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Switch.Backrest.Lumbar.IsLessSupportEngaged',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Switch.Backrest.Lumbar.IsMoreSupportEngaged',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Switch.Backrest.Lumbar.IsUpEngaged',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Switch.Backrest.SideBolster.IsLessSupportEngaged',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Switch.Backrest.SideBolster.IsMoreSupportEngaged',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Switch.Headrest.IsBackwardEngaged',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Switch.Headrest.IsDownEngaged',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Switch.Headrest.IsForwardEngaged',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Switch.Headrest.IsUpEngaged',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Switch.IsBackwardEngaged',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Switch.IsCoolerEngaged',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Switch.IsDownEngaged',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Switch.IsForwardEngaged',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Switch.IsTiltBackwardEngaged',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Switch.IsTiltForwardEngaged',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Switch.IsUpEngaged',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Switch.IsWarmerEngaged',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Switch.Massage.IsDecreaseEngaged',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Switch.Massage.IsIncreaseEngaged',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Switch.Seating.IsBackwardEngaged',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Switch.Seating.IsForwardEngaged',
+ 'Vehicle.Cabin.Seat.Row2.Middle.Tilt',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Airbag.IsDeployed',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Backrest.Lumbar.Height',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Backrest.Lumbar.Support',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Backrest.Recline',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Backrest.SideBolster.Support',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Headrest.Angle',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Headrest.Height',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Heating',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Height',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.IsBelted',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.IsOccupied',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Massage',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Occupant.Identifier.Issuer',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Occupant.Identifier.Subject',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Position',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Seating.Length',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.Backrest.IsReclineBackwardEngaged',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.Backrest.IsReclineForwardEngaged',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.Backrest.Lumbar.IsDownEngaged',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.Backrest.Lumbar.IsLessSupportEngaged',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.Backrest.Lumbar.IsMoreSupportEngaged',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.Backrest.Lumbar.IsUpEngaged',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.Backrest.SideBolster.',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.Backrest.SideBolster.',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.Headrest.IsBackwardEngaged',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.Headrest.IsDownEngaged',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.Headrest.IsForwardEngaged',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.Headrest.IsUpEngaged',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.IsBackwardEngaged',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.IsCoolerEngaged',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.IsDownEngaged',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.IsForwardEngaged',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.IsTiltBackwardEngaged',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.IsTiltForwardEngaged',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.IsUpEngaged',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.IsWarmerEngaged',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.Massage.IsDecreaseEngaged',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.Massage.IsIncreaseEngaged',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.Seating.IsBackwardEngaged',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Switch.Seating.IsForwardEngaged',
+ 'Vehicle.Cabin.Seat.Row2.PassengerSide.Tilt',
+ 'Vehicle.Cabin.SeatPosCount',
+ 'Vehicle.Cabin.SeatRowCount',
+ 'Vehicle.Cabin.Sunroof.Position',
+ 'Vehicle.Cabin.Sunroof.Shade.Position',
+ 'Vehicle.Cabin.Sunroof.Shade.Switch',
+ 'Vehicle.Cabin.Sunroof.Switch',
+ 'Vehicle.CargoVolume',
+ 'Vehicle.Chassis.Accelerator.PedalPosition',
+ 'Vehicle.Chassis.Axle.Row1.AxleWidth',
+ 'Vehicle.Chassis.Axle.Row1.SteeringAngle',
+ 'Vehicle.Chassis.Axle.Row1.TireAspectRatio',
+ 'Vehicle.Chassis.Axle.Row1.TireDiameter',
+ 'Vehicle.Chassis.Axle.Row1.TireWidth',
+ 'Vehicle.Chassis.Axle.Row1.TrackWidth',
+ 'Vehicle.Chassis.Axle.Row1.TreadWidth',
+ 'Vehicle.Chassis.Axle.Row1.Wheel.Left.Brake.FluidLevel',
+ 'Vehicle.Chassis.Axle.Row1.Wheel.Left.Brake.IsBrakesWorn',
+ 'Vehicle.Chassis.Axle.Row1.Wheel.Left.Brake.IsFluidLevelLow',
+ 'Vehicle.Chassis.Axle.Row1.Wheel.Left.Brake.PadWear',
+ 'Vehicle.Chassis.Axle.Row1.Wheel.Left.Speed',
+ 'Vehicle.Chassis.Axle.Row1.Wheel.Left.Tire.IsPressureLow',
+ 'Vehicle.Chassis.Axle.Row1.Wheel.Left.Tire.Pressure',
+ 'Vehicle.Chassis.Axle.Row1.Wheel.Left.Tire.Temperature',
+ 'Vehicle.Chassis.Axle.Row1.Wheel.Right.Brake.FluidLevel',
+ 'Vehicle.Chassis.Axle.Row1.Wheel.Right.Brake.IsBrakesWorn',
+ 'Vehicle.Chassis.Axle.Row1.Wheel.Right.Brake.IsFluidLevelLow',
+ 'Vehicle.Chassis.Axle.Row1.Wheel.Right.Brake.PadWear',
+ 'Vehicle.Chassis.Axle.Row1.Wheel.Right.Speed',
+ 'Vehicle.Chassis.Axle.Row1.Wheel.Right.Tire.IsPressureLow',
+ 'Vehicle.Chassis.Axle.Row1.Wheel.Right.Tire.Pressure',
+ 'Vehicle.Chassis.Axle.Row1.Wheel.Right.Tire.Temperature',
+ 'Vehicle.Chassis.Axle.Row1.WheelCount',
+ 'Vehicle.Chassis.Axle.Row1.WheelDiameter',
+ 'Vehicle.Chassis.Axle.Row1.WheelWidth',
+ 'Vehicle.Chassis.Axle.Row2.AxleWidth',
+ 'Vehicle.Chassis.Axle.Row2.SteeringAngle',
+ 'Vehicle.Chassis.Axle.Row2.TireAspectRatio',
+ 'Vehicle.Chassis.Axle.Row2.TireDiameter',
+ 'Vehicle.Chassis.Axle.Row2.TireWidth',
+ 'Vehicle.Chassis.Axle.Row2.TrackWidth',
+ 'Vehicle.Chassis.Axle.Row2.TreadWidth',
+ 'Vehicle.Chassis.Axle.Row2.Wheel.Left.Brake.FluidLevel',
+ 'Vehicle.Chassis.Axle.Row2.Wheel.Left.Brake.IsBrakesWorn',
+ 'Vehicle.Chassis.Axle.Row2.Wheel.Left.Brake.IsFluidLevelLow',
+ 'Vehicle.Chassis.Axle.Row2.Wheel.Left.Brake.PadWear',
+ 'Vehicle.Chassis.Axle.Row2.Wheel.Left.Speed',
+ 'Vehicle.Chassis.Axle.Row2.Wheel.Left.Tire.IsPressureLow',
+ 'Vehicle.Chassis.Axle.Row2.Wheel.Left.Tire.Pressure',
+ 'Vehicle.Chassis.Axle.Row2.Wheel.Left.Tire.Temperature',
+ 'Vehicle.Chassis.Axle.Row2.Wheel.Right.Brake.FluidLevel',
+ 'Vehicle.Chassis.Axle.Row2.Wheel.Right.Brake.IsBrakesWorn',
+ 'Vehicle.Chassis.Axle.Row2.Wheel.Right.Brake.IsFluidLevelLow',
+ 'Vehicle.Chassis.Axle.Row2.Wheel.Right.Brake.PadWear',
+ 'Vehicle.Chassis.Axle.Row2.Wheel.Right.Speed',
+ 'Vehicle.Chassis.Axle.Row2.Wheel.Right.Tire.IsPressureLow',
+ 'Vehicle.Chassis.Axle.Row2.Wheel.Right.Tire.Pressure',
+ 'Vehicle.Chassis.Axle.Row2.Wheel.Right.Tire.Temperature',
+ 'Vehicle.Chassis.Axle.Row2.WheelCount',
+ 'Vehicle.Chassis.Axle.Row2.WheelDiameter',
+ 'Vehicle.Chassis.Axle.Row2.WheelWidth',
+ 'Vehicle.Chassis.AxleCount',
+ 'Vehicle.Chassis.Brake.IsDriverEmergencyBrakingDetected',
+ 'Vehicle.Chassis.Brake.PedalPosition',
+ 'Vehicle.Chassis.ParkingBrake.IsAutoApplyEnabled',
+ 'Vehicle.Chassis.ParkingBrake.IsEngaged',
+ 'Vehicle.Chassis.SteeringWheel.Angle',
+ 'Vehicle.Chassis.SteeringWheel.Extension',
+ 'Vehicle.Chassis.SteeringWheel.Tilt',
+ 'Vehicle.Chassis.Wheelbase',
+ 'Vehicle.Connectivity.IsConnectivityAvailable',
+ 'Vehicle.CurbWeight',
+ 'Vehicle.CurrentLocation.Altitude',
+ 'Vehicle.CurrentLocation.GNSSReceiver.FixType',
+ 'Vehicle.CurrentLocation.GNSSReceiver.MountingPosition.X',
+ 'Vehicle.CurrentLocation.GNSSReceiver.MountingPosition.Y',
+ 'Vehicle.CurrentLocation.GNSSReceiver.MountingPosition.Z',
+ 'Vehicle.CurrentLocation.Heading',
+ 'Vehicle.CurrentLocation.HorizontalAccuracy',
+ 'Vehicle.CurrentLocation.Latitude',
+ 'Vehicle.CurrentLocation.Longitude',
+ 'Vehicle.CurrentLocation.Timestamp',
+ 'Vehicle.CurrentLocation.VerticalAccuracy',
+ 'Vehicle.CurrentOverallWeight',
+ 'Vehicle.Driver.AttentiveProbability',
+ 'Vehicle.Driver.DistractionLevel',
+ 'Vehicle.Driver.FatigueLevel',
+ 'Vehicle.Driver.HeartRate',
+ 'Vehicle.Driver.Identifier.Issuer',
+ 'Vehicle.Driver.Identifier.Subject',
+ 'Vehicle.Driver.IsEyesOnRoad',
+ 'Vehicle.Driver.IsHandsOnWheel',
+ 'Vehicle.EmissionsCO2',
+ 'Vehicle.Exterior.AirTemperature',
+ 'Vehicle.Exterior.Humidity',
+ 'Vehicle.Exterior.LightIntensity',
+ 'Vehicle.GrossWeight',
+ 'Vehicle.Height',
+ 'Vehicle.IsBrokenDown',
+ 'Vehicle.IsMoving',
+ 'Vehicle.Length',
+ 'Vehicle.LowVoltageBattery.CurrentCurrent',
+ 'Vehicle.LowVoltageBattery.CurrentVoltage',
+ 'Vehicle.LowVoltageBattery.NominalCapacity',
+ 'Vehicle.LowVoltageBattery.NominalVoltage',
+ 'Vehicle.LowVoltageSystemState',
+ 'Vehicle.MaxTowBallWeight',
+ 'Vehicle.MaxTowWeight',
+ 'Vehicle.OBD.AbsoluteLoad',
+ 'Vehicle.OBD.AcceleratorPositionD',
+ 'Vehicle.OBD.AcceleratorPositionE',
+ 'Vehicle.OBD.AcceleratorPositionF',
+ 'Vehicle.OBD.AirStatus',
+ 'Vehicle.OBD.AmbientAirTemperature',
+ 'Vehicle.OBD.BarometricPressure',
+ 'Vehicle.OBD.Catalyst.Bank1.Temperature1',
+ 'Vehicle.OBD.Catalyst.Bank1.Temperature2',
+ 'Vehicle.OBD.Catalyst.Bank2.Temperature1',
+ 'Vehicle.OBD.Catalyst.Bank2.Temperature2',
+ 'Vehicle.OBD.CommandedEGR',
+ 'Vehicle.OBD.CommandedEVAP',
+ 'Vehicle.OBD.CommandedEquivalenceRatio',
+ 'Vehicle.OBD.ControlModuleVoltage',
+ 'Vehicle.OBD.CoolantTemperature',
+ 'Vehicle.OBD.DTCList',
+ 'Vehicle.OBD.DistanceSinceDTCClear',
+ 'Vehicle.OBD.DistanceWithMIL',
+ 'Vehicle.OBD.DriveCycleStatus.DTCCount',
+ 'Vehicle.OBD.DriveCycleStatus.IgnitionType',
+ 'Vehicle.OBD.DriveCycleStatus.IsMILOn',
+ 'Vehicle.OBD.EGRError',
+ 'Vehicle.OBD.EVAPVaporPressure',
+ 'Vehicle.OBD.EVAPVaporPressureAbsolute',
+ 'Vehicle.OBD.EVAPVaporPressureAlternate',
+ 'Vehicle.OBD.EngineLoad',
+ 'Vehicle.OBD.EngineSpeed',
+ 'Vehicle.OBD.EthanolPercent',
+ 'Vehicle.OBD.FreezeDTC',
+ 'Vehicle.OBD.FuelInjectionTiming',
+ 'Vehicle.OBD.FuelLevel',
+ 'Vehicle.OBD.FuelPressure',
+ 'Vehicle.OBD.FuelRailPressureAbsolute',
+ 'Vehicle.OBD.FuelRailPressureDirect',
+ 'Vehicle.OBD.FuelRailPressureVac',
+ 'Vehicle.OBD.FuelRate',
+ 'Vehicle.OBD.FuelStatus',
+ 'Vehicle.OBD.FuelType',
+ 'Vehicle.OBD.HybridBatteryRemaining',
+ 'Vehicle.OBD.IntakeTemp',
+ 'Vehicle.OBD.IsPTOActive',
+ 'Vehicle.OBD.LongTermFuelTrim1',
+ 'Vehicle.OBD.LongTermFuelTrim2',
+ 'Vehicle.OBD.LongTermO2Trim1',
+ 'Vehicle.OBD.LongTermO2Trim2',
+ 'Vehicle.OBD.LongTermO2Trim3',
+ 'Vehicle.OBD.LongTermO2Trim4',
+ 'Vehicle.OBD.MAF',
+ 'Vehicle.OBD.MAP',
+ 'Vehicle.OBD.MaxMAF',
+ 'Vehicle.OBD.O2.Sensor1.ShortTermFuelTrim',
+ 'Vehicle.OBD.O2.Sensor1.Voltage',
+ 'Vehicle.OBD.O2.Sensor2.ShortTermFuelTrim',
+ 'Vehicle.OBD.O2.Sensor2.Voltage',
+ 'Vehicle.OBD.O2.Sensor3.ShortTermFuelTrim',
+ 'Vehicle.OBD.O2.Sensor3.Voltage',
+ 'Vehicle.OBD.O2.Sensor4.ShortTermFuelTrim',
+ 'Vehicle.OBD.O2.Sensor4.Voltage',
+ 'Vehicle.OBD.O2.Sensor5.ShortTermFuelTrim',
+ 'Vehicle.OBD.O2.Sensor5.Voltage',
+ 'Vehicle.OBD.O2.Sensor6.ShortTermFuelTrim',
+ 'Vehicle.OBD.O2.Sensor6.Voltage',
+ 'Vehicle.OBD.O2.Sensor7.ShortTermFuelTrim',
+ 'Vehicle.OBD.O2.Sensor7.Voltage',
+ 'Vehicle.OBD.O2.Sensor8.ShortTermFuelTrim',
+ 'Vehicle.OBD.O2.Sensor8.Voltage',
+ 'Vehicle.OBD.O2WR.Sensor1.Current',
+ 'Vehicle.OBD.O2WR.Sensor1.Lambda',
+ 'Vehicle.OBD.O2WR.Sensor1.Voltage',
+ 'Vehicle.OBD.O2WR.Sensor2.Current',
+ 'Vehicle.OBD.O2WR.Sensor2.Lambda',
+ 'Vehicle.OBD.O2WR.Sensor2.Voltage',
+ 'Vehicle.OBD.O2WR.Sensor3.Current',
+ 'Vehicle.OBD.O2WR.Sensor3.Lambda',
+ 'Vehicle.OBD.O2WR.Sensor3.Voltage',
+ 'Vehicle.OBD.O2WR.Sensor4.Current',
+ 'Vehicle.OBD.O2WR.Sensor4.Lambda',
+ 'Vehicle.OBD.O2WR.Sensor4.Voltage',
+ 'Vehicle.OBD.O2WR.Sensor5.Current',
+ 'Vehicle.OBD.O2WR.Sensor5.Lambda',
+ 'Vehicle.OBD.O2WR.Sensor5.Voltage',
+ 'Vehicle.OBD.O2WR.Sensor6.Current',
+ 'Vehicle.OBD.O2WR.Sensor6.Lambda',
+ 'Vehicle.OBD.O2WR.Sensor6.Voltage',
+ 'Vehicle.OBD.O2WR.Sensor7.Current',
+ 'Vehicle.OBD.O2WR.Sensor7.Lambda',
+ 'Vehicle.OBD.O2WR.Sensor7.Voltage',
+ 'Vehicle.OBD.O2WR.Sensor8.Current',
+ 'Vehicle.OBD.O2WR.Sensor8.Lambda',
+ 'Vehicle.OBD.O2WR.Sensor8.Voltage',
+ 'Vehicle.OBD.OBDStandards',
+ 'Vehicle.OBD.OilTemperature',
+ 'Vehicle.OBD.OxygenSensorsIn2Banks',
+ 'Vehicle.OBD.OxygenSensorsIn4Banks',
+ 'Vehicle.OBD.PidsA',
+ 'Vehicle.OBD.PidsB',
+ 'Vehicle.OBD.PidsC',
+ 'Vehicle.OBD.RelativeAcceleratorPosition',
+ 'Vehicle.OBD.RelativeThrottlePosition',
+ 'Vehicle.OBD.RunTime',
+ 'Vehicle.OBD.RunTimeMIL',
+ 'Vehicle.OBD.ShortTermFuelTrim1',
+ 'Vehicle.OBD.ShortTermFuelTrim2',
+ 'Vehicle.OBD.ShortTermO2Trim1',
+ 'Vehicle.OBD.ShortTermO2Trim2',
+ 'Vehicle.OBD.ShortTermO2Trim3',
+ 'Vehicle.OBD.ShortTermO2Trim4',
+ 'Vehicle.OBD.Speed',
+ 'Vehicle.OBD.Status.DTCCount',
+ 'Vehicle.OBD.Status.IgnitionType',
+ 'Vehicle.OBD.Status.IsMILOn',
+ 'Vehicle.OBD.ThrottleActuator',
+ 'Vehicle.OBD.ThrottlePosition',
+ 'Vehicle.OBD.ThrottlePositionB',
+ 'Vehicle.OBD.ThrottlePositionC',
+ 'Vehicle.OBD.TimeSinceDTCCleared',
+ 'Vehicle.OBD.TimingAdvance',
+ 'Vehicle.OBD.WarmupsSinceDTCClear',
+ 'Vehicle.PowerOptimizeLevel',
+ 'Vehicle.Powertrain.AccumulatedBrakingEnergy',
+ 'Vehicle.Powertrain.CombustionEngine.AspirationType',
+ 'Vehicle.Powertrain.CombustionEngine.Bore',
+ 'Vehicle.Powertrain.CombustionEngine.CompressionRatio',
+ 'Vehicle.Powertrain.CombustionEngine.Configuration',
+ 'Vehicle.Powertrain.CombustionEngine.DieselExhaustFluid.Capacity',
+ 'Vehicle.Powertrain.CombustionEngine.DieselExhaustFluid.IsLevelLow',
+ 'Vehicle.Powertrain.CombustionEngine.DieselExhaustFluid.Level',
+ 'Vehicle.Powertrain.CombustionEngine.DieselExhaustFluid.Range',
+ 'Vehicle.Powertrain.CombustionEngine.DieselParticulateFilter.DeltaPressure',
+ 'Vehicle.Powertrain.CombustionEngine.DieselParticulateFilter.InletTemperature',
+ 'Vehicle.Powertrain.CombustionEngine.DieselParticulateFilter.OutletTemperature',
+ 'Vehicle.Powertrain.CombustionEngine.Displacement',
+ 'Vehicle.Powertrain.CombustionEngine.ECT',
+ 'Vehicle.Powertrain.CombustionEngine.EOP',
+ 'Vehicle.Powertrain.CombustionEngine.EOT',
+ 'Vehicle.Powertrain.CombustionEngine.EngineCode',
+ 'Vehicle.Powertrain.CombustionEngine.EngineCoolantCapacity',
+ 'Vehicle.Powertrain.CombustionEngine.EngineHours',
+ 'Vehicle.Powertrain.CombustionEngine.EngineOilCapacity',
+ 'Vehicle.Powertrain.CombustionEngine.EngineOilLevel',
+ 'Vehicle.Powertrain.CombustionEngine.IdleHours',
+ 'Vehicle.Powertrain.CombustionEngine.IsRunning',
+ 'Vehicle.Powertrain.CombustionEngine.MAF',
+ 'Vehicle.Powertrain.CombustionEngine.MAP',
+ 'Vehicle.Powertrain.CombustionEngine.MaxPower',
+ 'Vehicle.Powertrain.CombustionEngine.MaxTorque',
+ 'Vehicle.Powertrain.CombustionEngine.NumberOfCylinders',
+ 'Vehicle.Powertrain.CombustionEngine.NumberOfValvesPerCylinder',
+ 'Vehicle.Powertrain.CombustionEngine.OilLifeRemaining',
+ 'Vehicle.Powertrain.CombustionEngine.Power',
+ 'Vehicle.Powertrain.CombustionEngine.Speed',
+ 'Vehicle.Powertrain.CombustionEngine.StrokeLength',
+ 'Vehicle.Powertrain.CombustionEngine.TPS',
+ 'Vehicle.Powertrain.CombustionEngine.Torque',
+ 'Vehicle.Powertrain.ElectricMotor.CoolantTemperature',
+ 'Vehicle.Powertrain.ElectricMotor.EngineCode',
+ 'Vehicle.Powertrain.ElectricMotor.MaxPower',
+ 'Vehicle.Powertrain.ElectricMotor.MaxRegenPower',
+ 'Vehicle.Powertrain.ElectricMotor.MaxRegenTorque',
+ 'Vehicle.Powertrain.ElectricMotor.MaxTorque',
+ 'Vehicle.Powertrain.ElectricMotor.Power',
+ 'Vehicle.Powertrain.ElectricMotor.Speed',
+ 'Vehicle.Powertrain.ElectricMotor.Temperature',
+ 'Vehicle.Powertrain.ElectricMotor.Torque',
+ 'Vehicle.Powertrain.FuelSystem.AbsoluteLevel',
+ 'Vehicle.Powertrain.FuelSystem.AverageConsumption',
+ 'Vehicle.Powertrain.FuelSystem.ConsumptionSinceStart',
+ 'Vehicle.Powertrain.FuelSystem.HybridType',
+ 'Vehicle.Powertrain.FuelSystem.InstantConsumption',
+ 'Vehicle.Powertrain.FuelSystem.IsEngineStopStartEnabled',
+ 'Vehicle.Powertrain.FuelSystem.IsFuelLevelLow',
+ 'Vehicle.Powertrain.FuelSystem.Range',
+ 'Vehicle.Powertrain.FuelSystem.RelativeLevel',
+ 'Vehicle.Powertrain.FuelSystem.SupportedFuel',
+ 'Vehicle.Powertrain.FuelSystem.SupportedFuelTypes',
+ 'Vehicle.Powertrain.FuelSystem.TankCapacity',
+ 'Vehicle.Powertrain.PowerOptimizeLevel',
+ 'Vehicle.Powertrain.Range',
+ 'Vehicle.Powertrain.TractionBattery.AccumulatedChargedEnergy',
+ 'Vehicle.Powertrain.TractionBattery.AccumulatedChargedThroughput',
+ 'Vehicle.Powertrain.TractionBattery.AccumulatedConsumedEnergy',
+ 'Vehicle.Powertrain.TractionBattery.AccumulatedConsumedThroughput',
+ 'Vehicle.Powertrain.TractionBattery.CellVoltage.Max',
+ 'Vehicle.Powertrain.TractionBattery.CellVoltage.Min',
+ 'Vehicle.Powertrain.TractionBattery.Charging.ChargeCurrent.DC',
+ 'Vehicle.Powertrain.TractionBattery.Charging.ChargeCurrent.Phase1',
+ 'Vehicle.Powertrain.TractionBattery.Charging.ChargeCurrent.Phase2',
+ 'Vehicle.Powertrain.TractionBattery.Charging.ChargeCurrent.Phase3',
+ 'Vehicle.Powertrain.TractionBattery.Charging.ChargeLimit',
+ 'Vehicle.Powertrain.TractionBattery.Charging.ChargePlugType',
+ 'Vehicle.Powertrain.TractionBattery.Charging.ChargePortFlap',
+ 'Vehicle.Powertrain.TractionBattery.Charging.ChargeRate',
+ 'Vehicle.Powertrain.TractionBattery.Charging.ChargeVoltage.DC',
+ 'Vehicle.Powertrain.TractionBattery.Charging.ChargeVoltage.Phase1',
+ 'Vehicle.Powertrain.TractionBattery.Charging.ChargeVoltage.Phase2',
+ 'Vehicle.Powertrain.TractionBattery.Charging.ChargeVoltage.Phase3',
+ 'Vehicle.Powertrain.TractionBattery.Charging.IsCharging',
+ 'Vehicle.Powertrain.TractionBattery.Charging.IsChargingCableConnected',
+ 'Vehicle.Powertrain.TractionBattery.Charging.IsChargingCableLocked',
+ 'Vehicle.Powertrain.TractionBattery.Charging.IsDischarging',
+ 'Vehicle.Powertrain.TractionBattery.Charging.MaximumChargingCurrent.DC',
+ 'Vehicle.Powertrain.TractionBattery.Charging.MaximumChargingCurrent.Phase1',
+ 'Vehicle.Powertrain.TractionBattery.Charging.MaximumChargingCurrent.Phase2',
+ 'Vehicle.Powertrain.TractionBattery.Charging.MaximumChargingCurrent.Phase3',
+ 'Vehicle.Powertrain.TractionBattery.Charging.Mode',
+ 'Vehicle.Powertrain.TractionBattery.Charging.PowerLoss',
+ 'Vehicle.Powertrain.TractionBattery.Charging.StartStopCharging',
+ 'Vehicle.Powertrain.TractionBattery.Charging.Temperature',
+ 'Vehicle.Powertrain.TractionBattery.Charging.TimeToComplete',
+ 'Vehicle.Powertrain.TractionBattery.Charging.Timer.Mode',
+ 'Vehicle.Powertrain.TractionBattery.Charging.Timer.Time',
+ 'Vehicle.Powertrain.TractionBattery.CurrentCurrent',
+ 'Vehicle.Powertrain.TractionBattery.CurrentPower',
+ 'Vehicle.Powertrain.TractionBattery.CurrentVoltage',
+ 'Vehicle.Powertrain.TractionBattery.DCDC.PowerLoss',
+ 'Vehicle.Powertrain.TractionBattery.DCDC.Temperature',
+ 'Vehicle.Powertrain.TractionBattery.GrossCapacity',
+ 'Vehicle.Powertrain.TractionBattery.Id',
+ 'Vehicle.Powertrain.TractionBattery.IsGroundConnected',
+ 'Vehicle.Powertrain.TractionBattery.IsPowerConnected',
+ 'Vehicle.Powertrain.TractionBattery.MaxVoltage',
+ 'Vehicle.Powertrain.TractionBattery.NetCapacity',
+ 'Vehicle.Powertrain.TractionBattery.NominalVoltage',
+ 'Vehicle.Powertrain.TractionBattery.PowerLoss',
+ 'Vehicle.Powertrain.TractionBattery.ProductionDate',
+ 'Vehicle.Powertrain.TractionBattery.Range',
+ 'Vehicle.Powertrain.TractionBattery.StateOfCharge.Current',
+ 'Vehicle.Powertrain.TractionBattery.StateOfCharge.CurrentEnergy',
+ 'Vehicle.Powertrain.TractionBattery.StateOfCharge.Displayed',
+ 'Vehicle.Powertrain.TractionBattery.StateOfHealth',
+ 'Vehicle.Powertrain.TractionBattery.Temperature.Average',
+ 'Vehicle.Powertrain.TractionBattery.Temperature.Max',
+ 'Vehicle.Powertrain.TractionBattery.Temperature.Min',
+ 'Vehicle.Powertrain.Transmission.ClutchEngagement',
+ 'Vehicle.Powertrain.Transmission.ClutchWear',
+ 'Vehicle.Powertrain.Transmission.CurrentGear',
+ 'Vehicle.Powertrain.Transmission.DiffLockFrontEngagement',
+ 'Vehicle.Powertrain.Transmission.DiffLockRearEngagement',
+ 'Vehicle.Powertrain.Transmission.DriveType',
+ 'Vehicle.Powertrain.Transmission.GearChangeMode',
+ 'Vehicle.Powertrain.Transmission.GearCount',
+ 'Vehicle.Powertrain.Transmission.IsElectricalPowertrainEngaged',
+ 'Vehicle.Powertrain.Transmission.IsLowRangeEngaged',
+ 'Vehicle.Powertrain.Transmission.IsParkLockEngaged',
+ 'Vehicle.Powertrain.Transmission.PerformanceMode',
+ 'Vehicle.Powertrain.Transmission.SelectedGear',
+ 'Vehicle.Powertrain.Transmission.Temperature',
+ 'Vehicle.Powertrain.Transmission.TorqueDistribution',
+ 'Vehicle.Powertrain.Transmission.TravelledDistance',
+ 'Vehicle.Powertrain.Transmission.Type',
+ 'Vehicle.Powertrain.Type',
+ 'Vehicle.RoofLoad',
+ 'Vehicle.Service.DistanceToService',
+ 'Vehicle.Service.IsServiceDue',
+ 'Vehicle.Service.TimeToService',
+ 'Vehicle.Speed',
+ 'Vehicle.StartTime',
+ 'Vehicle.Trailer.IsConnected',
+ 'Vehicle.TraveledDistance',
+ 'Vehicle.TraveledDistanceSinceStart',
+ 'Vehicle.TripDuration',
+ 'Vehicle.TripMeterReading',
+ 'Vehicle.VehicleIdentification.AcrissCode',
+ 'Vehicle.VehicleIdentification.BodyType',
+ 'Vehicle.VehicleIdentification.Brand',
+ 'Vehicle.VehicleIdentification.DateVehicleFirstRegistered',
+ 'Vehicle.VehicleIdentification.KnownVehicleDamages',
+ 'Vehicle.VehicleIdentification.MeetsEmissionStandard',
+ 'Vehicle.VehicleIdentification.Model',
+ 'Vehicle.VehicleIdentification.OptionalExtras',
+ 'Vehicle.VehicleIdentification.ProductionDate',
+ 'Vehicle.VehicleIdentification.PurchaseDate',
+ 'Vehicle.VehicleIdentification.VIN',
+ 'Vehicle.VehicleIdentification.VehicleConfiguration',
+ 'Vehicle.VehicleIdentification.VehicleInteriorColor',
+ 'Vehicle.VehicleIdentification.VehicleInteriorType',
+ 'Vehicle.VehicleIdentification.VehicleModelDate',
+ 'Vehicle.VehicleIdentification.VehicleSeatingCapacity',
+ 'Vehicle.VehicleIdentification.VehicleSpecialUsage',
+ 'Vehicle.VehicleIdentification.WMI',
+ 'Vehicle.VehicleIdentification.Year',
+ 'Vehicle.VersionVSS.Label',
+ 'Vehicle.VersionVSS.Major',
+ 'Vehicle.VersionVSS.Minor',
+ 'Vehicle.VersionVSS.Patch',
+ 'Vehicle.Width',
+];
diff --git a/lib/core/constants/val_client_helper.dart b/lib/core/constants/val_client_helper.dart
new file mode 100644
index 0000000..0d7a284
--- /dev/null
+++ b/lib/core/constants/val_client_helper.dart
@@ -0,0 +1,58 @@
+import 'package:protos/protos.dart';
+
+class ValClientHelper {
+ final ClientChannel channel;
+ final VALClient stub;
+
+ ValClientHelper({required this.channel, required this.stub});
+
+ void setUint32(String path, int value, [bool actuator = true]) async {
+ var dp = Datapoint()..uint32 = value;
+ set(path, dp, actuator);
+ }
+
+ void setInt32(String path, int value, [bool actuator = true]) async {
+ var dp = Datapoint()..int32 = value;
+ set(path, dp, actuator);
+ }
+
+ void setBool(String path, bool value, [bool actuator = true]) async {
+ var dp = Datapoint()..bool_12 = value;
+ set(path, dp, actuator);
+ }
+
+ void setString(String path, String value, [bool actuator = true]) async {
+ var dp = Datapoint()..string = value;
+ set(path, dp, actuator);
+ }
+
+ void setFloat(String path, double value, [bool actuator = true]) async {
+ var dp = Datapoint()..float = value;
+ set(path, dp, actuator);
+ }
+
+ void setDouble(String path, double value, [bool actuator = true]) async {
+ var dp = Datapoint()..double_18 = value;
+ set(path, dp, actuator);
+ }
+
+ void set(String path, Datapoint dp, bool actuator) async {
+ var entry = DataEntry()..path = path;
+ var update = EntryUpdate();
+ if (actuator) {
+ entry.actuatorTarget = dp;
+ update.fields.add(Field.FIELD_ACTUATOR_TARGET);
+ } else {
+ entry.value = dp;
+ update.fields.add(Field.FIELD_VALUE);
+ }
+ update.entry = entry;
+ var request = SetRequest();
+ request.updates.add(update);
+ Map<String, String> metadata = {};
+ // if (config.authorization.isNotEmpty) {
+ // metadata = {'authorization': "Bearer ${config.authorization}"};
+ // }
+ await stub.set(request, options: CallOptions(metadata: metadata));
+ }
+}
diff --git a/lib/core/constants/vss_path.dart b/lib/core/constants/vss_path.dart
new file mode 100644
index 0000000..8875d1e
--- /dev/null
+++ b/lib/core/constants/vss_path.dart
@@ -0,0 +1,58 @@
+class VSSPath {
+ static const String vehicleSpeed = 'Vehicle.Speed';
+ static const String vehicleInsideTemperature =
+ 'Vehicle.Cabin.HVAC.AmbientAirTemperature';
+ static const String vehicleOutsideTemperature =
+ 'Vehicle.Exterior.AirTemperature';
+ static const String vehicleRange = 'Vehicle.Powertrain.FuelSystem.Range';
+ static const String vehicleFuelLevel = 'Vehicle.OBD.FuelLevel';
+ static const String vehicleMediaVolume =
+ 'Vehicle.Cabin.Infotainment.Media.Volume';
+ static const String vehicleIsChildLockActiveLeft =
+ 'Vehicle.Cabin.Door.Row1.DriverSide.IsChildLockActive';
+ static const String vehicleIsChildLockActiveRight =
+ 'Vehicle.Cabin.Door.Row1.PassengerSide.IsChildLockActive';
+ static const String vehicleEngineSpeed =
+ 'Vehicle.Powertrain.CombustionEngine.Speed';
+ static const String vehicleFrontLeftTire =
+ 'Vehicle.Chassis.Axle.Row1.Wheel.Left.Tire.Pressure';
+ static const String vehicleFrontRightTire =
+ 'Vehicle.Chassis.Axle.Row1.Wheel.Right.Tire.Pressure';
+ static const String vehicleRearLeftTire =
+ 'Vehicle.Chassis.Axle.Row2.Wheel.Left.Tire.Pressure';
+ static const String vehicleRearRightTire =
+ 'Vehicle.Chassis.Axle.Row2.Wheel.Right.Tire.Pressure';
+ static const String vehicleIsAirConditioningActive =
+ 'Vehicle.Cabin.HVAC.IsAirConditioningActive';
+ static const String vehicleIsFrontDefrosterActive =
+ 'Vehicle.Cabin.HVAC.IsFrontDefrosterActive';
+ static const String vehicleIsRearDefrosterActive =
+ 'Vehicle.Cabin.HVAC.IsRearDefrosterActive';
+ static const String vehicleIsRecirculationActive =
+ 'Vehicle.Cabin.HVAC.IsRecirculationActive';
+ static const String vehicleFanSpeed =
+ 'Vehicle.Cabin.HVAC.Station.Row1.Driver.FanSpeed';
+
+ List<String> getSignalsList() {
+ return const [
+ vehicleSpeed,
+ vehicleInsideTemperature,
+ vehicleOutsideTemperature,
+ vehicleRange,
+ vehicleFuelLevel,
+ vehicleMediaVolume,
+ vehicleIsChildLockActiveLeft,
+ vehicleIsChildLockActiveRight,
+ vehicleEngineSpeed,
+ vehicleFrontLeftTire,
+ vehicleFrontRightTire,
+ vehicleRearLeftTire,
+ vehicleRearRightTire,
+ vehicleIsAirConditioningActive,
+ vehicleIsFrontDefrosterActive,
+ vehicleIsRearDefrosterActive,
+ vehicleIsRecirculationActive,
+ vehicleFanSpeed
+ ];
+ }
+}
diff --git a/lib/core/utils/helpers.dart b/lib/core/utils/helpers.dart
new file mode 100644
index 0000000..f2dbca2
--- /dev/null
+++ b/lib/core/utils/helpers.dart
@@ -0,0 +1,17 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+class Helpers {
+ static Shadow dropShadowRegular = Shadow(
+ color: Colors.black.withOpacity(0.70),
+ offset: const Offset(1, 2),
+ blurRadius: 3);
+ static BoxShadow boxDropShadowRegular = BoxShadow(
+ color: Colors.black.withOpacity(0.70),
+ offset: const Offset(1, 2),
+ blurRadius: 3);
+
+ static Shadow dropShadowBig = Shadow(
+ color: Colors.black.withOpacity(0.70),
+ offset: const Offset(1, 4),
+ blurRadius: 4);
+}
diff --git a/lib/core/utils/widgets/back_button.dart b/lib/core/utils/widgets/back_button.dart
new file mode 100644
index 0000000..8f0862b
--- /dev/null
+++ b/lib/core/utils/widgets/back_button.dart
@@ -0,0 +1,16 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+class CustomBackButton extends ConsumerWidget {
+ const CustomBackButton({super.key});
+
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ return BackButton(
+ onPressed: () {
+ ref.read(appProvider.notifier).update(
+ (state) => state = AppState.home,
+ );
+ },
+ );
+ }
+}
diff --git a/lib/data/data_providers/app.dart b/lib/data/data_providers/app.dart
new file mode 100644
index 0000000..acfaa01
--- /dev/null
+++ b/lib/data/data_providers/app.dart
@@ -0,0 +1,25 @@
+import '../../export.dart';
+
+class App extends StatelessWidget {
+ const App({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return const AppView();
+ }
+}
+
+class AppView extends StatelessWidget {
+ const AppView({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return ProviderScope(
+ child: MaterialApp(
+ debugShowCheckedModeBanner: false,
+ theme: theme,
+ home: const HomeScreen(),
+ ),
+ );
+ }
+}
diff --git a/lib/data/data_providers/app_provider.dart b/lib/data/data_providers/app_provider.dart
new file mode 100644
index 0000000..c528a1a
--- /dev/null
+++ b/lib/data/data_providers/app_provider.dart
@@ -0,0 +1,63 @@
+import 'package:flutter_ics_homescreen/data/data_providers/datetime_notifier.dart';
+import 'package:flutter_ics_homescreen/data/data_providers/hybrid_notifier.dart';
+import 'package:flutter_ics_homescreen/data/data_providers/signal_notifier.dart';
+import 'package:flutter_ics_homescreen/data/data_providers/units_notifier.dart';
+import 'package:flutter_ics_homescreen/data/data_providers/audio_notifier.dart';
+import 'package:flutter_ics_homescreen/data/data_providers/users_notifier.dart';
+import 'package:flutter_ics_homescreen/data/models/date_time.dart';
+import 'package:flutter_ics_homescreen/export.dart';
+
+import '../models/users.dart';
+import 'vehicle_notifier.dart';
+
+enum AppState {
+ home,
+ dashboard,
+ hvac,
+ apps,
+ mediaPlayer,
+ settings,
+ splash,
+ dateTime,
+ bluetooth,
+ wifi,
+ wired,
+ audioSettings,
+ profiles,
+ newProfile,
+ units,
+ versionInfo,
+ weather,
+ distanceUnit,
+ tempUnit,
+ clock,
+ date,
+ time
+}
+
+final appProvider = StateProvider<AppState>((ref) => AppState.splash);
+final vehicleProvider = StateNotifierProvider<VehicleNotifier, Vehicle>((ref) {
+ return VehicleNotifier(const Vehicle.initial());
+});
+final signalsProvider = StateNotifierProvider<SignalNotifier, Signals>((ref) {
+ return SignalNotifier(const Signals.initial());
+});
+
+final unitStateProvider = StateNotifierProvider<UnitsNotifier, Units>((ref) {
+ return UnitsNotifier(const Units.initial());
+});
+final audioStateProvider = StateNotifierProvider<AudioNotifier, Audio>((ref) {
+ return AudioNotifier(const Audio.initial());
+});
+
+final usersProvider = StateNotifierProvider<UsersNotifier, Users>((ref) {
+ return UsersNotifier(Users.initial());
+});
+
+final dateTimeStateProvider =
+ StateNotifierProvider<DateTimeNotifier, DateAndTime>((ref) {
+ return DateTimeNotifier(DateAndTime.initial());
+});
+final hybridtateProvider = StateNotifierProvider<HybridNotifier, Hybrid>((ref) {
+ return HybridNotifier(const Hybrid.initial());
+});
diff --git a/lib/data/data_providers/audio_notifier.dart b/lib/data/data_providers/audio_notifier.dart
new file mode 100644
index 0000000..8981036
--- /dev/null
+++ b/lib/data/data_providers/audio_notifier.dart
@@ -0,0 +1,25 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+class AudioNotifier extends StateNotifier<Audio> {
+ AudioNotifier(super.state);
+
+ void resetToDefaults() {
+ state = state.copyWith(treble: 5.0, bass: 5.0, rearFront: 5.0);
+ }
+
+ void setVolume(double newVal) {
+ state = state.copyWith(volume: newVal);
+ }
+
+ void setTreble(double newVal) {
+ state = state.copyWith(treble: newVal);
+ }
+
+ void setBass(double newVal) {
+ state = state.copyWith(bass: newVal);
+ }
+
+ void setRearFront(double newVal) {
+ state = state.copyWith(rearFront: newVal);
+ }
+}
diff --git a/lib/data/data_providers/datetime_notifier.dart b/lib/data/data_providers/datetime_notifier.dart
new file mode 100644
index 0000000..6947a34
--- /dev/null
+++ b/lib/data/data_providers/datetime_notifier.dart
@@ -0,0 +1,14 @@
+import 'package:flutter_ics_homescreen/data/models/date_time.dart';
+import 'package:flutter_ics_homescreen/export.dart';
+
+class DateTimeNotifier extends StateNotifier<DateAndTime> {
+ DateTimeNotifier(super.state);
+
+ void setDate(String newVal) {
+ state = state.copyWith(date: newVal);
+ }
+
+ void setTime(String newVal) {
+ state = state.copyWith(time: newVal);
+ }
+}
diff --git a/lib/data/data_providers/hybrid_notifier.dart b/lib/data/data_providers/hybrid_notifier.dart
new file mode 100644
index 0000000..a19bf58
--- /dev/null
+++ b/lib/data/data_providers/hybrid_notifier.dart
@@ -0,0 +1,91 @@
+import '../../export.dart';
+
+class HybridNotifier extends StateNotifier<Hybrid> {
+ HybridNotifier(super.state);
+
+ void setHybridState(HybridState hybridState) {
+ switch (hybridState) {
+ case HybridState.idle:
+ state = state.copyWith(
+ topArrowState: ArrowState.blue,
+ leftArrowState: ArrowState.blue,
+ rightArrowState: ArrowState.blue,
+ batteryState: BatteryState.white,
+ );
+ break;
+ case HybridState.engineOutput:
+ state = state.copyWith(
+ topArrowState: ArrowState.red,
+ leftArrowState: ArrowState.red,
+ rightArrowState: ArrowState.blue,
+ batteryState: BatteryState.red,
+ );
+ break;
+ case HybridState.regenerativeBreaking:
+ state = state.copyWith(
+ topArrowState: ArrowState.blue,
+ leftArrowState: ArrowState.blue,
+ rightArrowState: ArrowState.green,
+ batteryState: BatteryState.green);
+
+ break;
+ case HybridState.baterryOutput:
+ state = state.copyWith(
+ topArrowState: ArrowState.blue,
+ leftArrowState: ArrowState.blue,
+ rightArrowState: ArrowState.yellow,
+ batteryState: BatteryState.yellow);
+ break;
+ default:
+ }
+ state = state.copyWith(hybridState: hybridState);
+ }
+
+ void updateHybridState() {
+ // Variable to store the current state
+ HybridState currentState = state.hybridState;
+
+ // Variable to store the previous state
+ HybridState previousState = currentState;
+
+ // Variable to store the average speed value
+ double avgSpeed = 0.0;
+
+ // Variable for storing the average value of RPM
+ double avgRpm = 0.0;
+
+ // Variable to store the brake value state
+ bool brake = false;
+
+ // Collect 10 samples
+ for (int i = 0; i < 10; i++) {
+ // Get the current values for speed, engine rpm and brake status
+
+ // speed = vehicleProvider();
+ // rpm = _rpmFromServer();
+ // brake = _brakeFromServer();
+
+ // Calculate the average speed value
+ // avgSpeed = (avgSpeed * (i + 1) + speed) / (i + 2);
+
+ // Calculate the average engine rpm
+ // avgRpm = (avgRpm * (i + 1) + rpm) / (i + 2);
+ }
+
+ // define new state
+ // if (avgSpeed == 0 && avgRpm == 0) {
+ // currentState = HybridState.idle;
+ // } else if (avgRpm > 0 && avgSpeed > 0) {
+ // currentState = HybridState.engineOutput;
+ // } else if (avgRpm == 0 && brake) {
+ // currentState = HybridState.regenerativeBreaking;
+ // } else if (avgSpeed > 0 && avgRpm <= avgSpeed) {
+ // currentState = HybridState.baterryOutput;
+ // }
+
+ // Zaktualizuj stan
+ if (currentState != previousState) {
+ state = state.copyWith(hybridState: currentState);
+ }
+ }
+}
diff --git a/lib/data/data_providers/signal_notifier.dart b/lib/data/data_providers/signal_notifier.dart
new file mode 100644
index 0000000..3059174
--- /dev/null
+++ b/lib/data/data_providers/signal_notifier.dart
@@ -0,0 +1,14 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+class SignalNotifier extends StateNotifier<Signals> {
+ SignalNotifier(super.state);
+
+ void startListen() {}
+ void toggleBluetooth() {
+ state = state.copyWith(isBluetoothConnected: !state.isBluetoothConnected);
+ }
+
+ void toggleWifi() {
+ state = state.copyWith(isWifiConnected: !state.isWifiConnected);
+ }
+}
diff --git a/lib/data/data_providers/units_notifier.dart b/lib/data/data_providers/units_notifier.dart
new file mode 100644
index 0000000..f7c25aa
--- /dev/null
+++ b/lib/data/data_providers/units_notifier.dart
@@ -0,0 +1,13 @@
+import '../../export.dart';
+
+class UnitsNotifier extends StateNotifier<Units> {
+ UnitsNotifier(super.state);
+
+ void setDistanceUnit(DistanceUnit unit) {
+ state = state.copyWith(distanceUnit: unit);
+ }
+
+ void setTemperatureUnit(TemperatureUnit unit) {
+ state = state.copyWith(temperatureUnit: unit);
+ }
+}
diff --git a/lib/data/data_providers/users_notifier.dart b/lib/data/data_providers/users_notifier.dart
new file mode 100644
index 0000000..8b48382
--- /dev/null
+++ b/lib/data/data_providers/users_notifier.dart
@@ -0,0 +1,49 @@
+import 'package:flutter_ics_homescreen/data/models/users.dart';
+import 'package:flutter_ics_homescreen/export.dart';
+import 'package:uuid/uuid.dart';
+
+import '../models/user.dart';
+
+class UsersNotifier extends StateNotifier<Users> {
+ UsersNotifier(super.state) {
+ loadUsers();
+ }
+
+ void loadUsers() {
+ state = state.copyWith(users: _users);
+ }
+
+ final List<User> _users = [
+ const User(id: '1', name: 'Heather'),
+ const User(id: '2', name: 'George'),
+ const User(id: '3', name: 'Riley'),
+ ];
+ void selectUser(String userId) {
+ var seletedUser = state.users.firstWhere((user) => user.id == userId);
+ state = state.copyWith(selectedUser: seletedUser);
+ }
+
+ void removeUser(String userId) {
+ state.users.removeWhere((user) => user.id == userId);
+ if (state.users.isNotEmpty) {
+ state = state.copyWith(selectedUser: state.users.first);
+ }
+ if (state.users.isEmpty) {
+ state = state.copyWith(selectedUser: const User(id: '', name: ''));
+ }
+ }
+
+ void addUser(String userName) {
+ final id = const Uuid().v1();
+ final user = User(id: id, name: userName);
+
+ state.users.insert(0, user);
+ state = state.copyWith(selectedUser: state.users.first);
+ }
+
+ void editUser(User user) {
+ // final id = const Uuid().v1();
+ // final user = User(id: id, name: userName);
+ //_users.add(user);
+ }
+}
diff --git a/lib/data/data_providers/vehicle_notifier.dart b/lib/data/data_providers/vehicle_notifier.dart
new file mode 100644
index 0000000..7842311
--- /dev/null
+++ b/lib/data/data_providers/vehicle_notifier.dart
@@ -0,0 +1,367 @@
+import 'dart:async';
+
+import 'package:flutter_ics_homescreen/export.dart';
+import 'package:flutter/services.dart';
+import 'package:protos/protos.dart';
+
+class VehicleNotifier extends StateNotifier<Vehicle> {
+ VehicleNotifier(super.state);
+
+ late ClientChannel channel;
+ late VALClient stub;
+
+ void updateSpeed(double newValue) {
+ state = state.copyWith(speed: newValue);
+ }
+
+ void handleSignalsUpdate(EntryUpdate update) {
+ switch (update.entry.path) {
+ case VSSPath.vehicleSpeed:
+ if (update.entry.value.hasFloat()) {
+ state = state.copyWith(speed: update.entry.value.float);
+ }
+ break;
+ case VSSPath.vehicleInsideTemperature:
+ if (update.entry.value.hasFloat()) {
+ state = state.copyWith(insideTemperature: update.entry.value.float);
+ }
+ break;
+ case VSSPath.vehicleOutsideTemperature:
+ if (update.entry.value.hasFloat()) {
+ state = state.copyWith(outsideTemperature: update.entry.value.float);
+ }
+ break;
+ case VSSPath.vehicleRange:
+ if (update.entry.value.hasUint32()) {
+ state = state.copyWith(range: update.entry.value.uint32);
+ }
+ break;
+ case VSSPath.vehicleFuelLevel:
+ if (update.entry.value.hasFloat()) {
+ state = state.copyWith(fuelLevel: update.entry.value.float);
+ }
+ break;
+ // case VSSPath.vehicleMediaVolume:
+ // if (update.entry.value.hasInt32()) {
+ // ref
+ // .read(vehicleMediaVolume.notifier)
+ // .update((state) => state = update.entry.value.uint32);
+ // }
+ // break;
+ case VSSPath.vehicleIsChildLockActiveLeft:
+ if (update.entry.value.hasBool_12()) {
+ state =
+ state.copyWith(isChildLockActiveLeft: update.entry.value.bool_12);
+ }
+ break;
+ case VSSPath.vehicleIsChildLockActiveRight:
+ if (update.entry.value.hasBool_12()) {
+ state = state.copyWith(
+ isChildLockActiveRight: update.entry.value.bool_12);
+ }
+ break;
+ case VSSPath.vehicleEngineSpeed:
+ if (update.entry.value.hasUint32()) {
+ state = state.copyWith(engineSpeed: update.entry.value.uint32);
+ }
+ break;
+ case VSSPath.vehicleFrontLeftTire:
+ if (update.entry.value.hasUint32()) {
+ state = state.copyWith(frontLeftTire: update.entry.value.uint32);
+ }
+ break;
+ case VSSPath.vehicleFrontRightTire:
+ if (update.entry.value.hasUint32()) {
+ state = state.copyWith(frontRightTire: update.entry.value.uint32);
+ }
+ break;
+ case VSSPath.vehicleRearLeftTire:
+ if (update.entry.value.hasUint32()) {
+ state = state.copyWith(rearLeftTire: update.entry.value.uint32);
+ }
+ break;
+ case VSSPath.vehicleRearRightTire:
+ if (update.entry.value.hasUint32()) {
+ state = state.copyWith(rearRightTire: update.entry.value.uint32);
+ }
+ break;
+
+ ///
+ case VSSPath.vehicleIsAirConditioningActive:
+ if (update.entry.value.hasBool_12()) {
+ state = state.copyWith(
+ isAirConditioningActive: update.entry.value.bool_12);
+ }
+ break;
+ case VSSPath.vehicleIsFrontDefrosterActive:
+ if (update.entry.value.hasBool_12()) {
+ state = state.copyWith(
+ isFrontDefrosterActive: update.entry.value.bool_12);
+ }
+ break;
+ case VSSPath.vehicleIsRearDefrosterActive:
+ if (update.entry.value.hasBool_12()) {
+ state =
+ state.copyWith(isRearDefrosterActive: update.entry.value.bool_12);
+ }
+ break;
+ case VSSPath.vehicleIsRecirculationActive:
+ if (update.entry.value.hasBool_12()) {
+ state =
+ state.copyWith(isRecirculationActive: update.entry.value.bool_12);
+ }
+ break;
+ case VSSPath.vehicleFanSpeed:
+ if (update.entry.value.hasUint32()) {
+ state = state.copyWith(fanSpeed: update.entry.value.uint32);
+ }
+ break;
+
+ // default:
+ // debugPrint("ERROR: Unexpected path ${update.entry.path}");
+ // break;
+ }
+ }
+
+ void startListen() async {
+ String hostName = 'localhost';
+ int port = 8080;
+ try {
+ var data = await rootBundle.loadString('config/config.yaml');
+ final dynamic yamlMap = loadYaml(data);
+
+ if (yamlMap.containsKey('hostname')) {
+ hostName = yamlMap['hostname'];
+ }
+
+ if (yamlMap.containsKey('port')) {
+ port = yamlMap['port'];
+ }
+ } catch (e) {
+ //debugPrint('ERROR: Could not read from file: $configFile');
+ debugPrint(e.toString());
+ }
+ channel = ClientChannel(
+ hostName,
+ port: port,
+ options: const ChannelOptions(
+ credentials: ChannelCredentials.insecure(),
+ ),
+ );
+
+ debugPrint('Start Listen on port: $port');
+ stub = VALClient(channel);
+ List<String> fewSignals = VSSPath().getSignalsList();
+ var request = SubscribeRequest();
+ for (int i = 0; i < fewSignals.length; i++) {
+ var entry = SubscribeEntry();
+ entry.path = fewSignals[i];
+ entry.fields.add(Field.FIELD_PATH);
+ entry.fields.add(Field.FIELD_VALUE);
+ request.entries.add(entry);
+ // _stub.subscribe(request).listen((value) async {
+ // //debugPrint(value.toString());
+ // });
+ }
+ try {
+ // ignore: unused_local_variable
+ Map<String, String> metadata = {};
+ //var responseStream = _stub.subscribe(request);
+ stub.subscribe(request).listen((value) async {
+ for (var update in value.updates) {
+ if (!(update.hasEntry() && update.entry.hasPath())) continue;
+ handleSignalsUpdate(update);
+ }
+ }, onError: (stacktrace, errorDescriptor) {
+ debugPrint(stacktrace.toString());
+ state = const Vehicle.initialForDebug();
+
+ });
+ } catch (e) {
+ debugPrint(e.toString());
+ }
+ }
+
+ void setChildLock({required String side}) {
+ var helper = ValClientHelper(channel: channel, stub: stub);
+ try {
+ switch (side) {
+ case 'left':
+ helper.setBool(
+ VSSPath.vehicleIsChildLockActiveLeft,
+ !state.isChildLockActiveLeft,
+ false,
+ );
+ state = state.copyWith(
+ isChildLockActiveLeft: !state.isChildLockActiveLeft);
+ break;
+ case 'right':
+ helper.setBool(
+ VSSPath.vehicleIsChildLockActiveRight,
+ !state.isChildLockActiveRight,
+ false,
+ );
+ state = state.copyWith(
+ isChildLockActiveRight: !state.isChildLockActiveRight);
+ break;
+ default:
+ debugPrint("ERROR: Unexpected side value $side}");
+ break;
+ }
+ } catch (e) {
+ debugPrint(e.toString());
+ }
+ }
+
+ void updateFanSpeed(int newValue) {
+ state = state.copyWith(fanSpeed: newValue);
+ }
+
+ void setHVACMode({required String mode}) {
+ var helper = ValClientHelper(channel: channel, stub: stub);
+ try {
+ switch (mode) {
+ case 'airCondition':
+ helper.setBool(
+ VSSPath.vehicleIsAirConditioningActive,
+ !state.isAirConditioningActive,
+ false,
+ );
+ state = state.copyWith(
+ isAirConditioningActive: !state.isAirConditioningActive);
+ break;
+ case 'frontDefrost':
+ helper.setBool(
+ VSSPath.vehicleIsFrontDefrosterActive,
+ !state.isFrontDefrosterActive,
+ false,
+ );
+ state = state.copyWith(
+ isFrontDefrosterActive: !state.isFrontDefrosterActive);
+ break;
+ case 'rearDefrost':
+ helper.setBool(
+ VSSPath.vehicleIsRearDefrosterActive,
+ !state.isRearDefrosterActive,
+ false,
+ );
+ state = state.copyWith(
+ isRearDefrosterActive: !state.isRearDefrosterActive);
+ break;
+ case 'recirculation':
+ helper.setBool(
+ VSSPath.vehicleIsRecirculationActive,
+ !state.isRecirculationActive,
+ false,
+ );
+ state = state.copyWith(
+ isRecirculationActive: !state.isRecirculationActive);
+ break;
+ default:
+ debugPrint("ERROR: Unexpected mode value $mode}");
+ break;
+ }
+ } catch (e) {
+ debugPrint(e.toString());
+ }
+ }
+
+ void setInitialState() {
+ var speed = state.speed;
+ var rpm = state.engineSpeed;
+ var fuelLevel = state.fuelLevel;
+ var insideTemp = state.insideTemperature;
+ var outsideTemp = state.outsideTemperature;
+ var range = state.range;
+ var psi = state.frontLeftTire;
+ var actualSpeed = 0.0;
+ var actualRpm = 0;
+ var actualFuelLevel = 0.0;
+ var actualInsideTemp = 0.0;
+ var actualOutsideTemp = 0.0;
+ var actualRange = 0;
+ var actualPsi = 0;
+
+ state = const Vehicle.initial();
+ Timer speedTimer =
+ Timer.periodic(const Duration(milliseconds: 600), (timer) {
+ actualSpeed = actualSpeed + 10;
+
+ if (actualSpeed > speed) {
+ actualSpeed = speed;
+
+ timer.cancel();
+ }
+ state = state.copyWith(speed: actualSpeed);
+ });
+ Timer rpmTimer = Timer.periodic(const Duration(milliseconds: 400), (timer) {
+ actualRpm = actualRpm + 150;
+
+ if (actualRpm > rpm) {
+ actualRpm = rpm;
+ timer.cancel();
+ }
+ state = state.copyWith(engineSpeed: actualRpm);
+ });
+ Timer fuelLevelTimer =
+ Timer.periodic(const Duration(milliseconds: 400), (timer) {
+ actualFuelLevel = actualFuelLevel + 1;
+
+ if (actualFuelLevel > fuelLevel) {
+ actualFuelLevel = fuelLevel;
+
+ timer.cancel();
+ }
+ state = state.copyWith(fuelLevel: actualFuelLevel);
+ });
+ Timer outsideTemperatureTimer =
+ Timer.periodic(const Duration(milliseconds: 300), (timer) {
+ actualOutsideTemp = actualOutsideTemp + 0.5;
+
+ if (actualOutsideTemp > outsideTemp) {
+ actualOutsideTemp = outsideTemp;
+
+ timer.cancel();
+ }
+ state = state.copyWith(outsideTemperature: actualOutsideTemp);
+ });
+ Timer insideTemperatureTimer =
+ Timer.periodic(const Duration(milliseconds: 300), (timer) {
+ actualInsideTemp = actualInsideTemp + 0.5;
+
+ if (actualInsideTemp > insideTemp) {
+ actualInsideTemp = insideTemp;
+
+ timer.cancel();
+ }
+ state = state.copyWith(insideTemperature: actualInsideTemp);
+ });
+ Timer rangeTimer =
+ Timer.periodic(const Duration(milliseconds: 300), (timer) {
+ actualRange = actualRange + 5;
+
+ if (actualRange > range) {
+ actualRange = range;
+
+ timer.cancel();
+ }
+ state = state.copyWith(range: actualRange);
+ });
+ Timer psiTimer =
+ Timer.periodic(const Duration(milliseconds: 1200), (timer) {
+ actualPsi = actualPsi + 5;
+
+ if (actualPsi > psi) {
+ actualPsi = psi;
+
+ timer.cancel();
+ }
+ state = state.copyWith(
+ frontLeftTire: actualPsi,
+ rearLeftTire: actualPsi,
+ frontRightTire: actualPsi,
+ rearRightTire: actualPsi,
+ );
+ });
+ }
+}
diff --git a/lib/data/data_providers/vss_provider.dart b/lib/data/data_providers/vss_provider.dart
new file mode 100644
index 0000000..ca02de6
--- /dev/null
+++ b/lib/data/data_providers/vss_provider.dart
@@ -0,0 +1,105 @@
+import 'package:flutter_ics_homescreen/export.dart';
+import 'package:protos/protos.dart';
+
+class VSS {
+ static handleSignalUpdates(
+ EntryUpdate update,
+ ) {
+ //final ref = ProviderContainer().read(vehicleStateProvider);
+ switch (update.entry.path) {
+ case VSSPath.vehicleSpeed:
+ if (update.entry.value.hasFloat()) {
+ //print(ref);
+ }
+ break;
+ // case VSSPath.vehicleInsideTemperature:
+ // if (update.entry.value.hasFloat()) {
+ // ref
+ // .read(vehicleInsideTemperature.notifier)
+ // .update((state) => state = update.entry.value.float);
+ // }
+ // break;
+ // case VSSPath.vehicleOutsideTemperature:
+ // if (update.entry.value.hasFloat()) {
+ // ref
+ // .read(vehicleOutSideTemperature.notifier)
+ // .update((state) => state = update.entry.value.float);
+ // }
+ // break;
+ // case VSSPath.vehicleRange:
+ // if (update.entry.value.hasInt32()) {
+ // ref
+ // .read(vehicleRange.notifier)
+ // .update((state) => state = update.entry.value.uint32);
+ // }
+ // break;
+ // case VSSPath.vehicleFuelLevel:
+ // if (update.entry.value.hasInt32()) {
+ // ref
+ // .read(vehicleFuelLevel.notifier)
+ // .update((state) => state = update.entry.value.uint32);
+ // }
+ // break;
+ // case VSSPath.vehicleMediaVolume:
+ // if (update.entry.value.hasInt32()) {
+ // ref
+ // .read(vehicleMediaVolume.notifier)
+ // .update((state) => state = update.entry.value.uint32);
+ // }
+ // break;
+ // case VSSPath.vehicleIsChildLockActiveLeft:
+ // if (update.entry.value.hasBool_12()) {
+ // ref
+ // .read(vehicleIsChildLockActiveLeft.notifier)
+ // .update((state) => state = update.entry.value.bool_12);
+ // }
+ // break;
+ // case VSSPath.vehicleIsChildLockActiveRight:
+ // if (update.entry.value.hasBool_12()) {
+ // ref
+ // .read(vehicleIsChildLockActiveRight.notifier)
+ // .update((state) => state = update.entry.value.bool_12);
+ // }
+ // break;
+ // case VSSPath.vehicleEngineSpeed:
+ // if (update.entry.value.hasFloat()) {
+ // ref
+ // .read(vehicleEngineSpeed.notifier)
+ // .update((state) => state = update.entry.value.float);
+ // }
+ // break;
+ // case VSSPath.vehicleFrontLeftTire:
+ // if (update.entry.value.hasFloat()) {
+ // ref
+ // .read(vehicleFrontLeftTire.notifier)
+ // .update((state) => state = update.entry.value.float);
+ // }
+ // break;
+ // case VSSPath.vehicleFrontRightTire:
+ // if (update.entry.value.hasFloat()) {
+ // ref
+ // .read(vehicleFrontRightTire.notifier)
+ // .update((state) => state = update.entry.value.float);
+ // }
+ // break;
+ // case VSSPath.vehicleRearLeftTire:
+ // if (update.entry.value.hasFloat()) {
+ // ref
+ // .read(vehicleRearLeftTire.notifier)
+ // .update((state) => state = update.entry.value.float);
+ // }
+ // break;
+ // case VSSPath.vehicleRearRightTire:
+ // if (update.entry.value.hasFloat()) {
+ // ref
+ // .read(vehicleRearRightTire.notifier)
+ // .update((state) => state = update.entry.value.float);
+ // }
+ // break;
+
+ default:
+ debugPrint("ERROR: Unexpected path ${update.entry.path}");
+ break;
+ }
+ }
+}
diff --git a/lib/data/models/audio.dart b/lib/data/models/audio.dart
new file mode 100644
index 0000000..69df18b
--- /dev/null
+++ b/lib/data/models/audio.dart
@@ -0,0 +1,84 @@
+import 'dart:convert';
+
+import 'package:flutter_ics_homescreen/export.dart';
+
+@immutable
+class Audio {
+ final double volume;
+ final double treble;
+ final double bass;
+ final double rearFront;
+ const Audio({
+ required this.volume,
+ required this.treble,
+ required this.bass,
+ required this.rearFront,
+ });
+
+ const Audio.initial()
+ : volume = 5.0,
+ treble = 5.0,
+ bass = 5.0,
+ rearFront = 5.0;
+
+
+ Audio copyWith({
+ double? volume,
+ double? treble,
+ double? bass,
+ double? rearFront,
+ }) {
+ return Audio(
+ volume: volume ?? this.volume,
+ treble: treble ?? this.treble,
+ bass: bass ?? this.bass,
+ rearFront: rearFront ?? this.rearFront,
+ );
+ }
+
+ Map<String, dynamic> toMap() {
+ return {
+ 'volume': volume,
+ 'treble': treble,
+ 'bass': bass,
+ 'rearFront': rearFront,
+ };
+ }
+
+ factory Audio.fromMap(Map<String, dynamic> map) {
+ return Audio(
+ volume: map['volume']?.toDouble() ?? 0.0,
+ treble: map['treble']?.toDouble() ?? 0.0,
+ bass: map['bass']?.toDouble() ?? 0.0,
+ rearFront: map['rearFront']?.toDouble() ?? 0.0,
+ );
+ }
+
+ String toJson() => json.encode(toMap());
+
+ factory Audio.fromJson(String source) => Audio.fromMap(json.decode(source));
+
+ @override
+ String toString() {
+ return 'Audio(volume: $volume, treble: $treble, bass: $bass, rearFront: $rearFront)';
+ }
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(this, other)) return true;
+
+ return other is Audio &&
+ other.volume == volume &&
+ other.treble == treble &&
+ other.bass == bass &&
+ other.rearFront == rearFront;
+ }
+
+ @override
+ int get hashCode {
+ return volume.hashCode ^
+ treble.hashCode ^
+ bass.hashCode ^
+ rearFront.hashCode;
+ }
+}
diff --git a/lib/data/models/connections_signals.dart b/lib/data/models/connections_signals.dart
new file mode 100644
index 0000000..cd6d695
--- /dev/null
+++ b/lib/data/models/connections_signals.dart
@@ -0,0 +1,92 @@
+import 'dart:convert';
+
+import 'package:flutter_ics_homescreen/export.dart';
+
+@immutable
+class Signals {
+ final bool isBluetoothConnected;
+ final bool isDataConnected;
+ final bool isWifiConnected;
+ final int dataSignalStrenght;
+ final int wifiSignalStrenght;
+ const Signals({
+ required this.isBluetoothConnected,
+ required this.isDataConnected,
+ required this.isWifiConnected,
+ required this.dataSignalStrenght,
+ required this.wifiSignalStrenght,
+ });
+ const Signals.initial()
+ : isBluetoothConnected = false,
+ isDataConnected = false,
+ isWifiConnected = false,
+ dataSignalStrenght = 0,
+ wifiSignalStrenght = 0;
+
+ Signals copyWith({
+ bool? isBluetoothConnected,
+ bool? isDataConnected,
+ bool? isWifiConnected,
+ int? dataSignalStrenght,
+ int? wifiSignalStrenght,
+ }) {
+ return Signals(
+ isBluetoothConnected: isBluetoothConnected ?? this.isBluetoothConnected,
+ isDataConnected: isDataConnected ?? this.isDataConnected,
+ isWifiConnected: isWifiConnected ?? this.isWifiConnected,
+ dataSignalStrenght: dataSignalStrenght ?? this.dataSignalStrenght,
+ wifiSignalStrenght: wifiSignalStrenght ?? this.wifiSignalStrenght,
+ );
+ }
+
+ Map<String, dynamic> toMap() {
+ return {
+ 'isBluetoothConnected': isBluetoothConnected,
+ 'isDataConnected': isDataConnected,
+ 'isWifiConnected': isWifiConnected,
+ 'dataSignalStrenght': dataSignalStrenght,
+ 'wifiSignalStrenght': wifiSignalStrenght,
+ };
+ }
+
+ factory Signals.fromMap(Map<String, dynamic> map) {
+ return Signals(
+ isBluetoothConnected: map['isBluetoothConnected'] ?? false,
+ isDataConnected: map['isDataConnected'] ?? false,
+ isWifiConnected: map['isWifiConnected'] ?? false,
+ dataSignalStrenght: map['dataSignalStrenght']?.toInt() ?? 0,
+ wifiSignalStrenght: map['wifiSignalStrenght']?.toInt() ?? 0,
+ );
+ }
+
+ String toJson() => json.encode(toMap());
+
+ factory Signals.fromJson(String source) =>
+ Signals.fromMap(json.decode(source));
+
+ @override
+ String toString() {
+ return 'Signals(isBluetoothConnected: $isBluetoothConnected, isDataConnected: $isDataConnected, isWifiConnected: $isWifiConnected, dataSignalStrenght: $dataSignalStrenght, wifiSignalStrenght: $wifiSignalStrenght)';
+ }
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(this, other)) return true;
+
+ return other is Signals &&
+ other.isBluetoothConnected == isBluetoothConnected &&
+ other.isDataConnected == isDataConnected &&
+ other.isWifiConnected == isWifiConnected &&
+ other.dataSignalStrenght == dataSignalStrenght &&
+ other.wifiSignalStrenght == wifiSignalStrenght;
+ }
+
+ @override
+ int get hashCode {
+ return isBluetoothConnected.hashCode ^
+ isDataConnected.hashCode ^
+ isWifiConnected.hashCode ^
+ dataSignalStrenght.hashCode ^
+ wifiSignalStrenght.hashCode;
+ }
+}
diff --git a/lib/data/models/date_time.dart b/lib/data/models/date_time.dart
new file mode 100644
index 0000000..62d7743
--- /dev/null
+++ b/lib/data/models/date_time.dart
@@ -0,0 +1,59 @@
+import 'dart:convert';
+
+import 'package:flutter_ics_homescreen/export.dart';
+import 'package:intl/intl.dart';
+
+@immutable
+class DateAndTime {
+ final String date;
+ final String time;
+ const DateAndTime({
+ required this.date,
+ required this.time,
+ });
+
+ DateAndTime.initial()
+ : date = DateFormat().add_yMMMMd().format(DateTime.now()),
+ time = DateFormat('hh:mm a').format(DateTime.now());
+ DateAndTime copyWith({
+ String? date,
+ String? time,
+ }) {
+ return DateAndTime(
+ date: date ?? this.date,
+ time: time ?? this.time,
+ );
+ }
+
+ Map<String, dynamic> toMap() {
+ return {
+ 'date': date,
+ 'time': time,
+ };
+ }
+
+ factory DateAndTime.fromMap(Map<String, dynamic> map) {
+ return DateAndTime(
+ date: map['date'],
+ time: map['time'],
+ );
+ }
+
+ String toJson() => json.encode(toMap());
+
+ factory DateAndTime.fromJson(String source) =>
+ DateAndTime.fromMap(json.decode(source));
+
+ @override
+ String toString() => 'DateAndTime(date: $date, time: $time)';
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(this, other)) return true;
+
+ return other is DateAndTime && other.date == date && other.time == time;
+ }
+
+ @override
+ int get hashCode => date.hashCode ^ time.hashCode;
+}
diff --git a/lib/data/models/hybrid.dart b/lib/data/models/hybrid.dart
new file mode 100644
index 0000000..d567f14
--- /dev/null
+++ b/lib/data/models/hybrid.dart
@@ -0,0 +1,98 @@
+enum HybridState {
+ idle,
+ engineOutput,
+ regenerativeBreaking,
+ baterryOutput,
+}
+
+enum ArrowState { blue, red, green, yellow }
+
+enum BatteryState { white, red, green, yellow, orange }
+
+class Hybrid {
+ final HybridState hybridState;
+ final ArrowState topArrowState;
+ final ArrowState leftArrowState;
+ final ArrowState rightArrowState;
+ final BatteryState batteryState;
+ Hybrid({
+ required this.hybridState,
+ required this.topArrowState,
+ required this.leftArrowState,
+ required this.rightArrowState,
+ required this.batteryState,
+ });
+
+ const Hybrid.initial()
+ : hybridState = HybridState.idle,
+ topArrowState = ArrowState.blue,
+ leftArrowState = ArrowState.blue,
+ rightArrowState = ArrowState.blue,
+ batteryState = BatteryState.white;
+
+ Hybrid copyWith({
+ HybridState? hybridState,
+ ArrowState? topArrowState,
+ ArrowState? leftArrowState,
+ ArrowState? rightArrowState,
+ BatteryState? batteryState,
+ }) {
+ return Hybrid(
+ hybridState: hybridState ?? this.hybridState,
+ topArrowState: topArrowState ?? this.topArrowState,
+ leftArrowState: leftArrowState ?? this.leftArrowState,
+ rightArrowState: rightArrowState ?? this.rightArrowState,
+ batteryState: batteryState ?? this.batteryState,
+ );
+ }
+
+ // Map<String, dynamic> toMap() {
+ // return {
+ // 'hybridState': hybridState.toMap(),
+ // 'topArrowState': topArrowState.toMap(),
+ // 'leftArrowState': leftArrowState.toMap(),
+ // 'rightArrowState': rightArrowState.toMap(),
+ // 'batteryState': batteryState.toMap(),
+ // };
+ // }
+
+ // factory Hybrid.fromMap(Map<String, dynamic> map) {
+ // return Hybrid(
+ // hybridState: HybridState.fromMap(map['hybridState']),
+ // topArrowState: ArrowState.fromMap(map['topArrowState']),
+ // leftArrowState: ArrowState.fromMap(map['leftArrowState']),
+ // rightArrowState: ArrowState.fromMap(map['rightArrowState']),
+ // batteryState: BatteryState.fromMap(map['batteryState']),
+ // );
+ // }
+
+ // String toJson() => json.encode(toMap());
+
+ // factory Hybrid.fromJson(String source) => Hybrid.fromMap(json.decode(source));
+
+ @override
+ String toString() {
+ return 'Hybrid(hybridState: $hybridState, topArrowState: $topArrowState, leftArrowState: $leftArrowState, rightArrowState: $rightArrowState, batteryState: $batteryState)';
+ }
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(this, other)) return true;
+
+ return other is Hybrid &&
+ other.hybridState == hybridState &&
+ other.topArrowState == topArrowState &&
+ other.leftArrowState == leftArrowState &&
+ other.rightArrowState == rightArrowState &&
+ other.batteryState == batteryState;
+ }
+
+ @override
+ int get hashCode {
+ return hybridState.hashCode ^
+ topArrowState.hashCode ^
+ leftArrowState.hashCode ^
+ rightArrowState.hashCode ^
+ batteryState.hashCode;
+ }
+}
diff --git a/lib/data/models/units.dart b/lib/data/models/units.dart
new file mode 100644
index 0000000..9e71213
--- /dev/null
+++ b/lib/data/models/units.dart
@@ -0,0 +1,45 @@
+import '../../export.dart';
+
+enum DistanceUnit { kilometers, miles }
+
+enum TemperatureUnit { celsius, fahrenheit }
+
+@immutable
+class Units {
+ final DistanceUnit distanceUnit;
+ final TemperatureUnit temperatureUnit;
+
+ const Units(
+ this.distanceUnit,
+ this.temperatureUnit,
+ );
+ const Units.initial()
+ : distanceUnit = DistanceUnit.kilometers,
+ temperatureUnit = TemperatureUnit.celsius;
+
+ Units copyWith({
+ DistanceUnit? distanceUnit,
+ TemperatureUnit? temperatureUnit,
+ }) {
+ return Units(
+ distanceUnit ?? this.distanceUnit,
+ temperatureUnit ?? this.temperatureUnit,
+ );
+ }
+
+ @override
+ String toString() =>
+ 'Units(distanceUnit: $distanceUnit, temperatureUnit: $temperatureUnit)';
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(this, other)) return true;
+
+ return other is Units &&
+ other.distanceUnit == distanceUnit &&
+ other.temperatureUnit == temperatureUnit;
+ }
+
+ @override
+ int get hashCode => distanceUnit.hashCode ^ temperatureUnit.hashCode;
+}
diff --git a/lib/data/models/user.dart b/lib/data/models/user.dart
new file mode 100644
index 0000000..b163c5e
--- /dev/null
+++ b/lib/data/models/user.dart
@@ -0,0 +1,54 @@
+import 'dart:convert';
+
+import 'package:flutter_ics_homescreen/export.dart';
+
+@immutable
+class User {
+ final String id;
+ final String name;
+ const User({
+ required this.id,
+ required this.name,
+ });
+
+ User copyWith({
+ String? id,
+ String? name,
+ }) {
+ return User(
+ id: id ?? this.id,
+ name: name ?? this.name,
+ );
+ }
+
+ Map<String, dynamic> toMap() {
+ return {
+ 'id': id,
+ 'name': name,
+ };
+ }
+
+ factory User.fromMap(Map<String, dynamic> map) {
+ return User(
+ id: map['id'] ?? '',
+ name: map['name'] ?? '',
+ );
+ }
+
+ String toJson() => json.encode(toMap());
+
+ factory User.fromJson(String source) => User.fromMap(json.decode(source));
+
+ @override
+ String toString() => 'User(id: $id, name: $name)';
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(this, other)) return true;
+
+ return other is User && other.id == id && other.name == name;
+ }
+
+ @override
+ int get hashCode => id.hashCode ^ name.hashCode;
+}
diff --git a/lib/data/models/users.dart b/lib/data/models/users.dart
new file mode 100644
index 0000000..9b4d027
--- /dev/null
+++ b/lib/data/models/users.dart
@@ -0,0 +1,64 @@
+import 'dart:convert';
+
+import 'package:flutter_ics_homescreen/data/models/user.dart';
+import 'package:flutter_ics_homescreen/export.dart';
+// ignore: depend_on_referenced_packages
+import 'package:collection/collection.dart';
+
+@immutable
+class Users {
+ final List<User> users;
+ final User selectedUser;
+ const Users({
+ required this.users,
+ required this.selectedUser,
+ });
+ Users.initial()
+ //: users = <User>[],
+ : users = [],
+ selectedUser = const User(id: '', name: '');
+
+ Users copyWith({
+ List<User>? users,
+ User? selectedUser,
+ }) {
+ return Users(
+ users: users ?? this.users,
+ selectedUser: selectedUser ?? this.selectedUser,
+ );
+ }
+
+ Map<String, dynamic> toMap() {
+ return {
+ 'users': users.map((x) => x.toMap()).toList(),
+ 'selectedUser': selectedUser.toMap(),
+ };
+ }
+
+ factory Users.fromMap(Map<String, dynamic> map) {
+ return Users(
+ users: List<User>.from(map['users']?.map((x) => User.fromMap(x))),
+ selectedUser: User.fromMap(map['selectedUser']),
+ );
+ }
+
+ String toJson() => json.encode(toMap());
+
+ factory Users.fromJson(String source) => Users.fromMap(json.decode(source));
+
+ @override
+ String toString() => 'Users(users: $users, selectedUser: $selectedUser)';
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(this, other)) return true;
+ final listEquals = const DeepCollectionEquality().equals;
+
+ return other is Users &&
+ listEquals(other.users, users) &&
+ other.selectedUser == selectedUser;
+ }
+
+ @override
+ int get hashCode => users.hashCode ^ selectedUser.hashCode;
+}
diff --git a/lib/data/models/vehicle.dart b/lib/data/models/vehicle.dart
new file mode 100644
index 0000000..f27b750
--- /dev/null
+++ b/lib/data/models/vehicle.dart
@@ -0,0 +1,233 @@
+import 'dart:convert';
+
+import '../../export.dart';
+
+@immutable
+class Vehicle {
+ final double speed;
+ final double insideTemperature;
+ final double outsideTemperature;
+ final int range;
+ final double fuelLevel;
+ final int mediaVolume;
+ final bool isChildLockActiveLeft;
+ final bool isChildLockActiveRight;
+ final int engineSpeed;
+ final int frontLeftTire;
+ final int frontRightTire;
+ final int rearLeftTire;
+ final int rearRightTire;
+ final bool isAirConditioningActive;
+ final bool isFrontDefrosterActive;
+ final bool isRearDefrosterActive;
+ final bool isRecirculationActive;
+ final int fanSpeed;
+
+ const Vehicle(
+ this.speed,
+ this.insideTemperature,
+ this.outsideTemperature,
+ this.range,
+ this.fuelLevel,
+ this.mediaVolume,
+ this.isChildLockActiveLeft,
+ this.isChildLockActiveRight,
+ this.engineSpeed,
+ this.frontLeftTire,
+ this.frontRightTire,
+ this.rearLeftTire,
+ this.rearRightTire,
+ this.isAirConditioningActive,
+ this.isFrontDefrosterActive,
+ this.isRearDefrosterActive,
+ this.isRecirculationActive,
+ this.fanSpeed);
+
+ const Vehicle.initial()
+ : speed = 0,
+ insideTemperature = 0,
+ outsideTemperature = 0,
+ range = 0,
+ fuelLevel = 0,
+ mediaVolume = 50,
+ isChildLockActiveLeft = false,
+ isChildLockActiveRight = true,
+ engineSpeed = 0,
+ frontLeftTire = 33,
+ frontRightTire = 31,
+ rearLeftTire = 31,
+ rearRightTire = 32,
+ isAirConditioningActive = false,
+ isFrontDefrosterActive = false,
+ isRearDefrosterActive = false,
+ isRecirculationActive = false,
+ fanSpeed = 0;
+
+ const Vehicle.initialForDebug()
+ : speed = 60,
+ insideTemperature = 25,
+ outsideTemperature = 32.0,
+ range = 21,
+ fuelLevel = 49.5,
+ mediaVolume = 50,
+ isChildLockActiveLeft = false,
+ isChildLockActiveRight = true,
+ engineSpeed = 6500,
+ frontLeftTire = 33,
+ frontRightTire = 31,
+ rearLeftTire = 31,
+ rearRightTire = 32,
+ isAirConditioningActive = false,
+ isFrontDefrosterActive = false,
+ isRearDefrosterActive = false,
+ isRecirculationActive = false,
+ fanSpeed = 0;
+
+ Vehicle copyWith(
+ {double? speed,
+ double? insideTemperature,
+ double? outsideTemperature,
+ int? range,
+ double? fuelLevel,
+ int? mediaVolume,
+ bool? isChildLockActiveLeft,
+ bool? isChildLockActiveRight,
+ int? engineSpeed,
+ int? frontLeftTire,
+ int? frontRightTire,
+ int? rearLeftTire,
+ int? rearRightTire,
+ bool? isAirConditioningActive,
+ bool? isFrontDefrosterActive,
+ bool? isRearDefrosterActive,
+ bool? isRecirculationActive,
+ int? fanSpeed}) {
+ return Vehicle(
+ speed ?? this.speed,
+ insideTemperature ?? this.insideTemperature,
+ outsideTemperature ?? this.outsideTemperature,
+ range ?? this.range,
+ fuelLevel ?? this.fuelLevel,
+ mediaVolume ?? this.mediaVolume,
+ isChildLockActiveLeft ?? this.isChildLockActiveLeft,
+ isChildLockActiveRight ?? this.isChildLockActiveRight,
+ engineSpeed ?? this.engineSpeed,
+ frontLeftTire ?? this.frontLeftTire,
+ frontRightTire ?? this.frontRightTire,
+ rearLeftTire ?? this.rearLeftTire,
+ rearRightTire ?? this.rearRightTire,
+ isAirConditioningActive ?? this.isAirConditioningActive,
+ isFrontDefrosterActive ?? this.isFrontDefrosterActive,
+ isRearDefrosterActive ?? this.isRearDefrosterActive,
+ isRecirculationActive ?? this.isRecirculationActive,
+ fanSpeed ?? this.fanSpeed);
+ }
+
+ Map<String, dynamic> toMap() {
+ return {
+ 'speed': speed,
+ 'insideTemperature': insideTemperature,
+ 'outsideTemperature': outsideTemperature,
+ 'range': range,
+ 'fuelLevel': fuelLevel,
+ 'mediaVolume': mediaVolume,
+ 'isChildLockActiveLeft': isChildLockActiveLeft,
+ 'isChildLockActiveRight': isChildLockActiveRight,
+ 'engineSpeed': engineSpeed,
+ 'frontLeftTire': frontLeftTire,
+ 'frontRightTire': frontRightTire,
+ 'rearLeftTire': rearLeftTire,
+ 'rearRightTire': rearRightTire,
+ 'isAirConditioningActive': isAirConditioningActive,
+ 'isFrontDefrosterActive': isFrontDefrosterActive,
+ 'isRearDefrosterActive': isRearDefrosterActive,
+ 'isRecirculationActive': isRecirculationActive,
+ 'fanSpeed': fanSpeed
+ };
+ }
+
+ factory Vehicle.fromMap(Map<String, dynamic> map) {
+ return Vehicle(
+ map['speed']?.toDouble() ?? 0.0,
+ map['insideTemperature']?.toDouble() ?? 0.0,
+ map['outsideTemperature']?.toDouble() ?? 0.0,
+ map['range']?.toInt() ?? 0,
+ map['fuelLevel']?.toDouble() ?? 0.0,
+ map['mediaVolume']?.toInt() ?? 0,
+ map['isChildLockActiveLeft'] ?? false,
+ map['isChildLockActiveRight'] ?? false,
+ map['engineSpeed']?.toInt() ?? 0,
+ map['frontLeftTire']?.toInt() ?? 0,
+ map['frontRightTire']?.toInt() ?? 0,
+ map['rearLeftTire']?.toInt() ?? 0,
+ map['rearRightTire']?.toInt() ?? 0,
+ map['isAirConditioningActive'] ?? false,
+ map['isFrontDefrosterActive'] ?? false,
+ map['isRearDefrosterActive'] ?? false,
+ map['isRecirculationActive'] ?? false,
+ map['fanSpeed'] ?? 0,
+ );
+ }
+
+ String toJson() => json.encode(toMap());
+
+ factory Vehicle.fromJson(String source) =>
+ Vehicle.fromMap(json.decode(source));
+
+ @override
+ String toString() {
+ return 'Vehicle(speed: $speed, insideTemperature: $insideTemperature, outsideTemperature: $outsideTemperature, range: $range, fuelLevel: $fuelLevel, mediaVolume: $mediaVolume, isChildLockActiveLeft: $isChildLockActiveLeft, isChildLockActiveRight: $isChildLockActiveRight, engineSpeed: $engineSpeed, frontLeftTire: $frontLeftTire, frontRightTire: $frontRightTire, rearLeftTire: $rearLeftTire, rearRightTire: $rearRightTire, isAirConditioningActive: $isAirConditioningActive, isFrontDefrosterActive: $isFrontDefrosterActive, isRearDefrosterActive: $isRearDefrosterActive, isRecirculationActive: $isRecirculationActive,fanSpeed:$fanSpeed)';
+ }
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(this, other)) return true;
+
+ return other is Vehicle &&
+ other.speed == speed &&
+ other.insideTemperature == insideTemperature &&
+ other.outsideTemperature == outsideTemperature &&
+ other.range == range &&
+ other.fuelLevel == fuelLevel &&
+ other.mediaVolume == mediaVolume &&
+ other.isChildLockActiveLeft == isChildLockActiveLeft &&
+ other.isChildLockActiveRight == isChildLockActiveRight &&
+ other.engineSpeed == engineSpeed &&
+ other.frontLeftTire == frontLeftTire &&
+ other.frontRightTire == frontRightTire &&
+ other.rearLeftTire == rearLeftTire &&
+ other.rearRightTire == rearRightTire &&
+ other.isAirConditioningActive == isAirConditioningActive &&
+ other.isFrontDefrosterActive == isFrontDefrosterActive &&
+ other.isRearDefrosterActive == isRearDefrosterActive &&
+ other.isRecirculationActive == isRecirculationActive &&
+ other.fanSpeed == fanSpeed;
+ }
+
+ @override
+ int get hashCode {
+ return speed.hashCode ^
+ insideTemperature.hashCode ^
+ outsideTemperature.hashCode ^
+ range.hashCode ^
+ fuelLevel.hashCode ^
+ mediaVolume.hashCode ^
+ isChildLockActiveLeft.hashCode ^
+ isChildLockActiveRight.hashCode ^
+ engineSpeed.hashCode ^
+ frontLeftTire.hashCode ^
+ frontRightTire.hashCode ^
+ rearLeftTire.hashCode ^
+ rearRightTire.hashCode ^
+ isAirConditioningActive.hashCode ^
+ isFrontDefrosterActive.hashCode ^
+ isRearDefrosterActive.hashCode ^
+ isRecirculationActive.hashCode ^
+ fanSpeed.hashCode;
+ }
+// }
+// / class VehicleNotifier extends StateNotifier<Vehicle> {
+// // VehicleNotifier() : super(Vehicle());
+
+// // }
+}
diff --git a/lib/data/theme/theme.dart b/lib/data/theme/theme.dart
new file mode 100644
index 0000000..a04d03d
--- /dev/null
+++ b/lib/data/theme/theme.dart
@@ -0,0 +1,43 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+// ignore_for_file: overridden_fields
+
+ThemeData theme = ThemeData(
+ scaffoldBackgroundColor: const Color(0xFF0D113F),
+ useMaterial3: false,
+ fontFamily: GoogleFonts.firaSans().fontFamily,
+ // Define the default brightness and colors.
+ colorScheme: ColorScheme.fromSeed(
+ seedColor: Colors.blue,
+ // ···
+ brightness: Brightness.dark,
+ ),
+
+ // Define the default `TextTheme`. Use this to specify the default
+ // text styling for headlines, titles, bodies of text, and more.
+ textTheme: TextTheme(
+
+ displayLarge: const TextStyle(
+ fontSize: 72,
+ fontWeight: FontWeight.bold,
+
+ ),
+ // ···
+ titleLarge: GoogleFonts.oswald(
+ fontSize: 30,
+ fontStyle: FontStyle.italic,
+ color: Colors.red
+ ),
+
+ titleMedium: GoogleFonts.firaSans(
+ color: AGLDemoColors.periwinkleColor, fontSize: 40),
+ bodyMedium: GoogleFonts.firaSans(color: AGLDemoColors.periwinkleColor),
+
+
+ ),
+ appBarTheme: const AppBarTheme(
+ backgroundColor: Colors.blue,
+ foregroundColor: Colors.white, //here you can give the text color
+ titleTextStyle: TextStyle()
+ ),
+);
diff --git a/lib/export.dart b/lib/export.dart
new file mode 100644
index 0000000..08dff4f
--- /dev/null
+++ b/lib/export.dart
@@ -0,0 +1,101 @@
+export 'data/data_providers/app.dart';
+export 'data/data_providers/app_provider.dart';
+export 'presentation/router/routes/routes.dart';
+export 'data/data_providers/vss_provider.dart';
+export 'data/theme/theme.dart';
+
+//Models
+export 'data/models/vehicle.dart';
+export 'data/models/units.dart';
+export 'data/models/audio.dart';
+export 'data/models/connections_signals.dart';
+export 'data/models/hybrid.dart';
+
+//Screens
+export 'presentation/screens/home/home.dart';
+export 'presentation/screens/home/widgets/custom_tile.dart';
+export 'presentation/screens/dashboard/dashboard.dart';
+export 'presentation/screens/dashboard/widgets/hybrid/hybrid.dart';
+export 'presentation/screens/dashboard/widgets/car_status.dart';
+export 'presentation/screens/dashboard/widgets/range.dart';
+export 'presentation/screens/dashboard/widgets/temperature.dart';
+export 'presentation/screens/dashboard/widgets/circle_indicator.dart';
+export 'presentation/screens/dashboard/widgets/child_lock.dart';
+export 'presentation/screens/dashboard/widgets/hybrid_mode.dart';
+export 'presentation/common_widget/custom_bottom_bar.dart';
+export 'presentation/common_widget/custom_top_bar.dart';
+export 'presentation/screens/media_player/media_player.dart';
+export 'presentation/screens/hvac/hvac.dart';
+export 'presentation/screens/settings/settings.dart';
+export 'presentation/screens/settings/widgets/settings_list_tile.dart';
+export 'presentation/screens/settings/settings_screens/date_time/date_time_screen.dart';
+export 'presentation/screens/settings/settings_screens/bluetooth/bluetooth_screen.dart';
+export 'presentation/screens/settings/settings_screens/wifi/wifi_screen.dart';
+export 'presentation/screens/settings/settings_screens/wired/wired_screen.dart';
+export 'presentation/screens/settings/settings_screens/audio_settings/audio_settings_screen.dart';
+export 'presentation/screens/settings/settings_screens/profiles/profiles_screen.dart';
+export 'presentation/screens/settings/settings_screens/units/units_screen.dart';
+export 'presentation/screens/settings/settings_screens/version_info/version_info_screend.dart';
+export 'presentation/screens/settings/settings_screens/units/distance/distance_unit_screen.dart';
+export 'presentation/screens/settings/settings_screens/units/temperature/temperature_unit_screen.dart';
+export 'package:flutter_ics_homescreen/presentation/screens/settings/settings_screens/profiles/widgets/new_profile_screen.dart';
+
+export 'presentation/screens/apps/apps.dart';
+export 'presentation/screens/splash/splash.dart';
+export 'presentation/screens/splash/widget/splash_content.dart';
+//export 'presentation/screens/apps/apps_content.dart';
+export 'presentation/screens/hvac/hvac_content.dart';
+export 'presentation/screens/media_player/media_controls.dart';
+export 'presentation/screens/media_player/play_list_table.dart';
+export 'presentation/screens/media_player/player_navigation.dart';
+export 'presentation/screens/media_player/segmented_buttons.dart';
+export 'presentation/screens/media_player/media_content.dart';
+export 'presentation/screens/hvac/widgets/climate_controls.dart';
+export 'presentation/screens/hvac/widgets/fan_focus.dart';
+export 'presentation/screens/hvac/widgets/fan_speed_controls.dart';
+export 'presentation/screens/hvac/widgets/temperature_control.dart';
+export 'presentation/common_widget/custom_title.dart';
+export 'presentation/screens/weather/weather.dart';
+export 'presentation/screens/weather/hourly_forecast.dart';
+export 'presentation/screens/clock/clock.dart';
+
+export 'core/utils/widgets/back_button.dart';
+export 'core/constants/vss_path.dart';
+export 'core/constants/val_client_helper.dart';
+export 'core/constants/constants.dart';
+export 'core/constants/paths.dart';
+//Common widgets
+export 'presentation/common_widget/settings_top_bar.dart';
+export 'presentation/common_widget/generic_button.dart';
+
+//Packages
+export 'package:flow_builder/flow_builder.dart';
+export 'package:flutter_riverpod/flutter_riverpod.dart';
+export 'package:google_fonts/google_fonts.dart';
+export 'package:flutter_analog_clock/flutter_analog_clock.dart';
+export 'package:yaml/yaml.dart';
+export 'package:lottie/lottie.dart';
+//export 'package:new_virtual_keyboard/virtual_keyboard.dart';
+
+
+//export 'package:intl/intl.dart';
+
+//export 'package:protos/protos.dart';
+
+//other
+export 'dart:typed_data';
+export 'dart:io';
+
+export 'package:flutter/material.dart';
+export 'package:flutter_svg/svg.dart';
+export 'package:flutter_ics_homescreen/core/constants/colors.dart';
+export 'package:flutter_ics_homescreen/presentation/screens/hvac/widgets/semi_circle_painter.dart';
+export 'package:flutter_ics_homescreen/presentation/common_widget/volume_and_fan_control.dart';
+
+
+
+//proto
+
+
+// export 'l10n/l10n.dart';
+// export 'package:flutter_gen/gen_l10n/app_localizations.dart';
diff --git a/lib/main.dart b/lib/main.dart
new file mode 100644
index 0000000..ec5a5d0
--- /dev/null
+++ b/lib/main.dart
@@ -0,0 +1,15 @@
+import 'package:device_preview/device_preview.dart';
+
+import 'export.dart';
+
+void main() async {
+ WidgetsFlutterBinding.ensureInitialized();
+ // MediaKit.ensureInitialized(); //replace with lottie
+ runApp(DevicePreview(
+ enabled: false, // Chnage to false to disable device preview
+ tools: const [
+ ...DevicePreview.defaultTools,
+ ],
+ builder: (context) => const App(),
+ ));
+}
diff --git a/lib/presentation/common_widget/custom_bottom_bar.dart b/lib/presentation/common_widget/custom_bottom_bar.dart
new file mode 100644
index 0000000..13084c0
--- /dev/null
+++ b/lib/presentation/common_widget/custom_bottom_bar.dart
@@ -0,0 +1,211 @@
+// ignore_for_file: prefer_const_constructors
+
+import '../../export.dart';
+
+class CustomBottomBar extends ConsumerStatefulWidget {
+ const CustomBottomBar({super.key});
+
+ @override
+ CustomBottomBarState createState() => CustomBottomBarState();
+}
+
+class CustomBottomBarState extends ConsumerState<CustomBottomBar> {
+ @override
+ void initState() {
+ super.initState();
+ // "ref" can be used in all life-cycles of a StatefulWidget.
+ //ref.read(counterProvider);
+ }
+
+ double iconSize = 57;
+ List<BottomBarItems> navItems = [
+ BottomBarItems(title: "Home", image: "Dashboard"),
+ BottomBarItems(title: "HVAC", image: "HVAC"),
+ BottomBarItems(title: "Media", image: "MediaPlayer"),
+ BottomBarItems(title: "Settings", image: "Settings"),
+ BottomBarItems(title: "Apps", image: "Apps")
+ ];
+ String selectedNav = "Home";
+
+ void _onItemTapped(String title) {
+ AppState status = AppState.dashboard;
+ switch (title) {
+ case "Home":
+ status = AppState.dashboard;
+ case "HVAC":
+ status = AppState.hvac;
+ case "Media":
+ status = AppState.mediaPlayer;
+ case "Settings":
+ status = AppState.settings;
+ case "Apps":
+ status = AppState.apps;
+ }
+ setState(() {
+ selectedNav = title;
+ });
+
+ ref.read(appProvider.notifier).update((state) => state = status);
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Padding(
+ padding: const EdgeInsets.all(24.0),
+ child: Row(
+ children: navItems
+ .map((e) => Expanded(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Container(
+
+ margin: const EdgeInsets.symmetric(
+ horizontal: 2,
+ ),
+ decoration: BoxDecoration(
+ gradient: LinearGradient(
+ colors: [
+ selectedNav == e.title
+ ? Color.fromARGB(217, 41, 98, 255)
+ : Color.fromARGB(163, 28, 46, 146),
+ selectedNav == e.title
+ ? Color.fromARGB(0, 41, 98, 255)
+ : Color.fromARGB(0, 41, 98, 255),
+ ],
+ stops: [
+ selectedNav == e.title ? 0.3 : 0,
+ selectedNav == e.title ? 1 : 0.8,
+ ],
+ begin: Alignment.bottomCenter,
+ end: Alignment.topCenter),
+ // color: selectedNav == e
+ // ? AGLDemoColors.neonBlueColor
+ // : AGLDemoColors.buttonFillEnabledColor,
+ border: Border(
+ bottom: const BorderSide(
+ width: 1.0,
+ color: AGLDemoColors.jordyBlueColor),
+ ),
+ ),
+ child: Material(
+ color: Colors.transparent,
+ child: InkWell(
+ onTap: () {
+ _onItemTapped(e.title);
+ },
+ child: Container(
+ padding: const EdgeInsets.symmetric(vertical: 7),
+ decoration: BoxDecoration(
+ border: Border(
+ left: selectedNav == e.title
+ ? const BorderSide(color: Colors.white30)
+ : BorderSide.none,
+ right: selectedNav == e.title
+ ? const BorderSide(color: Colors.white30)
+ : BorderSide.none,
+ // bottom: BorderSide(
+ // color: selectedNav == e.title
+ // ? Colors.white
+ // : Colors.white24,
+ // width:
+ // selectedNav == e.title ? 2 : 1)
+ )),
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ SvgPicture.asset(
+ "assets/${e.image}${selectedNav == e.title ? "Selected" : ""}.svg",
+ width: iconSize,
+ height: iconSize,
+ ),
+ Text(
+ e.title,
+ textAlign: TextAlign.center,
+ style: TextStyle(
+ fontSize: 26,
+ shadows: [
+ Shadow(
+ color:
+ Colors.black.withOpacity(0.7),
+ offset: Offset(
+ 1,
+ e.title == selectedNav
+ ? 1.5
+ : 3),
+ blurRadius: e.title == selectedNav
+ ? 1
+ : 3)
+ ],
+ color: e.title == selectedNav
+ ? Colors.white
+ : AGLDemoColors.periwinkleColor,
+ fontWeight: selectedNav == e.title
+ ? FontWeight.bold
+ : FontWeight.w300),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ ),
+ //if (selectedNav == e.title)
+ Container(
+ margin: const EdgeInsets.symmetric(horizontal: 2),
+ color: selectedNav == e.title
+ ? Colors.white
+ : Colors.transparent,
+ height: 3,
+ )
+ ],
+ )))
+ .toList()),
+ );
+
+ // return Container(
+ // // decoration: const BoxDecoration(
+ // // gradient: LinearGradient(
+ // // begin: Alignment.topCenter,
+ // // end: Alignment.bottomCenter,
+ // // stops: [0.01, 1],
+ // // colors: <Color>[Colors.black, Color(0xFF1A237E)],
+ // // ),
+ // // ),
+ // //color: Color(0xFF0D113F),
+ // child: BottomNavigationBar(
+ // elevation: 0,
+ // showSelectedLabels: true,
+ // showUnselectedLabels: true,
+ // //backgroundColor: Colors.white,
+ // backgroundColor: const Color(0xFF0D113F),
+ // type: BottomNavigationBarType.fixed,
+ // items: const <BottomNavigationBarItem>[
+ // BottomNavigationBarItem(
+ // icon: Icon(Icons.directions_car),
+ // label: 'Home',
+ // backgroundColor: Color(0xFF0D113F)),
+ // BottomNavigationBarItem(icon: Icon(Icons.ac_unit), label: 'HVAC'),
+ // BottomNavigationBarItem(
+ // icon: Icon(Icons.library_music), label: 'Media'),
+ // BottomNavigationBarItem(
+ // icon: Icon(Icons.settings), label: 'Settings'),
+ // BottomNavigationBarItem(icon: Icon(Icons.apps), label: 'Apps'),
+ // ],
+ // currentIndex: _selectedIndex,
+ // selectedItemColor: Colors.white,
+ // unselectedItemColor: Colors.grey,
+
+ // onTap: _onItemTapped,
+ // ),
+ // );
+ }
+}
+
+class BottomBarItems {
+ final String title;
+ final String image;
+
+ BottomBarItems({required this.title, required this.image});
+}
diff --git a/lib/presentation/common_widget/custom_title.dart b/lib/presentation/common_widget/custom_title.dart
new file mode 100644
index 0000000..f60c11e
--- /dev/null
+++ b/lib/presentation/common_widget/custom_title.dart
@@ -0,0 +1,103 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+class CommonTitle extends StatelessWidget {
+ const CommonTitle(
+ {super.key,
+ required this.title,
+ this.hasBackButton = false,
+ this.onPressed});
+
+ final String title;
+ final bool? hasBackButton;
+ final VoidCallback? onPressed;
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Padding(
+ padding: const EdgeInsets.only(top: 80),
+ child: SizedBox(
+ //color: Colors.amber,
+ height: 120,
+ child: Stack(
+ fit: StackFit.expand,
+ children: [
+ Container(
+ decoration: BoxDecoration(
+ gradient: LinearGradient(
+ begin: Alignment.bottomCenter,
+ end: Alignment.center,
+ colors: [
+ AGLDemoColors.jordyBlueColor.withOpacity(0.2),
+ AGLDemoColors.jordyBlueColor.withOpacity(0)
+ ],
+ stops: const [
+ 0.0,
+ 1
+ ])),
+ alignment: Alignment.center,
+ child: Text(
+ title,
+ textAlign: TextAlign.center,
+ style: const TextStyle(
+ color: Colors.white,
+ fontSize: 40,
+ fontWeight: FontWeight.w500),
+ ),
+ ),
+ if (hasBackButton!)
+ Align(
+ alignment: AlignmentDirectional.centerStart,
+ child: Padding(
+ padding: const EdgeInsets.only(left: 20.0),
+ child: InkWell(
+ customBorder: const CircleBorder(),
+ onTap: onPressed,
+ child: const Icon(
+ Icons.arrow_back,
+ color: Colors.white,
+ size: 48,
+ )),
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ Container(
+ height: 2,
+ decoration: BoxDecoration(
+ gradient: const LinearGradient(
+ begin: Alignment.centerLeft,
+ end: Alignment.centerRight,
+ colors: [
+ Colors.white10,
+ AGLDemoColors.jordyBlueColor,
+ Colors.white10
+ ],
+ ),
+ boxShadow: [
+ BoxShadow(
+ color: Colors.black.withOpacity(0.5),
+ blurRadius: 6,
+ spreadRadius: 3,
+ offset: const Offset(0, 6),
+ ),
+ ],
+ )),
+ Container(
+ height: 48,
+ decoration: BoxDecoration(
+ gradient: LinearGradient(
+ begin: Alignment.topCenter,
+ end: Alignment.bottomCenter,
+ colors: [Colors.black, Colors.black.withOpacity(0.0)],
+ ),
+ ),
+ )
+ ],
+ );
+ }
+}
diff --git a/lib/presentation/common_widget/custom_top_bar.dart b/lib/presentation/common_widget/custom_top_bar.dart
new file mode 100644
index 0000000..c268f53
--- /dev/null
+++ b/lib/presentation/common_widget/custom_top_bar.dart
@@ -0,0 +1,106 @@
+import 'package:intl/intl.dart';
+
+import '../../export.dart';
+
+class CustomTopBar extends ConsumerStatefulWidget
+ implements PreferredSizeWidget {
+ const CustomTopBar({super.key});
+
+ @override
+ CustomTopBarState createState() => CustomTopBarState();
+
+ @override
+ Size get preferredSize => const Size.fromHeight(80);
+}
+
+class CustomTopBarState extends ConsumerState<CustomTopBar> {
+ @override
+ Widget build(BuildContext context) {
+ final singnalsConnection =
+ ref.watch(signalsProvider.select((sinals) => sinals));
+ final user = ref.watch(usersProvider.select((user) => user));
+ final time2 =
+ ref.watch(dateTimeStateProvider.select((dateTime) => dateTime));
+
+ DateFormat dateFormat = DateFormat('HH:mm');
+ //var time = dateFormat.format(DateTime.now());
+ var time = time2.time;
+
+ return AppBar(
+ elevation: 0,
+ backgroundColor: Colors.transparent,
+ //leadingWidth: 100,
+
+ title: Stack(
+ //mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Positioned.fill(
+ child: Align(
+ alignment: Alignment.centerLeft,
+ child: Wrap(
+ children: [
+ RichText(
+ text: TextSpan(
+ text: '$time ',
+ style: const TextStyle(color: Colors.white, fontSize: 26),
+ children: <InlineSpan>[
+ const WidgetSpan(
+ child: SizedBox(width: 16), // 16px space
+ ),
+ TextSpan(
+ text: user.selectedUser.name,
+ style: const TextStyle(fontWeight: FontWeight.bold),
+ ),
+ ],
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ Align(
+ alignment: Alignment.center,
+ child: Image.asset(
+ 'assets/topBarLogo.png',
+ width: 659,
+ height: 56,
+ ),
+ ),
+ Positioned.fill(
+ child: Align(
+ alignment: Alignment.centerRight,
+ child: Wrap(
+ children: [
+ Icon(
+ singnalsConnection.isBluetoothConnected
+ ? Icons.bluetooth
+ : Icons.bluetooth_disabled,
+ size: 24,
+ ),
+ const SizedBox(
+ width: 24,
+ ),
+ const Icon(
+ Icons.signal_cellular_4_bar_outlined,
+ size: 24,
+ ),
+ const SizedBox(
+ width: 24,
+ ),
+ Icon(
+ singnalsConnection.isWifiConnected
+ ? Icons.wifi
+ : Icons.wifi_off,
+ size: 24,
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ ),
+
+ // ),
+ );
+ }
+}
diff --git a/lib/presentation/common_widget/fan_bar.dart b/lib/presentation/common_widget/fan_bar.dart
new file mode 100644
index 0000000..e119089
--- /dev/null
+++ b/lib/presentation/common_widget/fan_bar.dart
@@ -0,0 +1,188 @@
+import '../../export.dart';
+import 'package:flutter_ics_homescreen/presentation/custom_icons/custom_icons.dart';
+
+enum FanMode { off, min, medium, max }
+
+class FanBar extends ConsumerStatefulWidget {
+ const FanBar({super.key});
+
+ @override
+ FanBarState createState() => FanBarState();
+}
+
+class FanBarState extends ConsumerState<FanBar> {
+ int selectedFanSpeed = 0;
+
+ @override
+ Widget build(BuildContext context) {
+ final vehicle = ref.watch(vehicleProvider.select((vehicle) => vehicle));
+ selectedFanSpeed = vehicle.fanSpeed;
+
+ return Column(children: [
+ Container(
+ padding: EdgeInsets.zero,
+ //width: 80,
+ height: 256,
+ decoration: const ShapeDecoration(
+ // gradient: RadialGradient(
+ // colors: [Color.fromARGB(255, 19, 24, 75), Colors.black],
+ // stops: [0, 0.9],
+ // radius: 1,
+ // ),
+ color: AGLDemoColors.buttonFillEnabledColor,
+ shape: StadiumBorder(
+ side: BorderSide(
+ color: Color(0xFF5477D4),
+ width: 1,
+ )),
+ ),
+ //alignment: Alignment.topLeft,
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: [
+ Material(
+ color: Colors.transparent,
+ child: SizedBox(
+ width: 80,
+ height: 64,
+ child: IconButton(
+ isSelected: selectedFanSpeed == 3,
+ padding: EdgeInsets.zero,
+ color: AGLDemoColors.periwinkleColor,
+ onPressed: () {
+ ref.read(vehicleProvider.notifier).updateFanSpeed(3);
+ },
+ icon: selectedFanSpeed == 3
+ ? Stack(
+ alignment: Alignment.center,
+ children: [
+ SvgPicture.asset('assets/fanButtonBg.svg'),
+ const Icon(
+ CustomIcons.fan_on_enabled,
+ color: Colors.white,
+ size: 40,
+ ),
+ ],
+ )
+ : const Icon(
+ CustomIcons.fan_on_enabled,
+ size: 40,
+ ),
+ ),
+ ),
+ ),
+ Material(
+ color: Colors.transparent,
+ child: SizedBox(
+ width: 64,
+ height: 64,
+ child: IconButton(
+ isSelected: selectedFanSpeed == 2,
+ padding: EdgeInsets.zero,
+ color: AGLDemoColors.periwinkleColor,
+ onPressed: () {
+ ref.read(vehicleProvider.notifier).updateFanSpeed(2);
+ },
+ icon: selectedFanSpeed == 2
+ ? Stack(
+ alignment: Alignment.center,
+ children: [
+ SvgPicture.asset('assets/fanButtonBg.svg'),
+ const Icon(
+ CustomIcons.fan_on_enabled,
+ color: Colors.white,
+ size: 28,
+ ),
+ ],
+ )
+ : const Icon(
+ CustomIcons.fan_on_enabled,
+ size: 28,
+ ),
+ ),
+ ),
+ ),
+ Material(
+ color: Colors.transparent,
+ child: SizedBox(
+ width: 64,
+ height: 64,
+ child: IconButton(
+ isSelected: selectedFanSpeed == 1,
+ iconSize: 20,
+ padding: EdgeInsets.zero,
+ color: AGLDemoColors.periwinkleColor,
+ onPressed: () {
+ ref.read(vehicleProvider.notifier).updateFanSpeed(1);
+ },
+ icon: selectedFanSpeed == 1
+ ? Stack(
+ alignment: Alignment.center,
+ children: [
+ SvgPicture.asset('assets/fanButtonBg.svg'),
+ const Icon(
+ CustomIcons.fan_on_enabled,
+ color: Colors.white,
+ size: 20,
+ ),
+ ],
+ )
+ : const Icon(
+ CustomIcons.fan_on_enabled,
+ size: 20,
+ ),
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ const SizedBox(height: 10),
+ Container(
+ width: 80,
+ height: 80,
+ decoration: const ShapeDecoration(
+ // gradient: RadialGradient(
+ // colors: [Color.fromARGB(255, 19, 24, 75), Colors.black],
+ // stops: [0, 0.9],
+ // radius: 1,
+ // ),
+ color: AGLDemoColors.buttonFillEnabledColor,
+ shape: StadiumBorder(
+ side: BorderSide(
+ color: Color(0xFF5477D4),
+ width: 1,
+ )),
+ ),
+ //alignment: Alignment.topLeft,
+ child: Material(
+ color: Colors.transparent,
+ child: IconButton(
+ isSelected: selectedFanSpeed == 0,
+ padding: EdgeInsets.zero,
+ color: AGLDemoColors.periwinkleColor,
+ onPressed: () {
+ ref.read(vehicleProvider.notifier).updateFanSpeed(0);
+ },
+ icon: selectedFanSpeed == 0
+ ? Stack(
+ alignment: Alignment.center,
+ children: [
+ SvgPicture.asset('assets/fanButtonBg.svg'),
+ const Icon(
+ Icons.mode_fan_off,
+ color: Colors.white,
+ size: 28.4,
+ ),
+ ],
+ )
+ : const Icon(
+ Icons.mode_fan_off,
+ size: 28.4,
+ ),
+ ),
+ )),
+ ]);
+ }
+}
diff --git a/lib/presentation/common_widget/generic_button.dart b/lib/presentation/common_widget/generic_button.dart
new file mode 100644
index 0000000..cca354f
--- /dev/null
+++ b/lib/presentation/common_widget/generic_button.dart
@@ -0,0 +1,91 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+class GenericButton extends StatefulWidget {
+ final double heigth;
+ final double width;
+ final String text;
+ final Function onTap;
+
+ const GenericButton({
+ super.key,
+ required this.heigth,
+ required this.width,
+ required this.text,
+ required this.onTap,
+ });
+
+ @override
+ State<GenericButton> createState() => _GenericButtonState();
+}
+
+class _GenericButtonState extends State<GenericButton> {
+ LinearGradient gradientEnable1 = const LinearGradient(colors: <Color>[
+ Color(0xFF2962FF),
+ Color(0x802962FF),
+ ]);
+ LinearGradient gradientEnable2 = const LinearGradient(colors: <Color>[
+ Color(0xFF1A237E),
+ Color(0xFF141F64),
+ ]);
+ @override
+ Widget build(BuildContext context) {
+ return GestureDetector(
+ onTapDown: (details) {
+ setState(() {
+ gradientEnable1 = const LinearGradient(colors: <Color>[
+ Color(0x802962FF),
+ Color(0xFF2962FF),
+ ]);
+ gradientEnable2 = const LinearGradient(colors: <Color>[
+ Color(0xFF1A237E),
+ Color(0xFF1C2D92),
+ ]);
+ });
+ //change style
+ },
+ onTapUp: (details) {
+ setState(() {
+ gradientEnable1 = const LinearGradient(colors: <Color>[
+ Color(0xFF2962FF),
+ Color(0x802962FF),
+ ]);
+ gradientEnable2 = const LinearGradient(colors: <Color>[
+ Color(0xFF1A237E),
+ Color(0xFF141F64),
+ ]);
+ });
+ widget.onTap();
+ },
+ child: Container(
+ height: widget.heigth,
+ width: widget.width,
+ decoration: BoxDecoration(
+ gradient: Gradient.lerp(gradientEnable1, gradientEnable2, 0.5),
+ boxShadow: const [
+ BoxShadow(
+ color: Colors.black,
+ blurRadius: 2,
+ offset: Offset(0, 2), // Shadow position
+ ),
+ ],
+ border: Border.all(
+ color: const Color(0xFF285DF4),
+ width: 1,
+ ),
+ borderRadius: const BorderRadius.all(
+ Radius.circular(4),
+ ),
+ ),
+ child: Center(
+ child: Text(
+ widget.text,
+ style: const TextStyle(
+ color: Color(0xFFC1D8FF),
+ fontSize: 44,
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/common_widget/settings_top_bar.dart b/lib/presentation/common_widget/settings_top_bar.dart
new file mode 100644
index 0000000..fb4e953
--- /dev/null
+++ b/lib/presentation/common_widget/settings_top_bar.dart
@@ -0,0 +1,37 @@
+import '../../export.dart';
+
+class SettingsTopBar extends ConsumerStatefulWidget
+ implements PreferredSizeWidget {
+ final String title;
+ const SettingsTopBar(this.title, {super.key});
+
+ @override
+ SettingsTopBarState createState() => SettingsTopBarState();
+ @override
+ Size get preferredSize => const Size.fromHeight(50);
+}
+
+class SettingsTopBarState extends ConsumerState<SettingsTopBar> {
+ @override
+ Widget build(
+ BuildContext context,
+ ) {
+ return AppBar(
+ elevation: 0,
+ backgroundColor: const Color(0xFF0D113F),
+ leading: BackButton(
+ onPressed: () {
+ context.flow<AppState>().update((state) => AppState.settings);
+ },
+ ),
+ title: Text(
+ widget.title,
+ style: const TextStyle(
+ fontStyle: FontStyle.normal,
+ fontWeight: FontWeight.normal,
+ fontSize: 20),
+ ),
+ //centerTitle: true,
+ );
+ }
+}
diff --git a/lib/presentation/common_widget/volume_and_fan_control.dart b/lib/presentation/common_widget/volume_and_fan_control.dart
new file mode 100644
index 0000000..051e360
--- /dev/null
+++ b/lib/presentation/common_widget/volume_and_fan_control.dart
@@ -0,0 +1,36 @@
+import '../common_widget/volume_bar.dart';
+import '../common_widget/fan_bar.dart';
+
+import '../../export.dart';
+
+class VolumeFanControl extends ConsumerWidget {
+ const VolumeFanControl({
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ final state = ref.watch(appProvider);
+ final size = MediaQuery.of(context).size;
+ final gapSize = size.height * 0.06;
+
+ return Padding(
+ padding: const EdgeInsets.only(left: 10),
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Visibility.maintain(
+ visible: state == AppState.mediaPlayer ? false : true,
+ child: const VolumeBar()),
+ SizedBox(
+ height: gapSize,
+ ),
+ Visibility.maintain(
+ visible: state == AppState.hvac ? false : true,
+ child: const FanBar(),
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/common_widget/volume_bar.dart b/lib/presentation/common_widget/volume_bar.dart
new file mode 100644
index 0000000..a029698
--- /dev/null
+++ b/lib/presentation/common_widget/volume_bar.dart
@@ -0,0 +1,356 @@
+import 'package:flutter_ics_homescreen/presentation/custom_icons/custom_icons.dart';
+
+import '../../export.dart';
+
+class VolumeBar extends ConsumerStatefulWidget {
+ const VolumeBar({super.key});
+
+ @override
+ VolumeBarState createState() => VolumeBarState();
+}
+
+class VolumeBarState extends ConsumerState<VolumeBar> {
+ double val = 0;
+ @override
+ void initState() {
+ super.initState();
+ // "ref" can be used in all life-cycles of a StatefulWidget.
+ //ref.read(counterProvider);
+ }
+
+ void increaseVolume() {
+ setState(() {
+ if (val < 20) {
+ val++;
+ ref.read(audioStateProvider.notifier).setVolume(val);
+ }
+ });
+ }
+
+ void decreaseVolume() {
+ setState(() {
+ if (val > 0) {
+ val--;
+ ref.read(audioStateProvider.notifier).setVolume(val);
+ }
+ });
+ }
+
+ void setVolume(double newWalue) {
+ setState(() {
+ val = newWalue;
+ ref.read(audioStateProvider.notifier).setVolume(val);
+ });
+ }
+
+ void pause() {}
+
+ @override
+ Widget build(BuildContext context) {
+ final volumeValue =
+ ref.watch(audioStateProvider.select((audio) => audio.volume));
+ val = volumeValue;
+ return Column(
+ // mainAxisAlignment: MainAxisAlignment.center,
+ // crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ Container(
+ width: 80,
+ height: 418,
+ //padding: const EdgeInsets.all(16),
+ decoration: const ShapeDecoration(
+ // gradient: RadialGradient(
+ // colors: [Color.fromARGB(255, 19, 24, 75), Colors.black],
+ // stops: [0, 0.9],
+ // radius: 1,
+ // ),
+ color: AGLDemoColors.buttonFillEnabledColor,
+ shape: StadiumBorder(
+ side: BorderSide(
+ color: Color(0xFF5477D4),
+ width: 1,
+ )),
+ ),
+ //alignment: Alignment.topLeft,
+ child: Column(
+ children: [
+ SizedBox(
+ height: 68.0,
+ width: 56.0,
+ child: IconButton(
+ padding: EdgeInsets.zero,
+ color: AGLDemoColors.periwinkleColor,
+ onPressed: () {
+ increaseVolume();
+ },
+ icon: const Icon(
+ CustomIcons.vol_max,
+ size: 56,
+ ),
+ ),
+ ),
+ Padding(
+ padding: const EdgeInsets.only(
+ top: 4, bottom: 4), // Top and bottom padding
+ child: SizedBox(
+ height: 274.0,
+ child: RotatedBox(
+ quarterTurns: 3,
+ child: SliderTheme(
+ data: SliderTheme.of(context).copyWith(
+ activeTrackColor: AGLDemoColors.periwinkleColor,
+ inactiveTrackColor: const Color(0xFF0D113F),
+ trackShape: const GradinetRectangularSliderTrackShape(),
+ //trackShape: CustomTrackShape(),
+ trackHeight: 56.0,
+ //thumbColor: Colors.blueAccent,
+ thumbShape: const RectSliderThumbShape(
+ enabledThumbRadius: 0, disabledThumbRadius: 0),
+ //overlayColor: Colors.red.withAlpha(32),
+ overlayShape:
+ //RoundSliderOverlayShape(overlayRadius: 33.0),
+ //RoundSliderOverlayShape(overlayRadius: 0.0),
+ SliderComponentShape.noOverlay,
+ ),
+ child: Slider(
+ min: 0,
+ max: 20,
+ value: volumeValue,
+ divisions: 20,
+ onChanged: (newValue) {
+ setVolume(newValue);
+ },
+ ),
+ ),
+ ),
+ ),
+ ),
+ SizedBox(
+ height: 56.0,
+ width: 56.0,
+ child: IconButton(
+ padding: EdgeInsets.zero,
+ color: AGLDemoColors.periwinkleColor,
+ onPressed: () {
+ decreaseVolume();
+ },
+ icon: const Icon(
+ CustomIcons.vol_min,
+ size: 56,
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ const SizedBox(height: 10),
+ Container(
+ width: 80,
+ height: 80,
+ //padding: const EdgeInsets.all(16),
+ decoration: const ShapeDecoration(
+ // gradient: RadialGradient(
+ // colors: [Color.fromARGB(255, 19, 24, 75), Colors.black],
+ // stops: [0, 0.9],
+ // radius: 1,
+ // ),
+ color: AGLDemoColors.buttonFillEnabledColor,
+ shape: StadiumBorder(
+ side: BorderSide(
+ color: Color(0xFF5477D4),
+ width: 1,
+ )),
+ ),
+ //alignment: Alignment.topLeft,
+ child: IconButton(
+ padding: EdgeInsets.zero,
+ color: AGLDemoColors.periwinkleColor,
+ onPressed: () {
+ pause();
+ },
+ icon: const Icon(
+ Icons.pause,
+ size: 30,
+ )),
+ ),
+ ],
+ );
+ }
+}
+
+class RectSliderThumbShape extends SliderComponentShape {
+ /// Create a slider thumb that draws a Rect.
+ const RectSliderThumbShape({
+ this.enabledThumbRadius = 10.0,
+ this.disabledThumbRadius,
+ this.elevation = 1.0,
+ this.pressedElevation = 6.0,
+ });
+
+ final double enabledThumbRadius;
+
+ final double? disabledThumbRadius;
+ double get _disabledThumbRadius => disabledThumbRadius ?? enabledThumbRadius;
+
+ final double elevation;
+
+ final double pressedElevation;
+
+ @override
+ Size getPreferredSize(bool isEnabled, bool isDiscrete) {
+ return Size.fromRadius(
+ isEnabled == true ? enabledThumbRadius : _disabledThumbRadius);
+ }
+
+ @override
+ void paint(
+ PaintingContext context,
+ Offset center, {
+ required Animation<double> activationAnimation,
+ required Animation<double> enableAnimation,
+ required bool isDiscrete,
+ required TextPainter labelPainter,
+ required RenderBox parentBox,
+ required SliderThemeData sliderTheme,
+ required TextDirection textDirection,
+ required double value,
+ required double textScaleFactor,
+ required Size sizeWithOverflow,
+ }) {
+ final Canvas canvas = context.canvas;
+
+ const Color color = Colors.white;
+ //const double radius = 0;
+
+ final Tween<double> elevationTween = Tween<double>(
+ begin: elevation,
+ end: pressedElevation,
+ );
+
+ final double evaluatedElevation =
+ elevationTween.evaluate(activationAnimation);
+
+ final Path path = Path()
+ ..addRect(
+ Rect.fromCenter(
+ center: Offset(center.dx - 3, center.dy + 2), width: 3, height: 54),
+ );
+
+ // canvas.drawRect(
+ // Rect.fromCenter(center: center, width: 4, height: 25),
+ // Paint()..color = color,
+ // );
+ canvas.drawRect(
+ Rect.fromCenter(center: center, width: 4, height: 54),
+ Paint()..color = color,
+ );
+ canvas.drawShadow(path, Colors.black, evaluatedElevation, true);
+ }
+}
+
+class GradinetRectangularSliderTrackShape extends SliderTrackShape
+ with BaseSliderTrackShape {
+ /// Creates a slider track that draws 2 rectangles.
+ const GradinetRectangularSliderTrackShape();
+
+ @override
+ void paint(
+ PaintingContext context,
+ Offset offset, {
+ required RenderBox parentBox,
+ required SliderThemeData sliderTheme,
+ required Animation<double> enableAnimation,
+ required TextDirection textDirection,
+ required Offset thumbCenter,
+ Offset? secondaryOffset,
+ bool isDiscrete = false,
+ bool isEnabled = false,
+ }) {
+ assert(sliderTheme.disabledActiveTrackColor != null);
+ assert(sliderTheme.disabledInactiveTrackColor != null);
+ assert(sliderTheme.activeTrackColor != null);
+ assert(sliderTheme.inactiveTrackColor != null);
+ assert(sliderTheme.thumbShape != null);
+ // If the slider [SliderThemeData.trackHeight] is less than or equal to 0,
+ // then it makes no difference whether the track is painted or not,
+ // therefore the painting can be a no-op.
+ if (sliderTheme.trackHeight! <= 0) {
+ return;
+ }
+
+ LinearGradient gradient = const LinearGradient(
+ colors: <Color>[
+ //AGLDemoColors.periwinkleColor,
+ Color(0xff81A9ED),
+ Colors.white,
+ ],
+ );
+ final Rect trackRect = getPreferredRect(
+ parentBox: parentBox,
+ offset: offset,
+ sliderTheme: sliderTheme,
+ isEnabled: isEnabled,
+ isDiscrete: isDiscrete,
+ );
+ // Assign the track segment paints, which are left: active, right: inactive,
+ // but reversed for right to left text.
+ final ColorTween activeTrackColorTween = ColorTween(
+ begin: sliderTheme.disabledActiveTrackColor,
+ end: sliderTheme.activeTrackColor);
+ final ColorTween inactiveTrackColorTween = ColorTween(
+ begin: sliderTheme.disabledInactiveTrackColor,
+ end: sliderTheme.inactiveTrackColor);
+ final Paint activePaint = Paint()
+ ..shader = gradient.createShader(trackRect)
+ ..color = activeTrackColorTween.evaluate(enableAnimation)!;
+ final Paint inactivePaint = Paint()
+ ..color = inactiveTrackColorTween.evaluate(enableAnimation)!;
+ final Paint leftTrackPaint;
+ final Paint rightTrackPaint;
+ switch (textDirection) {
+ case TextDirection.ltr:
+ leftTrackPaint = activePaint;
+ rightTrackPaint = inactivePaint;
+ case TextDirection.rtl:
+ leftTrackPaint = inactivePaint;
+ rightTrackPaint = activePaint;
+ }
+
+ final Rect leftTrackSegment = Rect.fromLTRB(
+ trackRect.left, trackRect.top, thumbCenter.dx, trackRect.bottom);
+ if (!leftTrackSegment.isEmpty) {
+ context.canvas.drawRect(leftTrackSegment, leftTrackPaint);
+ }
+ final Rect rightTrackSegment = Rect.fromLTRB(
+ thumbCenter.dx, trackRect.top, trackRect.right, trackRect.bottom);
+ if (!rightTrackSegment.isEmpty) {
+ context.canvas.drawRect(rightTrackSegment, rightTrackPaint);
+ }
+
+ final bool showSecondaryTrack = (secondaryOffset != null) &&
+ ((textDirection == TextDirection.ltr)
+ ? (secondaryOffset.dx > thumbCenter.dx)
+ : (secondaryOffset.dx < thumbCenter.dx));
+
+ if (showSecondaryTrack) {
+ final ColorTween secondaryTrackColorTween = ColorTween(
+ begin: sliderTheme.disabledSecondaryActiveTrackColor,
+ end: sliderTheme.secondaryActiveTrackColor);
+ final Paint secondaryTrackPaint = Paint()
+ ..color = secondaryTrackColorTween.evaluate(enableAnimation)!;
+ final Rect secondaryTrackSegment = Rect.fromLTRB(
+ (textDirection == TextDirection.ltr)
+ ? thumbCenter.dx
+ : secondaryOffset.dx,
+ trackRect.top,
+ (textDirection == TextDirection.ltr)
+ ? secondaryOffset.dx
+ : thumbCenter.dx,
+ trackRect.bottom,
+ );
+ if (!secondaryTrackSegment.isEmpty) {
+ context.canvas.drawRect(secondaryTrackSegment, secondaryTrackPaint);
+ }
+ }
+ }
+}
diff --git a/lib/presentation/custom_icons/custom_icons.dart b/lib/presentation/custom_icons/custom_icons.dart
new file mode 100644
index 0000000..2a42c95
--- /dev/null
+++ b/lib/presentation/custom_icons/custom_icons.dart
@@ -0,0 +1,76 @@
+/// Flutter icons CustomIcons
+/// Copyright (C) 2023 by original authors @ fluttericon.com, fontello.com
+/// This font was generated by FlutterIcon.com, which is derived from Fontello.
+///
+/// To use this font, place it in your fonts/ directory and include the
+/// following in your pubspec.yaml
+///
+/// flutter:
+/// fonts:
+/// - family: CustomIcons
+/// fonts:
+/// - asset: fonts/CustomIcons.ttf
+///
+///
+/// * Font Awesome 5, Copyright (C) 2016 by Dave Gandy
+/// Author: Dave Gandy
+/// License: SIL (https://github.com/FortAwesome/Font-Awesome/blob/master/LICENSE.txt)
+/// Homepage: http://fortawesome.github.com/Font-Awesome/
+///
+// ignore_for_file: constant_identifier_names
+
+import 'package:flutter/widgets.dart';
+
+class CustomIcons {
+ CustomIcons._();
+
+ static const _kFontFam = 'CustomIcons';
+ static const String? _kFontPkg = null;
+
+ static const IconData fan_off_enabled =
+ IconData(0xe800, fontFamily: _kFontFam, fontPackage: _kFontPkg);
+ static const IconData fan_off_pressed =
+ IconData(0xe801, fontFamily: _kFontFam, fontPackage: _kFontPkg);
+ static const IconData fan_on_enabled =
+ IconData(0xe802, fontFamily: _kFontFam, fontPackage: _kFontPkg);
+ static const IconData fan_on_pressed =
+ IconData(0xe803, fontFamily: _kFontFam, fontPackage: _kFontPkg);
+ static const IconData vol_max =
+ IconData(0xe804, fontFamily: _kFontFam, fontPackage: _kFontPkg);
+ static const IconData vol_min =
+ IconData(0xe805, fontFamily: _kFontFam, fontPackage: _kFontPkg);
+ static const IconData wifi_0_bar_locked =
+ IconData(0xe806, fontFamily: _kFontFam, fontPackage: _kFontPkg);
+ static const IconData wifi_0_bar_unlocked =
+ IconData(0xe807, fontFamily: _kFontFam, fontPackage: _kFontPkg);
+ static const IconData wifi_1_bar_locked =
+ IconData(0xe808, fontFamily: _kFontFam, fontPackage: _kFontPkg);
+ static const IconData wifi_1_bar_unlocked =
+ IconData(0xe809, fontFamily: _kFontFam, fontPackage: _kFontPkg);
+ static const IconData wifi_2_bar_locked =
+ IconData(0xe80a, fontFamily: _kFontFam, fontPackage: _kFontPkg);
+ static const IconData wifi_2_bar_unlocked =
+ IconData(0xe80b, fontFamily: _kFontFam, fontPackage: _kFontPkg);
+ static const IconData wifi_3_bar_locked =
+ IconData(0xe80c, fontFamily: _kFontFam, fontPackage: _kFontPkg);
+ static const IconData wifi_3_bar_unlocked =
+ IconData(0xe80d, fontFamily: _kFontFam, fontPackage: _kFontPkg);
+ static const IconData wifi_4_bar_locked =
+ IconData(0xe80e, fontFamily: _kFontFam, fontPackage: _kFontPkg);
+ static const IconData wifi_4_bar_unlocked =
+ IconData(0xe80f, fontFamily: _kFontFam, fontPackage: _kFontPkg);
+ static const IconData wifi_5_bar_locked =
+ IconData(0xe810, fontFamily: _kFontFam, fontPackage: _kFontPkg);
+ static const IconData wifi_5_bar_unlocked =
+ IconData(0xe811, fontFamily: _kFontFam, fontPackage: _kFontPkg);
+ static const IconData wiredicon =
+ IconData(0xe812, fontFamily: _kFontFam, fontPackage: _kFontPkg);
+ static const IconData range =
+ IconData(0xe813, fontFamily: _kFontFam, fontPackage: _kFontPkg);
+ static const IconData slider_front =
+ IconData(0xe814, fontFamily: _kFontFam, fontPackage: _kFontPkg);
+ static const IconData slider_rear =
+ IconData(0xe815, fontFamily: _kFontFam, fontPackage: _kFontPkg);
+ static const IconData fan =
+ IconData(0xf863, fontFamily: _kFontFam, fontPackage: _kFontPkg);
+}
diff --git a/lib/presentation/router/routes/routes.dart b/lib/presentation/router/routes/routes.dart
new file mode 100644
index 0000000..d6d74c4
--- /dev/null
+++ b/lib/presentation/router/routes/routes.dart
@@ -0,0 +1,56 @@
+import 'package:flutter_ics_homescreen/presentation/screens/settings/settings_screens/date_time/date/date_screen.dart';
+import 'package:flutter_ics_homescreen/presentation/screens/settings/settings_screens/date_time/time/time_screen.dart';
+
+import '../../../../export.dart';
+
+List<Page<dynamic>> onGenerateAppViewPages(
+ AppState state,
+ List<Page<dynamic>> pages,
+) {
+ switch (state) {
+ case AppState.home:
+ return [DasboardPage.page()];
+ case AppState.dashboard:
+ return [DasboardPage.page()];
+ case AppState.hvac:
+ return [HvacPage.page()];
+ case AppState.apps:
+ return [AppsPage.page()];
+ case AppState.mediaPlayer:
+ return [MediaPlayerPage.page()];
+ case AppState.settings:
+ return [SettingsPage.page()];
+ case AppState.splash:
+ return [SplashPage.page()];
+ case AppState.dateTime:
+ return [DateTimePage.page()];
+ case AppState.bluetooth:
+ return [BluetoothPage.page()];
+ case AppState.wifi:
+ return [WifiPage.page()];
+ case AppState.wired:
+ return [WiredPage.page()];
+ case AppState.audioSettings:
+ return [AudioSettingsPage.page()];
+ case AppState.profiles:
+ return [ProfilesPage.page()];
+ case AppState.units:
+ return [UnitsPage.page()];
+ case AppState.versionInfo:
+ return [VersionInfoPage.page()];
+ case AppState.weather:
+ return [WeatherPage.page()];
+ case AppState.distanceUnit:
+ return [DistanceUnitPage.page()];
+ case AppState.tempUnit:
+ return [TemperatureUnitPage.page()];
+ case AppState.clock:
+ return [ClockPage.page()];
+ case AppState.newProfile:
+ return [NewProfilePage.page()];
+ case AppState.date:
+ return [DatePage.page()];
+ case AppState.time:
+ return [TimePage.page()];
+ }
+}
diff --git a/lib/presentation/routes/widget/page_widget.dart b/lib/presentation/routes/widget/page_widget.dart
new file mode 100644
index 0000000..8a08377
--- /dev/null
+++ b/lib/presentation/routes/widget/page_widget.dart
@@ -0,0 +1,21 @@
+import '../../../export.dart';
+
+class MyPage<T> extends Page<T> {
+ const MyPage({required this.child, super.key});
+
+ final Widget child;
+
+ @override
+ Route<T> createRoute(BuildContext context) {
+ return PageRouteBuilder(
+ settings: this,
+ pageBuilder: (
+ BuildContext context,
+ Animation<double> animation,
+ Animation<double> secondaryAnimation,
+ ) {
+ return FadeTransition(opacity: animation, child: child);
+ },
+ );
+ }
+}
diff --git a/lib/presentation/screens/apps/apps.dart b/lib/presentation/screens/apps/apps.dart
new file mode 100644
index 0000000..5a789fa
--- /dev/null
+++ b/lib/presentation/screens/apps/apps.dart
@@ -0,0 +1,30 @@
+import '/export.dart';
+import 'apps_content.dart';
+
+class AppsPage extends StatelessWidget {
+ const AppsPage({super.key});
+
+ static Page<void> page() => const MaterialPage<void>(child: AppsPage());
+ @override
+ Widget build(BuildContext context) {
+ return const Stack(
+ children: [
+ // SizedBox(
+ // width: double.infinity,
+ // height: double.infinity,
+ // //color: Colors.black,
+ // // decoration:
+ // // BoxDecoration(gradient: AGLDemoColors.gradientBackgroundColor),
+ // child: SvgPicture.asset(
+ // 'assets/HVACBackground.svg',
+ // alignment: Alignment.center,
+ // fit: BoxFit.cover,
+ // //width: 200,
+ // //height: 200,
+ // ),
+ // ),
+ Apps(),
+ ],
+ );
+ }
+}
diff --git a/lib/presentation/screens/apps/apps_content.dart b/lib/presentation/screens/apps/apps_content.dart
new file mode 100644
index 0000000..52da10c
--- /dev/null
+++ b/lib/presentation/screens/apps/apps_content.dart
@@ -0,0 +1,60 @@
+import 'package:flutter_ics_homescreen/data/models/hybrid.dart';
+import 'package:flutter_ics_homescreen/export.dart';
+import 'package:flutter_ics_homescreen/presentation/screens/apps/widgets/app_button.dart';
+
+class Apps extends StatefulWidget {
+ const Apps({super.key});
+
+ @override
+ State<Apps> createState() => _AppsState();
+}
+
+class _AppsState extends State<Apps> {
+ onPressed({required String type}) {
+ if (type == "weather") {
+ context.flow<AppState>().update((next) => AppState.weather);
+ } else if (type == "clock") {
+ context.flow<AppState>().update((next) => AppState.clock);
+ }
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ const CommonTitle(title: "Applications"),
+ Padding(
+ padding: const EdgeInsets.symmetric(vertical: 50, horizontal: 148),
+ child: Wrap(
+ children: [
+ AppButton(
+ image: "weather.svg",
+ title: "Weather",
+ onPressed: () {
+ onPressed(type: "weather");
+ },
+ ),
+ AppButton(
+ image: "clock.svg",
+ title: "Clock",
+ onPressed: () {
+ onPressed(type: "clock");
+ },
+ )
+ ],
+ ),
+ ),
+ // Center(
+ // child: SizedBox(
+ // width: 500,
+ // height: 500,
+ // child: Center(
+ // child: Lottie.asset(''),
+ // )),
+ // ),
+ ],
+ );
+ }
+}
+
diff --git a/lib/presentation/screens/apps/widgets/app_button.dart b/lib/presentation/screens/apps/widgets/app_button.dart
new file mode 100644
index 0000000..a890786
--- /dev/null
+++ b/lib/presentation/screens/apps/widgets/app_button.dart
@@ -0,0 +1,61 @@
+import 'package:flutter_ics_homescreen/core/utils/helpers.dart';
+import 'package:flutter_ics_homescreen/export.dart';
+
+class AppButton extends StatefulWidget {
+ const AppButton(
+ {super.key,
+ required this.image,
+ required this.title,
+ required this.onPressed});
+ final String image;
+ final String title;
+ final VoidCallback onPressed;
+
+ @override
+ State<AppButton> createState() => _AppButtonState();
+}
+
+class _AppButtonState extends State<AppButton> {
+ @override
+ Widget build(BuildContext context) {
+ Size size = MediaQuery.sizeOf(context);
+ return Container(
+ width: 250,
+ height: 250,
+ margin: const EdgeInsets.all(8),
+ decoration: BoxDecoration(
+ boxShadow: [Helpers.boxDropShadowRegular],
+ border: Border.all(color: AGLDemoColors.neonBlueColor),
+ color: AGLDemoColors.buttonFillEnabledColor,
+ borderRadius: BorderRadius.circular(4)),
+ child: Material(
+ color: Colors.transparent,
+ child: InkWell(
+ borderRadius: BorderRadius.circular(4),
+ onTap: widget.onPressed,
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ Padding(
+ padding: const EdgeInsets.only(
+ left: 10, right: 10, top: 6, bottom: 6),
+ child: SvgPicture.asset(
+ "assets/${widget.image}",
+ ),
+ ),
+ Text(
+ widget.title,
+ textAlign: TextAlign.center,
+ style: TextStyle(
+ fontSize: 40,
+ shadows: [Helpers.dropShadowRegular],
+ color: AGLDemoColors.periwinkleColor,
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/screens/clock/clock.dart b/lib/presentation/screens/clock/clock.dart
new file mode 100644
index 0000000..f0858e7
--- /dev/null
+++ b/lib/presentation/screens/clock/clock.dart
@@ -0,0 +1,145 @@
+import 'dart:async';
+
+import 'package:flutter_ics_homescreen/export.dart';
+
+class ClockPage extends ConsumerWidget {
+ const ClockPage({super.key});
+
+ static Page<void> page() => const MaterialPage<void>(child: ClockPage());
+
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ double clockSize = MediaQuery.sizeOf(context).width * 0.51;
+
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ CommonTitle(
+ title: "Clock",
+ hasBackButton: true,
+ onPressed: () {
+ context.flow<AppState>().update((state) => AppState.apps);
+ },
+ ),
+ const SizedBox(
+ height: 25,
+ ),
+ Expanded(
+ child: Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 10),
+ child: SingleChildScrollView(
+ child: Column(
+ children: [
+ const Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Icon(
+ Icons.location_on_outlined,
+ color: Colors.white,
+ size: 48,
+ ),
+ SizedBox(
+ width: 7,
+ ),
+ Text(
+ "Fortaleza",
+ style: TextStyle(
+ color: Colors.white,
+ fontSize: 40,
+ fontWeight: FontWeight.w500),
+ ),
+ ],
+ ),
+ const SizedBox(
+ height: 80,
+ ),
+ const SizedBox(
+ height: 140,
+ ),
+ Container(
+ width: clockSize,
+ height: clockSize,
+ decoration: const BoxDecoration(
+ image: DecorationImage(
+ image: AssetImage(
+ "assets/clockBackground.png",
+ ),
+ ),
+ ),
+ child: const AnalogClock(
+ dialColor: null,
+ markingColor: null,
+ hourNumberColor: null,
+ secondHandColor: AGLDemoColors.jordyBlueColor,
+ hourHandColor: AGLDemoColors.jordyBlueColor,
+ minuteHandColor: AGLDemoColors.jordyBlueColor,
+ centerPointColor: null,
+ hourHandLengthFactor: 0.6,
+ secondHandLengthFactor: 0.6,
+ secondHandWidthFactor: 1.5,
+ minuteHandLengthFactor: 0.7,
+ minuteHandWidthFactor: 2.5,
+ hourHandWidthFactor: 1.2,
+ ),
+ ),
+ const SizedBox(
+ height: 120,
+ ),
+ const RealTimeClock(),
+ ],
+ ),
+ ),
+ ),
+ )
+ ],
+ );
+ }
+}
+
+class RealTimeClock extends StatefulWidget {
+ const RealTimeClock({super.key});
+
+ @override
+ State<RealTimeClock> createState() => _RealTimeClockState();
+}
+
+class _RealTimeClockState extends State<RealTimeClock> {
+ late String _timeString;
+ late Timer _timer;
+
+ @override
+ void initState() {
+ _timeString = _formatDateTime(DateTime.now());
+ _timer =
+ Timer.periodic(const Duration(seconds: 1), (Timer t) => _getTime());
+ super.initState();
+ }
+
+ @override
+ void dispose() {
+ _timer.cancel();
+ super.dispose();
+ }
+
+ void _getTime() {
+ final DateTime now = DateTime.now();
+ final String formattedDateTime = _formatDateTime(now);
+ if (mounted) {
+ setState(() {
+ _timeString = formattedDateTime;
+ });
+ }
+ }
+
+ String _formatDateTime(DateTime dateTime) {
+ return "${dateTime.hour}:${dateTime.minute.toString().padLeft(2, '0')}";
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Text(
+ _timeString,
+ style: GoogleFonts.brunoAce(color: Colors.white, fontSize: 128),
+ );
+ }
+}
diff --git a/lib/presentation/screens/dashboard/dashboard.dart b/lib/presentation/screens/dashboard/dashboard.dart
new file mode 100644
index 0000000..977bb31
--- /dev/null
+++ b/lib/presentation/screens/dashboard/dashboard.dart
@@ -0,0 +1,33 @@
+
+import '/export.dart';
+import 'widgets/dashboard_content.dart';
+
+class DasboardPage extends ConsumerWidget {
+ const DasboardPage({super.key});
+
+ static Page<void> page() => const MaterialPage<void>(child: DasboardPage());
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ return Stack(
+ children: [
+
+ Padding(
+ padding: const EdgeInsets.only(top: 150.0),
+ child: SizedBox(
+ width: double.infinity,
+ height: double.infinity,
+ child: SvgPicture.asset(
+ 'assets/dashboardTextures.svg',
+ alignment: Alignment.center,
+ ),
+ ),
+ ),
+ const Padding(
+ padding: EdgeInsets.symmetric(vertical: 50, horizontal: 140),
+ child: DashBoard(),
+ ),
+ ],
+
+ );
+ }
+}
diff --git a/lib/presentation/screens/dashboard/widgets/car_status.dart b/lib/presentation/screens/dashboard/widgets/car_status.dart
new file mode 100644
index 0000000..b824871
--- /dev/null
+++ b/lib/presentation/screens/dashboard/widgets/car_status.dart
@@ -0,0 +1,251 @@
+// ignore_for_file: prefer_const_constructors, prefer_const_literals_to_create_immutables
+
+import 'package:gradient_borders/gradient_borders.dart';
+
+import '../../../../export.dart';
+
+class CarStatus extends ConsumerStatefulWidget {
+ const CarStatus({super.key});
+
+ @override
+ CarStatusState createState() => CarStatusState();
+}
+
+class CarStatusState extends ConsumerState<CarStatus> {
+ @override
+ void initState() {
+ super.initState();
+ // "ref" can be used in all life-cycles of a StatefulWidget.
+ //ref.read(counterProvider);
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Padding(
+ padding: const EdgeInsets.fromLTRB(0,0,0,84),
+ child: SizedBox(
+ height: 440,
+ width: 652,
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ const LeftCarStatus(),
+ Padding(
+ padding: const EdgeInsets.symmetric(
+ horizontal: 47.0), // Adding horizontal padding
+ child: SvgPicture.asset(
+ 'assets/Car Illustration.svg',
+ width: 625,
+ height: 440,
+ fit: BoxFit.fitHeight,
+ ),
+ ),
+ const RightCarStatus(),
+ ],
+ ),
+ ),
+ );
+ }
+}
+
+class LeftCarStatus extends ConsumerWidget {
+ const LeftCarStatus({
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ final frontLeftTire =
+ ref.watch(vehicleProvider.select((vehicle) => vehicle.frontLeftTire));
+ final rearLeftTire =
+ ref.watch(vehicleProvider.select((vehicle) => vehicle.rearLeftTire));
+
+ return Column(
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
+ crossAxisAlignment: CrossAxisAlignment.end,
+ children: [
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.end,
+ children: [
+ PSIProgressIndicator(value: frontLeftTire.toDouble()),
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.end,
+ mainAxisAlignment: MainAxisAlignment.end,
+ children: [
+ Text(
+ frontLeftTire.toStringAsFixed(1),
+ style: GoogleFonts.brunoAce(
+ textStyle: TextStyle(
+ color: Colors.white, fontSize: 44),
+ ),
+ ),
+ SizedBox(
+ width: 5,
+ ),
+ PSIWidget(),
+ ],
+ ),
+ ],
+ ),
+ ChildLockLeft(),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.end,
+ children: [
+ PSIProgressIndicator(value: rearLeftTire.toDouble()),
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.end,
+ mainAxisAlignment: MainAxisAlignment.end,
+ children: [
+ Text(
+ rearLeftTire.toStringAsFixed(1),
+ style: GoogleFonts.brunoAce(
+ textStyle: TextStyle(
+ color: Colors.white, fontSize: 44),
+ ),
+ ),
+ SizedBox(
+ width: 5,
+ ),
+ PSIWidget(),
+ ],
+ ),
+ ],
+ ),
+ ],
+ );
+ }
+}
+
+class RightCarStatus extends ConsumerWidget {
+ const RightCarStatus({
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ final frontRightTire =
+ ref.watch(vehicleProvider.select((vehicle) => vehicle.frontRightTire));
+ final rearRightTire =
+ ref.watch(vehicleProvider.select((vehicle) => vehicle.rearRightTire));
+
+ return Column(
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+
+ children: [
+ PSIProgressIndicator(value: frontRightTire.toDouble()),
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.end,
+ children: [
+ Text(
+ frontRightTire.toStringAsFixed(1),
+ style: GoogleFonts.brunoAce(
+ textStyle: TextStyle(
+ color: Colors.white, fontSize: 44),
+ ),
+ ),
+ SizedBox(
+ width: 5,
+ ),
+ PSIWidget(),
+ ],
+ ),
+ ],
+ ),
+ const ChildLockRight(),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ PSIProgressIndicator(value: rearRightTire.toDouble()),
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.end,
+ mainAxisAlignment: MainAxisAlignment.start,
+ children: [
+ Text(
+ rearRightTire.toStringAsFixed(1),
+ style: GoogleFonts.brunoAce(
+ textStyle: TextStyle(
+ color: Colors.white, fontSize: 44),
+ ),
+ ),
+ SizedBox(
+ width: 5,
+ ),
+ PSIWidget(),
+ ],
+ ),
+ ],
+ ),
+ ],
+ );
+ }
+}
+
+class PSIProgressIndicator extends StatelessWidget {
+ final double value;
+ const PSIProgressIndicator({
+ Key? key,
+ required this.value, // Require the value to be passed
+ }) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ // Calculate the width as a percentage of the full width (74 in this case)
+ final double fillWidth = (value / 35) * 74;
+
+ return Stack(
+ alignment: AlignmentDirectional.centerStart,
+ children: [
+ Container(
+ width: 100,
+ height: 24,
+ decoration: BoxDecoration(
+ border: GradientBoxBorder(
+ gradient:
+ LinearGradient(colors: const [Colors.white30, Colors.white]),
+ ),
+ ),
+
+ ),
+ Positioned(
+ left: 3,
+ child: Container(
+ width: fillWidth, // Use the calculated width here
+ height: 18, // Match the height of the progress bar
+ decoration: BoxDecoration(
+ gradient: LinearGradient(
+ colors: const [AGLDemoColors.periwinkleColor, Colors.white],
+ stops: [
+ 0.8,
+ 1,
+ ],
+ ),
+ ),
+ ),
+ ),
+ ],
+ );
+ }
+}
+
+class PSIWidget extends StatelessWidget {
+ const PSIWidget({
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return Padding(
+ padding: const EdgeInsets.only(left: 4.0, right: 1.0, bottom: 2.0),
+ child: Text(
+ 'PSI',
+ style: TextStyle(
+ fontSize: 26,
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/screens/dashboard/widgets/child_lock.dart b/lib/presentation/screens/dashboard/widgets/child_lock.dart
new file mode 100644
index 0000000..b8701d7
--- /dev/null
+++ b/lib/presentation/screens/dashboard/widgets/child_lock.dart
@@ -0,0 +1,96 @@
+
+import 'package:flutter_ics_homescreen/export.dart';
+
+class ChildLockLeft extends ConsumerWidget {
+ const ChildLockLeft({
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ final isChildLockActiveLeft = ref.watch(
+ vehicleProvider.select((vehicle) => vehicle.isChildLockActiveLeft));
+
+ return GestureDetector(
+ onTap: () {
+ debugPrint('Tapped child lock left');
+ ref.read(vehicleProvider.notifier).setChildLock(side: 'left');
+ },
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.end,
+ children: [
+ const Text(
+ 'Child Lock',
+ style: TextStyle(
+ fontSize: 26, // Set the font size to 26
+ ),
+ ),
+ Wrap(
+ crossAxisAlignment: WrapCrossAlignment.center,
+ children: [
+ Icon(
+ isChildLockActiveLeft ? Icons.lock : Icons.lock_open,
+ color: isChildLockActiveLeft ? Colors.white : Colors.redAccent,
+ size: 16,
+ ),
+ Text(
+ isChildLockActiveLeft ? 'Activated' : 'Unlocked',
+ style: TextStyle(
+ color: isChildLockActiveLeft ? Colors.white : Colors.redAccent,
+ fontSize: 26, // Set the font size to 26
+ ),
+ ),
+ ],
+ ),
+ ],
+ ),
+ );
+ }
+}
+
+class ChildLockRight extends ConsumerWidget {
+ const ChildLockRight({
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ final isChildLockActiveRight = ref.watch(
+ vehicleProvider.select((vehicle) => vehicle.isChildLockActiveRight));
+
+ return GestureDetector(
+ onTap: () {
+ debugPrint('Tapped child lock right');
+ ref.read(vehicleProvider.notifier).setChildLock(side: 'right');
+ },
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ const Text(
+ 'Child Lock',
+ style: TextStyle(
+ fontSize: 26, // Set the font size to 26
+ ),
+ ),
+ Wrap(
+ crossAxisAlignment: WrapCrossAlignment.center,
+ children: [
+ Text(
+ isChildLockActiveRight ? 'Activated' : 'Unlocked',
+ style: TextStyle(
+ color: isChildLockActiveRight ? Colors.white : Colors.redAccent,
+ fontSize: 26, // Set the font size to 26
+ ),
+ ),
+ Icon(
+ isChildLockActiveRight ? Icons.lock : Icons.lock_open,
+ color: isChildLockActiveRight ? Colors.white : Colors.redAccent,
+ size: 16,
+ ),
+ ],
+ ),
+ ],
+ ),
+ );
+ }
+} \ No newline at end of file
diff --git a/lib/presentation/screens/dashboard/widgets/circle_indicator.dart b/lib/presentation/screens/dashboard/widgets/circle_indicator.dart
new file mode 100644
index 0000000..7a4e724
--- /dev/null
+++ b/lib/presentation/screens/dashboard/widgets/circle_indicator.dart
@@ -0,0 +1,305 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+import 'custom_circle.dart';
+
+class RPMProgressIndicator extends ConsumerStatefulWidget {
+ const RPMProgressIndicator({super.key});
+
+ @override
+ RPMProgressIndicatorState createState() => RPMProgressIndicatorState();
+}
+
+class RPMProgressIndicatorState extends ConsumerState<RPMProgressIndicator>
+ with TickerProviderStateMixin {
+ late AnimationController controller;
+
+ @override
+ void initState() {
+ controller = AnimationController(
+ /// [AnimationController]s can be created with `vsync: this` because of
+ /// [TickerProviderStateMixin].
+ vsync: this,
+ duration: const Duration(seconds: 5),
+ )..addListener(() {
+ //setState(() {});
+ });
+ controller.repeat(reverse: true);
+ super.initState();
+ }
+
+ @override
+ void dispose() {
+ controller.dispose();
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ final rpm =
+ ref.watch(vehicleProvider.select((vehicle) => vehicle.engineSpeed));
+ return Column(
+ children: [
+ SizedBox(
+ height: 252,
+ child: Stack(
+ alignment: Alignment.center,
+ children: [
+
+ Text(
+ rpm.toString(),
+ style: GoogleFonts.brunoAce(
+ textStyle: const TextStyle(color: Colors.white, fontSize: 44),
+ ),
+ ),
+ Stack(
+ children: [
+ if (rpm > 6500)
+ SizedBox(
+ height: 200,
+ width: 200,
+ child: CircularProgressIndicator(
+ strokeWidth: 12,
+ backgroundColor: Colors.transparent,
+ //value: controller.value,
+ valueColor: const AlwaysStoppedAnimation<Color>(
+ AGLDemoColors.redProgressStrokeColor),
+ value: rpm * (1 / maxRpm),
+ ),
+ ),
+ SizedBox(
+ height: 200,
+ width: 200,
+ child: CircularProgressIndicator(
+ strokeWidth: 12,
+ backgroundColor: Colors.transparent,
+ //value: controller.value,
+ valueColor: const AlwaysStoppedAnimation<Color>(
+ AGLDemoColors.jordyBlueColor),
+ value: rpm >= 6500
+ ? 6500 * (1 / maxRpm)
+ : rpm * (1 / maxRpm),
+ ),
+ ),
+ ],
+ ),
+ SizedBox(
+ height: 220,
+ width: 220,
+ child: CustomPaint(
+ foregroundPainter: CirclePainter(
+ value: rpm.toDouble(),
+ maxValue: maxRpm.toDouble(),
+ isRPM: true,
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ const Text(
+ 'RPM',
+ style: TextStyle(color: Colors.white, fontSize: 40),
+ ),
+ ],
+ );
+ }
+}
+
+
+
+class SpeedProgressIndicator extends ConsumerStatefulWidget {
+ const SpeedProgressIndicator({super.key});
+
+ @override
+ SpeedProgressIndicatorState createState() => SpeedProgressIndicatorState();
+}
+
+class SpeedProgressIndicatorState extends ConsumerState<SpeedProgressIndicator>
+ with TickerProviderStateMixin {
+ late AnimationController controller;
+
+ @override
+ void initState() {
+ controller = AnimationController(
+ /// [AnimationController]s can be created with `vsync: this` because of
+ /// [TickerProviderStateMixin].
+ vsync: this,
+ duration: const Duration(seconds: 5),
+ )..addListener(() {
+ //setState(() {});
+ });
+ controller.repeat(reverse: true);
+ super.initState();
+ }
+
+ @override
+ void dispose() {
+ controller.dispose();
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ final speed = ref.watch(vehicleProvider.select((vehicle) => vehicle.speed));
+ final unit =
+ ref.watch(unitStateProvider.select((unit) => unit.distanceUnit));
+ return Column(
+ children: [
+
+ SizedBox(
+ height: 252,
+ child: Stack(
+ alignment: Alignment.center,
+ children: [
+
+ Text(
+ unit == DistanceUnit.kilometers
+ ? speed.toStringAsFixed(0)
+ : (speed * 1.609).toStringAsFixed(0),
+ style: GoogleFonts.brunoAce(
+ textStyle: const TextStyle(
+ color: Colors.white,
+ fontSize: 44,
+ ),
+ ),
+ ),
+ SizedBox(
+ height: 200,
+ width: 200,
+ child: CircularProgressIndicator(
+ strokeWidth: 12,
+ //backgroundColor: const Color(0xFF2962FF),
+ //value: controller.value,
+ value: unit == DistanceUnit.kilometers
+ ? speed * (1 / maxSpeed)
+ : (speed * (1 / maxSpeed) * 1.609),
+ semanticsLabel: 'Speed progress indicator',
+ ),
+ ),
+ SizedBox(
+ height: 220,
+ width: 220,
+ child: CustomPaint(
+ foregroundPainter:
+ CirclePainter(value: speed, maxValue: maxSpeed),
+ ),
+ ),
+ ],
+ ),
+
+ ),
+ Text(
+ unit == DistanceUnit.kilometers ? 'Km/h' : 'Mph',
+ style: const TextStyle(color: Colors.white, fontSize: 40),
+ ),
+ ],
+ );
+ }
+}
+
+class FuelProgressIndicator extends ConsumerStatefulWidget {
+ const FuelProgressIndicator({super.key});
+
+ @override
+ FuelProgressIndicatorState createState() => FuelProgressIndicatorState();
+}
+
+class FuelProgressIndicatorState extends ConsumerState<FuelProgressIndicator>
+ with TickerProviderStateMixin {
+ late AnimationController controller;
+
+ @override
+ void initState() {
+ controller = AnimationController(
+ /// [AnimationController]s can be created with `vsync: this` because of
+ /// [TickerProviderStateMixin].
+ vsync: this,
+ duration: const Duration(seconds: 5),
+ )..addListener(() {
+ //setState(() {});
+ });
+ controller.repeat(reverse: true);
+ super.initState();
+ }
+
+ @override
+ void dispose() {
+ controller.dispose();
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ final fuelLevel =
+ ref.watch(vehicleProvider.select((vehicle) => vehicle.fuelLevel));
+ return Column(
+ children: [
+ SizedBox(
+ height: 252,
+ child: Stack(
+ alignment: Alignment.center,
+ children: [
+
+ Text(
+ '${(fuelLevel * (1 / maxFuelLevel) * 100).toStringAsFixed(0)}%',
+ style: GoogleFonts.brunoAce(
+ textStyle: const TextStyle(
+ color: Colors.white,
+ fontSize: 44,
+ ),
+ ),
+ ),
+ Stack(
+ children: [
+ SizedBox(
+ height: 200,
+ width: 200,
+ child: CircularProgressIndicator(
+ strokeWidth: 12,
+ backgroundColor: Colors.transparent,
+ value: fuelLevel >= 12
+ ? 12 * (1 / maxFuelLevel)
+ : fuelLevel * (1 / maxFuelLevel),
+ valueColor: const AlwaysStoppedAnimation<Color>(
+ AGLDemoColors.redProgressStrokeColor),
+ ),
+ ),
+ if (fuelLevel > 12)
+ SizedBox(
+ height: 200,
+ width: 200,
+ child: CircularProgressIndicator(
+ strokeWidth: 12,
+ backgroundColor: Colors.transparent,
+ //value: controller.value,
+ valueColor: const AlwaysStoppedAnimation<Color>(
+ AGLDemoColors.jordyBlueColor),
+ value: fuelLevel * (1 / maxFuelLevel),
+ ),
+ ),
+
+ ],
+ ),
+ SizedBox(
+ height: 220,
+ width: 220,
+ child: CustomPaint(
+ foregroundPainter: CirclePainter(
+ value: fuelLevel,
+ maxValue: maxFuelLevel,
+ isFuel: true,
+ isRPM: false),
+ ),
+ ),
+ ],
+ ),
+ ),
+ const Text(
+ 'Fuel',
+ style: TextStyle(color: Colors.white, fontSize: 40),
+ ),
+ ],
+ );
+ }
+}
+
diff --git a/lib/presentation/screens/dashboard/widgets/custom_circle.dart b/lib/presentation/screens/dashboard/widgets/custom_circle.dart
new file mode 100644
index 0000000..4e26f0b
--- /dev/null
+++ b/lib/presentation/screens/dashboard/widgets/custom_circle.dart
@@ -0,0 +1,107 @@
+import 'dart:math' as math;
+
+import 'package:flutter_ics_homescreen/export.dart';
+
+class CirclePainter extends CustomPainter {
+ final double value;
+ final double maxValue;
+ final bool? isRPM;
+ final bool? isFuel;
+
+ CirclePainter({
+ required this.value,
+ required this.maxValue,
+ this.isRPM = false,
+ this.isFuel = false,
+ });
+ @override
+ void paint(Canvas canvas, Size size) {
+ final paint = Paint()
+ ..color = AGLDemoColors.neonBlueColor
+ ..strokeWidth = 2
+ ..style = PaintingStyle.stroke;
+ final paintRed = Paint()
+ ..color = const Color(0xFFBF360C)
+ ..strokeWidth = 2
+ ..style = PaintingStyle.stroke;
+
+ final smallCirclePaint = Paint()
+ ..color = AGLDemoColors.resolutionBlueColor
+ ..strokeWidth = 10
+ // Use [PaintingStyle.fill] if you want the circle to be filled.
+ ..style = PaintingStyle.fill;
+
+ final center = Offset(size.width / 2, size.height / 2);
+
+ final double radius = (size.width / 2) - 10;
+
+ const totalDegree = 360;
+
+ // Total ticks to display
+ var totalTicks = isFuel! ? 4 : 8;
+
+ var values = [];
+ for (int i = 0; i < totalTicks; i++) {
+ values.add(i * (maxValue / totalTicks));
+ }
+
+ /// The angle between each tick
+ var unitAngle = totalDegree / totalTicks;
+ for (int i = 0; i < totalTicks; i++) {
+ final angle = -90.0.radians + (i * unitAngle).radians;
+ final xOffset = radius * math.cos(angle);
+ final yOffset = radius * math.sin(angle);
+ final offset = Offset(center.dx + xOffset, center.dy + yOffset);
+ if (value > values[i]) {
+ canvas.drawCircle(offset, 3, smallCirclePaint);
+ } else {
+ canvas.drawCircle(offset, 3, smallCirclePaint..color = Colors.white);
+ }
+ }
+
+ final rect = Rect.fromCenter(
+ center: center,
+ width: ((size.width / 2.4) * 2) + 2,
+ height: (size.width / 2.4) * 2 + 2,
+ );
+ canvas.drawArc(
+ rect,
+ _deg2Rads(-90),
+ _deg2Rads(360),
+ false,
+ paint,
+ );
+ if (isRPM == true) {
+ canvas.drawArc(
+ rect,
+ _deg2Rads(202),
+ _deg2Rads(68),
+ false,
+ paintRed,
+ );
+ }
+ if (isFuel == true) {
+ canvas.drawArc(
+ rect,
+ _deg2Rads(-90),
+ _deg2Rads(80),
+ false,
+ paintRed,
+ );
+ }
+
+ //canvas.drawArc(rect, pi / 4, pi * 3 / 4, false, paint);
+ }
+
+ double _deg2Rads(num deg) {
+ return (deg * math.pi) / 180.0;
+ }
+
+ @override
+ bool shouldRepaint(oldDelegate) => false;
+}
+
+extension on num {
+ /// This is an extension we created so we can easily convert a value /// to a radian value
+ double get radians => (this * math.pi) / 180.0;
+}
diff --git a/lib/presentation/screens/dashboard/widgets/dashboard_content.dart b/lib/presentation/screens/dashboard/widgets/dashboard_content.dart
new file mode 100644
index 0000000..74f0d2a
--- /dev/null
+++ b/lib/presentation/screens/dashboard/widgets/dashboard_content.dart
@@ -0,0 +1,108 @@
+import 'dart:math';
+
+import 'package:flutter_ics_homescreen/export.dart';
+
+class DashBoard extends ConsumerStatefulWidget {
+ const DashBoard({super.key});
+
+ @override
+ DashBoardState createState() => DashBoardState();
+}
+
+class DashBoardState extends ConsumerState<DashBoard>
+ with SingleTickerProviderStateMixin {
+ late AnimationController _animationController;
+ late Animation<double> _animation;
+ static bool _isAnimationPlayed = false;
+
+ @override
+ void initState() {
+ super.initState();
+ _animationController = AnimationController(
+ duration: const Duration(milliseconds: 1800),
+ vsync: this,
+ value: _isAnimationPlayed ? 1.0 : 0.0,
+ );
+
+ _animation = CurvedAnimation(
+ parent: _animationController,
+ curve: Curves.easeIn,
+ );
+
+ // Start the animation on first build.
+ if (!_isAnimationPlayed) {
+ Future.delayed(const Duration(milliseconds: 500), () {
+ _animationController.forward();
+ _isAnimationPlayed = true;
+ });
+ }
+ }
+
+ @override
+ void dispose() {
+ _animationController.dispose();
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ Widget svgImage = Align(
+ alignment: Alignment.bottomCenter,
+ child: SvgPicture.asset(
+ 'assets/Car Illustration.svg',
+ width: 625,
+ height: 440,
+ fit: BoxFit.fitHeight,
+ ),
+ );
+
+ Widget fadeContent = FadeTransition(
+ opacity: _animation,
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: <Widget>[
+ const Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ //mainAxisSize: MainAxisSize.max,
+ children: [
+ RPMProgressIndicator(),
+ SpeedProgressIndicator(),
+ FuelProgressIndicator(),
+ ],
+ ),
+ GestureDetector(
+ onTap: () {
+ Random random = Random();
+ int randomState = random.nextInt(4);
+ var hybridState = HybridState.values[randomState];
+ ref
+ .read(hybridtateProvider.notifier)
+ .setHybridState(hybridState);
+ },
+ child: const HybridModel()),
+ const Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ TemperatureWidget(),
+ RangeWidget(),
+ ],
+ ),
+ const CarStatus(),
+ ],
+ ));
+
+ return Stack(
+ alignment: Alignment.center,
+ children: [
+ Positioned.fill(
+ child: fadeContent,
+ ),
+ Positioned(
+ bottom: 138,
+ child: svgImage,
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/presentation/screens/dashboard/widgets/hybrid/hybrid.dart b/lib/presentation/screens/dashboard/widgets/hybrid/hybrid.dart
new file mode 100644
index 0000000..b6844de
--- /dev/null
+++ b/lib/presentation/screens/dashboard/widgets/hybrid/hybrid.dart
@@ -0,0 +1,142 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+class HybridBackround extends StatelessWidget {
+ const HybridBackround({
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return SvgPicture.asset('animations/hybrid_model/hybrid_bg.svg');
+ }
+}
+
+class TopArrow extends StatelessWidget {
+ const TopArrow({
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return Align(
+ alignment: const Alignment(0, -0.75),
+ child: Consumer(builder: (context, ref, child) {
+ final state = ref.watch(hybridtateProvider.select((hybrid) => hybrid));
+ Widget? widget;
+ switch (state.topArrowState) {
+ case ArrowState.blue:
+ widget = SvgPicture.asset(
+ 'animations/hybrid_model/top_blue.svg',
+ );
+ break;
+ case ArrowState.red:
+ widget = Lottie.asset('animations/hybrid_model/top_arrow_red.json');
+
+ break;
+
+ default:
+ }
+
+ return widget ??
+ SvgPicture.asset(
+ 'animations/hybrid_model/left_blue.svg',
+ );
+ }),
+ );
+ }
+}
+
+class LeftArrow extends StatelessWidget {
+ const LeftArrow({
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return Align(
+ alignment: const Alignment(-0.7, 0.5),
+ child: Consumer(builder: (context, ref, child) {
+ final state = ref.watch(hybridtateProvider.select((hybrid) => hybrid));
+ Widget? widget;
+ switch (state.leftArrowState) {
+ case ArrowState.blue:
+ widget = SvgPicture.asset(
+ 'animations/hybrid_model/left_blue.svg',
+ );
+ break;
+ case ArrowState.red:
+ widget =
+ Lottie.asset('animations/hybrid_model/left_arrow_red.json');
+
+ break;
+
+ default:
+ }
+
+ return widget ??
+ SvgPicture.asset(
+ 'animations/hybrid_model/left_blue.svg',
+ );
+ }),
+ );
+ }
+}
+
+class RightArrow extends StatelessWidget {
+ const RightArrow({
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return Align(
+ alignment: const Alignment(0.70, 0.5),
+ child: Consumer(builder: (context, ref, child) {
+ final state = ref.watch(hybridtateProvider.select((hybrid) => hybrid));
+
+ Widget? widget;
+ switch (state.rightArrowState) {
+ case ArrowState.blue:
+ widget = SvgPicture.asset(
+ 'animations/hybrid_model/right_blue.svg',
+ );
+ break;
+ case ArrowState.yellow:
+ widget =
+ Lottie.asset('animations/hybrid_model/right_arrow_yellow.json');
+
+ break;
+ case ArrowState.green:
+ widget =
+ Lottie.asset('animations/hybrid_model/right_arrow_green.json');
+
+ break;
+ default:
+ }
+
+ return widget ??
+ SvgPicture.asset(
+ 'animations/hybrid_model/right_blue.svg',
+ );
+ }),
+ );
+ }
+}
+
+class BatteryHybrid extends ConsumerWidget {
+ const BatteryHybrid({
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ final batteryState =
+ ref.watch(hybridtateProvider.select((hybrid) => hybrid.batteryState));
+ return Align(
+ alignment: const Alignment(0, 0.8),
+ child: SvgPicture.asset(
+ 'animations/hybrid_model/battery_${batteryState.name}.svg',
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/screens/dashboard/widgets/hybrid_mode.dart b/lib/presentation/screens/dashboard/widgets/hybrid_mode.dart
new file mode 100644
index 0000000..9a657b8
--- /dev/null
+++ b/lib/presentation/screens/dashboard/widgets/hybrid_mode.dart
@@ -0,0 +1,30 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+class HybridModel extends StatefulWidget {
+ const HybridModel({super.key});
+
+ @override
+ State<HybridModel> createState() => _HybridModelState();
+}
+
+class _HybridModelState extends State<HybridModel> {
+ @override
+ Widget build(BuildContext context) {
+
+ return GestureDetector(
+ child: const SizedBox(
+ width: 500,
+ height: 500,
+ child: Stack(
+ children: [
+ HybridBackround(),
+ TopArrow(),
+ LeftArrow(),
+ RightArrow(),
+ BatteryHybrid(),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/screens/dashboard/widgets/range.dart b/lib/presentation/screens/dashboard/widgets/range.dart
new file mode 100644
index 0000000..aea92af
--- /dev/null
+++ b/lib/presentation/screens/dashboard/widgets/range.dart
@@ -0,0 +1,85 @@
+import 'package:flutter_ics_homescreen/presentation/custom_icons/custom_icons.dart';
+
+import '../../../../export.dart';
+
+class RangeWidget extends ConsumerWidget {
+ const RangeWidget({super.key});
+
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ final range = ref.watch(vehicleProvider.select((vehicle) => vehicle.range));
+ final unit =
+ ref.watch(unitStateProvider.select((unit) => unit.distanceUnit));
+ return Container(
+ height:130,
+ width: 306,
+ // padding: const EdgeInsets.all(10),
+ decoration: const ShapeDecoration(
+ gradient: RadialGradient(
+ colors: [
+ Color.fromARGB(255, 19, 24, 75),
+ Color.fromARGB(127, 0, 0, 0)
+ ],
+ stops: [0, 0.7],
+ radius: 1,
+ ),
+ //color: Colors.grey,
+ shape: StadiumBorder(
+ side: BorderSide(
+ color: Color.fromARGB(156, 0, 0, 0),
+ width: 2,
+ )),
+ ),
+ alignment: Alignment.topLeft,
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ const Icon(
+ CustomIcons.range,
+ color: Color(0xFF2962FF),
+ size: 48,
+ ),
+ const SizedBox(width: 8),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ const Text(
+ 'Range',
+ textAlign: TextAlign.start,
+ style: TextStyle(
+ color: Color(0xFFC1D8FF),
+ fontSize: 26,
+ ),
+ ),
+ RichText(
+ text: TextSpan(
+
+ text: '$range',
+ style: GoogleFonts.brunoAce(
+
+ textStyle:
+ const TextStyle(
+ color: Colors.white,
+ fontSize: 44,
+ ),
+ ),
+ children: <TextSpan>[
+ TextSpan(
+ text:
+ unit == DistanceUnit.kilometers ? ' Km' : ' Mi',
+ style: GoogleFonts.brunoAce(
+ textStyle: const TextStyle(
+ color: Color(0xFFC1D8FF),
+ fontSize: 38),
+ ),
+ ),
+ ]),
+ ),
+ ],
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/screens/dashboard/widgets/temperature.dart b/lib/presentation/screens/dashboard/widgets/temperature.dart
new file mode 100644
index 0000000..0817b53
--- /dev/null
+++ b/lib/presentation/screens/dashboard/widgets/temperature.dart
@@ -0,0 +1,143 @@
+import '../../../../export.dart';
+
+class TemperatureWidget extends ConsumerWidget {
+ const TemperatureWidget({super.key});
+
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ final temperature = ref.watch(vehicleProvider.select((vehicle) => vehicle));
+ // final outsideTemperature = ref
+ // .watch(vehicleProvider.select((vehicle) => vehicle.outsideTemperature));
+ final tempUnit =
+ ref.watch(unitStateProvider.select((unit) => unit.temperatureUnit));
+
+ TextStyle temperatureTextStyle = const TextStyle(
+ fontFamily: 'BrunoAce',
+ color: Colors.white,
+ fontSize: 44,
+ );
+
+ TextStyle unitTextStyle = const TextStyle(
+ fontFamily: 'BrunoAce',
+ color: Color(0xFFC1D8FF),
+ fontSize: 38,
+ );
+
+ return Container(
+ width:
+ 442, // needs to be adjusted after the celsius and farenheight symbols are fixed
+ height: 130, // Height of the oval
+ //padding: const EdgeInsets.all(10),
+ decoration: ShapeDecoration(
+ gradient: const RadialGradient(
+ colors: [
+ Color.fromARGB(255, 19, 24, 75),
+ Color.fromARGB(127, 0, 0, 0)
+ ],
+ stops: [0.0, 0.7],
+ radius: 1,
+ ),
+ //color: Colors.grey,
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(65), // Half of the height for an oval effect
+ side: const BorderSide(
+ color: Color.fromARGB(156, 0, 0, 0),
+ width: 2,
+ ),
+ ),
+ ),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ // Inside temperature
+ buildTemperatureRow(
+ context,
+ Icons.thermostat_outlined,
+ "Inside",
+ temperature.insideTemperature,
+ tempUnit,
+ temperatureTextStyle,
+ unitTextStyle,
+ false,
+ ),
+ const SizedBox(width: 10),
+ // Outside temperature
+ buildTemperatureRow(
+ context,
+ Icons.thermostat_outlined,
+ "Outside",
+ temperature.outsideTemperature,
+ tempUnit,
+ temperatureTextStyle,
+ unitTextStyle,
+ true,
+ ),
+ ],
+ ),
+ );
+ }
+
+ Widget buildTemperatureRow(
+ BuildContext context,
+ IconData icon,
+ String label,
+ double temperatureValue,
+ TemperatureUnit tempUnit,
+ TextStyle tempTextStyle,
+ TextStyle unitTextStyle,
+ bool isOutside,
+
+ ) {
+ int temperatureAsInt = temperatureValue.toInt();
+ double convertedTemperature = tempUnit == TemperatureUnit.celsius
+ ? temperatureAsInt.toDouble()
+ : (temperatureAsInt * 9 / 5) + 32;
+
+ // Format the temperature for display.
+ String temperatureDisplay = tempUnit == TemperatureUnit.celsius
+ ? '$temperatureAsInt'
+ : '${convertedTemperature.toStringAsFixed(0)}';
+
+ return Padding(
+ padding: isOutside
+ ? const EdgeInsets.only(right: 22) // Padding for the outside temperature
+ : const EdgeInsets.only(left: 12), // Padding for the inside temperature
+ child: Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Icon(
+ icon,
+ color: const Color(0xFF2962FF),
+ size: 48,
+ ),
+ const SizedBox(width: 4), // Space between icon and text
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text(
+ label,
+ style: const TextStyle(
+ color: Color(0xFFC1D8FF),
+ fontSize: 26,
+ ),
+ ),
+ RichText(
+ text: TextSpan(
+ text: temperatureDisplay,
+ style: tempTextStyle,
+ children: <TextSpan>[
+ TextSpan(
+ text: tempUnit == TemperatureUnit.celsius ? '°C' : '°F',
+ style: unitTextStyle,
+ ),
+ ],
+ ),
+ ),
+ ],
+ ),
+ ],
+ ),
+ );
+ }
+} \ No newline at end of file
diff --git a/lib/presentation/screens/home/home.dart b/lib/presentation/screens/home/home.dart
new file mode 100644
index 0000000..c132c98
--- /dev/null
+++ b/lib/presentation/screens/home/home.dart
@@ -0,0 +1,71 @@
+import 'package:flutter_ics_homescreen/export.dart';
+// import 'package:media_kit_video/media_kit_video.dart';
+
+class HomeScreen extends ConsumerStatefulWidget {
+ const HomeScreen({
+ super.key,
+ });
+
+ @override
+ HomeScreenState createState() => HomeScreenState();
+}
+
+class HomeScreenState extends ConsumerState<HomeScreen> {
+
+
+
+ @override
+ void initState() {
+ super.initState();
+ }
+
+ @override
+ void dispose() {
+ // player.dispose();
+ super.dispose();
+ }
+
+ @override
+ Widget build(
+ BuildContext context,
+ ) {
+ return Consumer(builder: (context, ref, child) {
+ final state = ref.read(appProvider);
+ return Scaffold(
+ key: homeScaffoldKey,
+ extendBody: true,
+ extendBodyBehindAppBar: true,
+ appBar: const CustomTopBar(),
+ body: Stack(
+ children: [
+ /*
+ Lottie.asset(
+ 'animations/BG-dotwaveform.json',
+ fit: BoxFit.cover,
+ repeat: true,
+ ),
+ */
+ FlowBuilder<AppState>(
+ state: ref.watch(appProvider),
+ onGeneratePages: onGenerateAppViewPages,
+ observers: [
+ HeroController(),
+ ],
+ ),
+ if (state != AppState.splash)
+ Positioned(
+ top: 0,
+ bottom: 0,
+ child: Container(
+ padding: const EdgeInsets.only(left: 8),
+ height: 500,
+ child: const VolumeFanControl()),
+ ),
+ ],
+ ),
+ bottomNavigationBar:
+ state == AppState.splash ? null : const CustomBottomBar(),
+ );
+ });
+ }
+}
diff --git a/lib/presentation/screens/home/widgets/custom_tile.dart b/lib/presentation/screens/home/widgets/custom_tile.dart
new file mode 100644
index 0000000..389a75d
--- /dev/null
+++ b/lib/presentation/screens/home/widgets/custom_tile.dart
@@ -0,0 +1,50 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+class CustomTile extends StatelessWidget {
+ final String name;
+ final Color color;
+ final VoidCallback callback;
+ const CustomTile({
+ Key? key,
+ required this.name,
+ required this.color,
+ required this.callback,
+ }) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ // Calculate the container size based on the app size
+ //final size = MediaQuery.of(context).size;
+ // final width = size.width * 0.15;
+ // final height = size.height * 0.15;
+ return Expanded(
+ child: GestureDetector(
+ onTap: callback,
+ child: Padding(
+ padding: const EdgeInsets.fromLTRB(0.0, 8.0, 8.0, 8.0),
+ child: Container(
+ padding: const EdgeInsets.symmetric(
+ horizontal: 20,
+ vertical: 10,
+ ),
+ height: 150, //height,
+ width: 150, //width,
+ color: color,
+ child: Center(
+ child: Text(
+ name,
+ textAlign: TextAlign.center,
+ overflow: TextOverflow.fade,
+ style: const TextStyle(
+ color: Colors.white,
+ //fontSize: width * 0.15,
+ fontSize: 18,
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/screens/hvac/hvac.dart b/lib/presentation/screens/hvac/hvac.dart
new file mode 100644
index 0000000..ebdaea4
--- /dev/null
+++ b/lib/presentation/screens/hvac/hvac.dart
@@ -0,0 +1,45 @@
+import '/export.dart';
+
+class HvacPage extends StatelessWidget {
+ const HvacPage({super.key});
+
+ static Page<void> page() => const MaterialPage<void>(child: HvacPage());
+ @override
+ Widget build(BuildContext context) {
+ // print(MediaQuery.of(context).size);
+ // print(MediaQuery.of(context).size.width *
+ // MediaQuery.of(context).devicePixelRatio);
+ // print(MediaQuery.of(context).size.height *
+ // MediaQuery.of(context).devicePixelRatio);
+ return Stack(
+ children: [
+ // SizedBox(
+ // width: double.infinity,
+ // height: double.infinity,
+ // //color: Colors.black,
+ // // decoration:
+ // // BoxDecoration(gradient: AGLDemoColors.gradientBackgroundColor),
+ // child: SvgPicture.asset(
+ // 'assets/HVACBackground.svg',
+ // alignment: Alignment.center,
+ // fit: BoxFit.cover,
+ // //width: 200,
+ // //height: 200,
+ // ),
+ // ),
+ SizedBox(
+ width: double.infinity,
+ height: double.infinity,
+ // color: Colors.black,
+ child: SvgPicture.asset(
+ 'assets/backgroundTextures.svg',
+ alignment: Alignment.center,
+ //width: 200,
+ //height: 200,
+ ),
+ ),
+ const SingleChildScrollView(child: HVAC()),
+ ],
+ );
+ }
+}
diff --git a/lib/presentation/screens/hvac/hvac_content.dart b/lib/presentation/screens/hvac/hvac_content.dart
new file mode 100644
index 0000000..f79ec14
--- /dev/null
+++ b/lib/presentation/screens/hvac/hvac_content.dart
@@ -0,0 +1,249 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+class HVAC extends ConsumerStatefulWidget {
+ const HVAC({super.key});
+
+ @override
+ HVACState createState() => HVACState();
+}
+
+class HVACState extends ConsumerState<HVAC> {
+ bool isFanFocusLeftTopSelected = false;
+ bool isFanFocusRightTopSelected = true;
+ bool isFanFocusLeftBottomSelected = true;
+ bool isFanFocusRightBottomSelected = false;
+
+ late bool isACSelected;
+ bool isSYNCSelected = true;
+ late bool isFrontDefrostSelected;
+ bool isAutoSelected = true;
+ late bool isRecirculationSelected;
+ late bool isRearDefrostSelected;
+
+ int temperatureLeft = 26;
+ int temperatureRight = 26;
+ @override
+ void initState() {
+ super.initState();
+ }
+
+ TextStyle climateControlTextStyle = GoogleFonts.raleway(
+ color: AGLDemoColors.periwinkleColor,
+ fontSize: 44,
+ height: 1.25,
+ fontWeight: FontWeight.w500,
+ shadows: [
+ Shadow(
+ offset: const Offset(1, 2),
+ blurRadius: 3,
+ color: Colors.black.withOpacity(0.7))
+ ]);
+ TextStyle climateControlSelectedTextStyle = GoogleFonts.raleway(
+ color: Colors.white,
+ fontWeight: FontWeight.bold,
+ fontSize: 44,
+ height: 1.25,
+ shadows: [
+ Shadow(
+ offset: const Offset(1, 2),
+ blurRadius: 3,
+ color: Colors.black.withOpacity(0.7))
+ ]);
+
+ @override
+ Widget build(BuildContext context) {
+ final vehicle = ref.watch(vehicleProvider.select((vehicle) => vehicle));
+ isACSelected = vehicle.isAirConditioningActive;
+ isFrontDefrostSelected = vehicle.isFrontDefrosterActive;
+ isRearDefrostSelected = vehicle.isRearDefrosterActive;
+ isRecirculationSelected = vehicle.isRecirculationActive;
+ Size size = MediaQuery.sizeOf(context);
+
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ const SizedBox(
+ height: 83,
+ ),
+ Row(
+ children: [
+ SizedBox(
+ width: size.width * 0.125,
+ ),
+ Expanded(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ const Padding(
+ padding: EdgeInsets.symmetric(vertical: 20),
+ child: Text(
+ "Left",
+ style: TextStyle(color: Colors.white, fontSize: 40),
+ textAlign: TextAlign.center,
+ ),
+ ),
+ FanFocus(
+ onPressed: () {
+ setState(() {
+ isFanFocusLeftTopSelected = !isFanFocusLeftTopSelected;
+ });
+ },
+ isSelected: isFanFocusLeftTopSelected,
+ focusType: "top_half"),
+ const SizedBox(
+ height: 12,
+ ),
+ FanFocus(
+ onPressed: () {
+ setState(() {
+ isFanFocusLeftBottomSelected =
+ !isFanFocusLeftBottomSelected;
+ });
+ },
+ isSelected: isFanFocusLeftBottomSelected,
+ focusType: "bottom_half")
+ ],
+ )),
+ SizedBox(
+ width: size.width * 0.05,
+ ),
+ Expanded(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ const Padding(
+ padding: EdgeInsets.symmetric(vertical: 20),
+ child: Text(
+ "Right",
+ style: TextStyle(color: Colors.white, fontSize: 40),
+ textAlign: TextAlign.center,
+ ),
+ ),
+ FanFocus(
+ onPressed: () {
+ setState(() {
+ isFanFocusRightTopSelected =
+ !isFanFocusRightTopSelected;
+ });
+ },
+ isSelected: isFanFocusRightTopSelected,
+ focusType: "top_half"),
+ const SizedBox(
+ height: 12,
+ ),
+ FanFocus(
+ onPressed: () {
+ setState(() {
+ isFanFocusRightBottomSelected =
+ !isFanFocusRightBottomSelected;
+ });
+ },
+ isSelected: isFanFocusRightBottomSelected,
+ focusType: "bottom_half")
+ ],
+ )),
+ SizedBox(
+ width: size.width * 0.1,
+ ),
+ ],
+ ),
+ const SizedBox(
+ height: 80,
+ ),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: [
+ TemperatureControl(temperature: temperatureLeft),
+ TemperatureControl(temperature: temperatureRight)
+ ],
+ ),
+ const SizedBox(
+ height: 170,
+ ),
+ const FanSpeedControls(),
+ const SizedBox(
+ height: 70,
+ ),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ ClimateControls(
+ isSelected: isACSelected,
+ onPressed: () {
+ ref
+ .read(vehicleProvider.notifier)
+ .setHVACMode(mode: 'airCondition');
+ },
+ child: Text(
+ "A/C",
+ style: isACSelected
+ ? climateControlSelectedTextStyle
+ : climateControlTextStyle,
+ )),
+ ClimateControls(
+ onPressed: () {
+ setState(() {
+ isSYNCSelected = !isSYNCSelected;
+ });
+ },
+ isSelected: isSYNCSelected,
+ child: Text(
+ "SYNC",
+ style: isSYNCSelected
+ ? climateControlSelectedTextStyle
+ : climateControlTextStyle,
+ )),
+ ClimateControls(
+ onPressed: () {
+ ref
+ .read(vehicleProvider.notifier)
+ .setHVACMode(mode: 'frontDefrost');
+ },
+ isSelected: isFrontDefrostSelected,
+ child: SvgPicture.asset(
+ "assets/${isFrontDefrostSelected ? "FrontDefrostFilled.svg" : "FrontDefrost.svg"}",
+ ))
+ ],
+ ),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ ClimateControls(
+ isSelected: isAutoSelected,
+ onPressed: () {
+ setState(() {
+ isAutoSelected = !isAutoSelected;
+ });
+ },
+ child: Text(
+ "AUTO",
+ style: isAutoSelected
+ ? climateControlSelectedTextStyle
+ : climateControlTextStyle,
+ )),
+ ClimateControls(
+ onPressed: () {
+ ref
+ .read(vehicleProvider.notifier)
+ .setHVACMode(mode: 'recirculation');
+ },
+ isSelected: isRecirculationSelected,
+ child: SvgPicture.asset(
+ "assets/${isRecirculationSelected ? "RecirculationFilled.svg" : "Recirculation.svg"}",
+ )),
+ ClimateControls(
+ onPressed: () {
+ ref
+ .read(vehicleProvider.notifier)
+ .setHVACMode(mode: 'rearDefrost');
+ },
+ isSelected: isRearDefrostSelected,
+ child: SvgPicture.asset(
+ "assets/${isRearDefrostSelected ? "BackDefrostFilled.svg" : "BackDefrost.svg"}",
+ ))
+ ],
+ )
+ ],
+ );
+ }
+}
diff --git a/lib/presentation/screens/hvac/widgets/climate_controls.dart b/lib/presentation/screens/hvac/widgets/climate_controls.dart
new file mode 100644
index 0000000..c7dcd52
--- /dev/null
+++ b/lib/presentation/screens/hvac/widgets/climate_controls.dart
@@ -0,0 +1,80 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+class ClimateControls extends StatefulWidget {
+ const ClimateControls(
+ {super.key,
+ required this.child,
+ required this.isSelected,
+ required this.onPressed});
+ final Widget child;
+ final bool isSelected;
+ final VoidCallback onPressed;
+
+ @override
+ State<ClimateControls> createState() => _ClimateControlsState();
+}
+
+class _ClimateControlsState extends State<ClimateControls> {
+ @override
+ Widget build(BuildContext context) {
+ Size size = MediaQuery.sizeOf(context);
+
+ return Container(
+ margin: const EdgeInsets.all(8),
+ width: size.width * 0.23,
+ height: size.height * 0.07,
+ decoration: BoxDecoration(
+ borderRadius: BorderRadius.circular(2),
+ boxShadow: [
+ BoxShadow(
+ offset: Offset(
+ widget.isSelected ? 0 : 1, widget.isSelected ? 4 : 2),
+ blurRadius: widget.isSelected ? 4 : 3,
+ spreadRadius: 0,
+ color: Colors.black.withOpacity(widget.isSelected ? 0.25 : 0.7))
+ ],
+ gradient: LinearGradient(
+ colors: widget.isSelected
+ ? [
+ AGLDemoColors.periwinkleColor,
+ AGLDemoColors.periwinkleColor.withOpacity(0.25)
+ ]
+ : [
+ AGLDemoColors.neonBlueColor,
+ AGLDemoColors.neonBlueColor.withOpacity(0.2)
+ ],
+ begin: Alignment.centerLeft,
+ end: Alignment.centerRight),
+ border: Border.all(color: Colors.white12)),
+ child: Container(
+ padding: const EdgeInsets.all(2),
+ decoration: BoxDecoration(
+ borderRadius: BorderRadius.circular(2),
+ boxShadow: [
+ BoxShadow(
+ offset: Offset(
+ widget.isSelected ? 0 : 1, widget.isSelected ? 4 : 2),
+ blurRadius: widget.isSelected ? 4 : 3,
+ spreadRadius: 0,
+ color:
+ Colors.black.withOpacity(widget.isSelected ? 0.25 : 0.7))
+ ],
+ color: widget.isSelected
+ ? AGLDemoColors.neonBlueColor
+ : AGLDemoColors.buttonFillEnabledColor,
+ border: Border.all(color: Colors.white12)),
+ child: Material(
+ color: Colors.transparent,
+ child: InkWell(
+ onTap: widget.onPressed,
+ child: Center(
+ child: Padding(
+ padding: const EdgeInsets.symmetric(vertical: 8),
+ child: widget.child,
+ )),
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/screens/hvac/widgets/fan_focus.dart b/lib/presentation/screens/hvac/widgets/fan_focus.dart
new file mode 100644
index 0000000..556c2c7
--- /dev/null
+++ b/lib/presentation/screens/hvac/widgets/fan_focus.dart
@@ -0,0 +1,116 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+class FanFocus extends StatefulWidget {
+ const FanFocus(
+ {super.key,
+ required this.isSelected,
+ required this.focusType,
+ required this.onPressed});
+ final bool isSelected;
+ final String focusType;
+ final VoidCallback onPressed;
+ @override
+ State<FanFocus> createState() => _FanFocusState();
+}
+
+class _FanFocusState extends State<FanFocus> {
+ @override
+ Widget build(BuildContext context) {
+ double height = MediaQuery.sizeOf(context).height * 0.10;
+ double iconSize = 32;
+
+ return Container(
+ height: height,
+ decoration: BoxDecoration(
+ gradient: LinearGradient(
+ colors: widget.isSelected
+ ? [
+ AGLDemoColors.periwinkleColor,
+ AGLDemoColors.periwinkleColor.withOpacity(0.25)
+ ]
+ : [
+ AGLDemoColors.jordyBlueColor,
+ AGLDemoColors.jordyBlueColor.withOpacity(0.2)
+ ]),
+ borderRadius: BorderRadius.only(
+ topLeft: Radius.circular(widget.focusType == "top_half" ? 16 : 0),
+ topRight: Radius.circular(widget.focusType == "top_half" ? 16 : 0),
+ bottomLeft:
+ Radius.circular(widget.focusType == "bottom_half" ? 16 : 0),
+ bottomRight:
+ Radius.circular(widget.focusType == "bottom_half" ? 16 : 0)),
+ ),
+ child: Container(
+ margin: const EdgeInsets.all(1),
+ decoration: BoxDecoration(
+ borderRadius: BorderRadius.only(
+ topLeft: Radius.circular(widget.focusType == "top_half" ? 16 : 0),
+ topRight:
+ Radius.circular(widget.focusType == "top_half" ? 16 : 0),
+ bottomLeft:
+ Radius.circular(widget.focusType == "bottom_half" ? 16 : 0),
+ bottomRight:
+ Radius.circular(widget.focusType == "bottom_half" ? 16 : 0)),
+ color: widget.isSelected
+ ? AGLDemoColors.neonBlueColor
+ : AGLDemoColors.buttonFillEnabledColor,
+ image: const DecorationImage(
+ image: AssetImage("assets/PlusVector.png"),
+ opacity: 0.5,
+ fit: BoxFit.cover),
+ ),
+ child: Material(
+ color: Colors.transparent,
+ child: InkWell(
+ borderRadius: BorderRadius.only(
+ topLeft:
+ Radius.circular(widget.focusType == "top_half" ? 16 : 0),
+ topRight:
+ Radius.circular(widget.focusType == "top_half" ? 16 : 0),
+ bottomLeft:
+ Radius.circular(widget.focusType == "bottom_half" ? 16 : 0),
+ bottomRight: Radius.circular(
+ widget.focusType == "bottom_half" ? 16 : 0)),
+ onTap: widget.onPressed,
+ child: Row(
+ crossAxisAlignment: widget.focusType == "top_half"
+ ? CrossAxisAlignment.end
+ : CrossAxisAlignment.start,
+ mainAxisAlignment: MainAxisAlignment.end,
+ children: [
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Padding(
+ padding: const EdgeInsets.only(top: 38),
+ child: Icon(
+ Icons.arrow_forward,
+ color: Colors.white,
+ size: iconSize,
+ shadows: [
+ Shadow(
+ offset: Offset(1, widget.isSelected ? 2 : 4),
+ blurRadius: widget.isSelected ? 3 : 4,
+ color: Colors.black.withOpacity(0.7))
+ ],
+ ),
+ ),
+ Image.asset(
+ "assets/${widget.focusType == "top_half" ? widget.isSelected ? "head_selected" : "head" : widget.isSelected ? "legs_selected" : "legs"}.png",
+ //fit: BoxFit.contain,
+ // alignment: Alignment.bottomRight,
+ // width: widget.focusType == "top_half" ? 108 : 250,
+ // height: 180,
+ ),
+ ],
+ ),
+ SizedBox(
+ width: widget.focusType == "top_half" ? 5 : 40,
+ )
+ ]),
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/screens/hvac/widgets/fan_speed_controls.dart b/lib/presentation/screens/hvac/widgets/fan_speed_controls.dart
new file mode 100644
index 0000000..00f1181
--- /dev/null
+++ b/lib/presentation/screens/hvac/widgets/fan_speed_controls.dart
@@ -0,0 +1,251 @@
+import 'package:flutter_ics_homescreen/export.dart';
+import 'package:gradient_borders/gradient_borders.dart';
+import 'package:rive/rive.dart' as rive;
+
+class FanSpeedControls extends ConsumerStatefulWidget {
+ const FanSpeedControls({super.key});
+
+ @override
+ FanSpeedControlsState createState() => FanSpeedControlsState();
+}
+
+class FanSpeedControlsState extends ConsumerState<FanSpeedControls>
+ with TickerProviderStateMixin {
+ bool isPressed = false;
+ LinearGradient gradientEnable1 = const LinearGradient(colors: <Color>[
+ Color(0xFF2962FF),
+ Color(0x802962FF),
+ ]);
+ LinearGradient gradientEnable2 = const LinearGradient(colors: <Color>[
+ Color(0xFF1A237E),
+ Color(0xFF141F64),
+ ]);
+ bool isMainACSelected = false;
+ late AnimationController animationController;
+ double controlProgress = 0.0;
+ int selectedFanSpeed = 0;
+ late rive.RiveAnimationController _controller;
+
+ bool _isPlaying = false;
+
+ /// Tracks if the animation is playing by whether controller is running
+ bool get isPlaying => _controller.isActive;
+
+ @override
+ void initState() {
+ super.initState();
+ _controller = rive.OneShotAnimation(
+ 'Fan Spin',
+ autoplay: false,
+ onStop: () => setState(() => _isPlaying = false),
+ onStart: () => setState(() => _isPlaying = true),
+ );
+ animationController = AnimationController(
+ vsync: this,
+ duration: const Duration(seconds: 1),
+ );
+
+ animationController.addListener(() {
+ setState(() {
+ // _currentColorIndex = (_currentColorIndex + 1) % colorsList.length;
+ }); // Trigger a rebuild to repaint the CustomPaint
+ });
+ animationController.forward();
+ }
+
+ @override
+ void dispose() {
+ animationController.dispose();
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ double size = MediaQuery.sizeOf(context).height * 0.13021;
+ double fanSpeedWidth = MediaQuery.sizeOf(context).width * 0.35;
+ double fanSpeedHeight = MediaQuery.sizeOf(context).height * 0.15;
+ double strokeWidth = MediaQuery.sizeOf(context).height * 0.03;
+
+ double iconSize = 80;
+
+ final vehicle = ref.watch(vehicleProvider.select((vehicle) => vehicle));
+ selectedFanSpeed = vehicle.fanSpeed;
+ controlProgress = selectedFanSpeed * 0.3;
+
+ return Stack(
+ children: [
+ Center(
+ child: CustomPaint(
+ size: Size(
+ fanSpeedWidth, fanSpeedHeight), // Set the desired size here
+ painter: AnimatedColorPainter(
+ animationController,
+ controlProgress,
+ AGLDemoColors.blueGlowFillColor,
+ AGLDemoColors.backgroundInsetColor,
+ strokeWidth,
+ ),
+ ),
+ ),
+ Center(
+ child: Container(
+ margin: const EdgeInsets.only(top: 3),
+ // decoration: BoxDecoration(
+ // shape: BoxShape.circle,
+ // gradient: LinearGradient(
+ // colors: !isMainACSelected
+ // ? [
+ // AGLDemoColors.neonBlueColor,
+ // AGLDemoColors.neonBlueColor.withOpacity(0.2)
+ // ]
+ // : [
+ // const Color.fromARGB(255, 255, 193, 193)
+ // .withOpacity(0.2),
+ // const Color.fromARGB(255, 255, 193, 193)
+ // ]),
+ // boxShadow: isMainACSelected
+ // ? [
+ // BoxShadow(
+ // offset: Offset(
+ // isMainACSelected ? 1 : 1, isMainACSelected ? 2 : 2),
+ // blurRadius: isMainACSelected ? 16 : 16,
+ // spreadRadius: 0,
+ // color: isMainACSelected
+ // ? Colors.black.withOpacity(0.5)
+ // : Colors.black)
+ // ]
+ // : [],
+ // ),
+ //border: Border.all(color: Colors.white12, width: 1)),
+ //width: 90,
+ //height: 90,
+ child: Container(
+ margin: const EdgeInsets.all(1),
+ decoration: BoxDecoration(
+ shape: BoxShape.circle,
+ image: const DecorationImage(
+ image: AssetImage("assets/PlusVector.png"),
+ ),
+ gradient: Gradient.lerp(gradientEnable1, gradientEnable2, 0.5),
+ // border: Border.all(
+ // color: isMainACSelected
+ // ? AGLDemoColors.buttonFillEnabledColor
+ // : Colors.white12,
+ // width: isMainACSelected ? 3 : 1),
+ border: const GradientBoxBorder(
+ width: 2,
+ gradient: LinearGradient(
+ colors: [
+ Color(0x30C1D8FF),
+ Color(0xFFC1D8FF),
+ ],
+ ),
+ ),
+ ),
+ alignment: Alignment.center,
+ child: Material(
+ color: Colors.transparent,
+ child: InkWell(
+ splashColor: Colors.transparent,
+ hoverColor: Colors.transparent,
+ highlightColor: Colors.transparent,
+ customBorder: const CircleBorder(),
+ onTap: () {
+ _isPlaying ? null : _controller.isActive = true;
+ setState(() {
+ if (controlProgress >= 0.80) {
+ controlProgress = 0.0;
+ isMainACSelected = false;
+ animationController.reverse();
+ } else {
+ isMainACSelected = true;
+ _controller.isActive = true;
+ _isPlaying = true;
+ controlProgress += 0.30;
+ animationController.forward();
+ }
+ ref
+ .read(vehicleProvider.notifier)
+ .updateFanSpeed(controlProgress ~/ 0.3);
+
+ // isMainACSelected = !isMainACSelected;
+ // if (controlProgress != 0.0) {
+ // previousProgress = controlProgress;
+ // }
+ // if (isMainACSelected) {
+ // controlProgress = previousProgress;
+ // animationController.forward();
+ // } else {
+ // controlProgress = 0.0;
+ // animationController.reverse();
+ // }
+ });
+ },
+ onTapDown: (details) {
+ setState(() {
+ gradientEnable1 = LinearGradient(colors: <Color>[
+ const Color(0xFF2962FF).withOpacity(0.15),
+ const Color(0x802962FF).withOpacity(0.15),
+ ]);
+ gradientEnable2 = const LinearGradient(colors: <Color>[
+ Color(0xFF1A237E),
+ Color(0xFF1C2D92),
+ ]);
+ });
+ //change style
+ },
+ onTapUp: (details) {
+ setState(() {
+ gradientEnable1 = const LinearGradient(colors: <Color>[
+ Color(0xFF2962FF),
+ Color(0x802962FF),
+ ]);
+ gradientEnable2 = const LinearGradient(colors: <Color>[
+ Color(0xFF1A237E),
+ Color(0xFF141F64),
+ ]);
+ });
+ },
+ child: Container(
+ width: size,
+ height: size,
+ alignment: Alignment.center,
+ child: !_isPlaying && controlProgress == 0.0
+ ? SvgPicture.asset(
+ "assets/ACMainButtonOff.svg",
+ width: iconSize,
+ height: iconSize,
+ )
+ // : !_isPlaying && controlProgress > 0.8
+ // ? SvgPicture.asset(
+ // "assets/ACMainButton.svg",
+ // width: iconSize,
+ // height: iconSize,
+ // )
+ : SizedBox(
+ width: iconSize,
+ height: iconSize,
+ child: rive.RiveAnimation.asset(
+ 'assets/new_file.riv',
+ controllers: [_controller],
+ onInit: (_) => setState(() {
+ _controller.isActive = true;
+ }))))
+ // Container(
+ // width: size,
+ // height: size,
+ // alignment: Alignment.center,
+ // child: SvgPicture.asset(
+ // "assets/ACMainButton.svg",
+ // width: iconSize,
+ // height: iconSize,
+ // ),
+ // ),
+ ),
+ ),
+ ),
+ ))
+ ],
+ );
+ }
+}
diff --git a/lib/presentation/screens/hvac/widgets/semi_circle_painter.dart b/lib/presentation/screens/hvac/widgets/semi_circle_painter.dart
new file mode 100644
index 0000000..e2003c5
--- /dev/null
+++ b/lib/presentation/screens/hvac/widgets/semi_circle_painter.dart
@@ -0,0 +1,109 @@
+import 'package:flutter_ics_homescreen/export.dart';
+import 'dart:math' as math;
+
+class AnimatedColorPainter extends CustomPainter {
+ final AnimationController animationController;
+ final double progress;
+ final Color progressColor; // New parameter for progress color
+ final Color backgroundColor;
+ final double strokeWidth;
+
+ AnimatedColorPainter(this.animationController, this.progress,
+ this.progressColor, this.backgroundColor, this.strokeWidth);
+
+ @override
+ void paint(Canvas canvas, Size size) {
+ // const strokeWidth = 25.0;
+ const borderWidth = 2.0;
+
+ // Divide the arc into equal parts based on the number of colors
+ const arcAngle = math.pi;
+ const arcPart = arcAngle / 3;
+ const gapAngle = arcAngle / 150;
+
+ // Calculate the current color index based on animation progress and progress value
+ final double normalizedProgress = progress * 3;
+ int currentColorIndex =
+ (animationController.value * normalizedProgress).floor();
+ if (progress == 0.0) {
+ currentColorIndex = -1; // Force background color when progress is 0
+ }
+ // Draw each part with a border and inner color
+ double startAngle = -math.pi; // Start from left
+ for (int i = 0; i < 3; i++) {
+ Color? currentColor = backgroundColor;
+ if (i <= currentColorIndex) {
+ // Use progress color if within progress range
+ currentColor = progressColor;
+ } else {
+ // Use background color if outside progress range
+ currentColor = backgroundColor;
+ }
+
+ // Draw border
+ final borderPaint = Paint()
+ ..strokeWidth = strokeWidth + borderWidth
+ ..style = PaintingStyle.stroke
+ ..color = Colors.white12;
+ canvas.drawArc(
+ Rect.fromCircle(
+ center: Offset(size.width / 2, size.height / 2),
+ radius: size.width / 2,
+ ),
+ startAngle,
+ arcPart - 2 * gapAngle,
+ false, // Draw clockwise
+ borderPaint,
+ );
+
+ // Draw inner color
+ final colorPaint = Paint()
+ ..strokeWidth = strokeWidth
+ ..style = PaintingStyle.stroke
+ ..shader = _createColorShader(currentColor, size);
+ canvas.drawArc(
+ Rect.fromCircle(
+ center: Offset(size.width / 2, size.height / 2),
+ radius: size.width / 2,
+ ),
+ startAngle,
+ arcPart - 2 * gapAngle,
+ false, // Draw clockwise
+ colorPaint,
+ );
+
+ startAngle += arcPart + gapAngle;
+ }
+ }
+
+ @override
+ bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
+
+ Shader _createColorShader(Color color, Size size) {
+ if (color == progressColor) {
+ return const RadialGradient(
+ center: Alignment.center,
+ radius: 2,
+ tileMode: TileMode.repeated,
+ focal: Alignment.center,
+ focalRadius: 8,
+ colors: [
+ AGLDemoColors.blueGlowFillColor,
+ AGLDemoColors.jordyBlueColor,
+ AGLDemoColors.neonBlueColor
+ ],
+ ).createShader(
+ Rect.fromCircle(
+ center: Offset(size.width / 2, size.height / 2),
+ radius: size.width / 2,
+ ),
+ );
+ }
+ return LinearGradient(colors: [color, color]).createShader(
+ Rect.fromCircle(
+ center: Offset(size.width / 2, size.height / 2),
+ radius: size.width / 2,
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/screens/hvac/widgets/temperature_control.dart b/lib/presentation/screens/hvac/widgets/temperature_control.dart
new file mode 100644
index 0000000..df83840
--- /dev/null
+++ b/lib/presentation/screens/hvac/widgets/temperature_control.dart
@@ -0,0 +1,255 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+class TemperatureControl extends StatefulWidget {
+ const TemperatureControl({super.key, required this.temperature});
+ final int temperature;
+
+ @override
+ State<TemperatureControl> createState() => _TemperatureControlState();
+}
+
+class _TemperatureControlState extends State<TemperatureControl> {
+ int temperature = 0;
+ bool isUpButtonHighlighted = false;
+ bool isDownButtonHighlighted = false;
+
+ @override
+ void initState() {
+ super.initState();
+ setState(() {
+ temperature = widget.temperature;
+ });
+ }
+
+ onPressed({required String type}) {
+ setState(() {
+ if (type == "add") {
+ temperature = temperature + 1;
+ } else if (type == "subtract") {
+ temperature = temperature - 1;
+ }
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ double iconSize = 32;
+ double height = MediaQuery.sizeOf(context).height * 0.0417;
+ double width = MediaQuery.sizeOf(context).width * 0.2112;
+
+ return Column(
+ children: [
+ Material(
+ color: Colors.transparent,
+ child: InkWell(
+ onHighlightChanged: (value) {
+ setState(() {
+ isUpButtonHighlighted = value;
+ });
+ },
+ onTap: () {
+ onPressed(type: "add");
+ },
+ child: SizedBox(
+ height: height,
+ width: width,
+ child: Image.asset(
+ "assets/${isUpButtonHighlighted ? 'UpPressed' : 'Up'}.png")),
+ ),
+ ),
+ // ClipRect(
+ // clipper: MyCustomClipper(type: "top"),
+ // child: ClipRRect(
+ // borderRadius: const BorderRadius.only(
+ // bottomLeft: Radius.circular(22),
+ // bottomRight: Radius.circular(22)),
+ // child: Container(
+ // height: height,
+ // width: width,
+ // decoration: BoxDecoration(
+ // boxShadow: [
+ // BoxShadow(
+ // offset: const Offset(1, 2),
+ // blurRadius: 3,
+ // color: Colors.black.withOpacity(0.7)),
+ // ],
+ // gradient: LinearGradient(colors: [
+ // AGLDemoColors.neonBlueColor,
+ // AGLDemoColors.neonBlueColor.withOpacity(0.20)
+ // ]),
+ // borderRadius: const BorderRadius.only(
+ // topLeft: Radius.circular(100),
+ // topRight: Radius.circular(100),
+ // bottomLeft: Radius.circular(10),
+ // bottomRight: Radius.circular(10))),
+ // child: Container(
+ // margin: const EdgeInsets.all(1),
+ // decoration: const BoxDecoration(
+ // color: AGLDemoColors.buttonFillEnabledColor,
+ // borderRadius: BorderRadius.only(
+ // topLeft: Radius.circular(100),
+ // topRight: Radius.circular(100),
+ // bottomLeft: Radius.circular(10),
+ // bottomRight: Radius.circular(10))),
+ // child: Material(
+ // color: Colors.transparent,
+ // child: InkWell(
+ // onTap: () {
+ // onPressed(type: "add");
+ // },
+ // child: Padding(
+ // padding: const EdgeInsets.only(bottom: 10),
+ // child: Icon(
+ // Icons.arrow_upward,
+ // color: Colors.white,
+ // size: iconSize,
+ // shadows: [
+ // BoxShadow(
+ // offset: const Offset(1, 2),
+ // blurRadius: 3,
+ // color: Colors.black.withOpacity(0.7)),
+ // ],
+ // ),
+ // ),
+ // ),
+ // ),
+ // ),
+ // ),
+ // ),
+ // ),
+ Padding(
+ padding: const EdgeInsets.symmetric(vertical: 10),
+ child: Text(
+ "$temperature°C",
+ style: GoogleFonts.brunoAce(fontSize: 44, height: 1.25),
+ ),
+ ),
+ Material(
+ color: Colors.transparent,
+ child: InkWell(
+ onHighlightChanged: (value) {
+ setState(() {
+ isDownButtonHighlighted = value;
+ });
+ },
+ onTap: () {
+ onPressed(type: "subtract");
+ },
+ child: SizedBox(
+ height: height,
+ width: width,
+ child: Image.asset(
+ "assets/${isDownButtonHighlighted ? 'DownPressed' : 'Down'}.png")),
+ ),
+ ),
+ // ClipRect(
+ // clipper: MyCustomClipper(type: "bottom"),
+ // child: ClipRRect(
+ // borderRadius: const BorderRadius.only(
+ // topLeft: Radius.circular(20), topRight: Radius.circular(20)),
+ // child: Container(
+ // height: height,
+ // width: width,
+ // decoration: BoxDecoration(
+ // boxShadow: [
+ // BoxShadow(
+ // offset: const Offset(1, 2),
+ // blurRadius: 3,
+ // color: Colors.black.withOpacity(0.7)),
+ // ],
+ // gradient: LinearGradient(colors: [
+ // AGLDemoColors.neonBlueColor,
+ // AGLDemoColors.neonBlueColor.withOpacity(0.20)
+ // ]),
+ // border: Border.all(color: Colors.white12),
+ // borderRadius: const BorderRadius.only(
+ // bottomLeft: Radius.circular(100),
+ // bottomRight: Radius.circular(100),
+ // topLeft: Radius.circular(10),
+ // topRight: Radius.circular(10))),
+ // child: Container(
+ // margin: const EdgeInsets.all(1),
+ // decoration: const BoxDecoration(
+ // color: AGLDemoColors.buttonFillEnabledColor,
+ // borderRadius: BorderRadius.only(
+ // bottomLeft: Radius.circular(100),
+ // bottomRight: Radius.circular(100),
+ // topLeft: Radius.circular(10),
+ // topRight: Radius.circular(10))),
+ // child: Material(
+ // color: Colors.transparent,
+ // child: InkWell(
+ // onTap: () {
+ // onPressed(type: "subtract");
+ // },
+ // child: Padding(
+ // padding: const EdgeInsets.only(top: 10),
+ // child: Icon(
+ // Icons.arrow_downward,
+ // color: Colors.white,
+ // size: iconSize,
+ // shadows: [
+ // BoxShadow(
+ // offset: const Offset(1, 2),
+ // blurRadius: 3,
+ // color: Colors.black.withOpacity(0.7)),
+ // ],
+ // ),
+ // ),
+ // ),
+ // ),
+ // )),
+ // )),
+ ],
+ );
+ }
+}
+
+class MyCustomClipper extends CustomClipper<Rect> {
+ final String type;
+
+ MyCustomClipper({super.reclip, required this.type});
+ @override
+ Rect getClip(Size size) {
+ // Clip 10 pixels from the top of the container
+ return Rect.fromPoints(
+ Offset(0, type == "top" ? 0 : 10),
+ Offset(size.width, type == "top" ? size.height - 10 : size.height),
+ );
+ }
+
+ @override
+ bool shouldReclip(CustomClipper<Rect> oldClipper) {
+ return false;
+ }
+}
+
+class CustomShapePainter extends CustomPainter {
+ @override
+ void paint(Canvas canvas, Size size) {
+ final paint = Paint()
+ ..color = Colors.blue
+ ..strokeWidth = 5.0;
+
+ final path = Path();
+
+ // Draw the top part of the oval
+ path.moveTo(0.0, size.height / 2.0);
+ path.quadraticBezierTo(
+ size.width / 3.0, size.height / 2.0, size.width / 2.0, size.height);
+
+ // Draw the straight line for the bottom part
+ path.lineTo(size.width / 2.0, size.height);
+
+ // Draw the left part of the oval
+ path.quadraticBezierTo(size.width / 3.0, 0.0, 0.0, 0.0);
+
+ // Close the path
+ path.close();
+
+ canvas.drawPath(path, paint);
+ }
+
+ @override
+ bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
+}
diff --git a/lib/presentation/screens/media_player/fm_player.dart b/lib/presentation/screens/media_player/fm_player.dart
new file mode 100644
index 0000000..31a22ae
--- /dev/null
+++ b/lib/presentation/screens/media_player/fm_player.dart
@@ -0,0 +1,76 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+class FMPlayer extends StatefulWidget {
+ const FMPlayer({super.key});
+
+ @override
+ State<FMPlayer> createState() => _FMPlayerState();
+}
+
+class _FMPlayerState extends State<FMPlayer> {
+ String selectedNav = "Standard";
+ List<String> navItems = [
+ "Standard",
+ "HD",
+ ];
+ String tableName = "Presets";
+ List<PlayListModel> playList = [
+ PlayListModel(songName: "93.1 The Mountain", albumName: "93.1"),
+ PlayListModel(songName: "Mix 94.1", albumName: "94.1 MHz"),
+ PlayListModel(songName: "96.3 KKLZ", albumName: "96.3 MHz"),
+ ];
+ String selectedPlayListSongName = "93.1 The Mountain";
+ @override
+ Widget build(BuildContext context) {
+ double fmSignalHeight = 460;
+ double fmSignalWidth = 460;
+
+ return Container(
+ padding: const EdgeInsets.only(left: 7, right: 7),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ SegmentedButtons(
+ navItems: navItems,
+ selectedNav: selectedNav,
+ ),
+ const SizedBox(
+ height: 32,
+ ),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Image.asset(
+ "assets/AlbumArtFM.png",
+ width: fmSignalWidth,
+ height: fmSignalHeight,
+ )
+ ],
+ ),
+ const SizedBox(
+ height: 40,
+ ),
+ Column(
+ children: [
+ const MediaControls(
+ songName: "87.9",
+ songLengthStart: "87.9 MHz",
+ songLengthStop: "87.9 MHz",
+ type: "fm",
+ ),
+ const SizedBox(
+ height: 70,
+ ),
+ PlayListTable(
+ playList: playList,
+ selectedPlayListSongName: selectedPlayListSongName,
+ tableName: tableName,
+ type: "fm",
+ ),
+ ],
+ )
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/screens/media_player/media_content.dart b/lib/presentation/screens/media_player/media_content.dart
new file mode 100644
index 0000000..9a0ce19
--- /dev/null
+++ b/lib/presentation/screens/media_player/media_content.dart
@@ -0,0 +1,82 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+class MediaPlayer extends StatefulWidget {
+ const MediaPlayer({super.key});
+
+ @override
+ State<MediaPlayer> createState() => _MediaPlayerState();
+}
+
+class _MediaPlayerState extends State<MediaPlayer> {
+ String selectedNav = "Bluetooth";
+ List<String> navItems = ["Bluetooth", "SD", "USB"];
+
+ late String songName = "Feel Good Inc.";
+
+ String tableName = "2000’s Dance Hits";
+ List<PlayListModel> playList = [
+ PlayListModel(songName: "Feel Good Inc.", albumName: "Gorillaz"),
+ PlayListModel(
+ songName: "Hips Don’t Lie", albumName: "Shakira, Wyclef Jean"),
+ PlayListModel(songName: "AG1", albumName: "Paid Advertisement"),
+ PlayListModel(songName: "Hey Ya!", albumName: "Outkast"),
+ PlayListModel(songName: "One, Two, Step", albumName: "Ciara, Missy Elliot"),
+ PlayListModel(songName: "Don’t Trust Me", albumName: "3OH!3"),
+ PlayListModel(songName: "Feel Good Inc.", albumName: "Gorillaz"),
+ PlayListModel(songName: "Feel Good Inc.", albumName: "Gorillaz"),
+ PlayListModel(songName: "Feel Good Inc.", albumName: "Gorillaz"),
+ PlayListModel(songName: "Feel Good Inc.", albumName: "Gorillaz"),
+ ];
+ String selectedPlayListSongName = "Feel Good Inc.";
+
+ @override
+ Widget build(BuildContext context) {
+ double albumArtSize = 460;
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ // const PlayerNavigation(),
+ SegmentedButtons(
+ navItems: navItems,
+ selectedNav: selectedNav,
+ ),
+ const SizedBox(
+ height: 32,
+ ),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Image.asset(
+ "assets/AlbumArtMedia.png",
+ width: albumArtSize,
+ height: albumArtSize,
+ )
+ ],
+ ),
+ const SizedBox(
+ height: 40,
+ ),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ MediaControls(
+ songName: songName,
+ songLengthStart: "-1:23",
+ songLengthStop: "5:03",
+ type: "media",
+ ),
+ const SizedBox(
+ height: 72,
+ ),
+ PlayListTable(
+ playList: playList,
+ selectedPlayListSongName: selectedPlayListSongName,
+ tableName: tableName,
+ type: "media",
+ ),
+ ],
+ )
+ ],
+ );
+ }
+}
diff --git a/lib/presentation/screens/media_player/media_controls.dart b/lib/presentation/screens/media_player/media_controls.dart
new file mode 100644
index 0000000..0686187
--- /dev/null
+++ b/lib/presentation/screens/media_player/media_controls.dart
@@ -0,0 +1,413 @@
+import 'package:flutter_ics_homescreen/core/utils/helpers.dart';
+import 'package:flutter_ics_homescreen/export.dart';
+import 'package:flutter_ics_homescreen/presentation/screens/media_player/widgets/gradient_progress_indicator.dart';
+
+class MediaControls extends StatefulWidget {
+ const MediaControls(
+ {super.key,
+ required this.type,
+ required this.songName,
+ required this.songLengthStart,
+ required this.songLengthStop});
+
+ final String type;
+ final String songName;
+ final String songLengthStart;
+ final String songLengthStop;
+
+ @override
+ State<MediaControls> createState() => _MediaControlsState();
+}
+
+class _MediaControlsState extends State<MediaControls> {
+ late String songName;
+ late String songLengthStart;
+ late String songLengthStop;
+ final String albumName = "Gorillaz";
+
+ int songProgress = 20;
+
+ @override
+ void initState() {
+ songName = widget.songName;
+ songLengthStart = widget.songLengthStart;
+ songLengthStop = widget.songLengthStop;
+ super.initState();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Material(
+ color: Colors.transparent,
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ Text(
+ songName,
+ style: TextStyle(
+ color: Colors.white,
+ fontWeight: FontWeight.w400,
+ shadows: [Helpers.dropShadowRegular],
+ fontSize: 44),
+ ),
+ if (widget.type == "media")
+ MediaControlSubDetails(
+ albumName: albumName,
+ )
+ else if (widget.type == "fm")
+ const FMPlayerSubDetails(),
+ if (widget.type == "media")
+ Column(children: [
+ GradientProgressIndicator(
+ percent: songProgress,
+ type: "media",
+ gradient: LinearGradient(
+ begin: Alignment.centerLeft,
+ end: Alignment.centerRight,
+ colors: [
+ AGLDemoColors.jordyBlueColor,
+ AGLDemoColors.jordyBlueColor.withOpacity(0.8),
+ ]),
+ backgroundColor: AGLDemoColors.gradientBackgroundDarkColor,
+ ),
+ // const LinearProgressIndicator(
+ // backgroundColor: AGLDemoColors.gradientBackgroundDarkColor,
+ // color: Colors.white70,
+ // minHeight: 8,
+ // value: 0.7,
+ // ),
+ Padding(
+ padding: const EdgeInsets.symmetric(vertical: 5),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text(
+ songLengthStart,
+ style: TextStyle(
+ color: Colors.white,
+ fontSize: 26,
+ shadows: [Helpers.dropShadowRegular]),
+ ),
+ Text(
+ songLengthStop,
+ style: TextStyle(
+ color: Colors.white,
+ fontSize: 26,
+ shadows: [Helpers.dropShadowRegular]),
+ )
+ ],
+ ),
+ ),
+ ])
+ else if (widget.type == "fm")
+ FMPlayerSlider(
+ minHertz: songLengthStart,
+ maxHertz: songLengthStop,
+ songProgress: songProgress,
+ ),
+ if (widget.type == "media") const MediaPlayerActions()
+ ],
+ ),
+ );
+ }
+}
+
+class MediaControlSubDetails extends StatefulWidget {
+ const MediaControlSubDetails({super.key, required this.albumName});
+ final String albumName;
+
+ @override
+ State<MediaControlSubDetails> createState() => _MediaControlSubDetailsState();
+}
+
+class _MediaControlSubDetailsState extends State<MediaControlSubDetails> {
+ bool isShuffleEnabled = false;
+ bool isRepeatEnabled = false;
+ @override
+ Widget build(BuildContext context) {
+ return Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text(
+ widget.albumName,
+ style: TextStyle(
+ color: Colors.white,
+ fontWeight: FontWeight.w400,
+ fontSize: 40,
+ shadows: [Helpers.dropShadowRegular]),
+ ),
+ Row(
+ children: [
+ InkWell(
+ customBorder: const CircleBorder(),
+ onTap: () {
+ setState(() {
+ isShuffleEnabled = !isShuffleEnabled;
+ });
+ },
+ child: Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: SvgPicture.asset(
+ "assets/${isShuffleEnabled ? "ShufflePressed.svg" : "Shuffle.svg"}",
+ width: 48,
+ ))),
+ InkWell(
+ customBorder: const CircleBorder(),
+ onTap: () {
+ setState(() {
+ isRepeatEnabled = !isRepeatEnabled;
+ });
+ },
+ child: Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: SvgPicture.asset(
+ "assets/${isRepeatEnabled ? "RepeatPressed.svg" : "Repeat.svg"}",
+ width: 48,
+ ))),
+ ],
+ )
+ ],
+ );
+ }
+}
+
+class FMPlayerSubDetails extends StatefulWidget {
+ const FMPlayerSubDetails({
+ super.key,
+ });
+
+ @override
+ State<FMPlayerSubDetails> createState() => _FMPlayerSubDetailsState();
+}
+
+class _FMPlayerSubDetailsState extends State<FMPlayerSubDetails> {
+ onPressed({required String type}) {}
+ @override
+ Widget build(BuildContext context) {
+ return Padding(
+ padding: const EdgeInsets.only(bottom: 5),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Row(
+ children: [
+ Text(
+ "Tune",
+ style: TextStyle(
+ color: Colors.white,
+ fontWeight: FontWeight.w400,
+ fontSize: 40,
+ shadows: [Helpers.dropShadowRegular]),
+ ),
+ const SizedBox(
+ width: 25,
+ ),
+ InkWell(
+ customBorder: const CircleBorder(),
+ onTap: () {
+ onPressed(type: "scanLeft");
+ },
+ child: const Padding(
+ padding: EdgeInsets.all(8.0),
+ child: Icon(
+ Icons.arrow_back,
+ size: 48,
+ color: AGLDemoColors.periwinkleColor,
+ ))),
+ const SizedBox(
+ width: 25,
+ ),
+ InkWell(
+ customBorder: const CircleBorder(),
+ onTap: () {
+ onPressed(type: "scanRight");
+ },
+ child: const Padding(
+ padding: EdgeInsets.all(8.0),
+ child: Icon(
+ Icons.arrow_forward,
+ color: AGLDemoColors.periwinkleColor,
+ size: 48,
+ ))),
+ ],
+ ),
+ Row(
+ children: [
+ Text(
+ "Scan",
+ style: TextStyle(
+ color: Colors.white,
+ fontWeight: FontWeight.w400,
+ fontSize: 40,
+ shadows: [Helpers.dropShadowRegular]),
+ ),
+ const SizedBox(
+ width: 25,
+ ),
+ InkWell(
+ customBorder: const CircleBorder(),
+ onTap: () {
+ onPressed(type: "scanLeft");
+ },
+ child: const Padding(
+ padding: EdgeInsets.all(8.0),
+ child: Icon(
+ Icons.arrow_back,
+ color: AGLDemoColors.periwinkleColor,
+ size: 48,
+ ))),
+ const SizedBox(
+ width: 25,
+ ),
+ InkWell(
+ customBorder: const CircleBorder(),
+ onTap: () {
+ onPressed(type: "scanRight");
+ },
+ child: const Padding(
+ padding: EdgeInsets.all(8.0),
+ child: Icon(
+ Icons.arrow_forward,
+ color: AGLDemoColors.periwinkleColor,
+ size: 48,
+ ))),
+ ],
+ )
+ ],
+ ),
+ );
+ }
+}
+
+class MediaPlayerActions extends StatefulWidget {
+ const MediaPlayerActions({super.key});
+
+ @override
+ State<MediaPlayerActions> createState() => _MediaPlayerActionsState();
+}
+
+class _MediaPlayerActionsState extends State<MediaPlayerActions> {
+ bool isPressed = false;
+ bool isPlaying = true;
+
+ @override
+ Widget build(BuildContext context) {
+ return Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ InkWell(
+ customBorder: const CircleBorder(),
+ onTap: () {},
+ child: Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: SvgPicture.asset(
+ "assets/SkipPrevious.svg",
+ width: 48,
+ ),
+ )),
+ const SizedBox(
+ width: 120,
+ ),
+ InkWell(
+ customBorder: const CircleBorder(),
+ onTap: () {
+ setState(() {
+ isPlaying = !isPlaying;
+ });
+ },
+ onTapDown: (details) {
+ setState(() {
+ isPressed = true;
+ });
+ },
+ onTapUp: (details) {
+ isPressed = false;
+
+ },
+ child: Container(
+ width: 64,
+ height: 64,
+ decoration: BoxDecoration(
+ shape: BoxShape.circle,
+ color:
+ isPressed ? Colors.white : AGLDemoColors.periwinkleColor,
+ boxShadow: [Helpers.boxDropShadowRegular]),
+ child: Icon(
+ isPlaying ? Icons.pause : Icons.play_arrow,
+ color: AGLDemoColors.resolutionBlueColor,
+ size: 60,
+ ),
+ )),
+ const SizedBox(
+ width: 120,
+ ),
+ InkWell(
+ customBorder: const CircleBorder(),
+ onTap: () {},
+ child: Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: SvgPicture.asset(
+ "assets/SkipNext.svg",
+ width: 48,
+ ),
+ )),
+ ],
+ );
+ }
+}
+
+class FMPlayerSlider extends StatefulWidget {
+ const FMPlayerSlider(
+ {super.key,
+ required this.minHertz,
+ required this.maxHertz,
+ required this.songProgress});
+ final String minHertz;
+ final String maxHertz;
+ final int songProgress;
+
+ @override
+ State<FMPlayerSlider> createState() => _FMPlayerSliderState();
+}
+
+class _FMPlayerSliderState extends State<FMPlayerSlider> {
+ @override
+ Widget build(BuildContext context) {
+ return Row(
+ children: [
+ Text(
+ widget.minHertz,
+ style: TextStyle(
+ color: Colors.white,
+ fontSize: 26,
+ shadows: [Helpers.dropShadowRegular]),
+ ),
+ Expanded(
+ child: Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 40),
+ child: GradientProgressIndicator(
+ percent: widget.songProgress,
+ height: 10,
+ type: "fm",
+ gradient: LinearGradient(
+ begin: Alignment.centerLeft,
+ end: Alignment.centerRight,
+ colors: [
+ AGLDemoColors.jordyBlueColor,
+ AGLDemoColors.jordyBlueColor.withOpacity(0.8),
+ ]),
+ backgroundColor: AGLDemoColors.gradientBackgroundDarkColor,
+ ),
+ ),
+ ),
+ Text(
+ widget.maxHertz,
+ style: TextStyle(
+ color: Colors.white,
+ fontSize: 26,
+ shadows: [Helpers.dropShadowRegular]),
+ )
+ ],
+ );
+ }
+}
diff --git a/lib/presentation/screens/media_player/media_player.dart b/lib/presentation/screens/media_player/media_player.dart
new file mode 100644
index 0000000..9ec31e2
--- /dev/null
+++ b/lib/presentation/screens/media_player/media_player.dart
@@ -0,0 +1,99 @@
+import 'package:flutter_ics_homescreen/presentation/screens/media_player/fm_player.dart';
+
+import '/export.dart';
+import 'widgets/media_volume_bar.dart';
+
+class MediaPlayerPage extends StatelessWidget {
+ const MediaPlayerPage({super.key});
+
+ static Page<void> page() =>
+ const MaterialPage<void>(child: MediaPlayerPage());
+ @override
+ Widget build(BuildContext context) {
+ Size size = MediaQuery.sizeOf(context);
+
+ return Stack(
+ children: [
+ // SizedBox(
+ // width: size.width,
+ // height: size.height,
+ // //color: Colors.black,
+ // // decoration:
+ // // BoxDecoration(gradient: AGLDemoColors.gradientBackgroundColor),
+ // child: SvgPicture.asset(
+ // 'assets/MediaPlayerBackground.svg',
+ // alignment: Alignment.center,
+ // fit: BoxFit.cover,
+ // //width: 200,
+ // //height: 200,
+ // ),
+ // ),
+ SizedBox(
+ width: size.width,
+ height: size.height,
+ // color: Colors.black,
+ child: SvgPicture.asset(
+ 'assets/MediaPlayerBackgroundTextures.svg',
+ // alignment: Alignment.center,
+ fit: BoxFit.cover,
+ //width: 200,
+ //height: 200,
+ ),
+ ),
+ const Padding(
+ padding: EdgeInsets.symmetric(vertical: 50, horizontal: 50),
+ child: MediaPlayerBackground(),
+ )
+ //const MediaPlayer(),
+ ],
+ );
+ }
+}
+
+class MediaPlayerBackground extends StatefulWidget {
+ const MediaPlayerBackground({super.key});
+
+ @override
+ State<MediaPlayerBackground> createState() => _MediaPlayerBackgroundState();
+}
+
+class _MediaPlayerBackgroundState extends State<MediaPlayerBackground> {
+ String selectedNav = "My Media";
+ onPressed(type) {
+ setState(() {
+ selectedNav = type;
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return SingleChildScrollView(
+ child: Column(
+ children: [
+ const SizedBox(
+ height: 55,
+ ),
+ PlayerNavigation(
+ onPressed: (val) {
+ onPressed(val);
+ },
+ ),
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 144),
+ child: SingleChildScrollView(
+ child: selectedNav == "My Media"
+ ? const MediaPlayer()
+ : selectedNav == "FM"
+ ? const FMPlayer()
+ : Container(),
+ ),
+ ),
+ const Padding(
+ padding: EdgeInsets.symmetric(horizontal: 144, vertical: 23.5),
+ child: CustomVolumeSlider(),
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/screens/media_player/my_media.dart b/lib/presentation/screens/media_player/my_media.dart
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lib/presentation/screens/media_player/my_media.dart
diff --git a/lib/presentation/screens/media_player/play_list_table.dart b/lib/presentation/screens/media_player/play_list_table.dart
new file mode 100644
index 0000000..b17cfca
--- /dev/null
+++ b/lib/presentation/screens/media_player/play_list_table.dart
@@ -0,0 +1,154 @@
+import 'package:flutter_ics_homescreen/core/utils/helpers.dart';
+import 'package:flutter_ics_homescreen/export.dart';
+
+class PlayListTable extends StatefulWidget {
+ const PlayListTable(
+ {super.key,
+ required this.type,
+ required this.tableName,
+ required this.playList,
+ required this.selectedPlayListSongName});
+ final String type;
+ final String tableName;
+ final List<PlayListModel> playList;
+ final String selectedPlayListSongName;
+
+ @override
+ State<PlayListTable> createState() => _PlayListTableState();
+}
+
+class _PlayListTableState extends State<PlayListTable> {
+ bool isAudioSettingsEnabled = false;
+ late String tableName;
+ late List<PlayListModel> playList;
+ late String selectedPlayListSongName;
+ @override
+ void initState() {
+ tableName = widget.tableName;
+ playList = widget.playList;
+ selectedPlayListSongName = widget.selectedPlayListSongName;
+ super.initState();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Material(
+ color: Colors.transparent,
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Row(
+ children: [
+ Text(
+ tableName,
+ style: const TextStyle(
+ color: Colors.white,
+ fontWeight: FontWeight.w400,
+ fontSize: 40),
+ ),
+ if (widget.type == "media")
+ InkWell(
+ customBorder: const CircleBorder(),
+ onTap: () {},
+ child: Opacity(
+ opacity: 0.5,
+ child: Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: SvgPicture.asset(
+ "assets/AppleMusic.svg",
+ width: 32,
+ )),
+ )),
+ ],
+ ),
+ InkWell(
+ customBorder: const CircleBorder(),
+ onTap: () {
+ setState(() {
+ isAudioSettingsEnabled = !isAudioSettingsEnabled;
+ });
+ },
+ child: Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: SvgPicture.asset(
+ "assets/${isAudioSettingsEnabled ? "AudioSettingsPressed.svg" : "AudioSettings.svg"}",
+ width: 48,
+ )))
+ ],
+ ),
+ SizedBox(
+ height: 325,
+ child: SingleChildScrollView(
+ child: Column(
+ children: playList.map((index) {
+ return Container(
+ height: 100,
+ margin: const EdgeInsets.symmetric(vertical: 4),
+ decoration: BoxDecoration(
+ border: Border(
+ left: selectedPlayListSongName == index.songName
+ ? const BorderSide(
+ color: Colors.white, width: 4)
+ : BorderSide.none),
+ gradient: LinearGradient(
+ colors: selectedPlayListSongName == index.songName
+ ? [
+ AGLDemoColors.neonBlueColor,
+ AGLDemoColors.neonBlueColor
+ .withOpacity(0.15)
+ ]
+ : [
+ Colors.black,
+ Colors.black.withOpacity(0.20)
+ ])),
+ child: InkWell(
+ onTap: () {
+ setState(() {
+ selectedPlayListSongName = index.songName;
+ });
+ },
+ child: Padding(
+ padding: const EdgeInsets.symmetric(
+ vertical: 17, horizontal: 24),
+ child: Row(
+ children: [
+ Expanded(
+ flex: 6,
+ child: Text(
+ index.songName,
+ style: TextStyle(
+ color: Colors.white,
+ fontSize: 40,
+ shadows: [Helpers.dropShadowRegular]),
+ )),
+ Expanded(
+ flex: 4,
+ child: Text(
+ index.albumName,
+ style: TextStyle(
+ color: Colors.white,
+ fontSize: 26,
+ shadows: [Helpers.dropShadowRegular]),
+ ))
+ ],
+ ),
+ ),
+ ),
+ );
+ }).toList()),
+ ),
+ ),
+ ],
+ ));
+ }
+}
+
+class PlayListModel {
+ final String songName;
+ final String albumName;
+
+ PlayListModel({required this.songName, required this.albumName});
+}
diff --git a/lib/presentation/screens/media_player/player_navigation.dart b/lib/presentation/screens/media_player/player_navigation.dart
new file mode 100644
index 0000000..8e09e53
--- /dev/null
+++ b/lib/presentation/screens/media_player/player_navigation.dart
@@ -0,0 +1,80 @@
+import 'package:flutter_ics_homescreen/core/utils/helpers.dart';
+import 'package:flutter_ics_homescreen/export.dart';
+
+class PlayerNavigation extends StatefulWidget {
+ const PlayerNavigation({super.key, required this.onPressed});
+ final Function onPressed;
+
+ @override
+ State<PlayerNavigation> createState() => _PlayerNavigationState();
+}
+
+class _PlayerNavigationState extends State<PlayerNavigation> {
+ List<String> navItems = ["My Media", "FM", "AM", "XM"];
+ String selectedNav = "My Media";
+ @override
+ Widget build(BuildContext context) {
+ return Row(
+ children: navItems
+ .map((e) => Expanded(
+ child: Container(
+ margin: const EdgeInsets.symmetric(horizontal: 2),
+ decoration: BoxDecoration(
+ gradient: LinearGradient(colors: [
+ selectedNav == e
+ ? AGLDemoColors.neonBlueColor
+ : AGLDemoColors.buttonFillEnabledColor,
+ AGLDemoColors.gradientBackgroundDarkColor
+ ], begin: Alignment.topCenter, end: Alignment.bottomCenter),
+ // color: selectedNav == e
+ // ? AGLDemoColors.neonBlueColor
+ // : AGLDemoColors.buttonFillEnabledColor,
+ ),
+ child: Material(
+ color: Colors.transparent,
+ child: InkWell(
+ onTap: () {
+ setState(() {
+ selectedNav = e;
+ });
+ widget.onPressed(selectedNav);
+ },
+ child: Container(
+ padding: const EdgeInsets.symmetric(vertical: 7),
+ decoration: BoxDecoration(
+ border: Border(
+ left: selectedNav == e
+ ? const BorderSide(color: Colors.white12)
+ : BorderSide.none,
+ right: selectedNav == e
+ ? const BorderSide(color: Colors.white12)
+ : BorderSide.none,
+ top: BorderSide(
+ color: selectedNav == e
+ ? Colors.white
+ : Colors.white24,
+ width: selectedNav == e ? 2 : 1))),
+ child: Text(
+ e,
+ textAlign: TextAlign.center,
+ style: TextStyle(
+ fontSize: 26,
+ shadows: [
+ selectedNav == e
+ ? Helpers.dropShadowRegular
+ : Helpers.dropShadowBig
+ ],
+ color: selectedNav == e
+ ? Colors.white
+ : AGLDemoColors.periwinkleColor,
+ fontWeight: selectedNav == e
+ ? FontWeight.w700
+ : FontWeight.w500),
+ ),
+ ),
+ ),
+ ),
+ )))
+ .toList());
+ }
+}
diff --git a/lib/presentation/screens/media_player/segmented_buttons.dart b/lib/presentation/screens/media_player/segmented_buttons.dart
new file mode 100644
index 0000000..e649be3
--- /dev/null
+++ b/lib/presentation/screens/media_player/segmented_buttons.dart
@@ -0,0 +1,82 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+class SegmentedButtons extends StatefulWidget {
+ const SegmentedButtons(
+ {super.key, required this.navItems, required this.selectedNav});
+
+ final List<String> navItems;
+ final String selectedNav;
+ @override
+ State<SegmentedButtons> createState() => _SegmentedButtonsState();
+}
+
+class _SegmentedButtonsState extends State<SegmentedButtons> {
+ late List<String> navItems;
+ late String selectedNav;
+
+ @override
+ void initState() {
+ navItems = widget.navItems;
+ selectedNav = widget.selectedNav;
+ super.initState();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Container(
+ margin: const EdgeInsets.only(top: 40),
+ padding: const EdgeInsets.all(3),
+ decoration: BoxDecoration(
+ boxShadow: [
+ BoxShadow(
+ offset: const Offset(0, 4),
+ blurRadius: 4,
+ color: Colors.black.withOpacity(0.25))
+ ],
+ borderRadius: BorderRadius.circular(40),
+ color: AGLDemoColors.buttonFillEnabledColor,
+ border: Border.all(color: Colors.white12),
+ ),
+ child: Row(
+ children: navItems
+ .map((e) => Container(
+ padding: const EdgeInsets.symmetric(
+ vertical: 24, horizontal: 32),
+ decoration: BoxDecoration(
+ borderRadius: selectedNav == e
+ ? BorderRadius.circular(40)
+ : BorderRadius.zero,
+ color: selectedNav == e
+ ? AGLDemoColors.backgroundInsetColor
+ : null,
+ ),
+ child: InkWell(
+ borderRadius: BorderRadius.circular(40),
+ onTap: () {
+ setState(() {
+ selectedNav = e;
+ });
+ },
+ child: Text(
+ e,
+ style: TextStyle(
+ color: selectedNav == e
+ ? Colors.white
+ : AGLDemoColors.periwinkleColor,
+ fontSize: 26,
+ fontWeight: selectedNav == e
+ ? FontWeight.w700
+ : FontWeight.w500),
+ ),
+ ),
+ ))
+ .toList(),
+ ),
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/presentation/screens/media_player/widgets/gradient_progress_indicator.dart b/lib/presentation/screens/media_player/widgets/gradient_progress_indicator.dart
new file mode 100644
index 0000000..24aa244
--- /dev/null
+++ b/lib/presentation/screens/media_player/widgets/gradient_progress_indicator.dart
@@ -0,0 +1,88 @@
+import 'package:flutter_ics_homescreen/core/utils/helpers.dart';
+import 'package:flutter_ics_homescreen/export.dart';
+
+class GradientProgressIndicator extends StatelessWidget {
+ ///it can be anything between 0 to 100
+ final int percent;
+ final Gradient gradient;
+ final Color backgroundColor;
+ final double height;
+ final String type;
+
+ const GradientProgressIndicator(
+ {required this.percent,
+ required this.gradient,
+ required this.backgroundColor,
+ Key? key,
+ this.height = 16,
+ required this.type})
+ : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return Row(
+ children: [
+ Flexible(
+ flex: percent,
+ fit: FlexFit.tight,
+ child: Container(
+ height: height,
+ margin: const EdgeInsets.all(1),
+ decoration: BoxDecoration(
+ border: Border.all(
+ color: AGLDemoColors.neonBlueColor.withOpacity(0.5),
+ width: 1),
+ gradient: gradient,
+ borderRadius:
+ BorderRadius.all(Radius.circular(type == "fm" ? 16 : 2)),
+ ),
+ alignment: Alignment.centerRight,
+ ),
+ ),
+ type == "media"
+ ? Container(
+ height: height,
+ width: 2,
+ color: Colors.white,
+ )
+ : Container(
+ height: 64,
+ width: 64,
+ alignment: Alignment.center,
+ decoration: BoxDecoration(
+ shape: BoxShape.circle,
+ boxShadow: [
+ Helpers.boxDropShadowRegular,
+ ],
+ color: AGLDemoColors.periwinkleColor),
+ child: Container(
+ height: 32,
+ width: 32,
+ decoration: BoxDecoration(
+ shape: BoxShape.circle,
+ boxShadow: [
+ Helpers.boxDropShadowRegular,
+ ],
+ border: Border.all(
+ color: AGLDemoColors.neonBlueColor, width: 2),
+ color: AGLDemoColors.periwinkleColor),
+ ),
+ ),
+ Flexible(
+ fit: FlexFit.tight,
+ flex: 100 - percent,
+ child: Container(
+ decoration: BoxDecoration(
+ color: backgroundColor,
+ border: Border.all(
+ color: AGLDemoColors.neonBlueColor.withOpacity(0.5),
+ width: 1),
+ borderRadius: const BorderRadius.all(Radius.circular(2)),
+ ),
+ child: SizedBox(height: height),
+ ),
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/presentation/screens/media_player/widgets/media_volume_bar.dart b/lib/presentation/screens/media_player/widgets/media_volume_bar.dart
new file mode 100644
index 0000000..f8d58e6
--- /dev/null
+++ b/lib/presentation/screens/media_player/widgets/media_volume_bar.dart
@@ -0,0 +1,117 @@
+import 'package:flutter_ics_homescreen/presentation/custom_icons/custom_icons.dart';
+
+import '../../../../export.dart';
+import '../../settings/settings_screens/audio_settings/widget/slider_widgets.dart';
+
+class CustomVolumeSlider extends ConsumerStatefulWidget {
+ const CustomVolumeSlider({
+ super.key,
+ });
+
+ @override
+ CustomVolumeSliderState createState() => CustomVolumeSliderState();
+}
+
+class CustomVolumeSliderState extends ConsumerState<CustomVolumeSlider> {
+ void _increase() {
+ setState(() {
+ if (_currentVal < 20) {
+ _currentVal++;
+ ref.read(audioStateProvider.notifier).setVolume(_currentVal);
+ }
+ });
+ }
+
+ void _dercrease() {
+ setState(() {
+ if (_currentVal > 0) {
+ _currentVal--;
+ ref.read(audioStateProvider.notifier).setVolume(_currentVal);
+ }
+ });
+ }
+
+ double _currentVal = 5;
+ @override
+ Widget build(BuildContext context) {
+ final volumeValue =
+ ref.watch(audioStateProvider.select((audio) => audio.volume));
+
+ return Column(
+ //crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ Container(
+ decoration: const ShapeDecoration(
+ color: AGLDemoColors.buttonFillEnabledColor,
+ shape: StadiumBorder(
+ side: BorderSide(
+ color: Color(0xFF5477D4),
+ width: 0.5,
+ )),
+ ),
+ height: 160,
+ child: Row(
+ children: [
+ Padding(
+ padding: const EdgeInsets.only(left: 10.0),
+ child: SizedBox(
+ width: 50,
+ child: IconButton(
+ padding: EdgeInsets.zero,
+ onPressed: () {
+ _dercrease();
+ },
+ icon: const Icon(
+ CustomIcons.vol_min,
+ color: AGLDemoColors.periwinkleColor,
+ size: 48,
+ )),
+ ),
+ ),
+ Expanded(
+ child: SliderTheme(
+ data: SliderThemeData(
+ overlayShape: SliderComponentShape.noOverlay,
+ valueIndicatorShape: SliderComponentShape.noOverlay,
+ activeTickMarkColor: Colors.transparent,
+ inactiveTickMarkColor: Colors.transparent,
+ inactiveTrackColor: AGLDemoColors.backgroundInsetColor,
+ thumbShape: const PolygonSliderThumb(
+ sliderValue: 3, thumbRadius: 23),
+ //trackHeight: 5,
+ ),
+ child: Slider(
+ divisions: 20,
+ min: 0,
+ max: 20,
+ value: volumeValue,
+ onChanged: (newValue) {
+ ref.read(audioStateProvider.notifier).setVolume(newValue);
+ _currentVal = newValue;
+ },
+ ),
+ ),
+ ),
+ Padding(
+ padding: const EdgeInsets.only(right: 10.0),
+ child: SizedBox(
+ width: 60,
+ child: IconButton(
+ padding: EdgeInsets.zero,
+ onPressed: () {
+ _increase();
+ },
+ icon: const Icon(
+ CustomIcons.vol_max,
+ color: AGLDemoColors.periwinkleColor,
+ size: 48,
+ )),
+ ),
+ ),
+ ],
+ ),
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/presentation/screens/settings/settings.dart b/lib/presentation/screens/settings/settings.dart
new file mode 100644
index 0000000..aa0c150
--- /dev/null
+++ b/lib/presentation/screens/settings/settings.dart
@@ -0,0 +1,26 @@
+import '/export.dart';
+import 'widgets/settings_content.dart';
+
+class SettingsPage extends StatelessWidget {
+ const SettingsPage({super.key});
+
+ static Page<void> page() => const MaterialPage<void>(child: SettingsPage());
+ @override
+ Widget build(BuildContext context) {
+ return const SettingsContent();
+ }
+}
+
+class SettingsContent extends StatelessWidget {
+ const SettingsContent({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return const Stack(
+ children: [
+ Settings(),
+ ],
+ );
+ }
+}
+
diff --git a/lib/presentation/screens/settings/settings_screens/audio_settings/audio_settings_screen.dart b/lib/presentation/screens/settings/settings_screens/audio_settings/audio_settings_screen.dart
new file mode 100644
index 0000000..3c3508e
--- /dev/null
+++ b/lib/presentation/screens/settings/settings_screens/audio_settings/audio_settings_screen.dart
@@ -0,0 +1,30 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+import 'widget/audio_content.dart';
+
+
+class AudioSettingsPage extends ConsumerWidget {
+ const AudioSettingsPage({super.key});
+
+ static Page<void> page() =>
+ const MaterialPage<void>(child: AudioSettingsPage());
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ return Scaffold(
+ body: Column(
+ children: [
+ CommonTitle(
+ title: 'Audio Settings',
+ hasBackButton: true,
+ onPressed: () {
+ context.flow<AppState>().update((state) => AppState.settings);
+ },
+ ),
+ const Expanded(
+ child: AudioContent()),
+ ],
+ ),
+ );
+ }
+}
+
diff --git a/lib/presentation/screens/settings/settings_screens/audio_settings/widget/audio_content.dart b/lib/presentation/screens/settings/settings_screens/audio_settings/widget/audio_content.dart
new file mode 100644
index 0000000..8fb0437
--- /dev/null
+++ b/lib/presentation/screens/settings/settings_screens/audio_settings/widget/audio_content.dart
@@ -0,0 +1,41 @@
+import '../../../../../../export.dart';
+import 'slider_widgets.dart';
+
+class AudioContent extends ConsumerWidget {
+ const AudioContent({
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ return Padding(
+ padding: const EdgeInsets.symmetric(vertical: 50, horizontal: 144),
+ child: Column(
+ children: [
+ const Expanded(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ CustomTrebleSlider(),
+ CustomBassSlider(),
+ CustomRearFrontSlider(),
+ ],
+ ),
+ ),
+ Padding(
+ padding: const EdgeInsets.only(bottom: 150),
+ child: GenericButton(
+ heigth: 130,
+ width: 420,
+ text: 'Reset to Default',
+ onTap: () {
+ ref.read(audioStateProvider.notifier).resetToDefaults();
+ },
+ ),
+
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/screens/settings/settings_screens/audio_settings/widget/slider_widgets.dart b/lib/presentation/screens/settings/settings_screens/audio_settings/widget/slider_widgets.dart
new file mode 100644
index 0000000..973c9bf
--- /dev/null
+++ b/lib/presentation/screens/settings/settings_screens/audio_settings/widget/slider_widgets.dart
@@ -0,0 +1,603 @@
+import 'package:flutter_ics_homescreen/export.dart';
+import 'package:flutter_ics_homescreen/presentation/custom_icons/custom_icons.dart';
+
+class CustomTrebleSlider extends ConsumerStatefulWidget {
+ const CustomTrebleSlider({
+ super.key,
+ });
+
+ @override
+ CustomTrebleSliderState createState() => CustomTrebleSliderState();
+}
+
+class CustomTrebleSliderState extends ConsumerState<CustomTrebleSlider> {
+ bool isPressed = false;
+ void _increase() {
+ setState(() {
+ if (_currentVal < 10) {
+ _currentVal++;
+ ref.read(audioStateProvider.notifier).setTreble(_currentVal);
+ }
+ });
+ }
+
+ void _dercrease() {
+ setState(() {
+ if (_currentVal > 0) {
+ _currentVal--;
+ ref.read(audioStateProvider.notifier).setTreble(_currentVal);
+ }
+ });
+ }
+
+ double _currentVal = 5;
+ @override
+ Widget build(BuildContext context) {
+ final trebleValue =
+ ref.watch(audioStateProvider.select((audio) => audio.treble));
+ return Column(
+ //crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ const Padding(
+ padding: EdgeInsets.symmetric(vertical: 8),
+ child: Text(
+ 'Treble',
+ style: TextStyle(fontSize: 40),
+ ),
+ ),
+ Container(
+ width: 792,
+ height: 160,
+ decoration: const ShapeDecoration(
+ gradient: LinearGradient(
+ colors: <Color>[
+ AGLDemoColors.neonBlueColor,
+ AGLDemoColors.resolutionBlueColor,
+ Color.fromARGB(127, 20, 31, 100),
+ Color(0xFF2962FF)
+ ],
+ stops: [0, 0, 1, 1],
+ ),
+ shape: StadiumBorder(
+ side: BorderSide(
+ color: Color(0xFF5477D4),
+ width: 1,
+ )),
+ ),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Padding(
+ padding: const EdgeInsets.only(left: 40),
+ child: InkWell(
+ onTap: () {
+ _dercrease();
+ },
+ child: const Icon(
+ Icons.remove,
+ color: AGLDemoColors.periwinkleColor,
+ size: 48,
+ ),
+ ),
+ ),
+ SizedBox(
+ width: 584,
+ child: SliderTheme(
+ data: SliderThemeData(
+ showValueIndicator: ShowValueIndicator.always,
+ trackShape: CustomRoundedRectSliderTrackShape(
+ silderVal: trebleValue),
+ activeTickMarkColor: Colors.transparent,
+ inactiveTickMarkColor: Colors.transparent,
+ inactiveTrackColor: AGLDemoColors.backgroundInsetColor,
+ thumbShape: PolygonSliderThumb(
+ sliderValue: 3, thumbRadius: 23, isPressed: isPressed),
+ trackHeight: 16,
+ ),
+ child: Slider(
+ divisions: 10,
+ min: 0,
+ max: 10,
+ value: trebleValue,
+ onChanged: (newValue) {
+ ref.read(audioStateProvider.notifier).setTreble(newValue);
+ _currentVal = newValue;
+ },
+ onChangeEnd: (value) {
+ setState(() {
+ isPressed = false;
+ });
+ },
+ onChangeStart: (value) {
+ setState(() {
+ isPressed = true;
+ });
+ },
+ ),
+ ),
+ ),
+
+ Padding(
+ padding: const EdgeInsets.only(
+ right: 40,
+ ),
+ child: InkWell(
+ onTap: () {
+ _increase();
+ },
+ child: const Icon(
+ Icons.add,
+ color: AGLDemoColors.periwinkleColor,
+ size: 48,
+ )),
+ ),
+ ],
+ ),
+ ),
+ ],
+ );
+ }
+}
+
+class CustomBassSlider extends ConsumerStatefulWidget {
+ const CustomBassSlider({
+ super.key,
+ });
+
+ @override
+ CustomBassSliderState createState() => CustomBassSliderState();
+}
+
+class CustomBassSliderState extends ConsumerState<CustomBassSlider> {
+ bool isPressed = false;
+
+ void _increase() {
+ setState(() {
+ if (_currentVal < 10) {
+ _currentVal++;
+ ref.read(audioStateProvider.notifier).setBass(_currentVal);
+ }
+ });
+ }
+
+ void _dercrease() {
+ setState(() {
+ if (_currentVal > 0) {
+ _currentVal--;
+ ref.read(audioStateProvider.notifier).setBass(_currentVal);
+ }
+ });
+ }
+
+ double _currentVal = 5;
+ @override
+ Widget build(BuildContext context) {
+ final bassValue =
+ ref.watch(audioStateProvider.select((audio) => audio.bass));
+
+ return Column(
+ //crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ const Padding(
+ padding: EdgeInsets.symmetric(vertical: 8),
+ child: Text(
+ 'Bass',
+ style: TextStyle(fontSize: 40),
+ ),
+ ),
+ Container(
+ width: 792,
+ height: 160,
+ decoration: const ShapeDecoration(
+ gradient: LinearGradient(
+ colors: <Color>[
+ AGLDemoColors.neonBlueColor,
+ AGLDemoColors.resolutionBlueColor,
+ Color.fromARGB(127, 20, 31, 100),
+ Color(0xFF2962FF)
+ ],
+ stops: [0, 0, 1, 1],
+ ),
+ shape: StadiumBorder(
+ side: BorderSide(
+ color: Color(0xFF5477D4),
+ width: 1,
+ )),
+ ),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Padding(
+ padding: const EdgeInsets.only(left: 40),
+ child: InkWell(
+ onTap: () {
+ _dercrease();
+ },
+ child: const Icon(
+ Icons.remove,
+ color: AGLDemoColors.periwinkleColor,
+ size: 48,
+ )),
+ ),
+ SizedBox(
+ width: 584,
+ child: SliderTheme(
+ data: SliderThemeData(
+ showValueIndicator: ShowValueIndicator.always,
+ trackShape:
+ CustomRoundedRectSliderTrackShape(silderVal: bassValue),
+ activeTickMarkColor: Colors.transparent,
+ inactiveTickMarkColor: Colors.transparent,
+ inactiveTrackColor: AGLDemoColors.backgroundInsetColor,
+ thumbShape: PolygonSliderThumb(
+ sliderValue: 3, thumbRadius: 23, isPressed: isPressed),
+ trackHeight: 16,
+ ),
+ child: Slider(
+ divisions: 10,
+ min: 0,
+ max: 10,
+ value: bassValue,
+ onChanged: (newValue) {
+ ref.read(audioStateProvider.notifier).setBass(newValue);
+ _currentVal = newValue;
+ },
+ onChangeEnd: (value) {
+ setState(() {
+ isPressed = false;
+ });
+ },
+ onChangeStart: (value) {
+ setState(() {
+ isPressed = true;
+ });
+ },
+ ),
+ ),
+ ),
+ Padding(
+ padding: const EdgeInsets.only(right: 40),
+ child: InkWell(
+ onTap: () {
+ _increase();
+ },
+ child: const Icon(
+ Icons.add,
+ color: AGLDemoColors.periwinkleColor,
+ size: 48,
+ )),
+ ),
+ ],
+ ),
+ ),
+ ],
+ );
+ }
+}
+
+class CustomRearFrontSlider extends ConsumerStatefulWidget {
+ const CustomRearFrontSlider({
+ super.key,
+ });
+
+ @override
+ CustomRearFrontState createState() => CustomRearFrontState();
+}
+
+class CustomRearFrontState extends ConsumerState<CustomRearFrontSlider> {
+ bool isPressed = false;
+
+ void _increase() {
+ setState(() {
+ if (_currentVal < 10) {
+ _currentVal++;
+ ref.read(audioStateProvider.notifier).setRearFront(_currentVal);
+ }
+ });
+ }
+
+ void _dercrease() {
+ setState(() {
+ if (_currentVal > 0) {
+ _currentVal--;
+ ref.read(audioStateProvider.notifier).setRearFront(_currentVal);
+ }
+ });
+ }
+
+ double _currentVal = 5;
+ @override
+ Widget build(BuildContext context) {
+ final rearFrontValue =
+ ref.watch(audioStateProvider.select((audio) => audio.rearFront));
+ return Column(
+ //crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ const Padding(
+ padding: EdgeInsets.symmetric(vertical: 8),
+ child: Text(
+ 'Rear/Front',
+ style: TextStyle(fontSize: 40),
+ ),
+ ),
+ Container(
+ width: 792,
+ height: 160,
+ decoration: const ShapeDecoration(
+ gradient: LinearGradient(
+ colors: <Color>[
+ AGLDemoColors.neonBlueColor,
+ AGLDemoColors.resolutionBlueColor,
+ Color.fromARGB(127, 20, 31, 100),
+ Color(0xFF2962FF)
+ ],
+ stops: [0, 0, 1, 1],
+ ),
+ shape: StadiumBorder(
+ side: BorderSide(
+ color: Color(0xFF5477D4),
+ width: 1,
+ )),
+ ),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Padding(
+ padding: const EdgeInsets.only(left: 40),
+ child: InkWell(
+ onTap: () {
+ _dercrease();
+ },
+ child: const Icon(
+ CustomIcons.slider_rear,
+ color: AGLDemoColors.periwinkleColor,
+ size: 48,
+ )),
+ ),
+ SizedBox(
+ width: 584,
+ child: SliderTheme(
+ data: SliderThemeData(
+ showValueIndicator: ShowValueIndicator.always,
+ trackShape: CustomRoundedRectSliderTrackShape(
+ silderVal: rearFrontValue, isFrontRear: true),
+ activeTickMarkColor: Colors.transparent,
+ inactiveTickMarkColor: Colors.transparent,
+ inactiveTrackColor: AGLDemoColors.backgroundInsetColor,
+ thumbShape: PolygonSliderThumb(
+ sliderValue: 3, thumbRadius: 23, isPressed: isPressed),
+ trackHeight: 16,
+ ),
+ child: Slider(
+ divisions: 10,
+ min: 0,
+ max: 10,
+ value: rearFrontValue,
+ onChanged: (newValue) {
+ ref
+ .read(audioStateProvider.notifier)
+ .setRearFront(newValue);
+ _currentVal = newValue;
+ },
+ onChangeEnd: (value) {
+ setState(() {
+ isPressed = false;
+ });
+ },
+ onChangeStart: (value) {
+ setState(() {
+ isPressed = true;
+ });
+ },
+ ),
+ ),
+ ),
+ Padding(
+ padding: const EdgeInsets.only(right: 40),
+ child: InkWell(
+ onTap: () {
+ _increase();
+ },
+ child: const Icon(
+ CustomIcons.slider_front,
+ color: AGLDemoColors.periwinkleColor,
+ size: 48,
+ )),
+ ),
+ ],
+ ),
+ ),
+ ],
+ );
+ }
+}
+
+class PolygonSliderThumb extends SliderComponentShape {
+ final double thumbRadius;
+ final double sliderValue;
+ final bool isPressed;
+ const PolygonSliderThumb(
+ {required this.thumbRadius,
+ required this.sliderValue,
+ this.isPressed = false});
+
+ @override
+ Size getPreferredSize(bool isEnabled, bool isDiscrete) {
+ return Size.fromRadius(thumbRadius);
+ }
+
+ @override
+ void paint(
+ PaintingContext context,
+ Offset center, {
+ required Animation<double> activationAnimation,
+ required Animation<double> enableAnimation,
+ required bool isDiscrete,
+ required TextPainter labelPainter,
+ required RenderBox parentBox,
+ required SliderThemeData sliderTheme,
+ required TextDirection textDirection,
+ required double value,
+ required double textScaleFactor,
+ required Size sizeWithOverflow,
+ }) {
+ // Define the slider thumb design here
+ final Canvas canvas = context.canvas;
+ var paintStroke = Paint()
+ ..color =
+ isPressed ? AGLDemoColors.jordyBlueColor : AGLDemoColors.neonBlueColor
+ ..strokeWidth = 2
+ ..style = PaintingStyle.stroke
+ ..strokeCap = StrokeCap.round;
+ var paintFill = Paint()
+ ..color = isPressed ? Colors.white : AGLDemoColors.periwinkleColor
+ ..strokeWidth = 2
+ ..style = PaintingStyle.fill
+ ..strokeCap = StrokeCap.round;
+ var path = Path();
+ path.addOval(Rect.fromCircle(
+ center: center,
+ radius: 9,
+ ));
+ canvas.drawCircle(center, isPressed ? 37 : 32, paintFill);
+ canvas.drawShadow(path, Colors.black26, 0.5, false);
+ canvas.drawCircle(center, isPressed ? 21 : 16, paintStroke);
+ }
+}
+
+//TODO add border to custom track Shape
+class CustomRoundedRectSliderTrackShape extends SliderTrackShape
+ with BaseSliderTrackShape {
+ final double silderVal;
+ final bool? isFrontRear;
+
+ CustomRoundedRectSliderTrackShape({
+ required this.silderVal,
+ this.isFrontRear = false,
+ });
+ @override
+ void paint(
+ PaintingContext context,
+ Offset offset, {
+ required RenderBox parentBox,
+ required SliderThemeData sliderTheme,
+ required Animation<double> enableAnimation,
+ required TextDirection textDirection,
+ required Offset thumbCenter,
+ Offset? secondaryOffset,
+ bool isDiscrete = false,
+ bool isEnabled = false,
+ double additionalActiveTrackHeight = 2,
+ }) {
+ assert(sliderTheme.disabledActiveTrackColor != null);
+ assert(sliderTheme.disabledInactiveTrackColor != null);
+ assert(sliderTheme.activeTrackColor != null);
+ assert(sliderTheme.inactiveTrackColor != null);
+ assert(sliderTheme.thumbShape != null);
+ if (sliderTheme.trackHeight == null || sliderTheme.trackHeight! <= 0) {
+ return;
+ }
+
+ final Rect trackRect = getPreferredRect(
+ parentBox: parentBox,
+ offset: offset,
+ sliderTheme: sliderTheme,
+ isEnabled: isEnabled,
+ isDiscrete: isDiscrete,
+ );
+ final Radius trackRadius = Radius.circular(trackRect.height / 2);
+ final Radius activeTrackRadius =
+ Radius.circular((trackRect.height + additionalActiveTrackHeight) / 2);
+ final activeGradientRect = Rect.fromLTRB(
+ trackRect.left,
+ textDirection == TextDirection.ltr
+ ? trackRect.top - (additionalActiveTrackHeight / 2)
+ : trackRect.top,
+ thumbCenter.dx,
+ (textDirection == TextDirection.ltr)
+ ? trackRect.bottom + (additionalActiveTrackHeight / 2)
+ : trackRect.bottom,
+ );
+
+ LinearGradient gradient = const LinearGradient(
+ colors: [AGLDemoColors.jordyBlueColor, Colors.white]);
+ // Assign the track segment paints, which are leading: active and
+ // trailing: inactive.
+ final ColorTween activeTrackColorTween = ColorTween(
+ begin: sliderTheme.disabledActiveTrackColor,
+ end: sliderTheme.activeTrackColor);
+ final ColorTween inactiveTrackColorTween = ColorTween(
+ begin: sliderTheme.disabledInactiveTrackColor,
+ end: sliderTheme.inactiveTrackColor);
+ final Paint activePaint = Paint()
+ ..shader = gradient.createShader(activeGradientRect)
+ ..color = activeTrackColorTween.evaluate(enableAnimation)!;
+ final Paint inactivePaint = Paint()
+ ..color = inactiveTrackColorTween.evaluate(enableAnimation)!;
+ final Paint leftTrackPaint;
+ final Paint rightTrackPaint;
+ switch (textDirection) {
+ case TextDirection.ltr:
+ leftTrackPaint = activePaint;
+ rightTrackPaint = inactivePaint;
+ case TextDirection.rtl:
+ leftTrackPaint = inactivePaint;
+ rightTrackPaint = activePaint;
+ }
+ //center divider
+ final smallRect =
+ Rect.fromLTWH(trackRect.right / 2, trackRect.bottom / 2 + 15, 10, 40);
+ context.canvas.drawRRect(
+ RRect.fromRectAndCorners(smallRect,
+ topLeft: const Radius.circular(25),
+ topRight: const Radius.circular(25),
+ bottomLeft: const Radius.circular(25),
+ bottomRight: const Radius.circular(25)),
+ //silderVal > 5 ? leftTrackPaint : rightTrackPaint);
+ isFrontRear!
+ ? rightTrackPaint
+ : silderVal > 5
+ ? leftTrackPaint
+ : rightTrackPaint);
+//active
+ context.canvas.drawRRect(
+ RRect.fromLTRBAndCorners(
+ trackRect.left,
+ (textDirection == TextDirection.ltr)
+ ? trackRect.top - (additionalActiveTrackHeight / 2)
+ : trackRect.top,
+ thumbCenter.dx,
+ (textDirection == TextDirection.ltr)
+ ? trackRect.bottom + (additionalActiveTrackHeight / 2)
+ : trackRect.bottom,
+ topLeft: (textDirection == TextDirection.ltr)
+ ? activeTrackRadius
+ : trackRadius,
+ bottomLeft: (textDirection == TextDirection.ltr)
+ ? activeTrackRadius
+ : trackRadius,
+ ),
+ isFrontRear! ? rightTrackPaint : leftTrackPaint,
+ );
+ //inactive
+ context.canvas.drawRRect(
+ RRect.fromLTRBAndCorners(
+ thumbCenter.dx,
+ (textDirection == TextDirection.rtl)
+ ? trackRect.top - (additionalActiveTrackHeight / 2)
+ : trackRect.top,
+ trackRect.right,
+ (textDirection == TextDirection.rtl)
+ ? trackRect.bottom + (additionalActiveTrackHeight / 2)
+ : trackRect.bottom,
+ topRight: (textDirection == TextDirection.rtl)
+ ? activeTrackRadius
+ : trackRadius,
+ bottomRight: (textDirection == TextDirection.rtl)
+ ? activeTrackRadius
+ : trackRadius,
+ ),
+ rightTrackPaint,
+ );
+ }
+}
diff --git a/lib/presentation/screens/settings/settings_screens/bluetooth/bluetooth_screen.dart b/lib/presentation/screens/settings/settings_screens/bluetooth/bluetooth_screen.dart
new file mode 100644
index 0000000..fe53953
--- /dev/null
+++ b/lib/presentation/screens/settings/settings_screens/bluetooth/bluetooth_screen.dart
@@ -0,0 +1,12 @@
+import 'package:flutter_ics_homescreen/export.dart';
+import 'widgets/bluetooth_content.dart';
+
+class BluetoothPage extends ConsumerWidget {
+ const BluetoothPage({super.key});
+
+ static Page<void> page() => const MaterialPage<void>(child: BluetoothPage());
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ return const Scaffold(body: BluetoothContent());
+ }
+}
diff --git a/lib/presentation/screens/settings/settings_screens/bluetooth/widgets/bluetooth.dart b/lib/presentation/screens/settings/settings_screens/bluetooth/widgets/bluetooth.dart
new file mode 100644
index 0000000..39ba417
--- /dev/null
+++ b/lib/presentation/screens/settings/settings_screens/bluetooth/widgets/bluetooth.dart
@@ -0,0 +1,12 @@
+import '../../../../../../export.dart';
+
+class Bluetooth {
+ final Icon icon;
+ final String name;
+ final bool? isConnected;
+ Bluetooth({
+ required this.icon,
+ required this.name,
+ this.isConnected = false,
+ });
+}
diff --git a/lib/presentation/screens/settings/settings_screens/bluetooth/widgets/bluetooth_content.dart b/lib/presentation/screens/settings/settings_screens/bluetooth/widgets/bluetooth_content.dart
new file mode 100644
index 0000000..446a3b5
--- /dev/null
+++ b/lib/presentation/screens/settings/settings_screens/bluetooth/widgets/bluetooth_content.dart
@@ -0,0 +1,219 @@
+import 'package:flutter_ics_homescreen/presentation/custom_icons/custom_icons.dart';
+
+import '../../../../../../../export.dart';
+import 'bluetooth.dart';
+
+class BluetoothContent extends ConsumerStatefulWidget {
+ const BluetoothContent({
+ super.key,
+ });
+
+ @override
+ BluetoothContentState createState() => BluetoothContentState();
+}
+
+class BluetoothContentState extends ConsumerState<BluetoothContent> {
+ final List<Bluetooth> btList = [
+ Bluetooth(
+ icon: const Icon(CustomIcons.wifi_4_bar_unlocked),
+ name: 'bt',
+ isConnected: true),
+ Bluetooth(
+ icon: const Icon(CustomIcons.wifi_4_bar_locked), name: 'BT Phone 0'),
+ Bluetooth(
+ icon: const Icon(CustomIcons.wifi_3_bar_locked), name: 'BT Phone 1'),
+ Bluetooth(
+ icon: const Icon(CustomIcons.wifi_2_bar_locked), name: 'BT Phone 2'),
+ Bluetooth(
+ icon: const Icon(CustomIcons.wifi_1_bar_locked), name: 'BT Phone 1'),
+ ];
+ bool isLoading = false;
+ Bluetooth currentBt =
+ Bluetooth(icon: const Icon(Icons.wifi), name: '22', isConnected: true);
+ @override
+ void initState() {
+ currentBt = btList[0];
+ super.initState();
+ }
+
+ void setCurrentBt(int index) async {
+ if (currentBt == btList[index]) return;
+ isLoading = true;
+ setState(() {
+ currentBt = btList[index];
+ });
+ Future.delayed(const Duration(seconds: 2), () {
+ setState(() {
+ isLoading = false;
+ });
+ });
+ }
+
+ void removeBtPair(int index) {
+ setState(() {
+ btList.removeAt(index);
+ });
+ }
+
+ void disconnect() {
+ setState(() {
+ currentBt = Bluetooth(
+ icon: const Icon(
+ Icons.bluetooth_disabled,
+ ),
+ name: '');
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ ref.watch(usersProvider.select((user) => user.selectedUser));
+
+ return Column(
+ children: [
+ CommonTitle(
+ title: "Bluetooth",
+ hasBackButton: true,
+ onPressed: () {
+ context.flow<AppState>().update((state) => AppState.settings);
+ },
+ ),
+ Expanded(
+ child: ListView.separated(
+ padding: const EdgeInsets.symmetric(vertical: 50, horizontal: 144),
+ itemCount: btList.length,
+ separatorBuilder: (context, index) {
+ return const SizedBox(
+ height: 8,
+ );
+ },
+ itemBuilder: (context, index) {
+ return Container(
+ height: 130,
+ alignment: Alignment.center,
+ decoration: BoxDecoration(
+ gradient: LinearGradient(
+ begin: Alignment.centerLeft,
+ end: Alignment.centerRight,
+ stops: currentBt == btList[index]
+ ? [0, 0.01, 0.8]
+ : [0.1, 1],
+ colors: currentBt == btList[index]
+ ? <Color>[
+ Colors.white,
+ Colors.blue,
+ const Color.fromARGB(16, 41, 98, 255)
+ ]
+ : <Color>[Colors.black, Colors.black12]),
+ ),
+ child: InkWell(
+ onTap: () {
+ setCurrentBt(index);
+ },
+ child: Padding(
+ padding: const EdgeInsets.symmetric(
+ vertical: 17, horizontal: 24),
+ child: Row(children: [
+ Expanded(
+ child: Text(
+ btList[index].name,
+ //style: Theme.of(context).textTheme.titleMedium,
+ style: TextStyle(
+ color: currentBt == btList[index]
+ ? Colors.white
+ : AGLDemoColors.periwinkleColor,
+ fontSize: 40),
+ ),
+ ),
+ currentBt == btList[index]
+ ? Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ isLoading
+ ? const Padding(
+ padding: EdgeInsets.only(right: 15.0),
+ child: Text(
+ 'Connecting...',
+ style: TextStyle(fontSize: 26),
+ ),
+ )
+ : Padding(
+ padding:
+ const EdgeInsets.only(right: 8.0),
+ child: ElevatedButton(
+ style: ElevatedButton.styleFrom(
+ backgroundColor:
+ const Color(0xFF1C2D92),
+ side: const BorderSide(
+ color: Color(0xFF285DF4),
+ width: 2),
+ ),
+ child: const Padding(
+ padding: EdgeInsets.all(18),
+ child: Text(
+ 'Disconnect',
+ style: TextStyle(
+ color: Color(0xFFC1D8FF),
+ fontSize: 26,
+ ),
+ ),
+ ),
+ onPressed: () {
+ disconnect();
+ },
+ ),
+ ),
+ isLoading
+ ? const SizedBox(
+ width: 48,
+ height: 48,
+ child: CircularProgressIndicator(
+ strokeWidth: 3,
+ ))
+ : IconButton(
+ padding: EdgeInsets.zero,
+ onPressed: () {
+ removeBtPair(index);
+ },
+ icon: const Icon(
+ Icons.close,
+ color: AGLDemoColors.periwinkleColor,
+ size: 48,
+ ),
+ ),
+ ],
+ )
+ : IconButton(
+ padding: EdgeInsets.zero,
+ onPressed: () {
+ removeBtPair(index);
+ },
+ icon: const Icon(
+ Icons.close,
+ color: AGLDemoColors.periwinkleColor,
+ size: 48,
+ ),
+ ),
+ ]),
+ ),
+ ),
+ );
+ },
+ ),
+ ),
+ Padding(
+ padding: const EdgeInsets.only(bottom: 150.0),
+ child: GenericButton(
+ heigth: 130,
+ width: 501,
+ text: 'Scan for New Device',
+ onTap: () {},
+ ),
+ ),
+ const SizedBox(
+ height: 100,
+ )
+ ],
+ );
+ }
+}
diff --git a/lib/presentation/screens/settings/settings_screens/date_time/date/date_screen.dart b/lib/presentation/screens/settings/settings_screens/date_time/date/date_screen.dart
new file mode 100644
index 0000000..6802ed0
--- /dev/null
+++ b/lib/presentation/screens/settings/settings_screens/date_time/date/date_screen.dart
@@ -0,0 +1,218 @@
+import 'package:flutter_ics_homescreen/export.dart';
+import 'package:calendar_date_picker2/calendar_date_picker2.dart';
+import 'package:intl/intl.dart';
+
+class DatePage extends ConsumerWidget {
+ const DatePage({super.key});
+ static Page<void> page() => const MaterialPage<void>(child: DatePage());
+
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ return Scaffold(
+ body: Column(children: [
+ CommonTitle(
+ title: 'Date',
+ hasBackButton: true,
+ onPressed: () {
+ context.flow<AppState>().update((state) => AppState.dateTime);
+ },
+ ),
+ const Expanded(
+ child: Padding(
+ padding: EdgeInsets.symmetric(vertical: 20, horizontal: 144),
+ child: SingleChildScrollView(child: DateScreenWidget())),
+ ),
+ ]),
+ );
+ }
+}
+
+class DateScreenWidget extends ConsumerStatefulWidget {
+ const DateScreenWidget({super.key});
+ Page<void> page() => const MaterialPage<void>(child: DateScreenWidget());
+
+ @override
+ DateScreenWidgetState createState() => DateScreenWidgetState();
+}
+
+class DateScreenWidgetState extends ConsumerState<DateScreenWidget> {
+ late String selectedDate;
+
+ onPressed({required String type}) {
+ if (type == "confirm") {
+ ref.read(dateTimeStateProvider.notifier).setDate(selectedDate);
+ context.flow<AppState>().update((state) => AppState.dateTime);
+ } else if (type == "cancel") {
+ context.flow<AppState>().update((state) => AppState.dateTime);
+ }
+ }
+
+ @override
+ void initState() {
+ selectedDate = ref.read(dateTimeStateProvider).date;
+
+ super.initState();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ Size size = MediaQuery.sizeOf(context);
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ CalendarDatePicker2(
+ config: CalendarDatePicker2Config(
+ calendarType: CalendarDatePicker2Type.single,
+ dayBuilder: (
+ {required date,
+ decoration,
+ isDisabled,
+ isSelected,
+ isToday,
+ textStyle}) {
+ Widget? dayWidget;
+ dayWidget = Container(
+ decoration: decoration,
+ child: Center(
+ child: Stack(
+ alignment: AlignmentDirectional.center,
+ children: [
+ Text(
+ MaterialLocalizations.of(context)
+ .formatDecimal(date.day),
+ style: textStyle,
+ ),
+ ],
+ ),
+ ),
+ );
+
+ return dayWidget;
+ },
+ dayTextStyle: const TextStyle(
+ color: AGLDemoColors.periwinkleColor, fontSize: 40),
+ selectedDayHighlightColor: AGLDemoColors.neonBlueColor,
+ controlsTextStyle: const TextStyle(
+ color: AGLDemoColors.periwinkleColor, fontSize: 40),
+ weekdayLabelTextStyle: const TextStyle(
+ color: AGLDemoColors.periwinkleColor, fontSize: 40),
+ controlsHeight: 40,
+ dayTextStylePredicate: ({required date}) {
+ return const TextStyle(
+ color: AGLDemoColors.periwinkleColor, fontSize: 40);
+ },
+ selectedDayTextStyle:
+ const TextStyle(color: Colors.white, fontSize: 40)),
+ value: selectedDate == "mm/dd/yyyy"
+ ? []
+ : [DateFormat().add_yMMMMd().parse(selectedDate)],
+ onValueChanged: (dates) {
+ setState(() {
+ selectedDate = DateFormat().add_yMMMMd().format(dates.first!);
+ });
+ },
+ ),
+ const SizedBox(
+ height: 120,
+ ),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: [
+ Material(
+ color: Colors.transparent,
+ child: InkWell(
+ onHighlightChanged: (value) {
+ // setState(() {
+ // isCancelButtonHighlighted = value;
+ // });
+ },
+ onTap: () {
+ onPressed(type: "cancel");
+
+ // onTap(type: "cancel");
+ },
+ child: Container(
+ width: size.width / 3.2,
+ alignment: Alignment.center,
+ decoration: BoxDecoration(
+ boxShadow: [
+ BoxShadow(
+ color: Colors.black.withOpacity(0.7),
+ blurRadius: 1.5,
+ offset: const Offset(1, 2))
+ ],
+ gradient: LinearGradient(colors: [
+ AGLDemoColors.resolutionBlueColor,
+ AGLDemoColors.neonBlueColor.withOpacity(0.15),
+ ]),
+ borderRadius: BorderRadius.circular(3),
+ border: Border.all(
+ color:
+ AGLDemoColors.neonBlueColor.withOpacity(0.20))),
+ child: const Padding(
+ padding: EdgeInsets.symmetric(vertical: 20),
+ child: Text(
+ "Cancel",
+ style: TextStyle(
+ color: AGLDemoColors.periwinkleColor,
+ fontWeight: FontWeight.w600,
+ fontSize: 40,
+ letterSpacing: 0.4),
+ ),
+ ),
+ ),
+ ),
+ ),
+ const SizedBox(
+ width: 10,
+ ),
+ Material(
+ color: Colors.transparent,
+ child: InkWell(
+ onHighlightChanged: (value) {
+ // setState(() {
+ // isCancelButtonHighlighted = value;
+ // });
+ },
+ onTap: () {
+ onPressed(type: "confirm");
+ // onTap(type: "cancel");
+ },
+ child: Container(
+ width: MediaQuery.sizeOf(context).width / 3.2,
+ alignment: Alignment.center,
+ decoration: BoxDecoration(
+ boxShadow: [
+ BoxShadow(
+ color: Colors.black.withOpacity(0.7),
+ blurRadius: 1.5,
+ offset: const Offset(1, 2))
+ ],
+ gradient: LinearGradient(colors: [
+ AGLDemoColors.resolutionBlueColor,
+ AGLDemoColors.neonBlueColor.withOpacity(0.15),
+ ]),
+ borderRadius: BorderRadius.circular(3),
+ border: Border.all(
+ color:
+ AGLDemoColors.neonBlueColor.withOpacity(0.20))),
+ child: const Padding(
+ padding: EdgeInsets.symmetric(vertical: 20),
+ child: Text(
+ "Confirm",
+ style: TextStyle(
+ color: AGLDemoColors.periwinkleColor,
+ fontWeight: FontWeight.w600,
+ fontSize: 40,
+ letterSpacing: 0.4),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ],
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/presentation/screens/settings/settings_screens/date_time/date_time_screen.dart b/lib/presentation/screens/settings/settings_screens/date_time/date_time_screen.dart
new file mode 100644
index 0000000..2365ecc
--- /dev/null
+++ b/lib/presentation/screens/settings/settings_screens/date_time/date_time_screen.dart
@@ -0,0 +1,54 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+class DateTimePage extends ConsumerWidget {
+ const DateTimePage({super.key});
+
+ static Page<void> page() => const MaterialPage<void>(child: DateTimePage());
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ final dateTime = ref.watch(dateTimeStateProvider.select((val) => val));
+
+ return Scaffold(
+ body: Column(
+ children: [
+ CommonTitle(
+ title: 'Date & Time',
+ hasBackButton: true,
+ onPressed: () {
+ context.flow<AppState>().update((state) => AppState.settings);
+ },
+ ),
+ Expanded(
+ child: Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 144),
+ child: ListView(
+ children: [
+ UnitsTile(
+ image: "assets/Calendar.svg",
+ title: 'Date',
+ unitName: dateTime.date,
+ hasSwich: false,
+ voidCallback: () async {
+ context
+ .flow<AppState>()
+ .update((next) => AppState.date);
+ }),
+ UnitsTile(
+ image: "assets/Time.svg",
+ title: 'Time',
+ unitName: dateTime.time,
+ hasSwich: true,
+ voidCallback: () {
+ context
+ .flow<AppState>()
+ .update((next) => AppState.time);
+ }),
+ ],
+ ),
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/screens/settings/settings_screens/date_time/time/time_screen.dart b/lib/presentation/screens/settings/settings_screens/date_time/time/time_screen.dart
new file mode 100644
index 0000000..61131b5
--- /dev/null
+++ b/lib/presentation/screens/settings/settings_screens/date_time/time/time_screen.dart
@@ -0,0 +1,426 @@
+import 'package:flutter_ics_homescreen/export.dart';
+import 'package:flutter/services.dart';
+import 'package:intl/intl.dart';
+
+class TimePage extends ConsumerWidget {
+ const TimePage({super.key});
+ static Page<void> page() => const MaterialPage<void>(child: TimePage());
+
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ return Scaffold(
+ body: Column(children: [
+ CommonTitle(
+ title: 'Time',
+ hasBackButton: true,
+ onPressed: () {
+ context.flow<AppState>().update((state) => AppState.dateTime);
+ },
+ ),
+ const Expanded(
+ child: Padding(
+ padding: EdgeInsets.symmetric(vertical: 20, horizontal: 144),
+ child: SingleChildScrollView(child: TimeScreenWidget())),
+ ),
+ ]),
+ );
+ }
+}
+
+class TimeScreenWidget extends ConsumerStatefulWidget {
+ const TimeScreenWidget({super.key});
+ Page<void> page() => const MaterialPage<void>(child: TimeScreenWidget());
+
+ @override
+ TimeScreenWidgetState createState() => TimeScreenWidgetState();
+}
+
+class TimeScreenWidgetState extends ConsumerState<TimeScreenWidget> {
+ late int selectedTimeHour;
+ late int selectedTimeMinute;
+ String selectedMeridien = "AM";
+
+ TextEditingController hourController = TextEditingController();
+ TextEditingController minuteController = TextEditingController();
+
+ onPressed({required String type}) {
+ if (type == "confirm") {
+ ref.read(dateTimeStateProvider.notifier).setTime(
+ "${hourController.text}:${minuteController.text} $selectedMeridien");
+ context.flow<AppState>().update((state) => AppState.dateTime);
+ } else if (type == "cancel") {
+ context.flow<AppState>().update((state) => AppState.dateTime);
+ }
+ }
+
+ @override
+ void initState() {
+ String time = ref.read(dateTimeStateProvider).time;
+ if (time == "hh:mm a") {
+ time = DateFormat('hh:mm a').format(DateTime.now());
+ }
+ List<String> split = time.split(":");
+ selectedTimeHour = int.parse(split[0]);
+ List<String> splitMeridian = split[1].split(" ");
+
+ selectedTimeMinute = int.parse(splitMeridian[0]);
+
+ setState(() {
+ selectedMeridien = splitMeridian[1];
+ hourController.text = selectedTimeHour.toString();
+ minuteController.text = selectedTimeMinute.toString();
+ });
+
+ super.initState();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ Size size = MediaQuery.sizeOf(context);
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ const SizedBox(
+ height: 60,
+ ),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ TimeTextField(
+ controller: hourController,
+ type: "hour",
+ ),
+ const Padding(
+ padding: EdgeInsets.all(15),
+ child: Text(
+ ":",
+ style: TextStyle(
+ color: AGLDemoColors.periwinkleColor, fontSize: 44),
+ ),
+ ),
+ TimeTextField(
+ controller: minuteController,
+ type: "minute",
+ ),
+ ],
+ ),
+ const SizedBox(
+ height: 50,
+ ),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Container(
+ decoration: BoxDecoration(
+ borderRadius: const BorderRadius.only(
+ topLeft: Radius.circular(30),
+ bottomLeft: Radius.circular(30),
+ ),
+ border: Border.all(color: AGLDemoColors.periwinkleColor),
+ color: selectedMeridien == "AM"
+ ? AGLDemoColors.neonBlueColor
+ : Colors.transparent),
+ child: Material(
+ color: Colors.transparent,
+ child: InkWell(
+ borderRadius: const BorderRadius.only(
+ topLeft: Radius.circular(30),
+ bottomLeft: Radius.circular(30),
+ ),
+ onTap: () {
+ setState(() {
+ selectedMeridien = "AM";
+ });
+ },
+ child: Padding(
+ padding: const EdgeInsets.only(
+ top: 17, bottom: 17, right: 30, left: 25),
+ child: Row(
+ children: [
+ selectedMeridien == "AM"
+ ? const Icon(
+ Icons.check,
+ size: 48,
+ color: Colors.white,
+ )
+ : const SizedBox(
+ width: 48,
+ height: 48,
+ ),
+ const SizedBox(
+ width: 3,
+ ),
+ Text(
+ "AM",
+ style: TextStyle(
+ color: selectedMeridien == "AM"
+ ? Colors.white
+ : AGLDemoColors.periwinkleColor,
+ fontSize: 40),
+ )
+ ],
+ ),
+ ),
+ ),
+ ),
+ ),
+ Container(
+ decoration: BoxDecoration(
+ borderRadius: const BorderRadius.only(
+ topRight: Radius.circular(30),
+ bottomRight: Radius.circular(30),
+ ),
+ border: Border.all(color: AGLDemoColors.periwinkleColor),
+ color: selectedMeridien == "PM"
+ ? AGLDemoColors.neonBlueColor
+ : Colors.transparent),
+ child: Material(
+ color: Colors.transparent,
+ child: InkWell(
+ borderRadius: const BorderRadius.only(
+ topRight: Radius.circular(30),
+ bottomRight: Radius.circular(30),
+ ),
+ onTap: () {
+ setState(() {
+ selectedMeridien = "PM";
+ });
+ },
+ child: Padding(
+ padding: const EdgeInsets.only(
+ top: 17, bottom: 17, right: 30, left: 25),
+ child: Row(
+ children: [
+ selectedMeridien == "PM"
+ ? const Icon(
+ Icons.check,
+ size: 48,
+ color: Colors.white,
+ )
+ : const SizedBox(
+ width: 48,
+ height: 48,
+ ),
+ const SizedBox(
+ width: 3,
+ ),
+ Text(
+ "PM",
+ style: TextStyle(
+ color: selectedMeridien == "PM"
+ ? Colors.white
+ : AGLDemoColors.periwinkleColor,
+ fontSize: 40),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ ),
+ ],
+ ),
+ const SizedBox(
+ height: 200,
+ ),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: [
+ Material(
+ color: Colors.transparent,
+ child: InkWell(
+ onHighlightChanged: (value) {
+ // setState(() {
+ // isCancelButtonHighlighted = value;
+ // });
+ },
+ onTap: () {
+ onPressed(type: "cancel");
+
+ // onTap(type: "cancel");
+ },
+ child: Container(
+ width: size.width / 3.2,
+ alignment: Alignment.center,
+ decoration: BoxDecoration(
+ boxShadow: [
+ BoxShadow(
+ color: Colors.black.withOpacity(0.7),
+ blurRadius: 1.5,
+ offset: const Offset(1, 2))
+ ],
+ gradient: LinearGradient(colors: [
+ AGLDemoColors.resolutionBlueColor,
+ AGLDemoColors.neonBlueColor.withOpacity(0.15),
+ ]),
+ borderRadius: BorderRadius.circular(3),
+ border: Border.all(
+ color:
+ AGLDemoColors.neonBlueColor.withOpacity(0.20))),
+ child: const Padding(
+ padding: EdgeInsets.symmetric(vertical: 10),
+ child: Text(
+ "Cancel",
+ style: TextStyle(
+ color: AGLDemoColors.periwinkleColor,
+ fontWeight: FontWeight.w600,
+ fontSize: 40,
+ letterSpacing: 0.4),
+ ),
+ ),
+ ),
+ ),
+ ),
+ const SizedBox(
+ width: 10,
+ ),
+ Material(
+ color: Colors.transparent,
+ child: InkWell(
+ onHighlightChanged: (value) {
+ // setState(() {
+ // isCancelButtonHighlighted = value;
+ // });
+ },
+ onTap: () {
+ onPressed(type: "confirm");
+ // onTap(type: "cancel");
+ },
+ child: Container(
+ width: MediaQuery.sizeOf(context).width / 3.2,
+ alignment: Alignment.center,
+ decoration: BoxDecoration(
+ boxShadow: [
+ BoxShadow(
+ color: Colors.black.withOpacity(0.7),
+ blurRadius: 1.5,
+ offset: const Offset(1, 2))
+ ],
+ gradient: LinearGradient(colors: [
+ AGLDemoColors.resolutionBlueColor,
+ AGLDemoColors.neonBlueColor.withOpacity(0.15),
+ ]),
+ borderRadius: BorderRadius.circular(3),
+ border: Border.all(
+ color:
+ AGLDemoColors.neonBlueColor.withOpacity(0.20))),
+ child: const Padding(
+ padding: EdgeInsets.symmetric(vertical: 10),
+ child: Text(
+ "Confirm",
+ style: TextStyle(
+ color: AGLDemoColors.periwinkleColor,
+ fontWeight: FontWeight.w600,
+ fontSize: 40,
+ letterSpacing: 0.4),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ],
+ ),
+ ],
+ );
+ }
+}
+
+class TimeTextField extends StatefulWidget {
+ const TimeTextField(
+ {super.key, required this.controller, required this.type});
+ final TextEditingController controller;
+ final String type;
+
+ @override
+ State<TimeTextField> createState() => _TimeTextFieldState();
+}
+
+class _TimeTextFieldState extends State<TimeTextField> {
+ TextEditingController controller = TextEditingController();
+ @override
+ void initState() {
+ super.initState();
+ controller = widget.controller;
+ }
+
+ @override
+ void dispose() {
+ controller.dispose();
+ super.dispose();
+ }
+
+ onKeyBoardEvent(RawKeyEvent event) {
+ if (event.isKeyPressed(LogicalKeyboardKey.arrowUp)) {
+ if (controller.text != "") {
+ int value = int.tryParse(controller.text) ?? 0;
+ if (widget.type == "hour") {
+ if (value > 11) {
+ controller.text = "12";
+ } else {
+ controller.text = (value + 1).toString();
+ }
+ } else if (widget.type == "minute") {
+ if (value > 58) {
+ controller.text = "59";
+ } else {
+ controller.text = (value + 1).toString();
+ }
+ }
+ return KeyEventResult.handled;
+ } else {
+ controller.text = "0";
+ return KeyEventResult.handled;
+ }
+ } else if (event.isKeyPressed(LogicalKeyboardKey.arrowDown)) {
+ if (controller.text.isNotEmpty) {
+ int value = int.tryParse(controller.text) ?? 0;
+ if (value < 1) {
+ controller.text = "0";
+ } else {
+ controller.text = (value - 1).toString();
+ }
+ return KeyEventResult.handled;
+ } else {
+ controller.text = "0";
+ return KeyEventResult.handled;
+ }
+ }
+ return KeyEventResult.ignored;
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return SizedBox(
+ width: 185,
+ child: RawKeyboardListener(
+ focusNode: FocusNode(onKey: (node, event) {
+ return onKeyBoardEvent(event);
+ }),
+ child: TextField(
+ style: const TextStyle(color: Colors.white, fontSize: 40),
+ decoration: InputDecoration(
+ contentPadding: const EdgeInsets.symmetric(vertical: 23),
+ filled: true,
+ fillColor: AGLDemoColors.blueGlowFillColor.withOpacity(0.1)),
+ controller: controller,
+ textAlign: TextAlign.center,
+ inputFormatters: [
+ FilteringTextInputFormatter.digitsOnly,
+ ],
+ onChanged: (value) {
+ if (value.isNotEmpty) {
+ if (widget.type == "hour") {
+ if (int.parse(value) > 12) {
+ widget.controller.text = '12';
+ }
+ } else if (widget.type == "minute") {
+ if (int.parse(value) > 59) {
+ widget.controller.text = '59';
+ }
+ }
+ }
+ },
+ ),
+ ));
+ }
+}
diff --git a/lib/presentation/screens/settings/settings_screens/profiles/profiles_screen.dart b/lib/presentation/screens/settings/settings_screens/profiles/profiles_screen.dart
new file mode 100644
index 0000000..cd831b1
--- /dev/null
+++ b/lib/presentation/screens/settings/settings_screens/profiles/profiles_screen.dart
@@ -0,0 +1,20 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+import 'widgets/profiles_content.dart';
+
+class ProfilesPage extends StatelessWidget {
+ const ProfilesPage({super.key});
+
+ static Page<void> page() => const MaterialPage<void>(child: ProfilesPage());
+ @override
+ Widget build(BuildContext context) {
+ return const Scaffold(
+ body: Stack(
+ children: [
+ ProfilesContent(),
+ ],
+ ),
+ );
+ }
+}
+
diff --git a/lib/presentation/screens/settings/settings_screens/profiles/widgets/new_profile_screen.dart b/lib/presentation/screens/settings/settings_screens/profiles/widgets/new_profile_screen.dart
new file mode 100644
index 0000000..0cf1ddb
--- /dev/null
+++ b/lib/presentation/screens/settings/settings_screens/profiles/widgets/new_profile_screen.dart
@@ -0,0 +1,252 @@
+import 'package:new_virtual_keyboard/virtual_keyboard.dart';
+import 'package:flutter_ics_homescreen/export.dart';
+
+class NewProfilePage extends ConsumerStatefulWidget {
+ const NewProfilePage({super.key});
+
+ static Page<void> page() => const MaterialPage<void>(child: NewProfilePage());
+
+ @override
+ NewProfilePageState createState() => NewProfilePageState();
+}
+
+class NewProfilePageState extends ConsumerState<NewProfilePage> {
+ final _controller = TextEditingController();
+ final _formKey = GlobalKey<FormState>();
+ bool shiftEnabled = false;
+
+ int chars = 0;
+ @override
+ void initState() {
+ super.initState();
+ }
+
+ _onKeyPress(VirtualKeyboardKey key) {
+ String text = _controller.text;
+ if (key.keyType == VirtualKeyboardKeyType.String) {
+ text = text + (shiftEnabled ? key.capsText : key.text)!;
+ } else if (key.keyType == VirtualKeyboardKeyType.Action) {
+ switch (key.action) {
+ case VirtualKeyboardKeyAction.Backspace:
+ if (text.isEmpty) return;
+ text = text.substring(0, text.length - 1);
+ break;
+ case VirtualKeyboardKeyAction.Return:
+ text = '$text\n';
+ break;
+ case VirtualKeyboardKeyAction.Space:
+ text = text + key.text!;
+ break;
+ case VirtualKeyboardKeyAction.Shift:
+ shiftEnabled = !shiftEnabled;
+ break;
+ default:
+ }
+ }
+
+// Update the screen
+ if (text.length >= 25) {
+ _controller.text = text.substring(0, 25);
+ } else {
+ _controller.text = text;
+ }
+
+ updateMaxChar(_controller.text.length);
+ }
+
+ void showKeyboard() {
+ var ctx = homeScaffoldKey.currentContext;
+ showModalBottomSheet(
+ elevation: 0.0,
+ backgroundColor: Colors.transparent,
+ barrierColor: Colors.transparent,
+ context: ctx!,
+ builder: (ctx) {
+ return Container(
+ height: 479,
+ width: 1080,
+ decoration: const BoxDecoration(
+ color: AGLDemoColors.resolutionBlueColor,
+ border: Border(
+ top: BorderSide(
+ color: Color(0xFF295EF7),
+ width: 1,
+ )),
+ ),
+ child: VirtualKeyboard(
+ height: 478,
+ textColor: AGLDemoColors.periwinkleColor,
+ fontSize: 40,
+ // [A-Z, 0-9]
+ type: VirtualKeyboardType.Alphanumeric,
+ // Callback for key press event
+ onKeyPress: (key) {
+ _onKeyPress(key);
+ },
+ ),
+ );
+ },
+ );
+ }
+
+ @override
+ void didChangeDependencies() async {
+ Future.delayed(const Duration(seconds: 0), () {
+ showKeyboard();
+ });
+ super.didChangeDependencies();
+ }
+
+ @override
+ void dispose() {
+ _controller.dispose();
+ super.dispose();
+ }
+
+ void updateMaxChar(int charsCount) {
+ setState(() {
+ chars = charsCount;
+ });
+ }
+
+ void addUser() {
+ ref.read(usersProvider.notifier).addUser(_controller.text);
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ body: Form(
+ key: _formKey,
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ CommonTitle(
+ title: 'New Profile',
+ hasBackButton: true,
+ onPressed: () {
+ context.flow<AppState>().update((state) => AppState.profiles);
+ },
+ ),
+ Expanded(
+ child: Padding(
+ padding:
+ const EdgeInsets.symmetric(vertical: 50, horizontal: 144),
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.start,
+ children: [
+ Text(
+ 'Profile Name',
+ style: Theme.of(context)
+ .textTheme
+ .bodyMedium!
+ .copyWith(fontSize: 40),
+ ),
+ const SizedBox(
+ height: 20,
+ ),
+ Container(
+ decoration: const BoxDecoration(
+ gradient: LinearGradient(
+ begin: Alignment.centerLeft,
+ end: Alignment.centerRight,
+ stops: [0, 0.5, 1],
+ colors: <Color>[
+ Colors.black12,
+ Colors.black,
+ Colors.black12
+ ],
+ ),
+ ),
+ child: Column(
+ children: [
+ Container(
+ height: 140,
+ padding: const EdgeInsets.only(top: 30),
+ child: TextFormField(
+ onTap: () {
+ showKeyboard();
+ },
+ controller: _controller,
+ autofocus: true,
+ maxLength: 25,
+ validator: (value) {
+ if (value == null || value.isEmpty) {
+ return 'Please enter some text';
+ }
+ return null;
+ },
+ //maxLengthEnforcement: MaxLengthEnforcement.none,
+ onChanged: (value) {
+ if (_controller.text.length <= 1) {
+ if (_formKey.currentState!.validate()) {}
+ _formKey.currentState!.save();
+ }
+ updateMaxChar(_controller.text.length);
+ },
+ decoration: const InputDecoration(
+ border: InputBorder.none,
+ counterText: '',
+ ),
+ textAlign: TextAlign.center,
+ textDirection: TextDirection.rtl,
+ style: const TextStyle(fontSize: 60),
+ ),
+ ),
+ Container(
+ decoration: const BoxDecoration(
+ gradient: LinearGradient(
+ begin: Alignment.centerLeft,
+ end: Alignment.centerRight,
+ stops: [0, 0.2, 0.8, 1],
+ colors: <Color>[
+ Colors.transparent,
+ AGLDemoColors.neonBlueColor,
+ AGLDemoColors.neonBlueColor,
+ Colors.transparent,
+ ],
+ ),
+ ),
+ height: 2,
+ )
+ ],
+ ),
+ ),
+ const SizedBox(
+ height: 20,
+ ),
+ Center(
+ child: Text('$chars/25 Characters',
+ style: const TextStyle(fontSize: 26)),
+ ),
+ ],
+ ),
+ ),
+ ),
+ Padding(
+ padding: const EdgeInsets.only(bottom: 350.0),
+ child: GenericButton(
+ heigth: 130,
+ width: 493,
+ text: 'Save Profile',
+ onTap: () {
+ if (_formKey.currentState!.validate()) {
+ addUser();
+ context
+ .flow<AppState>()
+ .update((state) => AppState.profiles);
+ }
+ },
+ ),
+
+ ),
+ Padding(
+ padding: const EdgeInsets.only(bottom: 150.0),
+ child: Container(),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/screens/settings/settings_screens/profiles/widgets/profiles_content.dart b/lib/presentation/screens/settings/settings_screens/profiles/widgets/profiles_content.dart
new file mode 100644
index 0000000..eb89553
--- /dev/null
+++ b/lib/presentation/screens/settings/settings_screens/profiles/widgets/profiles_content.dart
@@ -0,0 +1,125 @@
+import '../../../../../../data/models/user.dart';
+import '../../../../../../export.dart';
+
+class ProfilesContent extends ConsumerStatefulWidget {
+ const ProfilesContent({super.key});
+
+ @override
+ ProfilesContentState createState() => ProfilesContentState();
+}
+
+class ProfilesContentState extends ConsumerState<ProfilesContent> {
+ late User currentUser;
+
+ void setCurrentUser(String userId) {
+ setState(() {
+ ref.read(usersProvider.notifier).selectUser(userId);
+ });
+ }
+
+ void removeUser(String userId) {
+ setState(() {
+ ref.read(usersProvider.notifier).removeUser(userId);
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ var users = ref.watch(usersProvider.select((users) => users));
+ final currentUser = users.selectedUser;
+ final usersList = users.users;
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ CommonTitle(
+ title: "Profiles",
+ hasBackButton: true,
+ onPressed: () {
+ context.flow<AppState>().update((state) => AppState.settings);
+ },
+ ),
+ Expanded(
+ child: ListView.separated(
+ padding: const EdgeInsets.symmetric(vertical: 50, horizontal: 144),
+ itemCount: usersList.length,
+ separatorBuilder: (context, index) {
+ return const SizedBox(
+ height: 8,
+ );
+ },
+ itemBuilder: (context, index) {
+ return Container(
+ height: 130,
+ decoration: BoxDecoration(
+ gradient: LinearGradient(
+ begin: Alignment.centerLeft,
+ end: Alignment.centerRight,
+ stops: currentUser == usersList[index]
+ ? [0, 0.01, 0.8]
+ : [0.1, 1],
+ colors: currentUser == usersList[index]
+ ? <Color>[
+ Colors.white,
+ Colors.blue,
+ const Color.fromARGB(16, 41, 98, 255)
+ ]
+ : <Color>[Colors.black, Colors.black12]),
+ ),
+ child: ListTile(
+ minVerticalPadding: 0.0,
+ contentPadding: const EdgeInsets.symmetric(
+ horizontal: 16.0, vertical: 40.0),
+ leading: Text(users.users[index].name,
+ style: const TextStyle(fontSize: 40)),
+ //title: Text(widget.title),
+ //enabled: isSwitchOn,
+ trailing: IconButton(
+ padding: EdgeInsets.zero,
+ onPressed: () {
+ removeUser(users.users[index].id);
+ },
+ icon: const Icon(
+ Icons.close,
+ color: AGLDemoColors.periwinkleColor,
+ size: 48,
+ ),
+ ),
+
+ onTap: () {
+ setCurrentUser(usersList[index].id);
+ },
+ ),
+ );
+ },
+ ),
+ ),
+ Padding(
+ padding: const EdgeInsets.only(bottom: 150.0),
+ child: Column(
+ children: [
+ GenericButton(
+ heigth: 122,
+ width: 317,
+ text: 'New Profile',
+ onTap: () {
+ context
+ .flow<AppState>()
+ .update((state) => AppState.newProfile);
+ },
+ ),
+
+ const SizedBox(height: 20),
+ GenericButton(
+ heigth: 122,
+ width: 412,
+ text: 'Reset to Default',
+ onTap: () {},
+ ),
+ ],
+ ),
+ ),
+ ],
+ );
+ }
+}
+
diff --git a/lib/presentation/screens/settings/settings_screens/units/distance/distance_unit_screen.dart b/lib/presentation/screens/settings/settings_screens/units/distance/distance_unit_screen.dart
new file mode 100644
index 0000000..3e9c135
--- /dev/null
+++ b/lib/presentation/screens/settings/settings_screens/units/distance/distance_unit_screen.dart
@@ -0,0 +1,120 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+class DistanceUnitPage extends ConsumerWidget {
+ const DistanceUnitPage({super.key});
+
+ static Page<void> page() =>
+ const MaterialPage<void>(child: DistanceUnitPage());
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ final unit =
+ ref.watch(unitStateProvider.select((unit) => unit.distanceUnit));
+
+ return Scaffold(
+
+ body: Column(
+ children: [
+ CommonTitle(
+ title: 'Distance',
+ hasBackButton: true,
+ onPressed: () {
+ context.flow<AppState>().update((state) => AppState.units);
+ },
+ ),
+ Expanded(
+ child: Padding(
+ padding: const EdgeInsets.symmetric(vertical: 0, horizontal: 144),
+ child: ListView(
+ children: [
+ Container(
+ height: 130,
+ decoration: BoxDecoration(
+ gradient: LinearGradient(
+ begin: Alignment.centerLeft,
+ end: Alignment.centerRight,
+ stops: unit == DistanceUnit.kilometers
+ ? [0, 0.01, 0.8]
+ : [0.1, 1],
+ colors: unit == DistanceUnit.kilometers
+ ? <Color>[
+ Colors.white,
+ Colors.blue,
+ const Color.fromARGB(16, 41, 98, 255)
+ ]
+ : <Color>[Colors.black, Colors.black12]),
+ ),
+ child: ListTile(
+ minVerticalPadding: 0.0,
+ contentPadding: const EdgeInsets.symmetric(
+ horizontal: 16.0, vertical: 40.0),
+ leading: Text(
+ 'Kilometers',
+ style: Theme.of(context).textTheme.titleMedium,
+ ),
+ //title: Text(widget.title),
+ //enabled: isSwitchOn,
+ trailing: unit == DistanceUnit.kilometers
+ ? const Icon(Icons.done,
+ color: AGLDemoColors.periwinkleColor,
+ size: 48,
+ )
+ : null,
+ onTap: () {
+ ref
+ .read(unitStateProvider.notifier)
+ .setDistanceUnit(DistanceUnit.kilometers);
+ }),
+ ),
+ const SizedBox(
+ height: 8,
+ ),
+ Container(
+ height: 130,
+ decoration: BoxDecoration(
+ gradient: LinearGradient(
+ begin: Alignment.centerLeft,
+ end: Alignment.centerRight,
+ stops: unit == DistanceUnit.miles
+ ? [0, 0.01, 0.8]
+ : [0.1, 1],
+ colors: unit == DistanceUnit.miles
+ ? <Color>[
+ Colors.white,
+ Colors.blue,
+ const Color.fromARGB(16, 41, 98, 255)
+ ]
+ : <Color>[Colors.black, Colors.black12]),
+ ),
+ child: ListTile(
+ minVerticalPadding: 0.0,
+ contentPadding: const EdgeInsets.symmetric(
+ horizontal: 16.0, vertical: 40.0),
+ leading: Text(
+ 'Miles',
+ style: Theme.of(context).textTheme.titleMedium,
+ ),
+ //title: Text(widget.title),
+ //enabled: isSwitchOn,
+ trailing: unit == DistanceUnit.miles
+ ? const Icon(Icons.done,
+ color: AGLDemoColors.periwinkleColor,
+ size: 48,
+ )
+ : null,
+
+ onTap: () {
+ ref
+ .read(unitStateProvider.notifier)
+ .setDistanceUnit(DistanceUnit.miles);
+ },
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/screens/settings/settings_screens/units/temperature/temperature_unit_screen.dart b/lib/presentation/screens/settings/settings_screens/units/temperature/temperature_unit_screen.dart
new file mode 100644
index 0000000..414bf32
--- /dev/null
+++ b/lib/presentation/screens/settings/settings_screens/units/temperature/temperature_unit_screen.dart
@@ -0,0 +1,120 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+class TemperatureUnitPage extends ConsumerWidget {
+ const TemperatureUnitPage({super.key});
+
+ static Page<void> page() =>
+ const MaterialPage<void>(child: TemperatureUnitPage());
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ final unit =
+ ref.watch(unitStateProvider.select((unit) => unit.temperatureUnit));
+
+ return Scaffold(
+
+ body: Column(
+ children: [
+ CommonTitle(
+ title: 'Temperature',
+ hasBackButton: true,
+ onPressed: () {
+ context.flow<AppState>().update((state) => AppState.units);
+ },
+ ),
+ Expanded(
+ child: Padding(
+ padding: const EdgeInsets.symmetric(vertical: 0, horizontal: 144),
+ child: ListView(
+ children: [
+ Container(
+ height: 130,
+ decoration: BoxDecoration(
+ gradient: LinearGradient(
+ begin: Alignment.centerLeft,
+ end: Alignment.centerRight,
+ stops: unit == TemperatureUnit.celsius
+ ? [0, 0.01, 0.8]
+ : [0.1, 1],
+ colors: unit == TemperatureUnit.celsius
+ ? <Color>[
+ Colors.white,
+ Colors.blue,
+ const Color.fromARGB(16, 41, 98, 255)
+ ]
+ : <Color>[Colors.black, Colors.black12]),
+ ),
+ child: ListTile(
+ minVerticalPadding: 0.0,
+ contentPadding: const EdgeInsets.symmetric(
+ horizontal: 16.0, vertical: 40.0),
+ leading: Text(
+ 'Celsius',
+ style: Theme.of(context).textTheme.titleMedium,
+ ),
+ //title: Text(widget.title),
+ //enabled: isSwitchOn,
+ trailing: unit == TemperatureUnit.celsius
+ ? const Icon(Icons.done,
+ color: AGLDemoColors.periwinkleColor,
+ size: 48,
+ )
+ : null,
+ onTap: () {
+ ref
+ .read(unitStateProvider.notifier)
+ .setTemperatureUnit(TemperatureUnit.celsius);
+ }),
+ ),
+ const SizedBox(
+ height: 5,
+ ),
+ Container(
+ height: 130,
+ decoration: BoxDecoration(
+ gradient: LinearGradient(
+ begin: Alignment.centerLeft,
+ end: Alignment.centerRight,
+ stops: unit == TemperatureUnit.fahrenheit
+ ? [0, 0.01, 0.8]
+ : [0.1, 1],
+ colors: unit == TemperatureUnit.fahrenheit
+ ? <Color>[
+ Colors.white,
+ Colors.blue,
+ const Color.fromARGB(16, 41, 98, 255)
+ ]
+ : <Color>[Colors.black, Colors.black12]),
+ ),
+ child: ListTile(
+ minVerticalPadding: 0.0,
+ contentPadding: const EdgeInsets.symmetric(
+ horizontal: 16.0, vertical: 40.0),
+ leading: Text(
+ 'Fahrenheit',
+ style: Theme.of(context).textTheme.titleMedium,
+ ),
+ //title: Text(widget.title),
+ //enabled: isSwitchOn,
+ trailing: unit == TemperatureUnit.fahrenheit
+ ? const Icon(Icons.done,
+ color: AGLDemoColors.periwinkleColor,
+ size: 38,
+ )
+ : null,
+
+ onTap: () {
+ ref
+ .read(unitStateProvider.notifier)
+ .setTemperatureUnit(TemperatureUnit.fahrenheit);
+ },
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/screens/settings/settings_screens/units/units_screen.dart b/lib/presentation/screens/settings/settings_screens/units/units_screen.dart
new file mode 100644
index 0000000..1c6e37c
--- /dev/null
+++ b/lib/presentation/screens/settings/settings_screens/units/units_screen.dart
@@ -0,0 +1,159 @@
+import 'package:flutter_ics_homescreen/core/utils/helpers.dart';
+import 'package:flutter_ics_homescreen/export.dart';
+
+class UnitsPage extends ConsumerWidget {
+ const UnitsPage({super.key});
+
+ static Page<void> page() => const MaterialPage<void>(child: UnitsPage());
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ final unit = ref.watch(unitStateProvider.select((unit) => unit));
+
+ return Scaffold(
+ //appBar: SettingsTopBar('Units'),
+
+ body: Column(
+ children: [
+ CommonTitle(
+ title: 'Units',
+ hasBackButton: true,
+ onPressed: () {
+ context.flow<AppState>().update((state) => AppState.settings);
+ },
+ ),
+ Expanded(
+ child: Padding(
+ padding: const EdgeInsets.symmetric(vertical: 0, horizontal: 144),
+ child: ListView(
+ children: [
+ UnitsTile(
+ icon: Icons.calendar_month_outlined,
+ title: 'Distance',
+ unitName: unit.distanceUnit == DistanceUnit.kilometers
+ ? 'Kilometers'
+ : 'Miles',
+ hasSwich: false,
+ voidCallback: () async {
+ context
+ .flow<AppState>()
+ .update((next) => AppState.distanceUnit);
+ }),
+ UnitsTile(
+ icon: Icons.straighten,
+ title: 'Temperature',
+ unitName: unit.temperatureUnit == TemperatureUnit.celsius
+ ? 'Celsius'
+ : 'Fahrenheit',
+ hasSwich: true,
+ voidCallback: () {
+ context
+ .flow<AppState>()
+ .update((next) => AppState.tempUnit);
+ }),
+ ],
+ ),
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+}
+
+class UnitsTile extends ConsumerStatefulWidget {
+ final IconData? icon;
+ final String title;
+ final String unitName;
+ final bool hasSwich;
+ final VoidCallback voidCallback;
+ final String? image;
+ const UnitsTile({
+ Key? key,
+ this.icon,
+ required this.title,
+ required this.unitName,
+ required this.hasSwich,
+ required this.voidCallback,
+ this.image,
+ }) : super(key: key);
+
+ @override
+ UnitsTileState createState() => UnitsTileState();
+}
+
+class UnitsTileState extends ConsumerState<UnitsTile> {
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ children: [
+ Container(
+ margin: const EdgeInsets.symmetric(vertical: 8),
+ padding: const EdgeInsets.symmetric(vertical: 15),
+ decoration: const BoxDecoration(
+ gradient: LinearGradient(
+ begin: Alignment.centerLeft,
+ end: Alignment.centerRight,
+ stops: [0.3, 1],
+ colors: <Color>[Colors.black, Colors.black12]),
+ ),
+ //color: Color(0xFF0D113F),
+ child: ListTile(
+ contentPadding:
+ const EdgeInsets.symmetric(vertical: 17, horizontal: 24),
+ leading: widget.icon != null
+ ? Icon(
+ widget.icon,
+ color: AGLDemoColors.periwinkleColor,
+ size: 48,
+ )
+ : Padding(
+ padding: const EdgeInsets.only(right: 24),
+ child: SvgPicture.asset(
+ widget.image!,
+ width: 48,
+ height: 48,
+ ),
+ ),
+ title: Text(
+ widget.title,
+ style: TextStyle(
+ color: AGLDemoColors.periwinkleColor,
+ shadows: [
+ Helpers.dropShadowRegular,
+ ],
+ fontSize: 40),
+ ),
+ trailing: Row(
+ mainAxisSize: MainAxisSize.min,
+ mainAxisAlignment: MainAxisAlignment.end,
+ children: [
+ Text(
+ widget.unitName,
+ style: TextStyle(
+ color: AGLDemoColors.periwinkleColor,
+ shadows: [
+ Helpers.dropShadowRegular,
+ ],
+ fontSize: 40,
+ ),
+ ),
+ const SizedBox(
+ width: 24,
+ ),
+ const Icon(
+ Icons.arrow_forward_ios,
+ color: AGLDemoColors.periwinkleColor,
+ size: 48,
+ ),
+ ],
+ ),
+ onTap: widget.voidCallback,
+ ),
+ ),
+ const SizedBox(
+ height: 8,
+ )
+ ],
+ );
+ }
+}
diff --git a/lib/presentation/screens/settings/settings_screens/version_info/version_info_screend.dart b/lib/presentation/screens/settings/settings_screens/version_info/version_info_screend.dart
new file mode 100644
index 0000000..fce1837
--- /dev/null
+++ b/lib/presentation/screens/settings/settings_screens/version_info/version_info_screend.dart
@@ -0,0 +1,83 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+class VersionInfoPage extends ConsumerWidget {
+ const VersionInfoPage({super.key});
+
+ static Page<void> page() =>
+ const MaterialPage<void>(child: VersionInfoPage());
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ return Scaffold(
+ body: Column(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ CommonTitle(
+ title: 'Version Information',
+ hasBackButton: true,
+ onPressed: () {
+ context.flow<AppState>().update((state) => AppState.settings);
+ },
+ ),
+ Padding(
+ padding: const EdgeInsets.symmetric(vertical: 50, horizontal: 144),
+ child: Column(
+ children: [
+ //Lottie.asset('animations/hybrid_model_yellow_arrow.json'),
+ Lottie.asset(
+ 'animations/Logo_JSON.json',
+ fit: BoxFit.cover,
+ repeat: false,
+ ),
+ const SizedBox(
+ height: 24,
+ ),
+ Container(
+ height: 140,
+ decoration: const BoxDecoration(
+ gradient: LinearGradient(
+ begin: Alignment.centerLeft,
+ end: Alignment.centerRight,
+ stops: [0.1, 1],
+ colors: <Color>[Colors.black, Colors.black12]),
+ ),
+ child: ListTile(
+ contentPadding: const EdgeInsets.only(top: 50, left: 25),
+ leading: Text(
+ aglVeriosn,
+ style: Theme.of(context).textTheme.titleMedium,
+ ),
+ ),
+ ),
+ const SizedBox(
+ height: 5,
+ ),
+ Container(
+ height: 140,
+ decoration: const BoxDecoration(
+ gradient: LinearGradient(
+ begin: Alignment.centerLeft,
+ end: Alignment.centerRight,
+ stops: [0.1, 1],
+ colors: <Color>[Colors.black, Colors.black12]),
+ ),
+ child: ListTile(
+ contentPadding: const EdgeInsets.only(top: 50, left: 25),
+
+ leading: Text(
+ kernelVeriosn,
+ style: Theme.of(context).textTheme.titleMedium,
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ const SizedBox(
+ height: 100,
+ )
+ ],
+ ),
+
+ );
+ }
+}
diff --git a/lib/presentation/screens/settings/settings_screens/wifi/widgets/wifi.dart b/lib/presentation/screens/settings/settings_screens/wifi/widgets/wifi.dart
new file mode 100644
index 0000000..cef2014
--- /dev/null
+++ b/lib/presentation/screens/settings/settings_screens/wifi/widgets/wifi.dart
@@ -0,0 +1,12 @@
+import '../../../../../../export.dart';
+
+class Wifi {
+ final Icon icon;
+ final String name;
+ final bool? isConnected;
+ Wifi({
+ required this.icon,
+ required this.name,
+ this.isConnected = false,
+ });
+}
diff --git a/lib/presentation/screens/settings/settings_screens/wifi/widgets/wifi_content.dart b/lib/presentation/screens/settings/settings_screens/wifi/widgets/wifi_content.dart
new file mode 100644
index 0000000..2473847
--- /dev/null
+++ b/lib/presentation/screens/settings/settings_screens/wifi/widgets/wifi_content.dart
@@ -0,0 +1,150 @@
+import 'package:flutter_ics_homescreen/presentation/custom_icons/custom_icons.dart';
+
+import '../../../../../../export.dart';
+import 'wifi.dart';
+
+class WifiContent extends ConsumerStatefulWidget {
+ const WifiContent({
+ super.key,
+ });
+
+ @override
+ WifiContentState createState() => WifiContentState();
+}
+
+class WifiContentState extends ConsumerState<WifiContent> {
+ final List<Wifi> wifiList = [
+ Wifi(
+ icon: const Icon(
+ CustomIcons.wifi_4_bar_unlocked,
+ size: 48,
+ ),
+ name: 'box2',
+ isConnected: true),
+ Wifi(
+ icon: const Icon(
+ CustomIcons.wifi_4_bar_locked,
+ size: 48,
+ ),
+ name: 'WIVACOM_FiberNew_B61E'),
+ Wifi(
+ icon: const Icon(
+ CustomIcons.wifi_3_bar_locked,
+ size: 48,
+ ),
+ name: 'OpenWrt',
+ ),
+ Wifi(
+ icon: const Icon(
+ CustomIcons.wifi_2_bar_locked,
+ size: 48,
+ ),
+ name: 'kahuna2'),
+ Wifi(
+ icon: const Icon(
+ CustomIcons.wifi_1_bar_locked,
+ size: 48,
+ ),
+ name: 'mip2'),
+ ];
+ Wifi currentWifi =
+ Wifi(icon: const Icon(Icons.wifi), name: 'box2', isConnected: true);
+ @override
+ void initState() {
+ currentWifi = wifiList[0];
+ super.initState();
+ }
+
+ void setCurrentWifi(int index) {
+ setState(() {
+ currentWifi = wifiList[index];
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ ref.watch(usersProvider.select((user) => user.selectedUser));
+
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ CommonTitle(
+ title: "Wifi",
+ hasBackButton: true,
+ onPressed: () {
+ context.flow<AppState>().update((state) => AppState.settings);
+ },
+ ),
+ Expanded(
+ child: ListView.separated(
+ padding: const EdgeInsets.symmetric(vertical: 50, horizontal: 144),
+ itemCount: wifiList.length,
+ separatorBuilder: (context, index) {
+ return const SizedBox(
+ height: 8,
+ );
+ },
+ itemBuilder: (context, index) {
+ return Container(
+ height: 130,
+
+ decoration: BoxDecoration(
+ gradient: LinearGradient(
+ begin: Alignment.centerLeft,
+ end: Alignment.centerRight,
+ stops: currentWifi == wifiList[index]
+ ? [0, 0.01, 0.8]
+ : [0.1, 1],
+ colors: currentWifi == wifiList[index]
+ ? <Color>[
+ Colors.white,
+ Colors.blue,
+ const Color.fromARGB(16, 41, 98, 255)
+ ]
+ : <Color>[Colors.black, Colors.black12]),
+ ),
+ child: ListTile(
+ contentPadding:
+ const EdgeInsets.symmetric(vertical: 41, horizontal: 24),
+
+ leading: wifiList[index].icon,
+ title: Text(
+ wifiList[index].name,
+ style: Theme.of(context).textTheme.titleMedium,
+ ),
+ onTap: () {
+ setCurrentWifi(index);
+ },
+ ),
+ );
+ },
+ ),
+ ),
+ // Container(
+ // padding: const EdgeInsets.symmetric(
+ // horizontal: 175,
+ // ),
+ // child: ElevatedButton(
+ // style: ElevatedButton.styleFrom(
+ // backgroundColor: const Color(0xFF1C2D92),
+ // ),
+ // child: const Padding(
+ // padding: EdgeInsets.symmetric(horizontal: 0, vertical: 15),
+ // child: Text(
+ // 'New Profile',
+ // textAlign: TextAlign.center,
+ // style: TextStyle(
+ // color: Color(0xFFC1D8FF),
+ // fontSize: 20,
+ // ),
+ // ),
+ // ),
+ // onPressed: () {
+ // //context.flow<AppState>().update((state) => AppState.newProfile);
+ // },
+ // ),
+ // ),
+ ],
+ );
+ }
+}
diff --git a/lib/presentation/screens/settings/settings_screens/wifi/wifi_screen.dart b/lib/presentation/screens/settings/settings_screens/wifi/wifi_screen.dart
new file mode 100644
index 0000000..1f85ae8
--- /dev/null
+++ b/lib/presentation/screens/settings/settings_screens/wifi/wifi_screen.dart
@@ -0,0 +1,17 @@
+
+import 'package:flutter_ics_homescreen/export.dart';
+import 'widgets/wifi_content.dart';
+
+class WifiPage extends StatelessWidget {
+ const WifiPage({super.key});
+
+ static Page<void> page() => const MaterialPage<void>(child: WifiPage());
+ @override
+ Widget build(BuildContext context) {
+ //final currentUser =
+ //ref.watch(usersProvider.select((user) => user.selectedUser));
+
+ return const Scaffold(body: WifiContent());
+ }
+}
+
diff --git a/lib/presentation/screens/settings/settings_screens/wired/wired_screen.dart b/lib/presentation/screens/settings/settings_screens/wired/wired_screen.dart
new file mode 100644
index 0000000..916b1b6
--- /dev/null
+++ b/lib/presentation/screens/settings/settings_screens/wired/wired_screen.dart
@@ -0,0 +1,76 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+class WiredPage extends ConsumerWidget {
+ const WiredPage({super.key});
+
+ static Page<void> page() => const MaterialPage<void>(child: WiredPage());
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ return Scaffold(
+ body: Column(
+ children: [
+ CommonTitle(
+ title: 'Wired',
+ hasBackButton: true,
+ onPressed: () {
+ context.flow<AppState>().update((state) => AppState.settings);
+ },
+ ),
+ Padding(
+ padding: const EdgeInsets.symmetric(vertical: 50, horizontal: 80),
+ child: Container(
+ height: 130,
+ decoration: const BoxDecoration(
+ gradient: LinearGradient(
+ begin: Alignment.centerLeft,
+ end: Alignment.centerRight,
+ stops: [
+ 0,
+ 0.01,
+ 0.8
+ ],
+ colors: <Color>[
+ Colors.white,
+ Colors.blue,
+ Color.fromARGB(16, 41, 98, 255)
+ ]),
+ ),
+ child: ListTile(
+ contentPadding:
+ const EdgeInsets.symmetric(vertical: 41, horizontal: 24),
+
+ title: const Text(
+ 'hernet_0090451v407b_cable',
+ style: TextStyle(color: Colors.white, fontSize: 40),
+ ),
+ subtitle: const Text(
+ 'connected, 192.168.234.120',
+ style: TextStyle(color: Colors.white, fontSize: 26),
+ ),
+ trailing: ElevatedButton(
+ style: ElevatedButton.styleFrom(
+ backgroundColor: const Color(0xFF1C2D92),
+ side: const BorderSide(color: Color(0xFF285DF4), width: 2),
+ ),
+ child: const Padding(
+ padding:
+ EdgeInsets.symmetric(vertical: 15.0, horizontal: 0),
+ child: Text(
+
+ 'Configure',
+ style: TextStyle(
+ color: Color(0xFFC1D8FF),
+ fontSize: 26,
+ ),
+ ),
+ ),
+ onPressed: () {},
+ ),
+ ),
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/screens/settings/widgets/settings_content.dart b/lib/presentation/screens/settings/widgets/settings_content.dart
new file mode 100644
index 0000000..f73bf6d
--- /dev/null
+++ b/lib/presentation/screens/settings/widgets/settings_content.dart
@@ -0,0 +1,95 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+import '../../../custom_icons/custom_icons.dart';
+
+class Settings extends StatelessWidget {
+ const Settings({
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ mainAxisAlignment: MainAxisAlignment.start,
+ //crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ const CommonTitle(
+ title: 'Settings',
+ ),
+ Expanded(
+ child: ListView(
+ padding: const EdgeInsets.symmetric(vertical: 50, horizontal: 144),
+ children: [
+ SettingsTile(
+ icon: Icons.calendar_month_outlined,
+ title: 'Date & Time',
+ hasSwich: false,
+ voidCallback: () async {
+ context
+ .flow<AppState>()
+ .update((next) => AppState.dateTime);
+ }),
+ SettingsTile(
+ icon: Icons.bluetooth,
+ title: 'Bluetooth',
+ hasSwich: true,
+ voidCallback: () {
+ context
+ .flow<AppState>()
+ .update((next) => AppState.bluetooth);
+ }),
+ SettingsTile(
+ icon: Icons.wifi,
+ title: 'Wifi',
+ hasSwich: true,
+ voidCallback: () {
+ context.flow<AppState>().update((next) => AppState.wifi);
+ }),
+ SettingsTile(
+ icon: CustomIcons.wiredicon,
+ title: 'Wired',
+ hasSwich: false,
+ voidCallback: () {
+ context.flow<AppState>().update((next) => AppState.wired);
+ }),
+ SettingsTile(
+ icon: Icons.tune,
+ title: 'Audio Settings',
+ hasSwich: false,
+ voidCallback: () {
+ context
+ .flow<AppState>()
+ .update((next) => AppState.audioSettings);
+ }),
+ SettingsTile(
+ icon: Icons.person_2_outlined,
+ title: 'Profiles',
+ hasSwich: false,
+ voidCallback: () {
+ context
+ .flow<AppState>()
+ .update((next) => AppState.profiles);
+ }),
+ SettingsTile(
+ icon: Icons.straighten,
+ title: 'Units',
+ hasSwich: false,
+ voidCallback: () {
+ context.flow<AppState>().update((next) => AppState.units);
+ }),
+ SettingsTile(
+ icon: Icons.help_sharp,
+ title: 'Version Info',
+ hasSwich: false,
+ voidCallback: () {
+ context
+ .flow<AppState>()
+ .update((next) => AppState.versionInfo);
+ }),
+ ],
+ ),
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/presentation/screens/settings/widgets/settings_list_tile.dart b/lib/presentation/screens/settings/widgets/settings_list_tile.dart
new file mode 100644
index 0000000..4720001
--- /dev/null
+++ b/lib/presentation/screens/settings/widgets/settings_list_tile.dart
@@ -0,0 +1,234 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+class SettingsTile extends ConsumerStatefulWidget {
+ final IconData icon;
+ final String title;
+ final bool hasSwich;
+ final VoidCallback voidCallback;
+ const SettingsTile({
+ Key? key,
+ required this.icon,
+ required this.title,
+ required this.hasSwich,
+ required this.voidCallback,
+ }) : super(key: key);
+
+ @override
+ SettingsTileState createState() => SettingsTileState();
+}
+
+class SettingsTileState extends ConsumerState<SettingsTile> {
+ bool isSwitchOn = true;
+ @override
+ Widget build(BuildContext context) {
+ final signal = ref.watch(signalsProvider.select((signal) => signal));
+ if (widget.title == 'Bluetooth') {
+ isSwitchOn = signal.isBluetoothConnected;
+ } else if (widget.title == 'Wifi') {
+ isSwitchOn = signal.isWifiConnected;
+ } else {
+ // isSwitchOn = false;
+ }
+ return Column(
+ children: [
+ GestureDetector(
+ onTap: isSwitchOn ? widget.voidCallback : () {},
+ child: Container(
+ height: 130,
+ decoration: BoxDecoration(
+ gradient: LinearGradient(
+ begin: Alignment.centerLeft,
+ end: Alignment.centerRight,
+ stops: isSwitchOn ? [0.3, 1] : [0.8, 1],
+ colors: isSwitchOn
+ ? <Color>[Colors.black, Colors.black12]
+ : <Color>[
+ const Color.fromARGB(50, 0, 0, 0),
+ Colors.transparent
+ ],
+ ),
+ ),
+ child: Card(
+ // shape: RoundedRectangleBorder(
+ // borderRadius: BorderRadius.circular(12),
+ // ),
+ color: Colors.transparent,
+ elevation: 5,
+ child: Padding(
+ padding:
+ const EdgeInsets.symmetric(vertical: 0, horizontal: 24),
+ child: Row(
+ children: [
+ Icon(
+ widget.icon,
+ color: AGLDemoColors.periwinkleColor,
+ size: 48,
+ ),
+ const SizedBox(width: 24),
+ Expanded(
+ child: Text(
+ widget.title,
+ style: const TextStyle(fontSize: 40),
+ ),
+ ),
+ widget.hasSwich
+ ? Container(
+ width: 126,
+ height: 80,
+ decoration: const ShapeDecoration(
+ color:
+ AGLDemoColors.gradientBackgroundDarkColor,
+ shape: StadiumBorder(
+ side: BorderSide(
+ color: Color(0xFF5477D4),
+ width: 4,
+ )),
+ ),
+ child: FittedBox(
+ fit: BoxFit.fill,
+ child: Switch(
+ value: isSwitchOn,
+ onChanged: (bool value) {
+ switch (widget.title) {
+ case 'Bluetooth':
+ ref
+ .read(signalsProvider.notifier)
+ .toggleBluetooth();
+ break;
+ case 'Wifi':
+ ref
+ .read(signalsProvider.notifier)
+ .toggleWifi();
+ break;
+ default:
+ }
+ setState(() {
+ isSwitchOn = value;
+ });
+ // This is called when the user toggles the switch.
+ },
+ inactiveTrackColor: Colors.transparent,
+ activeTrackColor: Colors.transparent,
+ thumbColor:
+ MaterialStateProperty.all<Color>(
+ AGLDemoColors.periwinkleColor)),
+ ),
+ )
+ : const SizedBox(),
+ ],
+ ),
+ ),
+ )
+ // ListTile(
+ // contentPadding:
+ // const EdgeInsets.symmetric(vertical: 41, horizontal: 24),
+ // minLeadingWidth: 55.0,
+ // minVerticalPadding: 0.0,
+ // leading: Icon(
+ // widget.icon,
+ // color: AGLDemoColors.periwinkleColor,
+ // size: 48,
+ // ),
+ // title: Text(
+ // widget.title,
+ // style: const TextStyle(fontSize: 40),
+ // ),
+ // enabled: isSwitchOn,
+ // trailing: widget.hasSwich
+ // ? Container(
+ // width: 126,
+ // height: 80,
+ // decoration: const ShapeDecoration(
+ // color: AGLDemoColors.gradientBackgroundDarkColor,
+ // shape: StadiumBorder(
+ // side: BorderSide(
+ // color: Color(0xFF5477D4),
+ // //color: Colors.amber,
+
+ // width: 1.5,
+ // )),
+ // ),
+ // child: Switch(
+ // value: isSwitchOn,
+ // onChanged: (bool value) {
+ // switch (widget.title) {
+ // case 'Bluetooth':
+ // ref
+ // .read(signalsProvider.notifier)
+ // .toggleBluetooth();
+ // break;
+ // case 'Wifi':
+ // ref.read(signalsProvider.notifier).toggleWifi();
+ // break;
+ // default:
+ // }
+ // setState(() {
+ // isSwitchOn = value;
+ // });
+ // // This is called when the user toggles the switch.
+ // },
+ // inactiveTrackColor: Colors.transparent,
+ // activeTrackColor: Colors.transparent,
+ // thumbColor: MaterialStateProperty.all<Color>(
+ // AGLDemoColors.periwinkleColor)),
+ // )
+ // : const SizedBox(
+ // //Spacer
+ // height: 80,
+ // ),
+ // onTap: widget.voidCallback,
+
+ // ),
+ ),
+ ),
+ const SizedBox(
+ height: 8,
+ )
+ ],
+ );
+ }
+}
+
+// List<SettingsTile> settingsList = [
+// SettingsTile(
+// icon: Icons.calendar_month_outlined,
+// title: 'Date & Time',
+// hasSwich: false,
+// voidCallback: () {}),
+// SettingsTile(
+// icon: Icons.bluetooth,
+// title: 'Bluetooth',
+// hasSwich: true,
+// voidCallback: () {}),
+// SettingsTile(
+// icon: Icons.wifi,
+// title: 'Wifi',
+// hasSwich: true,
+// voidCallback: () {},
+// ),
+// SettingsTile(
+// icon: Icons.settings,
+// title: 'Wired',
+// hasSwich: false,
+// voidCallback: () {}),
+// SettingsTile(
+// icon: Icons.tune,
+// title: 'Audio Settings',
+// hasSwich: false,
+// voidCallback: () {}),
+// SettingsTile(
+// icon: Icons.person_2_outlined,
+// title: 'Profiles',
+// hasSwich: false,
+// voidCallback: () {}),
+// SettingsTile(
+// icon: Icons.straighten,
+// title: 'Units',
+// hasSwich: false,
+// voidCallback: () {}),
+// SettingsTile(
+// icon: Icons.help_sharp,
+// title: 'Veriosn Info',
+// hasSwich: false,
+// voidCallback: () {}),
+// ];
diff --git a/lib/presentation/screens/splash/splash.dart b/lib/presentation/screens/splash/splash.dart
new file mode 100644
index 0000000..a51f425
--- /dev/null
+++ b/lib/presentation/screens/splash/splash.dart
@@ -0,0 +1,26 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+class SplashPage extends StatelessWidget {
+ const SplashPage({super.key});
+
+ static Page<void> page() => const MaterialPage<void>(child: SplashPage());
+ @override
+ Widget build(BuildContext context) {
+ final size = MediaQuery.of(context).size;
+ debugPrint(size.width.toString());
+ debugPrint(size.height.toString());
+ return Stack(
+ children: [
+ SizedBox(
+ width: double.infinity,
+ height: double.infinity,
+ child: SvgPicture.asset(
+ 'assets/splashTextures.svg',
+ alignment: Alignment.center,
+ ),
+ ),
+ const Center(child: SplashContent()),
+ ],
+ );
+ }
+}
diff --git a/lib/presentation/screens/splash/widget/splash_content.dart b/lib/presentation/screens/splash/widget/splash_content.dart
new file mode 100644
index 0000000..325baeb
--- /dev/null
+++ b/lib/presentation/screens/splash/widget/splash_content.dart
@@ -0,0 +1,142 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+class SplashContent extends ConsumerStatefulWidget {
+ const SplashContent({super.key});
+
+ @override
+ SplashContentState createState() => SplashContentState();
+}
+
+class SplashContentState extends ConsumerState<SplashContent>
+ with TickerProviderStateMixin {
+ late Animation<double> _fadeAnimation;
+ late AnimationController _lottieController;
+ late AnimationController _fadeController;
+ bool _showLottieAnimation =
+ true; // New state to control the visibility of Lottie animation
+
+ @override
+ void initState() {
+ super.initState();
+ // If you need to control the Lottie animation, initialize its controller
+ _lottieController = AnimationController(
+ vsync: this,
+ duration: const Duration(seconds: 7),
+ );
+
+ Future.delayed(const Duration(milliseconds: 1500), () {
+ _lottieController.repeat();
+ });
+
+ // Initialize the fade animation controller
+ _fadeController = AnimationController(
+ vsync: this,
+ duration: const Duration(seconds: 1), // Fade transition duration
+ );
+
+ // Set up the fade animation
+ _fadeAnimation =
+ Tween<double>(begin: 0.0, end: 1.0).animate(_fadeController)
+ ..addListener(() {
+ // Check the status of the animation and set the state to hide Lottie when fading starts.
+ if (_fadeAnimation.value > 0.0 && _showLottieAnimation) {
+ setState(() {
+ _showLottieAnimation = false;
+ });
+ }
+ });
+
+ // Start the fade-in transition after the Lottie animation has played for some time
+ Future.delayed(const Duration(seconds: 6), () {
+ // Stop the Lottie animation if needed
+ _lottieController.stop();
+
+ // Start the fade-in transition
+ _fadeController.forward();
+ });
+ }
+
+ @override
+ void dispose() {
+ // Dispose the animation controller to release resources.
+ _fadeController.dispose();
+ _lottieController.dispose();
+ super.dispose();
+ }
+
+ @override
+ void didChangeDependencies() {
+ ref.read(vehicleProvider.notifier).startListen();
+ super.didChangeDependencies();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Stack(
+ children: [
+ if (_showLottieAnimation)
+ Center(
+ child: Lottie.asset(
+ 'animations/Logo_JSON.json',
+ controller: _lottieController,
+ onLoaded: (composition) {
+ _lottieController.duration = composition.duration;
+ },
+ ),
+ ),
+ // FadeTransition wraps existing UI.
+ FadeTransition(
+ opacity: _fadeAnimation,
+ child: Center(
+ child: buildWarningUI(),
+ ),
+ ),
+ ],
+ );
+ }
+
+ Widget buildWarningUI() {
+ return Column(
+ children: [
+ const Expanded(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Text(
+ 'WARNING:',
+ style: TextStyle(color: Color(0xFFC1D8FF), fontSize: 44),
+ ),
+ SizedBox(height: 38),
+ SizedBox(
+ //color: Colors.amber,
+ width: 757,
+ height: 488,
+ child: Text(
+ splashWarning,
+ style: TextStyle(color: Colors.white, fontSize: 40, height: 1.7, fontWeight: FontWeight.w400),
+ textAlign: TextAlign.left,
+
+ ),
+ ),
+ ],
+ ),
+ ),
+ GenericButton(
+ heigth: 122,
+ width: 452,
+ text: 'Continue',
+ onTap: () {
+ ref.read(vehicleProvider.notifier).setInitialState();
+ ref
+ .read(appProvider.notifier)
+ .update((state) => state = AppState.dashboard);
+ },
+ ),
+
+ const SizedBox(
+ height: 72,
+ )
+ ],
+ );
+ }
+}
diff --git a/lib/presentation/screens/weather/hourly_forecast.dart b/lib/presentation/screens/weather/hourly_forecast.dart
new file mode 100644
index 0000000..aed8a6c
--- /dev/null
+++ b/lib/presentation/screens/weather/hourly_forecast.dart
@@ -0,0 +1,152 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+class HourlyForecast extends StatefulWidget {
+ const HourlyForecast({super.key});
+
+ @override
+ State<HourlyForecast> createState() => _HourlyForecastState();
+}
+
+class _HourlyForecastState extends State<HourlyForecast> {
+ String selectedForescastTime = "13:00";
+ List<ForecastModel> foreCastList = [
+ ForecastModel(
+ time: "13:00", image: "assets/weatherStat.svg", weather: "29.1°"),
+ ForecastModel(
+ time: "14:00", image: "assets/weatherStat.svg", weather: "28.1°"),
+ ForecastModel(
+ time: "15:00", image: "assets/weatherStat.svg", weather: "27.1°"),
+ ForecastModel(
+ time: "16:00", image: "assets/weatherStat.svg", weather: "29.1°"),
+ ForecastModel(
+ time: "13:00", image: "assets/weatherStat.svg", weather: "29.1°"),
+ ForecastModel(
+ time: "14:00", image: "assets/weatherStat.svg", weather: "28.1°"),
+ ForecastModel(
+ time: "15:00", image: "assets/weatherStat.svg", weather: "27.1°"),
+ ForecastModel(
+ time: "16:00", image: "assets/weatherStat.svg", weather: "29.1°"),
+ ];
+ @override
+ Widget build(BuildContext context) {
+ double weatherIconSize = 126;
+ return Container(
+ padding: const EdgeInsets.all(1),
+ decoration: BoxDecoration(
+ gradient: LinearGradient(colors: [
+ AGLDemoColors.periwinkleColor.withOpacity(0.2),
+ AGLDemoColors.periwinkleColor
+ ]),
+ boxShadow: [
+ BoxShadow(
+ offset: const Offset(1, 2),
+ blurRadius: 16,
+ color: Colors.black.withOpacity(0.5))
+ ],
+ borderRadius: BorderRadius.circular(40),
+ // border: Border.all(color: Colors.white12),
+ ),
+ child: Container(
+ padding: const EdgeInsets.only(top: 5, bottom: 20, left: 5, right: 5),
+ decoration: BoxDecoration(
+ borderRadius: BorderRadius.circular(40),
+ // border: Border.all(color: AGLDemoColors.periwinkleColor),
+ // boxShadow: [
+ // BoxShadow(
+ // offset: const Offset(1, 2),
+ // blurRadius: 16,
+ // color: Colors.black.withOpacity(0.5))
+ // ],
+ gradient: const RadialGradient(
+ //center: Alignment(0.7, -0.6), // near the top right
+ radius: 1,
+ colors: <Color>[
+ Color.fromARGB(255, 12, 16, 57), // yellow sun
+ Color.fromARGB(255, 0, 0, 0), // blue sky
+ ],
+ ),
+ ),
+ child:
+ Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 10),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ const Text(
+ "Hourly Forecast",
+ style: TextStyle(
+ color: Colors.white,
+ fontWeight: FontWeight.w500,
+ fontSize: 44),
+ ),
+ Text(
+ "March 9",
+ style: GoogleFonts.firaSans(
+ color: Colors.white,
+ fontWeight: FontWeight.w200,
+ fontSize: 44),
+ ),
+ ]),
+ ),
+ const SizedBox(
+ height: 20,
+ ),
+ SizedBox(
+ height: 320,
+ child: ListView.builder(
+ itemCount: foreCastList.length,
+ shrinkWrap: true,
+ padding: EdgeInsets.zero,
+ scrollDirection: Axis.horizontal,
+ itemBuilder: (context, index) {
+ return Container(
+ margin: const EdgeInsets.symmetric(horizontal: 32),
+ decoration: BoxDecoration(
+ borderRadius: BorderRadius.circular(32),
+ color: foreCastList[index].time == selectedForescastTime
+ ? AGLDemoColors.resolutionBlueColor
+ : Colors.transparent),
+ padding: const EdgeInsets.symmetric(
+ horizontal: 18, vertical: 10),
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Text(
+ foreCastList[index].time,
+ style: GoogleFonts.firaSans(
+ fontWeight: FontWeight.w100,
+ color: Colors.white,
+ fontSize: 40),
+ ),
+ Padding(
+ padding: const EdgeInsets.symmetric(vertical: 30),
+ child: SvgPicture.asset(
+ "assets/weatherStat.svg",
+ width: weatherIconSize,
+ height: weatherIconSize,
+ ),
+ ),
+ Text(
+ foreCastList[index].weather,
+ style: const TextStyle(
+ color: Colors.white, fontSize: 40),
+ ),
+ ]),
+ );
+ }),
+ )
+ ]),
+ ),
+ );
+ }
+}
+
+class ForecastModel {
+ final String time;
+ final String image;
+ final String weather;
+
+ ForecastModel(
+ {required this.time, required this.image, required this.weather});
+}
diff --git a/lib/presentation/screens/weather/weather.dart b/lib/presentation/screens/weather/weather.dart
new file mode 100644
index 0000000..7231700
--- /dev/null
+++ b/lib/presentation/screens/weather/weather.dart
@@ -0,0 +1,91 @@
+import 'package:flutter_ics_homescreen/export.dart';
+
+class WeatherPage extends ConsumerWidget {
+ const WeatherPage({super.key});
+
+ static Page<void> page() => const MaterialPage<void>(child: WeatherPage());
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ double weatherIconSize = MediaQuery.sizeOf(context).width * 0.278;
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ CommonTitle(
+ title: "Weather",
+ hasBackButton: true,
+ onPressed: () {
+ context.flow<AppState>().update((state) => AppState.apps);
+ },
+ ),
+ const SizedBox(
+ height: 25,
+ ),
+ Expanded(
+ child: Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 144),
+ child: SingleChildScrollView(
+ child: Column(
+ children: [
+ const Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Icon(
+ Icons.location_on_outlined,
+ color: Colors.white,
+ size: 48,
+ ),
+ SizedBox(
+ width: 7,
+ ),
+ Text(
+ "Fortaleza",
+ style: TextStyle(
+ color: Colors.white,
+ fontSize: 40,
+ fontWeight: FontWeight.w500),
+ ),
+ ],
+ ),
+ const SizedBox(
+ height: 80,
+ ),
+ SvgPicture.asset(
+ "assets/weatherStat.svg",
+ width: weatherIconSize,
+ height: weatherIconSize,
+ ),
+ const SizedBox(
+ height: 60,
+ ),
+ Text(
+ "28.3°C",
+ style: GoogleFonts.brunoAce(
+ color: Colors.white, fontSize: 128),
+ ),
+ const Padding(
+ padding: EdgeInsets.all(30.0),
+ child: Text(
+ "Partially Cloudy",
+ style: TextStyle(color: Colors.white, fontSize: 44),
+ ),
+ ),
+ const SizedBox(
+ height: 5,
+ ),
+ const Text(
+ "Max: 31° Min: 25°",
+ style: TextStyle(color: Colors.white, fontSize: 40),
+ ),
+ const SizedBox(
+ height: 80,
+ ),
+ const HourlyForecast()
+ ],
+ ),
+ ),
+ ),
+ )
+ ],
+ );
+ }
+}