From 80f16dd4ef90aab509ba6777f6f3253c76269dfe Mon Sep 17 00:00:00 2001 From: Priyonto M Rahman Date: Tue, 2 Jul 2024 22:16:29 +0200 Subject: [PATCH] task: Add a separate consent checkbox for firebase analytics #2022 --- .../Analytics/RuuviAnalyticsImpl.swift | 9 ++- .../Classes/Application/AppDelegate.swift | 2 + .../Sources/Classes/Routers/AppRouter.swift | 14 ++++- .../Classes/Routers/OnboardRouter.swift | 22 +++++++- .../Pages/RuuviOnboardPages.swift | 23 +++++++- .../Pages/RuuviOnboardSignInCell.swift | 55 +++++++++++++++++-- .../Pages/RuuviOnboardViewCheckboxView.swift | 6 +- .../Pages/RuuviOnboardViewController.swift | 35 ++++++++++-- .../Sources/RuuviOnboard/RuuviOnboard.swift | 4 ++ .../RuuviAnalytics/RuuviAnalytics.swift | 1 + .../RuuviLocal/RuuviLocalSettings.swift | 1 + .../RuuviLocalSettingsUserDefaults.swift | 3 + station.localization | 2 +- 13 files changed, 160 insertions(+), 17 deletions(-) diff --git a/Apps/RuuviStation/Sources/Classes/Analytics/RuuviAnalyticsImpl.swift b/Apps/RuuviStation/Sources/Classes/Analytics/RuuviAnalyticsImpl.swift index e865d71ae..4e742ea8f 100644 --- a/Apps/RuuviStation/Sources/Classes/Analytics/RuuviAnalyticsImpl.swift +++ b/Apps/RuuviStation/Sources/Classes/Analytics/RuuviAnalyticsImpl.swift @@ -135,7 +135,6 @@ public final class RuuviAnalyticsImpl: RuuviAnalytics { self.ruuviStorage = ruuviStorage self.settings = settings self.alertService = alertService - self.setConsentSettings() } public func update() { @@ -187,6 +186,10 @@ public final class RuuviAnalyticsImpl: RuuviAnalytics { set(.alertRSSI(0)) } + public func setConsent(allowed: Bool) { + setConsentSettings(allowed: allowed) + } + private func set(_ property: Properties) { let value: String = switch property { case let .loggedIn(isLoggedIn): @@ -276,12 +279,12 @@ public final class RuuviAnalyticsImpl: RuuviAnalytics { return (temperatureAlertCount, humidityAlertCount, pressureAlertCount, movementAlertCount) } - private func setConsentSettings() { + private func setConsentSettings(allowed: Bool) { let consentSettings: [ConsentType: ConsentStatus] = [ .adStorage: .denied, .adUserData: .denied, .adPersonalization: .denied, - .analyticsStorage: .granted, + .analyticsStorage: allowed ? .granted : .denied, ] #if DEBUG || ALPHA // skip using analytics diff --git a/Apps/RuuviStation/Sources/Classes/Application/AppDelegate.swift b/Apps/RuuviStation/Sources/Classes/Application/AppDelegate.swift index 9bc43751a..943042f13 100644 --- a/Apps/RuuviStation/Sources/Classes/Application/AppDelegate.swift +++ b/Apps/RuuviStation/Sources/Classes/Application/AppDelegate.swift @@ -6,6 +6,7 @@ import UIKit #if (DEBUG || ALPHA) && canImport(FLEX) import FLEX #endif +import RuuviAnalytics import RuuviContext import RuuviCore import RuuviLocal @@ -80,6 +81,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { window = UIWindow(frame: UIScreen.main.bounds) let appRouter = AppRouter() appRouter.settings = r.resolve(RuuviLocalSettings.self) + appRouter.ruuviAnalytics = r.resolve(RuuviAnalytics.self) window?.rootViewController = appRouter.viewController window?.makeKeyAndVisible() self.appRouter = appRouter diff --git a/Apps/RuuviStation/Sources/Classes/Routers/AppRouter.swift b/Apps/RuuviStation/Sources/Classes/Routers/AppRouter.swift index 99e705f85..ddde027e9 100644 --- a/Apps/RuuviStation/Sources/Classes/Routers/AppRouter.swift +++ b/Apps/RuuviStation/Sources/Classes/Routers/AppRouter.swift @@ -1,4 +1,5 @@ import LightRoute +import RuuviAnalytics import RuuviLocal import RuuviOntology import RuuviUser @@ -10,6 +11,7 @@ final class AppRouter { } var settings: RuuviLocalSettings! + var ruuviAnalytics: RuuviAnalytics! // navigation controller private var navigationController: UINavigationController { @@ -17,7 +19,7 @@ final class AppRouter { return navigationController } else { let rootViewController: UIViewController - if settings.welcomeShown && settings.tosAccepted { + if settings.welcomeShown && settings.tosAccepted && settings.analyticsConsentGiven { let controller = dashboardViewController() rootViewController = controller } else { @@ -121,9 +123,19 @@ extension AppRouter: OnboardRouterDelegate { }) } + func ruuviOnboardDidProvideAnalyticsConsent( + _ router: OnboardRouter, + consentGiven: Bool + ) { + ruuviAnalytics.setConsent( + allowed: consentGiven + ) + } + private func presentDashboard() { settings.welcomeShown = true settings.tosAccepted = true + settings.analyticsConsentGiven = true AppUtility.lockOrientation(.all) let controller = dashboardViewController() navigationController.setNavigationBarHidden(false, animated: false) diff --git a/Apps/RuuviStation/Sources/Classes/Routers/OnboardRouter.swift b/Apps/RuuviStation/Sources/Classes/Routers/OnboardRouter.swift index 4a0bee7f7..968bc2929 100644 --- a/Apps/RuuviStation/Sources/Classes/Routers/OnboardRouter.swift +++ b/Apps/RuuviStation/Sources/Classes/Routers/OnboardRouter.swift @@ -1,3 +1,4 @@ +import RuuviLocal import RuuviOnboard import RuuviUser import UIKit @@ -13,6 +14,10 @@ protocol OnboardRouterDelegate: AnyObject { _ router: OnboardRouter, output: SignInBenefitsModuleOutput ) + func ruuviOnboardDidProvideAnalyticsConsent( + _ router: OnboardRouter, + consentGiven: Bool + ) } final class OnboardRouter { @@ -28,7 +33,12 @@ final class OnboardRouter { return onboard } else { let ruuviUser = r.resolve(RuuviUser.self)! - let onboard = RuuviOnboardPages(ruuviUser: ruuviUser) + let settings = r.resolve(RuuviLocalSettings.self)! + let onboard = RuuviOnboardPages( + ruuviUser: ruuviUser, + tosAccepted: settings.tosAccepted, + analyticsConsentGiven: settings.analyticsConsentGiven + ) onboard.router = self onboard.output = self weakOnboard = onboard @@ -47,6 +57,16 @@ extension OnboardRouter: RuuviOnboardOutput { func ruuviOnboardDidShowSignIn(_: RuuviOnboard) { delegate?.onboardRouterDidShowSignIn(self, output: self) } + + func ruuviOnboardDidProvideAnalyticsConsent( + _ ruuviOnboard: RuuviOnboard, + consentGiven: Bool + ) { + delegate?.ruuviOnboardDidProvideAnalyticsConsent( + self, + consentGiven: consentGiven + ) + } } extension OnboardRouter: SignInBenefitsModuleOutput { diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardPages.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardPages.swift index 1df5cb0bc..fc683b11a 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardPages.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardPages.swift @@ -12,15 +12,25 @@ public final class RuuviOnboardPages: RuuviOnboard { let view = RuuviOnboardViewController() view.output = self view.ruuviUser = ruuviUser + view.tosAccepted = tosAccepted + view.analyticsConsentGiven = analyticsConsentGiven weakView = view return view } } private let ruuviUser: RuuviUser + private var tosAccepted: Bool + private var analyticsConsentGiven: Bool - public init(ruuviUser: RuuviUser) { + public init( + ruuviUser: RuuviUser, + tosAccepted: Bool, + analyticsConsentGiven: Bool + ) { self.ruuviUser = ruuviUser + self.tosAccepted = tosAccepted + self.analyticsConsentGiven = analyticsConsentGiven } private weak var weakView: UIViewController? @@ -40,4 +50,15 @@ extension RuuviOnboardPages: RuuviOnboardViewControllerOutput { ) { output?.ruuviOnboardDidShowSignIn(self) } + + func ruuviOnboardAnalytics( + _ viewController: RuuviOnboardViewController, + didProvideAnalyticsConsent isConsentGiven: Bool, + sender: Any? + ) { + output?.ruuviOnboardDidProvideAnalyticsConsent( + self, + consentGiven: isConsentGiven + ) + } } diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardSignInCell.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardSignInCell.swift index 2fbc499cd..9878a1694 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardSignInCell.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardSignInCell.swift @@ -3,6 +3,10 @@ import UIKit protocol RuuviOnboardSignInCellDelegate: NSObjectProtocol { func didTapContinueButton(sender: RuuviOnboardSignInCell) + func didProvideAnalyticsConsent( + isConsentGiven: Bool, + sender: RuuviOnboardSignInCell + ) } class RuuviOnboardSignInCell: UICollectionViewCell { @@ -41,6 +45,12 @@ class RuuviOnboardSignInCell: UICollectionViewCell { return provider }() + private lazy var analyticsCheckbox: RuuviOnboardCheckboxProvider = { + let provider = RuuviOnboardCheckboxProvider() + provider.delegate = self + return provider + }() + private lazy var continueButton: UIButton = { let button = UIButton(color: RuuviColor.tintColor.color, cornerRadius: 22) button.setTitle( @@ -118,9 +128,30 @@ private extension RuuviOnboardSignInCell { ) ) + let analyticsCheckboxVC = analyticsCheckbox.makeViewController( + title: RuuviLocalization.onboardingStartAnonymousDataCollectionTitle, + titleMarkupString: "", + titleLink: "" + ) + analyticsCheckboxVC.view.backgroundColor = .clear + container.addSubview(analyticsCheckboxVC.view) + + analyticsCheckboxVC.view.anchor( + top: tosCheckboxVC.view.bottomAnchor, + leading: container.safeLeadingAnchor, + bottom: nil, + trailing: container.safeTrailingAnchor, + padding: .init( + top: 8, + left: 16, + bottom: 0, + right: 16 + ) + ) + container.addSubview(continueButton) continueButton.anchor( - top: tosCheckboxVC.view.bottomAnchor, + top: analyticsCheckboxVC.view.bottomAnchor, leading: nil, bottom: nil, trailing: nil, @@ -173,10 +204,16 @@ private extension RuuviOnboardSignInCell { // MARK: - Public extension RuuviOnboardSignInCell { - func configure(with viewModel: OnboardViewModel) { + func configure( + with viewModel: OnboardViewModel, + tosAccepted: Bool, + analyticsConsentGiven: Bool + ) { titleLabel.text = viewModel.title subtitleLabel.text = viewModel.subtitle - setContinueButtonEnabled(false) + tosCheckbox.setChecked(tosAccepted) + analyticsCheckbox.setChecked(analyticsConsentGiven) + setContinueButtonEnabled(tosAccepted) } } @@ -186,6 +223,16 @@ extension RuuviOnboardSignInCell: RuuviOnboardCheckboxViewDelegate { isChecked: Bool, sender: RuuviOnboardCheckboxProvider ) { - setContinueButtonEnabled(isChecked, animated: true) + if sender == tosCheckbox { + setContinueButtonEnabled( + isChecked, + animated: true + ) + } else if sender == analyticsCheckbox { + delegate?.didProvideAnalyticsConsent( + isConsentGiven: isChecked, + sender: self + ) + } } } diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewCheckboxView.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewCheckboxView.swift index c06877fd5..9c8563273 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewCheckboxView.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewCheckboxView.swift @@ -47,6 +47,10 @@ public class RuuviOnboardCheckboxProvider: NSObject { ) } + public func setChecked(_ isChecked: Bool) { + stateHolder.isChecked = isChecked + } + // MARK: - Private private func setupSubscriptions() { stateHolder.$isChecked @@ -92,7 +96,7 @@ struct RuuviOnboardViewCheckboxView: View { } } .toggleStyle(CheckboxToggleStyle()) - .padding(.vertical) + .padding(.vertical, 4) } struct TitleView: UIViewRepresentable { diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewController.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewController.swift index 71dde4abc..26ef34311 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewController.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewController.swift @@ -13,6 +13,11 @@ protocol RuuviOnboardViewControllerOutput: AnyObject { _ viewController: RuuviOnboardViewController, didPresentSignIn sender: Any? ) + func ruuviOnboardAnalytics( + _ viewController: RuuviOnboardViewController, + didProvideAnalyticsConsent isConsentGiven: Bool, + sender: Any? + ) } enum OnboardPageType: Int { @@ -30,7 +35,7 @@ enum OnboardPageType: Int { struct OnboardViewModel { var pageType: OnboardPageType var title: String - var subtitle: String + var subtitle: String? var sub_subtitle: String? var image: UIImage? } @@ -38,6 +43,8 @@ struct OnboardViewModel { class RuuviOnboardViewController: UIViewController { var output: RuuviOnboardViewControllerOutput? var ruuviUser: RuuviUser? + var tosAccepted: Bool = false + var analyticsConsentGiven: Bool = false init() { super.init(nibName: nil, bundle: nil) @@ -102,6 +109,9 @@ class RuuviOnboardViewController: UIViewController { didSet { pageControl.numberOfPages = viewModels.count collectionView.reloadData() + if tosAccepted && !analyticsConsentGiven { + scrollToLast() + } } } @@ -141,6 +151,8 @@ extension RuuviOnboardViewController { } private func scrollToLast() { + collectionView.layoutIfNeeded() + guard collectionView.numberOfItems(inSection: 0) > 0 else { return } let lastPageIndex = viewModels.count - 1 currentPage = lastPageIndex pageControl.currentPage = lastPageIndex @@ -257,7 +269,11 @@ extension RuuviOnboardViewController { for: indexPath ) as? RuuviOnboardSignInCell cell?.delegate = self - cell?.configure(with: viewModel) + cell?.configure( + with: viewModel, + tosAccepted: tosAccepted, + analyticsConsentGiven: analyticsConsentGiven + ) return cell } } @@ -271,6 +287,17 @@ extension RuuviOnboardViewController: RuuviOnboardSignInCellDelegate { output?.ruuviOnboardCloudSignIn(self, didPresentSignIn: nil) } } + + func didProvideAnalyticsConsent( + isConsentGiven: Bool, + sender: RuuviOnboardSignInCell + ) { + output?.ruuviOnboardAnalytics( + self, + didProvideAnalyticsConsent: isConsentGiven, + sender: nil + ) + } } extension RuuviOnboardViewController { @@ -428,9 +455,7 @@ private extension RuuviOnboardViewController { title: isUserAuthorized() ? RuuviLocalization.onboardingThatsItAlreadySignedIn : RuuviLocalization.onboardingThatsIt, - subtitle: isUserAuthorized() ? - RuuviLocalization.onboardingGoToSignInAlreadySignedIn : - RuuviLocalization.onboardingGoToSignIn + subtitle: nil ) return [ diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/RuuviOnboard.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/RuuviOnboard.swift index 1336e51fa..b62a4d3e6 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/RuuviOnboard.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/RuuviOnboard.swift @@ -8,4 +8,8 @@ public protocol RuuviOnboard: AnyObject { public protocol RuuviOnboardOutput: AnyObject { func ruuviOnboardDidFinish(_ ruuviOnboard: RuuviOnboard) func ruuviOnboardDidShowSignIn(_ ruuviOnboard: RuuviOnboard) + func ruuviOnboardDidProvideAnalyticsConsent( + _ ruuviOnboard: RuuviOnboard, + consentGiven: Bool + ) } diff --git a/Packages/RuuviAnalytics/Sources/RuuviAnalytics/RuuviAnalytics.swift b/Packages/RuuviAnalytics/Sources/RuuviAnalytics/RuuviAnalytics.swift index b384d5430..efb0a3afc 100644 --- a/Packages/RuuviAnalytics/Sources/RuuviAnalytics/RuuviAnalytics.swift +++ b/Packages/RuuviAnalytics/Sources/RuuviAnalytics/RuuviAnalytics.swift @@ -1,3 +1,4 @@ public protocol RuuviAnalytics { func update() + func setConsent(allowed: Bool) } diff --git a/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalSettings.swift b/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalSettings.swift index 3018f4cb4..6a9c3be6c 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalSettings.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalSettings.swift @@ -52,6 +52,7 @@ public protocol RuuviLocalSettings { var pressureAccuracy: MeasurementAccuracyType { get set } var welcomeShown: Bool { get set } var tosAccepted: Bool { get set } + var analyticsConsentGiven: Bool { get set } var tagChartsLandscapeSwipeInstructionWasShown: Bool { get set } var language: Language { get set } var cloudProfileLanguageCode: String? { get set } diff --git a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift index 960f57761..ce01afc6c 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift @@ -248,6 +248,9 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { @UserDefault("SettingsUserDefaults.tosAccepted", defaultValue: false) var tosAccepted: Bool + @UserDefault("SettingsUserDefaults.analyticsConsentGiven", defaultValue: false) + var analyticsConsentGiven: Bool + @UserDefault("SettingsUserDegaults.tagChartsLandscapeSwipeInstructionWasShown", defaultValue: false) var tagChartsLandscapeSwipeInstructionWasShown: Bool diff --git a/station.localization b/station.localization index 95f714700..59b525077 160000 --- a/station.localization +++ b/station.localization @@ -1 +1 @@ -Subproject commit 95f71470080fb2b0a0a996dccc13e8335850f9c3 +Subproject commit 59b5250774102c4af1103331d564c3f84fc0f891