diff --git a/src/app/pages/player/player.page.scss b/src/app/pages/player/player.page.scss
index ac422b8..db88a04 100644
--- a/src/app/pages/player/player.page.scss
+++ b/src/app/pages/player/player.page.scss
@@ -449,3 +449,86 @@ ion-content.full-screen-content {
transform: translateX(0);
}
}
+
+.floating-autoscroll-bar {
+ position: fixed;
+ bottom: 120px;
+ left: 50%;
+ transform: translateX(-50%);
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ background: rgba(18, 18, 18, 0.85) !important;
+ backdrop-filter: blur(20px);
+ border: 1px solid rgba(var(--ion-color-secondary-rgb), 0.3);
+ padding: 6px 16px;
+ border-radius: 30px;
+ z-index: 999;
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
+ animation: slideUp 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ pointer-events: auto;
+
+ &.fullscreen-active {
+ bottom: 24px !important;
+ }
+
+ &.high-contrast {
+ background: #ffffff !important;
+ border-color: #555555 !important;
+ box-shadow: none !important;
+
+ .autoscroll-control-center {
+ background: rgba(0, 0, 0, 0.05);
+ border-color: rgba(0, 0, 0, 0.15);
+
+ .speed-badge {
+ color: #000000 !important;
+ }
+ }
+ }
+
+ ion-button {
+ --padding-start: 4px;
+ --padding-end: 4px;
+ margin: 0;
+
+ ion-icon {
+ font-size: 1.4rem;
+ }
+ }
+
+ .autoscroll-control-center {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ cursor: pointer;
+ background: rgba(255, 255, 255, 0.05);
+ padding: 4px 10px;
+ border-radius: 20px;
+ border: 1px solid rgba(255, 255, 255, 0.1);
+ transition: all 0.2s ease;
+
+ &:active {
+ transform: scale(0.95);
+ }
+
+ .speed-badge {
+ font-size: 0.75rem;
+ font-weight: 700;
+ color: var(--ion-color-secondary);
+ letter-spacing: 0.5px;
+ }
+ }
+}
+
+:host-context(body.high-contrast) {
+ .slim-controls .group {
+ background: rgba(0, 0, 0, 0.05) !important;
+ border: 1px solid rgba(0, 0, 0, 0.15) !important;
+ }
+
+ .landscape-side-controls .side-scroll-container .side-group {
+ background: rgba(0, 0, 0, 0.05) !important;
+ border: 1px solid rgba(0, 0, 0, 0.15) !important;
+ }
+}
diff --git a/src/app/pages/player/player.page.ts b/src/app/pages/player/player.page.ts
index b4556f0..e7a3eb7 100644
--- a/src/app/pages/player/player.page.ts
+++ b/src/app/pages/player/player.page.ts
@@ -27,6 +27,11 @@ export class PlayerPage implements OnInit, AfterViewInit, OnDestroy {
public showChords = signal(false);
public showSensitivitySlider = signal(false);
+ /** Autoscroll standard */
+ public isAutoscrolling = signal(false);
+ public autoscrollSpeed = signal(2);
+ private autoscrollTimer: any = null;
+
/** Font size scale factor (1.0 = default) */
public fontSize = signal(1.0);
@@ -524,6 +529,47 @@ export class PlayerPage implements OnInit, AfterViewInit, OnDestroy {
return info && info.num_canto ? info.num_canto.toString() : null;
}
+ toggleAutoscroll() {
+ if (this.isAutoscrolling()) {
+ this.stopAutoscroll();
+ } else {
+ this.startAutoscroll();
+ }
+ }
+
+ startAutoscroll() {
+ this.isAutoscrolling.set(true);
+ if (this.autoscrollTimer) clearInterval(this.autoscrollTimer);
+
+ const scrollEl = this.el.nativeElement.querySelector('.lyrics-container');
+ if (!scrollEl) return;
+
+ this.autoscrollTimer = setInterval(() => {
+ if (!this.isAutoscrolling()) {
+ clearInterval(this.autoscrollTimer);
+ return;
+ }
+ const step = this.autoscrollSpeed() * 0.25;
+ scrollEl.scrollTop += step;
+ }, 40);
+ }
+
+ stopAutoscroll() {
+ this.isAutoscrolling.set(false);
+ if (this.autoscrollTimer) {
+ clearInterval(this.autoscrollTimer);
+ this.autoscrollTimer = null;
+ }
+ }
+
+ increaseAutoscrollSpeed() {
+ this.autoscrollSpeed.update(s => Math.min(10, s + 1));
+ }
+
+ decreaseAutoscrollSpeed() {
+ this.autoscrollSpeed.update(s => Math.max(1, s - 1));
+ }
+
private logPreviousSongTime() {
const c = this.canto();
if (c && this.songStartTime > 0) {
@@ -534,6 +580,7 @@ export class PlayerPage implements OnInit, AfterViewInit, OnDestroy {
}
ngOnDestroy() {
+ this.stopAutoscroll();
this.logPreviousSongTime();
this.audioEngine.stopListening();
this.channel.close();
diff --git a/src/app/pages/propose-canto/propose-canto.page.html b/src/app/pages/propose-canto/propose-canto.page.html
index 1b6d28f..f941c26 100644
--- a/src/app/pages/propose-canto/propose-canto.page.html
+++ b/src/app/pages/propose-canto/propose-canto.page.html
@@ -4,11 +4,6 @@
Mio Canto
-
-
-
-
-
@@ -58,9 +53,28 @@