Der Upload zu App Store Connect scheiterte am Namen. „Halo" ist eine eingetragene Marke von Microsoft; im App Store heisst zwar keine App exakt so, aber reservierte und markenrechtlich belegte Namen tauchen in keiner Suche auf. Der einzige verlässliche Test war die Eingabe dort, und die ging daneben. **Der Name wurde diesmal vorher geprüft.** Zwanzig Kandidaten gegen den deutschen und amerikanischen App Store, auf exakte Treffer und auf ähnliche Namen. „Kavo" wäre dieselbe Wand gewesen — exakt belegt in beiden Stores, in Deutschland von KaVo Dental GmbH. „Flare" ist mit 42 ähnlichen Apps je Store der am dichtesten besetzte Name der ganzen Runde. **Flaro** ist in beiden frei und liest sich als eigenes Wort, nicht als Flare mit Tippfehler. Das bleibt eine Store-Suche und keine Markenrecherche — reservierte Namen ohne veröffentlichte App sieht sie nicht. Aber es ist mehr Prüfung, als beim letzten Mal stattfand. --- 2160 Textvorkommen in 273 Dateien, 49 Pfade. Betroffen ist diesmal auch der Server: `Flaro.Api`, `Flaro.Core`, `Flaro.Data`, `Flaro.Media`, `Flaro.Metadata`, `FlaroContext`, `FlaroPaths`, `flaro.db`, die Variablen `FLARO_DATA`, `FLARO_CACHE`, `FLARO_TRANSCODE`, `FLARO_WRITE_SIDECARS`, und das Image. **Vor dem Ersetzen geprüft**, ob „halo" irgendwo als Teil eines anderen Wortes steckt — und ob es im TMDB-Token vorkommt. Tat es nicht; ein blindes Ersetzen hätte den sonst zerlegt. `docs/superpowers/specs/` bleibt wie beim letzten Mal unangetastet: datierte Entwurfsdokumente sind ein Protokoll getroffener Entscheidungen. Das Server-Dokument hat stattdessen einen Nachtrag bekommen, damit es niemanden in die Irre führt. **Die Bundle-ID wandert mit**, zum zweiten Mal an einem Tag: `com.scarriffleservices.flaro`. Wer die vorige Fassung installiert hat, hat jetzt zwei Karteileichen auf dem Gerät — beide löschen, dann ist Ruhe. 308 Server-Tests grün, 368 im Swift-Paket, null Warnungen. iOS und tvOS bauen, das Image baut, und ein frischer Container läuft durch Einrichtung und Anmeldung. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
82 lines
3.6 KiB
Swift
82 lines
3.6 KiB
Swift
#if os(iOS)
|
|
import SwiftUI
|
|
import UIKit
|
|
|
|
/// Blendet die vom System gezeichnete Seitenleiste und Tableiste aus.
|
|
///
|
|
/// Der Grund ist das Aussehen, nicht das Verhalten. `UITabBarController`
|
|
/// zeichnet seine Seitenleiste auf dem iPad als schwebende Fläche und auf dem
|
|
/// Mac angeklebt am Fensterrand — und das lässt sich nicht umstellen.
|
|
/// `preferredLayout = .overlap` ist die dafür vorgesehene Bitte; macOS verwirft
|
|
/// sie stillschweigend. Gemessen, nicht vermutet.
|
|
///
|
|
/// Statt deshalb die ganze Navigation selbst zu bauen, bleibt der
|
|
/// `TabView` **stehen** und verliert nur sein Kleid: Auswahl, getrennte
|
|
/// Navigationsstapel je Eintrag, erhaltener Scrollstand beim Wechseln,
|
|
/// Zustandspflege — all das macht weiter das System. Gezeichnet wird darüber.
|
|
///
|
|
/// Dass das geht, war kein Ratschluss: derselbe Griff hat die Leiste
|
|
/// versuchsweise schon einmal verschwinden lassen.
|
|
struct TabChromeSuppressor: UIViewControllerRepresentable {
|
|
func makeUIViewController(context: Context) -> UIViewController { Probe() }
|
|
func updateUIViewController(_ controller: UIViewController, context: Context) {}
|
|
|
|
/// Ein Controller, der nichts zeigt und nur da ist, um im Baum zu stehen.
|
|
private final class Probe: UIViewController {
|
|
override func didMove(toParent parent: UIViewController?) {
|
|
super.didMove(toParent: parent)
|
|
suppress()
|
|
}
|
|
|
|
override func viewDidAppear(_ animated: Bool) {
|
|
super.viewDidAppear(animated)
|
|
// Ein zweites Mal: beim ersten Anhängen steht der Tab-Controller
|
|
// noch nicht zwingend im Baum.
|
|
suppress()
|
|
}
|
|
|
|
override func viewWillLayoutSubviews() {
|
|
super.viewWillLayoutSubviews()
|
|
// Und bei jedem Umbau: das System stellt die Leisten wieder her,
|
|
// wenn sich die Größenklasse ändert — beim Drehen etwa.
|
|
suppress()
|
|
}
|
|
|
|
private func suppress() {
|
|
guard let controller = Self.tabBarController(from: self) else { return }
|
|
|
|
// Erst die Form festlegen, dann ausblenden — und zwar auf die
|
|
// Tableiste, nicht auf die Seitenleiste.
|
|
//
|
|
// Nur `sidebar.isHidden = true` reichte nicht: auf dem Mac stand
|
|
// die System-Seitenleiste danach wieder da, mit eigenem Pfeil und
|
|
// eigenem Knopf, hinter unserer. Solange `mode` auf `tabSidebar`
|
|
// steht, gehört die Seitenleiste zur Darstellung und das System
|
|
// stellt sie wieder her. Steht `mode` auf `tabBar`, gibt es keine
|
|
// Seitenleiste mehr, die zurückkommen könnte — und die Tableiste
|
|
// ist ausgeblendet.
|
|
if controller.mode != .tabBar { controller.mode = .tabBar }
|
|
if !controller.isTabBarHidden { controller.isTabBarHidden = true }
|
|
if !controller.sidebar.isHidden { controller.sidebar.isHidden = true }
|
|
}
|
|
|
|
/// Sucht vom eigenen Platz aus nach oben bis zur Wurzel und von dort
|
|
/// nach unten: die Leiste liegt in der SwiftUI-Sicht *über* uns, die
|
|
/// reine Elternkette führt an ihr vorbei.
|
|
private static func tabBarController(from start: UIViewController) -> UITabBarController? {
|
|
var root = start
|
|
while let parent = root.parent { root = parent }
|
|
return search(root)
|
|
}
|
|
|
|
private static func search(_ controller: UIViewController) -> UITabBarController? {
|
|
if let found = controller as? UITabBarController { return found }
|
|
for child in controller.children {
|
|
if let found = search(child) { return found }
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
#endif
|