summaryrefslogtreecommitdiffstats
path: root/lib/presentation/screens
diff options
context:
space:
mode:
authorLisandro Pérez Meyer <lpmeyer@ics.com>2023-11-14 17:20:58 -0300
committerLisandro Pérez Meyer <lpmeyer@ics.com>2023-11-14 17:31:12 -0300
commit70ec8a79a121471a004e7e4c23157d10157e136f (patch)
treea4f9c0a4fac4e4274ec4324a289b6ef62e1c5653 /lib/presentation/screens
Initial cleanup push.
Based on agldemo2024 on commit 2a5dc04d801134338150c3f6afc67eaa65599763 Disable device preview. Disable Lottie animation. The original commit was b3c493c340fcb4bb0a937692838fc830bec3e9ea but I am just keeping this change, because the json did not really needed to change. I think. Signed-off-by: Lisandro Pérez Meyer <lpmeyer@ics.com>
Diffstat (limited to 'lib/presentation/screens')
-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
60 files changed, 7528 insertions, 0 deletions
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()
+ ],
+ ),
+ ),
+ ),
+ )
+ ],
+ );
+ }
+}