11import SwiftUI
22
3- typealias BooleanUserDefaultsSections = [ String : BooleanUserDefaultEntries ]
4- typealias BooleanUserDefaultEntries = [ String : BooleanUserDefault ]
5-
63final class BooleanUserDefaultsDebugViewModel : ObservableObject {
7- @Published private var allUserDefaultsSections = BooleanUserDefaultsSections ( )
8- @Published var searchQuery : String = " "
9-
10- private var persistentRepository : UserPersistentRepository
11-
12- var userDefaultsSections : BooleanUserDefaultsSections {
13- return filterUserDefaults ( by: searchQuery)
14- }
15-
16- let coreDataStack : CoreDataStack
4+ private let persistentRepository : UserPersistentRepository
5+ private let coreDataStack : CoreDataStack
176
18- private func filterUserDefaults ( by query : String ) -> BooleanUserDefaultsSections {
19- guard !query . isEmpty else {
20- return allUserDefaultsSections
7+ private var allUserDefaultsSections = Sections ( ) {
8+ didSet {
9+ self . reloadSections ( )
2110 }
11+ }
2212
23- var filteredSections = BooleanUserDefaultsSections ( )
24- allUserDefaultsSections. forEach { sectionKey, userDefaults in
25- let filteredUserDefaults = userDefaults. filter { key, userDefault in
26- key. localizedCaseInsensitiveContains ( query) || userDefault. title. localizedCaseInsensitiveContains ( query)
27- }
28- if sectionKey. localizedCaseInsensitiveContains ( query) || !filteredUserDefaults. isEmpty {
29- filteredSections [ sectionKey] = filteredUserDefaults. isEmpty ? userDefaults : filteredUserDefaults
30- }
13+ @Published var searchQuery : String = " " {
14+ didSet {
15+ self . reloadSections ( )
3116 }
32- return filteredSections
3317 }
3418
19+ @Published var userDefaultsSections : Sections = [ ]
20+
3521 init ( coreDataStack: CoreDataStack = ContextManager . shared,
3622 persistentRepository: UserPersistentRepository = UserPersistentStoreFactory . instance ( ) ) {
3723 self . coreDataStack = coreDataStack
3824 self . persistentRepository = persistentRepository
39- load ( )
4025 }
4126
4227 func load( ) {
4328 let allUserDefaults = persistentRepository. dictionaryRepresentation ( )
44- var loadedUserDefaultsSections = BooleanUserDefaultsSections ( )
45- var otherSection = BooleanUserDefaultEntries ( )
46-
47- for (entryKey, entryValue) in allUserDefaults {
48- if let groupedUserDefaults = entryValue as? [ String : Bool ] , !isFeatureFlagsSection( entryKey) {
49- loadedUserDefaultsSections [ entryKey] = processGroupedUserDefaults ( groupedUserDefaults)
50- } else if let booleanUserDefault = entryValue as? Bool , !isGutenbergUserDefault( entryKey) {
51- otherSection [ entryKey] = BooleanUserDefault ( title: entryKey, value: booleanUserDefault)
29+ var loadedUserDefaultsSections = Sections ( )
30+ var otherSection = [ Row] ( )
31+
32+ for (key, value) in allUserDefaults {
33+ if let groupedUserDefaults = value as? [ String : Bool ] , !isFeatureFlagsSection( key) {
34+ let section = Section (
35+ key: key,
36+ rows: processGroupedUserDefaults ( groupedUserDefaults)
37+ )
38+ loadedUserDefaultsSections. append ( section)
39+ } else if let booleanUserDefault = value as? Bool , !isGutenbergUserDefault( key) {
40+ otherSection. append ( . init( key: key, title: key, value: booleanUserDefault) )
5241 }
5342 }
5443 if !otherSection. isEmpty {
55- loadedUserDefaultsSections [ Strings . otherBooleanUserDefaultsSectionID] = otherSection
44+ let rows = otherSection. sorted { $0. title < $1. title }
45+ let section = Section ( key: Strings . otherBooleanUserDefaultsSectionID, rows: rows)
46+ loadedUserDefaultsSections. append ( section)
5647 }
5748 allUserDefaultsSections = loadedUserDefaultsSections
5849 }
5950
60- private func processGroupedUserDefaults( _ userDefaults: [ String : Bool ] ) -> BooleanUserDefaultEntries {
61- userDefaults. reduce ( into: BooleanUserDefaultEntries ( ) ) { result, keyValue in
51+ private func reloadSections( ) {
52+ self . userDefaultsSections = filterUserDefaults ( by: searchQuery)
53+ }
54+
55+ private func filterUserDefaults( by query: String ) -> Sections {
56+ guard !query. isEmpty else {
57+ return allUserDefaultsSections
58+ }
59+
60+ var filteredSections = Sections ( )
61+ allUserDefaultsSections. forEach { section in
62+ let filteredUserDefaults = section. rows. filter { entry in
63+ section. key. localizedCaseInsensitiveContains ( query) || entry. title. localizedCaseInsensitiveContains ( query)
64+ }
65+ if section. key. localizedCaseInsensitiveContains ( query) || !filteredUserDefaults. isEmpty {
66+ let section = Section (
67+ key: section. key,
68+ rows: filteredUserDefaults. isEmpty ? section. rows : filteredUserDefaults
69+ )
70+ filteredSections. append ( section)
71+ }
72+ }
73+ return filteredSections
74+ }
75+
76+ private func processGroupedUserDefaults( _ userDefaults: [ String : Bool ] ) -> [ Row ] {
77+ var rows = userDefaults. reduce ( into: [ Row] ( ) ) { result, keyValue in
6278 let ( key, value) = keyValue
63- result [ key ] = processSingleUserDefault ( key: key, value: value)
79+ result. append ( processSingleUserDefault ( key: key, value: value) )
6480 }
81+ rows = rows. sorted { $0. title < $1. title }
82+ return rows
83+ }
84+
85+ private func processSingleUserDefault( key: String , value: Bool ) -> Row {
86+ let title = findBlog ( byID: key) ? . url ?? key
87+ return Row ( key: key, title: title, value: value)
6588 }
6689
67- private func processSingleUserDefault( key: String , value: Bool ) -> BooleanUserDefault {
68- if let siteID = Int ( key) , let blogURL = try ? Blog . lookup ( withID: siteID, in: coreDataStack. mainContext) ? . url {
69- return BooleanUserDefault ( title: blogURL, value: value)
90+ private func findBlog( byID id: String ) -> Blog ? {
91+ return try ? Blog . lookup ( withID: Int ( id) ?? 0 , in: coreDataStack. mainContext)
92+ }
93+
94+ func updateUserDefault( _ newValue: Bool , forSection targetSection: String , forRow targetRow: String ) {
95+ updateAllUserDefaultsSections ( newValue, forSection: targetSection, forRow: targetRow)
96+ if targetSection == Strings . otherBooleanUserDefaultsSectionID {
97+ persistentRepository. set ( newValue, forKey: targetRow)
7098 } else {
71- return BooleanUserDefault ( title: key, value: value)
99+ guard let section = allUserDefaultsSections. first ( where: { $0. key == targetSection } ) else {
100+ return
101+ }
102+ let entries = section. rows. reduce ( into: [ String: Bool] ( ) ) { result, row in
103+ result [ row. key] = newValue
104+ }
105+ persistentRepository. set ( entries, forKey: targetSection)
72106 }
73107 }
74108
75- func updateUserDefault( _ value: Bool , forSection sectionID: String , forUserDefault userDefaultID: String ) {
76- if sectionID == Strings . otherBooleanUserDefaultsSectionID {
77- persistentRepository. set ( value, forKey: userDefaultID)
78- } else if var section = allUserDefaultsSections [ sectionID] {
79- section [ userDefaultID] = BooleanUserDefault ( title: userDefaultID, value: value)
80- let sectionValues = section. mapValues { $0. value }
81- persistentRepository. set ( sectionValues, forKey: sectionID)
109+ func updateAllUserDefaultsSections( _ newValue: Bool , forSection targetSection: String , forRow targetRow: String ) {
110+ allUserDefaultsSections = allUserDefaultsSections. map { currentSection in
111+ if currentSection. key == targetSection {
112+ let updatedRows = currentSection. rows. map { currentRow in
113+ if currentRow. key == targetRow {
114+ return Row ( key: currentRow. key, title: currentRow. title, value: newValue)
115+ } else {
116+ return currentRow
117+ }
118+ }
119+ return Section ( key: currentSection. key, rows: updatedRows)
120+ } else {
121+ return currentSection
122+ }
82123 }
83- load ( )
84124 }
85125
86126 private func isGutenbergUserDefault( _ key: String ) -> Bool {
@@ -90,13 +130,32 @@ final class BooleanUserDefaultsDebugViewModel: ObservableObject {
90130 private func isFeatureFlagsSection( _ key: String ) -> Bool {
91131 key. isEqual ( to: Strings . featureFlagSectionKey)
92132 }
93- }
94133
95- struct BooleanUserDefault : Equatable {
96- var title : String
97- var value : Bool
134+ // MARK: - Types
135+
136+ struct Section {
137+ let key : String
138+ let rows : [ Row ]
139+ }
140+
141+ final class Row {
142+ let key : String
143+ let title : String
144+ let value : Bool
145+
146+ init ( key: String , title: String , value: Bool ) {
147+ self . key = key
148+ self . title = title
149+ self . value = value
150+ }
151+ }
152+
153+ typealias Sections = [ Section ]
154+
98155}
99156
157+ // MARK: - Constants
158+
100159private enum Strings {
101160 static let otherBooleanUserDefaultsSectionID = " Other "
102161 static let gutenbergUserDefaultPrefix = " com.wordpress.gutenberg- "
0 commit comments