Merge pull request #201 from cypherstack/desktop

Desktop
This commit is contained in:
Diego Salazar 2022-11-03 19:40:52 -06:00 committed by GitHub
commit fe44b14453
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 1970 additions and 1740 deletions

View file

@ -7,13 +7,17 @@ import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/conditional_parent.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/desktop/primary_button.dart';
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
import 'package:stackwallet/widgets/rounded_container.dart';
import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart';
import 'package:stackwallet/utilities/util.dart';
import '../../../widgets/rounded_white_container.dart';
class BaseCurrencySettingsView extends ConsumerStatefulWidget {
const BaseCurrencySettingsView({Key? key}) : super(key: key);
@ -102,31 +106,90 @@ class _CurrencyViewState extends ConsumerState<BaseCurrencySettingsView> {
currenciesWithoutSelected.insert(0, current);
}
currenciesWithoutSelected = _filtered();
return Scaffold(
backgroundColor: Theme.of(context).extension<StackColors>()!.background,
appBar: AppBar(
leading: AppBarBackButton(
onPressed: () async {
if (FocusScope.of(context).hasFocus) {
FocusScope.of(context).unfocus();
await Future<void>.delayed(const Duration(milliseconds: 75));
}
if (mounted) {
Navigator.of(context).pop();
}
},
),
title: Text(
"Currency",
style: STextStyles.navBarTitle(context),
),
),
body: Padding(
padding: const EdgeInsets.only(
top: 12,
left: 16,
right: 16,
),
final isDesktop = Util.isDesktop;
return ConditionalParent(
condition: !isDesktop,
builder: (child) {
return Scaffold(
backgroundColor:
Theme.of(context).extension<StackColors>()!.background,
appBar: AppBar(
leading: AppBarBackButton(
onPressed: () async {
if (FocusScope.of(context).hasFocus) {
FocusScope.of(context).unfocus();
await Future<void>.delayed(const Duration(milliseconds: 75));
}
if (mounted) {
Navigator.of(context).pop();
}
},
),
title: Text(
"Currency",
style: STextStyles.navBarTitle(context),
),
),
body: Padding(
padding: const EdgeInsets.only(
top: 12,
left: 16,
right: 16,
),
child: child,
),
);
},
child: ConditionalParent(
condition: isDesktop,
builder: (child) {
return Padding(
padding: const EdgeInsets.only(
top: 16,
bottom: 32,
left: 32,
right: 32,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Expanded(
child: RoundedWhiteContainer(
padding: const EdgeInsets.all(20),
borderColor:
Theme.of(context).extension<StackColors>()!.background,
child: child,
),
),
const SizedBox(
height: 16,
),
Row(
children: [
Expanded(
child: SecondaryButton(
label: "Cancel",
desktopMed: true,
onPressed: Navigator.of(context).pop,
),
),
const SizedBox(
width: 16,
),
Expanded(
child: PrimaryButton(
label: "Save changes",
desktopMed: true,
onPressed: Navigator.of(context).pop,
),
),
],
),
],
),
);
},
child: NestedScrollView(
floatHeaderSlivers: true,
headerSliverBuilder: (context, innerBoxIsScrolled) {

View file

@ -8,7 +8,6 @@ import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/electrumx_rpc/electrumx.dart';
import 'package:stackwallet/models/node_model.dart';
import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/providers/global/node_service_provider.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';
@ -20,15 +19,18 @@ import 'package:stackwallet/utilities/test_epic_box_connection.dart';
import 'package:stackwallet/utilities/test_monero_node_connection.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/conditional_parent.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
import 'package:stackwallet/widgets/desktop/primary_button.dart';
import 'package:stackwallet/widgets/desktop/secondary_button.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:uuid/uuid.dart';
import 'package:stackwallet/utilities/util.dart';
enum AddEditNodeViewType { add, edit }
class AddEditNodeView extends ConsumerStatefulWidget {
@ -59,6 +61,7 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> {
late final AddEditNodeViewType viewType;
late final Coin coin;
late final String? nodeId;
late final bool isDesktop;
late bool saveEnabled;
late bool testConnectionEnabled;
@ -162,8 +165,198 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> {
return testPassed;
}
Future<void> attemptSave() async {
final canConnect = await _testConnection(showFlushBar: false);
bool? shouldSave;
if (!canConnect) {
await showDialog<dynamic>(
context: context,
useSafeArea: true,
barrierDismissible: true,
builder: (_) => isDesktop
? DesktopDialog(
maxWidth: 440,
maxHeight: 300,
child: Column(
children: [
Padding(
padding: const EdgeInsets.only(
top: 32,
),
child: Row(
children: [
const SizedBox(
width: 32,
),
Text(
"Server currently unreachable",
style: STextStyles.desktopH3(context),
),
],
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.only(
left: 32,
right: 32,
top: 16,
bottom: 32,
),
child: Column(
children: [
const Spacer(),
Text(
"Would you like to save this node anyways?",
style: STextStyles.desktopTextMedium(context),
),
const Spacer(
flex: 2,
),
Row(
children: [
Expanded(
child: SecondaryButton(
label: "Cancel",
desktopMed: true,
onPressed: () => Navigator.of(
context,
rootNavigator: true,
).pop(false),
),
),
const SizedBox(
width: 16,
),
Expanded(
child: PrimaryButton(
label: "Save",
desktopMed: true,
onPressed: () => Navigator.of(
context,
rootNavigator: true,
).pop(true),
),
),
],
),
],
),
),
),
],
),
)
: StackDialog(
title: "Server currently unreachable",
message: "Would you like to save this node anyways?",
leftButton: TextButton(
onPressed: () async {
Navigator.of(context).pop(false);
},
child: Text(
"Cancel",
style: STextStyles.button(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark),
),
),
rightButton: TextButton(
onPressed: () async {
Navigator.of(context).pop(true);
},
style: Theme.of(context)
.extension<StackColors>()!
.getPrimaryEnabledButtonColor(context),
child: Text(
"Save",
style: STextStyles.button(context),
),
),
),
).then((value) {
if (value is bool && value) {
shouldSave = true;
} else {
shouldSave = false;
}
});
}
if (!canConnect && !shouldSave!) {
// return without saving
return;
}
final formData = ref.read(nodeFormDataProvider);
// strip unused path
String address = formData.host!;
if (coin == Coin.monero || coin == Coin.wownero || coin == Coin.epicCash) {
if (address.startsWith("http")) {
final uri = Uri.parse(address);
address = "${uri.scheme}://${uri.host}";
}
}
switch (viewType) {
case AddEditNodeViewType.add:
NodeModel node = NodeModel(
host: address,
port: formData.port!,
name: formData.name!,
id: const Uuid().v1(),
useSSL: formData.useSSL!,
loginName: formData.login,
enabled: true,
coinName: coin.name,
isFailover: formData.isFailover!,
isDown: false,
);
await ref.read(nodeServiceChangeNotifierProvider).add(
node,
formData.password,
true,
);
if (mounted) {
Navigator.of(context)
.popUntil(ModalRoute.withName(widget.routeOnSuccessOrDelete));
}
break;
case AddEditNodeViewType.edit:
NodeModel node = NodeModel(
host: address,
port: formData.port!,
name: formData.name!,
id: nodeId!,
useSSL: formData.useSSL!,
loginName: formData.login,
enabled: true,
coinName: coin.name,
isFailover: formData.isFailover!,
isDown: false,
);
await ref.read(nodeServiceChangeNotifierProvider).add(
node,
formData.password,
true,
);
if (mounted) {
Navigator.of(context)
.popUntil(ModalRoute.withName(widget.routeOnSuccessOrDelete));
}
break;
}
}
@override
void initState() {
isDesktop = Util.isDesktop;
ref.refresh(nodeFormDataProvider);
viewType = widget.viewType;
@ -196,279 +389,203 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> {
.select((value) => value.getNodeById(id: nodeId!)))
: null;
return Scaffold(
backgroundColor: Theme.of(context).extension<StackColors>()!.background,
appBar: AppBar(
leading: AppBarBackButton(
onPressed: () async {
if (FocusScope.of(context).hasFocus) {
FocusScope.of(context).unfocus();
await Future<void>.delayed(const Duration(milliseconds: 75));
}
if (mounted) {
Navigator.of(context).pop();
}
},
),
title: Text(
viewType == AddEditNodeViewType.edit ? "Edit node" : "Add node",
style: STextStyles.navBarTitle(context),
),
actions: [
if (viewType == AddEditNodeViewType.edit)
Padding(
padding: const EdgeInsets.only(
top: 10,
bottom: 10,
right: 10,
),
child: AspectRatio(
aspectRatio: 1,
child: AppBarIconButton(
key: const Key("deleteNodeAppBarButtonKey"),
size: 36,
shadows: const [],
color: Theme.of(context).extension<StackColors>()!.background,
icon: SvgPicture.asset(
Assets.svg.trash,
color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark,
width: 20,
height: 20,
),
onPressed: () async {
Navigator.popUntil(context,
ModalRoute.withName(widget.routeOnSuccessOrDelete));
return ConditionalParent(
condition: !isDesktop,
builder: (child) => Scaffold(
backgroundColor: Theme.of(context).extension<StackColors>()!.background,
appBar: AppBar(
leading: AppBarBackButton(
onPressed: () async {
if (FocusScope.of(context).hasFocus) {
FocusScope.of(context).unfocus();
await Future<void>.delayed(const Duration(milliseconds: 75));
}
if (mounted) {
Navigator.of(context).pop();
}
},
),
title: Text(
viewType == AddEditNodeViewType.edit ? "Edit node" : "Add node",
style: STextStyles.navBarTitle(context),
),
actions: [
if (viewType == AddEditNodeViewType.edit)
Padding(
padding: const EdgeInsets.only(
top: 10,
bottom: 10,
right: 10,
),
child: AspectRatio(
aspectRatio: 1,
child: AppBarIconButton(
key: const Key("deleteNodeAppBarButtonKey"),
size: 36,
shadows: const [],
color:
Theme.of(context).extension<StackColors>()!.background,
icon: SvgPicture.asset(
Assets.svg.trash,
color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark,
width: 20,
height: 20,
),
onPressed: () async {
Navigator.popUntil(context,
ModalRoute.withName(widget.routeOnSuccessOrDelete));
await ref.read(nodeServiceChangeNotifierProvider).delete(
nodeId!,
true,
);
},
await ref.read(nodeServiceChangeNotifierProvider).delete(
nodeId!,
true,
);
},
),
),
),
),
],
),
body: Padding(
padding: const EdgeInsets.only(
top: 12,
left: 12,
right: 12,
bottom: 12,
],
),
child: LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(4),
child: ConstrainedBox(
constraints:
BoxConstraints(minHeight: constraints.maxHeight - 8),
child: IntrinsicHeight(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
NodeForm(
node: node,
secureStore: widget.secureStore,
readOnly: false,
coin: widget.coin,
onChanged: (canSave, canTest) {
if (canSave != saveEnabled &&
canTest != testConnectionEnabled) {
setState(() {
saveEnabled = canSave;
testConnectionEnabled = canTest;
});
} else if (canSave != saveEnabled) {
setState(() {
saveEnabled = canSave;
});
} else if (canTest != testConnectionEnabled) {
setState(() {
testConnectionEnabled = canTest;
});
}
},
),
const Spacer(),
TextButton(
onPressed: testConnectionEnabled
? () async {
await _testConnection();
}
: null,
style: Theme.of(context)
.extension<StackColors>()!
.getSecondaryEnabledButtonColor(context),
child: Text(
"Test connection",
style: STextStyles.button(context).copyWith(
color: testConnectionEnabled
? Theme.of(context)
.extension<StackColors>()!
.textDark
: Theme.of(context)
.extension<StackColors>()!
.textWhite,
),
),
),
const SizedBox(height: 16),
TextButton(
style: saveEnabled
? Theme.of(context)
.extension<StackColors>()!
.getPrimaryEnabledButtonColor(context)
: Theme.of(context)
.extension<StackColors>()!
.getPrimaryDisabledButtonColor(context),
onPressed: saveEnabled
? () async {
final canConnect = await _testConnection(
showFlushBar: false);
bool? shouldSave;
if (!canConnect) {
await showDialog<dynamic>(
context: context,
useSafeArea: true,
barrierDismissible: true,
builder: (_) => StackDialog(
title: "Server currently unreachable",
message:
"Would you like to save this node anyways?",
leftButton: TextButton(
onPressed: () async {
Navigator.of(context).pop(false);
},
child: Text(
"Cancel",
style: STextStyles.button(context)
.copyWith(
color: Theme.of(context)
.extension<
StackColors>()!
.accentColorDark),
),
),
rightButton: TextButton(
onPressed: () async {
Navigator.of(context).pop(true);
},
style: Theme.of(context)
.extension<StackColors>()!
.getPrimaryEnabledButtonColor(
context),
child: Text(
"Save",
style: STextStyles.button(context),
),
),
),
).then((value) {
if (value is bool && value) {
shouldSave = true;
} else {
shouldSave = false;
}
});
}
if (!canConnect && !shouldSave!) {
// return without saving
return;
}
final formData =
ref.read(nodeFormDataProvider);
// strip unused path
String address = formData.host!;
if (coin == Coin.monero ||
coin == Coin.wownero ||
coin == Coin.epicCash) {
if (address.startsWith("http")) {
final uri = Uri.parse(address);
address = "${uri.scheme}://${uri.host}";
}
}
switch (viewType) {
case AddEditNodeViewType.add:
NodeModel node = NodeModel(
host: address,
port: formData.port!,
name: formData.name!,
id: const Uuid().v1(),
useSSL: formData.useSSL!,
loginName: formData.login,
enabled: true,
coinName: coin.name,
isFailover: formData.isFailover!,
isDown: false,
);
await ref
.read(
nodeServiceChangeNotifierProvider)
.add(
node,
formData.password,
true,
);
if (mounted) {
Navigator.of(context).popUntil(
ModalRoute.withName(
widget.routeOnSuccessOrDelete));
}
break;
case AddEditNodeViewType.edit:
NodeModel node = NodeModel(
host: address,
port: formData.port!,
name: formData.name!,
id: nodeId!,
useSSL: formData.useSSL!,
loginName: formData.login,
enabled: true,
coinName: coin.name,
isFailover: formData.isFailover!,
isDown: false,
);
await ref
.read(
nodeServiceChangeNotifierProvider)
.add(
node,
formData.password,
true,
);
if (mounted) {
Navigator.of(context).popUntil(
ModalRoute.withName(
widget.routeOnSuccessOrDelete));
}
break;
}
}
: null,
child: Text(
"Save",
style: STextStyles.button(context),
),
),
],
body: Padding(
padding: const EdgeInsets.only(
top: 12,
left: 12,
right: 12,
bottom: 12,
),
child: LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(4),
child: ConstrainedBox(
constraints:
BoxConstraints(minHeight: constraints.maxHeight - 8),
child: IntrinsicHeight(
child: child,
),
),
),
);
},
),
),
),
child: ConditionalParent(
condition: isDesktop,
builder: (child) => DesktopDialog(
maxWidth: 580,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
children: [
const SizedBox(
width: 8,
),
const AppBarBackButton(
iconSize: 24,
size: 40,
),
Text(
"Add new node",
style: STextStyles.desktopH3(context),
)
],
),
);
},
Padding(
padding: const EdgeInsets.only(
left: 32,
right: 32,
top: 16,
bottom: 32,
),
child: child,
),
],
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
NodeForm(
node: node,
secureStore: widget.secureStore,
readOnly: false,
coin: widget.coin,
onChanged: (canSave, canTest) {
if (canSave != saveEnabled &&
canTest != testConnectionEnabled) {
setState(() {
saveEnabled = canSave;
testConnectionEnabled = canTest;
});
} else if (canSave != saveEnabled) {
setState(() {
saveEnabled = canSave;
});
} else if (canTest != testConnectionEnabled) {
setState(() {
testConnectionEnabled = canTest;
});
}
},
),
if (!isDesktop) const Spacer(),
if (isDesktop)
const SizedBox(
height: 78,
),
Row(
children: [
Expanded(
child: SecondaryButton(
label: "Test connection",
enabled: testConnectionEnabled,
desktopMed: true,
onPressed: testConnectionEnabled
? () async {
await _testConnection();
}
: null,
),
),
if (isDesktop)
const SizedBox(
width: 16,
),
if (isDesktop)
Expanded(
child: PrimaryButton(
label: "Save",
enabled: saveEnabled,
desktopMed: true,
onPressed: saveEnabled ? attemptSave : null,
),
),
],
),
if (!isDesktop)
const SizedBox(
height: 16,
),
if (!isDesktop)
TextButton(
style: saveEnabled
? Theme.of(context)
.extension<StackColors>()!
.getPrimaryEnabledButtonColor(context)
: Theme.of(context)
.extension<StackColors>()!
.getPrimaryDisabledButtonColor(context),
onPressed: saveEnabled ? attemptSave : null,
child: Text(
"Save",
style: STextStyles.button(context),
),
),
],
),
),
);

View file

@ -9,6 +9,7 @@ import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
import 'package:tuple/tuple.dart';
@ -17,11 +18,13 @@ class CoinNodesView extends ConsumerStatefulWidget {
const CoinNodesView({
Key? key,
required this.coin,
this.rootNavigator = false,
}) : super(key: key);
static const String routeName = "/coinNodes";
final Coin coin;
final bool rootNavigator;
@override
ConsumerState<CoinNodesView> createState() => _CoinNodesViewState();
@ -63,12 +66,17 @@ class _CoinNodesViewState extends ConsumerState<CoinNodesView> {
textAlign: TextAlign.center,
),
Expanded(
child: const DesktopDialogCloseButton(),
child: DesktopDialogCloseButton(
onPressedOverride: Navigator.of(
context,
rootNavigator: widget.rootNavigator,
).pop,
),
),
],
),
Padding(
padding: EdgeInsets.only(
padding: const EdgeInsets.only(
left: 32,
right: 32,
),
@ -83,14 +91,19 @@ class _CoinNodesViewState extends ConsumerState<CoinNodesView> {
),
textAlign: TextAlign.left,
),
RichText(
text: TextSpan(
text: 'Add new nodes',
style:
STextStyles.desktopTextExtraSmall(context).copyWith(
color: Colors.blueAccent,
),
),
BlueTextButton(
text: "Add new node",
onTap: () {
Navigator.of(context).pushNamed(
AddEditNodeView.routeName,
arguments: Tuple4(
AddEditNodeViewType.add,
widget.coin,
null,
CoinNodesView.routeName,
),
);
},
),
],
),

View file

@ -17,7 +17,13 @@ import 'package:stackwallet/utilities/test_epic_box_connection.dart';
import 'package:stackwallet/utilities/test_monero_node_connection.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/conditional_parent.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/desktop/delete_button.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
import 'package:stackwallet/widgets/desktop/primary_button.dart';
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
import 'package:tuple/tuple.dart';
class NodeDetailsView extends ConsumerStatefulWidget {
@ -48,6 +54,8 @@ class _NodeDetailsViewState extends ConsumerState<NodeDetailsView> {
late final String nodeId;
late final String popRouteName;
bool _desktopReadOnly = true;
@override
initState() {
secureStore = widget.secureStore;
@ -126,130 +134,239 @@ class _NodeDetailsViewState extends ConsumerState<NodeDetailsView> {
}
if (testPassed) {
showFloatingFlushBar(
type: FlushBarType.success,
message: "Server ping success",
context: context,
unawaited(
showFloatingFlushBar(
type: FlushBarType.success,
message: "Server ping success",
context: context,
),
);
} else {
showFloatingFlushBar(
type: FlushBarType.warning,
message: "Server unreachable",
context: context,
unawaited(
showFloatingFlushBar(
type: FlushBarType.warning,
message: "Server unreachable",
context: context,
),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).extension<StackColors>()!.background,
appBar: AppBar(
leading: AppBarBackButton(
onPressed: () async {
if (FocusScope.of(context).hasFocus) {
FocusScope.of(context).unfocus();
await Future<void>.delayed(const Duration(milliseconds: 75));
}
if (mounted) {
Navigator.of(context).pop();
}
},
),
title: Text(
"Node details",
style: STextStyles.navBarTitle(context),
),
actions: [
if (!nodeId.startsWith("default"))
Padding(
padding: const EdgeInsets.only(
top: 10,
bottom: 10,
right: 10,
),
child: AspectRatio(
aspectRatio: 1,
child: AppBarIconButton(
key: const Key("nodeDetailsEditNodeAppBarButtonKey"),
size: 36,
shadows: const [],
color: Theme.of(context).extension<StackColors>()!.background,
icon: SvgPicture.asset(
Assets.svg.pencil,
color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark,
width: 20,
height: 20,
final isDesktop = Util.isDesktop;
final node = ref.watch(nodeServiceChangeNotifierProvider
.select((value) => value.getNodeById(id: nodeId)));
return ConditionalParent(
condition: !isDesktop,
builder: (child) => Scaffold(
backgroundColor: Theme.of(context).extension<StackColors>()!.background,
appBar: AppBar(
leading: AppBarBackButton(
onPressed: () async {
if (FocusScope.of(context).hasFocus) {
FocusScope.of(context).unfocus();
await Future<void>.delayed(const Duration(milliseconds: 75));
}
if (mounted) {
Navigator.of(context).pop();
}
},
),
title: Text(
"Node details",
style: STextStyles.navBarTitle(context),
),
actions: [
if (!nodeId.startsWith("default"))
Padding(
padding: const EdgeInsets.only(
top: 10,
bottom: 10,
right: 10,
),
child: AspectRatio(
aspectRatio: 1,
child: AppBarIconButton(
key: const Key("nodeDetailsEditNodeAppBarButtonKey"),
size: 36,
shadows: const [],
color:
Theme.of(context).extension<StackColors>()!.background,
icon: SvgPicture.asset(
Assets.svg.pencil,
color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark,
width: 20,
height: 20,
),
onPressed: () {
Navigator.of(context).pushNamed(
AddEditNodeView.routeName,
arguments: Tuple4(
AddEditNodeViewType.edit,
coin,
nodeId,
popRouteName,
),
);
},
),
onPressed: () {
Navigator.of(context).pushNamed(
AddEditNodeView.routeName,
arguments: Tuple4(
AddEditNodeViewType.edit,
coin,
nodeId,
popRouteName,
),
);
},
),
),
),
],
),
body: Padding(
padding: const EdgeInsets.only(
top: 12,
left: 12,
right: 12,
],
),
child: LayoutBuilder(
builder: (context, constraints) {
final node = ref.watch(nodeServiceChangeNotifierProvider
.select((value) => value.getNodeById(id: nodeId)));
return SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(4),
child: ConstrainedBox(
constraints:
BoxConstraints(minHeight: constraints.maxHeight - 8),
child: IntrinsicHeight(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
NodeForm(
node: node,
secureStore: secureStore,
readOnly: true,
coin: coin,
),
const Spacer(),
TextButton(
style: Theme.of(context)
.extension<StackColors>()!
.getSecondaryEnabledButtonColor(context),
onPressed: () async {
await _testConnection(ref, context);
},
child: Text(
"Test connection",
style: STextStyles.button(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark),
),
),
const SizedBox(height: 16),
],
body: Padding(
padding: const EdgeInsets.only(
top: 12,
left: 12,
right: 12,
),
child: LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(4),
child: ConstrainedBox(
constraints:
BoxConstraints(minHeight: constraints.maxHeight - 8),
child: IntrinsicHeight(
child: child,
),
),
),
);
},
),
),
),
child: ConditionalParent(
condition: isDesktop,
builder: (child) => DesktopDialog(
maxWidth: 580,
maxHeight: double.infinity,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
children: [
const SizedBox(
width: 8,
),
const AppBarBackButton(
iconSize: 24,
size: 40,
),
Text(
"Node details",
style: STextStyles.desktopH3(context),
)
],
),
);
},
Padding(
padding: const EdgeInsets.only(
left: 32,
right: 32,
top: 16,
bottom: 32,
),
child: child,
),
],
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
NodeForm(
node: node,
secureStore: secureStore,
readOnly: isDesktop ? _desktopReadOnly : true,
coin: coin,
),
if (!isDesktop) const Spacer(),
if (isDesktop)
const SizedBox(
height: 22,
),
if (isDesktop)
SizedBox(
height: 56,
child: _desktopReadOnly
? null
: Row(
children: [
Expanded(
child: DeleteButton(
label: "Delete node",
desktopMed: true,
onPressed: () async {
Navigator.of(context).pop();
await ref
.read(nodeServiceChangeNotifierProvider)
.delete(
node!.id,
true,
);
},
),
),
const SizedBox(
width: 16,
),
const Spacer(),
],
),
),
if (isDesktop && !_desktopReadOnly)
const SizedBox(
height: 45,
),
Row(
children: [
Expanded(
child: SecondaryButton(
label: "Test connection",
desktopMed: true,
onPressed: () async {
await _testConnection(ref, context);
},
),
),
if (isDesktop)
const SizedBox(
width: 16,
),
if (isDesktop)
Expanded(
child: !nodeId.startsWith("default")
? PrimaryButton(
label: _desktopReadOnly ? "Edit" : "Save",
desktopMed: true,
onPressed: () async {
final shouldSave = _desktopReadOnly == false;
setState(() {
_desktopReadOnly = !_desktopReadOnly;
});
if (shouldSave) {
// todo save node
}
},
)
: Container(),
),
],
),
if (!isDesktop)
const SizedBox(
height: 16,
),
],
),
),
);

View file

@ -6,7 +6,11 @@ import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/sync_type_enum.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/conditional_parent.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
class SyncingOptionsView extends ConsumerWidget {
@ -16,384 +20,390 @@ class SyncingOptionsView extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
backgroundColor: Theme.of(context).extension<StackColors>()!.background,
appBar: AppBar(
leading: AppBarBackButton(
onPressed: () async {
Navigator.of(context).pop();
},
),
title: Text(
"Syncing",
style: STextStyles.navBarTitle(context),
),
),
body: Padding(
padding: const EdgeInsets.all(16),
child: LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: constraints.maxHeight,
),
child: IntrinsicHeight(
child: Column(
children: [
RoundedWhiteContainer(
padding: const EdgeInsets.all(0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
final isDesktop = Util.isDesktop;
return ConditionalParent(
condition: !isDesktop,
builder: (child) {
return Scaffold(
backgroundColor:
Theme.of(context).extension<StackColors>()!.background,
appBar: AppBar(
leading: AppBarBackButton(
onPressed: () async {
Navigator.of(context).pop();
},
),
title: Text(
"Syncing",
style: STextStyles.navBarTitle(context),
),
),
body: Padding(
padding: const EdgeInsets.all(16),
child: LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: constraints.maxHeight,
),
child: IntrinsicHeight(
child: child,
),
),
);
},
),
),
);
},
child: Column(
children: [
RoundedWhiteContainer(
padding: const EdgeInsets.all(0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: const EdgeInsets.all(4),
child: RawMaterialButton(
// splashColor: Theme.of(context).extension<StackColors>()!.highlight,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
onPressed: () {
final state =
ref.read(prefsChangeNotifierProvider).syncType;
if (state != SyncingType.currentWalletOnly) {
ref.read(prefsChangeNotifierProvider).syncType =
SyncingType.currentWalletOnly;
// disable auto sync on all wallets that aren't active/current
ref
.read(walletsChangeNotifierProvider)
.managers
.forEach((e) {
if (!e.isActiveWallet) {
e.shouldAutoSync = false;
}
});
}
},
child: Container(
color: Colors.transparent,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(4),
child: RawMaterialButton(
// splashColor: Theme.of(context).extension<StackColors>()!.highlight,
materialTapTargetSize:
MaterialTapTargetSize.shrinkWrap,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
SizedBox(
width: 20,
height: 20,
child: Radio(
activeColor: Theme.of(context)
.extension<StackColors>()!
.radioButtonIconEnabled,
value: SyncingType.currentWalletOnly,
groupValue: ref.watch(
prefsChangeNotifierProvider
.select((value) => value.syncType),
),
onPressed: () {
final state = ref
.read(prefsChangeNotifierProvider)
.syncType;
if (state != SyncingType.currentWalletOnly) {
onChanged: (value) {
if (value is SyncingType) {
ref
.read(prefsChangeNotifierProvider)
.syncType =
SyncingType.currentWalletOnly;
// disable auto sync on all wallets that aren't active/current
ref
.read(walletsChangeNotifierProvider)
.managers
.forEach((e) {
if (!e.isActiveWallet) {
e.shouldAutoSync = false;
}
});
}
},
child: Container(
color: Colors.transparent,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
SizedBox(
width: 20,
height: 20,
child: Radio(
activeColor: Theme.of(context)
.extension<StackColors>()!
.radioButtonIconEnabled,
value:
SyncingType.currentWalletOnly,
groupValue: ref.watch(
prefsChangeNotifierProvider
.select((value) =>
value.syncType),
),
onChanged: (value) {
if (value is SyncingType) {
ref
.read(
prefsChangeNotifierProvider)
.syncType = value;
}
},
),
),
const SizedBox(
width: 12,
),
Flexible(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
"Sync only currently open wallet",
style: STextStyles.titleBold12(
context),
textAlign: TextAlign.left,
),
Text(
"Sync only the wallet that you are using",
style: STextStyles.itemSubtitle(
context),
textAlign: TextAlign.left,
),
],
),
),
],
),
),
),
),
),
Padding(
padding: const EdgeInsets.all(4.0),
child: RawMaterialButton(
// splashColor: Theme.of(context).extension<StackColors>()!.highlight,
materialTapTargetSize:
MaterialTapTargetSize.shrinkWrap,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
onPressed: () {
final state = ref
.read(prefsChangeNotifierProvider)
.syncType;
if (state !=
SyncingType.allWalletsOnStartup) {
ref
.read(prefsChangeNotifierProvider)
.syncType =
SyncingType.allWalletsOnStartup;
// enable auto sync on all wallets
ref
.read(walletsChangeNotifierProvider)
.managers
.forEach(
(e) => e.shouldAutoSync = true);
}
},
child: Container(
color: Colors.transparent,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
SizedBox(
width: 20,
height: 20,
child: Radio(
activeColor: Theme.of(context)
.extension<StackColors>()!
.radioButtonIconEnabled,
value:
SyncingType.allWalletsOnStartup,
groupValue: ref.watch(
prefsChangeNotifierProvider
.select((value) =>
value.syncType),
),
onChanged: (value) {
if (value is SyncingType) {
ref
.read(
prefsChangeNotifierProvider)
.syncType = value;
}
},
),
),
const SizedBox(
width: 12,
),
Flexible(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
"Sync all wallets at startup",
style: STextStyles.titleBold12(
context),
textAlign: TextAlign.left,
),
Text(
"All of your wallets will start syncing when you open the app",
style: STextStyles.itemSubtitle(
context),
textAlign: TextAlign.left,
),
],
),
),
],
),
),
),
),
),
Padding(
padding: const EdgeInsets.all(4),
child: RawMaterialButton(
// splashColor: Theme.of(context).extension<StackColors>()!.highlight,
materialTapTargetSize:
MaterialTapTargetSize.shrinkWrap,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
onPressed: () {
final state = ref
.read(prefsChangeNotifierProvider)
.syncType;
if (state !=
SyncingType.selectedWalletsAtStartup) {
ref
.read(prefsChangeNotifierProvider)
.syncType =
SyncingType.selectedWalletsAtStartup;
final ids = ref
.read(prefsChangeNotifierProvider)
.walletIdsSyncOnStartup;
// enable auto sync on selected wallets only
ref
.read(walletsChangeNotifierProvider)
.managers
.forEach((e) => e.shouldAutoSync =
ids.contains(e.walletId));
.syncType = value;
}
},
child: Container(
color: Colors.transparent,
child: Padding(
padding: const EdgeInsets.all(8),
child: Row(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
SizedBox(
width: 20,
height: 20,
child: Radio(
activeColor: Theme.of(context)
.extension<StackColors>()!
.radioButtonIconEnabled,
value: SyncingType
.selectedWalletsAtStartup,
groupValue: ref.watch(
prefsChangeNotifierProvider
.select((value) =>
value.syncType),
),
onChanged: (value) {
if (value is SyncingType) {
ref
.read(
prefsChangeNotifierProvider)
.syncType = value;
}
},
),
),
const SizedBox(
width: 12,
),
Flexible(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
"Sync only selected wallets at startup",
style: STextStyles.titleBold12(
context),
textAlign: TextAlign.left,
),
Text(
"Only the wallets you select will start syncing when you open the app",
style: STextStyles.itemSubtitle(
context),
textAlign: TextAlign.left,
),
],
),
),
],
),
),
),
),
),
if (ref.watch(prefsChangeNotifierProvider
.select((value) => value.syncType)) !=
SyncingType.selectedWalletsAtStartup)
const SizedBox(
height: 12,
),
if (ref.watch(prefsChangeNotifierProvider
.select((value) => value.syncType)) ==
SyncingType.selectedWalletsAtStartup)
Container(
color: Colors.transparent,
child: Padding(
padding: const EdgeInsets.only(
left: 12.0,
right: 12,
bottom: 12,
const SizedBox(
width: 12,
),
Flexible(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Sync only currently open wallet",
style: STextStyles.titleBold12(context),
textAlign: TextAlign.left,
),
child: Row(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
const SizedBox(
width: 12 + 20,
height: 12,
),
Flexible(
child: RawMaterialButton(
// splashColor: Theme.of(context).extension<StackColors>()!.highlight,
materialTapTargetSize:
MaterialTapTargetSize.shrinkWrap,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
Constants
.size.circularBorderRadius,
),
),
onPressed: () {
Navigator.of(context).pushNamed(
WalletSyncingOptionsView
.routeName);
},
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
"Select wallets...",
style:
STextStyles.link2(context),
textAlign: TextAlign.left,
),
],
),
),
),
],
Text(
"Sync only the wallet that you are using",
style: STextStyles.itemSubtitle(context),
textAlign: TextAlign.left,
),
),
],
),
),
],
),
),
],
),
),
),
),
);
},
),
Padding(
padding: const EdgeInsets.all(4.0),
child: RawMaterialButton(
// splashColor: Theme.of(context).extension<StackColors>()!.highlight,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
onPressed: () {
final state =
ref.read(prefsChangeNotifierProvider).syncType;
if (state != SyncingType.allWalletsOnStartup) {
ref.read(prefsChangeNotifierProvider).syncType =
SyncingType.allWalletsOnStartup;
// enable auto sync on all wallets
ref
.read(walletsChangeNotifierProvider)
.managers
.forEach((e) => e.shouldAutoSync = true);
}
},
child: Container(
color: Colors.transparent,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 20,
height: 20,
child: Radio(
activeColor: Theme.of(context)
.extension<StackColors>()!
.radioButtonIconEnabled,
value: SyncingType.allWalletsOnStartup,
groupValue: ref.watch(
prefsChangeNotifierProvider
.select((value) => value.syncType),
),
onChanged: (value) {
if (value is SyncingType) {
ref
.read(prefsChangeNotifierProvider)
.syncType = value;
}
},
),
),
const SizedBox(
width: 12,
),
Flexible(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Sync all wallets at startup",
style: STextStyles.titleBold12(context),
textAlign: TextAlign.left,
),
Text(
"All of your wallets will start syncing when you open the app",
style: STextStyles.itemSubtitle(context),
textAlign: TextAlign.left,
),
],
),
),
],
),
),
),
),
),
Padding(
padding: const EdgeInsets.all(4),
child: RawMaterialButton(
// splashColor: Theme.of(context).extension<StackColors>()!.highlight,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
onPressed: () {
final state =
ref.read(prefsChangeNotifierProvider).syncType;
if (state != SyncingType.selectedWalletsAtStartup) {
ref.read(prefsChangeNotifierProvider).syncType =
SyncingType.selectedWalletsAtStartup;
final ids = ref
.read(prefsChangeNotifierProvider)
.walletIdsSyncOnStartup;
// enable auto sync on selected wallets only
ref
.read(walletsChangeNotifierProvider)
.managers
.forEach((e) =>
e.shouldAutoSync = ids.contains(e.walletId));
}
},
child: Container(
color: Colors.transparent,
child: Padding(
padding: const EdgeInsets.all(8),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 20,
height: 20,
child: Radio(
activeColor: Theme.of(context)
.extension<StackColors>()!
.radioButtonIconEnabled,
value: SyncingType.selectedWalletsAtStartup,
groupValue: ref.watch(
prefsChangeNotifierProvider
.select((value) => value.syncType),
),
onChanged: (value) {
if (value is SyncingType) {
ref
.read(prefsChangeNotifierProvider)
.syncType = value;
}
},
),
),
const SizedBox(
width: 12,
),
Flexible(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Sync only selected wallets at startup",
style: STextStyles.titleBold12(context),
textAlign: TextAlign.left,
),
Text(
"Only the wallets you select will start syncing when you open the app",
style: STextStyles.itemSubtitle(context),
textAlign: TextAlign.left,
),
],
),
),
],
),
),
),
),
),
if (ref.watch(prefsChangeNotifierProvider
.select((value) => value.syncType)) !=
SyncingType.selectedWalletsAtStartup)
const SizedBox(
height: 12,
),
if (ref.watch(prefsChangeNotifierProvider
.select((value) => value.syncType)) ==
SyncingType.selectedWalletsAtStartup)
Container(
color: Colors.transparent,
child: Padding(
padding: const EdgeInsets.only(
left: 12.0,
right: 12,
bottom: 12,
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
width: 12 + 20,
height: 12,
),
Flexible(
child: RawMaterialButton(
// splashColor: Theme.of(context).extension<StackColors>()!.highlight,
materialTapTargetSize:
MaterialTapTargetSize.shrinkWrap,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
onPressed: () {
!isDesktop
? Navigator.of(context).pushNamed(
WalletSyncingOptionsView.routeName)
: showDialog(
context: context,
useSafeArea: false,
barrierDismissible: true,
builder: (context) {
return DesktopDialog(
maxWidth: 600,
maxHeight: 800,
child: Column(
children: [
Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
Padding(
padding:
const EdgeInsets.all(
32),
child: Text(
"Select wallets to sync",
style: STextStyles
.desktopH3(context),
textAlign:
TextAlign.center,
),
),
const DesktopDialogCloseButton(),
],
),
const Expanded(
child:
WalletSyncingOptionsView(),
),
],
),
);
});
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Select wallets...",
style: STextStyles.link2(context),
textAlign: TextAlign.left,
),
],
),
),
),
],
),
),
),
],
),
),
],
),
);
}

