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,231 @@
import 'package:refilc/api/providers/user_provider.dart';
import 'package:refilc_kreta_api/models/absence.dart';
import 'package:refilc_kreta_api/models/grade.dart';
import 'package:refilc_kreta_api/models/subject.dart';
import 'package:refilc_kreta_api/providers/absence_provider.dart';
import 'package:refilc_kreta_api/providers/grade_provider.dart';
import 'package:refilc_kreta_api/providers/homework_provider.dart';
import 'package:refilc_mobile_ui/screens/summary/summary_screen.i18n.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class AllSumBody extends StatefulWidget {
const AllSumBody({super.key});
@override
AllSumBodyState createState() => AllSumBodyState();
}
class AllSumBodyState extends State<AllSumBody> {
late UserProvider user;
late GradeProvider gradeProvider;
late HomeworkProvider homeworkProvider;
late AbsenceProvider absenceProvider;
//late TimetableProvider timetableProvider;
late Map<String, Map<String, dynamic>> things = {};
late List<Widget> firstSixTiles = [];
late List<Widget> lastSixTiles = [];
int avgDropValue = 0;
bool animation = false;
List<Grade> getSubjectGrades(GradeSubject subject, {int days = 0}) =>
gradeProvider.grades
.where((e) =>
e.subject == subject &&
e.type == GradeType.midYear &&
(days == 0 ||
e.date
.isBefore(DateTime.now().subtract(Duration(days: days)))))
.toList();
@override
void initState() {
super.initState();
gradeProvider = Provider.of<GradeProvider>(context, listen: false);
homeworkProvider = Provider.of<HomeworkProvider>(context, listen: false);
absenceProvider = Provider.of<AbsenceProvider>(context, listen: false);
//timetableProvider = Provider.of<TimetableProvider>(context, listen: false);
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
setState(() {
animation = true;
});
});
}
void getGrades() {
var allGrades = gradeProvider.grades;
var testsGrades = gradeProvider.grades.where((a) => a.value.weight == 100);
var closingTestsGrades =
gradeProvider.grades.where((a) => a.value.weight >= 200);
things.addAll({
'tests': {'name': 'test'.i18n, 'value': testsGrades.length},
'closingTests': {
'name': 'closingtest'.i18n,
'value': closingTestsGrades.length
},
'grades': {'name': 'grade'.i18n, 'value': allGrades.length}
});
}
void getHomework() {
var allHomework = homeworkProvider.homework;
things.addAll({
'homework': {'name': 'hw'.i18n, 'value': allHomework.length}
});
}
void getSubjects() {
var allSubjects = gradeProvider.grades
.map((e) => e.subject)
.toSet()
.toList()
..sort((a, b) => a.name.compareTo(b.name));
//var totalLessons;
var totalLessons = 0;
things.addAll({
'subjects': {'name': 'subject'.i18n, 'value': allSubjects.length},
'lessons': {'name': 'lesson'.i18n, 'value': totalLessons}
});
}
void getAbsences() {
var allAbsences = absenceProvider.absences.where((a) => a.delay == 0);
var excusedAbsences = absenceProvider.absences
.where((a) => a.state == Justification.excused && a.delay == 0);
var unexcusedAbsences = absenceProvider.absences.where((a) =>
(a.state == Justification.unexcused ||
a.state == Justification.pending) &&
a.delay == 0);
things.addAll({
'absences': {'name': 'absence_sum'.i18n, 'value': allAbsences.length},
'excusedAbsences': {
'name': 'excused'.i18n,
'value': excusedAbsences.length
},
'unexcusedAbsences': {
'name': 'unexcused'.i18n,
'value': unexcusedAbsences.length
}
});
}
void getDelays() {
var allDelays = absenceProvider.absences.where((a) => a.delay > 0);
var delayTimeList = (allDelays.map((a) {
return a.delay;
}).toList());
var totalDelayTime = 0;
if (delayTimeList.isNotEmpty) {
totalDelayTime = delayTimeList.reduce((a, b) => a + b);
}
var unexcusedDelays = absenceProvider.absences
.where((a) => a.state == Justification.unexcused && a.delay > 0);
things.addAll({
'delays': {'name': 'delay_sum'.i18n, 'value': allDelays.length},
'totalDelay': {'name': 'min'.i18n, 'value': totalDelayTime},
'unexcusedDelays': {
'name': 'unexcused'.i18n,
'value': unexcusedDelays.length
}
});
}
void getEverything() {
getGrades();
getHomework();
getSubjects();
getAbsences();
getDelays();
}
void generateTiles() {
for (var i in things.values) {
Widget w = Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
i.values.toList()[1].toString(),
textAlign: TextAlign.center,
style: const TextStyle(
fontWeight: FontWeight.w800,
fontSize: 36.0,
color: Colors.white,
),
),
Text(
i.values.toList()[0],
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 18.0,
color: Colors.white,
),
),
],
);
// TO-DO: az orakat es a hazikat szarul keri le, de majd meg lesz csinalva
if (firstSixTiles.length < 6) {
firstSixTiles.add(w);
} else if (lastSixTiles.length < 6) {
lastSixTiles.add(w);
} else {
break;
}
}
}
@override
Widget build(BuildContext context) {
getEverything();
generateTiles();
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(
height: 45,
),
AnimatedContainer(
curve: Curves.easeInOut,
duration: const Duration(milliseconds: 420),
transform: Matrix4.translationValues(
animation ? 0 : MediaQuery.of(context).size.width, 0, 0),
height: 250,
child: GridView.count(
crossAxisCount: 3,
mainAxisSpacing: 0,
crossAxisSpacing: 5,
children: firstSixTiles,
),
),
const SizedBox(
height: 30,
),
AnimatedContainer(
curve: Curves.easeInOut,
duration: const Duration(milliseconds: 420),
transform: Matrix4.translationValues(
animation ? 0 : -MediaQuery.of(context).size.width, 0, 0),
height: 250,
child: GridView.count(
crossAxisCount: 3,
mainAxisSpacing: 0,
crossAxisSpacing: 5,
children: lastSixTiles,
),
),
],
);
}
}

