diff --git a/lib/features/add_transaction/screen.dart b/lib/features/add_transaction/screen.dart index 4d36176..7d11806 100644 --- a/lib/features/add_transaction/screen.dart +++ b/lib/features/add_transaction/screen.dart @@ -433,33 +433,16 @@ class _AddTransactionScreenState extends ConsumerState ListView( padding: const EdgeInsets.all(20), children: [ - Stack( - children: [ - IgnorePointer( - ignoring: isEditing, - child: TypeToggle( - selected: state.type, - onChanged: (type) => ref - .read( - addTransactionProvider(widget.initial).notifier, - ) - .setType(type), - 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), - ), - ), - ], + IgnorePointer( + ignoring: isEditing, + child: TypeToggle( + selected: state.type, + onChanged: (type) => ref + .read(addTransactionProvider(widget.initial).notifier) + .setType(type), + isDark: isDark, + isEditing: isEditing, + ), ), const SizedBox(height: 16), @@ -796,7 +779,6 @@ class _ToAccountDropdownOverlay extends ConsumerWidget { // Calculate position from trigger key double top = 340; double left = 20; - double? width; if (triggerKey?.currentContext != null) { final renderBox = @@ -805,98 +787,98 @@ class _ToAccountDropdownOverlay extends ConsumerWidget { final size = renderBox.size; top = offset.dy + size.height + 4; left = offset.dx; - width = size.width; } return Positioned( top: top, left: left, - width: width, - child: Material( - elevation: 8, - borderRadius: BorderRadius.circular(12), - color: Colors.transparent, - child: Container( - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surface, - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: const Color(0xFF7C6DED).withOpacity(0.3), - width: 1.5, - ), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.2), - blurRadius: 16, - offset: const Offset(0, 4), + child: IntrinsicWidth( + child: Material( + elevation: 8, + borderRadius: BorderRadius.circular(12), + color: Colors.transparent, + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: const Color(0xFF7C6DED).withOpacity(0.3), + width: 1.5, ), - ], - ), - child: accountsAsync.when( - data: (accounts) { - final filteredAccounts = accounts - .where((a) => a.id != selectedAccountId) - .toList(); + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.2), + blurRadius: 16, + offset: const Offset(0, 4), + ), + ], + ), + child: accountsAsync.when( + data: (accounts) { + final filteredAccounts = accounts + .where((a) => a.id != selectedAccountId) + .toList(); - return Column( - mainAxisSize: MainAxisSize.min, - children: filteredAccounts.map((account) { - final isSelected = account.id == toAccountId; - return InkWell( - borderRadius: BorderRadius.circular(12), - onTap: () { - ref - .read(addTransactionProvider(initial).notifier) - .setToAccountId(account.id); - onClose(); - HapticService.light(); - }, - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 14, - vertical: 12, - ), - child: Row( - children: [ - Icon( - Icons.account_balance_wallet_rounded, - size: 16, - color: isSelected - ? const Color(0xFF7C6DED) - : Theme.of( - context, - ).colorScheme.onSurface.withOpacity(0.5), - ), - const SizedBox(width: 10), - Expanded( - child: Text( - account.name, - style: TextStyle( - fontSize: 14, - fontWeight: isSelected - ? FontWeight.w600 - : FontWeight.w400, - color: isSelected - ? const Color(0xFF7C6DED) - : Theme.of(context).colorScheme.onSurface, + return Column( + mainAxisSize: MainAxisSize.min, + children: filteredAccounts.map((account) { + final isSelected = account.id == toAccountId; + return InkWell( + borderRadius: BorderRadius.circular(12), + onTap: () { + ref + .read(addTransactionProvider(initial).notifier) + .setToAccountId(account.id); + onClose(); + HapticService.light(); + }, + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 14, + vertical: 12, + ), + child: Row( + children: [ + Icon( + Icons.account_balance_wallet_rounded, + size: 16, + color: isSelected + ? const Color(0xFF7C6DED) + : Theme.of( + context, + ).colorScheme.onSurface.withOpacity(0.5), + ), + const SizedBox(width: 10), + Expanded( + child: Text( + account.name, + style: TextStyle( + fontSize: 14, + fontWeight: isSelected + ? FontWeight.w600 + : FontWeight.w400, + color: isSelected + ? const Color(0xFF7C6DED) + : Theme.of(context).colorScheme.onSurface, + ), ), ), - ), - if (isSelected) - const Icon( - Icons.check_rounded, - size: 16, - color: Color(0xFF7C6DED), - ), - ], + if (isSelected) + const Icon( + Icons.check_rounded, + size: 16, + color: Color(0xFF7C6DED), + ), + ], + ), ), - ), - ); - }).toList(), - ); - }, - loading: () => const SizedBox.shrink(), - error: (_, __) => const SizedBox.shrink(), + ); + }).toList(), + ); + }, + loading: () => const SizedBox.shrink(), + error: (_, __) => const SizedBox.shrink(), + ), ), ), ), diff --git a/lib/features/add_transaction/widgets/account_row.dart b/lib/features/add_transaction/widgets/account_row.dart index 7618901..4a6b3ac 100644 --- a/lib/features/add_transaction/widgets/account_row.dart +++ b/lib/features/add_transaction/widgets/account_row.dart @@ -418,13 +418,6 @@ class _AccountHalf extends StatelessWidget { ), ), ), - if (error != null) ...[ - const SizedBox(height: 4), - Text( - error!, - style: const TextStyle(fontSize: 11, color: Color(0xFFE05C6B)), - ), - ], ], ); } diff --git a/lib/features/add_transaction/widgets/account_selector.dart b/lib/features/add_transaction/widgets/account_selector.dart index c1db176..189f0b6 100644 --- a/lib/features/add_transaction/widgets/account_selector.dart +++ b/lib/features/add_transaction/widgets/account_selector.dart @@ -136,7 +136,6 @@ class AccountDropdownOverlay extends ConsumerWidget { // Calculate position from trigger key double top = 76; double left = 20; - double? width; if (triggerKey?.currentContext != null) { final renderBox = @@ -145,115 +144,115 @@ class AccountDropdownOverlay extends ConsumerWidget { final size = renderBox.size; top = offset.dy + size.height + 4; left = offset.dx; - width = size.width; } return Positioned( top: top, left: left, - width: width, - child: Material( - elevation: 8, - borderRadius: BorderRadius.circular(12), - color: Colors.transparent, - child: Container( - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surface, - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: const Color(0xFF7C6DED).withOpacity(0.3), - width: 1.5, - ), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.2), - blurRadius: 16, - offset: const Offset(0, 4), + child: IntrinsicWidth( + child: Material( + elevation: 8, + borderRadius: BorderRadius.circular(12), + color: Colors.transparent, + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: const Color(0xFF7C6DED).withOpacity(0.3), + width: 1.5, ), - ], - ), - child: accountsAsync.when( - data: (accounts) { - final txAccountId = ref - .read(addTransactionProvider(initial)) - .selectedAccountId; - final Account displayAccount; - if (txAccountId != null) { - displayAccount = accounts.firstWhere( - (a) => a.id == txAccountId, - orElse: () => accounts.firstWhere( - (a) => a.isMain, - orElse: () => accounts.first, - ), - ); - } else { - displayAccount = - activeAccount ?? - accounts.firstWhere( + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.2), + blurRadius: 16, + offset: const Offset(0, 4), + ), + ], + ), + child: accountsAsync.when( + data: (accounts) { + final txAccountId = ref + .read(addTransactionProvider(initial)) + .selectedAccountId; + final Account displayAccount; + if (txAccountId != null) { + displayAccount = accounts.firstWhere( + (a) => a.id == txAccountId, + orElse: () => accounts.firstWhere( (a) => a.isMain, orElse: () => accounts.first, - ); - } - - return Column( - mainAxisSize: MainAxisSize.min, - children: accounts.map((account) { - final isSelected = account.id == displayAccount.id; - return InkWell( - borderRadius: BorderRadius.circular(12), - onTap: () { - ref - .read(addTransactionProvider(initial).notifier) - .setAccountId(account.id); - onClose(); - HapticService.light(); - }, - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 14, - vertical: 12, - ), - child: Row( - children: [ - Icon( - Icons.account_balance_wallet_rounded, - size: 16, - color: isSelected - ? const Color(0xFF7C6DED) - : Theme.of( - context, - ).colorScheme.onSurface.withOpacity(0.5), - ), - const SizedBox(width: 10), - Expanded( - child: Text( - account.name, - style: TextStyle( - fontSize: 14, - fontWeight: isSelected - ? FontWeight.w600 - : FontWeight.w400, - color: isSelected - ? const Color(0xFF7C6DED) - : Theme.of(context).colorScheme.onSurface, - ), - ), - ), - if (isSelected) - const Icon( - Icons.check_rounded, - size: 16, - color: Color(0xFF7C6DED), - ), - ], - ), ), ); - }).toList(), - ); - }, - loading: () => const SizedBox.shrink(), - error: (_, __) => const SizedBox.shrink(), + } else { + displayAccount = + activeAccount ?? + accounts.firstWhere( + (a) => a.isMain, + orElse: () => accounts.first, + ); + } + + return Column( + mainAxisSize: MainAxisSize.min, + children: accounts.map((account) { + final isSelected = account.id == displayAccount.id; + return InkWell( + borderRadius: BorderRadius.circular(12), + onTap: () { + ref + .read(addTransactionProvider(initial).notifier) + .setAccountId(account.id); + onClose(); + HapticService.light(); + }, + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 14, + vertical: 12, + ), + child: Row( + children: [ + Icon( + Icons.account_balance_wallet_rounded, + size: 16, + color: isSelected + ? const Color(0xFF7C6DED) + : Theme.of( + context, + ).colorScheme.onSurface.withOpacity(0.5), + ), + const SizedBox(width: 10), + Expanded( + child: Text( + account.name, + style: TextStyle( + fontSize: 14, + fontWeight: isSelected + ? FontWeight.w600 + : FontWeight.w400, + color: isSelected + ? const Color(0xFF7C6DED) + : Theme.of(context).colorScheme.onSurface, + ), + ), + ), + if (isSelected) + const Icon( + Icons.check_rounded, + size: 16, + color: Color(0xFF7C6DED), + ), + ], + ), + ), + ); + }).toList(), + ); + }, + loading: () => const SizedBox.shrink(), + error: (_, __) => const SizedBox.shrink(), + ), ), ), ), diff --git a/lib/features/add_transaction/widgets/type_toggle.dart b/lib/features/add_transaction/widgets/type_toggle.dart index 86971f6..80bef93 100644 --- a/lib/features/add_transaction/widgets/type_toggle.dart +++ b/lib/features/add_transaction/widgets/type_toggle.dart @@ -8,12 +8,14 @@ class TypeToggle extends ConsumerWidget { final TransactionType selected; final ValueChanged onChanged; final bool isDark; + final bool isEditing; const TypeToggle({ super.key, required this.selected, required this.onChanged, required this.isDark, + this.isEditing = false, }); @override @@ -41,6 +43,7 @@ class TypeToggle extends ConsumerWidget { isSelected: selected == TransactionType.income, onTap: () => onChanged(TransactionType.income), isDark: isDark, + showLock: isEditing && selected == TransactionType.income, ), ), Expanded( @@ -51,6 +54,7 @@ class TypeToggle extends ConsumerWidget { isSelected: selected == TransactionType.expense, onTap: () => onChanged(TransactionType.expense), isDark: isDark, + showLock: isEditing && selected == TransactionType.expense, ), ), Expanded( @@ -64,6 +68,7 @@ class TypeToggle extends ConsumerWidget { : () => onChanged(TransactionType.transfer), isDark: isDark, disabled: transferDisabled, + showLock: isEditing && selected == TransactionType.transfer, ), ), ], @@ -80,6 +85,7 @@ class _TypeOption extends StatelessWidget { final VoidCallback? onTap; final bool isDark; final bool disabled; + final bool showLock; const _TypeOption({ required this.icon, @@ -89,6 +95,7 @@ class _TypeOption extends StatelessWidget { required this.onTap, required this.isDark, this.disabled = false, + this.showLock = false, }); @override @@ -99,46 +106,62 @@ class _TypeOption extends StatelessWidget { return GestureDetector( onTap: disabled ? null : onTap, - child: AnimatedContainer( - duration: const Duration(milliseconds: 200), - decoration: BoxDecoration( - color: isSelected && !disabled - ? effectiveColor.withOpacity(0.15) - : Colors.transparent, - borderRadius: BorderRadius.circular(11), - border: isSelected && !disabled - ? Border.all(color: effectiveColor, width: 1.5) - : null, - ), - child: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - icon, - color: isSelected && !disabled - ? effectiveColor - : Theme.of( - context, - ).colorScheme.onSurface.withOpacity(disabled ? 0.2 : 0.4), - size: 20, + child: Stack( + children: [ + AnimatedContainer( + duration: const Duration(milliseconds: 200), + decoration: BoxDecoration( + color: isSelected && !disabled + ? effectiveColor.withOpacity(0.15) + : Colors.transparent, + borderRadius: BorderRadius.circular(11), + border: isSelected && !disabled + ? Border.all(color: effectiveColor, width: 1.5) + : null, + ), + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + icon, + color: isSelected && !disabled + ? effectiveColor + : Theme.of(context).colorScheme.onSurface.withOpacity( + disabled ? 0.2 : 0.4, + ), + size: 20, + ), + const SizedBox(height: 4), + Text( + label, + style: TextStyle( + fontSize: 11, + fontWeight: isSelected + ? FontWeight.w600 + : FontWeight.w400, + color: isSelected && !disabled + ? effectiveColor + : Theme.of(context).colorScheme.onSurface.withOpacity( + disabled ? 0.2 : 0.5, + ), + ), + ), + ], ), - const SizedBox(height: 4), - Text( - label, - style: TextStyle( - fontSize: 11, - fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400, - color: isSelected && !disabled - ? effectiveColor - : Theme.of(context).colorScheme.onSurface.withOpacity( - disabled ? 0.2 : 0.5, - ), - ), - ), - ], + ), ), - ), + if (showLock) + Positioned( + top: 4, + right: 4, + child: Icon( + Icons.lock_outline, + size: 10, + color: Theme.of(context).colorScheme.onSurface.withOpacity(0.5), + ), + ), + ], ), ); }