diff --git a/ios/Flutter/flutter_export_environment.sh b/ios/Flutter/flutter_export_environment.sh new file mode 100755 index 0000000..3109580 --- /dev/null +++ b/ios/Flutter/flutter_export_environment.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# This is a generated file; do not edit or check into version control. +export "FLUTTER_ROOT=/Users/philippmuellauer/Developer/flutter" +export "FLUTTER_APPLICATION_PATH=/Users/philippmuellauer/Documents/Flutter/Flutter Complete/bmi-calculator" +export "FLUTTER_TARGET=lib/main.dart" +export "FLUTTER_BUILD_DIR=build" +export "SYMROOT=${SOURCE_ROOT}/../build/ios" +export "FLUTTER_FRAMEWORK_DIR=/Users/philippmuellauer/Developer/flutter/bin/cache/artifacts/engine/ios" +export "FLUTTER_BUILD_NAME=1.0.0" +export "FLUTTER_BUILD_NUMBER=1" diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 1df82eb..92f82fb 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -8,7 +8,6 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAA1A9400D5DBA9 /* flutter_assets */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; @@ -40,7 +39,6 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; @@ -73,7 +71,6 @@ 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( - 2D5378251FAA1A9400D5DBA9 /* flutter_assets */, 3B80C3931E831B6300D905FE /* App.framework */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 9740EEBA1CF902C7004384FC /* Flutter.framework */, @@ -190,7 +187,6 @@ 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..949b678 --- /dev/null +++ b/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + BuildSystemType + Original + + diff --git a/lib/calculator_brain.dart b/lib/calculator_brain.dart new file mode 100644 index 0000000..5783edd --- /dev/null +++ b/lib/calculator_brain.dart @@ -0,0 +1,35 @@ +import 'dart:math'; + +class CalculatorBrain { + CalculatorBrain({this.height, this.weight}); + + final int height; + final int weight; + + double _bmi; + + String calculateBMI() { + _bmi = weight / pow(height / 100, 2); + return _bmi.toStringAsFixed(1); + } + + String getResult() { + if (_bmi >= 25) { + return 'Overweight'; + } else if (_bmi > 18.5) { + return 'Normal'; + } else { + return 'Underweight'; + } + } + + String getInterpretation() { + if (_bmi >= 25) { + return 'You have a higher than normal body weight. Try to exercise more.'; + } else if (_bmi >= 18.5) { + return 'You have a normal body weight. Good job!'; + } else { + return 'You have a lower than normal body weight. You can eat a bit more.'; + } + } +} diff --git a/lib/components/bottom_button.dart b/lib/components/bottom_button.dart new file mode 100644 index 0000000..d2822f2 --- /dev/null +++ b/lib/components/bottom_button.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import 'package:bmi_calculator/constants.dart'; + +class BottomButton extends StatelessWidget { + BottomButton({@required this.onTap, @required this.buttonTitle}); + + final Function onTap; + final String buttonTitle; + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: onTap, + child: Container( + child: Center( + child: Text( + buttonTitle, + style: kLargeButtonTextStyle, + ), + ), + color: kBottomContainerColour, + margin: EdgeInsets.only(top: 10.0), + padding: EdgeInsets.only(bottom: 20.0), + width: double.infinity, + height: kBottomContainerHeight, + ), + ); + } +} diff --git a/lib/components/icon_content.dart b/lib/components/icon_content.dart new file mode 100644 index 0000000..474bda6 --- /dev/null +++ b/lib/components/icon_content.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import 'package:bmi_calculator/constants.dart'; + +class IconContent extends StatelessWidget { + IconContent({this.icon, this.label}); + + final IconData icon; + final String label; + + @override + Widget build(BuildContext context) { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + icon, + size: 80.0, + ), + SizedBox( + height: 15.0, + ), + Text( + label, + style: kLabelTextStyle, + ) + ], + ); + } +} diff --git a/lib/components/reusable_card.dart b/lib/components/reusable_card.dart new file mode 100644 index 0000000..c5d65de --- /dev/null +++ b/lib/components/reusable_card.dart @@ -0,0 +1,24 @@ +import 'package:flutter/material.dart'; + +class ReusableCard extends StatelessWidget { + ReusableCard({@required this.colour, this.cardChild, this.onPress}); + + final Color colour; + final Widget cardChild; + final Function onPress; + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: onPress, + child: Container( + child: cardChild, + margin: EdgeInsets.all(15.0), + decoration: BoxDecoration( + color: colour, + borderRadius: BorderRadius.circular(10.0), + ), + ), + ); + } +} diff --git a/lib/components/round_icon_button.dart b/lib/components/round_icon_button.dart new file mode 100644 index 0000000..966bca5 --- /dev/null +++ b/lib/components/round_icon_button.dart @@ -0,0 +1,23 @@ +import 'package:flutter/material.dart'; + +class RoundIconButton extends StatelessWidget { + RoundIconButton({@required this.icon, @required this.onPressed}); + + final IconData icon; + final Function onPressed; + + @override + Widget build(BuildContext context) { + return RawMaterialButton( + elevation: 0.0, + child: Icon(icon), + onPressed: onPressed, + constraints: BoxConstraints.tightFor( + width: 56.0, + height: 56.0, + ), + shape: CircleBorder(), + fillColor: Color(0xFF4C4F5E), + ); + } +} diff --git a/lib/constants.dart b/lib/constants.dart new file mode 100644 index 0000000..8ea4ec1 --- /dev/null +++ b/lib/constants.dart @@ -0,0 +1,41 @@ +import 'package:flutter/material.dart'; + +const kBottomContainerHeight = 80.0; +const kActiveCardColour = Color(0xFF1D1E33); +const kInactiveCardColour = Color(0xFF111328); +const kBottomContainerColour = Color(0xFFEB1555); + +const kLabelTextStyle = TextStyle( + fontSize: 18.0, + color: Color(0xFF8D8E98), +); + +const kNumberTextStyle = TextStyle( + fontSize: 50.0, + fontWeight: FontWeight.w900, +); + +const kLargeButtonTextStyle = TextStyle( + fontSize: 25.0, + fontWeight: FontWeight.bold, +); + +const kTitleTextStyle = TextStyle( + fontSize: 50.0, + fontWeight: FontWeight.bold, +); + +const kResultTextStyle = TextStyle( + color: Color(0xFF24D876), + fontSize: 22.0, + fontWeight: FontWeight.bold, +); + +const kBMITextStyle = TextStyle( + fontSize: 100.0, + fontWeight: FontWeight.bold, +); + +const kBodyTextStyle = TextStyle( + fontSize: 22.0, +); diff --git a/lib/main.dart b/lib/main.dart index 78f51b1..2d04eb6 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:bmi_calculator/screens/input_page.dart'; void main() => runApp(BMICalculator()); @@ -6,29 +7,11 @@ class BMICalculator extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( - home: InputPage(), - ); - } -} - -class InputPage extends StatefulWidget { - @override - _InputPageState createState() => _InputPageState(); -} - -class _InputPageState extends State { - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text('BMI CALCULATOR'), - ), - body: Center( - child: Text('Body Text'), - ), - floatingActionButton: FloatingActionButton( - child: Icon(Icons.add), + theme: ThemeData.dark().copyWith( + primaryColor: Color(0xFF0A0E21), + scaffoldBackgroundColor: Color(0xFF0A0E21), ), + home: InputPage(), ); } } diff --git a/lib/screens/input_page.dart b/lib/screens/input_page.dart new file mode 100644 index 0000000..d3da204 --- /dev/null +++ b/lib/screens/input_page.dart @@ -0,0 +1,236 @@ +import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:bmi_calculator/components/icon_content.dart'; +import 'package:bmi_calculator/components/reusable_card.dart'; +import 'package:bmi_calculator/constants.dart'; +import 'package:bmi_calculator/screens/results_page.dart'; +import 'package:bmi_calculator/components/bottom_button.dart'; +import 'package:bmi_calculator/components/round_icon_button.dart'; +import 'package:bmi_calculator/calculator_brain.dart'; + +enum Gender { + male, + female, +} + +class InputPage extends StatefulWidget { + @override + _InputPageState createState() => _InputPageState(); +} + +class _InputPageState extends State { + Gender selectedGender; + int height = 180; + int weight = 60; + int age = 20; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('BMI CALCULATOR'), + ), + body: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Expanded( + child: Row( + children: [ + Expanded( + child: ReusableCard( + onPress: () { + setState(() { + selectedGender = Gender.male; + }); + }, + colour: selectedGender == Gender.male + ? kActiveCardColour + : kInactiveCardColour, + cardChild: IconContent( + icon: FontAwesomeIcons.mars, + label: 'MALE', + ), + ), + ), + Expanded( + child: ReusableCard( + onPress: () { + setState(() { + selectedGender = Gender.female; + }); + }, + colour: selectedGender == Gender.female + ? kActiveCardColour + : kInactiveCardColour, + cardChild: IconContent( + icon: FontAwesomeIcons.venus, + label: 'FEMALE', + ), + ), + ), + ], + )), + Expanded( + child: ReusableCard( + colour: kActiveCardColour, + cardChild: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'HEIGHT', + style: kLabelTextStyle, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.baseline, + textBaseline: TextBaseline.alphabetic, + children: [ + Text( + height.toString(), + style: kNumberTextStyle, + ), + Text( + 'cm', + style: kLabelTextStyle, + ) + ], + ), + SliderTheme( + data: SliderTheme.of(context).copyWith( + inactiveTrackColor: Color(0xFF8D8E98), + activeTrackColor: Colors.white, + thumbColor: Color(0xFFEB1555), + overlayColor: Color(0x29EB1555), + thumbShape: + RoundSliderThumbShape(enabledThumbRadius: 15.0), + overlayShape: + RoundSliderOverlayShape(overlayRadius: 30.0), + ), + child: Slider( + value: height.toDouble(), + min: 120.0, + max: 220.0, + onChanged: (double newValue) { + setState(() { + height = newValue.round(); + }); + }, + ), + ), + ], + ), + ), + ), + Expanded( + child: Row( + children: [ + Expanded( + child: ReusableCard( + colour: kActiveCardColour, + cardChild: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'WEIGHT', + style: kLabelTextStyle, + ), + Text( + weight.toString(), + style: kNumberTextStyle, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + RoundIconButton( + icon: FontAwesomeIcons.minus, + onPressed: () { + setState(() { + weight--; + }); + }), + SizedBox( + width: 10.0, + ), + RoundIconButton( + icon: FontAwesomeIcons.plus, + onPressed: () { + setState(() { + weight++; + }); + }, + ), + ], + ), + ], + ), + ), + ), + Expanded( + child: ReusableCard( + colour: kActiveCardColour, + cardChild: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'AGE', + style: kLabelTextStyle, + ), + Text( + age.toString(), + style: kNumberTextStyle, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + RoundIconButton( + icon: FontAwesomeIcons.minus, + onPressed: () { + setState( + () { + age--; + }, + ); + }, + ), + SizedBox( + width: 10.0, + ), + RoundIconButton( + icon: FontAwesomeIcons.plus, + onPressed: () { + setState(() { + age++; + }); + }) + ], + ) + ], + ), + ), + ), + ], + ), + ), + BottomButton( + buttonTitle: 'CALCULATE', + onTap: () { + CalculatorBrain calc = + CalculatorBrain(height: height, weight: weight); + + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ResultsPage( + bmiResult: calc.calculateBMI(), + resultText: calc.getResult(), + interpretation: calc.getInterpretation(), + ), + ), + ); + }, + ), + ], + ), + ); + } +} diff --git a/lib/screens/results_page.dart b/lib/screens/results_page.dart new file mode 100644 index 0000000..5fe5239 --- /dev/null +++ b/lib/screens/results_page.dart @@ -0,0 +1,71 @@ +import 'package:flutter/material.dart'; +import 'package:bmi_calculator/constants.dart'; +import 'package:bmi_calculator/components/reusable_card.dart'; +import 'package:bmi_calculator/components/bottom_button.dart'; + +class ResultsPage extends StatelessWidget { + ResultsPage( + {@required this.interpretation, + @required this.bmiResult, + @required this.resultText}); + + final String bmiResult; + final String resultText; + final String interpretation; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('BMI CALCULATOR'), + ), + body: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Expanded( + child: Container( + padding: EdgeInsets.all(15.0), + alignment: Alignment.bottomLeft, + child: Text( + 'Your Result', + style: kTitleTextStyle, + ), + ), + ), + Expanded( + flex: 5, + child: ReusableCard( + colour: kActiveCardColour, + cardChild: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + resultText.toUpperCase(), + style: kResultTextStyle, + ), + Text( + bmiResult, + style: kBMITextStyle, + ), + Text( + interpretation, + textAlign: TextAlign.center, + style: kBodyTextStyle, + ), + ], + ), + ), + ), + BottomButton( + buttonTitle: 'RE-CALCULATE', + onTap: () { + Navigator.pop(context); + }, + ) + ], + ), + ); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index a0e1d3c..e24dc38 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,6 +11,7 @@ dependencies: sdk: flutter cupertino_icons: ^0.1.2 + font_awesome_flutter: ^8.4.0 dev_dependencies: flutter_test: