Merge pull request #251 from cypherstack/desktop

Desktop
This commit is contained in:
Diego Salazar 2022-11-29 18:20:10 -07:00 committed by GitHub
commit 972494fc94
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 1664 additions and 348 deletions

View file

@ -77,12 +77,12 @@ void main() async {
} }
Screen? screen; Screen? screen;
if (Platform.isLinux || Util.isDesktop) { if (Platform.isLinux || (Util.isDesktop && !Platform.isIOS)) {
screen = await getCurrentScreen(); screen = await getCurrentScreen();
Util.screenWidth = screen?.frame.width; Util.screenWidth = screen?.frame.width;
} }
if (Util.isDesktop) { if (Util.isDesktop && !Platform.isIOS) {
setWindowTitle('Stack Wallet'); setWindowTitle('Stack Wallet');
setWindowMinSize(const Size(1220, 100)); setWindowMinSize(const Size(1220, 100));
setWindowMaxSize(Size.infinite); setWindowMaxSize(Size.infinite);

View file

@ -33,6 +33,19 @@ class AddressEntryData extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
bool get isEmpty {
if (address != null && address!.isNotEmpty) {
return false;
}
if (addressLabel != null && addressLabel!.isNotEmpty) {
return false;
}
if (coin != null) {
return false;
}
return true;
}
bool get isValid { bool get isValid {
if (_address == null || coin == null || _addressLabel == null) { if (_address == null || coin == null || _addressLabel == null) {
return false; return false;

View file

@ -2,13 +2,16 @@ import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_view/new_wallet_recovery_phrase_view.dart'; import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_view/new_wallet_recovery_phrase_view.dart';
import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/recovery_phrase_explanation_dialog.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/exit_to_my_stack_button.dart'; import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/exit_to_my_stack_button.dart';
import 'package:stackwallet/providers/global/secure_store_provider.dart'; import 'package:stackwallet/providers/global/secure_store_provider.dart';
import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/services/coins/coin_service.dart'; import 'package:stackwallet/services/coins/coin_service.dart';
import 'package:stackwallet/services/coins/manager.dart'; import 'package:stackwallet/services/coins/manager.dart';
import 'package:stackwallet/services/transaction_notification_tracker.dart'; import 'package:stackwallet/services/transaction_notification_tracker.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/default_nodes.dart'; import 'package:stackwallet/utilities/default_nodes.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
@ -20,6 +23,7 @@ import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart'; import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart'; import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
import 'package:stackwallet/widgets/loading_indicator.dart'; import 'package:stackwallet/widgets/loading_indicator.dart';
import 'package:stackwallet/widgets/rounded_container.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:tuple/tuple.dart'; import 'package:tuple/tuple.dart';
@ -74,6 +78,31 @@ class _NewWalletRecoveryPhraseWarningViewState
) )
: AppBar( : AppBar(
leading: const AppBarBackButton(), leading: const AppBarBackButton(),
actions: [
Padding(
padding: const EdgeInsets.only(
top: 10,
bottom: 10,
right: 10,
),
child: AppBarIconButton(
icon: SvgPicture.asset(
Assets.svg.circleQuestion,
width: 20,
height: 20,
color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark,
),
onPressed: () async {
await showDialog<void>(
context: context,
builder: (context) => const RecoveryPhraseExplanationDialog(),
);
},
),
)
],
), ),
body: Padding( body: Padding(
padding: EdgeInsets.all(isDesktop ? 0 : 16), padding: EdgeInsets.all(isDesktop ? 0 : 16),
@ -113,17 +142,182 @@ class _NewWalletRecoveryPhraseWarningViewState
height: isDesktop ? 32 : 16, height: isDesktop ? 32 : 16,
), ),
RoundedWhiteContainer( RoundedWhiteContainer(
padding: isDesktop padding: const EdgeInsets.all(32),
? const EdgeInsets.all(32)
: const EdgeInsets.all(12),
width: isDesktop ? 480 : null, width: isDesktop ? 480 : null,
child: Text( child: isDesktop
? Text(
"On the next screen you will see $_numberOfPhraseWords words that make up your recovery phrase.\n\nPlease write it down. Keep it safe and never share it with anyone. Your recovery phrase is the only way you can access your funds if you forget your PIN, lose your phone, etc.\n\nStack Wallet does not keep nor is able to restore your recover phrase. Only you have access to your wallet.", "On the next screen you will see $_numberOfPhraseWords words that make up your recovery phrase.\n\nPlease write it down. Keep it safe and never share it with anyone. Your recovery phrase is the only way you can access your funds if you forget your PIN, lose your phone, etc.\n\nStack Wallet does not keep nor is able to restore your recover phrase. Only you have access to your wallet.",
style: isDesktop style: isDesktop
? STextStyles.desktopTextMediumRegular(context) ? STextStyles.desktopTextMediumRegular(context)
: STextStyles.subtitle(context).copyWith( : STextStyles.subtitle(context).copyWith(
fontSize: 12, fontSize: 12,
), ),
)
: Column(
children: [
Text(
"Important",
style: STextStyles.desktopH3(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.accentColorBlue,
),
),
const SizedBox(
height: 24,
),
RichText(
textAlign: TextAlign.center,
text: TextSpan(
style: STextStyles.desktopH3(context)
.copyWith(fontSize: 18),
children: [
TextSpan(
text: "On the next screen you will be given ",
style: STextStyles.desktopH3(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textDark,
fontSize: 18,
),
),
TextSpan(
text: "12 words",
style: STextStyles.desktopH3(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.accentColorBlue,
fontSize: 18,
),
),
TextSpan(
text: ". They are your ",
style: STextStyles.desktopH3(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textDark,
fontSize: 18,
),
),
TextSpan(
text: "recovery phrase",
style: STextStyles.desktopH3(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.accentColorBlue,
fontSize: 18,
),
),
TextSpan(
text: ".",
style: STextStyles.desktopH3(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textDark,
fontSize: 18,
),
),
],
),
),
const SizedBox(
height: 40,
),
Column(
children: [
Row(
children: [
SizedBox(
width: 32,
height: 32,
child: RoundedContainer(
radiusMultiplier: 20,
padding: const EdgeInsets.all(9),
color: Theme.of(context)
.extension<StackColors>()!
.buttonBackSecondary,
child: SvgPicture.asset(
Assets.svg.pencil,
color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark,
),
),
),
const SizedBox(
width: 20,
),
Text(
"Write them down.",
style: STextStyles.navBarTitle(context),
),
],
),
const SizedBox(
height: 30,
),
Row(
children: [
SizedBox(
width: 32,
height: 32,
child: RoundedContainer(
radiusMultiplier: 20,
padding: const EdgeInsets.all(8),
color: Theme.of(context)
.extension<StackColors>()!
.buttonBackSecondary,
child: SvgPicture.asset(
Assets.svg.lock,
color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark,
),
),
),
const SizedBox(
width: 20,
),
Text(
"Keep them safe.",
style: STextStyles.navBarTitle(context),
),
],
),
const SizedBox(
height: 30,
),
Row(
children: [
SizedBox(
width: 32,
height: 32,
child: RoundedContainer(
radiusMultiplier: 20,
padding: const EdgeInsets.all(8),
color: Theme.of(context)
.extension<StackColors>()!
.buttonBackSecondary,
child: SvgPicture.asset(
Assets.svg.eyeSlash,
color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark,
),
),
),
const SizedBox(
width: 20,
),
Text(
"Do not show them to anyone.",
style: STextStyles.navBarTitle(context),
),
],
),
],
)
],
), ),
), ),
if (!isDesktop) const Spacer(), if (!isDesktop) const Spacer(),
@ -150,27 +344,30 @@ class _NewWalletRecoveryPhraseWarningViewState
child: Container( child: Container(
color: Colors.transparent, color: Colors.transparent,
child: Row( child: Row(
crossAxisAlignment: isDesktop crossAxisAlignment: CrossAxisAlignment.start,
? CrossAxisAlignment.start
: CrossAxisAlignment.center,
children: [ children: [
Checkbox( SizedBox(
width: 24,
height: 24,
child: Checkbox(
materialTapTargetSize: materialTapTargetSize:
MaterialTapTargetSize.shrinkWrap, MaterialTapTargetSize.shrinkWrap,
value: ref value: ref
.watch(checkBoxStateProvider.state) .watch(checkBoxStateProvider.state)
.state, .state,
onChanged: (newValue) { onChanged: (newValue) {
ref.read(checkBoxStateProvider.state).state = ref
newValue!; .read(checkBoxStateProvider.state)
.state = newValue!;
}, },
), ),
),
SizedBox( SizedBox(
width: isDesktop ? 14 : 4, width: isDesktop ? 20 : 10,
), ),
Flexible( Flexible(
child: Text( child: Text(
"I understand that if I lose my recovery phrase, I will not be able to access my funds.", "I understand that Stack Wallet does not keep and cannot restore your recovery phrase, and If I lose my recovery phrase, I will not be able to access my funds.",
style: isDesktop style: isDesktop
? STextStyles.desktopTextMedium(context) ? STextStyles.desktopTextMedium(context)
: STextStyles.baseXS(context), : STextStyles.baseXS(context),

View file

@ -0,0 +1,90 @@
import 'package:flutter/material.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
import 'package:stackwallet/widgets/stack_dialog.dart';
class RecoveryPhraseExplanationDialog extends StatelessWidget {
const RecoveryPhraseExplanationDialog({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return StackDialogBase(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: MediaQuery.of(context).size.height -
16 -
16 -
24 -
24 -
24 -
76,
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Recovery phrase explained",
style: STextStyles.titleBold12(context),
),
const SizedBox(
height: 12,
),
Text(
"The car analogy.",
style: STextStyles.titleBold12(context).copyWith(
fontSize: 14,
),
),
const SizedBox(
height: 8,
),
Text(
"You can drive your car when your have your car keys. If you lose your car keys, you cant drive you car. If someone steals your car keys, they can steal your car. If someone copies your car keys, they can also steal your car.",
style: STextStyles.baseXS(context),
),
const SizedBox(
height: 8,
),
Text(
"Cryptocurrency works the same way. These recovery phrase words were about to show you are like the car keys in the metaphor above.",
style: STextStyles.baseXS(context),
),
const SizedBox(
height: 8,
),
Text(
"If you lose these words, you cant access your money. If someone steals these words, they can access and steal your money. If someone copies these words, they can access and steal your money.",
style: STextStyles.baseXS(context),
),
const SizedBox(
height: 8,
),
Text(
"If your funds are lost or stolen because of you dont write down your recovery phrase or keep it safe, then NOBODY, NOT EVEN US, can help you recover your money.",
style: STextStyles.baseXS(context),
),
],
),
),
),
const SizedBox(
height: 24,
),
Row(
children: [
const Spacer(),
Expanded(
child: SecondaryButton(
label: "Close",
onPressed: Navigator.of(context).pop,
),
),
],
),
],
),
);
}
}

View file

@ -168,8 +168,9 @@ class _FixedRateMarketPairCoinSelectionViewState
Constants.size.circularBorderRadius, Constants.size.circularBorderRadius,
), ),
child: TextField( child: TextField(
autocorrect: Util.isDesktop ? false : true, autofocus: isDesktop,
enableSuggestions: Util.isDesktop ? false : true, autocorrect: !isDesktop,
enableSuggestions: !isDesktop,
controller: _searchController, controller: _searchController,
focusNode: _searchFocusNode, focusNode: _searchFocusNode,
onChanged: filter, onChanged: filter,

View file

@ -125,6 +125,7 @@ class _FloatingRateCurrencySelectionViewState
Constants.size.circularBorderRadius, Constants.size.circularBorderRadius,
), ),
child: TextField( child: TextField(
autofocus: isDesktop,
autocorrect: !isDesktop, autocorrect: !isDesktop,
enableSuggestions: !isDesktop, enableSuggestions: !isDesktop,
controller: _searchController, controller: _searchController,

View file

@ -1359,9 +1359,12 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
SizedBox( SizedBox(
height: isDesktop ? 20 : 12, height: isDesktop ? 20 : 12,
), ),
RateTypeToggle( SizedBox(
height: 60,
child: RateTypeToggle(
onChanged: onRateTypeChanged, onChanged: onRateTypeChanged,
), ),
),
if (ref.read(exchangeFormStateProvider).fromAmount != null && if (ref.read(exchangeFormStateProvider).fromAmount != null &&
ref.read(exchangeFormStateProvider).fromAmount != Decimal.zero) ref.read(exchangeFormStateProvider).fromAmount != Decimal.zero)
SizedBox( SizedBox(

View file

@ -1,15 +1,13 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart'; import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart';
import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/utilities/assets.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/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/conditional_parent.dart'; import 'package:stackwallet/widgets/toggle.dart';
import 'package:stackwallet/widgets/rounded_container.dart';
import '../../../utilities/constants.dart';
class RateTypeToggle extends ConsumerWidget { class RateTypeToggle extends ConsumerWidget {
const RateTypeToggle({ const RateTypeToggle({
@ -28,177 +26,203 @@ class RateTypeToggle extends ConsumerWidget {
.select((value) => value.exchangeRateType)) == .select((value) => value.exchangeRateType)) ==
ExchangeRateType.estimated; ExchangeRateType.estimated;
return RoundedContainer( return Toggle(
padding: const EdgeInsets.all(0), onValueChanged: (value) {
color: isDesktop
? Theme.of(context).extension<StackColors>()!.buttonBackSecondary
: Theme.of(context).extension<StackColors>()!.popupBG,
child: Row(
children: [
Expanded(
child: ConditionalParent(
condition: isDesktop,
builder: (child) => MouseRegion(
cursor: estimated
? SystemMouseCursors.basic
: SystemMouseCursors.click,
child: child,
),
child: GestureDetector(
onTap: () {
if (!estimated) { if (!estimated) {
ref.read(prefsChangeNotifierProvider).exchangeRateType = ref.read(prefsChangeNotifierProvider).exchangeRateType =
ExchangeRateType.estimated; ExchangeRateType.estimated;
onChanged?.call(ExchangeRateType.estimated); onChanged?.call(ExchangeRateType.estimated);
} } else {
},
child: RoundedContainer(
padding: isDesktop
? const EdgeInsets.all(17)
: const EdgeInsets.all(12),
color: estimated
? Theme.of(context)
.extension<StackColors>()!
.textFieldDefaultBG
: Colors.transparent,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SvgPicture.asset(
Assets.svg.lockOpen,
width: 12,
height: 14,
color: isDesktop
? estimated
? Theme.of(context)
.extension<StackColors>()!
.accentColorBlue
: Theme.of(context)
.extension<StackColors>()!
.buttonTextSecondary
: estimated
? Theme.of(context)
.extension<StackColors>()!
.textDark
: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
const SizedBox(
width: 5,
),
Text(
"Estimate rate",
style: isDesktop
? STextStyles.desktopTextExtraExtraSmall(context)
.copyWith(
color: estimated
? Theme.of(context)
.extension<StackColors>()!
.accentColorBlue
: Theme.of(context)
.extension<StackColors>()!
.buttonTextSecondary,
)
: STextStyles.smallMed12(context).copyWith(
color: estimated
? Theme.of(context)
.extension<StackColors>()!
.textDark
: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
),
],
),
),
),
),
),
Expanded(
child: ConditionalParent(
condition: isDesktop,
builder: (child) => MouseRegion(
cursor: !estimated
? SystemMouseCursors.basic
: SystemMouseCursors.click,
child: child,
),
child: GestureDetector(
onTap: () {
if (estimated) {
ref.read(prefsChangeNotifierProvider).exchangeRateType =
ExchangeRateType.fixed;
onChanged?.call(ExchangeRateType.fixed); onChanged?.call(ExchangeRateType.fixed);
} }
}, },
child: RoundedContainer( isOn: !estimated,
padding: isDesktop onColor: Theme.of(context).extension<StackColors>()!.textFieldDefaultBG,
? const EdgeInsets.all(17) offColor: isDesktop
: const EdgeInsets.all(12), ? Theme.of(context).extension<StackColors>()!.buttonBackSecondary
color: !estimated : Theme.of(context).extension<StackColors>()!.popupBG,
? Theme.of(context) decoration: BoxDecoration(
.extension<StackColors>()! borderRadius: BorderRadius.circular(
.textFieldDefaultBG Constants.size.circularBorderRadius,
: Colors.transparent,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SvgPicture.asset(
Assets.svg.lock,
width: 12,
height: 14,
color: isDesktop
? !estimated
? Theme.of(context)
.extension<StackColors>()!
.accentColorBlue
: Theme.of(context)
.extension<StackColors>()!
.buttonTextSecondary
: !estimated
? Theme.of(context)
.extension<StackColors>()!
.textDark
: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
const SizedBox(
width: 5,
),
Text(
"Fixed rate",
style: isDesktop
? STextStyles.desktopTextExtraExtraSmall(context)
.copyWith(
color: !estimated
? Theme.of(context)
.extension<StackColors>()!
.accentColorBlue
: Theme.of(context)
.extension<StackColors>()!
.buttonTextSecondary,
)
: STextStyles.smallMed12(context).copyWith(
color: !estimated
? Theme.of(context)
.extension<StackColors>()!
.textDark
: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
), ),
), ),
], onIcon: Assets.svg.lockOpen,
), onText: "Estimate rate",
), offIcon: Assets.svg.lock,
), offText: "Fixed rate",
),
),
],
),
); );
//
// return RoundedContainer(
// padding: const EdgeInsets.all(0),
// color: isDesktop
// ? Theme.of(context).extension<StackColors>()!.buttonBackSecondary
// : Theme.of(context).extension<StackColors>()!.popupBG,
// child: Row(
// children: [
// Expanded(
// child: ConditionalParent(
// condition: isDesktop,
// builder: (child) => MouseRegion(
// cursor: estimated
// ? SystemMouseCursors.basic
// : SystemMouseCursors.click,
// child: child,
// ),
// child: GestureDetector(
// onTap: () {
// if (!estimated) {
// ref.read(prefsChangeNotifierProvider).exchangeRateType =
// ExchangeRateType.estimated;
// onChanged?.call(ExchangeRateType.estimated);
// }
// },
// child: RoundedContainer(
// padding: isDesktop
// ? const EdgeInsets.all(17)
// : const EdgeInsets.all(12),
// color: estimated
// ? Theme.of(context)
// .extension<StackColors>()!
// .textFieldDefaultBG
// : Colors.transparent,
// child: Row(
// mainAxisAlignment: MainAxisAlignment.center,
// children: [
// SvgPicture.asset(
// Assets.svg.lockOpen,
// width: 12,
// height: 14,
// color: isDesktop
// ? estimated
// ? Theme.of(context)
// .extension<StackColors>()!
// .accentColorBlue
// : Theme.of(context)
// .extension<StackColors>()!
// .buttonTextSecondary
// : estimated
// ? Theme.of(context)
// .extension<StackColors>()!
// .textDark
// : Theme.of(context)
// .extension<StackColors>()!
// .textSubtitle1,
// ),
// const SizedBox(
// width: 5,
// ),
// Text(
// "Estimate rate",
// style: isDesktop
// ? STextStyles.desktopTextExtraExtraSmall(context)
// .copyWith(
// color: estimated
// ? Theme.of(context)
// .extension<StackColors>()!
// .accentColorBlue
// : Theme.of(context)
// .extension<StackColors>()!
// .buttonTextSecondary,
// )
// : STextStyles.smallMed12(context).copyWith(
// color: estimated
// ? Theme.of(context)
// .extension<StackColors>()!
// .textDark
// : Theme.of(context)
// .extension<StackColors>()!
// .textSubtitle1,
// ),
// ),
// ],
// ),
// ),
// ),
// ),
// ),
// Expanded(
// child: ConditionalParent(
// condition: isDesktop,
// builder: (child) => MouseRegion(
// cursor: !estimated
// ? SystemMouseCursors.basic
// : SystemMouseCursors.click,
// child: child,
// ),
// child: GestureDetector(
// onTap: () {
// if (estimated) {
// ref.read(prefsChangeNotifierProvider).exchangeRateType =
// ExchangeRateType.fixed;
// onChanged?.call(ExchangeRateType.fixed);
// }
// },
// child: RoundedContainer(
// padding: isDesktop
// ? const EdgeInsets.all(17)
// : const EdgeInsets.all(12),
// color: !estimated
// ? Theme.of(context)
// .extension<StackColors>()!
// .textFieldDefaultBG
// : Colors.transparent,
// child: Row(
// mainAxisAlignment: MainAxisAlignment.center,
// children: [
// SvgPicture.asset(
// Assets.svg.lock,
// width: 12,
// height: 14,
// color: isDesktop
// ? !estimated
// ? Theme.of(context)
// .extension<StackColors>()!
// .accentColorBlue
// : Theme.of(context)
// .extension<StackColors>()!
// .buttonTextSecondary
// : !estimated
// ? Theme.of(context)
// .extension<StackColors>()!
// .textDark
// : Theme.of(context)
// .extension<StackColors>()!
// .textSubtitle1,
// ),
// const SizedBox(
// width: 5,
// ),
// Text(
// "Fixed rate",
// style: isDesktop
// ? STextStyles.desktopTextExtraExtraSmall(context)
// .copyWith(
// color: !estimated
// ? Theme.of(context)
// .extension<StackColors>()!
// .accentColorBlue
// : Theme.of(context)
// .extension<StackColors>()!
// .buttonTextSecondary,
// )
// : STextStyles.smallMed12(context).copyWith(
// color: !estimated
// ? Theme.of(context)
// .extension<StackColors>()!
// .textDark
// : Theme.of(context)
// .extension<StackColors>()!
// .textSubtitle1,
// ),
// ),
// ],
// ),
// ),
// ),
// ),
// ),
// ],
// ),
// );
} }
} }

View file

@ -214,8 +214,9 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
RoundedWhiteContainer( RoundedWhiteContainer(
borderColor: borderColor: Theme.of(context)
Theme.of(context).extension<StackColors>()!.background, .extension<StackColors>()!
.backgroundAppBar,
padding: const EdgeInsets.all(0), padding: const EdgeInsets.all(0),
child: ListView( child: ListView(
primary: false, primary: false,
@ -281,7 +282,7 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
? BoxDecoration( ? BoxDecoration(
color: Theme.of(context) color: Theme.of(context)
.extension<StackColors>()! .extension<StackColors>()!
.background, .backgroundAppBar,
borderRadius: BorderRadius.vertical( borderRadius: BorderRadius.vertical(
top: Radius.circular( top: Radius.circular(
Constants.size.circularBorderRadius, Constants.size.circularBorderRadius,
@ -1115,7 +1116,8 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
const SizedBox( const SizedBox(
height: 4, height: 4,
), ),
Builder(builder: (context) { Builder(
builder: (context) {
late final String url; late final String url;
switch (trade.exchangeName) { switch (trade.exchangeName) {
case ChangeNowExchange.exchangeName: case ChangeNowExchange.exchangeName:
@ -1127,7 +1129,13 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
"https://simpleswap.io/exchange?id=${trade.tradeId}"; "https://simpleswap.io/exchange?id=${trade.tradeId}";
break; break;
} }
return GestureDetector( return ConditionalParent(
condition: isDesktop,
builder: (child) => MouseRegion(
cursor: SystemMouseCursors.click,
child: child,
),
child: GestureDetector(
onTap: () { onTap: () {
launchUrl( launchUrl(
Uri.parse(url), Uri.parse(url),
@ -1138,8 +1146,10 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
url, url,
style: STextStyles.link2(context), style: STextStyles.link2(context),
), ),
),
); );
}), },
),
], ],
), ),
), ),
@ -1188,7 +1198,7 @@ class _Divider extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
height: 1, height: 1,
color: Theme.of(context).extension<StackColors>()!.background, color: Theme.of(context).extension<StackColors>()!.backgroundAppBar,
); );
} }
} }

View file

@ -109,9 +109,7 @@ class _TransactionsListState extends ConsumerState<TransactionsList> {
return [ return [
FadePageRoute( FadePageRoute(
DesktopDialog( DesktopDialog(
// maxHeight: maxHeight: null,
// MediaQuery.of(context).size.height - 64,
maxHeight: double.infinity,
maxWidth: 580, maxWidth: 580,
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,

View file

@ -16,7 +16,6 @@ import 'package:stackwallet/providers/ui/transaction_filter_provider.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/format.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart';

View file

@ -358,7 +358,7 @@ class _TransactionDetailsViewState
borderColor: isDesktop borderColor: isDesktop
? Theme.of(context) ? Theme.of(context)
.extension<StackColors>()! .extension<StackColors>()!
.background .backgroundAppBar
: null, : null,
padding: const EdgeInsets.all(0), padding: const EdgeInsets.all(0),
child: child, child: child,
@ -382,7 +382,7 @@ class _TransactionDetailsViewState
? BoxDecoration( ? BoxDecoration(
color: Theme.of(context) color: Theme.of(context)
.extension<StackColors>()! .extension<StackColors>()!
.background, .backgroundAppBar,
borderRadius: BorderRadius.vertical( borderRadius: BorderRadius.vertical(
top: Radius.circular( top: Radius.circular(
Constants.size.circularBorderRadius, Constants.size.circularBorderRadius,
@ -1387,7 +1387,7 @@ class _Divider extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
height: 1, height: 1,
color: Theme.of(context).extension<StackColors>()!.background, color: Theme.of(context).extension<StackColors>()!.backgroundAppBar,
); );
} }
} }

View file

@ -0,0 +1,569 @@
import 'dart:async';
import 'package:decimal/decimal.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/models/exchange/change_now/exchange_transaction_status.dart';
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
import 'package:stackwallet/pages/exchange_view/trade_details_view.dart';
import 'package:stackwallet/providers/exchange/trade_sent_from_stack_lookup_provider.dart';
import 'package:stackwallet/providers/global/trades_service_provider.dart';
import 'package:stackwallet/providers/global/wallets_provider.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.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/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';
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart';
import 'package:tuple/tuple.dart';
import '../../route_generator.dart';
class DesktopAllTradesView extends ConsumerStatefulWidget {
const DesktopAllTradesView({Key? key}) : super(key: key);
static const String routeName = "/desktopAllTrades";
@override
ConsumerState<DesktopAllTradesView> createState() =>
_DesktopAllTradesViewState();
}
class _DesktopAllTradesViewState extends ConsumerState<DesktopAllTradesView> {
late final TextEditingController _searchController;
late final FocusNode searchFieldFocusNode;
String _searchString = "";
List<Tuple2<String, List<Trade>>> groupTransactionsByMonth(
List<Trade> trades) {
Map<String, List<Trade>> map = {};
for (var trade in trades) {
final date = trade.timestamp;
final monthYear = "${Constants.monthMap[date.month]} ${date.year}";
if (map[monthYear] == null) {
map[monthYear] = [];
}
map[monthYear]!.add(trade);
}
List<Tuple2<String, List<Trade>>> result = [];
map.forEach((key, value) {
result.add(Tuple2(key, value));
});
return result;
}
@override
void initState() {
_searchController = TextEditingController();
searchFieldFocusNode = FocusNode();
super.initState();
}
@override
void dispose() {
_searchController.dispose();
searchFieldFocusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return DesktopScaffold(
appBar: DesktopAppBar(
isCompactHeight: true,
background: Theme.of(context).extension<StackColors>()!.popupBG,
leading: Row(
children: [
const SizedBox(
width: 32,
),
AppBarIconButton(
size: 32,
color: Theme.of(context)
.extension<StackColors>()!
.textFieldDefaultBG,
shadows: const [],
icon: SvgPicture.asset(
Assets.svg.arrowLeft,
width: 18,
height: 18,
color: Theme.of(context)
.extension<StackColors>()!
.topNavIconPrimary,
),
onPressed: Navigator.of(context).pop,
),
const SizedBox(
width: 12,
),
Text(
"Trades",
style: STextStyles.desktopH3(context),
),
],
),
),
body: Padding(
padding: const EdgeInsets.only(
left: 20,
top: 20,
right: 20,
),
child: Column(
children: [
Row(
children: [
SizedBox(
width: 570,
child: ClipRRect(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
child: TextField(
autocorrect: false,
enableSuggestions: false,
controller: _searchController,
focusNode: searchFieldFocusNode,
onChanged: (value) {
setState(() {
_searchString = value;
});
},
style:
STextStyles.desktopTextExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textFieldActiveText,
height: 1.8,
),
decoration: standardInputDecoration(
"Search...",
searchFieldFocusNode,
context,
desktopMed: true,
).copyWith(
prefixIcon: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 18,
),
child: SvgPicture.asset(
Assets.svg.search,
width: 20,
height: 20,
),
),
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,
),
),
),
),
],
),
const SizedBox(
height: 8,
),
Expanded(
child: Consumer(
builder: (_, ref, __) {
List<Trade> trades = ref.watch(
tradesServiceProvider.select((value) => value.trades));
if (_searchString.isNotEmpty) {
final term = _searchString.toLowerCase();
trades = trades
.where((e) => e.toString().toLowerCase().contains(term))
.toList(growable: false);
}
final monthlyList = groupTransactionsByMonth(trades);
return ListView.builder(
primary: false,
itemCount: monthlyList.length,
itemBuilder: (_, index) {
final month = monthlyList[index];
return Padding(
padding: const EdgeInsets.all(4),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (index != 0)
const SizedBox(
height: 12,
),
Text(
month.item1,
style: STextStyles.smallMed12(context),
),
const SizedBox(
height: 12,
),
RoundedWhiteContainer(
padding: const EdgeInsets.all(0),
child: ListView.separated(
shrinkWrap: true,
primary: false,
separatorBuilder: (context, _) => Container(
height: 1,
color: Theme.of(context)
.extension<StackColors>()!
.background,
),
itemCount: month.item2.length,
itemBuilder: (context, index) => Padding(
padding: const EdgeInsets.all(4),
child: DesktopTradeRowCard(
key: Key(
"transactionCard_key_${month.item2[index].tradeId}"),
tradeId: month.item2[index].tradeId,
),
),
),
),
],
),
);
},
);
},
),
),
],
),
),
);
}
}
class DesktopTradeRowCard extends ConsumerStatefulWidget {
const DesktopTradeRowCard({
Key? key,
required this.tradeId,
}) : super(key: key);
final String tradeId;
@override
ConsumerState<DesktopTradeRowCard> createState() =>
_DesktopTradeRowCardState();
}
class _DesktopTradeRowCardState extends ConsumerState<DesktopTradeRowCard> {
late final String tradeId;
String _fetchIconAssetForStatus(String statusString, BuildContext context) {
ChangeNowTransactionStatus? status;
try {
if (statusString.toLowerCase().startsWith("waiting")) {
statusString = "waiting";
}
status = changeNowTransactionStatusFromStringIgnoreCase(statusString);
} on ArgumentError catch (_) {
status = ChangeNowTransactionStatus.Failed;
}
switch (status) {
case ChangeNowTransactionStatus.New:
case ChangeNowTransactionStatus.Waiting:
case ChangeNowTransactionStatus.Confirming:
case ChangeNowTransactionStatus.Exchanging:
case ChangeNowTransactionStatus.Sending:
case ChangeNowTransactionStatus.Refunded:
case ChangeNowTransactionStatus.Verifying:
return Assets.svg.txExchangePending(context);
case ChangeNowTransactionStatus.Finished:
return Assets.svg.txExchange(context);
case ChangeNowTransactionStatus.Failed:
return Assets.svg.txExchangeFailed(context);
}
}
@override
void initState() {
tradeId = widget.tradeId;
super.initState();
}
@override
Widget build(BuildContext context) {
final String? txid =
ref.read(tradeSentFromStackLookupProvider).getTxidForTradeId(tradeId);
final List<String>? walletIds = ref
.read(tradeSentFromStackLookupProvider)
.getWalletIdsForTradeId(tradeId);
final trade =
ref.watch(tradesServiceProvider.select((value) => value.get(tradeId)))!;
return Material(
color: Theme.of(context).extension<StackColors>()!.popupBG,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(Constants.size.circularBorderRadius),
),
child: RawMaterialButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
onPressed: () async {
if (txid != null && walletIds != null && walletIds.isNotEmpty) {
final manager = ref
.read(walletsChangeNotifierProvider)
.getManager(walletIds.first);
debugPrint("name: ${manager.walletName}");
// TODO store tx data completely locally in isar so we don't lock up ui here when querying txData
final txData = await manager.transactionData;
final tx = txData.getAllTransactions()[txid];
await showDialog<void>(
context: context,
builder: (context) => DesktopDialog(
maxHeight: MediaQuery.of(context).size.height - 64,
maxWidth: 580,
child: TradeDetailsView(
tradeId: tradeId,
transactionIfSentFromStack: tx,
walletName: manager.walletName,
walletId: walletIds.first,
),
),
);
if (mounted) {
unawaited(
showDialog<void>(
context: context,
builder: (context) => Navigator(
initialRoute: TradeDetailsView.routeName,
onGenerateRoute: RouteGenerator.generateRoute,
onGenerateInitialRoutes: (_, __) {
return [
FadePageRoute(
DesktopDialog(
maxHeight: null,
maxWidth: 580,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.only(
left: 32,
bottom: 16,
),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
"Trade details",
style: STextStyles.desktopH3(context),
),
DesktopDialogCloseButton(
onPressedOverride: Navigator.of(
context,
rootNavigator: true,
).pop,
),
],
),
),
Flexible(
child: SingleChildScrollView(
primary: false,
child: TradeDetailsView(
tradeId: tradeId,
transactionIfSentFromStack: tx,
walletName: manager.walletName,
walletId: walletIds.first,
),
),
),
],
),
),
const RouteSettings(
name: TradeDetailsView.routeName,
),
),
];
},
),
),
);
}
} else {
unawaited(
showDialog<void>(
context: context,
builder: (context) => Navigator(
initialRoute: TradeDetailsView.routeName,
onGenerateRoute: RouteGenerator.generateRoute,
onGenerateInitialRoutes: (_, __) {
return [
FadePageRoute(
DesktopDialog(
maxHeight: null,
maxWidth: 580,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.only(
left: 32,
bottom: 16,
),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
"Trade details",
style: STextStyles.desktopH3(context),
),
DesktopDialogCloseButton(
onPressedOverride: Navigator.of(
context,
rootNavigator: true,
).pop,
),
],
),
),
Flexible(
child: SingleChildScrollView(
primary: false,
child: TradeDetailsView(
tradeId: tradeId,
transactionIfSentFromStack: null,
walletName: null,
walletId: walletIds?.first,
),
),
),
],
),
),
const RouteSettings(
name: TradeDetailsView.routeName,
),
),
];
},
),
),
);
}
},
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 10,
horizontal: 16,
),
child: Row(
children: [
Container(
width: 32,
height: 32,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(32),
),
child: Center(
child: SvgPicture.asset(
_fetchIconAssetForStatus(
trade.status,
context,
),
width: 32,
height: 32,
),
),
),
const SizedBox(
width: 12,
),
Expanded(
flex: 3,
child: Text(
"${trade.payInCurrency.toUpperCase()}${trade.payOutCurrency.toUpperCase()}",
style:
STextStyles.desktopTextExtraExtraSmall(context).copyWith(
color: Theme.of(context).extension<StackColors>()!.textDark,
),
),
),
Expanded(
flex: 4,
child: Text(
Format.extractDateFrom(
trade.timestamp.millisecondsSinceEpoch ~/ 1000),
style: STextStyles.desktopTextExtraExtraSmall(context),
),
),
Expanded(
flex: 6,
child: Text(
"-${Decimal.tryParse(trade.payInAmount)?.toStringAsFixed(8) ?? "..."} ${trade.payInCurrency.toUpperCase()}",
style:
STextStyles.desktopTextExtraExtraSmall(context).copyWith(
color: Theme.of(context).extension<StackColors>()!.textDark,
),
),
),
Expanded(
flex: 4,
child: Text(
trade.exchangeName,
style: STextStyles.desktopTextExtraExtraSmall(context),
),
),
SvgPicture.asset(
Assets.svg.circleInfo,
width: 20,
height: 20,
color:
Theme.of(context).extension<StackColors>()!.textSubtitle2,
),
],
),
),
),
);
}
}

