mirror of
https://github.com/koloideal/Casha.git
synced 2026-06-10 10:25:28 +03:00
update
This commit is contained in:
@@ -5,6 +5,7 @@ import 'package:uuid/uuid.dart';
|
|||||||
import '../../core/constants.dart';
|
import '../../core/constants.dart';
|
||||||
import '../../core/l10n/locale_provider.dart';
|
import '../../core/l10n/locale_provider.dart';
|
||||||
import '../../core/services/haptic_service.dart';
|
import '../../core/services/haptic_service.dart';
|
||||||
|
import '../../shared/models/account.dart';
|
||||||
import '../../shared/models/transaction.dart';
|
import '../../shared/models/transaction.dart';
|
||||||
import '../dashboard/provider.dart';
|
import '../dashboard/provider.dart';
|
||||||
import '../settings/provider.dart';
|
import '../settings/provider.dart';
|
||||||
@@ -375,6 +376,10 @@ class _AddTransactionScreenState extends ConsumerState<AddTransactionScreen>
|
|||||||
final categories = ref.watch(availableCategoriesProvider(widget.initial));
|
final categories = ref.watch(availableCategoriesProvider(widget.initial));
|
||||||
final overrideCurrency = state.overrideCurrency;
|
final overrideCurrency = state.overrideCurrency;
|
||||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||||
|
final isEditing = state.isEditing;
|
||||||
|
final activeAccount = ref.watch(activeAccountProvider);
|
||||||
|
final isAccountLocked = activeAccount != null;
|
||||||
|
final isTransfer = state.type == TransactionType.transfer;
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
||||||
@@ -428,15 +433,37 @@ class _AddTransactionScreenState extends ConsumerState<AddTransactionScreen>
|
|||||||
ListView(
|
ListView(
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(20),
|
||||||
children: [
|
children: [
|
||||||
TypeToggle(
|
Stack(
|
||||||
|
children: [
|
||||||
|
IgnorePointer(
|
||||||
|
ignoring: isEditing,
|
||||||
|
child: TypeToggle(
|
||||||
selected: state.type,
|
selected: state.type,
|
||||||
onChanged: (type) => ref
|
onChanged: (type) => ref
|
||||||
.read(addTransactionProvider(widget.initial).notifier)
|
.read(
|
||||||
|
addTransactionProvider(widget.initial).notifier,
|
||||||
|
)
|
||||||
.setType(type),
|
.setType(type),
|
||||||
isDark: isDark,
|
isDark: isDark,
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
if (isEditing)
|
||||||
|
Positioned(
|
||||||
|
top: 8,
|
||||||
|
right: 8,
|
||||||
|
child: Icon(
|
||||||
|
Icons.lock_outline,
|
||||||
|
size: 16,
|
||||||
|
color: Theme.of(
|
||||||
|
context,
|
||||||
|
).colorScheme.onSurface.withOpacity(0.4),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
|
if (isTransfer)
|
||||||
AccountRow(
|
AccountRow(
|
||||||
initial: widget.initial,
|
initial: widget.initial,
|
||||||
showFromDropdown: _showFromAccountDropdown,
|
showFromDropdown: _showFromAccountDropdown,
|
||||||
@@ -454,12 +481,17 @@ class _AddTransactionScreenState extends ConsumerState<AddTransactionScreen>
|
|||||||
fromAccountError: _fromAccountError,
|
fromAccountError: _fromAccountError,
|
||||||
toAccountError: _toAccountError,
|
toAccountError: _toAccountError,
|
||||||
isDark: isDark,
|
isDark: isDark,
|
||||||
|
isAccountLocked: isAccountLocked,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 24),
|
if (isTransfer) const SizedBox(height: 24),
|
||||||
|
|
||||||
SectionLabel(s.amount),
|
SectionLabel(s.amount),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
AmountInput(
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: AmountInput(
|
||||||
controller: _amountController,
|
controller: _amountController,
|
||||||
currencySymbol: overrideCurrency,
|
currencySymbol: overrideCurrency,
|
||||||
currencyCode: state.overrideCurrencyCode,
|
currencyCode: state.overrideCurrencyCode,
|
||||||
@@ -469,10 +501,32 @@ class _AddTransactionScreenState extends ConsumerState<AddTransactionScreen>
|
|||||||
onChanged: (v) {
|
onChanged: (v) {
|
||||||
final parsed = double.tryParse(v);
|
final parsed = double.tryParse(v);
|
||||||
ref
|
ref
|
||||||
.read(addTransactionProvider(widget.initial).notifier)
|
.read(
|
||||||
|
addTransactionProvider(
|
||||||
|
widget.initial,
|
||||||
|
).notifier,
|
||||||
|
)
|
||||||
.setAmount(parsed);
|
.setAmount(parsed);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
if (!isTransfer) ...[
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
_InlineAccountSelector(
|
||||||
|
initial: widget.initial,
|
||||||
|
showDropdown: _showFromAccountDropdown,
|
||||||
|
onToggleDropdown: () => setState(() {
|
||||||
|
_showFromAccountDropdown =
|
||||||
|
!_showFromAccountDropdown;
|
||||||
|
_fromAccountError = null;
|
||||||
|
}),
|
||||||
|
indicatorKey: _fromAccountIndicatorKey,
|
||||||
|
isDark: isDark,
|
||||||
|
isLocked: isAccountLocked,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
@@ -589,6 +643,131 @@ class _AddTransactionScreenState extends ConsumerState<AddTransactionScreen>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _InlineAccountSelector extends ConsumerWidget {
|
||||||
|
final Transaction? initial;
|
||||||
|
final bool showDropdown;
|
||||||
|
final VoidCallback onToggleDropdown;
|
||||||
|
final GlobalKey indicatorKey;
|
||||||
|
final bool isDark;
|
||||||
|
final bool isLocked;
|
||||||
|
|
||||||
|
const _InlineAccountSelector({
|
||||||
|
required this.initial,
|
||||||
|
required this.showDropdown,
|
||||||
|
required this.onToggleDropdown,
|
||||||
|
required this.indicatorKey,
|
||||||
|
required this.isDark,
|
||||||
|
required this.isLocked,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final accountsAsync = ref.watch(accountsProvider);
|
||||||
|
final state = ref.watch(addTransactionProvider(initial));
|
||||||
|
final activeAccount = ref.watch(activeAccountProvider);
|
||||||
|
|
||||||
|
return accountsAsync.when(
|
||||||
|
data: (accounts) {
|
||||||
|
final selectedAccountId = state.selectedAccountId;
|
||||||
|
final Account? displayAccount;
|
||||||
|
|
||||||
|
if (selectedAccountId != null) {
|
||||||
|
displayAccount = accounts.firstWhere(
|
||||||
|
(a) => a.id == selectedAccountId,
|
||||||
|
orElse: () => accounts.isNotEmpty
|
||||||
|
? accounts.first
|
||||||
|
: Account(
|
||||||
|
id: 0,
|
||||||
|
name: '',
|
||||||
|
currency: 'USD',
|
||||||
|
isMain: false,
|
||||||
|
sortOrder: 0,
|
||||||
|
createdAt: DateTime.now(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
displayAccount =
|
||||||
|
activeAccount ?? (accounts.isNotEmpty ? accounts.first : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Opacity(
|
||||||
|
opacity: isLocked ? 0.7 : 1.0,
|
||||||
|
child: IgnorePointer(
|
||||||
|
ignoring: isLocked,
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: onToggleDropdown,
|
||||||
|
child: Container(
|
||||||
|
key: indicatorKey,
|
||||||
|
height: 56,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 14),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context).colorScheme.surface,
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
border: Border.all(
|
||||||
|
color: isDark
|
||||||
|
? Colors.white.withOpacity(0.1)
|
||||||
|
: const Color(0xFFDDDDEE),
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.account_balance_wallet_rounded,
|
||||||
|
size: 16,
|
||||||
|
color: Theme.of(
|
||||||
|
context,
|
||||||
|
).colorScheme.onSurface.withOpacity(0.6),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Text(
|
||||||
|
displayAccount?.name ?? 'Account',
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||||
|
color: Theme.of(context).colorScheme.onSurface,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
fontSize: 14,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (!isLocked) ...[
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
Icon(
|
||||||
|
showDropdown
|
||||||
|
? Icons.arrow_drop_up
|
||||||
|
: Icons.arrow_drop_down,
|
||||||
|
size: 20,
|
||||||
|
color: Theme.of(
|
||||||
|
context,
|
||||||
|
).colorScheme.onSurface.withOpacity(0.6),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
loading: () => Container(
|
||||||
|
height: 56,
|
||||||
|
width: 140,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context).colorScheme.surface,
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
error: (_, __) => Container(
|
||||||
|
height: 56,
|
||||||
|
width: 140,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context).colorScheme.surface,
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class _ToAccountDropdownOverlay extends ConsumerWidget {
|
class _ToAccountDropdownOverlay extends ConsumerWidget {
|
||||||
final Transaction? initial;
|
final Transaction? initial;
|
||||||
final VoidCallback onClose;
|
final VoidCallback onClose;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ class AccountRow extends ConsumerWidget {
|
|||||||
final String? fromAccountError;
|
final String? fromAccountError;
|
||||||
final String? toAccountError;
|
final String? toAccountError;
|
||||||
final bool isDark;
|
final bool isDark;
|
||||||
|
final bool isAccountLocked;
|
||||||
|
|
||||||
const AccountRow({
|
const AccountRow({
|
||||||
super.key,
|
super.key,
|
||||||
@@ -29,6 +30,7 @@ class AccountRow extends ConsumerWidget {
|
|||||||
this.fromAccountError,
|
this.fromAccountError,
|
||||||
this.toAccountError,
|
this.toAccountError,
|
||||||
required this.isDark,
|
required this.isDark,
|
||||||
|
this.isAccountLocked = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -79,6 +81,7 @@ class AccountRow extends ConsumerWidget {
|
|||||||
fromAccountError: fromAccountError,
|
fromAccountError: fromAccountError,
|
||||||
toAccountError: toAccountError,
|
toAccountError: toAccountError,
|
||||||
isDark: isDark,
|
isDark: isDark,
|
||||||
|
isAccountLocked: isAccountLocked,
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
_SingleAccountSelector(
|
_SingleAccountSelector(
|
||||||
@@ -226,6 +229,7 @@ class _TransferAccountRow extends ConsumerWidget {
|
|||||||
final String? fromAccountError;
|
final String? fromAccountError;
|
||||||
final String? toAccountError;
|
final String? toAccountError;
|
||||||
final bool isDark;
|
final bool isDark;
|
||||||
|
final bool isAccountLocked;
|
||||||
|
|
||||||
const _TransferAccountRow({
|
const _TransferAccountRow({
|
||||||
required this.initial,
|
required this.initial,
|
||||||
@@ -239,6 +243,7 @@ class _TransferAccountRow extends ConsumerWidget {
|
|||||||
this.fromAccountError,
|
this.fromAccountError,
|
||||||
this.toAccountError,
|
this.toAccountError,
|
||||||
required this.isDark,
|
required this.isDark,
|
||||||
|
this.isAccountLocked = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -285,10 +290,11 @@ class _TransferAccountRow extends ConsumerWidget {
|
|||||||
account: fromAccount,
|
account: fromAccount,
|
||||||
label: 'From',
|
label: 'From',
|
||||||
showDropdown: showFromDropdown,
|
showDropdown: showFromDropdown,
|
||||||
onToggle: onToggleFromDropdown,
|
onToggle: isAccountLocked ? null : onToggleFromDropdown,
|
||||||
indicatorKey: fromIndicatorKey,
|
indicatorKey: fromIndicatorKey,
|
||||||
error: fromAccountError,
|
error: fromAccountError,
|
||||||
isDark: isDark,
|
isDark: isDark,
|
||||||
|
disabled: isAccountLocked,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
|
|||||||
Reference in New Issue
Block a user