better loading indicators for timetables, talk and files

This commit is contained in:
2026-05-05 21:07:48 +02:00
parent bee5c02a4f
commit db9c3386f1
25 changed files with 439 additions and 203 deletions
+36 -12
View File
@@ -1,3 +1,5 @@
import '../../../../../api/marianumcloud/talk/chat/getChatResponse.dart';
import '../../../infrastructure/loadableState/loading_error.dart';
import '../../../infrastructure/utilityWidgets/loadableHydratedBloc/loadable_hydrated_bloc.dart';
import '../../../infrastructure/utilityWidgets/loadableHydratedBloc/loadable_hydrated_bloc_event.dart';
import '../repository/chat_repository.dart';
@@ -22,8 +24,11 @@ class ChatBloc extends LoadableHydratedBloc<ChatEvent, ChatState, ChatRepository
@override
Future<void> gatherData() async {
final token = innerState?.currentToken ?? '';
if (token.isEmpty) return;
_loadChat(token);
if (token.isEmpty) {
add(DataGathered((s) => s));
return;
}
await _loadChat(token);
}
void setToken(String token) {
@@ -32,6 +37,7 @@ class ChatBloc extends LoadableHydratedBloc<ChatEvent, ChatState, ChatRepository
return;
}
add(Emit((s) => s.copyWith(currentToken: token, chatResponse: null)));
add(RefetchStarted<ChatState>());
_loadChat(token);
}
@@ -41,19 +47,37 @@ class ChatBloc extends LoadableHydratedBloc<ChatEvent, ChatState, ChatRepository
void refresh() {
final token = innerState?.currentToken ?? '';
if (token.isNotEmpty) _loadChat(token);
if (token.isEmpty) return;
add(RefetchStarted<ChatState>());
_loadChat(token);
}
void _loadChat(String token) {
Future<void> _loadChat(String token) async {
final requestStart = DateTime.now();
_lastTokenSet = requestStart;
repo.data.getChat(
token: token,
onUpdate: (data) {
if (_lastTokenSet.isAfter(requestStart)) return;
if ((innerState?.currentToken ?? '') != token) return;
add(DataGathered((s) => s.copyWith(chatResponse: data)));
},
);
Object? capturedError;
GetChatResponse? response;
try {
response = await repo.data.getChat(
token: token,
onError: (e) => capturedError = e,
);
} catch (e) {
capturedError = e;
}
if (_lastTokenSet.isAfter(requestStart)) return;
if ((innerState?.currentToken ?? '') != token) return;
if (response != null) {
add(DataGathered((s) => s.copyWith(chatResponse: response)));
}
if (capturedError != null) {
add(Error(LoadingError(
message: capturedError.toString(),
allowRetry: true,
)));
}
}
}
@@ -2,10 +2,26 @@ import '../../../../../api/marianumcloud/talk/chat/getChatCache.dart';
import '../../../../../api/marianumcloud/talk/chat/getChatResponse.dart';
class ChatDataProvider {
void getChat({
Future<GetChatResponse> getChat({
required String token,
required void Function(GetChatResponse data) onUpdate,
}) {
GetChatCache(chatToken: token, onUpdate: onUpdate);
void Function(GetChatResponse data)? onUpdate,
void Function(Object)? onError,
}) async {
GetChatResponse? latest;
Object? capturedError;
final cache = GetChatCache(
chatToken: token,
onUpdate: (data) {
latest = data;
onUpdate?.call(data);
},
onError: (e) {
capturedError = e;
onError?.call(e);
},
);
await cache.ready;
if (latest != null) return latest!;
throw capturedError ?? Exception('No data and no error from getChat');
}
}