View File

@@ -0,0 +1,363 @@
import 'dart:math';
import 'package:refilc/api/providers/user_provider.dart';
import 'package:refilc/helpers/average_helper.dart';
import 'package:refilc/models/settings.dart';
import 'package:refilc/ui/widgets/grade/grade_tile.dart';
import 'package:refilc/utils/format.dart';
import 'package:refilc_kreta_api/models/grade.dart';
import 'package:refilc_kreta_api/models/subject.dart';
import 'package:refilc_kreta_api/providers/grade_provider.dart';
import 'package:refilc_mobile_ui/screens/summary/summary_screen.i18n.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:auto_size_text/auto_size_text.dart';
import 'package:i18n_extension/i18n_widget.dart';
List<String> faces = [
"(·.·)",
"(≥o≤)",
"(·_·)",
"(˚Δ˚)b",
"(^-^*)",
"(='X'=)",
"(>_<)",
"(;-;)",
"\\(^Д^)/",
"\\(o_o)/",
];
class GradesBody extends StatefulWidget {
const GradesBody({super.key});
@override
GradesBodyState createState() => GradesBodyState();
}
class GradesBodyState extends State<GradesBody> {
late UserProvider user;
late GradeProvider gradeProvider;
late SettingsProvider settings;
late double subjectAvg;
late double endYearAvg;
late String endYearAvgText;
List<Widget> subjectTiles5 = [];
List<Widget> subjectTiles3 = [];
List<Widget> subjectTiles1 = [];
int avgDropValue = 0;
bool animation = false;
List<Grade> getSubjectGrades(GradeSubject subject, {int days = 0}) =>
gradeProvider.grades
.where((e) =>
e.subject == subject &&
e.type == GradeType.midYear &&
(days == 0 ||
e.date
.isBefore(DateTime.now().subtract(Duration(days: days)))))
.toList();
@override
void initState() {
super.initState();
gradeProvider = Provider.of<GradeProvider>(context, listen: false);
settings = Provider.of<SettingsProvider>(context, listen: false);
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
setState(() {
animation = true;
});
});
}
void generateTiles({required int filter}) {
List<GradeSubject> subjects = gradeProvider.grades
.map((e) => e.subject)
.toSet()
.toList()
..sort((a, b) => a.name.compareTo(b.name));
List<Widget> tiles = [];
Map<GradeSubject, double> subjectAvgs = {};
var count = 1;
for (GradeSubject subject in subjects) {
List<Grade> subjectGrades = getSubjectGrades(subject);
double avg = AverageHelper.averageEvals(subjectGrades);
if (avg != 0) subjectAvgs[subject] = avg;
Widget widget = AnimatedContainer(
curve: Curves.easeInOut,
duration: Duration(milliseconds: 300 + (count * 120)),
transform: Matrix4.translationValues(
animation ? 0 : MediaQuery.of(context).size.width, 0, 0),
child: Row(
children: [
GradeValueWidget(
GradeValue(avg.round(), '', '', 100),
fill: true,
size: 28.0,
),
const SizedBox(width: 8),
Text(
subject.renamedTo ?? subject.name.capital(),
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20.0,
color: Colors.white.withOpacity(0.98),
fontStyle: settings.renamedSubjectsItalics && subject.isRenamed
? FontStyle.italic
: null,
),
)
],
),
);
if (avg.round() == filter) {
tiles.add(widget);
count++;
}
}
if (tiles.isEmpty) {
int index = Random(DateTime.now().minute).nextInt(faces.length);
Widget faceWidget = Center(
child: Text.rich(
TextSpan(
text: faces[index],
style: const TextStyle(
fontSize: 32.0,
fontWeight: FontWeight.w500,
color: Colors.white,
),
children: [
TextSpan(
text: "\n${'no_grades'.i18n}",
style: TextStyle(
fontSize: 18.0,
height: 2.0,
color: Colors.white.withOpacity(0.5)),
),
],
),
textAlign: TextAlign.center,
),
);
tiles.insert(0, faceWidget);
}
subjectAvg = subjectAvgs.isNotEmpty
? subjectAvgs.values.fold(0.0, (double a, double b) => a + b) /
subjectAvgs.length
: 0.0;
List<Grade> endYearGrades = gradeProvider.grades
.where((grade) => grade.type == GradeType.endYear)
.toList();
endYearAvg = AverageHelper.averageEvals(endYearGrades, finalAvg: true);
endYearAvgText = endYearAvg.toStringAsFixed(1);
if (I18n.of(context).locale.languageCode != "en") {
endYearAvgText = endYearAvgText.replaceAll(".", ",");
}
if (filter == 5) {
subjectTiles5 = List.castFrom(tiles);
if (subjectTiles5.length > 4) {
subjectTiles5.length = 4;
}
} else if (filter == 3) {
subjectTiles3 = List.castFrom(tiles);
if (subjectTiles3.length > 3) {
subjectTiles3.length = 3;
}
} else if (filter == 1) {
subjectTiles1 = List.castFrom(tiles);
if (subjectTiles1.length > 2) {
subjectTiles1.length = 2;
}
}
}
void getGrades() {
generateTiles(filter: 5);
generateTiles(filter: 3);
generateTiles(filter: 1);
}
@override
Widget build(BuildContext context) {
user = Provider.of<UserProvider>(context);
settings = Provider.of<SettingsProvider>(context);
getGrades();
return Expanded(
child: ListView(
children: [
SizedBox(
height: ((100 * subjectTiles5.length) /
(subjectTiles5[0].runtimeType == AnimatedContainer
? 1.95
: 1.2))
.toDouble(),
child: ListView.builder(
padding: const EdgeInsets.only(left: 5),
physics: const BouncingScrollPhysics(),
itemCount: max(subjectTiles5.length, 1),
itemBuilder: (context, index) {
if (subjectTiles5.isNotEmpty) {
EdgeInsetsGeometry panelPadding =
const EdgeInsets.symmetric(horizontal: 24.0);
if (subjectTiles5[index].runtimeType == AnimatedContainer) {
return Padding(
padding: const EdgeInsets.only(top: 8),
child: subjectTiles5[index]);
} else {
return Padding(
padding: panelPadding, child: subjectTiles5[index]);
}
} else {
return Container();
}
},
),
),
const SizedBox(height: 12.0),
Text(
'tryagain'.i18n,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 22.0,
color: Colors.white,
),
),
const SizedBox(height: 12.0),
SizedBox(
height: ((100 * subjectTiles3.length) /
(subjectTiles3[0].runtimeType == AnimatedContainer
? 1.95
: 1.2))
.toDouble(),
child: ListView.builder(
padding: const EdgeInsets.only(left: 5),
physics: const BouncingScrollPhysics(),
itemCount: max(subjectTiles3.length, 1),
itemBuilder: (context, index) {
if (subjectTiles3.isNotEmpty) {
EdgeInsetsGeometry panelPadding =
const EdgeInsets.symmetric(horizontal: 24.0);
if (subjectTiles3[index].runtimeType == AnimatedContainer) {
return Padding(
padding: const EdgeInsets.only(top: 8),
child: subjectTiles3[index]);
} else {
return Padding(
padding: panelPadding, child: subjectTiles3[index]);
}
} else {
return Container();
}
},
),
),
const SizedBox(height: 12.0),
Text(
'oops'.i18n,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 22.0,
color: Colors.white,
),
),
const SizedBox(height: 12.0),
SizedBox(
height: ((100 * subjectTiles1.length) /
(subjectTiles1[0].runtimeType == AnimatedContainer
? 1.95
: 1.2))
.toDouble(),
child: ListView.builder(
padding: const EdgeInsets.only(left: 5),
physics: const BouncingScrollPhysics(),
itemCount: max(subjectTiles1.length, 1),
itemBuilder: (context, index) {
if (subjectTiles1.isNotEmpty) {
EdgeInsetsGeometry panelPadding =
const EdgeInsets.symmetric(horizontal: 24.0);
if (subjectTiles1[index].runtimeType == AnimatedContainer) {
return Padding(
padding: const EdgeInsets.only(top: 8),
child: subjectTiles1[index]);
} else {
return Padding(
padding: panelPadding, child: subjectTiles1[index]);
}
} else {
return Container();
}
},
),
),
const SizedBox(height: 30.0),
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
'endyear_avg'.i18n,
textAlign: TextAlign.center,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 22.0,
color: Colors.white,
),
),
Container(
margin: const EdgeInsets.only(top: 10.0),
padding: const EdgeInsets.symmetric(
horizontal: 16.0, vertical: 4.0),
decoration: BoxDecoration(
color: gradeColor(context: context, value: endYearAvg)
.withOpacity(.2),
border: Border.all(
color: (gradeColor(context: context, value: endYearAvg))
.withOpacity(0.0),
width: 2.0,
),
borderRadius: BorderRadius.circular(45.0),
),
child: AutoSizeText.rich(
TextSpan(
text: endYearAvgText,
),
maxLines: 1,
minFontSize: 5,
textAlign: TextAlign.center,
style: TextStyle(
color: gradeColor(context: context, value: endYearAvg),
fontWeight: FontWeight.w800,
fontSize: 32.0,
),
),
),
],
),
),
],
),
);
}
}

