Skip to content

Commit 9c7c514

Browse files
committed
blog: new flutter calculator again
1 parent 0473cb9 commit 9c7c514

File tree

2 files changed

+386
-0
lines changed

2 files changed

+386
-0
lines changed
5.93 KB
Loading
Lines changed: 386 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,386 @@
1+
+++
2+
title = 'Flutter study - Calculator'
3+
summary = "With full code"
4+
date = "2025-04-09"
5+
# lastmod = 2025-03-11
6+
tags = ["flutter", "study", "coding", "sample"]
7+
coverImg = "calculator.webp"
8+
# externalUrl = "https://www.example.com" # Redirect
9+
draft = false
10+
showDate = true
11+
showReadingTime = false
12+
showToC = false
13+
showComments = true
14+
+++
15+
16+
Source code reference: <https://www.geeksforgeeks.org/advanced-calculator-app-using-flutter/>
17+
18+
I made some modifications here.
19+
20+
21+
### pubspec.yaml
22+
23+
```yaml {linenos=true}
24+
dependencies:
25+
flutter:
26+
sdk: flutter
27+
math_expressions: ^2.6.0
28+
```
29+
30+
### lib/main.dart
31+
32+
```dart {linenos=true}
33+
import 'package:flutter/material.dart';
34+
35+
import 'screens/calculator_screen.dart';
36+
37+
void main() {
38+
runApp(const MainApp());
39+
}
40+
41+
class MainApp extends StatelessWidget {
42+
const MainApp({super.key});
43+
44+
@override
45+
Widget build(BuildContext context) {
46+
return MaterialApp(
47+
title: 'Calculator+',
48+
theme: ThemeData(
49+
colorScheme: ColorScheme.fromSeed(
50+
seedColor: Colors.deepOrange,
51+
),
52+
),
53+
debugShowCheckedModeBanner: false,
54+
home: CalculatorScreen(),
55+
);
56+
}
57+
}
58+
```
59+
60+
### lib/models/button_type_enum.dart
61+
62+
```dart {linenos=true}
63+
enum BtnType { number, operator, equal }
64+
```
65+
66+
### lib/screens/calculator_screen.dart
67+
68+
```dart {linenos=true}
69+
import 'package:flutter/material.dart';
70+
import 'package:math_expressions/math_expressions.dart';
71+
72+
import '../models/button_type_enum.dart';
73+
import '../widgets/buttons_row.dart';
74+
import '../widgets/calculator_button.dart';
75+
76+
class CalculatorScreen extends StatelessWidget {
77+
final ValueNotifier<String> inputNumbers = ValueNotifier<String>("");
78+
79+
CalculatorScreen({super.key});
80+
81+
void _btnClick({required String name}) {
82+
if (name == "c") {
83+
inputNumbers.value = "";
84+
} else if (name == "remove") {
85+
inputNumbers.value =
86+
inputNumbers.value.substring(0, inputNumbers.value.length - 1);
87+
} else {
88+
inputNumbers.value += name;
89+
}
90+
}
91+
92+
Text _calculating(BuildContext context, String value, Widget? child) {
93+
if (value.isNotEmpty) {
94+
if (int.tryParse(value[value.length - 1]) != null) {
95+
try {
96+
return Text(Parser()
97+
.parse(value)
98+
.evaluate(EvaluationType.REAL, ContextModel())
99+
.toString());
100+
} catch (e) {
101+
return Text("");
102+
}
103+
} else if (value[value.length - 1] == "%") {
104+
value = "(${value.substring(0, value.length - 1)})/100";
105+
try {
106+
return Text(Parser()
107+
.parse(value)
108+
.evaluate(EvaluationType.REAL, ContextModel())
109+
.toString());
110+
} catch (e) {
111+
return Text("");
112+
}
113+
}
114+
}
115+
return Text("");
116+
}
117+
118+
@override
119+
Widget build(BuildContext context) {
120+
return Scaffold(
121+
body: Column(
122+
children: [
123+
Expanded(
124+
flex: 30,
125+
child: Column(
126+
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
127+
children: [
128+
ValueListenableBuilder<String>(
129+
valueListenable: inputNumbers,
130+
builder: (context, value, child) {
131+
return Text(
132+
value,
133+
style: TextStyle(
134+
fontSize: 30,
135+
),
136+
);
137+
},
138+
),
139+
ValueListenableBuilder<String>(
140+
valueListenable: inputNumbers,
141+
builder: (context, value, child) {
142+
return _calculating(context, value, child);
143+
},
144+
),
145+
],
146+
),
147+
),
148+
BtnRow(children: [
149+
CalcButton(
150+
name: "C",
151+
btnType: BtnType.operator,
152+
function: () => _btnClick(name: "c"),
153+
),
154+
CalcButton(
155+
name: "←",
156+
btnType: BtnType.operator,
157+
function: () => _btnClick(name: "remove"),
158+
),
159+
CalcButton(
160+
name: "",
161+
btnType: BtnType.number,
162+
function: () {},
163+
),
164+
CalcButton(
165+
name: "/",
166+
btnType: BtnType.operator,
167+
function: () => _btnClick(name: "/"),
168+
),
169+
]),
170+
BtnRow(children: [
171+
CalcButton(
172+
name: "7",
173+
btnType: BtnType.number,
174+
function: () => _btnClick(name: "7"),
175+
),
176+
CalcButton(
177+
name: "8",
178+
btnType: BtnType.number,
179+
function: () => _btnClick(name: "8"),
180+
),
181+
CalcButton(
182+
name: "9",
183+
btnType: BtnType.number,
184+
function: () => _btnClick(name: "9"),
185+
),
186+
CalcButton(
187+
name: "*",
188+
btnType: BtnType.operator,
189+
function: () => _btnClick(name: "*"),
190+
),
191+
]),
192+
BtnRow(children: [
193+
CalcButton(
194+
name: "4",
195+
btnType: BtnType.number,
196+
function: () => _btnClick(name: "4"),
197+
),
198+
CalcButton(
199+
name: "5",
200+
btnType: BtnType.number,
201+
function: () => _btnClick(name: "5"),
202+
),
203+
CalcButton(
204+
name: "6",
205+
btnType: BtnType.number,
206+
function: () => _btnClick(name: "6"),
207+
),
208+
CalcButton(
209+
name: "-",
210+
btnType: BtnType.operator,
211+
function: () => _btnClick(name: "-"),
212+
),
213+
]),
214+
BtnRow(children: [
215+
CalcButton(
216+
name: "1",
217+
btnType: BtnType.number,
218+
function: () => _btnClick(name: "1"),
219+
),
220+
CalcButton(
221+
name: "2",
222+
btnType: BtnType.number,
223+
function: () => _btnClick(name: "2"),
224+
),
225+
CalcButton(
226+
name: "3",
227+
btnType: BtnType.number,
228+
function: () => _btnClick(name: "3"),
229+
),
230+
CalcButton(
231+
name: "+",
232+
btnType: BtnType.operator,
233+
function: () => _btnClick(name: "+"),
234+
),
235+
]),
236+
BtnRow(children: [
237+
CalcButton(
238+
name: "%",
239+
btnType: BtnType.operator,
240+
function: () => _btnClick(name: "%"),
241+
),
242+
CalcButton(
243+
name: "0",
244+
btnType: BtnType.number,
245+
function: () => _btnClick(name: "0"),
246+
),
247+
CalcButton(
248+
name: ".",
249+
btnType: BtnType.number,
250+
function: () => _btnClick(name: "."),
251+
),
252+
CalcButton(
253+
name: "=",
254+
btnType: BtnType.equal,
255+
function: () {},
256+
),
257+
]),
258+
],
259+
),
260+
);
261+
}
262+
}
263+
```
264+
265+
### lib/styles/button_style.dart
266+
267+
```dart {linenos=true}
268+
import 'package:flutter/material.dart';
269+
270+
import '../models/button_type_enum.dart';
271+
272+
ButtonStyle btnStyle({
273+
required BuildContext context,
274+
required BtnType btnType,
275+
}) {
276+
return switch (btnType) {
277+
BtnType.number => _numberStyle(context: context),
278+
BtnType.operator => _operatorStyle(context: context),
279+
BtnType.equal => _equalStyle(context: context),
280+
};
281+
}
282+
283+
ButtonStyle _numberStyle({required BuildContext context}) {
284+
return ButtonStyle(
285+
backgroundColor:
286+
WidgetStatePropertyAll(Theme.of(context).colorScheme.primaryContainer),
287+
foregroundColor: WidgetStatePropertyAll(
288+
Theme.of(context).colorScheme.onPrimaryContainer),
289+
);
290+
}
291+
292+
ButtonStyle _operatorStyle({required BuildContext context}) {
293+
return ButtonStyle(
294+
backgroundColor:
295+
WidgetStatePropertyAll(Theme.of(context).colorScheme.tertiaryContainer),
296+
foregroundColor: WidgetStatePropertyAll(
297+
Theme.of(context).colorScheme.onTertiaryContainer),
298+
);
299+
}
300+
301+
ButtonStyle _equalStyle({required BuildContext context}) {
302+
return ButtonStyle(
303+
backgroundColor:
304+
WidgetStatePropertyAll(Theme.of(context).colorScheme.primary),
305+
foregroundColor:
306+
WidgetStatePropertyAll(Theme.of(context).colorScheme.onPrimary),
307+
);
308+
}
309+
```
310+
311+
### lib/widgets/buttons_row.dart
312+
313+
```dart {linenos=true}
314+
import 'package:flutter/material.dart';
315+
316+
class BtnRow extends StatelessWidget {
317+
final List<Widget> children;
318+
319+
const BtnRow({
320+
super.key,
321+
required this.children,
322+
});
323+
324+
@override
325+
Widget build(BuildContext context) {
326+
return Expanded(
327+
flex: 14,
328+
child: Row(
329+
mainAxisAlignment: MainAxisAlignment.center,
330+
children: children,
331+
),
332+
);
333+
}
334+
}
335+
```
336+
337+
### lib/widgets/calculator_button.dart
338+
339+
```dart {linenos=true}
340+
import 'package:flutter/material.dart';
341+
342+
import '../models/button_type_enum.dart';
343+
import '../styles/button_style.dart';
344+
345+
class CalcButton extends StatelessWidget {
346+
final String name;
347+
final BtnType btnType;
348+
final VoidCallback function;
349+
350+
const CalcButton({
351+
super.key,
352+
required this.name,
353+
required this.btnType,
354+
required this.function,
355+
});
356+
357+
@override
358+
Widget build(BuildContext context) {
359+
return Padding(
360+
padding: const EdgeInsets.all(8.0),
361+
child: SizedBox(
362+
width: 70,
363+
height: 70,
364+
child: ElevatedButton(
365+
style: btnStyle(context: context, btnType: btnType).copyWith(
366+
shape: WidgetStatePropertyAll(
367+
RoundedRectangleBorder(
368+
borderRadius: BorderRadius.all(
369+
Radius.circular(50),
370+
),
371+
),
372+
),
373+
),
374+
onPressed: function,
375+
child: Text(
376+
name,
377+
style: TextStyle(
378+
fontSize: 20,
379+
),
380+
),
381+
),
382+
),
383+
);
384+
}
385+
}
386+
```

0 commit comments

Comments
 (0)