creek

The AI Image Editor of 2030

top_bar.dart (15046B)


import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:creekui/data/models/project_model.dart';
import 'package:creekui/data/repos/project_repo.dart';
import 'package:creekui/ui/styles/variables.dart';
import 'package:creekui/ui/pages/settings_page.dart';
import 'package:creekui/ui/pages/home_page.dart';

class TopBar extends StatefulWidget implements PreferredSizeWidget {
  final int currentProjectId;
  final VoidCallback? onBack;
  final Function(ProjectModel)? onProjectChanged;
  final VoidCallback? onSettingsPressed;
  final String? titleOverride;
  final VoidCallback? onLayoutPressed;
  final VoidCallback? onFilterPressed;
  final VoidCallback? onAIPressed;
  final bool? isAlternateView;
  final VoidCallback? onLayoutToggle;
  final bool hideSecondRow;
  final bool hideSelector;
  final bool showSettings;

  const TopBar({
    super.key,
    required this.currentProjectId,
    this.onBack,
    this.onProjectChanged,
    this.onSettingsPressed,
    this.titleOverride,
    this.onLayoutPressed,
    this.onFilterPressed,
    this.onAIPressed,
    this.isAlternateView,
    this.onLayoutToggle,
    this.hideSecondRow = false,
    this.hideSelector = false,
    this.showSettings = true,
  });

  @override
  State<TopBar> createState() => _TopBarState();

  @override
  Size get preferredSize =>
      hideSecondRow ? const Size.fromHeight(48.0) : const Size.fromHeight(88.0);
}

class _TopBarState extends State<TopBar> {
  final ProjectRepo _projectRepo = ProjectRepo();

  bool _isLoading = true;
  ProjectModel? _currentProject;
  ProjectModel? _rootProject;
  List<ProjectModel> _contextList = [];

  @override
  void initState() {
    super.initState();
    _loadData();
  }

