[Features] Adds @Feature property wrapper
Simplifies defining feature flags that can enabled + disabled via UserDefaults.
This commit is contained in:
parent
3fb7e8b4b7
commit
d613cc9ad7
@ -186,6 +186,7 @@
|
|||||||
D5D797E9298DCC7300738869 /* cheatbase.zip in Resources */ = {isa = PBXBuildFile; fileRef = D5D797E7298DC9E200738869 /* cheatbase.zip */; };
|
D5D797E9298DCC7300738869 /* cheatbase.zip in Resources */ = {isa = PBXBuildFile; fileRef = D5D797E7298DC9E200738869 /* cheatbase.zip */; };
|
||||||
D5D7C1FA29E60EDE00663793 /* libDeltaFeatures.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D5D7C1F129E60DFF00663793 /* libDeltaFeatures.a */; };
|
D5D7C1FA29E60EDE00663793 /* libDeltaFeatures.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D5D7C1F129E60DFF00663793 /* libDeltaFeatures.a */; };
|
||||||
D5D7C20429E60F2000663793 /* Feature.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A9BFFD29DDECF100A8D610 /* Feature.swift */; };
|
D5D7C20429E60F2000663793 /* Feature.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A9BFFD29DDECF100A8D610 /* Feature.swift */; };
|
||||||
|
D5D7C20829E616CF00663793 /* FeatureContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5D7C20729E616CF00663793 /* FeatureContainer.swift */; };
|
||||||
D5F82FB82981D3AC00B229AF /* LegacySearchBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F82FB72981D3AC00B229AF /* LegacySearchBar.swift */; };
|
D5F82FB82981D3AC00B229AF /* LegacySearchBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F82FB72981D3AC00B229AF /* LegacySearchBar.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
@ -419,6 +420,7 @@
|
|||||||
D5D797E5298D946200738869 /* Contributor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Contributor.swift; sourceTree = "<group>"; };
|
D5D797E5298D946200738869 /* Contributor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Contributor.swift; sourceTree = "<group>"; };
|
||||||
D5D797E7298DC9E200738869 /* cheatbase.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = cheatbase.zip; sourceTree = "<group>"; };
|
D5D797E7298DC9E200738869 /* cheatbase.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = cheatbase.zip; sourceTree = "<group>"; };
|
||||||
D5D7C1F129E60DFF00663793 /* libDeltaFeatures.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libDeltaFeatures.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
D5D7C1F129E60DFF00663793 /* libDeltaFeatures.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libDeltaFeatures.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
D5D7C20729E616CF00663793 /* FeatureContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureContainer.swift; sourceTree = "<group>"; };
|
||||||
D5F82FB72981D3AC00B229AF /* LegacySearchBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacySearchBar.swift; sourceTree = "<group>"; };
|
D5F82FB72981D3AC00B229AF /* LegacySearchBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacySearchBar.swift; sourceTree = "<group>"; };
|
||||||
DC866E433B3BA9AE18ABA1EC /* libPods-Delta.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Delta.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
DC866E433B3BA9AE18ABA1EC /* libPods-Delta.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Delta.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
@ -1013,6 +1015,7 @@
|
|||||||
children = (
|
children = (
|
||||||
D5A9BFFD29DDECF100A8D610 /* Feature.swift */,
|
D5A9BFFD29DDECF100A8D610 /* Feature.swift */,
|
||||||
D517F6BB29E737F5000D14D0 /* Types */,
|
D517F6BB29E737F5000D14D0 /* Types */,
|
||||||
|
D5D7C1FE29E60EF700663793 /* Protocols */,
|
||||||
D5D7C1F829E60E8600663793 /* Extensions */,
|
D5D7C1F829E60E8600663793 /* Extensions */,
|
||||||
);
|
);
|
||||||
path = DeltaFeatures;
|
path = DeltaFeatures;
|
||||||
@ -1026,6 +1029,14 @@
|
|||||||
path = Extensions;
|
path = Extensions;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
D5D7C1FE29E60EF700663793 /* Protocols */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
D5D7C20729E616CF00663793 /* FeatureContainer.swift */,
|
||||||
|
);
|
||||||
|
path = Protocols;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
FD1E8AE87FA2DB8793F7B937 /* Pods */ = {
|
FD1E8AE87FA2DB8793F7B937 /* Pods */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -1504,6 +1515,7 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
D5D7C20829E616CF00663793 /* FeatureContainer.swift in Sources */,
|
||||||
D517F6BA29E730DA000D14D0 /* SettingsName.swift in Sources */,
|
D517F6BA29E730DA000D14D0 /* SettingsName.swift in Sources */,
|
||||||
D5D7C20429E60F2000663793 /* Feature.swift in Sources */,
|
D5D7C20429E60F2000663793 /* Feature.swift in Sources */,
|
||||||
D54F710429E89DFC009C069A /* NotificationName+Settings.swift in Sources */,
|
D54F710429E89DFC009C069A /* NotificationName+Settings.swift in Sources */,
|
||||||
|
|||||||
@ -6,5 +6,43 @@
|
|||||||
// Copyright © 2023 Riley Testut. All rights reserved.
|
// Copyright © 2023 Riley Testut. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import SwiftUI
|
||||||
|
import Combine
|
||||||
|
|
||||||
|
@propertyWrapper @dynamicMemberLookup
|
||||||
|
public final class Feature
|
||||||
|
{
|
||||||
|
public let name: LocalizedStringKey
|
||||||
|
public let description: LocalizedStringKey?
|
||||||
|
|
||||||
|
// Assigned to property name.
|
||||||
|
public internal(set) var key: String = ""
|
||||||
|
|
||||||
|
// Used for `SettingsUserInfoKey.name` value in .settingsDidChange notification.
|
||||||
|
public var settingsKey: SettingsName {
|
||||||
|
return SettingsName(rawValue: self.key)
|
||||||
|
}
|
||||||
|
|
||||||
|
public var isEnabled: Bool {
|
||||||
|
get {
|
||||||
|
let isEnabled = UserDefaults.standard.bool(forKey: self.key)
|
||||||
|
return isEnabled
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
self.objectWillChange.send()
|
||||||
|
UserDefaults.standard.set(newValue, forKey: self.key)
|
||||||
|
|
||||||
|
NotificationCenter.default.post(name: .settingsDidChange, object: nil, userInfo: [SettingsUserInfoKey.name: self.settingsKey, SettingsUserInfoKey.value: newValue])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var wrappedValue: Feature {
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(name: LocalizedStringKey, description: LocalizedStringKey? = nil)
|
||||||
|
{
|
||||||
|
self.name = name
|
||||||
|
self.description = description
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
36
DeltaFeatures/Protocols/FeatureContainer.swift
Normal file
36
DeltaFeatures/Protocols/FeatureContainer.swift
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
//
|
||||||
|
// FeatureContainer.swift
|
||||||
|
// DeltaFeatures
|
||||||
|
//
|
||||||
|
// Created by Riley Testut on 4/11/23.
|
||||||
|
// Copyright © 2023 Riley Testut. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
public protocol FeatureContainer
|
||||||
|
{
|
||||||
|
static var shared: Self { get }
|
||||||
|
}
|
||||||
|
|
||||||
|
public extension FeatureContainer
|
||||||
|
{
|
||||||
|
var allFeatures: [Feature] {
|
||||||
|
let features = Mirror(reflecting: self).children.compactMap { (child) -> Feature? in
|
||||||
|
let feature = child.value as? Feature
|
||||||
|
return feature
|
||||||
|
}
|
||||||
|
return features
|
||||||
|
}
|
||||||
|
|
||||||
|
func prepareFeatures()
|
||||||
|
{
|
||||||
|
// Assign keys to property names.
|
||||||
|
for case (let key?, let feature as Feature) in Mirror(reflecting: self).children
|
||||||
|
{
|
||||||
|
// Remove leading underscore.
|
||||||
|
let sanitizedKey = key.dropFirst()
|
||||||
|
feature.key = String(sanitizedKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user