View File

@@ -0,0 +1,321 @@
// ignore_for_file: no_leading_underscores_for_local_identifiers
import 'dart:math';
import 'package:refilc/api/providers/user_provider.dart';
import 'package:refilc/helpers/subject.dart';
import 'package:refilc/models/settings.dart';
import 'package:refilc/utils/format.dart';
import 'package:refilc_kreta_api/models/absence.dart';
import 'package:refilc_kreta_api/models/lesson.dart';
import 'package:refilc_kreta_api/models/subject.dart';
import 'package:refilc_kreta_api/models/week.dart';
import 'package:refilc_kreta_api/providers/absence_provider.dart';
import 'package:refilc_kreta_api/providers/timetable_provider.dart';
import 'package:refilc_mobile_ui/screens/summary/summary_screen.i18n.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
List<String> faces = [
"(·.·)",
"(≥o≤)",
"(·_·)",
"(˚Δ˚)b",
"(^-^*)",
"(='X'=)",
"(>_<)",
"(;-;)",
"\\(^Д^)/",
"\\(o_o)/",
];
class SubjectAbsence {
GradeSubject subject;
List<Absence> absences;
double percentage;
SubjectAbsence(
{required this.subject, this.absences = const [], this.percentage = 0.0});
}
class LessonsBody extends StatefulWidget {
const LessonsBody({super.key});
@override
LessonsBodyState createState() => LessonsBodyState();
}
class LessonsBodyState extends State<LessonsBody> {
late UserProvider user;
late AbsenceProvider absenceProvider;
late SettingsProvider settingsProvider;
late TimetableProvider timetableProvider;
late List<SubjectAbsence> absences = [];
late List<Widget> lessons = [];
late List<Absence> delays = [];
final Map<GradeSubject, Lesson> _lessonCount = {};
@override
void initState() {
super.initState();
absenceProvider = Provider.of<AbsenceProvider>(context, listen: false);
settingsProvider = Provider.of<SettingsProvider>(context, listen: false);
timetableProvider = Provider.of<TimetableProvider>(context, listen: false);
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
for (final lesson in timetableProvider.getWeek(Week.current()) ?? []) {
if (!lesson.isEmpty &&
lesson.subject.id != '' &&
lesson.lessonYearIndex != null) {
_lessonCount.update(
lesson.subject,
(value) {
if (lesson.lessonYearIndex! > value.lessonYearIndex!) {
return lesson;
} else {
return value;
}
},
ifAbsent: () => lesson,
);
}
}
setState(() {});
});
}
void buildSubjectAbsences() {
Map<GradeSubject, SubjectAbsence> _absences = {};
for (final absence in absenceProvider.absences) {
if (absence.delay != 0) continue;
if (!_absences.containsKey(absence.subject)) {
_absences[absence.subject] =
SubjectAbsence(subject: absence.subject, absences: [absence]);
} else {
_absences[absence.subject]?.absences.add(absence);
}
}
_absences.forEach((subject, absence) {
final absentLessonsOfSubject = absenceProvider.absences
.where((e) => e.subject == subject && e.delay == 0)
.length;
final totalLessonsOfSubject = _lessonCount[subject]?.lessonYearIndex ?? 0;
double absentLessonsOfSubjectPercentage;
if (absentLessonsOfSubject <= totalLessonsOfSubject) {
absentLessonsOfSubjectPercentage =
absentLessonsOfSubject / totalLessonsOfSubject * 100;
} else {
absentLessonsOfSubjectPercentage = -1;
}
_absences[subject]?.percentage =
absentLessonsOfSubjectPercentage.clamp(-1, 100.0);
});
absences = _absences.values.toList();
absences.sort((a, b) => -a.percentage.compareTo(b.percentage));
}
void getAndSortDelays() {
delays = absenceProvider.absences;
delays.sort((a, b) => -a.delay.compareTo(b.delay));
}
void generateTiles() {
Widget leastAbsent = Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(
SubjectIcon.resolveVariant(
subject: absences.last.subject, context: context),
color: Colors.white,
size: 64,
),
Text(
absences.last.subject.renamedTo ??
absences.last.subject.name.capital(),
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontWeight: FontWeight.w800,
fontSize: 36.0,
fontStyle: absences.last.subject.isRenamed &&
settingsProvider.renamedSubjectsItalics
? FontStyle.italic
: null,
color: Colors.white,
),
),
Text(
'absence'.i18n.fill([absences.last.absences.length]),
style: const TextStyle(
fontSize: 18.0,
color: Colors.white,
),
)
],
),
);
if (absences.last.absences.isNotEmpty) {
lessons.add(leastAbsent);
} else {
lessons.add(buildFaceWidget());
}
Widget mostAbsent = Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(
SubjectIcon.resolveVariant(
subject: absences.first.subject, context: context),
color: Colors.white,
size: 64,
),
Text(
absences.first.subject.renamedTo ??
absences.first.subject.name.capital(),
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontWeight: FontWeight.w800,
fontSize: 36.0,
fontStyle: absences.first.subject.isRenamed &&
settingsProvider.renamedSubjectsItalics
? FontStyle.italic
: null,
color: Colors.white,
),
),
Text(
'absence'.i18n.fill([absences.first.absences.length]),
style: const TextStyle(
fontSize: 18.0,
color: Colors.white,
),
)
],
),
);
if (absences.first.absences.isNotEmpty) {
lessons.add(mostAbsent);
} else {
lessons.add(buildFaceWidget());
}
Widget mostDelays = Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(
SubjectIcon.resolveVariant(
subject: delays.first.subject, context: context),
color: Colors.white,
size: 64,
),
Text(
delays.first.subject.renamedTo ??
delays.first.subject.name.capital(),
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontWeight: FontWeight.w800,
fontSize: 36.0,
fontStyle: delays.first.subject.isRenamed &&
settingsProvider.renamedSubjectsItalics
? FontStyle.italic
: null,
color: Colors.white,
),
),
Text(
'delay'.i18n.fill([delays.first.delay]),
style: const TextStyle(
fontSize: 18.0,
color: Colors.white,
),
)
],
),
);
if (delays.first.delay != 0) {
lessons.add(mostDelays);
} else {
lessons.add(buildFaceWidget());
}
}
@override
Widget build(BuildContext context) {
buildSubjectAbsences();
getAndSortDelays();
generateTiles();
return Expanded(
child: ListView(
children: [
lessons[0],
const SizedBox(height: 18.0),
Text(
'dontfelt'.i18n,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 22.0,
color: Colors.white,
),
),
const SizedBox(height: 18.0),
lessons[1],
const SizedBox(height: 18.0),
Text(
'youlate'.i18n,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 22.0,
color: Colors.white,
),
),
const SizedBox(height: 18.0),
lessons[2],
],
),
);
}
Widget buildFaceWidget() {
int index = Random(DateTime.now().minute).nextInt(faces.length);
return Center(
child: Text.rich(
TextSpan(
text: faces[index],
style: const TextStyle(
fontSize: 32.0,
fontWeight: FontWeight.w500,
color: Colors.white,
),
children: [
TextSpan(
text: "\n${'no_lesson'.i18n}",
style: TextStyle(
fontSize: 18.0,
height: 2.0,
color: Colors.white.withOpacity(0.5)),
),
],
),
textAlign: TextAlign.center,
),
);
}
}

