From 59c3015fff31f65e8270b8342288daeeb36a62a6 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Tue, 7 Jul 2020 19:31:24 -0500 Subject: [PATCH] Made web view preloading code and scheme handler shared code --- .../Article/ArticleIconSchemeHandler.swift | 0 .../Article/PreloadedWebView.swift | 2 + .../Article/WebViewProvider.swift | 2 +- .../Article/WrapperScriptMessageHandler.swift | 0 Multiplatform/Shared/SceneModel.swift | 6 - Multiplatform/macOS/Article/IconView.swift | 131 ++++++++++++++++++ NetNewsWire.xcodeproj/project.pbxproj | 22 ++- 7 files changed, 151 insertions(+), 12 deletions(-) rename Multiplatform/{iOS => Shared}/Article/ArticleIconSchemeHandler.swift (100%) rename Multiplatform/{iOS => Shared}/Article/PreloadedWebView.swift (98%) rename Multiplatform/{iOS => Shared}/Article/WebViewProvider.swift (99%) rename Multiplatform/{iOS => Shared}/Article/WrapperScriptMessageHandler.swift (100%) create mode 100644 Multiplatform/macOS/Article/IconView.swift diff --git a/Multiplatform/iOS/Article/ArticleIconSchemeHandler.swift b/Multiplatform/Shared/Article/ArticleIconSchemeHandler.swift similarity index 100% rename from Multiplatform/iOS/Article/ArticleIconSchemeHandler.swift rename to Multiplatform/Shared/Article/ArticleIconSchemeHandler.swift diff --git a/Multiplatform/iOS/Article/PreloadedWebView.swift b/Multiplatform/Shared/Article/PreloadedWebView.swift similarity index 98% rename from Multiplatform/iOS/Article/PreloadedWebView.swift rename to Multiplatform/Shared/Article/PreloadedWebView.swift index 944e1d578..0807b94da 100644 --- a/Multiplatform/iOS/Article/PreloadedWebView.swift +++ b/Multiplatform/Shared/Article/PreloadedWebView.swift @@ -22,7 +22,9 @@ class PreloadedWebView: WKWebView { let configuration = WKWebViewConfiguration() configuration.preferences = preferences configuration.setValue(true, forKey: "allowUniversalAccessFromFileURLs") + #if os(iOS) configuration.allowsInlineMediaPlayback = true + #endif configuration.mediaTypesRequiringUserActionForPlayback = .audio configuration.setURLSchemeHandler(articleIconSchemeHandler, forURLScheme: ArticleRenderer.imageIconScheme) diff --git a/Multiplatform/iOS/Article/WebViewProvider.swift b/Multiplatform/Shared/Article/WebViewProvider.swift similarity index 99% rename from Multiplatform/iOS/Article/WebViewProvider.swift rename to Multiplatform/Shared/Article/WebViewProvider.swift index dea43b7ff..ca30a4a57 100644 --- a/Multiplatform/iOS/Article/WebViewProvider.swift +++ b/Multiplatform/Shared/Article/WebViewProvider.swift @@ -6,7 +6,7 @@ // Copyright © 2020 Ranchero Software. All rights reserved. // -import UIKit +import Foundation import RSCore import WebKit diff --git a/Multiplatform/iOS/Article/WrapperScriptMessageHandler.swift b/Multiplatform/Shared/Article/WrapperScriptMessageHandler.swift similarity index 100% rename from Multiplatform/iOS/Article/WrapperScriptMessageHandler.swift rename to Multiplatform/Shared/Article/WrapperScriptMessageHandler.swift diff --git a/Multiplatform/Shared/SceneModel.swift b/Multiplatform/Shared/SceneModel.swift index 67f198928..e93f7b7c8 100644 --- a/Multiplatform/Shared/SceneModel.swift +++ b/Multiplatform/Shared/SceneModel.swift @@ -19,9 +19,7 @@ final class SceneModel: ObservableObject { var articleModel: ArticleModel? private var refreshProgressModel: RefreshProgressModel? = nil - #if os(iOS) private var _webViewProvider: WebViewProvider? = nil - #endif // MARK: API @@ -29,9 +27,7 @@ final class SceneModel: ObservableObject { self.refreshProgressModel = RefreshProgressModel() self.refreshProgressModel!.$state.assign(to: self.$refreshProgressState) - #if os(iOS) self._webViewProvider = WebViewProvider(sceneModel: self) - #endif } func articleFor(_ articleID: String) -> Article? { @@ -64,11 +60,9 @@ extension SceneModel: TimelineModelDelegate { extension SceneModel: ArticleModelDelegate { - #if os(iOS) var webViewProvider: WebViewProvider? { return _webViewProvider } - #endif func findPrevArticle(_: ArticleModel, article: Article) -> Article? { return timelineModel?.findPrevArticle(article) diff --git a/Multiplatform/macOS/Article/IconView.swift b/Multiplatform/macOS/Article/IconView.swift new file mode 100644 index 000000000..481a77fa4 --- /dev/null +++ b/Multiplatform/macOS/Article/IconView.swift @@ -0,0 +1,131 @@ +// +// IconView.swift +// Multiplatform macOS +// +// Created by Maurice Parker on 7/7/20. +// Copyright © 2020 Ranchero Software. All rights reserved. +// + +import AppKit + +final class IconView: NSView { + + var iconImage: IconImage? = nil { + didSet { + if iconImage !== oldValue { + imageView.image = iconImage?.image + + if NSApplication.shared.effectiveAppearance.isDarkMode { + if self.iconImage?.isDark ?? false { + self.isDisconcernable = false + } else { + self.isDisconcernable = true + } + } else { + if self.iconImage?.isBright ?? false { + self.isDisconcernable = false + } else { + self.isDisconcernable = true + } + } + + needsDisplay = true + needsLayout = true + } + } + } + + private var isDisconcernable = true + + override var isFlipped: Bool { + return true + } + + private let imageView: NSImageView = { + let imageView = NSImageView(frame: NSRect.zero) + imageView.animates = false + imageView.imageAlignment = .alignCenter + imageView.imageScaling = .scaleProportionallyUpOrDown + return imageView + }() + + private var hasExposedVerticalBackground: Bool { + return imageView.frame.size.height < bounds.size.height + } + + override init(frame frameRect: NSRect) { + super.init(frame: frameRect) + commonInit() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + commonInit() + } + + convenience init() { + self.init(frame: NSRect.zero) + } + + override func viewDidMoveToSuperview() { + needsLayout = true + needsDisplay = true + } + + override func layout() { + resizeSubviews(withOldSize: NSZeroSize) + } + + override func resizeSubviews(withOldSize oldSize: NSSize) { + imageView.setFrame(ifNotEqualTo: rectForImageView()) + } + + override func draw(_ dirtyRect: NSRect) { + guard hasExposedVerticalBackground || !isDisconcernable else { + return + } + + let color = AppAssets.iconBackgroundColor + color.set() + dirtyRect.fill() + } +} + +private extension IconView { + + func commonInit() { + addSubview(imageView) + wantsLayer = true + layer?.cornerRadius = 4.0 + } + + func rectForImageView() -> NSRect { + guard let image = iconImage?.image else { + return NSRect.zero + } + + let imageSize = image.size + let viewSize = bounds.size + if imageSize.height == imageSize.width { + if imageSize.height >= viewSize.height * 0.75 { + // Close enough to viewSize to scale up the image. + return NSMakeRect(0.0, 0.0, viewSize.width, viewSize.height) + } + let offset = floor((viewSize.height - imageSize.height) / 2.0) + return NSMakeRect(offset, offset, imageSize.width, imageSize.height) + } + else if imageSize.height > imageSize.width { + let factor = viewSize.height / imageSize.height + let width = imageSize.width * factor + let originX = floor((viewSize.width - width) / 2.0) + return NSMakeRect(originX, 0.0, width, viewSize.height) + } + + // Wider than tall: imageSize.width > imageSize.height + let factor = viewSize.width / imageSize.width + let height = imageSize.height * factor + let originY = floor((viewSize.height - height) / 2.0) + return NSMakeRect(0.0, originY, viewSize.width, height) + } +} + diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index be30735dc..29f64d84b 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -326,6 +326,11 @@ 51A9A5F52380F6A60033AADF /* ModalNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A9A5F42380F6A60033AADF /* ModalNavigationController.swift */; }; 51A9A60A2382FD240033AADF /* PoppableGestureRecognizerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A9A6092382FD240033AADF /* PoppableGestureRecognizerDelegate.swift */; }; 51AB8AB323B7F4C6008F147D /* WebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51AB8AB223B7F4C6008F147D /* WebViewController.swift */; }; + 51B54A4324B5499B0014348B /* WebViewProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5177471924B3863000EB0F74 /* WebViewProvider.swift */; }; + 51B54A6524B549B20014348B /* WrapperScriptMessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 517B2EBB24B3E62A001AC46C /* WrapperScriptMessageHandler.swift */; }; + 51B54A6624B549CB0014348B /* PreloadedWebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5177471324B37D4000EB0F74 /* PreloadedWebView.swift */; }; + 51B54A6724B549FE0014348B /* ArticleIconSchemeHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5177471524B37D9700EB0F74 /* ArticleIconSchemeHandler.swift */; }; + 51B54A6924B54A490014348B /* IconView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51B54A6824B54A490014348B /* IconView.swift */; }; 51B5C87723F22B8200032075 /* ExtensionContainers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51B5C87623F22B8200032075 /* ExtensionContainers.swift */; }; 51B5C87B23F2317700032075 /* ExtensionFeedAddRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51B5C87A23F2317700032075 /* ExtensionFeedAddRequest.swift */; }; 51B5C87D23F2346200032075 /* ExtensionContainersFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51B5C87C23F2346200032075 /* ExtensionContainersFile.swift */; }; @@ -1969,6 +1974,7 @@ 51A9A5F42380F6A60033AADF /* ModalNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalNavigationController.swift; sourceTree = ""; }; 51A9A6092382FD240033AADF /* PoppableGestureRecognizerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PoppableGestureRecognizerDelegate.swift; sourceTree = ""; }; 51AB8AB223B7F4C6008F147D /* WebViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewController.swift; sourceTree = ""; }; + 51B54A6824B54A490014348B /* IconView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconView.swift; sourceTree = ""; }; 51B5C87623F22B8200032075 /* ExtensionContainers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionContainers.swift; sourceTree = ""; }; 51B5C87A23F2317700032075 /* ExtensionFeedAddRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionFeedAddRequest.swift; sourceTree = ""; }; 51B5C87C23F2346200032075 /* ExtensionContainersFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionContainersFile.swift; sourceTree = ""; }; @@ -2706,17 +2712,13 @@ isa = PBXGroup; children = ( 5177472124B38CAE00EB0F74 /* ArticleExtractorButtonState.swift */, - 5177471524B37D9700EB0F74 /* ArticleIconSchemeHandler.swift */, 5177470D24B2FF6F00EB0F74 /* ArticleView.swift */, 5177470F24B3029400EB0F74 /* ArticleViewController.swift */, 5177471724B3812200EB0F74 /* IconView.swift */, 5177471B24B387AC00EB0F74 /* ImageScrollView.swift */, 5177471D24B387E100EB0F74 /* ImageTransition.swift */, 5177471F24B3882600EB0F74 /* ImageViewController.swift */, - 5177471324B37D4000EB0F74 /* PreloadedWebView.swift */, 5177471124B37C5400EB0F74 /* WebViewController.swift */, - 5177471924B3863000EB0F74 /* WebViewProvider.swift */, - 517B2EBB24B3E62A001AC46C /* WrapperScriptMessageHandler.swift */, ); path = Article; sourceTree = ""; @@ -2725,6 +2727,7 @@ isa = PBXGroup; children = ( 51A576BD24AE637400078888 /* ArticleView.swift */, + 51B54A6824B54A490014348B /* IconView.swift */, ); path = Article; sourceTree = ""; @@ -2838,8 +2841,12 @@ 517B2EDE24B3E8FE001AC46C /* page.html */, 517B2EE124B3E8FE001AC46C /* main_multiplatform.js */, 51A5769524AE617200078888 /* ArticleContainerView.swift */, + 5177471524B37D9700EB0F74 /* ArticleIconSchemeHandler.swift */, 51A576BA24AE621800078888 /* ArticleModel.swift */, 5177470524B2910300EB0F74 /* ArticleToolbarModifier.swift */, + 5177471324B37D4000EB0F74 /* PreloadedWebView.swift */, + 5177471924B3863000EB0F74 /* WebViewProvider.swift */, + 517B2EBB24B3E62A001AC46C /* WrapperScriptMessageHandler.swift */, ); path = Article; sourceTree = ""; @@ -2883,12 +2890,12 @@ 51C0519424A77E6D00194D5E /* macOS */ = { isa = PBXGroup; children = ( - 5177470C24B2FF3B00EB0F74 /* Article */, 51C051CD24A7A6DB00194D5E /* macOS-dev.entitlements */, 51C0514724A77DF800194D5E /* macOS.entitlements */, 51C0514624A77DF800194D5E /* Info.plist */, 51E4993924A8708800B667CB /* AppDelegate.swift */, 1729529A24AA1FD200D65E66 /* MacSearchField.swift */, + 5177470C24B2FF3B00EB0F74 /* Article */, 1729528F24AA1A4F00D65E66 /* Preferences */, ); path = macOS; @@ -5084,6 +5091,7 @@ 51E498CE24A8085D00B667CB /* UnreadFeed.swift in Sources */, 51E498C724A8085D00B667CB /* StarredFeedDelegate.swift in Sources */, 51919FB724AABCA100541E64 /* IconImageView.swift in Sources */, + 51B54A6924B54A490014348B /* IconView.swift in Sources */, 51E498FA24A808BA00B667CB /* SingleFaviconDownloader.swift in Sources */, 51E4993F24A8713B00B667CB /* ArticleStatusSyncTimer.swift in Sources */, 51E4993724A8680E00B667CB /* Reachability.swift in Sources */, @@ -5102,6 +5110,7 @@ 17D5F17224B0BC6700375168 /* SidebarToolbarModel.swift in Sources */, 514E6C0724AD2B5F00AC6F6E /* Image-Extensions.swift in Sources */, 51E4994D24A8734C00B667CB /* ExtensionPointIdentifer.swift in Sources */, + 51B54A6724B549FE0014348B /* ArticleIconSchemeHandler.swift in Sources */, 51E4992224A8095600B667CB /* URL-Extensions.swift in Sources */, 51E4990424A808C300B667CB /* WebFeedIconDownloader.swift in Sources */, 51E498CB24A8085D00B667CB /* TodayFeedDelegate.swift in Sources */, @@ -5135,6 +5144,7 @@ 51E4994A24A8734C00B667CB /* ExtensionPointManager.swift in Sources */, 514E6C0324AD29A300AC6F6E /* TimelineItemStatusView.swift in Sources */, 51A576BC24AE621800078888 /* ArticleModel.swift in Sources */, + 51B54A6524B549B20014348B /* WrapperScriptMessageHandler.swift in Sources */, 51E4996D24A8762D00B667CB /* ArticleExtractor.swift in Sources */, 51E4994024A8713B00B667CB /* AccountRefreshTimer.swift in Sources */, 51E49A0424A91FF600B667CB /* SceneNavigationView.swift in Sources */, @@ -5173,6 +5183,7 @@ FA80C13F24B072AB00974098 /* AddFolderModel.swift in Sources */, 51392D1C24AC19A000BE0D35 /* SidebarExpandedContainers.swift in Sources */, 51C0515F24A77DF800194D5E /* MainApp.swift in Sources */, + 51B54A4324B5499B0014348B /* WebViewProvider.swift in Sources */, 514E6C0024AD255D00AC6F6E /* PreviewArticles.swift in Sources */, 1729529524AA1CAA00D65E66 /* GeneralPreferencesView.swift in Sources */, 1729529424AA1CAA00D65E66 /* AdvancedPreferencesView.swift in Sources */, @@ -5183,6 +5194,7 @@ 51E4991424A808FF00B667CB /* ArticleStringFormatter.swift in Sources */, 51A576BF24AE637400078888 /* ArticleView.swift in Sources */, FF64D0EA24AF53EE0084080A /* RefreshProgressView.swift in Sources */, + 51B54A6624B549CB0014348B /* PreloadedWebView.swift in Sources */, 51E4991024A808DE00B667CB /* SmallIconProvider.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0;