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

View file

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

View file

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

View file

@ -1,8 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:barcode_scan2/barcode_scan2.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:qr_flutter/qr_flutter.dart'; import 'package:qr_flutter/qr_flutter.dart';
import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/steps/frost_route_generator.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/providers/frost_wallet/frost_wallet_providers.dart';
import 'package:stackwallet/services/frost.dart'; import 'package:stackwallet/services/frost.dart';
import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/wallets/isar/models/frost_wallet_info.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/custom_buttons/simple_copy_button.dart';
import 'package:stackwallet/widgets/desktop/primary_button.dart'; import 'package:stackwallet/widgets/desktop/primary_button.dart';
import 'package:stackwallet/widgets/detail_item.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_dialog.dart';
import 'package:stackwallet/widgets/stack_text_field.dart'; import 'package:stackwallet/widgets/textfields/frost_step_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart';
class FrostReshareStep2abd extends ConsumerStatefulWidget { class FrostReshareStep2abd extends ConsumerStatefulWidget {
const FrostReshareStep2abd({super.key}); const FrostReshareStep2abd({super.key});
@ -41,7 +33,7 @@ class _FrostReshareStep2abdState extends ConsumerState<FrostReshareStep2abd> {
final List<TextEditingController> controllers = []; final List<TextEditingController> controllers = [];
final List<FocusNode> focusNodes = []; final List<FocusNode> focusNodes = [];
late final List<int> resharerIndexes; late final Map<String, int> resharers;
late final int myResharerIndexIndex; late final int myResharerIndexIndex;
late final String myResharerStart; late final String myResharerStart;
late final bool amOutgoingParticipant; late final bool amOutgoingParticipant;
@ -67,7 +59,9 @@ class _FrostReshareStep2abdState extends ConsumerState<FrostReshareStep2abd> {
final result = Frost.beginReshared( final result = Frost.beginReshared(
myName: ref.read(pFrostResharingData).myName!, myName: ref.read(pFrostResharingData).myName!,
resharerConfig: ref.read(pFrostResharingData).resharerConfig!, resharerConfig: Frost.decodeRConfig(
ref.read(pFrostResharingData).resharerRConfig!,
),
resharerStarts: resharerStarts, resharerStarts: resharerStarts,
); );
@ -116,11 +110,11 @@ class _FrostReshareStep2abdState extends ConsumerState<FrostReshareStep2abd> {
myResharerStart = myResharerStart =
ref.read(pFrostResharingData).startResharerData!.resharerStart; ref.read(pFrostResharingData).startResharerData!.resharerStart;
resharerIndexes = ref.read(pFrostResharingData).configData!.resharers; resharers = ref.read(pFrostResharingData).configData!.resharers;
myResharerIndexIndex = resharerIndexes.indexOf(myOldIndex); myResharerIndexIndex = resharers.values.toList().indexOf(myOldIndex);
if (myResharerIndexIndex >= 0) { if (myResharerIndexIndex >= 0) {
// remove my name for now as we don't need a text field for it // 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 amOutgoingParticipant = !ref
@ -129,7 +123,7 @@ class _FrostReshareStep2abdState extends ConsumerState<FrostReshareStep2abd> {
.newParticipants .newParticipants
.contains(ref.read(pFrostResharingData).myName!); .contains(ref.read(pFrostResharingData).myName!);
for (int i = 0; i < resharerIndexes.length; i++) { for (int i = 0; i < resharers.length; i++) {
controllers.add(TextEditingController()); controllers.add(TextEditingController());
focusNodes.add(FocusNode()); focusNodes.add(FocusNode());
fieldIsEmptyFlags.add(true); fieldIsEmptyFlags.add(true);
@ -192,137 +186,20 @@ class _FrostReshareStep2abdState extends ConsumerState<FrostReshareStep2abd> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
for (int i = 0; i < resharerIndexes.length; i++) for (int i = 0; i < resharers.length; i++)
Column( FrostStepField(
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], controller: controllers[i],
focusNode: focusNodes[i], focusNode: focusNodes[i],
readOnly: false, showQrScanOption: true,
autocorrect: false, label: resharers.keys.elementAt(i),
enableSuggestions: false, hint: "Enter "
style: STextStyles.field(context), "${resharers.keys.elementAt(i)}"
"'s resharer",
onChanged: (_) { onChanged: (_) {
setState(() { setState(() {
fieldIsEmptyFlags[i] = fieldIsEmptyFlags[i] = controllers[i].text.isEmpty;
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(),
),
],
),
),
),
),
),
),
),
],
), ),
], ],
), ),

View file

@ -1,23 +1,15 @@
import 'dart:async'; import 'dart:async';
import 'package:barcode_scan2/barcode_scan2.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.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/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/providers/frost_wallet/frost_wallet_providers.dart';
import 'package:stackwallet/services/frost.dart'; import 'package:stackwallet/services/frost.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/desktop/primary_button.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_dialog.dart';
import 'package:stackwallet/widgets/stack_text_field.dart'; import 'package:stackwallet/widgets/textfields/frost_step_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart';
class FrostReshareStep2c extends ConsumerStatefulWidget { class FrostReshareStep2c extends ConsumerStatefulWidget {
const FrostReshareStep2c({super.key}); const FrostReshareStep2c({super.key});
@ -33,7 +25,7 @@ class _FrostReshareStep2cState extends ConsumerState<FrostReshareStep2c> {
final List<TextEditingController> controllers = []; final List<TextEditingController> controllers = [];
final List<FocusNode> focusNodes = []; final List<FocusNode> focusNodes = [];
late final List<int> resharerIndexes; late final Map<String, int> resharers;
final List<bool> fieldIsEmptyFlags = []; final List<bool> fieldIsEmptyFlags = [];
@ -50,7 +42,9 @@ class _FrostReshareStep2cState extends ConsumerState<FrostReshareStep2c> {
final result = Frost.beginReshared( final result = Frost.beginReshared(
myName: ref.read(pFrostResharingData).myName!, myName: ref.read(pFrostResharingData).myName!,
resharerConfig: ref.read(pFrostResharingData).resharerConfig!, resharerConfig: Frost.decodeRConfig(
ref.read(pFrostResharingData).resharerRConfig!,
),
resharerStarts: resharerStarts, resharerStarts: resharerStarts,
); );
@ -84,9 +78,9 @@ class _FrostReshareStep2cState extends ConsumerState<FrostReshareStep2c> {
@override @override
void initState() { 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()); controllers.add(TextEditingController());
focusNodes.add(FocusNode()); focusNodes.add(FocusNode());
fieldIsEmptyFlags.add(true); fieldIsEmptyFlags.add(true);
@ -115,137 +109,23 @@ class _FrostReshareStep2cState extends ConsumerState<FrostReshareStep2c> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
for (int i = 0; i < resharerIndexes.length; i++) for (int i = 0; i < resharers.length; i++)
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding( Padding(
padding: const EdgeInsets.symmetric(vertical: 8), padding: const EdgeInsets.symmetric(vertical: 8),
child: ClipRRect( child: FrostStepField(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
child: TextField(
key: Key("frostResharerTextFieldKey_$i"),
controller: controllers[i], controller: controllers[i],
focusNode: focusNodes[i], focusNode: focusNodes[i],
readOnly: false, showQrScanOption: true,
autocorrect: false, label: resharers.keys.elementAt(i),
enableSuggestions: false, hint: "Enter "
style: STextStyles.field(context), "${resharers.keys.elementAt(i)}"
"'s resharer",
onChanged: (_) { onChanged: (_) {
setState(() { setState(() {
fieldIsEmptyFlags[i] = fieldIsEmptyFlags[i] = controllers[i].text.isEmpty;
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(),
),
],
),
),
),
),
),
),
),
],
), ),
], ],
), ),

View file

@ -1,8 +1,6 @@
import 'dart:ffi'; import 'dart:ffi';
import 'package:barcode_scan2/barcode_scan2.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:qr_flutter/qr_flutter.dart'; import 'package:qr_flutter/qr_flutter.dart';
import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/steps/frost_route_generator.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/providers/frost_wallet/frost_wallet_providers.dart';
import 'package:stackwallet/services/frost.dart'; import 'package:stackwallet/services/frost.dart';
import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/wallets/isar/models/frost_wallet_info.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/custom_buttons/simple_copy_button.dart';
import 'package:stackwallet/widgets/desktop/primary_button.dart'; import 'package:stackwallet/widgets/desktop/primary_button.dart';
import 'package:stackwallet/widgets/detail_item.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_dialog.dart';
import 'package:stackwallet/widgets/stack_text_field.dart'; import 'package:stackwallet/widgets/textfields/frost_step_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart';
// was FinishResharingView // was FinishResharingView
class FrostReshareStep4 extends ConsumerStatefulWidget { class FrostReshareStep4 extends ConsumerStatefulWidget {
@ -43,7 +35,7 @@ class _FrostReshareStep4State extends ConsumerState<FrostReshareStep4> {
final List<TextEditingController> controllers = []; final List<TextEditingController> controllers = [];
final List<FocusNode> focusNodes = []; final List<FocusNode> focusNodes = [];
late final List<int> resharerIndexes; late final Map<String, int> resharers;
late final String myName; late final String myName;
late final int? myResharerIndexIndex; late final int? myResharerIndexIndex;
late final String? myResharerComplete; late final String? myResharerComplete;
@ -118,7 +110,7 @@ class _FrostReshareStep4State extends ConsumerState<FrostReshareStep4> {
myName = ref.read(pFrostResharingData).myName!; myName = ref.read(pFrostResharingData).myName!;
resharerIndexes = ref.read(pFrostResharingData).configData!.resharers; resharers = ref.read(pFrostResharingData).configData!.resharers;
if (amNewParticipant) { if (amNewParticipant) {
myResharerComplete = null; myResharerComplete = null;
@ -135,10 +127,10 @@ class _FrostReshareStep4State extends ConsumerState<FrostReshareStep4> {
final myOldIndex = final myOldIndex =
frostInfo.participants.indexOf(ref.read(pFrostResharingData).myName!); frostInfo.participants.indexOf(ref.read(pFrostResharingData).myName!);
myResharerIndexIndex = resharerIndexes.indexOf(myOldIndex); myResharerIndexIndex = resharers.values.toList().indexOf(myOldIndex);
if (myResharerIndexIndex! >= 0) { if (myResharerIndexIndex! >= 0) {
// remove my name for now as we don't need a text field for it // 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 amOutgoingParticipant = !ref
@ -148,7 +140,7 @@ class _FrostReshareStep4State extends ConsumerState<FrostReshareStep4> {
.contains(ref.read(pFrostResharingData).myName!); .contains(ref.read(pFrostResharingData).myName!);
} }
for (int i = 0; i < resharerIndexes.length; i++) { for (int i = 0; i < resharers.length; i++) {
controllers.add(TextEditingController()); controllers.add(TextEditingController());
focusNodes.add(FocusNode()); focusNodes.add(FocusNode());
fieldIsEmptyFlags.add(true); fieldIsEmptyFlags.add(true);
@ -216,139 +208,23 @@ class _FrostReshareStep4State extends ConsumerState<FrostReshareStep4> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
for (int i = 0; i < resharerIndexes.length; i++) for (int i = 0; i < resharers.length; i++)
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding( Padding(
padding: const EdgeInsets.symmetric(vertical: 8), padding: const EdgeInsets.symmetric(vertical: 8),
child: ClipRRect( child: FrostStepField(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
child: TextField(
key: Key("frostEncryptionKeyTextFieldKey_$i"),
controller: controllers[i], controller: controllers[i],
focusNode: focusNodes[i], focusNode: focusNodes[i],
readOnly: false, showQrScanOption: true,
autocorrect: false, label: resharers.keys.elementAt(i),
enableSuggestions: false, hint: "Enter "
style: STextStyles.field(context), "${resharers.keys.elementAt(i)}"
"'s resharer",
onChanged: (_) { onChanged: (_) {
setState(() { setState(() {
fieldIsEmptyFlags[i] = fieldIsEmptyFlags[i] = controllers[i].text.isEmpty;
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(),
),
],
),
),
),
),
),
),
),
],
), ),
], ],
), ),

View file

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

View file

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

View file

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

View file

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

View file

@ -1,3 +1,4 @@
import 'dart:convert';
import 'dart:ffi'; import 'dart:ffi';
import 'dart:typed_data'; import 'dart:typed_data';
@ -551,11 +552,14 @@ abstract class Frost {
static ({ static ({
int newThreshold, int newThreshold,
List<int> resharers, Map<String, int> resharers,
List<String> newParticipants, List<String> newParticipants,
}) extractResharerConfigData({ }) extractResharerConfigData({
required String resharerConfig, required String rConfig,
}) { }) {
final decoded = _decodeRConfigWithResharers(rConfig);
final resharerConfig = decoded.config;
try { try {
final newThreshold = resharerNewThreshold( final newThreshold = resharerNewThreshold(
resharerConfigPointer: decodedResharerConfig( 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 ( return (
newThreshold: newThreshold, newThreshold: newThreshold,
resharers: resharers, resharers: resharersMap,
newParticipants: newParticipants, newParticipants: newParticipants,
); );
} catch (e, s) { } catch (e, s) {
@ -610,4 +622,29 @@ abstract class Frost {
rethrow; 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);
}
} }