diff --git a/lib/main.dart b/lib/main.dart index 364760d..b3ae274 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,6 +2,7 @@ import 'package:coiler_app/arguments/HelicalCalculatorArgs.dart'; import 'package:coiler_app/dao/DriftCoilDao.dart'; import 'package:coiler_app/database/drift_coil_database.dart'; import 'package:coiler_app/providers/CoilProvider.dart'; +import 'package:coiler_app/providers/FrequencyProvider.dart'; import 'package:coiler_app/providers/HelicalCalculatorProvider.dart'; import 'package:coiler_app/screens/calculators/capacitor_screen.dart'; import 'package:coiler_app/screens/calculators/helical_coil_screen.dart'; @@ -73,7 +74,10 @@ class MyApp extends StatelessWidget { ), CalculatorsScreen.id: (context) => const CalculatorsScreen(), CapacitorScreen.id: (context) => const CapacitorScreen(), - ResonantFrequencyScreen.id: (context) => const ResonantFrequencyScreen(), + ResonantFrequencyScreen.id: (context) => ChangeNotifierProvider( + create: (context) => ResonantFrequencyProvider(), + child: const ResonantFrequencyScreen(), + ), /*HelicalCoilCalculatorScreen.id: (context) => const HelicalCoilCalculatorScreen(),*/ CoilsListScreen.id: (context) => const CoilsListScreen(), diff --git a/lib/providers/FrequencyProvider.dart b/lib/providers/FrequencyProvider.dart new file mode 100644 index 0000000..14faba7 --- /dev/null +++ b/lib/providers/FrequencyProvider.dart @@ -0,0 +1,82 @@ +import 'package:coiler_app/calculator/calculator.dart'; +import 'package:coiler_app/entities/Validation.dart'; +import 'package:coiler_app/util/constants.dart'; +import 'package:coiler_app/util/conversion.dart'; +import 'package:flutter/cupertino.dart'; + +class ResonantFrequencyProvider extends ChangeNotifier { + var _inductanceValidation = InputValidation(value: null, error: null); + var _capacitanceValidation = InputValidation(value: null, error: null); + + InputValidation get inductance => _inductanceValidation; + InputValidation get capacitance => _capacitanceValidation; + + Units _inductanceUnit = Units.MICRO; + Units _capacitanceUnit = Units.MICRO; + Units _frequencyUnit = Units.KILO; + + Units get capacitanceUnit => _capacitanceUnit; + + Units get frequencyUnit => _frequencyUnit; + + Units get inductanceUnit => _inductanceUnit; + + double _frequency = 0.0; + String frequencyText = ""; + + void calculateFrequency() { + if (!validate()) { + return; + } + parseResultAndCalculate(); + notifyListeners(); + } + + void parseResultAndCalculate() { + final inductanceTemp = Converter().convertToDefault(_inductanceValidation.value, _inductanceUnit); + final capacitanceTemp = Converter().convertToDefault(_capacitanceValidation.value, _capacitanceUnit); + + final tempFreq = Calculator().calculateResFrequency(inductanceTemp, capacitanceTemp); + + _frequency = tempFreq; + + frequencyText = Converter().convertUnits(tempFreq, Units.DEFAULT, _frequencyUnit).toStringAsFixed(7); + } + + void setFrequencyUnit(Units unit) { + _frequencyUnit = unit; + notifyListeners(); + } + + void setInductanceUnit(Units unit) { + _inductanceUnit = unit; + notifyListeners(); + } + + void setCapacitanceUnit(Units unit) { + _capacitanceUnit = unit; + notifyListeners(); + } + + void validateInductance(double? inductance) { + if (inductance != null && inductance > 0) { + _inductanceValidation = InputValidation(value: inductance, error: null); + } else { + _inductanceValidation = InputValidation(value: null, error: "Invalid inductance value."); + } + notifyListeners(); + } + + void validateCapacitance(double? capacitance) { + if (capacitance == null || capacitance <= 0) { + _capacitanceValidation = InputValidation(value: null, error: "Invalid capacitance value."); + } else { + _capacitanceValidation = InputValidation(value: capacitance, error: null); + } + notifyListeners(); + } + + bool validate() { + return (_inductanceValidation.value != null && _capacitanceValidation.value != null); + } +} diff --git a/lib/screens/calculators/resonant_freq_screen.dart b/lib/screens/calculators/resonant_freq_screen.dart index e062c7c..8394f45 100644 --- a/lib/screens/calculators/resonant_freq_screen.dart +++ b/lib/screens/calculators/resonant_freq_screen.dart @@ -1,11 +1,13 @@ -import 'package:coiler_app/calculator/calculator.dart'; +import 'package:coiler_app/providers/FrequencyProvider.dart'; +import 'package:coiler_app/util/color_constants.dart' as ColorUtil; import 'package:coiler_app/util/constants.dart'; -import 'package:coiler_app/util/conversion.dart'; +import 'package:coiler_app/util/extensions/theme_extension.dart'; import 'package:coiler_app/util/list_constants.dart'; import 'package:coiler_app/widgets/border_container.dart'; import 'package:coiler_app/widgets/input_field_dropdown.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; class ResonantFrequencyScreen extends StatefulWidget { const ResonantFrequencyScreen({Key? key}) : super(key: key); @@ -13,25 +15,24 @@ class ResonantFrequencyScreen extends StatefulWidget { static String id = "/calculators/resfreq"; @override - _ResonantFrequencyScreenState createState() => - _ResonantFrequencyScreenState(); + _ResonantFrequencyScreenState createState() => _ResonantFrequencyScreenState(); } class _ResonantFrequencyScreenState extends State { final _formKey = GlobalKey(); - String inductance = ""; + /*String inductance = ""; String capacitance = ""; String frequency = ""; Units inductanceUnit = Units.MICRO; Units capacitanceUnit = Units.MICRO; - Units frequencyUnit = Units.KILO; + Units frequencyUnit = Units.KILO;*/ TextEditingController inductanceController = TextEditingController(); TextEditingController capacitanceController = TextEditingController(); - void calculateFrequency() { + /*void calculateFrequency() { if (!_formKey.currentState!.validate()) { return; } @@ -39,26 +40,23 @@ class _ResonantFrequencyScreenState extends State { var capacitanceTemp = double.tryParse(capacitance); if (inductanceTemp != 0 && capacitanceTemp != 0) { - var inductance = Converter() - .convertUnits(inductanceTemp, inductanceUnit, Units.DEFAULT); - var capacitance = Converter() - .convertUnits(capacitanceTemp, capacitanceUnit, Units.DEFAULT); + var inductance = Converter().convertUnits(inductanceTemp, inductanceUnit, Units.DEFAULT); + var capacitance = Converter().convertUnits(capacitanceTemp, capacitanceUnit, Units.DEFAULT); - var frequencyTemp = - Calculator().calculateResFrequency(inductance, capacitance); - var frequency = - Converter().convertUnits(frequencyTemp, Units.DEFAULT, frequencyUnit); + var frequencyTemp = Calculator().calculateResFrequency(inductance, capacitance); + var frequency = Converter().convertUnits(frequencyTemp, Units.DEFAULT, frequencyUnit); setState(() { this.frequency = frequency.toStringAsFixed(4); }); } } - +*/ @override Widget build(BuildContext context) { + final theme = Theme.of(context); return Scaffold( - backgroundColor: Colors.white, + backgroundColor: theme.backgroundColor, body: SafeArea( child: Padding( padding: const EdgeInsets.symmetric( @@ -67,7 +65,6 @@ class _ResonantFrequencyScreenState extends State { ), child: SingleChildScrollView( child: Form( - autovalidateMode: AutovalidateMode.always, key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, @@ -75,23 +72,23 @@ class _ResonantFrequencyScreenState extends State { Align( alignment: Alignment.center, child: BorderContainer( - elevated: true, child: Column( children: [ Image.asset( "assets/lc_circuit.png", height: 200, + color: context.isDarkTheme() ? Colors.white : Colors.black87, ), Text( "Calculate resonant frequency of your LC circuit by entering values below.", - style: normalTextStyleOpenSans14, + style: theme.textTheme.displayMedium, textAlign: TextAlign.center, ) ], ), ), ), - SizedBox( + const SizedBox( height: 10, ), BorderContainer( @@ -99,86 +96,91 @@ class _ResonantFrequencyScreenState extends State { mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text("Frequency: $frequency"), + Text( + "Frequency: ${Provider.of(context).frequencyText}", + style: theme.textTheme.displaySmall, + ), Container( - padding: EdgeInsets.symmetric( + padding: const EdgeInsets.symmetric( horizontal: 9, ), decoration: BoxDecoration( - color: lightBlueColor, + color: context.isDarkTheme() ? Colors.grey.shade800 : ColorUtil.lightestBlue, borderRadius: BorderRadius.circular(9), ), - child: DropdownButton( - value: frequencyUnit, - items: frequencyDropDownList, - borderRadius: BorderRadius.circular(9), - underline: Container(), - onChanged: (value) { - setState(() { - frequencyUnit = value!; - calculateFrequency(); - }); - }), + child: Consumer( + builder: (context, provider, child) { + return DropdownButton( + value: provider.frequencyUnit, + items: frequencyDropDownList, + style: theme.textTheme.displaySmall?.copyWith(fontWeight: FontWeight.bold), + borderRadius: BorderRadius.circular(9), + underline: Container(), + onChanged: (unitValue) { + provider.setFrequencyUnit(unitValue!); + provider.calculateFrequency(); + }, + ); + }, + ), ), ], ), ), - SizedBox( + const SizedBox( height: 20, ), Padding( padding: const EdgeInsets.symmetric( vertical: 9, ), - child: InputFieldDropDown( - hintText: "Enter inductance", - labelText: "Inductance", - controller: inductanceController, - onTextChanged: (text) { - setState(() { - inductance = text; - calculateFrequency(); - }); - }, - validator: (text) { - if (text == null || text.isEmpty) { - return "Input invalid"; - } else { - return null; - } - }, - dropDownValue: inductanceUnit, - onDropDownChanged: (value) { - setState(() { - inductanceUnit = value!; - calculateFrequency(); - }); - }, - dropDownList: inductanceDropDownList), + child: Consumer( + builder: (context, provider, child) { + return InputFieldDropDown( + hintText: "Enter inductance", + labelText: "Inductance", + controller: inductanceController, + onTextChanged: (text) { + provider.validateInductance(double.tryParse(text)); + provider.calculateFrequency(); + }, + validator: (text) => null, + errorText: provider.inductance.error, + dropDownValue: provider.inductanceUnit, + onDropDownChanged: (value) { + provider.setInductanceUnit(value!); + provider.calculateFrequency(); + }, + dropDownList: inductanceDropDownList, + ); + }, + ), ), Padding( padding: const EdgeInsets.symmetric( vertical: 9, ), - child: InputFieldDropDown( - hintText: "Enter capacitance", - labelText: "Capacitance", - controller: capacitanceController, - onTextChanged: (text) { - setState(() { - capacitance = text; - calculateFrequency(); - }); - }, - validator: (text) {}, - dropDownValue: capacitanceUnit, - onDropDownChanged: (value) { - setState(() { - capacitanceUnit = value!; - calculateFrequency(); - }); - }, - dropDownList: capacitanceDropDownList), + child: Consumer( + builder: (context, provider, child) { + return InputFieldDropDown( + hintText: "Enter capacitance", + labelText: "Capacitance", + controller: capacitanceController, + onTextChanged: (text) { + provider.validateCapacitance(double.tryParse(text)); + provider.calculateFrequency(); + }, + validator: (text) => null, + errorText: provider.capacitance.error, + dropDownValue: provider.capacitanceUnit, + onDropDownChanged: (value) { + provider.setCapacitanceUnit(value!); + provider.calculateFrequency(); + }, + dropDownList: capacitanceDropDownList, + ); + }, + ), ), ], ), diff --git a/lib/theme/darkTheme.dart b/lib/theme/darkTheme.dart index ddaf3f4..8f72bd5 100644 --- a/lib/theme/darkTheme.dart +++ b/lib/theme/darkTheme.dart @@ -1,16 +1,19 @@ import 'package:coiler_app/util/constants.dart'; import 'package:coiler_app/util/ui_constants.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; final darkTheme = ThemeData( appBarTheme: AppBarTheme( titleTextStyle: normalTextStyleOpenSans14.copyWith(color: Colors.black87), toolbarTextStyle: normalTextStyleOpenSans14.copyWith(color: Colors.black87), backgroundColor: darkAppBarBackgroundColor, + systemOverlayStyle: SystemUiOverlayStyle.light, iconTheme: const IconThemeData( color: Colors.white, ), ), + canvasColor: Colors.grey.shade900, popupMenuTheme: PopupMenuThemeData( color: darkThemeBackgroundColor, textStyle: normalTextStyleOpenSans14.copyWith( @@ -29,7 +32,7 @@ final darkTheme = ThemeData( color: Colors.white54, fontSize: 14, ), - displayMedium: normalTextStyleOpenSans14.copyWith(color: Colors.white), + displayMedium: normalTextStyleOpenSans14.copyWith(color: Colors.white54), ), listTileTheme: ListTileThemeData( textColor: Colors.white, @@ -40,6 +43,14 @@ final darkTheme = ThemeData( side: const BorderSide(color: Colors.white12), ), ), + inputDecorationTheme: InputDecorationTheme( + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.grey.shade700, width: 1.2), + borderRadius: BorderRadius.circular(9), + ), + labelStyle: normalTextStyleOpenSans14.copyWith(color: Colors.white54), + floatingLabelStyle: lightCategoryTextStyle.copyWith(color: Colors.white54, fontWeight: FontWeight.bold), + ), backgroundColor: darkThemeBackgroundColor, dialogTheme: DialogTheme( backgroundColor: darkThemeBackgroundColor, diff --git a/lib/theme/lightTheme.dart b/lib/theme/lightTheme.dart index 5a1beb5..5d16f16 100644 --- a/lib/theme/lightTheme.dart +++ b/lib/theme/lightTheme.dart @@ -11,6 +11,7 @@ final lightTheme = ThemeData( color: Colors.black87, ), ), + canvasColor: Colors.white, backgroundColor: lightThemeBackgroundColor, listTileTheme: ListTileThemeData( tileColor: Colors.white, @@ -42,4 +43,12 @@ final lightTheme = ThemeData( contentTextStyle: normalTextStyleOpenSans14, shape: roundedBorder16, ), + inputDecorationTheme: InputDecorationTheme( + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.grey.shade400, width: 1.2), + borderRadius: BorderRadius.circular(9), + ), + labelStyle: normalTextStyleOpenSans14.copyWith(color: Colors.grey.shade600), + floatingLabelStyle: lightCategoryTextStyle.copyWith(color: Colors.white54, fontWeight: FontWeight.bold), + ), ); diff --git a/lib/util/color_constants.dart b/lib/util/color_constants.dart index 4ad5e41..d808227 100644 --- a/lib/util/color_constants.dart +++ b/lib/util/color_constants.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; const lightestBlue = Color(0xffe1efff); +const borderColor = Color(0x44595959); const orangeGradient = Color(0xFFffd47d); const blueGradient = Color(0xFF7accff); diff --git a/lib/util/extensions/theme_extension.dart b/lib/util/extensions/theme_extension.dart new file mode 100644 index 0000000..4414048 --- /dev/null +++ b/lib/util/extensions/theme_extension.dart @@ -0,0 +1,8 @@ +import 'package:flutter/cupertino.dart'; + +extension ThemeCheck on BuildContext { + bool isDarkTheme() { + final bright = MediaQuery.of(this).platformBrightness; + return bright == Brightness.dark; + } +} diff --git a/lib/util/list_constants.dart b/lib/util/list_constants.dart index b490017..f91be7e 100644 --- a/lib/util/list_constants.dart +++ b/lib/util/list_constants.dart @@ -7,7 +7,7 @@ const capacitanceDropDownList = [ value: Constants.Units.DEFAULT, ), DropdownMenuItem( - child: Text("uF"), + child: Text("µF"), value: Constants.Units.MICRO, ), DropdownMenuItem( @@ -30,7 +30,7 @@ const inductanceDropDownList = [ value: Constants.Units.MILI, ), DropdownMenuItem( - child: Text("uH"), + child: Text("µH"), value: Constants.Units.MICRO, ), DropdownMenuItem( diff --git a/lib/widgets/border_container.dart b/lib/widgets/border_container.dart index 166d765..7e64deb 100644 --- a/lib/widgets/border_container.dart +++ b/lib/widgets/border_container.dart @@ -1,3 +1,4 @@ +import 'package:coiler_app/util/color_constants.dart' as ColorUtil; import 'package:flutter/material.dart'; /// [backgroundImage] is image asset path which displays image in the background of the container with certain opacity. @@ -29,13 +30,13 @@ class BorderContainer extends StatelessWidget { @override Widget build(BuildContext context) { return Material( - color: Colors.white, + color: Theme.of(context).canvasColor, borderRadius: BorderRadius.circular(16), child: Container( padding: padding, decoration: BoxDecoration( boxShadow: (elevated != null && elevated != false) ? shadows : [], - border: Border.all(color: Colors.black26), + border: Border.all(color: ColorUtil.borderColor), //Colors.black26 borderRadius: BorderRadius.circular(16), image: backgroundImage != null ? DecorationImage( diff --git a/lib/widgets/input_field_dropdown.dart b/lib/widgets/input_field_dropdown.dart index e139fce..7d2d2dc 100644 --- a/lib/widgets/input_field_dropdown.dart +++ b/lib/widgets/input_field_dropdown.dart @@ -1,4 +1,6 @@ +import 'package:coiler_app/util/color_constants.dart' as ColorUtil; import 'package:coiler_app/util/constants.dart'; +import 'package:coiler_app/util/extensions/theme_extension.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -32,6 +34,7 @@ class InputFieldDropDown extends StatelessWidget { @override Widget build(BuildContext context) { + final theme = Theme.of(context); return TextFormField( autovalidateMode: AutovalidateMode.onUserInteraction, onChanged: (value) => onTextChanged(value), @@ -39,6 +42,7 @@ class InputFieldDropDown extends StatelessWidget { controller: controller, keyboardType: inputType, inputFormatters: inputFormatters, + style: theme.textTheme.displayMedium, decoration: InputDecoration( suffixIcon: Padding( padding: const EdgeInsets.only( @@ -50,7 +54,7 @@ class InputFieldDropDown extends StatelessWidget { horizontal: 12, ), decoration: BoxDecoration( - color: const Color(0xffe1efff), + color: context.isDarkTheme() ? Colors.grey.shade800 : ColorUtil.lightestBlue, //const Color(0xffe1efff), borderRadius: BorderRadius.circular(9), ), child: Align( @@ -59,7 +63,8 @@ class InputFieldDropDown extends StatelessWidget { child: DropdownButton( borderRadius: BorderRadius.circular(9), value: dropDownValue, - style: normalTextStyleOpenSans14.copyWith(color: Colors.black87), + style: + theme.textTheme.displaySmall?.copyWith(fontWeight: FontWeight.bold), //normalTextStyleOpenSans14.copyWith(color: Colors.black87), underline: Container(), items: dropDownList, onChanged: (value) => onDropDownChanged(value), @@ -71,10 +76,35 @@ class InputFieldDropDown extends StatelessWidget { hintText: hintText, labelText: labelText, errorText: errorText, + hintStyle: theme.inputDecorationTheme.labelStyle, + labelStyle: theme.inputDecorationTheme.labelStyle, + floatingLabelStyle: MaterialStateTextStyle.resolveWith((states) { + var color = theme.textTheme.displayMedium?.color; + + if (states.contains(MaterialState.error)) { + color = Colors.red; + } else if (states.contains(MaterialState.focused)) { + color = theme.primaryColor; + } + return (theme.inputDecorationTheme.floatingLabelStyle?.copyWith(color: color))!; + }), border: OutlineInputBorder( + borderSide: BorderSide(color: theme.primaryColor), borderRadius: BorderRadius.circular(9), ), + enabledBorder: theme.inputDecorationTheme.enabledBorder, ), ); } + + TextStyle? getLabelStyle(ThemeData theme, Set states) { + var style = theme.inputDecorationTheme.labelStyle; + + if (states.contains(MaterialState.focused)) { + style = theme.inputDecorationTheme.labelStyle?.copyWith(color: theme.primaryColor); + } else if (states.contains(MaterialState.error)) { + style = theme.inputDecorationTheme.labelStyle?.copyWith(color: Colors.red); + } + return style!; + } }