mirror of
https://github.com/yattee/yattee.git
synced 2026-06-04 13:54:19 +00:00
Give TVSidebarDetailContainer an optional bottom action slot and use it to show the Add Source button beside the sources list on tvOS. Switch the Settings > Sources list from a focus-capturing List to the same ScrollView+LazyVStack layout MediaSourcesView already uses, drop .buttonStyle(.card) so row icons no longer clip, and bump the row icon-to-title spacing to 24pt. Replace the sheet-based Add/Edit flow in MediaSourcesView with navigationDestinations wrapped in the sidebar container, and decorate each Add Source form (WebDAV, SMB, remote server, PeerTube browse) with its own sidebar icon and title.
69 lines
2.1 KiB
Swift
69 lines
2.1 KiB
Swift
//
|
|
// TVSidebarDetailContainer.swift
|
|
// Yattee
|
|
//
|
|
// Decorates a tvOS detail screen with a fixed 400pt left sidebar showing
|
|
// a large SF Symbol and a title, matching the look of tvOS settings.
|
|
//
|
|
|
|
#if os(tvOS)
|
|
import SwiftUI
|
|
|
|
struct TVSidebarDetailContainer<Content: View, BottomAction: View>: View {
|
|
let content: Content
|
|
let bottomAction: BottomAction
|
|
var systemImage: String?
|
|
var title: String?
|
|
|
|
init(
|
|
systemImage: String? = nil,
|
|
title: String? = nil,
|
|
@ViewBuilder bottomAction: () -> BottomAction = { EmptyView() },
|
|
@ViewBuilder content: () -> Content
|
|
) {
|
|
self.content = content()
|
|
self.bottomAction = bottomAction()
|
|
self.systemImage = systemImage
|
|
self.title = title
|
|
}
|
|
|
|
var body: some View {
|
|
content
|
|
.focusSection()
|
|
.safeAreaInset(edge: .leading) {
|
|
if let systemImage {
|
|
VStack(spacing: 0) {
|
|
Spacer()
|
|
VStack(spacing: 16) {
|
|
Image(systemName: systemImage)
|
|
.font(.system(size: 80))
|
|
.foregroundStyle(.secondary)
|
|
if let title {
|
|
Text(title)
|
|
.font(.title3)
|
|
.fontWeight(.semibold)
|
|
.foregroundStyle(.secondary)
|
|
.multilineTextAlignment(.center)
|
|
}
|
|
}
|
|
.allowsHitTesting(false)
|
|
|
|
if BottomAction.self != EmptyView.self {
|
|
bottomAction
|
|
.padding(.top, 40)
|
|
.focusSection()
|
|
}
|
|
|
|
Spacer()
|
|
}
|
|
.frame(width: 400)
|
|
} else {
|
|
Spacer()
|
|
.frame(width: 400)
|
|
.allowsHitTesting(false)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|