From f0ad1f0e7b9f7ad7222e623bfd798b36c43c9942 Mon Sep 17 00:00:00 2001 From: Alexander Harding <2166114+aeharding@users.noreply.github.com> Date: Mon, 19 Feb 2024 09:17:46 -0600 Subject: [PATCH] Add iOS native reader mode setting Resolves #701 --- android/capacitor.settings.gradle | 2 +- ios/App/Podfile | 2 +- ios/App/Podfile.lock | 6 +- package.json | 3 + patches/@capacitor__browser@5.2.0.patch | 61 +++++++++++++++++++ pnpm-lock.yaml | 58 ++++++++++-------- .../settings/general/GeneralSettings.tsx | 2 + .../general/safari/AlwaysUseReaderMode.tsx | 22 +++++++ .../settings/general/safari/Safari.tsx | 19 ++++++ src/features/settings/settingsSlice.tsx | 19 ++++++ src/features/shared/useNativeBrowser.ts | 6 +- src/services/db.ts | 1 + 12 files changed, 169 insertions(+), 32 deletions(-) create mode 100644 patches/@capacitor__browser@5.2.0.patch create mode 100644 src/features/settings/general/safari/AlwaysUseReaderMode.tsx create mode 100644 src/features/settings/general/safari/Safari.tsx diff --git a/android/capacitor.settings.gradle b/android/capacitor.settings.gradle index 9e356e611..895b09b48 100644 --- a/android/capacitor.settings.gradle +++ b/android/capacitor.settings.gradle @@ -9,7 +9,7 @@ include ':capacitor-app' project(':capacitor-app').projectDir = new File('../node_modules/.pnpm/@capacitor+app@5.0.7_@capacitor+core@5.7.0/node_modules/@capacitor/app/android') include ':capacitor-browser' -project(':capacitor-browser').projectDir = new File('../node_modules/.pnpm/@capacitor+browser@5.2.0_@capacitor+core@5.7.0/node_modules/@capacitor/browser/android') +project(':capacitor-browser').projectDir = new File('../node_modules/.pnpm/@capacitor+browser@5.2.0_patch_hash=bc25ohpkb4iimysp77pbkkz45i_@capacitor+core@5.7.0/node_modules/@capacitor/browser/android') include ':capacitor-filesystem' project(':capacitor-filesystem').projectDir = new File('../node_modules/.pnpm/@capacitor+filesystem@5.2.1_@capacitor+core@5.7.0/node_modules/@capacitor/filesystem/android') diff --git a/ios/App/Podfile b/ios/App/Podfile index aa0df61cc..dc40b15dd 100644 --- a/ios/App/Podfile +++ b/ios/App/Podfile @@ -13,7 +13,7 @@ def capacitor_pods pod 'CapacitorCordova', :path => '../../node_modules/.pnpm/@capacitor+ios@5.7.0_@capacitor+core@5.7.0/node_modules/@capacitor/ios' pod 'CapacitorCommunityAppIcon', :path => '../../node_modules/.pnpm/@capacitor-community+app-icon@4.1.1_@capacitor+core@5.7.0/node_modules/@capacitor-community/app-icon' pod 'CapacitorApp', :path => '../../node_modules/.pnpm/@capacitor+app@5.0.7_@capacitor+core@5.7.0/node_modules/@capacitor/app' - pod 'CapacitorBrowser', :path => '../../node_modules/.pnpm/@capacitor+browser@5.2.0_@capacitor+core@5.7.0/node_modules/@capacitor/browser' + pod 'CapacitorBrowser', :path => '../../node_modules/.pnpm/@capacitor+browser@5.2.0_patch_hash=bc25ohpkb4iimysp77pbkkz45i_@capacitor+core@5.7.0/node_modules/@capacitor/browser' pod 'CapacitorFilesystem', :path => '../../node_modules/.pnpm/@capacitor+filesystem@5.2.1_@capacitor+core@5.7.0/node_modules/@capacitor/filesystem' pod 'CapacitorHaptics', :path => '../../node_modules/.pnpm/voyager-capacitor-haptics@5.0.7_@capacitor+core@5.7.0/node_modules/voyager-capacitor-haptics' pod 'CapacitorKeyboard', :path => '../../node_modules/.pnpm/@capacitor+keyboard@5.0.8_@capacitor+core@5.7.0/node_modules/@capacitor/keyboard' diff --git a/ios/App/Podfile.lock b/ios/App/Podfile.lock index e305c516c..91d28f69c 100644 --- a/ios/App/Podfile.lock +++ b/ios/App/Podfile.lock @@ -43,7 +43,7 @@ DEPENDENCIES: - "CapacitorApp (from `../../node_modules/.pnpm/@capacitor+app@5.0.7_@capacitor+core@5.7.0/node_modules/@capacitor/app`)" - "CapacitorApplicationContext (from `../../node_modules/.pnpm/capacitor-application-context@0.0.1_@capacitor+core@5.7.0/node_modules/capacitor-application-context`)" - "CapacitorBiometricLock (from `../../node_modules/.pnpm/capacitor-biometric-lock@0.1.1_@capacitor+core@5.7.0/node_modules/capacitor-biometric-lock`)" - - "CapacitorBrowser (from `../../node_modules/.pnpm/@capacitor+browser@5.2.0_@capacitor+core@5.7.0/node_modules/@capacitor/browser`)" + - "CapacitorBrowser (from `../../node_modules/.pnpm/@capacitor+browser@5.2.0_patch_hash=bc25ohpkb4iimysp77pbkkz45i_@capacitor+core@5.7.0/node_modules/@capacitor/browser`)" - "CapacitorCommunityAppIcon (from `../../node_modules/.pnpm/@capacitor-community+app-icon@4.1.1_@capacitor+core@5.7.0/node_modules/@capacitor-community/app-icon`)" - "CapacitorCordova (from `../../node_modules/.pnpm/@capacitor+ios@5.7.0_@capacitor+core@5.7.0/node_modules/@capacitor/ios`)" - "CapacitorFilesystem (from `../../node_modules/.pnpm/@capacitor+filesystem@5.2.1_@capacitor+core@5.7.0/node_modules/@capacitor/filesystem`)" @@ -72,7 +72,7 @@ EXTERNAL SOURCES: CapacitorBiometricLock: :path: "../../node_modules/.pnpm/capacitor-biometric-lock@0.1.1_@capacitor+core@5.7.0/node_modules/capacitor-biometric-lock" CapacitorBrowser: - :path: "../../node_modules/.pnpm/@capacitor+browser@5.2.0_@capacitor+core@5.7.0/node_modules/@capacitor/browser" + :path: "../../node_modules/.pnpm/@capacitor+browser@5.2.0_patch_hash=bc25ohpkb4iimysp77pbkkz45i_@capacitor+core@5.7.0/node_modules/@capacitor/browser" CapacitorCommunityAppIcon: :path: "../../node_modules/.pnpm/@capacitor-community+app-icon@4.1.1_@capacitor+core@5.7.0/node_modules/@capacitor-community/app-icon" CapacitorCordova: @@ -116,6 +116,6 @@ SPEC CHECKSUMS: CapacitorTips: 045758a9354574aa4807265e1bccbca0919ad861 SDWebImage: 750adf017a315a280c60fde706ab1e552a3ae4e9 -PODFILE CHECKSUM: 60e067b3584bd11d5c774c089886aebd272632db +PODFILE CHECKSUM: 7bbc79e4b01b6183e68d41416625999cc78f4bc7 COCOAPODS: 1.12.1 diff --git a/package.json b/package.json index 164e11f58..4383eb342 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,9 @@ "pnpm": { "overrides": { "@ionic/core": "npm:voyager-ionic-core" + }, + "patchedDependencies": { + "@capacitor/browser@5.2.0": "patches/@capacitor__browser@5.2.0.patch" } }, "dependencies": { diff --git a/patches/@capacitor__browser@5.2.0.patch b/patches/@capacitor__browser@5.2.0.patch new file mode 100644 index 000000000..d24edab72 --- /dev/null +++ b/patches/@capacitor__browser@5.2.0.patch @@ -0,0 +1,61 @@ +diff --git a/dist/esm/definitions.d.ts b/dist/esm/definitions.d.ts +index 9cd84087179ce4fc2139e3d771506552b0d82254..1c158d3ec3cfcff6d7f3aec0e1a3b2b99160a53a 100644 +--- a/dist/esm/definitions.d.ts ++++ b/dist/esm/definitions.d.ts +@@ -88,6 +88,7 @@ export interface OpenOptions { + * @since 4.0.0 + */ + height?: number; ++ entersReaderIfAvailable?: boolean; + } + /** + * @deprecated Use `OpenOptions`. +diff --git a/ios/Plugin/Browser.swift b/ios/Plugin/Browser.swift +index 3f1d1ade3e05d142a2295b354228d0a21ba0a01f..225101acfe73c068705fb18074460d8bd3c815a8 100644 +--- a/ios/Plugin/Browser.swift ++++ b/ios/Plugin/Browser.swift +@@ -15,9 +15,12 @@ import SafariServices + return safariViewController + } + +- @objc public func prepare(for url: URL, withTint tint: UIColor? = nil, modalPresentation style: UIModalPresentationStyle = .fullScreen) -> Bool { ++ @objc public func prepare(for url: URL, withTint tint: UIColor? = nil, modalPresentation style: UIModalPresentationStyle = .fullScreen, entersReaderIfAvailable: Bool = false) -> Bool { + if safariViewController == nil, let scheme = url.scheme?.lowercased(), ["http", "https"].contains(scheme) { +- let safariVC = SFSafariViewController(url: url) ++ let config = SFSafariViewController.Configuration() ++ config.entersReaderIfAvailable = entersReaderIfAvailable ++ ++ let safariVC = SFSafariViewController(url: url, configuration: config) + safariVC.delegate = self + if let color = tint { + safariVC.preferredBarTintColor = color +diff --git a/ios/Plugin/BrowserPlugin.swift b/ios/Plugin/BrowserPlugin.swift +index f6be40dd72cdd1ced0fe43869d26d9188ca08ea8..ae31df607cc96589ed9de959d6d926174ed24a5d 100644 +--- a/ios/Plugin/BrowserPlugin.swift ++++ b/ios/Plugin/BrowserPlugin.swift +@@ -2,7 +2,13 @@ import Foundation + import Capacitor + + @objc(CAPBrowserPlugin) +-public class CAPBrowserPlugin: CAPPlugin { ++public class CAPBrowserPlugin: CAPPlugin, CAPBridgedPlugin { ++ public let identifier = "CAPBrowserPlugin" ++ public let jsName = "Browser" ++ public let pluginMethods: [CAPPluginMethod] = [ ++ CAPPluginMethod(name: "open", returnType: CAPPluginReturnPromise), ++ CAPPluginMethod(name: "close", returnType: CAPPluginReturnPromise), ++ ] + private let implementation = Browser() + + @objc func open(_ call: CAPPluginCall) { +@@ -17,8 +23,9 @@ public class CAPBrowserPlugin: CAPPlugin { + color = UIColor.capacitor.color(fromHex: toolbarColor) + } + let style = self.presentationStyle(for: call.getString("presentationStyle")) ++ let entersReaderIfAvailable = call.getBool("entersReaderIfAvailable") ?? false + // prepare for display +- guard implementation.prepare(for: url, withTint: color, modalPresentation: style), let viewController = implementation.viewController else { ++ guard implementation.prepare(for: url, withTint: color, modalPresentation: style, entersReaderIfAvailable: entersReaderIfAvailable), let viewController = implementation.viewController else { + call.reject("Unable to display URL") + return + } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ea9604a42..2793f7d70 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,6 +7,11 @@ settings: overrides: '@ionic/core': npm:voyager-ionic-core +patchedDependencies: + '@capacitor/browser@5.2.0': + hash: bc25ohpkb4iimysp77pbkkz45i + path: patches/@capacitor__browser@5.2.0.patch + dependencies: compression: specifier: ^1.7.4 @@ -42,7 +47,7 @@ devDependencies: version: 3.0.4(@types/node@20.11.17)(typescript@5.3.3) '@capacitor/browser': specifier: ^5.2.0 - version: 5.2.0(@capacitor/core@5.7.0) + version: 5.2.0(patch_hash=bc25ohpkb4iimysp77pbkkz45i)(@capacitor/core@5.7.0) '@capacitor/cli': specifier: 5.7.0 version: 5.7.0 @@ -2736,13 +2741,14 @@ packages: - typescript dev: true - /@capacitor/browser@5.2.0(@capacitor/core@5.7.0): + /@capacitor/browser@5.2.0(patch_hash=bc25ohpkb4iimysp77pbkkz45i)(@capacitor/core@5.7.0): resolution: {integrity: sha512-pWFrsNPOG6DlDWGl+bJqTWLvoJ2vvV27LKaSZ/A7S4td4bK3umwZmgGlp8ispjpYiurjliT25Ae8I+ywMV8X9w==} peerDependencies: '@capacitor/core': ^5.0.0 dependencies: '@capacitor/core': 5.7.0 dev: true + patched: true /@capacitor/cli@5.7.0: resolution: {integrity: sha512-md6217RXFQwSNo9vr1gDgBqR88MJaQVwu3C5W3bpWlmajhec6NUR7yT7QNcBWErhCIJfqOOqXu4ZSSShndF0ug==} @@ -5071,7 +5077,7 @@ packages: /array-buffer-byte-length@1.0.0: resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 is-array-buffer: 3.0.2 dev: true @@ -5153,7 +5159,7 @@ packages: engines: {node: '>= 0.4'} dependencies: array-buffer-byte-length: 1.0.0 - call-bind: 1.0.5 + call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.22.3 get-intrinsic: 1.2.2 @@ -6800,7 +6806,7 @@ packages: '@one-ini/wasm': 0.1.1 commander: 10.0.1 minimatch: 9.0.1 - semver: 7.5.4 + semver: 7.6.0 dev: true /ee-first@1.1.1: @@ -7745,7 +7751,7 @@ packages: resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.22.3 functions-have-names: 1.2.3 @@ -7834,7 +7840,7 @@ packages: resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 get-intrinsic: 1.2.2 dev: true @@ -8544,7 +8550,7 @@ packages: /is-array-buffer@3.0.2: resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 get-intrinsic: 1.2.2 is-typed-array: 1.1.12 dev: true @@ -8589,7 +8595,7 @@ packages: resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 has-tostringtag: 1.0.0 dev: true @@ -8657,7 +8663,7 @@ packages: /is-finalizationregistry@1.0.2: resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 dev: true /is-fullwidth-code-point@3.0.0: @@ -8793,7 +8799,7 @@ packages: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 has-tostringtag: 1.0.0 dev: true @@ -8814,7 +8820,7 @@ packages: /is-shared-array-buffer@1.0.2: resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 dev: true /is-ssh@1.4.0: @@ -8894,13 +8900,13 @@ packages: /is-weakref@1.0.2: resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 dev: true /is-weakset@2.0.2: resolution: {integrity: sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 get-intrinsic: 1.2.2 dev: true @@ -10450,7 +10456,7 @@ packages: dependencies: hosted-git-info: 4.1.0 is-core-module: 2.13.1 - semver: 7.5.4 + semver: 7.6.0 validate-npm-package-license: 3.0.4 dev: true @@ -11597,7 +11603,7 @@ packages: resolution: {integrity: sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.22.3 get-intrinsic: 1.2.2 @@ -11980,7 +11986,7 @@ packages: /safe-regex-test@1.0.0: resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 get-intrinsic: 1.2.2 is-regex: 1.1.4 dev: true @@ -12511,7 +12517,7 @@ packages: resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.22.3 dev: true @@ -12519,7 +12525,7 @@ packages: /string.prototype.trimend@1.0.7: resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.22.3 dev: true @@ -12527,7 +12533,7 @@ packages: /string.prototype.trimstart@1.0.7: resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.22.3 dev: true @@ -13020,7 +13026,7 @@ packages: resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 get-intrinsic: 1.2.2 is-typed-array: 1.1.12 dev: true @@ -13038,7 +13044,7 @@ packages: resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 for-each: 0.3.3 has-proto: 1.0.1 is-typed-array: 1.1.12 @@ -13049,7 +13055,7 @@ packages: engines: {node: '>= 0.4'} dependencies: available-typed-arrays: 1.0.5 - call-bind: 1.0.5 + call-bind: 1.0.7 for-each: 0.3.3 has-proto: 1.0.1 is-typed-array: 1.1.12 @@ -13058,7 +13064,7 @@ packages: /typed-array-length@1.0.4: resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 for-each: 0.3.3 is-typed-array: 1.1.12 dev: true @@ -13098,7 +13104,7 @@ packages: /unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 has-bigints: 1.0.2 has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 @@ -13747,7 +13753,7 @@ packages: engines: {node: '>= 0.4'} dependencies: available-typed-arrays: 1.0.5 - call-bind: 1.0.5 + call-bind: 1.0.7 for-each: 0.3.3 gopd: 1.0.1 has-tostringtag: 1.0.0 diff --git a/src/features/settings/general/GeneralSettings.tsx b/src/features/settings/general/GeneralSettings.tsx index 7499b48b2..a8303aa5d 100644 --- a/src/features/settings/general/GeneralSettings.tsx +++ b/src/features/settings/general/GeneralSettings.tsx @@ -1,12 +1,14 @@ import Comments from "./comments/Comments"; import Other from "./other/Other"; import Posts from "./posts/Posts"; +import Safari from "./safari/Safari"; export default function GeneralSettings() { return ( <> + ); diff --git a/src/features/settings/general/safari/AlwaysUseReaderMode.tsx b/src/features/settings/general/safari/AlwaysUseReaderMode.tsx new file mode 100644 index 000000000..f97ef56a0 --- /dev/null +++ b/src/features/settings/general/safari/AlwaysUseReaderMode.tsx @@ -0,0 +1,22 @@ +import { IonToggle } from "@ionic/react"; +import { InsetIonItem } from "../../../../routes/pages/profile/ProfileFeedItemsPage"; +import { useAppDispatch, useAppSelector } from "../../../../store"; +import { setAlwaysUseReaderMode } from "../../settingsSlice"; + +export default function AlwaysUseReaderMode() { + const dispatch = useAppDispatch(); + const alwaysUseReaderMode = useAppSelector( + (state) => state.settings.general.safari.alwaysUseReaderMode, + ); + + return ( + + dispatch(setAlwaysUseReaderMode(e.detail.checked))} + > + Always Use Reader Mode + + + ); +} diff --git a/src/features/settings/general/safari/Safari.tsx b/src/features/settings/general/safari/Safari.tsx new file mode 100644 index 000000000..3ee6cd3a6 --- /dev/null +++ b/src/features/settings/general/safari/Safari.tsx @@ -0,0 +1,19 @@ +import { isAppleDeviceInstallable, isNative } from "../../../../helpers/device"; +import { IonLabel, IonList } from "@ionic/react"; +import { ListHeader } from "../../shared/formatting"; +import AlwaysUseReaderMode from "./AlwaysUseReaderMode"; + +export default function Safari() { + if (!isNative() || !isAppleDeviceInstallable()) return; + + return ( + <> + + Safari + + + + + + ); +} diff --git a/src/features/settings/settingsSlice.tsx b/src/features/settings/settingsSlice.tsx index cdf5bce75..9fa8d86ff 100644 --- a/src/features/settings/settingsSlice.tsx +++ b/src/features/settings/settingsSlice.tsx @@ -116,6 +116,9 @@ interface SettingsState { rememberCommunitySort: boolean; autoplayMedia: AutoplayMediaType; }; + safari: { + alwaysUseReaderMode: boolean; + }; enableHapticFeedback: boolean; linkHandler: LinkHandlerType; defaultFeed: DefaultFeedType | undefined; @@ -202,6 +205,9 @@ export const initialState: SettingsState = { rememberCommunitySort: false, autoplayMedia: OAutoplayMediaType.Always, }, + safari: { + alwaysUseReaderMode: false, + }, enableHapticFeedback: true, linkHandler: OLinkHandlerType.InApp, defaultFeed: undefined, @@ -347,6 +353,10 @@ export const appearanceSlice = createSlice({ state.general.noSubscribedInFeed = action.payload; db.setSetting("no_subscribed_in_feed", action.payload); }, + setAlwaysUseReaderMode(state, action: PayloadAction) { + state.general.safari.alwaysUseReaderMode = action.payload; + db.setSetting("always_use_reader_mode", action.payload); + }, setLargeShowVotingButtons(state, action: PayloadAction) { state.appearance.large.showVotingButtons = action.payload; db.setSetting("large_show_voting_buttons", action.payload); @@ -630,6 +640,9 @@ export const fetchSettingsFromDatabase = createAsyncThunk( const no_subscribed_in_feed = await db.getSetting( "no_subscribed_in_feed", ); + const always_use_reader_mode = await db.getSetting( + "always_use_reader_mode", + ); const default_post_sort = await db.getSetting("default_post_sort"); return { @@ -731,6 +744,11 @@ export const fetchSettingsFromDatabase = createAsyncThunk( autoplayMedia: autoplay_media ?? initialState.general.posts.autoplayMedia, }, + safari: { + alwaysUseReaderMode: + always_use_reader_mode ?? + initialState.general.safari.alwaysUseReaderMode, + }, linkHandler: link_handler ?? initialState.general.linkHandler, enableHapticFeedback: enable_haptic_feedback ?? initialState.general.enableHapticFeedback, @@ -805,6 +823,7 @@ export const { setPureBlack, setDefaultFeed, setNoSubscribedInFeed, + setAlwaysUseReaderMode, } = appearanceSlice.actions; export default appearanceSlice.reducer; diff --git a/src/features/shared/useNativeBrowser.ts b/src/features/shared/useNativeBrowser.ts index f666d14e6..52e454530 100644 --- a/src/features/shared/useNativeBrowser.ts +++ b/src/features/shared/useNativeBrowser.ts @@ -10,6 +10,9 @@ export default function useNativeBrowser() { const { usingSystemDarkMode, pureBlack } = useAppSelector( (state) => state.settings.appearance.dark, ); + const alwaysUseReaderMode = useAppSelector( + (state) => state.settings.general.safari.alwaysUseReaderMode, + ); return useCallback( (href: string) => { @@ -35,9 +38,10 @@ export default function useNativeBrowser() { Browser.open({ url: href, toolbarColor, + entersReaderIfAvailable: alwaysUseReaderMode, }); notifyStatusTapThatBrowserWasOpened(); }, - [isDark, usingSystemDarkMode, pureBlack], + [isDark, usingSystemDarkMode, pureBlack, alwaysUseReaderMode], ); } diff --git a/src/services/db.ts b/src/services/db.ts index 10824f1cd..104a9ecee 100644 --- a/src/services/db.ts +++ b/src/services/db.ts @@ -296,6 +296,7 @@ export type SettingValueTypes = { long_swipe_trigger_point: LongSwipeTriggerPointType; has_presented_block_nsfw_tip: boolean; no_subscribed_in_feed: boolean; + always_use_reader_mode: boolean; infinite_scrolling: boolean; upvote_on_save: boolean; default_post_sort: SortType;