This commit is contained in:
Márton Kiss
2023-05-26 21:25:00 +02:00
parent 9e3b805fdd
commit 1558794e93
528 changed files with 38239 additions and 37732 deletions

View File

@@ -1,17 +1,17 @@
import 'package:animations/animations.dart';
import 'package:flutter/material.dart';
Route loginRoute(Widget widget) {
return PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) => widget,
transitionDuration: const Duration(milliseconds: 650),
transitionsBuilder: (context, animation, secondaryAnimation, child) {
return FadeThroughTransition(
fillColor: Colors.transparent,
animation: animation,
secondaryAnimation: secondaryAnimation,
child: child,
);
},
);
}
import 'package:animations/animations.dart';
import 'package:flutter/material.dart';
Route loginRoute(Widget widget) {
return PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) => widget,
transitionDuration: const Duration(milliseconds: 650),
transitionsBuilder: (context, animation, secondaryAnimation, child) {
return FadeThroughTransition(
fillColor: Colors.transparent,
animation: animation,
secondaryAnimation: secondaryAnimation,
child: child,
);
},
);
}

View File

@@ -1,319 +1,319 @@
import 'dart:io';
import 'dart:ui';
import 'package:elegant_notification/elegant_notification.dart';
import 'package:elegant_notification/resources/arrays.dart';
import 'package:filcnaplo/api/client.dart';
import 'package:filcnaplo/api/login.dart';
import 'package:filcnaplo/theme/colors/colors.dart';
import 'package:filcnaplo_mobile_ui/screens/login/login_button.dart';
import 'package:filcnaplo_mobile_ui/screens/login/login_input.dart';
import 'package:filcnaplo_mobile_ui/screens/login/school_input/school_input.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_acrylic/flutter_acrylic.dart';
import 'login_screen.i18n.dart';
class LoginScreen extends StatefulWidget {
const LoginScreen({Key? key, this.back = false}) : super(key: key);
final bool back;
@override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
final usernameController = TextEditingController();
final passwordController = TextEditingController();
final schoolController = SchoolInputController();
final _scrollController = ScrollController();
LoginState _loginState = LoginState.normal;
bool showBack = false;
double topInset = 12.0;
@override
void initState() {
super.initState();
showBack = widget.back;
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness: Brightness.light,
systemNavigationBarColor: Colors.white,
systemNavigationBarIconBrightness: Brightness.dark,
));
FilcAPI.getSchools().then((schools) {
if (schools != null) {
schoolController.update(() {
schoolController.schools = schools;
});
} else {
ElegantNotification.error(
background: Colors.white,
description: Text(
"schools_error".i18n,
overflow: TextOverflow.ellipsis,
style: const TextStyle(color: Colors.red),
),
onActionPressed: () {},
onCloseButtonPressed: () {},
onDismiss: () {},
onProgressFinished: () {},
displayCloseButton: false,
showProgressIndicator: false,
autoDismiss: true,
animation: AnimationType.fromTop,
).show(context);
}
});
if (Platform.isMacOS) Window.getTitlebarHeight().then((value) => setState(() => topInset = value));
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.of(context).filc,
body: SafeArea(
child: Stack(
children: [
Row(
children: [
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// App logo
Padding(
padding: const EdgeInsets.only(bottom: 24.0),
child: ClipRect(
child: Padding(
padding: const EdgeInsets.only(left: 12.0, right: 12.0, bottom: 32.0),
child: SizedBox(
width: 82.0,
height: 82.0,
// Png shadow *hack*
child: Stack(
children: [
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Opacity(child: Image.asset("assets/icons/ic_splash.png", color: Colors.black), opacity: 0.3),
),
BackdropFilter(
filter: ImageFilter.blur(sigmaX: 6.0, sigmaY: 6.0),
child: Image.asset("assets/icons/ic_splash.png"),
)
],
),
),
),
),
),
// Inputs
SizedBox(
width: 400.0,
child: AutofillGroup(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Username
Padding(
padding: const EdgeInsets.only(bottom: 6.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
"username".i18n,
maxLines: 1,
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
fontSize: 14.0,
),
),
),
Expanded(
child: Text(
"usernameHint".i18n,
maxLines: 1,
textAlign: TextAlign.right,
style: const TextStyle(
color: Colors.white54,
fontWeight: FontWeight.w500,
fontSize: 12.0,
),
),
),
],
),
),
Padding(
padding: const EdgeInsets.only(bottom: 12.0),
child: LoginInput(
style: LoginInputStyle.username,
controller: usernameController,
),
),
// Password
Padding(
padding: const EdgeInsets.only(bottom: 6.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
"password".i18n,
maxLines: 1,
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
fontSize: 14.0,
),
),
),
Expanded(
child: Text(
"passwordHint".i18n,
maxLines: 1,
textAlign: TextAlign.right,
style: const TextStyle(
color: Colors.white54,
fontWeight: FontWeight.w500,
fontSize: 12.0,
),
),
),
],
),
),
Padding(
padding: const EdgeInsets.only(bottom: 12.0),
child: LoginInput(
style: LoginInputStyle.password,
controller: passwordController,
),
),
// School
Padding(
padding: const EdgeInsets.only(bottom: 6.0),
child: Text(
"school".i18n,
maxLines: 1,
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
fontSize: 14.0,
),
),
),
SchoolInput(
scroll: _scrollController,
controller: schoolController,
),
],
),
),
),
// Log in button
SizedBox(
width: 400.0,
child: Padding(
padding: const EdgeInsets.only(top: 42.0),
child: Visibility(
child: LoginButton(
child: Text("login".i18n,
maxLines: 1,
style: const TextStyle(
fontWeight: FontWeight.w600,
fontSize: 15.0,
)),
onPressed: () => _loginApi(context: context),
),
visible: _loginState != LoginState.inProgress,
replacement: const Padding(
padding: EdgeInsets.symmetric(vertical: 6.0),
child: Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
),
),
),
),
),
),
if (_loginState == LoginState.missingFields || _loginState == LoginState.invalidGrant || _loginState == LoginState.failed)
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
["missing_fields", "invalid_grant", "error"][_loginState.index].i18n,
style: const TextStyle(color: Colors.red, fontWeight: FontWeight.w500),
),
),
],
),
),
],
),
if (showBack)
Container(
alignment: Alignment.topLeft,
padding: EdgeInsets.only(left: 16.0, top: topInset),
child: const ClipOval(
child: Material(
type: MaterialType.transparency,
child: BackButton(color: Colors.white),
),
),
),
],
),
),
);
}
void _loginApi({required BuildContext context}) {
String username = usernameController.text;
String password = passwordController.text;
if (username == "" || password == "" || schoolController.selectedSchool == null) {
return setState(() => _loginState = LoginState.missingFields);
}
setState(() => _loginState = LoginState.inProgress);
loginApi(
username: username,
password: password,
instituteCode: schoolController.selectedSchool!.instituteCode,
context: context,
onLogin: (user) {
ElegantNotification.success(
background: Colors.white,
description: Text(
"welcome".i18n.fill([user.name]),
overflow: TextOverflow.ellipsis,
style: const TextStyle(color: Colors.black),
),
onActionPressed: () {},
onCloseButtonPressed: () {},
onDismiss: () {},
onProgressFinished: () {},
displayCloseButton: false,
showProgressIndicator: false,
autoDismiss: true,
animation: AnimationType.fromTop,
).show(context);
},
onSuccess: () {
Navigator.of(context).pushNamedAndRemoveUntil("login_to_navigation", (_) => false);
}).then((res) => setState(() => _loginState = res));
}
}
import 'dart:io';
import 'dart:ui';
import 'package:elegant_notification/elegant_notification.dart';
import 'package:elegant_notification/resources/arrays.dart';
import 'package:filcnaplo/api/client.dart';
import 'package:filcnaplo/api/login.dart';
import 'package:filcnaplo/theme/colors/colors.dart';
import 'package:filcnaplo_mobile_ui/screens/login/login_button.dart';
import 'package:filcnaplo_mobile_ui/screens/login/login_input.dart';
import 'package:filcnaplo_mobile_ui/screens/login/school_input/school_input.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_acrylic/flutter_acrylic.dart';
import 'login_screen.i18n.dart';
class LoginScreen extends StatefulWidget {
const LoginScreen({Key? key, this.back = false}) : super(key: key);
final bool back;
@override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
final usernameController = TextEditingController();
final passwordController = TextEditingController();
final schoolController = SchoolInputController();
final _scrollController = ScrollController();
LoginState _loginState = LoginState.normal;
bool showBack = false;
double topInset = 12.0;
@override
void initState() {
super.initState();
showBack = widget.back;
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness: Brightness.light,
systemNavigationBarColor: Colors.white,
systemNavigationBarIconBrightness: Brightness.dark,
));
FilcAPI.getSchools().then((schools) {
if (schools != null) {
schoolController.update(() {
schoolController.schools = schools;
});
} else {
ElegantNotification.error(
background: Colors.white,
description: Text(
"schools_error".i18n,
overflow: TextOverflow.ellipsis,
style: const TextStyle(color: Colors.red),
),
onActionPressed: () {},
onCloseButtonPressed: () {},
onDismiss: () {},
onProgressFinished: () {},
displayCloseButton: false,
showProgressIndicator: false,
autoDismiss: true,
animation: AnimationType.fromTop,
).show(context);
}
});
if (Platform.isMacOS) Window.getTitlebarHeight().then((value) => setState(() => topInset = value));
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.of(context).filc,
body: SafeArea(
child: Stack(
children: [
Row(
children: [
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// App logo
Padding(
padding: const EdgeInsets.only(bottom: 24.0),
child: ClipRect(
child: Padding(
padding: const EdgeInsets.only(left: 12.0, right: 12.0, bottom: 32.0),
child: SizedBox(
width: 82.0,
height: 82.0,
// Png shadow *hack*
child: Stack(
children: [
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Opacity(child: Image.asset("assets/icons/ic_splash.png", color: Colors.black), opacity: 0.3),
),
BackdropFilter(
filter: ImageFilter.blur(sigmaX: 6.0, sigmaY: 6.0),
child: Image.asset("assets/icons/ic_splash.png"),
)
],
),
),
),
),
),
// Inputs
SizedBox(
width: 400.0,
child: AutofillGroup(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Username
Padding(
padding: const EdgeInsets.only(bottom: 6.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
"username".i18n,
maxLines: 1,
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
fontSize: 14.0,
),
),
),
Expanded(
child: Text(
"usernameHint".i18n,
maxLines: 1,
textAlign: TextAlign.right,
style: const TextStyle(
color: Colors.white54,
fontWeight: FontWeight.w500,
fontSize: 12.0,
),
),
),
],
),
),
Padding(
padding: const EdgeInsets.only(bottom: 12.0),
child: LoginInput(
style: LoginInputStyle.username,
controller: usernameController,
),
),
// Password
Padding(
padding: const EdgeInsets.only(bottom: 6.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
"password".i18n,
maxLines: 1,
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
fontSize: 14.0,
),
),
),
Expanded(
child: Text(
"passwordHint".i18n,
maxLines: 1,
textAlign: TextAlign.right,
style: const TextStyle(
color: Colors.white54,
fontWeight: FontWeight.w500,
fontSize: 12.0,
),
),
),
],
),
),
Padding(
padding: const EdgeInsets.only(bottom: 12.0),
child: LoginInput(
style: LoginInputStyle.password,
controller: passwordController,
),
),
// School
Padding(
padding: const EdgeInsets.only(bottom: 6.0),
child: Text(
"school".i18n,
maxLines: 1,
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
fontSize: 14.0,
),
),
),
SchoolInput(
scroll: _scrollController,
controller: schoolController,
),
],
),
),
),
// Log in button
SizedBox(
width: 400.0,
child: Padding(
padding: const EdgeInsets.only(top: 42.0),
child: Visibility(
child: LoginButton(
child: Text("login".i18n,
maxLines: 1,
style: const TextStyle(
fontWeight: FontWeight.w600,
fontSize: 15.0,
)),
onPressed: () => _loginApi(context: context),
),
visible: _loginState != LoginState.inProgress,
replacement: const Padding(
padding: EdgeInsets.symmetric(vertical: 6.0),
child: Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
),
),
),
),
),
),
if (_loginState == LoginState.missingFields || _loginState == LoginState.invalidGrant || _loginState == LoginState.failed)
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
["missing_fields", "invalid_grant", "error"][_loginState.index].i18n,
style: const TextStyle(color: Colors.red, fontWeight: FontWeight.w500),
),
),
],
),
),
],
),
if (showBack)
Container(
alignment: Alignment.topLeft,
padding: EdgeInsets.only(left: 16.0, top: topInset),
child: const ClipOval(
child: Material(
type: MaterialType.transparency,
child: BackButton(color: Colors.white),
),
),
),
],
),
),
);
}
void _loginApi({required BuildContext context}) {
String username = usernameController.text;
String password = passwordController.text;
if (username == "" || password == "" || schoolController.selectedSchool == null) {
return setState(() => _loginState = LoginState.missingFields);
}
setState(() => _loginState = LoginState.inProgress);
loginApi(
username: username,
password: password,
instituteCode: schoolController.selectedSchool!.instituteCode,
context: context,
onLogin: (user) {
ElegantNotification.success(
background: Colors.white,
description: Text(
"welcome".i18n.fill([user.name]),
overflow: TextOverflow.ellipsis,
style: const TextStyle(color: Colors.black),
),
onActionPressed: () {},
onCloseButtonPressed: () {},
onDismiss: () {},
onProgressFinished: () {},
displayCloseButton: false,
showProgressIndicator: false,
autoDismiss: true,
animation: AnimationType.fromTop,
).show(context);
},
onSuccess: () {
Navigator.of(context).pushNamedAndRemoveUntil("login_to_navigation", (_) => false);
}).then((res) => setState(() => _loginState = res));
}
}

