mirror of
https://github.com/yattee/yattee.git
synced 2026-07-21 06:42:01 +00:00
Render Add Source buttons inline on macOS where toolbar items aren't shown
Pre-macOS 26 doesn't reliably surface a detail-pane NavigationStack's toolbar confirmation items in the window title bar, leaving the "Add Source" actions invisible. Gate the toolbar placement behind macOS 26+ and fall back to an inline form/header button on older macOS across the add-source views and the sources list.
This commit is contained in:
@@ -31,6 +31,21 @@ struct AddLocalFolderView: View {
|
|||||||
!name.isEmpty && selectedFolderURL != nil
|
!name.isEmpty && selectedFolderURL != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// macOS surfaces toolbar confirmation items from a pushed-in-sheet view
|
||||||
|
/// reliably only from macOS 26 onward. On older macOS we render the
|
||||||
|
/// "Add Source" action button inline in the form instead.
|
||||||
|
private var usesToolbarActionButton: Bool {
|
||||||
|
#if os(macOS)
|
||||||
|
if #available(macOS 26, *) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return false
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Body
|
// MARK: - Body
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
@@ -99,10 +114,15 @@ struct AddLocalFolderView: View {
|
|||||||
if let result = testResult {
|
if let result = testResult {
|
||||||
SourceTestResultSection(result: result)
|
SourceTestResultSection(result: result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !usesToolbarActionButton {
|
||||||
|
actionSection
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.formStyle(.grouped)
|
.formStyle(.grouped)
|
||||||
.navigationTitle(String(localized: "sources.addLocalFolder"))
|
.navigationTitle(String(localized: "sources.addLocalFolder"))
|
||||||
.toolbar {
|
.toolbar {
|
||||||
|
if usesToolbarActionButton {
|
||||||
ToolbarItem(placement: .confirmationAction) {
|
ToolbarItem(placement: .confirmationAction) {
|
||||||
Button(String(localized: "sources.addSource")) {
|
Button(String(localized: "sources.addSource")) {
|
||||||
addSource()
|
addSource()
|
||||||
@@ -112,6 +132,7 @@ struct AddLocalFolderView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// MARK: - Sections
|
// MARK: - Sections
|
||||||
|
|||||||
@@ -87,6 +87,22 @@ struct AddRemoteServerView: View {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// macOS surfaces toolbar confirmation items from a pushed-in-sheet view
|
||||||
|
/// reliably only from macOS 26 onward. On older macOS (and on iOS/tvOS) we
|
||||||
|
/// render the "Add Source" action button inline in the form instead, so it
|
||||||
|
/// is always visible.
|
||||||
|
private var usesToolbarActionButton: Bool {
|
||||||
|
#if os(macOS)
|
||||||
|
if #available(macOS 26, *) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return false
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
private var canAdd: Bool {
|
private var canAdd: Bool {
|
||||||
guard !urlString.isEmpty else { return false }
|
guard !urlString.isEmpty else { return false }
|
||||||
|
|
||||||
@@ -172,9 +188,9 @@ struct AddRemoteServerView: View {
|
|||||||
|
|
||||||
if isFieldsRevealed {
|
if isFieldsRevealed {
|
||||||
serverConfigurationFields
|
serverConfigurationFields
|
||||||
#if !os(macOS)
|
if !usesToolbarActionButton {
|
||||||
actionSection
|
actionSection
|
||||||
#endif
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
@@ -183,8 +199,8 @@ struct AddRemoteServerView: View {
|
|||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
.formStyle(.grouped)
|
.formStyle(.grouped)
|
||||||
.toolbar {
|
.toolbar {
|
||||||
|
if isFieldsRevealed, usesToolbarActionButton {
|
||||||
ToolbarItem(placement: .confirmationAction) {
|
ToolbarItem(placement: .confirmationAction) {
|
||||||
if isFieldsRevealed {
|
|
||||||
Button {
|
Button {
|
||||||
addSource()
|
addSource()
|
||||||
} label: {
|
} label: {
|
||||||
|
|||||||
@@ -36,6 +36,21 @@ struct AddSMBView: View {
|
|||||||
!name.isEmpty && !server.isEmpty
|
!name.isEmpty && !server.isEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// macOS surfaces toolbar confirmation items from a pushed-in-sheet view
|
||||||
|
/// reliably only from macOS 26 onward. On older macOS we render the
|
||||||
|
/// "Add Source" action button inline in the form instead.
|
||||||
|
private var usesToolbarActionButton: Bool {
|
||||||
|
#if os(macOS)
|
||||||
|
if #available(macOS 26, *) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return false
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Body
|
// MARK: - Body
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
@@ -133,10 +148,15 @@ struct AddSMBView: View {
|
|||||||
if let result = testResult {
|
if let result = testResult {
|
||||||
SourceTestResultSection(result: result)
|
SourceTestResultSection(result: result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !usesToolbarActionButton {
|
||||||
|
actionSection
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.formStyle(.grouped)
|
.formStyle(.grouped)
|
||||||
.navigationTitle(String(localized: "sources.addSMB"))
|
.navigationTitle(String(localized: "sources.addSMB"))
|
||||||
.toolbar {
|
.toolbar {
|
||||||
|
if usesToolbarActionButton {
|
||||||
ToolbarItem(placement: .confirmationAction) {
|
ToolbarItem(placement: .confirmationAction) {
|
||||||
Button {
|
Button {
|
||||||
addSource()
|
addSource()
|
||||||
@@ -154,6 +174,7 @@ struct AddSMBView: View {
|
|||||||
.keyboardShortcut(.defaultAction)
|
.keyboardShortcut(.defaultAction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
if let prefillServer {
|
if let prefillServer {
|
||||||
server = prefillServer
|
server = prefillServer
|
||||||
|
|||||||
@@ -37,6 +37,21 @@ struct AddWebDAVView: View {
|
|||||||
!name.isEmpty && !urlString.isEmpty && URL(string: urlString) != nil
|
!name.isEmpty && !urlString.isEmpty && URL(string: urlString) != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// macOS surfaces toolbar confirmation items from a pushed-in-sheet view
|
||||||
|
/// reliably only from macOS 26 onward. On older macOS we render the
|
||||||
|
/// "Add Source" action button inline in the form instead.
|
||||||
|
private var usesToolbarActionButton: Bool {
|
||||||
|
#if os(macOS)
|
||||||
|
if #available(macOS 26, *) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return false
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Body
|
// MARK: - Body
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
@@ -134,10 +149,15 @@ struct AddWebDAVView: View {
|
|||||||
if let result = testResult {
|
if let result = testResult {
|
||||||
SourceTestResultSection(result: result)
|
SourceTestResultSection(result: result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !usesToolbarActionButton {
|
||||||
|
actionSection
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.formStyle(.grouped)
|
.formStyle(.grouped)
|
||||||
.navigationTitle(String(localized: "sources.addWebDAV"))
|
.navigationTitle(String(localized: "sources.addWebDAV"))
|
||||||
.toolbar {
|
.toolbar {
|
||||||
|
if usesToolbarActionButton {
|
||||||
ToolbarItem(placement: .confirmationAction) {
|
ToolbarItem(placement: .confirmationAction) {
|
||||||
Button {
|
Button {
|
||||||
addSource()
|
addSource()
|
||||||
@@ -155,6 +175,7 @@ struct AddWebDAVView: View {
|
|||||||
.keyboardShortcut(.defaultAction)
|
.keyboardShortcut(.defaultAction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
if let url = prefillURL {
|
if let url = prefillURL {
|
||||||
urlString = url.absoluteString
|
urlString = url.absoluteString
|
||||||
|
|||||||
@@ -64,6 +64,16 @@ struct SourcesListView: View {
|
|||||||
.focusSection()
|
.focusSection()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#elseif os(macOS)
|
||||||
|
VStack(spacing: 0) {
|
||||||
|
// macOS 15 does not surface a detail-pane NavigationStack's
|
||||||
|
// toolbar items to the window title bar, so the toolbar
|
||||||
|
// "Add Source" button is invisible there. Show an inline
|
||||||
|
// header button as a fallback on older macOS. On macOS 26+
|
||||||
|
// the toolbar button works, so this header is omitted.
|
||||||
|
macOSLegacyAddHeader
|
||||||
|
sourcesInner
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
sourcesInner
|
sourcesInner
|
||||||
#endif
|
#endif
|
||||||
@@ -76,6 +86,7 @@ struct SourcesListView: View {
|
|||||||
#endif
|
#endif
|
||||||
#if os(iOS) || os(macOS)
|
#if os(iOS) || os(macOS)
|
||||||
.toolbar {
|
.toolbar {
|
||||||
|
if showAddButtonInToolbar {
|
||||||
ToolbarItem(placement: .primaryAction) {
|
ToolbarItem(placement: .primaryAction) {
|
||||||
Button {
|
Button {
|
||||||
showingAddSheet = true
|
showingAddSheet = true
|
||||||
@@ -85,6 +96,7 @@ struct SourcesListView: View {
|
|||||||
.accessibilityIdentifier("sources.addButton")
|
.accessibilityIdentifier("sources.addButton")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
.navigationDestination(isPresented: $showingAddSheet) {
|
.navigationDestination(isPresented: $showingAddSheet) {
|
||||||
@@ -122,6 +134,47 @@ struct SourcesListView: View {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether the "Add Source" button should be placed in the window/navigation
|
||||||
|
/// toolbar. On macOS this only works reliably from macOS 26 onward (see
|
||||||
|
/// `macOSLegacyAddHeader`); iOS always uses the toolbar.
|
||||||
|
private var showAddButtonInToolbar: Bool {
|
||||||
|
#if os(iOS)
|
||||||
|
return true
|
||||||
|
#elseif os(macOS)
|
||||||
|
if #available(macOS 26, *) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return false
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if os(macOS)
|
||||||
|
// Inline fallback "Add Source" button for macOS versions where the
|
||||||
|
// detail-pane toolbar item is not shown (pre-macOS 26). Only needed when
|
||||||
|
// there are existing sources — the empty state already offers its own
|
||||||
|
// add button.
|
||||||
|
@ViewBuilder
|
||||||
|
private var macOSLegacyAddHeader: some View {
|
||||||
|
if !showAddButtonInToolbar, !isEmpty {
|
||||||
|
HStack {
|
||||||
|
Spacer()
|
||||||
|
Button {
|
||||||
|
showingAddSheet = true
|
||||||
|
} label: {
|
||||||
|
Label(String(localized: "sources.addSource"), systemImage: "plus")
|
||||||
|
}
|
||||||
|
.accessibilityIdentifier("sources.addButton")
|
||||||
|
}
|
||||||
|
.padding(.horizontal, 16)
|
||||||
|
.padding(.top, 12)
|
||||||
|
.padding(.bottom, 4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
private var sourcesInner: some View {
|
private var sourcesInner: some View {
|
||||||
if isEmpty {
|
if isEmpty {
|
||||||
|
|||||||
Reference in New Issue
Block a user