From 940401d8a9d0cf39e453df336aaa9864c2b14ffd Mon Sep 17 00:00:00 2001 From: Michael Henry Date: Tue, 17 Jan 2023 21:21:20 +1100 Subject: [PATCH] [Feature] Custom display name support (#22) --- Demo/DemoTests/MockConfigs.swift | 4 +- Demo/DemoTests/SnapshotTests.swift | 8 +- Demo/DemoTests/XConfigsTests.swift | 346 +++++++++--------- Sources/XConfigs/Models/InputModel.swift | 1 + .../Models/OptionSelectionModel.swift | 1 + Sources/XConfigs/Models/ToggleModel.swift | 1 + .../XConfigs/PropertyWrappers/XConfig.swift | 4 +- Sources/XConfigs/Protocols/ConfigInfo.swift | 1 + .../XConfigsViewController.swift | 6 +- .../ViewModels/XConfigsViewModel.swift | 7 +- 10 files changed, 193 insertions(+), 186 deletions(-) diff --git a/Demo/DemoTests/MockConfigs.swift b/Demo/DemoTests/MockConfigs.swift index 1a226dd..e0d1121 100644 --- a/Demo/DemoTests/MockConfigs.swift +++ b/Demo/DemoTests/MockConfigs.swift @@ -40,10 +40,10 @@ struct MockConfigs: XConfigsSpec { @XConfig(key: "width", defaultValue: 320, group: .feature2) var width: Double - @XConfig(key: "accountType", defaultValue: .guest, group: .feature3) + @XConfig(key: "accountType", displayName: "Account Type", defaultValue: .guest, group: .feature3) var accountType: AccountType - @XConfig(key: "contact", defaultValue: .default, group: .feature3) + @XConfig(key: "contact", displayName: "Contact", defaultValue: .default, group: .feature3) var contact: Contact } diff --git a/Demo/DemoTests/SnapshotTests.swift b/Demo/DemoTests/SnapshotTests.swift index ebd7d01..5e7a46a 100644 --- a/Demo/DemoTests/SnapshotTests.swift +++ b/Demo/DemoTests/SnapshotTests.swift @@ -40,23 +40,23 @@ final class SnapshotTests: XCTestCase { } func testInputValueViewController() throws { - let vc = InputValueViewController(viewModel: .init(model: .init(key: "Hello", value: "World"))).wrapInsideNavVC() + let vc = InputValueViewController(viewModel: .init(model: .init(key: "Hello", value: "World", displayName: "Hello"))).wrapInsideNavVC() assertSnapshot(matching: vc, as: .image) } func testInputValueViewControllerJSON() throws { - let vc = InputValueViewController(viewModel: .init(model: .init(key: "JSON", value: "{\"name\":\"Kel\", \"city\": \"Melbourne\" }"))).wrapInsideNavVC() + let vc = InputValueViewController(viewModel: .init(model: .init(key: "JSON", value: "{\"name\":\"Kel\", \"city\": \"Melbourne\" }", displayName: "Contact"))).wrapInsideNavVC() assertSnapshot(matching: vc, as: .image) } func testInputValueViewControllerURL() throws { - let vc = InputValueViewController(viewModel: .init(model: .init(key: "URL", value: "https://google.com"))).wrapInsideNavVC() + let vc = InputValueViewController(viewModel: .init(model: .init(key: "URL", value: "https://google.com", displayName: "URL"))).wrapInsideNavVC() assertSnapshot(matching: vc, as: .image) } func testOptionViewController() throws { let choices = [1, 2, 3, 4].map { "Value\($0)" }.map { Choice(displayName: $0, value: $0) } - let vc = OptionViewController(viewModel: .init(model: .init(key: "Name", value: "Value1", choices: choices))).wrapInsideNavVC() + let vc = OptionViewController(viewModel: .init(model: .init(key: "Name", value: "Value1", choices: choices, displayName: "Name"))).wrapInsideNavVC() assertSnapshot(matching: vc, as: .image(precision: 0.95)) } diff --git a/Demo/DemoTests/XConfigsTests.swift b/Demo/DemoTests/XConfigsTests.swift index 688cf03..33d5c09 100644 --- a/Demo/DemoTests/XConfigsTests.swift +++ b/Demo/DemoTests/XConfigsTests.swift @@ -104,30 +104,30 @@ final class XConfigsTests: XCTestCase { .actionButton(title: "Reset", action: .showResetConfirmation("Are you sure you want to reset these values?")), ]), .init(section: .group(""), items: [ - .toggle(.init(key: "isOnboardingEnabled", value: false)), - .textInput(.init(key: "apiURL", value: "https://prod.google.com")), - .textInput(.init(key: "apiVersion", value: "v1.2.3")), - .optionSelection(.init(key: "region", value: "north", choices: regionChoices)), - .textInput(.init(key: "maxRetry", value: "10")), - .textInput(.init(key: "threshold", value: "1")), - .textInput(.init(key: "rate", value: "2.5")), - .textInput(.init(key: "tags", value: "apple,banana,mango")), + .toggle(.init(key: "isOnboardingEnabled", value: false, displayName: "isOnboardingEnabled")), + .textInput(.init(key: "apiURL", value: "https://prod.google.com", displayName: "apiURL")), + .textInput(.init(key: "apiVersion", value: "v1.2.3", displayName: "apiVersion")), + .optionSelection(.init(key: "region", value: "north", choices: regionChoices, displayName: "region")), + .textInput(.init(key: "maxRetry", value: "10", displayName: "maxRetry")), + .textInput(.init(key: "threshold", value: "1", displayName: "threshold")), + .textInput(.init(key: "rate", value: "2.5", displayName: "rate")), + .textInput(.init(key: "tags", value: "apple,banana,mango", displayName: "tags")), ]), .init(section: .group("Feature 1"), items: [ - .textInput(.init(key: "maxScore", value: "100")), - .textInput(.init(key: "maxRate", value: "1.0")), + .textInput(.init(key: "maxScore", value: "100", displayName: "maxScore")), + .textInput(.init(key: "maxRate", value: "1.0", displayName: "maxRate")), ]), .init(section: .group("Feature 2"), items: [ - .textInput(.init(key: "height", value: "44.0")), - .textInput(.init(key: "width", value: "320.0")), + .textInput(.init(key: "height", value: "44.0", displayName: "height")), + .textInput(.init(key: "width", value: "320.0", displayName: "width")), ]), .init(section: .group("Feature 3"), items: [ .optionSelection(.init(key: "accountType", value: "Guest", choices: [ .init(displayName: "Guest", value: "0"), .init(displayName: "Member", value: "1"), .init(displayName: "Admin", value: "2"), - ])), - .textInput(.init(key: "contact", value: "{\"name\":\"Ken\",\"phoneNumber\":\"1234 5678\"}")), + ], displayName: "Account Type")), + .textInput(.init(key: "contact", value: "{\"name\":\"Ken\",\"phoneNumber\":\"1234 5678\"}", displayName: "Contact")), ]), ]), ]) @@ -174,30 +174,30 @@ final class XConfigsTests: XCTestCase { .actionButton(title: "Reset", action: .showResetConfirmation("Are you sure you want to reset these values?")), ]), .init(section: .group(""), items: [ - .toggle(.init(key: "isOnboardingEnabled", value: false)), - .textInput(.init(key: "apiURL", value: "https://prod.google.com")), - .textInput(.init(key: "apiVersion", value: "v1.2.3")), - .optionSelection(.init(key: "region", value: "north", choices: regionChoices)), - .textInput(.init(key: "maxRetry", value: "10")), - .textInput(.init(key: "threshold", value: "1")), - .textInput(.init(key: "rate", value: "2.5")), - .textInput(.init(key: "tags", value: "apple,banana,mango")), + .toggle(.init(key: "isOnboardingEnabled", value: false, displayName: "isOnboardingEnabled")), + .textInput(.init(key: "apiURL", value: "https://prod.google.com", displayName: "apiURL")), + .textInput(.init(key: "apiVersion", value: "v1.2.3", displayName: "apiVersion")), + .optionSelection(.init(key: "region", value: "north", choices: regionChoices, displayName: "region")), + .textInput(.init(key: "maxRetry", value: "10", displayName: "maxRetry")), + .textInput(.init(key: "threshold", value: "1", displayName: "threshold")), + .textInput(.init(key: "rate", value: "2.5", displayName: "rate")), + .textInput(.init(key: "tags", value: "apple,banana,mango", displayName: "tags")), ]), .init(section: .group("Feature 1"), items: [ - .textInput(.init(key: "maxScore", value: "100")), - .textInput(.init(key: "maxRate", value: "1.0")), + .textInput(.init(key: "maxScore", value: "100", displayName: "maxScore")), + .textInput(.init(key: "maxRate", value: "1.0", displayName: "maxRate")), ]), .init(section: .group("Feature 2"), items: [ - .textInput(.init(key: "height", value: "44.0")), - .textInput(.init(key: "width", value: "320.0")), + .textInput(.init(key: "height", value: "44.0", displayName: "height")), + .textInput(.init(key: "width", value: "320.0", displayName: "width")), ]), .init(section: .group("Feature 3"), items: [ .optionSelection(.init(key: "accountType", value: "Guest", choices: [ .init(displayName: "Guest", value: "0"), .init(displayName: "Member", value: "1"), .init(displayName: "Admin", value: "2"), - ])), - .textInput(.init(key: "contact", value: "{\"name\":\"Ken\",\"phoneNumber\":\"1234 5678\"}")), + ], displayName: "Account Type")), + .textInput(.init(key: "contact", value: "{\"name\":\"Ken\",\"phoneNumber\":\"1234 5678\"}", displayName: "Contact")), ]), ]), .next(1, [ @@ -206,30 +206,30 @@ final class XConfigsTests: XCTestCase { .actionButton(title: "Reset", action: .showResetConfirmation("Are you sure you want to reset these values?")), ]), .init(section: .group(""), items: [ - .toggle(.init(key: "isOnboardingEnabled", value: false)), - .textInput(.init(key: "apiURL", value: "https://prod.google.com")), - .textInput(.init(key: "apiVersion", value: "v1.2.3")), - .optionSelection(.init(key: "region", value: "north", choices: regionChoices)), - .textInput(.init(key: "maxRetry", value: "20")), - .textInput(.init(key: "threshold", value: "1")), - .textInput(.init(key: "rate", value: "2.5")), - .textInput(.init(key: "tags", value: "apple,banana,mango")), + .toggle(.init(key: "isOnboardingEnabled", value: false, displayName: "isOnboardingEnabled")), + .textInput(.init(key: "apiURL", value: "https://prod.google.com", displayName: "apiURL")), + .textInput(.init(key: "apiVersion", value: "v1.2.3", displayName: "apiVersion")), + .optionSelection(.init(key: "region", value: "north", choices: regionChoices, displayName: "region")), + .textInput(.init(key: "maxRetry", value: "20", displayName: "maxRetry")), + .textInput(.init(key: "threshold", value: "1", displayName: "threshold")), + .textInput(.init(key: "rate", value: "2.5", displayName: "rate")), + .textInput(.init(key: "tags", value: "apple,banana,mango", displayName: "tags")), ]), .init(section: .group("Feature 1"), items: [ - .textInput(.init(key: "maxScore", value: "100")), - .textInput(.init(key: "maxRate", value: "1.0")), + .textInput(.init(key: "maxScore", value: "100", displayName: "maxScore")), + .textInput(.init(key: "maxRate", value: "1.0", displayName: "maxRate")), ]), .init(section: .group("Feature 2"), items: [ - .textInput(.init(key: "height", value: "44.0")), - .textInput(.init(key: "width", value: "320.0")), + .textInput(.init(key: "height", value: "44.0", displayName: "height")), + .textInput(.init(key: "width", value: "320.0", displayName: "width")), ]), .init(section: .group("Feature 3"), items: [ .optionSelection(.init(key: "accountType", value: "Guest", choices: [ .init(displayName: "Guest", value: "0"), .init(displayName: "Member", value: "1"), .init(displayName: "Admin", value: "2"), - ])), - .textInput(.init(key: "contact", value: "{\"name\":\"Ken\",\"phoneNumber\":\"1234 5678\"}")), + ], displayName: "Account Type")), + .textInput(.init(key: "contact", value: "{\"name\":\"Ken\",\"phoneNumber\":\"1234 5678\"}", displayName: "Contact")), ]), ]), .next(2, [ @@ -238,30 +238,30 @@ final class XConfigsTests: XCTestCase { .actionButton(title: "Reset", action: .showResetConfirmation("Are you sure you want to reset these values?")), ]), .init(section: .group(""), items: [ - .toggle(.init(key: "isOnboardingEnabled", value: false)), - .textInput(.init(key: "apiURL", value: "https://prod.google.com")), - .textInput(.init(key: "apiVersion", value: "v1.2.3")), - .optionSelection(.init(key: "region", value: "north", choices: regionChoices)), - .textInput(.init(key: "maxRetry", value: "20")), - .textInput(.init(key: "threshold", value: "1")), - .textInput(.init(key: "rate", value: "2.5")), - .textInput(.init(key: "tags", value: "apple,banana,mango")), + .toggle(.init(key: "isOnboardingEnabled", value: false, displayName: "isOnboardingEnabled")), + .textInput(.init(key: "apiURL", value: "https://prod.google.com", displayName: "apiURL")), + .textInput(.init(key: "apiVersion", value: "v1.2.3", displayName: "apiVersion")), + .optionSelection(.init(key: "region", value: "north", choices: regionChoices, displayName: "region")), + .textInput(.init(key: "maxRetry", value: "20", displayName: "maxRetry")), + .textInput(.init(key: "threshold", value: "1", displayName: "threshold")), + .textInput(.init(key: "rate", value: "2.5", displayName: "rate")), + .textInput(.init(key: "tags", value: "apple,banana,mango", displayName: "tags")), ]), .init(section: .group("Feature 1"), items: [ - .textInput(.init(key: "maxScore", value: "100")), - .textInput(.init(key: "maxRate", value: "0.99")), + .textInput(.init(key: "maxScore", value: "100", displayName: "maxScore")), + .textInput(.init(key: "maxRate", value: "0.99", displayName: "maxRate")), ]), .init(section: .group("Feature 2"), items: [ - .textInput(.init(key: "height", value: "44.0")), - .textInput(.init(key: "width", value: "320.0")), + .textInput(.init(key: "height", value: "44.0", displayName: "height")), + .textInput(.init(key: "width", value: "320.0", displayName: "width")), ]), .init(section: .group("Feature 3"), items: [ .optionSelection(.init(key: "accountType", value: "Guest", choices: [ .init(displayName: "Guest", value: "0"), .init(displayName: "Member", value: "1"), .init(displayName: "Admin", value: "2"), - ])), - .textInput(.init(key: "contact", value: "{\"name\":\"Ken\",\"phoneNumber\":\"1234 5678\"}")), + ], displayName: "Account Type")), + .textInput(.init(key: "contact", value: "{\"name\":\"Ken\",\"phoneNumber\":\"1234 5678\"}", displayName: "Contact")), ]), ]), .next(3, [ @@ -270,30 +270,30 @@ final class XConfigsTests: XCTestCase { .actionButton(title: "Reset", action: .showResetConfirmation("Are you sure you want to reset these values?")), ]), .init(section: .group(""), items: [ - .toggle(.init(key: "isOnboardingEnabled", value: false)), - .textInput(.init(key: "apiURL", value: "https://stage.google.com")), - .textInput(.init(key: "apiVersion", value: "v1.2.3")), - .optionSelection(.init(key: "region", value: "north", choices: regionChoices)), - .textInput(.init(key: "maxRetry", value: "20")), - .textInput(.init(key: "threshold", value: "1")), - .textInput(.init(key: "rate", value: "2.5")), - .textInput(.init(key: "tags", value: "apple,banana,mango")), + .toggle(.init(key: "isOnboardingEnabled", value: false, displayName: "isOnboardingEnabled")), + .textInput(.init(key: "apiURL", value: "https://stage.google.com", displayName: "apiURL")), + .textInput(.init(key: "apiVersion", value: "v1.2.3", displayName: "apiVersion")), + .optionSelection(.init(key: "region", value: "north", choices: regionChoices, displayName: "region")), + .textInput(.init(key: "maxRetry", value: "20", displayName: "maxRetry")), + .textInput(.init(key: "threshold", value: "1", displayName: "threshold")), + .textInput(.init(key: "rate", value: "2.5", displayName: "rate")), + .textInput(.init(key: "tags", value: "apple,banana,mango", displayName: "tags")), ]), .init(section: .group("Feature 1"), items: [ - .textInput(.init(key: "maxScore", value: "100")), - .textInput(.init(key: "maxRate", value: "0.99")), + .textInput(.init(key: "maxScore", value: "100", displayName: "maxScore")), + .textInput(.init(key: "maxRate", value: "0.99", displayName: "maxRate")), ]), .init(section: .group("Feature 2"), items: [ - .textInput(.init(key: "height", value: "44.0")), - .textInput(.init(key: "width", value: "320.0")), + .textInput(.init(key: "height", value: "44.0", displayName: "height")), + .textInput(.init(key: "width", value: "320.0", displayName: "width")), ]), .init(section: .group("Feature 3"), items: [ .optionSelection(.init(key: "accountType", value: "Guest", choices: [ .init(displayName: "Guest", value: "0"), .init(displayName: "Member", value: "1"), .init(displayName: "Admin", value: "2"), - ])), - .textInput(.init(key: "contact", value: "{\"name\":\"Ken\",\"phoneNumber\":\"1234 5678\"}")), + ], displayName: "Account Type")), + .textInput(.init(key: "contact", value: "{\"name\":\"Ken\",\"phoneNumber\":\"1234 5678\"}", displayName: "Contact")), ]), ]), .next(4, [ @@ -302,30 +302,30 @@ final class XConfigsTests: XCTestCase { .actionButton(title: "Reset", action: .showResetConfirmation("Are you sure you want to reset these values?")), ]), .init(section: .group(""), items: [ - .toggle(.init(key: "isOnboardingEnabled", value: false)), - .textInput(.init(key: "apiURL", value: "https://stage.google.com")), - .textInput(.init(key: "apiVersion", value: "v1.2.3")), - .optionSelection(.init(key: "region", value: "north", choices: regionChoices)), - .textInput(.init(key: "maxRetry", value: "20")), - .textInput(.init(key: "threshold", value: "1")), - .textInput(.init(key: "rate", value: "2.5")), - .textInput(.init(key: "tags", value: "apple,banana,mango")), + .toggle(.init(key: "isOnboardingEnabled", value: false, displayName: "isOnboardingEnabled")), + .textInput(.init(key: "apiURL", value: "https://stage.google.com", displayName: "apiURL")), + .textInput(.init(key: "apiVersion", value: "v1.2.3", displayName: "apiVersion")), + .optionSelection(.init(key: "region", value: "north", choices: regionChoices, displayName: "region")), + .textInput(.init(key: "maxRetry", value: "20", displayName: "maxRetry")), + .textInput(.init(key: "threshold", value: "1", displayName: "threshold")), + .textInput(.init(key: "rate", value: "2.5", displayName: "rate")), + .textInput(.init(key: "tags", value: "apple,banana,mango", displayName: "tags")), ]), .init(section: .group("Feature 1"), items: [ - .textInput(.init(key: "maxScore", value: "100")), - .textInput(.init(key: "maxRate", value: "0.99")), + .textInput(.init(key: "maxScore", value: "100", displayName: "maxScore")), + .textInput(.init(key: "maxRate", value: "0.99", displayName: "maxRate")), ]), .init(section: .group("Feature 2"), items: [ - .textInput(.init(key: "height", value: "44.0")), - .textInput(.init(key: "width", value: "320.0")), + .textInput(.init(key: "height", value: "44.0", displayName: "height")), + .textInput(.init(key: "width", value: "320.0", displayName: "width")), ]), .init(section: .group("Feature 3"), items: [ .optionSelection(.init(key: "accountType", value: "Guest", choices: [ .init(displayName: "Guest", value: "0"), .init(displayName: "Member", value: "1"), .init(displayName: "Admin", value: "2"), - ])), - .textInput(.init(key: "contact", value: "{\"name\":\"Ken\",\"phoneNumber\":\"2222 5678\"}")), + ], displayName: "Account Type")), + .textInput(.init(key: "contact", value: "{\"name\":\"Ken\",\"phoneNumber\":\"2222 5678\"}", displayName: "Contact")), ]), ]), .next(5, [ @@ -334,30 +334,30 @@ final class XConfigsTests: XCTestCase { .actionButton(title: "Reset", action: .showResetConfirmation("Are you sure you want to reset these values?")), ]), .init(section: .group(""), items: [ - .toggle(.init(key: "isOnboardingEnabled", value: false)), - .textInput(.init(key: "apiURL", value: "https://stage.google.com")), - .textInput(.init(key: "apiVersion", value: "v1.2.3")), - .optionSelection(.init(key: "region", value: "north", choices: regionChoices)), - .textInput(.init(key: "maxRetry", value: "20")), - .textInput(.init(key: "threshold", value: "1")), - .textInput(.init(key: "rate", value: "2.5")), - .textInput(.init(key: "tags", value: "apple,banana,mango")), + .toggle(.init(key: "isOnboardingEnabled", value: false, displayName: "isOnboardingEnabled")), + .textInput(.init(key: "apiURL", value: "https://stage.google.com", displayName: "apiURL")), + .textInput(.init(key: "apiVersion", value: "v1.2.3", displayName: "apiVersion")), + .optionSelection(.init(key: "region", value: "north", choices: regionChoices, displayName: "region")), + .textInput(.init(key: "maxRetry", value: "20", displayName: "maxRetry")), + .textInput(.init(key: "threshold", value: "1", displayName: "threshold")), + .textInput(.init(key: "rate", value: "2.5", displayName: "rate")), + .textInput(.init(key: "tags", value: "apple,banana,mango", displayName: "tags")), ]), .init(section: .group("Feature 1"), items: [ - .textInput(.init(key: "maxScore", value: "100")), - .textInput(.init(key: "maxRate", value: "0.99")), + .textInput(.init(key: "maxScore", value: "100", displayName: "maxScore")), + .textInput(.init(key: "maxRate", value: "0.99", displayName: "maxRate")), ]), .init(section: .group("Feature 2"), items: [ - .textInput(.init(key: "height", value: "44.0")), - .textInput(.init(key: "width", value: "320.0")), + .textInput(.init(key: "height", value: "44.0", displayName: "height")), + .textInput(.init(key: "width", value: "320.0", displayName: "width")), ]), .init(section: .group("Feature 3"), items: [ .optionSelection(.init(key: "accountType", value: "Admin", choices: [ .init(displayName: "Guest", value: "0"), .init(displayName: "Member", value: "1"), .init(displayName: "Admin", value: "2"), - ])), - .textInput(.init(key: "contact", value: "{\"name\":\"Ken\",\"phoneNumber\":\"2222 5678\"}")), + ], displayName: "Account Type")), + .textInput(.init(key: "contact", value: "{\"name\":\"Ken\",\"phoneNumber\":\"2222 5678\"}", displayName: "Contact")), ]), ]), ]) @@ -460,30 +460,30 @@ final class XConfigsTests: XCTestCase { .actionButton(title: "Reset", action: .showResetConfirmation("Are you sure you want to reset these values?")), ]), .init(section: .group(""), items: [ - .toggle(.init(key: "isOnboardingEnabled", value: true)), - .textInput(.init(key: "apiURL", value: "https://prod.google.com")), - .textInput(.init(key: "apiVersion", value: "v1.2.3")), - .optionSelection(.init(key: "region", value: "north", choices: regionChoices)), - .textInput(.init(key: "maxRetry", value: "10")), - .textInput(.init(key: "threshold", value: "1")), - .textInput(.init(key: "rate", value: "2.5")), - .textInput(.init(key: "tags", value: "apple,banana,mango")), + .toggle(.init(key: "isOnboardingEnabled", value: true, displayName: "isOnboardingEnabled")), + .textInput(.init(key: "apiURL", value: "https://prod.google.com", displayName: "apiURL")), + .textInput(.init(key: "apiVersion", value: "v1.2.3", displayName: "apiVersion")), + .optionSelection(.init(key: "region", value: "north", choices: regionChoices, displayName: "region")), + .textInput(.init(key: "maxRetry", value: "10", displayName: "maxRetry")), + .textInput(.init(key: "threshold", value: "1", displayName: "threshold")), + .textInput(.init(key: "rate", value: "2.5", displayName: "rate")), + .textInput(.init(key: "tags", value: "apple,banana,mango", displayName: "tags")), ]), .init(section: .group("Feature 1"), items: [ - .textInput(.init(key: "maxScore", value: "100")), - .textInput(.init(key: "maxRate", value: "1.0")), + .textInput(.init(key: "maxScore", value: "100", displayName: "maxScore")), + .textInput(.init(key: "maxRate", value: "1.0", displayName: "maxRate")), ]), .init(section: .group("Feature 2"), items: [ - .textInput(.init(key: "height", value: "44.0")), - .textInput(.init(key: "width", value: "320.0")), + .textInput(.init(key: "height", value: "44.0", displayName: "height")), + .textInput(.init(key: "width", value: "320.0", displayName: "width")), ]), .init(section: .group("Feature 3"), items: [ .optionSelection(.init(key: "accountType", value: "Guest", choices: [ .init(displayName: "Guest", value: "0"), .init(displayName: "Member", value: "1"), .init(displayName: "Admin", value: "2"), - ])), - .textInput(.init(key: "contact", value: "{\"name\":\"Ken\",\"phoneNumber\":\"1234 5678\"}")), + ], displayName: "Account Type")), + .textInput(.init(key: "contact", value: "{\"name\":\"Ken\",\"phoneNumber\":\"1234 5678\"}", displayName: "Contact")), ]), ]), .next(1, [ @@ -492,30 +492,30 @@ final class XConfigsTests: XCTestCase { .actionButton(title: "Reset", action: .showResetConfirmation("Are you sure you want to reset these values?")), ]), .init(section: .group(""), items: [ - .toggle(.init(key: "isOnboardingEnabled", value: true)), - .textInput(.init(key: "apiURL", value: "https://prod.google.com")), - .textInput(.init(key: "apiVersion", value: "v1.2.3")), - .optionSelection(.init(key: "region", value: "north", choices: regionChoices)), - .textInput(.init(key: "maxRetry", value: "20")), - .textInput(.init(key: "threshold", value: "1")), - .textInput(.init(key: "rate", value: "2.5")), - .textInput(.init(key: "tags", value: "apple,banana,mango")), + .toggle(.init(key: "isOnboardingEnabled", value: true, displayName: "isOnboardingEnabled")), + .textInput(.init(key: "apiURL", value: "https://prod.google.com", displayName: "apiURL")), + .textInput(.init(key: "apiVersion", value: "v1.2.3", displayName: "apiVersion")), + .optionSelection(.init(key: "region", value: "north", choices: regionChoices, displayName: "region")), + .textInput(.init(key: "maxRetry", value: "20", displayName: "maxRetry")), + .textInput(.init(key: "threshold", value: "1", displayName: "threshold")), + .textInput(.init(key: "rate", value: "2.5", displayName: "rate")), + .textInput(.init(key: "tags", value: "apple,banana,mango", displayName: "tags")), ]), .init(section: .group("Feature 1"), items: [ - .textInput(.init(key: "maxScore", value: "100")), - .textInput(.init(key: "maxRate", value: "1.0")), + .textInput(.init(key: "maxScore", value: "100", displayName: "maxScore")), + .textInput(.init(key: "maxRate", value: "1.0", displayName: "maxRate")), ]), .init(section: .group("Feature 2"), items: [ - .textInput(.init(key: "height", value: "44.0")), - .textInput(.init(key: "width", value: "320.0")), + .textInput(.init(key: "height", value: "44.0", displayName: "height")), + .textInput(.init(key: "width", value: "320.0", displayName: "width")), ]), .init(section: .group("Feature 3"), items: [ .optionSelection(.init(key: "accountType", value: "Guest", choices: [ .init(displayName: "Guest", value: "0"), .init(displayName: "Member", value: "1"), .init(displayName: "Admin", value: "2"), - ])), - .textInput(.init(key: "contact", value: "{\"name\":\"Ken\",\"phoneNumber\":\"1234 5678\"}")), + ], displayName: "Account Type")), + .textInput(.init(key: "contact", value: "{\"name\":\"Ken\",\"phoneNumber\":\"1234 5678\"}", displayName: "Contact")), ]), ]), .next(2, [ @@ -524,30 +524,30 @@ final class XConfigsTests: XCTestCase { .actionButton(title: "Reset", action: .showResetConfirmation("Are you sure you want to reset these values?")), ]), .init(section: .group(""), items: [ - .toggle(.init(key: "isOnboardingEnabled", value: true)), - .textInput(.init(key: "apiURL", value: "https://prod.google.com")), - .textInput(.init(key: "apiVersion", value: "v1.2.3")), - .optionSelection(.init(key: "region", value: "north", choices: regionChoices)), - .textInput(.init(key: "maxRetry", value: "20")), - .textInput(.init(key: "threshold", value: "1")), - .textInput(.init(key: "rate", value: "2.5")), - .textInput(.init(key: "tags", value: "apple,banana,mango")), + .toggle(.init(key: "isOnboardingEnabled", value: true, displayName: "isOnboardingEnabled")), + .textInput(.init(key: "apiURL", value: "https://prod.google.com", displayName: "apiURL")), + .textInput(.init(key: "apiVersion", value: "v1.2.3", displayName: "apiVersion")), + .optionSelection(.init(key: "region", value: "north", choices: regionChoices, displayName: "region")), + .textInput(.init(key: "maxRetry", value: "20", displayName: "maxRetry")), + .textInput(.init(key: "threshold", value: "1", displayName: "threshold")), + .textInput(.init(key: "rate", value: "2.5", displayName: "rate")), + .textInput(.init(key: "tags", value: "apple,banana,mango", displayName: "tags")), ]), .init(section: .group("Feature 1"), items: [ - .textInput(.init(key: "maxScore", value: "100")), - .textInput(.init(key: "maxRate", value: "0.99")), + .textInput(.init(key: "maxScore", value: "100", displayName: "maxScore")), + .textInput(.init(key: "maxRate", value: "0.99", displayName: "maxRate")), ]), .init(section: .group("Feature 2"), items: [ - .textInput(.init(key: "height", value: "44.0")), - .textInput(.init(key: "width", value: "320.0")), + .textInput(.init(key: "height", value: "44.0", displayName: "height")), + .textInput(.init(key: "width", value: "320.0", displayName: "width")), ]), .init(section: .group("Feature 3"), items: [ .optionSelection(.init(key: "accountType", value: "Guest", choices: [ .init(displayName: "Guest", value: "0"), .init(displayName: "Member", value: "1"), .init(displayName: "Admin", value: "2"), - ])), - .textInput(.init(key: "contact", value: "{\"name\":\"Ken\",\"phoneNumber\":\"1234 5678\"}")), + ], displayName: "Account Type")), + .textInput(.init(key: "contact", value: "{\"name\":\"Ken\",\"phoneNumber\":\"1234 5678\"}", displayName: "Contact")), ]), ]), .next(3, [ @@ -556,30 +556,30 @@ final class XConfigsTests: XCTestCase { .actionButton(title: "Reset", action: .showResetConfirmation("Are you sure you want to reset these values?")), ]), .init(section: .group(""), items: [ - .toggle(.init(key: "isOnboardingEnabled", value: true)), - .textInput(.init(key: "apiURL", value: "https://prod.google.com")), - .textInput(.init(key: "apiVersion", value: "v1.2.3")), - .optionSelection(.init(key: "region", value: "north", choices: regionChoices)), - .textInput(.init(key: "maxRetry", value: "20")), - .textInput(.init(key: "threshold", value: "1")), - .textInput(.init(key: "rate", value: "2.5")), - .textInput(.init(key: "tags", value: "apple,banana")), + .toggle(.init(key: "isOnboardingEnabled", value: true, displayName: "isOnboardingEnabled")), + .textInput(.init(key: "apiURL", value: "https://prod.google.com", displayName: "apiURL")), + .textInput(.init(key: "apiVersion", value: "v1.2.3", displayName: "apiVersion")), + .optionSelection(.init(key: "region", value: "north", choices: regionChoices, displayName: "region")), + .textInput(.init(key: "maxRetry", value: "20", displayName: "maxRetry")), + .textInput(.init(key: "threshold", value: "1", displayName: "threshold")), + .textInput(.init(key: "rate", value: "2.5", displayName: "rate")), + .textInput(.init(key: "tags", value: "apple,banana", displayName: "tags")), ]), .init(section: .group("Feature 1"), items: [ - .textInput(.init(key: "maxScore", value: "100")), - .textInput(.init(key: "maxRate", value: "0.99")), + .textInput(.init(key: "maxScore", value: "100", displayName: "maxScore")), + .textInput(.init(key: "maxRate", value: "0.99", displayName: "maxRate")), ]), .init(section: .group("Feature 2"), items: [ - .textInput(.init(key: "height", value: "44.0")), - .textInput(.init(key: "width", value: "320.0")), + .textInput(.init(key: "height", value: "44.0", displayName: "height")), + .textInput(.init(key: "width", value: "320.0", displayName: "width")), ]), .init(section: .group("Feature 3"), items: [ .optionSelection(.init(key: "accountType", value: "Guest", choices: [ .init(displayName: "Guest", value: "0"), .init(displayName: "Member", value: "1"), .init(displayName: "Admin", value: "2"), - ])), - .textInput(.init(key: "contact", value: "{\"name\":\"Ken\",\"phoneNumber\":\"1234 5678\"}")), + ], displayName: "Account Type")), + .textInput(.init(key: "contact", value: "{\"name\":\"Ken\",\"phoneNumber\":\"1234 5678\"}", displayName: "Contact")), ]), ]), .next(4, [ @@ -588,30 +588,30 @@ final class XConfigsTests: XCTestCase { .actionButton(title: "Reset", action: .showResetConfirmation("Are you sure you want to reset these values?")), ]), .init(section: .group(""), items: [ - .toggle(.init(key: "isOnboardingEnabled", value: true)), // uses remote - .textInput(.init(key: "apiURL", value: "https://prod.google.com")), // uses remote - .textInput(.init(key: "apiVersion", value: "v1.2.3")), - .optionSelection(.init(key: "region", value: "north", choices: regionChoices)), - .textInput(.init(key: "maxRetry", value: "10")), - .textInput(.init(key: "threshold", value: "1")), - .textInput(.init(key: "rate", value: "2.5")), - .textInput(.init(key: "tags", value: "apple,banana,mango")), + .toggle(.init(key: "isOnboardingEnabled", value: true, displayName: "isOnboardingEnabled")), // uses remote + .textInput(.init(key: "apiURL", value: "https://prod.google.com", displayName: "apiURL")), // uses remote + .textInput(.init(key: "apiVersion", value: "v1.2.3", displayName: "apiVersion")), + .optionSelection(.init(key: "region", value: "north", choices: regionChoices, displayName: "region")), + .textInput(.init(key: "maxRetry", value: "10", displayName: "maxRetry")), + .textInput(.init(key: "threshold", value: "1", displayName: "threshold")), + .textInput(.init(key: "rate", value: "2.5", displayName: "rate")), + .textInput(.init(key: "tags", value: "apple,banana,mango", displayName: "tags")), ]), .init(section: .group("Feature 1"), items: [ - .textInput(.init(key: "maxScore", value: "100")), - .textInput(.init(key: "maxRate", value: "1.0")), + .textInput(.init(key: "maxScore", value: "100", displayName: "maxScore")), + .textInput(.init(key: "maxRate", value: "1.0", displayName: "maxRate")), ]), .init(section: .group("Feature 2"), items: [ - .textInput(.init(key: "height", value: "44.0")), - .textInput(.init(key: "width", value: "320.0")), + .textInput(.init(key: "height", value: "44.0", displayName: "height")), + .textInput(.init(key: "width", value: "320.0", displayName: "width")), ]), .init(section: .group("Feature 3"), items: [ .optionSelection(.init(key: "accountType", value: "Guest", choices: [ .init(displayName: "Guest", value: "0"), .init(displayName: "Member", value: "1"), .init(displayName: "Admin", value: "2"), - ])), - .textInput(.init(key: "contact", value: "{\"name\":\"Ken\",\"phoneNumber\":\"1234 5678\"}")), + ], displayName: "Account Type")), + .textInput(.init(key: "contact", value: "{\"name\":\"Ken\",\"phoneNumber\":\"1234 5678\"}", displayName: "Contact")), ]), ]), ]) @@ -628,9 +628,9 @@ final class XConfigsTests: XCTestCase { scheduler .createColdObservable([ - .next(0, .textInput(.init(key: "textInputA", value: "Text Input A"))), - .next(1, .toggle(.init(key: "toggleA", value: false))), - .next(2, .optionSelection(.init(key: "options", value: "optionA", choices: [.init(displayName: "Option A", value: "optionA"), .init(displayName: "Option B", value: "optionB")]))), + .next(0, .textInput(.init(key: "textInputA", value: "Text Input A", displayName: "Text Input A"))), + .next(1, .toggle(.init(key: "toggleA", value: false, displayName: "Toggle A"))), + .next(2, .optionSelection(.init(key: "options", value: "optionA", choices: [.init(displayName: "Option A", value: "optionA"), .init(displayName: "Option B", value: "optionB")], displayName: "Options"))), .next(3, .actionButton(title: "Reset", action: .showResetConfirmation("Do you want to reset?"))), ]).bind(to: selectItemPublisher) .disposed(by: disposeBag) @@ -646,8 +646,8 @@ final class XConfigsTests: XCTestCase { // MARK: OUTPUTS XCTAssertEqual(action.events, [ - .next(0, .showTextInput(.init(key: "textInputA", value: "Text Input A"))), - .next(2, .showOptionSelection(.init(key: "options", value: "optionA", choices: [.init(displayName: "Option A", value: "optionA"), .init(displayName: "Option B", value: "optionB")]))), + .next(0, .showTextInput(.init(key: "textInputA", value: "Text Input A", displayName: "Text Input A"))), + .next(2, .showOptionSelection(.init(key: "options", value: "optionA", choices: [.init(displayName: "Option A", value: "optionA"), .init(displayName: "Option B", value: "optionB")], displayName: "Options"))), .next(3, .showResetConfirmation("Do you want to reset?")), .next(4, .dismiss), ]) diff --git a/Sources/XConfigs/Models/InputModel.swift b/Sources/XConfigs/Models/InputModel.swift index ef04350..0d99505 100644 --- a/Sources/XConfigs/Models/InputModel.swift +++ b/Sources/XConfigs/Models/InputModel.swift @@ -3,4 +3,5 @@ import Foundation struct TextInputModel: Hashable { let key: String let value: String + let displayName: String } diff --git a/Sources/XConfigs/Models/OptionSelectionModel.swift b/Sources/XConfigs/Models/OptionSelectionModel.swift index c15ae8b..72bd648 100644 --- a/Sources/XConfigs/Models/OptionSelectionModel.swift +++ b/Sources/XConfigs/Models/OptionSelectionModel.swift @@ -9,4 +9,5 @@ struct OptionSelectionModel: Hashable { let key: String let value: String let choices: [Choice] + let displayName: String } diff --git a/Sources/XConfigs/Models/ToggleModel.swift b/Sources/XConfigs/Models/ToggleModel.swift index 26f6204..dbc3706 100644 --- a/Sources/XConfigs/Models/ToggleModel.swift +++ b/Sources/XConfigs/Models/ToggleModel.swift @@ -3,4 +3,5 @@ import Foundation struct ToggleModel: Hashable { let key: String let value: Bool + let displayName: String } diff --git a/Sources/XConfigs/PropertyWrappers/XConfig.swift b/Sources/XConfigs/PropertyWrappers/XConfig.swift index deea85d..646e34a 100644 --- a/Sources/XConfigs/PropertyWrappers/XConfig.swift +++ b/Sources/XConfigs/PropertyWrappers/XConfig.swift @@ -3,6 +3,7 @@ import Foundation @propertyWrapper public struct XConfig: ConfigInfo { public let key: String + public let displayName: String? public let defaultValue: Value public let group: XConfigGroup @@ -10,8 +11,9 @@ public struct XConfig: ConfigInfo { defaultConfigUseCase.get(for: key, defaultValue: defaultValue, group: group) } - public init(key: String, defaultValue: Value, group: XConfigGroup = .default) { + public init(key: String, displayName: String? = nil, defaultValue: Value, group: XConfigGroup = .default) { self.key = key + self.displayName = displayName self.defaultValue = defaultValue self.group = group } diff --git a/Sources/XConfigs/Protocols/ConfigInfo.swift b/Sources/XConfigs/Protocols/ConfigInfo.swift index eeaf922..a997446 100644 --- a/Sources/XConfigs/Protocols/ConfigInfo.swift +++ b/Sources/XConfigs/Protocols/ConfigInfo.swift @@ -2,6 +2,7 @@ import Foundation public protocol ConfigInfo { var configKey: String { get } + var displayName: String? { get } var configValue: RawStringValueRepresentable { get } var group: XConfigGroup { get } diff --git a/Sources/XConfigs/ViewControllers/XConfigsViewController.swift b/Sources/XConfigs/ViewControllers/XConfigsViewController.swift index f5a79fd..e4e2186 100644 --- a/Sources/XConfigs/ViewControllers/XConfigsViewController.swift +++ b/Sources/XConfigs/ViewControllers/XConfigsViewController.swift @@ -18,7 +18,7 @@ final class XConfigsViewController: UITableViewController { switch item { case let .toggle(vm): let cell = tableView.dequeueCell(UIViewTableWrapperCell.self, for: indexPath) - cell.configure(with: (vm.key, vm.value)) + cell.configure(with: (vm.displayName, vm.value)) cell.mainView.valueChangedPublisher .map { KeyValue(key: vm.key, value: $0) } .bind(to: self.updateValueSubject) @@ -27,11 +27,11 @@ final class XConfigsViewController: UITableViewController { return cell case let .textInput(vm): let cell = tableView.dequeueCell(UIViewTableWrapperCell.self, for: indexPath) - cell.configure(with: (vm.key, vm.value)) + cell.configure(with: (vm.displayName, vm.value)) return cell case let .optionSelection(vm): let cell = tableView.dequeueCell(UIViewTableWrapperCell.self, for: indexPath) - cell.configure(with: (vm.key, vm.value)) + cell.configure(with: (vm.displayName, vm.value)) return cell case let .actionButton(title, _): let cell = tableView.dequeueCell(UIViewTableWrapperCell.self, for: indexPath) diff --git a/Sources/XConfigs/ViewModels/XConfigsViewModel.swift b/Sources/XConfigs/ViewModels/XConfigsViewModel.swift index a49d7c1..16c6436 100644 --- a/Sources/XConfigs/ViewModels/XConfigsViewModel.swift +++ b/Sources/XConfigs/ViewModels/XConfigsViewModel.swift @@ -116,15 +116,16 @@ struct XConfigsViewModel: ViewModelType { let key = info.configKey switch info.configValue { case let val as Bool: - return .toggle(.init(key: key, value: val)) + return .toggle(.init(key: key, value: val, displayName: info.displayName ?? info.configKey)) case let val as any CaseIterable & RawStringValueRepresentable: return .optionSelection(.init( key: key, value: (val as? CustomStringConvertible)?.description ?? val.rawString, - choices: val.allChoices + choices: val.allChoices, + displayName: info.displayName ?? info.configKey )) default: - return .textInput(.init(key: key, value: info.configValue.rawString)) + return .textInput(.init(key: key, value: info.configValue.rawString, displayName: info.displayName ?? info.configKey)) } } }