diff --git a/lib/features/dashboard/widgets/account_editor_overlay.dart b/lib/features/dashboard/widgets/account_editor_overlay.dart index fbf18b4..ea81549 100644 --- a/lib/features/dashboard/widgets/account_editor_overlay.dart +++ b/lib/features/dashboard/widgets/account_editor_overlay.dart @@ -32,6 +32,7 @@ class _AccountEditorOverlayState extends State { dynamic get dash => widget.dashboardState; late TextEditingController _nameController; late String _selectedCurrency; + bool _showCurrencyDropdown = false; @override void initState() { @@ -54,7 +55,7 @@ class _AccountEditorOverlayState extends State { final mq = MediaQuery.of(widget.context); final cardTop = mq.padding.top + kToolbarHeight + 16; const cardHeight = 220.0; - const editorPanelHeight = 140.0; // Increased to accommodate currency picker + const editorPanelHeight = 102.0; // Increased from 90 to prevent overflow final editorPanelTop = cardTop + cardHeight + 20; final colorPanelTop = editorPanelTop + editorPanelHeight + 12; const colorPanelHeight = 410.0; @@ -71,7 +72,15 @@ class _AccountEditorOverlayState extends State { ), Positioned.fill( child: GestureDetector( - onTap: () => dash.closeAccountOverlay(apply: false), + onTap: () { + if (_showCurrencyDropdown) { + setState(() { + _showCurrencyDropdown = false; + }); + } else { + dash.closeAccountOverlay(apply: false); + } + }, behavior: HitTestBehavior.translucent, child: const SizedBox.expand(), ), @@ -113,11 +122,105 @@ class _AccountEditorOverlayState extends State { left: 20, right: 20, child: GestureDetector( - onTap: () {}, + onTap: () { + if (_showCurrencyDropdown) { + setState(() { + _showCurrencyDropdown = false; + }); + } + }, behavior: HitTestBehavior.opaque, child: _buildColorPanel(colorPanelHeight), ), ), + // Currency Dropdown - Above everything + if (_showCurrencyDropdown) + Positioned( + top: editorPanelTop + 58, // Position below the currency button + left: 20 + 14 + (MediaQuery.of(context).size.width - 40 - 28) * 0.75 + 8, // Align with currency button + width: (MediaQuery.of(context).size.width - 40 - 28) * 0.25, // Same width as currency button + child: Consumer( + builder: (context, ref, _) { + final exchangeService = ref.read(exchangeRateServiceProvider); + + return Material( + elevation: 12, + borderRadius: BorderRadius.circular(12), + child: Container( + decoration: BoxDecoration( + color: Theme.of(widget.context).colorScheme.surface, + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: Theme.of(widget.context).colorScheme.onSurface.withOpacity(0.15), + width: 1.5, + ), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + ('USD', '\$'), + ('EUR', '€'), + ('BYN', 'Br'), + ('RUB', '₽'), + ].map((entry) { + final isSelected = entry.$1 == _selectedCurrency; + return InkWell( + onTap: () { + final oldCurrency = _selectedCurrency; + final newCurrency = entry.$1; + + setState(() { + _selectedCurrency = newCurrency; + dash.tempAccountCurrency = newCurrency; + _showCurrencyDropdown = false; + }); + + // Note: Currency conversion will happen automatically + // when the account is saved, as the exchangeRateServiceProvider + // will handle the conversion in the balance calculations + }, + borderRadius: BorderRadius.circular(12), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + entry.$2, + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + color: isSelected ? const Color(0xFF7C6DED) : null, + ), + ), + const SizedBox(width: 6), + Text( + entry.$1, + style: TextStyle( + fontSize: 11, + color: isSelected + ? const Color(0xFF7C6DED) + : Theme.of(widget.context).colorScheme.onSurface.withOpacity(0.6), + ), + ), + const SizedBox(width: 4), + if (isSelected) + const Icon( + Icons.check_rounded, + size: 14, + color: Color(0xFF7C6DED), + ), + ], + ), + ), + ); + }).toList(), + ), + ), + ); + }, + ), + ), // Close Button - Top Right Positioned( top: mq.padding.top + 8, @@ -154,13 +257,6 @@ class _AccountEditorOverlayState extends State { } Widget _buildEditorPanel(double panelHeight) { - final currencies = [ - ('USD', '\$'), - ('EUR', '€'), - ('BYN', 'Br'), - ('RUB', '₽'), - ]; - return Container( height: panelHeight, decoration: BoxDecoration( @@ -179,100 +275,101 @@ class _AccountEditorOverlayState extends State { ], ), child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), + padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text( - 'Account Name', + 'Account Settings', style: TextStyle( fontSize: 11, fontWeight: FontWeight.w600, color: Theme.of(widget.context).colorScheme.onSurface.withOpacity(0.6), ), ), - const SizedBox(height: 6), - TextField( - controller: _nameController, - maxLength: 17, - buildCounter: (context, {required currentLength, required isFocused, maxLength}) => null, - decoration: InputDecoration( - hintText: 'Enter account name', - filled: true, - fillColor: Theme.of(widget.context).colorScheme.onSurface.withOpacity(0.05), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: BorderSide.none, - ), - contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), - ), - ), - const SizedBox(height: 12), - Text( - 'Currency', - style: TextStyle( - fontSize: 11, - fontWeight: FontWeight.w600, - color: Theme.of(widget.context).colorScheme.onSurface.withOpacity(0.6), - ), - ), - const SizedBox(height: 6), + const SizedBox(height: 8), Row( - children: currencies.map((c) { - final isSelected = c.$1 == _selectedCurrency; - return Expanded( - child: GestureDetector( - onTap: () { - setState(() { - _selectedCurrency = c.$1; - dash.tempAccountCurrency = c.$1; - }); - }, - child: Container( - margin: EdgeInsets.only( - right: c.$1 == currencies.last.$1 ? 0 : 8, - ), - padding: const EdgeInsets.symmetric(vertical: 8), - decoration: BoxDecoration( - color: isSelected - ? const Color(0xFF7C6DED).withOpacity(0.15) - : Theme.of(widget.context).colorScheme.onSurface.withOpacity(0.05), - borderRadius: BorderRadius.circular(10), - border: Border.all( - color: isSelected - ? const Color(0xFF7C6DED) - : Colors.transparent, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + flex: 3, + child: TextField( + controller: _nameController, + maxLength: 17, + buildCounter: (context, {required currentLength, required isFocused, maxLength}) => null, + style: const TextStyle(fontSize: 13), + decoration: InputDecoration( + hintText: 'Account name', + hintStyle: TextStyle(fontSize: 13, color: Theme.of(widget.context).colorScheme.onSurface.withOpacity(0.4)), + filled: true, + fillColor: Theme.of(widget.context).colorScheme.onSurface.withOpacity(0.05), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide( + color: Theme.of(widget.context).colorScheme.onSurface.withOpacity(0.15), width: 1.5, ), ), - child: Column( - mainAxisSize: MainAxisSize.min, + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide( + color: Theme.of(widget.context).colorScheme.onSurface.withOpacity(0.15), + width: 1.5, + ), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: const BorderSide( + color: Color(0xFF7C6DED), + width: 1.5, + ), + ), + contentPadding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10), + ), + ), + ), + const SizedBox(width: 8), + Expanded( + child: GestureDetector( + onTap: () { + setState(() { + _showCurrencyDropdown = !_showCurrencyDropdown; + }); + }, + child: Container( + height: 44, // Increased to match TextField height + decoration: BoxDecoration( + color: Theme.of(widget.context).colorScheme.onSurface.withOpacity(0.05), + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: _showCurrencyDropdown + ? const Color(0xFF7C6DED) + : Theme.of(widget.context).colorScheme.onSurface.withOpacity(0.15), + width: 1.5, + ), + ), + padding: const EdgeInsets.symmetric(horizontal: 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, children: [ Text( - c.$2, - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: isSelected - ? const Color(0xFF7C6DED) - : Theme.of(widget.context).colorScheme.onSurface, - ), + [('USD', '\$'), ('EUR', '€'), ('BYN', 'Br'), ('RUB', '₽')] + .firstWhere((c) => c.$1 == _selectedCurrency).$2, + style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600), ), - const SizedBox(height: 2), - Text( - c.$1, - style: TextStyle( - fontSize: 9, - color: Theme.of(widget.context).colorScheme.onSurface.withOpacity(0.5), - ), + const SizedBox(width: 4), + Icon( + _showCurrencyDropdown ? Icons.arrow_drop_up : Icons.arrow_drop_down, + size: 20, + color: Theme.of(widget.context).colorScheme.onSurface.withOpacity(0.6), ), ], ), ), ), - ); - }).toList(), + ), + ], ), ], ), diff --git a/lib/features/dashboard/widgets/color_editor_overlay.dart b/lib/features/dashboard/widgets/color_editor_overlay.dart index f975926..7300086 100644 --- a/lib/features/dashboard/widgets/color_editor_overlay.dart +++ b/lib/features/dashboard/widgets/color_editor_overlay.dart @@ -81,6 +81,36 @@ class _FullScreenBlurOverlayState extends State { child: _buildPanel(panelHeight), ), ), + // Close Button - Top Right + Positioned( + top: mq.padding.top + 8, + right: 20, + child: SafeArea( + child: GestureDetector( + onTap: () => dash.closeOverlay(apply: false), + child: Container( + width: 40, + height: 40, + decoration: BoxDecoration( + color: Theme.of(widget.context).colorScheme.surface, + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.3), + blurRadius: 8, + offset: const Offset(0, 2), + ), + ], + ), + child: Icon( + Icons.close_rounded, + size: 24, + color: Theme.of(widget.context).colorScheme.onSurface, + ), + ), + ), + ), + ), ], ), ); @@ -135,112 +165,102 @@ class _FullScreenBlurOverlayState extends State { mainAxisSize: MainAxisSize.max, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( - children: [ - Expanded( - child: PanelTab( - label: s.colorPrimary, - isSelected: dash.editingPrimary, - color: dash.tempPrimary, - isDimmed: isSolid, - onTap: () { + IntrinsicHeight( + child: Row( + children: [ + Expanded( + child: PanelTab( + label: s.colorPrimary, + isSelected: dash.editingPrimary, + color: dash.tempPrimary, + isDimmed: isSolid, + onTap: () { + dash.setState(() { + if (isSolid) dash.tempGradientType = CardColorService.defaultGradient; + dash.editingPrimary = true; + }); + setPanelState(() {}); + dash.overlayEntry?.markNeedsBuild(); + }, + ), + ), + const SizedBox(width: 6), + Expanded( + child: PanelTab( + label: s.colorSecondary, + isSelected: !dash.editingPrimary, + color: dash.tempSecondary, + isDimmed: isSolid, + onTap: () { + dash.setState(() { + if (isSolid) dash.tempGradientType = CardColorService.defaultGradient; + dash.editingPrimary = false; + }); + setPanelState(() {}); + dash.overlayEntry?.markNeedsBuild(); + }, + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: Container( + width: 1, + color: Theme.of(widget.context) + .colorScheme + .onSurface + .withOpacity(0.15), + margin: const EdgeInsets.symmetric(vertical: 4), + ), + ), + GestureDetector( + onTap: isSolid ? null : () { dash.setState(() { - if (isSolid) dash.tempGradientType = CardColorService.defaultGradient; + dash.tempGradientType = GradientType.solid; dash.editingPrimary = true; }); setPanelState(() {}); dash.overlayEntry?.markNeedsBuild(); }, - ), - ), - const SizedBox(width: 6), - Expanded( - child: PanelTab( - label: s.colorSecondary, - isSelected: !dash.editingPrimary, - color: dash.tempSecondary, - isDimmed: isSolid, - onTap: () { - dash.setState(() { - if (isSolid) dash.tempGradientType = CardColorService.defaultGradient; - dash.editingPrimary = false; - }); - setPanelState(() {}); - dash.overlayEntry?.markNeedsBuild(); - }, - ), - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8), - child: Container( - width: 1, - height: 20, - color: Theme.of(widget.context) - .colorScheme - .onSurface - .withOpacity(0.15), - ), - ), - GestureDetector( - onTap: isSolid ? null : () { - dash.setState(() { - dash.tempGradientType = GradientType.solid; - dash.editingPrimary = true; - }); - setPanelState(() {}); - dash.overlayEntry?.markNeedsBuild(); - }, - child: AnimatedContainer( - duration: const Duration(milliseconds: 150), - padding: const EdgeInsets.symmetric( - horizontal: 10, vertical: 6), - decoration: BoxDecoration( - color: isSolid - ? const Color(0xFF7C6DED).withOpacity(0.15) - : Colors.transparent, - borderRadius: BorderRadius.circular(10), - border: Border.all( + child: Container( + height: double.infinity, + padding: const EdgeInsets.symmetric( + horizontal: 10, vertical: 6), + decoration: BoxDecoration( color: isSolid - ? const Color(0xFF7C6DED) - : Theme.of(widget.context) - .colorScheme - .onSurface - .withOpacity(0.2), - width: 1.5, + ? const Color(0xFF7C6DED).withOpacity(0.15) + : Colors.transparent, + borderRadius: BorderRadius.circular(10), + border: Border.all( + color: isSolid + ? const Color(0xFF7C6DED) + : Theme.of(widget.context) + .colorScheme + .onSurface + .withOpacity(0.2), + width: 1.5, + ), ), - ), - child: Text( - s.colorSolid, - style: TextStyle( - fontSize: 11, - fontWeight: isSolid - ? FontWeight.w600 - : FontWeight.normal, - color: isSolid - ? const Color(0xFF7C6DED) - : Theme.of(widget.context) - .colorScheme - .onSurface - .withOpacity(0.5), + child: Center( + child: Text( + s.colorSolid, + style: TextStyle( + fontSize: 11, + fontWeight: isSolid + ? FontWeight.w600 + : FontWeight.normal, + color: isSolid + ? const Color(0xFF7C6DED) + : Theme.of(widget.context) + .colorScheme + .onSurface + .withOpacity(0.5), + ), + ), ), ), ), - ), - const SizedBox(width: 8), - GestureDetector( - onTap: () => dash.closeOverlay(apply: false), - child: Container( - width: 30, - height: 30, - decoration: BoxDecoration( - color: const Color(0xFFE05C6B).withOpacity(0.15), - shape: BoxShape.circle, - ), - child: const Icon(Icons.close_rounded, - size: 16, color: Color(0xFFE05C6B)), - ), - ), - ], + ], + ), ), const SizedBox(height: 10), Expanded(