438 lines
13 KiB
Markdown
438 lines
13 KiB
Markdown
# Segnapunti - Anto
|
||
|
||
Un'applicazione web segnapunti per pallavolo con funzionalità di sintesi vocale, modalità formazione e supporto PWA (Progressive Web App).
|
||
|
||
## Cos'è
|
||
|
||
Segnapunti è un'applicazione standalone per tenere il punteggio durante le partite di pallavolo. L'applicazione è ottimizzata per dispositivi mobili in modalità landscape (orizzontale) e può essere installata come app nativa grazie al supporto PWA.
|
||
|
||
### Caratteristiche principali
|
||
|
||
- **Segnapunti digitale**: Visualizzazione chiara del punteggio per le due squadre (Home e Guest)
|
||
- **Contatore set**: Traccia i set vinti da ciascuna squadra (fino a 3 set)
|
||
- **Indicatore battuta**: Mostra quale squadra ha il servizio
|
||
- **Modalità formazione**: Visualizza la rotazione dei giocatori in campo (posizioni 1-6)
|
||
- **Sintesi vocale**: Annuncia il punteggio in italiano
|
||
- **PWA**: Installabile come app standalone con funzionamento offline
|
||
- **Controllo da tastiera**: Scorciatoie per gestire rapidamente il punteggio
|
||
- **No Sleep**: Impedisce allo schermo di spegnersi durante l'uso
|
||
- **Fullscreen automatico**: Su dispositivi mobili si avvia a schermo intero
|
||
|
||
## Come funziona
|
||
|
||
### Interfaccia
|
||
|
||
L'applicazione divide lo schermo in due metà :
|
||
|
||
- **Metà sinistra (gialla su sfondo nero)**: Squadra Home - Antoniana
|
||
- **Metà destra (bianca su sfondo blu)**: Squadra Guest
|
||
|
||
#### Visualizzazioni
|
||
|
||
1. **Modalità Punteggio** (default):
|
||
- Mostra il punteggio corrente in caratteri molto grandi
|
||
- Cliccando sul punteggio si incrementa di 1
|
||
- Cliccando sul nome della squadra si decrementa di 1
|
||
|
||
2. **Modalità Formazione**:
|
||
- Mostra le posizioni dei giocatori in campo (1-6)
|
||
- La formazione ruota automaticamente quando si incrementa il punteggio
|
||
- L'ordine visualizzato è: [3, 2, 1, 4, 5, 0] (ordine inverso rispetto alla rotazione standard)
|
||
|
||
#### FunzionalitÃ
|
||
|
||
- **Reset**: Azzera punteggio e formazioni, mantiene i nomi delle squadre
|
||
- **Cambio servizio**: Toggle manuale del servizio tra le squadre
|
||
- **Configurazione nomi**: Dialog per modificare i nomi delle squadre
|
||
- **Sintesi vocale**:
|
||
- Pronuncia il punteggio in italiano
|
||
- Se 0-0 dice "zero a zero"
|
||
- Se pari dice "[punteggio] pari"
|
||
- Altrimenti annuncia prima il punteggio della squadra al servizio
|
||
- **Incremento set**: Click sul contatore set per aumentarlo (si azzera dopo 2)
|
||
|
||
### Controlli da tastiera
|
||
|
||
- **Ctrl + M**: Apri dialog configurazione nomi
|
||
- **Ctrl + B**: Mostra/nascondi barra pulsanti in basso
|
||
- **Ctrl + F**: Attiva modalità fullscreen
|
||
- **Ctrl + S**: Pronuncia il punteggio
|
||
- **Ctrl + Z**: Alterna tra modalità punteggio e formazione
|
||
- **Ctrl + ↑**: Incrementa punteggio Home
|
||
- **Ctrl + ↓**: Decrementa punteggio Home
|
||
- **Ctrl + →**: Incrementa set Home
|
||
- **Shift + ↑**: Incrementa punteggio Guest
|
||
- **Shift + ↓**: Decrementa punteggio Guest
|
||
- **Shift + →**: Incrementa set Guest
|
||
- **Ctrl + â†**: Cambia servizio
|
||
|
||
### Comportamento su mobile
|
||
|
||
Su dispositivi mobili l'applicazione:
|
||
1. Attiva automaticamente NoSleep per impedire lo spegnimento dello schermo
|
||
2. Si avvia in modalità fullscreen
|
||
3. Esegue un test di sintesi vocale al caricamento
|
||
4. Mostra il pulsante "Esci" per chiudere l'app
|
||
|
||
## Stack tecnologico
|
||
|
||
### Framework e librerie
|
||
|
||
- **Vue 3** (^3.2.47): Framework JavaScript progressivo per l'interfaccia utente
|
||
- **Vite** (^4.3.9): Build tool moderno e veloce
|
||
- **Wave UI** (^3.3.0): Libreria di componenti UI per Vue
|
||
- **NoSleep.js** (^0.12.0): Previene lo spegnimento automatico dello schermo
|
||
- **vite-plugin-pwa** (^0.16.0): Plugin per generare la PWA
|
||
|
||
### API Web utilizzate
|
||
|
||
- **Web Speech API**: Per la sintesi vocale (Text-to-Speech)
|
||
- **Fullscreen API**: Per la modalità schermo intero
|
||
- **Service Worker**: Per il funzionamento offline (PWA)
|
||
|
||
## Come svilupparlo
|
||
|
||
### Prerequisiti
|
||
|
||
- **Node.js** (versione 14 o superiore, raccomandata v20.2.0)
|
||
- **npm** o **yarn**
|
||
|
||
### Installazione
|
||
|
||
1. Clona il repository:
|
||
|
||
2. Installa le dipendenze:
|
||
```bash
|
||
npm install
|
||
```
|
||
|
||
### Comandi di sviluppo
|
||
|
||
#### Avviare il server di sviluppo
|
||
```bash
|
||
npm run dev
|
||
```
|
||
Questo comando avvia Vite in modalità development. L'applicazione sarà disponibile su `http://localhost:5173` (o altra porta se già occupata).
|
||
|
||
#### Build per produzione
|
||
```bash
|
||
npm run build
|
||
```
|
||
Genera i file ottimizzati per la produzione nella cartella `dist/`. Include:
|
||
- Minificazione del codice
|
||
- Tree-shaking per rimuovere codice non utilizzato
|
||
- Generazione del Service Worker per la PWA
|
||
- Generazione del manifest per l'installazione
|
||
|
||
#### Anteprima build di produzione
|
||
```bash
|
||
npm run preview
|
||
```
|
||
Avvia un server locale per testare la build di produzione.
|
||
|
||
La configurazione PWA si trova in [vite.config.js](vite.config.js:10-32):
|
||
|
||
- **Display**: fullscreen
|
||
- **Orientamento**: landscape (orizzontale)
|
||
- **Colore tema**: bianco
|
||
- **Base path**: `/segnap` in produzione, `/` in sviluppo
|
||
|
||
### Modifiche comuni
|
||
|
||
#### Cambiare i colori delle squadre
|
||
|
||
Modifica il file [src/style.css](src/style.css:101-108):
|
||
```css
|
||
.home {
|
||
background-color: black;
|
||
color: yellow;
|
||
}
|
||
.guest {
|
||
background-color: blue;
|
||
color: white;
|
||
}
|
||
```
|
||
|
||
#### Modificare i nomi predefiniti
|
||
|
||
Nel file [src/components/HomePage.vue](src/components/HomePage.vue:20), modifica:
|
||
```javascript
|
||
nomi: { home: "Antoniana", guest: "Guest" }
|
||
```
|
||
|
||
#### Cambiare la voce della sintesi vocale
|
||
|
||
Nel file [src/components/HomePage.vue](src/components/HomePage.vue:104), modifica:
|
||
```javascript
|
||
msg.voice = voices.find(voice => voice.name === 'Google italiano');
|
||
```
|
||
|
||
#### Modificare l'ordine di visualizzazione delle formazioni
|
||
|
||
Nel template del componente [src/components/HomePage.vue](src/components/HomePage.vue:181), l'ordine di visualizzazione delle posizioni è controllato dall'array nell'attributo `v-for`. La sequenza `[3, 2, 1, 4, 5, 0]` rappresenta l'ordine in cui vengono mostrate le posizioni dei giocatori sulla griglia 2x3 del campo.
|
||
|
||
Per modificare l'ordine di visualizzazione, modifica questo array:
|
||
```vue
|
||
<div class="formdiv" v-for="x in [3, 2, 1, 4, 5, 0]">
|
||
{{ sp.form.home[x] }}
|
||
</div>
|
||
```
|
||
|
||
L'ordine attuale mostra le posizioni in questo schema:
|
||
```
|
||
3 2 1
|
||
4 5 0
|
||
```
|
||
|
||
Dove 0 corrisponde alla posizione 1 nel pallavolo, 1 alla posizione 2, e così via.
|
||
|
||
## Testing e Deploy
|
||
|
||
### Testing su dispositivi mobili
|
||
|
||
Per testare l'applicazione su dispositivi mobili nella stessa rete locale:
|
||
|
||
1. Avvia il server di sviluppo:
|
||
```bash
|
||
npm run dev
|
||
```
|
||
|
||
2. Vite mostrerà l'indirizzo locale e di rete. Se non viene mostrato, trova l'indirizzo IP del tuo computer:
|
||
```bash
|
||
# Su Linux/Mac
|
||
hostname -I
|
||
# oppure
|
||
ifconfig | grep "inet "
|
||
|
||
# Su Windows
|
||
ipconfig
|
||
```
|
||
|
||
3. Dal dispositivo mobile, connesso alla stessa rete Wi-Fi, naviga su:
|
||
```
|
||
http://[tuo-ip]:5173
|
||
```
|
||
|
||
4. Accetta eventuali permessi richiesti dal browser per:
|
||
- Modalità fullscreen
|
||
- Sintesi vocale
|
||
- Wake Lock (prevenzione spegnimento schermo)
|
||
|
||
### Build e Deploy
|
||
|
||
#### Build per produzione
|
||
|
||
Genera i file ottimizzati per la produzione:
|
||
```bash
|
||
npm run build
|
||
```
|
||
|
||
Questo comando crea una cartella `dist/` contenente:
|
||
- HTML, CSS e JavaScript minificati
|
||
- Service Worker per il funzionamento offline
|
||
- Manifest PWA per l'installazione come app
|
||
- Asset ottimizzati
|
||
|
||
#### Anteprima della build
|
||
|
||
Prima del deploy, puoi testare la build in locale:
|
||
```bash
|
||
npm run preview
|
||
```
|
||
|
||
#### Deploy su GitHub Pages
|
||
|
||
1. Nel file [vite.config.js](vite.config.js:7), verifica che il `base` path corrisponda al nome del repository:
|
||
```javascript
|
||
base: process.env.NODE_ENV === 'production' ? '/nome-repository' : '/',
|
||
```
|
||
|
||
2. Esegui la build:
|
||
```bash
|
||
npm run build
|
||
```
|
||
|
||
3. Publica il contenuto della cartella `dist/` su GitHub Pages usando uno di questi metodi:
|
||
- Manualmente tramite l'interfaccia GitHub
|
||
- Usando `gh-pages`:
|
||
```bash
|
||
npm install -D gh-pages
|
||
npx gh-pages -d dist
|
||
```
|
||
- Tramite GitHub Actions (configurando un workflow)
|
||
|
||
#### Deploy su server web
|
||
|
||
Il contenuto della cartella `dist/` può essere servito da qualsiasi server web statico:
|
||
|
||
**Nginx:**
|
||
```nginx
|
||
server {
|
||
listen 80;
|
||
server_name tuo-dominio.com;
|
||
root /percorso/a/dist;
|
||
index index.html;
|
||
|
||
location / {
|
||
try_files $uri $uri/ /index.html;
|
||
}
|
||
}
|
||
```
|
||
|
||
**Apache (.htaccess):**
|
||
```apache
|
||
<IfModule mod_rewrite.c>
|
||
RewriteEngine On
|
||
RewriteBase /
|
||
RewriteRule ^index\.html$ - [L]
|
||
RewriteCond %{REQUEST_FILENAME} !-f
|
||
RewriteCond %{REQUEST_FILENAME} !-d
|
||
RewriteRule . /index.html [L]
|
||
</IfModule>
|
||
```
|
||
|
||
#### Installazione come PWA
|
||
|
||
Dopo il deploy, gli utenti possono installare l'app:
|
||
|
||
**Su Android/Chrome:**
|
||
1. Visita il sito
|
||
2. Tocca il menu (â‹®) > "Aggiungi a schermata Home"
|
||
3. L'app si avvierà in modalità fullscreen standalone
|
||
|
||
**Su iOS/Safari:**
|
||
1. Visita il sito
|
||
2. Tocca il pulsante Condividi
|
||
3. Seleziona "Aggiungi a Home"
|
||
|
||
## Dettagli tecnici
|
||
|
||
### Architettura del componente
|
||
|
||
L'applicazione è strutturata come Single Page Application (SPA) con un unico componente principale `HomePage`. Questo design semplice è ideale per un'app focalizzata su un'unica funzionalità .
|
||
|
||
### Gestione dello stato
|
||
|
||
Lo stato dell'applicazione è gestito localmente nel componente tramite `data()`:
|
||
- `punt`: punteggio corrente delle due squadre
|
||
- `set`: numero di set vinti
|
||
- `servHome`: boolean che indica quale squadra ha il servizio
|
||
- `form`: array con le posizioni dei giocatori (1-6)
|
||
- `nomi`: nomi personalizzabili delle squadre
|
||
- `visuForm`: toggle tra visualizzazione punteggio/formazione
|
||
- `visuButt`: visibilità della barra dei pulsanti
|
||
|
||
### Gestione della rotazione
|
||
|
||
La rotazione dei giocatori segue le regole del pallavolo:
|
||
|
||
**Incremento punteggio** ([HomePage.vue:74-78](src/components/HomePage.vue:74-78)):
|
||
```javascript
|
||
incPunt(team) {
|
||
this.sp.punt[team]++;
|
||
this.sp.servHome = (team == "home");
|
||
this.sp.form[team].push(this.sp.form[team].shift());
|
||
}
|
||
```
|
||
- Il servizio passa alla squadra che ha segnato
|
||
- La rotazione avviene con `push(shift())`: il primo elemento va in fondo
|
||
- Simula la rotazione oraria dei giocatori
|
||
|
||
**Decremento punteggio** ([HomePage.vue:79-85](src/components/HomePage.vue:79-85)):
|
||
```javascript
|
||
decPunt(team) {
|
||
if (this.sp.punt[team] > 0) {
|
||
this.sp.punt[team]--;
|
||
this.sp.form[team].unshift(this.sp.form[team].pop());
|
||
}
|
||
}
|
||
```
|
||
- La rotazione inversa avviene con `unshift(pop())`: l'ultimo elemento va all'inizio
|
||
- Permette di annullare errori di punteggio
|
||
|
||
### Sintesi vocale
|
||
|
||
La funzione `speak()` ([HomePage.vue:86-112](src/components/HomePage.vue:86-112)) utilizza la Web Speech API:
|
||
|
||
```javascript
|
||
const msg = new SpeechSynthesisUtterance();
|
||
msg.lang = 'it_IT';
|
||
msg.voice = voices.find(voice => voice.name === 'Google italiano');
|
||
```
|
||
|
||
Logica di annuncio:
|
||
- "zero a zero" se il punteggio è 0-0
|
||
- "[numero] pari" se il punteggio è uguale
|
||
- "[servizio] a [ricezione]" annunciando prima chi ha il servizio
|
||
|
||
### Prevenzione spegnimento schermo
|
||
|
||
NoSleep.js ([HomePage.vue:32-33](src/components/HomePage.vue:32-33)) viene attivato al mount su dispositivi mobili:
|
||
```javascript
|
||
var noSleep = new NoSleep();
|
||
noSleep.enable();
|
||
```
|
||
|
||
Questo impedisce allo schermo di spegnersi durante le partite, funzionalità essenziale per un segnapunti.
|
||
|
||
### Controlli da tastiera
|
||
|
||
Gli eventi tastiera sono gestiti tramite listener globale ([HomePage.vue:121-150](src/components/HomePage.vue:121-150)):
|
||
|
||
```javascript
|
||
window.addEventListener("keydown", this.funzioneTastiSpeciali);
|
||
```
|
||
|
||
I listener vengono temporaneamente disabilitati quando si aprono dialog per permettere l'inserimento di testo.
|
||
|
||
### Progressive Web App
|
||
|
||
La configurazione PWA in [vite.config.js](vite.config.js:10-33) definisce:
|
||
|
||
- **Manifest**: metadati dell'app (nome, icone, orientamento)
|
||
- **Service Worker**: strategia di cache per funzionamento offline
|
||
- **Display mode**: fullscreen per esperienza app-like
|
||
- **Orientamento forzato**: landscape per massimizzare spazio visibile
|
||
|
||
## Setup IDE raccomandato
|
||
|
||
- [VS Code](https://code.visualstudio.com/) - Editor consigliato
|
||
- [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) - Supporto Vue 3 (disabilita Vetur se installato)
|
||
- [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) - IntelliSense migliorato
|
||
|
||
### Estensioni VS Code utili
|
||
|
||
File [.vscode/extensions.json](.vscode/extensions.json) suggerisce:
|
||
- Vue Language Features (Volar)
|
||
- TypeScript Vue Plugin
|
||
|
||
## Risoluzione problemi comuni
|
||
|
||
### La sintesi vocale non funziona
|
||
|
||
- Verifica che il browser supporti la Web Speech API (Chrome/Edge consigliati)
|
||
- Su alcuni browser è necessaria l'interazione utente prima di utilizzare la sintesi vocale
|
||
- Controlla che la voce "Google italiano" sia disponibile nel sistema
|
||
|
||
### L'app non si installa come PWA
|
||
|
||
- Verifica che il sito sia servito tramite HTTPS (richiesto per Service Workers)
|
||
- Controlla che le icone in `public/` siano presenti e accessibili
|
||
- Ispeziona la console del browser per errori del Service Worker
|
||
|
||
### Lo schermo si spegne comunque
|
||
|
||
- NoSleep.js richiede un'interazione utente per attivarsi
|
||
- Su iOS, la prevenzione dello spegnimento ha limitazioni del sistema operativo
|
||
- Verifica che non ci siano impostazioni di risparmio energetico aggressive
|
||
|
||
### La rotazione non funziona correttamente
|
||
|
||
- Le formazioni si azzerano con il RESET
|
||
- Verifica che gli array `form` abbiano sempre 6 elementi
|
||
- La visualizzazione può essere invertita ma la logica di rotazione rimane corretta
|
||
|
||
## Licenza
|
||
|
||
Progetto privato. Tutti i diritti riservati.
|