View file

@ -3,19 +3,20 @@ import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/pages/exchange_view/trade_details_view.dart'; import 'package:stackwallet/pages/exchange_view/trade_details_view.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_exchange/desktop_all_trades_view.dart';
import 'package:stackwallet/providers/exchange/trade_sent_from_stack_lookup_provider.dart'; import 'package:stackwallet/providers/exchange/trade_sent_from_stack_lookup_provider.dart';
import 'package:stackwallet/providers/global/trades_service_provider.dart'; import 'package:stackwallet/providers/global/trades_service_provider.dart';
import 'package:stackwallet/providers/global/wallets_provider.dart'; import 'package:stackwallet/providers/global/wallets_provider.dart';
import 'package:stackwallet/route_generator.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/utilities/theme/stack_colors.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:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:stackwallet/widgets/trade_card.dart'; import 'package:stackwallet/widgets/trade_card.dart';
import '../../../route_generator.dart';
import '../../../widgets/desktop/desktop_dialog.dart';
import '../../../widgets/desktop/desktop_dialog_close_button.dart';
class DesktopTradeHistory extends ConsumerStatefulWidget { class DesktopTradeHistory extends ConsumerStatefulWidget {
const DesktopTradeHistory({Key? key}) : super(key: key); const DesktopTradeHistory({Key? key}) : super(key: key);
@ -59,11 +60,23 @@ class _DesktopTradeHistoryState extends ConsumerState<DesktopTradeHistory> {
return Column( return Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
"Exchange details", "Recent trades",
style: STextStyles.desktopTextExtraExtraSmall(context), style: STextStyles.desktopTextExtraExtraSmall(context),
), ),
BlueTextButton(
text: "See all",
onTap: () {
Navigator.of(context)
.pushNamed(DesktopAllTradesView.routeName);
},
),
],
),
const SizedBox( const SizedBox(
height: 16, height: 16,
), ),
@ -126,9 +139,7 @@ class _DesktopTradeHistoryState extends ConsumerState<DesktopTradeHistory> {
return [ return [
FadePageRoute( FadePageRoute(
DesktopDialog( DesktopDialog(
// maxHeight: maxHeight: null,
// MediaQuery.of(context).size.height - 64,
maxHeight: double.infinity,
maxWidth: 580, maxWidth: 580,
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@ -159,6 +170,8 @@ class _DesktopTradeHistoryState extends ConsumerState<DesktopTradeHistory> {
), ),
), ),
Flexible( Flexible(
child: SingleChildScrollView(
primary: false,
child: TradeDetailsView( child: TradeDetailsView(
tradeId: tradeId, tradeId: tradeId,
transactionIfSentFromStack: tx, transactionIfSentFromStack: tx,
@ -166,6 +179,7 @@ class _DesktopTradeHistoryState extends ConsumerState<DesktopTradeHistory> {
walletId: walletIds.first, walletId: walletIds.first,
), ),
), ),
),
], ],
), ),
), ),
@ -189,9 +203,7 @@ class _DesktopTradeHistoryState extends ConsumerState<DesktopTradeHistory> {
return [ return [
FadePageRoute( FadePageRoute(
DesktopDialog( DesktopDialog(
// maxHeight: maxHeight: null,
// MediaQuery.of(context).size.height - 64,
maxHeight: double.infinity,
maxWidth: 580, maxWidth: 580,
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@ -222,13 +234,17 @@ class _DesktopTradeHistoryState extends ConsumerState<DesktopTradeHistory> {
), ),
), ),
Flexible( Flexible(
child: SingleChildScrollView(
primary: false,
child: TradeDetailsView( child: TradeDetailsView(
tradeId: tradeId, tradeId: tradeId,
transactionIfSentFromStack: null, transactionIfSentFromStack:
null,
walletName: null, walletName: null,
walletId: walletIds?.first, walletId: walletIds?.first,
), ),
), ),
),
], ],
), ),
), ),
@ -258,13 +274,26 @@ class _DesktopTradeHistoryState extends ConsumerState<DesktopTradeHistory> {
], ],
); );
} else { } else {
return RoundedWhiteContainer( return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Recent trades",
style: STextStyles.desktopTextExtraExtraSmall(context),
),
const SizedBox(
height: 16,
),
RoundedWhiteContainer(
child: Center( child: Center(
child: Text( child: Text(
"Trades will appear here", "Trades will appear here",
style: STextStyles.desktopTextExtraExtraSmall(context), style: STextStyles.desktopTextExtraExtraSmall(context),
), ),
), ),
),
],
); );
} }
} }

