encode resharer names in resharer config

This commit is contained in:
julian 2024-05-01 10:44:06 -06:00
parent 7455ab55f5
commit 76844a562b
11 changed files with 143 additions and 460 deletions

View file

@ -63,7 +63,9 @@ class _FrostReshareStep1aState extends ConsumerState<FrostReshareStep1a> {
if (mounted) {
final result = Frost.beginResharer(
serializedKeys: serializedKeys!,
config: ref.read(pFrostResharingData).resharerConfig!,
config: Frost.decodeRConfig(
ref.read(pFrostResharingData).resharerRConfig!,
),
);
ref.read(pFrostResharingData).startResharerData = result;
@ -216,6 +218,7 @@ class _FrostReshareStep1aState extends ConsumerState<FrostReshareStep1a> {
.read(pFrostResharingData)
.configData!
.resharers
.values
.contains(myOldIndex);
super.initState();
}
@ -236,7 +239,7 @@ class _FrostReshareStep1aState extends ConsumerState<FrostReshareStep1a> {
mainAxisAlignment: MainAxisAlignment.center,
children: [
QrImageView(
data: ref.watch(pFrostResharingData).resharerConfig!,
data: ref.watch(pFrostResharingData).resharerRConfig!,
size: 220,
backgroundColor:
Theme.of(context).extension<StackColors>()!.background,
@ -252,13 +255,13 @@ class _FrostReshareStep1aState extends ConsumerState<FrostReshareStep1a> {
),
DetailItem(
title: "Config",
detail: ref.watch(pFrostResharingData).resharerConfig!,
detail: ref.watch(pFrostResharingData).resharerRConfig!,
button: Util.isDesktop
? IconCopyButton(
data: ref.watch(pFrostResharingData).resharerConfig!,
data: ref.watch(pFrostResharingData).resharerRConfig!,
)
: SimpleCopyButton(
data: ref.watch(pFrostResharingData).resharerConfig!,
data: ref.watch(pFrostResharingData).resharerRConfig!,
),
),
SizedBox(

View file

@ -63,13 +63,16 @@ class _FrostReshareStep1bState extends ConsumerState<FrostReshareStep1b> {
ref.read(pFrostResharingData).reset();
ref.read(pFrostResharingData).myName = frostInfo.myName;
ref.read(pFrostResharingData).resharerConfig = configFieldController.text;
ref.read(pFrostResharingData).resharerRConfig =
configFieldController.text;
String? salt;
try {
salt = Format.uint8listToString(
resharerSalt(
resharerConfig: ref.read(pFrostResharingData).resharerConfig!,
resharerConfig: Frost.decodeRConfig(
ref.read(pFrostResharingData).resharerRConfig!,
),
),
);
} catch (_) {
@ -97,7 +100,9 @@ class _FrostReshareStep1bState extends ConsumerState<FrostReshareStep1b> {
if (mounted) {
final result = Frost.beginResharer(
serializedKeys: serializedKeys!,
config: ref.read(pFrostResharingData).resharerConfig!,
config: Frost.decodeRConfig(
ref.read(pFrostResharingData).resharerRConfig!,
),
);
ref.read(pFrostResharingData).startResharerData = result;

View file

@ -176,7 +176,7 @@ class _FrostReshareStep1cState extends ConsumerState<FrostReshareStep1c> {
ref.read(pFrostResharingData).reset();
ref.read(pFrostResharingData).myName =
myNameFieldController.text;
ref.read(pFrostResharingData).resharerConfig =
ref.read(pFrostResharingData).resharerRConfig =
configFieldController.text;
if (!ref

View file

@ -1,8 +1,6 @@
import 'dart:async';
import 'package:barcode_scan2/barcode_scan2.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:qr_flutter/qr_flutter.dart';
import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/steps/frost_route_generator.dart';
@ -11,20 +9,14 @@ import 'package:stackwallet/providers/db/main_db_provider.dart';
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
import 'package:stackwallet/services/frost.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/wallets/isar/models/frost_wallet_info.dart';
import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart';
import 'package:stackwallet/widgets/desktop/primary_button.dart';
import 'package:stackwallet/widgets/detail_item.dart';
import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart';
import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart';
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
import 'package:stackwallet/widgets/stack_dialog.dart';
import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart';
import 'package:stackwallet/widgets/textfields/frost_step_field.dart';
class FrostReshareStep2abd extends ConsumerStatefulWidget {
const FrostReshareStep2abd({super.key});
@ -41,7 +33,7 @@ class _FrostReshareStep2abdState extends ConsumerState<FrostReshareStep2abd> {
final List<TextEditingController> controllers = [];
final List<FocusNode> focusNodes = [];
late final List<int> resharerIndexes;
late final Map<String, int> resharers;
late final int myResharerIndexIndex;
late final String myResharerStart;
late final bool amOutgoingParticipant;
@ -67,7 +59,9 @@ class _FrostReshareStep2abdState extends ConsumerState<FrostReshareStep2abd> {
final result = Frost.beginReshared(
myName: ref.read(pFrostResharingData).myName!,
resharerConfig: ref.read(pFrostResharingData).resharerConfig!,
resharerConfig: Frost.decodeRConfig(
ref.read(pFrostResharingData).resharerRConfig!,
),
resharerStarts: resharerStarts,
);
@ -116,11 +110,11 @@ class _FrostReshareStep2abdState extends ConsumerState<FrostReshareStep2abd> {
myResharerStart =
ref.read(pFrostResharingData).startResharerData!.resharerStart;
resharerIndexes = ref.read(pFrostResharingData).configData!.resharers;
myResharerIndexIndex = resharerIndexes.indexOf(myOldIndex);
resharers = ref.read(pFrostResharingData).configData!.resharers;
myResharerIndexIndex = resharers.values.toList().indexOf(myOldIndex);
if (myResharerIndexIndex >= 0) {
// remove my name for now as we don't need a text field for it
resharerIndexes.removeAt(myResharerIndexIndex);
resharers.remove(ref.read(pFrostResharingData).myName!);
}
amOutgoingParticipant = !ref
@ -129,7 +123,7 @@ class _FrostReshareStep2abdState extends ConsumerState<FrostReshareStep2abd> {
.newParticipants
.contains(ref.read(pFrostResharingData).myName!);
for (int i = 0; i < resharerIndexes.length; i++) {
for (int i = 0; i < resharers.length; i++) {
controllers.add(TextEditingController());
focusNodes.add(FocusNode());
fieldIsEmptyFlags.add(true);
@ -192,137 +186,20 @@ class _FrostReshareStep2abdState extends ConsumerState<FrostReshareStep2abd> {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
for (int i = 0; i < resharerIndexes.length; i++)
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: ClipRRect(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
child: TextField(
key: Key("frostResharerTextFieldKey_$i"),
controller: controllers[i],
focusNode: focusNodes[i],
readOnly: false,
autocorrect: false,
enableSuggestions: false,
style: STextStyles.field(context),
onChanged: (_) {
setState(() {
fieldIsEmptyFlags[i] =
controllers[i].text.isEmpty;
});
},
decoration: standardInputDecoration(
"Enter index "
"${resharerIndexes[i]}"
"'s resharer",
focusNodes[i],
context,
).copyWith(
contentPadding: const EdgeInsets.only(
left: 16,
top: 6,
bottom: 8,
right: 5,
),
suffixIcon: Padding(
padding: fieldIsEmptyFlags[i]
? const EdgeInsets.only(right: 8)
: const EdgeInsets.only(right: 0),
child: UnconstrainedBox(
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceAround,
children: [
!fieldIsEmptyFlags[i]
? TextFieldIconButton(
semanticsLabel:
"Clear Button. Clears The Resharer Field Input.",
key: Key(
"frostResharerClearButtonKey_$i"),
onTap: () {
controllers[i].text = "";
setState(() {
fieldIsEmptyFlags[i] = true;
});
},
child: const XIcon(),
)
: TextFieldIconButton(
semanticsLabel:
"Paste Button. Pastes From Clipboard To Resharer Field Input.",
key: Key(
"frostResharerPasteButtonKey_$i"),
onTap: () async {
final ClipboardData? data =
await Clipboard.getData(
Clipboard.kTextPlain);
if (data?.text != null &&
data!.text!.isNotEmpty) {
controllers[i].text =
data.text!.trim();
}
setState(() {
fieldIsEmptyFlags[i] =
controllers[i].text.isEmpty;
});
},
child: fieldIsEmptyFlags[i]
? const ClipboardIcon()
: const XIcon(),
),
if (fieldIsEmptyFlags[i])
TextFieldIconButton(
semanticsLabel: "Scan QR Button. "
"Opens Camera For Scanning QR Code.",
key: Key(
"frostCommitmentsScanQrButtonKey_$i"),
onTap: () async {
try {
if (FocusScope.of(context)
.hasFocus) {
FocusScope.of(context).unfocus();
await Future<void>.delayed(
const Duration(
milliseconds: 75));
}
final qrResult =
await BarcodeScanner.scan();
controllers[i].text =
qrResult.rawContent;
setState(() {
fieldIsEmptyFlags[i] =
controllers[i].text.isEmpty;
});
} on PlatformException catch (e, s) {
Logging.instance.log(
"Failed to get camera permissions "
"while trying to scan qr code: $e\n$s",
level: LogLevel.Warning,
);
}
},
child: const QrCodeIcon(),
),
],
),
),
),
),
),
),
),
],
for (int i = 0; i < resharers.length; i++)
FrostStepField(
controller: controllers[i],
focusNode: focusNodes[i],
showQrScanOption: true,
label: resharers.keys.elementAt(i),
hint: "Enter "
"${resharers.keys.elementAt(i)}"
"'s resharer",
onChanged: (_) {
setState(() {
fieldIsEmptyFlags[i] = controllers[i].text.isEmpty;
});
},
),
],
),

View file

@ -1,23 +1,15 @@
import 'dart:async';
import 'package:barcode_scan2/barcode_scan2.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/steps/frost_route_generator.dart';
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
import 'package:stackwallet/services/frost.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/desktop/primary_button.dart';
import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart';
import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart';
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
import 'package:stackwallet/widgets/stack_dialog.dart';
import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart';
import 'package:stackwallet/widgets/textfields/frost_step_field.dart';
class FrostReshareStep2c extends ConsumerStatefulWidget {
const FrostReshareStep2c({super.key});
@ -33,7 +25,7 @@ class _FrostReshareStep2cState extends ConsumerState<FrostReshareStep2c> {
final List<TextEditingController> controllers = [];
final List<FocusNode> focusNodes = [];
late final List<int> resharerIndexes;
late final Map<String, int> resharers;
final List<bool> fieldIsEmptyFlags = [];
@ -50,7 +42,9 @@ class _FrostReshareStep2cState extends ConsumerState<FrostReshareStep2c> {
final result = Frost.beginReshared(
myName: ref.read(pFrostResharingData).myName!,
resharerConfig: ref.read(pFrostResharingData).resharerConfig!,
resharerConfig: Frost.decodeRConfig(
ref.read(pFrostResharingData).resharerRConfig!,
),
resharerStarts: resharerStarts,
);
@ -84,9 +78,9 @@ class _FrostReshareStep2cState extends ConsumerState<FrostReshareStep2c> {
@override
void initState() {
resharerIndexes = ref.read(pFrostResharingData).configData!.resharers;
resharers = ref.read(pFrostResharingData).configData!.resharers;
for (int i = 0; i < resharerIndexes.length; i++) {
for (int i = 0; i < resharers.length; i++) {
controllers.add(TextEditingController());
focusNodes.add(FocusNode());
fieldIsEmptyFlags.add(true);
@ -115,137 +109,23 @@ class _FrostReshareStep2cState extends ConsumerState<FrostReshareStep2c> {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
for (int i = 0; i < resharerIndexes.length; i++)
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: ClipRRect(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
child: TextField(
key: Key("frostResharerTextFieldKey_$i"),
controller: controllers[i],
focusNode: focusNodes[i],
readOnly: false,
autocorrect: false,
enableSuggestions: false,
style: STextStyles.field(context),
onChanged: (_) {
setState(() {
fieldIsEmptyFlags[i] =
controllers[i].text.isEmpty;
});
},
decoration: standardInputDecoration(
"Enter index "
"${resharerIndexes[i]}"
"'s resharer",
focusNodes[i],
context,
).copyWith(
contentPadding: const EdgeInsets.only(
left: 16,
top: 6,
bottom: 8,
right: 5,
),
suffixIcon: Padding(
padding: fieldIsEmptyFlags[i]
? const EdgeInsets.only(right: 8)
: const EdgeInsets.only(right: 0),
child: UnconstrainedBox(
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceAround,
children: [
!fieldIsEmptyFlags[i]
? TextFieldIconButton(
semanticsLabel:
"Clear Button. Clears The Resharer Field Input.",
key: Key(
"frostResharerClearButtonKey_$i"),
onTap: () {
controllers[i].text = "";
setState(() {
fieldIsEmptyFlags[i] = true;
});
},
child: const XIcon(),
)
: TextFieldIconButton(
semanticsLabel:
"Paste Button. Pastes From Clipboard To Resharer Field Input.",
key: Key(
"frostResharerPasteButtonKey_$i"),
onTap: () async {
final ClipboardData? data =
await Clipboard.getData(
Clipboard.kTextPlain);
if (data?.text != null &&
data!.text!.isNotEmpty) {
controllers[i].text =
data.text!.trim();
}
setState(() {
fieldIsEmptyFlags[i] =
controllers[i].text.isEmpty;
});
},
child: fieldIsEmptyFlags[i]
? const ClipboardIcon()
: const XIcon(),
),
if (fieldIsEmptyFlags[i])
TextFieldIconButton(
semanticsLabel: "Scan QR Button. "
"Opens Camera For Scanning QR Code.",
key: Key(
"frostCommitmentsScanQrButtonKey_$i"),
onTap: () async {
try {
if (FocusScope.of(context)
.hasFocus) {
FocusScope.of(context).unfocus();
await Future<void>.delayed(
const Duration(
milliseconds: 75));
}
final qrResult =
await BarcodeScanner.scan();
controllers[i].text =
qrResult.rawContent;
setState(() {
fieldIsEmptyFlags[i] =
controllers[i].text.isEmpty;
});
} on PlatformException catch (e, s) {
Logging.instance.log(
"Failed to get camera permissions "
"while trying to scan qr code: $e\n$s",
level: LogLevel.Warning,
);
}
},
child: const QrCodeIcon(),
),
],
),
),
),
),
),
),
),
],
for (int i = 0; i < resharers.length; i++)
Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: FrostStepField(
controller: controllers[i],
focusNode: focusNodes[i],
showQrScanOption: true,
label: resharers.keys.elementAt(i),
hint: "Enter "
"${resharers.keys.elementAt(i)}"
"'s resharer",
onChanged: (_) {
setState(() {
fieldIsEmptyFlags[i] = controllers[i].text.isEmpty;
});
},
),
),
],
),

View file

@ -1,8 +1,6 @@
import 'dart:ffi';
import 'package:barcode_scan2/barcode_scan2.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:qr_flutter/qr_flutter.dart';
import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/steps/frost_route_generator.dart';
@ -13,20 +11,14 @@ import 'package:stackwallet/providers/db/main_db_provider.dart';
import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
import 'package:stackwallet/services/frost.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/wallets/isar/models/frost_wallet_info.dart';
import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart';
import 'package:stackwallet/widgets/desktop/primary_button.dart';
import 'package:stackwallet/widgets/detail_item.dart';
import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart';
import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart';
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
import 'package:stackwallet/widgets/stack_dialog.dart';
import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart';
import 'package:stackwallet/widgets/textfields/frost_step_field.dart';
// was FinishResharingView
class FrostReshareStep4 extends ConsumerStatefulWidget {
@ -43,7 +35,7 @@ class _FrostReshareStep4State extends ConsumerState<FrostReshareStep4> {
final List<TextEditingController> controllers = [];
final List<FocusNode> focusNodes = [];
late final List<int> resharerIndexes;
late final Map<String, int> resharers;
late final String myName;
late final int? myResharerIndexIndex;
late final String? myResharerComplete;
@ -118,7 +110,7 @@ class _FrostReshareStep4State extends ConsumerState<FrostReshareStep4> {
myName = ref.read(pFrostResharingData).myName!;
resharerIndexes = ref.read(pFrostResharingData).configData!.resharers;
resharers = ref.read(pFrostResharingData).configData!.resharers;
if (amNewParticipant) {
myResharerComplete = null;
@ -135,10 +127,10 @@ class _FrostReshareStep4State extends ConsumerState<FrostReshareStep4> {
final myOldIndex =
frostInfo.participants.indexOf(ref.read(pFrostResharingData).myName!);
myResharerIndexIndex = resharerIndexes.indexOf(myOldIndex);
myResharerIndexIndex = resharers.values.toList().indexOf(myOldIndex);
if (myResharerIndexIndex! >= 0) {
// remove my name for now as we don't need a text field for it
resharerIndexes.removeAt(myResharerIndexIndex!);
resharers.remove(ref.read(pFrostResharingData).myName!);
}
amOutgoingParticipant = !ref
@ -148,7 +140,7 @@ class _FrostReshareStep4State extends ConsumerState<FrostReshareStep4> {
.contains(ref.read(pFrostResharingData).myName!);
}
for (int i = 0; i < resharerIndexes.length; i++) {
for (int i = 0; i < resharers.length; i++) {
controllers.add(TextEditingController());
focusNodes.add(FocusNode());
fieldIsEmptyFlags.add(true);
@ -216,139 +208,23 @@ class _FrostReshareStep4State extends ConsumerState<FrostReshareStep4> {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
for (int i = 0; i < resharerIndexes.length; i++)
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: ClipRRect(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
child: TextField(
key: Key("frostEncryptionKeyTextFieldKey_$i"),
controller: controllers[i],
focusNode: focusNodes[i],
readOnly: false,
autocorrect: false,
enableSuggestions: false,
style: STextStyles.field(context),
onChanged: (_) {
setState(() {
fieldIsEmptyFlags[i] =
controllers[i].text.isEmpty;
});
},
decoration: standardInputDecoration(
"Enter index "
"${resharerIndexes[i]}"
"'s resharer complete",
focusNodes[i],
context,
).copyWith(
contentPadding: const EdgeInsets.only(
left: 16,
top: 6,
bottom: 8,
right: 5,
),
suffixIcon: Padding(
padding: fieldIsEmptyFlags[i]
? const EdgeInsets.only(right: 8)
: const EdgeInsets.only(right: 0),
child: UnconstrainedBox(
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceAround,
children: [
!fieldIsEmptyFlags[i]
? TextFieldIconButton(
semanticsLabel:
"Clear Button. Clears The Encryption Key Field Input.",
key: Key(
"frostEncryptionKeyClearButtonKey_$i"),
onTap: () {
controllers[i].text = "";
setState(() {
fieldIsEmptyFlags[i] = true;
});
},
child: const XIcon(),
)
: TextFieldIconButton(
semanticsLabel:
"Paste Button. Pastes From Clipboard To Encryption Key Field Input.",
key: Key(
"frostEncryptionKeyPasteButtonKey_$i"),
onTap: () async {
final ClipboardData? data =
await Clipboard.getData(
Clipboard.kTextPlain);
if (data?.text != null &&
data!.text!.isNotEmpty) {
controllers[i].text =
data.text!.trim();
}
setState(() {
fieldIsEmptyFlags[i] =
controllers[i]
.text
.isEmpty;
});
},
child: fieldIsEmptyFlags[i]
? const ClipboardIcon()
: const XIcon(),
),
if (fieldIsEmptyFlags[i])
TextFieldIconButton(
semanticsLabel: "Scan QR Button. "
"Opens Camera For Scanning QR Code.",
key: Key("frostScanQrButtonKey_$i"),
onTap: () async {
try {
if (FocusScope.of(context)
.hasFocus) {
FocusScope.of(context)
.unfocus();
await Future<void>.delayed(
const Duration(
milliseconds: 75));
}
final qrResult =
await BarcodeScanner.scan();
controllers[i].text =
qrResult.rawContent;
setState(() {
fieldIsEmptyFlags[i] =
controllers[i].text.isEmpty;
});
} on PlatformException catch (e, s) {
Logging.instance.log(
"Failed to get camera permissions "
"while trying to scan qr code: $e\n$s",
level: LogLevel.Warning,
);
}
},
child: const QrCodeIcon(),
),
],
),
),
),
),
),
),
),
],
for (int i = 0; i < resharers.length; i++)
Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: FrostStepField(
controller: controllers[i],
focusNode: focusNodes[i],
showQrScanOption: true,
label: resharers.keys.elementAt(i),
hint: "Enter "
"${resharers.keys.elementAt(i)}"
"'s resharer",
onChanged: (_) {
setState(() {
fieldIsEmptyFlags[i] = controllers[i].text.isEmpty;
});
},
),
),
],
),

View file

@ -37,7 +37,7 @@ final class CompleteReshareConfigView extends ConsumerStatefulWidget {
static const String routeName = "/completeReshareConfigView";
final String walletId;
final List<int> resharers;
final Map<String, int> resharers;
@override
ConsumerState<CompleteReshareConfigView> createState() =>
@ -91,7 +91,7 @@ class _CompleteReshareConfigViewState
final config = Frost.createResharerConfig(
newThreshold: int.parse(_newThresholdController.text),
resharers: widget.resharers,
resharers: widget.resharers.values.toList(),
newParticipants: newParticipants,
);
@ -121,7 +121,10 @@ class _CompleteReshareConfigViewState
}
ref.read(pFrostResharingData).myName = myName;
ref.read(pFrostResharingData).resharerConfig = config;
ref.read(pFrostResharingData).resharerRConfig = Frost.encodeRConfig(
config,
widget.resharers,
);
final wallet =
ref.read(pWallets).getWallet(widget.walletId) as BitcoinFrostWallet;

View file

@ -234,10 +234,11 @@ class _BeginReshareConfigViewState
onPressed: () async {
// include self now
selectedParticipants.add(myName);
final List<int> resharers = [];
final Map<String, int> resharers = {};
for (final name in selectedParticipants) {
resharers.add(originalParticipants.indexOf(name));
resharers[name] = originalParticipants.indexOf(name);
}
await Navigator.of(context).pushNamed(

View file

@ -60,13 +60,14 @@ class _ResharingData {
IncompleteFrostWallet? incompleteWallet;
// resharer encoded config string
String? resharerConfig;
String? resharerRConfig;
({
int newThreshold,
List<int> resharers,
Map<String, int> resharers,
List<String> newParticipants,
})? get configData => resharerConfig != null
? Frost.extractResharerConfigData(resharerConfig: resharerConfig!)
})? get configData => resharerRConfig != null
? Frost.extractResharerConfigData(rConfig: resharerRConfig!)
: null;
// resharer start string (for sharing) and machine
@ -93,7 +94,7 @@ class _ResharingData {
// reset/clear all data
void reset() {
resharerConfig = null;
resharerRConfig = null;
startResharerData = null;
startResharedData = null;
resharerComplete = null;

View file

@ -542,7 +542,7 @@ class RouteGenerator {
return _routeError("${settings.name} invalid args: ${args.toString()}");
case CompleteReshareConfigView.routeName:
if (args is ({String walletId, List<int> resharers})) {
if (args is ({String walletId, Map<String, int> resharers})) {
return getRoute(
shouldUseMaterialRoute: useMaterialPageRoute,
builder: (_) => CompleteReshareConfigView(

View file

@ -1,3 +1,4 @@
import 'dart:convert';
import 'dart:ffi';
import 'dart:typed_data';
@ -551,11 +552,14 @@ abstract class Frost {
static ({
int newThreshold,
List<int> resharers,
Map<String, int> resharers,
List<String> newParticipants,
}) extractResharerConfigData({
required String resharerConfig,
required String rConfig,
}) {
final decoded = _decodeRConfigWithResharers(rConfig);
final resharerConfig = decoded.config;
try {
final newThreshold = resharerNewThreshold(
resharerConfigPointer: decodedResharerConfig(
@ -597,9 +601,17 @@ abstract class Frost {
);
}
final Map<String, int> resharersMap = {};
for (final resharer in resharers) {
resharersMap[decoded.resharers.entries
.firstWhere((e) => e.value == resharer)
.key] = resharer;
}
return (
newThreshold: newThreshold,
resharers: resharers,
resharers: resharersMap,
newParticipants: newParticipants,
);
} catch (e, s) {
@ -610,4 +622,29 @@ abstract class Frost {
rethrow;
}
}
static String encodeRConfig(
String config,
Map<String, int> resharers,
) {
return base64Encode("$config@${jsonEncode(resharers)}".toUint8ListFromUtf8);
}
static String decodeRConfig(
String rConfig,
) {
return base64Decode(rConfig).toUtf8String.split("@").first;
}
static ({Map<String, int> resharers, String config})
_decodeRConfigWithResharers(
String rConfig,
) {
final parts = base64Decode(rConfig).toUtf8String.split("@");
final config = parts[0];
final resharers = Map<String, int>.from(jsonDecode(parts[1]) as Map);
return (resharers: resharers, config: config);
}
}