note.dart 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  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. /// Saves note content correctly
  124. void handleSave() async {
  125. if (isNew) {
  126. if (contentController.text != "") {
  127. addNewNote();
  128. }
  129. } else {
  130. updateNote();
  131. }
  132. mode = NOTESCREEN_MODE_VIEW;
  133. setState(() {});
  134. }
  135. /// Deletes note content correctly
  136. void handleDelete() async {
  137. if (nm.id != null) NotesDatabaseService.db.deleteNoteInDB(nm);
  138. Navigator.pop(context, true);
  139. }
  140. void mSetState() {
  141. mode = NOTESCREEN_MODE_EDIT;
  142. setState(() {});
  143. }
  144. /// Adds new note content correctly
  145. void addNewNote() async {
  146. if (contentController.text != "") {
  147. NotesModel newNm =
  148. NotesModel(content: contentController.text, date: DateTime.now());
  149. nm = await NotesDatabaseService.db.addNoteInDB(newNm);
  150. isNew = false;
  151. if (notificationModel != null) notificationModel.note = nm.id;
  152. }
  153. }
  154. /// Updates note in db
  155. void updateNote() {
  156. nm.content = contentController.text;
  157. nm.date = DateTime.now();
  158. NotesDatabaseService.db.updateNoteInDB(nm);
  159. }
  160. void saveObBackBtn() {
  161. if (isNew) {
  162. if (contentController.text != "") {
  163. addNewNote();
  164. }
  165. } else {
  166. updateNote();
  167. }
  168. }
  169. /// Starts listening
  170. void _listen() async {
  171. if (!_isListening) {
  172. bool available = await _speech.initialize(
  173. onStatus: (val) => print('onStatus: $val'),
  174. onError: (val) => print('onError: $val'),
  175. );
  176. if (available) {
  177. setState(() => _isListening = true);
  178. _speech.listen(
  179. onResult: (val) => setState(() {
  180. if (mode == NOTESCREEN_MODE_VIEW) {
  181. nm.content += val.recognizedWords;
  182. contentController.text = nm.content;
  183. NotesDatabaseService.db.updateNoteInDB(nm);
  184. } else {
  185. contentController.text += val.recognizedWords;
  186. if (isNew)
  187. addNewNote();
  188. else
  189. updateNote();
  190. }
  191. //if (val.hasConfidenceRating && val.confidence > 0) {
  192. //_confidence = val.confidence;
  193. //}
  194. }),
  195. );
  196. }
  197. } else {
  198. setState(() => _isListening = false);
  199. _speech.stop();
  200. }
  201. }
  202. }
  203. class EditScreen extends StatelessWidget {
  204. EditScreen({this.handleSave, this.widget});
  205. final Function handleSave;
  206. final AddNoteScreenState widget;
  207. @override
  208. Widget build(BuildContext context) {
  209. return Column(
  210. children: [
  211. CustomToolbar(
  212. title: 'Edit Note',
  213. icon: FontAwesomeIcons.solidSave,
  214. onPressed: () {
  215. handleSave();
  216. },
  217. additionalBack: widget.saveObBackBtn,
  218. ),
  219. Expanded(
  220. child: CustomTextField(
  221. maxLines: 50,
  222. hintText: 'Note',
  223. controller: widget.contentController),
  224. ),
  225. ],
  226. );
  227. }
  228. }
  229. class ViewScreen extends StatelessWidget {
  230. ViewScreen({this.mSetState, this.getText, this.handleDelete, this.widget});
  231. final Function mSetState;
  232. final Function getText;
  233. final Function handleDelete;
  234. final AddNoteScreenState widget;
  235. @override
  236. Widget build(BuildContext context) {
  237. return Column(
  238. children: [
  239. CustomToolbar(
  240. title: 'View Note',
  241. icon: FontAwesomeIcons.trash,
  242. onPressed: () {
  243. handleDelete();
  244. },
  245. additionalBack: widget.saveObBackBtn,
  246. ),
  247. GestureDetector(
  248. onTap: () => mSetState(),
  249. child: ReadingTextField(
  250. text: getText(),
  251. fontWeight: FontWeight.w400,
  252. fontSize: 22,
  253. ),
  254. ),
  255. ],
  256. );
  257. }
  258. }
  259. class CustomTextField extends StatelessWidget {
  260. final int maxLines;
  261. final String hintText;
  262. final TextEditingController controller;
  263. CustomTextField({this.maxLines, this.hintText, this.controller});
  264. @override
  265. Widget build(BuildContext context) {
  266. return Padding(
  267. padding: const EdgeInsets.all(15),
  268. child: TextField(
  269. style: TextStyle(color: Theme.of(context).primaryColor),
  270. controller: controller,
  271. maxLines: maxLines,
  272. autofocus: true,
  273. decoration: InputDecoration(hintText: hintText),
  274. onChanged: (input) {
  275. if (input != null) {
  276. // TODO save data
  277. }
  278. },
  279. ),
  280. );
  281. }
  282. }
  283. class MicrophoneButton extends StatelessWidget {
  284. final bool isListening;
  285. final Function listen;
  286. final bool keyboardIsUp;
  287. MicrophoneButton({this.isListening, this.listen, this.keyboardIsUp});
  288. @override
  289. Widget build(BuildContext context) {
  290. return Visibility(
  291. child: AvatarGlow(
  292. animate: isListening,
  293. glowColor: Theme.of(context).primaryColor,
  294. endRadius: 75.0,
  295. duration: const Duration(milliseconds: 2000),
  296. repeatPauseDuration: const Duration(milliseconds: 100),
  297. repeat: true,
  298. child: FloatingActionButton(
  299. heroTag: null,
  300. onPressed: listen,
  301. child: Icon(isListening ? Icons.mic : Icons.mic_none),
  302. ),
  303. ),
  304. visible: !keyboardIsUp,
  305. );
  306. }
  307. }
  308. class ReadingTextField extends StatelessWidget {
  309. final String text;
  310. final double fontSize;
  311. final FontWeight fontWeight;
  312. ReadingTextField({this.text, this.fontSize, this.fontWeight});
  313. @override
  314. Widget build(BuildContext context) {
  315. return Padding(
  316. padding: const EdgeInsets.symmetric(horizontal: 20),
  317. child: TextField(
  318. enabled: false,
  319. maxLines: null,
  320. controller: TextEditingController(text: text),
  321. decoration: InputDecoration(fillColor: Colors.transparent),
  322. style: TextStyle(
  323. fontSize: fontSize,
  324. fontWeight: fontWeight,
  325. color: Theme.of(context).primaryColor),
  326. ),
  327. );
  328. }
  329. }