diff --git a/assets/lc_circuit.png b/assets/lc_circuit.png new file mode 100644 index 0000000..af326f8 Binary files /dev/null and b/assets/lc_circuit.png differ diff --git a/lib/calculator/calculator.dart b/lib/calculator/calculator.dart new file mode 100644 index 0000000..4e1c5de --- /dev/null +++ b/lib/calculator/calculator.dart @@ -0,0 +1,31 @@ +import 'dart:math' as math; + +class Calculator { + double calculateMMC(double capacitance, int seriesCap, int parallelCap) { + double? _capacitance = 0.0; + + try { + var _cap = (capacitance * parallelCap) / seriesCap; + _capacitance = double.parse(_cap.toStringAsFixed(7)); + } catch (e) { + _capacitance = 0.0; + } + return _capacitance; + } + + double calculateResFrequency(double inductance, double capacitance) { + double resFreqResult = 0.0; + + var sqrtCap = math.sqrt(capacitance); + var sqrtInd = math.sqrt(inductance); + + var frequency = 1 / (2 * math.pi * sqrtInd * sqrtCap); + + /*try { + resFreqResult = double.parse(frequency.toStringAsFixed(2)); + } catch (e) { + resFreqResult = 0.0; + }*/ + return frequency; + } +} diff --git a/lib/main.dart b/lib/main.dart index 3e32ec9..fff48eb 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,5 @@ import 'package:coiler_app/screens/calculators/capacitor_screen.dart'; +import 'package:coiler_app/screens/calculators/resonant_freq_screen.dart'; import 'package:coiler_app/screens/calculators_screen.dart'; import 'package:coiler_app/screens/information_screen.dart'; import 'package:coiler_app/screens/main_screen.dart'; @@ -19,6 +20,8 @@ class MyApp extends StatelessWidget { MainScreen.id: (context) => const MainScreen(), CalculatorsScreen.id: (context) => const CalculatorsScreen(), CapacitorScreen.id: (context) => const CapacitorScreen(), + ResonantFrequencyScreen.id: (context) => + const ResonantFrequencyScreen(), InformationScreen.id: (context) => const InformationScreen(), }, initialRoute: MainScreen.id, diff --git a/lib/screens/calculators/resonant_freq_screen.dart b/lib/screens/calculators/resonant_freq_screen.dart new file mode 100644 index 0000000..e062c7c --- /dev/null +++ b/lib/screens/calculators/resonant_freq_screen.dart @@ -0,0 +1,191 @@ +import 'package:coiler_app/calculator/calculator.dart'; +import 'package:coiler_app/util/constants.dart'; +import 'package:coiler_app/util/conversion.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'; + +class ResonantFrequencyScreen extends StatefulWidget { + const ResonantFrequencyScreen({Key? key}) : super(key: key); + + static String id = "/calculators/resfreq"; + + @override + _ResonantFrequencyScreenState createState() => + _ResonantFrequencyScreenState(); +} + +class _ResonantFrequencyScreenState extends State { + final _formKey = GlobalKey(); + + String inductance = ""; + String capacitance = ""; + String frequency = ""; + + Units inductanceUnit = Units.MICRO; + Units capacitanceUnit = Units.MICRO; + Units frequencyUnit = Units.KILO; + + TextEditingController inductanceController = TextEditingController(); + TextEditingController capacitanceController = TextEditingController(); + + void calculateFrequency() { + if (!_formKey.currentState!.validate()) { + return; + } + var inductanceTemp = double.tryParse(inductance); + 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 frequencyTemp = + Calculator().calculateResFrequency(inductance, capacitance); + var frequency = + Converter().convertUnits(frequencyTemp, Units.DEFAULT, frequencyUnit); + + setState(() { + this.frequency = frequency.toStringAsFixed(4); + }); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 8, + ), + child: SingleChildScrollView( + child: Form( + autovalidateMode: AutovalidateMode.always, + key: _formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Align( + alignment: Alignment.center, + child: BorderContainer( + elevated: true, + child: Column( + children: [ + Image.asset( + "assets/lc_circuit.png", + height: 200, + ), + Text( + "Calculate resonant frequency of your LC circuit by entering values below.", + style: normalTextStyleOpenSans14, + textAlign: TextAlign.center, + ) + ], + ), + ), + ), + SizedBox( + height: 10, + ), + BorderContainer( + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text("Frequency: $frequency"), + Container( + padding: EdgeInsets.symmetric( + horizontal: 9, + ), + decoration: BoxDecoration( + color: lightBlueColor, + borderRadius: BorderRadius.circular(9), + ), + child: DropdownButton( + value: frequencyUnit, + items: frequencyDropDownList, + borderRadius: BorderRadius.circular(9), + underline: Container(), + onChanged: (value) { + setState(() { + frequencyUnit = value!; + calculateFrequency(); + }); + }), + ), + ], + ), + ), + 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), + ), + 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), + ), + ], + ), + ), + ), + ), + ), + ); + } +} diff --git a/lib/screens/calculators_screen.dart b/lib/screens/calculators_screen.dart index d133a6c..5f466e5 100644 --- a/lib/screens/calculators_screen.dart +++ b/lib/screens/calculators_screen.dart @@ -1,4 +1,5 @@ import 'package:coiler_app/screens/calculators/capacitor_screen.dart'; +import 'package:coiler_app/screens/calculators/resonant_freq_screen.dart'; import 'package:coiler_app/util/constants.dart'; import 'package:flutter/material.dart'; @@ -13,7 +14,7 @@ class CalculatorsScreen extends StatelessWidget { body: SafeArea( child: Column( children: [ - Center( + const Center( child: Padding( padding: const EdgeInsets.all(8.0), child: Text( @@ -48,7 +49,7 @@ class CalculatorsScreen extends StatelessWidget { height: 26, ), onTap: () { - //TODO Navigate + Navigator.pushNamed(context, ResonantFrequencyScreen.id); }, ), CalculatorItem( diff --git a/lib/util/constants.dart b/lib/util/constants.dart index 5d7b930..9beb754 100644 --- a/lib/util/constants.dart +++ b/lib/util/constants.dart @@ -10,3 +10,21 @@ const lightCategoryTextStyle = TextStyle( fontFamily: "OpenSans", color: Colors.black54, ); + +const normalTextStyleOpenSans14 = TextStyle( + fontFamily: "OpenSans", + fontWeight: FontWeight.normal, + fontSize: 15, +); + +const biggerTextStyleOpenSans15 = TextStyle( + fontFamily: "OpenSans", + fontWeight: FontWeight.w500, + fontSize: 16, +); + +const lightBlueColor = Color(0xffe1efff); + +enum Units { DEFAULT, MILI, MICRO, NANO, PICO, KILO, MEGA, GIGA } + +const voltageUnitText = "V"; diff --git a/lib/util/conversion.dart b/lib/util/conversion.dart new file mode 100644 index 0000000..096defa --- /dev/null +++ b/lib/util/conversion.dart @@ -0,0 +1,41 @@ +import 'package:coiler_app/util/constants.dart'; + +class Converter { + static const Map unitsMap = { + Units.DEFAULT: 1.0, + Units.MILI: 0.001, + Units.MICRO: 0.000001, + Units.NANO: 0.000000001, + Units.PICO: 0.000000000001, + Units.KILO: 1000, + Units.MEGA: 1000000, + Units.GIGA: 1000000000, + }; + + double getCapMultiplier(Units unit) => unitsMap[unit]!; + + /// Function used to convert different units + /// [value] value to be converted + /// [from] from which unit we need to convert + /// [to] unit which we will convert to + /// + /// Example: + /// + /// ```dart + /// result = convertUnits(22, Units.MICRO, Units.NANO) -> 22000.0 + /// result = convertUnits(2, Units.DEFAULT, Units.MICRO) -> 2000000.0 + /// result = convertUnits(13.4, Units.PICO, Units.NANO) -> 0.0134 + /// ``` + /// + double convertUnits(dynamic value, Units from, Units to) { + double result = 0.0; + try { + var multiplier = getCapMultiplier(from) / getCapMultiplier(to); + double tempResult = value * multiplier; + result = tempResult; //double.parse(tempResult.toStringAsFixed(7)); + } catch (e) { + print(e); + } + return result; + } +} diff --git a/lib/util/list_constants.dart b/lib/util/list_constants.dart new file mode 100644 index 0000000..66c016f --- /dev/null +++ b/lib/util/list_constants.dart @@ -0,0 +1,59 @@ +import 'package:coiler_app/util/constants.dart'; +import 'package:flutter/material.dart'; + +const capacitanceDropDownList = [ + DropdownMenuItem( + child: Text("F"), + value: Units.DEFAULT, + ), + DropdownMenuItem( + child: Text("uF"), + value: Units.MICRO, + ), + DropdownMenuItem( + child: Text("nF"), + value: Units.NANO, + ), + DropdownMenuItem( + child: Text("pF"), + value: Units.PICO, + ), +]; + +const inductanceDropDownList = [ + DropdownMenuItem( + child: Text("H"), + value: Units.DEFAULT, + ), + DropdownMenuItem( + child: Text("mH"), + value: Units.MILI, + ), + DropdownMenuItem( + child: Text("uH"), + value: Units.MICRO, + ), + DropdownMenuItem( + child: Text("nH"), + value: Units.NANO, + ), +]; + +const frequencyDropDownList = [ + DropdownMenuItem( + child: Text("Hz"), + value: Units.DEFAULT, + ), + DropdownMenuItem( + child: Text("kHz"), + value: Units.KILO, + ), + DropdownMenuItem( + child: Text("MHz"), + value: Units.MEGA, + ), + DropdownMenuItem( + child: Text("GHz"), + value: Units.GIGA, + ), +]; diff --git a/lib/widgets/border_container.dart b/lib/widgets/border_container.dart new file mode 100644 index 0000000..49e8a3e --- /dev/null +++ b/lib/widgets/border_container.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.dart'; + +/// [backgroundImage] is image asset path which displays image in the background of the container with certain opacity. +/// +/// +class BorderContainer extends StatelessWidget { + const BorderContainer( + {Key? key, this.child, this.backgroundImage, this.elevated}) + : super(key: key); + + final Widget? child; + final String? backgroundImage; + final bool? elevated; + + static const List shadows = [ + BoxShadow( + color: Color(0xFFebebeb), + blurRadius: 12, + spreadRadius: 1, + offset: Offset(0, 3), + ), + ]; + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.all(9), + decoration: BoxDecoration( + color: Colors.white, + boxShadow: (elevated != null && elevated != false) ? shadows : [], + border: Border.all(color: Colors.black26), + borderRadius: BorderRadius.circular(16), + image: backgroundImage != null + ? DecorationImage( + opacity: 0.04, + fit: BoxFit.contain, + image: AssetImage(backgroundImage ?? ""), + ) + : null, + ), + child: child, + ); + } +} diff --git a/lib/widgets/input_field.dart b/lib/widgets/input_field.dart new file mode 100644 index 0000000..e665bc5 --- /dev/null +++ b/lib/widgets/input_field.dart @@ -0,0 +1,81 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +class InputField extends StatelessWidget { + const InputField( + {Key? key, + required this.controller, + required this.onTextChanged, + required this.validator, + this.inputType = const TextInputType.numberWithOptions(decimal: true), + this.hintText = "", + this.labelText = "", + this.maxLength, + required this.unitText, + required this.inputFormatter}) + : super(key: key); + + final TextEditingController controller; + final Function(String? text) validator; + final Function(dynamic value) onTextChanged; + final List inputFormatter; + final TextInputType inputType; + final String hintText; + final String labelText; + final String unitText; + final int? maxLength; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.only( + top: 12, + ), + child: TextFormField( + autovalidateMode: AutovalidateMode.onUserInteraction, + onChanged: (value) => onTextChanged(value), + validator: (text) => validator(text), + controller: controller, + keyboardType: inputType, + maxLines: 1, + maxLength: maxLength, + inputFormatters: inputFormatter, + decoration: InputDecoration( + suffixIcon: Padding( + padding: const EdgeInsets.only( + right: 9, + ), + child: Container( + padding: const EdgeInsets.symmetric( + vertical: 3, + horizontal: 9, + ), + decoration: BoxDecoration( + color: const Color(0xffe1efff), + borderRadius: BorderRadius.circular(9), + ), + child: Align( + alignment: Alignment.center, + widthFactor: 1, + child: Text( + unitText, + textAlign: TextAlign.center, + maxLines: 1, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontFamily: "OpenSans", + ), + ), + ), + ), + ), + hintText: hintText, + labelText: labelText, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(9), + ), + ), + ), + ); + } +} diff --git a/lib/widgets/input_field_dropdown.dart b/lib/widgets/input_field_dropdown.dart new file mode 100644 index 0000000..b4ab1bd --- /dev/null +++ b/lib/widgets/input_field_dropdown.dart @@ -0,0 +1,74 @@ +import 'package:coiler_app/util/constants.dart'; +import 'package:flutter/material.dart'; + +class InputFieldDropDown extends StatelessWidget { + const InputFieldDropDown({ + Key? key, + required this.controller, + required this.onTextChanged, + required this.validator, + this.inputType = const TextInputType.numberWithOptions(decimal: true), + this.hintText = "", + this.labelText = "", + required this.dropDownValue, + required this.onDropDownChanged, + required this.dropDownList, + }) : super(key: key); + + final TextEditingController controller; + final Function(String? text) validator; + final Function(dynamic value) onTextChanged; + final Function(Units? unit) onDropDownChanged; + final TextInputType inputType; + final String hintText; + final String labelText; + final Units dropDownValue; + final List> dropDownList; + + @override + Widget build(BuildContext context) { + return TextFormField( + autovalidateMode: AutovalidateMode.onUserInteraction, + onChanged: (value) => onTextChanged(value), + validator: (text) => validator(text), + controller: controller, + keyboardType: inputType, + decoration: InputDecoration( + suffixIcon: Padding( + padding: const EdgeInsets.only( + right: 9, + ), + child: Container( + padding: const EdgeInsets.symmetric( + vertical: 3, + horizontal: 12, + ), + decoration: BoxDecoration( + color: const Color(0xffe1efff), + borderRadius: BorderRadius.circular(9), + ), + child: Align( + alignment: Alignment.centerRight, + widthFactor: 1, + child: DropdownButton( + borderRadius: BorderRadius.circular(9), + value: dropDownValue, + style: + normalTextStyleOpenSans14.copyWith(color: Colors.black87), + underline: Container(), + items: dropDownList, + onChanged: (value) => onDropDownChanged(value), + isDense: true, + ), + ), + ), + ), + hintText: hintText, + labelText: labelText, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(9), + ), + ), + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index 7e78bae..5576fde 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,27 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + url: "https://pub.dartlang.org" + source: hosted + version: "31.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + url: "https://pub.dartlang.org" + source: hosted + version: "2.8.0" + args: + dependency: transitive + description: + name: args + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.0" async: dependency: transitive description: @@ -29,6 +50,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.1" + cli_util: + dependency: transitive + description: + name: cli_util + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.5" clock: dependency: transitive description: @@ -43,6 +71,27 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.15.0" + convert: + dependency: transitive + description: + name: convert + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + coverage: + dependency: transitive + description: + name: coverage + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.3" + crypto: + dependency: transitive + description: + name: crypto + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" cupertino_icons: dependency: "direct main" description: @@ -57,6 +106,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.0" + file: + dependency: transitive + description: + name: file + url: "https://pub.dartlang.org" + source: hosted + version: "6.1.2" flutter: dependency: "direct main" description: flutter @@ -74,6 +130,48 @@ packages: description: flutter source: sdk version: "0.0.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.2" + glob: + dependency: transitive + description: + name: glob + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.2" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + url: "https://pub.dartlang.org" + source: hosted + version: "3.2.0" + http_parser: + dependency: transitive + description: + name: http_parser + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.0" + io: + dependency: transitive + description: + name: io + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.3" + js: + dependency: transitive + description: + name: js + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.4" lints: dependency: transitive description: @@ -81,6 +179,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.1" + logging: + dependency: transitive + description: + name: logging + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" matcher: dependency: transitive description: @@ -102,6 +207,27 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.7.0" + mime: + dependency: transitive + description: + name: mime + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + node_preamble: + dependency: transitive + description: + name: node_preamble + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + package_config: + dependency: transitive + description: + name: package_config + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.2" path: dependency: transitive description: @@ -109,11 +235,67 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.0" + pool: + dependency: transitive + description: + name: pool + url: "https://pub.dartlang.org" + source: hosted + version: "1.5.0" + pub_semver: + dependency: transitive + description: + name: pub_semver + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + shelf: + dependency: transitive + description: + name: shelf + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + shelf_static: + dependency: transitive + description: + name: shelf_static + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" sky_engine: dependency: transitive description: flutter source: sdk version: "0.0.99" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + source_maps: + dependency: transitive + description: + name: source_maps + url: "https://pub.dartlang.org" + source: hosted + version: "0.10.10" source_span: dependency: transitive description: @@ -149,6 +331,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.0" + test: + dependency: "direct main" + description: + name: test + url: "https://pub.dartlang.org" + source: hosted + version: "1.19.5" test_api: dependency: transitive description: @@ -156,6 +345,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.4.8" + test_core: + dependency: transitive + description: + name: test_core + url: "https://pub.dartlang.org" + source: hosted + version: "0.4.9" typed_data: dependency: transitive description: @@ -170,5 +366,40 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.1" + vm_service: + dependency: transitive + description: + name: vm_service + url: "https://pub.dartlang.org" + source: hosted + version: "7.5.0" + watcher: + dependency: transitive + description: + name: watcher + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + yaml: + dependency: transitive + description: + name: yaml + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" sdks: dart: ">=2.16.1 <3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index b64ce00..6948f15 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -34,6 +34,7 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.2 + test: dev_dependencies: flutter_test: