diff --git a/lib/providers/apps_service.dart b/lib/providers/apps_service.dart index 6a10d8d..bd0ff81 100644 --- a/lib/providers/apps_service.dart +++ b/lib/providers/apps_service.dart @@ -185,7 +185,7 @@ class AppsService extends ChangeNotifier _initialized = true; notifyListeners(); - + // Pre-cache icons for visible apps _preCacheIcons(); } @@ -216,29 +216,29 @@ class AppsService extends ChangeNotifier } Future _initDefaultCategories() { - final tvApplications = _applications.values.where((application) => application.sideloaded == false); - final nonTvApplications = _applications.values.where((application) => application.sideloaded == true); + final tvApplications = + _applications.values.where((application) => !application.sideloaded); + final nonTvApplications = + _applications.values.where((application) => application.sideloaded); return _database.transaction(() async { if (nonTvApplications.isNotEmpty) { - int categoryId = await addCategory("Non-TV Apps", + int categoryId = await addCategory( + "Non-TV Apps", shouldNotifyListeners: false, ); Category nonTvAppsCategory = _categoriesById[categoryId]!; - for (final app in nonTvApplications) { - await addToCategory(app, nonTvAppsCategory, shouldNotifyListeners: false); - } + await addAppsToCategory(nonTvApplications, nonTvAppsCategory, + shouldNotifyListeners: false); } if (tvApplications.isNotEmpty) { int categoryId = await addCategory("TV Apps", - type: CategoryType.grid, shouldNotifyListeners: false - ); + type: CategoryType.grid, shouldNotifyListeners: false); Category tvAppsCategory = _categoriesById[categoryId]!; - for (final app in tvApplications) { - await addToCategory(app, tvAppsCategory, shouldNotifyListeners: false); - } + await addAppsToCategory(tvApplications, tvAppsCategory, + shouldNotifyListeners: false); } await addCategory("Favorites", shouldNotifyListeners: false); @@ -457,20 +457,36 @@ class AppsService extends ChangeNotifier Future startAmbientMode() => _fLauncherChannel.startAmbientMode(); - Future addToCategory(App app, Category category, {bool shouldNotifyListeners = true}) async { - int index = await _database.nextAppCategoryOrder(category.id) ?? 0; - await _database.insertAppsCategories([ - AppsCategoriesCompanion.insert( + Future addToCategory(App app, Category category, + {bool shouldNotifyListeners = true}) async { + await addAppsToCategory([app], category, + shouldNotifyListeners: shouldNotifyListeners); + } + + Future addAppsToCategory(Iterable apps, Category category, + {bool shouldNotifyListeners = true}) async { + if (apps.isEmpty) return; + + int nextIndex = await _database.nextAppCategoryOrder(category.id) ?? 0; + List companions = []; + + for (final app in apps) { + companions.add(AppsCategoriesCompanion.insert( categoryId: category.id, appPackageName: app.packageName, - order: index, - ) - ]); + order: nextIndex++, + )); + } - if (_categoriesById.containsKey(category.id)) { - Category categoryFound = _categoriesById[category.id]!; - app.categoryOrders[categoryFound.id] = index; - categoryFound.applications.add(app); + await _database.insertAppsCategories(companions); + + final categoryFound = _categoriesById[category.id]; + if (categoryFound != null) { + int index = nextIndex - apps.length; + for (final app in apps) { + app.categoryOrders[categoryFound.id] = index++; + categoryFound.applications.add(app); + } if (shouldNotifyListeners) { sortCategory(categoryFound); @@ -481,8 +497,8 @@ class AppsService extends ChangeNotifier Future removeFromCategory(App application, Category category) async { await _database.deleteAppCategory(category.id, application.packageName); - if (_categoriesById.containsKey(category.id)) { - Category categoryFound = _categoriesById[category.id]!; + final categoryFound = _categoriesById[category.id]; + if (categoryFound != null) { application.categoryOrders.remove(categoryFound.id); categoryFound.applications.remove(application); @@ -499,79 +515,80 @@ class AppsService extends ChangeNotifier return; } Category actualCategory = _categoriesById[category.id]!; - + Iterable appsToAdd; - + switch (actualCategory.name) { case 'TV Apps': - appsToAdd = _applications.values.where((app) => !app.sideloaded && !app.hidden); + appsToAdd = + _applications.values.where((app) => !app.sideloaded && !app.hidden); break; case 'Non-TV Apps': - appsToAdd = _applications.values.where((app) => app.sideloaded && !app.hidden); + appsToAdd = + _applications.values.where((app) => app.sideloaded && !app.hidden); break; default: return; // Not a special category } - - for (final app in appsToAdd) { - await addToCategory(app, actualCategory, shouldNotifyListeners: false); - } - + + await addAppsToCategory(appsToAdd, actualCategory, + shouldNotifyListeners: false); + notifyListeners(); } // === FAVORITES METHODS === - + /// Gets the Favorites category, creating it if it doesn't exist Future getOrCreateFavoritesCategory() async { // Look for existing Favorites category Category? favorites = _categoriesById.values.firstWhereOrNull( (category) => category.name == 'Favorites' ); - + if (favorites != null) { return favorites; } - + // Create Favorites category if it doesn't exist int categoryId = await addCategory('Favorites', shouldNotifyListeners: false); return _categoriesById[categoryId]!; } - + /// Checks if an app is in the Favorites category bool isAppInFavorites(App app) { Category? favorites = _categoriesById.values.firstWhereOrNull( (category) => category.name == 'Favorites' ); - + if (favorites == null) { return false; } - + return favorites.applications.any((a) => a.packageName == app.packageName); } - + /// Adds an app to Favorites Future addToFavorites(App app) async { Category favorites = await getOrCreateFavoritesCategory(); - + // Check if already in favorites if (!favorites.applications.any((a) => a.packageName == app.packageName)) { await addToCategory(app, favorites); } } - + /// Removes an app from Favorites Future removeFromFavorites(App app) async { Category? favorites = _categoriesById.values.firstWhereOrNull( (category) => category.name == 'Favorites' ); - + if (favorites != null) { await removeFromCategory(app, favorites); } } - + /// Toggles an app in/out of Favorites Future toggleFavorite(App app) async { if (isAppInFavorites(app)) { @@ -585,7 +602,7 @@ class AppsService extends ChangeNotifier if (!_categoriesById.containsKey(category.id)) { return; } - + Category categoryFound = _categoriesById[category.id]!; List applications = categoryFound.applications; List orderedAppCategories = []; @@ -635,10 +652,10 @@ class AppsService extends ChangeNotifier // Remove from current await removeFromCategory(app, currentCategory); - + // Set pending focus package so AppCard can reclaim focus and reorder mode _pendingReorderFocusPackage = app.packageName; - + // Add to target int newIndex = 0; if (direction == AxisDirection.up) { @@ -652,14 +669,14 @@ class AppsService extends ChangeNotifier // DB Insert Logic // 1. Get current items in target List targetApps = targetCategory.applications; - + // 2. Adjust local list if (direction == AxisDirection.down) { targetApps.insert(0, app); // Insert at top } else { targetApps.add(app); // Insert at bottom } - + // 3. Update orders for all items in target category List orderedAppCategories = []; for (int i = 0; i < targetApps.length; ++i) { @@ -671,10 +688,10 @@ class AppsService extends ChangeNotifier order: Value(i), )); } - + // 4. Batch DB update await _database.replaceAppsCategories(orderedAppCategories); - + notifyListeners(); } @@ -828,7 +845,7 @@ class AppsService extends ChangeNotifier else { await _database.deleteSpacer(section.id); } - + _launcherSections.removeAt(index); notifyListeners(); @@ -837,7 +854,7 @@ class AppsService extends ChangeNotifier void moveSectionInMemory(int oldIndex, int newIndex) { if (oldIndex < 0 || oldIndex >= _launcherSections.length || newIndex < 0 || newIndex >= _launcherSections.length) return; - + final section = _launcherSections.removeAt(oldIndex); _launcherSections.insert(newIndex, section); notifyListeners(); @@ -846,7 +863,7 @@ class AppsService extends ChangeNotifier Future persistSectionsOrder() async { List orderedCategories = []; List orderedSpacers = []; - + for (int i = 0; i < _launcherSections.length; ++i) { LauncherSection section = _launcherSections[i]; // Update the order property on the object itself