diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/HomePage.dart | 469 | ||||
-rw-r--r-- | lib/Kuksa-server/intial_connection.dart | 38 | ||||
-rw-r--r-- | lib/Kuksa-server/onBoarding_page.dart | 61 | ||||
-rw-r--r-- | lib/Kuksa-server/vehicle_class.dart | 75 | ||||
-rw-r--r-- | lib/Kuksa-server/vehicle_config.dart | 39 | ||||
-rw-r--r-- | lib/Kuksa-server/vehicle_methods.dart | 190 | ||||
-rw-r--r-- | lib/Kuksa-server/vehicle_provider.dart | 64 | ||||
-rw-r--r-- | lib/Kuksa-server/vehicle_server_path.dart | 34 | ||||
-rw-r--r-- | lib/Tier_pressure.dart | 60 | ||||
-rw-r--r-- | lib/config.dart | 111 | ||||
-rw-r--r-- | lib/drawArrow.dart | 81 | ||||
-rw-r--r-- | lib/main.dart | 28 | ||||
-rw-r--r-- | lib/provider.dart | 41 | ||||
-rw-r--r-- | lib/size.dart | 48 | ||||
-rw-r--r-- | lib/widgets/child_lock.dart | 61 | ||||
-rw-r--r-- | lib/widgets/fuel_and_speed.dart | 111 | ||||
-rw-r--r-- | lib/widgets/weather.dart | 84 |
17 files changed, 1595 insertions, 0 deletions
diff --git a/lib/HomePage.dart b/lib/HomePage.dart new file mode 100644 index 0000000..c583fbf --- /dev/null +++ b/lib/HomePage.dart @@ -0,0 +1,469 @@ +// SPDX-License-Identifier: Apache-2.0 +import 'package:dashboard_app/Tier_pressure.dart'; +import 'package:dashboard_app/drawArrow.dart'; +import 'package:dashboard_app/provider.dart'; +import 'package:dashboard_app/size.dart'; +import 'package:dashboard_app/widgets/child_lock.dart'; +import 'package:dashboard_app/widgets/fuel_and_speed.dart'; +import 'package:dashboard_app/widgets/weather.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:latlng/latlng.dart'; + + + +import 'Kuksa-server/vehicle_provider.dart'; + + +class HomePage extends ConsumerStatefulWidget { + const HomePage({Key? key}) : super(key: key); + + @override + _HomePageState createState() => _HomePageState(); +} + +class _HomePageState extends ConsumerState<HomePage> { + @override + Widget build(BuildContext context) { + SizeConfig().init(context); + final vehicle = ref.watch(vehicleSignalProvider); + LatLng pos = LatLng(vehicle.currentLatitude, vehicle.currentLongitude); + + DateTime _now = ref.watch(DateTimeProvider); + + + + return Scaffold( + backgroundColor: Colors.black87, + body: OrientationBuilder( + builder: (context, orientation) { + if (orientation == Orientation.landscape) { + return Stack( + children: [ + SizedBox( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height, + child: Container( + color: Colors.black87, + ), + ), + + + + + Positioned( + right: SizeConfig.safeBlockHorizontal * 41, + top: SizeConfig.safeBlockVertical * 58, + child: ChildLockStatus( + isChildLockActiveLeft: vehicle.isChildLockActiveLeft, + isChildLockActiveRight: vehicle.isChildLockActiveRight), + ), + + Positioned( + top: SizeConfig.safeBlockVertical * 18, + right: SizeConfig.safeBlockHorizontal * 38, + child: Column( + + children: [ + TierPressure( + tname: 'L Front Tier', + tpress: vehicle.frontLeftTP, + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.end, + ), + Container( + height: SizeConfig.safeBlockVertical * 10, + width: SizeConfig.safeBlockHorizontal * 12, + child: CustomPaint( + painter: Arrowpaint2(), + ), + ) + ], + ), + ), + Positioned( + top: SizeConfig.safeBlockVertical * 65, + right: SizeConfig.safeBlockHorizontal * 38, + child: Column( + + children: [ + RotatedBox( + quarterTurns: 2, + child: Container( + height: SizeConfig.safeBlockVertical * 10, + width: SizeConfig.safeBlockHorizontal * 12, + child: CustomPaint( + painter: Arrowpaint(), + ), + ), + ), + TierPressure( + tname: 'L Rear Tier', + tpress: vehicle.rearLeftTP, + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.start, + ), + ], + ), + ), + Positioned( + top: SizeConfig.safeBlockVertical * 18, + right: SizeConfig.safeBlockHorizontal * 7, + child: Column( + children: [ + TierPressure( + tname: 'R Front Tier', + tpress: vehicle.frontRightTP, + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.start, + ), + Container( + height: SizeConfig.safeBlockVertical * 10, + width: SizeConfig.safeBlockHorizontal * 12, + child: CustomPaint( + painter: Arrowpaint(), + ), + ), + ], + ), + ), + Positioned( + top: SizeConfig.safeBlockVertical * 65, + right: SizeConfig.safeBlockHorizontal * 7, + child: Column( + children: [ + RotatedBox( + quarterTurns: 2, + child: Container( + height: SizeConfig.safeBlockVertical * 10, + width: SizeConfig.safeBlockHorizontal * 12, + child: CustomPaint( + painter: Arrowpaint2(), + ), + ), + ), + TierPressure( + tname: 'R Rear Tier', + tpress: vehicle.rearRightTP, + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + ), + ], + ), + ), + Positioned( + top: SizeConfig.safeBlockVertical * 20, + right: SizeConfig.blockSizeHorizontal * 13, + bottom: SizeConfig.blockSizeVertical * 20, + child: SizedBox( + height: SizeConfig.screenHeight * 0.6, + width: SizeConfig.screenWidth * 0.30, + child: AnimatedContainer( + duration: Duration(milliseconds: 10), + child: Image.asset('images/car_img.png'), + ), + ), + ), + + Positioned( + top: SizeConfig.safeBlockVertical * 7, + left: SizeConfig.safeBlockHorizontal * 2, + bottom: SizeConfig.safeBlockVertical * 4, + child: Container( + width: SizeConfig.screenWidth / 2, + height: SizeConfig.screenHeight * 0.75, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Rpm(rpm: vehicle.rpm), + + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Avg. Fuel Consumtion', + style: SizeConfig.smallnormalfont, + ), + Text( + vehicle.fuelRate.toString() + ' KM/Litre', + style: SizeConfig.smallnormalfont, + ), + ], + ), + // ignore: prefer_const_constructors + weather( + insideTemperatue: vehicle.insideTemperature, + outsideTempearure: vehicle.outsideTemperature, + ), + SpeedAndFuel( + fuel: vehicle.fuelLevel, speed: vehicle.speed), + ], + ), + )) + ], + ); + } + //--------------------------Portrait mode ------------------------------------------------ + else { + return Stack( + children: [ + Positioned( + top: 0, + bottom: 0, + left: 0, + right: 0, + child: Padding( + padding: EdgeInsets.fromLTRB( + SizeConfig.safeBlockHorizontal * 2, + SizeConfig.safeBlockVertical * 2, + SizeConfig.safeBlockHorizontal * 2, + 0), + + child: Column( + children: [ + Flexible(flex: 1, child: SizedBox()), + SizedBox( + height: SizeConfig.safeBlockVertical, + ), + Flexible( + flex: 1, + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + ], + ), + ), + + SizedBox( + height: SizeConfig.safeBlockVertical, + ), + Flexible( + flex: 2, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Flexible( + flex: 1, + child: weather( + insideTemperatue: vehicle.insideTemperature, + outsideTempearure: + vehicle.outsideTemperature, + ), + ), + Flexible( + flex: 2, + child: SpeedAndFuel( + fuel: vehicle.fuelLevel, + speed: vehicle.speed), + ), + ], + ), + ), + SizedBox( + height: SizeConfig.safeBlockVertical * 6, + ), + Flexible( + flex: 5, + child: Container( + + + // color: Colors.red, + height: SizeConfig.screenHeight * 0.6, + width: SizeConfig.screenWidth * 0.53, + child: Stack( + children: [ + Positioned( + top: 0, + left: 0, + child: Column( + mainAxisAlignment: + MainAxisAlignment.start, + crossAxisAlignment: + CrossAxisAlignment.end, + children: [ + TierPressure( + tname: 'L Front Tire', + tpress: vehicle.frontLeftTP, + mainAxisAlignment: + MainAxisAlignment.end, + crossAxisAlignment: + CrossAxisAlignment.end, + ), + Container( + height: + SizeConfig.safeBlockVertical * 6, + width: + SizeConfig.safeBlockHorizontal * + 12, + child: CustomPaint( + painter: Arrowpaint2(), + ), + ), + ], + ), + ), + Positioned( + bottom: 0, + left: 0, + child: Column( + children: [ + ChildLockStatus( + isChildLockActiveLeft: + vehicle.isChildLockActiveLeft, + isChildLockActiveRight: + vehicle.isChildLockActiveRight), + RotatedBox( + quarterTurns: 2, + child: Container( + height: + SizeConfig.safeBlockVertical * + 6, + width: + SizeConfig.safeBlockHorizontal * + 12, + child: CustomPaint( + painter: Arrowpaint(), + ), + ), + ), + TierPressure( + tname: 'L Rear Tire', + tpress: vehicle.rearLeftTP, + mainAxisAlignment: + MainAxisAlignment.start, + crossAxisAlignment: + CrossAxisAlignment.end, + ), + ], + ), + ), + Positioned( + top: 0, + bottom: 0, + left: SizeConfig.safeBlockHorizontal * 12, + right: SizeConfig.safeBlockHorizontal * 12, + child: SizedBox( + + child: AnimatedContainer( + duration: Duration(milliseconds: 10), + child: Image.asset( + 'images/car_img.png', + fit: BoxFit.fill, + ), + ), + ), + ), + Positioned( + right: 0, + top: 0, + child: Column( + children: [ + TierPressure( + tname: 'R Front Tire', + tpress: vehicle.frontRightTP, + mainAxisAlignment: + MainAxisAlignment.end, + crossAxisAlignment: + CrossAxisAlignment.start, + ), + Container( + height: + SizeConfig.safeBlockVertical * 6, + width: + SizeConfig.safeBlockHorizontal * + 12, + child: CustomPaint( + painter: Arrowpaint(), + ), + ), + ], + ), + ), + Positioned( + bottom: 0, + right: 0, + child: Column( + children: [ + ChildLockStatus( + isChildLockActiveLeft: + vehicle.isChildLockActiveLeft, + isChildLockActiveRight: + vehicle.isChildLockActiveRight), + RotatedBox( + quarterTurns: 2, + child: Container( + height: + SizeConfig.safeBlockVertical * + 6, + width: + SizeConfig.safeBlockHorizontal * + 12, + child: CustomPaint( + painter: Arrowpaint2(), + ), + ), + ), + TierPressure( + tname: 'R Rear Tire', + tpress: vehicle.rearRightTP, + mainAxisAlignment: + MainAxisAlignment.start, + crossAxisAlignment: + CrossAxisAlignment.start, + ), + ], + ), + ), + ], + ), + ), + ), + SizedBox( + height: SizeConfig.safeBlockVertical, + ), + Flexible( + flex: 1, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Flexible( + flex: 1, + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + 'Avg. Fuel Consumtion', + style: SizeConfig.smallnormalfont2, + ), + Text( + vehicle.fuelRate.toString() + + ' KM/Litre', + style: SizeConfig.smallnormalfont, + ), + ], + ), + ), + Flexible(flex: 1, child: Rpm(rpm: vehicle.rpm)), + ], + ), + ), + + ], + ), + ), + ) + ], + ); + + } + }, + )); + } +} diff --git a/lib/Kuksa-server/intial_connection.dart b/lib/Kuksa-server/intial_connection.dart new file mode 100644 index 0000000..dfac031 --- /dev/null +++ b/lib/Kuksa-server/intial_connection.dart @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: Apache-2.0 +import 'dart:io'; +import 'package:dashboard_app/Kuksa-server/vehicle_config.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'onBoarding_page.dart'; + +class InitialScreen extends ConsumerWidget { + InitialScreen({Key? key, required this.client}) : super(key: key); + final HttpClient client; + late WebSocket socket; + + @override + Widget build(BuildContext context, ref) { + final sockConnect = ref.watch(sockConnectprovider(client)); + + return sockConnect.when( + data: (socket) { + this.socket = socket; + this.socket.pingInterval = const Duration(seconds: 2); + return OnBoardingPage(client: client, socket: this.socket); + }, + error: (e, stk) { + print(e); + ref.refresh(sockConnectprovider(client)); + return const Scaffold( + backgroundColor: Colors.black, + body: Center(child: Text('error',style: TextStyle(color: Colors.white),)), + ); + }, + loading: () => const Scaffold( + backgroundColor: Colors.black, + body: Center(child: Text('loading',style: TextStyle(color: Colors.white))), + ), + ); + } +}
\ No newline at end of file diff --git a/lib/Kuksa-server/onBoarding_page.dart b/lib/Kuksa-server/onBoarding_page.dart new file mode 100644 index 0000000..264c7a0 --- /dev/null +++ b/lib/Kuksa-server/onBoarding_page.dart @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: Apache-2.0 +import 'dart:async'; +import 'dart:io'; + +import 'package:dashboard_app/Kuksa-server/vehicle_config.dart'; +import 'package:dashboard_app/Kuksa-server/vehicle_methods.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import '../HomePage.dart'; + +class OnBoardingPage extends ConsumerStatefulWidget { + const OnBoardingPage({Key? key, required this.client, required this.socket}) + : super(key: key); + final WebSocket socket; + final HttpClient client; + + @override + ConsumerState<OnBoardingPage> createState() => _OnBoardingPageState(); +} + +class _OnBoardingPageState extends ConsumerState<OnBoardingPage> { + late Timer _timer; + + + @override + void initState() { + super.initState(); + VISS.init(widget.socket,ref); + _timer = Timer.periodic(const Duration(seconds: 2), (timer) { + + if (widget.socket.readyState == 3) { + ref.refresh(sockConnectprovider(widget.client)); + } + }); + WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + widget.socket.listen( + (data) { + VISS.parseData(ref, data); + + }, + onError: (e, stk) { + print(e.toString()); + ref.refresh(sockConnectprovider(widget.client)); + }, + ); + }); + } + + @override + void dispose() { + super.dispose(); + _timer.cancel(); + widget.socket.close(786887, "Connection lost with server!"); + } + + @override + Widget build(BuildContext context) { + return const HomePage(); + } +}
\ No newline at end of file diff --git a/lib/Kuksa-server/vehicle_class.dart b/lib/Kuksa-server/vehicle_class.dart new file mode 100644 index 0000000..c2f2ac2 --- /dev/null +++ b/lib/Kuksa-server/vehicle_class.dart @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: Apache-2.0 +class VehicleSignal { + VehicleSignal({ + required this.speed, + required this.rpm, + required this.fuelLevel, + required this.frontLeftTP, + required this.frontRightTP, + required this.rearLeftTP, + required this.rearRightTP, + required this.isBatteryCharging, + required this.isChildLockActiveLeft, + required this.isChildLockActiveRight, + required this.currentLatitude, + required this.currentLongitude, + required this.fuelRate, + required this.insideTemperature, + required this.outsideTemperature, + }); + + final double speed; + final double rpm; + final double fuelLevel; + final double frontLeftTP; + final double frontRightTP; + final double rearLeftTP; + final double rearRightTP; + final bool isChildLockActiveLeft; + final bool isChildLockActiveRight; + final double currentLongitude; + final double currentLatitude; + final double fuelRate; + final int insideTemperature; + final int outsideTemperature; + + final bool isBatteryCharging; + + VehicleSignal copyWith({ + double? speed, + double? rpm, + double? fuelLevel, + double? frontLeftTP, + double? frontRightTP, + double? rearLeftTP, + double? rearRightTP, + bool? isBatteryCharging, + bool? isChildLockActiveLeft, + bool? isChildLockActiveRight, + double? currentLongitude, + double? currentLatitude, + double? fuelRate, + int? insideTemperature, + int? outsideTemperature, + }) { + return VehicleSignal( + speed: speed ?? this.speed, + rpm: rpm ?? this.rpm, + fuelLevel: fuelLevel ?? this.fuelLevel, + frontLeftTP: frontLeftTP ?? this.frontLeftTP, + frontRightTP: frontRightTP ?? this.frontRightTP, + rearLeftTP: rearLeftTP ?? this.rearLeftTP, + rearRightTP: rearRightTP ?? this.rearRightTP, + isChildLockActiveLeft: + isChildLockActiveLeft ?? this.isChildLockActiveLeft, + isChildLockActiveRight: + isChildLockActiveRight ?? this.isChildLockActiveRight, + isBatteryCharging: isBatteryCharging ?? this.isBatteryCharging, + currentLatitude: currentLatitude ?? this.currentLatitude, + currentLongitude: currentLongitude ?? this.currentLongitude, + fuelRate: fuelRate ?? this.fuelRate, + insideTemperature: insideTemperature ?? this.insideTemperature, + outsideTemperature: outsideTemperature ?? this.outsideTemperature, + ); + } +} diff --git a/lib/Kuksa-server/vehicle_config.dart b/lib/Kuksa-server/vehicle_config.dart new file mode 100644 index 0000000..59682c4 --- /dev/null +++ b/lib/Kuksa-server/vehicle_config.dart @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: Apache-2.0 +import 'dart:convert'; +import 'dart:io'; + +import 'package:dashboard_app/config.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:http/http.dart' as http; + + + +final sockConnectprovider = FutureProvider.family<WebSocket, HttpClient>( + (ref, client) => connect(client,ref)); + + + +Future<HttpClient> initializeClient() async { + + + SecurityContext ctx = SecurityContext.defaultContext; + + HttpClient client = HttpClient(context: ctx) + ..findProxy = null + ..badCertificateCallback = (cert, host, port) { + return true; + }; + return client; +} + + + +Future<WebSocket> connect(HttpClient client, ref) async { + final config = ref.read(ConfigStateprovider); + WebSocket socket = await WebSocket.connect( + "wss://${config.hostname}:${config.port}", + customClient: client); + return socket; +} + + diff --git a/lib/Kuksa-server/vehicle_methods.dart b/lib/Kuksa-server/vehicle_methods.dart new file mode 100644 index 0000000..500f694 --- /dev/null +++ b/lib/Kuksa-server/vehicle_methods.dart @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: Apache-2.0 +import 'dart:convert'; +import 'dart:io'; + +import 'package:dashboard_app/Kuksa-server/vehicle_provider.dart'; +import 'package:dashboard_app/Kuksa-server/vehicle_server_path.dart'; +import 'package:dashboard_app/config.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class VISS { + static const requestId = "test-id"; + static void init(WebSocket socket, WidgetRef ref) { + authorize(socket,ref); + subscribe(socket,ref, VSPath.vehicleSpeed); + subscribe(socket,ref, VSPath.vehicleEngineRPM); + subscribe(socket,ref, VSPath.vehicleFuelLevel); + subscribe(socket,ref, VSPath.vehicleFrontLeftTier); + subscribe(socket, ref,VSPath.vehicleFrontRightTier); + subscribe(socket, ref,VSPath.vehicleRearLeftTier); + subscribe(socket,ref, VSPath.vehicleRearRightTier); + subscribe(socket, ref,VSPath.vehicleIsChildLockActiveLeft); + subscribe(socket,ref, VSPath.vehicleIsChildLockActiveRight); + subscribe(socket,ref, VSPath.vehicleCurrentLatitude); + subscribe(socket,ref, VSPath.vehicleCurrentLongitude); + subscribe(socket,ref, VSPath.vehicleFuelRate); + subscribe(socket,ref, VSPath.vehicleInsideTemperature); + subscribe(socket, ref,VSPath.vehicleAmbientAirTemperature); + } + + static void update(WebSocket socket, WidgetRef ref) { + get(socket,ref, VSPath.vehicleSpeed); + get(socket,ref, VSPath.vehicleEngineRPM); + get(socket,ref, VSPath.vehicleFuelLevel); + get(socket,ref,VSPath.vehicleAmbientAirTemperature); + get(socket,ref,VSPath.vehicleFrontLeftTier); + get(socket,ref, VSPath.vehicleFrontRightTier); + get(socket,ref, VSPath.vehicleRearLeftTier); + get(socket,ref, VSPath.vehicleRearRightTier); + get(socket,ref,VSPath.vehicleIsChildLockActiveLeft); + get(socket,ref, VSPath.vehicleIsChildLockActiveRight); + get(socket,ref,VSPath.vehicleCurrentLatitude); + get(socket,ref,VSPath.vehicleCurrentLongitude); + get(socket,ref,VSPath.vehicleFuelRate); + get(socket,ref, VSPath.vehicleInsideTemperature); + } + + static void authorize(WebSocket socket,WidgetRef ref) { + final config = ref.read(ConfigStateprovider); + + Map<String, dynamic> map = { + "action": "authorize", + "tokens": config.kuksaAuthToken, + "requestId": requestId + }; + socket.add(jsonEncode(map)); + } + + static void get(WebSocket socket,WidgetRef ref, String path) { + final config = ref.read(ConfigStateprovider); + + Map<String, dynamic> map = { + "action": "get", + "tokens": config.kuksaAuthToken, + "path": path, + "requestId": requestId + }; + socket.add(jsonEncode(map)); + } + + static void set(WebSocket socket, WidgetRef ref,String path, String value) { + final config = ref.read(ConfigStateprovider); + Map<String, dynamic> map = { + "action": "set", + "tokens": config.kuksaAuthToken, + "path": path, + "requestId": requestId, + "value": value + }; + socket.add(jsonEncode(map)); + } + + static void subscribe(WebSocket socket,WidgetRef ref, String path) { + final config = ref.read(ConfigStateprovider); + + Map<String, dynamic> map = { + "action": "subscribe", + "tokens": config.kuksaAuthToken, + "path": path, + "requestId": requestId + }; + socket.add(jsonEncode(map)); + } + + static String? numToGear(int? number) { + switch (number) { + case -1: + return 'R'; + case 0: + return 'N'; + case 126: + return 'P'; + case 127: + return 'D'; + default: + return null; + } + } + + static void parseData(WidgetRef ref, String data) { + final vehicleSignal = ref.read(vehicleSignalProvider.notifier); + Map<String, dynamic> dataMap = jsonDecode(data); + if (dataMap["action"] == "subscription" || dataMap["action"] == "get") { + if (dataMap.containsKey("data")) { + if ((dataMap["data"] as Map<String, dynamic>).containsKey("dp") && + (dataMap["data"] as Map<String, dynamic>).containsKey("path")) { + String path = dataMap["data"]["path"]; + Map<String, dynamic> dp = dataMap["data"]["dp"]; + if (dp.containsKey("value")) { + if (dp["value"] != "---") { + switch (path) { + case VSPath.vehicleSpeed: + vehicleSignal.update(speed: double.parse(dp["value"])); + break; + case VSPath.vehicleEngineRPM: + vehicleSignal.update(rpm: double.parse(dp["value"])); + break; + case VSPath.vehicleFuelLevel: + vehicleSignal.update(fuelLevel: double.parse(dp["value"])); + break; + case VSPath.vehicleFrontLeftTier: + vehicleSignal.update(frontLeftTP: double.parse(dp["value"])); + break; + case VSPath.vehicleFrontRightTier: + vehicleSignal.update(frontRightTP: double.parse(dp["value"])); + break; + case VSPath.vehicleRearLeftTier: + vehicleSignal.update(rearLeftTP: double.parse(dp["value"])); + break; + case VSPath.vehicleRearRightTier: + vehicleSignal.update(rearRightTP: double.parse(dp["value"])); + break; + + + case VSPath.vehicleIsChildLockActiveLeft: + vehicleSignal.update(isChildLockActiveLeft: dp['value']); + break; + case VSPath.vehicleIsChildLockActiveRight: + vehicleSignal.update(isChildLockActiveRight: dp['value']); + break; + case VSPath.vehicleCurrentLatitude: + vehicleSignal.update( + currentLatitude: double.parse(dp["value"])); + break; + case VSPath.vehicleCurrentLongitude: + vehicleSignal.update( + currentLongitude: double.parse(dp["value"])); + break; + case VSPath.vehicleFuelRate: + vehicleSignal.update(fuelRate: double.parse(dp["value"])); + break; + case VSPath.vehicleInsideTemperature: + vehicleSignal.update( + insideTemperature: int.parse(dp["value"])); + break; + case VSPath.vehicleAmbientAirTemperature: + vehicleSignal.update( + outsideTemperature: int.parse(dp["value"])); + break; + default: + print("$path Not Available yet!"); + } + } else { + print("ERROR:Value not available yet! Set Value of $path"); + } + } else { + print("ERROR:'value': Key not found!"); + } + } else if ((!dataMap["data"] as Map<String, dynamic>) + .containsKey("path")) { + print("ERROR:'path':key not found !"); + } else if ((dataMap["data"] as Map<String, dynamic>) + .containsKey("dp")) { + print("ERROR:'dp':key not found !"); + } + } else { + print("ERROR:'data':key not found!"); + } + } + } +} diff --git a/lib/Kuksa-server/vehicle_provider.dart b/lib/Kuksa-server/vehicle_provider.dart new file mode 100644 index 0000000..e7b67df --- /dev/null +++ b/lib/Kuksa-server/vehicle_provider.dart @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: Apache-2.0 +import 'package:dashboard_app/Kuksa-server/vehicle_class.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +final vehicleSignalProvider = + StateNotifierProvider<VehicleSignalNotifier, VehicleSignal>( + (ref) => VehicleSignalNotifier(), +); + +class VehicleSignalNotifier extends StateNotifier<VehicleSignal> { + VehicleSignalNotifier() : super(_initialValue); + static final VehicleSignal _initialValue = VehicleSignal( + speed: 140, + rpm: 7000, + fuelLevel: 90, + frontRightTP: 32, + frontLeftTP: 32, + rearRightTP: 33, + rearLeftTP: 34, + isChildLockActiveLeft: true, + isChildLockActiveRight: true, + isBatteryCharging: true, + currentLatitude: 37.772701, + currentLongitude: -122.416626, + fuelRate: 21, + insideTemperature: 25, + outsideTemperature: 32, + ); + void update({ + double? speed, + double? rpm, + double? fuelLevel, + double? frontLeftTP, + double? frontRightTP, + double? rearLeftTP, + double? rearRightTP, + bool? isBatteryCharging, + bool? isChildLockActiveLeft, + bool? isChildLockActiveRight, + double? currentLatitude, + double? currentLongitude, + double? fuelRate, + int? insideTemperature, + int? outsideTemperature, + }) { + state = state.copyWith( + speed: speed, + rpm: rpm, + fuelLevel: fuelLevel, + frontLeftTP: frontLeftTP, + frontRightTP: frontRightTP, + rearLeftTP: rearLeftTP, + rearRightTP: rearRightTP, + isChildLockActiveLeft: isChildLockActiveLeft, + isChildLockActiveRight: isChildLockActiveRight, + isBatteryCharging: isBatteryCharging, + currentLatitude: currentLatitude, + currentLongitude: currentLongitude, + fuelRate: fuelRate, + insideTemperature: insideTemperature, + outsideTemperature: outsideTemperature, + ); + } +} diff --git a/lib/Kuksa-server/vehicle_server_path.dart b/lib/Kuksa-server/vehicle_server_path.dart new file mode 100644 index 0000000..9854320 --- /dev/null +++ b/lib/Kuksa-server/vehicle_server_path.dart @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: Apache-2.0 +class VSPath { + static const String vehicleSpeed = "Vehicle.Speed"; + static const String vehicleEngineRPM = + "Vehicle.Powertrain.CombustionEngine.Engine.Speed"; + static const String vehicleFuelLevel = "Vehicle.Powertrain.FuelSystem.Level"; + + + + + static const String vehicleAmbientAirTemperature = + "Vehicle.AmbientAirTemperature"; + + static const String vehicleFrontLeftTier = + "Vehicle.Chassis.Axle.Row1.Wheel.Left.Tire.Pressure"; + static const String vehicleFrontRightTier = + "Vehicle.Chassis.Axle.Row1.Wheel.Right.Tire.Pressure"; + static const String vehicleRearLeftTier = + "Vehicle.Chassis.Axle.Row2.Wheel.Left.Tire.Pressure"; + + static const String vehicleRearRightTier = + "Vehicle.Chassis.Axle.Row2.Wheel.Right.Tire.Pressure"; + static const String vehicleIsChildLockActiveLeft = + "Vehicle.Cabin.Door.Row2.Left.IsChildLockActive"; + static const String vehicleIsChildLockActiveRight = + "Vehicle.Cabin.Door.Row2.Right.IsChildLockActive"; + static const String vehicleCurrentLongitude = + "Vehicle.CurrentLocation.Longitude"; + static const String vehicleCurrentLatitude = + "Vehicle.CurrentLocation.Latitude"; + static const String vehicleFuelRate = "Vehicle.OBD.FuelRate"; + static const String vehicleInsideTemperature = + "Vehicle.Cabin.HVAC.AmbientAirTemperature"; +} diff --git a/lib/Tier_pressure.dart b/lib/Tier_pressure.dart new file mode 100644 index 0000000..cb8ace5 --- /dev/null +++ b/lib/Tier_pressure.dart @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: Apache-2.0 +import 'package:dashboard_app/size.dart'; +import 'package:flutter/material.dart'; +import 'package:percent_indicator/linear_percent_indicator.dart'; + + + +class TierPressure extends StatefulWidget { + String tname; + double tpress; + CrossAxisAlignment crossAxisAlignment; + MainAxisAlignment mainAxisAlignment; + TierPressure( + {Key? key, + required this.tname, + required this.tpress, + required this.crossAxisAlignment, + required this.mainAxisAlignment}) + : super(key: key); + + @override + State<TierPressure> createState() => _TierPressureState(); +} + +class _TierPressureState extends State<TierPressure> { + @override + Widget build(BuildContext context) { + return SizedBox( + height: SizeConfig.safeBlockVertical * 12, + width: SizeConfig.safeBlockHorizontal * 14, + child: Column( + mainAxisAlignment: widget.mainAxisAlignment, + + children: [ + Text( + '${widget.tname}', + style: SizeConfig.smallnormalfont2, + ), + Text( + widget.tpress.toString() + ' PSI', + style: SizeConfig.smallnormalfont, + ), + LinearPercentIndicator( + width: SizeConfig.safeBlockHorizontal * 11, + + progressColor: widget.tpress / 50 > 0.6 ? Colors.green : Colors.red, + lineHeight: SizeConfig.safeBlockVertical * 1.5, + alignment: MainAxisAlignment.center, + animateFromLastPercent: true, + animation: true, + percent: widget.tpress / 50, + + barRadius: Radius.circular(SizeConfig.fontsize / 4), + backgroundColor: Colors.grey, + ), + ], + ), + ); + } +} diff --git a/lib/config.dart b/lib/config.dart new file mode 100644 index 0000000..963f798 --- /dev/null +++ b/lib/config.dart @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: Apache-2.0 +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:yaml/yaml.dart'; + +import 'Kuksa-server/intial_connection.dart'; + +class GetConfig extends ConsumerStatefulWidget { + const GetConfig({Key? key, required this.client}) : super(key: key); + final HttpClient client; + + @override + ConsumerState<GetConfig> createState() => _GetConfigState(); +} + +class _GetConfigState extends ConsumerState<GetConfig> { + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + final configStateProvider = ref.read(ConfigStateprovider.notifier); + + String configFilePath = '/etc/xdg/AGL/dashboard_config.yaml'; + + + + final configFile = File(configFilePath); + configFile.readAsString().then((content) { + final dynamic yamlMap = loadYaml(content); + configStateProvider.update( + hostname: yamlMap['hostname'], + port: yamlMap['port'], + kuksaAuthToken: yamlMap['kuskaAuthToken'], + ); + }); + }); + } + + @override + Widget build(BuildContext context) { + final config = ref.watch(ConfigStateprovider); + if (config.hostname == "" || + config.port == 0 || + config.kuksaAuthToken == "" + ) { + return Scaffold( + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: const [ + Text("ERROR", + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)), + Text( + "Something Wrong with config file! Check config.yaml file and restart"), + ], + )), + ); + } + return InitialScreen(client: widget.client); + } +} + +class Config { + Config({ + required this.hostname, + required this.port, + required this.kuksaAuthToken, + + }); + final String hostname; + final int port; + final String kuksaAuthToken; + + Config copywith({ + String? hostname, + int? port, + String? kuksaAuthToken, + }) => + Config( + hostname: hostname ?? this.hostname, + port: port ?? this.port, + kuksaAuthToken: kuksaAuthToken ?? this.kuksaAuthToken, + ); +} + +final ConfigStateprovider = +StateNotifierProvider<ConfigStateNotifier, Config>( + (ref) => ConfigStateNotifier()); + +class ConfigStateNotifier extends StateNotifier<Config> { + ConfigStateNotifier() : super(_initialValue); + static final Config _initialValue = Config( + hostname: "", + port: 0, + kuksaAuthToken: "", + ); + void update({ + String? hostname, + int? port, + String? kuksaAuthToken, + }) { + state = state.copywith( + hostname: hostname, + port: port, + kuksaAuthToken: kuksaAuthToken, + ); + } +} + diff --git a/lib/drawArrow.dart b/lib/drawArrow.dart new file mode 100644 index 0000000..71b751f --- /dev/null +++ b/lib/drawArrow.dart @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: Apache-2.0 +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class Arrowpaint extends CustomPainter{ + @override + void paint(Canvas canvas, Size size) { + var paint = Paint(); + var path = Path(); + paint.color = Colors.grey; + paint.style = PaintingStyle.stroke; + paint.strokeWidth = 1; + path.moveTo(0, size.height*0.8); + path.lineTo(size.width*0.8, size.height*0.8); + path.lineTo(size.width*0.8, size.height*0.2); + path.moveTo(size.width*0.75, size.height*0.25); + path.lineTo(size.width*0.8, size.height*0.15); + path.lineTo(size.width*0.85, size.height*0.25); + canvas.drawPath(path, paint); + // TODO: implement paint + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) { + // TODO: implement shouldRepaint + // throw UnimplementedError(); + return false; + } + +} +class Arrowpaint2 extends CustomPainter{ + @override + void paint(Canvas canvas, Size size) { + var paint = Paint(); + var path = Path(); + paint.color = Colors.grey; + paint.style = PaintingStyle.stroke; + paint.strokeWidth = 1; + path.moveTo(size.width, size.height*0.8); + path.lineTo(size.width*0.2, size.height*0.8); + path.lineTo(size.width*0.2, size.height*0.2); + path.moveTo(size.width*0.15, size.height*0.25); + path.lineTo(size.width*0.2, size.height*0.15); + path.lineTo(size.width*0.25, size.height*0.25); + canvas.drawPath(path, paint); + // TODO: implement paint + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) { + // TODO: implement shouldRepaint + // throw UnimplementedError(); + return false; + } + +} + +class simplearrow extends CustomPainter{ + @override + void paint(Canvas canvas, Size size) { + var paint = Paint(); + var path = Path(); + paint.color = Colors.grey; + paint.strokeWidth = 1; + paint.style = PaintingStyle.stroke; + path.moveTo(0, size.height*0.5); + path.lineTo(size.width*0.8, size.height*0.5); + path.moveTo(size.width*0.75, size.height*0.40); + path.lineTo(size.width*0.85, size.height*0.5); + path.lineTo(size.width*0.75, size.height*0.60); + canvas.drawPath(path, paint); + // TODO: implement paint + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) { + // TODO: implement shouldRepaint + return false; + } + +}
\ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..27ba557 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: Apache-2.0 + +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'Kuksa-server/intial_connection.dart'; +import 'Kuksa-server/vehicle_config.dart'; +import 'config.dart'; + +Future<void> main() async { + WidgetsFlutterBinding.ensureInitialized(); + HttpClient client = await initializeClient(); + + + runApp( + + ProviderScope( + child: MaterialApp( + debugShowCheckedModeBanner: false, + home: GetConfig(client: client), + ), + ), + ); +} + + diff --git a/lib/provider.dart b/lib/provider.dart new file mode 100644 index 0000000..4c9ed0a --- /dev/null +++ b/lib/provider.dart @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: Apache-2.0 + +import 'dart:async'; +import 'dart:math'; + +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +final fuelProvider = StateNotifierProvider<fuel,double>((ref) => + fuel(), +); + +class fuel extends StateNotifier<double>{ + late Timer timer; + fuel() : super(0.2){ + + Timer.periodic(Duration(seconds: 5), (timer) { + double num = Random().nextInt(100).toDouble(); + update(num); + }); + } + void update(value){ + state = value; + } +} + +final DateTimeProvider = StateNotifierProvider<datetime,DateTime>((ref) => + datetime(), +); + +class datetime extends StateNotifier<DateTime>{ + datetime() : super(DateTime.now()){ + + Timer.periodic(Duration(seconds: 30), (timer) { + DateTime _now = DateTime.now(); + update(_now); + }); + } + void update(value){ + state = value; + } +} diff --git a/lib/size.dart b/lib/size.dart new file mode 100644 index 0000000..2bcbcd9 --- /dev/null +++ b/lib/size.dart @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: Apache-2.0 +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +class SizeConfig { + static late MediaQueryData _mediaQueryData; + static late double screenWidth; + static late double screenHeight; + static late double blockSizeHorizontal; + static late double blockSizeVertical; + static late double _safeAreaHorizontal; + static late double _safeAreaVertical; + static late double safeBlockHorizontal; + static late double safeBlockVertical; + static late double fontsize; + static late TextStyle normalfont; + static late TextStyle smallnormalfont; + static late TextStyle smallnormalfont2; + + void init(BuildContext context) { + _mediaQueryData = MediaQuery.of(context); + screenWidth = _mediaQueryData.size.width; + screenHeight = _mediaQueryData.size.height; + blockSizeHorizontal = screenWidth / 100; + blockSizeVertical = screenHeight / 100; + _safeAreaHorizontal = + _mediaQueryData.padding.left + _mediaQueryData.padding.right; + _safeAreaVertical = + _mediaQueryData.padding.top + _mediaQueryData.padding.bottom; + safeBlockHorizontal = (screenWidth - _safeAreaHorizontal) / 100; + safeBlockVertical = (screenHeight - _safeAreaVertical) / 100; + fontsize = screenHeight * screenWidth * 0.01 * 0.01 * 0.3; + normalfont = TextStyle( + fontSize: fontsize * 0.8, + fontWeight: FontWeight.w700, + color: Colors.white, + ); + smallnormalfont = TextStyle( + fontSize: fontsize / 2, + fontWeight: FontWeight.w700, + color: Colors.white, + ); + smallnormalfont2 = TextStyle( + fontSize: fontsize * 0.4, + color: Colors.white, + ); + } +} diff --git a/lib/widgets/child_lock.dart b/lib/widgets/child_lock.dart new file mode 100644 index 0000000..c2efb0d --- /dev/null +++ b/lib/widgets/child_lock.dart @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: Apache-2.0 +import 'package:dashboard_app/size.dart'; +import 'package:flutter/src/foundation/key.dart'; +import 'package:flutter/src/widgets/framework.dart'; +import 'package:flutter/material.dart'; + +class ChildLockStatus extends StatelessWidget { + bool isChildLockActiveLeft; + bool isChildLockActiveRight; + ChildLockStatus( + {Key? key, + required this.isChildLockActiveLeft, + required this.isChildLockActiveRight}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return isChildLockActiveLeft && isChildLockActiveRight + ? Column( + children: [ + Text( + "Child Lock", + style: TextStyle( + fontSize: SizeConfig.fontsize / 3, color: Colors.green), + ), + Text( + "Activated", + style: TextStyle( + fontSize: SizeConfig.fontsize / 3, color: Colors.green), + ), + SizedBox( + width: SizeConfig.safeBlockVertical / 2, + ), + Icon( + Icons.lock, + size: SizeConfig.fontsize / 3, + color: Colors.green, + ), + ], + ) + : Column( + children: [ + Text( + 'No child Lock', + style: TextStyle( + fontSize: SizeConfig.fontsize / 2, + color: Colors.redAccent, + ), + ), + SizedBox( + height: SizeConfig.safeBlockVertical / 2, + ), + Icon( + Icons.lock_open_outlined, + size: SizeConfig.fontsize / 4, + color: Colors.red, + ), + ], + ); + } +} diff --git a/lib/widgets/fuel_and_speed.dart b/lib/widgets/fuel_and_speed.dart new file mode 100644 index 0000000..2ee902e --- /dev/null +++ b/lib/widgets/fuel_and_speed.dart @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: Apache-2.0 +import 'package:dashboard_app/size.dart'; +import 'package:flutter/src/foundation/key.dart'; +import 'package:flutter/src/widgets/framework.dart'; +import 'package:flutter/material.dart'; +import 'package:percent_indicator/circular_percent_indicator.dart'; +import 'package:percent_indicator/linear_percent_indicator.dart'; + + + +class SpeedAndFuel extends StatelessWidget { + double fuel; + double speed; + SpeedAndFuel({Key? key, required this.fuel, required this.speed}) + : super(key: key); + + @override + Widget build(BuildContext context) { + double width = MediaQuery.of(context).size.width; + return SizedBox( + width: width * 0.4, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + CircularPercentIndicator( + radius: SizeConfig.fontsize * 1.6, + percent: fuel / 100, + lineWidth: SizeConfig.fontsize / 2, + + backgroundColor: Colors.lightBlue.shade100, + progressColor: fuel < 25 + ? Colors.redAccent + : fuel < 50 + ? Colors.orange + : Colors.green, + animation: true, + circularStrokeCap: CircularStrokeCap.round, + animateFromLastPercent: true, + center: Text( + fuel.toString() + ' %', + style: SizeConfig.smallnormalfont, + ), + footer: Text( + 'fuel', + style: SizeConfig.smallnormalfont2, + ), + ), + CircularPercentIndicator( + radius: SizeConfig.fontsize * 1.6, + percent: speed / 300, + lineWidth: SizeConfig.fontsize / 2, + backgroundColor: Color.fromARGB(255, 176, 213, 195), + progressColor: Colors.lightBlueAccent, + animation: true, + circularStrokeCap: CircularStrokeCap.round, + animateFromLastPercent: true, + center: Text( + speed.toString(), + style: SizeConfig.smallnormalfont, + ), + footer: Text( + 'Speed in KM/H', + style: SizeConfig.smallnormalfont2, + ), + ), + ], + ), + ); + } +} + +class Rpm extends StatelessWidget { + double rpm; + Rpm({Key? key, required this.rpm}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SizedBox( + height: SizeConfig.safeBlockVertical * 9, + width: SizeConfig.safeBlockHorizontal * 35, + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text( + "Engine Status", + style: SizeConfig.smallnormalfont2, + ), + LinearPercentIndicator( + backgroundColor: Colors.white70, + addAutomaticKeepAlive: true, + progressColor: Colors.lightBlueAccent, + animateFromLastPercent: true, + animation: true, + animationDuration: 500, + percent: rpm / 8000, + barRadius: Radius.circular(15), + leading: Text( + 'RPM', + style: SizeConfig.smallnormalfont, + ), + trailing: Text( + rpm.toString(), + style: SizeConfig.smallnormalfont2, + ), + ), + ], + ), + ); + } +} diff --git a/lib/widgets/weather.dart b/lib/widgets/weather.dart new file mode 100644 index 0000000..fe31c72 --- /dev/null +++ b/lib/widgets/weather.dart @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: Apache-2.0 +import 'package:dashboard_app/size.dart'; +import 'package:flutter/src/foundation/key.dart'; +import 'package:flutter/src/widgets/framework.dart'; + +import 'package:flutter/material.dart'; + +class weather extends StatelessWidget { + int insideTemperatue; + int outsideTempearure; + weather( + {Key? key, + required this.insideTemperatue, + required this.outsideTempearure}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(SizeConfig.safeBlockVertical * 2), + ), + height: SizeConfig.safeBlockVertical * 20, + width: SizeConfig.blockSizeHorizontal * 20, + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Flexible( + flex: 1, + child: Text( + 'Weather', + style: SizeConfig.smallnormalfont, + textAlign: TextAlign.left, + )), + Flexible( + flex: 3, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + height: SizeConfig.safeBlockVertical * 5, + width: SizeConfig.blockSizeHorizontal * 5, + child: Image.asset( + 'images/thermostate.png', + color: Colors.orangeAccent, + )), + SizedBox( + height: SizeConfig.safeBlockVertical, + ), + Row( + children: [ + Column( + children: [ + Text(insideTemperatue.toString() + ' \u00B0', + style: SizeConfig.normalfont), + Text('Inside', style: SizeConfig.smallnormalfont2), + ], + ), + SizedBox( + width: SizeConfig.safeBlockHorizontal, + ), + Column( + children: [ + Text( + outsideTempearure.toString() + ' \u00B0', + style: SizeConfig.normalfont, + ), + Text( + 'Outside', + style: SizeConfig.smallnormalfont2, + ), + ], + ) + ], + ), + ], + ), + ), + ], + ), + ); + } +} |