harbour-henflow

Porting nativo Sailfish OS dell'app Android Henflow (it.carlobaratto.henflow). UI in QML/Silica, calcolo e dati locali, pubblicazione prevista sullo store Jolla Harbour.

Il porting non usa il runtime Flutter community (flutter-sailfishos): quello resta una via OpenRepos, non Harbour-safe, e non supporta i plugin nativi Android (AdMob/File picker/Share). Nessun account, nessun cloud, come l'originale.

Sorgenti di riferimento

  • Flutter (originale): workspace/henflow-flutter — export da Nextcloud, repo Gitea HenFlow.
  • Screenshot dello store usati come riferimento UI.

Stato

parte stato
Packaging (spec RPM, desktop SailJail, icone, i18n) pronto
Livello dati C++ (src/datastore.*, JSON compatibile con l'app Android) fatto e verificato
Motore di calcolo (qml/js/henflow.js) portato e verificato con node
Traduzioni 4 lingue (qml/js/i18n.js, 126 chiavi) portate e verificate con node
Catalogo razze con foto (qml/js/catalog.js) portato e verificato con node
Home con produzione stimata e coda ordini fatta
Scheda ordine (nuovo/modifica, data calcolata) fatta
Cover con produzione e ordini pendenti fatta
Razze disponibili, mio pollaio, registro galline fatte
Clienti (anagrafica) fatta
Backup e ripristino (JSON dell'app Android) fatto
Scelta lingua a runtime (4 lingue) fatta
Introduzione (primo avvio e dalle impostazioni) fatta
Calendario delle consegne fatto

Struttura

harbour-henflow.pro          # QT += quick qml, INSTALLS icone + foto razze
rpm/harbour-henflow.spec     # lrelease + desktop cercati con find (layout sorgente variabile)
rpm/harbour-henflow.desktop  # profilo [X-Sailjail] + permesso Documents (backup)
src/main.cpp                 # SailfishApp, context property appSettings/appData/appVersion
src/settings.h/.cpp          # QSettings su path esplicito AppConfigLocation + sync() (lingua, intro vista)
src/datastore.h/.cpp         # dati in un JSON in AppConfigLocation + backup nel formato dell'app Android
qml/harbour-henflow.qml      # ApplicationWindow: initialPage + cover
qml/pages/MainPage.qml       # Home: produzione stimata, coda ordini, menu (ordine, clienti, impostazioni)
qml/pages/OrderPage.qml      # nuovo/modifica ordine con anteprima della data di consegna
qml/pages/CalendarPage.qml    # calendario delle consegne: griglia del mese + ordini del giorno
qml/pages/SettingsPage.qml   # indice delle impostazioni
qml/pages/BreedsPage.qml     # razze disponibili (attiva/disattiva con conferma)
qml/pages/CoopPage.qml       # mio pollaio: conteggi e produzione per razza
qml/pages/BreedDetailPage.qml# scheda razza + registro galline (deposizione, elimina)
qml/pages/HenPage.qml        # nuova/modifica gallina: nome, data di nascita, deposizione
qml/pages/CustomersPage.qml  # anagrafica clienti
qml/pages/CustomerPage.qml   # nuovo/modifica cliente
qml/pages/BackupPage.qml     # esporta in Documenti / copia negli appunti / ripristina da JSON
qml/pages/LanguagePage.qml   # lingua (EN/IT/FR/DE) applicata a runtime
qml/pages/IntroPage.qml      # introduzione in 4 passi
qml/pages/AboutPage.qml      # informazioni e versione
qml/cover/CoverPage.qml      # produzione del giorno e ordini pendenti
qml/js/henflow.js            # motore di calcolo (ES5, testabile con node)
qml/js/i18n.js               # 126 chiavi x 4 lingue + t(chiave, arg, lingua)
qml/js/catalog.js            # 7 razze: nome/descrizione/colore uova/foto
assets/breeds/*.jpg          # foto delle razze (installate nel datadir)
tools/gen_from_flutter.py    # rigenera i18n.js e catalog.js dai sorgenti Flutter
tools/check_qml.py           # controlli statici: chiavi, simboli JS, pagine, componenti
tests/run.sh                 # motore + traduzioni (node) + controlli QML + qmllint
tests/cpp_test.sh            # livello dati (Qt 5.15 locale, config in cartella temporanea)
icons/make_icons.py          # icone 86/108/128/172 dall'artwork originale
translations/*.ts            # stringhe statiche QML (il testo dell'app viene da i18n.js)

Test

sh tests/run.sh        # motore di calcolo, traduzioni e catalogo (node), controlli
                       # statici della QML (chiavi, simboli JS, pagine, componenti) e qmllint
sh tests/cpp_test.sh   # livello dati: compila src/datastore.cpp col Qt locale e prova
                       # persistenza, rilettura, compatibilita' delle chiavi, backup, file corrotto

I controlli statici della QML servono perche' la UI non e' eseguibile senza SDK: prima di consegnare verificano che ogni chiave di traduzione usata esista in tutte e quattro le lingue, che le funzioni del motore chiamate esistano, che le pagine aperte con pageStack esistano davvero e che non si usino componenti inesistenti (es. Toast, che in Sailfish non c'e'). qmllint aggiunge la sintassi: gli errori di sintassi sono proprio quelli che sul device fanno fallire la pagina con "Impossibile caricare la pagina".

Il testo dell'app vive in i18n.js (come il TranslationService dell'originale), quindi la lingua cambia a runtime senza riavviare l'app: cosa che i .ts di Qt 5.6 non permettono. La lingua predefinita segue quella del telefono.

Motore di calcolo (portato fedelmente da lib/main.dart)

  • Produzione stimata per razza = galline in deposizione x uova/gallina/giorno (catalogo: tutte 1.0). Una gallina conta da 6 mesi in su (_ageInMonths).
  • Magazzino: all'apertura, i giorni passati dall'ultimo aggiornamento aggiungono la produzione giornaliera alle scorte di ogni razza attiva.
  • Coda FIFO: ordini in ordine di creazione; ognuno consuma le scorte virtuali della sua razza, chi le trova consegna oggi, gli altri aspettano ceil(uova_mancanti / produzione) giorni. Gli ordini gia' consegnati non consumano scorte.
  • Stima per un nuovo ordine: ceil((pendenti + richieste - scorte) / produzione).

Le date sono sempre normalizzate a YYYY-MM-DD e le funzioni non mutano l'input.

Modello dati (fedele a StorageService, SharedPreferences + JSON)

chiave contenuto
breed_settings_v2 [{breedId, hens:[{id, name, birthDate, isLaying}]}]
reservations_v2 [{id, customerName, breedId, eggsRequested, createdAt, deliveryDate, isDelivered}]
customers_v1 [{id, firstName, lastName, phoneNumber}]
warehouse_stock_v1 {breedId: uova}
last_production_update_v1 data ISO dell'ultimo accrual

Nel porting: un unico file JSON in ~/.config/harbour/henflow/ (nessuna dipendenza extra, nessun driver SQL da verificare sul device) con la stessa struttura, cosi' i due formati restano leggibili.

Backup (formato dell'app Android)

L'export e il ripristino usano le chiavi dell'app Android — breedSettings, reservations, customers (camelCase) — non quelle interne del file: un backup esportato sul telefono Android si ripristina qui e viceversa. Il file viene scritto in ~/Documents (serve il permesso Documents nel profilo SailJail); in alternativa il JSON si copia negli appunti. Scorte e data dell'ultimo aggiornamento non stanno nel backup: al ripristino restano quelli correnti, cosi' non si azzera il magazzino. tests/cpp_test.sh prova il round-trip con un backup scritto esattamente come lo esporta l'app Android.

Schermate mappate (da sorgenti + screenshot)

schermata Flutter contenuto porting
OnboardingPage 4 passi introduttivi IntroPage (primo avvio + dalle impostazioni)
ModeSelectionPage modalita' allevatore / cliente non portata: solo allevatore, come deciso
HomePage card produzione stimata, ordini con stato e azioni, FAB New order MainPage + OrderPage
HomePage tab Calendar calendario delle prenotazioni CalendarPage
SettingsPage tab Available breeds catalogo con foto e spunta, conferma alla disattivazione BreedsPage
SettingsPage tab My coop razze allevate, galline registrate/in deposizione, produzione CoopPage + BreedDetailPage
BreedDetailPage + AddHenDialog galline della razza, eta' in mesi, stato deposizione BreedDetailPage + HenPage (data con tre selettori)
CustomersPage + dialoghi anagrafica clienti CustomersPage + CustomerPage
AddReservationSheet nuovo/modifica ordine OrderPage
SettingsPage backup esporta su file / importa da JSON BackupPage (formato identico all'Android)
AboutPage info app AboutPage
CoopIcon (CustomPainter) icona pollaio disegnata a mano non portata: la Home usa la card con la produzione

Differenze da tenere presenti: niente annunci (AdMob non esiste su Sailfish), share/export via file JSON in Download invece di share_plus/file_picker.

Build e deploy

Sul PC con l'SDK Sailfish (qui non c'e' sfdk):

sfdk target use SailfishOS-5.0.0.62-aarch64   # o il target del tuo device
sfdk build                                    # RPM in build-*/RPMS/
sfdk deploy                                   # oppure Qt Creator

Tarball per lo store (con --prefix, esclude .git e i file non tracciati):

git archive --format=tar.gz --prefix=harbour-henflow-0.2.0/ -o harbour-henflow-0.2.0.tar.gz HEAD

Aperti

  1. Verifica su device: la UI Silica non e' verificabile senza SDK/dispositivo (qui si verificano motore, traduzioni, catalogo, livello dati, chiavi e sintassi della QML, ma non il comportamento a schermo).

Correzioni rispetto all'originale (bug trovati nei sorgenti Flutter)

  • app_language.dart e' una copia vecchia della tabella traduzioni (111 chiavi contro 126), usata solo da lib/dialogs/confirm_dialogs.dart, e ha gli a capo scritti \\n: quei dialoghi mostrano un backslash visibile. Il porting estrae dalla tabella viva in main.dart.
  • Il francese ha 2 chiavi in meno (name_generic, desc_generic) e t() non ha fallback: in francese la razza "generic" usciva come testo name_generic. Nel porting i buchi sono colmati dall'inglese e un test lo verifica.
  • assets/breeds/olive.jpg era un WEBP con estensione .jpg: Qt 5.6 su Sailfish non ha il plugin webp. Riconvertito in JPEG.
  • Niente annunci (AdMob non esiste su Sailfish) e niente share_plus/file_picker: export/import JSON in Download.
  • Il tab Calendar ha i messaggi del dialogo di consegna scritti a mano in italiano ("Conferma Consegna", ...): non tradotti in nessuna delle 4 lingue. Nel porting la consegna si segna con l'interruttore della riga, come nella Home.
  • Gli ordini dell'app Android hanno anche clientNote e source: il ricalcolo della coda ricopia tutti i campi, cosi' un ordine che arriva dall'Android non perde la nota del cliente (c'e' un test apposta).
  • La consegna scala le uova dal magazzino della razza, come nell'originale; nel porting annullarla le rimette (l'originale non prevedeva l'annulla).
S
Description
No description provided
Readme
2.8 MiB
Languages
QML 47.4%
JavaScript 28.1%
C++ 13.4%
Python 8.8%
QMake 1.2%
Other 1.1%