Files
Finlytic/FinlyticApp/lib/features/news/bloc/news_bloc.dart
T

109 lines
3.3 KiB
Dart

import 'dart:async';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:finlytic_app/features/news/repositories/news_repository.dart';
import 'news_event.dart';
import 'news_state.dart';
class NewsBloc extends Bloc<NewsEvent, NewsState> {
final NewsRepository repository;
static const int pageSize = 20;
StreamSubscription? _liveNewsSubscription;
NewsBloc({required this.repository}) : super(NewsInitial()) {
on<FetchNews>(_onFetchNews);
on<LoadMoreNews>(_onLoadMoreNews);
on<ReceiveLiveNews>(_onReceiveLiveNews);
// Subscribe to live news from SignalR
_liveNewsSubscription = repository.liveNewsStream.listen((article) {
add(ReceiveLiveNews(article));
});
// Connect to SignalR
repository.connectToLiveFeed();
}
Future<void> _onFetchNews(FetchNews event, Emitter<NewsState> emit) async {
try {
emit(NewsLoading());
final articles = await repository.fetchNews(
page: 1,
pageSize: pageSize,
symbol: event.symbol,
isin: event.isin,
date: event.date,
);
emit(NewsLoaded(
articles: articles,
hasReachedMax: articles.length < pageSize,
currentPage: 1,
symbol: event.symbol,
isin: event.isin,
date: event.date,
));
} catch (e) {
emit(NewsError("Failed to fetch news. Please try again."));
}
}
Future<void> _onLoadMoreNews(LoadMoreNews event, Emitter<NewsState> emit) async {
if (state is NewsLoaded) {
final currentState = state as NewsLoaded;
if (currentState.hasReachedMax) return;
try {
final nextPage = currentState.currentPage + 1;
final articles = await repository.fetchNews(
page: nextPage,
pageSize: pageSize,
symbol: currentState.symbol,
isin: currentState.isin,
date: currentState.date,
);
if (articles.isEmpty) {
emit(currentState.copyWith(hasReachedMax: true));
} else {
emit(NewsLoaded(
articles: currentState.articles + articles,
hasReachedMax: articles.length < pageSize,
currentPage: nextPage,
symbol: currentState.symbol,
isin: currentState.isin,
date: currentState.date,
));
}
} catch (e) {
emit(NewsError("Failed to load more news."));
}
}
}
void _onReceiveLiveNews(ReceiveLiveNews event, Emitter<NewsState> emit) {
if (state is NewsLoaded) {
final currentState = state as NewsLoaded;
// Check if the article matches current filters before prepending
bool matchesFilter = true;
if (currentState.symbol != null || currentState.isin != null) {
// Needs proper matching logic if needed, but for now we prepend if there's no filter or if it matches
// Assuming we prepend it regardless for live feed, or we could filter based on MatchedAssets if added to model.
}
if (matchesFilter) {
// Prepend new article to the top of the list!
final updatedArticles = [event.article, ...currentState.articles];
emit(currentState.copyWith(articles: updatedArticles));
}
}
}
@override
Future<void> close() {
_liveNewsSubscription?.cancel();
repository.dispose();
return super.close();
}
}