Skip to content

Commit 2ef6bce

Browse files
committed
Initial commit.
0 parents  commit 2ef6bce

20 files changed

Lines changed: 1073 additions & 0 deletions

.gitignore

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
################################
2+
### Xcode project .gitignore ###
3+
################################
4+
5+
### macOS ###
6+
7+
.DS_Store
8+
9+
### User settings and such ###
10+
11+
xcuserdata/
12+
*.xcworkspace
13+
!default.xcworkspace
14+
15+
### Build Artifacts ###
16+
17+
*.hmap
18+
*.ipa
19+
*.dSYM.zip
20+
*.dSYM
21+
22+
*.xcworkspace
23+
!default.xcworkspace
24+
xcuserdata
25+
profile
26+
*.moved-aside
27+
DerivedData
28+
.idea/
29+
*.xccheckout
30+
build/
31+
32+
### Swift Package Manager ###
33+
34+
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
35+
.build/
36+
37+
### Playgrounds ###
38+
39+
timeline.xctimeline
40+
playground.xcworkspace

.swiftlint.yml

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
whitelist_rules: # only these rules will be applied
2+
- colon
3+
- comma
4+
- conditional_returns_on_newline
5+
- control_statement
6+
- empty_enum_arguments
7+
- empty_parameters
8+
- empty_parentheses_with_trailing_closure
9+
- file_length
10+
- legacy_cggeometry_functions
11+
- legacy_constant
12+
- legacy_constructor
13+
- legacy_hashing
14+
- legacy_nsgeometry_functions
15+
- line_length
16+
- class_delegate_protocol
17+
- weak_delegate
18+
- anyobject_protocol
19+
- closing_brace
20+
- closure_end_indentation
21+
- closure_parameter_position
22+
- closure_spacing
23+
- explicit_init
24+
- generic_type_name
25+
- identical_operands
26+
- implicit_getter
27+
- is_disjoint
28+
- leading_whitespace
29+
- literal_expression_end_indentation
30+
- mark
31+
- modifier_order
32+
- multiline_arguments
33+
- multiline_function_chains
34+
- multiple_closures_with_trailing_closure
35+
- operator_usage_whitespace
36+
- operator_whitespace
37+
- overridden_super_call
38+
- override_in_extension
39+
- prohibited_super_call
40+
- protocol_property_accessors_order
41+
- redundant_discardable_let
42+
- redundant_nil_coalescing
43+
- redundant_objc_attribute
44+
- redundant_optional_initialization
45+
- redundant_void_return
46+
- return_arrow_whitespace
47+
- shorthand_operator
48+
- statement_position
49+
- switch_case_alignment
50+
- syntactic_sugar
51+
- trailing_comma
52+
- trailing_semicolon
53+
- type_name
54+
- unneeded_break_in_switch
55+
- unused_enumerated
56+
- unused_optional_binding
57+
- valid_ibinspectable
58+
- vertical_parameter_alignment
59+
- vertical_parameter_alignment_on_call
60+
- vertical_whitespace
61+
- void_return
62+
- yoda_condition
63+
- array_init
64+
- attributes
65+
- compiler_protocol_init
66+
- contains_over_first_not_nil
67+
- discouraged_direct_init
68+
- discouraged_object_literal
69+
- discouraged_optional_boolean
70+
- dynamic_inline
71+
- force_try
72+
- force_unwrapping
73+
- legacy_random
74+
75+
# The values below are not final and may need further tweaking.
76+
77+
file_length:
78+
- 2000 #warning
79+
- 2500 #error
80+
81+
function_body_length:
82+
- 200 #warning
83+
- 400 #error
84+
85+
line_length:
86+
- 200 #warning
87+
- 400 #error
88+
89+
type_body_length:
90+
- 1000 #warning
91+
- 2000 #error
92+
93+
identifier_name:
94+
min_length: 1 #warning
95+
max_length: #warning or error
96+
warning: 100
97+
error: 150
98+
99+
type_name:
100+
min_length: 1
101+
max_length: 80 #warning
102+
103+
excluded: # paths to ignore during linting. Takes precedence over `included`.
104+
- External
105+
106+
reporter: "xcode" # reporter type (xcode, json, csv, checkstyle, junit, html, emoji, sonarqube, markdown)

LICENSE

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
BSD Zero Clause License
2+
3+
Copyright (c) 2023 Apparata AB
4+
5+
Permission to use, copy, modify, and/or distribute this software for any
6+
purpose with or without fee is hereby granted.
7+
8+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14+
PERFORMANCE OF THIS SOFTWARE.

Package.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// swift-tools-version:5.8
2+
3+
import PackageDescription
4+
5+
let package = Package(
6+
name: "UserDefaultsUI",
7+
platforms: [
8+
.iOS(.v15), .macOS(.v12), .tvOS(.v15)
9+
],
10+
products: [
11+
.library(name: "UserDefaultsUI", targets: ["UserDefaultsUI"])
12+
],
13+
targets: [
14+
.target(
15+
name: "UserDefaultsUI",
16+
dependencies: [],
17+
swiftSettings: [
18+
.define("DEBUG", .when(configuration: .debug)),
19+
.define("RELEASE", .when(configuration: .release)),
20+
.define("SWIFT_PACKAGE")
21+
])
22+
]
23+
)

