Zweiter Block aus der UX-Simulation (39 Funde insgesamt): - Songtext-Icon deaktiviert statt totem Knopf, wenn kein Ziel bekannt ist - Sleep-Timer-Restzeit jetzt auch im Sheet sichtbar, nicht nur im Tooltip - Drag-Handle in der Warteschlange, Wisch-nach-unten schließt den Vollbild-Player - Fehlender Tooltip am Songtext-Sheet-Schließen-Knopf ergänzt - YouTube-Download: Zeitüberschreitung meldet sich anders als toter Server - Server-Tab zeigte beim Öffnen kurz fälschlich "nicht verbunden" - Einstellungen: Favoriten-/Playlisten-Sync von "Speicher" zu "Musikserver" verschoben, Navidrome-Eintrag erklärt jetzt seinen Zweck - Kommentar in geteilte_adresse.dart korrigiert (Verhalten unverändert, dafür gibt es einen Test) Bewusst zurückgestellt: ServerFavoriteButton bleibt lokal-only (dokumentierte Architektur-Entscheidung, siehe G3 im UX-Review), Live-Wischgeste am Mini-Player, YouTube-Download-Abbrechen, Download-Badge im inaktiven Unterreiter, Versionsnummer (neue Abhängigkeit nötig). 539 Tests grün (vorher 537), flutter analyze ohne Befund.
51 lines
1.9 KiB
Dart
51 lines
1.9 KiB
Dart
import 'package:flutter/services.dart';
|
|
|
|
/// Erste Web-Adresse in [text], oder `null`.
|
|
///
|
|
/// Wer ein Video an Melo teilt, schickt selten nur die Adresse — die
|
|
/// YouTube-App hängt Titel und „über @YouTube" drumherum.
|
|
///
|
|
/// Bewusst **nicht** auf youtube.com eingeschränkt: das Herauslösen der
|
|
/// Adresse aus dem geteilten Text ist unabhängig von ihrer Herkunft. Ob eine
|
|
/// nicht-YouTube-Adresse tatsächlich heruntergeladen werden kann, entscheidet
|
|
/// [YtDownloadService.herunterladen] — der lehnt sie heute client-seitig ab
|
|
/// (siehe dort), unabhängig davon, was der Server könnte.
|
|
String? adresseAus(String? text) {
|
|
if (text == null || text.isEmpty) return null;
|
|
final treffer = _adresse.firstMatch(text);
|
|
if (treffer == null) return null;
|
|
// Satzzeichen am Ende gehören zum Satz, nicht zur Adresse.
|
|
return treffer.group(0)!.replaceAll(RegExp(r'[.,;:!?)\]]+$'), '');
|
|
}
|
|
|
|
final _adresse = RegExp(r'https?://\S+');
|
|
|
|
/// Nimmt entgegen, was andere Apps über „Teilen" an Melo schicken.
|
|
///
|
|
/// Eigene Brücke statt eines Zusatzpakets — das Projekt hat für MediaStore
|
|
/// und Klangeffekte bereits eigene (siehe `MediaStoreBridge`).
|
|
class GeteilteAdresse {
|
|
const GeteilteAdresse({this.channel = const MethodChannel(kanalName)});
|
|
|
|
static const kanalName = 'de.baka.melo/geteilt';
|
|
|
|
final MethodChannel channel;
|
|
|
|
/// Die Adresse, mit der die App gerade geöffnet wurde, oder `null`.
|
|
///
|
|
/// Wird beim Abholen auf der Android-Seite gelöscht: sonst spränge die App
|
|
/// bei jedem Wiedereintritt erneut in den Downloader.
|
|
Future<String?> abholen() async {
|
|
try {
|
|
final text = await channel.invokeMethod<String>('hole');
|
|
return adresseAus(text);
|
|
} on PlatformException {
|
|
return null;
|
|
} on MissingPluginException {
|
|
// Andere Plattformen kennen die Brücke nicht — dort gibt es kein
|
|
// Teilen an Melo, und das ist kein Fehler.
|
|
return null;
|
|
}
|
|
}
|
|
}
|