Build exchange workspace and shared transaction services (#28)
This commit is contained in:
1 parent
52b7135eda
commit
c496da8a55
48 files changed
+4757
-120
No files matched your search
@@ -0,0 +1,150 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import 'package:sxchnge_analytics/sxchnge_analytics.dart';
|
||||
|
||||
import '../models/wallet.dart';
|
||||
import '../services/contracts.dart';
|
||||
|
||||
class WalletProvider extends ChangeNotifier {
|
||||
WalletProvider(this.service, this.analytics);
|
||||
final WalletService service;
|
||||
final AnalyticsService analytics;
|
||||
WalletSnapshot? data;
|
||||
bool loading = false,
|
||||
failed = false,
|
||||
profileLoading = false,
|
||||
profileFailed = false,
|
||||
saving = false,
|
||||
saveFailed = false;
|
||||
String? preferredLocale;
|
||||
bool _disposed = false;
|
||||
int _revision = 0;
|
||||
Timer? _poll;
|
||||
final _settlements = <String, (JourneyRecorder, JourneyOperation)>{};
|
||||
CurrencyAccount? account(String? id) {
|
||||
for (final a in data?.accounts ?? <CurrencyAccount>[]) {
|
||||
if (a.id == id) return a;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
WalletOperation? operation(String id) {
|
||||
for (final o in data?.operations ?? <WalletOperation>[]) {
|
||||
if (o.id == id) return o;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
bool get hasPending =>
|
||||
data?.operations.any((o) => o.status == OperationStatus.pending) ?? false;
|
||||
Future<void> refresh() async {
|
||||
final rev = ++_revision;
|
||||
loading = true;
|
||||
failed = false;
|
||||
notifyListeners();
|
||||
try {
|
||||
final result = await service.fetch();
|
||||
if (_disposed || rev != _revision) return;
|
||||
data = result;
|
||||
for (final o in result.operations) {
|
||||
if (o.status == OperationStatus.pending) continue;
|
||||
final pair = _settlements.remove(o.id);
|
||||
if (pair != null) {
|
||||
pair.$1.finish(
|
||||
pair.$2,
|
||||
simulated: service.isSimulated,
|
||||
failure: o.status == OperationStatus.failed
|
||||
? JourneyFailure.declined
|
||||
: null,
|
||||
terminal: true,
|
||||
);
|
||||
pair.$1.dispose();
|
||||
}
|
||||
}
|
||||
} catch (_) {
|
||||
if (_disposed || rev != _revision) return;
|
||||
failed = true;
|
||||
}
|
||||
if (_disposed || rev != _revision) return;
|
||||
loading = false;
|
||||
_poll?.cancel();
|
||||
if (hasPending) {
|
||||
_poll = Timer(const Duration(seconds: 3), () {
|
||||
if (!_disposed) refresh();
|
||||
});
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void track(
|
||||
WalletOperation operation,
|
||||
JourneyRecorder recorder,
|
||||
JourneyKind kind,
|
||||
) {
|
||||
final step = recorder.begin(
|
||||
kind,
|
||||
JourneyStep.settlement,
|
||||
simulated: service.isSimulated,
|
||||
);
|
||||
_settlements[operation.id] = (recorder, step);
|
||||
final snapshot = data;
|
||||
if (snapshot != null) {
|
||||
data = WalletSnapshot(
|
||||
accounts: snapshot.accounts,
|
||||
operations: [
|
||||
operation,
|
||||
...snapshot.operations.where((o) => o.id != operation.id),
|
||||
],
|
||||
);
|
||||
}
|
||||
unawaited(refresh());
|
||||
}
|
||||
|
||||
Future<void> loadProfile() async {
|
||||
if (profileLoading) return;
|
||||
profileLoading = true;
|
||||
profileFailed = false;
|
||||
notifyListeners();
|
||||
try {
|
||||
final result = await service.profile();
|
||||
if (_disposed) return;
|
||||
preferredLocale = result.locale;
|
||||
} catch (_) {
|
||||
if (_disposed) return;
|
||||
profileFailed = true;
|
||||
}
|
||||
profileLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<bool> saveLocale(String locale) async {
|
||||
if (saving) return false;
|
||||
saving = true;
|
||||
saveFailed = false;
|
||||
notifyListeners();
|
||||
try {
|
||||
final result = await service.saveLocale(locale);
|
||||
if (_disposed) return false;
|
||||
preferredLocale = result.locale;
|
||||
} catch (_) {
|
||||
if (_disposed) return false;
|
||||
saveFailed = true;
|
||||
}
|
||||
saving = false;
|
||||
notifyListeners();
|
||||
return !saveFailed;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_disposed = true;
|
||||
_poll?.cancel();
|
||||
for (final p in _settlements.values) {
|
||||
p.$1.dispose(abandonActive: false);
|
||||
}
|
||||
_settlements.clear();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user