mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-03-22 15:19:11 +00:00
various frost settings view ui tweaks and fixes
This commit is contained in:
parent
3bddec00f1
commit
a9449ace0d
4 changed files with 456 additions and 42 deletions
|
@ -1,8 +1,11 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:stackwallet/pages/wallet_view/transaction_views/tx_v2/transaction_v2_details_view.dart';
|
||||||
import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
|
import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
|
||||||
import 'package:stackwallet/providers/db/main_db_provider.dart';
|
import 'package:stackwallet/providers/db/main_db_provider.dart';
|
||||||
import 'package:stackwallet/themes/stack_colors.dart';
|
import 'package:stackwallet/themes/stack_colors.dart';
|
||||||
|
import 'package:stackwallet/utilities/assets.dart';
|
||||||
import 'package:stackwallet/utilities/text_styles.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';
|
||||||
|
@ -11,6 +14,7 @@ import 'package:stackwallet/widgets/conditional_parent.dart';
|
||||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
|
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
||||||
|
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||||
|
|
||||||
class FrostParticipantsView extends ConsumerWidget {
|
class FrostParticipantsView extends ConsumerWidget {
|
||||||
const FrostParticipantsView({
|
const FrostParticipantsView({
|
||||||
|
@ -84,31 +88,56 @@ class FrostParticipantsView extends ConsumerWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: Util.isDesktop
|
||||||
|
? CrossAxisAlignment.start
|
||||||
|
: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
for (int i = 0; i < frostInfo.participants.length; i++)
|
for (int i = 0; i < frostInfo.participants.length; i++)
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
vertical: 8,
|
vertical: 5,
|
||||||
),
|
),
|
||||||
child: Column(
|
child: RoundedWhiteContainer(
|
||||||
mainAxisSize: MainAxisSize.min,
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
children: [
|
||||||
children: [
|
Container(
|
||||||
Text(
|
width: 26,
|
||||||
"Index $i",
|
height: 26,
|
||||||
style: STextStyles.label(context),
|
decoration: BoxDecoration(
|
||||||
),
|
color: Theme.of(context)
|
||||||
const SizedBox(
|
.extension<StackColors>()!
|
||||||
height: 6,
|
.textFieldActiveBG,
|
||||||
),
|
borderRadius: BorderRadius.circular(
|
||||||
SelectableText(
|
200,
|
||||||
frostInfo.participants[i] == frostInfo.myName
|
),
|
||||||
? "${frostInfo.participants[i]} (me)"
|
),
|
||||||
: frostInfo.participants[i],
|
child: Center(
|
||||||
style: STextStyles.itemSubtitle12(context),
|
child: SvgPicture.asset(
|
||||||
),
|
Assets.svg.user,
|
||||||
],
|
width: 16,
|
||||||
|
height: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 8,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
frostInfo.participants[i] == frostInfo.myName
|
||||||
|
? "${frostInfo.participants[i]} (me)"
|
||||||
|
: frostInfo.participants[i],
|
||||||
|
style: STextStyles.w500_14(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 8,
|
||||||
|
),
|
||||||
|
IconCopyButton(
|
||||||
|
data: frostInfo.participants[i],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
@ -19,6 +21,7 @@ import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
|
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||||
|
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||||
import 'package:stackwallet/widgets/stack_dialog.dart';
|
import 'package:stackwallet/widgets/stack_dialog.dart';
|
||||||
|
|
||||||
final class CompleteReshareConfigView extends ConsumerStatefulWidget {
|
final class CompleteReshareConfigView extends ConsumerStatefulWidget {
|
||||||
|
@ -45,9 +48,12 @@ class _CompleteReshareConfigViewState
|
||||||
|
|
||||||
final List<TextEditingController> controllers = [];
|
final List<TextEditingController> controllers = [];
|
||||||
|
|
||||||
|
late final String myName;
|
||||||
|
|
||||||
int _participantsCount = 0;
|
int _participantsCount = 0;
|
||||||
|
|
||||||
bool _buttonLock = false;
|
bool _buttonLock = false;
|
||||||
|
bool _includeMeInReshare = false;
|
||||||
|
|
||||||
Future<void> _onPressed() async {
|
Future<void> _onPressed() async {
|
||||||
if (_buttonLock) {
|
if (_buttonLock) {
|
||||||
|
@ -74,10 +80,16 @@ class _CompleteReshareConfigViewState
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final List<String> newParticipants =
|
||||||
|
controllers.map((e) => e.text.trim()).toList();
|
||||||
|
if (_includeMeInReshare) {
|
||||||
|
newParticipants.insert(0, myName);
|
||||||
|
}
|
||||||
|
|
||||||
final config = Frost.createResharerConfig(
|
final config = Frost.createResharerConfig(
|
||||||
newThreshold: int.parse(_newThresholdController.text),
|
newThreshold: int.parse(_newThresholdController.text),
|
||||||
resharers: widget.resharers,
|
resharers: widget.resharers,
|
||||||
newParticipants: controllers.map((e) => e.text).toList(),
|
newParticipants: newParticipants,
|
||||||
);
|
);
|
||||||
|
|
||||||
final salt = Format.uint8listToString(
|
final salt = Format.uint8listToString(
|
||||||
|
@ -105,7 +117,7 @@ class _CompleteReshareConfigViewState
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ref.read(pFrostResharingData).myName = frostInfo.myName;
|
ref.read(pFrostResharingData).myName = myName;
|
||||||
ref.read(pFrostResharingData).resharerConfig = config;
|
ref.read(pFrostResharingData).resharerConfig = config;
|
||||||
|
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
|
@ -152,18 +164,29 @@ class _CompleteReshareConfigViewState
|
||||||
return "At least two participants required";
|
return "At least two participants required";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (controllers.length != partsCount) {
|
final newParticipants = controllers.map((e) => e.text.trim()).toList();
|
||||||
|
|
||||||
|
if (newParticipants.contains(myName)) {
|
||||||
|
return "Using your own name should be done using the checkbox to include"
|
||||||
|
" yourself";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_includeMeInReshare) {
|
||||||
|
newParticipants.add(myName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newParticipants.length != partsCount) {
|
||||||
return "Participants count error";
|
return "Participants count error";
|
||||||
}
|
}
|
||||||
|
|
||||||
final hasEmptyParticipants = controllers
|
final hasEmptyParticipants = newParticipants
|
||||||
.map((e) => e.text.isEmpty)
|
.map((e) => e.trim().isEmpty)
|
||||||
.reduce((value, element) => value |= element);
|
.reduce((value, element) => value |= element);
|
||||||
if (hasEmptyParticipants) {
|
if (hasEmptyParticipants) {
|
||||||
return "Participants must not be empty";
|
return "Participants must not be empty";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (controllers.length != controllers.map((e) => e.text).toSet().length) {
|
if (newParticipants.length != newParticipants.toSet().length) {
|
||||||
return "Duplicate participant name found";
|
return "Duplicate participant name found";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,8 +194,12 @@ class _CompleteReshareConfigViewState
|
||||||
}
|
}
|
||||||
|
|
||||||
void _participantsCountChanged(String newValue) {
|
void _participantsCountChanged(String newValue) {
|
||||||
final count = int.tryParse(newValue);
|
int? count = int.tryParse(newValue);
|
||||||
if (count != null) {
|
if (count != null) {
|
||||||
|
if (_includeMeInReshare) {
|
||||||
|
count = max(0, count - 1);
|
||||||
|
}
|
||||||
|
|
||||||
if (count > _participantsCount) {
|
if (count > _participantsCount) {
|
||||||
for (int i = _participantsCount; i < count; i++) {
|
for (int i = _participantsCount; i < count; i++) {
|
||||||
controllers.add(TextEditingController());
|
controllers.add(TextEditingController());
|
||||||
|
@ -192,6 +219,17 @@ class _CompleteReshareConfigViewState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
final frostInfo = ref
|
||||||
|
.read(mainDBProvider)
|
||||||
|
.isar
|
||||||
|
.frostWalletInfo
|
||||||
|
.getByWalletIdSync(widget.walletId)!;
|
||||||
|
myName = frostInfo.myName;
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_newThresholdController.dispose();
|
_newThresholdController.dispose();
|
||||||
|
@ -231,7 +269,7 @@ class _CompleteReshareConfigViewState
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
"Modify Participants",
|
"Edit group details",
|
||||||
style: STextStyles.navBarTitle(context),
|
style: STextStyles.navBarTitle(context),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -258,11 +296,62 @@ class _CompleteReshareConfigViewState
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: Util.isDesktop
|
||||||
|
? CrossAxisAlignment.start
|
||||||
|
: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
|
const SizedBox(
|
||||||
|
height: 8,
|
||||||
|
),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
_includeMeInReshare = !_includeMeInReshare;
|
||||||
|
});
|
||||||
|
_participantsCountChanged(_newParticipantsCountController.text);
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: 20,
|
||||||
|
height: 26,
|
||||||
|
child: Checkbox(
|
||||||
|
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||||
|
value: _includeMeInReshare,
|
||||||
|
onChanged: (value) {
|
||||||
|
setState(
|
||||||
|
() => _includeMeInReshare = value == true,
|
||||||
|
);
|
||||||
|
_participantsCountChanged(
|
||||||
|
_newParticipantsCountController.text);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 12,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
"I will be a signer in the new config",
|
||||||
|
style: STextStyles.w500_14(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 20,
|
||||||
|
),
|
||||||
Text(
|
Text(
|
||||||
"New threshold",
|
"New threshold",
|
||||||
style: STextStyles.label(context),
|
style: STextStyles.w500_14(context).copyWith(
|
||||||
|
color:
|
||||||
|
Theme.of(context).extension<StackColors>()!.textSubtitle1,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 10,
|
height: 10,
|
||||||
|
@ -271,13 +360,32 @@ class _CompleteReshareConfigViewState
|
||||||
keyboardType: TextInputType.number,
|
keyboardType: TextInputType.number,
|
||||||
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||||||
controller: _newThresholdController,
|
controller: _newThresholdController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: "Enter number of signatures",
|
||||||
|
hintStyle: STextStyles.fieldLabel(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 6,
|
||||||
|
),
|
||||||
|
RoundedWhiteContainer(
|
||||||
|
child: Text(
|
||||||
|
"Enter number of signatures required for fund management.",
|
||||||
|
style: STextStyles.w500_12(context).copyWith(
|
||||||
|
color:
|
||||||
|
Theme.of(context).extension<StackColors>()!.textSubtitle2,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 16,
|
height: 16,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
"Number of participants",
|
"New number of participants",
|
||||||
style: STextStyles.label(context),
|
style: STextStyles.w500_14(context).copyWith(
|
||||||
|
color:
|
||||||
|
Theme.of(context).extension<StackColors>()!.textSubtitle1,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 10,
|
height: 10,
|
||||||
|
@ -287,6 +395,23 @@ class _CompleteReshareConfigViewState
|
||||||
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||||||
controller: _newParticipantsCountController,
|
controller: _newParticipantsCountController,
|
||||||
onChanged: _participantsCountChanged,
|
onChanged: _participantsCountChanged,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: "Enter number of participants",
|
||||||
|
hintStyle: STextStyles.fieldLabel(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 6,
|
||||||
|
),
|
||||||
|
RoundedWhiteContainer(
|
||||||
|
child: Text(
|
||||||
|
"The number of participants must be equal to or less than the"
|
||||||
|
" number of required signatures.",
|
||||||
|
style: STextStyles.w500_12(context).copyWith(
|
||||||
|
color:
|
||||||
|
Theme.of(context).extension<StackColors>()!.textSubtitle2,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 16,
|
height: 16,
|
||||||
|
@ -294,12 +419,26 @@ class _CompleteReshareConfigViewState
|
||||||
if (controllers.isNotEmpty)
|
if (controllers.isNotEmpty)
|
||||||
Text(
|
Text(
|
||||||
"Participants",
|
"Participants",
|
||||||
style: STextStyles.label(context),
|
style: STextStyles.w500_14(context).copyWith(
|
||||||
|
color:
|
||||||
|
Theme.of(context).extension<StackColors>()!.textSubtitle1,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
if (controllers.isNotEmpty)
|
if (controllers.isNotEmpty)
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 10,
|
height: 10,
|
||||||
),
|
),
|
||||||
|
if (controllers.isNotEmpty)
|
||||||
|
RoundedWhiteContainer(
|
||||||
|
child: Text(
|
||||||
|
"Type each name in one word without spaces.",
|
||||||
|
style: STextStyles.w500_12(context).copyWith(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.textSubtitle2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
if (controllers.isNotEmpty)
|
if (controllers.isNotEmpty)
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
|
@ -310,6 +449,10 @@ class _CompleteReshareConfigViewState
|
||||||
),
|
),
|
||||||
child: TextField(
|
child: TextField(
|
||||||
controller: controllers[i],
|
controller: controllers[i],
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: "Enter name",
|
||||||
|
hintStyle: STextStyles.fieldLabel(context),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:qr_flutter/qr_flutter.dart';
|
import 'package:qr_flutter/qr_flutter.dart';
|
||||||
import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_2/begin_resharing_view.dart';
|
import 'package:stackwallet/pages/settings_views/wallet_settings_view/frost_ms/resharing/involved/step_2/begin_resharing_view.dart';
|
||||||
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
|
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
|
||||||
|
@ -8,6 +9,7 @@ import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart';
|
||||||
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
import 'package:stackwallet/providers/global/wallets_provider.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/assets.dart';
|
||||||
import 'package:stackwallet/utilities/logger.dart';
|
import 'package:stackwallet/utilities/logger.dart';
|
||||||
import 'package:stackwallet/utilities/text_styles.dart';
|
import 'package:stackwallet/utilities/text_styles.dart';
|
||||||
import 'package:stackwallet/utilities/util.dart';
|
import 'package:stackwallet/utilities/util.dart';
|
||||||
|
@ -20,7 +22,10 @@ import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
|
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||||
|
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
|
||||||
import 'package:stackwallet/widgets/detail_item.dart';
|
import 'package:stackwallet/widgets/detail_item.dart';
|
||||||
|
import 'package:stackwallet/widgets/dialogs/simple_mobile_dialog.dart';
|
||||||
|
import 'package:stackwallet/widgets/frost_step_user_steps.dart';
|
||||||
import 'package:stackwallet/widgets/stack_dialog.dart';
|
import 'package:stackwallet/widgets/stack_dialog.dart';
|
||||||
|
|
||||||
class DisplayReshareConfigView extends ConsumerStatefulWidget {
|
class DisplayReshareConfigView extends ConsumerStatefulWidget {
|
||||||
|
@ -40,9 +45,19 @@ class DisplayReshareConfigView extends ConsumerStatefulWidget {
|
||||||
|
|
||||||
class _DisplayReshareConfigViewState
|
class _DisplayReshareConfigViewState
|
||||||
extends ConsumerState<DisplayReshareConfigView> {
|
extends ConsumerState<DisplayReshareConfigView> {
|
||||||
|
static const info = [
|
||||||
|
"Share this config with the signing group participants as well as any new "
|
||||||
|
"participant.",
|
||||||
|
"Wait for them to import the config.",
|
||||||
|
"Verify that everyone has imported the config. If you try to continue "
|
||||||
|
"before everyone is ready, the process will be canceled.",
|
||||||
|
"Check the box and press “Start resharing”.",
|
||||||
|
];
|
||||||
|
|
||||||
late final bool iAmInvolved;
|
late final bool iAmInvolved;
|
||||||
|
|
||||||
bool _buttonLock = false;
|
bool _buttonLock = false;
|
||||||
|
bool _userVerifyContinue = false;
|
||||||
|
|
||||||
Future<void> _onPressed() async {
|
Future<void> _onPressed() async {
|
||||||
if (_buttonLock) {
|
if (_buttonLock) {
|
||||||
|
@ -88,6 +103,111 @@ class _DisplayReshareConfigViewState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _showParticipantsDialog() {
|
||||||
|
final participants =
|
||||||
|
ref.read(pFrostResharingData).configData!.newParticipants;
|
||||||
|
|
||||||
|
showDialog<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (_) => SimpleMobileDialog(
|
||||||
|
showCloseButton: false,
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
const SizedBox(
|
||||||
|
height: 24,
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
child: Text(
|
||||||
|
"Group participants",
|
||||||
|
style: STextStyles.w600_20(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 12,
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
child: Text(
|
||||||
|
"The names are case-sensitive and must be entered exactly.",
|
||||||
|
style: STextStyles.w400_16(context).copyWith(
|
||||||
|
color: Theme.of(context).extension<StackColors>()!.textDark3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 12,
|
||||||
|
),
|
||||||
|
for (final participant in participants)
|
||||||
|
Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 1.5,
|
||||||
|
color:
|
||||||
|
Theme.of(context).extension<StackColors>()!.background,
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 12,
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 26,
|
||||||
|
height: 26,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.textFieldActiveBG,
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
200,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Center(
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
Assets.svg.user,
|
||||||
|
width: 16,
|
||||||
|
height: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 8,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
participant,
|
||||||
|
style: STextStyles.w500_14(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 8,
|
||||||
|
),
|
||||||
|
IconCopyButton(
|
||||||
|
data: participant,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 12,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 24,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
// TODO: optimize this by creating watcher providers (similar to normal WalletInfo)
|
// TODO: optimize this by creating watcher providers (similar to normal WalletInfo)
|
||||||
|
@ -162,7 +282,13 @@ class _DisplayReshareConfigViewState
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
if (!Util.isDesktop) const Spacer(),
|
const SizedBox(
|
||||||
|
height: 16,
|
||||||
|
),
|
||||||
|
const FrostStepUserSteps(
|
||||||
|
userSteps: info,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 220,
|
height: 220,
|
||||||
child: Row(
|
child: Row(
|
||||||
|
@ -197,13 +323,66 @@ class _DisplayReshareConfigViewState
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: Util.isDesktop ? 64 : 16,
|
height: Util.isDesktop ? 64 : 16,
|
||||||
),
|
),
|
||||||
if (!Util.isDesktop)
|
Row(
|
||||||
const Spacer(
|
children: [
|
||||||
flex: 2,
|
Expanded(
|
||||||
|
child: SecondaryButton(
|
||||||
|
label: "Show group participants",
|
||||||
|
onPressed: _showParticipantsDialog,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (iAmInvolved && !Util.isDesktop) const Spacer(),
|
||||||
|
if (iAmInvolved)
|
||||||
|
const SizedBox(
|
||||||
|
height: 16,
|
||||||
|
),
|
||||||
|
if (iAmInvolved)
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
_userVerifyContinue = !_userVerifyContinue;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: 20,
|
||||||
|
height: 26,
|
||||||
|
child: Checkbox(
|
||||||
|
materialTapTargetSize:
|
||||||
|
MaterialTapTargetSize.shrinkWrap,
|
||||||
|
value: _userVerifyContinue,
|
||||||
|
onChanged: (value) => setState(
|
||||||
|
() => _userVerifyContinue = value == true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 12,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
"I have verified that everyone has imported the config",
|
||||||
|
style: STextStyles.w500_14(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (iAmInvolved)
|
||||||
|
const SizedBox(
|
||||||
|
height: 16,
|
||||||
),
|
),
|
||||||
if (iAmInvolved)
|
if (iAmInvolved)
|
||||||
PrimaryButton(
|
PrimaryButton(
|
||||||
label: "Start resharing",
|
label: "Start resharing",
|
||||||
|
enabled: _userVerifyContinue,
|
||||||
onPressed: _onPressed,
|
onPressed: _onPressed,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -21,6 +21,7 @@ import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
|
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||||
|
import 'package:stackwallet/widgets/frost_step_user_steps.dart';
|
||||||
import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.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/qrcode_icon.dart';
|
||||||
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
|
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
|
||||||
|
@ -45,12 +46,22 @@ class ImportReshareConfigView extends ConsumerStatefulWidget {
|
||||||
|
|
||||||
class _ImportReshareConfigViewState
|
class _ImportReshareConfigViewState
|
||||||
extends ConsumerState<ImportReshareConfigView> {
|
extends ConsumerState<ImportReshareConfigView> {
|
||||||
|
static const info = [
|
||||||
|
"Scan the config QR code or paste the code provided by the group member who"
|
||||||
|
" is initiating resharing.",
|
||||||
|
"Wait for other participants to finish importing the config.",
|
||||||
|
"Verify that everyone has filled out their forms before continuing. If you "
|
||||||
|
"try to continue before everyone is ready, the process will be canceled.",
|
||||||
|
"Check the box and press “Start resharing”.",
|
||||||
|
];
|
||||||
|
|
||||||
late final TextEditingController configFieldController;
|
late final TextEditingController configFieldController;
|
||||||
late final FocusNode configFocusNode;
|
late final FocusNode configFocusNode;
|
||||||
|
|
||||||
bool _configEmpty = true;
|
bool _configEmpty = true;
|
||||||
|
|
||||||
bool _buttonLock = false;
|
bool _buttonLock = false;
|
||||||
|
bool _userVerifyContinue = false;
|
||||||
|
|
||||||
Future<void> _onPressed() async {
|
Future<void> _onPressed() async {
|
||||||
if (_buttonLock) {
|
if (_buttonLock) {
|
||||||
|
@ -84,14 +95,14 @@ class _ImportReshareConfigViewState
|
||||||
if (frostInfo.knownSalts.contains(salt)) {
|
if (frostInfo.knownSalts.contains(salt)) {
|
||||||
throw Exception("Duplicate config salt");
|
throw Exception("Duplicate config salt");
|
||||||
} else {
|
} else {
|
||||||
final salts = frostInfo.knownSalts;
|
final salts = frostInfo.knownSalts.toList();
|
||||||
salts.add(salt);
|
salts.add(salt);
|
||||||
final mainDB = ref.read(mainDBProvider);
|
final mainDB = ref.read(mainDBProvider);
|
||||||
await mainDB.isar.writeTxn(() async {
|
await mainDB.isar.writeTxn(() async {
|
||||||
final info = frostInfo;
|
final id = frostInfo.id;
|
||||||
await mainDB.isar.frostWalletInfo.delete(info.id);
|
await mainDB.isar.frostWalletInfo.delete(id);
|
||||||
await mainDB.isar.frostWalletInfo.put(
|
await mainDB.isar.frostWalletInfo.put(
|
||||||
info.copyWith(knownSalts: salts),
|
frostInfo.copyWith(knownSalts: salts),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -201,6 +212,20 @@ class _ImportReshareConfigViewState
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 16,
|
height: 16,
|
||||||
),
|
),
|
||||||
|
const FrostStepUserSteps(
|
||||||
|
userSteps: info,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
Text(
|
||||||
|
"Enter config",
|
||||||
|
style: STextStyles.w500_14(context).copyWith(
|
||||||
|
color:
|
||||||
|
Theme.of(context).extension<StackColors>()!.textSubtitle1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 10,
|
||||||
|
),
|
||||||
ClipRRect(
|
ClipRRect(
|
||||||
borderRadius: BorderRadius.circular(
|
borderRadius: BorderRadius.circular(
|
||||||
Constants.size.circularBorderRadius,
|
Constants.size.circularBorderRadius,
|
||||||
|
@ -319,9 +344,47 @@ class _ImportReshareConfigViewState
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 16,
|
height: 16,
|
||||||
),
|
),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
_userVerifyContinue = !_userVerifyContinue;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: 20,
|
||||||
|
height: 26,
|
||||||
|
child: Checkbox(
|
||||||
|
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||||
|
value: _userVerifyContinue,
|
||||||
|
onChanged: (value) => setState(
|
||||||
|
() => _userVerifyContinue = value == true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 12,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
"I have verified that everyone has imported the config",
|
||||||
|
style: STextStyles.w500_14(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 16,
|
||||||
|
),
|
||||||
PrimaryButton(
|
PrimaryButton(
|
||||||
label: "Start resharing",
|
label: "Start resharing",
|
||||||
enabled: !_configEmpty,
|
enabled: !_configEmpty && _userVerifyContinue,
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
if (FocusScope.of(context).hasFocus) {
|
if (FocusScope.of(context).hasFocus) {
|
||||||
FocusScope.of(context).unfocus();
|
FocusScope.of(context).unfocus();
|
||||||
|
|
Loading…
Reference in a new issue