creek

The AI Image Editor of 2030

lib/ui/widgets/bottom_bar.dart (3649B)


  1import 'dart:math';
  2import 'package:flutter/material.dart';
  3import 'package:flutter_svg/flutter_svg.dart';
  4import 'package:creekui/ui/styles/variables.dart';
  5import 'package:creekui/ui/pages/project_board_page.dart';
  6import 'package:creekui/ui/pages/stylesheet_page.dart';
  7import 'package:creekui/ui/pages/project_file_page.dart';
  8
  9enum BottomBarItem { moodboard, stylesheet, files }
 10
 11class BottomBar extends StatelessWidget {
 12  final BottomBarItem currentTab;
 13  final int projectId;
 14
 15  const BottomBar({
 16    super.key,
 17    required this.currentTab,
 18    required this.projectId,
 19  });
 20
 21  void _onTap(BuildContext context, BottomBarItem item) {
 22    if (item == currentTab) return;
 23
 24    Widget nextPage;
 25    switch (item) {
 26      case BottomBarItem.moodboard:
 27        nextPage = ProjectBoardPage(projectId: projectId);
 28        break;
 29      case BottomBarItem.stylesheet:
 30        nextPage = StylesheetPage(projectId: projectId);
 31        break;
 32      case BottomBarItem.files:
 33        nextPage = ProjectFilePage(projectId: projectId);
 34        break;
 35    }
 36
 37    Navigator.pushReplacement(
 38      context,
 39      PageRouteBuilder(
 40        pageBuilder: (context, anim1, anim2) => nextPage,
 41        transitionDuration: Duration.zero,
 42        reverseTransitionDuration: Duration.zero,
 43      ),
 44    );
 45  }
 46
 47  @override
 48  Widget build(BuildContext context) {
 49    // Safe Area Padding
 50    final double safeBottom = MediaQuery.of(context).padding.bottom;
 51    final double effectiveBottomPadding = max(safeBottom, 24.0);
 52
 53    return Container(
 54      decoration: const BoxDecoration(
 55        color: Variables.background,
 56        border: Border(
 57          top: BorderSide(color: Variables.borderSubtle, width: 1),
 58        ),
 59      ),
 60      padding: EdgeInsets.only(bottom: effectiveBottomPadding, top: 12),
 61      child: SizedBox(
 62        height: 54,
 63        child: Row(
 64          children: [
 65            Expanded(
 66              child: _buildNavItem(
 67                context,
 68                BottomBarItem.moodboard,
 69                "Moodboard",
 70                "assets/icons/moodboard_icon.svg",
 71              ),
 72            ),
 73            Expanded(
 74              child: _buildNavItem(
 75                context,
 76                BottomBarItem.stylesheet,
 77                "Stylesheet",
 78                "assets/icons/stylesheet_icon.svg",
 79              ),
 80            ),
 81            Expanded(
 82              child: _buildNavItem(
 83                context,
 84                BottomBarItem.files,
 85                "Files",
 86                "assets/icons/files_icon.svg",
 87              ),
 88            ),
 89          ],
 90        ),
 91      ),
 92    );
 93  }
 94
 95  Widget _buildNavItem(
 96    BuildContext context,
 97    BottomBarItem item,
 98    String label,
 99    String assetPath,
100  ) {
101    final bool isSelected = item == currentTab;
102    final Color color =
103        isSelected ? Variables.textPrimary : Variables.textDisabled;
104
105    return GestureDetector(
106      onTap: () => _onTap(context, item),
107      behavior: HitTestBehavior.opaque,
108      child: Center(
109        child: Column(
110          mainAxisAlignment: MainAxisAlignment.center,
111          children: [
112            SvgPicture.asset(
113              assetPath,
114              width: 24,
115              height: 24,
116              colorFilter: ColorFilter.mode(color, BlendMode.srcIn),
117            ),
118            const SizedBox(height: 6),
119            Text(
120              label,
121              style: Variables.captionStyle.copyWith(
122                color: color,
123                fontSize: 11,
124                fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal,
125              ),
126            ),
127          ],
128        ),
129      ),
130    );
131  }
132}