notes page finished, messing with theme and navbar things

This commit is contained in:
Kima 2024-03-04 22:58:34 +01:00
parent e6fc1fd656
commit 7363fc81cb
8 changed files with 425 additions and 40 deletions

View File

@ -0,0 +1,22 @@
import 'package:flutter/material.dart';
class ColorsUtils {
Color darken(Color color, {double amount = .1}) {
assert(amount >= 0 && amount <= 1);
final hsl = HSLColor.fromColor(color);
final hslDark = hsl.withLightness((hsl.lightness - amount).clamp(0.0, 1.0));
return hslDark.toColor();
}
Color lighten(Color color, {double amount = .1}) {
assert(amount >= 0 && amount <= 1);
final hsl = HSLColor.fromColor(color);
final hslLight =
hsl.withLightness((hsl.lightness + amount).clamp(0.0, 1.0));
return hslLight.toColor();
}
}

View File

@ -1,6 +1,7 @@
import 'package:refilc/models/settings.dart';
import 'package:refilc/theme/colors/accent.dart';
import 'package:refilc/theme/colors/colors.dart';
import 'package:refilc/theme/colors/utils.dart';
import 'package:refilc/theme/observer.dart';
import 'package:flutter/material.dart';
import 'package:material_color_utilities/material_color_utilities.dart';
@ -61,18 +62,22 @@ class AppTheme {
: _paletteHighlightLight(palette)) ??
lightColors.highlight;
Color newPrimary = ColorsUtils().darken(accent, amount: 0.4);
// Color newScaffoldBg = ColorsUtils().lighten(accent, amount: 0.4);
Color newScaffoldBg = backgroundColor;
return ThemeData(
brightness: Brightness.light,
useMaterial3: true,
fontFamily: _defaultFontFamily,
textTheme: googleFontsMap[settings.fontFamily],
scaffoldBackgroundColor: backgroundColor,
scaffoldBackgroundColor: newScaffoldBg,
primaryColor: lightColors.filc,
dividerColor: const Color(0x00000000),
colorScheme: ColorScheme(
primary: accent,
primary: newPrimary,
onPrimary:
(accent.computeLuminance() > 0.5 ? Colors.black : Colors.white)
(newPrimary.computeLuminance() > 0.5 ? Colors.black : Colors.white)
.withOpacity(.9),
secondary: accent,
onSecondary:

View File

@ -0,0 +1,308 @@
// ignore_for_file: no_leading_underscores_for_local_identifiers, use_build_context_synchronously
import 'dart:math';
import 'package:flutter/cupertino.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:refilc/api/providers/database_provider.dart';
import 'package:refilc/api/providers/self_note_provider.dart';
import 'package:refilc/api/providers/update_provider.dart';
import 'package:refilc/utils/format.dart';
import 'package:refilc_kreta_api/models/absence.dart';
import 'package:refilc_kreta_api/models/homework.dart';
import 'package:refilc_kreta_api/models/subject.dart';
import 'package:refilc/api/providers/user_provider.dart';
import 'package:refilc/theme/colors/colors.dart';
import 'package:refilc_kreta_api/providers/homework_provider.dart';
import 'package:refilc_mobile_ui/common/empty.dart';
import 'package:refilc_mobile_ui/common/panel/panel.dart';
import 'package:refilc_mobile_ui/common/profile_image/profile_button.dart';
import 'package:refilc_mobile_ui/common/profile_image/profile_image.dart';
import 'package:refilc_mobile_ui/common/soon_alert/soon_alert.dart';
import 'package:refilc_mobile_ui/common/widgets/tick_tile.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:refilc_mobile_ui/screens/notes/add_note_screen.dart';
import 'package:refilc_mobile_ui/screens/notes/note_view_screen.dart';
import 'package:refilc_mobile_ui/screens/notes/self_note_tile.dart';
import 'package:refilc_plus/models/premium_scopes.dart';
import 'package:refilc_plus/providers/premium_provider.dart';
import 'package:refilc_plus/ui/mobile/premium/premium_inline.dart';
import 'package:refilc_plus/ui/mobile/premium/upsell.dart';
import 'notes_page.i18n.dart';
enum AbsenceFilter { absences, delays, misses }
class SubjectAbsence {
GradeSubject subject;
List<Absence> absences;
double percentage;
SubjectAbsence(
{required this.subject, this.absences = const [], this.percentage = 0.0});
}
class NotesPage extends StatefulWidget {
const NotesPage({super.key});
@override
NotesPageState createState() => NotesPageState();
}
class NotesPageState extends State<NotesPage> with TickerProviderStateMixin {
late UserProvider user;
late UpdateProvider updateProvider;
late DatabaseProvider databaseProvider;
late SelfNoteProvider selfNoteProvider;
late String firstName;
Map<String, bool> doneItems = {};
List<Widget> noteTiles = [];
void generateTiles() async {
doneItems = await databaseProvider.userQuery.toDoItems(userId: user.id!);
List<Widget> tiles = [];
List<Homework> hw = Provider.of<HomeworkProvider>(context, listen: false)
.homework
.where((e) => e.deadline.isAfter(DateTime.now()))
// e.deadline.isBefore(DateTime(DateTime.now().year,
// DateTime.now().month, DateTime.now().day + 3)))
.toList();
// todo tiles
List<Widget> toDoTiles = [];
if (hw.isNotEmpty &&
!Provider.of<PremiumProvider>(context, listen: false)
.hasScope(PremiumScopes.unlimitedSelfNotes)) {
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: doneItems[e.id] ?? false,
onTap: (p0) async {
if (!doneItems.containsKey(e.id)) {
doneItems.addAll({e.id: p0});
} else {
doneItems[e.id] = p0;
}
await databaseProvider.userStore
.storeToDoItem(doneItems, userId: user.id!);
},
)));
}
if (toDoTiles.isNotEmpty) {
tiles.add(const SizedBox(
height: 10.0,
));
tiles.add(Panel(
title: Text('todo'.i18n),
child: Column(
children: toDoTiles,
),
));
}
// self notes
List<Widget> selfNoteTiles = [];
if (selfNoteProvider.notes.isNotEmpty) {
selfNoteTiles.addAll(selfNoteProvider.notes.reversed.map(
(e) => SelfNoteTile(
title: e.title ?? e.content.split(' ')[0],
content: e.content,
onTap: () => Navigator.of(context, rootNavigator: true).push(
CupertinoPageRoute(
builder: (context) => NoteViewScreen(note: e))),
),
));
}
if (selfNoteTiles.isNotEmpty) {
// padding
tiles.add(const SizedBox(
height: 28.0,
));
// actual thing
tiles.add(Panel(
title: Text('your_notes'.i18n),
padding: EdgeInsets.zero,
isTransparent: true,
child: Wrap(
spacing: 18.0,
runSpacing: 18.0,
children: selfNoteTiles,
),
));
}
// insert empty tile
if (tiles.isEmpty) {
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);
setState(() {});
}
@override
Widget build(BuildContext context) {
user = Provider.of<UserProvider>(context);
databaseProvider = Provider.of<DatabaseProvider>(context);
updateProvider = Provider.of<UpdateProvider>(context);
selfNoteProvider = Provider.of<SelfNoteProvider>(context);
List<String> nameParts = user.displayName?.split(" ") ?? ["?"];
firstName = nameParts.length > 1 ? nameParts[1] : nameParts[0];
generateTiles();
return Scaffold(
body: Padding(
padding: const EdgeInsets.only(top: 12.0),
child: NestedScrollView(
physics: const BouncingScrollPhysics(
parent: AlwaysScrollableScrollPhysics()),
headerSliverBuilder: (context, _) => [
SliverAppBar(
pinned: true,
floating: false,
snap: false,
centerTitle: false,
surfaceTintColor: Theme.of(context).scaffoldBackgroundColor,
actions: [
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16.0, vertical: 5.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
GestureDetector(
onTap: () async {
SoonAlert.show(context: context);
},
child: Icon(
FeatherIcons.search,
color: AppColors.of(context).text,
size: 22.0,
),
),
const SizedBox(
width: 12.0,
),
GestureDetector(
onTap: () async {
// handle tap
if (!Provider.of<PremiumProvider>(context,
listen: false)
.hasScope(PremiumScopes.unlimitedSelfNotes) &&
noteTiles.length > 10) {
return PremiumLockedFeatureUpsell.show(
context: context,
feature: PremiumFeature.selfNotes);
}
Navigator.of(context, rootNavigator: true).push(
CupertinoPageRoute(
builder: (context) => const AddNoteScreen()));
},
child: Icon(
FeatherIcons.plus,
color: AppColors.of(context).text,
),
),
],
),
),
// Profile Icon
Padding(
padding: const EdgeInsets.only(right: 24.0),
child: ProfileButton(
child: ProfileImage(
heroTag: "profile",
name: firstName,
backgroundColor: Theme.of(context)
.colorScheme
.primary, //ColorUtils.stringToColor(user.displayName ?? "?"),
badge: updateProvider.available,
role: user.role,
profilePictureString: user.picture,
),
),
),
],
automaticallyImplyLeading: false,
shadowColor: Theme.of(context).shadowColor,
title: Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Text(
"notes".i18n,
style: TextStyle(
color: AppColors.of(context).text,
fontSize: 32.0,
fontWeight: FontWeight.bold),
),
),
),
],
body: RefreshIndicator(
onRefresh: () {
var state = Provider.of<HomeworkProvider>(context, listen: false)
.fetch(
from: DateTime.now().subtract(const Duration(days: 30)));
Provider.of<SelfNoteProvider>(context, listen: false).restore();
generateTiles();
return state;
},
color: Theme.of(context).colorScheme.secondary,
child: ListView.builder(
padding: EdgeInsets.zero,
physics: const BouncingScrollPhysics(),
itemCount: max(noteTiles.length, 1),
itemBuilder: (context, index) {
if (noteTiles.isNotEmpty) {
const EdgeInsetsGeometry panelPadding =
EdgeInsets.symmetric(horizontal: 24.0);
return Padding(
padding: panelPadding, child: noteTiles[index]);
} else {
return Container();
}
},
),
),
),
),
);
}
}

