Simple Notes: General Refactor

master
EmaMaker 2021-09-26 15:13:04 +00:00
parent 85c7b1909e
commit 6fd3e0379d
5 changed files with 276 additions and 328 deletions

View File

@ -1,196 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:notes_app/components/storage.dart';
import 'package:path/path.dart';
import 'dart:io';
class MyListTile extends StatefulWidget {
MyListTile(
{Key? key,
required this.file,
required this.storage,
required this.updateFunction,
required this.deleteFunction,
required this.toggleFunction,
required this.selectFunction,
required this.selectMode,
required this.isChecked})
: super(key: key);
final File file;
final CounterStorage storage;
final Function updateFunction;
final Function toggleFunction;
final Function deleteFunction;
final Function selectFunction;
final bool selectMode;
bool isChecked;
@override
MyListTileState createState() => MyListTileState();
}
class MyListTileState extends State<MyListTile> {
final _biggerFont = const TextStyle(fontSize: 18);
late TextEditingController _controller;
@override
void initState() {
super.initState();
_controller = TextEditingController();
}
@override
Widget build(BuildContext context) {
// print("${widget.isChecked} / ${widget.file}");
return widget.selectMode
? CheckboxListTile(
title: Text(basename(widget.file.path)),
checkColor: Colors.white,
value: widget.isChecked,
onChanged: (bool? value) {
setState(() {
widget.toggleFunction(widget.file, widget.isChecked);
});
})
: ListTile(
title: Text(
basename(widget.file.path),
style: _biggerFont,
),
onTap: () =>
widget.storage.openNote(context, basename(widget.file.path)),
onLongPress: () {
widget.toggleFunction(widget.file, true);
widget.selectFunction();
},
// onTap: _handleNote,
subtitle: _subtitle(widget.file),
trailing: btnListTileMore(context, widget.file),
);
}
DropdownButton btnListTileMore(BuildContext context, File f) {
return DropdownButton<String>(
icon: const Icon(Icons.more_vert_outlined),
onChanged: (String? newValue) {
switch (newValue) {
case "Delete":
_deleteDialog(context, f);
break;
case "Rename":
_changeTitleDialog(context, f.path);
break;
}
setState(() {});
},
underline: Container(color: Colors.transparent),
items: <String>['Rename', 'Delete']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
);
}
/* DIALOGS */
void _changeTitleDialog(BuildContext context, String path) {
// debugdebugPrint("Clicked title");
showDialog(
context: context,
builder: (BuildContext ctx) {
return AlertDialog(
title: Text('Rename note:'),
content: TextField(
controller: _controller,
maxLines: 1,
decoration: InputDecoration(
hintText: basename(path),
),
),
actions: [
TextButton(
onPressed: () {
// Return to previous screen
Navigator.pop(context);
_controller.text = "";
widget.updateFunction();
// Remove the box
},
child: Text('No')),
TextButton(
onPressed: () {
if (_controller.text != "") {
Navigator.pop(context);
widget.toggleFunction(widget.file, false);
widget.storage.renameNote(
basename(widget.file.path), _controller.text);
_controller.text = "";
}
},
child: Text('Yes')),
],
);
});
}
void _deleteDialog(BuildContext context, File f) {
// debugdebugPrint("Clicked title");
showDialog(
context: context,
builder: (BuildContext ctx) {
return AlertDialog(
title: Text('Delete note'),
content: Text(
"Are you sure you want to delete this note? This action cannot be undone!"),
actions: [
TextButton(
onPressed: () {
// Remove the box
// Return to previous screen
Navigator.pop(context);
setState(() {});
widget.updateFunction();
},
child: Text('Cancel')),
TextButton(
onPressed: () {
Navigator.pop(context);
//Return to previous screen
setState(() {});
widget.deleteFunction(widget.file);
},
child: Text('Ok')),
],
);
});
}
Widget _subtitle(File f) {
try {
return Text(_lastEdited(f.lastModifiedSync()));
} catch (e) {
return Text("");
}
}
String _lastEdited(DateTime now) {
return "Last edited: ${now.year.toString()}-${now.month.toString().padLeft(2, '0')}-${now.day.toString().padLeft(2, '0')} at ${now.hour.toString().padLeft(2, '0')}:${now.minute.toString().padLeft(2, '0')}";
}
Color getColor(Set<MaterialState> states) {
const Set<MaterialState> interactiveStates = <MaterialState>{
MaterialState.pressed,
MaterialState.hovered,
MaterialState.focused,
};
if (states.any(interactiveStates.contains)) {
return Colors.blue;
}
return Colors.red;
}
}