View file

@ -10,7 +10,9 @@ import 'package:stackwallet/utilities/enums/sync_type_enum.dart';
import 'package:stackwallet/utilities/format.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/animated_text.dart';
import 'package:stackwallet/widgets/conditional_parent.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/custom_buttons/draggable_switch_button.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
@ -25,30 +27,47 @@ class WalletSyncingOptionsView extends ConsumerWidget {
final managers = ref
.watch(walletsChangeNotifierProvider.select((value) => value.managers));
return Scaffold(
backgroundColor: Theme.of(context).extension<StackColors>()!.background,
appBar: AppBar(
leading: AppBarBackButton(
onPressed: () async {
Navigator.of(context).pop();
},
),
title: FittedBox(
fit: BoxFit.scaleDown,
child: Text(
"Sync only selected wallets at startup",
style: STextStyles.navBarTitle(context),
final isDesktop = Util.isDesktop;
return ConditionalParent(
condition: !isDesktop,
builder: (child) {
return Scaffold(
backgroundColor:
Theme.of(context).extension<StackColors>()!.background,
appBar: AppBar(
leading: AppBarBackButton(
onPressed: () async {
Navigator.of(context).pop();
},
),
title: FittedBox(
fit: BoxFit.scaleDown,
child: Text(
"Sync only selected wallets at startup",
style: STextStyles.navBarTitle(context),
),
),
),
),
),
body: LayoutBuilder(builder: (context, constraints) {
return Padding(
padding: const EdgeInsets.only(
left: 12,
top: 12,
right: 12,
body: Padding(
padding: const EdgeInsets.only(
left: 12,
top: 12,
right: 12,
),
child: child,
),
child: SingleChildScrollView(
);
},
child: ConditionalParent(
condition: isDesktop,
builder: (child) {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 32),
child: child,
);
},
child: LayoutBuilder(builder: (context, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: constraints.maxHeight - 24,
@ -71,6 +90,11 @@ class WalletSyncingOptionsView extends ConsumerWidget {
),
RoundedWhiteContainer(
padding: const EdgeInsets.all(0),
borderColor: !isDesktop
? Colors.transparent
: Theme.of(context)
.extension<StackColors>()!
.background,
child: Column(
children: [
...managers.map(
@ -208,9 +232,9 @@ class WalletSyncingOptionsView extends ConsumerWidget {
),
),
),
),
);
}),
);
}),
),
);
}
}

View file

@ -14,6 +14,7 @@ import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/conditional_parent.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_scaffold.dart';
@ -70,180 +71,195 @@ class _StackPrivacyCalls extends ConsumerState<StackPrivacyCalls> {
),
),
body: SafeArea(
child: Padding(
padding: EdgeInsets.fromLTRB(0, isDesktop ? 0 : 40, 0, 0),
child: ConstrainedBox(
constraints: BoxConstraints(
maxWidth: isDesktop ? 480 : double.infinity,
child: ConditionalParent(
condition: !isDesktop,
builder: (child) => LayoutBuilder(
builder: (context, constraints) => SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: constraints.maxHeight,
),
child: IntrinsicHeight(
child: child,
),
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Choose your Stack experience",
style: isDesktop
? STextStyles.desktopH2(context)
: STextStyles.pageTitleH1(context),
),
SizedBox(
height: isDesktop ? 16 : 8,
),
Text(
!widget.isSettings
? "You can change it later in Settings"
: "",
style: isDesktop
? STextStyles.desktopSubtitleH2(context)
: STextStyles.subtitle(context),
),
SizedBox(
height: isDesktop ? 32 : 36,
),
Padding(
padding: EdgeInsets.symmetric(
horizontal: isDesktop ? 0 : 16,
),
child: Padding(
padding: EdgeInsets.fromLTRB(0, isDesktop ? 0 : 40, 0, 0),
child: ConstrainedBox(
constraints: BoxConstraints(
maxWidth: isDesktop ? 480 : double.infinity,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Choose your Stack experience",
style: isDesktop
? STextStyles.desktopH2(context)
: STextStyles.pageTitleH1(context),
),
child: PrivacyToggle(
externalCallsEnabled: isEasy,
onChanged: (externalCalls) {
isEasy = externalCalls;
setState(() {
infoToggle = isEasy;
});
},
SizedBox(
height: isDesktop ? 16 : 8,
),
),
SizedBox(
height: isDesktop ? 16 : 36,
),
Padding(
padding: isDesktop
? const EdgeInsets.all(0)
: const EdgeInsets.all(16.0),
child: RoundedWhiteContainer(
child: Center(
child: RichText(
textAlign: TextAlign.left,
text: TextSpan(
style: isDesktop
? STextStyles.desktopTextExtraExtraSmall(context)
: STextStyles.label(context).copyWith(
fontSize: 12.0,
),
children: infoToggle
? [
const TextSpan(
text:
"Exchange data preloaded for a seamless experience."),
const TextSpan(
text:
"\n\nCoinGecko enabled: (24 hour price change shown in-app, total wallet value shown in USD or other currency)."),
TextSpan(
text:
"\n\nRecommended for most crypto users.",
style: isDesktop
? STextStyles
.desktopTextExtraExtraSmall600(
context)
: TextStyle(
color: Theme.of(context)
.extension<StackColors>()!
.textDark,
fontWeight: FontWeight.w600,
),
Text(
!widget.isSettings
? "You can change it later in Settings"
: "",
style: isDesktop
? STextStyles.desktopSubtitleH2(context)
: STextStyles.subtitle(context),
),
SizedBox(
height: isDesktop ? 32 : 36,
),
Padding(
padding: EdgeInsets.symmetric(
horizontal: isDesktop ? 0 : 16,
),
child: PrivacyToggle(
externalCallsEnabled: isEasy,
onChanged: (externalCalls) {
isEasy = externalCalls;
setState(() {
infoToggle = isEasy;
});
},
),
),
SizedBox(
height: isDesktop ? 16 : 36,
),
Padding(
padding: isDesktop
? const EdgeInsets.all(0)
: const EdgeInsets.all(16.0),
child: RoundedWhiteContainer(
child: Center(
child: RichText(
textAlign: TextAlign.left,
text: TextSpan(
style: isDesktop
? STextStyles.desktopTextExtraExtraSmall(context)
: STextStyles.label(context).copyWith(
fontSize: 12.0,
),
]
: [
const TextSpan(
children: infoToggle
? [
const TextSpan(
text:
"Exchange data preloaded for a seamless experience."),
const TextSpan(
text:
"\n\nCoinGecko enabled: (24 hour price change shown in-app, total wallet value shown in USD or other currency)."),
TextSpan(
text:
"Exchange data not preloaded (slower experience)."),
const TextSpan(
"\n\nRecommended for most crypto users.",
style: isDesktop
? STextStyles
.desktopTextExtraExtraSmall600(
context)
: TextStyle(
color: Theme.of(context)
.extension<StackColors>()!
.textDark,
fontWeight: FontWeight.w600,
),
),
]
: [
const TextSpan(
text:
"Exchange data not preloaded (slower experience)."),
const TextSpan(
text:
"\n\nCoinGecko disabled (price changes not shown, no wallet value shown in other currencies)."),
TextSpan(
text:
"\n\nCoinGecko disabled (price changes not shown, no wallet value shown in other currencies)."),
TextSpan(
text:
"\n\nRecommended for the privacy conscious.",
style: isDesktop
? STextStyles
.desktopTextExtraExtraSmall600(
context)
: TextStyle(
color: Theme.of(context)
.extension<StackColors>()!
.textDark,
fontWeight: FontWeight.w600,
),
),
],
"\n\nRecommended for the privacy conscious.",
style: isDesktop
? STextStyles
.desktopTextExtraExtraSmall600(
context)
: TextStyle(
color: Theme.of(context)
.extension<StackColors>()!
.textDark,
fontWeight: FontWeight.w600,
),
),
],
),
),
),
),
),
),
if (!isDesktop)
const Spacer(
flex: 4,
),
if (isDesktop)
const SizedBox(
height: 32,
),
Padding(
padding: isDesktop
? const EdgeInsets.all(0)
: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 16,
),
child: Row(
children: [
Expanded(
child: PrimaryButton(
label:
!widget.isSettings ? "Continue" : "Save changes",
onPressed: () {
ref
.read(prefsChangeNotifierProvider)
.externalCalls = isEasy;
if (!isDesktop)
const Spacer(
flex: 4,
),
if (isDesktop)
const SizedBox(
height: 32,
),
Padding(
padding: isDesktop
? const EdgeInsets.all(0)
: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 16,
),
child: Row(
children: [
Expanded(
child: PrimaryButton(
label:
!widget.isSettings ? "Continue" : "Save changes",
onPressed: () {
ref
.read(prefsChangeNotifierProvider)
.externalCalls = isEasy;
DB.instance
.put<dynamic>(
boxName: DB.boxNamePrefs,
key: "externalCalls",
value: isEasy)
.then((_) {
if (isEasy) {
unawaited(
ExchangeDataLoadingService().loadAll(ref));
ref
.read(priceAnd24hChangeNotifierProvider)
.start(true);
}
});
if (!widget.isSettings) {
if (isDesktop) {
Navigator.of(context).pushNamed(
CreatePasswordView.routeName,
);
DB.instance
.put<dynamic>(
boxName: DB.boxNamePrefs,
key: "externalCalls",
value: isEasy)
.then((_) {
if (isEasy) {
unawaited(
ExchangeDataLoadingService().loadAll(ref));
ref
.read(priceAnd24hChangeNotifierProvider)
.start(true);
}
});
if (!widget.isSettings) {
if (isDesktop) {
Navigator.of(context).pushNamed(
CreatePasswordView.routeName,
);
} else {
Navigator.of(context).pushNamed(
CreatePinView.routeName,
);
}
} else {
Navigator.of(context).pushNamed(
CreatePinView.routeName,
);
Navigator.pop(context);
}
} else {
Navigator.pop(context);
}
},
},
),
),
),
],
],
),
),
),
if (isDesktop)
const SizedBox(
height: kDesktopAppBarHeight,
),
],
if (isDesktop)
const SizedBox(
height: kDesktopAppBarHeight,
),
],
),
),
),
),
@ -494,158 +510,3 @@ class _PrivacyToggleState extends State<PrivacyToggle> {
);
}
}
// class ContinueButton extends ConsumerWidget {
// const ContinueButton({
// Key? key,
// required this.isDesktop,
// required this.onPressed,
// required this.label,
// }) : super(key: key);
//
// final String label;
// final bool isDesktop;
// final VoidCallback onPressed;
//
// @override
// Widget build(BuildContext context, WidgetRef ref) {
// if (isDesktop) {
// return SizedBox(
// width: 328,
// height: 70,
// child: TextButton(
// style: Theme.of(context)
// .extension<StackColors>()!
// .getPrimaryEnabledButtonColor(context),
// onPressed: onPressed,
// child: Text(
// label,
// style: STextStyles.button(context).copyWith(fontSize: 20),
// ),
// ),
// );
// } else {
// return TextButton(
// style: Theme.of(context)
// .extension<StackColors>()!
// .getPrimaryEnabledButtonColor(context),
// onPressed: onPressed,
// child: Text(
// label,
// style: STextStyles.button(context),
// ),
// );
// }
// }
// }
// class CustomRadio extends StatefulWidget {
// CustomRadio(this.upperCall, {Key? key}) : super(key: key);
//
// Function upperCall;
//
// @override
// createState() {
// return CustomRadioState();
// }
// }
//
// class CustomRadioState extends State<CustomRadio> {
// List<RadioModel> sampleData = <RadioModel>[];
//
// @override
// void initState() {
// super.initState();
// sampleData.add(
// RadioModel(true, Assets.svg.personaEasy, 'Easy Crypto', 'Recommended'));
// sampleData.add(RadioModel(
// false, Assets.svg.personaIncognito, 'Incognito', 'Privacy conscious'));
// }
//
// @override
// Widget build(BuildContext context) {
// return Row(
// mainAxisAlignment: MainAxisAlignment.center,
// children: [
// InkWell(
// onTap: () {
// setState(() {
// // if (!sampleData[0].isSelected) {
// widget.upperCall.call(true);
// // }
// for (var element in sampleData) {
// element.isSelected = false;
// }
// sampleData[0].isSelected = true;
// });
// },
// child: RadioItem(sampleData[0]),
// ),
// InkWell(
// onTap: () {
// setState(() {
// // if (!sampleData[1].isSelected) {
// widget.upperCall.call(false);
// // }
// for (var element in sampleData) {
// element.isSelected = false;
// }
// sampleData[1].isSelected = true;
// });
// },
// child: RadioItem(sampleData[1]),
// )
// ],
// );
// }
// }
//
// class RadioItem extends StatelessWidget {
// final RadioModel _item;
// const RadioItem(this._item, {Key? key}) : super(key: key);
// @override
// Widget build(BuildContext context) {
// return Container(
// margin: const EdgeInsets.all(15.0),
// child: RoundedWhiteContainer(
// borderColor: _item.isSelected ? const Color(0xFF0056D2) : null,
// child: Center(
// child: Column(
// children: [
// SvgPicture.asset(
// _item.svg,
// // color: Theme.of(context).extension<StackColors>()!.textWhite,
// width: 140,
// height: 140,
// ),
// RichText(
// textAlign: TextAlign.center,
// text: TextSpan(
// style: STextStyles.label(context).copyWith(fontSize: 12.0),
// children: [
// TextSpan(
// text: _item.topText,
// style: TextStyle(
// color: Theme.of(context)
// .extension<StackColors>()!
// .textDark,
// fontWeight: FontWeight.bold)),
// TextSpan(text: "\n${_item.bottomText}"),
// ],
// ),
// ),
// ],
// )),
// ),
// );
// }
// }
//
// class RadioModel {
// bool isSelected;
// final String svg;
// final String topText;
// final String bottomText;
//
// RadioModel(this.isSelected, this.svg, this.topText, this.bottomText);
// }

View file

@ -21,6 +21,7 @@ import 'package:stackwallet/utilities/format.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/conditional_parent.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_dialog.dart';
@ -302,68 +303,78 @@ class _TransactionDetailsViewState extends ConsumerState<AllTransactionsView> {
padding: const EdgeInsets.all(4),
child: Row(
children: [
SizedBox(
width: isDesktop ? 570 : null,
child: ClipRRect(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
ConditionalParent(
condition: isDesktop,
builder: (child) => SizedBox(
width: 570,
child: child,
),
child: ConditionalParent(
condition: !isDesktop,
builder: (child) => Expanded(
child: child,
),
child: TextField(
autocorrect: !isDesktop,
enableSuggestions: !isDesktop,
controller: _searchController,
focusNode: searchFieldFocusNode,
onChanged: (value) {
setState(() {
_searchString = value;
});
},
style: isDesktop
? STextStyles.desktopTextExtraSmall(context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textFieldActiveText,
height: 1.8,
)
: STextStyles.field(context),
decoration: standardInputDecoration(
"Search...",
searchFieldFocusNode,
context,
desktopMed: isDesktop,
).copyWith(
prefixIcon: Padding(
padding: EdgeInsets.symmetric(
horizontal: isDesktop ? 12 : 10,
vertical: isDesktop ? 18 : 16,
),
child: SvgPicture.asset(
Assets.svg.search,
width: isDesktop ? 20 : 16,
height: isDesktop ? 20 : 16,
),
),
suffixIcon: _searchController.text.isNotEmpty
? Padding(
padding: const EdgeInsets.only(right: 0),
child: UnconstrainedBox(
child: Row(
children: [
TextFieldIconButton(
child: const XIcon(),
onTap: () async {
setState(() {
_searchController.text = "";
_searchString = "";
});
},
),
],
),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
child: TextField(
autocorrect: !isDesktop,
enableSuggestions: !isDesktop,
controller: _searchController,
focusNode: searchFieldFocusNode,
onChanged: (value) {
setState(() {
_searchString = value;
});
},
style: isDesktop
? STextStyles.desktopTextExtraSmall(context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textFieldActiveText,
height: 1.8,
)
: null,
: STextStyles.field(context),
decoration: standardInputDecoration(
"Search...",
searchFieldFocusNode,
context,
desktopMed: isDesktop,
).copyWith(
prefixIcon: Padding(
padding: EdgeInsets.symmetric(
horizontal: isDesktop ? 12 : 10,
vertical: isDesktop ? 18 : 16,
),
child: SvgPicture.asset(
Assets.svg.search,
width: isDesktop ? 20 : 16,
height: isDesktop ? 20 : 16,
),
),
suffixIcon: _searchController.text.isNotEmpty
? Padding(
padding: const EdgeInsets.only(right: 0),
child: UnconstrainedBox(
child: Row(
children: [
TextFieldIconButton(
child: const XIcon(),
onTap: () async {
setState(() {
_searchController.text = "";
_searchString = "";
});
},
),
],
),
),
)
: null,
),
),
),
),

View file

@ -10,6 +10,8 @@ import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/custom_buttons/draggable_switch_button.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'debug_info_dialog.dart';
class AdvancedSettings extends ConsumerStatefulWidget {
const AdvancedSettings({Key? key}) : super(key: key);
@ -226,16 +228,16 @@ class ShowLogsButton extends ConsumerWidget {
}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
// Future<void> viewDebugLogs() async {
// await showDialog<dynamic>(
// context: context,
// useSafeArea: false,
// barrierDismissible: true,
// builder: (context) {
// return const DebugInfoDialog();
// },
// );
// }
Future<void> viewDebugLogs() async {
await showDialog<dynamic>(
context: context,
useSafeArea: false,
barrierDismissible: true,
builder: (context) {
return const DebugInfoDialog();
},
);
}
return SizedBox(
width: 101,
@ -245,8 +247,7 @@ class ShowLogsButton extends ConsumerWidget {
.extension<StackColors>()!
.getPrimaryEnabledButtonColor(context),
onPressed: () {
//
// viewDebugLogs();
viewDebugLogs();
},
child: Text(
"Show logs",

View file

@ -1,29 +1,33 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/models/isar/models/log.dart';
import 'package:stackwallet/providers/global/debug_service_provider.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/log_level_enum.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
import 'package:stackwallet/widgets/desktop/primary_button.dart';
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
import 'package:stackwallet/widgets/rounded_container.dart';
import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart';
// import '../../../utilities/assets.dart';
// import '../../../utilities/util.dart';
// import '../../../widgets/icon_widgets/x_icon.dart';
// import '../../../widgets/stack_text_field.dart';
// import '../../../widgets/textfield_icon_button.dart';
class DebugInfoDialog extends StatefulWidget {
class DebugInfoDialog extends ConsumerStatefulWidget {
const DebugInfoDialog({Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() => _DebugInfoDialog();
ConsumerState<DebugInfoDialog> createState() => _DebugInfoDialog();
}
class _DebugInfoDialog extends State<DebugInfoDialog> {
final _searchController = TextEditingController();
final _searchFocusNode = FocusNode();
class _DebugInfoDialog extends ConsumerState<DebugInfoDialog> {
late final TextEditingController searchDebugController;
late final FocusNode searchDebugFocusNode;
final scrollController = ScrollController();
@ -62,15 +66,19 @@ class _DebugInfoDialog extends State<DebugInfoDialog> {
@override
void initState() {
// ref.read(debugServiceProvider).updateRecentLogs();
searchDebugController = TextEditingController();
searchDebugFocusNode = FocusNode();
ref.read(debugServiceProvider).updateRecentLogs();
super.initState();
}
@override
void dispose() {
_searchController.dispose();
searchDebugFocusNode.dispose();
searchDebugController.dispose();
scrollController.dispose();
_searchFocusNode.dispose();
super.dispose();
}
@ -78,7 +86,7 @@ class _DebugInfoDialog extends State<DebugInfoDialog> {
@override
Widget build(BuildContext context) {
return DesktopDialog(
maxHeight: 800,
maxHeight: 850,
maxWidth: 600,
child: Column(
children: [
@ -96,68 +104,216 @@ class _DebugInfoDialog extends State<DebugInfoDialog> {
const DesktopDialogCloseButton(),
],
),
Row(
children: [
// ClipRRect(
// borderRadius: BorderRadius.circular(
// Constants.size.circularBorderRadius,
// ),
// child: TextField(
// key: const Key("desktopSettingDebugInfo"),
// autocorrect: Util.isDesktop ? false : true,
// enableSuggestions: Util.isDesktop ? false : true,
// controller: _searchController,
// focusNode: _searchFocusNode,
// // onChanged: (newString) {
// // setState(() => _searchTerm = newString);
// // },
// style: STextStyles.field(context),
// decoration: standardInputDecoration(
// "Search",
// _searchFocusNode,
// context,
// ).copyWith(
// prefixIcon: Padding(
// padding: const EdgeInsets.symmetric(
// horizontal: 10,
// vertical: 16,
// ),
// child: SvgPicture.asset(
// Assets.svg.search,
// width: 16,
// height: 16,
// ),
// ),
// suffixIcon: _searchController.text.isNotEmpty
// ? Padding(
// padding: const EdgeInsets.only(right: 0),
// child: UnconstrainedBox(
// child: Row(
// children: [
// TextFieldIconButton(
// child: const XIcon(),
// onTap: () async {
// setState(() {
// _searchController.text = "";
// _searchTerm = "";
// });
// },
// ),
// ],
// ),
// ),
// )
// : null,
// ),
// ),
// ),
],
Expanded(
flex: 24,
child: NestedScrollView(
floatHeaderSlivers: true,
headerSliverBuilder: (context, innerBoxIsScrolled) {
return [
SliverOverlapAbsorber(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
context),
sliver: SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 16, horizontal: 32),
child: Column(
children: [
Padding(
padding: const EdgeInsets.only(bottom: 16),
child: ClipRRect(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
child: TextField(
autocorrect: Util.isDesktop ? false : true,
enableSuggestions:
Util.isDesktop ? false : true,
controller: searchDebugController,
focusNode: searchDebugFocusNode,
onChanged: (newString) {
setState(() => _searchTerm = newString);
},
style: STextStyles.field(context),
decoration: standardInputDecoration(
"Search",
searchDebugFocusNode,
context,
).copyWith(
prefixIcon: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 16,
),
child: SvgPicture.asset(
Assets.svg.search,
width: 16,
height: 16,
),
),
suffixIcon: searchDebugController
.text.isNotEmpty
? Padding(
padding:
const EdgeInsets.only(right: 0),
child: UnconstrainedBox(
child: Row(
children: [
TextFieldIconButton(
child: const XIcon(),
onTap: () async {
setState(() {
searchDebugController
.text = "";
_searchTerm = "";
});
},
),
],
),
),
)
: null,
),
),
),
),
const SizedBox(
height: 12,
),
],
),
),
),
),
];
},
body: Builder(
builder: (context) {
final logs = filtered(
ref.watch(debugServiceProvider
.select((value) => value.recentLogs)),
_searchTerm)
.reversed
.toList(growable: false);
return CustomScrollView(
reverse: true,
// shrinkWrap: true,
controller: scrollController,
slivers: [
SliverOverlapInjector(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
context,
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
final log = logs[index];
return Container(
key: Key(
"log_${log.id}_${log.timestampInMillisUTC}"),
decoration: BoxDecoration(
color: Theme.of(context)
.extension<StackColors>()!
.popupBG,
borderRadius: _borderRadius(index, logs.length),
),
child: Padding(
padding: const EdgeInsets.all(4),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 32),
child: RoundedContainer(
padding: const EdgeInsets.all(0),
color: Theme.of(context)
.extension<StackColors>()!
.popupBG,
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
" [${log.logLevel.name}]",
style: STextStyles.baseXS(context)
.copyWith(
fontSize: 8,
color: (log.logLevel ==
LogLevel.Info
? Theme.of(context)
.extension<
StackColors>()!
.topNavIconGreen
: (log.logLevel ==
LogLevel.Warning
? Theme.of(context)
.extension<
StackColors>()!
.topNavIconYellow
: (log.logLevel ==
LogLevel.Error
? Colors.orange
: Theme.of(context)
.extension<
StackColors>()!
.topNavIconRed))),
),
),
Text(
"[${DateTime.fromMillisecondsSinceEpoch(log.timestampInMillisUTC, isUtc: true)}]: ",
style: STextStyles.baseXS(context)
.copyWith(
fontSize: 12,
color: Theme.of(context)
.extension<StackColors>()!
.textDark3,
),
),
],
),
Row(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
const SizedBox(
width: 20,
),
Flexible(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
SelectableText(
log.message,
style: STextStyles.baseXS(
context)
.copyWith(
fontSize: 11.5),
),
],
),
),
],
),
],
),
),
),
),
);
},
childCount: logs.length,
),
),
],
);
},
),
),
),
// Column(
// children: [
//
// ],
// ),
const Spacer(),
Padding(
padding: const EdgeInsets.all(32),

View file

@ -1,371 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/providers/global/base_currencies_provider.dart';
import 'package:stackwallet/providers/global/prefs_provider.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
import 'package:stackwallet/widgets/desktop/primary_button.dart';
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
import 'package:stackwallet/widgets/rounded_container.dart';
import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart';
class CurrencyDialog extends ConsumerStatefulWidget {
const CurrencyDialog({Key? key}) : super(key: key);
@override
ConsumerState<CurrencyDialog> createState() => _CurrencyDialog();
}
class _CurrencyDialog extends ConsumerState<CurrencyDialog> {
late String current;
late List<String> currenciesWithoutSelected;
late final TextEditingController searchCurrencyController;
late final FocusNode searchCurrencyFocusNode;
void onTap(int index) {
if (currenciesWithoutSelected[index] == current || current.isEmpty) {
// ignore if already selected currency
return;
}
current = currenciesWithoutSelected[index];
currenciesWithoutSelected.remove(current);
currenciesWithoutSelected.insert(0, current);
ref.read(prefsChangeNotifierProvider).currency = current;
}
BorderRadius? _borderRadius(int index) {
if (index == 0 && currenciesWithoutSelected.length == 1) {
return BorderRadius.circular(
Constants.size.circularBorderRadius,
);
} else if (index == 0) {
return BorderRadius.vertical(
top: Radius.circular(
Constants.size.circularBorderRadius,
),
);
} else if (index == currenciesWithoutSelected.length - 1) {
return BorderRadius.vertical(
bottom: Radius.circular(
Constants.size.circularBorderRadius,
),
);
}
return null;
}
String filter = "";
List<String> _filtered() {
final currencyMap = ref.read(baseCurrenciesProvider).map;
return currenciesWithoutSelected.where((element) {
return element.toLowerCase().contains(filter.toLowerCase()) ||
(currencyMap[element]?.toLowerCase().contains(filter.toLowerCase()) ??
false);
}).toList();
}
@override
void initState() {
searchCurrencyController = TextEditingController();
searchCurrencyFocusNode = FocusNode();
super.initState();
}
@override
void dispose() {
searchCurrencyController.dispose();
searchCurrencyFocusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
current = ref
.watch(prefsChangeNotifierProvider.select((value) => value.currency));
currenciesWithoutSelected = ref
.watch(baseCurrenciesProvider.select((value) => value.map))
.keys
.toList();
if (current.isNotEmpty) {
currenciesWithoutSelected.remove(current);
currenciesWithoutSelected.insert(0, current);
}
currenciesWithoutSelected = _filtered();
return DesktopDialog(
maxHeight: 800,
maxWidth: 600,
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(
padding: const EdgeInsets.all(32),
child: Text(
"Select currency",
style: STextStyles.desktopH3(context),
textAlign: TextAlign.center,
),
),
const DesktopDialogCloseButton(),
],
),
Expanded(
flex: 24,
child: NestedScrollView(
floatHeaderSlivers: true,
headerSliverBuilder: (context, innerBoxIsScrolled) {
return [
SliverOverlapAbsorber(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
context),
sliver: SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 16, horizontal: 32),
child: Column(
children: [
Padding(
padding: const EdgeInsets.only(bottom: 16),
child: ClipRRect(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
child: TextField(
autocorrect: Util.isDesktop ? false : true,
enableSuggestions:
Util.isDesktop ? false : true,
controller: searchCurrencyController,
focusNode: searchCurrencyFocusNode,
onChanged: (newString) {
setState(() => filter = newString);
},
style: STextStyles.field(context),
decoration: standardInputDecoration(
"Search",
searchCurrencyFocusNode,
context,
).copyWith(
prefixIcon: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 16,
),
child: SvgPicture.asset(
Assets.svg.search,
width: 16,
height: 16,
),
),
suffixIcon: searchCurrencyController
.text.isNotEmpty
? Padding(
padding:
const EdgeInsets.only(right: 0),
child: UnconstrainedBox(
child: Row(
children: [
TextFieldIconButton(
child: const XIcon(),
onTap: () async {
setState(() {
searchCurrencyController
.text = "";
filter = "";
});
},
),
],
),
),
)
: null,
),
),
),
),
],
),
),
),
),
];
},
body: Builder(
builder: (context) {
return CustomScrollView(
slivers: [
SliverOverlapInjector(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
context,
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return Container(
decoration: BoxDecoration(
color: Theme.of(context)
.extension<StackColors>()!
.popupBG,
borderRadius: _borderRadius(index),
),
child: Padding(
padding: const EdgeInsets.all(4),
key: Key(
"desktopSettingsCurrencySelect_${currenciesWithoutSelected[index]}"),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 32),
child: RoundedContainer(
padding: const EdgeInsets.all(0),
color: currenciesWithoutSelected[index] ==
current
? Theme.of(context)
.extension<StackColors>()!
.currencyListItemBG
: Theme.of(context)
.extension<StackColors>()!
.popupBG,
child: RawMaterialButton(
onPressed: () async {
onTap(index);
},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Row(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
SizedBox(
width: 20,
height: 20,
child: Radio(
activeColor: Theme.of(context)
.extension<StackColors>()!
.radioButtonIconEnabled,
materialTapTargetSize:
MaterialTapTargetSize
.shrinkWrap,
value: true,
groupValue:
currenciesWithoutSelected[
index] ==
current,
onChanged: (_) {
onTap(index);
},
),
),
const SizedBox(
width: 12,
),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
currenciesWithoutSelected[
index],
key: (currenciesWithoutSelected[
index] ==
current)
? const Key(
"desktopSettingsSelectedCurrencyText")
: null,
style:
STextStyles.largeMedium14(
context),
),
const SizedBox(
height: 2,
),
Text(
ref.watch(baseCurrenciesProvider
.select((value) =>
value.map))[
currenciesWithoutSelected[
index]] ??
"",
key: (currenciesWithoutSelected[
index] ==
current)
? const Key(
"desktopSelectedCurrencyTextDescription")
: null,
style:
STextStyles.itemSubtitle(
context),
),
],
),
],
),
),
),
),
),
),
);
},
childCount: currenciesWithoutSelected.length,
),
),
],
);
},
),
),
),
const Spacer(),
Padding(
padding: const EdgeInsets.all(32),
child: Row(
children: [
Expanded(
child: SecondaryButton(
label: "Cancel",
onPressed: () {
Navigator.of(context).pop();
},
),
),
const SizedBox(
width: 16,
),
Expanded(
child: PrimaryButton(
label: "Save Changes",
onPressed: () {},
),
)
],
),
),
],
),
);
}
}

