forked from firka/student-legacy
pfp color fix
This commit is contained in:
parent
5c7b33e6f2
commit
85f7fb71cb
@ -478,7 +478,7 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 195;
|
||||
DEVELOPMENT_TEAM = JWGEQSC9U7;
|
||||
DEVELOPMENT_TEAM = 48XS7JAZB7;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = reFilc;
|
||||
@ -488,7 +488,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.6.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = hu.refilc.naplo;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.refilc.naplo;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
@ -510,7 +510,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = JWGEQSC9U7;
|
||||
DEVELOPMENT_TEAM = 48XS7JAZB7;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = livecard/Info.plist;
|
||||
@ -526,7 +526,7 @@
|
||||
MARKETING_VERSION = 1.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = hu.refilc.naplo.livecardpro;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.refilc.naplo.livecardpro;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SKIP_INSTALL = YES;
|
||||
@ -552,7 +552,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = JWGEQSC9U7;
|
||||
DEVELOPMENT_TEAM = 48XS7JAZB7;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = livecard/Info.plist;
|
||||
@ -567,7 +567,7 @@
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = hu.refilc.naplo.livecardpro;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.refilc.naplo.livecardpro;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SKIP_INSTALL = YES;
|
||||
@ -592,7 +592,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = JWGEQSC9U7;
|
||||
DEVELOPMENT_TEAM = 48XS7JAZB7;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = livecard/Info.plist;
|
||||
@ -607,7 +607,7 @@
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = hu.refilc.naplo.livecardpro;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.refilc.naplo.livecardpro;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SKIP_INSTALL = YES;
|
||||
@ -736,7 +736,7 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 195;
|
||||
DEVELOPMENT_TEAM = JWGEQSC9U7;
|
||||
DEVELOPMENT_TEAM = 48XS7JAZB7;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = reFilc;
|
||||
@ -746,7 +746,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.6.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = hu.refilc.naplo;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.refilc.naplo;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
@ -764,7 +764,7 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 195;
|
||||
DEVELOPMENT_TEAM = JWGEQSC9U7;
|
||||
DEVELOPMENT_TEAM = 48XS7JAZB7;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = reFilc;
|
||||
@ -774,7 +774,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.6.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = hu.refilc.naplo;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.refilc.naplo;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
|
@ -1,71 +1,71 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>BGTaskSchedulerPermittedIdentifiers</key>
|
||||
<array>
|
||||
<string>com.transistorsoft.fetch</string>
|
||||
</array>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Filc Napló</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(FLUTTER_BUILD_NAME)</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>LSApplicationQueriesSchemes</key>
|
||||
<array>
|
||||
<string>https</string>
|
||||
<string>http</string>
|
||||
</array>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>The app requires the photo library to set a custom profile picture.</string>
|
||||
<key>NSSupportsLiveActivities</key>
|
||||
<true/>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true/>
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>fetch</string>
|
||||
<string>processing</string>
|
||||
</array>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UIStatusBarHidden</key>
|
||||
<false/>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>BGTaskSchedulerPermittedIdentifiers</key>
|
||||
<array>
|
||||
<string>com.transistorsoft.fetch</string>
|
||||
</array>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Filc Napló</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(FLUTTER_BUILD_NAME)</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>LSApplicationQueriesSchemes</key>
|
||||
<array>
|
||||
<string>https</string>
|
||||
<string>http</string>
|
||||
</array>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>The app requires the photo library to set a custom profile picture.</string>
|
||||
<key>NSSupportsLiveActivities</key>
|
||||
<true/>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true/>
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>fetch</string>
|
||||
<string>processing</string>
|
||||
</array>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UIStatusBarHidden</key>
|
||||
<false/>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
@ -10,5 +10,6 @@ class ColorUtils {
|
||||
return HSLColor.fromAHSL(1, hash % 360, .8, .75).toColor();
|
||||
}
|
||||
|
||||
static Color foregroundColor(Color color) => color.computeLuminance() >= .5 ? Colors.black : Colors.white;
|
||||
static Color foregroundColor(Color color) =>
|
||||
color.computeLuminance() >= .5 ? Colors.black : Colors.white;
|
||||
}
|
||||
|
@ -38,7 +38,8 @@ class SubjectAbsence {
|
||||
List<Absence> absences;
|
||||
double percentage;
|
||||
|
||||
SubjectAbsence({required this.subject, this.absences = const [], this.percentage = 0.0});
|
||||
SubjectAbsence(
|
||||
{required this.subject, this.absences = const [], this.percentage = 0.0});
|
||||
}
|
||||
|
||||
class AbsencesPage extends StatefulWidget {
|
||||
@ -48,7 +49,8 @@ class AbsencesPage extends StatefulWidget {
|
||||
_AbsencesPageState createState() => _AbsencesPageState();
|
||||
}
|
||||
|
||||
class _AbsencesPageState extends State<AbsencesPage> with TickerProviderStateMixin {
|
||||
class _AbsencesPageState extends State<AbsencesPage>
|
||||
with TickerProviderStateMixin {
|
||||
late UserProvider user;
|
||||
late AbsenceProvider absenceProvider;
|
||||
late TimetableProvider timetableProvider;
|
||||
@ -68,7 +70,9 @@ class _AbsencesPageState extends State<AbsencesPage> with TickerProviderStateMix
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
|
||||
for (final lesson in timetableProvider.getWeek(Week.current()) ?? []) {
|
||||
if (!lesson.isEmpty && lesson.subject.id != '' && lesson.lessonYearIndex != null) {
|
||||
if (!lesson.isEmpty &&
|
||||
lesson.subject.id != '' &&
|
||||
lesson.lessonYearIndex != null) {
|
||||
_lessonCount.update(
|
||||
lesson.subject,
|
||||
(value) {
|
||||
@ -93,25 +97,30 @@ class _AbsencesPageState extends State<AbsencesPage> with TickerProviderStateMix
|
||||
if (absence.delay != 0) continue;
|
||||
|
||||
if (!_absences.containsKey(absence.subject)) {
|
||||
_absences[absence.subject] = SubjectAbsence(subject: absence.subject, absences: [absence]);
|
||||
_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 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;
|
||||
absentLessonsOfSubjectPercentage =
|
||||
absentLessonsOfSubject / totalLessonsOfSubject * 100;
|
||||
} else {
|
||||
absentLessonsOfSubjectPercentage = -1;
|
||||
}
|
||||
|
||||
_absences[subject]?.percentage = absentLessonsOfSubjectPercentage.clamp(-1, 100.0);
|
||||
_absences[subject]?.percentage =
|
||||
absentLessonsOfSubjectPercentage.clamp(-1, 100.0);
|
||||
});
|
||||
|
||||
absences = _absences.values.toList();
|
||||
@ -135,7 +144,8 @@ class _AbsencesPageState extends State<AbsencesPage> with TickerProviderStateMix
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.only(top: 12.0),
|
||||
child: NestedScrollView(
|
||||
physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()),
|
||||
physics: const BouncingScrollPhysics(
|
||||
parent: AlwaysScrollableScrollPhysics()),
|
||||
headerSliverBuilder: (context, _) => [
|
||||
SliverAppBar(
|
||||
pinned: true,
|
||||
@ -151,7 +161,9 @@ class _AbsencesPageState extends State<AbsencesPage> with TickerProviderStateMix
|
||||
child: ProfileImage(
|
||||
heroTag: "profile",
|
||||
name: firstName,
|
||||
backgroundColor: ColorUtils.stringToColor(user.displayName ?? "?"),
|
||||
backgroundColor: Theme.of(context)
|
||||
.colorScheme
|
||||
.primary, //ColorUtils.stringToColor(user.displayName ?? "?"),
|
||||
badge: updateProvider.available,
|
||||
role: user.role,
|
||||
profilePictureString: user.picture,
|
||||
@ -165,7 +177,10 @@ class _AbsencesPageState extends State<AbsencesPage> with TickerProviderStateMix
|
||||
padding: const EdgeInsets.only(left: 8.0),
|
||||
child: Text(
|
||||
"Absences".i18n,
|
||||
style: TextStyle(color: AppColors.of(context).text, fontSize: 32.0, fontWeight: FontWeight.bold),
|
||||
style: TextStyle(
|
||||
color: AppColors.of(context).text,
|
||||
fontSize: 32.0,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
bottom: FilterBar(items: [
|
||||
@ -178,7 +193,8 @@ class _AbsencesPageState extends State<AbsencesPage> with TickerProviderStateMix
|
||||
body: TabBarView(
|
||||
physics: const BouncingScrollPhysics(),
|
||||
controller: _tabController,
|
||||
children: List.generate(3, (index) => filterViewBuilder(context, index))),
|
||||
children: List.generate(
|
||||
3, (index) => filterViewBuilder(context, index))),
|
||||
),
|
||||
),
|
||||
);
|
||||
@ -194,10 +210,17 @@ class _AbsencesPageState extends State<AbsencesPage> with TickerProviderStateMix
|
||||
widget: AbsenceSubjectTile(
|
||||
a.subject,
|
||||
percentage: a.percentage,
|
||||
excused: a.absences.where((a) => a.state == Justification.excused).length,
|
||||
unexcused: a.absences.where((a) => a.state == Justification.unexcused).length,
|
||||
pending: a.absences.where((a) => a.state == Justification.pending).length,
|
||||
onTap: () => AbsenceSubjectView.show(a.subject, a.absences, context: context),
|
||||
excused: a.absences
|
||||
.where((a) => a.state == Justification.excused)
|
||||
.length,
|
||||
unexcused: a.absences
|
||||
.where((a) => a.state == Justification.unexcused)
|
||||
.length,
|
||||
pending: a.absences
|
||||
.where((a) => a.state == Justification.pending)
|
||||
.length,
|
||||
onTap: () => AbsenceSubjectView.show(a.subject, a.absences,
|
||||
context: context),
|
||||
),
|
||||
));
|
||||
}
|
||||
@ -214,7 +237,8 @@ class _AbsencesPageState extends State<AbsencesPage> with TickerProviderStateMix
|
||||
break;
|
||||
case AbsenceFilter.misses:
|
||||
for (var note in noteProvider.notes) {
|
||||
if (note.type?.name == "HaziFeladatHiany" || note.type?.name == "Felszereleshiany") {
|
||||
if (note.type?.name == "HaziFeladatHiany" ||
|
||||
note.type?.name == "Felszereleshiany") {
|
||||
items.add(DateWidget(
|
||||
date: note.date,
|
||||
widget: MissTile(note),
|
||||
@ -252,10 +276,15 @@ class _AbsencesPageState extends State<AbsencesPage> with TickerProviderStateMix
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.0)),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12.0)),
|
||||
title: Text("attention".i18n),
|
||||
content: Text("attention_body".i18n),
|
||||
actions: [ActionButton(label: "Ok", onTap: () => Navigator.of(context).pop())],
|
||||
actions: [
|
||||
ActionButton(
|
||||
label: "Ok",
|
||||
onTap: () => Navigator.of(context).pop())
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
@ -282,7 +311,10 @@ class _AbsencesPageState extends State<AbsencesPage> with TickerProviderStateMix
|
||||
);
|
||||
},
|
||||
child: Column(
|
||||
children: getFilterWidgets(AbsenceFilter.values[activeData]).map((e) => e.widget).cast<Widget>().toList(),
|
||||
children: getFilterWidgets(AbsenceFilter.values[activeData])
|
||||
.map((e) => e.widget)
|
||||
.cast<Widget>()
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -304,7 +336,8 @@ class _AbsencesPageState extends State<AbsencesPage> with TickerProviderStateMix
|
||||
itemCount: max(filterWidgets.length + (activeData <= 1 ? 1 : 0), 1),
|
||||
itemBuilder: (context, index) {
|
||||
if (filterWidgets.isNotEmpty) {
|
||||
if ((index == 0 && activeData == 1) || (index == 0 && activeData == 0)) {
|
||||
if ((index == 0 && activeData == 1) ||
|
||||
(index == 0 && activeData == 0)) {
|
||||
int value1 = 0;
|
||||
int value2 = 0;
|
||||
String title1 = "";
|
||||
@ -312,18 +345,26 @@ class _AbsencesPageState extends State<AbsencesPage> with TickerProviderStateMix
|
||||
String suffix = "";
|
||||
|
||||
if (activeData == AbsenceFilter.absences.index) {
|
||||
value1 = absenceProvider.absences.where((e) => e.delay == 0 && e.state == Justification.excused).length;
|
||||
value2 = absenceProvider.absences.where((e) => e.delay == 0 && e.state == Justification.unexcused).length;
|
||||
value1 = absenceProvider.absences
|
||||
.where((e) =>
|
||||
e.delay == 0 && e.state == Justification.excused)
|
||||
.length;
|
||||
value2 = absenceProvider.absences
|
||||
.where((e) =>
|
||||
e.delay == 0 && e.state == Justification.unexcused)
|
||||
.length;
|
||||
title1 = "stat_1".i18n;
|
||||
title2 = "stat_2".i18n;
|
||||
suffix = " " + "hr".i18n;
|
||||
} else if (activeData == AbsenceFilter.delays.index) {
|
||||
value1 = absenceProvider.absences
|
||||
.where((e) => e.delay != 0 && e.state == Justification.excused)
|
||||
.where((e) =>
|
||||
e.delay != 0 && e.state == Justification.excused)
|
||||
.map((e) => e.delay)
|
||||
.fold(0, (a, b) => a + b);
|
||||
value2 = absenceProvider.absences
|
||||
.where((e) => e.delay != 0 && e.state == Justification.unexcused)
|
||||
.where((e) =>
|
||||
e.delay != 0 && e.state == Justification.unexcused)
|
||||
.map((e) => e.delay)
|
||||
.fold(0, (a, b) => a + b);
|
||||
title1 = "stat_3".i18n;
|
||||
@ -332,7 +373,8 @@ class _AbsencesPageState extends State<AbsencesPage> with TickerProviderStateMix
|
||||
}
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 24.0, left: 24.0, right: 24.0),
|
||||
padding: const EdgeInsets.only(
|
||||
bottom: 24.0, left: 24.0, right: 24.0),
|
||||
child: Row(children: [
|
||||
Expanded(
|
||||
child: StatisticsTile(
|
||||
@ -368,7 +410,8 @@ class _AbsencesPageState extends State<AbsencesPage> with TickerProviderStateMix
|
||||
}
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 6.0),
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 24.0, vertical: 6.0),
|
||||
child: filterWidgets[index - (activeData <= 1 ? 1 : 0)],
|
||||
);
|
||||
} else {
|
||||
|
@ -47,13 +47,21 @@ class _GradesPageState extends State<GradesPage> {
|
||||
|
||||
int avgDropValue = 0;
|
||||
|
||||
List<Grade> getSubjectGrades(Subject 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)))))
|
||||
List<Grade> getSubjectGrades(Subject 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();
|
||||
|
||||
void generateTiles() {
|
||||
List<Subject> subjects = gradeProvider.grades.map((e) => e.subject).toSet().toList()..sort((a, b) => a.name.compareTo(b.name));
|
||||
List<Subject> subjects = gradeProvider.grades
|
||||
.map((e) => e.subject)
|
||||
.toSet()
|
||||
.toList()
|
||||
..sort((a, b) => a.name.compareTo(b.name));
|
||||
List<Widget> tiles = [];
|
||||
|
||||
Map<Subject, double> subjectAvgs = {};
|
||||
@ -65,11 +73,15 @@ class _GradesPageState extends State<GradesPage> {
|
||||
double averageBefore = 0.0;
|
||||
|
||||
if (avgDropValue != 0) {
|
||||
List<Grade> gradesBefore = getSubjectGrades(subject, days: avgDropValue);
|
||||
averageBefore = avgDropValue == 0 ? 0.0 : AverageHelper.averageEvals(gradesBefore);
|
||||
List<Grade> gradesBefore =
|
||||
getSubjectGrades(subject, days: avgDropValue);
|
||||
averageBefore =
|
||||
avgDropValue == 0 ? 0.0 : AverageHelper.averageEvals(gradesBefore);
|
||||
}
|
||||
var nullavg = GroupAverage(average: 0.0, subject: subject, uid: "0");
|
||||
double groupAverage = gradeProvider.groupAverages.firstWhere((e) => e.subject == subject, orElse: () => nullavg).average;
|
||||
double groupAverage = gradeProvider.groupAverages
|
||||
.firstWhere((e) => e.subject == subject, orElse: () => nullavg)
|
||||
.average;
|
||||
|
||||
if (avg != 0) subjectAvgs[subject] = avg;
|
||||
|
||||
@ -79,7 +91,8 @@ class _GradesPageState extends State<GradesPage> {
|
||||
average: avg,
|
||||
groupAverage: avgDropValue == 0 ? groupAverage : 0.0,
|
||||
onTap: () {
|
||||
GradeSubjectView(subject, groupAverage: groupAverage).push(context, root: true);
|
||||
GradeSubjectView(subject, groupAverage: groupAverage)
|
||||
.push(context, root: true);
|
||||
},
|
||||
);
|
||||
}));
|
||||
@ -88,7 +101,12 @@ class _GradesPageState extends State<GradesPage> {
|
||||
tiles.insert(0, yearlyGraph);
|
||||
tiles.insert(1, gradesCount);
|
||||
tiles.insert(2, FailWarning(subjectAvgs: subjectAvgs));
|
||||
tiles.insert(3, PanelTitle(title: Text(avgDropValue == 0 ? "Subjects".i18n : "Subjects_changes".i18n)));
|
||||
tiles.insert(
|
||||
3,
|
||||
PanelTitle(
|
||||
title: Text(avgDropValue == 0
|
||||
? "Subjects".i18n
|
||||
: "Subjects_changes".i18n)));
|
||||
tiles.insert(4, const PanelHeader(padding: EdgeInsets.only(top: 12.0)));
|
||||
tiles.add(const PanelFooter(padding: EdgeInsets.only(bottom: 12.0)));
|
||||
tiles.add(const Padding(padding: EdgeInsets.only(bottom: 24.0)));
|
||||
@ -102,9 +120,15 @@ class _GradesPageState extends State<GradesPage> {
|
||||
);
|
||||
}
|
||||
|
||||
double subjectAvg = subjectAvgs.isNotEmpty ? subjectAvgs.values.fold(0.0, (double a, double b) => a + b) / subjectAvgs.length : 0.0;
|
||||
double subjectAvg = subjectAvgs.isNotEmpty
|
||||
? subjectAvgs.values.fold(0.0, (double a, double b) => a + b) /
|
||||
subjectAvgs.length
|
||||
: 0.0;
|
||||
final double classAvg = gradeProvider.groupAverages.isNotEmpty
|
||||
? gradeProvider.groupAverages.map((e) => e.average).fold(0.0, (double a, double b) => a + b) / gradeProvider.groupAverages.length
|
||||
? gradeProvider.groupAverages
|
||||
.map((e) => e.average)
|
||||
.fold(0.0, (double a, double b) => a + b) /
|
||||
gradeProvider.groupAverages.length
|
||||
: 0.0;
|
||||
|
||||
if (subjectAvg > 0) {
|
||||
@ -169,18 +193,31 @@ class _GradesPageState extends State<GradesPage> {
|
||||
|
||||
final double totalClassAvg = gradeProvider.groupAverages.isEmpty
|
||||
? 0.0
|
||||
: gradeProvider.groupAverages.map((e) => e.average).fold(0.0, (double a, double b) => a + b) / gradeProvider.groupAverages.length;
|
||||
: gradeProvider.groupAverages
|
||||
.map((e) => e.average)
|
||||
.fold(0.0, (double a, double b) => a + b) /
|
||||
gradeProvider.groupAverages.length;
|
||||
|
||||
final now = gradeProvider.grades.isNotEmpty ? gradeProvider.grades.reduce((v, e) => e.date.isAfter(v.date) ? e : v).date : DateTime.now();
|
||||
final now = gradeProvider.grades.isNotEmpty
|
||||
? gradeProvider.grades
|
||||
.reduce((v, e) => e.date.isAfter(v.date) ? e : v)
|
||||
.date
|
||||
: DateTime.now();
|
||||
|
||||
final currentStudentAvg = AverageHelper.averageEvals(gradeProvider.grades.where((e) => e.type == GradeType.midYear).toList());
|
||||
final currentStudentAvg = AverageHelper.averageEvals(gradeProvider.grades
|
||||
.where((e) => e.type == GradeType.midYear)
|
||||
.toList());
|
||||
final prevStudentAvg = AverageHelper.averageEvals(gradeProvider.grades
|
||||
.where((e) => e.type == GradeType.midYear)
|
||||
.where((e) => e.date.isBefore(now.subtract(const Duration(days: 30))))
|
||||
.toList());
|
||||
|
||||
List<Grade> graphGrades = gradeProvider.grades
|
||||
.where((e) => e.type == GradeType.midYear && (avgDropValue == 0 || e.date.isAfter(DateTime.now().subtract(Duration(days: avgDropValue)))))
|
||||
.where((e) =>
|
||||
e.type == GradeType.midYear &&
|
||||
(avgDropValue == 0 ||
|
||||
e.date.isAfter(
|
||||
DateTime.now().subtract(Duration(days: avgDropValue)))))
|
||||
.toList();
|
||||
|
||||
yearlyGraph = Padding(
|
||||
@ -201,15 +238,20 @@ class _GradesPageState extends State<GradesPage> {
|
||||
children: [
|
||||
// if (totalClassAvg >= 1.0) AverageDisplay(average: totalClassAvg, border: true),
|
||||
// const SizedBox(width: 4.0),
|
||||
TrendDisplay(previous: prevStudentAvg, current: currentStudentAvg),
|
||||
if (gradeProvider.grades.where((e) => e.type == GradeType.midYear).isNotEmpty) AverageDisplay(average: currentStudentAvg),
|
||||
TrendDisplay(
|
||||
previous: prevStudentAvg, current: currentStudentAvg),
|
||||
if (gradeProvider.grades
|
||||
.where((e) => e.type == GradeType.midYear)
|
||||
.isNotEmpty)
|
||||
AverageDisplay(average: currentStudentAvg),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(top: 12.0, right: 12.0),
|
||||
child: GradeGraph(graphGrades, dayThreshold: 2, classAvg: totalClassAvg),
|
||||
child:
|
||||
GradeGraph(graphGrades, dayThreshold: 2, classAvg: totalClassAvg),
|
||||
),
|
||||
),
|
||||
);
|
||||
@ -225,7 +267,8 @@ class _GradesPageState extends State<GradesPage> {
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.only(top: 9.0),
|
||||
child: NestedScrollView(
|
||||
physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()),
|
||||
physics: const BouncingScrollPhysics(
|
||||
parent: AlwaysScrollableScrollPhysics()),
|
||||
headerSliverBuilder: (context, _) => [
|
||||
SliverAppBar(
|
||||
centerTitle: false,
|
||||
@ -241,7 +284,9 @@ class _GradesPageState extends State<GradesPage> {
|
||||
child: ProfileImage(
|
||||
heroTag: "profile",
|
||||
name: firstName,
|
||||
backgroundColor: ColorUtils.stringToColor(user.displayName ?? "?"),
|
||||
backgroundColor: Theme.of(context)
|
||||
.colorScheme
|
||||
.primary, //ColorUtils.stringToColor(user.displayName ?? "?"),
|
||||
badge: updateProvider.available,
|
||||
role: user.role,
|
||||
profilePictureString: user.picture,
|
||||
@ -254,7 +299,10 @@ class _GradesPageState extends State<GradesPage> {
|
||||
padding: const EdgeInsets.only(left: 8.0),
|
||||
child: Text(
|
||||
"Grades".i18n,
|
||||
style: TextStyle(color: AppColors.of(context).text, fontSize: 32.0, fontWeight: FontWeight.bold),
|
||||
style: TextStyle(
|
||||
color: AppColors.of(context).text,
|
||||
fontSize: 32.0,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
shadowColor: Theme.of(context).shadowColor,
|
||||
@ -269,7 +317,8 @@ class _GradesPageState extends State<GradesPage> {
|
||||
itemCount: max(subjectTiles.length, 1),
|
||||
itemBuilder: (context, index) {
|
||||
if (subjectTiles.isNotEmpty) {
|
||||
EdgeInsetsGeometry panelPadding = const EdgeInsets.symmetric(horizontal: 24.0);
|
||||
EdgeInsetsGeometry panelPadding =
|
||||
const EdgeInsets.symmetric(horizontal: 24.0);
|
||||
|
||||
if (subjectTiles[index].runtimeType == GradeSubjectTile) {
|
||||
return Padding(
|
||||
@ -279,7 +328,8 @@ class _GradesPageState extends State<GradesPage> {
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
));
|
||||
} else {
|
||||
return Padding(padding: panelPadding, child: subjectTiles[index]);
|
||||
return Padding(
|
||||
padding: panelPadding, child: subjectTiles[index]);
|
||||
}
|
||||
} else {
|
||||
return Container();
|
||||
|
@ -73,9 +73,11 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
|
||||
_pageController = PageController();
|
||||
user = Provider.of<UserProvider>(context, listen: false);
|
||||
_liveCard = Provider.of<LiveCardProvider>(context, listen: false);
|
||||
_liveCardAnimation = AnimationController(vsync: this, duration: const Duration(milliseconds: 500));
|
||||
_liveCardAnimation = AnimationController(
|
||||
vsync: this, duration: const Duration(milliseconds: 500));
|
||||
|
||||
_liveCardAnimation.animateTo(_liveCard.show ? 1.0 : 0.0, duration: Duration.zero);
|
||||
_liveCardAnimation.animateTo(_liveCard.show ? 1.0 : 0.0,
|
||||
duration: Duration.zero);
|
||||
|
||||
listOrder = List.generate(pageCount, (index) => "$index");
|
||||
}
|
||||
@ -93,21 +95,29 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
|
||||
|
||||
void setGreeting() {
|
||||
DateTime now = DateTime.now();
|
||||
if (now.isBefore(DateTime(now.year, DateTime.august, 31)) && now.isAfter(DateTime(now.year, DateTime.june, 14))) {
|
||||
if (now.isBefore(DateTime(now.year, DateTime.august, 31)) &&
|
||||
now.isAfter(DateTime(now.year, DateTime.june, 14))) {
|
||||
greeting = "goodrest";
|
||||
|
||||
if (NavigationScreen.of(context)?.init("confetti") ?? false) {
|
||||
_confettiController = ConfettiController(duration: const Duration(seconds: 1));
|
||||
Future.delayed(const Duration(seconds: 1)).then((value) => mounted ? _confettiController?.play() : null);
|
||||
_confettiController =
|
||||
ConfettiController(duration: const Duration(seconds: 1));
|
||||
Future.delayed(const Duration(seconds: 1))
|
||||
.then((value) => mounted ? _confettiController?.play() : null);
|
||||
}
|
||||
} else if (now.month == user.student?.birth.month && now.day == user.student?.birth.day) {
|
||||
} else if (now.month == user.student?.birth.month &&
|
||||
now.day == user.student?.birth.day) {
|
||||
greeting = "happybirthday";
|
||||
|
||||
if (NavigationScreen.of(context)?.init("confetti") ?? false) {
|
||||
_confettiController = ConfettiController(duration: const Duration(seconds: 3));
|
||||
Future.delayed(const Duration(seconds: 1)).then((value) => mounted ? _confettiController?.play() : null);
|
||||
_confettiController =
|
||||
ConfettiController(duration: const Duration(seconds: 3));
|
||||
Future.delayed(const Duration(seconds: 1))
|
||||
.then((value) => mounted ? _confettiController?.play() : null);
|
||||
}
|
||||
} else if (now.month == DateTime.december && now.day >= 24 && now.day <= 26) {
|
||||
} else if (now.month == DateTime.december &&
|
||||
now.day >= 24 &&
|
||||
now.day <= 26) {
|
||||
greeting = "merryxmas";
|
||||
} else if (now.month == DateTime.january && now.day == 1) {
|
||||
greeting = "happynewyear";
|
||||
@ -149,14 +159,16 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 12.0),
|
||||
child: NestedScrollView(
|
||||
physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()),
|
||||
physics: const BouncingScrollPhysics(
|
||||
parent: AlwaysScrollableScrollPhysics()),
|
||||
headerSliverBuilder: (context, _) => [
|
||||
AnimatedBuilder(
|
||||
animation: _liveCardAnimation,
|
||||
builder: (context, child) {
|
||||
return SliverAppBar(
|
||||
automaticallyImplyLeading: false,
|
||||
surfaceTintColor: Theme.of(context).scaffoldBackgroundColor,
|
||||
surfaceTintColor:
|
||||
Theme.of(context).scaffoldBackgroundColor,
|
||||
centerTitle: false,
|
||||
titleSpacing: 0.0,
|
||||
// Welcome text
|
||||
@ -168,7 +180,10 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 18.0,
|
||||
color: Theme.of(context).textTheme.bodyMedium?.color,
|
||||
color: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium
|
||||
?.color,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -180,9 +195,11 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
|
||||
child: ProfileImage(
|
||||
heroTag: "profile",
|
||||
name: firstName,
|
||||
backgroundColor: !settings.presentationMode
|
||||
? ColorUtils.stringToColor(user.displayName ?? "?")
|
||||
: Theme.of(context).colorScheme.secondary,
|
||||
backgroundColor: Theme.of(context)
|
||||
.colorScheme
|
||||
.primary, //!settings.presentationMode
|
||||
//? ColorUtils.stringToColor(user.displayName ?? "?")
|
||||
//: Theme.of(context).colorScheme.secondary,
|
||||
badge: updateProvider.available,
|
||||
role: user.role,
|
||||
profilePictureString: user.picture,
|
||||
@ -199,7 +216,8 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
|
||||
padding: EdgeInsets.only(
|
||||
left: 24.0,
|
||||
right: 24.0,
|
||||
top: 58.0 + MediaQuery.of(context).padding.top,
|
||||
top:
|
||||
58.0 + MediaQuery.of(context).padding.top,
|
||||
bottom: 52.0,
|
||||
),
|
||||
child: Transform.scale(
|
||||
@ -223,11 +241,15 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
|
||||
],
|
||||
controller: _tabController,
|
||||
onTap: (i) async {
|
||||
int selectedPage = _pageController.page!.round();
|
||||
int selectedPage =
|
||||
_pageController.page!.round();
|
||||
|
||||
if (i == selectedPage) return;
|
||||
if (_pageController.page?.roundToDouble() != _pageController.page) {
|
||||
_pageController.animateToPage(i, curve: Curves.easeIn, duration: kTabScrollDuration);
|
||||
if (_pageController.page?.roundToDouble() !=
|
||||
_pageController.page) {
|
||||
_pageController.animateToPage(i,
|
||||
curve: Curves.easeIn,
|
||||
duration: kTabScrollDuration);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -252,14 +274,22 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
|
||||
child: NotificationListener<ScrollNotification>(
|
||||
onNotification: (notification) {
|
||||
// from flutter source
|
||||
if (notification is ScrollUpdateNotification && !_tabController.indexIsChanging) {
|
||||
if ((_pageController.page! - _tabController.index).abs() > 1.0) {
|
||||
if (notification is ScrollUpdateNotification &&
|
||||
!_tabController.indexIsChanging) {
|
||||
if ((_pageController.page! - _tabController.index)
|
||||
.abs() >
|
||||
1.0) {
|
||||
_tabController.index = _pageController.page!.floor();
|
||||
}
|
||||
_tabController.offset = (_pageController.page! - _tabController.index).clamp(-1.0, 1.0);
|
||||
_tabController.offset =
|
||||
(_pageController.page! - _tabController.index)
|
||||
.clamp(-1.0, 1.0);
|
||||
} else if (notification is ScrollEndNotification) {
|
||||
_tabController.index = _pageController.page!.round();
|
||||
if (!_tabController.indexIsChanging) _tabController.offset = (_pageController.page! - _tabController.index).clamp(-1.0, 1.0);
|
||||
if (!_tabController.indexIsChanging)
|
||||
_tabController.offset =
|
||||
(_pageController.page! - _tabController.index)
|
||||
.clamp(-1.0, 1.0);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
@ -269,33 +299,44 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
|
||||
(BuildContext context, int index) {
|
||||
return FutureBuilder<List<DateWidget>>(
|
||||
key: ValueKey<String>(listOrder[index]),
|
||||
future: getFilterWidgets(homeFilters[index], context: context),
|
||||
builder: (context, dateWidgets) => dateWidgets.data != null
|
||||
future: getFilterWidgets(homeFilters[index],
|
||||
context: context),
|
||||
builder: (context, dateWidgets) => dateWidgets
|
||||
.data !=
|
||||
null
|
||||
? RefreshIndicator(
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
color:
|
||||
Theme.of(context).colorScheme.secondary,
|
||||
onRefresh: () => syncAll(context),
|
||||
child: ImplicitlyAnimatedList<Widget>(
|
||||
items: [
|
||||
if (index == 0) const SizedBox(key: Key("\$premium")),
|
||||
...sortDateWidgets(context, dateWidgets: dateWidgets.data!),
|
||||
if (index == 0)
|
||||
const SizedBox(key: Key("\$premium")),
|
||||
...sortDateWidgets(context,
|
||||
dateWidgets: dateWidgets.data!),
|
||||
],
|
||||
itemBuilder: filterItemBuilder,
|
||||
spawnIsolate: false,
|
||||
areItemsTheSame: (a, b) => a.key == b.key,
|
||||
physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24.0),
|
||||
physics: const BouncingScrollPhysics(
|
||||
parent:
|
||||
AlwaysScrollableScrollPhysics()),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 24.0),
|
||||
))
|
||||
: Container(),
|
||||
);
|
||||
},
|
||||
childCount: 4,
|
||||
findChildIndexCallback: (Key key) {
|
||||
final ValueKey<String> valueKey = key as ValueKey<String>;
|
||||
final ValueKey<String> valueKey =
|
||||
key as ValueKey<String>;
|
||||
final String data = valueKey.value;
|
||||
return listOrder.indexOf(data);
|
||||
},
|
||||
),
|
||||
physics: const PageScrollPhysics().applyTo(const BouncingScrollPhysics()),
|
||||
physics: const PageScrollPhysics()
|
||||
.applyTo(const BouncingScrollPhysics()),
|
||||
),
|
||||
),
|
||||
)),
|
||||
|
@ -24,7 +24,8 @@ class MessagesPage extends StatefulWidget {
|
||||
_MessagesPageState createState() => _MessagesPageState();
|
||||
}
|
||||
|
||||
class _MessagesPageState extends State<MessagesPage> with TickerProviderStateMixin {
|
||||
class _MessagesPageState extends State<MessagesPage>
|
||||
with TickerProviderStateMixin {
|
||||
late UserProvider user;
|
||||
late MessageProvider messageProvider;
|
||||
late UpdateProvider updateProvider;
|
||||
@ -51,7 +52,8 @@ class _MessagesPageState extends State<MessagesPage> with TickerProviderStateMix
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.only(top: 12.0),
|
||||
child: NestedScrollView(
|
||||
physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()),
|
||||
physics: const BouncingScrollPhysics(
|
||||
parent: AlwaysScrollableScrollPhysics()),
|
||||
headerSliverBuilder: (context, _) => [
|
||||
SliverAppBar(
|
||||
pinned: true,
|
||||
@ -67,7 +69,9 @@ class _MessagesPageState extends State<MessagesPage> with TickerProviderStateMix
|
||||
child: ProfileImage(
|
||||
heroTag: "profile",
|
||||
name: firstName,
|
||||
backgroundColor: ColorUtils.stringToColor(user.displayName ?? "?"),
|
||||
backgroundColor: Theme.of(context)
|
||||
.colorScheme
|
||||
.primary, //ColorUtils.stringToColor(user.displayName ?? "?"),
|
||||
badge: updateProvider.available,
|
||||
role: user.role,
|
||||
profilePictureString: user.picture,
|
||||
@ -81,7 +85,10 @@ class _MessagesPageState extends State<MessagesPage> with TickerProviderStateMix
|
||||
padding: const EdgeInsets.only(left: 8.0),
|
||||
child: Text(
|
||||
"Messages".i18n,
|
||||
style: TextStyle(color: AppColors.of(context).text, fontSize: 32.0, fontWeight: FontWeight.bold),
|
||||
style: TextStyle(
|
||||
color: AppColors.of(context).text,
|
||||
fontSize: 32.0,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
bottom: FilterBar(items: [
|
||||
@ -95,7 +102,8 @@ class _MessagesPageState extends State<MessagesPage> with TickerProviderStateMix
|
||||
body: TabBarView(
|
||||
physics: const BouncingScrollPhysics(),
|
||||
controller: tabController,
|
||||
children: List.generate(4, (index) => filterViewBuilder(context, index))),
|
||||
children: List.generate(
|
||||
4, (index) => filterViewBuilder(context, index))),
|
||||
),
|
||||
),
|
||||
);
|
||||
@ -149,7 +157,9 @@ class _MessagesPageState extends State<MessagesPage> with TickerProviderStateMix
|
||||
}
|
||||
|
||||
Widget filterViewBuilder(context, int activeData) {
|
||||
List<Widget> filterWidgets = sortDateWidgets(context, dateWidgets: getFilterWidgets(MessageType.values[activeData]), hasShadow: true);
|
||||
List<Widget> filterWidgets = sortDateWidgets(context,
|
||||
dateWidgets: getFilterWidgets(MessageType.values[activeData]),
|
||||
hasShadow: true);
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 12.0),
|
||||
@ -167,7 +177,8 @@ class _MessagesPageState extends State<MessagesPage> with TickerProviderStateMix
|
||||
physics: const BouncingScrollPhysics(),
|
||||
itemBuilder: (context, index) => filterWidgets.isNotEmpty
|
||||
? Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 6.0),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 24.0, vertical: 6.0),
|
||||
child: filterWidgets[index],
|
||||
)
|
||||
: Empty(subtitle: "empty".i18n),
|
||||
|
@ -31,21 +31,24 @@ import 'timetable_page.i18n.dart';
|
||||
// todo: "fix" overflow (priority: -1)
|
||||
|
||||
class TimetablePage extends StatefulWidget {
|
||||
const TimetablePage({Key? key, this.initialDay, this.initialWeek}) : super(key: key);
|
||||
const TimetablePage({Key? key, this.initialDay, this.initialWeek})
|
||||
: super(key: key);
|
||||
|
||||
final DateTime? initialDay;
|
||||
final Week? initialWeek;
|
||||
|
||||
static void jump(BuildContext context, {Week? week, DateTime? day, Lesson? lesson}) {
|
||||
static void jump(BuildContext context,
|
||||
{Week? week, DateTime? day, Lesson? lesson}) {
|
||||
// Go to timetable page with arguments
|
||||
NavigationScreen.of(context)?.customRoute(navigationPageRoute((context) => TimetablePage(
|
||||
initialDay: lesson?.date ?? day,
|
||||
initialWeek: lesson?.date != null
|
||||
? Week.fromDate(lesson!.date)
|
||||
: day != null
|
||||
? Week.fromDate(day)
|
||||
: week,
|
||||
)));
|
||||
NavigationScreen.of(context)
|
||||
?.customRoute(navigationPageRoute((context) => TimetablePage(
|
||||
initialDay: lesson?.date ?? day,
|
||||
initialWeek: lesson?.date != null
|
||||
? Week.fromDate(lesson!.date)
|
||||
: day != null
|
||||
? Week.fromDate(day)
|
||||
: week,
|
||||
)));
|
||||
|
||||
NavigationScreen.of(context)?.setPage("timetable");
|
||||
|
||||
@ -57,7 +60,8 @@ class TimetablePage extends StatefulWidget {
|
||||
_TimetablePageState createState() => _TimetablePageState();
|
||||
}
|
||||
|
||||
class _TimetablePageState extends State<TimetablePage> with TickerProviderStateMixin, WidgetsBindingObserver {
|
||||
class _TimetablePageState extends State<TimetablePage>
|
||||
with TickerProviderStateMixin, WidgetsBindingObserver {
|
||||
late UserProvider user;
|
||||
late TimetableProvider timetableProvider;
|
||||
late UpdateProvider updateProvider;
|
||||
@ -68,7 +72,8 @@ class _TimetablePageState extends State<TimetablePage> with TickerProviderStateM
|
||||
|
||||
int _getDayIndex(DateTime date) {
|
||||
int index = 0;
|
||||
if (_controller.days == null || (_controller.days?.isEmpty ?? true)) return index;
|
||||
if (_controller.days == null || (_controller.days?.isEmpty ?? true))
|
||||
return index;
|
||||
|
||||
// find the first day with upcoming lessons
|
||||
index = _controller.days!.indexWhere((day) => day.last.end.isAfter(date));
|
||||
@ -110,11 +115,14 @@ class _TimetablePageState extends State<TimetablePage> with TickerProviderStateM
|
||||
_tabController = TabController(
|
||||
length: _controller.days!.length,
|
||||
vsync: this,
|
||||
initialIndex: min(_tabController.index, max(_controller.days!.length - 1, 0)),
|
||||
initialIndex:
|
||||
min(_tabController.index, max(_controller.days!.length - 1, 0)),
|
||||
);
|
||||
|
||||
if (initial || _controller.previousWeekId != _controller.currentWeekId) {
|
||||
_tabController.animateTo(_getDayIndex(widget.initialDay ?? DateTime.now()));
|
||||
if (initial ||
|
||||
_controller.previousWeekId != _controller.currentWeekId) {
|
||||
_tabController
|
||||
.animateTo(_getDayIndex(widget.initialDay ?? DateTime.now()));
|
||||
}
|
||||
initial = false;
|
||||
|
||||
@ -127,7 +135,8 @@ class _TimetablePageState extends State<TimetablePage> with TickerProviderStateM
|
||||
if (widget.initialWeek != null) {
|
||||
_controller.jump(widget.initialWeek!, context: context, initial: true);
|
||||
} else {
|
||||
_controller.jump(_controller.currentWeek, context: context, initial: true, skip: true);
|
||||
_controller.jump(_controller.currentWeek,
|
||||
context: context, initial: true, skip: true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -152,7 +161,8 @@ class _TimetablePageState extends State<TimetablePage> with TickerProviderStateM
|
||||
// Sometimes when changing weeks really fast,
|
||||
// controller.days might be null or won't include index
|
||||
try {
|
||||
return DateFormat("EEEE", I18n.of(context).locale.languageCode).format(_controller.days![index].first.date);
|
||||
return DateFormat("EEEE", I18n.of(context).locale.languageCode)
|
||||
.format(_controller.days![index].first.date);
|
||||
} catch (e) {
|
||||
return "timetable".i18n;
|
||||
}
|
||||
@ -172,11 +182,15 @@ class _TimetablePageState extends State<TimetablePage> with TickerProviderStateM
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.only(top: 9.0),
|
||||
child: RefreshIndicator(
|
||||
onRefresh: () => mounted ? _controller.jump(_controller.currentWeek, context: context, loader: false) : Future.value(null),
|
||||
onRefresh: () => mounted
|
||||
? _controller.jump(_controller.currentWeek,
|
||||
context: context, loader: false)
|
||||
: Future.value(null),
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
edgeOffset: 132.0,
|
||||
child: NestedScrollView(
|
||||
physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()),
|
||||
physics: const BouncingScrollPhysics(
|
||||
parent: AlwaysScrollableScrollPhysics()),
|
||||
headerSliverBuilder: (context, _) => [
|
||||
SliverAppBar(
|
||||
centerTitle: false,
|
||||
@ -194,7 +208,9 @@ class _TimetablePageState extends State<TimetablePage> with TickerProviderStateM
|
||||
child: ProfileImage(
|
||||
heroTag: "profile",
|
||||
name: firstName,
|
||||
backgroundColor: ColorUtils.stringToColor(user.displayName ?? "?"),
|
||||
backgroundColor: Theme.of(context)
|
||||
.colorScheme
|
||||
.primary, //ColorUtils.stringToColor(user.displayName ?? "?"),
|
||||
badge: updateProvider.available,
|
||||
role: user.role,
|
||||
profilePictureString: user.picture,
|
||||
@ -205,7 +221,8 @@ class _TimetablePageState extends State<TimetablePage> with TickerProviderStateM
|
||||
automaticallyImplyLeading: false,
|
||||
// Current day text
|
||||
title: PageTransitionSwitcher(
|
||||
reverse: _controller.currentWeekId < _controller.previousWeekId,
|
||||
reverse:
|
||||
_controller.currentWeekId < _controller.previousWeekId,
|
||||
transitionBuilder: (
|
||||
Widget child,
|
||||
Animation<double> primaryAnimation,
|
||||
@ -229,8 +246,9 @@ class _TimetablePageState extends State<TimetablePage> with TickerProviderStateM
|
||||
child: Row(
|
||||
children: [
|
||||
() {
|
||||
final show =
|
||||
_controller.days == null || (_controller.loadType != LoadType.offline && _controller.loadType != LoadType.online);
|
||||
final show = _controller.days == null ||
|
||||
(_controller.loadType != LoadType.offline &&
|
||||
_controller.loadType != LoadType.online);
|
||||
const duration = Duration(milliseconds: 150);
|
||||
return AnimatedOpacity(
|
||||
opacity: show ? 1.0 : 0.0,
|
||||
@ -249,7 +267,8 @@ class _TimetablePageState extends State<TimetablePage> with TickerProviderStateM
|
||||
}(),
|
||||
() {
|
||||
if ((_controller.days?.length ?? 0) > 0) {
|
||||
return DayTitle(controller: _tabController, dayTitle: dayTitle);
|
||||
return DayTitle(
|
||||
controller: _tabController, dayTitle: dayTitle);
|
||||
} else {
|
||||
return Text(
|
||||
"timetable".i18n,
|
||||
@ -292,10 +311,12 @@ class _TimetablePageState extends State<TimetablePage> with TickerProviderStateM
|
||||
_controller.jump(
|
||||
_controller.currentWeek,
|
||||
context: context,
|
||||
loader: _controller.currentWeekId != _controller.previousWeekId,
|
||||
loader: _controller.currentWeekId !=
|
||||
_controller.previousWeekId,
|
||||
);
|
||||
}
|
||||
_tabController.animateTo(_getDayIndex(DateTime.now()));
|
||||
_tabController
|
||||
.animateTo(_getDayIndex(DateTime.now()));
|
||||
}),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
@ -304,12 +325,22 @@ class _TimetablePageState extends State<TimetablePage> with TickerProviderStateM
|
||||
"week".i18n +
|
||||
" (" +
|
||||
// Week start
|
||||
DateFormat((_controller.currentWeek.start.year != DateTime.now().year ? "yy. " : "") + "MMM d.",
|
||||
DateFormat(
|
||||
(_controller.currentWeek.start.year !=
|
||||
DateTime.now().year
|
||||
? "yy. "
|
||||
: "") +
|
||||
"MMM d.",
|
||||
I18n.of(context).locale.languageCode)
|
||||
.format(_controller.currentWeek.start) +
|
||||
" - " +
|
||||
// Week end
|
||||
DateFormat((_controller.currentWeek.start.year != DateTime.now().year ? "yy. " : "") + "MMM d.",
|
||||
DateFormat(
|
||||
(_controller.currentWeek.start.year !=
|
||||
DateTime.now().year
|
||||
? "yy. "
|
||||
: "") +
|
||||
"MMM d.",
|
||||
I18n.of(context).locale.languageCode)
|
||||
.format(_controller.currentWeek.end) +
|
||||
")",
|
||||
@ -365,41 +396,70 @@ class _TimetablePageState extends State<TimetablePage> with TickerProviderStateM
|
||||
children: List.generate(
|
||||
_controller.days!.length,
|
||||
(tab) => RefreshIndicator(
|
||||
onRefresh: () =>
|
||||
mounted ? _controller.jump(_controller.currentWeek, context: context, loader: false) : Future.value(null),
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
onRefresh: () => mounted
|
||||
? _controller.jump(
|
||||
_controller.currentWeek,
|
||||
context: context,
|
||||
loader: false)
|
||||
: Future.value(null),
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.secondary,
|
||||
child: ListView.builder(
|
||||
padding: EdgeInsets.zero,
|
||||
physics: const BouncingScrollPhysics(),
|
||||
itemCount: _controller.days![tab].length + 2,
|
||||
itemCount:
|
||||
_controller.days![tab].length + 2,
|
||||
itemBuilder: (context, index) {
|
||||
if (_controller.days == null) return Container();
|
||||
if (_controller.days == null)
|
||||
return Container();
|
||||
|
||||
// Header
|
||||
if (index == 0) {
|
||||
return const Padding(
|
||||
padding: EdgeInsets.only(top: 8.0, left: 24.0, right: 24.0),
|
||||
child: PanelHeader(padding: EdgeInsets.only(top: 12.0)),
|
||||
padding: EdgeInsets.only(
|
||||
top: 8.0,
|
||||
left: 24.0,
|
||||
right: 24.0),
|
||||
child: PanelHeader(
|
||||
padding: EdgeInsets.only(
|
||||
top: 12.0)),
|
||||
);
|
||||
}
|
||||
|
||||
// Footer
|
||||
if (index == _controller.days![tab].length + 1) {
|
||||
if (index ==
|
||||
_controller.days![tab].length +
|
||||
1) {
|
||||
return const Padding(
|
||||
padding: EdgeInsets.only(bottom: 8.0, left: 24.0, right: 24.0),
|
||||
child: PanelFooter(padding: EdgeInsets.only(top: 12.0)),
|
||||
padding: EdgeInsets.only(
|
||||
bottom: 8.0,
|
||||
left: 24.0,
|
||||
right: 24.0),
|
||||
child: PanelFooter(
|
||||
padding: EdgeInsets.only(
|
||||
top: 12.0)),
|
||||
);
|
||||
}
|
||||
|
||||
// Body
|
||||
final Lesson lesson = _controller.days![tab][index - 1];
|
||||
final bool swapDescDay = _controller.days![tab].map((l) => l.swapDesc ? 1 : 0).reduce((a, b) => a + b) >=
|
||||
_controller.days![tab].length * .5;
|
||||
final Lesson lesson =
|
||||
_controller.days![tab][index - 1];
|
||||
final bool swapDescDay = _controller
|
||||
.days![tab]
|
||||
.map(
|
||||
(l) => l.swapDesc ? 1 : 0)
|
||||
.reduce((a, b) => a + b) >=
|
||||
_controller.days![tab].length *
|
||||
.5;
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24.0),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 24.0),
|
||||
child: PanelBody(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
||||
padding:
|
||||
const EdgeInsets.symmetric(
|
||||
horizontal: 10.0),
|
||||
child: LessonViewable(
|
||||
lesson,
|
||||
swapDesc: swapDescDay,
|
||||
@ -425,32 +485,48 @@ class _TimetablePageState extends State<TimetablePage> with TickerProviderStateM
|
||||
// Label
|
||||
labelPadding: EdgeInsets.zero,
|
||||
labelColor: Theme.of(context).colorScheme.secondary,
|
||||
unselectedLabelColor: AppColors.of(context).text.withOpacity(0.9),
|
||||
unselectedLabelColor:
|
||||
AppColors.of(context).text.withOpacity(0.9),
|
||||
// Indicator
|
||||
indicatorSize: TabBarIndicatorSize.tab,
|
||||
indicatorPadding: EdgeInsets.zero,
|
||||
indicator: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.secondary.withOpacity(0.25),
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.secondary
|
||||
.withOpacity(0.25),
|
||||
borderRadius: BorderRadius.circular(45.0),
|
||||
),
|
||||
overlayColor: MaterialStateProperty.all(const Color(0x00000000)),
|
||||
overlayColor: MaterialStateProperty.all(
|
||||
const Color(0x00000000)),
|
||||
// Tabs
|
||||
padding: const EdgeInsets.symmetric(vertical: 6.0, horizontal: 8.0),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 6.0, horizontal: 8.0),
|
||||
tabs: List.generate(_tabController.length, (index) {
|
||||
String label = DateFormat("E", I18n.of(context).locale.languageCode).format(_controller.days![index].first.date);
|
||||
String label = DateFormat(
|
||||
"E", I18n.of(context).locale.languageCode)
|
||||
.format(_controller.days![index].first.date);
|
||||
return Tab(
|
||||
height: 46.0,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
if (_sameDate(_controller.days![index].first.date, DateTime.now()))
|
||||
if (_sameDate(
|
||||
_controller.days![index].first.date,
|
||||
DateTime.now()))
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 4.0),
|
||||
child: Dot(size: 4.0, color: Theme.of(context).colorScheme.secondary),
|
||||
child: Dot(
|
||||
size: 4.0,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.secondary),
|
||||
),
|
||||
Text(
|
||||
label.substring(0, min(2, label.length)),
|
||||
style: const TextStyle(fontSize: 26.0, fontWeight: FontWeight.w600),
|
||||
style: const TextStyle(
|
||||
fontSize: 26.0,
|
||||
fontWeight: FontWeight.w600),
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -469,4 +545,5 @@ class _TimetablePageState extends State<TimetablePage> with TickerProviderStateM
|
||||
}
|
||||
|
||||
// difference.inDays is not reliable
|
||||
bool _sameDate(DateTime a, DateTime b) => (a.year == b.year && a.month == b.month && a.day == b.day);
|
||||
bool _sameDate(DateTime a, DateTime b) =>
|
||||
(a.year == b.year && a.month == b.month && a.day == b.day);
|
||||
|
@ -96,15 +96,17 @@ class _SettingsScreenState extends State<SettingsScreen>
|
||||
}
|
||||
|
||||
accountTiles.add(AccountTile(
|
||||
name: Text(!settings.presentationMode ? account.name : "Béla",
|
||||
name: Text(!settings.presentationMode ? account.name : "János",
|
||||
style: const TextStyle(fontWeight: FontWeight.w500)),
|
||||
username:
|
||||
Text(!settings.presentationMode ? account.username : "72469696969"),
|
||||
Text(!settings.presentationMode ? account.username : "01234567890"),
|
||||
profileImage: ProfileImage(
|
||||
name: _firstName,
|
||||
backgroundColor: !settings.presentationMode
|
||||
? ColorUtils.stringToColor(account.name)
|
||||
: Theme.of(context).colorScheme.secondary,
|
||||
backgroundColor: Theme.of(context)
|
||||
.colorScheme
|
||||
.primary, //!settings.presentationMode
|
||||
//? ColorUtils.stringToColor(account.name)
|
||||
//: Theme.of(context).colorScheme.secondary,
|
||||
role: account.role,
|
||||
),
|
||||
onTap: () {
|
||||
@ -169,7 +171,7 @@ class _SettingsScreenState extends State<SettingsScreen>
|
||||
if (!settings.presentationMode) {
|
||||
firstName = nameParts.length > 1 ? nameParts[1] : nameParts[0];
|
||||
} else {
|
||||
firstName = "Béla";
|
||||
firstName = "János";
|
||||
}
|
||||
|
||||
String startPageTitle =
|
||||
@ -349,18 +351,18 @@ class _SettingsScreenState extends State<SettingsScreen>
|
||||
// padding: EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0),
|
||||
// child: PremiumBannerButton(),
|
||||
// ),
|
||||
if (!context.watch<PremiumProvider>().hasPremium)
|
||||
const ClipRect(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 12.0),
|
||||
child: PremiumButton(),
|
||||
),
|
||||
)
|
||||
else
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0),
|
||||
child: ActiveSponsorCard(),
|
||||
),
|
||||
// if (!context.watch<PremiumProvider>().hasPremium)
|
||||
// const ClipRect(
|
||||
// child: Padding(
|
||||
// padding: EdgeInsets.symmetric(vertical: 12.0),
|
||||
// child: PremiumButton(),
|
||||
// ),
|
||||
// )
|
||||
// else
|
||||
// const Padding(
|
||||
// padding: EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0),
|
||||
// child: ActiveSponsorCard(),
|
||||
// ),
|
||||
|
||||
// General Settings
|
||||
Padding(
|
||||
|
Loading…
x
Reference in New Issue
Block a user