README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
# UserDefaultsUI
3+
4+
Swift package that provides a `UserDefaults` browser and editor for debug mode in SwiftUI apps.
5+
6+
## License
7+
8+
See the LICENSE file for licensing information.
9+
10+
## Usage
11+
12+
Let's say the keys of your user defaults have a prefix, e.g. "com.example.", and you don't need to see it prominently in the `UserDefaults` browser, then you would list that prefix in the `hidePrefixes` parameter to the `UserDefaultsBrowser` initializer.
13+
14+
In the example below, `NavigationView` is used, but `NavigationStack` works too.
15+
16+
```swift
17+
import SwiftUI
18+
import UserDefaultsUI
19+
20+
struct ContentView: View {
21+
var body: some View {
22+
NavigationView {
23+
UserDefaultsBrowser(hidePrefixes: ["com.example."])
24+
}
25+
}
26+
}
27+
```
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import SwiftUI
2+
3+
struct AddUserDefaultEditor: View {
4+
5+
let value: UserDefaultValue
6+
7+
let model: UserDefaultsModel
8+
9+
@Environment(\.dismiss) private var dismiss
10+
11+
@State private var key: String = "example.key"
12+
13+
var body: some View {
14+
NavigationView {
15+
VStack {
16+
VStack(alignment: .leading) {
17+
Text("Key")
18+
.font(.caption)
19+
.foregroundStyle(.secondary)
20+
TextField("", text: $key)
21+
.labelsHidden()
22+
.keyboardType(.numbersAndPunctuation)
23+
.padding(4)
24+
.background(Color(white: 0, opacity: 0.05))
25+
.cornerRadius(4)
26+
}
27+
.padding()
28+
switch value {
29+
30+
case .boolean(let value):
31+
AddBoolEditor(value: value) { value in
32+
let key = key.trimmingCharacters(in: .whitespacesAndNewlines)
33+
model.actions.setValue(value, forKey: key)
34+
dismiss()
35+
}
36+
37+
case .integer(let value):
38+
IntValueEditor(value: value) { value in
39+
let key = key.trimmingCharacters(in: .whitespacesAndNewlines)
40+
model.actions.setValue(value, forKey: key)
41+
dismiss()
42+
}
43+
44+
case .float(let value):
45+
FloatValueEditor(value: value) { value in
46+
let key = key.trimmingCharacters(in: .whitespacesAndNewlines)
47+
model.actions.setValue(value, forKey: key)
48+
dismiss()
49+
}
50+
51+
case .double(let value):
52+
DoubleValueEditor(value: value) { value in
53+
let key = key.trimmingCharacters(in: .whitespacesAndNewlines)
54+
model.actions.setValue(value, forKey: key)
55+
dismiss()
56+
}
57+
58+
case .string(let value):
59+
StringValueEditor(text: value) { text in
60+
let key = key.trimmingCharacters(in: .whitespacesAndNewlines)
61+
model.actions.setValue(text, forKey: key)
62+
dismiss()
63+
}
64+
65+
case .other(_):
66+
Text("Type is not editable")
67+
}
68+
69+
Spacer()
70+
}
71+
.navigationTitle("Add User Default")
72+
.navigationBarTitleDisplayMode(.inline)
73+
.toolbar {
74+
ToolbarItem(placement: .navigationBarTrailing) {
75+
Button {
76+
dismiss()
77+
} label: {
78+
Image(systemName: "xmark")
79+
}
80+
}
81+
}
82+
}
83+
}
84+
}
85+
86+
private struct AddBoolEditor: View {
87+
88+
@State private var value: Bool
89+
90+
private var apply: (Bool) -> Void
91+
92+
init(value: Bool, apply: @escaping (Bool) -> Void) {
93+
_value = State(initialValue: value)
94+
self.apply = apply
95+
}
96+
97+
var body: some View {
98+
VStack {
99+
Toggle("", isOn: $value)
100+
.labelsHidden()
101+
Button {
102+
apply(value)
103+
} label: {
104+
Text("Apply")
105+
}
106+
.buttonStyle(.borderedProminent)
107+
.padding(.bottom)
108+
Spacer()
109+
}
110+
}
111+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import SwiftUI
2+
3+
struct BoolValueEditor: View {
4+
5+
@Binding var value: Bool
6+
7+
var body: some View {
8+
Toggle("", isOn: $value)
9+
.labelsHidden()
10+
}
11+
}
12+
13+
// Comment out until Xcode 15 goes live.
14+
/*
15+
#Preview {
16+
BoolValueEditor(value: .constant(true))
17+
}
18+
*/
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import SwiftUI
2+
3+
struct DoubleValueEditor: View {
4+
5+
@State private var text: String
6+
7+
@FocusState private var isFocused: Bool
8+
9+
@Environment(\.dismiss) private var dismiss
10+
11+
private var apply: (Double) -> Void
12+
13+
init(value: Double, apply: @escaping (Double) -> Void) {
14+
_text = State(initialValue: String(value))
15+
self.apply = apply
16+
}
17+
18+
var body: some View {
19+
VStack {
20+
TextField("", text: $text)
21+
.labelsHidden()
22+
.keyboardType(.numbersAndPunctuation)
23+
.focused($isFocused)
24+
.padding(.vertical, 4)
25+
.padding(.horizontal, 8)
26+
.background(Color(white: 0, opacity: 0.05))
27+
.cornerRadius(8)
28+
.padding()
29+
.onAppear {
30+
isFocused = true
31+
}
32+
Button {
33+
let value = Double(text) ?? 0
34+
apply(value)
35+
text = "\(value)"
36+
dismiss()
37+
} label: {
38+
Text("Apply")
39+
}
40+
.buttonStyle(.borderedProminent)
41+
.padding(.bottom)
42+
Spacer()
43+
}
44+
}
45+
}
46+
47+
// Comment out until Xcode 15 goes live.
48+
/*
49+
#Preview {
50+
DoubleValueEditor(value: 3.141592654, apply: { value in print(value) })
51+
}
52+
*/

0 commit comments

Comments
 (0)