Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle contingency settings state on remote config #3190

Merged
merged 8 commits into from
Aug 6, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions DuckDuckGo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -672,9 +672,9 @@
9F5E5AAC2C3D0FCD00165F54 /* ContextualDaxDialogsFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F5E5AAB2C3D0FCD00165F54 /* ContextualDaxDialogsFactory.swift */; };
9F5E5AB02C3E4C6000165F54 /* ContextualOnboardingPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F5E5AAF2C3E4C6000165F54 /* ContextualOnboardingPresenter.swift */; };
9F5E5AB22C3E606D00165F54 /* ContextualOnboardingPresenterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F5E5AB12C3E606D00165F54 /* ContextualOnboardingPresenterTests.swift */; };
9F6933192C59BB0300CD6A5D /* OnboardingPixelReporterMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F6933182C59BB0300CD6A5D /* OnboardingPixelReporterMock.swift */; };
9F69331B2C5A16E200CD6A5D /* OnboardingDaxFavouritesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F69331A2C5A16E200CD6A5D /* OnboardingDaxFavouritesTests.swift */; };
9F69331D2C5A191400CD6A5D /* MockTutorialSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F69331C2C5A191400CD6A5D /* MockTutorialSettings.swift */; };
9F6933192C59BB0300CD6A5D /* OnboardingPixelReporterMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F6933182C59BB0300CD6A5D /* OnboardingPixelReporterMock.swift */; };
9F69331F2C5B1D0C00CD6A5D /* OnFirstAppearViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F69331E2C5B1D0C00CD6A5D /* OnFirstAppearViewModifier.swift */; };
9F6933212C5B9A5B00CD6A5D /* OnboardingHostingControllerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F6933202C5B9A5B00CD6A5D /* OnboardingHostingControllerMock.swift */; };
9F8007262C5261AF003EDAF4 /* MockPrivacyDataReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F8007252C5261AF003EDAF4 /* MockPrivacyDataReporter.swift */; };
Expand Down Expand Up @@ -2404,9 +2404,9 @@
9F5E5AAB2C3D0FCD00165F54 /* ContextualDaxDialogsFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextualDaxDialogsFactory.swift; sourceTree = "<group>"; };
9F5E5AAF2C3E4C6000165F54 /* ContextualOnboardingPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextualOnboardingPresenter.swift; sourceTree = "<group>"; };
9F5E5AB12C3E606D00165F54 /* ContextualOnboardingPresenterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextualOnboardingPresenterTests.swift; sourceTree = "<group>"; };
9F6933182C59BB0300CD6A5D /* OnboardingPixelReporterMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingPixelReporterMock.swift; sourceTree = "<group>"; };
9F69331A2C5A16E200CD6A5D /* OnboardingDaxFavouritesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingDaxFavouritesTests.swift; sourceTree = "<group>"; };
9F69331C2C5A191400CD6A5D /* MockTutorialSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockTutorialSettings.swift; sourceTree = "<group>"; };
9F6933182C59BB0300CD6A5D /* OnboardingPixelReporterMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingPixelReporterMock.swift; sourceTree = "<group>"; };
9F69331E2C5B1D0C00CD6A5D /* OnFirstAppearViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnFirstAppearViewModifier.swift; sourceTree = "<group>"; };
9F6933202C5B9A5B00CD6A5D /* OnboardingHostingControllerMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingHostingControllerMock.swift; sourceTree = "<group>"; };
9F8007252C5261AF003EDAF4 /* MockPrivacyDataReporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockPrivacyDataReporter.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -10468,8 +10468,8 @@
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit";
requirement = {
kind = exactVersion;
version = 180.0.0;
branch = "bunn/duckplayer/contingency-handler";
kind = branch;
};
};
9F8FE9472BAE50E50071E372 /* XCRemoteSwiftPackageReference "lottie-spm" */ = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/DuckDuckGo/BrowserServicesKit",
"state" : {
"revision" : "92ecebfb4172ab9561959a07d7ef7037aea8c6e1",
"version" : "180.0.0"
"branch" : "bunn/duckplayer/contingency-handler",
"revision" : "9dc529a22fda53cbaa8785be2b4f7642b35bdf21"
}
},
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "WarningYoutube.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file not shown.
5 changes: 3 additions & 2 deletions DuckDuckGo/SettingsCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,8 @@ struct SettingsPickerCellView<T: CaseIterable & Hashable & CustomStringConvertib
let label: String
let options: [T]
@Binding var selectedOption: T

