rename container folders

This commit is contained in:
2026-01-29 11:11:45 +02:00
parent d5349d981c
commit 5b052a1fa9
654 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,102 @@
import 'package:go_router/go_router.dart';
import 'package:mzansi_innovation_hub/mih_package_components/mih_package.dart';
import 'package:mzansi_innovation_hub/mih_package_components/mih_package_action.dart';
import 'package:mzansi_innovation_hub/mih_package_components/mih_package_tools.dart';
import 'package:mzansi_innovation_hub/mih_providers/mih_calculator_provider.dart';
import 'package:mzansi_innovation_hub/mih_packages/calculator/package_tools/currency_exchange_rate.dart';
import 'package:mzansi_innovation_hub/mih_packages/calculator/package_tools/simple_calc.dart';
import 'package:mzansi_innovation_hub/mih_packages/calculator/package_tools/tip_calc.dart';
import 'package:flutter/material.dart';
import 'package:mzansi_innovation_hub/mih_services/mih_currency_exchange_rate_services.dart';
import 'package:provider/provider.dart';
class MIHCalculator extends StatefulWidget {
const MIHCalculator({
super.key,
});
@override
State<MIHCalculator> createState() => _MIHCalculatorState();
}
class _MIHCalculatorState extends State<MIHCalculator> {
late final SimpleCalc _simpleCalc;
late final TipCalc _tipCalc;
late final CurrencyExchangeRate _currencyExchangeRate;
Future<void> getCurrencyCodeList() async {
await MihCurrencyExchangeRateServices.getCurrencyCodeList(context);
}
@override
void initState() {
super.initState();
_simpleCalc = SimpleCalc();
_tipCalc = TipCalc();
_currencyExchangeRate = CurrencyExchangeRate();
WidgetsBinding.instance.addPostFrameCallback((_) async {
await getCurrencyCodeList();
});
}
@override
Widget build(BuildContext context) {
return MihPackage(
appActionButton: getAction(),
appTools: getTools(),
appBody: getToolBody(),
appToolTitles: getToolTitle(),
selectedbodyIndex: context.watch<MihCalculatorProvider>().toolIndex,
onIndexChange: (newIndex) {
context.read<MihCalculatorProvider>().setToolIndex(newIndex);
},
);
}
MihPackageAction getAction() {
return MihPackageAction(
icon: const Icon(Icons.arrow_back),
iconSize: 35,
onTap: () {
context.goNamed(
'mihHome',
);
FocusScope.of(context).unfocus();
},
);
}
MihPackageTools getTools() {
Map<Widget, void Function()?> temp = {};
temp[const Icon(Icons.calculate)] = () {
context.read<MihCalculatorProvider>().setToolIndex(0);
};
temp[const Icon(Icons.money)] = () {
context.read<MihCalculatorProvider>().setToolIndex(1);
};
temp[const Icon(Icons.currency_exchange)] = () {
context.read<MihCalculatorProvider>().setToolIndex(2);
};
return MihPackageTools(
tools: temp,
selcetedIndex: context.watch<MihCalculatorProvider>().toolIndex,
);
}
List<Widget> getToolBody() {
return [
_simpleCalc,
_tipCalc,
_currencyExchangeRate,
];
}
List<String> getToolTitle() {
List<String> toolTitles = [
"Simple Calculator",
"Tip Calculator",
"Forex Calculator",
];
return toolTitles;
}
}

View File

@@ -0,0 +1,41 @@
import 'package:go_router/go_router.dart';
import 'package:mzansi_innovation_hub/main.dart';
import 'package:mzansi_innovation_hub/mih_package_components/mih_package_tile.dart';
import 'package:flutter/material.dart';
import 'package:mzansi_innovation_hub/mih_package_components/mih_icons.dart';
import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart';
class MihCalculatorTile extends StatefulWidget {
final double packageSize;
const MihCalculatorTile({
super.key,
required this.packageSize,
});
@override
State<MihCalculatorTile> createState() => _MihCalculatorTileState();
}
class _MihCalculatorTileState extends State<MihCalculatorTile> {
@override
Widget build(BuildContext context) {
return MihPackageTile(
onTap: () {
context.goNamed(
"mihCalculator",
);
},
appName: "Calculator",
appIcon: Icon(
MihIcons.calculator,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
// size: widget.packageSize,
),
iconSize: widget.packageSize,
textColor: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
);
}
}

