97 lines
2.8 KiB
Dart
97 lines
2.8 KiB
Dart
import '../../../../../api/errors/error_mapper.dart';
|
|
import '../../../infrastructure/loadable_state/loading_error.dart';
|
|
import '../../../infrastructure/utility_widgets/loadable_hydrated_bloc/loadable_hydrated_bloc.dart';
|
|
import '../../../infrastructure/utility_widgets/loadable_hydrated_bloc/loadable_hydrated_bloc_event.dart';
|
|
import '../repository/chat_repository.dart';
|
|
import 'chat_event.dart';
|
|
import 'chat_state.dart';
|
|
|
|
class ChatBloc extends LoadableHydratedBloc<ChatEvent, ChatState, ChatRepository> {
|
|
DateTime _lastTokenSet = DateTime.fromMillisecondsSinceEpoch(0);
|
|
|
|
@override
|
|
ChatRepository repository() => ChatRepository();
|
|
|
|
@override
|
|
ChatState fromNothing() => const ChatState();
|
|
|
|
@override
|
|
ChatState fromStorage(Map<String, dynamic> json) => ChatState.fromJson(json);
|
|
|
|
@override
|
|
Map<String, dynamic>? toStorage(ChatState state) => state.toJson();
|
|
|
|
@override
|
|
Future<void> gatherData() async {
|
|
final token = innerState?.currentToken ?? '';
|
|
if (token.isEmpty) {
|
|
add(DataGathered((s) => s));
|
|
return;
|
|
}
|
|
await _loadChat(token);
|
|
}
|
|
|
|
void setToken(String token) {
|
|
if (token == (innerState?.currentToken ?? '')) {
|
|
refresh();
|
|
return;
|
|
}
|
|
add(Emit((s) => s.copyWith(currentToken: token, chatResponse: null)));
|
|
add(RefetchStarted<ChatState>());
|
|
_loadChat(token);
|
|
}
|
|
|
|
void setReferenceMessageId(int? messageId) {
|
|
add(Emit((s) => s.copyWith(referenceMessageId: messageId)));
|
|
}
|
|
|
|
void refresh() {
|
|
final token = innerState?.currentToken ?? '';
|
|
if (token.isEmpty) return;
|
|
add(RefetchStarted<ChatState>());
|
|
_loadChat(token);
|
|
}
|
|
|
|
Future<void> _loadChat(String token) async {
|
|
final requestStart = DateTime.now();
|
|
_lastTokenSet = requestStart;
|
|
|
|
bool stillCurrent() {
|
|
if (_lastTokenSet.isAfter(requestStart)) return false;
|
|
if ((innerState?.currentToken ?? '') != token) return false;
|
|
return true;
|
|
}
|
|
|
|
Object? capturedError;
|
|
try {
|
|
await repo.data.getChat(
|
|
token: token,
|
|
onCacheData: (data) {
|
|
if (!stillCurrent()) return;
|
|
// Cache hit: show data immediately but preserve lastFetch — the
|
|
// cached payload may be stale and we don't want the UI to claim a
|
|
// fresh fetch just happened.
|
|
add(Emit((s) => s.copyWith(chatResponse: data)));
|
|
},
|
|
onNetworkData: (data) {
|
|
if (!stillCurrent()) return;
|
|
add(DataGathered((s) => s.copyWith(chatResponse: data)));
|
|
},
|
|
onError: (e) => capturedError = e,
|
|
);
|
|
} catch (e) {
|
|
capturedError = e;
|
|
}
|
|
|
|
if (!stillCurrent()) return;
|
|
|
|
if (capturedError != null) {
|
|
add(Error(LoadingError(
|
|
message: errorToUserMessage(capturedError),
|
|
technicalDetails: errorToTechnicalDetails(capturedError),
|
|
allowRetry: errorAllowsRetry(capturedError),
|
|
)));
|
|
}
|
|
}
|
|
}
|