Files
rmtPocketWatcher/flutter_app/lib/providers/price_provider.dart
2025-12-14 21:53:46 -05:00

177 lines
4.8 KiB
Dart

import 'dart:async';
import 'package:flutter/foundation.dart';
import '../models/price_data.dart';
import '../services/websocket_service.dart';
import '../services/api_service.dart';
import '../services/storage_service.dart';
import '../services/notification_service.dart';
class PriceProvider with ChangeNotifier {
final WebSocketService _wsService = WebSocketService();
final ApiService _apiService = ApiService();
final StorageService _storageService = StorageService();
final NotificationService _notificationService = NotificationService();
LatestPrice? _latestPrice;
HistoryData? _historyData;
String _connectionStatus = 'Disconnected';
List<PriceAlert> _alerts = [];
double? _customAuecAmount;
String _selectedRange = '7d';
bool _isLoading = false;
bool _isHistoryLoading = false;
LatestPrice? get latestPrice => _latestPrice;
HistoryData? get historyData => _historyData;
String get connectionStatus => _connectionStatus;
List<PriceAlert> get alerts => _alerts;
double? get customAuecAmount => _customAuecAmount;
String get selectedRange => _selectedRange;
bool get isLoading => _isLoading;
bool get isHistoryLoading => _isHistoryLoading;
PriceProvider() {
_initialize();
}
Timer? _pollTimer;
void _initialize() {
// Load saved data
_loadAlerts();
_loadCustomAuecAmount();
// Connect WebSocket (currently disabled)
_wsService.connect();
// Listen to WebSocket streams
_wsService.latestPriceStream.listen((price) {
_latestPrice = price;
_checkAlerts(price);
notifyListeners();
});
_wsService.connectionStatusStream.listen((status) {
_connectionStatus = status;
notifyListeners();
});
// Fetch initial data
fetchInitialData();
// Start polling for updates every 5 minutes as backup to WebSocket
_startPolling();
}
void _startPolling() {
_pollTimer = Timer.periodic(const Duration(minutes: 5), (timer) {
fetchInitialData();
});
}
Future<void> fetchInitialData() async {
final latest = await _apiService.fetchLatestPrice();
if (latest != null) {
_latestPrice = latest;
notifyListeners();
}
await fetchHistory(_selectedRange);
}
Future<void> fetchHistory(String range) async {
_isHistoryLoading = true;
_selectedRange = range;
notifyListeners();
try {
final history = await _apiService.fetchHistory(range);
if (history != null) {
_historyData = history;
}
_wsService.requestHistory(range);
} catch (e) {
if (kDebugMode) {
print('Error fetching history: $e');
}
} finally {
_isHistoryLoading = false;
notifyListeners();
}
}
Future<void> _loadAlerts() async {
_alerts = await _storageService.getAlerts();
notifyListeners();
}
Future<void> _loadCustomAuecAmount() async {
_customAuecAmount = await _storageService.getCustomAuecAmount();
notifyListeners();
}
Future<void> addAlert(double auecAmount, double maxPrice) async {
final alert = PriceAlert(
id: DateTime.now().millisecondsSinceEpoch.toString(),
auecAmount: auecAmount,
maxPrice: maxPrice,
enabled: true,
);
await _storageService.addAlert(alert);
await _loadAlerts();
}
Future<void> toggleAlert(String id) async {
final alert = _alerts.firstWhere((a) => a.id == id);
final updated = alert.copyWith(enabled: !alert.enabled);
await _storageService.updateAlert(updated);
await _loadAlerts();
}
Future<void> deleteAlert(String id) async {
await _storageService.deleteAlert(id);
await _loadAlerts();
}
Future<void> setCustomAuecAmount(double amount) async {
await _storageService.setCustomAuecAmount(amount);
_customAuecAmount = amount;
notifyListeners();
}
void _checkAlerts(LatestPrice price) {
for (final alert in _alerts) {
if (!alert.enabled) continue;
final matchingSeller = price.allPrices.firstWhere(
(p) {
final totalPrice = (alert.auecAmount / 1000000) * p.pricePerMillion;
return totalPrice <= alert.maxPrice;
},
orElse: () => price.allPrices.first,
);
final totalPrice = (alert.auecAmount / 1000000) * matchingSeller.pricePerMillion;
if (totalPrice <= alert.maxPrice) {
// Trigger notification
_notificationService.showPriceAlert(
title: 'Price Alert Triggered!',
body: '${(alert.auecAmount / 1000000000).toStringAsFixed(1)}B AUEC available for \$${totalPrice.toStringAsFixed(2)} from ${matchingSeller.sellerName}',
auecAmount: alert.auecAmount,
price: totalPrice,
seller: matchingSeller.sellerName,
);
// Disable alert
toggleAlert(alert.id);
}
}
}
@override
void dispose() {
_pollTimer?.cancel();
_wsService.dispose();
super.dispose();
}
}