feat(app): clean architecture with typed repositories, DTO models and calendar event logos

This commit is contained in:
2026-08-15 01:03:22 +02:00
parent f08fecde23
commit 15f8f7896e
34 changed files with 1435 additions and 1420 deletions
@@ -0,0 +1,49 @@
import '../../../core/network/api_client.dart';
import '../models/favorite_asset_model.dart';
/// Clean Architecture Repository for managing user favorite assets.
class FavoritesRepository {
final ApiClient apiClient;
const FavoritesRepository({required this.apiClient});
/// Fetches the user's favorite asset list from the backend.
Future<List<FavoriteAssetModel>> getFavorites() async {
final ts = DateTime.now().millisecondsSinceEpoch;
final res = await apiClient.get('/api/v1/user/favorites?_t=$ts');
if (res.statusCode == 200 && res.data is List) {
final rawList = res.data as List;
final dedupMap = <String, FavoriteAssetModel>{};
for (var item in rawList) {
if (item is Map<String, dynamic>) {
final model = FavoriteAssetModel.fromJson(item);
final key = (model.isin.isNotEmpty ? model.isin : (model.symbol.isNotEmpty ? model.symbol : model.name)).toUpperCase();
if (!dedupMap.containsKey(key)) {
dedupMap[key] = model;
}
}
}
return dedupMap.values.toList();
}
return [];
}
/// Adds an asset to user favorites by ISIN or symbol.
Future<bool> addFavorite(String identifier) async {
final res = await apiClient.post('/api/v1/user/favorites/$identifier');
return res.statusCode == 200 || res.statusCode == 201;
}
/// Removes an asset from user favorites.
Future<bool> removeFavorite(String identifier) async {
final res = await apiClient.delete('/api/v1/user/favorites/$identifier');
return res.statusCode == 200 || res.statusCode == 204;
}
/// Updates the preferred active ticker for a favorite asset.
Future<bool> updateFavoriteTicker(String symbolOrIsin, String ticker) async {
final res = await apiClient.post('/api/v1/user/favorites/$symbolOrIsin/ticker?ticker=$ticker');
return res.statusCode == 200;
}
}