View File

@@ -1,51 +1,51 @@
import 'package:i18n_extension/i18n_extension.dart';
extension Localization on String {
static final _t = Translations.byLocale("hu_hu") +
{
"en_en": {
"username": "Username",
"usernameHint": "Student ID number",
"password": "Password",
"passwordHint": "Date of birth",
"school": "School",
"login": "Log in",
"welcome": "Welcome, %s!",
"missing_fields": "Missing Fields!",
"invalid_grant": "Invalid Username/Password!",
"error": "Failed to log in.",
"schools_error": "Failed to get schools."
},
"hu_hu": {
"username": "Felhasználónév",
"usernameHint": "Oktatási azonosító",
"password": "Jelszó",
"passwordHint": "Születési dátum",
"school": "Iskola",
"login": "Belépés",
"welcome": "Üdv, %s!",
"missing_fields": "Hiányzó adatok!",
"invalid_grant": "Helytelen Felhasználónév/Jelszó!",
"error": "Sikertelen bejelentkezés.",
"schools_error": "Nem sikerült lekérni az iskolákat."
},
"de_de": {
"username": "Benutzername",
"usernameHint": "Ausbildung ID",
"password": "Passwort",
"passwordHint": "Geburtsdatum",
"school": "Schule",
"login": "Einloggen",
"welcome": "Wilkommen, %s!",
"missing_fields": "Fehlende Felder!",
"invalid_grant": "Ungültiger Benutzername/Passwort!",
"error": "Anmeldung fehlgeschlagen.",
"schools_error": "Keine Schulen gefunden."
},
};
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);
}
import 'package:i18n_extension/i18n_extension.dart';
extension Localization on String {
static final _t = Translations.byLocale("hu_hu") +
{
"en_en": {
"username": "Username",
"usernameHint": "Student ID number",
"password": "Password",
"passwordHint": "Date of birth",
"school": "School",
"login": "Log in",
"welcome": "Welcome, %s!",
"missing_fields": "Missing Fields!",
"invalid_grant": "Invalid Username/Password!",
"error": "Failed to log in.",
"schools_error": "Failed to get schools."
},
"hu_hu": {
"username": "Felhasználónév",
"usernameHint": "Oktatási azonosító",
"password": "Jelszó",
"passwordHint": "Születési dátum",
"school": "Iskola",
"login": "Belépés",
"welcome": "Üdv, %s!",
"missing_fields": "Hiányzó adatok!",
"invalid_grant": "Helytelen Felhasználónév/Jelszó!",
"error": "Sikertelen bejelentkezés.",
"schools_error": "Nem sikerült lekérni az iskolákat."
},
"de_de": {
"username": "Benutzername",
"usernameHint": "Ausbildung ID",
"password": "Passwort",
"passwordHint": "Geburtsdatum",
"school": "Schule",
"login": "Einloggen",
"welcome": "Wilkommen, %s!",
"missing_fields": "Fehlende Felder!",
"invalid_grant": "Ungültiger Benutzername/Passwort!",
"error": "Anmeldung fehlgeschlagen.",
"schools_error": "Keine Schulen gefunden."
},
};
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

@@ -1,25 +1,25 @@
class NavigationRoute {
late String _name;
late int _index;
final List<String> _internalPageMap = [
"home",
"grades",
"timetable",
"messages",
"absences",
];
String get name => _name;
int get index => _index;
set name(String n) {
_name = n;
_index = _internalPageMap.indexOf(n);
}
set index(int i) {
_index = i;
_name = _internalPageMap.elementAt(i);
}
}
class NavigationRoute {
late String _name;
late int _index;
final List<String> _internalPageMap = [
"home",
"grades",
"timetable",
"messages",
"absences",
];
String get name => _name;
int get index => _index;
set name(String n) {
_name = n;
_index = _internalPageMap.indexOf(n);
}
set index(int i) {
_index = i;
_name = _internalPageMap.elementAt(i);
}
}

View File

@@ -1,37 +1,37 @@
import 'package:animations/animations.dart';
import 'package:filcnaplo_desktop_ui/pages/absences/absences_page.dart';
import 'package:filcnaplo_desktop_ui/pages/grades/grades_page.dart';
import 'package:filcnaplo_desktop_ui/pages/home/home_page.dart';
import 'package:filcnaplo_desktop_ui/pages/messages/messages_page.dart';
import 'package:filcnaplo_desktop_ui/pages/timetable/timetable_page.dart';
import 'package:flutter/material.dart';
Route navigationRouteHandler(RouteSettings settings) {
switch (settings.name) {
case "grades":
return navigationPageRoute((context) => const GradesPage());
case "timetable":
return navigationPageRoute((context) => const TimetablePage());
case "messages":
return navigationPageRoute((context) => const MessagesPage());
case "absences":
return navigationPageRoute((context) => const AbsencesPage());
case "home":
default:
return navigationPageRoute((context) => const HomePage());
}
}
Route navigationPageRoute(Widget Function(BuildContext) builder) {
return PageRouteBuilder(
pageBuilder: (context, _, __) => builder(context),
transitionsBuilder: (context, animation, secondaryAnimation, child) {
return FadeThroughTransition(
fillColor: Theme.of(context).scaffoldBackgroundColor,
animation: animation,
secondaryAnimation: secondaryAnimation,
child: child,
);
},
);
}
import 'package:animations/animations.dart';
import 'package:filcnaplo_desktop_ui/pages/absences/absences_page.dart';
import 'package:filcnaplo_desktop_ui/pages/grades/grades_page.dart';
import 'package:filcnaplo_desktop_ui/pages/home/home_page.dart';
import 'package:filcnaplo_desktop_ui/pages/messages/messages_page.dart';
import 'package:filcnaplo_desktop_ui/pages/timetable/timetable_page.dart';
import 'package:flutter/material.dart';
Route navigationRouteHandler(RouteSettings settings) {
switch (settings.name) {
case "grades":
return navigationPageRoute((context) => const GradesPage());
case "timetable":
return navigationPageRoute((context) => const TimetablePage());
case "messages":
return navigationPageRoute((context) => const MessagesPage());
case "absences":
return navigationPageRoute((context) => const AbsencesPage());
case "home":
default:
return navigationPageRoute((context) => const HomePage());
}
}
Route navigationPageRoute(Widget Function(BuildContext) builder) {
return PageRouteBuilder(
pageBuilder: (context, _, __) => builder(context),
transitionsBuilder: (context, animation, secondaryAnimation, child) {
return FadeThroughTransition(
fillColor: Theme.of(context).scaffoldBackgroundColor,
animation: animation,
secondaryAnimation: secondaryAnimation,
child: child,
);
},
);
}

View File

@@ -1,137 +1,137 @@
import 'dart:io';
import 'package:filcnaplo/api/providers/news_provider.dart';
import 'package:filcnaplo/api/providers/sync.dart';
import 'package:filcnaplo/theme/colors/colors.dart';
import 'package:filcnaplo/theme/observer.dart';
import 'package:filcnaplo_desktop_ui/screens/navigation/navigation_route.dart';
import 'package:filcnaplo_desktop_ui/screens/navigation/navigation_route_handler.dart';
import 'package:filcnaplo_desktop_ui/screens/navigation/sidebar.dart';
import 'package:flutter/material.dart';
import 'package:flutter_acrylic/flutter_acrylic.dart';
import 'package:provider/provider.dart';
import 'package:filcnaplo/models/settings.dart';
import 'package:filcnaplo_kreta_api/client/client.dart';
class NavigationScreen extends StatefulWidget {
const NavigationScreen({Key? key}) : super(key: key);
static NavigationScreenState? of(BuildContext context) => context.findAncestorStateOfType<NavigationScreenState>();
@override
State<NavigationScreen> createState() => NavigationScreenState();
}
class NavigationScreenState extends State<NavigationScreen> with WidgetsBindingObserver {
final _navigatorState = GlobalKey<NavigatorState>();
late NavigationRoute selected;
late SettingsProvider settings;
late NewsProvider newsProvider;
double topInset = 0.0;
@override
void initState() {
super.initState();
settings = Provider.of<SettingsProvider>(context, listen: false);
selected = NavigationRoute();
selected.index = 0;
// add brightness observer
WidgetsBinding.instance.addObserver(this);
// set client User-Agent
Provider.of<KretaClient>(context, listen: false).userAgent = settings.config.userAgent;
// Get news
newsProvider = Provider.of<NewsProvider>(context, listen: false);
newsProvider.restore().then((value) => newsProvider.fetch());
// Initial sync
syncAll(context);
() async {
try {
await Window.initialize();
} catch (_) {}
// Transparent sidebar
await Window.setEffect(effect: WindowEffect.acrylic, color: Platform.isMacOS ? Colors.transparent : const Color.fromARGB(27, 27, 27, 27));
// todo: do for windows
if (Platform.isMacOS) {
topInset = await Window.getTitlebarHeight();
await Window.enableFullSizeContentView();
await Window.hideTitle();
await Window.makeTitlebarTransparent();
}
}();
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
void didChangePlatformBrightness() {
if (settings.theme == ThemeMode.system) {
Brightness? brightness = WidgetsBinding.instance.window.platformBrightness;
Provider.of<ThemeModeObserver>(context, listen: false).changeTheme(brightness == Brightness.light ? ThemeMode.light : ThemeMode.dark);
}
super.didChangePlatformBrightness();
}
void setPage(String page) => setState(() => selected.name = page);
@override
Widget build(BuildContext context) {
settings = Provider.of<SettingsProvider>(context);
newsProvider = Provider.of<NewsProvider>(context);
// Show news
WidgetsBinding.instance.addPostFrameCallback((_) {
if (newsProvider.show) {
newsProvider.lock();
// NewsView.show(newsProvider.news[newsProvider.state], context: context).then((value) => newsProvider.release());
}
});
return Scaffold(
backgroundColor: Colors.transparent,
body: Row(
children: [
if (_navigatorState.currentState != null)
Container(
decoration: BoxDecoration(
color: Theme.of(context).scaffoldBackgroundColor.withOpacity(.5),
border: Border(right: BorderSide(color: AppColors.of(context).shadow.withOpacity(.7), width: 1.0)),
),
child: Padding(
padding: EdgeInsets.only(top: topInset),
child: Sidebar(
navigator: _navigatorState.currentState!,
selected: selected.name,
onRouteChange: (name) => setPage(name),
),
),
),
Expanded(
child: Container(
color: Theme.of(context).scaffoldBackgroundColor,
child: MediaQuery(
data: MediaQuery.of(context).copyWith(
padding: EdgeInsets.only(top: topInset),
),
child: Navigator(
key: _navigatorState,
initialRoute: selected.name,
onGenerateRoute: (settings) => navigationRouteHandler(settings),
),
),
),
),
],
),
);
}
}
import 'dart:io';
import 'package:filcnaplo/api/providers/news_provider.dart';
import 'package:filcnaplo/api/providers/sync.dart';
import 'package:filcnaplo/theme/colors/colors.dart';
import 'package:filcnaplo/theme/observer.dart';
import 'package:filcnaplo_desktop_ui/screens/navigation/navigation_route.dart';
import 'package:filcnaplo_desktop_ui/screens/navigation/navigation_route_handler.dart';
import 'package:filcnaplo_desktop_ui/screens/navigation/sidebar.dart';
import 'package:flutter/material.dart';
import 'package:flutter_acrylic/flutter_acrylic.dart';
import 'package:provider/provider.dart';
import 'package:filcnaplo/models/settings.dart';
import 'package:filcnaplo_kreta_api/client/client.dart';
class NavigationScreen extends StatefulWidget {
const NavigationScreen({Key? key}) : super(key: key);
static NavigationScreenState? of(BuildContext context) => context.findAncestorStateOfType<NavigationScreenState>();
@override
State<NavigationScreen> createState() => NavigationScreenState();
}
class NavigationScreenState extends State<NavigationScreen> with WidgetsBindingObserver {
final _navigatorState = GlobalKey<NavigatorState>();
late NavigationRoute selected;
late SettingsProvider settings;
late NewsProvider newsProvider;
double topInset = 0.0;
@override
void initState() {
super.initState();
settings = Provider.of<SettingsProvider>(context, listen: false);
selected = NavigationRoute();
selected.index = 0;
// add brightness observer
WidgetsBinding.instance.addObserver(this);
// set client User-Agent
Provider.of<KretaClient>(context, listen: false).userAgent = settings.config.userAgent;
// Get news
newsProvider = Provider.of<NewsProvider>(context, listen: false);
newsProvider.restore().then((value) => newsProvider.fetch());
// Initial sync
syncAll(context);
() async {
try {
await Window.initialize();
} catch (_) {}
// Transparent sidebar
await Window.setEffect(effect: WindowEffect.acrylic, color: Platform.isMacOS ? Colors.transparent : const Color.fromARGB(27, 27, 27, 27));
// todo: do for windows
if (Platform.isMacOS) {
topInset = await Window.getTitlebarHeight();
await Window.enableFullSizeContentView();
await Window.hideTitle();
await Window.makeTitlebarTransparent();
}
}();
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
void didChangePlatformBrightness() {
if (settings.theme == ThemeMode.system) {
Brightness? brightness = WidgetsBinding.instance.window.platformBrightness;
Provider.of<ThemeModeObserver>(context, listen: false).changeTheme(brightness == Brightness.light ? ThemeMode.light : ThemeMode.dark);
}
super.didChangePlatformBrightness();
}
void setPage(String page) => setState(() => selected.name = page);
@override
Widget build(BuildContext context) {
settings = Provider.of<SettingsProvider>(context);
newsProvider = Provider.of<NewsProvider>(context);
// Show news
WidgetsBinding.instance.addPostFrameCallback((_) {
if (newsProvider.show) {
newsProvider.lock();
// NewsView.show(newsProvider.news[newsProvider.state], context: context).then((value) => newsProvider.release());
}
});
return Scaffold(
backgroundColor: Colors.transparent,
body: Row(
children: [
if (_navigatorState.currentState != null)
Container(
decoration: BoxDecoration(
color: Theme.of(context).scaffoldBackgroundColor.withOpacity(.5),
border: Border(right: BorderSide(color: AppColors.of(context).shadow.withOpacity(.7), width: 1.0)),
),
child: Padding(
padding: EdgeInsets.only(top: topInset),
child: Sidebar(
navigator: _navigatorState.currentState!,
selected: selected.name,
onRouteChange: (name) => setPage(name),
),
),
),
Expanded(
child: Container(
color: Theme.of(context).scaffoldBackgroundColor,
child: MediaQuery(
data: MediaQuery.of(context).copyWith(
padding: EdgeInsets.only(top: topInset),
),
child: Navigator(
key: _navigatorState,
initialRoute: selected.name,
onGenerateRoute: (settings) => navigationRouteHandler(settings),
),
),
),
),
],
),
);
}
}

View File

@@ -1,304 +1,304 @@
import 'package:animations/animations.dart';
import 'package:filcnaplo/api/providers/database_provider.dart';
import 'package:filcnaplo/api/providers/user_provider.dart';
import 'package:filcnaplo/icons/filc_icons.dart';
import 'package:filcnaplo/models/settings.dart';
import 'package:filcnaplo/utils/color.dart';
import 'package:filcnaplo_desktop_ui/common/panel_button.dart';
import 'package:filcnaplo_desktop_ui/common/profile_image.dart';
import 'package:filcnaplo_desktop_ui/screens/navigation/sidebar_action.dart';
import 'package:filcnaplo_desktop_ui/screens/settings/settings_screen.dart';
import 'package:filcnaplo_mobile_ui/screens/settings/accounts/account_tile.dart';
import 'package:filcnaplo_kreta_api/client/client.dart';
import 'package:filcnaplo_kreta_api/providers/absence_provider.dart';
import 'package:filcnaplo_kreta_api/providers/event_provider.dart';
import 'package:filcnaplo_kreta_api/providers/exam_provider.dart';
import 'package:filcnaplo_kreta_api/providers/grade_provider.dart';
import 'package:filcnaplo_kreta_api/providers/homework_provider.dart';
import 'package:filcnaplo_kreta_api/providers/message_provider.dart';
import 'package:filcnaplo_kreta_api/providers/note_provider.dart';
import 'package:filcnaplo_kreta_api/providers/timetable_provider.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:provider/provider.dart';
import 'package:filcnaplo/theme/colors/colors.dart';
class Sidebar extends StatefulWidget {
const Sidebar({Key? key, required this.navigator, required this.onRouteChange, this.selected = "home"}) : super(key: key);
final NavigatorState navigator;
final String selected;
final Function(String) onRouteChange;
@override
State<Sidebar> createState() => _SidebarState();
}
class _SidebarState extends State<Sidebar> {
late UserProvider user;
late SettingsProvider settings;
late String firstName;
String topNav = "";
bool expandAccount = false;
List<Widget> accountTiles = [];
@override
void initState() {
super.initState();
user = Provider.of<UserProvider>(context, listen: false);
}
Future<void> restore() => Future.wait([
Provider.of<GradeProvider>(context, listen: false).restore(),
Provider.of<TimetableProvider>(context, listen: false).restoreUser(),
Provider.of<ExamProvider>(context, listen: false).restore(),
Provider.of<HomeworkProvider>(context, listen: false).restore(),
Provider.of<MessageProvider>(context, listen: false).restore(),
Provider.of<NoteProvider>(context, listen: false).restore(),
Provider.of<EventProvider>(context, listen: false).restore(),
Provider.of<AbsenceProvider>(context, listen: false).restore(),
Provider.of<KretaClient>(context, listen: false).refreshLogin(),
]);
@override
Widget build(BuildContext context) {
user = Provider.of<UserProvider>(context);
settings = Provider.of<SettingsProvider>(context);
List<String> nameParts = user.name?.split(" ") ?? ["?"];
if (!settings.presentationMode) {
firstName = nameParts.length > 1 ? nameParts[1] : nameParts[0];
} else {
firstName = "Béla";
}
List<Widget> pageWidgets = [
SidebarAction(
title: const Text("Home"),
icon: const Icon(FilcIcons.home),
selected: widget.selected == "home",
onTap: () {
if (widget.selected != "home") {
widget.navigator.pushReplacementNamed("home");
widget.onRouteChange("home");
}
},
),
SidebarAction(
title: const Text("Grades"),
icon: const Icon(FeatherIcons.bookmark),
selected: widget.selected == "grades",
onTap: () {
if (widget.selected != "grades") {
widget.navigator.pushReplacementNamed("grades");
widget.onRouteChange("grades");
}
},
),
SidebarAction(
title: const Text("Timetable"),
icon: const Icon(FeatherIcons.calendar),
selected: widget.selected == "timetable",
onTap: () {
if (widget.selected != "timetable") {
widget.navigator.pushReplacementNamed("timetable");
widget.onRouteChange("timetable");
}
},
),
SidebarAction(
title: const Text("Messages"),
icon: const Icon(FeatherIcons.messageSquare),
selected: widget.selected == "messages",
onTap: () {
if (widget.selected != "messages") {
widget.navigator.pushReplacementNamed("messages");
widget.onRouteChange("messages");
}
},
),
SidebarAction(
title: const Text("Absences"),
icon: const Icon(FeatherIcons.clock),
selected: widget.selected == "absences",
onTap: () {
if (widget.selected != "absences") {
widget.navigator.pushReplacementNamed("absences");
widget.onRouteChange("absences");
}
},
),
];
List<Widget> bottomActions = [
SidebarAction(
title: const Text("Settings"),
selected: true,
icon: const Icon(FeatherIcons.settings),
onTap: () {
if (topNav != "settings") {
widget.navigator.push(CupertinoPageRoute(builder: (context) => const SettingsScreen())).then((value) => topNav = "");
topNav = "settings";
}
},
),
];
buildAccountTiles();
List<Widget> accountWidgets = [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: Column(children: accountTiles),
),
// Account settings
PanelButton(
onPressed: () {
Navigator.of(context).pushNamed("login_back");
},
title: const Text("Add User"),
leading: const Icon(FeatherIcons.userPlus),
),
PanelButton(
onPressed: () async {
String? userId = user.id;
if (userId == null) return;
// Delete User
user.removeUser(userId);
await Provider.of<DatabaseProvider>(context, listen: false).store.removeUser(userId);
// If no other Users left, go back to LoginScreen
if (user.getUsers().isNotEmpty) {
user.setUser(user.getUsers().first.id);
restore().then((_) => user.setUser(user.getUsers().first.id));
} else {
Navigator.of(context).pushNamedAndRemoveUntil("login", (_) => false);
}
},
title: const Text("Log Out"),
leading: Icon(FeatherIcons.logOut, color: AppColors.of(context).red),
),
];
return SizedBox(
height: double.infinity,
width: 250.0,
child: Column(
children: [
Padding(
padding: const EdgeInsets.only(left: 18.0, top: 18.0, bottom: 24.0, right: 8.0),
child: Row(
children: [
Padding(
padding: const EdgeInsets.only(right: 12.0),
child: ProfileImage(
name: firstName,
radius: 18.0,
backgroundColor:
!settings.presentationMode ? ColorUtils.stringToColor(user.name ?? "?") : Theme.of(context).colorScheme.secondary,
),
),
Expanded(
child: Text(
firstName,
style: const TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.w600,
),
),
),
PageTransitionSwitcher(
transitionBuilder: (child, primaryAnimation, secondaryAnimation) {
return FadeThroughTransition(
fillColor: Colors.transparent,
animation: primaryAnimation,
secondaryAnimation: secondaryAnimation,
child: child,
);
},
child: IconButton(
key: Key(expandAccount ? "accounts" : "pages"),
icon: Icon(expandAccount ? FeatherIcons.chevronDown : FeatherIcons.chevronRight),
padding: EdgeInsets.zero,
splashRadius: 20.0,
onPressed: () {
setState(() {
expandAccount = !expandAccount;
});
},
),
),
],
),
),
// Pages
Expanded(
child: PageTransitionSwitcher(
duration: const Duration(milliseconds: 500),
transitionBuilder: (child, primaryAnimation, secondaryAnimation) {
return SharedAxisTransition(
fillColor: Colors.transparent,
animation: primaryAnimation,
secondaryAnimation: secondaryAnimation,
transitionType: SharedAxisTransitionType.scaled,
child: child,
);
},
child: !expandAccount
? Column(
key: const Key("pages"),
children: pageWidgets,
)
: Column(
key: const Key("accounts"),
children: accountWidgets,
),
),
),
// Settings
...bottomActions,
// Bottom padding
const SizedBox(height: 12.0),
],
),
);
}
void buildAccountTiles() {
accountTiles = [];
user.getUsers().forEach((account) {
if (account.id == user.id) return;
String _firstName;
List<String> _nameParts = user.name?.split(" ") ?? ["?"];
if (!settings.presentationMode) {
_firstName = _nameParts.length > 1 ? _nameParts[1] : _nameParts[0];
} else {
_firstName = "Béla";
}
accountTiles.add(AccountTile(
name: Text(!settings.presentationMode ? account.name : "Béla", style: const TextStyle(fontWeight: FontWeight.w500)),
username: Text(!settings.presentationMode ? account.username : "72469696969"),
profileImage: ProfileImage(
name: _firstName,
backgroundColor: !settings.presentationMode ? ColorUtils.stringToColor(account.name) : Theme.of(context).colorScheme.secondary,
role: account.role,
),
onTap: () {
user.setUser(account.id);
restore().then((_) => user.setUser(account.id));
},
// onTapMenu: () => _showBottomSheet(account),
));
});
}
}
import 'package:animations/animations.dart';
import 'package:filcnaplo/api/providers/database_provider.dart';
import 'package:filcnaplo/api/providers/user_provider.dart';
import 'package:filcnaplo/icons/filc_icons.dart';
import 'package:filcnaplo/models/settings.dart';
import 'package:filcnaplo/utils/color.dart';
import 'package:filcnaplo_desktop_ui/common/panel_button.dart';
import 'package:filcnaplo_desktop_ui/common/profile_image.dart';
import 'package:filcnaplo_desktop_ui/screens/navigation/sidebar_action.dart';
import 'package:filcnaplo_desktop_ui/screens/settings/settings_screen.dart';
import 'package:filcnaplo_mobile_ui/screens/settings/accounts/account_tile.dart';
import 'package:filcnaplo_kreta_api/client/client.dart';
import 'package:filcnaplo_kreta_api/providers/absence_provider.dart';
import 'package:filcnaplo_kreta_api/providers/event_provider.dart';
import 'package:filcnaplo_kreta_api/providers/exam_provider.dart';
import 'package:filcnaplo_kreta_api/providers/grade_provider.dart';
import 'package:filcnaplo_kreta_api/providers/homework_provider.dart';
import 'package:filcnaplo_kreta_api/providers/message_provider.dart';
import 'package:filcnaplo_kreta_api/providers/note_provider.dart';
import 'package:filcnaplo_kreta_api/providers/timetable_provider.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:provider/provider.dart';
import 'package:filcnaplo/theme/colors/colors.dart';
class Sidebar extends StatefulWidget {
const Sidebar({Key? key, required this.navigator, required this.onRouteChange, this.selected = "home"}) : super(key: key);
final NavigatorState navigator;
final String selected;
final Function(String) onRouteChange;
@override
State<Sidebar> createState() => _SidebarState();
}
class _SidebarState extends State<Sidebar> {
late UserProvider user;
late SettingsProvider settings;
late String firstName;
String topNav = "";
bool expandAccount = false;
List<Widget> accountTiles = [];
@override
void initState() {
super.initState();
user = Provider.of<UserProvider>(context, listen: false);
}
Future<void> restore() => Future.wait([
Provider.of<GradeProvider>(context, listen: false).restore(),
Provider.of<TimetableProvider>(context, listen: false).restoreUser(),
Provider.of<ExamProvider>(context, listen: false).restore(),
Provider.of<HomeworkProvider>(context, listen: false).restore(),
Provider.of<MessageProvider>(context, listen: false).restore(),
Provider.of<NoteProvider>(context, listen: false).restore(),
Provider.of<EventProvider>(context, listen: false).restore(),
Provider.of<AbsenceProvider>(context, listen: false).restore(),
Provider.of<KretaClient>(context, listen: false).refreshLogin(),
]);
@override
Widget build(BuildContext context) {
user = Provider.of<UserProvider>(context);
settings = Provider.of<SettingsProvider>(context);
List<String> nameParts = user.name?.split(" ") ?? ["?"];
if (!settings.presentationMode) {
firstName = nameParts.length > 1 ? nameParts[1] : nameParts[0];
} else {
firstName = "Béla";
}
List<Widget> pageWidgets = [
SidebarAction(
title: const Text("Home"),
icon: const Icon(FilcIcons.home),
selected: widget.selected == "home",
onTap: () {
if (widget.selected != "home") {
widget.navigator.pushReplacementNamed("home");
widget.onRouteChange("home");
}
},
),
SidebarAction(
title: const Text("Grades"),
icon: const Icon(FeatherIcons.bookmark),
selected: widget.selected == "grades",
onTap: () {
if (widget.selected != "grades") {
widget.navigator.pushReplacementNamed("grades");
widget.onRouteChange("grades");
}
},
),
SidebarAction(
title: const Text("Timetable"),
icon: const Icon(FeatherIcons.calendar),
selected: widget.selected == "timetable",
onTap: () {
if (widget.selected != "timetable") {
widget.navigator.pushReplacementNamed("timetable");
widget.onRouteChange("timetable");
}
},
),
SidebarAction(
title: const Text("Messages"),
icon: const Icon(FeatherIcons.messageSquare),
selected: widget.selected == "messages",
onTap: () {
if (widget.selected != "messages") {
widget.navigator.pushReplacementNamed("messages");
widget.onRouteChange("messages");
}
},
),
SidebarAction(
title: const Text("Absences"),
icon: const Icon(FeatherIcons.clock),
selected: widget.selected == "absences",
onTap: () {
if (widget.selected != "absences") {
widget.navigator.pushReplacementNamed("absences");
widget.onRouteChange("absences");
}
},
),
];
List<Widget> bottomActions = [
SidebarAction(
title: const Text("Settings"),
selected: true,
icon: const Icon(FeatherIcons.settings),
onTap: () {
if (topNav != "settings") {
widget.navigator.push(CupertinoPageRoute(builder: (context) => const SettingsScreen())).then((value) => topNav = "");
topNav = "settings";
}
},
),
];
buildAccountTiles();
List<Widget> accountWidgets = [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: Column(children: accountTiles),
),
// Account settings
PanelButton(
onPressed: () {
Navigator.of(context).pushNamed("login_back");
},
title: const Text("Add User"),
leading: const Icon(FeatherIcons.userPlus),
),
PanelButton(
onPressed: () async {
String? userId = user.id;
if (userId == null) return;
// Delete User
user.removeUser(userId);
await Provider.of<DatabaseProvider>(context, listen: false).store.removeUser(userId);
// If no other Users left, go back to LoginScreen
if (user.getUsers().isNotEmpty) {
user.setUser(user.getUsers().first.id);
restore().then((_) => user.setUser(user.getUsers().first.id));
} else {
Navigator.of(context).pushNamedAndRemoveUntil("login", (_) => false);
}
},
title: const Text("Log Out"),
leading: Icon(FeatherIcons.logOut, color: AppColors.of(context).red),
),
];
return SizedBox(
height: double.infinity,
width: 250.0,
child: Column(
children: [
Padding(
padding: const EdgeInsets.only(left: 18.0, top: 18.0, bottom: 24.0, right: 8.0),
child: Row(
children: [
Padding(
padding: const EdgeInsets.only(right: 12.0),
child: ProfileImage(
name: firstName,
radius: 18.0,
backgroundColor:
!settings.presentationMode ? ColorUtils.stringToColor(user.name ?? "?") : Theme.of(context).colorScheme.secondary,
),
),
Expanded(
child: Text(
firstName,
style: const TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.w600,
),
),
),
PageTransitionSwitcher(
transitionBuilder: (child, primaryAnimation, secondaryAnimation) {
return FadeThroughTransition(
fillColor: Colors.transparent,
animation: primaryAnimation,
secondaryAnimation: secondaryAnimation,
child: child,
);
},
child: IconButton(
key: Key(expandAccount ? "accounts" : "pages"),
icon: Icon(expandAccount ? FeatherIcons.chevronDown : FeatherIcons.chevronRight),
padding: EdgeInsets.zero,
splashRadius: 20.0,
onPressed: () {
setState(() {
expandAccount = !expandAccount;
});
},
),
),
],
),
),
// Pages
Expanded(
child: PageTransitionSwitcher(
duration: const Duration(milliseconds: 500),
transitionBuilder: (child, primaryAnimation, secondaryAnimation) {
return SharedAxisTransition(
fillColor: Colors.transparent,
animation: primaryAnimation,
secondaryAnimation: secondaryAnimation,
transitionType: SharedAxisTransitionType.scaled,
child: child,
);
},
child: !expandAccount
? Column(
key: const Key("pages"),
children: pageWidgets,
)
: Column(
key: const Key("accounts"),
children: accountWidgets,
),
),
),
// Settings
...bottomActions,
// Bottom padding
const SizedBox(height: 12.0),
],
),
);
}
void buildAccountTiles() {
accountTiles = [];
user.getUsers().forEach((account) {
if (account.id == user.id) return;
String _firstName;
List<String> _nameParts = user.name?.split(" ") ?? ["?"];
if (!settings.presentationMode) {
_firstName = _nameParts.length > 1 ? _nameParts[1] : _nameParts[0];
} else {
_firstName = "Béla";
}
accountTiles.add(AccountTile(
name: Text(!settings.presentationMode ? account.name : "Béla", style: const TextStyle(fontWeight: FontWeight.w500)),
username: Text(!settings.presentationMode ? account.username : "72469696969"),
profileImage: ProfileImage(
name: _firstName,
backgroundColor: !settings.presentationMode ? ColorUtils.stringToColor(account.name) : Theme.of(context).colorScheme.secondary,
role: account.role,
),
onTap: () {
user.setUser(account.id);
restore().then((_) => user.setUser(account.id));
},
// onTapMenu: () => _showBottomSheet(account),
));
});
}
}

