other things in notes

This commit is contained in:
Kima 2023-12-30 13:27:52 +01:00
parent f5ad70fb28
commit f238b86dc7
6 changed files with 486 additions and 14 deletions

View File

@ -0,0 +1,22 @@
class SelfNote {
String id;
String? title;
String content;
Map? json;
SelfNote({
required this.id,
this.title,
required this.content,
this.json,
});
factory SelfNote.fromJson(Map json) {
return SelfNote(
id: json['id'],
title: json['title'],
content: json['content'],
json: json,
);
}
}

View File

@ -0,0 +1,98 @@
// // ignore_for_file: no_leading_underscores_for_local_identifiers
// import 'package:filcnaplo/api/providers/user_provider.dart';
// import 'package:filcnaplo/api/providers/database_provider.dart';
// import 'package:filcnaplo/models/user.dart';
// import 'package:filcnaplo_kreta_api/client/api.dart';
// import 'package:filcnaplo_kreta_api/client/client.dart';
// import 'package:filcnaplo_kreta_api/models/absence.dart';
// import 'package:flutter/material.dart';
// import 'package:provider/provider.dart';
// class TodoNotesProvider with ChangeNotifier {
// late Map<> _absences;
// late BuildContext _context;
// List<Absence> get absences => _absences;
// TodoNotesProvider({
// List<Absence> initialAbsences = const [],
// required BuildContext context,
// }) {
// _absences = List.castFrom(initialAbsences);
// _context = context;
// if (_absences.isEmpty) restore();
// }
// Future<void> restore() async {
// String? userId = Provider.of<UserProvider>(_context, listen: false).id;
// // Load absences from the database
// if (userId != null) {
// var dbAbsences =
// await Provider.of<DatabaseProvider>(_context, listen: false)
// .userQuery
// .getAbsences(userId: userId);
// _absences = dbAbsences;
// await convertBySettings();
// }
// }
// // for renamed subjects
// Future<void> convertBySettings() async {
// final _database = Provider.of<DatabaseProvider>(_context, listen: false);
// Map<String, String> renamedSubjects =
// (await _database.query.getSettings(_database)).renamedSubjectsEnabled
// ? await _database.userQuery.renamedSubjects(
// userId:
// // ignore: use_build_context_synchronously
// Provider.of<UserProvider>(_context, listen: false).user!.id)
// : {};
// Map<String, String> renamedTeachers =
// (await _database.query.getSettings(_database)).renamedTeachersEnabled
// ? await _database.userQuery.renamedTeachers(
// userId:
// // ignore: use_build_context_synchronously
// Provider.of<UserProvider>(_context, listen: false).user!.id)
// : {};
// for (Absence absence in _absences) {
// absence.subject.renamedTo = renamedSubjects.isNotEmpty
// ? renamedSubjects[absence.subject.id]
// : null;
// absence.teacher.renamedTo = renamedTeachers.isNotEmpty
// ? renamedTeachers[absence.teacher.id]
// : null;
// }
// notifyListeners();
// }
// // Fetches Absences from the Kreta API then stores them in the database
// Future<void> fetch() async {
// User? user = Provider.of<UserProvider>(_context, listen: false).user;
// if (user == null) throw "Cannot fetch Absences for User null";
// String iss = user.instituteCode;
// List? absencesJson = await Provider.of<KretaClient>(_context, listen: false)
// .getAPI(KretaAPI.absences(iss));
// if (absencesJson == null) throw "Cannot fetch Absences for User ${user.id}";
// List<Absence> absences =
// absencesJson.map((e) => Absence.fromJson(e)).toList();
// if (absences.isNotEmpty || _absences.isNotEmpty) await store(absences);
// }
// // Stores Absences in the database
// Future<void> store(List<Absence> absences) async {
// User? user = Provider.of<UserProvider>(_context, listen: false).user;
// if (user == null) throw "Cannot store Absences for User null";
// String userId = user.id;
// await Provider.of<DatabaseProvider>(_context, listen: false)
// .userStore
// .storeAbsences(absences, userId: userId);
// _absences = absences;
// await convertBySettings();
// }
// }

View File

