Merge pull request #732 from omnivore-app/feature/ios-web-prefs

iOS web prefs
This commit is contained in:
Satindar Dhillon
2022-06-02 14:29:23 -07:00
committed by GitHub
10 changed files with 294 additions and 55 deletions

View File

@ -15,6 +15,10 @@ import WebKit
@Binding var increaseFontActionID: UUID?
@Binding var decreaseFontActionID: UUID?
@Binding var increaseMarginActionID: UUID?
@Binding var decreaseMarginActionID: UUID?
@Binding var increaseLineHeightActionID: UUID?
@Binding var decreaseLineHeightActionID: UUID?
@Binding var annotationSaveTransactionID: UUID?
@Binding var showNavBarActionID: UUID?
@Binding var shareActionID: UUID?
@ -29,6 +33,16 @@ import WebKit
return storedSize <= 1 ? UITraitCollection.current.preferredWebFontSize : storedSize
}
func lineHeight() -> Int {
let storedSize = UserDefaults.standard.integer(forKey: UserDefaultKey.preferredWebLineSpacing.rawValue)
return storedSize <= 1 ? 150 : storedSize
}
func margin() -> Int {
let storedSize = UserDefaults.standard.integer(forKey: UserDefaultKey.preferredWebMargin.rawValue)
return storedSize <= 1 ? 360 : storedSize
}
func makeUIView(context: Context) -> WKWebView {
let webView = WebViewManager.shared()
let contentController = WKUserContentController()
@ -77,6 +91,26 @@ import WebKit
(webView as? WebView)?.decreaseFontSize()
}
if increaseMarginActionID != context.coordinator.previousIncreaseMarginActionID {
context.coordinator.previousIncreaseMarginActionID = increaseMarginActionID
(webView as? WebView)?.increaseMargin()
}
if decreaseMarginActionID != context.coordinator.previousDecreaseMarginActionID {
context.coordinator.previousDecreaseMarginActionID = decreaseMarginActionID
(webView as? WebView)?.decreaseMargin()
}
if increaseLineHeightActionID != context.coordinator.previousIncreaseLineHeightActionID {
context.coordinator.previousIncreaseLineHeightActionID = increaseLineHeightActionID
(webView as? WebView)?.increaseLineHeight()
}
if decreaseLineHeightActionID != context.coordinator.previousDecreaseLineHeightActionID {
context.coordinator.previousDecreaseLineHeightActionID = decreaseLineHeightActionID
(webView as? WebView)?.decreaseLineHeight()
}
if showNavBarActionID != context.coordinator.previousShowNavBarActionID {
context.coordinator.previousShowNavBarActionID = showNavBarActionID
context.coordinator.showNavBar()
@ -116,7 +150,9 @@ import WebKit
highlightsJSONString: highlightsJSONString,
item: item,
isDark: UITraitCollection.current.userInterfaceStyle == .dark,
fontSize: fontSize()
fontSize: fontSize(),
lineHeight: lineHeight(),
margin: margin()
)
.styledContent,
baseURL: ViewsPackage.bundleURL

View File

