diff --git a/lib/features/dashboard/widgets/account_editor_overlay/account_editor_overlay.dart b/lib/features/dashboard/widgets/account_editor_overlay/account_editor_overlay.dart index 3d84a4b..222920d 100644 --- a/lib/features/dashboard/widgets/account_editor_overlay/account_editor_overlay.dart +++ b/lib/features/dashboard/widgets/account_editor_overlay/account_editor_overlay.dart @@ -87,15 +87,15 @@ class _AccountEditorOverlayState extends State { final mq = MediaQuery.of(widget.context); final layout = CardOverlayLayout.fromMediaQuery(mq); final cardTop = layout.cardTop; - final cardHeight = layout.cardHeight; final editorPanelHeight = layout.editorPanelHeight; - final editorPanelTop = cardTop + cardHeight + layout.sectionGap; - final colorPanelTop = editorPanelTop + editorPanelHeight + layout.sectionGap; - final colorPanelHeight = layout.colorPanelHeight(mq, colorPanelTop); return Consumer( builder: (context, ref, _) { final exchangeService = ref.watch(exchangeRateServiceProvider); + final cardHeight = ref.watch(cardHeightProvider); + final editorPanelTop = cardTop + cardHeight + layout.sectionGap; + final colorPanelTop = editorPanelTop + editorPanelHeight + layout.sectionGap; + final colorPanelHeight = layout.colorPanelHeight(mq, colorPanelTop); double previewBalance = 0.0; if (!dash.isAddingAccount) { @@ -220,11 +220,38 @@ class _AccountEditorOverlayState extends State { Brightness.dark ? dash.tempDarkGradientType : dash.tempLightGradientType, + cardHeight: cardHeight, ), ), ), ), ), + Positioned( + top: cardTop - 28, + left: 0, + right: 0, + child: Center( + child: _HeightHandle( + onDrag: (delta) { + final newHeight = cardHeight - delta * 2; + ref.read(cardHeightProvider.notifier).set(newHeight); + }, + ), + ), + ), + Positioned( + top: cardTop + cardHeight + 6, + left: 0, + right: 0, + child: Center( + child: _HeightHandle( + onDrag: (delta) { + final newHeight = cardHeight + delta * 2; + ref.read(cardHeightProvider.notifier).set(newHeight); + }, + ), + ), + ), Positioned( top: editorPanelTop, left: 20, @@ -468,3 +495,36 @@ class _AccountEditorOverlayState extends State { ); } } + +class _HeightHandle extends StatefulWidget { + final ValueChanged onDrag; + + const _HeightHandle({required this.onDrag}); + + @override + State<_HeightHandle> createState() => _HeightHandleState(); +} + +class _HeightHandleState extends State<_HeightHandle> { + bool _active = false; + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + return GestureDetector( + onVerticalDragStart: (_) => setState(() => _active = true), + onVerticalDragUpdate: (details) => widget.onDrag(details.delta.dy), + onVerticalDragEnd: (_) => setState(() => _active = false), + behavior: HitTestBehavior.opaque, + child: AnimatedContainer( + duration: const Duration(milliseconds: 150), + width: _active ? 56 : 44, + height: _active ? 6 : 4, + decoration: BoxDecoration( + color: theme.colorScheme.onSurface.withOpacity(_active ? 0.5 : 0.25), + borderRadius: BorderRadius.circular(3), + ), + ), + ); + } +} diff --git a/lib/features/dashboard/widgets/balance_card.dart b/lib/features/dashboard/widgets/balance_card.dart index b6f7be9..d495523 100644 --- a/lib/features/dashboard/widgets/balance_card.dart +++ b/lib/features/dashboard/widgets/balance_card.dart @@ -37,6 +37,7 @@ class BalanceCard extends ConsumerStatefulWidget { final GradientType? previewGradientType; final String? accountName; final CardColors? accountColors; + final double? cardHeight; const BalanceCard({ super.key, @@ -48,6 +49,7 @@ class BalanceCard extends ConsumerStatefulWidget { this.previewGradientType, this.accountName, this.accountColors, + this.cardHeight, }); @override @@ -132,7 +134,7 @@ class BalanceCardState extends ConsumerState ..rotateY(_tiltY * 0.42), child: Container( width: double.infinity, - height: kBalanceCardHeight, + height: widget.cardHeight ?? kBalanceCardHeight, decoration: BoxDecoration( borderRadius: BorderRadius.circular(20), gradient: buildCardGradient(primary, secondary, gradientType), diff --git a/lib/features/dashboard/widgets/balance_card_carousel.dart b/lib/features/dashboard/widgets/balance_card_carousel.dart index 4e6b16a..a6cdf45 100644 --- a/lib/features/dashboard/widgets/balance_card_carousel.dart +++ b/lib/features/dashboard/widgets/balance_card_carousel.dart @@ -59,6 +59,7 @@ class _BalanceCardCarouselState extends ConsumerState { Widget build(BuildContext context) { final accountsAsync = ref.watch(accountsProvider); final activeIndex = ref.watch(activeAccountIndexProvider); + final cardHeight = ref.watch(cardHeightProvider); return accountsAsync.when( data: (accounts) { @@ -67,7 +68,7 @@ class _BalanceCardCarouselState extends ConsumerState { return Column( children: [ SizedBox( - height: kBalanceCardCarouselHeight, + height: cardHeight + 10, child: OverflowBox( maxWidth: MediaQuery.of(context).size.width, child: PageView.builder( @@ -96,6 +97,7 @@ class _BalanceCardCarouselState extends ConsumerState { previewPrimary: widget.previewPrimary, previewSecondary: widget.previewSecondary, previewGradientType: widget.previewGradientType, + cardHeight: cardHeight, ); } else if (index <= accounts.length) { final account = accounts[index - 1]; @@ -134,10 +136,12 @@ class _BalanceCardCarouselState extends ConsumerState { widget.onAccountLongPress?.call(account), accountName: account.name, accountColors: accountColors, + cardHeight: cardHeight, ); } else { cardWidget = AddAccountCard( onTap: widget.onAddAccountTap, + cardHeight: cardHeight, ); } @@ -154,15 +158,15 @@ class _BalanceCardCarouselState extends ConsumerState { ], ); }, - loading: () => const SizedBox( - height: kBalanceCardCarouselHeight, - child: Center(child: CircularProgressIndicator()), + loading: () => SizedBox( + height: cardHeight + 10, + child: const Center(child: CircularProgressIndicator()), ), error: (error, stack) { return Column( children: [ SizedBox( - height: kBalanceCardCarouselHeight, + height: cardHeight + 10, child: BalanceCard( balance: widget.balance, currencyInfo: widget.currencyInfo, @@ -170,6 +174,7 @@ class _BalanceCardCarouselState extends ConsumerState { previewPrimary: widget.previewPrimary, previewSecondary: widget.previewSecondary, previewGradientType: widget.previewGradientType, + cardHeight: cardHeight, ), ), const SizedBox(height: 12), @@ -183,8 +188,9 @@ class _BalanceCardCarouselState extends ConsumerState { class AddAccountCard extends StatelessWidget { final VoidCallback? onTap; + final double? cardHeight; - const AddAccountCard({super.key, this.onTap}); + const AddAccountCard({super.key, this.onTap, this.cardHeight}); @override Widget build(BuildContext context) { @@ -199,7 +205,7 @@ class AddAccountCard extends StatelessWidget { painter: _DashedBorderPainter(), child: Container( width: double.infinity, - height: kAddAccountCardHeight, + height: cardHeight ?? kAddAccountCardHeight, decoration: BoxDecoration( color: Theme.of(context).colorScheme.surface.withOpacity(0.4), borderRadius: BorderRadius.circular(20), diff --git a/lib/features/dashboard/widgets/color_editor_overlay.dart b/lib/features/dashboard/widgets/color_editor_overlay.dart index 4b764be..f85c81f 100644 --- a/lib/features/dashboard/widgets/color_editor_overlay.dart +++ b/lib/features/dashboard/widgets/color_editor_overlay.dart @@ -37,9 +37,12 @@ class _FullScreenBlurOverlayState extends State { final mq = MediaQuery.of(widget.context); final layout = CardOverlayLayout.fromMediaQuery(mq); final cardTop = layout.cardTop; - final cardHeight = layout.cardHeight; - final panelTop = cardTop + cardHeight + layout.cardPreviewGap; - final panelHeight = layout.colorPanelHeight(mq, panelTop); + + return Consumer( + builder: (context, ref, _) { + final cardHeight = ref.watch(cardHeightProvider); + final panelTop = cardTop + cardHeight + layout.cardPreviewGap; + final panelHeight = layout.colorPanelHeight(mq, panelTop); return Material( color: Colors.transparent, @@ -80,6 +83,7 @@ class _FullScreenBlurOverlayState extends State { Theme.of(widget.context).brightness == Brightness.dark ? dash.tempDarkGradientType : dash.tempLightGradientType, + cardHeight: cardHeight, ), ), ), @@ -132,6 +136,8 @@ class _FullScreenBlurOverlayState extends State { ], ), ); + }, + ); } Widget _buildPanel(double panelHeight, CardOverlayLayout layout) { diff --git a/lib/features/settings/provider.dart b/lib/features/settings/provider.dart index 82260f3..e2d7c83 100644 --- a/lib/features/settings/provider.dart +++ b/lib/features/settings/provider.dart @@ -103,6 +103,31 @@ final exchangeRateServiceProvider = Provider((ref) { return ExchangeRateService(prefs); }); +final cardHeightProvider = NotifierProvider( + CardHeightNotifier.new, +); + +class CardHeightNotifier extends Notifier { + static const _key = 'card_height'; + static const _minHeight = 160.0; + static const _maxHeight = 280.0; + static const _defaultHeight = 200.0; + + @override + double build() { + final prefs = ref.watch(sharedPreferencesProvider); + final saved = prefs.getDouble(_key); + if (saved == null) return _defaultHeight; + return saved.clamp(_minHeight, _maxHeight); + } + + void set(double height) { + final clamped = height.clamp(_minHeight, _maxHeight); + state = clamped; + ref.read(sharedPreferencesProvider).setDouble(_key, clamped); + } +} + final ratesInitProvider = FutureProvider((ref) async { await ref.read(exchangeRateServiceProvider).fetchRates(); });