Merge pull request #71 from omnivore-app/feature/iphone-nav-bar

iPhone NavBar Visibility
This commit is contained in:
Satindar Dhillon
2022-02-17 20:27:36 -08:00
committed by GitHub
5 changed files with 189 additions and 14 deletions

View File

@ -10,6 +10,7 @@ import WebKit
let rawAuthCookie: String?
let openLinkAction: (URL) -> Void
let webViewActionHandler: (WKScriptMessage) -> Void
let navBarVisibilityRatioUpdater: (Double) -> Void
@Binding var annotation: String
@Binding var annotationSaveTransactionID: UUID?
@Binding var sendIncreaseFontSignal: Bool
@ -28,11 +29,12 @@ import WebKit
let webView = WebView(frame: CGRect.zero)
let contentController = WKUserContentController()
webView.scrollView.isScrollEnabled = true
webView.scrollView.contentInset.top = LinkItemDetailView.navBarHeight
webView.navigationDelegate = context.coordinator
webView.isOpaque = false
webView.backgroundColor = UIColor.clear
webView.configuration.userContentController = contentController
webView.scrollView.delegate = context.coordinator
for action in WebViewAction.allCases {
webView.configuration.userContentController.add(context.coordinator, name: action.rawValue)
@ -53,6 +55,7 @@ import WebKit
context.coordinator.linkHandler = openLinkAction
context.coordinator.webViewActionHandler = webViewActionHandler
context.coordinator.updateNavBarVisibilityRatio = navBarVisibilityRatioUpdater
return webView
}

View File