View File

@@ -0,0 +1,128 @@
import 'dart:io';
import 'package:refilc/api/providers/user_provider.dart';
import 'package:refilc_mobile_ui/common/personality_card/empty_card.dart';
import 'package:refilc_mobile_ui/common/personality_card/personality_card.dart';
import 'package:refilc_mobile_ui/screens/summary/summary_screen.i18n.dart';
import 'package:flutter/material.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:provider/provider.dart';
import 'package:screenshot/screenshot.dart';
import 'package:share_plus/share_plus.dart';
import 'package:path_provider/path_provider.dart';
import 'package:image_gallery_saver/image_gallery_saver.dart';
class PersonalityBody extends StatefulWidget {
const PersonalityBody({super.key});
@override
PersonalityBodyState createState() => PersonalityBodyState();
}
class PersonalityBodyState extends State<PersonalityBody> {
late UserProvider user;
bool isRevealed = false;
ScreenshotController screenshotController = ScreenshotController();
sharePersonality() async {
await screenshotController.capture().then((image) async {
if (image != null) {
final directory = await getApplicationDocumentsDirectory();
if (await File('${directory.path}/refilc_personality.png').exists()) {
await File('${directory.path}/refilc_personality.png').delete();
}
final imagePath =
await File('${directory.path}/refilc_personality.png').create();
await imagePath.writeAsBytes(image);
await Share.shareXFiles([XFile(imagePath.path)]);
}
}).catchError((err) {
throw err;
});
}
savePersonality() async {
await screenshotController.capture().then((image) async {
if (image != null) {
await ImageGallerySaver.saveImage(image, name: 'refilc_personality');
}
}).catchError((err) {
throw err;
});
}
@override
Widget build(BuildContext context) {
user = Provider.of<UserProvider>(context);
return Expanded(
child: ListView(
children: [
const SizedBox(height: 30),
AnimatedCrossFade(
duration: const Duration(milliseconds: 1000),
sizeCurve: Curves.easeInToLinear,
firstChild: Screenshot(
controller: screenshotController,
child: PersonalityCard(user: user),
),
secondChild: GestureDetector(
onTap: () => setState(() {
isRevealed = true;
}),
child: EmptyCard(text: 'click_reveal'.i18n),
),
crossFadeState: isRevealed
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
),
const SizedBox(height: 30),
if (isRevealed)
Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
IconButton(
onPressed: () async {
await sharePersonality();
},
icon: const Icon(
FeatherIcons.share,
color: Colors.white,
size: 30,
),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
Colors.white.withOpacity(0.2)),
),
),
const SizedBox(
width: 10,
),
IconButton(
onPressed: () async {
await savePersonality();
},
icon: const Icon(
FeatherIcons.bookmark,
color: Colors.white,
size: 30,
),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
Colors.white.withOpacity(0.2)),
),
),
],
),
),
const SizedBox(height: 60),
],
),
);
}
}

