finished
parent
3a3b7841a6
commit
13d3a48d06
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
|
||||||
|
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||||
|
<!-- Show a splash screen on the activity. Automatically removed when
|
||||||
|
the Flutter engine draws its first frame -->
|
||||||
|
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||||
|
</style>
|
||||||
|
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||||
|
This theme determines the color of the Android Window while your
|
||||||
|
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||||
|
running.
|
||||||
|
|
||||||
|
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||||
|
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||||
|
<item name="android:windowBackground">?android:colorBackground</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
|
@ -1,4 +1,4 @@
|
||||||
import 'package:cpd_2022_energy/widgets/input_card_widget.dart';
|
import 'package:cpd_2022_energy/widgets/input_widget.dart';
|
||||||
import 'package:cpd_2022_energy/widgets/output_card_widget.dart';
|
import 'package:cpd_2022_energy/widgets/output_card_widget.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
@ -36,7 +36,7 @@ class EnergyCalculation extends StatelessWidget {
|
||||||
create: (context) => EnergyModel(),
|
create: (context) => EnergyModel(),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: const [
|
children: const [
|
||||||
InputCardWidget(),
|
InputWidget(),
|
||||||
OutputCardWidget(),
|
OutputCardWidget(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,18 +1,64 @@
|
||||||
import 'package:cpd_2022_energy/widgets/input_card_widget.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class EnergyModel with ChangeNotifier {
|
class EnergyModel with ChangeNotifier {
|
||||||
|
final double weightForce = 9.81;
|
||||||
|
final double _waterStartTemp = 20.0;
|
||||||
|
final double _waterEndTemp = 100.0;
|
||||||
|
final double _waterHeatCapacity = 4.183;
|
||||||
|
final double _ironStartTemp = 20.0;
|
||||||
|
final double _ironEndTemp = 700.0;
|
||||||
|
final double _ironHeatCapacity = 0.444;
|
||||||
|
|
||||||
|
double heightStart = 0.0;
|
||||||
|
double heightEnd = 0.0;
|
||||||
|
double velocityStart = 0.0;
|
||||||
|
double velocityEnd = 0.0;
|
||||||
|
double weight = 0.0;
|
||||||
|
|
||||||
calculateJoule(InputCardWidget value) {
|
double totalEnergy = 0.0;
|
||||||
|
double boilingWaterAmount = 0.0;
|
||||||
|
double annealingIronAmount = 0.0;
|
||||||
|
|
||||||
|
double calcPotentialEnergy(m, g, h) {
|
||||||
|
return m * g * h;
|
||||||
}
|
}
|
||||||
|
|
||||||
calculateBoiledWater() {
|
double calcPotentialEnergyBetweenTwoPointsInJoule(
|
||||||
|
heightStart, heightEnd, weight) {
|
||||||
|
return calcPotentialEnergy(weight, weightForce, heightStart) -
|
||||||
|
calcPotentialEnergy(weight, weightForce, heightEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
calculateGlowedIron() {
|
double calcKineticEnergy(m, v) {
|
||||||
|
return (m * v * v) / 2.0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
double calcKineticEnergyBetweenTwoPointsInJoule(
|
||||||
|
velocityStart, velocityEnd, weight) {
|
||||||
|
return calcKineticEnergy(weight, velocityEnd) -
|
||||||
|
calcKineticEnergy(weight, velocityStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
void calcBoilingWaterAmount() {
|
||||||
|
boilingWaterAmount = (totalEnergy /
|
||||||
|
(_waterHeatCapacity * (_waterEndTemp - _waterStartTemp)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void calcIronAnnealingAmount() {
|
||||||
|
annealingIronAmount =
|
||||||
|
(totalEnergy / (_ironHeatCapacity * (_ironEndTemp - _ironStartTemp)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void calcTotalEnergyInKiloJoule() {
|
||||||
|
totalEnergy = (calcKineticEnergyBetweenTwoPointsInJoule(velocityStart, velocityEnd, weight) +
|
||||||
|
calcPotentialEnergyBetweenTwoPointsInJoule(heightStart, heightEnd, weight))
|
||||||
|
/1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
void calc() {
|
||||||
|
calcTotalEnergyInKiloJoule();
|
||||||
|
calcBoilingWaterAmount();
|
||||||
|
calcIronAnnealingAmount();
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class HeightWidget extends StatelessWidget {
|
|
||||||
const HeightWidget({super.key});
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
|
|
||||||
return Form(
|
|
||||||
child: Column(
|
|
||||||
children: <Widget>[
|
|
||||||
const Text('Height'),
|
|
||||||
TextFormField(
|
|
||||||
decoration: const InputDecoration(
|
|
||||||
hintText: 'Enter the height of the starting point (in m)',
|
|
||||||
),
|
|
||||||
validator: (String? value) {
|
|
||||||
if (value == null || value.isEmpty) {
|
|
||||||
return 'Invalid input. Please enter the height of the starting point (in m)';
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
|
|
||||||
TextFormField(
|
|
||||||
decoration: const InputDecoration(
|
|
||||||
hintText: 'Enter the height of the ending point (in m)',
|
|
||||||
),
|
|
||||||
validator: (String? value) {
|
|
||||||
if (value == null || value.isEmpty) {
|
|
||||||
return 'Invalid input. Please enter the height of the ending point (in m)';
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
import 'package:cpd_2022_energy/widgets/submit_button_widget.dart';
|
|
||||||
import 'package:cpd_2022_energy/widgets/velocity_widget.dart';
|
|
||||||
import 'package:cpd_2022_energy/widgets/weight_widget.dart';
|
|
||||||
import 'package:cpd_2022_energy/widgets/height_widget.dart';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class InputCardWidget extends StatelessWidget {
|
|
||||||
const InputCardWidget({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Card(
|
|
||||||
child: Column(children: <Widget>[
|
|
||||||
Form(
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
VelocityWidget(),
|
|
||||||
HeightWidget(),
|
|
||||||
WeightWidget(),
|
|
||||||
SubmitButtonWidget(),
|
|
||||||
],
|
|
||||||
))
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
import 'package:cpd_2022_energy/provider/energy_model.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class InputWidget extends StatelessWidget {
|
||||||
|
const InputWidget({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
var heightStartInputController = TextEditingController();
|
||||||
|
var heightEndInputController = TextEditingController();
|
||||||
|
var velocityStartInputController = TextEditingController();
|
||||||
|
var velocityEndInputController = TextEditingController();
|
||||||
|
var weightInputController = TextEditingController();
|
||||||
|
|
||||||
|
final ButtonStyle style =
|
||||||
|
ElevatedButton.styleFrom(textStyle: const TextStyle(fontSize: 20));
|
||||||
|
final formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
|
final energyModel = Provider.of<EnergyModel>(context, listen: false);
|
||||||
|
|
||||||
|
void onSubmitButtonClick() {
|
||||||
|
if (formKey.currentState!.validate() == false) return;
|
||||||
|
|
||||||
|
energyModel.heightStart = double.parse(heightStartInputController.text);
|
||||||
|
energyModel.heightEnd = double.parse(heightEndInputController.text);
|
||||||
|
energyModel.velocityStart = double.parse(velocityStartInputController.text);
|
||||||
|
energyModel.velocityEnd = double.parse(velocityEndInputController.text);
|
||||||
|
energyModel.weight = double.parse(weightInputController.text);
|
||||||
|
energyModel.calc();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isNumeric(String s) {
|
||||||
|
return double.tryParse(s) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Form(
|
||||||
|
key: formKey,
|
||||||
|
child: Column(
|
||||||
|
children: <Widget>[
|
||||||
|
const Text('Height'),
|
||||||
|
TextFormField(
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
hintText: 'Enter the height of the starting point (in m)',
|
||||||
|
),
|
||||||
|
validator: (String? value) {
|
||||||
|
if (value == null || value.isEmpty || !isNumeric(value)) {
|
||||||
|
return 'Invalid input. Please enter the height of the starting point (in m)';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
controller: heightStartInputController,
|
||||||
|
),
|
||||||
|
TextFormField(
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
hintText: 'Enter the height of the ending point (in m)',
|
||||||
|
),
|
||||||
|
validator: (String? value) {
|
||||||
|
if (value == null || value.isEmpty || !isNumeric(value)) {
|
||||||
|
return 'Invalid input. Please enter the height of the ending point (in m)';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
controller: heightEndInputController,
|
||||||
|
),
|
||||||
|
const Text('Velocity'),
|
||||||
|
TextFormField(
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
hintText: 'Enter the velocity of the starting point (in s)',
|
||||||
|
),
|
||||||
|
validator: (String? value) {
|
||||||
|
if (value == null || value.isEmpty || !isNumeric(value)) {
|
||||||
|
return 'Invalid input. Please enter the velocity of the starting point (in s)';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
controller: velocityStartInputController,
|
||||||
|
),
|
||||||
|
TextFormField(
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
hintText: 'Enter the velocity of the ending point (in s)',
|
||||||
|
),
|
||||||
|
validator: (String? value) {
|
||||||
|
if (value == null || value.isEmpty || !isNumeric(value)) {
|
||||||
|
return 'Invalid input. Please enter the velocity of the ending point (in s)';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
controller: velocityEndInputController,
|
||||||
|
),
|
||||||
|
const Text('Weight'),
|
||||||
|
TextFormField(
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
hintText: 'Enter the weight in kg',
|
||||||
|
),
|
||||||
|
validator: (String? value) {
|
||||||
|
if (value == null || value.isEmpty || !isNumeric(value)) {
|
||||||
|
return 'Invalid input. Please enter the weight (in kg)';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
controller: weightInputController,
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
style: style,
|
||||||
|
onPressed: onSubmitButtonClick,
|
||||||
|
child: const Text('Calculate Energy'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,10 +9,10 @@ class OutputCardWidget extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Consumer<EnergyModel>(
|
return Consumer<EnergyModel>(
|
||||||
builder: (context, model, child) => Card(
|
builder: (context, model, child) => Card(
|
||||||
child: Column(children: const <Widget>[
|
child: Column(children: <Widget>[
|
||||||
Text('Joule:'),
|
Text("Energy in Kilo Joule: ${model.totalEnergy.toStringAsFixed(2)}"),
|
||||||
Text('Water:'),
|
Text('Water in Liter: ${model.boilingWaterAmount.toStringAsFixed(2)}'),
|
||||||
Text('Iron'),
|
Text('Iron in Kilogram: ${model.annealingIronAmount.toStringAsFixed(2)}'),
|
||||||
])));
|
])));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
import 'input_card_widget.dart';
|
|
||||||
|
|
||||||
class SubmitButtonWidget extends StatelessWidget {
|
|
||||||
const SubmitButtonWidget({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final ButtonStyle style =
|
|
||||||
ElevatedButton.styleFrom(textStyle: const TextStyle(fontSize: 20));
|
|
||||||
|
|
||||||
return Center(
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
ElevatedButton(
|
|
||||||
style: style,
|
|
||||||
onPressed: () {},
|
|
||||||
child: const Text('Calculate Energy'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class VelocityWidget extends StatelessWidget {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Form(
|
|
||||||
child: Column(
|
|
||||||
children: <Widget>[
|
|
||||||
const Text('Velocity'),
|
|
||||||
TextFormField(
|
|
||||||
decoration: const InputDecoration(
|
|
||||||
hintText: 'Enter the velocity of the starting point (in s)',
|
|
||||||
),
|
|
||||||
validator: (String? value) {
|
|
||||||
if (value == null || value.isEmpty) {
|
|
||||||
return 'Invalid input. Please enter the velocity of the starting point (in s)';
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
TextFormField(
|
|
||||||
decoration: const InputDecoration(
|
|
||||||
hintText: 'Enter the velocity of the ending point (in s)',
|
|
||||||
),
|
|
||||||
validator: (String? value) {
|
|
||||||
if (value == null || value.isEmpty) {
|
|
||||||
return 'Invalid input. Please enter the velocity of the ending point (in s)';
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class WeightWidget extends StatelessWidget {
|
|
||||||
const WeightWidget({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Form(
|
|
||||||
child: Column(
|
|
||||||
children: <Widget>[
|
|
||||||
const Text('Weight'),
|
|
||||||
TextFormField(
|
|
||||||
decoration: const InputDecoration(
|
|
||||||
hintText: 'Enter the weight in kg',
|
|
||||||
),
|
|
||||||
validator: (String? value) {
|
|
||||||
if (value == null || value.isEmpty) {
|
|
||||||
return 'Invalid input. Please enter the weight (in kg)';
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,30 +1,55 @@
|
||||||
// This is a basic Flutter widget test.
|
import 'package:cpd_2022_energy/provider/energy_model.dart';
|
||||||
//
|
|
||||||
// To perform an interaction with a widget in your test, use the WidgetTester
|
|
||||||
// utility in the flutter_test package. For example, you can send tap and scroll
|
|
||||||
// gestures. You can also use WidgetTester to find child widgets in the widget
|
|
||||||
// tree, read text, and verify that the values of widget properties are correct.
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
import 'package:cpd_2022_energy/energy_app.dart';
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
EnergyModel model = EnergyModel();
|
||||||
// Build our app and trigger a frame.
|
|
||||||
await tester.pumpWidget(const EnergyCalculationApp());
|
|
||||||
|
|
||||||
// Verify that our counter starts at 0.
|
const double heightStart = 50.0;
|
||||||
expect(find.text('0'), findsOneWidget);
|
const double heightEnd = 10.0;
|
||||||
expect(find.text('1'), findsNothing);
|
const double velocityStart = 0.0;
|
||||||
|
const double velocityEnd = 40.0;
|
||||||
|
const double weight = 777.0;
|
||||||
|
|
||||||
// Tap the '+' icon and trigger a frame.
|
group('Test Energy Model', () {
|
||||||
await tester.tap(find.byIcon(Icons.add));
|
test('Set Values', () {
|
||||||
await tester.pump();
|
model.heightStart = heightStart;
|
||||||
|
model.heightEnd = heightEnd;
|
||||||
|
model.velocityStart = velocityStart;
|
||||||
|
model.velocityEnd = velocityEnd;
|
||||||
|
model.weight = weight;
|
||||||
|
expect(heightStart, model.heightStart);
|
||||||
|
expect(heightEnd, model.heightEnd);
|
||||||
|
expect(velocityStart, model.velocityStart);
|
||||||
|
expect(velocityEnd, model.velocityEnd);
|
||||||
|
expect(weight, model.weight);
|
||||||
|
});
|
||||||
|
test('Calculate Potential Energy', () {
|
||||||
|
expect(double.parse(model.calcPotentialEnergy(model.weight, model.weightForce, model.heightStart).toStringAsFixed(2)), 381118.5);
|
||||||
|
expect(double.parse(model.calcPotentialEnergy(model.weight, model.weightForce, model.heightEnd).toStringAsFixed(2)), 76223.70);
|
||||||
|
});
|
||||||
|
test('Calculate Potential Energy between two point in Joule', () {
|
||||||
|
expect(double.parse(model.calcPotentialEnergyBetweenTwoPointsInJoule(model.heightStart, model.heightEnd, model.weight).toStringAsFixed(2)), 304894.8);
|
||||||
|
});
|
||||||
|
test('Calculate Kinetic Energy', () {
|
||||||
|
expect(double.parse(model.calcKineticEnergy(model.weight, model.velocityStart).toStringAsFixed(2)), 0);
|
||||||
|
expect(double.parse(model.calcKineticEnergy(model.weight, model.velocityEnd).toStringAsFixed(2)), 621600.0);
|
||||||
|
});
|
||||||
|
test('Calculate Kinetic Energy between two points in Joule', () {
|
||||||
|
expect(double.parse(model.calcKineticEnergyBetweenTwoPointsInJoule(model.velocityStart, model.velocityEnd, model.weight).toStringAsFixed(2)), 621600.0);
|
||||||
|
});
|
||||||
|
test('Calculate total energy in Kilo Joule', () {
|
||||||
|
model.calcTotalEnergyInKiloJoule();
|
||||||
|
expect(double.parse(model.totalEnergy.toStringAsFixed(2)), 926.49);
|
||||||
|
});
|
||||||
|
test('Calculate amount of boiling water', () {
|
||||||
|
model.calcBoilingWaterAmount();
|
||||||
|
expect(double.parse(model.boilingWaterAmount.toStringAsFixed(2)), 2.77);
|
||||||
|
});
|
||||||
|
test('Calculate amount of annealing iron', () {
|
||||||
|
model.calcIronAnnealingAmount();
|
||||||
|
expect(double.parse(model.annealingIronAmount.toStringAsFixed(2)), 3.07);
|
||||||
|
|
||||||
// Verify that our counter has incremented.
|
});
|
||||||
expect(find.text('0'), findsNothing);
|
|
||||||
expect(find.text('1'), findsOneWidget);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue