made task creation flow

This commit is contained in:
Kima 2024-05-05 21:11:13 +02:00
parent 7488c9abdd
commit d915200faa
10 changed files with 284 additions and 3 deletions

View File

@ -7,17 +7,23 @@ import 'package:provider/provider.dart';
class SelfNoteProvider with ChangeNotifier {
late List<SelfNote> _notes;
late List<TodoItem> _todoItems;
late BuildContext _context;
List<SelfNote> get notes => _notes;
List<TodoItem> get todos => _todoItems;
SelfNoteProvider({
List<SelfNote> initialNotes = const [],
List<TodoItem> initialTodoItems = const [],
required BuildContext context,
}) {
_notes = List.castFrom(initialNotes);
_todoItems = List.castFrom(initialTodoItems);
_context = context;
if (_notes.isEmpty) restore();
if (_todoItems.isEmpty) restoreTodo();
}
// restore self notes from db
@ -38,6 +44,24 @@ class SelfNoteProvider with ChangeNotifier {
}
}
// restore todo items from db
Future<void> restoreTodo() async {
String? userId = Provider.of<UserProvider>(_context, listen: false).id;
// await Provider.of<DatabaseProvider>(_context, listen: false)
// .userStore
// .storeSelfNotes([], userId: userId!);
// load self notes from db
if (userId != null) {
var dbTodo = await Provider.of<DatabaseProvider>(_context, listen: false)
.userQuery
.getTodoItems(userId: userId);
_todoItems = dbTodo;
notifyListeners();
}
}
// fetches fresh data from api (not needed, cuz no api for that)
// Future<void> fetch() async {
// }
@ -54,4 +78,17 @@ class SelfNoteProvider with ChangeNotifier {
_notes = notes;
notifyListeners();
}
// store todo items in db
Future<void> storeTodo(List<TodoItem> todos) async {
User? user = Provider.of<UserProvider>(_context, listen: false).user;
if (user == null) throw "Cannot store Self Notes for User null";
String userId = user.id;
await Provider.of<DatabaseProvider>(_context, listen: false)
.userStore
.storeSelfTodoItems(todos, userId: userId);
_todoItems = todos;
notifyListeners();
}
}

View File

