diff --git a/mobile-app/android/app/src/main/AndroidManifest.xml b/mobile-app/android/app/src/main/AndroidManifest.xml
index b64593bf..2d6320d9 100644
--- a/mobile-app/android/app/src/main/AndroidManifest.xml
+++ b/mobile-app/android/app/src/main/AndroidManifest.xml
@@ -47,6 +47,7 @@
+
diff --git a/mobile-app/lib/features/components/button.dart b/mobile-app/lib/features/components/button.dart
index 0a6901a4..28842fc3 100644
--- a/mobile-app/lib/features/components/button.dart
+++ b/mobile-app/lib/features/components/button.dart
@@ -3,8 +3,9 @@ import 'package:flutter/material.dart';
import 'package:quantus_sdk/quantus_sdk.dart';
import 'package:resonance_network_wallet/features/styles/app_colors_theme.dart';
import 'package:resonance_network_wallet/features/styles/app_text_theme.dart';
+import 'package:resonance_network_wallet/v2/theme/app_colors.dart';
-enum ButtonVariant { transparent, neutral, primary, success, danger, glass, glassOutline, dangerOutline }
+enum ButtonVariant { transparent, neutral, primary, success, danger, glass, glassOutline, dangerOutline, accent }
class Button extends StatelessWidget {
final String label;
@@ -34,6 +35,8 @@ class Button extends StatelessWidget {
switch (variant) {
case ButtonVariant.neutral:
return context.themeColors.textSecondary;
+ case ButtonVariant.accent:
+ return Colors.black;
default:
return null;
}
@@ -169,6 +172,18 @@ class Button extends StatelessWidget {
);
break;
+ case ButtonVariant.accent:
+ buttonWidget = Container(
+ width: width,
+ padding: padding,
+ decoration: ShapeDecoration(
+ color: disabled ? disabledBtnColor : context.colors.accentGreen,
+ shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(buttonRadius)),
+ ),
+ child: buttonContent,
+ );
+ break;
+
default:
buttonWidget = ClipRRect(
borderRadius: BorderRadius.circular(buttonRadius),
diff --git a/mobile-app/lib/features/components/shared_address_action_sheet.dart b/mobile-app/lib/features/components/shared_address_action_sheet.dart
index 1d16a9db..e40481ee 100644
--- a/mobile-app/lib/features/components/shared_address_action_sheet.dart
+++ b/mobile-app/lib/features/components/shared_address_action_sheet.dart
@@ -9,6 +9,7 @@ import 'package:resonance_network_wallet/features/styles/app_colors_theme.dart';
import 'package:resonance_network_wallet/features/styles/app_text_theme.dart';
import 'package:resonance_network_wallet/shared/extensions/clipboard_extensions.dart';
import 'package:resonance_network_wallet/shared/extensions/media_query_data_extension.dart';
+import 'package:resonance_network_wallet/v2/screens/send/send_sheet.dart';
class SharedAddressActionSheet extends StatefulWidget {
final String address;
@@ -56,7 +57,8 @@ class _SharedAddressActionSheetState extends State {
}
void _sendToAddress() {
- Navigator.of(context).pushNamed('/send', arguments: widget.address);
+ Navigator.of(context).pop();
+ showSendSheetV2(context, address: widget.address);
}
void _closeSheet() {
diff --git a/mobile-app/lib/providers/route_intent_providers.dart b/mobile-app/lib/providers/route_intent_providers.dart
index a0fe38d6..4b211420 100644
--- a/mobile-app/lib/providers/route_intent_providers.dart
+++ b/mobile-app/lib/providers/route_intent_providers.dart
@@ -3,3 +3,13 @@ import 'package:quantus_sdk/quantus_sdk.dart';
final transactionIntentProvider = StateProvider((_) => null);
final sharedAccountIntentProvider = StateProvider((_) => null);
+
+class PaymentIntent {
+ final String to;
+ final String amount;
+ final String? ref;
+
+ const PaymentIntent({required this.to, required this.amount, this.ref});
+}
+
+final paymentIntentProvider = StateProvider((_) => null);
diff --git a/mobile-app/lib/providers/wallet_providers.dart b/mobile-app/lib/providers/wallet_providers.dart
index 4aac4d12..3cc73900 100644
--- a/mobile-app/lib/providers/wallet_providers.dart
+++ b/mobile-app/lib/providers/wallet_providers.dart
@@ -152,3 +152,19 @@ class IsBalanceHiddenNotifier extends StateNotifier {
state = value;
}
}
+
+final posModeProvider = StateNotifierProvider((ref) {
+ final settingsService = ref.watch(settingsServiceProvider);
+ return PosModeNotifier(settingsService);
+});
+
+class PosModeNotifier extends StateNotifier {
+ final SettingsService _settingsService;
+
+ PosModeNotifier(this._settingsService) : super(_settingsService.isPosModeEnabled());
+
+ Future setPosMode(bool value) async {
+ await _settingsService.setPosModeEnabled(value);
+ state = value;
+ }
+}
diff --git a/mobile-app/lib/services/deep_link_service.dart b/mobile-app/lib/services/deep_link_service.dart
index 0cae95fe..d58a8d8d 100644
--- a/mobile-app/lib/services/deep_link_service.dart
+++ b/mobile-app/lib/services/deep_link_service.dart
@@ -53,6 +53,19 @@ class DeepLinkService {
}
}
+ if (uri.pathSegments.isNotEmpty && uri.pathSegments.first == 'pay') {
+ final to = uri.queryParameters['to'];
+ final amount = uri.queryParameters['amount'];
+ final ref = uri.queryParameters['ref'];
+
+ if (to != null && to.isNotEmpty && amount != null && amount.isNotEmpty) {
+ _ref.read(paymentIntentProvider.notifier).state = PaymentIntent(to: to, amount: amount, ref: ref);
+ navigatorKey.currentState?.pushNamed('/account');
+ } else {
+ print('Missing payment parameters');
+ }
+ }
+
if (uri.pathSegments.isNotEmpty && uri.pathSegments.first == 'oauth') {
_ref.invalidate(accountAssociationsProvider);
}
diff --git a/mobile-app/lib/services/pos_service.dart b/mobile-app/lib/services/pos_service.dart
new file mode 100644
index 00000000..b005c5e2
--- /dev/null
+++ b/mobile-app/lib/services/pos_service.dart
@@ -0,0 +1,25 @@
+class PosPaymentRequest {
+ final String paymentUrl;
+ final String refId;
+ final String amount;
+
+ const PosPaymentRequest({required this.paymentUrl, required this.refId, required this.amount});
+}
+
+class PosService {
+ String generateRefId() {
+ final now = DateTime.now().millisecondsSinceEpoch;
+ return now.toRadixString(36).toUpperCase();
+ }
+
+ String buildPaymentUrl({required String accountId, required String amount, required String refId}) {
+ final uri = Uri.https('www.quantus.com', '/pay', {'to': accountId, 'amount': amount, 'ref': refId});
+ return uri.toString();
+ }
+
+ PosPaymentRequest createPaymentRequest({required String accountId, required String amount}) {
+ final refId = generateRefId();
+ final url = buildPaymentUrl(accountId: accountId, amount: amount, refId: refId);
+ return PosPaymentRequest(paymentUrl: url, refId: refId, amount: amount);
+ }
+}
diff --git a/mobile-app/lib/v2/screens/home/home_screen.dart b/mobile-app/lib/v2/screens/home/home_screen.dart
index 7f89da8c..7e420105 100644
--- a/mobile-app/lib/v2/screens/home/home_screen.dart
+++ b/mobile-app/lib/v2/screens/home/home_screen.dart
@@ -4,15 +4,17 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:quantus_sdk/quantus_sdk.dart';
import 'package:resonance_network_wallet/features/components/account_gradient_image.dart';
+import 'package:resonance_network_wallet/features/components/button.dart';
import 'package:resonance_network_wallet/features/components/shared_address_action_sheet.dart';
import 'package:resonance_network_wallet/features/components/skeleton.dart';
-import 'package:resonance_network_wallet/v2/components/glass_button.dart';
+import 'package:resonance_network_wallet/v2/components/glass_button.dart' hide ButtonVariant;
import 'package:resonance_network_wallet/v2/components/glass_icon_button.dart';
import 'package:resonance_network_wallet/v2/screens/accounts/accounts_sheet.dart';
import 'package:resonance_network_wallet/v2/screens/receive/receive_sheet.dart';
import 'package:resonance_network_wallet/v2/screens/send/send_sheet.dart';
import 'package:resonance_network_wallet/v2/screens/settings/settings_screen.dart';
import 'package:resonance_network_wallet/utils/feature_flags.dart';
+import 'package:resonance_network_wallet/v2/screens/pos/pos_amount_screen.dart';
import 'package:resonance_network_wallet/v2/screens/swap/swap_screen.dart';
import 'package:resonance_network_wallet/providers/account_id_list_cache.dart';
import 'package:resonance_network_wallet/providers/account_providers.dart';
@@ -48,6 +50,15 @@ class _HomeScreenState extends ConsumerState {
}
void _processIntentIfAvailable() {
+ final payment = ref.read(paymentIntentProvider);
+ if (payment != null) {
+ WidgetsBinding.instance.addPostFrameCallback((_) {
+ ref.read(paymentIntentProvider.notifier).state = null;
+ showSendSheetV2(context, address: payment.to, amount: payment.amount, isPayMode: true);
+ });
+ return;
+ }
+
final shared = ref.read(sharedAccountIntentProvider);
if (shared != null) {
WidgetsBinding.instance.addPostFrameCallback((_) {
@@ -67,13 +78,14 @@ class _HomeScreenState extends ConsumerState {
_processIntentIfAvailable();
final isBalanceHidden = ref.watch(isBalanceHiddenProvider);
+ final isPosMode = ref.watch(posModeProvider);
final accountAsync = ref.watch(activeAccountProvider);
final balanceAsync = ref.watch(balanceProvider);
final txAsync = ref.watch(activeAccountTransactionsProvider);
final colors = context.colors;
final text = context.themeText;
- return accountAsync.when(
+ Widget screen = accountAsync.when(
loading: () => ScaffoldBase(
child: Center(child: CircularProgressIndicator(color: colors.textPrimary)),
),
@@ -91,11 +103,34 @@ class _HomeScreenState extends ConsumerState {
slivers: [
_buildContent(active, balanceAsync, isBalanceHidden, colors, text),
ActivitySection(txAsync: txAsync, activeAccount: active.account, onRetry: _refresh),
- const SizedBox(height: 58),
+ SizedBox(height: isPosMode ? 120 : 58),
],
);
},
);
+
+ if (!isPosMode) return screen;
+
+ return Stack(
+ children: [
+ screen,
+ Positioned(
+ left: 24,
+ right: 24,
+ bottom: MediaQuery.of(context).padding.bottom + 24,
+ child: _buildPosButton(colors, text),
+ ),
+ ],
+ );
+ }
+
+ Widget _buildPosButton(AppColorsV2 colors, AppTextTheme text) {
+ return Button(
+ label: 'New Charge',
+ variant: ButtonVariant.accent,
+ onPressed: () => Navigator.push(context, MaterialPageRoute(builder: (_) => const PosAmountScreen())),
+ textStyle: text.smallTitle?.copyWith(fontWeight: FontWeight.w700, fontSize: 20, decoration: TextDecoration.none),
+ );
}
Widget _buildContent(
diff --git a/mobile-app/lib/v2/screens/pos/pos_amount_screen.dart b/mobile-app/lib/v2/screens/pos/pos_amount_screen.dart
new file mode 100644
index 00000000..79e3a2a1
--- /dev/null
+++ b/mobile-app/lib/v2/screens/pos/pos_amount_screen.dart
@@ -0,0 +1,143 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:intl/intl.dart';
+import 'package:quantus_sdk/quantus_sdk.dart';
+import 'package:resonance_network_wallet/features/components/button.dart';
+import 'package:resonance_network_wallet/v2/components/scaffold_base.dart';
+import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart';
+import 'package:resonance_network_wallet/v2/screens/pos/pos_qr_screen.dart';
+import 'package:resonance_network_wallet/v2/theme/app_colors.dart';
+import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart';
+
+class PosAmountScreen extends ConsumerStatefulWidget {
+ const PosAmountScreen({super.key});
+
+ @override
+ ConsumerState createState() => _PosAmountScreenState();
+}
+
+class _PosAmountScreenState extends ConsumerState {
+ String _input = '0';
+ final _fmt = NumberFormattingService();
+ final _decimalFilter = DecimalInputFilter();
+
+ void _onDigit(String digit) {
+ final oldText = _input == '0' && digit != '.' && digit != ',' ? '' : _input;
+ final newText = oldText + digit;
+
+ final oldValue = TextEditingValue(text: oldText);
+ final newValue = TextEditingValue(text: newText);
+
+ final formatted = _decimalFilter.formatEditUpdate(oldValue, newValue);
+
+ setState(() {
+ _input = formatted.text.isEmpty ? '0' : formatted.text;
+ });
+ }
+
+ void _onBackspace() {
+ setState(() {
+ if (_input.length <= 1) {
+ _input = '0';
+ } else {
+ _input = _input.substring(0, _input.length - 1);
+ }
+ });
+ }
+
+ void _onClear() => setState(() => _input = '0');
+
+ void _onCharge() {
+ final amount = _fmt.parseAmount(_input);
+ if (amount == null || amount <= BigInt.zero) return;
+ Navigator.push(context, MaterialPageRoute(builder: (_) => PosQrScreen(amount: _input)));
+ }
+
+ bool get _isValid {
+ final amount = _fmt.parseAmount(_input);
+ return amount != null && amount > BigInt.zero;
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ final colors = context.colors;
+ final text = context.themeText;
+
+ return ScaffoldBase(
+ appBar: const V2AppBar(title: 'New Charge'),
+ child: Column(
+ children: [
+ Expanded(
+ child: Center(
+ child: FittedBox(
+ fit: BoxFit.scaleDown,
+ child: Text(
+ '$_input ${AppConstants.tokenSymbol}',
+ style: text.extraLargeTitle?.copyWith(
+ color: colors.textPrimary,
+ fontSize: 56,
+ fontWeight: FontWeight.w600,
+ ),
+ ),
+ ),
+ ),
+ ),
+ _buildKeypad(colors, text),
+ const SizedBox(height: 16),
+ _buildChargeButton(colors, text),
+ const SizedBox(height: 24),
+ ],
+ ),
+ );
+ }
+
+ Widget _buildKeypad(AppColorsV2 colors, AppTextTheme text) {
+ final decimalSeparator = NumberFormat().symbols.DECIMAL_SEP;
+ final keys = [
+ ['1', '2', '3'],
+ ['4', '5', '6'],
+ ['7', '8', '9'],
+ [decimalSeparator, '0', 'backspace'],
+ ];
+
+ return Column(
+ children: keys.map((row) {
+ return Padding(
+ padding: const EdgeInsets.symmetric(vertical: 6),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: row.map((key) => _buildKey(key, colors, text)).toList(),
+ ),
+ );
+ }).toList(),
+ );
+ }
+
+ Widget _buildKey(String key, AppColorsV2 colors, AppTextTheme text) {
+ return Expanded(
+ child: GestureDetector(
+ onTap: () => key == 'backspace' ? _onBackspace() : _onDigit(key),
+ onLongPress: key == 'backspace' ? _onClear : null,
+ behavior: HitTestBehavior.opaque,
+ child: Container(
+ height: 60,
+ alignment: Alignment.center,
+ child: key == 'backspace'
+ ? Icon(Icons.backspace_outlined, color: colors.textPrimary, size: 28)
+ : Text(key, style: text.mediumTitle?.copyWith(color: colors.textPrimary, fontSize: 28)),
+ ),
+ ),
+ );
+ }
+
+ Widget _buildChargeButton(AppColorsV2 colors, AppTextTheme text) {
+ final disabled = !_isValid;
+ return Button(
+ label: _isValid ? 'Charge $_input ${AppConstants.tokenSymbol}' : 'Enter Amount',
+ variant: ButtonVariant.accent,
+ isDisabled: disabled,
+ onPressed: _onCharge,
+ textStyle: text.smallTitle?.copyWith(fontWeight: FontWeight.w700),
+ );
+ }
+}
diff --git a/mobile-app/lib/v2/screens/pos/pos_qr_screen.dart b/mobile-app/lib/v2/screens/pos/pos_qr_screen.dart
new file mode 100644
index 00000000..fd1d9fe7
--- /dev/null
+++ b/mobile-app/lib/v2/screens/pos/pos_qr_screen.dart
@@ -0,0 +1,89 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:qr_flutter/qr_flutter.dart';
+import 'package:quantus_sdk/quantus_sdk.dart';
+import 'package:resonance_network_wallet/providers/account_providers.dart';
+import 'package:resonance_network_wallet/services/pos_service.dart';
+import 'package:resonance_network_wallet/v2/components/glass_button.dart';
+import 'package:resonance_network_wallet/v2/components/scaffold_base.dart';
+import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart';
+import 'package:resonance_network_wallet/v2/theme/app_colors.dart';
+import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart';
+
+class PosQrScreen extends ConsumerStatefulWidget {
+ final String amount;
+ const PosQrScreen({super.key, required this.amount});
+
+ @override
+ ConsumerState createState() => _PosQrScreenState();
+}
+
+class _PosQrScreenState extends ConsumerState {
+ final _posService = PosService();
+ PosPaymentRequest? _request;
+
+ @override
+ Widget build(BuildContext context) {
+ final colors = context.colors;
+ final text = context.themeText;
+ final accountAsync = ref.watch(activeAccountProvider);
+
+ return ScaffoldBase(
+ appBar: const V2AppBar(title: 'Scan to Pay'),
+ child: accountAsync.when(
+ loading: () => Center(child: CircularProgressIndicator(color: colors.textPrimary)),
+ error: (e, _) => Center(
+ child: Text('Error: $e', style: text.detail?.copyWith(color: colors.textError)),
+ ),
+ data: (active) {
+ if (active == null) return const Center(child: Text('No active account'));
+ _request ??= _posService.createPaymentRequest(accountId: active.account.accountId, amount: widget.amount);
+ debugPrint('POS Payment URL: ${_request!.paymentUrl}');
+ return _buildContent(_request!, colors, text);
+ },
+ ),
+ );
+ }
+
+ Widget _buildContent(PosPaymentRequest request, AppColorsV2 colors, AppTextTheme text) {
+ return Column(
+ children: [
+ const Spacer(),
+ Text(
+ '${request.amount} ${AppConstants.tokenSymbol}',
+ style: text.extraLargeTitle?.copyWith(color: colors.textPrimary, fontSize: 40),
+ ),
+ const SizedBox(height: 32),
+ _buildQrCode(request.paymentUrl, colors),
+ const SizedBox(height: 16),
+ Text('Ref: ${request.refId}', style: text.detail?.copyWith(color: colors.textTertiary)),
+ const Spacer(),
+ GlassButton.simple(label: 'New Charge', onTap: () => Navigator.pop(context), variant: ButtonVariant.secondary),
+ const SizedBox(height: 16),
+ GlassButton.simple(
+ label: 'Done',
+ onTap: () => Navigator.of(context).popUntil((route) => route.isFirst),
+ variant: ButtonVariant.primary,
+ ),
+ const SizedBox(height: 24),
+ ],
+ );
+ }
+
+ Widget _buildQrCode(String data, AppColorsV2 colors) {
+ return Center(
+ child: ClipRRect(
+ borderRadius: BorderRadius.circular(16),
+ child: QrImageView(
+ data: data,
+ version: QrVersions.auto,
+ size: 280,
+ padding: const EdgeInsets.all(16),
+ backgroundColor: Colors.white,
+ eyeStyle: const QrEyeStyle(eyeShape: QrEyeShape.square, color: Colors.black),
+ dataModuleStyle: const QrDataModuleStyle(dataModuleShape: QrDataModuleShape.square, color: Colors.black),
+ ),
+ ),
+ );
+ }
+}
diff --git a/mobile-app/lib/v2/screens/send/send_sheet.dart b/mobile-app/lib/v2/screens/send/send_sheet.dart
index 0062da7b..f946eabc 100644
--- a/mobile-app/lib/v2/screens/send/send_sheet.dart
+++ b/mobile-app/lib/v2/screens/send/send_sheet.dart
@@ -19,7 +19,9 @@ enum _Step { form, confirm, sending, complete }
class SendSheet extends ConsumerStatefulWidget {
final String? initialAddress;
- const SendSheet({super.key, this.initialAddress});
+ final String? initialAmount;
+ final bool isPayMode;
+ const SendSheet({super.key, this.initialAddress, this.initialAmount, this.isPayMode = false});
@override
ConsumerState createState() => _SendSheetState();
@@ -48,6 +50,9 @@ class _SendSheetState extends ConsumerState {
if (widget.initialAddress != null) {
_recipientController.text = widget.initialAddress!;
}
+ if (widget.initialAmount != null) {
+ _amountController.text = widget.initialAmount!;
+ }
}
@override
@@ -169,7 +174,7 @@ class _SendSheetState extends ConsumerState {
final balance = ref.watch(effectiveMaxBalanceProvider);
return BottomSheetContainer(
- title: 'Send',
+ title: widget.isPayMode ? 'Pay' : 'Send',
onBack: _step == _Step.confirm ? _backToForm : null,
child: AnimatedSize(
duration: const Duration(milliseconds: 200),
@@ -404,7 +409,10 @@ class _SendSheetState extends ConsumerState {
const SizedBox(height: 48),
CircularProgressIndicator(color: colors.textPrimary),
const SizedBox(height: 24),
- Text('Sending...', style: text.smallTitle?.copyWith(color: colors.textPrimary)),
+ Text(
+ widget.isPayMode ? 'Paying...' : 'Sending...',
+ style: text.smallTitle?.copyWith(color: colors.textPrimary),
+ ),
const SizedBox(height: 80),
],
);
@@ -417,7 +425,7 @@ class _SendSheetState extends ConsumerState {
const SizedBox(height: 48),
const SuccessCheck(size: 64),
const SizedBox(height: 24),
- Text('Sent!', style: text.smallTitle?.copyWith(color: colors.textPrimary)),
+ Text(widget.isPayMode ? 'Paid!' : 'Sent!', style: text.smallTitle?.copyWith(color: colors.textPrimary)),
const SizedBox(height: 8),
Text(
'${_fmt.formatBalance(_amount)} ${AppConstants.tokenSymbol}',
@@ -444,12 +452,12 @@ class _SendSheetState extends ConsumerState {
}
}
-void showSendSheetV2(BuildContext context, {String? address}) {
+void showSendSheetV2(BuildContext context, {String? address, String? amount, bool isPayMode = false}) {
BottomSheetContainer.show(
context,
builder: (_) => Padding(
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
- child: SendSheet(initialAddress: address),
+ child: SendSheet(initialAddress: address, initialAmount: amount, isPayMode: isPayMode),
),
);
}
diff --git a/mobile-app/lib/v2/screens/settings/settings_screen.dart b/mobile-app/lib/v2/screens/settings/settings_screen.dart
index 63e6ea99..516d3c6a 100644
--- a/mobile-app/lib/v2/screens/settings/settings_screen.dart
+++ b/mobile-app/lib/v2/screens/settings/settings_screen.dart
@@ -13,6 +13,7 @@ import 'package:resonance_network_wallet/providers/account_associations_provider
import 'package:resonance_network_wallet/providers/account_providers.dart';
import 'package:resonance_network_wallet/providers/notification_config_provider.dart';
import 'package:resonance_network_wallet/providers/pending_transactions_provider.dart';
+import 'package:resonance_network_wallet/providers/wallet_providers.dart';
import 'package:resonance_network_wallet/shared/utils/account_utils.dart';
import 'package:resonance_network_wallet/v2/components/scaffold_base.dart';
import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart';
@@ -99,6 +100,7 @@ class _SettingsScreenV2State extends ConsumerState {
final colors = context.colors;
final text = context.themeText;
final notifConfig = ref.watch(notificationConfigProvider);
+ final posMode = ref.watch(posModeProvider);
return ScaffoldBase(
appBar: const V2AppBar(title: 'Settings'),
@@ -134,8 +136,15 @@ class _SettingsScreenV2State extends ConsumerState {
]),
const SizedBox(height: 40),
_section('Preferences', colors, text, [
- // _chevronItem('Currency', 'USD (\$)', colors, text, onTap: () {}),
- // _divider(colors),
+ _toggleItem(
+ 'POS Mode',
+ posMode ? 'Point of Sale Enabled' : 'Disabled',
+ posMode,
+ (v) => ref.read(posModeProvider.notifier).setPosMode(v),
+ colors,
+ text,
+ ),
+ _divider(colors),
_toggleItem(
'Notifications',
notifConfig.enabled ? 'Transaction Alerts Enabled' : 'Alerts Disabled',
diff --git a/quantus_sdk/lib/src/services/settings_service.dart b/quantus_sdk/lib/src/services/settings_service.dart
index ce2495ca..715b84ee 100644
--- a/quantus_sdk/lib/src/services/settings_service.dart
+++ b/quantus_sdk/lib/src/services/settings_service.dart
@@ -287,6 +287,17 @@ class SettingsService {
return _prefs.getBool(_balanceHiddenKey) ?? false;
}
+ // POS Mode Settings
+ static const String _posModeEnabledKey = 'pos_mode_enabled';
+
+ Future setPosModeEnabled(bool enabled) async {
+ await _prefs.setBool(_posModeEnabledKey, enabled);
+ }
+
+ bool isPosModeEnabled() {
+ return _prefs.getBool(_posModeEnabledKey) ?? false;
+ }
+
// --- Primitive Accessors for General Use ---
/// Get a boolean value from SharedPreferences