Skip to content

Commit 36c8bed

Browse files
authored
BMI calculator example (#130)
1 parent f761e55 commit 36c8bed

19 files changed

+780
-0
lines changed

bmi_calculator/.gitignore

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
.DS_Store
2+
.dart_tool/
3+
4+
.vscode/
5+
6+
.packages
7+
.pub/
8+
9+
.idea/
10+
.vagrant/
11+
.sconsign.dblite
12+
.svn/
13+
14+
migrate_working_dir/
15+
16+
*.swp
17+
profile
18+
19+
DerivedData/
20+
21+
.generated/
22+
23+
*.pbxuser
24+
*.mode1v3
25+
*.mode2v3
26+
*.perspectivev3
27+
28+
!default.pbxuser
29+
!default.mode1v3
30+
!default.mode2v3
31+
!default.perspectivev3
32+
33+
xcuserdata
34+
35+
*.moved-aside
36+
37+
*.pyc
38+
*sync/
39+
Icon?
40+
.tags*
41+
42+
build/
43+
.android/
44+
.ios/
45+
.flutter-plugins
46+
.flutter-plugins-dependencies
47+
48+
# Symbolication related
49+
app.*.symbols
50+
51+
# Obfuscation related
52+
app.*.map.json

bmi_calculator/.metadata

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# This file tracks properties of this Flutter project.
2+
# Used by Flutter tool to assess capabilities and perform upgrades etc.
3+
#
4+
# This file should be version controlled and should not be manually edited.
5+
6+
version:
7+
revision: f1875d570e39de09040c8f79aa13cc56baab8db1
8+
channel: stable
9+
10+
project_type: module

bmi_calculator/README.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# bmi_calculator
2+
3+
A person’s Body-Mass Index, or BMI, helps them check whether they’re a healthy weight for their height. If a person weighs less or more than the recommended weight for their height, it could lead to health issues in the future. While BMI is not the only factor individuals should consider while working on their health and fitness, it is a good starting point. To understand what your BMI is, you need to know your height and weight. You can then use an online BMI calculator to check your BMI, which will help you understand if you’re underweight, a healthy weight, overweight or obese. Or, you can measure your height in metres and weight in kilograms. Divide your weight by your height squared to calculate your BMI.
4+
5+
BMI Calculator [Wiki](https://en.wikipedia.org/wiki/Body_mass_index)
6+
7+

bmi_calculator/analysis_options.yaml

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
include: package:flutter_lints/flutter.yaml
2+
3+
# Additional information about this file can be found at
4+
# https://dart.dev/guides/language/analysis-options
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import 'dart:math';
2+
3+
import 'package:bmi_calculator/body_model.dart';
4+
5+
// I've used weight/height^2 (kg/m^2)
6+
// You can expand this logic
7+
double calculateBMI({required BodyModel bodyModel}) {
8+
return (bodyModel.weight) / pow(bodyModel.height / 100, 2);
9+
}

bmi_calculator/lib/body_model.dart

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
enum Sex {
2+
male,
3+
female,
4+
}
5+
6+
// User body model class
7+
class BodyModel {
8+
Sex sex;
9+
int height;
10+
int weight;
11+
int age;
12+
13+
BodyModel({
14+
required this.sex,
15+
required this.height,
16+
required this.weight,
17+
required this.age,
18+
});
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import 'package:flutter/material.dart';
2+
3+
import '../palette.dart';
4+
5+
class CalculateButton extends StatelessWidget {
6+
const CalculateButton({
7+
super.key,
8+
required this.onTap,
9+
});
10+
11+
final VoidCallback onTap;
12+
13+
@override
14+
Widget build(BuildContext context) {
15+
return Container(
16+
height: MediaQuery.of(context).size.height / 12,
17+
width: double.infinity,
18+
decoration: BoxDecoration(
19+
borderRadius: BorderRadius.circular(5),
20+
color: Palette.action,
21+
),
22+
child: TextButton(
23+
style: ButtonStyle(
24+
overlayColor:
25+
MaterialStateProperty.all(Colors.white.withOpacity(0.10)),
26+
),
27+
onPressed: onTap,
28+
child: const Text(
29+
'CALCULATE YOUR BMI',
30+
style: TextStyle(
31+
color: Palette.textActive,
32+
fontSize: 20,
33+
),
34+
),
35+
),
36+
);
37+
}
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import 'package:bmi_calculator/calculator/calculate_button.dart';
2+
import 'package:flutter/material.dart';
3+
import 'package:bmi_calculator/calculator/height_widget.dart';
4+
import 'package:bmi_calculator/calculator/int_picker_widget.dart';
5+
import 'package:bmi_calculator/calculator/sex_widget.dart';
6+
import 'package:bmi_calculator/result/result_page.dart';
7+
import 'package:bmi_calculator/body_model.dart';
8+
import 'package:bmi_calculator/palette.dart';
9+
10+
class CalculatorBody extends StatefulWidget {
11+
const CalculatorBody({
12+
super.key,
13+
required this.model,
14+
});
15+
16+
final BodyModel model;
17+
18+
@override
19+
State<CalculatorBody> createState() => _CalculatorBodyState();
20+
}
21+
22+
class _CalculatorBodyState extends State<CalculatorBody> {
23+
@override
24+
Widget build(BuildContext context) {
25+
return Container(
26+
color: Palette.background,
27+
child: Padding(
28+
padding: const EdgeInsets.symmetric(horizontal: 24.0),
29+
child: Column(
30+
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
31+
children: [
32+
SexWidget(
33+
sex: widget.model.sex,
34+
onMaleTap: () => setState(() {
35+
// Set sex to male
36+
widget.model.sex = Sex.male;
37+
}),
38+
onFemaleTap: () => setState(() {
39+
// Set sex to female
40+
widget.model.sex = Sex.female;
41+
})),
42+
HeightWidget(
43+
height: widget.model.height,
44+
onHeightChanged: (height) => setState(() {
45+
// Set height and round to Int
46+
widget.model.height = height.toInt();
47+
}),
48+
),
49+
SizedBox(
50+
height: (MediaQuery.of(context).size.width - 48) / 2,
51+
child: Row(
52+
children: [
53+
Expanded(
54+
// Weight widget
55+
child: IntPickerWidget(
56+
title: 'Weight',
57+
onIncreaseTap: () => setState(() {
58+
// Increase weight
59+
widget.model.weight++;
60+
}),
61+
onDecreaseTap: () => setState(() {
62+
// Decrease weight
63+
widget.model.weight--;
64+
}),
65+
value: widget.model.weight,
66+
),
67+
),
68+
const SizedBox(
69+
width: 5,
70+
),
71+
Expanded(
72+
// Age widget
73+
child: IntPickerWidget(
74+
title: 'Age',
75+
onIncreaseTap: () => setState(() {
76+
// Increase age
77+
widget.model.age++;
78+
}),
79+
onDecreaseTap: () => setState(() {
80+
// Decrease age
81+
widget.model.age--;
82+
}),
83+
value: widget.model.age,
84+
),
85+
)
86+
],
87+
),
88+
),
89+
CalculateButton(
90+
onTap: () {
91+
// Navigate to Result Page
92+
Navigator.push(
93+
context,
94+
MaterialPageRoute(
95+
builder: ((context) => ResultPage(model: widget.model)),
96+
),
97+
);
98+
},
99+
),
100+
],
101+
),
102+
),
103+
);
104+
}
105+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import 'package:bmi_calculator/calculator/calculator_body.dart';
2+
import 'package:flutter/material.dart';
3+
import 'package:bmi_calculator/body_model.dart';
4+
import 'package:bmi_calculator/palette.dart';
5+
6+
class CalculatorPage extends StatelessWidget {
7+
CalculatorPage({
8+
Key? key,
9+
required this.title,
10+
}) : super(key: key);
11+
12+
final String title;
13+
14+
final BodyModel model = BodyModel(
15+
sex: Sex.male,
16+
height: 183,
17+
weight: 74,
18+
age: 19,
19+
);
20+
21+
@override
22+
Widget build(BuildContext context) {
23+
return Scaffold(
24+
appBar: AppBar(
25+
title: Text(title),
26+
backgroundColor: Palette.background,
27+
),
28+
body: CalculatorBody(model: model),
29+
);
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import 'package:flutter/material.dart';
2+
3+
import '../palette.dart';
4+
5+
class HeightWidget extends StatelessWidget {
6+
const HeightWidget({
7+
super.key,
8+
required this.height,
9+
required this.onHeightChanged,
10+
});
11+
12+
final int height;
13+
final Function(double) onHeightChanged;
14+
15+
@override
16+
Widget build(BuildContext context) {
17+
return Container(
18+
height: (MediaQuery.of(context).size.width - 48) / 2,
19+
width: double.infinity,
20+
decoration: BoxDecoration(
21+
borderRadius: BorderRadius.circular(5),
22+
color: Palette.cardBackgroundInactive,
23+
),
24+
child: Column(
25+
mainAxisAlignment: MainAxisAlignment.center,
26+
children: [
27+
const Text(
28+
'HEIGHT',
29+
style: TextStyle(
30+
fontSize: 23,
31+
fontWeight: FontWeight.w600,
32+
color: Palette.textInactive,
33+
),
34+
),
35+
Row(
36+
mainAxisAlignment: MainAxisAlignment.center,
37+
crossAxisAlignment: CrossAxisAlignment.baseline,
38+
textBaseline: TextBaseline.alphabetic,
39+
children: [
40+
Text(
41+
height.round().toString(),
42+
style: const TextStyle(
43+
fontSize: 50,
44+
fontWeight: FontWeight.w800,
45+
color: Palette.textActive,
46+
),
47+
),
48+
const Text(
49+
'cm',
50+
style: TextStyle(
51+
fontSize: 30,
52+
color: Palette.textInactive,
53+
),
54+
),
55+
],
56+
),
57+
Padding(
58+
padding: const EdgeInsets.symmetric(
59+
horizontal: 24.0,
60+
),
61+
child: SliderTheme(
62+
data: SliderTheme.of(context).copyWith(
63+
trackHeight: 1.0,
64+
thumbShape: const RoundSliderThumbShape(
65+
enabledThumbRadius: 15,
66+
),
67+
),
68+
child: Slider(
69+
value: height.toDouble(),
70+
min: 150.0,
71+
max: 210.0,
72+
activeColor: Palette.textActive,
73+
inactiveColor: Palette.textInactive,
74+
thumbColor: Palette.action,
75+
onChanged: onHeightChanged,
76+
),
77+
),
78+
),
79+
],
80+
),
81+
);
82+
}
83+
}

0 commit comments

Comments
 (0)