View File

@ -0,0 +1,45 @@
import 'package:i18n_extension/i18n_extension.dart';
extension ScreensLocalization on String {
static final _t = Translations.byLocale("hu_hu") +
{
"en_en": {
"notes": "Notes",
"empty": "You don't have any notes",
"todo": "Tasks",
"homework": "Homework",
"new_note": "New Note",
"edit_note": "Edit Note",
"hint": "Note content...",
"hint_t": "Note title...",
"your_notes": "Your Notes",
},
"hu_hu": {
"notes": "Füzet",
"empty": "Nincsenek jegyzeteid",
"todo": "Feladatok",
"homework": "Házi feladat",
"new_note": "Új jegyzet",
"edit_note": "Jegyzet szerkesztése",
"hint": "Jegyzet tartalma...",
"hint_t": "Jegyzet címe...",
"your_notes": "Jegyzeteid",
},
"de_de": {
"notes": "Broschüre",
"empty": "Sie haben keine Notizen",
"todo": "Aufgaben",
"homework": "Hausaufgaben",
"new_note": "Neue Notiz",
"edit_note": "Notiz bearbeiten",
"hint": "Inhalt beachten...",
"hint_t": "Titel notieren...",
"your_notes": "Deine Noten",
},
};
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

@ -38,24 +38,25 @@ class NavbarItem extends StatelessWidget {
: null,
borderRadius: BorderRadius.circular(14.0),
),
child: Stack(
children: [
IconTheme(
data: IconThemeData(
color: Theme.of(context).colorScheme.secondary,
),
child: icon,
),
IconTheme(
data: IconThemeData(
color: Theme.of(context).brightness == Brightness.light
? Colors.black.withOpacity(.5)
: Colors.white.withOpacity(.3),
),
child: icon,
),
],
),
child: icon,
// child: Stack(
// children: [
// IconTheme(
// data: IconThemeData(
// color: Theme.of(context).colorScheme.secondary,
// ),
// child: icon,
// ),
// IconTheme(
// data: IconThemeData(
// color: Theme.of(context).brightness == Brightness.light
// ? Colors.black.withOpacity(.5)
// : Colors.white.withOpacity(.3),
// ),
// child: icon,
// ),
// ],
// ),
),
),
),