View File

@@ -0,0 +1,98 @@
import 'package:refilc/api/providers/user_provider.dart';
import 'package:refilc/models/settings.dart';
import 'package:refilc_kreta_api/providers/grade_provider.dart';
import 'package:refilc_mobile_ui/screens/summary/summary_screen.dart';
import 'package:refilc_mobile_ui/screens/summary/summary_screen.i18n.dart';
import 'package:flutter/material.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:provider/provider.dart';
import 'package:wtf_sliding_sheet/wtf_sliding_sheet.dart';
class StartBody extends StatefulWidget {
const StartBody({super.key});
@override
StartBodyState createState() => StartBodyState();
}
class StartBodyState extends State<StartBody> {
late UserProvider user;
late GradeProvider gradeProvider;
late SettingsProvider settings;
late String firstName;
@override
void initState() {
super.initState();
gradeProvider = Provider.of<GradeProvider>(context, listen: false);
settings = Provider.of<SettingsProvider>(context, listen: false);
}
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const SizedBox(height: 40.0),
GestureDetector(
onTap: () {
Navigator.of(context).pop();
showSlidingBottomSheet(
context,
useRootNavigator: true,
builder: (context) => SlidingSheetDialog(
color: Colors.black.withOpacity(0.99),
duration: const Duration(milliseconds: 400),
scrollSpec: const ScrollSpec.bouncingScroll(),
snapSpec: const SnapSpec(
snap: true,
snappings: [1.0],
initialSnap: 1.0,
positioning: SnapPositioning.relativeToAvailableSpace,
),
minHeight: MediaQuery.of(context).size.height,
cornerRadius: 16,
cornerRadiusOnFullscreen: 0,
builder: (context, state) => const Material(
color: Colors.black,
child: SummaryScreen(
currentPage: 'grades',
isBottomSheet: true,
),
),
),
);
},
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Icon(
FeatherIcons.arrowRight,
size: 145,
color: Colors.white,
grade: 0.001,
weight: 0.001,
),
Text(
'start'.i18n,
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 16.0,
color: Colors.white.withOpacity(0.7),
),
),
],
),
),
),
const SizedBox(height: 169.69),
],
);
}
}