View File

@ -1,10 +1,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:notes_app/components/storage.dart';
import 'package:notes_app/screens/home/components/MyListTile.dart';
import 'package:notes_app/screens/settings/settings.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:notes_app/components/storage.dart';
import 'package:notes_app/screens/settings/settings.dart';
import 'package:path/path.dart';
import 'dart:io'; import 'dart:io';
class MyHomePage extends StatefulWidget { class MyHomePage extends StatefulWidget {
@ -18,12 +18,15 @@ class MyHomePage extends StatefulWidget {
class _MyHomePageState extends State<MyHomePage> { class _MyHomePageState extends State<MyHomePage> {
List<File> _allFilesNames = []; List<File> _allFilesNames = [];
List<String> _selected = []; List<String> _selected = [];
bool selectMode = false;
String _sortBy = ""; String _sortBy = "";
late TextEditingController _controller;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_controller = TextEditingController();
} }
void getSortBy() async { void getSortBy() async {
@ -44,7 +47,7 @@ class _MyHomePageState extends State<MyHomePage> {
centerTitle: true, centerTitle: true,
toolbarHeight: 50, toolbarHeight: 50,
actions: selectMode actions: selectMode
? [btnAppBarMoreSelect()] ? [btnAppBarMoreSelect(context)]
: [btnAppBarMoreNoSelect(context)], : [btnAppBarMoreNoSelect(context)],
), ),
body: FutureBuilder<List<File>>( body: FutureBuilder<List<File>>(
@ -89,7 +92,46 @@ class _MyHomePageState extends State<MyHomePage> {
}); });
} }
bool selectMode = false; Widget _buildList(BuildContext context) {
sortFiles();
final tiles = _allFilesNames.map(
(
File file,
) {
return selectMode
? CheckboxListTile(
title: Text(basename(file.path)),
checkColor: Colors.white,
value: _selected.contains(file.path),
onChanged: (bool? value) {
toggleFile(file);
})
: ListTile(
title: Text(
basename(file.path),
style: TextStyle(fontSize: 18),
),
onTap: () =>
widget.storage.openNote(context, basename(file.path)),
onLongPress: () {
_selected.add(file.path);
enterSelectMode();
},
subtitle: _subtitle(file),
trailing: btnListTileMore(context, file),
);
},
);
final divided = tiles.isNotEmpty
? ListTile.divideTiles(context: context, tiles: tiles).toList()
: <Widget>[];
return ListView(
padding: const EdgeInsets.all(8),
children: divided,
);
}
/* --------------------------------------- UTILITY FUNCTIONS ------------------------------------------- */
void sortFiles() { void sortFiles() {
if (_sortBy == "Name") { if (_sortBy == "Name") {
@ -103,30 +145,16 @@ class _MyHomePageState extends State<MyHomePage> {
} }
} }
Widget _buildList(BuildContext context) { Widget _subtitle(File f) {
sortFiles(); try {
final tiles = _allFilesNames.map( return Text(_lastEdited(f.lastModifiedSync()));
( } catch (e) {
File f, return Text("");
) { }
return new MyListTile( }
file: f,
selectMode: selectMode, String _lastEdited(DateTime now) {
storage: widget.storage, return "Last edited: ${now.year.toString()}-${now.month.toString().padLeft(2, '0')}-${now.day.toString().padLeft(2, '0')} at ${now.hour.toString().padLeft(2, '0')}:${now.minute.toString().padLeft(2, '0')}";
selectFunction: enterSelectMode,
updateFunction: updateChildren,
toggleFunction: toggleFile,
deleteFunction: _deleteFile,
isChecked: _selected.contains(f.path));
},
);
final divided = tiles.isNotEmpty
? ListTile.divideTiles(context: context, tiles: tiles).toList()
: <Widget>[];
return ListView(
padding: const EdgeInsets.all(8),
children: divided,
);
} }
void enterSelectMode() { void enterSelectMode() {
@ -142,16 +170,11 @@ class _MyHomePageState extends State<MyHomePage> {
}); });
} }
void updateChildren() { void toggleFile(File file) {
setState(() {}); if (_selected.contains(file.path))
} _selected.remove(file.path);
void toggleFile(File f, bool b) {
if (_selected.contains(f.path))
_selected.remove(f.path);
else else
_selected.add(f.path); _selected.add(file.path);
setState(() {});
} }
void _deleteFile(File f) { void _deleteFile(File f) {
@ -164,16 +187,17 @@ class _MyHomePageState extends State<MyHomePage> {
exitSelectMode(); exitSelectMode();
} }
/* DROP DOWN MENUS*/ /* --------------------------------------- DROP DOWN MENUS ------------------------------------------- */
DropdownButton btnAppBarMoreSelect() { /* APPBAR MORE (SELECT)*/
DropdownButton btnAppBarMoreSelect(BuildContext context) {
return DropdownButton<String>( return DropdownButton<String>(
icon: const Icon(Icons.more_vert), icon: const Icon(Icons.more_vert),
onChanged: (String? newValue) { onChanged: (String? newValue) {
switch (newValue) { switch (newValue) {
case "Delete": case "Delete Selected":
_deleteDialog(context); _deleteAllDialog(context);
break; break;
case "Cancel": case "Exit Select Mode":
exitSelectMode(); exitSelectMode();
break; break;
case "Select All": case "Select All":
@ -202,11 +226,11 @@ class _MyHomePageState extends State<MyHomePage> {
}, },
underline: Container(color: Colors.transparent), underline: Container(color: Colors.transparent),
items: <String>[ items: <String>[
"Delete", "Delete Selected",
"Select All", "Select All",
"Deselect All", "Deselect All",
"Toggle Selected", "Toggle Selected",
"Cancel", "Exit Select Mode",
].map<DropdownMenuItem<String>>((String value) { ].map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>( return DropdownMenuItem<String>(
value: value, value: value,
@ -215,7 +239,9 @@ class _MyHomePageState extends State<MyHomePage> {
}).toList(), }).toList(),
); );
} }
/* --------------------- */
/* APPBAR MORE (NO SELECT)*/
DropdownButton btnAppBarMoreNoSelect(BuildContext context) { DropdownButton btnAppBarMoreNoSelect(BuildContext context) {
return DropdownButton<String>( return DropdownButton<String>(
icon: const Icon(Icons.more_vert), icon: const Icon(Icons.more_vert),
@ -245,7 +271,76 @@ class _MyHomePageState extends State<MyHomePage> {
); );
} }
void _deleteDialog(BuildContext context) { /* TILE MORE */
DropdownButton btnListTileMore(BuildContext context, File f) {
return DropdownButton<String>(
icon: const Icon(Icons.more_vert_outlined),
onChanged: (String? newValue) {
switch (newValue) {
case "Delete":
_deleteSingleDialog(context, f);
break;
case "Rename":
_changeTitleDialog(context, f.path);
break;
}
setState(() {});
},
underline: Container(color: Colors.transparent),
items: <String>['Rename', 'Delete']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
);
}
/* --------------------- */
/* --------------------------------------- DIALOGS ------------------------------------------- */
/* RENAME DIALOG */
void _changeTitleDialog(BuildContext context, String path) {
// debugdebugPrint("Clicked title");
showDialog(
context: context,
builder: (BuildContext ctx) {
return AlertDialog(
title: Text('Rename note:'),
content: TextField(
controller: _controller,
maxLines: 1,
decoration: InputDecoration(
hintText: basename(path),
),
),
actions: [
TextButton(
onPressed: () {
// Return to previous screen
Navigator.pop(context);
_controller.text = "";
},
child: Text('No')),
TextButton(
onPressed: () {
if (_controller.text != "") {
Navigator.pop(context);
_selected.remove(path);
widget.storage
.renameNote(basename(path), _controller.text);
_controller.text = "";
}
},
child: Text('Yes')),
],
);
});
}
/* --------------------- */
/* DELETE MULTIPLE DIALOG */
void _deleteAllDialog(BuildContext context) {
// debugdebugPrint("Clicked title"); // debugdebugPrint("Clicked title");
showDialog( showDialog(
context: context, context: context,
@ -261,7 +356,6 @@ class _MyHomePageState extends State<MyHomePage> {
// Return to previous screen // Return to previous screen
Navigator.pop(context); Navigator.pop(context);
setState(() {}); setState(() {});
updateChildren();
}, },
child: Text('Cancel')), child: Text('Cancel')),
TextButton( TextButton(
@ -280,4 +374,37 @@ class _MyHomePageState extends State<MyHomePage> {
); );
}); });
} }
/* --------------------- */
/* DELETE SINGLE DIALOG */
void _deleteSingleDialog(BuildContext context, File f) {
showDialog(
context: context,
builder: (BuildContext ctx) {
return AlertDialog(
title: Text('Delete note'),
content: Text(
"Are you sure you want to delete this note? This action cannot be undone!"),
actions: [
TextButton(
onPressed: () {
// Remove the box
// Return to previous screen
Navigator.pop(context);
setState(() {});
},
child: Text('Cancel')),
TextButton(
onPressed: () {
Navigator.pop(context);
//Return to previous screen
setState(() {});
_deleteFile(f);
},
child: Text('Ok')),
],
);
});
}
/* --------------------- */
} }

