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,8 +106,14 @@ class _CurrencyViewState extends ConsumerState<BaseCurrencySettingsView> {
currenciesWithoutSelected.insert(0, current);
}
currenciesWithoutSelected = _filtered();
final isDesktop = Util.isDesktop;
return ConditionalParent(
condition: !isDesktop,
builder: (child) {
return Scaffold(
backgroundColor: Theme.of(context).extension<StackColors>()!.background,
backgroundColor:
Theme.of(context).extension<StackColors>()!.background,
appBar: AppBar(
leading: AppBarBackButton(
onPressed: () async {
@ -127,6 +137,59 @@ class _CurrencyViewState extends ConsumerState<BaseCurrencySettingsView> {
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,7 +389,9 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> {
.select((value) => value.getNodeById(id: nodeId!)))
: null;
return Scaffold(
return ConditionalParent(
condition: !isDesktop,
builder: (child) => Scaffold(
backgroundColor: Theme.of(context).extension<StackColors>()!.background,
appBar: AppBar(
leading: AppBarBackButton(
@ -228,7 +423,8 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> {
key: const Key("deleteNodeAppBarButtonKey"),
size: 36,
shadows: const [],
color: Theme.of(context).extension<StackColors>()!.background,
color:
Theme.of(context).extension<StackColors>()!.background,
icon: SvgPicture.asset(
Assets.svg.trash,
color: Theme.of(context)
@ -267,6 +463,49 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> {
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: [
@ -293,30 +532,45 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> {
}
},
),
const Spacer(),
TextButton(
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,
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,
),
),
if (isDesktop)
const SizedBox(
width: 16,
),
const SizedBox(height: 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)
@ -325,138 +579,7 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> {
: 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,
onPressed: saveEnabled ? attemptSave : null,
child: Text(
"Save",
style: STextStyles.button(context),
@ -465,12 +588,6 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> {
],
),
),
),
),
);
},
),
),
);
}
}

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,23 +134,34 @@ class _NodeDetailsViewState extends ConsumerState<NodeDetailsView> {
}
if (testPassed) {
unawaited(
showFloatingFlushBar(
type: FlushBarType.success,
message: "Server ping success",
context: context,
),
);
} else {
unawaited(
showFloatingFlushBar(
type: FlushBarType.warning,
message: "Server unreachable",
context: context,
),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
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(
@ -174,7 +193,8 @@ class _NodeDetailsViewState extends ConsumerState<NodeDetailsView> {
key: const Key("nodeDetailsEditNodeAppBarButtonKey"),
size: 36,
shadows: const [],
color: Theme.of(context).extension<StackColors>()!.background,
color:
Theme.of(context).extension<StackColors>()!.background,
icon: SvgPicture.asset(
Assets.svg.pencil,
color: Theme.of(context)
@ -207,9 +227,6 @@ class _NodeDetailsViewState extends ConsumerState<NodeDetailsView> {
),
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),
@ -217,41 +234,141 @@ class _NodeDetailsViewState extends ConsumerState<NodeDetailsView> {
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: true,
readOnly: isDesktop ? _desktopReadOnly : true,
coin: coin,
),
const Spacer(),
TextButton(
style: Theme.of(context)
.extension<StackColors>()!
.getSecondaryEnabledButtonColor(context),
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 {
await _testConnection(ref, context);
Navigator.of(context).pop();
await ref
.read(nodeServiceChangeNotifierProvider)
.delete(
node!.id,
true,
);
},
child: Text(
"Test connection",
style: STextStyles.button(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark),
),
),
const SizedBox(height: 16),
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,8 +20,13 @@ class SyncingOptionsView extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final isDesktop = Util.isDesktop;
return ConditionalParent(
condition: !isDesktop,
builder: (child) {
return Scaffold(
backgroundColor: Theme.of(context).extension<StackColors>()!.background,
backgroundColor:
Theme.of(context).extension<StackColors>()!.background,
appBar: AppBar(
leading: AppBarBackButton(
onPressed: () async {
@ -39,6 +48,15 @@ class SyncingOptionsView extends ConsumerWidget {
minHeight: constraints.maxHeight,
),
child: IntrinsicHeight(
child: child,
),
),
);
},
),
),
);
},
child: Column(
children: [
RoundedWhiteContainer(
@ -50,21 +68,17 @@ class SyncingOptionsView extends ConsumerWidget {
padding: const EdgeInsets.all(4),
child: RawMaterialButton(
// splashColor: Theme.of(context).extension<StackColors>()!.highlight,
materialTapTargetSize:
MaterialTapTargetSize.shrinkWrap,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
onPressed: () {
final state = ref
.read(prefsChangeNotifierProvider)
.syncType;
final state =
ref.read(prefsChangeNotifierProvider).syncType;
if (state != SyncingType.currentWalletOnly) {
ref
.read(prefsChangeNotifierProvider)
.syncType =
ref.read(prefsChangeNotifierProvider).syncType =
SyncingType.currentWalletOnly;
// disable auto sync on all wallets that aren't active/current
@ -83,8 +97,7 @@ class SyncingOptionsView extends ConsumerWidget {
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
crossAxisAlignment:
CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 20,
@ -93,18 +106,15 @@ class SyncingOptionsView extends ConsumerWidget {
activeColor: Theme.of(context)
.extension<StackColors>()!
.radioButtonIconEnabled,
value:
SyncingType.currentWalletOnly,
value: SyncingType.currentWalletOnly,
groupValue: ref.watch(
prefsChangeNotifierProvider
.select((value) =>
value.syncType),
.select((value) => value.syncType),
),
onChanged: (value) {
if (value is SyncingType) {
ref
.read(
prefsChangeNotifierProvider)
.read(prefsChangeNotifierProvider)
.syncType = value;
}
},
@ -115,19 +125,16 @@ class SyncingOptionsView extends ConsumerWidget {
),
Flexible(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Sync only currently open wallet",
style: STextStyles.titleBold12(
context),
style: STextStyles.titleBold12(context),
textAlign: TextAlign.left,
),
Text(
"Sync only the wallet that you are using",
style: STextStyles.itemSubtitle(
context),
style: STextStyles.itemSubtitle(context),
textAlign: TextAlign.left,
),
],
@ -143,30 +150,24 @@ class SyncingOptionsView extends ConsumerWidget {
padding: const EdgeInsets.all(4.0),
child: RawMaterialButton(
// splashColor: Theme.of(context).extension<StackColors>()!.highlight,
materialTapTargetSize:
MaterialTapTargetSize.shrinkWrap,
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 =
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);
.forEach((e) => e.shouldAutoSync = true);
}
},
child: Container(
@ -174,8 +175,7 @@ class SyncingOptionsView extends ConsumerWidget {
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
crossAxisAlignment:
CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 20,
@ -184,18 +184,15 @@ class SyncingOptionsView extends ConsumerWidget {
activeColor: Theme.of(context)
.extension<StackColors>()!
.radioButtonIconEnabled,
value:
SyncingType.allWalletsOnStartup,
value: SyncingType.allWalletsOnStartup,
groupValue: ref.watch(
prefsChangeNotifierProvider
.select((value) =>
value.syncType),
.select((value) => value.syncType),
),
onChanged: (value) {
if (value is SyncingType) {
ref
.read(
prefsChangeNotifierProvider)
.read(prefsChangeNotifierProvider)
.syncType = value;
}
},
@ -206,19 +203,16 @@ class SyncingOptionsView extends ConsumerWidget {
),
Flexible(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Sync all wallets at startup",
style: STextStyles.titleBold12(
context),
style: STextStyles.titleBold12(context),
textAlign: TextAlign.left,
),
Text(
"All of your wallets will start syncing when you open the app",
style: STextStyles.itemSubtitle(
context),
style: STextStyles.itemSubtitle(context),
textAlign: TextAlign.left,
),
],
@ -234,22 +228,17 @@ class SyncingOptionsView extends ConsumerWidget {
padding: const EdgeInsets.all(4),
child: RawMaterialButton(
// splashColor: Theme.of(context).extension<StackColors>()!.highlight,
materialTapTargetSize:
MaterialTapTargetSize.shrinkWrap,
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 =
final state =
ref.read(prefsChangeNotifierProvider).syncType;
if (state != SyncingType.selectedWalletsAtStartup) {
ref.read(prefsChangeNotifierProvider).syncType =
SyncingType.selectedWalletsAtStartup;
final ids = ref
@ -260,8 +249,8 @@ class SyncingOptionsView extends ConsumerWidget {
ref
.read(walletsChangeNotifierProvider)
.managers
.forEach((e) => e.shouldAutoSync =
ids.contains(e.walletId));
.forEach((e) =>
e.shouldAutoSync = ids.contains(e.walletId));
}
},
child: Container(
@ -269,8 +258,7 @@ class SyncingOptionsView extends ConsumerWidget {
child: Padding(
padding: const EdgeInsets.all(8),
child: Row(
crossAxisAlignment:
CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 20,
@ -279,18 +267,15 @@ class SyncingOptionsView extends ConsumerWidget {
activeColor: Theme.of(context)
.extension<StackColors>()!
.radioButtonIconEnabled,
value: SyncingType
.selectedWalletsAtStartup,
value: SyncingType.selectedWalletsAtStartup,
groupValue: ref.watch(
prefsChangeNotifierProvider
.select((value) =>
value.syncType),
.select((value) => value.syncType),
),
onChanged: (value) {
if (value is SyncingType) {
ref
.read(
prefsChangeNotifierProvider)
.read(prefsChangeNotifierProvider)
.syncType = value;
}
},
@ -301,19 +286,16 @@ class SyncingOptionsView extends ConsumerWidget {
),
Flexible(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Sync only selected wallets at startup",
style: STextStyles.titleBold12(
context),
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),
style: STextStyles.itemSubtitle(context),
textAlign: TextAlign.left,
),
],
@ -343,8 +325,7 @@ class SyncingOptionsView extends ConsumerWidget {
bottom: 12,
),
child: Row(
crossAxisAlignment:
CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
width: 12 + 20,
@ -357,23 +338,58 @@ class SyncingOptionsView extends ConsumerWidget {
MaterialTapTargetSize.shrinkWrap,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
Constants
.size.circularBorderRadius,
Constants.size.circularBorderRadius,
),
),
onPressed: () {
Navigator.of(context).pushNamed(
WalletSyncingOptionsView
.routeName);
!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,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Select wallets...",
style:
STextStyles.link2(context),
style: STextStyles.link2(context),
textAlign: TextAlign.left,
),
],
@ -389,12 +405,6 @@ class SyncingOptionsView extends ConsumerWidget {
),
],
),
),
),
);
},
),
),
);
}
}

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,8 +27,13 @@ class WalletSyncingOptionsView extends ConsumerWidget {
final managers = ref
.watch(walletsChangeNotifierProvider.select((value) => value.managers));
final isDesktop = Util.isDesktop;
return ConditionalParent(
condition: !isDesktop,
builder: (child) {
return Scaffold(
backgroundColor: Theme.of(context).extension<StackColors>()!.background,
backgroundColor:
Theme.of(context).extension<StackColors>()!.background,
appBar: AppBar(
leading: AppBarBackButton(
onPressed: () async {
@ -41,14 +48,26 @@ class WalletSyncingOptionsView extends ConsumerWidget {
),
),
),
body: LayoutBuilder(builder: (context, constraints) {
return Padding(
body: Padding(
padding: const EdgeInsets.only(
left: 12,
top: 12,
right: 12,
),
child: SingleChildScrollView(
child: child,
),
);
},
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,6 +71,20 @@ class _StackPrivacyCalls extends ConsumerState<StackPrivacyCalls> {
),
),
body: SafeArea(
child: ConditionalParent(
condition: !isDesktop,
builder: (child) => LayoutBuilder(
builder: (context, constraints) => SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: constraints.maxHeight,
),
child: IntrinsicHeight(
child: child,
),
),
),
),
child: Padding(
padding: EdgeInsets.fromLTRB(0, isDesktop ? 0 : 40, 0, 0),
child: ConstrainedBox(
@ -248,6 +263,7 @@ class _StackPrivacyCalls extends ConsumerState<StackPrivacyCalls> {
),
),
),
),
);
}
}
@ -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,8 +303,17 @@ class _TransactionDetailsViewState extends ConsumerState<AllTransactionsView> {
padding: const EdgeInsets.all(4),
child: Row(
children: [
SizedBox(
width: isDesktop ? 570 : null,
ConditionalParent(
condition: isDesktop,
builder: (child) => SizedBox(
width: 570,
child: child,
),
child: ConditionalParent(
condition: !isDesktop,
builder: (child) => Expanded(
child: child,
),
child: ClipRRect(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
@ -368,6 +378,7 @@ class _TransactionDetailsViewState extends ConsumerState<AllTransactionsView> {
),
),
),
),
if (isDesktop)
const SizedBox(
width: 20,

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(
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: [
// 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,
// ),
// ),
// ),
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 = "";
});
},
),
],
),
// Column(
// children: [
//
// ],
// ),
),
)
: 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,
),
),
],
);
},
),
),
),
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);
@override
Widget build(BuildContext context, WidgetRef ref) {
Future<void> chooseCurrency() async {
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 CurrencyDialog();
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) {
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);
@override
Widget build(BuildContext context, WidgetRef ref) {
Future<void> chooseLanguage() async {
Future<void> chooseLanguage(BuildContext context) async {
await showDialog<dynamic>(
context: context,
useSafeArea: false,
barrierDismissible: true,
builder: (context) {
return LanguageDialog();
return const LanguageDialog();
},
);
}
@override
Widget build(BuildContext context, WidgetRef ref) {
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,13 +103,52 @@ class _NodesSettings extends ConsumerState<NodesSettings> {
),
],
),
//TODO: add search bar
SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
...coins.map(
(coin) {
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)))
@ -105,17 +162,29 @@ class _NodesSettings extends ConsumerState<NodesSettings> {
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,
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(
@ -165,8 +234,14 @@ class _NodesSettings extends ConsumerState<NodesSettings> {
),
);
},
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"