View File

@@ -0,0 +1,222 @@
import 'package:confetti/confetti.dart';
import 'package:refilc/api/providers/user_provider.dart';
import 'package:refilc/models/settings.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:wtf_sliding_sheet/wtf_sliding_sheet.dart';
import 'summary_screen.i18n.dart';
import 'pages/allsum_page.dart';
import 'pages/start_page.dart';
import 'pages/grades_page.dart';
import 'pages/lessons_page.dart';
import 'pages/personality_page.dart';
class SummaryScreen extends StatefulWidget {
final String currentPage;
final bool isBottomSheet;
const SummaryScreen({
super.key,
this.currentPage = 'personality',
this.isBottomSheet = false,
});
@override
SummaryScreenState createState() => SummaryScreenState();
static show(
{required BuildContext context,
String currentPage = 'personality'}) =>
Navigator.of(context, rootNavigator: true).push(CupertinoPageRoute(
builder: (context) => SummaryScreen(currentPage: currentPage)));
}
class SummaryScreenState extends State<SummaryScreen>
with SingleTickerProviderStateMixin {
late UserProvider user;
late SettingsProvider settings;
ConfettiController? _confettiController;
late String firstName;
final LinearGradient _backgroundGradient = const LinearGradient(
colors: [
Color(0xff1d56ac),
Color(0xff170a3d),
],
begin: Alignment(-0.8, -1.0),
end: Alignment(0.8, 1.0),
stops: [-1.0, 1.0],
);
@override
void initState() {
super.initState();
}
@override
void dispose() {
_confettiController?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
user = Provider.of<UserProvider>(context);
settings = Provider.of<SettingsProvider>(context);
List<String> nameParts = user.displayName?.split(" ") ?? ["?"];
if (!settings.presentationMode) {
firstName = nameParts.length > 1 ? nameParts[1] : nameParts[0];
} else {
firstName = "János";
}
return widget.isBottomSheet
? buildContainer()
: Scaffold(
body: buildContainer(),
);
}
Widget buildContainer() {
return Container(
decoration: BoxDecoration(gradient: _backgroundGradient),
child: Container(
decoration: BoxDecoration(gradient: _backgroundGradient),
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: SafeArea(
child: Padding(
padding: const EdgeInsets.only(
left: 24.0,
right: 24.0,
top: 15.0,
bottom: 40.0,
),
child: Column(
crossAxisAlignment: widget.currentPage == 'start'
? CrossAxisAlignment.center
: CrossAxisAlignment.start,
mainAxisAlignment: widget.currentPage == 'start'
? MainAxisAlignment.spaceBetween
: MainAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'greeting'.i18n.fill([firstName]),
textAlign: TextAlign.left,
maxLines: 2,
overflow: TextOverflow.ellipsis,
softWrap: true,
style: const TextStyle(
fontWeight: FontWeight.w900,
fontSize: 26.0,
color: Colors.white,
),
),
Text(
widget.currentPage == 'start'
? 'title_start'.i18n
: widget.currentPage == 'grades'
? 'title_grades'.i18n
: widget.currentPage == 'lessons'
? 'title_lessons'.i18n
: widget.currentPage == 'personality'
? 'title_personality'.i18n
: '',
maxLines: 1,
overflow: TextOverflow.fade,
softWrap: false,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 22.0,
color: Colors.white,
),
),
],
),
),
widget.currentPage != 'start'
? IconButton(
onPressed: () async {
Navigator.of(context).pop();
if (widget.currentPage == 'grades') {
openNewPage(page: 'lessons');
} else if (widget.currentPage == 'lessons') {
openNewPage(page: 'allsum');
} else if (widget.currentPage == 'allsum') {
openNewPage(page: 'personality');
} else {
Navigator.of(context).maybePop();
}
},
icon: Icon(
widget.currentPage == 'personality'
? FeatherIcons.x
: FeatherIcons.arrowRight,
color: Colors.white,
),
)
: Container()
],
),
const SizedBox(height: 12.0),
widget.currentPage == 'start'
? const StartBody()
: widget.currentPage == 'grades'
? const GradesBody()
: widget.currentPage == 'lessons'
? const LessonsBody()
: widget.currentPage == 'allsum'
? const AllSumBody()
: const PersonalityBody(),
],
),
),
),
),
);
}
void openNewPage({String page = 'personality'}) {
showSlidingBottomSheet(
context,
useRootNavigator: true,
builder: (context) => SlidingSheetDialog(
color: Colors.black.withOpacity(0.99),
duration: const Duration(milliseconds: 400),
scrollSpec: const ScrollSpec.bouncingScroll(),
snapSpec: const SnapSpec(
snap: true,
snappings: [1.0],
initialSnap: 1.0,
positioning: SnapPositioning.relativeToAvailableSpace,
),
minHeight: MediaQuery.of(context).size.height,
cornerRadius: 16,
cornerRadiusOnFullscreen: 0,
builder: (context, state) => Material(
color: Colors.black,
child: SummaryScreen(
currentPage: page,
isBottomSheet: true,
),
),
),
);
//SummaryScreen.show(context: context, currentPage: page);
}
}

