diff --git a/.gitignore b/.gitignore index d2b10de..a24413d 100644 --- a/.gitignore +++ b/.gitignore @@ -9,8 +9,8 @@ xcuserdata/ # Von XcodeGen aus project.yml erzeugt — nicht eingecheckt, damit es keine # Konflikte in der pbxproj gibt. Nach dem Klonen: xcodegen generate # -# Flixy.xcworkspace daneben ist dagegen von Hand geschrieben und gehört dazu: +# Halo.xcworkspace daneben ist dagegen von Hand geschrieben und gehört dazu: # er verweist nur auf das Projekt und überlebt jedes Neuerzeugen. Warum das -# nötig ist, steht in Flixy.xcworkspace/README.md. -Flixy.xcodeproj/ +# nötig ist, steht in Halo.xcworkspace/README.md. +Halo.xcodeproj/ node_modules/ diff --git a/DownloadWidget/DownloadLiveActivity.swift b/DownloadWidget/DownloadLiveActivity.swift index 30c2562..e9b34b7 100644 --- a/DownloadWidget/DownloadLiveActivity.swift +++ b/DownloadWidget/DownloadLiveActivity.swift @@ -1,8 +1,8 @@ import ActivityKit import SwiftUI import WidgetKit -import FlixyDesign -import FlixyDownloads +import HaloDesign +import HaloDownloads /// Der Download-Fortschritt im Sperrbildschirm und in der Dynamic Island. struct DownloadLiveActivity: Widget { diff --git a/DownloadWidget/Info.plist b/DownloadWidget/Info.plist index 74c0a10..49e5165 100644 --- a/DownloadWidget/Info.plist +++ b/DownloadWidget/Info.plist @@ -5,7 +5,7 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName - Flixy Downloads + Halo Downloads CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier diff --git a/Flixy.xcworkspace/README.md b/Halo.xcworkspace/README.md similarity index 83% rename from Flixy.xcworkspace/README.md rename to Halo.xcworkspace/README.md index fe3028d..efd8ddd 100644 --- a/Flixy.xcworkspace/README.md +++ b/Halo.xcworkspace/README.md @@ -1,9 +1,9 @@ # Diesen Arbeitsbereich öffnen, nicht das Projekt -`Flixy.xcodeproj` wird von XcodeGen aus `project.yml` erzeugt — und dabei +`Halo.xcodeproj` wird von XcodeGen aus `project.yml` erzeugt — und dabei **ersetzt**, nicht bearbeitet: jede Datei darin bekommt einen neuen Inode, auch die, deren Inhalt gleich bleibt. Hat Xcode den Arbeitsbereich **im** -Projekt offen (`Flixy.xcodeproj/project.xcworkspace`), meldet es danach +Projekt offen (`Halo.xcodeproj/project.xcworkspace`), meldet es danach > The workspace file … has disappeared. Do you want to re-save the container, > or close it? diff --git a/Flixy.xcworkspace/contents.xcworkspacedata b/Halo.xcworkspace/contents.xcworkspacedata similarity index 57% rename from Flixy.xcworkspace/contents.xcworkspacedata rename to Halo.xcworkspace/contents.xcworkspacedata index ae372ab..7416b61 100644 --- a/Flixy.xcworkspace/contents.xcworkspacedata +++ b/Halo.xcworkspace/contents.xcworkspacedata @@ -1,4 +1,4 @@ - + diff --git a/Flixy/AppIcon.icon/Assets/play.svg b/Halo/AppIcon.icon/Assets/play.svg similarity index 100% rename from Flixy/AppIcon.icon/Assets/play.svg rename to Halo/AppIcon.icon/Assets/play.svg diff --git a/Flixy/AppIcon.icon/icon.json b/Halo/AppIcon.icon/icon.json similarity index 100% rename from Flixy/AppIcon.icon/icon.json rename to Halo/AppIcon.icon/icon.json diff --git a/Flixy/Branding.swift b/Halo/Branding.swift similarity index 90% rename from Flixy/Branding.swift rename to Halo/Branding.swift index dc30d62..91a3608 100644 --- a/Flixy/Branding.swift +++ b/Halo/Branding.swift @@ -9,21 +9,21 @@ import Foundation /// /// Der Name steht noch nicht fest. Damit ein späterer Wechsel nicht zur Suche /// quer durch den Quelltext wird, greift die App nirgends auf ein hart -/// geschriebenes „Flixy" zu, sondern immer hierauf. Zu ändern sind dann genau +/// geschriebenes „Halo" zu, sondern immer hierauf. Zu ändern sind dann genau /// zwei Dinge: diese Datei und `project.yml` (Produktname, Bundle-Kennung, /// Anzeigename). /// -/// Die Typen aus FlixyKit behalten ihre Namen — sie sind Bauteile, keine Marke. +/// Die Typen aus HaloKit behalten ihre Namen — sie sind Bauteile, keine Marke. enum Branding { /// Wie die App sich selbst nennt. - static let appName = "Flixy" + static let appName = "Halo" /// Unter welchem Namen die Tokens im Schlüsselbund liegen. /// /// An die Bundle-Kennung gebunden statt an den Anzeigenamen: eine spätere /// Umbenennung der App soll niemanden abmelden. static var keychainService: String { - Bundle.main.bundleIdentifier ?? "com.scarriffleservices.flixy" + Bundle.main.bundleIdentifier ?? "com.scarriffleservices.halo" } /// Wann dieser Build entstanden ist. diff --git a/Flixy/FlixyApp.swift b/Halo/HaloApp.swift similarity index 95% rename from Flixy/FlixyApp.swift rename to Halo/HaloApp.swift index 9b95a17..f0c5f6d 100644 --- a/Flixy/FlixyApp.swift +++ b/Halo/HaloApp.swift @@ -3,14 +3,14 @@ import SwiftUI #if os(iOS) import UIKit #endif -import FlixyDesign -import FlixyDownloads -import FlixyPlayback +import HaloDesign +import HaloDownloads +import HaloPlayback import JellyfinKit import MediaKit @main -struct FlixyApp: App { +struct HaloApp: App { #if os(iOS) /// Nimmt das Signal entgegen, mit dem iOS die App zum Abschluss von /// Hintergrund-Downloads aufweckt. Dafür gibt es in SwiftUI keinen @@ -23,8 +23,8 @@ struct FlixyApp: App { /// Leben hier, nicht in einer View: sie gelten für die gesamte App, und /// ein Neuaufbau der Wurzelansicht darf weder die Anmeldung noch laufende /// Downloads zurücksetzen. - @State private var theme = FlixyTheme() - @State private var session: FlixySession + @State private var theme = HaloTheme() + @State private var session: HaloSession @State private var playback = PlaybackCoordinator() @State private var playbackSettings = PlaybackSettings() @State private var languages = LanguagePreferences() @@ -40,7 +40,7 @@ struct FlixyApp: App { private let modelContainer: ModelContainer init() { - _session = State(initialValue: FlixySession( + _session = State(initialValue: HaloSession( jellyfinIdentity: JellyfinIdentity.current( client: Branding.appName, version: Branding.version @@ -74,8 +74,8 @@ struct FlixyApp: App { // Notizzettelgröße, und darin fällt der Aufmacher in sich // zusammen, weil seine Abstände dehnbar sind. .frame( - minWidth: FlixyPlatform.isMac ? 900 : nil, - minHeight: FlixyPlatform.isMac ? 620 : nil + minWidth: HaloPlatform.isMac ? 900 : nil, + minHeight: HaloPlatform.isMac ? 620 : nil ) // `defaultSize` gibt es hier nicht; die Größe hängt an der // Szene. @@ -133,7 +133,7 @@ struct FlixyApp: App { } #if os(iOS) -extension FlixyApp { +extension HaloApp { /// Gibt dem Fenster eine vernünftige Mindestgröße. /// /// Auf dem Mac öffnet das System sonst ein Fenster von der Größe eines diff --git a/Flixy/Info.plist b/Halo/Info.plist similarity index 91% rename from Flixy/Info.plist rename to Halo/Info.plist index ff46941..6d76d2a 100644 --- a/Flixy/Info.plist +++ b/Halo/Info.plist @@ -5,7 +5,7 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName - Flixy + Halo CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -28,7 +28,7 @@ NSLocalNetworkUsageDescription - Flixy benötigt Zugriff auf das lokale Netzwerk, um deinen Jellyfin-Server zu erreichen und Medien direkt von ihm zu laden. + Halo benötigt Zugriff auf das lokale Netzwerk, um deinen Jellyfin-Server zu erreichen und Medien direkt von ihm zu laden. NSSupportsLiveActivities UIBackgroundModes diff --git a/Flixy/Resources/Assets.xcassets/Contents.json b/Halo/Resources/Assets.xcassets/Contents.json similarity index 100% rename from Flixy/Resources/Assets.xcassets/Contents.json rename to Halo/Resources/Assets.xcassets/Contents.json diff --git a/Flixy/Resources/Assets.xcassets/LaunchBackground.colorset/Contents.json b/Halo/Resources/Assets.xcassets/LaunchBackground.colorset/Contents.json similarity index 100% rename from Flixy/Resources/Assets.xcassets/LaunchBackground.colorset/Contents.json rename to Halo/Resources/Assets.xcassets/LaunchBackground.colorset/Contents.json diff --git a/Flixy/Resources/Localizable.xcstrings b/Halo/Resources/Localizable.xcstrings similarity index 99% rename from Flixy/Resources/Localizable.xcstrings rename to Halo/Resources/Localizable.xcstrings index 60f3cf8..91d8409 100644 --- a/Flixy/Resources/Localizable.xcstrings +++ b/Halo/Resources/Localizable.xcstrings @@ -5647,13 +5647,13 @@ "de": { "stringUnit": { "state": "translated", - "value": "Die Obergrenze, nicht das Ziel. Im eigenen Netz überträgt der Server das Original; unterwegs beginnt Flixy kleiner und tastet sich hinauf, solange die Verbindung es trägt — höchstens bis zu dieser Stufe. Auflösung und Bitrate gehen dabei zusammen." + "value": "Die Obergrenze, nicht das Ziel. Im eigenen Netz überträgt der Server das Original; unterwegs beginnt Halo kleiner und tastet sich hinauf, solange die Verbindung es trägt — höchstens bis zu dieser Stufe. Auflösung und Bitrate gehen dabei zusammen." } }, "en": { "stringUnit": { "state": "translated", - "value": "An upper limit, not a target. On your own network the server sends the original; away from home Flixy starts lower and works its way up as long as the connection holds — never above this step. Resolution and bitrate move together." + "value": "An upper limit, not a target. On your own network the server sends the original; away from home Halo starts lower and works its way up as long as the connection holds — never above this step. Resolution and bitrate move together." } } } diff --git a/Flixy/Session/DownloadRefiller.swift b/Halo/Session/DownloadRefiller.swift similarity index 99% rename from Flixy/Session/DownloadRefiller.swift rename to Halo/Session/DownloadRefiller.swift index 1b5b9f2..c7d03b4 100644 --- a/Flixy/Session/DownloadRefiller.swift +++ b/Halo/Session/DownloadRefiller.swift @@ -1,5 +1,5 @@ import Foundation -import FlixyDownloads +import HaloDownloads import MediaKit /// Füllt den Vorrat an ungesehenen Folgen wieder auf. diff --git a/Flixy/Session/DownloadService.swift b/Halo/Session/DownloadService.swift similarity index 99% rename from Flixy/Session/DownloadService.swift rename to Halo/Session/DownloadService.swift index f102e14..06394c5 100644 --- a/Flixy/Session/DownloadService.swift +++ b/Halo/Session/DownloadService.swift @@ -1,6 +1,6 @@ import Foundation -import FlixyDownloads -import FlixyPlayback +import HaloDownloads +import HaloPlayback import MediaKit /// Übersetzt Titel vom Server in Download-Aufträge. diff --git a/Flixy/Session/FlixySession.swift b/Halo/Session/HaloSession.swift similarity index 95% rename from Flixy/Session/FlixySession.swift rename to Halo/Session/HaloSession.swift index dd12c97..4fc1e90 100644 --- a/Flixy/Session/FlixySession.swift +++ b/Halo/Session/HaloSession.swift @@ -15,7 +15,7 @@ import Observation /// Umschalten ja, nebeneinander nein. @MainActor @Observable -final class FlixySession { +final class HaloSession { enum Phase: Equatable { /// Beim Start: liegt ein Token im Schlüsselbund? case launching @@ -32,11 +32,11 @@ final class FlixySession { } private enum Key { - static let jellyfinAddress = "flixy.jellyfin.address" - static let jellyfinUserID = "flixy.jellyfin.userID" - static let jellyfinUserName = "flixy.jellyfin.userName" - static let jellyfinServerName = "flixy.jellyfin.serverName" - static let jellyfinIsAdministrator = "flixy.jellyfin.isAdministrator" + static let jellyfinAddress = "halo.jellyfin.address" + static let jellyfinUserID = "halo.jellyfin.userID" + static let jellyfinUserName = "halo.jellyfin.userName" + static let jellyfinServerName = "halo.jellyfin.serverName" + static let jellyfinIsAdministrator = "halo.jellyfin.isAdministrator" } /// Unter welchem Namen das Server-Token im Schlüsselbund liegt. @@ -55,14 +55,14 @@ final class FlixySession { /// könnte. Deshalb wird einmalig aufgeräumt, bevor die Namen endgültig /// verschwinden. private enum Altlast { - static let merker = "flixy.migration.plexPurged" + static let merker = "halo.migration.plexPurged" static let tokenKonten = ["plex.account", "plex.server"] static let schlüssel = [ - "flixy.backend.kind", - "flixy.server.clientIdentifier", - "flixy.server.connectionURI", - "flixy.server.name", - "flixy.server.connectionIsLocal", + "halo.backend.kind", + "halo.server.clientIdentifier", + "halo.server.connectionURI", + "halo.server.name", + "halo.server.connectionIsLocal", ] } @@ -93,7 +93,7 @@ final class FlixySession { /// Wer angemeldet ist — sofern der Server einen Namen dafür kennt. var accountName: String? { jellyfinAccount?.userName } - /// Die Mediatheken, die Flixy darstellen kann — Musik und Fotos + /// Die Mediatheken, die Halo darstellen kann — Musik und Fotos /// erscheinen gar nicht erst. private(set) var libraries: [MediaLibrary] = [] @@ -233,14 +233,14 @@ final class FlixySession { /// Meldet sich an der Attrappe aus `Tools/JellyfinStub` an. /// /// Nur in der Entwicklung und nur auf ausdrückliches Kommando: - /// `-FlixyStubServer http://127.0.0.1:8096` als Startargument. Der Weg + /// `-HaloStubServer http://127.0.0.1:8096` als Startargument. Der Weg /// führt bewusst **am Schlüsselbund vorbei** und schreibt nichts fort — /// so lässt sich die Oberfläche ansehen, prüfen und fotografieren, ohne /// dass je ein echter Server, ein echtes Konto oder ein echter Token im /// Spiel wäre. Genau daran hat es bisher gefehlt: Aussagen über das /// Aussehen waren Vermutungen, weil niemand hinsehen konnte. private func adoptStubServerIfRequested() async -> Bool { - guard let raw = defaults.string(forKey: "FlixyStubServer"), + guard let raw = defaults.string(forKey: "HaloStubServer"), let baseURL = URL(string: raw) else { return false } diff --git a/Flixy/Session/HeroArtwork.swift b/Halo/Session/HeroArtwork.swift similarity index 96% rename from Flixy/Session/HeroArtwork.swift rename to Halo/Session/HeroArtwork.swift index 63ab0c3..1d1eed0 100644 --- a/Flixy/Session/HeroArtwork.swift +++ b/Halo/Session/HeroArtwork.swift @@ -1,5 +1,5 @@ import Foundation -import FlixyDesign +import HaloDesign import MediaKit /// Woher der Aufmacher seine Bilder nimmt. @@ -64,8 +64,8 @@ enum HeroArtwork { } static func aspectRatio(_ placement: Placement = .carousel, compact: Bool) -> CGFloat { - if isPortrait(placement, compact: compact) { return FlixyAspectRatio.poster } - return compact ? FlixyAspectRatio.heroCompact : FlixyAspectRatio.hero + if isPortrait(placement, compact: compact) { return HaloAspectRatio.poster } + return compact ? HaloAspectRatio.heroCompact : HaloAspectRatio.hero } static func backdropURL( diff --git a/Flixy/Session/HomeFeed.swift b/Halo/Session/HomeFeed.swift similarity index 100% rename from Flixy/Session/HomeFeed.swift rename to Halo/Session/HomeFeed.swift diff --git a/Flixy/Session/HomeLayoutSettings.swift b/Halo/Session/HomeLayoutSettings.swift similarity index 92% rename from Flixy/Session/HomeLayoutSettings.swift rename to Halo/Session/HomeLayoutSettings.swift index 19aca00..7c878b0 100644 --- a/Flixy/Session/HomeLayoutSettings.swift +++ b/Halo/Session/HomeLayoutSettings.swift @@ -12,15 +12,15 @@ import MediaKit @Observable final class HomeLayoutSettings { private enum Key { - static let hidden = "flixy.home.hiddenHubs" - static let order = "flixy.home.hubOrder" - static let heroCount = "flixy.home.heroCount" - static let heroSource = "flixy.home.heroSource" - static let heroLibraries = "flixy.home.heroLibraries" - static let combinesContinueRows = "flixy.home.combinesContinueRows" - static let hidesWatchedInLatest = "flixy.home.hidesWatchedInLatest" - static let cardScale = "flixy.home.cardScale" - static let heroHeight = "flixy.home.heroHeight" + static let hidden = "halo.home.hiddenHubs" + static let order = "halo.home.hubOrder" + static let heroCount = "halo.home.heroCount" + static let heroSource = "halo.home.heroSource" + static let heroLibraries = "halo.home.heroLibraries" + static let combinesContinueRows = "halo.home.combinesContinueRows" + static let hidesWatchedInLatest = "halo.home.hidesWatchedInLatest" + static let cardScale = "halo.home.cardScale" + static let heroHeight = "halo.home.heroHeight" } /// Woraus sich der Aufmacher speist. diff --git a/Flixy/Session/JellyfinSignInModel.swift b/Halo/Session/JellyfinSignInModel.swift similarity index 98% rename from Flixy/Session/JellyfinSignInModel.swift rename to Halo/Session/JellyfinSignInModel.swift index c3ca91a..0d55b33 100644 --- a/Flixy/Session/JellyfinSignInModel.swift +++ b/Halo/Session/JellyfinSignInModel.swift @@ -5,14 +5,14 @@ import Observation /// Führt durch die Anmeldung an einem Jellyfin-Server. /// -/// Eigenes Modell statt eines weiteren Falls in `FlixySession.Phase`: die +/// Eigenes Modell statt eines weiteren Falls in `HaloSession.Phase`: die /// Anmeldung besteht aus mehreren Schritten mit eigener Bedienung — Adresse /// eintippen, Code bestätigen lassen, notfalls doch Benutzername und Passwort /// —, und keiner davon interessiert den Rest der App. Was hier ankommt, ist am /// Ende ein einziges Ergebnis: ein Konto und ein Weg dorthin. /// /// **Quick Connect zuerst.** Der sechsstellige Code wird in einem bereits -/// angemeldeten Client bestätigt; das Passwort erreicht Flixy dabei nie — +/// angemeldeten Client bestätigt; das Passwort erreicht Halo dabei nie — /// dieselbe Zusage wie bei Plex, wo die Anmeldemaske von Plex selbst kommt. /// Benutzername und Passwort sind der Rückfall für Server, auf denen Quick /// Connect abgeschaltet ist. Dann hält die App das Passwort für die Dauer diff --git a/Flixy/Session/LanguagePreferences.swift b/Halo/Session/LanguagePreferences.swift similarity index 93% rename from Flixy/Session/LanguagePreferences.swift rename to Halo/Session/LanguagePreferences.swift index 60e2954..821dafb 100644 --- a/Flixy/Session/LanguagePreferences.swift +++ b/Halo/Session/LanguagePreferences.swift @@ -1,7 +1,7 @@ import Foundation import Observation import MediaKit -import FlixyPlayback +import HaloPlayback /// Welche Tonspur gewählt werden soll — und auf welcher Ebene das jemand /// gesagt hat. @@ -28,13 +28,13 @@ final class LanguagePreferences { private enum Key { /// Absichtlich die Schlüssel aus `PlaybackSettings`: hier ist nur der /// Besitzer gewechselt, nicht der Wert. - static let audio = "flixy.playback.audioLanguage" - static let subtitles = "flixy.playback.subtitleLanguage" - static let fallbacks = "flixy.languages.fallbacks" - static let avoidsAudioDescription = "flixy.languages.avoidsAudioDescription" - static let perLibrary = "flixy.languages.library" - static let perSeries = "flixy.languages.series" - static let rememberedTracks = "flixy.languages.seriesTrack" + static let audio = "halo.playback.audioLanguage" + static let subtitles = "halo.playback.subtitleLanguage" + static let fallbacks = "halo.languages.fallbacks" + static let avoidsAudioDescription = "halo.languages.avoidsAudioDescription" + static let perLibrary = "halo.languages.library" + static let perSeries = "halo.languages.series" + static let rememberedTracks = "halo.languages.seriesTrack" } /// Die Sprachen, die zur Auswahl stehen. diff --git a/Flixy/Session/LibraryFeed.swift b/Halo/Session/LibraryFeed.swift similarity index 100% rename from Flixy/Session/LibraryFeed.swift rename to Halo/Session/LibraryFeed.swift diff --git a/Flixy/Session/MediaItem+Presentation.swift b/Halo/Session/MediaItem+Presentation.swift similarity index 98% rename from Flixy/Session/MediaItem+Presentation.swift rename to Halo/Session/MediaItem+Presentation.swift index 36f3cbf..8a44b0b 100644 --- a/Flixy/Session/MediaItem+Presentation.swift +++ b/Halo/Session/MediaItem+Presentation.swift @@ -10,7 +10,7 @@ import MediaKit /// sieht nicht nach einem Fehler aus, sondern nach einem Server ohne Bild. /// /// Reine Ableitungen aus `MediaItem`, keine Ansicht — deshalb neben den -/// übrigen Modellen und nicht in FlixyDesign, das `MediaItem` gar nicht kennt. +/// übrigen Modellen und nicht in HaloDesign, das `MediaItem` gar nicht kennt. extension MediaItem { /// Der Titel auf einer Kachel in einer Reihe. /// diff --git a/Flixy/Session/NavigationLayoutSettings.swift b/Halo/Session/NavigationLayoutSettings.swift similarity index 95% rename from Flixy/Session/NavigationLayoutSettings.swift rename to Halo/Session/NavigationLayoutSettings.swift index 233d2f9..83480d8 100644 --- a/Flixy/Session/NavigationLayoutSettings.swift +++ b/Halo/Session/NavigationLayoutSettings.swift @@ -13,8 +13,8 @@ import MediaKit @Observable final class NavigationLayoutSettings { private enum Key { - static let hidden = "flixy.navigation.hidden" - static let order = "flixy.navigation.order" + static let hidden = "halo.navigation.hidden" + static let order = "halo.navigation.order" } private let defaults: UserDefaults diff --git a/Flixy/Session/NowPlaying.swift b/Halo/Session/NowPlaying.swift similarity index 100% rename from Flixy/Session/NowPlaying.swift rename to Halo/Session/NowPlaying.swift diff --git a/Flixy/Session/OrientationLock.swift b/Halo/Session/OrientationLock.swift similarity index 100% rename from Flixy/Session/OrientationLock.swift rename to Halo/Session/OrientationLock.swift diff --git a/Flixy/Session/PlaybackCoordinator.swift b/Halo/Session/PlaybackCoordinator.swift similarity index 100% rename from Flixy/Session/PlaybackCoordinator.swift rename to Halo/Session/PlaybackCoordinator.swift diff --git a/Flixy/Session/PlaybackDiagnostics.swift b/Halo/Session/PlaybackDiagnostics.swift similarity index 99% rename from Flixy/Session/PlaybackDiagnostics.swift rename to Halo/Session/PlaybackDiagnostics.swift index 8d0fd95..015dfe5 100644 --- a/Flixy/Session/PlaybackDiagnostics.swift +++ b/Halo/Session/PlaybackDiagnostics.swift @@ -1,6 +1,6 @@ import Foundation import Observation -import FlixyPlayback +import HaloPlayback /// Hält fest, was beim letzten Abspielversuch passiert ist. /// diff --git a/Flixy/Session/PlaybackSettings.swift b/Halo/Session/PlaybackSettings.swift similarity index 87% rename from Flixy/Session/PlaybackSettings.swift rename to Halo/Session/PlaybackSettings.swift index 7a93ce2..b5310a3 100644 --- a/Flixy/Session/PlaybackSettings.swift +++ b/Halo/Session/PlaybackSettings.swift @@ -1,6 +1,6 @@ import Foundation import Observation -import FlixyPlayback +import HaloPlayback /// Was der Nutzer über die Wiedergabe eingestellt hat. /// @@ -28,19 +28,19 @@ final class PlaybackSettings { } private enum Key { - static let wifiQuality = "flixy.playback.quality.wifi" - static let cellularQuality = "flixy.playback.quality.cellular" - static let autoSkipIntro = "flixy.playback.autoSkipIntro" - static let autoSkipCredits = "flixy.playback.autoSkipCredits" - static let autoPlayNext = "flixy.playback.autoPlayNext" - static let locksLandscape = "flixy.playback.locksLandscape" - static let rewindSeconds = "flixy.playback.rewindSeconds" - static let forwardSeconds = "flixy.playback.forwardSeconds" - static let defaultRate = "flixy.playback.defaultRate" - static let remembersQuality = "flixy.playback.remembersQuality" - static let rememberedQuality = "flixy.playback.rememberedQuality" - static let showsBitrate = "flixy.playback.showsBitrate" - static let lastPlaybackStruggled = "flixy.playback.struggled" + static let wifiQuality = "halo.playback.quality.wifi" + static let cellularQuality = "halo.playback.quality.cellular" + static let autoSkipIntro = "halo.playback.autoSkipIntro" + static let autoSkipCredits = "halo.playback.autoSkipCredits" + static let autoPlayNext = "halo.playback.autoPlayNext" + static let locksLandscape = "halo.playback.locksLandscape" + static let rewindSeconds = "halo.playback.rewindSeconds" + static let forwardSeconds = "halo.playback.forwardSeconds" + static let defaultRate = "halo.playback.defaultRate" + static let remembersQuality = "halo.playback.remembersQuality" + static let rememberedQuality = "halo.playback.rememberedQuality" + static let showsBitrate = "halo.playback.showsBitrate" + static let lastPlaybackStruggled = "halo.playback.struggled" } /// Die Sprünge, die es zur Auswahl gibt. diff --git a/Flixy/Session/QuickPlay.swift b/Halo/Session/QuickPlay.swift similarity index 100% rename from Flixy/Session/QuickPlay.swift rename to Halo/Session/QuickPlay.swift diff --git a/Flixy/Session/ScreenSafeArea.swift b/Halo/Session/ScreenSafeArea.swift similarity index 100% rename from Flixy/Session/ScreenSafeArea.swift rename to Halo/Session/ScreenSafeArea.swift diff --git a/Flixy/Session/SearchFeed.swift b/Halo/Session/SearchFeed.swift similarity index 98% rename from Flixy/Session/SearchFeed.swift rename to Halo/Session/SearchFeed.swift index b66838e..768987e 100644 --- a/Flixy/Session/SearchFeed.swift +++ b/Halo/Session/SearchFeed.swift @@ -15,7 +15,7 @@ import Observation final class SearchFeed { /// Wie viele zuletzt gesuchte Begriffe gemerkt werden. private static let recentLimit = 8 - private static let recentKey = "flixy.search.recent" + private static let recentKey = "halo.search.recent" private(set) var hubs: [MediaRowGroup] = [] private(set) var isSearching = false diff --git a/Flixy/Session/SubtitleAppearance.swift b/Halo/Session/SubtitleAppearance.swift similarity index 91% rename from Flixy/Session/SubtitleAppearance.swift rename to Halo/Session/SubtitleAppearance.swift index 4dcfbef..3c28e1f 100644 --- a/Flixy/Session/SubtitleAppearance.swift +++ b/Halo/Session/SubtitleAppearance.swift @@ -1,6 +1,6 @@ import Foundation import Observation -import FlixyPlayback +import HaloPlayback /// Wie Untertitel aussehen sollen — gemerkt über Neustarts hinweg. /// @@ -14,8 +14,8 @@ import FlixyPlayback @Observable final class SubtitleAppearance { private enum Key { - static let size = "flixy.subtitles.size" - static let palette = "flixy.subtitles.palette" + static let size = "halo.subtitles.size" + static let palette = "halo.subtitles.palette" } private let defaults: UserDefaults diff --git a/Flixy/Session/SubtitleStyle+Labels.swift b/Halo/Session/SubtitleStyle+Labels.swift similarity index 98% rename from Flixy/Session/SubtitleStyle+Labels.swift rename to Halo/Session/SubtitleStyle+Labels.swift index ad0e4cd..753918a 100644 --- a/Flixy/Session/SubtitleStyle+Labels.swift +++ b/Halo/Session/SubtitleStyle+Labels.swift @@ -1,4 +1,4 @@ -import FlixyPlayback +import HaloPlayback import Foundation /// Die Namen der Stufen stehen neben dem Modell, nicht darin — dasselbe diff --git a/Flixy/Session/TopShelfWriter.swift b/Halo/Session/TopShelfWriter.swift similarity index 97% rename from Flixy/Session/TopShelfWriter.swift rename to Halo/Session/TopShelfWriter.swift index 29dbee7..976399c 100644 --- a/Flixy/Session/TopShelfWriter.swift +++ b/Halo/Session/TopShelfWriter.swift @@ -1,6 +1,6 @@ // **Die ganze Datei nur für den Fernseher.** // -// Sie liegt im geteilten Ordner, weil `Flixy/Session/` von beiden Zielen +// Sie liegt im geteilten Ordner, weil `Halo/Session/` von beiden Zielen // übersetzt wird — und `TVServices` gibt es auf iOS nicht. Ein `#if` um den // einen Import genügte dabei nicht: der Abhängigkeits-Sucher von Clang prüft // ihn trotzdem und bricht mit „Unable to resolve module dependency: @@ -21,7 +21,7 @@ import TVServices @MainActor enum TopShelfWriter { /// Die App-Gruppe, die App und Erweiterung teilen. - static let group = "group.com.scarriffleservices.flixy" + static let group = "group.com.scarriffleservices.halo" /// Die Kante, in der das Regal Plakate zeigt. /// diff --git a/Flixy/Views/Components/ItemActionEntries.swift b/Halo/Views/Components/ItemActionEntries.swift similarity index 98% rename from Flixy/Views/Components/ItemActionEntries.swift rename to Halo/Views/Components/ItemActionEntries.swift index 5b43238..2609a0a 100644 --- a/Flixy/Views/Components/ItemActionEntries.swift +++ b/Halo/Views/Components/ItemActionEntries.swift @@ -99,5 +99,5 @@ extension EnvironmentValues { /// /// Die Voreinstellung tut nichts: wo niemand etwas hinterlegt, gibt es /// auch nichts neu zu laden. - @Entry var flixyItemChanged: () async -> Void = {} + @Entry var haloItemChanged: () async -> Void = {} } diff --git a/Flixy/Views/Components/QuickPlayTile.swift b/Halo/Views/Components/QuickPlayTile.swift similarity index 96% rename from Flixy/Views/Components/QuickPlayTile.swift rename to Halo/Views/Components/QuickPlayTile.swift index 8c9a8d7..a6c04ed 100644 --- a/Flixy/Views/Components/QuickPlayTile.swift +++ b/Halo/Views/Components/QuickPlayTile.swift @@ -1,6 +1,6 @@ import SwiftUI -import FlixyDesign -import FlixyDownloads +import HaloDesign +import HaloDownloads import MediaKit /// Eine Kachel, die zur Detailseite führt — mit einem Knopf, der sofort @@ -11,7 +11,7 @@ import MediaKit /// Zwei Schritte für eine Absicht. /// /// **Warum eine Hülle und keine Änderung an der Karte.** `PosterCard` liegt -/// in `FlixyDesign`, und das Paket ist ohne Abhängigkeiten deklariert — es +/// in `HaloDesign`, und das Paket ist ohne Abhängigkeiten deklariert — es /// kennt weder `MediaItem` noch `PlaybackCoordinator`. Ein Überzug **in** der /// Karte fiele ausserdem unter ihr `.accessibilityElement(children: .combine)` /// und wäre für VoiceOver gar nicht mehr da. @@ -27,12 +27,12 @@ struct QuickPlayTile: View { var opensDetails: Bool = false @ViewBuilder let card: () -> Card - @Environment(FlixySession.self) private var session + @Environment(HaloSession.self) private var session @Environment(PlaybackCoordinator.self) private var playback @Environment(QuickPlay.self) private var quickPlay @Environment(DownloadCoordinator.self) private var downloads @Environment(LanguagePreferences.self) private var languages - @Environment(\.flixyAccent) private var accent + @Environment(\.haloAccent) private var accent @State private var isPointerInside = false @State private var errorMessage: String? @@ -48,11 +48,11 @@ struct QuickPlayTile: View { /// Was die umgebende Seite tun soll, wenn sich am Server etwas geändert /// hat. Siehe `ItemActionEntries`. - @Environment(\.flixyItemChanged) private var itemChanged + @Environment(\.haloItemChanged) private var itemChanged /// Der Weg auf die Detailseite — siehe `MediaStack`. - @Environment(\.flixyPush) private var push + @Environment(\.haloPush) private var push - private var isMac: Bool { FlixyPlatform.isMac } + private var isMac: Bool { HaloPlatform.isMac } /// Ob es überhaupt etwas zu starten gibt. /// @@ -236,7 +236,7 @@ struct QuickPlayTile: View { .shadow(color: .black.opacity(0.35), radius: 3, y: 1) } .buttonStyle(.plain) - .padding(FlixySpacing.snug) + .padding(HaloSpacing.snug) .opacity(isPointerInside ? 1 : 0) // Er ist eine Zeigergeste; für VoiceOver gibt es die benannte Aktion // oben. Beides anzubieten hiesse, jede Kachel zu verdoppeln. diff --git a/Flixy/Views/Detail/ItemActionsMenu.swift b/Halo/Views/Detail/ItemActionsMenu.swift similarity index 97% rename from Flixy/Views/Detail/ItemActionsMenu.swift rename to Halo/Views/Detail/ItemActionsMenu.swift index 85d6912..3eec8ef 100644 --- a/Flixy/Views/Detail/ItemActionsMenu.swift +++ b/Halo/Views/Detail/ItemActionsMenu.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign import MediaKit /// Das Aktionsmenü auf einer Detailseite. @@ -17,7 +17,7 @@ struct ItemActionsMenu: View { /// Detailseite neu geladen werden sollte. let onChange: () async -> Void - @Environment(FlixySession.self) private var session + @Environment(HaloSession.self) private var session @State private var isWorking = false @State private var errorMessage: String? diff --git a/Flixy/Views/Detail/MediaDetailView.swift b/Halo/Views/Detail/MediaDetailView.swift similarity index 89% rename from Flixy/Views/Detail/MediaDetailView.swift rename to Halo/Views/Detail/MediaDetailView.swift index d06a4f3..c4c527d 100644 --- a/Flixy/Views/Detail/MediaDetailView.swift +++ b/Halo/Views/Detail/MediaDetailView.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign import MediaKit /// Die Detailseite eines Titels. @@ -10,7 +10,7 @@ import MediaKit struct MediaDetailView: View { let route: MediaRoute - @Environment(FlixySession.self) private var session + @Environment(HaloSession.self) private var session @State private var state: LoadState = .loading var body: some View { @@ -37,12 +37,12 @@ struct MediaDetailView: View { } } } - .background(Color.flixyCanvas) + .background(Color.haloCanvas) .navigationTitle(state.value?.title ?? route.title) - .flixyInlineTitle() + .haloInlineTitle() .toolbar { if let item = state.value { - ToolbarItem(placement: .flixyTrailing) { + ToolbarItem(placement: .haloTrailing) { ItemActionsMenu(item: item) { await load() } } } diff --git a/Flixy/Views/Detail/ParentLinks.swift b/Halo/Views/Detail/ParentLinks.swift similarity index 85% rename from Flixy/Views/Detail/ParentLinks.swift rename to Halo/Views/Detail/ParentLinks.swift index 9e1850f..abf61d4 100644 --- a/Flixy/Views/Detail/ParentLinks.swift +++ b/Halo/Views/Detail/ParentLinks.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign import MediaKit /// Der Weg nach oben: von der Folge zur Staffel, von der Staffel zur Serie. @@ -15,7 +15,7 @@ struct ParentLinks: View { var body: some View { if !destinations.isEmpty { ScrollView(.horizontal) { - HStack(spacing: FlixySpacing.snug) { + HStack(spacing: HaloSpacing.snug) { ForEach(destinations, id: \.route.ratingKey) { destination in NavigationLink(value: destination.route) { Label { @@ -24,16 +24,16 @@ struct ParentLinks: View { } icon: { Image(systemName: destination.symbol) } - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextPrimary) - .padding(.horizontal, FlixySpacing.regular) - .padding(.vertical, FlixySpacing.snug) - .background(Color.flixyElevated, in: .capsule) + .font(.haloCaption) + .foregroundStyle(Color.haloTextPrimary) + .padding(.horizontal, HaloSpacing.regular) + .padding(.vertical, HaloSpacing.snug) + .background(Color.haloElevated, in: .capsule) } .buttonStyle(.plain) } } - .padding(.horizontal, FlixySpacing.screenMargin) + .padding(.horizontal, HaloSpacing.screenMargin) } .scrollIndicators(.never) } diff --git a/Flixy/Views/Detail/PlayableDetailView.swift b/Halo/Views/Detail/PlayableDetailView.swift similarity index 80% rename from Flixy/Views/Detail/PlayableDetailView.swift rename to Halo/Views/Detail/PlayableDetailView.swift index 97e17a6..061ee82 100644 --- a/Flixy/Views/Detail/PlayableDetailView.swift +++ b/Halo/Views/Detail/PlayableDetailView.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign import MediaKit /// Die Detailseite von etwas, das sich direkt abspielen lässt — Film oder @@ -7,9 +7,9 @@ import MediaKit struct PlayableDetailView: View { let item: MediaItem - @Environment(FlixySession.self) private var session + @Environment(HaloSession.self) private var session @Environment(PlaybackCoordinator.self) private var playback - @Environment(\.flixyAccent) private var accent + @Environment(\.haloAccent) private var accent @Environment(\.horizontalSizeClass) private var sizeClass @State private var selectedVersion = 0 @@ -17,7 +17,7 @@ struct PlayableDetailView: View { var body: some View { ScrollView { - VStack(alignment: .leading, spacing: FlixySpacing.section) { + VStack(alignment: .leading, spacing: HaloSpacing.section) { header // Bei einer Folge nicht mehr: dorthin führt jetzt die Zeile @@ -29,14 +29,14 @@ struct PlayableDetailView: View { if item.hasMultipleVersions { VersionPicker(media: item.versions, selection: $selectedVersion) - .padding(.horizontal, FlixySpacing.screenMargin) + .padding(.horizontal, HaloSpacing.screenMargin) } if let summary = item.summary, !summary.isEmpty { Text(summary) - .font(.flixyBody) - .foregroundStyle(Color.flixyTextSecondary) - .padding(.horizontal, FlixySpacing.screenMargin) + .font(.haloBody) + .foregroundStyle(Color.haloTextSecondary) + .padding(.horizontal, HaloSpacing.screenMargin) } if !item.genres.isEmpty { @@ -53,13 +53,13 @@ struct PlayableDetailView: View { part: part, isExpanded: $showsTechnicalDetails ) - .padding(.horizontal, FlixySpacing.screenMargin) + .padding(.horizontal, HaloSpacing.screenMargin) } } - .padding(.bottom, FlixySpacing.section) + .padding(.bottom, HaloSpacing.section) } .scrollIndicators(.never) - .flixyRevealsTopChrome() + .haloRevealsTopChrome() } private var currentMedia: MediaVersion? { @@ -104,9 +104,9 @@ struct PlayableDetailView: View { item.watchProgress == nil ? "hero.play" : "hero.resume", systemImage: "play.fill" ) - .font(.flixyCardTitle) - .padding(.horizontal, FlixySpacing.loose) - .padding(.vertical, FlixySpacing.snug) + .font(.haloCardTitle) + .padding(.horizontal, HaloSpacing.loose) + .padding(.vertical, HaloSpacing.snug) } .buttonStyle(.borderedProminent) .tint(accent) @@ -118,11 +118,11 @@ struct PlayableDetailView: View { } label: { Label("detail.playFromStart", systemImage: "gobackward") .labelStyle(.iconOnly) - .font(.flixyCardTitle) - .padding(FlixySpacing.snug) + .font(.haloCardTitle) + .padding(HaloSpacing.snug) } .buttonStyle(.bordered) - .tint(Color.flixyTextSecondary) + .tint(Color.haloTextSecondary) } DownloadButton(item: item, mediaIndex: selectedVersion) @@ -210,10 +210,10 @@ struct VersionPicker: View { @Binding var selection: Int var body: some View { - VStack(alignment: .leading, spacing: FlixySpacing.snug) { + VStack(alignment: .leading, spacing: HaloSpacing.snug) { Text("detail.versions") - .font(.flixyRowHeader) - .foregroundStyle(Color.flixyTextPrimary) + .font(.haloRowHeader) + .foregroundStyle(Color.haloTextPrimary) Picker("detail.versions", selection: $selection) { ForEach(Array(media.enumerated()), id: \.offset) { index, version in @@ -232,17 +232,17 @@ struct TagStrip: View { var body: some View { ScrollView(.horizontal) { - HStack(spacing: FlixySpacing.snug) { + HStack(spacing: HaloSpacing.snug) { ForEach(tags, id: \.self) { tag in Text(tag) - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextSecondary) - .padding(.horizontal, FlixySpacing.regular) - .padding(.vertical, FlixySpacing.tight) - .background(Color.flixyElevated, in: .capsule) + .font(.haloCaption) + .foregroundStyle(Color.haloTextSecondary) + .padding(.horizontal, HaloSpacing.regular) + .padding(.vertical, HaloSpacing.tight) + .background(Color.haloElevated, in: .capsule) } } - .padding(.horizontal, FlixySpacing.screenMargin) + .padding(.horizontal, HaloSpacing.screenMargin) } .scrollIndicators(.never) } @@ -251,20 +251,20 @@ struct TagStrip: View { /// Die Besetzung mit Porträts. struct CastRow: View { let cast: [MediaPerson] - @Environment(FlixySession.self) private var session + @Environment(HaloSession.self) private var session var body: some View { - VStack(alignment: .leading, spacing: FlixySpacing.regular) { + VStack(alignment: .leading, spacing: HaloSpacing.regular) { Text("detail.cast") - .font(.flixyRowHeader) - .foregroundStyle(Color.flixyTextPrimary) - .padding(.horizontal, FlixySpacing.screenMargin) + .font(.haloRowHeader) + .foregroundStyle(Color.haloTextPrimary) + .padding(.horizontal, HaloSpacing.screenMargin) ScrollView(.horizontal) { - HStack(alignment: .top, spacing: FlixySpacing.regular) { + HStack(alignment: .top, spacing: HaloSpacing.regular) { ForEach(cast.prefix(20)) { role in - VStack(spacing: FlixySpacing.snug) { - FlixyArtwork( + VStack(spacing: HaloSpacing.snug) { + HaloArtwork( url: session.backend?.artworkURL(path: role.thumb, width: 160, height: 160), aspectRatio: 1, fallbackSymbol: "person" @@ -273,15 +273,15 @@ struct CastRow: View { .clipShape(.circle) Text(role.name) - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextPrimary) + .font(.haloCaption) + .foregroundStyle(Color.haloTextPrimary) .lineLimit(2) .multilineTextAlignment(.center) if let character = role.role { Text(character) - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextMuted) + .font(.haloCaption) + .foregroundStyle(Color.haloTextMuted) .lineLimit(1) } } @@ -289,7 +289,7 @@ struct CastRow: View { .accessibilityElement(children: .combine) } } - .padding(.horizontal, FlixySpacing.screenMargin) + .padding(.horizontal, HaloSpacing.screenMargin) } .scrollIndicators(.never) } diff --git a/Flixy/Views/Detail/SeriesDetailView.swift b/Halo/Views/Detail/SeriesDetailView.swift similarity index 88% rename from Flixy/Views/Detail/SeriesDetailView.swift rename to Halo/Views/Detail/SeriesDetailView.swift index ddbfc36..dc93fb7 100644 --- a/Flixy/Views/Detail/SeriesDetailView.swift +++ b/Halo/Views/Detail/SeriesDetailView.swift @@ -1,6 +1,6 @@ import SwiftUI -import FlixyDesign -import FlixyDownloads +import HaloDesign +import HaloDownloads import MediaKit /// Die Detailseite einer Serie oder Staffel. @@ -10,10 +10,10 @@ import MediaKit struct SeriesDetailView: View { let item: MediaItem - @Environment(FlixySession.self) private var session + @Environment(HaloSession.self) private var session @Environment(DownloadCoordinator.self) private var downloads @Environment(LanguagePreferences.self) private var languages - @Environment(\.flixyAccent) private var accent + @Environment(\.haloAccent) private var accent @Environment(\.horizontalSizeClass) private var sizeClass @State private var children: LoadState<[MediaItem]> = .loading @@ -35,16 +35,16 @@ struct SeriesDetailView: View { var body: some View { ScrollView { - VStack(alignment: .leading, spacing: FlixySpacing.section) { + VStack(alignment: .leading, spacing: HaloSpacing.section) { header ParentLinks(item: item) if let summary = item.summary, !summary.isEmpty { Text(summary) - .font(.flixyBody) - .foregroundStyle(Color.flixyTextSecondary) - .padding(.horizontal, FlixySpacing.screenMargin) + .font(.haloBody) + .foregroundStyle(Color.haloTextSecondary) + .padding(.horizontal, HaloSpacing.screenMargin) } if !item.genres.isEmpty { TagStrip(tags: item.genres) } @@ -58,17 +58,17 @@ struct SeriesDetailView: View { scope: .series(item.id), title: "languages.forThisSeries" ) - .padding(.horizontal, FlixySpacing.screenMargin) + .padding(.horizontal, HaloSpacing.screenMargin) } childList if !item.cast.isEmpty { CastRow(cast: item.cast) } } - .padding(.bottom, FlixySpacing.section) + .padding(.bottom, HaloSpacing.section) } .scrollIndicators(.never) - .flixyRevealsTopChrome() + .haloRevealsTopChrome() .safeAreaInset(edge: .bottom, spacing: 0) { selectionBar } .confirmationDialog( Text("downloads.quality.title"), @@ -163,34 +163,34 @@ struct SeriesDetailView: View { private var childList: some View { switch children { case .loading: - ProgressView().frame(maxWidth: .infinity).padding(.vertical, FlixySpacing.section) + ProgressView().frame(maxWidth: .infinity).padding(.vertical, HaloSpacing.section) case .failed(let message): Text(message) - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextMuted) - .padding(.horizontal, FlixySpacing.screenMargin) + .font(.haloCaption) + .foregroundStyle(Color.haloTextMuted) + .padding(.horizontal, HaloSpacing.screenMargin) case .loaded(let entries): - VStack(alignment: .leading, spacing: FlixySpacing.regular) { + VStack(alignment: .leading, spacing: HaloSpacing.regular) { // **Der Auswählen-Knopf steht bei dem, was er auswählt.** // Oben in der Werkzeugleiste wäre er weiter weg von der Liste // als von allem anderen auf dieser Seite. HStack { Text(item.kind == .show ? "detail.seasons" : "detail.episodes") - .font(.flixyRowHeader) - .foregroundStyle(Color.flixyTextPrimary) + .font(.haloRowHeader) + .foregroundStyle(Color.haloTextPrimary) Spacer() if entries.contains(where: { $0.kind == .episode }) { selectionControls(for: entries) } } - .padding(.horizontal, FlixySpacing.screenMargin) + .padding(.horizontal, HaloSpacing.screenMargin) LazyVStack(spacing: 0) { ForEach(entries) { entry in row(for: entry) - Divider().overlay(Color.flixySeparator) + Divider().overlay(Color.haloSeparator) } } } @@ -207,16 +207,16 @@ struct SeriesDetailView: View { Button { if gewaehlt { selection.remove(entry.id) } else { selection.insert(entry.id) } } label: { - HStack(spacing: FlixySpacing.snug) { + HStack(spacing: HaloSpacing.snug) { ChildRow(item: entry) Image(systemName: gewaehlt ? "checkmark.circle.fill" : "circle") .font(.title3) - .foregroundStyle(gewaehlt ? accent : Color.flixyTextMuted) + .foregroundStyle(gewaehlt ? accent : Color.haloTextMuted) } .contentShape(.rect) } .buttonStyle(.plain) - .padding(.horizontal, FlixySpacing.screenMargin) + .padding(.horizontal, HaloSpacing.screenMargin) .accessibilityAddTraits(gewaehlt ? .isSelected : []) } else { // **Der Knopf steht neben dem Link, nicht darin.** Ein `Button` im @@ -228,7 +228,7 @@ struct SeriesDetailView: View { // Als Geschwister in einer Reihe statt als Überzug: dann teilt das // Layout den Platz auf, und der Titel kann gar nicht erst unter // dem Knopf verschwinden. - HStack(spacing: FlixySpacing.snug) { + HStack(spacing: HaloSpacing.snug) { NavigationLink(value: MediaRoute(ratingKey: entry.id, title: entry.title)) { ChildRow(item: entry) } @@ -241,7 +241,7 @@ struct SeriesDetailView: View { DownloadButton(item: entry, loadsDetails: true) } } - .padding(.horizontal, FlixySpacing.screenMargin) + .padding(.horizontal, HaloSpacing.screenMargin) } } @@ -249,7 +249,7 @@ struct SeriesDetailView: View { private func selectionControls(for entries: [MediaItem]) -> some View { let folgen = entries.filter { $0.kind == .episode }.map(\.id) - HStack(spacing: FlixySpacing.regular) { + HStack(spacing: HaloSpacing.regular) { if isSelecting { Button(selection.count == folgen.count ? "detail.selectNone" : "detail.selectAll") { selection = selection.count == folgen.count ? [] : Set(folgen) @@ -258,12 +258,12 @@ struct SeriesDetailView: View { isSelecting = false selection = [] } - .foregroundStyle(Color.flixyTextSecondary) + .foregroundStyle(Color.haloTextSecondary) } else { Button("detail.select") { isSelecting = true } } } - .font(.flixyCaption) + .font(.haloCaption) .buttonStyle(.plain) .foregroundStyle(accent) } @@ -288,14 +288,14 @@ struct SeriesDetailView: View { ) } } - .font(.flixyCardTitle) - .padding(.horizontal, FlixySpacing.loose) - .padding(.vertical, FlixySpacing.snug) + .font(.haloCardTitle) + .padding(.horizontal, HaloSpacing.loose) + .padding(.vertical, HaloSpacing.snug) } .buttonStyle(.borderedProminent) .tint(accent) .disabled(isWorking) - .padding(.vertical, FlixySpacing.regular) + .padding(.vertical, HaloSpacing.regular) .frame(maxWidth: .infinity) .background(.bar) } @@ -387,11 +387,11 @@ struct SeriesDetailView: View { /// Eine Staffel- oder Folgenzeile. private struct ChildRow: View { let item: MediaItem - @Environment(FlixySession.self) private var session + @Environment(HaloSession.self) private var session var body: some View { - HStack(spacing: FlixySpacing.regular) { - FlixyArtwork( + HStack(spacing: HaloSpacing.regular) { + HaloArtwork( url: session.backend?.artworkURL( path: item.thumb, width: item.kind == .season ? 120 : 240, @@ -411,14 +411,14 @@ private struct ChildRow: View { VStack(alignment: .leading, spacing: 2) { Text(rowTitle) - .font(.flixyCardTitle) - .foregroundStyle(Color.flixyTextPrimary) + .font(.haloCardTitle) + .foregroundStyle(Color.haloTextPrimary) .lineLimit(2) if let subtitle { Text(subtitle) - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextMuted) + .font(.haloCaption) + .foregroundStyle(Color.haloTextMuted) .lineLimit(1) } } @@ -427,14 +427,14 @@ private struct ChildRow: View { if item.isWatched { Image(systemName: "checkmark.circle.fill") - .foregroundStyle(Color.flixyTextMuted) + .foregroundStyle(Color.haloTextMuted) .accessibilityLabel(Text("item.watched")) } } // Das waagerechte Polster liegt jetzt eine Ebene höher, bei der // Reihe aus Zeile und Download-Knopf — sonst klebte der Knopf am // Bildschirmrand. - .padding(.vertical, FlixySpacing.snug) + .padding(.vertical, HaloSpacing.snug) .contentShape(.rect) .accessibilityElement(children: .combine) } diff --git a/Flixy/Views/Detail/TechnicalDetails.swift b/Halo/Views/Detail/TechnicalDetails.swift similarity index 84% rename from Flixy/Views/Detail/TechnicalDetails.swift rename to Halo/Views/Detail/TechnicalDetails.swift index 2d1cdd5..6b037f5 100644 --- a/Flixy/Views/Detail/TechnicalDetails.swift +++ b/Halo/Views/Detail/TechnicalDetails.swift @@ -1,11 +1,11 @@ import SwiftUI -import FlixyDesign -import FlixyPlayback +import HaloDesign +import HaloPlayback import MediaKit /// Die aufklappbaren technischen Angaben zu einer Datei. /// -/// Zeigt nicht nur, was in der Datei steckt, sondern auch, wie Flixy sie +/// Zeigt nicht nur, was in der Datei steckt, sondern auch, wie Halo sie /// abspielen wird und warum. Bei der Frage „warum ruckelt das" ist das die /// erste Stelle zum Nachsehen — und in Phase 1, wo es noch kein Transcoding /// gibt, erklärt es, warum bei manchen Dateien kein Bild-in-Bild angeboten wird. @@ -34,13 +34,13 @@ struct TechnicalDetails: View { var body: some View { DisclosureGroup(isExpanded: $isExpanded) { - VStack(alignment: .leading, spacing: FlixySpacing.snug) { + VStack(alignment: .leading, spacing: HaloSpacing.snug) { row("technical.playbackMethod", playbackMethodLabel) if let reason = rationaleLabel { row("technical.reason", reason) } - Divider().overlay(Color.flixySeparator).padding(.vertical, FlixySpacing.tight) + Divider().overlay(Color.haloSeparator).padding(.vertical, HaloSpacing.tight) if let container = part.container { row("technical.container", container.uppercased()) } if let codec = media.videoCodec { row("technical.videoCodec", codec.uppercased()) } @@ -55,7 +55,7 @@ struct TechnicalDetails: View { } if !part.audioStreams.isEmpty { - Divider().overlay(Color.flixySeparator).padding(.vertical, FlixySpacing.tight) + Divider().overlay(Color.haloSeparator).padding(.vertical, HaloSpacing.tight) ForEach(part.audioStreams) { stream in row("technical.audio", trackLabel(stream)) } @@ -68,36 +68,36 @@ struct TechnicalDetails: View { } if let file = part.file { - Divider().overlay(Color.flixySeparator).padding(.vertical, FlixySpacing.tight) + Divider().overlay(Color.haloSeparator).padding(.vertical, HaloSpacing.tight) VStack(alignment: .leading, spacing: 2) { Text("technical.file") - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextMuted) + .font(.haloCaption) + .foregroundStyle(Color.haloTextMuted) Text(file) .font(.system(.caption, design: .monospaced)) - .foregroundStyle(Color.flixyTextSecondary) + .foregroundStyle(Color.haloTextSecondary) .textSelection(.enabled) } } } - .padding(.top, FlixySpacing.snug) + .padding(.top, HaloSpacing.snug) } label: { Text("technical.title") - .font(.flixyRowHeader) - .foregroundStyle(Color.flixyTextPrimary) + .font(.haloRowHeader) + .foregroundStyle(Color.haloTextPrimary) } - .tint(Color.flixyTextSecondary) + .tint(Color.haloTextSecondary) } private func row(_ label: LocalizedStringKey, _ value: String) -> some View { HStack(alignment: .top) { Text(label) - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextMuted) + .font(.haloCaption) + .foregroundStyle(Color.haloTextMuted) Spacer() Text(value) - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextSecondary) + .font(.haloCaption) + .foregroundStyle(Color.haloTextSecondary) .multilineTextAlignment(.trailing) } } diff --git a/Flixy/Views/Downloads/DownloadButton.swift b/Halo/Views/Downloads/DownloadButton.swift similarity index 96% rename from Flixy/Views/Downloads/DownloadButton.swift rename to Halo/Views/Downloads/DownloadButton.swift index b4b991e..6fa8e2c 100644 --- a/Flixy/Views/Downloads/DownloadButton.swift +++ b/Halo/Views/Downloads/DownloadButton.swift @@ -1,6 +1,6 @@ import SwiftUI -import FlixyDesign -import FlixyDownloads +import HaloDesign +import HaloDownloads import MediaKit /// Der Download-Knopf auf einer Detailseite. @@ -25,10 +25,10 @@ struct DownloadButton: View { /// nicht drückt. var loadsDetails: Bool = false - @Environment(FlixySession.self) private var session + @Environment(HaloSession.self) private var session @Environment(DownloadCoordinator.self) private var downloads @Environment(LanguagePreferences.self) private var languages - @Environment(\.flixyAccent) private var accent + @Environment(\.haloAccent) private var accent @State private var refusal: DownloadRefusal? @State private var showsQualityChoice = false @@ -64,18 +64,18 @@ struct DownloadButton: View { } else { Label(label, systemImage: symbol) .labelStyle(.iconOnly) - .font(.flixyCardTitle) + .font(.haloCardTitle) } } // Feste Größe, damit der Knopf beim Nachladen nicht springt: der // Kreisel ist schmaler als das Symbol, und eine Zeile, die während // des Wartens die Breite wechselt, sieht aus wie ein Fehler. .frame(width: 22, height: 22) - .padding(FlixySpacing.snug) + .padding(HaloSpacing.snug) } .disabled(isLoadingDetails) .buttonStyle(.bordered) - .tint(existing?.state == .completed ? accent : Color.flixyTextSecondary) + .tint(existing?.state == .completed ? accent : Color.haloTextSecondary) .accessibilityLabel(Text(label)) .confirmationDialog( Text("downloads.quality.title"), @@ -247,10 +247,10 @@ extension DownloadQuality { struct DownloadAllButton: View { let container: MediaItem - @Environment(FlixySession.self) private var session + @Environment(HaloSession.self) private var session @Environment(DownloadCoordinator.self) private var downloads @Environment(LanguagePreferences.self) private var languages - @Environment(\.flixyAccent) private var accent + @Environment(\.haloAccent) private var accent @State private var isWorking = false @State private var summary: String? @@ -269,7 +269,7 @@ struct DownloadAllButton: View { } } .buttonStyle(.bordered) - .tint(Color.flixyTextSecondary) + .tint(Color.haloTextSecondary) .disabled(isWorking) .alert( Text("downloads.batch.title"), diff --git a/Flixy/Views/Downloads/DownloadQualityChoice.swift b/Halo/Views/Downloads/DownloadQualityChoice.swift similarity index 99% rename from Flixy/Views/Downloads/DownloadQualityChoice.swift rename to Halo/Views/Downloads/DownloadQualityChoice.swift index e25d9e0..5c81f10 100644 --- a/Flixy/Views/Downloads/DownloadQualityChoice.swift +++ b/Halo/Views/Downloads/DownloadQualityChoice.swift @@ -1,5 +1,5 @@ import Foundation -import FlixyDownloads +import HaloDownloads import MediaKit /// Welche Qualitätsstufen für einen Titel zur Wahl stehen — und wie sie heißen. diff --git a/Flixy/Views/Downloads/DownloadsView.swift b/Halo/Views/Downloads/DownloadsView.swift similarity index 87% rename from Flixy/Views/Downloads/DownloadsView.swift rename to Halo/Views/Downloads/DownloadsView.swift index 742d314..ec71a40 100644 --- a/Flixy/Views/Downloads/DownloadsView.swift +++ b/Halo/Views/Downloads/DownloadsView.swift @@ -1,14 +1,14 @@ import SwiftUI -import FlixyDesign -import FlixyDownloads -import FlixyPlayback +import HaloDesign +import HaloDownloads +import HaloPlayback /// Was offline ist und was gerade geladen wird. struct DownloadsView: View { @Environment(DownloadCoordinator.self) private var downloads @Environment(PlaybackCoordinator.self) private var playback @Environment(NetworkConditions.self) private var network - @Environment(\.flixyAccent) private var accent + @Environment(\.haloAccent) private var accent @Environment(\.horizontalSizeClass) private var sizeClass @@ -24,16 +24,16 @@ struct DownloadsView: View { list } } - .background(Color.flixyCanvas) + .background(Color.haloCanvas) .navigationTitle(Text("sidebar.downloads")) .toolbar { // Nur auf dem iPhone: dort gibt es den Einstellungen-Tab nicht // mehr, und dies ist der Weg dorthin. if sizeClass == .compact { - ToolbarItem(placement: .flixyTrailing) { AccountToolbarButton() } + ToolbarItem(placement: .haloTrailing) { AccountToolbarButton() } } } - .flixyInlineTitle() + .haloInlineTitle() // Keine Rückfrage beim Entfernen. // // Sie stand hier, weil „löschen" nach etwas Endgültigem klingt. Es ist @@ -88,8 +88,8 @@ struct DownloadsView: View { } } .scrollContentBackground(.hidden) - .listRowBackground(Color.flixySurface) - .flixyRevealsTopChrome() + .listRowBackground(Color.haloSurface) + .haloRevealsTopChrome() } private var active: [DownloadItem] { @@ -125,7 +125,7 @@ struct DownloadsView: View { /// Die Kopfzeile mit Speicherbelegung und Schaltern. private struct StorageSection: View { @Environment(DownloadCoordinator.self) private var downloads - @Environment(\.flixyAccent) private var accent + @Environment(\.haloAccent) private var accent var body: some View { @Bindable var downloads = downloads @@ -133,10 +133,10 @@ private struct StorageSection: View { Section { HStack { Text("downloads.used") - .foregroundStyle(Color.flixyTextSecondary) + .foregroundStyle(Color.haloTextSecondary) Spacer() Text(downloads.usedBytes.formatted(.byteCount(style: .file))) - .foregroundStyle(Color.flixyTextPrimary) + .foregroundStyle(Color.haloTextPrimary) } if let limit = downloads.storageLimitBytes, limit > 0 { @@ -157,20 +157,20 @@ private struct DownloadRow: View { let onRemove: () -> Void @Environment(DownloadCoordinator.self) private var downloads - @Environment(\.flixyAccent) private var accent + @Environment(\.haloAccent) private var accent var body: some View { - VStack(alignment: .leading, spacing: FlixySpacing.snug) { - HStack(spacing: FlixySpacing.regular) { + VStack(alignment: .leading, spacing: HaloSpacing.snug) { + HStack(spacing: HaloSpacing.regular) { VStack(alignment: .leading, spacing: 2) { Text(item.title) - .font(.flixyCardTitle) - .foregroundStyle(Color.flixyTextPrimary) + .font(.haloCardTitle) + .foregroundStyle(Color.haloTextPrimary) .lineLimit(1) if let subtitle = item.subtitle { Text(subtitle) - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextMuted) + .font(.haloCaption) + .foregroundStyle(Color.haloTextMuted) .lineLimit(1) } } @@ -190,19 +190,19 @@ private struct DownloadRow: View { hold == .offline ? "downloads.hold.offline" : "downloads.hold.wifi", systemImage: hold == .offline ? "wifi.slash" : "wifi.exclamationmark" ) - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextMuted) + .font(.haloCaption) + .foregroundStyle(Color.haloTextMuted) } if let message = item.failureMessage { Text(message) - .font(.flixyCaption) - .foregroundStyle(Color.flixyDestructive) + .font(.haloCaption) + .foregroundStyle(Color.haloDestructive) .lineLimit(2) } } - .padding(.vertical, FlixySpacing.tight) - .listRowBackground(Color.flixySurface) + .padding(.vertical, HaloSpacing.tight) + .listRowBackground(Color.haloSurface) .swipeActions(edge: .trailing) { Button("action.delete", role: .destructive, action: onRemove) } @@ -240,18 +240,18 @@ private struct DownloadRow: View { case .completed: Image(systemName: "checkmark.circle.fill") - .foregroundStyle(Color.flixyTextMuted) + .foregroundStyle(Color.haloTextMuted) .accessibilityLabel(Text("downloads.available")) case .queued, .waiting: Image(systemName: "clock") - .foregroundStyle(Color.flixyTextMuted) + .foregroundStyle(Color.haloTextMuted) .accessibilityLabel(Text("downloads.queued")) } } private var progress: some View { - VStack(alignment: .leading, spacing: FlixySpacing.tight) { + VStack(alignment: .leading, spacing: HaloSpacing.tight) { // Ohne bekannte Gesamtgröße ein unbestimmter Balken: ein Balken bei // null Prozent, der sich nie bewegt, sieht aus wie ein hängender // Download. @@ -273,17 +273,17 @@ private struct DownloadRow: View { // gemeinsames Mass für beide Zahlen (siehe `unit`), und die // Prozente am rechten Rand — die wachsen nach innen und schieben // nichts. - HStack(alignment: .firstTextBaseline, spacing: FlixySpacing.snug) { + HStack(alignment: .firstTextBaseline, spacing: HaloSpacing.snug) { Text(statusLine) .lineLimit(1) - Spacer(minLength: FlixySpacing.snug) + Spacer(minLength: HaloSpacing.snug) if let percentage { Text(percentage) } } - .font(.flixyCaption) + .font(.haloCaption) .monospacedDigit() - .foregroundStyle(Color.flixyTextMuted) + .foregroundStyle(Color.haloTextMuted) } } @@ -387,28 +387,28 @@ private struct DownloadRow: View { private struct HoldNotice: View { let hold: TransferHold - @Environment(\.flixyAccent) private var accent + @Environment(\.haloAccent) private var accent var body: some View { - HStack(alignment: .top, spacing: FlixySpacing.regular) { + HStack(alignment: .top, spacing: HaloSpacing.regular) { Image(systemName: hold == .offline ? "wifi.slash" : "wifi.exclamationmark") .font(.title3) .foregroundStyle(accent) VStack(alignment: .leading, spacing: 2) { Text(hold == .offline ? "downloads.hold.offline" : "downloads.hold.wifi") - .font(.flixyCardTitle) - .foregroundStyle(Color.flixyTextPrimary) + .font(.haloCardTitle) + .foregroundStyle(Color.haloTextPrimary) Text(hold == .offline ? "downloads.hold.offline.description" : "downloads.hold.wifi.description") - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextSecondary) + .font(.haloCaption) + .foregroundStyle(Color.haloTextSecondary) } } - .padding(.vertical, FlixySpacing.tight) - .listRowBackground(Color.flixySurface) + .padding(.vertical, HaloSpacing.tight) + .listRowBackground(Color.haloSurface) .accessibilityElement(children: .combine) } } diff --git a/Flixy/Views/Home/HeroCarousel.swift b/Halo/Views/Home/HeroCarousel.swift similarity index 97% rename from Flixy/Views/Home/HeroCarousel.swift rename to Halo/Views/Home/HeroCarousel.swift index cae76d5..d414e37 100644 --- a/Flixy/Views/Home/HeroCarousel.swift +++ b/Halo/Views/Home/HeroCarousel.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign import MediaKit /// Der Aufmacher oben auf der Startseite — mehrere Titel, die sich abwechseln. @@ -65,8 +65,8 @@ struct HeroCarousel: View { @State private var isHoveringDots = false @Environment(\.accessibilityReduceMotion) private var reduceMotion - @Environment(\.flixyAccent) private var accent - @Environment(FlixySession.self) private var session + @Environment(\.haloAccent) private var accent + @Environment(HaloSession.self) private var session @Environment(\.horizontalSizeClass) private var sizeClass @Environment(TopChrome.self) private var chrome @Environment(HomeLayoutSettings.self) private var layout @@ -118,7 +118,7 @@ struct HeroCarousel: View { } var body: some View { - VStack(spacing: FlixySpacing.regular) { + VStack(spacing: HaloSpacing.regular) { heroSection // Die Höhe: fast das ganze Fenster. // @@ -189,7 +189,7 @@ struct HeroCarousel: View { } } - private var isMac: Bool { FlixyPlatform.isMac } + private var isMac: Bool { HaloPlatform.isMac } /// Die beiden Pfeile links und rechts. /// @@ -203,7 +203,7 @@ struct HeroCarousel: View { Spacer() arrow(symbol: "chevron.right", direction: 1) } - .padding(.horizontal, FlixySpacing.regular) + .padding(.horizontal, HaloSpacing.regular) .opacity(isPointerInside ? 1 : 0) .animation(.easeOut(duration: 0.2), value: isPointerInside) .onContinuousHover { phase in @@ -219,7 +219,7 @@ struct HeroCarousel: View { Image(systemName: symbol) .font(.system(size: 18, weight: .semibold)) .foregroundStyle(.white) - .padding(FlixySpacing.regular) + .padding(HaloSpacing.regular) .background(.black.opacity(0.45), in: .circle) } .buttonStyle(.plain) @@ -237,10 +237,10 @@ struct HeroCarousel: View { /// Auf dem iPhone und dem iPad bleibt es eine Anzeige. Dort gibt es /// keinen Zeiger, der sich nähern könnte, und getippt wird gewischt. private var indicator: some View { - HStack(spacing: isEnlarged ? FlixySpacing.regular : FlixySpacing.snug) { + HStack(spacing: isEnlarged ? HaloSpacing.regular : HaloSpacing.snug) { ForEach(items.indices, id: \.self) { position in Capsule() - .fill(position == currentIndex ? accent : Color.flixyTextMuted.opacity(0.4)) + .fill(position == currentIndex ? accent : Color.haloTextMuted.opacity(0.4)) .frame( width: position == currentIndex ? (isEnlarged ? 28 : 18) : (isEnlarged ? 12 : 6), height: isEnlarged ? 12 : 6 @@ -255,7 +255,7 @@ struct HeroCarousel: View { } // Eine grössere Fläche als die Punkte selbst: der Zeiger soll schon // beim Annähern etwas bewirken, nicht erst beim Treffen. - .padding(.vertical, FlixySpacing.snug) + .padding(.vertical, HaloSpacing.snug) .contentShape(.rect) .onContinuousHover { phase in guard isMac else { return } diff --git a/Flixy/Views/Home/HeroSection.swift b/Halo/Views/Home/HeroSection.swift similarity index 89% rename from Flixy/Views/Home/HeroSection.swift rename to Halo/Views/Home/HeroSection.swift index 8de27dd..4e68112 100644 --- a/Flixy/Views/Home/HeroSection.swift +++ b/Halo/Views/Home/HeroSection.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign import MediaKit /// Der Aufmacher oben auf der Startseite. @@ -12,10 +12,10 @@ struct HeroSection: View { /// Wie weit es dabei hereinrutscht. var incomingOffset: CGFloat = 0 - @Environment(FlixySession.self) private var session + @Environment(HaloSession.self) private var session @Environment(PlaybackCoordinator.self) private var playback @Environment(QuickPlay.self) private var quickPlay - @Environment(\.flixyAccent) private var accent + @Environment(\.haloAccent) private var accent @Environment(\.horizontalSizeClass) private var sizeClass var body: some View { @@ -56,21 +56,21 @@ struct HeroSection: View { quickPlay.start(item, backend: session.backend, coordinator: playback) } label: { Label(playLabel, systemImage: "play.fill") - .font(.flixyCardTitle) - .padding(.horizontal, FlixySpacing.loose) - .padding(.vertical, FlixySpacing.snug) + .font(.haloCardTitle) + .padding(.horizontal, HaloSpacing.loose) + .padding(.vertical, HaloSpacing.snug) } .buttonStyle(.borderedProminent) .tint(accent) NavigationLink(value: MediaRoute(ratingKey: item.id, title: item.title)) { Label("hero.details", systemImage: "info.circle") - .font(.flixyCardTitle) - .padding(.horizontal, FlixySpacing.loose) - .padding(.vertical, FlixySpacing.snug) + .font(.haloCardTitle) + .padding(.horizontal, HaloSpacing.loose) + .padding(.vertical, HaloSpacing.snug) } .buttonStyle(.bordered) - .tint(Color.flixyTextSecondary) + .tint(Color.haloTextSecondary) } } diff --git a/Flixy/Views/Home/HomeView.swift b/Halo/Views/Home/HomeView.swift similarity index 87% rename from Flixy/Views/Home/HomeView.swift rename to Halo/Views/Home/HomeView.swift index c9d48b1..4767a90 100644 --- a/Flixy/Views/Home/HomeView.swift +++ b/Halo/Views/Home/HomeView.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign import MediaKit /// Die Startseite: Aufmacher oben, darunter die Reihen vom Server. @@ -9,7 +9,7 @@ import MediaKit /// Reihen zeigt und die Logik sonst zweimal dastünde. Kopiert wäre dabei /// ausgerechnet der Teil gewesen, an dem schon mehrere Fehler steckten. struct HomeView: View { - @Environment(FlixySession.self) private var session + @Environment(HaloSession.self) private var session @Environment(HomeLayoutSettings.self) private var layout @State private var feed = HomeFeed() @@ -41,17 +41,17 @@ struct HomeView: View { } } } - .background(Color.flixyCanvas) + .background(Color.haloCanvas) // Kein Titel: der Name der App gehört auf den Homescreen, nicht // über jeden Bildschirm. Darunter liegt der Aufmacher, und der sagt // ohnehin mehr. .navigationTitle("") - .flixyInlineTitle() + .haloInlineTitle() // Gar kein Hintergrund statt eines weichgezeichneten: die Knöpfe // bringen ihre eigene Glasfläche mit und bleiben auch über dem Bild // lesbar. `.ultraThinMaterial` verschleierte dagegen den halben // Aufmacher. - .flixyClearToolbarBackground() + .haloClearToolbarBackground() // Gar keine Navigationsleiste auf der Startseite. // // Sie war leer — kein Titel, keine Knöpfe — und belegte trotzdem ihre @@ -63,12 +63,12 @@ struct HomeView: View { .refreshable { await feed.load(from: session.backend) } // Was eine Kachel am Server ändert, ändert auch, was hier steht: // eine abgehakte Folge gehört nicht mehr in „Weiterschauen". - .environment(\.flixyItemChanged, { await feed.load(from: session.backend) }) + .environment(\.haloItemChanged, { await feed.load(from: session.backend) }) } private func content(hubs: [MediaRowGroup]) -> some View { ScrollView { - LazyVStack(alignment: .leading, spacing: FlixySpacing.section) { + LazyVStack(alignment: .leading, spacing: HaloSpacing.section) { let featured = feed.heroItems(for: layout) if !featured.isEmpty { HeroCarousel(items: featured) @@ -78,9 +78,9 @@ struct HomeView: View { MediaRow(row: hub) } } - .padding(.bottom, FlixySpacing.section) + .padding(.bottom, HaloSpacing.section) } .scrollIndicators(.never) - .flixyRevealsTopChrome() + .haloRevealsTopChrome() } } diff --git a/Flixy/Views/Home/MediaRow.swift b/Halo/Views/Home/MediaRow.swift similarity index 85% rename from Flixy/Views/Home/MediaRow.swift rename to Halo/Views/Home/MediaRow.swift index 5030f23..4f2868f 100644 --- a/Flixy/Views/Home/MediaRow.swift +++ b/Halo/Views/Home/MediaRow.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign import MediaKit /// Eine waagerechte Reihe von Titeln. @@ -8,7 +8,7 @@ struct MediaRow: View { /// Wird durchgereicht — siehe `QuickPlayTile`. var opensDetails: Bool = false - @Environment(FlixySession.self) private var session + @Environment(HaloSession.self) private var session @Environment(HomeLayoutSettings.self) private var layout @@ -23,19 +23,19 @@ struct MediaRow: View { private var posterWidth: CGFloat { 116 * layout.cardScale } var body: some View { - VStack(alignment: .leading, spacing: FlixySpacing.regular) { + VStack(alignment: .leading, spacing: HaloSpacing.regular) { Text(row.title) - .font(.flixyRowHeader) - .foregroundStyle(Color.flixyTextPrimary) - .padding(.horizontal, FlixySpacing.screenMargin) + .font(.haloRowHeader) + .foregroundStyle(Color.haloTextPrimary) + .padding(.horizontal, HaloSpacing.screenMargin) ScrollView(.horizontal) { - LazyHStack(spacing: FlixySpacing.regular) { + LazyHStack(spacing: HaloSpacing.regular) { ForEach(row.items) { item in QuickPlayTile(item: item, opensDetails: opensDetails) { card(for: item) } } } - .padding(.horizontal, FlixySpacing.screenMargin) + .padding(.horizontal, HaloSpacing.screenMargin) // Ohne dieses Ziel rasten die Kacheln nicht ein und die Reihe // bleibt an beliebiger Stelle stehen. .scrollTargetLayout() diff --git a/Flixy/Views/Library/LibraryBrowser.swift b/Halo/Views/Library/LibraryBrowser.swift similarity index 89% rename from Flixy/Views/Library/LibraryBrowser.swift rename to Halo/Views/Library/LibraryBrowser.swift index 79e5757..9637093 100644 --- a/Flixy/Views/Library/LibraryBrowser.swift +++ b/Halo/Views/Library/LibraryBrowser.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign import MediaKit /// Die Mediatheken auf dem iPhone — mit einer Leiste zum Wechseln. @@ -20,7 +20,7 @@ import MediaKit /// dessen Einträge zwei Navigationsleisten übereinander tragen. Eine selbst /// gezeichnete Leiste kennt diese Grenze nicht. struct LibraryBrowser: View { - @Environment(FlixySession.self) private var session + @Environment(HaloSession.self) private var session /// Was gerade gezeigt wird. /// @@ -36,7 +36,7 @@ struct LibraryBrowser: View { var body: some View { inhalt - .background(Color.flixyCanvas) + .background(Color.haloCanvas) // **Als Sicherheitsrand, nicht als Überzug.** So endet die Liste // über der Leiste, statt dahinter zu verschwinden — und das gilt // auch für die Ladeanzeige und den Fuss „alles geladen". @@ -86,11 +86,11 @@ struct LibraryBrowser: View { } // Dieselbe Fläche wie die Insel auf dem iPad — ein `static`-Bauteil, // kein nachgebautes Aussehen. - .background { FlixySidebar.surface(in: .capsule) } + .background { HaloSidebar.surface(in: .capsule) } .clipShape(.capsule) .shadow(color: .black.opacity(0.45), radius: 18, y: 6) - .padding(.horizontal, FlixySpacing.regular) - .padding(.bottom, FlixySpacing.snug) + .padding(.horizontal, HaloSpacing.regular) + .padding(.bottom, HaloSpacing.snug) } private var reihe: some View { @@ -99,8 +99,8 @@ struct LibraryBrowser: View { pille(eintrag) } } - .padding(.horizontal, FlixySpacing.snug) - .padding(.vertical, FlixySpacing.snug) + .padding(.horizontal, HaloSpacing.snug) + .padding(.vertical, HaloSpacing.snug) } private func pille(_ eintrag: Eintrag) -> some View { @@ -116,12 +116,12 @@ struct LibraryBrowser: View { } // Kleiner als in der Leiste auf dem iPad: dort stehen drei // Einträge, hier bis zu fünf — und auf einem Telefon. - .font(.flixyCaption) - .foregroundStyle(gewaehlt ? Color.flixyTextPrimary : Color.flixyTextSecondary) - .padding(.horizontal, FlixySpacing.snug) - .padding(.vertical, FlixySpacing.snug) + .font(.haloCaption) + .foregroundStyle(gewaehlt ? Color.haloTextPrimary : Color.haloTextSecondary) + .padding(.horizontal, HaloSpacing.snug) + .padding(.vertical, HaloSpacing.snug) .background { - if gewaehlt { Capsule().fill(Color.flixyElevated) } + if gewaehlt { Capsule().fill(Color.haloElevated) } } .contentShape(Capsule()) } diff --git a/Flixy/Views/Library/LibraryFilterSheet.swift b/Halo/Views/Library/LibraryFilterSheet.swift similarity index 95% rename from Flixy/Views/Library/LibraryFilterSheet.swift rename to Halo/Views/Library/LibraryFilterSheet.swift index d9d77b2..48ee206 100644 --- a/Flixy/Views/Library/LibraryFilterSheet.swift +++ b/Halo/Views/Library/LibraryFilterSheet.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign import MediaKit /// Filter und Sortierung einer Mediathek. @@ -14,8 +14,8 @@ struct LibraryFilterSheet: View { let library: MediaLibrary @Environment(\.dismiss) private var dismiss - @Environment(\.flixyAccent) private var accent - @Environment(FlixySession.self) private var session + @Environment(\.haloAccent) private var accent + @Environment(HaloSession.self) private var session @State private var genres: [MediaFilterOption] = [] /// Ein Arbeitsstand, der erst beim Bestätigen übernommen wird. @@ -91,11 +91,11 @@ struct LibraryFilterSheet: View { // gehen können — sichtbar an Picker-Werten, die in der Standardfarbe // leuchteten, während die Schalter daneben schon die gewählte trugen. .tint(accent) - .flixyForm() + .haloForm() .scrollContentBackground(.hidden) - .background(Color.flixyCanvas) + .background(Color.haloCanvas) .navigationTitle(Text("filter.title")) - .flixyInlineTitle() + .haloInlineTitle() .toolbar { ToolbarItem(placement: .cancellationAction) { Button("action.cancel") { dismiss() } @@ -109,7 +109,7 @@ struct LibraryFilterSheet: View { } .task { await loadGenres() } } - .flixyResizableSheet() + .haloResizableSheet() } private func loadGenres() async { diff --git a/Flixy/Views/Library/LibraryView.swift b/Halo/Views/Library/LibraryView.swift similarity index 88% rename from Flixy/Views/Library/LibraryView.swift rename to Halo/Views/Library/LibraryView.swift index b635c1c..ab11e08 100644 --- a/Flixy/Views/Library/LibraryView.swift +++ b/Halo/Views/Library/LibraryView.swift @@ -1,16 +1,16 @@ import SwiftUI -import FlixyDesign +import HaloDesign import MediaKit /// Eine Mediathek zum Durchblättern. struct LibraryView: View { let library: MediaLibrary - @Environment(FlixySession.self) private var session + @Environment(HaloSession.self) private var session /// Nur für die Kachelgröße. „layout“ heißt hier schon die Wahl /// zwischen Raster und Liste. @Environment(HomeLayoutSettings.self) private var sizing - @AppStorage("flixy.library.layout") private var layout: LibraryLayout = .grid + @AppStorage("halo.library.layout") private var layout: LibraryLayout = .grid @Environment(\.horizontalSizeClass) private var sizeClass @State private var items: [MediaItem] = [] @@ -59,9 +59,9 @@ struct LibraryView: View { } } } - .background(Color.flixyCanvas) + .background(Color.haloCanvas) .navigationTitle(library.title) - .flixyInlineTitle() + .haloInlineTitle() .toolbar { toolbar } .sheet(isPresented: $showsFilters) { LibraryFilterSheet(query: $query, library: library) @@ -80,7 +80,7 @@ struct LibraryView: View { .onChange(of: query) { _, _ in Task { await reload() } } .refreshable { await reload() } // Siehe `HomeView`: was eine Kachel ändert, muss im Raster ankommen. - .environment(\.flixyItemChanged, { await reload() }) + .environment(\.haloItemChanged, { await reload() }) } @ViewBuilder @@ -97,8 +97,8 @@ struct LibraryView: View { // Mindestbreite statt fester Spaltenzahl: dieselbe Ansicht // ergibt auf dem iPhone drei und auf dem iPad sechs Spalten, // ohne dass die Größenklasse abgefragt werden muss. - columns: [GridItem(.adaptive(minimum: 110 * sizing.cardScale), spacing: FlixySpacing.regular)], - spacing: FlixySpacing.loose + columns: [GridItem(.adaptive(minimum: 110 * sizing.cardScale), spacing: HaloSpacing.regular)], + spacing: HaloSpacing.loose ) { ForEach(items) { item in QuickPlayTile(item: item) { @@ -119,12 +119,12 @@ struct LibraryView: View { PlaceholderCard(index: position) } } - .padding(FlixySpacing.screenMargin) + .padding(HaloSpacing.screenMargin) - moreButton.padding(.bottom, FlixySpacing.section) - footerCount.padding(.bottom, FlixySpacing.section) + moreButton.padding(.bottom, HaloSpacing.section) + footerCount.padding(.bottom, HaloSpacing.section) } - .flixyRevealsTopChrome() + .haloRevealsTopChrome() } private var list: some View { @@ -137,19 +137,19 @@ struct LibraryView: View { .buttonStyle(.plain) .task { await loadMoreIfNeeded(reaching: item) } - Divider().overlay(Color.flixySeparator) + Divider().overlay(Color.haloSeparator) } } if pendingCount > 0 { ProgressView() - .padding(.vertical, FlixySpacing.section) + .padding(.vertical, HaloSpacing.section) .frame(maxWidth: .infinity) } - moreButton.padding(.vertical, FlixySpacing.section) - footerCount.padding(.bottom, FlixySpacing.section) + moreButton.padding(.vertical, HaloSpacing.section) + footerCount.padding(.bottom, HaloSpacing.section) } - .flixyRevealsTopChrome() + .haloRevealsTopChrome() } /// Wie viele Kacheln noch kommen — und zwar **gemeldet**, nicht geraten. @@ -173,8 +173,8 @@ struct LibraryView: View { private var footerCount: some View { if let page, !page.hasMore, !items.isEmpty { Text("library.allLoaded \(items.count)") - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextMuted) + .font(.haloCaption) + .foregroundStyle(Color.haloTextMuted) .frame(maxWidth: .infinity) } } @@ -183,10 +183,10 @@ struct LibraryView: View { @ViewBuilder private var moreButton: some View { if loadMoreFailed, let page, page.hasMore { - VStack(spacing: FlixySpacing.snug) { + VStack(spacing: HaloSpacing.snug) { Text("library.loadMoreFailed") - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextMuted) + .font(.haloCaption) + .foregroundStyle(Color.haloTextMuted) Button("library.loadMore") { Task { await loadMore() } } @@ -206,7 +206,7 @@ struct LibraryView: View { // steht der Knopf. Auf dem iPad steht die Suche in der Seitenleiste, // und ein zweiter Weg dorthin wäre nur Verdopplung. if sizeClass == .compact { - ToolbarItem(placement: .flixyTrailing) { + ToolbarItem(placement: .haloTrailing) { NavigationLink(value: SearchRoute()) { Image(systemName: "magnifyingglass") } @@ -218,7 +218,7 @@ struct LibraryView: View { // oben, und selbst dort wo es das gibt, ist es in einem Raster kaum // zu treffen. Wer den Verdacht hat, dass etwas fehlt, braucht einen // Knopf und keine Geste. - ToolbarItem(placement: .flixyTrailing) { + ToolbarItem(placement: .haloTrailing) { Button { Task { await reload() } } label: { @@ -228,7 +228,7 @@ struct LibraryView: View { .disabled(isLoadingMore) } - ToolbarItem(placement: .flixyTrailing) { + ToolbarItem(placement: .haloTrailing) { Button { showsFilters = true } label: { @@ -239,7 +239,7 @@ struct LibraryView: View { .accessibilityLabel(Text("library.filters")) } - ToolbarItem(placement: .flixyTrailing) { + ToolbarItem(placement: .haloTrailing) { Button { layout = layout == .grid ? .list : .grid } label: { @@ -255,7 +255,7 @@ struct LibraryView: View { // Reihe etwas steht, kann nur der entscheiden, der die Reihe // schreibt. if sizeClass == .compact { - ToolbarItem(placement: .flixyTrailing) { AccountToolbarButton() } + ToolbarItem(placement: .haloTrailing) { AccountToolbarButton() } } } @@ -380,11 +380,11 @@ enum LibraryLayout: String, CaseIterable { /// Eine Zeile in der Listenansicht. private struct LibraryListRow: View { let item: MediaItem - @Environment(FlixySession.self) private var session + @Environment(HaloSession.self) private var session var body: some View { - HStack(spacing: FlixySpacing.regular) { - FlixyArtwork( + HStack(spacing: HaloSpacing.regular) { + HaloArtwork( url: session.backend?.artworkURL(path: item.thumb, width: 120, height: 180), aspectRatio: PosterCard.aspectRatio ) @@ -393,13 +393,13 @@ private struct LibraryListRow: View { VStack(alignment: .leading, spacing: 2) { Text(item.title) - .font(.flixyCardTitle) - .foregroundStyle(Color.flixyTextPrimary) + .font(.haloCardTitle) + .foregroundStyle(Color.haloTextPrimary) .lineLimit(1) if let subtitle = item.cardSubtitle { Text(subtitle) - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextMuted) + .font(.haloCaption) + .foregroundStyle(Color.haloTextMuted) } } @@ -407,12 +407,12 @@ private struct LibraryListRow: View { if item.isWatched { Image(systemName: "checkmark.circle.fill") - .foregroundStyle(Color.flixyTextMuted) + .foregroundStyle(Color.haloTextMuted) .accessibilityLabel(Text("item.watched")) } } - .padding(.horizontal, FlixySpacing.screenMargin) - .padding(.vertical, FlixySpacing.snug) + .padding(.horizontal, HaloSpacing.screenMargin) + .padding(.vertical, HaloSpacing.snug) .contentShape(.rect) .accessibilityElement(children: .combine) } diff --git a/Flixy/Views/LiveTV/ChannelSelectionSheet.swift b/Halo/Views/LiveTV/ChannelSelectionSheet.swift similarity index 88% rename from Flixy/Views/LiveTV/ChannelSelectionSheet.swift rename to Halo/Views/LiveTV/ChannelSelectionSheet.swift index 5e76cb2..9aac8a9 100644 --- a/Flixy/Views/LiveTV/ChannelSelectionSheet.swift +++ b/Halo/Views/LiveTV/ChannelSelectionSheet.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign import MediaKit /// Welche Sender überhaupt angezeigt werden. @@ -12,8 +12,8 @@ struct ChannelSelectionSheet: View { let channels: [LiveChannel] @Binding var selection: Set - @Environment(FlixySession.self) private var session - @Environment(\.flixyAccent) private var accent + @Environment(HaloSession.self) private var session + @Environment(\.haloAccent) private var accent @Environment(\.dismiss) private var dismiss var body: some View { @@ -28,9 +28,9 @@ struct ChannelSelectionSheet: View { } } .navigationTitle(Text("liveTV.selection")) - .flixyInlineTitle() + .haloInlineTitle() .toolbar { - ToolbarItem(placement: .flixyLeading) { + ToolbarItem(placement: .haloLeading) { // „Alle" statt „keine": eine leere Auswahl bedeutet // ohnehin alle, und ein Knopf, der scheinbar nichts tut, // wäre verwirrend. @@ -57,10 +57,10 @@ struct ChannelSelectionSheet: View { selection.insert(channel.id) } } label: { - HStack(spacing: FlixySpacing.regular) { - FlixyArtwork( + HStack(spacing: HaloSpacing.regular) { + HaloArtwork( url: session.backend?.artworkURL(path: channel.artworkPath, width: 200, height: 120), - aspectRatio: FlixyAspectRatio.channelLogo, + aspectRatio: HaloAspectRatio.channelLogo, fallbackSymbol: "tv", contentMode: .fit ) @@ -69,17 +69,17 @@ struct ChannelSelectionSheet: View { if let number = channel.number { Text(number) .font(.system(.caption, design: .monospaced)) - .foregroundStyle(Color.flixyTextMuted) + .foregroundStyle(Color.haloTextMuted) } Text(channel.title) - .font(.flixyBody) - .foregroundStyle(Color.flixyTextPrimary) + .font(.haloBody) + .foregroundStyle(Color.haloTextPrimary) Spacer() Image(systemName: isShown(channel) ? "checkmark.circle.fill" : "circle") - .foregroundStyle(isShown(channel) ? accent : Color.flixyTextMuted) + .foregroundStyle(isShown(channel) ? accent : Color.haloTextMuted) } .contentShape(.rect) } diff --git a/Flixy/Views/LiveTV/LiveTVView.swift b/Halo/Views/LiveTV/LiveTVView.swift similarity index 87% rename from Flixy/Views/LiveTV/LiveTVView.swift rename to Halo/Views/LiveTV/LiveTVView.swift index a4dbc1a..b76554c 100644 --- a/Flixy/Views/LiveTV/LiveTVView.swift +++ b/Halo/Views/LiveTV/LiveTVView.swift @@ -1,11 +1,11 @@ import SwiftUI -import FlixyDesign -import FlixyPlayback +import HaloDesign +import HaloPlayback import MediaKit /// Live-TV mit Programmführer. struct LiveTVView: View { - @Environment(FlixySession.self) private var session + @Environment(HaloSession.self) private var session @Environment(PlaybackCoordinator.self) private var playback @Environment(PlaybackSettings.self) private var settings @Environment(NetworkConditions.self) private var network @@ -74,7 +74,7 @@ struct LiveTVView: View { } description: { Text("liveTV.noChannels.description") } actions: { - VStack(spacing: FlixySpacing.regular) { + VStack(spacing: HaloSpacing.regular) { Button("action.retry") { Task { await load() } } searchTrace } @@ -107,12 +107,12 @@ struct LiveTVView: View { } } } - .background(Color.flixyCanvas) + .background(Color.haloCanvas) .navigationTitle(Text("sidebar.liveTV")) - .flixyInlineTitle() + .haloInlineTitle() .toolbar { if case .available = availability, !channels.isEmpty { - ToolbarItem(placement: .flixyTrailing) { + ToolbarItem(placement: .haloTrailing) { Button { showsSelection = true } label: { @@ -120,7 +120,7 @@ struct LiveTVView: View { } .accessibilityLabel(Text("liveTV.selection")) } - ToolbarItem(placement: .flixyTrailing) { + ToolbarItem(placement: .haloTrailing) { Picker("liveTV.mode", selection: $mode) { Image(systemName: "calendar.day.timeline.left").tag(LiveTVMode.guide) Image(systemName: "list.bullet").tag(LiveTVMode.channels) @@ -169,11 +169,11 @@ struct LiveTVView: View { @ViewBuilder private var searchTrace: some View { if !trace.isEmpty { - VStack(alignment: .leading, spacing: FlixySpacing.snug) { + VStack(alignment: .leading, spacing: HaloSpacing.snug) { if let channelSource { Text(channelSource) - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextSecondary) + .font(.haloCaption) + .foregroundStyle(Color.haloTextSecondary) } ScrollView { @@ -181,7 +181,7 @@ struct LiveTVView: View { ForEach(trace) { probe in Text("\(probe.path) → \(probe.result)") .font(.system(size: 10, design: .monospaced)) - .foregroundStyle(Color.flixyTextMuted) + .foregroundStyle(Color.haloTextMuted) .lineLimit(2) .textSelection(.enabled) } @@ -191,18 +191,18 @@ struct LiveTVView: View { .frame(maxHeight: 200) Button { - FlixyClipboard.copy( + HaloClipboard.copy( trace .map { "\($0.path) → \($0.result)" } .joined(separator: "\n") ) } label: { Label("diagnostics.copy", systemImage: "doc.on.doc") - .font(.flixyCaption) + .font(.haloCaption) } .buttonStyle(.bordered) } - .padding(.horizontal, FlixySpacing.screenMargin) + .padding(.horizontal, HaloSpacing.screenMargin) } } @@ -216,11 +216,11 @@ struct LiveTVView: View { isTuning: isTuning == channel.id, onTune: { Task { await tune(channel) } } ) - Divider().overlay(Color.flixySeparator) + Divider().overlay(Color.haloSeparator) } } } - .flixyRevealsTopChrome() + .haloRevealsTopChrome() } private func load() async { @@ -329,43 +329,43 @@ private struct ChannelRow: View { let isTuning: Bool let onTune: () -> Void - @Environment(FlixySession.self) private var session - @Environment(\.flixyAccent) private var accent + @Environment(HaloSession.self) private var session + @Environment(\.haloAccent) private var accent private var current: LiveProgram? { programs.first { $0.isRunning() } } private var next: LiveProgram? { programs.first { $0.startsAt > Date() } } var body: some View { Button(action: onTune) { - HStack(spacing: FlixySpacing.regular) { + HStack(spacing: HaloSpacing.regular) { // Breiter als hoch und ohne Beschneiden: Sendersymbole sind // fast nie quadratisch, und formatfüllend fehlten links und // rechts genau die Teile, an denen man den Sender erkennt. - FlixyArtwork( + HaloArtwork( url: session.backend?.artworkURL(path: channel.artworkPath, width: 200, height: 120), - aspectRatio: FlixyAspectRatio.channelLogo, + aspectRatio: HaloAspectRatio.channelLogo, fallbackSymbol: "tv", contentMode: .fit ) .frame(width: 56, height: 34) VStack(alignment: .leading, spacing: 2) { - HStack(spacing: FlixySpacing.snug) { + HStack(spacing: HaloSpacing.snug) { if let number = channel.number { Text(number) .font(.system(.caption, design: .monospaced)) - .foregroundStyle(Color.flixyTextMuted) + .foregroundStyle(Color.haloTextMuted) } Text(channel.title) - .font(.flixyCardTitle) - .foregroundStyle(Color.flixyTextPrimary) + .font(.haloCardTitle) + .foregroundStyle(Color.haloTextPrimary) .lineLimit(1) } if let current { Text(current.title) - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextSecondary) + .font(.haloCaption) + .foregroundStyle(Color.haloTextSecondary) .lineLimit(1) // Der Balken zeigt, wie weit die Sendung ist — beim // Umschalten die nützlichste Angabe überhaupt. @@ -373,14 +373,14 @@ private struct ChannelRow: View { .padding(.top, 2) } else { Text("liveTV.noProgram") - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextMuted) + .font(.haloCaption) + .foregroundStyle(Color.haloTextMuted) } if let next { Text("liveTV.next \(next.startsAt.formatted(date: .omitted, time: .shortened)) \(next.title)") - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextMuted) + .font(.haloCaption) + .foregroundStyle(Color.haloTextMuted) .lineLimit(1) } } @@ -395,8 +395,8 @@ private struct ChannelRow: View { .foregroundStyle(accent) } } - .padding(.horizontal, FlixySpacing.screenMargin) - .padding(.vertical, FlixySpacing.regular) + .padding(.horizontal, HaloSpacing.screenMargin) + .padding(.vertical, HaloSpacing.regular) .contentShape(.rect) } .buttonStyle(.plain) @@ -427,43 +427,43 @@ private struct TuneFailureSheet: View { var body: some View { NavigationStack { ScrollView { - VStack(alignment: .leading, spacing: FlixySpacing.regular) { + VStack(alignment: .leading, spacing: HaloSpacing.regular) { Text(failure.channel) - .font(.flixyRowHeader) - .foregroundStyle(Color.flixyTextPrimary) + .font(.haloRowHeader) + .foregroundStyle(Color.haloTextPrimary) Text(failure.reason) - .font(.flixyBody) - .foregroundStyle(Color.flixyTextSecondary) + .font(.haloBody) + .foregroundStyle(Color.haloTextSecondary) ForEach(Array(failure.trace.enumerated()), id: \.offset) { _, line in Text(line) .font(.system(size: 11, design: .monospaced)) - .foregroundStyle(Color.flixyTextMuted) + .foregroundStyle(Color.haloTextMuted) .textSelection(.enabled) .frame(maxWidth: .infinity, alignment: .leading) } Button { - FlixyClipboard.copy(failure.trace.joined(separator: "\n")) + HaloClipboard.copy(failure.trace.joined(separator: "\n")) } label: { Label("diagnostics.copy", systemImage: "doc.on.doc") - .font(.flixyCaption) + .font(.haloCaption) } .buttonStyle(.bordered) } - .padding(FlixySpacing.screenMargin) + .padding(HaloSpacing.screenMargin) .frame(maxWidth: .infinity, alignment: .leading) } - .background(Color.flixyCanvas) + .background(Color.haloCanvas) .navigationTitle(Text("liveTV.tuneFailed")) - .flixyInlineTitle() + .haloInlineTitle() .toolbar { ToolbarItem(placement: .confirmationAction) { Button("action.close") { dismiss() } } } } - .flixyResizableSheet() + .haloResizableSheet() } } diff --git a/Flixy/Views/LiveTV/ProgramGuide.swift b/Halo/Views/LiveTV/ProgramGuide.swift similarity index 82% rename from Flixy/Views/LiveTV/ProgramGuide.swift rename to Halo/Views/LiveTV/ProgramGuide.swift index c559bb2..8a9436f 100644 --- a/Flixy/Views/LiveTV/ProgramGuide.swift +++ b/Halo/Views/LiveTV/ProgramGuide.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign import MediaKit /// Das Programmraster: Sender als Zeilen, Zeit als Achse. @@ -34,7 +34,7 @@ struct ProgramGuide: View { var onRecord: ((LiveProgram) -> Void)? var onRecordSeries: ((LiveProgram) -> Void)? - @Environment(\.flixyAccent) private var accent + @Environment(\.haloAccent) private var accent @State private var scrollX: CGFloat = 0 @State private var selection: GuideSelection? @@ -50,7 +50,7 @@ struct ProgramGuide: View { var body: some View { VStack(spacing: 0) { axis - Divider().overlay(Color.flixySeparator) + Divider().overlay(Color.haloSeparator) ScrollView(.vertical) { HStack(alignment: .top, spacing: 0) { @@ -65,7 +65,7 @@ struct ProgramGuide: View { } .scrollIndicators(.never) } - .background(Color.flixyCanvas) + .background(Color.haloCanvas) .sheet(item: $selection) { selection in ProgramDetailSheet( channel: selection.channel, @@ -104,12 +104,12 @@ struct ProgramGuide: View { private var axis: some View { HStack(spacing: 0) { Text("liveTV.channelCount \(channels.count)") - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextMuted) + .font(.haloCaption) + .foregroundStyle(Color.haloTextMuted) // Der Abstand gehört in die Spaltenbreite hinein, nicht // dazu: außen addiert er sich, und die ganze Zeitachse steht // acht Punkte neben dem Programm darunter. - .padding(.leading, FlixySpacing.snug) + .padding(.leading, HaloSpacing.snug) .frame(width: channelWidth, alignment: .leading) .layoutPriority(1) @@ -125,7 +125,7 @@ struct ProgramGuide: View { ForEach(layout.ticks, id: \.self) { tick in Text(tick.formatted(date: .omitted, time: .shortened)) .font(.system(.caption2, design: .rounded)) - .foregroundStyle(Color.flixyTextMuted) + .foregroundStyle(Color.haloTextMuted) .frame(width: layout.tickWidth, alignment: .leading) } } @@ -135,7 +135,7 @@ struct ProgramGuide: View { .clipped() } .frame(height: axisHeight) - .background(Color.flixyCanvas) + .background(Color.haloCanvas) } /// Was auf diesem Sender gerade läuft. @@ -147,20 +147,20 @@ struct ProgramGuide: View { VStack(spacing: 0) { ForEach(channels) { channel in Button { onTune(channel, running(on: channel)) } label: { - HStack(spacing: FlixySpacing.snug) { - FlixyArtwork(url: artwork(channel), aspectRatio: 1, fallbackSymbol: "tv") + HStack(spacing: HaloSpacing.snug) { + HaloArtwork(url: artwork(channel), aspectRatio: 1, fallbackSymbol: "tv") .frame(width: 30, height: 30) .clipShape(.rect(cornerRadius: 4)) VStack(alignment: .leading, spacing: 1) { Text(channel.title) - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextPrimary) + .font(.haloCaption) + .foregroundStyle(Color.haloTextPrimary) .lineLimit(2) if let number = channel.number { Text(number) .font(.system(.caption2, design: .monospaced)) - .foregroundStyle(Color.flixyTextMuted) + .foregroundStyle(Color.haloTextMuted) } } @@ -170,7 +170,7 @@ struct ProgramGuide: View { ProgressView().controlSize(.mini) } } - .padding(.horizontal, FlixySpacing.snug) + .padding(.horizontal, HaloSpacing.snug) .frame(width: channelWidth, height: rowHeight, alignment: .leading) .overlay(alignment: .bottom) { rowSeparator } .contentShape(.rect) @@ -179,7 +179,7 @@ struct ProgramGuide: View { } } .frame(width: channelWidth) - .background(Color.flixyElevated.opacity(0.4)) + .background(Color.haloElevated.opacity(0.4)) } private var lanes: some View { @@ -217,9 +217,9 @@ struct ProgramGuide: View { return ZStack(alignment: .topLeading) { if entries.isEmpty { Text("liveTV.noProgram") - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextMuted) - .padding(.horizontal, FlixySpacing.regular) + .font(.haloCaption) + .foregroundStyle(Color.haloTextMuted) + .padding(.horizontal, HaloSpacing.regular) .frame(height: rowHeight, alignment: .leading) } @@ -240,7 +240,7 @@ struct ProgramGuide: View { /// Zeile, die man antippt, gehört dann zum Nachbarsender. private var rowSeparator: some View { Rectangle() - .fill(Color.flixySeparator) + .fill(Color.haloSeparator) .frame(height: 1) } @@ -250,21 +250,21 @@ struct ProgramGuide: View { return Button { selection = GuideSelection(channel: channel, program: program) } label: { VStack(alignment: .leading, spacing: 2) { Text(program.title) - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextPrimary) + .font(.haloCaption) + .foregroundStyle(Color.haloTextPrimary) .lineLimit(2) .multilineTextAlignment(.leading) Text(program.startsAt.formatted(date: .omitted, time: .shortened)) .font(.system(.caption2, design: .rounded)) - .foregroundStyle(Color.flixyTextMuted) + .foregroundStyle(Color.haloTextMuted) } - .padding(.horizontal, FlixySpacing.snug) + .padding(.horizontal, HaloSpacing.snug) .padding(.vertical, 6) .frame(width: layout.width(from: program.startsAt, to: program.endsAt) - 2, height: rowHeight - 2, alignment: .topLeading) .background( - running ? accent.opacity(0.28) : Color.flixyElevated, - in: .rect(cornerRadius: FlixyRadius.control) + running ? accent.opacity(0.28) : Color.haloElevated, + in: .rect(cornerRadius: HaloRadius.control) ) .overlay(alignment: .bottomLeading) { // Der Balken zeigt, wie weit die laufende Sendung ist — beim @@ -299,45 +299,45 @@ private struct ProgramDetailSheet: View { let onRecord: (() -> Void)? let onRecordSeries: (() -> Void)? - @Environment(\.flixyAccent) private var accent + @Environment(\.haloAccent) private var accent @Environment(\.dismiss) private var dismiss var body: some View { NavigationStack { ScrollView { - VStack(alignment: .leading, spacing: FlixySpacing.regular) { - HStack(spacing: FlixySpacing.regular) { - FlixyArtwork(url: artworkURL, aspectRatio: 1, fallbackSymbol: "tv") + VStack(alignment: .leading, spacing: HaloSpacing.regular) { + HStack(spacing: HaloSpacing.regular) { + HaloArtwork(url: artworkURL, aspectRatio: 1, fallbackSymbol: "tv") .frame(width: 44, height: 44) .clipShape(.rect(cornerRadius: 6)) VStack(alignment: .leading, spacing: 2) { Text(channel.title) - .font(.flixyCardTitle) - .foregroundStyle(Color.flixyTextPrimary) + .font(.haloCardTitle) + .foregroundStyle(Color.haloTextPrimary) Text("liveTV.timeRange \(program.startsAt.formatted(date: .omitted, time: .shortened)) \(program.endsAt.formatted(date: .omitted, time: .shortened))") - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextSecondary) + .font(.haloCaption) + .foregroundStyle(Color.haloTextSecondary) } Spacer() } Text(program.title) - .font(.flixyRowHeader) - .foregroundStyle(Color.flixyTextPrimary) + .font(.haloRowHeader) + .foregroundStyle(Color.haloTextPrimary) if let subtitle = program.subtitle { Text(subtitle) - .font(.flixyBody) - .foregroundStyle(Color.flixyTextSecondary) + .font(.haloBody) + .foregroundStyle(Color.haloTextSecondary) } if isRunning { Button { onTune(); dismiss() } label: { Label("liveTV.tune", systemImage: "play.fill") .frame(maxWidth: .infinity) - .padding(.vertical, FlixySpacing.snug) + .padding(.vertical, HaloSpacing.snug) } .buttonStyle(.borderedProminent) .tint(accent) @@ -348,15 +348,15 @@ private struct ProgramDetailSheet: View { // ohne Aufnahmen fehlt hier schlicht alles. if program.seriesTimerID != nil { Label("liveTV.alreadyScheduled", systemImage: "checkmark.circle") - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextSecondary) + .font(.haloCaption) + .foregroundStyle(Color.haloTextSecondary) } else if onRecord != nil || onRecordSeries != nil { - HStack(spacing: FlixySpacing.regular) { + HStack(spacing: HaloSpacing.regular) { if let onRecord { Button { onRecord(); dismiss() } label: { Label("liveTV.record", systemImage: "record.circle") .frame(maxWidth: .infinity) - .padding(.vertical, FlixySpacing.snug) + .padding(.vertical, HaloSpacing.snug) } .buttonStyle(.bordered) } @@ -364,7 +364,7 @@ private struct ProgramDetailSheet: View { Button { onRecordSeries(); dismiss() } label: { Label("liveTV.recordSeries", systemImage: "rectangle.stack.badge.record") .frame(maxWidth: .infinity) - .padding(.vertical, FlixySpacing.snug) + .padding(.vertical, HaloSpacing.snug) } .buttonStyle(.bordered) } @@ -373,20 +373,20 @@ private struct ProgramDetailSheet: View { if let summary = program.summary, !summary.isEmpty { Text(summary) - .font(.flixyBody) - .foregroundStyle(Color.flixyTextSecondary) + .font(.haloBody) + .foregroundStyle(Color.haloTextSecondary) } } - .padding(FlixySpacing.screenMargin) + .padding(HaloSpacing.screenMargin) .frame(maxWidth: .infinity, alignment: .leading) } - .background(Color.flixyCanvas) + .background(Color.haloCanvas) .toolbar { ToolbarItem(placement: .confirmationAction) { Button("action.close") { dismiss() } } } } - .flixyResizableSheet() + .haloResizableSheet() } } diff --git a/Flixy/Views/LiveTV/RecordingsView.swift b/Halo/Views/LiveTV/RecordingsView.swift similarity index 87% rename from Flixy/Views/LiveTV/RecordingsView.swift rename to Halo/Views/LiveTV/RecordingsView.swift index a8916ad..6cacb46 100644 --- a/Flixy/Views/LiveTV/RecordingsView.swift +++ b/Halo/Views/LiveTV/RecordingsView.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign import MediaKit /// Aufnahmen und was noch vorgemerkt ist. @@ -12,7 +12,7 @@ import MediaKit /// kommt noch" sind dieselbe Frage in zwei Zeitformen, und wer die eine /// stellt, stellt meist gleich die andere mit. struct RecordingsView: View { - @Environment(FlixySession.self) private var session + @Environment(HaloSession.self) private var session @State private var recordings: [LiveRecording] = [] @State private var timers: [LiveTimer] = [] @@ -47,7 +47,7 @@ struct RecordingsView: View { list } } - .background(Color.flixyCanvas) + .background(Color.haloCanvas) .task { await load() } .refreshable { await load() } .confirmationDialog( @@ -90,7 +90,7 @@ struct RecordingsView: View { } } } - .listRowBackground(Color.flixySurface) + .listRowBackground(Color.haloSurface) } header: { Text("liveTV.recordings") } @@ -118,23 +118,23 @@ struct RecordingsView: View { } } } - .listRowBackground(Color.flixySurface) + .listRowBackground(Color.haloSurface) } header: { Text("liveTV.scheduled") } - .listRowBackground(Color.flixySurface) + .listRowBackground(Color.haloSurface) } } .listStyle(.insetGrouped) .scrollContentBackground(.hidden) - .flixyRevealsTopChrome() + .haloRevealsTopChrome() } // MARK: - Zeilen private func row(_ recording: LiveRecording) -> some View { - HStack(spacing: FlixySpacing.regular) { - FlixyArtwork( + HStack(spacing: HaloSpacing.regular) { + HaloArtwork( url: session.backend?.artworkURL(path: recording.artworkPath, width: 200, height: 120), aspectRatio: 16 / 9, fallbackSymbol: "recordingtape", @@ -145,23 +145,23 @@ struct RecordingsView: View { VStack(alignment: .leading, spacing: 2) { Text(recording.title) - .font(.flixyBody) - .foregroundStyle(Color.flixyTextPrimary) + .font(.haloBody) + .foregroundStyle(Color.haloTextPrimary) .lineLimit(1) - HStack(spacing: FlixySpacing.tight) { + HStack(spacing: HaloSpacing.tight) { if recording.isInProgress { // Eine laufende Aufnahme ist keine fertige: sie wächst // noch, und wer sie jetzt öffnet, sieht ein Ende, das // nicht das Ende ist. Label("liveTV.recording.inProgress", systemImage: "record.circle") - .font(.flixyCaption) - .foregroundStyle(Color.flixyDestructive) + .font(.haloCaption) + .foregroundStyle(Color.haloDestructive) } if let subtitle = subtitle(for: recording) { Text(subtitle) - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextSecondary) + .font(.haloCaption) + .foregroundStyle(Color.haloTextSecondary) .lineLimit(1) } } @@ -175,29 +175,29 @@ struct RecordingsView: View { private func timerRow(_ timer: LiveTimer) -> some View { VStack(alignment: .leading, spacing: 2) { Text(timer.title) - .font(.flixyBody) - .foregroundStyle(Color.flixyTextPrimary) + .font(.haloBody) + .foregroundStyle(Color.haloTextPrimary) .lineLimit(1) if let subtitle = subtitle(channel: timer.channelName, start: timer.startsAt) { Text(subtitle) - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextSecondary) + .font(.haloCaption) + .foregroundStyle(Color.haloTextSecondary) } } } private func seriesRow(_ timer: LiveSeriesTimer) -> some View { - HStack(spacing: FlixySpacing.snug) { + HStack(spacing: HaloSpacing.snug) { Image(systemName: "rectangle.stack.badge.record") - .foregroundStyle(Color.flixyTextSecondary) + .foregroundStyle(Color.haloTextSecondary) VStack(alignment: .leading, spacing: 2) { Text(timer.name) - .font(.flixyBody) - .foregroundStyle(Color.flixyTextPrimary) + .font(.haloBody) + .foregroundStyle(Color.haloTextPrimary) .lineLimit(1) Text(timer.recordsAnyChannel ? "liveTV.anyChannel" : "liveTV.series") - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextSecondary) + .font(.haloCaption) + .foregroundStyle(Color.haloTextSecondary) } } } diff --git a/Flixy/Views/LoadState.swift b/Halo/Views/LoadState.swift similarity index 98% rename from Flixy/Views/LoadState.swift rename to Halo/Views/LoadState.swift index b8788fe..e222621 100644 --- a/Flixy/Views/LoadState.swift +++ b/Halo/Views/LoadState.swift @@ -52,7 +52,7 @@ extension LoadState { /// Übersetzt Fehler in Sätze, die man einem Menschen zeigen kann. /// -/// **Eine** Stelle. Es gab davon zwei — hier und in `FlixySession` —, und sie +/// **Eine** Stelle. Es gab davon zwei — hier und in `HaloSession` —, und sie /// waren bereits auseinandergelaufen: derselbe Fehler bekam je nach /// Bildschirm eine andere Erklärung. enum ErrorText { diff --git a/Flixy/Views/Navigation/AccountAvatar.swift b/Halo/Views/Navigation/AccountAvatar.swift similarity index 88% rename from Flixy/Views/Navigation/AccountAvatar.swift rename to Halo/Views/Navigation/AccountAvatar.swift index 42ff18e..fd943d4 100644 --- a/Flixy/Views/Navigation/AccountAvatar.swift +++ b/Halo/Views/Navigation/AccountAvatar.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign /// Der erste Buchstabe auf einer Scheibe. /// @@ -16,7 +16,7 @@ struct AccountAvatar: View { let name: String var diameter: CGFloat = 26 - @Environment(\.flixyAccent) private var accent + @Environment(\.haloAccent) private var accent var body: some View { Text(name.prefix(1).uppercased()) @@ -25,7 +25,7 @@ struct AccountAvatar: View { // Kleinschrift auf einer grossen Scheibe sieht aus wie ein // Fehler. .font(.system(size: diameter * 0.46, weight: .semibold)) - .foregroundStyle(Color.flixyCanvas) + .foregroundStyle(Color.haloCanvas) .frame(width: diameter, height: diameter) .background(accent, in: .circle) } @@ -38,7 +38,7 @@ extension EnvironmentValues { /// Blatt gehört der Wurzel — nur sie überlebt den Wechsel des Bereichs. /// Jeder Bildschirm, der den Knopf zeigt, müsste den Weg dorthin sonst /// als Argument durchgereicht bekommen. - @Entry var flixyOpenSettings: () -> Void = {} + @Entry var haloOpenSettings: () -> Void = {} } /// Das Monogramm als Knopf für eine Werkzeugleiste. @@ -48,8 +48,8 @@ extension EnvironmentValues { /// damit **vor** Suche, Filter und Ansicht statt dahinter. Wo in der Reihe es /// steht, kann nur der entscheiden, der die Reihe schreibt. struct AccountToolbarButton: View { - @Environment(FlixySession.self) private var session - @Environment(\.flixyOpenSettings) private var openSettings + @Environment(HaloSession.self) private var session + @Environment(\.haloOpenSettings) private var openSettings var body: some View { Button(action: openSettings) { diff --git a/Flixy/Views/Navigation/AccountBar.swift b/Halo/Views/Navigation/AccountBar.swift similarity index 83% rename from Flixy/Views/Navigation/AccountBar.swift rename to Halo/Views/Navigation/AccountBar.swift index f75f04a..2cd1c8a 100644 --- a/Flixy/Views/Navigation/AccountBar.swift +++ b/Halo/Views/Navigation/AccountBar.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign /// Wer angemeldet ist — unten in der Seitenleiste. /// @@ -22,7 +22,7 @@ import FlixyDesign struct AccountBar: View { @Binding var selection: SidebarDestination - @Environment(FlixySession.self) private var session + @Environment(HaloSession.self) private var session @State private var isExpanded = false @State private var showsSignOutConfirmation = false @@ -55,7 +55,7 @@ struct AccountBar: View { } } .frame(minWidth: 240) - .background(Color.flixySurface) + .background(Color.haloSurface) // Auf dem iPhone gäbe es diese Leiste gar nicht; die Angabe // steht trotzdem da, damit aus dem Popover dort kein // bildschirmfüllendes Sheet wird. @@ -77,19 +77,19 @@ struct AccountBar: View { Button { isExpanded.toggle() } label: { - HStack(spacing: FlixySpacing.snug) { + HStack(spacing: HaloSpacing.snug) { AccountAvatar(name: title) VStack(alignment: .leading, spacing: 0) { Text(title) - .font(.flixyCardTitle) - .foregroundStyle(Color.flixyTextPrimary) + .font(.haloCardTitle) + .foregroundStyle(Color.haloTextPrimary) .lineLimit(1) if let subtitle { Text(subtitle) - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextMuted) + .font(.haloCaption) + .foregroundStyle(Color.haloTextMuted) .lineLimit(1) } } @@ -102,10 +102,10 @@ struct AccountBar: View { // Zeigt nach oben: dorthin geht die Karte auf. Image(systemName: "chevron.up") .font(.caption2.weight(.semibold)) - .foregroundStyle(Color.flixyTextMuted) + .foregroundStyle(Color.haloTextMuted) } - .padding(.horizontal, FlixySpacing.regular) - .padding(.vertical, FlixySpacing.snug) + .padding(.horizontal, HaloSpacing.regular) + .padding(.vertical, HaloSpacing.snug) .contentShape(.rect) } .buttonStyle(.plain) @@ -121,18 +121,18 @@ struct AccountBar: View { ) -> some View { Button(action: perform) { Label(title, systemImage: symbol) - .font(.flixyBody) - .foregroundStyle(isDestructive ? Color.flixyDestructive : Color.flixyTextPrimary) + .font(.haloBody) + .foregroundStyle(isDestructive ? Color.haloDestructive : Color.haloTextPrimary) .frame(maxWidth: .infinity, alignment: .leading) - .padding(.horizontal, FlixySpacing.regular) - .padding(.vertical, FlixySpacing.regular) + .padding(.horizontal, HaloSpacing.regular) + .padding(.vertical, HaloSpacing.regular) .contentShape(.rect) } .buttonStyle(.plain) } private var separator: some View { - Divider().overlay(Color.flixySeparator) + Divider().overlay(Color.haloSeparator) } } diff --git a/Flixy/Views/Navigation/FlixyNavigationBar.swift b/Halo/Views/Navigation/HaloNavigationBar.swift similarity index 79% rename from Flixy/Views/Navigation/FlixyNavigationBar.swift rename to Halo/Views/Navigation/HaloNavigationBar.swift index 40d87fd..ae32527 100644 --- a/Flixy/Views/Navigation/FlixyNavigationBar.swift +++ b/Halo/Views/Navigation/HaloNavigationBar.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign import MediaKit /// Wo die Navigation sitzt. @@ -49,7 +49,7 @@ struct NavigationGroup: Identifiable { /// mit Kontur; Glas bringt seine Kante selbst mit — sie hellt auf, wo Licht /// fällt, und verschwindet, wo keins ist. Das ist der Unterschied zwischen /// „umrandet" und „aus Glas". -struct FlixySidebar: View { +struct HaloSidebar: View { /// Alle Einträge, **ungefiltert**. Was davon zu sehen ist, entscheidet /// `layout` — beim Bearbeiten müssen auch die ausgeblendeten dastehen. let groups: [NavigationGroup] @@ -57,7 +57,7 @@ struct FlixySidebar: View { @Binding var placement: NavigationPlacement let layout: NavigationLayoutSettings - @Environment(\.flixyAccent) private var accent + @Environment(\.haloAccent) private var accent /// Welche Gruppen eingeklappt sind. Nach Kennung, nicht nach Stellung: /// kommt eine Mediathek dazu, soll nicht plötzlich die falsche zuklappen. @State private var collapsed: Set = [] @@ -80,7 +80,7 @@ struct FlixySidebar: View { static func surface(in shape: some InsettableShape) -> some View { shape .fill(.ultraThinMaterial) - .overlay { shape.fill(Color.flixyCanvas.opacity(0.55)) } + .overlay { shape.fill(Color.haloCanvas.opacity(0.55)) } .overlay { shape.strokeBorder( LinearGradient( @@ -134,10 +134,10 @@ struct FlixySidebar: View { // Ziehen zum Umsortieren mit, und die scrollt von sich aus. if isEditing { Text("sidebar.editHint") - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextMuted) - .padding(.horizontal, FlixySpacing.regular) - .padding(.bottom, FlixySpacing.snug) + .font(.haloCaption) + .foregroundStyle(Color.haloTextMuted) + .padding(.horizontal, HaloSpacing.regular) + .padding(.bottom, HaloSpacing.snug) List { ForEach(groups) { group in @@ -149,8 +149,8 @@ struct FlixySidebar: View { } header: { if let title = group.title { Text(title) - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextMuted) + .font(.haloCaption) + .foregroundStyle(Color.haloTextMuted) } } .listRowBackground(Color.clear) @@ -162,13 +162,13 @@ struct FlixySidebar: View { .environment(\.editMode, .constant(.active)) } else { ScrollView { - VStack(alignment: .leading, spacing: FlixySpacing.regular) { + VStack(alignment: .leading, spacing: HaloSpacing.regular) { ForEach(groups) { group in section(visible(group)) } } - .padding(.horizontal, FlixySpacing.snug) - .padding(.bottom, FlixySpacing.regular) + .padding(.horizontal, HaloSpacing.snug) + .padding(.bottom, HaloSpacing.regular) } .scrollBounceBehavior(.basedOnSize) .scrollIndicators(.never) @@ -176,14 +176,14 @@ struct FlixySidebar: View { Spacer(minLength: 0) - Divider().overlay(Color.flixySeparator) + Divider().overlay(Color.haloSeparator) AccountBar(selection: $selection) - .padding(.horizontal, FlixySpacing.snug) - .padding(.vertical, FlixySpacing.snug) + .padding(.horizontal, HaloSpacing.snug) + .padding(.vertical, HaloSpacing.snug) } .frame(width: Self.width) - .background { Self.surface(in: .rect(cornerRadius: FlixyRadius.panel, style: .continuous)) } - .clipShape(.rect(cornerRadius: FlixyRadius.panel, style: .continuous)) + .background { Self.surface(in: .rect(cornerRadius: HaloRadius.panel, style: .continuous)) } + .clipShape(.rect(cornerRadius: HaloRadius.panel, style: .continuous)) .shadow(color: .black.opacity(0.45), radius: 22, y: 8) // **Kein** Abstand nach rechts: dort schließt der Inhalt unmittelbar // an. Ein Abstand dorthin war der schwarze Spalt zwischen Aufmacher @@ -194,18 +194,18 @@ struct FlixySidebar: View { } private var header: some View { - HStack(spacing: FlixySpacing.snug) { + HStack(spacing: HaloSpacing.snug) { Button { withAnimation(.snappy(duration: 0.25)) { isEditing.toggle() } } label: { Text(isEditing ? "action.done" : "sidebar.edit") - .font(.flixyCaption) - .padding(.horizontal, FlixySpacing.snug) - .padding(.vertical, FlixySpacing.tight) + .font(.haloCaption) + .padding(.horizontal, HaloSpacing.snug) + .padding(.vertical, HaloSpacing.tight) .contentShape(Capsule()) } .buttonStyle(.plain) - .foregroundStyle(isEditing ? accent : Color.flixyTextSecondary) + .foregroundStyle(isEditing ? accent : Color.haloTextSecondary) Spacer(minLength: 0) @@ -214,21 +214,21 @@ struct FlixySidebar: View { placement = .top } label: { Image(systemName: "rectangle.topthird.inset.filled") - .font(.flixyRowHeader) - .padding(FlixySpacing.tight) + .font(.haloRowHeader) + .padding(HaloSpacing.tight) // Ohne eigene Klickfläche reicht das Ziel nur so weit // wie das Zeichen selbst — auf dem Mac trifft man das // mit dem Zeiger kaum. .contentShape(Rectangle()) } .buttonStyle(.plain) - .foregroundStyle(Color.flixyTextSecondary) + .foregroundStyle(Color.haloTextSecondary) .accessibilityLabel(Text("sidebar.moveToTop")) } } - .padding(.horizontal, FlixySpacing.regular) - .padding(.top, FlixySpacing.regular) - .padding(.bottom, FlixySpacing.snug) + .padding(.horizontal, HaloSpacing.regular) + .padding(.top, HaloSpacing.regular) + .padding(.bottom, HaloSpacing.snug) } /// Die Einträge einer Gruppe beim Bearbeiten: alle, in der gespeicherten @@ -271,16 +271,16 @@ struct FlixySidebar: View { } label: { HStack { Text(title) - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextMuted) + .font(.haloCaption) + .foregroundStyle(Color.haloTextMuted) Spacer() Image(systemName: "chevron.down") - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextMuted) + .font(.haloCaption) + .foregroundStyle(Color.haloTextMuted) .rotationEffect(.degrees(collapsed.contains(group.id) ? -90 : 0)) } - .padding(.horizontal, FlixySpacing.regular) - .padding(.top, FlixySpacing.snug) + .padding(.horizontal, HaloSpacing.regular) + .padding(.top, HaloSpacing.snug) } .buttonStyle(.plain) } @@ -301,12 +301,12 @@ struct FlixySidebar: View { private func editRow(_ entry: NavigationEntry) -> some View { let isHidden = layout.isHidden(entry.arrangementID) - return HStack(spacing: FlixySpacing.snug) { + return HStack(spacing: HaloSpacing.snug) { Button { layout.setHidden(!isHidden, for: entry.arrangementID) } label: { Image(systemName: isHidden ? "circle" : "checkmark.circle.fill") - .foregroundStyle(isHidden ? Color.flixyTextMuted : accent) + .foregroundStyle(isHidden ? Color.haloTextMuted : accent) .contentShape(Rectangle()) } .buttonStyle(.plain) @@ -318,8 +318,8 @@ struct FlixySidebar: View { .lineLimit(1) Spacer(minLength: 0) } - .font(.flixyBody) - .foregroundStyle(isHidden ? Color.flixyTextMuted : Color.flixyTextPrimary) + .font(.haloBody) + .foregroundStyle(isHidden ? Color.haloTextMuted : Color.haloTextPrimary) } private func row(_ entry: NavigationEntry) -> some View { @@ -328,23 +328,23 @@ struct FlixySidebar: View { return Button { selection = entry.destination } label: { - HStack(spacing: FlixySpacing.snug) { + HStack(spacing: HaloSpacing.snug) { Image(systemName: entry.symbol) - .font(.flixyBody) + .font(.haloBody) .frame(width: 22, alignment: .center) entry.title - .font(.flixyBody) + .font(.haloBody) // Ein langer Mediathekenname darf die Leiste nicht // breiter machen; sie hat eine feste Breite. .lineLimit(1) Spacer(minLength: 0) } - .foregroundStyle(isSelected ? accent : Color.flixyTextPrimary) - .padding(.horizontal, FlixySpacing.regular) - .padding(.vertical, FlixySpacing.snug) + .foregroundStyle(isSelected ? accent : Color.haloTextPrimary) + .padding(.horizontal, HaloSpacing.regular) + .padding(.vertical, HaloSpacing.snug) .background { if isSelected { - Capsule().fill(Color.flixyElevated) + Capsule().fill(Color.haloElevated) } } .contentShape(Capsule()) @@ -360,29 +360,29 @@ struct FlixySidebar: View { /// Mediatheken stehen hier in einem Menü statt einzeln: oben ist der Platz /// waagerecht begrenzt, und eine Reihe, die bei acht Mediatheken über den Rand /// hinauswächst, wäre schlechter als ein Menü. -struct FlixyTopBar: View { +struct HaloTopBar: View { let groups: [NavigationGroup] @Binding var selection: SidebarDestination @Binding var placement: NavigationPlacement - @Environment(\.flixyAccent) private var accent + @Environment(\.haloAccent) private var accent var body: some View { - HStack(spacing: FlixySpacing.tight) { + HStack(spacing: HaloSpacing.tight) { Button { placement = .sidebar } label: { Image(systemName: "sidebar.leading") - .font(.flixyBody) - .padding(.horizontal, FlixySpacing.regular) - .padding(.vertical, FlixySpacing.snug) + .font(.haloBody) + .padding(.horizontal, HaloSpacing.regular) + .padding(.vertical, HaloSpacing.snug) // Ohne eigene Klickfläche reicht das Ziel nur so weit wie // das Zeichen; auf dem Mac war der Umschalter damit // praktisch nicht zu treffen. .contentShape(Capsule()) } .buttonStyle(.plain) - .foregroundStyle(Color.flixyTextSecondary) + .foregroundStyle(Color.haloTextSecondary) .accessibilityLabel(Text("sidebar.moveToSide")) ForEach(groups) { group in @@ -395,12 +395,12 @@ struct FlixyTopBar: View { } } } - .padding(.horizontal, FlixySpacing.snug) - .padding(.vertical, FlixySpacing.snug) - .background { FlixySidebar.surface(in: .capsule) } + .padding(.horizontal, HaloSpacing.snug) + .padding(.vertical, HaloSpacing.snug) + .background { HaloSidebar.surface(in: .capsule) } .clipShape(.capsule) .shadow(color: .black.opacity(0.45), radius: 18, y: 6) - .padding(.top, FlixySpacing.snug) + .padding(.top, HaloSpacing.snug) } private func pill(_ entry: NavigationEntry) -> some View { @@ -410,13 +410,13 @@ struct FlixyTopBar: View { selection = entry.destination } label: { entry.title - .font(.flixyBody) + .font(.haloBody) .lineLimit(1) - .foregroundStyle(isSelected ? accent : Color.flixyTextPrimary) - .padding(.horizontal, FlixySpacing.loose) - .padding(.vertical, FlixySpacing.snug) + .foregroundStyle(isSelected ? accent : Color.haloTextPrimary) + .padding(.horizontal, HaloSpacing.loose) + .padding(.vertical, HaloSpacing.snug) .background { - if isSelected { Capsule().fill(Color.flixyElevated) } + if isSelected { Capsule().fill(Color.haloElevated) } } .contentShape(Capsule()) } @@ -433,21 +433,21 @@ struct FlixyTopBar: View { } } } label: { - HStack(spacing: FlixySpacing.tight) { + HStack(spacing: HaloSpacing.tight) { if let title = group.title { // Ohne das wurde aus „Mediatheken" ein „Mediathe…". // Die Leiste ist so breit wie ihr Inhalt; sie hat keinen // Grund, an einem Wort zu sparen. Text(title).fixedSize() } - Image(systemName: "chevron.down").font(.flixyCaption) + Image(systemName: "chevron.down").font(.haloCaption) } - .font(.flixyBody) - .foregroundStyle(containsSelection ? accent : Color.flixyTextPrimary) - .padding(.horizontal, FlixySpacing.loose) - .padding(.vertical, FlixySpacing.snug) + .font(.haloBody) + .foregroundStyle(containsSelection ? accent : Color.haloTextPrimary) + .padding(.horizontal, HaloSpacing.loose) + .padding(.vertical, HaloSpacing.snug) .background { - if containsSelection { Capsule().fill(Color.flixyElevated) } + if containsSelection { Capsule().fill(Color.haloElevated) } } .contentShape(Capsule()) } diff --git a/Flixy/Views/Navigation/MediaStack.swift b/Halo/Views/Navigation/MediaStack.swift similarity index 91% rename from Flixy/Views/Navigation/MediaStack.swift rename to Halo/Views/Navigation/MediaStack.swift index ac29ff9..6c55008 100644 --- a/Flixy/Views/Navigation/MediaStack.swift +++ b/Halo/Views/Navigation/MediaStack.swift @@ -16,7 +16,7 @@ import MediaKit struct MediaStack: View { @ViewBuilder let content: () -> Content - @Environment(FlixySession.self) private var session + @Environment(HaloSession.self) private var session @State private var path = NavigationPath() var body: some View { @@ -31,7 +31,7 @@ struct MediaStack: View { .navigationDestination(for: LiveTVRoute.self) { _ in LiveTVView() } .navigationDestination(for: SearchRoute.self) { _ in SearchView() } } - .environment(\.flixyPush) { ziel in path.append(ziel) } + .environment(\.haloPush) { ziel in path.append(ziel) } } } @@ -45,5 +45,5 @@ extension EnvironmentValues { /// /// Die Voreinstellung tut nichts: ausserhalb eines Stapels gibt es nichts /// zu schieben, und ein Absturz wäre die schlechtere Antwort. - @Entry var flixyPush: (any Hashable) -> Void = { _ in } + @Entry var haloPush: (any Hashable) -> Void = { _ in } } diff --git a/Flixy/Views/Navigation/RootView.swift b/Halo/Views/Navigation/RootView.swift similarity index 95% rename from Flixy/Views/Navigation/RootView.swift rename to Halo/Views/Navigation/RootView.swift index 886bd04..0b63c7e 100644 --- a/Flixy/Views/Navigation/RootView.swift +++ b/Halo/Views/Navigation/RootView.swift @@ -1,8 +1,8 @@ import SwiftUI -import FlixyDesign +import HaloDesign import MediaKit -import FlixyDownloads -import FlixyPlayback +import HaloDownloads +import HaloPlayback /// Die Wurzelansicht. /// @@ -10,8 +10,8 @@ import FlixyPlayback /// Welche Form die Navigation danach annimmt — Seitenleiste, Leiste oben, /// Leiste unten —, entscheidet das System und der Nutzer, nicht diese Datei. struct RootView: View { - @Environment(FlixySession.self) private var session - @Environment(FlixyTheme.self) private var theme + @Environment(HaloSession.self) private var session + @Environment(HaloTheme.self) private var theme @Environment(PlaybackCoordinator.self) private var playback @Environment(PlaybackSettings.self) private var settings @Environment(LanguagePreferences.self) private var languages @@ -35,13 +35,13 @@ struct RootView: View { /// Reihenfolge, Ein- und Ausblenden, und ob ein Eintrag in der Leiste oben /// liegt: das System schreibt es hier hinein, wir geben ihm nur einen Ort /// zum Aufbewahren. - @AppStorage("flixy.navigation.customization") + @AppStorage("halo.navigation.customization") private var customization = TabViewCustomization() /// Ob die Navigation an der Seite oder oben sitzt — gespeichert. /// /// Die Wahl gehört dem Nutzer und muss den Neustart überleben. - @AppStorage("flixy.navigation.placement") + @AppStorage("halo.navigation.placement") private var storedPlacement: NavigationPlacement = .sidebar /// Dieselbe Wahl, aber als Zustand dieser Ansicht. @@ -85,7 +85,7 @@ struct RootView: View { case .launching: ProgressView() .frame(maxWidth: .infinity, maxHeight: .infinity) - .background(Color.flixyCanvas) + .background(Color.haloCanvas) case .signedOut: SignInView() @@ -104,7 +104,7 @@ struct RootView: View { library } } - .background(Color.flixyCanvas) + .background(Color.haloCanvas) .environment(topChrome) // **Aus dem Fenster, nicht aus dem Layout.** // @@ -121,7 +121,7 @@ struct RootView: View { // Durchgang. // // **Nicht** die Ursache des Players, der oben und unten hinausging: - // das war die Seitenleiste selbst, siehe `FlixySidebar`. Diese Zeile + // das war die Seitenleiste selbst, siehe `HaloSidebar`. Diese Zeile // spart eine Layoutrunde, mehr nicht. .onGeometryChange(for: CGSize.self) { proxy in proxy.size @@ -129,7 +129,7 @@ struct RootView: View { .onAppear { statusBarHeight = ScreenSafeArea.current.top } // Hier statt in der Scene: eine View wertet Beobachtungsänderungen // zuverlässig neu aus, ein Scene-Body nicht. - .flixyAccent(theme) + .haloAccent(theme) .tint(theme.accentColor) // **Einer für alle Kacheln.** Einer je Kachel wäre bei einem // Serverausfall ein Stapel aus zwanzig gleichen Meldungen. @@ -174,7 +174,7 @@ struct RootView: View { // ihn jemand von Hand antippte — auch dann, wenn das WLAN seit einer // Stunde wieder stand. // - // Hier und nicht im Koordinator: `FlixyDownloads` hängt bewusst nicht + // Hier und nicht im Koordinator: `HaloDownloads` hängt bewusst nicht // an `NetworkConditions`, es bekommt den Netzzustand als Wert gereicht // (siehe `TransferHold`). Diese Ansicht kennt beide. .onChange(of: network.isReachable) { _, erreichbar in @@ -289,7 +289,7 @@ struct RootView: View { .overlay(alignment: .topTrailing) { profileButton } } } - .customizationID("flixy.tab.home") + .customizationID("halo.tab.home") // Auf dem iPad jede Mediathek einzeln, auf dem iPhone alle // zusammen hinter einem Eintrag. Der Grund ist nicht Geschmack: @@ -307,12 +307,12 @@ struct RootView: View { } label: { sidebarLabel(Text(library.title), symbol: library.kind.symbol) } - .customizationID("flixy.tab.library.\(library.id)") + .customizationID("halo.tab.library.\(library.id)") } } header: { Text("sidebar.libraries") } - .customizationID("flixy.tab.libraries") + .customizationID("halo.tab.libraries") if session.supportsLiveTV { Tab(value: SidebarDestination.liveTV) { @@ -320,7 +320,7 @@ struct RootView: View { } label: { tabLabel("sidebar.liveTV", symbol: "dot.radiowaves.left.and.right") } - .customizationID("flixy.tab.liveTV") + .customizationID("halo.tab.liveTV") } } else { Tab(value: SidebarDestination.libraryHub) { @@ -328,7 +328,7 @@ struct RootView: View { } label: { tabLabel("sidebar.library", symbol: "books.vertical") } - .customizationID("flixy.tab.libraryHub") + .customizationID("halo.tab.libraryHub") } Tab(value: SidebarDestination.downloads) { @@ -336,7 +336,7 @@ struct RootView: View { } label: { tabLabel("sidebar.downloads", symbol: "arrow.down.circle") } - .customizationID("flixy.tab.downloads") + .customizationID("halo.tab.downloads") // **Nicht auf dem iPhone.** Dort führt der Weg über das // Monogramm oben rechts — siehe `profileButton`. Einstellungen @@ -349,7 +349,7 @@ struct RootView: View { } label: { tabLabel("sidebar.settings", symbol: "gearshape") } - .customizationID("flixy.tab.settings") + .customizationID("halo.tab.settings") } // Die Suche nur dort, wo Platz für sie ist. @@ -362,7 +362,7 @@ struct RootView: View { Tab(value: SidebarDestination.search, role: .search) { mediaStack { SearchView() } } - .customizationID("flixy.tab.search") + .customizationID("halo.tab.search") } } .tabViewStyle(.sidebarAdaptable) @@ -389,7 +389,7 @@ struct RootView: View { if sizeClass == .regular { HStack(spacing: 0) { if placement == .sidebar { - FlixySidebar( + HaloSidebar( groups: navigationGroups, selection: $selection, placement: $placement.animation(Self.placementAnimation), @@ -433,7 +433,7 @@ struct RootView: View { .background { TabChromeSuppressor().frame(width: 0, height: 0) } .overlay(alignment: .top) { if placement == .top { - FlixyTopBar( + HaloTopBar( groups: navigationGroups.map(visible), selection: $selection, placement: $placement.animation(Self.placementAnimation) @@ -473,7 +473,7 @@ struct RootView: View { // Navigationsstapel um sich — die Medienziele aus `mediaStack` ruft // es nie auf. Und beim Schliessen steht man wieder dort, wo man war, // statt in einem Bereich, den man erst wieder verlassen muss. - .environment(\.flixyOpenSettings, { showsSettings = true }) + .environment(\.haloOpenSettings, { showsSettings = true }) .sheet(isPresented: $showsSettings) { NavigationStack { SettingsView() @@ -481,7 +481,7 @@ struct RootView: View { // jeder weiss das, und wer in einem Unterbildschirm steht, // zieht damit gleich alles weg. Ein Knopf sagt es. .toolbar { - ToolbarItem(placement: .flixyTrailing) { + ToolbarItem(placement: .haloTrailing) { Button("action.close") { showsSettings = false } } } @@ -515,16 +515,16 @@ struct RootView: View { showsSettings = true } label: { AccountAvatar(name: session.accountName ?? session.serverName, diameter: 34) - .padding(FlixySpacing.snug) + .padding(HaloSpacing.snug) // Damit er auch über einem hellen Aufmacher steht. .background(.black.opacity(0.28), in: .circle) } .buttonStyle(.plain) - .padding(.trailing, FlixySpacing.regular) + .padding(.trailing, HaloSpacing.regular) // **Ohne die Statusleiste.** Auf dem iPhone sitzt der Baum innerhalb // des Sicherheitsrands; sie noch einmal dazuzurechnen schöbe den // Knopf um ihre Höhe nach unten, mitten ins Bild. - .padding(.top, FlixySpacing.snug) + .padding(.top, HaloSpacing.snug) .opacity(topChrome.isRevealed ? 1 : 0) .allowsHitTesting(topChrome.isRevealed) .animation(.snappy(duration: 0.28), value: topChrome.isRevealed) @@ -543,7 +543,7 @@ struct RootView: View { /// schwebt nichts, worunter man greifen müsste. private var topInset: CGFloat { guard sizeClass == .regular else { return 0 } - return statusBarHeight + (placement == .sidebar ? FlixySidebar.margin : Self.topBarHeight) + return statusBarHeight + (placement == .sidebar ? HaloSidebar.margin : Self.topBarHeight) } private var navigationGroups: [NavigationGroup] { diff --git a/Flixy/Views/Navigation/SidebarDestination.swift b/Halo/Views/Navigation/SidebarDestination.swift similarity index 100% rename from Flixy/Views/Navigation/SidebarDestination.swift rename to Halo/Views/Navigation/SidebarDestination.swift diff --git a/Flixy/Views/Navigation/TabChrome.swift b/Halo/Views/Navigation/TabChrome.swift similarity index 100% rename from Flixy/Views/Navigation/TabChrome.swift rename to Halo/Views/Navigation/TabChrome.swift diff --git a/Flixy/Views/Navigation/TopChrome.swift b/Halo/Views/Navigation/TopChrome.swift similarity index 98% rename from Flixy/Views/Navigation/TopChrome.swift rename to Halo/Views/Navigation/TopChrome.swift index e1ca5aa..e8c4348 100644 --- a/Flixy/Views/Navigation/TopChrome.swift +++ b/Halo/Views/Navigation/TopChrome.swift @@ -40,7 +40,7 @@ extension View { /// die nächstgelegene, und eine Reihe, die man seitwärts schiebt, steht /// immer bei null — die Insel käme beim Blättern zurück, obwohl die Seite /// weit unten steht. - func flixyRevealsTopChrome() -> some View { + func haloRevealsTopChrome() -> some View { modifier(RevealsTopChrome()) } } diff --git a/Flixy/Views/Placeholder/PlaceholderScreen.swift b/Halo/Views/Placeholder/PlaceholderScreen.swift similarity index 86% rename from Flixy/Views/Placeholder/PlaceholderScreen.swift rename to Halo/Views/Placeholder/PlaceholderScreen.swift index 887962f..3351b9b 100644 --- a/Flixy/Views/Placeholder/PlaceholderScreen.swift +++ b/Halo/Views/Placeholder/PlaceholderScreen.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign /// Ein noch nicht gebauter Bereich. /// @@ -15,9 +15,9 @@ struct PlaceholderScreen: View { } description: { Text("placeholder.description") } - .background(Color.flixyCanvas) + .background(Color.haloCanvas) .navigationTitle(destination.title) - .flixyInlineTitle() + .haloInlineTitle() } } diff --git a/Flixy/Views/Player/AirPlayButton.swift b/Halo/Views/Player/AirPlayButton.swift similarity index 100% rename from Flixy/Views/Player/AirPlayButton.swift rename to Halo/Views/Player/AirPlayButton.swift diff --git a/Flixy/Views/Player/MacFullScreen.swift b/Halo/Views/Player/MacFullScreen.swift similarity index 100% rename from Flixy/Views/Player/MacFullScreen.swift rename to Halo/Views/Player/MacFullScreen.swift diff --git a/Flixy/Views/Player/MiniPlayer.swift b/Halo/Views/Player/MiniPlayer.swift similarity index 96% rename from Flixy/Views/Player/MiniPlayer.swift rename to Halo/Views/Player/MiniPlayer.swift index 3b40b78..a23166e 100644 --- a/Flixy/Views/Player/MiniPlayer.swift +++ b/Halo/Views/Player/MiniPlayer.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign /// Die schwebende Videokachel. /// @@ -51,7 +51,7 @@ struct MiniPlayer: View { // ist als das Fenster, ließe sich nicht mehr wegziehen. let upper = max(160, min(bounds.width * 0.75, 560)) let width = min(max(chosen * zoom, 140), upper) - return CGSize(width: width, height: (width / FlixyAspectRatio.landscape).rounded()) + return CGSize(width: width, height: (width / HaloAspectRatio.landscape).rounded()) } var body: some View { @@ -105,10 +105,10 @@ struct MiniPlayer: View { } } } - .clipShape(.rect(cornerRadius: FlixyRadius.card)) + .clipShape(.rect(cornerRadius: HaloRadius.card)) .overlay { - RoundedRectangle(cornerRadius: FlixyRadius.card) - .strokeBorder(Color.flixySeparator, lineWidth: 0.5) + RoundedRectangle(cornerRadius: HaloRadius.card) + .strokeBorder(Color.haloSeparator, lineWidth: 0.5) } .shadow(color: .black.opacity(0.5), radius: 12, y: 4) .contentShape(.rect) @@ -158,9 +158,9 @@ struct MiniPlayer: View { } } } - .padding(FlixySpacing.tight) + .padding(HaloSpacing.tight) // Über dem Fortschrittsbalken, nicht darauf. - .padding(.bottom, FlixySpacing.tight) + .padding(.bottom, HaloSpacing.tight) } /// Ein kleiner Knopf, der auf jedem Bild lesbar bleibt. diff --git a/Flixy/Views/Player/PlaybackScrubber.swift b/Halo/Views/Player/PlaybackScrubber.swift similarity index 98% rename from Flixy/Views/Player/PlaybackScrubber.swift rename to Halo/Views/Player/PlaybackScrubber.swift index b5675d0..0dbadee 100644 --- a/Flixy/Views/Player/PlaybackScrubber.swift +++ b/Halo/Views/Player/PlaybackScrubber.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign /// Der Regler unter dem Film — mit dem, was schon geladen ist. /// @@ -34,7 +34,7 @@ struct PlaybackScrubber: View { /// Bei jeder Berührung — damit die Bedienung stehen bleibt. let onActivity: () -> Void - @Environment(\.flixyAccent) private var accent + @Environment(\.haloAccent) private var accent private static let trackHeight: CGFloat = 5 private static let thumbSize: CGFloat = 13 diff --git a/Flixy/Views/Player/PlayerModel.swift b/Halo/Views/Player/PlayerModel.swift similarity index 99% rename from Flixy/Views/Player/PlayerModel.swift rename to Halo/Views/Player/PlayerModel.swift index ef819d8..ca25264 100644 --- a/Flixy/Views/Player/PlayerModel.swift +++ b/Halo/Views/Player/PlayerModel.swift @@ -2,8 +2,8 @@ import AVKit import Foundation import MediaKit import Observation -import FlixyDownloads -import FlixyPlayback +import HaloDownloads +import HaloPlayback /// Führt einen Abspielwunsch aus. /// @@ -169,10 +169,10 @@ final class PlayerModel { /// Wo das Bild aufhört. /// - /// Liegt bei `FlixyPlayback`, weil beide Engines es brauchen. Der Name + /// Liegt bei `HaloPlayback`, weil beide Engines es brauchen. Der Name /// hier bleibt, damit die Ansicht weiter `PlayerModel.VideoFit` schreiben /// kann. - typealias VideoFit = FlixyPlayback.VideoFit + typealias VideoFit = HaloPlayback.VideoFit /// Bild-in-Bild hängt an genau dieser Ebene und wandert deshalb mit. /// diff --git a/Flixy/Views/Player/PlayerView.swift b/Halo/Views/Player/PlayerView.swift similarity index 95% rename from Flixy/Views/Player/PlayerView.swift rename to Halo/Views/Player/PlayerView.swift index ca0bf39..6d3321d 100644 --- a/Flixy/Views/Player/PlayerView.swift +++ b/Halo/Views/Player/PlayerView.swift @@ -1,7 +1,7 @@ import SwiftUI -import FlixyDesign -import FlixyDownloads -import FlixyPlayback +import HaloDesign +import HaloDownloads +import HaloPlayback /// Der Vollbildplayer. struct PlayerView: View { @@ -13,14 +13,14 @@ struct PlayerView: View { /// Nutzers statt eine Nebenwirkung der Navigation. let model: PlayerModel - @Environment(FlixySession.self) private var session + @Environment(HaloSession.self) private var session @Environment(PlaybackCoordinator.self) private var playback @Environment(PlaybackSettings.self) private var settings @Environment(SubtitleAppearance.self) private var subtitleAppearance @Environment(NetworkConditions.self) private var network @Environment(DownloadCoordinator.self) private var downloads @Environment(PlaybackDiagnostics.self) private var diagnostics - @Environment(\.flixyAccent) private var accent + @Environment(\.haloAccent) private var accent /// Woran sich Quer- und Hochformat unterscheiden lassen. /// /// Auf jedem iPhone ist das Querformat senkrecht kompakt und das @@ -72,7 +72,7 @@ struct PlayerView: View { /// Knopf. @State private var isFullScreen = false /// Ob Zeiger und Tastatur gelten. Einmal beim Start ermittelt. - private var isMac: Bool { FlixyPlatform.isMac } + private var isMac: Bool { HaloPlatform.isMac } /// Ob gedreht und mit zwei Fingern gezoomt werden kann. /// /// Ein iPad dreht sich von selbst und braucht keinen Knopf dafür; der @@ -200,7 +200,7 @@ struct PlayerView: View { } .opacity(zeigt ? 1 : 0) .allowsHitTesting(zeigt) - .padding(FlixySpacing.loose) + .padding(HaloSpacing.loose) // Siehe `controls(for:)`: die Kopfzeile lag sonst hinter // der Dynamic Island, und der Zurück-Pfeil war tot. .padding(.top, safeArea.top) @@ -217,7 +217,7 @@ struct PlayerView: View { // ein zweiter Klick auf dieselbe Stelle legte das Fenster // ins Dock, weil das der Doppelklick auf eine // Fensterleiste tut. - .padding(.top, FlixyPlatform.isMac ? Self.titleBarHeight : 0) + .padding(.top, HaloPlatform.isMac ? Self.titleBarHeight : 0) } } } @@ -334,12 +334,12 @@ struct PlayerView: View { // kein Absturz, aber die falsche Farbe. .sheet(item: $trackPicker) { kind in TrackPickerSheet(model: model, kind: kind) - .environment(\.flixyAccent, accent) + .environment(\.haloAccent, accent) } .sheet(isPresented: $showsQualityChoice) { QualitySheet(model: model) .environment(settings) - .environment(\.flixyAccent, accent) + .environment(\.haloAccent, accent) } .onChange(of: showsQualityChoice) { _, isShown in // Nach dem Schließen die Bedienelemente stehen lassen und die @@ -371,7 +371,7 @@ struct PlayerView: View { Spacer() scrubber(for: model) } - .padding(FlixySpacing.loose) + .padding(HaloSpacing.loose) // **Zusätzlich zum Polster, nicht statt.** Der Sicherheitsrand sagt, // wo der Bildschirm aufhört; das Polster sagt, wie luftig es aussehen // soll. Ersetzte eines das andere, klebte der Schieberegler im @@ -395,7 +395,7 @@ struct PlayerView: View { } private func topBar(for model: PlayerModel) -> some View { - HStack(alignment: .top, spacing: FlixySpacing.regular) { + HStack(alignment: .top, spacing: HaloSpacing.regular) { // Der Pfeil verkleinert, er beendet nicht. Das ist der ganze // Zweck der Übung: weiterschauen, während man stöbert. Button { @@ -403,7 +403,7 @@ struct PlayerView: View { } label: { Image(systemName: "chevron.down") .font(.title3) - .padding(FlixySpacing.snug) + .padding(HaloSpacing.snug) } .accessibilityLabel(Text("player.minimize")) @@ -414,17 +414,17 @@ struct PlayerView: View { } label: { Image(systemName: "xmark") .font(.callout.weight(.semibold)) - .padding(FlixySpacing.snug) + .padding(HaloSpacing.snug) } .accessibilityLabel(Text("player.stop")) VStack(alignment: .leading, spacing: 2) { Text(model.title) - .font(.flixyCardTitle) + .font(.haloCardTitle) .lineLimit(1) if let subtitle = model.subtitle { Text(subtitle) - .font(.flixyCaption) + .font(.haloCaption) .foregroundStyle(.white.opacity(0.7)) .lineLimit(1) } @@ -447,7 +447,7 @@ struct PlayerView: View { ? "arrow.down.right.and.arrow.up.left" : "arrow.up.left.and.arrow.down.right") .font(.callout.weight(.semibold)) - .padding(FlixySpacing.snug) + .padding(HaloSpacing.snug) } .accessibilityLabel(Text(isFullScreen ? "player.exitFullScreen" : "player.fullScreen")) .keyboardShortcut("f", modifiers: [.command, .control]) @@ -465,7 +465,7 @@ struct PlayerView: View { ? "arrow.down.right.and.arrow.up.left" : "arrow.up.left.and.arrow.down.right") .font(.title3) - .padding(FlixySpacing.snug) + .padding(HaloSpacing.snug) } .accessibilityLabel(Text(model.videoFit == .fill ? "player.fitVideo" : "player.fillVideo")) } @@ -488,7 +488,7 @@ struct PlayerView: View { // Zwei Pfeile im Kreis sagen, was passiert: es dreht. Image(systemName: "arrow.triangle.2.circlepath") .font(.title3) - .padding(FlixySpacing.snug) + .padding(HaloSpacing.snug) } .accessibilityLabel(Text("player.rotate")) } @@ -524,7 +524,7 @@ struct PlayerView: View { } label: { Image(systemName: model.isPictureInPictureActive ? "pip.exit" : "pip.enter") .font(.title3) - .padding(FlixySpacing.snug) + .padding(HaloSpacing.snug) } .accessibilityLabel(Text("player.pictureInPicture")) } @@ -532,7 +532,7 @@ struct PlayerView: View { if model.engine?.supportsAirPlay == true { AirPlayButton(tint: accent) .frame(width: 28, height: 28) - .padding(FlixySpacing.snug) + .padding(HaloSpacing.snug) .accessibilityLabel(Text("player.airPlay")) } @@ -554,7 +554,7 @@ struct PlayerView: View { } label: { Image(systemName: symbol) .font(.title3) - .padding(FlixySpacing.snug) + .padding(HaloSpacing.snug) } .accessibilityLabel(Text(label)) } @@ -578,15 +578,15 @@ struct PlayerView: View { // sagen nicht, was eingestellt ist; „1080p" schon — und genau // das ist die Frage, wegen der man hier hintippt. Text(model.qualityLabel) - .font(.flixyCaption.weight(.semibold)) + .font(.haloCaption.weight(.semibold)) .monospacedDigit() - .padding(.horizontal, FlixySpacing.snug) - .padding(.vertical, FlixySpacing.tight) + .padding(.horizontal, HaloSpacing.snug) + .padding(.vertical, HaloSpacing.tight) .overlay { - RoundedRectangle(cornerRadius: FlixyRadius.card) + RoundedRectangle(cornerRadius: HaloRadius.card) .strokeBorder(.white.opacity(0.5), lineWidth: 1) } - .padding(FlixySpacing.snug) + .padding(HaloSpacing.snug) } } .disabled(model.isChangingQuality) @@ -594,7 +594,7 @@ struct PlayerView: View { } private func transport(for model: PlayerModel) -> some View { - HStack(spacing: FlixySpacing.section * 2) { + HStack(spacing: HaloSpacing.section * 2) { Button { model.skip(by: .seconds(-settings.rewindSeconds)) scheduleControlsHide() @@ -652,7 +652,7 @@ struct PlayerView: View { } private func scrubber(for model: PlayerModel) -> some View { - VStack(spacing: FlixySpacing.tight) { + VStack(spacing: HaloSpacing.tight) { PlaybackScrubber( position: model.currentTime, duration: model.duration ?? .seconds(1), @@ -695,9 +695,9 @@ struct PlayerView: View { } } label: { Label("player.nextEpisode", systemImage: "forward.end.fill") - .font(.flixyCardTitle) - .padding(.horizontal, FlixySpacing.loose) - .padding(.vertical, FlixySpacing.regular) + .font(.haloCardTitle) + .padding(.horizontal, HaloSpacing.loose) + .padding(.vertical, HaloSpacing.regular) } .buttonStyle(.borderedProminent) .tint(accent) @@ -706,21 +706,21 @@ struct PlayerView: View { model.skipActiveMarker() } label: { Text(marker.isIntro ? "player.skipIntro" : "player.skipCredits") - .font(.flixyCardTitle) - .padding(.horizontal, FlixySpacing.loose) - .padding(.vertical, FlixySpacing.regular) + .font(.haloCardTitle) + .padding(.horizontal, HaloSpacing.loose) + .padding(.vertical, HaloSpacing.regular) } .buttonStyle(.bordered) .tint(.white) .transition(.move(edge: .trailing).combined(with: .opacity)) } } - .padding(.horizontal, FlixySpacing.section) + .padding(.horizontal, HaloSpacing.section) .padding(.leading, safeArea.leading) .padding(.trailing, safeArea.trailing) // Über dem Schieberegler, damit sich beides nicht überdeckt, wenn // die Bedienelemente eingeblendet sind. - .padding(.bottom, (showsControls ? 110 : FlixySpacing.section) + safeArea.bottom) + .padding(.bottom, (showsControls ? 110 : HaloSpacing.section) + safeArea.bottom) } .animation(.snappy, value: model.activeMarker?.id) .animation(.snappy, value: model.hasReachedEnd) @@ -731,10 +731,10 @@ struct PlayerView: View { ZStack { Color.black.ignoresSafeArea() - VStack(spacing: FlixySpacing.regular) { + VStack(spacing: HaloSpacing.regular) { ProgressView().tint(.white) Text("player.restoring") - .font(.flixyCardTitle) + .font(.haloCardTitle) .foregroundStyle(.white) // Die Stelle ausdrücklich nennen: der ganze Zweck ist, dass // niemand denkt, er müsse sie wiederfinden. @@ -747,33 +747,33 @@ struct PlayerView: View { } private func preparing(for model: PlayerModel) -> some View { - VStack(spacing: FlixySpacing.loose) { + VStack(spacing: HaloSpacing.loose) { ProgressView().tint(.white) Text(model.title) - .font(.flixyCardTitle) + .font(.haloCardTitle) .foregroundStyle(.white) .multilineTextAlignment(.center) Text("player.preparing") - .font(.flixyCaption) + .font(.haloCaption) .foregroundStyle(.white.opacity(0.6)) } - .padding(FlixySpacing.section) + .padding(HaloSpacing.section) } private func failure(message: String) -> some View { - VStack(spacing: FlixySpacing.loose) { + VStack(spacing: HaloSpacing.loose) { Image(systemName: "exclamationmark.triangle") .font(.largeTitle) .foregroundStyle(.white.opacity(0.8)) Text(message) - .font(.flixyBody) + .font(.haloBody) .foregroundStyle(.white) .multilineTextAlignment(.center) Button("action.close") { playback.close() } .buttonStyle(.borderedProminent) .tint(accent) } - .padding(FlixySpacing.section) + .padding(HaloSpacing.section) } /// Die beiden Flächen zum Springen. @@ -821,7 +821,7 @@ struct PlayerView: View { .labelStyle(.iconOnly) .font(.system(size: 44)) .foregroundStyle(.white) - .padding(FlixySpacing.section) + .padding(HaloSpacing.section) .background(.black.opacity(0.35), in: .circle) .transition(.opacity.combined(with: .scale)) } diff --git a/Flixy/Views/Player/QualitySheet.swift b/Halo/Views/Player/QualitySheet.swift similarity index 96% rename from Flixy/Views/Player/QualitySheet.swift rename to Halo/Views/Player/QualitySheet.swift index ca1680d..9305a8c 100644 --- a/Flixy/Views/Player/QualitySheet.swift +++ b/Halo/Views/Player/QualitySheet.swift @@ -1,6 +1,6 @@ import SwiftUI -import FlixyDesign -import FlixyPlayback +import HaloDesign +import HaloPlayback /// Die Qualitätswahl im Player, samt dem, was gerade tatsächlich läuft. /// @@ -11,7 +11,7 @@ import FlixyPlayback struct QualitySheet: View { let model: PlayerModel - @Environment(\.flixyAccent) private var accent + @Environment(\.haloAccent) private var accent /// **Als Fragezeichen**, nicht als Behauptung. /// /// `@Environment(PlaybackSettings.self)` ohne Optional hält die Anwendung @@ -62,14 +62,14 @@ struct QualitySheet: View { } } .navigationTitle(Text("player.quality")) - .flixyInlineTitle() + .haloInlineTitle() .toolbar { ToolbarItem(placement: .confirmationAction) { Button("action.done") { dismiss() } } } } - .flixyResizableSheet() + .haloResizableSheet() } /// Was gerade läuft — gemessen, nicht gewünscht. @@ -158,11 +158,11 @@ struct QualitySheet: View { } label: { HStack { Text(label(for: option)) - .foregroundStyle(Color.flixyTextPrimary) + .foregroundStyle(Color.haloTextPrimary) if let detail { Text(detail) - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextMuted) + .font(.haloCaption) + .foregroundStyle(Color.haloTextMuted) } Spacer() if option == model.quality { diff --git a/Flixy/Views/Player/TrackPickerSheet.swift b/Halo/Views/Player/TrackPickerSheet.swift similarity index 94% rename from Flixy/Views/Player/TrackPickerSheet.swift rename to Halo/Views/Player/TrackPickerSheet.swift index 046dc0d..b91477e 100644 --- a/Flixy/Views/Player/TrackPickerSheet.swift +++ b/Halo/Views/Player/TrackPickerSheet.swift @@ -1,6 +1,6 @@ import SwiftUI -import FlixyDesign -import FlixyPlayback +import HaloDesign +import HaloPlayback import MediaKit /// Auswahl einer Spur — Ton **oder** Untertitel, nicht beides. @@ -27,7 +27,7 @@ struct TrackPickerSheet: View { let kind: Kind @Environment(\.dismiss) private var dismiss - @Environment(\.flixyAccent) private var accent + @Environment(\.haloAccent) private var accent var body: some View { NavigationStack { @@ -68,7 +68,7 @@ struct TrackPickerSheet: View { } label: { Label("player.forgetRememberedTrack", systemImage: "arrow.uturn.backward") } - .listRowBackground(Color.flixySurface) + .listRowBackground(Color.haloSurface) } header: { Text("player.rememberedTrack") } footer: { @@ -121,23 +121,23 @@ struct TrackPickerSheet: View { } } .scrollContentBackground(.hidden) - .background(Color.flixyCanvas) + .background(Color.haloCanvas) .navigationTitle(Text(kind.title)) - .flixyInlineTitle() + .haloInlineTitle() .toolbar { ToolbarItem(placement: .confirmationAction) { Button("action.close") { dismiss() } } } } - .flixyMediumSheet() + .haloMediumSheet() } private func row(title: String, isSelected: Bool, action: @escaping () -> Void) -> some View { Button(action: action) { HStack { Text(title) - .foregroundStyle(Color.flixyTextPrimary) + .foregroundStyle(Color.haloTextPrimary) Spacer() if isSelected { Image(systemName: "checkmark").foregroundStyle(accent) @@ -146,7 +146,7 @@ struct TrackPickerSheet: View { .contentShape(.rect) } .buttonStyle(.plain) - .listRowBackground(Color.flixySurface) + .listRowBackground(Color.haloSurface) .accessibilityAddTraits(isSelected ? [.isButton, .isSelected] : .isButton) } } diff --git a/Flixy/Views/Player/VideoSurface.swift b/Halo/Views/Player/VideoSurface.swift similarity index 99% rename from Flixy/Views/Player/VideoSurface.swift rename to Halo/Views/Player/VideoSurface.swift index b463756..60b2386 100644 --- a/Flixy/Views/Player/VideoSurface.swift +++ b/Halo/Views/Player/VideoSurface.swift @@ -1,6 +1,6 @@ import AVKit import SwiftUI -import FlixyPlayback +import HaloPlayback #if canImport(UIKit) import UIKit #else diff --git a/Flixy/Views/Search/SearchView.swift b/Halo/Views/Search/SearchView.swift similarity index 82% rename from Flixy/Views/Search/SearchView.swift rename to Halo/Views/Search/SearchView.swift index 2aacb21..4b48fac 100644 --- a/Flixy/Views/Search/SearchView.swift +++ b/Halo/Views/Search/SearchView.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign import MediaKit /// Sucht über alle Mediatheken des Servers. @@ -8,7 +8,7 @@ import MediaKit /// `SearchFeed`, weil der Fernseher dieselben Fragen an denselben Server /// stellt. Siehe dort, warum das kein Beiwerk ist. struct SearchView: View { - @Environment(FlixySession.self) private var session + @Environment(HaloSession.self) private var session @State private var text = "" @State private var feed = SearchFeed() @@ -23,9 +23,9 @@ struct SearchView: View { results } } - .background(Color.flixyCanvas) + .background(Color.haloCanvas) .navigationTitle(Text("search.title")) - .flixyInlineTitle() + .haloInlineTitle() .searchable(text: $text) // Jeder Tastendruck löst eine Anfrage aus — aber erst nach einer // kurzen Pause. Ohne sie schickt „Blade Runner" zwölf Anfragen los, @@ -35,12 +35,12 @@ struct SearchView: View { // in der Suche nicht, und deshalb wirkte „als gesehen markieren" aus // dem Kontextmenü zwar am Server, aber die Kachel lud nie neu — es sah // aus, als wäre nichts passiert. - .environment(\.flixyItemChanged, { await feed.search(text, from: session.backend) }) + .environment(\.haloItemChanged, { await feed.search(text, from: session.backend) }) } private var results: some View { ScrollView { - LazyVStack(alignment: .leading, spacing: FlixySpacing.section) { + LazyVStack(alignment: .leading, spacing: HaloSpacing.section) { ForEach(feed.hubs) { hub in // **Antippen führt auf die Seite, nicht in den Film.** Die // Suche benutzt dieselbe Reihe wie die Startseite — und @@ -51,9 +51,9 @@ struct SearchView: View { MediaRow(row: hub, opensDetails: true) } } - .padding(.vertical, FlixySpacing.loose) + .padding(.vertical, HaloSpacing.loose) } - .flixyRevealsTopChrome() + .haloRevealsTopChrome() } @ViewBuilder @@ -72,7 +72,7 @@ struct SearchView: View { text = entry } label: { Label(entry, systemImage: "clock.arrow.circlepath") - .foregroundStyle(Color.flixyTextSecondary) + .foregroundStyle(Color.haloTextSecondary) } } } header: { @@ -81,12 +81,12 @@ struct SearchView: View { Button("search.forgetRecent", role: .destructive) { feed.forgetRecent() } - .font(.flixyCaption) + .font(.haloCaption) } - .listRowBackground(Color.flixySurface) + .listRowBackground(Color.haloSurface) } .scrollContentBackground(.hidden) - .flixyRevealsTopChrome() + .haloRevealsTopChrome() } } } diff --git a/Flixy/Views/Settings/AppearanceView.swift b/Halo/Views/Settings/AppearanceView.swift similarity index 78% rename from Flixy/Views/Settings/AppearanceView.swift rename to Halo/Views/Settings/AppearanceView.swift index d138b49..d797e36 100644 --- a/Flixy/Views/Settings/AppearanceView.swift +++ b/Halo/Views/Settings/AppearanceView.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign /// Die Farbeinstellungen. /// @@ -8,22 +8,22 @@ import FlixyDesign /// Farbe greift die Kontrastkorrektur — und sagt es auch, statt die Farbe /// stillschweigend zu verändern. struct AppearanceView: View { - @Environment(FlixyTheme.self) private var theme + @Environment(HaloTheme.self) private var theme @Environment(HomeLayoutSettings.self) private var layout @State private var customHex: String = "" @State private var showsCustomField = false - private let columns = [GridItem(.adaptive(minimum: 64), spacing: FlixySpacing.regular)] + private let columns = [GridItem(.adaptive(minimum: 64), spacing: HaloSpacing.regular)] var body: some View { Form { Section { - LazyVGrid(columns: columns, spacing: FlixySpacing.regular) { + LazyVGrid(columns: columns, spacing: HaloSpacing.regular) { ForEach(AccentOption.palette) { option in swatch(option) } } - .padding(.vertical, FlixySpacing.snug) + .padding(.vertical, HaloSpacing.snug) } header: { Text("appearance.accent") } footer: { @@ -38,7 +38,7 @@ struct AppearanceView: View { LabeledContent { Text(layout.cardScale.formatted(.percent.precision(.fractionLength(0)))) - .foregroundStyle(Color.flixyTextSecondary) + .foregroundStyle(Color.haloTextSecondary) .monospacedDigit() } label: { Text("appearance.cardScale") @@ -52,7 +52,7 @@ struct AppearanceView: View { } footer: { Text("appearance.cardScaleExplanation") } - .listRowBackground(Color.flixySurface) + .listRowBackground(Color.haloSurface) Section { Toggle("appearance.customColor", isOn: $showsCustomField.animation(.snappy)) @@ -60,7 +60,7 @@ struct AppearanceView: View { if showsCustomField { HStack { TextField("appearance.hexPlaceholder", text: $customHex) - .flixyPlainEntry() + .haloPlainEntry() .onSubmit(applyCustomColor) Button("action.apply", action: applyCustomColor) @@ -69,8 +69,8 @@ struct AppearanceView: View { if !customHex.isEmpty, RGB(string: customHex) == nil { Text("appearance.invalidHex") - .font(.flixyCaption) - .foregroundStyle(Color.flixyDestructive) + .font(.haloCaption) + .foregroundStyle(Color.haloDestructive) } } @@ -80,11 +80,11 @@ struct AppearanceView: View { // als im Farbwähler, und niemand wüsste warum. Label { Text("appearance.adjusted \(theme.accent.hexString)") - .font(.flixyCaption) + .font(.haloCaption) } icon: { Image(systemName: "info.circle") } - .foregroundStyle(Color.flixyTextSecondary) + .foregroundStyle(Color.haloTextSecondary) } } @@ -92,11 +92,11 @@ struct AppearanceView: View { PreviewRow() } } - .flixyForm() + .haloForm() .scrollContentBackground(.hidden) - .background(Color.flixyCanvas) + .background(Color.haloCanvas) .navigationTitle(Text("appearance.title")) - .flixyInlineTitle() + .haloInlineTitle() .onAppear { if theme.selection.id == AccentOption.customIdentifier { customHex = theme.selection.color.hexString @@ -119,13 +119,13 @@ struct AppearanceView: View { // Dunkel auf der Farbe, nicht weiß: die Palette // enthält helle Töne wie Amber, auf denen Weiß // verschwinden würde. - .foregroundStyle(Color.flixyCanvas) + .foregroundStyle(Color.haloCanvas) } } .overlay { Circle() .strokeBorder( - theme.selection == option ? Color.flixyTextPrimary : .clear, + theme.selection == option ? Color.haloTextPrimary : .clear, lineWidth: 2 ) .padding(-4) @@ -144,27 +144,27 @@ struct AppearanceView: View { /// Zeigt die gewählte Farbe an den Stellen, an denen sie später auftaucht. private struct PreviewRow: View { - @Environment(\.flixyAccent) private var accent + @Environment(\.haloAccent) private var accent var body: some View { - VStack(alignment: .leading, spacing: FlixySpacing.regular) { - HStack(spacing: FlixySpacing.regular) { + VStack(alignment: .leading, spacing: HaloSpacing.regular) { + HStack(spacing: HaloSpacing.regular) { Label("hero.play", systemImage: "play.fill") - .font(.flixyCardTitle) - .padding(.horizontal, FlixySpacing.loose) - .padding(.vertical, FlixySpacing.snug) - .background(accent, in: .rect(cornerRadius: FlixyRadius.control)) - .foregroundStyle(Color.flixyCanvas) + .font(.haloCardTitle) + .padding(.horizontal, HaloSpacing.loose) + .padding(.vertical, HaloSpacing.snug) + .background(accent, in: .rect(cornerRadius: HaloRadius.control)) + .foregroundStyle(Color.haloCanvas) Label("sidebar.downloads", systemImage: "arrow.down.circle") - .font(.flixyCardTitle) + .font(.haloCardTitle) .foregroundStyle(accent) } WatchProgressBar(fraction: 0.45) } - .padding(.vertical, FlixySpacing.snug) - .listRowBackground(Color.flixySurface) + .padding(.vertical, HaloSpacing.snug) + .listRowBackground(Color.haloSurface) } } diff --git a/Flixy/Views/Settings/AudioLanguagePicker.swift b/Halo/Views/Settings/AudioLanguagePicker.swift similarity index 86% rename from Flixy/Views/Settings/AudioLanguagePicker.swift rename to Halo/Views/Settings/AudioLanguagePicker.swift index f2661f7..8785ab4 100644 --- a/Flixy/Views/Settings/AudioLanguagePicker.swift +++ b/Halo/Views/Settings/AudioLanguagePicker.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign /// „Welche Tonsprache gilt hier?" — an genau zwei Orten dieselbe Frage. /// @@ -23,15 +23,15 @@ struct AudioLanguagePicker: View { let title: LocalizedStringKey @Environment(LanguagePreferences.self) private var languages - @Environment(\.flixyAccent) private var accent + @Environment(\.haloAccent) private var accent var body: some View { - HStack(spacing: FlixySpacing.regular) { + HStack(spacing: HaloSpacing.regular) { Text(title) - .font(.flixyBody) - .foregroundStyle(Color.flixyTextPrimary) + .font(.haloBody) + .foregroundStyle(Color.haloTextPrimary) - Spacer(minLength: FlixySpacing.regular) + Spacer(minLength: HaloSpacing.regular) Menu { // „Wie allgemein" zuerst und als Vorgabe: die meisten Ebenen @@ -53,11 +53,11 @@ struct AudioLanguagePicker: View { } } } label: { - HStack(spacing: FlixySpacing.tight) { + HStack(spacing: HaloSpacing.tight) { Text(currentLabel) - .font(.flixyBody) + .font(.haloBody) Image(systemName: "chevron.up.chevron.down") - .font(.flixyCaption) + .font(.haloCaption) } .foregroundStyle(accent) } diff --git a/Flixy/Views/Settings/DiagnosticsView.swift b/Halo/Views/Settings/DiagnosticsView.swift similarity index 83% rename from Flixy/Views/Settings/DiagnosticsView.swift rename to Halo/Views/Settings/DiagnosticsView.swift index 8524347..cc2e7d6 100644 --- a/Flixy/Views/Settings/DiagnosticsView.swift +++ b/Halo/Views/Settings/DiagnosticsView.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign /// Was beim letzten Abspielversuch passiert ist. /// @@ -7,8 +7,8 @@ import FlixyDesign /// wurde, über welche Verbindung, und wie lange jeder Schritt gedauert hat. /// Ein Screenshot davon sagt mehr als jede Beschreibung. struct DiagnosticsView: View { - @Environment(FlixySession.self) private var session - @Environment(\.flixyAccent) private var accent + @Environment(HaloSession.self) private var session + @Environment(\.haloAccent) private var accent @Environment(PlaybackDiagnostics.self) private var diagnostics var body: some View { Form { @@ -17,14 +17,14 @@ struct DiagnosticsView: View { LabeledContent("settings.serverName", value: session.serverName) if let address = session.serverAddress { LabeledContent("settings.address", value: address) - .font(.flixyCaption) + .font(.haloCaption) } if let beschreibung = session.connectionDescription { LabeledContent("settings.connection", value: beschreibung) - .font(.flixyCaption) + .font(.haloCaption) } } else { - Text("diagnostics.noServer").foregroundStyle(Color.flixyTextMuted) + Text("diagnostics.noServer").foregroundStyle(Color.haloTextMuted) } } @@ -36,11 +36,11 @@ struct DiagnosticsView: View { VStack(alignment: .leading, spacing: 2) { Text("diagnostics.source") - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextMuted) + .font(.haloCaption) + .foregroundStyle(Color.haloTextMuted) Text(attempt.sourceDescription) .font(.system(.caption2, design: .monospaced)) - .foregroundStyle(Color.flixyTextSecondary) + .foregroundStyle(Color.haloTextSecondary) } } @@ -48,13 +48,13 @@ struct DiagnosticsView: View { ForEach(Array(attempt.steps.enumerated()), id: \.offset) { _, step in Text(step) .font(.system(.caption, design: .monospaced)) - .foregroundStyle(Color.flixyTextSecondary) + .foregroundStyle(Color.haloTextSecondary) } } Section { Button { - FlixyClipboard.copy(report(for: attempt)) + HaloClipboard.copy(report(for: attempt)) } label: { Label("diagnostics.copy", systemImage: "doc.on.doc") } @@ -63,7 +63,7 @@ struct DiagnosticsView: View { } } else { Section("diagnostics.lastAttempt") { - Text("diagnostics.nothingYet").foregroundStyle(Color.flixyTextMuted) + Text("diagnostics.nothingYet").foregroundStyle(Color.haloTextMuted) } } @@ -79,11 +79,11 @@ struct DiagnosticsView: View { // gehen können — sichtbar an Picker-Werten, die in der Standardfarbe // leuchteten, während die Schalter daneben schon die gewählte trugen. .tint(accent) - .flixyForm() + .haloForm() .scrollContentBackground(.hidden) - .background(Color.flixyCanvas) + .background(Color.haloCanvas) .navigationTitle(Text("diagnostics.title")) - .flixyInlineTitle() + .haloInlineTitle() } /// Der Bericht als Text zum Weitergeben. @@ -92,7 +92,7 @@ struct DiagnosticsView: View { /// Abfrageteil abgelegt, und der Servername verrät nichts Vertrauliches. private func report(for attempt: PlaybackDiagnostics.Attempt) -> String { """ - Flixy \(Branding.version) · Build \(Branding.buildStamp) + Halo \(Branding.version) · Build \(Branding.buildStamp) Verbindung: \(attempt.connection) Titel: \(attempt.title) Weg: \(attempt.method) diff --git a/Flixy/Views/Settings/DownloadSettingsView.swift b/Halo/Views/Settings/DownloadSettingsView.swift similarity index 95% rename from Flixy/Views/Settings/DownloadSettingsView.swift rename to Halo/Views/Settings/DownloadSettingsView.swift index 0aceb49..5ecffb9 100644 --- a/Flixy/Views/Settings/DownloadSettingsView.swift +++ b/Halo/Views/Settings/DownloadSettingsView.swift @@ -1,6 +1,6 @@ import SwiftUI -import FlixyDesign -import FlixyDownloads +import HaloDesign +import HaloDownloads import MediaKit /// Was beim Herunterladen gilt. @@ -11,7 +11,7 @@ import MediaKit /// rutschen. struct DownloadSettingsView: View { @Environment(DownloadCoordinator.self) private var downloads - @Environment(\.flixyAccent) private var accent + @Environment(\.haloAccent) private var accent var body: some View { @Bindable var downloads = downloads @@ -73,11 +73,11 @@ struct DownloadSettingsView: View { } } .tint(accent) - .flixyForm() + .haloForm() .scrollContentBackground(.hidden) - .background(Color.flixyCanvas) + .background(Color.haloCanvas) .navigationTitle(Text("sidebar.downloads")) - .flixyInlineTitle() + .haloInlineTitle() } private var storageLimitBinding: Binding { diff --git a/Flixy/Views/Settings/HomeLayoutView.swift b/Halo/Views/Settings/HomeLayoutView.swift similarity index 90% rename from Flixy/Views/Settings/HomeLayoutView.swift rename to Halo/Views/Settings/HomeLayoutView.swift index a3b569d..018c986 100644 --- a/Flixy/Views/Settings/HomeLayoutView.swift +++ b/Halo/Views/Settings/HomeLayoutView.swift @@ -1,11 +1,11 @@ import SwiftUI -import FlixyDesign +import HaloDesign import MediaKit /// Reihen der Startseite ein- und ausblenden und umsortieren. struct HomeLayoutView: View { - @Environment(FlixySession.self) private var session - @Environment(\.flixyAccent) private var accent + @Environment(HaloSession.self) private var session + @Environment(\.haloAccent) private var accent @Environment(HomeLayoutSettings.self) private var layout @State private var rows: [HomeRow] = [] @@ -21,9 +21,9 @@ struct HomeLayoutView: View { var body: some View { list - .background(Color.flixyCanvas) + .background(Color.haloCanvas) .navigationTitle(Text("homeLayout.title")) - .flixyInlineTitle() + .haloInlineTitle() .task { await load() } } @@ -48,7 +48,7 @@ struct HomeLayoutView: View { // gerade so weit hereinlugt, wie man es mag. LabeledContent { Text(layout.heroHeight.formatted(.percent.precision(.fractionLength(0)))) - .foregroundStyle(Color.flixyTextSecondary) + .foregroundStyle(Color.haloTextSecondary) .monospacedDigit() } label: { Text("home.heroHeight") @@ -64,7 +64,7 @@ struct HomeLayoutView: View { } footer: { Text("home.heroExplanation") } - .listRowBackground(Color.flixySurface) + .listRowBackground(Color.haloSurface) // **Mehrfachauswahl, und leer heisst alle.** Ein `Picker` könnte // nur eine Mediathek, und „keine" wäre dort ein eigener Eintrag, @@ -84,7 +84,7 @@ struct HomeLayoutView: View { } } label: { Text(library.title) - .foregroundStyle(Color.flixyTextPrimary) + .foregroundStyle(Color.haloTextPrimary) } // Damit der ganze Streifen trifft und nicht nur // die Schrift — eine Zeile, bei der nur ein Wort @@ -99,7 +99,7 @@ struct HomeLayoutView: View { } header: { Text("home.heroLibraries") } footer: { - VStack(alignment: .leading, spacing: FlixySpacing.snug) { + VStack(alignment: .leading, spacing: HaloSpacing.snug) { Text("home.heroLibrariesExplanation") // Lieber eine Erklärung als ein Aufmacher, der // heimlich etwas anderes zeigt: trifft die Auswahl @@ -107,18 +107,18 @@ struct HomeLayoutView: View { // dann muss dastehen, warum. if greiftInsLeere { Text("home.heroLibrariesNoMatch") - .foregroundStyle(Color.flixyDestructive) + .foregroundStyle(Color.haloDestructive) } } } - .listRowBackground(Color.flixySurface) + .listRowBackground(Color.haloSurface) } Section { Toggle("home.combineContinue", isOn: $layout.combinesContinueRows) Toggle("home.hideWatched", isOn: $layout.hidesWatchedInLatest) } - .listRowBackground(Color.flixySurface) + .listRowBackground(Color.haloSurface) if isLoading { ProgressView() @@ -126,8 +126,8 @@ struct HomeLayoutView: View { .listRowBackground(Color.clear) } else if rows.isEmpty { Text("homeLayout.empty") - .foregroundStyle(Color.flixyTextSecondary) - .listRowBackground(Color.flixySurface) + .foregroundStyle(Color.haloTextSecondary) + .listRowBackground(Color.haloSurface) } Section { @@ -140,9 +140,9 @@ struct HomeLayoutView: View { } )) { Text(row.title) - .foregroundStyle(Color.flixyTextPrimary) + .foregroundStyle(Color.haloTextPrimary) } - .listRowBackground(Color.flixySurface) + .listRowBackground(Color.haloSurface) } .onMove { indices, destination in rows.move(fromOffsets: indices, toOffset: destination) @@ -162,7 +162,7 @@ struct HomeLayoutView: View { if !rows.isEmpty { Spacer() EditButton() - .font(.flixyCaption) + .font(.haloCaption) .textCase(nil) } #endif diff --git a/Flixy/Views/Settings/LanguagesView.swift b/Halo/Views/Settings/LanguagesView.swift similarity index 90% rename from Flixy/Views/Settings/LanguagesView.swift rename to Halo/Views/Settings/LanguagesView.swift index 65a7d11..6777fd3 100644 --- a/Flixy/Views/Settings/LanguagesView.swift +++ b/Halo/Views/Settings/LanguagesView.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign /// Welche Sprachen der Player von sich aus wählen soll. /// @@ -9,7 +9,7 @@ import FlixyDesign /// Vorliebe, die niemand äußern kann, ist keine. struct LanguagesView: View { @Environment(LanguagePreferences.self) private var settings - @Environment(\.flixyAccent) private var accent + @Environment(\.haloAccent) private var accent @State private var isAdding = false @@ -61,11 +61,11 @@ struct LanguagesView: View { } } .tint(accent) - .flixyForm() + .haloForm() .scrollContentBackground(.hidden) - .background(Color.flixyCanvas) + .background(Color.haloCanvas) .navigationTitle(Text("languages.title")) - .flixyInlineTitle() + .haloInlineTitle() // Eine Rangliste ohne Umsortieren wäre keine. Auf dem iPhone braucht // das Ziehen den Bearbeitungsmodus nicht — `onMove` in einer `Form` // genügt, sobald die Liste bearbeitbar ist. @@ -86,19 +86,19 @@ struct LanguagesView: View { Section { if settings.fallbacks.isEmpty { Text("languages.fallbackEmpty") - .foregroundStyle(Color.flixyTextSecondary) + .foregroundStyle(Color.haloTextSecondary) } else { ForEach(Array(settings.fallbacks.enumerated()), id: \.element) { position, code in - HStack(spacing: FlixySpacing.regular) { + HStack(spacing: HaloSpacing.regular) { // Die Nummer, weil die Reihenfolge der ganze Zweck // ist — eine Liste ohne sichtbaren Rang liest sich // wie eine Menge. Text("\(position + 1)") - .font(.flixyCaption.monospacedDigit()) - .foregroundStyle(Color.flixyTextSecondary) + .font(.haloCaption.monospacedDigit()) + .foregroundStyle(Color.haloTextSecondary) .frame(minWidth: 18, alignment: .trailing) Text(name(of: code)) - .foregroundStyle(Color.flixyTextPrimary) + .foregroundStyle(Color.haloTextPrimary) } } .onMove { von, nach in diff --git a/Flixy/Views/Settings/PlaybackSettingsView.swift b/Halo/Views/Settings/PlaybackSettingsView.swift similarity index 93% rename from Flixy/Views/Settings/PlaybackSettingsView.swift rename to Halo/Views/Settings/PlaybackSettingsView.swift index d9d714e..cbee23b 100644 --- a/Flixy/Views/Settings/PlaybackSettingsView.swift +++ b/Halo/Views/Settings/PlaybackSettingsView.swift @@ -1,6 +1,6 @@ import SwiftUI -import FlixyDesign -import FlixyPlayback +import HaloDesign +import HaloPlayback /// Alles, was die Wiedergabe betrifft. /// @@ -9,7 +9,7 @@ import FlixyPlayback /// einmal durchgeht und dann in Ruhe lässt. struct PlaybackSettingsView: View { @Environment(PlaybackSettings.self) private var settings - @Environment(\.flixyAccent) private var accent + @Environment(\.haloAccent) private var accent var body: some View { @Bindable var settings = settings @@ -36,7 +36,7 @@ struct PlaybackSettingsView: View { } header: { Text("settings.quality") } footer: { - VStack(alignment: .leading, spacing: FlixySpacing.snug) { + VStack(alignment: .leading, spacing: HaloSpacing.snug) { Text("settings.qualityExplanation") // **Nur mit Beleg.** Eine Warnung, die immer dasteht, @@ -55,8 +55,8 @@ struct PlaybackSettingsView: View { } icon: { Image(systemName: "exclamationmark.triangle") } - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextSecondary) + .font(.haloCaption) + .foregroundStyle(Color.haloTextSecondary) } } } @@ -108,11 +108,11 @@ struct PlaybackSettingsView: View { } } .tint(accent) - .flixyForm() + .haloForm() .scrollContentBackground(.hidden) - .background(Color.flixyCanvas) + .background(Color.haloCanvas) .navigationTitle(Text("settings.playback")) - .flixyInlineTitle() + .haloInlineTitle() } private func rateLabel(_ rate: Double) -> String { diff --git a/Flixy/Views/Settings/ServerSettingsView.swift b/Halo/Views/Settings/ServerSettingsView.swift similarity index 90% rename from Flixy/Views/Settings/ServerSettingsView.swift rename to Halo/Views/Settings/ServerSettingsView.swift index c39ff40..12e279f 100644 --- a/Flixy/Views/Settings/ServerSettingsView.swift +++ b/Halo/Views/Settings/ServerSettingsView.swift @@ -1,11 +1,11 @@ import SwiftUI -import FlixyDesign +import HaloDesign import MediaKit /// Mit welchem Server gesprochen wird — und was er gerade anbietet. struct ServerSettingsView: View { - @Environment(FlixySession.self) private var session - @Environment(\.flixyAccent) private var accent + @Environment(HaloSession.self) private var session + @Environment(\.haloAccent) private var accent var body: some View { Form { @@ -19,7 +19,7 @@ struct ServerSettingsView: View { } if let address = session.serverAddress { LabeledContent("settings.address", value: address) - .font(.flixyCaption) + .font(.haloCaption) .textSelection(.enabled) } if let accountName = session.accountName { @@ -44,11 +44,11 @@ struct ServerSettingsView: View { } } .tint(accent) - .flixyForm() + .haloForm() .scrollContentBackground(.hidden) - .background(Color.flixyCanvas) + .background(Color.haloCanvas) .navigationTitle(Text("settings.server")) - .flixyInlineTitle() + .haloInlineTitle() } /// Zeigt, ob der Server im selben Netz steht — beim Suchen nach Ruckeln @@ -64,20 +64,20 @@ struct ServerSettingsView: View { struct LibraryRow: View { let library: MediaLibrary - @Environment(FlixySession.self) private var session - @Environment(\.flixyAccent) private var accent + @Environment(HaloSession.self) private var session + @Environment(\.haloAccent) private var accent @State private var phase: Phase = .idle private enum Phase { case idle, running, done } var body: some View { LabeledContent { - HStack(spacing: FlixySpacing.regular) { + HStack(spacing: HaloSpacing.regular) { // Nur, wenn es nicht dasselbe Wort ist: eine Mediathek namens // „Filme" stand sonst als „Filme — Filme" da. if library.title.localizedCaseInsensitiveCompare(library.kind.label) != .orderedSame { Text(library.kind.label) - .foregroundStyle(Color.flixyTextSecondary) + .foregroundStyle(Color.haloTextSecondary) } if session.backend?.capabilities.contains(.libraryScan) == true { diff --git a/Flixy/Views/Settings/SettingsChrome.swift b/Halo/Views/Settings/SettingsChrome.swift similarity index 84% rename from Flixy/Views/Settings/SettingsChrome.swift rename to Halo/Views/Settings/SettingsChrome.swift index 4c76ecc..c78a569 100644 --- a/Flixy/Views/Settings/SettingsChrome.swift +++ b/Halo/Views/Settings/SettingsChrome.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign /// Das farbige Symbol vor einer Einstellungszeile. /// @@ -35,7 +35,7 @@ struct SettingsHeader: View { let explanation: LocalizedStringKey var body: some View { - VStack(alignment: .leading, spacing: FlixySpacing.regular) { + VStack(alignment: .leading, spacing: HaloSpacing.regular) { Image(systemName: symbol) .font(.title2.weight(.semibold)) .foregroundStyle(.white) @@ -43,16 +43,16 @@ struct SettingsHeader: View { .background(colour.gradient, in: .rect(cornerRadius: 13)) Text(title) - .font(.flixyTitle) - .foregroundStyle(Color.flixyTextPrimary) + .font(.haloTitle) + .foregroundStyle(Color.haloTextPrimary) Text(explanation) - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextSecondary) + .font(.haloCaption) + .foregroundStyle(Color.haloTextSecondary) } .frame(maxWidth: .infinity, alignment: .leading) - .padding(.vertical, FlixySpacing.snug) - .listRowBackground(Color.flixySurface) + .padding(.vertical, HaloSpacing.snug) + .listRowBackground(Color.haloSurface) } } diff --git a/Flixy/Views/Settings/SettingsView.swift b/Halo/Views/Settings/SettingsView.swift similarity index 92% rename from Flixy/Views/Settings/SettingsView.swift rename to Halo/Views/Settings/SettingsView.swift index 4927632..49a0299 100644 --- a/Flixy/Views/Settings/SettingsView.swift +++ b/Halo/Views/Settings/SettingsView.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign /// Die Einstellungen — als Übersicht, nicht als eine lange Liste. /// @@ -10,8 +10,8 @@ import FlixyDesign /// /// Jetzt führt jede Zeile in einen Bildschirm, der zu **einer** Frage gehört. struct SettingsView: View { - @Environment(FlixySession.self) private var session - @Environment(\.flixyAccent) private var accent + @Environment(HaloSession.self) private var session + @Environment(\.haloAccent) private var accent @State private var showsSignOutConfirmation = false var body: some View { @@ -23,7 +23,7 @@ struct SettingsView: View { } label: { LabeledContent { Text(session.serverName) - .foregroundStyle(Color.flixyTextSecondary) + .foregroundStyle(Color.haloTextSecondary) } label: { row( "settings.server", @@ -83,12 +83,12 @@ struct SettingsView: View { // gehen können — sichtbar an Picker-Werten, die in der Standardfarbe // leuchteten, während die Schalter daneben schon die gewählte trugen. .tint(accent) - .flixyForm() + .haloForm() .scrollContentBackground(.hidden) - .flixyRevealsTopChrome() - .background(Color.flixyCanvas) + .haloRevealsTopChrome() + .background(Color.haloCanvas) .navigationTitle(Text("sidebar.settings")) - .flixyInlineTitle() + .haloInlineTitle() .confirmationDialog( Text("settings.signOutConfirm"), isPresented: $showsSignOutConfirmation, @@ -115,7 +115,7 @@ struct SettingsView: View { } private func row(_ title: LocalizedStringKey, symbol: String, colour: Color) -> some View { - HStack(spacing: FlixySpacing.regular) { + HStack(spacing: HaloSpacing.regular) { SettingsIcon(symbol: symbol, colour: colour) Text(title) } diff --git a/Flixy/Views/Settings/SubtitleAppearanceView.swift b/Halo/Views/Settings/SubtitleAppearanceView.swift similarity index 92% rename from Flixy/Views/Settings/SubtitleAppearanceView.swift rename to Halo/Views/Settings/SubtitleAppearanceView.swift index 0e80501..ed2d35d 100644 --- a/Flixy/Views/Settings/SubtitleAppearanceView.swift +++ b/Halo/Views/Settings/SubtitleAppearanceView.swift @@ -1,11 +1,11 @@ import SwiftUI -import FlixyDesign -import FlixyPlayback +import HaloDesign +import HaloPlayback /// Wie Untertitel aussehen sollen. struct SubtitleAppearanceView: View { @Environment(SubtitleAppearance.self) private var appearance - @Environment(\.flixyAccent) private var accent + @Environment(\.haloAccent) private var accent var body: some View { @Bindable var appearance = appearance @@ -51,11 +51,11 @@ struct SubtitleAppearanceView: View { } } .tint(accent) - .flixyForm() + .haloForm() .scrollContentBackground(.hidden) - .background(Color.flixyCanvas) + .background(Color.haloCanvas) .navigationTitle(Text("subtitleStyle.title")) - .flixyInlineTitle() + .haloInlineTitle() } /// Ein Beispielsatz über grauer Fläche. @@ -84,10 +84,10 @@ struct SubtitleAppearanceView: View { radius: 2, y: 1 ) - .padding(FlixySpacing.regular) + .padding(HaloSpacing.regular) } .frame(height: 96) - .clipShape(.rect(cornerRadius: FlixyRadius.card)) + .clipShape(.rect(cornerRadius: HaloRadius.card)) .listRowInsets(EdgeInsets()) .listRowBackground(Color.clear) } diff --git a/Flixy/Views/SignIn/ConnectionStateViews.swift b/Halo/Views/SignIn/ConnectionStateViews.swift similarity index 75% rename from Flixy/Views/SignIn/ConnectionStateViews.swift rename to Halo/Views/SignIn/ConnectionStateViews.swift index 6f9ec8e..ae803c4 100644 --- a/Flixy/Views/SignIn/ConnectionStateViews.swift +++ b/Halo/Views/SignIn/ConnectionStateViews.swift @@ -1,21 +1,21 @@ import SwiftUI -import FlixyDesign +import HaloDesign /// Während ein Weg zum Server gesucht wird. struct ConnectingView: View { let serverName: String var body: some View { - VStack(spacing: FlixySpacing.loose) { + VStack(spacing: HaloSpacing.loose) { ProgressView() Text(serverName.isEmpty ? String(localized: "connecting.searching") : String(localized: "connecting.to \(serverName)")) - .font(.flixyBody) - .foregroundStyle(Color.flixyTextSecondary) + .font(.haloBody) + .foregroundStyle(Color.haloTextSecondary) } .frame(maxWidth: .infinity, maxHeight: .infinity) - .background(Color.flixyCanvas) + .background(Color.haloCanvas) } } @@ -33,8 +33,8 @@ struct ConnectionFailureView: View { } actions: { Button("action.retry", action: onRetry).buttonStyle(.borderedProminent) Button("action.signOut", action: onSignOut) - .foregroundStyle(Color.flixyTextSecondary) + .foregroundStyle(Color.haloTextSecondary) } - .background(Color.flixyCanvas) + .background(Color.haloCanvas) } } diff --git a/Flixy/Views/SignIn/JellyfinSignInView.swift b/Halo/Views/SignIn/JellyfinSignInView.swift similarity index 71% rename from Flixy/Views/SignIn/JellyfinSignInView.swift rename to Halo/Views/SignIn/JellyfinSignInView.swift index 408339b..6272732 100644 --- a/Flixy/Views/SignIn/JellyfinSignInView.swift +++ b/Halo/Views/SignIn/JellyfinSignInView.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign import JellyfinKit /// Die Anmeldung an einem Jellyfin-Server. @@ -9,9 +9,9 @@ import JellyfinKit /// diesen Code. Der Weg über den Code steht vorn, weil dabei kein Passwort /// durch diese App läuft. struct JellyfinSignInView: View { - @Environment(FlixySession.self) private var session + @Environment(HaloSession.self) private var session @Environment(\.dismiss) private var dismiss - @Environment(\.flixyAccent) private var accent + @Environment(\.haloAccent) private var accent @State private var model: JellyfinSignInModel? @FocusState private var focusedField: Field? @@ -23,16 +23,16 @@ struct JellyfinSignInView: View { ScrollView { if let model { content(for: model) - .padding(.horizontal, FlixySpacing.section) - .padding(.vertical, FlixySpacing.section) + .padding(.horizontal, HaloSpacing.section) + .padding(.vertical, HaloSpacing.section) .frame(maxWidth: 420) .frame(maxWidth: .infinity) } } .scrollDismissesKeyboard(.interactively) - .background(Color.flixyCanvas) + .background(Color.haloCanvas) .navigationTitle(Text("signIn.jellyfin.title")) - .flixyInlineTitle() + .haloInlineTitle() .toolbar { ToolbarItem(placement: .cancellationAction) { Button("action.cancel") { @@ -66,7 +66,7 @@ struct JellyfinSignInView: View { private func content(for model: JellyfinSignInModel) -> some View { @Bindable var model = model - VStack(alignment: .leading, spacing: FlixySpacing.section) { + VStack(alignment: .leading, spacing: HaloSpacing.section) { switch model.step { case .address: addressStep(model: model) @@ -82,8 +82,8 @@ struct JellyfinSignInView: View { if let message = model.errorMessage { Label(message, systemImage: "exclamationmark.triangle") - .font(.flixyCaption) - .foregroundStyle(Color.flixyDestructive) + .font(.haloCaption) + .foregroundStyle(Color.haloDestructive) } } } @@ -94,39 +94,39 @@ struct JellyfinSignInView: View { private func addressStep(model: JellyfinSignInModel) -> some View { @Bindable var model = model - VStack(alignment: .leading, spacing: FlixySpacing.regular) { + VStack(alignment: .leading, spacing: HaloSpacing.regular) { Text("signIn.jellyfin.addressPrompt") - .font(.flixyRowHeader) - .foregroundStyle(Color.flixyTextPrimary) + .font(.haloRowHeader) + .foregroundStyle(Color.haloTextPrimary) TextField("signIn.jellyfin.addressPlaceholder", text: $model.address) .textFieldStyle(.plain) .textContentType(.URL) - .flixyPlainEntry(isAddress: true) + .haloPlainEntry(isAddress: true) .submitLabel(.go) .focused($focusedField, equals: .address) .onSubmit { Task { await model.findServer() } } // Hier statt beim Öffnen des Sheets: so bekommt das Feld den // Fokus auch dann, wenn man nach einem Vertipper zurückkommt. .task { focusedField = .address } - .padding(FlixySpacing.regular) - .background(Color.flixyElevated, in: .rect(cornerRadius: FlixyRadius.control)) - .foregroundStyle(Color.flixyTextPrimary) + .padding(HaloSpacing.regular) + .background(Color.haloElevated, in: .rect(cornerRadius: HaloRadius.control)) + .foregroundStyle(Color.haloTextPrimary) // Ein Beispiel statt einer Erklärung: „Schema, Host, Port" sagt // niemandem etwas, „192.168.1.50" jedem. Text("signIn.jellyfin.addressHint") - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextMuted) + .font(.haloCaption) + .foregroundStyle(Color.haloTextMuted) Button { focusedField = nil Task { await model.findServer() } } label: { Text("signIn.jellyfin.connect") - .font(.flixyRowHeader) + .font(.haloRowHeader) .frame(maxWidth: .infinity) - .padding(.vertical, FlixySpacing.regular) + .padding(.vertical, HaloSpacing.regular) } .buttonStyle(.borderedProminent) .tint(accent) @@ -138,40 +138,40 @@ struct JellyfinSignInView: View { @ViewBuilder private func quickConnectStep(model: JellyfinSignInModel, code: String) -> some View { - VStack(alignment: .leading, spacing: FlixySpacing.regular) { + VStack(alignment: .leading, spacing: HaloSpacing.regular) { foundServerHeader(model: model) Text("signIn.jellyfin.quickConnectHint") - .font(.flixyBody) - .foregroundStyle(Color.flixyTextSecondary) + .font(.haloBody) + .foregroundStyle(Color.haloTextSecondary) Text(code) .font(.system(.largeTitle, design: .monospaced, weight: .semibold)) .tracking(8) - .foregroundStyle(Color.flixyTextPrimary) + .foregroundStyle(Color.haloTextPrimary) .textSelection(.enabled) - .padding(.vertical, FlixySpacing.regular) + .padding(.vertical, HaloSpacing.regular) .frame(maxWidth: .infinity) - .background(Color.flixyElevated, in: .rect(cornerRadius: FlixyRadius.control)) + .background(Color.haloElevated, in: .rect(cornerRadius: HaloRadius.control)) - HStack(spacing: FlixySpacing.snug) { + HStack(spacing: HaloSpacing.snug) { ProgressView().controlSize(.small) Text("signIn.jellyfin.waitingForApproval") - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextMuted) + .font(.haloCaption) + .foregroundStyle(Color.haloTextMuted) } Text("signIn.jellyfin.privacy") - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextMuted) + .font(.haloCaption) + .foregroundStyle(Color.haloTextMuted) - Divider().overlay(Color.flixySeparator) + Divider().overlay(Color.haloSeparator) Button("signIn.jellyfin.usePassword") { model.useCredentials() } - .font(.flixyCaption) + .font(.haloCaption) Button("signIn.jellyfin.otherAddress") { model.startOver() } - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextSecondary) + .font(.haloCaption) + .foregroundStyle(Color.haloTextSecondary) } } @@ -181,12 +181,12 @@ struct JellyfinSignInView: View { private func credentialsStep(model: JellyfinSignInModel) -> some View { @Bindable var model = model - VStack(alignment: .leading, spacing: FlixySpacing.regular) { + VStack(alignment: .leading, spacing: HaloSpacing.regular) { foundServerHeader(model: model) TextField("signIn.jellyfin.userName", text: $model.userName) .textContentType(.username) - .flixyPlainEntry() + .haloPlainEntry() .submitLabel(.next) .focused($focusedField, equals: .userName) .onSubmit { focusedField = .password } @@ -200,8 +200,8 @@ struct JellyfinSignInView: View { focusedField = .password return .handled } - .padding(FlixySpacing.regular) - .background(Color.flixyElevated, in: .rect(cornerRadius: FlixyRadius.control)) + .padding(HaloSpacing.regular) + .background(Color.haloElevated, in: .rect(cornerRadius: HaloRadius.control)) SecureField("signIn.jellyfin.password", text: $model.password) .textContentType(.password) @@ -214,17 +214,17 @@ struct JellyfinSignInView: View { focusedField = .userName return .handled } - .padding(FlixySpacing.regular) - .background(Color.flixyElevated, in: .rect(cornerRadius: FlixyRadius.control)) + .padding(HaloSpacing.regular) + .background(Color.haloElevated, in: .rect(cornerRadius: HaloRadius.control)) Button { focusedField = nil Task { await model.signInWithPassword() } } label: { Text("signIn.jellyfin.submit") - .font(.flixyRowHeader) + .font(.haloRowHeader) .frame(maxWidth: .infinity) - .padding(.vertical, FlixySpacing.regular) + .padding(.vertical, HaloSpacing.regular) } .buttonStyle(.borderedProminent) .tint(accent) @@ -234,46 +234,46 @@ struct JellyfinSignInView: View { // verworfen. Gespeichert wird nur der Token, und der im // Schlüsselbund. Text("signIn.jellyfin.passwordNote") - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextMuted) + .font(.haloCaption) + .foregroundStyle(Color.haloTextMuted) - Divider().overlay(Color.flixySeparator) + Divider().overlay(Color.haloSeparator) if model.offersQuickConnect { Button("signIn.jellyfin.useCode") { Task { await model.beginQuickConnect() } } - .font(.flixyCaption) + .font(.haloCaption) } Button("signIn.jellyfin.otherAddress") { model.startOver() } - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextSecondary) + .font(.haloCaption) + .foregroundStyle(Color.haloTextSecondary) } - .foregroundStyle(Color.flixyTextPrimary) + .foregroundStyle(Color.haloTextPrimary) } // MARK: - Bausteine @ViewBuilder private func foundServerHeader(model: JellyfinSignInModel) -> some View { - VStack(alignment: .leading, spacing: FlixySpacing.tight) { + VStack(alignment: .leading, spacing: HaloSpacing.tight) { Text("signIn.jellyfin.foundServer") - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextMuted) + .font(.haloCaption) + .foregroundStyle(Color.haloTextMuted) .textCase(.uppercase) Text(model.serverName ?? model.address) - .font(.flixyTitle) - .foregroundStyle(Color.flixyTextPrimary) + .font(.haloTitle) + .foregroundStyle(Color.haloTextPrimary) } } @ViewBuilder private func waiting(text: LocalizedStringKey) -> some View { - HStack(spacing: FlixySpacing.snug) { + HStack(spacing: HaloSpacing.snug) { ProgressView().controlSize(.small) Text(text) - .font(.flixyBody) - .foregroundStyle(Color.flixyTextSecondary) + .font(.haloBody) + .foregroundStyle(Color.haloTextSecondary) } .frame(maxWidth: .infinity, alignment: .center) - .padding(.vertical, FlixySpacing.section) + .padding(.vertical, HaloSpacing.section) } } diff --git a/Flixy/Views/SignIn/SignInView.swift b/Halo/Views/SignIn/SignInView.swift similarity index 67% rename from Flixy/Views/SignIn/SignInView.swift rename to Halo/Views/SignIn/SignInView.swift index f268436..de818f1 100644 --- a/Flixy/Views/SignIn/SignInView.swift +++ b/Halo/Views/SignIn/SignInView.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign /// Der Anmeldebildschirm. /// @@ -12,54 +12,54 @@ import FlixyDesign /// wird die Adresse eingetippt und, wann immer der Server es anbietet, ein /// Code bestätigt statt eines Passworts — das führt `JellyfinSignInView`. struct SignInView: View { - @Environment(\.flixyAccent) private var accent + @Environment(\.haloAccent) private var accent @State private var showsJellyfinSignIn = false var body: some View { - VStack(spacing: FlixySpacing.section) { + VStack(spacing: HaloSpacing.section) { Spacer() - VStack(spacing: FlixySpacing.regular) { + VStack(spacing: HaloSpacing.regular) { Image(systemName: "play.rectangle.on.rectangle") .font(.system(size: 52)) .foregroundStyle(accent) Text(Branding.appName) - .font(.flixyHero) - .foregroundStyle(Color.flixyTextPrimary) + .font(.haloHero) + .foregroundStyle(Color.haloTextPrimary) Text("signIn.tagline") - .font(.flixyBody) - .foregroundStyle(Color.flixyTextSecondary) + .font(.haloBody) + .foregroundStyle(Color.haloTextSecondary) .multilineTextAlignment(.center) } Spacer() - VStack(spacing: FlixySpacing.regular) { + VStack(spacing: HaloSpacing.regular) { Button { showsJellyfinSignIn = true } label: { Text("signIn.withJellyfin") - .font(.flixyRowHeader) + .font(.haloRowHeader) .frame(maxWidth: .infinity) - .padding(.vertical, FlixySpacing.regular) + .padding(.vertical, HaloSpacing.regular) } .buttonStyle(.borderedProminent) .tint(accent) Text("signIn.privacy") - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextMuted) + .font(.haloCaption) + .foregroundStyle(Color.haloTextMuted) .multilineTextAlignment(.center) } - Spacer().frame(height: FlixySpacing.section) + Spacer().frame(height: HaloSpacing.section) } - .padding(.horizontal, FlixySpacing.section) + .padding(.horizontal, HaloSpacing.section) .frame(maxWidth: 420) .frame(maxWidth: .infinity, maxHeight: .infinity) - .background(Color.flixyCanvas) + .background(Color.haloCanvas) .sheet(isPresented: $showsJellyfinSignIn) { JellyfinSignInView() } diff --git a/FlixyTV/Flixy.entitlements b/HaloTV/Halo.entitlements similarity index 82% rename from FlixyTV/Flixy.entitlements rename to HaloTV/Halo.entitlements index aa7bef7..4140325 100644 --- a/FlixyTV/Flixy.entitlements +++ b/HaloTV/Halo.entitlements @@ -4,7 +4,7 @@ com.apple.security.application-groups - group.com.scarriffleservices.flixy + group.com.scarriffleservices.halo diff --git a/FlixyTV/FlixyTVApp.swift b/HaloTV/HaloTVApp.swift similarity index 87% rename from FlixyTV/FlixyTVApp.swift rename to HaloTV/HaloTVApp.swift index f3ae2e1..7674a8e 100644 --- a/FlixyTV/FlixyTVApp.swift +++ b/HaloTV/HaloTVApp.swift @@ -1,12 +1,12 @@ import SwiftUI -import FlixyDesign -import FlixyPlayback +import HaloDesign +import HaloPlayback import MediaKit import JellyfinKit /// Die App auf dem Fernseher. /// -/// **Eine eigene Wurzel statt eines Zweigs in `FlixyApp`.** Der Unterschied +/// **Eine eigene Wurzel statt eines Zweigs in `HaloApp`.** Der Unterschied /// zwischen Telefon und Fernseher ist keine Feinheit der Darstellung, sondern /// die Bedienart: kein Finger, keine Grössenklasse, keine Werkzeugleiste, kein /// Ziehen zum Aktualisieren, keine halbhohen Sheets — und dafür ein Fokus, den @@ -14,7 +14,7 @@ import JellyfinKit /// wäre kein Zweig, sondern ein zweiter Rumpf in derselben Datei, und der /// nächste, der die iOS-Seite ändert, bräche die andere, ohne es zu merken. /// -/// **Die Modelle dagegen werden geteilt**, nicht kopiert: `Flixy/Session/` +/// **Die Modelle dagegen werden geteilt**, nicht kopiert: `Halo/Session/` /// kommt über einen Pfadeintrag in `project.yml` mit. Die Naht verläuft /// zwischen Modell und Ansicht, nicht zwischen den Plattformen. /// @@ -22,9 +22,9 @@ import JellyfinKit /// iOS-App trägt ausschliesslich Downloads, und die gibt es hier nicht — damit /// fällt beides weg. @main -struct FlixyTVApp: App { - @State private var session: FlixySession - @State private var theme = FlixyTheme() +struct HaloTVApp: App { + @State private var session: HaloSession + @State private var theme = HaloTheme() @State private var playback = PlaybackCoordinator() @State private var playbackSettings = PlaybackSettings() @State private var languages = LanguagePreferences() @@ -40,7 +40,7 @@ struct FlixyTVApp: App { @State private var network = NetworkConditions() init() { - _session = State(initialValue: FlixySession( + _session = State(initialValue: HaloSession( jellyfinIdentity: JellyfinIdentity.current( client: Branding.appName, version: Branding.version @@ -62,7 +62,7 @@ struct FlixyTVApp: App { .environment(homeLayout) .environment(diagnostics) .environment(network) - .flixyAccent(theme) + .haloAccent(theme) .tint(theme.accentColor) // Ein Fernseher ist immer dunkel. Der Schalter in der // Info.plist gilt fürs System, diese Zeile für die Vorschauen. diff --git a/FlixyTV/Info.plist b/HaloTV/Info.plist similarity index 84% rename from FlixyTV/Info.plist rename to HaloTV/Info.plist index 7d72703..63f8a60 100644 --- a/FlixyTV/Info.plist +++ b/HaloTV/Info.plist @@ -5,7 +5,7 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName - Flixy + Halo CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -22,10 +22,10 @@ CFBundleURLName - com.scarriffleservices.flixy.topshelf + com.scarriffleservices.halo.topshelf CFBundleURLSchemes - flixy + halo @@ -39,7 +39,7 @@ NSLocalNetworkUsageDescription - Flixy benötigt Zugriff auf das lokale Netzwerk, um deinen Jellyfin-Server zu erreichen. + Halo benötigt Zugriff auf das lokale Netzwerk, um deinen Jellyfin-Server zu erreichen. UIUserInterfaceStyle Dark diff --git a/FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json b/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json similarity index 100% rename from FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json rename to HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json diff --git a/FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/back.png b/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/back.png similarity index 100% rename from FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/back.png rename to HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/back.png diff --git a/FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json b/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json similarity index 100% rename from FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json rename to HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json diff --git a/FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json b/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json similarity index 100% rename from FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json rename to HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json diff --git a/FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json b/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json similarity index 100% rename from FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json rename to HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json diff --git a/FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/front.png b/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/front.png similarity index 100% rename from FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/front.png rename to HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/front.png diff --git a/FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json b/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json similarity index 100% rename from FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json rename to HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json diff --git a/FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json b/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json similarity index 100% rename from FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json rename to HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json diff --git a/FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/back.png b/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/back.png similarity index 100% rename from FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/back.png rename to HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/back.png diff --git a/FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/back@2x.png b/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/back@2x.png similarity index 100% rename from FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/back@2x.png rename to HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/back@2x.png diff --git a/FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json b/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json similarity index 100% rename from FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json rename to HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json diff --git a/FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json b/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json similarity index 100% rename from FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json rename to HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json diff --git a/FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json b/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json similarity index 100% rename from FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json rename to HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json diff --git a/FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/front.png b/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/front.png similarity index 100% rename from FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/front.png rename to HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/front.png diff --git a/FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/front@2x.png b/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/front@2x.png similarity index 100% rename from FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/front@2x.png rename to HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/front@2x.png diff --git a/FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json b/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json similarity index 100% rename from FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json rename to HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json diff --git a/FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json b/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json similarity index 100% rename from FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json rename to HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json diff --git a/FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json b/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json similarity index 100% rename from FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json rename to HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json diff --git a/FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/topshelfwide.png b/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/topshelfwide.png similarity index 100% rename from FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/topshelfwide.png rename to HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/topshelfwide.png diff --git a/FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/topshelfwide@2x.png b/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/topshelfwide@2x.png similarity index 100% rename from FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/topshelfwide@2x.png rename to HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/topshelfwide@2x.png diff --git a/FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json b/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json similarity index 100% rename from FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json rename to HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json diff --git a/FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/topshelf.png b/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/topshelf.png similarity index 100% rename from FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/topshelf.png rename to HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/topshelf.png diff --git a/FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/topshelf@2x.png b/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/topshelf@2x.png similarity index 100% rename from FlixyTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/topshelf@2x.png rename to HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/topshelf@2x.png diff --git a/FlixyTV/Resources/TVAssets.xcassets/Contents.json b/HaloTV/Resources/TVAssets.xcassets/Contents.json similarity index 100% rename from FlixyTV/Resources/TVAssets.xcassets/Contents.json rename to HaloTV/Resources/TVAssets.xcassets/Contents.json diff --git a/FlixyTV/Views/Detail/TVDetailView.swift b/HaloTV/Views/Detail/TVDetailView.swift similarity index 87% rename from FlixyTV/Views/Detail/TVDetailView.swift rename to HaloTV/Views/Detail/TVDetailView.swift index 7006268..4516d8a 100644 --- a/FlixyTV/Views/Detail/TVDetailView.swift +++ b/HaloTV/Views/Detail/TVDetailView.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign import MediaKit /// Die Detailseite auf dem Fernseher. @@ -10,7 +10,7 @@ import MediaKit struct TVDetailView: View { let route: MediaRoute - @Environment(FlixySession.self) private var session + @Environment(HaloSession.self) private var session @Environment(PlaybackCoordinator.self) private var playback @Environment(QuickPlay.self) private var quickPlay @@ -22,8 +22,8 @@ struct TVDetailView: View { case .loading: ProgressView().frame(maxWidth: .infinity, maxHeight: .infinity) case .failed(let meldung): - VStack(spacing: FlixySpacing.regular) { - Text(meldung).font(.flixyBody).foregroundStyle(.white) + VStack(spacing: HaloSpacing.regular) { + Text(meldung).font(.haloBody).foregroundStyle(.white) Button("action.retry") { Task { await lade() } } } case .loaded(let item): diff --git a/FlixyTV/Views/Home/TVHeroSection.swift b/HaloTV/Views/Home/TVHeroSection.swift similarity index 92% rename from FlixyTV/Views/Home/TVHeroSection.swift rename to HaloTV/Views/Home/TVHeroSection.swift index 125b9cf..a9ef245 100644 --- a/FlixyTV/Views/Home/TVHeroSection.swift +++ b/HaloTV/Views/Home/TVHeroSection.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign import MediaKit /// Der Aufmacher oben auf der Startseite des Fernsehers. @@ -13,8 +13,8 @@ struct TVHeroSection: View { let onPlay: () -> Void let onDetails: () -> Void - @Environment(FlixySession.self) private var session - @Environment(\.flixyAccent) private var accent + @Environment(HaloSession.self) private var session + @Environment(\.haloAccent) private var accent var body: some View { HeroBanner( @@ -25,7 +25,7 @@ struct TVHeroSection: View { HeroArtwork.backdropURLs(for: item, backend: $0, compact: false) } ?? [], logoURL: session.backend.flatMap { HeroArtwork.logoURL(for: item, backend: $0) }, - aspectRatio: FlixyAspectRatio.hero, + aspectRatio: HaloAspectRatio.hero, // Der Aufmacher nimmt die Höhe, die das Karussell ihm gibt. fillsAvailableSpace: true ) { diff --git a/FlixyTV/Views/Home/TVHomeView.swift b/HaloTV/Views/Home/TVHomeView.swift similarity index 87% rename from FlixyTV/Views/Home/TVHomeView.swift rename to HaloTV/Views/Home/TVHomeView.swift index bda7e2d..bfb78aa 100644 --- a/FlixyTV/Views/Home/TVHomeView.swift +++ b/HaloTV/Views/Home/TVHomeView.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign import MediaKit /// Die Startseite auf dem Fernseher. @@ -16,7 +16,7 @@ struct TVHomeView: View { /// hiesse zwei Stapel gleich zu halten. @Binding var deepLinkTarget: MediaRoute? - @Environment(FlixySession.self) private var session + @Environment(HaloSession.self) private var session @Environment(HomeLayoutSettings.self) private var layout @Environment(PlaybackCoordinator.self) private var playback @Environment(QuickPlay.self) private var quickPlay @@ -54,8 +54,8 @@ struct TVHomeView: View { ProgressView().frame(maxWidth: .infinity, maxHeight: .infinity) case .failed(let meldung): - VStack(spacing: FlixySpacing.regular) { - Text(meldung).font(.flixyBody).foregroundStyle(.white) + VStack(spacing: HaloSpacing.regular) { + Text(meldung).font(.haloBody).foregroundStyle(.white) Button("action.retry") { Task { await feed.load(from: session.backend) } } @@ -64,7 +64,7 @@ struct TVHomeView: View { case .loaded: let reihen = feed.rows(for: layout) if reihen.isEmpty && session.libraries.isEmpty { - Text("home.empty.title").font(.flixyRowHeader).foregroundStyle(.white) + Text("home.empty.title").font(.haloRowHeader).foregroundStyle(.white) } else { seite(reihen: reihen) } @@ -73,7 +73,7 @@ struct TVHomeView: View { private func seite(reihen: [MediaRowGroup]) -> some View { ScrollView { - LazyVStack(alignment: .leading, spacing: FlixySpacing.section) { + LazyVStack(alignment: .leading, spacing: HaloSpacing.section) { if let gezeigt = aufmacher ?? feed.heroItems(for: layout).first { TVHeroSection( item: gezeigt, @@ -94,7 +94,7 @@ struct TVHomeView: View { ) } } - .padding(.bottom, FlixySpacing.screenMargin) + .padding(.bottom, HaloSpacing.screenMargin) } .scrollIndicators(.never) // **Bildfüllend, und der Rand steckt in `screenMargin`.** Der @@ -116,16 +116,16 @@ struct TVHomeView: View { @ViewBuilder private var regalStatus: some View { #if DEBUG - VStack(alignment: .leading, spacing: FlixySpacing.tight) { + VStack(alignment: .leading, spacing: HaloSpacing.tight) { Text("topShelf.title") - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextMuted) + .font(.haloCaption) + .foregroundStyle(Color.haloTextMuted) Text(TopShelfWriter.status) - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextSecondary) + .font(.haloCaption) + .foregroundStyle(Color.haloTextSecondary) } - .padding(.horizontal, FlixySpacing.screenMargin) - .padding(.bottom, FlixySpacing.regular) + .padding(.horizontal, HaloSpacing.screenMargin) + .padding(.bottom, HaloSpacing.regular) .frame(maxWidth: .infinity, alignment: .leading) .background(Color.black.opacity(0.6)) #endif diff --git a/FlixyTV/Views/Home/TVMediaRow.swift b/HaloTV/Views/Home/TVMediaRow.swift similarity index 83% rename from FlixyTV/Views/Home/TVMediaRow.swift rename to HaloTV/Views/Home/TVMediaRow.swift index b432fef..43d615c 100644 --- a/FlixyTV/Views/Home/TVMediaRow.swift +++ b/HaloTV/Views/Home/TVMediaRow.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign import MediaKit /// Eine waagerechte Reihe von Titeln auf dem Fernseher. @@ -13,32 +13,32 @@ struct TVMediaRow: View { /// Wer gerade dran ist — damit der Aufmacher oben mitwandert. var onFocus: (MediaItem) -> Void = { _ in } - @Environment(FlixySession.self) private var session + @Environment(HaloSession.self) private var session /// Breit genug, dass die übernächste Karte angeschnitten ist — das zeigt, /// dass es weitergeht, ohne einen Pfeil dafür zu brauchen. private var breite: CGFloat { row.isContinueWatching ? 500 : 280 } var body: some View { - VStack(alignment: .leading, spacing: FlixySpacing.regular) { + VStack(alignment: .leading, spacing: HaloSpacing.regular) { Text(row.title) - .font(.flixyRowHeader) - .foregroundStyle(Color.flixyTextPrimary) - .padding(.horizontal, FlixySpacing.screenMargin) + .font(.haloRowHeader) + .foregroundStyle(Color.haloTextPrimary) + .padding(.horizontal, HaloSpacing.screenMargin) ScrollView(.horizontal) { - LazyHStack(spacing: FlixySpacing.regular) { + LazyHStack(spacing: HaloSpacing.regular) { ForEach(row.items) { item in karte(for: item).frame(width: breite) } } - .padding(.horizontal, FlixySpacing.screenMargin) + .padding(.horizontal, HaloSpacing.screenMargin) // **Platz zum Anheben.** Eine fokussierte Karte wächst über // ihren Rahmen hinaus, und eine ScrollView beschneidet am // Rand. Ohne Polster und ohne das abgeschaltete Beschneiden // fehlt der obersten Reihe die Anhebung — und zwar nur ihr, // was wie ein Zufall aussieht statt wie ein Fehler. - .padding(.vertical, FlixySpacing.regular) + .padding(.vertical, HaloSpacing.regular) } .scrollClipDisabled() .scrollIndicators(.never) diff --git a/FlixyTV/Views/Library/TVLibraryView.swift b/HaloTV/Views/Library/TVLibraryView.swift similarity index 85% rename from FlixyTV/Views/Library/TVLibraryView.swift rename to HaloTV/Views/Library/TVLibraryView.swift index f30385c..9bcaf3b 100644 --- a/FlixyTV/Views/Library/TVLibraryView.swift +++ b/HaloTV/Views/Library/TVLibraryView.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign import MediaKit /// Eine Mediathek als Raster auf dem Fernseher. @@ -12,7 +12,7 @@ import MediaKit struct TVLibraryView: View { let libraryID: String - @Environment(FlixySession.self) private var session + @Environment(HaloSession.self) private var session @Environment(PlaybackCoordinator.self) private var playback @Environment(QuickPlay.self) private var quickPlay @@ -24,7 +24,7 @@ struct TVLibraryView: View { private static let spalten = 6 private var raster: [GridItem] { - Array(repeating: GridItem(.flexible(), spacing: FlixySpacing.section), count: Self.spalten) + Array(repeating: GridItem(.flexible(), spacing: HaloSpacing.section), count: Self.spalten) } var body: some View { @@ -52,8 +52,8 @@ struct TVLibraryView: View { ProgressView().frame(maxWidth: .infinity, maxHeight: .infinity) case .failed(let meldung) where feed.items.isEmpty: - VStack(spacing: FlixySpacing.regular) { - Text(meldung).font(.flixyBody).foregroundStyle(.white) + VStack(spacing: HaloSpacing.regular) { + Text(meldung).font(.haloBody).foregroundStyle(.white) Button("action.retry") { Task { await feed.reload(from: session.backend) } } } @@ -64,13 +64,13 @@ struct TVLibraryView: View { private func raster(feed: LibraryFeed) -> some View { ScrollView { - VStack(alignment: .leading, spacing: FlixySpacing.section) { + VStack(alignment: .leading, spacing: HaloSpacing.section) { Text(feed.library.title) - .font(.flixyHero) + .font(.haloHero) .foregroundStyle(.white) - .padding(.horizontal, FlixySpacing.screenMargin) + .padding(.horizontal, HaloSpacing.screenMargin) - LazyVGrid(columns: raster, spacing: FlixySpacing.section) { + LazyVGrid(columns: raster, spacing: HaloSpacing.section) { ForEach(Array(feed.items.enumerated()), id: \.element.id) { stelle, item in TVPosterCard( title: item.rowTitle, @@ -111,20 +111,20 @@ struct TVLibraryView: View { .focusable(false) } } - .padding(.horizontal, FlixySpacing.screenMargin) + .padding(.horizontal, HaloSpacing.screenMargin) if feed.loadMoreFailed { Button("library.loadMore") { Task { await feed.loadMore(from: session.backend) } } - .padding(.horizontal, FlixySpacing.screenMargin) + .padding(.horizontal, HaloSpacing.screenMargin) } } - .padding(.vertical, FlixySpacing.screenMargin) + .padding(.vertical, HaloSpacing.screenMargin) } .scrollClipDisabled() .scrollIndicators(.never) - // Siehe `FlixySpacing.screenMargin`: bildfüllend, Rand im Wert. + // Siehe `HaloSpacing.screenMargin`: bildfüllend, Rand im Wert. .ignoresSafeArea() } } diff --git a/FlixyTV/Views/Player/TVPlayerCoordinator.swift b/HaloTV/Views/Player/TVPlayerCoordinator.swift similarity index 99% rename from FlixyTV/Views/Player/TVPlayerCoordinator.swift rename to HaloTV/Views/Player/TVPlayerCoordinator.swift index af82040..f17afd3 100644 --- a/FlixyTV/Views/Player/TVPlayerCoordinator.swift +++ b/HaloTV/Views/Player/TVPlayerCoordinator.swift @@ -1,6 +1,6 @@ import AVKit import UIKit -import FlixyPlayback +import HaloPlayback import MediaKit /// Führt Apples Player — und hält ihn über einen Neuaufbau hinweg am Leben. diff --git a/FlixyTV/Views/Player/TVPlayerHost.swift b/HaloTV/Views/Player/TVPlayerHost.swift similarity index 99% rename from FlixyTV/Views/Player/TVPlayerHost.swift rename to HaloTV/Views/Player/TVPlayerHost.swift index ffb9874..d0cc304 100644 --- a/FlixyTV/Views/Player/TVPlayerHost.swift +++ b/HaloTV/Views/Player/TVPlayerHost.swift @@ -1,6 +1,6 @@ import AVKit import SwiftUI -import FlixyPlayback +import HaloPlayback import MediaKit /// Hängt Apples Player in den SwiftUI-Baum. diff --git a/FlixyTV/Views/Player/TVPlayerScreen.swift b/HaloTV/Views/Player/TVPlayerScreen.swift similarity index 97% rename from FlixyTV/Views/Player/TVPlayerScreen.swift rename to HaloTV/Views/Player/TVPlayerScreen.swift index 7ee9a80..0cc54ec 100644 --- a/FlixyTV/Views/Player/TVPlayerScreen.swift +++ b/HaloTV/Views/Player/TVPlayerScreen.swift @@ -1,6 +1,6 @@ import SwiftUI -import FlixyDesign -import FlixyPlayback +import HaloDesign +import HaloPlayback import MediaKit /// Der Player auf dem Fernseher. @@ -14,7 +14,7 @@ import MediaKit struct TVPlayerScreen: View { let request: PlaybackRequest - @Environment(FlixySession.self) private var session + @Environment(HaloSession.self) private var session @Environment(PlaybackCoordinator.self) private var playback @Environment(PlaybackSettings.self) private var settings @Environment(LanguagePreferences.self) private var languages diff --git a/FlixyTV/Views/Player/TVTrackMenuBuilder.swift b/HaloTV/Views/Player/TVTrackMenuBuilder.swift similarity index 99% rename from FlixyTV/Views/Player/TVTrackMenuBuilder.swift rename to HaloTV/Views/Player/TVTrackMenuBuilder.swift index 2de3ed7..08de4a6 100644 --- a/FlixyTV/Views/Player/TVTrackMenuBuilder.swift +++ b/HaloTV/Views/Player/TVTrackMenuBuilder.swift @@ -1,6 +1,6 @@ import AVKit import UIKit -import FlixyPlayback +import HaloPlayback /// Baut aus unseren Spurlisten die Menüs für Apples Transportleiste. /// diff --git a/FlixyTV/Views/Search/TVSearchView.swift b/HaloTV/Views/Search/TVSearchView.swift similarity index 83% rename from FlixyTV/Views/Search/TVSearchView.swift rename to HaloTV/Views/Search/TVSearchView.swift index 915b5c9..d9e7388 100644 --- a/FlixyTV/Views/Search/TVSearchView.swift +++ b/HaloTV/Views/Search/TVSearchView.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign import MediaKit /// Die Suche am Fernseher. @@ -12,7 +12,7 @@ import MediaKit /// Das Modell dahinter ist dasselbe wie am Telefon: `SearchFeed` entprellt, /// fragt und merkt sich die letzten Begriffe. struct TVSearchView: View { - @Environment(FlixySession.self) private var session + @Environment(HaloSession.self) private var session @Environment(PlaybackCoordinator.self) private var playback @Environment(QuickPlay.self) private var quickPlay @@ -49,7 +49,7 @@ struct TVSearchView: View { private var ergebnisse: some View { ScrollView { - LazyVStack(alignment: .leading, spacing: FlixySpacing.section) { + LazyVStack(alignment: .leading, spacing: HaloSpacing.section) { ForEach(feed.hubs) { reihe in TVMediaRow( row: reihe, @@ -57,7 +57,7 @@ struct TVSearchView: View { ) } } - .padding(.vertical, FlixySpacing.section) + .padding(.vertical, HaloSpacing.section) } .scrollClipDisabled() .scrollIndicators(.never) @@ -73,20 +73,20 @@ struct TVSearchView: View { if feed.recent.isEmpty { hinweis("search.hint") } else { - VStack(alignment: .leading, spacing: FlixySpacing.regular) { + VStack(alignment: .leading, spacing: HaloSpacing.regular) { Text("search.recent") - .font(.flixyRowHeader) - .foregroundStyle(Color.flixyTextPrimary) + .font(.haloRowHeader) + .foregroundStyle(Color.haloTextPrimary) ForEach(feed.recent, id: \.self) { eintrag in Button(eintrag) { text = eintrag } } Button("search.forgetRecent", role: .destructive) { feed.forgetRecent() } - .padding(.top, FlixySpacing.regular) + .padding(.top, HaloSpacing.regular) } .frame(maxWidth: 700, alignment: .leading) - .padding(FlixySpacing.section) + .padding(HaloSpacing.section) } } @@ -96,9 +96,9 @@ struct TVSearchView: View { private func hinweis(_ text: LocalizedStringKey) -> some View { Text(text) - .font(.flixyBody) - .foregroundStyle(Color.flixyTextMuted) + .font(.haloBody) + .foregroundStyle(Color.haloTextMuted) .frame(maxWidth: 700) - .padding(FlixySpacing.section) + .padding(HaloSpacing.section) } } diff --git a/FlixyTV/Views/SignIn/TVSignInView.swift b/HaloTV/Views/SignIn/TVSignInView.swift similarity index 77% rename from FlixyTV/Views/SignIn/TVSignInView.swift rename to HaloTV/Views/SignIn/TVSignInView.swift index c78a074..31ddccc 100644 --- a/FlixyTV/Views/SignIn/TVSignInView.swift +++ b/HaloTV/Views/SignIn/TVSignInView.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign import JellyfinKit /// Die Anmeldung am Fernseher. @@ -13,13 +13,13 @@ import JellyfinKit /// Der Weg über Benutzername und Passwort bleibt erreichbar — für Server, auf /// denen Quick Connect abgeschaltet ist. struct TVSignInView: View { - @Environment(FlixySession.self) private var session + @Environment(HaloSession.self) private var session @State private var model: JellyfinSignInModel? var body: some View { ZStack { - Color.flixyCanvas.ignoresSafeArea() + Color.haloCanvas.ignoresSafeArea() if let model { inhalt(for: model) @@ -55,9 +55,9 @@ struct TVSignInView: View { private func inhalt(for model: JellyfinSignInModel) -> some View { @Bindable var model = model - VStack(alignment: .leading, spacing: FlixySpacing.section) { - Text(Branding.appName).font(.flixyHero) - Text("signIn.tagline").font(.flixyBody).foregroundStyle(Color.flixyTextMuted) + VStack(alignment: .leading, spacing: HaloSpacing.section) { + Text(Branding.appName).font(.haloHero) + Text("signIn.tagline").font(.haloBody).foregroundStyle(Color.haloTextMuted) switch model.step { case .address: @@ -73,10 +73,10 @@ struct TVSignInView: View { } if let fehler = model.errorMessage { - Text(fehler).font(.flixyBody).foregroundStyle(Color.flixyDestructive) + Text(fehler).font(.haloBody).foregroundStyle(Color.haloDestructive) } } - .padding(FlixySpacing.section) + .padding(HaloSpacing.section) } // MARK: - Die vier Schritte @@ -84,15 +84,15 @@ struct TVSignInView: View { private func adresse(model: JellyfinSignInModel) -> some View { @Bindable var model = model - return VStack(alignment: .leading, spacing: FlixySpacing.regular) { - Text("signIn.jellyfin.addressPrompt").font(.flixyRowHeader) + return VStack(alignment: .leading, spacing: HaloSpacing.regular) { + Text("signIn.jellyfin.addressPrompt").font(.haloRowHeader) // Auf tvOS öffnet ein Textfeld beim Fokussieren die // Bildschirmtastatur ganzseitig — deshalb steht hier nur das Feld // und keine Maske drumherum. TextField("signIn.jellyfin.addressPlaceholder", text: $model.address) - .flixyPlainEntry(isAddress: true) + .haloPlainEntry(isAddress: true) Text("signIn.jellyfin.addressHint") - .font(.flixyCaption).foregroundStyle(Color.flixyTextMuted) + .font(.haloCaption).foregroundStyle(Color.haloTextMuted) Button("signIn.jellyfin.connect") { Task { await model.findServer() } } @@ -100,9 +100,9 @@ struct TVSignInView: View { } private func codeAnzeigen(model: JellyfinSignInModel, code: String) -> some View { - VStack(alignment: .leading, spacing: FlixySpacing.regular) { + VStack(alignment: .leading, spacing: HaloSpacing.regular) { if let name = model.serverName { - Text(name).font(.flixyRowHeader) + Text(name).font(.haloRowHeader) } // **Der Code ist hier der Inhalt, nicht eine Beschriftung.** // Er wird aus drei Metern abgelesen und in ein Telefon getippt; @@ -111,11 +111,11 @@ struct TVSignInView: View { .font(.system(size: 96, weight: .bold, design: .monospaced)) .kerning(12) .foregroundStyle(.white) - Text("signIn.jellyfin.quickConnectHint").font(.flixyBody) + Text("signIn.jellyfin.quickConnectHint").font(.haloBody) Label("signIn.jellyfin.waitingForApproval", systemImage: "hourglass") - .font(.flixyCaption).foregroundStyle(Color.flixyTextMuted) + .font(.haloCaption).foregroundStyle(Color.haloTextMuted) - HStack(spacing: FlixySpacing.regular) { + HStack(spacing: HaloSpacing.regular) { Button("signIn.jellyfin.usePassword") { model.useCredentials() } Button("signIn.jellyfin.otherAddress") { model.startOver() } } @@ -125,17 +125,17 @@ struct TVSignInView: View { private func zugangsdaten(model: JellyfinSignInModel) -> some View { @Bindable var model = model - return VStack(alignment: .leading, spacing: FlixySpacing.regular) { + return VStack(alignment: .leading, spacing: HaloSpacing.regular) { if let name = model.serverName { - Text(name).font(.flixyRowHeader) + Text(name).font(.haloRowHeader) } TextField("signIn.jellyfin.userName", text: $model.userName) - .flixyPlainEntry() + .haloPlainEntry() SecureField("signIn.jellyfin.password", text: $model.password) Text("signIn.jellyfin.passwordNote") - .font(.flixyCaption).foregroundStyle(Color.flixyTextMuted) + .font(.haloCaption).foregroundStyle(Color.haloTextMuted) - HStack(spacing: FlixySpacing.regular) { + HStack(spacing: HaloSpacing.regular) { Button("signIn.jellyfin.submit") { Task { await model.signInWithPassword() } } @@ -150,9 +150,9 @@ struct TVSignInView: View { } private func warten(_ text: LocalizedStringKey) -> some View { - HStack(spacing: FlixySpacing.regular) { + HStack(spacing: HaloSpacing.regular) { ProgressView() - Text(text).font(.flixyBody) + Text(text).font(.haloBody) } } } diff --git a/FlixyTV/Views/TVDeepLink.swift b/HaloTV/Views/TVDeepLink.swift similarity index 88% rename from FlixyTV/Views/TVDeepLink.swift rename to HaloTV/Views/TVDeepLink.swift index 90f5536..efddeaf 100644 --- a/FlixyTV/Views/TVDeepLink.swift +++ b/HaloTV/Views/TVDeepLink.swift @@ -9,7 +9,7 @@ import Foundation /// Geprüft ist er trotzdem nicht — das Fernseh-Ziel hat kein Testziel, und /// ihn dafür nach MediaKit zu schieben hiesse, ein Schema dieser App in ein /// Paket zu legen, das keine App kennt. Wer ihn anfasst, prüft ihn am Gerät: -/// `xcrun simctl openurl … flixy://play/`. +/// `xcrun simctl openurl … halo://play/`. enum TVDeepLink: Equatable { /// Abspielen, was dahintersteckt. case play(id: String) @@ -17,12 +17,12 @@ enum TVDeepLink: Equatable { case detail(id: String) /// Muss mit `CFBundleURLSchemes` in der Info.plist übereinstimmen. - static let scheme = "flixy" + static let scheme = "halo" init?(_ url: URL) { guard url.scheme == Self.scheme else { return nil } - // **`host` und nicht `pathComponents[0]`.** Bei `flixy://play/42` + // **`host` und nicht `pathComponents[0]`.** Bei `halo://play/42` // steht „play" im Rechnernamen, nicht im Pfad — der lautet schlicht // „/42". Wer hier den Pfad zerlegt, bekommt die Kennung als Aktion // und wundert sich. diff --git a/FlixyTV/Views/TVRootView.swift b/HaloTV/Views/TVRootView.swift similarity index 88% rename from FlixyTV/Views/TVRootView.swift rename to HaloTV/Views/TVRootView.swift index 3890732..501b082 100644 --- a/FlixyTV/Views/TVRootView.swift +++ b/HaloTV/Views/TVRootView.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign /// Was auf dem Fernseher zu sehen ist. /// @@ -10,7 +10,7 @@ import FlixyDesign /// bestehenden — ein `#if` wäre kein Zweig gewesen, sondern ein zweiter Rumpf /// in derselben Datei. struct TVRootView: View { - @Environment(FlixySession.self) private var session + @Environment(HaloSession.self) private var session @Environment(PlaybackCoordinator.self) private var playback @Environment(QuickPlay.self) private var quickPlay @@ -19,7 +19,7 @@ struct TVRootView: View { var body: some View { ZStack { - Color.flixyCanvas.ignoresSafeArea() + Color.haloCanvas.ignoresSafeArea() switch session.phase { case .launching: @@ -82,16 +82,16 @@ struct TVRootView: View { } private func verbinden(mit name: String) -> some View { - VStack(spacing: FlixySpacing.regular) { + VStack(spacing: HaloSpacing.regular) { ProgressView() - Text(name).font(.flixyRowHeader).foregroundStyle(.white) + Text(name).font(.haloRowHeader).foregroundStyle(.white) } } private func fehlgeschlagen(_ meldung: String) -> some View { - VStack(spacing: FlixySpacing.regular) { - Text(meldung).font(.flixyBody).foregroundStyle(.white) - HStack(spacing: FlixySpacing.regular) { + VStack(spacing: HaloSpacing.regular) { + Text(meldung).font(.haloBody).foregroundStyle(.white) + HStack(spacing: HaloSpacing.regular) { Button("action.retry") { Task { await session.retry() } } Button("action.signOut") { session.signOut() } } diff --git a/FlixyTV/Views/TVShell.swift b/HaloTV/Views/TVShell.swift similarity index 96% rename from FlixyTV/Views/TVShell.swift rename to HaloTV/Views/TVShell.swift index 9b57e51..21574a0 100644 --- a/FlixyTV/Views/TVShell.swift +++ b/HaloTV/Views/TVShell.swift @@ -1,5 +1,5 @@ import SwiftUI -import FlixyDesign +import HaloDesign import MediaKit /// Start, die Mediatheken und die Suche nebeneinander. @@ -14,7 +14,7 @@ import MediaKit struct TVShell: View { @Binding var deepLinkTarget: MediaRoute? - @Environment(FlixySession.self) private var session + @Environment(HaloSession.self) private var session /// Welcher Reiter offen ist. /// diff --git a/FlixyTopShelf/FlixyTopShelf.entitlements b/HaloTopShelf/HaloTopShelf.entitlements similarity index 82% rename from FlixyTopShelf/FlixyTopShelf.entitlements rename to HaloTopShelf/HaloTopShelf.entitlements index aa7bef7..4140325 100644 --- a/FlixyTopShelf/FlixyTopShelf.entitlements +++ b/HaloTopShelf/HaloTopShelf.entitlements @@ -4,7 +4,7 @@ com.apple.security.application-groups - group.com.scarriffleservices.flixy + group.com.scarriffleservices.halo diff --git a/FlixyTopShelf/Info.plist b/HaloTopShelf/Info.plist similarity index 97% rename from FlixyTopShelf/Info.plist rename to HaloTopShelf/Info.plist index e6f017b..5057614 100644 --- a/FlixyTopShelf/Info.plist +++ b/HaloTopShelf/Info.plist @@ -5,7 +5,7 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName - Flixy + Halo CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier diff --git a/FlixyTopShelf/TopShelfIdentity.swift b/HaloTopShelf/TopShelfIdentity.swift similarity index 89% rename from FlixyTopShelf/TopShelfIdentity.swift rename to HaloTopShelf/TopShelfIdentity.swift index 3360187..22c42d2 100644 --- a/FlixyTopShelf/TopShelfIdentity.swift +++ b/HaloTopShelf/TopShelfIdentity.swift @@ -8,11 +8,11 @@ import Foundation enum TopShelfIdentity { /// Muss mit `TopShelfWriter.group` und beiden Entitlement-Dateien /// übereinstimmen. - static let group = "group.com.scarriffleservices.flixy" + static let group = "group.com.scarriffleservices.halo" /// Muss mit `CFBundleURLSchemes` in der Info.plist des Fernseh-Ziels /// übereinstimmen. - static let scheme = "flixy" + static let scheme = "halo" static func playURL(for id: String) -> URL { URL(string: "\(scheme)://play/\(id)") ?? URL(string: "\(scheme)://")! diff --git a/FlixyTopShelf/TopShelfProvider.swift b/HaloTopShelf/TopShelfProvider.swift similarity index 100% rename from FlixyTopShelf/TopShelfProvider.swift rename to HaloTopShelf/TopShelfProvider.swift diff --git a/FlixyUITests/LayoutSnapshots.swift b/HaloUITests/LayoutSnapshots.swift similarity index 94% rename from FlixyUITests/LayoutSnapshots.swift rename to HaloUITests/LayoutSnapshots.swift index 045cd3e..982cdd8 100644 --- a/FlixyUITests/LayoutSnapshots.swift +++ b/HaloUITests/LayoutSnapshots.swift @@ -42,8 +42,8 @@ final class LayoutSnapshots: XCTestCase { func testPushedSettingsScreen() throws { let app = XCUIApplication() app.launchArguments = [ - "-FlixyStubServer", "http://127.0.0.1:8096", - "-flixy.navigation.placement", "sidebar", + "-HaloStubServer", "http://127.0.0.1:8096", + "-halo.navigation.placement", "sidebar", ] app.launch() @@ -68,8 +68,8 @@ final class LayoutSnapshots: XCTestCase { // sie womöglich umgestellt. Ein Startargument überschreibt sie, damit // jeder Lauf beim selben Bild anfängt. app.launchArguments = [ - "-FlixyStubServer", "http://127.0.0.1:8096", - "-flixy.navigation.placement", "sidebar", + "-HaloStubServer", "http://127.0.0.1:8096", + "-halo.navigation.placement", "sidebar", ] app.launch() @@ -99,7 +99,7 @@ final class LayoutSnapshots: XCTestCase { /// Leiste unten, und der Aufmacher hochkant statt 16:9. func testPhoneHome() throws { let app = XCUIApplication() - app.launchArguments = ["-FlixyStubServer", "http://127.0.0.1:8096"] + app.launchArguments = ["-HaloStubServer", "http://127.0.0.1:8096"] app.launch() XCTAssertTrue(app.staticTexts["Weiterschauen"].waitForExistence(timeout: 20)) @@ -113,8 +113,8 @@ final class LayoutSnapshots: XCTestCase { // sie womöglich umgestellt. Ein Startargument überschreibt sie, damit // jeder Lauf beim selben Bild anfängt. app.launchArguments = [ - "-FlixyStubServer", "http://127.0.0.1:8096", - "-flixy.navigation.placement", "sidebar", + "-HaloStubServer", "http://127.0.0.1:8096", + "-halo.navigation.placement", "sidebar", ] app.launch() diff --git a/FlixyUITests/PlayerSheets.swift b/HaloUITests/PlayerSheets.swift similarity index 95% rename from FlixyUITests/PlayerSheets.swift rename to HaloUITests/PlayerSheets.swift index 7e9a912..94bfff5 100644 --- a/FlixyUITests/PlayerSheets.swift +++ b/HaloUITests/PlayerSheets.swift @@ -10,7 +10,7 @@ import XCTest final class PlayerSheets: XCTestCase { func testQualitySheetOpens() { let app = XCUIApplication() - app.launchArguments = ["-FlixyStubServer", "http://127.0.0.1:8096"] + app.launchArguments = ["-HaloStubServer", "http://127.0.0.1:8096"] app.launch() XCTAssertTrue(app.staticTexts["Weiterschauen"].waitForExistence(timeout: 30)) diff --git a/Packages/FlixyKit/Package.swift b/Packages/HaloKit/Package.swift similarity index 73% rename from Packages/FlixyKit/Package.swift rename to Packages/HaloKit/Package.swift index fad3b07..15d432d 100644 --- a/Packages/FlixyKit/Package.swift +++ b/Packages/HaloKit/Package.swift @@ -2,21 +2,21 @@ import PackageDescription let package = Package( - name: "FlixyKit", + name: "HaloKit", // Quellsprache ist Englisch, damit die Schlüssel im Code lesbar bleiben. // Deutsch kommt als Übersetzung dazu; die Systemsprache entscheidet. defaultLocalization: "en", // macOS steht hier nur, damit `swift test` die Logik-Tests ohne // Simulator laufen lassen kann — das spart bei jedem Durchlauf Minuten. // Welche Plattformen die Apps bedienen, legt project.yml fest: iOS für - // Flixy, tvOS für FlixyTV. + // Halo, tvOS für HaloTV. platforms: [.iOS(.v26), .macOS(.v26), .tvOS(.v26)], products: [ .library(name: "MediaKit", targets: ["MediaKit"]), .library(name: "JellyfinKit", targets: ["JellyfinKit"]), - .library(name: "FlixyDesign", targets: ["FlixyDesign"]), - .library(name: "FlixyPlayback", targets: ["FlixyPlayback"]), - .library(name: "FlixyDownloads", targets: ["FlixyDownloads"]), + .library(name: "HaloDesign", targets: ["HaloDesign"]), + .library(name: "HaloPlayback", targets: ["HaloPlayback"]), + .library(name: "HaloDownloads", targets: ["HaloDownloads"]), ], targets: [ // Sprechen mit dem Server: Anmeldung, Endpunkte, Modelle. Kein SwiftUI, @@ -42,21 +42,21 @@ let package = Package( // Ein Werkzeug für die Fragen, die reines HTTP sind — ohne Oberfläche, // ohne Gerät, ohne Upload. Eine Runde dauert damit Sekunden statt // eines halben Tages, und das Upload-Kontingent bleibt für Builds. - .executableTarget(name: "FlixyProbe", dependencies: ["MediaKit", "JellyfinKit"]), + .executableTarget(name: "HaloProbe", dependencies: ["MediaKit", "JellyfinKit"]), // Farben, Typografie, wiederkehrende Bausteine. Hängt bewusst von // nichts ab: dadurch bleibt das Umstellen der Akzentfarbe ein // Token-Wechsel und keine Suche quer durch die App. - .target(name: "FlixyDesign", resources: [.process("Localizable.xcstrings")]), - .testTarget(name: "FlixyDesignTests", dependencies: ["FlixyDesign"]), + .target(name: "HaloDesign", resources: [.process("Localizable.xcstrings")]), + .testTarget(name: "HaloDesignTests", dependencies: ["HaloDesign"]), // Die Wiedergabe-Abstraktion samt AVPlayer-Engine und der Entscheidung // direkt / umpacken / umrechnen. - .target(name: "FlixyPlayback", dependencies: ["MediaKit"]), - .testTarget(name: "FlixyPlaybackTests", dependencies: ["FlixyPlayback"]), + .target(name: "HaloPlayback", dependencies: ["MediaKit"]), + .testTarget(name: "HaloPlaybackTests", dependencies: ["HaloPlayback"]), // Warteschlange, Hintergrundübertragung, Offline-Bestand. - .target(name: "FlixyDownloads", dependencies: ["MediaKit"], resources: [.process("Localizable.xcstrings")]), - .testTarget(name: "FlixyDownloadsTests", dependencies: ["FlixyDownloads"]), + .target(name: "HaloDownloads", dependencies: ["MediaKit"], resources: [.process("Localizable.xcstrings")]), + .testTarget(name: "HaloDownloadsTests", dependencies: ["HaloDownloads"]), ] ) diff --git a/Packages/FlixyKit/Sources/FlixyDesign/Color/AccentEnvironment.swift b/Packages/HaloKit/Sources/HaloDesign/Color/AccentEnvironment.swift similarity index 65% rename from Packages/FlixyKit/Sources/FlixyDesign/Color/AccentEnvironment.swift rename to Packages/HaloKit/Sources/HaloDesign/Color/AccentEnvironment.swift index 3422191..7ddf118 100644 --- a/Packages/FlixyKit/Sources/FlixyDesign/Color/AccentEnvironment.swift +++ b/Packages/HaloKit/Sources/HaloDesign/Color/AccentEnvironment.swift @@ -4,7 +4,7 @@ extension EnvironmentValues { /// Die aktuelle Akzentfarbe, bereits kontrastkorrigiert. /// /// Bewusst eine schlichte `Color` in der Umgebung statt einer Abhängigkeit - /// auf `FlixyTheme`: Bausteine wie `WatchProgressBar` sollen sich in einer + /// auf `HaloTheme`: Bausteine wie `WatchProgressBar` sollen sich in einer /// Vorschau mit einer beliebigen Farbe zeigen lassen, ohne dass dafür ein /// ganzes Theme-Objekt gebaut werden muss. /// Der Vorgabewert liest die gespeicherte Auswahl, statt blind die @@ -14,19 +14,19 @@ extension EnvironmentValues { /// Formulare zeichnen Zeilen teilweise in einem eigenen Kontext. Vorher /// leuchtete dort die Standardfarbe, während daneben schon die gewählte /// stand; jetzt stimmen beide. - @Entry public var flixyAccent: Color = AccentOption.storedAccentColor() + @Entry public var haloAccent: Color = AccentOption.storedAccentColor() } extension View { /// Setzt die Akzentfarbe für diesen Teilbaum. /// - /// Wird einmal an der Wurzel aus `FlixyTheme` gesetzt; darunter greift + /// Wird einmal an der Wurzel aus `HaloTheme` gesetzt; darunter greift /// alles automatisch darauf zu. - public func flixyAccent(_ color: Color) -> some View { - environment(\.flixyAccent, color) + public func haloAccent(_ color: Color) -> some View { + environment(\.haloAccent, color) } - public func flixyAccent(_ theme: FlixyTheme) -> some View { - environment(\.flixyAccent, theme.accentColor) + public func haloAccent(_ theme: HaloTheme) -> some View { + environment(\.haloAccent, theme.accentColor) } } diff --git a/Packages/FlixyKit/Sources/FlixyDesign/Color/AccentOption.swift b/Packages/HaloKit/Sources/HaloDesign/Color/AccentOption.swift similarity index 92% rename from Packages/FlixyKit/Sources/FlixyDesign/Color/AccentOption.swift rename to Packages/HaloKit/Sources/HaloDesign/Color/AccentOption.swift index a2d0d7b..e44567a 100644 --- a/Packages/FlixyKit/Sources/FlixyDesign/Color/AccentOption.swift +++ b/Packages/HaloKit/Sources/HaloDesign/Color/AccentOption.swift @@ -3,7 +3,7 @@ import SwiftUI /// Eine wählbare Akzentfarbe. /// -/// Die kuratierten Werte sind so gewählt, dass sie auf `FlixyColor.canvas` +/// Die kuratierten Werte sind so gewählt, dass sie auf `HaloColor.canvas` /// mindestens 4,5:1 erreichen — geprüft von `AccentPaletteTests`, damit beim /// Nachlegen einer Farbe nicht versehentlich etwas Unlesbares hineinrutscht. public struct AccentOption: Sendable, Identifiable { @@ -66,13 +66,13 @@ extension AccentOption { extension AccentOption { /// Wo die Auswahl liegt. /// - /// Hier statt in `FlixyTheme`, weil zwei Stellen sie brauchen: das Theme + /// Hier statt in `HaloTheme`, weil zwei Stellen sie brauchen: das Theme /// und der Vorgabewert der Umgebung. Zwei Kopien derselben Schlüssel /// driften auseinander, und zwar unbemerkt — es fällt erst auf, wenn eine /// Farbe irgendwo nicht mitkommt. enum StorageKey { - static let identifier = "flixy.accent.identifier" - static let customHex = "flixy.accent.customHex" + static let identifier = "halo.accent.identifier" + static let customHex = "halo.accent.customHex" } /// Die gespeicherte Auswahl, oder die Voreinstellung. @@ -102,6 +102,6 @@ extension AccentOption { /// Die gespeicherte Farbe, bereits kontrastkorrigiert. public static func storedAccentColor(in defaults: UserDefaults = .standard) -> Color { - Contrast.legible(stored(in: defaults).color, on: FlixyColor.canvas).swiftUIColor + Contrast.legible(stored(in: defaults).color, on: HaloColor.canvas).swiftUIColor } } diff --git a/Packages/FlixyKit/Sources/FlixyDesign/Color/Contrast.swift b/Packages/HaloKit/Sources/HaloDesign/Color/Contrast.swift similarity index 97% rename from Packages/FlixyKit/Sources/FlixyDesign/Color/Contrast.swift rename to Packages/HaloKit/Sources/HaloDesign/Color/Contrast.swift index a513a25..7a0609f 100644 --- a/Packages/FlixyKit/Sources/FlixyDesign/Color/Contrast.swift +++ b/Packages/HaloKit/Sources/HaloDesign/Color/Contrast.swift @@ -2,7 +2,7 @@ import Foundation /// Kontrastrechnung nach WCAG 2.1. /// -/// Gebraucht wird sie für die eigene Akzentfarbe: Flixy lässt jede Farbe zu, +/// Gebraucht wird sie für die eigene Akzentfarbe: Halo lässt jede Farbe zu, /// aber ein dunkles Marineblau auf fast schwarzem Grund ist als Schrift oder /// Symbol unlesbar. `legible(_:on:)` hebt solche Farben so weit an, bis sie /// den geforderten Kontrast erreichen — und lässt alles in Ruhe, was ihn diff --git a/Packages/FlixyKit/Sources/FlixyDesign/Color/HSB.swift b/Packages/HaloKit/Sources/HaloDesign/Color/HSB.swift similarity index 100% rename from Packages/FlixyKit/Sources/FlixyDesign/Color/HSB.swift rename to Packages/HaloKit/Sources/HaloDesign/Color/HSB.swift diff --git a/Packages/FlixyKit/Sources/FlixyDesign/Color/FlixyColor.swift b/Packages/HaloKit/Sources/HaloDesign/Color/HaloColor.swift similarity index 59% rename from Packages/FlixyKit/Sources/FlixyDesign/Color/FlixyColor.swift rename to Packages/HaloKit/Sources/HaloDesign/Color/HaloColor.swift index d55c197..1b2f169 100644 --- a/Packages/FlixyKit/Sources/FlixyDesign/Color/FlixyColor.swift +++ b/Packages/HaloKit/Sources/HaloDesign/Color/HaloColor.swift @@ -2,10 +2,10 @@ import SwiftUI /// Die Flächen- und Schriftfarben der App. /// -/// Flixy kennt nur den dunklen Modus — es gibt deshalb bewusst keine +/// Halo kennt nur den dunklen Modus — es gibt deshalb bewusst keine /// Hell-/Dunkel-Paare, sondern je einen festen Wert. Die einzige Farbe, die -/// sich zur Laufzeit ändert, ist der Akzent; er kommt aus `FlixyTheme`. -public enum FlixyColor { +/// sich zur Laufzeit ändert, ist der Akzent; er kommt aus `HaloTheme`. +public enum HaloColor { // Flächen, von hinten nach vorn gestaffelt. /// Der Seitenhintergrund. public static let canvas = RGB(hex: 0x0B0B0D) @@ -28,18 +28,18 @@ public enum FlixyColor { } extension Color { - public static let flixyCanvas = FlixyColor.canvas.swiftUIColor - public static let flixySurface = FlixyColor.surface.swiftUIColor - public static let flixyElevated = FlixyColor.elevated.swiftUIColor - public static let flixyPlaceholder = FlixyColor.placeholder.swiftUIColor - public static let flixyTextPrimary = FlixyColor.textPrimary.swiftUIColor - public static let flixyTextSecondary = FlixyColor.textSecondary.swiftUIColor - public static let flixyTextMuted = FlixyColor.textMuted.swiftUIColor - public static let flixyDestructive = FlixyColor.destructive.swiftUIColor + public static let haloCanvas = HaloColor.canvas.swiftUIColor + public static let haloSurface = HaloColor.surface.swiftUIColor + public static let haloElevated = HaloColor.elevated.swiftUIColor + public static let haloPlaceholder = HaloColor.placeholder.swiftUIColor + public static let haloTextPrimary = HaloColor.textPrimary.swiftUIColor + public static let haloTextSecondary = HaloColor.textSecondary.swiftUIColor + public static let haloTextMuted = HaloColor.textMuted.swiftUIColor + public static let haloDestructive = HaloColor.destructive.swiftUIColor /// Trennlinien und Ränder. Als Weiß mit Deckkraft statt als fester Wert, /// damit sie auf jeder Flächenstufe gleich zurückhaltend wirken. - public static let flixySeparator = Color.white.opacity(0.10) + public static let haloSeparator = Color.white.opacity(0.10) /// Die Abdunklung hinter der ausgefahrenen Seitenleiste. - public static let flixyScrim = Color.black.opacity(0.55) + public static let haloScrim = Color.black.opacity(0.55) } diff --git a/Packages/FlixyKit/Sources/FlixyDesign/Color/RGB.swift b/Packages/HaloKit/Sources/HaloDesign/Color/RGB.swift similarity index 100% rename from Packages/FlixyKit/Sources/FlixyDesign/Color/RGB.swift rename to Packages/HaloKit/Sources/HaloDesign/Color/RGB.swift diff --git a/Packages/FlixyKit/Sources/FlixyDesign/Components/ArtworkLoader.swift b/Packages/HaloKit/Sources/HaloDesign/Components/ArtworkLoader.swift similarity index 100% rename from Packages/FlixyKit/Sources/FlixyDesign/Components/ArtworkLoader.swift rename to Packages/HaloKit/Sources/HaloDesign/Components/ArtworkLoader.swift diff --git a/Packages/FlixyKit/Sources/FlixyDesign/Components/FlixyArtwork.swift b/Packages/HaloKit/Sources/HaloDesign/Components/HaloArtwork.swift similarity index 96% rename from Packages/FlixyKit/Sources/FlixyDesign/Components/FlixyArtwork.swift rename to Packages/HaloKit/Sources/HaloDesign/Components/HaloArtwork.swift index 14700bd..bf6e424 100644 --- a/Packages/FlixyKit/Sources/FlixyDesign/Components/FlixyArtwork.swift +++ b/Packages/HaloKit/Sources/HaloDesign/Components/HaloArtwork.swift @@ -7,7 +7,7 @@ import SwiftUI /// Startseite zeigt dutzende Bilder gleichzeitig, und `AsyncImage` lädt sie bei /// jedem Erscheinen neu. Auf dem Mac wurde daraus ein sichtbarer Fehler: der /// Aufmacher und die Hälfte der Plakate blieben grau. -public struct FlixyArtwork: View { +public struct HaloArtwork: View { /// Die Adressen, der Reihe nach probiert. /// /// **Warum mehrere.** Eine Folge hat selten ein eigenes Querformatbild, @@ -90,9 +90,9 @@ public struct FlixyArtwork: View { @ViewBuilder private var placeholder: some View { if fillsFrame { - Rectangle().fill(Color.flixyPlaceholder) + Rectangle().fill(Color.haloPlaceholder) } else { - Rectangle().fill(Color.flixyPlaceholder).aspectRatio(aspectRatio, contentMode: .fit) + Rectangle().fill(Color.haloPlaceholder).aspectRatio(aspectRatio, contentMode: .fit) } } @@ -124,7 +124,7 @@ public struct FlixyArtwork: View { // mehr Lärm als Hilfe. Das Symbol sagt genug. Image(systemName: fallbackSymbol) .font(.title2) - .foregroundStyle(Color.flixyTextMuted) + .foregroundStyle(Color.haloTextMuted) } else { ShimmerPlaceholder() } diff --git a/Packages/FlixyKit/Sources/FlixyDesign/Components/HeroBanner.swift b/Packages/HaloKit/Sources/HaloDesign/Components/HeroBanner.swift similarity index 91% rename from Packages/FlixyKit/Sources/FlixyDesign/Components/HeroBanner.swift rename to Packages/HaloKit/Sources/HaloDesign/Components/HeroBanner.swift index f3a430c..9a11321 100644 --- a/Packages/FlixyKit/Sources/FlixyDesign/Components/HeroBanner.swift +++ b/Packages/HaloKit/Sources/HaloDesign/Components/HeroBanner.swift @@ -81,7 +81,7 @@ public struct HeroBanner: View { // 3:4 — mit `scaledToFill` wurde das Bild dadurch links und rechts // kräftig beschnitten, und vom Aufmacher war nur ein Ausschnitt zu // sehen. - aspectRatio: CGFloat = FlixyAspectRatio.hero, + aspectRatio: CGFloat = HaloAspectRatio.hero, fillsAvailableSpace: Bool = false, @ViewBuilder actions: () -> Actions ) { @@ -114,16 +114,16 @@ public struct HeroBanner: View { /// Das Bild — und, solange gewechselt wird, das vorige darunter. /// - /// Ohne Wechsel ist es genau ein `FlixyArtwork` wie zuvor: die zweite + /// Ohne Wechsel ist es genau ein `HaloArtwork` wie zuvor: die zweite /// Ebene entsteht nur, wenn jemand eine vorige Adresse mitgibt. @ViewBuilder private var bild: some View { if outgoingArtworkURLs.isEmpty { - FlixyArtwork(urls: artworkURLs, aspectRatio: aspectRatio, fillsFrame: fillsAvailableSpace) + HaloArtwork(urls: artworkURLs, aspectRatio: aspectRatio, fillsFrame: fillsAvailableSpace) } else { ZStack { - FlixyArtwork(urls: outgoingArtworkURLs, aspectRatio: aspectRatio, fillsFrame: fillsAvailableSpace) - FlixyArtwork(urls: artworkURLs, aspectRatio: aspectRatio, fillsFrame: fillsAvailableSpace) + HaloArtwork(urls: outgoingArtworkURLs, aspectRatio: aspectRatio, fillsFrame: fillsAvailableSpace) + HaloArtwork(urls: artworkURLs, aspectRatio: aspectRatio, fillsFrame: fillsAvailableSpace) .opacity(crossfade) .offset(x: incomingOffset) } @@ -166,8 +166,8 @@ public struct HeroBanner: View { LinearGradient( stops: [ .init(color: .clear, location: 0), - .init(color: Color.flixyCanvas.opacity(0.75), location: 0.45), - .init(color: Color.flixyCanvas, location: 1), + .init(color: Color.haloCanvas.opacity(0.75), location: 0.45), + .init(color: Color.haloCanvas, location: 1), ], startPoint: .top, endPoint: .bottom @@ -250,7 +250,7 @@ public struct HeroBanner: View { logo: PlatformImage?, scale: CGFloat ) -> some View { - VStack(alignment: .leading, spacing: FlixySpacing.snug * scale) { + VStack(alignment: .leading, spacing: HaloSpacing.snug * scale) { if let logo { Image(platform: logo) .resizable() @@ -266,24 +266,24 @@ public struct HeroBanner: View { // eine Systemschrift. Text(title) .font(.system(size: 34 * scale, weight: .bold)) - .foregroundStyle(Color.flixyTextPrimary) + .foregroundStyle(Color.haloTextPrimary) .lineLimit(2) } if let metadataContent { metadataContent .font(.system(size: 12 * scale)) - .foregroundStyle(Color.flixyTextSecondary) + .foregroundStyle(Color.haloTextSecondary) } else if let metadata { Text(metadata) .font(.system(size: 12 * scale)) - .foregroundStyle(Color.flixyTextSecondary) + .foregroundStyle(Color.haloTextSecondary) } if let summary { Text(summary) .font(.system(size: 12 * scale)) - .foregroundStyle(Color.flixyTextSecondary) + .foregroundStyle(Color.haloTextSecondary) .lineLimit(2) // Ein Satz über die ganze Breite eines großen Fensters ist // unlesbar; das Auge verliert die Zeile. Achtzig Zeichen @@ -291,12 +291,12 @@ public struct HeroBanner: View { .frame(maxWidth: 640 * scale, alignment: .leading) } - HStack(spacing: FlixySpacing.regular) { + HStack(spacing: HaloSpacing.regular) { actions } - .padding(.top, FlixySpacing.tight) + .padding(.top, HaloSpacing.tight) } - .padding(.horizontal, FlixySpacing.screenMargin * scale) - .padding(.bottom, FlixySpacing.loose * scale) + .padding(.horizontal, HaloSpacing.screenMargin * scale) + .padding(.bottom, HaloSpacing.loose * scale) } } diff --git a/Packages/FlixyKit/Sources/FlixyDesign/Components/LandscapeCard.swift b/Packages/HaloKit/Sources/HaloDesign/Components/LandscapeCard.swift similarity index 73% rename from Packages/FlixyKit/Sources/FlixyDesign/Components/LandscapeCard.swift rename to Packages/HaloKit/Sources/HaloDesign/Components/LandscapeCard.swift index fd68024..e257a87 100644 --- a/Packages/FlixyKit/Sources/FlixyDesign/Components/LandscapeCard.swift +++ b/Packages/HaloKit/Sources/HaloDesign/Components/LandscapeCard.swift @@ -20,24 +20,24 @@ public struct LandscapeCard: View { } public var body: some View { - VStack(alignment: .leading, spacing: FlixySpacing.snug) { - FlixyArtwork(url: artworkURL, aspectRatio: Self.aspectRatio, fallbackSymbol: "play.rectangle") + VStack(alignment: .leading, spacing: HaloSpacing.snug) { + HaloArtwork(url: artworkURL, aspectRatio: Self.aspectRatio, fallbackSymbol: "play.rectangle") .overlay(alignment: .bottom) { if let progress { WatchProgressBar(fraction: progress) } } - .clipShape(.rect(cornerRadius: FlixyRadius.card)) + .clipShape(.rect(cornerRadius: HaloRadius.card)) VStack(alignment: .leading, spacing: 2) { Text(title) - .font(.flixyCardTitle) - .foregroundStyle(Color.flixyTextPrimary) + .font(.haloCardTitle) + .foregroundStyle(Color.haloTextPrimary) .lineLimit(1) if let subtitle { Text(subtitle) - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextMuted) + .font(.haloCaption) + .foregroundStyle(Color.haloTextMuted) .lineLimit(1) } } diff --git a/Packages/FlixyKit/Sources/FlixyDesign/Components/PlaceholderCard.swift b/Packages/HaloKit/Sources/HaloDesign/Components/PlaceholderCard.swift similarity index 89% rename from Packages/FlixyKit/Sources/FlixyDesign/Components/PlaceholderCard.swift rename to Packages/HaloKit/Sources/HaloDesign/Components/PlaceholderCard.swift index 9d98a48..b706b87 100644 --- a/Packages/FlixyKit/Sources/FlixyDesign/Components/PlaceholderCard.swift +++ b/Packages/HaloKit/Sources/HaloDesign/Components/PlaceholderCard.swift @@ -30,18 +30,18 @@ public struct PlaceholderCard: View { } public var body: some View { - VStack(alignment: .leading, spacing: FlixySpacing.snug) { - RoundedRectangle(cornerRadius: FlixyRadius.card) - .fill(Color.flixyElevated) + VStack(alignment: .leading, spacing: HaloSpacing.snug) { + RoundedRectangle(cornerRadius: HaloRadius.card) + .fill(Color.haloElevated) .aspectRatio(PosterCard.aspectRatio, contentMode: .fit) // Zwei Balken an der Stelle von Titel und Jahr. Ohne sie springt // die Zeile, sobald der echte Titel kommt. RoundedRectangle(cornerRadius: 3) - .fill(Color.flixyElevated) + .fill(Color.haloElevated) .frame(height: 10) RoundedRectangle(cornerRadius: 3) - .fill(Color.flixyElevated) + .fill(Color.haloElevated) .frame(width: 32, height: 8) } .opacity(isBright ? 0.85 : 0.45) diff --git a/Packages/FlixyKit/Sources/FlixyDesign/Components/PosterCard.swift b/Packages/HaloKit/Sources/HaloDesign/Components/PosterCard.swift similarity index 74% rename from Packages/FlixyKit/Sources/FlixyDesign/Components/PosterCard.swift rename to Packages/HaloKit/Sources/HaloDesign/Components/PosterCard.swift index 71ba608..c643501 100644 --- a/Packages/FlixyKit/Sources/FlixyDesign/Components/PosterCard.swift +++ b/Packages/HaloKit/Sources/HaloDesign/Components/PosterCard.swift @@ -19,25 +19,25 @@ public struct PosterCard: View { } public var body: some View { - VStack(alignment: .leading, spacing: FlixySpacing.snug) { - FlixyArtwork(url: artworkURL, aspectRatio: Self.aspectRatio) - .clipShape(.rect(cornerRadius: FlixyRadius.card)) + VStack(alignment: .leading, spacing: HaloSpacing.snug) { + HaloArtwork(url: artworkURL, aspectRatio: Self.aspectRatio) + .clipShape(.rect(cornerRadius: HaloRadius.card)) .overlay(alignment: .bottom) { if let progress { WatchProgressBar(fraction: progress) } } - .clipShape(.rect(cornerRadius: FlixyRadius.card)) + .clipShape(.rect(cornerRadius: HaloRadius.card)) VStack(alignment: .leading, spacing: 2) { Text(title) - .font(.flixyCardTitle) - .foregroundStyle(Color.flixyTextPrimary) + .font(.haloCardTitle) + .foregroundStyle(Color.haloTextPrimary) .lineLimit(1) if let subtitle { Text(subtitle) - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextMuted) + .font(.haloCaption) + .foregroundStyle(Color.haloTextMuted) .lineLimit(1) } } diff --git a/Packages/FlixyKit/Sources/FlixyDesign/Components/ShimmerPlaceholder.swift b/Packages/HaloKit/Sources/HaloDesign/Components/ShimmerPlaceholder.swift similarity index 97% rename from Packages/FlixyKit/Sources/FlixyDesign/Components/ShimmerPlaceholder.swift rename to Packages/HaloKit/Sources/HaloDesign/Components/ShimmerPlaceholder.swift index 09ee152..f9cbc3c 100644 --- a/Packages/FlixyKit/Sources/FlixyDesign/Components/ShimmerPlaceholder.swift +++ b/Packages/HaloKit/Sources/HaloDesign/Components/ShimmerPlaceholder.swift @@ -15,7 +15,7 @@ public struct ShimmerPlaceholder: View { public var body: some View { Rectangle() - .fill(Color.flixyPlaceholder) + .fill(Color.haloPlaceholder) .overlay { if !reduceMotion { GeometryReader { proxy in diff --git a/Packages/FlixyKit/Sources/FlixyDesign/Components/TVCards.swift b/Packages/HaloKit/Sources/HaloDesign/Components/TVCards.swift similarity index 90% rename from Packages/FlixyKit/Sources/FlixyDesign/Components/TVCards.swift rename to Packages/HaloKit/Sources/HaloDesign/Components/TVCards.swift index 185d344..a1c2710 100644 --- a/Packages/FlixyKit/Sources/FlixyDesign/Components/TVCards.swift +++ b/Packages/HaloKit/Sources/HaloDesign/Components/TVCards.swift @@ -10,7 +10,7 @@ import SwiftUI /// `scaleEffect` und ein Schatten — sieht auf den ersten Blick gleich aus und /// auf den zweiten falsch: die Parallaxe ist der Teil, den man wiedererkennt. /// -/// Liegt in FlixyDesign und nicht im Fernseh-Ziel, aus demselben Grund wie +/// Liegt in HaloDesign und nicht im Fernseh-Ziel, aus demselben Grund wie /// `PosterCard`: das Paket kennt weder `MediaItem` noch die Wiedergabe, und /// das soll so bleiben. Herein kommen Zeichenketten und Adressen. public struct TVPosterCard: View { @@ -100,7 +100,7 @@ public struct TVLandscapeCard: View { public var body: some View { TVCard( - aspectRatio: FlixyAspectRatio.landscape, + aspectRatio: HaloAspectRatio.landscape, title: title, subtitle: subtitle, artworkURL: artworkURL, @@ -124,13 +124,13 @@ private struct TVCard: View { let action: () -> Void var body: some View { - VStack(alignment: .leading, spacing: FlixySpacing.snug) { + VStack(alignment: .leading, spacing: HaloSpacing.snug) { Button(action: action) { - FlixyArtwork(url: artworkURL, aspectRatio: aspectRatio) + HaloArtwork(url: artworkURL, aspectRatio: aspectRatio) .overlay(alignment: .bottom) { if let progress { WatchProgressBar(fraction: progress) } } - .clipShape(.rect(cornerRadius: FlixyRadius.card)) + .clipShape(.rect(cornerRadius: HaloRadius.card)) } .buttonStyle(.card) .focused($isFocused) @@ -143,13 +143,13 @@ private struct TVCard: View { // Metern eine Textwand. VStack(alignment: .leading, spacing: 2) { Text(title) - .font(.flixyCardTitle) - .foregroundStyle(Color.flixyTextPrimary) + .font(.haloCardTitle) + .foregroundStyle(Color.haloTextPrimary) .lineLimit(1) if let subtitle { Text(subtitle) - .font(.flixyCaption) - .foregroundStyle(Color.flixyTextMuted) + .font(.haloCaption) + .foregroundStyle(Color.haloTextMuted) .lineLimit(1) } } diff --git a/Packages/FlixyKit/Sources/FlixyDesign/Components/WatchProgressBar.swift b/Packages/HaloKit/Sources/HaloDesign/Components/WatchProgressBar.swift similarity index 94% rename from Packages/FlixyKit/Sources/FlixyDesign/Components/WatchProgressBar.swift rename to Packages/HaloKit/Sources/HaloDesign/Components/WatchProgressBar.swift index 99d13f0..31b026c 100644 --- a/Packages/FlixyKit/Sources/FlixyDesign/Components/WatchProgressBar.swift +++ b/Packages/HaloKit/Sources/HaloDesign/Components/WatchProgressBar.swift @@ -5,7 +5,7 @@ public struct WatchProgressBar: View { /// 0…1. Werte außerhalb werden abgeschnitten, damit ein fehlerhafter /// Serverwert den Balken nicht über die Kachel hinausschieben kann. private let fraction: Double - @Environment(\.flixyAccent) private var accent + @Environment(\.haloAccent) private var accent public init(fraction: Double) { self.fraction = fraction.clamped() diff --git a/Packages/FlixyKit/Sources/FlixyDesign/GuideLayout.swift b/Packages/HaloKit/Sources/HaloDesign/GuideLayout.swift similarity index 100% rename from Packages/FlixyKit/Sources/FlixyDesign/GuideLayout.swift rename to Packages/HaloKit/Sources/HaloDesign/GuideLayout.swift diff --git a/Packages/FlixyKit/Sources/FlixyDesign/FlixyFont.swift b/Packages/HaloKit/Sources/HaloDesign/HaloFont.swift similarity index 82% rename from Packages/FlixyKit/Sources/FlixyDesign/FlixyFont.swift rename to Packages/HaloKit/Sources/HaloDesign/HaloFont.swift index fae9c56..964cb77 100644 --- a/Packages/FlixyKit/Sources/FlixyDesign/FlixyFont.swift +++ b/Packages/HaloKit/Sources/HaloDesign/HaloFont.swift @@ -24,17 +24,17 @@ import SwiftUI extension Font { #if os(macOS) /// Der Titel im Aufmacher-Bild. - public static let flixyHero = Font.system(size: 34, weight: .bold) + public static let haloHero = Font.system(size: 34, weight: .bold) /// Titel auf Detailseiten. - public static let flixyTitle = Font.system(size: 22, weight: .semibold) + public static let haloTitle = Font.system(size: 22, weight: .semibold) /// Überschrift einer Reihe auf der Startseite. - public static let flixyRowHeader = Font.system(size: 17, weight: .semibold) + public static let haloRowHeader = Font.system(size: 17, weight: .semibold) /// Titel unter einem Poster. - public static let flixyCardTitle = Font.system(size: 15, weight: .medium) + public static let haloCardTitle = Font.system(size: 15, weight: .medium) /// Fließtext, Beschreibungen. - public static let flixyBody = Font.system(size: 17) + public static let haloBody = Font.system(size: 17) /// Jahreszahl, Laufzeit, Auflösung — alles, was neben dem Titel steht. - public static let flixyCaption = Font.system(size: 12) + public static let haloCaption = Font.system(size: 12) #elseif os(tvOS) /// Der Titel im Aufmacher-Bild. /// @@ -43,34 +43,34 @@ extension Font { /// verfügbar markiert. Was SwiftUI daraus macht, steht nirgends, und eine /// Schrift, deren Grösse niemand nennen kann, gehört nicht in die grösste /// Zeile der App. - public static let flixyHero = Font.system(.title, design: .default, weight: .bold) + public static let haloHero = Font.system(.title, design: .default, weight: .bold) /// Titel auf Detailseiten. - public static let flixyTitle = Font.system(.title2, design: .default, weight: .semibold) + public static let haloTitle = Font.system(.title2, design: .default, weight: .semibold) /// Überschrift einer Reihe auf der Startseite. - public static let flixyRowHeader = Font.system(.headline, design: .default, weight: .semibold) + public static let haloRowHeader = Font.system(.headline, design: .default, weight: .semibold) /// Titel unter einem Poster — auf tvOS nur bei Fokus sichtbar. /// /// Eine Stufe tiefer als auf iOS, und das ist gewollt: auf tvOS ist /// `caption` schon gross, und ein Raster aus sechs Spalten mit /// `subheadline`-Titeln hätte mehr Schrift als Bild. - public static let flixyCardTitle = Font.system(.caption, design: .default, weight: .medium) + public static let haloCardTitle = Font.system(.caption, design: .default, weight: .medium) /// Fließtext, Beschreibungen. - public static let flixyBody = Font.system(.body) + public static let haloBody = Font.system(.body) /// Jahreszahl, Laufzeit, Auflösung — alles, was neben dem Titel steht. - public static let flixyCaption = Font.system(.caption2) + public static let haloCaption = Font.system(.caption2) #else /// Der Titel im Aufmacher-Bild. - public static let flixyHero = Font.system(.largeTitle, design: .default, weight: .bold) + public static let haloHero = Font.system(.largeTitle, design: .default, weight: .bold) /// Titel auf Detailseiten. - public static let flixyTitle = Font.system(.title2, design: .default, weight: .semibold) + public static let haloTitle = Font.system(.title2, design: .default, weight: .semibold) /// Überschrift einer Reihe auf der Startseite. - public static let flixyRowHeader = Font.system(.headline, design: .default, weight: .semibold) + public static let haloRowHeader = Font.system(.headline, design: .default, weight: .semibold) /// Titel unter einem Poster. - public static let flixyCardTitle = Font.system(.subheadline, design: .default, weight: .medium) + public static let haloCardTitle = Font.system(.subheadline, design: .default, weight: .medium) /// Fließtext, Beschreibungen. - public static let flixyBody = Font.system(.body) + public static let haloBody = Font.system(.body) /// Jahreszahl, Laufzeit, Auflösung — alles, was neben dem Titel steht. - public static let flixyCaption = Font.system(.caption) + public static let haloCaption = Font.system(.caption) #endif } @@ -78,7 +78,7 @@ extension Font { /// /// Eine Skala statt frei gewählter Zahlen: dadurch stimmen die Ränder zwischen /// Bildschirmen überein, ohne dass man sie einzeln nachmisst. -public enum FlixySpacing { +public enum HaloSpacing { #if os(tvOS) // Durchweg doppelt: ein Fernseher ist 1920 Punkte breit und wird aus drei // Metern gelesen. Acht Punkte Abstand sind dort keine Trennung mehr. @@ -124,15 +124,15 @@ public enum FlixySpacing { /// „neunzig" stimmt nicht; eine zweite Quelle nannte achtzig und hatte recht. /// /// **Und man bekommt sie geschenkt.** SwiftUI legt sie von selbst als -/// Sicherheitsrand an — deshalb steht in `FlixySpacing.screenMargin` nur die +/// Sicherheitsrand an — deshalb steht in `HaloSpacing.screenMargin` nur die /// Rinne innerhalb davon. Die Zahl hier ist für die Gegenrichtung: ein /// bildfüllender Aufmacher, der den Sicherheitsrand absichtlich übergeht und /// dessen Schrift trotzdem drinbleiben muss. -public enum FlixySafeArea { +public enum HaloSafeArea { public static let tv = EdgeInsets(top: 60, leading: 80, bottom: 60, trailing: 80) } -public enum FlixyRadius { +public enum HaloRadius { /// Die Ecke einer Kachel. /// /// Auf dem Fernseher grösser: eine Kachel, die sich beim Fokus anhebt, @@ -155,7 +155,7 @@ public enum FlixyRadius { /// beschneidet: ein 16:9-Hintergrundbild in einem 3:4-Rahmen verliert links /// und rechts je ein Viertel, und man sieht dem Ergebnis nicht an, dass etwas /// fehlt. -public enum FlixyAspectRatio { +public enum HaloAspectRatio { /// Kinoplakate im Hochformat. public static let poster: CGFloat = 2.0 / 3.0 /// Szenenbilder und Hintergrundbilder. diff --git a/Packages/FlixyKit/Sources/FlixyDesign/FlixyTheme.swift b/Packages/HaloKit/Sources/HaloDesign/HaloTheme.swift similarity index 93% rename from Packages/FlixyKit/Sources/FlixyDesign/FlixyTheme.swift rename to Packages/HaloKit/Sources/HaloDesign/HaloTheme.swift index 1ccaa6f..7af89e8 100644 --- a/Packages/FlixyKit/Sources/FlixyDesign/FlixyTheme.swift +++ b/Packages/HaloKit/Sources/HaloDesign/HaloTheme.swift @@ -7,7 +7,7 @@ import SwiftUI /// darauf zu achten. @MainActor @Observable -public final class FlixyTheme { +public final class HaloTheme { private let defaults: UserDefaults /// Was in den Einstellungen ausgewählt ist — unkorrigiert, damit die @@ -24,7 +24,7 @@ public final class FlixyTheme { /// Bei den kuratierten Werten ändert die Korrektur nichts — sie erfüllen /// den Grenzwert bereits. Sie greift nur bei eigenen Farben. public var accent: RGB { - Contrast.legible(selection.color, on: FlixyColor.canvas) + Contrast.legible(selection.color, on: HaloColor.canvas) } public var accentColor: Color { accent.swiftUIColor } diff --git a/Packages/FlixyKit/Sources/FlixyDesign/Localizable.xcstrings b/Packages/HaloKit/Sources/HaloDesign/Localizable.xcstrings similarity index 100% rename from Packages/FlixyKit/Sources/FlixyDesign/Localizable.xcstrings rename to Packages/HaloKit/Sources/HaloDesign/Localizable.xcstrings diff --git a/Packages/FlixyKit/Sources/FlixyDesign/MiniPlayerPlacement.swift b/Packages/HaloKit/Sources/HaloDesign/MiniPlayerPlacement.swift similarity index 97% rename from Packages/FlixyKit/Sources/FlixyDesign/MiniPlayerPlacement.swift rename to Packages/HaloKit/Sources/HaloDesign/MiniPlayerPlacement.swift index 44dc35a..adce732 100644 --- a/Packages/FlixyKit/Sources/FlixyDesign/MiniPlayerPlacement.swift +++ b/Packages/HaloKit/Sources/HaloDesign/MiniPlayerPlacement.swift @@ -24,7 +24,7 @@ public struct MiniPlayerPlacement: Sendable, Equatable { /// Fehler statt wie eine Entscheidung. public let inset: CGFloat - public init(bounds: CGSize, tile: CGSize, inset: CGFloat = FlixySpacing.regular) { + public init(bounds: CGSize, tile: CGSize, inset: CGFloat = HaloSpacing.regular) { self.bounds = bounds self.tile = tile self.inset = inset diff --git a/Packages/FlixyKit/Sources/FlixyDesign/PlatformShims.swift b/Packages/HaloKit/Sources/HaloDesign/PlatformShims.swift similarity index 89% rename from Packages/FlixyKit/Sources/FlixyDesign/PlatformShims.swift rename to Packages/HaloKit/Sources/HaloDesign/PlatformShims.swift index 4632fee..2bf99ef 100644 --- a/Packages/FlixyKit/Sources/FlixyDesign/PlatformShims.swift +++ b/Packages/HaloKit/Sources/HaloDesign/PlatformShims.swift @@ -13,7 +13,7 @@ import AppKit /// nirgends sonst. Sonst wandert er in zwanzig Dateien und wird beim /// nächsten Bildschirm vergessen. /// Auf was für einem Gerät läuft das hier gerade? -public enum FlixyPlatform { +public enum HaloPlatform { /// Läuft die App auf einem Mac? /// /// **Zwei Wege führen dorthin, und für den Übersetzer sehen sie @@ -43,7 +43,7 @@ public enum FlixyPlatform { #elseif os(macOS) true #else - #error("FlixyPlatform kennt diese Plattform nicht. Hier eintragen — nicht raten.") + #error("HaloPlatform kennt diese Plattform nicht. Hier eintragen — nicht raten.") #endif }() @@ -60,7 +60,7 @@ public enum FlixyPlatform { #elseif os(iOS) || os(macOS) false #else - #error("FlixyPlatform kennt diese Plattform nicht. Hier eintragen — nicht raten.") + #error("HaloPlatform kennt diese Plattform nicht. Hier eintragen — nicht raten.") #endif }() } @@ -68,7 +68,7 @@ public enum FlixyPlatform { extension View { /// Eine schmale Titelzeile — auf dem Mac und auf dem Fernseher gibt es /// sie nicht. Beide fallen in denselben `#else`-Zweig, und beide zu Recht. - public func flixyInlineTitle() -> some View { + public func haloInlineTitle() -> some View { #if os(iOS) navigationBarTitleDisplayMode(.inline) #else @@ -80,7 +80,7 @@ extension View { /// /// Auf dem Mac ist ein Sheet ein Fenster: dort zählt keine Rastung, /// sondern eine vernünftige Mindestgröße. - public func flixyMediumSheet() -> some View { + public func haloMediumSheet() -> some View { #if os(tvOS) // Auf dem Fernseher ist ein Sheet immer bildfüllend. `presentationDetents` // übersetzt dort zwar — es gibt sie seit tvOS 16 —, bewirkt aber @@ -92,18 +92,18 @@ extension View { // macOS griff nie: auf dem Mac läuft der iOS-Bau, und damit bekam ein // grosses Fenster eine Sheet-Kante in iPhone-Höhe — ein schmaler // Streifen, der unten im Nichts klebt. - presentationDetents(FlixyPlatform.isMac ? [.large] : [.medium]) + presentationDetents(HaloPlatform.isMac ? [.large] : [.medium]) #endif } /// Dasselbe, aber auf Wunsch bis zur vollen Höhe aufziehbar. - public func flixyResizableSheet() -> some View { + public func haloResizableSheet() -> some View { #if os(tvOS) self #else // Siehe oben. Auf dem Mac gibt es kein „halb aufgezogen": ein Fenster // hat die Höhe, die es hat, und eine Liste soll sie nutzen. - presentationDetents(FlixyPlatform.isMac ? [.large] : [.medium, .large]) + presentationDetents(HaloPlatform.isMac ? [.large] : [.medium, .large]) #endif } @@ -117,7 +117,7 @@ extension View { /// Stil ist derselbe, den iOS ohnehin nimmt — und der Grund, warum die /// Einstellungen auf dem Mac wie ein Systemdialog aus einem anderen /// Jahrzehnt aussahen. - public func flixyForm() -> some View { + public func haloForm() -> some View { #if os(macOS) formStyle(.grouped) #else @@ -130,7 +130,7 @@ extension View { /// /// Auf tvOS ebenfalls der `#else`-Zweig: die Bildschirmtastatur dort /// kennt weder `keyboardType` noch Autokorrektur in dieser Form. - public func flixyPlainEntry(isAddress: Bool = false) -> some View { + public func haloPlainEntry(isAddress: Bool = false) -> some View { #if os(iOS) self .keyboardType(isAddress ? .URL : .default) @@ -149,7 +149,7 @@ extension View { /// Leiste verschleierte die Hälfte davon. Auf dem Mac und auf dem /// Fernseher gibt es die Leiste in dieser Form nicht — beide fallen in /// den `#else`-Zweig. - public func flixyClearToolbarBackground() -> some View { + public func haloClearToolbarBackground() -> some View { #if os(iOS) self .toolbarBackground(.hidden, for: .navigationBar) @@ -164,7 +164,7 @@ extension View { /// /// UIKit und AppKit heißen verschieden und meinen dasselbe; die Diagnose soll /// deswegen nicht mit `#if` beginnen. -public enum FlixyClipboard { +public enum HaloClipboard { public static func copy(_ text: String) { #if os(tvOS) // Es gibt keine. `UIPasteboard` ist auf tvOS als nicht verfügbar @@ -186,7 +186,7 @@ public enum FlixyClipboard { extension ToolbarItemPlacement { /// Rechts in der Titelzeile. - public static var flixyTrailing: ToolbarItemPlacement { + public static var haloTrailing: ToolbarItemPlacement { #if os(iOS) || os(tvOS) .topBarTrailing #else @@ -195,7 +195,7 @@ extension ToolbarItemPlacement { } /// Links in der Titelzeile. - public static var flixyLeading: ToolbarItemPlacement { + public static var haloLeading: ToolbarItemPlacement { #if os(iOS) || os(tvOS) .topBarLeading #else diff --git a/Packages/FlixyKit/Sources/FlixyDownloads/DownloadRate.swift b/Packages/HaloKit/Sources/HaloDownloads/DownloadRate.swift similarity index 100% rename from Packages/FlixyKit/Sources/FlixyDownloads/DownloadRate.swift rename to Packages/HaloKit/Sources/HaloDownloads/DownloadRate.swift diff --git a/Packages/FlixyKit/Sources/FlixyDownloads/DownloadState.swift b/Packages/HaloKit/Sources/HaloDownloads/DownloadState.swift similarity index 100% rename from Packages/FlixyKit/Sources/FlixyDownloads/DownloadState.swift rename to Packages/HaloKit/Sources/HaloDownloads/DownloadState.swift diff --git a/Packages/FlixyKit/Sources/FlixyDownloads/Engine/DownloadActivityPresenter.swift b/Packages/HaloKit/Sources/HaloDownloads/Engine/DownloadActivityPresenter.swift similarity index 100% rename from Packages/FlixyKit/Sources/FlixyDownloads/Engine/DownloadActivityPresenter.swift rename to Packages/HaloKit/Sources/HaloDownloads/Engine/DownloadActivityPresenter.swift diff --git a/Packages/FlixyKit/Sources/FlixyDownloads/Engine/DownloadCoordinator.swift b/Packages/HaloKit/Sources/HaloDownloads/Engine/DownloadCoordinator.swift similarity index 98% rename from Packages/FlixyKit/Sources/FlixyDownloads/Engine/DownloadCoordinator.swift rename to Packages/HaloKit/Sources/HaloDownloads/Engine/DownloadCoordinator.swift index f4578e8..3cf9ab6 100644 --- a/Packages/FlixyKit/Sources/FlixyDownloads/Engine/DownloadCoordinator.swift +++ b/Packages/HaloKit/Sources/HaloDownloads/Engine/DownloadCoordinator.swift @@ -78,7 +78,7 @@ public enum DownloadRefusal: Error, Equatable, Sendable { public final class DownloadCoordinator { /// Die Kennung der Hintergrundsitzung. Muss über App-Starts hinweg gleich /// bleiben, sonst findet iOS die laufenden Übertragungen nicht wieder. - public static let sessionIdentifier = "com.scarriffleservices.flixy.downloads" + public static let sessionIdentifier = "com.scarriffleservices.halo.downloads" public private(set) var items: [DownloadItem] = [] /// Wie viel die Downloads insgesamt belegen. @@ -134,11 +134,11 @@ public final class DownloadCoordinator { } private enum Key { - static let wifiOnly = "flixy.downloads.wifiOnly" - static let storageLimit = "flixy.downloads.storageLimit" - static let deleteAfter = "flixy.downloads.deleteWatchedAfter" - static let keepUnwatched = "flixy.downloads.keepUnwatched" - static let maximumConcurrent = "flixy.downloads.maximumConcurrent" + static let wifiOnly = "halo.downloads.wifiOnly" + static let storageLimit = "halo.downloads.storageLimit" + static let deleteAfter = "halo.downloads.deleteWatchedAfter" + static let keepUnwatched = "halo.downloads.keepUnwatched" + static let maximumConcurrent = "halo.downloads.maximumConcurrent" } /// Der Container, nicht nur der Kontext. diff --git a/Packages/FlixyKit/Sources/FlixyDownloads/Engine/DownloadFileStore.swift b/Packages/HaloKit/Sources/HaloDownloads/Engine/DownloadFileStore.swift similarity index 100% rename from Packages/FlixyKit/Sources/FlixyDownloads/Engine/DownloadFileStore.swift rename to Packages/HaloKit/Sources/HaloDownloads/Engine/DownloadFileStore.swift diff --git a/Packages/FlixyKit/Sources/FlixyDownloads/Engine/DownloadRules.swift b/Packages/HaloKit/Sources/HaloDownloads/Engine/DownloadRules.swift similarity index 100% rename from Packages/FlixyKit/Sources/FlixyDownloads/Engine/DownloadRules.swift rename to Packages/HaloKit/Sources/HaloDownloads/Engine/DownloadRules.swift diff --git a/Packages/FlixyKit/Sources/FlixyDownloads/Localizable.xcstrings b/Packages/HaloKit/Sources/HaloDownloads/Localizable.xcstrings similarity index 100% rename from Packages/FlixyKit/Sources/FlixyDownloads/Localizable.xcstrings rename to Packages/HaloKit/Sources/HaloDownloads/Localizable.xcstrings diff --git a/Packages/FlixyKit/Sources/FlixyDownloads/Model/DownloadActivityAttributes.swift b/Packages/HaloKit/Sources/HaloDownloads/Model/DownloadActivityAttributes.swift similarity index 96% rename from Packages/FlixyKit/Sources/FlixyDownloads/Model/DownloadActivityAttributes.swift rename to Packages/HaloKit/Sources/HaloDownloads/Model/DownloadActivityAttributes.swift index 9281876..27db132 100644 --- a/Packages/FlixyKit/Sources/FlixyDownloads/Model/DownloadActivityAttributes.swift +++ b/Packages/HaloKit/Sources/HaloDownloads/Model/DownloadActivityAttributes.swift @@ -11,7 +11,7 @@ import ActivityKit /// Was im Sperrbildschirm und in der Dynamic Island steht. /// -/// Liegt in FlixyDownloads, weil App und Widget-Erweiterung denselben Typ +/// Liegt in HaloDownloads, weil App und Widget-Erweiterung denselben Typ /// brauchen — zwei getrennte Kopien wären die klassische Quelle für eine Live /// Activity, die sich nicht mehr aktualisieren lässt: ActivityKit gleicht die /// Typen über ihren vollen Namen ab. diff --git a/Packages/FlixyKit/Sources/FlixyDownloads/Model/DownloadItem.swift b/Packages/HaloKit/Sources/HaloDownloads/Model/DownloadItem.swift similarity index 100% rename from Packages/FlixyKit/Sources/FlixyDownloads/Model/DownloadItem.swift rename to Packages/HaloKit/Sources/HaloDownloads/Model/DownloadItem.swift diff --git a/Packages/FlixyKit/Sources/FlixyDownloads/TransferHold.swift b/Packages/HaloKit/Sources/HaloDownloads/TransferHold.swift similarity index 100% rename from Packages/FlixyKit/Sources/FlixyDownloads/TransferHold.swift rename to Packages/HaloKit/Sources/HaloDownloads/TransferHold.swift diff --git a/Packages/FlixyKit/Sources/FlixyPlayback/Decision/AudioTrackChooser.swift b/Packages/HaloKit/Sources/HaloPlayback/Decision/AudioTrackChooser.swift similarity index 100% rename from Packages/FlixyKit/Sources/FlixyPlayback/Decision/AudioTrackChooser.swift rename to Packages/HaloKit/Sources/HaloPlayback/Decision/AudioTrackChooser.swift diff --git a/Packages/FlixyKit/Sources/FlixyPlayback/Decision/DeviceCapabilities.swift b/Packages/HaloKit/Sources/HaloPlayback/Decision/DeviceCapabilities.swift similarity index 100% rename from Packages/FlixyKit/Sources/FlixyPlayback/Decision/DeviceCapabilities.swift rename to Packages/HaloKit/Sources/HaloPlayback/Decision/DeviceCapabilities.swift diff --git a/Packages/FlixyKit/Sources/FlixyPlayback/Decision/DowngradeRule.swift b/Packages/HaloKit/Sources/HaloPlayback/Decision/DowngradeRule.swift similarity index 100% rename from Packages/FlixyKit/Sources/FlixyPlayback/Decision/DowngradeRule.swift rename to Packages/HaloKit/Sources/HaloPlayback/Decision/DowngradeRule.swift diff --git a/Packages/FlixyKit/Sources/FlixyPlayback/Decision/LanguageCode.swift b/Packages/HaloKit/Sources/HaloPlayback/Decision/LanguageCode.swift similarity index 100% rename from Packages/FlixyKit/Sources/FlixyPlayback/Decision/LanguageCode.swift rename to Packages/HaloKit/Sources/HaloPlayback/Decision/LanguageCode.swift diff --git a/Packages/FlixyKit/Sources/FlixyPlayback/Decision/NetworkConditions.swift b/Packages/HaloKit/Sources/HaloPlayback/Decision/NetworkConditions.swift similarity index 94% rename from Packages/FlixyKit/Sources/FlixyPlayback/Decision/NetworkConditions.swift rename to Packages/HaloKit/Sources/HaloPlayback/Decision/NetworkConditions.swift index 662d713..cd41c88 100644 --- a/Packages/FlixyKit/Sources/FlixyPlayback/Decision/NetworkConditions.swift +++ b/Packages/HaloKit/Sources/HaloPlayback/Decision/NetworkConditions.swift @@ -29,7 +29,7 @@ public final class NetworkConditions { isConstrained = path.isConstrained } } - monitor.start(queue: DispatchQueue(label: "flixy.network")) + monitor.start(queue: DispatchQueue(label: "halo.network")) } deinit { diff --git a/Packages/FlixyKit/Sources/FlixyPlayback/Decision/PlaybackDecider.swift b/Packages/HaloKit/Sources/HaloPlayback/Decision/PlaybackDecider.swift similarity index 100% rename from Packages/FlixyKit/Sources/FlixyPlayback/Decision/PlaybackDecider.swift rename to Packages/HaloKit/Sources/HaloPlayback/Decision/PlaybackDecider.swift diff --git a/Packages/FlixyKit/Sources/FlixyPlayback/Decision/PlaybackDecision.swift b/Packages/HaloKit/Sources/HaloPlayback/Decision/PlaybackDecision.swift similarity index 100% rename from Packages/FlixyKit/Sources/FlixyPlayback/Decision/PlaybackDecision.swift rename to Packages/HaloKit/Sources/HaloPlayback/Decision/PlaybackDecision.swift diff --git a/Packages/FlixyKit/Sources/FlixyPlayback/Decision/PlaybackPolicy.swift b/Packages/HaloKit/Sources/HaloPlayback/Decision/PlaybackPolicy.swift similarity index 100% rename from Packages/FlixyKit/Sources/FlixyPlayback/Decision/PlaybackPolicy.swift rename to Packages/HaloKit/Sources/HaloPlayback/Decision/PlaybackPolicy.swift diff --git a/Packages/FlixyKit/Sources/FlixyPlayback/Decision/PlayerQuality.swift b/Packages/HaloKit/Sources/HaloPlayback/Decision/PlayerQuality.swift similarity index 100% rename from Packages/FlixyKit/Sources/FlixyPlayback/Decision/PlayerQuality.swift rename to Packages/HaloKit/Sources/HaloPlayback/Decision/PlayerQuality.swift diff --git a/Packages/FlixyKit/Sources/FlixyPlayback/Decision/StallLedger.swift b/Packages/HaloKit/Sources/HaloPlayback/Decision/StallLedger.swift similarity index 100% rename from Packages/FlixyKit/Sources/FlixyPlayback/Decision/StallLedger.swift rename to Packages/HaloKit/Sources/HaloPlayback/Decision/StallLedger.swift diff --git a/Packages/FlixyKit/Sources/FlixyPlayback/Decision/StreamHealth.swift b/Packages/HaloKit/Sources/HaloPlayback/Decision/StreamHealth.swift similarity index 100% rename from Packages/FlixyKit/Sources/FlixyPlayback/Decision/StreamHealth.swift rename to Packages/HaloKit/Sources/HaloPlayback/Decision/StreamHealth.swift diff --git a/Packages/FlixyKit/Sources/FlixyPlayback/Decision/TrackMenu.swift b/Packages/HaloKit/Sources/HaloPlayback/Decision/TrackMenu.swift similarity index 100% rename from Packages/FlixyKit/Sources/FlixyPlayback/Decision/TrackMenu.swift rename to Packages/HaloKit/Sources/HaloPlayback/Decision/TrackMenu.swift diff --git a/Packages/FlixyKit/Sources/FlixyPlayback/Decision/UpgradeRule.swift b/Packages/HaloKit/Sources/HaloPlayback/Decision/UpgradeRule.swift similarity index 100% rename from Packages/FlixyKit/Sources/FlixyPlayback/Decision/UpgradeRule.swift rename to Packages/HaloKit/Sources/HaloPlayback/Decision/UpgradeRule.swift diff --git a/Packages/FlixyKit/Sources/FlixyPlayback/Engine/AVPlayerEngine.swift b/Packages/HaloKit/Sources/HaloPlayback/Engine/AVPlayerEngine.swift similarity index 100% rename from Packages/FlixyKit/Sources/FlixyPlayback/Engine/AVPlayerEngine.swift rename to Packages/HaloKit/Sources/HaloPlayback/Engine/AVPlayerEngine.swift diff --git a/Packages/FlixyKit/Sources/FlixyPlayback/Engine/MediaTrack.swift b/Packages/HaloKit/Sources/HaloPlayback/Engine/MediaTrack.swift similarity index 100% rename from Packages/FlixyKit/Sources/FlixyPlayback/Engine/MediaTrack.swift rename to Packages/HaloKit/Sources/HaloPlayback/Engine/MediaTrack.swift diff --git a/Packages/FlixyKit/Sources/FlixyPlayback/Engine/PlaybackState.swift b/Packages/HaloKit/Sources/HaloPlayback/Engine/PlaybackState.swift similarity index 100% rename from Packages/FlixyKit/Sources/FlixyPlayback/Engine/PlaybackState.swift rename to Packages/HaloKit/Sources/HaloPlayback/Engine/PlaybackState.swift diff --git a/Packages/FlixyKit/Sources/FlixyPlayback/Engine/SubtitleStyle+AVFoundation.swift b/Packages/HaloKit/Sources/HaloPlayback/Engine/SubtitleStyle+AVFoundation.swift similarity index 100% rename from Packages/FlixyKit/Sources/FlixyPlayback/Engine/SubtitleStyle+AVFoundation.swift rename to Packages/HaloKit/Sources/HaloPlayback/Engine/SubtitleStyle+AVFoundation.swift diff --git a/Packages/FlixyKit/Sources/FlixyPlayback/Engine/SubtitleStyle.swift b/Packages/HaloKit/Sources/HaloPlayback/Engine/SubtitleStyle.swift similarity index 100% rename from Packages/FlixyKit/Sources/FlixyPlayback/Engine/SubtitleStyle.swift rename to Packages/HaloKit/Sources/HaloPlayback/Engine/SubtitleStyle.swift diff --git a/Packages/FlixyKit/Sources/FlixyPlayback/Engine/VideoPlayerEngine.swift b/Packages/HaloKit/Sources/HaloPlayback/Engine/VideoPlayerEngine.swift similarity index 100% rename from Packages/FlixyKit/Sources/FlixyPlayback/Engine/VideoPlayerEngine.swift rename to Packages/HaloKit/Sources/HaloPlayback/Engine/VideoPlayerEngine.swift diff --git a/Packages/FlixyKit/Sources/FlixyPlayback/Prefetch/LocalStreamServer.swift b/Packages/HaloKit/Sources/HaloPlayback/Prefetch/LocalStreamServer.swift similarity index 99% rename from Packages/FlixyKit/Sources/FlixyPlayback/Prefetch/LocalStreamServer.swift rename to Packages/HaloKit/Sources/HaloPlayback/Prefetch/LocalStreamServer.swift index 5c13463..01867f7 100644 --- a/Packages/FlixyKit/Sources/FlixyPlayback/Prefetch/LocalStreamServer.swift +++ b/Packages/HaloKit/Sources/HaloPlayback/Prefetch/LocalStreamServer.swift @@ -70,7 +70,7 @@ public actor LocalStreamServer { } private let cache: StreamCache - private let logger = Logger(subsystem: "app.flixy", category: "LocalStreamServer") + private let logger = Logger(subsystem: "app.halo", category: "LocalStreamServer") private var listener: NWListener? private var port: UInt16? private var playlist: String? diff --git a/Packages/FlixyKit/Sources/FlixyPlayback/Prefetch/MediaPlaylist.swift b/Packages/HaloKit/Sources/HaloPlayback/Prefetch/MediaPlaylist.swift similarity index 100% rename from Packages/FlixyKit/Sources/FlixyPlayback/Prefetch/MediaPlaylist.swift rename to Packages/HaloKit/Sources/HaloPlayback/Prefetch/MediaPlaylist.swift diff --git a/Packages/FlixyKit/Sources/FlixyPlayback/Prefetch/StreamCache.swift b/Packages/HaloKit/Sources/HaloPlayback/Prefetch/StreamCache.swift similarity index 98% rename from Packages/FlixyKit/Sources/FlixyPlayback/Prefetch/StreamCache.swift rename to Packages/HaloKit/Sources/HaloPlayback/Prefetch/StreamCache.swift index de1f602..ba5eee5 100644 --- a/Packages/FlixyKit/Sources/FlixyPlayback/Prefetch/StreamCache.swift +++ b/Packages/HaloKit/Sources/HaloPlayback/Prefetch/StreamCache.swift @@ -44,7 +44,7 @@ public actor StreamCache { private let policy: Policy private let session: URLSession private let directory: URL - private let logger = Logger(subsystem: "app.flixy", category: "StreamCache") + private let logger = Logger(subsystem: "app.halo", category: "StreamCache") /// Woher die Schnipsel wirklich kommen. private var upstream: URL? @@ -83,7 +83,7 @@ public actor StreamCache { self.session = URLSession(configuration: configuration) self.directory = FileManager.default.temporaryDirectory - .appending(path: "flixy-stream-\(UUID().uuidString)", directoryHint: .isDirectory) + .appending(path: "halo-stream-\(UUID().uuidString)", directoryHint: .isDirectory) try? FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true) } diff --git a/Packages/FlixyKit/Sources/FlixyProbe/Leiter.swift b/Packages/HaloKit/Sources/HaloProbe/Leiter.swift similarity index 99% rename from Packages/FlixyKit/Sources/FlixyProbe/Leiter.swift rename to Packages/HaloKit/Sources/HaloProbe/Leiter.swift index adcfce5..0c75312 100644 --- a/Packages/FlixyKit/Sources/FlixyProbe/Leiter.swift +++ b/Packages/HaloKit/Sources/HaloProbe/Leiter.swift @@ -172,9 +172,9 @@ func jellyfinLeiter(host: String) async { } let identity = JellyfinIdentity( - client: "Flixy-Probe", + client: "Halo-Probe", device: "Mac", - deviceID: "flixy-probe-" + UUID().uuidString, + deviceID: "halo-probe-" + UUID().uuidString, version: "1.0" ) let client = JellyfinClient(baseURL: basis, identity: identity) @@ -471,9 +471,9 @@ func zeigeSpuren(host: String, suche: String) async { guard let passwort = String(validatingCString: getpass("Passwort: ")), !passwort.isEmpty else { return } let identity = JellyfinIdentity( - client: "Flixy-Probe", + client: "Halo-Probe", device: "Mac", - deviceID: "flixy-probe-" + UUID().uuidString, + deviceID: "halo-probe-" + UUID().uuidString, version: "1.0" ) let client = JellyfinClient(baseURL: basis, identity: identity) diff --git a/Packages/FlixyKit/Sources/FlixyProbe/main.swift b/Packages/HaloKit/Sources/HaloProbe/main.swift similarity index 96% rename from Packages/FlixyKit/Sources/FlixyProbe/main.swift rename to Packages/HaloKit/Sources/HaloProbe/main.swift index cb53ef7..773f2c5 100644 --- a/Packages/FlixyKit/Sources/FlixyProbe/main.swift +++ b/Packages/HaloKit/Sources/HaloProbe/main.swift @@ -46,7 +46,7 @@ if let index = CommandLine.arguments.firstIndex(of: "--jellyfin"), // Kein Modus erkannt. Ohne diesen Hinweis endete das Werkzeug wortlos — und // ein Tippfehler im Argument sähe aus wie ein Server, der nichts liefert. print(""" - FlixyProbe — fragt Server über reines HTTP, ohne Oberfläche und ohne Gerät. + HaloProbe — fragt Server über reines HTTP, ohne Oberfläche und ohne Gerät. --playlist Eine HLS-Leiter prüfen: Varianten, Tonspuren, erster Schnipsel diff --git a/Packages/FlixyKit/Sources/JellyfinKit/JellyfinAddress.swift b/Packages/HaloKit/Sources/JellyfinKit/JellyfinAddress.swift similarity index 100% rename from Packages/FlixyKit/Sources/JellyfinKit/JellyfinAddress.swift rename to Packages/HaloKit/Sources/JellyfinKit/JellyfinAddress.swift diff --git a/Packages/FlixyKit/Sources/JellyfinKit/JellyfinAuthenticator.swift b/Packages/HaloKit/Sources/JellyfinKit/JellyfinAuthenticator.swift similarity index 98% rename from Packages/FlixyKit/Sources/JellyfinKit/JellyfinAuthenticator.swift rename to Packages/HaloKit/Sources/JellyfinKit/JellyfinAuthenticator.swift index 0f98da0..18bd93e 100644 --- a/Packages/FlixyKit/Sources/JellyfinKit/JellyfinAuthenticator.swift +++ b/Packages/HaloKit/Sources/JellyfinKit/JellyfinAuthenticator.swift @@ -54,7 +54,7 @@ public struct QuickConnectRequest: Sendable, Equatable, Decodable { /// /// **Quick Connect** ist der erste: die App zeigt einen sechsstelligen Code, /// den man in einem bereits angemeldeten Client bestätigt. Das Passwort -/// erreicht Flixy dabei nie — dieselbe Zusage, die bei Plex gilt, wo die +/// erreicht Halo dabei nie — dieselbe Zusage, die bei Plex gilt, wo die /// Anmeldemaske von Plex selbst kommt. /// /// **Benutzername und Passwort** sind der Rückfall, falls der Server Quick diff --git a/Packages/FlixyKit/Sources/JellyfinKit/JellyfinBackend+LiveTV.swift b/Packages/HaloKit/Sources/JellyfinKit/JellyfinBackend+LiveTV.swift similarity index 100% rename from Packages/FlixyKit/Sources/JellyfinKit/JellyfinBackend+LiveTV.swift rename to Packages/HaloKit/Sources/JellyfinKit/JellyfinBackend+LiveTV.swift diff --git a/Packages/FlixyKit/Sources/JellyfinKit/JellyfinBackend+Playback.swift b/Packages/HaloKit/Sources/JellyfinKit/JellyfinBackend+Playback.swift similarity index 100% rename from Packages/FlixyKit/Sources/JellyfinKit/JellyfinBackend+Playback.swift rename to Packages/HaloKit/Sources/JellyfinKit/JellyfinBackend+Playback.swift diff --git a/Packages/FlixyKit/Sources/JellyfinKit/JellyfinBackend+Recordings.swift b/Packages/HaloKit/Sources/JellyfinKit/JellyfinBackend+Recordings.swift similarity index 100% rename from Packages/FlixyKit/Sources/JellyfinKit/JellyfinBackend+Recordings.swift rename to Packages/HaloKit/Sources/JellyfinKit/JellyfinBackend+Recordings.swift diff --git a/Packages/FlixyKit/Sources/JellyfinKit/JellyfinBackend+Segments.swift b/Packages/HaloKit/Sources/JellyfinKit/JellyfinBackend+Segments.swift similarity index 100% rename from Packages/FlixyKit/Sources/JellyfinKit/JellyfinBackend+Segments.swift rename to Packages/HaloKit/Sources/JellyfinKit/JellyfinBackend+Segments.swift diff --git a/Packages/FlixyKit/Sources/JellyfinKit/JellyfinBackend.swift b/Packages/HaloKit/Sources/JellyfinKit/JellyfinBackend.swift similarity index 99% rename from Packages/FlixyKit/Sources/JellyfinKit/JellyfinBackend.swift rename to Packages/HaloKit/Sources/JellyfinKit/JellyfinBackend.swift index a6010e9..17a510f 100644 --- a/Packages/FlixyKit/Sources/JellyfinKit/JellyfinBackend.swift +++ b/Packages/HaloKit/Sources/JellyfinKit/JellyfinBackend.swift @@ -453,7 +453,7 @@ public func isInLocalNetwork() async -> Bool { private static func transcodeSession(itemID: String, deviceID: String) -> [URLQueryItem] { [ URLQueryItem(name: "deviceId", value: deviceID), - URLQueryItem(name: "playSessionId", value: "flixy-\(UUID().uuidString)"), + URLQueryItem(name: "playSessionId", value: "halo-\(UUID().uuidString)"), ] } diff --git a/Packages/FlixyKit/Sources/JellyfinKit/JellyfinClient.swift b/Packages/HaloKit/Sources/JellyfinKit/JellyfinClient.swift similarity index 100% rename from Packages/FlixyKit/Sources/JellyfinKit/JellyfinClient.swift rename to Packages/HaloKit/Sources/JellyfinKit/JellyfinClient.swift diff --git a/Packages/FlixyKit/Sources/JellyfinKit/JellyfinIdentity+Current.swift b/Packages/HaloKit/Sources/JellyfinKit/JellyfinIdentity+Current.swift similarity index 95% rename from Packages/FlixyKit/Sources/JellyfinKit/JellyfinIdentity+Current.swift rename to Packages/HaloKit/Sources/JellyfinKit/JellyfinIdentity+Current.swift index 1a5a6c1..480b233 100644 --- a/Packages/FlixyKit/Sources/JellyfinKit/JellyfinIdentity+Current.swift +++ b/Packages/HaloKit/Sources/JellyfinKit/JellyfinIdentity+Current.swift @@ -4,7 +4,7 @@ import UIKit #endif extension JellyfinIdentity { - private static let storageKey = "flixy.jellyfin.deviceID" + private static let storageKey = "halo.jellyfin.deviceID" /// Baut die Kennung für das laufende Gerät und merkt sie sich. /// diff --git a/Packages/FlixyKit/Sources/JellyfinKit/JellyfinItem+Media.swift b/Packages/HaloKit/Sources/JellyfinKit/JellyfinItem+Media.swift similarity index 100% rename from Packages/FlixyKit/Sources/JellyfinKit/JellyfinItem+Media.swift rename to Packages/HaloKit/Sources/JellyfinKit/JellyfinItem+Media.swift diff --git a/Packages/FlixyKit/Sources/JellyfinKit/JellyfinItem.swift b/Packages/HaloKit/Sources/JellyfinKit/JellyfinItem.swift similarity index 100% rename from Packages/FlixyKit/Sources/JellyfinKit/JellyfinItem.swift rename to Packages/HaloKit/Sources/JellyfinKit/JellyfinItem.swift diff --git a/Packages/FlixyKit/Sources/JellyfinKit/JellyfinLibraryMemo.swift b/Packages/HaloKit/Sources/JellyfinKit/JellyfinLibraryMemo.swift similarity index 100% rename from Packages/FlixyKit/Sources/JellyfinKit/JellyfinLibraryMemo.swift rename to Packages/HaloKit/Sources/JellyfinKit/JellyfinLibraryMemo.swift diff --git a/Packages/FlixyKit/Sources/JellyfinKit/Localizable.xcstrings b/Packages/HaloKit/Sources/JellyfinKit/Localizable.xcstrings similarity index 100% rename from Packages/FlixyKit/Sources/JellyfinKit/Localizable.xcstrings rename to Packages/HaloKit/Sources/JellyfinKit/Localizable.xcstrings diff --git a/Packages/FlixyKit/Sources/MediaKit/Arrangement.swift b/Packages/HaloKit/Sources/MediaKit/Arrangement.swift similarity index 100% rename from Packages/FlixyKit/Sources/MediaKit/Arrangement.swift rename to Packages/HaloKit/Sources/MediaKit/Arrangement.swift diff --git a/Packages/FlixyKit/Sources/MediaKit/Duration+Units.swift b/Packages/HaloKit/Sources/MediaKit/Duration+Units.swift similarity index 100% rename from Packages/FlixyKit/Sources/MediaKit/Duration+Units.swift rename to Packages/HaloKit/Sources/MediaKit/Duration+Units.swift diff --git a/Packages/FlixyKit/Sources/MediaKit/EpisodeSelection.swift b/Packages/HaloKit/Sources/MediaKit/EpisodeSelection.swift similarity index 100% rename from Packages/FlixyKit/Sources/MediaKit/EpisodeSelection.swift rename to Packages/HaloKit/Sources/MediaKit/EpisodeSelection.swift diff --git a/Packages/FlixyKit/Sources/MediaKit/HeroSelection.swift b/Packages/HaloKit/Sources/MediaKit/HeroSelection.swift similarity index 100% rename from Packages/FlixyKit/Sources/MediaKit/HeroSelection.swift rename to Packages/HaloKit/Sources/MediaKit/HeroSelection.swift diff --git a/Packages/FlixyKit/Sources/MediaKit/LibraryCache.swift b/Packages/HaloKit/Sources/MediaKit/LibraryCache.swift similarity index 98% rename from Packages/FlixyKit/Sources/MediaKit/LibraryCache.swift rename to Packages/HaloKit/Sources/MediaKit/LibraryCache.swift index 5aafd18..4995a51 100644 --- a/Packages/FlixyKit/Sources/MediaKit/LibraryCache.swift +++ b/Packages/HaloKit/Sources/MediaKit/LibraryCache.swift @@ -47,7 +47,7 @@ public actor LibraryCache { } private let root: URL - private let logger = Logger(subsystem: "app.flixy", category: "LibraryCache") + private let logger = Logger(subsystem: "app.halo", category: "LibraryCache") /// Wie viele Titel höchstens gespeichert werden. /// diff --git a/Packages/FlixyKit/Sources/MediaKit/LiveTV.swift b/Packages/HaloKit/Sources/MediaKit/LiveTV.swift similarity index 100% rename from Packages/FlixyKit/Sources/MediaKit/LiveTV.swift rename to Packages/HaloKit/Sources/MediaKit/LiveTV.swift diff --git a/Packages/FlixyKit/Sources/MediaKit/MediaBackend.swift b/Packages/HaloKit/Sources/MediaKit/MediaBackend.swift similarity index 100% rename from Packages/FlixyKit/Sources/MediaKit/MediaBackend.swift rename to Packages/HaloKit/Sources/MediaKit/MediaBackend.swift diff --git a/Packages/FlixyKit/Sources/MediaKit/MediaBackendError.swift b/Packages/HaloKit/Sources/MediaKit/MediaBackendError.swift similarity index 100% rename from Packages/FlixyKit/Sources/MediaKit/MediaBackendError.swift rename to Packages/HaloKit/Sources/MediaKit/MediaBackendError.swift diff --git a/Packages/FlixyKit/Sources/MediaKit/MediaItem.swift b/Packages/HaloKit/Sources/MediaKit/MediaItem.swift similarity index 100% rename from Packages/FlixyKit/Sources/MediaKit/MediaItem.swift rename to Packages/HaloKit/Sources/MediaKit/MediaItem.swift diff --git a/Packages/FlixyKit/Sources/MediaKit/MediaLibrary.swift b/Packages/HaloKit/Sources/MediaKit/MediaLibrary.swift similarity index 100% rename from Packages/FlixyKit/Sources/MediaKit/MediaLibrary.swift rename to Packages/HaloKit/Sources/MediaKit/MediaLibrary.swift diff --git a/Packages/FlixyKit/Sources/MediaKit/MediaPlayback.swift b/Packages/HaloKit/Sources/MediaKit/MediaPlayback.swift similarity index 100% rename from Packages/FlixyKit/Sources/MediaKit/MediaPlayback.swift rename to Packages/HaloKit/Sources/MediaKit/MediaPlayback.swift diff --git a/Packages/FlixyKit/Sources/MediaKit/MediaProfile.swift b/Packages/HaloKit/Sources/MediaKit/MediaProfile.swift similarity index 100% rename from Packages/FlixyKit/Sources/MediaKit/MediaProfile.swift rename to Packages/HaloKit/Sources/MediaKit/MediaProfile.swift diff --git a/Packages/FlixyKit/Sources/MediaKit/MediaQuery.swift b/Packages/HaloKit/Sources/MediaKit/MediaQuery.swift similarity index 100% rename from Packages/FlixyKit/Sources/MediaKit/MediaQuery.swift rename to Packages/HaloKit/Sources/MediaKit/MediaQuery.swift diff --git a/Packages/FlixyKit/Sources/MediaKit/MediaVersion.swift b/Packages/HaloKit/Sources/MediaKit/MediaVersion.swift similarity index 100% rename from Packages/FlixyKit/Sources/MediaKit/MediaVersion.swift rename to Packages/HaloKit/Sources/MediaKit/MediaVersion.swift diff --git a/Packages/FlixyKit/Sources/MediaKit/PagingWindow.swift b/Packages/HaloKit/Sources/MediaKit/PagingWindow.swift similarity index 100% rename from Packages/FlixyKit/Sources/MediaKit/PagingWindow.swift rename to Packages/HaloKit/Sources/MediaKit/PagingWindow.swift diff --git a/Packages/FlixyKit/Sources/MediaKit/TokenStore.swift b/Packages/HaloKit/Sources/MediaKit/TokenStore.swift similarity index 100% rename from Packages/FlixyKit/Sources/MediaKit/TokenStore.swift rename to Packages/HaloKit/Sources/MediaKit/TokenStore.swift diff --git a/Packages/FlixyKit/Sources/MediaKit/TopShelfSnapshot.swift b/Packages/HaloKit/Sources/MediaKit/TopShelfSnapshot.swift similarity index 100% rename from Packages/FlixyKit/Sources/MediaKit/TopShelfSnapshot.swift rename to Packages/HaloKit/Sources/MediaKit/TopShelfSnapshot.swift diff --git a/Packages/FlixyKit/Sources/MediaKit/VideoResolution.swift b/Packages/HaloKit/Sources/MediaKit/VideoResolution.swift similarity index 100% rename from Packages/FlixyKit/Sources/MediaKit/VideoResolution.swift rename to Packages/HaloKit/Sources/MediaKit/VideoResolution.swift diff --git a/Packages/FlixyKit/Tests/FlixyDesignTests/ContrastTests.swift b/Packages/HaloKit/Tests/HaloDesignTests/ContrastTests.swift similarity index 96% rename from Packages/FlixyKit/Tests/FlixyDesignTests/ContrastTests.swift rename to Packages/HaloKit/Tests/HaloDesignTests/ContrastTests.swift index 550176b..eb20689 100644 --- a/Packages/FlixyKit/Tests/FlixyDesignTests/ContrastTests.swift +++ b/Packages/HaloKit/Tests/HaloDesignTests/ContrastTests.swift @@ -1,10 +1,10 @@ import Foundation import Testing -@testable import FlixyDesign +@testable import HaloDesign @Suite("Kontrastkorrektur") struct ContrastTests { - private let canvas = FlixyColor.canvas + private let canvas = HaloColor.canvas @Test("Schwarz zu Weiß ergibt das Maximum von 21:1") func extremesProduceMaximumRatio() { @@ -73,7 +73,7 @@ struct AccentPaletteTests { // hier durch, gehört sie nicht in die Palette — nicht in die // Korrektur. for option in AccentOption.palette { - let ratio = Contrast.ratio(option.color, FlixyColor.canvas) + let ratio = Contrast.ratio(option.color, HaloColor.canvas) #expect( ratio >= Contrast.minimumForText, "\(option.id) erreicht nur \(String(format: "%.2f", ratio)):1" @@ -146,7 +146,7 @@ struct DefaultAccentTests { @Test("Die Voreinstellung braucht keine Kontrastkorrektur") func defaultNeedsNoCorrection() { - let corrected = Contrast.legible(AccentOption.default.color, on: FlixyColor.canvas) + let corrected = Contrast.legible(AccentOption.default.color, on: HaloColor.canvas) #expect(corrected == AccentOption.default.color) } } @@ -154,7 +154,7 @@ struct DefaultAccentTests { @Suite("Gespeicherte Akzentfarbe") struct AccentStorageTests { private func freshDefaults() -> UserDefaults { - UserDefaults(suiteName: "flixy.accent.tests.\(UUID().uuidString)")! + UserDefaults(suiteName: "halo.accent.tests.\(UUID().uuidString)")! } @Test("Ohne gespeicherte Auswahl gilt die Voreinstellung") @@ -200,7 +200,7 @@ struct AccentStorageTests { let defaults = freshDefaults() AccentOption.custom(RGB(hex: 0x8B5CF6)).store(in: defaults) - let theme = FlixyTheme(defaults: defaults) + let theme = HaloTheme(defaults: defaults) #expect(theme.accentColor == AccentOption.storedAccentColor(in: defaults)) } } diff --git a/Packages/FlixyKit/Tests/FlixyDesignTests/GuideLayoutTests.swift b/Packages/HaloKit/Tests/HaloDesignTests/GuideLayoutTests.swift similarity index 99% rename from Packages/FlixyKit/Tests/FlixyDesignTests/GuideLayoutTests.swift rename to Packages/HaloKit/Tests/HaloDesignTests/GuideLayoutTests.swift index 50e60bb..b1e63e4 100644 --- a/Packages/FlixyKit/Tests/FlixyDesignTests/GuideLayoutTests.swift +++ b/Packages/HaloKit/Tests/HaloDesignTests/GuideLayoutTests.swift @@ -1,6 +1,6 @@ import Foundation import Testing -@testable import FlixyDesign +@testable import HaloDesign /// Die Geometrie des Programmrasters. @Suite("Raster-Geometrie") diff --git a/Packages/FlixyKit/Tests/FlixyDesignTests/FlixyPlatformTests.swift b/Packages/HaloKit/Tests/HaloDesignTests/HaloPlatformTests.swift similarity index 87% rename from Packages/FlixyKit/Tests/FlixyDesignTests/FlixyPlatformTests.swift rename to Packages/HaloKit/Tests/HaloDesignTests/HaloPlatformTests.swift index d050d42..8009be8 100644 --- a/Packages/FlixyKit/Tests/FlixyDesignTests/FlixyPlatformTests.swift +++ b/Packages/HaloKit/Tests/HaloDesignTests/HaloPlatformTests.swift @@ -1,8 +1,8 @@ import Testing -@testable import FlixyDesign +@testable import HaloDesign @Suite("Auf welchem Gerät wir laufen") -struct FlixyPlatformTests { +struct HaloPlatformTests { /// **Der Test, den es vorher nicht gab — und der gefehlt hat.** /// @@ -17,6 +17,6 @@ struct FlixyPlatformTests { /// hält er wenigstens fest, dass die Frage gestellt gehört. @Test("Ein Gerät ist nicht zugleich Mac und Fernseher") func neverBoth() { - #expect(!(FlixyPlatform.isMac && FlixyPlatform.isTV)) + #expect(!(HaloPlatform.isMac && HaloPlatform.isTV)) } } diff --git a/Packages/FlixyKit/Tests/FlixyDesignTests/MiniPlayerPlacementTests.swift b/Packages/HaloKit/Tests/HaloDesignTests/MiniPlayerPlacementTests.swift similarity index 99% rename from Packages/FlixyKit/Tests/FlixyDesignTests/MiniPlayerPlacementTests.swift rename to Packages/HaloKit/Tests/HaloDesignTests/MiniPlayerPlacementTests.swift index 6863ac4..8d882c2 100644 --- a/Packages/FlixyKit/Tests/FlixyDesignTests/MiniPlayerPlacementTests.swift +++ b/Packages/HaloKit/Tests/HaloDesignTests/MiniPlayerPlacementTests.swift @@ -1,6 +1,6 @@ import Foundation import Testing -@testable import FlixyDesign +@testable import HaloDesign /// Wo die schwebende Videokachel landet. @Suite("Kachel-Platzierung") diff --git a/Packages/FlixyKit/Tests/FlixyDownloadsTests/DownloadCoordinatorTests.swift b/Packages/HaloKit/Tests/HaloDownloadsTests/DownloadCoordinatorTests.swift similarity index 98% rename from Packages/FlixyKit/Tests/FlixyDownloadsTests/DownloadCoordinatorTests.swift rename to Packages/HaloKit/Tests/HaloDownloadsTests/DownloadCoordinatorTests.swift index 2da77d5..4aa502e 100644 --- a/Packages/FlixyKit/Tests/FlixyDownloadsTests/DownloadCoordinatorTests.swift +++ b/Packages/HaloKit/Tests/HaloDownloadsTests/DownloadCoordinatorTests.swift @@ -1,7 +1,7 @@ import Foundation import SwiftData import Testing -@testable import FlixyDownloads +@testable import HaloDownloads /// Baut einen Koordinator, der nichts überträgt. /// @@ -16,7 +16,7 @@ private func makeCoordinator( for: DownloadItem.self, configurations: ModelConfiguration(isStoredInMemoryOnly: true) ) - let defaults = UserDefaults(suiteName: "flixy.tests.\(UUID().uuidString)")! + let defaults = UserDefaults(suiteName: "halo.tests.\(UUID().uuidString)")! let coordinator = DownloadCoordinator( container: container, @@ -48,7 +48,7 @@ private func plan( } private func temporaryRoot() -> URL { - FileManager.default.temporaryDirectory.appending(path: "flixy-tests-\(UUID().uuidString)") + FileManager.default.temporaryDirectory.appending(path: "halo-tests-\(UUID().uuidString)") } @MainActor diff --git a/Packages/FlixyKit/Tests/FlixyDownloadsTests/DownloadRateTests.swift b/Packages/HaloKit/Tests/HaloDownloadsTests/DownloadRateTests.swift similarity index 99% rename from Packages/FlixyKit/Tests/FlixyDownloadsTests/DownloadRateTests.swift rename to Packages/HaloKit/Tests/HaloDownloadsTests/DownloadRateTests.swift index a7d1259..a62586b 100644 --- a/Packages/FlixyKit/Tests/FlixyDownloadsTests/DownloadRateTests.swift +++ b/Packages/HaloKit/Tests/HaloDownloadsTests/DownloadRateTests.swift @@ -1,5 +1,5 @@ import Testing -@testable import FlixyDownloads +@testable import HaloDownloads @Suite("Downloadrate und Restzeit") struct DownloadRateTests { diff --git a/Packages/FlixyKit/Tests/FlixyDownloadsTests/DownloadRulesTests.swift b/Packages/HaloKit/Tests/HaloDownloadsTests/DownloadRulesTests.swift similarity index 99% rename from Packages/FlixyKit/Tests/FlixyDownloadsTests/DownloadRulesTests.swift rename to Packages/HaloKit/Tests/HaloDownloadsTests/DownloadRulesTests.swift index c51ddfd..0af6a94 100644 --- a/Packages/FlixyKit/Tests/FlixyDownloadsTests/DownloadRulesTests.swift +++ b/Packages/HaloKit/Tests/HaloDownloadsTests/DownloadRulesTests.swift @@ -1,7 +1,7 @@ import Foundation import MediaKit import Testing -@testable import FlixyDownloads +@testable import HaloDownloads /// Baut einen Eintrag im gewünschten Zustand, ohne Datenbank. @MainActor diff --git a/Packages/FlixyKit/Tests/FlixyDownloadsTests/DownloadStateTests.swift b/Packages/HaloKit/Tests/HaloDownloadsTests/DownloadStateTests.swift similarity index 99% rename from Packages/FlixyKit/Tests/FlixyDownloadsTests/DownloadStateTests.swift rename to Packages/HaloKit/Tests/HaloDownloadsTests/DownloadStateTests.swift index 7ab5042..b1b1d14 100644 --- a/Packages/FlixyKit/Tests/FlixyDownloadsTests/DownloadStateTests.swift +++ b/Packages/HaloKit/Tests/HaloDownloadsTests/DownloadStateTests.swift @@ -1,5 +1,5 @@ import Testing -@testable import FlixyDownloads +@testable import HaloDownloads @Suite("Download-Zustandsautomat") struct DownloadStateTests { diff --git a/Packages/FlixyKit/Tests/FlixyDownloadsTests/TransferHoldTests.swift b/Packages/HaloKit/Tests/HaloDownloadsTests/TransferHoldTests.swift similarity index 97% rename from Packages/FlixyKit/Tests/FlixyDownloadsTests/TransferHoldTests.swift rename to Packages/HaloKit/Tests/HaloDownloadsTests/TransferHoldTests.swift index 43dbedd..66648de 100644 --- a/Packages/FlixyKit/Tests/FlixyDownloadsTests/TransferHoldTests.swift +++ b/Packages/HaloKit/Tests/HaloDownloadsTests/TransferHoldTests.swift @@ -1,5 +1,5 @@ import Testing -@testable import FlixyDownloads +@testable import HaloDownloads /// Warum gerade nichts übertragen wird. @Suite("Übertragungssperre") diff --git a/Packages/FlixyKit/Tests/FlixyPlaybackTests/AudioTrackChooserTests.swift b/Packages/HaloKit/Tests/HaloPlaybackTests/AudioTrackChooserTests.swift similarity index 99% rename from Packages/FlixyKit/Tests/FlixyPlaybackTests/AudioTrackChooserTests.swift rename to Packages/HaloKit/Tests/HaloPlaybackTests/AudioTrackChooserTests.swift index 0f3cfac..3668dfb 100644 --- a/Packages/FlixyKit/Tests/FlixyPlaybackTests/AudioTrackChooserTests.swift +++ b/Packages/HaloKit/Tests/HaloPlaybackTests/AudioTrackChooserTests.swift @@ -1,7 +1,7 @@ import Testing import Foundation import MediaKit -@testable import FlixyPlayback +@testable import HaloPlayback @Suite("Sprachkürzel") struct LanguageCodeTests { diff --git a/Packages/FlixyKit/Tests/FlixyPlaybackTests/DowngradeRuleTests.swift b/Packages/HaloKit/Tests/HaloPlaybackTests/DowngradeRuleTests.swift similarity index 99% rename from Packages/FlixyKit/Tests/FlixyPlaybackTests/DowngradeRuleTests.swift rename to Packages/HaloKit/Tests/HaloPlaybackTests/DowngradeRuleTests.swift index bc97701..8afbeef 100644 --- a/Packages/FlixyKit/Tests/FlixyPlaybackTests/DowngradeRuleTests.swift +++ b/Packages/HaloKit/Tests/HaloPlaybackTests/DowngradeRuleTests.swift @@ -1,6 +1,6 @@ import Testing import Foundation -@testable import FlixyPlayback +@testable import HaloPlayback @Suite("Wann der teure Weg erlaubt ist") struct DowngradeRuleTests { diff --git a/Packages/FlixyKit/Tests/FlixyPlaybackTests/LocalStreamServerTests.swift b/Packages/HaloKit/Tests/HaloPlaybackTests/LocalStreamServerTests.swift similarity index 99% rename from Packages/FlixyKit/Tests/FlixyPlaybackTests/LocalStreamServerTests.swift rename to Packages/HaloKit/Tests/HaloPlaybackTests/LocalStreamServerTests.swift index 539413f..24142b1 100644 --- a/Packages/FlixyKit/Tests/FlixyPlaybackTests/LocalStreamServerTests.swift +++ b/Packages/HaloKit/Tests/HaloPlaybackTests/LocalStreamServerTests.swift @@ -1,7 +1,7 @@ import Foundation import Network import Testing -@testable import FlixyPlayback +@testable import HaloPlayback /// Was der lokale Server dem Player wirklich schickt. /// diff --git a/Packages/FlixyKit/Tests/FlixyPlaybackTests/MediaPlaylistTests.swift b/Packages/HaloKit/Tests/HaloPlaybackTests/MediaPlaylistTests.swift similarity index 99% rename from Packages/FlixyKit/Tests/FlixyPlaybackTests/MediaPlaylistTests.swift rename to Packages/HaloKit/Tests/HaloPlaybackTests/MediaPlaylistTests.swift index 845b1b9..bc963f2 100644 --- a/Packages/FlixyKit/Tests/FlixyPlaybackTests/MediaPlaylistTests.swift +++ b/Packages/HaloKit/Tests/HaloPlaybackTests/MediaPlaylistTests.swift @@ -1,6 +1,6 @@ import Testing import Foundation -@testable import FlixyPlayback +@testable import HaloPlayback @Suite("Abspielliste lesen und umschreiben") struct MediaPlaylistTests { diff --git a/Packages/FlixyKit/Tests/FlixyPlaybackTests/PlaybackDeciderTests.swift b/Packages/HaloKit/Tests/HaloPlaybackTests/PlaybackDeciderTests.swift similarity index 99% rename from Packages/FlixyKit/Tests/FlixyPlaybackTests/PlaybackDeciderTests.swift rename to Packages/HaloKit/Tests/HaloPlaybackTests/PlaybackDeciderTests.swift index eaf7580..7f8cd1f 100644 --- a/Packages/FlixyKit/Tests/FlixyPlaybackTests/PlaybackDeciderTests.swift +++ b/Packages/HaloKit/Tests/HaloPlaybackTests/PlaybackDeciderTests.swift @@ -1,6 +1,6 @@ import Testing import MediaKit -@testable import FlixyPlayback +@testable import HaloPlayback /// Die Tabelle, die festhält, welche Datei auf welchem Weg landet. /// diff --git a/Packages/FlixyKit/Tests/FlixyPlaybackTests/QualityMemoryTests.swift b/Packages/HaloKit/Tests/HaloPlaybackTests/QualityMemoryTests.swift similarity index 98% rename from Packages/FlixyKit/Tests/FlixyPlaybackTests/QualityMemoryTests.swift rename to Packages/HaloKit/Tests/HaloPlaybackTests/QualityMemoryTests.swift index 576f2cd..e05cf0f 100644 --- a/Packages/FlixyKit/Tests/FlixyPlaybackTests/QualityMemoryTests.swift +++ b/Packages/HaloKit/Tests/HaloPlaybackTests/QualityMemoryTests.swift @@ -1,5 +1,5 @@ import Testing -@testable import FlixyPlayback +@testable import HaloPlayback /// Die gemerkte Qualitätsstufe über mehrere Filme hinweg. /// diff --git a/Packages/FlixyKit/Tests/FlixyPlaybackTests/StallLedgerTests.swift b/Packages/HaloKit/Tests/HaloPlaybackTests/StallLedgerTests.swift similarity index 99% rename from Packages/FlixyKit/Tests/FlixyPlaybackTests/StallLedgerTests.swift rename to Packages/HaloKit/Tests/HaloPlaybackTests/StallLedgerTests.swift index ed05886..7e3cf1e 100644 --- a/Packages/FlixyKit/Tests/FlixyPlaybackTests/StallLedgerTests.swift +++ b/Packages/HaloKit/Tests/HaloPlaybackTests/StallLedgerTests.swift @@ -1,6 +1,6 @@ import Testing import Foundation -@testable import FlixyPlayback +@testable import HaloPlayback @Suite("Rückler-Buchführung") struct StallLedgerTests { diff --git a/Packages/FlixyKit/Tests/FlixyPlaybackTests/StreamHealthTests.swift b/Packages/HaloKit/Tests/HaloPlaybackTests/StreamHealthTests.swift similarity index 99% rename from Packages/FlixyKit/Tests/FlixyPlaybackTests/StreamHealthTests.swift rename to Packages/HaloKit/Tests/HaloPlaybackTests/StreamHealthTests.swift index ff14b3d..028f45e 100644 --- a/Packages/FlixyKit/Tests/FlixyPlaybackTests/StreamHealthTests.swift +++ b/Packages/HaloKit/Tests/HaloPlaybackTests/StreamHealthTests.swift @@ -1,6 +1,6 @@ import Testing import Foundation -@testable import FlixyPlayback +@testable import HaloPlayback @Suite("Zustand des Streams") struct StreamHealthTests { diff --git a/Packages/FlixyKit/Tests/FlixyPlaybackTests/SubtitleStyleTests.swift b/Packages/HaloKit/Tests/HaloPlaybackTests/SubtitleStyleTests.swift similarity index 99% rename from Packages/FlixyKit/Tests/FlixyPlaybackTests/SubtitleStyleTests.swift rename to Packages/HaloKit/Tests/HaloPlaybackTests/SubtitleStyleTests.swift index 0cfbb72..fcdfe34 100644 --- a/Packages/FlixyKit/Tests/FlixyPlaybackTests/SubtitleStyleTests.swift +++ b/Packages/HaloKit/Tests/HaloPlaybackTests/SubtitleStyleTests.swift @@ -2,7 +2,7 @@ import AVFoundation import CoreMedia import Foundation import Testing -@testable import FlixyPlayback +@testable import HaloPlayback @Suite("Aussehen der Untertitel") struct SubtitleStyleTests { diff --git a/Packages/FlixyKit/Tests/FlixyPlaybackTests/TrackMenuTests.swift b/Packages/HaloKit/Tests/HaloPlaybackTests/TrackMenuTests.swift similarity index 99% rename from Packages/FlixyKit/Tests/FlixyPlaybackTests/TrackMenuTests.swift rename to Packages/HaloKit/Tests/HaloPlaybackTests/TrackMenuTests.swift index b96e363..722df59 100644 --- a/Packages/FlixyKit/Tests/FlixyPlaybackTests/TrackMenuTests.swift +++ b/Packages/HaloKit/Tests/HaloPlaybackTests/TrackMenuTests.swift @@ -1,6 +1,6 @@ import Testing import MediaKit -@testable import FlixyPlayback +@testable import HaloPlayback @Suite("Was im Spurenmenü steht") struct TrackMenuTests { diff --git a/Packages/FlixyKit/Tests/FlixyPlaybackTests/UpgradeRuleTests.swift b/Packages/HaloKit/Tests/HaloPlaybackTests/UpgradeRuleTests.swift similarity index 99% rename from Packages/FlixyKit/Tests/FlixyPlaybackTests/UpgradeRuleTests.swift rename to Packages/HaloKit/Tests/HaloPlaybackTests/UpgradeRuleTests.swift index d1ab496..c979ba4 100644 --- a/Packages/FlixyKit/Tests/FlixyPlaybackTests/UpgradeRuleTests.swift +++ b/Packages/HaloKit/Tests/HaloPlaybackTests/UpgradeRuleTests.swift @@ -1,6 +1,6 @@ import Foundation import Testing -@testable import FlixyPlayback +@testable import HaloPlayback @Suite("Wann hinaufgeschaltet wird") struct UpgradeRuleTests { diff --git a/Packages/FlixyKit/Tests/JellyfinKitTests/AdaptiveURLTests.swift b/Packages/HaloKit/Tests/JellyfinKitTests/AdaptiveURLTests.swift similarity index 100% rename from Packages/FlixyKit/Tests/JellyfinKitTests/AdaptiveURLTests.swift rename to Packages/HaloKit/Tests/JellyfinKitTests/AdaptiveURLTests.swift diff --git a/Packages/FlixyKit/Tests/JellyfinKitTests/AddressTests.swift b/Packages/HaloKit/Tests/JellyfinKitTests/AddressTests.swift similarity index 100% rename from Packages/FlixyKit/Tests/JellyfinKitTests/AddressTests.swift rename to Packages/HaloKit/Tests/JellyfinKitTests/AddressTests.swift diff --git a/Packages/FlixyKit/Tests/JellyfinKitTests/Fixtures/episode.json b/Packages/HaloKit/Tests/JellyfinKitTests/Fixtures/episode.json similarity index 100% rename from Packages/FlixyKit/Tests/JellyfinKitTests/Fixtures/episode.json rename to Packages/HaloKit/Tests/JellyfinKitTests/Fixtures/episode.json diff --git a/Packages/FlixyKit/Tests/JellyfinKitTests/Fixtures/series.json b/Packages/HaloKit/Tests/JellyfinKitTests/Fixtures/series.json similarity index 100% rename from Packages/FlixyKit/Tests/JellyfinKitTests/Fixtures/series.json rename to Packages/HaloKit/Tests/JellyfinKitTests/Fixtures/series.json diff --git a/Packages/FlixyKit/Tests/JellyfinKitTests/PlaybackTests.swift b/Packages/HaloKit/Tests/JellyfinKitTests/PlaybackTests.swift similarity index 98% rename from Packages/FlixyKit/Tests/JellyfinKitTests/PlaybackTests.swift rename to Packages/HaloKit/Tests/JellyfinKitTests/PlaybackTests.swift index ef6f9d8..9ec5cfd 100644 --- a/Packages/FlixyKit/Tests/JellyfinKitTests/PlaybackTests.swift +++ b/Packages/HaloKit/Tests/JellyfinKitTests/PlaybackTests.swift @@ -15,7 +15,7 @@ struct PlaybackTests { let client = JellyfinClient( baseURL: URL(string: "http://server:8096")!, identity: JellyfinIdentity( - client: "Flixy", device: "Testgerät", deviceID: "gerät-1", version: "1" + client: "Halo", device: "Testgerät", deviceID: "gerät-1", version: "1" ), token: "tok", transport: transport @@ -240,7 +240,7 @@ struct AudioStreamIndexTests { let client = JellyfinClient( baseURL: URL(string: "http://server:8096")!, identity: JellyfinIdentity( - client: "Flixy", device: "Testgerät", deviceID: "gerät-1", version: "1" + client: "Halo", device: "Testgerät", deviceID: "gerät-1", version: "1" ), token: "tok", transport: transport @@ -299,7 +299,7 @@ struct SubtitleStreamIndexTests { client: JellyfinClient( baseURL: URL(string: "http://server:8096")!, identity: JellyfinIdentity( - client: "Flixy", device: "Testgerät", deviceID: "gerät-1", version: "1" + client: "Halo", device: "Testgerät", deviceID: "gerät-1", version: "1" ), token: "tok", transport: transport @@ -358,7 +358,7 @@ struct MasterPlaylistTests { client: JellyfinClient( baseURL: URL(string: "http://server:8096")!, identity: JellyfinIdentity( - client: "Flixy", device: "Testgerät", deviceID: "gerät-1", version: "1" + client: "Halo", device: "Testgerät", deviceID: "gerät-1", version: "1" ), token: "tok", transport: transport diff --git a/Packages/FlixyKit/Tests/JellyfinKitTests/TranslationTests.swift b/Packages/HaloKit/Tests/JellyfinKitTests/TranslationTests.swift similarity index 100% rename from Packages/FlixyKit/Tests/JellyfinKitTests/TranslationTests.swift rename to Packages/HaloKit/Tests/JellyfinKitTests/TranslationTests.swift diff --git a/Packages/FlixyKit/Tests/MediaKitTests/.keep b/Packages/HaloKit/Tests/MediaKitTests/.keep similarity index 100% rename from Packages/FlixyKit/Tests/MediaKitTests/.keep rename to Packages/HaloKit/Tests/MediaKitTests/.keep diff --git a/Packages/FlixyKit/Tests/MediaKitTests/ArrangementTests.swift b/Packages/HaloKit/Tests/MediaKitTests/ArrangementTests.swift similarity index 100% rename from Packages/FlixyKit/Tests/MediaKitTests/ArrangementTests.swift rename to Packages/HaloKit/Tests/MediaKitTests/ArrangementTests.swift diff --git a/Packages/FlixyKit/Tests/MediaKitTests/DurationUnitsTests.swift b/Packages/HaloKit/Tests/MediaKitTests/DurationUnitsTests.swift similarity index 100% rename from Packages/FlixyKit/Tests/MediaKitTests/DurationUnitsTests.swift rename to Packages/HaloKit/Tests/MediaKitTests/DurationUnitsTests.swift diff --git a/Packages/FlixyKit/Tests/MediaKitTests/EpisodeSelectionTests.swift b/Packages/HaloKit/Tests/MediaKitTests/EpisodeSelectionTests.swift similarity index 100% rename from Packages/FlixyKit/Tests/MediaKitTests/EpisodeSelectionTests.swift rename to Packages/HaloKit/Tests/MediaKitTests/EpisodeSelectionTests.swift diff --git a/Packages/FlixyKit/Tests/MediaKitTests/HeroSelectionTests.swift b/Packages/HaloKit/Tests/MediaKitTests/HeroSelectionTests.swift similarity index 100% rename from Packages/FlixyKit/Tests/MediaKitTests/HeroSelectionTests.swift rename to Packages/HaloKit/Tests/MediaKitTests/HeroSelectionTests.swift diff --git a/Packages/FlixyKit/Tests/MediaKitTests/LibraryCacheTests.swift b/Packages/HaloKit/Tests/MediaKitTests/LibraryCacheTests.swift similarity index 99% rename from Packages/FlixyKit/Tests/MediaKitTests/LibraryCacheTests.swift rename to Packages/HaloKit/Tests/MediaKitTests/LibraryCacheTests.swift index 33e7a46..726f351 100644 --- a/Packages/FlixyKit/Tests/MediaKitTests/LibraryCacheTests.swift +++ b/Packages/HaloKit/Tests/MediaKitTests/LibraryCacheTests.swift @@ -8,7 +8,7 @@ struct LibraryCacheTests { /// Jeder Test bekommt ein eigenes Verzeichnis. Ein gemeinsames hiesse, /// dass die Reihenfolge der Tests über ihr Ergebnis mitentscheidet. private func frischerSpeicher() -> LibraryCache { - let ort = URL.temporaryDirectory.appending(path: "flixy-cache-\(UUID().uuidString)") + let ort = URL.temporaryDirectory.appending(path: "halo-cache-\(UUID().uuidString)") return LibraryCache(root: ort) } diff --git a/Packages/FlixyKit/Tests/MediaKitTests/PagingWindowTests.swift b/Packages/HaloKit/Tests/MediaKitTests/PagingWindowTests.swift similarity index 100% rename from Packages/FlixyKit/Tests/MediaKitTests/PagingWindowTests.swift rename to Packages/HaloKit/Tests/MediaKitTests/PagingWindowTests.swift diff --git a/Packages/FlixyKit/Tests/MediaKitTests/TopShelfSnapshotTests.swift b/Packages/HaloKit/Tests/MediaKitTests/TopShelfSnapshotTests.swift similarity index 97% rename from Packages/FlixyKit/Tests/MediaKitTests/TopShelfSnapshotTests.swift rename to Packages/HaloKit/Tests/MediaKitTests/TopShelfSnapshotTests.swift index 09ab8de..4f0a496 100644 --- a/Packages/FlixyKit/Tests/MediaKitTests/TopShelfSnapshotTests.swift +++ b/Packages/HaloKit/Tests/MediaKitTests/TopShelfSnapshotTests.swift @@ -34,7 +34,7 @@ struct TopShelfSnapshotTests { /// geschrieben wurde. @Test("Eine unbekannte App-Gruppe bringt nichts zum Absturz") func unknownGroupIsHarmless() { - let unbekannt = "group.flixy.test.\(UUID().uuidString)" + let unbekannt = "group.halo.test.\(UUID().uuidString)" TopShelfStore.write(TopShelfSnapshot(sections: []), group: unbekannt) let gelesen = TopShelfStore.read(group: unbekannt) #expect(gelesen?.sections.isEmpty ?? true) diff --git a/Packages/FlixyKit/Tests/MediaKitTests/VideoResolutionTests.swift b/Packages/HaloKit/Tests/MediaKitTests/VideoResolutionTests.swift similarity index 100% rename from Packages/FlixyKit/Tests/MediaKitTests/VideoResolutionTests.swift rename to Packages/HaloKit/Tests/MediaKitTests/VideoResolutionTests.swift diff --git a/README.md b/README.md index 4a39ac6..66d98e9 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -# Flixy +# Halo > Ein nativer Jellyfin-Client für iPhone, iPad, Mac und Apple TV — dunkel, > mit ausfahrbarer Seitenleiste und Offline-Downloads. -Der Name ist ein Platzhalter. Siehe [`Flixy/Branding.swift`](Flixy/Branding.swift). +Der Name ist ein Platzhalter. Siehe [`Halo/Branding.swift`](Halo/Branding.swift). ## Stand @@ -11,7 +11,7 @@ Alle sechs Phasen sind gebaut. Anmeldung, Blättern und Wiedergabe laufen am echten Server; der Rest ist unterschiedlich weit geprüft. Der Fahrplan steht in -[`docs/superpowers/specs/2026-09-11-flixy-design.md`](docs/superpowers/specs/2026-09-11-flixy-design.md). +[`docs/superpowers/specs/2026-09-11-halo-design.md`](docs/superpowers/specs/2026-09-11-halo-design.md). | Phase | Inhalt | Stand | |---|---|---| @@ -46,7 +46,7 @@ eingecheckt — das erspart Konflikte in der `pbxproj`. ```bash xcodegen generate -open Flixy.xcodeproj +open Halo.xcodeproj ``` > **Wichtig: Xcode vorher beenden.** @@ -63,16 +63,16 @@ open Flixy.xcodeproj > Ob der Build aktuell ist, steht in der App unter **Einstellungen → > Diagnose** als Build-Datum. -Der Code liegt zum größten Teil in lokalen Packages unter `Packages/FlixyKit`. +Der Code liegt zum größten Teil in lokalen Packages unter `Packages/HaloKit`. Das App-Target enthält nur Oberfläche und Navigation. | Modul | Aufgabe | Hängt ab von | |---|---|---| | `MediaKit` | Die serverneutrale Grundschicht: Typen und Rechnungen, die für jeden Server gelten. | — | | `JellyfinKit` | Anmeldung, Endpunkte, Modelle. Kein SwiftUI. | `MediaKit` | -| `FlixyDesign` | Farben, Typografie, wiederkehrende Bausteine. | — | -| `FlixyPlayback` | Wiedergabe-Abstraktion und die Entscheidung DirectPlay/Umpacken/Transcode. | `MediaKit` | -| `FlixyDownloads` | Warteschlange, Hintergrundübertragung, Offline-Bestand. | `MediaKit` | +| `HaloDesign` | Farben, Typografie, wiederkehrende Bausteine. | — | +| `HaloPlayback` | Wiedergabe-Abstraktion und die Entscheidung DirectPlay/Umpacken/Transcode. | `MediaKit` | +| `HaloDownloads` | Warteschlange, Hintergrundübertragung, Offline-Bestand. | `MediaKit` | ### Warum umgepackt wird @@ -95,7 +95,7 @@ Oberfläche bleibt unberührt. Die Logik-Tests laufen ohne Simulator, deshalb in Sekunden: ```bash -cd Packages/FlixyKit && swift test +cd Packages/HaloKit && swift test ``` Die wichtigste Testdatei ist `PlaybackDeciderTests` — sie hält fest, welche @@ -136,10 +136,10 @@ Irgendwann war das Upload-Kontingent des Tages aufgebraucht — für eine Frage, die keine Oberfläche braucht. ```bash -cd Packages/FlixyKit -swift run FlixyProbe --jellyfin # Welche Leiter baut der Server? -swift run FlixyProbe --spuren # Welche Tonspuren hat ein Titel? -swift run FlixyProbe --playlist # Was steht in dieser HLS-Leiter? +cd Packages/HaloKit +swift run HaloProbe --jellyfin # Welche Leiter baut der Server? +swift run HaloProbe --spuren # Welche Tonspuren hat ein Titel? +swift run HaloProbe --playlist # Was steht in dieser HLS-Leiter? ``` `--jellyfin` und `--spuren` fragen nach Benutzername und Passwort und legen den diff --git a/Tools/JellyfinStub/server.py b/Tools/JellyfinStub/server.py index 38259f6..a957ca3 100644 --- a/Tools/JellyfinStub/server.py +++ b/Tools/JellyfinStub/server.py @@ -139,7 +139,7 @@ def item(key, name, kind, overview, *, resume=None, series=None): # # Zum Prüfen des Nachladens: mit einer Handvoll Titeln passt alles auf eine # Seite, und ob überhaupt eine zweite angefordert wird, sieht man nie. -FUELLUNG = int(os.environ.get("FLIXY_STUB_LIBRARY", "0")) +FUELLUNG = int(os.environ.get("HALO_STUB_LIBRARY", "0")) def fuellmaterial(kind): return [ diff --git a/Tools/TVBrandAssets.py b/Tools/TVBrandAssets.py index 93ff67f..a2b5e2b 100644 --- a/Tools/TVBrandAssets.py +++ b/Tools/TVBrandAssets.py @@ -16,7 +16,7 @@ import math from pathlib import Path from PIL import Image, ImageDraw, ImageFilter -WURZEL = Path("FlixyTV/Resources/TVAssets.xcassets") +WURZEL = Path("HaloTV/Resources/TVAssets.xcassets") MARKE = WURZEL / "App Icon & Top Shelf Image.brandassets" # Gemessen am gerenderten iOS-Icon, Spalte neben dem Dreieck bzw. durch es. diff --git a/Tools/WindowShot/main.swift b/Tools/WindowShot/main.swift index aac1989..913ab65 100644 --- a/Tools/WindowShot/main.swift +++ b/Tools/WindowShot/main.swift @@ -8,7 +8,7 @@ import Foundation // Gebaut, weil es sonst keinen Weg dorthin gibt: das System-Python bringt // PyObjC nicht mehr mit, und `screencapture` kennt nur Kennungen, keine Namen. -let name = CommandLine.arguments.dropFirst().first ?? "Flixy" +let name = CommandLine.arguments.dropFirst().first ?? "Halo" /// Zweites Argument: die Prozesskennung. Nötig, sobald zwei Bauarten /// desselben Programms gleichzeitig laufen — sonst trifft es die falsche. let wantedPID = CommandLine.arguments.dropFirst(2).first.flatMap(Int.init) diff --git a/project.yml b/project.yml index 33c033f..8f39928 100644 --- a/project.yml +++ b/project.yml @@ -1,4 +1,4 @@ -name: Flixy +name: Halo options: bundleIdPrefix: com.scarriffleservices @@ -19,11 +19,11 @@ settings: SWIFT_STRICT_CONCURRENCY: complete packages: - FlixyKit: - path: Packages/FlixyKit + HaloKit: + path: Packages/HaloKit targets: - Flixy: + Halo: type: application platform: iOS # Ausdrücklich aufgeschrieben, statt Xcode raten zu lassen. @@ -34,39 +34,39 @@ targets: # auflösen. Hier steht es im Projekt und überlebt jedes Neuerzeugen. scheme: testTargets: - - FlixyUITests + - HaloUITests sources: # Das Icon ist ein Bündel, also technisch ein Ordner. Ohne diesen # Ausschluss läuft XcodeGen hinein und trägt icon.json und play.svg # einzeln ein — dann fehlt das Icon, ohne dass irgendwo ein Fehler # auftaucht. # - - path: Flixy + - path: Halo excludes: - "AppIcon.icon" - - path: Flixy/AppIcon.icon + - path: Halo/AppIcon.icon type: file dependencies: - target: DownloadWidget # Die neutrale Grundschicht. Ausdrücklich genannt, obwohl sie über # JellyfinKit ohnehin im Baum hängt: die App soll sie direkt benutzen und # nicht davon abhängen, dass ein bestimmter Server sie mitschleppt. - - package: FlixyKit + - package: HaloKit product: MediaKit # Der Server. Steht auf der neutralen Schicht, nicht darin — kommt ein # zweiter dazu, steht er daneben. - - package: FlixyKit + - package: HaloKit product: JellyfinKit - - package: FlixyKit - product: FlixyDesign - - package: FlixyKit - product: FlixyPlayback - - package: FlixyKit - product: FlixyDownloads + - package: HaloKit + product: HaloDesign + - package: HaloKit + product: HaloPlayback + - package: HaloKit + product: HaloDownloads settings: base: - PRODUCT_BUNDLE_IDENTIFIER: com.scarriffleservices.flixy - PRODUCT_NAME: Flixy + PRODUCT_BUNDLE_IDENTIFIER: com.scarriffleservices.halo + PRODUCT_NAME: Halo # Verweist auf AppIcon.icon. Der frühere leere AppIcon.appiconset im # Asset-Katalog ist entfernt — zwei Dinge namens AppIcon, und Xcode # nimmt das falsche. @@ -75,9 +75,9 @@ targets: TARGETED_DEVICE_FAMILY: "1,2" CODE_SIGN_STYLE: Automatic info: - path: Flixy/Info.plist + path: Halo/Info.plist properties: - CFBundleDisplayName: Flixy + CFBundleDisplayName: Halo UILaunchScreen: UIColorName: LaunchBackground @@ -136,25 +136,25 @@ targets: # Freigabe. Fehlt der Text, verweigert das System sie kommentarlos und # die Serversuche findet dauerhaft nichts. NSLocalNetworkUsageDescription: >- - Flixy benötigt Zugriff auf das lokale Netzwerk, um deinen + Halo benötigt Zugriff auf das lokale Netzwerk, um deinen Jellyfin-Server zu erreichen und Medien direkt von ihm zu laden. # Die Fassung für den Fernseher. # # **Eigene Ansichten, geteilte Modelle.** Die Quellenpfade sind die ganze - # Aussage dieses Blocks: `FlixyTV/` gehört nur hierher, `Flixy/Session/` + # Aussage dieses Blocks: `HaloTV/` gehört nur hierher, `Halo/Session/` # gehört beiden. Keine Datei muss dafür umziehen — XcodeGen nimmt Pfade je # Ziel, und die iOS-Fassung sieht von der ganzen Sache nichts. - FlixyTV: + HaloTV: type: application platform: tvOS - # Aus demselben Grund ausgeschrieben wie bei Flixy — siehe dort. + # Aus demselben Grund ausgeschrieben wie bei Halo — siehe dort. scheme: {} sources: # Die eigenen Ansichten. - - path: FlixyTV + - path: HaloTV # Die Modelle. - - path: Flixy/Session + - path: Halo/Session excludes: # Ein Fernseher dreht sich nicht. - "OrientationLock.swift" @@ -169,60 +169,60 @@ targets: # aufruft. Beide sind reine Übersetzer ohne UIKit. # Reines Modell trotz des Ordnernamens: LoadState, ErrorText und # MediaRoute liegen zusammen in einer Datei. - - path: Flixy/Views/LoadState.swift + - path: Halo/Views/LoadState.swift type: file # Der Player. **Ohne PlayerView** — die zeichnet auf iOS das Bild und # alle Bedienelemente selbst; auf dem Fernseher macht das Apples # AVPlayerViewController. Das Modell darunter ist dasselbe. - - path: Flixy/Views/Player/PlayerModel.swift + - path: Halo/Views/Player/PlayerModel.swift type: file - - path: Flixy/Views/Player/VideoSurface.swift + - path: Halo/Views/Player/VideoSurface.swift type: file - - path: Flixy/Branding.swift + - path: Halo/Branding.swift type: file # Die Texte. Dieselben Schlüssel, dieselben Übersetzungen. - - path: Flixy/Resources/Localizable.xcstrings + - path: Halo/Resources/Localizable.xcstrings type: file dependencies: - - package: FlixyKit + - package: HaloKit product: MediaKit - - package: FlixyKit + - package: HaloKit product: JellyfinKit - - package: FlixyKit - product: FlixyDesign - - package: FlixyKit - product: FlixyPlayback + - package: HaloKit + product: HaloDesign + - package: HaloKit + product: HaloPlayback # Nur damit `PlayerModel` den Typ nennen darf. Angelegt wird nie einer: - # FlixyTVApp reicht `nil` durch, und damit gibt es auf tvOS auch keinen + # HaloTVApp reicht `nil` durch, und damit gibt es auf tvOS auch keinen # ModelContainer und kein SwiftData. - - package: FlixyKit - product: FlixyDownloads - - target: FlixyTopShelf + - package: HaloKit + product: HaloDownloads + - target: HaloTopShelf settings: base: - PRODUCT_BUNDLE_IDENTIFIER: com.scarriffleservices.flixy.tv - PRODUCT_NAME: Flixy + PRODUCT_BUNDLE_IDENTIFIER: com.scarriffleservices.halo.tv + PRODUCT_NAME: Halo # Nur Apple TV. TARGETED_DEVICE_FAMILY: "3" # Kein AppIcon.icon: Icon Composer deckt iOS, macOS und watchOS ab, # tvOS nicht. Der Name zeigt auf die Brand-Assets-Gruppe im Katalog, - # und der Katalog liegt unter FlixyTV/Resources. + # und der Katalog liegt unter HaloTV/Resources. ASSETCATALOG_COMPILER_APPICON_NAME: "App Icon & Top Shelf Image" CODE_SIGN_STYLE: Automatic - CODE_SIGN_ENTITLEMENTS: FlixyTV/Flixy.entitlements + CODE_SIGN_ENTITLEMENTS: HaloTV/Halo.entitlements info: - path: FlixyTV/Info.plist + path: HaloTV/Info.plist properties: - CFBundleDisplayName: Flixy + CFBundleDisplayName: Halo UIUserInterfaceStyle: Dark ITSAppUsesNonExemptEncryption: false # Über dieses Schema schickt das Regal zurück in die App. Ohne den # Eintrag kennt tvOS es nicht, und ein Druck auf ein Plakat tut # nichts — ohne Fehler, ohne Hinweis. CFBundleURLTypes: - - CFBundleURLName: com.scarriffleservices.flixy.topshelf + - CFBundleURLName: com.scarriffleservices.halo.topshelf CFBundleURLSchemes: - - flixy + - halo # Was hier **nicht** steht, und warum: # # UILaunchScreen — tvOS hat kein Startbild dieser Art. @@ -234,7 +234,7 @@ targets: NSAppTransportSecurity: NSAllowsLocalNetworking: true NSLocalNetworkUsageDescription: >- - Flixy benötigt Zugriff auf das lokale Netzwerk, um deinen + Halo benötigt Zugriff auf das lokale Netzwerk, um deinen Jellyfin-Server zu erreichen. # Das Regal über der App im tvOS-Menü. @@ -243,25 +243,25 @@ targets: # läuft — und mit weniger als einer Sekunde Zeit. Sie liest deshalb nur eine # Datei aus der App-Gruppe, die die App beim Laden der Startseite ablegt: # kein Netz, kein Schlüsselbund, kein Blättern. - FlixyTopShelf: + HaloTopShelf: type: tv-app-extension platform: tvOS sources: - - path: FlixyTopShelf + - path: HaloTopShelf dependencies: - - package: FlixyKit + - package: HaloKit product: MediaKit settings: base: - PRODUCT_BUNDLE_IDENTIFIER: com.scarriffleservices.flixy.tv.topshelf - PRODUCT_NAME: FlixyTopShelf + PRODUCT_BUNDLE_IDENTIFIER: com.scarriffleservices.halo.tv.topshelf + PRODUCT_NAME: HaloTopShelf CODE_SIGN_STYLE: Automatic - CODE_SIGN_ENTITLEMENTS: FlixyTopShelf/FlixyTopShelf.entitlements + CODE_SIGN_ENTITLEMENTS: HaloTopShelf/HaloTopShelf.entitlements SKIP_INSTALL: YES info: - path: FlixyTopShelf/Info.plist + path: HaloTopShelf/Info.plist properties: - CFBundleDisplayName: Flixy + CFBundleDisplayName: Halo # **Die Erweiterung hat ihre eigene Info.plist.** # # Und damit ihre eigene Transportsicherheit: die Ausnahme in der @@ -278,17 +278,17 @@ targets: # Nur zum Hinsehen: fährt die App mit der Attrappe in einen bestimmten # Zustand und hält sie dort an, damit von außen fotografiert werden kann. # Kein Teil der App, wird nie mitgeliefert. - FlixyUITests: + HaloUITests: type: bundle.ui-testing platform: iOS sources: - - FlixyUITests + - HaloUITests dependencies: - - target: Flixy + - target: Halo settings: base: - PRODUCT_BUNDLE_IDENTIFIER: com.scarriffleservices.flixy.uitests - TEST_TARGET_NAME: Flixy + PRODUCT_BUNDLE_IDENTIFIER: com.scarriffleservices.halo.uitests + TEST_TARGET_NAME: Halo TARGETED_DEVICE_FAMILY: "1,2" CODE_SIGN_STYLE: Automatic GENERATE_INFOPLIST_FILE: YES @@ -303,13 +303,13 @@ targets: sources: - path: DownloadWidget dependencies: - - package: FlixyKit - product: FlixyDownloads - - package: FlixyKit - product: FlixyDesign + - package: HaloKit + product: HaloDownloads + - package: HaloKit + product: HaloDesign settings: base: - PRODUCT_BUNDLE_IDENTIFIER: com.scarriffleservices.flixy.downloadwidget + PRODUCT_BUNDLE_IDENTIFIER: com.scarriffleservices.halo.downloadwidget PRODUCT_NAME: DownloadWidget CODE_SIGN_STYLE: Automatic SKIP_INSTALL: YES @@ -320,6 +320,6 @@ targets: info: path: DownloadWidget/Info.plist properties: - CFBundleDisplayName: Flixy Downloads + CFBundleDisplayName: Halo Downloads NSExtension: NSExtensionPointIdentifier: com.apple.widgetkit-extension diff --git a/web/README.md b/web/README.md index 4a4a2ab..57846e4 100644 --- a/web/README.md +++ b/web/README.md @@ -1,4 +1,4 @@ -# Flixy Web +# Halo Web Die Weboberfläche für Rechner, auf denen es keine App gibt — Windows vor allem. @@ -28,7 +28,7 @@ Nebenbei bleibt der Zugangsschlüssel beim Server, statt im Browser zu liegen. ```bash cd app && npm install && npm run build -cd ../server && FLIXY_SERVER=http://jellyfin:8096 node index.js +cd ../server && HALO_SERVER=http://jellyfin:8096 node index.js ``` Dann auf `http://localhost:8080`. Der Port lässt sich über `PORT` ändern. @@ -36,7 +36,7 @@ Dann auf `http://localhost:8080`. Der Port lässt sich über `PORT` ändern. ## Entwickeln ```bash -cd app && FLIXY_SERVER=http://jellyfin:8096 npm run dev +cd app && HALO_SERVER=http://jellyfin:8096 npm run dev ``` Vite übernimmt dabei das Weiterreichen, der eigene Server wird nicht gebraucht. diff --git a/web/app/index.html b/web/app/index.html index d78fbda..616e5f8 100644 --- a/web/app/index.html +++ b/web/app/index.html @@ -3,7 +3,7 @@ -Flixy +Halo
diff --git a/web/app/package-lock.json b/web/app/package-lock.json index 62f2881..ba62eef 100644 --- a/web/app/package-lock.json +++ b/web/app/package-lock.json @@ -1,11 +1,11 @@ { - "name": "flixy-web", + "name": "halo-web", "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "flixy-web", + "name": "halo-web", "version": "0.1.0", "dependencies": { "hls.js": "^1.5.18" diff --git a/web/app/package.json b/web/app/package.json index 76d8c06..d46ec0c 100644 --- a/web/app/package.json +++ b/web/app/package.json @@ -1,5 +1,5 @@ { - "name": "flixy-web", + "name": "halo-web", "private": true, "version": "0.1.0", "type": "module", diff --git a/web/app/src/api.ts b/web/app/src/api.ts index 17b1536..a47fd49 100644 --- a/web/app/src/api.ts +++ b/web/app/src/api.ts @@ -14,13 +14,13 @@ import type { Wiedergabeauskunft } from './types'; const BASIS = '/api'; export const sitzung = { - token: localStorage.getItem('flixy.token') ?? '', - userId: localStorage.getItem('flixy.user') ?? '', + token: localStorage.getItem('halo.token') ?? '', + userId: localStorage.getItem('halo.user') ?? '', geraet: - localStorage.getItem('flixy.device') ?? + localStorage.getItem('halo.device') ?? (() => { - const id = 'flixy-web-' + Math.random().toString(36).slice(2, 12); - localStorage.setItem('flixy.device', id); + const id = 'halo-web-' + Math.random().toString(36).slice(2, 12); + localStorage.setItem('halo.device', id); return id; })(), }; @@ -32,7 +32,7 @@ export const sitzung = { * angemeldet, obwohl der Schlüssel stimmt. */ function kopfzeile(): string { const teile = [ - 'Client="Flixy Web"', + 'Client="Halo Web"', 'Device="Browser"', `DeviceId="${sitzung.geraet}"`, 'Version="0.1"', @@ -90,13 +90,13 @@ export async function anmelden(benutzer: string, passwort: string): Promise(schluessel: K): Einstellungen[K] { - const roh = localStorage.getItem('flixy.' + schluessel); + const roh = localStorage.getItem('halo.' + schluessel); if (roh == null) return vorgabe[schluessel]; const art = typeof vorgabe[schluessel]; if (Array.isArray(vorgabe[schluessel])) { @@ -92,7 +92,7 @@ export function setzen(schluessel: K, wert: Einst // Listen müssen als JSON abgelegt werden — ein Array landete sonst als // "a,b,c" im Speicher und käme als Zeichenkette zurück. localStorage.setItem( - 'flixy.' + schluessel, + 'halo.' + schluessel, Array.isArray(wert) ? JSON.stringify(wert) : String(wert), ); anwenden(); diff --git a/web/app/src/style.css b/web/app/src/style.css index d7cc23a..d46531c 100644 --- a/web/app/src/style.css +++ b/web/app/src/style.css @@ -1,7 +1,7 @@ /* ============================================================================ - Flixy Web — ein Frontend für Jellyfin + Halo Web — ein Frontend für Jellyfin ---------------------------------------------------------------------------- - Die Werte stammen aus FlixyDesign, nicht aus dem Augenmaß: dieselben + Die Werte stammen aus HaloDesign, nicht aus dem Augenmaß: dieselben Flächen, dieselben Radien, dieselben Abstände wie in der App. ========================================================================= */ :root { diff --git a/web/app/src/views/login.ts b/web/app/src/views/login.ts index 7af63b0..f41efea 100644 --- a/web/app/src/views/login.ts +++ b/web/app/src/views/login.ts @@ -4,7 +4,7 @@ import { esc } from '../util'; export function anmeldung(wurzel: HTMLElement, fertig: () => void): void { wurzel.innerHTML = `