import 'package:flutter/material.dart'; import '../../app/bookmarks_controller.dart'; import '../../core/bookmarks.dart'; import '../../l10n/tr.dart'; import '../bookmark_ui.dart'; import '../theme.dart'; // ───────── 즐겨찾기 표시줄 (주소창 아래) ───────── /// 약속: 즐겨찾기 표시줄의 항목을 보이고, 누르면 [onOpen] · [onOpenExternal] · [onOpenManager] 를 부른다 (바꾸기는 [bm] 이) class BookmarkBar extends StatelessWidget { final BookmarksController bm; final void Function(String url) onOpen; final void Function(String url) onOpenExternal; final String currentUrl; final String currentTitle; final void Function({String? folderId}) onOpenManager; const BookmarkBar({ super.key, required this.bm, required this.onOpen, required this.onOpenExternal, this.currentUrl = '', this.currentTitle = '', required this.onOpenManager, }); void _menu(BuildContext context, Offset at, [BookmarkNode? n]) => showBookmarkMenu(context, bm: bm, globalPosition: at, n: n, folderId: BookmarkTree.barId, onOpen: onOpen, onOpenExternal: onOpenExternal, currentUrl: currentUrl, currentTitle: currentTitle, onOpenManager: () => onOpenManager(folderId: n != null && n.isFolder ? n.id : null)); @override Widget build(BuildContext context) { final items = bm.tree.bar.children!; // 빈 곳: 오른쪽 클릭 메뉴 (페이지 · 폴더 추가, 관리자), 다른 폴더의 즐겨찾기를 끌어다 놓으면 표시줄 맨 뒤로 return DragTarget( // 다른 폴더에서 온 것만 (표시줄 안에서는 다른 즐겨찾기 위에 놓아 순서를 바꾼다. 길게 눌렀다 떼도 맨 뒤로 가지 않게) onWillAcceptWithDetails: (d) => bm.canMoveInto(d.data.id, BookmarkTree.barId) && bm.tree.parentOf(d.data.id)?.id != BookmarkTree.barId, onAcceptWithDetails: (d) => bm.moveInto(d.data.id, BookmarkTree.barId), builder: (context, _, _) => GestureDetector( behavior: HitTestBehavior.opaque, onSecondaryTapDown: (d) => _menu(context, d.globalPosition), // 터치 화면: 길게 누르면 같은 메뉴 onLongPressStart: (d) => _menu(context, d.globalPosition), child: Container( height: 32, color: JjColors.panel, padding: const EdgeInsets.symmetric(horizontal: 6), child: items.isEmpty ? Align( alignment: Alignment.centerLeft, child: Text(tr(' ☆ 를 누르면 여기에 즐겨찾기가 추가됩니다 · 오른쪽 클릭: 폴더 추가'), style: TextStyle(fontSize: 11, color: JjColors.textDim)), ) : ListView( scrollDirection: Axis.horizontal, children: [for (final (i, n) in items.indexed) _barItem(context, n, i)], ), ), ), ); } Widget _barItem(BuildContext context, BookmarkNode n, int index) { final label = n.title.length > 24 ? '${n.title.substring(0, 23)}…' : n.title; final Widget button; if (n.isFolder) { // 폴더: 누르면 내용 (하위 폴더는 옆으로 펼침), 즐겨찾기를 끌어다 놓으면 그 안으로 button = BookmarkFolderDrop( bm: bm, folderId: n.id, child: MenuAnchor( menuChildren: _folderMenu(context, n), builder: (context, ctl, _) => TextButton.icon( onPressed: () => ctl.isOpen ? ctl.close() : ctl.open(), icon: Icon(Icons.folder, size: 15, color: JjColors.amber), label: Text(label, style: const TextStyle(fontSize: 12)), ), ), ); } else { // 주소: 다른 즐겨찾기를 이 위에 놓으면 그 자리 (앞) 로 옮긴다 button = DragTarget( onWillAcceptWithDetails: (d) => d.data.id != n.id && bm.canMoveInto(d.data.id, BookmarkTree.barId), onAcceptWithDetails: (d) => bm.move(d.data.id, BookmarkTree.barId, index), builder: (context, cand, _) => Container( decoration: BoxDecoration( border: Border(left: BorderSide(color: cand.isNotEmpty ? JjColors.accent : Colors.transparent, width: 2)), ), child: Tooltip( message: '${n.title}\n${n.url}', waitDuration: const Duration(milliseconds: 600), // 길게 누르기는 메뉴에 (마우스를 올리면 주소) triggerMode: TooltipTriggerMode.manual, child: TextButton.icon( onPressed: () => onOpen(n.url!), icon: const Icon(Icons.public, size: 14), label: Text(label, style: const TextStyle(fontSize: 12)), ), ), ), ); } return GestureDetector( onSecondaryTapDown: (d) => _menu(context, d.globalPosition, n), // 길게 누르기 (터치 화면): 움직이지 않고 떼면 메뉴, 끌면 옮기기 (BookmarkDraggable) child: BookmarkDraggable(n: n, onMenu: (at) => _menu(context, at, n), child: button), ); } List _folderMenu(BuildContext context, BookmarkNode f) => [ if (f.children!.isEmpty) MenuItemButton(child: Text(tr('(비어 있음)'))), for (final c in f.children!) c.isFolder ? SubmenuButton( leadingIcon: Icon(Icons.folder, size: 16, color: JjColors.amber), menuChildren: _folderMenu(context, c), child: Text(c.title), ) : MenuItemButton( leadingIcon: const Icon(Icons.public, size: 16), onPressed: () => onOpen(c.url!), child: Text(c.title), ), const Divider(height: 8), MenuItemButton( leadingIcon: const Icon(Icons.bookmark_add_outlined, size: 16), onPressed: currentUrl.startsWith('http') ? () => bm.addLink(currentTitle.isEmpty ? currentUrl : currentTitle, currentUrl, parentId: f.id) : null, child: Text(tr('이 폴더에 현재 페이지 추가')), ), MenuItemButton( leadingIcon: const Icon(Icons.create_new_folder_outlined, size: 16), onPressed: () => showNewFolderDialog(context, bm, f.id), child: Text(tr('이 폴더에 새 폴더')), ), MenuItemButton( leadingIcon: const Icon(Icons.edit_outlined, size: 16), onPressed: () => showBookmarkEditor(context, bm, f), child: Text(tr('폴더 이름 바꾸기 · 이동')), ), MenuItemButton( leadingIcon: const Icon(Icons.bookmarks_outlined, size: 16), onPressed: () => onOpenManager(folderId: f.id), child: Text(tr('즐겨찾기 관리자에서 보기')), ), ]; }