import 'package:flutter/material.dart'; import 'dart:html' as html; import '../models/tab_data.dart'; import '../services/browser_api_service.dart'; import '../services/extension_service.dart'; import '../widgets/item_card.dart'; import '../widgets/item_list_tile.dart'; import '../widgets/search_bar.dart' as custom; import '../widgets/filter_chips.dart'; import '../widgets/app_bar_actions.dart'; // StatefulWidget class TabManagerHome extends StatefulWidget { const TabManagerHome({super.key}); @override State createState() => _TabManagerHomeState(); } class _TabManagerHomeState extends State { // State variables List allItems = []; List filteredItems = []; final TextEditingController searchController = TextEditingController(); bool isGridView = true; String sortBy = 'recent'; String filterType = 'all'; bool isLoading = true; bool extensionConnected = false; bool extensionMode = false; // Services final BrowserApiService _browserApi = BrowserApiService(); final ExtensionService _extensionService = ExtensionService(); @override void initState() { super.initState(); _setupExtensionService(); _loadAllData(); searchController.addListener(_filterItems); } @override void dispose() { searchController.dispose(); super.dispose(); } void _setupExtensionService() { _extensionService.onTabsUpdate = (tabs) { setState(() { allItems = tabs; extensionConnected = true; extensionMode = true; _filterItems(); }); }; _extensionService.onTrackingStart = () { setState(() { extensionMode = true; extensionConnected = true; }); }; _extensionService.onTrackingStop = () { setState(() { extensionMode = false; _loadAllData(); }); }; _extensionService.setupListener(); } void _startExtensionTracking() { _extensionService.startTracking(); setState(() { extensionMode = true; allItems.clear(); }); } void _stopExtensionTracking() { _extensionService.stopTracking(); setState(() { extensionMode = false; }); _loadAllData(); } Future _loadAllData() async { if (extensionMode) return; setState(() { isLoading = true; }); try { final tabs = await _browserApi.getTabs(); final bookmarks = await _browserApi.getBookmarks(); final history = await _browserApi.getHistory(); setState(() { allItems = [...tabs, ...bookmarks, ...history]; _filterItems(); isLoading = false; }); _checkExtensionConnection(); } catch (e) { print('Error loading data: $e'); setState(() { isLoading = false; }); } } void _checkExtensionConnection() { _extensionService.getStatus(); Future.delayed(const Duration(milliseconds: 500), () { if (mounted) { setState(() {}); } }); } void _filterItems() { final query = searchController.text.toLowerCase(); setState(() { filteredItems = allItems.where((item) { if (filterType != 'all' && item.type != filterType.replaceAll('s', '')) { return false; } if (query.isNotEmpty) { return item.title.toLowerCase().contains(query) || item.url.toLowerCase().contains(query); } return true; }).toList(); _sortItems(); }); } void _sortItems() { switch (sortBy) { case 'recent': filteredItems.sort((a, b) => b.lastAccessed.compareTo(a.lastAccessed)); break; case 'title': filteredItems.sort((a, b) => a.title.compareTo(b.title)); break; case 'url': filteredItems.sort((a, b) => a.url.compareTo(b.url)); break; case 'visits': filteredItems.sort((a, b) => (b.visitCount ?? 0).compareTo(a.visitCount ?? 0)); break; } filteredItems.sort((a, b) => b.isPinned ? 1 : (a.isPinned ? -1 : 0)); } Future _openItem(TabData item) async { print('🔥 DEBUG: _openItem called with item: ${item.title}'); print('🔥 DEBUG: Extension mode: $extensionMode'); print('🔥 DEBUG: Item type: ${item.type}'); print('🔥 DEBUG: Item URL: ${item.url}'); if (extensionMode) { print('🔥 DEBUG: Opening in new tab via html.window.open'); html.window.open(item.url, '_blank'); } else { if (item.type == 'tab') { print('🔥 DEBUG: Switching to existing tab with ID: ${item.id}'); await _browserApi.switchToTab(item.id); } else { print('🔥 DEBUG: Opening new tab for bookmark/history'); await _browserApi.openTab(item.url); } } print('🔥 DEBUG: _openItem completed'); } Future _deleteItem(TabData item) async { if (extensionMode) return; if (item.type == 'tab') { await _browserApi.closeTab(item.id); } else if (item.type == 'bookmark') { await _browserApi.removeBookmark(item.id); } await _loadAllData(); } Future _togglePin(TabData item) async { if (extensionMode) return; if (item.type == 'tab') { await _browserApi.togglePinTab(item.id, !item.isPinned); await _loadAllData(); } } String _getIcon(TabData item) { if (item.favicon.isNotEmpty && !item.favicon.contains('data:')) { return '🌐'; } switch (item.type) { case 'tab': return '🔖'; case 'bookmark': return '⭐'; case 'history': return '🕒'; default: return '🌐'; } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Row( children: [ const Text('Browser Tab Manager'), if (extensionMode) ...[ const SizedBox(width: 12), Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: Colors.green, borderRadius: BorderRadius.circular(12), ), child: const Text( 'TRACKING', style: TextStyle(fontSize: 10, color: Colors.white), ), ), ], ], ), actions: [ AppBarActions( extensionMode: extensionMode, extensionConnected: extensionConnected, isGridView: isGridView, sortBy: sortBy, onStartTracking: _startExtensionTracking, onStopTracking: _stopExtensionTracking, onRefresh: _loadAllData, onToggleView: () { setState(() { isGridView = !isGridView; }); }, onSortChanged: (value) { setState(() { sortBy = value; _filterItems(); }); }, ), ], ), body: Column( children: [ Padding( padding: const EdgeInsets.all(16.0), child: Column( children: [ custom.SearchBar( controller: searchController, extensionMode: extensionMode, onClear: () { searchController.clear(); }, ), const SizedBox(height: 12), if (!extensionMode) FilterChips( allItems: allItems, filterType: filterType, onFilterChanged: (type) { setState(() { filterType = type; _filterItems(); }); }, ), ], ), ), Expanded( child: isLoading ? const Center(child: CircularProgressIndicator()) : filteredItems.isEmpty ? Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( extensionMode ? Icons.track_changes : Icons.search_off, size: 80, color: Theme.of(context) .colorScheme .primary .withOpacity(0.3), ), const SizedBox(height: 16), Text( extensionMode ? 'Waiting for tabs...' : 'No items found', style: Theme.of(context).textTheme.titleLarge, ), const SizedBox(height: 8), Text( extensionMode ? 'Open some tabs to see them here' : 'Try a different search or filter', style: Theme.of(context).textTheme.bodyMedium, ), ], ), ) : isGridView ? GridView.builder( padding: const EdgeInsets.all(16), gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 300, childAspectRatio: 1.3, crossAxisSpacing: 16, mainAxisSpacing: 16, ), itemCount: filteredItems.length, itemBuilder: (context, index) { return ItemCard( item: filteredItems[index], icon: _getIcon(filteredItems[index]), onTap: () => _openItem(filteredItems[index]), onDelete: () => _deleteItem(filteredItems[index]), onTogglePin: () => _togglePin(filteredItems[index]), extensionMode: extensionMode, ); }, ) : ListView.builder( padding: const EdgeInsets.all(16), itemCount: filteredItems.length, itemBuilder: (context, index) { return ItemListTile( item: filteredItems[index], icon: _getIcon(filteredItems[index]), onTap: () => _openItem(filteredItems[index]), onDelete: () => _deleteItem(filteredItems[index]), onTogglePin: () => _togglePin(filteredItems[index]), extensionMode: extensionMode, ); }, ), ), ], ), ); } } // This is the main screen of our app where users see and manage their browser tabs. // // It is a StatefulWidget which means it holds data that can change over time. // // The state includes lists of tabs, search text, view preferences, and loading status. // // It communicates with two services: BrowserApiService for browser data and ExtensionService for real-time tracking. // // When the screen loads, it fetches all tabs, bookmarks, and history from the browser. // // Users can search items, filter by type, sort by different criteria, and switch between grid and list views. // // Extension mode allows real-time tracking of browser tabs as they open and close. // // The build method creates the UI with an app bar, search box, filters, and either a grid or list of items. // // User actions like opening, deleting, or pinning items trigger methods that update the browser and refresh the display. // // This is the central hub that coordinates all the app functionality and user interactions.