changed everything from filcnaplo to refilc finally

This commit is contained in:
Kima
2024-02-24 20:12:25 +01:00
parent 0d1c7b7143
commit 1171e3aaaf
655 changed files with 38728 additions and 44967 deletions

View File

@@ -0,0 +1,56 @@
import 'package:refilc/theme/colors/colors.dart';
import 'package:flutter/material.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart';
class AbsenceDisplay extends StatelessWidget {
const AbsenceDisplay(this.excused, this.unexcused, this.pending, {super.key});
final int excused;
final int unexcused;
final int pending;
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.only(top: 5.0),
// padding: const EdgeInsets.symmetric(vertical: 4.0, horizontal: 6.0),
// decoration: BoxDecoration(
// color: Theme.of(context).scaffoldBackgroundColor.withOpacity(.2),
// borderRadius: BorderRadius.circular(12.0),
// ),
child: Row(children: [
if (excused > 0)
Icon(
FeatherIcons.check,
size: 16.0,
color: AppColors.of(context).green,
),
if (excused > 0) const SizedBox(width: 2.0),
if (excused > 0)
Text(excused.toString(),
style: const TextStyle(fontFamily: "monospace", fontSize: 14.0)),
if (excused > 0 && pending > 0) const SizedBox(width: 6.0),
if (pending > 0)
Icon(
FeatherIcons.slash,
size: 14.0,
color: AppColors.of(context).orange,
),
if (pending > 0) const SizedBox(width: 3.0),
if (pending > 0)
Text(pending.toString(),
style: const TextStyle(fontFamily: "monospace", fontSize: 14.0)),
if (unexcused > 0 && pending > 0) const SizedBox(width: 3.0),
if (unexcused > 0)
Icon(
FeatherIcons.x,
size: 18.0,
color: AppColors.of(context).red,
),
if (unexcused > 0)
Text(unexcused.toString(),
style: const TextStyle(fontFamily: "monospace", fontSize: 14.0)),
]),
);
}
}

View File

@@ -0,0 +1,99 @@
import 'package:refilc/helpers/subject.dart';
import 'package:refilc/models/settings.dart';
import 'package:refilc/theme/colors/colors.dart';
import 'package:refilc/utils/format.dart';
import 'package:refilc_kreta_api/models/subject.dart';
import 'package:refilc_mobile_ui/common/widgets/absence/absence_display.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class AbsenceSubjectTile extends StatelessWidget {
const AbsenceSubjectTile(this.subject,
{super.key,
this.percentage = 0.0,
this.excused = 0,
this.unexcused = 0,
this.pending = 0,
this.onTap});
final GradeSubject subject;
final void Function()? onTap;
final double percentage;
final int excused;
final int unexcused;
final int pending;
@override
Widget build(BuildContext context) {
SettingsProvider settingsProvider = Provider.of<SettingsProvider>(context);
return Material(
type: MaterialType.transparency,
child: ListTile(
// minLeadingWidth: 32.0,
dense: true,
contentPadding: const EdgeInsets.only(left: 8.0, right: 6.0),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.0)),
visualDensity: VisualDensity.compact,
onTap: onTap,
leading: Icon(
SubjectIcon.resolveVariant(subject: subject, context: context),
size: 32.0),
title: Text(
subject.renamedTo ?? subject.name.capital(),
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 15.0,
fontStyle:
subject.isRenamed && settingsProvider.renamedSubjectsItalics
? FontStyle.italic
: null),
),
subtitle: AbsenceDisplay(excused, unexcused, pending),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(width: 8.0),
if (percentage >= 0)
Stack(
alignment: Alignment.centerRight,
children: [
const Opacity(
opacity: 0,
child: Text("100%",
style: TextStyle(fontFamily: "monospace"))),
Text(
"${percentage.round()}%",
style: TextStyle(
// fontFamily: "monospace",
color: getColorByPercentage(percentage, context: context),
fontWeight: FontWeight.w700,
fontSize: 24.0,
),
),
],
),
],
),
),
);
}
}
Color getColorByPercentage(double percentage, {required BuildContext context}) {
Color color = AppColors.of(context).text;
percentage = percentage.round().toDouble();
if (percentage > 35) {
color = AppColors.of(context).red;
} else if (percentage > 25) {
color = AppColors.of(context).orange;
} else if (percentage > 15) {
color = AppColors.of(context).yellow;
}
return color.withOpacity(.8);
}