@ -0,0 +1,109 @@
import 'package:filcnaplo/theme/colors/colors.dart';
import 'package:flutter/material.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart';
class TickTile extends StatefulWidget {
const TickTile({
super.key,
this.onTap,
this.isTicked = false,
required this.title,
this.description,
this.padding,
});
final Function(bool)? onTap;
final bool isTicked;
final String title;
final String? description;
final EdgeInsetsGeometry? padding;
@override
TickTileState createState() => TickTileState();
}
class TickTileState extends State<TickTile> {
late bool isTicked;
@override
void initState() {
isTicked = widget.isTicked;
super.initState();
}
@override
Widget build(BuildContext context) {
return Material(
type: MaterialType.transparency,
child: Padding(
padding: widget.padding ?? const EdgeInsets.symmetric(horizontal: 8.0),
child: ListTile(
onTap: () {
widget.onTap!(!isTicked);
setState(() {
isTicked == true ? isTicked = false : isTicked = true;
});
},
visualDensity: VisualDensity.compact,
contentPadding: const EdgeInsets.only(left: 8.0, right: 4.0),
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(14.0)),
leading: !isTicked
? Padding(
padding: const EdgeInsets.only(top: 2.0, left: 0.8),
child: Container(
width: 20.5,
height: 20.5,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: Theme.of(context).colorScheme.primary,
width: 2.0,
),
),
),
)
: Icon(
FeatherIcons.checkCircle,
size: 22.0,
color: Theme.of(context).colorScheme.primary,
),
title: Row(
children: [
Expanded(
child: Text(
widget.title,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontWeight: FontWeight.w700,
fontSize: 15.5,
decoration: isTicked ? TextDecoration.lineThrough : null,
color: isTicked
? AppColors.of(context).text.withOpacity(0.5)
: null,
),
),
),
],
),
subtitle: widget.description != null
? Text(
widget.description!,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 12.0,
color: isTicked
? AppColors.of(context).text.withOpacity(0.5)
: null,
),
)
: null,
),
),
);
}
}

View File

@ -1,25 +1,230 @@
import 'package:filcnaplo/theme/colors/colors.dart';
import 'package:filcnaplo_mobile_ui/screens/settings/settings_screen.i18n.dart';
import 'package:flutter/material.dart';
import 'dart:math';
class NotesScreen extends StatelessWidget {
const NotesScreen({super.key});
import 'package:filcnaplo/api/providers/database_provider.dart';
import 'package:filcnaplo/api/providers/user_provider.dart';
import 'package:filcnaplo/theme/colors/colors.dart';
import 'package:filcnaplo/utils/format.dart';
import 'package:filcnaplo_kreta_api/models/homework.dart';
import 'package:filcnaplo_kreta_api/providers/homework_provider.dart';
import 'package:filcnaplo_mobile_ui/common/empty.dart';
import 'package:filcnaplo_mobile_ui/common/panel/panel.dart';
import 'package:filcnaplo_mobile_ui/common/widgets/tick_tile.dart';
import 'package:filcnaplo_mobile_ui/screens/notes/notes_screen.i18n.dart';
import 'package:filcnaplo_premium/providers/premium_provider.dart';
import 'package:filcnaplo_premium/ui/mobile/premium/premium_inline.dart';
import 'package:flutter/material.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:provider/provider.dart';
class NotesScreen extends StatefulWidget {
const NotesScreen({super.key, required this.doneItems});
final Map<String, bool> doneItems;
@override
NotesScreenState createState() => NotesScreenState();
}
class NotesScreenState extends State<NotesScreen> {
late UserProvider user;
late HomeworkProvider homeworkProvider;
late DatabaseProvider databaseProvider;
List<Widget> noteTiles = [];
@override
Widget build(BuildContext context) {
user = Provider.of<UserProvider>(context);
homeworkProvider = Provider.of<HomeworkProvider>(context);
databaseProvider = Provider.of<DatabaseProvider>(context);
void generateTiles() {
List<Widget> tiles = [];
List<Homework> hw = homeworkProvider.homework
.where((e) => e.deadline.isAfter(DateTime.now()))
// e.deadline.isBefore(DateTime(DateTime.now().year,
// DateTime.now().month, DateTime.now().day + 3)))
.toList();
List<Widget> toDoTiles = [];
if (hw.isNotEmpty) {
toDoTiles.addAll(hw.map((e) => TickTile(
padding: EdgeInsets.zero,
title: 'homework'.i18n,
description:
'${(e.subject.isRenamed ? e.subject.renamedTo : e.subject.name) ?? ''}, ${e.content.escapeHtml()}',
isTicked: widget.doneItems[e.id] ?? false,
onTap: (p0) async {
if (!widget.doneItems.containsKey(e.id)) {
widget.doneItems.addAll({e.id: p0});
} else {
widget.doneItems[e.id] = p0;
}
await databaseProvider.userStore
.storeToDoItem(widget.doneItems, userId: user.id!);
},
)));
}
if (toDoTiles.isNotEmpty) {
tiles.add(Panel(
title: Text('todo'.i18n),
child: Column(
children: toDoTiles,
),
));
}
if (tiles.isNotEmpty) {
} else {
tiles.insert(
0,
Padding(
padding: const EdgeInsets.only(top: 24.0),
child: Empty(subtitle: "empty".i18n),
),
);
}
tiles.add(Provider.of<PremiumProvider>(context, listen: false).hasPremium
? const SizedBox()
: const Padding(
padding: EdgeInsets.only(top: 24.0),
child: PremiumInline(features: [
PremiumInlineFeature.stats,
]),
));
// padding
tiles.add(const SizedBox(height: 32.0));
noteTiles = List.castFrom(tiles);
}
generateTiles();
return Scaffold(
appBar: AppBar(
surfaceTintColor: Theme.of(context).scaffoldBackgroundColor,
leading: BackButton(color: AppColors.of(context).text),
title: Text("notes".i18n,
style: TextStyle(color: AppColors.of(context).text)),
title: Text(
"notes".i18n,
style: TextStyle(
color: AppColors.of(context).text,
fontSize: 26.0,
fontWeight: FontWeight.bold,
),
),
actions: [
ClipRRect(
borderRadius: BorderRadius.circular(10.1),
child: GestureDetector(
onTap: () {
// handle tap
},
child: Container(
color: Theme.of(context).colorScheme.primary.withOpacity(0.4),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Stack(
children: [
IconTheme(
data: IconThemeData(
color: Theme.of(context).colorScheme.secondary,
),
child: const Icon(
FeatherIcons.search,
size: 20.0,
),
),
IconTheme(
data: IconThemeData(
color:
Theme.of(context).brightness == Brightness.light
? Colors.black.withOpacity(.5)
: Colors.white.withOpacity(.3),
),
child: const Icon(
FeatherIcons.search,
size: 20.0,
),
),
],
),
),
),
),
),
const SizedBox(
width: 10,
),
ClipRRect(
borderRadius: BorderRadius.circular(10.1),
child: GestureDetector(
onTap: () {
// handle tap
},
child: Container(
color: Theme.of(context).colorScheme.primary.withOpacity(0.4),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Stack(
children: [
IconTheme(
data: IconThemeData(
color: Theme.of(context).colorScheme.secondary,
),
child: const Icon(
FeatherIcons.plus,
size: 20.0,
),
),
IconTheme(
data: IconThemeData(
color:
Theme.of(context).brightness == Brightness.light
? Colors.black.withOpacity(.5)
: Colors.white.withOpacity(.3),
),
child: const Icon(
FeatherIcons.plus,
size: 20.0,
),
),
],
),
),
),
),
),
const SizedBox(
width: 20,
),
],
),
body: SafeArea(
child: RefreshIndicator(
onRefresh: () {
return Future(() => null);
onRefresh: () async {
await homeworkProvider.fetch();
},
child: ListView.builder(
padding: EdgeInsets.zero,
physics: const BouncingScrollPhysics(),
itemCount: max(noteTiles.length, 1),
itemBuilder: (context, index) {
if (noteTiles.isNotEmpty) {
EdgeInsetsGeometry panelPadding =
const EdgeInsets.symmetric(horizontal: 24.0);
return Padding(padding: panelPadding, child: noteTiles[index]);
} else {
return Container();
}
},
child: Text('soon')),
),
),
),
);
}

