import 'package:flutter/material.dart'; import 'theme.dart'; /// Ab welcher Länge sich der Schnellzugriff lohnt. /// /// Darunter scrollt man in zwei Wischern durch — die Leiste wäre dann nur /// eine schmale Fläche, die Platz nimmt und Fehltreffer produziert. const alphabetAb = 30; /// Wie viele **verschiedene** Anfangsbuchstaben es mindestens braucht. /// /// Ein Album mit 40 Titeln „Track 01…40" hat genau einen — eine Leiste mit /// einem Buchstaben ist kein Schnellzugriff, sondern nur eine Fläche. const alphabetMindestBuchstaben = 3; /// Feste Breite der Leiste. /// /// Bewusst fest und nicht mitwachsend: vorher skalierte jeder Buchstabe auf /// die volle Höhe seines Platzes, die Leiste wurde dadurch **breiter**, je /// weniger Buchstaben es gab — bei einem einzigen schob sie die Songliste /// vollständig aus dem Bild. const alphabetBreite = 24.0; /// Schmale A–Z–#-Leiste am rechten Rand. Tippen und Ziehen springt zur /// ersten Stelle des Buchstabens. /// /// Zeigt **nur** die Buchstaben, unter denen wirklich etwas steht: eine volle /// A–Z-Leiste in einer Bibliothek mit vier Künstlern wäre zum größten Teil /// tote Fläche. class AlphabetLeiste extends StatefulWidget { const AlphabetLeiste({ super.key, required this.buchstaben, required this.onGewaehlt, }); final List buchstaben; final ValueChanged onGewaehlt; @override State createState() => _AlphabetLeisteState(); } class _AlphabetLeisteState extends State { String? _beruehrt; void _waehleBei(double y, double hoehe) { if (widget.buchstaben.isEmpty) return; final proBuchstabe = hoehe / widget.buchstaben.length; final index = (y / proBuchstabe).floor().clamp(0, widget.buchstaben.length - 1); final buchstabe = widget.buchstaben[index]; if (buchstabe == _beruehrt) return; setState(() => _beruehrt = buchstabe); widget.onGewaehlt(buchstabe); } @override Widget build(BuildContext context) { if (widget.buchstaben.isEmpty) return const SizedBox.shrink(); return SizedBox( width: alphabetBreite, child: LayoutBuilder( builder: (context, raum) => GestureDetector( behavior: HitTestBehavior.opaque, onVerticalDragStart: (d) => _waehleBei(d.localPosition.dy, raum.maxHeight), onVerticalDragUpdate: (d) => _waehleBei(d.localPosition.dy, raum.maxHeight), onVerticalDragEnd: (_) => setState(() => _beruehrt = null), onVerticalDragCancel: () => setState(() => _beruehrt = null), onTapDown: (d) => _waehleBei(d.localPosition.dy, raum.maxHeight), onTapUp: (_) => setState(() => _beruehrt = null), child: Semantics( label: 'Schnellzugriff nach Anfangsbuchstabe', child: Padding( padding: const EdgeInsets.symmetric(horizontal: MeloSpace.xs), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ for (final buchstabe in widget.buchstaben) Expanded( child: Center( child: Text( buchstabe, style: TextStyle( fontSize: 11, fontWeight: buchstabe == _beruehrt ? FontWeight.w700 : FontWeight.w500, color: buchstabe == _beruehrt ? MeloTheme.red : MeloTheme.text3, ), ), ), ), ], ), ), ), ), ), ); } }