View File

@@ -0,0 +1,151 @@
import 'package:refilc/models/settings.dart';
import 'package:refilc/theme/colors/colors.dart';
import 'package:refilc/utils/format.dart';
import 'package:refilc_kreta_api/models/absence.dart';
import 'package:refilc_mobile_ui/common/widgets/absence_group/absence_group_container.dart';
import 'package:flutter/material.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:provider/provider.dart';
import 'absence_tile.i18n.dart';
class AbsenceTile extends StatelessWidget {
const AbsenceTile(this.absence,
{super.key, this.onTap, this.elevation = 0.0, this.padding});
final Absence absence;
final void Function()? onTap;
final double elevation;
final EdgeInsetsGeometry? padding;
@override
Widget build(BuildContext context) {
Color color = justificationColor(absence.state, context: context);
bool group = AbsenceGroupContainer.of(context) != null;
SettingsProvider settingsProvider = Provider.of<SettingsProvider>(context);
return Container(
decoration: BoxDecoration(
boxShadow: [
if (elevation > 0)
BoxShadow(
offset: Offset(0, 21 * elevation),
blurRadius: 23.0 * elevation,
color: Theme.of(context).shadowColor,
)
],
borderRadius: BorderRadius.circular(14.0),
),
child: Material(
type: MaterialType.transparency,
child: Padding(
// padding: padding ??
// (group
// ? EdgeInsets.zero
// : const EdgeInsets.symmetric(
// horizontal: 0.0,
// )),
padding: padding ?? EdgeInsets.zero,
child: ListTile(
onTap: onTap,
visualDensity: VisualDensity.compact,
dense: group,
contentPadding: const EdgeInsets.only(
left: 15.5, right: 12.0, top: 2.0, bottom: 2.0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(!group ? 14.0 : 12.0)),
leading: Container(
width: 39,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: !group ? color.withOpacity(.25) : null,
),
child: Center(
child: Icon(justificationIcon(absence.state), color: color)),
),
title: !group
? Text.rich(TextSpan(
text: "${absence.delay == 0 ? "" : absence.delay}",
style: const TextStyle(
fontWeight: FontWeight.w700, fontSize: 15.5),
children: [
TextSpan(
text: absence.delay == 0
? justificationName(absence.state)
.fill(["absence".i18n]).capital()
: 'minute'.plural(absence.delay) +
justificationName(absence.state)
.fill(["delay".i18n]),
style: const TextStyle(fontWeight: FontWeight.w600),
),
],
))
: Text(
(absence.lessonIndex != null
? "${absence.lessonIndex}. "
: "") +
(absence.subject.renamedTo ??
absence.subject.name.capital()),
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 14.0,
fontStyle: absence.subject.isRenamed &&
settingsProvider.renamedSubjectsItalics
? FontStyle.italic
: null),
),
subtitle: !group
? Text(
absence.subject.renamedTo ?? absence.subject.name.capital(),
maxLines: 2,
overflow: TextOverflow.ellipsis,
// DateFormat("MM. dd. (EEEEE)", I18n.of(context).locale.toString()).format(absence.date),
style: TextStyle(
fontWeight: FontWeight.w500,
fontStyle: absence.subject.isRenamed &&
settingsProvider.renamedSubjectsItalics
? FontStyle.italic
: null),
)
: null,
),
),
),
);
}
static String justificationName(Justification state) {
switch (state) {
case Justification.excused:
return "excused".i18n;
case Justification.pending:
return "pending".i18n;
case Justification.unexcused:
return "unexcused".i18n;
}
}
static Color justificationColor(Justification state,
{required BuildContext context}) {
switch (state) {
case Justification.excused:
return AppColors.of(context).green;
case Justification.pending:
return AppColors.of(context).orange;
case Justification.unexcused:
return AppColors.of(context).red;
}
}
static IconData justificationIcon(Justification state) {
switch (state) {
case Justification.excused:
return FeatherIcons.check;
case Justification.pending:
return FeatherIcons.slash;
case Justification.unexcused:
return FeatherIcons.x;
}
}
}

View File