View File

@@ -0,0 +1,117 @@
import 'package:i18n_extension/i18n_extension.dart';
extension SettingsLocalization on String {
static final _t = Translations.byLocale("hu_hu") +
{
"en_en": {
// main thingies
"no_grades": "No grades found",
"no_lesson": "No lessons found",
"greeting": "You had a good year, %s!",
"title_start": "So let's summarize...",
"title_grades": "Let's look at your marks... 📖",
"title_lessons": "Your favorite lesson 💓",
"title_personality": "Your personality is...",
// start page
"start": "Start",
// grades page
"tryagain": "He puts the master to the test! 🔃",
"oops": "Ouch... 🥴",
"endyear_avg": "Year-end average",
// lessons page
"absence": "%s absence(s)",
"delay": "A total of %s minute(s) late",
"dontfelt": "You didn't like it...",
"youlate": "You're late!",
// allsum page
"test": "test(s)",
"closingtest": "module test(s)",
"grade": "grades",
"hw": "homework",
"subject": "subjects",
"lesson": "lessons",
"absence_sum": "absence(s)",
"excused": "excused",
"unexcused": "unexcused",
"delay_sum": "delay(s)",
"min": "minute(s)",
// personality page
"click_reveal": "Click to reveal...",
},
"hu_hu": {
// main thingies
"no_grades": "Nincsenek jegyek",
"no_lesson": "Nincsenek tanórák",
"greeting": "Jó éved volt, %s!",
"title_start": "Összegezzünk hát...",
"title_grades": "Nézzük a jegyeidet... 📖",
"title_lessons": "A kedvenc órád 💓",
"title_personality": "A te személyiséged...",
// start page
"start": "Kezdés",
// grades page
"tryagain": "Próba teszi a mestert! 🔃",
"oops": "Ajjaj... 🥴",
"endyear_avg": "Év végi átlagod",
// lessons page
"absence": "%s hiányzás",
"delay": "Összesen %s perc késés",
"dontfelt": "Nem volt kedved hozzá...",
"youlate": "Késtél!",
// allsum page
"test": "dolgozat",
"closingtest": "témazáró",
"grade": "jegy",
"hw": "házi",
"subject": "tantárgy",
"lesson": "óra",
"absence_sum": "hiányzás",
"excused": "igazolt",
"unexcused": "igazolatlan",
"delay_sum": "késés",
"min": "perc",
// personality page
"click_reveal": "Kattints a felfedéshez...",
},
"de_de": {
// main thingies
"no_grades": "Keine Grade gefunden",
"no_lesson": "Keine Lektionen gefunden",
"greeting": "Du hattest ein gutes Jahr, %s!",
"title_start": "Fassen wir also zusammen...",
"title_grades": "Schauen wir uns eure Tickets an... 📖",
"title_lessons": "Deine Lieblingsuhr 💓",
"title_personality": "Deine Persönlichkeit...",
// start page
"start": "Anfang",
// grades page
"tryagain": "Er stellt den Meister auf die Probe! 🔃",
"oops": "Autsch... 🥴",
"endyear_avg": "Ihr Jahresenddurchschnitt",
// lessons page
"absence": "%s Abwesenheit(en)",
"delay": "Insgesamt %s Minute(n) zu spät",
"dontfelt": "Es hat dir nicht gefallen...",
"youlate": "Du bist spät!",
// allsum page
"test": "These(n)",
"closingtest": "Modultest",
"grade": "Grad",
"hw": "Hausaufgaben",
"subject": "Themen",
"lesson": "Lektionen",
"absence_sum": "Abwesenheit(en)",
"excused": "bescheinigte",
"unexcused": "unentschuldigte",
"delay_sum": "Verzögerung(en)",
"min": "Minute(n)",
// personality page
"click_reveal": "Klicken Sie hier, um es anzuzeigen...",
},
};
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);
}