working on this flutter app
main.dart
import 'package:flutter/material.dart';
import 'pages/shopping_list_page.dart'; // Adjust the path as needed

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Shopping List',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: ShoppingListPage(
        toggleTheme: () {}, // Placeholder if you already have a toggle function
        isDarkTheme: false, // Set this according to your initial theme preference
      ),
    );
  }
}

item.dart
// lib/item.dart

class Item {
  final String name;
  final double quantity; // Use double to handle both whole numbers and decimals
  final String unit;
  final String userInitial;
  final String group;
  bool picked;

  Item({
    required this.name,
    required this.quantity,
    required this.unit,
    required this.userInitial,
    required this.group,
    this.picked = false,
  });
}

final List<Item> items = [
  Item(name: 'Apples', quantity: 5, unit: 'kg', userInitial: 'A', group: 'Family'), // Whole number
  Item(name: 'Bananas', quantity: 12, unit: 'pcs', userInitial: 'B', group: 'Timos Party'),
  Item(name: 'Bread', quantity: 2, unit: 'loaves', userInitial: 'C', group: 'Family'),
  Item(name: 'Carrots', quantity: 3.5, unit: 'kg', userInitial: 'D', group: 'Family'), // Decimal
  Item(name: 'Detergent', quantity: 1, unit: 'bottle', userInitial: 'E', group: 'Family'),
  Item(name: 'Eggs', quantity: 30, unit: 'pcs', userInitial: 'F', group: 'Timos Party'),
  Item(name: 'Flour', quantity: 2.25, unit: 'kg', userInitial: 'G', group: 'Family'), // Decimal
  Item(name: 'Grapes', quantity: 1.5, unit: 'bag', userInitial: 'H', group: 'Timos Party'), // Decimal
  Item(name: 'Honey', quantity: 1, unit: 'jar', userInitial: 'I', group: 'Family'),
  Item(name: 'Ice Cream', quantity: 2, unit: 'liters', userInitial: 'J', group: 'Timos Party'),
  Item(name: 'Juice', quantity: 4, unit: 'liters', userInitial: 'K', group: 'Family'),
  Item(name: 'Kale', quantity: 1, unit: 'bag', userInitial: 'L', group: 'Family'),
  Item(name: 'Lemons', quantity: 10, unit: 'pcs', userInitial: 'M', group: 'Family'),
  Item(name: 'Milk', quantity: 3, unit: 'liters', userInitial: 'N', group: 'Family'),
  Item(name: 'Nuts', quantity: 200, unit: 'g', userInitial: 'O', group: 'Timos Party'),
  Item(name: 'Oranges', quantity: 7, unit: 'pcs', userInitial: 'P', group: 'Family'),
  Item(name: 'Pasta', quantity: 1, unit: 'kg', userInitial: 'Q', group: 'Family'),
  Item(name: 'Quinoa', quantity: 0.75, unit: 'bag', userInitial: 'R', group: 'Family'), // Decimal
  Item(name: 'Rice', quantity: 5, unit: 'kg', userInitial: 'S', group: 'Family'),
  Item(name: 'Strawberries', quantity: 2, unit: 'boxes', userInitial: 'T', group: 'Timos Party'),
  Item(name: 'Tomatoes', quantity: 1, unit: 'kg', userInitial: 'U', group: 'Family'),
  Item(name: 'Umbrellas', quantity: 3, unit: 'pcs', userInitial: 'V', group: 'Timos Party'),
  Item(name: 'Vinegar', quantity: 1, unit: 'bottle', userInitial: 'W', group: 'Family'),
  Item(name: 'Watermelon', quantity: 1, unit: 'pcs', userInitial: 'X', group: 'Timos Party'),
  Item(name: 'Watermelon', quantity: 1, unit: 'pcs', userInitial: 'X', group: 'Family'),
];

// Note: Ensure all entries have non-null values.

shopping_list_page.dart in pages sub directory
// lib/pages/shopping_list_page.dart
import 'package:flutter/material.dart';
import '../item.dart'; // Ensure the correct path

class ShoppingListPage extends StatefulWidget {
  final Function toggleTheme;
  final bool isDarkTheme;

  const ShoppingListPage({super.key, required this.toggleTheme, required this.isDarkTheme});