View file

@ -1,14 +1,14 @@
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/pages/settings_views/global_settings_view/currency_view.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'currency_dialog.dart';
class CurrencySettings extends ConsumerStatefulWidget {
const CurrencySettings({Key? key}) : super(key: key);
@ -84,19 +84,51 @@ class NewPasswordButton extends ConsumerWidget {
const NewPasswordButton({
Key? key,
}) : super(key: key);
Future<void> chooseCurrency(BuildContext context) async {
// await showDialog<dynamic>(
// context: context,
// useSafeArea: false,
// barrierDismissible: true,
// builder: (context) {
// return CurrencyDialog();
// },
// );
await showDialog<dynamic>(
context: context,
useSafeArea: false,
barrierDismissible: true,
builder: (context) {
return DesktopDialog(
maxHeight: 800,
maxWidth: 600,
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(
padding: const EdgeInsets.all(32),
child: Text(
"Select currency",
style: STextStyles.desktopH3(context),
textAlign: TextAlign.center,
),
),
const DesktopDialogCloseButton(),
],
),
const Expanded(
child: BaseCurrencySettingsView(),
),
],
),
);
},
);
}
@override
Widget build(BuildContext context, WidgetRef ref) {
Future<void> chooseCurrency() async {
await showDialog<dynamic>(
context: context,
useSafeArea: false,
barrierDismissible: true,
builder: (context) {
return CurrencyDialog();
},
);
}
return SizedBox(
width: 200,
height: 48,
@ -105,7 +137,7 @@ class NewPasswordButton extends ConsumerWidget {
.extension<StackColors>()!
.getPrimaryEnabledButtonColor(context),
onPressed: () {
chooseCurrency();
chooseCurrency(context);
},
child: Text(
"Change currency",

View file

@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/language_settings/language_dialog.dart';
@ -86,19 +85,20 @@ class ChangeLanguageButton extends ConsumerWidget {
const ChangeLanguageButton({
Key? key,
}) : super(key: key);
Future<void> chooseLanguage(BuildContext context) async {
await showDialog<dynamic>(
context: context,
useSafeArea: false,
barrierDismissible: true,
builder: (context) {
return const LanguageDialog();
},
);
}
@override
Widget build(BuildContext context, WidgetRef ref) {
Future<void> chooseLanguage() async {
await showDialog<dynamic>(
context: context,
useSafeArea: false,
barrierDismissible: true,
builder: (context) {
return LanguageDialog();
},
);
}
return SizedBox(
width: 200,
height: 48,
@ -107,7 +107,7 @@ class ChangeLanguageButton extends ConsumerWidget {
.extension<StackColors>()!
.getPrimaryEnabledButtonColor(context),
onPressed: () {
chooseLanguage();
chooseLanguage(context);
},
child: Text(
"Change language",

View file

@ -1,15 +1,18 @@
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/pages/settings_views/global_settings_view/manage_nodes_views/coin_nodes_view.dart';
import 'package:stackwallet/providers/global/node_service_provider.dart';
import 'package:stackwallet/providers/global/prefs_provider.dart';
import 'package:stackwallet/route_generator.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:stackwallet/widgets/stack_text_field.dart';
class NodesSettings extends ConsumerStatefulWidget {
const NodesSettings({Key? key}) : super(key: key);
@ -23,15 +26,27 @@ class NodesSettings extends ConsumerStatefulWidget {
class _NodesSettings extends ConsumerState<NodesSettings> {
List<Coin> _coins = [...Coin.values];
late final TextEditingController searchNodeController;
late final FocusNode searchNodeFocusNode;
String filter = "";
@override
void initState() {
_coins = _coins.toList();
_coins.remove(Coin.firoTestNet);
searchNodeController = TextEditingController();
searchNodeFocusNode = FocusNode();
super.initState();
}
@override
void dispose() {
searchNodeController.dispose();
searchNodeFocusNode.dispose();
super.dispose();
}
@ -47,6 +62,7 @@ class _NodesSettings extends ConsumerState<NodesSettings> {
debugPrint("BUILD: $runtimeType");
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.only(
@ -55,6 +71,7 @@ class _NodesSettings extends ConsumerState<NodesSettings> {
child: RoundedWhiteContainer(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
SvgPicture.asset(
Assets.svg.circleNode,
@ -63,6 +80,7 @@ class _NodesSettings extends ConsumerState<NodesSettings> {
),
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.all(10),
@ -85,88 +103,145 @@ class _NodesSettings extends ConsumerState<NodesSettings> {
),
],
),
//TODO: add search bar
SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
...coins.map(
(coin) {
final count = ref
.watch(nodeServiceChangeNotifierProvider
.select((value) => value.getNodesFor(coin)))
.length;
Padding(
padding: const EdgeInsets.all(10.0),
child: ClipRRect(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
child: TextField(
autocorrect: Util.isDesktop ? false : true,
enableSuggestions: Util.isDesktop ? false : true,
controller: searchNodeController,
focusNode: searchNodeFocusNode,
onChanged: (newString) {
setState(() => filter = newString);
},
style: STextStyles.field(context),
decoration: standardInputDecoration(
"Search",
searchNodeFocusNode,
context,
).copyWith(
prefixIcon: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 16,
),
child: SvgPicture.asset(
Assets.svg.search,
width: 16,
height: 16,
),
),
),
),
),
),
Padding(
padding: const EdgeInsets.all(10.0),
child: RoundedWhiteContainer(
padding: const EdgeInsets.all(0),
borderColor:
Theme.of(context).extension<StackColors>()!.background,
child: ListView.separated(
primary: false,
shrinkWrap: true,
itemBuilder: (context, index) {
final coin = coins[index];
final count = ref
.watch(nodeServiceChangeNotifierProvider
.select((value) => value.getNodesFor(coin)))
.length;
return Padding(
padding: const EdgeInsets.all(0),
child: RawMaterialButton(
// splashColor: Theme.of(context).extension<StackColors>()!.highlight,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
// side: BorderSide(
// color: Theme.of(context)
// .extension<StackColors>()!
// .shadow),
),
materialTapTargetSize:
MaterialTapTargetSize.shrinkWrap,
onPressed: () {
Navigator.of(context).pushNamed(
CoinNodesView.routeName,
arguments: coin,
);
},
child: Padding(
padding: const EdgeInsets.all(
12.0,
),
child: Row(
children: [
Row(
children: [
SvgPicture.asset(
Assets.svg.iconFor(coin: coin),
width: 24,
height: 24,
),
const SizedBox(
width: 12,
),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
"${coin.prettyName} nodes",
style: STextStyles.titleBold12(
context),
),
Text(
count > 1
? "$count nodes"
: "Default",
style: STextStyles.label(context),
),
],
),
],
),
Expanded(
child: SvgPicture.asset(
Assets.svg.chevronRight,
alignment: Alignment.centerRight,
),
),
],
),
return Padding(
padding: const EdgeInsets.all(0),
child: RawMaterialButton(
// splashColor: Theme.of(context).extension<StackColors>()!.highlight,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
);
},
materialTapTargetSize:
MaterialTapTargetSize.shrinkWrap,
onPressed: () {
showDialog<void>(
context: context,
builder: (context) => Navigator(
initialRoute: CoinNodesView.routeName,
onGenerateRoute: RouteGenerator.generateRoute,
onGenerateInitialRoutes: (_, __) {
return [
FadePageRoute(
CoinNodesView(
coin: coin,
rootNavigator: true,
),
const RouteSettings(
name: CoinNodesView.routeName,
),
),
];
},
),
);
},
child: Padding(
padding: const EdgeInsets.all(
12.0,
),
child: Row(
children: [
Row(
children: [
SvgPicture.asset(
Assets.svg.iconFor(coin: coin),
width: 24,
height: 24,
),
const SizedBox(
width: 12,
),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
"${coin.prettyName} nodes",
style: STextStyles.titleBold12(
context),
),
Text(
count > 1
? "$count nodes"
: "Default",
style: STextStyles.label(context),
),
],
),
],
),
Expanded(
child: SvgPicture.asset(
Assets.svg.chevronRight,
alignment: Alignment.centerRight,
),
),
],
),
),
),
);
},
separatorBuilder: (context, index) => Container(
height: 1,
color: Theme.of(context)
.extension<StackColors>()!
.background,
),
],
itemCount: coins.length,
),
),
),
],

View file

@ -7,6 +7,8 @@ import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
import '../../../pages/settings_views/global_settings_view/syncing_preferences_views/syncing_options_view.dart';
class SyncingPreferencesSettings extends ConsumerStatefulWidget {
const SyncingPreferencesSettings({Key? key}) : super(key: key);
@ -62,6 +64,13 @@ class _SyncingPreferencesSettings
),
],
),
///TODO: ONLY SHOW SYNC OPTIONS ON BUTTON PRESS
Column(
children: [
SyncingOptionsView(),
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [

View file

@ -1468,6 +1468,20 @@ class StackColors extends ThemeExtension<StackColors> {
}
}
ButtonStyle? getDeleteEnabledButtonColor(BuildContext context) =>
Theme.of(context).textButtonTheme.style?.copyWith(
backgroundColor: MaterialStateProperty.all<Color>(
textFieldErrorBG,
),
);
ButtonStyle? getDeleteDisabledButtonColor(BuildContext context) =>
Theme.of(context).textButtonTheme.style?.copyWith(
backgroundColor: MaterialStateProperty.all<Color>(
buttonBackSecondaryDisabled,
),
);
ButtonStyle? getPrimaryEnabledButtonColor(BuildContext context) =>
Theme.of(context).textButtonTheme.style?.copyWith(
backgroundColor: MaterialStateProperty.all<Color>(

View file

@ -0,0 +1,98 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/desktop/custom_text_button.dart';
class DeleteButton extends StatelessWidget {
const DeleteButton({
Key? key,
this.width,
this.height,
this.label,
this.onPressed,
this.enabled = true,
this.desktopMed = false,
}) : super(key: key);
final double? width;
final double? height;
final String? label;
final VoidCallback? onPressed;
final bool enabled;
final bool desktopMed;
TextStyle getStyle(bool isDesktop, BuildContext context) {
if (isDesktop) {
if (desktopMed) {
return STextStyles.desktopTextExtraSmall(context).copyWith(
color: enabled
? Theme.of(context).extension<StackColors>()!.accentColorRed
: Theme.of(context)
.extension<StackColors>()!
.buttonTextSecondaryDisabled,
);
} else {
return enabled
? STextStyles.desktopButtonSecondaryEnabled(context).copyWith(
color:
Theme.of(context).extension<StackColors>()!.accentColorRed)
: STextStyles.desktopButtonSecondaryDisabled(context);
}
} else {
return STextStyles.button(context).copyWith(
color: enabled
? Theme.of(context).extension<StackColors>()!.accentColorRed
: Theme.of(context)
.extension<StackColors>()!
.buttonTextSecondaryDisabled,
);
}
}
@override
Widget build(BuildContext context) {
final isDesktop = Util.isDesktop;
return CustomTextButtonBase(
height: desktopMed ? 56 : height,
width: width,
textButton: TextButton(
onPressed: enabled ? onPressed : null,
style: enabled
? Theme.of(context)
.extension<StackColors>()!
.getDeleteEnabledButtonColor(context)
: Theme.of(context)
.extension<StackColors>()!
.getDeleteDisabledButtonColor(context),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SvgPicture.asset(
Assets.svg.trash,
width: 20,
height: 20,
color: enabled
? Theme.of(context).extension<StackColors>()!.accentColorRed
: Theme.of(context)
.extension<StackColors>()!
.buttonTextSecondaryDisabled,
),
if (label != null)
const SizedBox(
width: 10,
),
if (label != null)
Text(
label!,
style: getStyle(isDesktop, context),
),
],
),
),
);
}
}

View file

@ -11,7 +11,7 @@ description: Stack Wallet
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.5.13+85
version: 1.5.14+86
environment:
sdk: ">=2.17.0 <3.0.0"