diff --git a/Yattee/ContentView.swift b/Yattee/ContentView.swift index 9f410999..9b060f41 100644 --- a/Yattee/ContentView.swift +++ b/Yattee/ContentView.swift @@ -206,8 +206,9 @@ struct AdaptiveTabView: View { } // The tab bar layout on iOS 26.1+ shows the mini player as the tab - // bar's bottom accessory; the split-view sidebar layout has no tab bar. - if usesSidebar || !Self.usesTabBottomAccessory { + // bar's bottom accessory; the split-view sidebar layout insets it + // into its detail column. + if !usesSidebar && !Self.usesTabBottomAccessory { miniPlayerOverlay } @@ -262,9 +263,8 @@ struct AdaptiveTabView: View { MiniPlayerView() } .padding(.horizontal, 16) - // The tab bar layout has a bottom tab bar (49pt) to clear; the sidebar - // layout (sidebarAdaptable) keeps its tabs at the top, so only float above the edge. - .padding(.bottom, usesSidebar ? 12 : 49 + 8) + // Clear the bottom tab bar (49pt) + .padding(.bottom, 49 + 8) // Use move-only transition (no opacity) to prevent thumbnail flash during collapse // The opacity transition caused video to appear faded during player sheet dismiss .transition(.move(edge: .bottom)) diff --git a/Yattee/Views/Navigation/UnifiedTabView.swift b/Yattee/Views/Navigation/UnifiedTabView.swift index b407447b..94ee9a68 100644 --- a/Yattee/Views/Navigation/UnifiedTabView.swift +++ b/Yattee/Views/Navigation/UnifiedTabView.swift @@ -87,6 +87,9 @@ struct UnifiedTabView: View { sidebar } detail: { detailForSelection + #if os(iOS) + .safeAreaInset(edge: .bottom, spacing: 0) { miniPlayerInset } + #endif } .zoomTransitionNamespace(zoomTransition) #if os(iOS) @@ -270,6 +273,28 @@ struct UnifiedTabView: View { } private var settingsManager: SettingsManager? { appEnvironment?.settingsManager } + + #if os(iOS) + /// The split view has no tab bar to host the mini player as a bottom + /// accessory, so it takes the detail column's bottom safe area instead: + /// floating content such as the subscriptions channel strip and the last + /// rows of every list then clear it, as they clear the tab accessory. + private var miniPlayerInset: some View { + let hasActiveVideo = appEnvironment?.playerService.state.currentVideo != nil + let isExpanded = appEnvironment?.navigationCoordinator.isPlayerExpanded ?? false + + return VStack(spacing: 0) { + if hasActiveVideo && !isExpanded { + MiniPlayerView() + .padding(.horizontal, 16) + .padding(.bottom, 12) + // Move-only transition (no opacity) prevents a thumbnail flash during collapse + .transition(.move(edge: .bottom)) + } + } + .animation(.spring(response: 0.3), value: hasActiveVideo) + } + #endif } #Preview("Unified Tab View") {