Skip to content

Commit 9ce35ff

Browse files
authored
[Local catalog] Store catalog cellular sync preference (#16314)
2 parents ea5ebd9 + 29fc16b commit 9ce35ff

File tree

13 files changed

+339
-21
lines changed

13 files changed

+339
-21
lines changed

Modules/Sources/Networking/Model/Copiable/Models+Copiable.generated.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -436,8 +436,8 @@ extension Networking.Booking {
436436
allDay: CopiableProp<Bool> = .copy,
437437
cost: CopiableProp<String> = .copy,
438438
customerID: CopiableProp<Int64> = .copy,
439-
dateCreated: CopiableProp<Date> = .copy,
440-
dateModified: CopiableProp<Date> = .copy,
439+
dateCreated: NullableCopiableProp<Date> = .copy,
440+
dateModified: NullableCopiableProp<Date> = .copy,
441441
endDate: CopiableProp<Date> = .copy,
442442
googleCalendarEventID: NullableCopiableProp<String> = .copy,
443443
orderID: CopiableProp<Int64> = .copy,

Modules/Sources/PointOfSale/Presentation/Settings/POSSettingsLocalCatalogDetailView.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import SwiftUI
22

33
struct POSSettingsLocalCatalogDetailView: View {
44
// TODO: WOOMOB-1335 - implement full sync cellular data setting functionality
5-
@State private var allowFullSyncOnCellular: Bool = true
65
private let viewModel: POSSettingsLocalCatalogViewModel
76

87
init(viewModel: POSSettingsLocalCatalogViewModel) {
@@ -51,11 +50,12 @@ private extension POSSettingsLocalCatalogDetailView {
5150

5251
@ViewBuilder
5352
var managingDataUsage: some View {
53+
@Bindable var viewModel = viewModel
5454
VStack(spacing: POSSpacing.none) {
5555
sectionHeaderView(title: Localization.managingDataUsage)
5656

5757
VStack(spacing: POSSpacing.medium) {
58-
toggleRowView(label: Localization.allowFullSyncOnCellular, isOn: $allowFullSyncOnCellular)
58+
toggleRowView(label: Localization.allowFullSyncOnCellular, isOn: $viewModel.allowFullSyncOnCellular)
5959
}
6060
.padding(.bottom, POSPadding.medium)
6161
}

Modules/Sources/PointOfSale/Presentation/Settings/POSSettingsLocalCatalogViewModel.swift

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import CocoaLumberjackSwift
22
import Yosemite
33
import Foundation
4+
import Storage
45

56
@Observable
67
final class POSSettingsLocalCatalogViewModel {
@@ -14,19 +15,31 @@ final class POSSettingsLocalCatalogViewModel {
1415
private let siteID: Int64
1516
private let catalogSettingsService: POSCatalogSettingsServiceProtocol
1617
private let catalogSyncCoordinator: POSCatalogSyncCoordinatorProtocol
18+
private let siteSettings: SiteSpecificAppSettingsStoreMethodsProtocol
1719
private let dateFormatter: RelativeDateTimeFormatter = {
1820
let formatter = RelativeDateTimeFormatter()
1921
formatter.dateTimeStyle = .named
2022
formatter.unitsStyle = .full
2123
return formatter
2224
}()
2325

26+
var allowFullSyncOnCellular: Bool {
27+
get {
28+
siteSettings.getPOSLocalCatalogCellularDataAllowed(siteID: siteID)
29+
}
30+
set {
31+
siteSettings.setPOSLocalCatalogCellularDataAllowed(siteID: siteID, allowed: newValue)
32+
}
33+
}
34+
2435
init(siteID: Int64,
2536
catalogSettingsService: POSCatalogSettingsServiceProtocol,
26-
catalogSyncCoordinator: POSCatalogSyncCoordinatorProtocol) {
37+
catalogSyncCoordinator: POSCatalogSyncCoordinatorProtocol,
38+
siteSettings: SiteSpecificAppSettingsStoreMethodsProtocol? = nil) {
2739
self.siteID = siteID
2840
self.catalogSettingsService = catalogSettingsService
2941
self.catalogSyncCoordinator = catalogSyncCoordinator
42+
self.siteSettings = siteSettings ?? SiteSpecificAppSettingsStoreMethods(fileStorage: PListFileStorage())
3043
}
3144

3245
@MainActor

Modules/Sources/Storage/Model/Copiable/Models+Copiable.generated.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,8 @@ extension Storage.GeneralStoreSettings {
127127
searchTermsByKey: CopiableProp<[String: [String]]> = .copy,
128128
isPOSTabVisible: NullableCopiableProp<Bool> = .copy,
129129
lastPOSOpenedDate: NullableCopiableProp<Date> = .copy,
130-
firstPOSCatalogSyncDate: NullableCopiableProp<Date> = .copy
130+
firstPOSCatalogSyncDate: NullableCopiableProp<Date> = .copy,
131+
syncPOSCatalogOverCellular: CopiableProp<Bool> = .copy
131132
) -> Storage.GeneralStoreSettings {
132133
let storeID = storeID ?? self.storeID
133134
let isTelemetryAvailable = isTelemetryAvailable ?? self.isTelemetryAvailable
@@ -151,6 +152,7 @@ extension Storage.GeneralStoreSettings {
151152
let isPOSTabVisible = isPOSTabVisible ?? self.isPOSTabVisible
152153
let lastPOSOpenedDate = lastPOSOpenedDate ?? self.lastPOSOpenedDate
153154
let firstPOSCatalogSyncDate = firstPOSCatalogSyncDate ?? self.firstPOSCatalogSyncDate
155+
let syncPOSCatalogOverCellular = syncPOSCatalogOverCellular ?? self.syncPOSCatalogOverCellular
154156

155157
return Storage.GeneralStoreSettings(
156158
storeID: storeID,
@@ -174,7 +176,8 @@ extension Storage.GeneralStoreSettings {
174176
searchTermsByKey: searchTermsByKey,
175177
isPOSTabVisible: isPOSTabVisible,
176178
lastPOSOpenedDate: lastPOSOpenedDate,
177-
firstPOSCatalogSyncDate: firstPOSCatalogSyncDate
179+
firstPOSCatalogSyncDate: firstPOSCatalogSyncDate,
180+
syncPOSCatalogOverCellular: syncPOSCatalogOverCellular
178181
)
179182
}
180183
}

Modules/Sources/Storage/Model/GeneralStoreSettings.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ public struct GeneralStoreSettings: Codable, Equatable, GeneratedCopiable {
9494
///
9595
public var firstPOSCatalogSyncDate: Date?
9696

97+
/// Whether we should sync catalog data over cellular connections for this store
98+
///
99+
public var syncPOSCatalogOverCellular: Bool
100+
97101
public init(storeID: String? = nil,
98102
isTelemetryAvailable: Bool = false,
99103
telemetryLastReportedTime: Date? = nil,
@@ -115,7 +119,8 @@ public struct GeneralStoreSettings: Codable, Equatable, GeneratedCopiable {
115119
searchTermsByKey: [String: [String]] = [:],
116120
isPOSTabVisible: Bool? = nil,
117121
lastPOSOpenedDate: Date? = nil,
118-
firstPOSCatalogSyncDate: Date? = nil) {
122+
firstPOSCatalogSyncDate: Date? = nil,
123+
syncPOSCatalogOverCellular: Bool = true) {
119124
self.storeID = storeID
120125
self.isTelemetryAvailable = isTelemetryAvailable
121126
self.telemetryLastReportedTime = telemetryLastReportedTime
@@ -138,6 +143,7 @@ public struct GeneralStoreSettings: Codable, Equatable, GeneratedCopiable {
138143
self.isPOSTabVisible = isPOSTabVisible
139144
self.lastPOSOpenedDate = lastPOSOpenedDate
140145
self.firstPOSCatalogSyncDate = firstPOSCatalogSyncDate
146+
self.syncPOSCatalogOverCellular = syncPOSCatalogOverCellular
141147
}
142148

143149
public func erasingSelectedTaxRateID() -> GeneralStoreSettings {
@@ -198,6 +204,7 @@ extension GeneralStoreSettings {
198204
self.isPOSTabVisible = try container.decodeIfPresent(Bool.self, forKey: .isPOSTabVisible)
199205
self.lastPOSOpenedDate = try container.decodeIfPresent(Date.self, forKey: .lastPOSOpenedDate)
200206
self.firstPOSCatalogSyncDate = try container.decodeIfPresent(Date.self, forKey: .firstPOSCatalogSyncDate)
207+
self.syncPOSCatalogOverCellular = try container.decodeIfPresent(Bool.self, forKey: .syncPOSCatalogOverCellular) ?? true
201208

202209
// Decode new properties with `decodeIfPresent` and provide a default value if necessary.
203210
}

Modules/Sources/Yosemite/Actions/AppSettingsAction.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,4 +414,11 @@ public enum AppSettingsAction: Action {
414414
/// Gets the date of the first POS catalog sync for a specific site
415415
///
416416
case getFirstPOSCatalogSyncDate(siteID: Int64, onCompletion: (Date?) -> Void)
417+
418+
/// Sets whether we should allow cellular data use downloading POS catalogs for a specific site
419+
///
420+
case setPOSLocalCatalogCellularDataAllowed(siteID: Int64, allowed: Bool, onCompletion: () -> Void)
421+
422+
/// Gets whether we should allow cellular data use downloading POS catalogs for a specific site
423+
case getPOSLocalCatalogCellularDataAllowed(siteID: Int64, onCompletion: (Bool) -> Void)
417424
}

Modules/Sources/Yosemite/Stores/AppSettingsStore.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,10 @@ public class AppSettingsStore: Store {
315315
setFirstPOSCatalogSyncDate(siteID: siteID, date: date, onCompletion: onCompletion)
316316
case .getFirstPOSCatalogSyncDate(siteID: let siteID, onCompletion: let onCompletion):
317317
getFirstPOSCatalogSyncDate(siteID: siteID, onCompletion: onCompletion)
318+
case .setPOSLocalCatalogCellularDataAllowed(let siteID, let allowed, let onCompletion):
319+
setPOSLocalCatalogCellularDataAllowed(siteID: siteID, allowed: allowed, onCompletion: onCompletion)
320+
case .getPOSLocalCatalogCellularDataAllowed(let siteID, let onCompletion):
321+
getPOSLocalCatalogCellularDataAllowed(siteID: siteID, onCompletion: onCompletion)
318322
}
319323
}
320324
}
@@ -1365,7 +1369,10 @@ private extension AppSettingsStore {
13651369
onCompletion(.failure(error))
13661370
}
13671371
}
1372+
}
13681373

1374+
// MARK: - Point of Sale local catalog settings
1375+
private extension AppSettingsStore {
13691376
func setPOSLastOpenedDate(siteID: Int64, date: Date, onCompletion: () -> Void) {
13701377
siteSpecificAppSettingsStoreMethods.setPOSLastOpenedDate(siteID: siteID, date: date)
13711378
onCompletion()
@@ -1385,6 +1392,16 @@ private extension AppSettingsStore {
13851392
let date = siteSpecificAppSettingsStoreMethods.getFirstPOSCatalogSyncDate(siteID: siteID)
13861393
onCompletion(date)
13871394
}
1395+
1396+
func setPOSLocalCatalogCellularDataAllowed(siteID: Int64, allowed: Bool, onCompletion: () -> Void) {
1397+
siteSpecificAppSettingsStoreMethods.setPOSLocalCatalogCellularDataAllowed(siteID: siteID, allowed: allowed)
1398+
onCompletion()
1399+
}
1400+
1401+
func getPOSLocalCatalogCellularDataAllowed(siteID: Int64, onCompletion: (Bool) -> Void) {
1402+
let allowed = siteSpecificAppSettingsStoreMethods.getPOSLocalCatalogCellularDataAllowed(siteID: siteID)
1403+
onCompletion(allowed)
1404+
}
13881405
}
13891406

13901407
// MARK: - Errors

Modules/Sources/Yosemite/Stores/Helpers/SiteSpecificAppSettingsStoreMethods.swift

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,15 @@ public protocol SiteSpecificAppSettingsStoreMethodsProtocol {
1717
func setPOSLastOpenedDate(siteID: Int64, date: Date)
1818
func getFirstPOSCatalogSyncDate(siteID: Int64) -> Date?
1919
func setFirstPOSCatalogSyncDate(siteID: Int64, date: Date)
20+
21+
// POS local catalog cellular data
22+
func setPOSLocalCatalogCellularDataAllowed(siteID: Int64, allowed: Bool)
23+
func getPOSLocalCatalogCellularDataAllowed(siteID: Int64) -> Bool
2024
}
2125

2226
/// Methods for managing site-specific app settings
2327
///
24-
struct SiteSpecificAppSettingsStoreMethods: SiteSpecificAppSettingsStoreMethodsProtocol {
28+
public struct SiteSpecificAppSettingsStoreMethods: SiteSpecificAppSettingsStoreMethodsProtocol {
2529
private let fileStorage: FileStorage
2630
private let generalStoreSettingsFileURL: URL
2731

@@ -40,7 +44,7 @@ struct SiteSpecificAppSettingsStoreMethods: SiteSpecificAppSettingsStoreMethodsP
4044

4145
// MARK: - Store Settings
4246
extension SiteSpecificAppSettingsStoreMethods {
43-
func getStoreSettings(for siteID: Int64) -> GeneralStoreSettings {
47+
public func getStoreSettings(for siteID: Int64) -> GeneralStoreSettings {
4448
guard let existingData: GeneralStoreSettingsBySite = try? fileStorage.data(for: generalStoreSettingsFileURL),
4549
let storeSettings = existingData.storeSettingsBySite[siteID] else {
4650
return GeneralStoreSettings()
@@ -49,7 +53,7 @@ extension SiteSpecificAppSettingsStoreMethods {
4953
return storeSettings
5054
}
5155

52-
func setStoreSettings(settings: GeneralStoreSettings, for siteID: Int64, onCompletion: ((Result<Void, Error>) -> Void)? = nil) {
56+
public func setStoreSettings(settings: GeneralStoreSettings, for siteID: Int64, onCompletion: ((Result<Void, Error>) -> Void)? = nil) {
5357
var storeSettingsBySite: [Int64: GeneralStoreSettings] = [:]
5458
if let existingData: GeneralStoreSettingsBySite = try? fileStorage.data(for: generalStoreSettingsFileURL) {
5559
storeSettingsBySite = existingData.storeSettingsBySite
@@ -66,64 +70,80 @@ extension SiteSpecificAppSettingsStoreMethods {
6670
}
6771
}
6872

69-
func resetStoreSettings() {
73+
public func resetStoreSettings() {
7074
do {
7175
try fileStorage.deleteFile(at: generalStoreSettingsFileURL)
7276
} catch {
7377
DDLogError("⛔️ Deleting store settings file failed. Error: \(error)")
7478
}
7579
}
7680

77-
func setStoreID(siteID: Int64, id: String?) {
81+
public func setStoreID(siteID: Int64, id: String?) {
7882
let storeSettings = getStoreSettings(for: siteID)
7983
let updatedSettings = storeSettings.copy(storeID: id)
8084
setStoreSettings(settings: updatedSettings, for: siteID)
8185
}
8286

83-
func getStoreID(siteID: Int64, onCompletion: (String?) -> Void) {
87+
public func getStoreID(siteID: Int64, onCompletion: (String?) -> Void) {
8488
let storeSettings = getStoreSettings(for: siteID)
8589
onCompletion(storeSettings.storeID)
8690
}
8791
}
8892

8993
// MARK: - Search History
9094
extension SiteSpecificAppSettingsStoreMethods {
91-
func getSearchTerms(for itemType: POSItemType, siteID: Int64) -> [String] {
95+
public func getSearchTerms(for itemType: POSItemType, siteID: Int64) -> [String] {
9296
let storeSettings = getStoreSettings(for: siteID)
9397
let key = itemType.storedSearchHistoryKey
9498
return storeSettings.searchTermsByKey[key] ?? []
9599
}
96100

97-
func setSearchTerms(_ terms: [String], for itemType: POSItemType, siteID: Int64) {
101+
public func setSearchTerms(_ terms: [String], for itemType: POSItemType, siteID: Int64) {
98102
let storeSettings = getStoreSettings(for: siteID)
99103
let key = itemType.storedSearchHistoryKey
100104
var updatedSearchTermsByKey = storeSettings.searchTermsByKey
101105
updatedSearchTermsByKey[key] = terms
102106
let updatedSettings = storeSettings.copy(searchTermsByKey: updatedSearchTermsByKey)
103107
setStoreSettings(settings: updatedSettings, for: siteID)
104108
}
109+
}
105110

106-
func getPOSLastOpenedDate(siteID: Int64) -> Date? {
111+
// MARK: - POS sync eligibility tracking
112+
extension SiteSpecificAppSettingsStoreMethods {
113+
public func getPOSLastOpenedDate(siteID: Int64) -> Date? {
107114
getStoreSettings(for: siteID).lastPOSOpenedDate
108115
}
109116

110-
func setPOSLastOpenedDate(siteID: Int64, date: Date) {
117+
public func setPOSLastOpenedDate(siteID: Int64, date: Date) {
111118
let storeSettings = getStoreSettings(for: siteID)
112119
let updatedSettings = storeSettings.copy(lastPOSOpenedDate: date)
113120
setStoreSettings(settings: updatedSettings, for: siteID)
114121
}
115122

116-
func getFirstPOSCatalogSyncDate(siteID: Int64) -> Date? {
123+
public func getFirstPOSCatalogSyncDate(siteID: Int64) -> Date? {
117124
getStoreSettings(for: siteID).firstPOSCatalogSyncDate
118125
}
119126

120-
func setFirstPOSCatalogSyncDate(siteID: Int64, date: Date) {
127+
public func setFirstPOSCatalogSyncDate(siteID: Int64, date: Date) {
121128
let storeSettings = getStoreSettings(for: siteID)
122129
let updatedSettings = storeSettings.copy(firstPOSCatalogSyncDate: date)
123130
setStoreSettings(settings: updatedSettings, for: siteID)
124131
}
125132
}
126133

134+
// MARK: - POS local catalog cellular data
135+
extension SiteSpecificAppSettingsStoreMethods {
136+
public func setPOSLocalCatalogCellularDataAllowed(siteID: Int64, allowed: Bool) {
137+
let storeSettings = getStoreSettings(for: siteID)
138+
let updatedSettings = storeSettings.copy(syncPOSCatalogOverCellular: allowed)
139+
setStoreSettings(settings: updatedSettings, for: siteID)
140+
}
141+
142+
public func getPOSLocalCatalogCellularDataAllowed(siteID: Int64) -> Bool {
143+
getStoreSettings(for: siteID).syncPOSCatalogOverCellular
144+
}
145+
}
146+
127147
// MARK: - Constants
128148
private enum Constants {
129149
static let generalStoreSettingsFileName = "general-store-settings.plist"
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
@testable import Yosemite
2+
import Foundation
3+
import Storage
4+
5+
/// Minimal mock for SiteSpecificAppSettingsStoreMethodsProtocol
6+
/// Only implements the methods needed for POS local catalog tests
7+
final class MockSiteSpecificAppSettingsStoreMethods: SiteSpecificAppSettingsStoreMethodsProtocol {
8+
var currentSiteID: Int64 = 1
9+
10+
// POS local catalog cellular data properties
11+
var getPOSLocalCatalogCellularDataAllowedCalled = false
12+
var setPOSLocalCatalogCellularDataAllowedCalled = false
13+
var mockPOSLocalCatalogCellularDataAllowed: Bool?
14+
15+
// Implement only the methods we actually use
16+
func setPOSLocalCatalogCellularDataAllowed(siteID: Int64, allowed: Bool) {
17+
setPOSLocalCatalogCellularDataAllowedCalled = true
18+
mockPOSLocalCatalogCellularDataAllowed = allowed
19+
}
20+
21+
func getPOSLocalCatalogCellularDataAllowed(siteID: Int64) -> Bool {
22+
getPOSLocalCatalogCellularDataAllowedCalled = true
23+
return mockPOSLocalCatalogCellularDataAllowed ?? false
24+
}
25+
26+
// Protocol requirements - minimal implementations
27+
func getStoreSettings(for siteID: Int64) -> GeneralStoreSettings {
28+
GeneralStoreSettings()
29+
}
30+
31+
func setStoreSettings(settings: GeneralStoreSettings, for siteID: Int64, onCompletion: ((Result<Void, Error>) -> Void)?) {
32+
onCompletion?(.success(()))
33+
}
34+
35+
func resetStoreSettings() {}
36+
37+
func setStoreID(siteID: Int64, id: String?) {}
38+
39+
func getStoreID(siteID: Int64, onCompletion: (String?) -> Void) {
40+
onCompletion(nil)
41+
}
42+
43+
func getSearchTerms(for itemType: POSItemType, siteID: Int64) -> [String] {
44+
[]
45+
}
46+
47+
func setSearchTerms(_ terms: [String], for itemType: POSItemType, siteID: Int64) {}
48+
49+
func getPOSLastOpenedDate(siteID: Int64) -> Date? {
50+
nil
51+
}
52+
53+
func setPOSLastOpenedDate(siteID: Int64, date: Date) {}
54+
55+
func getFirstPOSCatalogSyncDate(siteID: Int64) -> Date? {
56+
nil
57+
}
58+
59+
func setFirstPOSCatalogSyncDate(siteID: Int64, date: Date) {}
60+
}

0 commit comments

Comments
 (0)