@ -8,7 +8,7 @@ import WebKit
struct WebReaderContainerView: View {
let item: LinkedItem
@State private var showFontSizePopover = false
@State private var showPreferencesPopover = false
@State private var showLabelsModal = false
@State var showHighlightAnnotationModal = false
@State var safariWebLink: SafariWebLink?
@ -17,6 +17,10 @@ import WebKit
@State private var progressViewOpacity = 0.0
@State var increaseFontActionID: UUID?
@State var decreaseFontActionID: UUID?
@State var increaseMarginActionID: UUID?
@State var decreaseMarginActionID: UUID?
@State var increaseLineHeightActionID: UUID?
@State var decreaseLineHeightActionID: UUID?
@State var annotationSaveTransactionID: UUID?
@State var showNavBarActionID: UUID?
@State var shareActionID: UUID?
@ -26,13 +30,6 @@ import WebKit
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
@StateObject var viewModel = WebReaderViewModel()
var fontAdjustmentPopoverView: some View {
FontSizeAdjustmentPopoverView(
increaseFontAction: { increaseFontActionID = UUID() },
decreaseFontAction: { decreaseFontActionID = UUID() }
)
}
func webViewActionHandler(message: WKScriptMessage, replyHandler: WKScriptMessageReplyHandler?) {
if let replyHandler = replyHandler {
viewModel.webViewActionWithReplyHandler(
@ -75,7 +72,7 @@ import WebKit
.scaleEffect(navBarVisibilityRatio)
Spacer()
Button(
action: { showFontSizePopover.toggle() },
action: { showPreferencesPopover.toggle() },
label: {
Image(systemName: "textformat.size")
.font(.appTitleTwo)
@ -122,9 +119,6 @@ import WebKit
.frame(height: readerViewNavBarHeight * navBarVisibilityRatio)
.opacity(navBarVisibilityRatio)
.background(Color.systemBackground)
.onTapGesture {
showFontSizePopover = false
}
.alert("Are you sure?", isPresented: $showDeleteConfirmation) {
Button("Remove Link", role: .destructive) {
Snackbar.show(message: "Link removed")
@ -153,13 +147,14 @@ import WebKit
},
webViewActionHandler: webViewActionHandler,
navBarVisibilityRatioUpdater: {
if $0 < 1 {
showFontSizePopover = false
}
navBarVisibilityRatio = $0
},
increaseFontActionID: $increaseFontActionID,
decreaseFontActionID: $decreaseFontActionID,
increaseMarginActionID: $increaseMarginActionID,
decreaseMarginActionID: $decreaseMarginActionID,
increaseLineHeightActionID: $increaseLineHeightActionID,
decreaseLineHeightActionID: $decreaseLineHeightActionID,
annotationSaveTransactionID: $annotationSaveTransactionID,
showNavBarActionID: $showNavBarActionID,
shareActionID: $shareActionID,
@ -200,33 +195,23 @@ import WebKit
await viewModel.loadContent(dataService: dataService, itemID: item.unwrappedID)
}
}
if showFontSizePopover {
VStack {
Color.clear
.contentShape(Rectangle())
.frame(height: LinkItemDetailView.navBarHeight)
HStack {
Spacer()
fontAdjustmentPopoverView
.background(Color.appButtonBackground)
.cornerRadius(8)
.padding(.trailing, 44)
}
Spacer()
}
.background(
Color.clear
.contentShape(Rectangle())
.onTapGesture {
showFontSizePopover = false
}
)
}
VStack(spacing: 0) {
navBar
Spacer()
}
}.onDisappear {
}
.formSheet(isPresented: $showPreferencesPopover) {
WebPreferencesPopoverView(
increaseFontAction: { increaseFontActionID = UUID() },
decreaseFontAction: { decreaseFontActionID = UUID() },
increaseMarginAction: { increaseMarginActionID = UUID() },
decreaseMarginAction: { decreaseMarginActionID = UUID() },
increaseLineHeightAction: { increaseLineHeightActionID = UUID() },
decreaseLineHeightAction: { decreaseLineHeightActionID = UUID() },
dismissAction: { showPreferencesPopover = false }
)
}
.onDisappear {
// Clear the shared webview content when exiting
WebViewManager.shared().loadHTMLString("<html></html>", baseURL: nil)
}

View File

@ -4,6 +4,8 @@ import Utils
struct WebReaderContent {
let textFontSize: Int
let lineHeight: Int
let margin: Int
let htmlContent: String
let highlightsJSONString: String
let item: LinkedItem
@ -14,9 +16,13 @@ struct WebReaderContent {
highlightsJSONString: String,
item: LinkedItem,
isDark: Bool,
fontSize: Int
fontSize: Int,
lineHeight: Int,
margin: Int
) {
self.textFontSize = fontSize
self.lineHeight = lineHeight
self.margin = margin
self.htmlContent = htmlContent
self.highlightsJSONString = highlightsJSONString
self.item = item
@ -71,6 +77,8 @@ struct WebReaderContent {
}
window.fontSize = \(textFontSize)
window.margin = \(margin)
window.lineHeight = \(lineHeight)
window.localStorage.setItem("theme", "\(themeKey)")
</script>
<script src="bundle.js"></script>

View File

@ -17,6 +17,10 @@ final class WebReaderCoordinator: NSObject {
var lastSavedAnnotationID: UUID?
var previousIncreaseFontActionID: UUID?
var previousDecreaseFontActionID: UUID?
var previousIncreaseMarginActionID: UUID?
var previousDecreaseMarginActionID: UUID?
var previousIncreaseLineHeightActionID: UUID?
var previousDecreaseLineHeightActionID: UUID?
var previousShowNavBarActionID: UUID?
var previousShareActionID: UUID?
var updateNavBarVisibilityRatio: (Double) -> Void = { _ in }

View File

@ -2,6 +2,8 @@ import Foundation
public enum UserDefaultKey: String {
case preferredWebFontSize
case preferredWebLineSpacing
case preferredWebMargin
case userHasDeniedPushPrimer
case firebasePushToken
case homeFeedlayoutPreference

View File

@ -34,6 +34,26 @@ public final class WebView: WKWebView {
dispatchEvent("decreaseFontSize")
}
public func increaseMargin() {
print("increase margin")
dispatchEvent("increaseMargin")
}
public func decreaseMargin() {
print("decrease margin")
dispatchEvent("decreaseMargin")
}
public func increaseLineHeight() {
print("increase line height")
dispatchEvent("increaseLineHeight")
}
public func decreaseLineHeight() {
print("decrease line height")
dispatchEvent("decreaseLineHeight")
}
public func shareOriginalItem() {
dispatchEvent("share")
}

View File

@ -1,6 +1,143 @@
import SwiftUI
import Utils
public struct WebPreferencesPopoverView: View {
let increaseFontAction: () -> Void
let decreaseFontAction: () -> Void
let increaseMarginAction: () -> Void
let decreaseMarginAction: () -> Void
let increaseLineHeightAction: () -> Void
let decreaseLineHeightAction: () -> Void
let dismissAction: () -> Void
static let preferredWebFontSizeKey = UserDefaultKey.preferredWebFontSize.rawValue
#if os(macOS)
@AppStorage(preferredWebFontSizeKey) var storedFontSize = Int(NSFont.userFont(ofSize: 16)?.pointSize ?? 16)
#else
@AppStorage(preferredWebFontSizeKey) var storedFontSize: Int = UITraitCollection.current.preferredWebFontSize
#endif
@AppStorage(UserDefaultKey.preferredWebLineSpacing.rawValue) var storedLineSpacing = 150
@AppStorage(UserDefaultKey.preferredWebMargin.rawValue) var storedMargin = 360
public init(
increaseFontAction: @escaping () -> Void,
decreaseFontAction: @escaping () -> Void,
increaseMarginAction: @escaping () -> Void,
decreaseMarginAction: @escaping () -> Void,
increaseLineHeightAction: @escaping () -> Void,
decreaseLineHeightAction: @escaping () -> Void,
dismissAction: @escaping () -> Void
) {
self.increaseFontAction = increaseFontAction
self.decreaseFontAction = decreaseFontAction
self.increaseMarginAction = increaseMarginAction
self.decreaseMarginAction = decreaseMarginAction
self.increaseLineHeightAction = increaseLineHeightAction
self.decreaseLineHeightAction = decreaseLineHeightAction
self.dismissAction = dismissAction
}
public var body: some View {
VStack(alignment: .center) {
ZStack {
Text("Preferences").font(.appTitleTwo)
HStack {
Spacer()
Button(
action: dismissAction,
label: { Image(systemName: "xmark").foregroundColor(.appGrayTextContrast) }
)
}
}
.padding()
LabelledStepper(
labelText: "Font Size:",
onIncrement: {
storedFontSize = min(storedFontSize + 2, 28)
increaseFontAction()
},
onDecrement: {
storedFontSize = max(storedFontSize - 2, 10)
decreaseFontAction()
}
)
if UIDevice.isIPad {
LabelledStepper(
labelText: "Margin:",
onIncrement: {
storedMargin = min(storedMargin + 45, 560)
increaseMarginAction()
},
onDecrement: {
storedMargin = max(storedMargin - 45, 200)
decreaseMarginAction()
}
)
}
LabelledStepper(
labelText: "Line Spacing:",
onIncrement: {
storedLineSpacing = min(storedLineSpacing + 25, 300)
increaseLineHeightAction()
},
onDecrement: {
storedLineSpacing = max(storedLineSpacing - 25, 100)
decreaseLineHeightAction()
}
)
Spacer()
}
.padding()
}
}
struct LabelledStepper: View {
let labelText: String
let onIncrement: () -> Void
let onDecrement: () -> Void
var body: some View {
HStack(alignment: .center, spacing: 0) {
Text(labelText)
Spacer()
HStack(spacing: 0) {
Button(
action: onDecrement,
label: {
Image(systemName: "minus")
#if os(iOS)
.foregroundColor(.systemLabel)
.padding()
#endif
}
)
.frame(width: 55, height: 40, alignment: .center)
Divider()
.frame(height: 30)
.background(Color.systemLabel)
Button(
action: onIncrement,
label: {
Image(systemName: "plus")
#if os(iOS)
.foregroundColor(.systemLabel)
.padding()
#endif
}
)
.frame(width: 55, height: 40, alignment: .center)
}
.background(Color.appButtonBackground)
.cornerRadius(8)
}
}
}
public struct FontSizeAdjustmentPopoverView: View {
let increaseFontAction: () -> Void
let decreaseFontAction: () -> Void

File diff suppressed because one or more lines are too long

View File

@ -7,10 +7,11 @@ import '@omnivore/web/styles/globals.css'
import '@omnivore/web/styles/articleInnerStyling.css'
const mutation = async (name, input) => {
const result = await window?.webkit?.messageHandlers.articleAction?.postMessage({
actionID: name,
...input
})
const result =
await window?.webkit?.messageHandlers.articleAction?.postMessage({
actionID: name,
...input,
})
console.log('action result', result, result.result)
return result.result
}
@ -40,13 +41,19 @@ const App = () => {
highlightBarDisabled={true}
highlightsBaseURL="https://example.com"
fontSize={window.fontSize ?? 18}
margin={0}
margin={window.margin}
lineHeight={window.lineHeight}
articleMutations={{
createHighlightMutation: (input) => mutation('createHighlight', input),
deleteHighlightMutation: (highlightId) => mutation('deleteHighlight', { highlightId }),
mergeHighlightMutation: (input) => mutation('mergeHighlight', input),
updateHighlightMutation: (input) => mutation('updateHighlight', input),
articleReadingProgressMutation: (input) => mutation('articleReadingProgress', input),
createHighlightMutation: (input) =>
mutation('createHighlight', input),
deleteHighlightMutation: (highlightId) =>
mutation('deleteHighlight', { highlightId }),
mergeHighlightMutation: (input) =>
mutation('mergeHighlight', input),
updateHighlightMutation: (input) =>
mutation('updateHighlight', input),
articleReadingProgressMutation: (input) =>
mutation('articleReadingProgress', input),
}}
/>
</VStack>

View File

@ -40,6 +40,14 @@ export function ArticleContainer(props: ArticleContainerProps): JSX.Element {
const [showShareModal, setShowShareModal] = useState(false)
const [showReportIssuesModal, setShowReportIssuesModal] = useState(false)
const [fontSize, setFontSize] = useState(props.fontSize ?? 20)
// iOS app embed can overide the original margin and line height
const [marginOverride, setMarginOverride] = useState<number | null>(null)
const [lineHeightOverride, setLineHeightOverride] = useState<number | null>(
null
)
const [fontFamilyOverride, setFontFamilyOverride] = useState<string | null>(
null
)
const highlightHref = useRef(
window.location.hash ? window.location.hash.split('#')[1] : null
)
@ -74,8 +82,32 @@ export function ArticleContainer(props: ArticleContainerProps): JSX.Element {
setHighlightReady(true)
}, [props.article.highlights, setHighlightLocations])
// Listen for font size and color mode change events sent from host apps (ios, macos...)
// Listen for preference change events sent from host apps (ios, macos...)
useEffect(() => {
const increaseLineHeight = () => {
setLineHeightOverride(
Math.min((lineHeightOverride ?? props.lineHeight ?? 150) + 25, 300)
)
}
const decreaseLineHeight = () => {
setLineHeightOverride(
Math.max((lineHeightOverride ?? props.lineHeight ?? 150) - 25, 100)
)
}
const increaseMargin = () => {
setMarginOverride(
Math.min((marginOverride ?? props.margin ?? 360) + 45, 560)
)
}
const decreaseMargin = () => {
setMarginOverride(
Math.max((marginOverride ?? props.margin ?? 360) - 45, 200)
)
}
const increaseFontSize = async () => {
await updateFontSize(Math.min(fontSize + 2, 28))
}
@ -101,6 +133,10 @@ export function ArticleContainer(props: ArticleContainerProps): JSX.Element {
}
}
document.addEventListener('increaseLineHeight', increaseLineHeight)
document.addEventListener('decreaseLineHeight', decreaseLineHeight)
document.addEventListener('increaseMargin', increaseMargin)
document.addEventListener('decreaseMargin', decreaseMargin)
document.addEventListener('increaseFontSize', increaseFontSize)
document.addEventListener('decreaseFontSize', decreaseFontSize)
document.addEventListener('switchToDarkMode', switchToDarkMode)
@ -108,6 +144,10 @@ export function ArticleContainer(props: ArticleContainerProps): JSX.Element {
document.addEventListener('share', share)
return () => {
document.removeEventListener('increaseLineHeight', increaseLineHeight)
document.removeEventListener('decreaseLineHeight', decreaseLineHeight)
document.removeEventListener('increaseMargin', increaseMargin)
document.removeEventListener('decreaseMargin', decreaseMargin)
document.removeEventListener('increaseFontSize', increaseFontSize)
document.removeEventListener('decreaseFontSize', decreaseFontSize)
document.removeEventListener('switchToDarkMode', switchToDarkMode)
@ -118,9 +158,9 @@ export function ArticleContainer(props: ArticleContainerProps): JSX.Element {
const styles = {
fontSize,
margin: props.margin ?? 360,
lineHeight: props.lineHeight ?? 150,
fontFamily: props.fontFamily ?? 'inter',
margin: marginOverride ?? props.margin ?? 360,
lineHeight: lineHeightOverride ?? props.lineHeight ?? 150,
fontFamily: fontFamilyOverride ?? props.fontFamily ?? 'inter',
readerFontColor: theme.colors.readerFont.toString(),
readerFontColorTransparent: theme.colors.readerFontTransparent.toString(),
readerTableHeaderColor: theme.colors.readerTableHeader.toString(),