  @override
  State<ShoppingListPage> createState() => _ShoppingListPageState();
}

class _ShoppingListPageState extends State<ShoppingListPage> {
  String _searchQuery = "";
  String _selectedGroup = 'Family'; // Default selected group
  List<Item> _filteredItems = List.from(items);
  final TextEditingController _searchController = TextEditingController();
  final ScrollController _scrollController = ScrollController();
  Color? _highlightColor;

  // Controllers for adding new items
  final TextEditingController _nameController = TextEditingController();
  final TextEditingController _quantityController = TextEditingController();
  final TextEditingController _unitController = TextEditingController();
  final TextEditingController _userInitialController = TextEditingController();

  // Using StateSetter for updating the duplicate check
  FocusNode _nameFocusNode = FocusNode();
  bool _isDuplicateName = false;

  List<String> _getGroups() {
    return items.map((item) => item.group).toSet().toList();
  }

  @override
  void initState() {
    super.initState();
    _sortItems(); // Initial sorting
  }

  @override
  void dispose() {
    _nameController.dispose();
    _quantityController.dispose();
    _unitController.dispose();
    _userInitialController.dispose();
    _nameFocusNode.dispose();
    super.dispose();
  }

  void _filterItems(String query) {
    setState(() {
      _searchQuery = query;
      _sortItems();
    });
  }

  void _clearSearch() {
    _searchController.clear();
    setState(() {
      _searchQuery = "";
      _sortItems();
    });
  }

  void _toggleItemPicked(Item item) {
    setState(() {
      item.picked = !item.picked;
      _filteredItems.remove(item);
      _filteredItems.insert(0, item); // Move item to the top

      _highlightColor = widget.isDarkTheme ? Colors.tealAccent[700] : Colors.lightBlue[100];

      _scrollController.animateTo(
        0.0,
        duration: Duration(milliseconds: 300),
        curve: Curves.easeInOut,
      );
    });

    Future.delayed(Duration(milliseconds: 800)).then((_) {
      setState(() {
        _highlightColor = null; // Clear highlight color
        _clearSearch(); // Clear search after changing item state
        _sortItems(); // Re-sort items
      });
    });
  }

  void _sortItems() {
    _filteredItems = items.where((item) => item.group == _selectedGroup).toList();
    if (_searchQuery.isNotEmpty) {
      _filteredItems = _filteredItems
          .where((item) => item.name.toLowerCase().contains(_searchQuery.toLowerCase()))
          .toList();
    }

    _filteredItems.sort((a, b) {
      if (a.picked && !b.picked) return -1;
      if (!a.picked && b.picked) return 1;
      return a.name.compareTo(b.name);
    });
  }

  void _addItem() {
    _showDialogToAddItem();
  }

  void _editItem(Item item) {
    print("Edit item clicked: ${item.name}");
    // Implement your edit functionality here
  }

