diff --git a/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReader.swift b/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReader.swift index 78a8f3dce..0e5a7551c 100644 --- a/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReader.swift +++ b/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReader.swift @@ -16,6 +16,7 @@ struct WebReader: PlatformViewRepresentable { @Binding var showNavBarActionID: UUID? @Binding var shareActionID: UUID? @Binding var annotation: String + @Binding var showBottomBar: Bool func makeCoordinator() -> WebReaderCoordinator { WebReaderCoordinator() @@ -70,6 +71,10 @@ struct WebReader: PlatformViewRepresentable { context.coordinator.linkHandler = openLinkAction context.coordinator.webViewActionHandler = webViewActionHandler context.coordinator.updateNavBarVisibilityRatio = navBarVisibilityRatioUpdater + context.coordinator.updateShowBottomBar = { newValue in + self.showBottomBar = newValue + } + context.coordinator.articleContentID = articleContent.id loadContent(webView: webView) diff --git a/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContainer.swift b/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContainer.swift index 31e410553..a81f5de1f 100644 --- a/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContainer.swift +++ b/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContainer.swift @@ -24,6 +24,8 @@ struct WebReaderContainerView: View { @State var showNavBarActionID: UUID? @State var shareActionID: UUID? @State var annotation = String() + @State var showBottomBar = false + @State private var bottomBarOpacity = 0.0 @EnvironmentObject var dataService: DataService @EnvironmentObject var audioController: AudioController @@ -119,6 +121,38 @@ struct WebReaderContainerView: View { } #endif + var bottomButtons: some View { + HStack(alignment: .center) { + Button(action: archive, label: { + Image(systemName: item.isArchived ? "tray.and.arrow.down" : "archivebox") + }).frame(width: 48, height: 48) + .padding(.leading, 8) + Divider().opacity(0.8) + + Button(action: delete, label: { + Image(systemName: "trash") + }).frame(width: 48, height: 48) + Divider().opacity(0.8) + + Button(action: editLabels, label: { + Image(systemName: "tag") + }).frame(width: 48, height: 48) + Divider().opacity(0.8) + + Button(action: share, label: { + Image(systemName: "square.and.arrow.up") + }).frame(width: 48, height: 48) + + // TODO: We don't have a single note function yet +// Divider() +// +// Button(action: addNote, label: { +// Image(systemName: "note") +// }).frame(width: 48, height: 48) + .padding(.trailing, 8) + }.foregroundColor(.appGrayTextContrast) + } + var navBar: some View { HStack(alignment: .center) { #if os(iOS) @@ -159,16 +193,12 @@ struct WebReaderContainerView: View { label: { Label("Edit Title/Description", systemImage: "textbox") } ) Button( - action: { showLabelsModal = true }, + action: editLabels, label: { Label("Edit Labels", systemImage: "tag") } ) Button( action: { - dataService.archiveLink(objectID: item.objectID, archived: !item.isArchived) - #if os(iOS) - presentationMode.wrappedValue.dismiss() - #endif - Snackbar.show(message: !item.isArchived ? "Link archived" : "Link moved to Inbox") + archive() }, label: { Label( @@ -184,11 +214,11 @@ struct WebReaderContainerView: View { label: { Label("Reset Read Location", systemImage: "arrow.counterclockwise.circle") } ) Button( - action: { shareActionID = UUID() }, + action: share, label: { Label("Share Original", systemImage: "square.and.arrow.up") } ) Button( - action: { showDeleteConfirmation = true }, + action: delete, label: { Label("Delete", systemImage: "trash") } ) } @@ -268,7 +298,8 @@ struct WebReaderContainerView: View { annotationSaveTransactionID: $annotationSaveTransactionID, showNavBarActionID: $showNavBarActionID, shareActionID: $shareActionID, - annotation: $annotation + annotation: $annotation, + showBottomBar: $showBottomBar ) .onTapGesture { withAnimation { @@ -319,6 +350,21 @@ struct WebReaderContainerView: View { VStack(spacing: 0) { navBar Spacer() + if showBottomBar { + bottomButtons + .frame(height: 48) + .background(Color.webControlButtonBackground) + .cornerRadius(6) + .padding(.bottom, 34) + .shadow(color: .gray.opacity(0.13), radius: 8, x: 0, y: 4) + .opacity(bottomBarOpacity) + .onAppear { + withAnimation(Animation.linear(duration: 0.25)) { self.bottomBarOpacity = 1 } + } + .onDisappear { + self.bottomBarOpacity = 0 + } + } } #endif } @@ -336,4 +382,26 @@ struct WebReaderContainerView: View { WebViewManager.shared().loadHTMLString("", baseURL: nil) } } + + func archive() { + dataService.archiveLink(objectID: item.objectID, archived: !item.isArchived) + #if os(iOS) + presentationMode.wrappedValue.dismiss() + #endif + Snackbar.show(message: !item.isArchived ? "Link archived" : "Link moved to Inbox") + } + + func share() { + shareActionID = UUID() + } + + func delete() { + showDeleteConfirmation = true + } + + func editLabels() { + showLabelsModal = true + } + + func scrollToTop() {} } diff --git a/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderCoordinator.swift b/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderCoordinator.swift index a08377a45..99e9952d3 100644 --- a/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderCoordinator.swift +++ b/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderCoordinator.swift @@ -19,6 +19,7 @@ final class WebReaderCoordinator: NSObject { var previousShowNavBarActionID: UUID? var previousShareActionID: UUID? var updateNavBarVisibilityRatio: (Double) -> Void = { _ in } + var updateShowBottomBar: (Bool) -> Void = { _ in } var articleContentID = UUID() private var yOffsetAtStartOfDrag: Double? private var lastYOffset: Double = 0 @@ -121,6 +122,12 @@ extension WebReaderCoordinator: WKNavigationDelegate { navBarVisibilityRatio = min(ratio, 1) scrollView.contentInset.top = navBarVisibilityRatio * readerViewNavBarHeight } + + if yOffset + scrollView.visibleSize.height > scrollView.contentSize.height - 140 { + updateShowBottomBar(true) + } else { + updateShowBottomBar(false) + } } func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { diff --git a/apple/OmnivoreKit/Sources/Views/Colors/Colors.swift b/apple/OmnivoreKit/Sources/Views/Colors/Colors.swift index 4f8c60afa..a7aaa4f53 100644 --- a/apple/OmnivoreKit/Sources/Views/Colors/Colors.swift +++ b/apple/OmnivoreKit/Sources/Views/Colors/Colors.swift @@ -19,6 +19,7 @@ public extension Color { static var appTextDefault: Color { Color("_utilityTextDefault", bundle: .module) } static var appPrimaryBackground: Color { Color("_appPrimaryBackground", bundle: .module) } static var checkmarkBlue: Color { Color("_checkmarkBlue", bundle: .module) } + static var webControlButtonBackground: Color { Color("_webControlButtonBackground", bundle: .module) } // Apple system UIColor equivalents #if os(iOS) diff --git a/apple/OmnivoreKit/Sources/Views/Colors/Colors.xcassets/_webControlButtonBackground.colorset/Contents.json b/apple/OmnivoreKit/Sources/Views/Colors/Colors.xcassets/_webControlButtonBackground.colorset/Contents.json new file mode 100644 index 000000000..075a6992e --- /dev/null +++ b/apple/OmnivoreKit/Sources/Views/Colors/Colors.xcassets/_webControlButtonBackground.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "46", + "green" : "44", + "red" : "44" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +}