replace mobile_scanner with an older library that does not use MLKit on android
What changed, and why it matters
This commit swaps the app's QR code scanning library on Android from one that uses Google's ML Kit to an older one that does not. The change is framed as a privacy move to avoid sending camera frames to Google's ML services. The diff also adds null checks on scanned QR results, which prevents some crashes when a scan returns no content. There is no direct evidence in the commit that this fixes an active security vulnerability, and the bulk of the diff is formatting changes unrelated to security.
Review the new QR scanning library for known vulnerabilities and maintenance status before relying on it. Verify that the null-handling changes cover all scan call sites and do not silently skip user-intended actions. If this change was motivated by a security or privacy concern, request a vendor advisory or changelog entry documenting the rationale and any associated risks.
Security signals we found
Dependency swap away from MLKit/Google on-device ML on Android
Added null-safety guards on QR scan results
Large formatting-only noise reduces signal-to-noise ratio
No vendor security disclosure or advisory referenced
Evidence from the diff
The commit replaces the mobile_scanner dependency with an older library that avoids MLKit on Android. It updates pubspec.template.yaml and pubspec.lock, and refactors barcode_scanner_interface.dart and qr_scanner.dart to use the new library’s API. Call sites now handle rawContent as nullable (qrResult.rawContent == null checks and ?? "" fallbacks). Most of the 18 changed files contain cosmetic Dart formatting changes (trailing commas, indentation) rather than functional changes. The commit does not describe a CVE, disclose a security bug, or credit a researcher.
Changed components
lib/utilities/barcode_scanner_interface.dartlib/widgets/qr_scanner.dartpubspec.template.yamlpubspec.lockMultiple QR scan call sites in wallet restore, send, exchange, buy, and address book viewsInspect captured patch +1751 / −1742
diff --git a/lib/pages/add_wallet_views/frost_ms/restore/restore_frost_ms_wallet_view.dart b/lib/pages/add_wallet_views/frost_ms/restore/restore_frost_ms_wallet_view.dart
index 33eddc5..0c756d0 100644
--- a/lib/pages/add_wallet_views/frost_ms/restore/restore_frost_ms_wallet_view.dart
+++ b/lib/pages/add_wallet_views/frost_ms/restore/restore_frost_ms_wallet_view.dart
@@ -215,8 +215,9 @@ class _RestoreFrostMsWalletViewState
}
final qrResult = await ref.read(pBarcodeScanner).scan(context: context);
+ if (qrResult.rawContent == null) return;
- configFieldController.text = qrResult.rawContent;
+ configFieldController.text = qrResult.rawContent!;
setState(() {
_configEmpty = configFieldController.text.isEmpty;
diff --git a/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart b/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart
index e87305f..1627c3c 100644
--- a/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart
+++ b/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart
@@ -622,7 +622,7 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> {
try {
final qrResult = await ref.read(pBarcodeScanner).scan(context: context);
- final results = AddressUtils.decodeQRSeedData(qrResult.rawContent);
+ final results = AddressUtils.decodeQRSeedData(qrResult.rawContent ?? "");
if (results["mnemonic"] != null) {
final list = (results["mnemonic"] as List)
diff --git a/lib/pages/address_book_views/subviews/new_contact_address_entry_form.dart b/lib/pages/address_book_views/subviews/new_contact_address_entry_form.dart
index b6dcd7b..1be9783 100644
--- a/lib/pages/address_book_views/subviews/new_contact_address_entry_form.dart
+++ b/lib/pages/address_book_views/subviews/new_contact_address_entry_form.dart
@@ -71,6 +71,7 @@ class _NewContactAddressEntryFormState
// .state)
// .state = false;
final qrResult = await ref.read(pBarcodeScanner).scan(context: context);
+ if (qrResult.rawContent == null) return;
// Future<void>.delayed(
// const Duration(seconds: 2),
@@ -82,7 +83,7 @@ class _NewContactAddressEntryFormState
// );
final paymentData = AddressUtils.parsePaymentUri(
- qrResult.rawContent,
+ qrResult.rawContent!,
logging: Logging.instance,
);
@@ -93,18 +94,19 @@ class _NewContactAddressEntryFormState
addressLabelController.text =
paymentData.label ?? addressLabelController.text;
- ref.read(addressEntryDataProvider(widget.id)).addressLabel =
- addressLabelController.text.isEmpty
- ? null
- : addressLabelController.text;
+ ref
+ .read(addressEntryDataProvider(widget.id))
+ .addressLabel = addressLabelController.text.isEmpty
+ ? null
+ : addressLabelController.text;
// now check for non standard encoded basic address
} else if (ref.read(addressEntryDataProvider(widget.id)).coin != null) {
if (ref
.read(addressEntryDataProvider(widget.id))
.coin!
- .validateAddress(qrResult.rawContent)) {
- addressController.text = qrResult.rawContent;
+ .validateAddress(qrResult.rawContent!)) {
+ addressController.text = qrResult.rawContent!;
ref.read(addressEntryDataProvider(widget.id)).address =
qrResult.rawContent;
}
@@ -140,13 +142,10 @@ class _NewContactAddressEntryFormState
@override
void initState() {
- addressLabelController =
- TextEditingController()
- ..text =
- ref.read(addressEntryDataProvider(widget.id)).addressLabel ?? "";
- addressController =
- TextEditingController()
- ..text = ref.read(addressEntryDataProvider(widget.id)).address ?? "";
+ addressLabelController = TextEditingController()
+ ..text = ref.read(addressEntryDataProvider(widget.id)).addressLabel ?? "";
+ addressController = TextEditingController()
+ ..text = ref.read(addressEntryDataProvider(widget.id)).address ?? "";
addressLabelFocusNode = FocusNode();
addressFocusNode = FocusNode();
coins = [...AppConfig.coins];
@@ -177,15 +176,15 @@ class _NewContactAddressEntryFormState
coins = [...AppConfig.coins];
coins.removeWhere((e) => e is Firo && e.network.isTestNet);
- final showTestNet =
- ref.read(prefsChangeNotifierProvider).showTestNetCoins;
+ final showTestNet = ref
+ .read(prefsChangeNotifierProvider)
+ .showTestNetCoins;
if (showTestNet) {
coins = coins.toList();
} else {
- coins =
- coins
- .where((e) => e.network != CryptoCurrencyNetwork.test)
- .toList();
+ coins = coins
+ .where((e) => e.network != CryptoCurrencyNetwork.test)
+ .toList();
}
}
@@ -202,10 +201,9 @@ class _NewContactAddressEntryFormState
offset: const Offset(0, -10),
elevation: 0,
decoration: BoxDecoration(
- color:
- Theme.of(
- context,
- ).extension<StackColors>()!.textFieldDefaultBG,
+ color: Theme.of(
+ context,
+ ).extension<StackColors>()!.textFieldDefaultBG,
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
@@ -249,14 +247,14 @@ class _NewContactAddressEntryFormState
const SizedBox(width: 12),
Text(
coin.prettyName,
- style: STextStyles.desktopTextExtraExtraSmall(
- context,
- ).copyWith(
- color:
- Theme.of(
+ style:
+ STextStyles.desktopTextExtraExtraSmall(
+ context,
+ ).copyWith(
+ color: Theme.of(
context,
).extension<StackColors>()!.textDark,
- ),
+ ),
),
],
),
@@ -279,8 +277,9 @@ class _NewContactAddressEntryFormState
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: RawMaterialButton(
- splashColor:
- Theme.of(context).extension<StackColors>()!.highlight,
+ splashColor: Theme.of(
+ context,
+ ).extension<StackColors>()!.highlight,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
@@ -308,48 +307,47 @@ class _NewContactAddressEntryFormState
) ==
null
? Text(
- "Select cryptocurrency",
- style: STextStyles.fieldLabel(context),
- )
+ "Select cryptocurrency",
+ style: STextStyles.fieldLabel(context),
+ )
: Row(
- children: [
- SvgPicture.file(
- File(
- ref.watch(
- coinIconProvider(
- ref.watch(
+ children: [
+ SvgPicture.file(
+ File(
+ ref.watch(
+ coinIconProvider(
+ ref.watch(
+ addressEntryDataProvider(
+ widget.id,
+ ).select((value) => value.coin),
+ )!,
+ ),
+ ),
+ ),
+ height: 20,
+ width: 20,
+ ),
+ const SizedBox(width: 12),
+ Text(
+ ref
+ .watch(
addressEntryDataProvider(
widget.id,
).select((value) => value.coin),
- )!,
- ),
- ),
+ )!
+ .prettyName,
+ style: STextStyles.itemSubtitle12(context),
),
- height: 20,
- width: 20,
- ),
- const SizedBox(width: 12),
- Text(
- ref
- .watch(
- addressEntryDataProvider(
- widget.id,
- ).select((value) => value.coin),
- )!
- .prettyName,
- style: STextStyles.itemSubtitle12(context),
- ),
- ],
- ),
+ ],
+ ),
if (!isDesktop)
SvgPicture.asset(
Assets.svg.chevronDown,
width: 8,
height: 4,
- color:
- Theme.of(
- context,
- ).extension<StackColors>()!.textSubtitle2,
+ color: Theme.of(
+ context,
+ ).extension<StackColors>()!.textSubtitle2,
),
],
),
@@ -369,33 +367,35 @@ class _NewContactAddressEntryFormState
focusNode: addressLabelFocusNode,
controller: addressLabelController,
style: STextStyles.field(context),
- decoration: standardInputDecoration(
- "Enter address label",
- addressLabelFocusNode,
- context,
- ).copyWith(
- labelStyle: isDesktop ? STextStyles.fieldLabel(context) : null,
- suffixIcon:
- addressLabelController.text.isNotEmpty
+ decoration:
+ standardInputDecoration(
+ "Enter address label",
+ addressLabelFocusNode,
+ context,
+ ).copyWith(
+ labelStyle: isDesktop
+ ? STextStyles.fieldLabel(context)
+ : null,
+ suffixIcon: addressLabelController.text.isNotEmpty
? Padding(
- padding: const EdgeInsets.only(right: 0),
- child: UnconstrainedBox(
- child: Row(
- children: [
- TextFieldIconButton(
- child: const XIcon(),
- onTap: () async {
- setState(() {
- addressLabelController.text = "";
- });
- },
- ),
- ],
+ padding: const EdgeInsets.only(right: 0),
+ child: UnconstrainedBox(
+ child: Row(
+ children: [
+ TextFieldIconButton(
+ child: const XIcon(),
+ onTap: () async {
+ setState(() {
+ addressLabelController.text = "";
+ });
+ },
+ ),
+ ],
+ ),
),
- ),
- )
+ )
: null,
- ),
+ ),
onChanged: (newValue) {
ref.read(addressEntryDataProvider(widget.id)).addressLabel =
newValue;
@@ -413,76 +413,87 @@ class _NewContactAddressEntryFormState
focusNode: addressFocusNode,
controller: addressController,
style: STextStyles.field(context),
- decoration: standardInputDecoration(
- "Paste address",
- addressFocusNode,
- context,
- ).copyWith(
- labelStyle: isDesktop ? STextStyles.fieldLabel(context) : null,
- suffixIcon: UnconstrainedBox(
- child: Row(
- children: [
- if (ref.watch(
- addressEntryDataProvider(
- widget.id,
- ).select((value) => value.address),
- ) !=
- null)
- TextFieldIconButton(
- key: const Key("addAddressBookClearAddressButtonKey"),
- onTap: () async {
- addressController.text = "";
- ref
- .read(addressEntryDataProvider(widget.id))
- .address = null;
- },
- child: const XIcon(),
- ),
- if (ref.watch(
- addressEntryDataProvider(
- widget.id,
- ).select((value) => value.address),
- ) ==
- null)
- TextFieldIconButton(
- key: const Key("addAddressPasteAddressButtonKey"),
- onTap: () async {
- final ClipboardData? data = await widget.clipboard
- .getData(Clipboard.kTextPlain);
-
- if (data?.text != null && data!.text!.isNotEmpty) {
- String content = data.text!.trim();
- if (content.contains("\n")) {
- content = content.substring(
- 0,
- content.indexOf("\n"),
- );
- }
- addressController.text = content;
- ref
- .read(addressEntryDataProvider(widget.id))
- .address = content.isEmpty ? null : content;
- }
- },
- child: const ClipboardIcon(),
- ),
- if (!Util.isDesktop &&
- ref.watch(
+ decoration:
+ standardInputDecoration(
+ "Paste address",
+ addressFocusNode,
+ context,
+ ).copyWith(
+ labelStyle: isDesktop
+ ? STextStyles.fieldLabel(context)
+ : null,
+ suffixIcon: UnconstrainedBox(
+ child: Row(
+ children: [
+ if (ref.watch(
+ addressEntryDataProvider(
+ widget.id,
+ ).select((value) => value.address),
+ ) !=
+ null)
+ TextFieldIconButton(
+ key: const Key(
+ "addAddressBookClearAddressButtonKey",
+ ),
+ onTap: () async {
+ addressController.text = "";
+ ref
+ .read(addressEntryDataProvider(widget.id))
+ .address =
+ null;
+ },
+ child: const XIcon(),
+ ),
+ if (ref.watch(
addressEntryDataProvider(
widget.id,
).select((value) => value.address),
) ==
null)
- TextFieldIconButton(
- key: const Key("addAddressBookEntryScanQrButtonKey"),
- onTap: _onQrTapped,
- child: const QrCodeIcon(),
- ),
- const SizedBox(width: 8),
- ],
+ TextFieldIconButton(
+ key: const Key("addAddressPasteAddressButtonKey"),
+ onTap: () async {
+ final ClipboardData? data = await widget.clipboard
+ .getData(Clipboard.kTextPlain);
+
+ if (data?.text != null &&
+ data!.text!.isNotEmpty) {
+ String content = data.text!.trim();
+ if (content.contains("\n")) {
+ content = content.substring(
+ 0,
+ content.indexOf("\n"),
+ );
+ }
+ addressController.text = content;
+ ref
+ .read(addressEntryDataProvider(widget.id))
+ .address = content.isEmpty
+ ? null
+ : content;
+ }
+ },
+ child: const ClipboardIcon(),
+ ),
+ if (!Util.isDesktop &&
+ ref.watch(
+ addressEntryDataProvider(
+ widget.id,
+ ).select((value) => value.address),
+ ) ==
+ null)
+ TextFieldIconButton(
+ key: const Key(
+ "addAddressBookEntryScanQrButtonKey",
+ ),
+ onTap: _onQrTapped,
+ child: const QrCodeIcon(),
+ ),
+ const SizedBox(width: 8),
+ ],
+ ),
+ ),
),
- ),
- ),
key: const Key("addAddressBookEntryViewAddressField"),
readOnly: false,
autocorrect: false,
@@ -517,8 +528,9 @@ class _NewContactAddressEntryFormState
"Invalid address",
textAlign: TextAlign.left,
style: STextStyles.label(context).copyWith(
- color:
- Theme.of(context).extension<StackColors>()!.textError,
+ color: Theme.of(
+ context,
+ ).extension<StackColors>()!.textError,
),
),
],
diff --git a/lib/pages/buy_view/buy_form.dart b/lib/pages/buy_view/buy_form.dart
index 8f8a0c9..4791104 100644
--- a/lib/pages/buy_view/buy_form.dart
+++ b/lib/pages/buy_view/buy_form.dart
@@ -163,14 +163,13 @@ class _BuyFormState extends ConsumerState<BuyForm> {
unawaited(
showDialog(
context: context,
- builder:
- (context) => WillPopScope(
- child: const CustomLoadingOverlay(
- message: "Loading currency data",
- eventBus: null,
- ),
- onWillPop: () async => shouldPop,
- ),
+ builder: (context) => WillPopScope(
+ child: const CustomLoadingOverlay(
+ message: "Loading currency data",
+ eventBus: null,
+ ),
+ onWillPop: () async => shouldPop,
+ ),
),
);
await _loadSimplexCryptos();
@@ -204,62 +203,60 @@ class _BuyFormState extends ConsumerState<BuyForm> {
_fiatFocusNode.unfocus();
_cryptoFocusNode.unfocus();
- final result =
- isDesktop
- ? await showDialog<Crypto?>(
- context: context,
- builder: (context) {
- return DesktopDialog(
- maxHeight: 700,
- maxWidth: 580,
- child: Column(
- children: [
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- Padding(
- padding: const EdgeInsets.only(left: 32),
- child: Text(
- "Choose a crypto to buy",
- style: STextStyles.desktopH3(context),
- ),
- ),
- const DesktopDialogCloseButton(),
- ],
- ),
- Expanded(
- child: Padding(
- padding: const EdgeInsets.only(
- left: 32,
- right: 32,
- bottom: 32,
+ final result = isDesktop
+ ? await showDialog<Crypto?>(
+ context: context,
+ builder: (context) {
+ return DesktopDialog(
+ maxHeight: 700,
+ maxWidth: 580,
+ child: Column(
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Padding(
+ padding: const EdgeInsets.only(left: 32),
+ child: Text(
+ "Choose a crypto to buy",
+ style: STextStyles.desktopH3(context),
),
- child: Row(
- children: [
- Expanded(
- child: RoundedWhiteContainer(
- padding: const EdgeInsets.all(16),
- borderColor:
- Theme.of(
- context,
- ).extension<StackColors>()!.background,
- child: CryptoSelectionView(coins: coins),
- ),
+ ),
+ const DesktopDialogCloseButton(),
+ ],
+ ),
+ Expanded(
+ child: Padding(
+ padding: const EdgeInsets.only(
+ left: 32,
+ right: 32,
+ bottom: 32,
+ ),
+ child: Row(
+ children: [
+ Expanded(
+ child: RoundedWhiteContainer(
+ padding: const EdgeInsets.all(16),
+ borderColor: Theme.of(
+ context,
+ ).extension<StackColors>()!.background,
+ child: CryptoSelectionView(coins: coins),
),
- ],
- ),
+ ),
+ ],
),
),
- ],
- ),
- );
- },
- )
- : await Navigator.of(context).push(
- MaterialPageRoute<dynamic>(
- builder: (_) => CryptoSelectionView(coins: coins),
- ),
- );
+ ),
+ ],
+ ),
+ );
+ },
+ )
+ : await Navigator.of(context).push(
+ MaterialPageRoute<dynamic>(
+ builder: (_) => CryptoSelectionView(coins: coins),
+ ),
+ );
if (mounted && result is Crypto) {
onSelected(result);
@@ -272,14 +269,13 @@ class _BuyFormState extends ConsumerState<BuyForm> {
unawaited(
showDialog(
context: context,
- builder:
- (context) => WillPopScope(
- child: const CustomLoadingOverlay(
- message: "Loading currency data",
- eventBus: null,
- ),
- onWillPop: () async => shouldPop,
- ),
+ builder: (context) => WillPopScope(
+ child: const CustomLoadingOverlay(
+ message: "Loading currency data",
+ eventBus: null,
+ ),
+ onWillPop: () async => shouldPop,
+ ),
),
);
await _loadSimplexFiats();
@@ -333,62 +329,60 @@ class _BuyFormState extends ConsumerState<BuyForm> {
_fiatFocusNode.unfocus();
_cryptoFocusNode.unfocus();
- final result =
- isDesktop
- ? await showDialog<Fiat?>(
- context: context,
- builder: (context) {
- return DesktopDialog(
- maxHeight: 700,
- maxWidth: 580,
- child: Column(
- children: [
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- Padding(
- padding: const EdgeInsets.only(left: 32),
- child: Text(
- "Choose a fiat with which to pay",
- style: STextStyles.desktopH3(context),
- ),
- ),
- const DesktopDialogCloseButton(),
- ],
- ),
- Expanded(
- child: Padding(
- padding: const EdgeInsets.only(
- left: 32,
- right: 32,
- bottom: 32,
+ final result = isDesktop
+ ? await showDialog<Fiat?>(
+ context: context,
+ builder: (context) {
+ return DesktopDialog(
+ maxHeight: 700,
+ maxWidth: 580,
+ child: Column(
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Padding(
+ padding: const EdgeInsets.only(left: 32),
+ child: Text(
+ "Choose a fiat with which to pay",
+ style: STextStyles.desktopH3(context),
),
- child: Row(
- children: [
- Expanded(
- child: RoundedWhiteContainer(
- padding: const EdgeInsets.all(16),
- borderColor:
- Theme.of(
- context,
- ).extension<StackColors>()!.background,
- child: FiatSelectionView(fiats: fiats),
- ),
+ ),
+ const DesktopDialogCloseButton(),
+ ],
+ ),
+ Expanded(
+ child: Padding(
+ padding: const EdgeInsets.only(
+ left: 32,
+ right: 32,
+ bottom: 32,
+ ),
+ child: Row(
+ children: [
+ Expanded(
+ child: RoundedWhiteContainer(
+ padding: const EdgeInsets.all(16),
+ borderColor: Theme.of(
+ context,
+ ).extension<StackColors>()!.background,
+ child: FiatSelectionView(fiats: fiats),
),
- ],
- ),
+ ),
+ ],
),
),
- ],
- ),
- );
- },
- )
- : await Navigator.of(context).push(
- MaterialPageRoute<dynamic>(
- builder: (_) => FiatSelectionView(fiats: fiats),
- ),
- );
+ ),
+ ],
+ ),
+ );
+ },
+ )
+ : await Navigator.of(context).push(
+ MaterialPageRoute<dynamic>(
+ builder: (_) => FiatSelectionView(fiats: fiats),
+ ),
+ );
if (mounted && result is Fiat) {
onSelected(result);
@@ -406,28 +400,25 @@ class _BuyFormState extends ConsumerState<BuyForm> {
unawaited(
showDialog(
context: context,
- builder:
- (context) => WillPopScope(
- child: const CustomLoadingOverlay(
- message: "Loading quote data",
- eventBus: null,
- ),
- onWillPop: () async => shouldPop,
- ),
+ builder: (context) => WillPopScope(
+ child: const CustomLoadingOverlay(
+ message: "Loading quote data",
+ eventBus: null,
+ ),
+ onWillPop: () async => shouldPop,
+ ),
),
);
quote = SimplexQuote(
crypto: selectedCrypto!,
fiat: selectedFiat!,
- youPayFiatPrice:
- buyWithFiat
- ? Decimal.parse(_buyAmountController.text)
- : Decimal.parse("100"), // dummy value
- youReceiveCryptoAmount:
- buyWithFiat
- ? Decimal.parse("0.000420282") // dummy value
- : Decimal.parse(_buyAmountController.text), // Ternary for this
+ youPayFiatPrice: buyWithFiat
+ ? Decimal.parse(_buyAmountController.text)
+ : Decimal.parse("100"), // dummy value
+ youReceiveCryptoAmount: buyWithFiat
+ ? Decimal.parse("0.000420282") // dummy value
+ : Decimal.parse(_buyAmountController.text), // Ternary for this
id: "id", // anything; we get an ID back
receivingAddress: _receiveAddressController.text,
buyWithFiat: buyWithFiat,
@@ -500,10 +491,9 @@ class _BuyFormState extends ConsumerState<BuyForm> {
child: Text(
"Ok",
style: STextStyles.button(context).copyWith(
- color:
- Theme.of(
- context,
- ).extension<StackColors>()!.accentColorDark,
+ color: Theme.of(
+ context,
+ ).extension<StackColors>()!.accentColorDark,
),
),
onPressed: () {
@@ -587,10 +577,9 @@ class _BuyFormState extends ConsumerState<BuyForm> {
child: Text(
"Ok",
style: STextStyles.button(context).copyWith(
- color:
- Theme.of(
- context,
- ).extension<StackColors>()!.accentColorDark,
+ color: Theme.of(
+ context,
+ ).extension<StackColors>()!.accentColorDark,
),
),
onPressed: () {
@@ -628,62 +617,60 @@ class _BuyFormState extends ConsumerState<BuyForm> {
_fiatFocusNode.unfocus();
_cryptoFocusNode.unfocus();
- final result =
- isDesktop
- ? await showDialog<Fiat?>(
- context: context,
- builder: (context) {
- return DesktopDialog(
- maxHeight: 700,
- maxWidth: 580,
- child: Column(
- children: [
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- Padding(
- padding: const EdgeInsets.only(left: 32),
- child: Text(
- "Preview quote",
- style: STextStyles.desktopH3(context),
- ),
- ),
- const DesktopDialogCloseButton(),
- ],
- ),
- Expanded(
- child: Padding(
- padding: const EdgeInsets.only(
- left: 32,
- right: 32,
- bottom: 32,
+ final result = isDesktop
+ ? await showDialog<Fiat?>(
+ context: context,
+ builder: (context) {
+ return DesktopDialog(
+ maxHeight: 700,
+ maxWidth: 580,
+ child: Column(
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Padding(
+ padding: const EdgeInsets.only(left: 32),
+ child: Text(
+ "Preview quote",
+ style: STextStyles.desktopH3(context),
),
- child: Row(
- children: [
- Expanded(
- child: RoundedWhiteContainer(
- padding: const EdgeInsets.all(16),
- borderColor:
- Theme.of(
- context,
- ).extension<StackColors>()!.background,
- child: BuyQuotePreviewView(quote: quote),
- ),
+ ),
+ const DesktopDialogCloseButton(),
+ ],
+ ),
+ Expanded(
+ child: Padding(
+ padding: const EdgeInsets.only(
+ left: 32,
+ right: 32,
+ bottom: 32,
+ ),
+ child: Row(
+ children: [
+ Expanded(
+ child: RoundedWhiteContainer(
+ padding: const EdgeInsets.all(16),
+ borderColor: Theme.of(
+ context,
+ ).extension<StackColors>()!.background,
+ child: BuyQuotePreviewView(quote: quote),
),
- ],
- ),
+ ),
+ ],
),
),
- ],
- ),
- );
- },
- )
- : await Navigator.of(context).push(
- MaterialPageRoute<dynamic>(
- builder: (_) => BuyQuotePreviewView(quote: quote),
- ),
- );
+ ),
+ ],
+ ),
+ );
+ },
+ )
+ : await Navigator.of(context).push(
+ MaterialPageRoute<dynamic>(
+ builder: (_) => BuyQuotePreviewView(quote: quote),
+ ),
+ );
if (mounted && result is SimplexQuote) {
onSelected(result);
@@ -698,11 +685,12 @@ class _BuyFormState extends ConsumerState<BuyForm> {
}
final qrResult = await ref.read(pBarcodeScanner).scan(context: context);
+ if (qrResult.rawContent == null) return;
Logging.instance.d("qrResult content: ${qrResult.rawContent}");
final paymentData = AddressUtils.parsePaymentUri(
- qrResult.rawContent,
+ qrResult.rawContent!,
logging: Logging.instance,
);
@@ -816,18 +804,14 @@ class _BuyFormState extends ConsumerState<BuyForm> {
builder: (child) => SizedBox(width: 458, child: child),
child: ConditionalParent(
condition: !isDesktop,
- builder:
- (child) => LayoutBuilder(
- builder:
- (context, constraints) => SingleChildScrollView(
- child: ConstrainedBox(
- constraints: BoxConstraints(
- minHeight: constraints.maxHeight,
- ),
- child: IntrinsicHeight(child: child),
- ),
- ),
+ builder: (child) => LayoutBuilder(
+ builder: (context, constraints) => SingleChildScrollView(
+ child: ConstrainedBox(
+ constraints: BoxConstraints(minHeight: constraints.maxHeight),
+ child: IntrinsicHeight(child: child),
),
+ ),
+ ),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
@@ -852,15 +836,14 @@ class _BuyFormState extends ConsumerState<BuyForm> {
vertical: 6,
horizontal: 2,
),
- color:
- _hovering1
- ? Theme.of(context)
- .extension<StackColors>()!
- .currencyListItemBG
- .withOpacity(_hovering1 ? 0.3 : 0)
- : Theme.of(
- context,
- ).extension<StackColors>()!.textFieldDefaultBG,
+ color: _hovering1
+ ? Theme.of(context)
+ .extension<StackColors>()!
+ .currencyListItemBG
+ .withOpacity(_hovering1 ? 0.3 : 0)
+ : Theme.of(
+ context,
+ ).extension<StackColors>()!.textFieldDefaultBG,
child: Padding(
padding: const EdgeInsets.all(12),
child: Row(
@@ -878,10 +861,9 @@ class _BuyFormState extends ConsumerState<BuyForm> {
),
SvgPicture.asset(
Assets.svg.chevronDown,
- color:
- Theme.of(context)
- .extension<StackColors>()!
- .buttonTextSecondaryDisabled,
+ color: Theme.of(context)
+ .extension<StackColors>()!
+ .buttonTextSecondaryDisabled,
width: 10,
height: 5,
),
@@ -899,8 +881,9 @@ class _BuyFormState extends ConsumerState<BuyForm> {
Text(
"I want to pay with",
style: STextStyles.itemSubtitle(context).copyWith(
- color:
- Theme.of(context).extension<StackColors>()!.textDark3,
+ color: Theme.of(
+ context,
+ ).extension<StackColors>()!.textDark3,
),
),
],
@@ -919,15 +902,14 @@ class _BuyFormState extends ConsumerState<BuyForm> {
vertical: 3,
horizontal: 2,
),
- color:
- _hovering2
- ? Theme.of(context)
- .extension<StackColors>()!
- .currencyListItemBG
- .withOpacity(_hovering2 ? 0.3 : 0)
- : Theme.of(
- context,
- ).extension<StackColors>()!.textFieldDefaultBG,
+ color: _hovering2
+ ? Theme.of(context)
+ .extension<StackColors>()!
+ .currencyListItemBG
+ .withOpacity(_hovering2 ? 0.3 : 0)
+ : Theme.of(
+ context,
+ ).extension<StackColors>()!.textFieldDefaultBG,
child: Padding(
padding: const EdgeInsets.only(
left: 12.0,
@@ -943,10 +925,9 @@ class _BuyFormState extends ConsumerState<BuyForm> {
horizontal: 6,
),
decoration: BoxDecoration(
- color:
- Theme.of(
- context,
- ).extension<StackColors>()!.currencyListItemBG,
+ color: Theme.of(
+ context,
+ ).extension<StackColors>()!.currencyListItemBG,
borderRadius: BorderRadius.circular(4),
),
child: Text(
@@ -955,10 +936,9 @@ class _BuyFormState extends ConsumerState<BuyForm> {
),
textAlign: TextAlign.center,
style: STextStyles.smallMed12(context).copyWith(
- color:
- Theme.of(
- context,
- ).extension<StackColors>()!.accentColorDark,
+ color: Theme.of(
+ context,
+ ).extension<StackColors>()!.accentColorDark,
),
),
),
@@ -976,10 +956,9 @@ class _BuyFormState extends ConsumerState<BuyForm> {
),
SvgPicture.asset(
Assets.svg.chevronDown,
- color:
- Theme.of(context)
- .extension<StackColors>()!
- .buttonTextSecondaryDisabled,
+ color: Theme.of(context)
+ .extension<StackColors>()!
+ .buttonTextSecondaryDisabled,
width: 10,
height: 5,
),
@@ -997,8 +976,9 @@ class _BuyFormState extends ConsumerState<BuyForm> {
Text(
buyWithFiat ? "Enter amount" : "Enter crypto amount",
style: STextStyles.itemSubtitle(context).copyWith(
- color:
- Theme.of(context).extension<StackColors>()!.textDark3,
+ color: Theme.of(
+ context,
+ ).extension<StackColors>()!.textDark3,
),
),
CustomTextButton(
@@ -1026,13 +1006,12 @@ class _BuyFormState extends ConsumerState<BuyForm> {
// ? _BuyFormState.minFiat.toStringAsFixed(2) ?? '50.00'
// : _BuyFormState.minCrypto.toStringAsFixed(8),
focusNode: _buyAmountFocusNode,
- keyboardType:
- Util.isDesktop
- ? null
- : const TextInputType.numberWithOptions(
- signed: false,
- decimal: true,
- ),
+ keyboardType: Util.isDesktop
+ ? null
+ : const TextInputType.numberWithOptions(
+ signed: false,
+ decimal: true,
+ ),
textAlign: TextAlign.left,
// inputFormatters: [NumericalRangeFormatter()],
onChanged: (_) {
@@ -1050,10 +1029,9 @@ class _BuyFormState extends ConsumerState<BuyForm> {
),
hintText: "0",
hintStyle: STextStyles.desktopTextExtraSmall(context).copyWith(
- color:
- Theme.of(
- context,
- ).extension<StackColors>()!.textFieldDefaultText,
+ color: Theme.of(
+ context,
+ ).extension<StackColors>()!.textFieldDefaultText,
),
prefixIcon: FittedBox(
fit: BoxFit.scaleDown,
@@ -1064,34 +1042,33 @@ class _BuyFormState extends ConsumerState<BuyForm> {
const SizedBox(width: 2),
buyWithFiat
? Container(
- padding: const EdgeInsets.symmetric(
- vertical: 3,
- horizontal: 6,
- ),
- decoration: BoxDecoration(
- color:
- Theme.of(context)
- .extension<StackColors>()!
- .currencyListItemBG,
- borderRadius: BorderRadius.circular(4),
- ),
- child: Text(
- format.simpleCurrencySymbol(
- selectedFiat?.ticker.toUpperCase() ?? "ERR",
+ padding: const EdgeInsets.symmetric(
+ vertical: 3,
+ horizontal: 6,
),
- textAlign: TextAlign.center,
- style: STextStyles.smallMed12(context).copyWith(
- color:
- Theme.of(context)
- .extension<StackColors>()!
- .accentColorDark,
+ decoration: BoxDecoration(
+ color: Theme.of(context)
+ .extension<StackColors>()!
+ .currencyListItemBG,
+ borderRadius: BorderRadius.circular(4),
),
- ),
- )
+ child: Text(
+ format.simpleCurrencySymbol(
+ selectedFiat?.ticker.toUpperCase() ?? "ERR",
+ ),
+ textAlign: TextAlign.center,
+ style: STextStyles.smallMed12(context)
+ .copyWith(
+ color: Theme.of(context)
+ .extension<StackColors>()!
+ .accentColorDark,
+ ),
+ ),
+ )
: CoinIconForTicker(
- ticker: selectedCrypto?.ticker ?? "BTC",
- size: 20,
- ),
+ ticker: selectedCrypto?.ticker ?? "BTC",
+ size: 20,
+ ),
SizedBox(
width: buyWithFiat ? 8 : 10,
), // maybe make isDesktop-aware?
@@ -1100,10 +1077,9 @@ class _BuyFormState extends ConsumerState<BuyForm> {
? selectedFiat?.ticker ?? "ERR"
: selectedCrypto?.ticker ?? "ERR",
style: STextStyles.smallMed14(context).copyWith(
- color:
- Theme.of(
- context,
- ).extension<StackColors>()!.accentColorDark,
+ color: Theme.of(
+ context,
+ ).extension<StackColors>()!.accentColorDark,
),
),
],
@@ -1118,50 +1094,49 @@ class _BuyFormState extends ConsumerState<BuyForm> {
children: [
_buyAmountController.text.isNotEmpty
? TextFieldIconButton(
- key: const Key(
- "buyViewClearAmountFieldButtonKey",
- ),
- onTap: () {
- // if (_BuyFormState.buyWithFiat) {
- // _buyAmountController.text = _BuyFormState
- // .minFiat
- // .toStringAsFixed(2);
- // } else {
- // if (selectedCrypto?.ticker ==
- // _BuyFormState.boundedCryptoTicker) {
- // _buyAmountController.text = _BuyFormState
- // .minCrypto
- // .toStringAsFixed(8);
- // }
- // }
- _buyAmountController.text = "";
- validateAmount();
- },
- child: const XIcon(),
- )
+ key: const Key(
+ "buyViewClearAmountFieldButtonKey",
+ ),
+ onTap: () {
+ // if (_BuyFormState.buyWithFiat) {
+ // _buyAmountController.text = _BuyFormState
+ // .minFiat
+ // .toStringAsFixed(2);
+ // } else {
+ // if (selectedCrypto?.ticker ==
+ // _BuyFormState.boundedCryptoTicker) {
+ // _buyAmountController.text = _BuyFormState
+ // .minCrypto
+ // .toStringAsFixed(8);
+ // }
+ // }
+ _buyAmountController.text = "";
+ validateAmount();
+ },
+ child: const XIcon(),
+ )
: TextFieldIconButton(
- key: const Key(
- "buyViewPasteAddressFieldButtonKey",
- ),
- onTap: () async {
- final ClipboardData? data = await clipboard
- .getData(Clipboard.kTextPlain);
+ key: const Key(
+ "buyViewPasteAddressFieldButtonKey",
+ ),
+ onTap: () async {
+ final ClipboardData? data = await clipboard
+ .getData(Clipboard.kTextPlain);
- final amountString = Decimal.tryParse(
- data?.text ?? "",
- );
- if (amountString != null) {
- _buyAmountController.text =
- amountString.toString();
+ final amountString = Decimal.tryParse(
+ data?.text ?? "",
+ );
+ if (amountString != null) {
+ _buyAmountController.text = amountString
+ .toString();
- validateAmount();
- }
- },
- child:
- _buyAmountController.text.isEmpty
- ? const ClipboardIcon()
- : const XIcon(),
- ),
+ validateAmount();
+ }
+ },
+ child: _buyAmountController.text.isEmpty
+ ? const ClipboardIcon()
+ : const XIcon(),
+ ),
],
),
),
@@ -1182,8 +1157,9 @@ class _BuyFormState extends ConsumerState<BuyForm> {
Text(
"Enter receiving address",
style: STextStyles.itemSubtitle(context).copyWith(
- color:
- Theme.of(context).extension<StackColors>()!.textDark3,
+ color: Theme.of(
+ context,
+ ).extension<StackColors>()!.textDark3,
),
),
if (AppConfig.isStackCoin(selectedCrypto?.ticker))
@@ -1209,8 +1185,8 @@ class _BuyFormState extends ConsumerState<BuyForm> {
// model.recipientAddress =
// await manager.currentReceivingAddress;
- final address =
- await wallet.getCurrentReceivingAddress();
+ final address = await wallet
+ .getCurrentReceivingAddress();
if (address!.type == AddressType.p2tr &&
wallet is Bip39HDWallet) {
@@ -1289,85 +1265,87 @@ class _BuyFormState extends ConsumerState<BuyForm> {
},
focusNode: _receiveAddressFocusNode,
style: STextStyles.field(context),
- decoration: standardInputDecoration(
- "Enter ${selectedCrypto?.ticker} address",
- _receiveAddressFocusNode,
- context,
- ).copyWith(
- contentPadding: const EdgeInsets.only(
- left: 13,
- top: 6,
- bottom: 8,
- right: 5,
- ),
- suffixIcon: Padding(
- padding:
- _receiveAddressController.text.isEmpty
+ decoration:
+ standardInputDecoration(
+ "Enter ${selectedCrypto?.ticker} address",
+ _receiveAddressFocusNode,
+ context,
+ ).copyWith(
+ contentPadding: const EdgeInsets.only(
+ left: 13,
+ top: 6,
+ bottom: 8,
+ right: 5,
+ ),
+ suffixIcon: Padding(
+ padding: _receiveAddressController.text.isEmpty
? const EdgeInsets.only(right: 8)
: const EdgeInsets.only(right: 0),
- child: UnconstrainedBox(
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceAround,
- children: [
- _addressToggleFlag
- ? TextFieldIconButton(
- key: const Key(
- "buyViewClearAddressFieldButtonKey",
- ),
- onTap: () {
- _receiveAddressController.text = "";
- _address = "";
- setState(() {
- _addressToggleFlag = false;
- });
- },
- child: const XIcon(),
- )
- : TextFieldIconButton(
- key: const Key(
- "buyViewPasteAddressFieldButtonKey",
- ),
- onTap: () async {
- final ClipboardData? data = await clipboard
- .getData(Clipboard.kTextPlain);
- if (data?.text != null &&
- data!.text!.isNotEmpty) {
- String content = data.text!.trim();
- if (content.contains("\n")) {
- content = content.substring(
- 0,
- content.indexOf("\n"),
- );
- }
-
- _receiveAddressController.text = content;
- _address = content;
-
- setState(() {
- _addressToggleFlag =
- _receiveAddressController
- .text
- .isNotEmpty;
- });
- }
- },
- child:
- _receiveAddressController.text.isEmpty
- ? const ClipboardIcon()
- : const XIcon(),
- ),
- if (_receiveAddressController.text.isEmpty &&
- AppConfig.isStackCoin(selectedCrypto?.ticker) &&
- isDesktop)
- TextFieldIconButton(
- key: const Key("buyViewAddressBookButtonKey"),
- onTap: () async {
- final entry = await showDialog<
- ContactAddressEntry?
- >(
- context: context,
- builder:
- (context) => DesktopDialog(
+ child: UnconstrainedBox(
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
+ children: [
+ _addressToggleFlag
+ ? TextFieldIconButton(
+ key: const Key(
+ "buyViewClearAddressFieldButtonKey",
+ ),
+ onTap: () {
+ _receiveAddressController.text = "";
+ _address = "";
+ setState(() {
+ _addressToggleFlag = false;
+ });
+ },
+ child: const XIcon(),
+ )
+ : TextFieldIconButton(
+ key: const Key(
+ "buyViewPasteAddressFieldButtonKey",
+ ),
+ onTap: () async {
+ final ClipboardData? data =
+ await clipboard.getData(
+ Clipboard.kTextPlain,
+ );
+ if (data?.text != null &&
+ data!.text!.isNotEmpty) {
+ String content = data.text!.trim();
+ if (content.contains("\n")) {
+ content = content.substring(
+ 0,
+ content.indexOf("\n"),
+ );
+ }
+
+ _receiveAddressController.text =
+ content;
+ _address = content;
+
+ setState(() {
+ _addressToggleFlag =
+ _receiveAddressController
+ .text
+ .isNotEmpty;
+ });
+ }
+ },
+ child:
+ _receiveAddressController.text.isEmpty
+ ? const ClipboardIcon()
+ : const XIcon(),
+ ),
+ if (_receiveAddressController.text.isEmpty &&
+ AppConfig.isStackCoin(
+ selectedCrypto?.ticker,
+ ) &&
+ isDesktop)
+ TextFieldIconButton(
+ key: const Key("buyViewAddressBookButtonKey"),
+ onTap: () async {
+ final entry = await showDialog<ContactAddressEntry?>(
+ context: context,
+ builder: (context) => DesktopDialog(
maxWidth: 696,
maxHeight: 600,
child: Column(
@@ -1410,45 +1388,47 @@ class _BuyFormState extends ConsumerState<BuyForm> {
],
),
),
- );
+ );
- if (entry != null) {
- _receiveAddressController.text =
- entry.address;
- _address = entry.address;
+ if (entry != null) {
+ _receiveAddressController.text =
+ entry.address;
+ _address = entry.address;
- setState(() {
- _addressToggleFlag = true;
- });
- }
- },
- child: const AddressBookIcon(),
- ),
- if (_receiveAddressController.text.isEmpty &&
- AppConfig.isStackCoin(selectedCrypto?.ticker) &&
- !isDesktop)
- TextFieldIconButton(
- key: const Key("buyViewAddressBookButtonKey"),
- onTap: () {
- Navigator.of(
- context,
- rootNavigator: isDesktop,
- ).pushNamed(AddressBookView.routeName);
- },
- child: const AddressBookIcon(),
- ),
- if (_receiveAddressController.text.isEmpty &&
- !isDesktop)
- TextFieldIconButton(
- key: const Key("buyViewScanQrButtonKey"),
- onTap: _onQrTapped,
- child: const QrCodeIcon(),
- ),
- ],
+ setState(() {
+ _addressToggleFlag = true;
+ });
+ }
+ },
+ child: const AddressBookIcon(),
+ ),
+ if (_receiveAddressController.text.isEmpty &&
+ AppConfig.isStackCoin(
+ selectedCrypto?.ticker,
+ ) &&
+ !isDesktop)
+ TextFieldIconButton(
+ key: const Key("buyViewAddressBookButtonKey"),
+ onTap: () {
+ Navigator.of(
+ context,
+ rootNavigator: isDesktop,
+ ).pushNamed(AddressBookView.routeName);
+ },
+ child: const AddressBookIcon(),
+ ),
+ if (_receiveAddressController.text.isEmpty &&
+ !isDesktop)
+ TextFieldIconButton(
+ key: const Key("buyViewScanQrButtonKey"),
+ onTap: _onQrTapped,
+ child: const QrCodeIcon(),
+ ),
+ ],
+ ),
+ ),
),
),
- ),
- ),
),
),
SizedBox(height: isDesktop ? 10 : 4),
diff --git a/lib/pages/exchange_view/exchange_step_views/step_2_view.dart b/lib/pages/exchange_view/exchange_step_views/step_2_view.dart
index a731bf9..3bead41 100644
--- a/lib/pages/exchange_view/exchange_step_views/step_2_view.dart
+++ b/lib/pages/exchange_view/exchange_step_views/step_2_view.dart
@@ -70,9 +70,10 @@ class _Step2ViewState extends ConsumerState<Step2View> {
void _onRefundQrTapped() async {
try {
final qrResult = await ref.read(pBarcodeScanner).scan(context: context);
+ if (qrResult.rawContent == null) return;
final paymentData = AddressUtils.parsePaymentUri(
- qrResult.rawContent,
+ qrResult.rawContent!,
logging: Logging.instance,
);
@@ -87,7 +88,7 @@ class _Step2ViewState extends ConsumerState<Step2View> {
_refundController.text.isNotEmpty;
});
} else {
- _refundController.text = qrResult.rawContent;
+ _refundController.text = qrResult.rawContent!;
model.refundAddress = _refundController.text;
setState(() {
@@ -123,9 +124,10 @@ class _Step2ViewState extends ConsumerState<Step2View> {
void _onToQrTapped() async {
try {
final qrResult = await ref.read(pBarcodeScanner).scan(context: context);
+ if (qrResult.rawContent == null) return;
final paymentData = AddressUtils.parsePaymentUri(
- qrResult.rawContent,
+ qrResult.rawContent!,
logging: Logging.instance,
);
@@ -141,7 +143,7 @@ class _Step2ViewState extends ConsumerState<Step2View> {
!ref.read(efExchangeProvider).supportsRefundAddress);
});
} else {
- _toController.text = qrResult.rawContent;
+ _toController.text = qrResult.rawContent!;
model.recipientAddress = _toController.text;
setState(() {
@@ -373,156 +375,168 @@ class _Step2ViewState extends ConsumerState<Step2View> {
!supportsRefund);
});
},
- decoration: standardInputDecoration(
- "Enter the ${model.receiveTicker.toUpperCase()} payout address",
- _toFocusNode,
- context,
- ).copyWith(
- contentPadding: const EdgeInsets.only(
- left: 16,
- top: 6,
- bottom: 8,
- right: 5,
- ),
- suffixIcon: Padding(
- padding:
- _toController.text.isEmpty
+ decoration:
+ standardInputDecoration(
+ "Enter the ${model.receiveTicker.toUpperCase()} payout address",
+ _toFocusNode,
+ context,
+ ).copyWith(
+ contentPadding: const EdgeInsets.only(
+ left: 16,
+ top: 6,
+ bottom: 8,
+ right: 5,
+ ),
+ suffixIcon: Padding(
+ padding: _toController.text.isEmpty
? const EdgeInsets.only(right: 8)
: const EdgeInsets.only(right: 0),
- child: UnconstrainedBox(
- child: Row(
- mainAxisAlignment:
- MainAxisAlignment.spaceAround,
- children: [
- _toController.text.isNotEmpty
- ? TextFieldIconButton(
- key: const Key(
- "sendViewClearAddressFieldButtonKey",
- ),
- onTap: () {
- _toController.text = "";
- model.recipientAddress =
- _toController.text;
-
- setState(() {
- enableNext =
- _toController
- .text
- .isNotEmpty &&
- (_refundController
- .text
- .isNotEmpty ||
- !supportsRefund);
- });
- },
- child: const XIcon(),
- )
- : TextFieldIconButton(
- key: const Key(
- "sendViewPasteAddressFieldButtonKey",
- ),
- onTap: () async {
- final ClipboardData? data =
- await clipboard.getData(
- Clipboard.kTextPlain,
- );
- if (data?.text != null &&
- data!.text!.isNotEmpty) {
- final content =
- data.text!.trim();
-
- _toController.text =
- content;
- model.recipientAddress =
- _toController.text;
-
- setState(() {
- enableNext =
- _toController
- .text
- .isNotEmpty &&
- (_refundController
+ child: UnconstrainedBox(
+ child: Row(
+ mainAxisAlignment:
+ MainAxisAlignment.spaceAround,
+ children: [
+ _toController.text.isNotEmpty
+ ? TextFieldIconButton(
+ key: const Key(
+ "sendViewClearAddressFieldButtonKey",
+ ),
+ onTap: () {
+ _toController.text = "";
+ model.recipientAddress =
+ _toController.text;
+
+ setState(() {
+ enableNext =
+ _toController
.text
- .isNotEmpty ||
- !supportsRefund);
- });
- }
- },
- child:
- _toController.text.isEmpty
- ? const ClipboardIcon()
- : const XIcon(),
- ),
- if (_toController.text.isEmpty)
- TextFieldIconButton(
- key: const Key(
- "sendViewAddressBookButtonKey",
- ),
- onTap: () {
- ref
- .read(
- exchangeFlowIsActiveStateProvider
- .state,
+ .isNotEmpty &&
+ (_refundController
+ .text
+ .isNotEmpty ||
+ !supportsRefund);
+ });
+ },
+ child: const XIcon(),
)
- .state = true;
- Navigator.of(
- context,
- ).pushNamed(AddressBookView.routeName).then((
- _,
- ) {
- ref
- .read(
- exchangeFlowIsActiveStateProvider
- .state,
- )
- .state = false;
+ : TextFieldIconButton(
+ key: const Key(
+ "sendViewPasteAddressFieldButtonKey",
+ ),
+ onTap: () async {
+ final ClipboardData?
+ data = await clipboard
+ .getData(
+ Clipboard
+ .kTextPlain,
+ );
+ if (data?.text !=
+ null &&
+ data!
+ .text!
+ .isNotEmpty) {
+ final content = data
+ .text!
+ .trim();
+
+ _toController.text =
+ content;
+ model.recipientAddress =
+ _toController
+ .text;
- final address =
+ setState(() {
+ enableNext =
+ _toController
+ .text
+ .isNotEmpty &&
+ (_refundController
+ .text
+ .isNotEmpty ||
+ !supportsRefund);
+ });
+ }
+ },
+ child:
+ _toController
+ .text
+ .isEmpty
+ ? const ClipboardIcon()
+ : const XIcon(),
+ ),
+ if (_toController.text.isEmpty)
+ TextFieldIconButton(
+ key: const Key(
+ "sendViewAddressBookButtonKey",
+ ),
+ onTap: () {
+ ref
+ .read(
+ exchangeFlowIsActiveStateProvider
+ .state,
+ )
+ .state =
+ true;
+ Navigator.of(
+ context,
+ ).pushNamed(AddressBookView.routeName).then((
+ _,
+ ) {
ref
+ .read(
+ exchangeFlowIsActiveStateProvider
+ .state,
+ )
+ .state =
+ false;
+
+ final address = ref
.read(
exchangeFromAddressBookAddressStateProvider
.state,
)
.state;
- if (address.isNotEmpty) {
- _toController.text =
- address;
- model.recipientAddress =
- _toController.text;
- ref
- .read(
- exchangeFromAddressBookAddressStateProvider
- .state,
- )
- .state = "";
- }
- setState(() {
- enableNext =
- _toController
- .text
- .isNotEmpty &&
- (_refundController
+ if (address.isNotEmpty) {
+ _toController.text =
+ address;
+ model.recipientAddress =
+ _toController.text;
+ ref
+ .read(
+ exchangeFromAddressBookAddressStateProvider
+ .state,
+ )
+ .state =
+ "";
+ }
+ setState(() {
+ enableNext =
+ _toController
.text
- .isNotEmpty ||
- !supportsRefund);
- });
- });
- },
- child: const AddressBookIcon(),
- ),
- if (_toController.text.isEmpty)
- TextFieldIconButton(
- key: const Key(
- "sendViewScanQrButtonKey",
- ),
- onTap: _onToQrTapped,
- child: const QrCodeIcon(),
- ),
- ],
+ .isNotEmpty &&
+ (_refundController
+ .text
+ .isNotEmpty ||
+ !supportsRefund);
+ });
+ });
+ },
+ child:
+ const AddressBookIcon(),
+ ),
+ if (_toController.text.isEmpty)
+ TextFieldIconButton(
+ key: const Key(
+ "sendViewScanQrButtonKey",
+ ),
+ onTap: _onToQrTapped,
+ child: const QrCodeIcon(),
+ ),
+ ],
+ ),
+ ),
),
),
- ),
- ),
),
),
const SizedBox(height: 6),
@@ -628,154 +642,172 @@ class _Step2ViewState extends ConsumerState<Step2View> {
_refundController.text.isNotEmpty;
});
},
- decoration: standardInputDecoration(
- "Enter ${model.sendTicker.toUpperCase()} refund address",
- _refundFocusNode,
- context,
- ).copyWith(
- contentPadding: const EdgeInsets.only(
- left: 16,
- top: 6,
- bottom: 8,
- right: 5,
- ),
- suffixIcon: Padding(
- padding:
- _refundController.text.isEmpty
+ decoration:
+ standardInputDecoration(
+ "Enter ${model.sendTicker.toUpperCase()} refund address",
+ _refundFocusNode,
+ context,
+ ).copyWith(
+ contentPadding: const EdgeInsets.only(
+ left: 16,
+ top: 6,
+ bottom: 8,
+ right: 5,
+ ),
+ suffixIcon: Padding(
+ padding:
+ _refundController.text.isEmpty
? const EdgeInsets.only(right: 16)
: const EdgeInsets.only(right: 0),
- child: UnconstrainedBox(
- child: Row(
- mainAxisAlignment:
- MainAxisAlignment.spaceAround,
- children: [
- _refundController.text.isNotEmpty
- ? TextFieldIconButton(
- key: const Key(
- "sendViewClearAddressFieldButtonKey",
- ),
- onTap: () {
- _refundController.text = "";
- model.refundAddress =
- _refundController.text;
-
- setState(() {
- enableNext =
- _toController
- .text
- .isNotEmpty &&
- _refundController
- .text
- .isNotEmpty;
- });
- },
- child: const XIcon(),
- )
- : TextFieldIconButton(
- key: const Key(
- "sendViewPasteAddressFieldButtonKey",
- ),
- onTap: () async {
- final ClipboardData? data =
- await clipboard.getData(
- Clipboard.kTextPlain,
- );
- if (data?.text != null &&
- data!
- .text!
- .isNotEmpty) {
- final content =
- data.text!.trim();
-
- _refundController.text =
- content;
- model.refundAddress =
+ child: UnconstrainedBox(
+ child: Row(
+ mainAxisAlignment:
+ MainAxisAlignment.spaceAround,
+ children: [
+ _refundController
+ .text
+ .isNotEmpty
+ ? TextFieldIconButton(
+ key: const Key(
+ "sendViewClearAddressFieldButtonKey",
+ ),
+ onTap: () {
_refundController
- .text;
+ .text =
+ "";
+ model.refundAddress =
+ _refundController
+ .text;
+
+ setState(() {
+ enableNext =
+ _toController
+ .text
+ .isNotEmpty &&
+ _refundController
+ .text
+ .isNotEmpty;
+ });
+ },
+ child: const XIcon(),
+ )
+ : TextFieldIconButton(
+ key: const Key(
+ "sendViewPasteAddressFieldButtonKey",
+ ),
+ onTap: () async {
+ final ClipboardData?
+ data = await clipboard
+ .getData(
+ Clipboard
+ .kTextPlain,
+ );
+ if (data?.text !=
+ null &&
+ data!
+ .text!
+ .isNotEmpty) {
+ final content = data
+ .text!
+ .trim();
- setState(() {
- enableNext =
- _toController
- .text
- .isNotEmpty &&
+ _refundController
+ .text =
+ content;
+ model.refundAddress =
+ _refundController
+ .text;
+
+ setState(() {
+ enableNext =
+ _toController
+ .text
+ .isNotEmpty &&
+ _refundController
+ .text
+ .isNotEmpty;
+ });
+ }
+ },
+ child:
_refundController
.text
- .isNotEmpty;
- });
- }
- },
- child:
- _refundController
- .text
- .isEmpty
- ? const ClipboardIcon()
- : const XIcon(),
- ),
- if (_refundController.text.isEmpty)
- TextFieldIconButton(
- key: const Key(
- "sendViewAddressBookButtonKey",
- ),
- onTap: () {
- ref
- .read(
- exchangeFlowIsActiveStateProvider
- .state,
- )
- .state = true;
- Navigator.of(context)
- .pushNamed(
- AddressBookView
- .routeName,
- )
- .then((_) {
- ref
- .read(
- exchangeFlowIsActiveStateProvider
- .state,
- )
- .state = false;
- final address =
+ .isEmpty
+ ? const ClipboardIcon()
+ : const XIcon(),
+ ),
+ if (_refundController
+ .text
+ .isEmpty)
+ TextFieldIconButton(
+ key: const Key(
+ "sendViewAddressBookButtonKey",
+ ),
+ onTap: () {
+ ref
+ .read(
+ exchangeFlowIsActiveStateProvider
+ .state,
+ )
+ .state =
+ true;
+ Navigator.of(context)
+ .pushNamed(
+ AddressBookView
+ .routeName,
+ )
+ .then((_) {
ref
+ .read(
+ exchangeFlowIsActiveStateProvider
+ .state,
+ )
+ .state =
+ false;
+ final address = ref
.read(
exchangeFromAddressBookAddressStateProvider
.state,
)
.state;
- if (address
- .isNotEmpty) {
- _refundController
- .text = address;
- model.refundAddress =
+ if (address
+ .isNotEmpty) {
_refundController
- .text;
- }
- setState(() {
- enableNext =
- _toController
- .text
- .isNotEmpty &&
- _refundController
- .text
- .isNotEmpty;
- });
- });
- },
- child: const AddressBookIcon(),
- ),
- if (_refundController.text.isEmpty)
- TextFieldIconButton(
- key: const Key(
- "sendViewScanQrButtonKey",
- ),
- onTap: _onRefundQrTapped,
- child: const QrCodeIcon(),
- ),
- ],
+ .text =
+ address;
+ model.refundAddress =
+ _refundController
+ .text;
+ }
+ setState(() {
+ enableNext =
+ _toController
+ .text
+ .isNotEmpty &&
+ _refundController
+ .text
+ .isNotEmpty;
+ });
+ });
+ },
+ child:
+ const AddressBookIcon(),
+ ),
+ if (_refundController
+ .text
+ .isEmpty)
+ TextFieldIconButton(
+ key: const Key(
+ "sendViewScanQrButtonKey",
+ ),
+ onTap: _onRefundQrTapped,
+ child: const QrCodeIcon(),
+ ),
+ ],
+ ),
+ ),
),
),
- ),
- ),
),
),
if (supportsRefund) const SizedBox(height: 6),
@@ -802,14 +834,12 @@ class _Step2ViewState extends ConsumerState<Step2View> {
),
child: Text(
"Back",
- style: STextStyles.button(
- context,
- ).copyWith(
- color:
- Theme.of(context)
+ style: STextStyles.button(context)
+ .copyWith(
+ color: Theme.of(context)
.extension<StackColors>()!
.buttonTextSecondary,
- ),
+ ),
),
),
),
diff --git a/lib/pages/finalize_view/finalize_view.dart b/lib/pages/finalize_view/finalize_view.dart
index e0a3415..65fb50a 100644
--- a/lib/pages/finalize_view/finalize_view.dart
+++ b/lib/pages/finalize_view/finalize_view.dart
@@ -80,8 +80,8 @@ class _FinalizeViewState extends ConsumerState<FinalizeView> {
if (mounted) {
final qrResult = await ref.read(pBarcodeScanner).scan(context: context);
- if (qrResult.rawContent.isNotEmpty && qrResult.rawContent != "null") {
- _slateController.text = qrResult.rawContent;
+ if (qrResult.rawContent != null && qrResult.rawContent!.isNotEmpty) {
+ _slateController.text = qrResult.rawContent!;
setState(() {
_slateToggleFlag = _slateController.text.isNotEmpty;
});
@@ -156,14 +156,12 @@ class _FinalizeViewState extends ConsumerState<FinalizeView> {
if (ex != null) {
await showDialog<void>(
context: context,
- builder:
- (context) => StackOkDialog(
- desktopPopRootNavigator: Util.isDesktop,
- title: "Slatepack finalize error",
- message:
- ex?.toString() ?? "Unexpected result without exception",
- maxWidth: Util.isDesktop ? 400 : null,
- ),
+ builder: (context) => StackOkDialog(
+ desktopPopRootNavigator: Util.isDesktop,
+ title: "Slatepack finalize error",
+ message: ex?.toString() ?? "Unexpected result without exception",
+ maxWidth: Util.isDesktop ? 400 : null,
+ ),
);
} else {
setState(() {
@@ -201,45 +199,45 @@ class _FinalizeViewState extends ConsumerState<FinalizeView> {
return ConditionalParent(
condition: !Util.isDesktop,
- builder:
- (child) => Background(
- child: Scaffold(
- backgroundColor:
- Theme.of(context).extension<StackColors>()!.background,
- appBar: AppBar(
- leading: AppBarBackButton(
- onPressed: () {
- Navigator.of(context).pop();
- },
- ),
- title: Text(
- "Finalize slatepack",
- style: STextStyles.navBarTitle(context),
- ),
- ),
- body: SafeArea(
- child: LayoutBuilder(
- builder: (context, constraints) {
- return SingleChildScrollView(
- child: ConstrainedBox(
- constraints: BoxConstraints(
- minHeight: constraints.maxHeight,
- ),
- child: IntrinsicHeight(
- child: Padding(
- padding: EdgeInsets.symmetric(
- horizontal: Constants.size.standardPadding,
- ),
- child: child,
- ),
+ builder: (child) => Background(
+ child: Scaffold(
+ backgroundColor: Theme.of(
+ context,
+ ).extension<StackColors>()!.background,
+ appBar: AppBar(
+ leading: AppBarBackButton(
+ onPressed: () {
+ Navigator.of(context).pop();
+ },
+ ),
+ title: Text(
+ "Finalize slatepack",
+ style: STextStyles.navBarTitle(context),
+ ),
+ ),
+ body: SafeArea(
+ child: LayoutBuilder(
+ builder: (context, constraints) {
+ return SingleChildScrollView(
+ child: ConstrainedBox(
+ constraints: BoxConstraints(
+ minHeight: constraints.maxHeight,
+ ),
+ child: IntrinsicHeight(
+ child: Padding(
+ padding: EdgeInsets.symmetric(
+ horizontal: Constants.size.standardPadding,
),
+ child: child,
),
- );
- },
- ),
- ),
+ ),
+ ),
+ );
+ },
),
),
+ ),
+ ),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
@@ -268,61 +266,61 @@ class _FinalizeViewState extends ConsumerState<FinalizeView> {
},
focusNode: _slateFocusNode,
style: STextStyles.field(context),
- decoration: standardInputDecoration(
- "Enter Final Slatepack Message",
- _slateFocusNode,
- context,
- desktopMed: true,
- ).copyWith(
- contentPadding: const EdgeInsets.symmetric(
- horizontal: 16,
- vertical: 12, // Adjust vertical padding for better alignment
- ),
- suffixIcon: Padding(
- padding:
- _slateController.text.isEmpty
+ decoration:
+ standardInputDecoration(
+ "Enter Final Slatepack Message",
+ _slateFocusNode,
+ context,
+ desktopMed: true,
+ ).copyWith(
+ contentPadding: const EdgeInsets.symmetric(
+ horizontal: 16,
+ vertical:
+ 12, // Adjust vertical padding for better alignment
+ ),
+ suffixIcon: Padding(
+ padding: _slateController.text.isEmpty
? const EdgeInsets.only(right: 8)
: const EdgeInsets.only(right: 0),
- child: UnconstrainedBox(
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceAround,
- children: [
- _slateToggleFlag
- ? TextFieldIconButton(
- key: const Key(
- "slateFinalizeClearFieldButtonKey",
+ child: UnconstrainedBox(
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
+ children: [
+ _slateToggleFlag
+ ? TextFieldIconButton(
+ key: const Key(
+ "slateFinalizeClearFieldButtonKey",
+ ),
+ onTap: () {
+ _slateController.text = "";
+ setState(() {
+ _slateToggleFlag = false;
+ });
+ },
+ child: const XIcon(),
+ )
+ : TextFieldIconButton(
+ key: const Key(
+ "slateFinalizePasteFieldButtonKey",
+ ),
+ onTap: _pasteSlatepack,
+ child: _slateController.text.isEmpty
+ ? const ClipboardIcon()
+ : const XIcon(),
+ ),
+ if (_slateController.text.isEmpty)
+ TextFieldIconButton(
+ semanticsLabel:
+ "Scan QR Button. Opens Camera For Scanning QR Code.",
+ key: const Key("sendViewScanQrButtonKey"),
+ onTap: _scanQr,
+ child: const QrCodeIcon(),
),
- onTap: () {
- _slateController.text = "";
- setState(() {
- _slateToggleFlag = false;
- });
- },
- child: const XIcon(),
- )
- : TextFieldIconButton(
- key: const Key(
- "slateFinalizePasteFieldButtonKey",
- ),
- onTap: _pasteSlatepack,
- child:
- _slateController.text.isEmpty
- ? const ClipboardIcon()
- : const XIcon(),
- ),
- if (_slateController.text.isEmpty)
- TextFieldIconButton(
- semanticsLabel:
- "Scan QR Button. Opens Camera For Scanning QR Code.",
- key: const Key("sendViewScanQrButtonKey"),
- onTap: _scanQr,
- child: const QrCodeIcon(),
- ),
- ],
+ ],
+ ),
+ ),
),
),
- ),
- ),
),
),
Util.isDesktop ? const SizedBox(height: 24) : const Spacer(),
diff --git a/lib/pages/namecoin_names/sub_widgets/transfer_option_widget.dart b/lib/pages/namecoin_names/sub_widgets/transfer_option_widget.dart
index 89be612..5dbc649 100644
--- a/lib/pages/namecoin_names/sub_widgets/transfer_option_widget.dart
+++ b/lib/pages/namecoin_names/sub_widgets/transfer_option_widget.dart
@@ -169,16 +169,15 @@ class _TransferOptionWidgetState extends ConsumerState<TransferOptionWidget> {
if (Util.isDesktop) {
await showDialog<void>(
context: context,
- builder:
- (context) => SDialog(
- child: SizedBox(
- width: 580,
- child: ConfirmNameTransactionView(
- txData: txData,
- walletId: widget.walletId,
- ),
- ),
+ builder: (context) => SDialog(
+ child: SizedBox(
+ width: 580,
+ child: ConfirmNameTransactionView(
+ txData: txData,
+ walletId: widget.walletId,
),
+ ),
+ ),
);
} else {
await Navigator.of(context).pushNamed(
@@ -203,13 +202,12 @@ class _TransferOptionWidgetState extends ConsumerState<TransferOptionWidget> {
await showDialog<void>(
context: context,
- builder:
- (_) => StackOkDialog(
- title: "Error",
- message: err,
- desktopPopRootNavigator: Util.isDesktop,
- maxWidth: Util.isDesktop ? 600 : null,
- ),
+ builder: (_) => StackOkDialog(
+ title: "Error",
+ message: err,
+ desktopPopRootNavigator: Util.isDesktop,
+ maxWidth: Util.isDesktop ? 600 : null,
+ ),
);
}
} finally {
@@ -238,12 +236,14 @@ class _TransferOptionWidgetState extends ConsumerState<TransferOptionWidget> {
}
final qrResult = await ref.read(pBarcodeScanner).scan(context: context);
+ if (qrResult.rawContent == null) return;
+
final coin = ref.read(pWalletCoin(walletId));
Logging.instance.d("qrResult content: ${qrResult.rawContent}");
final paymentData = AddressUtils.parsePaymentUri(
- qrResult.rawContent,
+ qrResult.rawContent!,
logging: Logging.instance,
);
@@ -257,7 +257,7 @@ class _TransferOptionWidgetState extends ConsumerState<TransferOptionWidget> {
// now check for non standard encoded basic address
} else {
- _address = qrResult.rawContent.split("\n").first.trim();
+ _address = qrResult.rawContent!.split("\n").first.trim();
_addressController.text = _address ?? "";
_setValidAddressProviders(_address);
@@ -313,8 +313,9 @@ class _TransferOptionWidgetState extends ConsumerState<TransferOptionWidget> {
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
- crossAxisAlignment:
- Util.isDesktop ? CrossAxisAlignment.start : CrossAxisAlignment.center,
+ crossAxisAlignment: Util.isDesktop
+ ? CrossAxisAlignment.start
+ : CrossAxisAlignment.center,
children: [
ClipRRect(
borderRadius: BorderRadius.circular(
@@ -338,121 +339,120 @@ class _TransferOptionWidgetState extends ConsumerState<TransferOptionWidget> {
},
focusNode: _addressFocusNode,
style: STextStyles.field(context),
- decoration: standardInputDecoration(
- "Enter ${ref.watch(pWalletCoin(walletId)).ticker} address",
- _addressFocusNode,
- context,
- ).copyWith(
- contentPadding: const EdgeInsets.only(
- left: 16,
- top: 6,
- bottom: 8,
- right: 5,
- ),
- suffixIcon: Padding(
- padding:
- _addressController.text.isEmpty
+ decoration:
+ standardInputDecoration(
+ "Enter ${ref.watch(pWalletCoin(walletId)).ticker} address",
+ _addressFocusNode,
+ context,
+ ).copyWith(
+ contentPadding: const EdgeInsets.only(
+ left: 16,
+ top: 6,
+ bottom: 8,
+ right: 5,
+ ),
+ suffixIcon: Padding(
+ padding: _addressController.text.isEmpty
? const EdgeInsets.only(right: 8)
: const EdgeInsets.only(right: 0),
- child: UnconstrainedBox(
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceAround,
- children: [
- _addressController.text.isNotEmpty
- ? TextFieldIconButton(
- semanticsLabel:
- "Clear Button. Clears The Address Field Input.",
- key: const Key(
- "nameTransferClearAddressFieldButtonKey",
+ child: UnconstrainedBox(
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
+ children: [
+ _addressController.text.isNotEmpty
+ ? TextFieldIconButton(
+ semanticsLabel:
+ "Clear Button. Clears The Address Field Input.",
+ key: const Key(
+ "nameTransferClearAddressFieldButtonKey",
+ ),
+ onTap: () {
+ _addressController.text = "";
+ _address = "";
+ _setValidAddressProviders(_address);
+ setState(() {});
+ },
+ child: const XIcon(),
+ )
+ : TextFieldIconButton(
+ semanticsLabel:
+ "Paste Button. Pastes From Clipboard To Address Field Input.",
+ key: const Key(
+ "nameTransferPasteAddressFieldButtonKey",
+ ),
+ onTap: () async {
+ final ClipboardData? data = await clipboard
+ .getData(Clipboard.kTextPlain);
+ if (data?.text != null &&
+ data!.text!.isNotEmpty) {
+ String content = data.text!.trim();
+ if (content.contains("\n")) {
+ content = content.substring(
+ 0,
+ content.indexOf("\n"),
+ );
+ }
+
+ _addressController.text = content.trim();
+ _address = content.trim();
+
+ _setValidAddressProviders(_address);
+ }
+ },
+ child: _addressController.text.isEmpty
+ ? const ClipboardIcon()
+ : const XIcon(),
+ ),
+ if (_addressController.text.isEmpty)
+ TextFieldIconButton(
+ semanticsLabel:
+ "Address Book Button. Opens Address Book For Address Field.",
+ key: const Key(
+ "nameTransferAddressBookButtonKey",
+ ),
+ onTap: () {
+ Navigator.of(context).pushNamed(
+ AddressBookView.routeName,
+ arguments: ref.read(pWalletCoin(walletId)),
+ );
+ },
+ child: const AddressBookIcon(),
),
- onTap: () {
- _addressController.text = "";
- _address = "";
- _setValidAddressProviders(_address);
- setState(() {});
- },
- child: const XIcon(),
- )
- : TextFieldIconButton(
- semanticsLabel:
- "Paste Button. Pastes From Clipboard To Address Field Input.",
- key: const Key(
- "nameTransferPasteAddressFieldButtonKey",
+ if (_addressController.text.isEmpty)
+ TextFieldIconButton(
+ semanticsLabel:
+ "Scan QR Button. Opens Camera For Scanning QR Code.",
+ key: const Key("nameTransferScanQrButtonKey"),
+ onTap: _scanQr,
+ child: const QrCodeIcon(),
),
- onTap: () async {
- final ClipboardData? data = await clipboard
- .getData(Clipboard.kTextPlain);
- if (data?.text != null &&
- data!.text!.isNotEmpty) {
- String content = data.text!.trim();
- if (content.contains("\n")) {
- content = content.substring(
- 0,
- content.indexOf("\n"),
- );
- }
-
- _addressController.text = content.trim();
- _address = content.trim();
-
- _setValidAddressProviders(_address);
- }
- },
- child:
- _addressController.text.isEmpty
- ? const ClipboardIcon()
- : const XIcon(),
- ),
- if (_addressController.text.isEmpty)
- TextFieldIconButton(
- semanticsLabel:
- "Address Book Button. Opens Address Book For Address Field.",
- key: const Key("nameTransferAddressBookButtonKey"),
- onTap: () {
- Navigator.of(context).pushNamed(
- AddressBookView.routeName,
- arguments: ref.read(pWalletCoin(walletId)),
- );
- },
- child: const AddressBookIcon(),
- ),
- if (_addressController.text.isEmpty)
- TextFieldIconButton(
- semanticsLabel:
- "Scan QR Button. Opens Camera For Scanning QR Code.",
- key: const Key("nameTransferScanQrButtonKey"),
- onTap: _scanQr,
- child: const QrCodeIcon(),
- ),
- ],
+ ],
+ ),
+ ),
),
),
- ),
- ),
),
),
SizedBox(height: Util.isDesktop ? 42 : 16),
if (!Util.isDesktop) const Spacer(),
ConditionalParent(
condition: Util.isDesktop,
- builder:
- (child) => Row(
- children: [
- Expanded(
- child: SecondaryButton(
- label: "Cancel",
- buttonHeight: ButtonHeight.l,
- onPressed:
- Navigator.of(
- context,
- rootNavigator: Util.isDesktop,
- ).pop,
- ),
- ),
- const SizedBox(width: 16),
- Expanded(child: child),
- ],
+ builder: (child) => Row(
+ children: [
+ Expanded(
+ child: SecondaryButton(
+ label: "Cancel",
+ buttonHeight: ButtonHeight.l,
+ onPressed: Navigator.of(
+ context,
+ rootNavigator: Util.isDesktop,
+ ).pop,
+ ),
),
+ const SizedBox(width: 16),
+ Expanded(child: child),
+ ],
+ ),
child: PrimaryButton(
label: "Transfer",
enabled: _enableButton,
diff --git a/lib/pages/paynym/add_new_paynym_follow_view.dart b/lib/pages/paynym/add_new_paynym_follow_view.dart
index 85e4c3a..37c5b1a 100644
--- a/lib/pages/paynym/add_new_paynym_follow_view.dart
+++ b/lib/pages/paynym/add_new_paynym_follow_view.dart
@@ -122,8 +122,9 @@ class _AddNewPaynymFollowViewState
}
final qrResult = await ref.read(pBarcodeScanner).scan(context: context);
+ if (qrResult.rawContent == null) return;
- final pCodeString = qrResult.rawContent;
+ final pCodeString = qrResult.rawContent!;
_searchString = pCodeString;
@@ -173,93 +174,82 @@ class _AddNewPaynymFollowViewState
return ConditionalParent(
condition: !isDesktop,
- builder:
- (child) => MasterScaffold(
- isDesktop: isDesktop,
- appBar: AppBar(
- leading: AppBarBackButton(
- onPressed: () {
- Navigator.of(context).pop();
- },
- ),
- titleSpacing: 0,
- title: Text(
- "New follow",
- style: STextStyles.navBarTitle(context),
- overflow: TextOverflow.ellipsis,
- ),
- ),
- body: SafeArea(
- child: LayoutBuilder(
- builder:
- (context, constraints) => SingleChildScrollView(
- child: ConstrainedBox(
- constraints: BoxConstraints(
- minHeight: constraints.maxHeight,
- ),
- child: IntrinsicHeight(
- child: Padding(
- padding: const EdgeInsets.all(16),
- child: child,
- ),
- ),
- ),
- ),
+ builder: (child) => MasterScaffold(
+ isDesktop: isDesktop,
+ appBar: AppBar(
+ leading: AppBarBackButton(
+ onPressed: () {
+ Navigator.of(context).pop();
+ },
+ ),
+ titleSpacing: 0,
+ title: Text(
+ "New follow",
+ style: STextStyles.navBarTitle(context),
+ overflow: TextOverflow.ellipsis,
+ ),
+ ),
+ body: SafeArea(
+ child: LayoutBuilder(
+ builder: (context, constraints) => SingleChildScrollView(
+ child: ConstrainedBox(
+ constraints: BoxConstraints(minHeight: constraints.maxHeight),
+ child: IntrinsicHeight(
+ child: Padding(
+ padding: const EdgeInsets.all(16),
+ child: child,
+ ),
+ ),
),
),
),
+ ),
+ ),
child: ConditionalParent(
condition: isDesktop,
- builder:
- (child) => DesktopDialog(
- maxWidth: 580,
- maxHeight: double.infinity,
- child: Column(
+ builder: (child) => DesktopDialog(
+ maxWidth: 580,
+ maxHeight: double.infinity,
+ child: Column(
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- Padding(
- padding: const EdgeInsets.only(left: 32),
- child: Text(
- "New follow",
- style: STextStyles.desktopH3(context),
- ),
- ),
- const DesktopDialogCloseButton(),
- ],
- ),
Padding(
- padding: const EdgeInsets.only(
- left: 32,
- right: 32,
- bottom: 32,
+ padding: const EdgeInsets.only(left: 32),
+ child: Text(
+ "New follow",
+ style: STextStyles.desktopH3(context),
),
- child: child,
),
+ const DesktopDialogCloseButton(),
],
),
- ),
+ Padding(
+ padding: const EdgeInsets.only(left: 32, right: 32, bottom: 32),
+ child: child,
+ ),
+ ],
+ ),
+ ),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 10),
Text(
"Featured PayNyms",
- style:
- isDesktop
- ? STextStyles.desktopTextExtraExtraSmall(context)
- : STextStyles.sectionLabelMedium12(context),
+ style: isDesktop
+ ? STextStyles.desktopTextExtraExtraSmall(context)
+ : STextStyles.sectionLabelMedium12(context),
),
const SizedBox(height: 12),
FeaturedPaynymsWidget(walletId: widget.walletId),
const SizedBox(height: 24),
Text(
"Add new",
- style:
- isDesktop
- ? STextStyles.desktopTextExtraExtraSmall(context)
- : STextStyles.sectionLabelMedium12(context),
+ style: isDesktop
+ ? STextStyles.desktopTextExtraExtraSmall(context)
+ : STextStyles.sectionLabelMedium12(context),
),
const SizedBox(height: 12),
if (isDesktop)
@@ -270,10 +260,9 @@ class _AddNewPaynymFollowViewState
children: [
RoundedContainer(
padding: const EdgeInsets.all(0),
- color:
- Theme.of(
- context,
- ).extension<StackColors>()!.textFieldDefaultBG,
+ color: Theme.of(
+ context,
+ ).extension<StackColors>()!.textFieldDefaultBG,
height: 56,
child: Center(
child: TextField(
@@ -286,15 +275,15 @@ class _AddNewPaynymFollowViewState
_searchString = value;
});
},
- style: STextStyles.desktopTextExtraExtraSmall(
- context,
- ).copyWith(
- color:
- Theme.of(context)
+ style:
+ STextStyles.desktopTextExtraExtraSmall(
+ context,
+ ).copyWith(
+ color: Theme.of(context)
.extension<StackColors>()!
.textFieldActiveText,
- // height: 1.8,
- ),
+ // height: 1.8,
+ ),
decoration: InputDecoration(
hintText: "Paste payment code",
hoverColor: Colors.transparent,
@@ -315,38 +304,32 @@ class _AddNewPaynymFollowViewState
children: [
_searchController.text.isNotEmpty
? TextFieldIconButton(
- onTap: _clear,
- child: RoundedContainer(
- padding: const EdgeInsets.all(
- 8,
+ onTap: _clear,
+ child: RoundedContainer(
+ padding: const EdgeInsets.all(
+ 8,
+ ),
+ color: Theme.of(context)
+ .extension<StackColors>()!
+ .buttonBackSecondary,
+ child: const XIcon(),
),
- color:
- Theme.of(context)
- .extension<
- StackColors
- >()!
- .buttonBackSecondary,
- child: const XIcon(),
- ),
- )
+ )
: TextFieldIconButton(
- key: const Key(
- "paynymPasteAddressFieldButtonKey",
- ),
- onTap: _paste,
- child: RoundedContainer(
- padding: const EdgeInsets.all(
- 8,
+ key: const Key(
+ "paynymPasteAddressFieldButtonKey",
+ ),
+ onTap: _paste,
+ child: RoundedContainer(
+ padding: const EdgeInsets.all(
+ 8,
+ ),
+ color: Theme.of(context)
+ .extension<StackColors>()!
+ .buttonBackSecondary,
+ child: const ClipboardIcon(),
),
- color:
- Theme.of(context)
- .extension<
- StackColors
- >()!
- .buttonBackSecondary,
- child: const ClipboardIcon(),
),
- ),
TextFieldIconButton(
key: const Key(
"paynymScanQrButtonKey",
@@ -354,10 +337,9 @@ class _AddNewPaynymFollowViewState
onTap: _scanQr,
child: RoundedContainer(
padding: const EdgeInsets.all(8),
- color:
- Theme.of(context)
- .extension<StackColors>()!
- .buttonBackSecondary,
+ color: Theme.of(context)
+ .extension<StackColors>()!
+ .buttonBackSecondary,
child: const QrCodeIcon(),
),
),
@@ -392,39 +374,40 @@ class _AddNewPaynymFollowViewState
});
},
style: STextStyles.field(context),
- decoration: standardInputDecoration(
- "Paste payment code",
- searchFieldFocusNode,
- context,
- desktopMed: isDesktop,
- ).copyWith(
- suffixIcon: Padding(
- padding: const EdgeInsets.only(right: 8),
- child: UnconstrainedBox(
- child: Row(
- children: [
- _searchController.text.isNotEmpty
- ? TextFieldIconButton(
- onTap: _clear,
- child: const XIcon(),
- )
- : TextFieldIconButton(
- key: const Key(
- "paynymPasteAddressFieldButtonKey",
- ),
- onTap: _paste,
- child: const ClipboardIcon(),
+ decoration:
+ standardInputDecoration(
+ "Paste payment code",
+ searchFieldFocusNode,
+ context,
+ desktopMed: isDesktop,
+ ).copyWith(
+ suffixIcon: Padding(
+ padding: const EdgeInsets.only(right: 8),
+ child: UnconstrainedBox(
+ child: Row(
+ children: [
+ _searchController.text.isNotEmpty
+ ? TextFieldIconButton(
+ onTap: _clear,
+ child: const XIcon(),
+ )
+ : TextFieldIconButton(
+ key: const Key(
+ "paynymPasteAddressFieldButtonKey",
+ ),
+ onTap: _paste,
+ child: const ClipboardIcon(),
+ ),
+ TextFieldIconButton(
+ key: const Key("paynymScanQrButtonKey"),
+ onTap: _scanQr,
+ child: const QrCodeIcon(),
),
- TextFieldIconButton(
- key: const Key("paynymScanQrButtonKey"),
- onTap: _scanQr,
- child: const QrCodeIcon(),
+ ],
),
- ],
+ ),
),
),
- ),
- ),
),
),
if (!isDesktop) const SizedBox(height: 12),
@@ -433,21 +416,19 @@ class _AddNewPaynymFollowViewState
if (_didSearch) const SizedBox(height: 20),
if (_didSearch && _searchResult == null)
RoundedWhiteContainer(
- borderColor:
- isDesktop
- ? Theme.of(
- context,
- ).extension<StackColors>()!.backgroundAppBar
- : null,
+ borderColor: isDesktop
+ ? Theme.of(
+ context,
+ ).extension<StackColors>()!.backgroundAppBar
+ : null,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Nothing found. Please check the payment code.",
- style:
- isDesktop
- ? STextStyles.desktopTextExtraExtraSmall(context)
- : STextStyles.label(context),
+ style: isDesktop
+ ? STextStyles.desktopTextExtraExtraSmall(context)
+ : STextStyles.label(context),
),
],
),
@@ -455,12 +436,11 @@ class _AddNewPaynymFollowViewState
if (_didSearch && _searchResult != null)
RoundedWhiteContainer(
padding: const EdgeInsets.all(0),
- borderColor:
- isDesktop
- ? Theme.of(
- context,
- ).extension<StackColors>()!.backgroundAppBar
- : null,
+ borderColor: isDesktop
+ ? Theme.of(
+ context,
+ ).extension<StackColors>()!.backgroundAppBar
+ : null,
child: PaynymCard(
key: UniqueKey(),
label: _searchResult!.nymName,
diff --git a/lib/pages/receive_view/sub_widgets/slatepack_entry_dialog.dart b/lib/pages/receive_view/sub_widgets/slatepack_entry_dialog.dart
index ec9aee0..941e775 100644
--- a/lib/pages/receive_view/sub_widgets/slatepack_entry_dialog.dart
+++ b/lib/pages/receive_view/sub_widgets/slatepack_entry_dialog.dart
@@ -58,8 +58,8 @@ class _SlatepackEntryDialogState extends ConsumerState<SlatepackEntryDialog> {
if (mounted) {
final qrResult = await ref.read(pBarcodeScanner).scan(context: context);
- if (qrResult.rawContent.isNotEmpty && qrResult.rawContent != "null") {
- _receiveSlateController.text = qrResult.rawContent;
+ if (qrResult.rawContent != null && qrResult.rawContent!.isNotEmpty) {
+ _receiveSlateController.text = qrResult.rawContent!;
setState(() {
_slateToggleFlag = _receiveSlateController.text.isNotEmpty;
});
@@ -105,10 +105,9 @@ class _SlatepackEntryDialogState extends ConsumerState<SlatepackEntryDialog> {
Text(
"Receive Slatepack",
style: STextStyles.desktopTextExtraSmall(context).copyWith(
- color:
- Theme.of(
- context,
- ).extension<StackColors>()!.textFieldActiveSearchIconRight,
+ color: Theme.of(
+ context,
+ ).extension<StackColors>()!.textFieldActiveSearchIconRight,
),
textAlign: TextAlign.left,
),
@@ -138,78 +137,75 @@ class _SlatepackEntryDialogState extends ConsumerState<SlatepackEntryDialog> {
},
focusNode: _slateFocusNode,
style: STextStyles.desktopTextExtraSmall(context).copyWith(
- color:
- Theme.of(
- context,
- ).extension<StackColors>()!.textFieldActiveText,
+ color: Theme.of(
+ context,
+ ).extension<StackColors>()!.textFieldActiveText,
height: 1.8,
),
- decoration: standardInputDecoration(
- "Enter Slatepack Message",
- _slateFocusNode,
- context,
- desktopMed: true,
- ).copyWith(
- contentPadding: const EdgeInsets.symmetric(
- horizontal: 16,
- vertical: 12, // Adjust vertical padding for better alignment
- ),
- suffixIcon: Padding(
- padding:
- _receiveSlateController.text.isEmpty
+ decoration:
+ standardInputDecoration(
+ "Enter Slatepack Message",
+ _slateFocusNode,
+ context,
+ desktopMed: true,
+ ).copyWith(
+ contentPadding: const EdgeInsets.symmetric(
+ horizontal: 16,
+ vertical:
+ 12, // Adjust vertical padding for better alignment
+ ),
+ suffixIcon: Padding(
+ padding: _receiveSlateController.text.isEmpty
? const EdgeInsets.only(right: 8)
: const EdgeInsets.only(right: 0),
- child: UnconstrainedBox(
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceAround,
- children: [
- _slateToggleFlag
- ? TextFieldIconButton(
- key: const Key(
- "receiveViewClearSlatepackFieldButtonKey",
- ),
- onTap: () {
- _receiveSlateController.text = "";
- setState(() {
- _slateToggleFlag = false;
- });
- },
- child: const XIcon(),
- )
- : TextFieldIconButton(
- key: const Key(
- "receiveViewPasteSlatepackFieldButtonKey",
+ child: UnconstrainedBox(
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
+ children: [
+ _slateToggleFlag
+ ? TextFieldIconButton(
+ key: const Key(
+ "receiveViewClearSlatepackFieldButtonKey",
+ ),
+ onTap: () {
+ _receiveSlateController.text = "";
+ setState(() {
+ _slateToggleFlag = false;
+ });
+ },
+ child: const XIcon(),
+ )
+ : TextFieldIconButton(
+ key: const Key(
+ "receiveViewPasteSlatepackFieldButtonKey",
+ ),
+ onTap: _pasteSlatepack,
+ child: _receiveSlateController.text.isEmpty
+ ? const ClipboardIcon()
+ : const XIcon(),
+ ),
+ if (_receiveSlateController.text.isEmpty)
+ TextFieldIconButton(
+ semanticsLabel:
+ "Scan QR Button. Opens Camera For Scanning QR Code.",
+ key: const Key("sendViewScanQrButtonKey"),
+ onTap: _scanQr,
+ child: const QrCodeIcon(),
),
- onTap: _pasteSlatepack,
- child:
- _receiveSlateController.text.isEmpty
- ? const ClipboardIcon()
- : const XIcon(),
- ),
- if (_receiveSlateController.text.isEmpty)
- TextFieldIconButton(
- semanticsLabel:
- "Scan QR Button. Opens Camera For Scanning QR Code.",
- key: const Key("sendViewScanQrButtonKey"),
- onTap: _scanQr,
- child: const QrCodeIcon(),
- ),
- ],
+ ],
+ ),
+ ),
),
),
- ),
- ),
),
),
const SizedBox(height: 16),
PrimaryButton(
label: "Import",
enabled: _slateToggleFlag,
- onPressed:
- !_slateToggleFlag
- ? null
- : () =>
- Navigator.of(context).pop(_receiveSlateController.text),
+ onPressed: !_slateToggleFlag
+ ? null
+ : () => Navigator.of(context).pop(_receiveSlateController.text),
),
const SizedBox(height: 16),
SecondaryButton(
diff --git a/lib/pages/send_view/frost_ms/recipient.dart b/lib/pages/send_view/frost_ms/recipient.dart
index 150eecb..7e48372 100644
--- a/lib/pages/send_view/frost_ms/recipient.dart
+++ b/lib/pages/send_view/frost_ms/recipient.dart
@@ -125,8 +125,10 @@ class _RecipientState extends ConsumerState<Recipient> {
Logging.instance.d("qrResult content: ${qrResult.rawContent}");
+ if (qrResult.rawContent == null) return;
+
final paymentData = AddressUtils.parsePaymentUri(
- qrResult.rawContent,
+ qrResult.rawContent!,
logging: Logging.instance,
);
@@ -148,7 +150,7 @@ class _RecipientState extends ConsumerState<Recipient> {
.format(amount, withUnitName: false);
}
} else {
- addressController.text = qrResult.rawContent.trim();
+ addressController.text = qrResult.rawContent!.trim();
}
setState(() {
@@ -244,8 +246,9 @@ class _RecipientState extends ConsumerState<Recipient> {
),
CustomTextButton(
text: isSingle ? "Add another recipient" : "Remove",
- onTap:
- isSingle ? widget.addAnotherRecipientTapped : widget.remove,
+ onTap: isSingle
+ ? widget.addAnotherRecipientTapped
+ : widget.remove,
),
],
),
@@ -268,93 +271,92 @@ class _RecipientState extends ConsumerState<Recipient> {
_addressIsEmpty = addressController.text.isEmpty;
});
},
- decoration: standardInputDecoration(
- "Enter ${widget.coin.ticker} address",
- addressFocusNode,
- context,
- ).copyWith(
- contentPadding: const EdgeInsets.only(
- left: 16,
- top: 6,
- bottom: 8,
- right: 5,
- ),
- suffixIcon: Padding(
- padding:
- _addressIsEmpty
+ decoration:
+ standardInputDecoration(
+ "Enter ${widget.coin.ticker} address",
+ addressFocusNode,
+ context,
+ ).copyWith(
+ contentPadding: const EdgeInsets.only(
+ left: 16,
+ top: 6,
+ bottom: 8,
+ right: 5,
+ ),
+ suffixIcon: Padding(
+ padding: _addressIsEmpty
? const EdgeInsets.only(right: 8)
: const EdgeInsets.only(right: 0),
- child: UnconstrainedBox(
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceAround,
- children: [
- !_addressIsEmpty
- ? TextFieldIconButton(
- semanticsLabel:
- "Clear Button. Clears The Address Field Input.",
- key: const Key(
- "sendViewClearAddressFieldButtonKey",
- ),
- onTap: () {
- addressController.text = "";
-
- setState(() {
- _addressIsEmpty = true;
- });
-
- _updateRecipientData();
- },
- child: const XIcon(),
- )
- : TextFieldIconButton(
- semanticsLabel:
- "Paste Button. Pastes From Clipboard To Address Field Input.",
- key: const Key(
- "sendViewPasteAddressFieldButtonKey",
+ child: UnconstrainedBox(
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
+ children: [
+ !_addressIsEmpty
+ ? TextFieldIconButton(
+ semanticsLabel:
+ "Clear Button. Clears The Address Field Input.",
+ key: const Key(
+ "sendViewClearAddressFieldButtonKey",
+ ),
+ onTap: () {
+ addressController.text = "";
+
+ setState(() {
+ _addressIsEmpty = true;
+ });
+
+ _updateRecipientData();
+ },
+ child: const XIcon(),
+ )
+ : TextFieldIconButton(
+ semanticsLabel:
+ "Paste Button. Pastes From Clipboard To Address Field Input.",
+ key: const Key(
+ "sendViewPasteAddressFieldButtonKey",
+ ),
+ onTap: () async {
+ final ClipboardData? data = await ref
+ .read(pClipboard)
+ .getData(Clipboard.kTextPlain);
+ if (data?.text != null &&
+ data!.text!.isNotEmpty) {
+ String content = data.text!.trim();
+ if (content.contains("\n")) {
+ content = content.substring(
+ 0,
+ content.indexOf("\n"),
+ );
+ }
+
+ addressController.text = content.trim();
+
+ setState(() {
+ _addressIsEmpty =
+ addressController.text.isEmpty;
+ });
+
+ _updateRecipientData();
+ }
+ },
+ child: _addressIsEmpty
+ ? const ClipboardIcon()
+ : const XIcon(),
+ ),
+ if (_addressIsEmpty)
+ TextFieldIconButton(
+ semanticsLabel:
+ "Scan QR Button. "
+ "Opens Camera For Scanning QR Code.",
+ key: const Key("sendViewScanQrButtonKey"),
+ onTap: _onQrTapped,
+ child: const QrCodeIcon(),
),
- onTap: () async {
- final ClipboardData? data = await ref
- .read(pClipboard)
- .getData(Clipboard.kTextPlain);
- if (data?.text != null &&
- data!.text!.isNotEmpty) {
- String content = data.text!.trim();
- if (content.contains("\n")) {
- content = content.substring(
- 0,
- content.indexOf("\n"),
- );
- }
-
- addressController.text = content.trim();
-
- setState(() {
- _addressIsEmpty =
- addressController.text.isEmpty;
- });
-
- _updateRecipientData();
- }
- },
- child:
- _addressIsEmpty
- ? const ClipboardIcon()
- : const XIcon(),
- ),
- if (_addressIsEmpty)
- TextFieldIconButton(
- semanticsLabel:
- "Scan QR Button. "
- "Opens Camera For Scanning QR Code.",
- key: const Key("sendViewScanQrButtonKey"),
- onTap: _onQrTapped,
- child: const QrCodeIcon(),
- ),
- ],
+ ],
+ ),
+ ),
),
),
- ),
- ),
),
),
SizedBox(height: isSingle ? 12 : 8),
@@ -391,13 +393,12 @@ class _RecipientState extends ConsumerState<Recipient> {
onChanged: (_) {
_updateRecipientData();
},
- keyboardType:
- Util.isDesktop
- ? null
- : const TextInputType.numberWithOptions(
- signed: false,
- decimal: true,
- ),
+ keyboardType: Util.isDesktop
+ ? null
+ : const TextInputType.numberWithOptions(
+ signed: false,
+ decimal: true,
+ ),
textAlign: TextAlign.right,
inputFormatters: [
AmountInputFormatter(
@@ -419,10 +420,9 @@ class _RecipientState extends ConsumerState<Recipient> {
.watch(pAmountUnit(widget.coin))
.unitForCoin(widget.coin),
style: STextStyles.smallMed14(context).copyWith(
- color:
- Theme.of(
- context,
- ).extension<StackColors>()!.accentColorDark,
+ color: Theme.of(
+ context,
+ ).extension<StackColors>()!.accentColorDark,
),
),
),
diff --git a/lib/pages/send_view/send_view.dart b/lib/pages/send_view/send_view.dart
index 54cdf51..884cb5d 100644
--- a/lib/pages/send_view/send_view.dart
+++ b/lib/pages/send_view/send_view.dart
@@ -290,9 +290,10 @@ class _SendViewState extends ConsumerState<SendView> {
// );
Logging.instance.d("qrResult content: ${qrResult.rawContent}");
+ if (qrResult.rawContent == null) return;
final paymentData = AddressUtils.parsePaymentUri(
- qrResult.rawContent,
+ qrResult.rawContent!,
logging: Logging.instance,
);
@@ -300,7 +301,7 @@ class _SendViewState extends ConsumerState<SendView> {
paymentData.coin?.uriScheme == coin.uriScheme) {
_applyUri(paymentData);
} else {
- _address = qrResult.rawContent.split("\n").first.trim();
+ _address = qrResult.rawContent!.split("\n").first.trim();
sendToController.text = _address ?? "";
_setValidAddressProviders(_address);
diff --git a/lib/pages/send_view/token_send_view.dart b/lib/pages/send_view/token_send_view.dart
index fdf7813..8294209 100644
--- a/lib/pages/send_view/token_send_view.dart
+++ b/lib/pages/send_view/token_send_view.dart
@@ -163,9 +163,10 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
// );
Logging.instance.d("qrResult content: ${qrResult.rawContent}");
+ if (qrResult.rawContent == null) return;
final paymentData = AddressUtils.parsePaymentUri(
- qrResult.rawContent,
+ qrResult.rawContent!,
logging: Logging.instance,
);
@@ -206,7 +207,7 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
// now check for non standard encoded basic address
} else {
- _address = qrResult.rawContent.split("\n").first.trim();
+ _address = qrResult.rawContent!.split("\n").first.trim();
sendToController.text = _address ?? "";
_updatePreviewButtonState(_address, _amountToSend);
@@ -249,24 +250,22 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
locale: ref.read(localeServiceChangeNotifierProvider).locale,
);
if (baseAmount != null) {
- final _price =
- ref
- .read(priceAnd24hChangeNotifierProvider)
- .getTokenPrice(tokenContract.address)
- ?.value;
+ final _price = ref
+ .read(priceAnd24hChangeNotifierProvider)
+ .getTokenPrice(tokenContract.address)
+ ?.value;
if (_price == null || _price == Decimal.zero) {
_amountToSend = Amount.zero;
} else {
- _amountToSend =
- baseAmount <= Amount.zero
- ? Amount.zero
- : Amount.fromDecimal(
- (baseAmount.decimal / _price).toDecimal(
- scaleOnInfinitePrecision: tokenContract.decimals,
- ),
- fractionDigits: tokenContract.decimals,
- );
+ _amountToSend = baseAmount <= Amount.zero
+ ? Amount.zero
+ : Amount.fromDecimal(
+ (baseAmount.decimal / _price).toDecimal(
+ scaleOnInfinitePrecision: tokenContract.decimals,
+ ),
+ fractionDigits: tokenContract.decimals,
+ );
}
if (_cachedAmountToSend != null && _cachedAmountToSend == _amountToSend) {
return;
@@ -305,11 +304,10 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
}
_cachedAmountToSend = _amountToSend;
- final price =
- ref
- .read(priceAnd24hChangeNotifierProvider)
- .getTokenPrice(tokenContract.address)
- ?.value;
+ final price = ref
+ .read(priceAnd24hChangeNotifierProvider)
+ .getTokenPrice(tokenContract.address)
+ ?.value;
if (price != null && price > Decimal.zero) {
baseAmountController.text = (_amountToSend!.decimal * price)
@@ -496,8 +494,9 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
address: _address!,
amount: amount,
isChange: false,
- addressType:
- tokenWallet.cryptoCurrency.getAddressType(_address!)!,
+ addressType: tokenWallet.cryptoCurrency.getAddressType(
+ _address!,
+ )!,
),
],
feeRateType: ref.read(feeRateTypeMobileStateProvider),
@@ -518,14 +517,13 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
Navigator.of(context).push(
RouteGenerator.getRoute(
shouldUseMaterialRoute: RouteGenerator.useMaterialPageRoute,
- builder:
- (_) => ConfirmTransactionView(
- txData: txData,
- walletId: walletId,
- isTokenTx: true,
- onSuccess: clearSendForm,
- routeOnSuccessName: TokenView.routeName,
- ),
+ builder: (_) => ConfirmTransactionView(
+ txData: txData,
+ walletId: walletId,
+ isTokenTx: true,
+ onSuccess: clearSendForm,
+ routeOnSuccessName: TokenView.routeName,
+ ),
settings: const RouteSettings(
name: ConfirmTransactionView.routeName,
),
@@ -555,10 +553,9 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
child: Text(
"Ok",
style: STextStyles.button(context).copyWith(
- color:
- Theme.of(
- context,
- ).extension<StackColors>()!.accentColorDark,
+ color: Theme.of(
+ context,
+ ).extension<StackColors>()!.accentColorDark,
),
),
onPressed: () {
@@ -699,10 +696,9 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
children: [
Container(
decoration: BoxDecoration(
- color:
- Theme.of(
- context,
- ).extension<StackColors>()!.popupBG,
+ color: Theme.of(
+ context,
+ ).extension<StackColors>()!.popupBG,
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
@@ -835,85 +831,90 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
},
focusNode: _addressFocusNode,
style: STextStyles.field(context),
- decoration: standardInputDecoration(
- "Enter ${tokenContract.symbol} address",
- _addressFocusNode,
- context,
- ).copyWith(
- contentPadding: const EdgeInsets.only(
- left: 16,
- top: 6,
- bottom: 8,
- right: 5,
- ),
- suffixIcon: Padding(
- padding:
- sendToController.text.isEmpty
+ decoration:
+ standardInputDecoration(
+ "Enter ${tokenContract.symbol} address",
+ _addressFocusNode,
+ context,
+ ).copyWith(
+ contentPadding: const EdgeInsets.only(
+ left: 16,
+ top: 6,
+ bottom: 8,
+ right: 5,
+ ),
+ suffixIcon: Padding(
+ padding: sendToController.text.isEmpty
? const EdgeInsets.only(right: 8)
: const EdgeInsets.only(right: 0),
- child: UnconstrainedBox(
- child: Row(
- mainAxisAlignment:
- MainAxisAlignment.spaceAround,
- children: [
- _addressToggleFlag
- ? TextFieldIconButton(
- key: const Key(
- "tokenSendViewClearAddressFieldButtonKey",
+ child: UnconstrainedBox(
+ child: Row(
+ mainAxisAlignment:
+ MainAxisAlignment.spaceAround,
+ children: [
+ _addressToggleFlag
+ ? TextFieldIconButton(
+ key: const Key(
+ "tokenSendViewClearAddressFieldButtonKey",
+ ),
+ onTap: () {
+ sendToController.text =
+ "";
+ _address = "";
+ _updatePreviewButtonState(
+ _address,
+ _amountToSend,
+ );
+ setState(() {
+ _addressToggleFlag =
+ false;
+ });
+ },
+ child: const XIcon(),
+ )
+ : TextFieldIconButton(
+ key: const Key(
+ "tokenSendViewPasteAddressFieldButtonKey",
+ ),
+ onTap:
+ _onTokenSendViewPasteAddressFieldButtonPressed,
+ child:
+ sendToController
+ .text
+ .isEmpty
+ ? const ClipboardIcon()
+ : const XIcon(),
+ ),
+ if (sendToController.text.isEmpty)
+ TextFieldIconButton(
+ key: const Key(
+ "sendViewAddressBookButtonKey",
+ ),
+ onTap: () {
+ Navigator.of(
+ context,
+ ).pushNamed(
+ AddressBookView.routeName,
+ arguments: widget.coin,
+ );
+ },
+ child:
+ const AddressBookIcon(),
),
- onTap: () {
- sendToController.text = "";
- _address = "";
- _updatePreviewButtonState(
- _address,
- _amountToSend,
- );
- setState(() {
- _addressToggleFlag = false;
- });
- },
- child: const XIcon(),
- )
- : TextFieldIconButton(
- key: const Key(
- "tokenSendViewPasteAddressFieldButtonKey",
+ if (sendToController.text.isEmpty)
+ TextFieldIconButton(
+ key: const Key(
+ "sendViewScanQrButtonKey",
+ ),
+ onTap:
+ _onTokenSendViewScanQrButtonPressed,
+ child: const QrCodeIcon(),
),
- onTap:
- _onTokenSendViewPasteAddressFieldButtonPressed,
- child:
- sendToController
- .text
- .isEmpty
- ? const ClipboardIcon()
- : const XIcon(),
- ),
- if (sendToController.text.isEmpty)
- TextFieldIconButton(
- key: const Key(
- "sendViewAddressBookButtonKey",
- ),
- onTap: () {
- Navigator.of(context).pushNamed(
- AddressBookView.routeName,
- arguments: widget.coin,
- );
- },
- child: const AddressBookIcon(),
- ),
- if (sendToController.text.isEmpty)
- TextFieldIconButton(
- key: const Key(
- "sendViewScanQrButtonKey",
- ),
- onTap:
- _onTokenSendViewScanQrButtonPressed,
- child: const QrCodeIcon(),
- ),
- ],
+ ],
+ ),
+ ),
),
),
- ),
- ),
),
),
Builder(
@@ -935,14 +936,12 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
child: Text(
error,
textAlign: TextAlign.left,
- style: STextStyles.label(
- context,
- ).copyWith(
- color:
- Theme.of(context)
+ style: STextStyles.label(context)
+ .copyWith(
+ color: Theme.of(context)
.extension<StackColors>()!
.textError,
- ),
+ ),
),
),
);
@@ -977,23 +976,21 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
autocorrect: Util.isDesktop ? false : true,
enableSuggestions: Util.isDesktop ? false : true,
style: STextStyles.smallMed14(context).copyWith(
- color:
- Theme.of(
- context,
- ).extension<StackColors>()!.textDark,
+ color: Theme.of(
+ context,
+ ).extension<StackColors>()!.textDark,
),
key: const Key(
"amountInputFieldCryptoTextFieldKey",
),
controller: cryptoAmountController,
focusNode: _cryptoFocus,
- keyboardType:
- Util.isDesktop
- ? null
- : const TextInputType.numberWithOptions(
- signed: false,
- decimal: true,
- ),
+ keyboardType: Util.isDesktop
+ ? null
+ : const TextInputType.numberWithOptions(
+ signed: false,
+ decimal: true,
+ ),
textAlign: TextAlign.right,
inputFormatters: [
AmountInputFormatter(
@@ -1026,14 +1023,12 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
ref
.watch(pAmountUnit(coin))
.unitForContract(tokenContract),
- style: STextStyles.smallMed14(
- context,
- ).copyWith(
- color:
- Theme.of(context)
+ style: STextStyles.smallMed14(context)
+ .copyWith(
+ color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark,
- ),
+ ),
),
),
),
@@ -1044,26 +1039,25 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
if (Prefs.instance.externalCalls)
TextField(
autocorrect: Util.isDesktop ? false : true,
- enableSuggestions:
- Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop
+ ? false
+ : true,
style: STextStyles.smallMed14(context).copyWith(
- color:
- Theme.of(
- context,
- ).extension<StackColors>()!.textDark,
+ color: Theme.of(
+ context,
+ ).extension<StackColors>()!.textDark,
),
key: const Key(
"amountInputFieldFiatTextFieldKey",
),
controller: baseAmountController,
focusNode: _baseFocus,
- keyboardType:
- Util.isDesktop
- ? null
- : const TextInputType.numberWithOptions(
- signed: false,
- decimal: true,
- ),
+ keyboardType: Util.isDesktop
+ ? null
+ : const TextInputType.numberWithOptions(
+ signed: false,
+ decimal: true,
+ ),
textAlign: TextAlign.right,
inputFormatters: [
AmountInputFormatter(
@@ -1098,14 +1092,12 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
(value) => value.currency,
),
),
- style: STextStyles.smallMed14(
- context,
- ).copyWith(
- color:
- Theme.of(context)
+ style: STextStyles.smallMed14(context)
+ .copyWith(
+ color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark,
- ),
+ ),
),
),
),
@@ -1124,41 +1116,42 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
),
child: TextField(
autocorrect: Util.isDesktop ? false : true,
- enableSuggestions:
- Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop
+ ? false
+ : true,
controller: noteController,
focusNode: _noteFocusNode,
style: STextStyles.field(context),
onChanged: (_) => setState(() {}),
- decoration: standardInputDecoration(
- "Type something...",
- _noteFocusNode,
- context,
- ).copyWith(
- suffixIcon:
- noteController.text.isNotEmpty
+ decoration:
+ standardInputDecoration(
+ "Type something...",
+ _noteFocusNode,
+ context,
+ ).copyWith(
+ suffixIcon: noteController.text.isNotEmpty
? Padding(
- padding: const EdgeInsets.only(
- right: 0,
- ),
- child: UnconstrainedBox(
- child: Row(
- children: [
- TextFieldIconButton(
- child: const XIcon(),
- onTap: () async {
- setState(() {
- noteController.text =
- "";
- });
- },
- ),
- ],
+ padding: const EdgeInsets.only(
+ right: 0,
),
- ),
- )
+ child: UnconstrainedBox(
+ child: Row(
+ children: [
+ TextFieldIconButton(
+ child: const XIcon(),
+ onTap: () async {
+ setState(() {
+ noteController.text =
+ "";
+ });
+ },
+ ),
+ ],
+ ),
+ ),
+ )
: null,
- ),
+ ),
),
),
const SizedBox(height: 12),
@@ -1172,8 +1165,9 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
children: [
TextField(
autocorrect: Util.isDesktop ? false : true,
- enableSuggestions:
- Util.isDesktop ? false : true,
+ enableSuggestions: Util.isDesktop
+ ? false
+ : true,
controller: feeController,
readOnly: true,
textInputAction: TextInputAction.none,
@@ -1183,10 +1177,9 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
horizontal: 12,
),
child: RawMaterialButton(
- splashColor:
- Theme.of(
- context,
- ).extension<StackColors>()!.highlight,
+ splashColor: Theme.of(
+ context,
+ ).extension<StackColors>()!.highlight,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
@@ -1201,19 +1194,21 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
top: Radius.circular(20),
),
),
- builder:
- (_) => TransactionFeeSelectionSheet(
+ builder: (_) =>
+ TransactionFeeSelectionSheet(
walletId: walletId,
isToken: true,
- amount: (Decimal.tryParse(
- cryptoAmountController
- .text,
- ) ??
- Decimal.zero)
- .toAmount(
- fractionDigits:
- tokenContract.decimals,
- ),
+ amount:
+ (Decimal.tryParse(
+ cryptoAmountController
+ .text,
+ ) ??
+ Decimal.zero)
+ .toAmount(
+ fractionDigits:
+ tokenContract
+ .decimals,
+ ),
updateChosen: (String fee) {
if (fee == "custom") {
if (!isCustomFee.value) {
@@ -1317,28 +1312,24 @@ class _TokenSendViewState extends ConsumerState<TokenSendView> {
TextButton(
onPressed:
ref
- .watch(
- previewTokenTxButtonStateProvider
- .state,
- )
- .state
- ? _previewTransaction
- : null,
+ .watch(
+ previewTokenTxButtonStateProvider.state,
+ )
+ .state
+ ? _previewTransaction
+ : null,
style:
ref
- .watch(
- previewTokenTxButtonStateProvider
- .state,
- )
- .state
- ? Theme.of(context)
- .extension<StackColors>()!
- .getPrimaryEnabledButtonStyle(context)
- : Theme.of(context)
- .extension<StackColors>()!
- .getPrimaryDisabledButtonStyle(
- context,
- ),
+ .watch(
+ previewTokenTxButtonStateProvider.state,
+ )
+ .state
+ ? Theme.of(context)
+ .extension<StackColors>()!
+ .getPrimaryEnabledButtonStyle(context)
+ : Theme.of(context)
+ .extension<StackColors>()!
+ .getPrimaryDisabledButtonStyle(context),
child: Text(
"Preview",
style: STextStyles.button(context),
diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
index 738ccb8..75411e9 100644
--- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
+++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart
@@ -375,7 +375,7 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> {
} else {
try {
final result = await ref.read(pBarcodeScanner).scan(context: context);
- await _processQrData(result.rawContent);
+ await _processQrData(result.rawContent ?? "");
} on PlatformException catch (e, s) {
if (mounted) {
try {
diff --git a/lib/utilities/barcode_scanner_interface.dart b/lib/utilities/barcode_scanner_interface.dart
index f8256f2..5ab338f 100644
--- a/lib/utilities/barcode_scanner_interface.dart
+++ b/lib/utilities/barcode_scanner_interface.dart
@@ -20,7 +20,7 @@ import '../widgets/stack_dialog.dart';
import 'logger.dart';
class ScanResult {
- final String rawContent;
+ final String? rawContent;
ScanResult({required this.rawContent});
}
@@ -35,12 +35,12 @@ class BarcodeScannerWrapper implements BarcodeScannerInterface {
@override
Future<ScanResult> scan({required BuildContext context}) async {
try {
- final data = await showDialog<Object?>(
+ final data = await showDialog<String>(
context: context,
builder: (context) => const QrScanner(),
);
- return ScanResult(rawContent: data.toString());
+ return ScanResult(rawContent: data);
} catch (e) {
rethrow;
}
@@ -61,19 +61,18 @@ Future<void> checkCamPermDeniedMobileAndOpenAppSettings(
if ((iosShow || androidShow) && context.mounted) {
final trySettings = await showDialog<bool>(
context: context,
- builder:
- (context) => StackDialog(
- title: "Camera permissions required",
- message: "Open settings?",
- leftButton: SecondaryButton(
- label: "Cancel",
- onPressed: Navigator.of(context).pop,
- ),
- rightButton: PrimaryButton(
- label: "Continue",
- onPressed: () => Navigator.of(context).pop(true),
- ),
- ),
+ builder: (context) => StackDialog(
+ title: "Camera permissions required",
+ message: "Open settings?",
+ leftButton: SecondaryButton(
+ label: "Cancel",
+ onPressed: Navigator.of(context).pop,
+ ),
+ rightButton: PrimaryButton(
+ label: "Continue",
+ onPressed: () => Navigator.of(context).pop(true),
+ ),
+ ),
);
if (trySettings == true) {
@@ -83,15 +82,14 @@ Future<void> checkCamPermDeniedMobileAndOpenAppSettings(
if (context.mounted) {
await showDialog<bool>(
context: context,
- builder:
- (context) => StackDialog(
- title: "Could not open app settings",
- message: "You will need manually go find your app settings",
- rightButton: PrimaryButton(
- label: "Ok",
- onPressed: Navigator.of(context).pop,
- ),
- ),
+ builder: (context) => StackDialog(
+ title: "Could not open app settings",
+ message: "You will need manually go find your app settings",
+ rightButton: PrimaryButton(
+ label: "Ok",
+ onPressed: Navigator.of(context).pop,
+ ),
+ ),
);
}
}
diff --git a/lib/widgets/qr_scanner.dart b/lib/widgets/qr_scanner.dart
index 66941ac..7f3c428 100644
--- a/lib/widgets/qr_scanner.dart
+++ b/lib/widgets/qr_scanner.dart
@@ -1,45 +1,72 @@
+import 'dart:async';
+import 'dart:io';
+
import 'package:flutter/material.dart';
-import 'package:flutter_riverpod/flutter_riverpod.dart';
-import 'package:mobile_scanner/mobile_scanner.dart';
+import 'package:qr_code_scanner_plus/qr_code_scanner_plus.dart';
import '../themes/stack_colors.dart';
-import '../utilities/logger.dart';
import '../utilities/text_styles.dart';
import 'background.dart';
import 'custom_buttons/app_bar_icon_button.dart';
-class QrScanner extends ConsumerWidget {
+class QrScanner extends StatefulWidget {
const QrScanner({super.key});
@override
- Widget build(BuildContext context, WidgetRef ref) {
+ State<QrScanner> createState() => _QrScannerState();
+}
+
+class _QrScannerState extends State<QrScanner> {
+ final GlobalKey qrKey = GlobalKey(debugLabel: "QR Scan Key");
+
+ QRViewController? controller;
+
+ StreamSubscription<Barcode>? sub;
+
+ void _onScanned(String? data) {
+ if (data != null && mounted) {
+ Navigator.of(context).pop(data);
+ }
+ }
+
+ // In order to get hot reload to work we need to pause the camera if the platform
+ // is android, or resume the camera if the platform is iOS.
+ @override
+ void reassemble() {
+ super.reassemble();
+ if (Platform.isAndroid) {
+ controller!.pauseCamera();
+ } else if (Platform.isIOS) {
+ controller!.resumeCamera();
+ }
+ }
+
+ @override
+ void dispose() {
+ sub?.cancel();
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
return Background(
child: Scaffold(
backgroundColor: Theme.of(context).extension<StackColors>()!.background,
appBar: AppBar(
- backgroundColor:
- Theme.of(context).extension<StackColors>()!.backgroundAppBar,
+ backgroundColor: Theme.of(
+ context,
+ ).extension<StackColors>()!.backgroundAppBar,
leading: const AppBarBackButton(),
title: Text("Scan QR code", style: STextStyles.navBarTitle(context)),
),
- body: MobileScanner(
- onDetect: (capture) {
- final data =
- ((capture.raw as Map?)?["data"] as List?)?.firstOrNull as Map?;
-
- final value =
- data?["rawValue"] as String? ??
- data?["displayValue"] as String?;
-
- Navigator.of(context).pop(value);
- },
- onDetectError: (error, stackTrace) {
- Logging.instance.w(
- "Mobile scanner",
- error: error,
- stackTrace: stackTrace,
- );
- Navigator.of(context).pop();
+ body: QRView(
+ key: qrKey,
+ onQRViewCreated: (QRViewController p1) {
+ sub?.cancel();
+ controller = p1;
+ sub = controller!.scannedDataStream.listen((data) {
+ _onScanned(data.code);
+ });
},
),
),
diff --git a/lib/widgets/textfields/frost_step_field.dart b/lib/widgets/textfields/frost_step_field.dart
index f94fac2..111ba88 100644
--- a/lib/widgets/textfields/frost_step_field.dart
+++ b/lib/widgets/textfields/frost_step_field.dart
@@ -80,8 +80,9 @@ class _FrostStepFieldState extends ConsumerState<FrostStepField> {
}
final qrResult = await ref.read(pBarcodeScanner).scan(context: context);
+ if (qrResult.rawContent == null) return;
- widget.controller.text = qrResult.rawContent;
+ widget.controller.text = qrResult.rawContent!;
_changed(widget.controller.text);
} else {
@@ -128,15 +129,14 @@ class _FrostStepFieldState extends ConsumerState<FrostStepField> {
Widget build(BuildContext context) {
return ConditionalParent(
condition: widget.label != null,
- builder:
- (child) => Column(
- crossAxisAlignment: CrossAxisAlignment.stretch,
- children: [
- Text(widget.label!, style: STextStyles.w500_14(context)),
- const SizedBox(height: 4),
- child,
- ],
- ),
+ builder: (child) => Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ Text(widget.label!, style: STextStyles.w500_14(context)),
+ const SizedBox(height: 4),
+ child,
+ ],
+ ),
child: TextField(
controller: widget.controller,
focusNode: widget.focusNode,
@@ -147,60 +147,55 @@ class _FrostStepFieldState extends ConsumerState<FrostStepField> {
onChanged: _changed,
decoration: InputDecoration(
hintText: widget.hint,
- fillColor:
- widget.focusNode.hasFocus
- ? Theme.of(
- context,
- ).extension<StackColors>()!.textFieldActiveBG
- : Theme.of(
- context,
- ).extension<StackColors>()!.textFieldDefaultBG,
- hintStyle:
- Util.isDesktop
- ? STextStyles.desktopTextFieldLabel(context)
- : STextStyles.fieldLabel(context),
+ fillColor: widget.focusNode.hasFocus
+ ? Theme.of(context).extension<StackColors>()!.textFieldActiveBG
+ : Theme.of(context).extension<StackColors>()!.textFieldDefaultBG,
+ hintStyle: Util.isDesktop
+ ? STextStyles.desktopTextFieldLabel(context)
+ : STextStyles.fieldLabel(context),
enabledBorder: _inputBorder,
focusedBorder: _inputBorder,
errorBorder: _inputBorder,
disabledBorder: _inputBorder,
focusedErrorBorder: _inputBorder,
suffixIcon: Padding(
- padding:
- _isEmpty
- ? const EdgeInsets.only(right: 8)
- : const EdgeInsets.only(right: 0),
+ padding: _isEmpty
+ ? const EdgeInsets.only(right: 8)
+ : const EdgeInsets.only(right: 0),
child: UnconstrainedBox(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
!_isEmpty
? TextFieldIconButton(
- semanticsLabel:
- "Clear Button. Clears The Frost Step Field Input.",
- key: _xKey,
- onTap: () {
- widget.controller.text = "";
-
- _changed(widget.controller.text);
- },
- child: const XIcon(),
- )
+ semanticsLabel:
+ "Clear Button. Clears The Frost Step Field Input.",
+ key: _xKey,
+ onTap: () {
+ widget.controller.text = "";
+
+ _changed(widget.controller.text);
+ },
+ child: const XIcon(),
+ )
: TextFieldIconButton(
- semanticsLabel:
- "Paste Button. Pastes From Clipboard To Frost Step Field Input.",
- key: _pasteKey,
- onTap: () async {
- final ClipboardData? data = await Clipboard.getData(
- Clipboard.kTextPlain,
- );
- if (data?.text != null && data!.text!.isNotEmpty) {
- widget.controller.text = data.text!.trim();
- }
-
- _changed(widget.controller.text);
- },
- child: _isEmpty ? const ClipboardIcon() : const XIcon(),
- ),
+ semanticsLabel:
+ "Paste Button. Pastes From Clipboard To Frost Step Field Input.",
+ key: _pasteKey,
+ onTap: () async {
+ final ClipboardData? data = await Clipboard.getData(
+ Clipboard.kTextPlain,
+ );
+ if (data?.text != null && data!.text!.isNotEmpty) {
+ widget.controller.text = data.text!.trim();
+ }
+
+ _changed(widget.controller.text);
+ },
+ child: _isEmpty
+ ? const ClipboardIcon()
+ : const XIcon(),
+ ),
if (_isEmpty && widget.showQrScanOption)
TextFieldIconButton(
semanticsLabel:
diff --git a/pubspec.lock b/pubspec.lock
index d308938..7ed626d 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -1611,14 +1611,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.6"
- mobile_scanner:
- dependency: "direct main"
- description:
- name: mobile_scanner
- sha256: "5e7e09d904dc01de071b79b3f3789b302b0ed3c9c963109cd3f83ad90de62ecf"
- url: "https://pub.dev"
- source: hosted
- version: "7.1.2"
mockingjay:
dependency: "direct dev"
description:
@@ -1940,6 +1932,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.0.2"
+ qr_code_scanner_plus:
+ dependency: "direct main"
+ description:
+ name: qr_code_scanner_plus
+ sha256: b764e5004251c58d9dee0c295e6006e05bd8d249e78ac3383abdb5afe0a996cd
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.14"
qr_flutter:
dependency: "direct main"
description:
diff --git a/scripts/app_config/templates/pubspec.template.yaml b/scripts/app_config/templates/pubspec.template.yaml
index b627779..80a1a18 100644
--- a/scripts/app_config/templates/pubspec.template.yaml
+++ b/scripts/app_config/templates/pubspec.template.yaml
@@ -157,7 +157,6 @@ dependencies:
event_bus: ^2.0.0
uuid: ^3.0.5
crypto: ^3.0.2
- mobile_scanner: ^7.0.1
image: ^4.3.0
wakelock_plus: ^1.2.8
intl: ^0.17.0
@@ -251,6 +250,7 @@ dependencies:
saf_util: ^0.11.0
saf_stream: ^0.12.3
unorm_dart: ^0.2.0
+ qr_code_scanner_plus: ^2.0.14
dev_dependencies:
flutter_test:
Why this scored 40/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.