View File

@ -7,7 +7,7 @@ class NavigationRoute {
"grades",
"timetable",
"notes",
"inbox",
"absences",
// "messages",
// "absences",
];

View File

@ -1,7 +1,9 @@
// import 'package:refilc_mobile_ui/pages/absences/absences_page.dart';
import 'package:refilc_mobile_ui/pages/absences/absences_page.dart';
import 'package:refilc_mobile_ui/pages/grades/grades_page.dart';
import 'package:refilc_mobile_ui/pages/home/home_page.dart';
import 'package:refilc_mobile_ui/pages/messages/messages_page.dart';
import 'package:refilc_mobile_ui/pages/notes/notes_page.dart';
// import 'package:refilc_mobile_ui/pages/messages/messages_page.dart';
import 'package:refilc_mobile_ui/pages/timetable/timetable_page.dart';
import 'package:flutter/material.dart';
import 'package:animations/animations.dart';
@ -15,8 +17,8 @@ Route navigationRouteHandler(RouteSettings settings) {
case "timetable":
return navigationPageRoute((context) => const TimetablePage());
case "notes":
return navigationPageRoute((context) => const MessagesPage());
case "inbox":
return navigationPageRoute((context) => const NotesPage());
case "absences":
return navigationPageRoute((context) => const AbsencesPage());
// case "messages":
// return navigationPageRoute((context) => const MessagesPage());

View File

@ -1,6 +1,8 @@
import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:flutter_svg/svg.dart';
import 'package:refilc/api/providers/update_provider.dart';
import 'package:refilc/helpers/quick_actions.dart';
import 'package:refilc/icons/filc_icons.dart';
import 'package:refilc/models/settings.dart';
import 'package:refilc/theme/observer.dart';
import 'package:refilc_kreta_api/client/client.dart';
@ -324,7 +326,7 @@ class NavigationScreenState extends State<NavigationScreen>
'assets/svg/menu_icons/today.svg',
color:
Theme.of(context).colorScheme.secondary,
height: 26,
height: 24,
),
Transform.translate(
offset: const Offset(0, 1.6),
@ -347,7 +349,7 @@ class NavigationScreenState extends State<NavigationScreen>
'assets/svg/menu_icons/today_selected.svg',
color:
Theme.of(context).colorScheme.secondary,
height: 26,
height: 24,
),
Transform.translate(
offset: const Offset(0, 1.8),
@ -369,12 +371,12 @@ class NavigationScreenState extends State<NavigationScreen>
icon: SvgPicture.asset(
'assets/svg/menu_icons/grades.svg',
color: Theme.of(context).colorScheme.secondary,
height: 24,
height: 22,
),
activeIcon: SvgPicture.asset(
'assets/svg/menu_icons/grades_selected.svg',
color: Theme.of(context).colorScheme.secondary,
height: 24,
height: 22,
),
),
NavItem(
@ -382,12 +384,12 @@ class NavigationScreenState extends State<NavigationScreen>
icon: SvgPicture.asset(
'assets/svg/menu_icons/timetable.svg',
color: Theme.of(context).colorScheme.secondary,
height: 24,
height: 22,
),
activeIcon: SvgPicture.asset(
'assets/svg/menu_icons/timetable_selected.svg',
color: Theme.of(context).colorScheme.secondary,
height: 24,
height: 22,
),
),
NavItem(
@ -395,25 +397,25 @@ class NavigationScreenState extends State<NavigationScreen>
icon: SvgPicture.asset(
'assets/svg/menu_icons/notes.svg',
color: Theme.of(context).colorScheme.secondary,
height: 24,
height: 22,
),
activeIcon: SvgPicture.asset(
'assets/svg/menu_icons/notes_selected.svg',
color: Theme.of(context).colorScheme.secondary,
height: 24,
height: 22,
),
),
NavItem(
title: "inbox".i18n,
icon: SvgPicture.asset(
'assets/svg/menu_icons/inbox.svg',
title: "absences".i18n,
icon: Icon(
FeatherIcons.clock,
color: Theme.of(context).colorScheme.secondary,
height: 24,
size: 24.0,
),
activeIcon: SvgPicture.asset(
'assets/svg/menu_icons/inbox_selected.svg',
activeIcon: Icon(
FilcIcons.absencesfill,
color: Theme.of(context).colorScheme.secondary,
height: 24,
size: 24.0,
),
),
// NavItem(