View File

@@ -0,0 +1,443 @@
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:mzansi_innovation_hub/main.dart';
import 'package:mzansi_innovation_hub/mih_package_components/mih_banner_ad.dart';
import 'package:mzansi_innovation_hub/mih_package_components/mih_button.dart';
import 'package:mzansi_innovation_hub/mih_package_components/mih_dropdwn_field.dart';
import 'package:mzansi_innovation_hub/mih_package_components/mih_form.dart';
import 'package:mzansi_innovation_hub/mih_package_components/mih_package_tool_body.dart';
import 'package:mzansi_innovation_hub/mih_package_components/mih_package_window.dart';
import 'package:mzansi_innovation_hub/mih_package_components/mih_single_child_scroll.dart';
import 'package:mzansi_innovation_hub/mih_package_components/mih_text_form_field.dart';
import 'package:mzansi_innovation_hub/mih_providers/mih_calculator_provider.dart';
import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart';
import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart';
import 'package:mzansi_innovation_hub/mih_services/mih_currency_exchange_rate_services.dart';
import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart';
import 'package:provider/provider.dart';
class CurrencyExchangeRate extends StatefulWidget {
const CurrencyExchangeRate({super.key});
@override
State<CurrencyExchangeRate> createState() => _CurrencyExchangeRateState();
}
class _CurrencyExchangeRateState extends State<CurrencyExchangeRate> {
final _formKey = GlobalKey<FormState>();
final TextEditingController _fromCurrencyController = TextEditingController();
final TextEditingController _toCurrencyController = TextEditingController();
final TextEditingController _fromAmountController = TextEditingController();
final TextEditingController _toAmountController = TextEditingController();
Future<void> submitForm() async {
String fromCurrencyCode = _fromCurrencyController.text.split(" - ")[0];
String toCurrencyCode = _toCurrencyController.text.split(" - ")[0];
List<String> dateValue = [];
double exchangeRate = 0;
await MihCurrencyExchangeRateServices.getCurrencyExchangeValue(
fromCurrencyCode, toCurrencyCode)
.then((amount) {
dateValue = amount;
});
exchangeRate = double.parse(dateValue[1]);
double exchangeValue =
double.parse(_fromAmountController.text) * exchangeRate;
print(
"Date: ${dateValue[0]}\n${_fromAmountController.text} | $fromCurrencyCode\n$exchangeValue | $toCurrencyCode");
displayResult(dateValue[0], _fromAmountController.text, fromCurrencyCode,
exchangeValue, toCurrencyCode);
}
void clearInput() {
_fromCurrencyController.clear();
_fromAmountController.clear();
_toCurrencyController.clear();
_toAmountController.clear();
}
void displayResult(String date, String amount, String fromCurrencyCode,
double exchangeValue, String toCurrencyCode) {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => MihPackageWindow(
fullscreen: false,
windowTitle: "Calculation Results",
onWindowTapClose: () {
Navigator.pop(context);
},
windowBody: Column(
children: [
Icon(
Icons.currency_exchange,
size: 150,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
const SizedBox(height: 20),
FittedBox(
child: Text(
"Values as at $date",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
),
),
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Expanded(
child: Text(
amount,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
),
),
),
const SizedBox(width: 10),
Expanded(
child: Text(
fromCurrencyCode.toUpperCase(),
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
),
),
),
],
),
const Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Expanded(
child: Text(
exchangeValue.toStringAsFixed(2),
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
),
),
),
const SizedBox(width: 10),
Expanded(
child: Text(
toCurrencyCode.toUpperCase(),
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
),
),
),
],
),
SizedBox(height: 10),
Consumer(builder: (context, bannerAdDisplay, child) {
return MihBannerAd();
}),
],
),
),
);
}
void displayDisclaimer() {
final String companyName = 'Mzansi Innovation Hub';
showDialog(
barrierDismissible: false,
context: context,
builder: (context) => MihPackageWindow(
fullscreen: false,
windowTitle: "Disclaimer Notice",
onWindowTapClose: () {
Navigator.pop(context);
},
windowBody: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Main Title
Text(
'Disclaimer of Warranty and Limitation of Liability for Forex Calculator',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 25,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 24.0),
// First Paragraph - using RichText to bold "the Tool"
_buildRichText(
'The Forex Calculator feature ("',
'the Tool',
'") is provided on an "as is" and "as available" basis. It is an experimental feature and is intended solely for informational and illustrative purposes.',
),
const SizedBox(height: 16.0),
// Second Paragraph
Text(
'$companyName makes no representations or warranties of any kind, express or implied, as to the accuracy, completeness, reliability, or suitability of the information and calculations generated by the Tool. All exchange rates and results are estimates and are subject to change without notice.',
style: TextStyle(
fontSize: 15,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
fontWeight: FontWeight.normal,
),
),
const SizedBox(height: 16.0),
// Third Paragraph
Text(
'The information provided by the Tool should not be construed as financial, investment, trading, or any other form of advice. You should not make any financial decisions based solely on the output of this Tool. We expressly recommend that you seek independent professional advice and verify all data with a qualified financial advisor and/or through alternative, reliable market data sources before executing any foreign exchange transactions.',
style: TextStyle(
fontSize: 15,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
fontWeight: FontWeight.normal,
),
),
const SizedBox(height: 16.0),
// Fourth Paragraph
Text(
'By using the Tool, you agree that $companyName, its affiliates, directors, and employees shall not be held liable for any direct, indirect, incidental, special, consequential, or exemplary damages, including but not limited to, damages for loss of profits, goodwill, use, data, or other intangible losses, resulting from: (i) the use or the inability to use the Tool; (ii) any inaccuracies, errors, or omissions in the Tool\'s calculations or data; or (iii) any reliance placed by you on the information provided by the Tool.',
style: TextStyle(
fontSize: 15,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
fontWeight: FontWeight.normal,
),
),
],
),
),
);
}
Widget _buildRichText(String start, String bold, String end) {
return RichText(
text: TextSpan(
style: TextStyle(
fontSize: 15,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
fontWeight: FontWeight.normal,
),
children: <TextSpan>[
TextSpan(text: start),
TextSpan(
text: bold, style: const TextStyle(fontWeight: FontWeight.bold)),
TextSpan(text: end),
],
),
);
}
@override
void dispose() {
super.dispose();
_fromCurrencyController.dispose();
_fromAmountController.dispose();
_toCurrencyController.dispose();
_toAmountController.dispose();
}
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
double screenWidth = MediaQuery.of(context).size.width;
return MihPackageToolBody(
borderOn: false,
innerHorizontalPadding: 10,
bodyItem: getBody(screenWidth),
);
}
Widget getBody(double width) {
return Consumer<MihCalculatorProvider>(
builder: (context, calculatorProvider, child) {
return MihSingleChildScroll(
child: Padding(
padding:
MzansiInnovationHub.of(context)!.theme.screenType == "desktop"
? EdgeInsets.symmetric(horizontal: width * 0.2)
: EdgeInsets.symmetric(horizontal: width * 0.075),
child: Column(
children: [
MihForm(
formKey: _formKey,
formFields: <Widget>[
MihTextFormField(
fillColor: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
inputColor: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
controller: _fromAmountController,
multiLineInput: false,
requiredText: true,
hintText: "Currency Amount",
numberMode: true,
validator: (value) {
return MihValidationServices().isEmpty(value);
},
),
const SizedBox(height: 10),
MihDropdownField(
controller: _fromCurrencyController,
hintText: "From",
dropdownOptions: calculatorProvider.availableCurrencies,
editable: true,
enableSearch: true,
validator: (value) {
return MihValidationServices().isEmpty(value);
},
requiredText: true,
),
const SizedBox(height: 10),
MihDropdownField(
controller: _toCurrencyController,
hintText: "To",
dropdownOptions: calculatorProvider.availableCurrencies,
editable: true,
enableSearch: true,
validator: (value) {
return MihValidationServices().isEmpty(value);
},
requiredText: true,
),
const SizedBox(height: 15),
RichText(
textAlign: TextAlign.left,
text: TextSpan(
style: TextStyle(
fontSize: 15,
color: MihColors.getRedColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
),
children: [
const TextSpan(
text: "* Experimental Feature: Please review "),
TextSpan(
text: "Diclaimer",
style: TextStyle(
decoration: TextDecoration.underline,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
fontWeight: FontWeight.bold,
),
recognizer: TapGestureRecognizer()
..onTap = () {
displayDisclaimer();
},
),
const TextSpan(text: " before use."),
],
),
),
const SizedBox(height: 25),
Center(
child: Wrap(
runAlignment: WrapAlignment.center,
crossAxisAlignment: WrapCrossAlignment.center,
alignment: WrapAlignment.center,
spacing: 10,
runSpacing: 10,
children: [
MihButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
submitForm();
FocusScope.of(context)
.requestFocus(FocusNode());
} else {
MihAlertServices().inputErrorAlert(context);
}
},
buttonColor: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
width: 300,
child: Text(
"Calculate",
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!
.theme
.mode ==
"Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
MihButton(
onPressed: () {
clearInput();
},
buttonColor: MihColors.getRedColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
width: 300,
child: Text(
"Clear",
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!
.theme
.mode ==
"Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
],
),
),
],
),
],
),
),
);
},
);
}
}