  void _showDialogToAddItem() {
    final textColor = widget.isDarkTheme ? Colors.white : Colors.black;

    showDialog(
      context: context,
      builder: (BuildContext context) {
        return StatefulBuilder(
          builder: (context, setState) {
            bool isFormValid() {
              return _nameController.text.isNotEmpty &&
                  !_isDuplicateName && // Include duplicate check in form validation
                  _quantityController.text.isNotEmpty &&
                  _unitController.text.isNotEmpty &&
                  _userInitialController.text.isNotEmpty;
            }

            return AlertDialog(
              title: const Text('Add New Item'),
              content: SingleChildScrollView(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    RichText(
                      text: TextSpan(
                        children: [
                          TextSpan(
                            text: 'Group: ',
                            style: TextStyle(
                              fontSize: 16.0,
                              color: textColor,
                            ),
                          ),
                          TextSpan(
                            text: _selectedGroup,
                            style: TextStyle(
                              fontWeight: FontWeight.bold,
                              fontSize: 18.0,
                              color: textColor,
                            ),
                          ),
                        ],
                      ),
                    ),
                    SizedBox(height: 8.0),
                    TextField(
                      controller: _nameController,
                      focusNode: _nameFocusNode,
                      decoration: InputDecoration(
                        labelText: 'Name',
                        errorText: _isDuplicateName
                            ? 'Item already exists in this group'
                            : null,
                      ),
                      onChanged: (text) {
                        setState(() {
                          _isDuplicateName =
                              _itemExistsForGroup(text.trim(), _selectedGroup);
                        });
                      },
                      onTap: () {
                        setState(() {
                          _isDuplicateName = false;
                        });
                      },
                    ),
                    TextField(
                      controller: _quantityController,
                      decoration: const InputDecoration(labelText: 'Quantity'),
                      keyboardType: TextInputType.number,
                    ),
                    TextField(
                      controller: _unitController,
                      decoration: const InputDecoration(labelText: 'Unit'),
                    ),
                    TextField(
                      controller: _userInitialController,
                      decoration: const InputDecoration(labelText: 'User Initial'),
                    ),
                    SizedBox(height: 20.0),
                    Row(
                      mainAxisAlignment: MainAxisAlignment.end,
                      children: [
                        TextButton(
                          child: const Text('Cancel'),
                          onPressed: () {
                            _clearTextControllers();
                            Navigator.of(context).pop();
                          },
                        ),
                        TextButton(
                          child: const Text('Add'),
                          onPressed: isFormValid()
                              ? () {
                                  setState(() {
                                    items.add(Item(
                                      name: _nameController.text.trim(),
                                      quantity: double.tryParse(
                                              _quantityController.text.trim()) ??
                                          0.0,
                                      unit: _unitController.text.trim(),
                                      userInitial: _userInitialController.text
                                          .trim()
                                          .toUpperCase(),
                                      group: _selectedGroup,
                                    ));
                                    _sortItems();
                                    _clearTextControllers();
                                  });
                                  Navigator.of(context).pop();
                                }
                              : null,
                        ),
                      ],
                    ),
                  ],
                ),
              ),
            );
          },
        );
      },
    );
  }

  bool _itemExistsForGroup(String name, String group) {
    return items.any(
        (item) => item.name.toLowerCase() == name.toLowerCase() && item.group == group);
  }

  void _clearTextControllers() {
    _nameController.clear();
    _quantityController.clear();
    _unitController.clear();
    _userInitialController.clear();
    _isDuplicateName = false;
  }

  void _confirmDeleteItem(Item item) {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: const Text('Confirm Delete'),
          content: Text('Are you sure you want to delete ${item.name}?'),
          actions: [
            TextButton(
              child: const Text('Cancel'),
              onPressed: () {
                Navigator.of(context).pop();
              },
            ),
            TextButton(
              child: const Text('Delete'),
              onPressed: () {
                setState(() {
                  items.remove(item);
                  _sortItems();
                });
                Navigator.of(context).pop();
                ScaffoldMessenger.of(context).showSnackBar(
                  SnackBar(content: Text("${item.name} deleted")),
                );
              },
            ),
          ],
        );
      },
    );
  }

  void _scrollToTop() {
    _scrollController.animateTo(
      0.0,
      duration: Duration(milliseconds: 300),
      curve: Curves.easeInOut,
    );
  }

  void _scrollToBottom() {
    _scrollController.animateTo(
      _scrollController.position.maxScrollExtent,
      duration: Duration(milliseconds: 300),
      curve: Curves.easeInOut,
    );
  }

  void _showGroupsDialog() {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: const Text('Manage Groups'),
          content: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              SimpleDialogOption(
                onPressed: () {
                  Navigator.pop(context);
                  print("Add Group clicked");
                  // Add functionality for adding a group
                },
                child: const Text('Add Group'),
              ),
              SimpleDialogOption(
                onPressed: () {
                  Navigator.pop(context);
                  print("Delete Group clicked");
                  // Add functionality for deleting a group
                },
                child: const Text('Delete Group'),
              ),
            ],
          ),
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    final rowColorsDefault = widget.isDarkTheme
        ? [Colors.grey[900]!, Colors.grey[850]!]
        : [Colors.blue[50]!, Colors.blue[100]!];

    final pickedRowColors = widget.isDarkTheme
        ? [Colors.teal[800]!.withOpacity(0.5), Colors.teal[700]!.withOpacity(0.5)]
        : [Colors.green[100]!, Colors.green[50]!];

    final groups = _getGroups();

    return Scaffold(
      appBar: AppBar(
        title: const Text('Shopping List'),
        leading: Builder(
          builder: (BuildContext context) {
            return IconButton(
              icon: const Icon(Icons.menu),
              onPressed: () {
                Scaffold.of(context).openDrawer();
              },
              tooltip: MaterialLocalizations.of(context).openAppDrawerTooltip,
            );
          },
        ),
        actions: <Widget>[
          // Removed the Add item button from the AppBar
        ],
      ),
      drawer: Container(
        width: MediaQuery.of(context).size.width * 0.75, // Reduce drawer width
        child: Drawer(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: <Widget>[
              const DrawerHeader(
                decoration: BoxDecoration(
                  color: Colors.blue,
                ),
                child: Text(
                  'Menu',
                  style: TextStyle(
                    color: Colors.white,
                    fontSize: 24,
                  ),
                ),
              ),
              Expanded(
                child: ListView(
                  padding: EdgeInsets.zero,
                  children: <Widget>[
                    ListTile(
                      leading: const Icon(Icons.home),
                      title: const Text('Home'),
                      onTap: () {
                        Navigator.pop(context);
                      },
                    ),
                    ListTile(
                      leading: const Icon(Icons.account_circle),
                      title: const Text('Profile'),
                      onTap: () {
                        Navigator.pop(context);
                      },
                    ),
                    ListTile(
                      leading: Icon(widget.isDarkTheme ? Icons.wb_sunny : Icons.nightlight_round),
                      title: Text('Toggle Theme'),
                      onTap: () {
                        Navigator.pop(context);
                        widget.toggleTheme();
                      },
                    ),
                  ],
                ),
              ),
              ListTile(
                leading: const Icon(Icons.settings),
                title: const Text('Settings'),
                onTap: () {
                  Navigator.pop(context);
                },
              ),
            ],
          ),
        ),
      ),
      body: Column(
        children: [
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: Row(
              children: [
                SizedBox(
                  width: MediaQuery.of(context).size.width * 0.3,
                  child: DropdownButton<String>(
                    isExpanded: true,
                    value: _selectedGroup,
                    icon: const Icon(Icons.arrow_downward),
                    onChanged: (String? newValue) {
                      setState(() {
                        _selectedGroup = newValue ?? _selectedGroup;
                        _sortItems();
                      });
                    },
                    items: groups.map<DropdownMenuItem<String>>((String group) {
                      return DropdownMenuItem<String>(
                        value: group,
                        child: Text(group),
                      );
                    }).toList(),
                  ),
                ),
                SizedBox(width: 10.0), // Space between dropdown and icon button
                Tooltip(
                  message: 'Manage Groups',
                  child: IconButton(
                    icon: const Icon(Icons.group),
                    onPressed: _showGroupsDialog,
                  ),
                ),
                Spacer(), // Pushes the search box to the right
                SizedBox(
                  width: MediaQuery.of(context).size.width * 0.375,
                  height: 40.0,
                  child: TextField(
                    controller: _searchController,
                    onChanged: _filterItems,
                    decoration: InputDecoration(
                      labelText: 'Search',
                      border: const OutlineInputBorder(),
                      isDense: true,
                      contentPadding: const EdgeInsets.all(8.0),
                      suffixIcon: Row(
                        mainAxisSize: MainAxisSize.min,
                        children: [
                          const Icon(Icons.search),
                          IconButton(
                            icon: const Icon(Icons.cancel),
                            onPressed: _clearSearch,
                          ),
                        ],
                      ),
                    ),
                    keyboardType: TextInputType.text,
                  ),
                ),
              ],
            ),
          ),
          Expanded(
            child: ListView.builder(
              controller: _scrollController,
              itemCount: _filteredItems.length,
              itemBuilder: (context, index) {
                final item = _filteredItems[index];
                final isPicked = item.picked;
                final backgroundColor = index == 0 && _highlightColor != null
                    ? _highlightColor
                    : (isPicked
                        ? pickedRowColors[index % pickedRowColors.length]
                        : rowColorsDefault[index % rowColorsDefault.length]);

                return Dismissible(
                  key: UniqueKey(),
                  confirmDismiss: (direction) async {
                    bool? result = await showDialog(
                      context: context,
                      builder: (context) {
                        return AlertDialog(
                          title: const Text('Confirm Delete'),
                          content:
                              Text('Are you sure you want to delete ${item.name}?'),
                          actions: [
                            TextButton(
                              child: const Text('Cancel'),
                              onPressed: () {
                                Navigator.of(context).pop(false);
                              },
                            ),
                            TextButton(
                              child: const Text('Delete'),
                              onPressed: () {
                                Navigator.of(context).pop(true);
                              },
                            ),
                          ],
                        );
                      },
                    );
                    return result ?? false;
                  },
                  onDismissed: (direction) {
                    setState(() {
                      items.remove(item);
                      _sortItems();
                    });
                    ScaffoldMessenger.of(context).showSnackBar(
                      SnackBar(content: Text("${item.name} deleted")),
                    );
                  },
                  background: Container(color: Colors.red),
                  child: Container(
                    color: backgroundColor,
                    child: ListTile(
                      contentPadding: const EdgeInsets.symmetric(
                          horizontal: 12.0, vertical: 0.0),
                      dense: true,
                      title: Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        children: [
                          Text(
                            item.name,
                            style: TextStyle(
                              color: widget.isDarkTheme
                                  ? Colors.white
                                  : Colors.black,
                            ),
                          ),
                          Text(
                            formatQuantity(item.quantity, item.unit),
                            style: TextStyle(
                              color: widget.isDarkTheme
                                  ? Colors.white
                                  : Colors.black,
                            ),
                          ),
                        ],
                      ),
                      trailing: Row(
                        mainAxisSize: MainAxisSize.min,
                        children: [
                          IconButton(
                            icon: Icon(Icons.edit, color: Colors.grey),
                            onPressed: () => _editItem(item),
                          ),
                          CircleAvatar(
                            backgroundColor: Colors.blue,
                            child: Text(
                              item.userInitial,
                              style: const TextStyle(color: Colors.white),
                            ),
                          ),
                          Transform.scale(
                            scale: 1.15,
                            child: Checkbox(
                              shape: CircleBorder(),
                              value: item.picked,
                              onChanged: (bool? newValue) {
                                _toggleItemPicked(item);
                              },
                            ),
                          ),
                        ],
                      ),
                      onTap: () => _toggleItemPicked(item),
                    ),
                  ),
                );
              },
            ),
          ),
          SizedBox(height: 16.0), // Space between list and buttons
          Row(
            mainAxisAlignment: MainAxisAlignment.start, // Align buttons to the start
            children: [
              SizedBox(width: 20.0), // Add fixed space from the left edge
              SizedBox(
                width: 48, // Reduced width for the up and down buttons
                height: 48,
                child: ElevatedButton(
                  style: ElevatedButton.styleFrom(
                    padding: EdgeInsets.zero, // Remove default padding
                    alignment: Alignment.center, // Center the icon
                  ),
                  onPressed: _scrollToBottom,
                  child: const Icon(Icons.arrow_downward),
                ),
              ),
              SizedBox(width: 8.0), // Space between buttons
              SizedBox(
                width: 48,
                height: 48,
                child: ElevatedButton(
                  style: ElevatedButton.styleFrom(
                    padding: EdgeInsets.zero, // Remove default padding
                    alignment: Alignment.center, // Center the icon
                  ),
                  onPressed: _scrollToTop,
                  child: const Icon(Icons.arrow_upward),
                ),
              ),
              Spacer(), // Flexible space to push Add Item to the right
              ElevatedButton.icon(
                onPressed: _addItem, // Add button functionality
                icon: const Icon(Icons.add),
                label: const Text('Add Item'),
                style: ElevatedButton.styleFrom(
                  backgroundColor: Colors.lightBlueAccent, // More subtle blue
                  padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
                  textStyle: TextStyle(fontSize: 18),
                  elevation: 3, // Moderate elevation
                ),
              ),
              SizedBox(width: 20.0), // Add fixed space from the right edge
            ],
          ),
          SizedBox(height: 16.0), // Add additional space if needed
        ],
      ),
    );
  }

  String formatQuantity(double quantity, String unit) {
    if (quantity == quantity.toInt()) {
      return '${quantity.toInt()} $unit'; // Display as integer if it's whole
    } else {
      return '$quantity $unit'; // Display as double for decimals
    }
  }
}