Aves_mio0.88/activity3.md
2026-10-03 12:51:15 +02:00

9.3 KiB
Raw Blame History

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.