View File

@@ -1,49 +1,49 @@
import 'package:flutter/material.dart';
import 'package:filcnaplo/theme/colors/colors.dart';
class SidebarAction extends StatelessWidget {
const SidebarAction({Key? key, this.title, this.icon, this.onTap, this.selected = false}) : super(key: key);
final bool selected;
final Widget? icon;
final Widget? title;
final Function()? onTap;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 2.0, horizontal: 12.0),
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(12.0),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
if (icon != null)
IconTheme(
data: IconThemeData(
color: AppColors.of(context).text.withOpacity(selected ? 1.0 : .3),
),
child: icon!,
),
if (title != null)
Padding(
padding: const EdgeInsets.only(left: 24.0),
child: AnimatedDefaultTextStyle(
duration: const Duration(milliseconds: 500),
style: TextStyle(
color: AppColors.of(context).text.withOpacity(selected ? 1.0 : .8),
fontWeight: FontWeight.w500,
fontFamily: "Montserrat",
),
child: title!,
),
),
],
),
),
),
);
}
}
import 'package:flutter/material.dart';
import 'package:filcnaplo/theme/colors/colors.dart';
class SidebarAction extends StatelessWidget {
const SidebarAction({Key? key, this.title, this.icon, this.onTap, this.selected = false}) : super(key: key);
final bool selected;
final Widget? icon;
final Widget? title;
final Function()? onTap;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 2.0, horizontal: 12.0),
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(12.0),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
if (icon != null)
IconTheme(
data: IconThemeData(
color: AppColors.of(context).text.withOpacity(selected ? 1.0 : .3),
),
child: icon!,
),
if (title != null)
Padding(
padding: const EdgeInsets.only(left: 24.0),
child: AnimatedDefaultTextStyle(
duration: const Duration(milliseconds: 500),
style: TextStyle(
color: AppColors.of(context).text.withOpacity(selected ? 1.0 : .8),
fontWeight: FontWeight.w500,
fontFamily: "Montserrat",
),
child: title!,
),
),
],
),
),
),
);
}
}

