248 lines
16 KiB
Dart
248 lines
16 KiB
Dart
import 'package:flutter/material.dart';
|
|
import '../models/category.dart'; // Import the Category model for return types
|
|
|
|
// Helper class to manage category details (icon, color) based on name
|
|
class CategoryUtils {
|
|
// Private map storing details for each predefined category name.
|
|
// Using a record `({IconData icon, Color color})` for concise structure.
|
|
// This map is mainly for initial data and potentially fallback display logic.
|
|
// The actual icon/color for user-created categories will come from the database.
|
|
// DEPRECATED: Rely on _stringToIconData and database color instead.
|
|
// static final Map<String, ({IconData iconCode, Color colorCode})> _categoryDetails = { ... };
|
|
|
|
// Default details to return if a category name is not found (e.g., deleted category).
|
|
// DEPRECATED: Use getIconFromString and default color instead.
|
|
// static final _defaultDetails = (iconCode: Icons.category_outlined, colorCode: Colors.grey.shade500);
|
|
|
|
/// DEPRECATED: Returns the IconData and Color associated with a given category name (primarily for fallback).
|
|
/// It's better to rely on data fetched directly from the database (CategoryDb).
|
|
static ({Color colorCode, IconData iconCode}) getCategoryDetails(String categoryName) {
|
|
// Fallback logic using the string-to-icon map and a default color
|
|
final icon = getIconFromString(categoryName); // Use the reliable method
|
|
// Find color from initial data if possible, otherwise default grey
|
|
// This part is still weak, ideally color comes from DB.
|
|
Color color = Colors.grey.shade500; // Default color
|
|
// Quick check against some known initial names for color fallback
|
|
if (categoryName == 'Groceries') color = Colors.green.shade400;
|
|
if (categoryName == 'Subscriptions') color = Colors.orange.shade400;
|
|
if (categoryName == 'Restaurant') color = Colors.red.shade400;
|
|
if (categoryName == 'Shopping') color = Colors.blue.shade400;
|
|
if (categoryName == 'Transport') color = Colors.purple.shade400;
|
|
if (categoryName == 'Travel') color = Colors.cyan.shade400;
|
|
if (categoryName == 'Utilities') color = Colors.teal.shade400; // Updated from home_outlined
|
|
if (categoryName == 'Income') color = Colors.lightGreenAccent.shade700;
|
|
|
|
return (colorCode: color, iconCode: icon);
|
|
}
|
|
|
|
/// DEPRECATED: Returns a `Category` object based on its name and amount (primarily for UI models like Pie Chart).
|
|
/// Fetches icon/color details using `getCategoryDetails` as a fallback mechanism.
|
|
/// Should be replaced by logic that uses CategoryDb data directly.
|
|
static Category getCategoryByName(String name, double amount) {
|
|
final details = getCategoryDetails(name);
|
|
return Category(name, amount, details.colorCode, details.iconCode);
|
|
}
|
|
|
|
/// DEPRECATED: Returns a list of all predefined category names (excluding placeholders).
|
|
/// Might be less useful now that categories are fully dynamic.
|
|
static List<String> getAllCategoryNames() {
|
|
// Return keys from _stringToIconData, excluding special ones
|
|
return _stringToIconData.keys.where((key) =>
|
|
key != 'help_outline' &&
|
|
key != 'label_outline' &&
|
|
key != 'attach_money' && // Exclude Income
|
|
key != 'category_outlined' // Exclude Other/Default
|
|
).toList();
|
|
}
|
|
|
|
/// Converts a string icon name (like 'shopping_cart_outlined') to IconData.
|
|
/// This map is crucial for displaying icons based on the string stored in the DB.
|
|
static final Map<String, IconData> _stringToIconData = {
|
|
// Existing Icons
|
|
'shopping_cart_outlined': Icons.shopping_cart_outlined, // Groceries
|
|
'subscriptions_outlined': Icons.subscriptions_outlined, // Subscriptions
|
|
'restaurant_menu_outlined': Icons.restaurant_menu_outlined, // Restaurant
|
|
'shopping_bag_outlined': Icons.shopping_bag_outlined, // Shopping
|
|
'directions_bus_filled_outlined': Icons.directions_bus_filled_outlined, // Transport
|
|
'flight_takeoff_outlined': Icons.flight_takeoff_outlined, // Travel
|
|
'lightbulb_outline': Icons.lightbulb_outline, // Utilities (alternative)
|
|
'local_hospital_outlined': Icons.local_hospital_outlined, // Health
|
|
'movie_filter_outlined': Icons.movie_filter_outlined, // Entertainment
|
|
'attach_money': Icons.attach_money, // Income (Special)
|
|
'category_outlined': Icons.category_outlined, // Other/Default (Fallback)
|
|
'label_outline': Icons.label_outline, // Placeholder (Internal)
|
|
'help_outline': Icons.help_outline, // Placeholder/Error (Internal)
|
|
'home_outlined': Icons.home_outlined, // Home/Rent/Mortgage/Utilities
|
|
'pets_outlined': Icons.pets_outlined, // Pets
|
|
'school_outlined': Icons.school_outlined, // Education/School
|
|
'fitness_center_outlined': Icons.fitness_center_outlined, // Gym/Fitness
|
|
'checkroom_outlined': Icons.checkroom_outlined, // Clothing
|
|
'devices_other_outlined': Icons.devices_other_outlined, // Electronics
|
|
'card_giftcard_outlined': Icons.card_giftcard_outlined, // Gifts
|
|
'volunteer_activism_outlined': Icons.volunteer_activism_outlined, // Charity/Donations
|
|
'receipt_long_outlined': Icons.receipt_long_outlined, // Bills/Receipts
|
|
'savings_outlined': Icons.savings_outlined, // Savings/Investments
|
|
'credit_card_outlined': Icons.credit_card_outlined, // Credit Card Payment
|
|
'build_outlined': Icons.build_outlined, // Repairs/Maintenance
|
|
'child_friendly_outlined': Icons.child_friendly_outlined, // Child Care
|
|
'work_outline': Icons.work_outline, // Work related
|
|
'book_outlined': Icons.book_outlined, // Books/Magazines
|
|
'music_note_outlined': Icons.music_note_outlined, // Music
|
|
'sports_esports_outlined': Icons.sports_esports_outlined, // Games/Hobbies
|
|
'local_bar_outlined': Icons.local_bar_outlined, // Drinks/Bar
|
|
'cake_outlined': Icons.cake_outlined, // Celebrations/Party
|
|
'park_outlined': Icons.park_outlined, // Parks/Outdoors
|
|
'science_outlined': Icons.science_outlined, // Science/Tech
|
|
'palette_outlined': Icons.palette_outlined, // Art/Design
|
|
'account_balance_outlined': Icons.account_balance_outlined, // Bank/Finance Fees
|
|
'analytics_outlined': Icons.analytics_outlined, // Analysis/Reports (Maybe internal?)
|
|
'apartment_outlined': Icons.apartment_outlined, // Rent/Mortgage (Alternative)
|
|
'beach_access_outlined': Icons.beach_access_outlined, // Vacation/Beach
|
|
'brush_outlined': Icons.brush_outlined, // Personal Care/Cosmetics
|
|
'business_center_outlined': Icons.business_center_outlined, // Business Expenses
|
|
'call_outlined': Icons.call_outlined, // Phone Bill
|
|
'camera_alt_outlined': Icons.camera_alt_outlined, // Photography/Equipment
|
|
'car_rental_outlined': Icons.car_rental_outlined, // Car Rental
|
|
'car_repair_outlined': Icons.car_repair_outlined, // Car Repair
|
|
'celebration_outlined': Icons.celebration_outlined, // Party/Events (Alternative)
|
|
'computer_outlined': Icons.computer_outlined, // Computer/Software
|
|
'construction_outlined': Icons.construction_outlined, // Home Improvement
|
|
'cottage_outlined': Icons.cottage_outlined, // Vacation Home/Cottage
|
|
'delivery_dining_outlined': Icons.delivery_dining_outlined, // Food Delivery
|
|
'diamond_outlined': Icons.diamond_outlined, // Jewelry/Luxury
|
|
'dry_cleaning_outlined': Icons.dry_cleaning_outlined, // Laundry/Dry Cleaning
|
|
'electrical_services_outlined': Icons.electrical_services_outlined, // Electrician
|
|
'emoji_events_outlined': Icons.emoji_events_outlined, // Awards/Competitions
|
|
'fastfood_outlined': Icons.fastfood_outlined, // Fast Food
|
|
'fax_outlined': Icons.fax_outlined, // Office Supplies (Maybe outdated?)
|
|
'festival_outlined': Icons.festival_outlined, // Festivals/Events
|
|
'fireplace_outlined': Icons.fireplace_outlined, // Heating/Fuel
|
|
'flatware_outlined': Icons.flatware_outlined, // Kitchenware
|
|
'gas_meter_outlined': Icons.gas_meter_outlined, // Gas Bill
|
|
'gavel_outlined': Icons.gavel_outlined, // Legal Fees
|
|
'grass_outlined': Icons.grass_outlined, // Gardening/Lawn Care
|
|
'hardware_outlined': Icons.hardware_outlined, // Hardware Store
|
|
'hearing_outlined': Icons.hearing_outlined, // Audio/Headphones
|
|
'hiking_outlined': Icons.hiking_outlined, // Hiking/Outdoor Gear
|
|
'icecream_outlined': Icons.icecream_outlined, // Ice Cream/Desserts
|
|
'interests_outlined': Icons.interests_outlined, // Hobbies General
|
|
'key_outlined': Icons.key_outlined, // Keys/Locks
|
|
'liquor_outlined': Icons.liquor_outlined, // Alcohol
|
|
'local_activity_outlined': Icons.local_activity_outlined, // Tickets/Events
|
|
'local_atm_outlined': Icons.local_atm_outlined, // ATM Withdrawal (Maybe internal?)
|
|
'local_convenience_store_outlined': Icons.local_convenience_store_outlined, // Convenience Store
|
|
'local_florist_outlined': Icons.local_florist_outlined, // Flowers
|
|
'local_gas_station_outlined': Icons.local_gas_station_outlined, // Gas/Fuel
|
|
'local_laundry_service_outlined': Icons.local_laundry_service_outlined, // Laundry Service
|
|
'local_mall_outlined': Icons.local_mall_outlined, // Mall Shopping
|
|
'local_offer_outlined': Icons.local_offer_outlined, // Discounts/Sales/Coupons
|
|
'local_parking_outlined': Icons.local_parking_outlined, // Parking Fees
|
|
'local_pharmacy_outlined': Icons.local_pharmacy_outlined, // Pharmacy
|
|
'local_pizza_outlined': Icons.local_pizza_outlined, // Pizza
|
|
'local_shipping_outlined': Icons.local_shipping_outlined, // Shipping Costs
|
|
'local_taxi_outlined': Icons.local_taxi_outlined, // Taxi/Rideshare
|
|
'lunch_dining_outlined': Icons.lunch_dining_outlined, // Lunch
|
|
'medication_outlined': Icons.medication_outlined, // Medication
|
|
'museum_outlined': Icons.museum_outlined, // Museum/Exhibits
|
|
'newspaper_outlined': Icons.newspaper_outlined, // Newspapers/Magazines
|
|
'paid_outlined': Icons.paid_outlined, // Payments/Transfers (Maybe internal?)
|
|
'pedal_bike_outlined': Icons.pedal_bike_outlined, // Cycling
|
|
'plumbing_outlined': Icons.plumbing_outlined, // Plumber
|
|
'ramen_dining_outlined': Icons.ramen_dining_outlined, // Noodles/Asian Food
|
|
'recycling_outlined': Icons.recycling_outlined, // Recycling Fees
|
|
'redeem_outlined': Icons.redeem_outlined, // Gifts Received/Redeemed (Maybe internal?)
|
|
'request_quote_outlined': Icons.request_quote_outlined, // Invoices/Quotes (Maybe internal?)
|
|
'roller_skating_outlined': Icons.roller_skating_outlined, // Skating
|
|
'roofing_outlined': Icons.roofing_outlined, // Roofing Repair
|
|
'room_service_outlined': Icons.room_service_outlined, // Hotel Service
|
|
'shield_outlined': Icons.shield_outlined, // Insurance
|
|
'skateboarding_outlined': Icons.skateboarding_outlined, // Skateboarding
|
|
'smoking_rooms_outlined': Icons.smoking_rooms_outlined, // Tobacco
|
|
'spa_outlined': Icons.spa_outlined, // Spa/Wellness
|
|
'sports_bar_outlined': Icons.sports_bar_outlined, // Sports Bar
|
|
'sports_basketball_outlined': Icons.sports_basketball_outlined, // Basketball
|
|
'sports_football_outlined': Icons.sports_football_outlined, // Football
|
|
'sports_golf_outlined': Icons.sports_golf_outlined, // Golf
|
|
'sports_gymnastics_outlined': Icons.sports_gymnastics_outlined, // Gymnastics
|
|
'sports_handball_outlined': Icons.sports_handball_outlined, // Handball
|
|
'sports_hockey_outlined': Icons.sports_hockey_outlined, // Hockey
|
|
'sports_kabaddi_outlined': Icons.sports_kabaddi_outlined, // Kabaddi
|
|
'sports_mma_outlined': Icons.sports_mma_outlined, // MMA
|
|
'sports_motorsports_outlined': Icons.sports_motorsports_outlined, // Motorsports
|
|
'sports_soccer_outlined': Icons.sports_soccer_outlined, // Soccer
|
|
'sports_tennis_outlined': Icons.sports_tennis_outlined, // Tennis
|
|
'sports_volleyball_outlined': Icons.sports_volleyball_outlined, // Volleyball
|
|
'stadium_outlined': Icons.stadium_outlined, // Stadium/Events
|
|
'store_mall_directory_outlined': Icons.store_mall_directory_outlined, // Department Store
|
|
'stroller_outlined': Icons.stroller_outlined, // Baby Supplies
|
|
'subway_outlined': Icons.subway_outlined, // Subway/Metro
|
|
'surfing_outlined': Icons.surfing_outlined, // Surfing
|
|
'sync_alt_outlined': Icons.sync_alt_outlined, // Transfers (Maybe internal?)
|
|
'theater_comedy_outlined': Icons.theater_comedy_outlined, // Comedy Club
|
|
'theaters_outlined': Icons.theaters_outlined, // Cinema/Theater
|
|
'toys_outlined': Icons.toys_outlined, // Toys
|
|
'train_outlined': Icons.train_outlined, // Train Travel
|
|
'tram_outlined': Icons.tram_outlined, // Tram
|
|
'two_wheeler_outlined': Icons.two_wheeler_outlined, // Motorcycle/Scooter
|
|
'vape_free_outlined': Icons.vape_free_outlined, // Vaping (quit)
|
|
'vaping_rooms_outlined': Icons.vaping_rooms_outlined, // Vaping
|
|
'videogame_asset_outlined': Icons.videogame_asset_outlined, // Video Games
|
|
'water_drop_outlined': Icons.water_drop_outlined, // Water Bill
|
|
'wifi_outlined': Icons.wifi_outlined, // Internet Bill
|
|
'wine_bar_outlined': Icons.wine_bar_outlined, // Wine Bar
|
|
};
|
|
|
|
/// Returns the IconData corresponding to the given icon name string.
|
|
/// If the `iconName` is not found or is null/empty, returns a default fallback icon (`Icons.help_outline`).
|
|
static IconData getIconFromString(String? iconName) {
|
|
if (iconName == null || iconName.isEmpty) {
|
|
return Icons.help_outline; // Default for null or empty
|
|
}
|
|
return _stringToIconData[iconName] ?? Icons.help_outline; // Return default if not found in map
|
|
}
|
|
|
|
/// Returns a map of available icons for selection in UI (e.g., dropdowns, dialogs).
|
|
/// Excludes placeholder/internal icons like 'help_outline', 'label_outline',
|
|
/// 'category_outlined', and the special 'attach_money' (Income).
|
|
static Map<String, IconData> getAvailableIcons() {
|
|
final availableIcons = Map<String, IconData>.from(_stringToIconData);
|
|
// Remove icons not intended for user selection as expense categories
|
|
availableIcons.remove('help_outline'); // Internal fallback/error
|
|
availableIcons.remove('label_outline'); // Internal placeholder
|
|
availableIcons.remove('category_outlined'); // Internal generic fallback
|
|
availableIcons.remove('attach_money'); // Reserved for Income type
|
|
// Consider removing others if they represent internal states:
|
|
// availableIcons.remove('sync_alt_outlined'); // Transfers?
|
|
// availableIcons.remove('paid_outlined'); // Payments?
|
|
// availableIcons.remove('local_atm_outlined'); // ATM?
|
|
// availableIcons.remove('redeem_outlined'); // Gifts Received?
|
|
// availableIcons.remove('request_quote_outlined'); // Invoices?
|
|
// availableIcons.remove('analytics_outlined'); // Reports?
|
|
return availableIcons;
|
|
}
|
|
|
|
/// List of available colors for category selection in UI.
|
|
static const List<Color> availableColors = [
|
|
// Primary Colors (Good starting points)
|
|
Colors.red, Colors.pink, Colors.purple, Colors.deepPurple,
|
|
Colors.indigo, Colors.blue, Colors.lightBlue, Colors.cyan,
|
|
Colors.teal, Colors.green, Colors.lightGreen, Colors.lime,
|
|
Colors.yellow, Colors.amber, Colors.orange, Colors.deepOrange,
|
|
Colors.brown, Colors.grey, Colors.blueGrey,
|
|
|
|
// Accent Colors (Brighter, use with care)
|
|
Colors.redAccent, Colors.pinkAccent, Colors.purpleAccent, Colors.deepPurpleAccent,
|
|
Colors.indigoAccent, Colors.blueAccent, Colors.lightBlueAccent, Colors.cyanAccent,
|
|
Colors.tealAccent, Colors.greenAccent, Colors.limeAccent,
|
|
Colors.yellowAccent, Colors.amberAccent, Colors.orangeAccent, Colors.deepOrangeAccent,
|
|
|
|
// Shade variations (More subtle options)
|
|
/*Colors.red.shade300, Colors.pink.shade200, Colors.purple.shade300,
|
|
Colors.indigo.shade300, Colors.blue.shade300, Colors.lightBlue.shade300,
|
|
Colors.cyan.shade300, Colors.teal.shade300, Colors.green.shade300,
|
|
Colors.lightGreen.shade300, Colors.lime.shade300, Colors.yellow.shade600, // Darker yellow
|
|
Colors.amber.shade300, Colors.orange.shade300, Colors.deepOrange.shade300,
|
|
Colors.brown.shade300, Colors.grey.shade400, Colors.blueGrey.shade300,*/
|
|
];
|
|
}
|