Merge pull request #757 from omnivore-app/feature/high-text-contrast-reader-text
This commit is contained in:
@ -15,6 +15,7 @@ import WebKit
|
||||
|
||||
@Binding var updateFontFamilyActionID: UUID?
|
||||
@Binding var updateFontActionID: UUID?
|
||||
@Binding var updateTextContrastActionID: UUID?
|
||||
@Binding var updateMarginActionID: UUID?
|
||||
@Binding var updateLineHeightActionID: UUID?
|
||||
@Binding var annotationSaveTransactionID: UUID?
|
||||
@ -89,6 +90,11 @@ import WebKit
|
||||
(webView as? WebView)?.updateFontSize()
|
||||
}
|
||||
|
||||
if updateTextContrastActionID != context.coordinator.previousUpdateTextContrastActionID {
|
||||
context.coordinator.previousUpdateTextContrastActionID = updateTextContrastActionID
|
||||
(webView as? WebView)?.updateTextContrast()
|
||||
}
|
||||
|
||||
if updateMarginActionID != context.coordinator.previousUpdateMarginActionID {
|
||||
context.coordinator.previousUpdateMarginActionID = updateMarginActionID
|
||||
(webView as? WebView)?.updateMargin()
|
||||
|
||||
@ -17,6 +17,7 @@ import WebKit
|
||||
@State private var progressViewOpacity = 0.0
|
||||
@State var updateFontFamilyActionID: UUID?
|
||||
@State var updateFontActionID: UUID?
|
||||
@State var updateTextContrastActionID: UUID?
|
||||
@State var updateMarginActionID: UUID?
|
||||
@State var updateLineHeightActionID: UUID?
|
||||
@State var annotationSaveTransactionID: UUID?
|
||||
@ -149,6 +150,7 @@ import WebKit
|
||||
},
|
||||
updateFontFamilyActionID: $updateFontFamilyActionID,
|
||||
updateFontActionID: $updateFontActionID,
|
||||
updateTextContrastActionID: $updateTextContrastActionID,
|
||||
updateMarginActionID: $updateMarginActionID,
|
||||
updateLineHeightActionID: $updateLineHeightActionID,
|
||||
annotationSaveTransactionID: $annotationSaveTransactionID,
|
||||
@ -200,6 +202,7 @@ import WebKit
|
||||
WebPreferencesPopoverView(
|
||||
updateFontFamilyAction: { updateFontFamilyActionID = UUID() },
|
||||
updateFontAction: { updateFontActionID = UUID() },
|
||||
updateTextContrastAction: { updateTextContrastActionID = UUID() },
|
||||
updateMarginAction: { updateMarginActionID = UUID() },
|
||||
updateLineHeightAction: { updateLineHeightActionID = UUID() },
|
||||
dismissAction: { showPreferencesPopover = false }
|
||||
|
||||
@ -17,6 +17,7 @@ final class WebReaderCoordinator: NSObject {
|
||||
var lastSavedAnnotationID: UUID?
|
||||
var previousUpdateFontFamilyActionID: UUID?
|
||||
var previousUpdateFontActionID: UUID?
|
||||
var previousUpdateTextContrastActionID: UUID?
|
||||
var previousUpdateMarginActionID: UUID?
|
||||
var previousUpdateLineHeightActionID: UUID?
|
||||
var previousShowNavBarActionID: UUID?
|
||||
|
||||
@ -5,6 +5,7 @@ public enum UserDefaultKey: String {
|
||||
case preferredWebFontSize
|
||||
case preferredWebLineSpacing
|
||||
case preferredWebMargin
|
||||
case prefersHighContrastWebFont
|
||||
case userHasDeniedPushPrimer
|
||||
case firebasePushToken
|
||||
case homeFeedlayoutPreference
|
||||
|
||||
@ -51,6 +51,16 @@ public final class WebView: WKWebView {
|
||||
}
|
||||
}
|
||||
|
||||
public func updateTextContrast() {
|
||||
let isHighContrast = UserDefaults.standard.value(
|
||||
forKey: UserDefaultKey.prefersHighContrastWebFont.rawValue
|
||||
) as? Bool
|
||||
|
||||
if let isHighContrast = isHighContrast {
|
||||
dispatchEvent(.handleFontContrastChange(isHighContrast: isHighContrast))
|
||||
}
|
||||
}
|
||||
|
||||
public func shareOriginalItem() {
|
||||
dispatchEvent(.share)
|
||||
}
|
||||
@ -228,6 +238,7 @@ public final class WebView: WKWebView {
|
||||
#endif
|
||||
|
||||
public enum WebViewDispatchEvent {
|
||||
case handleFontContrastChange(isHighContrast: Bool)
|
||||
case updateLineHeight(height: Int)
|
||||
case updateMargin(width: Int)
|
||||
case updateFontSize(size: Int)
|
||||
@ -247,6 +258,8 @@ public enum WebViewDispatchEvent {
|
||||
|
||||
private var eventName: String {
|
||||
switch self {
|
||||
case .handleFontContrastChange:
|
||||
return "handleFontContrastChange"
|
||||
case .updateLineHeight:
|
||||
return "updateLineHeight"
|
||||
case .updateMargin:
|
||||
@ -276,6 +289,8 @@ public enum WebViewDispatchEvent {
|
||||
|
||||
private var scriptPropertyLine: String {
|
||||
switch self {
|
||||
case let .handleFontContrastChange(isHighContrast: isHighContrast):
|
||||
return "event.fontContrast = '\(isHighContrast ? "high" : "normal")';"
|
||||
case let .updateLineHeight(height: height):
|
||||
return "event.lineHeight = '\(height)';"
|
||||
case let .updateMargin(width: width):
|
||||
|
||||
@ -12,6 +12,7 @@ public enum WebFont: String, CaseIterable {
|
||||
public struct WebPreferencesPopoverView: View {
|
||||
let updateFontFamilyAction: () -> Void
|
||||
let updateFontAction: () -> Void
|
||||
let updateTextContrastAction: () -> Void
|
||||
let updateMarginAction: () -> Void
|
||||
let updateLineHeightAction: () -> Void
|
||||
let dismissAction: () -> Void
|
||||
@ -26,16 +27,19 @@ public struct WebPreferencesPopoverView: View {
|
||||
@AppStorage(UserDefaultKey.preferredWebLineSpacing.rawValue) var storedLineSpacing = 150
|
||||
@AppStorage(UserDefaultKey.preferredWebMargin.rawValue) var storedMargin = 360
|
||||
@AppStorage(UserDefaultKey.preferredWebFont.rawValue) var preferredFont = WebFont.inter.rawValue
|
||||
@AppStorage(UserDefaultKey.prefersHighContrastWebFont.rawValue) var prefersHighContrastText = false
|
||||
|
||||
public init(
|
||||
updateFontFamilyAction: @escaping () -> Void,
|
||||
updateFontAction: @escaping () -> Void,
|
||||
updateTextContrastAction: @escaping () -> Void,
|
||||
updateMarginAction: @escaping () -> Void,
|
||||
updateLineHeightAction: @escaping () -> Void,
|
||||
dismissAction: @escaping () -> Void
|
||||
) {
|
||||
self.updateFontFamilyAction = updateFontFamilyAction
|
||||
self.updateFontAction = updateFontAction
|
||||
self.updateTextContrastAction = updateTextContrastAction
|
||||
self.updateMarginAction = updateMarginAction
|
||||
self.updateLineHeightAction = updateLineHeightAction
|
||||
self.dismissAction = dismissAction
|
||||
@ -60,69 +64,77 @@ public struct WebPreferencesPopoverView: View {
|
||||
}
|
||||
)
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.listStyle(.plain)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
}
|
||||
|
||||
public var body: some View {
|
||||
NavigationView {
|
||||
VStack(alignment: .center) {
|
||||
Text("Reader Preferences")
|
||||
.foregroundColor(.appGrayText)
|
||||
.font(Font.system(size: 17, weight: .semibold))
|
||||
ScrollView(showsIndicators: false) {
|
||||
VStack(alignment: .center) {
|
||||
VStack {
|
||||
LabelledStepper(
|
||||
labelText: "Font Size:",
|
||||
onIncrement: {
|
||||
storedFontSize = min(storedFontSize + 2, 28)
|
||||
updateFontAction()
|
||||
},
|
||||
onDecrement: {
|
||||
storedFontSize = max(storedFontSize - 2, 10)
|
||||
updateFontAction()
|
||||
}
|
||||
)
|
||||
|
||||
LabelledStepper(
|
||||
labelText: "Font Size:",
|
||||
onIncrement: {
|
||||
storedFontSize = min(storedFontSize + 2, 28)
|
||||
updateFontAction()
|
||||
},
|
||||
onDecrement: {
|
||||
storedFontSize = max(storedFontSize - 2, 10)
|
||||
updateFontAction()
|
||||
}
|
||||
)
|
||||
|
||||
if UIDevice.isIPad {
|
||||
LabelledStepper(
|
||||
labelText: "Margin:",
|
||||
onIncrement: {
|
||||
storedMargin = min(storedMargin + 45, 560)
|
||||
updateMarginAction()
|
||||
},
|
||||
onDecrement: {
|
||||
storedMargin = max(storedMargin - 45, 200)
|
||||
updateMarginAction()
|
||||
if UIDevice.isIPad {
|
||||
LabelledStepper(
|
||||
labelText: "Margin:",
|
||||
onIncrement: {
|
||||
storedMargin = min(storedMargin + 45, 560)
|
||||
updateMarginAction()
|
||||
},
|
||||
onDecrement: {
|
||||
storedMargin = max(storedMargin - 45, 200)
|
||||
updateMarginAction()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
LabelledStepper(
|
||||
labelText: "Line Spacing:",
|
||||
onIncrement: {
|
||||
storedLineSpacing = min(storedLineSpacing + 25, 300)
|
||||
updateLineHeightAction()
|
||||
},
|
||||
onDecrement: {
|
||||
storedLineSpacing = max(storedLineSpacing - 25, 100)
|
||||
updateLineHeightAction()
|
||||
LabelledStepper(
|
||||
labelText: "Line Spacing:",
|
||||
onIncrement: {
|
||||
storedLineSpacing = min(storedLineSpacing + 25, 300)
|
||||
updateLineHeightAction()
|
||||
},
|
||||
onDecrement: {
|
||||
storedLineSpacing = max(storedLineSpacing - 25, 100)
|
||||
updateLineHeightAction()
|
||||
}
|
||||
)
|
||||
|
||||
Toggle("High Contrast Text:", isOn: $prefersHighContrastText)
|
||||
.frame(height: 40)
|
||||
.padding(.trailing, 6)
|
||||
.onChange(of: prefersHighContrastText) { _ in
|
||||
updateTextContrastAction()
|
||||
}
|
||||
|
||||
HStack {
|
||||
NavigationLink(destination: fontList) {
|
||||
Text("Change Reader Font")
|
||||
}
|
||||
Image(systemName: "chevron.right")
|
||||
Spacer()
|
||||
}
|
||||
.frame(height: 40)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
)
|
||||
|
||||
HStack {
|
||||
NavigationLink(destination: fontList) {
|
||||
Text("Change Reader Font")
|
||||
}
|
||||
Image(systemName: "chevron.right")
|
||||
Spacer()
|
||||
}
|
||||
.frame(height: 40)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.padding()
|
||||
.navigationBarHidden(true)
|
||||
.navigationTitle("Reader Preferences")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
}
|
||||
.accentColor(.appGrayTextContrast)
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -32,6 +32,7 @@ type ArticleContainerProps = {
|
||||
fontSize?: number
|
||||
fontFamily?: string
|
||||
lineHeight?: number
|
||||
highContrastFont?: boolean
|
||||
showHighlightsModal: boolean
|
||||
setShowHighlightsModal: React.Dispatch<React.SetStateAction<boolean>>
|
||||
}
|
||||
@ -48,6 +49,7 @@ export function ArticleContainer(props: ArticleContainerProps): JSX.Element {
|
||||
const [fontFamilyOverride, setFontFamilyOverride] = useState<string | null>(
|
||||
null
|
||||
)
|
||||
const [highContrastFont, setHighContrastFont] = useState(props.highContrastFont ?? false)
|
||||
const highlightHref = useRef(
|
||||
window.location.hash ? window.location.hash.split('#')[1] : null
|
||||
)
|
||||
@ -117,6 +119,15 @@ export function ArticleContainer(props: ArticleContainerProps): JSX.Element {
|
||||
setFontFamilyOverride(newFontFamily)
|
||||
}
|
||||
|
||||
interface UpdateFontContrastEvent extends Event {
|
||||
fontContrast?: 'high' | 'normal'
|
||||
}
|
||||
|
||||
const handleFontContrastChange = async (event: UpdateFontContrastEvent) => {
|
||||
const highContrast = event.fontContrast == 'high'
|
||||
setHighContrastFont(highContrast)
|
||||
}
|
||||
|
||||
interface UpdateFontSizeEvent extends Event {
|
||||
fontSize?: number
|
||||
}
|
||||
@ -151,6 +162,7 @@ export function ArticleContainer(props: ArticleContainerProps): JSX.Element {
|
||||
document.addEventListener('updateMargin', updateMargin)
|
||||
document.addEventListener('updateFontSize', handleFontSizeChange)
|
||||
document.addEventListener('updateColorMode', updateColorMode)
|
||||
document.addEventListener('handleFontContrastChange', handleFontContrastChange)
|
||||
document.addEventListener('share', share)
|
||||
|
||||
return () => {
|
||||
@ -159,6 +171,7 @@ export function ArticleContainer(props: ArticleContainerProps): JSX.Element {
|
||||
document.removeEventListener('updateMargin', updateMargin)
|
||||
document.removeEventListener('updateFontSize', handleFontSizeChange)
|
||||
document.removeEventListener('updateColorMode', updateColorMode)
|
||||
document.removeEventListener('handleFontContrastChange', handleFontContrastChange)
|
||||
document.removeEventListener('share', share)
|
||||
}
|
||||
})
|
||||
@ -168,7 +181,7 @@ export function ArticleContainer(props: ArticleContainerProps): JSX.Element {
|
||||
margin: marginOverride ?? props.margin ?? 360,
|
||||
lineHeight: lineHeightOverride ?? props.lineHeight ?? 150,
|
||||
fontFamily: fontFamilyOverride ?? props.fontFamily ?? 'inter',
|
||||
readerFontColor: theme.colors.readerFont.toString(),
|
||||
readerFontColor: highContrastFont ? theme.colors.readerFontHighContrast.toString() : theme.colors.readerFont.toString(),
|
||||
readerFontColorTransparent: theme.colors.readerFontTransparent.toString(),
|
||||
readerTableHeaderColor: theme.colors.readerTableHeader.toString(),
|
||||
readerHeadersColor: theme.colors.readerHeader.toString(),
|
||||
|
||||
@ -139,6 +139,7 @@ export const { styled, css, theme, getCssText, globalCss, keyframes, config } =
|
||||
// Reader Colors
|
||||
readerBg: '#E5E5E5',
|
||||
readerFont: '#3D3D3D',
|
||||
readerFontHighContrast: 'black',
|
||||
readerFontTransparent: 'rgba(61,61,61,0.65)',
|
||||
readerHeader: '3D3D3D',
|
||||
readerTableHeader: '#FFFFFF',
|
||||
@ -194,6 +195,7 @@ const darkThemeSpec = {
|
||||
// Reader Colors
|
||||
readerBg: '#303030',
|
||||
readerFont: '#b9b9b9',
|
||||
readerFontHighContrast: 'black',
|
||||
readerFontTransparent: 'rgba(185,185,185,0.65)',
|
||||
readerHeader: '#b9b9b9',
|
||||
readerTableHeader: '#FFFFFF',
|
||||
|
||||
Reference in New Issue
Block a user