import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'api.dart'; import '../models/task_type.dart'; /// Centralized preload cache for app startup optimization class PreloadCache { static const _keyTaskTypes = 'preload_task_types'; static const _keyTaskTypesTimestamp = 'preload_task_types_ts'; static const _cacheDuration = Duration(hours: 12); // In-memory cache for current session static Map> _taskTypesCache = {}; /// Preload all cacheable data during splash /// Note: Task types require a business ID, so they're loaded on-demand per business static Future preloadAll() async { debugPrint('[PreloadCache] Preload cache initialized'); // Future: Add any global preloads here } /// Get or fetch task types for a business static Future> getTaskTypes(int businessId) async { // Check in-memory cache first if (_taskTypesCache.containsKey(businessId)) { return _taskTypesCache[businessId]!; } // Check disk cache final cached = await _loadTaskTypesFromDisk(businessId); if (cached != null) { _taskTypesCache[businessId] = cached; // Refresh in background _refreshTaskTypesInBackground(businessId); return cached; } // Fetch from server final types = await Api.getTaskTypes(businessId: businessId); _taskTypesCache[businessId] = types; await _saveTaskTypesToDisk(businessId, types); return types; } /// Preload task types for a specific business (call when entering a business) static Future preloadTaskTypes(int businessId) async { if (_taskTypesCache.containsKey(businessId)) return; try { final types = await Api.getTaskTypes(businessId: businessId); _taskTypesCache[businessId] = types; await _saveTaskTypesToDisk(businessId, types); debugPrint('[PreloadCache] Preloaded ${types.length} task types for business $businessId'); } catch (e) { debugPrint('[PreloadCache] Failed to preload task types: $e'); } } static void _refreshTaskTypesInBackground(int businessId) { Api.getTaskTypes(businessId: businessId).then((types) { _taskTypesCache[businessId] = types; _saveTaskTypesToDisk(businessId, types); }).catchError((e) { debugPrint('[PreloadCache] Task types refresh failed: $e'); }); } static Future?> _loadTaskTypesFromDisk(int businessId) async { final prefs = await SharedPreferences.getInstance(); final key = '${_keyTaskTypes}_$businessId'; final tsKey = '${_keyTaskTypesTimestamp}_$businessId'; final ts = prefs.getInt(tsKey); final data = prefs.getString(key); if (ts == null || data == null) return null; if (DateTime.now().difference(DateTime.fromMillisecondsSinceEpoch(ts)) > _cacheDuration) { return null; } try { final list = jsonDecode(data) as List; return list.map((j) => TaskType.fromJson(j as Map)).toList(); } catch (e) { return null; } } static Future _saveTaskTypesToDisk(int businessId, List types) async { final prefs = await SharedPreferences.getInstance(); final key = '${_keyTaskTypes}_$businessId'; final tsKey = '${_keyTaskTypesTimestamp}_$businessId'; final data = types.map((t) => { 'tasktypeid': t.taskTypeId, 'tasktypename': t.taskTypeName, 'tasktypeicon': t.taskTypeIcon, }).toList(); await prefs.setString(key, jsonEncode(data)); await prefs.setInt(tsKey, DateTime.now().millisecondsSinceEpoch); } /// Clear all caches static Future clearAll() async { _taskTypesCache.clear(); final prefs = await SharedPreferences.getInstance(); final keys = prefs.getKeys().where((k) => k.startsWith('preload_')); for (final key in keys) { await prefs.remove(key); } } }