Reader Mode
This commit is contained in:
@@ -240,6 +240,23 @@ class BrowserViewController: UIViewController, WKNavigationDelegate, WKUIDelegat
|
|||||||
documentControls.navigationControlView.forwardButton.isEnabled = webView.canGoForward
|
documentControls.navigationControlView.forwardButton.isEnabled = webView.canGoForward
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
// Reader mode
|
||||||
|
documentControls.readabilityView.addAction(UIAction { [unowned self] _ in
|
||||||
|
tab.bridge.parseDocumentForReaderMode { string in
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
documentControls.dismiss(animated: true, completion: nil)
|
||||||
|
|
||||||
|
let readableViewController = ReaderViewController(readableHTMLString: string, baseURL: tab.bridge.webView.url)
|
||||||
|
readableViewController.title = tab.bridge.webView.title
|
||||||
|
readableViewController.darkModeEnabled = tab.bridge.darkModeEnabled
|
||||||
|
readableViewController.delegate = self
|
||||||
|
|
||||||
|
let navigationController = UINavigationController(rootViewController: readableViewController)
|
||||||
|
present(navigationController, animated: true, completion: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, for: .touchUpInside)
|
||||||
|
|
||||||
present(documentControls, animated: true, completion: nil)
|
present(documentControls, animated: true, completion: nil)
|
||||||
}), for: .touchUpInside)
|
}), for: .touchUpInside)
|
||||||
|
|
||||||
@@ -708,3 +725,10 @@ class BrowserViewController: UIViewController, WKNavigationDelegate, WKUIDelegat
|
|||||||
tab.webView._viewScale -= 0.10
|
tab.webView._viewScale -= 0.10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension BrowserViewController: ReaderViewControllerDelegate
|
||||||
|
{
|
||||||
|
func readerViewController(_ reader: ReaderViewController, didRequestNavigationToURL navigationURL: URL) {
|
||||||
|
tab.beginLoadingURL(navigationURL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ class DocumentControlViewController: UIViewController
|
|||||||
let findOnPageControlView = DocumentControlView()
|
let findOnPageControlView = DocumentControlView()
|
||||||
let navigationControlView = NavigationControlsView()
|
let navigationControlView = NavigationControlsView()
|
||||||
let settingsView = DocumentControlView()
|
let settingsView = DocumentControlView()
|
||||||
|
let readabilityView = DocumentControlView()
|
||||||
|
|
||||||
var observations: [NSKeyValueObservation] = []
|
var observations: [NSKeyValueObservation] = []
|
||||||
|
|
||||||
@@ -28,9 +29,13 @@ class DocumentControlViewController: UIViewController
|
|||||||
settingsView.label.text = "Settings"
|
settingsView.label.text = "Settings"
|
||||||
settingsView.imageView.image = UIImage(systemName: "gear")
|
settingsView.imageView.image = UIImage(systemName: "gear")
|
||||||
|
|
||||||
|
readabilityView.label.text = "Reader Mode"
|
||||||
|
readabilityView.imageView.image = UIImage(systemName: "doc.richtext")
|
||||||
|
|
||||||
documentControlView.addArrangedSubview(navigationControlView)
|
documentControlView.addArrangedSubview(navigationControlView)
|
||||||
documentControlView.addArrangedSubview(fontSizeAdjustView)
|
documentControlView.addArrangedSubview(fontSizeAdjustView)
|
||||||
documentControlView.addArrangedSubview(findOnPageControlView)
|
documentControlView.addArrangedSubview(findOnPageControlView)
|
||||||
|
documentControlView.addArrangedSubview(readabilityView)
|
||||||
documentControlView.addArrangedSubview(settingsView)
|
documentControlView.addArrangedSubview(settingsView)
|
||||||
|
|
||||||
for (i, view) in documentControlView.arrangedSubviews.enumerated() {
|
for (i, view) in documentControlView.arrangedSubviews.enumerated() {
|
||||||
|
|||||||
102
App/Reader View/ReaderViewController.swift
Normal file
102
App/Reader View/ReaderViewController.swift
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
//
|
||||||
|
// ReaderViewController.swift
|
||||||
|
// App
|
||||||
|
//
|
||||||
|
// Created by James Magahern on 2/15/21.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import WebKit
|
||||||
|
|
||||||
|
protocol ReaderViewControllerDelegate: AnyObject
|
||||||
|
{
|
||||||
|
func readerViewController(_ reader: ReaderViewController, didRequestNavigationToURL navigationURL: URL)
|
||||||
|
}
|
||||||
|
|
||||||
|
class ReaderViewController: UIViewController
|
||||||
|
{
|
||||||
|
public let baseURL: URL?
|
||||||
|
public let readableHTMLString: String
|
||||||
|
public var darkModeEnabled: Bool = false { didSet { bridge.darkModeEnabled = darkModeEnabled; updateDarkModeButton() } }
|
||||||
|
|
||||||
|
public weak var delegate: ReaderViewControllerDelegate?
|
||||||
|
|
||||||
|
private let bridge = ProcessBundleBridge(webViewConfiguration: nil)
|
||||||
|
|
||||||
|
private let darkModeDisabledImage = UIImage(systemName: "moon.circle")
|
||||||
|
private let darkModeEnabledImage = UIImage(systemName: "moon.circle.fill")
|
||||||
|
|
||||||
|
private lazy var darkModeButton: UIBarButtonItem = {
|
||||||
|
UIBarButtonItem(image: darkModeEnabledImage, style: .plain, target: self, action: #selector(self.didTapDarkModeButton))
|
||||||
|
}()
|
||||||
|
|
||||||
|
init(readableHTMLString: String, baseURL: URL?) {
|
||||||
|
self.readableHTMLString = readableHTMLString
|
||||||
|
self.baseURL = baseURL
|
||||||
|
super.init(nibName: nil, bundle: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override func loadView() {
|
||||||
|
self.view = bridge.webView
|
||||||
|
bridge.webView.navigationDelegate = self
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
navigationItem.leftBarButtonItem = darkModeButton
|
||||||
|
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(self.didTapDoneButton))
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateDarkModeButton() {
|
||||||
|
if darkModeEnabled {
|
||||||
|
darkModeButton.image = darkModeEnabledImage
|
||||||
|
} else {
|
||||||
|
darkModeButton.image = darkModeDisabledImage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc
|
||||||
|
private func didTapDoneButton(_ sender: Any?) {
|
||||||
|
dismiss(animated: true, completion: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc
|
||||||
|
private func didTapDarkModeButton(_ sender: Any?) {
|
||||||
|
darkModeEnabled = !darkModeEnabled
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewWillAppear(_ animated: Bool) {
|
||||||
|
let readerHTMLURL = Bundle.main.url(forResource: "reader", withExtension: "html")!
|
||||||
|
var readerHTML = try! String(contentsOf: readerHTMLURL)
|
||||||
|
|
||||||
|
let bodyRange = readerHTML.range(of: "{{ body }}")!
|
||||||
|
readerHTML.replaceSubrange(bodyRange, with: readableHTMLString)
|
||||||
|
|
||||||
|
bridge.webView.loadHTMLString(readerHTML, baseURL: baseURL)
|
||||||
|
|
||||||
|
updateDarkModeButton()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ReaderViewController: WKNavigationDelegate
|
||||||
|
{
|
||||||
|
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
|
||||||
|
guard let url = navigationAction.request.url else { return }
|
||||||
|
|
||||||
|
if url == baseURL {
|
||||||
|
decisionHandler(.allow)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
// Don't load links in here, dismiss the reader view and load them in the tab behind us.
|
||||||
|
delegate?.readerViewController(self, didRequestNavigationToURL: url)
|
||||||
|
|
||||||
|
dismiss(animated: true, completion: nil)
|
||||||
|
decisionHandler(.cancel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2260
App/Resources/Readability.js
Normal file
2260
App/Resources/Readability.js
Normal file
File diff suppressed because it is too large
Load Diff
27
App/Resources/reader.html
Normal file
27
App/Resources/reader.html
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 2em;
|
||||||
|
|
||||||
|
line-height: 1.8em;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
display: block;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
{{ body }}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -18,7 +18,7 @@ class Tab: NSObject, SBRProcessBundleBridgeDelegate
|
|||||||
public weak var delegate: TabDelegate?
|
public weak var delegate: TabDelegate?
|
||||||
|
|
||||||
public let homeURL: URL?
|
public let homeURL: URL?
|
||||||
public let bridge: SBRProcessBundleBridge
|
public let bridge: ProcessBundleBridge
|
||||||
public var webView: WKWebView {
|
public var webView: WKWebView {
|
||||||
if self.loadedWebView == nil {
|
if self.loadedWebView == nil {
|
||||||
self.loadedWebView = bridge.webView
|
self.loadedWebView = bridge.webView
|
||||||
@@ -83,7 +83,7 @@ class Tab: NSObject, SBRProcessBundleBridgeDelegate
|
|||||||
self.homeURL = url
|
self.homeURL = url
|
||||||
self.policyManager = policyManager
|
self.policyManager = policyManager
|
||||||
|
|
||||||
self.bridge = SBRProcessBundleBridge(webViewConfiguration: webViewConfiguration)
|
self.bridge = ProcessBundleBridge(webViewConfiguration: webViewConfiguration)
|
||||||
self.bridge.policyDataSource = policyManager
|
self.bridge.policyDataSource = policyManager
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
@@ -102,12 +102,12 @@ class Tab: NSObject, SBRProcessBundleBridgeDelegate
|
|||||||
|
|
||||||
// MARK: SBRProcessBundleBridgeDelegate
|
// MARK: SBRProcessBundleBridgeDelegate
|
||||||
|
|
||||||
func webProcess(_ bridge: SBRProcessBundleBridge, didAllowScriptResourceFromOrigin origin: String) {
|
func webProcess(_ bridge: ProcessBundleBridge, didAllowScriptResourceFromOrigin origin: String) {
|
||||||
print("Allowed script resource from origin: \(origin)")
|
print("Allowed script resource from origin: \(origin)")
|
||||||
allowedScriptOrigins.formUnion([ origin ])
|
allowedScriptOrigins.formUnion([ origin ])
|
||||||
}
|
}
|
||||||
|
|
||||||
func webProcess(_ bridge: SBRProcessBundleBridge, didBlockScriptResourceFromOrigin origin: String) {
|
func webProcess(_ bridge: ProcessBundleBridge, didBlockScriptResourceFromOrigin origin: String) {
|
||||||
print("Blocked script resource from origin: \(origin)")
|
print("Blocked script resource from origin: \(origin)")
|
||||||
blockedScriptOrigins.formUnion([ origin ])
|
blockedScriptOrigins.formUnion([ origin ])
|
||||||
delegate?.didBlockScriptOrigin(origin, forTab: self)
|
delegate?.didBlockScriptOrigin(origin, forTab: self)
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
- (void)webProcess:(SBRProcessBundleBridge *)bridge didBlockScriptResourceFromOrigin:(NSString *)origin;
|
- (void)webProcess:(SBRProcessBundleBridge *)bridge didBlockScriptResourceFromOrigin:(NSString *)origin;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
NS_SWIFT_NAME(ProcessBundleBridge)
|
||||||
@interface SBRProcessBundleBridge : NSObject
|
@interface SBRProcessBundleBridge : NSObject
|
||||||
|
|
||||||
@property (nonatomic, readonly) WKWebView *webView;
|
@property (nonatomic, readonly) WKWebView *webView;
|
||||||
@@ -39,6 +40,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
- (void)policyDataSourceDidChange;
|
- (void)policyDataSourceDidChange;
|
||||||
- (void)tearDown;
|
- (void)tearDown;
|
||||||
|
|
||||||
|
- (void)parseDocumentForReaderMode:(void(^)(NSString *))completionBlock NS_SWIFT_NAME(parseDocumentForReaderMode(completion:));
|
||||||
|
|
||||||
- (instancetype)init NS_UNAVAILABLE;
|
- (instancetype)init NS_UNAVAILABLE;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
id<SBRWebProcessProxy> _webProcessProxy;
|
id<SBRWebProcessProxy> _webProcessProxy;
|
||||||
|
|
||||||
_WKUserStyleSheet *_darkModeStyleSheet;
|
_WKUserStyleSheet *_darkModeStyleSheet;
|
||||||
|
WKUserScript *_readabilityScript;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)tearDown
|
- (void)tearDown
|
||||||
@@ -161,4 +162,32 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void)parseDocumentForReaderMode:(void (^)(NSString * _Nonnull))completionBlock
|
||||||
|
{
|
||||||
|
WKUserContentController *userContentController = [_webViewConfiguration userContentController];
|
||||||
|
|
||||||
|
if (!_readabilityScript) {
|
||||||
|
NSURL *readabilityJSURL = [[NSBundle mainBundle] URLForResource:@"Readability" withExtension:@"js"];
|
||||||
|
NSString *readabilityJSSource = [NSString stringWithContentsOfURL:readabilityJSURL encoding:NSUTF8StringEncoding error:nil];
|
||||||
|
|
||||||
|
_readabilityScript = [[WKUserScript alloc] initWithSource:readabilityJSSource injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
[userContentController _addUserScriptImmediately:_readabilityScript];
|
||||||
|
|
||||||
|
NSString *script = @""
|
||||||
|
"var documentClone = document.cloneNode(true);"
|
||||||
|
"var article = new Readability(documentClone).parse();"
|
||||||
|
"article.content";
|
||||||
|
|
||||||
|
[_webView evaluateJavaScript:script completionHandler:^(NSString *result, NSError * _Nullable error) {
|
||||||
|
if (error != nil) {
|
||||||
|
NSLog(@"Bridge: Readability error: %@", error.localizedDescription);
|
||||||
|
} else {
|
||||||
|
completionBlock(result);
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -49,6 +49,9 @@
|
|||||||
CD853BD124E778B800D2BDCC /* History.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = CD853BCF24E778B800D2BDCC /* History.xcdatamodeld */; };
|
CD853BD124E778B800D2BDCC /* History.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = CD853BCF24E778B800D2BDCC /* History.xcdatamodeld */; };
|
||||||
CD853BD424E77BF900D2BDCC /* HistoryItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD853BD324E77BF900D2BDCC /* HistoryItem.swift */; };
|
CD853BD424E77BF900D2BDCC /* HistoryItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD853BD324E77BF900D2BDCC /* HistoryItem.swift */; };
|
||||||
CD97CF9225D5BE6F00288FEE /* NavigationControlsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD97CF9125D5BE6F00288FEE /* NavigationControlsView.swift */; };
|
CD97CF9225D5BE6F00288FEE /* NavigationControlsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD97CF9125D5BE6F00288FEE /* NavigationControlsView.swift */; };
|
||||||
|
CDC5DA3A25DB774D00BA8D99 /* Readability.js in Resources */ = {isa = PBXBuildFile; fileRef = CDC5DA3925DB774D00BA8D99 /* Readability.js */; };
|
||||||
|
CDC5DA3E25DB7C2C00BA8D99 /* ReaderViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDC5DA3D25DB7C2C00BA8D99 /* ReaderViewController.swift */; };
|
||||||
|
CDC5DA4025DB7EAC00BA8D99 /* reader.html in Resources */ = {isa = PBXBuildFile; fileRef = CDC5DA3F25DB7EAC00BA8D99 /* reader.html */; };
|
||||||
CDCE2664251AA80F007FE92A /* DocumentControlViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDCE2663251AA80F007FE92A /* DocumentControlViewController.swift */; };
|
CDCE2664251AA80F007FE92A /* DocumentControlViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDCE2663251AA80F007FE92A /* DocumentControlViewController.swift */; };
|
||||||
CDCE2666251AA840007FE92A /* StackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDCE2665251AA840007FE92A /* StackView.swift */; };
|
CDCE2666251AA840007FE92A /* StackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDCE2665251AA840007FE92A /* StackView.swift */; };
|
||||||
CDCE2668251AAA9A007FE92A /* FontSizeAdjustView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDCE2667251AAA9A007FE92A /* FontSizeAdjustView.swift */; };
|
CDCE2668251AAA9A007FE92A /* FontSizeAdjustView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDCE2667251AAA9A007FE92A /* FontSizeAdjustView.swift */; };
|
||||||
@@ -131,6 +134,9 @@
|
|||||||
CD853BD024E778B800D2BDCC /* History.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = History.xcdatamodel; sourceTree = "<group>"; };
|
CD853BD024E778B800D2BDCC /* History.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = History.xcdatamodel; sourceTree = "<group>"; };
|
||||||
CD853BD324E77BF900D2BDCC /* HistoryItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryItem.swift; sourceTree = "<group>"; };
|
CD853BD324E77BF900D2BDCC /* HistoryItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryItem.swift; sourceTree = "<group>"; };
|
||||||
CD97CF9125D5BE6F00288FEE /* NavigationControlsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationControlsView.swift; sourceTree = "<group>"; };
|
CD97CF9125D5BE6F00288FEE /* NavigationControlsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationControlsView.swift; sourceTree = "<group>"; };
|
||||||
|
CDC5DA3925DB774D00BA8D99 /* Readability.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = Readability.js; sourceTree = "<group>"; };
|
||||||
|
CDC5DA3D25DB7C2C00BA8D99 /* ReaderViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderViewController.swift; sourceTree = "<group>"; };
|
||||||
|
CDC5DA3F25DB7EAC00BA8D99 /* reader.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = reader.html; sourceTree = "<group>"; };
|
||||||
CDCE2663251AA80F007FE92A /* DocumentControlViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DocumentControlViewController.swift; sourceTree = "<group>"; };
|
CDCE2663251AA80F007FE92A /* DocumentControlViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DocumentControlViewController.swift; sourceTree = "<group>"; };
|
||||||
CDCE2665251AA840007FE92A /* StackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StackView.swift; sourceTree = "<group>"; };
|
CDCE2665251AA840007FE92A /* StackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StackView.swift; sourceTree = "<group>"; };
|
||||||
CDCE2667251AAA9A007FE92A /* FontSizeAdjustView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontSizeAdjustView.swift; sourceTree = "<group>"; };
|
CDCE2667251AAA9A007FE92A /* FontSizeAdjustView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontSizeAdjustView.swift; sourceTree = "<group>"; };
|
||||||
@@ -171,6 +177,8 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
1A14FC2524D251BD009B3F83 /* darkmode.css */,
|
1A14FC2524D251BD009B3F83 /* darkmode.css */,
|
||||||
|
CDC5DA3925DB774D00BA8D99 /* Readability.js */,
|
||||||
|
CDC5DA3F25DB7EAC00BA8D99 /* reader.html */,
|
||||||
);
|
);
|
||||||
path = Resources;
|
path = Resources;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -239,6 +247,7 @@
|
|||||||
1A03810E24E71CCA00826501 /* Common UI */,
|
1A03810E24E71CCA00826501 /* Common UI */,
|
||||||
CDCE2662251AA7FC007FE92A /* Document Controls UI */,
|
CDCE2662251AA7FC007FE92A /* Document Controls UI */,
|
||||||
1AD3104125254FA300A4A952 /* Find on Page */,
|
1AD3104125254FA300A4A952 /* Find on Page */,
|
||||||
|
CDC5DA3C25DB7A5500BA8D99 /* Reader View */,
|
||||||
1ADFF4CE24CBBCBD006DC7AE /* Script Policy UI */,
|
1ADFF4CE24CBBCBD006DC7AE /* Script Policy UI */,
|
||||||
1AB88F0324D3E1EC0006F850 /* Tabs */,
|
1AB88F0324D3E1EC0006F850 /* Tabs */,
|
||||||
1AB88F0424D3E1F90006F850 /* Titlebar and URL Bar */,
|
1AB88F0424D3E1F90006F850 /* Titlebar and URL Bar */,
|
||||||
@@ -350,6 +359,14 @@
|
|||||||
path = History;
|
path = History;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
CDC5DA3C25DB7A5500BA8D99 /* Reader View */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
CDC5DA3D25DB7C2C00BA8D99 /* ReaderViewController.swift */,
|
||||||
|
);
|
||||||
|
path = "Reader View";
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
CDCE2662251AA7FC007FE92A /* Document Controls UI */ = {
|
CDCE2662251AA7FC007FE92A /* Document Controls UI */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -443,8 +460,10 @@
|
|||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
1A14FC2624D251BD009B3F83 /* darkmode.css in Resources */,
|
1A14FC2624D251BD009B3F83 /* darkmode.css in Resources */,
|
||||||
|
CDC5DA4025DB7EAC00BA8D99 /* reader.html in Resources */,
|
||||||
1ADFF46C24C7DE54006DC7AE /* LaunchScreen.storyboard in Resources */,
|
1ADFF46C24C7DE54006DC7AE /* LaunchScreen.storyboard in Resources */,
|
||||||
1ADFF46924C7DE54006DC7AE /* Assets.xcassets in Resources */,
|
1ADFF46924C7DE54006DC7AE /* Assets.xcassets in Resources */,
|
||||||
|
CDC5DA3A25DB774D00BA8D99 /* Readability.js in Resources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -489,6 +508,7 @@
|
|||||||
1A03810B24E71C5600826501 /* ToolbarButtonContainerView.swift in Sources */,
|
1A03810B24E71C5600826501 /* ToolbarButtonContainerView.swift in Sources */,
|
||||||
1ADFF4CB24CB8278006DC7AE /* ScriptControllerIconView.swift in Sources */,
|
1ADFF4CB24CB8278006DC7AE /* ScriptControllerIconView.swift in Sources */,
|
||||||
CD7A8915251975B70075991E /* AutocompleteViewController.swift in Sources */,
|
CD7A8915251975B70075991E /* AutocompleteViewController.swift in Sources */,
|
||||||
|
CDC5DA3E25DB7C2C00BA8D99 /* ReaderViewController.swift in Sources */,
|
||||||
1AB88EFD24D3BA560006F850 /* TabController.swift in Sources */,
|
1AB88EFD24D3BA560006F850 /* TabController.swift in Sources */,
|
||||||
1ADFF4C324CA6AF6006DC7AE /* Geometry.swift in Sources */,
|
1ADFF4C324CA6AF6006DC7AE /* Geometry.swift in Sources */,
|
||||||
1ADFF4C924CA793E006DC7AE /* ToolbarViewController.swift in Sources */,
|
1ADFF4C924CA793E006DC7AE /* ToolbarViewController.swift in Sources */,
|
||||||
|
|||||||
Reference in New Issue
Block a user