# app-data-smart

App mobile della piattaforma MyTown (Ionic/Angular + Capacitor).

Componente della piattaforma open source **MyTown** (gruppo `mytown-agpl-v3`; documentazione, installazione e architettura nel repository `platform`).

Il progetto MyTown e' realizzato da **Kondor CS Srl** con il supporto di **CNA Teramo** ed e' cofinanziato dall'**Unione Europea** - PR FESR Abruzzo 2021-2027, Intervento 1.1.1.1 "Sostegno a progetti di Ricerca e Innovazione" (Det. DPH006/182 del 23/07/2024). Sito del progetto: <https://www.mytown.tech>.

**Licenza**: GNU AGPL v3 (vedi `LICENSE`). Copyright (C) Kondor Consulting & Services S.r.l. Licenze commerciali e note sui marchi: `LICENSING.md` e `TRADEMARKS.md` nel repository `platform`.

---

# App DataSmart - Note di sviluppo

---

## Rubrica telefono (WhatsApp-like contacts matching)

### Cosa fa

Quando l'utente apre la chat messaggi, l'app legge i contatti della rubrica del dispositivo e sostituisce il nome/cognome degli altri utenti con il nome salvato in rubrica, se il numero di telefono combacia. Funziona esattamente come WhatsApp.

I contatti vengono letti **solo localmente** — non vengono mai inviati al server.

### Come funziona il flusso

1. **Prima apertura di Messaggi** → appare una modale personalizzata (stile geolocation) che spiega cosa fa la rubrica e chiede il consenso
2. **Utente accetta la modale** → viene richiesto il permesso Android/iOS (`requestPermissions()`)
3. **Utente concede il permesso** → i contatti vengono caricati in memoria in una `Map<phone → nome>` e il flag `contacts_permission_granted` viene salvato in `localStorage`
4. **Avvii successivi** → se il flag è presente, i contatti vengono ricaricati silenziosamente all'avvio senza mostrare alcun dialog
5. **Utente disabilita la rubrica** (dal profilo) → la mappa viene svuotata e i flag vengono rimossi; la modale si ripresenterà alla prossima apertura di Messaggi

### Matching numeri di telefono

- Il numero è `usr_username` dell'utente (chi si registra con il telefono usa il numero come username)
- Normalizzazione: solo cifre, niente prefisso/spazi/trattini
- Fallback suffix matching: confronta gli ultimi 8 cifre per gestire varianti di prefisso internazionale

### File coinvolti

| File | Ruolo |
| ---- | ----- |
| `src/app/providers/contacts.service.ts` | Servizio principale: permessi, caricamento, matching |
| `src/app/pages/messaging/messaging.page.ts` | Mostra la modale di consenso, chiama `requestAndLoad()` |
| `src/app/pages/messaging/messaging.page.html` | Modale con anteprima funzionalità e animazione |
| `src/app/pages/messaging/messaging.page.scss` | Stili modale (classi `.ctc-*`) |
| `src/app/pages/messaging/chat/messaging-chat.page.ts` | Usa `getNameByPhone()` per label mittente |
| `src/app/pages/profilo/profilo.page.ts` | Gestione stato rubrica nelle impostazioni profilo |
| `src/app/pages/profilo/profilo.page.html` | Sezione "Rubrica telefono" con stato e bottone Disabilita |
| `android/app/src/main/AndroidManifest.xml` | Permessi `READ_CONTACTS` e `WRITE_CONTACTS` |

### Permessi Android

```xml
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
```

**Importante:** `npx cap sync` non aggiunge questi permessi automaticamente (il manifest del plugin è vuoto). Vanno mantenuti manualmente in `AndroidManifest.xml`. Sono stati anche aggiunti nel manifest del plugin (`node_modules/@capacitor-community/contacts/android/src/main/AndroidManifest.xml`) ma vengono persi con `npm install`.

### Problemi noti / soluzioni applicate

**`checkPermissions()` restituisce 'denied' anche se il permesso è concesso** (bug su alcuni Android)

→ Soluzione: non usare `checkPermissions()` come gate per `getContacts()`. Usare un flag `contacts_permission_granted` in `localStorage` che viene impostato solo dopo che `requestPermissions()` restituisce 'granted'. `getContacts()` viene chiamato solo se quel flag è presente.

**Loop infinito: `getContacts()` scatena `appStateChange`** (comportamento Android)

→ Soluzione: guard di rientranza `isLoadingContacts` in `loadContacts()` + controllo `phoneMap.size > 0` e `status === 'loading'` nel listener `appStateChange`.

**`requestPermissions()` durante il dialog causa `appStateChange`**

→ Soluzione: il listener salta se `statusSubject.value === 'loading'` (stato impostato da `requestAndLoad()` prima di chiamare `requestPermissions()`).

---

## @capawesome/capacitor-file-picker

### Android

#### Permissions

Questa API richiede di aggiungere le seguenti autorizzazioni al file `AndroidManifest.xml` **prima o dopo** il tag `application`:

```xml
<!-- Necessario se vuoi recuperare i metadati EXIF non redatti dalle foto -->
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />

<!-- Necessario se vuoi leggere file dalla memoria esterna -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
```

### iOS

#### Entitlements

Per usare questo plugin con Mac Catalyst, la tua app deve avere abilitato il seguente entitlement:

```xml
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
```

Questo consente all'app di leggere i file selezionati dall'utente. Se non vuoi usare il plugin con Mac Catalyst, puoi saltare questo passaggio.