View file

@ -140,7 +140,9 @@ class _DesktopAddressBook extends ConsumerState<DesktopAddressBook> {
ref.watch(addressBookServiceProvider.select((value) => value.contacts)); ref.watch(addressBookServiceProvider.select((value) => value.contacts));
final allContacts = contacts final allContacts = contacts
.where((element) => element.addresses .where((element) =>
element.addresses.isEmpty ||
element.addresses
.where((e) => ref.watch(addressBookFilterProvider .where((e) => ref.watch(addressBookFilterProvider
.select((value) => value.coins.contains(e.coin)))) .select((value) => value.coins.contains(e.coin))))
.isNotEmpty) .isNotEmpty)
@ -149,7 +151,9 @@ class _DesktopAddressBook extends ConsumerState<DesktopAddressBook> {
.toList(); .toList();
final favorites = contacts final favorites = contacts
.where((element) => element.addresses .where((element) =>
element.addresses.isEmpty ||
element.addresses
.where((e) => ref.watch(addressBookFilterProvider .where((e) => ref.watch(addressBookFilterProvider
.select((value) => value.coins.contains(e.coin)))) .select((value) => value.coins.contains(e.coin))))
.isNotEmpty) .isNotEmpty)

View file

@ -5,7 +5,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:stackwallet/pages_desktop_specific/home/desktop_menu_item.dart'; import 'package:stackwallet/pages_desktop_specific/home/desktop_menu_item.dart';
import 'package:stackwallet/providers/desktop/current_desktop_menu_item.dart'; import 'package:stackwallet/providers/desktop/current_desktop_menu_item.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart';
@ -191,29 +190,7 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
), ),
DesktopMenuItem( DesktopMenuItem(
duration: duration, duration: duration,
icon: SvgPicture.asset( icon: const DesktopNotificationsIcon(),
ref.watch(notificationsProvider.select(
(value) => value.hasUnreadNotifications))
? Assets.svg.bellNew(context)
: Assets.svg.bell,
width: 20,
height: 20,
color: ref.watch(notificationsProvider.select(
(value) => value.hasUnreadNotifications))
? null
: DesktopMenuItemId.notifications ==
ref
.watch(currentDesktopMenuItemProvider
.state)
.state
? Theme.of(context)
.extension<StackColors>()!
.accentColorDark
: Theme.of(context)
.extension<StackColors>()!
.accentColorDark
.withOpacity(0.8),
),
label: "Notifications", label: "Notifications",
value: DesktopMenuItemId.notifications, value: DesktopMenuItemId.notifications,
onChanged: updateSelectedMenuItem, onChanged: updateSelectedMenuItem,

View file

@ -1,6 +1,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/pages_desktop_specific/home/desktop_menu.dart';
import 'package:stackwallet/providers/desktop/current_desktop_menu_item.dart'; import 'package:stackwallet/providers/desktop/current_desktop_menu_item.dart';
import 'package:stackwallet/providers/global/notifications_provider.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart';
@ -11,6 +15,39 @@ class DMIController {
} }
} }
class DesktopNotificationsIcon extends ConsumerStatefulWidget {
const DesktopNotificationsIcon({Key? key}) : super(key: key);
@override
ConsumerState<DesktopNotificationsIcon> createState() =>
_DesktopNotificationsIconState();
}
class _DesktopNotificationsIconState
extends ConsumerState<DesktopNotificationsIcon> {
@override
Widget build(BuildContext context) {
return SvgPicture.asset(
ref.watch(notificationsProvider
.select((value) => value.hasUnreadNotifications))
? Assets.svg.bellNew(context)
: Assets.svg.bell,
width: 20,
height: 20,
color: ref.watch(notificationsProvider
.select((value) => value.hasUnreadNotifications))
? null
: DesktopMenuItemId.notifications ==
ref.watch(currentDesktopMenuItemProvider.state).state
? Theme.of(context).extension<StackColors>()!.accentColorDark
: Theme.of(context)
.extension<StackColors>()!
.accentColorDark
.withOpacity(0.8),
);
}
}
class DesktopMenuItem<T> extends ConsumerStatefulWidget { class DesktopMenuItem<T> extends ConsumerStatefulWidget {
const DesktopMenuItem({ const DesktopMenuItem({
Key? key, Key? key,

View file

@ -6,7 +6,6 @@ import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/desktop_attention_delete_wallet.dart'; import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/desktop_attention_delete_wallet.dart';
import 'package:stackwallet/providers/desktop/storage_crypto_handler_provider.dart'; import 'package:stackwallet/providers/desktop/storage_crypto_handler_provider.dart';
import 'package:stackwallet/providers/global/wallets_provider.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
@ -65,14 +64,8 @@ class _DesktopDeleteWalletDialog
.verifyPassphrase(passwordController.text); .verifyPassphrase(passwordController.text);
if (verified) { if (verified) {
Navigator.of(context, rootNavigator: true).pop();
final words = await ref
.read(walletsChangeNotifierProvider)
.getManager(widget.walletId)
.mnemonic;
if (mounted) { if (mounted) {
Navigator.of(context, rootNavigator: true).pop();
Navigator.of(context).pop(); Navigator.of(context).pop();
unawaited( unawaited(
@ -83,6 +76,7 @@ class _DesktopDeleteWalletDialog
); );
} }
} else { } else {
if (mounted) {
Navigator.of(context, rootNavigator: true).pop(); Navigator.of(context, rootNavigator: true).pop();
await Future<void>.delayed(const Duration(milliseconds: 300)); await Future<void>.delayed(const Duration(milliseconds: 300));
@ -96,6 +90,7 @@ class _DesktopDeleteWalletDialog
); );
} }
} }
}
@override @override
void initState() { void initState() {
@ -157,7 +152,9 @@ class _DesktopDeleteWalletDialog
key: const Key("desktopDeleteWalletPasswordFieldKey"), key: const Key("desktopDeleteWalletPasswordFieldKey"),
focusNode: passwordFocusNode, focusNode: passwordFocusNode,
controller: passwordController, controller: passwordController,
style: STextStyles.field(context), style: STextStyles.desktopTextMedium(context).copyWith(
height: 2,
),
obscureText: hidePassword, obscureText: hidePassword,
enableSuggestions: false, enableSuggestions: false,
autocorrect: false, autocorrect: false,
@ -240,7 +237,7 @@ class _DesktopDeleteWalletDialog
onPressed: _continueEnabled onPressed: _continueEnabled
? () async { ? () async {
// add loading indicator // add loading indicator
enterPassphrase(); await enterPassphrase();
} }
: null, : null,
), ),

View file

@ -5,10 +5,19 @@ final validContactStateProvider =
StateProvider.autoDispose.family<bool, List<int>>((ref, ids) { StateProvider.autoDispose.family<bool, List<int>>((ref, ids) {
bool isValid = true; bool isValid = true;
bool hasAtLeastOneValid = false;
for (int i = 0; i < ids.length; i++) { for (int i = 0; i < ids.length; i++) {
isValid = isValid && final _valid = ref.watch(
ref.watch(
addressEntryDataProvider(ids[i]).select((value) => value.isValid)); addressEntryDataProvider(ids[i]).select((value) => value.isValid));
final _isEmpty = ref.watch(
addressEntryDataProvider(ids[i]).select((value) => value.isEmpty));
isValid = isValid && (_valid || _isEmpty);
if (_valid) {
hasAtLeastOneValid = true;
} }
return isValid; }
return isValid && hasAtLeastOneValid;
}); });

View file

@ -85,6 +85,7 @@ import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_sear
import 'package:stackwallet/pages/wallet_view/wallet_view.dart'; import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
import 'package:stackwallet/pages/wallets_view/wallets_view.dart'; import 'package:stackwallet/pages/wallets_view/wallets_view.dart';
import 'package:stackwallet/pages_desktop_specific/create_password/create_password_view.dart'; import 'package:stackwallet/pages_desktop_specific/create_password/create_password_view.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_exchange/desktop_all_trades_view.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_exchange/desktop_exchange_view.dart'; import 'package:stackwallet/pages_desktop_specific/desktop_exchange/desktop_exchange_view.dart';
import 'package:stackwallet/pages_desktop_specific/forgot_password_desktop_view.dart'; import 'package:stackwallet/pages_desktop_specific/forgot_password_desktop_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/address_book_view/desktop_address_book.dart'; import 'package:stackwallet/pages_desktop_specific/home/address_book_view/desktop_address_book.dart';
@ -96,12 +97,14 @@ import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_vie
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/desktop_attention_delete_wallet.dart'; import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/desktop_attention_delete_wallet.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/desktop_delete_wallet_dialog.dart'; import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/desktop_delete_wallet_dialog.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/qr_code_desktop_popup_content.dart'; import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/qr_code_desktop_popup_content.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/unlock_wallet_keys_desktop.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/wallet_keys_desktop_popup.dart'; import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/wallet_keys_desktop_popup.dart';
import 'package:stackwallet/pages_desktop_specific/home/notifications/desktop_notifications_view.dart'; import 'package:stackwallet/pages_desktop_specific/home/notifications/desktop_notifications_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/advanced_settings/advanced_settings.dart'; import 'package:stackwallet/pages_desktop_specific/home/settings_menu/advanced_settings/advanced_settings.dart';
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/appearance_settings.dart'; import 'package:stackwallet/pages_desktop_specific/home/settings_menu/appearance_settings.dart';
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/backup_and_restore/backup_and_restore_settings.dart'; import 'package:stackwallet/pages_desktop_specific/home/settings_menu/backup_and_restore/backup_and_restore_settings.dart';
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/currency_settings/currency_settings.dart'; import 'package:stackwallet/pages_desktop_specific/home/settings_menu/currency_settings/currency_settings.dart';
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/language_settings/language_settings.dart';
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/nodes_settings.dart'; import 'package:stackwallet/pages_desktop_specific/home/settings_menu/nodes_settings.dart';
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/security_settings.dart'; import 'package:stackwallet/pages_desktop_specific/home/settings_menu/security_settings.dart';
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/settings_menu.dart'; import 'package:stackwallet/pages_desktop_specific/home/settings_menu/settings_menu.dart';
@ -115,9 +118,6 @@ import 'package:stackwallet/utilities/enums/add_wallet_type_enum.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:tuple/tuple.dart'; import 'package:tuple/tuple.dart';
import 'pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/unlock_wallet_keys_desktop.dart';
import 'pages_desktop_specific/home/settings_menu/language_settings/language_settings.dart';
class RouteGenerator { class RouteGenerator {
static const bool useMaterialPageRoute = true; static const bool useMaterialPageRoute = true;
@ -1029,6 +1029,12 @@ class RouteGenerator {
builder: (_) => const DesktopExchangeView(), builder: (_) => const DesktopExchangeView(),
settings: RouteSettings(name: settings.name)); settings: RouteSettings(name: settings.name));
case DesktopAllTradesView.routeName:
return getRoute(
shouldUseMaterialRoute: useMaterialPageRoute,
builder: (_) => const DesktopAllTradesView(),
settings: RouteSettings(name: settings.name));
case DesktopSettingsView.routeName: case DesktopSettingsView.routeName:
return getRoute( return getRoute(
shouldUseMaterialRoute: useMaterialPageRoute, shouldUseMaterialRoute: useMaterialPageRoute,

View file

@ -50,6 +50,9 @@ class AddressBookService extends ChangeNotifier {
} }
bool matches(String term, Contact contact) { bool matches(String term, Contact contact) {
if (term.isEmpty) {
return true;
}
final text = term.toLowerCase(); final text = term.toLowerCase();
if (contact.name.toLowerCase().contains(text)) { if (contact.name.toLowerCase().contains(text)) {
return true; return true;

View file

@ -11,6 +11,16 @@ class TradesService extends ChangeNotifier {
return list; return list;
} }
Trade? get(String tradeId) {
try {
return DB.instance
.values<Trade>(boxName: DB.boxNameTradesV2)
.firstWhere((e) => e.tradeId == tradeId);
} catch (_) {
return null;
}
}
Future<void> add({ Future<void> add({
required Trade trade, required Trade trade,
required bool shouldNotifyListeners, required bool shouldNotifyListeners,

View file

@ -3,6 +3,10 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/providers/ui/color_theme_provider.dart'; import 'package:stackwallet/providers/ui/color_theme_provider.dart';
import 'package:stackwallet/utilities/text_styles.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/rounded_container.dart';
class BlueTextButton extends ConsumerStatefulWidget { class BlueTextButton extends ConsumerStatefulWidget {
const BlueTextButton({ const BlueTextButton({
@ -28,6 +32,8 @@ class _BlueTextButtonState extends ConsumerState<BlueTextButton>
Animation<dynamic>? animation; Animation<dynamic>? animation;
late Color color; late Color color;
bool _hovering = false;
@override @override
void initState() { void initState() {
if (widget.enabled) { if (widget.enabled) {
@ -65,7 +71,28 @@ class _BlueTextButtonState extends ConsumerState<BlueTextButton>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return RichText( return ConditionalParent(
condition: Util.isDesktop,
builder: (child) {
return MouseRegion(
cursor: SystemMouseCursors.click,
onEnter: (_) => setState(() => _hovering = true),
onExit: (_) => setState(() => _hovering = false),
child: GestureDetector(
onTap: widget.onTap,
child: RoundedContainer(
radiusMultiplier: 20,
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 10),
color: Theme.of(context)
.extension<StackColors>()!
.highlight
.withOpacity(_hovering ? 0.3 : 0),
child: child,
),
),
);
},
child: RichText(
textAlign: TextAlign.center, textAlign: TextAlign.center,
text: TextSpan( text: TextSpan(
text: widget.text, text: widget.text,
@ -85,6 +112,7 @@ class _BlueTextButtonState extends ConsumerState<BlueTextButton>
}) })
: null, : null,
), ),
),
); );
} }
} }

View file

@ -11,7 +11,7 @@ class DesktopDialog extends StatelessWidget {
final Widget? child; final Widget? child;
final double maxWidth; final double maxWidth;
final double maxHeight; final double? maxHeight;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -22,7 +22,7 @@ class DesktopDialog extends StatelessWidget {
ConstrainedBox( ConstrainedBox(
constraints: BoxConstraints( constraints: BoxConstraints(
maxWidth: maxWidth, maxWidth: maxWidth,
maxHeight: maxHeight, maxHeight: maxHeight ?? MediaQuery.of(context).size.height - 64,
), ),
child: Material( child: Material(
color: Colors.transparent, color: Colors.transparent,

311
lib/widgets/toggle.dart Normal file
View file

@ -0,0 +1,311 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
class Toggle extends StatefulWidget {
const Toggle({
Key? key,
this.onIcon,
this.onText,
this.offIcon,
this.offText,
this.onValueChanged,
required this.isOn,
// this.enabled = true,
this.controller,
required this.onColor,
required this.offColor,
this.decoration,
}) : super(key: key);
final String? onIcon;
final String? onText;
final String? offIcon;
final String? offText;
final void Function(bool)? onValueChanged;
final bool isOn;
// final bool enabled;
final DSBController? controller;
final Color onColor;
final Color offColor;
final BoxDecoration? decoration;
@override
ToggleState createState() => ToggleState();
}
class ToggleState extends State<Toggle> {
late final BoxDecoration? decoration;
late final Color onColor;
late final Color offColor;
late final DSBController? controller;
final bool isDesktop = Util.isDesktop;
late bool _isOn;
bool get isOn => _isOn;
// late bool _enabled;
late ValueNotifier<double> valueListener;
final tapAnimationDuration = const Duration(milliseconds: 150);
bool _isDragging = false;
// Color _colorBG(bool isOn, double alpha) {
// return Color.alphaBlend(
// onColor.withOpacity(alpha),
// offColor,
// );
// }
// Color _colorFG(bool isOn, double alpha) {
// return Color.alphaBlend(
// onColor.withOpacity(alpha),
// offColor,
// );
// }
@override
initState() {
onColor = widget.onColor;
offColor = widget.offColor;
decoration = widget.decoration;
controller = widget.controller;
_isOn = widget.isOn;
// _enabled = widget.enabled;
valueListener = _isOn ? ValueNotifier(1.0) : ValueNotifier(0.0);
widget.controller?.activate = () {
_isOn = !_isOn;
// widget.onValueChanged?.call(_isOn);
valueListener.value = _isOn ? 1.0 : 0.0;
};
super.initState();
}
@override
void dispose() {
valueListener.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
debugPrint("BUILD: $runtimeType");
return GestureDetector(
onTap: () {
_isOn = !_isOn;
widget.onValueChanged?.call(_isOn);
valueListener.value = _isOn ? 1.0 : 0.0;
setState(() {});
},
child: LayoutBuilder(
builder: (context, constraint) {
return Stack(
children: [
AnimatedBuilder(
animation: valueListener,
builder: (context, child) {
return AnimatedContainer(
duration: tapAnimationDuration,
height: constraint.maxHeight,
width: constraint.maxWidth,
decoration: decoration?.copyWith(
color: offColor,
),
);
},
),
Builder(
builder: (context) {
final handle = GestureDetector(
key: const Key("draggableSwitchButtonSwitch"),
onHorizontalDragStart: (_) => _isDragging = true,
onHorizontalDragUpdate: (details) {
valueListener.value = (valueListener.value +
details.delta.dx / constraint.maxWidth)
.clamp(0.0, 1.0);
},
onHorizontalDragEnd: (details) {
bool oldValue = _isOn;
if (valueListener.value > 0.5) {
valueListener.value = 1.0;
_isOn = true;
} else {
valueListener.value = 0.0;
_isOn = false;
}
if (_isOn != oldValue) {
widget.onValueChanged?.call(_isOn);
controller?.isOn = _isOn;
setState(() {});
}
_isDragging = false;
},
child: AnimatedBuilder(
animation: valueListener,
builder: (context, child) {
return AnimatedContainer(
duration: tapAnimationDuration,
height: constraint.maxHeight,
width: constraint.maxWidth / 2,
decoration: decoration?.copyWith(
color:
onColor, //_colorFG(_isOn, valueListener.value),
),
);
},
),
);
return AnimatedBuilder(
animation: valueListener,
builder: (context, child) {
return AnimatedAlign(
duration:
_isDragging ? Duration.zero : tapAnimationDuration,
alignment: Alignment(valueListener.value * 2 - 1, 0.5),
child: child,
);
},
child: handle,
);
},
),
IgnorePointer(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
SizedBox(
width: constraint.maxWidth / 2,
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SvgPicture.asset(
widget.onIcon ?? "",
width: 12,
height: 14,
color: isDesktop
? !_isOn
? Theme.of(context)
.extension<StackColors>()!
.accentColorBlue
: Theme.of(context)
.extension<StackColors>()!
.buttonTextSecondary
: !_isOn
? Theme.of(context)
.extension<StackColors>()!
.textDark
: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
const SizedBox(
width: 5,
),
Text(
widget.onText ?? "",
style: isDesktop
? STextStyles.desktopTextExtraExtraSmall(
context)
.copyWith(
color: !_isOn
? Theme.of(context)
.extension<StackColors>()!
.accentColorBlue
: Theme.of(context)
.extension<StackColors>()!
.buttonTextSecondary,
)
: STextStyles.smallMed12(context).copyWith(
color: !_isOn
? Theme.of(context)
.extension<StackColors>()!
.textDark
: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
),
],
),
),
),
SizedBox(
width: constraint.maxWidth / 2,
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SvgPicture.asset(
widget.offIcon ?? "",
width: 12,
height: 14,
color: isDesktop
? _isOn
? Theme.of(context)
.extension<StackColors>()!
.accentColorBlue
: Theme.of(context)
.extension<StackColors>()!
.buttonTextSecondary
: _isOn
? Theme.of(context)
.extension<StackColors>()!
.textDark
: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
const SizedBox(
width: 5,
),
Text(
widget.offText ?? "",
style: isDesktop
? STextStyles.desktopTextExtraExtraSmall(
context)
.copyWith(
color: _isOn
? Theme.of(context)
.extension<StackColors>()!
.accentColorBlue
: Theme.of(context)
.extension<StackColors>()!
.buttonTextSecondary,
)
: STextStyles.smallMed12(context).copyWith(
color: _isOn
? Theme.of(context)
.extension<StackColors>()!
.textDark
: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
),
],
),
),
),
],
),
),
],
);
},
),
);
}
}
class DSBController {
VoidCallback? activate;
bool? isOn;
}