Skip to content

Commit

Permalink
[DIA-2937] special feature toggle tvos (#517)
Browse files Browse the repository at this point in the history
* [DIA-2937] Saving `specialFeatures`

* [DIA-2937] Add toggle logic for `specialFeatures`

* [DIA-2937] Add `specialFeatures` on `ManagePreferenceView`

* [DIA-2937] Test fix

* [DIA-2937] Test fix

* [DIA-2937] Short notation and remove inherit from `Int`

* [DIA-2937] lint fix
  • Loading branch information
Nevazhnovu authored Nov 15, 2023
1 parent 0438baa commit 9ffbafe
Show file tree
Hide file tree
Showing 14 changed files with 95 additions and 31 deletions.
3 changes: 3 additions & 0 deletions ConsentViewController/Classes/Consents/SPGDPRConsent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ public typealias SPGDPRPurposeId = String
case legIntVendors
case vendors
case categories
case specialFeatures
case dateCreated
case expirationDate
}
Expand Down Expand Up @@ -145,6 +146,7 @@ public typealias SPGDPRPurposeId = String
var legIntVendors: [String]?
var vendors: [String]?
var categories: [String]?
var specialFeatures: [String]?

override open var description: String {
"""
Expand All @@ -170,6 +172,7 @@ public typealias SPGDPRPurposeId = String
legIntVendors = try container.decodeIfPresent(Array.self, forKey: .legIntVendors)
vendors = try container.decodeIfPresent(Array.self, forKey: .vendors)
categories = try container.decodeIfPresent(Array.self, forKey: .categories)
specialFeatures = try container.decodeIfPresent(Array.self, forKey: .specialFeatures)
expirationDate = try container.decode(SPDate.self, forKey: .expirationDate)
if let date = try container.decodeIfPresent(SPDate.self, forKey: .dateCreated) {
dateCreated = date
Expand Down
1 change: 1 addition & 0 deletions ConsentViewController/Classes/SPConsentManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,7 @@ extension SPConsentManager: SPNativePMDelegate {
pmData.legIntVendors = self?.userData.gdpr?.consents?.legIntVendors ?? []
pmData.acceptedVendors = self?.userData.gdpr?.consents?.vendors ?? []
pmData.acceptedCategories = self?.userData.gdpr?.consents?.categories ?? []
pmData.acceptedSpecialFeatures = self?.userData.gdpr?.consents?.specialFeatures ?? []
pmData.hasConsentData = self?.userData.gdpr?.consents?.consentStatus.hasConsentData
handler(result.map { _ in pmData })
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ struct ChoiceAllResponse: Decodable {
let legIntVendors: [String]?
let vendors: [String]?
let categories: [String]?
let specialFeatures: [String]?
}

let gdpr: GDPR?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ struct GDPRChoiceResponse: Decodable, Equatable {
let legIntVendors: [String]?
let vendors: [String]?
let categories: [String]?
let specialFeatures: [String]?
}

struct CCPAChoiceResponse: Equatable {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ struct ConsentStatusResponse: Decodable, Equatable {
let legIntVendors: [String]
let vendors: [String]
let categories: [String]
let specialFeatures: [String]
}

struct CCPA: Decodable, Equatable {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ struct GDPRPrivacyManagerViewResponse: Decodable {
let vendors: [GDPRVendor]
let categories, specialPurposes, features, specialFeatures: [GDPRCategory]
var grants: SPGDPRVendorGrants?
var legIntCategories, legIntVendors, acceptedVendors, acceptedCategories: [String]?
var legIntCategories, legIntVendors, acceptedVendors, acceptedCategories, acceptedSpecialFeatures: [String]?
var hasConsentData: Bool?
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,7 @@ class SourcepointClientCoordinator: SPClientCoordinator {
state.gdpr?.legIntVendors = gdpr.legIntVendors
state.gdpr?.vendors = gdpr.vendors
state.gdpr?.categories = gdpr.categories
state.gdpr?.specialFeatures = gdpr.specialFeatures
}
if let ccpa = response.consentStatusData.ccpa {
state.ccpa?.uuid = ccpa.uuid
Expand Down Expand Up @@ -735,6 +736,7 @@ class SourcepointClientCoordinator: SPClientCoordinator {
state.gdpr?.legIntVendors = postResponse.legIntVendors ?? getResponse?.gdpr?.legIntVendors
state.gdpr?.vendors = postResponse.vendors ?? getResponse?.gdpr?.vendors
state.gdpr?.categories = postResponse.categories ?? getResponse?.gdpr?.categories
state.gdpr?.specialFeatures = postResponse.specialFeatures ?? getResponse?.gdpr?.specialFeatures
storage.spState = state
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class LongButtonViewCell: UITableViewCell {
var customText: String?
var selectable = false
var identifier: String = ""
var contentType: CategoryContentType?

@IBOutlet var label: UILabel!
@IBOutlet var customLabel: UILabel!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ protocol ConsentSnapshot {
func toPayload(language: SPMessageLanguage, pmId: String) -> JSONAble
}

public enum CategoryContentType {
case consent
case legitimate
case specialFeatures
}

class GDPRPMConsentSnaptshot: NSObject, ConsentSnapshot, PMVendorManager, PMCategoryManager {
typealias VendorType = GDPRVendor
typealias CategoryType = GDPRCategory
Expand All @@ -26,6 +32,7 @@ class GDPRPMConsentSnaptshot: NSObject, ConsentSnapshot, PMVendorManager, PMCate
var toggledCategoriesIds: Set<String>
var toggledConsentCategoriesIds: Set<String>
var toggledLICategoriesIds: Set<String>
var toggledSpecialFeatures: Set<String>

var consentVendorsWhosePurposesAreOff: [String] {
toggledConsentVendorsIds
Expand Down Expand Up @@ -78,6 +85,7 @@ class GDPRPMConsentSnaptshot: NSObject, ConsentSnapshot, PMVendorManager, PMCate
toggledLIVendorsIds = Set<String>([])
toggledConsentCategoriesIds = Set<String>([])
toggledLICategoriesIds = Set<String>([])
toggledSpecialFeatures = Set<String>([])
}

convenience init(
Expand All @@ -86,6 +94,7 @@ class GDPRPMConsentSnaptshot: NSObject, ConsentSnapshot, PMVendorManager, PMCate
legIntVendors: [String]?,
acceptedVendors: [String]?,
acceptedCategories: [String]?,
acceptedSpecialFeatures: [String]?,
hasConsentData: Bool,
vendors: Set<GDPRVendor>,
categories: Set<GDPRCategory>,
Expand All @@ -103,6 +112,7 @@ class GDPRPMConsentSnaptshot: NSObject, ConsentSnapshot, PMVendorManager, PMCate
)
toggledVendorsIds.formUnion(acceptedVendors ?? [])
toggledCategoriesIds.formUnion(acceptedCategories ?? [])
toggledSpecialFeatures.formUnion(acceptedSpecialFeatures ?? [])
if hasConsentData {
toggledConsentVendorsIds = Set<String>(acceptedVendors ?? [])
toggledLIVendorsIds = Set<String>(legIntVendors ?? [])
Expand All @@ -124,6 +134,7 @@ class GDPRPMConsentSnaptshot: NSObject, ConsentSnapshot, PMVendorManager, PMCate
toggledCategoriesIds = []
toggledConsentCategoriesIds = []
toggledLICategoriesIds = []
toggledSpecialFeatures = []
vendors = []
categories = []
specialPurposes = []
Expand All @@ -136,7 +147,7 @@ class GDPRPMConsentSnaptshot: NSObject, ConsentSnapshot, PMVendorManager, PMCate
lan: language,
privacyManagerId: pmId,
categories: toggledCategoriesIds.compactMap { id in
guard let category = categories.first(where: { c in c._id == id }) else { return nil }
guard let category = categories.first(where: { $0._id == id }) else { return nil }
return GDPRPMPayload.Category(
_id: id,
iabId: category.iabId,
Expand All @@ -146,14 +157,21 @@ class GDPRPMConsentSnaptshot: NSObject, ConsentSnapshot, PMVendorManager, PMCate
)
},
vendors: toggledVendorsIds.compactMap { id in
guard let vendor = vendors.first(where: { v in v.vendorId == id }) else { return nil }
guard let vendor = vendors.first(where: { $0.vendorId == id }) else { return nil }
return GDPRPMPayload.Vendor(
_id: id,
iabId: vendor.iabId,
consent: toggledConsentVendorsIds.contains(id),
legInt: toggledLIVendorsIds.contains(id),
vendorType: vendor.vendorType
)
},
specialFeatures: toggledSpecialFeatures.compactMap { id in
guard let feature = specialFeatures.first(where: { $0._id == id }) else { return nil }
return GDPRPMPayload.Feature(
_id: id,
iabId: feature.iabId
)
}
)
}
Expand All @@ -166,26 +184,44 @@ class GDPRPMConsentSnaptshot: NSObject, ConsentSnapshot, PMVendorManager, PMCate

func onVendorOff(_ vendor: GDPRVendor) {}

func onCategoryOn(category: GDPRCategory, legInt: Bool) {
if legInt {
toggledLICategoriesIds.insert(category._id)
toggledLIVendorsIds.formUnion(category.uniqueLIVendorIds)
} else {
func onCategoryOn(category: GDPRCategory, type: CategoryContentType?) {
switch type {
case .consent:
toggledConsentCategoriesIds.insert(category._id)
toggledConsentVendorsIds.formUnion(category.uniqueConsentVendorIds)

case .legitimate:
toggledLICategoriesIds.insert(category._id)
toggledLIVendorsIds.formUnion(category.uniqueLIVendorIds)

case .specialFeatures:
toggledSpecialFeatures.insert(category._id)

case .none:
break
}
if type != .specialFeatures {
toggledCategoriesIds.insert(category._id)
toggledVendorsIds.formUnion(category.uniqueVendorIds)
}
toggledCategoriesIds.insert(category._id)
toggledVendorsIds.formUnion(category.uniqueVendorIds)
onConsentsChange()
}

func onCategoryOff(category: GDPRCategory, legInt: Bool) {
if legInt {
toggledLICategoriesIds.remove(category._id)
toggledLIVendorsIds.subtract(liVendorsWhosePurposesAreOff)
} else {
func onCategoryOff(category: GDPRCategory, type: CategoryContentType?) {
switch type {
case .consent:
toggledConsentCategoriesIds.remove(category._id)
toggledConsentVendorsIds.subtract(consentVendorsWhosePurposesAreOff)

case .legitimate:
toggledLICategoriesIds.remove(category._id)
toggledLIVendorsIds.subtract(liVendorsWhosePurposesAreOff)

case .specialFeatures:
toggledSpecialFeatures.remove(category._id)

case .none:
break
}
onConsentsChange()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ class SPGDPRCategoryDetailsViewController: SPNativeScreenViewController {
weak var categoryManagerDelegate: GDPRPMConsentSnaptshot?

var category: GDPRCategory?
var displayingLegIntCategories = false
var categoryType: CategoryContentType?
var displayingLegIntCategories: Bool { categoryType == .legitimate }
var purposeToggleActive = true
var partners: [String] {
((displayingLegIntCategories ?
Expand Down Expand Up @@ -57,14 +58,14 @@ class SPGDPRCategoryDetailsViewController: SPNativeScreenViewController {

@IBAction func onOnButtonTap(_ sender: Any) {
if let category = category {
categoryManagerDelegate?.onCategoryOn(category: category, legInt: displayingLegIntCategories)
categoryManagerDelegate?.onCategoryOn(category: category, type: categoryType)
}
dismiss(animated: true)
}

@IBAction func onOffButtonTap(_ sender: Any) {
if let category = category {
categoryManagerDelegate?.onCategoryOff(category: category, legInt: displayingLegIntCategories)
categoryManagerDelegate?.onCategoryOff(category: category, type: categoryType)
}
dismiss(animated: true)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,13 @@ class SPGDPRManagePreferenceViewController: SPNativeScreenViewController {
// MARK: UITableViewDataSource
extension SPGDPRManagePreferenceViewController: UITableViewDataSource, UITableViewDelegate {
func currentCategory(_ index: IndexPath) -> GDPRCategory {
displayingLegIntCategories ?
if index.section >= 2 {
return sections[index.section].contentConsent[index.row]
} else {
return displayingLegIntCategories ?
sections[index.section].contentLegIntCategory[index.row] :
sections[index.section].contentConsent[index.row]
}
}

func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat {
Expand Down Expand Up @@ -194,14 +198,23 @@ extension SPGDPRManagePreferenceViewController: UITableViewDataSource, UITableVi
let category = currentCategory(indexPath)
cell.identifier = category._id
cell.labelText = category.name
if displayingLegIntCategories {
cell.isOn = section == 0 || section == 3 ?
consentsSnapshot.toggledLICategoriesIds.contains(category._id) :
nil
} else {
cell.isOn = section == 0 || section == 3 ?
consentsSnapshot.toggledConsentCategoriesIds.contains(category._id) :
nil
switch section {
case 0:
if displayingLegIntCategories {
cell.contentType = .legitimate
cell.isOn = consentsSnapshot.toggledLICategoriesIds.contains(category._id)
} else {
cell.contentType = .consent
cell.isOn = consentsSnapshot.toggledConsentCategoriesIds.contains(category._id)
}

case 3:
cell.contentType = .specialFeatures
cell.isOn = consentsSnapshot.toggledSpecialFeatures.contains(category._id)

default:
cell.contentType = nil
cell.isOn = nil
}
cell.selectable = true
cell.isCustom = category.type != .IAB || category.type != .IAB_PURPOSE
Expand Down Expand Up @@ -229,6 +242,7 @@ extension SPGDPRManagePreferenceViewController: UITableViewDataSource, UITableVi
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as? LongButtonViewCell
let categoryDetailsVC = SPGDPRCategoryDetailsViewController(
messageId: messageId,
campaignType: campaignType,
Expand All @@ -239,8 +253,8 @@ extension SPGDPRManagePreferenceViewController: UITableViewDataSource, UITableVi
)
categoryDetailsVC.category = currentCategory(indexPath)
categoryDetailsVC.categoryManagerDelegate = consentsSnapshot
categoryDetailsVC.displayingLegIntCategories = displayingLegIntCategories
categoryDetailsVC.purposeToggleActive = indexPath.section == 0
categoryDetailsVC.categoryType = cell?.contentType
categoryDetailsVC.purposeToggleActive = indexPath.section == 0 || indexPath.section == 3
present(categoryDetailsVC, animated: true)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ protocol SPNativePrivacyManagerHome {
legIntVendors: data.legIntVendors,
acceptedVendors: data.acceptedVendors,
acceptedCategories: data.acceptedCategories,
acceptedSpecialFeatures: data.acceptedSpecialFeatures,
hasConsentData: data.hasConsentData ?? false,
vendors: Set<GDPRVendor>(data.vendors),
categories: Set<GDPRCategory>(data.categories),
Expand Down Expand Up @@ -165,6 +166,7 @@ protocol SPNativePrivacyManagerHome {
legIntVendors: data.legIntVendors,
acceptedVendors: data.acceptedVendors,
acceptedCategories: data.acceptedCategories,
acceptedSpecialFeatures: data.acceptedSpecialFeatures,
hasConsentData: data.hasConsentData ?? false,
vendors: Set<GDPRVendor>(data.vendors),
categories: Set<GDPRCategory>(data.categories),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,8 @@ class SourcePointClientMock: SourcePointProtocol {
legIntCategories: nil,
legIntVendors: nil,
vendors: nil,
categories: nil
categories: nil,
specialFeatures: nil
)))
}
}
Expand Down
2 changes: 1 addition & 1 deletion Example/NativePMExampleAppUITests/NativePMUITests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ extension XCUIElement {
class NativePMUITests: QuickSpec {
var app: NativePMApp!
var timeout = 20
var gdprCategoriesCount = 10
var gdprCategoriesCount = 12
var ccpaCategoriesCount = 3
var gdprCategoriePlusSpecialFeatures = 12
var gdprDefaultOnCategories = 3
Expand Down

0 comments on commit 9ffbafe

Please sign in to comment.