@Environment(\.isEnabled) private var isEnabled: Bool

/// Initializes a SettingsPickerCellView.
/// Use a custom picker that mimics the MenuPickerStyle
/// But with specific design
Expand All @@ -214,7 +215,7 @@ struct SettingsPickerCellView<T: CaseIterable & Hashable & CustomStringConvertib
HStack {
Text(label)
.daxBodyRegular()
.foregroundColor(Color(designSystemColor: .textPrimary))
.foregroundColor(isEnabled ? Color(designSystemColor: .textPrimary): Color(designSystemColor: .textSecondary))
Spacer()
Menu {
ForEach(options, id: \.self) { option in
Expand Down
55 changes: 55 additions & 0 deletions DuckDuckGo/SettingsDuckPlayerView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,22 @@
import Core
import SwiftUI
import DesignResourcesKit
import DuckUI

struct SettingsDuckPlayerView: View {
private static let learnMoreURL = URL(string: "https://duckduckgo.com/duckduckgo-help-pages/duck-player/")!

@EnvironmentObject var viewModel: SettingsViewModel
var body: some View {
List {
if viewModel.shouldDisplayDuckPlayerContingencyMessage {
Section {
ContingencyMessageView {
viewModel.openDuckPlayerContingencyMessageSite()
}
}
}

VStack(alignment: .center) {
Image("SettingsDuckPlayerHero")
.padding(.top, -20) // Adjust for the image padding
Expand All @@ -51,6 +60,7 @@ struct SettingsDuckPlayerView: View {
SettingsPickerCellView(label: UserText.settingsOpenVideosInDuckPlayerLabel,
options: DuckPlayerMode.allCases,
selectedOption: viewModel.duckPlayerModeBinding)
.disabled(viewModel.shouldDisplayDuckPlayerContingencyMessage)
} footer: {
Text(UserText.settingsDuckPlayerFooter)
.daxFootnoteRegular()
Expand All @@ -62,3 +72,48 @@ struct SettingsDuckPlayerView: View {
viewModel: viewModel)
}
}

private struct ContingencyMessageView: View {
let buttonCallback: () -> Void

private enum Copy {
static let title: String = UserText.duckPlayerContingencyMessageTitle
static let message: String = UserText.duckPlayerContingencyMessageBody
static let buttonTitle: String = UserText.duckPlayerContingencyMessageCTA
}
private enum Constants {
static let imageName: String = "WarningYoutube"
static let imageSize: CGSize = CGSize(width: 50, height: 50)
static let buttonCornerRadius: CGFloat = 8.0
}

var body: some View {
VStack(alignment: .center, spacing: 8) {
Image(Constants.imageName)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: Constants.imageSize.width, height: Constants.imageSize.height)
.padding(.bottom, 8)

Text(Copy.title)
.daxHeadline()
.foregroundColor(Color(designSystemColor: .textPrimary))

Text(Copy.message)
.daxBodyRegular()
.multilineTextAlignment(.center)
.lineLimit(nil)
.foregroundColor(Color(designSystemColor: .textPrimary))

Button {
buttonCallback()
} label: {
Text(Copy.buttonTitle)
.foregroundColor(Color(designSystemColor: .textPrimary))
.bold()
}
.buttonStyle(SecondaryFillButtonStyle(fullWidth: false))
.padding(10)
}
}
}
20 changes: 17 additions & 3 deletions DuckDuckGo/SettingsViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import SwiftUI
import Common
import Combine
import SyncUI
import DuckPlayer

import Subscription
import NetworkProtection
Expand All @@ -42,11 +43,13 @@ final class SettingsViewModel: ObservableObject {
var emailManager: EmailManager { EmailManager() }
private let historyManager: HistoryManaging
let privacyProDataReporter: PrivacyProDataReporting?

// Subscription Dependencies
private let subscriptionManager: SubscriptionManager
private var subscriptionSignOutObserver: Any?

var duckPlayerContingencyHandler: DuckPlayerContingencyHandler {
DefaultDuckPlayerContingencyHandler(privacyConfigurationManager: ContentBlocking.shared.privacyConfigurationManager)
}

private enum UserDefaultsCacheKey: String, UserDefaultsCacheKeyStore {
case subscriptionState = "com.duckduckgo.ios.subscription.state"
}
Expand Down Expand Up @@ -396,7 +399,7 @@ extension SettingsViewModel {
networkProtection: getNetworkProtectionState(),
subscription: SettingsState.defaults.subscription,
sync: getSyncState(),
duckPlayerEnabled: featureFlagger.isFeatureOn(.duckPlayer),
duckPlayerEnabled: featureFlagger.isFeatureOn(.duckPlayer) || shouldDisplayDuckPlayerContingencyMessage,
duckPlayerMode: appSettings.duckPlayerMode
)

Expand Down Expand Up @@ -539,6 +542,17 @@ extension SettingsViewModel {
completionHandler: nil)
}

var shouldDisplayDuckPlayerContingencyMessage: Bool {
duckPlayerContingencyHandler.shouldDisplayContingencyMessage
}

func openDuckPlayerContingencyMessageSite() {
guard let url = duckPlayerContingencyHandler.learnMoreURL else { return }
UIApplication.shared.open(url,
options: [:],
completionHandler: nil)
}

@MainActor func openCookiePopupManagement() {
pushViewController(legacyViewProvider.autoConsent)
}
Expand Down
4 changes: 4 additions & 0 deletions DuckDuckGo/UserText.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1187,6 +1187,10 @@ But if you *do* want a peek under the hood, you can find more information about
public static let duckPlayerPresentationModalBody = NSLocalizedString("duckplayer.presentation.modal.body", value: "Duck Player lets you watch YouTube without targeted ads in a theater-like experience in DuckDuckGo and what you watch won’t influence your recommendations.", comment: "Body text for the modal feature explanation")
public static let duckPlayerPresentationModalDismissButton = NSLocalizedString("duckplayer.presentation.modal.dismiss-button", value: "Got it!", comment: "Button that will dismiss the modal")

static let duckPlayerContingencyMessageTitle = NSLocalizedString("duck-player.contingency-title", value: "Duck Player Unavailable", comment: "Title for message explaining to the user that Duck Player is not available")
static let duckPlayerContingencyMessageBody = NSLocalizedString("duck-player.video-contingency-message", value: "Duck Player's functionality has been affected by recent changes to YouTube. We’re working to fix these issues and appreciate your understanding.", comment: "Message explaining to the user that Duck Player is not available")
static let duckPlayerContingencyMessageCTA = NSLocalizedString("duck-player.video-contingency-cta", value: "Learn More", comment: "Button for the message explaining to the user that Duck Player is not available so the user can learn more")

// MARK: - New Tab Page

// MARK: Shortcuts
Expand Down
9 changes: 9 additions & 0 deletions DuckDuckGo/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,15 @@
/* Message confirming that the download process has started. Parameter is downloaded file's filename */
"downloads.message.download-started" = "Download started for %@";

/* Title for message explaining to the user that Duck Player is not available */
"duck-player.contingency-title" = "Duck Player Unavailable";

/* Button for the message explaining to the user that Duck Player is not available so the user can learn more */
"duck-player.video-contingency-cta" = "Learn More";

/* Message explaining to the user that Duck Player is not available */
"duck-player.video-contingency-message" = "Duck Player's functionality has been affected by recent changes to YouTube. We’re working to fix these issues and appreciate your understanding.";

/* Text displayed when DuckPlayer is always enabled */
"duckPlayer.alwaysEnabled.label" = "Always";

Expand Down
Loading