diff options
-rw-r--r-- | lib/homescreen.dart | 3 | ||||
-rw-r--r-- | lib/layout_size_helper.dart | 53 | ||||
-rw-r--r-- | lib/page_dashboard.dart | 137 | ||||
-rw-r--r-- | lib/page_home.dart | 34 | ||||
-rw-r--r-- | lib/page_hvac.dart | 168 | ||||
-rw-r--r-- | lib/page_media.dart | 85 |
6 files changed, 285 insertions, 195 deletions
diff --git a/lib/homescreen.dart b/lib/homescreen.dart index efc622e..29702aa 100644 --- a/lib/homescreen.dart +++ b/lib/homescreen.dart @@ -1,5 +1,3 @@ -import 'dart:math'; - import 'package:flutter/material.dart'; import 'package:flutter_homescreen/page_dashboard.dart'; import 'package:flutter_homescreen/page_home.dart'; @@ -59,6 +57,7 @@ class _HomescreenState extends State<Homescreen> with TickerProviderStateMixin { } Widget _buildLayout(BuildContext context, BoxConstraints constraints) { + // size the icons so they cover the left edge of the screen var iconSize = constraints.maxHeight / (PageIndex.values.length + 2); var railSize = constraints.maxHeight / (PageIndex.values.length + 1); diff --git a/lib/layout_size_helper.dart b/lib/layout_size_helper.dart new file mode 100644 index 0000000..9cbb0d7 --- /dev/null +++ b/lib/layout_size_helper.dart @@ -0,0 +1,53 @@ +import 'package:flutter/material.dart'; + +class LayoutSizeHelper { + Size _size; + double _ratio; + + LayoutSizeHelper(context) + : _size = MediaQuery.of(context).size, + _ratio = MediaQuery.of(context).devicePixelRatio; + + update(context) { + _size = MediaQuery.of(context).size; + _ratio = MediaQuery.of(context).devicePixelRatio; + } + + get defaultIconSize { + if (_size.height <= 480 || _size.width <= 600) { + return 64.0 * _ratio; + } else if (_size.height <= 900 || _size.width <= 840) { + return 96.0 * _ratio; + } else { + return 128.0 * _ratio; + } + } + + get defaultButtonHeight { + return defaultIconSize; + } + + get defaultButtonWidth { + return defaultButtonHeight * 3.0; + } + + get defaultPadding { + return defaultIconSize / 8.0; + } + + get defaultBorder { + return defaultIconSize / 16; + } + + get baseFontSize { + return (defaultIconSize / 3.0).floor().toDouble(); + } + + get largeIconSize { + return 1.5 * defaultIconSize; + } + + get largePadding { + return largeIconSize / 4.0; + } +} diff --git a/lib/page_dashboard.dart b/lib/page_dashboard.dart index 2ab1d38..172a38a 100644 --- a/lib/page_dashboard.dart +++ b/lib/page_dashboard.dart @@ -1,57 +1,68 @@ import 'package:flutter/material.dart'; +import 'package:flutter_homescreen/layout_size_helper.dart'; class DashboardPage extends StatelessWidget { const DashboardPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { - var screenHeight = MediaQuery.of(context).size.height; - var iconSize = screenHeight / 8; - + var sizeHelper = LayoutSizeHelper(context); return Container( color: Colors.indigo.shade50, constraints: BoxConstraints.expand(), alignment: Alignment.center, child: Column( - mainAxisAlignment: MainAxisAlignment.spaceAround, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Text( '0 kpm', - style: Theme.of(context).textTheme.headline4, + style: Theme.of(context).textTheme.headline2, ), Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ - Column( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - Text( - 'Left front tire', - style: Theme.of(context).textTheme.headline4, - ), - Text( - 'Left rear tire', - style: Theme.of(context).textTheme.headline4, - ), - ], + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text( + 'Left front tire', + style: Theme.of(context).textTheme.headline4, + ), + SizedBox( + height: sizeHelper.largeIconSize, + ), + Text( + 'Left rear tire', + style: Theme.of(context).textTheme.headline4, + ), + ], + ), ), - Icon( - Icons.drive_eta, - size: iconSize, - color: Colors.indigo.shade800, + Image.asset( + 'images/HMI_Dashboard_Car_720.png', + width: sizeHelper.largeIconSize, + fit: BoxFit.contain, ), - Column( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - Text( - 'Right front tire', - style: Theme.of(context).textTheme.headline4, - ), - Text( - 'Right rear tire', - style: Theme.of(context).textTheme.headline4, - ), - ], + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Right front tire', + style: Theme.of(context).textTheme.headline4, + ), + SizedBox( + height: sizeHelper.largeIconSize, + ), + Text( + 'Right rear tire', + style: Theme.of(context).textTheme.headline4, + ), + ], + ), ), ], ), @@ -59,10 +70,7 @@ class DashboardPage extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ _RPMWidget(), - Text( - 'Fuel', - style: Theme.of(context).textTheme.headline4, - ), + _FuelWidget(), ], ) ], @@ -71,22 +79,59 @@ class DashboardPage extends StatelessWidget { } } -// ignore: unused_element class _RPMWidget extends StatelessWidget { @override Widget build(BuildContext context) { - return Row( - mainAxisAlignment: MainAxisAlignment.start, + var sizeHelper = LayoutSizeHelper(context); + return Stack( + alignment: Alignment.center, children: [ - Icon(Icons.fastfood), + Text( + 'RPM', + style: Theme.of(context).textTheme.headline4, + ), Container( - height: 20, - width: 70, - child: LinearProgressIndicator( - value: 0.75, - semanticsLabel: 'Linear progress indicator', + height: sizeHelper.largeIconSize, + width: sizeHelper.largeIconSize, + margin: EdgeInsets.all(sizeHelper.largePadding), + child: RotatedBox( + quarterTurns: 2, + child: CircularProgressIndicator( + value: 0.75, + strokeWidth: sizeHelper.largeIconSize / 4.0, + semanticsLabel: 'RPM indicator', + ), ), + ) + ], + ); + } +} + +class _FuelWidget extends StatelessWidget { + @override + Widget build(BuildContext context) { + var sizeHelper = LayoutSizeHelper(context); + return Stack( + alignment: Alignment.center, + children: [ + Text( + 'Fuel', + style: Theme.of(context).textTheme.headline4, ), + Container( + height: sizeHelper.largeIconSize, + width: sizeHelper.largeIconSize, + margin: EdgeInsets.all(sizeHelper.largePadding), + child: RotatedBox( + quarterTurns: 2, + child: CircularProgressIndicator( + value: 0.75, + strokeWidth: sizeHelper.largeIconSize / 4.0, + semanticsLabel: 'RPM indicator', + ), + ), + ) ], ); } diff --git a/lib/page_home.dart b/lib/page_home.dart index 1fbda1f..7b4bc79 100644 --- a/lib/page_home.dart +++ b/lib/page_home.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_homescreen/layout_size_helper.dart'; class HomePage extends StatelessWidget { final Function(int index) onSetNavigationIndex; @@ -8,35 +9,34 @@ class HomePage extends StatelessWidget { @override Widget build(BuildContext context) { - final double spacing = MediaQuery.of(context).size.width / 32; - final double runSpacing = spacing / 2; + var themeHelper = LayoutSizeHelper(context); return Container( color: Colors.lightBlue.shade50, constraints: BoxConstraints.expand(), alignment: Alignment.center, child: Wrap( - spacing: spacing, - runSpacing: runSpacing, - children: <Widget>[ - createItem(context, Icons.drive_eta, 1), - createItem(context, Icons.thermostat, 2), - createItem(context, Icons.music_note, 3) - ], - )); + spacing: themeHelper.largePadding, + runSpacing: themeHelper.largePadding, + children: <Widget>[ + createItem(themeHelper, Icons.drive_eta, 1), + createItem(themeHelper, Icons.thermostat, 2), + createItem(themeHelper, Icons.music_note, 3) + ], + )); } - Widget createItem(BuildContext context, IconData icon, int tabPosition) { - final double size = MediaQuery.of(context).size.width / 6; - final double padding = size / 4; - final double border = padding / 4; + Widget createItem( + LayoutSizeHelper themeHelper, IconData icon, int tabPosition) { return Padding( padding: const EdgeInsets.symmetric(vertical: 8.0), child: OutlinedButton( style: OutlinedButton.styleFrom( shape: CircleBorder(), - padding: EdgeInsets.all(padding), + padding: EdgeInsets.all(themeHelper.largePadding), primary: Colors.lightBlue.shade400, - side: BorderSide(width: border, color: Colors.lightBlue.shade400) + side: BorderSide( + width: themeHelper.defaultBorder, + color: Colors.lightBlue.shade400), ), onPressed: () { onSetNavigationIndex(tabPosition); @@ -44,7 +44,7 @@ class HomePage extends StatelessWidget { child: Icon( icon, color: Colors.lightBlue.shade800, - size: size / 2, + size: themeHelper.largeIconSize, ), ), ); diff --git a/lib/page_hvac.dart b/lib/page_hvac.dart index ea6dd3b..d416a1b 100644 --- a/lib/page_hvac.dart +++ b/lib/page_hvac.dart @@ -1,6 +1,5 @@ -import 'dart:math'; - import 'package:flutter/material.dart'; +import 'package:flutter_homescreen/layout_size_helper.dart'; import 'package:numberpicker/numberpicker.dart'; class HVACPageContainer extends StatelessWidget { @@ -16,9 +15,7 @@ class HVACPageContainer extends StatelessWidget { } class _TemperatureSelector extends StatefulWidget { -final double referenceFontSize = 24; - - _TemperatureSelector({Key? key, referenceFontSize}) : super(key: key); + _TemperatureSelector({Key? key}) : super(key: key); @override _TemperatureSelectorState createState() => _TemperatureSelectorState(); @@ -29,6 +26,7 @@ class _TemperatureSelectorState extends State<_TemperatureSelector> { @override Widget build(BuildContext context) { + var sizeHelper = LayoutSizeHelper(context); return Column( children: <Widget>[ NumberPicker( @@ -38,14 +36,14 @@ class _TemperatureSelectorState extends State<_TemperatureSelector> { onChanged: (value) => setState(() => _currentValue = value), textStyle: DefaultTextStyle.of(context).style.copyWith( color: Colors.teal.shade200, - fontSize: widget.referenceFontSize, + fontSize: sizeHelper.baseFontSize, ), selectedTextStyle: DefaultTextStyle.of(context).style.copyWith( color: Colors.white, - fontSize: widget.referenceFontSize * 1.5, + fontSize: sizeHelper.baseFontSize * 1.5, ), - itemHeight: widget.referenceFontSize * 3, - itemWidth: widget.referenceFontSize * 6, + itemHeight: sizeHelper.baseFontSize * 3, + itemWidth: sizeHelper.baseFontSize * 6, ), ], ); @@ -72,16 +70,16 @@ class _HVACFanSpeedState extends State<HVACFanSpeed> { inactiveTrackColor: Colors.blueGrey.shade200, ), child: Slider( - value: _currentSliderValue, - min: 0, - max: 300, - label: _currentSliderValue.round().toString(), - onChanged: (double value) { - setState(() { - _currentSliderValue = value; - }); - }, - ), + value: _currentSliderValue, + min: 0, + max: 300, + label: _currentSliderValue.round().toString(), + onChanged: (double value) { + setState(() { + _currentSliderValue = value; + }); + }, + ), ); } } @@ -102,82 +100,75 @@ bool selected = true; // Get from API class _HVACPageState extends State<HVACPage> { final double fanSpeed = 20; - Widget _buildLayout(BuildContext context, BoxConstraints constraints) { - // describe the layout in terms of fractions of the container size - double mainDimension = max(constraints.maxWidth, constraints.maxHeight); - double minDimension = min(constraints.maxWidth, constraints.maxHeight); - double iconSize = mainDimension / 12.0; - double largeIconSize = mainDimension / 8.0; - double spacingSize = minDimension / 48.0; - double buttonWidth = constraints.maxWidth / 6.0; - double buttonHeight = constraints.maxHeight / 6.0; - double defaultFontSize = constraints.maxHeight / 24.0; + @override + Widget build(BuildContext context) { + var sizeHelper = LayoutSizeHelper(context); TextStyle buttonTextStyle = DefaultTextStyle.of(context).style.copyWith( color: Colors.white, - fontSize: defaultFontSize, + fontSize: sizeHelper.baseFontSize, ); Widget fanSpeedControl = Container( padding: EdgeInsets.symmetric( - vertical: spacingSize, - horizontal: 3 * spacingSize, + vertical: sizeHelper.defaultPadding, + horizontal: 3.0 * sizeHelper.defaultPadding, ), child: Row( children: [ Expanded(flex: 4, child: const HVACFanSpeed()), - SizedBox(width: spacingSize), + SizedBox(width: sizeHelper.defaultPadding), Expanded( flex: 1, child: Image.asset('images/HMI_HVAC_Fan_Icon.png', - width: iconSize, height: iconSize, fit: BoxFit.contain)), + width: sizeHelper.defaultIconSize, + height: sizeHelper.defaultIconSize, + fit: BoxFit.contain)), ], ), ); Widget rightSeat = Container( - padding: EdgeInsets.all(spacingSize), + padding: EdgeInsets.all(sizeHelper.defaultPadding), child: Column( children: [ IconButton( - iconSize: largeIconSize, + iconSize: sizeHelper.largeIconSize, icon: Image.asset(selected ? chairOn : chairOff, - width: largeIconSize, - height: largeIconSize, + width: sizeHelper.largeIconSize, + height: sizeHelper.largeIconSize, fit: BoxFit.contain), onPressed: () { selected = !selected; }, ), - SizedBox(height: spacingSize), - _TemperatureSelector( - referenceFontSize: defaultFontSize, - ), + SizedBox(height: sizeHelper.defaultPadding), + _TemperatureSelector(), ], ), ); Widget leftSeat = Container( - padding: EdgeInsets.all(spacingSize), + padding: EdgeInsets.all(sizeHelper.defaultPadding), child: Column( children: [ Image.asset('images/HMI_HVAC_Right_Chair_ON.png', - width: largeIconSize, height: largeIconSize, fit: BoxFit.contain), - SizedBox(height: spacingSize), - _TemperatureSelector( - referenceFontSize: defaultFontSize, - ), + width: sizeHelper.largeIconSize, + height: sizeHelper.largeIconSize, + fit: BoxFit.contain), + SizedBox(height: sizeHelper.defaultPadding), + _TemperatureSelector(), ], ), ); Widget centerView = Container( - padding: EdgeInsets.all(spacingSize), + padding: EdgeInsets.all(sizeHelper.defaultPadding), child: Column( children: [ Container( - width: buttonWidth, - height: buttonHeight, - margin: EdgeInsets.all(spacingSize), + width: sizeHelper.defaultButtonWidth, + height: sizeHelper.defaultButtonHeight, + margin: EdgeInsets.all(sizeHelper.defaultPadding), decoration: BoxDecoration( border: Border.all(color: Colors.green), borderRadius: BorderRadius.circular(20)), @@ -189,9 +180,9 @@ class _HVACPageState extends State<HVACPage> { ), ), Container( - width: buttonWidth, - height: buttonHeight, - margin: EdgeInsets.all(spacingSize), + width: sizeHelper.defaultButtonWidth, + height: sizeHelper.defaultButtonHeight, + margin: EdgeInsets.all(sizeHelper.defaultPadding), decoration: BoxDecoration( border: Border.all(color: Colors.green), borderRadius: BorderRadius.circular(20)), @@ -203,9 +194,9 @@ class _HVACPageState extends State<HVACPage> { ), ), Container( - width: buttonWidth, - height: buttonHeight, - margin: EdgeInsets.all(spacingSize), + width: sizeHelper.defaultButtonWidth, + height: sizeHelper.defaultButtonHeight, + margin: EdgeInsets.all(sizeHelper.defaultPadding), decoration: BoxDecoration( border: Border.all(color: Colors.green), borderRadius: BorderRadius.circular(20)), @@ -214,56 +205,57 @@ class _HVACPageState extends State<HVACPage> { // Respond to button press }, child: Image.asset('images/HMI_HVAC_Circulation_Inactive.png', - width: iconSize, height: iconSize, fit: BoxFit.contain)), + width: sizeHelper.defaultIconSize, + height: sizeHelper.defaultIconSize, + fit: BoxFit.contain)), ), ], ), ); Widget actions = Container( - padding: EdgeInsets.all(spacingSize), + padding: EdgeInsets.all(sizeHelper.defaultPadding), child: Column( children: [ Image.asset('images/HMI_HVAC_AirDown_Inactive.png', - width: iconSize, height: iconSize, fit: BoxFit.contain), - SizedBox(height: spacingSize), + width: sizeHelper.defaultIconSize, + height: sizeHelper.defaultIconSize, + fit: BoxFit.contain), + SizedBox(height: sizeHelper.defaultPadding), Image.asset('images/HMI_HVAC_AirUp_Inactive.png', - width: iconSize, height: iconSize, fit: BoxFit.contain), - SizedBox(height: spacingSize), + width: sizeHelper.defaultIconSize, + height: sizeHelper.defaultIconSize, + fit: BoxFit.contain), + SizedBox(height: sizeHelper.defaultPadding), Image.asset('images/HMI_HVAC_Front_Inactive.png', - width: iconSize, height: iconSize, fit: BoxFit.contain), - SizedBox(height: spacingSize), + width: sizeHelper.defaultIconSize, + height: sizeHelper.defaultIconSize, + fit: BoxFit.contain), + SizedBox(height: sizeHelper.defaultPadding), Image.asset('images/HMI_HVAC_Rear_Active.png', - width: iconSize, height: iconSize, fit: BoxFit.contain), + width: sizeHelper.defaultIconSize, + height: sizeHelper.defaultIconSize, + fit: BoxFit.contain), ], - ), ); - return Column( - mainAxisAlignment: MainAxisAlignment.center, - children: <Widget>[ - fanSpeedControl, - Row(children: [ - Expanded(flex: 1, child: rightSeat), - Expanded(flex: 1, child: centerView), - Expanded(flex: 1, child: leftSeat), - Expanded(flex: 1, child: actions) - ]) - ], - ); - } - - @override - Widget build(BuildContext context) { return Container( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topRight, end: Alignment.bottomLeft, colors: [Colors.blueGrey.shade900, Colors.grey.shade900])), - child: Center( - child: LayoutBuilder( - builder: _buildLayout, - ))); + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: <Widget>[ + fanSpeedControl, + Row(children: [ + Expanded(flex: 1, child: rightSeat), + Expanded(flex: 1, child: centerView), + Expanded(flex: 1, child: leftSeat), + Expanded(flex: 1, child: actions) + ]) + ], + )); } } diff --git a/lib/page_media.dart b/lib/page_media.dart index f87f20b..618feb3 100644 --- a/lib/page_media.dart +++ b/lib/page_media.dart @@ -1,17 +1,37 @@ -import 'dart:math'; - import 'package:flutter/material.dart'; +import 'package:flutter_homescreen/layout_size_helper.dart'; class MediaPage extends StatelessWidget { const MediaPage({Key? key}) : super(key: key); - Widget _buildLayout(BuildContext context, BoxConstraints constraints) { - // describe the layout in terms of fractions of the container size - double mainDimension = max(constraints.maxWidth, constraints.maxHeight); - //double minDimension = min(constraints.maxWidth, constraints.maxHeight); - double iconSize = mainDimension / 12.0; + Widget _createMediaButton( + IconData icon, double iconSize, Null Function() onPressed) { + return Padding( + padding: EdgeInsets.all(iconSize / 8), + child: ElevatedButton( + onPressed: onPressed, + child: Icon( + icon, + color: Colors.blueGrey.shade700, + size: iconSize, + ), + style: ElevatedButton.styleFrom( + shape: CircleBorder(), + padding: EdgeInsets.all(iconSize / 8), + primary: Colors.blueGrey.shade100, + onPrimary: Colors.white, + ), + ), + ); + } + @override + Widget build(BuildContext context) { + var sizeHelper = LayoutSizeHelper(context); return Container( + color: Colors.deepPurple.shade50, + child: Center( + child: Container( color: Colors.blueGrey.shade900, constraints: BoxConstraints.expand(), alignment: Alignment.center, @@ -34,44 +54,25 @@ class MediaPage extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - _createMediaButton(Icons.skip_previous, iconSize, () {}), - _createMediaButton(Icons.play_arrow, iconSize, () {}), - _createMediaButton(Icons.skip_next, iconSize, () {}), + _createMediaButton( + Icons.skip_previous, + sizeHelper.defaultIconSize, + () {}, + ), + _createMediaButton( + Icons.play_arrow, + sizeHelper.defaultIconSize, + () {}, + ), + _createMediaButton( + Icons.skip_next, + sizeHelper.defaultIconSize, + () {}, + ), ], ) ], ), - ); - } - - Widget _createMediaButton( - IconData icon, double iconSize, Null Function() onPressed) { - return Padding( - padding: EdgeInsets.all(iconSize / 8), - child: ElevatedButton( - onPressed: onPressed, - child: Icon( - icon, - color: Colors.blueGrey.shade700, - size: iconSize, - ), - style: ElevatedButton.styleFrom( - shape: CircleBorder(), - padding: EdgeInsets.all(iconSize / 8), - primary: Colors.blueGrey.shade100, - onPrimary: Colors.white, - ), - ), - ); - } - - @override - Widget build(BuildContext context) { - return Container( - color: Colors.deepPurple.shade50, - child: Center( - child: LayoutBuilder( - builder: _buildLayout, - ))); + ))); } } |