@@ -0,0 +1,36 @@
import 'package:i18n_extension/i18n_extension.dart';
extension Localization on String {
static final _t = Translations.byLocale("hu_hu") +
{
"en_en": {
"excused": "excused %s",
"pending": "%s to be excused",
"unexcused": "unexcused %s",
"absence": "absence",
"delay": "delay",
"minute": " minutes of ".one(" minute of "),
},
"hu_hu": {
"excused": "igazolt %s",
"pending": "igazolandó %s",
"unexcused": "igazolatlan %s",
"absence": "hiányzás",
"delay": "késés",
"minute": " perc ",
},
"de_de": {
"excused": "anerkannt %s",
"pending": "%s zu anerkennen",
"unexcused": "unanerkannt %s",
"absence": "Abwesenheit",
"delay": "Verspätung",
"minute": " Minuten ".one(" Minute "),
}
};
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

@@ -0,0 +1,155 @@
// ignore_for_file: empty_catches
import 'package:refilc/models/settings.dart';
import 'package:refilc/theme/colors/colors.dart';
import 'package:refilc_kreta_api/models/absence.dart';
import 'package:refilc_mobile_ui/common/bottom_card.dart';
import 'package:refilc_mobile_ui/common/custom_snack_bar.dart';
import 'package:refilc_mobile_ui/common/detail.dart';
import 'package:refilc_mobile_ui/common/panel/panel_action_button.dart';
import 'package:refilc_mobile_ui/common/widgets/absence/absence_tile.dart';
import 'package:refilc/utils/format.dart';
import 'package:refilc_mobile_ui/pages/timetable/timetable_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:refilc/utils/reverse_search.dart';
import 'package:provider/provider.dart';
import 'absence_view.i18n.dart';
class AbsenceView extends StatelessWidget {
const AbsenceView(this.absence,
{super.key, this.outsideContext, this.viewable = false});
final Absence absence;
final BuildContext? outsideContext;
final bool viewable;
static show(Absence absence, {required BuildContext context}) {
showBottomCard(
context: context, child: AbsenceView(absence, outsideContext: context));
}
@override
Widget build(BuildContext context) {
Color color =
AbsenceTile.justificationColor(absence.state, context: context);
SettingsProvider settingsProvider = Provider.of<SettingsProvider>(context);
return Padding(
padding: const EdgeInsets.only(bottom: 12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
visualDensity: VisualDensity.compact,
contentPadding: const EdgeInsets.only(left: 16.0, right: 12.0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0)),
leading: Container(
width: 44.0,
height: 44.0,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: color.withOpacity(.25),
),
child: Center(
child: Icon(
AbsenceTile.justificationIcon(absence.state),
color: color,
),
),
),
title: Text(
absence.subject.renamedTo ?? absence.subject.name.capital(),
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontWeight: FontWeight.w700,
fontStyle: absence.subject.isRenamed &&
settingsProvider.renamedSubjectsItalics
? FontStyle.italic
: null),
),
subtitle: Text(
(absence.teacher.isRenamed
? absence.teacher.renamedTo
: absence.teacher.name) ??
'',
// DateFormat("MM. dd. (EEEEE)", I18n.of(context).locale.toString()).format(absence.date),
style: const TextStyle(fontWeight: FontWeight.w500),
),
trailing: Text(
absence.date.format(context),
style: const TextStyle(fontWeight: FontWeight.w500),
),
),
// Absence Details
if (absence.delay > 0)
Detail(
title: "delay".i18n,
description:
"${absence.delay} ${"minutes".i18n.plural(absence.delay)}",
),
if (absence.lessonIndex != null)
Detail(
title: "Lesson".i18n,
description:
"${absence.lessonIndex}. (${absence.lessonStart.format(context, timeOnly: true)}"
" - "
"${absence.lessonEnd.format(context, timeOnly: true)})",
),
if (absence.justification != null)
Detail(
title: "Excuse".i18n,
description: absence.justification?.description ?? "",
),
if (absence.mode != null)
Detail(
title: "Mode".i18n,
description: absence.mode?.description ?? ""),
Detail(
title: "Submit date".i18n,
description: absence.submitDate.format(context)),
// Show in timetable
if (!viewable)
Padding(
padding: const EdgeInsets.only(
left: 16.0, right: 16.0, bottom: 6.0, top: 12.0),
child: PanelActionButton(
leading: const Icon(FeatherIcons.calendar),
title: Text(
"show in timetable".i18n,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
onPressed: () {
// https://discord.com/channels/1111649116020285532/1149964760130002945
Navigator.of(context).pop();
if (outsideContext != null) {
ReverseSearch.getLessonByAbsence(absence, context)
.then((lesson) {
if (lesson != null) {
TimetablePage.jump(outsideContext!, lesson: lesson);
} else {
ScaffoldMessenger.of(context)
.showSnackBar(CustomSnackBar(
content: Text("Cannot find lesson".i18n,
style: const TextStyle(color: Colors.white)),
backgroundColor: AppColors.of(context).red,
context: context,
));
}
});
}
},
),
),
],
),
);
}
}

