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

577 lines
9.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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:
```text
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:
```dart
final activities = await localMediaDb.loadActivities(...);
final ids = activities.map((entry) => entry.id).whereType<int>().toSet();
final previewPoints = await localMediaDb.loadActivityPreviewPointsByActivityIds(ids);
```
e anche:
```dart
final groups = ActivityGrouping.buildSportGroups(activities);
```
oppure:
```dart
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:
```dart
ActivityEntriesLoadResult
ActivityGroupsLoadResult<T>
ActivityDataLoader
```
***
## 1. `ActivityEntriesLoadResult`
Serve come contenitore per il risultato del caricamento della lista attività.
Contiene:
```dart
final List<ActivityEntry> entries;
final Map<int, List<ActivityPreviewPoint>> previewPointsByActivityId;
```
Quindi quando carichi la lista attività, il risultato contiene:
```text
entries
lista delle attività DB da mostrare
previewPointsByActivityId
mappa id attività → punti preview per disegnare la miniatura
```
Esempio concettuale:
```dart
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:
```dart
ActivitySportGroup
```
oppure:
```dart
ActivityAlbumGroup
```
Contiene:
```dart
final List<T> groups;
final Map<int, List<ActivityPreviewPoint>> previewPointsByActivityId;
```
Quindi per Sport restituisce:
```text
groups = lista di ActivitySportGroup
previewPointsByActivityId = preview della cover di ogni sport
```
Per Album restituisce:
```text
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:
```dart
ActivityDataLoader.loadEntries(...)
ActivityDataLoader.loadSportGroups()
ActivityDataLoader.loadAlbumGroups()
```
***
## Metodo 1 — `loadEntries(...)`
Firma:
```dart
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:
```dart
localMediaDb.loadActivities(
sport: withoutSportOnly ? null : sport,
directory: directory,
favourite: favouriteOnly ? true : null,
);
```
Quindi applica questi filtri:
```text
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é:
```dart
sport: null
```
di solito vuol dire:
```text
non filtrare per sport
```
non significa:
```text
dammi solo attività senza sport
```
Quindi il file fa un filtro manuale:
```dart
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:
```text
sport null
```
oppure:
```text
sport vuoto
```
***
### 3. Converte in lista
```dart
final entries = activities.toList();
```
Questo prepara i dati per la UI.
***
### 4. Carica i preview points
Prende gli ID attività:
```dart
final ids = entries
.map((entry) => entry.id)
.whereType<int>()
.toSet();
```
Poi carica le miniature:
```dart
final previewPoints =
await localMediaDb.loadActivityPreviewPointsByActivityIds(ids);
```
***
### 5. Ritorna tutto insieme
```dart
return ActivityEntriesLoadResult(
entries: entries,
previewPointsByActivityId: previewPoints,
);
```
Quindi `activity_files_page.dart` riceve già:
```text
lista attività + preview pronte
```
***
## Metodo 2 — `loadSportGroups()`
Firma:
```dart
static Future<ActivityGroupsLoadResult<ActivitySportGroup>> loadSportGroups()
```
Viene usato quando tocchi il tab **Sport**.
### Cosa fa
### 1. Carica tutte le attività
```dart
final activities = await localMediaDb.loadActivities();
```
Qui non applica filtri, perché deve costruire tutti i gruppi sport.
***
### 2. Costruisce i gruppi sport
Chiama:
```dart
final groups = ActivityGrouping.buildSportGroups(activities);
```
Questa logica sta in:
```text
lib/model/activity/activity_grouping.dart
```
e produce una lista tipo:
```text
Corsa 12 attività
Bici 8 attività
Camminata 3 attività
Senza sport 1 attività
```
Ogni gruppo ha:
```dart
displayName
sportFilter
withoutSport
count
coverEntry
```
***
### 3. Carica preview della cover
Per ogni gruppo prende la `coverEntry`, cioè l’attività usata come thumbnail:
```dart
final ids = groups
.map((group) => group.coverEntry?.id)
.whereType<int>()
.toSet();
```
Poi carica preview points:
```dart
final previewPoints =
await localMediaDb.loadActivityPreviewPointsByActivityIds(ids);
```
***
### 4. Ritorna gruppi + preview
```dart
return ActivityGroupsLoadResult<ActivitySportGroup>(
groups: groups,
previewPointsByActivityId: previewPoints,
);
```
***
## Metodo 3 — `loadAlbumGroups()`
Firma:
```dart
static Future<ActivityGroupsLoadResult<ActivityAlbumGroup>> loadAlbumGroups()
```
Viene usato quando tocchi il tab **Album**.
### Cosa fa
### 1. Carica tutte le attività
```dart
final activities = await localMediaDb.loadActivities();
```
***
### 2. Costruisce i gruppi album
Chiama:
```dart
final groups = ActivityGrouping.buildAlbumGroups(activities);
```
Questa logica crea gruppi usando:
```dart
entry.directoryName
entry.relativePath
```
Quindi produce card tipo:
```text
Activity
main
Garmin
Zepp
Strava
```
Ogni gruppo ha:
```dart
displayName
directoryFilter
count
coverEntry
```
***
### 3. Carica preview della cover
Come per gli sport:
```dart
final ids = groups
.map((group) => group.coverEntry?.id)
.whereType<int>()
.toSet();
```
Poi:
```dart
final previewPoints =
await localMediaDb.loadActivityPreviewPointsByActivityIds(ids);
```
***
### 4. Ritorna gruppi + preview
```dart
return ActivityGroupsLoadResult<ActivityAlbumGroup>(
groups: groups,
previewPointsByActivityId: previewPoints,
);
```
***
# Come viene usato in `activity_files_page.dart`
Ora `_loadDbActivities()` è molto più pulito:
```dart
final result = await ActivityDataLoader.loadEntries(
favouriteOnly: _activityFavouriteOnly,
withoutSportOnly: _activityWithoutSportOnly,
sport: _activitySportFilter,
directory: _activityDirectoryFilter,
);
```
Poi aggiorna lo state:
```dart
_dbActivities
..clear()
..addAll(result.entries);
_dbPreviewPoints
..clear()
..addAll(result.previewPointsByActivityId);
```
***
Per Sport:
```dart
final result = await ActivityDataLoader.loadSportGroups();
```
Poi:
```dart
_sportGroups
..clear()
..addAll(result.groups);
_dbPreviewPoints
..clear()
..addAll(result.previewPointsByActivityId);
```
***
Per Album:
```dart
final result = await ActivityDataLoader.loadAlbumGroups();
```
Poi:
```dart
_albumGroups
..clear()
..addAll(result.groups);
_dbPreviewPoints
..clear()
..addAll(result.previewPointsByActivityId);
```
***
# In sintesi breve
`activity_data_loader.dart` è il file che dice:
```text
"Dammi i dati pronti da mostrare nella UI Activity"
```
Fa da ponte tra:
```text
DB / grouping / preview points
```
e:
```text
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**:
```text
caricare attività
filtrare senza sport
costruire gruppi
recuperare preview
```
Sa solo:
```dart
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.