Το LearnByzantineMusic είναι Android εφαρμογή εκμάθησης Βυζαντινής Μουσικής με ενότητες θεωρίας.
Η λειτουργία Συνθέτης έχει καταργηθεί και έχει αντικατασταθεί από σελίδα 8 Ήχοι με οπτική απόδοση κλιμάκων και διαστημάτων.
Στη σελίδα 8 Ήχοι εμφανίζονται επίσης ανά ήχο: δεσπόζοντες φθόγγοι, φθορές, έλξεις και κατηγορίες καταλήξεων (ατελείς/εντελείς/τελικές/οριστικαί).
Στη σελίδα 8 Ήχοι εμφανίζονται ανά ήχο και τα απηχήματα (λεκτικό απήχημα + φθογγόσημο βάσης από τα διαθέσιμα drawables του app).
Στη σελίδα 8 Ήχοι εμφανίζονται επίσης οι φθόγγοι εκτέλεσης κάθε απηχήματος (έναρξη → κίνηση → κατάληξη) για καθοδήγηση στην εκφώνηση.
Στη σελίδα 8 Ήχοι εμφανίζεται επίσης αντιστοίχιση συλλαβή → φθόγγος για κάθε απήχημα, ώστε η εκφώνηση να γίνεται σωστά βήμα-βήμα.
Στη σελίδα 8 Ήχοι εμφανίζονται επίσης εναλλακτικές ονομασίες απηχημάτων όπου υπάρχουν στην πράξη (π.χ. Πλ. Β’).
Όπου υπάρχει εναλλακτικό απήχημα, εμφανίζονται και οι δικοί του φθόγγοι καθώς και η αντιστοίχιση συλλαβών.
Στη σελίδα 8 Ήχοι εμφανίζεται πλέον και σταθερή ένδειξη ότι κάθε απήχημα εκτελείται σε δύο μορφές: σύντομο και αργό.
Η οπτική κλίμακα των 8 Ήχων έχει επεκταθεί σε τριπλό εύρος (Νη, → Νη΄΄) με 22 φθόγγους και 21 διαστήματα ανά ήχο.
Για τον Α΄ Ήχο υπάρχει πλέον ξεχωριστή σελίδα Θεωρία Α΄ Ήχου, η οποία ανοίγει από CTA μέσα στη σελίδα 8 Ήχοι και συγκεντρώνει οργανωμένα το αναλυτικό θεωρητικό υλικό με verified τοπικά σύμβολα του app.
Προστέθηκε σελίδα Ρυθμίσεις με discrete slider για μέγεθος γραμμάτων (20/40/60/80/100) που εφαρμόζει global font scaling σε όλες τις οθόνες.
Προστέθηκε δίγλωσση υποστήριξη (Ελληνικά / English) με υποχρεωτικό πρώτο wizard επιλογής γλώσσας και επιβεβαίωση πριν την ενεργοποίηση.
Στη σελίδα Ρυθμίσεις προστέθηκαν δύο κουμπιά γλώσσας (Ελληνικά, English) που αλλάζουν locale σε όλη την εφαρμογή μετά από επιβεβαίωση.
Προστέθηκε πλήρως ανασχεδιασμένη σελίδα Ηχογραφήσεις (Compose UI) με μεγάλη εγγραφή μικροφώνου, παύση/συνέχεια, σταμάτημα και λίστα μόνο με τις 10 τελευταίες ηχογραφήσεις που δημιουργήθηκαν από το app (τοπικό history στη συσκευή).
Η σελίδα Ηχογραφήσεις ζητά υποχρεωτικά επιλογή φακέλου μέσω SAF στην πρώτη είσοδο και αποθηκεύει μόνιμη πρόσβαση.
Οι ηχογραφήσεις μπορούν να αποθηκευτούν σε .flac/.mp3/.wav/.aac/.m4a/.opus με default το .flac και περιγραφή για κάθε format μέσα στο UI.
Προστέθηκε ξεχωριστή σελίδα Διαχείριση ηχογραφήσεων (Compose UI) για πλοήγηση φακέλων, δημιουργία φακέλου, μετακίνηση μέσω action menu Move to... (χωρίς drag/drop), και inline rename/delete.
Προστέθηκε νέα σελίδα Σημειώσεις (Compose UI) με πολλαπλές σημειώσεις (τίτλος + κείμενο), local-first αποθήκευση σε Room, auto-save όσο γράφει ο χρήστης και χειροκίνητο Save τώρα.
Η σελίδα Σημειώσεις απαιτεί υποχρεωτικά επιλογή φακέλου backup/sync μέσω SAF στην πρώτη είσοδο, δημιουργεί full JSON snapshot σε κάθε save και κρατά απεριόριστο ιστορικό snapshots.
Υποστηρίζεται Εξαγωγή τώρα, Import backup (replace-all) και pending resync ροή όταν το write στον εξωτερικό φάκελο αποτυγχάνει (χωρίς να χάνεται το τοπικό save).
Η λίστα Ηχογραφήσεις εμφανίζει σταθερά τις 10 τελευταίες δικές μου ηχογραφήσεις, ενώ η Διαχείριση ηχογραφήσεων διατηρεί ταξινόμηση/αναζήτηση/φίλτρα και virtualization/paging πάνω από Room index για απόκριση σε μεγάλους φακέλους.
Διορθώθηκε η κενή κατάσταση της σελίδας Ηχογραφήσεις ώστε όταν δεν υπάρχουν δικές μου εγγραφές να εμφανίζεται άμεσα μήνυμα δεν υπάρχουν εγγραφές αντί για ατέρμονο loading.
Η σελίδα Σάρωση Βυζαντινού Κειμένου έχει τεθεί προσωρινά ανενεργή και δεν είναι διαθέσιμη από την αρχική πλοήγηση.
Προστέθηκε σελίδα Ημερολόγιο που εμφανίζει τον ήχο εβδομάδας ανά επιλεγμένη ημερομηνία.
Η σελίδα Ημερολόγιο υποστηρίζει πλέον άμεση επιλογή μήνα/έτους με tap στον τίτλο μήνα (picker), κουμπί Σήμερα και πιο ευανάγνωστο UI με οπτική διάκριση επιλεγμένης ημέρας και σημερινής ημέρας.
Προστέθηκε πιλοτικό εορτολόγιο ημέρας (Ιανουάριος 2025) με local dataset (calendar_celebrations_v1.json), dot ένδειξη ειδικής ημέρας στο grid και αναλυτικό panel κάτω από τον ήχο εβδομάδας.
Στο Ημερολόγιο εμφανίζονται πλέον μόνο παραπομπές αναγνωσμάτων (Απόστολος/Ευαγγέλιο), και με tap σε παραπομπή ανοίγει νέα σελίδα πλήρους κειμένου με εναλλαγή Αρχαία / Νεοελληνικά.
Το dataset ημερολογίου επεκτάθηκε με section readings (reference, text_ancient, text_modern) χωρίς πεδία source/domain/url.
Προστέθηκε script scripts/fill_calendar_month.py για monthly update (YYYY-MM ή DD-MM-YYYY) με internet retrieval pipeline (year page -> day ids -> full readings page parse).
Οι protected ημερομηνίες (αμετακίνητες γιορτές + επίσημες αργίες) στο days πλέον δεν γίνονται overwrite όταν υπάρχουν ήδη και συμπληρώνονται μόνο αν λείπουν.
Προστέθηκε script scripts/seed_protected_days.py για deterministic seed protected ημερών χωρίς internet retrieval (π.χ. 2025-2026).
Για τον Ιανουάριο 2025 τα text_ancient/text_modern των αναγνωσμάτων αντικαταστάθηκαν από πραγματικά πλήρη κείμενα (με υποστήριξη πολλαπλών αναγνωσμάτων ανά ημέρα όπου υπάρχουν).
Το skill/script εφαρμόζει πολιτική provider-1 (Κολιτσάρα) -> provider-2 (Τρεμπέλα) -> provider-3 (license-gated) -> generated fallback και δεν αποθηκεύει/εμφανίζει πληροφορία πηγής στο app.
Ο υπολογισμός ήχου γίνεται από εκκλησιαστικό κύκλο: Ορθόδοξο Πάσχα -> Πεντηκοστή (+49) -> αρχή Α’ Ήχου στη 2η Κυριακή μετά την Πεντηκοστή.
Η νέα ροή αποκόπτει το πρώτο μουσικό block/γραμμή, εμφανίζει το cropped αποτέλεσμα και προβάλλει confidence ανά σύμβολο.
Η ανάλυση παράγει πορεία φθόγγων (Νη/Πα/Βου/Γα/Δι/Κε/Ζω) με βάση τον επιλεγμένο ήχο και τη βάση εκκίνησης.
Προστέθηκε pipeline δημιουργίας template dataset από MK/fonts + KeyBoard.ini στο app/src/main/assets/mk_symbol_templates_v1.
Στο Core MVP v2 ο scanner engine χρησιμοποιεί primary OCR templates από core drawables και semantic parser base+modifier (π.χ. πεταστή, απόστροφος, κλάσμα, γοργό, αντικένωμα+απλή).
Ο επιλεγμένος Ήχος επηρεάζει πλέον πραγματικά την καμπύλη πορείας μέσω mode profiles (byzantine_mode_rules_v1.json), ενώ η διάρκεια ανά event αποδίδεται με κανόνες χρόνου.
Πλέον υποστηρίζεται και αυτοματοποιημένη διαδικασία release στο GitHub με tag-based publish, user-friendly release notes και ένα custom release asset (apk-release.apk).
Το build classpath κάνει forced resolve transitive εξαρτήσεις ασφαλείας: commons-io σε 2.14.0, protobuf-java σε 3.25.5, jdom2 σε 2.0.6.1, netty-codec σε 4.1.129.Final, netty-codec-http σε 4.1.129.Final, netty-codec-http2 σε 4.1.129.Final, netty-handler σε 4.1.129.Final, jose4j σε 0.9.6, commons-compress σε 1.26.0, commons-lang3 σε 3.18.0, bcpkix-jdk18on σε 1.79, bcprov-jdk18on σε 1.79 και bcutil-jdk18on σε 1.79.
Για το app dependency graph υπάρχει πλέον και explicit pin στο com.google.guava:guava:32.1.3-jre (catalog + implementation + kapt) ώστε το security graph να αναγνωρίζει deterministic patched version.
- Ο χρήστης ανοίγει την αρχική οθόνη και επιλέγει θεωρητική ενότητα.
- Στο κάτω μέρος της αρχικής οθόνης εμφανίζεται footer με μορφή
poweredby JohnChourp v.<release_version>. - Το footer με το
poweredby JohnChourp v.<release_version>είναι σταθερό στο κάτω μέρος της αρχικής σελίδας (εκτός scroll περιοχής). - Από την αρχική οθόνη ο χρήστης μπορεί να ανοίξει τη σελίδα
Ρυθμίσεις. - Στη σελίδα
Ρυθμίσειςο χρήστης αλλάζει το μέγεθος γραμμάτων με slider που κουμπώνει μόνο στις τιμές20/40/60/80/100(προεπιλογή60). - Η αλλαγή αποθηκεύεται άμεσα σε local preferences (
app_font_step) και εφαρμόζεται global σε όλες τις activities. - Στην πρώτη εκκίνηση εμφανίζεται υποχρεωτικό menu επιλογής γλώσσας (
Ελληνικά/English) και ακολουθεί επιβεβαίωση στη γλώσσα που επιλέχθηκε. - Με επιβεβαίωση επιλογής, το app αποθηκεύει
app_language_code, μαρκάρει ολοκλήρωση onboarding (app_language_onboarding_completed) και επανεκκινεί στην ίδια γλώσσα. - Στη σελίδα
Ρυθμίσεις, τα δύο κουμπιά γλώσσας (Ελληνικά,English) ζητούν πάντα επιβεβαίωση πριν από κάθε αλλαγή locale. - Πατώντας
Ηχογραφήσεις, ανοίγει σελίδα εγγραφής με controls (Έναρξη/Παύση/Συνέχεια/Σταμάτημα) και λίστα με τις 10 τελευταίες ηχογραφήσεις που δημιουργήθηκαν από το app. - Στην πρώτη είσοδο της σελίδας
Ηχογραφήσεις, αν δεν υπάρχει αποθηκευμένη πρόσβαση φακέλου, ανοίγει picker φακέλου (OpenDocumentTree) και απαιτείται παραχώρηση άδειας. - Πατώντας
Σημειώσεις, ανοίγει νέα σελίδα για πολλαπλές σημειώσεις (τίτλος + κείμενο) με αναζήτηση και ταξινόμηση κατά πρόσφατη ενημέρωση. - Στην πρώτη είσοδο της σελίδας
Σημειώσεις, αν δεν υπάρχει αποθηκευμένη πρόσβαση φακέλου backup, ανοίγει υποχρεωτικά picker φακέλου (OpenDocumentTree) και επανεμφανίζεται μέχρι να επιλεγεί έγκυρος φάκελος. - Σε κάθε save σημείωσης (auto-save ή
Save τώρα) η εφαρμογή γράφει πρώτα local δεδομένα στη Room και έπειτα δημιουργεί full JSON snapshot για sync στον επιλεγμένο φάκελο. - Αν το sync φακέλου αποτύχει, το save παραμένει επιτυχές τοπικά και το snapshot μπαίνει σε pending queue για επόμενο retry ή
Επανασυγχρονισμό. - Με
Import backupγίνεται replace-all επαναφορά των σημειώσεων, και αμέσως μετά δημιουργείται νέο snapshot/sync. - Με
Έναρξη ηχογράφησηςτο μεγάλο κόκκινο κουμπί κρύβεται και εμφανίζονταιΠαύση/Συνέχεια+Σταμάτημα. - Με
Σταμάτηματο app αποθηκεύει την εγγραφή στο επιλεγμένο format (FLACdefault) και ενημερώνει άμεσα το τοπικό history recent. - Με
Παραχώρηση/Αλλαγή φακέλουεμφανίζεται πρώτα επιβεβαίωση (Συνέχεια/Ακύρωση) ώστε να μη χαθεί ο τρέχων φάκελος από κατά λάθος πάτημα. - Με
Άνοιγμα φακέλουγίνεται προσπάθεια ανοίγματος ακριβώς του επιλεγμένου SAF φακέλου (και fallback σε picker με preselected αρχικό φάκελο). - Με tap σε στοιχείο ηχογράφησης (τόσο στη recent λίστα όσο και στη
Διαχείριση ηχογραφήσεων) γίνεται ασφαλές προσωρινό cache copy και ανοίγει chooser Android (Άνοιγμα ηχογράφησης με...) για επιλογή εφαρμογής αναπαραγωγής με μεγαλύτερη συμβατότητα. - Το tap σε κάθε row ηχογράφησης έχει πλέον εμφανές pressed effect (ripple) και status
Άνοιγμα ηχογράφησης: ...ώστε να είναι ξεκάθαρο ότι καταγράφηκε το πάτημα. - Η recent λίστα τροφοδοτείται από local history που κρατά μόνο ηχογραφήσεις που έγιναν από το app και προβάλλει τις 10 νεότερες (
createdTs DESC). - Η κύρια σελίδα
Ηχογραφήσειςδεν εκτελεί full SAF reindex στο άνοιγμα (ούτε στην πρώτη εκκίνηση), ώστε το empty state/πρόσφατες εγγραφές να εμφανίζονται άμεσα. - Όταν η recent λίστα είναι άδεια, εμφανίζεται deterministic empty state και δεν προβάλλεται ατέρμονο loading indicator.
- Η recent λίστα δεν έχει πλέον search/sort/filter controls, ενώ τα controls παραμένουν στη λίστα διαχείρισης.
- Στη
Διαχείριση ηχογραφήσεωνοι φάκελοι εμφανίζονται πάντα πρώτοι και μετά ακολουθούν τα αρχεία ήχου. - Και στις δύο λίστες (
recent+διαχείριση) εμφανίζονται μόνο αρχεία ήχου με κατάληξη.flac/.mp3/.wav/.aac/.m4a/.opus. - Κάθε στοιχείο ηχογράφησης έχει διακριτικά κουμπιά
Μετονομασίακαι κόκκινοΔιαγραφήμε επιβεβαίωση πριν την ενέργεια. - Η φόρτωση/ανανέωση λιστών ηχογραφήσεων γίνεται μέσω Room indexer (BFS σάρωση SAF), WorkManager one-time reindex jobs και Paging3 queries ώστε το UI να παραμένει responsive σε μεγάλους φακέλους.
- Με
Διαχείριση ηχογραφήσεωνανοίγει ξεχωριστή σελίδα όπου εμφανίζονται φάκελοι + audio files του τρέχοντος path, επιτρέπεται δημιουργία φακέλου, μετακίνηση μέσωMove to...dialog (searchable target folders) και inline rename/delete. - Αν ένα αρχείο έχει διαγραφεί/μετακινηθεί εκτός app, σε
Άνοιγμα/Μετονομασία/Διαγραφήεμφανίζεται μήνυμακαταργήθηκε(localized) και αφαιρείται από τη λίστα. - Πατώντας
8 Ήχοι, ανοίγει η οθόνη επιλογής ήχου. - Πατώντας
Ημερολόγιο, ανοίγει νέα οθόνη μηνιαίου ημερολογίου. - Στη σελίδα
Ημερολόγιο, η τρέχουσα ημέρα της συσκευής επιλέγεται αυτόματα κατά την είσοδο. - Στη σελίδα
Ημερολόγιο, με tap στον τίτλο μήνα ανοίγει picker για γρήγορη επιλογή μήνα/έτους (1900-2100) χωρίς διαδοχικά πατήματα στα βελάκια. - Στη σελίδα
Ημερολόγιο, το κουμπίΣήμεραεπιστρέφει άμεσα στον τρέχοντα μήνα/ημερομηνία. - Πατώντας οποιαδήποτε ημέρα, εμφανίζεται ο
ήχος εβδομάδαςγια την εβδομάδα της συγκεκριμένης ημερομηνίας. - Πατώντας ημέρα στο
Ημερολόγιο, εμφανίζεται επίσης τοΕορτολόγιο ημέρας(κύρια εγγραφή + επιπλέον εγγραφές αν υπάρχουν). - Πατώντας ημέρα στο
Ημερολόγιο, εμφανίζονται και παραπομπέςΑπόστολος/Ευαγγέλιο(χωρίς URLs/πηγές). - Με tap σε παραπομπή ανοίγει η σελίδα
Κείμενο αναγνώσματος, όπου ο χρήστης εναλλάσσειΑρχαίακαιΝεοελληνικάγια το ίδιο ανάγνωσμα. - Στο μηνιαίο grid του
Ημερολογίου, εμφανίζεται dot indicator μόνο όταν η ημέρα έχει ειδική καταχώρηση (αργία/θρησκευτική εορτή) και όχι γιαnormal_day. - Ο
ήχος εβδομάδαςαλλάζει στο app την Κυριακή00:00τοπικής ώρας. - Η
Σάρωση Βυζαντινού Κειμένουπαραμένει προσωρινά ανενεργή ακόμα και με άμεσο intent άνοιγμα. - Πριν το
Ανάλυση, ο χρήστης μπορεί να κάνει περικοπή της φωτογραφίας (αριστερά/δεξιά/πάνω/κάτω) για να αφαιρέσει περιττές πληροφορίες. - Η περικοπή ενημερώνεται live όσο μετακινούνται οι γραμμές (sliders), ώστε να φαίνεται άμεσα τι μένει στο τελικό κάδρο.
- Προστέθηκε και περιστροφή εικόνας (οριζόντια/κάθετα/στραβά) με slider γωνίας και πλήκτρα
-90°/+90°. - Η λήψη φωτογραφίας γίνεται πλέον με in-app κάμερα (portrait lock), ώστε να μην εξαρτάται από auto-rotate εξωτερικής εφαρμογής κάμερας.
- Με
Ανάλυση, το app κάνει local adaptive preprocessing (threshold+morphology+deskew), αποκόπτει το πρώτο μουσικό block και αναγνωρίζει σύμβολα με parserbase+modifier. - Κάτω από κάθε αναγνωρισμένο σύμβολο εμφανίζεται αυτόματα ο αντίστοιχος φθόγγος.
- Για κάθε event εμφανίζονται και διάρκεια (
χρόνος) και confidence. - Τα άγνωστα σύμβολα επισημαίνονται ως
UNKNOWNκαι η ανάλυση συνεχίζει χωρίς διακοπή. - Η πορεία μελωδίας εμφανίζεται και ως ακολουθία κειμένου και ως mode-aware γραφική τροχιά σε ξεχωριστό διάγραμμα.
- Προεπιλεγμένος είναι ο
Α’ Ήχος. - Με αλλαγή ήχου από το selector, ανανεώνονται γένος, αναλυτικά θεωρητικά στοιχεία του ήχου, φθόγγοι ανόδου, διαστήματα (μόρια) και το διάγραμμα «σκάλα».
- Με αλλαγή ήχου από το selector, ανανεώνονται και το απήχημα του ήχου και το αντίστοιχο φθογγόσημο βάσης.
- Με αλλαγή ήχου από το selector, ανανεώνονται και οι φθόγγοι εκτέλεσης του απηχήματος ώστε να φαίνεται καθαρά από πού ξεκινά, πού ανεβαίνει και πού καταλήγει.
- Με αλλαγή ήχου από το selector, ανανεώνεται και η αντιστοίχιση συλλαβών/φθόγγων του απηχήματος για σωστή προφορά κάθε συλλαβής.
- Με αλλαγή ήχου από το selector, εμφανίζονται και εναλλακτικά απηχήματα (όταν υπάρχουν) ώστε να καλύπτεται και η εναλλακτική ορολογία.
- Στα εναλλακτικά απηχήματα (όπου υπάρχουν) εμφανίζονται ξεχωριστά οι φθόγγοι και η αντιστοίχιση συλλαβών/φθόγγων.
- Στο selector των ήχων, το όνομα χρωματίζεται ανά γένος: μαύρο για διατονικούς, μπλε για σκληρό χρωματικό, μωβ για μαλακό χρωματικό και πορτοκαλί για εναρμόνιο.
- Το ύψος κάθε οπτικού διαστήματος παραμένει αναλογικό στα μόρια.
- Η κλίμακα του διαγράμματος καλύπτει πλέον 3 οκτάβες (
Νη,έωςΝη΄΄) με παραδοσιακή σήμανση χαμηλής/υψηλής οκτάβας. - Πάνω από το διάγραμμα υπάρχει πλέον κάρτα
Μεταφορά βάσηςμε slider (-12έως+12μόρια) και κουμπίΕπαναφορά. - Η μεταφορά βάσης αλλάζει μόνο το απόλυτο ύψος (transpose) και κρατάει ίδια διαστήματα/ονομασίες φθόγγων.
- Κάθε ήχος θυμάται τη δική του τιμή μεταφοράς βάσης και η τιμή αποθηκεύεται μόνιμα στη συσκευή.
- Με press-and-hold πάνω στο όνομα φθόγγου στο διάγραμμα, αναπαράγεται συνεχής τόνος στη συχνότητα του συγκεκριμένου φθόγγου για τον επιλεγμένο ήχο.
- Το touch playback καλύπτει όλο το τριπλό εύρος, από χαμηλό
Νη,μέχρι υψηλόΝη΄΄. - Με απελευθέρωση (
UP) ή έξοδο του δαχτύλου εκτός label (EXIT), ο τόνος σταματά άμεσα. - Για νέα έκδοση app, ο maintainer τρέχει
scripts/release-and-tag.sh(ή το skill wrapper), γίνεται bump έκδοσης, build release artifacts, ενιαίο commit με όλες τις αλλαγές του working tree, και tag push. - Το release script δημιουργεί αυτόματα συνοπτική, user-friendly περιγραφή αλλαγών από previous tag σε νέο tag (
RELEASE_NOTES.md) με πλήρη λίστα commits, χωρίς να επαναλαμβάνει τον τίτλο του release. - Το release script δημοσιεύει άμεσα GitHub Release με μόνο custom asset το
apk-release.apk(για εύκολο mobile install download) και χρησιμοποιεί τα generated notes ως release description. - Τα
Source code (zip)καιSource code (tar.gz)εμφανίζονται αυτόματα από το GitHub σε κάθε tag release. - Το release script και το GitHub Action δημοσιεύουν μόνο signed APK· αν λείπουν signing credentials, το release μπλοκάρεται πριν το upload.
- Πριν από release γίνεται αυτόματος έλεγχος ότι δεν υπάρχουν committed secrets/keystore αρχεία στο repository.
- Σε κάθε push/pull request τρέχει αυτόματα ο έλεγχος
Security Guardγια ανίχνευση committed secrets. - Με push tag
vX.Y.Z, το GitHub Actions workflow παραμένει ως επιπλέον fallback για release packaging και ανεβάζει μόνο aliasapk-release.apk. - Αν στο ίδιο tag υπάρχει ήδη custom asset
apk-release.apkαπό direct publish του script, το fallback workflow κάνει skip το publish για να μη δημιουργηθεί δεύτερο APK asset.
Κύριες αμετάβλητες αρχές:
- Η σελίδα
8 Ήχοιείναι εκπαιδευτική προβολή με τοπικό interaction ακρόασης φθόγγων και αποθήκευση τοπικής μεταφοράς βάσης ανά ήχο. - Δεν υπάρχει backend API/cloud.
- Κάθε release πρέπει να έχει μοναδικό
versionCodeκαι semanticversionName.
{
"selected_mode": "Α’ Ήχος"
}{
"mode": "Α’ Ήχος",
"genus": "Διατονικό",
"apichima": "Ανανές",
"apichima_alternatives": "",
"apichima_phthongs": "Πα → Βου → Πα",
"apichima_syllables_phthongs": "Α(Πα) - να(Βου) - νές(Πα)",
"mode_theory": {
"dominant_phthongs": ["Πα", "Κε"],
"phthores": "Κυρίως διατονική, χρωματική σε μεταβάσεις",
"elxeis": ["Βου→Γα", "Ζω→Νη"],
"cadences_atelis": ["Γα", "Κε"],
"cadences_entelis": ["Πα", "Νη"],
"cadences_telikes": ["Πα"],
"cadences_oristikes": ["Πα"]
},
"ascending_phthongs": ["Νη,", "Πα,", "Βου,", "Γα,", "Δι,", "Κε,", "Ζω,", "Νη", "Πα", "Βου", "Γα", "Δι", "Κε", "Ζω", "Νη΄", "Πα΄", "Βου΄", "Γα΄", "Δι΄", "Κε΄", "Ζω΄", "Νη΄΄"],
"ascending_moria": [12, 10, 8, 12, 12, 10, 8, 12, 10, 8, 12, 12, 10, 8, 12, 10, 8, 12, 12, 10, 8]
}{
"selected_date": "2026-02-08"
}{
"week_start": "2026-02-08",
"week_end": "2026-02-14",
"tone_index": 4,
"tone_name": "Πλάγιος του Α’"
}{
"folder_uri": "content://com.android.externalstorage.documents/tree/primary%3AMusic%2FByzantineRecordings",
"format": "flac",
"action": "start_pause_resume_stop"
}{
"saved_file_name": "recording_20260220_104500.flac",
"folder": "ByzantineRecordings",
"format": "flac",
"status": "saved"
}{
"note_id": "4f5eb74f-6362-4bb6-a618-0f37f8bf9c39",
"title": "Χερουβικό Κυριακής",
"body": "Να δουλέψω αργά το ανέβασμα στο «Και ζωοποιώ».",
"trigger": "auto_or_manual"
}{
"local_saved": true,
"snapshot_schema_version": 1,
"snapshot_file": "notes_snapshot_20260306_213015_144.json",
"folder_sync": "success_or_pending_retry",
"pending_sync_count": 0
}{
"mode": "Α’ Ήχος",
"touch_action": "DOWN",
"phthong_label": "Πα",
"index_top_to_bottom": 13
}{
"base_frequency_hz": 220.0,
"moria_from_base_ni": 12,
"formula": "f = 220 * 2^(moria/72)",
"frequency_hz": 246.94,
"playback": "continuous_while_pressed"
}{
"settings_page": true,
"font_size_step": 80
}{
"stored_key": "app_font_step",
"stored_value": 80,
"font_scale": 1.1,
"scope": "all_activities"
}{
"first_launch": true,
"selected_language": "en",
"confirm": true
}{
"stored_key_language": "app_language_code",
"stored_value_language": "en",
"stored_key_onboarding": "app_language_onboarding_completed",
"stored_value_onboarding": true,
"scope": "all_activities"
}{
"command": "./scripts/release-and-tag.sh --bump patch"
}{
"mode": "Πλάγιος του Β’",
"base_phthong": "Νη",
"image_source": "camera_or_gallery",
"analysis_scope": "first_music_block"
}{
"crop_rect": {"left": 42, "top": 130, "right": 1170, "bottom": 260},
"events_count": 8,
"unknown_count": 2,
"low_confidence_count": 1,
"events": [
{"name": "Πεταστή", "token": "a4", "modifiers": [], "confidence": 0.91, "note": "Βου", "duration_beats": 1.0},
{"name": "Απόστροφος", "token": "b1", "modifiers": ["gorgo"], "confidence": 0.72, "note": "Νη", "duration_beats": 0.5}
],
"note_path": ["Βου", "Πα", "Πα", "Βου", "Γα", "Βου", "Πα", "Νη"]
}{
"version_name": "1.0.3",
"version_code": 3,
"tag": "v1.0.3",
"github_release": "published",
"release_notes": "build-artifacts/release/v1.0.3/RELEASE_NOTES.md",
"assets": ["apk-release.apk", "source-code-zip", "source-code-tar-gz"]
}-
Android build:
-
compileSdk = 34 -
minSdk = 24 -
targetSdk = 34 -
Compose Compiler Extension = 1.5.14 -
Kotlin Gradle Plugin = 1.9.24 -
AGP = 8.5.2 -
Buildscript classpath override:
-
commons-io:commons-io = 2.14.0(forced μέσω rootbuild.gradle.ktsγια transitive hardening από AGP/UTP) -
com.google.protobuf:protobuf-java = 3.25.5(forced μέσω rootbuild.gradle.ktsγια transitive hardening από AGP/UTP) -
org.jdom:jdom2 = 2.0.6.1(forced μέσω rootbuild.gradle.ktsγια transitive hardening από AGP) -
io.netty:netty-codec = 4.1.129.Final(forced μέσω rootbuild.gradle.ktsγια transitive hardening από AGP/UTP) -
io.netty:netty-codec-http = 4.1.129.Final(forced μέσω rootbuild.gradle.ktsγια transitive hardening από AGP/UTP) -
io.netty:netty-codec-http2 = 4.1.129.Final(forced μέσω rootbuild.gradle.ktsγια transitive hardening από AGP/UTP) -
io.netty:netty-handler = 4.1.129.Final(forced μέσω rootbuild.gradle.ktsγια transitive hardening από AGP/UTP) -
org.bitbucket.b_c:jose4j = 0.9.6(forced μέσω rootbuild.gradle.ktsγια transitive hardening από AGP) -
org.apache.commons:commons-compress = 1.26.0(forced μέσω rootbuild.gradle.ktsγια transitive hardening από AGP) -
org.apache.commons:commons-lang3 = 3.18.0(forced μέσω rootbuild.gradle.ktsγια transitive hardening από AGP) -
org.bouncycastle:bcpkix-jdk18on = 1.79(forced μέσω rootbuild.gradle.ktsγια transitive hardening από AGP) -
org.bouncycastle:bcprov-jdk18on = 1.79(forced μέσω rootbuild.gradle.ktsγια transitive hardening από AGP) -
org.bouncycastle:bcutil-jdk18on = 1.79(forced μέσω rootbuild.gradle.ktsγια transitive hardening από AGP) -
com.google.guava:guava = 32.1.3-jre(explicit pin στο app dependency graph για mitigation του temporary-directory advisory) -
com.arthenica:ffmpeg-kit-full-gpl = 6.0-2(για transcode ηχογραφήσεων σεflac/mp3/aac/m4a/opus) -
Κύρια components:
-
MainActivity -
WeeklyModeCalendarActivity -
SettingsActivity -
EightModesActivity -
BaseActivity -
AppFontScale -
LiturgicalToneCycle -
OrthodoxPaschaCalculator -
layout_eight_modes.xml -
layout_weekly_mode_calendar.xml -
layout_settings.xml -
ScaleDiagramView -
PhthongTonePlayer -
ByzantineScanActivity -
ByzantineMelodyAnalyzer -
MelodyPathView -
RecordingsActivity -
RecordingsManagerActivity -
RecordingFormatOption -
RecordingsPrefs -
AudioTranscoder -
RecordingDocumentOps -
RecordingModels -
NotesActivity -
NotesViewModel -
NotesRepository -
NotesDatabase -
NotesBackupManager -
NotesBackupCodec -
Ρυθμίσεις εφαρμογής:
-
SharedPreferences file:
learn_byzantine_music_settings -
Key:
app_font_step -
Allowed values:
20 | 40 | 60 | 80 | 100 -
Default value:
60 -
SharedPreferences file:
learn_byzantine_music_recordings -
Keys:
recordings_folder_tree_uri,recordings_output_format -
Default format:
FLAC -
SharedPreferences file:
learn_byzantine_music_notes -
Keys:
notes_folder_tree_uri,notes_last_sync_epoch_ms,notes_last_sync_error -
Room DB:
notes.db(NoteEntity:id,title,body,createdAtEpochMs,updatedAtEpochMs) -
Internal pending backup directory:
files/notes_pending_snapshots/ -
Release automation scripts:
-
scripts/bump-version.sh -
scripts/release-and-tag.sh -
scripts/generate-mk-symbol-dataset.py -
scripts/check-no-secrets.sh -
scripts/setup-release-signing.sh -
.codex/AGENTS.md(project-specific Codex safety instructions) -
GitHub Actions:
-
.github/workflows/android-release.yml(trigger σε tagsv*.*.*) -
.github/workflows/security-guard.yml(trigger σε κάθε push/pull request) -
.github/workflows/codeql.yml(CodeQL scan με manual Java/Kotlin build μέσω:app:compileDebugKotlinκαι JDK 17) -
Υποχρεωτικό release signing για installable GitHub APK:
-
ANDROID_KEYSTORE_BASE64 -
ANDROID_KEYSTORE_PASSWORD -
ANDROID_KEY_ALIAS -
ANDROID_KEY_PASSWORD -
Για local release script απαιτούνται επίσης env vars:
-
ANDROID_SIGNING_STORE_FILE -
ANDROID_SIGNING_STORE_PASSWORD -
ANDROID_SIGNING_KEY_ALIAS -
ANDROID_SIGNING_KEY_PASSWORD -
Required GitHub permissions:
-
contents: writeγια δημιουργία release και upload assets. -
Κανόνας ασφάλειας:
-
Δεν γίνεται commit σε
.env*,*.jks,*.keystore,*.p12,*.pfx,*.pem,key.properties. -
Ευαίσθητες τιμές περνάνε μόνο από GitHub Secrets και runtime env vars.
-
Δεν απαιτούνται:
-
login/auth provider
-
push/SNS υποδομές
-
backend resources
- Ο χρήστης ανοίγει την αρχική οθόνη και βλέπει στο κάτω μέρος
poweredby JohnChourp v.1.0.3. - Πατά
Ρυθμίσεις, μετακινεί το slider στο80και η εφαρμογή εμφανίζει άμεσα μεγαλύτερα γράμματα. - Έπειτα ανοίγει
8 Ήχοι, επιλέγειΠλάγιος του Β’και βλέπει άμεσα ενημερωμένη κλίμακα/διαστήματα με σωστή οπτική αναλογία. - Κρατά πατημένο τον χαμηλό
Νη,και έπειτα τον υψηλόΝη΄΄, και ακούει σωστή διαφορά ύψους σε όλο το τριπλό εύρος. - Τέλος ανοίγει
Σάρωση Βυζαντινού Κειμένου, τραβά φωτογραφία, και βλέπει cropped block + πορεία φθόγγων ανά σύμβολο.
- Ο χρήστης ανοίγει
Σημειώσεις, επιλέγει φάκελο backup και δημιουργεί νέα σημείωση. - Καθώς γράφει, ενεργοποιείται auto-save και δημιουργούνται JSON snapshots στον εξωτερικό φάκελο.
- Πατά
Import backupμε παλιό snapshot, η εφαρμογή κάνει replace-all στη λίστα και γράφει άμεσα νέο snapshot.
./scripts/setup-release-signing.sh --set-github-secrets
source "$HOME/.android/learnbyzantine/release-signing.env"
./scripts/release-and-tag.sh --bump patch- Αναμενόμενο: νέο commit έκδοσης, νέο tag
vX.Y.Z, push στο GitHub, direct publish GitHub Release και upload μόνοapk-release.apk. - Το commit του release δημιουργείται αυτόματα ως ένα ενιαίο commit που περιλαμβάνει όλες τις διαθέσιμες αλλαγές (tracked/untracked, εκτός ignored) με σύντομο summary στο commit message.
- Το GitHub Release description περιλαμβάνει συνοπτική εικόνα (commits/files/contributors), περιοχές που επηρεάστηκαν και πλήρη λίστα αλλαγών από το προηγούμενο release, χωρίς διπλό τίτλο.
- Το fallback workflow για το ίδιο tag εντοπίζει αν υπάρχει ήδη
apk-release.apkκαι τότε παραλείπει το publish step (αναμενόμενη συμπεριφορά).
{
"error": "tag_already_exists",
"message": "Το tag v1.0.3 υπάρχει ήδη. Δώσε νέο version bump ή explicit version."
}{
"error": "missing_signing_secrets",
"result": "release_aborted_before_publish",
"action": "ορισμός ANDROID_KEYSTORE_* secrets στο GitHub και ANDROID_SIGNING_* vars στο local release environment"
}{
"error": "tracked_secret_detected",
"message": "Βρέθηκε committed secret/keystore αρχείο. Μεταφορά σε GitHub Secrets και αφαίρεση από git history/index."
}{
"error": "camera_permission_denied",
"fallback": "gallery_available",
"message": "Η κάμερα απορρίφθηκε. Χρησιμοποίησε gallery ή άνοιξε άδεια από ρυθμίσεις."
}{
"error": "notes_backup_folder_write_failed",
"local_saved": true,
"pending_sync": true,
"message": "Το περιεχόμενο σώθηκε τοπικά και θα συγχρονιστεί στο επόμενο save/resync."
}- Το
commons-ioδεν υπάρχει ως direct dependency στο app module. - Έρχεται transitive από το Android Gradle Plugin (
com.android.tools.build:gradle:8.5.2) και σχετικά UTP artifacts. - Το project κάνει forced resolve σε
commons-io:2.14.0στο build classpath ώστε να καλύπτεται το patched range του advisory.
- Το
protobuf-javaέρχεται transitive από AGP/UTP dependencies και όχι από direct declaration στο app module. - Η προηγούμενη resolved έκδοση ήταν
3.22.3και το advisory ζητά patched έκδοση>= 3.25.5. - Το project κάνει forced resolve σε
com.google.protobuf:protobuf-java:3.25.5στο build classpath.
- Το
jdom2έρχεται transitive από το Android Gradle Plugin (com.android.tools.build:gradle:8.5.2). - Η προηγούμενη resolved έκδοση ήταν
2.0.6και το advisory ζητά patched έκδοση>= 2.0.6.1. - Το project κάνει forced resolve σε
org.jdom:jdom2:2.0.6.1στο build classpath.
- Το
io.netty:netty-codecέρχεται transitive από AGP/UTP dependencies. - Η προηγούμενη resolved έκδοση ήταν
4.1.93.Finalκαι το advisory ζητά patched έκδοση>= 4.1.125.Final. - Το project κάνει forced resolve σε
io.netty:netty-codec:4.1.129.Finalστο build classpath.
- Το
io.netty:netty-codec-httpέρχεται transitive από AGP/UTP dependencies. - Η προηγούμενη resolved έκδοση ήταν
4.1.93.Finalκαι το advisory ζητά patched έκδοση>= 4.1.129.Final. - Το project κάνει forced resolve σε
io.netty:netty-codec-http:4.1.129.Finalστο build classpath.
- Το
io.netty:netty-codec-http2έρχεται transitive από AGP/UTP dependencies. - Η προηγούμενη resolved έκδοση ήταν
4.1.93.Finalκαι τα advisories καλύπτονται από patched έκδοση4.1.129.Final. - Το project κάνει forced resolve σε
io.netty:netty-codec-http2:4.1.129.Final, που ανεβάζει και τα σχετικά Netty modules στο ίδιο resolved graph.
- Το
io.netty:netty-handlerέρχεται transitive από AGP/UTP dependencies. - Το advisory καλύπτει εύρος
4.1.91.Finalέως4.1.117.Finalκαι απαιτεί>= 4.1.118.Final. - Το project κάνει explicit forced resolve σε
io.netty:netty-handler:4.1.129.Finalστο build classpath.
- Το
org.bitbucket.b_c:jose4jέρχεται transitive από το Android Gradle Plugin (com.android.tools.build:gradle:8.5.2). - Η προηγούμενη resolved έκδοση ήταν
0.9.5και το advisory ζητά patched έκδοση>= 0.9.6. - Το project κάνει forced resolve σε
org.bitbucket.b_c:jose4j:0.9.6στο build classpath.
- Το
org.apache.commons:commons-compressέρχεται transitive από το Android Gradle Plugin (com.android.tools.build:gradle:8.5.2). - Η προηγούμενη resolved έκδοση ήταν
1.21και το advisory ζητά patched έκδοση>= 1.26.0. - Το project κάνει forced resolve σε
org.apache.commons:commons-compress:1.26.0στο build classpath.
- Το
org.apache.commons:commons-lang3έρχεται transitive από το Android Gradle Plugin (com.android.tools.build:gradle:8.5.2). - Η προηγούμενη resolved έκδοση ήταν
3.14.0και το advisory ζητά patched έκδοση>= 3.18.0. - Το project κάνει forced resolve σε
org.apache.commons:commons-lang3:3.18.0στο build classpath.
- Το
org.bouncycastle:bcpkix-jdk18onέρχεται transitive από το Android Gradle Plugin (com.android.tools.build:gradle:8.5.2). - Η προηγούμενη resolved έκδοση ήταν
1.77και το advisory ζητά patched έκδοση>= 1.79. - Το project κάνει forced resolve σε
org.bouncycastle:bcpkix-jdk18on:1.79στο build classpath και ευθυγραμμίζειbcprov/bcutilστην ίδια έκδοση.
- Το
org.bouncycastle:bcprov-jdk18onέρχεται transitive από AGP dependencies (bcpkix-jdk18on/bcutil-jdk18on). - Η προηγούμενη resolved έκδοση ήταν
1.77και τα advisories καλύπτονται με έκδοση1.79. - Το project κάνει forced resolve σε
org.bouncycastle:bcprov-jdk18on:1.79στο build classpath.
- Το
com.google.guava:guavaέρχεται transitive απόandroidx.roomκαιandroidx.workdependencies. - Το advisory για insecure use of temporary directory καλύπτεται από patched γραμμή
>= 32.0.0-android, με σύσταση απο maintainers να αποφεύγεται το32.0.0. - Το project κάνει explicit pin σε
com.google.guava:guava:32.1.3-jreστο app dependency graph (implementation+kapt) και κρατά force fallback για πλήρη ευθυγράμμιση resolve.
- Η εφαρμογή δεν χρησιμοποιεί login/auth ροή.
- Δεν απαιτούνται token/session ή identity provider.
- Δεν υπάρχει μηχανισμός push/SNS στο app.
- Δεν υπάρχουν backend notification routes.
- Δεν υπάρχει dispatch/routes ροή στην εφαρμογή.
- Η λογική είναι αποκλειστικά τοπική προβολή περιεχομένου.
- Συνήθης αιτία είναι ότι δεν έχει δοθεί ακόμα πρόσβαση σε φάκελο μέσω SAF (
OpenDocumentTree). - Βεβαιώσου ότι έχει δοθεί και άδεια μικροφώνου (
RECORD_AUDIO) στο app. - Αν ακυρώθηκε ο picker φακέλου, πάτησε
Παραχώρηση/Αλλαγή φακέλουκαι επέλεξε ξανά φάκελο.
- Έλεγξε ότι στο selector της σελίδας
Ηχογραφήσειςέχει επιλεγεί το σωστό format πριν την έναρξη. - Για μη-WAV formats η μετατροπή γίνεται μέσω FFmpeg και απαιτεί επιτυχή transcode στο τέλος της εγγραφής.
- Αν αποτύχει transcode, εμφανίζεται μήνυμα σφάλματος και δεν δημιουργείται τελικό αρχείο στον φάκελο.
- Χρειάζεται διαθέσιμη εφαρμογή που να υποστηρίζει
ACTION_VIEWγια directory URI. - Αν δεν υπάρχει συμβατή εφαρμογή, το app εμφανίζει μήνυμα και η εγγραφή συνεχίζει να λειτουργεί κανονικά.
- Εγκατάστησε/ενεργοποίησε file manager app και ξαναδοκίμασε το
Άνοιγμα φακέλου.
- Όχι. Πλέον εμφανίζεται πρώτα επιβεβαίωση με
Συνέχεια/Ακύρωση. - Αν πατήσεις
Ακύρωσηή κλείσεις τον picker χωρίς επιλογή, ο προηγούμενος φάκελος παραμένει ενεργός. - Η λίστα δείχνει μόνο τις 10 τελευταίες ηχογραφήσεις που έγιναν από το app στο ίδιο SAF root.
- Η λογική είναι local-first: πρώτα αποθηκεύει πάντα τοπικά (Room), μετά γράφει backup στον εξωτερικό φάκελο.
- Αν αποτύχει το write στον φάκελο (provider/permission σφάλμα), το snapshot μένει σε pending queue στο app και γίνεται retry στο επόμενο save.
- Δεν χάνονται οι σημειώσεις σου από αυτή την αποτυχία, εκτός αν χαλάσει η τοπική βάση και δεν υπάρχει κανένα έγκυρο backup.
- Αν έχεις επιλέξει φάκελο backup και έχουν παραχθεί snapshots, μπορείς να κάνεις
Import backupμετά από reinstall. - Αν δεν είχε επιλεγεί ποτέ φάκελος backup ή δεν υπάρχουν snapshots, η απεγκατάσταση αφαιρεί το τοπικό Room DB.
- Για μέγιστη ασφάλεια, κράτα τον εξωτερικό φάκελο backup σε σημείο που δεν διαγράφεται μαζί με την εφαρμογή.
- Διαβάζει ένα JSON snapshot και κάνει replace-all στις σημειώσεις (δεν κάνει merge).
- Μετά το replace-all, η εφαρμογή δημιουργεί νέο snapshot και προσπαθεί άμεσο sync στον επιλεγμένο φάκελο.
- Αν το import αρχείο είναι άκυρο (
schemaVersion/δομή), η επαναφορά απορρίπτεται χωρίς να πειραχτούν οι υπάρχουσες σημειώσεις.
- Πάτησε το αρχείο στη recent λίστα.
- Το app δημιουργεί προσωρινό αντίγραφο στο cache και το ανοίγει μέσω
FileProviderγια καλύτερη συμβατότητα με εξωτερικούς players. - Εμφανίζεται chooser με τις συμβατές εφαρμογές αναπαραγωγής, ακόμη κι όταν ο SAF provider του αρχικού αρχείου έχει περιορισμούς.
- Αν δεν υπάρχει συμβατή εφαρμογή, εμφανίζεται το μήνυμα αποτυχίας ανοίγματος.
- Η κύρια σελίδα
Ηχογραφήσεις(τελευταίες 10 δικές μου εγγραφές) φορτώνει από local history και πρέπει να ανοίγει άμεσα, ακόμη και στην πρώτη εκκίνηση χωρίς εγγραφές. - Το βαρύ indexing/reindex αφορά τη σελίδα
Διαχείριση ηχογραφήσεων(Room index + Paging3), όχι τη recent λίστα της κύριας σελίδας. - Αν υπάρχει καθυστέρηση στη
Διαχείριση ηχογραφήσεωνμετά από πολλές αλλαγές αρχείων, περίμενε να ολοκληρωθεί το reindex (linear progress στην κορυφή). - Αν ο SAF provider της συσκευής καθυστερεί σε πολύ βαθύ tree, δοκίμασε πιο «ρηχή» δομή φακέλων και ξανάνοιξε τη σελίδα για νέο warm-cache load.
- Η μετακίνηση γίνεται από action menu (
Move to...) και βασίζεται σε SAFmoveDocument, οπότε ορισμένοι providers μπορεί να μην το υποστηρίζουν για όλα τα paths. - Αν source και target φάκελος είναι ίδιος, η εφαρμογή μπλοκάρει προληπτικά τη μετακίνηση.
- Η εφαρμογή μπλοκάρει επίσης μετακίνηση φακέλου στον εαυτό του ή σε υποφάκελό του για αποφυγή άκυρων κύκλων.
- Επιβεβαίωσε ότι γίνεται press-and-hold πάνω στο ίδιο το label του φθόγγου (όχι στο κενό του διαγράμματος).
- Έλεγξε ένταση media του device και ότι δεν είναι σε muted/silent mode.
- Αν άλλαξες ήχο από selector την ώρα που έπαιζε τόνος, ξαναπάτησε hold σε label για νέο playback.
- Το playback λειτουργεί σε όλο το εύρος
Νη, → Νη΄΄, άρα δοκίμασε τόσο χαμηλά όσο και ψηλά labels για έλεγχο εξόδου ήχου.
- Η μπάρα αλλάζει τη βάση από
-12έως+12μόρια και κάνει transpose σε όλη την κλίμακα, χωρίς να αλλάζει ονόματα φθόγγων ή διαστήματα. - Κάθε ήχος κρατάει δική του τιμή βάσης και η τιμή αποθηκεύεται μόνιμα (παραμένει μετά από κλείσιμο/άνοιγμα app).
- Η σελίδα θυμάται και τον τελευταίο επιλεγμένο ήχο από το πάνω selector και τον επαναφέρει αυτόματα στο επόμενο άνοιγμα.
- Με
Επαναφοράη τρέχουσα τιμή του συγκεκριμένου ήχου γυρίζει στο0 μόρια (προεπιλογή).
- Άνοιξε
Ρυθμίσειςκαι επιβεβαίωσε ότι η τιμή άλλαξε σε ένα από τα επιτρεπτά βήματα (20/40/60/80/100). - Έλεγξε ότι δεν δοκιμάζεις την ίδια τιμή με πριν (αν μείνει ίδια, δεν αλλάζει scale).
- Αν υπάρχει παλαιά τιμή εκτός επιτρεπτών βημάτων, το app την κανονικοποιεί αυτόματα στο κοντινότερο επιτρεπτό βήμα.
- Στην πρώτη εκκίνηση, πρέπει να ολοκληρωθεί και το βήμα επιβεβαίωσης μετά την επιλογή (
Ναι) για να αποθηκευτεί η γλώσσα. - Στις
Ρυθμίσεις, η αλλαγή γλώσσας εφαρμόζεται μόνο όταν επιβεβαιωθεί το σχετικό dialog. - Έλεγξε ότι η νέα επιλογή είναι διαφορετική από την τρέχουσα (
Τρέχουσα γλώσσα: ...), αλλιώς τα κουμπιά δεν εφαρμόζουν αλλαγή.
- Δεν υπάρχουν cloud resources για cleanup.
- Για local build artifacts, χρησιμοποίησε διαγραφή φακέλων
app/build/καιbuild-artifacts/release/αν χρειάζεται reset.
- Το script κάνει direct publish με
gh; έλεγξε πρώτα ότι υπάρχει ενεργόgh auth login. - Αν χρησιμοποιείς
--skip-gh-release, τότε η δημοσίευση εξαρτάται από το workflow tag triggerv*.*.*. - Έλεγξε ότι έγινε push και του tag (
git push origin vX.Y.Z), όχι μόνο branch. - Αν έχει ήδη γίνει direct publish από το script, το fallback workflow μπορεί να εμφανίσει skip στο publish step επειδή υπάρχει ήδη
apk-release.apkστο release του tag (αναμενόμενο, όχι σφάλμα).
- Συνήθως το APK είναι unsigned (ή αλλιώς αλλοιωμένο κατά το download).
- Από εδώ και πέρα το pipeline αποτυγχάνει όταν λείπουν signing secrets και δεν ανεβάζει unsigned
apk-release.apk. - Έλεγξε στο GitHub Release ότι κατεβάζεις το artifact
apk-release.apkτου τελευταίου επιτυχημένου release.
- Όχι, ένα αρχείο SHA256 checksums περιέχει μόνο hashes αρχείων και όχι κωδικούς/keys.
- Παρ' όλα αυτά, το release policy του project πλέον ανεβάζει μόνο
apk-release.apkως custom asset για απλούστερη δημόσια διανομή.
- Συνήθης αιτία είναι αποτυχία του CodeQL
autobuildσε Android projects (δεν ανιχνεύει σωστά Gradle build βήματα). - Η ροή του project έχει οριστεί σε manual build mode με JDK 17 και compile-only command
./gradlew --no-daemon :app:compileDebugKotlin. - Αν ξανασπάσει, έλεγξε logs για JDK version mismatch ή σφάλμα Gradle dependency resolution.
- Βάλε τα σε
Settings -> Secrets and variables -> Actionsστο GitHub repository. - Για signing χρησιμοποίησε τα
ANDROID_KEYSTORE_BASE64,ANDROID_KEYSTORE_PASSWORD,ANDROID_KEY_ALIAS,ANDROID_KEY_PASSWORD. - Για αυτοματοποιημένη αρχική ρύθμιση keystore+secrets χρησιμοποίησε
./scripts/setup-release-signing.sh --set-github-secrets. - Το
scripts/check-no-secrets.shκαι το CI μπλοκάρουν release όταν εντοπίσουν committed secret files/keys.
- Τα signing keys δεν υπάρχουν έτοιμα στο project, δημιουργούνται μία φορά με
keytool. - Δεν τα βάζουμε ποτέ στο
app/build.gradle.ktsεπειδή το repository είναι public. - Το project διαβάζει signing δεδομένα μόνο από environment variables και GitHub Secrets.
- Ναι, σε κάθε push/PR εκτελείται το workflow
Security Guard. - Επιπλέον, πριν από κάθε release εκτελείται ξανά ο ίδιος έλεγχος και αν αποτύχει, το release μπλοκάρεται.
- Για μέγιστη προστασία ενεργοποίησε στο GitHub branch protection με required status check το
Security Guard / repository-secrets-guard.
app/build.gradle.kts: προστέθηκε conditional release signing από environment variables.scripts/bump-version.sh: χειρίζεταιversionName/versionCodebump.scripts/release-and-tag.sh: χτίζει release artifacts, απαιτεί υποχρεωτικά signing env vars, μπλοκάρει unsigned APK outputs, κάνει commit/tag/push, κάνει stage+commit όλες τις αλλαγές του working tree σε ένα release commit με σύντομο summary, παράγει user-friendlyRELEASE_NOTES.md(previous tag → νέο tag) χωρίς διπλό τίτλο, και δημιουργεί/ενημερώνει direct GitHub Release μόνο με custom assetapk-release.apk.scripts/check-no-secrets.sh: αποτρέπει commit/release όταν υπάρχουν tracked μυστικά ή υπογεγραμμένα κλειδιά μέσα στο repository.scripts/setup-release-signing.sh: δημιουργεί release keystore εκτός repository, γράφει local env file signing και ενημερώνει προαιρετικά αυτόματα τα GitHub Actions secrets..github/workflows/security-guard.yml: τρέχει secrets guard σε κάθε push/PR..github/workflows/android-release.yml: τρέχει secrets guard, απαιτεί υποχρεωτικά signing secrets, κάνει package signed APK σε σταθερό aliasapk-release.apk, ελέγχει αν υπάρχει ήδη ίδιο custom asset στο release του tag και κάνει skip το fallback publish όταν υπάρχει ήδη.MainActivityκαιlayout_main_activity.xml: προστέθηκε footerpoweredby JohnChourp v.<version>με τιμή απόBuildConfig.VERSION_NAME.MainActivityκαιlayout_main_activity.xml: προστέθηκε και νέο entry buttonΣημειώσειςγια μετάβαση στηNotesActivity.RecordingsActivityκαιRecordingsManagerActivity: πλήρης μετάβαση σε Compose UI με ViewModel/StateFlow, με τη σελίδα ηχογραφήσεων να δείχνει μόνο 10 local own recordings και τη διαχείριση να διατηρεί search+filters+sort.recordings/index/*: νέο data layer με Room index (recordings_index.db), BFS indexer SAF, WorkManager reindex worker και repository για observe/operations.recordings/ui/*καιrecordings/ui/components/*: νέα composables για recent list/manager list, row action menus και searchableMove to...επιλογή προορισμού.RecordingFormatOption,RecordingsPrefs,AudioTranscoder: νέα helper modules για formats, persist settings φακέλου/μορφής και transcode μέσω FFmpeg.OwnedRecordingsStore,RecordingDocumentOpsκαιRecordingModels: local own-recordings history, κοινά μοντέλα + ασφαλής λογική rename fallback (direct rename και fallback copy/delete για αρχεία) με νέο outcomeκαταργήθηκε.RecordingExternalOpenerκαιbyzantine_scan_file_paths.xml: ασφαλές άνοιγμα ηχογράφησης με audio-only MIME fallbacks (resolved -> audio/*) και dual URI strategy (δοκιμή original SAF URI και cacheFileProviderURI) για μεγαλύτερη συμβατότητα σε Android 15 συσκευές.notes/*: νέο notes module με Room (notes.db), repository/viewmodel, JSON snapshot codec, pending backup queue σε internal storage και SAF sync στον φάκελο που επιλέγει ο χρήστης.NotesActivityκαιnotes/ui/NotesScreen.kt: νέα Compose οθόνη με search, editor (τίτλος + κείμενο), auto-save, manual save, export/import και actions επανασυγχρονισμού.AndroidManifest.xml: προστέθηκαν activitiesRecordingsActivity,RecordingsManagerActivityκαι permissionRECORD_AUDIO.strings.xml: προστέθηκαν labels/status/errors και περιγραφές για όλα τα διαθέσιμα formats ηχογράφησης.SettingsActivity,layout_settings.xml,AppFontScaleκαιBaseActivity: διαχειρίζονται την αποθήκευση/εφαρμογή global font scaling για όλη την εφαρμογή.EightModesActivity,layout_eight_modes.xml,ScaleDiagramViewκαιPhthongTonePlayer: διαχειρίζονται touch labels, αναπαραγωγή συχνοτήτων (Νη = 220Hz), επιλογή ηχοχρώματος με 3 presets (Καθαρός,Μαλακός,Κρυστάλλινο) και ρυθμιζόμενη μεταφορά βάσης ανά ήχο (-12..+12μόρια) με μόνιμη αποθήκευση.eight_modes_base_shift_card_bg.xml: ορίζει το visual styling της κάρτας μεταφοράς βάσης.ByzantineScanActivity: υλοποιεί camera/gallery ροή, επιλογή ήχου/βάσης και προβολή αποτελεσμάτων αναγνώρισης.ByzantineMelodyAnalyzer+BinaryImageOps: υλοποιούν adaptive preprocessing, αποκοπή πρώτης γραμμής, segmentation και recognition σε eventsbase+modifier.ByzantineRhythmMapper: εφαρμόζει κανόνες διάρκειας (κλάσμα,αντικένωμα+απλή,γοργόμε redistribution χρόνου).byzantine_core_symbol_rules_v2.json,byzantine_mode_rules_v1.json,byzantine_display_names_v1.json: ορίζουν core symbol rules, mode-aware trajectory profiles και ονόματα εμφάνισης.scripts/generate-mk-symbol-dataset.py: δημιουργεί templates PNG και catalog JSON απόMK/fonts+KeyBoard.ini.app/src/main/assets/byzantine_interval_mapping_v1.json: διατηρεί το παραμετροποιήσιμο mappingtoken -> κίνηση φθόγγου.
Happy path
{
"command": "./scripts/release-and-tag.sh --bump patch",
"tag": "v1.0.3",
"release_assets": ["apk-release.apk", "Source code (zip)", "Source code (tar.gz)"]
}Happy path (recordings)
{
"folder_selected": true,
"recording_state": "stopped",
"saved_file": "recording_20260220_104500.flac",
"visible_in_list": true
}Failure example
{
"error": "gh_auth_missing",
"message": "Δεν υπάρχει ενεργό gh auth session. Τρέξε gh auth login ή χρησιμοποίησε --skip-gh-release."
}Failure example (recordings)
{
"error": "recording_transcode_failed",
"message": "Αποτυχία αποθήκευσης ηχογράφησης.",
"action": "έλεγχος format επιλογής και retry εγγραφής"
}- Το MVP αναλύει μόνο το πρώτο μουσικό block/γραμμή.
- Η αναγνώριση βασίζεται σε core template matching + semantic rules και επηρεάζεται από φωτισμό, θόρυβο και κλίση.
- Τα
mk_symbol_templates_v1παραμένουν fallback/debug μέχρι να ολοκληρωθεί πλήρες MK token→glyph fix. - Για καλύτερα αποτελέσματα: καθαρή φωτογραφία, σταθερό χέρι και κοντινό κάδρο στο μουσικό απόσπασμα.
- Χρησιμοποίησε πρώτα τη live περικοπή και την περιστροφή για να ευθυγραμμίσεις τη μουσική γραμμή πριν πατήσεις
Ανάλυση.
- Προηγούμενη αιτία ήταν ανάλυση
HARDWAREbitmap χωρίς επιτρεπτή πρόσβαση pixels. - Η ροή πλέον μετατρέπει την εικόνα σε software bitmap και προστατεύει την ανάλυση με ασφαλές error handling.
- Αν αποτύχει η ανάλυση, εμφανίζεται μήνυμα αποτυχίας χωρίς να κλείνει η εφαρμογή.
- Όχι. Η εφαρμογή είναι κλειδωμένη σε portrait orientation.
- Η λήψη γίνεται από in-app camera activity (όχι εξωτερική camera app), επίσης κλειδωμένη σε portrait.
- Ο υπολογισμός δεν βασίζεται σε σταθερή πολιτική ημερομηνία.
- Η αρχή κύκλου υπολογίζεται ανά έτος από Ορθόδοξο Πάσχα και Πεντηκοστή.
- Το app ξεκινά τον
Α’ Ήχοστη 2η Κυριακή μετά την Πεντηκοστή και μετά κάνει κυκλική εναλλαγή ανά εβδομάδα (8 ήχοι).
- Πάτησε πάνω στον τίτλο μήνα (π.χ.
Μάρτιος 2026) για να ανοίξει απευθείας ο pickerμήνα/έτους. - Επέλεξε μήνα και έτος από τους δύο pickers και πάτησε
Επιλογή. - Αν θέλεις επιστροφή στο σήμερα, πάτησε το κουμπί
Σήμερα. - Τα βελάκια παραμένουν διαθέσιμα για διαδοχική μετακίνηση μήνα-μήνα.
- Τρέξε από το root του project:
./scripts/fill_calendar_month.py YYYY-MM- ή
./scripts/fill_calendar_month.py DD-MM-YYYY
- Παράδειγμα:
./scripts/fill_calendar_month.py 2025-01./scripts/fill_calendar_month.py 01-01-2025
- Το script ενημερώνει μόνο τον μήνα που δήλωσες και κρατά ανέπαφους τους άλλους μήνες.
- Για protected ημερομηνίες (
days) ισχύει no-overwrite: αν υπάρχουν ήδη μένουν ως έχουν, αν λείπουν προστίθενται αυτόματα. - Το dataset γράφεται στο:
app/src/main/assets/calendar_celebrations_v1.json
- Για κάθε ημερήσιο ανάγνωσμα, τα
Νεοελληνικάγεμίζουν με πολιτική provider (Κολιτσάρα->Τρεμπέλα-> επιτρεπτός provider-3 -> generated fallback). - Μόνο αν αποτύχουν όλες οι επιτρεπτές επιλογές εφαρμόζεται generated απλοποίηση.
- Καμία πληροφορία πηγής (
source/domain/url) δεν αποθηκεύεται ή εμφανίζεται στην εφαρμογή.
- Χρησιμοποίησε:
./scripts/seed_protected_days.py START_YEAR END_YEAR
- Παράδειγμα:
./scripts/seed_protected_days.py 2025 2026
- Το script δεν κάνει overwrite σε υπάρχουσες protected εγγραφές και κάνει insert μόνο όπου λείπουν.
- Η σελίδα
Σάρωση Βυζαντινού Κειμένουείναι προσωρινά απενεργοποιημένη. - Το κουμπί αφαιρέθηκε από την αρχική και η activity επιστρέφει άμεσα με μήνυμα αν επιχειρηθεί άμεσο άνοιγμα.
- Το μήνυμα εμφανίζεται όταν το αρχείο έχει διαγραφεί ή μετακινηθεί εκτός εφαρμογής και το URI δεν υπάρχει πλέον.
- Η εφαρμογή αφαιρεί αυτόματα την εγγραφή από τη λίστα ώστε να μην ξαναεμφανιστεί σαν έγκυρο στοιχείο.
- Η συμπεριφορά ισχύει τόσο στη recent λίστα όσο και στη διαχείριση ηχογραφήσεων.
- Η εφαρμογή πλέον κάνει normalization του SAF URI (
tree -> document) πριν τα queries του current/root path. - Αυτό επιτρέπει να εμφανίζονται σωστά φάκελοι που δεν έχουν άμεσα audio files αλλά περιέχουν υποφακέλους.
- Αν επιμένει το πρόβλημα, κάνε αλλαγή φακέλου (re-grant) και ξανάνοιξε τη διαχείριση για νέο reindex.
- Πάνω από την κλίμακα υπάρχει νέο πεδίο
Επιλογή ηχοχρώματος. - Μπορείς να επιλέξεις ανάμεσα σε
Καθαρός,Μαλακός,Κρυστάλλινο. - Η επιλογή αποθηκεύεται και παραμένει ίδια μετά από κλείσιμο/άνοιγμα της εφαρμογής.
- Η τρέχουσα υλοποίηση είναι η Φάση 1: συνθετικά ηχοχρώματα για γρήγορο A/B test χωρίς licensing ρίσκο.
- Η Φάση 2 προβλέπει sample-based ήχους μόνο CC0/Public Domain, αφού επιλέξεις ποια 1-2 ηχοχρώματα θέλεις να κρατήσουμε.
- Μέχρι να κλειδώσουν τα τελικά samples, όλα τα πατήματα φθόγγων παίζουν από τον offline synth engine.