import 'package:flutter/material.dart'; import 'dart:html' as html; import 'dart:convert'; import 'dart:js_util' as js_util; void main() { runApp(const BrowserTabManagerApp()); // ☝️ STATEMENT: Command that starts the app } class BrowserTabManagerApp extends StatelessWidget { // This is a STATELESS widget - no changing data const BrowserTabManagerApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( // STATEMENT: Return/create a MaterialApp widget title: 'Browser Tab Manager', theme: ThemeData( colorScheme: ColorScheme.fromSeed( seedColor: const Color(0xFF0175C2), brightness: Brightness.light, ), useMaterial3: true, ), darkTheme: ThemeData( colorScheme: ColorScheme.fromSeed( seedColor: const Color(0xFF0175C2), brightness: Brightness.dark, ), useMaterial3: true, ), home: const TabManagerHome(), ); } } class TabData { // This is a DATA MODEL - holds information about a tab String id; // STATEMENT: Declare a variable String title; // STATEMENT: Declare a variable String url; // STATEMENT: Declare a variable String favicon; DateTime lastAccessed; bool isPinned; String type; int? visitCount; String? folder; TabData({ required this.id, required this.title, required this.url, this.favicon = '', DateTime? lastAccessed, this.isPinned = false, this.type = 'tab', this.visitCount, this.folder, }) : lastAccessed = lastAccessed ?? DateTime.now(); // ☝️ STATEMENT: Constructor that creates TabData objects factory TabData.fromJson(Map json) => TabData( // ☝️ STATEMENT: Factory method to create TabData from JSON id: json['id'].toString(), title: json['title'] ?? 'Untitled', url: json['url'] ?? '', favicon: json['favicon'] ?? json['favIconUrl'] ?? '', lastAccessed: json['lastAccessed'] != null ? DateTime.parse(json['lastAccessed']) : (json['lastVisitTime'] != null ? DateTime.parse(json['lastVisitTime']) : (json['dateAdded'] != null ? DateTime.parse(json['dateAdded']) : (json['timestamp'] != null ? DateTime.parse(json['timestamp']) : DateTime.now()))), isPinned: json['isPinned'] ?? false, type: json['type'] ?? 'tab', visitCount: json['visitCount'], folder: json['folder'], ); } class TabManagerHome extends StatefulWidget { // This is a STATEFUL widget - has changing data (STATE) const TabManagerHome({super.key}); @override State createState() => _TabManagerHomeState(); // STATEMENT: Create the state object } class _TabManagerHomeState extends State { // This class holds all the STATE (changing data) List allItems = []; // 🔴 STATE: List of all tabs/bookmarks/history // When this changes, UI rebuilds to show new data List filteredItems = []; // 🔴 STATE: Filtered/searched items currently displayed final TextEditingController searchController = TextEditingController(); // 🔴 STATE: Controls search text field bool isGridView = true; // 🔴 STATE: Whether showing grid or list view String sortBy = 'recent'; // 🔴 STATE: Current sort method String filterType = 'all'; // 🔴 STATE: Current filter (all, tabs, bookmarks, history) bool isLoading = true; // 🔴 STATE: Whether data is loading bool extensionConnected = false; // 🔴 STATE: Whether browser extension is connected bool extensionMode = false; // 🔴 STATE: Whether in extension tracking mode @override void initState() { // STATEMENT: Method that runs when widget is created super.initState(); // STATEMENT: Call parent's initState _setupExtensionListener(); // STATEMENT: Call function to setup listener _loadAllData(); // STATEMENT: Call function to load data searchController.addListener(_filterItems); // STATEMENT: Add listener to search field } @override void dispose() { // STATEMENT: Method that runs when widget is destroyed searchController.dispose(); // STATEMENT: Clean up resources super.dispose(); // STATEMENT: Call parent's dispose } void _setupExtensionListener() { // STATEMENT: Function declaration html.window.onMessage.listen((event) { // STATEMENT: Start listening for messages final data = event.data; // STATEMENT: Get data from event if (data is Map && data['source'] == 'tab-tracker-extension') { // STATEMENT: Conditional check _handleExtensionMessage(Map.from(data)); // STATEMENT: Call function with data } }); } void _handleExtensionMessage(Map data) { print('Received from extension: $data'); // STATEMENT: Print to console if (data['action'] == 'updateTabs') { // STATEMENT: Check if action is updateTabs setState(() { // 🔥 SPECIAL STATEMENT: Updates STATE and rebuilds UI // Everything inside this block changes STATE final extensionTabs = (data['tabs'] as List).map((tab) { tab['type'] = 'tab'; return TabData.fromJson(tab); }).toList(); // STATEMENT: Transform data allItems = extensionTabs; // 🔴 STATE CHANGE: Update the list extensionConnected = true; // 🔴 STATE CHANGE: Mark extension as connected extensionMode = true; // 🔴 STATE CHANGE: Enable extension mode _filterItems(); // STATEMENT: Call filter function }); // After setState finishes, Flutter rebuilds the UI automatically } else if (data['action'] == 'clear') { // STATEMENT: Check another condition if (extensionMode) { setState(() { extensionMode = false; // 🔴 STATE CHANGE: Disable extension mode _loadAllData(); // STATEMENT: Reload data }); } } else if (data['response'] != null) { final response = data['response']; if (response['status'] == 'started') { setState(() { extensionMode = true; extensionConnected = true; }); } else if (response['status'] == 'stopped') { setState(() { extensionMode = false; _loadAllData(); }); } } } void _sendToExtension(Map message) { // STATEMENT: Function to send message html.window.postMessage({ 'source': 'tab-tracker-webapp', ...message }, '*'); // STATEMENT: Post message to window } void _startExtensionTracking() { _sendToExtension({'action': 'startTracking'}); // STATEMENT: Send message to extension setState(() { // 🔥 UPDATE STATE extensionMode = true; // 🔴 STATE CHANGE allItems.clear(); // 🔴 STATE CHANGE: Clear the list }); } void _stopExtensionTracking() { _sendToExtension({'action': 'stopTracking'}); // STATEMENT: Send stop message setState(() { extensionMode = false; // 🔴 STATE CHANGE }); _loadAllData(); // STATEMENT: Reload data } Future _loadAllData() async { // STATEMENT: Async function declaration if (extensionMode) return; // STATEMENT: Early return if in extension mode setState(() { isLoading = true; // 🔴 STATE CHANGE: Show loading spinner }); try { // STATEMENT: Try block for error handling final tabs = await _getTabs(); // STATEMENT: Wait for tabs to load final bookmarks = await _getBookmarks(); // STATEMENT: Wait for bookmarks to load final history = await _getHistory(); // STATEMENT: Wait for history to load setState(() { // 🔥 UPDATE STATE allItems = [...tabs, ...bookmarks, ...history]; // 🔴 STATE CHANGE: Combine all items _filterItems(); // STATEMENT: Filter items isLoading = false; // 🔴 STATE CHANGE: Hide loading spinner }); _checkExtensionConnection(); // STATEMENT: Check extension } catch (e) { // STATEMENT: Catch errors print('Error loading data: $e'); // STATEMENT: Print error setState(() { isLoading = false; // 🔴 STATE CHANGE: Hide loading spinner }); } } void _checkExtensionConnection() { _sendToExtension({'action': 'getStatus'}); // STATEMENT: Request status Future.delayed(const Duration(milliseconds: 500), () { // STATEMENT: Wait 500ms if (mounted) { // STATEMENT: Check if widget still exists setState(() { // 🔥 UPDATE STATE (even if empty, triggers rebuild) }); } }); } Future> _getTabs() async { // STATEMENT: Function that returns Future try { final result = await _callBrowserAPI('getTabs'); // STATEMENT: Call browser API if (result != null) { // STATEMENT: Check if got result final List data = json.decode(result); // STATEMENT: Parse JSON return data.map((item) { // STATEMENT: Transform each item item['type'] = 'tab'; // STATEMENT: Set type return TabData.fromJson(item); // STATEMENT: Create TabData object }).toList(); } } catch (e) { print('Error getting tabs: $e'); // STATEMENT: Print error } return []; // STATEMENT: Return empty list } Future> _getBookmarks() async { try { final result = await _callBrowserAPI('getBookmarks'); if (result != null) { final List data = json.decode(result); return data.map((item) { item['type'] = 'bookmark'; return TabData.fromJson(item); }).toList(); } } catch (e) { print('Error getting bookmarks: $e'); } return []; } Future> _getHistory() async { try { final result = await _callBrowserAPI('getHistory', [100]); if (result != null) { final List data = json.decode(result); return data.map((item) { item['type'] = 'history'; return TabData.fromJson(item); }).toList(); } } catch (e) { print('Error getting history: $e'); } return []; } Future _callBrowserAPI(String method, [List? args]) async { try { if (!js_util.hasProperty(html.window, 'BrowserAPI')) { // STATEMENT: Check if API exists print('BrowserAPI not found - running in development mode'); return null; // STATEMENT: Return null } final browserAPI = js_util.getProperty(html.window, 'BrowserAPI'); // STATEMENT: Get API object final function = js_util.getProperty(browserAPI, method); // STATEMENT: Get function final result = args == null ? await js_util.promiseToFuture(js_util.callMethod(function, 'call', [browserAPI])) : await js_util.promiseToFuture(js_util.callMethod(function, 'call', [browserAPI, ...args])); // STATEMENT: Call function and wait for result return json.encode(result); // STATEMENT: Convert to JSON string } catch (e) { print('Error calling $method: $e'); return null; } } void _filterItems() { final query = searchController.text.toLowerCase(); // STATEMENT: Get search text setState(() { // 🔥 UPDATE STATE filteredItems = allItems.where((item) { // STATEMENT: Filter list if (filterType != 'all' && item.type != filterType.replaceAll('s', '')) { return false; // STATEMENT: Exclude item } if (query.isNotEmpty) { return item.title.toLowerCase().contains(query) || item.url.toLowerCase().contains(query); // STATEMENT: Check if matches search } return true; // STATEMENT: Include item }).toList(); _sortItems(); // STATEMENT: Sort the filtered items }); } void _sortItems() { switch (sortBy) { // STATEMENT: Switch based on sortBy value case 'recent': filteredItems.sort((a, b) => b.lastAccessed.compareTo(a.lastAccessed)); // STATEMENT: Sort by date break; case 'title': filteredItems.sort((a, b) => a.title.compareTo(b.title)); // STATEMENT: Sort alphabetically 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)); // STATEMENT: Keep pinned items at top } Future _openItem(TabData item) async { if (extensionMode) { html.window.open(item.url, '_blank'); // STATEMENT: Open in new tab } else { if (item.type == 'tab') { await _callBrowserAPI('switchToTab', [item.id]); // STATEMENT: Switch to tab } else { await _callBrowserAPI('openTab', [item.url]); // STATEMENT: Open new tab } } } Future _deleteItem(TabData item) async { if (extensionMode) return; // STATEMENT: Can't delete in extension mode if (item.type == 'tab') { await _callBrowserAPI('closeTab', [item.id]); // STATEMENT: Close tab } else if (item.type == 'bookmark') { await _callBrowserAPI('removeBookmark', [item.id]); // STATEMENT: Delete bookmark } await _loadAllData(); // STATEMENT: Reload data } Future _togglePin(TabData item) async { if (extensionMode) return; if (item.type == 'tab') { await _callBrowserAPI('togglePinTab', [item.id, !item.isPinned]); // STATEMENT: Toggle pin status await _loadAllData(); // STATEMENT: Reload data } } String _getIcon(TabData item) { // STATEMENT: Function that returns icon emoji if (item.favicon.isNotEmpty && !item.favicon.contains('data:')) { return '🌐'; // STATEMENT: Return globe icon } switch (item.type) { case 'tab': return '📑'; case 'bookmark': return '⭐'; case 'history': return '🕐'; default: return '🌐'; } } @override Widget build(BuildContext context) { // STATEMENT: Build method that creates UI // This method runs every time setState() is called final stats = { 'tabs': allItems.where((i) => i.type == 'tab').length, 'bookmarks': allItems.where((i) => i.type == 'bookmark').length, 'history': allItems.where((i) => i.type == 'history').length, }; // STATEMENT: Calculate statistics // This uses current STATE (allItems) to calculate counts return Scaffold( // STATEMENT: Return Scaffold widget appBar: AppBar( title: Row( children: [ const Text('Browser Tab Manager'), if (extensionMode) ...[ // STATEMENT: Conditionally show badge based on STATE 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: [ if (extensionMode) // STATEMENT: Show stop button if in extension mode (based on STATE) TextButton.icon( onPressed: _stopExtensionTracking, // STATEMENT: When pressed, call function that changes STATE icon: const Icon(Icons.stop, color: Colors.white), label: const Text('Stop', style: TextStyle(color: Colors.white)), ) else TextButton.icon( onPressed: extensionConnected ? _startExtensionTracking : null, // STATEMENT: Enable button based on STATE icon: const Icon(Icons.play_arrow, color: Colors.white), label: const Text('Track Tabs', style: TextStyle(color: Colors.white)), ), const SizedBox(width: 8), IconButton( icon: const Icon(Icons.refresh), onPressed: extensionMode ? null : _loadAllData, // STATEMENT: Disable button based on STATE tooltip: 'Refresh', ), IconButton( icon: Icon(isGridView ? Icons.view_list : Icons.grid_view), // STATEMENT: Show different icon based on STATE onPressed: () { setState(() { // 🔥 UPDATE STATE isGridView = !isGridView; // 🔴 STATE CHANGE: Toggle view mode }); }, tooltip: isGridView ? 'List View' : 'Grid View', ), PopupMenuButton( icon: const Icon(Icons.sort), tooltip: 'Sort by', onSelected: (value) { setState(() { // 🔥 UPDATE STATE sortBy = value; // 🔴 STATE CHANGE: Change sort method _filterItems(); // STATEMENT: Re-filter with new sort }); }, itemBuilder: (context) => [ const PopupMenuItem(value: 'recent', child: Text('Recent')), const PopupMenuItem(value: 'title', child: Text('Title')), const PopupMenuItem(value: 'url', child: Text('URL')), const PopupMenuItem(value: 'visits', child: Text('Most Visited')), ], ), ], ), body: Column( children: [ Padding( padding: const EdgeInsets.all(16.0), child: Column( children: [ TextField( controller: searchController, // Uses STATE (searchController) decoration: InputDecoration( hintText: extensionMode ? 'Search tracked tabs...' : 'Search tabs, bookmarks, and history...', // STATEMENT: Show different hint based on STATE prefixIcon: const Icon(Icons.search), suffixIcon: searchController.text.isNotEmpty ? IconButton( icon: const Icon(Icons.clear), onPressed: () { searchController.clear(); // STATEMENT: Clear search (changes STATE) }, ) : null, border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), ), ), ), const SizedBox(height: 12), if (!extensionMode) // STATEMENT: Show filters only if not in extension mode (based on STATE) SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( children: [ FilterChip( label: Text('All (${allItems.length})'), // Uses STATE to show count selected: filterType == 'all', // Uses STATE to show selection onSelected: (selected) { setState(() { // 🔥 UPDATE STATE filterType = 'all'; // 🔴 STATE CHANGE _filterItems(); }); }, ), const SizedBox(width: 8), FilterChip( label: Text('Tabs (${stats['tabs']})'), selected: filterType == 'tabs', onSelected: (selected) { setState(() { filterType = 'tabs'; _filterItems(); }); }, ), const SizedBox(width: 8), FilterChip( label: Text('Bookmarks (${stats['bookmarks']})'), selected: filterType == 'bookmarks', onSelected: (selected) { setState(() { filterType = 'bookmarks'; _filterItems(); }); }, ), const SizedBox(width: 8), FilterChip( label: Text('History (${stats['history']})'), selected: filterType == 'history', onSelected: (selected) { setState(() { filterType = 'history'; _filterItems(); }); }, ), ], ), ), ], ), ), Expanded( child: isLoading // STATEMENT: Show different UI based on STATE ? const Center(child: CircularProgressIndicator()) // If isLoading is true, show spinner : filteredItems.isEmpty // If filteredItems is empty, show message ? Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( extensionMode ? Icons.track_changes : Icons.search_off, // Different icon based on STATE size: 80, color: Theme.of(context) .colorScheme .primary .withOpacity(0.3), ), const SizedBox(height: 16), Text( extensionMode ? 'Waiting for tabs...' : 'No items found', // Different message based on STATE 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 // If isGridView is true, show grid ? GridView.builder( padding: const EdgeInsets.all(16), gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 300, childAspectRatio: 1.3, crossAxisSpacing: 16, mainAxisSpacing: 16, ), itemCount: filteredItems.length, // Uses STATE to determine how many items itemBuilder: (context, index) { return ItemCard( item: filteredItems[index], // Passes STATE data to child widget icon: _getIcon(filteredItems[index]), onTap: () => _openItem(filteredItems[index]), onDelete: () => _deleteItem(filteredItems[index]), onTogglePin: () => _togglePin(filteredItems[index]), extensionMode: extensionMode, // Passes STATE to child ); }, ) : ListView.builder( // Otherwise show list 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, ); }, ), ), ], ), ); } } // ItemCard and ItemListTile are STATELESS widgets // They receive data (STATE) from parent and display it // They don't manage their own STATE class ItemCard extends StatelessWidget { // This widget receives STATE from parent via constructor parameters final TabData item; // STATE from parent final String icon; // STATE from parent final VoidCallback onTap; // Function from parent final VoidCallback onDelete; // Function from parent final VoidCallback onTogglePin; // Function from parent final bool extensionMode; // STATE from parent const ItemCard({ super.key, required this.item, required this.icon, required this.onTap, required this.onDelete, required this.onTogglePin, this.extensionMode = false, }); @override Widget build(BuildContext context) { // STATEMENT: Build method creates UI // This widget doesn't have setState because it's StatelessWidget // It just displays the data it receives return Card( clipBehavior: Clip.antiAlias, child: InkWell( onTap: onTap, // STATEMENT: When tapped, call function from parent child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( height: 60, color: Theme.of(context).colorScheme.primaryContainer, child: Center( child: item.favicon.isNotEmpty && item.favicon.startsWith('http') ? Image.network( item.favicon, width: 32, height: 32, errorBuilder: (context, error, stackTrace) { return Text(icon, style: const TextStyle(fontSize: 32)); }, ) : Text(icon, style: const TextStyle(fontSize: 32)), ), ), Expanded( child: Padding( padding: const EdgeInsets.all(12.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ if (item.isPinned) // STATEMENT: Show pin icon if item is pinned Icon( Icons.push_pin, size: 14, color: Theme.of(context).colorScheme.primary, ), if (item.isPinned) const SizedBox(width: 4), Container( padding: const EdgeInsets.symmetric( horizontal: 6, vertical: 2, ), decoration: BoxDecoration( color: _getTypeColor(context), borderRadius: BorderRadius.circular(4), ), child: Text( item.type.toUpperCase(), // STATEMENT: Display item type from STATE style: TextStyle( fontSize: 10, color: Theme.of(context).colorScheme.onPrimary, ), ), ), ], ), const SizedBox(height: 6), Expanded( child: Text( item.title, // STATEMENT: Display title from STATE style: Theme.of(context).textTheme.titleSmall, maxLines: 2, overflow: TextOverflow.ellipsis, ), ), const SizedBox(height: 4), Text( item.url, // STATEMENT: Display URL from STATE style: Theme.of(context).textTheme.bodySmall?.copyWith( color: Theme.of(context).colorScheme.secondary, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), if (item.visitCount != null) ...[ // STATEMENT: Show visit count if it exists const SizedBox(height: 4), Text( '${item.visitCount} visits', // STATEMENT: Display visit count from STATE style: Theme.of(context).textTheme.bodySmall, ), ], ], ), ), ), if (!extensionMode) // STATEMENT: Show buttons only if not in extension mode (based on STATE) ButtonBar( alignment: MainAxisAlignment.end, buttonPadding: EdgeInsets.zero, children: [ if (item.type == 'tab') // STATEMENT: Show pin button only for tabs IconButton( icon: Icon( item.isPinned ? Icons.push_pin : Icons.push_pin_outlined, // STATEMENT: Different icon based on pin STATE size: 18, ), onPressed: onTogglePin, // STATEMENT: When pressed, call parent's function tooltip: item.isPinned ? 'Unpin' : 'Pin', ), if (item.type != 'history') // STATEMENT: Show delete button for tabs and bookmarks (not history) IconButton( icon: const Icon(Icons.delete_outline, size: 18), onPressed: onDelete, // STATEMENT: When pressed, call parent's delete function tooltip: 'Delete', ), ], ), ], ), ), ); } Color _getTypeColor(BuildContext context) { // STATEMENT: Function that returns color based on item type switch (item.type) { // STATEMENT: Check item type (from STATE) case 'tab': return Colors.blue; // STATEMENT: Return blue for tabs case 'bookmark': return Colors.orange; // STATEMENT: Return orange for bookmarks case 'history': return Colors.purple; // STATEMENT: Return purple for history default: return Theme.of(context).colorScheme.primary; // STATEMENT: Return theme color as fallback } } } class ItemListTile extends StatelessWidget { // Another STATELESS widget - displays data from parent final TabData item; // STATE from parent final String icon; // STATE from parent final VoidCallback onTap; // Function from parent final VoidCallback onDelete; // Function from parent final VoidCallback onTogglePin; // Function from parent final bool extensionMode; // STATE from parent const ItemListTile({ super.key, required this.item, required this.icon, required this.onTap, required this.onDelete, required this.onTogglePin, this.extensionMode = false, }); @override Widget build(BuildContext context) { // STATEMENT: Build method creates UI return Card( margin: const EdgeInsets.only(bottom: 8), child: ListTile( leading: CircleAvatar( child: item.favicon.isNotEmpty && item.favicon.startsWith('http') ? Image.network( item.favicon, width: 20, height: 20, errorBuilder: (context, error, stackTrace) { return Text(icon, style: const TextStyle(fontSize: 20)); }, ) : Text(icon, style: const TextStyle(fontSize: 20)), ), title: Row( children: [ if (item.isPinned) ...[ // STATEMENT: Show pin icon if pinned Icon( Icons.push_pin, size: 14, color: Theme.of(context).colorScheme.primary, ), const SizedBox(width: 4), ], Container( padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), decoration: BoxDecoration( color: _getTypeColor(context), borderRadius: BorderRadius.circular(4), ), child: Text( item.type.toUpperCase(), // STATEMENT: Display type from STATE style: TextStyle( fontSize: 10, color: Theme.of(context).colorScheme.onPrimary, ), ), ), const SizedBox(width: 8), Expanded( child: Text( item.title, // STATEMENT: Display title from STATE maxLines: 1, overflow: TextOverflow.ellipsis, ), ), ], ), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( item.url, // STATEMENT: Display URL from STATE maxLines: 1, overflow: TextOverflow.ellipsis, ), if (item.visitCount != null) // STATEMENT: Show visit count if exists Text('${item.visitCount} visits', style: Theme.of(context).textTheme.bodySmall), ], ), trailing: extensionMode ? null : Row( // STATEMENT: Show buttons based on extensionMode STATE mainAxisSize: MainAxisSize.min, children: [ if (item.type == 'tab') // STATEMENT: Pin button only for tabs IconButton( icon: Icon( item.isPinned ? Icons.push_pin : Icons.push_pin_outlined, ), onPressed: onTogglePin, // STATEMENT: Call parent's function tooltip: item.isPinned ? 'Unpin' : 'Pin', ), if (item.type != 'history') // STATEMENT: Delete button for tabs and bookmarks IconButton( icon: const Icon(Icons.delete_outline), onPressed: onDelete, // STATEMENT: Call parent's function tooltip: 'Delete', ), ], ), onTap: onTap, // STATEMENT: When tapped, call parent's function ), ); } Color _getTypeColor(BuildContext context) { // STATEMENT: Function to get color based on type switch (item.type) { case 'tab': return Colors.blue; case 'bookmark': return Colors.orange; case 'history': return Colors.purple; default: return Theme.of(context).colorScheme.primary; } } }