add persistent fusion server prefs

This commit is contained in:
julian 2023-10-16 15:04:27 -06:00
parent a4c1814224
commit c54b4d39d3
4 changed files with 262 additions and 61 deletions

View file

@ -17,6 +17,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/pages/cashfusion/fusion_rounds_selection_sheet.dart';
import 'package:stackwallet/providers/cash_fusion/fusion_progress_ui_state_provider.dart';
import 'package:stackwallet/providers/global/prefs_provider.dart';
import 'package:stackwallet/providers/global/wallets_provider.dart';
import 'package:stackwallet/services/mixins/fusion_wallet_interface.dart';
import 'package:stackwallet/themes/stack_colors.dart';
@ -49,6 +50,8 @@ class _CashFusionViewState extends ConsumerState<CashFusionView> {
late final FocusNode serverFocusNode;
late final TextEditingController portController;
late final FocusNode portFocusNode;
late final TextEditingController fusionRoundController;
late final FocusNode fusionRoundFocusNode;
bool _enableSSLCheckbox = false;
bool _enableStartButton = false;
@ -59,11 +62,18 @@ class _CashFusionViewState extends ConsumerState<CashFusionView> {
void initState() {
serverController = TextEditingController();
portController = TextEditingController();
fusionRoundController = TextEditingController();
serverFocusNode = FocusNode();
portFocusNode = FocusNode();
fusionRoundFocusNode = FocusNode();
// TODO set controller text values to saved info
final info = ref.read(prefsChangeNotifierProvider).fusionServerInfo;
serverController.text = info.host;
portController.text = info.port.toString();
_enableSSLCheckbox = info.ssl;
_option = info.rounds == 0 ? FusionOption.continuous : FusionOption.custom;
fusionRoundController.text = info.rounds.toString();
_enableStartButton =
serverController.text.isNotEmpty && portController.text.isNotEmpty;
@ -75,9 +85,11 @@ class _CashFusionViewState extends ConsumerState<CashFusionView> {
void dispose() {
serverController.dispose();
portController.dispose();
fusionRoundController.dispose();
serverFocusNode.dispose();
portFocusNode.dispose();
fusionRoundFocusNode.dispose();
super.dispose();
}
@ -166,8 +178,9 @@ class _CashFusionViewState extends ConsumerState<CashFusionView> {
focusNode: serverFocusNode,
onChanged: (value) {
setState(() {
_enableStartButton = value.isNotEmpty &
portController.text.isNotEmpty;
_enableStartButton = value.isNotEmpty &&
portController.text.isNotEmpty &&
fusionRoundController.text.isNotEmpty;
});
},
style: STextStyles.field(context),
@ -197,8 +210,9 @@ class _CashFusionViewState extends ConsumerState<CashFusionView> {
keyboardType: TextInputType.number,
onChanged: (value) {
setState(() {
_enableStartButton = value.isNotEmpty &
serverController.text.isNotEmpty;
_enableStartButton = value.isNotEmpty &&
serverController.text.isNotEmpty &&
fusionRoundController.text.isNotEmpty;
});
},
style: STextStyles.field(context),
@ -311,6 +325,40 @@ class _CashFusionViewState extends ConsumerState<CashFusionView> {
),
),
),
if (_option == FusionOption.custom)
const SizedBox(
height: 10,
),
if (_option == FusionOption.custom)
ClipRRect(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
child: TextField(
autocorrect: false,
enableSuggestions: false,
controller: fusionRoundController,
focusNode: fusionRoundFocusNode,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly
],
keyboardType: TextInputType.number,
onChanged: (value) {
setState(() {
_enableStartButton = value.isNotEmpty &&
serverController.text.isNotEmpty &&
portController.text.isNotEmpty;
});
},
style: STextStyles.field(context),
decoration: standardInputDecoration(
"Number of fusions",
fusionRoundFocusNode,
context,
).copyWith(
labelText: "Enter number of fusions.."),
),
),
const SizedBox(
height: 16,
),
@ -336,12 +384,28 @@ class _CashFusionViewState extends ConsumerState<CashFusionView> {
}
}
unawaited(fusionWallet.fuse(
serverHost: serverController.text,
serverPort: int.parse(portController.text),
serverSsl: _enableSSLCheckbox,
roundCount: 0, // TODO update fusion rounds.
));
final int rounds =
_option == FusionOption.continuous
? 0
: int.parse(fusionRoundController.text);
final newInfo = FusionInfo(
host: serverController.text,
port: int.parse(portController.text),
ssl: _enableSSLCheckbox,
rounds: rounds,
);
// update user prefs (persistent)
ref
.read(prefsChangeNotifierProvider)
.fusionServerInfo = newInfo;
unawaited(
fusionWallet.fuse(
fusionInfo: newInfo,
),
);
// TODO: navigate to progress screen
},

View file

@ -20,8 +20,8 @@ import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/pages/cashfusion/fusion_rounds_selection_sheet.dart';
import 'package:stackwallet/pages_desktop_specific/cashfusion/sub_widgets/fusion_dialog.dart';
import 'package:stackwallet/providers/cash_fusion/fusion_progress_ui_state_provider.dart';
import 'package:stackwallet/providers/global/prefs_provider.dart';
import 'package:stackwallet/providers/global/wallets_provider.dart';
import 'package:stackwallet/providers/ui/check_box_state_provider.dart';
import 'package:stackwallet/services/mixins/fusion_wallet_interface.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/utilities/assets.dart';
@ -58,9 +58,8 @@ class _DesktopCashFusion extends ConsumerState<DesktopCashFusionView> {
late final TextEditingController fusionRoundController;
late final FocusNode fusionRoundFocusNode;
String _fusionRoundTerm = "";
bool _enableStartButton = false;
bool _enableSSLCheckbox = false;
FusionOption _roundType = FusionOption.continuous;
@ -74,7 +73,13 @@ class _DesktopCashFusion extends ConsumerState<DesktopCashFusionView> {
portFocusNode = FocusNode();
fusionRoundFocusNode = FocusNode();
// TODO set controller text values to saved info
final info = ref.read(prefsChangeNotifierProvider).fusionServerInfo;
serverController.text = info.host;
portController.text = info.port.toString();
_enableSSLCheckbox = info.ssl;
_roundType =
info.rounds == 0 ? FusionOption.continuous : FusionOption.custom;
fusionRoundController.text = info.rounds.toString();
_enableStartButton =
serverController.text.isNotEmpty && portController.text.isNotEmpty;
@ -285,25 +290,25 @@ class _DesktopCashFusion extends ConsumerState<DesktopCashFusionView> {
Constants.size.circularBorderRadius,
),
child: TextField(
autocorrect: false,
enableSuggestions: false,
controller: serverController,
focusNode: serverFocusNode,
onChanged: (value) {
setState(() {
_enableStartButton = value.isNotEmpty &
portController.text.isNotEmpty;
});
},
style: STextStyles.field(context),
decoration: standardInputDecoration(
"Server",
serverFocusNode,
context,
desktopMed: true,
)
// .copyWith(labelStyle: ),
),
autocorrect: false,
enableSuggestions: false,
controller: serverController,
focusNode: serverFocusNode,
onChanged: (value) {
setState(() {
_enableStartButton = value.isNotEmpty &&
portController.text.isNotEmpty &&
fusionRoundController.text.isNotEmpty;
});
},
style: STextStyles.field(context),
decoration: standardInputDecoration(
"Server",
serverFocusNode,
context,
desktopMed: true,
),
),
),
const SizedBox(
height: 12,
@ -322,8 +327,9 @@ class _DesktopCashFusion extends ConsumerState<DesktopCashFusionView> {
],
onChanged: (value) {
setState(() {
_enableStartButton = value.isNotEmpty &
serverController.text.isNotEmpty;
_enableStartButton = value.isNotEmpty &&
serverController.text.isNotEmpty &&
fusionRoundController.text.isNotEmpty;
});
},
style: STextStyles.field(context),
@ -340,10 +346,9 @@ class _DesktopCashFusion extends ConsumerState<DesktopCashFusionView> {
),
GestureDetector(
onTap: () {
final value =
ref.read(checkBoxStateProvider.state).state;
ref.read(checkBoxStateProvider.state).state =
!value;
setState(() {
_enableSSLCheckbox = !_enableSSLCheckbox;
});
},
child: Container(
color: Colors.transparent,
@ -355,13 +360,14 @@ class _DesktopCashFusion extends ConsumerState<DesktopCashFusionView> {
child: Checkbox(
materialTapTargetSize:
MaterialTapTargetSize.shrinkWrap,
value: ref
.watch(checkBoxStateProvider.state)
.state,
value: _enableSSLCheckbox,
onChanged: (newValue) {
ref
.watch(checkBoxStateProvider.state)
.state = newValue!;
setState(
() {
_enableSSLCheckbox =
!_enableSSLCheckbox;
},
);
},
),
),
@ -464,14 +470,21 @@ class _DesktopCashFusion extends ConsumerState<DesktopCashFusionView> {
enableSuggestions: false,
controller: fusionRoundController,
focusNode: fusionRoundFocusNode,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly
],
onChanged: (value) {
setState(() {
_fusionRoundTerm = value;
_enableStartButton = value
.isNotEmpty &&
serverController
.text.isNotEmpty &&
portController.text.isNotEmpty;
});
},
style: STextStyles.field(context),
decoration: standardInputDecoration(
"",
"Number of fusions",
fusionRoundFocusNode,
context,
desktopMed: true,
@ -507,12 +520,28 @@ class _DesktopCashFusion extends ConsumerState<DesktopCashFusionView> {
}
}
unawaited(fusionWallet.fuse(
serverHost: serverController.text,
serverPort: int.parse(portController.text),
serverSsl: ref.read(checkBoxStateProvider),
roundCount: 0, // TODO update fusion rounds.
));
final int rounds =
_roundType == FusionOption.continuous
? 0
: int.parse(fusionRoundController.text);
final newInfo = FusionInfo(
host: serverController.text,
port: int.parse(portController.text),
ssl: _enableSSLCheckbox,
rounds: rounds,
);
// update user prefs (persistent)
ref
.read(prefsChangeNotifierProvider)
.fusionServerInfo = newInfo;
unawaited(
fusionWallet.fuse(
fusionInfo: newInfo,
),
);
// unawaited(fusionWallet.stepThruUiStates());
await showDialog<void>(

View file

@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
@ -19,6 +20,77 @@ import 'package:stackwallet/utilities/stack_file_system.dart';
const String kReservedFusionAddress = "reserved_fusion_address";
class FusionInfo {
final String host;
final int port;
final bool ssl;
/// set to 0 for continuous
final int rounds;
const FusionInfo({
required this.host,
required this.port,
required this.ssl,
required this.rounds,
}) : assert(rounds >= 0);
// TODO update defaults
static const DEFAULTS = FusionInfo(
host: "cashfusion.stackwallet.com",
port: 8787,
ssl: false,
rounds: 0, // 0 is continuous
);
factory FusionInfo.fromJsonString(String jsonString) {
final json = jsonDecode(jsonString);
return FusionInfo(
host: json['host'] as String,
port: json['port'] as int,
ssl: json['ssl'] as bool,
rounds: json['rounds'] as int,
);
}
String toJsonString() {
return {
'host': host,
'port': port,
'ssl': ssl,
'rounds': rounds,
}.toString();
}
@override
String toString() {
return toJsonString();
}
@override
bool operator ==(Object other) {
if (identical(this, other)) {
return true;
}
return other is FusionInfo &&
other.host == host &&
other.port == port &&
other.ssl == ssl &&
other.rounds == rounds;
}
@override
int get hashCode {
return Object.hash(
host.hashCode,
port.hashCode,
ssl.hashCode,
rounds.hashCode,
);
}
}
/// A mixin for the BitcoinCashWallet class that adds CashFusion functionality.
mixin FusionWalletInterface {
// Passed in wallet data.
@ -292,17 +364,20 @@ mixin FusionWalletInterface {
/// Fuse the wallet's UTXOs.
///
/// This function is called when the user taps the "Fuse" button in the UI.
Future<void> fuse(
{required String serverHost,
required int serverPort,
required bool serverSsl,
required int roundCount}) async {
Future<void> fuse({
required FusionInfo fusionInfo,
}) async {
// Initial attempt for CashFusion integration goes here.
// Use server host and port which ultimately come from text fields.
// TODO validate.
fusion.FusionParams serverParams = fusion.FusionParams(
serverHost: serverHost, serverPort: serverPort, serverSsl: serverSsl, roundCount: roundCount);
serverHost: fusionInfo.host,
serverPort: fusionInfo.port,
serverSsl: fusionInfo.ssl,
);
// TODO use as required. Zero indicates continuous
final roundCount = fusionInfo.rounds;
// Instantiate a Fusion object with custom parameters.
final mainFusionObject = fusion.Fusion(serverParams);

View file

@ -12,6 +12,7 @@ import 'package:flutter/cupertino.dart';
import 'package:stackwallet/db/hive/db.dart';
import 'package:stackwallet/services/event_bus/events/global/tor_status_changed_event.dart';
import 'package:stackwallet/services/event_bus/global_event_bus.dart';
import 'package:stackwallet/services/mixins/fusion_wallet_interface.dart';
import 'package:stackwallet/utilities/amount/amount_unit.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/backup_frequency_type.dart';
@ -64,6 +65,7 @@ class Prefs extends ChangeNotifier {
await _setAmountUnits();
await _setMaxDecimals();
_useTor = await _getUseTor();
_fusionServerInfo = await _getFusionServerInfo();
_initialized = true;
}
@ -931,4 +933,35 @@ class Prefs extends ChangeNotifier {
) as bool? ??
false;
}
// fusion server info
FusionInfo _fusionServerInfo = FusionInfo.DEFAULTS;
FusionInfo get fusionServerInfo => _fusionServerInfo;
set fusionServerInfo(FusionInfo fusionServerInfo) {
if (this.fusionServerInfo != fusionServerInfo) {
DB.instance.put<dynamic>(
boxName: DB.boxNamePrefs,
key: "fusionServerInfo",
value: fusionServerInfo.toJsonString(),
);
_fusionServerInfo = fusionServerInfo;
notifyListeners();
}
}
Future<FusionInfo> _getFusionServerInfo() async {
final saved = await DB.instance.get<dynamic>(
boxName: DB.boxNamePrefs,
key: "fusionServerInfo",
) as String?;
if (saved == null) {
return FusionInfo.DEFAULTS;
} else {
return FusionInfo.fromJsonString(saved);
}
}
}