View File

@@ -0,0 +1,384 @@
import 'package:mzansi_innovation_hub/main.dart';
import 'package:mzansi_innovation_hub/mih_package_components/mih_single_child_scroll.dart';
import 'package:mzansi_innovation_hub/mih_package_components/mih_button.dart';
import 'package:mzansi_innovation_hub/mih_package_components/mih_package_tool_body.dart';
import 'package:flutter/material.dart';
import 'package:math_expressions/math_expressions.dart';
import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart';
class SimpleCalc extends StatefulWidget {
const SimpleCalc({super.key});
@override
State<SimpleCalc> createState() => _SimpleCalcState();
}
class _SimpleCalcState extends State<SimpleCalc> {
var userInput = '';
var answer = '0';
// Array of button
final List<String> buttons = [
'AC',
'(',
')',
'÷',
'7',
'8',
'9',
'x',
'4',
'5',
'6',
'-',
'1',
'2',
'3',
'+',
'0',
'.',
'D',
'=',
];
// function to calculate the input operation
void equalPressed() {
String finaluserinput = userInput;
finaluserinput = finaluserinput.replaceAll('x', '*');
finaluserinput = finaluserinput.replaceAll('÷', '/');
print(finaluserinput);
Parser p = Parser();
Expression exp = p.parse(finaluserinput);
ContextModel cm = ContextModel();
double eval = exp.evaluate(EvaluationType.REAL, cm);
if (eval.toString().length <= 1) {
} else if (eval
.toString()
.substring(eval.toString().length - 2, eval.toString().length) ==
".0") {
answer = eval.toString().substring(0, eval.toString().length - 2);
} else {
answer = eval.toString();
}
}
bool isNumeric(String? s) {
if (s == null) {
return false;
}
return double.tryParse(s) != null;
}
@override
Widget build(BuildContext context) {
return MihPackageToolBody(
borderOn: false,
innerHorizontalPadding: 10,
bodyItem: getBody(),
);
}
Widget getBody() {
// double width = MediaQuery.sizeOf(context).width;
double height = MediaQuery.sizeOf(context).height;
// var padding = MediaQuery.paddingOf(context);
// double newheight = height - padding.top - padding.bottom;
// print("width: $width");
// print("height: $height");
// print("newheight: $newheight");
double calcWidth = 500;
if (MzansiInnovationHub.of(context)!.theme.screenType == "desktop") {
if (height < 700) {
calcWidth = 300;
}
}
return MihSingleChildScroll(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
padding: const EdgeInsets.all(20),
alignment: Alignment.centerRight,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
reverse: true,
child: Text(
userInput,
style: TextStyle(
fontSize: 40,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
),
),
),
Container(
width: double.infinity,
//color: Colors.white,
padding: const EdgeInsets.all(15),
alignment: Alignment.centerRight,
child: Text(
answer,
style: TextStyle(
fontSize: 30,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
fontWeight: FontWeight.bold),
),
),
Container(
alignment: Alignment.centerRight,
child: SizedBox(
width: calcWidth,
child: GridView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
// padding: EdgeInsets.only(
// left: width / 10,
// right: width / 10,
// bottom: height / 15,
// //top: 20,
// ),
// shrinkWrap: true,
itemCount: buttons.length,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
//mainAxisExtent: 150,
),
itemBuilder: (context, index) {
// Clear Button
if (index == 0) {
return Padding(
padding: const EdgeInsets.all(4.0),
child: MihButton(
onPressed: () {
setState(() {
userInput = '';
answer = '0';
});
},
buttonColor: MihColors.getPurpleColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
width: 50,
height: 50,
borderRadius: 5,
child: Text(
buttons[index],
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
);
}
// ( button
else if (index == 1) {
return Padding(
padding: const EdgeInsets.all(4.0),
child: MihButton(
onPressed: () {
setState(() {
userInput += buttons[index];
});
},
buttonColor: MihColors.getGreyColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
width: 50,
height: 50,
borderRadius: 5,
child: Text(
buttons[index],
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
);
}
// ) Button
else if (index == 2) {
return Padding(
padding: const EdgeInsets.all(4.0),
child: MihButton(
onPressed: () {
setState(() {
userInput += buttons[index];
});
},
buttonColor: MihColors.getGreyColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
width: 50,
height: 50,
borderRadius: 5,
child: Text(
buttons[index],
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
);
}
// +, -, / x buttons
else if (index == 3 ||
index == 7 ||
index == 11 ||
index == 15) {
return Padding(
padding: const EdgeInsets.all(4.0),
child: MihButton(
onPressed: () {
if (answer == "0") {
setState(() {
userInput += buttons[index];
});
} else {
setState(() {
// userInput = answer;
// answer = "0";
userInput += buttons[index];
});
}
},
buttonColor: MihColors.getGreyColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
width: 50,
height: 50,
borderRadius: 5,
child: Text(
buttons[index],
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
);
}
// delete Button
else if (index == 18) {
return Padding(
padding: const EdgeInsets.all(4.0),
child: MihButton(
onPressed: () {
setState(() {
if (userInput.length == 1) {
userInput = '0';
} else if (userInput.length > 1) {
userInput =
userInput.substring(0, userInput.length - 1);
}
if (!isNumeric(userInput[userInput.length - 1])) {
userInput =
userInput.substring(0, userInput.length - 1);
}
equalPressed();
});
},
buttonColor: MihColors.getRedColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
width: 50,
height: 50,
borderRadius: 5,
child: Icon(
Icons.backspace,
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
),
),
);
}
// Equal_to Button
else if (index == 19) {
return Padding(
padding: const EdgeInsets.all(4.0),
child: MihButton(
onPressed: () {
setState(() {
equalPressed();
userInput = answer;
});
},
buttonColor: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
width: 50,
height: 50,
borderRadius: 5,
child: Text(
buttons[index],
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
);
}
// other buttons
else {
return Padding(
padding: const EdgeInsets.all(4.0),
child: MihButton(
onPressed: () {
setState(() {
userInput += buttons[index];
equalPressed();
});
},
buttonColor: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
width: 50,
height: 50,
borderRadius: 5,
child: Text(
buttons[index],
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
);
}
},
),
),
),
],
),
);
}
}

View File

@@ -0,0 +1,445 @@
import 'package:mzansi_innovation_hub/main.dart';
import 'package:mzansi_innovation_hub/mih_package_components/mih_banner_ad.dart';
import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart';
import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart';
import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart';
import 'package:mzansi_innovation_hub/mih_package_components/mih_single_child_scroll.dart';
import 'package:mzansi_innovation_hub/mih_package_components/mih_button.dart';
import 'package:mzansi_innovation_hub/mih_package_components/mih_form.dart';
import 'package:mzansi_innovation_hub/mih_package_components/mih_numeric_stepper.dart';
import 'package:mzansi_innovation_hub/mih_package_components/mih_package_tool_body.dart';
import 'package:mzansi_innovation_hub/mih_package_components/mih_package_window.dart';
import 'package:mzansi_innovation_hub/mih_package_components/mih_text_form_field.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:math_expressions/math_expressions.dart';
import 'package:mzansi_innovation_hub/mih_package_components/mih_toggle.dart';
import 'package:provider/provider.dart';
class TipCalc extends StatefulWidget {
const TipCalc({super.key});
@override
State<TipCalc> createState() => _TipCalcState();
}
class _TipCalcState extends State<TipCalc> {
TextEditingController billAmountController = TextEditingController();
TextEditingController tipPercentageController = TextEditingController();
TextEditingController splitBillController = TextEditingController();
TextEditingController noPeopleController = TextEditingController();
final ValueNotifier<String> splitValue = ValueNotifier("");
late bool splitPosition;
final _formKey = GlobalKey<FormState>();
String tip = "";
String total = "";
String amountPerPerson = "";
String temp = "";
void splitSelected() {
if (splitBillController.text.isNotEmpty) {
splitValue.value = splitBillController.text;
} else {
splitValue.value = "";
}
}
void validateInput() async {
calculatePressed();
}
void calculatePressed() {
String tipCalc =
"${billAmountController.text}*(${tipPercentageController.text}/100)";
Parser p = Parser();
ContextModel cm = ContextModel();
Expression exp = p.parse(tipCalc);
double eval = exp.evaluate(EvaluationType.REAL, cm);
tip = eval.toStringAsFixed(2);
//print("Tip: $tip");
String totalCalc = "${billAmountController.text}+$tip";
exp = p.parse(totalCalc);
eval = exp.evaluate(EvaluationType.REAL, cm);
total = eval.toStringAsFixed(2);
//print("Total Amount: $total");
if (splitBillController.text == "Yes") {
String splitCalc = "$total/${noPeopleController.text}";
exp = p.parse(splitCalc);
eval = exp.evaluate(EvaluationType.REAL, cm);
amountPerPerson = eval.toStringAsFixed(2);
}
//print("Amount Per Person: $amountPerPerson");
displayResult();
}
void clearInput() {
billAmountController.clear();
tipPercentageController.clear();
noPeopleController.clear();
setState(() {
splitBillController.text = "No";
});
}
@override
void dispose() {
billAmountController.dispose();
tipPercentageController.dispose();
splitBillController.dispose();
noPeopleController.dispose();
super.dispose();
}
void displayResult() {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => MihPackageWindow(
fullscreen: false,
windowTitle: "Calculation Results",
onWindowTapClose: () {
Navigator.pop(context);
},
windowBody: Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
FaIcon(
FontAwesomeIcons.coins,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
size: 35,
),
const SizedBox(width: 15),
Text(
"Tip",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
),
],
),
Text(
tip,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
),
const Divider(),
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
FaIcon(
FontAwesomeIcons.moneyBills,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
size: 35,
),
const SizedBox(width: 15),
Text(
"Total",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
),
],
),
Text(
total,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
),
Text(
"~ ${double.parse(total).ceil()}.00",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
),
if (splitBillController.text == "Yes") const Divider(),
if (splitBillController.text == "Yes")
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
FaIcon(
FontAwesomeIcons.peopleGroup,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
size: 35,
),
const SizedBox(width: 15),
Text(
"Total per Person",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
),
),
],
),
if (splitBillController.text == "Yes")
Text(
amountPerPerson,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
),
if (splitBillController.text == "Yes")
Text(
"~ ${double.parse(amountPerPerson).ceil()}.00",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
),
SizedBox(height: 10),
Consumer(builder: (context, bannerAdDisplay, child) {
return MihBannerAd();
}),
// if (splitBillController.text == "Yes") const Divider(),
],
),
),
);
}
@override
void initState() {
super.initState();
splitBillController.text = "No";
noPeopleController.text = "2";
splitPosition = false;
splitBillController.addListener(splitSelected);
}
@override
Widget build(BuildContext context) {
double screenWidth = MediaQuery.of(context).size.width;
return MihPackageToolBody(
borderOn: false,
innerHorizontalPadding: 10,
bodyItem: getBody(screenWidth),
);
}
Widget getBody(double width) {
return MihSingleChildScroll(
child: Padding(
padding: MzansiInnovationHub.of(context)!.theme.screenType == "desktop"
? EdgeInsets.symmetric(horizontal: width * 0.2)
: EdgeInsets.symmetric(horizontal: width * 0.075),
child: Column(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
MihForm(
formKey: _formKey,
formFields: [
MihTextFormField(
fillColor: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
inputColor: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
controller: billAmountController,
multiLineInput: false,
requiredText: true,
hintText: "Bill Amount",
numberMode: true,
validator: (value) {
return MihValidationServices().isEmpty(value);
},
),
const SizedBox(height: 10),
MihTextFormField(
fillColor: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
inputColor: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
controller: tipPercentageController,
multiLineInput: false,
requiredText: true,
hintText: "Tip Percentage",
numberMode: true,
validator: (value) {
return MihValidationServices().isEmpty(value);
},
),
const SizedBox(height: 10),
MihToggle(
hintText: "Split Bill",
initialPostion: splitPosition,
fillColor: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
secondaryFillColor: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
onChange: (value) {
setState(() {
splitBillController.text = value ? "Yes" : "No";
splitPosition = value;
if (value) {
noPeopleController.text =
noPeopleController.text.isEmpty
? "2"
: noPeopleController.text;
} else {
noPeopleController.clear();
}
});
// if (value) {
// setState(() {
// splitBillController.text = "Yes";
// splitPosition = value;
// });
// } else {
// setState(() {
// splitBillController.text = "No";
// splitPosition = value;
// });
// }
},
),
ValueListenableBuilder(
valueListenable: splitValue,
builder: (BuildContext context, String value, Widget? child) {
temp = value;
return Visibility(
visible: temp == "Yes",
child: Column(
children: [
MihNumericStepper(
controller: noPeopleController,
fillColor: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
inputColor: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
hintText: "No. People",
requiredText: temp == "Yes",
minValue: 2,
// maxValue: 5,
validationOn: true,
),
// MihTextFormField(
// fillColor: MzansiInnovationHub.of(context)!
// .theme
// .secondaryColor(),
// inputColor: MzansiInnovationHub.of(context)!
// .theme
// .primaryColor(),
// controller: noPeopleController,
// multiLineInput: false,
// requiredText: temp == "Yes",
// hintText: "No. of People",
// numberMode: true,
// validator: (validationValue) {
// if (temp == "Yes") {
// return MihValidationServices()
// .isEmpty(validationValue);
// } else {
// return null;
// }
// },
// ),
const SizedBox(height: 10),
],
),
);
},
),
const SizedBox(height: 10),
Center(
child: Wrap(
runAlignment: WrapAlignment.center,
crossAxisAlignment: WrapCrossAlignment.center,
alignment: WrapAlignment.center,
spacing: 10,
runSpacing: 10,
children: [
MihButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
validateInput();
} else {
MihAlertServices().inputErrorAlert(context);
}
},
buttonColor: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
width: 300,
child: Text(
"Calculate",
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
MihButton(
onPressed: () {
clearInput();
},
buttonColor: MihColors.getRedColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
width: 300,
child: Text(
"Clear",
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
],
),
),
],
),
],
),
),
);
}
}