View File

@@ -0,0 +1,39 @@
import 'package:i18n_extension/i18n_extension.dart';
extension Localization on String {
static final _t = Translations.byLocale("hu_hu") +
{
"en_en": {
"Lesson": "Lesson",
"Excuse": "Excuse",
"Mode": "Mode",
"Submit date": "Submit Date",
"show in timetable": "Show in timetable",
"minutes": "minutes".one("minute"),
"delay": "Delay",
},
"hu_hu": {
"Lesson": "Óra",
"Excuse": "Igazolás",
"Mode": "Típus",
"Submit date": "Rögzítés dátuma",
"show in timetable": "Megtekintés az órarendben",
"minutes": "perc",
"delay": "Késés",
},
"de_de": {
"Lesson": "Stunde",
"Excuse": "Anerkannt",
"Mode": "Typ",
"Submit date": "Datum einreichen",
"show in timetable": "im Stundenplan anzeigen",
"minutes": "Minuten".one("Minute"),
"delay": "Verspätung",
}
};
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

@@ -0,0 +1,70 @@
import 'package:refilc/theme/colors/colors.dart';
import 'package:refilc_kreta_api/models/absence.dart';
import 'package:refilc_mobile_ui/common/custom_snack_bar.dart';
import 'package:refilc_mobile_ui/common/panel/panel_button.dart';
import 'package:refilc_mobile_ui/common/viewable.dart';
import 'package:refilc_mobile_ui/common/widgets/absence/absence_tile.dart';
import 'package:refilc_mobile_ui/common/widgets/absence/absence_view.dart';
import 'package:refilc_mobile_ui/common/widgets/absence_group/absence_group_container.dart';
import 'package:refilc_mobile_ui/common/widgets/card_handle.dart';
import 'package:refilc_mobile_ui/pages/absences/absence_subject_view_container.dart';
import 'package:refilc_mobile_ui/pages/timetable/timetable_page.dart';
import 'package:flutter/material.dart';
import 'package:refilc/utils/reverse_search.dart';
import 'absence_view.i18n.dart';
class AbsenceViewable extends StatelessWidget {
const AbsenceViewable(this.absence, {super.key, this.padding});
final Absence absence;
final EdgeInsetsGeometry? padding;
@override
Widget build(BuildContext context) {
final subject = AbsenceSubjectViewContainer.of(context) != null;
final group = AbsenceGroupContainer.of(context) != null;
final tile = AbsenceTile(absence, padding: padding);
return Viewable(
tile: group ? AbsenceGroupContainer(child: tile) : tile,
view: CardHandle(child: AbsenceView(absence, viewable: true)),
actions: [
PanelButton(
background: true,
title: Text(
"show in timetable".i18n,
textAlign: TextAlign.center,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
onPressed: () {
Navigator.of(context, rootNavigator: true).pop();
if (subject) {
Future.delayed(const Duration(milliseconds: 250)).then((_) {
Navigator.of(context, rootNavigator: true).pop(absence);
});
} else {
Future.delayed(const Duration(milliseconds: 250)).then((_) {
ReverseSearch.getLessonByAbsence(absence, context)
.then((lesson) {
if (lesson != null) {
TimetablePage.jump(context, lesson: lesson);
} else {
ScaffoldMessenger.of(context).showSnackBar(CustomSnackBar(
content: Text("Cannot find lesson".i18n,
style: const TextStyle(color: Colors.white)),
backgroundColor: AppColors.of(context).red,
context: context,
));
}
});
});
}
},
),
],
);
}
}