implemented dynamic module settings and configurable bottom bar, added all-day event support to timetable, and overhauled marianum dates UI with month grouping and search

This commit is contained in:
2026-05-06 22:37:41 +02:00
parent 86d12884fc
commit 95ef29fb09
19 changed files with 1114 additions and 253 deletions
@@ -95,6 +95,11 @@ abstract class LoadableHydratedBloc<
gatherData().catchError(
(e) {
log('Error while fetching ${TState.toString()}: ${e.toString()}');
// The bloc may have been closed before this async error landed (e.g.
// when its scoping widget tree was disposed mid-fetch). Adding to a
// closed bloc throws "Cannot add new events after calling close",
// so swallow that case quietly.
if (isClosed) return;
add(Error(LoadingError(
message: errorToUserMessage(e),
technicalDetails: errorToTechnicalDetails(e),
+36 -2
View File
@@ -113,8 +113,42 @@ class AppModule {
return { for (var element in settings.val().modulesSettings.moduleOrder.where((element) => available.containsKey(element))) element : available[element]! };
}
static List<AppModule> getBottomBarModules(BuildContext context) => modules(context).values.toList().getRange(0, 3).toList();
static List<AppModule> getOverhangModules(BuildContext context) => modules(context).values.skip(3).toList();
static const int minBottomBarSlots = 3;
static const int maxBottomBarSlots = 5;
static int resolveBottomBarSlotCount(BuildContext context) {
final settings = context.read<SettingsCubit>().val().modulesSettings;
final available = modules(context).length;
int desired;
if (settings.autoFillBottomBar) {
final width = MediaQuery.of(context).size.width;
if (width >= 840) {
desired = 5;
} else if (width >= 600) {
desired = 4;
} else {
desired = 3;
}
} else {
desired = settings.fixedBottomBarSlots;
}
desired = desired.clamp(minBottomBarSlots, maxBottomBarSlots);
return desired.clamp(0, available);
}
static List<AppModule> getBottomBarModules(BuildContext context) {
final all = modules(context).values.toList();
final slots = resolveBottomBarSlotCount(context);
return all.take(slots).toList();
}
static List<AppModule> getOverhangModules(BuildContext context) {
final all = modules(context).values.toList();
final slots = resolveBottomBarSlotCount(context);
return all.skip(slots).toList();
}
Widget toListTile(BuildContext context, {Key? key, bool isReorder = false, Function()? onVisibleChange, bool isVisible = true}) => ListTile(
key: key,