View File

@ -42,6 +42,12 @@ class _NewNoteState extends State<NewNote> {
} }
} }
@override
void dispose() {
_controllerNote.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return new WillPopScope( return new WillPopScope(
@ -82,9 +88,11 @@ class _NewNoteState extends State<NewNote> {
}); });
} }
/* --------------------------------------- DIALOGS ------------------------------------------- */
/* RENAME DIALOG */
void _changeTitleDialog(BuildContext context) { void _changeTitleDialog(BuildContext context) {
// debugdebugPrint("Clicked title"); // debugdebugPrint("Clicked title");
showDialog ( showDialog(
context: context, context: context,
builder: (BuildContext ctx) { builder: (BuildContext ctx) {
return AlertDialog( return AlertDialog(
@ -111,10 +119,8 @@ class _NewNoteState extends State<NewNote> {
setState(() { setState(() {
Navigator.pop(context); Navigator.pop(context);
//Note: code repetition //Note: code repetition
if(_title != _controller.text){ if (_title != _controller.text) {
_changed = false; _save(rename: true, newname: _controller.text);
widget.storage.saveRename(_title, _controllerNote.text, _controller.text);
_title = _controller.text;
_controller.text = ""; _controller.text = "";
} }
@ -126,7 +132,9 @@ class _NewNoteState extends State<NewNote> {
); );
}); });
} }
/* --------------------- */
/* DELETE DIALOG */
void _deleteDialog(BuildContext context) { void _deleteDialog(BuildContext context) {
if (_changed) if (_changed)
showDialog( showDialog(
@ -167,7 +175,9 @@ class _NewNoteState extends State<NewNote> {
else else
_toPrevious(); _toPrevious();
} }
/* --------------------- */
/* --------------------------------------- UTILITY FUNCTIONS ------------------------------------------- */
void _toPrevious() { void _toPrevious() {
Navigator.pushReplacement( Navigator.pushReplacement(
context, context,
@ -175,22 +185,20 @@ class _NewNoteState extends State<NewNote> {
builder: (context) => MyHomePage(storage: widget.storage))); builder: (context) => MyHomePage(storage: widget.storage)));
} }
void _save() { void _save({bool rename = false, String newname = ""}) {
_changed = false; setState(() {
_changed = false;
widget.storage.saveNote(_title, _controllerNote.text); if (rename) {
widget.storage.saveRename(_title, _controllerNote.text, newname);
setState(() {}); _title = newname;
} else
widget.storage.saveNote(_title, _controllerNote.text);
});
} }
void _onChange(String s) { void _onChange(String s) {
_changed = true; setState(() {
setState(() {}); _changed = true;
} });
@override
void dispose() {
_controllerNote.dispose();
super.dispose();
} }
} }

View File

@ -13,6 +13,9 @@ class Settings extends StatefulWidget {
} }
class _SettingsState extends State<Settings> { class _SettingsState extends State<Settings> {
String _theme = "";
String _sortBy = "";
@override @override
void initState() { void initState() {
getTheme(); getTheme();
@ -21,31 +24,9 @@ class _SettingsState extends State<Settings> {
super.initState(); super.initState();
} }
String _theme = ""; @override
String _sortBy = ""; void dispose() {
super.dispose();
void getTheme() async {
final savedThemeMode = await AdaptiveTheme.getThemeMode();
setState(() {
switch (savedThemeMode) {
case AdaptiveThemeMode.dark:
_theme = "Dark";
break;
case AdaptiveThemeMode.light:
_theme = "Light";
break;
default:
_theme = "Follow System";
break;
}
});
}
void getSortBy() async {
final prefs = await SharedPreferences.getInstance();
setState(() {
_sortBy = prefs.getString("sortBy") ?? "Name";
});
} }
@override @override
@ -97,6 +78,7 @@ class _SettingsState extends State<Settings> {
); );
} }
/* --------------------------------------- UTLITY FUNCTIONS ------------------------------------------- */
void _toPrevious() { void _toPrevious() {
Navigator.pushReplacement( Navigator.pushReplacement(
context, context,
@ -104,37 +86,6 @@ class _SettingsState extends State<Settings> {
builder: (context) => MyHomePage(storage: widget.storage))); builder: (context) => MyHomePage(storage: widget.storage)));
} }
void _sortByDialog(BuildContext context) {
showDialog(
context: context,
builder: (BuildContext ctx) {
return SimpleDialog(
title: const Text('Choose theme'),
children: <Widget>[
_radioListTile("Name", "Name", _sortBy, _setSortBy),
_radioListTile(
"Last Modified", "Last Modified", _sortBy, _setSortBy),
],
);
});
}
void _themeDialog(BuildContext context) {
showDialog(
context: context,
builder: (BuildContext ctx) {
return SimpleDialog(
title: const Text('Choose theme'),
children: <Widget>[
_radioListTile(
"Follow System", "Follow System", _theme, _setTheme),
_radioListTile("Dark", "Dark", _theme, _setTheme),
_radioListTile("Light", "Light", _theme, _setTheme),
],
);
});
}
RadioListTile _radioListTile( RadioListTile _radioListTile(
String title, String value, String groupValue, Function(dynamic) f) { String title, String value, String groupValue, Function(dynamic) f) {
return new RadioListTile( return new RadioListTile(
@ -146,6 +97,32 @@ class _SettingsState extends State<Settings> {
}); });
} }
/* --------------------------------------- GETTERS ------------------------------------------- */
void getTheme() async {
final savedThemeMode = await AdaptiveTheme.getThemeMode();
setState(() {
switch (savedThemeMode) {
case AdaptiveThemeMode.dark:
_theme = "Dark";
break;
case AdaptiveThemeMode.light:
_theme = "Light";
break;
default:
_theme = "Follow System";
break;
}
});
}
void getSortBy() async {
final prefs = await SharedPreferences.getInstance();
setState(() {
_sortBy = prefs.getString("sortBy") ?? "Name";
});
}
/* --------------------------------------- SETTERS ------------------------------------------- */
void _setTheme(dynamic newTheme) { void _setTheme(dynamic newTheme) {
// final prefs = await SharedPreferences.getInstance(); // final prefs = await SharedPreferences.getInstance();
@ -179,6 +156,43 @@ class _SettingsState extends State<Settings> {
}); });
} }
/* --------------------------------------- DIALOGS ------------------------------------------- */
/* SORT BY DIALOG */
void _sortByDialog(BuildContext context) {
showDialog(
context: context,
builder: (BuildContext ctx) {
return SimpleDialog(
title: const Text('Choose theme'),
children: <Widget>[
_radioListTile("Name", "Name", _sortBy, _setSortBy),
_radioListTile(
"Last Modified", "Last Modified", _sortBy, _setSortBy),
],
);
});
}
/* --------------------- */
/* THEME DIALOG */
void _themeDialog(BuildContext context) {
showDialog(
context: context,
builder: (BuildContext ctx) {
return SimpleDialog(
title: const Text('Choose theme'),
children: <Widget>[
_radioListTile(
"Follow System", "Follow System", _theme, _setTheme),
_radioListTile("Dark", "Dark", _theme, _setTheme),
_radioListTile("Light", "Light", _theme, _setTheme),
],
);
});
}
/* --------------------- */
/* ABOUT DIALOG */
void _aboutDialog(BuildContext context) { void _aboutDialog(BuildContext context) {
showDialog( showDialog(
context: context, context: context,
@ -191,9 +205,4 @@ class _SettingsState extends State<Settings> {
); );
}); });
} }
@override
void dispose() {
super.dispose();
}
} }

View File

@ -14,7 +14,7 @@ packages:
name: async name: async
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.6.1" version: "2.8.1"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
@ -35,7 +35,7 @@ packages:
name: charcode name: charcode
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.2.0" version: "1.3.1"
clock: clock:
dependency: transitive dependency: transitive
description: description:
@ -113,7 +113,7 @@ packages:
name: meta name: meta
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.3.0" version: "1.7.0"
path: path:
dependency: transitive dependency: transitive
description: description:
@ -265,7 +265,7 @@ packages:
name: test_api name: test_api
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.3.0" version: "0.4.2"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description: