diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index e20eda02de..3f3ca57ec9 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -52,8 +52,11 @@ 1D69C553291302F200B75945 /* BWVault.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D69C552291302F200B75945 /* BWVault.swift */; }; 1D6A492029CF7A490011DF74 /* NSPopoverExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D6A491F29CF7A490011DF74 /* NSPopoverExtension.swift */; }; 1D6A492129CF7A490011DF74 /* NSPopoverExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D6A491F29CF7A490011DF74 /* NSPopoverExtension.swift */; }; + 1D76760E2A9CE4F000DA0BD7 /* SupportedOsChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D8057C72A83CAEE00F4FED6 /* SupportedOsChecker.swift */; }; 1D77921828FDC54C00BE0210 /* FaviconReferenceCacheTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D77921728FDC54C00BE0210 /* FaviconReferenceCacheTests.swift */; }; 1D77921A28FDC79800BE0210 /* FaviconStoringMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D77921928FDC79800BE0210 /* FaviconStoringMock.swift */; }; + 1D8057C82A83CAEE00F4FED6 /* SupportedOsChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D8057C72A83CAEE00F4FED6 /* SupportedOsChecker.swift */; }; + 1D8057C92A83CB3C00F4FED6 /* SupportedOsChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D8057C72A83CAEE00F4FED6 /* SupportedOsChecker.swift */; }; 1D8B7D6A2A38BF050045C6F6 /* FireproofDomainsStoreMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BBF1712744CE36004F850E /* FireproofDomainsStoreMock.swift */; }; 1D8B7D6B2A38BF060045C6F6 /* FireproofDomainsStoreMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BBF1712744CE36004F850E /* FireproofDomainsStoreMock.swift */; }; 1DA6D0FD2A1FF9A100540406 /* HTTPCookie.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DA6D0FC2A1FF9A100540406 /* HTTPCookie.swift */; }; @@ -2944,6 +2947,7 @@ 1D77921728FDC54C00BE0210 /* FaviconReferenceCacheTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FaviconReferenceCacheTests.swift; sourceTree = ""; }; 1D77921928FDC79800BE0210 /* FaviconStoringMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FaviconStoringMock.swift; sourceTree = ""; }; 1D77921C28FFF27C00BE0210 /* RunningApplicationCheck.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunningApplicationCheck.swift; sourceTree = ""; }; + 1D8057C72A83CAEE00F4FED6 /* SupportedOsChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportedOsChecker.swift; sourceTree = ""; }; 1DA6D0FC2A1FF9A100540406 /* HTTPCookie.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPCookie.swift; sourceTree = ""; }; 1DA6D0FF2A1FF9DC00540406 /* HTTPCookieTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPCookieTests.swift; sourceTree = ""; }; 1DB9617929F1D06D00CF5568 /* InternalUserDeciderMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InternalUserDeciderMock.swift; sourceTree = ""; }; @@ -4296,6 +4300,14 @@ path = RunningApplication; sourceTree = ""; }; + 1D8057C62A83CAD500F4FED6 /* OsVersion */ = { + isa = PBXGroup; + children = ( + 1D8057C72A83CAEE00F4FED6 /* SupportedOsChecker.swift */, + ); + path = OsVersion; + sourceTree = ""; + }; 313AED9F287CAC5A00E1E8F4 /* UI */ = { isa = PBXGroup; children = ( @@ -6268,6 +6280,7 @@ AA80EC52256BE33A007083E7 /* Localizables */, 1D43EAFF291D7D280065E5D6 /* Logging */, 85AC3B3325DA828900C7D2AA /* Network */, + 1D8057C62A83CAD500F4FED6 /* OsVersion */, 4BB88B4E25B7BA20006F6B06 /* Utilities */, 1D77921B28FFF26100BE0210 /* RunningApplication */, AA86491424D831C4001BABEE /* View */, @@ -8695,6 +8708,7 @@ 3192A00D2A4C4CFF0084EA89 /* ChromiumDataImporter.swift in Sources */, 3192A00E2A4C4CFF0084EA89 /* LegacyWebKitDownloadDelegate.swift in Sources */, 3192A00F2A4C4CFF0084EA89 /* WKBackForwardListItemViewModel.swift in Sources */, + 1D76760E2A9CE4F000DA0BD7 /* SupportedOsChecker.swift in Sources */, 3192A0102A4C4CFF0084EA89 /* BWNotRespondingAlert.swift in Sources */, 3192A0112A4C4CFF0084EA89 /* DebugUserScript.swift in Sources */, 3192A0122A4C4CFF0084EA89 /* RecentlyClosedTab.swift in Sources */, @@ -9274,6 +9288,7 @@ 3706FAB4293F65D500E42796 /* NSPopUpButtonExtension.swift in Sources */, 3706FAB5293F65D500E42796 /* ConfigurationManager.swift in Sources */, 3706FAB6293F65D500E42796 /* YoutubePlayerUserScript.swift in Sources */, + 1D8057C92A83CB3C00F4FED6 /* SupportedOsChecker.swift in Sources */, 373D9B4929EEAC1B00381FDD /* SyncMetadataDatabase.swift in Sources */, 3706FAB7293F65D500E42796 /* PixelParameters.swift in Sources */, 3706FAB8293F65D500E42796 /* FaviconImageCache.swift in Sources */, @@ -10417,6 +10432,7 @@ 4BE65485271FCD7B008D1D63 /* LoginFaviconView.swift in Sources */, 4B0511CA262CAA5A00F6079C /* FireproofDomainsViewController.swift in Sources */, AA4D700725545EF800C3411E /* URLEventHandler.swift in Sources */, + 1D8057C82A83CAEE00F4FED6 /* SupportedOsChecker.swift in Sources */, AA92127725ADA07900600CD4 /* WKWebViewExtension.swift in Sources */, AAAB9114288EB1D600A057A9 /* CleanThisHistoryMenuItem.swift in Sources */, B6A9E499261474120067D1B9 /* TimedPixel.swift in Sources */, diff --git a/DuckDuckGo/AppDelegate/UpdateController.swift b/DuckDuckGo/AppDelegate/UpdateController.swift index 0fe1f3ad8a..35bdfd41d9 100644 --- a/DuckDuckGo/AppDelegate/UpdateController.swift +++ b/DuckDuckGo/AppDelegate/UpdateController.swift @@ -38,6 +38,10 @@ final class UpdateController: NSObject { } func checkForUpdates(_ sender: Any!) { + if !SupportedOSChecker.isCurrentOSReceivingUpdates { + showNotSupportedInfo() + } + NSApp.windows.forEach { if let controller = $0.windowController, "\(type(of: controller))" == "SUUpdateAlert" { $0.orderFrontRegardless() @@ -65,6 +69,13 @@ final class UpdateController: NSObject { #endif } + private func showNotSupportedInfo() { + if NSAlert.osNotSupported().runModal() != .cancel { + let url = Preferences.UnsupportedDeviceInfoBox.softwareUpdateURL + NSWorkspace.shared.open(url) + } + } + } extension UpdateController: SPUStandardUserDriverDelegate { diff --git a/DuckDuckGo/Assets.xcassets/Colors/UnsupportedOSWarningColor.colorset/Contents.json b/DuckDuckGo/Assets.xcassets/Colors/UnsupportedOSWarningColor.colorset/Contents.json new file mode 100644 index 0000000000..b2738065a1 --- /dev/null +++ b/DuckDuckGo/Assets.xcassets/Colors/UnsupportedOSWarningColor.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.140", + "blue" : "0x33", + "green" : "0xCC", + "red" : "0xFF" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/DuckDuckGo/Common/Extensions/NSAlertExtension.swift b/DuckDuckGo/Common/Extensions/NSAlertExtension.swift index c92af90cb0..4f1f44ed44 100644 --- a/DuckDuckGo/Common/Extensions/NSAlertExtension.swift +++ b/DuckDuckGo/Common/Extensions/NSAlertExtension.swift @@ -177,6 +177,20 @@ extension NSAlert { return alert } + static func osNotSupported() -> NSAlert { + let alert = NSAlert() + alert.messageText = UserText.aboutUnsupportedDeviceInfo1 + alert.informativeText = UserText.aboutUnsupportedDeviceInfo2Part1 + " " + + UserText.aboutUnsupportedDeviceInfo2Part2(version: "\(SupportedOSChecker.SupportedVersion.major).\(SupportedOSChecker.SupportedVersion.minor)") + " " + + UserText.aboutUnsupportedDeviceInfo2Part3 + " " + + UserText.aboutUnsupportedDeviceInfo2Part4 + alert.alertStyle = .warning + + alert.addButton(withTitle: UserText.checkForUpdate) + alert.addButton(withTitle: UserText.ok) + return alert + } + @discardableResult func runModal() async -> NSApplication.ModalResponse { await withCheckedContinuation { continuation in diff --git a/DuckDuckGo/Common/Extensions/WKWebViewConfigurationExtensions.swift b/DuckDuckGo/Common/Extensions/WKWebViewConfigurationExtensions.swift index bd9de9ce64..a6fc39d874 100644 --- a/DuckDuckGo/Common/Extensions/WKWebViewConfigurationExtensions.swift +++ b/DuckDuckGo/Common/Extensions/WKWebViewConfigurationExtensions.swift @@ -39,8 +39,10 @@ extension WKWebViewConfiguration { preferences.javaScriptCanOpenWindowsAutomatically = true preferences.isFraudulentWebsiteWarningEnabled = false - if urlSchemeHandler(forURLScheme: DuckPlayer.duckPlayerScheme) == nil { - setURLSchemeHandler(DuckPlayerSchemeHandler(), forURLScheme: DuckPlayer.duckPlayerScheme) + if SupportedOSChecker.isCurrentOSReceivingUpdates { + if urlSchemeHandler(forURLScheme: DuckPlayer.duckPlayerScheme) == nil { + setURLSchemeHandler(DuckPlayerSchemeHandler(), forURLScheme: DuckPlayer.duckPlayerScheme) + } } let userContentController = UserContentController(assetsPublisher: contentBlocking.contentBlockingAssetsPublisher, diff --git a/DuckDuckGo/Common/Localizables/UserText.swift b/DuckDuckGo/Common/Localizables/UserText.swift index 3793a16c6e..3fb625a984 100644 --- a/DuckDuckGo/Common/Localizables/UserText.swift +++ b/DuckDuckGo/Common/Localizables/UserText.swift @@ -64,6 +64,7 @@ struct UserText { static let tabOnboardingTitle = NSLocalizedString("tab.onboarding.title", value: "Welcome", comment: "Tab onboarding title") static let tabErrorTitle = NSLocalizedString("tab.error.title", value: "Oops!", comment: "Tab error title") static let openSystemPreferences = NSLocalizedString("open.preferences", value: "Open System Preferences", comment: "Open System Preferences (to re-enable permission for the App) (up to and including macOS 12") + static let checkForUpdate = NSLocalizedString("check.for.update", value: "Check for Update", comment: "Button users can use to check for a new update") static let unknownErrorMessage = NSLocalizedString("error.unknown", value: "An unknown error has occurred", comment: "Error page subtitle") static let unknownErrorTryAgainMessage = NSLocalizedString("error.unknown.try.again", value: "An unknown error has occurred", comment: "Generic error message on a dialog for when the cause is not known.") @@ -322,6 +323,15 @@ struct UserText { static let aboutDuckDuckGo = NSLocalizedString("preferences.about.about-duckduckgo", value: "About DuckDuckGo", comment: "About screen") static let privacySimplified = NSLocalizedString("preferences.about.privacy-simplified", value: "Privacy, simplified.", comment: "About screen") + static let aboutUnsupportedDeviceInfo1 = NSLocalizedString("preferences.about.unsupported-device-info1", value: "DuckDuckGo is no longer providing browser updates for your version of macOS.", comment: "") + static let aboutUnsupportedDeviceInfo2Part1 = NSLocalizedString("preferences.about.unsupported-device-info2-part1", value: "Please", comment: "Second paragraph of unsupported device info - sentence part 1") + static func aboutUnsupportedDeviceInfo2Part2(version: String) -> String { + return String(format: NSLocalizedString("preferences.about.unsupported-device-info2-part2", value: "update to macOS %@", comment: "Second paragraph of unsupported device info - sentence part 2 (underlined)"), version) + } + static let aboutUnsupportedDeviceInfo2Part3 = NSLocalizedString("preferences.about.unsupported-device-info2-part3", value: "or later to use the most recent version", comment: "Second paragraph of unsupported device info - sentence part 3") + static let aboutUnsupportedDeviceInfo2Part4 = NSLocalizedString("preferences.about.unsupported-device-info2-part3", value: "of DuckDuckGo. You can also keep using your current version of the browser, but it will not receive further updates.", comment: "Second paragraph of unsupported device info - sentence part 4") + static let unsupportedDeviceInfoAlertHeader = NSLocalizedString("unsupported.device.info.alert.header", value: "Your version of macOS is no longer supported.", comment: "") + static func moreAt(url: String) -> String { let localized = NSLocalizedString("preferences.about.more-at", value: "More at %@", comment: "Link to the about page") diff --git a/DuckDuckGo/Common/OsVersion/SupportedOsChecker.swift b/DuckDuckGo/Common/OsVersion/SupportedOsChecker.swift new file mode 100644 index 0000000000..9290367f6b --- /dev/null +++ b/DuckDuckGo/Common/OsVersion/SupportedOsChecker.swift @@ -0,0 +1,46 @@ +// +// SupportedOsChecker.swift +// +// Copyright © 2023 DuckDuckGo. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation + +final class SupportedOSChecker { + + struct SupportedVersion { + static let major = 11 + static let minor = 4 + static let patch = 0 + } + + private static let currentOSVersion = ProcessInfo.processInfo.operatingSystemVersion + + // Check if the current macOS version is at least the supported version + static var isCurrentOSReceivingUpdates: Bool { + if currentOSVersion.majorVersion > SupportedVersion.major { + return true + } + if currentOSVersion.majorVersion == SupportedVersion.major { + if currentOSVersion.minorVersion > SupportedVersion.minor { + return true + } + if currentOSVersion.minorVersion == SupportedVersion.minor && currentOSVersion.patchVersion >= SupportedVersion.patch { + return true + } + } + return false + } +} diff --git a/DuckDuckGo/Feedback/View/Feedback.storyboard b/DuckDuckGo/Feedback/View/Feedback.storyboard index f48f80c778..510649b5af 100644 --- a/DuckDuckGo/Feedback/View/Feedback.storyboard +++ b/DuckDuckGo/Feedback/View/Feedback.storyboard @@ -1,8 +1,7 @@ - + - - + @@ -30,18 +29,18 @@ - + - + - + @@ -80,13 +79,74 @@ - + + - + - + @@ -108,11 +168,64 @@ - - + - + + + + + - + - + @@ -299,67 +374,6 @@ Gw - @@ -369,11 +383,11 @@ DQ + - @@ -383,21 +397,24 @@ DQ + + + - + diff --git a/DuckDuckGo/Feedback/View/FeedbackViewController.swift b/DuckDuckGo/Feedback/View/FeedbackViewController.swift index cab7217204..043cc1fa7f 100644 --- a/DuckDuckGo/Feedback/View/FeedbackViewController.swift +++ b/DuckDuckGo/Feedback/View/FeedbackViewController.swift @@ -19,6 +19,7 @@ import Cocoa import Combine import Common +import SwiftUI final class FeedbackViewController: NSViewController { @@ -27,7 +28,10 @@ final class FeedbackViewController: NSViewController { static let feedbackContentHeight: CGFloat = 338 static let websiteBreakageContentHeight: CGFloat = 472 static let thankYouContentHeight: CGFloat = 262 - + static let browserFeedbackViewTopConstraint: CGFloat = 53 + static let browserFeedbackViewWebsiteBreakageTopConstraint: CGFloat = 153 + static let unsupportedOSWarningHeight: CGFloat = 200 + static let websiteBreakageTopConstraint: CGFloat = 53 } enum FormOption { @@ -53,11 +57,15 @@ final class FeedbackViewController: NSViewController { @IBOutlet weak var contentViewHeightContraint: NSLayoutConstraint! @IBOutlet weak var browserFeedbackView: NSView! + @IBOutlet weak var browserFeedbackViewTopConstraint: NSLayoutConstraint! + @IBOutlet weak var browserFeedbackDescriptionLabel: NSTextField! @IBOutlet weak var browserFeedbackTextView: NSTextView! @IBOutlet weak var browserFeedbackDisclaimerTextView: NSTextField! + @IBOutlet weak var unsupportedOsView: NSView! @IBOutlet weak var websiteBreakageView: NSView! + @IBOutlet weak var websiteBreakageViewTopConstraint: NSLayoutConstraint! @IBOutlet weak var urlTextField: NSTextField! @IBOutlet weak var websiteBreakageCategoryPopUpButton: NSPopUpButton! @@ -66,9 +74,6 @@ final class FeedbackViewController: NSViewController { @IBOutlet weak var thankYouView: NSView! private var cancellables = Set() - private var browserFeedbackConstraint: NSLayoutConstraint? - private var browserFeedbackBreakageConstraint: NSLayoutConstraint? - var currentTab: Tab? var currentTabUrl: URL? { guard let url = currentTab?.content.url else { @@ -86,11 +91,6 @@ final class FeedbackViewController: NSViewController { super.viewDidLoad() setContentViewHeight(Constants.defaultContentHeight, animated: false) setupTextViews() - - browserFeedbackConstraint = browserFeedbackView.topAnchor.constraint(equalTo: optionPopUpButton.bottomAnchor, constant: 8) - browserFeedbackBreakageConstraint = browserFeedbackView.topAnchor.constraint(equalTo: websiteBreakageView.bottomAnchor) - - browserFeedbackConstraint?.isActive = true } override func viewDidAppear() { @@ -197,20 +197,22 @@ final class FeedbackViewController: NSViewController { browserFeedbackView.isHidden = false + showUnsupportedOsViewIfNeeded() + let unsupportedOSWarningHeight = isOsUnsupported ? Constants.unsupportedOSWarningHeight : 0 + let contentHeight: CGFloat switch selectedFormOption { case .feedback(let feedbackCategory): - contentHeight = Constants.feedbackContentHeight + contentHeight = Constants.feedbackContentHeight + unsupportedOSWarningHeight updateBrowserFeedbackDescriptionLabel(for: feedbackCategory) - browserFeedbackBreakageConstraint?.isActive = false - browserFeedbackConstraint?.isActive = true + browserFeedbackViewTopConstraint.constant = Constants.browserFeedbackViewTopConstraint + unsupportedOSWarningHeight websiteBreakageView.isHidden = true case .websiteBreakage: - contentHeight = Constants.websiteBreakageContentHeight + contentHeight = Constants.websiteBreakageContentHeight + unsupportedOSWarningHeight + websiteBreakageViewTopConstraint.constant = Constants.websiteBreakageTopConstraint + unsupportedOSWarningHeight urlTextField.stringValue = currentTabUrl?.absoluteString ?? "" updateBrowserFeedbackDescriptionLabel(for: .bug) - browserFeedbackConstraint?.isActive = false - browserFeedbackBreakageConstraint?.isActive = true + browserFeedbackViewTopConstraint.constant = Constants.browserFeedbackViewWebsiteBreakageTopConstraint + unsupportedOSWarningHeight websiteBreakageView.isHidden = false } updateBrowserFeedbackDisclaimerLabel(for: selectedFormOption) @@ -325,6 +327,21 @@ final class FeedbackViewController: NSViewController { contentView.isHidden = true thankYouView.isHidden = false } + + var isOsUnsupported: Bool { + return !SupportedOSChecker.isCurrentOSReceivingUpdates + } + + private weak var unsupportedOsChildView: NSView? + private func showUnsupportedOsViewIfNeeded() { + if isOsUnsupported && unsupportedOsChildView == nil { + let view = NSHostingView(rootView: Preferences.UnsupportedDeviceInfoBox(wide: false)) + unsupportedOsView.addAndLayout(view) + unsupportedOsView.isHidden = false + unsupportedOsChildView = view + } + } + } fileprivate extension WebsiteBreakage.Category { diff --git a/DuckDuckGo/Preferences/View/PreferencesAboutView.swift b/DuckDuckGo/Preferences/View/PreferencesAboutView.swift index 3c195d517e..7f75507bc1 100644 --- a/DuckDuckGo/Preferences/View/PreferencesAboutView.swift +++ b/DuckDuckGo/Preferences/View/PreferencesAboutView.swift @@ -40,6 +40,12 @@ extension Preferences { Text(UserText.aboutDuckDuckGo) .font(Const.Fonts.preferencePaneTitle) + if !SupportedOSChecker.isCurrentOSReceivingUpdates { + UnsupportedDeviceInfoBox(wide: true) + .padding(.top, 10) + .padding(.leading, -20) + } + PreferencePaneSection { HStack { Image("AboutPageLogo") @@ -79,4 +85,84 @@ extension Preferences { } } + struct UnsupportedDeviceInfoBox: View { + + static let softwareUpdateURL = URL(string: "x-apple.systempreferences:com.apple.preferences.softwareupdate")! + + var wide: Bool + + var width: CGFloat { + return wide ? 510 : 320 + } + + var height: CGFloat { + return wide ? 130 : 200 + } + + var osVersion: String { + return "\(ProcessInfo.processInfo.operatingSystemVersion)" + } + + var combinedText: String { + return UserText.aboutUnsupportedDeviceInfo2Part1 + " " + + UserText.aboutUnsupportedDeviceInfo2Part2(version: versionString) + " " + + UserText.aboutUnsupportedDeviceInfo2Part3 + " " + + UserText.aboutUnsupportedDeviceInfo2Part4 + } + + var versionString: String { + return "\(SupportedOSChecker.SupportedVersion.major).\(SupportedOSChecker.SupportedVersion.minor)" + } + + var body: some View { + let image = Image("Alert-Color-16") + .resizable() + .frame(width: 16, height: 16) + .padding(.trailing, 4) + + let versionText = Text(UserText.aboutUnsupportedDeviceInfo1) + + let narrowContentView = Text(combinedText) + + let wideContentView: some View = VStack(alignment: .leading, spacing: 0) { + HStack(alignment: .center, spacing: 0) { + Text(UserText.aboutUnsupportedDeviceInfo2Part1 + " ") + Button(action: { + NSWorkspace.shared.open(Self.softwareUpdateURL) + }) { + Text(UserText.aboutUnsupportedDeviceInfo2Part2(version: versionString) + " ") + .foregroundColor(Color.blue) + .underline() + } + .buttonStyle(PlainButtonStyle()) + .onHover { hovering in + if hovering { + NSCursor.pointingHand.set() + } else { + NSCursor.arrow.set() + } + } + Text(UserText.aboutUnsupportedDeviceInfo2Part3) + } + Text(UserText.aboutUnsupportedDeviceInfo2Part4) + } + + return HStack(alignment: .top) { + image + VStack(alignment: .leading, spacing: 12) { + versionText + if wide { + wideContentView + } else { + narrowContentView + } + } + } + .padding() + .background(Color("UnsupportedOSWarningColor")) + .cornerRadius(8) + .frame(width: width, height: height) + } + } + } diff --git a/DuckDuckGo/YoutubePlayer/DuckPlayer.swift b/DuckDuckGo/YoutubePlayer/DuckPlayer.swift index 30567cd4c3..54f9c95ef5 100644 --- a/DuckDuckGo/YoutubePlayer/DuckPlayer.swift +++ b/DuckDuckGo/YoutubePlayer/DuckPlayer.swift @@ -87,7 +87,11 @@ final class DuckPlayer { static let shared = DuckPlayer() var isAvailable: Bool { - isFeatureEnabled + if SupportedOSChecker.isCurrentOSReceivingUpdates { + return isFeatureEnabled + } else { + return false + } } @Published var mode: DuckPlayerMode