@ -1,17 +1,28 @@
// import Models
import SwiftUI
// import Utils
import WebKit
final class WebAppViewCoordinator: NSObject {
let navBarHeight = LinkItemDetailView.navBarHeight
var webViewActionHandler: (WKScriptMessage) -> Void = { _ in }
var linkHandler: (URL) -> Void = { _ in }
var needsReload = true
var lastSavedAnnotationID: UUID?
var updateNavBarVisibilityRatio: (Double) -> Void = { _ in }
private var yOffsetAtStartOfDrag: Double?
private var lastYOffset: Double = 0
private var hasDragged = false
private var isNavBarHidden = false
override init() {
super.init()
}
var navBarVisibilityRatio: Double = 1.0 {
didSet {
isNavBarHidden = navBarVisibilityRatio == 0
updateNavBarVisibilityRatio(navBarVisibilityRatio)
}
}
}
extension WebAppViewCoordinator: WKScriptMessageHandler {
@ -34,6 +45,60 @@ extension WebAppViewCoordinator: WKNavigationDelegate {
}
}
extension WebAppViewCoordinator: UIScrollViewDelegate {
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
hasDragged = true
yOffsetAtStartOfDrag = scrollView.contentOffset.y + scrollView.contentInset.top
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard hasDragged else { return }
let yOffset = scrollView.contentOffset.y
if yOffset == 0 {
scrollView.contentInset.top = navBarHeight
navBarVisibilityRatio = 1
return
}
if yOffset < 0 {
navBarVisibilityRatio = 1
scrollView.contentInset.top = navBarHeight
return
}
if yOffset < navBarHeight {
let isScrollingUp = yOffsetAtStartOfDrag ?? 0 > yOffset
navBarVisibilityRatio = isScrollingUp || yOffset < 0 ? 1 : min(1, 1 - (yOffset / navBarHeight))
scrollView.contentInset.top = navBarVisibilityRatio * navBarHeight
return
}
guard let yOffsetAtStartOfDrag = yOffsetAtStartOfDrag else { return }
if yOffset > yOffsetAtStartOfDrag, !isNavBarHidden {
let translation = yOffset - yOffsetAtStartOfDrag
let ratio = translation < navBarHeight ? 1 - (translation / navBarHeight) : 0
navBarVisibilityRatio = min(ratio, 1)
scrollView.contentInset.top = navBarVisibilityRatio * navBarHeight
}
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if decelerate, scrollView.contentOffset.y + scrollView.contentInset.top < (yOffsetAtStartOfDrag ?? 0) {
scrollView.contentInset.top = navBarHeight
navBarVisibilityRatio = 1
}
}
func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool {
scrollView.contentInset.top = navBarHeight
navBarVisibilityRatio = 1
return false
}
}
struct WebViewConfig {
let url: URL
let themeId: String

View File

@ -35,9 +35,11 @@ public struct WebAppWrapperView: View {
@State private var annotation = String()
@State var annotationSaveTransactionID: UUID?
@State var safariWebLink: SafariWebLink?
let navBarVisibilityRatioUpdater: (Double) -> Void
public init(viewModel: WebAppWrapperViewModel) {
public init(viewModel: WebAppWrapperViewModel, navBarVisibilityRatioUpdater: ((Double) -> Void)? = nil) {
self.viewModel = viewModel
self.navBarVisibilityRatioUpdater = navBarVisibilityRatioUpdater ?? { _ in }
}
public var body: some View {
@ -53,6 +55,7 @@ public struct WebAppWrapperView: View {
#endif
},
webViewActionHandler: webViewActionHandler,
navBarVisibilityRatioUpdater: navBarVisibilityRatioUpdater,
annotation: $annotation,
annotationSaveTransactionID: $annotationSaveTransactionID,
sendIncreaseFontSignal: $viewModel.sendIncreaseFontSignal,

View File

@ -23,6 +23,7 @@ public struct FontSizeAdjustmentPopoverView: View {
Image(systemName: "minus")
#if os(iOS)
.foregroundColor(.appGraySolid)
.padding()
#endif
}
)
@ -37,6 +38,7 @@ public struct FontSizeAdjustmentPopoverView: View {
Image(systemName: "plus")
#if os(iOS)
.foregroundColor(.appGraySolid)
.padding()
#endif
}
)

View File

@ -25,8 +25,12 @@ public final class LinkItemDetailViewModel: ObservableObject {
}
public struct LinkItemDetailView: View {
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
static let navBarHeight = 50.0
@ObservedObject private var viewModel: LinkItemDetailViewModel
@State private var showFontSizePopover = false
@State private var navBarVisibilityRatio = 1.0
public init(viewModel: LinkItemDetailViewModel) {
self.viewModel = viewModel
@ -50,13 +54,105 @@ public struct LinkItemDetailView: View {
)
}
var fontAdjustmentPopoverView: some View {
FontSizeAdjustmentPopoverView(
increaseFontAction: { viewModel.webAppWrapperViewModel?.sendIncreaseFontSignal = true },
decreaseFontAction: { viewModel.webAppWrapperViewModel?.sendDecreaseFontSignal = true }
)
}
public var body: some View {
innerBody
#if os(iOS)
.navigationBarTitleDisplayMode(.inline)
if UIDevice.isIPhone, !viewModel.item.isPDF {
compactInnerBody
} else {
innerBody
}
#else
innerBody
#endif
}
var navBar: some View {
HStack(alignment: .center) {
Button(
action: { self.presentationMode.wrappedValue.dismiss() },
label: {
Image(systemName: "chevron.backward")
.font(.appTitleTwo)
.foregroundColor(.appGrayTextContrast)
.padding(.horizontal)
}
)
.scaleEffect(navBarVisibilityRatio)
Spacer()
Button(
action: { showFontSizePopover.toggle() },
label: {
Image(systemName: "textformat.size")
.font(.appTitleTwo)
}
)
.padding(.horizontal)
.scaleEffect(navBarVisibilityRatio)
}
.frame(height: LinkItemDetailView.navBarHeight * navBarVisibilityRatio)
.opacity(navBarVisibilityRatio)
.background(Color.systemBackground)
}
@ViewBuilder private var compactInnerBody: some View {
if let webAppWrapperViewModel = viewModel.webAppWrapperViewModel {
ZStack {
WebAppWrapperView(
viewModel: webAppWrapperViewModel,
navBarVisibilityRatioUpdater: {
if $0 < 1 {
showFontSizePopover = false
}
navBarVisibilityRatio = $0
}
)
if showFontSizePopover {
VStack {
Color.clear
.contentShape(Rectangle())
.frame(height: LinkItemDetailView.navBarHeight)
HStack {
Spacer()
fontAdjustmentPopoverView
.background(Color.appButtonBackground)
.cornerRadius(8)
.padding(.trailing, 5)
}
Spacer()
}
.background(
Color.clear
.contentShape(Rectangle())
.onTapGesture {
showFontSizePopover = false
}
)
}
VStack(spacing: 0) {
navBar
Spacer()
}
}
.navigationBarHidden(true)
} else {
VStack(spacing: 0) {
navBar
Spacer()
}
.onAppear {
viewModel.performActionSubject.send(.load)
}
.navigationBarHidden(true)
}
}
@ViewBuilder private var innerBody: some View {
if let pdfURL = viewModel.item.pdfURL {
#if os(iOS)
@ -76,17 +172,11 @@ public struct LinkItemDetailView: View {
)
#if os(iOS)
.fittedPopover(isPresented: $showFontSizePopover) {
FontSizeAdjustmentPopoverView(
increaseFontAction: { viewModel.webAppWrapperViewModel?.sendIncreaseFontSignal = true },
decreaseFontAction: { viewModel.webAppWrapperViewModel?.sendDecreaseFontSignal = true }
)
fontAdjustmentPopoverView
}
#else
.popover(isPresented: $showFontSizePopover) {
FontSizeAdjustmentPopoverView(
increaseFontAction: { viewModel.webAppWrapperViewModel?.sendIncreaseFontSignal = true },
decreaseFontAction: { viewModel.webAppWrapperViewModel?.sendDecreaseFontSignal = true }
)
fontAdjustmentPopoverView
}
#endif
}
@ -103,3 +193,15 @@ public struct LinkItemDetailView: View {
}
}
}
// Enable swipe to go back behavior if nav bar is hidden
extension UINavigationController: UIGestureRecognizerDelegate {
override open func viewDidLoad() {
super.viewDidLoad()
interactivePopGestureRecognizer?.delegate = self
}
public func gestureRecognizerShouldBegin(_: UIGestureRecognizer) -> Bool {
viewControllers.count > 1
}
}