Files
yattee/Yattee/Views/MediaBrowser/MediaBrowserViewOptionsSheet.swift
Arkadiusz Fal 1157eef201 Fix macOS native styling for search toolbar pickers and view options
The content type segmented picker rendered as a Liquid-Glass pill instead
of a native macOS segmented control. Wrapping a `.segmented` Picker in
`.opacity`/`.disabled`/`.accessibilityHidden`/`.fixedSize` (used to keep
toolbar items mounted-but-invisible for stable layout) inserts a hosting
layer that makes the toolbar fall back to the pill rendering.

- SearchView: filters button and content type picker are now always
  visible on macOS, rendered bare so `.segmented` keeps native styling.
- SearchView: don't reset the content type to .video on submit on macOS,
  so a pre-selected type (e.g. Playlists) is preserved (iOS unchanged).
- InstanceBrowseView: same pill fix, rendering the tab / content type
  pickers bare via conditional `if` instead of opacity-masking.
- ViewOptionsSheet / MediaBrowserViewOptionsSheet: use `.formStyle(.grouped)`
  for native macOS form styling in the options popover.
2026-06-15 08:07:40 +02:00

133 lines
3.8 KiB
Swift

//
// MediaBrowserViewOptionsSheet.swift
// Yattee
//
// Sheet for customizing media browser view options.
//
import SwiftUI
struct MediaBrowserViewOptionsSheet: View {
@Environment(\.dismiss) private var dismiss
let sourceType: MediaSourceType
@Binding var sortOrder: MediaBrowserSortOrder
@Binding var sortAscending: Bool
@Binding var showOnlyPlayable: Bool
private var availableSortOptions: [MediaBrowserSortOrder] {
MediaBrowserSortOrder.availableOptions(for: sourceType)
}
var body: some View {
#if os(macOS)
// Popover content: no navigation chrome, click-outside dismisses.
formContent
.formStyle(.grouped)
.frame(width: 300)
.onAppear {
// Reset sort order if current selection is not available for this source type
if !availableSortOptions.contains(sortOrder) {
sortOrder = .name
}
}
#else
NavigationStack {
#if os(tvOS)
listContent
#else
formContent
.navigationTitle("mediaBrowser.viewOptions.title")
#if os(iOS)
.navigationBarTitleDisplayMode(.inline)
#endif
.toolbar {
sheetCloseToolbarItem { dismiss() }
}
#endif
}
#if os(iOS)
.presentationDetents([.height(280)])
.presentationDragIndicator(.visible)
#endif
.onAppear {
// Reset sort order if current selection is not available for this source type
if !availableSortOptions.contains(sortOrder) {
sortOrder = .name
}
}
#endif
}
@ViewBuilder
private var sharedOptions: some View {
Toggle("mediaBrowser.viewOptions.showOnlyPlayable", isOn: $showOnlyPlayable)
PlatformMenuPicker(String(localized: "mediaBrowser.viewOptions.sortBy"), selection: $sortOrder) {
ForEach(availableSortOptions) { order in
Label(order.displayName, systemImage: order.systemImage)
.tag(order)
}
}
Picker("mediaBrowser.viewOptions.order", selection: $sortAscending) {
Label(String(localized: "mediaBrowser.viewOptions.ascending"), systemImage: "arrow.up")
.tag(true)
Label(String(localized: "mediaBrowser.viewOptions.descending"), systemImage: "arrow.down")
.tag(false)
}
.pickerStyle(.segmented)
.listRowBackground(Color.clear)
.listRowInsets(EdgeInsets(top: 8, leading: 0, bottom: 8, trailing: 0))
}
#if os(tvOS)
private var listContent: some View {
List {
Section {
sharedOptions
}
}
.scrollClipDisabled()
.padding(.horizontal, 40)
.padding(.vertical, 24)
}
#endif
private var formContent: some View {
Form {
Section {
sharedOptions
}
}
}
}
// MARK: - Preview
#Preview("Local Folder") {
@Previewable @State var sortOrder: MediaBrowserSortOrder = .name
@Previewable @State var sortAscending = true
@Previewable @State var showOnlyPlayable = false
MediaBrowserViewOptionsSheet(
sourceType: .localFolder,
sortOrder: $sortOrder,
sortAscending: $sortAscending,
showOnlyPlayable: $showOnlyPlayable
)
}
#Preview("WebDAV") {
@Previewable @State var sortOrder: MediaBrowserSortOrder = .name
@Previewable @State var sortAscending = true
@Previewable @State var showOnlyPlayable = false
MediaBrowserViewOptionsSheet(
sourceType: .webdav,
sortOrder: $sortOrder,
sortAscending: $sortAscending,
showOnlyPlayable: $showOnlyPlayable
)
}