implemented foreign timetable support for students, teachers, rooms, and classes, including a searchable element picker with favorites support, introduced a capabilities system for feature gating, refactored the timetable UI into a reusable TimetableCalendarView component, and redesigned the chat input field with a unified emoji picker and integrated attachment actions.

This commit is contained in:
2026-05-31 21:29:16 +02:00
parent 6e12da08c0
commit b6d06dd3b4
41 changed files with 2325 additions and 290 deletions
@@ -0,0 +1,48 @@
import 'dart:developer';
import 'package:hydrated_bloc/hydrated_bloc.dart';
import '../../../../../api/marianumconnect/queries/get_capabilities/get_capabilities.dart';
import 'capabilities_state.dart';
/// Holds the current user's mobile capability flags. Hydrated so the last
/// known state is available immediately on cold start (no feature-flicker)
/// and offline. [load] refreshes it from the server after login.
class CapabilitiesCubit extends HydratedCubit<CapabilitiesState> {
CapabilitiesCubit() : super(const CapabilitiesState());
bool get canViewForeignTimetables => state.viewForeignTimetables;
/// Refreshes capabilities from the server. On any failure (endpoint not yet
/// live, network error, 4xx) the previously hydrated flags are kept but the
/// state is marked `loaded` — a failed fetch never silently grants a
/// capability, and an offline launch keeps whatever was cached.
Future<void> load() async {
try {
final response = await GetCapabilities().run();
emit(
CapabilitiesState(
viewForeignTimetables: response.viewForeignTimetables,
loaded: true,
),
);
} catch (e) {
log('Failed to load capabilities: $e');
emit(state.copyWith(loaded: true));
}
}
Future<void> reset() async => emit(const CapabilitiesState());
@override
CapabilitiesState fromJson(Map<String, dynamic> json) {
try {
return CapabilitiesState.fromJson(json);
} catch (_) {
return const CapabilitiesState();
}
}
@override
Map<String, dynamic>? toJson(CapabilitiesState state) => state.toJson();
}