note.dart 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. import 'package:avatar_glow/avatar_glow.dart';
  2. import 'package:flutter/cupertino.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:flutter/widgets.dart';
  5. import 'package:font_awesome_flutter/font_awesome_flutter.dart';
  6. import 'package:keyboard_visibility/keyboard_visibility.dart';
  7. import 'package:trpp/data/data.dart';
  8. import 'package:speech_to_text/speech_to_text.dart';
  9. import 'package:trpp/widgets/popup_dialog.dart';
  10. import 'package:trpp/widgets/toolbar.dart';
  11. const bool NOTESCREEN_MODE_VIEW = false;
  12. const bool NOTESCREEN_MODE_EDIT = true;
  13. class AddNoteScreen extends StatefulWidget {
  14. AddNoteScreen(
  15. {Key key, this.isNew, this.oldNm, this.mode, this.notificationModel})
  16. : super(key: key);
  17. final bool isNew;
  18. final NotesModel oldNm;
  19. final bool mode;
  20. final NotificationModel notificationModel;
  21. @override
  22. State<StatefulWidget> createState() =>
  23. AddNoteScreenState(this, mode, oldNm, isNew, notificationModel);
  24. }
  25. class AddNoteScreenState extends State<AddNoteScreen> {
  26. AddNoteScreenState(
  27. this.widget, this.mode, this.nm, this.isNew, this.notificationModel);
  28. final AddNoteScreen widget;
  29. bool isNew;
  30. bool mode;
  31. NotesModel nm;
  32. SpeechToText _speech;
  33. bool _isListening = false;
  34. bool keyboardIsUp = false;
  35. final TextEditingController contentController = TextEditingController();
  36. AddNotificationDialog addNotificationDialog;
  37. NotificationModel notificationModel;
  38. @override
  39. Widget build(BuildContext context) {
  40. StatelessWidget screen;
  41. if (mode == NOTESCREEN_MODE_VIEW)
  42. screen = new ViewScreen(
  43. mSetState: mSetState,
  44. getText: getText,
  45. handleDelete: handleDelete,
  46. widget: this,
  47. );
  48. else
  49. screen = new EditScreen(handleSave: handleSave, widget: this);
  50. return WillPopScope(
  51. child: Scaffold(
  52. body: SafeArea(
  53. child: Column(
  54. children: [Expanded(child: screen)],
  55. ),
  56. ),
  57. floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
  58. floatingActionButton: Padding(
  59. padding: EdgeInsets.only(right: 8),
  60. child: Row(
  61. mainAxisAlignment: MainAxisAlignment.end,
  62. children: [
  63. MicrophoneButton(
  64. isListening: _isListening,
  65. listen: _listen,
  66. keyboardIsUp: keyboardIsUp,
  67. ),
  68. Visibility(
  69. child: FloatingActionButton(
  70. child: getIconForNotificationBtn(),
  71. onPressed: () => addNotificationDialog.showDialog(),
  72. ),
  73. visible: !keyboardIsUp,
  74. ),
  75. ],
  76. ),
  77. ),
  78. backgroundColor: Theme.of(context).backgroundColor,
  79. ),
  80. onWillPop: onWillPop);
  81. }
  82. Future<bool> onWillPop() async {
  83. Navigator.pop(context, true);
  84. return true;
  85. }
  86. @override
  87. void initState() {
  88. super.initState();
  89. if (!isNew) contentController.text = nm.content;
  90. _speech = SpeechToText();
  91. KeyboardVisibilityNotification().addNewListener(
  92. onChange: (bool visible) {
  93. if (!visible && mode == NOTESCREEN_MODE_EDIT) {
  94. if (isNew)
  95. addNewNote();
  96. else
  97. updateNote();
  98. }
  99. keyboardIsUp = visible;
  100. setState(() {});
  101. },
  102. );
  103. addNotificationDialog =
  104. AddNotificationDialog(context, getResFromPicker, nm, this);
  105. }
  106. Icon getIconForNotificationBtn() {
  107. if (notificationModel == null)
  108. return Icon(FontAwesomeIcons.bell);
  109. else
  110. return Icon(FontAwesomeIcons.solidBell);
  111. }
  112. void getResFromPicker(DateTime dateTime, bool delete) {
  113. setState(() {});
  114. }
  115. String getText() {
  116. String res;
  117. if (nm != null)
  118. res = nm.content;
  119. else
  120. res = "";
  121. return res;
  122. }
  123. void handleSave() async {
  124. if (isNew) {
  125. if (contentController.text != "") {
  126. addNewNote();
  127. }
  128. } else {
  129. updateNote();
  130. }
  131. mode = NOTESCREEN_MODE_VIEW;
  132. setState(() {});
  133. }
  134. void handleDelete() async {
  135. if (nm.id != null) NotesDatabaseService.db.deleteNoteInDB(nm);
  136. Navigator.pop(context, true);
  137. }
  138. void mSetState() {
  139. mode = NOTESCREEN_MODE_EDIT;
  140. setState(() {});
  141. }
  142. void addNewNote() async {
  143. if (contentController.text != "") {
  144. NotesModel newNm =
  145. NotesModel(content: contentController.text, date: DateTime.now());
  146. nm = await NotesDatabaseService.db.addNoteInDB(newNm);
  147. isNew = false;
  148. if (notificationModel != null) notificationModel.note = nm.id;
  149. }
  150. }
  151. void updateNote() {
  152. nm.content = contentController.text;
  153. nm.date = DateTime.now();
  154. NotesDatabaseService.db.updateNoteInDB(nm);
  155. }
  156. void saveObBackBtn() {
  157. if (isNew) {
  158. if (contentController.text != "") {
  159. addNewNote();
  160. }
  161. } else {
  162. updateNote();
  163. }
  164. }
  165. void _listen() async {
  166. if (!_isListening) {
  167. bool available = await _speech.initialize(
  168. onStatus: (val) => print('onStatus: $val'),
  169. onError: (val) => print('onError: $val'),
  170. );
  171. if (available) {
  172. setState(() => _isListening = true);
  173. _speech.listen(
  174. onResult: (val) => setState(() {
  175. if (mode == NOTESCREEN_MODE_VIEW) {
  176. nm.content += val.recognizedWords;
  177. contentController.text = nm.content;
  178. NotesDatabaseService.db.updateNoteInDB(nm);
  179. } else {
  180. contentController.text += val.recognizedWords;
  181. if (isNew)
  182. addNewNote();
  183. else
  184. updateNote();
  185. }
  186. //if (val.hasConfidenceRating && val.confidence > 0) {
  187. //_confidence = val.confidence;
  188. //}
  189. }),
  190. );
  191. }
  192. } else {
  193. setState(() => _isListening = false);
  194. _speech.stop();
  195. }
  196. }
  197. }
  198. class EditScreen extends StatelessWidget {
  199. EditScreen({this.handleSave, this.widget});
  200. final Function handleSave;
  201. final AddNoteScreenState widget;
  202. @override
  203. Widget build(BuildContext context) {
  204. return Column(
  205. children: [
  206. CustomToolbar(
  207. title: 'Edit Note',
  208. icon: FontAwesomeIcons.solidSave,
  209. onPressed: () {
  210. handleSave();
  211. },
  212. additionalBack: widget.saveObBackBtn,
  213. ),
  214. Expanded(
  215. child: CustomTextField(
  216. maxLines: 50,
  217. hintText: 'Note',
  218. controller: widget.contentController),
  219. ),
  220. ],
  221. );
  222. }
  223. }
  224. class ViewScreen extends StatelessWidget {
  225. ViewScreen({this.mSetState, this.getText, this.handleDelete, this.widget});
  226. final Function mSetState;
  227. final Function getText;
  228. final Function handleDelete;
  229. final AddNoteScreenState widget;
  230. @override
  231. Widget build(BuildContext context) {
  232. return Column(
  233. children: [
  234. CustomToolbar(
  235. title: 'View Note',
  236. icon: FontAwesomeIcons.trash,
  237. onPressed: () {
  238. handleDelete();
  239. },
  240. additionalBack: widget.saveObBackBtn,
  241. ),
  242. GestureDetector(
  243. onTap: () => mSetState(),
  244. child: ReadingTextField(
  245. text: getText(),
  246. fontWeight: FontWeight.w400,
  247. fontSize: 22,
  248. ),
  249. ),
  250. ],
  251. );
  252. }
  253. }
  254. class CustomTextField extends StatelessWidget {
  255. final int maxLines;
  256. final String hintText;
  257. final TextEditingController controller;
  258. CustomTextField({this.maxLines, this.hintText, this.controller});
  259. @override
  260. Widget build(BuildContext context) {
  261. return Padding(
  262. padding: const EdgeInsets.all(15),
  263. child: TextField(
  264. style: TextStyle(color: Theme.of(context).primaryColor),
  265. controller: controller,
  266. maxLines: maxLines,
  267. autofocus: true,
  268. decoration: InputDecoration(hintText: hintText),
  269. onChanged: (input) {
  270. if (input != null) {
  271. // TODO save data
  272. }
  273. },
  274. ),
  275. );
  276. }
  277. }
  278. class MicrophoneButton extends StatelessWidget {
  279. final bool isListening;
  280. final Function listen;
  281. final bool keyboardIsUp;
  282. MicrophoneButton({this.isListening, this.listen, this.keyboardIsUp});
  283. @override
  284. Widget build(BuildContext context) {
  285. return Visibility(
  286. child: AvatarGlow(
  287. animate: isListening,
  288. glowColor: Theme.of(context).primaryColor,
  289. endRadius: 75.0,
  290. duration: const Duration(milliseconds: 2000),
  291. repeatPauseDuration: const Duration(milliseconds: 100),
  292. repeat: true,
  293. child: FloatingActionButton(
  294. heroTag: null,
  295. onPressed: listen,
  296. child: Icon(isListening ? Icons.mic : Icons.mic_none),
  297. ),
  298. ),
  299. visible: !keyboardIsUp,
  300. );
  301. }
  302. }
  303. class ReadingTextField extends StatelessWidget {
  304. final String text;
  305. final double fontSize;
  306. final FontWeight fontWeight;
  307. ReadingTextField({this.text, this.fontSize, this.fontWeight});
  308. @override
  309. Widget build(BuildContext context) {
  310. return Padding(
  311. padding: const EdgeInsets.symmetric(horizontal: 20),
  312. child: TextField(
  313. enabled: false,
  314. maxLines: null,
  315. controller: TextEditingController(text: text),
  316. decoration: InputDecoration(fillColor: Colors.transparent),
  317. style: TextStyle(
  318. fontSize: fontSize,
  319. fontWeight: fontWeight,
  320. color: Theme.of(context).primaryColor),
  321. ),
  322. );
  323. }
  324. }