diff --git a/.gitignore b/.gitignore index 7c0035e..7aef122 100644 --- a/.gitignore +++ b/.gitignore @@ -9,10 +9,10 @@ xcuserdata/ # Von XcodeGen aus project.yml erzeugt — nicht eingecheckt, damit es keine # Konflikte in der pbxproj gibt. Nach dem Klonen: xcodegen generate # -# Halo.xcworkspace daneben ist dagegen von Hand geschrieben und gehört dazu: +# Flaro.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 Halo.xcworkspace/README.md. -Halo.xcodeproj/ +# nötig ist, steht in Flaro.xcworkspace/README.md. +Flaro.xcodeproj/ node_modules/ # .NET diff --git a/DownloadWidget/DownloadLiveActivity.swift b/DownloadWidget/DownloadLiveActivity.swift index e9b34b7..3c510eb 100644 --- a/DownloadWidget/DownloadLiveActivity.swift +++ b/DownloadWidget/DownloadLiveActivity.swift @@ -1,8 +1,8 @@ import ActivityKit import SwiftUI import WidgetKit -import HaloDesign -import HaloDownloads +import FlaroDesign +import FlaroDownloads /// Der Download-Fortschritt im Sperrbildschirm und in der Dynamic Island. struct DownloadLiveActivity: Widget { diff --git a/DownloadWidget/Info.plist b/DownloadWidget/Info.plist index 49e5165..8b79382 100644 --- a/DownloadWidget/Info.plist +++ b/DownloadWidget/Info.plist @@ -5,7 +5,7 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName - Halo Downloads + Flaro Downloads CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier diff --git a/Halo.xcworkspace/README.md b/Flaro.xcworkspace/README.md similarity index 83% rename from Halo.xcworkspace/README.md rename to Flaro.xcworkspace/README.md index efd8ddd..40f7acf 100644 --- a/Halo.xcworkspace/README.md +++ b/Flaro.xcworkspace/README.md @@ -1,9 +1,9 @@ # Diesen Arbeitsbereich öffnen, nicht das Projekt -`Halo.xcodeproj` wird von XcodeGen aus `project.yml` erzeugt — und dabei +`Flaro.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 (`Halo.xcodeproj/project.xcworkspace`), meldet es danach +Projekt offen (`Flaro.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/Halo.xcworkspace/contents.xcworkspacedata b/Flaro.xcworkspace/contents.xcworkspacedata similarity index 57% rename from Halo.xcworkspace/contents.xcworkspacedata rename to Flaro.xcworkspace/contents.xcworkspacedata index 7416b61..33fcc87 100644 --- a/Halo.xcworkspace/contents.xcworkspacedata +++ b/Flaro.xcworkspace/contents.xcworkspacedata @@ -1,4 +1,4 @@ - + diff --git a/Halo/AppIcon.icon/Assets/play.svg b/Flaro/AppIcon.icon/Assets/play.svg similarity index 100% rename from Halo/AppIcon.icon/Assets/play.svg rename to Flaro/AppIcon.icon/Assets/play.svg diff --git a/Halo/AppIcon.icon/icon.json b/Flaro/AppIcon.icon/icon.json similarity index 100% rename from Halo/AppIcon.icon/icon.json rename to Flaro/AppIcon.icon/icon.json diff --git a/Halo/Branding.swift b/Flaro/Branding.swift similarity index 90% rename from Halo/Branding.swift rename to Flaro/Branding.swift index 91a3608..5ecdce0 100644 --- a/Halo/Branding.swift +++ b/Flaro/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 „Halo" zu, sondern immer hierauf. Zu ändern sind dann genau +/// geschriebenes „Flaro" zu, sondern immer hierauf. Zu ändern sind dann genau /// zwei Dinge: diese Datei und `project.yml` (Produktname, Bundle-Kennung, /// Anzeigename). /// -/// Die Typen aus HaloKit behalten ihre Namen — sie sind Bauteile, keine Marke. +/// Die Typen aus FlaroKit behalten ihre Namen — sie sind Bauteile, keine Marke. enum Branding { /// Wie die App sich selbst nennt. - static let appName = "Halo" + static let appName = "Flaro" /// 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.halo" + Bundle.main.bundleIdentifier ?? "com.scarriffleservices.flaro" } /// Wann dieser Build entstanden ist. diff --git a/Halo/HaloApp.swift b/Flaro/FlaroApp.swift similarity index 95% rename from Halo/HaloApp.swift rename to Flaro/FlaroApp.swift index f0c5f6d..fca3768 100644 --- a/Halo/HaloApp.swift +++ b/Flaro/FlaroApp.swift @@ -3,14 +3,14 @@ import SwiftUI #if os(iOS) import UIKit #endif -import HaloDesign -import HaloDownloads -import HaloPlayback +import FlaroDesign +import FlaroDownloads +import FlaroPlayback import JellyfinKit import MediaKit @main -struct HaloApp: App { +struct FlaroApp: 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 HaloApp: 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 = HaloTheme() - @State private var session: HaloSession + @State private var theme = FlaroTheme() + @State private var session: FlaroSession @State private var playback = PlaybackCoordinator() @State private var playbackSettings = PlaybackSettings() @State private var languages = LanguagePreferences() @@ -40,7 +40,7 @@ struct HaloApp: App { private let modelContainer: ModelContainer init() { - _session = State(initialValue: HaloSession( + _session = State(initialValue: FlaroSession( jellyfinIdentity: JellyfinIdentity.current( client: Branding.appName, version: Branding.version @@ -74,8 +74,8 @@ struct HaloApp: App { // Notizzettelgröße, und darin fällt der Aufmacher in sich // zusammen, weil seine Abstände dehnbar sind. .frame( - minWidth: HaloPlatform.isMac ? 900 : nil, - minHeight: HaloPlatform.isMac ? 620 : nil + minWidth: FlaroPlatform.isMac ? 900 : nil, + minHeight: FlaroPlatform.isMac ? 620 : nil ) // `defaultSize` gibt es hier nicht; die Größe hängt an der // Szene. @@ -133,7 +133,7 @@ struct HaloApp: App { } #if os(iOS) -extension HaloApp { +extension FlaroApp { /// 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/Halo/Info.plist b/Flaro/Info.plist similarity index 91% rename from Halo/Info.plist rename to Flaro/Info.plist index 6d76d2a..6ad3fbc 100644 --- a/Halo/Info.plist +++ b/Flaro/Info.plist @@ -5,7 +5,7 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName - Halo + Flaro CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -28,7 +28,7 @@ NSLocalNetworkUsageDescription - Halo benötigt Zugriff auf das lokale Netzwerk, um deinen Jellyfin-Server zu erreichen und Medien direkt von ihm zu laden. + Flaro 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/Halo/Resources/Assets.xcassets/Contents.json b/Flaro/Resources/Assets.xcassets/Contents.json similarity index 100% rename from Halo/Resources/Assets.xcassets/Contents.json rename to Flaro/Resources/Assets.xcassets/Contents.json diff --git a/Halo/Resources/Assets.xcassets/LaunchBackground.colorset/Contents.json b/Flaro/Resources/Assets.xcassets/LaunchBackground.colorset/Contents.json similarity index 100% rename from Halo/Resources/Assets.xcassets/LaunchBackground.colorset/Contents.json rename to Flaro/Resources/Assets.xcassets/LaunchBackground.colorset/Contents.json diff --git a/Halo/Resources/Localizable.xcstrings b/Flaro/Resources/Localizable.xcstrings similarity index 99% rename from Halo/Resources/Localizable.xcstrings rename to Flaro/Resources/Localizable.xcstrings index 91d8409..e2d6299 100644 --- a/Halo/Resources/Localizable.xcstrings +++ b/Flaro/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 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." + "value": "Die Obergrenze, nicht das Ziel. Im eigenen Netz überträgt der Server das Original; unterwegs beginnt Flaro 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 Halo 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 Flaro 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/Halo/Session/DownloadRefiller.swift b/Flaro/Session/DownloadRefiller.swift similarity index 99% rename from Halo/Session/DownloadRefiller.swift rename to Flaro/Session/DownloadRefiller.swift index c7d03b4..535e728 100644 --- a/Halo/Session/DownloadRefiller.swift +++ b/Flaro/Session/DownloadRefiller.swift @@ -1,5 +1,5 @@ import Foundation -import HaloDownloads +import FlaroDownloads import MediaKit /// Füllt den Vorrat an ungesehenen Folgen wieder auf. diff --git a/Halo/Session/DownloadService.swift b/Flaro/Session/DownloadService.swift similarity index 99% rename from Halo/Session/DownloadService.swift rename to Flaro/Session/DownloadService.swift index 06394c5..84075be 100644 --- a/Halo/Session/DownloadService.swift +++ b/Flaro/Session/DownloadService.swift @@ -1,6 +1,6 @@ import Foundation -import HaloDownloads -import HaloPlayback +import FlaroDownloads +import FlaroPlayback import MediaKit /// Übersetzt Titel vom Server in Download-Aufträge. diff --git a/Halo/Session/HaloSession.swift b/Flaro/Session/FlaroSession.swift similarity index 95% rename from Halo/Session/HaloSession.swift rename to Flaro/Session/FlaroSession.swift index 4fc1e90..f062875 100644 --- a/Halo/Session/HaloSession.swift +++ b/Flaro/Session/FlaroSession.swift @@ -15,7 +15,7 @@ import Observation /// Umschalten ja, nebeneinander nein. @MainActor @Observable -final class HaloSession { +final class FlaroSession { enum Phase: Equatable { /// Beim Start: liegt ein Token im Schlüsselbund? case launching @@ -32,11 +32,11 @@ final class HaloSession { } private enum Key { - 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" + static let jellyfinAddress = "flaro.jellyfin.address" + static let jellyfinUserID = "flaro.jellyfin.userID" + static let jellyfinUserName = "flaro.jellyfin.userName" + static let jellyfinServerName = "flaro.jellyfin.serverName" + static let jellyfinIsAdministrator = "flaro.jellyfin.isAdministrator" } /// Unter welchem Namen das Server-Token im Schlüsselbund liegt. @@ -55,14 +55,14 @@ final class HaloSession { /// könnte. Deshalb wird einmalig aufgeräumt, bevor die Namen endgültig /// verschwinden. private enum Altlast { - static let merker = "halo.migration.plexPurged" + static let merker = "flaro.migration.plexPurged" static let tokenKonten = ["plex.account", "plex.server"] static let schlüssel = [ - "halo.backend.kind", - "halo.server.clientIdentifier", - "halo.server.connectionURI", - "halo.server.name", - "halo.server.connectionIsLocal", + "flaro.backend.kind", + "flaro.server.clientIdentifier", + "flaro.server.connectionURI", + "flaro.server.name", + "flaro.server.connectionIsLocal", ] } @@ -93,7 +93,7 @@ final class HaloSession { /// Wer angemeldet ist — sofern der Server einen Namen dafür kennt. var accountName: String? { jellyfinAccount?.userName } - /// Die Mediatheken, die Halo darstellen kann — Musik und Fotos + /// Die Mediatheken, die Flaro darstellen kann — Musik und Fotos /// erscheinen gar nicht erst. private(set) var libraries: [MediaLibrary] = [] @@ -233,14 +233,14 @@ final class HaloSession { /// Meldet sich an der Attrappe aus `Tools/JellyfinStub` an. /// /// Nur in der Entwicklung und nur auf ausdrückliches Kommando: - /// `-HaloStubServer http://127.0.0.1:8096` als Startargument. Der Weg + /// `-FlaroStubServer 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: "HaloStubServer"), + guard let raw = defaults.string(forKey: "FlaroStubServer"), let baseURL = URL(string: raw) else { return false } diff --git a/Halo/Session/HeroArtwork.swift b/Flaro/Session/HeroArtwork.swift similarity index 96% rename from Halo/Session/HeroArtwork.swift rename to Flaro/Session/HeroArtwork.swift index 1d1eed0..0f75e99 100644 --- a/Halo/Session/HeroArtwork.swift +++ b/Flaro/Session/HeroArtwork.swift @@ -1,5 +1,5 @@ import Foundation -import HaloDesign +import FlaroDesign 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 HaloAspectRatio.poster } - return compact ? HaloAspectRatio.heroCompact : HaloAspectRatio.hero + if isPortrait(placement, compact: compact) { return FlaroAspectRatio.poster } + return compact ? FlaroAspectRatio.heroCompact : FlaroAspectRatio.hero } static func backdropURL( diff --git a/Halo/Session/HomeFeed.swift b/Flaro/Session/HomeFeed.swift similarity index 100% rename from Halo/Session/HomeFeed.swift rename to Flaro/Session/HomeFeed.swift diff --git a/Halo/Session/HomeLayoutSettings.swift b/Flaro/Session/HomeLayoutSettings.swift similarity index 92% rename from Halo/Session/HomeLayoutSettings.swift rename to Flaro/Session/HomeLayoutSettings.swift index 7c878b0..505195b 100644 --- a/Halo/Session/HomeLayoutSettings.swift +++ b/Flaro/Session/HomeLayoutSettings.swift @@ -12,15 +12,15 @@ import MediaKit @Observable final class HomeLayoutSettings { private enum Key { - 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" + static let hidden = "flaro.home.hiddenHubs" + static let order = "flaro.home.hubOrder" + static let heroCount = "flaro.home.heroCount" + static let heroSource = "flaro.home.heroSource" + static let heroLibraries = "flaro.home.heroLibraries" + static let combinesContinueRows = "flaro.home.combinesContinueRows" + static let hidesWatchedInLatest = "flaro.home.hidesWatchedInLatest" + static let cardScale = "flaro.home.cardScale" + static let heroHeight = "flaro.home.heroHeight" } /// Woraus sich der Aufmacher speist. diff --git a/Halo/Session/JellyfinSignInModel.swift b/Flaro/Session/JellyfinSignInModel.swift similarity index 98% rename from Halo/Session/JellyfinSignInModel.swift rename to Flaro/Session/JellyfinSignInModel.swift index 0d55b33..caf582b 100644 --- a/Halo/Session/JellyfinSignInModel.swift +++ b/Flaro/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 `HaloSession.Phase`: die +/// Eigenes Modell statt eines weiteren Falls in `FlaroSession.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 Halo dabei nie — +/// angemeldeten Client bestätigt; das Passwort erreicht Flaro 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/Halo/Session/LanguagePreferences.swift b/Flaro/Session/LanguagePreferences.swift similarity index 93% rename from Halo/Session/LanguagePreferences.swift rename to Flaro/Session/LanguagePreferences.swift index 821dafb..40ec1d4 100644 --- a/Halo/Session/LanguagePreferences.swift +++ b/Flaro/Session/LanguagePreferences.swift @@ -1,7 +1,7 @@ import Foundation import Observation import MediaKit -import HaloPlayback +import FlaroPlayback /// 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 = "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" + static let audio = "flaro.playback.audioLanguage" + static let subtitles = "flaro.playback.subtitleLanguage" + static let fallbacks = "flaro.languages.fallbacks" + static let avoidsAudioDescription = "flaro.languages.avoidsAudioDescription" + static let perLibrary = "flaro.languages.library" + static let perSeries = "flaro.languages.series" + static let rememberedTracks = "flaro.languages.seriesTrack" } /// Die Sprachen, die zur Auswahl stehen. diff --git a/Halo/Session/LibraryFeed.swift b/Flaro/Session/LibraryFeed.swift similarity index 100% rename from Halo/Session/LibraryFeed.swift rename to Flaro/Session/LibraryFeed.swift diff --git a/Halo/Session/MediaItem+Presentation.swift b/Flaro/Session/MediaItem+Presentation.swift similarity index 98% rename from Halo/Session/MediaItem+Presentation.swift rename to Flaro/Session/MediaItem+Presentation.swift index 8a44b0b..fa9b7de 100644 --- a/Halo/Session/MediaItem+Presentation.swift +++ b/Flaro/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 HaloDesign, das `MediaItem` gar nicht kennt. +/// übrigen Modellen und nicht in FlaroDesign, das `MediaItem` gar nicht kennt. extension MediaItem { /// Der Titel auf einer Kachel in einer Reihe. /// diff --git a/Halo/Session/NavigationLayoutSettings.swift b/Flaro/Session/NavigationLayoutSettings.swift similarity index 95% rename from Halo/Session/NavigationLayoutSettings.swift rename to Flaro/Session/NavigationLayoutSettings.swift index 83480d8..43ff95a 100644 --- a/Halo/Session/NavigationLayoutSettings.swift +++ b/Flaro/Session/NavigationLayoutSettings.swift @@ -13,8 +13,8 @@ import MediaKit @Observable final class NavigationLayoutSettings { private enum Key { - static let hidden = "halo.navigation.hidden" - static let order = "halo.navigation.order" + static let hidden = "flaro.navigation.hidden" + static let order = "flaro.navigation.order" } private let defaults: UserDefaults diff --git a/Halo/Session/NowPlaying.swift b/Flaro/Session/NowPlaying.swift similarity index 100% rename from Halo/Session/NowPlaying.swift rename to Flaro/Session/NowPlaying.swift diff --git a/Halo/Session/OrientationLock.swift b/Flaro/Session/OrientationLock.swift similarity index 100% rename from Halo/Session/OrientationLock.swift rename to Flaro/Session/OrientationLock.swift diff --git a/Halo/Session/PlaybackCoordinator.swift b/Flaro/Session/PlaybackCoordinator.swift similarity index 100% rename from Halo/Session/PlaybackCoordinator.swift rename to Flaro/Session/PlaybackCoordinator.swift diff --git a/Halo/Session/PlaybackDiagnostics.swift b/Flaro/Session/PlaybackDiagnostics.swift similarity index 99% rename from Halo/Session/PlaybackDiagnostics.swift rename to Flaro/Session/PlaybackDiagnostics.swift index 015dfe5..abc8afb 100644 --- a/Halo/Session/PlaybackDiagnostics.swift +++ b/Flaro/Session/PlaybackDiagnostics.swift @@ -1,6 +1,6 @@ import Foundation import Observation -import HaloPlayback +import FlaroPlayback /// Hält fest, was beim letzten Abspielversuch passiert ist. /// diff --git a/Halo/Session/PlaybackSettings.swift b/Flaro/Session/PlaybackSettings.swift similarity index 87% rename from Halo/Session/PlaybackSettings.swift rename to Flaro/Session/PlaybackSettings.swift index b5310a3..af860bb 100644 --- a/Halo/Session/PlaybackSettings.swift +++ b/Flaro/Session/PlaybackSettings.swift @@ -1,6 +1,6 @@ import Foundation import Observation -import HaloPlayback +import FlaroPlayback /// Was der Nutzer über die Wiedergabe eingestellt hat. /// @@ -28,19 +28,19 @@ final class PlaybackSettings { } private enum Key { - 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" + static let wifiQuality = "flaro.playback.quality.wifi" + static let cellularQuality = "flaro.playback.quality.cellular" + static let autoSkipIntro = "flaro.playback.autoSkipIntro" + static let autoSkipCredits = "flaro.playback.autoSkipCredits" + static let autoPlayNext = "flaro.playback.autoPlayNext" + static let locksLandscape = "flaro.playback.locksLandscape" + static let rewindSeconds = "flaro.playback.rewindSeconds" + static let forwardSeconds = "flaro.playback.forwardSeconds" + static let defaultRate = "flaro.playback.defaultRate" + static let remembersQuality = "flaro.playback.remembersQuality" + static let rememberedQuality = "flaro.playback.rememberedQuality" + static let showsBitrate = "flaro.playback.showsBitrate" + static let lastPlaybackStruggled = "flaro.playback.struggled" } /// Die Sprünge, die es zur Auswahl gibt. diff --git a/Halo/Session/QuickPlay.swift b/Flaro/Session/QuickPlay.swift similarity index 100% rename from Halo/Session/QuickPlay.swift rename to Flaro/Session/QuickPlay.swift diff --git a/Halo/Session/ScreenSafeArea.swift b/Flaro/Session/ScreenSafeArea.swift similarity index 100% rename from Halo/Session/ScreenSafeArea.swift rename to Flaro/Session/ScreenSafeArea.swift diff --git a/Halo/Session/SearchFeed.swift b/Flaro/Session/SearchFeed.swift similarity index 98% rename from Halo/Session/SearchFeed.swift rename to Flaro/Session/SearchFeed.swift index 768987e..4155e13 100644 --- a/Halo/Session/SearchFeed.swift +++ b/Flaro/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 = "halo.search.recent" + private static let recentKey = "flaro.search.recent" private(set) var hubs: [MediaRowGroup] = [] private(set) var isSearching = false diff --git a/Halo/Session/SubtitleAppearance.swift b/Flaro/Session/SubtitleAppearance.swift similarity index 91% rename from Halo/Session/SubtitleAppearance.swift rename to Flaro/Session/SubtitleAppearance.swift index 3c28e1f..8eddd93 100644 --- a/Halo/Session/SubtitleAppearance.swift +++ b/Flaro/Session/SubtitleAppearance.swift @@ -1,6 +1,6 @@ import Foundation import Observation -import HaloPlayback +import FlaroPlayback /// Wie Untertitel aussehen sollen — gemerkt über Neustarts hinweg. /// @@ -14,8 +14,8 @@ import HaloPlayback @Observable final class SubtitleAppearance { private enum Key { - static let size = "halo.subtitles.size" - static let palette = "halo.subtitles.palette" + static let size = "flaro.subtitles.size" + static let palette = "flaro.subtitles.palette" } private let defaults: UserDefaults diff --git a/Halo/Session/SubtitleStyle+Labels.swift b/Flaro/Session/SubtitleStyle+Labels.swift similarity index 98% rename from Halo/Session/SubtitleStyle+Labels.swift rename to Flaro/Session/SubtitleStyle+Labels.swift index 753918a..df6644c 100644 --- a/Halo/Session/SubtitleStyle+Labels.swift +++ b/Flaro/Session/SubtitleStyle+Labels.swift @@ -1,4 +1,4 @@ -import HaloPlayback +import FlaroPlayback import Foundation /// Die Namen der Stufen stehen neben dem Modell, nicht darin — dasselbe diff --git a/Halo/Session/TopShelfWriter.swift b/Flaro/Session/TopShelfWriter.swift similarity index 97% rename from Halo/Session/TopShelfWriter.swift rename to Flaro/Session/TopShelfWriter.swift index 976399c..78d158a 100644 --- a/Halo/Session/TopShelfWriter.swift +++ b/Flaro/Session/TopShelfWriter.swift @@ -1,6 +1,6 @@ // **Die ganze Datei nur für den Fernseher.** // -// Sie liegt im geteilten Ordner, weil `Halo/Session/` von beiden Zielen +// Sie liegt im geteilten Ordner, weil `Flaro/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.halo" + static let group = "group.com.scarriffleservices.flaro" /// Die Kante, in der das Regal Plakate zeigt. /// diff --git a/Halo/Views/Components/ItemActionEntries.swift b/Flaro/Views/Components/ItemActionEntries.swift similarity index 98% rename from Halo/Views/Components/ItemActionEntries.swift rename to Flaro/Views/Components/ItemActionEntries.swift index 2609a0a..973851c 100644 --- a/Halo/Views/Components/ItemActionEntries.swift +++ b/Flaro/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 haloItemChanged: () async -> Void = {} + @Entry var flaroItemChanged: () async -> Void = {} } diff --git a/Halo/Views/Components/QuickPlayTile.swift b/Flaro/Views/Components/QuickPlayTile.swift similarity index 96% rename from Halo/Views/Components/QuickPlayTile.swift rename to Flaro/Views/Components/QuickPlayTile.swift index a6c04ed..3f6e6c1 100644 --- a/Halo/Views/Components/QuickPlayTile.swift +++ b/Flaro/Views/Components/QuickPlayTile.swift @@ -1,6 +1,6 @@ import SwiftUI -import HaloDesign -import HaloDownloads +import FlaroDesign +import FlaroDownloads 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 `HaloDesign`, und das Paket ist ohne Abhängigkeiten deklariert — es +/// in `FlaroDesign`, 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(HaloSession.self) private var session + @Environment(FlaroSession.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(\.haloAccent) private var accent + @Environment(\.flaroAccent) 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(\.haloItemChanged) private var itemChanged + @Environment(\.flaroItemChanged) private var itemChanged /// Der Weg auf die Detailseite — siehe `MediaStack`. - @Environment(\.haloPush) private var push + @Environment(\.flaroPush) private var push - private var isMac: Bool { HaloPlatform.isMac } + private var isMac: Bool { FlaroPlatform.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(HaloSpacing.snug) + .padding(FlaroSpacing.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/Halo/Views/Detail/ItemActionsMenu.swift b/Flaro/Views/Detail/ItemActionsMenu.swift similarity index 97% rename from Halo/Views/Detail/ItemActionsMenu.swift rename to Flaro/Views/Detail/ItemActionsMenu.swift index 3eec8ef..546fadf 100644 --- a/Halo/Views/Detail/ItemActionsMenu.swift +++ b/Flaro/Views/Detail/ItemActionsMenu.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign import MediaKit /// Das Aktionsmenü auf einer Detailseite. @@ -17,7 +17,7 @@ struct ItemActionsMenu: View { /// Detailseite neu geladen werden sollte. let onChange: () async -> Void - @Environment(HaloSession.self) private var session + @Environment(FlaroSession.self) private var session @State private var isWorking = false @State private var errorMessage: String? diff --git a/Halo/Views/Detail/MediaDetailView.swift b/Flaro/Views/Detail/MediaDetailView.swift similarity index 89% rename from Halo/Views/Detail/MediaDetailView.swift rename to Flaro/Views/Detail/MediaDetailView.swift index c4c527d..72af4d5 100644 --- a/Halo/Views/Detail/MediaDetailView.swift +++ b/Flaro/Views/Detail/MediaDetailView.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign import MediaKit /// Die Detailseite eines Titels. @@ -10,7 +10,7 @@ import MediaKit struct MediaDetailView: View { let route: MediaRoute - @Environment(HaloSession.self) private var session + @Environment(FlaroSession.self) private var session @State private var state: LoadState = .loading var body: some View { @@ -37,12 +37,12 @@ struct MediaDetailView: View { } } } - .background(Color.haloCanvas) + .background(Color.flaroCanvas) .navigationTitle(state.value?.title ?? route.title) - .haloInlineTitle() + .flaroInlineTitle() .toolbar { if let item = state.value { - ToolbarItem(placement: .haloTrailing) { + ToolbarItem(placement: .flaroTrailing) { ItemActionsMenu(item: item) { await load() } } } diff --git a/Halo/Views/Detail/ParentLinks.swift b/Flaro/Views/Detail/ParentLinks.swift similarity index 85% rename from Halo/Views/Detail/ParentLinks.swift rename to Flaro/Views/Detail/ParentLinks.swift index abf61d4..930b691 100644 --- a/Halo/Views/Detail/ParentLinks.swift +++ b/Flaro/Views/Detail/ParentLinks.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign 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: HaloSpacing.snug) { + HStack(spacing: FlaroSpacing.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(.haloCaption) - .foregroundStyle(Color.haloTextPrimary) - .padding(.horizontal, HaloSpacing.regular) - .padding(.vertical, HaloSpacing.snug) - .background(Color.haloElevated, in: .capsule) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextPrimary) + .padding(.horizontal, FlaroSpacing.regular) + .padding(.vertical, FlaroSpacing.snug) + .background(Color.flaroElevated, in: .capsule) } .buttonStyle(.plain) } } - .padding(.horizontal, HaloSpacing.screenMargin) + .padding(.horizontal, FlaroSpacing.screenMargin) } .scrollIndicators(.never) } diff --git a/Halo/Views/Detail/PlayableDetailView.swift b/Flaro/Views/Detail/PlayableDetailView.swift similarity index 80% rename from Halo/Views/Detail/PlayableDetailView.swift rename to Flaro/Views/Detail/PlayableDetailView.swift index 061ee82..539c35a 100644 --- a/Halo/Views/Detail/PlayableDetailView.swift +++ b/Flaro/Views/Detail/PlayableDetailView.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign 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(HaloSession.self) private var session + @Environment(FlaroSession.self) private var session @Environment(PlaybackCoordinator.self) private var playback - @Environment(\.haloAccent) private var accent + @Environment(\.flaroAccent) 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: HaloSpacing.section) { + VStack(alignment: .leading, spacing: FlaroSpacing.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, HaloSpacing.screenMargin) + .padding(.horizontal, FlaroSpacing.screenMargin) } if let summary = item.summary, !summary.isEmpty { Text(summary) - .font(.haloBody) - .foregroundStyle(Color.haloTextSecondary) - .padding(.horizontal, HaloSpacing.screenMargin) + .font(.flaroBody) + .foregroundStyle(Color.flaroTextSecondary) + .padding(.horizontal, FlaroSpacing.screenMargin) } if !item.genres.isEmpty { @@ -53,13 +53,13 @@ struct PlayableDetailView: View { part: part, isExpanded: $showsTechnicalDetails ) - .padding(.horizontal, HaloSpacing.screenMargin) + .padding(.horizontal, FlaroSpacing.screenMargin) } } - .padding(.bottom, HaloSpacing.section) + .padding(.bottom, FlaroSpacing.section) } .scrollIndicators(.never) - .haloRevealsTopChrome() + .flaroRevealsTopChrome() } private var currentMedia: MediaVersion? { @@ -104,9 +104,9 @@ struct PlayableDetailView: View { item.watchProgress == nil ? "hero.play" : "hero.resume", systemImage: "play.fill" ) - .font(.haloCardTitle) - .padding(.horizontal, HaloSpacing.loose) - .padding(.vertical, HaloSpacing.snug) + .font(.flaroCardTitle) + .padding(.horizontal, FlaroSpacing.loose) + .padding(.vertical, FlaroSpacing.snug) } .buttonStyle(.borderedProminent) .tint(accent) @@ -118,11 +118,11 @@ struct PlayableDetailView: View { } label: { Label("detail.playFromStart", systemImage: "gobackward") .labelStyle(.iconOnly) - .font(.haloCardTitle) - .padding(HaloSpacing.snug) + .font(.flaroCardTitle) + .padding(FlaroSpacing.snug) } .buttonStyle(.bordered) - .tint(Color.haloTextSecondary) + .tint(Color.flaroTextSecondary) } DownloadButton(item: item, mediaIndex: selectedVersion) @@ -210,10 +210,10 @@ struct VersionPicker: View { @Binding var selection: Int var body: some View { - VStack(alignment: .leading, spacing: HaloSpacing.snug) { + VStack(alignment: .leading, spacing: FlaroSpacing.snug) { Text("detail.versions") - .font(.haloRowHeader) - .foregroundStyle(Color.haloTextPrimary) + .font(.flaroRowHeader) + .foregroundStyle(Color.flaroTextPrimary) 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: HaloSpacing.snug) { + HStack(spacing: FlaroSpacing.snug) { ForEach(tags, id: \.self) { tag in Text(tag) - .font(.haloCaption) - .foregroundStyle(Color.haloTextSecondary) - .padding(.horizontal, HaloSpacing.regular) - .padding(.vertical, HaloSpacing.tight) - .background(Color.haloElevated, in: .capsule) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextSecondary) + .padding(.horizontal, FlaroSpacing.regular) + .padding(.vertical, FlaroSpacing.tight) + .background(Color.flaroElevated, in: .capsule) } } - .padding(.horizontal, HaloSpacing.screenMargin) + .padding(.horizontal, FlaroSpacing.screenMargin) } .scrollIndicators(.never) } @@ -251,20 +251,20 @@ struct TagStrip: View { /// Die Besetzung mit Porträts. struct CastRow: View { let cast: [MediaPerson] - @Environment(HaloSession.self) private var session + @Environment(FlaroSession.self) private var session var body: some View { - VStack(alignment: .leading, spacing: HaloSpacing.regular) { + VStack(alignment: .leading, spacing: FlaroSpacing.regular) { Text("detail.cast") - .font(.haloRowHeader) - .foregroundStyle(Color.haloTextPrimary) - .padding(.horizontal, HaloSpacing.screenMargin) + .font(.flaroRowHeader) + .foregroundStyle(Color.flaroTextPrimary) + .padding(.horizontal, FlaroSpacing.screenMargin) ScrollView(.horizontal) { - HStack(alignment: .top, spacing: HaloSpacing.regular) { + HStack(alignment: .top, spacing: FlaroSpacing.regular) { ForEach(cast.prefix(20)) { role in - VStack(spacing: HaloSpacing.snug) { - HaloArtwork( + VStack(spacing: FlaroSpacing.snug) { + FlaroArtwork( 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(.haloCaption) - .foregroundStyle(Color.haloTextPrimary) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextPrimary) .lineLimit(2) .multilineTextAlignment(.center) if let character = role.role { Text(character) - .font(.haloCaption) - .foregroundStyle(Color.haloTextMuted) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextMuted) .lineLimit(1) } } @@ -289,7 +289,7 @@ struct CastRow: View { .accessibilityElement(children: .combine) } } - .padding(.horizontal, HaloSpacing.screenMargin) + .padding(.horizontal, FlaroSpacing.screenMargin) } .scrollIndicators(.never) } diff --git a/Halo/Views/Detail/SeriesDetailView.swift b/Flaro/Views/Detail/SeriesDetailView.swift similarity index 88% rename from Halo/Views/Detail/SeriesDetailView.swift rename to Flaro/Views/Detail/SeriesDetailView.swift index dc93fb7..e3a777c 100644 --- a/Halo/Views/Detail/SeriesDetailView.swift +++ b/Flaro/Views/Detail/SeriesDetailView.swift @@ -1,6 +1,6 @@ import SwiftUI -import HaloDesign -import HaloDownloads +import FlaroDesign +import FlaroDownloads import MediaKit /// Die Detailseite einer Serie oder Staffel. @@ -10,10 +10,10 @@ import MediaKit struct SeriesDetailView: View { let item: MediaItem - @Environment(HaloSession.self) private var session + @Environment(FlaroSession.self) private var session @Environment(DownloadCoordinator.self) private var downloads @Environment(LanguagePreferences.self) private var languages - @Environment(\.haloAccent) private var accent + @Environment(\.flaroAccent) 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: HaloSpacing.section) { + VStack(alignment: .leading, spacing: FlaroSpacing.section) { header ParentLinks(item: item) if let summary = item.summary, !summary.isEmpty { Text(summary) - .font(.haloBody) - .foregroundStyle(Color.haloTextSecondary) - .padding(.horizontal, HaloSpacing.screenMargin) + .font(.flaroBody) + .foregroundStyle(Color.flaroTextSecondary) + .padding(.horizontal, FlaroSpacing.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, HaloSpacing.screenMargin) + .padding(.horizontal, FlaroSpacing.screenMargin) } childList if !item.cast.isEmpty { CastRow(cast: item.cast) } } - .padding(.bottom, HaloSpacing.section) + .padding(.bottom, FlaroSpacing.section) } .scrollIndicators(.never) - .haloRevealsTopChrome() + .flaroRevealsTopChrome() .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, HaloSpacing.section) + ProgressView().frame(maxWidth: .infinity).padding(.vertical, FlaroSpacing.section) case .failed(let message): Text(message) - .font(.haloCaption) - .foregroundStyle(Color.haloTextMuted) - .padding(.horizontal, HaloSpacing.screenMargin) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextMuted) + .padding(.horizontal, FlaroSpacing.screenMargin) case .loaded(let entries): - VStack(alignment: .leading, spacing: HaloSpacing.regular) { + VStack(alignment: .leading, spacing: FlaroSpacing.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(.haloRowHeader) - .foregroundStyle(Color.haloTextPrimary) + .font(.flaroRowHeader) + .foregroundStyle(Color.flaroTextPrimary) Spacer() if entries.contains(where: { $0.kind == .episode }) { selectionControls(for: entries) } } - .padding(.horizontal, HaloSpacing.screenMargin) + .padding(.horizontal, FlaroSpacing.screenMargin) LazyVStack(spacing: 0) { ForEach(entries) { entry in row(for: entry) - Divider().overlay(Color.haloSeparator) + Divider().overlay(Color.flaroSeparator) } } } @@ -207,16 +207,16 @@ struct SeriesDetailView: View { Button { if gewaehlt { selection.remove(entry.id) } else { selection.insert(entry.id) } } label: { - HStack(spacing: HaloSpacing.snug) { + HStack(spacing: FlaroSpacing.snug) { ChildRow(item: entry) Image(systemName: gewaehlt ? "checkmark.circle.fill" : "circle") .font(.title3) - .foregroundStyle(gewaehlt ? accent : Color.haloTextMuted) + .foregroundStyle(gewaehlt ? accent : Color.flaroTextMuted) } .contentShape(.rect) } .buttonStyle(.plain) - .padding(.horizontal, HaloSpacing.screenMargin) + .padding(.horizontal, FlaroSpacing.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: HaloSpacing.snug) { + HStack(spacing: FlaroSpacing.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, HaloSpacing.screenMargin) + .padding(.horizontal, FlaroSpacing.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: HaloSpacing.regular) { + HStack(spacing: FlaroSpacing.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.haloTextSecondary) + .foregroundStyle(Color.flaroTextSecondary) } else { Button("detail.select") { isSelecting = true } } } - .font(.haloCaption) + .font(.flaroCaption) .buttonStyle(.plain) .foregroundStyle(accent) } @@ -288,14 +288,14 @@ struct SeriesDetailView: View { ) } } - .font(.haloCardTitle) - .padding(.horizontal, HaloSpacing.loose) - .padding(.vertical, HaloSpacing.snug) + .font(.flaroCardTitle) + .padding(.horizontal, FlaroSpacing.loose) + .padding(.vertical, FlaroSpacing.snug) } .buttonStyle(.borderedProminent) .tint(accent) .disabled(isWorking) - .padding(.vertical, HaloSpacing.regular) + .padding(.vertical, FlaroSpacing.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(HaloSession.self) private var session + @Environment(FlaroSession.self) private var session var body: some View { - HStack(spacing: HaloSpacing.regular) { - HaloArtwork( + HStack(spacing: FlaroSpacing.regular) { + FlaroArtwork( 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(.haloCardTitle) - .foregroundStyle(Color.haloTextPrimary) + .font(.flaroCardTitle) + .foregroundStyle(Color.flaroTextPrimary) .lineLimit(2) if let subtitle { Text(subtitle) - .font(.haloCaption) - .foregroundStyle(Color.haloTextMuted) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextMuted) .lineLimit(1) } } @@ -427,14 +427,14 @@ private struct ChildRow: View { if item.isWatched { Image(systemName: "checkmark.circle.fill") - .foregroundStyle(Color.haloTextMuted) + .foregroundStyle(Color.flaroTextMuted) .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, HaloSpacing.snug) + .padding(.vertical, FlaroSpacing.snug) .contentShape(.rect) .accessibilityElement(children: .combine) } diff --git a/Halo/Views/Detail/TechnicalDetails.swift b/Flaro/Views/Detail/TechnicalDetails.swift similarity index 84% rename from Halo/Views/Detail/TechnicalDetails.swift rename to Flaro/Views/Detail/TechnicalDetails.swift index 6b037f5..f0cd6c0 100644 --- a/Halo/Views/Detail/TechnicalDetails.swift +++ b/Flaro/Views/Detail/TechnicalDetails.swift @@ -1,11 +1,11 @@ import SwiftUI -import HaloDesign -import HaloPlayback +import FlaroDesign +import FlaroPlayback import MediaKit /// Die aufklappbaren technischen Angaben zu einer Datei. /// -/// Zeigt nicht nur, was in der Datei steckt, sondern auch, wie Halo sie +/// Zeigt nicht nur, was in der Datei steckt, sondern auch, wie Flaro 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: HaloSpacing.snug) { + VStack(alignment: .leading, spacing: FlaroSpacing.snug) { row("technical.playbackMethod", playbackMethodLabel) if let reason = rationaleLabel { row("technical.reason", reason) } - Divider().overlay(Color.haloSeparator).padding(.vertical, HaloSpacing.tight) + Divider().overlay(Color.flaroSeparator).padding(.vertical, FlaroSpacing.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.haloSeparator).padding(.vertical, HaloSpacing.tight) + Divider().overlay(Color.flaroSeparator).padding(.vertical, FlaroSpacing.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.haloSeparator).padding(.vertical, HaloSpacing.tight) + Divider().overlay(Color.flaroSeparator).padding(.vertical, FlaroSpacing.tight) VStack(alignment: .leading, spacing: 2) { Text("technical.file") - .font(.haloCaption) - .foregroundStyle(Color.haloTextMuted) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextMuted) Text(file) .font(.system(.caption, design: .monospaced)) - .foregroundStyle(Color.haloTextSecondary) + .foregroundStyle(Color.flaroTextSecondary) .textSelection(.enabled) } } } - .padding(.top, HaloSpacing.snug) + .padding(.top, FlaroSpacing.snug) } label: { Text("technical.title") - .font(.haloRowHeader) - .foregroundStyle(Color.haloTextPrimary) + .font(.flaroRowHeader) + .foregroundStyle(Color.flaroTextPrimary) } - .tint(Color.haloTextSecondary) + .tint(Color.flaroTextSecondary) } private func row(_ label: LocalizedStringKey, _ value: String) -> some View { HStack(alignment: .top) { Text(label) - .font(.haloCaption) - .foregroundStyle(Color.haloTextMuted) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextMuted) Spacer() Text(value) - .font(.haloCaption) - .foregroundStyle(Color.haloTextSecondary) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextSecondary) .multilineTextAlignment(.trailing) } } diff --git a/Halo/Views/Downloads/DownloadButton.swift b/Flaro/Views/Downloads/DownloadButton.swift similarity index 96% rename from Halo/Views/Downloads/DownloadButton.swift rename to Flaro/Views/Downloads/DownloadButton.swift index 6fa8e2c..c359416 100644 --- a/Halo/Views/Downloads/DownloadButton.swift +++ b/Flaro/Views/Downloads/DownloadButton.swift @@ -1,6 +1,6 @@ import SwiftUI -import HaloDesign -import HaloDownloads +import FlaroDesign +import FlaroDownloads import MediaKit /// Der Download-Knopf auf einer Detailseite. @@ -25,10 +25,10 @@ struct DownloadButton: View { /// nicht drückt. var loadsDetails: Bool = false - @Environment(HaloSession.self) private var session + @Environment(FlaroSession.self) private var session @Environment(DownloadCoordinator.self) private var downloads @Environment(LanguagePreferences.self) private var languages - @Environment(\.haloAccent) private var accent + @Environment(\.flaroAccent) 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(.haloCardTitle) + .font(.flaroCardTitle) } } // 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(HaloSpacing.snug) + .padding(FlaroSpacing.snug) } .disabled(isLoadingDetails) .buttonStyle(.bordered) - .tint(existing?.state == .completed ? accent : Color.haloTextSecondary) + .tint(existing?.state == .completed ? accent : Color.flaroTextSecondary) .accessibilityLabel(Text(label)) .confirmationDialog( Text("downloads.quality.title"), @@ -247,10 +247,10 @@ extension DownloadQuality { struct DownloadAllButton: View { let container: MediaItem - @Environment(HaloSession.self) private var session + @Environment(FlaroSession.self) private var session @Environment(DownloadCoordinator.self) private var downloads @Environment(LanguagePreferences.self) private var languages - @Environment(\.haloAccent) private var accent + @Environment(\.flaroAccent) private var accent @State private var isWorking = false @State private var summary: String? @@ -269,7 +269,7 @@ struct DownloadAllButton: View { } } .buttonStyle(.bordered) - .tint(Color.haloTextSecondary) + .tint(Color.flaroTextSecondary) .disabled(isWorking) .alert( Text("downloads.batch.title"), diff --git a/Halo/Views/Downloads/DownloadQualityChoice.swift b/Flaro/Views/Downloads/DownloadQualityChoice.swift similarity index 99% rename from Halo/Views/Downloads/DownloadQualityChoice.swift rename to Flaro/Views/Downloads/DownloadQualityChoice.swift index 5c81f10..ec993f4 100644 --- a/Halo/Views/Downloads/DownloadQualityChoice.swift +++ b/Flaro/Views/Downloads/DownloadQualityChoice.swift @@ -1,5 +1,5 @@ import Foundation -import HaloDownloads +import FlaroDownloads import MediaKit /// Welche Qualitätsstufen für einen Titel zur Wahl stehen — und wie sie heißen. diff --git a/Halo/Views/Downloads/DownloadsView.swift b/Flaro/Views/Downloads/DownloadsView.swift similarity index 87% rename from Halo/Views/Downloads/DownloadsView.swift rename to Flaro/Views/Downloads/DownloadsView.swift index ec71a40..4a16cfd 100644 --- a/Halo/Views/Downloads/DownloadsView.swift +++ b/Flaro/Views/Downloads/DownloadsView.swift @@ -1,14 +1,14 @@ import SwiftUI -import HaloDesign -import HaloDownloads -import HaloPlayback +import FlaroDesign +import FlaroDownloads +import FlaroPlayback /// 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(\.haloAccent) private var accent + @Environment(\.flaroAccent) private var accent @Environment(\.horizontalSizeClass) private var sizeClass @@ -24,16 +24,16 @@ struct DownloadsView: View { list } } - .background(Color.haloCanvas) + .background(Color.flaroCanvas) .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: .haloTrailing) { AccountToolbarButton() } + ToolbarItem(placement: .flaroTrailing) { AccountToolbarButton() } } } - .haloInlineTitle() + .flaroInlineTitle() // 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.haloSurface) - .haloRevealsTopChrome() + .listRowBackground(Color.flaroSurface) + .flaroRevealsTopChrome() } 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(\.haloAccent) private var accent + @Environment(\.flaroAccent) 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.haloTextSecondary) + .foregroundStyle(Color.flaroTextSecondary) Spacer() Text(downloads.usedBytes.formatted(.byteCount(style: .file))) - .foregroundStyle(Color.haloTextPrimary) + .foregroundStyle(Color.flaroTextPrimary) } 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(\.haloAccent) private var accent + @Environment(\.flaroAccent) private var accent var body: some View { - VStack(alignment: .leading, spacing: HaloSpacing.snug) { - HStack(spacing: HaloSpacing.regular) { + VStack(alignment: .leading, spacing: FlaroSpacing.snug) { + HStack(spacing: FlaroSpacing.regular) { VStack(alignment: .leading, spacing: 2) { Text(item.title) - .font(.haloCardTitle) - .foregroundStyle(Color.haloTextPrimary) + .font(.flaroCardTitle) + .foregroundStyle(Color.flaroTextPrimary) .lineLimit(1) if let subtitle = item.subtitle { Text(subtitle) - .font(.haloCaption) - .foregroundStyle(Color.haloTextMuted) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextMuted) .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(.haloCaption) - .foregroundStyle(Color.haloTextMuted) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextMuted) } if let message = item.failureMessage { Text(message) - .font(.haloCaption) - .foregroundStyle(Color.haloDestructive) + .font(.flaroCaption) + .foregroundStyle(Color.flaroDestructive) .lineLimit(2) } } - .padding(.vertical, HaloSpacing.tight) - .listRowBackground(Color.haloSurface) + .padding(.vertical, FlaroSpacing.tight) + .listRowBackground(Color.flaroSurface) .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.haloTextMuted) + .foregroundStyle(Color.flaroTextMuted) .accessibilityLabel(Text("downloads.available")) case .queued, .waiting: Image(systemName: "clock") - .foregroundStyle(Color.haloTextMuted) + .foregroundStyle(Color.flaroTextMuted) .accessibilityLabel(Text("downloads.queued")) } } private var progress: some View { - VStack(alignment: .leading, spacing: HaloSpacing.tight) { + VStack(alignment: .leading, spacing: FlaroSpacing.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: HaloSpacing.snug) { + HStack(alignment: .firstTextBaseline, spacing: FlaroSpacing.snug) { Text(statusLine) .lineLimit(1) - Spacer(minLength: HaloSpacing.snug) + Spacer(minLength: FlaroSpacing.snug) if let percentage { Text(percentage) } } - .font(.haloCaption) + .font(.flaroCaption) .monospacedDigit() - .foregroundStyle(Color.haloTextMuted) + .foregroundStyle(Color.flaroTextMuted) } } @@ -387,28 +387,28 @@ private struct DownloadRow: View { private struct HoldNotice: View { let hold: TransferHold - @Environment(\.haloAccent) private var accent + @Environment(\.flaroAccent) private var accent var body: some View { - HStack(alignment: .top, spacing: HaloSpacing.regular) { + HStack(alignment: .top, spacing: FlaroSpacing.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(.haloCardTitle) - .foregroundStyle(Color.haloTextPrimary) + .font(.flaroCardTitle) + .foregroundStyle(Color.flaroTextPrimary) Text(hold == .offline ? "downloads.hold.offline.description" : "downloads.hold.wifi.description") - .font(.haloCaption) - .foregroundStyle(Color.haloTextSecondary) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextSecondary) } } - .padding(.vertical, HaloSpacing.tight) - .listRowBackground(Color.haloSurface) + .padding(.vertical, FlaroSpacing.tight) + .listRowBackground(Color.flaroSurface) .accessibilityElement(children: .combine) } } diff --git a/Halo/Views/Home/HeroCarousel.swift b/Flaro/Views/Home/HeroCarousel.swift similarity index 97% rename from Halo/Views/Home/HeroCarousel.swift rename to Flaro/Views/Home/HeroCarousel.swift index d414e37..8b5050c 100644 --- a/Halo/Views/Home/HeroCarousel.swift +++ b/Flaro/Views/Home/HeroCarousel.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign 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(\.haloAccent) private var accent - @Environment(HaloSession.self) private var session + @Environment(\.flaroAccent) private var accent + @Environment(FlaroSession.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: HaloSpacing.regular) { + VStack(spacing: FlaroSpacing.regular) { heroSection // Die Höhe: fast das ganze Fenster. // @@ -189,7 +189,7 @@ struct HeroCarousel: View { } } - private var isMac: Bool { HaloPlatform.isMac } + private var isMac: Bool { FlaroPlatform.isMac } /// Die beiden Pfeile links und rechts. /// @@ -203,7 +203,7 @@ struct HeroCarousel: View { Spacer() arrow(symbol: "chevron.right", direction: 1) } - .padding(.horizontal, HaloSpacing.regular) + .padding(.horizontal, FlaroSpacing.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(HaloSpacing.regular) + .padding(FlaroSpacing.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 ? HaloSpacing.regular : HaloSpacing.snug) { + HStack(spacing: isEnlarged ? FlaroSpacing.regular : FlaroSpacing.snug) { ForEach(items.indices, id: \.self) { position in Capsule() - .fill(position == currentIndex ? accent : Color.haloTextMuted.opacity(0.4)) + .fill(position == currentIndex ? accent : Color.flaroTextMuted.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, HaloSpacing.snug) + .padding(.vertical, FlaroSpacing.snug) .contentShape(.rect) .onContinuousHover { phase in guard isMac else { return } diff --git a/Halo/Views/Home/HeroSection.swift b/Flaro/Views/Home/HeroSection.swift similarity index 89% rename from Halo/Views/Home/HeroSection.swift rename to Flaro/Views/Home/HeroSection.swift index 4e68112..f6c7732 100644 --- a/Halo/Views/Home/HeroSection.swift +++ b/Flaro/Views/Home/HeroSection.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign 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(HaloSession.self) private var session + @Environment(FlaroSession.self) private var session @Environment(PlaybackCoordinator.self) private var playback @Environment(QuickPlay.self) private var quickPlay - @Environment(\.haloAccent) private var accent + @Environment(\.flaroAccent) 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(.haloCardTitle) - .padding(.horizontal, HaloSpacing.loose) - .padding(.vertical, HaloSpacing.snug) + .font(.flaroCardTitle) + .padding(.horizontal, FlaroSpacing.loose) + .padding(.vertical, FlaroSpacing.snug) } .buttonStyle(.borderedProminent) .tint(accent) NavigationLink(value: MediaRoute(ratingKey: item.id, title: item.title)) { Label("hero.details", systemImage: "info.circle") - .font(.haloCardTitle) - .padding(.horizontal, HaloSpacing.loose) - .padding(.vertical, HaloSpacing.snug) + .font(.flaroCardTitle) + .padding(.horizontal, FlaroSpacing.loose) + .padding(.vertical, FlaroSpacing.snug) } .buttonStyle(.bordered) - .tint(Color.haloTextSecondary) + .tint(Color.flaroTextSecondary) } } diff --git a/Halo/Views/Home/HomeView.swift b/Flaro/Views/Home/HomeView.swift similarity index 87% rename from Halo/Views/Home/HomeView.swift rename to Flaro/Views/Home/HomeView.swift index 4767a90..cfe0ac9 100644 --- a/Halo/Views/Home/HomeView.swift +++ b/Flaro/Views/Home/HomeView.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign 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(HaloSession.self) private var session + @Environment(FlaroSession.self) private var session @Environment(HomeLayoutSettings.self) private var layout @State private var feed = HomeFeed() @@ -41,17 +41,17 @@ struct HomeView: View { } } } - .background(Color.haloCanvas) + .background(Color.flaroCanvas) // 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("") - .haloInlineTitle() + .flaroInlineTitle() // 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. - .haloClearToolbarBackground() + .flaroClearToolbarBackground() // 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(\.haloItemChanged, { await feed.load(from: session.backend) }) + .environment(\.flaroItemChanged, { await feed.load(from: session.backend) }) } private func content(hubs: [MediaRowGroup]) -> some View { ScrollView { - LazyVStack(alignment: .leading, spacing: HaloSpacing.section) { + LazyVStack(alignment: .leading, spacing: FlaroSpacing.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, HaloSpacing.section) + .padding(.bottom, FlaroSpacing.section) } .scrollIndicators(.never) - .haloRevealsTopChrome() + .flaroRevealsTopChrome() } } diff --git a/Halo/Views/Home/MediaRow.swift b/Flaro/Views/Home/MediaRow.swift similarity index 85% rename from Halo/Views/Home/MediaRow.swift rename to Flaro/Views/Home/MediaRow.swift index 4f2868f..e9cdffc 100644 --- a/Halo/Views/Home/MediaRow.swift +++ b/Flaro/Views/Home/MediaRow.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign import MediaKit /// Eine waagerechte Reihe von Titeln. @@ -8,7 +8,7 @@ struct MediaRow: View { /// Wird durchgereicht — siehe `QuickPlayTile`. var opensDetails: Bool = false - @Environment(HaloSession.self) private var session + @Environment(FlaroSession.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: HaloSpacing.regular) { + VStack(alignment: .leading, spacing: FlaroSpacing.regular) { Text(row.title) - .font(.haloRowHeader) - .foregroundStyle(Color.haloTextPrimary) - .padding(.horizontal, HaloSpacing.screenMargin) + .font(.flaroRowHeader) + .foregroundStyle(Color.flaroTextPrimary) + .padding(.horizontal, FlaroSpacing.screenMargin) ScrollView(.horizontal) { - LazyHStack(spacing: HaloSpacing.regular) { + LazyHStack(spacing: FlaroSpacing.regular) { ForEach(row.items) { item in QuickPlayTile(item: item, opensDetails: opensDetails) { card(for: item) } } } - .padding(.horizontal, HaloSpacing.screenMargin) + .padding(.horizontal, FlaroSpacing.screenMargin) // Ohne dieses Ziel rasten die Kacheln nicht ein und die Reihe // bleibt an beliebiger Stelle stehen. .scrollTargetLayout() diff --git a/Halo/Views/Library/LibraryBrowser.swift b/Flaro/Views/Library/LibraryBrowser.swift similarity index 89% rename from Halo/Views/Library/LibraryBrowser.swift rename to Flaro/Views/Library/LibraryBrowser.swift index 9637093..143e5cf 100644 --- a/Halo/Views/Library/LibraryBrowser.swift +++ b/Flaro/Views/Library/LibraryBrowser.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign 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(HaloSession.self) private var session + @Environment(FlaroSession.self) private var session /// Was gerade gezeigt wird. /// @@ -36,7 +36,7 @@ struct LibraryBrowser: View { var body: some View { inhalt - .background(Color.haloCanvas) + .background(Color.flaroCanvas) // **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 { HaloSidebar.surface(in: .capsule) } + .background { FlaroSidebar.surface(in: .capsule) } .clipShape(.capsule) .shadow(color: .black.opacity(0.45), radius: 18, y: 6) - .padding(.horizontal, HaloSpacing.regular) - .padding(.bottom, HaloSpacing.snug) + .padding(.horizontal, FlaroSpacing.regular) + .padding(.bottom, FlaroSpacing.snug) } private var reihe: some View { @@ -99,8 +99,8 @@ struct LibraryBrowser: View { pille(eintrag) } } - .padding(.horizontal, HaloSpacing.snug) - .padding(.vertical, HaloSpacing.snug) + .padding(.horizontal, FlaroSpacing.snug) + .padding(.vertical, FlaroSpacing.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(.haloCaption) - .foregroundStyle(gewaehlt ? Color.haloTextPrimary : Color.haloTextSecondary) - .padding(.horizontal, HaloSpacing.snug) - .padding(.vertical, HaloSpacing.snug) + .font(.flaroCaption) + .foregroundStyle(gewaehlt ? Color.flaroTextPrimary : Color.flaroTextSecondary) + .padding(.horizontal, FlaroSpacing.snug) + .padding(.vertical, FlaroSpacing.snug) .background { - if gewaehlt { Capsule().fill(Color.haloElevated) } + if gewaehlt { Capsule().fill(Color.flaroElevated) } } .contentShape(Capsule()) } diff --git a/Halo/Views/Library/LibraryFilterSheet.swift b/Flaro/Views/Library/LibraryFilterSheet.swift similarity index 95% rename from Halo/Views/Library/LibraryFilterSheet.swift rename to Flaro/Views/Library/LibraryFilterSheet.swift index 48ee206..62ce1bf 100644 --- a/Halo/Views/Library/LibraryFilterSheet.swift +++ b/Flaro/Views/Library/LibraryFilterSheet.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign import MediaKit /// Filter und Sortierung einer Mediathek. @@ -14,8 +14,8 @@ struct LibraryFilterSheet: View { let library: MediaLibrary @Environment(\.dismiss) private var dismiss - @Environment(\.haloAccent) private var accent - @Environment(HaloSession.self) private var session + @Environment(\.flaroAccent) private var accent + @Environment(FlaroSession.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) - .haloForm() + .flaroForm() .scrollContentBackground(.hidden) - .background(Color.haloCanvas) + .background(Color.flaroCanvas) .navigationTitle(Text("filter.title")) - .haloInlineTitle() + .flaroInlineTitle() .toolbar { ToolbarItem(placement: .cancellationAction) { Button("action.cancel") { dismiss() } @@ -109,7 +109,7 @@ struct LibraryFilterSheet: View { } .task { await loadGenres() } } - .haloResizableSheet() + .flaroResizableSheet() } private func loadGenres() async { diff --git a/Halo/Views/Library/LibraryView.swift b/Flaro/Views/Library/LibraryView.swift similarity index 88% rename from Halo/Views/Library/LibraryView.swift rename to Flaro/Views/Library/LibraryView.swift index ab11e08..64f629f 100644 --- a/Halo/Views/Library/LibraryView.swift +++ b/Flaro/Views/Library/LibraryView.swift @@ -1,16 +1,16 @@ import SwiftUI -import HaloDesign +import FlaroDesign import MediaKit /// Eine Mediathek zum Durchblättern. struct LibraryView: View { let library: MediaLibrary - @Environment(HaloSession.self) private var session + @Environment(FlaroSession.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("halo.library.layout") private var layout: LibraryLayout = .grid + @AppStorage("flaro.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.haloCanvas) + .background(Color.flaroCanvas) .navigationTitle(library.title) - .haloInlineTitle() + .flaroInlineTitle() .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(\.haloItemChanged, { await reload() }) + .environment(\.flaroItemChanged, { 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: HaloSpacing.regular)], - spacing: HaloSpacing.loose + columns: [GridItem(.adaptive(minimum: 110 * sizing.cardScale), spacing: FlaroSpacing.regular)], + spacing: FlaroSpacing.loose ) { ForEach(items) { item in QuickPlayTile(item: item) { @@ -119,12 +119,12 @@ struct LibraryView: View { PlaceholderCard(index: position) } } - .padding(HaloSpacing.screenMargin) + .padding(FlaroSpacing.screenMargin) - moreButton.padding(.bottom, HaloSpacing.section) - footerCount.padding(.bottom, HaloSpacing.section) + moreButton.padding(.bottom, FlaroSpacing.section) + footerCount.padding(.bottom, FlaroSpacing.section) } - .haloRevealsTopChrome() + .flaroRevealsTopChrome() } private var list: some View { @@ -137,19 +137,19 @@ struct LibraryView: View { .buttonStyle(.plain) .task { await loadMoreIfNeeded(reaching: item) } - Divider().overlay(Color.haloSeparator) + Divider().overlay(Color.flaroSeparator) } } if pendingCount > 0 { ProgressView() - .padding(.vertical, HaloSpacing.section) + .padding(.vertical, FlaroSpacing.section) .frame(maxWidth: .infinity) } - moreButton.padding(.vertical, HaloSpacing.section) - footerCount.padding(.bottom, HaloSpacing.section) + moreButton.padding(.vertical, FlaroSpacing.section) + footerCount.padding(.bottom, FlaroSpacing.section) } - .haloRevealsTopChrome() + .flaroRevealsTopChrome() } /// 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(.haloCaption) - .foregroundStyle(Color.haloTextMuted) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextMuted) .frame(maxWidth: .infinity) } } @@ -183,10 +183,10 @@ struct LibraryView: View { @ViewBuilder private var moreButton: some View { if loadMoreFailed, let page, page.hasMore { - VStack(spacing: HaloSpacing.snug) { + VStack(spacing: FlaroSpacing.snug) { Text("library.loadMoreFailed") - .font(.haloCaption) - .foregroundStyle(Color.haloTextMuted) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextMuted) 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: .haloTrailing) { + ToolbarItem(placement: .flaroTrailing) { 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: .haloTrailing) { + ToolbarItem(placement: .flaroTrailing) { Button { Task { await reload() } } label: { @@ -228,7 +228,7 @@ struct LibraryView: View { .disabled(isLoadingMore) } - ToolbarItem(placement: .haloTrailing) { + ToolbarItem(placement: .flaroTrailing) { Button { showsFilters = true } label: { @@ -239,7 +239,7 @@ struct LibraryView: View { .accessibilityLabel(Text("library.filters")) } - ToolbarItem(placement: .haloTrailing) { + ToolbarItem(placement: .flaroTrailing) { 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: .haloTrailing) { AccountToolbarButton() } + ToolbarItem(placement: .flaroTrailing) { AccountToolbarButton() } } } @@ -380,11 +380,11 @@ enum LibraryLayout: String, CaseIterable { /// Eine Zeile in der Listenansicht. private struct LibraryListRow: View { let item: MediaItem - @Environment(HaloSession.self) private var session + @Environment(FlaroSession.self) private var session var body: some View { - HStack(spacing: HaloSpacing.regular) { - HaloArtwork( + HStack(spacing: FlaroSpacing.regular) { + FlaroArtwork( 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(.haloCardTitle) - .foregroundStyle(Color.haloTextPrimary) + .font(.flaroCardTitle) + .foregroundStyle(Color.flaroTextPrimary) .lineLimit(1) if let subtitle = item.cardSubtitle { Text(subtitle) - .font(.haloCaption) - .foregroundStyle(Color.haloTextMuted) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextMuted) } } @@ -407,12 +407,12 @@ private struct LibraryListRow: View { if item.isWatched { Image(systemName: "checkmark.circle.fill") - .foregroundStyle(Color.haloTextMuted) + .foregroundStyle(Color.flaroTextMuted) .accessibilityLabel(Text("item.watched")) } } - .padding(.horizontal, HaloSpacing.screenMargin) - .padding(.vertical, HaloSpacing.snug) + .padding(.horizontal, FlaroSpacing.screenMargin) + .padding(.vertical, FlaroSpacing.snug) .contentShape(.rect) .accessibilityElement(children: .combine) } diff --git a/Halo/Views/LiveTV/ChannelSelectionSheet.swift b/Flaro/Views/LiveTV/ChannelSelectionSheet.swift similarity index 88% rename from Halo/Views/LiveTV/ChannelSelectionSheet.swift rename to Flaro/Views/LiveTV/ChannelSelectionSheet.swift index 9aac8a9..757d58e 100644 --- a/Halo/Views/LiveTV/ChannelSelectionSheet.swift +++ b/Flaro/Views/LiveTV/ChannelSelectionSheet.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign import MediaKit /// Welche Sender überhaupt angezeigt werden. @@ -12,8 +12,8 @@ struct ChannelSelectionSheet: View { let channels: [LiveChannel] @Binding var selection: Set - @Environment(HaloSession.self) private var session - @Environment(\.haloAccent) private var accent + @Environment(FlaroSession.self) private var session + @Environment(\.flaroAccent) private var accent @Environment(\.dismiss) private var dismiss var body: some View { @@ -28,9 +28,9 @@ struct ChannelSelectionSheet: View { } } .navigationTitle(Text("liveTV.selection")) - .haloInlineTitle() + .flaroInlineTitle() .toolbar { - ToolbarItem(placement: .haloLeading) { + ToolbarItem(placement: .flaroLeading) { // „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: HaloSpacing.regular) { - HaloArtwork( + HStack(spacing: FlaroSpacing.regular) { + FlaroArtwork( url: session.backend?.artworkURL(path: channel.artworkPath, width: 200, height: 120), - aspectRatio: HaloAspectRatio.channelLogo, + aspectRatio: FlaroAspectRatio.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.haloTextMuted) + .foregroundStyle(Color.flaroTextMuted) } Text(channel.title) - .font(.haloBody) - .foregroundStyle(Color.haloTextPrimary) + .font(.flaroBody) + .foregroundStyle(Color.flaroTextPrimary) Spacer() Image(systemName: isShown(channel) ? "checkmark.circle.fill" : "circle") - .foregroundStyle(isShown(channel) ? accent : Color.haloTextMuted) + .foregroundStyle(isShown(channel) ? accent : Color.flaroTextMuted) } .contentShape(.rect) } diff --git a/Halo/Views/LiveTV/LiveTVView.swift b/Flaro/Views/LiveTV/LiveTVView.swift similarity index 87% rename from Halo/Views/LiveTV/LiveTVView.swift rename to Flaro/Views/LiveTV/LiveTVView.swift index b76554c..60e82b5 100644 --- a/Halo/Views/LiveTV/LiveTVView.swift +++ b/Flaro/Views/LiveTV/LiveTVView.swift @@ -1,11 +1,11 @@ import SwiftUI -import HaloDesign -import HaloPlayback +import FlaroDesign +import FlaroPlayback import MediaKit /// Live-TV mit Programmführer. struct LiveTVView: View { - @Environment(HaloSession.self) private var session + @Environment(FlaroSession.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: HaloSpacing.regular) { + VStack(spacing: FlaroSpacing.regular) { Button("action.retry") { Task { await load() } } searchTrace } @@ -107,12 +107,12 @@ struct LiveTVView: View { } } } - .background(Color.haloCanvas) + .background(Color.flaroCanvas) .navigationTitle(Text("sidebar.liveTV")) - .haloInlineTitle() + .flaroInlineTitle() .toolbar { if case .available = availability, !channels.isEmpty { - ToolbarItem(placement: .haloTrailing) { + ToolbarItem(placement: .flaroTrailing) { Button { showsSelection = true } label: { @@ -120,7 +120,7 @@ struct LiveTVView: View { } .accessibilityLabel(Text("liveTV.selection")) } - ToolbarItem(placement: .haloTrailing) { + ToolbarItem(placement: .flaroTrailing) { 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: HaloSpacing.snug) { + VStack(alignment: .leading, spacing: FlaroSpacing.snug) { if let channelSource { Text(channelSource) - .font(.haloCaption) - .foregroundStyle(Color.haloTextSecondary) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextSecondary) } 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.haloTextMuted) + .foregroundStyle(Color.flaroTextMuted) .lineLimit(2) .textSelection(.enabled) } @@ -191,18 +191,18 @@ struct LiveTVView: View { .frame(maxHeight: 200) Button { - HaloClipboard.copy( + FlaroClipboard.copy( trace .map { "\($0.path) → \($0.result)" } .joined(separator: "\n") ) } label: { Label("diagnostics.copy", systemImage: "doc.on.doc") - .font(.haloCaption) + .font(.flaroCaption) } .buttonStyle(.bordered) } - .padding(.horizontal, HaloSpacing.screenMargin) + .padding(.horizontal, FlaroSpacing.screenMargin) } } @@ -216,11 +216,11 @@ struct LiveTVView: View { isTuning: isTuning == channel.id, onTune: { Task { await tune(channel) } } ) - Divider().overlay(Color.haloSeparator) + Divider().overlay(Color.flaroSeparator) } } } - .haloRevealsTopChrome() + .flaroRevealsTopChrome() } private func load() async { @@ -329,43 +329,43 @@ private struct ChannelRow: View { let isTuning: Bool let onTune: () -> Void - @Environment(HaloSession.self) private var session - @Environment(\.haloAccent) private var accent + @Environment(FlaroSession.self) private var session + @Environment(\.flaroAccent) 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: HaloSpacing.regular) { + HStack(spacing: FlaroSpacing.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. - HaloArtwork( + FlaroArtwork( url: session.backend?.artworkURL(path: channel.artworkPath, width: 200, height: 120), - aspectRatio: HaloAspectRatio.channelLogo, + aspectRatio: FlaroAspectRatio.channelLogo, fallbackSymbol: "tv", contentMode: .fit ) .frame(width: 56, height: 34) VStack(alignment: .leading, spacing: 2) { - HStack(spacing: HaloSpacing.snug) { + HStack(spacing: FlaroSpacing.snug) { if let number = channel.number { Text(number) .font(.system(.caption, design: .monospaced)) - .foregroundStyle(Color.haloTextMuted) + .foregroundStyle(Color.flaroTextMuted) } Text(channel.title) - .font(.haloCardTitle) - .foregroundStyle(Color.haloTextPrimary) + .font(.flaroCardTitle) + .foregroundStyle(Color.flaroTextPrimary) .lineLimit(1) } if let current { Text(current.title) - .font(.haloCaption) - .foregroundStyle(Color.haloTextSecondary) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextSecondary) .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(.haloCaption) - .foregroundStyle(Color.haloTextMuted) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextMuted) } if let next { Text("liveTV.next \(next.startsAt.formatted(date: .omitted, time: .shortened)) \(next.title)") - .font(.haloCaption) - .foregroundStyle(Color.haloTextMuted) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextMuted) .lineLimit(1) } } @@ -395,8 +395,8 @@ private struct ChannelRow: View { .foregroundStyle(accent) } } - .padding(.horizontal, HaloSpacing.screenMargin) - .padding(.vertical, HaloSpacing.regular) + .padding(.horizontal, FlaroSpacing.screenMargin) + .padding(.vertical, FlaroSpacing.regular) .contentShape(.rect) } .buttonStyle(.plain) @@ -427,43 +427,43 @@ private struct TuneFailureSheet: View { var body: some View { NavigationStack { ScrollView { - VStack(alignment: .leading, spacing: HaloSpacing.regular) { + VStack(alignment: .leading, spacing: FlaroSpacing.regular) { Text(failure.channel) - .font(.haloRowHeader) - .foregroundStyle(Color.haloTextPrimary) + .font(.flaroRowHeader) + .foregroundStyle(Color.flaroTextPrimary) Text(failure.reason) - .font(.haloBody) - .foregroundStyle(Color.haloTextSecondary) + .font(.flaroBody) + .foregroundStyle(Color.flaroTextSecondary) ForEach(Array(failure.trace.enumerated()), id: \.offset) { _, line in Text(line) .font(.system(size: 11, design: .monospaced)) - .foregroundStyle(Color.haloTextMuted) + .foregroundStyle(Color.flaroTextMuted) .textSelection(.enabled) .frame(maxWidth: .infinity, alignment: .leading) } Button { - HaloClipboard.copy(failure.trace.joined(separator: "\n")) + FlaroClipboard.copy(failure.trace.joined(separator: "\n")) } label: { Label("diagnostics.copy", systemImage: "doc.on.doc") - .font(.haloCaption) + .font(.flaroCaption) } .buttonStyle(.bordered) } - .padding(HaloSpacing.screenMargin) + .padding(FlaroSpacing.screenMargin) .frame(maxWidth: .infinity, alignment: .leading) } - .background(Color.haloCanvas) + .background(Color.flaroCanvas) .navigationTitle(Text("liveTV.tuneFailed")) - .haloInlineTitle() + .flaroInlineTitle() .toolbar { ToolbarItem(placement: .confirmationAction) { Button("action.close") { dismiss() } } } } - .haloResizableSheet() + .flaroResizableSheet() } } diff --git a/Halo/Views/LiveTV/ProgramGuide.swift b/Flaro/Views/LiveTV/ProgramGuide.swift similarity index 82% rename from Halo/Views/LiveTV/ProgramGuide.swift rename to Flaro/Views/LiveTV/ProgramGuide.swift index 8a9436f..8bce61e 100644 --- a/Halo/Views/LiveTV/ProgramGuide.swift +++ b/Flaro/Views/LiveTV/ProgramGuide.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign 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(\.haloAccent) private var accent + @Environment(\.flaroAccent) 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.haloSeparator) + Divider().overlay(Color.flaroSeparator) ScrollView(.vertical) { HStack(alignment: .top, spacing: 0) { @@ -65,7 +65,7 @@ struct ProgramGuide: View { } .scrollIndicators(.never) } - .background(Color.haloCanvas) + .background(Color.flaroCanvas) .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(.haloCaption) - .foregroundStyle(Color.haloTextMuted) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextMuted) // 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, HaloSpacing.snug) + .padding(.leading, FlaroSpacing.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.haloTextMuted) + .foregroundStyle(Color.flaroTextMuted) .frame(width: layout.tickWidth, alignment: .leading) } } @@ -135,7 +135,7 @@ struct ProgramGuide: View { .clipped() } .frame(height: axisHeight) - .background(Color.haloCanvas) + .background(Color.flaroCanvas) } /// 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: HaloSpacing.snug) { - HaloArtwork(url: artwork(channel), aspectRatio: 1, fallbackSymbol: "tv") + HStack(spacing: FlaroSpacing.snug) { + FlaroArtwork(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(.haloCaption) - .foregroundStyle(Color.haloTextPrimary) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextPrimary) .lineLimit(2) if let number = channel.number { Text(number) .font(.system(.caption2, design: .monospaced)) - .foregroundStyle(Color.haloTextMuted) + .foregroundStyle(Color.flaroTextMuted) } } @@ -170,7 +170,7 @@ struct ProgramGuide: View { ProgressView().controlSize(.mini) } } - .padding(.horizontal, HaloSpacing.snug) + .padding(.horizontal, FlaroSpacing.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.haloElevated.opacity(0.4)) + .background(Color.flaroElevated.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(.haloCaption) - .foregroundStyle(Color.haloTextMuted) - .padding(.horizontal, HaloSpacing.regular) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextMuted) + .padding(.horizontal, FlaroSpacing.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.haloSeparator) + .fill(Color.flaroSeparator) .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(.haloCaption) - .foregroundStyle(Color.haloTextPrimary) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextPrimary) .lineLimit(2) .multilineTextAlignment(.leading) Text(program.startsAt.formatted(date: .omitted, time: .shortened)) .font(.system(.caption2, design: .rounded)) - .foregroundStyle(Color.haloTextMuted) + .foregroundStyle(Color.flaroTextMuted) } - .padding(.horizontal, HaloSpacing.snug) + .padding(.horizontal, FlaroSpacing.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.haloElevated, - in: .rect(cornerRadius: HaloRadius.control) + running ? accent.opacity(0.28) : Color.flaroElevated, + in: .rect(cornerRadius: FlaroRadius.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(\.haloAccent) private var accent + @Environment(\.flaroAccent) private var accent @Environment(\.dismiss) private var dismiss var body: some View { NavigationStack { ScrollView { - VStack(alignment: .leading, spacing: HaloSpacing.regular) { - HStack(spacing: HaloSpacing.regular) { - HaloArtwork(url: artworkURL, aspectRatio: 1, fallbackSymbol: "tv") + VStack(alignment: .leading, spacing: FlaroSpacing.regular) { + HStack(spacing: FlaroSpacing.regular) { + FlaroArtwork(url: artworkURL, aspectRatio: 1, fallbackSymbol: "tv") .frame(width: 44, height: 44) .clipShape(.rect(cornerRadius: 6)) VStack(alignment: .leading, spacing: 2) { Text(channel.title) - .font(.haloCardTitle) - .foregroundStyle(Color.haloTextPrimary) + .font(.flaroCardTitle) + .foregroundStyle(Color.flaroTextPrimary) Text("liveTV.timeRange \(program.startsAt.formatted(date: .omitted, time: .shortened)) \(program.endsAt.formatted(date: .omitted, time: .shortened))") - .font(.haloCaption) - .foregroundStyle(Color.haloTextSecondary) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextSecondary) } Spacer() } Text(program.title) - .font(.haloRowHeader) - .foregroundStyle(Color.haloTextPrimary) + .font(.flaroRowHeader) + .foregroundStyle(Color.flaroTextPrimary) if let subtitle = program.subtitle { Text(subtitle) - .font(.haloBody) - .foregroundStyle(Color.haloTextSecondary) + .font(.flaroBody) + .foregroundStyle(Color.flaroTextSecondary) } if isRunning { Button { onTune(); dismiss() } label: { Label("liveTV.tune", systemImage: "play.fill") .frame(maxWidth: .infinity) - .padding(.vertical, HaloSpacing.snug) + .padding(.vertical, FlaroSpacing.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(.haloCaption) - .foregroundStyle(Color.haloTextSecondary) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextSecondary) } else if onRecord != nil || onRecordSeries != nil { - HStack(spacing: HaloSpacing.regular) { + HStack(spacing: FlaroSpacing.regular) { if let onRecord { Button { onRecord(); dismiss() } label: { Label("liveTV.record", systemImage: "record.circle") .frame(maxWidth: .infinity) - .padding(.vertical, HaloSpacing.snug) + .padding(.vertical, FlaroSpacing.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, HaloSpacing.snug) + .padding(.vertical, FlaroSpacing.snug) } .buttonStyle(.bordered) } @@ -373,20 +373,20 @@ private struct ProgramDetailSheet: View { if let summary = program.summary, !summary.isEmpty { Text(summary) - .font(.haloBody) - .foregroundStyle(Color.haloTextSecondary) + .font(.flaroBody) + .foregroundStyle(Color.flaroTextSecondary) } } - .padding(HaloSpacing.screenMargin) + .padding(FlaroSpacing.screenMargin) .frame(maxWidth: .infinity, alignment: .leading) } - .background(Color.haloCanvas) + .background(Color.flaroCanvas) .toolbar { ToolbarItem(placement: .confirmationAction) { Button("action.close") { dismiss() } } } } - .haloResizableSheet() + .flaroResizableSheet() } } diff --git a/Halo/Views/LiveTV/RecordingsView.swift b/Flaro/Views/LiveTV/RecordingsView.swift similarity index 87% rename from Halo/Views/LiveTV/RecordingsView.swift rename to Flaro/Views/LiveTV/RecordingsView.swift index 6cacb46..1f1feb5 100644 --- a/Halo/Views/LiveTV/RecordingsView.swift +++ b/Flaro/Views/LiveTV/RecordingsView.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign 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(HaloSession.self) private var session + @Environment(FlaroSession.self) private var session @State private var recordings: [LiveRecording] = [] @State private var timers: [LiveTimer] = [] @@ -47,7 +47,7 @@ struct RecordingsView: View { list } } - .background(Color.haloCanvas) + .background(Color.flaroCanvas) .task { await load() } .refreshable { await load() } .confirmationDialog( @@ -90,7 +90,7 @@ struct RecordingsView: View { } } } - .listRowBackground(Color.haloSurface) + .listRowBackground(Color.flaroSurface) } header: { Text("liveTV.recordings") } @@ -118,23 +118,23 @@ struct RecordingsView: View { } } } - .listRowBackground(Color.haloSurface) + .listRowBackground(Color.flaroSurface) } header: { Text("liveTV.scheduled") } - .listRowBackground(Color.haloSurface) + .listRowBackground(Color.flaroSurface) } } .listStyle(.insetGrouped) .scrollContentBackground(.hidden) - .haloRevealsTopChrome() + .flaroRevealsTopChrome() } // MARK: - Zeilen private func row(_ recording: LiveRecording) -> some View { - HStack(spacing: HaloSpacing.regular) { - HaloArtwork( + HStack(spacing: FlaroSpacing.regular) { + FlaroArtwork( 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(.haloBody) - .foregroundStyle(Color.haloTextPrimary) + .font(.flaroBody) + .foregroundStyle(Color.flaroTextPrimary) .lineLimit(1) - HStack(spacing: HaloSpacing.tight) { + HStack(spacing: FlaroSpacing.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(.haloCaption) - .foregroundStyle(Color.haloDestructive) + .font(.flaroCaption) + .foregroundStyle(Color.flaroDestructive) } if let subtitle = subtitle(for: recording) { Text(subtitle) - .font(.haloCaption) - .foregroundStyle(Color.haloTextSecondary) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextSecondary) .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(.haloBody) - .foregroundStyle(Color.haloTextPrimary) + .font(.flaroBody) + .foregroundStyle(Color.flaroTextPrimary) .lineLimit(1) if let subtitle = subtitle(channel: timer.channelName, start: timer.startsAt) { Text(subtitle) - .font(.haloCaption) - .foregroundStyle(Color.haloTextSecondary) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextSecondary) } } } private func seriesRow(_ timer: LiveSeriesTimer) -> some View { - HStack(spacing: HaloSpacing.snug) { + HStack(spacing: FlaroSpacing.snug) { Image(systemName: "rectangle.stack.badge.record") - .foregroundStyle(Color.haloTextSecondary) + .foregroundStyle(Color.flaroTextSecondary) VStack(alignment: .leading, spacing: 2) { Text(timer.name) - .font(.haloBody) - .foregroundStyle(Color.haloTextPrimary) + .font(.flaroBody) + .foregroundStyle(Color.flaroTextPrimary) .lineLimit(1) Text(timer.recordsAnyChannel ? "liveTV.anyChannel" : "liveTV.series") - .font(.haloCaption) - .foregroundStyle(Color.haloTextSecondary) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextSecondary) } } } diff --git a/Halo/Views/LoadState.swift b/Flaro/Views/LoadState.swift similarity index 98% rename from Halo/Views/LoadState.swift rename to Flaro/Views/LoadState.swift index e222621..d68af47 100644 --- a/Halo/Views/LoadState.swift +++ b/Flaro/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 `HaloSession` —, und sie +/// **Eine** Stelle. Es gab davon zwei — hier und in `FlaroSession` —, und sie /// waren bereits auseinandergelaufen: derselbe Fehler bekam je nach /// Bildschirm eine andere Erklärung. enum ErrorText { diff --git a/Halo/Views/Navigation/AccountAvatar.swift b/Flaro/Views/Navigation/AccountAvatar.swift similarity index 88% rename from Halo/Views/Navigation/AccountAvatar.swift rename to Flaro/Views/Navigation/AccountAvatar.swift index fd943d4..bab908d 100644 --- a/Halo/Views/Navigation/AccountAvatar.swift +++ b/Flaro/Views/Navigation/AccountAvatar.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign /// Der erste Buchstabe auf einer Scheibe. /// @@ -16,7 +16,7 @@ struct AccountAvatar: View { let name: String var diameter: CGFloat = 26 - @Environment(\.haloAccent) private var accent + @Environment(\.flaroAccent) 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.haloCanvas) + .foregroundStyle(Color.flaroCanvas) .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 haloOpenSettings: () -> Void = {} + @Entry var flaroOpenSettings: () -> 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(HaloSession.self) private var session - @Environment(\.haloOpenSettings) private var openSettings + @Environment(FlaroSession.self) private var session + @Environment(\.flaroOpenSettings) private var openSettings var body: some View { Button(action: openSettings) { diff --git a/Halo/Views/Navigation/AccountBar.swift b/Flaro/Views/Navigation/AccountBar.swift similarity index 83% rename from Halo/Views/Navigation/AccountBar.swift rename to Flaro/Views/Navigation/AccountBar.swift index 2cd1c8a..45f7a74 100644 --- a/Halo/Views/Navigation/AccountBar.swift +++ b/Flaro/Views/Navigation/AccountBar.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign /// Wer angemeldet ist — unten in der Seitenleiste. /// @@ -22,7 +22,7 @@ import HaloDesign struct AccountBar: View { @Binding var selection: SidebarDestination - @Environment(HaloSession.self) private var session + @Environment(FlaroSession.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.haloSurface) + .background(Color.flaroSurface) // 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: HaloSpacing.snug) { + HStack(spacing: FlaroSpacing.snug) { AccountAvatar(name: title) VStack(alignment: .leading, spacing: 0) { Text(title) - .font(.haloCardTitle) - .foregroundStyle(Color.haloTextPrimary) + .font(.flaroCardTitle) + .foregroundStyle(Color.flaroTextPrimary) .lineLimit(1) if let subtitle { Text(subtitle) - .font(.haloCaption) - .foregroundStyle(Color.haloTextMuted) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextMuted) .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.haloTextMuted) + .foregroundStyle(Color.flaroTextMuted) } - .padding(.horizontal, HaloSpacing.regular) - .padding(.vertical, HaloSpacing.snug) + .padding(.horizontal, FlaroSpacing.regular) + .padding(.vertical, FlaroSpacing.snug) .contentShape(.rect) } .buttonStyle(.plain) @@ -121,18 +121,18 @@ struct AccountBar: View { ) -> some View { Button(action: perform) { Label(title, systemImage: symbol) - .font(.haloBody) - .foregroundStyle(isDestructive ? Color.haloDestructive : Color.haloTextPrimary) + .font(.flaroBody) + .foregroundStyle(isDestructive ? Color.flaroDestructive : Color.flaroTextPrimary) .frame(maxWidth: .infinity, alignment: .leading) - .padding(.horizontal, HaloSpacing.regular) - .padding(.vertical, HaloSpacing.regular) + .padding(.horizontal, FlaroSpacing.regular) + .padding(.vertical, FlaroSpacing.regular) .contentShape(.rect) } .buttonStyle(.plain) } private var separator: some View { - Divider().overlay(Color.haloSeparator) + Divider().overlay(Color.flaroSeparator) } } diff --git a/Halo/Views/Navigation/HaloNavigationBar.swift b/Flaro/Views/Navigation/FlaroNavigationBar.swift similarity index 79% rename from Halo/Views/Navigation/HaloNavigationBar.swift rename to Flaro/Views/Navigation/FlaroNavigationBar.swift index ae32527..ebb0850 100644 --- a/Halo/Views/Navigation/HaloNavigationBar.swift +++ b/Flaro/Views/Navigation/FlaroNavigationBar.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign 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 HaloSidebar: View { +struct FlaroSidebar: 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 HaloSidebar: View { @Binding var placement: NavigationPlacement let layout: NavigationLayoutSettings - @Environment(\.haloAccent) private var accent + @Environment(\.flaroAccent) 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 HaloSidebar: View { static func surface(in shape: some InsettableShape) -> some View { shape .fill(.ultraThinMaterial) - .overlay { shape.fill(Color.haloCanvas.opacity(0.55)) } + .overlay { shape.fill(Color.flaroCanvas.opacity(0.55)) } .overlay { shape.strokeBorder( LinearGradient( @@ -134,10 +134,10 @@ struct HaloSidebar: View { // Ziehen zum Umsortieren mit, und die scrollt von sich aus. if isEditing { Text("sidebar.editHint") - .font(.haloCaption) - .foregroundStyle(Color.haloTextMuted) - .padding(.horizontal, HaloSpacing.regular) - .padding(.bottom, HaloSpacing.snug) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextMuted) + .padding(.horizontal, FlaroSpacing.regular) + .padding(.bottom, FlaroSpacing.snug) List { ForEach(groups) { group in @@ -149,8 +149,8 @@ struct HaloSidebar: View { } header: { if let title = group.title { Text(title) - .font(.haloCaption) - .foregroundStyle(Color.haloTextMuted) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextMuted) } } .listRowBackground(Color.clear) @@ -162,13 +162,13 @@ struct HaloSidebar: View { .environment(\.editMode, .constant(.active)) } else { ScrollView { - VStack(alignment: .leading, spacing: HaloSpacing.regular) { + VStack(alignment: .leading, spacing: FlaroSpacing.regular) { ForEach(groups) { group in section(visible(group)) } } - .padding(.horizontal, HaloSpacing.snug) - .padding(.bottom, HaloSpacing.regular) + .padding(.horizontal, FlaroSpacing.snug) + .padding(.bottom, FlaroSpacing.regular) } .scrollBounceBehavior(.basedOnSize) .scrollIndicators(.never) @@ -176,14 +176,14 @@ struct HaloSidebar: View { Spacer(minLength: 0) - Divider().overlay(Color.haloSeparator) + Divider().overlay(Color.flaroSeparator) AccountBar(selection: $selection) - .padding(.horizontal, HaloSpacing.snug) - .padding(.vertical, HaloSpacing.snug) + .padding(.horizontal, FlaroSpacing.snug) + .padding(.vertical, FlaroSpacing.snug) } .frame(width: Self.width) - .background { Self.surface(in: .rect(cornerRadius: HaloRadius.panel, style: .continuous)) } - .clipShape(.rect(cornerRadius: HaloRadius.panel, style: .continuous)) + .background { Self.surface(in: .rect(cornerRadius: FlaroRadius.panel, style: .continuous)) } + .clipShape(.rect(cornerRadius: FlaroRadius.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 HaloSidebar: View { } private var header: some View { - HStack(spacing: HaloSpacing.snug) { + HStack(spacing: FlaroSpacing.snug) { Button { withAnimation(.snappy(duration: 0.25)) { isEditing.toggle() } } label: { Text(isEditing ? "action.done" : "sidebar.edit") - .font(.haloCaption) - .padding(.horizontal, HaloSpacing.snug) - .padding(.vertical, HaloSpacing.tight) + .font(.flaroCaption) + .padding(.horizontal, FlaroSpacing.snug) + .padding(.vertical, FlaroSpacing.tight) .contentShape(Capsule()) } .buttonStyle(.plain) - .foregroundStyle(isEditing ? accent : Color.haloTextSecondary) + .foregroundStyle(isEditing ? accent : Color.flaroTextSecondary) Spacer(minLength: 0) @@ -214,21 +214,21 @@ struct HaloSidebar: View { placement = .top } label: { Image(systemName: "rectangle.topthird.inset.filled") - .font(.haloRowHeader) - .padding(HaloSpacing.tight) + .font(.flaroRowHeader) + .padding(FlaroSpacing.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.haloTextSecondary) + .foregroundStyle(Color.flaroTextSecondary) .accessibilityLabel(Text("sidebar.moveToTop")) } } - .padding(.horizontal, HaloSpacing.regular) - .padding(.top, HaloSpacing.regular) - .padding(.bottom, HaloSpacing.snug) + .padding(.horizontal, FlaroSpacing.regular) + .padding(.top, FlaroSpacing.regular) + .padding(.bottom, FlaroSpacing.snug) } /// Die Einträge einer Gruppe beim Bearbeiten: alle, in der gespeicherten @@ -271,16 +271,16 @@ struct HaloSidebar: View { } label: { HStack { Text(title) - .font(.haloCaption) - .foregroundStyle(Color.haloTextMuted) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextMuted) Spacer() Image(systemName: "chevron.down") - .font(.haloCaption) - .foregroundStyle(Color.haloTextMuted) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextMuted) .rotationEffect(.degrees(collapsed.contains(group.id) ? -90 : 0)) } - .padding(.horizontal, HaloSpacing.regular) - .padding(.top, HaloSpacing.snug) + .padding(.horizontal, FlaroSpacing.regular) + .padding(.top, FlaroSpacing.snug) } .buttonStyle(.plain) } @@ -301,12 +301,12 @@ struct HaloSidebar: View { private func editRow(_ entry: NavigationEntry) -> some View { let isHidden = layout.isHidden(entry.arrangementID) - return HStack(spacing: HaloSpacing.snug) { + return HStack(spacing: FlaroSpacing.snug) { Button { layout.setHidden(!isHidden, for: entry.arrangementID) } label: { Image(systemName: isHidden ? "circle" : "checkmark.circle.fill") - .foregroundStyle(isHidden ? Color.haloTextMuted : accent) + .foregroundStyle(isHidden ? Color.flaroTextMuted : accent) .contentShape(Rectangle()) } .buttonStyle(.plain) @@ -318,8 +318,8 @@ struct HaloSidebar: View { .lineLimit(1) Spacer(minLength: 0) } - .font(.haloBody) - .foregroundStyle(isHidden ? Color.haloTextMuted : Color.haloTextPrimary) + .font(.flaroBody) + .foregroundStyle(isHidden ? Color.flaroTextMuted : Color.flaroTextPrimary) } private func row(_ entry: NavigationEntry) -> some View { @@ -328,23 +328,23 @@ struct HaloSidebar: View { return Button { selection = entry.destination } label: { - HStack(spacing: HaloSpacing.snug) { + HStack(spacing: FlaroSpacing.snug) { Image(systemName: entry.symbol) - .font(.haloBody) + .font(.flaroBody) .frame(width: 22, alignment: .center) entry.title - .font(.haloBody) + .font(.flaroBody) // Ein langer Mediathekenname darf die Leiste nicht // breiter machen; sie hat eine feste Breite. .lineLimit(1) Spacer(minLength: 0) } - .foregroundStyle(isSelected ? accent : Color.haloTextPrimary) - .padding(.horizontal, HaloSpacing.regular) - .padding(.vertical, HaloSpacing.snug) + .foregroundStyle(isSelected ? accent : Color.flaroTextPrimary) + .padding(.horizontal, FlaroSpacing.regular) + .padding(.vertical, FlaroSpacing.snug) .background { if isSelected { - Capsule().fill(Color.haloElevated) + Capsule().fill(Color.flaroElevated) } } .contentShape(Capsule()) @@ -360,29 +360,29 @@ struct HaloSidebar: 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 HaloTopBar: View { +struct FlaroTopBar: View { let groups: [NavigationGroup] @Binding var selection: SidebarDestination @Binding var placement: NavigationPlacement - @Environment(\.haloAccent) private var accent + @Environment(\.flaroAccent) private var accent var body: some View { - HStack(spacing: HaloSpacing.tight) { + HStack(spacing: FlaroSpacing.tight) { Button { placement = .sidebar } label: { Image(systemName: "sidebar.leading") - .font(.haloBody) - .padding(.horizontal, HaloSpacing.regular) - .padding(.vertical, HaloSpacing.snug) + .font(.flaroBody) + .padding(.horizontal, FlaroSpacing.regular) + .padding(.vertical, FlaroSpacing.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.haloTextSecondary) + .foregroundStyle(Color.flaroTextSecondary) .accessibilityLabel(Text("sidebar.moveToSide")) ForEach(groups) { group in @@ -395,12 +395,12 @@ struct HaloTopBar: View { } } } - .padding(.horizontal, HaloSpacing.snug) - .padding(.vertical, HaloSpacing.snug) - .background { HaloSidebar.surface(in: .capsule) } + .padding(.horizontal, FlaroSpacing.snug) + .padding(.vertical, FlaroSpacing.snug) + .background { FlaroSidebar.surface(in: .capsule) } .clipShape(.capsule) .shadow(color: .black.opacity(0.45), radius: 18, y: 6) - .padding(.top, HaloSpacing.snug) + .padding(.top, FlaroSpacing.snug) } private func pill(_ entry: NavigationEntry) -> some View { @@ -410,13 +410,13 @@ struct HaloTopBar: View { selection = entry.destination } label: { entry.title - .font(.haloBody) + .font(.flaroBody) .lineLimit(1) - .foregroundStyle(isSelected ? accent : Color.haloTextPrimary) - .padding(.horizontal, HaloSpacing.loose) - .padding(.vertical, HaloSpacing.snug) + .foregroundStyle(isSelected ? accent : Color.flaroTextPrimary) + .padding(.horizontal, FlaroSpacing.loose) + .padding(.vertical, FlaroSpacing.snug) .background { - if isSelected { Capsule().fill(Color.haloElevated) } + if isSelected { Capsule().fill(Color.flaroElevated) } } .contentShape(Capsule()) } @@ -433,21 +433,21 @@ struct HaloTopBar: View { } } } label: { - HStack(spacing: HaloSpacing.tight) { + HStack(spacing: FlaroSpacing.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(.haloCaption) + Image(systemName: "chevron.down").font(.flaroCaption) } - .font(.haloBody) - .foregroundStyle(containsSelection ? accent : Color.haloTextPrimary) - .padding(.horizontal, HaloSpacing.loose) - .padding(.vertical, HaloSpacing.snug) + .font(.flaroBody) + .foregroundStyle(containsSelection ? accent : Color.flaroTextPrimary) + .padding(.horizontal, FlaroSpacing.loose) + .padding(.vertical, FlaroSpacing.snug) .background { - if containsSelection { Capsule().fill(Color.haloElevated) } + if containsSelection { Capsule().fill(Color.flaroElevated) } } .contentShape(Capsule()) } diff --git a/Halo/Views/Navigation/MediaStack.swift b/Flaro/Views/Navigation/MediaStack.swift similarity index 91% rename from Halo/Views/Navigation/MediaStack.swift rename to Flaro/Views/Navigation/MediaStack.swift index 6c55008..f30e16d 100644 --- a/Halo/Views/Navigation/MediaStack.swift +++ b/Flaro/Views/Navigation/MediaStack.swift @@ -16,7 +16,7 @@ import MediaKit struct MediaStack: View { @ViewBuilder let content: () -> Content - @Environment(HaloSession.self) private var session + @Environment(FlaroSession.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(\.haloPush) { ziel in path.append(ziel) } + .environment(\.flaroPush) { 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 haloPush: (any Hashable) -> Void = { _ in } + @Entry var flaroPush: (any Hashable) -> Void = { _ in } } diff --git a/Halo/Views/Navigation/RootView.swift b/Flaro/Views/Navigation/RootView.swift similarity index 95% rename from Halo/Views/Navigation/RootView.swift rename to Flaro/Views/Navigation/RootView.swift index 0b63c7e..a30f8fe 100644 --- a/Halo/Views/Navigation/RootView.swift +++ b/Flaro/Views/Navigation/RootView.swift @@ -1,8 +1,8 @@ import SwiftUI -import HaloDesign +import FlaroDesign import MediaKit -import HaloDownloads -import HaloPlayback +import FlaroDownloads +import FlaroPlayback /// Die Wurzelansicht. /// @@ -10,8 +10,8 @@ import HaloPlayback /// Welche Form die Navigation danach annimmt — Seitenleiste, Leiste oben, /// Leiste unten —, entscheidet das System und der Nutzer, nicht diese Datei. struct RootView: View { - @Environment(HaloSession.self) private var session - @Environment(HaloTheme.self) private var theme + @Environment(FlaroSession.self) private var session + @Environment(FlaroTheme.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("halo.navigation.customization") + @AppStorage("flaro.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("halo.navigation.placement") + @AppStorage("flaro.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.haloCanvas) + .background(Color.flaroCanvas) case .signedOut: SignInView() @@ -104,7 +104,7 @@ struct RootView: View { library } } - .background(Color.haloCanvas) + .background(Color.flaroCanvas) .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 `HaloSidebar`. Diese Zeile + // das war die Seitenleiste selbst, siehe `FlaroSidebar`. 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. - .haloAccent(theme) + .flaroAccent(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: `HaloDownloads` hängt bewusst nicht + // Hier und nicht im Koordinator: `FlaroDownloads` 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("halo.tab.home") + .customizationID("flaro.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("halo.tab.library.\(library.id)") + .customizationID("flaro.tab.library.\(library.id)") } } header: { Text("sidebar.libraries") } - .customizationID("halo.tab.libraries") + .customizationID("flaro.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("halo.tab.liveTV") + .customizationID("flaro.tab.liveTV") } } else { Tab(value: SidebarDestination.libraryHub) { @@ -328,7 +328,7 @@ struct RootView: View { } label: { tabLabel("sidebar.library", symbol: "books.vertical") } - .customizationID("halo.tab.libraryHub") + .customizationID("flaro.tab.libraryHub") } Tab(value: SidebarDestination.downloads) { @@ -336,7 +336,7 @@ struct RootView: View { } label: { tabLabel("sidebar.downloads", symbol: "arrow.down.circle") } - .customizationID("halo.tab.downloads") + .customizationID("flaro.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("halo.tab.settings") + .customizationID("flaro.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("halo.tab.search") + .customizationID("flaro.tab.search") } } .tabViewStyle(.sidebarAdaptable) @@ -389,7 +389,7 @@ struct RootView: View { if sizeClass == .regular { HStack(spacing: 0) { if placement == .sidebar { - HaloSidebar( + FlaroSidebar( 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 { - HaloTopBar( + FlaroTopBar( 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(\.haloOpenSettings, { showsSettings = true }) + .environment(\.flaroOpenSettings, { 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: .haloTrailing) { + ToolbarItem(placement: .flaroTrailing) { Button("action.close") { showsSettings = false } } } @@ -515,16 +515,16 @@ struct RootView: View { showsSettings = true } label: { AccountAvatar(name: session.accountName ?? session.serverName, diameter: 34) - .padding(HaloSpacing.snug) + .padding(FlaroSpacing.snug) // Damit er auch über einem hellen Aufmacher steht. .background(.black.opacity(0.28), in: .circle) } .buttonStyle(.plain) - .padding(.trailing, HaloSpacing.regular) + .padding(.trailing, FlaroSpacing.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, HaloSpacing.snug) + .padding(.top, FlaroSpacing.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 ? HaloSidebar.margin : Self.topBarHeight) + return statusBarHeight + (placement == .sidebar ? FlaroSidebar.margin : Self.topBarHeight) } private var navigationGroups: [NavigationGroup] { diff --git a/Halo/Views/Navigation/SidebarDestination.swift b/Flaro/Views/Navigation/SidebarDestination.swift similarity index 100% rename from Halo/Views/Navigation/SidebarDestination.swift rename to Flaro/Views/Navigation/SidebarDestination.swift diff --git a/Halo/Views/Navigation/TabChrome.swift b/Flaro/Views/Navigation/TabChrome.swift similarity index 100% rename from Halo/Views/Navigation/TabChrome.swift rename to Flaro/Views/Navigation/TabChrome.swift diff --git a/Halo/Views/Navigation/TopChrome.swift b/Flaro/Views/Navigation/TopChrome.swift similarity index 98% rename from Halo/Views/Navigation/TopChrome.swift rename to Flaro/Views/Navigation/TopChrome.swift index e8c4348..2f4f70d 100644 --- a/Halo/Views/Navigation/TopChrome.swift +++ b/Flaro/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 haloRevealsTopChrome() -> some View { + func flaroRevealsTopChrome() -> some View { modifier(RevealsTopChrome()) } } diff --git a/Halo/Views/Placeholder/PlaceholderScreen.swift b/Flaro/Views/Placeholder/PlaceholderScreen.swift similarity index 86% rename from Halo/Views/Placeholder/PlaceholderScreen.swift rename to Flaro/Views/Placeholder/PlaceholderScreen.swift index 3351b9b..562a9e3 100644 --- a/Halo/Views/Placeholder/PlaceholderScreen.swift +++ b/Flaro/Views/Placeholder/PlaceholderScreen.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign /// Ein noch nicht gebauter Bereich. /// @@ -15,9 +15,9 @@ struct PlaceholderScreen: View { } description: { Text("placeholder.description") } - .background(Color.haloCanvas) + .background(Color.flaroCanvas) .navigationTitle(destination.title) - .haloInlineTitle() + .flaroInlineTitle() } } diff --git a/Halo/Views/Player/AirPlayButton.swift b/Flaro/Views/Player/AirPlayButton.swift similarity index 100% rename from Halo/Views/Player/AirPlayButton.swift rename to Flaro/Views/Player/AirPlayButton.swift diff --git a/Halo/Views/Player/MacFullScreen.swift b/Flaro/Views/Player/MacFullScreen.swift similarity index 100% rename from Halo/Views/Player/MacFullScreen.swift rename to Flaro/Views/Player/MacFullScreen.swift diff --git a/Halo/Views/Player/MiniPlayer.swift b/Flaro/Views/Player/MiniPlayer.swift similarity index 96% rename from Halo/Views/Player/MiniPlayer.swift rename to Flaro/Views/Player/MiniPlayer.swift index a23166e..219ed7d 100644 --- a/Halo/Views/Player/MiniPlayer.swift +++ b/Flaro/Views/Player/MiniPlayer.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign /// 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 / HaloAspectRatio.landscape).rounded()) + return CGSize(width: width, height: (width / FlaroAspectRatio.landscape).rounded()) } var body: some View { @@ -105,10 +105,10 @@ struct MiniPlayer: View { } } } - .clipShape(.rect(cornerRadius: HaloRadius.card)) + .clipShape(.rect(cornerRadius: FlaroRadius.card)) .overlay { - RoundedRectangle(cornerRadius: HaloRadius.card) - .strokeBorder(Color.haloSeparator, lineWidth: 0.5) + RoundedRectangle(cornerRadius: FlaroRadius.card) + .strokeBorder(Color.flaroSeparator, lineWidth: 0.5) } .shadow(color: .black.opacity(0.5), radius: 12, y: 4) .contentShape(.rect) @@ -158,9 +158,9 @@ struct MiniPlayer: View { } } } - .padding(HaloSpacing.tight) + .padding(FlaroSpacing.tight) // Über dem Fortschrittsbalken, nicht darauf. - .padding(.bottom, HaloSpacing.tight) + .padding(.bottom, FlaroSpacing.tight) } /// Ein kleiner Knopf, der auf jedem Bild lesbar bleibt. diff --git a/Halo/Views/Player/PlaybackScrubber.swift b/Flaro/Views/Player/PlaybackScrubber.swift similarity index 98% rename from Halo/Views/Player/PlaybackScrubber.swift rename to Flaro/Views/Player/PlaybackScrubber.swift index 0dbadee..7ac17e1 100644 --- a/Halo/Views/Player/PlaybackScrubber.swift +++ b/Flaro/Views/Player/PlaybackScrubber.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign /// 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(\.haloAccent) private var accent + @Environment(\.flaroAccent) private var accent private static let trackHeight: CGFloat = 5 private static let thumbSize: CGFloat = 13 diff --git a/Halo/Views/Player/PlayerModel.swift b/Flaro/Views/Player/PlayerModel.swift similarity index 99% rename from Halo/Views/Player/PlayerModel.swift rename to Flaro/Views/Player/PlayerModel.swift index ca25264..69f29f9 100644 --- a/Halo/Views/Player/PlayerModel.swift +++ b/Flaro/Views/Player/PlayerModel.swift @@ -2,8 +2,8 @@ import AVKit import Foundation import MediaKit import Observation -import HaloDownloads -import HaloPlayback +import FlaroDownloads +import FlaroPlayback /// Führt einen Abspielwunsch aus. /// @@ -169,10 +169,10 @@ final class PlayerModel { /// Wo das Bild aufhört. /// - /// Liegt bei `HaloPlayback`, weil beide Engines es brauchen. Der Name + /// Liegt bei `FlaroPlayback`, weil beide Engines es brauchen. Der Name /// hier bleibt, damit die Ansicht weiter `PlayerModel.VideoFit` schreiben /// kann. - typealias VideoFit = HaloPlayback.VideoFit + typealias VideoFit = FlaroPlayback.VideoFit /// Bild-in-Bild hängt an genau dieser Ebene und wandert deshalb mit. /// diff --git a/Halo/Views/Player/PlayerView.swift b/Flaro/Views/Player/PlayerView.swift similarity index 95% rename from Halo/Views/Player/PlayerView.swift rename to Flaro/Views/Player/PlayerView.swift index 6d3321d..0d68fc6 100644 --- a/Halo/Views/Player/PlayerView.swift +++ b/Flaro/Views/Player/PlayerView.swift @@ -1,7 +1,7 @@ import SwiftUI -import HaloDesign -import HaloDownloads -import HaloPlayback +import FlaroDesign +import FlaroDownloads +import FlaroPlayback /// Der Vollbildplayer. struct PlayerView: View { @@ -13,14 +13,14 @@ struct PlayerView: View { /// Nutzers statt eine Nebenwirkung der Navigation. let model: PlayerModel - @Environment(HaloSession.self) private var session + @Environment(FlaroSession.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(\.haloAccent) private var accent + @Environment(\.flaroAccent) 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 { HaloPlatform.isMac } + private var isMac: Bool { FlaroPlatform.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(HaloSpacing.loose) + .padding(FlaroSpacing.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, HaloPlatform.isMac ? Self.titleBarHeight : 0) + .padding(.top, FlaroPlatform.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(\.haloAccent, accent) + .environment(\.flaroAccent, accent) } .sheet(isPresented: $showsQualityChoice) { QualitySheet(model: model) .environment(settings) - .environment(\.haloAccent, accent) + .environment(\.flaroAccent, 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(HaloSpacing.loose) + .padding(FlaroSpacing.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: HaloSpacing.regular) { + HStack(alignment: .top, spacing: FlaroSpacing.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(HaloSpacing.snug) + .padding(FlaroSpacing.snug) } .accessibilityLabel(Text("player.minimize")) @@ -414,17 +414,17 @@ struct PlayerView: View { } label: { Image(systemName: "xmark") .font(.callout.weight(.semibold)) - .padding(HaloSpacing.snug) + .padding(FlaroSpacing.snug) } .accessibilityLabel(Text("player.stop")) VStack(alignment: .leading, spacing: 2) { Text(model.title) - .font(.haloCardTitle) + .font(.flaroCardTitle) .lineLimit(1) if let subtitle = model.subtitle { Text(subtitle) - .font(.haloCaption) + .font(.flaroCaption) .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(HaloSpacing.snug) + .padding(FlaroSpacing.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(HaloSpacing.snug) + .padding(FlaroSpacing.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(HaloSpacing.snug) + .padding(FlaroSpacing.snug) } .accessibilityLabel(Text("player.rotate")) } @@ -524,7 +524,7 @@ struct PlayerView: View { } label: { Image(systemName: model.isPictureInPictureActive ? "pip.exit" : "pip.enter") .font(.title3) - .padding(HaloSpacing.snug) + .padding(FlaroSpacing.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(HaloSpacing.snug) + .padding(FlaroSpacing.snug) .accessibilityLabel(Text("player.airPlay")) } @@ -554,7 +554,7 @@ struct PlayerView: View { } label: { Image(systemName: symbol) .font(.title3) - .padding(HaloSpacing.snug) + .padding(FlaroSpacing.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(.haloCaption.weight(.semibold)) + .font(.flaroCaption.weight(.semibold)) .monospacedDigit() - .padding(.horizontal, HaloSpacing.snug) - .padding(.vertical, HaloSpacing.tight) + .padding(.horizontal, FlaroSpacing.snug) + .padding(.vertical, FlaroSpacing.tight) .overlay { - RoundedRectangle(cornerRadius: HaloRadius.card) + RoundedRectangle(cornerRadius: FlaroRadius.card) .strokeBorder(.white.opacity(0.5), lineWidth: 1) } - .padding(HaloSpacing.snug) + .padding(FlaroSpacing.snug) } } .disabled(model.isChangingQuality) @@ -594,7 +594,7 @@ struct PlayerView: View { } private func transport(for model: PlayerModel) -> some View { - HStack(spacing: HaloSpacing.section * 2) { + HStack(spacing: FlaroSpacing.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: HaloSpacing.tight) { + VStack(spacing: FlaroSpacing.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(.haloCardTitle) - .padding(.horizontal, HaloSpacing.loose) - .padding(.vertical, HaloSpacing.regular) + .font(.flaroCardTitle) + .padding(.horizontal, FlaroSpacing.loose) + .padding(.vertical, FlaroSpacing.regular) } .buttonStyle(.borderedProminent) .tint(accent) @@ -706,21 +706,21 @@ struct PlayerView: View { model.skipActiveMarker() } label: { Text(marker.isIntro ? "player.skipIntro" : "player.skipCredits") - .font(.haloCardTitle) - .padding(.horizontal, HaloSpacing.loose) - .padding(.vertical, HaloSpacing.regular) + .font(.flaroCardTitle) + .padding(.horizontal, FlaroSpacing.loose) + .padding(.vertical, FlaroSpacing.regular) } .buttonStyle(.bordered) .tint(.white) .transition(.move(edge: .trailing).combined(with: .opacity)) } } - .padding(.horizontal, HaloSpacing.section) + .padding(.horizontal, FlaroSpacing.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 : HaloSpacing.section) + safeArea.bottom) + .padding(.bottom, (showsControls ? 110 : FlaroSpacing.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: HaloSpacing.regular) { + VStack(spacing: FlaroSpacing.regular) { ProgressView().tint(.white) Text("player.restoring") - .font(.haloCardTitle) + .font(.flaroCardTitle) .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: HaloSpacing.loose) { + VStack(spacing: FlaroSpacing.loose) { ProgressView().tint(.white) Text(model.title) - .font(.haloCardTitle) + .font(.flaroCardTitle) .foregroundStyle(.white) .multilineTextAlignment(.center) Text("player.preparing") - .font(.haloCaption) + .font(.flaroCaption) .foregroundStyle(.white.opacity(0.6)) } - .padding(HaloSpacing.section) + .padding(FlaroSpacing.section) } private func failure(message: String) -> some View { - VStack(spacing: HaloSpacing.loose) { + VStack(spacing: FlaroSpacing.loose) { Image(systemName: "exclamationmark.triangle") .font(.largeTitle) .foregroundStyle(.white.opacity(0.8)) Text(message) - .font(.haloBody) + .font(.flaroBody) .foregroundStyle(.white) .multilineTextAlignment(.center) Button("action.close") { playback.close() } .buttonStyle(.borderedProminent) .tint(accent) } - .padding(HaloSpacing.section) + .padding(FlaroSpacing.section) } /// Die beiden Flächen zum Springen. @@ -821,7 +821,7 @@ struct PlayerView: View { .labelStyle(.iconOnly) .font(.system(size: 44)) .foregroundStyle(.white) - .padding(HaloSpacing.section) + .padding(FlaroSpacing.section) .background(.black.opacity(0.35), in: .circle) .transition(.opacity.combined(with: .scale)) } diff --git a/Halo/Views/Player/QualitySheet.swift b/Flaro/Views/Player/QualitySheet.swift similarity index 96% rename from Halo/Views/Player/QualitySheet.swift rename to Flaro/Views/Player/QualitySheet.swift index 9305a8c..59b1721 100644 --- a/Halo/Views/Player/QualitySheet.swift +++ b/Flaro/Views/Player/QualitySheet.swift @@ -1,6 +1,6 @@ import SwiftUI -import HaloDesign -import HaloPlayback +import FlaroDesign +import FlaroPlayback /// Die Qualitätswahl im Player, samt dem, was gerade tatsächlich läuft. /// @@ -11,7 +11,7 @@ import HaloPlayback struct QualitySheet: View { let model: PlayerModel - @Environment(\.haloAccent) private var accent + @Environment(\.flaroAccent) 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")) - .haloInlineTitle() + .flaroInlineTitle() .toolbar { ToolbarItem(placement: .confirmationAction) { Button("action.done") { dismiss() } } } } - .haloResizableSheet() + .flaroResizableSheet() } /// Was gerade läuft — gemessen, nicht gewünscht. @@ -158,11 +158,11 @@ struct QualitySheet: View { } label: { HStack { Text(label(for: option)) - .foregroundStyle(Color.haloTextPrimary) + .foregroundStyle(Color.flaroTextPrimary) if let detail { Text(detail) - .font(.haloCaption) - .foregroundStyle(Color.haloTextMuted) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextMuted) } Spacer() if option == model.quality { diff --git a/Halo/Views/Player/TrackPickerSheet.swift b/Flaro/Views/Player/TrackPickerSheet.swift similarity index 94% rename from Halo/Views/Player/TrackPickerSheet.swift rename to Flaro/Views/Player/TrackPickerSheet.swift index b91477e..b1ea80d 100644 --- a/Halo/Views/Player/TrackPickerSheet.swift +++ b/Flaro/Views/Player/TrackPickerSheet.swift @@ -1,6 +1,6 @@ import SwiftUI -import HaloDesign -import HaloPlayback +import FlaroDesign +import FlaroPlayback 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(\.haloAccent) private var accent + @Environment(\.flaroAccent) 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.haloSurface) + .listRowBackground(Color.flaroSurface) } header: { Text("player.rememberedTrack") } footer: { @@ -121,23 +121,23 @@ struct TrackPickerSheet: View { } } .scrollContentBackground(.hidden) - .background(Color.haloCanvas) + .background(Color.flaroCanvas) .navigationTitle(Text(kind.title)) - .haloInlineTitle() + .flaroInlineTitle() .toolbar { ToolbarItem(placement: .confirmationAction) { Button("action.close") { dismiss() } } } } - .haloMediumSheet() + .flaroMediumSheet() } private func row(title: String, isSelected: Bool, action: @escaping () -> Void) -> some View { Button(action: action) { HStack { Text(title) - .foregroundStyle(Color.haloTextPrimary) + .foregroundStyle(Color.flaroTextPrimary) Spacer() if isSelected { Image(systemName: "checkmark").foregroundStyle(accent) @@ -146,7 +146,7 @@ struct TrackPickerSheet: View { .contentShape(.rect) } .buttonStyle(.plain) - .listRowBackground(Color.haloSurface) + .listRowBackground(Color.flaroSurface) .accessibilityAddTraits(isSelected ? [.isButton, .isSelected] : .isButton) } } diff --git a/Halo/Views/Player/VideoSurface.swift b/Flaro/Views/Player/VideoSurface.swift similarity index 99% rename from Halo/Views/Player/VideoSurface.swift rename to Flaro/Views/Player/VideoSurface.swift index 60b2386..4812605 100644 --- a/Halo/Views/Player/VideoSurface.swift +++ b/Flaro/Views/Player/VideoSurface.swift @@ -1,6 +1,6 @@ import AVKit import SwiftUI -import HaloPlayback +import FlaroPlayback #if canImport(UIKit) import UIKit #else diff --git a/Halo/Views/Search/SearchView.swift b/Flaro/Views/Search/SearchView.swift similarity index 82% rename from Halo/Views/Search/SearchView.swift rename to Flaro/Views/Search/SearchView.swift index 4b48fac..87882b1 100644 --- a/Halo/Views/Search/SearchView.swift +++ b/Flaro/Views/Search/SearchView.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign 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(HaloSession.self) private var session + @Environment(FlaroSession.self) private var session @State private var text = "" @State private var feed = SearchFeed() @@ -23,9 +23,9 @@ struct SearchView: View { results } } - .background(Color.haloCanvas) + .background(Color.flaroCanvas) .navigationTitle(Text("search.title")) - .haloInlineTitle() + .flaroInlineTitle() .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(\.haloItemChanged, { await feed.search(text, from: session.backend) }) + .environment(\.flaroItemChanged, { await feed.search(text, from: session.backend) }) } private var results: some View { ScrollView { - LazyVStack(alignment: .leading, spacing: HaloSpacing.section) { + LazyVStack(alignment: .leading, spacing: FlaroSpacing.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, HaloSpacing.loose) + .padding(.vertical, FlaroSpacing.loose) } - .haloRevealsTopChrome() + .flaroRevealsTopChrome() } @ViewBuilder @@ -72,7 +72,7 @@ struct SearchView: View { text = entry } label: { Label(entry, systemImage: "clock.arrow.circlepath") - .foregroundStyle(Color.haloTextSecondary) + .foregroundStyle(Color.flaroTextSecondary) } } } header: { @@ -81,12 +81,12 @@ struct SearchView: View { Button("search.forgetRecent", role: .destructive) { feed.forgetRecent() } - .font(.haloCaption) + .font(.flaroCaption) } - .listRowBackground(Color.haloSurface) + .listRowBackground(Color.flaroSurface) } .scrollContentBackground(.hidden) - .haloRevealsTopChrome() + .flaroRevealsTopChrome() } } } diff --git a/Halo/Views/Settings/AppearanceView.swift b/Flaro/Views/Settings/AppearanceView.swift similarity index 78% rename from Halo/Views/Settings/AppearanceView.swift rename to Flaro/Views/Settings/AppearanceView.swift index d797e36..466bd12 100644 --- a/Halo/Views/Settings/AppearanceView.swift +++ b/Flaro/Views/Settings/AppearanceView.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign /// Die Farbeinstellungen. /// @@ -8,22 +8,22 @@ import HaloDesign /// Farbe greift die Kontrastkorrektur — und sagt es auch, statt die Farbe /// stillschweigend zu verändern. struct AppearanceView: View { - @Environment(HaloTheme.self) private var theme + @Environment(FlaroTheme.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: HaloSpacing.regular)] + private let columns = [GridItem(.adaptive(minimum: 64), spacing: FlaroSpacing.regular)] var body: some View { Form { Section { - LazyVGrid(columns: columns, spacing: HaloSpacing.regular) { + LazyVGrid(columns: columns, spacing: FlaroSpacing.regular) { ForEach(AccentOption.palette) { option in swatch(option) } } - .padding(.vertical, HaloSpacing.snug) + .padding(.vertical, FlaroSpacing.snug) } header: { Text("appearance.accent") } footer: { @@ -38,7 +38,7 @@ struct AppearanceView: View { LabeledContent { Text(layout.cardScale.formatted(.percent.precision(.fractionLength(0)))) - .foregroundStyle(Color.haloTextSecondary) + .foregroundStyle(Color.flaroTextSecondary) .monospacedDigit() } label: { Text("appearance.cardScale") @@ -52,7 +52,7 @@ struct AppearanceView: View { } footer: { Text("appearance.cardScaleExplanation") } - .listRowBackground(Color.haloSurface) + .listRowBackground(Color.flaroSurface) Section { Toggle("appearance.customColor", isOn: $showsCustomField.animation(.snappy)) @@ -60,7 +60,7 @@ struct AppearanceView: View { if showsCustomField { HStack { TextField("appearance.hexPlaceholder", text: $customHex) - .haloPlainEntry() + .flaroPlainEntry() .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(.haloCaption) - .foregroundStyle(Color.haloDestructive) + .font(.flaroCaption) + .foregroundStyle(Color.flaroDestructive) } } @@ -80,11 +80,11 @@ struct AppearanceView: View { // als im Farbwähler, und niemand wüsste warum. Label { Text("appearance.adjusted \(theme.accent.hexString)") - .font(.haloCaption) + .font(.flaroCaption) } icon: { Image(systemName: "info.circle") } - .foregroundStyle(Color.haloTextSecondary) + .foregroundStyle(Color.flaroTextSecondary) } } @@ -92,11 +92,11 @@ struct AppearanceView: View { PreviewRow() } } - .haloForm() + .flaroForm() .scrollContentBackground(.hidden) - .background(Color.haloCanvas) + .background(Color.flaroCanvas) .navigationTitle(Text("appearance.title")) - .haloInlineTitle() + .flaroInlineTitle() .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.haloCanvas) + .foregroundStyle(Color.flaroCanvas) } } .overlay { Circle() .strokeBorder( - theme.selection == option ? Color.haloTextPrimary : .clear, + theme.selection == option ? Color.flaroTextPrimary : .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(\.haloAccent) private var accent + @Environment(\.flaroAccent) private var accent var body: some View { - VStack(alignment: .leading, spacing: HaloSpacing.regular) { - HStack(spacing: HaloSpacing.regular) { + VStack(alignment: .leading, spacing: FlaroSpacing.regular) { + HStack(spacing: FlaroSpacing.regular) { Label("hero.play", systemImage: "play.fill") - .font(.haloCardTitle) - .padding(.horizontal, HaloSpacing.loose) - .padding(.vertical, HaloSpacing.snug) - .background(accent, in: .rect(cornerRadius: HaloRadius.control)) - .foregroundStyle(Color.haloCanvas) + .font(.flaroCardTitle) + .padding(.horizontal, FlaroSpacing.loose) + .padding(.vertical, FlaroSpacing.snug) + .background(accent, in: .rect(cornerRadius: FlaroRadius.control)) + .foregroundStyle(Color.flaroCanvas) Label("sidebar.downloads", systemImage: "arrow.down.circle") - .font(.haloCardTitle) + .font(.flaroCardTitle) .foregroundStyle(accent) } WatchProgressBar(fraction: 0.45) } - .padding(.vertical, HaloSpacing.snug) - .listRowBackground(Color.haloSurface) + .padding(.vertical, FlaroSpacing.snug) + .listRowBackground(Color.flaroSurface) } } diff --git a/Halo/Views/Settings/AudioLanguagePicker.swift b/Flaro/Views/Settings/AudioLanguagePicker.swift similarity index 86% rename from Halo/Views/Settings/AudioLanguagePicker.swift rename to Flaro/Views/Settings/AudioLanguagePicker.swift index 8785ab4..c89b244 100644 --- a/Halo/Views/Settings/AudioLanguagePicker.swift +++ b/Flaro/Views/Settings/AudioLanguagePicker.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign /// „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(\.haloAccent) private var accent + @Environment(\.flaroAccent) private var accent var body: some View { - HStack(spacing: HaloSpacing.regular) { + HStack(spacing: FlaroSpacing.regular) { Text(title) - .font(.haloBody) - .foregroundStyle(Color.haloTextPrimary) + .font(.flaroBody) + .foregroundStyle(Color.flaroTextPrimary) - Spacer(minLength: HaloSpacing.regular) + Spacer(minLength: FlaroSpacing.regular) Menu { // „Wie allgemein" zuerst und als Vorgabe: die meisten Ebenen @@ -53,11 +53,11 @@ struct AudioLanguagePicker: View { } } } label: { - HStack(spacing: HaloSpacing.tight) { + HStack(spacing: FlaroSpacing.tight) { Text(currentLabel) - .font(.haloBody) + .font(.flaroBody) Image(systemName: "chevron.up.chevron.down") - .font(.haloCaption) + .font(.flaroCaption) } .foregroundStyle(accent) } diff --git a/Halo/Views/Settings/DiagnosticsView.swift b/Flaro/Views/Settings/DiagnosticsView.swift similarity index 83% rename from Halo/Views/Settings/DiagnosticsView.swift rename to Flaro/Views/Settings/DiagnosticsView.swift index cc2e7d6..214df5d 100644 --- a/Halo/Views/Settings/DiagnosticsView.swift +++ b/Flaro/Views/Settings/DiagnosticsView.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign /// Was beim letzten Abspielversuch passiert ist. /// @@ -7,8 +7,8 @@ import HaloDesign /// wurde, über welche Verbindung, und wie lange jeder Schritt gedauert hat. /// Ein Screenshot davon sagt mehr als jede Beschreibung. struct DiagnosticsView: View { - @Environment(HaloSession.self) private var session - @Environment(\.haloAccent) private var accent + @Environment(FlaroSession.self) private var session + @Environment(\.flaroAccent) 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(.haloCaption) + .font(.flaroCaption) } if let beschreibung = session.connectionDescription { LabeledContent("settings.connection", value: beschreibung) - .font(.haloCaption) + .font(.flaroCaption) } } else { - Text("diagnostics.noServer").foregroundStyle(Color.haloTextMuted) + Text("diagnostics.noServer").foregroundStyle(Color.flaroTextMuted) } } @@ -36,11 +36,11 @@ struct DiagnosticsView: View { VStack(alignment: .leading, spacing: 2) { Text("diagnostics.source") - .font(.haloCaption) - .foregroundStyle(Color.haloTextMuted) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextMuted) Text(attempt.sourceDescription) .font(.system(.caption2, design: .monospaced)) - .foregroundStyle(Color.haloTextSecondary) + .foregroundStyle(Color.flaroTextSecondary) } } @@ -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.haloTextSecondary) + .foregroundStyle(Color.flaroTextSecondary) } } Section { Button { - HaloClipboard.copy(report(for: attempt)) + FlaroClipboard.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.haloTextMuted) + Text("diagnostics.nothingYet").foregroundStyle(Color.flaroTextMuted) } } @@ -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) - .haloForm() + .flaroForm() .scrollContentBackground(.hidden) - .background(Color.haloCanvas) + .background(Color.flaroCanvas) .navigationTitle(Text("diagnostics.title")) - .haloInlineTitle() + .flaroInlineTitle() } /// 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 { """ - Halo \(Branding.version) · Build \(Branding.buildStamp) + Flaro \(Branding.version) · Build \(Branding.buildStamp) Verbindung: \(attempt.connection) Titel: \(attempt.title) Weg: \(attempt.method) diff --git a/Halo/Views/Settings/DownloadSettingsView.swift b/Flaro/Views/Settings/DownloadSettingsView.swift similarity index 95% rename from Halo/Views/Settings/DownloadSettingsView.swift rename to Flaro/Views/Settings/DownloadSettingsView.swift index 5ecffb9..2b77ae4 100644 --- a/Halo/Views/Settings/DownloadSettingsView.swift +++ b/Flaro/Views/Settings/DownloadSettingsView.swift @@ -1,6 +1,6 @@ import SwiftUI -import HaloDesign -import HaloDownloads +import FlaroDesign +import FlaroDownloads import MediaKit /// Was beim Herunterladen gilt. @@ -11,7 +11,7 @@ import MediaKit /// rutschen. struct DownloadSettingsView: View { @Environment(DownloadCoordinator.self) private var downloads - @Environment(\.haloAccent) private var accent + @Environment(\.flaroAccent) private var accent var body: some View { @Bindable var downloads = downloads @@ -73,11 +73,11 @@ struct DownloadSettingsView: View { } } .tint(accent) - .haloForm() + .flaroForm() .scrollContentBackground(.hidden) - .background(Color.haloCanvas) + .background(Color.flaroCanvas) .navigationTitle(Text("sidebar.downloads")) - .haloInlineTitle() + .flaroInlineTitle() } private var storageLimitBinding: Binding { diff --git a/Halo/Views/Settings/HomeLayoutView.swift b/Flaro/Views/Settings/HomeLayoutView.swift similarity index 90% rename from Halo/Views/Settings/HomeLayoutView.swift rename to Flaro/Views/Settings/HomeLayoutView.swift index 018c986..2b465fb 100644 --- a/Halo/Views/Settings/HomeLayoutView.swift +++ b/Flaro/Views/Settings/HomeLayoutView.swift @@ -1,11 +1,11 @@ import SwiftUI -import HaloDesign +import FlaroDesign import MediaKit /// Reihen der Startseite ein- und ausblenden und umsortieren. struct HomeLayoutView: View { - @Environment(HaloSession.self) private var session - @Environment(\.haloAccent) private var accent + @Environment(FlaroSession.self) private var session + @Environment(\.flaroAccent) 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.haloCanvas) + .background(Color.flaroCanvas) .navigationTitle(Text("homeLayout.title")) - .haloInlineTitle() + .flaroInlineTitle() .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.haloTextSecondary) + .foregroundStyle(Color.flaroTextSecondary) .monospacedDigit() } label: { Text("home.heroHeight") @@ -64,7 +64,7 @@ struct HomeLayoutView: View { } footer: { Text("home.heroExplanation") } - .listRowBackground(Color.haloSurface) + .listRowBackground(Color.flaroSurface) // **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.haloTextPrimary) + .foregroundStyle(Color.flaroTextPrimary) } // 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: HaloSpacing.snug) { + VStack(alignment: .leading, spacing: FlaroSpacing.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.haloDestructive) + .foregroundStyle(Color.flaroDestructive) } } } - .listRowBackground(Color.haloSurface) + .listRowBackground(Color.flaroSurface) } Section { Toggle("home.combineContinue", isOn: $layout.combinesContinueRows) Toggle("home.hideWatched", isOn: $layout.hidesWatchedInLatest) } - .listRowBackground(Color.haloSurface) + .listRowBackground(Color.flaroSurface) if isLoading { ProgressView() @@ -126,8 +126,8 @@ struct HomeLayoutView: View { .listRowBackground(Color.clear) } else if rows.isEmpty { Text("homeLayout.empty") - .foregroundStyle(Color.haloTextSecondary) - .listRowBackground(Color.haloSurface) + .foregroundStyle(Color.flaroTextSecondary) + .listRowBackground(Color.flaroSurface) } Section { @@ -140,9 +140,9 @@ struct HomeLayoutView: View { } )) { Text(row.title) - .foregroundStyle(Color.haloTextPrimary) + .foregroundStyle(Color.flaroTextPrimary) } - .listRowBackground(Color.haloSurface) + .listRowBackground(Color.flaroSurface) } .onMove { indices, destination in rows.move(fromOffsets: indices, toOffset: destination) @@ -162,7 +162,7 @@ struct HomeLayoutView: View { if !rows.isEmpty { Spacer() EditButton() - .font(.haloCaption) + .font(.flaroCaption) .textCase(nil) } #endif diff --git a/Halo/Views/Settings/LanguagesView.swift b/Flaro/Views/Settings/LanguagesView.swift similarity index 90% rename from Halo/Views/Settings/LanguagesView.swift rename to Flaro/Views/Settings/LanguagesView.swift index 6777fd3..3764784 100644 --- a/Halo/Views/Settings/LanguagesView.swift +++ b/Flaro/Views/Settings/LanguagesView.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign /// Welche Sprachen der Player von sich aus wählen soll. /// @@ -9,7 +9,7 @@ import HaloDesign /// Vorliebe, die niemand äußern kann, ist keine. struct LanguagesView: View { @Environment(LanguagePreferences.self) private var settings - @Environment(\.haloAccent) private var accent + @Environment(\.flaroAccent) private var accent @State private var isAdding = false @@ -61,11 +61,11 @@ struct LanguagesView: View { } } .tint(accent) - .haloForm() + .flaroForm() .scrollContentBackground(.hidden) - .background(Color.haloCanvas) + .background(Color.flaroCanvas) .navigationTitle(Text("languages.title")) - .haloInlineTitle() + .flaroInlineTitle() // 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.haloTextSecondary) + .foregroundStyle(Color.flaroTextSecondary) } else { ForEach(Array(settings.fallbacks.enumerated()), id: \.element) { position, code in - HStack(spacing: HaloSpacing.regular) { + HStack(spacing: FlaroSpacing.regular) { // Die Nummer, weil die Reihenfolge der ganze Zweck // ist — eine Liste ohne sichtbaren Rang liest sich // wie eine Menge. Text("\(position + 1)") - .font(.haloCaption.monospacedDigit()) - .foregroundStyle(Color.haloTextSecondary) + .font(.flaroCaption.monospacedDigit()) + .foregroundStyle(Color.flaroTextSecondary) .frame(minWidth: 18, alignment: .trailing) Text(name(of: code)) - .foregroundStyle(Color.haloTextPrimary) + .foregroundStyle(Color.flaroTextPrimary) } } .onMove { von, nach in diff --git a/Halo/Views/Settings/PlaybackSettingsView.swift b/Flaro/Views/Settings/PlaybackSettingsView.swift similarity index 93% rename from Halo/Views/Settings/PlaybackSettingsView.swift rename to Flaro/Views/Settings/PlaybackSettingsView.swift index cbee23b..dfb4b47 100644 --- a/Halo/Views/Settings/PlaybackSettingsView.swift +++ b/Flaro/Views/Settings/PlaybackSettingsView.swift @@ -1,6 +1,6 @@ import SwiftUI -import HaloDesign -import HaloPlayback +import FlaroDesign +import FlaroPlayback /// Alles, was die Wiedergabe betrifft. /// @@ -9,7 +9,7 @@ import HaloPlayback /// einmal durchgeht und dann in Ruhe lässt. struct PlaybackSettingsView: View { @Environment(PlaybackSettings.self) private var settings - @Environment(\.haloAccent) private var accent + @Environment(\.flaroAccent) 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: HaloSpacing.snug) { + VStack(alignment: .leading, spacing: FlaroSpacing.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(.haloCaption) - .foregroundStyle(Color.haloTextSecondary) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextSecondary) } } } @@ -108,11 +108,11 @@ struct PlaybackSettingsView: View { } } .tint(accent) - .haloForm() + .flaroForm() .scrollContentBackground(.hidden) - .background(Color.haloCanvas) + .background(Color.flaroCanvas) .navigationTitle(Text("settings.playback")) - .haloInlineTitle() + .flaroInlineTitle() } private func rateLabel(_ rate: Double) -> String { diff --git a/Halo/Views/Settings/ServerSettingsView.swift b/Flaro/Views/Settings/ServerSettingsView.swift similarity index 90% rename from Halo/Views/Settings/ServerSettingsView.swift rename to Flaro/Views/Settings/ServerSettingsView.swift index 12e279f..615b711 100644 --- a/Halo/Views/Settings/ServerSettingsView.swift +++ b/Flaro/Views/Settings/ServerSettingsView.swift @@ -1,11 +1,11 @@ import SwiftUI -import HaloDesign +import FlaroDesign import MediaKit /// Mit welchem Server gesprochen wird — und was er gerade anbietet. struct ServerSettingsView: View { - @Environment(HaloSession.self) private var session - @Environment(\.haloAccent) private var accent + @Environment(FlaroSession.self) private var session + @Environment(\.flaroAccent) 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(.haloCaption) + .font(.flaroCaption) .textSelection(.enabled) } if let accountName = session.accountName { @@ -44,11 +44,11 @@ struct ServerSettingsView: View { } } .tint(accent) - .haloForm() + .flaroForm() .scrollContentBackground(.hidden) - .background(Color.haloCanvas) + .background(Color.flaroCanvas) .navigationTitle(Text("settings.server")) - .haloInlineTitle() + .flaroInlineTitle() } /// 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(HaloSession.self) private var session - @Environment(\.haloAccent) private var accent + @Environment(FlaroSession.self) private var session + @Environment(\.flaroAccent) private var accent @State private var phase: Phase = .idle private enum Phase { case idle, running, done } var body: some View { LabeledContent { - HStack(spacing: HaloSpacing.regular) { + HStack(spacing: FlaroSpacing.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.haloTextSecondary) + .foregroundStyle(Color.flaroTextSecondary) } if session.backend?.capabilities.contains(.libraryScan) == true { diff --git a/Halo/Views/Settings/SettingsChrome.swift b/Flaro/Views/Settings/SettingsChrome.swift similarity index 84% rename from Halo/Views/Settings/SettingsChrome.swift rename to Flaro/Views/Settings/SettingsChrome.swift index c78a569..5096991 100644 --- a/Halo/Views/Settings/SettingsChrome.swift +++ b/Flaro/Views/Settings/SettingsChrome.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign /// Das farbige Symbol vor einer Einstellungszeile. /// @@ -35,7 +35,7 @@ struct SettingsHeader: View { let explanation: LocalizedStringKey var body: some View { - VStack(alignment: .leading, spacing: HaloSpacing.regular) { + VStack(alignment: .leading, spacing: FlaroSpacing.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(.haloTitle) - .foregroundStyle(Color.haloTextPrimary) + .font(.flaroTitle) + .foregroundStyle(Color.flaroTextPrimary) Text(explanation) - .font(.haloCaption) - .foregroundStyle(Color.haloTextSecondary) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextSecondary) } .frame(maxWidth: .infinity, alignment: .leading) - .padding(.vertical, HaloSpacing.snug) - .listRowBackground(Color.haloSurface) + .padding(.vertical, FlaroSpacing.snug) + .listRowBackground(Color.flaroSurface) } } diff --git a/Halo/Views/Settings/SettingsView.swift b/Flaro/Views/Settings/SettingsView.swift similarity index 92% rename from Halo/Views/Settings/SettingsView.swift rename to Flaro/Views/Settings/SettingsView.swift index 49a0299..96a7ad2 100644 --- a/Halo/Views/Settings/SettingsView.swift +++ b/Flaro/Views/Settings/SettingsView.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign /// Die Einstellungen — als Übersicht, nicht als eine lange Liste. /// @@ -10,8 +10,8 @@ import HaloDesign /// /// Jetzt führt jede Zeile in einen Bildschirm, der zu **einer** Frage gehört. struct SettingsView: View { - @Environment(HaloSession.self) private var session - @Environment(\.haloAccent) private var accent + @Environment(FlaroSession.self) private var session + @Environment(\.flaroAccent) 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.haloTextSecondary) + .foregroundStyle(Color.flaroTextSecondary) } 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) - .haloForm() + .flaroForm() .scrollContentBackground(.hidden) - .haloRevealsTopChrome() - .background(Color.haloCanvas) + .flaroRevealsTopChrome() + .background(Color.flaroCanvas) .navigationTitle(Text("sidebar.settings")) - .haloInlineTitle() + .flaroInlineTitle() .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: HaloSpacing.regular) { + HStack(spacing: FlaroSpacing.regular) { SettingsIcon(symbol: symbol, colour: colour) Text(title) } diff --git a/Halo/Views/Settings/SubtitleAppearanceView.swift b/Flaro/Views/Settings/SubtitleAppearanceView.swift similarity index 92% rename from Halo/Views/Settings/SubtitleAppearanceView.swift rename to Flaro/Views/Settings/SubtitleAppearanceView.swift index ed2d35d..744bf9b 100644 --- a/Halo/Views/Settings/SubtitleAppearanceView.swift +++ b/Flaro/Views/Settings/SubtitleAppearanceView.swift @@ -1,11 +1,11 @@ import SwiftUI -import HaloDesign -import HaloPlayback +import FlaroDesign +import FlaroPlayback /// Wie Untertitel aussehen sollen. struct SubtitleAppearanceView: View { @Environment(SubtitleAppearance.self) private var appearance - @Environment(\.haloAccent) private var accent + @Environment(\.flaroAccent) private var accent var body: some View { @Bindable var appearance = appearance @@ -51,11 +51,11 @@ struct SubtitleAppearanceView: View { } } .tint(accent) - .haloForm() + .flaroForm() .scrollContentBackground(.hidden) - .background(Color.haloCanvas) + .background(Color.flaroCanvas) .navigationTitle(Text("subtitleStyle.title")) - .haloInlineTitle() + .flaroInlineTitle() } /// Ein Beispielsatz über grauer Fläche. @@ -84,10 +84,10 @@ struct SubtitleAppearanceView: View { radius: 2, y: 1 ) - .padding(HaloSpacing.regular) + .padding(FlaroSpacing.regular) } .frame(height: 96) - .clipShape(.rect(cornerRadius: HaloRadius.card)) + .clipShape(.rect(cornerRadius: FlaroRadius.card)) .listRowInsets(EdgeInsets()) .listRowBackground(Color.clear) } diff --git a/Halo/Views/SignIn/ConnectionStateViews.swift b/Flaro/Views/SignIn/ConnectionStateViews.swift similarity index 75% rename from Halo/Views/SignIn/ConnectionStateViews.swift rename to Flaro/Views/SignIn/ConnectionStateViews.swift index ae803c4..7f5ab71 100644 --- a/Halo/Views/SignIn/ConnectionStateViews.swift +++ b/Flaro/Views/SignIn/ConnectionStateViews.swift @@ -1,21 +1,21 @@ import SwiftUI -import HaloDesign +import FlaroDesign /// Während ein Weg zum Server gesucht wird. struct ConnectingView: View { let serverName: String var body: some View { - VStack(spacing: HaloSpacing.loose) { + VStack(spacing: FlaroSpacing.loose) { ProgressView() Text(serverName.isEmpty ? String(localized: "connecting.searching") : String(localized: "connecting.to \(serverName)")) - .font(.haloBody) - .foregroundStyle(Color.haloTextSecondary) + .font(.flaroBody) + .foregroundStyle(Color.flaroTextSecondary) } .frame(maxWidth: .infinity, maxHeight: .infinity) - .background(Color.haloCanvas) + .background(Color.flaroCanvas) } } @@ -33,8 +33,8 @@ struct ConnectionFailureView: View { } actions: { Button("action.retry", action: onRetry).buttonStyle(.borderedProminent) Button("action.signOut", action: onSignOut) - .foregroundStyle(Color.haloTextSecondary) + .foregroundStyle(Color.flaroTextSecondary) } - .background(Color.haloCanvas) + .background(Color.flaroCanvas) } } diff --git a/Halo/Views/SignIn/JellyfinSignInView.swift b/Flaro/Views/SignIn/JellyfinSignInView.swift similarity index 71% rename from Halo/Views/SignIn/JellyfinSignInView.swift rename to Flaro/Views/SignIn/JellyfinSignInView.swift index 6272732..9a898fc 100644 --- a/Halo/Views/SignIn/JellyfinSignInView.swift +++ b/Flaro/Views/SignIn/JellyfinSignInView.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign 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(HaloSession.self) private var session + @Environment(FlaroSession.self) private var session @Environment(\.dismiss) private var dismiss - @Environment(\.haloAccent) private var accent + @Environment(\.flaroAccent) 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, HaloSpacing.section) - .padding(.vertical, HaloSpacing.section) + .padding(.horizontal, FlaroSpacing.section) + .padding(.vertical, FlaroSpacing.section) .frame(maxWidth: 420) .frame(maxWidth: .infinity) } } .scrollDismissesKeyboard(.interactively) - .background(Color.haloCanvas) + .background(Color.flaroCanvas) .navigationTitle(Text("signIn.jellyfin.title")) - .haloInlineTitle() + .flaroInlineTitle() .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: HaloSpacing.section) { + VStack(alignment: .leading, spacing: FlaroSpacing.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(.haloCaption) - .foregroundStyle(Color.haloDestructive) + .font(.flaroCaption) + .foregroundStyle(Color.flaroDestructive) } } } @@ -94,39 +94,39 @@ struct JellyfinSignInView: View { private func addressStep(model: JellyfinSignInModel) -> some View { @Bindable var model = model - VStack(alignment: .leading, spacing: HaloSpacing.regular) { + VStack(alignment: .leading, spacing: FlaroSpacing.regular) { Text("signIn.jellyfin.addressPrompt") - .font(.haloRowHeader) - .foregroundStyle(Color.haloTextPrimary) + .font(.flaroRowHeader) + .foregroundStyle(Color.flaroTextPrimary) TextField("signIn.jellyfin.addressPlaceholder", text: $model.address) .textFieldStyle(.plain) .textContentType(.URL) - .haloPlainEntry(isAddress: true) + .flaroPlainEntry(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(HaloSpacing.regular) - .background(Color.haloElevated, in: .rect(cornerRadius: HaloRadius.control)) - .foregroundStyle(Color.haloTextPrimary) + .padding(FlaroSpacing.regular) + .background(Color.flaroElevated, in: .rect(cornerRadius: FlaroRadius.control)) + .foregroundStyle(Color.flaroTextPrimary) // Ein Beispiel statt einer Erklärung: „Schema, Host, Port" sagt // niemandem etwas, „192.168.1.50" jedem. Text("signIn.jellyfin.addressHint") - .font(.haloCaption) - .foregroundStyle(Color.haloTextMuted) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextMuted) Button { focusedField = nil Task { await model.findServer() } } label: { Text("signIn.jellyfin.connect") - .font(.haloRowHeader) + .font(.flaroRowHeader) .frame(maxWidth: .infinity) - .padding(.vertical, HaloSpacing.regular) + .padding(.vertical, FlaroSpacing.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: HaloSpacing.regular) { + VStack(alignment: .leading, spacing: FlaroSpacing.regular) { foundServerHeader(model: model) Text("signIn.jellyfin.quickConnectHint") - .font(.haloBody) - .foregroundStyle(Color.haloTextSecondary) + .font(.flaroBody) + .foregroundStyle(Color.flaroTextSecondary) Text(code) .font(.system(.largeTitle, design: .monospaced, weight: .semibold)) .tracking(8) - .foregroundStyle(Color.haloTextPrimary) + .foregroundStyle(Color.flaroTextPrimary) .textSelection(.enabled) - .padding(.vertical, HaloSpacing.regular) + .padding(.vertical, FlaroSpacing.regular) .frame(maxWidth: .infinity) - .background(Color.haloElevated, in: .rect(cornerRadius: HaloRadius.control)) + .background(Color.flaroElevated, in: .rect(cornerRadius: FlaroRadius.control)) - HStack(spacing: HaloSpacing.snug) { + HStack(spacing: FlaroSpacing.snug) { ProgressView().controlSize(.small) Text("signIn.jellyfin.waitingForApproval") - .font(.haloCaption) - .foregroundStyle(Color.haloTextMuted) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextMuted) } Text("signIn.jellyfin.privacy") - .font(.haloCaption) - .foregroundStyle(Color.haloTextMuted) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextMuted) - Divider().overlay(Color.haloSeparator) + Divider().overlay(Color.flaroSeparator) Button("signIn.jellyfin.usePassword") { model.useCredentials() } - .font(.haloCaption) + .font(.flaroCaption) Button("signIn.jellyfin.otherAddress") { model.startOver() } - .font(.haloCaption) - .foregroundStyle(Color.haloTextSecondary) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextSecondary) } } @@ -181,12 +181,12 @@ struct JellyfinSignInView: View { private func credentialsStep(model: JellyfinSignInModel) -> some View { @Bindable var model = model - VStack(alignment: .leading, spacing: HaloSpacing.regular) { + VStack(alignment: .leading, spacing: FlaroSpacing.regular) { foundServerHeader(model: model) TextField("signIn.jellyfin.userName", text: $model.userName) .textContentType(.username) - .haloPlainEntry() + .flaroPlainEntry() .submitLabel(.next) .focused($focusedField, equals: .userName) .onSubmit { focusedField = .password } @@ -200,8 +200,8 @@ struct JellyfinSignInView: View { focusedField = .password return .handled } - .padding(HaloSpacing.regular) - .background(Color.haloElevated, in: .rect(cornerRadius: HaloRadius.control)) + .padding(FlaroSpacing.regular) + .background(Color.flaroElevated, in: .rect(cornerRadius: FlaroRadius.control)) SecureField("signIn.jellyfin.password", text: $model.password) .textContentType(.password) @@ -214,17 +214,17 @@ struct JellyfinSignInView: View { focusedField = .userName return .handled } - .padding(HaloSpacing.regular) - .background(Color.haloElevated, in: .rect(cornerRadius: HaloRadius.control)) + .padding(FlaroSpacing.regular) + .background(Color.flaroElevated, in: .rect(cornerRadius: FlaroRadius.control)) Button { focusedField = nil Task { await model.signInWithPassword() } } label: { Text("signIn.jellyfin.submit") - .font(.haloRowHeader) + .font(.flaroRowHeader) .frame(maxWidth: .infinity) - .padding(.vertical, HaloSpacing.regular) + .padding(.vertical, FlaroSpacing.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(.haloCaption) - .foregroundStyle(Color.haloTextMuted) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextMuted) - Divider().overlay(Color.haloSeparator) + Divider().overlay(Color.flaroSeparator) if model.offersQuickConnect { Button("signIn.jellyfin.useCode") { Task { await model.beginQuickConnect() } } - .font(.haloCaption) + .font(.flaroCaption) } Button("signIn.jellyfin.otherAddress") { model.startOver() } - .font(.haloCaption) - .foregroundStyle(Color.haloTextSecondary) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextSecondary) } - .foregroundStyle(Color.haloTextPrimary) + .foregroundStyle(Color.flaroTextPrimary) } // MARK: - Bausteine @ViewBuilder private func foundServerHeader(model: JellyfinSignInModel) -> some View { - VStack(alignment: .leading, spacing: HaloSpacing.tight) { + VStack(alignment: .leading, spacing: FlaroSpacing.tight) { Text("signIn.jellyfin.foundServer") - .font(.haloCaption) - .foregroundStyle(Color.haloTextMuted) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextMuted) .textCase(.uppercase) Text(model.serverName ?? model.address) - .font(.haloTitle) - .foregroundStyle(Color.haloTextPrimary) + .font(.flaroTitle) + .foregroundStyle(Color.flaroTextPrimary) } } @ViewBuilder private func waiting(text: LocalizedStringKey) -> some View { - HStack(spacing: HaloSpacing.snug) { + HStack(spacing: FlaroSpacing.snug) { ProgressView().controlSize(.small) Text(text) - .font(.haloBody) - .foregroundStyle(Color.haloTextSecondary) + .font(.flaroBody) + .foregroundStyle(Color.flaroTextSecondary) } .frame(maxWidth: .infinity, alignment: .center) - .padding(.vertical, HaloSpacing.section) + .padding(.vertical, FlaroSpacing.section) } } diff --git a/Halo/Views/SignIn/SignInView.swift b/Flaro/Views/SignIn/SignInView.swift similarity index 67% rename from Halo/Views/SignIn/SignInView.swift rename to Flaro/Views/SignIn/SignInView.swift index de818f1..1b04848 100644 --- a/Halo/Views/SignIn/SignInView.swift +++ b/Flaro/Views/SignIn/SignInView.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign /// Der Anmeldebildschirm. /// @@ -12,54 +12,54 @@ import HaloDesign /// 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(\.haloAccent) private var accent + @Environment(\.flaroAccent) private var accent @State private var showsJellyfinSignIn = false var body: some View { - VStack(spacing: HaloSpacing.section) { + VStack(spacing: FlaroSpacing.section) { Spacer() - VStack(spacing: HaloSpacing.regular) { + VStack(spacing: FlaroSpacing.regular) { Image(systemName: "play.rectangle.on.rectangle") .font(.system(size: 52)) .foregroundStyle(accent) Text(Branding.appName) - .font(.haloHero) - .foregroundStyle(Color.haloTextPrimary) + .font(.flaroHero) + .foregroundStyle(Color.flaroTextPrimary) Text("signIn.tagline") - .font(.haloBody) - .foregroundStyle(Color.haloTextSecondary) + .font(.flaroBody) + .foregroundStyle(Color.flaroTextSecondary) .multilineTextAlignment(.center) } Spacer() - VStack(spacing: HaloSpacing.regular) { + VStack(spacing: FlaroSpacing.regular) { Button { showsJellyfinSignIn = true } label: { Text("signIn.withJellyfin") - .font(.haloRowHeader) + .font(.flaroRowHeader) .frame(maxWidth: .infinity) - .padding(.vertical, HaloSpacing.regular) + .padding(.vertical, FlaroSpacing.regular) } .buttonStyle(.borderedProminent) .tint(accent) Text("signIn.privacy") - .font(.haloCaption) - .foregroundStyle(Color.haloTextMuted) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextMuted) .multilineTextAlignment(.center) } - Spacer().frame(height: HaloSpacing.section) + Spacer().frame(height: FlaroSpacing.section) } - .padding(.horizontal, HaloSpacing.section) + .padding(.horizontal, FlaroSpacing.section) .frame(maxWidth: 420) .frame(maxWidth: .infinity, maxHeight: .infinity) - .background(Color.haloCanvas) + .background(Color.flaroCanvas) .sheet(isPresented: $showsJellyfinSignIn) { JellyfinSignInView() } diff --git a/HaloTV/Halo.entitlements b/FlaroTV/Flaro.entitlements similarity index 82% rename from HaloTV/Halo.entitlements rename to FlaroTV/Flaro.entitlements index 4140325..b9a5ad2 100644 --- a/HaloTV/Halo.entitlements +++ b/FlaroTV/Flaro.entitlements @@ -4,7 +4,7 @@ com.apple.security.application-groups - group.com.scarriffleservices.halo + group.com.scarriffleservices.flaro diff --git a/HaloTV/HaloTVApp.swift b/FlaroTV/FlaroTVApp.swift similarity index 87% rename from HaloTV/HaloTVApp.swift rename to FlaroTV/FlaroTVApp.swift index 7674a8e..1a3e5fb 100644 --- a/HaloTV/HaloTVApp.swift +++ b/FlaroTV/FlaroTVApp.swift @@ -1,12 +1,12 @@ import SwiftUI -import HaloDesign -import HaloPlayback +import FlaroDesign +import FlaroPlayback import MediaKit import JellyfinKit /// Die App auf dem Fernseher. /// -/// **Eine eigene Wurzel statt eines Zweigs in `HaloApp`.** Der Unterschied +/// **Eine eigene Wurzel statt eines Zweigs in `FlaroApp`.** 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: `Halo/Session/` +/// **Die Modelle dagegen werden geteilt**, nicht kopiert: `Flaro/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 HaloTVApp: App { - @State private var session: HaloSession - @State private var theme = HaloTheme() +struct FlaroTVApp: App { + @State private var session: FlaroSession + @State private var theme = FlaroTheme() @State private var playback = PlaybackCoordinator() @State private var playbackSettings = PlaybackSettings() @State private var languages = LanguagePreferences() @@ -40,7 +40,7 @@ struct HaloTVApp: App { @State private var network = NetworkConditions() init() { - _session = State(initialValue: HaloSession( + _session = State(initialValue: FlaroSession( jellyfinIdentity: JellyfinIdentity.current( client: Branding.appName, version: Branding.version @@ -62,7 +62,7 @@ struct HaloTVApp: App { .environment(homeLayout) .environment(diagnostics) .environment(network) - .haloAccent(theme) + .flaroAccent(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/HaloTV/Info.plist b/FlaroTV/Info.plist similarity index 84% rename from HaloTV/Info.plist rename to FlaroTV/Info.plist index 63f8a60..d8cab78 100644 --- a/HaloTV/Info.plist +++ b/FlaroTV/Info.plist @@ -5,7 +5,7 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName - Halo + Flaro CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -22,10 +22,10 @@ CFBundleURLName - com.scarriffleservices.halo.topshelf + com.scarriffleservices.flaro.topshelf CFBundleURLSchemes - halo + flaro @@ -39,7 +39,7 @@ NSLocalNetworkUsageDescription - Halo benötigt Zugriff auf das lokale Netzwerk, um deinen Jellyfin-Server zu erreichen. + Flaro benötigt Zugriff auf das lokale Netzwerk, um deinen Jellyfin-Server zu erreichen. UIUserInterfaceStyle Dark diff --git a/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json b/FlaroTV/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 HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json rename to FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json diff --git a/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/back.png b/FlaroTV/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 HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/back.png rename to FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/back.png diff --git a/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json b/FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json similarity index 100% rename from HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json rename to FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json diff --git a/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json b/FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json similarity index 100% rename from HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json rename to FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json diff --git a/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json b/FlaroTV/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 HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json rename to FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json diff --git a/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/front.png b/FlaroTV/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 HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/front.png rename to FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/front.png diff --git a/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json b/FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json similarity index 100% rename from HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json rename to FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json diff --git a/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json b/FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json similarity index 100% rename from HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json rename to FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json diff --git a/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/back.png b/FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/back.png similarity index 100% rename from HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/back.png rename to FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/back.png diff --git a/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/back@2x.png b/FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/back@2x.png similarity index 100% rename from HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/back@2x.png rename to FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/back@2x.png diff --git a/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json b/FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json similarity index 100% rename from HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json rename to FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json diff --git a/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json b/FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json similarity index 100% rename from HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json rename to FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json diff --git a/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json b/FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json similarity index 100% rename from HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json rename to FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json diff --git a/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/front.png b/FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/front.png similarity index 100% rename from HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/front.png rename to FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/front.png diff --git a/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/front@2x.png b/FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/front@2x.png similarity index 100% rename from HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/front@2x.png rename to FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/front@2x.png diff --git a/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json b/FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json similarity index 100% rename from HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json rename to FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json diff --git a/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json b/FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json similarity index 100% rename from HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json rename to FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json diff --git a/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json b/FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json similarity index 100% rename from HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json rename to FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json diff --git a/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/topshelfwide.png b/FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/topshelfwide.png similarity index 100% rename from HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/topshelfwide.png rename to FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/topshelfwide.png diff --git a/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/topshelfwide@2x.png b/FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/topshelfwide@2x.png similarity index 100% rename from HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/topshelfwide@2x.png rename to FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/topshelfwide@2x.png diff --git a/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json b/FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json similarity index 100% rename from HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json rename to FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json diff --git a/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/topshelf.png b/FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/topshelf.png similarity index 100% rename from HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/topshelf.png rename to FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/topshelf.png diff --git a/HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/topshelf@2x.png b/FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/topshelf@2x.png similarity index 100% rename from HaloTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/topshelf@2x.png rename to FlaroTV/Resources/TVAssets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/topshelf@2x.png diff --git a/HaloTV/Resources/TVAssets.xcassets/Contents.json b/FlaroTV/Resources/TVAssets.xcassets/Contents.json similarity index 100% rename from HaloTV/Resources/TVAssets.xcassets/Contents.json rename to FlaroTV/Resources/TVAssets.xcassets/Contents.json diff --git a/HaloTV/Views/Detail/TVDetailView.swift b/FlaroTV/Views/Detail/TVDetailView.swift similarity index 87% rename from HaloTV/Views/Detail/TVDetailView.swift rename to FlaroTV/Views/Detail/TVDetailView.swift index 4516d8a..a1e2437 100644 --- a/HaloTV/Views/Detail/TVDetailView.swift +++ b/FlaroTV/Views/Detail/TVDetailView.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign import MediaKit /// Die Detailseite auf dem Fernseher. @@ -10,7 +10,7 @@ import MediaKit struct TVDetailView: View { let route: MediaRoute - @Environment(HaloSession.self) private var session + @Environment(FlaroSession.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: HaloSpacing.regular) { - Text(meldung).font(.haloBody).foregroundStyle(.white) + VStack(spacing: FlaroSpacing.regular) { + Text(meldung).font(.flaroBody).foregroundStyle(.white) Button("action.retry") { Task { await lade() } } } case .loaded(let item): diff --git a/HaloTV/Views/Home/TVHeroSection.swift b/FlaroTV/Views/Home/TVHeroSection.swift similarity index 92% rename from HaloTV/Views/Home/TVHeroSection.swift rename to FlaroTV/Views/Home/TVHeroSection.swift index a9ef245..95e58cc 100644 --- a/HaloTV/Views/Home/TVHeroSection.swift +++ b/FlaroTV/Views/Home/TVHeroSection.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign import MediaKit /// Der Aufmacher oben auf der Startseite des Fernsehers. @@ -13,8 +13,8 @@ struct TVHeroSection: View { let onPlay: () -> Void let onDetails: () -> Void - @Environment(HaloSession.self) private var session - @Environment(\.haloAccent) private var accent + @Environment(FlaroSession.self) private var session + @Environment(\.flaroAccent) 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: HaloAspectRatio.hero, + aspectRatio: FlaroAspectRatio.hero, // Der Aufmacher nimmt die Höhe, die das Karussell ihm gibt. fillsAvailableSpace: true ) { diff --git a/HaloTV/Views/Home/TVHomeView.swift b/FlaroTV/Views/Home/TVHomeView.swift similarity index 87% rename from HaloTV/Views/Home/TVHomeView.swift rename to FlaroTV/Views/Home/TVHomeView.swift index bfb78aa..ff5bd19 100644 --- a/HaloTV/Views/Home/TVHomeView.swift +++ b/FlaroTV/Views/Home/TVHomeView.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign 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(HaloSession.self) private var session + @Environment(FlaroSession.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: HaloSpacing.regular) { - Text(meldung).font(.haloBody).foregroundStyle(.white) + VStack(spacing: FlaroSpacing.regular) { + Text(meldung).font(.flaroBody).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(.haloRowHeader).foregroundStyle(.white) + Text("home.empty.title").font(.flaroRowHeader).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: HaloSpacing.section) { + LazyVStack(alignment: .leading, spacing: FlaroSpacing.section) { if let gezeigt = aufmacher ?? feed.heroItems(for: layout).first { TVHeroSection( item: gezeigt, @@ -94,7 +94,7 @@ struct TVHomeView: View { ) } } - .padding(.bottom, HaloSpacing.screenMargin) + .padding(.bottom, FlaroSpacing.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: HaloSpacing.tight) { + VStack(alignment: .leading, spacing: FlaroSpacing.tight) { Text("topShelf.title") - .font(.haloCaption) - .foregroundStyle(Color.haloTextMuted) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextMuted) Text(TopShelfWriter.status) - .font(.haloCaption) - .foregroundStyle(Color.haloTextSecondary) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextSecondary) } - .padding(.horizontal, HaloSpacing.screenMargin) - .padding(.bottom, HaloSpacing.regular) + .padding(.horizontal, FlaroSpacing.screenMargin) + .padding(.bottom, FlaroSpacing.regular) .frame(maxWidth: .infinity, alignment: .leading) .background(Color.black.opacity(0.6)) #endif diff --git a/HaloTV/Views/Home/TVMediaRow.swift b/FlaroTV/Views/Home/TVMediaRow.swift similarity index 83% rename from HaloTV/Views/Home/TVMediaRow.swift rename to FlaroTV/Views/Home/TVMediaRow.swift index 43d615c..a17c993 100644 --- a/HaloTV/Views/Home/TVMediaRow.swift +++ b/FlaroTV/Views/Home/TVMediaRow.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign 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(HaloSession.self) private var session + @Environment(FlaroSession.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: HaloSpacing.regular) { + VStack(alignment: .leading, spacing: FlaroSpacing.regular) { Text(row.title) - .font(.haloRowHeader) - .foregroundStyle(Color.haloTextPrimary) - .padding(.horizontal, HaloSpacing.screenMargin) + .font(.flaroRowHeader) + .foregroundStyle(Color.flaroTextPrimary) + .padding(.horizontal, FlaroSpacing.screenMargin) ScrollView(.horizontal) { - LazyHStack(spacing: HaloSpacing.regular) { + LazyHStack(spacing: FlaroSpacing.regular) { ForEach(row.items) { item in karte(for: item).frame(width: breite) } } - .padding(.horizontal, HaloSpacing.screenMargin) + .padding(.horizontal, FlaroSpacing.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, HaloSpacing.regular) + .padding(.vertical, FlaroSpacing.regular) } .scrollClipDisabled() .scrollIndicators(.never) diff --git a/HaloTV/Views/Library/TVLibraryView.swift b/FlaroTV/Views/Library/TVLibraryView.swift similarity index 85% rename from HaloTV/Views/Library/TVLibraryView.swift rename to FlaroTV/Views/Library/TVLibraryView.swift index 9bcaf3b..a4c4d07 100644 --- a/HaloTV/Views/Library/TVLibraryView.swift +++ b/FlaroTV/Views/Library/TVLibraryView.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign import MediaKit /// Eine Mediathek als Raster auf dem Fernseher. @@ -12,7 +12,7 @@ import MediaKit struct TVLibraryView: View { let libraryID: String - @Environment(HaloSession.self) private var session + @Environment(FlaroSession.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: HaloSpacing.section), count: Self.spalten) + Array(repeating: GridItem(.flexible(), spacing: FlaroSpacing.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: HaloSpacing.regular) { - Text(meldung).font(.haloBody).foregroundStyle(.white) + VStack(spacing: FlaroSpacing.regular) { + Text(meldung).font(.flaroBody).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: HaloSpacing.section) { + VStack(alignment: .leading, spacing: FlaroSpacing.section) { Text(feed.library.title) - .font(.haloHero) + .font(.flaroHero) .foregroundStyle(.white) - .padding(.horizontal, HaloSpacing.screenMargin) + .padding(.horizontal, FlaroSpacing.screenMargin) - LazyVGrid(columns: raster, spacing: HaloSpacing.section) { + LazyVGrid(columns: raster, spacing: FlaroSpacing.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, HaloSpacing.screenMargin) + .padding(.horizontal, FlaroSpacing.screenMargin) if feed.loadMoreFailed { Button("library.loadMore") { Task { await feed.loadMore(from: session.backend) } } - .padding(.horizontal, HaloSpacing.screenMargin) + .padding(.horizontal, FlaroSpacing.screenMargin) } } - .padding(.vertical, HaloSpacing.screenMargin) + .padding(.vertical, FlaroSpacing.screenMargin) } .scrollClipDisabled() .scrollIndicators(.never) - // Siehe `HaloSpacing.screenMargin`: bildfüllend, Rand im Wert. + // Siehe `FlaroSpacing.screenMargin`: bildfüllend, Rand im Wert. .ignoresSafeArea() } } diff --git a/HaloTV/Views/Player/TVPlayerCoordinator.swift b/FlaroTV/Views/Player/TVPlayerCoordinator.swift similarity index 99% rename from HaloTV/Views/Player/TVPlayerCoordinator.swift rename to FlaroTV/Views/Player/TVPlayerCoordinator.swift index f17afd3..282a3cb 100644 --- a/HaloTV/Views/Player/TVPlayerCoordinator.swift +++ b/FlaroTV/Views/Player/TVPlayerCoordinator.swift @@ -1,6 +1,6 @@ import AVKit import UIKit -import HaloPlayback +import FlaroPlayback import MediaKit /// Führt Apples Player — und hält ihn über einen Neuaufbau hinweg am Leben. diff --git a/HaloTV/Views/Player/TVPlayerHost.swift b/FlaroTV/Views/Player/TVPlayerHost.swift similarity index 99% rename from HaloTV/Views/Player/TVPlayerHost.swift rename to FlaroTV/Views/Player/TVPlayerHost.swift index d0cc304..f44eb14 100644 --- a/HaloTV/Views/Player/TVPlayerHost.swift +++ b/FlaroTV/Views/Player/TVPlayerHost.swift @@ -1,6 +1,6 @@ import AVKit import SwiftUI -import HaloPlayback +import FlaroPlayback import MediaKit /// Hängt Apples Player in den SwiftUI-Baum. diff --git a/HaloTV/Views/Player/TVPlayerScreen.swift b/FlaroTV/Views/Player/TVPlayerScreen.swift similarity index 97% rename from HaloTV/Views/Player/TVPlayerScreen.swift rename to FlaroTV/Views/Player/TVPlayerScreen.swift index 0cc54ec..cc9c153 100644 --- a/HaloTV/Views/Player/TVPlayerScreen.swift +++ b/FlaroTV/Views/Player/TVPlayerScreen.swift @@ -1,6 +1,6 @@ import SwiftUI -import HaloDesign -import HaloPlayback +import FlaroDesign +import FlaroPlayback import MediaKit /// Der Player auf dem Fernseher. @@ -14,7 +14,7 @@ import MediaKit struct TVPlayerScreen: View { let request: PlaybackRequest - @Environment(HaloSession.self) private var session + @Environment(FlaroSession.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/HaloTV/Views/Player/TVTrackMenuBuilder.swift b/FlaroTV/Views/Player/TVTrackMenuBuilder.swift similarity index 99% rename from HaloTV/Views/Player/TVTrackMenuBuilder.swift rename to FlaroTV/Views/Player/TVTrackMenuBuilder.swift index 08de4a6..c0615b4 100644 --- a/HaloTV/Views/Player/TVTrackMenuBuilder.swift +++ b/FlaroTV/Views/Player/TVTrackMenuBuilder.swift @@ -1,6 +1,6 @@ import AVKit import UIKit -import HaloPlayback +import FlaroPlayback /// Baut aus unseren Spurlisten die Menüs für Apples Transportleiste. /// diff --git a/HaloTV/Views/Search/TVSearchView.swift b/FlaroTV/Views/Search/TVSearchView.swift similarity index 83% rename from HaloTV/Views/Search/TVSearchView.swift rename to FlaroTV/Views/Search/TVSearchView.swift index d9e7388..e8b290f 100644 --- a/HaloTV/Views/Search/TVSearchView.swift +++ b/FlaroTV/Views/Search/TVSearchView.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign 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(HaloSession.self) private var session + @Environment(FlaroSession.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: HaloSpacing.section) { + LazyVStack(alignment: .leading, spacing: FlaroSpacing.section) { ForEach(feed.hubs) { reihe in TVMediaRow( row: reihe, @@ -57,7 +57,7 @@ struct TVSearchView: View { ) } } - .padding(.vertical, HaloSpacing.section) + .padding(.vertical, FlaroSpacing.section) } .scrollClipDisabled() .scrollIndicators(.never) @@ -73,20 +73,20 @@ struct TVSearchView: View { if feed.recent.isEmpty { hinweis("search.hint") } else { - VStack(alignment: .leading, spacing: HaloSpacing.regular) { + VStack(alignment: .leading, spacing: FlaroSpacing.regular) { Text("search.recent") - .font(.haloRowHeader) - .foregroundStyle(Color.haloTextPrimary) + .font(.flaroRowHeader) + .foregroundStyle(Color.flaroTextPrimary) ForEach(feed.recent, id: \.self) { eintrag in Button(eintrag) { text = eintrag } } Button("search.forgetRecent", role: .destructive) { feed.forgetRecent() } - .padding(.top, HaloSpacing.regular) + .padding(.top, FlaroSpacing.regular) } .frame(maxWidth: 700, alignment: .leading) - .padding(HaloSpacing.section) + .padding(FlaroSpacing.section) } } @@ -96,9 +96,9 @@ struct TVSearchView: View { private func hinweis(_ text: LocalizedStringKey) -> some View { Text(text) - .font(.haloBody) - .foregroundStyle(Color.haloTextMuted) + .font(.flaroBody) + .foregroundStyle(Color.flaroTextMuted) .frame(maxWidth: 700) - .padding(HaloSpacing.section) + .padding(FlaroSpacing.section) } } diff --git a/HaloTV/Views/SignIn/TVSignInView.swift b/FlaroTV/Views/SignIn/TVSignInView.swift similarity index 77% rename from HaloTV/Views/SignIn/TVSignInView.swift rename to FlaroTV/Views/SignIn/TVSignInView.swift index 31ddccc..2220de4 100644 --- a/HaloTV/Views/SignIn/TVSignInView.swift +++ b/FlaroTV/Views/SignIn/TVSignInView.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign 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(HaloSession.self) private var session + @Environment(FlaroSession.self) private var session @State private var model: JellyfinSignInModel? var body: some View { ZStack { - Color.haloCanvas.ignoresSafeArea() + Color.flaroCanvas.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: HaloSpacing.section) { - Text(Branding.appName).font(.haloHero) - Text("signIn.tagline").font(.haloBody).foregroundStyle(Color.haloTextMuted) + VStack(alignment: .leading, spacing: FlaroSpacing.section) { + Text(Branding.appName).font(.flaroHero) + Text("signIn.tagline").font(.flaroBody).foregroundStyle(Color.flaroTextMuted) switch model.step { case .address: @@ -73,10 +73,10 @@ struct TVSignInView: View { } if let fehler = model.errorMessage { - Text(fehler).font(.haloBody).foregroundStyle(Color.haloDestructive) + Text(fehler).font(.flaroBody).foregroundStyle(Color.flaroDestructive) } } - .padding(HaloSpacing.section) + .padding(FlaroSpacing.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: HaloSpacing.regular) { - Text("signIn.jellyfin.addressPrompt").font(.haloRowHeader) + return VStack(alignment: .leading, spacing: FlaroSpacing.regular) { + Text("signIn.jellyfin.addressPrompt").font(.flaroRowHeader) // 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) - .haloPlainEntry(isAddress: true) + .flaroPlainEntry(isAddress: true) Text("signIn.jellyfin.addressHint") - .font(.haloCaption).foregroundStyle(Color.haloTextMuted) + .font(.flaroCaption).foregroundStyle(Color.flaroTextMuted) 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: HaloSpacing.regular) { + VStack(alignment: .leading, spacing: FlaroSpacing.regular) { if let name = model.serverName { - Text(name).font(.haloRowHeader) + Text(name).font(.flaroRowHeader) } // **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(.haloBody) + Text("signIn.jellyfin.quickConnectHint").font(.flaroBody) Label("signIn.jellyfin.waitingForApproval", systemImage: "hourglass") - .font(.haloCaption).foregroundStyle(Color.haloTextMuted) + .font(.flaroCaption).foregroundStyle(Color.flaroTextMuted) - HStack(spacing: HaloSpacing.regular) { + HStack(spacing: FlaroSpacing.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: HaloSpacing.regular) { + return VStack(alignment: .leading, spacing: FlaroSpacing.regular) { if let name = model.serverName { - Text(name).font(.haloRowHeader) + Text(name).font(.flaroRowHeader) } TextField("signIn.jellyfin.userName", text: $model.userName) - .haloPlainEntry() + .flaroPlainEntry() SecureField("signIn.jellyfin.password", text: $model.password) Text("signIn.jellyfin.passwordNote") - .font(.haloCaption).foregroundStyle(Color.haloTextMuted) + .font(.flaroCaption).foregroundStyle(Color.flaroTextMuted) - HStack(spacing: HaloSpacing.regular) { + HStack(spacing: FlaroSpacing.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: HaloSpacing.regular) { + HStack(spacing: FlaroSpacing.regular) { ProgressView() - Text(text).font(.haloBody) + Text(text).font(.flaroBody) } } } diff --git a/HaloTV/Views/TVDeepLink.swift b/FlaroTV/Views/TVDeepLink.swift similarity index 88% rename from HaloTV/Views/TVDeepLink.swift rename to FlaroTV/Views/TVDeepLink.swift index efddeaf..23e04da 100644 --- a/HaloTV/Views/TVDeepLink.swift +++ b/FlaroTV/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 … halo://play/`. +/// `xcrun simctl openurl … flaro://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 = "halo" + static let scheme = "flaro" init?(_ url: URL) { guard url.scheme == Self.scheme else { return nil } - // **`host` und nicht `pathComponents[0]`.** Bei `halo://play/42` + // **`host` und nicht `pathComponents[0]`.** Bei `flaro://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/HaloTV/Views/TVRootView.swift b/FlaroTV/Views/TVRootView.swift similarity index 88% rename from HaloTV/Views/TVRootView.swift rename to FlaroTV/Views/TVRootView.swift index 501b082..76397e5 100644 --- a/HaloTV/Views/TVRootView.swift +++ b/FlaroTV/Views/TVRootView.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign /// Was auf dem Fernseher zu sehen ist. /// @@ -10,7 +10,7 @@ import HaloDesign /// bestehenden — ein `#if` wäre kein Zweig gewesen, sondern ein zweiter Rumpf /// in derselben Datei. struct TVRootView: View { - @Environment(HaloSession.self) private var session + @Environment(FlaroSession.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.haloCanvas.ignoresSafeArea() + Color.flaroCanvas.ignoresSafeArea() switch session.phase { case .launching: @@ -82,16 +82,16 @@ struct TVRootView: View { } private func verbinden(mit name: String) -> some View { - VStack(spacing: HaloSpacing.regular) { + VStack(spacing: FlaroSpacing.regular) { ProgressView() - Text(name).font(.haloRowHeader).foregroundStyle(.white) + Text(name).font(.flaroRowHeader).foregroundStyle(.white) } } private func fehlgeschlagen(_ meldung: String) -> some View { - VStack(spacing: HaloSpacing.regular) { - Text(meldung).font(.haloBody).foregroundStyle(.white) - HStack(spacing: HaloSpacing.regular) { + VStack(spacing: FlaroSpacing.regular) { + Text(meldung).font(.flaroBody).foregroundStyle(.white) + HStack(spacing: FlaroSpacing.regular) { Button("action.retry") { Task { await session.retry() } } Button("action.signOut") { session.signOut() } } diff --git a/HaloTV/Views/TVShell.swift b/FlaroTV/Views/TVShell.swift similarity index 96% rename from HaloTV/Views/TVShell.swift rename to FlaroTV/Views/TVShell.swift index 21574a0..7df07fb 100644 --- a/HaloTV/Views/TVShell.swift +++ b/FlaroTV/Views/TVShell.swift @@ -1,5 +1,5 @@ import SwiftUI -import HaloDesign +import FlaroDesign import MediaKit /// Start, die Mediatheken und die Suche nebeneinander. @@ -14,7 +14,7 @@ import MediaKit struct TVShell: View { @Binding var deepLinkTarget: MediaRoute? - @Environment(HaloSession.self) private var session + @Environment(FlaroSession.self) private var session /// Welcher Reiter offen ist. /// diff --git a/HaloTopShelf/HaloTopShelf.entitlements b/FlaroTopShelf/FlaroTopShelf.entitlements similarity index 82% rename from HaloTopShelf/HaloTopShelf.entitlements rename to FlaroTopShelf/FlaroTopShelf.entitlements index 4140325..b9a5ad2 100644 --- a/HaloTopShelf/HaloTopShelf.entitlements +++ b/FlaroTopShelf/FlaroTopShelf.entitlements @@ -4,7 +4,7 @@ com.apple.security.application-groups - group.com.scarriffleservices.halo + group.com.scarriffleservices.flaro diff --git a/HaloTopShelf/Info.plist b/FlaroTopShelf/Info.plist similarity index 97% rename from HaloTopShelf/Info.plist rename to FlaroTopShelf/Info.plist index 5057614..8716d45 100644 --- a/HaloTopShelf/Info.plist +++ b/FlaroTopShelf/Info.plist @@ -5,7 +5,7 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName - Halo + Flaro CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier diff --git a/HaloTopShelf/TopShelfIdentity.swift b/FlaroTopShelf/TopShelfIdentity.swift similarity index 89% rename from HaloTopShelf/TopShelfIdentity.swift rename to FlaroTopShelf/TopShelfIdentity.swift index 22c42d2..507c202 100644 --- a/HaloTopShelf/TopShelfIdentity.swift +++ b/FlaroTopShelf/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.halo" + static let group = "group.com.scarriffleservices.flaro" /// Muss mit `CFBundleURLSchemes` in der Info.plist des Fernseh-Ziels /// übereinstimmen. - static let scheme = "halo" + static let scheme = "flaro" static func playURL(for id: String) -> URL { URL(string: "\(scheme)://play/\(id)") ?? URL(string: "\(scheme)://")! diff --git a/HaloTopShelf/TopShelfProvider.swift b/FlaroTopShelf/TopShelfProvider.swift similarity index 100% rename from HaloTopShelf/TopShelfProvider.swift rename to FlaroTopShelf/TopShelfProvider.swift diff --git a/HaloUITests/LayoutSnapshots.swift b/FlaroUITests/LayoutSnapshots.swift similarity index 94% rename from HaloUITests/LayoutSnapshots.swift rename to FlaroUITests/LayoutSnapshots.swift index 982cdd8..c9cf0f1 100644 --- a/HaloUITests/LayoutSnapshots.swift +++ b/FlaroUITests/LayoutSnapshots.swift @@ -42,8 +42,8 @@ final class LayoutSnapshots: XCTestCase { func testPushedSettingsScreen() throws { let app = XCUIApplication() app.launchArguments = [ - "-HaloStubServer", "http://127.0.0.1:8096", - "-halo.navigation.placement", "sidebar", + "-FlaroStubServer", "http://127.0.0.1:8096", + "-flaro.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 = [ - "-HaloStubServer", "http://127.0.0.1:8096", - "-halo.navigation.placement", "sidebar", + "-FlaroStubServer", "http://127.0.0.1:8096", + "-flaro.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 = ["-HaloStubServer", "http://127.0.0.1:8096"] + app.launchArguments = ["-FlaroStubServer", "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 = [ - "-HaloStubServer", "http://127.0.0.1:8096", - "-halo.navigation.placement", "sidebar", + "-FlaroStubServer", "http://127.0.0.1:8096", + "-flaro.navigation.placement", "sidebar", ] app.launch() diff --git a/HaloUITests/PlayerSheets.swift b/FlaroUITests/PlayerSheets.swift similarity index 95% rename from HaloUITests/PlayerSheets.swift rename to FlaroUITests/PlayerSheets.swift index 94bfff5..fd8ff6d 100644 --- a/HaloUITests/PlayerSheets.swift +++ b/FlaroUITests/PlayerSheets.swift @@ -10,7 +10,7 @@ import XCTest final class PlayerSheets: XCTestCase { func testQualitySheetOpens() { let app = XCUIApplication() - app.launchArguments = ["-HaloStubServer", "http://127.0.0.1:8096"] + app.launchArguments = ["-FlaroStubServer", "http://127.0.0.1:8096"] app.launch() XCTAssertTrue(app.staticTexts["Weiterschauen"].waitForExistence(timeout: 30)) diff --git a/LICENSES.md b/LICENSES.md index 025b544..ed10845 100644 --- a/LICENSES.md +++ b/LICENSES.md @@ -5,7 +5,7 @@ Dieses Repo trägt **zwei** Lizenzen. Welche gilt, hängt vom Verzeichnis ab. | Was | Lizenz | Datei | |---|---|---| | `server/`, `web/`, `Tools/`, `docs/` | **GPL-2.0-only** | [`LICENSE`](LICENSE) | -| `Halo/`, `HaloTV/`, `HaloTopShelf/`, `HaloUITests/`, `DownloadWidget/`, `Packages/HaloKit/` | **MPL-2.0** | [`LICENSE-MPL-2.0`](LICENSE-MPL-2.0) | +| `Flaro/`, `FlaroTV/`, `FlaroTopShelf/`, `FlaroUITests/`, `DownloadWidget/`, `Packages/FlaroKit/` | **MPL-2.0** | [`LICENSE-MPL-2.0`](LICENSE-MPL-2.0) | ## Warum zweierlei diff --git a/Packages/HaloKit/Package.swift b/Packages/FlaroKit/Package.swift similarity index 73% rename from Packages/HaloKit/Package.swift rename to Packages/FlaroKit/Package.swift index 15d432d..1b43314 100644 --- a/Packages/HaloKit/Package.swift +++ b/Packages/FlaroKit/Package.swift @@ -2,21 +2,21 @@ import PackageDescription let package = Package( - name: "HaloKit", + name: "FlaroKit", // 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 - // Halo, tvOS für HaloTV. + // Flaro, tvOS für FlaroTV. platforms: [.iOS(.v26), .macOS(.v26), .tvOS(.v26)], products: [ .library(name: "MediaKit", targets: ["MediaKit"]), .library(name: "JellyfinKit", targets: ["JellyfinKit"]), - .library(name: "HaloDesign", targets: ["HaloDesign"]), - .library(name: "HaloPlayback", targets: ["HaloPlayback"]), - .library(name: "HaloDownloads", targets: ["HaloDownloads"]), + .library(name: "FlaroDesign", targets: ["FlaroDesign"]), + .library(name: "FlaroPlayback", targets: ["FlaroPlayback"]), + .library(name: "FlaroDownloads", targets: ["FlaroDownloads"]), ], 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: "HaloProbe", dependencies: ["MediaKit", "JellyfinKit"]), + .executableTarget(name: "FlaroProbe", 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: "HaloDesign", resources: [.process("Localizable.xcstrings")]), - .testTarget(name: "HaloDesignTests", dependencies: ["HaloDesign"]), + .target(name: "FlaroDesign", resources: [.process("Localizable.xcstrings")]), + .testTarget(name: "FlaroDesignTests", dependencies: ["FlaroDesign"]), // Die Wiedergabe-Abstraktion samt AVPlayer-Engine und der Entscheidung // direkt / umpacken / umrechnen. - .target(name: "HaloPlayback", dependencies: ["MediaKit"]), - .testTarget(name: "HaloPlaybackTests", dependencies: ["HaloPlayback"]), + .target(name: "FlaroPlayback", dependencies: ["MediaKit"]), + .testTarget(name: "FlaroPlaybackTests", dependencies: ["FlaroPlayback"]), // Warteschlange, Hintergrundübertragung, Offline-Bestand. - .target(name: "HaloDownloads", dependencies: ["MediaKit"], resources: [.process("Localizable.xcstrings")]), - .testTarget(name: "HaloDownloadsTests", dependencies: ["HaloDownloads"]), + .target(name: "FlaroDownloads", dependencies: ["MediaKit"], resources: [.process("Localizable.xcstrings")]), + .testTarget(name: "FlaroDownloadsTests", dependencies: ["FlaroDownloads"]), ] ) diff --git a/Packages/HaloKit/Sources/HaloDesign/Color/AccentEnvironment.swift b/Packages/FlaroKit/Sources/FlaroDesign/Color/AccentEnvironment.swift similarity index 65% rename from Packages/HaloKit/Sources/HaloDesign/Color/AccentEnvironment.swift rename to Packages/FlaroKit/Sources/FlaroDesign/Color/AccentEnvironment.swift index 7ddf118..d8fefa1 100644 --- a/Packages/HaloKit/Sources/HaloDesign/Color/AccentEnvironment.swift +++ b/Packages/FlaroKit/Sources/FlaroDesign/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 `HaloTheme`: Bausteine wie `WatchProgressBar` sollen sich in einer + /// auf `FlaroTheme`: 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 haloAccent: Color = AccentOption.storedAccentColor() + @Entry public var flaroAccent: Color = AccentOption.storedAccentColor() } extension View { /// Setzt die Akzentfarbe für diesen Teilbaum. /// - /// Wird einmal an der Wurzel aus `HaloTheme` gesetzt; darunter greift + /// Wird einmal an der Wurzel aus `FlaroTheme` gesetzt; darunter greift /// alles automatisch darauf zu. - public func haloAccent(_ color: Color) -> some View { - environment(\.haloAccent, color) + public func flaroAccent(_ color: Color) -> some View { + environment(\.flaroAccent, color) } - public func haloAccent(_ theme: HaloTheme) -> some View { - environment(\.haloAccent, theme.accentColor) + public func flaroAccent(_ theme: FlaroTheme) -> some View { + environment(\.flaroAccent, theme.accentColor) } } diff --git a/Packages/HaloKit/Sources/HaloDesign/Color/AccentOption.swift b/Packages/FlaroKit/Sources/FlaroDesign/Color/AccentOption.swift similarity index 92% rename from Packages/HaloKit/Sources/HaloDesign/Color/AccentOption.swift rename to Packages/FlaroKit/Sources/FlaroDesign/Color/AccentOption.swift index e44567a..a07e139 100644 --- a/Packages/HaloKit/Sources/HaloDesign/Color/AccentOption.swift +++ b/Packages/FlaroKit/Sources/FlaroDesign/Color/AccentOption.swift @@ -3,7 +3,7 @@ import SwiftUI /// Eine wählbare Akzentfarbe. /// -/// Die kuratierten Werte sind so gewählt, dass sie auf `HaloColor.canvas` +/// Die kuratierten Werte sind so gewählt, dass sie auf `FlaroColor.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 `HaloTheme`, weil zwei Stellen sie brauchen: das Theme + /// Hier statt in `FlaroTheme`, 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 = "halo.accent.identifier" - static let customHex = "halo.accent.customHex" + static let identifier = "flaro.accent.identifier" + static let customHex = "flaro.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: HaloColor.canvas).swiftUIColor + Contrast.legible(stored(in: defaults).color, on: FlaroColor.canvas).swiftUIColor } } diff --git a/Packages/HaloKit/Sources/HaloDesign/Color/Contrast.swift b/Packages/FlaroKit/Sources/FlaroDesign/Color/Contrast.swift similarity index 97% rename from Packages/HaloKit/Sources/HaloDesign/Color/Contrast.swift rename to Packages/FlaroKit/Sources/FlaroDesign/Color/Contrast.swift index 7a0609f..49f1035 100644 --- a/Packages/HaloKit/Sources/HaloDesign/Color/Contrast.swift +++ b/Packages/FlaroKit/Sources/FlaroDesign/Color/Contrast.swift @@ -2,7 +2,7 @@ import Foundation /// Kontrastrechnung nach WCAG 2.1. /// -/// Gebraucht wird sie für die eigene Akzentfarbe: Halo lässt jede Farbe zu, +/// Gebraucht wird sie für die eigene Akzentfarbe: Flaro 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/HaloKit/Sources/HaloDesign/Color/HaloColor.swift b/Packages/FlaroKit/Sources/FlaroDesign/Color/FlaroColor.swift similarity index 59% rename from Packages/HaloKit/Sources/HaloDesign/Color/HaloColor.swift rename to Packages/FlaroKit/Sources/FlaroDesign/Color/FlaroColor.swift index 1b2f169..5cdd564 100644 --- a/Packages/HaloKit/Sources/HaloDesign/Color/HaloColor.swift +++ b/Packages/FlaroKit/Sources/FlaroDesign/Color/FlaroColor.swift @@ -2,10 +2,10 @@ import SwiftUI /// Die Flächen- und Schriftfarben der App. /// -/// Halo kennt nur den dunklen Modus — es gibt deshalb bewusst keine +/// Flaro 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 `HaloTheme`. -public enum HaloColor { +/// sich zur Laufzeit ändert, ist der Akzent; er kommt aus `FlaroTheme`. +public enum FlaroColor { // Flächen, von hinten nach vorn gestaffelt. /// Der Seitenhintergrund. public static let canvas = RGB(hex: 0x0B0B0D) @@ -28,18 +28,18 @@ public enum HaloColor { } extension Color { - 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 + public static let flaroCanvas = FlaroColor.canvas.swiftUIColor + public static let flaroSurface = FlaroColor.surface.swiftUIColor + public static let flaroElevated = FlaroColor.elevated.swiftUIColor + public static let flaroPlaceholder = FlaroColor.placeholder.swiftUIColor + public static let flaroTextPrimary = FlaroColor.textPrimary.swiftUIColor + public static let flaroTextSecondary = FlaroColor.textSecondary.swiftUIColor + public static let flaroTextMuted = FlaroColor.textMuted.swiftUIColor + public static let flaroDestructive = FlaroColor.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 haloSeparator = Color.white.opacity(0.10) + public static let flaroSeparator = Color.white.opacity(0.10) /// Die Abdunklung hinter der ausgefahrenen Seitenleiste. - public static let haloScrim = Color.black.opacity(0.55) + public static let flaroScrim = Color.black.opacity(0.55) } diff --git a/Packages/HaloKit/Sources/HaloDesign/Color/HSB.swift b/Packages/FlaroKit/Sources/FlaroDesign/Color/HSB.swift similarity index 100% rename from Packages/HaloKit/Sources/HaloDesign/Color/HSB.swift rename to Packages/FlaroKit/Sources/FlaroDesign/Color/HSB.swift diff --git a/Packages/HaloKit/Sources/HaloDesign/Color/RGB.swift b/Packages/FlaroKit/Sources/FlaroDesign/Color/RGB.swift similarity index 100% rename from Packages/HaloKit/Sources/HaloDesign/Color/RGB.swift rename to Packages/FlaroKit/Sources/FlaroDesign/Color/RGB.swift diff --git a/Packages/HaloKit/Sources/HaloDesign/Components/ArtworkLoader.swift b/Packages/FlaroKit/Sources/FlaroDesign/Components/ArtworkLoader.swift similarity index 100% rename from Packages/HaloKit/Sources/HaloDesign/Components/ArtworkLoader.swift rename to Packages/FlaroKit/Sources/FlaroDesign/Components/ArtworkLoader.swift diff --git a/Packages/HaloKit/Sources/HaloDesign/Components/HaloArtwork.swift b/Packages/FlaroKit/Sources/FlaroDesign/Components/FlaroArtwork.swift similarity index 96% rename from Packages/HaloKit/Sources/HaloDesign/Components/HaloArtwork.swift rename to Packages/FlaroKit/Sources/FlaroDesign/Components/FlaroArtwork.swift index bf6e424..d4e0e7d 100644 --- a/Packages/HaloKit/Sources/HaloDesign/Components/HaloArtwork.swift +++ b/Packages/FlaroKit/Sources/FlaroDesign/Components/FlaroArtwork.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 HaloArtwork: View { +public struct FlaroArtwork: View { /// Die Adressen, der Reihe nach probiert. /// /// **Warum mehrere.** Eine Folge hat selten ein eigenes Querformatbild, @@ -90,9 +90,9 @@ public struct HaloArtwork: View { @ViewBuilder private var placeholder: some View { if fillsFrame { - Rectangle().fill(Color.haloPlaceholder) + Rectangle().fill(Color.flaroPlaceholder) } else { - Rectangle().fill(Color.haloPlaceholder).aspectRatio(aspectRatio, contentMode: .fit) + Rectangle().fill(Color.flaroPlaceholder).aspectRatio(aspectRatio, contentMode: .fit) } } @@ -124,7 +124,7 @@ public struct HaloArtwork: View { // mehr Lärm als Hilfe. Das Symbol sagt genug. Image(systemName: fallbackSymbol) .font(.title2) - .foregroundStyle(Color.haloTextMuted) + .foregroundStyle(Color.flaroTextMuted) } else { ShimmerPlaceholder() } diff --git a/Packages/HaloKit/Sources/HaloDesign/Components/HeroBanner.swift b/Packages/FlaroKit/Sources/FlaroDesign/Components/HeroBanner.swift similarity index 91% rename from Packages/HaloKit/Sources/HaloDesign/Components/HeroBanner.swift rename to Packages/FlaroKit/Sources/FlaroDesign/Components/HeroBanner.swift index 9a11321..c863d7c 100644 --- a/Packages/HaloKit/Sources/HaloDesign/Components/HeroBanner.swift +++ b/Packages/FlaroKit/Sources/FlaroDesign/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 = HaloAspectRatio.hero, + aspectRatio: CGFloat = FlaroAspectRatio.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 `HaloArtwork` wie zuvor: die zweite + /// Ohne Wechsel ist es genau ein `FlaroArtwork` wie zuvor: die zweite /// Ebene entsteht nur, wenn jemand eine vorige Adresse mitgibt. @ViewBuilder private var bild: some View { if outgoingArtworkURLs.isEmpty { - HaloArtwork(urls: artworkURLs, aspectRatio: aspectRatio, fillsFrame: fillsAvailableSpace) + FlaroArtwork(urls: artworkURLs, aspectRatio: aspectRatio, fillsFrame: fillsAvailableSpace) } else { ZStack { - HaloArtwork(urls: outgoingArtworkURLs, aspectRatio: aspectRatio, fillsFrame: fillsAvailableSpace) - HaloArtwork(urls: artworkURLs, aspectRatio: aspectRatio, fillsFrame: fillsAvailableSpace) + FlaroArtwork(urls: outgoingArtworkURLs, aspectRatio: aspectRatio, fillsFrame: fillsAvailableSpace) + FlaroArtwork(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.haloCanvas.opacity(0.75), location: 0.45), - .init(color: Color.haloCanvas, location: 1), + .init(color: Color.flaroCanvas.opacity(0.75), location: 0.45), + .init(color: Color.flaroCanvas, location: 1), ], startPoint: .top, endPoint: .bottom @@ -250,7 +250,7 @@ public struct HeroBanner: View { logo: PlatformImage?, scale: CGFloat ) -> some View { - VStack(alignment: .leading, spacing: HaloSpacing.snug * scale) { + VStack(alignment: .leading, spacing: FlaroSpacing.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.haloTextPrimary) + .foregroundStyle(Color.flaroTextPrimary) .lineLimit(2) } if let metadataContent { metadataContent .font(.system(size: 12 * scale)) - .foregroundStyle(Color.haloTextSecondary) + .foregroundStyle(Color.flaroTextSecondary) } else if let metadata { Text(metadata) .font(.system(size: 12 * scale)) - .foregroundStyle(Color.haloTextSecondary) + .foregroundStyle(Color.flaroTextSecondary) } if let summary { Text(summary) .font(.system(size: 12 * scale)) - .foregroundStyle(Color.haloTextSecondary) + .foregroundStyle(Color.flaroTextSecondary) .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: HaloSpacing.regular) { + HStack(spacing: FlaroSpacing.regular) { actions } - .padding(.top, HaloSpacing.tight) + .padding(.top, FlaroSpacing.tight) } - .padding(.horizontal, HaloSpacing.screenMargin * scale) - .padding(.bottom, HaloSpacing.loose * scale) + .padding(.horizontal, FlaroSpacing.screenMargin * scale) + .padding(.bottom, FlaroSpacing.loose * scale) } } diff --git a/Packages/HaloKit/Sources/HaloDesign/Components/LandscapeCard.swift b/Packages/FlaroKit/Sources/FlaroDesign/Components/LandscapeCard.swift similarity index 73% rename from Packages/HaloKit/Sources/HaloDesign/Components/LandscapeCard.swift rename to Packages/FlaroKit/Sources/FlaroDesign/Components/LandscapeCard.swift index e257a87..5034819 100644 --- a/Packages/HaloKit/Sources/HaloDesign/Components/LandscapeCard.swift +++ b/Packages/FlaroKit/Sources/FlaroDesign/Components/LandscapeCard.swift @@ -20,24 +20,24 @@ public struct LandscapeCard: View { } public var body: some View { - VStack(alignment: .leading, spacing: HaloSpacing.snug) { - HaloArtwork(url: artworkURL, aspectRatio: Self.aspectRatio, fallbackSymbol: "play.rectangle") + VStack(alignment: .leading, spacing: FlaroSpacing.snug) { + FlaroArtwork(url: artworkURL, aspectRatio: Self.aspectRatio, fallbackSymbol: "play.rectangle") .overlay(alignment: .bottom) { if let progress { WatchProgressBar(fraction: progress) } } - .clipShape(.rect(cornerRadius: HaloRadius.card)) + .clipShape(.rect(cornerRadius: FlaroRadius.card)) VStack(alignment: .leading, spacing: 2) { Text(title) - .font(.haloCardTitle) - .foregroundStyle(Color.haloTextPrimary) + .font(.flaroCardTitle) + .foregroundStyle(Color.flaroTextPrimary) .lineLimit(1) if let subtitle { Text(subtitle) - .font(.haloCaption) - .foregroundStyle(Color.haloTextMuted) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextMuted) .lineLimit(1) } } diff --git a/Packages/HaloKit/Sources/HaloDesign/Components/PlaceholderCard.swift b/Packages/FlaroKit/Sources/FlaroDesign/Components/PlaceholderCard.swift similarity index 89% rename from Packages/HaloKit/Sources/HaloDesign/Components/PlaceholderCard.swift rename to Packages/FlaroKit/Sources/FlaroDesign/Components/PlaceholderCard.swift index b706b87..8364e57 100644 --- a/Packages/HaloKit/Sources/HaloDesign/Components/PlaceholderCard.swift +++ b/Packages/FlaroKit/Sources/FlaroDesign/Components/PlaceholderCard.swift @@ -30,18 +30,18 @@ public struct PlaceholderCard: View { } public var body: some View { - VStack(alignment: .leading, spacing: HaloSpacing.snug) { - RoundedRectangle(cornerRadius: HaloRadius.card) - .fill(Color.haloElevated) + VStack(alignment: .leading, spacing: FlaroSpacing.snug) { + RoundedRectangle(cornerRadius: FlaroRadius.card) + .fill(Color.flaroElevated) .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.haloElevated) + .fill(Color.flaroElevated) .frame(height: 10) RoundedRectangle(cornerRadius: 3) - .fill(Color.haloElevated) + .fill(Color.flaroElevated) .frame(width: 32, height: 8) } .opacity(isBright ? 0.85 : 0.45) diff --git a/Packages/HaloKit/Sources/HaloDesign/Components/PosterCard.swift b/Packages/FlaroKit/Sources/FlaroDesign/Components/PosterCard.swift similarity index 74% rename from Packages/HaloKit/Sources/HaloDesign/Components/PosterCard.swift rename to Packages/FlaroKit/Sources/FlaroDesign/Components/PosterCard.swift index c643501..6c7da20 100644 --- a/Packages/HaloKit/Sources/HaloDesign/Components/PosterCard.swift +++ b/Packages/FlaroKit/Sources/FlaroDesign/Components/PosterCard.swift @@ -19,25 +19,25 @@ public struct PosterCard: View { } public var body: some View { - VStack(alignment: .leading, spacing: HaloSpacing.snug) { - HaloArtwork(url: artworkURL, aspectRatio: Self.aspectRatio) - .clipShape(.rect(cornerRadius: HaloRadius.card)) + VStack(alignment: .leading, spacing: FlaroSpacing.snug) { + FlaroArtwork(url: artworkURL, aspectRatio: Self.aspectRatio) + .clipShape(.rect(cornerRadius: FlaroRadius.card)) .overlay(alignment: .bottom) { if let progress { WatchProgressBar(fraction: progress) } } - .clipShape(.rect(cornerRadius: HaloRadius.card)) + .clipShape(.rect(cornerRadius: FlaroRadius.card)) VStack(alignment: .leading, spacing: 2) { Text(title) - .font(.haloCardTitle) - .foregroundStyle(Color.haloTextPrimary) + .font(.flaroCardTitle) + .foregroundStyle(Color.flaroTextPrimary) .lineLimit(1) if let subtitle { Text(subtitle) - .font(.haloCaption) - .foregroundStyle(Color.haloTextMuted) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextMuted) .lineLimit(1) } } diff --git a/Packages/HaloKit/Sources/HaloDesign/Components/ShimmerPlaceholder.swift b/Packages/FlaroKit/Sources/FlaroDesign/Components/ShimmerPlaceholder.swift similarity index 97% rename from Packages/HaloKit/Sources/HaloDesign/Components/ShimmerPlaceholder.swift rename to Packages/FlaroKit/Sources/FlaroDesign/Components/ShimmerPlaceholder.swift index f9cbc3c..dc5a943 100644 --- a/Packages/HaloKit/Sources/HaloDesign/Components/ShimmerPlaceholder.swift +++ b/Packages/FlaroKit/Sources/FlaroDesign/Components/ShimmerPlaceholder.swift @@ -15,7 +15,7 @@ public struct ShimmerPlaceholder: View { public var body: some View { Rectangle() - .fill(Color.haloPlaceholder) + .fill(Color.flaroPlaceholder) .overlay { if !reduceMotion { GeometryReader { proxy in diff --git a/Packages/HaloKit/Sources/HaloDesign/Components/TVCards.swift b/Packages/FlaroKit/Sources/FlaroDesign/Components/TVCards.swift similarity index 90% rename from Packages/HaloKit/Sources/HaloDesign/Components/TVCards.swift rename to Packages/FlaroKit/Sources/FlaroDesign/Components/TVCards.swift index a1c2710..9126456 100644 --- a/Packages/HaloKit/Sources/HaloDesign/Components/TVCards.swift +++ b/Packages/FlaroKit/Sources/FlaroDesign/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 HaloDesign und nicht im Fernseh-Ziel, aus demselben Grund wie +/// Liegt in FlaroDesign 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: HaloAspectRatio.landscape, + aspectRatio: FlaroAspectRatio.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: HaloSpacing.snug) { + VStack(alignment: .leading, spacing: FlaroSpacing.snug) { Button(action: action) { - HaloArtwork(url: artworkURL, aspectRatio: aspectRatio) + FlaroArtwork(url: artworkURL, aspectRatio: aspectRatio) .overlay(alignment: .bottom) { if let progress { WatchProgressBar(fraction: progress) } } - .clipShape(.rect(cornerRadius: HaloRadius.card)) + .clipShape(.rect(cornerRadius: FlaroRadius.card)) } .buttonStyle(.card) .focused($isFocused) @@ -143,13 +143,13 @@ private struct TVCard: View { // Metern eine Textwand. VStack(alignment: .leading, spacing: 2) { Text(title) - .font(.haloCardTitle) - .foregroundStyle(Color.haloTextPrimary) + .font(.flaroCardTitle) + .foregroundStyle(Color.flaroTextPrimary) .lineLimit(1) if let subtitle { Text(subtitle) - .font(.haloCaption) - .foregroundStyle(Color.haloTextMuted) + .font(.flaroCaption) + .foregroundStyle(Color.flaroTextMuted) .lineLimit(1) } } diff --git a/Packages/HaloKit/Sources/HaloDesign/Components/WatchProgressBar.swift b/Packages/FlaroKit/Sources/FlaroDesign/Components/WatchProgressBar.swift similarity index 94% rename from Packages/HaloKit/Sources/HaloDesign/Components/WatchProgressBar.swift rename to Packages/FlaroKit/Sources/FlaroDesign/Components/WatchProgressBar.swift index 31b026c..709f3f3 100644 --- a/Packages/HaloKit/Sources/HaloDesign/Components/WatchProgressBar.swift +++ b/Packages/FlaroKit/Sources/FlaroDesign/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(\.haloAccent) private var accent + @Environment(\.flaroAccent) private var accent public init(fraction: Double) { self.fraction = fraction.clamped() diff --git a/Packages/HaloKit/Sources/HaloDesign/HaloFont.swift b/Packages/FlaroKit/Sources/FlaroDesign/FlaroFont.swift similarity index 82% rename from Packages/HaloKit/Sources/HaloDesign/HaloFont.swift rename to Packages/FlaroKit/Sources/FlaroDesign/FlaroFont.swift index 964cb77..9abe561 100644 --- a/Packages/HaloKit/Sources/HaloDesign/HaloFont.swift +++ b/Packages/FlaroKit/Sources/FlaroDesign/FlaroFont.swift @@ -24,17 +24,17 @@ import SwiftUI extension Font { #if os(macOS) /// Der Titel im Aufmacher-Bild. - public static let haloHero = Font.system(size: 34, weight: .bold) + public static let flaroHero = Font.system(size: 34, weight: .bold) /// Titel auf Detailseiten. - public static let haloTitle = Font.system(size: 22, weight: .semibold) + public static let flaroTitle = Font.system(size: 22, weight: .semibold) /// Überschrift einer Reihe auf der Startseite. - public static let haloRowHeader = Font.system(size: 17, weight: .semibold) + public static let flaroRowHeader = Font.system(size: 17, weight: .semibold) /// Titel unter einem Poster. - public static let haloCardTitle = Font.system(size: 15, weight: .medium) + public static let flaroCardTitle = Font.system(size: 15, weight: .medium) /// Fließtext, Beschreibungen. - public static let haloBody = Font.system(size: 17) + public static let flaroBody = Font.system(size: 17) /// Jahreszahl, Laufzeit, Auflösung — alles, was neben dem Titel steht. - public static let haloCaption = Font.system(size: 12) + public static let flaroCaption = 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 haloHero = Font.system(.title, design: .default, weight: .bold) + public static let flaroHero = Font.system(.title, design: .default, weight: .bold) /// Titel auf Detailseiten. - public static let haloTitle = Font.system(.title2, design: .default, weight: .semibold) + public static let flaroTitle = Font.system(.title2, design: .default, weight: .semibold) /// Überschrift einer Reihe auf der Startseite. - public static let haloRowHeader = Font.system(.headline, design: .default, weight: .semibold) + public static let flaroRowHeader = 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 haloCardTitle = Font.system(.caption, design: .default, weight: .medium) + public static let flaroCardTitle = Font.system(.caption, design: .default, weight: .medium) /// Fließtext, Beschreibungen. - public static let haloBody = Font.system(.body) + public static let flaroBody = Font.system(.body) /// Jahreszahl, Laufzeit, Auflösung — alles, was neben dem Titel steht. - public static let haloCaption = Font.system(.caption2) + public static let flaroCaption = Font.system(.caption2) #else /// Der Titel im Aufmacher-Bild. - public static let haloHero = Font.system(.largeTitle, design: .default, weight: .bold) + public static let flaroHero = Font.system(.largeTitle, design: .default, weight: .bold) /// Titel auf Detailseiten. - public static let haloTitle = Font.system(.title2, design: .default, weight: .semibold) + public static let flaroTitle = Font.system(.title2, design: .default, weight: .semibold) /// Überschrift einer Reihe auf der Startseite. - public static let haloRowHeader = Font.system(.headline, design: .default, weight: .semibold) + public static let flaroRowHeader = Font.system(.headline, design: .default, weight: .semibold) /// Titel unter einem Poster. - public static let haloCardTitle = Font.system(.subheadline, design: .default, weight: .medium) + public static let flaroCardTitle = Font.system(.subheadline, design: .default, weight: .medium) /// Fließtext, Beschreibungen. - public static let haloBody = Font.system(.body) + public static let flaroBody = Font.system(.body) /// Jahreszahl, Laufzeit, Auflösung — alles, was neben dem Titel steht. - public static let haloCaption = Font.system(.caption) + public static let flaroCaption = 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 HaloSpacing { +public enum FlaroSpacing { #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 HaloSpacing { /// „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 `HaloSpacing.screenMargin` nur die +/// Sicherheitsrand an — deshalb steht in `FlaroSpacing.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 HaloSafeArea { +public enum FlaroSafeArea { public static let tv = EdgeInsets(top: 60, leading: 80, bottom: 60, trailing: 80) } -public enum HaloRadius { +public enum FlaroRadius { /// Die Ecke einer Kachel. /// /// Auf dem Fernseher grösser: eine Kachel, die sich beim Fokus anhebt, @@ -155,7 +155,7 @@ public enum HaloRadius { /// 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 HaloAspectRatio { +public enum FlaroAspectRatio { /// Kinoplakate im Hochformat. public static let poster: CGFloat = 2.0 / 3.0 /// Szenenbilder und Hintergrundbilder. diff --git a/Packages/HaloKit/Sources/HaloDesign/HaloTheme.swift b/Packages/FlaroKit/Sources/FlaroDesign/FlaroTheme.swift similarity index 93% rename from Packages/HaloKit/Sources/HaloDesign/HaloTheme.swift rename to Packages/FlaroKit/Sources/FlaroDesign/FlaroTheme.swift index 7af89e8..7b55353 100644 --- a/Packages/HaloKit/Sources/HaloDesign/HaloTheme.swift +++ b/Packages/FlaroKit/Sources/FlaroDesign/FlaroTheme.swift @@ -7,7 +7,7 @@ import SwiftUI /// darauf zu achten. @MainActor @Observable -public final class HaloTheme { +public final class FlaroTheme { private let defaults: UserDefaults /// Was in den Einstellungen ausgewählt ist — unkorrigiert, damit die @@ -24,7 +24,7 @@ public final class HaloTheme { /// 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: HaloColor.canvas) + Contrast.legible(selection.color, on: FlaroColor.canvas) } public var accentColor: Color { accent.swiftUIColor } diff --git a/Packages/HaloKit/Sources/HaloDesign/GuideLayout.swift b/Packages/FlaroKit/Sources/FlaroDesign/GuideLayout.swift similarity index 100% rename from Packages/HaloKit/Sources/HaloDesign/GuideLayout.swift rename to Packages/FlaroKit/Sources/FlaroDesign/GuideLayout.swift diff --git a/Packages/HaloKit/Sources/HaloDesign/Localizable.xcstrings b/Packages/FlaroKit/Sources/FlaroDesign/Localizable.xcstrings similarity index 100% rename from Packages/HaloKit/Sources/HaloDesign/Localizable.xcstrings rename to Packages/FlaroKit/Sources/FlaroDesign/Localizable.xcstrings diff --git a/Packages/HaloKit/Sources/HaloDesign/MiniPlayerPlacement.swift b/Packages/FlaroKit/Sources/FlaroDesign/MiniPlayerPlacement.swift similarity index 97% rename from Packages/HaloKit/Sources/HaloDesign/MiniPlayerPlacement.swift rename to Packages/FlaroKit/Sources/FlaroDesign/MiniPlayerPlacement.swift index adce732..534a246 100644 --- a/Packages/HaloKit/Sources/HaloDesign/MiniPlayerPlacement.swift +++ b/Packages/FlaroKit/Sources/FlaroDesign/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 = HaloSpacing.regular) { + public init(bounds: CGSize, tile: CGSize, inset: CGFloat = FlaroSpacing.regular) { self.bounds = bounds self.tile = tile self.inset = inset diff --git a/Packages/HaloKit/Sources/HaloDesign/PlatformShims.swift b/Packages/FlaroKit/Sources/FlaroDesign/PlatformShims.swift similarity index 89% rename from Packages/HaloKit/Sources/HaloDesign/PlatformShims.swift rename to Packages/FlaroKit/Sources/FlaroDesign/PlatformShims.swift index 2bf99ef..6acb42e 100644 --- a/Packages/HaloKit/Sources/HaloDesign/PlatformShims.swift +++ b/Packages/FlaroKit/Sources/FlaroDesign/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 HaloPlatform { +public enum FlaroPlatform { /// 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 HaloPlatform { #elseif os(macOS) true #else - #error("HaloPlatform kennt diese Plattform nicht. Hier eintragen — nicht raten.") + #error("FlaroPlatform kennt diese Plattform nicht. Hier eintragen — nicht raten.") #endif }() @@ -60,7 +60,7 @@ public enum HaloPlatform { #elseif os(iOS) || os(macOS) false #else - #error("HaloPlatform kennt diese Plattform nicht. Hier eintragen — nicht raten.") + #error("FlaroPlatform kennt diese Plattform nicht. Hier eintragen — nicht raten.") #endif }() } @@ -68,7 +68,7 @@ public enum HaloPlatform { 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 haloInlineTitle() -> some View { + public func flaroInlineTitle() -> 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 haloMediumSheet() -> some View { + public func flaroMediumSheet() -> 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(HaloPlatform.isMac ? [.large] : [.medium]) + presentationDetents(FlaroPlatform.isMac ? [.large] : [.medium]) #endif } /// Dasselbe, aber auf Wunsch bis zur vollen Höhe aufziehbar. - public func haloResizableSheet() -> some View { + public func flaroResizableSheet() -> 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(HaloPlatform.isMac ? [.large] : [.medium, .large]) + presentationDetents(FlaroPlatform.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 haloForm() -> some View { + public func flaroForm() -> 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 haloPlainEntry(isAddress: Bool = false) -> some View { + public func flaroPlainEntry(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 haloClearToolbarBackground() -> some View { + public func flaroClearToolbarBackground() -> 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 HaloClipboard { +public enum FlaroClipboard { 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 HaloClipboard { extension ToolbarItemPlacement { /// Rechts in der Titelzeile. - public static var haloTrailing: ToolbarItemPlacement { + public static var flaroTrailing: ToolbarItemPlacement { #if os(iOS) || os(tvOS) .topBarTrailing #else @@ -195,7 +195,7 @@ extension ToolbarItemPlacement { } /// Links in der Titelzeile. - public static var haloLeading: ToolbarItemPlacement { + public static var flaroLeading: ToolbarItemPlacement { #if os(iOS) || os(tvOS) .topBarLeading #else diff --git a/Packages/HaloKit/Sources/HaloDownloads/DownloadRate.swift b/Packages/FlaroKit/Sources/FlaroDownloads/DownloadRate.swift similarity index 100% rename from Packages/HaloKit/Sources/HaloDownloads/DownloadRate.swift rename to Packages/FlaroKit/Sources/FlaroDownloads/DownloadRate.swift diff --git a/Packages/HaloKit/Sources/HaloDownloads/DownloadState.swift b/Packages/FlaroKit/Sources/FlaroDownloads/DownloadState.swift similarity index 100% rename from Packages/HaloKit/Sources/HaloDownloads/DownloadState.swift rename to Packages/FlaroKit/Sources/FlaroDownloads/DownloadState.swift diff --git a/Packages/HaloKit/Sources/HaloDownloads/Engine/DownloadActivityPresenter.swift b/Packages/FlaroKit/Sources/FlaroDownloads/Engine/DownloadActivityPresenter.swift similarity index 100% rename from Packages/HaloKit/Sources/HaloDownloads/Engine/DownloadActivityPresenter.swift rename to Packages/FlaroKit/Sources/FlaroDownloads/Engine/DownloadActivityPresenter.swift diff --git a/Packages/HaloKit/Sources/HaloDownloads/Engine/DownloadCoordinator.swift b/Packages/FlaroKit/Sources/FlaroDownloads/Engine/DownloadCoordinator.swift similarity index 98% rename from Packages/HaloKit/Sources/HaloDownloads/Engine/DownloadCoordinator.swift rename to Packages/FlaroKit/Sources/FlaroDownloads/Engine/DownloadCoordinator.swift index 3cf9ab6..f0f3a96 100644 --- a/Packages/HaloKit/Sources/HaloDownloads/Engine/DownloadCoordinator.swift +++ b/Packages/FlaroKit/Sources/FlaroDownloads/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.halo.downloads" + public static let sessionIdentifier = "com.scarriffleservices.flaro.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 = "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" + static let wifiOnly = "flaro.downloads.wifiOnly" + static let storageLimit = "flaro.downloads.storageLimit" + static let deleteAfter = "flaro.downloads.deleteWatchedAfter" + static let keepUnwatched = "flaro.downloads.keepUnwatched" + static let maximumConcurrent = "flaro.downloads.maximumConcurrent" } /// Der Container, nicht nur der Kontext. diff --git a/Packages/HaloKit/Sources/HaloDownloads/Engine/DownloadFileStore.swift b/Packages/FlaroKit/Sources/FlaroDownloads/Engine/DownloadFileStore.swift similarity index 100% rename from Packages/HaloKit/Sources/HaloDownloads/Engine/DownloadFileStore.swift rename to Packages/FlaroKit/Sources/FlaroDownloads/Engine/DownloadFileStore.swift diff --git a/Packages/HaloKit/Sources/HaloDownloads/Engine/DownloadRules.swift b/Packages/FlaroKit/Sources/FlaroDownloads/Engine/DownloadRules.swift similarity index 100% rename from Packages/HaloKit/Sources/HaloDownloads/Engine/DownloadRules.swift rename to Packages/FlaroKit/Sources/FlaroDownloads/Engine/DownloadRules.swift diff --git a/Packages/HaloKit/Sources/HaloDownloads/Localizable.xcstrings b/Packages/FlaroKit/Sources/FlaroDownloads/Localizable.xcstrings similarity index 100% rename from Packages/HaloKit/Sources/HaloDownloads/Localizable.xcstrings rename to Packages/FlaroKit/Sources/FlaroDownloads/Localizable.xcstrings diff --git a/Packages/HaloKit/Sources/HaloDownloads/Model/DownloadActivityAttributes.swift b/Packages/FlaroKit/Sources/FlaroDownloads/Model/DownloadActivityAttributes.swift similarity index 96% rename from Packages/HaloKit/Sources/HaloDownloads/Model/DownloadActivityAttributes.swift rename to Packages/FlaroKit/Sources/FlaroDownloads/Model/DownloadActivityAttributes.swift index 27db132..f9b081a 100644 --- a/Packages/HaloKit/Sources/HaloDownloads/Model/DownloadActivityAttributes.swift +++ b/Packages/FlaroKit/Sources/FlaroDownloads/Model/DownloadActivityAttributes.swift @@ -11,7 +11,7 @@ import ActivityKit /// Was im Sperrbildschirm und in der Dynamic Island steht. /// -/// Liegt in HaloDownloads, weil App und Widget-Erweiterung denselben Typ +/// Liegt in FlaroDownloads, 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/HaloKit/Sources/HaloDownloads/Model/DownloadItem.swift b/Packages/FlaroKit/Sources/FlaroDownloads/Model/DownloadItem.swift similarity index 100% rename from Packages/HaloKit/Sources/HaloDownloads/Model/DownloadItem.swift rename to Packages/FlaroKit/Sources/FlaroDownloads/Model/DownloadItem.swift diff --git a/Packages/HaloKit/Sources/HaloDownloads/TransferHold.swift b/Packages/FlaroKit/Sources/FlaroDownloads/TransferHold.swift similarity index 100% rename from Packages/HaloKit/Sources/HaloDownloads/TransferHold.swift rename to Packages/FlaroKit/Sources/FlaroDownloads/TransferHold.swift diff --git a/Packages/HaloKit/Sources/HaloPlayback/Decision/AudioTrackChooser.swift b/Packages/FlaroKit/Sources/FlaroPlayback/Decision/AudioTrackChooser.swift similarity index 100% rename from Packages/HaloKit/Sources/HaloPlayback/Decision/AudioTrackChooser.swift rename to Packages/FlaroKit/Sources/FlaroPlayback/Decision/AudioTrackChooser.swift diff --git a/Packages/HaloKit/Sources/HaloPlayback/Decision/DeviceCapabilities.swift b/Packages/FlaroKit/Sources/FlaroPlayback/Decision/DeviceCapabilities.swift similarity index 100% rename from Packages/HaloKit/Sources/HaloPlayback/Decision/DeviceCapabilities.swift rename to Packages/FlaroKit/Sources/FlaroPlayback/Decision/DeviceCapabilities.swift diff --git a/Packages/HaloKit/Sources/HaloPlayback/Decision/DowngradeRule.swift b/Packages/FlaroKit/Sources/FlaroPlayback/Decision/DowngradeRule.swift similarity index 100% rename from Packages/HaloKit/Sources/HaloPlayback/Decision/DowngradeRule.swift rename to Packages/FlaroKit/Sources/FlaroPlayback/Decision/DowngradeRule.swift diff --git a/Packages/HaloKit/Sources/HaloPlayback/Decision/LanguageCode.swift b/Packages/FlaroKit/Sources/FlaroPlayback/Decision/LanguageCode.swift similarity index 100% rename from Packages/HaloKit/Sources/HaloPlayback/Decision/LanguageCode.swift rename to Packages/FlaroKit/Sources/FlaroPlayback/Decision/LanguageCode.swift diff --git a/Packages/HaloKit/Sources/HaloPlayback/Decision/NetworkConditions.swift b/Packages/FlaroKit/Sources/FlaroPlayback/Decision/NetworkConditions.swift similarity index 94% rename from Packages/HaloKit/Sources/HaloPlayback/Decision/NetworkConditions.swift rename to Packages/FlaroKit/Sources/FlaroPlayback/Decision/NetworkConditions.swift index cd41c88..0bb38b7 100644 --- a/Packages/HaloKit/Sources/HaloPlayback/Decision/NetworkConditions.swift +++ b/Packages/FlaroKit/Sources/FlaroPlayback/Decision/NetworkConditions.swift @@ -29,7 +29,7 @@ public final class NetworkConditions { isConstrained = path.isConstrained } } - monitor.start(queue: DispatchQueue(label: "halo.network")) + monitor.start(queue: DispatchQueue(label: "flaro.network")) } deinit { diff --git a/Packages/HaloKit/Sources/HaloPlayback/Decision/PlaybackDecider.swift b/Packages/FlaroKit/Sources/FlaroPlayback/Decision/PlaybackDecider.swift similarity index 100% rename from Packages/HaloKit/Sources/HaloPlayback/Decision/PlaybackDecider.swift rename to Packages/FlaroKit/Sources/FlaroPlayback/Decision/PlaybackDecider.swift diff --git a/Packages/HaloKit/Sources/HaloPlayback/Decision/PlaybackDecision.swift b/Packages/FlaroKit/Sources/FlaroPlayback/Decision/PlaybackDecision.swift similarity index 100% rename from Packages/HaloKit/Sources/HaloPlayback/Decision/PlaybackDecision.swift rename to Packages/FlaroKit/Sources/FlaroPlayback/Decision/PlaybackDecision.swift diff --git a/Packages/HaloKit/Sources/HaloPlayback/Decision/PlaybackPolicy.swift b/Packages/FlaroKit/Sources/FlaroPlayback/Decision/PlaybackPolicy.swift similarity index 100% rename from Packages/HaloKit/Sources/HaloPlayback/Decision/PlaybackPolicy.swift rename to Packages/FlaroKit/Sources/FlaroPlayback/Decision/PlaybackPolicy.swift diff --git a/Packages/HaloKit/Sources/HaloPlayback/Decision/PlayerQuality.swift b/Packages/FlaroKit/Sources/FlaroPlayback/Decision/PlayerQuality.swift similarity index 100% rename from Packages/HaloKit/Sources/HaloPlayback/Decision/PlayerQuality.swift rename to Packages/FlaroKit/Sources/FlaroPlayback/Decision/PlayerQuality.swift diff --git a/Packages/HaloKit/Sources/HaloPlayback/Decision/StallLedger.swift b/Packages/FlaroKit/Sources/FlaroPlayback/Decision/StallLedger.swift similarity index 100% rename from Packages/HaloKit/Sources/HaloPlayback/Decision/StallLedger.swift rename to Packages/FlaroKit/Sources/FlaroPlayback/Decision/StallLedger.swift diff --git a/Packages/HaloKit/Sources/HaloPlayback/Decision/StreamHealth.swift b/Packages/FlaroKit/Sources/FlaroPlayback/Decision/StreamHealth.swift similarity index 100% rename from Packages/HaloKit/Sources/HaloPlayback/Decision/StreamHealth.swift rename to Packages/FlaroKit/Sources/FlaroPlayback/Decision/StreamHealth.swift diff --git a/Packages/HaloKit/Sources/HaloPlayback/Decision/TrackMenu.swift b/Packages/FlaroKit/Sources/FlaroPlayback/Decision/TrackMenu.swift similarity index 100% rename from Packages/HaloKit/Sources/HaloPlayback/Decision/TrackMenu.swift rename to Packages/FlaroKit/Sources/FlaroPlayback/Decision/TrackMenu.swift diff --git a/Packages/HaloKit/Sources/HaloPlayback/Decision/UpgradeRule.swift b/Packages/FlaroKit/Sources/FlaroPlayback/Decision/UpgradeRule.swift similarity index 100% rename from Packages/HaloKit/Sources/HaloPlayback/Decision/UpgradeRule.swift rename to Packages/FlaroKit/Sources/FlaroPlayback/Decision/UpgradeRule.swift diff --git a/Packages/HaloKit/Sources/HaloPlayback/Engine/AVPlayerEngine.swift b/Packages/FlaroKit/Sources/FlaroPlayback/Engine/AVPlayerEngine.swift similarity index 100% rename from Packages/HaloKit/Sources/HaloPlayback/Engine/AVPlayerEngine.swift rename to Packages/FlaroKit/Sources/FlaroPlayback/Engine/AVPlayerEngine.swift diff --git a/Packages/HaloKit/Sources/HaloPlayback/Engine/MediaTrack.swift b/Packages/FlaroKit/Sources/FlaroPlayback/Engine/MediaTrack.swift similarity index 100% rename from Packages/HaloKit/Sources/HaloPlayback/Engine/MediaTrack.swift rename to Packages/FlaroKit/Sources/FlaroPlayback/Engine/MediaTrack.swift diff --git a/Packages/HaloKit/Sources/HaloPlayback/Engine/PlaybackState.swift b/Packages/FlaroKit/Sources/FlaroPlayback/Engine/PlaybackState.swift similarity index 100% rename from Packages/HaloKit/Sources/HaloPlayback/Engine/PlaybackState.swift rename to Packages/FlaroKit/Sources/FlaroPlayback/Engine/PlaybackState.swift diff --git a/Packages/HaloKit/Sources/HaloPlayback/Engine/SubtitleStyle+AVFoundation.swift b/Packages/FlaroKit/Sources/FlaroPlayback/Engine/SubtitleStyle+AVFoundation.swift similarity index 100% rename from Packages/HaloKit/Sources/HaloPlayback/Engine/SubtitleStyle+AVFoundation.swift rename to Packages/FlaroKit/Sources/FlaroPlayback/Engine/SubtitleStyle+AVFoundation.swift diff --git a/Packages/HaloKit/Sources/HaloPlayback/Engine/SubtitleStyle.swift b/Packages/FlaroKit/Sources/FlaroPlayback/Engine/SubtitleStyle.swift similarity index 100% rename from Packages/HaloKit/Sources/HaloPlayback/Engine/SubtitleStyle.swift rename to Packages/FlaroKit/Sources/FlaroPlayback/Engine/SubtitleStyle.swift diff --git a/Packages/HaloKit/Sources/HaloPlayback/Engine/VideoPlayerEngine.swift b/Packages/FlaroKit/Sources/FlaroPlayback/Engine/VideoPlayerEngine.swift similarity index 100% rename from Packages/HaloKit/Sources/HaloPlayback/Engine/VideoPlayerEngine.swift rename to Packages/FlaroKit/Sources/FlaroPlayback/Engine/VideoPlayerEngine.swift diff --git a/Packages/HaloKit/Sources/HaloPlayback/Prefetch/LocalStreamServer.swift b/Packages/FlaroKit/Sources/FlaroPlayback/Prefetch/LocalStreamServer.swift similarity index 99% rename from Packages/HaloKit/Sources/HaloPlayback/Prefetch/LocalStreamServer.swift rename to Packages/FlaroKit/Sources/FlaroPlayback/Prefetch/LocalStreamServer.swift index 01867f7..264c3fd 100644 --- a/Packages/HaloKit/Sources/HaloPlayback/Prefetch/LocalStreamServer.swift +++ b/Packages/FlaroKit/Sources/FlaroPlayback/Prefetch/LocalStreamServer.swift @@ -70,7 +70,7 @@ public actor LocalStreamServer { } private let cache: StreamCache - private let logger = Logger(subsystem: "app.halo", category: "LocalStreamServer") + private let logger = Logger(subsystem: "app.flaro", category: "LocalStreamServer") private var listener: NWListener? private var port: UInt16? private var playlist: String? diff --git a/Packages/HaloKit/Sources/HaloPlayback/Prefetch/MediaPlaylist.swift b/Packages/FlaroKit/Sources/FlaroPlayback/Prefetch/MediaPlaylist.swift similarity index 100% rename from Packages/HaloKit/Sources/HaloPlayback/Prefetch/MediaPlaylist.swift rename to Packages/FlaroKit/Sources/FlaroPlayback/Prefetch/MediaPlaylist.swift diff --git a/Packages/HaloKit/Sources/HaloPlayback/Prefetch/StreamCache.swift b/Packages/FlaroKit/Sources/FlaroPlayback/Prefetch/StreamCache.swift similarity index 98% rename from Packages/HaloKit/Sources/HaloPlayback/Prefetch/StreamCache.swift rename to Packages/FlaroKit/Sources/FlaroPlayback/Prefetch/StreamCache.swift index ba5eee5..c3cab84 100644 --- a/Packages/HaloKit/Sources/HaloPlayback/Prefetch/StreamCache.swift +++ b/Packages/FlaroKit/Sources/FlaroPlayback/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.halo", category: "StreamCache") + private let logger = Logger(subsystem: "app.flaro", 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: "halo-stream-\(UUID().uuidString)", directoryHint: .isDirectory) + .appending(path: "flaro-stream-\(UUID().uuidString)", directoryHint: .isDirectory) try? FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true) } diff --git a/Packages/HaloKit/Sources/HaloProbe/Leiter.swift b/Packages/FlaroKit/Sources/FlaroProbe/Leiter.swift similarity index 99% rename from Packages/HaloKit/Sources/HaloProbe/Leiter.swift rename to Packages/FlaroKit/Sources/FlaroProbe/Leiter.swift index 0c75312..93b4ca7 100644 --- a/Packages/HaloKit/Sources/HaloProbe/Leiter.swift +++ b/Packages/FlaroKit/Sources/FlaroProbe/Leiter.swift @@ -172,9 +172,9 @@ func jellyfinLeiter(host: String) async { } let identity = JellyfinIdentity( - client: "Halo-Probe", + client: "Flaro-Probe", device: "Mac", - deviceID: "halo-probe-" + UUID().uuidString, + deviceID: "flaro-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: "Halo-Probe", + client: "Flaro-Probe", device: "Mac", - deviceID: "halo-probe-" + UUID().uuidString, + deviceID: "flaro-probe-" + UUID().uuidString, version: "1.0" ) let client = JellyfinClient(baseURL: basis, identity: identity) diff --git a/Packages/HaloKit/Sources/HaloProbe/main.swift b/Packages/FlaroKit/Sources/FlaroProbe/main.swift similarity index 96% rename from Packages/HaloKit/Sources/HaloProbe/main.swift rename to Packages/FlaroKit/Sources/FlaroProbe/main.swift index 773f2c5..8b49dbf 100644 --- a/Packages/HaloKit/Sources/HaloProbe/main.swift +++ b/Packages/FlaroKit/Sources/FlaroProbe/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(""" - HaloProbe — fragt Server über reines HTTP, ohne Oberfläche und ohne Gerät. + FlaroProbe — 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/HaloKit/Sources/JellyfinKit/JellyfinAddress.swift b/Packages/FlaroKit/Sources/JellyfinKit/JellyfinAddress.swift similarity index 100% rename from Packages/HaloKit/Sources/JellyfinKit/JellyfinAddress.swift rename to Packages/FlaroKit/Sources/JellyfinKit/JellyfinAddress.swift diff --git a/Packages/HaloKit/Sources/JellyfinKit/JellyfinAuthenticator.swift b/Packages/FlaroKit/Sources/JellyfinKit/JellyfinAuthenticator.swift similarity index 98% rename from Packages/HaloKit/Sources/JellyfinKit/JellyfinAuthenticator.swift rename to Packages/FlaroKit/Sources/JellyfinKit/JellyfinAuthenticator.swift index 18bd93e..f76f1f6 100644 --- a/Packages/HaloKit/Sources/JellyfinKit/JellyfinAuthenticator.swift +++ b/Packages/FlaroKit/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 Halo dabei nie — dieselbe Zusage, die bei Plex gilt, wo die +/// erreicht Flaro 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/HaloKit/Sources/JellyfinKit/JellyfinBackend+LiveTV.swift b/Packages/FlaroKit/Sources/JellyfinKit/JellyfinBackend+LiveTV.swift similarity index 100% rename from Packages/HaloKit/Sources/JellyfinKit/JellyfinBackend+LiveTV.swift rename to Packages/FlaroKit/Sources/JellyfinKit/JellyfinBackend+LiveTV.swift diff --git a/Packages/HaloKit/Sources/JellyfinKit/JellyfinBackend+Playback.swift b/Packages/FlaroKit/Sources/JellyfinKit/JellyfinBackend+Playback.swift similarity index 100% rename from Packages/HaloKit/Sources/JellyfinKit/JellyfinBackend+Playback.swift rename to Packages/FlaroKit/Sources/JellyfinKit/JellyfinBackend+Playback.swift diff --git a/Packages/HaloKit/Sources/JellyfinKit/JellyfinBackend+Recordings.swift b/Packages/FlaroKit/Sources/JellyfinKit/JellyfinBackend+Recordings.swift similarity index 100% rename from Packages/HaloKit/Sources/JellyfinKit/JellyfinBackend+Recordings.swift rename to Packages/FlaroKit/Sources/JellyfinKit/JellyfinBackend+Recordings.swift diff --git a/Packages/HaloKit/Sources/JellyfinKit/JellyfinBackend+Segments.swift b/Packages/FlaroKit/Sources/JellyfinKit/JellyfinBackend+Segments.swift similarity index 100% rename from Packages/HaloKit/Sources/JellyfinKit/JellyfinBackend+Segments.swift rename to Packages/FlaroKit/Sources/JellyfinKit/JellyfinBackend+Segments.swift diff --git a/Packages/HaloKit/Sources/JellyfinKit/JellyfinBackend.swift b/Packages/FlaroKit/Sources/JellyfinKit/JellyfinBackend.swift similarity index 99% rename from Packages/HaloKit/Sources/JellyfinKit/JellyfinBackend.swift rename to Packages/FlaroKit/Sources/JellyfinKit/JellyfinBackend.swift index 17a510f..1b2b99a 100644 --- a/Packages/HaloKit/Sources/JellyfinKit/JellyfinBackend.swift +++ b/Packages/FlaroKit/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: "halo-\(UUID().uuidString)"), + URLQueryItem(name: "playSessionId", value: "flaro-\(UUID().uuidString)"), ] } diff --git a/Packages/HaloKit/Sources/JellyfinKit/JellyfinClient.swift b/Packages/FlaroKit/Sources/JellyfinKit/JellyfinClient.swift similarity index 100% rename from Packages/HaloKit/Sources/JellyfinKit/JellyfinClient.swift rename to Packages/FlaroKit/Sources/JellyfinKit/JellyfinClient.swift diff --git a/Packages/HaloKit/Sources/JellyfinKit/JellyfinIdentity+Current.swift b/Packages/FlaroKit/Sources/JellyfinKit/JellyfinIdentity+Current.swift similarity index 95% rename from Packages/HaloKit/Sources/JellyfinKit/JellyfinIdentity+Current.swift rename to Packages/FlaroKit/Sources/JellyfinKit/JellyfinIdentity+Current.swift index 480b233..a7637fc 100644 --- a/Packages/HaloKit/Sources/JellyfinKit/JellyfinIdentity+Current.swift +++ b/Packages/FlaroKit/Sources/JellyfinKit/JellyfinIdentity+Current.swift @@ -4,7 +4,7 @@ import UIKit #endif extension JellyfinIdentity { - private static let storageKey = "halo.jellyfin.deviceID" + private static let storageKey = "flaro.jellyfin.deviceID" /// Baut die Kennung für das laufende Gerät und merkt sie sich. /// diff --git a/Packages/HaloKit/Sources/JellyfinKit/JellyfinItem+Media.swift b/Packages/FlaroKit/Sources/JellyfinKit/JellyfinItem+Media.swift similarity index 100% rename from Packages/HaloKit/Sources/JellyfinKit/JellyfinItem+Media.swift rename to Packages/FlaroKit/Sources/JellyfinKit/JellyfinItem+Media.swift diff --git a/Packages/HaloKit/Sources/JellyfinKit/JellyfinItem.swift b/Packages/FlaroKit/Sources/JellyfinKit/JellyfinItem.swift similarity index 100% rename from Packages/HaloKit/Sources/JellyfinKit/JellyfinItem.swift rename to Packages/FlaroKit/Sources/JellyfinKit/JellyfinItem.swift diff --git a/Packages/HaloKit/Sources/JellyfinKit/JellyfinLibraryMemo.swift b/Packages/FlaroKit/Sources/JellyfinKit/JellyfinLibraryMemo.swift similarity index 100% rename from Packages/HaloKit/Sources/JellyfinKit/JellyfinLibraryMemo.swift rename to Packages/FlaroKit/Sources/JellyfinKit/JellyfinLibraryMemo.swift diff --git a/Packages/HaloKit/Sources/JellyfinKit/Localizable.xcstrings b/Packages/FlaroKit/Sources/JellyfinKit/Localizable.xcstrings similarity index 100% rename from Packages/HaloKit/Sources/JellyfinKit/Localizable.xcstrings rename to Packages/FlaroKit/Sources/JellyfinKit/Localizable.xcstrings diff --git a/Packages/HaloKit/Sources/MediaKit/Arrangement.swift b/Packages/FlaroKit/Sources/MediaKit/Arrangement.swift similarity index 100% rename from Packages/HaloKit/Sources/MediaKit/Arrangement.swift rename to Packages/FlaroKit/Sources/MediaKit/Arrangement.swift diff --git a/Packages/HaloKit/Sources/MediaKit/Duration+Units.swift b/Packages/FlaroKit/Sources/MediaKit/Duration+Units.swift similarity index 100% rename from Packages/HaloKit/Sources/MediaKit/Duration+Units.swift rename to Packages/FlaroKit/Sources/MediaKit/Duration+Units.swift diff --git a/Packages/HaloKit/Sources/MediaKit/EpisodeSelection.swift b/Packages/FlaroKit/Sources/MediaKit/EpisodeSelection.swift similarity index 100% rename from Packages/HaloKit/Sources/MediaKit/EpisodeSelection.swift rename to Packages/FlaroKit/Sources/MediaKit/EpisodeSelection.swift diff --git a/Packages/HaloKit/Sources/MediaKit/HeroSelection.swift b/Packages/FlaroKit/Sources/MediaKit/HeroSelection.swift similarity index 100% rename from Packages/HaloKit/Sources/MediaKit/HeroSelection.swift rename to Packages/FlaroKit/Sources/MediaKit/HeroSelection.swift diff --git a/Packages/HaloKit/Sources/MediaKit/LibraryCache.swift b/Packages/FlaroKit/Sources/MediaKit/LibraryCache.swift similarity index 98% rename from Packages/HaloKit/Sources/MediaKit/LibraryCache.swift rename to Packages/FlaroKit/Sources/MediaKit/LibraryCache.swift index 4995a51..228a200 100644 --- a/Packages/HaloKit/Sources/MediaKit/LibraryCache.swift +++ b/Packages/FlaroKit/Sources/MediaKit/LibraryCache.swift @@ -47,7 +47,7 @@ public actor LibraryCache { } private let root: URL - private let logger = Logger(subsystem: "app.halo", category: "LibraryCache") + private let logger = Logger(subsystem: "app.flaro", category: "LibraryCache") /// Wie viele Titel höchstens gespeichert werden. /// diff --git a/Packages/HaloKit/Sources/MediaKit/LiveTV.swift b/Packages/FlaroKit/Sources/MediaKit/LiveTV.swift similarity index 100% rename from Packages/HaloKit/Sources/MediaKit/LiveTV.swift rename to Packages/FlaroKit/Sources/MediaKit/LiveTV.swift diff --git a/Packages/HaloKit/Sources/MediaKit/MediaBackend.swift b/Packages/FlaroKit/Sources/MediaKit/MediaBackend.swift similarity index 100% rename from Packages/HaloKit/Sources/MediaKit/MediaBackend.swift rename to Packages/FlaroKit/Sources/MediaKit/MediaBackend.swift diff --git a/Packages/HaloKit/Sources/MediaKit/MediaBackendError.swift b/Packages/FlaroKit/Sources/MediaKit/MediaBackendError.swift similarity index 100% rename from Packages/HaloKit/Sources/MediaKit/MediaBackendError.swift rename to Packages/FlaroKit/Sources/MediaKit/MediaBackendError.swift diff --git a/Packages/HaloKit/Sources/MediaKit/MediaItem.swift b/Packages/FlaroKit/Sources/MediaKit/MediaItem.swift similarity index 100% rename from Packages/HaloKit/Sources/MediaKit/MediaItem.swift rename to Packages/FlaroKit/Sources/MediaKit/MediaItem.swift diff --git a/Packages/HaloKit/Sources/MediaKit/MediaLibrary.swift b/Packages/FlaroKit/Sources/MediaKit/MediaLibrary.swift similarity index 100% rename from Packages/HaloKit/Sources/MediaKit/MediaLibrary.swift rename to Packages/FlaroKit/Sources/MediaKit/MediaLibrary.swift diff --git a/Packages/HaloKit/Sources/MediaKit/MediaPlayback.swift b/Packages/FlaroKit/Sources/MediaKit/MediaPlayback.swift similarity index 100% rename from Packages/HaloKit/Sources/MediaKit/MediaPlayback.swift rename to Packages/FlaroKit/Sources/MediaKit/MediaPlayback.swift diff --git a/Packages/HaloKit/Sources/MediaKit/MediaProfile.swift b/Packages/FlaroKit/Sources/MediaKit/MediaProfile.swift similarity index 100% rename from Packages/HaloKit/Sources/MediaKit/MediaProfile.swift rename to Packages/FlaroKit/Sources/MediaKit/MediaProfile.swift diff --git a/Packages/HaloKit/Sources/MediaKit/MediaQuery.swift b/Packages/FlaroKit/Sources/MediaKit/MediaQuery.swift similarity index 100% rename from Packages/HaloKit/Sources/MediaKit/MediaQuery.swift rename to Packages/FlaroKit/Sources/MediaKit/MediaQuery.swift diff --git a/Packages/HaloKit/Sources/MediaKit/MediaVersion.swift b/Packages/FlaroKit/Sources/MediaKit/MediaVersion.swift similarity index 100% rename from Packages/HaloKit/Sources/MediaKit/MediaVersion.swift rename to Packages/FlaroKit/Sources/MediaKit/MediaVersion.swift diff --git a/Packages/HaloKit/Sources/MediaKit/PagingWindow.swift b/Packages/FlaroKit/Sources/MediaKit/PagingWindow.swift similarity index 100% rename from Packages/HaloKit/Sources/MediaKit/PagingWindow.swift rename to Packages/FlaroKit/Sources/MediaKit/PagingWindow.swift diff --git a/Packages/HaloKit/Sources/MediaKit/TokenStore.swift b/Packages/FlaroKit/Sources/MediaKit/TokenStore.swift similarity index 100% rename from Packages/HaloKit/Sources/MediaKit/TokenStore.swift rename to Packages/FlaroKit/Sources/MediaKit/TokenStore.swift diff --git a/Packages/HaloKit/Sources/MediaKit/TopShelfSnapshot.swift b/Packages/FlaroKit/Sources/MediaKit/TopShelfSnapshot.swift similarity index 100% rename from Packages/HaloKit/Sources/MediaKit/TopShelfSnapshot.swift rename to Packages/FlaroKit/Sources/MediaKit/TopShelfSnapshot.swift diff --git a/Packages/HaloKit/Sources/MediaKit/VideoResolution.swift b/Packages/FlaroKit/Sources/MediaKit/VideoResolution.swift similarity index 100% rename from Packages/HaloKit/Sources/MediaKit/VideoResolution.swift rename to Packages/FlaroKit/Sources/MediaKit/VideoResolution.swift diff --git a/Packages/HaloKit/Tests/HaloDesignTests/ContrastTests.swift b/Packages/FlaroKit/Tests/FlaroDesignTests/ContrastTests.swift similarity index 96% rename from Packages/HaloKit/Tests/HaloDesignTests/ContrastTests.swift rename to Packages/FlaroKit/Tests/FlaroDesignTests/ContrastTests.swift index eb20689..10f880c 100644 --- a/Packages/HaloKit/Tests/HaloDesignTests/ContrastTests.swift +++ b/Packages/FlaroKit/Tests/FlaroDesignTests/ContrastTests.swift @@ -1,10 +1,10 @@ import Foundation import Testing -@testable import HaloDesign +@testable import FlaroDesign @Suite("Kontrastkorrektur") struct ContrastTests { - private let canvas = HaloColor.canvas + private let canvas = FlaroColor.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, HaloColor.canvas) + let ratio = Contrast.ratio(option.color, FlaroColor.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: HaloColor.canvas) + let corrected = Contrast.legible(AccentOption.default.color, on: FlaroColor.canvas) #expect(corrected == AccentOption.default.color) } } @@ -154,7 +154,7 @@ struct DefaultAccentTests { @Suite("Gespeicherte Akzentfarbe") struct AccentStorageTests { private func freshDefaults() -> UserDefaults { - UserDefaults(suiteName: "halo.accent.tests.\(UUID().uuidString)")! + UserDefaults(suiteName: "flaro.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 = HaloTheme(defaults: defaults) + let theme = FlaroTheme(defaults: defaults) #expect(theme.accentColor == AccentOption.storedAccentColor(in: defaults)) } } diff --git a/Packages/HaloKit/Tests/HaloDesignTests/HaloPlatformTests.swift b/Packages/FlaroKit/Tests/FlaroDesignTests/FlaroPlatformTests.swift similarity index 87% rename from Packages/HaloKit/Tests/HaloDesignTests/HaloPlatformTests.swift rename to Packages/FlaroKit/Tests/FlaroDesignTests/FlaroPlatformTests.swift index 8009be8..118760c 100644 --- a/Packages/HaloKit/Tests/HaloDesignTests/HaloPlatformTests.swift +++ b/Packages/FlaroKit/Tests/FlaroDesignTests/FlaroPlatformTests.swift @@ -1,8 +1,8 @@ import Testing -@testable import HaloDesign +@testable import FlaroDesign @Suite("Auf welchem Gerät wir laufen") -struct HaloPlatformTests { +struct FlaroPlatformTests { /// **Der Test, den es vorher nicht gab — und der gefehlt hat.** /// @@ -17,6 +17,6 @@ struct HaloPlatformTests { /// hält er wenigstens fest, dass die Frage gestellt gehört. @Test("Ein Gerät ist nicht zugleich Mac und Fernseher") func neverBoth() { - #expect(!(HaloPlatform.isMac && HaloPlatform.isTV)) + #expect(!(FlaroPlatform.isMac && FlaroPlatform.isTV)) } } diff --git a/Packages/HaloKit/Tests/HaloDesignTests/GuideLayoutTests.swift b/Packages/FlaroKit/Tests/FlaroDesignTests/GuideLayoutTests.swift similarity index 99% rename from Packages/HaloKit/Tests/HaloDesignTests/GuideLayoutTests.swift rename to Packages/FlaroKit/Tests/FlaroDesignTests/GuideLayoutTests.swift index b1e63e4..b101c78 100644 --- a/Packages/HaloKit/Tests/HaloDesignTests/GuideLayoutTests.swift +++ b/Packages/FlaroKit/Tests/FlaroDesignTests/GuideLayoutTests.swift @@ -1,6 +1,6 @@ import Foundation import Testing -@testable import HaloDesign +@testable import FlaroDesign /// Die Geometrie des Programmrasters. @Suite("Raster-Geometrie") diff --git a/Packages/HaloKit/Tests/HaloDesignTests/MiniPlayerPlacementTests.swift b/Packages/FlaroKit/Tests/FlaroDesignTests/MiniPlayerPlacementTests.swift similarity index 99% rename from Packages/HaloKit/Tests/HaloDesignTests/MiniPlayerPlacementTests.swift rename to Packages/FlaroKit/Tests/FlaroDesignTests/MiniPlayerPlacementTests.swift index 8d882c2..551e08c 100644 --- a/Packages/HaloKit/Tests/HaloDesignTests/MiniPlayerPlacementTests.swift +++ b/Packages/FlaroKit/Tests/FlaroDesignTests/MiniPlayerPlacementTests.swift @@ -1,6 +1,6 @@ import Foundation import Testing -@testable import HaloDesign +@testable import FlaroDesign /// Wo die schwebende Videokachel landet. @Suite("Kachel-Platzierung") diff --git a/Packages/HaloKit/Tests/HaloDownloadsTests/DownloadCoordinatorTests.swift b/Packages/FlaroKit/Tests/FlaroDownloadsTests/DownloadCoordinatorTests.swift similarity index 98% rename from Packages/HaloKit/Tests/HaloDownloadsTests/DownloadCoordinatorTests.swift rename to Packages/FlaroKit/Tests/FlaroDownloadsTests/DownloadCoordinatorTests.swift index 4aa502e..3059851 100644 --- a/Packages/HaloKit/Tests/HaloDownloadsTests/DownloadCoordinatorTests.swift +++ b/Packages/FlaroKit/Tests/FlaroDownloadsTests/DownloadCoordinatorTests.swift @@ -1,7 +1,7 @@ import Foundation import SwiftData import Testing -@testable import HaloDownloads +@testable import FlaroDownloads /// 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: "halo.tests.\(UUID().uuidString)")! + let defaults = UserDefaults(suiteName: "flaro.tests.\(UUID().uuidString)")! let coordinator = DownloadCoordinator( container: container, @@ -48,7 +48,7 @@ private func plan( } private func temporaryRoot() -> URL { - FileManager.default.temporaryDirectory.appending(path: "halo-tests-\(UUID().uuidString)") + FileManager.default.temporaryDirectory.appending(path: "flaro-tests-\(UUID().uuidString)") } @MainActor diff --git a/Packages/HaloKit/Tests/HaloDownloadsTests/DownloadRateTests.swift b/Packages/FlaroKit/Tests/FlaroDownloadsTests/DownloadRateTests.swift similarity index 99% rename from Packages/HaloKit/Tests/HaloDownloadsTests/DownloadRateTests.swift rename to Packages/FlaroKit/Tests/FlaroDownloadsTests/DownloadRateTests.swift index a62586b..cbb16ac 100644 --- a/Packages/HaloKit/Tests/HaloDownloadsTests/DownloadRateTests.swift +++ b/Packages/FlaroKit/Tests/FlaroDownloadsTests/DownloadRateTests.swift @@ -1,5 +1,5 @@ import Testing -@testable import HaloDownloads +@testable import FlaroDownloads @Suite("Downloadrate und Restzeit") struct DownloadRateTests { diff --git a/Packages/HaloKit/Tests/HaloDownloadsTests/DownloadRulesTests.swift b/Packages/FlaroKit/Tests/FlaroDownloadsTests/DownloadRulesTests.swift similarity index 99% rename from Packages/HaloKit/Tests/HaloDownloadsTests/DownloadRulesTests.swift rename to Packages/FlaroKit/Tests/FlaroDownloadsTests/DownloadRulesTests.swift index 0af6a94..b112db0 100644 --- a/Packages/HaloKit/Tests/HaloDownloadsTests/DownloadRulesTests.swift +++ b/Packages/FlaroKit/Tests/FlaroDownloadsTests/DownloadRulesTests.swift @@ -1,7 +1,7 @@ import Foundation import MediaKit import Testing -@testable import HaloDownloads +@testable import FlaroDownloads /// Baut einen Eintrag im gewünschten Zustand, ohne Datenbank. @MainActor diff --git a/Packages/HaloKit/Tests/HaloDownloadsTests/DownloadStateTests.swift b/Packages/FlaroKit/Tests/FlaroDownloadsTests/DownloadStateTests.swift similarity index 99% rename from Packages/HaloKit/Tests/HaloDownloadsTests/DownloadStateTests.swift rename to Packages/FlaroKit/Tests/FlaroDownloadsTests/DownloadStateTests.swift index b1b1d14..527ec21 100644 --- a/Packages/HaloKit/Tests/HaloDownloadsTests/DownloadStateTests.swift +++ b/Packages/FlaroKit/Tests/FlaroDownloadsTests/DownloadStateTests.swift @@ -1,5 +1,5 @@ import Testing -@testable import HaloDownloads +@testable import FlaroDownloads @Suite("Download-Zustandsautomat") struct DownloadStateTests { diff --git a/Packages/HaloKit/Tests/HaloDownloadsTests/TransferHoldTests.swift b/Packages/FlaroKit/Tests/FlaroDownloadsTests/TransferHoldTests.swift similarity index 97% rename from Packages/HaloKit/Tests/HaloDownloadsTests/TransferHoldTests.swift rename to Packages/FlaroKit/Tests/FlaroDownloadsTests/TransferHoldTests.swift index 66648de..65ca2d1 100644 --- a/Packages/HaloKit/Tests/HaloDownloadsTests/TransferHoldTests.swift +++ b/Packages/FlaroKit/Tests/FlaroDownloadsTests/TransferHoldTests.swift @@ -1,5 +1,5 @@ import Testing -@testable import HaloDownloads +@testable import FlaroDownloads /// Warum gerade nichts übertragen wird. @Suite("Übertragungssperre") diff --git a/Packages/HaloKit/Tests/HaloPlaybackTests/AudioTrackChooserTests.swift b/Packages/FlaroKit/Tests/FlaroPlaybackTests/AudioTrackChooserTests.swift similarity index 99% rename from Packages/HaloKit/Tests/HaloPlaybackTests/AudioTrackChooserTests.swift rename to Packages/FlaroKit/Tests/FlaroPlaybackTests/AudioTrackChooserTests.swift index 3668dfb..bd7370a 100644 --- a/Packages/HaloKit/Tests/HaloPlaybackTests/AudioTrackChooserTests.swift +++ b/Packages/FlaroKit/Tests/FlaroPlaybackTests/AudioTrackChooserTests.swift @@ -1,7 +1,7 @@ import Testing import Foundation import MediaKit -@testable import HaloPlayback +@testable import FlaroPlayback @Suite("Sprachkürzel") struct LanguageCodeTests { diff --git a/Packages/HaloKit/Tests/HaloPlaybackTests/DowngradeRuleTests.swift b/Packages/FlaroKit/Tests/FlaroPlaybackTests/DowngradeRuleTests.swift similarity index 99% rename from Packages/HaloKit/Tests/HaloPlaybackTests/DowngradeRuleTests.swift rename to Packages/FlaroKit/Tests/FlaroPlaybackTests/DowngradeRuleTests.swift index 8afbeef..5045c9e 100644 --- a/Packages/HaloKit/Tests/HaloPlaybackTests/DowngradeRuleTests.swift +++ b/Packages/FlaroKit/Tests/FlaroPlaybackTests/DowngradeRuleTests.swift @@ -1,6 +1,6 @@ import Testing import Foundation -@testable import HaloPlayback +@testable import FlaroPlayback @Suite("Wann der teure Weg erlaubt ist") struct DowngradeRuleTests { diff --git a/Packages/HaloKit/Tests/HaloPlaybackTests/LocalStreamServerTests.swift b/Packages/FlaroKit/Tests/FlaroPlaybackTests/LocalStreamServerTests.swift similarity index 99% rename from Packages/HaloKit/Tests/HaloPlaybackTests/LocalStreamServerTests.swift rename to Packages/FlaroKit/Tests/FlaroPlaybackTests/LocalStreamServerTests.swift index 24142b1..ec6432d 100644 --- a/Packages/HaloKit/Tests/HaloPlaybackTests/LocalStreamServerTests.swift +++ b/Packages/FlaroKit/Tests/FlaroPlaybackTests/LocalStreamServerTests.swift @@ -1,7 +1,7 @@ import Foundation import Network import Testing -@testable import HaloPlayback +@testable import FlaroPlayback /// Was der lokale Server dem Player wirklich schickt. /// diff --git a/Packages/HaloKit/Tests/HaloPlaybackTests/MediaPlaylistTests.swift b/Packages/FlaroKit/Tests/FlaroPlaybackTests/MediaPlaylistTests.swift similarity index 99% rename from Packages/HaloKit/Tests/HaloPlaybackTests/MediaPlaylistTests.swift rename to Packages/FlaroKit/Tests/FlaroPlaybackTests/MediaPlaylistTests.swift index bc963f2..76240e3 100644 --- a/Packages/HaloKit/Tests/HaloPlaybackTests/MediaPlaylistTests.swift +++ b/Packages/FlaroKit/Tests/FlaroPlaybackTests/MediaPlaylistTests.swift @@ -1,6 +1,6 @@ import Testing import Foundation -@testable import HaloPlayback +@testable import FlaroPlayback @Suite("Abspielliste lesen und umschreiben") struct MediaPlaylistTests { diff --git a/Packages/HaloKit/Tests/HaloPlaybackTests/PlaybackDeciderTests.swift b/Packages/FlaroKit/Tests/FlaroPlaybackTests/PlaybackDeciderTests.swift similarity index 99% rename from Packages/HaloKit/Tests/HaloPlaybackTests/PlaybackDeciderTests.swift rename to Packages/FlaroKit/Tests/FlaroPlaybackTests/PlaybackDeciderTests.swift index 7f8cd1f..5cd5aa6 100644 --- a/Packages/HaloKit/Tests/HaloPlaybackTests/PlaybackDeciderTests.swift +++ b/Packages/FlaroKit/Tests/FlaroPlaybackTests/PlaybackDeciderTests.swift @@ -1,6 +1,6 @@ import Testing import MediaKit -@testable import HaloPlayback +@testable import FlaroPlayback /// Die Tabelle, die festhält, welche Datei auf welchem Weg landet. /// diff --git a/Packages/HaloKit/Tests/HaloPlaybackTests/QualityMemoryTests.swift b/Packages/FlaroKit/Tests/FlaroPlaybackTests/QualityMemoryTests.swift similarity index 98% rename from Packages/HaloKit/Tests/HaloPlaybackTests/QualityMemoryTests.swift rename to Packages/FlaroKit/Tests/FlaroPlaybackTests/QualityMemoryTests.swift index e05cf0f..2a19262 100644 --- a/Packages/HaloKit/Tests/HaloPlaybackTests/QualityMemoryTests.swift +++ b/Packages/FlaroKit/Tests/FlaroPlaybackTests/QualityMemoryTests.swift @@ -1,5 +1,5 @@ import Testing -@testable import HaloPlayback +@testable import FlaroPlayback /// Die gemerkte Qualitätsstufe über mehrere Filme hinweg. /// diff --git a/Packages/HaloKit/Tests/HaloPlaybackTests/StallLedgerTests.swift b/Packages/FlaroKit/Tests/FlaroPlaybackTests/StallLedgerTests.swift similarity index 99% rename from Packages/HaloKit/Tests/HaloPlaybackTests/StallLedgerTests.swift rename to Packages/FlaroKit/Tests/FlaroPlaybackTests/StallLedgerTests.swift index 7e3cf1e..117491e 100644 --- a/Packages/HaloKit/Tests/HaloPlaybackTests/StallLedgerTests.swift +++ b/Packages/FlaroKit/Tests/FlaroPlaybackTests/StallLedgerTests.swift @@ -1,6 +1,6 @@ import Testing import Foundation -@testable import HaloPlayback +@testable import FlaroPlayback @Suite("Rückler-Buchführung") struct StallLedgerTests { diff --git a/Packages/HaloKit/Tests/HaloPlaybackTests/StreamHealthTests.swift b/Packages/FlaroKit/Tests/FlaroPlaybackTests/StreamHealthTests.swift similarity index 99% rename from Packages/HaloKit/Tests/HaloPlaybackTests/StreamHealthTests.swift rename to Packages/FlaroKit/Tests/FlaroPlaybackTests/StreamHealthTests.swift index 028f45e..58fd7c6 100644 --- a/Packages/HaloKit/Tests/HaloPlaybackTests/StreamHealthTests.swift +++ b/Packages/FlaroKit/Tests/FlaroPlaybackTests/StreamHealthTests.swift @@ -1,6 +1,6 @@ import Testing import Foundation -@testable import HaloPlayback +@testable import FlaroPlayback @Suite("Zustand des Streams") struct StreamHealthTests { diff --git a/Packages/HaloKit/Tests/HaloPlaybackTests/SubtitleStyleTests.swift b/Packages/FlaroKit/Tests/FlaroPlaybackTests/SubtitleStyleTests.swift similarity index 99% rename from Packages/HaloKit/Tests/HaloPlaybackTests/SubtitleStyleTests.swift rename to Packages/FlaroKit/Tests/FlaroPlaybackTests/SubtitleStyleTests.swift index fcdfe34..44bf998 100644 --- a/Packages/HaloKit/Tests/HaloPlaybackTests/SubtitleStyleTests.swift +++ b/Packages/FlaroKit/Tests/FlaroPlaybackTests/SubtitleStyleTests.swift @@ -2,7 +2,7 @@ import AVFoundation import CoreMedia import Foundation import Testing -@testable import HaloPlayback +@testable import FlaroPlayback @Suite("Aussehen der Untertitel") struct SubtitleStyleTests { diff --git a/Packages/HaloKit/Tests/HaloPlaybackTests/TrackMenuTests.swift b/Packages/FlaroKit/Tests/FlaroPlaybackTests/TrackMenuTests.swift similarity index 99% rename from Packages/HaloKit/Tests/HaloPlaybackTests/TrackMenuTests.swift rename to Packages/FlaroKit/Tests/FlaroPlaybackTests/TrackMenuTests.swift index 722df59..b793551 100644 --- a/Packages/HaloKit/Tests/HaloPlaybackTests/TrackMenuTests.swift +++ b/Packages/FlaroKit/Tests/FlaroPlaybackTests/TrackMenuTests.swift @@ -1,6 +1,6 @@ import Testing import MediaKit -@testable import HaloPlayback +@testable import FlaroPlayback @Suite("Was im Spurenmenü steht") struct TrackMenuTests { diff --git a/Packages/HaloKit/Tests/HaloPlaybackTests/UpgradeRuleTests.swift b/Packages/FlaroKit/Tests/FlaroPlaybackTests/UpgradeRuleTests.swift similarity index 99% rename from Packages/HaloKit/Tests/HaloPlaybackTests/UpgradeRuleTests.swift rename to Packages/FlaroKit/Tests/FlaroPlaybackTests/UpgradeRuleTests.swift index c979ba4..ce5b43e 100644 --- a/Packages/HaloKit/Tests/HaloPlaybackTests/UpgradeRuleTests.swift +++ b/Packages/FlaroKit/Tests/FlaroPlaybackTests/UpgradeRuleTests.swift @@ -1,6 +1,6 @@ import Foundation import Testing -@testable import HaloPlayback +@testable import FlaroPlayback @Suite("Wann hinaufgeschaltet wird") struct UpgradeRuleTests { diff --git a/Packages/HaloKit/Tests/JellyfinKitTests/AdaptiveURLTests.swift b/Packages/FlaroKit/Tests/JellyfinKitTests/AdaptiveURLTests.swift similarity index 100% rename from Packages/HaloKit/Tests/JellyfinKitTests/AdaptiveURLTests.swift rename to Packages/FlaroKit/Tests/JellyfinKitTests/AdaptiveURLTests.swift diff --git a/Packages/HaloKit/Tests/JellyfinKitTests/AddressTests.swift b/Packages/FlaroKit/Tests/JellyfinKitTests/AddressTests.swift similarity index 100% rename from Packages/HaloKit/Tests/JellyfinKitTests/AddressTests.swift rename to Packages/FlaroKit/Tests/JellyfinKitTests/AddressTests.swift diff --git a/Packages/HaloKit/Tests/JellyfinKitTests/Fixtures/episode.json b/Packages/FlaroKit/Tests/JellyfinKitTests/Fixtures/episode.json similarity index 100% rename from Packages/HaloKit/Tests/JellyfinKitTests/Fixtures/episode.json rename to Packages/FlaroKit/Tests/JellyfinKitTests/Fixtures/episode.json diff --git a/Packages/HaloKit/Tests/JellyfinKitTests/Fixtures/series.json b/Packages/FlaroKit/Tests/JellyfinKitTests/Fixtures/series.json similarity index 100% rename from Packages/HaloKit/Tests/JellyfinKitTests/Fixtures/series.json rename to Packages/FlaroKit/Tests/JellyfinKitTests/Fixtures/series.json diff --git a/Packages/HaloKit/Tests/JellyfinKitTests/PlaybackTests.swift b/Packages/FlaroKit/Tests/JellyfinKitTests/PlaybackTests.swift similarity index 98% rename from Packages/HaloKit/Tests/JellyfinKitTests/PlaybackTests.swift rename to Packages/FlaroKit/Tests/JellyfinKitTests/PlaybackTests.swift index 9ec5cfd..765474e 100644 --- a/Packages/HaloKit/Tests/JellyfinKitTests/PlaybackTests.swift +++ b/Packages/FlaroKit/Tests/JellyfinKitTests/PlaybackTests.swift @@ -15,7 +15,7 @@ struct PlaybackTests { let client = JellyfinClient( baseURL: URL(string: "http://server:8096")!, identity: JellyfinIdentity( - client: "Halo", device: "Testgerät", deviceID: "gerät-1", version: "1" + client: "Flaro", 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: "Halo", device: "Testgerät", deviceID: "gerät-1", version: "1" + client: "Flaro", 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: "Halo", device: "Testgerät", deviceID: "gerät-1", version: "1" + client: "Flaro", 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: "Halo", device: "Testgerät", deviceID: "gerät-1", version: "1" + client: "Flaro", device: "Testgerät", deviceID: "gerät-1", version: "1" ), token: "tok", transport: transport diff --git a/Packages/HaloKit/Tests/JellyfinKitTests/TranslationTests.swift b/Packages/FlaroKit/Tests/JellyfinKitTests/TranslationTests.swift similarity index 100% rename from Packages/HaloKit/Tests/JellyfinKitTests/TranslationTests.swift rename to Packages/FlaroKit/Tests/JellyfinKitTests/TranslationTests.swift diff --git a/Packages/HaloKit/Tests/MediaKitTests/.keep b/Packages/FlaroKit/Tests/MediaKitTests/.keep similarity index 100% rename from Packages/HaloKit/Tests/MediaKitTests/.keep rename to Packages/FlaroKit/Tests/MediaKitTests/.keep diff --git a/Packages/HaloKit/Tests/MediaKitTests/ArrangementTests.swift b/Packages/FlaroKit/Tests/MediaKitTests/ArrangementTests.swift similarity index 100% rename from Packages/HaloKit/Tests/MediaKitTests/ArrangementTests.swift rename to Packages/FlaroKit/Tests/MediaKitTests/ArrangementTests.swift diff --git a/Packages/HaloKit/Tests/MediaKitTests/DurationUnitsTests.swift b/Packages/FlaroKit/Tests/MediaKitTests/DurationUnitsTests.swift similarity index 100% rename from Packages/HaloKit/Tests/MediaKitTests/DurationUnitsTests.swift rename to Packages/FlaroKit/Tests/MediaKitTests/DurationUnitsTests.swift diff --git a/Packages/HaloKit/Tests/MediaKitTests/EpisodeSelectionTests.swift b/Packages/FlaroKit/Tests/MediaKitTests/EpisodeSelectionTests.swift similarity index 100% rename from Packages/HaloKit/Tests/MediaKitTests/EpisodeSelectionTests.swift rename to Packages/FlaroKit/Tests/MediaKitTests/EpisodeSelectionTests.swift diff --git a/Packages/HaloKit/Tests/MediaKitTests/HeroSelectionTests.swift b/Packages/FlaroKit/Tests/MediaKitTests/HeroSelectionTests.swift similarity index 100% rename from Packages/HaloKit/Tests/MediaKitTests/HeroSelectionTests.swift rename to Packages/FlaroKit/Tests/MediaKitTests/HeroSelectionTests.swift diff --git a/Packages/HaloKit/Tests/MediaKitTests/LibraryCacheTests.swift b/Packages/FlaroKit/Tests/MediaKitTests/LibraryCacheTests.swift similarity index 99% rename from Packages/HaloKit/Tests/MediaKitTests/LibraryCacheTests.swift rename to Packages/FlaroKit/Tests/MediaKitTests/LibraryCacheTests.swift index 726f351..7403e88 100644 --- a/Packages/HaloKit/Tests/MediaKitTests/LibraryCacheTests.swift +++ b/Packages/FlaroKit/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: "halo-cache-\(UUID().uuidString)") + let ort = URL.temporaryDirectory.appending(path: "flaro-cache-\(UUID().uuidString)") return LibraryCache(root: ort) } diff --git a/Packages/HaloKit/Tests/MediaKitTests/PagingWindowTests.swift b/Packages/FlaroKit/Tests/MediaKitTests/PagingWindowTests.swift similarity index 100% rename from Packages/HaloKit/Tests/MediaKitTests/PagingWindowTests.swift rename to Packages/FlaroKit/Tests/MediaKitTests/PagingWindowTests.swift diff --git a/Packages/HaloKit/Tests/MediaKitTests/TopShelfSnapshotTests.swift b/Packages/FlaroKit/Tests/MediaKitTests/TopShelfSnapshotTests.swift similarity index 97% rename from Packages/HaloKit/Tests/MediaKitTests/TopShelfSnapshotTests.swift rename to Packages/FlaroKit/Tests/MediaKitTests/TopShelfSnapshotTests.swift index 4f0a496..45507bd 100644 --- a/Packages/HaloKit/Tests/MediaKitTests/TopShelfSnapshotTests.swift +++ b/Packages/FlaroKit/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.halo.test.\(UUID().uuidString)" + let unbekannt = "group.flaro.test.\(UUID().uuidString)" TopShelfStore.write(TopShelfSnapshot(sections: []), group: unbekannt) let gelesen = TopShelfStore.read(group: unbekannt) #expect(gelesen?.sections.isEmpty ?? true) diff --git a/Packages/HaloKit/Tests/MediaKitTests/VideoResolutionTests.swift b/Packages/FlaroKit/Tests/MediaKitTests/VideoResolutionTests.swift similarity index 100% rename from Packages/HaloKit/Tests/MediaKitTests/VideoResolutionTests.swift rename to Packages/FlaroKit/Tests/MediaKitTests/VideoResolutionTests.swift diff --git a/README.md b/README.md index 66d98e9..be33e70 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -# Halo +# Flaro > 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 [`Halo/Branding.swift`](Halo/Branding.swift). +Der Name ist ein Platzhalter. Siehe [`Flaro/Branding.swift`](Flaro/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-halo-design.md`](docs/superpowers/specs/2026-09-11-halo-design.md). +[`docs/superpowers/specs/2026-09-11-flaro-design.md`](docs/superpowers/specs/2026-09-11-flaro-design.md). | Phase | Inhalt | Stand | |---|---|---| @@ -46,7 +46,7 @@ eingecheckt — das erspart Konflikte in der `pbxproj`. ```bash xcodegen generate -open Halo.xcodeproj +open Flaro.xcodeproj ``` > **Wichtig: Xcode vorher beenden.** @@ -63,16 +63,16 @@ open Halo.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/HaloKit`. +Der Code liegt zum größten Teil in lokalen Packages unter `Packages/FlaroKit`. 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` | -| `HaloDesign` | Farben, Typografie, wiederkehrende Bausteine. | — | -| `HaloPlayback` | Wiedergabe-Abstraktion und die Entscheidung DirectPlay/Umpacken/Transcode. | `MediaKit` | -| `HaloDownloads` | Warteschlange, Hintergrundübertragung, Offline-Bestand. | `MediaKit` | +| `FlaroDesign` | Farben, Typografie, wiederkehrende Bausteine. | — | +| `FlaroPlayback` | Wiedergabe-Abstraktion und die Entscheidung DirectPlay/Umpacken/Transcode. | `MediaKit` | +| `FlaroDownloads` | 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/HaloKit && swift test +cd Packages/FlaroKit && 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/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? +cd Packages/FlaroKit +swift run FlaroProbe --jellyfin # Welche Leiter baut der Server? +swift run FlaroProbe --spuren # Welche Tonspuren hat ein Titel? +swift run FlaroProbe --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 a957ca3..6e6a3c2 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("HALO_STUB_LIBRARY", "0")) +FUELLUNG = int(os.environ.get("FLARO_STUB_LIBRARY", "0")) def fuellmaterial(kind): return [ diff --git a/Tools/TVBrandAssets.py b/Tools/TVBrandAssets.py index a2b5e2b..c77448a 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("HaloTV/Resources/TVAssets.xcassets") +WURZEL = Path("FlaroTV/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 913ab65..86136b0 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 ?? "Halo" +let name = CommandLine.arguments.dropFirst().first ?? "Flaro" /// 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/docs/superpowers/specs/2026-10-03-halo-server-design.md b/docs/superpowers/specs/2026-10-03-halo-server-design.md index c94d1ad..f11146e 100644 --- a/docs/superpowers/specs/2026-10-03-halo-server-design.md +++ b/docs/superpowers/specs/2026-10-03-halo-server-design.md @@ -1,3 +1,12 @@ +> **Nachtrag vom selben Tag: das Projekt heisst inzwischen Flaro.** +> +> „Halo" liess sich in App Store Connect nicht eintragen — der Name ist von +> KaVo-ähnlichen Fällen abgesehen vor allem eine Marke von Microsoft, und der +> Upload scheiterte daran. Dieses Dokument bleibt im Wortlaut stehen: es ist +> ein Protokoll der Entscheidungen, nicht ihre Fortschreibung. Überall, wo +> hier „Halo" steht, heisst es heute „Flaro"; die Begründungen gelten +> unverändert. + # Halo-Server — Entwurf *3. Oktober 2026* diff --git a/project.yml b/project.yml index 8f39928..9cd12b4 100644 --- a/project.yml +++ b/project.yml @@ -1,4 +1,4 @@ -name: Halo +name: Flaro options: bundleIdPrefix: com.scarriffleservices @@ -19,11 +19,11 @@ settings: SWIFT_STRICT_CONCURRENCY: complete packages: - HaloKit: - path: Packages/HaloKit + FlaroKit: + path: Packages/FlaroKit targets: - Halo: + Flaro: 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: - - HaloUITests + - FlaroUITests 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: Halo + - path: Flaro excludes: - "AppIcon.icon" - - path: Halo/AppIcon.icon + - path: Flaro/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: HaloKit + - package: FlaroKit product: MediaKit # Der Server. Steht auf der neutralen Schicht, nicht darin — kommt ein # zweiter dazu, steht er daneben. - - package: HaloKit + - package: FlaroKit product: JellyfinKit - - package: HaloKit - product: HaloDesign - - package: HaloKit - product: HaloPlayback - - package: HaloKit - product: HaloDownloads + - package: FlaroKit + product: FlaroDesign + - package: FlaroKit + product: FlaroPlayback + - package: FlaroKit + product: FlaroDownloads settings: base: - PRODUCT_BUNDLE_IDENTIFIER: com.scarriffleservices.halo - PRODUCT_NAME: Halo + PRODUCT_BUNDLE_IDENTIFIER: com.scarriffleservices.flaro + PRODUCT_NAME: Flaro # 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: Halo/Info.plist + path: Flaro/Info.plist properties: - CFBundleDisplayName: Halo + CFBundleDisplayName: Flaro UILaunchScreen: UIColorName: LaunchBackground @@ -136,25 +136,25 @@ targets: # Freigabe. Fehlt der Text, verweigert das System sie kommentarlos und # die Serversuche findet dauerhaft nichts. NSLocalNetworkUsageDescription: >- - Halo benötigt Zugriff auf das lokale Netzwerk, um deinen + Flaro 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: `HaloTV/` gehört nur hierher, `Halo/Session/` + # Aussage dieses Blocks: `FlaroTV/` gehört nur hierher, `Flaro/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. - HaloTV: + FlaroTV: type: application platform: tvOS - # Aus demselben Grund ausgeschrieben wie bei Halo — siehe dort. + # Aus demselben Grund ausgeschrieben wie bei Flaro — siehe dort. scheme: {} sources: # Die eigenen Ansichten. - - path: HaloTV + - path: FlaroTV # Die Modelle. - - path: Halo/Session + - path: Flaro/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: Halo/Views/LoadState.swift + - path: Flaro/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: Halo/Views/Player/PlayerModel.swift + - path: Flaro/Views/Player/PlayerModel.swift type: file - - path: Halo/Views/Player/VideoSurface.swift + - path: Flaro/Views/Player/VideoSurface.swift type: file - - path: Halo/Branding.swift + - path: Flaro/Branding.swift type: file # Die Texte. Dieselben Schlüssel, dieselben Übersetzungen. - - path: Halo/Resources/Localizable.xcstrings + - path: Flaro/Resources/Localizable.xcstrings type: file dependencies: - - package: HaloKit + - package: FlaroKit product: MediaKit - - package: HaloKit + - package: FlaroKit product: JellyfinKit - - package: HaloKit - product: HaloDesign - - package: HaloKit - product: HaloPlayback + - package: FlaroKit + product: FlaroDesign + - package: FlaroKit + product: FlaroPlayback # Nur damit `PlayerModel` den Typ nennen darf. Angelegt wird nie einer: - # HaloTVApp reicht `nil` durch, und damit gibt es auf tvOS auch keinen + # FlaroTVApp reicht `nil` durch, und damit gibt es auf tvOS auch keinen # ModelContainer und kein SwiftData. - - package: HaloKit - product: HaloDownloads - - target: HaloTopShelf + - package: FlaroKit + product: FlaroDownloads + - target: FlaroTopShelf settings: base: - PRODUCT_BUNDLE_IDENTIFIER: com.scarriffleservices.halo.tv - PRODUCT_NAME: Halo + PRODUCT_BUNDLE_IDENTIFIER: com.scarriffleservices.flaro.tv + PRODUCT_NAME: Flaro # 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 HaloTV/Resources. + # und der Katalog liegt unter FlaroTV/Resources. ASSETCATALOG_COMPILER_APPICON_NAME: "App Icon & Top Shelf Image" CODE_SIGN_STYLE: Automatic - CODE_SIGN_ENTITLEMENTS: HaloTV/Halo.entitlements + CODE_SIGN_ENTITLEMENTS: FlaroTV/Flaro.entitlements info: - path: HaloTV/Info.plist + path: FlaroTV/Info.plist properties: - CFBundleDisplayName: Halo + CFBundleDisplayName: Flaro 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.halo.topshelf + - CFBundleURLName: com.scarriffleservices.flaro.topshelf CFBundleURLSchemes: - - halo + - flaro # Was hier **nicht** steht, und warum: # # UILaunchScreen — tvOS hat kein Startbild dieser Art. @@ -234,7 +234,7 @@ targets: NSAppTransportSecurity: NSAllowsLocalNetworking: true NSLocalNetworkUsageDescription: >- - Halo benötigt Zugriff auf das lokale Netzwerk, um deinen + Flaro 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. - HaloTopShelf: + FlaroTopShelf: type: tv-app-extension platform: tvOS sources: - - path: HaloTopShelf + - path: FlaroTopShelf dependencies: - - package: HaloKit + - package: FlaroKit product: MediaKit settings: base: - PRODUCT_BUNDLE_IDENTIFIER: com.scarriffleservices.halo.tv.topshelf - PRODUCT_NAME: HaloTopShelf + PRODUCT_BUNDLE_IDENTIFIER: com.scarriffleservices.flaro.tv.topshelf + PRODUCT_NAME: FlaroTopShelf CODE_SIGN_STYLE: Automatic - CODE_SIGN_ENTITLEMENTS: HaloTopShelf/HaloTopShelf.entitlements + CODE_SIGN_ENTITLEMENTS: FlaroTopShelf/FlaroTopShelf.entitlements SKIP_INSTALL: YES info: - path: HaloTopShelf/Info.plist + path: FlaroTopShelf/Info.plist properties: - CFBundleDisplayName: Halo + CFBundleDisplayName: Flaro # **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. - HaloUITests: + FlaroUITests: type: bundle.ui-testing platform: iOS sources: - - HaloUITests + - FlaroUITests dependencies: - - target: Halo + - target: Flaro settings: base: - PRODUCT_BUNDLE_IDENTIFIER: com.scarriffleservices.halo.uitests - TEST_TARGET_NAME: Halo + PRODUCT_BUNDLE_IDENTIFIER: com.scarriffleservices.flaro.uitests + TEST_TARGET_NAME: Flaro TARGETED_DEVICE_FAMILY: "1,2" CODE_SIGN_STYLE: Automatic GENERATE_INFOPLIST_FILE: YES @@ -303,13 +303,13 @@ targets: sources: - path: DownloadWidget dependencies: - - package: HaloKit - product: HaloDownloads - - package: HaloKit - product: HaloDesign + - package: FlaroKit + product: FlaroDownloads + - package: FlaroKit + product: FlaroDesign settings: base: - PRODUCT_BUNDLE_IDENTIFIER: com.scarriffleservices.halo.downloadwidget + PRODUCT_BUNDLE_IDENTIFIER: com.scarriffleservices.flaro.downloadwidget PRODUCT_NAME: DownloadWidget CODE_SIGN_STYLE: Automatic SKIP_INSTALL: YES @@ -320,6 +320,6 @@ targets: info: path: DownloadWidget/Info.plist properties: - CFBundleDisplayName: Halo Downloads + CFBundleDisplayName: Flaro Downloads NSExtension: NSExtensionPointIdentifier: com.apple.widgetkit-extension diff --git a/server/Dockerfile b/server/Dockerfile index a600957..14d8cdf 100644 --- a/server/Dockerfile +++ b/server/Dockerfile @@ -14,17 +14,17 @@ WORKDIR /src # weil eine Liste bei jedem neuen Projekt vergessen wird — und dann scheitert # erst der Bau im Container, nicht der auf dem Arbeitsrechner. COPY --parents src/*/*.csproj ./ -RUN dotnet restore src/Halo.Api/Halo.Api.csproj -a $TARGETARCH +RUN dotnet restore src/Flaro.Api/Flaro.Api.csproj -a $TARGETARCH COPY . . -RUN dotnet publish src/Halo.Api/Halo.Api.csproj -a $TARGETARCH -c Release -o /app --no-restore +RUN dotnet publish src/Flaro.Api/Flaro.Api.csproj -a $TARGETARCH -c Release -o /app --no-restore FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime # ffmpeg und die Treiber für Hardware-Beschleunigung. # -# **Als eigenes Programm, nicht als Bibliothek.** Halo ruft es als Prozess +# **Als eigenes Programm, nicht als Bibliothek.** Flaro ruft es als Prozess # auf; damit bleiben die Lizenzen getrennt (ffmpeg steht unter GPL) und ein # Absturz dort nimmt den Server nicht mit. # @@ -57,9 +57,9 @@ RUN mkdir -p /config /cache /transcode && chown -R 1000:1000 /config /cache /tra # braucht weder ein Startskript noch root im Container. USER 1000:1000 -ENV HALO_DATA=/config \ - HALO_CACHE=/cache \ - HALO_TRANSCODE=/transcode \ +ENV FLARO_DATA=/config \ + FLARO_CACHE=/cache \ + FLARO_TRANSCODE=/transcode \ ASPNETCORE_URLS=http://+:8080 \ DOTNET_gcServer=0 @@ -69,4 +69,4 @@ COPY --from=build /app . EXPOSE 8080 VOLUME ["/config", "/cache", "/transcode"] -ENTRYPOINT ["dotnet", "Halo.Api.dll"] +ENTRYPOINT ["dotnet", "Flaro.Api.dll"] diff --git a/server/Flaro.slnx b/server/Flaro.slnx new file mode 100644 index 0000000..d866a72 --- /dev/null +++ b/server/Flaro.slnx @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/server/Halo.slnx b/server/Halo.slnx deleted file mode 100644 index 887226e..0000000 --- a/server/Halo.slnx +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/server/README.md b/server/README.md index 8a042bb..70e89f3 100644 --- a/server/README.md +++ b/server/README.md @@ -1,4 +1,4 @@ -# Halo-Server +# Flaro-Server Ein Medienserver, der dieselben Dinge kann wie Jellyfin — und zwei, die dort nicht gehen. @@ -7,7 +7,7 @@ nicht gehen. Metadaten — und **Download mit allen Ton- und Textspuren**, der Grund für dieses Projekt. Was noch fehlt: Streamen mit Umrechnen (HLS), Fortschritt und Gesehen-Status, Live TV. Der Entwurf samt Begründungen steht -in [`docs/superpowers/specs/2026-10-03-halo-server-design.md`](../docs/superpowers/specs/2026-10-03-halo-server-design.md). +in [`docs/superpowers/specs/2026-10-03-flaro-server-design.md`](../docs/superpowers/specs/2026-10-03-flaro-server-design.md). ## Warum @@ -35,13 +35,13 @@ Administratorkonto an. Danach verschliesst sich dieser Weg von selbst. | Variable | Bedeutung | Voreinstellung im Image | |---|---|---| -| `HALO_DATA` | Datenbank und Einstellungen. **Das Einzige, was gesichert werden muss.** | `/config` | -| `HALO_CACHE` | Bilder und Zwischenstände. Darf verlorengehen. | `/cache` | -| `HALO_TRANSCODE` | Kratzplatz fürs Umrechnen. Am besten auf eine SSD. | `/transcode` | +| `FLARO_DATA` | Datenbank und Einstellungen. **Das Einzige, was gesichert werden muss.** | `/config` | +| `FLARO_CACHE` | Bilder und Zwischenstände. Darf verlorengehen. | `/cache` | +| `FLARO_TRANSCODE` | Kratzplatz fürs Umrechnen. Am besten auf eine SSD. | `/transcode` | | `ASPNETCORE_URLS` | Worauf gelauscht wird | `http://+:8080` | | `TZ` | Zeitzone | `UTC` | -| `HALO_RATELIMIT_SIGNIN` | Anmeldeversuche je Minute und Adresse | `10` | -| `HALO_RATELIMIT_POLLING` | Nachfragen je Minute und Adresse | `120` | +| `FLARO_RATELIMIT_SIGNIN` | Anmeldeversuche je Minute und Adresse | `10` | +| `FLARO_RATELIMIT_POLLING` | Nachfragen je Minute und Adresse | `120` | **Medienpfade stehen hier nicht.** Sie werden in der Oberfläche als Bibliotheken angelegt und liegen in der Datenbank — sonst müsste der Container @@ -60,7 +60,7 @@ diese Meldung stünde dort nur „unable to open database file". ### Hardware fürs Umrechnen -`/dev/dri` durchreichen — VAAPI deckt Intel wie AMD ab. Fehlt es, rechnet Halo +`/dev/dri` durchreichen — VAAPI deckt Intel wie AMD ab. Fehlt es, rechnet Flaro in Software; das ist langsamer, aber es läuft. **Zum blossen Umpacken wird gar keine Hardware gebraucht**, und das ist der Weg, der den meisten Beständen hilft. @@ -69,7 +69,7 @@ hilft. ```bash dotnet test # 293 Tests -dotnet run --project src/Halo.Api # auf http://localhost:5000 +dotnet run --project src/Flaro.Api # auf http://localhost:5000 ``` Ohne gesetzte Variablen legt der Server `data/`, `cache/` und `transcode/` @@ -77,10 +77,10 @@ neben dem Programm an. ```bash # Image bauen, beide Architekturen -docker buildx build --platform linux/amd64,linux/arm64 -t halo:dev . +docker buildx build --platform linux/amd64,linux/arm64 -t flaro:dev . # Eine Migration nach einer Modelländerung -dotnet ef migrations add --project src/Halo.Data --startup-project src/Halo.Api --output-dir Migrations +dotnet ef migrations add --project src/Flaro.Data --startup-project src/Flaro.Api --output-dir Migrations ``` Migrationen wandern **beim Start** des Servers, nicht über ein eigenes @@ -90,13 +90,13 @@ Kommando. | Projekt | Aufgabe | |---|---| -| `Halo.Core` | Domäne: Benutzer, Anmeldung, Bibliotheken. Kennt kein HTTP und keine Datenbank | -| `Halo.Data` | EF Core, SQLite, Migrationen | -| `Halo.Media` | ffprobe und ffmpeg. Als eigene Prozesse, nicht eingebunden | -| `Halo.Metadata` | TMDB und die Bildablage. Hinter einer Schnittstelle, damit alles andere ohne Netz prüfbar bleibt | -| `Halo.Api` | Endpunkte, Authentifizierung, Auslieferung der Oberfläche | +| `Flaro.Core` | Domäne: Benutzer, Anmeldung, Bibliotheken. Kennt kein HTTP und keine Datenbank | +| `Flaro.Data` | EF Core, SQLite, Migrationen | +| `Flaro.Media` | ffprobe und ffmpeg. Als eigene Prozesse, nicht eingebunden | +| `Flaro.Metadata` | TMDB und die Bildablage. Hinter einer Schnittstelle, damit alles andere ohne Netz prüfbar bleibt | +| `Flaro.Api` | Endpunkte, Authentifizierung, Auslieferung der Oberfläche | -Was sicherheitsrelevant ist, liegt in `Halo.Core` — dort ist es ohne Server +Was sicherheitsrelevant ist, liegt in `Flaro.Core` — dort ist es ohne Server prüfbar, und die Tests dazu sind die, die am meisten wert sind. ### Zwei Entscheidungen, die beim Lesen Fragen aufwerfen @@ -133,7 +133,7 @@ und ändert sich dabei. ### Metadaten -**Halo bringt einen TMDB-Zugang mit** — es läuft ohne Einrichtung. Wer lieber +**Flaro bringt einen TMDB-Zugang mit** — es läuft ohne Einrichtung. Wer lieber seinen eigenen benutzt, hinterlegt ihn unter `PUT /api/v1/settings/metadata`; der sticht den mitgelieferten. Abgefragt werden kann nur, *ob* einer da ist und ob es der mitgelieferte ist — der Zugang selbst kommt nie zurück. @@ -144,8 +144,8 @@ in der Adresse, und kann nur lesen) oder der ältere **API Key**. Die Sprache steht auf `en-US` und wird in denselben Einstellungen umgestellt. -Bilder werden einmal heruntergeladen und liegen unter `HALO_CACHE`. Die App -holt sie bei Halo, nicht bei TMDB: sonst bräuchte sie dafür Internet, und TMDB +Bilder werden einmal heruntergeladen und liegen unter `FLARO_CACHE`. Die App +holt sie bei Flaro, nicht bei TMDB: sonst bräuchte sie dafür Internet, und TMDB erführe, wer wann was ansieht. **Der Hinweis auf TMDB ist Pflicht, keine Höflichkeit.** Deren Bedingungen @@ -182,12 +182,12 @@ geschehen. **Umgepackt wird auf die Platte, nicht in die Antwort.** Der bequeme Weg wäre, ffmpeg unmittelbar durchzureichen — dann kennt aber niemand die Länge im Voraus: kein Fortschrittsbalken, kein Fortsetzen, kein Springen. Dafür gibt es -`HALO_TRANSCODE`. +`FLARO_TRANSCODE`. | Variable | Bedeutung | Voreinstellung | |---|---|---| -| `HALO_FFMPEG` | Pfad zu ffmpeg | `ffmpeg` | -| `HALO_FFPROBE` | Pfad zu ffprobe | `ffprobe` | +| `FLARO_FFMPEG` | Pfad zu ffmpeg | `ffmpeg` | +| `FLARO_FFPROBE` | Pfad zu ffprobe | `ffprobe` | ## Zuordnung korrigieren @@ -213,7 +213,7 @@ Nur Administratoren, denn es ändert die Mediathek für alle. ## Beiwerk im Medienordner -Mit `HALO_WRITE_SIDECARS=true` legt Halo Plakate, Hintergründe und +Mit `FLARO_WRITE_SIDECARS=true` legt Flaro Plakate, Hintergründe und NFO-Dateien neben den Film: ``` @@ -230,20 +230,20 @@ Serien bekommen `tvshow.nfo` eine Ebene über dem Staffelordner, Folgen je eine NFO und ein Standbild neben der Datei. **Standardmässig aus**, und die Medieneinhängung muss dafür ohne `:ro` -auskommen. Was Halo schreiben darf, steht als Erlaubnisliste im Code +auskommen. Was Flaro schreiben darf, steht als Erlaubnisliste im Code (`SidecarNames`): alles andere wird abgelehnt, und Mediendateien werden nie geändert, umbenannt oder gelöscht. Transcode-Zwischenstände kommen nie in -einen Medienordner — die liegen unter `HALO_TRANSCODE`. +einen Medienordner — die liegen unter `FLARO_TRANSCODE`. **Gelesen wird auch ohne Schreiberlaubnis.** Eine vorhandene NFO ist eine -Zuordnung, die jemand getroffen hat; Halo nimmt sie und sucht gar nicht erst. +Zuordnung, die jemand getroffen hat; Flaro nimmt sie und sucht gar nicht erst. Dasselbe gilt für Ordnernamen der Form `Der Untergang (2004) [tmdbid-613]` — -Halo liest sie, benennt aber **nichts** um. Umbenennen ist der einzige +Flaro liest sie, benennt aber **nichts** um. Umbenennen ist der einzige Eingriff, der eine Bibliothek wirklich zerlegen kann. | Variable | Bedeutung | Voreinstellung | |---|---|---| -| `HALO_WRITE_SIDECARS` | Beiwerk in den Medienordner schreiben | `false` | +| `FLARO_WRITE_SIDECARS` | Beiwerk in den Medienordner schreiben | `false` | ## Anmeldung am Fernseher diff --git a/server/docker-compose.example.yml b/server/docker-compose.example.yml index 4f690b2..24c0d36 100644 --- a/server/docker-compose.example.yml +++ b/server/docker-compose.example.yml @@ -4,9 +4,9 @@ # Form ist bewährt, die Werte sind es nur dort. services: - halo: - image: ghcr.io/scarriffle/halo:latest - container_name: halo + flaro: + image: ghcr.io/scarriffle/flaro:latest + container_name: flaro restart: unless-stopped ports: @@ -27,7 +27,7 @@ services: # # Der Gewinn: dein Bestand wird tragbar. Ein Umzug, ein Neuaufbau der # Datenbank oder ein zweiter Server finden Zuordnungen und Bilder wieder. - - HALO_WRITE_SIDECARS=true + - FLARO_WRITE_SIDECARS=true # Wem die Dateien auf dem Wirt gehören. 1000:1000 ist die Voreinstellung # im Image; wer andere Kennungen hat, trägt sie hier ein — `id -u` und @@ -36,10 +36,10 @@ services: volumes: # Datenbank und Einstellungen. **Das Einzige, was gesichert werden muss.** - - /volume4/CRITICAL/Docker/Halo/config:/config + - /volume4/CRITICAL/Docker/Flaro/config:/config # Bilder und Zwischenstände. Darf verlorengehen, baut sich neu auf. - - /volume4/CRITICAL/Docker/Halo/cache:/cache + - /volume4/CRITICAL/Docker/Flaro/cache:/cache # Kratzplatz fürs Umrechnen. Am besten auf eine SSD und nicht dorthin, # wo die Medien liegen — hier wird viel und kurzlebig geschrieben. @@ -47,9 +47,9 @@ services: # Die Medien. # - # **Ohne `:ro`, weil HALO_WRITE_SIDECARS oben an ist.** Wer das nicht + # **Ohne `:ro`, weil FLARO_WRITE_SIDECARS oben an ist.** Wer das nicht # will, setzt die Variable auf `false` und hängt wieder mit `:ro` ein — - # dann bleiben Bilder und Metadaten nur in Halos Cache, und der Bestand + # dann bleiben Bilder und Metadaten nur in Flaros Cache, und der Bestand # ist gegen jeden Zugriff des Servers geschützt. # # Transcode-Zwischenstände kommen hier **nie** her; die liegen auf dem @@ -60,7 +60,7 @@ services: - /volume4/MYFLIX:/media # Hardware fürs Umrechnen. Intel wie AMD laufen über VAAPI an derselben - # Stelle. Fehlt die Zeile, rechnet Halo in Software — langsamer, aber es + # Stelle. Fehlt die Zeile, rechnet Flaro in Software — langsamer, aber es # läuft. Zum blossen Umpacken wird sie ohnehin nicht gebraucht. devices: - /dev/dri:/dev/dri diff --git a/server/src/Halo.Api/Auth/TokenAuthentication.cs b/server/src/Flaro.Api/Auth/TokenAuthentication.cs similarity index 91% rename from server/src/Halo.Api/Auth/TokenAuthentication.cs rename to server/src/Flaro.Api/Auth/TokenAuthentication.cs index 8df59d7..6104973 100644 --- a/server/src/Halo.Api/Auth/TokenAuthentication.cs +++ b/server/src/Flaro.Api/Auth/TokenAuthentication.cs @@ -1,12 +1,12 @@ using System.Security.Claims; using System.Text.Encodings.Web; -using Halo.Core.Auth; -using Halo.Data; +using Flaro.Core.Auth; +using Flaro.Data; using Microsoft.AspNetCore.Authentication; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Options; -namespace Halo.Api.Auth; +namespace Flaro.Api.Auth; /// Weist Anfragen über ein Geräte-Token aus. /// @@ -26,11 +26,11 @@ public sealed class TokenAuthenticationHandler( IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, - HaloContext db, + FlaroContext db, TimeProvider clock) : AuthenticationHandler(options, logger, encoder) { - public const string SchemeName = "HaloToken"; - public const string DeviceTokenIdClaim = "halo:device"; + public const string SchemeName = "FlaroToken"; + public const string DeviceTokenIdClaim = "flaro:device"; protected override async Task HandleAuthenticateAsync() { @@ -66,14 +66,14 @@ public sealed class TokenAuthenticationHandler( new Claim(ClaimTypes.NameIdentifier, benutzer.Id.ToString()), new Claim(ClaimTypes.Name, benutzer.UserName), new Claim(DeviceTokenIdClaim, eintrag.Id.ToString()), - .. benutzer.IsAdministrator ? new[] { new Claim(ClaimTypes.Role, HaloRoles.Administrator) } : [], + .. benutzer.IsAdministrator ? new[] { new Claim(ClaimTypes.Role, FlaroRoles.Administrator) } : [], ], SchemeName); return AuthenticateResult.Success(new AuthenticationTicket(new ClaimsPrincipal(ausweis), SchemeName)); } } -public static class HaloRoles +public static class FlaroRoles { public const string Administrator = "administrator"; } diff --git a/server/src/Halo.Api/Endpoints/AuthEndpoints.cs b/server/src/Flaro.Api/Endpoints/AuthEndpoints.cs similarity index 89% rename from server/src/Halo.Api/Endpoints/AuthEndpoints.cs rename to server/src/Flaro.Api/Endpoints/AuthEndpoints.cs index 8c79be6..4ee009f 100644 --- a/server/src/Halo.Api/Endpoints/AuthEndpoints.cs +++ b/server/src/Flaro.Api/Endpoints/AuthEndpoints.cs @@ -1,11 +1,11 @@ using System.Security.Claims; -using Halo.Api.Auth; -using Halo.Core.Auth; -using Halo.Core.Users; -using Halo.Data; +using Flaro.Api.Auth; +using Flaro.Core.Auth; +using Flaro.Core.Users; +using Flaro.Data; using Microsoft.EntityFrameworkCore; -namespace Halo.Api.Endpoints; +namespace Flaro.Api.Endpoints; public static class AuthEndpoints { @@ -23,7 +23,7 @@ public static class AuthEndpoints public static void MapAuth(this IEndpointRouteBuilder app) { app.MapPost("/api/v1/auth/login", async ( - LoginRequest anfrage, HaloContext db, TimeProvider clock) => + LoginRequest anfrage, FlaroContext db, TimeProvider clock) => { var name = anfrage.UserName.Trim(); var benutzer = await db.Users.FirstOrDefaultAsync(u => u.UserName == name); @@ -46,9 +46,9 @@ public static class AuthEndpoints var antwort = await TokenAusstellen(db, clock, benutzer, anfrage.DeviceName, anfrage.DeviceId); await db.SaveChangesAsync(); return Results.Ok(antwort); - }).AllowAnonymous().RequireRateLimiting(HaloRateLimits.SignIn); + }).AllowAnonymous().RequireRateLimiting(FlaroRateLimits.SignIn); - app.MapPost("/api/v1/auth/logout", async (ClaimsPrincipal wer, HaloContext db, TimeProvider clock) => + app.MapPost("/api/v1/auth/logout", async (ClaimsPrincipal wer, FlaroContext db, TimeProvider clock) => { if (!Guid.TryParse(wer.FindFirstValue(TokenAuthenticationHandler.DeviceTokenIdClaim), out var id)) return Results.Unauthorized(); @@ -67,7 +67,7 @@ public static class AuthEndpoints ? Results.Ok(new AuthenticatedUser( id, wer.FindFirstValue(ClaimTypes.Name) ?? "", - wer.IsInRole(HaloRoles.Administrator))) + wer.IsInRole(FlaroRoles.Administrator))) : Results.Unauthorized()) .RequireAuthorization(); @@ -77,7 +77,7 @@ public static class AuthEndpoints /// Anmelden mit einem Code auf dem Bildschirm. private static void MapCodeFlow(IEndpointRouteBuilder app) { - app.MapPost("/api/v1/auth/code", async (CodeRequest anfrage, HaloContext db, TimeProvider clock) => + app.MapPost("/api/v1/auth/code", async (CodeRequest anfrage, FlaroContext db, TimeProvider clock) => { var jetzt = clock.GetUtcNow(); @@ -99,10 +99,10 @@ public static class AuthEndpoints await db.SaveChangesAsync(); return Results.Ok(new CodeResponse(code.Code, abholschein, code.ExpiresAt)); - }).AllowAnonymous().RequireRateLimiting(HaloRateLimits.SignIn); + }).AllowAnonymous().RequireRateLimiting(FlaroRateLimits.SignIn); app.MapGet("/api/v1/auth/code/{handle}", async ( - string handle, HaloContext db, TimeProvider clock) => + string handle, FlaroContext db, TimeProvider clock) => { var jetzt = clock.GetUtcNow(); var fingerabdruck = Secrets.Fingerprint(handle); @@ -124,10 +124,10 @@ public static class AuthEndpoints await db.SaveChangesAsync(); return Results.Ok(new CodeState("approved", antwort)); - }).AllowAnonymous().RequireRateLimiting(HaloRateLimits.Polling); + }).AllowAnonymous().RequireRateLimiting(FlaroRateLimits.Polling); app.MapPost("/api/v1/auth/code/{code}", async ( - string code, ClaimsPrincipal wer, HaloContext db, TimeProvider clock) => + string code, ClaimsPrincipal wer, FlaroContext db, TimeProvider clock) => { if (!Guid.TryParse(wer.FindFirstValue(ClaimTypes.NameIdentifier), out var benutzerId)) return Results.Unauthorized(); @@ -144,7 +144,7 @@ public static class AuthEndpoints // Damit am Telefon steht, was man da gerade hereinlässt. return Results.Ok(new { device = offen.DeviceName }); - }).RequireAuthorization().RequireRateLimiting(HaloRateLimits.SignIn); + }).RequireAuthorization().RequireRateLimiting(FlaroRateLimits.SignIn); } /// Stellt ein Geräte-Token aus und löst ein älteres desselben Geräts ab. @@ -155,7 +155,7 @@ public static class AuthEndpoints /// und nach einem Jahr weiss niemand mehr, welches Telefon welches ist. /// private static async Task TokenAusstellen( - HaloContext db, TimeProvider clock, User benutzer, string geräteName, string geräteKennung) + FlaroContext db, TimeProvider clock, User benutzer, string geräteName, string geräteKennung) { var jetzt = clock.GetUtcNow(); var kennung = Kürzen(geräteKennung, 128); diff --git a/server/src/Halo.Api/Endpoints/Contracts.cs b/server/src/Flaro.Api/Endpoints/Contracts.cs similarity index 99% rename from server/src/Halo.Api/Endpoints/Contracts.cs rename to server/src/Flaro.Api/Endpoints/Contracts.cs index 2066aa7..0575885 100644 --- a/server/src/Halo.Api/Endpoints/Contracts.cs +++ b/server/src/Flaro.Api/Endpoints/Contracts.cs @@ -1,4 +1,4 @@ -namespace Halo.Api.Endpoints; +namespace Flaro.Api.Endpoints; // Was über die Leitung geht. Bewusst eigene Typen und nicht die der Domäne: // sonst wandert jede Umbenennung im Datenmodell ungefragt in die Schnittstelle diff --git a/server/src/Halo.Api/Endpoints/DeliveryEndpoints.cs b/server/src/Flaro.Api/Endpoints/DeliveryEndpoints.cs similarity index 93% rename from server/src/Halo.Api/Endpoints/DeliveryEndpoints.cs rename to server/src/Flaro.Api/Endpoints/DeliveryEndpoints.cs index aa90ad2..892146d 100644 --- a/server/src/Halo.Api/Endpoints/DeliveryEndpoints.cs +++ b/server/src/Flaro.Api/Endpoints/DeliveryEndpoints.cs @@ -1,16 +1,16 @@ -using Halo.Core.Delivery; -using Halo.Core.Library; -using Halo.Data; +using Flaro.Core.Delivery; +using Flaro.Core.Library; +using Flaro.Data; using Microsoft.EntityFrameworkCore; -namespace Halo.Api.Endpoints; +namespace Flaro.Api.Endpoints; public static class DeliveryEndpoints { public static void MapDelivery(this IEndpointRouteBuilder app) { app.MapGet("/api/v1/files/{id:guid}/delivery", async ( - Guid id, HaloContext db, PackageCoordinator packer) => + Guid id, FlaroContext db, PackageCoordinator packer) => { var gefunden = await Laden(db, id); if (gefunden is not var (datei, plan)) return Results.NotFound(); @@ -19,7 +19,7 @@ public static class DeliveryEndpoints }).RequireAuthorization(); app.MapGet("/api/v1/files/{id:guid}/download", async ( - Guid id, HaloContext db, PackageCoordinator packer) => + Guid id, FlaroContext db, PackageCoordinator packer) => { var gefunden = await Laden(db, id); if (gefunden is not var (datei, plan)) return Results.NotFound(); @@ -64,7 +64,7 @@ public static class DeliveryEndpoints }).RequireAuthorization(); } - private static async Task<(MediaFile Datei, DeliveryPlan Plan)?> Laden(HaloContext db, Guid id) + private static async Task<(MediaFile Datei, DeliveryPlan Plan)?> Laden(FlaroContext db, Guid id) { var datei = await db.MediaFiles.AsNoTracking().FirstOrDefaultAsync(f => f.Id == id); if (datei is null) return null; diff --git a/server/src/Halo.Api/Endpoints/ImageEndpoints.cs b/server/src/Flaro.Api/Endpoints/ImageEndpoints.cs similarity index 95% rename from server/src/Halo.Api/Endpoints/ImageEndpoints.cs rename to server/src/Flaro.Api/Endpoints/ImageEndpoints.cs index 1d8b566..e6e05e2 100644 --- a/server/src/Halo.Api/Endpoints/ImageEndpoints.cs +++ b/server/src/Flaro.Api/Endpoints/ImageEndpoints.cs @@ -1,7 +1,7 @@ -using Halo.Metadata; +using Flaro.Metadata; using Microsoft.AspNetCore.Mvc; -namespace Halo.Api.Endpoints; +namespace Flaro.Api.Endpoints; public static class ImageEndpoints { diff --git a/server/src/Halo.Api/Endpoints/LibraryContentEndpoints.cs b/server/src/Flaro.Api/Endpoints/LibraryContentEndpoints.cs similarity index 94% rename from server/src/Halo.Api/Endpoints/LibraryContentEndpoints.cs rename to server/src/Flaro.Api/Endpoints/LibraryContentEndpoints.cs index 5a6ce4d..11a1472 100644 --- a/server/src/Halo.Api/Endpoints/LibraryContentEndpoints.cs +++ b/server/src/Flaro.Api/Endpoints/LibraryContentEndpoints.cs @@ -1,7 +1,7 @@ -using Halo.Data; +using Flaro.Data; using Microsoft.EntityFrameworkCore; -namespace Halo.Api.Endpoints; +namespace Flaro.Api.Endpoints; public static class LibraryContentEndpoints { @@ -26,7 +26,7 @@ public static class LibraryContentEndpoints /// Je Datei einzeln zu fragen hiesse: fünfzig Titel, fünfzig Abfragen — /// und SQLite führt die nacheinander aus. /// - private static async Task> SpurenZu(HaloContext db, List dateien) + private static async Task> SpurenZu(FlaroContext db, List dateien) { if (dateien.Count == 0) return Array.Empty<(Guid, MediaStreamResponse)>().ToLookup(x => x.Item1, x => x.Item2); @@ -48,7 +48,7 @@ public static class LibraryContentEndpoints private static void MapScan(IEndpointRouteBuilder app) { app.MapPost("/api/v1/libraries/{id:guid}/scan", async ( - Guid id, HaloContext db, ScanCoordinator koordinator) => + Guid id, FlaroContext db, ScanCoordinator koordinator) => { if (!await db.Libraries.AnyAsync(l => l.Id == id)) return Results.NotFound(); @@ -57,7 +57,7 @@ public static class LibraryContentEndpoints : Results.Problem( "Für diese Bibliothek läuft bereits ein Scan.", statusCode: StatusCodes.Status409Conflict); - }).RequireAuthorization(HaloPolicies.Administrator); + }).RequireAuthorization(FlaroPolicies.Administrator); app.MapGet("/api/v1/libraries/{id:guid}/scan", (Guid id, ScanCoordinator koordinator) => { @@ -82,7 +82,7 @@ public static class LibraryContentEndpoints private static void MapBrowse(IEndpointRouteBuilder app) { app.MapGet("/api/v1/movies", async ( - HaloContext db, Guid? library, string? search, int skip = 0, int take = 50) => + FlaroContext db, Guid? library, string? search, int skip = 0, int take = 50) => { var abfrage = db.Movies.AsNoTracking(); if (library is { } kennung) abfrage = abfrage.Where(m => m.LibraryId == kennung); @@ -115,7 +115,7 @@ public static class LibraryContentEndpoints }).RequireAuthorization(); app.MapGet("/api/v1/series", async ( - HaloContext db, Guid? library, string? search, int skip = 0, int take = 50) => + FlaroContext db, Guid? library, string? search, int skip = 0, int take = 50) => { var abfrage = db.Series.AsNoTracking(); if (library is { } kennung) abfrage = abfrage.Where(s => s.LibraryId == kennung); @@ -146,7 +146,7 @@ public static class LibraryContentEndpoints return Results.Ok(new Page(items, gesamt)); }).RequireAuthorization(); - app.MapGet("/api/v1/series/{id:guid}/episodes", async (Guid id, HaloContext db, int? season) => + app.MapGet("/api/v1/series/{id:guid}/episodes", async (Guid id, FlaroContext db, int? season) => { if (!await db.Series.AnyAsync(s => s.Id == id)) return Results.NotFound(); diff --git a/server/src/Halo.Api/Endpoints/ManagementEndpoints.cs b/server/src/Flaro.Api/Endpoints/ManagementEndpoints.cs similarity index 88% rename from server/src/Halo.Api/Endpoints/ManagementEndpoints.cs rename to server/src/Flaro.Api/Endpoints/ManagementEndpoints.cs index e7db424..eba52d5 100644 --- a/server/src/Halo.Api/Endpoints/ManagementEndpoints.cs +++ b/server/src/Flaro.Api/Endpoints/ManagementEndpoints.cs @@ -1,24 +1,24 @@ -using Halo.Api.Auth; -using Halo.Core.Libraries; -using Halo.Core.Users; -using Halo.Data; +using Flaro.Api.Auth; +using Flaro.Core.Libraries; +using Flaro.Core.Users; +using Flaro.Data; using Microsoft.EntityFrameworkCore; -namespace Halo.Api.Endpoints; +namespace Flaro.Api.Endpoints; public static class ManagementEndpoints { public static void MapManagement(this IEndpointRouteBuilder app) { - var benutzer = app.MapGroup("/api/v1/users").RequireAuthorization(HaloPolicies.Administrator); + var benutzer = app.MapGroup("/api/v1/users").RequireAuthorization(FlaroPolicies.Administrator); - benutzer.MapGet("/", async (HaloContext db) => + benutzer.MapGet("/", async (FlaroContext db) => Results.Ok(await db.Users .OrderBy(u => u.UserName) .Select(u => new AuthenticatedUser(u.Id, u.UserName, u.IsAdministrator)) .ToListAsync())); - benutzer.MapPost("/", async (CreateUserRequest anfrage, HaloContext db) => + benutzer.MapPost("/", async (CreateUserRequest anfrage, FlaroContext db) => { var name = anfrage.UserName.Trim(); if (name.Length == 0 || anfrage.Password.Length < 8) @@ -45,14 +45,14 @@ public static class ManagementEndpoints var bibliotheken = app.MapGroup("/api/v1/libraries"); // Lesen darf jeder Angemeldete — ohne die Liste zeigt die App nichts an. - bibliotheken.MapGet("/", async (HaloContext db) => + bibliotheken.MapGet("/", async (FlaroContext db) => Results.Ok(await db.Libraries .OrderBy(l => l.Name) .Select(l => new LibraryResponse(l.Id, l.Name, l.Kind.ToString(), l.Path)) .ToListAsync())) .RequireAuthorization(); - bibliotheken.MapPost("/", async (CreateLibraryRequest anfrage, HaloContext db) => + bibliotheken.MapPost("/", async (CreateLibraryRequest anfrage, FlaroContext db) => { if (!Enum.TryParse(anfrage.Kind, ignoreCase: true, out var art)) return Results.ValidationProblem(new Dictionary @@ -75,16 +75,16 @@ public static class ManagementEndpoints await db.SaveChangesAsync(); return Results.Created($"/api/v1/libraries/{neu.Id}", new LibraryResponse(neu.Id, neu.Name, neu.Kind.ToString(), neu.Path)); - }).RequireAuthorization(HaloPolicies.Administrator); + }).RequireAuthorization(FlaroPolicies.Administrator); } } -public static class HaloPolicies +public static class FlaroPolicies { public const string Administrator = "administrator-only"; } -public static class HaloRateLimits +public static class FlaroRateLimits { /// Für alles, was ein Geheimnis prüft. public const string SignIn = "sign-in"; diff --git a/server/src/Halo.Api/Endpoints/MatchEndpoints.cs b/server/src/Flaro.Api/Endpoints/MatchEndpoints.cs similarity index 84% rename from server/src/Halo.Api/Endpoints/MatchEndpoints.cs rename to server/src/Flaro.Api/Endpoints/MatchEndpoints.cs index a6024e0..ac5de8b 100644 --- a/server/src/Halo.Api/Endpoints/MatchEndpoints.cs +++ b/server/src/Flaro.Api/Endpoints/MatchEndpoints.cs @@ -1,9 +1,9 @@ -using Halo.Core.Library; -using Halo.Core.Metadata; -using Halo.Data; +using Flaro.Core.Library; +using Flaro.Core.Metadata; +using Flaro.Data; using Microsoft.EntityFrameworkCore; -namespace Halo.Api.Endpoints; +namespace Flaro.Api.Endpoints; /// Eine falsche Zuordnung von Hand richtigstellen. /// @@ -26,7 +26,7 @@ public static class MatchEndpoints public static void MapMatching(this IEndpointRouteBuilder app) { app.MapGet("/api/v1/movies/{id:guid}/matches", async ( - Guid id, HaloContext db, IMetadataProvider anbieter, string? query, int? year) => + Guid id, FlaroContext db, IMetadataProvider anbieter, string? query, int? year) => { var film = await db.Movies.AsNoTracking().FirstOrDefaultAsync(m => m.Id == id); if (film is null) return Results.NotFound(); @@ -38,10 +38,10 @@ public static class MatchEndpoints return Results.Ok(vorschläge.Select(v => new MatchCandidate(v.ProviderId, v.Title, v.Year, v.Overview, v.Poster?.Url)).ToList()); - }).RequireAuthorization(HaloPolicies.Administrator); + }).RequireAuthorization(FlaroPolicies.Administrator); app.MapPut("/api/v1/movies/{id:guid}/match", async ( - Guid id, ApplyMatchRequest anfrage, HaloContext db, + Guid id, ApplyMatchRequest anfrage, FlaroContext db, IMetadataProvider anbieter, MatchApplier anwender) => { var film = await db.Movies.FirstOrDefaultAsync(m => m.Id == id); @@ -54,10 +54,10 @@ public static class MatchEndpoints await anwender.ApplyAsync(film, gefunden); return Results.Ok(new MatchState(film.TmdbId, film.ImdbId, film.MatchLocked, film.Title, film.Year)); - }).RequireAuthorization(HaloPolicies.Administrator); + }).RequireAuthorization(FlaroPolicies.Administrator); app.MapGet("/api/v1/series/{id:guid}/matches", async ( - Guid id, HaloContext db, IMetadataProvider anbieter, string? query, int? year) => + Guid id, FlaroContext db, IMetadataProvider anbieter, string? query, int? year) => { var serie = await db.Series.AsNoTracking().FirstOrDefaultAsync(s => s.Id == id); if (serie is null) return Results.NotFound(); @@ -67,10 +67,10 @@ public static class MatchEndpoints return Results.Ok(vorschläge.Select(v => new MatchCandidate(v.ProviderId, v.Title, v.Year, v.Overview, v.Poster?.Url)).ToList()); - }).RequireAuthorization(HaloPolicies.Administrator); + }).RequireAuthorization(FlaroPolicies.Administrator); app.MapPut("/api/v1/series/{id:guid}/match", async ( - Guid id, ApplyMatchRequest anfrage, HaloContext db, + Guid id, ApplyMatchRequest anfrage, FlaroContext db, IMetadataProvider anbieter, MatchApplier anwender) => { var serie = await db.Series.FirstOrDefaultAsync(s => s.Id == id); @@ -83,6 +83,6 @@ public static class MatchEndpoints await anwender.ApplyAsync(serie, gefunden); return Results.Ok(new MatchState(serie.TmdbId, serie.ImdbId, serie.MatchLocked, serie.Title, serie.Year)); - }).RequireAuthorization(HaloPolicies.Administrator); + }).RequireAuthorization(FlaroPolicies.Administrator); } } diff --git a/server/src/Halo.Api/Endpoints/SettingsEndpoints.cs b/server/src/Flaro.Api/Endpoints/SettingsEndpoints.cs similarity index 84% rename from server/src/Halo.Api/Endpoints/SettingsEndpoints.cs rename to server/src/Flaro.Api/Endpoints/SettingsEndpoints.cs index f9ec169..7607242 100644 --- a/server/src/Halo.Api/Endpoints/SettingsEndpoints.cs +++ b/server/src/Flaro.Api/Endpoints/SettingsEndpoints.cs @@ -1,15 +1,15 @@ -using Halo.Core; -using Halo.Data; -using Halo.Metadata; +using Flaro.Core; +using Flaro.Data; +using Flaro.Metadata; using Microsoft.EntityFrameworkCore; -namespace Halo.Api.Endpoints; +namespace Flaro.Api.Endpoints; public static class SettingsEndpoints { public static void MapSettings(this IEndpointRouteBuilder app) { - app.MapGet("/api/v1/settings/metadata", async (HaloContext db) => + app.MapGet("/api/v1/settings/metadata", async (FlaroContext db) => { var zeilen = await db.Settings.AsNoTracking() .Where(s => s.Key == DatabaseTmdbSettings.ApiKeyName || s.Key == DatabaseTmdbSettings.LanguageName) @@ -28,10 +28,10 @@ public static class SettingsEndpoints // Damit in der Oberfläche steht, ob der mitgelieferte Schlüssel // benutzt wird — und dass ein eigener ihn ablösen würde. UsingProjectKey: aufgelöst.UsingProjectKey)); - }).RequireAuthorization(HaloPolicies.Administrator); + }).RequireAuthorization(FlaroPolicies.Administrator); app.MapPut("/api/v1/settings/metadata", async ( - MetadataSettingsRequest anfrage, HaloContext db) => + MetadataSettingsRequest anfrage, FlaroContext db) => { if (anfrage.ApiKey is not null) await Setzen(db, DatabaseTmdbSettings.ApiKeyName, anfrage.ApiKey.Trim()); if (anfrage.Language is not null) @@ -49,10 +49,10 @@ public static class SettingsEndpoints await db.SaveChangesAsync(); return Results.NoContent(); - }).RequireAuthorization(HaloPolicies.Administrator); + }).RequireAuthorization(FlaroPolicies.Administrator); } - private static async Task Setzen(HaloContext db, string schlüssel, string wert) + private static async Task Setzen(FlaroContext db, string schlüssel, string wert) { var vorhanden = await db.Settings.FindAsync(schlüssel); if (vorhanden is null) db.Settings.Add(new ServerSetting { Key = schlüssel, Value = wert }); diff --git a/server/src/Halo.Api/Endpoints/SystemEndpoints.cs b/server/src/Flaro.Api/Endpoints/SystemEndpoints.cs similarity index 93% rename from server/src/Halo.Api/Endpoints/SystemEndpoints.cs rename to server/src/Flaro.Api/Endpoints/SystemEndpoints.cs index 5ef5811..9344a42 100644 --- a/server/src/Halo.Api/Endpoints/SystemEndpoints.cs +++ b/server/src/Flaro.Api/Endpoints/SystemEndpoints.cs @@ -1,9 +1,9 @@ -using Halo.Core.Users; -using Halo.Metadata; -using Halo.Data; +using Flaro.Core.Users; +using Flaro.Metadata; +using Flaro.Data; using Microsoft.EntityFrameworkCore; -namespace Halo.Api.Endpoints; +namespace Flaro.Api.Endpoints; public static class SystemEndpoints { @@ -18,7 +18,7 @@ public static class SystemEndpoints public static void MapSystem(this IEndpointRouteBuilder app) { - app.MapGet("/api/v1/system/info", async (HaloContext db) => + app.MapGet("/api/v1/system/info", async (FlaroContext db) => Results.Ok(new SystemInfo( Version: typeof(SystemEndpoints).Assembly.GetName().Version?.ToString(3) ?? "0.0.0", NeedsSetup: !await db.Users.AnyAsync(), @@ -30,7 +30,7 @@ public static class SystemEndpoints ]))) .AllowAnonymous(); - app.MapPost("/api/v1/system/setup", async (SetupRequest anfrage, HaloContext db) => + app.MapPost("/api/v1/system/setup", async (SetupRequest anfrage, FlaroContext db) => { if (string.IsNullOrWhiteSpace(anfrage.UserName) || anfrage.Password.Length < 8) return Results.ValidationProblem(new Dictionary diff --git a/server/src/Halo.Api/Halo.Api.csproj b/server/src/Flaro.Api/Flaro.Api.csproj similarity index 65% rename from server/src/Halo.Api/Halo.Api.csproj rename to server/src/Flaro.Api/Flaro.Api.csproj index ccea93a..ccf464e 100644 --- a/server/src/Halo.Api/Halo.Api.csproj +++ b/server/src/Flaro.Api/Flaro.Api.csproj @@ -1,10 +1,10 @@ - - - - + + + + diff --git a/server/src/Halo.Api/HaloPaths.cs b/server/src/Flaro.Api/FlaroPaths.cs similarity index 84% rename from server/src/Halo.Api/HaloPaths.cs rename to server/src/Flaro.Api/FlaroPaths.cs index 33810a2..93b2d1c 100644 --- a/server/src/Halo.Api/HaloPaths.cs +++ b/server/src/Flaro.Api/FlaroPaths.cs @@ -1,4 +1,4 @@ -namespace Halo.Api; +namespace Flaro.Api; /// Wo der Server seine Sachen ablegt. /// @@ -21,26 +21,26 @@ namespace Halo.Api; /// Container neu starten, um eine Bibliothek hinzuzufügen. /// /// -public sealed class HaloPaths +public sealed class FlaroPaths { public required string Data { get; init; } public required string Cache { get; init; } public required string Transcode { get; init; } - public string DatabaseFile => Path.Combine(Data, "halo.db"); + public string DatabaseFile => Path.Combine(Data, "flaro.db"); - public static HaloPaths FromEnvironment(string contentRoot) + public static FlaroPaths FromEnvironment(string contentRoot) { string lies(string name, string voreinstellung) => Environment.GetEnvironmentVariable(name) is { Length: > 0 } wert ? wert : Path.Combine(contentRoot, voreinstellung); - return new HaloPaths + return new FlaroPaths { - Data = lies("HALO_DATA", "data"), - Cache = lies("HALO_CACHE", "cache"), - Transcode = lies("HALO_TRANSCODE", "transcode"), + Data = lies("FLARO_DATA", "data"), + Cache = lies("FLARO_CACHE", "cache"), + Transcode = lies("FLARO_TRANSCODE", "transcode"), }; } @@ -62,13 +62,13 @@ public sealed class HaloPaths /// public void EnsureExists() { - foreach (var (name, pfad) in new[] { ("HALO_DATA", Data), ("HALO_CACHE", Cache), ("HALO_TRANSCODE", Transcode) }) + foreach (var (name, pfad) in new[] { ("FLARO_DATA", Data), ("FLARO_CACHE", Cache), ("FLARO_TRANSCODE", Transcode) }) { try { Directory.CreateDirectory(pfad); - var probe = Path.Combine(pfad, $".halo-schreibprobe-{Environment.ProcessId}"); + var probe = Path.Combine(pfad, $".flaro-schreibprobe-{Environment.ProcessId}"); File.WriteAllBytes(probe, []); File.Delete(probe); } @@ -78,7 +78,7 @@ public sealed class HaloPaths $""" {name} zeigt auf „{pfad}“, und dort lässt sich nicht schreiben. - Halo läuft als Benutzer {Kennung()}. Dieses Verzeichnis muss + Flaro läuft als Benutzer {Kennung()}. Dieses Verzeichnis muss ihm gehören oder für ihn beschreibbar sein. Im Container ist das fast immer die Einhängung: entweder gehört diff --git a/server/src/Halo.Api/MatchApplier.cs b/server/src/Flaro.Api/MatchApplier.cs similarity index 98% rename from server/src/Halo.Api/MatchApplier.cs rename to server/src/Flaro.Api/MatchApplier.cs index 3b96660..77bd3e9 100644 --- a/server/src/Halo.Api/MatchApplier.cs +++ b/server/src/Flaro.Api/MatchApplier.cs @@ -1,9 +1,9 @@ -using Halo.Core.Library; -using Halo.Core.Metadata; -using Halo.Data; +using Flaro.Core.Library; +using Flaro.Core.Metadata; +using Flaro.Data; using Microsoft.EntityFrameworkCore; -namespace Halo.Api; +namespace Flaro.Api; /// Schreibt eine korrigierte Zuordnung überallhin, wo sie hingehört. /// @@ -14,7 +14,7 @@ namespace Halo.Api; /// Entscheidung wieder überstimmt. /// public sealed class MatchApplier( - HaloContext db, + FlaroContext db, IMetadataProvider anbieter, IImageStore bilder, IImageReader bildLeser, diff --git a/server/src/Halo.Api/MetadataSettings.cs b/server/src/Flaro.Api/MetadataSettings.cs similarity index 82% rename from server/src/Halo.Api/MetadataSettings.cs rename to server/src/Flaro.Api/MetadataSettings.cs index a13edd9..6b1a615 100644 --- a/server/src/Halo.Api/MetadataSettings.cs +++ b/server/src/Flaro.Api/MetadataSettings.cs @@ -1,20 +1,20 @@ -using Halo.Data; -using Halo.Metadata; +using Flaro.Data; +using Flaro.Metadata; using Microsoft.EntityFrameworkCore; -namespace Halo.Api; +namespace Flaro.Api; /// Holt die Metadaten-Einstellungen aus der Datenbank. /// /// -/// Hier und nicht in Halo.Data: sonst müsste die Datenschicht +/// Hier und nicht in Flaro.Data: sonst müsste die Datenschicht /// den Metadaten-Anbieter kennen. So zeigen beide Richtungen auf den Kern und /// keine aufeinander. /// /// Je Anfrage einmal gelesen und dann gemerkt. Ohne das fragte ein Scan über /// tausend Titel tausendmal dieselbe Zeile ab. /// -public sealed class DatabaseTmdbSettings(HaloContext db) : ITmdbSettingsSource +public sealed class DatabaseTmdbSettings(FlaroContext db) : ITmdbSettingsSource { public const string ApiKeyName = "metadata.tmdb.apiKey"; public const string LanguageName = "metadata.language"; diff --git a/server/src/Halo.Api/PackageCoordinator.cs b/server/src/Flaro.Api/PackageCoordinator.cs similarity index 96% rename from server/src/Halo.Api/PackageCoordinator.cs rename to server/src/Flaro.Api/PackageCoordinator.cs index a05e56c..7de433d 100644 --- a/server/src/Halo.Api/PackageCoordinator.cs +++ b/server/src/Flaro.Api/PackageCoordinator.cs @@ -1,11 +1,11 @@ using System.Collections.Concurrent; -using Halo.Core.Delivery; -using Halo.Core.Library; -using Halo.Data; -using Halo.Media; +using Flaro.Core.Delivery; +using Flaro.Core.Library; +using Flaro.Data; +using Flaro.Media; using Microsoft.EntityFrameworkCore; -namespace Halo.Api; +namespace Flaro.Api; public sealed record PackageState( string Status, @@ -27,12 +27,12 @@ public sealed record PackageState( /// /// /// Der Preis ist Plattenplatz und Wartezeit vor dem ersten Byte. Dafür gibt -/// es HALO_TRANSCODE, und dafür meldet dieser Weg einen Fortschritt. +/// es FLARO_TRANSCODE, und dafür meldet dieser Weg einen Fortschritt. /// /// public sealed class PackageCoordinator( IServiceScopeFactory scopes, - HaloPaths pfade, + FlaroPaths pfade, TimeProvider clock, ILogger log) { @@ -77,7 +77,7 @@ public sealed class PackageCoordinator( try { using var bereich = scopes.CreateScope(); - var db = bereich.ServiceProvider.GetRequiredService(); + var db = bereich.ServiceProvider.GetRequiredService(); var datei = await db.MediaFiles.AsNoTracking().FirstOrDefaultAsync(f => f.Id == fileId) ?? throw new InvalidOperationException("Diese Datei steht nicht mehr in der Mediathek."); diff --git a/server/src/Halo.Api/Program.cs b/server/src/Flaro.Api/Program.cs similarity index 84% rename from server/src/Halo.Api/Program.cs rename to server/src/Flaro.Api/Program.cs index 776d9bf..a7dc27d 100644 --- a/server/src/Halo.Api/Program.cs +++ b/server/src/Flaro.Api/Program.cs @@ -1,24 +1,24 @@ using System.Threading.RateLimiting; -using Halo.Api; -using Halo.Api.Auth; -using Halo.Api.Endpoints; -using Halo.Core.Metadata; -using Halo.Data; -using Halo.Core.Library; -using Halo.Media; -using Halo.Metadata; +using Flaro.Api; +using Flaro.Api.Auth; +using Flaro.Api.Endpoints; +using Flaro.Core.Metadata; +using Flaro.Data; +using Flaro.Core.Library; +using Flaro.Media; +using Flaro.Metadata; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.RateLimiting; using Microsoft.EntityFrameworkCore; var builder = WebApplication.CreateBuilder(args); -var pfade = HaloPaths.FromEnvironment(builder.Environment.ContentRootPath); +var pfade = FlaroPaths.FromEnvironment(builder.Environment.ContentRootPath); pfade.EnsureExists(); builder.Services.AddSingleton(pfade); builder.Services.AddSingleton(TimeProvider.System); -builder.Services.AddDbContext(o => o.UseSqlite($"Data Source={pfade.DatabaseFile}")); +builder.Services.AddDbContext(o => o.UseSqlite($"Data Source={pfade.DatabaseFile}")); builder.Services .AddAuthentication(TokenAuthenticationHandler.SchemeName) @@ -31,9 +31,9 @@ builder.Services.AddAuthorizationBuilder() // dem irgendwann einer vergessen wird. .SetFallbackPolicy(new Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder() .RequireAuthenticatedUser().Build()) - .AddPolicy(HaloPolicies.Administrator, p => p.RequireRole(HaloRoles.Administrator)); + .AddPolicy(FlaroPolicies.Administrator, p => p.RequireRole(FlaroRoles.Administrator)); -// Einstellbar, weil die richtige Zahl vom Aufbau abhängt: steht Halo hinter +// Einstellbar, weil die richtige Zahl vom Aufbau abhängt: steht Flaro hinter // einem Reverse Proxy, erscheinen **alle** Benutzer unter derselben Adresse // und teilen sich einen Eimer. Wer das nicht weiss, hält die eigene App für // kaputt, während in Wahrheit der Nachbar im selben Haus gerade angemeldet hat. @@ -47,16 +47,16 @@ int grenze(string name, int voreinstellung) => builder.Services.AddRateLimiter(o => { o.RejectionStatusCode = StatusCodes.Status429TooManyRequests; - var beimAnmelden = grenze("HALO_RATELIMIT_SIGNIN", 10); - var beimNachfragen = grenze("HALO_RATELIMIT_POLLING", 120); + var beimAnmelden = grenze("FLARO_RATELIMIT_SIGNIN", 10); + var beimNachfragen = grenze("FLARO_RATELIMIT_POLLING", 120); // Je Absender, nicht global: sonst sperrt ein einzelner Angreifer den // ganzen Haushalt aus, und die Abwehr wäre selbst der Ausfall. - o.AddPolicy(HaloRateLimits.SignIn, anfrage => RateLimitPartition.GetFixedWindowLimiter( + o.AddPolicy(FlaroRateLimits.SignIn, anfrage => RateLimitPartition.GetFixedWindowLimiter( anfrage.Connection.RemoteIpAddress?.ToString() ?? "unbekannt", _ => new FixedWindowRateLimiterOptions { PermitLimit = beimAnmelden, Window = TimeSpan.FromMinutes(1) })); - o.AddPolicy(HaloRateLimits.Polling, anfrage => RateLimitPartition.GetFixedWindowLimiter( + o.AddPolicy(FlaroRateLimits.Polling, anfrage => RateLimitPartition.GetFixedWindowLimiter( anfrage.Connection.RemoteIpAddress?.ToString() ?? "unbekannt", _ => new FixedWindowRateLimiterOptions { PermitLimit = beimNachfragen, Window = TimeSpan.FromMinutes(1) })); }); @@ -100,7 +100,7 @@ var app = builder.Build(); // hochfährt, soll nicht erst eine Migration von Hand anstossen müssen. using (var bereich = app.Services.CreateScope()) { - await bereich.ServiceProvider.GetRequiredService().Database.MigrateAsync(); + await bereich.ServiceProvider.GetRequiredService().Database.MigrateAsync(); } app.UseExceptionHandler(); diff --git a/server/src/Halo.Api/Properties/launchSettings.json b/server/src/Flaro.Api/Properties/launchSettings.json similarity index 100% rename from server/src/Halo.Api/Properties/launchSettings.json rename to server/src/Flaro.Api/Properties/launchSettings.json diff --git a/server/src/Halo.Api/ScanCoordinator.cs b/server/src/Flaro.Api/ScanCoordinator.cs similarity index 98% rename from server/src/Halo.Api/ScanCoordinator.cs rename to server/src/Flaro.Api/ScanCoordinator.cs index a03bef7..84158e5 100644 --- a/server/src/Halo.Api/ScanCoordinator.cs +++ b/server/src/Flaro.Api/ScanCoordinator.cs @@ -1,7 +1,7 @@ using System.Collections.Concurrent; -using Halo.Data; +using Flaro.Data; -namespace Halo.Api; +namespace Flaro.Api; public sealed record ScanState( string Status, diff --git a/server/src/Halo.Api/appsettings.Development.json b/server/src/Flaro.Api/appsettings.Development.json similarity index 100% rename from server/src/Halo.Api/appsettings.Development.json rename to server/src/Flaro.Api/appsettings.Development.json diff --git a/server/src/Halo.Api/appsettings.json b/server/src/Flaro.Api/appsettings.json similarity index 100% rename from server/src/Halo.Api/appsettings.json rename to server/src/Flaro.Api/appsettings.json diff --git a/server/src/Halo.Core/Auth/AuthCode.cs b/server/src/Flaro.Core/Auth/AuthCode.cs similarity index 98% rename from server/src/Halo.Core/Auth/AuthCode.cs rename to server/src/Flaro.Core/Auth/AuthCode.cs index 7ca70ed..d2744dd 100644 --- a/server/src/Halo.Core/Auth/AuthCode.cs +++ b/server/src/Flaro.Core/Auth/AuthCode.cs @@ -1,6 +1,6 @@ using System.Security.Cryptography; -namespace Halo.Core.Auth; +namespace Flaro.Core.Auth; /// Eine laufende Anmeldung per Code — für den Fernseher. /// diff --git a/server/src/Halo.Core/Auth/DeviceToken.cs b/server/src/Flaro.Core/Auth/DeviceToken.cs similarity index 97% rename from server/src/Halo.Core/Auth/DeviceToken.cs rename to server/src/Flaro.Core/Auth/DeviceToken.cs index 7a079c4..becd684 100644 --- a/server/src/Halo.Core/Auth/DeviceToken.cs +++ b/server/src/Flaro.Core/Auth/DeviceToken.cs @@ -1,4 +1,4 @@ -namespace Halo.Core.Auth; +namespace Flaro.Core.Auth; /// Ein angemeldetes Gerät. /// diff --git a/server/src/Halo.Core/Auth/Secrets.cs b/server/src/Flaro.Core/Auth/Secrets.cs similarity index 97% rename from server/src/Halo.Core/Auth/Secrets.cs rename to server/src/Flaro.Core/Auth/Secrets.cs index 2142cfb..ddecaf3 100644 --- a/server/src/Halo.Core/Auth/Secrets.cs +++ b/server/src/Flaro.Core/Auth/Secrets.cs @@ -1,7 +1,7 @@ using System.Security.Cryptography; using System.Text; -namespace Halo.Core.Auth; +namespace Flaro.Core.Auth; /// Erzeugt und verfingert Geheimnisse, die Clients vorzeigen. /// diff --git a/server/src/Halo.Core/Delivery/DeliveryDecider.cs b/server/src/Flaro.Core/Delivery/DeliveryDecider.cs similarity index 98% rename from server/src/Halo.Core/Delivery/DeliveryDecider.cs rename to server/src/Flaro.Core/Delivery/DeliveryDecider.cs index e5ce7a4..1be610a 100644 --- a/server/src/Halo.Core/Delivery/DeliveryDecider.cs +++ b/server/src/Flaro.Core/Delivery/DeliveryDecider.cs @@ -1,6 +1,6 @@ -using Halo.Core.Library; +using Flaro.Core.Library; -namespace Halo.Core.Delivery; +namespace Flaro.Core.Delivery; public enum DeliveryMethod { diff --git a/server/src/Halo.Core/Delivery/DeviceProfile.cs b/server/src/Flaro.Core/Delivery/DeviceProfile.cs similarity index 98% rename from server/src/Halo.Core/Delivery/DeviceProfile.cs rename to server/src/Flaro.Core/Delivery/DeviceProfile.cs index f30067f..7ad7b98 100644 --- a/server/src/Halo.Core/Delivery/DeviceProfile.cs +++ b/server/src/Flaro.Core/Delivery/DeviceProfile.cs @@ -1,4 +1,4 @@ -namespace Halo.Core.Delivery; +namespace Flaro.Core.Delivery; /// Was ein Gerät von sich aus öffnen kann. /// diff --git a/server/src/Halo.Core/Halo.Core.csproj b/server/src/Flaro.Core/Flaro.Core.csproj similarity index 100% rename from server/src/Halo.Core/Halo.Core.csproj rename to server/src/Flaro.Core/Flaro.Core.csproj diff --git a/server/src/Halo.Core/Libraries/Library.cs b/server/src/Flaro.Core/Libraries/Library.cs similarity index 85% rename from server/src/Halo.Core/Libraries/Library.cs rename to server/src/Flaro.Core/Libraries/Library.cs index 5e26baf..fc249e0 100644 --- a/server/src/Halo.Core/Libraries/Library.cs +++ b/server/src/Flaro.Core/Libraries/Library.cs @@ -1,4 +1,4 @@ -namespace Halo.Core.Libraries; +namespace Flaro.Core.Libraries; public enum LibraryKind { Movies, Shows } @@ -7,7 +7,7 @@ public enum LibraryKind { Movies, Shows } /// /// In der Datenbank und nicht in der Umgebung. Stünden Medienpfade in /// der Compose-Datei, müsste der Container neu starten, um eine Bibliothek -/// hinzuzufügen — und ein Fremder, der Halo zum ersten Mal startet, hätte +/// hinzuzufügen — und ein Fremder, der Flaro zum ersten Mal startet, hätte /// keine Datei, in der schon das Richtige steht. /// public sealed class Library diff --git a/server/src/Halo.Core/Library/FileNames.cs b/server/src/Flaro.Core/Library/FileNames.cs similarity index 99% rename from server/src/Halo.Core/Library/FileNames.cs rename to server/src/Flaro.Core/Library/FileNames.cs index 376d5dd..fb2f696 100644 --- a/server/src/Halo.Core/Library/FileNames.cs +++ b/server/src/Flaro.Core/Library/FileNames.cs @@ -1,7 +1,7 @@ using System.Globalization; using System.Text.RegularExpressions; -namespace Halo.Core.Library; +namespace Flaro.Core.Library; public sealed record MovieName(string Title, int? Year); diff --git a/server/src/Halo.Core/Library/IMediaProbe.cs b/server/src/Flaro.Core/Library/IMediaProbe.cs similarity index 96% rename from server/src/Halo.Core/Library/IMediaProbe.cs rename to server/src/Flaro.Core/Library/IMediaProbe.cs index da44104..004ca67 100644 --- a/server/src/Halo.Core/Library/IMediaProbe.cs +++ b/server/src/Flaro.Core/Library/IMediaProbe.cs @@ -1,4 +1,4 @@ -namespace Halo.Core.Library; +namespace Flaro.Core.Library; /// Was in einer Datei steckt. public sealed record ProbeResult( diff --git a/server/src/Halo.Core/Library/ISidecarStore.cs b/server/src/Flaro.Core/Library/ISidecarStore.cs similarity index 97% rename from server/src/Halo.Core/Library/ISidecarStore.cs rename to server/src/Flaro.Core/Library/ISidecarStore.cs index 6262b5f..905ed55 100644 --- a/server/src/Halo.Core/Library/ISidecarStore.cs +++ b/server/src/Flaro.Core/Library/ISidecarStore.cs @@ -1,4 +1,4 @@ -namespace Halo.Core.Library; +namespace Flaro.Core.Library; /// Legt Beiwerk neben eine Mediendatei. /// diff --git a/server/src/Halo.Core/Library/LibraryWalker.cs b/server/src/Flaro.Core/Library/LibraryWalker.cs similarity index 99% rename from server/src/Halo.Core/Library/LibraryWalker.cs rename to server/src/Flaro.Core/Library/LibraryWalker.cs index 109aa4e..22a7369 100644 --- a/server/src/Halo.Core/Library/LibraryWalker.cs +++ b/server/src/Flaro.Core/Library/LibraryWalker.cs @@ -1,4 +1,4 @@ -namespace Halo.Core.Library; +namespace Flaro.Core.Library; /// Eine gefundene Datei, so wie das Dateisystem sie beschreibt. public sealed record ScannedFile(string Path, long SizeBytes, DateTimeOffset ModifiedAt); diff --git a/server/src/Halo.Core/Library/MediaEntities.cs b/server/src/Flaro.Core/Library/MediaEntities.cs similarity index 99% rename from server/src/Halo.Core/Library/MediaEntities.cs rename to server/src/Flaro.Core/Library/MediaEntities.cs index b334524..8fc59e3 100644 --- a/server/src/Halo.Core/Library/MediaEntities.cs +++ b/server/src/Flaro.Core/Library/MediaEntities.cs @@ -1,4 +1,4 @@ -namespace Halo.Core.Library; +namespace Flaro.Core.Library; /// Eine Datei auf der Platte, so wie der Scan sie vorgefunden hat. /// diff --git a/server/src/Halo.Core/Library/MediaExtensions.cs b/server/src/Flaro.Core/Library/MediaExtensions.cs similarity index 98% rename from server/src/Halo.Core/Library/MediaExtensions.cs rename to server/src/Flaro.Core/Library/MediaExtensions.cs index a0d7afa..a885fa9 100644 --- a/server/src/Halo.Core/Library/MediaExtensions.cs +++ b/server/src/Flaro.Core/Library/MediaExtensions.cs @@ -1,4 +1,4 @@ -namespace Halo.Core.Library; +namespace Flaro.Core.Library; /// Welche Dateien überhaupt als Medien gelten. /// diff --git a/server/src/Halo.Core/Library/MediaStreams.cs b/server/src/Flaro.Core/Library/MediaStreams.cs similarity index 98% rename from server/src/Halo.Core/Library/MediaStreams.cs rename to server/src/Flaro.Core/Library/MediaStreams.cs index a9da49d..cd97281 100644 --- a/server/src/Halo.Core/Library/MediaStreams.cs +++ b/server/src/Flaro.Core/Library/MediaStreams.cs @@ -1,4 +1,4 @@ -namespace Halo.Core.Library; +namespace Flaro.Core.Library; public enum MediaStreamKind { Video, Audio, Subtitle } diff --git a/server/src/Halo.Core/Library/Nfo.cs b/server/src/Flaro.Core/Library/Nfo.cs similarity index 99% rename from server/src/Halo.Core/Library/Nfo.cs rename to server/src/Flaro.Core/Library/Nfo.cs index 605268f..4c6c19c 100644 --- a/server/src/Halo.Core/Library/Nfo.cs +++ b/server/src/Flaro.Core/Library/Nfo.cs @@ -1,7 +1,7 @@ using System.Xml; using System.Xml.Linq; -namespace Halo.Core.Library; +namespace Flaro.Core.Library; public sealed record MovieNfo( string Title, int? Year, string? Plot, ProviderIds Ids, bool Locked); @@ -132,7 +132,7 @@ public static class Nfo /// /// /// DTDs sind abgeschaltet und es wird nichts nachgeladen. Diese - /// Dateien liegen im Medienordner, und was dort liegt, hat Halo nicht + /// Dateien liegen im Medienordner, und was dort liegt, hat Flaro nicht /// geschrieben — eine NFO mit einer externen Entität könnte sonst den /// Server dazu bringen, fremde Dateien zu lesen und auszuliefern. /// diff --git a/server/src/Halo.Core/Library/ProviderIds.cs b/server/src/Flaro.Core/Library/ProviderIds.cs similarity index 91% rename from server/src/Halo.Core/Library/ProviderIds.cs rename to server/src/Flaro.Core/Library/ProviderIds.cs index 13c8324..c594b93 100644 --- a/server/src/Halo.Core/Library/ProviderIds.cs +++ b/server/src/Flaro.Core/Library/ProviderIds.cs @@ -1,6 +1,6 @@ using System.Text.RegularExpressions; -namespace Halo.Core.Library; +namespace Flaro.Core.Library; /// Kennungen bei Metadatenquellen, wie sie in Namen stehen können. public sealed record ProviderIds(int? Tmdb, string? Imdb) @@ -16,10 +16,10 @@ public sealed record ProviderIds(int? Tmdb, string? Imdb) /// Die Form stammt von Kodi und wird von Jellyfin gelesen: /// Der Untergang (2004) [tmdbid-613]. Wer seine Ordner so benennt — /// von Hand oder über Radarr —, hat seine Zuordnung damit festgeschrieben, -/// und Halo soll sie nicht erneut erraten. +/// und Flaro soll sie nicht erneut erraten. /// /// -/// Halo benennt nichts um. Es liest nur. Festgeschrieben wird eine +/// Flaro benennt nichts um. Es liest nur. Festgeschrieben wird eine /// Korrektur in der NFO-Datei — dieselbe Wirkung, ohne den einen Eingriff, /// der eine Bibliothek wirklich zerlegen kann. /// diff --git a/server/src/Halo.Core/Library/SidecarNames.cs b/server/src/Flaro.Core/Library/SidecarNames.cs similarity index 94% rename from server/src/Halo.Core/Library/SidecarNames.cs rename to server/src/Flaro.Core/Library/SidecarNames.cs index 7ccc783..54fdf35 100644 --- a/server/src/Halo.Core/Library/SidecarNames.cs +++ b/server/src/Flaro.Core/Library/SidecarNames.cs @@ -1,6 +1,6 @@ -namespace Halo.Core.Library; +namespace Flaro.Core.Library; -/// Welche Dateien Halo neben eine Mediendatei legen darf — und sonst keine. +/// Welche Dateien Flaro neben eine Mediendatei legen darf — und sonst keine. /// /// /// @@ -17,7 +17,7 @@ namespace Halo.Core.Library; /// /// /// Transcode-Zwischenstände gehören ausdrücklich nicht hierher. Die -/// liegen unter HALO_TRANSCODE, auf einem eigenen Volume. Ein +/// liegen unter FLARO_TRANSCODE, auf einem eigenen Volume. Ein /// Medienordner ist kein Kratzplatz. /// /// diff --git a/server/src/Halo.Core/Library/SortTitle.cs b/server/src/Flaro.Core/Library/SortTitle.cs similarity index 97% rename from server/src/Halo.Core/Library/SortTitle.cs rename to server/src/Flaro.Core/Library/SortTitle.cs index e13758f..9c77cbc 100644 --- a/server/src/Halo.Core/Library/SortTitle.cs +++ b/server/src/Flaro.Core/Library/SortTitle.cs @@ -1,4 +1,4 @@ -namespace Halo.Core.Library; +namespace Flaro.Core.Library; /// Der Titel, nach dem sortiert wird — ohne den Artikel davor. /// diff --git a/server/src/Halo.Core/Metadata/IMetadataProvider.cs b/server/src/Flaro.Core/Metadata/IMetadataProvider.cs similarity index 99% rename from server/src/Halo.Core/Metadata/IMetadataProvider.cs rename to server/src/Flaro.Core/Metadata/IMetadataProvider.cs index 995f22e..4610d26 100644 --- a/server/src/Halo.Core/Metadata/IMetadataProvider.cs +++ b/server/src/Flaro.Core/Metadata/IMetadataProvider.cs @@ -1,4 +1,4 @@ -namespace Halo.Core.Metadata; +namespace Flaro.Core.Metadata; /// Ein Bild bei der Quelle — noch nicht heruntergeladen. public sealed record RemoteImage(string Url); diff --git a/server/src/Halo.Core/Settings.cs b/server/src/Flaro.Core/Settings.cs similarity index 95% rename from server/src/Halo.Core/Settings.cs rename to server/src/Flaro.Core/Settings.cs index 8468190..be6a0ae 100644 --- a/server/src/Halo.Core/Settings.cs +++ b/server/src/Flaro.Core/Settings.cs @@ -1,4 +1,4 @@ -namespace Halo.Core; +namespace Flaro.Core; /// Eine Einstellung des Servers, als Zeile in der Datenbank. /// diff --git a/server/src/Halo.Core/Users/PasswordHasher.cs b/server/src/Flaro.Core/Users/PasswordHasher.cs similarity index 99% rename from server/src/Halo.Core/Users/PasswordHasher.cs rename to server/src/Flaro.Core/Users/PasswordHasher.cs index c98eac8..5570dc2 100644 --- a/server/src/Halo.Core/Users/PasswordHasher.cs +++ b/server/src/Flaro.Core/Users/PasswordHasher.cs @@ -2,7 +2,7 @@ using System.Security.Cryptography; using System.Text; using Konscious.Security.Cryptography; -namespace Halo.Core.Users; +namespace Flaro.Core.Users; /// Passwörter als Argon2id, im PHC-Format abgelegt. /// diff --git a/server/src/Halo.Core/Users/User.cs b/server/src/Flaro.Core/Users/User.cs similarity index 96% rename from server/src/Halo.Core/Users/User.cs rename to server/src/Flaro.Core/Users/User.cs index e99a897..a2ade8c 100644 --- a/server/src/Halo.Core/Users/User.cs +++ b/server/src/Flaro.Core/Users/User.cs @@ -1,4 +1,4 @@ -namespace Halo.Core.Users; +namespace Flaro.Core.Users; /// Ein Benutzerkonto. /// diff --git a/server/src/Halo.Data/Converters.cs b/server/src/Flaro.Data/Converters.cs similarity index 99% rename from server/src/Halo.Data/Converters.cs rename to server/src/Flaro.Data/Converters.cs index feab212..83d5f67 100644 --- a/server/src/Halo.Data/Converters.cs +++ b/server/src/Flaro.Data/Converters.cs @@ -1,6 +1,6 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -namespace Halo.Data; +namespace Flaro.Data; /// Zeitpunkte als Unix-Millisekunden statt als Text. /// diff --git a/server/src/Halo.Data/Halo.Data.csproj b/server/src/Flaro.Data/Flaro.Data.csproj similarity index 90% rename from server/src/Halo.Data/Halo.Data.csproj rename to server/src/Flaro.Data/Flaro.Data.csproj index e8abc84..5da3a9e 100644 --- a/server/src/Halo.Data/Halo.Data.csproj +++ b/server/src/Flaro.Data/Flaro.Data.csproj @@ -1,7 +1,7 @@  - + diff --git a/server/src/Halo.Data/HaloContext.cs b/server/src/Flaro.Data/FlaroContext.cs similarity index 96% rename from server/src/Halo.Data/HaloContext.cs rename to server/src/Flaro.Data/FlaroContext.cs index 3691051..40248a3 100644 --- a/server/src/Halo.Data/HaloContext.cs +++ b/server/src/Flaro.Data/FlaroContext.cs @@ -1,11 +1,11 @@ -using Halo.Core; -using Halo.Core.Auth; -using Halo.Core.Libraries; -using Halo.Core.Library; -using Halo.Core.Users; +using Flaro.Core; +using Flaro.Core.Auth; +using Flaro.Core.Libraries; +using Flaro.Core.Library; +using Flaro.Core.Users; using Microsoft.EntityFrameworkCore; -namespace Halo.Data; +namespace Flaro.Data; /// Die Datenbank des Servers. /// @@ -19,7 +19,7 @@ namespace Halo.Data; /// nicht — dann ist der Umstieg auf PostgreSQL fällig, und deshalb steht hier /// nirgends SQLite-eigenes SQL. /// -public sealed class HaloContext(DbContextOptions options) : DbContext(options) +public sealed class FlaroContext(DbContextOptions options) : DbContext(options) { public DbSet Users => Set(); public DbSet DeviceTokens => Set(); diff --git a/server/src/Halo.Data/LibraryScanner.cs b/server/src/Flaro.Data/LibraryScanner.cs similarity index 98% rename from server/src/Halo.Data/LibraryScanner.cs rename to server/src/Flaro.Data/LibraryScanner.cs index 927405a..142eb14 100644 --- a/server/src/Halo.Data/LibraryScanner.cs +++ b/server/src/Flaro.Data/LibraryScanner.cs @@ -1,9 +1,9 @@ -using Halo.Core.Libraries; -using Halo.Core.Library; +using Flaro.Core.Libraries; +using Flaro.Core.Library; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; -namespace Halo.Data; +namespace Flaro.Data; public sealed record ScanReport( int FilesFound, @@ -31,7 +31,7 @@ public sealed record ScanReport( /// /// public sealed class LibraryScanner( - HaloContext db, IMediaProbe sonde, TimeProvider clock, ILogger log) + FlaroContext db, IMediaProbe sonde, TimeProvider clock, ILogger log) { public async Task ScanAsync(Guid libraryId, CancellationToken ct = default) { diff --git a/server/src/Halo.Data/MetadataEnricher.cs b/server/src/Flaro.Data/MetadataEnricher.cs similarity index 99% rename from server/src/Halo.Data/MetadataEnricher.cs rename to server/src/Flaro.Data/MetadataEnricher.cs index c77b6b9..9907549 100644 --- a/server/src/Halo.Data/MetadataEnricher.cs +++ b/server/src/Flaro.Data/MetadataEnricher.cs @@ -1,9 +1,9 @@ -using Halo.Core.Library; -using Halo.Core.Metadata; +using Flaro.Core.Library; +using Flaro.Core.Metadata; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; -namespace Halo.Data; +namespace Flaro.Data; public sealed record EnrichReport( int MoviesMatched, int SeriesMatched, int EpisodesMatched, bool Skipped, string? Error); @@ -25,7 +25,7 @@ public sealed record EnrichReport( /// /// public sealed class MetadataEnricher( - HaloContext db, + FlaroContext db, IMetadataProvider anbieter, IImageStore bilder, IImageReader bildLeser, diff --git a/server/src/Halo.Data/Migrations/20261003095500_Initial.Designer.cs b/server/src/Flaro.Data/Migrations/20261003095500_Initial.Designer.cs similarity index 91% rename from server/src/Halo.Data/Migrations/20261003095500_Initial.Designer.cs rename to server/src/Flaro.Data/Migrations/20261003095500_Initial.Designer.cs index c5e3f98..f99ebd3 100644 --- a/server/src/Halo.Data/Migrations/20261003095500_Initial.Designer.cs +++ b/server/src/Flaro.Data/Migrations/20261003095500_Initial.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Halo.Data; +using Flaro.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; @@ -8,9 +8,9 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion; #nullable disable -namespace Halo.Data.Migrations +namespace Flaro.Data.Migrations { - [DbContext(typeof(HaloContext))] + [DbContext(typeof(FlaroContext))] [Migration("20261003095500_Initial")] partial class Initial { @@ -20,7 +20,7 @@ namespace Halo.Data.Migrations #pragma warning disable 612, 618 modelBuilder.HasAnnotation("ProductVersion", "10.0.12"); - modelBuilder.Entity("Halo.Core.Auth.AuthCode", b => + modelBuilder.Entity("Flaro.Core.Auth.AuthCode", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -68,7 +68,7 @@ namespace Halo.Data.Migrations b.ToTable("AuthCodes"); }); - modelBuilder.Entity("Halo.Core.Auth.DeviceToken", b => + modelBuilder.Entity("Flaro.Core.Auth.DeviceToken", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -111,7 +111,7 @@ namespace Halo.Data.Migrations b.ToTable("DeviceTokens"); }); - modelBuilder.Entity("Halo.Core.Libraries.Library", b => + modelBuilder.Entity("Flaro.Core.Libraries.Library", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -140,7 +140,7 @@ namespace Halo.Data.Migrations b.ToTable("Libraries"); }); - modelBuilder.Entity("Halo.Core.ServerSetting", b => + modelBuilder.Entity("Flaro.Core.ServerSetting", b => { b.Property("Key") .HasMaxLength(128) @@ -156,7 +156,7 @@ namespace Halo.Data.Migrations b.ToTable("Settings"); }); - modelBuilder.Entity("Halo.Core.Users.User", b => + modelBuilder.Entity("Flaro.Core.Users.User", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -187,9 +187,9 @@ namespace Halo.Data.Migrations b.ToTable("Users"); }); - modelBuilder.Entity("Halo.Core.Auth.DeviceToken", b => + modelBuilder.Entity("Flaro.Core.Auth.DeviceToken", b => { - b.HasOne("Halo.Core.Users.User", null) + b.HasOne("Flaro.Core.Users.User", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) diff --git a/server/src/Halo.Data/Migrations/20261003095500_Initial.cs b/server/src/Flaro.Data/Migrations/20261003095500_Initial.cs similarity index 99% rename from server/src/Halo.Data/Migrations/20261003095500_Initial.cs rename to server/src/Flaro.Data/Migrations/20261003095500_Initial.cs index ec712be..87dac3c 100644 --- a/server/src/Halo.Data/Migrations/20261003095500_Initial.cs +++ b/server/src/Flaro.Data/Migrations/20261003095500_Initial.cs @@ -3,7 +3,7 @@ using Microsoft.EntityFrameworkCore.Migrations; #nullable disable -namespace Halo.Data.Migrations +namespace Flaro.Data.Migrations { /// public partial class Initial : Migration diff --git a/server/src/Halo.Data/Migrations/20261003115256_Mediathek.Designer.cs b/server/src/Flaro.Data/Migrations/20261003115256_Mediathek.Designer.cs similarity index 89% rename from server/src/Halo.Data/Migrations/20261003115256_Mediathek.Designer.cs rename to server/src/Flaro.Data/Migrations/20261003115256_Mediathek.Designer.cs index 6f8a33b..0666583 100644 --- a/server/src/Halo.Data/Migrations/20261003115256_Mediathek.Designer.cs +++ b/server/src/Flaro.Data/Migrations/20261003115256_Mediathek.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Halo.Data; +using Flaro.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; @@ -8,9 +8,9 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion; #nullable disable -namespace Halo.Data.Migrations +namespace Flaro.Data.Migrations { - [DbContext(typeof(HaloContext))] + [DbContext(typeof(FlaroContext))] [Migration("20261003115256_Mediathek")] partial class Mediathek { @@ -20,7 +20,7 @@ namespace Halo.Data.Migrations #pragma warning disable 612, 618 modelBuilder.HasAnnotation("ProductVersion", "10.0.12"); - modelBuilder.Entity("Halo.Core.Auth.AuthCode", b => + modelBuilder.Entity("Flaro.Core.Auth.AuthCode", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -68,7 +68,7 @@ namespace Halo.Data.Migrations b.ToTable("AuthCodes"); }); - modelBuilder.Entity("Halo.Core.Auth.DeviceToken", b => + modelBuilder.Entity("Flaro.Core.Auth.DeviceToken", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -111,7 +111,7 @@ namespace Halo.Data.Migrations b.ToTable("DeviceTokens"); }); - modelBuilder.Entity("Halo.Core.Libraries.Library", b => + modelBuilder.Entity("Flaro.Core.Libraries.Library", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -140,7 +140,7 @@ namespace Halo.Data.Migrations b.ToTable("Libraries"); }); - modelBuilder.Entity("Halo.Core.Library.Episode", b => + modelBuilder.Entity("Flaro.Core.Library.Episode", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -173,7 +173,7 @@ namespace Halo.Data.Migrations b.ToTable("Episodes"); }); - modelBuilder.Entity("Halo.Core.Library.MediaFile", b => + modelBuilder.Entity("Flaro.Core.Library.MediaFile", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -214,7 +214,7 @@ namespace Halo.Data.Migrations b.ToTable("MediaFiles"); }); - modelBuilder.Entity("Halo.Core.Library.Movie", b => + modelBuilder.Entity("Flaro.Core.Library.Movie", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -252,7 +252,7 @@ namespace Halo.Data.Migrations b.ToTable("Movies"); }); - modelBuilder.Entity("Halo.Core.Library.Series", b => + modelBuilder.Entity("Flaro.Core.Library.Series", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -290,7 +290,7 @@ namespace Halo.Data.Migrations b.ToTable("Series"); }); - modelBuilder.Entity("Halo.Core.ServerSetting", b => + modelBuilder.Entity("Flaro.Core.ServerSetting", b => { b.Property("Key") .HasMaxLength(128) @@ -306,7 +306,7 @@ namespace Halo.Data.Migrations b.ToTable("Settings"); }); - modelBuilder.Entity("Halo.Core.Users.User", b => + modelBuilder.Entity("Flaro.Core.Users.User", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -337,45 +337,45 @@ namespace Halo.Data.Migrations b.ToTable("Users"); }); - modelBuilder.Entity("Halo.Core.Auth.DeviceToken", b => + modelBuilder.Entity("Flaro.Core.Auth.DeviceToken", b => { - b.HasOne("Halo.Core.Users.User", null) + b.HasOne("Flaro.Core.Users.User", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Halo.Core.Library.Episode", b => + modelBuilder.Entity("Flaro.Core.Library.Episode", b => { - b.HasOne("Halo.Core.Library.Series", null) + b.HasOne("Flaro.Core.Library.Series", null) .WithMany() .HasForeignKey("SeriesId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Halo.Core.Library.MediaFile", b => + modelBuilder.Entity("Flaro.Core.Library.MediaFile", b => { - b.HasOne("Halo.Core.Libraries.Library", null) + b.HasOne("Flaro.Core.Libraries.Library", null) .WithMany() .HasForeignKey("LibraryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Halo.Core.Library.Movie", b => + modelBuilder.Entity("Flaro.Core.Library.Movie", b => { - b.HasOne("Halo.Core.Libraries.Library", null) + b.HasOne("Flaro.Core.Libraries.Library", null) .WithMany() .HasForeignKey("LibraryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Halo.Core.Library.Series", b => + modelBuilder.Entity("Flaro.Core.Library.Series", b => { - b.HasOne("Halo.Core.Libraries.Library", null) + b.HasOne("Flaro.Core.Libraries.Library", null) .WithMany() .HasForeignKey("LibraryId") .OnDelete(DeleteBehavior.Cascade) diff --git a/server/src/Halo.Data/Migrations/20261003115256_Mediathek.cs b/server/src/Flaro.Data/Migrations/20261003115256_Mediathek.cs similarity index 99% rename from server/src/Halo.Data/Migrations/20261003115256_Mediathek.cs rename to server/src/Flaro.Data/Migrations/20261003115256_Mediathek.cs index 39470c2..5c2b802 100644 --- a/server/src/Halo.Data/Migrations/20261003115256_Mediathek.cs +++ b/server/src/Flaro.Data/Migrations/20261003115256_Mediathek.cs @@ -3,7 +3,7 @@ using Microsoft.EntityFrameworkCore.Migrations; #nullable disable -namespace Halo.Data.Migrations +namespace Flaro.Data.Migrations { /// public partial class Mediathek : Migration diff --git a/server/src/Halo.Data/Migrations/20261003120100_Metadaten.Designer.cs b/server/src/Flaro.Data/Migrations/20261003120100_Metadaten.Designer.cs similarity index 90% rename from server/src/Halo.Data/Migrations/20261003120100_Metadaten.Designer.cs rename to server/src/Flaro.Data/Migrations/20261003120100_Metadaten.Designer.cs index f64f72f..cec8cda 100644 --- a/server/src/Halo.Data/Migrations/20261003120100_Metadaten.Designer.cs +++ b/server/src/Flaro.Data/Migrations/20261003120100_Metadaten.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Halo.Data; +using Flaro.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; @@ -8,9 +8,9 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion; #nullable disable -namespace Halo.Data.Migrations +namespace Flaro.Data.Migrations { - [DbContext(typeof(HaloContext))] + [DbContext(typeof(FlaroContext))] [Migration("20261003120100_Metadaten")] partial class Metadaten { @@ -20,7 +20,7 @@ namespace Halo.Data.Migrations #pragma warning disable 612, 618 modelBuilder.HasAnnotation("ProductVersion", "10.0.12"); - modelBuilder.Entity("Halo.Core.Auth.AuthCode", b => + modelBuilder.Entity("Flaro.Core.Auth.AuthCode", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -68,7 +68,7 @@ namespace Halo.Data.Migrations b.ToTable("AuthCodes"); }); - modelBuilder.Entity("Halo.Core.Auth.DeviceToken", b => + modelBuilder.Entity("Flaro.Core.Auth.DeviceToken", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -111,7 +111,7 @@ namespace Halo.Data.Migrations b.ToTable("DeviceTokens"); }); - modelBuilder.Entity("Halo.Core.Libraries.Library", b => + modelBuilder.Entity("Flaro.Core.Libraries.Library", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -140,7 +140,7 @@ namespace Halo.Data.Migrations b.ToTable("Libraries"); }); - modelBuilder.Entity("Halo.Core.Library.Episode", b => + modelBuilder.Entity("Flaro.Core.Library.Episode", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -176,7 +176,7 @@ namespace Halo.Data.Migrations b.ToTable("Episodes"); }); - modelBuilder.Entity("Halo.Core.Library.MediaFile", b => + modelBuilder.Entity("Flaro.Core.Library.MediaFile", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -217,7 +217,7 @@ namespace Halo.Data.Migrations b.ToTable("MediaFiles"); }); - modelBuilder.Entity("Halo.Core.Library.Movie", b => + modelBuilder.Entity("Flaro.Core.Library.Movie", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -261,7 +261,7 @@ namespace Halo.Data.Migrations b.ToTable("Movies"); }); - modelBuilder.Entity("Halo.Core.Library.Series", b => + modelBuilder.Entity("Flaro.Core.Library.Series", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -305,7 +305,7 @@ namespace Halo.Data.Migrations b.ToTable("Series"); }); - modelBuilder.Entity("Halo.Core.ServerSetting", b => + modelBuilder.Entity("Flaro.Core.ServerSetting", b => { b.Property("Key") .HasMaxLength(128) @@ -321,7 +321,7 @@ namespace Halo.Data.Migrations b.ToTable("Settings"); }); - modelBuilder.Entity("Halo.Core.Users.User", b => + modelBuilder.Entity("Flaro.Core.Users.User", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -352,45 +352,45 @@ namespace Halo.Data.Migrations b.ToTable("Users"); }); - modelBuilder.Entity("Halo.Core.Auth.DeviceToken", b => + modelBuilder.Entity("Flaro.Core.Auth.DeviceToken", b => { - b.HasOne("Halo.Core.Users.User", null) + b.HasOne("Flaro.Core.Users.User", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Halo.Core.Library.Episode", b => + modelBuilder.Entity("Flaro.Core.Library.Episode", b => { - b.HasOne("Halo.Core.Library.Series", null) + b.HasOne("Flaro.Core.Library.Series", null) .WithMany() .HasForeignKey("SeriesId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Halo.Core.Library.MediaFile", b => + modelBuilder.Entity("Flaro.Core.Library.MediaFile", b => { - b.HasOne("Halo.Core.Libraries.Library", null) + b.HasOne("Flaro.Core.Libraries.Library", null) .WithMany() .HasForeignKey("LibraryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Halo.Core.Library.Movie", b => + modelBuilder.Entity("Flaro.Core.Library.Movie", b => { - b.HasOne("Halo.Core.Libraries.Library", null) + b.HasOne("Flaro.Core.Libraries.Library", null) .WithMany() .HasForeignKey("LibraryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Halo.Core.Library.Series", b => + modelBuilder.Entity("Flaro.Core.Library.Series", b => { - b.HasOne("Halo.Core.Libraries.Library", null) + b.HasOne("Flaro.Core.Libraries.Library", null) .WithMany() .HasForeignKey("LibraryId") .OnDelete(DeleteBehavior.Cascade) diff --git a/server/src/Halo.Data/Migrations/20261003120100_Metadaten.cs b/server/src/Flaro.Data/Migrations/20261003120100_Metadaten.cs similarity index 98% rename from server/src/Halo.Data/Migrations/20261003120100_Metadaten.cs rename to server/src/Flaro.Data/Migrations/20261003120100_Metadaten.cs index 8bb9234..b84ed49 100644 --- a/server/src/Halo.Data/Migrations/20261003120100_Metadaten.cs +++ b/server/src/Flaro.Data/Migrations/20261003120100_Metadaten.cs @@ -2,7 +2,7 @@ #nullable disable -namespace Halo.Data.Migrations +namespace Flaro.Data.Migrations { /// public partial class Metadaten : Migration diff --git a/server/src/Halo.Data/Migrations/20261003123234_GeparsterTitel.Designer.cs b/server/src/Flaro.Data/Migrations/20261003123234_GeparsterTitel.Designer.cs similarity index 90% rename from server/src/Halo.Data/Migrations/20261003123234_GeparsterTitel.Designer.cs rename to server/src/Flaro.Data/Migrations/20261003123234_GeparsterTitel.Designer.cs index 88d9f04..8c1d7b0 100644 --- a/server/src/Halo.Data/Migrations/20261003123234_GeparsterTitel.Designer.cs +++ b/server/src/Flaro.Data/Migrations/20261003123234_GeparsterTitel.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Halo.Data; +using Flaro.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; @@ -8,9 +8,9 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion; #nullable disable -namespace Halo.Data.Migrations +namespace Flaro.Data.Migrations { - [DbContext(typeof(HaloContext))] + [DbContext(typeof(FlaroContext))] [Migration("20261003123234_GeparsterTitel")] partial class GeparsterTitel { @@ -20,7 +20,7 @@ namespace Halo.Data.Migrations #pragma warning disable 612, 618 modelBuilder.HasAnnotation("ProductVersion", "10.0.12"); - modelBuilder.Entity("Halo.Core.Auth.AuthCode", b => + modelBuilder.Entity("Flaro.Core.Auth.AuthCode", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -68,7 +68,7 @@ namespace Halo.Data.Migrations b.ToTable("AuthCodes"); }); - modelBuilder.Entity("Halo.Core.Auth.DeviceToken", b => + modelBuilder.Entity("Flaro.Core.Auth.DeviceToken", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -111,7 +111,7 @@ namespace Halo.Data.Migrations b.ToTable("DeviceTokens"); }); - modelBuilder.Entity("Halo.Core.Libraries.Library", b => + modelBuilder.Entity("Flaro.Core.Libraries.Library", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -140,7 +140,7 @@ namespace Halo.Data.Migrations b.ToTable("Libraries"); }); - modelBuilder.Entity("Halo.Core.Library.Episode", b => + modelBuilder.Entity("Flaro.Core.Library.Episode", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -176,7 +176,7 @@ namespace Halo.Data.Migrations b.ToTable("Episodes"); }); - modelBuilder.Entity("Halo.Core.Library.MediaFile", b => + modelBuilder.Entity("Flaro.Core.Library.MediaFile", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -217,7 +217,7 @@ namespace Halo.Data.Migrations b.ToTable("MediaFiles"); }); - modelBuilder.Entity("Halo.Core.Library.Movie", b => + modelBuilder.Entity("Flaro.Core.Library.Movie", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -265,7 +265,7 @@ namespace Halo.Data.Migrations b.ToTable("Movies"); }); - modelBuilder.Entity("Halo.Core.Library.Series", b => + modelBuilder.Entity("Flaro.Core.Library.Series", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -313,7 +313,7 @@ namespace Halo.Data.Migrations b.ToTable("Series"); }); - modelBuilder.Entity("Halo.Core.ServerSetting", b => + modelBuilder.Entity("Flaro.Core.ServerSetting", b => { b.Property("Key") .HasMaxLength(128) @@ -329,7 +329,7 @@ namespace Halo.Data.Migrations b.ToTable("Settings"); }); - modelBuilder.Entity("Halo.Core.Users.User", b => + modelBuilder.Entity("Flaro.Core.Users.User", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -360,45 +360,45 @@ namespace Halo.Data.Migrations b.ToTable("Users"); }); - modelBuilder.Entity("Halo.Core.Auth.DeviceToken", b => + modelBuilder.Entity("Flaro.Core.Auth.DeviceToken", b => { - b.HasOne("Halo.Core.Users.User", null) + b.HasOne("Flaro.Core.Users.User", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Halo.Core.Library.Episode", b => + modelBuilder.Entity("Flaro.Core.Library.Episode", b => { - b.HasOne("Halo.Core.Library.Series", null) + b.HasOne("Flaro.Core.Library.Series", null) .WithMany() .HasForeignKey("SeriesId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Halo.Core.Library.MediaFile", b => + modelBuilder.Entity("Flaro.Core.Library.MediaFile", b => { - b.HasOne("Halo.Core.Libraries.Library", null) + b.HasOne("Flaro.Core.Libraries.Library", null) .WithMany() .HasForeignKey("LibraryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Halo.Core.Library.Movie", b => + modelBuilder.Entity("Flaro.Core.Library.Movie", b => { - b.HasOne("Halo.Core.Libraries.Library", null) + b.HasOne("Flaro.Core.Libraries.Library", null) .WithMany() .HasForeignKey("LibraryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Halo.Core.Library.Series", b => + modelBuilder.Entity("Flaro.Core.Library.Series", b => { - b.HasOne("Halo.Core.Libraries.Library", null) + b.HasOne("Flaro.Core.Libraries.Library", null) .WithMany() .HasForeignKey("LibraryId") .OnDelete(DeleteBehavior.Cascade) diff --git a/server/src/Halo.Data/Migrations/20261003123234_GeparsterTitel.cs b/server/src/Flaro.Data/Migrations/20261003123234_GeparsterTitel.cs similarity index 97% rename from server/src/Halo.Data/Migrations/20261003123234_GeparsterTitel.cs rename to server/src/Flaro.Data/Migrations/20261003123234_GeparsterTitel.cs index f1753fd..9445ecf 100644 --- a/server/src/Halo.Data/Migrations/20261003123234_GeparsterTitel.cs +++ b/server/src/Flaro.Data/Migrations/20261003123234_GeparsterTitel.cs @@ -2,7 +2,7 @@ #nullable disable -namespace Halo.Data.Migrations +namespace Flaro.Data.Migrations { /// public partial class GeparsterTitel : Migration diff --git a/server/src/Halo.Data/Migrations/20261003150124_Spuren.Designer.cs b/server/src/Flaro.Data/Migrations/20261003150124_Spuren.Designer.cs similarity index 90% rename from server/src/Halo.Data/Migrations/20261003150124_Spuren.Designer.cs rename to server/src/Flaro.Data/Migrations/20261003150124_Spuren.Designer.cs index b1339e8..465c2b6 100644 --- a/server/src/Halo.Data/Migrations/20261003150124_Spuren.Designer.cs +++ b/server/src/Flaro.Data/Migrations/20261003150124_Spuren.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Halo.Data; +using Flaro.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; @@ -8,9 +8,9 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion; #nullable disable -namespace Halo.Data.Migrations +namespace Flaro.Data.Migrations { - [DbContext(typeof(HaloContext))] + [DbContext(typeof(FlaroContext))] [Migration("20261003150124_Spuren")] partial class Spuren { @@ -20,7 +20,7 @@ namespace Halo.Data.Migrations #pragma warning disable 612, 618 modelBuilder.HasAnnotation("ProductVersion", "10.0.12"); - modelBuilder.Entity("Halo.Core.Auth.AuthCode", b => + modelBuilder.Entity("Flaro.Core.Auth.AuthCode", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -68,7 +68,7 @@ namespace Halo.Data.Migrations b.ToTable("AuthCodes"); }); - modelBuilder.Entity("Halo.Core.Auth.DeviceToken", b => + modelBuilder.Entity("Flaro.Core.Auth.DeviceToken", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -111,7 +111,7 @@ namespace Halo.Data.Migrations b.ToTable("DeviceTokens"); }); - modelBuilder.Entity("Halo.Core.Libraries.Library", b => + modelBuilder.Entity("Flaro.Core.Libraries.Library", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -140,7 +140,7 @@ namespace Halo.Data.Migrations b.ToTable("Libraries"); }); - modelBuilder.Entity("Halo.Core.Library.Episode", b => + modelBuilder.Entity("Flaro.Core.Library.Episode", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -176,7 +176,7 @@ namespace Halo.Data.Migrations b.ToTable("Episodes"); }); - modelBuilder.Entity("Halo.Core.Library.MediaFile", b => + modelBuilder.Entity("Flaro.Core.Library.MediaFile", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -230,7 +230,7 @@ namespace Halo.Data.Migrations b.ToTable("MediaFiles"); }); - modelBuilder.Entity("Halo.Core.Library.MediaStream", b => + modelBuilder.Entity("Flaro.Core.Library.MediaStream", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -282,7 +282,7 @@ namespace Halo.Data.Migrations b.ToTable("MediaStreams"); }); - modelBuilder.Entity("Halo.Core.Library.Movie", b => + modelBuilder.Entity("Flaro.Core.Library.Movie", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -330,7 +330,7 @@ namespace Halo.Data.Migrations b.ToTable("Movies"); }); - modelBuilder.Entity("Halo.Core.Library.Series", b => + modelBuilder.Entity("Flaro.Core.Library.Series", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -378,7 +378,7 @@ namespace Halo.Data.Migrations b.ToTable("Series"); }); - modelBuilder.Entity("Halo.Core.ServerSetting", b => + modelBuilder.Entity("Flaro.Core.ServerSetting", b => { b.Property("Key") .HasMaxLength(128) @@ -394,7 +394,7 @@ namespace Halo.Data.Migrations b.ToTable("Settings"); }); - modelBuilder.Entity("Halo.Core.Users.User", b => + modelBuilder.Entity("Flaro.Core.Users.User", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -425,54 +425,54 @@ namespace Halo.Data.Migrations b.ToTable("Users"); }); - modelBuilder.Entity("Halo.Core.Auth.DeviceToken", b => + modelBuilder.Entity("Flaro.Core.Auth.DeviceToken", b => { - b.HasOne("Halo.Core.Users.User", null) + b.HasOne("Flaro.Core.Users.User", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Halo.Core.Library.Episode", b => + modelBuilder.Entity("Flaro.Core.Library.Episode", b => { - b.HasOne("Halo.Core.Library.Series", null) + b.HasOne("Flaro.Core.Library.Series", null) .WithMany() .HasForeignKey("SeriesId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Halo.Core.Library.MediaFile", b => + modelBuilder.Entity("Flaro.Core.Library.MediaFile", b => { - b.HasOne("Halo.Core.Libraries.Library", null) + b.HasOne("Flaro.Core.Libraries.Library", null) .WithMany() .HasForeignKey("LibraryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Halo.Core.Library.MediaStream", b => + modelBuilder.Entity("Flaro.Core.Library.MediaStream", b => { - b.HasOne("Halo.Core.Library.MediaFile", null) + b.HasOne("Flaro.Core.Library.MediaFile", null) .WithMany() .HasForeignKey("MediaFileId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Halo.Core.Library.Movie", b => + modelBuilder.Entity("Flaro.Core.Library.Movie", b => { - b.HasOne("Halo.Core.Libraries.Library", null) + b.HasOne("Flaro.Core.Libraries.Library", null) .WithMany() .HasForeignKey("LibraryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Halo.Core.Library.Series", b => + modelBuilder.Entity("Flaro.Core.Library.Series", b => { - b.HasOne("Halo.Core.Libraries.Library", null) + b.HasOne("Flaro.Core.Libraries.Library", null) .WithMany() .HasForeignKey("LibraryId") .OnDelete(DeleteBehavior.Cascade) diff --git a/server/src/Halo.Data/Migrations/20261003150124_Spuren.cs b/server/src/Flaro.Data/Migrations/20261003150124_Spuren.cs similarity index 99% rename from server/src/Halo.Data/Migrations/20261003150124_Spuren.cs rename to server/src/Flaro.Data/Migrations/20261003150124_Spuren.cs index 1bd01e5..75027d8 100644 --- a/server/src/Halo.Data/Migrations/20261003150124_Spuren.cs +++ b/server/src/Flaro.Data/Migrations/20261003150124_Spuren.cs @@ -3,7 +3,7 @@ using Microsoft.EntityFrameworkCore.Migrations; #nullable disable -namespace Halo.Data.Migrations +namespace Flaro.Data.Migrations { /// public partial class Spuren : Migration diff --git a/server/src/Halo.Data/Migrations/20261003165210_Zuordnung.Designer.cs b/server/src/Flaro.Data/Migrations/20261003165210_Zuordnung.Designer.cs similarity index 90% rename from server/src/Halo.Data/Migrations/20261003165210_Zuordnung.Designer.cs rename to server/src/Flaro.Data/Migrations/20261003165210_Zuordnung.Designer.cs index ef14929..1ab9c1c 100644 --- a/server/src/Halo.Data/Migrations/20261003165210_Zuordnung.Designer.cs +++ b/server/src/Flaro.Data/Migrations/20261003165210_Zuordnung.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Halo.Data; +using Flaro.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; @@ -8,9 +8,9 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion; #nullable disable -namespace Halo.Data.Migrations +namespace Flaro.Data.Migrations { - [DbContext(typeof(HaloContext))] + [DbContext(typeof(FlaroContext))] [Migration("20261003165210_Zuordnung")] partial class Zuordnung { @@ -20,7 +20,7 @@ namespace Halo.Data.Migrations #pragma warning disable 612, 618 modelBuilder.HasAnnotation("ProductVersion", "10.0.12"); - modelBuilder.Entity("Halo.Core.Auth.AuthCode", b => + modelBuilder.Entity("Flaro.Core.Auth.AuthCode", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -68,7 +68,7 @@ namespace Halo.Data.Migrations b.ToTable("AuthCodes"); }); - modelBuilder.Entity("Halo.Core.Auth.DeviceToken", b => + modelBuilder.Entity("Flaro.Core.Auth.DeviceToken", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -111,7 +111,7 @@ namespace Halo.Data.Migrations b.ToTable("DeviceTokens"); }); - modelBuilder.Entity("Halo.Core.Libraries.Library", b => + modelBuilder.Entity("Flaro.Core.Libraries.Library", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -140,7 +140,7 @@ namespace Halo.Data.Migrations b.ToTable("Libraries"); }); - modelBuilder.Entity("Halo.Core.Library.Episode", b => + modelBuilder.Entity("Flaro.Core.Library.Episode", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -176,7 +176,7 @@ namespace Halo.Data.Migrations b.ToTable("Episodes"); }); - modelBuilder.Entity("Halo.Core.Library.MediaFile", b => + modelBuilder.Entity("Flaro.Core.Library.MediaFile", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -230,7 +230,7 @@ namespace Halo.Data.Migrations b.ToTable("MediaFiles"); }); - modelBuilder.Entity("Halo.Core.Library.MediaStream", b => + modelBuilder.Entity("Flaro.Core.Library.MediaStream", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -282,7 +282,7 @@ namespace Halo.Data.Migrations b.ToTable("MediaStreams"); }); - modelBuilder.Entity("Halo.Core.Library.Movie", b => + modelBuilder.Entity("Flaro.Core.Library.Movie", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -337,7 +337,7 @@ namespace Halo.Data.Migrations b.ToTable("Movies"); }); - modelBuilder.Entity("Halo.Core.Library.Series", b => + modelBuilder.Entity("Flaro.Core.Library.Series", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -392,7 +392,7 @@ namespace Halo.Data.Migrations b.ToTable("Series"); }); - modelBuilder.Entity("Halo.Core.ServerSetting", b => + modelBuilder.Entity("Flaro.Core.ServerSetting", b => { b.Property("Key") .HasMaxLength(128) @@ -408,7 +408,7 @@ namespace Halo.Data.Migrations b.ToTable("Settings"); }); - modelBuilder.Entity("Halo.Core.Users.User", b => + modelBuilder.Entity("Flaro.Core.Users.User", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -439,54 +439,54 @@ namespace Halo.Data.Migrations b.ToTable("Users"); }); - modelBuilder.Entity("Halo.Core.Auth.DeviceToken", b => + modelBuilder.Entity("Flaro.Core.Auth.DeviceToken", b => { - b.HasOne("Halo.Core.Users.User", null) + b.HasOne("Flaro.Core.Users.User", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Halo.Core.Library.Episode", b => + modelBuilder.Entity("Flaro.Core.Library.Episode", b => { - b.HasOne("Halo.Core.Library.Series", null) + b.HasOne("Flaro.Core.Library.Series", null) .WithMany() .HasForeignKey("SeriesId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Halo.Core.Library.MediaFile", b => + modelBuilder.Entity("Flaro.Core.Library.MediaFile", b => { - b.HasOne("Halo.Core.Libraries.Library", null) + b.HasOne("Flaro.Core.Libraries.Library", null) .WithMany() .HasForeignKey("LibraryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Halo.Core.Library.MediaStream", b => + modelBuilder.Entity("Flaro.Core.Library.MediaStream", b => { - b.HasOne("Halo.Core.Library.MediaFile", null) + b.HasOne("Flaro.Core.Library.MediaFile", null) .WithMany() .HasForeignKey("MediaFileId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Halo.Core.Library.Movie", b => + modelBuilder.Entity("Flaro.Core.Library.Movie", b => { - b.HasOne("Halo.Core.Libraries.Library", null) + b.HasOne("Flaro.Core.Libraries.Library", null) .WithMany() .HasForeignKey("LibraryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Halo.Core.Library.Series", b => + modelBuilder.Entity("Flaro.Core.Library.Series", b => { - b.HasOne("Halo.Core.Libraries.Library", null) + b.HasOne("Flaro.Core.Libraries.Library", null) .WithMany() .HasForeignKey("LibraryId") .OnDelete(DeleteBehavior.Cascade) diff --git a/server/src/Halo.Data/Migrations/20261003165210_Zuordnung.cs b/server/src/Flaro.Data/Migrations/20261003165210_Zuordnung.cs similarity index 98% rename from server/src/Halo.Data/Migrations/20261003165210_Zuordnung.cs rename to server/src/Flaro.Data/Migrations/20261003165210_Zuordnung.cs index 2bb8f9c..6b1e7e8 100644 --- a/server/src/Halo.Data/Migrations/20261003165210_Zuordnung.cs +++ b/server/src/Flaro.Data/Migrations/20261003165210_Zuordnung.cs @@ -2,7 +2,7 @@ #nullable disable -namespace Halo.Data.Migrations +namespace Flaro.Data.Migrations { /// public partial class Zuordnung : Migration diff --git a/server/src/Halo.Data/Migrations/20261003165918_GeparstesJahr.Designer.cs b/server/src/Flaro.Data/Migrations/20261003165918_GeparstesJahr.Designer.cs similarity index 90% rename from server/src/Halo.Data/Migrations/20261003165918_GeparstesJahr.Designer.cs rename to server/src/Flaro.Data/Migrations/20261003165918_GeparstesJahr.Designer.cs index b757341..033ab00 100644 --- a/server/src/Halo.Data/Migrations/20261003165918_GeparstesJahr.Designer.cs +++ b/server/src/Flaro.Data/Migrations/20261003165918_GeparstesJahr.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Halo.Data; +using Flaro.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; @@ -8,9 +8,9 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion; #nullable disable -namespace Halo.Data.Migrations +namespace Flaro.Data.Migrations { - [DbContext(typeof(HaloContext))] + [DbContext(typeof(FlaroContext))] [Migration("20261003165918_GeparstesJahr")] partial class GeparstesJahr { @@ -20,7 +20,7 @@ namespace Halo.Data.Migrations #pragma warning disable 612, 618 modelBuilder.HasAnnotation("ProductVersion", "10.0.12"); - modelBuilder.Entity("Halo.Core.Auth.AuthCode", b => + modelBuilder.Entity("Flaro.Core.Auth.AuthCode", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -68,7 +68,7 @@ namespace Halo.Data.Migrations b.ToTable("AuthCodes"); }); - modelBuilder.Entity("Halo.Core.Auth.DeviceToken", b => + modelBuilder.Entity("Flaro.Core.Auth.DeviceToken", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -111,7 +111,7 @@ namespace Halo.Data.Migrations b.ToTable("DeviceTokens"); }); - modelBuilder.Entity("Halo.Core.Libraries.Library", b => + modelBuilder.Entity("Flaro.Core.Libraries.Library", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -140,7 +140,7 @@ namespace Halo.Data.Migrations b.ToTable("Libraries"); }); - modelBuilder.Entity("Halo.Core.Library.Episode", b => + modelBuilder.Entity("Flaro.Core.Library.Episode", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -176,7 +176,7 @@ namespace Halo.Data.Migrations b.ToTable("Episodes"); }); - modelBuilder.Entity("Halo.Core.Library.MediaFile", b => + modelBuilder.Entity("Flaro.Core.Library.MediaFile", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -230,7 +230,7 @@ namespace Halo.Data.Migrations b.ToTable("MediaFiles"); }); - modelBuilder.Entity("Halo.Core.Library.MediaStream", b => + modelBuilder.Entity("Flaro.Core.Library.MediaStream", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -282,7 +282,7 @@ namespace Halo.Data.Migrations b.ToTable("MediaStreams"); }); - modelBuilder.Entity("Halo.Core.Library.Movie", b => + modelBuilder.Entity("Flaro.Core.Library.Movie", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -340,7 +340,7 @@ namespace Halo.Data.Migrations b.ToTable("Movies"); }); - modelBuilder.Entity("Halo.Core.Library.Series", b => + modelBuilder.Entity("Flaro.Core.Library.Series", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -398,7 +398,7 @@ namespace Halo.Data.Migrations b.ToTable("Series"); }); - modelBuilder.Entity("Halo.Core.ServerSetting", b => + modelBuilder.Entity("Flaro.Core.ServerSetting", b => { b.Property("Key") .HasMaxLength(128) @@ -414,7 +414,7 @@ namespace Halo.Data.Migrations b.ToTable("Settings"); }); - modelBuilder.Entity("Halo.Core.Users.User", b => + modelBuilder.Entity("Flaro.Core.Users.User", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -445,54 +445,54 @@ namespace Halo.Data.Migrations b.ToTable("Users"); }); - modelBuilder.Entity("Halo.Core.Auth.DeviceToken", b => + modelBuilder.Entity("Flaro.Core.Auth.DeviceToken", b => { - b.HasOne("Halo.Core.Users.User", null) + b.HasOne("Flaro.Core.Users.User", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Halo.Core.Library.Episode", b => + modelBuilder.Entity("Flaro.Core.Library.Episode", b => { - b.HasOne("Halo.Core.Library.Series", null) + b.HasOne("Flaro.Core.Library.Series", null) .WithMany() .HasForeignKey("SeriesId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Halo.Core.Library.MediaFile", b => + modelBuilder.Entity("Flaro.Core.Library.MediaFile", b => { - b.HasOne("Halo.Core.Libraries.Library", null) + b.HasOne("Flaro.Core.Libraries.Library", null) .WithMany() .HasForeignKey("LibraryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Halo.Core.Library.MediaStream", b => + modelBuilder.Entity("Flaro.Core.Library.MediaStream", b => { - b.HasOne("Halo.Core.Library.MediaFile", null) + b.HasOne("Flaro.Core.Library.MediaFile", null) .WithMany() .HasForeignKey("MediaFileId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Halo.Core.Library.Movie", b => + modelBuilder.Entity("Flaro.Core.Library.Movie", b => { - b.HasOne("Halo.Core.Libraries.Library", null) + b.HasOne("Flaro.Core.Libraries.Library", null) .WithMany() .HasForeignKey("LibraryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Halo.Core.Library.Series", b => + modelBuilder.Entity("Flaro.Core.Library.Series", b => { - b.HasOne("Halo.Core.Libraries.Library", null) + b.HasOne("Flaro.Core.Libraries.Library", null) .WithMany() .HasForeignKey("LibraryId") .OnDelete(DeleteBehavior.Cascade) diff --git a/server/src/Halo.Data/Migrations/20261003165918_GeparstesJahr.cs b/server/src/Flaro.Data/Migrations/20261003165918_GeparstesJahr.cs similarity index 96% rename from server/src/Halo.Data/Migrations/20261003165918_GeparstesJahr.cs rename to server/src/Flaro.Data/Migrations/20261003165918_GeparstesJahr.cs index 315584e..f0b6d2b 100644 --- a/server/src/Halo.Data/Migrations/20261003165918_GeparstesJahr.cs +++ b/server/src/Flaro.Data/Migrations/20261003165918_GeparstesJahr.cs @@ -2,7 +2,7 @@ #nullable disable -namespace Halo.Data.Migrations +namespace Flaro.Data.Migrations { /// public partial class GeparstesJahr : Migration diff --git a/server/src/Halo.Data/Migrations/HaloContextModelSnapshot.cs b/server/src/Flaro.Data/Migrations/FlaroContextModelSnapshot.cs similarity index 90% rename from server/src/Halo.Data/Migrations/HaloContextModelSnapshot.cs rename to server/src/Flaro.Data/Migrations/FlaroContextModelSnapshot.cs index 898d171..2959b7d 100644 --- a/server/src/Halo.Data/Migrations/HaloContextModelSnapshot.cs +++ b/server/src/Flaro.Data/Migrations/FlaroContextModelSnapshot.cs @@ -1,23 +1,23 @@ // using System; -using Halo.Data; +using Flaro.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; #nullable disable -namespace Halo.Data.Migrations +namespace Flaro.Data.Migrations { - [DbContext(typeof(HaloContext))] - partial class HaloContextModelSnapshot : ModelSnapshot + [DbContext(typeof(FlaroContext))] + partial class FlaroContextModelSnapshot : ModelSnapshot { protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder.HasAnnotation("ProductVersion", "10.0.12"); - modelBuilder.Entity("Halo.Core.Auth.AuthCode", b => + modelBuilder.Entity("Flaro.Core.Auth.AuthCode", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -65,7 +65,7 @@ namespace Halo.Data.Migrations b.ToTable("AuthCodes"); }); - modelBuilder.Entity("Halo.Core.Auth.DeviceToken", b => + modelBuilder.Entity("Flaro.Core.Auth.DeviceToken", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -108,7 +108,7 @@ namespace Halo.Data.Migrations b.ToTable("DeviceTokens"); }); - modelBuilder.Entity("Halo.Core.Libraries.Library", b => + modelBuilder.Entity("Flaro.Core.Libraries.Library", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -137,7 +137,7 @@ namespace Halo.Data.Migrations b.ToTable("Libraries"); }); - modelBuilder.Entity("Halo.Core.Library.Episode", b => + modelBuilder.Entity("Flaro.Core.Library.Episode", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -173,7 +173,7 @@ namespace Halo.Data.Migrations b.ToTable("Episodes"); }); - modelBuilder.Entity("Halo.Core.Library.MediaFile", b => + modelBuilder.Entity("Flaro.Core.Library.MediaFile", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -227,7 +227,7 @@ namespace Halo.Data.Migrations b.ToTable("MediaFiles"); }); - modelBuilder.Entity("Halo.Core.Library.MediaStream", b => + modelBuilder.Entity("Flaro.Core.Library.MediaStream", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -279,7 +279,7 @@ namespace Halo.Data.Migrations b.ToTable("MediaStreams"); }); - modelBuilder.Entity("Halo.Core.Library.Movie", b => + modelBuilder.Entity("Flaro.Core.Library.Movie", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -337,7 +337,7 @@ namespace Halo.Data.Migrations b.ToTable("Movies"); }); - modelBuilder.Entity("Halo.Core.Library.Series", b => + modelBuilder.Entity("Flaro.Core.Library.Series", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -395,7 +395,7 @@ namespace Halo.Data.Migrations b.ToTable("Series"); }); - modelBuilder.Entity("Halo.Core.ServerSetting", b => + modelBuilder.Entity("Flaro.Core.ServerSetting", b => { b.Property("Key") .HasMaxLength(128) @@ -411,7 +411,7 @@ namespace Halo.Data.Migrations b.ToTable("Settings"); }); - modelBuilder.Entity("Halo.Core.Users.User", b => + modelBuilder.Entity("Flaro.Core.Users.User", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -442,54 +442,54 @@ namespace Halo.Data.Migrations b.ToTable("Users"); }); - modelBuilder.Entity("Halo.Core.Auth.DeviceToken", b => + modelBuilder.Entity("Flaro.Core.Auth.DeviceToken", b => { - b.HasOne("Halo.Core.Users.User", null) + b.HasOne("Flaro.Core.Users.User", null) .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Halo.Core.Library.Episode", b => + modelBuilder.Entity("Flaro.Core.Library.Episode", b => { - b.HasOne("Halo.Core.Library.Series", null) + b.HasOne("Flaro.Core.Library.Series", null) .WithMany() .HasForeignKey("SeriesId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Halo.Core.Library.MediaFile", b => + modelBuilder.Entity("Flaro.Core.Library.MediaFile", b => { - b.HasOne("Halo.Core.Libraries.Library", null) + b.HasOne("Flaro.Core.Libraries.Library", null) .WithMany() .HasForeignKey("LibraryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Halo.Core.Library.MediaStream", b => + modelBuilder.Entity("Flaro.Core.Library.MediaStream", b => { - b.HasOne("Halo.Core.Library.MediaFile", null) + b.HasOne("Flaro.Core.Library.MediaFile", null) .WithMany() .HasForeignKey("MediaFileId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Halo.Core.Library.Movie", b => + modelBuilder.Entity("Flaro.Core.Library.Movie", b => { - b.HasOne("Halo.Core.Libraries.Library", null) + b.HasOne("Flaro.Core.Libraries.Library", null) .WithMany() .HasForeignKey("LibraryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Halo.Core.Library.Series", b => + modelBuilder.Entity("Flaro.Core.Library.Series", b => { - b.HasOne("Halo.Core.Libraries.Library", null) + b.HasOne("Flaro.Core.Libraries.Library", null) .WithMany() .HasForeignKey("LibraryId") .OnDelete(DeleteBehavior.Cascade) diff --git a/server/src/Halo.Media/FfmpegOptions.cs b/server/src/Flaro.Media/FfmpegOptions.cs similarity index 81% rename from server/src/Halo.Media/FfmpegOptions.cs rename to server/src/Flaro.Media/FfmpegOptions.cs index 8021278..65f019a 100644 --- a/server/src/Halo.Media/FfmpegOptions.cs +++ b/server/src/Flaro.Media/FfmpegOptions.cs @@ -1,4 +1,4 @@ -namespace Halo.Media; +namespace Flaro.Media; /// Wo ffmpeg liegt und wie lange es brauchen darf. /// @@ -20,6 +20,6 @@ public sealed record FfmpegOptions(string Ffmpeg = "ffmpeg", string Ffprobe = "f public TimeSpan ProbeTimeout { get; init; } = TimeSpan.FromSeconds(30); public static FfmpegOptions FromEnvironment() => new( - Environment.GetEnvironmentVariable("HALO_FFMPEG") is { Length: > 0 } f ? f : "ffmpeg", - Environment.GetEnvironmentVariable("HALO_FFPROBE") is { Length: > 0 } p ? p : "ffprobe"); + Environment.GetEnvironmentVariable("FLARO_FFMPEG") is { Length: > 0 } f ? f : "ffmpeg", + Environment.GetEnvironmentVariable("FLARO_FFPROBE") is { Length: > 0 } p ? p : "ffprobe"); } diff --git a/server/src/Halo.Media/FfmpegRemuxer.cs b/server/src/Flaro.Media/FfmpegRemuxer.cs similarity index 99% rename from server/src/Halo.Media/FfmpegRemuxer.cs rename to server/src/Flaro.Media/FfmpegRemuxer.cs index 6bd5cb1..0ec0623 100644 --- a/server/src/Halo.Media/FfmpegRemuxer.cs +++ b/server/src/Flaro.Media/FfmpegRemuxer.cs @@ -2,7 +2,7 @@ using System.Diagnostics; using System.Globalization; using Microsoft.Extensions.Logging; -namespace Halo.Media; +namespace Flaro.Media; public sealed record RemuxOutcome(bool Success, string? Error); diff --git a/server/src/Halo.Media/FfprobeRunner.cs b/server/src/Flaro.Media/FfprobeRunner.cs similarity index 99% rename from server/src/Halo.Media/FfprobeRunner.cs rename to server/src/Flaro.Media/FfprobeRunner.cs index 1be0039..2a6346f 100644 --- a/server/src/Halo.Media/FfprobeRunner.cs +++ b/server/src/Flaro.Media/FfprobeRunner.cs @@ -1,10 +1,10 @@ using System.Diagnostics; using System.Globalization; using System.Text.Json; -using Halo.Core.Library; +using Flaro.Core.Library; using Microsoft.Extensions.Logging; -namespace Halo.Media; +namespace Flaro.Media; /// Liest die technischen Angaben einer Datei mit ffprobe. /// diff --git a/server/src/Halo.Media/Halo.Media.csproj b/server/src/Flaro.Media/Flaro.Media.csproj similarity index 84% rename from server/src/Halo.Media/Halo.Media.csproj rename to server/src/Flaro.Media/Flaro.Media.csproj index 14ec534..56d8b23 100644 --- a/server/src/Halo.Media/Halo.Media.csproj +++ b/server/src/Flaro.Media/Flaro.Media.csproj @@ -1,7 +1,7 @@  - + diff --git a/server/src/Halo.Media/RemuxArguments.cs b/server/src/Flaro.Media/RemuxArguments.cs similarity index 98% rename from server/src/Halo.Media/RemuxArguments.cs rename to server/src/Flaro.Media/RemuxArguments.cs index 15800ac..f1e1a7c 100644 --- a/server/src/Halo.Media/RemuxArguments.cs +++ b/server/src/Flaro.Media/RemuxArguments.cs @@ -1,7 +1,7 @@ -using Halo.Core.Delivery; -using Halo.Core.Library; +using Flaro.Core.Delivery; +using Flaro.Core.Library; -namespace Halo.Media; +namespace Flaro.Media; public sealed record RemuxRequest( string SourcePath, diff --git a/server/src/Halo.Media/SidecarWriter.cs b/server/src/Flaro.Media/SidecarWriter.cs similarity index 91% rename from server/src/Halo.Media/SidecarWriter.cs rename to server/src/Flaro.Media/SidecarWriter.cs index cd76576..af5f1c4 100644 --- a/server/src/Halo.Media/SidecarWriter.cs +++ b/server/src/Flaro.Media/SidecarWriter.cs @@ -1,20 +1,20 @@ -using Halo.Core.Library; +using Flaro.Core.Library; using Microsoft.Extensions.Logging; -namespace Halo.Media; +namespace Flaro.Media; -/// Ob Halo überhaupt in Medienordner schreiben darf. +/// Ob Flaro überhaupt in Medienordner schreiben darf. /// /// /// Standardmässig aus. In fremde Medienordner zu schreiben ist nichts, /// was ein Server ungefragt tun sollte — und für viele Aufbauten ist die /// Einhängung ohnehin schreibgeschützt. Wer es will, setzt -/// HALO_WRITE_SIDECARS=true und hängt die Medien ohne :ro ein. +/// FLARO_WRITE_SIDECARS=true und hängt die Medien ohne :ro ein. /// public sealed record SidecarOptions(bool Enabled) { public static SidecarOptions FromEnvironment() => new( - Environment.GetEnvironmentVariable("HALO_WRITE_SIDECARS")?.Trim() + Environment.GetEnvironmentVariable("FLARO_WRITE_SIDECARS")?.Trim() .Equals("true", StringComparison.OrdinalIgnoreCase) == true); } @@ -52,7 +52,7 @@ public sealed class SidecarWriter(SidecarOptions optionen, ILoggerWas TMDB verlangt, wenn man ihre Daten benutzt. /// diff --git a/server/src/Halo.Metadata/Halo.Metadata.csproj b/server/src/Flaro.Metadata/Flaro.Metadata.csproj similarity index 83% rename from server/src/Halo.Metadata/Halo.Metadata.csproj rename to server/src/Flaro.Metadata/Flaro.Metadata.csproj index 7b42664..d307572 100644 --- a/server/src/Halo.Metadata/Halo.Metadata.csproj +++ b/server/src/Flaro.Metadata/Flaro.Metadata.csproj @@ -1,7 +1,7 @@  - + diff --git a/server/src/Halo.Metadata/ImageCache.cs b/server/src/Flaro.Metadata/ImageCache.cs similarity index 98% rename from server/src/Halo.Metadata/ImageCache.cs rename to server/src/Flaro.Metadata/ImageCache.cs index 8c8a32f..2777f1e 100644 --- a/server/src/Halo.Metadata/ImageCache.cs +++ b/server/src/Flaro.Metadata/ImageCache.cs @@ -1,9 +1,9 @@ using System.Security.Cryptography; using System.Text; -using Halo.Core.Metadata; +using Flaro.Core.Metadata; using Microsoft.Extensions.Logging; -namespace Halo.Metadata; +namespace Flaro.Metadata; public sealed record ImageCacheOptions(string Root); @@ -80,7 +80,7 @@ public sealed class ImageCache( /// /// /// Die Prüfung ist kein Schmuck. Der Schlüssel kommt aus einer - /// Adresszeile. Ohne sie wäre /api/v1/images/..%2f..%2fconfig%2fhalo.db + /// Adresszeile. Ohne sie wäre /api/v1/images/..%2f..%2fconfig%2fflaro.db /// ein Weg, die Datenbank herunterzuladen — samt aller Token-Fingerabdrücke. /// public string? PfadFür(string schlüssel) diff --git a/server/src/Halo.Metadata/TmdbClient.cs b/server/src/Flaro.Metadata/TmdbClient.cs similarity index 99% rename from server/src/Halo.Metadata/TmdbClient.cs rename to server/src/Flaro.Metadata/TmdbClient.cs index 2fe937d..04041a3 100644 --- a/server/src/Halo.Metadata/TmdbClient.cs +++ b/server/src/Flaro.Metadata/TmdbClient.cs @@ -1,10 +1,10 @@ using System.Net; using System.Text.Json; using System.Text.Json.Serialization; -using Halo.Core.Metadata; +using Flaro.Core.Metadata; using Microsoft.Extensions.Logging; -namespace Halo.Metadata; +namespace Flaro.Metadata; /// Fragt TMDB nach Titeln, Beschreibungen und Bildern. /// diff --git a/server/src/Halo.Metadata/TmdbSettings.cs b/server/src/Flaro.Metadata/TmdbSettings.cs similarity index 90% rename from server/src/Halo.Metadata/TmdbSettings.cs rename to server/src/Flaro.Metadata/TmdbSettings.cs index 2292a56..228ae85 100644 --- a/server/src/Halo.Metadata/TmdbSettings.cs +++ b/server/src/Flaro.Metadata/TmdbSettings.cs @@ -1,9 +1,9 @@ -namespace Halo.Metadata; +namespace Flaro.Metadata; /// Was TMDB braucht, um zu antworten. public sealed record TmdbSettings(string? ApiKey, string Language, bool UsingProjectKey = false) { - /// Englisch als Voreinstellung, weil Halo nicht nur hier läuft. + /// Englisch als Voreinstellung, weil Flaro nicht nur hier läuft. /// /// /// Der Betreiber stellt in der Oberfläche um. Eine deutsche Voreinstellung @@ -16,8 +16,8 @@ public sealed record TmdbSettings(string? ApiKey, string Language, bool UsingPro /// /// /// - /// Hier gehört der Schlüssel hinein, den Halo ausliefert. Ist er - /// leer, verlangt Halo von jedem Betreiber einen eigenen — die Mediathek + /// Hier gehört der Schlüssel hinein, den Flaro ausliefert. Ist er + /// leer, verlangt Flaro von jedem Betreiber einen eigenen — die Mediathek /// läuft dann trotzdem, nur mit Dateinamen statt Titeln. /// /// diff --git a/server/tests/Halo.Api.Tests/AbgeschalteterAnbieter.cs b/server/tests/Flaro.Api.Tests/AbgeschalteterAnbieter.cs similarity index 97% rename from server/tests/Halo.Api.Tests/AbgeschalteterAnbieter.cs rename to server/tests/Flaro.Api.Tests/AbgeschalteterAnbieter.cs index 696fe5a..0915460 100644 --- a/server/tests/Halo.Api.Tests/AbgeschalteterAnbieter.cs +++ b/server/tests/Flaro.Api.Tests/AbgeschalteterAnbieter.cs @@ -1,6 +1,6 @@ -using Halo.Core.Metadata; +using Flaro.Core.Metadata; -namespace Halo.Api.Tests; +namespace Flaro.Api.Tests; /// Ein Anbieter, der nichts weiss und nichts fragt. /// diff --git a/server/tests/Halo.Api.Tests/CodeSignInTests.cs b/server/tests/Flaro.Api.Tests/CodeSignInTests.cs similarity index 92% rename from server/tests/Halo.Api.Tests/CodeSignInTests.cs rename to server/tests/Flaro.Api.Tests/CodeSignInTests.cs index 97fb1b4..07372f8 100644 --- a/server/tests/Halo.Api.Tests/CodeSignInTests.cs +++ b/server/tests/Flaro.Api.Tests/CodeSignInTests.cs @@ -1,19 +1,19 @@ using System.Net; using System.Net.Http.Json; -using Halo.Api.Endpoints; +using Flaro.Api.Endpoints; -namespace Halo.Api.Tests; +namespace Flaro.Api.Tests; /// Anmelden am Fernseher, ohne ein Passwort zu tippen. public class CodeSignInTests { - private static Task CodeAnfordern(HaloServer server) => + private static Task CodeAnfordern(FlaroServer server) => server.Client.PostAsJsonAsync("/api/v1/auth/code", new CodeRequest("Wohnzimmer", "tv-1")); [Test] public async Task Der_ganze_Weg_vom_Bildschirm_zum_Token() { - using var server = new HaloServer(); + using var server = new FlaroServer(); var telefon = await server.SetUpAndSignIn(); // 1. Der Fernseher fordert an und zeigt den Code. @@ -52,7 +52,7 @@ public class CodeSignInTests [Test] public async Task Ein_fremder_Abholschein_bekommt_nichts() { - using var server = new HaloServer(); + using var server = new FlaroServer(); var telefon = await server.SetUpAndSignIn(); var echt = await (await CodeAnfordern(server)).Content.ReadFromJsonAsync(); @@ -69,7 +69,7 @@ public class CodeSignInTests [Test] public async Task Der_Code_ist_kein_Abholschein() { - using var server = new HaloServer(); + using var server = new FlaroServer(); var telefon = await server.SetUpAndSignIn(); var echt = await (await CodeAnfordern(server)).Content.ReadFromJsonAsync(); @@ -82,7 +82,7 @@ public class CodeSignInTests [Test] public async Task Ein_abgeholtes_Token_gibt_es_kein_zweites_Mal() { - using var server = new HaloServer(); + using var server = new FlaroServer(); var telefon = await server.SetUpAndSignIn(); var angefordert = await (await CodeAnfordern(server)).Content.ReadFromJsonAsync(); @@ -100,7 +100,7 @@ public class CodeSignInTests [Test] public async Task Ein_Unangemeldeter_kann_nichts_bestaetigen() { - using var server = new HaloServer(); + using var server = new FlaroServer(); await server.SetUpAndSignIn(); var angefordert = await (await CodeAnfordern(server)).Content.ReadFromJsonAsync(); @@ -114,7 +114,7 @@ public class CodeSignInTests [Test] public async Task Ein_erfundener_Code_laesst_sich_nicht_bestaetigen() { - using var server = new HaloServer(); + using var server = new FlaroServer(); var telefon = await server.SetUpAndSignIn(); var versuch = await server.AlsAngemeldeter(telefon.Token).PostAsync("/api/v1/auth/code/000000", null); @@ -125,7 +125,7 @@ public class CodeSignInTests [Test] public async Task Die_Bestaetigung_nennt_das_Geraet() { - using var server = new HaloServer(); + using var server = new FlaroServer(); var telefon = await server.SetUpAndSignIn(); var angefordert = await (await CodeAnfordern(server)).Content.ReadFromJsonAsync(); diff --git a/server/tests/Halo.Api.Tests/DeliveryTests.cs b/server/tests/Flaro.Api.Tests/DeliveryTests.cs similarity index 96% rename from server/tests/Halo.Api.Tests/DeliveryTests.cs rename to server/tests/Flaro.Api.Tests/DeliveryTests.cs index 4bcfd5a..548f45b 100644 --- a/server/tests/Halo.Api.Tests/DeliveryTests.cs +++ b/server/tests/Flaro.Api.Tests/DeliveryTests.cs @@ -2,9 +2,9 @@ using System.Diagnostics; using System.Net; using System.Net.Http.Headers; using System.Net.Http.Json; -using Halo.Api.Endpoints; +using Flaro.Api.Endpoints; -namespace Halo.Api.Tests; +namespace Flaro.Api.Tests; /// Der Weg vom Scan bis zur heruntergeladenen Datei. public class DeliveryTests @@ -21,7 +21,7 @@ public class DeliveryTests { if (Werkzeug("ffmpeg") is null) Assert.Ignore("ffmpeg ist auf diesem Rechner nicht installiert."); _bestand = Directory.CreateDirectory( - Path.Combine(Path.GetTempPath(), "halo-liefern-" + Guid.CreateVersion7().ToString("N"))).FullName; + Path.Combine(Path.GetTempPath(), "flaro-liefern-" + Guid.CreateVersion7().ToString("N"))).FullName; } [TearDown] @@ -56,7 +56,7 @@ public class DeliveryTests private async Task<(HttpClient Client, MediaFileResponse Datei)> Eingelesen() { - var server = _server = new HaloServer(); + var server = _server = new FlaroServer(); var admin = await server.SetUpAndSignIn(); var client = server.AlsAngemeldeter(admin.Token); @@ -78,7 +78,7 @@ public class DeliveryTests return (client, filme.Items[0].Files.Single()); } - private HaloServer? _server; + private FlaroServer? _server; [TearDown] public void ServerSchliessen() { _server?.Dispose(); _server = null; } diff --git a/server/tests/Halo.Api.Tests/Halo.Api.Tests.csproj b/server/tests/Flaro.Api.Tests/Flaro.Api.Tests.csproj similarity index 79% rename from server/tests/Halo.Api.Tests/Halo.Api.Tests.csproj rename to server/tests/Flaro.Api.Tests/Flaro.Api.Tests.csproj index 691dc86..5841313 100644 --- a/server/tests/Halo.Api.Tests/Halo.Api.Tests.csproj +++ b/server/tests/Flaro.Api.Tests/Flaro.Api.Tests.csproj @@ -22,9 +22,9 @@ - - - + + + diff --git a/server/tests/Halo.Api.Tests/HaloPathsTests.cs b/server/tests/Flaro.Api.Tests/FlaroPathsTests.cs similarity index 83% rename from server/tests/Halo.Api.Tests/HaloPathsTests.cs rename to server/tests/Flaro.Api.Tests/FlaroPathsTests.cs index dc145b2..d0d820d 100644 --- a/server/tests/Halo.Api.Tests/HaloPathsTests.cs +++ b/server/tests/Flaro.Api.Tests/FlaroPathsTests.cs @@ -1,9 +1,9 @@ -namespace Halo.Api.Tests; +namespace Flaro.Api.Tests; /// Was beim allerersten Start passiert, bevor irgendetwas anderes greift. -public class HaloPathsTests +public class FlaroPathsTests { - private static readonly string[] Variablen = ["HALO_DATA", "HALO_CACHE", "HALO_TRANSCODE"]; + private static readonly string[] Variablen = ["FLARO_DATA", "FLARO_CACHE", "FLARO_TRANSCODE"]; private string _wurzel = ""; private Dictionary _vorher = []; @@ -26,7 +26,7 @@ public class HaloPathsTests { _vorher = Variablen.ToDictionary(v => v, Environment.GetEnvironmentVariable); _wurzel = Directory.CreateDirectory( - Path.Combine(Path.GetTempPath(), "halo-pfade-" + Guid.CreateVersion7().ToString("N"))).FullName; + Path.Combine(Path.GetTempPath(), "flaro-pfade-" + Guid.CreateVersion7().ToString("N"))).FullName; } [TearDown] @@ -43,7 +43,7 @@ public class HaloPathsTests foreach (var (name, wert) in _vorher) Environment.SetEnvironmentVariable(name, wert); } - private HaloPaths Pfade(string? daten = null) => new() + private FlaroPaths Pfade(string? daten = null) => new() { Data = daten ?? Path.Combine(_wurzel, "config"), Cache = Path.Combine(_wurzel, "cache"), @@ -90,7 +90,7 @@ public class HaloPathsTests var fehler = Assert.Throws(() => Pfade(daten: gesperrt).EnsureExists()); - Assert.That(fehler!.Message, Does.Contain("HALO_DATA"), "Welche Einstellung gemeint ist"); + Assert.That(fehler!.Message, Does.Contain("FLARO_DATA"), "Welche Einstellung gemeint ist"); Assert.That(fehler.Message, Does.Contain(gesperrt), "Welches Verzeichnis"); Assert.That(fehler.Message, Does.Contain("uid="), "Als wer der Server läuft"); Assert.That(fehler.Message, Does.Contain("chown"), "Was zu tun ist"); @@ -99,20 +99,20 @@ public class HaloPathsTests [Test] public void Ohne_Umgebungsvariablen_liegt_alles_neben_dem_Programm() { - foreach (var name in new[] { "HALO_DATA", "HALO_CACHE", "HALO_TRANSCODE" }) + foreach (var name in new[] { "FLARO_DATA", "FLARO_CACHE", "FLARO_TRANSCODE" }) Environment.SetEnvironmentVariable(name, null); - var pfade = HaloPaths.FromEnvironment(_wurzel); + var pfade = FlaroPaths.FromEnvironment(_wurzel); Assert.That(pfade.Data, Is.EqualTo(Path.Combine(_wurzel, "data"))); - Assert.That(pfade.DatabaseFile, Does.EndWith("halo.db")); + Assert.That(pfade.DatabaseFile, Does.EndWith("flaro.db")); } [Test] public void Die_Umgebung_sticht_die_Voreinstellung() { - Environment.SetEnvironmentVariable("HALO_DATA", "/woanders"); - Assert.That(HaloPaths.FromEnvironment(_wurzel).Data, Is.EqualTo("/woanders")); + Environment.SetEnvironmentVariable("FLARO_DATA", "/woanders"); + Assert.That(FlaroPaths.FromEnvironment(_wurzel).Data, Is.EqualTo("/woanders")); // Zurückgesetzt wird im TearDown, für alle drei Variablen gemeinsam. } } diff --git a/server/tests/Halo.Api.Tests/HaloServer.cs b/server/tests/Flaro.Api.Tests/FlaroServer.cs similarity index 85% rename from server/tests/Halo.Api.Tests/HaloServer.cs rename to server/tests/Flaro.Api.Tests/FlaroServer.cs index 3eab9b8..e0b99cc 100644 --- a/server/tests/Halo.Api.Tests/HaloServer.cs +++ b/server/tests/Flaro.Api.Tests/FlaroServer.cs @@ -1,12 +1,12 @@ using System.Net.Http.Headers; using System.Net.Http.Json; -using Halo.Api.Endpoints; +using Flaro.Api.Endpoints; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Halo.Core.Metadata; +using Flaro.Core.Metadata; -namespace Halo.Api.Tests; +namespace Flaro.Api.Tests; /// Ein frisch gestarteter Server mit leerer Datenbank. /// @@ -16,7 +16,7 @@ namespace Halo.Api.Tests; /// Migration wandern lassen, Einrichtung anbieten. Genau diese Kette sieht ein /// Fremder als Erstes — und genau sie würde ein Ersatzspeicher überspringen. /// -public sealed class HaloServer : IDisposable +public sealed class FlaroServer : IDisposable { private readonly WebApplicationFactory _grundlage; private readonly WebApplicationFactory _fabrik; @@ -24,16 +24,16 @@ public sealed class HaloServer : IDisposable public HttpClient Client { get; } - public HaloServer(Action? dienste = null) + public FlaroServer(Action? dienste = null) { - _verzeichnis = Path.Combine(Path.GetTempPath(), "halo-test-" + Guid.CreateVersion7().ToString("N")); - Environment.SetEnvironmentVariable("HALO_DATA", Path.Combine(_verzeichnis, "config")); - Environment.SetEnvironmentVariable("HALO_CACHE", Path.Combine(_verzeichnis, "cache")); - Environment.SetEnvironmentVariable("HALO_TRANSCODE", Path.Combine(_verzeichnis, "transcode")); + _verzeichnis = Path.Combine(Path.GetTempPath(), "flaro-test-" + Guid.CreateVersion7().ToString("N")); + Environment.SetEnvironmentVariable("FLARO_DATA", Path.Combine(_verzeichnis, "config")); + Environment.SetEnvironmentVariable("FLARO_CACHE", Path.Combine(_verzeichnis, "cache")); + Environment.SetEnvironmentVariable("FLARO_TRANSCODE", Path.Combine(_verzeichnis, "transcode")); // Die Zugriffsgrenze zählt je Adresse, und im Test kommt alles von // derselben. Ohne das Hochsetzen prüfte man hier die Grenze statt der // Anmeldung. - Environment.SetEnvironmentVariable("HALO_RATELIMIT_SIGNIN", "10000"); + Environment.SetEnvironmentVariable("FLARO_RATELIMIT_SIGNIN", "10000"); _grundlage = new WebApplicationFactory(); _fabrik = _grundlage.WithWebHostBuilder(b => b.ConfigureServices(sammlung => diff --git a/server/tests/Halo.Api.Tests/ManagementTests.cs b/server/tests/Flaro.Api.Tests/ManagementTests.cs similarity index 92% rename from server/tests/Halo.Api.Tests/ManagementTests.cs rename to server/tests/Flaro.Api.Tests/ManagementTests.cs index c1bc600..15e07a3 100644 --- a/server/tests/Halo.Api.Tests/ManagementTests.cs +++ b/server/tests/Flaro.Api.Tests/ManagementTests.cs @@ -1,15 +1,15 @@ using System.Net; using System.Net.Http.Json; -using Halo.Api.Endpoints; +using Flaro.Api.Endpoints; -namespace Halo.Api.Tests; +namespace Flaro.Api.Tests; public class ManagementTests { [Test] public async Task Ein_Administrator_legt_Benutzer_an() { - using var server = new HaloServer(); + using var server = new FlaroServer(); var admin = await server.SetUpAndSignIn(); var client = server.AlsAngemeldeter(admin.Token); @@ -25,7 +25,7 @@ public class ManagementTests [Test] public async Task Ein_gewoehnlicher_Benutzer_darf_keine_Benutzer_anlegen() { - using var server = new HaloServer(); + using var server = new FlaroServer(); var admin = await server.SetUpAndSignIn(); await server.AlsAngemeldeter(admin.Token).PostAsJsonAsync("/api/v1/users", new CreateUserRequest("mitbewohner", "auch-ein-langes-passwort", false)); @@ -40,7 +40,7 @@ public class ManagementTests [Test] public async Task Derselbe_Benutzername_zweimal_wird_abgelehnt() { - using var server = new HaloServer(); + using var server = new FlaroServer(); var admin = await server.SetUpAndSignIn(); var client = server.AlsAngemeldeter(admin.Token); @@ -60,7 +60,7 @@ public class ManagementTests [Test] public async Task Eine_Bibliothek_auf_einem_Pfad_den_es_nicht_gibt_wird_abgelehnt() { - using var server = new HaloServer(); + using var server = new FlaroServer(); var admin = await server.SetUpAndSignIn(); var versuch = await server.AlsAngemeldeter(admin.Token).PostAsJsonAsync("/api/v1/libraries", @@ -73,7 +73,7 @@ public class ManagementTests [Test] public async Task Eine_Bibliothek_auf_einem_vorhandenen_Pfad_wird_angelegt() { - using var server = new HaloServer(); + using var server = new FlaroServer(); var admin = await server.SetUpAndSignIn(); var client = server.AlsAngemeldeter(admin.Token); var pfad = Path.GetTempPath(); @@ -89,7 +89,7 @@ public class ManagementTests [Test] public async Task Eine_unbekannte_Art_wird_abgelehnt() { - using var server = new HaloServer(); + using var server = new FlaroServer(); var admin = await server.SetUpAndSignIn(); var versuch = await server.AlsAngemeldeter(admin.Token).PostAsJsonAsync("/api/v1/libraries", diff --git a/server/tests/Halo.Api.Tests/MatchCorrectionTests.cs b/server/tests/Flaro.Api.Tests/MatchCorrectionTests.cs similarity index 94% rename from server/tests/Halo.Api.Tests/MatchCorrectionTests.cs rename to server/tests/Flaro.Api.Tests/MatchCorrectionTests.cs index 2692054..c1a4d9d 100644 --- a/server/tests/Halo.Api.Tests/MatchCorrectionTests.cs +++ b/server/tests/Flaro.Api.Tests/MatchCorrectionTests.cs @@ -1,20 +1,20 @@ using System.Diagnostics; using System.Net; using System.Net.Http.Json; -using Halo.Api.Endpoints; -using Halo.Core.Library; -using Halo.Core.Metadata; -using Halo.Media; +using Flaro.Api.Endpoints; +using Flaro.Core.Library; +using Flaro.Core.Metadata; +using Flaro.Media; using Microsoft.Extensions.DependencyInjection; -namespace Halo.Api.Tests; +namespace Flaro.Api.Tests; /// Eine falsche Zuordnung richtigstellen — und sie festschreiben. public class MatchCorrectionTests { private string _bestand = ""; private string _filmOrdner = ""; - private HaloServer? _server; + private FlaroServer? _server; private static string? Werkzeug(string name) => (Environment.GetEnvironmentVariable("PATH") ?? "").Split(Path.PathSeparator) @@ -26,7 +26,7 @@ public class MatchCorrectionTests { if (Werkzeug("ffmpeg") is null) Assert.Ignore("ffmpeg ist auf diesem Rechner nicht installiert."); _bestand = Directory.CreateDirectory( - Path.Combine(Path.GetTempPath(), "halo-korrektur-" + Guid.CreateVersion7().ToString("N"))).FullName; + Path.Combine(Path.GetTempPath(), "flaro-korrektur-" + Guid.CreateVersion7().ToString("N"))).FullName; _filmOrdner = Directory.CreateDirectory(Path.Combine(_bestand, "Dark (2017)")).FullName; var start = new ProcessStartInfo(Werkzeug("ffmpeg")!) { RedirectStandardError = true, UseShellExecute = false }; @@ -87,7 +87,7 @@ public class MatchCorrectionTests private async Task<(HttpClient Client, MovieResponse Film)> Eingelesen(bool beiwerkSchreiben) { - _server = new HaloServer(dienste => + _server = new FlaroServer(dienste => { dienste.AddScoped(); dienste.AddSingleton( @@ -213,13 +213,13 @@ public class MatchCorrectionTests (await client.PutAsJsonAsync($"/api/v1/movies/{film.Id}/match", new ApplyMatchRequest(613))) .EnsureSuccessStatusCode(); - var bibliotheken = await client.GetFromJsonAsync>("/api/v1/libraries"); - (await client.PostAsync($"/api/v1/libraries/{bibliotheken!.Single().Id}/scan", null)) + var bibliothek = (await client.GetFromJsonAsync>("/api/v1/libraries"))!.Single(); + (await client.PostAsync($"/api/v1/libraries/{bibliothek.Id}/scan", null)) .EnsureSuccessStatusCode(); for (var i = 0; i < 150; i++) { var stand = await client.GetFromJsonAsync( - $"/api/v1/libraries/{bibliotheken.Single().Id}/scan"); + $"/api/v1/libraries/{bibliothek.Id}/scan"); if (stand!.State == "finished") break; await Task.Delay(50); } diff --git a/server/tests/Halo.Api.Tests/MetadataTests.cs b/server/tests/Flaro.Api.Tests/MetadataTests.cs similarity index 94% rename from server/tests/Halo.Api.Tests/MetadataTests.cs rename to server/tests/Flaro.Api.Tests/MetadataTests.cs index 9fb8531..a4c8b48 100644 --- a/server/tests/Halo.Api.Tests/MetadataTests.cs +++ b/server/tests/Flaro.Api.Tests/MetadataTests.cs @@ -1,10 +1,10 @@ using System.Net; using System.Net.Http.Json; -using Halo.Api.Endpoints; -using Halo.Core.Metadata; +using Flaro.Api.Endpoints; +using Flaro.Core.Metadata; using Microsoft.Extensions.DependencyInjection; -namespace Halo.Api.Tests; +namespace Flaro.Api.Tests; /// Ein Anbieter, der antwortet, was der Test vorgibt. public sealed class VorgegebenerAnbieter : IMetadataProvider @@ -84,7 +84,7 @@ public class MetadataTests [SetUp] public void Anlegen() => _bestand = Directory.CreateDirectory( - Path.Combine(Path.GetTempPath(), "halo-meta-" + Guid.CreateVersion7().ToString("N"))).FullName; + Path.Combine(Path.GetTempPath(), "flaro-meta-" + Guid.CreateVersion7().ToString("N"))).FullName; [TearDown] public void Aufraeumen() @@ -99,14 +99,14 @@ public class MetadataTests File.WriteAllBytes(voll, new byte[1024]); } - private HaloServer MitAnbieter(VorgegebenerAnbieter anbieter, VorgegebeneBilder? bilder = null) => + private FlaroServer MitAnbieter(VorgegebenerAnbieter anbieter, VorgegebeneBilder? bilder = null) => new(dienste => { dienste.AddScoped(_ => anbieter); dienste.AddScoped(_ => bilder ?? new VorgegebeneBilder()); }); - private async Task<(HttpClient Admin, Guid Library)> Einrichten(HaloServer server, string art) + private async Task<(HttpClient Admin, Guid Library)> Einrichten(FlaroServer server, string art) { var admin = await server.SetUpAndSignIn(); var client = server.AlsAngemeldeter(admin.Token); @@ -282,7 +282,7 @@ public class MetadataSettingsTests [Test] public async Task Der_Schluessel_kommt_nicht_zurueck() { - using var server = new HaloServer(); + using var server = new FlaroServer(); var admin = await server.SetUpAndSignIn(); var client = server.AlsAngemeldeter(admin.Token); @@ -308,12 +308,12 @@ public class MetadataSettingsTests [Test] public async Task Ohne_eigenen_Schluessel_greift_der_mitgelieferte() { - using var server = new HaloServer(); + using var server = new FlaroServer(); var admin = await server.SetUpAndSignIn(); var stand = await server.AlsAngemeldeter(admin.Token) .GetFromJsonAsync("/api/v1/settings/metadata"); - var mitgeliefert = Halo.Metadata.TmdbSettings.ProjectApiKey.Length > 0; + var mitgeliefert = Flaro.Metadata.TmdbSettings.ProjectApiKey.Length > 0; Assert.That(stand!.HasApiKey, Is.EqualTo(mitgeliefert)); Assert.That(stand.UsingProjectKey, Is.EqualTo(mitgeliefert)); Assert.That(stand.Language, Is.EqualTo("en-US")); @@ -322,7 +322,7 @@ public class MetadataSettingsTests [Test] public async Task Ein_eigener_Schluessel_loest_den_mitgelieferten_ab() { - using var server = new HaloServer(); + using var server = new FlaroServer(); var admin = await server.SetUpAndSignIn(); var client = server.AlsAngemeldeter(admin.Token); @@ -338,7 +338,7 @@ public class MetadataSettingsTests [Test] public async Task Der_Pflichthinweis_zu_TMDB_steht_in_der_Systemauskunft() { - using var server = new HaloServer(); + using var server = new FlaroServer(); var info = await server.Client.GetFromJsonAsync("/api/v1/system/info"); var tmdb = info!.Attributions.Single(); @@ -352,7 +352,7 @@ public class MetadataSettingsTests [TestCase("de-de")] public async Task Eine_unsinnige_Sprachkennung_wird_abgelehnt(string sprache) { - using var server = new HaloServer(); + using var server = new FlaroServer(); var admin = await server.SetUpAndSignIn(); var antwort = await server.AlsAngemeldeter(admin.Token) @@ -364,7 +364,7 @@ public class MetadataSettingsTests [Test] public async Task Ein_gewoehnlicher_Benutzer_sieht_die_Einstellungen_nicht() { - using var server = new HaloServer(); + using var server = new FlaroServer(); var admin = await server.SetUpAndSignIn(); await server.AlsAngemeldeter(admin.Token).PostAsJsonAsync("/api/v1/users", new CreateUserRequest("gast", "auch-ein-langes-passwort", false)); @@ -380,7 +380,7 @@ public class ImageEndpointTests [Test] public async Task Bilder_gibt_es_nur_fuer_Angemeldete() { - using var server = new HaloServer(); + using var server = new FlaroServer(); await server.SetUpAndSignIn(); var antwort = await server.Client.GetAsync($"/api/v1/images/{new string('a', 64)}"); @@ -388,12 +388,12 @@ public class ImageEndpointTests } /// Der Weg, der sonst die Datenbank herausgäbe. - [TestCase("..%2F..%2Fconfig%2Fhalo.db")] + [TestCase("..%2F..%2Fconfig%2Fflaro.db")] [TestCase("nichtsechzigvierzeichen")] [TestCase("ZZZZ567890123456789012345678901234567890123456789012345678901234")] public async Task Ein_Schluessel_der_keiner_ist_fuehrt_ins_Leere(string versuch) { - using var server = new HaloServer(); + using var server = new FlaroServer(); var admin = await server.SetUpAndSignIn(); var antwort = await server.AlsAngemeldeter(admin.Token).GetAsync($"/api/v1/images/{versuch}"); diff --git a/server/tests/Halo.Api.Tests/ScanTests.cs b/server/tests/Flaro.Api.Tests/ScanTests.cs similarity index 93% rename from server/tests/Halo.Api.Tests/ScanTests.cs rename to server/tests/Flaro.Api.Tests/ScanTests.cs index 5f8cb7d..4e0ba08 100644 --- a/server/tests/Halo.Api.Tests/ScanTests.cs +++ b/server/tests/Flaro.Api.Tests/ScanTests.cs @@ -1,8 +1,8 @@ using System.Net; using System.Net.Http.Json; -using Halo.Api.Endpoints; +using Flaro.Api.Endpoints; -namespace Halo.Api.Tests; +namespace Flaro.Api.Tests; /// Scan gegen einen echten Ordner mit echten Dateien. public class ScanTests @@ -11,7 +11,7 @@ public class ScanTests [SetUp] public void Anlegen() => _bestand = Directory.CreateDirectory( - Path.Combine(Path.GetTempPath(), "halo-medien-" + Guid.CreateVersion7().ToString("N"))).FullName; + Path.Combine(Path.GetTempPath(), "flaro-medien-" + Guid.CreateVersion7().ToString("N"))).FullName; [TearDown] public void Aufraeumen() @@ -26,7 +26,7 @@ public class ScanTests File.WriteAllBytes(voll, new byte[bytes]); } - private async Task<(HttpClient Admin, Guid LibraryId)> MitBibliothek(HaloServer server, string art) + private async Task<(HttpClient Admin, Guid LibraryId)> MitBibliothek(FlaroServer server, string art) { var admin = await server.SetUpAndSignIn(); var client = server.AlsAngemeldeter(admin.Token); @@ -62,7 +62,7 @@ public class ScanTests Datei("The Matrix (1999).srt"); // zählt nicht Datei("@eaDir/The.Matrix.1999.mkv"); // zählt auch nicht - using var server = new HaloServer(); + using var server = new FlaroServer(); var (client, bibliothek) = await MitBibliothek(server, "Movies"); var stand = await Scannen(client, bibliothek); @@ -89,7 +89,7 @@ public class ScanTests Datei("The Matrix (1999).mkv"); Datei("Inception (2010).mkv"); - using var server = new HaloServer(); + using var server = new FlaroServer(); var (client, bibliothek) = await MitBibliothek(server, "Movies"); await Scannen(client, bibliothek); @@ -106,7 +106,7 @@ public class ScanTests Datei("The Matrix (1999).mkv"); Datei("Inception (2010).mkv"); - using var server = new HaloServer(); + using var server = new FlaroServer(); var (client, bibliothek) = await MitBibliothek(server, "Movies"); await Scannen(client, bibliothek); @@ -125,7 +125,7 @@ public class ScanTests Datei("The Matrix (1999) - 1080p.mkv"); Datei("The Matrix (1999) - 2160p.mkv"); - using var server = new HaloServer(); + using var server = new FlaroServer(); var (client, bibliothek) = await MitBibliothek(server, "Movies"); await Scannen(client, bibliothek); @@ -142,7 +142,7 @@ public class ScanTests Datei("Dark/Staffel 2/Dark - S02E01 - Anfänge.mkv"); Datei("Notruf.Hafenkante.S01E01.German.1080p.mkv"); - using var server = new HaloServer(); + using var server = new FlaroServer(); var (client, bibliothek) = await MitBibliothek(server, "Shows"); await Scannen(client, bibliothek); @@ -169,7 +169,7 @@ public class ScanTests Datei("Dark/Dark - S01E01.mkv"); Datei("Dark/Irgendein Mitschnitt.mkv"); - using var server = new HaloServer(); + using var server = new FlaroServer(); var (client, bibliothek) = await MitBibliothek(server, "Shows"); var stand = await Scannen(client, bibliothek); @@ -185,7 +185,7 @@ public class ScanTests Datei("The Matrix Reloaded (2003).mkv"); Datei("Inception (2010).mkv"); - using var server = new HaloServer(); + using var server = new FlaroServer(); var (client, bibliothek) = await MitBibliothek(server, "Movies"); await Scannen(client, bibliothek); @@ -199,7 +199,7 @@ public class ScanTests { for (var i = 1; i <= 5; i++) Datei($"Film {i} (200{i}).mkv"); - using var server = new HaloServer(); + using var server = new FlaroServer(); var (client, bibliothek) = await MitBibliothek(server, "Movies"); await Scannen(client, bibliothek); @@ -215,7 +215,7 @@ public class ScanTests [Test] public async Task Vor_dem_ersten_Lauf_steht_der_Scan_auf_untaetig() { - using var server = new HaloServer(); + using var server = new FlaroServer(); var (client, bibliothek) = await MitBibliothek(server, "Movies"); var stand = await client.GetFromJsonAsync($"/api/v1/libraries/{bibliothek}/scan"); @@ -225,7 +225,7 @@ public class ScanTests [Test] public async Task Ein_gewoehnlicher_Benutzer_stoesst_keinen_Scan_an() { - using var server = new HaloServer(); + using var server = new FlaroServer(); var (admin, bibliothek) = await MitBibliothek(server, "Movies"); await admin.PostAsJsonAsync("/api/v1/users", new CreateUserRequest("gast", "auch-ein-langes-passwort", false)); @@ -240,7 +240,7 @@ public class ScanTests [Test] public async Task Eine_Bibliothek_die_es_nicht_gibt_laesst_sich_nicht_scannen() { - using var server = new HaloServer(); + using var server = new FlaroServer(); var (client, _) = await MitBibliothek(server, "Movies"); var versuch = await client.PostAsync($"/api/v1/libraries/{Guid.CreateVersion7()}/scan", null); diff --git a/server/tests/Halo.Api.Tests/SetupTests.cs b/server/tests/Flaro.Api.Tests/SetupTests.cs similarity index 89% rename from server/tests/Halo.Api.Tests/SetupTests.cs rename to server/tests/Flaro.Api.Tests/SetupTests.cs index ba8b961..e24a4d9 100644 --- a/server/tests/Halo.Api.Tests/SetupTests.cs +++ b/server/tests/Flaro.Api.Tests/SetupTests.cs @@ -1,15 +1,15 @@ using System.Net; using System.Net.Http.Json; -using Halo.Api.Endpoints; +using Flaro.Api.Endpoints; -namespace Halo.Api.Tests; +namespace Flaro.Api.Tests; public class SetupTests { [Test] public async Task Ein_frischer_Server_verlangt_Einrichtung() { - using var server = new HaloServer(); + using var server = new FlaroServer(); var info = await server.Client.GetFromJsonAsync("/api/v1/system/info"); Assert.That(info!.NeedsSetup, Is.True); } @@ -17,7 +17,7 @@ public class SetupTests [Test] public async Task Die_Einrichtung_legt_einen_Administrator_an() { - using var server = new HaloServer(); + using var server = new FlaroServer(); var antwort = await server.Client.PostAsJsonAsync("/api/v1/system/setup", new SetupRequest("guido", "ein-langes-passwort")); @@ -40,7 +40,7 @@ public class SetupTests [Test] public async Task Ein_zweites_Mal_Einrichten_wird_abgelehnt() { - using var server = new HaloServer(); + using var server = new FlaroServer(); await server.SetUpAndSignIn(); var zweiterVersuch = await server.Client.PostAsJsonAsync("/api/v1/system/setup", @@ -52,7 +52,7 @@ public class SetupTests [Test] public async Task Ein_zu_kurzes_Passwort_wird_abgelehnt() { - using var server = new HaloServer(); + using var server = new FlaroServer(); var antwort = await server.Client.PostAsJsonAsync("/api/v1/system/setup", new SetupRequest("guido", "kurz")); @@ -64,7 +64,7 @@ public class SetupTests [Test] public async Task Die_Gesundheitsfrage_braucht_keine_Anmeldung() { - using var server = new HaloServer(); + using var server = new FlaroServer(); var antwort = await server.Client.GetAsync("/health"); Assert.That(antwort.StatusCode, Is.EqualTo(HttpStatusCode.OK)); } diff --git a/server/tests/Halo.Api.Tests/SignInTests.cs b/server/tests/Flaro.Api.Tests/SignInTests.cs similarity index 91% rename from server/tests/Halo.Api.Tests/SignInTests.cs rename to server/tests/Flaro.Api.Tests/SignInTests.cs index dc681ea..480219b 100644 --- a/server/tests/Halo.Api.Tests/SignInTests.cs +++ b/server/tests/Flaro.Api.Tests/SignInTests.cs @@ -1,16 +1,16 @@ using System.Net; using System.Net.Http.Headers; using System.Net.Http.Json; -using Halo.Api.Endpoints; +using Flaro.Api.Endpoints; -namespace Halo.Api.Tests; +namespace Flaro.Api.Tests; public class SignInTests { [Test] public async Task Mit_richtigem_Passwort_gibt_es_ein_Token() { - using var server = new HaloServer(); + using var server = new FlaroServer(); var anmeldung = await server.SetUpAndSignIn(); Assert.That(anmeldung.Token, Is.Not.Empty); @@ -20,7 +20,7 @@ public class SignInTests [Test] public async Task Mit_falschem_Passwort_gibt_es_keines() { - using var server = new HaloServer(); + using var server = new FlaroServer(); await server.SetUpAndSignIn(); var antwort = await server.Client.PostAsJsonAsync("/api/v1/auth/login", @@ -33,7 +33,7 @@ public class SignInTests [Test] public async Task Ein_unbekannter_Name_antwortet_wie_ein_falsches_Passwort() { - using var server = new HaloServer(); + using var server = new FlaroServer(); await server.SetUpAndSignIn(); var unbekannt = await server.Client.PostAsJsonAsync("/api/v1/auth/login", @@ -55,7 +55,7 @@ public class SignInTests [Test] public async Task Mit_Token_beantwortet_der_Server_wer_man_ist() { - using var server = new HaloServer(); + using var server = new FlaroServer(); var anmeldung = await server.SetUpAndSignIn(); var ich = await server.AlsAngemeldeter(anmeldung.Token) @@ -68,7 +68,7 @@ public class SignInTests [Test] public async Task Ohne_Token_antwortet_er_nicht() { - using var server = new HaloServer(); + using var server = new FlaroServer(); await server.SetUpAndSignIn(); var antwort = await server.Client.GetAsync("/api/v1/auth/me"); @@ -78,7 +78,7 @@ public class SignInTests [Test] public async Task Ein_erfundenes_Token_gilt_nicht() { - using var server = new HaloServer(); + using var server = new FlaroServer(); await server.SetUpAndSignIn(); var antwort = await server.AlsAngemeldeter("ausgedacht-aber-lang-genug").GetAsync("/api/v1/auth/me"); @@ -95,7 +95,7 @@ public class SignInTests [Test] public async Task Abmelden_entwertet_das_Token_augenblicklich() { - using var server = new HaloServer(); + using var server = new FlaroServer(); var anmeldung = await server.SetUpAndSignIn(); var client = server.AlsAngemeldeter(anmeldung.Token); @@ -109,7 +109,7 @@ public class SignInTests [Test] public async Task Eine_erneute_Anmeldung_desselben_Geraets_entwertet_das_alte_Token() { - using var server = new HaloServer(); + using var server = new FlaroServer(); var erste = await server.SetUpAndSignIn(); var zweite = await server.SignIn("guido", "ein-langes-passwort", "iPhone", "geraet-1"); @@ -124,7 +124,7 @@ public class SignInTests [Test] public async Task Ein_anderes_Geraet_laesst_das_erste_in_Ruhe() { - using var server = new HaloServer(); + using var server = new FlaroServer(); var telefon = await server.SetUpAndSignIn(); var fernseher = await server.SignIn("guido", "ein-langes-passwort", "Apple TV", "geraet-2"); diff --git a/server/tests/Halo.Core.Tests/AuthCodeTests.cs b/server/tests/Flaro.Core.Tests/AuthCodeTests.cs similarity index 98% rename from server/tests/Halo.Core.Tests/AuthCodeTests.cs rename to server/tests/Flaro.Core.Tests/AuthCodeTests.cs index 1d81805..bde65c1 100644 --- a/server/tests/Halo.Core.Tests/AuthCodeTests.cs +++ b/server/tests/Flaro.Core.Tests/AuthCodeTests.cs @@ -1,6 +1,6 @@ -using Halo.Core.Auth; +using Flaro.Core.Auth; -namespace Halo.Core.Tests; +namespace Flaro.Core.Tests; public class SecretsTests { diff --git a/server/tests/Halo.Core.Tests/DeliveryDeciderTests.cs b/server/tests/Flaro.Core.Tests/DeliveryDeciderTests.cs similarity index 98% rename from server/tests/Halo.Core.Tests/DeliveryDeciderTests.cs rename to server/tests/Flaro.Core.Tests/DeliveryDeciderTests.cs index 7e60c20..0c61a5a 100644 --- a/server/tests/Halo.Core.Tests/DeliveryDeciderTests.cs +++ b/server/tests/Flaro.Core.Tests/DeliveryDeciderTests.cs @@ -1,7 +1,7 @@ -using Halo.Core.Delivery; -using Halo.Core.Library; +using Flaro.Core.Delivery; +using Flaro.Core.Library; -namespace Halo.Core.Tests; +namespace Flaro.Core.Tests; public class DeliveryDeciderTests { diff --git a/server/tests/Halo.Core.Tests/FileNameTests.cs b/server/tests/Flaro.Core.Tests/FileNameTests.cs similarity index 99% rename from server/tests/Halo.Core.Tests/FileNameTests.cs rename to server/tests/Flaro.Core.Tests/FileNameTests.cs index af6a470..2c1ea0c 100644 --- a/server/tests/Halo.Core.Tests/FileNameTests.cs +++ b/server/tests/Flaro.Core.Tests/FileNameTests.cs @@ -1,6 +1,6 @@ -using Halo.Core.Library; +using Flaro.Core.Library; -namespace Halo.Core.Tests; +namespace Flaro.Core.Tests; public class FilmNamenTests { diff --git a/server/tests/Halo.Core.Tests/Halo.Core.Tests.csproj b/server/tests/Flaro.Core.Tests/Flaro.Core.Tests.csproj similarity index 91% rename from server/tests/Halo.Core.Tests/Halo.Core.Tests.csproj rename to server/tests/Flaro.Core.Tests/Flaro.Core.Tests.csproj index 7aa314b..2dda915 100644 --- a/server/tests/Halo.Core.Tests/Halo.Core.Tests.csproj +++ b/server/tests/Flaro.Core.Tests/Flaro.Core.Tests.csproj @@ -21,7 +21,7 @@ - + diff --git a/server/tests/Halo.Core.Tests/LibraryWalkerTests.cs b/server/tests/Flaro.Core.Tests/LibraryWalkerTests.cs similarity index 97% rename from server/tests/Halo.Core.Tests/LibraryWalkerTests.cs rename to server/tests/Flaro.Core.Tests/LibraryWalkerTests.cs index e30f5ea..5f64097 100644 --- a/server/tests/Halo.Core.Tests/LibraryWalkerTests.cs +++ b/server/tests/Flaro.Core.Tests/LibraryWalkerTests.cs @@ -1,6 +1,6 @@ -using Halo.Core.Library; +using Flaro.Core.Library; -namespace Halo.Core.Tests; +namespace Flaro.Core.Tests; public class LibraryWalkerTests { @@ -8,7 +8,7 @@ public class LibraryWalkerTests [SetUp] public void Anlegen() => _wurzel = Directory.CreateDirectory( - Path.Combine(Path.GetTempPath(), "halo-bestand-" + Guid.CreateVersion7().ToString("N"))).FullName; + Path.Combine(Path.GetTempPath(), "flaro-bestand-" + Guid.CreateVersion7().ToString("N"))).FullName; [TearDown] public void Aufraeumen() diff --git a/server/tests/Halo.Core.Tests/PasswordHasherTests.cs b/server/tests/Flaro.Core.Tests/PasswordHasherTests.cs similarity index 98% rename from server/tests/Halo.Core.Tests/PasswordHasherTests.cs rename to server/tests/Flaro.Core.Tests/PasswordHasherTests.cs index 16a6fbe..d6ce53c 100644 --- a/server/tests/Halo.Core.Tests/PasswordHasherTests.cs +++ b/server/tests/Flaro.Core.Tests/PasswordHasherTests.cs @@ -1,6 +1,6 @@ -using Halo.Core.Users; +using Flaro.Core.Users; -namespace Halo.Core.Tests; +namespace Flaro.Core.Tests; public class PasswordHasherTests { diff --git a/server/tests/Halo.Core.Tests/SidecarTests.cs b/server/tests/Flaro.Core.Tests/SidecarTests.cs similarity index 95% rename from server/tests/Halo.Core.Tests/SidecarTests.cs rename to server/tests/Flaro.Core.Tests/SidecarTests.cs index dbec577..5576aec 100644 --- a/server/tests/Halo.Core.Tests/SidecarTests.cs +++ b/server/tests/Flaro.Core.Tests/SidecarTests.cs @@ -1,8 +1,8 @@ -using Halo.Core.Library; +using Flaro.Core.Library; -namespace Halo.Core.Tests; +namespace Flaro.Core.Tests; -/// Was Halo in einen Medienordner schreiben darf. +/// Was Flaro in einen Medienordner schreiben darf. /// /// /// Die wichtigste Prüfdatei des Projekts. Damit Plakate neben dem Film @@ -86,7 +86,7 @@ public class SidecarNamesTests /// /// /// Die beiden Hälften könnten auseinanderlaufen — jemand ändert das Muster - /// für Folgen und vergisst die Liste. Dann schriebe Halo nichts mehr und + /// für Folgen und vergisst die Liste. Dann schriebe Flaro nichts mehr und /// niemand wüsste, warum. /// [TestCase("Dark - S01E01.mkv")] @@ -190,12 +190,12 @@ public class NfoTests Assert.That(Nfo.ReadLocked(kaputt), Is.False); } - /// Eine NFO aus dem Medienordner hat Halo nicht geschrieben. + /// Eine NFO aus dem Medienordner hat Flaro nicht geschrieben. /// /// /// Ohne abgeschaltete DTDs wäre das ein Weg, fremde Dateien zu lesen. /// Eine untergeschobene NFO mit einer externen Entität könnte den Server - /// dazu bringen, /config/halo.db einzulesen und den Inhalt als + /// dazu bringen, /config/flaro.db einzulesen und den Inhalt als /// Titel auszuliefern. /// [Test] diff --git a/server/tests/Halo.Media.Tests/FfprobeRunnerTests.cs b/server/tests/Flaro.Media.Tests/FfprobeRunnerTests.cs similarity index 97% rename from server/tests/Halo.Media.Tests/FfprobeRunnerTests.cs rename to server/tests/Flaro.Media.Tests/FfprobeRunnerTests.cs index f1f9218..3012226 100644 --- a/server/tests/Halo.Media.Tests/FfprobeRunnerTests.cs +++ b/server/tests/Flaro.Media.Tests/FfprobeRunnerTests.cs @@ -1,7 +1,7 @@ -using Halo.Core.Library; +using Flaro.Core.Library; using Microsoft.Extensions.Logging.Abstractions; -namespace Halo.Media.Tests; +namespace Flaro.Media.Tests; public class FfprobeRunnerTests { @@ -13,7 +13,7 @@ public class FfprobeRunnerTests { if (!Testdateien.FfmpegVorhanden) Assert.Ignore("ffmpeg ist auf diesem Rechner nicht installiert."); _ordner = Directory.CreateDirectory( - Path.Combine(Path.GetTempPath(), "halo-probe-" + Guid.CreateVersion7().ToString("N"))).FullName; + Path.Combine(Path.GetTempPath(), "flaro-probe-" + Guid.CreateVersion7().ToString("N"))).FullName; _ffprobe = new FfprobeRunner( new FfmpegOptions(Testdateien.Suchen("ffmpeg")!, Testdateien.Suchen("ffprobe")!), NullLogger.Instance); diff --git a/server/tests/Halo.Media.Tests/Halo.Media.Tests.csproj b/server/tests/Flaro.Media.Tests/Flaro.Media.Tests.csproj similarity index 84% rename from server/tests/Halo.Media.Tests/Halo.Media.Tests.csproj rename to server/tests/Flaro.Media.Tests/Flaro.Media.Tests.csproj index 82330b5..231695f 100644 --- a/server/tests/Halo.Media.Tests/Halo.Media.Tests.csproj +++ b/server/tests/Flaro.Media.Tests/Flaro.Media.Tests.csproj @@ -21,8 +21,8 @@ - - + + diff --git a/server/tests/Halo.Media.Tests/RemuxArgumentsTests.cs b/server/tests/Flaro.Media.Tests/RemuxArgumentsTests.cs similarity index 98% rename from server/tests/Halo.Media.Tests/RemuxArgumentsTests.cs rename to server/tests/Flaro.Media.Tests/RemuxArgumentsTests.cs index bdcebba..430fd69 100644 --- a/server/tests/Halo.Media.Tests/RemuxArgumentsTests.cs +++ b/server/tests/Flaro.Media.Tests/RemuxArgumentsTests.cs @@ -1,7 +1,7 @@ -using Halo.Core.Delivery; -using Halo.Core.Library; +using Flaro.Core.Delivery; +using Flaro.Core.Library; -namespace Halo.Media.Tests; +namespace Flaro.Media.Tests; /// Die ffmpeg-Zeile, betrachtet ohne sie auszuführen. public class RemuxArgumentsTests diff --git a/server/tests/Halo.Media.Tests/RemuxTests.cs b/server/tests/Flaro.Media.Tests/RemuxTests.cs similarity index 97% rename from server/tests/Halo.Media.Tests/RemuxTests.cs rename to server/tests/Flaro.Media.Tests/RemuxTests.cs index 4b8d740..3a51241 100644 --- a/server/tests/Halo.Media.Tests/RemuxTests.cs +++ b/server/tests/Flaro.Media.Tests/RemuxTests.cs @@ -1,8 +1,8 @@ -using Halo.Core.Delivery; -using Halo.Core.Library; +using Flaro.Core.Delivery; +using Flaro.Core.Library; using Microsoft.Extensions.Logging.Abstractions; -namespace Halo.Media.Tests; +namespace Flaro.Media.Tests; /// Umpacken, von der echten Datei bis zum Ergebnis. public class RemuxTests @@ -16,7 +16,7 @@ public class RemuxTests { if (!Testdateien.FfmpegVorhanden) Assert.Ignore("ffmpeg ist auf diesem Rechner nicht installiert."); _ordner = Directory.CreateDirectory( - Path.Combine(Path.GetTempPath(), "halo-umpacken-" + Guid.CreateVersion7().ToString("N"))).FullName; + Path.Combine(Path.GetTempPath(), "flaro-umpacken-" + Guid.CreateVersion7().ToString("N"))).FullName; var optionen = new FfmpegOptions(Testdateien.Suchen("ffmpeg")!, Testdateien.Suchen("ffprobe")!); _ffprobe = new FfprobeRunner(optionen, NullLogger.Instance); _umpacker = new FfmpegRemuxer(optionen, NullLogger.Instance); diff --git a/server/tests/Halo.Media.Tests/SidecarWriterTests.cs b/server/tests/Flaro.Media.Tests/SidecarWriterTests.cs similarity index 94% rename from server/tests/Halo.Media.Tests/SidecarWriterTests.cs rename to server/tests/Flaro.Media.Tests/SidecarWriterTests.cs index 79fce01..9b09541 100644 --- a/server/tests/Halo.Media.Tests/SidecarWriterTests.cs +++ b/server/tests/Flaro.Media.Tests/SidecarWriterTests.cs @@ -1,8 +1,8 @@ using System.Text; -using Halo.Core.Library; +using Flaro.Core.Library; using Microsoft.Extensions.Logging.Abstractions; -namespace Halo.Media.Tests; +namespace Flaro.Media.Tests; /// Was wirklich auf der Platte landet. public class SidecarWriterTests @@ -14,7 +14,7 @@ public class SidecarWriterTests public void Anlegen() { _ordner = Directory.CreateDirectory(Path.Combine( - Path.GetTempPath(), "halo-beiwerk-" + Guid.CreateVersion7().ToString("N"), + Path.GetTempPath(), "flaro-beiwerk-" + Guid.CreateVersion7().ToString("N"), "Der Untergang (2004)")).FullName; _film = Path.Combine(_ordner, "Der Untergang (2004).mkv"); File.WriteAllBytes(_film, new byte[2048]); @@ -96,7 +96,7 @@ public class SidecarWriterTests /// /// /// Eine vorhandene NFO ist eine Zuordnung, die jemand getroffen hat. Sie - /// zu übergehen, bloss weil Halo selbst nicht schreiben darf, wäre + /// zu übergehen, bloss weil Flaro selbst nicht schreiben darf, wäre /// verkehrt herum. /// [Test] @@ -121,7 +121,7 @@ public class SidecarWriterTests await Schreiber().WriteTextAsync(_film, SidecarNames.MovieNfo, "neu"); Assert.That(await File.ReadAllTextAsync(Path.Combine(_ordner, "movie.nfo")), Is.EqualTo("neu")); - Assert.That(Directory.GetFiles(_ordner, "*.halo-tmp"), Is.Empty, "Keine Reste vom Umbenennen"); + Assert.That(Directory.GetFiles(_ordner, "*.flaro-tmp"), Is.Empty, "Keine Reste vom Umbenennen"); } [Test] diff --git a/server/tests/Halo.Media.Tests/Testdateien.cs b/server/tests/Flaro.Media.Tests/Testdateien.cs similarity index 96% rename from server/tests/Halo.Media.Tests/Testdateien.cs rename to server/tests/Flaro.Media.Tests/Testdateien.cs index d0c1d3f..430c792 100644 --- a/server/tests/Halo.Media.Tests/Testdateien.cs +++ b/server/tests/Flaro.Media.Tests/Testdateien.cs @@ -1,13 +1,13 @@ using System.Diagnostics; -namespace Halo.Media.Tests; +namespace Flaro.Media.Tests; /// Baut echte Mediendateien mit ffmpeg. /// /// /// Echte Dateien und keine aufgezeichneten Antworten. Bei TMDB ist das /// umgekehrt richtig — dort steht ein fremder Dienst dahinter. Hier geht es -/// um das Werkzeug, das Halo im Container ohnehin mitbringt, und die Frage +/// um das Werkzeug, das Flaro im Container ohnehin mitbringt, und die Frage /// „liest er die zweite Tonspur mitsamt Sprache?" lässt sich nur an einer /// Datei beantworten, die wirklich zwei hat. /// @@ -67,7 +67,7 @@ public static class Testdateien /// daran entscheidet sich, ob eine sonst tadellose Datei stumm bliebe. /// Der Encoder gilt bei ffmpeg als erprobungsweise und braucht deshalb /// -strict -2 — das betrifft nur das Erzeugen dieser Testvorlage, - /// nicht Halo. + /// nicht Flaro. /// public static void MitUntauglichemTon(string ziel) => Ausführen("ffmpeg", [ diff --git a/server/tests/Halo.Metadata.Tests/Attrappe.cs b/server/tests/Flaro.Metadata.Tests/Attrappe.cs similarity index 98% rename from server/tests/Halo.Metadata.Tests/Attrappe.cs rename to server/tests/Flaro.Metadata.Tests/Attrappe.cs index 89decde..25489c0 100644 --- a/server/tests/Halo.Metadata.Tests/Attrappe.cs +++ b/server/tests/Flaro.Metadata.Tests/Attrappe.cs @@ -1,7 +1,7 @@ using System.Net; using System.Text; -namespace Halo.Metadata.Tests; +namespace Flaro.Metadata.Tests; /// Ein HTTP-Gegenüber, das antwortet, was der Test vorgibt. /// diff --git a/server/tests/Halo.Metadata.Tests/Halo.Metadata.Tests.csproj b/server/tests/Flaro.Metadata.Tests/Flaro.Metadata.Tests.csproj similarity index 82% rename from server/tests/Halo.Metadata.Tests/Halo.Metadata.Tests.csproj rename to server/tests/Flaro.Metadata.Tests/Flaro.Metadata.Tests.csproj index a9ddc52..d3add5c 100644 --- a/server/tests/Halo.Metadata.Tests/Halo.Metadata.Tests.csproj +++ b/server/tests/Flaro.Metadata.Tests/Flaro.Metadata.Tests.csproj @@ -21,8 +21,8 @@ - - + + diff --git a/server/tests/Halo.Metadata.Tests/ImageCacheTests.cs b/server/tests/Flaro.Metadata.Tests/ImageCacheTests.cs similarity index 95% rename from server/tests/Halo.Metadata.Tests/ImageCacheTests.cs rename to server/tests/Flaro.Metadata.Tests/ImageCacheTests.cs index 262f2fa..ae5b954 100644 --- a/server/tests/Halo.Metadata.Tests/ImageCacheTests.cs +++ b/server/tests/Flaro.Metadata.Tests/ImageCacheTests.cs @@ -1,9 +1,9 @@ using System.Net; using System.Text; -using Halo.Core.Metadata; +using Flaro.Core.Metadata; using Microsoft.Extensions.Logging.Abstractions; -namespace Halo.Metadata.Tests; +namespace Flaro.Metadata.Tests; public class ImageCacheTests { @@ -11,7 +11,7 @@ public class ImageCacheTests [SetUp] public void Anlegen() => _wurzel = Directory.CreateDirectory( - Path.Combine(Path.GetTempPath(), "halo-bilder-" + Guid.CreateVersion7().ToString("N"))).FullName; + Path.Combine(Path.GetTempPath(), "flaro-bilder-" + Guid.CreateVersion7().ToString("N"))).FullName; [TearDown] public void Aufraeumen() @@ -71,10 +71,10 @@ public class ImageCacheTests /// /// Die wichtigste Prüfung dieser Datei. Der Schlüssel kommt aus /// einer URL. Liesse er Pfadangaben durch, wäre - /// /api/v1/images/../../config/halo.db ein Weg, die Datenbank + /// /api/v1/images/../../config/flaro.db ein Weg, die Datenbank /// herunterzuladen — samt aller Token-Fingerabdrücke. /// - [TestCase("../../config/halo.db")] + [TestCase("../../config/flaro.db")] [TestCase("..%2f..%2fconfig")] [TestCase("/etc/passwd")] [TestCase("abc")] diff --git a/server/tests/Halo.Metadata.Tests/TmdbClientTests.cs b/server/tests/Flaro.Metadata.Tests/TmdbClientTests.cs similarity index 99% rename from server/tests/Halo.Metadata.Tests/TmdbClientTests.cs rename to server/tests/Flaro.Metadata.Tests/TmdbClientTests.cs index f7bf623..253d082 100644 --- a/server/tests/Halo.Metadata.Tests/TmdbClientTests.cs +++ b/server/tests/Flaro.Metadata.Tests/TmdbClientTests.cs @@ -1,8 +1,8 @@ using System.Net; -using Halo.Core.Metadata; +using Flaro.Core.Metadata; using Microsoft.Extensions.Logging.Abstractions; -namespace Halo.Metadata.Tests; +namespace Flaro.Metadata.Tests; public class TmdbClientTests { diff --git a/server/tests/Halo.Metadata.Tests/ZugangTests.cs b/server/tests/Flaro.Metadata.Tests/ZugangTests.cs similarity index 98% rename from server/tests/Halo.Metadata.Tests/ZugangTests.cs rename to server/tests/Flaro.Metadata.Tests/ZugangTests.cs index 2815f7c..aabd353 100644 --- a/server/tests/Halo.Metadata.Tests/ZugangTests.cs +++ b/server/tests/Flaro.Metadata.Tests/ZugangTests.cs @@ -1,8 +1,8 @@ using Microsoft.Extensions.Logging.Abstractions; -namespace Halo.Metadata.Tests; +namespace Flaro.Metadata.Tests; -/// Womit sich Halo bei TMDB ausweist. +/// Womit sich Flaro bei TMDB ausweist. public class ZugangTests { private const string LeseToken = "eyJhbGciOiJIUzI1NiJ9.beispiel.unterschrift"; diff --git a/web/README.md b/web/README.md index 57846e4..32efd93 100644 --- a/web/README.md +++ b/web/README.md @@ -1,4 +1,4 @@ -# Halo Web +# Flaro 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 && HALO_SERVER=http://jellyfin:8096 node index.js +cd ../server && FLARO_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 && HALO_SERVER=http://jellyfin:8096 npm run dev +cd app && FLARO_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 616e5f8..6d2119e 100644 --- a/web/app/index.html +++ b/web/app/index.html @@ -3,7 +3,7 @@ -Halo +Flaro
diff --git a/web/app/package-lock.json b/web/app/package-lock.json index ba62eef..a0fe749 100644 --- a/web/app/package-lock.json +++ b/web/app/package-lock.json @@ -1,11 +1,11 @@ { - "name": "halo-web", + "name": "flaro-web", "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "halo-web", + "name": "flaro-web", "version": "0.1.0", "dependencies": { "hls.js": "^1.5.18" diff --git a/web/app/package.json b/web/app/package.json index d46ec0c..e77adda 100644 --- a/web/app/package.json +++ b/web/app/package.json @@ -1,5 +1,5 @@ { - "name": "halo-web", + "name": "flaro-web", "private": true, "version": "0.1.0", "type": "module", diff --git a/web/app/src/api.ts b/web/app/src/api.ts index a47fd49..e15c18e 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('halo.token') ?? '', - userId: localStorage.getItem('halo.user') ?? '', + token: localStorage.getItem('flaro.token') ?? '', + userId: localStorage.getItem('flaro.user') ?? '', geraet: - localStorage.getItem('halo.device') ?? + localStorage.getItem('flaro.device') ?? (() => { - const id = 'halo-web-' + Math.random().toString(36).slice(2, 12); - localStorage.setItem('halo.device', id); + const id = 'flaro-web-' + Math.random().toString(36).slice(2, 12); + localStorage.setItem('flaro.device', id); return id; })(), }; @@ -32,7 +32,7 @@ export const sitzung = { * angemeldet, obwohl der Schlüssel stimmt. */ function kopfzeile(): string { const teile = [ - 'Client="Halo Web"', + 'Client="Flaro 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('halo.' + schluessel); + const roh = localStorage.getItem('flaro.' + 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( - 'halo.' + schluessel, + 'flaro.' + 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 d46531c..313c629 100644 --- a/web/app/src/style.css +++ b/web/app/src/style.css @@ -1,7 +1,7 @@ /* ============================================================================ - Halo Web — ein Frontend für Jellyfin + Flaro Web — ein Frontend für Jellyfin ---------------------------------------------------------------------------- - Die Werte stammen aus HaloDesign, nicht aus dem Augenmaß: dieselben + Die Werte stammen aus FlaroDesign, 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 f41efea..b428e98 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 = `