View File

@ -0,0 +1,30 @@
import 'package:i18n_extension/i18n_extension.dart';
extension SettingsLocalization on String {
static final _t = Translations.byLocale("hu_hu") +
{
"en_en": {
"notes": "Notes",
"empty": "You don't have any notes",
"todo": "Tasks",
"homework": "Homework",
},
"hu_hu": {
"notes": "Füzet",
"empty": "Nincsenek jegyzeteid",
"todo": "Feladatok",
"homework": "Házi feladat",
},
"de_de": {
"notes": "Broschüre",
"empty": "Sie haben keine Notizen",
"todo": "Aufgaben",
"homework": "Hausaufgaben",
},
};
String get i18n => localize(this, _t);
String fill(List<Object> params) => localizeFill(this, params);
String plural(int value) => localizePlural(value, this, _t);
String version(Object modifier) => localizeVersion(modifier, this, _t);
}

View File

@ -65,7 +65,9 @@ class SettingsScreenState extends State<SettingsScreen>
late UserProvider user;
late UpdateProvider updateProvider;
late SettingsProvider settings;
late DatabaseProvider databaseProvider;
late KretaClient kretaClient;
late String firstName;
List<Widget> accountTiles = [];
@ -181,6 +183,7 @@ class SettingsScreenState extends State<SettingsScreen>
user = Provider.of<UserProvider>(context);
settings = Provider.of<SettingsProvider>(context);
updateProvider = Provider.of<UpdateProvider>(context);
databaseProvider = Provider.of<DatabaseProvider>(context);
kretaClient = Provider.of<KretaClient>(context);
List<String> nameParts = user.displayName?.split(" ") ?? ["?"];
@ -237,7 +240,10 @@ class SettingsScreenState extends State<SettingsScreen>
// ),
IconButton(
splashRadius: 32.0,
onPressed: () => _openNotes(context),
onPressed: () async => _openNotes(
context,
await databaseProvider.userQuery
.toDoItems(userId: user.id!)),
// _showBottomSheet(user.getUser(user.id ?? "")),
icon: Icon(FeatherIcons.fileText,
color: AppColors.of(context).text.withOpacity(0.8)),
@ -1106,7 +1112,9 @@ class SettingsScreenState extends State<SettingsScreen>
void _openUpdates(BuildContext context) =>
UpdateView.show(updateProvider.releases.first, context: context);
void _openPrivacy(BuildContext context) => PrivacyView.show(context);
void _openNotes(BuildContext context) =>
Navigator.of(context, rootNavigator: true)
.push(CupertinoPageRoute(builder: (context) => const NotesScreen()));
void _openNotes(BuildContext context, Map<String, bool> doneItems) async =>
Navigator.of(context, rootNavigator: true).push(CupertinoPageRoute(
builder: (context) => NotesScreen(
doneItems: doneItems,
)));
}