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