Initial peyawallet import with monero_c submodule
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:logger/logger.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
||||
import '../domain/models.dart';
|
||||
|
||||
class ConfigRepository {
|
||||
ConfigRepository(this._configFile, this._logger);
|
||||
|
||||
final File _configFile;
|
||||
final Logger _logger;
|
||||
|
||||
static Future<ConfigRepository> create(Logger logger) async {
|
||||
final baseDir = await getApplicationSupportDirectory();
|
||||
final configDir = Directory(baseDir.path);
|
||||
if (!await configDir.exists()) {
|
||||
await configDir.create(recursive: true);
|
||||
}
|
||||
final configFile = File(p.join(configDir.path, 'config.json'));
|
||||
return ConfigRepository(configFile, logger);
|
||||
}
|
||||
|
||||
File get configFile => _configFile;
|
||||
|
||||
Future<AppConfig> loadConfig() async {
|
||||
if (!await _configFile.exists()) {
|
||||
_logger.i('Config not found, using defaults.');
|
||||
return AppConfig.defaults();
|
||||
}
|
||||
try {
|
||||
final contents = await _configFile.readAsString();
|
||||
return AppConfig.fromJson(_decode(contents));
|
||||
} catch (error, stack) {
|
||||
_logger.e('Failed to load config, using defaults.', error: error, stackTrace: stack);
|
||||
return AppConfig.defaults();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> saveConfig(AppConfig config) async {
|
||||
try {
|
||||
await _configFile.writeAsString(AppConfig.prettyPrint(config));
|
||||
_logger.i('Config saved to ${_configFile.path}');
|
||||
} catch (error, stack) {
|
||||
_logger.e('Failed to save config', error: error, stackTrace: stack);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, dynamic> _decode(String raw) {
|
||||
final json = raw.trim().isEmpty ? '{}' : raw;
|
||||
return json.isEmpty ? <String, dynamic>{} : (jsonDecode(json) as Map<String, dynamic>);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import '../domain/models.dart';
|
||||
import 'config_repository.dart';
|
||||
|
||||
class NodeRepository {
|
||||
NodeRepository(this._configRepository);
|
||||
|
||||
final ConfigRepository _configRepository;
|
||||
|
||||
Future<NodeConfig> loadNodeConfig() async {
|
||||
final config = await _configRepository.loadConfig();
|
||||
return config.nodeConfig;
|
||||
}
|
||||
|
||||
Future<void> saveNodeConfig(AppConfig config, NodeConfig nodeConfig) async {
|
||||
await _configRepository.saveConfig(config.copyWith(nodeConfig: nodeConfig));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import '../domain/models.dart';
|
||||
import 'config_repository.dart';
|
||||
|
||||
class SettingsRepository {
|
||||
SettingsRepository(this._configRepository);
|
||||
|
||||
final ConfigRepository _configRepository;
|
||||
|
||||
Future<AppConfig> loadSettings() => _configRepository.loadConfig();
|
||||
|
||||
Future<void> saveSettings(AppConfig config) => _configRepository.saveConfig(config);
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
import '../domain/models.dart';
|
||||
import '../domain/send.dart';
|
||||
import '../domain/transactions.dart';
|
||||
import '../native/wallet_backend.dart';
|
||||
|
||||
class WalletSnapshot {
|
||||
const WalletSnapshot({
|
||||
required this.address,
|
||||
required this.balanceAtomic,
|
||||
required this.unlockedAtomic,
|
||||
required this.nodeHeight,
|
||||
required this.walletHeight,
|
||||
required this.synced,
|
||||
required this.progress,
|
||||
required this.subaddresses,
|
||||
});
|
||||
|
||||
final String address;
|
||||
final int balanceAtomic;
|
||||
final int unlockedAtomic;
|
||||
final int nodeHeight;
|
||||
final int walletHeight;
|
||||
final bool synced;
|
||||
final double progress;
|
||||
final List<SubaddressInfo> subaddresses;
|
||||
}
|
||||
|
||||
class WalletRepository {
|
||||
WalletRepository(this._backend);
|
||||
|
||||
final WalletBackend _backend;
|
||||
Future<void> _operationQueue = Future.value();
|
||||
|
||||
int get maxDestinations => _backend.maxDestinations;
|
||||
|
||||
Future<T> _runLocked<T>(Future<T> Function() action) {
|
||||
final next = _operationQueue.then((_) => action());
|
||||
_operationQueue = next.then((_) => null, onError: (_) => null);
|
||||
return next;
|
||||
}
|
||||
|
||||
Future<void> createWallet({
|
||||
required String name,
|
||||
required String path,
|
||||
required String password,
|
||||
}) {
|
||||
return _runLocked(() {
|
||||
return _backend.createWallet(name: name, path: path, password: password);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> restoreWalletFromSeed({
|
||||
required String name,
|
||||
required String seed,
|
||||
required String path,
|
||||
required String password,
|
||||
}) {
|
||||
return _runLocked(() {
|
||||
return _backend.restoreWalletFromSeed(
|
||||
name: name,
|
||||
seed: seed,
|
||||
path: path,
|
||||
password: password,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> openWallet({
|
||||
required String path,
|
||||
required String password,
|
||||
}) {
|
||||
return _runLocked(() {
|
||||
return _backend.openWallet(path: path, password: password);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> closeWallet() {
|
||||
return _runLocked(() => _backend.closeWallet());
|
||||
}
|
||||
|
||||
Future<String> getAddress() {
|
||||
return _runLocked(() => _backend.getAddress());
|
||||
}
|
||||
|
||||
Future<String> getSeed() {
|
||||
return _runLocked(() => _backend.getSeed());
|
||||
}
|
||||
|
||||
Future<List<WalletTransaction>> getTransactions() {
|
||||
return _runLocked(() => _backend.getTransactions());
|
||||
}
|
||||
|
||||
Future<bool> isConnected() {
|
||||
return _runLocked(() => _backend.isConnected());
|
||||
}
|
||||
|
||||
Future<String> createSubaddress({String? label}) {
|
||||
return _runLocked(() => _backend.createSubaddress(label: label));
|
||||
}
|
||||
|
||||
Future<List<SubaddressInfo>> getSubaddresses() {
|
||||
return _runLocked(() => _backend.getSubaddresses());
|
||||
}
|
||||
|
||||
Future<void> setSubaddressLabel({
|
||||
required int accountIndex,
|
||||
required int addressIndex,
|
||||
required String label,
|
||||
}) {
|
||||
return _runLocked(() {
|
||||
return _backend.setSubaddressLabel(
|
||||
accountIndex: accountIndex,
|
||||
addressIndex: addressIndex,
|
||||
label: label,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Future<SendPreview> prepareSend(SendRequest request) {
|
||||
return _runLocked(() => _backend.prepareSend(request));
|
||||
}
|
||||
|
||||
Future<SendResult> commitPreparedSend() {
|
||||
return _runLocked(() => _backend.commitPreparedSend());
|
||||
}
|
||||
|
||||
Future<void> discardPreparedSend() {
|
||||
return _runLocked(() => _backend.discardPreparedSend());
|
||||
}
|
||||
|
||||
Future<void> connectNode(NodeConfig nodeConfig) {
|
||||
return _runLocked(() => _backend.connectToNode(nodeConfig));
|
||||
}
|
||||
|
||||
Future<WalletSnapshot> refresh() async {
|
||||
return _runLocked(() async {
|
||||
await _backend.refresh();
|
||||
final address = await _backend.getAddress();
|
||||
final balance = await _backend.getBalance();
|
||||
final unlockedBalance = await _backend.getUnlockedBalance();
|
||||
final nodeHeight = await _backend.getNodeHeight();
|
||||
final walletHeight = await _backend.getWalletHeight();
|
||||
final synced = await _backend.isSynced();
|
||||
final progress = await _backend.getSyncProgress();
|
||||
List<SubaddressInfo> subaddresses;
|
||||
try {
|
||||
subaddresses = await _backend.getSubaddresses();
|
||||
} catch (_) {
|
||||
subaddresses = const [];
|
||||
}
|
||||
|
||||
return WalletSnapshot(
|
||||
address: address,
|
||||
balanceAtomic: balance,
|
||||
unlockedAtomic: unlockedBalance,
|
||||
nodeHeight: nodeHeight,
|
||||
walletHeight: walletHeight,
|
||||
synced: synced,
|
||||
progress: progress,
|
||||
subaddresses: subaddresses,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> rescanBlockchain({int? fromHeight}) {
|
||||
return _runLocked(() => _backend.rescanBlockchain(fromHeight: fromHeight));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user