LCOV - code coverage report
Current view: top level - lib - main.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 119 183 65.0 %
Date: 2024-05-20 13:51:31 Functions: 0 0 -

          Line data    Source code
       1             : import 'package:flutter/material.dart';
       2             : import 'package:flutter/services.dart';
       3             : import 'package:logger/logger.dart';
       4             : import 'package:flutter_math_fork/flutter_math.dart';
       5             : import 'package:clc/fractexpr.dart';
       6             : import 'package:clc/fract.dart';
       7             : import 'package:url_launcher/url_launcher.dart';
       8             : import 'package:package_info_plus/package_info_plus.dart';
       9             : import 'package:flutter_svg/flutter_svg.dart';
      10             : 
      11           3 : var log = Logger(
      12           1 :   printer: SimplePrinter(printTime: true),
      13             : );
      14             : 
      15           0 : void main() {
      16           0 :   runApp(const MyApp());
      17             : }
      18             : 
      19             : class MyApp extends StatelessWidget {
      20           4 :   const MyApp({super.key});
      21             : 
      22           1 :   @override
      23             :   Widget build(BuildContext context) {
      24           1 :     return MaterialApp(
      25             :       title: 'Simple Calculator',
      26           1 :       theme: ThemeData(
      27             :         primarySwatch: Colors.blue,
      28             :       ),
      29             :       home: const MyHomePage(title: 'Simple Calculator'),
      30             :     );
      31             :   }
      32             : }
      33             : 
      34             : class MyHomePage extends StatefulWidget {
      35           3 :   const MyHomePage({super.key, required this.title});
      36             : 
      37             :   final String title;
      38             : 
      39           1 :   @override
      40           1 :   State<MyHomePage> createState() => _MyHomePageState();
      41             : }
      42             : 
      43             : class _MyHomePageState extends State<MyHomePage> {
      44             :   String _resultStr = "";
      45             :   String _resultStr2 = "";
      46             :   String _exprStr = "";
      47             :   Fraction _result = Fraction(BigInt.one, BigInt.one);
      48             :   TextEditingController ctrl = TextEditingController();
      49             : 
      50           0 :   void _showResult2() {
      51           0 :     setState(() {
      52           0 :       _resultStr = _result.toString();
      53           0 :       _resultStr2 = _result.toString2();
      54             :     });
      55             :   }
      56             : 
      57           1 :   void _showResult(String s) {
      58           2 :     setState(() {
      59           1 :       if (s == "") {
      60           0 :         _result = Fraction(BigInt.zero, BigInt.one);
      61           0 :         _resultStr = "";
      62           0 :         _resultStr2 = "";
      63           0 :         _exprStr = "";
      64             :       } else {
      65             :         try {
      66           1 :           FractRpn f = FractRpn();
      67           1 :           var v = f.eval(s);
      68             :           if (v != null) {
      69           1 :             _result = v;
      70           3 :             _resultStr = _result.toExpr();
      71           3 :             _resultStr2 = _result.toExpr2();
      72           2 :             _exprStr = f.toExpr();
      73             :           } else {
      74           1 :             _resultStr = "ERR";
      75           1 :             _resultStr2 = "ERR";
      76             :           }
      77           0 :         } on Exception catch (e) {
      78           0 :           _resultStr = "ERR";
      79           0 :           _resultStr2 = "ERR";
      80           0 :           log.d("$e");
      81             :         }
      82             :       }
      83             :     });
      84             :   }
      85             : 
      86           1 :   void pushTxt(String txt) {
      87           3 :     log.d("push $txt");
      88           1 :     if (txt == "AC") {
      89           0 :       ctrl.text = "";
      90             :       txt = "";
      91           0 :       _showResult(ctrl.text);
      92           1 :     } else if (txt == "BS") {
      93           0 :       var start = ctrl.selection.start;
      94           0 :       log.d("start=$start");
      95           0 :       if (start == -1) {
      96           0 :         if (ctrl.text.isNotEmpty) {
      97           0 :           ctrl.text = ctrl.text.substring(0, ctrl.text.length - 1);
      98             :         }
      99           0 :       } else if (start != 0) {
     100           0 :         ctrl.text =
     101           0 :             ctrl.text.substring(0, start - 1) + ctrl.text.substring(start);
     102           0 :         _showResult(ctrl.text);
     103             :       }
     104             :       return;
     105           1 :     } else if (txt == "+/-") {
     106           0 :       _showResult(ctrl.text);
     107           0 :       if (_resultStr != "ERR") {
     108           0 :         _showResult2();
     109           0 :         ctrl.text = _result.toString();
     110             :       }
     111             :       txt = "";
     112           1 :     } else if (txt == "=") {
     113           3 :       _showResult(ctrl.text);
     114           2 :       if (_resultStr != "ERR") {
     115           4 :         ctrl.text = _result.toString();
     116             :       }
     117             :       txt = "";
     118             :     }
     119           3 :     var start = ctrl.selection.start;
     120           3 :     var end = ctrl.selection.end;
     121           3 :     log.d("pre: start=$start, end=$end");
     122           2 :     if (start == -1) {
     123           3 :       start = ctrl.text.length;
     124             :     }
     125           2 :     if (end == -1) {
     126             :       end = start;
     127             :     }
     128           3 :     log.d("fix: start=$start, end=$end");
     129          10 :     ctrl.text = ctrl.text.substring(0, start) + txt + ctrl.text.substring(end);
     130           2 :     ctrl.selection =
     131           4 :         TextSelection.fromPosition(TextPosition(offset: start + txt.length));
     132           3 :     _showResult(ctrl.text);
     133             :   }
     134             : 
     135           1 :   Widget txtbtn(String txt,
     136             :       {Color fgcolor = Colors.black,
     137             :       Color bgcolor = Colors.black12,
     138             :       int flex = 1}) {
     139           1 :     return Expanded(
     140             :         flex: flex,
     141           1 :         child: TextButton(
     142           2 :             onPressed: () => pushTxt(txt),
     143           1 :             style: ButtonStyle(
     144           1 :               foregroundColor: WidgetStateProperty.all<Color>(fgcolor),
     145           1 :               backgroundColor: WidgetStateProperty.all<Color>(bgcolor),
     146             :             ),
     147           1 :             child: Text(txt,
     148             :                 style: const TextStyle(
     149             :                   fontWeight: FontWeight.bold,
     150             :                   fontSize: 25,
     151             :                 )),
     152             :             ));
     153             :   }
     154             : 
     155           1 :   Widget buttons() {
     156           2 :     return Column(children: <Widget>[
     157           2 :       Row(children: <Widget>[
     158           1 :         txtbtn("7"),
     159           1 :         txtbtn("8"),
     160           1 :         txtbtn("9"),
     161           1 :         txtbtn("(", bgcolor: Colors.orangeAccent),
     162           1 :         txtbtn(")", bgcolor: Colors.orangeAccent),
     163             :       ]),
     164           2 :       Row(children: <Widget>[
     165           1 :         txtbtn("4"),
     166           1 :         txtbtn("5"),
     167           1 :         txtbtn("6"),
     168           1 :         txtbtn("ร—", bgcolor: Colors.orangeAccent),
     169           1 :         txtbtn("รท", bgcolor: Colors.orangeAccent),
     170             :       ]),
     171           2 :       Row(children: <Widget>[
     172           1 :         txtbtn("1"),
     173           1 :         txtbtn("2"),
     174           1 :         txtbtn("3"),
     175           1 :         txtbtn("+", bgcolor: Colors.orangeAccent),
     176           1 :         txtbtn("-", bgcolor: Colors.orangeAccent),
     177             :       ]),
     178           2 :       Row(children: <Widget>[
     179           1 :         txtbtn("0"),
     180           1 :         txtbtn("."),
     181           1 :         txtbtn("AC", bgcolor: Colors.orangeAccent),
     182           1 :         txtbtn("BS", bgcolor: Colors.orangeAccent),
     183           1 :         txtbtn("=", bgcolor: Colors.orangeAccent),
     184             :       ]),
     185             :     ]);
     186             :   }
     187             : 
     188           1 :   @override
     189             :   Widget build(BuildContext context) {
     190           1 :     return DefaultTabController(
     191             :         length: 4,
     192           1 :         child: Builder(
     193           1 :           builder: (BuildContext context) {
     194           1 :             return Scaffold(
     195             :                 extendBody: false,
     196             :                 floatingActionButtonLocation:
     197             :                     FloatingActionButtonLocation.startDocked,
     198           1 :                 floatingActionButton: FloatingActionButton(
     199           0 :                   onPressed: () {
     200           0 :                     var tabid = DefaultTabController.of(context).index;
     201             :                     String copyText = "";
     202           0 :                     if (tabid == 1) {
     203           0 :                       copyText = _result.toString2();
     204           0 :                     } else if (tabid == 2) {
     205           0 :                       copyText = _result.toDouble().toString();
     206           0 :                     } else if (tabid == 3) {
     207           0 :                       copyText = _exprStr;
     208             :                     } else {
     209           0 :                       copyText = _result.toString();
     210             :                     }
     211           0 :                     log.d("copy$tabid: $copyText");
     212           0 :                     Clipboard.setData(ClipboardData(text: copyText));
     213             :                   },
     214             :                   tooltip: "copy",
     215             :                   child: const Icon(Icons.copy),
     216             :                 ),
     217           1 :                 drawer: Drawer(
     218           1 :                   child: ListView(
     219           1 :                     children: <Widget>[
     220           1 :                       DrawerHeader(
     221             :                         decoration: const BoxDecoration(color: Colors.blue),
     222           3 :                         child: Text(widget.title,
     223             :                             style: const TextStyle(color: Colors.white)),
     224             :                       ),
     225           1 :                       ListTile(
     226             :                         title: const Row(children: <Widget>[
     227             :                           Icon(Icons.bug_report),
     228             :                           Text("Report issue ๐Ÿ”—"),
     229             :                         ]),
     230           0 :                         onTap: () {
     231           0 :                           launchUrl(Uri.parse("https://github.com/wtnb75/clc/issues"));
     232             :                         },
     233             :                       ),
     234           1 :                       ListTile(
     235             :                         title: const Row(children: <Widget>[
     236             :                           Icon(Icons.search),
     237             :                           Text("by google ๐Ÿ”—"),
     238             :                         ]),
     239           0 :                         onTap: () {
     240           0 :                           launchUrl(Uri.parse("https://google.com/search").replace(queryParameters: {"q": ctrl.text}));
     241             :                         },
     242             :                       ),
     243           1 :                       ListTile(
     244             :                         title: const Row(children: <Widget>[
     245             :                           Icon(Icons.calculate),
     246             :                           Text("by wolfram alpha ๐Ÿ”—"),
     247             :                         ]),
     248           0 :                         onTap: () {
     249           0 :                           launchUrl(Uri.parse("https://www.wolframalpha.com/input/").replace(queryParameters: {"i": ctrl.text}));
     250             :                         },
     251             :                       ),
     252           1 :                       ListTile(
     253             :                         title: const Text("About..."),
     254           0 :                         onTap: () {
     255           0 :                           var packageInfo = PackageInfo.fromPlatform();
     256           0 :                           packageInfo.then((pkginfo) {
     257           0 :                             showDialog(
     258             :                                 context: context,
     259           0 :                                 builder: (_) {
     260           0 :                                   String appName = pkginfo.appName;
     261           0 :                                   String packageName = pkginfo.packageName;
     262           0 :                                   String version = pkginfo.version;
     263           0 :                                   String buildId = pkginfo.buildNumber;
     264           0 :                                   String content = "appName = $appName\n";
     265           0 :                                   content += "packageName = $packageName\n";
     266           0 :                                   content += "version = $version\n";
     267           0 :                                   content += "buildId = $buildId\n";
     268           0 :                                   return AlertDialog(
     269           0 :                                       title: Row(children: [
     270           0 :                                         SvgPicture.asset(
     271             :                                           "assets/clc.svg",
     272             :                                           height: 50,
     273             :                                         ),
     274             :                                         const VerticalDivider(),
     275           0 :                                         Text("About $appName..."),
     276             :                                       ]),
     277           0 :                                       content: Text(content));
     278             :                                 });
     279             :                           });
     280             :                         },
     281             :                       ),
     282             :                     ],
     283             :                   ),
     284             :                 ),
     285           1 :                 appBar: AppBar(
     286           3 :                     title: Text(widget.title),
     287           1 :                     bottom: TabBar(
     288           1 :                       tabs: <Widget>[
     289           2 :                         Tab(child: Math.tex(r'\frac{3}{2}')),
     290           2 :                         Tab(child: Math.tex(r'1 \frac{1}{2}')),
     291           2 :                         Tab(child: Math.tex(r'1.5')),
     292           2 :                         Tab(child: Math.tex(r'\frac{1}{2} \times 3')),
     293             :                       ],
     294             :                     )),
     295           1 :                 body: Container(
     296             :                   decoration:
     297           2 :                       BoxDecoration(border: Border.all(color: Colors.blueGrey)),
     298             :                   constraints: const BoxConstraints(minHeight: 100),
     299             :                   margin: const EdgeInsets.all(8),
     300           2 :                   child: TabBarView(children: <Widget>[
     301           1 :                     Center(
     302           1 :                         child: Math.tex(
     303           1 :                       _resultStr,
     304             :                       mathStyle: MathStyle.display,
     305             :                       textStyle: const TextStyle(fontSize: 42),
     306             :                     )),
     307           1 :                     Center(
     308           1 :                         child: Math.tex(
     309           1 :                       _resultStr2,
     310             :                       mathStyle: MathStyle.display,
     311             :                       textStyle: const TextStyle(fontSize: 42),
     312             :                     )),
     313           1 :                     Center(
     314           1 :                         child: Math.tex(
     315           3 :                       '${_result.toDouble()}',
     316             :                       mathStyle: MathStyle.display,
     317             :                       textStyle: const TextStyle(fontSize: 42),
     318             :                     )),
     319           1 :                     Center(
     320           1 :                         child: Math.tex(
     321           1 :                       _exprStr,
     322             :                       mathStyle: MathStyle.display,
     323             :                       textStyle: const TextStyle(fontSize: 42),
     324             :                     )),
     325             :                   ]),
     326             :                 ),
     327           1 :                 bottomNavigationBar: Container(
     328             :                   padding: const EdgeInsets.all(10),
     329             :                   child:
     330           2 :                       Column(mainAxisSize: MainAxisSize.min, children: <Widget>[
     331           1 :                     Container(
     332             :                         margin: const EdgeInsets.symmetric(horizontal: 8),
     333           1 :                         child: TextField(
     334           1 :                             controller: ctrl,
     335             :                             textAlign: TextAlign.right,
     336             :                             enabled: true,
     337             :                             maxLines: 1,
     338             :                             style: const TextStyle(fontSize: 30),
     339             :                             keyboardType: TextInputType.number,
     340           1 :                             onChanged: _showResult,
     341             :                             decoration: const InputDecoration(
     342             :                               border: OutlineInputBorder(),
     343             :                               hintText: 'Enter formula',
     344             :                             ))),
     345             :                     const Divider(),
     346           1 :                     buttons(),
     347             :                   ]),
     348             :                 ));
     349             :           },
     350             :         ));
     351             :   }
     352             : }

Generated by: LCOV version 1.14