View File

@@ -1,10 +1,10 @@
import 'package:flutter/material.dart';
class NewsView extends StatelessWidget {
const NewsView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container();
}
}
import 'package:flutter/material.dart';
class NewsView extends StatelessWidget {
const NewsView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,188 +1,188 @@
import 'package:i18n_extension/i18n_extension.dart';
extension SettingsLocalization on String {
static final _t = Translations.byLocale("hu_hu") +
{
"en_en": {
"personal_details": "Personal Details",
"open_dkt": "Open DKT",
"edit_nickname": "Edit Nickname",
"edit_profile_picture": "Edit Profile Picture",
"remove_profile_picture": "Remove Profile Picture",
"light": "Light",
"dark": "Dark",
"system": "System",
"add_user": "Add User",
"log_out": "Log Out",
"update_available": "Update Available",
"general": "General",
"language": "Language",
"startpage": "Startpage",
"rounding": "Rounding",
"appearance": "Appearance",
"theme": "Theme",
"color": "Color",
"grade_colors": "Grade Colors",
"notifications": "Notifications",
"news": "News",
"extras": "Extras",
"about": "About",
"supporters": "Supporters",
"privacy": "Privacy Policy",
"licenses": "Licenses",
"vibrate": "Vibration",
"voff": "Off",
"vlight": "Light",
"vmedium": "Medium",
"vstrong": "Strong",
"cancel": "Cancel",
"done": "Done",
"reset": "Reset",
"open": "Open",
"data_collected": "Data collected: Platform (eg. Android), App version (eg. 3.0.0), Unique Install Identifier",
"Analytics": "Analytics",
"Anonymous Usage Analytics": "Anonymous Usage Analytics",
"graph_class_avg": "Class average on graph",
"goodstudent": "Good student mode",
"attention": "Attention!",
"goodstudent_disclaimer":
"Filc Napló® Informatikai Zrt. can not be held liable for the usage of this feature.\n\n(if your mother beats you up because you showed her fake grades, you can only blame yourself for it)",
"understand": "I understand",
"secret": "Secret Settings",
"bell_delay": "Bell Delay",
"delay": "Delay",
"hurry": "Hurry",
"sync": "Synchronize",
"sync_help": "Press the Synchronize button when the bell rings.",
"surprise_grades": "Surprise Grades",
"icon_pack": "Icon Pack",
"change_username": "Set a nickname",
"Accent Color": "Accent Color",
"Background Color": "Background Color",
"Highlight Color": "Highlight Color",
"Adaptive Theme": "Adaptive Theme",
},
"hu_hu": {
"personal_details": "Személyes információk",
"open_dkt": "DKT megnyitása",
"edit_nickname": "Becenév szerkesztése",
"edit_profile_picture": "Profil-kép szerkesztése",
"remove_profile_picture": "Profil-kép törlése",
"light": "Világos",
"dark": "Sötét",
"system": "Rendszer",
"add_user": "Felhasználó hozzáadása",
"log_out": "Kijelentkezés",
"update_available": "Frissítés elérhető",
"general": "Általános",
"language": "Nyelv",
"startpage": "Kezdőlap",
"rounding": "Kerekítés",
"appearance": "Kinézet",
"theme": "Téma",
"color": "Színek",
"grade_colors": "Jegyek színei",
"notifications": "Értesítések",
"news": "Hírek",
"extras": "Extrák",
"about": "Névjegy",
"supporters": "Támogatók",
"privacy": "Adatvédelmi irányelvek",
"licenses": "Licenszek",
"vibrate": "Rezgés",
"voff": "Kikapcsolás",
"vlight": "Alacsony",
"vmedium": "Közepes",
"vstrong": "Erős",
"cancel": "Mégsem",
"done": "Kész",
"reset": "Visszaállítás",
"open": "Megnyitás",
"data_collected": "Gyűjtött adat: Platform (pl. Android), App verzió (pl. 3.0.0), Egyedi telepítési azonosító",
"Analytics": "Analitika",
"Anonymous Usage Analytics": "Névtelen használati analitika",
"graph_class_avg": "Osztályátlag a grafikonon",
"goodstudent": "Jó tanuló mód",
"attention": "Figyelem!",
"goodstudent_disclaimer":
"A Filc Napló® Informatikai Zrt. minden felelősséget elhárít a funkció használatával kapcsolatban.\n\n(Értsd: ha az anyád megver, mert megtévesztő ábrákat mutattál neki, azért csakis magadadat hibáztathatod.)",
"understand": "Értem",
"secret": "Titkos Beállítások",
"bell_delay": "Csengő eltolódása",
"delay": "Késleltetés",
"hurry": "Siettetés",
"sync": "Szinkronizálás",
"sync_help": "Csengetéskor nyomd meg a Szinkronizálás gombot.",
"surprise_grades": "Meglepetés jegyek",
"icon_pack": "Ikon séma",
"change_username": "Becenév beállítása",
"Accent Color": "Egyedi szín",
"Background Color": "Háttér színe",
"Highlight Color": "Panelek színe",
"Adaptive Theme": "Adaptív téma",
},
"de_de": {
"personal_details": "Persönliche Angaben",
"open_dkt": "Öffnen DKT",
"edit_nickname": "Spitznamen bearbeiten",
"edit_profile_picture": "Profilbild bearbeiten",
"remove_profile_picture": "Profilbild entfernen",
"light": "Licht",
"dark": "Dunkel",
"system": "System",
"add_user": "Benutzer hinzufügen",
"log_out": "Abmelden",
"update_available": "Update verfügbar",
"general": "Allgemein",
"language": "Sprache",
"startpage": "Startseite",
"rounding": "Rundung",
"appearance": "Erscheinungsbild",
"theme": "Thema",
"color": "Farbe",
"grade_colors": "Grad Farben",
"notifications": "Benachrichtigungen",
"news": "Nachrichten",
"extras": "Extras",
"about": "Informationen",
"supporters": "Unterstützer",
"privacy": "Datenschutzbestimmungen",
"licenses": "Lizenzen",
"vibrate": "Vibration",
"voff": "Aus",
"vlight": "Leicht",
"vmedium": "Mittel",
"vstrong": "Stark",
"cancel": "Abbrechen",
"done": "Fertig",
"reset": "Zurücksetzen",
"open": "Öffnen",
"data_collected": "Erhobene Daten: Plattform (z.B. Android), App version (z.B. 3.0.0), Eindeutige Installationskennung",
"Analytics": "Analytik",
"Anonymous Usage Analytics": "Anonyme Nutzungsanalyse",
"graph_class_avg": "Klassendurchschnitt in der Grafik",
"goodstudent": "Guter Student Modus",
"attention": "Achtung!",
"goodstudent_disclaimer": "Same in English.",
"understand": "Ich verstehe",
"secret": "Geheime Einstellungen",
"bell_delay": "Klingelverzögerung",
"delay": "Verzögern",
"hurry": "Eile",
"sync": "Synchronisieren",
"sync_help": "Drücken Sie die Sync-Taste, wenn die Glocke läutet.",
"surprise_grades": "Überraschungsnoten",
"icon_pack": "Icon-Pack",
"change_username": "Einen Spitznamen festlegen",
"Accent Color": "Accent Color",
"Background Color": "Background Color",
"Highlight Color": "Highlight Color",
"Adaptive Theme": "Adaptive Theme",
},
};
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);
}
import 'package:i18n_extension/i18n_extension.dart';
extension SettingsLocalization on String {
static final _t = Translations.byLocale("hu_hu") +
{
"en_en": {
"personal_details": "Personal Details",
"open_dkt": "Open DKT",
"edit_nickname": "Edit Nickname",
"edit_profile_picture": "Edit Profile Picture",
"remove_profile_picture": "Remove Profile Picture",
"light": "Light",
"dark": "Dark",
"system": "System",
"add_user": "Add User",
"log_out": "Log Out",
"update_available": "Update Available",
"general": "General",
"language": "Language",
"startpage": "Startpage",
"rounding": "Rounding",
"appearance": "Appearance",
"theme": "Theme",
"color": "Color",
"grade_colors": "Grade Colors",
"notifications": "Notifications",
"news": "News",
"extras": "Extras",
"about": "About",
"supporters": "Supporters",
"privacy": "Privacy Policy",
"licenses": "Licenses",
"vibrate": "Vibration",
"voff": "Off",
"vlight": "Light",
"vmedium": "Medium",
"vstrong": "Strong",
"cancel": "Cancel",
"done": "Done",
"reset": "Reset",
"open": "Open",
"data_collected": "Data collected: Platform (eg. Android), App version (eg. 3.0.0), Unique Install Identifier",
"Analytics": "Analytics",
"Anonymous Usage Analytics": "Anonymous Usage Analytics",
"graph_class_avg": "Class average on graph",
"goodstudent": "Good student mode",
"attention": "Attention!",
"goodstudent_disclaimer":
"Filc Napló® Informatikai Zrt. can not be held liable for the usage of this feature.\n\n(if your mother beats you up because you showed her fake grades, you can only blame yourself for it)",
"understand": "I understand",
"secret": "Secret Settings",
"bell_delay": "Bell Delay",
"delay": "Delay",
"hurry": "Hurry",
"sync": "Synchronize",
"sync_help": "Press the Synchronize button when the bell rings.",
"surprise_grades": "Surprise Grades",
"icon_pack": "Icon Pack",
"change_username": "Set a nickname",
"Accent Color": "Accent Color",
"Background Color": "Background Color",
"Highlight Color": "Highlight Color",
"Adaptive Theme": "Adaptive Theme",
},
"hu_hu": {
"personal_details": "Személyes információk",
"open_dkt": "DKT megnyitása",
"edit_nickname": "Becenév szerkesztése",
"edit_profile_picture": "Profil-kép szerkesztése",
"remove_profile_picture": "Profil-kép törlése",
"light": "Világos",
"dark": "Sötét",
"system": "Rendszer",
"add_user": "Felhasználó hozzáadása",
"log_out": "Kijelentkezés",
"update_available": "Frissítés elérhető",
"general": "Általános",
"language": "Nyelv",
"startpage": "Kezdőlap",
"rounding": "Kerekítés",
"appearance": "Kinézet",
"theme": "Téma",
"color": "Színek",
"grade_colors": "Jegyek színei",
"notifications": "Értesítések",
"news": "Hírek",
"extras": "Extrák",
"about": "Névjegy",
"supporters": "Támogatók",
"privacy": "Adatvédelmi irányelvek",
"licenses": "Licenszek",
"vibrate": "Rezgés",
"voff": "Kikapcsolás",
"vlight": "Alacsony",
"vmedium": "Közepes",
"vstrong": "Erős",
"cancel": "Mégsem",
"done": "Kész",
"reset": "Visszaállítás",
"open": "Megnyitás",
"data_collected": "Gyűjtött adat: Platform (pl. Android), App verzió (pl. 3.0.0), Egyedi telepítési azonosító",
"Analytics": "Analitika",
"Anonymous Usage Analytics": "Névtelen használati analitika",
"graph_class_avg": "Osztályátlag a grafikonon",
"goodstudent": "Jó tanuló mód",
"attention": "Figyelem!",
"goodstudent_disclaimer":
"A Filc Napló® Informatikai Zrt. minden felelősséget elhárít a funkció használatával kapcsolatban.\n\n(Értsd: ha az anyád megver, mert megtévesztő ábrákat mutattál neki, azért csakis magadadat hibáztathatod.)",
"understand": "Értem",
"secret": "Titkos Beállítások",
"bell_delay": "Csengő eltolódása",
"delay": "Késleltetés",
"hurry": "Siettetés",
"sync": "Szinkronizálás",
"sync_help": "Csengetéskor nyomd meg a Szinkronizálás gombot.",
"surprise_grades": "Meglepetés jegyek",
"icon_pack": "Ikon séma",
"change_username": "Becenév beállítása",
"Accent Color": "Egyedi szín",
"Background Color": "Háttér színe",
"Highlight Color": "Panelek színe",
"Adaptive Theme": "Adaptív téma",
},
"de_de": {
"personal_details": "Persönliche Angaben",
"open_dkt": "Öffnen DKT",
"edit_nickname": "Spitznamen bearbeiten",
"edit_profile_picture": "Profilbild bearbeiten",
"remove_profile_picture": "Profilbild entfernen",
"light": "Licht",
"dark": "Dunkel",
"system": "System",
"add_user": "Benutzer hinzufügen",
"log_out": "Abmelden",
"update_available": "Update verfügbar",
"general": "Allgemein",
"language": "Sprache",
"startpage": "Startseite",
"rounding": "Rundung",
"appearance": "Erscheinungsbild",
"theme": "Thema",
"color": "Farbe",
"grade_colors": "Grad Farben",
"notifications": "Benachrichtigungen",
"news": "Nachrichten",
"extras": "Extras",
"about": "Informationen",
"supporters": "Unterstützer",
"privacy": "Datenschutzbestimmungen",
"licenses": "Lizenzen",
"vibrate": "Vibration",
"voff": "Aus",
"vlight": "Leicht",
"vmedium": "Mittel",
"vstrong": "Stark",
"cancel": "Abbrechen",
"done": "Fertig",
"reset": "Zurücksetzen",
"open": "Öffnen",
"data_collected": "Erhobene Daten: Plattform (z.B. Android), App version (z.B. 3.0.0), Eindeutige Installationskennung",
"Analytics": "Analytik",
"Anonymous Usage Analytics": "Anonyme Nutzungsanalyse",
"graph_class_avg": "Klassendurchschnitt in der Grafik",
"goodstudent": "Guter Student Modus",
"attention": "Achtung!",
"goodstudent_disclaimer": "Same in English.",
"understand": "Ich verstehe",
"secret": "Geheime Einstellungen",
"bell_delay": "Klingelverzögerung",
"delay": "Verzögern",
"hurry": "Eile",
"sync": "Synchronisieren",
"sync_help": "Drücken Sie die Sync-Taste, wenn die Glocke läutet.",
"surprise_grades": "Überraschungsnoten",
"icon_pack": "Icon-Pack",
"change_username": "Einen Spitznamen festlegen",
"Accent Color": "Accent Color",
"Background Color": "Background Color",
"Highlight Color": "Highlight Color",
"Adaptive Theme": "Adaptive Theme",
},
};
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);
}