mirror of
https://github.com/ProtonDriveApps/mac-drive.git
synced 2026-05-15 09:50:33 +00:00
2.10.1
This commit is contained in:
@@ -30,6 +30,7 @@ public enum ExternalFeatureFlag: String, CaseIterable, Codable {
|
||||
case driveDDKDisabled = "DriveDDKDisabled"
|
||||
case driveMacSyncRecoveryDisabled = "DriveMacSyncRecoveryDisabled"
|
||||
case driveMacKeepDownloadedDisabled = "DriveMacKeepDownloadedDisabled"
|
||||
case driveMacPromoBannerDisabled = "DriveMacPromoBannerDisabled"
|
||||
|
||||
// Sharing
|
||||
case driveSharingMigration = "DriveSharingMigration"
|
||||
|
||||
@@ -150,6 +150,7 @@ class ExternalFeatureFlagsRepository: FeatureFlagsRepository {
|
||||
case .driveDDKDisabled: return .driveDDKDisabled
|
||||
case .driveMacSyncRecoveryDisabled: return .driveMacSyncRecoveryDisabled
|
||||
case .driveMacKeepDownloadedDisabled: return .driveMacKeepDownloadedDisabled
|
||||
case .driveMacPromoBannerDisabled: return .driveMacPromoBannerDisabled
|
||||
// Sharing
|
||||
case .driveSharingMigration: return .driveSharingMigration
|
||||
case .driveSharingInvitations: return .driveSharingInvitations
|
||||
|
||||
@@ -39,6 +39,7 @@ extension LocalSettings: ExternalFeatureFlagsStore {
|
||||
case .driveDDKDisabled: driveDDKDisabled = value
|
||||
case .driveMacSyncRecoveryDisabled: driveMacSyncRecoveryDisabled = value
|
||||
case .driveMacKeepDownloadedDisabled: driveMacKeepDownloadedDisabled = value
|
||||
case .driveMacPromoBannerDisabled: driveMacPromoBannerDisabled = value
|
||||
// Sharing
|
||||
case .driveSharingMigration: driveSharingMigration = value
|
||||
case .driveSharingInvitations: driveSharingInvitations = value
|
||||
@@ -103,6 +104,7 @@ extension LocalSettings: ExternalFeatureFlagsStore {
|
||||
case .driveDDKDisabled: return driveDDKDisabled
|
||||
case .driveMacSyncRecoveryDisabled: return driveMacSyncRecoveryDisabled
|
||||
case .driveMacKeepDownloadedDisabled: return driveMacKeepDownloadedDisabled
|
||||
case .driveMacPromoBannerDisabled: return driveMacPromoBannerDisabled
|
||||
// Sharing
|
||||
case .driveSharingMigration: return driveSharingMigration
|
||||
case .driveSharingInvitations: return driveSharingInvitations
|
||||
|
||||
@@ -33,6 +33,7 @@ public enum FeatureAvailabilityFlag: CaseIterable {
|
||||
case driveDDKDisabled
|
||||
case driveMacSyncRecoveryDisabled
|
||||
case driveMacKeepDownloadedDisabled
|
||||
case driveMacPromoBannerDisabled
|
||||
|
||||
// Sharing
|
||||
case driveSharingMigration
|
||||
|
||||
@@ -61,6 +61,7 @@ public class LocalSettings: NSObject {
|
||||
@SettingsStorage("DriveDDKDisabled") public var driveDDKDisabledValue: Bool?
|
||||
@SettingsStorage("DriveMacSyncRecoveryDisabled") public var driveMacSyncRecoveryDisabledValue: Bool?
|
||||
@SettingsStorage("DriveMacKeepDownloadedDisabled") public var driveMacKeepDownloadedDisabledValue: Bool?
|
||||
@SettingsStorage("DriveMacPromoBannerDisabled") public var driveMacPromoBannerDisabledValue: Bool?
|
||||
@SettingsStorage("DriveAlbumsDisabled") public var driveAlbumsDisabledValue: Bool?
|
||||
@SettingsStorage("DriveCopyDisabled") public var driveCopyDisabledValue: Bool?
|
||||
@SettingsStorage("photoVolumeMigrationLastShownDate") public var photoVolumeMigrationLastShownDate: Date?
|
||||
@@ -184,6 +185,7 @@ public class LocalSettings: NSObject {
|
||||
self._driveDDKDisabledValue.configure(with: suite)
|
||||
self._driveMacSyncRecoveryDisabledValue.configure(with: suite)
|
||||
self._driveMacKeepDownloadedDisabledValue.configure(with: suite)
|
||||
self._driveMacPromoBannerDisabledValue.configure(with: suite)
|
||||
self._didFetchFeatureFlags.configure(with: suite)
|
||||
self._promotedNewFeaturesValue.configure(with: suite)
|
||||
self._driveAlbumsDisabledValue.configure(with: suite)
|
||||
@@ -663,6 +665,11 @@ public class LocalSettings: NSObject {
|
||||
set { driveMacKeepDownloadedDisabledValue = newValue }
|
||||
}
|
||||
|
||||
public var driveMacPromoBannerDisabled: Bool {
|
||||
get { driveMacPromoBannerDisabledValue ?? false }
|
||||
set { driveMacPromoBannerDisabledValue = newValue }
|
||||
}
|
||||
|
||||
public var ratingIOSDrive: Bool {
|
||||
get { ratingIOSDriveValue ?? false }
|
||||
set { ratingIOSDriveValue = newValue }
|
||||
|
||||
@@ -1152,14 +1152,14 @@
|
||||
);
|
||||
mainGroup = AB71531724274ED900543720;
|
||||
packageReferences = (
|
||||
D83C419C2C53A233002EF29C /* XCRemoteSwiftPackageReference "Sparkle.git" */,
|
||||
D83C419C2C53A233002EF29C /* XCRemoteSwiftPackageReference "Sparkle" */,
|
||||
D8AB30D62C6217B5006A5F7C /* XCRemoteSwiftPackageReference "OHHTTPStubs" */,
|
||||
D8AB30D92C621957006A5F7C /* XCRemoteSwiftPackageReference "TrustKit.git" */,
|
||||
D8AB30E32C621ABF006A5F7C /* XCRemoteSwiftPackageReference "apple-fusion.git" */,
|
||||
D8AB30D92C621957006A5F7C /* XCRemoteSwiftPackageReference "TrustKit" */,
|
||||
D8AB30E32C621ABF006A5F7C /* XCRemoteSwiftPackageReference "apple-fusion" */,
|
||||
3E9137BE2CC77C0400651BC1 /* XCRemoteSwiftPackageReference "SwiftLintPlugins" */,
|
||||
661DC23D2CB94C3C00DECBDE /* XCRemoteSwiftPackageReference "CryptoSwift.git" */,
|
||||
66E09DFC2E7DA3C30082A1B0 /* XCRemoteSwiftPackageReference "Yams.git" */,
|
||||
66E09E202E7DAD9F0082A1B0 /* XCRemoteSwiftPackageReference "protoncore_ios.git" */,
|
||||
661DC23D2CB94C3C00DECBDE /* XCRemoteSwiftPackageReference "CryptoSwift" */,
|
||||
66E09DFC2E7DA3C30082A1B0 /* XCRemoteSwiftPackageReference "Yams" */,
|
||||
66E09E202E7DAD9F0082A1B0 /* XCRemoteSwiftPackageReference "protoncore_ios" */,
|
||||
);
|
||||
productRefGroup = AB71532124274ED900543720 /* Products */;
|
||||
projectDirPath = "";
|
||||
@@ -1825,7 +1825,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
MARKETING_VERSION = 2.10.0;
|
||||
MARKETING_VERSION = 2.10.1;
|
||||
OTHER_CODE_SIGN_FLAGS = "";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = ch.protonmail.drive;
|
||||
PRODUCT_MODULE_NAME = ProtonDriveMac;
|
||||
@@ -1912,7 +1912,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
MARKETING_VERSION = 2.10.0;
|
||||
MARKETING_VERSION = 2.10.1;
|
||||
OTHER_CODE_SIGN_FLAGS = "";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = ch.protonmail.drive;
|
||||
PRODUCT_MODULE_NAME = ProtonDriveMac;
|
||||
@@ -1983,7 +1983,7 @@
|
||||
"@executable_path/../../../../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
MARKETING_VERSION = 2.10.0;
|
||||
MARKETING_VERSION = 2.10.1;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
OTHER_CODE_SIGN_FLAGS = "";
|
||||
@@ -2686,7 +2686,7 @@
|
||||
version = 0.57.0;
|
||||
};
|
||||
};
|
||||
661DC23D2CB94C3C00DECBDE /* XCRemoteSwiftPackageReference "CryptoSwift.git" */ = {
|
||||
661DC23D2CB94C3C00DECBDE /* XCRemoteSwiftPackageReference "CryptoSwift" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/krzyzanowskim/CryptoSwift.git";
|
||||
requirement = {
|
||||
@@ -2694,7 +2694,7 @@
|
||||
minimumVersion = 1.8.3;
|
||||
};
|
||||
};
|
||||
66E09DFC2E7DA3C30082A1B0 /* XCRemoteSwiftPackageReference "Yams.git" */ = {
|
||||
66E09DFC2E7DA3C30082A1B0 /* XCRemoteSwiftPackageReference "Yams" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/jpsim/Yams.git";
|
||||
requirement = {
|
||||
@@ -2702,7 +2702,7 @@
|
||||
minimumVersion = 5.0.0;
|
||||
};
|
||||
};
|
||||
66E09E202E7DAD9F0082A1B0 /* XCRemoteSwiftPackageReference "protoncore_ios.git" */ = {
|
||||
66E09E202E7DAD9F0082A1B0 /* XCRemoteSwiftPackageReference "protoncore_ios" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/ProtonMail/protoncore_ios.git";
|
||||
requirement = {
|
||||
@@ -2710,7 +2710,7 @@
|
||||
version = 33.2.0;
|
||||
};
|
||||
};
|
||||
D83C419C2C53A233002EF29C /* XCRemoteSwiftPackageReference "Sparkle.git" */ = {
|
||||
D83C419C2C53A233002EF29C /* XCRemoteSwiftPackageReference "Sparkle" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/sparkle-project/Sparkle.git";
|
||||
requirement = {
|
||||
@@ -2727,7 +2727,7 @@
|
||||
minimumVersion = 0.0.0;
|
||||
};
|
||||
};
|
||||
D8AB30D92C621957006A5F7C /* XCRemoteSwiftPackageReference "TrustKit.git" */ = {
|
||||
D8AB30D92C621957006A5F7C /* XCRemoteSwiftPackageReference "TrustKit" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/ProtonMail/TrustKit.git";
|
||||
requirement = {
|
||||
@@ -2736,7 +2736,7 @@
|
||||
minimumVersion = 0.0.0;
|
||||
};
|
||||
};
|
||||
D8AB30E32C621ABF006A5F7C /* XCRemoteSwiftPackageReference "apple-fusion.git" */ = {
|
||||
D8AB30E32C621ABF006A5F7C /* XCRemoteSwiftPackageReference "apple-fusion" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/ProtonMail/apple-fusion.git";
|
||||
requirement = {
|
||||
@@ -2766,7 +2766,7 @@
|
||||
};
|
||||
661DC23E2CB94C3C00DECBDE /* CryptoSwift */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 661DC23D2CB94C3C00DECBDE /* XCRemoteSwiftPackageReference "CryptoSwift.git" */;
|
||||
package = 661DC23D2CB94C3C00DECBDE /* XCRemoteSwiftPackageReference "CryptoSwift" */;
|
||||
productName = CryptoSwift;
|
||||
};
|
||||
667B32052C69F4E500D15C95 /* PDCore */ = {
|
||||
@@ -2787,47 +2787,47 @@
|
||||
};
|
||||
66E09DFD2E7DA3C30082A1B0 /* Yams */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 66E09DFC2E7DA3C30082A1B0 /* XCRemoteSwiftPackageReference "Yams.git" */;
|
||||
package = 66E09DFC2E7DA3C30082A1B0 /* XCRemoteSwiftPackageReference "Yams" */;
|
||||
productName = Yams;
|
||||
};
|
||||
66E09DFF2E7DA42D0082A1B0 /* Yams */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 66E09DFC2E7DA3C30082A1B0 /* XCRemoteSwiftPackageReference "Yams.git" */;
|
||||
package = 66E09DFC2E7DA3C30082A1B0 /* XCRemoteSwiftPackageReference "Yams" */;
|
||||
productName = Yams;
|
||||
};
|
||||
66E09E012E7DA4490082A1B0 /* Yams */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 66E09DFC2E7DA3C30082A1B0 /* XCRemoteSwiftPackageReference "Yams.git" */;
|
||||
package = 66E09DFC2E7DA3C30082A1B0 /* XCRemoteSwiftPackageReference "Yams" */;
|
||||
productName = Yams;
|
||||
};
|
||||
66E09E282E7DB0A40082A1B0 /* ProtonCoreCryptoMultiversionPatchedGoImplementation */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 66E09E202E7DAD9F0082A1B0 /* XCRemoteSwiftPackageReference "protoncore_ios.git" */;
|
||||
package = 66E09E202E7DAD9F0082A1B0 /* XCRemoteSwiftPackageReference "protoncore_ios" */;
|
||||
productName = ProtonCoreCryptoMultiversionPatchedGoImplementation;
|
||||
};
|
||||
66E09E2A2E7DB0CA0082A1B0 /* ProtonCoreCryptoMultiversionPatchedGoImplementation */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 66E09E202E7DAD9F0082A1B0 /* XCRemoteSwiftPackageReference "protoncore_ios.git" */;
|
||||
package = 66E09E202E7DAD9F0082A1B0 /* XCRemoteSwiftPackageReference "protoncore_ios" */;
|
||||
productName = ProtonCoreCryptoMultiversionPatchedGoImplementation;
|
||||
};
|
||||
66E09E2C2E7DB0D00082A1B0 /* ProtonCoreCryptoMultiversionPatchedGoImplementation */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 66E09E202E7DAD9F0082A1B0 /* XCRemoteSwiftPackageReference "protoncore_ios.git" */;
|
||||
package = 66E09E202E7DAD9F0082A1B0 /* XCRemoteSwiftPackageReference "protoncore_ios" */;
|
||||
productName = ProtonCoreCryptoMultiversionPatchedGoImplementation;
|
||||
};
|
||||
66E09E2E2E7DB2F60082A1B0 /* ProtonCoreQuarkCommands */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 66E09E202E7DAD9F0082A1B0 /* XCRemoteSwiftPackageReference "protoncore_ios.git" */;
|
||||
package = 66E09E202E7DAD9F0082A1B0 /* XCRemoteSwiftPackageReference "protoncore_ios" */;
|
||||
productName = ProtonCoreQuarkCommands;
|
||||
};
|
||||
66E09E302E7DB2FC0082A1B0 /* ProtonCoreQuarkCommands */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 66E09E202E7DAD9F0082A1B0 /* XCRemoteSwiftPackageReference "protoncore_ios.git" */;
|
||||
package = 66E09E202E7DAD9F0082A1B0 /* XCRemoteSwiftPackageReference "protoncore_ios" */;
|
||||
productName = ProtonCoreQuarkCommands;
|
||||
};
|
||||
66E09E322E7DB3030082A1B0 /* ProtonCoreQuarkCommands */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 66E09E202E7DAD9F0082A1B0 /* XCRemoteSwiftPackageReference "protoncore_ios.git" */;
|
||||
package = 66E09E202E7DAD9F0082A1B0 /* XCRemoteSwiftPackageReference "protoncore_ios" */;
|
||||
productName = ProtonCoreQuarkCommands;
|
||||
};
|
||||
726691C02E9FCACD00796513 /* PDCoreTestingToolkit */ = {
|
||||
@@ -2852,7 +2852,7 @@
|
||||
};
|
||||
D83C419D2C53A233002EF29C /* Sparkle */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = D83C419C2C53A233002EF29C /* XCRemoteSwiftPackageReference "Sparkle.git" */;
|
||||
package = D83C419C2C53A233002EF29C /* XCRemoteSwiftPackageReference "Sparkle" */;
|
||||
productName = Sparkle;
|
||||
};
|
||||
D85AB8362C539D5600FFDC10 /* PDFileProvider */ = {
|
||||
@@ -2913,17 +2913,17 @@
|
||||
};
|
||||
D8AB30DA2C621957006A5F7C /* TrustKit */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = D8AB30D92C621957006A5F7C /* XCRemoteSwiftPackageReference "TrustKit.git" */;
|
||||
package = D8AB30D92C621957006A5F7C /* XCRemoteSwiftPackageReference "TrustKit" */;
|
||||
productName = TrustKit;
|
||||
};
|
||||
D8AB30E12C621A2F006A5F7C /* TrustKit */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = D8AB30D92C621957006A5F7C /* XCRemoteSwiftPackageReference "TrustKit.git" */;
|
||||
package = D8AB30D92C621957006A5F7C /* XCRemoteSwiftPackageReference "TrustKit" */;
|
||||
productName = TrustKit;
|
||||
};
|
||||
D8AB30E42C621ABF006A5F7C /* fusion */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = D8AB30E32C621ABF006A5F7C /* XCRemoteSwiftPackageReference "apple-fusion.git" */;
|
||||
package = D8AB30E32C621ABF006A5F7C /* XCRemoteSwiftPackageReference "apple-fusion" */;
|
||||
productName = fusion;
|
||||
};
|
||||
D8AB30E62C621B7F006A5F7C /* OHHTTPStubs */ = {
|
||||
|
||||
@@ -652,15 +652,13 @@ class AppCoordinator: NSObject, ObservableObject {
|
||||
state: appState,
|
||||
domainOperationsService: domainOperationsService
|
||||
)
|
||||
|
||||
await applicationEventObserver?.startSyncMonitoring(
|
||||
|
||||
await applicationEventObserver?.configurePostLoginServices(
|
||||
syncObserver: syncObserver,
|
||||
globalProgressObserver: globalProgressObserver,
|
||||
sessionVault: postLoginServices.tower.sessionVault
|
||||
)
|
||||
|
||||
applicationEventObserver?.startGeneralSettingsMonitoring(
|
||||
settingsService: postLoginServices.tower.generalSettings
|
||||
sessionVault: postLoginServices.tower.sessionVault,
|
||||
settingsService: postLoginServices.tower.generalSettings,
|
||||
featureFlagsRepository: postLoginServices.tower.featureFlags
|
||||
)
|
||||
|
||||
let hasPlan = initialServices.sessionVault.userInfo?.hasAnySubscription
|
||||
|
||||
@@ -47,6 +47,7 @@ struct PromoCampaignConfiguration {
|
||||
|
||||
fileprivate static let activeCampaigns: [PromoCampaignConfiguration] = [
|
||||
PromoCampaignConfiguration(
|
||||
campaignId: "bf-25-stage-1",
|
||||
timeRange: .limitedTime(
|
||||
start: Date(timeIntervalSinceReferenceDate: 783860400), // 2025-11-03 12:00 CET
|
||||
end: Date(timeIntervalSinceReferenceDate: 785156400) // 2025-11-18 12:00 CET
|
||||
@@ -54,9 +55,11 @@ struct PromoCampaignConfiguration {
|
||||
backgroundColor: Color(hex: "#D8FF00"),
|
||||
tintColor: Color(hex: "#291C5D"),
|
||||
icon: .discount,
|
||||
text: "Black Friday: 50% off"
|
||||
text: "Black Friday: 50% off",
|
||||
resetsPreviousDismissal: false
|
||||
),
|
||||
PromoCampaignConfiguration(
|
||||
campaignId: "bf-25-stage-2",
|
||||
timeRange: .limitedTime(
|
||||
start: Date(timeIntervalSinceReferenceDate: 785156400), // 2025-11-18 12:00 CET
|
||||
end: Date(timeIntervalSinceReferenceDate: 786452400) // 2025-12-03 12:00 CET
|
||||
@@ -64,24 +67,29 @@ struct PromoCampaignConfiguration {
|
||||
backgroundColor: Color(hex: "#D8FF00"),
|
||||
tintColor: Color(hex: "#291C5D"),
|
||||
icon: .discount,
|
||||
text: "Black Friday: 80% off"
|
||||
text: "Black Friday: 80% off",
|
||||
resetsPreviousDismissal: true
|
||||
),
|
||||
PromoCampaignConfiguration(
|
||||
campaignId: "upgrade-drive-plus",
|
||||
timeRange: .indefinite(
|
||||
after: Date(timeIntervalSinceReferenceDate: 786452400) // 2025-12-03 12:00 CET
|
||||
),
|
||||
backgroundColor: ColorProvider.Primary,
|
||||
tintColor: ColorProvider.White,
|
||||
icon: .drivePlus,
|
||||
text: "Upgrade to Drive Plus"
|
||||
text: "Upgrade to Drive Plus",
|
||||
resetsPreviousDismissal: false
|
||||
)
|
||||
]
|
||||
|
||||
let campaignId: String
|
||||
let timeRange: TimeRange
|
||||
let backgroundColor: Color
|
||||
let tintColor: Color
|
||||
let icon: BannerIcon
|
||||
let text: String
|
||||
let resetsPreviousDismissal: Bool
|
||||
}
|
||||
|
||||
protocol PromoCampaignInteractorProtocol {
|
||||
@@ -96,18 +104,19 @@ final class PromoCampaignInteractor: PromoCampaignInteractorProtocol {
|
||||
}
|
||||
|
||||
@SettingsStorage(UserDefaults.PromoCampaign.hasDismissedBanner.rawValue) private var hasDismissedBanner: Bool?
|
||||
@SettingsStorage(UserDefaults.PromoCampaign.lastSeenCampaignId.rawValue) private var lastSeenCampaign: String?
|
||||
|
||||
private var currentlyActiveCampaign = CurrentValueSubject<PromoCampaignConfiguration?, Never>(nil)
|
||||
|
||||
private let dateResource: DateResource
|
||||
|
||||
static let shared = PromoCampaignInteractor()
|
||||
|
||||
init(
|
||||
dateResource: DateResource
|
||||
) {
|
||||
init(dateResource: DateResource) {
|
||||
self.dateResource = dateResource
|
||||
|
||||
_hasDismissedBanner.configure(with: Constants.appGroup)
|
||||
_lastSeenCampaign.configure(with: Constants.appGroup)
|
||||
|
||||
refreshCampaign()
|
||||
}
|
||||
@@ -116,17 +125,18 @@ final class PromoCampaignInteractor: PromoCampaignInteractorProtocol {
|
||||
self.init(dateResource: PromoCampaignDateResource())
|
||||
}
|
||||
|
||||
func refreshCampaign(resetBannerDismissal: Bool = false) {
|
||||
if resetBannerDismissal {
|
||||
func refreshCampaign(forceResetBannerDismissal: Bool = false) {
|
||||
let activeCampaign = getActiveCampaign()
|
||||
|
||||
if forceResetBannerDismissal || shouldResetBannerDismissal(for: activeCampaign) {
|
||||
hasDismissedBanner = false
|
||||
}
|
||||
|
||||
guard (hasDismissedBanner ?? false) == false else {
|
||||
currentlyActiveCampaign.send(.none)
|
||||
return
|
||||
if hasDismissedBanner == true {
|
||||
return currentlyActiveCampaign.send(.none)
|
||||
}
|
||||
|
||||
let activeCampaign = getActiveCampaign()
|
||||
lastSeenCampaign = activeCampaign?.campaignId
|
||||
currentlyActiveCampaign.send(activeCampaign)
|
||||
}
|
||||
|
||||
@@ -149,4 +159,12 @@ final class PromoCampaignInteractor: PromoCampaignInteractorProtocol {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func shouldResetBannerDismissal(for activeCampaign: PromoCampaignConfiguration?) -> Bool {
|
||||
guard let activeCampaign, let lastSeenCampaign, hasDismissedBanner == true else {
|
||||
return false
|
||||
}
|
||||
|
||||
return activeCampaign.resetsPreviousDismissal && activeCampaign.campaignId != lastSeenCampaign
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,5 +20,6 @@ import Foundation
|
||||
extension UserDefaults {
|
||||
enum PromoCampaign: String {
|
||||
case hasDismissedBanner
|
||||
case lastSeenCampaignId
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,9 +198,35 @@ struct QASettingsView: View {
|
||||
exit(0)
|
||||
}
|
||||
|
||||
Text("Unleash FFs — DriveDDKDisabled: \(vm.driveDDKDisabledFeatureFlagValue ? "true" : "false"), DriveDDKIntelEnabled: \(vm.driveDDKIntelEnabledFeatureFlagValue ? "true" : "false") (used on Intel)")
|
||||
Text(
|
||||
[
|
||||
"Unleash FFs — DriveDDKDisabled: \(vm.driveDDKDisabledFeatureFlagValue ? "true" : "false"),",
|
||||
"DriveDDKIntelEnabled: \(vm.driveDDKIntelEnabledFeatureFlagValue ? "true" : "false") (used on Intel),",
|
||||
].joined(separator: "\n")
|
||||
)
|
||||
}
|
||||
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text("BF'25:")
|
||||
.fontWeight(.bold)
|
||||
Picker("", selection: $vm.driveMacPromoBannerDisabled) {
|
||||
ForEach(QASettingsViewModel.FeatureFlagOptions.allCases.map(\.rawValue), id: \.self) {
|
||||
Text($0)
|
||||
}
|
||||
}
|
||||
.pickerStyle(SegmentedPickerStyle())
|
||||
.onChange(of: vm.driveMacPromoBannerDisabled) { _ in
|
||||
exit(0)
|
||||
}
|
||||
Text("Remember, this is a killswitch: enabled means banner should be disabled.")
|
||||
Text(
|
||||
[
|
||||
"Unleash FFs — DriveMacPromoBannerDisabled: \(vm.driveDDKDisabledFeatureFlagValue ? "true" : "false"),",
|
||||
"QA Setting - DriveMacPromoBannerDisabled: \(vm.driveMacPromoBannerDisabledStorage ?? false)"
|
||||
].joined(separator: "\n")
|
||||
)
|
||||
}
|
||||
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text("Disconnect domain:")
|
||||
.fontWeight(.bold)
|
||||
@@ -210,7 +236,7 @@ struct QASettingsView: View {
|
||||
}
|
||||
}
|
||||
.pickerStyle(SegmentedPickerStyle())
|
||||
|
||||
|
||||
Text("Backend feature flag value: \(vm.domainReconnectionFeatureFlagValue ? "true" : "false")")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ struct QASettingsConstants {
|
||||
static let driveDDKEnabledInQASettings = "driveDDKEnabledInQASettings"
|
||||
static let globalProgressStatusMenuEnabled = "globalProgressStatusMenuEnabled"
|
||||
static let overrideDateForPromoCampaign = "overrideDateForPromoCampaign"
|
||||
static let driveMacPromoBannerDisabled = "driveMacPromoBannerDisabled"
|
||||
}
|
||||
|
||||
protocol EventLoopManager: AnyObject {
|
||||
@@ -126,11 +127,23 @@ class QASettingsViewModel: ObservableObject {
|
||||
var driveDDKDisabledFeatureFlagValue: Bool {
|
||||
featureFlags?.isEnabled(flag: .driveDDKDisabled) ?? false
|
||||
}
|
||||
|
||||
@Published var driveDDKEnabled: String = FeatureFlagOptions.useFF.rawValue {
|
||||
didSet { driveDDKEnabledStorage = FeatureFlagOptions(rawValue: driveDDKEnabled)?.toBool }
|
||||
}
|
||||
|
||||
@SettingsStorage(QASettingsConstants.driveDDKEnabledInQASettings) var driveDDKEnabledStorage: Bool?
|
||||
|
||||
var driveMacPromoBannerDisabledFeatureFlagValue: Bool {
|
||||
featureFlags?.isEnabled(flag: .driveMacPromoBannerDisabled) ?? false
|
||||
}
|
||||
|
||||
@Published var driveMacPromoBannerDisabled: String = FeatureFlagOptions.useFF.rawValue {
|
||||
didSet { driveMacPromoBannerDisabledStorage = FeatureFlagOptions(rawValue: driveMacPromoBannerDisabled)?.toBool }
|
||||
}
|
||||
|
||||
@SettingsStorage(QASettingsConstants.driveMacPromoBannerDisabled) var driveMacPromoBannerDisabledStorage: Bool?
|
||||
|
||||
@Published var overrideDateForPromoCampaign: String = "" {
|
||||
didSet { overrideDateForPromoCampaignStorage = overrideDateForPromoCampaign }
|
||||
}
|
||||
@@ -175,6 +188,7 @@ class QASettingsViewModel: ObservableObject {
|
||||
self._requiresPostMigrationCleanup.configure(with: suite)
|
||||
self._disconnectDomainOnSignOutStorage.configure(with: suite)
|
||||
self._driveDDKEnabledStorage.configure(with: suite)
|
||||
self._driveMacPromoBannerDisabledStorage.configure(with: suite)
|
||||
|
||||
self.dumper = dumperDependencies.map(Dumper.init)
|
||||
self.environment = Constants.appGroup.userDefaults.string(forKey: Constants.SettingsBundleKeys.host.rawValue) ?? ""
|
||||
@@ -203,6 +217,7 @@ class QASettingsViewModel: ObservableObject {
|
||||
self.enablePostMigrationCleanup = requiresPostMigrationCleanup ?? false
|
||||
self.disconnectDomainOnSignOut = FeatureFlagOptions(bool: disconnectDomainOnSignOutStorage).rawValue
|
||||
self.driveDDKEnabled = FeatureFlagOptions(bool: driveDDKEnabledStorage).rawValue
|
||||
self.driveMacPromoBannerDisabled = FeatureFlagOptions(bool: driveMacPromoBannerDisabledStorage).rawValue
|
||||
|
||||
self.promoCampaignInteractor.activeCampaign.sink { activeCampaign in
|
||||
self.activeCampaign = activeCampaign
|
||||
@@ -497,7 +512,7 @@ class QASettingsViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
func refreshPromoCampaign() {
|
||||
self.promoCampaignInteractor.refreshCampaign(resetBannerDismissal: true)
|
||||
self.promoCampaignInteractor.refreshCampaign(forceResetBannerDismissal: true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ class ApplicationEventObserver: ObservableObject {
|
||||
#if HAS_QA_FEATURES
|
||||
@Published private(set) var state: ApplicationState
|
||||
@Published var syncItemHistory = [SyncHistoryItem]()
|
||||
@SettingsStorage(QASettingsConstants.driveMacPromoBannerDisabled) var hasPromoBannerDisabledInQASettings: Bool?
|
||||
|
||||
/// Counts how many times the application state is updated, to enable detecting when it happens too much.
|
||||
static var updateCounter = 0
|
||||
@@ -71,6 +72,9 @@ class ApplicationEventObserver: ObservableObject {
|
||||
/// Fires every `ElapsedTimeService.timeInterval` seconds, only the dropdown Menu or Status Window are opened.
|
||||
private var elapsedTimeService: ElapsedTimeService?
|
||||
|
||||
/// Fires whenever there's a change to feature flags for the user
|
||||
private var featureFlagsRepository: FeatureFlagsRepository?
|
||||
|
||||
/// Fires whenever there's a change to active promo campaigns for the user.
|
||||
private var promoCampaignInteractor: PromoCampaignInteractorProtocol?
|
||||
|
||||
@@ -99,6 +103,10 @@ class ApplicationEventObserver: ObservableObject {
|
||||
|
||||
self.deleteAlerter = DeleteAlerter()
|
||||
|
||||
#if HAS_QA_FEATURES
|
||||
self._hasPromoBannerDisabledInQASettings.configure(with: Constants.appGroup)
|
||||
#endif
|
||||
|
||||
setUpObservers()
|
||||
}
|
||||
|
||||
@@ -109,9 +117,19 @@ class ApplicationEventObserver: ObservableObject {
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
public func startSyncMonitoring(syncObserver: SyncDBObserver,
|
||||
globalProgressObserver: GlobalProgressObserver?,
|
||||
sessionVault: SessionVault?) async {
|
||||
/// Some Drive services are only available after user is logged in,
|
||||
/// such as the session vault, general settings and feature flags.
|
||||
///
|
||||
/// This function provides a convenient place to configure observation
|
||||
/// of these services. It's expected that any service with long running
|
||||
/// observations are cancelled in `stopMonitoring` as needed.
|
||||
public func configurePostLoginServices(
|
||||
syncObserver: SyncDBObserver,
|
||||
globalProgressObserver: GlobalProgressObserver?,
|
||||
sessionVault: SessionVault?,
|
||||
settingsService: GeneralSettings?,
|
||||
featureFlagsRepository: FeatureFlagsRepository?
|
||||
) async {
|
||||
Log.trace()
|
||||
|
||||
self.syncObserver = syncObserver
|
||||
@@ -126,10 +144,6 @@ class ApplicationEventObserver: ObservableObject {
|
||||
|
||||
self.subscribetoLogin()
|
||||
self.subscribetoUserInfo()
|
||||
}
|
||||
|
||||
public func startGeneralSettingsMonitoring(settingsService: GeneralSettings) {
|
||||
Log.trace()
|
||||
|
||||
generalSettingsService = settingsService
|
||||
generalSettingsService?.fetchUserSettings()
|
||||
@@ -140,6 +154,8 @@ class ApplicationEventObserver: ObservableObject {
|
||||
self?.state.setUserSettings(userSettings)
|
||||
}
|
||||
.store(in: &userCancellables)
|
||||
|
||||
self.featureFlagsRepository = featureFlagsRepository
|
||||
}
|
||||
|
||||
/// - Parameters:
|
||||
@@ -151,8 +167,12 @@ class ApplicationEventObserver: ObservableObject {
|
||||
self.globalProgressObserver = nil
|
||||
self.elapsedTimeService = nil
|
||||
self.sessionVault = nil
|
||||
self.generalSettingsService = nil
|
||||
self.featureFlagsRepository = nil
|
||||
self.userCancellables.removeAll()
|
||||
|
||||
didReceiveLogoutState(isSignedIn: false)
|
||||
|
||||
if !dueToSignOut {
|
||||
self.globalCancellables.removeAll()
|
||||
}
|
||||
@@ -344,9 +364,25 @@ class ApplicationEventObserver: ObservableObject {
|
||||
)
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] campaign, userInfo, userSettings in
|
||||
guard let self, let featureFlagsRepository else {
|
||||
return
|
||||
}
|
||||
|
||||
guard !featureFlagsRepository.isEnabled(flag: .driveMacPromoBannerDisabled) else {
|
||||
Log.trace("Promo campaign filtered out because killswitch is active")
|
||||
return self.state.setVisibleCampaign(nil)
|
||||
}
|
||||
|
||||
#if HAS_QA_FEATURES
|
||||
if hasPromoBannerDisabledInQASettings == true {
|
||||
Log.trace("Promo campaign filtered out because it's disabled in QA settings")
|
||||
return self.state.setVisibleCampaign(nil)
|
||||
}
|
||||
#endif
|
||||
|
||||
guard let userInfo, let userSettings else {
|
||||
Log.trace("Promo campaign filtered out because user info or settings aren't available yet")
|
||||
self?.state.setVisibleCampaign(.none)
|
||||
self.state.setVisibleCampaign(.none)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -359,11 +395,11 @@ class ApplicationEventObserver: ObservableObject {
|
||||
// * Users who disabled in-app notifications
|
||||
if userInfo.isDelinquent || userInfo.isPaid || !userHasInAppNotificationsEnabled {
|
||||
Log.trace("Promo campaign filtered out because user is not in the target audience")
|
||||
self?.state.setVisibleCampaign(.none)
|
||||
self.state.setVisibleCampaign(.none)
|
||||
return
|
||||
}
|
||||
|
||||
self?.state.setVisibleCampaign(campaign)
|
||||
self.state.setVisibleCampaign(campaign)
|
||||
}
|
||||
.store(in: &userCancellables)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
<div>
|
||||
<h1>2.10.1</h1>
|
||||
|
||||
<p>
|
||||
- Fixes a rare crash encountered when uploading or downloading many files<br>
|
||||
</p>
|
||||
|
||||
<h1>2.10.0</h1>
|
||||
|
||||
<p>
|
||||
|
||||
Reference in New Issue
Block a user