  @override
  void didUpdateWidget(covariant TopBar oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.currentProjectId != widget.currentProjectId) {
      _loadData();
    }
  }

  Future<void> _loadData() async {
    try {
      final current = await _projectRepo.getProjectById(
        widget.currentProjectId,
      );
      if (current == null) {
        if (mounted) setState(() => _isLoading = false);
        return;
      }

      ProjectModel? root;
      List<ProjectModel> events = [];

      if (current.parentId == null) {
        root = current;
        events = await _projectRepo.getEvents(current.id!);
      } else {
        root = await _projectRepo.getProjectById(current.parentId!);
        if (root != null) {
          events = await _projectRepo.getEvents(root.id!);
        }
      }
      root ??= current;
      final List<ProjectModel> fullList = [root, ...events];
      if (mounted) {
        setState(() {
          _currentProject = current;
          _rootProject = root;
          _contextList = fullList;
          _isLoading = false;
        });
      }
    } catch (e) {
      debugPrint("TopBar Error: $e");
      if (mounted) setState(() => _isLoading = false);
    }
  }

  void _handleSafeBack() {
    if (widget.onBack != null) {
      widget.onBack!();
      return;
    }

    if (Navigator.canPop(context)) {
      Navigator.pop(context);
    } else {
      // Fallback: Go to HomePage to prevent app exit/crash
      Navigator.pushReplacement(
        context,
        MaterialPageRoute(builder: (_) => const HomePage()),
      );
    }
  }

  void _openSettings() {
    if (widget.onSettingsPressed != null) {
      widget.onSettingsPressed!();
    } else {
      Navigator.push(
        context,
        MaterialPageRoute(builder: (_) => const SettingsPage()),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.white,
      child: SafeArea(
        bottom: false,
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            // Row 1: Title and Settings
            Container(
              height: 48.0,
              padding: const EdgeInsets.symmetric(horizontal: 16.0),
              child: Row(
                children: [
                  // Back Button
                  GestureDetector(
                    onTap: _handleSafeBack,
                    behavior: HitTestBehavior.opaque,
                    child: Container(
                      width: 24,
                      height: 24,
                      alignment: Alignment.center,
                      child: const Icon(
                        Icons.arrow_back,
                        size: 20,
                        color: Variables.textPrimary,
                      ),
                    ),
                  ),
                  const SizedBox(width: 10),

                  // Title
                  Expanded(
                    child:
                        widget.titleOverride != null
                            ? Text(
                              widget.titleOverride!,
                              style: Variables.headerStyle.copyWith(
                                fontSize: 20,
                                height: 24 / 20,
                              ),
                              overflow: TextOverflow.ellipsis,
                            )
                            : (!_isLoading &&
                                _currentProject != null &&
                                _rootProject != null)
                            ? Text(
                              _rootProject!.title,
                              style: Variables.headerStyle.copyWith(
                                fontSize: 20,
                                height: 24 / 20,
                              ),
                              overflow: TextOverflow.ellipsis,
                            )
                            : const SizedBox(),
                  ),

                  // Settings Icon
                  if (widget.showSettings)
                    Material(
                      color: Colors.transparent,
                      child: InkWell(
                        onTap: _openSettings,
                        borderRadius: BorderRadius.circular(24),
                        child: Container(
                          width: 48,
                          height: 48,
                          alignment: Alignment.center,
                          child: SvgPicture.asset(
                            'assets/icons/settings-line.svg',
                            width: 24,
                            height: 24,
                            colorFilter: const ColorFilter.mode(
                              Variables.textPrimary,
                              BlendMode.srcIn,
                            ),
                          ),
                        ),
                      ),
                    ),
                ],
              ),
            ),
            // Row 2: Global Dropdown and Action Buttons
            if (!widget.hideSecondRow)
              Container(
                height: 40.0,
                padding: const EdgeInsets.symmetric(horizontal: 16.0),
                child: Row(
                  children: [
                    // Left group: Global Dropdown and Layout Button
                    Row(
                      children: [
                        // Global Dropdown
                        if (!widget.hideSelector &&
                            !_isLoading &&
                            _currentProject != null &&
                            _rootProject != null)
                          PopupMenuButton<ProjectModel>(
                            padding: EdgeInsets.zero,
                            onSelected:
                                (project) =>
                                    widget.onProjectChanged?.call(project),
                            color: Colors.white,
                            shape: RoundedRectangleBorder(
                              borderRadius: BorderRadius.circular(8),
                            ),
                            offset: const Offset(0, 42),
                            child: Container(
                              padding: const EdgeInsets.symmetric(
                                horizontal: 16,
                                vertical: 10,
                              ),
                              decoration: BoxDecoration(
                                color: Variables.borderSubtle,
                                borderRadius: BorderRadius.circular(1000),
                              ),
                              child: Row(
                                mainAxisSize: MainAxisSize.min,
                                children: [
                                  Text(
                                    _currentProject!.id == _rootProject!.id
                                        ? "Global"
                                        : _currentProject!.title,
                                    style: const TextStyle(
                                      fontFamily: 'GeneralSans',
                                      fontSize: 14,
                                      fontWeight: FontWeight.w500,
                                      height: 20 / 14,
                                      color: Variables.textPrimary,
                                    ),
                                  ),
                                  const SizedBox(width: 8),
                                  const Icon(
                                    Icons.keyboard_arrow_down_rounded,
                                    size: 20,
                                    color: Variables.textPrimary,
                                  ),
                                ],
                              ),
                            ),
                            itemBuilder: (context) {
                              return _contextList.map((project) {
                                final isSelected =
                                    project.id == _currentProject!.id;
                                final isRoot = project.id == _rootProject!.id;
                                return PopupMenuItem<ProjectModel>(
                                  value: project,
                                  child: Text(
                                    isRoot ? "Global" : project.title,
                                    style: Variables.bodyStyle.copyWith(
                                      fontWeight:
                                          isSelected
                                              ? FontWeight.bold
                                              : FontWeight.normal,
                                      color:
                                          isSelected
                                              ? Variables.textPrimary
                                              : Variables.textSecondary,
                                    ),
                                  ),
                                );
                              }).toList();
                            },
                          ),
                        if (widget.onLayoutToggle != null ||
                            widget.onLayoutPressed != null) ...[
                          const SizedBox(width: 8),
                          GestureDetector(
                            onTap:
                                widget.onLayoutToggle ?? widget.onLayoutPressed,
                            child: Container(
                              padding: const EdgeInsets.symmetric(
                                horizontal: 16,
                                vertical: 10,
                              ),
                              decoration: BoxDecoration(
                                color: Variables.borderSubtle,
                                borderRadius: BorderRadius.circular(1000),
                              ),
                              child: Icon(
                                widget.onLayoutToggle != null
                                    ? (widget.isAlternateView == true
                                        ? Icons.dashboard
                                        : Icons.view_agenda_outlined)
                                    : Icons.edit,
                                size: 20,
                                color: Variables.textPrimary,
                              ),
                            ),
                          ),
                        ],
                      ],
                    ),
                    const Spacer(),
                    // Right group: Filter and AI Buttons
                    if (widget.onFilterPressed != null ||
                        widget.onAIPressed != null)
                      Row(
                        children: [
                          // Filter Button
                          if (widget.onFilterPressed != null)
                            GestureDetector(
                              onTap: widget.onFilterPressed,
                              child: Container(
                                padding: const EdgeInsets.symmetric(
                                  horizontal: 16,
                                  vertical: 10,
                                ),
                                decoration: BoxDecoration(
                                  color: Variables.borderSubtle,
                                  borderRadius: BorderRadius.circular(1000),
                                ),
                                child: const Icon(
                                  Icons.tune,
                                  size: 20,
                                  color: Variables.textPrimary,
                                ),
                              ),
                            ),
                          if (widget.onFilterPressed != null &&
                              widget.onAIPressed != null)
                            const SizedBox(width: 8),
                          // AI Button
                          if (widget.onAIPressed != null)
                            GestureDetector(
                              onTap: widget.onAIPressed,
                              child: Container(
                                padding: const EdgeInsets.symmetric(
                                  horizontal: 16,
                                  vertical: 10,
                                ),
                                decoration: BoxDecoration(
                                  color: Variables.borderSubtle,
                                  borderRadius: BorderRadius.circular(1000),
                                ),
                                child: const Icon(
                                  Icons.auto_awesome,
                                  size: 20,
                                  color: Variables.textPrimary,
                                ),
                              ),
                            ),
                        ],
                      ),
                  ],
                ),
              ),
          ],
        ),
      ),
    );
  }
}