Am Fernseher steht der Code vorn, nicht das Passwort
Schritt drei: anmelden. Die Oberfläche ist neu, das Modell dahinter ist dasselbe wie am Telefon — `JellyfinSignInModel`, unverändert bis auf einen Wert im Initialisierer. **Die eine Verhaltensänderung.** Nach gefundenem Server sprang der Weg bisher immer zu Benutzername und Passwort, mit der Begründung, ein Passwortspeicher fülle beide Felder in einer Sekunde. Vor einem Fernseher stimmt daran kein Wort: es gibt keinen Passwortspeicher, man tippt mit dem Steuerkreuz, und das Gerät, auf dem man den Code bestätigt, liegt sowieso auf dem Sofa. Also `preferring: .quickConnect` — ein Wert im Initialisierer und keine Plattformbedingung mitten in `findServer()`. Welcher Fall gilt, weiß die Oberfläche; das Modell nicht. Der Vorgabewert hält iOS unverändert. Der sechsstellige Code steht in 96 Punkt mit Sperrung: er wird aus drei Metern abgelesen und in ein Telefon getippt. In Fliesstextgrösse wäre das eine Zumutung. Beide Wege bleiben erreichbar — für Server, auf denen Quick Connect abgeschaltet ist, und für den Fall, dass gerade kein zweites Gerät zur Hand ist. **Und der Beweis, dass die geteilte Schicht trägt.** Gegen die Jellyfin-Attrappe im Simulator: die App verbindet sich, lädt die drei Mediatheken und zeigt sie. FlixySession, JellyfinBackend, die Zustandsmaschine der Anmeldung — alles unverändert, alles über Pfadeinträge geteilt, keine Zeile kopiert. Die Startseite ist noch eine Liste von Namen. Sie kommt in Schritt vier; hier steht sie, damit die Wurzel vollständig ist und die Anmeldung für sich prüfbar bleibt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
22f824b000
commit
1552e5f2b9
@@ -32,6 +32,16 @@ final class JellyfinSignInModel {
|
||||
case signingIn
|
||||
}
|
||||
|
||||
/// Welcher Weg nach dem Fund zuerst angeboten wird.
|
||||
///
|
||||
/// **Am Telefon und am Fernseher verschieden herum.** Dort füllt ein
|
||||
/// Passwortspeicher beide Felder in einer Sekunde; hier tippt man sie mit
|
||||
/// einem Steuerkreuz, Buchstabe für Buchstabe, und der Code ist der
|
||||
/// bequemere Weg. Welcher Fall gilt, weiß die Oberfläche — dieses Modell
|
||||
/// nicht. Deshalb ein Wert im Initialisierer statt einer
|
||||
/// Plattformbedingung mitten in `findServer()`.
|
||||
enum PreferredMethod { case credentials, quickConnect }
|
||||
|
||||
var address = ""
|
||||
var userName = ""
|
||||
var password = ""
|
||||
@@ -51,12 +61,15 @@ final class JellyfinSignInModel {
|
||||
var onAuthenticated: ((JellyfinClient, JellyfinAccount, String) -> Void)?
|
||||
|
||||
private let identity: JellyfinIdentity
|
||||
private let preferred: PreferredMethod
|
||||
private var client: JellyfinClient?
|
||||
private var authenticator: JellyfinAuthenticator?
|
||||
private var pollTask: Task<Void, Never>?
|
||||
|
||||
init(identity: JellyfinIdentity) {
|
||||
/// Der Vorgabewert hält iOS unverändert.
|
||||
init(identity: JellyfinIdentity, preferring: PreferredMethod = .credentials) {
|
||||
self.identity = identity
|
||||
self.preferred = preferring
|
||||
}
|
||||
|
||||
// MARK: - Schritt 1: den Server finden
|
||||
@@ -89,17 +102,26 @@ final class JellyfinSignInModel {
|
||||
address = candidate.absoluteString
|
||||
offersQuickConnect = await authenticator.supportsQuickConnect()
|
||||
|
||||
// **Name und Passwort zuerst.**
|
||||
// **Am Telefon Name und Passwort zuerst, am Fernseher der Code.**
|
||||
//
|
||||
// Hier sprang der Weg bisher von selbst in den Code-Fluss, sobald
|
||||
// der Server ihn anbietet. Das war gut gemeint — dabei läuft kein
|
||||
// Passwort durch diese App —, geht aber am Alltag vorbei: der Code
|
||||
// muss in einem zweiten Gerät bestätigt werden, und wer gerade im
|
||||
// Zug sitzt, hat das nicht offen. Ein Passwortspeicher füllt
|
||||
// dagegen beide Felder in einer Sekunde.
|
||||
// Hier sprang der Weg früher immer von selbst in den Code-Fluss,
|
||||
// sobald der Server ihn anbietet. Das war gut gemeint — dabei
|
||||
// läuft kein Passwort durch diese App —, geht am Telefon aber am
|
||||
// Alltag vorbei: der Code muss in einem zweiten Gerät bestätigt
|
||||
// werden, und wer gerade im Zug sitzt, hat das nicht offen. Ein
|
||||
// Passwortspeicher füllt dagegen beide Felder in einer Sekunde.
|
||||
//
|
||||
// Der Code bleibt erreichbar: `offersQuickConnect` steuert den
|
||||
// Knopf darunter, und der steht schon da.
|
||||
// Vor einem Fernseher stimmt jedes Wort davon nicht mehr: dort
|
||||
// gibt es keinen Passwortspeicher, dort tippt man mit dem
|
||||
// Steuerkreuz, und das zweite Gerät liegt sowieso auf dem Sofa.
|
||||
//
|
||||
// Beide Wege bleiben erreichbar: `offersQuickConnect` steuert den
|
||||
// Knopf darunter, und `useCredentials()` führt zurück.
|
||||
if preferred == .quickConnect, offersQuickConnect {
|
||||
await beginQuickConnect()
|
||||
return
|
||||
}
|
||||
|
||||
step = .credentials
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user