@ -84,7 +84,7 @@ const userDataDB = DatabaseStruct("user_data", {
"goal_befores": String,
"goal_pin_dates": String,
// todo and notes
"todo_items": String, "self_notes": String,
"todo_items": String, "self_notes": String, "self_todo": String,
// v5 shit
"roundings": String,
"grade_rarities": String,
@ -152,7 +152,7 @@ Future<Database> initDB(DatabaseProvider database) async {
"goal_befores": "{}",
"goal_pin_dates": "{}",
// todo and notes
"todo_items": "{}", "self_notes": "[]",
"todo_items": "{}", "self_notes": "[]", "self_todo": "[]",
// v5 shit
"roundings": "{}",
"grade_rarities": "{}",

View File

@ -317,6 +317,18 @@ class UserDatabaseQuery {
return selfNotes;
}
Future<List<TodoItem>> getTodoItems({required String userId}) async {
List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return [];
String? todoItemsJson = userData.elementAt(0)["self_todo"] as String?;
if (todoItemsJson == null) return [];
List<TodoItem> todoItems = (jsonDecode(todoItemsJson) as List)
.map((e) => TodoItem.fromJson(e))
.toList();
return todoItems;
}
// v5
Future<Map<String, String>> getRoundings({required String userId}) async {
List<Map> userData =

View File

@ -196,6 +196,13 @@ class UserDatabaseStore {
where: "id = ?", whereArgs: [userId]);
}
Future<void> storeSelfTodoItems(List<TodoItem> todoItems,
{required String userId}) async {
String todoItemsJson = jsonEncode(todoItems.map((e) => e.json).toList());
await db.update("user_data", {"self_todo": todoItemsJson},
where: "id = ?", whereArgs: [userId]);
}
// v5
Future<void> storeRoundings(Map<String, String> roundings,
{required String userId}) async {

View File

@ -33,3 +33,37 @@ class SelfNote {
'note_type': noteType == NoteType.image ? 'image' : 'text',
};
}
class TodoItem {
String id;
String title;
String content;
bool done;
Map? json;
TodoItem({
required this.id,
required this.title,
required this.content,
required this.done,
this.json,
});
factory TodoItem.fromJson(Map json) {
return TodoItem(
id: json['id'],
title: json['title'],
content: json['content'],
done: json['done'],
json: json,
);
}
get toJson => {
'id': id,
'title': title,
'content': content,
'done': done,
};
}

View File

@ -667,6 +667,8 @@ class GradesPageState extends State<GradesPage> {
// SoonAlert.show(context: context);
gradeCalcTotal(context);
Navigator.of(context, rootNavigator: true).pop();
},
),
),

View File

@ -35,6 +35,7 @@ import 'package:refilc_plus/models/premium_scopes.dart';
import 'package:refilc_plus/providers/plus_provider.dart';
import 'package:refilc_plus/ui/mobile/plus/premium_inline.dart';
import 'package:refilc_plus/ui/mobile/plus/upsell.dart';
import 'package:uuid/uuid.dart';
import 'notes_page.i18n.dart';
enum AbsenceFilter { absences, delays, misses }
@ -65,9 +66,14 @@ class NotesPageState extends State<NotesPage> with TickerProviderStateMixin {
Map<String, bool> doneItems = {};
List<Widget> noteTiles = [];
List<TodoItem> todoItems = [];
final TextEditingController _taskName = TextEditingController();
final TextEditingController _taskContent = TextEditingController();
void generateTiles() async {
doneItems = await databaseProvider.userQuery.toDoItems(userId: user.id!);
todoItems = await databaseProvider.userQuery.getTodoItems(userId: user.id!);
List<Widget> tiles = [];
@ -82,7 +88,7 @@ class NotesPageState extends State<NotesPage> with TickerProviderStateMixin {
List<Widget> toDoTiles = [];
if (hw.isNotEmpty &&
!Provider.of<PlusProvider>(context, listen: false)
Provider.of<PlusProvider>(context, listen: false)
.hasScope(PremiumScopes.unlimitedSelfNotes)) {
toDoTiles.addAll(hw.map((e) => TickTile(
padding: EdgeInsets.zero,
@ -102,6 +108,21 @@ class NotesPageState extends State<NotesPage> with TickerProviderStateMixin {
)));
}
if (selfNoteProvider.todos.isNotEmpty) {
toDoTiles.addAll(selfNoteProvider.todos.map((e) => TickTile(
padding: EdgeInsets.zero,
title: e.title,
description: e.content,
isTicked: e.done,
onTap: (p0) async {
todoItems.firstWhere((element) => element.id == e.id).done = p0;
await databaseProvider.userStore
.storeSelfTodoItems(todoItems, userId: user.id!);
},
)));
}
if (toDoTiles.isNotEmpty) {
tiles.add(const SizedBox(
height: 10.0,
@ -313,6 +334,8 @@ class NotesPageState extends State<NotesPage> with TickerProviderStateMixin {
.fetch(
from: DateTime.now().subtract(const Duration(days: 30)));
Provider.of<SelfNoteProvider>(context, listen: false).restore();
Provider.of<SelfNoteProvider>(context, listen: false)
.restoreTodo();
generateTiles();
@ -410,7 +433,159 @@ class NotesPageState extends State<NotesPage> with TickerProviderStateMixin {
},
),
),
const SizedBox(
height: 10.0,
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12.0),
color: Theme.of(context).colorScheme.background),
child: ListTile(
title: Row(
children: [
const Icon(Icons.task_outlined),
const SizedBox(
width: 10.0,
),
Text('new_task'.i18n),
],
),
onTap: () {
if (!Provider.of<PlusProvider>(context, listen: false)
.hasScope(PremiumScopes.unlimitedSelfNotes)) {
PlusLockedFeaturePopup.show(
context: context, feature: PremiumFeature.selfNotes);
return;
}
showTaskCreation(context);
},
),
),
]),
);
}
void showTaskCreation(context) {
showDialog(
context: context,
builder: (context) => AlertDialog(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(14.0))),
contentPadding: const EdgeInsets.only(top: 10.0),
title: Text("new_task".i18n),
content: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 10.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(
controller: _taskName,
decoration: InputDecoration(
border: OutlineInputBorder(
borderSide:
const BorderSide(color: Colors.grey, width: 1.5),
borderRadius: BorderRadius.circular(12.0),
),
focusedBorder: OutlineInputBorder(
borderSide:
const BorderSide(color: Colors.grey, width: 1.5),
borderRadius: BorderRadius.circular(12.0),
),
contentPadding: const EdgeInsets.symmetric(horizontal: 12.0),
hintText: "task_name".i18n,
suffixIcon: IconButton(
icon: const Icon(
FeatherIcons.x,
color: Colors.grey,
),
onPressed: () {
setState(() {
_taskName.text = "";
});
},
),
),
),
const SizedBox(
height: 10.0,
),
TextField(
controller: _taskContent,
decoration: InputDecoration(
border: OutlineInputBorder(
borderSide:
const BorderSide(color: Colors.grey, width: 1.5),
borderRadius: BorderRadius.circular(12.0),
),
focusedBorder: OutlineInputBorder(
borderSide:
const BorderSide(color: Colors.grey, width: 1.5),
borderRadius: BorderRadius.circular(12.0),
),
contentPadding: const EdgeInsets.symmetric(horizontal: 12.0),
hintText: "task_content".i18n,
suffixIcon: IconButton(
icon: const Icon(
FeatherIcons.x,
color: Colors.grey,
),
onPressed: () {
setState(() {
_taskContent.text = "";
});
},
),
),
),
],
),
),
actions: [
TextButton(
child: Text(
"cancel".i18n,
style: const TextStyle(fontWeight: FontWeight.w500),
),
onPressed: () {
Navigator.of(context).maybePop();
},
),
TextButton(
child: Text(
"next".i18n,
style: const TextStyle(fontWeight: FontWeight.w500),
),
onPressed: () async {
todoItems.add(TodoItem.fromJson({
'id': const Uuid().v4(),
'title': _taskName.text.replaceAll(' ', '') != ""
? _taskName.text
: 'no_title'.i18n,
'content': _taskContent.text,
'done': false,
}));
await databaseProvider.userStore
.storeSelfTodoItems(todoItems, userId: user.id!);
setState(() {
_taskName.text = "";
_taskContent.text = "";
});
Provider.of<SelfNoteProvider>(context, listen: false).restore();
Provider.of<SelfNoteProvider>(context, listen: false)
.restoreTodo();
generateTiles();
Navigator.of(context).pop(true);
},
),
],
),
);
}
}

