9.3 KiB
Sì Fabio.
lib/widgets/activity/activity_data_loader.dart è un helper di caricamento dati per la pagina Activity.
In pratica serve a togliere da activity_files_page.dart tutta la logica ripetitiva di:
1. leggere attività dal DB
2. applicare filtri
3. caricare preview points
4. costruire gruppi Sport
5. costruire gruppi Album
6. restituire un risultato pronto per la UI
Perché lo abbiamo creato
Prima activity_files_page.dart faceva direttamente cose tipo:
final activities = await localMediaDb.loadActivities(...);
final ids = activities.map((entry) => entry.id).whereType<int>().toSet();
final previewPoints = await localMediaDb.loadActivityPreviewPointsByActivityIds(ids);
e anche:
final groups = ActivityGrouping.buildSportGroups(activities);
oppure:
final groups = ActivityGrouping.buildAlbumGroups(activities);
Ora invece quella logica sta dentro ActivityDataLoader, così activity_files_page.dart resta più pulito.
Cosa contiene activity_data_loader.dart
Il file contiene tre classi principali:
ActivityEntriesLoadResult
ActivityGroupsLoadResult<T>
ActivityDataLoader
1. ActivityEntriesLoadResult
Serve come contenitore per il risultato del caricamento della lista attività.
Contiene:
final List<ActivityEntry> entries;
final Map<int, List<ActivityPreviewPoint>> previewPointsByActivityId;
Quindi quando carichi la lista attività, il risultato contiene:
entries
lista delle attività DB da mostrare
previewPointsByActivityId
mappa id attività → punti preview per disegnare la miniatura
Esempio concettuale:
ActivityEntriesLoadResult(
entries: [activity1, activity2, activity3],
previewPointsByActivityId: {
1: [point1, point2, point3],
2: [point1, point2, point3],
},
)
2. ActivityGroupsLoadResult<T>
Serve come contenitore generico per i gruppi.
È generico perché può contenere:
ActivitySportGroup
oppure:
ActivityAlbumGroup
Contiene:
final List<T> groups;
final Map<int, List<ActivityPreviewPoint>> previewPointsByActivityId;
Quindi per Sport restituisce:
groups = lista di ActivitySportGroup
previewPointsByActivityId = preview della cover di ogni sport
Per Album restituisce:
groups = lista di ActivityAlbumGroup
previewPointsByActivityId = preview della cover di ogni album
3. ActivityDataLoader
È la classe utility vera e propria.
Ha solo metodi statici, quindi non la istanzi:
ActivityDataLoader.loadEntries(...)
ActivityDataLoader.loadSportGroups()
ActivityDataLoader.loadAlbumGroups()
Metodo 1 — loadEntries(...)
Firma:
static Future<ActivityEntriesLoadResult> loadEntries({
required bool favouriteOnly,
required bool withoutSportOnly,
String? sport,
String? directory,
})
Questo metodo carica la lista attività normale.
Viene usato da activity_files_page.dart dentro _loadDbActivities().
Cosa fa passo per passo
1. Legge attività dal DB
Chiama:
localMediaDb.loadActivities(
sport: withoutSportOnly ? null : sport,
directory: directory,
favourite: favouriteOnly ? true : null,
);
Quindi applica questi filtri:
favouriteOnly → solo preferiti
sport → solo uno sport specifico
directory → solo un album/cartella specifica
withoutSportOnly → caso speciale per attività senza sport
2. Gestisce il caso “Senza sport”
Questo caso è speciale.
Perché:
sport: null
di solito vuol dire:
non filtrare per sport
non significa:
dammi solo attività senza sport
Quindi il file fa un filtro manuale:
if (withoutSportOnly) {
activities = activities.where((entry) {
final sport = entry.sport?.trim();
return sport == null || sport.isEmpty;
});
}
Così quando tocchi la card Senza sport, mostra solo attività con:
sport null
oppure:
sport vuoto
3. Converte in lista
final entries = activities.toList();
Questo prepara i dati per la UI.
4. Carica i preview points
Prende gli ID attività:
final ids = entries
.map((entry) => entry.id)
.whereType<int>()
.toSet();
Poi carica le miniature:
final previewPoints =
await localMediaDb.loadActivityPreviewPointsByActivityIds(ids);
5. Ritorna tutto insieme
return ActivityEntriesLoadResult(
entries: entries,
previewPointsByActivityId: previewPoints,
);
Quindi activity_files_page.dart riceve già:
lista attività + preview pronte
Metodo 2 — loadSportGroups()
Firma:
static Future<ActivityGroupsLoadResult<ActivitySportGroup>> loadSportGroups()
Viene usato quando tocchi il tab Sport.
Cosa fa
1. Carica tutte le attività
final activities = await localMediaDb.loadActivities();
Qui non applica filtri, perché deve costruire tutti i gruppi sport.
2. Costruisce i gruppi sport
Chiama:
final groups = ActivityGrouping.buildSportGroups(activities);
Questa logica sta in:
lib/model/activity/activity_grouping.dart
e produce una lista tipo:
Corsa 12 attività
Bici 8 attività
Camminata 3 attività
Senza sport 1 attività
Ogni gruppo ha:
displayName
sportFilter
withoutSport
count
coverEntry
3. Carica preview della cover
Per ogni gruppo prende la coverEntry, cioè l’attività usata come thumbnail:
final ids = groups
.map((group) => group.coverEntry?.id)
.whereType<int>()
.toSet();
Poi carica preview points:
final previewPoints =
await localMediaDb.loadActivityPreviewPointsByActivityIds(ids);
4. Ritorna gruppi + preview
return ActivityGroupsLoadResult<ActivitySportGroup>(
groups: groups,
previewPointsByActivityId: previewPoints,
);
Metodo 3 — loadAlbumGroups()
Firma:
static Future<ActivityGroupsLoadResult<ActivityAlbumGroup>> loadAlbumGroups()
Viene usato quando tocchi il tab Album.
Cosa fa
1. Carica tutte le attività
final activities = await localMediaDb.loadActivities();
2. Costruisce i gruppi album
Chiama:
final groups = ActivityGrouping.buildAlbumGroups(activities);
Questa logica crea gruppi usando:
entry.directoryName
entry.relativePath
Quindi produce card tipo:
Activity
main
Garmin
Zepp
Strava
Ogni gruppo ha:
displayName
directoryFilter
count
coverEntry
3. Carica preview della cover
Come per gli sport:
final ids = groups
.map((group) => group.coverEntry?.id)
.whereType<int>()
.toSet();
Poi:
final previewPoints =
await localMediaDb.loadActivityPreviewPointsByActivityIds(ids);
4. Ritorna gruppi + preview
return ActivityGroupsLoadResult<ActivityAlbumGroup>(
groups: groups,
previewPointsByActivityId: previewPoints,
);
Come viene usato in activity_files_page.dart
Ora _loadDbActivities() è molto più pulito:
final result = await ActivityDataLoader.loadEntries(
favouriteOnly: _activityFavouriteOnly,
withoutSportOnly: _activityWithoutSportOnly,
sport: _activitySportFilter,
directory: _activityDirectoryFilter,
);
Poi aggiorna lo state:
_dbActivities
..clear()
..addAll(result.entries);
_dbPreviewPoints
..clear()
..addAll(result.previewPointsByActivityId);
Per Sport:
final result = await ActivityDataLoader.loadSportGroups();
Poi:
_sportGroups
..clear()
..addAll(result.groups);
_dbPreviewPoints
..clear()
..addAll(result.previewPointsByActivityId);
Per Album:
final result = await ActivityDataLoader.loadAlbumGroups();
Poi:
_albumGroups
..clear()
..addAll(result.groups);
_dbPreviewPoints
..clear()
..addAll(result.previewPointsByActivityId);
In sintesi breve
activity_data_loader.dart è il file che dice:
"Dammi i dati pronti da mostrare nella UI Activity"
Fa da ponte tra:
DB / grouping / preview points
e:
ActivityFilesPage / UI
Responsabilità attuale
| Metodo | Cosa carica | Usato da |
|---|---|---|
loadEntries(...) |
Lista attività filtrata + preview | tab Attività, Preferiti, Sport selezionato, Album selezionato |
loadSportGroups() |
Gruppi sport + cover preview | tab Sport |
loadAlbumGroups() |
Gruppi album + cover preview | tab Album |
Perché è utile
Perché adesso activity_files_page.dart non deve più sapere come:
caricare attività
filtrare senza sport
costruire gruppi
recuperare preview
Sa solo:
final result = await ActivityDataLoader.loadEntries(...);
Quindi sarà più facile in futuro:
- aggiungere ordinamenti;
- aggiungere statistiche per gruppo;
- aggiungere cache;
- aggiungere paginazione;
- cambiare logica DB;
- trasformare la lista in griglia senza toccare il caricamento dati.