refactored data providers with centralized cache resolution, unified UI using custom dialogs and bottom sheets, and enhanced network error handling for Dio and TLS errors

This commit is contained in:
2026-05-08 20:01:45 +02:00
parent c62a14645a
commit 9e139b5704
37 changed files with 595 additions and 753 deletions
+13 -38
View File
@@ -25,22 +25,15 @@ import '../widget/debug/cache_view.dart';
import '../widget/file_viewer.dart';
import '../widget/user_avatar.dart';
/// Single entry point for full-page navigations across the app.
///
/// Every full-page push in modules should go through one of these methods.
/// Dialogs (`showDialog`), bottom sheets (`showStickyFlexibleBottomSheet`,
/// `showDetailsBottomSheet`), and `Navigator.pop` for closing those
/// remain unchanged and live at the call sites.
/// Single entry point for full-page navigations. Dialogs and bottom sheets
/// stay at the call sites; only full-page pushes go through here.
class AppRoutes {
AppRoutes._();
/// Token of a chat that should be auto-opened in the Talk tab once
/// the chat list view picks it up. Set by [openChatByToken] (e.g. from
/// a tapped notification) and consumed by the `ChatList` widget.
/// Set by [openChatByToken] (e.g. from a tapped notification) and consumed
/// by `ChatList` once the matching room is loaded.
static final ValueNotifier<String?> pendingChatToken = ValueNotifier(null);
// -- Files --------------------------------------------------------------
static void openFolder(BuildContext context, List<String> path) {
pushScreen(context, withNavBar: false, screen: Files(path: path));
}
@@ -53,14 +46,10 @@ class AppRoutes {
);
}
// -- Timetable ----------------------------------------------------------
static void openCustomEvents(BuildContext context) {
pushScreen(context, withNavBar: false, screen: const CustomEventsView());
}
// -- Marianum Message ---------------------------------------------------
static void openMarianumMessage(BuildContext context, String basePath, MarianumMessage message) {
pushScreen(
context,
@@ -69,8 +58,6 @@ class AppRoutes {
);
}
// -- Sharing / Settings / Feedback / DevTools ---------------------------
static void openQrShare(BuildContext context) {
pushScreen(context, withNavBar: false, screen: const QrShareView());
}
@@ -95,8 +82,6 @@ class AppRoutes {
pushScreen(context, withNavBar: false, screen: const Roomplan());
}
// -- Talk ---------------------------------------------------------------
static void openMessageReactions(BuildContext context, String token, int messageId) {
pushScreen(
context,
@@ -105,8 +90,6 @@ class AppRoutes {
);
}
/// Opens a chat from a known [GetRoomResponseObject]. Delegates to
/// [TalkNavigator.pushSplitView] so tablet split-view behaviour stays intact.
static void openChatView(
BuildContext context, {
required GetRoomResponseObject room,
@@ -122,9 +105,8 @@ class AppRoutes {
context.read<ChatBloc>().setToken(room.token);
}
/// Schedules a chat to be opened in the Talk tab. Use this when only the
/// token is known (e.g. from a tapped notification) — the actual push
/// happens inside the `ChatList` widget once the room is available.
/// Schedules a chat to be opened in the Talk tab once the room is loaded.
/// Use when only the token is known (e.g. from a tapped notification).
static void openChatByToken(BuildContext context, String token) {
pendingChatToken.value = token;
goToTalkTab(context);
@@ -135,11 +117,9 @@ class AppRoutes {
}
}
/// Resolves a pending chat token (set via [openChatByToken]) using the
/// [ChatListBloc]'s current rooms and the active [AccountData] credentials.
/// Returns `null` if the token cannot yet be matched (e.g. the room is
/// still being loaded). Callers should keep listening to [pendingChatToken]
/// and the bloc state and retry when either changes.
/// Resolves a pending chat token (set via [openChatByToken]). Returns null
/// if the room or account is not ready yet — callers should retry when
/// [pendingChatToken] or the bloc state change.
static ResolvedPendingChat? resolvePendingChat(BuildContext context) {
final token = pendingChatToken.value;
if (token == null) return null;
@@ -166,17 +146,14 @@ class AppRoutes {
return null;
}
// -- Module / Tab navigation -------------------------------------------
/// Opens an [AppModule]'s root view as a full screen push (used by the
/// "Mehr" tab list). Modules that live in the bottom bar are reached via
/// [goToTab] instead.
/// Pushes a module from the "Mehr" tab list. Modules already in the bottom
/// bar are switched to via [goToTab] instead.
static void openModule(BuildContext context, AppModule module) {
pushScreen(context, withNavBar: false, screen: module.create());
}
/// Switches the bottom navigation to the given [module] if it is currently
/// in the bottom bar. Returns `true` if the jump happened.
/// Switches the bottom navigation to [module]. Returns false when the
/// module is not currently in the bottom bar.
static bool goToTab(BuildContext context, Modules module) {
final index = AppModule.getBottomBarModules(context)
.map((e) => e.module)
@@ -187,8 +164,6 @@ class AppRoutes {
return true;
}
/// Convenience wrapper for the Talk tab — preserved for the notification
/// handler API which only knows about Talk.
static void goToTalkTab(BuildContext context) {
goToTab(context, Modules.talk);
}