mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-03-12 09:27:01 +00:00
WIP desktop send view coin control
This commit is contained in:
parent
8838f68524
commit
6c1d9d2912
9 changed files with 608 additions and 125 deletions
3
assets/svg/list-ul.svg
Normal file
3
assets/svg/list-ul.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0.832031 4.08279C0.832031 3.10291 1.62635 2.30859 2.60622 2.30859C3.5861 2.30859 4.38042 3.10291 4.38042 4.08279C4.38042 5.06229 3.5861 5.85698 2.60622 5.85698C1.62635 5.85698 0.832031 5.06229 0.832031 4.08279ZM17.9826 2.89999C18.6368 2.89999 19.1654 3.42966 19.1654 4.08279C19.1654 4.73702 18.6368 5.26558 17.9826 5.26558H7.33741C6.68317 5.26558 6.15461 4.73702 6.15461 4.08279C6.15461 3.42966 6.68317 2.89999 7.33741 2.89999H17.9826ZM17.9826 8.81397C18.6368 8.81397 19.1654 9.34253 19.1654 9.99677C19.1654 10.651 18.6368 11.1796 17.9826 11.1796H7.33741C6.68317 11.1796 6.15461 10.651 6.15461 9.99677C6.15461 9.34253 6.68317 8.81397 7.33741 8.81397H17.9826ZM17.9826 14.7279C18.6368 14.7279 19.1654 15.2565 19.1654 15.9107C19.1654 16.565 18.6368 17.0935 17.9826 17.0935H7.33741C6.68317 17.0935 6.15461 16.565 6.15461 15.9107C6.15461 15.2565 6.68317 14.7279 7.33741 14.7279H17.9826ZM0.832031 15.9107C0.832031 14.9312 1.62635 14.1365 2.60622 14.1365C3.5861 14.1365 4.38042 14.9312 4.38042 15.9107C4.38042 16.8902 3.5861 17.6849 2.60622 17.6849C1.62635 17.6849 0.832031 16.8902 0.832031 15.9107ZM4.38042 9.99677C4.38042 10.9763 3.5861 11.771 2.60622 11.771C1.62635 11.771 0.832031 10.9763 0.832031 9.99677C0.832031 9.01726 1.62635 8.22257 2.60622 8.22257C3.5861 8.22257 4.38042 9.01726 4.38042 9.99677Z" fill="#232323"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
|
@ -1,9 +1,15 @@
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:flutter_native_splash/cli_commands.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
import 'package:stackwallet/exceptions/main_db/main_db_exception.dart';
|
||||
import 'package:stackwallet/models/isar/models/isar_models.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/stack_file_system.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
|
||||
part 'queries/queries.dart';
|
||||
|
||||
class MainDB {
|
||||
MainDB._();
|
||||
static MainDB? _instance;
|
||||
|
|
101
lib/db/queries/queries.dart
Normal file
101
lib/db/queries/queries.dart
Normal file
|
@ -0,0 +1,101 @@
|
|||
part of 'package:stackwallet/db/main_db.dart';
|
||||
|
||||
enum CCFilter {
|
||||
all,
|
||||
available,
|
||||
frozen;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
if (this == all) {
|
||||
return "Show $name outputs";
|
||||
}
|
||||
|
||||
return "${name.capitalize()} outputs";
|
||||
}
|
||||
}
|
||||
|
||||
enum CCSortDescriptor {
|
||||
age,
|
||||
address,
|
||||
value;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return name.capitalize();
|
||||
}
|
||||
}
|
||||
|
||||
extension MainDBQueries on MainDB {
|
||||
List<Id> queryUTXOsSync({
|
||||
required String walletId,
|
||||
required CCFilter filter,
|
||||
required CCSortDescriptor sort,
|
||||
required String searchTerm,
|
||||
required Coin coin,
|
||||
}) {
|
||||
var preSort = getUTXOs(walletId).filter().group((q) {
|
||||
final qq = q.group(
|
||||
(q) => q.usedIsNull().or().usedEqualTo(false),
|
||||
);
|
||||
switch (filter) {
|
||||
case CCFilter.frozen:
|
||||
return qq.and().isBlockedEqualTo(true);
|
||||
case CCFilter.available:
|
||||
return qq.and().isBlockedEqualTo(false);
|
||||
case CCFilter.all:
|
||||
return qq;
|
||||
}
|
||||
});
|
||||
|
||||
if (searchTerm.isNotEmpty) {
|
||||
preSort = preSort.and().group(
|
||||
(q) {
|
||||
var qq = q.addressContains(searchTerm, caseSensitive: false);
|
||||
|
||||
qq = qq.or().nameContains(searchTerm, caseSensitive: false);
|
||||
qq = qq.or().group(
|
||||
(q) => q
|
||||
.isBlockedEqualTo(true)
|
||||
.and()
|
||||
.blockedReasonContains(searchTerm, caseSensitive: false),
|
||||
);
|
||||
|
||||
qq = qq.or().txidContains(searchTerm, caseSensitive: false);
|
||||
qq = qq.or().blockHashContains(searchTerm, caseSensitive: false);
|
||||
|
||||
final maybeDecimal = Decimal.tryParse(searchTerm);
|
||||
if (maybeDecimal != null) {
|
||||
qq = qq.or().valueEqualTo(
|
||||
Format.decimalAmountToSatoshis(
|
||||
maybeDecimal,
|
||||
coin,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final maybeInt = int.tryParse(searchTerm);
|
||||
if (maybeInt != null) {
|
||||
qq = qq.or().valueEqualTo(maybeInt);
|
||||
}
|
||||
|
||||
return qq;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
final List<Id> ids;
|
||||
switch (sort) {
|
||||
case CCSortDescriptor.age:
|
||||
ids = preSort.sortByBlockHeight().idProperty().findAllSync();
|
||||
break;
|
||||
case CCSortDescriptor.address:
|
||||
ids = preSort.sortByAddress().idProperty().findAllSync();
|
||||
break;
|
||||
case CCSortDescriptor.value:
|
||||
ids = preSort.sortByValueDesc().idProperty().findAllSync();
|
||||
break;
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,365 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
import 'package:stackwallet/db/main_db.dart';
|
||||
import 'package:stackwallet/models/isar/models/blockchain_data/utxo.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/coin_control/utxo_row.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/enums/coin_enum.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_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/rounded_container.dart';
|
||||
import 'package:stackwallet/widgets/stack_text_field.dart';
|
||||
import 'package:stackwallet/widgets/textfield_icon_button.dart';
|
||||
import 'package:stackwallet/widgets/toggle.dart';
|
||||
|
||||
final desktopUseUTXOs = StateProvider.autoDispose((ref) => <UTXO>{});
|
||||
|
||||
class DesktopCoinControlUseDialog extends ConsumerStatefulWidget {
|
||||
const DesktopCoinControlUseDialog({
|
||||
Key? key,
|
||||
required this.walletId,
|
||||
}) : super(key: key);
|
||||
|
||||
final String walletId;
|
||||
|
||||
@override
|
||||
ConsumerState<DesktopCoinControlUseDialog> createState() =>
|
||||
_DesktopCoinControlUseDialogState();
|
||||
}
|
||||
|
||||
class _DesktopCoinControlUseDialogState
|
||||
extends ConsumerState<DesktopCoinControlUseDialog> {
|
||||
late final TextEditingController _searchController;
|
||||
late final Coin coin;
|
||||
final searchFieldFocusNode = FocusNode();
|
||||
|
||||
final Set<UtxoRowData> _selectedUTXOs = {};
|
||||
|
||||
String _searchString = "";
|
||||
|
||||
CCFilter _filter = CCFilter.available;
|
||||
CCSortDescriptor _sort = CCSortDescriptor.age;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_searchController = TextEditingController();
|
||||
coin = ref
|
||||
.read(walletsChangeNotifierProvider)
|
||||
.getManager(widget.walletId)
|
||||
.coin;
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_searchController.dispose();
|
||||
searchFieldFocusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ids = MainDB.instance.queryUTXOsSync(
|
||||
walletId: widget.walletId,
|
||||
filter: _filter,
|
||||
sort: _sort,
|
||||
searchTerm: _searchString,
|
||||
coin: coin,
|
||||
);
|
||||
|
||||
return DesktopDialog(
|
||||
maxWidth: 700,
|
||||
maxHeight: MediaQuery.of(context).size.height - 128,
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
const AppBarBackButton(
|
||||
size: 40,
|
||||
iconSize: 24,
|
||||
),
|
||||
Text(
|
||||
"Coin control",
|
||||
style: STextStyles.desktopH3(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Column(
|
||||
children: [
|
||||
RoundedContainer(
|
||||
color: Colors.transparent,
|
||||
borderColor: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textFieldDefaultBG,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"This option allows you to control, freeze, and utilize "
|
||||
"outputs at your discretion.",
|
||||
style:
|
||||
STextStyles.desktopTextExtraExtraSmall(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
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(
|
||||
width: 16,
|
||||
),
|
||||
SizedBox(
|
||||
height: 56,
|
||||
width: 240,
|
||||
child: Toggle(
|
||||
isOn: _filter == CCFilter.frozen,
|
||||
onColor: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.rateTypeToggleDesktopColorOn,
|
||||
offColor: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.rateTypeToggleDesktopColorOff,
|
||||
onIcon: Assets.svg.coinControl.unBlocked,
|
||||
onText: "Available",
|
||||
offIcon: Assets.svg.coinControl.blocked,
|
||||
offText: "Frozen",
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
),
|
||||
onValueChanged: (value) {
|
||||
setState(() {
|
||||
if (value) {
|
||||
_filter = CCFilter.frozen;
|
||||
} else {
|
||||
_filter = CCFilter.available;
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 16,
|
||||
),
|
||||
SizedBox(
|
||||
height: 56,
|
||||
width: 56,
|
||||
child: TextButton(
|
||||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getSecondaryEnabledButtonStyle(context)
|
||||
?.copyWith(
|
||||
shape: MaterialStateProperty.all(
|
||||
RoundedRectangleBorder(
|
||||
side: BorderSide(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.buttonBackBorderSecondary,
|
||||
width: 1,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
onPressed: () {},
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.list,
|
||||
width: 20,
|
||||
height: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
Expanded(
|
||||
child: ListView.separated(
|
||||
shrinkWrap: true,
|
||||
primary: false,
|
||||
itemCount: ids.length,
|
||||
separatorBuilder: (context, _) => const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
itemBuilder: (context, index) {
|
||||
final utxo = MainDB.instance.isar.utxos
|
||||
.where()
|
||||
.idEqualTo(ids[index])
|
||||
.findFirstSync()!;
|
||||
final data = UtxoRowData(utxo.id, false);
|
||||
data.selected = _selectedUTXOs.contains(data);
|
||||
|
||||
return UtxoRow(
|
||||
key: Key(
|
||||
"${utxo.walletId}_${utxo.id}_${utxo.isBlocked}"),
|
||||
data: data,
|
||||
compact: true,
|
||||
walletId: widget.walletId,
|
||||
onSelectionChanged: (value) {
|
||||
setState(() {
|
||||
if (data.selected) {
|
||||
_selectedUTXOs.add(value);
|
||||
} else {
|
||||
_selectedUTXOs.remove(value);
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
RoundedContainer(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textFieldDefaultBG,
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Selected amount",
|
||||
style: STextStyles.desktopTextExtraExtraSmall(context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
"LOL",
|
||||
style: STextStyles.desktopTextExtraExtraSmall(context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: SecondaryButton(
|
||||
enabled: _selectedUTXOs.isNotEmpty,
|
||||
buttonHeight: ButtonHeight.l,
|
||||
label: _selectedUTXOs.isEmpty
|
||||
? "Clear selection"
|
||||
: "Clear selection (${_selectedUTXOs.length})",
|
||||
onPressed: () => setState(() {
|
||||
_selectedUTXOs.clear();
|
||||
}),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 20,
|
||||
),
|
||||
Expanded(
|
||||
child: PrimaryButton(
|
||||
enabled: _selectedUTXOs.isNotEmpty,
|
||||
buttonHeight: ButtonHeight.l,
|
||||
label: "Use coins",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,4 @@
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_native_splash/cli_commands.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
|
@ -12,7 +10,6 @@ import 'package:stackwallet/providers/global/wallets_provider.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/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';
|
||||
|
@ -24,32 +21,6 @@ import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
|
|||
import 'package:stackwallet/widgets/stack_text_field.dart';
|
||||
import 'package:stackwallet/widgets/textfield_icon_button.dart';
|
||||
|
||||
enum CCFilter {
|
||||
all,
|
||||
available,
|
||||
frozen;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
if (this == all) {
|
||||
return "Show $name outputs";
|
||||
}
|
||||
|
||||
return "${name.capitalize()} outputs";
|
||||
}
|
||||
}
|
||||
|
||||
enum CCSortDescriptor {
|
||||
age,
|
||||
address,
|
||||
value;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return name.toString().capitalize();
|
||||
}
|
||||
}
|
||||
|
||||
class DesktopCoinControlView extends ConsumerStatefulWidget {
|
||||
const DesktopCoinControlView({
|
||||
Key? key,
|
||||
|
@ -99,68 +70,13 @@ class _DesktopCoinControlViewState
|
|||
Widget build(BuildContext context) {
|
||||
debugPrint("BUILD: $runtimeType");
|
||||
|
||||
var preSort = MainDB.instance.getUTXOs(widget.walletId).filter().group((q) {
|
||||
final qq = q.group(
|
||||
(q) => q.usedIsNull().or().usedEqualTo(false),
|
||||
);
|
||||
switch (_filter) {
|
||||
case CCFilter.frozen:
|
||||
return qq.and().isBlockedEqualTo(true);
|
||||
case CCFilter.available:
|
||||
return qq.and().isBlockedEqualTo(false);
|
||||
case CCFilter.all:
|
||||
return qq;
|
||||
}
|
||||
});
|
||||
|
||||
if (_searchString.isNotEmpty) {
|
||||
preSort = preSort.and().group(
|
||||
(q) {
|
||||
var qq = q.addressContains(_searchString, caseSensitive: false);
|
||||
|
||||
qq = qq.or().nameContains(_searchString, caseSensitive: false);
|
||||
qq = qq.or().group(
|
||||
(q) => q
|
||||
.isBlockedEqualTo(true)
|
||||
.and()
|
||||
.blockedReasonContains(_searchString, caseSensitive: false),
|
||||
);
|
||||
|
||||
qq = qq.or().txidContains(_searchString, caseSensitive: false);
|
||||
qq = qq.or().blockHashContains(_searchString, caseSensitive: false);
|
||||
|
||||
final maybeDecimal = Decimal.tryParse(_searchString);
|
||||
if (maybeDecimal != null) {
|
||||
qq = qq.or().valueEqualTo(
|
||||
Format.decimalAmountToSatoshis(
|
||||
maybeDecimal,
|
||||
coin,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final maybeInt = int.tryParse(_searchString);
|
||||
if (maybeInt != null) {
|
||||
qq = qq.or().valueEqualTo(maybeInt);
|
||||
}
|
||||
|
||||
return qq;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
final List<Id> ids;
|
||||
switch (_sort) {
|
||||
case CCSortDescriptor.age:
|
||||
ids = preSort.sortByBlockHeight().idProperty().findAllSync();
|
||||
break;
|
||||
case CCSortDescriptor.address:
|
||||
ids = preSort.sortByAddress().idProperty().findAllSync();
|
||||
break;
|
||||
case CCSortDescriptor.value:
|
||||
ids = preSort.sortByValueDesc().idProperty().findAllSync();
|
||||
break;
|
||||
}
|
||||
final ids = MainDB.instance.queryUTXOsSync(
|
||||
walletId: widget.walletId,
|
||||
filter: _filter,
|
||||
sort: _sort,
|
||||
searchTerm: _searchString,
|
||||
coin: coin,
|
||||
);
|
||||
|
||||
return DesktopScaffold(
|
||||
appBar: DesktopAppBar(
|
||||
|
|
|
@ -9,9 +9,11 @@ import 'package:stackwallet/utilities/enums/coin_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/widgets/conditional_parent.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
|
||||
import 'package:stackwallet/widgets/icon_widgets/utxo_status_icon.dart';
|
||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||
import 'package:stackwallet/widgets/rounded_container.dart';
|
||||
|
||||
class UtxoRowData {
|
||||
UtxoRowData(this.utxoId, this.selected);
|
||||
|
@ -39,11 +41,13 @@ class UtxoRow extends ConsumerStatefulWidget {
|
|||
required this.data,
|
||||
required this.walletId,
|
||||
this.onSelectionChanged,
|
||||
this.compact = false,
|
||||
}) : super(key: key);
|
||||
|
||||
final String walletId;
|
||||
final UtxoRowData data;
|
||||
final void Function(UtxoRowData)? onSelectionChanged;
|
||||
final bool compact;
|
||||
|
||||
@override
|
||||
ConsumerState<UtxoRow> createState() => _UtxoRowState();
|
||||
|
@ -53,6 +57,16 @@ class _UtxoRowState extends ConsumerState<UtxoRow> {
|
|||
late Stream<UTXO?> stream;
|
||||
late UTXO utxo;
|
||||
|
||||
void _details() async {
|
||||
await showDialog<String?>(
|
||||
context: context,
|
||||
builder: (context) => UtxoDetailsView(
|
||||
utxoId: utxo.id,
|
||||
walletId: widget.walletId,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
utxo = MainDB.instance.isar.utxos
|
||||
|
@ -81,7 +95,11 @@ class _UtxoRowState extends ConsumerState<UtxoRow> {
|
|||
utxo = snapshot.data!;
|
||||
}
|
||||
|
||||
return RoundedWhiteContainer(
|
||||
return RoundedContainer(
|
||||
borderColor: widget.compact
|
||||
? Theme.of(context).extension<StackColors>()!.textFieldDefaultBG
|
||||
: null,
|
||||
color: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||
boxShadow: widget.data.selected
|
||||
? [
|
||||
Theme.of(context).extension<StackColors>()!.standardBoxShadow,
|
||||
|
@ -117,46 +135,70 @@ class _UtxoRowState extends ConsumerState<UtxoRow> {
|
|||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Text(
|
||||
"${Format.satoshisToAmount(
|
||||
utxo.value,
|
||||
coin: coin,
|
||||
).toStringAsFixed(coin.decimals)} ${coin.ticker}",
|
||||
textAlign: TextAlign.right,
|
||||
style: STextStyles.w600_14(context),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
if (!widget.compact)
|
||||
Text(
|
||||
"${Format.satoshisToAmount(
|
||||
utxo.value,
|
||||
coin: coin,
|
||||
).toStringAsFixed(coin.decimals)} ${coin.ticker}",
|
||||
textAlign: TextAlign.right,
|
||||
style: STextStyles.w600_14(context),
|
||||
),
|
||||
if (!widget.compact)
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Expanded(
|
||||
flex: 13,
|
||||
child: Text(
|
||||
utxo.name.isNotEmpty ? utxo.name : utxo.address ?? utxo.txid,
|
||||
textAlign: TextAlign.center,
|
||||
style: STextStyles.w500_12(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
child: ConditionalParent(
|
||||
condition: widget.compact,
|
||||
builder: (child) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
"${Format.satoshisToAmount(
|
||||
utxo.value,
|
||||
coin: coin,
|
||||
).toStringAsFixed(coin.decimals)} ${coin.ticker}",
|
||||
textAlign: TextAlign.right,
|
||||
style: STextStyles.w600_14(context),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
child,
|
||||
],
|
||||
);
|
||||
},
|
||||
child: Text(
|
||||
utxo.name.isNotEmpty
|
||||
? utxo.name
|
||||
: utxo.address ?? utxo.txid,
|
||||
textAlign:
|
||||
widget.compact ? TextAlign.left : TextAlign.center,
|
||||
style: STextStyles.w500_12(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
SecondaryButton(
|
||||
width: 120,
|
||||
buttonHeight: ButtonHeight.xs,
|
||||
label: "Details",
|
||||
onPressed: () async {
|
||||
await showDialog<String?>(
|
||||
context: context,
|
||||
builder: (context) => UtxoDetailsView(
|
||||
utxoId: utxo.id,
|
||||
walletId: widget.walletId,
|
||||
widget.compact
|
||||
? CustomTextButton(
|
||||
text: "Details",
|
||||
onTap: _details,
|
||||
)
|
||||
: SecondaryButton(
|
||||
width: 120,
|
||||
buttonHeight: ButtonHeight.xs,
|
||||
label: "Details",
|
||||
onPressed: _details,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
|
@ -13,6 +13,7 @@ import 'package:stackwallet/models/send_view_auto_fill_data.dart';
|
|||
import 'package:stackwallet/pages/send_view/confirm_transaction_view.dart';
|
||||
import 'package:stackwallet/pages/send_view/sub_widgets/building_transaction_dialog.dart';
|
||||
import 'package:stackwallet/pages/send_view/sub_widgets/transaction_fee_selection_sheet.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/coin_control/desktop_coin_control_use_dialog.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/address_book_address_chooser/address_book_address_chooser.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_fee_dropdown.dart';
|
||||
|
@ -44,6 +45,7 @@ import 'package:stackwallet/widgets/desktop/secondary_button.dart';
|
|||
import 'package:stackwallet/widgets/icon_widgets/addressbook_icon.dart';
|
||||
import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.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';
|
||||
|
||||
|
@ -679,6 +681,18 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
}
|
||||
}
|
||||
|
||||
void _showDesktopCoinControl() async {
|
||||
if (_amountToSend == null) {
|
||||
//
|
||||
}
|
||||
final result = await showDialog(
|
||||
context: context,
|
||||
builder: (context) => DesktopCoinControlUseDialog(
|
||||
walletId: widget.walletId,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
|
@ -776,6 +790,17 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
});
|
||||
}
|
||||
|
||||
final showCoinControl = ref.watch(
|
||||
prefsChangeNotifierProvider.select(
|
||||
(value) => value.enableCoinControl,
|
||||
),
|
||||
) &&
|
||||
ref.watch(
|
||||
provider.select(
|
||||
(value) => value.hasCoinControlSupport,
|
||||
),
|
||||
);
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
|
@ -1052,6 +1077,29 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
),
|
||||
),
|
||||
),
|
||||
if (showCoinControl)
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
if (showCoinControl)
|
||||
RoundedContainer(
|
||||
color: Colors.transparent,
|
||||
borderColor:
|
||||
Theme.of(context).extension<StackColors>()!.textFieldDefaultBG,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Coin control",
|
||||
style: STextStyles.desktopTextExtraExtraSmall(context),
|
||||
),
|
||||
CustomTextButton(
|
||||
text: "Select coins",
|
||||
onTap: _showDesktopCoinControl,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
|
|
|
@ -236,6 +236,7 @@ class _SVG {
|
|||
String get walletFa => "assets/svg/wallet-fa.svg";
|
||||
String get exchange3 => "assets/svg/exchange-3.svg";
|
||||
String get messageQuestion => "assets/svg/message-question-1.svg";
|
||||
String get list => "assets/svg/list-ul.svg";
|
||||
|
||||
// TODO provide proper assets
|
||||
String get bitcoinTestnet => "assets/svg/coin_icons/Bitcoin.svg";
|
||||
|
|
|
@ -313,6 +313,7 @@ flutter:
|
|||
- assets/svg/box-auto.svg
|
||||
- assets/svg/framed-address-book.svg
|
||||
- assets/svg/framed-gear.svg
|
||||
- assets/svg/list-ul.svg
|
||||
|
||||
|
||||
# coin icons
|
||||
|
|
Loading…
Reference in a new issue