View File

@ -14,6 +14,10 @@ extension ScreensLocalization on String {
"hint_t": "Note title...",
"your_notes": "Your Notes",
"new_image": "New Image",
"no_title": "No title",
"task_content": "Task content...",
"task_name": "Task title...",
"new_task": "New Task",
},
"hu_hu": {
"notes": "Füzet",
@ -26,6 +30,10 @@ extension ScreensLocalization on String {
"hint_t": "Jegyzet címe...",
"your_notes": "Jegyzeteid",
"new_image": "Új kép",
"no_title": "Nincs cím",
"task_content": "Feladat tartalma...",
"task_name": "Feladat címe...",
"new_task": "Új feladat",
},
"de_de": {
"notes": "Broschüre",
@ -38,6 +46,10 @@ extension ScreensLocalization on String {
"hint_t": "Titel notieren...",
"your_notes": "Deine Noten",
"new_image": "Neues Bild",
"no_title": "Kein Titel",
"task_content": "Aufgabeninhalt...",
"task_name": "Aufgabentitel...",
"new_task": "Neue Aufgabe",
},
};

View File

@ -143,6 +143,7 @@ class _ImageNoteEditorState extends State<ImageNoteEditor> {
.storeSelfNotes(selfNotes, userId: widget.u.id);
Provider.of<SelfNoteProvider>(context, listen: false).restore();
Provider.of<SelfNoteProvider>(context, listen: false).restoreTodo();
debugPrint('$file');
}

View File

@ -268,6 +268,7 @@ class NotesScreenState extends State<NotesScreen> {
Provider.of<HomeworkProvider>(context, listen: false)
.fetch(from: DateTime.now().subtract(const Duration(days: 30)));
Provider.of<SelfNoteProvider>(context, listen: false).restore();
Provider.of<SelfNoteProvider>(context, listen: false).restoreTodo();
return Future(() => null);
},