135 lines
3.7 KiB
Dart
135 lines
3.7 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
|
|
import 'package:pshared/models/auto_refresh_mode.dart';
|
|
import 'package:pshared/models/payment/quote/status_type.dart';
|
|
import 'package:pshared/provider/payment/quotation/quotation.dart';
|
|
|
|
import 'package:pweb/providers/quotation/auto_refresh.dart';
|
|
|
|
|
|
class QuotationController extends ChangeNotifier {
|
|
QuotationProvider? _quotation;
|
|
AutoRefreshMode _autoRefreshMode = AutoRefreshMode.on;
|
|
final QuotationAutoRefreshController _autoRefreshController =
|
|
QuotationAutoRefreshController();
|
|
Timer? _ticker;
|
|
|
|
void update(QuotationProvider quotation) {
|
|
if (identical(_quotation, quotation)) return;
|
|
_quotation?.removeListener(_handleQuotationChanged);
|
|
_quotation = quotation;
|
|
_quotation?.addListener(_handleQuotationChanged);
|
|
_handleQuotationChanged();
|
|
}
|
|
|
|
bool get isLoading => _quotation?.isLoading ?? false;
|
|
Exception? get error => _quotation?.error;
|
|
bool get canRefresh => _quotation?.canRefresh ?? false;
|
|
bool get isReady => _quotation?.isReady ?? false;
|
|
AutoRefreshMode get autoRefreshMode => _autoRefreshMode;
|
|
|
|
DateTime? get quoteExpiresAt => _quotation?.quoteExpiresAt;
|
|
|
|
Duration? get timeLeft {
|
|
final expiresAt = quoteExpiresAt;
|
|
if (expiresAt == null) return null;
|
|
return expiresAt.difference(DateTime.now().toUtc());
|
|
}
|
|
|
|
bool get isExpired {
|
|
final remaining = timeLeft;
|
|
if (remaining == null) return false;
|
|
return remaining <= Duration.zero;
|
|
}
|
|
|
|
QuoteStatusType get quoteStatus {
|
|
if (isLoading) return QuoteStatusType.loading;
|
|
if (error != null) return QuoteStatusType.error;
|
|
if (_quotation?.quotation == null) return QuoteStatusType.missing;
|
|
if (isExpired) return QuoteStatusType.expired;
|
|
return QuoteStatusType.active;
|
|
}
|
|
|
|
bool get hasLiveQuote => isReady && _quotation?.quotation != null && !isExpired;
|
|
|
|
void setAutoRefreshMode(AutoRefreshMode mode) {
|
|
if (_autoRefreshMode == mode) return;
|
|
_autoRefreshMode = mode;
|
|
_syncAutoRefresh();
|
|
notifyListeners();
|
|
}
|
|
|
|
void refreshQuotation() {
|
|
_quotation?.refreshQuotation();
|
|
}
|
|
|
|
void _handleQuotationChanged() {
|
|
_syncAutoRefresh();
|
|
_syncTicker();
|
|
notifyListeners();
|
|
}
|
|
|
|
void _syncTicker() {
|
|
final expiresAt = quoteExpiresAt;
|
|
if (expiresAt == null) {
|
|
_stopTicker();
|
|
return;
|
|
}
|
|
|
|
final remaining = expiresAt.difference(DateTime.now().toUtc());
|
|
if (remaining <= Duration.zero) {
|
|
_stopTicker();
|
|
return;
|
|
}
|
|
|
|
_ticker ??= Timer.periodic(const Duration(seconds: 1), (_) {
|
|
final expiresAt = quoteExpiresAt;
|
|
if (expiresAt == null) {
|
|
_stopTicker();
|
|
return;
|
|
}
|
|
final remaining = expiresAt.difference(DateTime.now().toUtc());
|
|
if (remaining <= Duration.zero) {
|
|
_stopTicker();
|
|
}
|
|
notifyListeners();
|
|
});
|
|
}
|
|
|
|
void _stopTicker() {
|
|
_ticker?.cancel();
|
|
_ticker = null;
|
|
}
|
|
|
|
void _syncAutoRefresh() {
|
|
final quotation = _quotation;
|
|
if (quotation == null) {
|
|
_autoRefreshController.reset();
|
|
return;
|
|
}
|
|
|
|
final isAutoRefreshEnabled = _autoRefreshMode == AutoRefreshMode.on;
|
|
_autoRefreshController.setEnabled(isAutoRefreshEnabled);
|
|
final canAutoRefresh = isAutoRefreshEnabled && quotation.canRefresh;
|
|
_autoRefreshController.sync(
|
|
isLoading: quotation.isLoading,
|
|
canRefresh: canAutoRefresh,
|
|
expiresAt: quoteExpiresAt,
|
|
onRefresh: _refreshQuotation,
|
|
);
|
|
}
|
|
|
|
Future<void> _refreshQuotation() async {
|
|
await _quotation?.refreshQuotation();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_quotation?.removeListener(_handleQuotationChanged);
|
|
_autoRefreshController.dispose();
|
|
_stopTicker();
|
|
super.dispose();
|
|
}
|
|
} |