diff --git a/lib/src/data/dbUtil.dart b/lib/src/data/dbUtil.dart index 88e9194..70421ca 100644 --- a/lib/src/data/dbUtil.dart +++ b/lib/src/data/dbUtil.dart @@ -1,7 +1,9 @@ import 'dart:io'; +import 'package:flutter/animation.dart'; import 'package:path/path.dart'; import 'package:sqflite/sqflite.dart'; import 'package:xiaoming/src/data/appData.dart'; +import 'package:xiaoming/src/view/widget/myTextView.dart'; class DBUtil { ///从字符串中读取矩阵(矩阵自动写入的格式) diff --git a/lib/src/view/route/homeRoute.dart b/lib/src/view/route/homeRoute.dart index 5999839..27e667f 100644 --- a/lib/src/view/route/homeRoute.dart +++ b/lib/src/view/route/homeRoute.dart @@ -1,14 +1,13 @@ -import 'dart:async'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:keyboard_visibility/keyboard_visibility.dart'; import 'package:provide/provide.dart'; -import 'package:sqflite/sqflite.dart'; import 'package:xiaoming/src/data/appData.dart'; import 'package:xiaoming/src/data/dbUtil.dart'; import 'package:xiaoming/src/data/settingData.dart'; import 'package:xiaoming/src/language/xiaomingLocalizations.dart'; import 'package:xiaoming/src/view/widget/myButtons.dart'; +import 'package:xiaoming/src/view/widget/myTextComposer.dart'; import 'package:xiaoming/src/view/widget/myTextView.dart'; class HomeRoute extends StatefulWidget { @@ -21,18 +20,19 @@ class HomeRoute extends StatefulWidget { class HomeRouteState extends State with TickerProviderStateMixin { TextEditingController _textController; // _textController用来获取输入文本和控制输入焦点 FocusNode _textFocusNode; // _textFocusNode用来控制键盘弹出/收回 - static List _texts = []; //存储消息的列表 + static List _texts; //存储消息的列表 bool _isComposing = false; //判断是否有输入 bool _buttonsIsVisible = false; //控制便捷输入栏显示与隐藏 double tabHeight; //输入框底部高度(防止被底部导航栏遮挡) bool isComplete = true; //计算是否完成 - static bool isUnload = true; //历史消息是否加载 + static bool _isInit = false; UserData ud; ///初始化对象及加载数据 @override void initState() { - if (isUnload) readText(); + super.initState(); + if (!_isInit) readText(); UserData.nowPage = 0; SettingData.readSettingData(); //读取设置数据 _textController = new TextEditingController(); @@ -54,8 +54,6 @@ class HomeRouteState extends State with TickerProviderStateMixin { } }, ); - - super.initState(); } ///home界面布局 @@ -66,93 +64,29 @@ class HomeRouteState extends State with TickerProviderStateMixin { UserData.language = Localizations.localeOf(context).languageCode; tabHeight = MediaQuery.of(context).padding.bottom; //初始化底部导航栏高度 - ///处理发送按钮的点击事件 - void _handleSubmitted(String text) async { - _textController.clear(); - setState(() { - _isComposing = false; - isComplete = false; - }); - String handleText = await ud.handleCommand(text); - DBUtil.addMessage(text); - DBUtil.addMessage(handleText); - TextView textView1 = new TextView( - text: text, - context: context, - animationController: new AnimationController( - duration: new Duration(milliseconds: 200), vsync: this)); - TextView textView2 = new TextView( - text: handleText, - context: context, - animationController: new AnimationController( - duration: new Duration(milliseconds: 200), vsync: this)); - setState(() { - isComplete = true; - _texts.insert(0, textView1); - _texts.insert(0, textView2); - }); - - textView1.animationController.forward(); - textView2.animationController.forward(); - } - - ///输入框和发送按钮 - Widget _textComposer = Row(children: [ - SizedBox( - width: 10.0, - ), - Flexible( - child: CupertinoTextField( - focusNode: _textFocusNode, - maxLines: 1, - placeholder: 'Input Command', - controller: _textController, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(15.0), - border: Border.all( - color: CupertinoColors.inactiveGray, - width: 0.0, - ), - ), - onChanged: (String text) { - setState(() { - _isComposing = text.length > 0; - }); - }, - onSubmitted: _handleSubmitted, - ), - ), - new Container( - margin: new EdgeInsets.symmetric(horizontal: 4.0), - child: new CupertinoButton( - child: new Icon(CupertinoIcons.forward), - onPressed: _isComposing - ? () => _handleSubmitted(_textController.text) - : null, - ), - ), - ]); - ///消息列表,未加载完成时显示加载中动画 Widget _buildList() { - if (isUnload) { + if (!_isInit) { return Center(child: CupertinoActivityIndicator()); } else { if (isComplete) { return Column( children: [ - new Flexible( - child: new GestureDetector( + Flexible( + child: GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { _textFocusNode.unfocus(); }, - child: ListView( - padding: new EdgeInsets.only(left: 5.0), + child: ListView.builder( reverse: true, - children: _texts, + padding: const EdgeInsets.only(left: 5.0), + itemBuilder: (context, index) { + return _texts[index]; + }, + itemCount: _texts.length, ))), - new Divider( + Divider( height: _buttonsIsVisible ? 1.0 : 0.0, color: _buttonsIsVisible ? Colors.black : null, ), @@ -162,7 +96,7 @@ class HomeRouteState extends State with TickerProviderStateMixin { ), child: Container( height: _buttonsIsVisible ? 200.0 : 0.0, - child: _buildButtons(), + child: buildButtons(_handleTextButton), ), ), new Divider(height: 1.0), @@ -170,7 +104,17 @@ class HomeRouteState extends State with TickerProviderStateMixin { decoration: new BoxDecoration( color: Theme.of(context).cardColor, ), - child: _textComposer, + child: TextComposer( + textFocusNode: _textFocusNode, + textController: _textController, + isComposing: _isComposing, + onChanged: (String text) { + setState(() { + _isComposing = text.length > 0; + }); + }, + onSubmitted: _handleSubmitted, + ), ), new SizedBox( height: tabHeight, @@ -244,148 +188,6 @@ class HomeRouteState extends State with TickerProviderStateMixin { ); } - ///创建便捷输入按钮 - Widget _buildTextButton(String label, {double width = 50.0}) { - return LimitedBox( - maxWidth: width, - child: new FlatButton( - padding: const EdgeInsets.all(0.0), - onPressed: () => _handleTextButton(label), - child: new Text(label, style: new TextStyle(fontSize: 14.0)), - ), - ); - } - - ///创建方便输入的按钮栏 - Widget _buildButtons() { - return Column(children: [ - Flexible( - child: CupertinoScrollbar( - child: _buildMethodButtons(), - ), - ), - Divider(height: 1.0), - LimitedBox( - maxHeight: 40, - child: new Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - _buildTextButton(','), - _buildTextButton(';'), - _buildTextButton(':'), - _buildTextButton('['), - _buildTextButton('='), - _buildTextButton('('), - ], - ), - ), - Divider(height: 1.0), - LimitedBox( - maxHeight: 40, - child: new Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - _buildTextButton('^'), - _buildTextButton('+'), - _buildTextButton('-'), - _buildTextButton('*'), - _buildTextButton('/'), - ], - ), - ), - ]); - } - - ///构造方法按钮列表 - Widget _buildMethodButtons() { - return Provide( - builder: (context, child, ud) { - List list = []; - if (ud.userFunctions.isNotEmpty) { - int i = 0; - var blist = []; - ud.userFunctions.forEach((u) { - blist - .add(_buildTextButton(u.funName + '(', width: double.infinity)); - i++; - if (i == 4) { - list.add(Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: blist, - )); - blist.clear(); - i = 0; - } - }); - if (i != 0) { - list.add(Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: blist, - )); - } - } - list - ..add(Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - _buildTextButton('Fun', width: double.infinity), - _buildTextButton('inv(', width: double.infinity), - _buildTextButton('tran(', width: double.infinity), - _buildTextButton('value(', width: double.infinity), - ], - )) - ..add(Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - _buildTextButton('upmat(', width: double.infinity), - _buildTextButton('cofa(', width: double.infinity), - _buildTextButton('calculus(', width: double.infinity), - _buildTextButton('roots(', width: double.infinity), - ], - )) - ..add(Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - _buildTextButton('sum(', width: double.infinity), - _buildTextButton('average(', width: double.infinity), - _buildTextButton('factorial(', width: double.infinity), - _buildTextButton('sin(', width: double.infinity), - ], - )) - ..add(Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - _buildTextButton('cos(', width: double.infinity), - _buildTextButton('tan(', width: double.infinity), - _buildTextButton('asin(', width: double.infinity), - _buildTextButton('acos(', width: double.infinity), - ], - )) - ..add(Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - _buildTextButton('atan(', width: double.infinity), - _buildTextButton('formatDeg(', width: double.infinity), - _buildTextButton('reForDeg(', width: double.infinity), - _buildTextButton('absSum(', width: double.infinity), - ], - )) - ..add(Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - _buildTextButton('absAverage(', width: double.infinity), - _buildTextButton('radToDeg(', width: double.infinity), - _buildTextButton('lagrange(', width: double.infinity), - ], - )); - return ListView( - reverse: true, - children: list, - ); - }, - ); - } - /// 处理便捷输入按钮的点击事件 void _handleTextButton(String text) { int temp = 0; @@ -418,6 +220,34 @@ class HomeRouteState extends State with TickerProviderStateMixin { } } + ///处理发送按钮的点击事件 + void _handleSubmitted(String text) { + _textController.clear(); + setState(() { + _isComposing = false; + isComplete = false; + }); + ud.handleCommand(text).then((handleText) { + DBUtil.addMessage(text); + DBUtil.addMessage(handleText); + TextView textView1 = new TextView( + text: text, + animationController: new AnimationController( + duration: new Duration(milliseconds: 200), vsync: this)); + TextView textView2 = new TextView( + text: handleText, + animationController: new AnimationController( + duration: new Duration(milliseconds: 200), vsync: this)); + setState(() { + _texts.insert(0, textView1); + _texts.insert(0, textView2); + isComplete = true; + }); + textView1.animationController.forward(); + textView2.animationController.forward(); + }); + } + ///退出该路由时释放动画资源 @override void dispose() { @@ -431,21 +261,23 @@ class HomeRouteState extends State with TickerProviderStateMixin { } ///加载数据库中的历史数据 - Future readText() async { - Database db = await DBUtil.getDB(); - var list = await db.rawQuery('select * from Message'); - list.forEach((m) { - var textView = TextView( - context: context, - text: m['msg'], - animationController: AnimationController( - duration: new Duration(milliseconds: 200), vsync: this), - ); - _texts.insert(0, textView); - textView.animationController.forward(); - }); - setState(() { - isUnload = false; + void readText() { + _texts = List(); + DBUtil.getDB().then((db) { + db.rawQuery('select * from Message').then((list) { + setState(() { + list.forEach((m) { + var textView = TextView( + text: m['msg'], + animationController: AnimationController( + duration: new Duration(milliseconds: 200), vsync: this), + ); + _texts.insert(0, textView); + textView.animationController.forward(); + }); + _isInit = true; + }); + }); }); } } diff --git a/lib/src/view/widget/myButtons.dart b/lib/src/view/widget/myButtons.dart index dd7b2e4..0433c75 100644 --- a/lib/src/view/widget/myButtons.dart +++ b/lib/src/view/widget/myButtons.dart @@ -1,9 +1,13 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:provide/provide.dart'; +import 'package:xiaoming/src/data/appData.dart'; import 'package:xiaoming/src/data/settingData.dart'; import 'package:xiaoming/src/language/xiaomingLocalizations.dart'; import 'package:xiaoming/src/view/route/helpRoute.dart'; +typedef OnCommit = void Function(String text); + class DeleteButton extends StatelessWidget { DeleteButton(this.onPressed, {Key key}) : super(key: key); final VoidCallback onPressed; @@ -53,40 +57,40 @@ class _SettingSheetState extends State { @override Widget build(BuildContext context) { return CupertinoActionSheet( - title: Text(XiaomingLocalizations.of(context).decimalDigits), - message: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - CupertinoSlider( - divisions: 8, - max: 9.0, - min: 1.0, - value: SettingData.fixedNum, - onChanged: (double d) { - setState(() { - SettingData.fixedNum = d; - }); - SettingData.writeSettingData(); - }, - ), - Text(SettingData.fixedNum.toString()), - ], - ), - actions: [ - CupertinoActionSheetAction( - onPressed: (){ - Navigator.pop(context); - onPressed(); + title: Text(XiaomingLocalizations.of(context).decimalDigits), + message: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + CupertinoSlider( + divisions: 8, + max: 9.0, + min: 1.0, + value: SettingData.fixedNum, + onChanged: (double d) { + setState(() { + SettingData.fixedNum = d; + }); + SettingData.writeSettingData(); }, - child: const Text("Delete All Message"), - ) + ), + Text(SettingData.fixedNum.toString()), ], - cancelButton: CupertinoActionSheetAction( - child: const Text('Cancel'), - isDefaultAction: true, - onPressed: () => Navigator.pop(context), - ), - ); + ), + actions: [ + CupertinoActionSheetAction( + onPressed: () { + Navigator.pop(context); + onPressed(); + }, + child: const Text("Delete All Message"), + ) + ], + cancelButton: CupertinoActionSheetAction( + child: const Text('Cancel'), + isDefaultAction: true, + onPressed: () => Navigator.pop(context), + ), + ); } } @@ -112,3 +116,144 @@ Widget buildHelpButton(BuildContext context) { }, ); } + +///创建便捷输入按钮 +Widget _buildTextButton(String label, OnCommit onPressed, {double width = 50.0}) { + return LimitedBox( + maxWidth: width, + child: new FlatButton( + padding: const EdgeInsets.all(0.0), + onPressed: () => onPressed(label), + child: new Text(label, style: new TextStyle(fontSize: 14.0)), + ), + ); +} + +///创建方便输入的按钮栏 +Widget buildButtons(OnCommit onPressed) { + return Column(children: [ + Flexible( + child: CupertinoScrollbar( + child: _buildMethodButtons(onPressed), + ), + ), + Divider(height: 1.0), + LimitedBox( + maxHeight: 40, + child: new Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + _buildTextButton(',', onPressed), + _buildTextButton(';', onPressed), + _buildTextButton(':', onPressed), + _buildTextButton('[', onPressed), + _buildTextButton('=', onPressed), + _buildTextButton('(', onPressed), + ], + ), + ), + Divider(height: 1.0), + LimitedBox( + maxHeight: 40, + child: new Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + _buildTextButton('^', onPressed), + _buildTextButton('+', onPressed), + _buildTextButton('-', onPressed), + _buildTextButton('*', onPressed), + _buildTextButton('/', onPressed), + ], + ), + ), + ]); +} + +///构造方法按钮列表 +Widget _buildMethodButtons(OnCommit onPressed) { + return Provide( + builder: (context, child, ud) { + List list = []; + if (ud.userFunctions.isNotEmpty) { + int i = 0; + var blist = []; + ud.userFunctions.forEach((u) { + blist.add(_buildTextButton(u.funName + '(', onPressed, width: double.infinity)); + i++; + if (i == 4) { + list.add(Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: blist, + )); + blist.clear(); + i = 0; + } + }); + if (i != 0) { + list.add(Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: blist, + )); + } + } + list + ..add(Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + _buildTextButton('Fun', onPressed, width: double.infinity), + _buildTextButton('inv(', onPressed, width: double.infinity), + _buildTextButton('tran(', onPressed, width: double.infinity), + _buildTextButton('value(', onPressed, width: double.infinity), + ], + )) + ..add(Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + _buildTextButton('upmat(', onPressed, width: double.infinity), + _buildTextButton('cofa(', onPressed, width: double.infinity), + _buildTextButton('calculus(', onPressed, width: double.infinity), + _buildTextButton('roots(', onPressed, width: double.infinity), + ], + )) + ..add(Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + _buildTextButton('sum(', onPressed, width: double.infinity), + _buildTextButton('average(', onPressed, width: double.infinity), + _buildTextButton('factorial(', onPressed, width: double.infinity), + _buildTextButton('sin(', onPressed, width: double.infinity), + ], + )) + ..add(Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + _buildTextButton('cos(', onPressed, width: double.infinity), + _buildTextButton('tan(', onPressed, width: double.infinity), + _buildTextButton('asin(', onPressed, width: double.infinity), + _buildTextButton('acos(', onPressed, width: double.infinity), + ], + )) + ..add(Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + _buildTextButton('atan(', onPressed, width: double.infinity), + _buildTextButton('formatDeg(', onPressed, width: double.infinity), + _buildTextButton('reForDeg(', onPressed, width: double.infinity), + _buildTextButton('absSum(', onPressed, width: double.infinity), + ], + )) + ..add(Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + _buildTextButton('absAverage(', onPressed, width: double.infinity), + _buildTextButton('radToDeg(', onPressed, width: double.infinity), + _buildTextButton('lagrange(', onPressed, width: double.infinity), + ], + )); + return ListView( + reverse: true, + children: list, + ); + }, + ); +} diff --git a/lib/src/view/widget/myTextComposer.dart b/lib/src/view/widget/myTextComposer.dart new file mode 100644 index 0000000..6fbe351 --- /dev/null +++ b/lib/src/view/widget/myTextComposer.dart @@ -0,0 +1,54 @@ +import 'package:flutter/cupertino.dart'; + +typedef OnChanged = void Function(String text); + +///输入框和发送按钮 +class TextComposer extends StatelessWidget { + TextComposer( + {this.textFocusNode, + this.textController, + this.onChanged, + this.onSubmitted, + this.isComposing}); + + final FocusNode textFocusNode; + final TextEditingController textController; + final OnChanged onChanged; + final OnChanged onSubmitted; + final bool isComposing; + + @override + Widget build(BuildContext context) { + return Row(children: [ + SizedBox( + width: 10.0, + ), + Flexible( + child: CupertinoTextField( + clearButtonMode: OverlayVisibilityMode.editing, + focusNode: textFocusNode, + maxLines: 1, + placeholder: 'Input Command', + controller: textController, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(15.0), + border: Border.all( + color: CupertinoColors.inactiveGray, + width: 0.0, + ), + ), + onChanged: onChanged, + onSubmitted: onSubmitted, + ), + ), + new Container( + margin: new EdgeInsets.symmetric(horizontal: 4.0), + child: new CupertinoButton( + child: new Icon(CupertinoIcons.forward), + onPressed: + isComposing ? () => onSubmitted(textController.text) : null, + ), + ), + ]); + } +} diff --git a/lib/src/view/widget/myTextView.dart b/lib/src/view/widget/myTextView.dart index e11213d..eac5e0f 100644 --- a/lib/src/view/widget/myTextView.dart +++ b/lib/src/view/widget/myTextView.dart @@ -5,8 +5,7 @@ import 'package:xiaoming/src/language/xiaomingLocalizations.dart'; ///单个输出文本的视图 class TextView extends StatelessWidget { - TextView({this.context, this.text, this.animationController}); - final BuildContext context; + TextView({this.text, this.animationController}); final AnimationController animationController; final String text; @@ -31,14 +30,13 @@ class TextView extends StatelessWidget { fontWeight: FontWeight.w400, )), ), - onLongPress: _handleLongPress, + onLongPress: () => _handleLongPress(context), ), ); } - void _handleLongPress() { + void _handleLongPress(context) { Clipboard.setData(new ClipboardData(text: text)); - Navigator.of(context, rootNavigator: true); showDialog( context: context, builder: (BuildContext context) { @@ -48,3 +46,17 @@ class TextView extends StatelessWidget { }); } } + +Widget buildTextListView({Stream stream}) { + List list = []; + return StreamBuilder>( + stream: stream, + builder: (context, snapshot) { + return ListView.builder( + padding: const EdgeInsets.only(left: 5.0), + reverse: true, + itemBuilder: (context, index) => snapshot.data[index], + ); + }, + ); +}