diff --git a/Sources/Recap/Public/RecapScreen.swift b/Sources/Recap/Public/RecapScreen.swift index bee5a33..5d361d8 100644 --- a/Sources/Recap/Public/RecapScreen.swift +++ b/Sources/Recap/Public/RecapScreen.swift @@ -44,7 +44,7 @@ public struct RecapScreen: View { } public var body: some View { - NavigationStack { + VStack(spacing: 0.0) { TabView(selection: $selectedIndex) { self.leadingView .tag(self.tabIndex(from: .leadingView)) @@ -62,27 +62,31 @@ public struct RecapScreen: View { } .tabViewStyle(.page(indexDisplayMode: self.releases.count > 1 ? .always : .never)) .background(self.derivedBackgroundStyle) - .navigationBarTitleDisplayMode(.inline) - .toolbar(.hidden, for: .navigationBar) - .toolbar { - ToolbarItem(placement: .bottomBar) { - Button(action: { - dismissAction?() ?? dismiss() - }, label: { - Text("RECAP.SCREEN.DISMISS.BUTTON.TITLE", bundle: .module) - .font(.system(.title3, weight: .bold)) - .padding(8.0) - .padding(.vertical, 4.0) - .padding(.horizontal, 16.0) - .foregroundStyle(dismissButtonStyle.foregroundStyle) - }) - .frame(maxWidth: .infinity) - .background(self.dismissButtonStyle.backgroundStyle) - .clipShape(.rect(cornerRadius: 16.0)) - .padding(.horizontal, 20.0) - .foregroundStyle(.primary) + + Button(action: { + dismissAction?() ?? dismiss() + }, label: { + HStack { + Spacer(minLength: 0.0) + + Text("RECAP.SCREEN.DISMISS.BUTTON.TITLE", bundle: .module) + .font(.system(.title3, weight: .bold)) + .padding(8.0) + .padding(.vertical, 4.0) + .padding(.horizontal, 16.0) + .foregroundStyle(dismissButtonStyle.foregroundStyle) + + Spacer(minLength: 0.0) } - } + .contentShape(.rect(cornerRadius: 16.0)) + }) + .frame(maxWidth: .infinity) + .background(self.dismissButtonStyle.backgroundStyle) + .clipShape(.rect(cornerRadius: 16.0)) + .padding(.horizontal, 40.0) + .foregroundStyle(.primary) + .withBottomPaddingIfNoSafeArea() + .background(self.derivedBackgroundStyle) .onAppear(perform: { self.selectedIndex = self.tabIndex(from: self.startIndex) }) @@ -96,6 +100,34 @@ public struct RecapScreen: View { } } +// MARK: Convenience Initializers + +public extension RecapScreen where LeadingView == EmptyView { + init(releases: [Release], @ViewBuilder trailingView: () -> TrailingView) { + self.releases = releases + self.leadingView = EmptyView() + self.trailingView = trailingView() + } +} + +public extension RecapScreen where TrailingView == EmptyView { + init(releases: [Release], @ViewBuilder leadingView: () -> LeadingView) { + self.releases = releases + self.leadingView = leadingView() + self.trailingView = EmptyView() + } +} + +public extension RecapScreen where LeadingView == EmptyView, TrailingView == EmptyView { + init(releases: [Release]) { + self.releases = releases + self.leadingView = EmptyView() + self.trailingView = EmptyView() + } +} + +// MARK: Private + private extension RecapScreen { var displayedReleases: [Release] { self.releases.reversed() @@ -136,28 +168,24 @@ private extension RecapScreen { } } -// MARK: Convenience Initializers - -public extension RecapScreen where LeadingView == EmptyView { - init(releases: [Release], @ViewBuilder trailingView: () -> TrailingView) { - self.releases = releases - self.leadingView = EmptyView() - self.trailingView = trailingView() - } -} +// MARK: Safe Area Insets -public extension RecapScreen where TrailingView == EmptyView { - init(releases: [Release], @ViewBuilder leadingView: () -> LeadingView) { - self.releases = releases - self.leadingView = leadingView() - self.trailingView = EmptyView() +private extension View { + var hasSafeAreaForBottomPadding: Bool { +#if os(macOS) + return false +#else + if UIDevice.current.userInterfaceIdiom == .pad { + // On iPad, we don't display fullscreen so the home bar isn't relevant. + return false + } else { + return (UIApplication.shared.windows.first?.safeAreaInsets.bottom ?? 0.0) > 0.0 + } +#endif } -} -public extension RecapScreen where LeadingView == EmptyView, TrailingView == EmptyView { - init(releases: [Release]) { - self.releases = releases - self.leadingView = EmptyView() - self.trailingView = EmptyView() + func withBottomPaddingIfNoSafeArea() -> some View { + guard !hasSafeAreaForBottomPadding else { return self } + return self.padding(.bottom, 24.0) } }