💄 Optimize styling
This commit is contained in:
3
devtools_options.yaml
Normal file
3
devtools_options.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
description: This file stores settings for Dart & Flutter DevTools.
|
||||
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
|
||||
extensions:
|
117
lib/main.dart
117
lib/main.dart
@@ -1,20 +1,28 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:latext/latext.dart';
|
||||
import 'package:simple_math_calc/models/calculation_step.dart';
|
||||
import 'package:simple_math_calc/solver_service.dart';
|
||||
import 'package:simple_math_calc/solver.dart';
|
||||
import 'dart:math';
|
||||
|
||||
void main() async {
|
||||
runApp(const MyApp());
|
||||
runApp(const CalcApp());
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
const MyApp({super.key});
|
||||
class CalcApp extends StatelessWidget {
|
||||
const CalcApp({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
title: '方程计算器',
|
||||
theme: ThemeData(primarySwatch: Colors.blue, useMaterial3: true),
|
||||
theme: ThemeData(
|
||||
primarySwatch: Colors.blue,
|
||||
useMaterial3: true,
|
||||
textTheme: GoogleFonts.notoSerifScTextTheme(
|
||||
Theme.of(context).textTheme, // Inherit existing text theme
|
||||
),
|
||||
),
|
||||
home: const CalculatorHomePage(),
|
||||
);
|
||||
}
|
||||
@@ -68,23 +76,33 @@ class _CalculatorHomePageState extends State<CalculatorHomePage> {
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('方程与表达式计算器')),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
body: Column(
|
||||
children: [
|
||||
TextField(
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 16.0, right: 16.0, top: 16.0),
|
||||
child: Row(
|
||||
spacing: 8,
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: _controller,
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(),
|
||||
textAlign: TextAlign.center,
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: '输入方程或表达式',
|
||||
floatingLabelAlignment: FloatingLabelAlignment.center,
|
||||
hintText: '例如: 2x^2 - 8x + 6 = 0',
|
||||
),
|
||||
onSubmitted: (_) => _solveEquation(),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
ElevatedButton(onPressed: _solveEquation, child: const Text('计算')),
|
||||
const SizedBox(height: 16),
|
||||
const Divider(),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: _solveEquation,
|
||||
icon: Icon(Icons.play_arrow),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: _isLoading
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
@@ -94,21 +112,35 @@ class _CalculatorHomePageState extends State<CalculatorHomePage> {
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// 构建结果展示视图
|
||||
Widget buildResultView(CalculationResult result) {
|
||||
return ListView(
|
||||
padding: EdgeInsets.only(
|
||||
left: 16,
|
||||
right: 16,
|
||||
bottom: MediaQuery.of(context).padding.bottom + 16,
|
||||
top: 16,
|
||||
),
|
||||
children: [
|
||||
...result.steps.map(
|
||||
(step) => Card(
|
||||
margin: const EdgeInsets.symmetric(vertical: 8),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
child: ClipRRect(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||
child: Stack(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 12,
|
||||
right: 12,
|
||||
bottom: 4,
|
||||
top: 16,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
step.title,
|
||||
@@ -116,8 +148,36 @@ class _CalculatorHomePageState extends State<CalculatorHomePage> {
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
SelectableText(step.explanation),
|
||||
const SizedBox(height: 8),
|
||||
Center(child: LaTexT(laTeXCode: Text(step.formula))),
|
||||
Center(
|
||||
child: LaTexT(
|
||||
laTeXCode: Text(
|
||||
step.formula,
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
left: -8,
|
||||
top: -8,
|
||||
child: Transform.rotate(
|
||||
angle: pi / -5,
|
||||
child: Opacity(
|
||||
opacity: 0.8,
|
||||
child: Badge(
|
||||
backgroundColor: Theme.of(
|
||||
context,
|
||||
).colorScheme.primary,
|
||||
label: Text(
|
||||
step.stepNumber.toString(),
|
||||
style: TextStyle(fontSize: 32),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -127,17 +187,24 @@ class _CalculatorHomePageState extends State<CalculatorHomePage> {
|
||||
Card(
|
||||
color: Theme.of(context).colorScheme.primaryContainer,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
"最终答案:",
|
||||
"最终答案",
|
||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||
color: Theme.of(context).colorScheme.onPrimaryContainer,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
LaTexT(laTeXCode: Text(result.finalAnswer)),
|
||||
LaTexT(
|
||||
laTeXCode: Text(
|
||||
result.finalAnswer,
|
||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||
color: Theme.of(context).colorScheme.onPrimaryContainer,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@@ -1,10 +1,12 @@
|
||||
// 用来描述计算过程中的每一步
|
||||
class CalculationStep {
|
||||
final String title; // 这一步的标题,例如:“第一步:整理方程”
|
||||
final int stepNumber; // 步骤编号,例如:1, 2, 3...
|
||||
final String title; // 这一步的标题,例如:"整理方程"
|
||||
final String explanation; // 对这一步的具体文字描述
|
||||
final String formula; // 这一步得到的数学式子 (可以使用 LaTeX 格式)
|
||||
|
||||
CalculationStep({
|
||||
required this.stepNumber,
|
||||
required this.title,
|
||||
required this.explanation,
|
||||
required this.formula,
|
||||
|
@@ -56,16 +56,16 @@ class SolverService {
|
||||
final steps = <CalculationStep>[];
|
||||
steps.add(
|
||||
CalculationStep(
|
||||
title: '第一步:表达式求值',
|
||||
stepNumber: 1,
|
||||
title: '表达式求值',
|
||||
explanation: '这是一个标准的数学表达式,我们将直接计算其结果。',
|
||||
formula: input,
|
||||
),
|
||||
);
|
||||
|
||||
Parser p = Parser();
|
||||
GrammarParser p = GrammarParser();
|
||||
Expression exp = p.parse(input);
|
||||
ContextModel cm = ContextModel();
|
||||
final result = exp.evaluate(EvaluationType.REAL, cm);
|
||||
final result = RealEvaluator().evaluate(exp);
|
||||
|
||||
return CalculationResult(steps: steps, finalAnswer: result.toString());
|
||||
}
|
||||
@@ -75,6 +75,7 @@ class SolverService {
|
||||
final steps = <CalculationStep>[];
|
||||
steps.add(
|
||||
CalculationStep(
|
||||
stepNumber: 0,
|
||||
title: '原方程',
|
||||
explanation: '这是一元一次方程。',
|
||||
formula: '\$\$$input\$\$',
|
||||
@@ -89,7 +90,8 @@ class SolverService {
|
||||
|
||||
steps.add(
|
||||
CalculationStep(
|
||||
title: '第一步:移项',
|
||||
stepNumber: 1,
|
||||
title: '移项',
|
||||
explanation: '将所有含 x 的项移到等式左边,常数项移到右边。',
|
||||
formula:
|
||||
'\$\$${a}x ${c >= 0 ? '-' : '+'} ${c.abs()}x = $d ${b >= 0 ? '-' : '+'} ${b.abs()}\$\$',
|
||||
@@ -98,7 +100,8 @@ class SolverService {
|
||||
|
||||
steps.add(
|
||||
CalculationStep(
|
||||
title: '第二步:合并同类项',
|
||||
stepNumber: 2,
|
||||
title: '合并同类项',
|
||||
explanation: '合并等式两边的项。',
|
||||
formula: '\$\$${newA}x = $newD\$\$',
|
||||
),
|
||||
@@ -114,7 +117,8 @@ class SolverService {
|
||||
final x = newD / newA;
|
||||
steps.add(
|
||||
CalculationStep(
|
||||
title: '第三步:求解 x',
|
||||
stepNumber: 3,
|
||||
title: '求解 x',
|
||||
explanation: '两边同时除以 x 的系数 ($newA)。',
|
||||
formula: '\$\$x = \frac{$newD}{$newA}\$\$',
|
||||
),
|
||||
@@ -143,7 +147,8 @@ class SolverService {
|
||||
|
||||
steps.add(
|
||||
CalculationStep(
|
||||
title: '第一步:整理方程',
|
||||
stepNumber: 1,
|
||||
title: '整理方程',
|
||||
explanation: r'将方程整理成标准形式 ax^2+bx+c=0。',
|
||||
formula:
|
||||
'\$\$${a}x^2 ${b >= 0 ? '+' : ''} ${b}x ${c >= 0 ? '+' : ''} $c = 0\$\$',
|
||||
@@ -155,16 +160,18 @@ class SolverService {
|
||||
if (factors != null) {
|
||||
steps.add(
|
||||
CalculationStep(
|
||||
title: '第二步:因式分解法 (十字相乘)',
|
||||
stepNumber: 2,
|
||||
title: '因式分解法 (十字相乘)',
|
||||
explanation: '我们发现可以将方程分解为两个一次因式的乘积。',
|
||||
formula: factors.formula,
|
||||
),
|
||||
);
|
||||
steps.add(
|
||||
CalculationStep(
|
||||
title: '第三步:求解',
|
||||
stepNumber: 3,
|
||||
title: '求解',
|
||||
explanation: '分别令每个因式等于 0,解出 x。',
|
||||
formula: '解得 ${factors.solution}',
|
||||
formula: factors.solution,
|
||||
),
|
||||
);
|
||||
return CalculationResult(steps: steps, finalAnswer: factors.solution);
|
||||
@@ -173,7 +180,8 @@ class SolverService {
|
||||
|
||||
steps.add(
|
||||
CalculationStep(
|
||||
title: '第二步:选择解法',
|
||||
stepNumber: 2,
|
||||
title: '选择解法',
|
||||
explanation: '无法进行因式分解,我们选择使用求根公式法。',
|
||||
formula: '\$\$\\Delta = b^2 - 4ac\$\$',
|
||||
),
|
||||
@@ -182,7 +190,8 @@ class SolverService {
|
||||
final delta = b * b - 4 * a * c;
|
||||
steps.add(
|
||||
CalculationStep(
|
||||
title: '第三步:计算判别式 (Delta)',
|
||||
stepNumber: 3,
|
||||
title: '计算判别式 (Delta)',
|
||||
explanation:
|
||||
'\$\$\\Delta = b^2 - 4ac = ($b)^2 - 4 \\cdot ($a) \\cdot ($c) = $delta\$\$',
|
||||
formula: '\$\$\\Delta = $delta\$\$',
|
||||
@@ -194,7 +203,8 @@ class SolverService {
|
||||
final x2 = (-b - sqrt(delta)) / (2 * a);
|
||||
steps.add(
|
||||
CalculationStep(
|
||||
title: '第四步:应用求根公式',
|
||||
stepNumber: 4,
|
||||
title: '应用求根公式',
|
||||
explanation:
|
||||
r'因为 $\Delta > 0$,方程有两个不相等的实数根。公式: $x = \frac{-b \pm \sqrt{\Delta}}{2a}$。',
|
||||
formula:
|
||||
@@ -210,7 +220,8 @@ class SolverService {
|
||||
final x = -b / (2 * a);
|
||||
steps.add(
|
||||
CalculationStep(
|
||||
title: '第四步:应用求根公式',
|
||||
stepNumber: 4,
|
||||
title: '应用求根公式',
|
||||
explanation: r'因为 $\Delta = 0$,方程有两个相等的实数根。',
|
||||
formula: '\$\$x_1 = x_2 = ${x.toStringAsFixed(4)}\$\$',
|
||||
),
|
||||
@@ -222,7 +233,8 @@ class SolverService {
|
||||
} else {
|
||||
steps.add(
|
||||
CalculationStep(
|
||||
title: '第四步:判断解',
|
||||
stepNumber: 4,
|
||||
title: '判断解',
|
||||
explanation: r'因为 $\Delta < 0$,该方程在实数范围内无解。',
|
||||
formula: '无实数解',
|
||||
),
|
||||
@@ -245,6 +257,7 @@ class SolverService {
|
||||
|
||||
steps.add(
|
||||
CalculationStep(
|
||||
stepNumber: 0,
|
||||
title: '原始方程组',
|
||||
explanation: '这是一个二元一次方程组,我们将使用加减消元法求解。',
|
||||
formula:
|
||||
@@ -272,7 +285,8 @@ ${a2}x ${b2 >= 0 ? '+' : ''} ${b2}y = $c2 & (2)
|
||||
|
||||
steps.add(
|
||||
CalculationStep(
|
||||
title: '第一步:消元',
|
||||
stepNumber: 1,
|
||||
title: '消元',
|
||||
explanation: '为了消去变量 y,将方程(1)两边乘以 $b2,方程(2)两边乘以 $b1。',
|
||||
formula:
|
||||
'''
|
||||
@@ -291,17 +305,19 @@ ${newA2}x ${b1 * b2 >= 0 ? '+' : ''} ${b1 * b2}y = $newC2 & (4)
|
||||
|
||||
steps.add(
|
||||
CalculationStep(
|
||||
title: '第二步:相减',
|
||||
stepNumber: 2,
|
||||
title: '相减',
|
||||
explanation: '将方程(3)减去方程(4),得到一个只含 x 的方程。',
|
||||
formula:
|
||||
'\$\$($newA1 - $newA2)x = $newC1 - $newC2 \Rightarrow ${xCoeff}x = $constCoeff\$\$',
|
||||
'\$\$($newA1 - $newA2)x = $newC1 - $newC2 \\Rightarrow ${xCoeff}x = $constCoeff\$\$',
|
||||
),
|
||||
);
|
||||
|
||||
final x = constCoeff / xCoeff;
|
||||
steps.add(
|
||||
CalculationStep(
|
||||
title: '第三步:解出 x',
|
||||
stepNumber: 3,
|
||||
title: '解出 x',
|
||||
explanation: '求解上述方程得到 x 的值。',
|
||||
formula: '\$\$x = $x\$\$',
|
||||
),
|
||||
@@ -313,7 +329,8 @@ ${newA2}x ${b1 * b2 >= 0 ? '+' : ''} ${b1 * b2}y = $newC2 & (4)
|
||||
final y = yConst / yCoeff;
|
||||
steps.add(
|
||||
CalculationStep(
|
||||
title: '第四步:回代求解 y',
|
||||
stepNumber: 4,
|
||||
title: '回代求解 y',
|
||||
explanation: '将 x = $x 代入原方程(2)中。',
|
||||
formula:
|
||||
'''
|
||||
@@ -330,14 +347,15 @@ ${b2}y &= ${c2 - a2 * x}
|
||||
);
|
||||
steps.add(
|
||||
CalculationStep(
|
||||
title: '第五步:解出 y',
|
||||
stepNumber: 5,
|
||||
title: '解出 y',
|
||||
explanation: '求解得到 y 的值。',
|
||||
formula: '\$\$y = $y\$\$',
|
||||
),
|
||||
);
|
||||
return CalculationResult(
|
||||
steps: steps,
|
||||
finalAnswer: '\$\$x = $x, \quad y = $y\$\$',
|
||||
finalAnswer: '\$\$x = $x, \\quad y = $y\$\$',
|
||||
);
|
||||
} else {
|
||||
final yCoeff = b1;
|
||||
@@ -345,7 +363,8 @@ ${b2}y &= ${c2 - a2 * x}
|
||||
final y = yConst / yCoeff;
|
||||
steps.add(
|
||||
CalculationStep(
|
||||
title: '第四步:回代求解 y',
|
||||
stepNumber: 4,
|
||||
title: '回代求解 y',
|
||||
explanation: '将 x = $x 代入原方程(1)中。',
|
||||
formula:
|
||||
'''
|
||||
@@ -362,7 +381,8 @@ ${b1}y &= ${c1 - a1 * x}
|
||||
);
|
||||
steps.add(
|
||||
CalculationStep(
|
||||
title: '第五步:解出 y',
|
||||
stepNumber: 5,
|
||||
title: '解出 y',
|
||||
explanation: '求解得到 y 的值。',
|
||||
formula: '\$\$y = $y\$\$',
|
||||
),
|
Reference in New Issue
Block a user