mirror of
https://github.com/somegeekintn/SimDirs.git
synced 2026-04-27 14:57:40 +00:00
Restructuring of model data, item organization. rudimentary search
This commit is contained in:
parent
019df42354
commit
4a5876222a
17 changed files with 267 additions and 183 deletions
|
|
@ -9,11 +9,14 @@
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
C927A0D92846414900533D66 /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = C927A0D82846414900533D66 /* Helpers.swift */; };
|
C927A0D92846414900533D66 /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = C927A0D82846414900533D66 /* Helpers.swift */; };
|
||||||
C927A0DB2846502300533D66 /* PathActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C927A0DA2846502300533D66 /* PathActions.swift */; };
|
C927A0DB2846502300533D66 /* PathActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C927A0DA2846502300533D66 /* PathActions.swift */; };
|
||||||
C94C52C52844E7D400E2129E /* SimItemList.swift in Sources */ = {isa = PBXBuildFile; fileRef = C94C52C42844E7D400E2129E /* SimItemList.swift */; };
|
|
||||||
C94C52C72844E80A00E2129E /* SimItemRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = C94C52C62844E80A00E2129E /* SimItemRow.swift */; };
|
C94C52C72844E80A00E2129E /* SimItemRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = C94C52C62844E80A00E2129E /* SimItemRow.swift */; };
|
||||||
C94C52C92844E99B00E2129E /* SimItemContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C94C52C82844E99B00E2129E /* SimItemContent.swift */; };
|
C94C52C92844E99B00E2129E /* SimItemContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C94C52C82844E99B00E2129E /* SimItemContent.swift */; };
|
||||||
C94C52CB2844EAAC00E2129E /* RuntimeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C94C52CA2844EAAC00E2129E /* RuntimeView.swift */; };
|
C94C52CB2844EAAC00E2129E /* RuntimeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C94C52CA2844EAAC00E2129E /* RuntimeView.swift */; };
|
||||||
C95E5AB6284B6DDE00A2124E /* AppView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C95E5AB5284B6DDE00A2124E /* AppView.swift */; };
|
C95E5AB6284B6DDE00A2124E /* AppView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C95E5AB5284B6DDE00A2124E /* AppView.swift */; };
|
||||||
|
C977973C284F58A900706DFB /* PresentationState.swift in Sources */ = {isa = PBXBuildFile; fileRef = C977973B284F58A900706DFB /* PresentationState.swift */; };
|
||||||
|
C977973E284F5AE100706DFB /* SimItemNavLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = C977973D284F5AE100706DFB /* SimItemNavLink.swift */; };
|
||||||
|
C9779740284F5CBB00706DFB /* SimItemGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = C977973F284F5CBB00706DFB /* SimItemGroup.swift */; };
|
||||||
|
C9779742284F6DE000706DFB /* ToolbarMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9779741284F6DE000706DFB /* ToolbarMenu.swift */; };
|
||||||
C982F859283B9F9000D491F4 /* SimDirsApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = C982F858283B9F9000D491F4 /* SimDirsApp.swift */; };
|
C982F859283B9F9000D491F4 /* SimDirsApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = C982F858283B9F9000D491F4 /* SimDirsApp.swift */; };
|
||||||
C982F85B283B9F9000D491F4 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C982F85A283B9F9000D491F4 /* ContentView.swift */; };
|
C982F85B283B9F9000D491F4 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C982F85A283B9F9000D491F4 /* ContentView.swift */; };
|
||||||
C982F85D283B9F9200D491F4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C982F85C283B9F9200D491F4 /* Assets.xcassets */; };
|
C982F85D283B9F9200D491F4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C982F85C283B9F9200D491F4 /* Assets.xcassets */; };
|
||||||
|
|
@ -25,7 +28,6 @@
|
||||||
C982F877283D020C00D491F4 /* SimProductFamily.swift in Sources */ = {isa = PBXBuildFile; fileRef = C982F876283D020C00D491F4 /* SimProductFamily.swift */; };
|
C982F877283D020C00D491F4 /* SimProductFamily.swift in Sources */ = {isa = PBXBuildFile; fileRef = C982F876283D020C00D491F4 /* SimProductFamily.swift */; };
|
||||||
C982F879283D042E00D491F4 /* SimModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C982F878283D042E00D491F4 /* SimModel.swift */; };
|
C982F879283D042E00D491F4 /* SimModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C982F878283D042E00D491F4 /* SimModel.swift */; };
|
||||||
C982F87B283E40C800D491F4 /* SimCtl.swift in Sources */ = {isa = PBXBuildFile; fileRef = C982F87A283E40C800D491F4 /* SimCtl.swift */; };
|
C982F87B283E40C800D491F4 /* SimCtl.swift in Sources */ = {isa = PBXBuildFile; fileRef = C982F87A283E40C800D491F4 /* SimCtl.swift */; };
|
||||||
C982F87E283E57B200D491F4 /* PresentableModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C982F87D283E57B200D491F4 /* PresentableModel.swift */; };
|
|
||||||
C982F880283E57E600D491F4 /* PresentationItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C982F87F283E57E600D491F4 /* PresentationItem.swift */; };
|
C982F880283E57E600D491F4 /* PresentationItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C982F87F283E57E600D491F4 /* PresentationItem.swift */; };
|
||||||
C982F883283E813F00D491F4 /* DeviceTypeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C982F882283E813F00D491F4 /* DeviceTypeView.swift */; };
|
C982F883283E813F00D491F4 /* DeviceTypeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C982F882283E813F00D491F4 /* DeviceTypeView.swift */; };
|
||||||
C9D729F128478AB00064152D /* DeviceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9D729F028478AB00064152D /* DeviceView.swift */; };
|
C9D729F128478AB00064152D /* DeviceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9D729F028478AB00064152D /* DeviceView.swift */; };
|
||||||
|
|
@ -36,11 +38,14 @@
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
C927A0D82846414900533D66 /* Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Helpers.swift; sourceTree = "<group>"; };
|
C927A0D82846414900533D66 /* Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Helpers.swift; sourceTree = "<group>"; };
|
||||||
C927A0DA2846502300533D66 /* PathActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PathActions.swift; sourceTree = "<group>"; };
|
C927A0DA2846502300533D66 /* PathActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PathActions.swift; sourceTree = "<group>"; };
|
||||||
C94C52C42844E7D400E2129E /* SimItemList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimItemList.swift; sourceTree = "<group>"; };
|
|
||||||
C94C52C62844E80A00E2129E /* SimItemRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimItemRow.swift; sourceTree = "<group>"; };
|
C94C52C62844E80A00E2129E /* SimItemRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimItemRow.swift; sourceTree = "<group>"; };
|
||||||
C94C52C82844E99B00E2129E /* SimItemContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimItemContent.swift; sourceTree = "<group>"; };
|
C94C52C82844E99B00E2129E /* SimItemContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimItemContent.swift; sourceTree = "<group>"; };
|
||||||
C94C52CA2844EAAC00E2129E /* RuntimeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuntimeView.swift; sourceTree = "<group>"; };
|
C94C52CA2844EAAC00E2129E /* RuntimeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuntimeView.swift; sourceTree = "<group>"; };
|
||||||
C95E5AB5284B6DDE00A2124E /* AppView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppView.swift; sourceTree = "<group>"; };
|
C95E5AB5284B6DDE00A2124E /* AppView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppView.swift; sourceTree = "<group>"; };
|
||||||
|
C977973B284F58A900706DFB /* PresentationState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PresentationState.swift; sourceTree = "<group>"; };
|
||||||
|
C977973D284F5AE100706DFB /* SimItemNavLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimItemNavLink.swift; sourceTree = "<group>"; };
|
||||||
|
C977973F284F5CBB00706DFB /* SimItemGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimItemGroup.swift; sourceTree = "<group>"; };
|
||||||
|
C9779741284F6DE000706DFB /* ToolbarMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToolbarMenu.swift; sourceTree = "<group>"; };
|
||||||
C982F855283B9F9000D491F4 /* SimDirs.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SimDirs.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
C982F855283B9F9000D491F4 /* SimDirs.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SimDirs.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
C982F858283B9F9000D491F4 /* SimDirsApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimDirsApp.swift; sourceTree = "<group>"; };
|
C982F858283B9F9000D491F4 /* SimDirsApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimDirsApp.swift; sourceTree = "<group>"; };
|
||||||
C982F85A283B9F9000D491F4 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
C982F85A283B9F9000D491F4 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
||||||
|
|
@ -54,7 +59,6 @@
|
||||||
C982F876283D020C00D491F4 /* SimProductFamily.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimProductFamily.swift; sourceTree = "<group>"; };
|
C982F876283D020C00D491F4 /* SimProductFamily.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimProductFamily.swift; sourceTree = "<group>"; };
|
||||||
C982F878283D042E00D491F4 /* SimModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimModel.swift; sourceTree = "<group>"; };
|
C982F878283D042E00D491F4 /* SimModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimModel.swift; sourceTree = "<group>"; };
|
||||||
C982F87A283E40C800D491F4 /* SimCtl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimCtl.swift; sourceTree = "<group>"; };
|
C982F87A283E40C800D491F4 /* SimCtl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimCtl.swift; sourceTree = "<group>"; };
|
||||||
C982F87D283E57B200D491F4 /* PresentableModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PresentableModel.swift; sourceTree = "<group>"; };
|
|
||||||
C982F87F283E57E600D491F4 /* PresentationItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PresentationItem.swift; sourceTree = "<group>"; };
|
C982F87F283E57E600D491F4 /* PresentationItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PresentationItem.swift; sourceTree = "<group>"; };
|
||||||
C982F882283E813F00D491F4 /* DeviceTypeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceTypeView.swift; sourceTree = "<group>"; };
|
C982F882283E813F00D491F4 /* DeviceTypeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceTypeView.swift; sourceTree = "<group>"; };
|
||||||
C9D729F028478AB00064152D /* DeviceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceView.swift; sourceTree = "<group>"; };
|
C9D729F028478AB00064152D /* DeviceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceView.swift; sourceTree = "<group>"; };
|
||||||
|
|
@ -131,8 +135,8 @@
|
||||||
C982F87C283E579900D491F4 /* Presentation */ = {
|
C982F87C283E579900D491F4 /* Presentation */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
C982F87D283E57B200D491F4 /* PresentableModel.swift */,
|
|
||||||
C982F87F283E57E600D491F4 /* PresentationItem.swift */,
|
C982F87F283E57E600D491F4 /* PresentationItem.swift */,
|
||||||
|
C977973B284F58A900706DFB /* PresentationState.swift */,
|
||||||
);
|
);
|
||||||
path = Presentation;
|
path = Presentation;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|
@ -147,8 +151,10 @@
|
||||||
C9EE0CD128478FDB00E9B97A /* PathRow.swift */,
|
C9EE0CD128478FDB00E9B97A /* PathRow.swift */,
|
||||||
C94C52CA2844EAAC00E2129E /* RuntimeView.swift */,
|
C94C52CA2844EAAC00E2129E /* RuntimeView.swift */,
|
||||||
C94C52C82844E99B00E2129E /* SimItemContent.swift */,
|
C94C52C82844E99B00E2129E /* SimItemContent.swift */,
|
||||||
C94C52C42844E7D400E2129E /* SimItemList.swift */,
|
C977973F284F5CBB00706DFB /* SimItemGroup.swift */,
|
||||||
|
C977973D284F5AE100706DFB /* SimItemNavLink.swift */,
|
||||||
C94C52C62844E80A00E2129E /* SimItemRow.swift */,
|
C94C52C62844E80A00E2129E /* SimItemRow.swift */,
|
||||||
|
C9779741284F6DE000706DFB /* ToolbarMenu.swift */,
|
||||||
);
|
);
|
||||||
path = Views;
|
path = Views;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|
@ -227,10 +233,14 @@
|
||||||
C94C52C92844E99B00E2129E /* SimItemContent.swift in Sources */,
|
C94C52C92844E99B00E2129E /* SimItemContent.swift in Sources */,
|
||||||
C927A0DB2846502300533D66 /* PathActions.swift in Sources */,
|
C927A0DB2846502300533D66 /* PathActions.swift in Sources */,
|
||||||
C9EE0CD42847B79E00E9B97A /* SimApp.swift in Sources */,
|
C9EE0CD42847B79E00E9B97A /* SimApp.swift in Sources */,
|
||||||
|
C9779742284F6DE000706DFB /* ToolbarMenu.swift in Sources */,
|
||||||
|
C9779740284F5CBB00706DFB /* SimItemGroup.swift in Sources */,
|
||||||
C95E5AB6284B6DDE00A2124E /* AppView.swift in Sources */,
|
C95E5AB6284B6DDE00A2124E /* AppView.swift in Sources */,
|
||||||
C982F85B283B9F9000D491F4 /* ContentView.swift in Sources */,
|
C982F85B283B9F9000D491F4 /* ContentView.swift in Sources */,
|
||||||
C982F875283CEEBB00D491F4 /* SimDevice.swift in Sources */,
|
C982F875283CEEBB00D491F4 /* SimDevice.swift in Sources */,
|
||||||
|
C977973C284F58A900706DFB /* PresentationState.swift in Sources */,
|
||||||
C982F873283CE9AD00D491F4 /* SimDeviceType.swift in Sources */,
|
C982F873283CE9AD00D491F4 /* SimDeviceType.swift in Sources */,
|
||||||
|
C977973E284F5AE100706DFB /* SimItemNavLink.swift in Sources */,
|
||||||
C982F877283D020C00D491F4 /* SimProductFamily.swift in Sources */,
|
C982F877283D020C00D491F4 /* SimProductFamily.swift in Sources */,
|
||||||
C982F859283B9F9000D491F4 /* SimDirsApp.swift in Sources */,
|
C982F859283B9F9000D491F4 /* SimDirsApp.swift in Sources */,
|
||||||
C982F871283CE7B800D491F4 /* SimRuntime.swift in Sources */,
|
C982F871283CE7B800D491F4 /* SimRuntime.swift in Sources */,
|
||||||
|
|
@ -238,12 +248,10 @@
|
||||||
C94C52C72844E80A00E2129E /* SimItemRow.swift in Sources */,
|
C94C52C72844E80A00E2129E /* SimItemRow.swift in Sources */,
|
||||||
C982F86B283BA22100D491F4 /* SimPlatform.swift in Sources */,
|
C982F86B283BA22100D491F4 /* SimPlatform.swift in Sources */,
|
||||||
C927A0D92846414900533D66 /* Helpers.swift in Sources */,
|
C927A0D92846414900533D66 /* Helpers.swift in Sources */,
|
||||||
C982F87E283E57B200D491F4 /* PresentableModel.swift in Sources */,
|
|
||||||
C94C52CB2844EAAC00E2129E /* RuntimeView.swift in Sources */,
|
C94C52CB2844EAAC00E2129E /* RuntimeView.swift in Sources */,
|
||||||
C982F880283E57E600D491F4 /* PresentationItem.swift in Sources */,
|
C982F880283E57E600D491F4 /* PresentationItem.swift in Sources */,
|
||||||
C982F879283D042E00D491F4 /* SimModel.swift in Sources */,
|
C982F879283D042E00D491F4 /* SimModel.swift in Sources */,
|
||||||
C9D729F128478AB00064152D /* DeviceView.swift in Sources */,
|
C9D729F128478AB00064152D /* DeviceView.swift in Sources */,
|
||||||
C94C52C52844E7D400E2129E /* SimItemList.swift in Sources */,
|
|
||||||
C982F87B283E40C800D491F4 /* SimCtl.swift in Sources */,
|
C982F87B283E40C800D491F4 /* SimCtl.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
|
|
||||||
|
|
@ -8,15 +8,33 @@
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct ContentView: View {
|
struct ContentView: View {
|
||||||
|
let model : SimModel
|
||||||
|
var rootItems : [PresentationItem] { state.presentationItems(from: model) }
|
||||||
|
|
||||||
|
@State private var state = PresentationState(filter: [])
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
SimItemList()
|
NavigationView {
|
||||||
|
List {
|
||||||
|
ForEach(rootItems) { item in
|
||||||
|
SimItemGroup(item: item, state: $state)
|
||||||
|
}
|
||||||
|
.padding(.leading, 2.0)
|
||||||
|
}
|
||||||
|
.frame(minWidth: 200)
|
||||||
|
.toolbar {
|
||||||
|
ToolbarItem { ToolbarMenu(state: $state) }
|
||||||
|
}
|
||||||
|
Text("SimDirs")
|
||||||
|
}
|
||||||
|
.searchable(text: $state.searchTerm, placement: .sidebar)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ContentView_Previews: PreviewProvider {
|
struct ContentView_Previews: PreviewProvider {
|
||||||
|
static var simModel = SimModel()
|
||||||
|
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
ContentView()
|
ContentView(model: simModel)
|
||||||
.environmentObject(PresentableModel())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,13 @@ extension NSWorkspace {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension OptionSet where Self == Self.Element {
|
||||||
|
mutating func booleanSet(_ value: Bool, options: Self) {
|
||||||
|
if value { update(with: options) }
|
||||||
|
else { subtract(options) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extension PropertyListSerialization {
|
extension PropertyListSerialization {
|
||||||
class func propertyList(from url: URL) -> [String : AnyObject]? {
|
class func propertyList(from url: URL) -> [String : AnyObject]? {
|
||||||
guard let plistData = try? Data(contentsOf: url) else { return nil }
|
guard let plistData = try? Data(contentsOf: url) else { return nil }
|
||||||
|
|
|
||||||
|
|
@ -53,26 +53,43 @@ struct PresentationItem: Identifiable {
|
||||||
customImage = image
|
customImage = image
|
||||||
}
|
}
|
||||||
|
|
||||||
func filtered(_ filter: PresentationFilter) -> Self {
|
func titlesContain(_ searchTerm: String) -> Bool {
|
||||||
guard var childItems = self.children, !filter.isEmpty else { return self }
|
return title.contains(searchTerm) || children?.contains(where: { $0.titlesContain(searchTerm)}) ?? false
|
||||||
var filteredItem = self
|
|
||||||
|
|
||||||
if filter.contains(.withApps) {
|
|
||||||
childItems = childItems.filter { $0.containsType(SimApp.self) }
|
|
||||||
}
|
|
||||||
if filter.contains(.runtimeInstalled) {
|
|
||||||
childItems = childItems.filter {
|
|
||||||
guard let runtime = $0.underlying as? SimRuntime else { return true }
|
|
||||||
|
|
||||||
return runtime.isAvailable
|
|
||||||
}
|
|
||||||
}
|
|
||||||
filteredItem.children = childItems.isEmpty ? nil : childItems.map { $0.filtered(filter)}
|
|
||||||
|
|
||||||
return filteredItem
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func containsType<T> (_ type: T.Type) -> Bool {
|
func containsType<T>(_ type: T.Type) -> Bool {
|
||||||
return underlying is T || children?.contains(where: { $0.containsType(type)}) ?? false
|
return underlying is T || children?.contains(where: { $0.containsType(type)}) ?? false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension Array where Element == PresentationItem {
|
||||||
|
var flatItems : [PresentationItem] { self.flatMap { $0.flattened } }
|
||||||
|
|
||||||
|
func itemsOf<T> (type: T.Type) -> [T] {
|
||||||
|
return flatItems.compactMap { $0.underlying as? T }
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateItems() {
|
||||||
|
let allIDs = flatItems.map { $0.id }
|
||||||
|
var idSet = Set<String>()
|
||||||
|
|
||||||
|
print("Validating \(allIDs.count) items")
|
||||||
|
for id in allIDs {
|
||||||
|
if !idSet.insert(id).inserted {
|
||||||
|
print("Duplicate PresentationItem.id: \(id)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dumpPresentation(level: Int = 0) {
|
||||||
|
let ident = Array<String>(repeating: "\t", count: level).joined()
|
||||||
|
|
||||||
|
for item in self {
|
||||||
|
print("\(ident)\(item.title) [\(item.id)]")
|
||||||
|
|
||||||
|
if let children = item.children {
|
||||||
|
children.dumpPresentation(level: level + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,56 +1,53 @@
|
||||||
//
|
//
|
||||||
// PresentableModel.swift
|
// PresentationState.swift
|
||||||
// SimDirs
|
// SimDirs
|
||||||
//
|
//
|
||||||
// Created by Casey Fleser on 5/25/22.
|
// Created by Casey Fleser on 6/7/22.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct PresentationFilter: OptionSet, CaseIterable {
|
struct PresentationState {
|
||||||
let rawValue: Int
|
enum Organization: String, CaseIterable, Identifiable {
|
||||||
|
case byDevice = "By Device"
|
||||||
|
case byRuntime = "By Runtime"
|
||||||
|
|
||||||
static let withApps = PresentationFilter(rawValue: 1 << 0)
|
var id: Organization { self }
|
||||||
static let runtimeInstalled = PresentationFilter(rawValue: 1 << 1)
|
|
||||||
|
|
||||||
static var allCases : [PresentationFilter] = [.withApps, .runtimeInstalled]
|
|
||||||
}
|
|
||||||
|
|
||||||
class PresentableModel: ObservableObject {
|
|
||||||
enum Style {
|
|
||||||
case byDevice
|
|
||||||
case byRuntime
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var baseModel = SimModel()
|
struct Filter: OptionSet, CaseIterable {
|
||||||
var style = Style.byRuntime
|
let rawValue: Int
|
||||||
var items = [PresentationItem]()
|
|
||||||
var flatItems : [PresentationItem] { items.flatMap { $0.flattened } }
|
|
||||||
|
|
||||||
init() {
|
static let withApps = Filter(rawValue: 1 << 0)
|
||||||
rebuildPresentation()
|
static let runtimeInstalled = Filter(rawValue: 1 << 1)
|
||||||
validateItems()
|
|
||||||
// dumpPresentationItems(items)
|
static var allCases : [Filter] = [.withApps, .runtimeInstalled]
|
||||||
}
|
}
|
||||||
|
|
||||||
func filteredItems(filter: PresentationFilter) -> [PresentationItem] {
|
var organization = Organization.byRuntime
|
||||||
return items.map { $0.filtered(filter) }
|
var filter = Filter()
|
||||||
|
var searchTerm = ""
|
||||||
|
|
||||||
|
static func testItemsOf<T>(type: T.Type) -> [T] {
|
||||||
|
let flatItems = PresentationState().presentationItems(from: SimModel()).flatItems
|
||||||
|
|
||||||
|
return flatItems.itemsOf(type: type)
|
||||||
}
|
}
|
||||||
|
|
||||||
func rebuildPresentation() {
|
func presentationItems(from model: SimModel) -> [PresentationItem] {
|
||||||
switch style {
|
switch organization {
|
||||||
case .byDevice: items = itemsForDevicePresentation()
|
case .byDevice: return itemsForDeviceStyle(from: model)
|
||||||
case .byRuntime: items = itemsForRuntimePresentation()
|
case .byRuntime: return itemsForRuntimeStyle(from: model)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func itemsForDevicePresentation() -> [PresentationItem] {
|
func itemsForDeviceStyle(from model: SimModel) -> [PresentationItem] {
|
||||||
return SimProductFamily.presentation.map{ family in
|
return SimProductFamily.presentation.map{ family in
|
||||||
var familyItem = PresentationItem(family)
|
var familyItem = PresentationItem(family)
|
||||||
|
|
||||||
familyItem.children = baseModel.deviceTypes.filter({ $0.supports(productFamily: family) }).map { deviceType in
|
familyItem.children = model.deviceTypes.filter({ $0.supports(productFamily: family) }).map { deviceType in
|
||||||
var deviceTypeItem = PresentationItem(deviceType, identifier: deviceType.id)
|
var deviceTypeItem = PresentationItem(deviceType, identifier: deviceType.id)
|
||||||
let deviceTypeChildren : [PresentationItem] = baseModel.runtimes.filter({ $0.supports(deviceType: deviceType) }).map { runtime in
|
let deviceTypeChildren : [PresentationItem] = model.runtimes.filter({ $0.supports(deviceType: deviceType) }).map { runtime in
|
||||||
var runtimeItem = PresentationItem(runtime, identifier: "\(deviceType.id) - \(runtime.id)")
|
var runtimeItem = PresentationItem(runtime, identifier: "\(deviceType.id) - \(runtime.id)")
|
||||||
let runtimeItemChildren = runtime.devices.filter({ $0.isDeviceOfType(deviceType) }).map { device -> PresentationItem in
|
let runtimeItemChildren = runtime.devices.filter({ $0.isDeviceOfType(deviceType) }).map { device -> PresentationItem in
|
||||||
var deviceItem = PresentationItem(device, image: family.imageName)
|
var deviceItem = PresentationItem(device, image: family.imageName)
|
||||||
|
|
@ -81,13 +78,13 @@ class PresentableModel: ObservableObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func itemsForRuntimePresentation() -> [PresentationItem] {
|
func itemsForRuntimeStyle(from model: SimModel) -> [PresentationItem] {
|
||||||
return SimPlatform.presentation.map{ platform in
|
return SimPlatform.presentation.map{ platform in
|
||||||
var platformItem = PresentationItem(platform)
|
var platformItem = PresentationItem(platform)
|
||||||
|
|
||||||
platformItem.children = baseModel.runtimes.filter({ $0.supports(platform: platform) }).map { runtime in
|
platformItem.children = model.runtimes.filter({ $0.supports(platform: platform) }).map { runtime in
|
||||||
var runtimeItem = PresentationItem(runtime)
|
var runtimeItem = PresentationItem(runtime)
|
||||||
let runtimeItemChildren : [PresentationItem] = baseModel.deviceTypes.filter({ $0.supports(runtime: runtime) }).map { deviceType in
|
let runtimeItemChildren : [PresentationItem] = model.deviceTypes.filter({ $0.supports(runtime: runtime) }).map { deviceType in
|
||||||
var deviceTypeItem = PresentationItem(deviceType, identifier: "\(runtime.id) - \(deviceType.id)")
|
var deviceTypeItem = PresentationItem(deviceType, identifier: "\(runtime.id) - \(deviceType.id)")
|
||||||
let deviceTypeChildren = runtime.devices.filter({ $0.isDeviceOfType(deviceType) }).map { device -> PresentationItem in
|
let deviceTypeChildren = runtime.devices.filter({ $0.isDeviceOfType(deviceType) }).map { device -> PresentationItem in
|
||||||
var deviceItem = PresentationItem(device, image: deviceType.imageName)
|
var deviceItem = PresentationItem(device, image: deviceType.imageName)
|
||||||
|
|
@ -117,33 +114,5 @@ class PresentableModel: ObservableObject {
|
||||||
return platformItem
|
return platformItem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func itemsOf<T> (type: T.Type) -> [T] {
|
|
||||||
return flatItems.compactMap { $0.underlying as? T }
|
|
||||||
}
|
|
||||||
|
|
||||||
func validateItems() {
|
|
||||||
let allIDs = flatItems.map { $0.id }
|
|
||||||
var idSet = Set<String>()
|
|
||||||
|
|
||||||
print("Validating \(allIDs.count) items")
|
|
||||||
for id in allIDs {
|
|
||||||
if !idSet.insert(id).inserted {
|
|
||||||
print("Duplicate PresentationItem.id: \(id)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func dumpPresentationItems(_ items: [PresentationItem], level: Int = 0) {
|
|
||||||
let ident = Array(repeating: "\t", count: level).joined()
|
|
||||||
|
|
||||||
for item in items {
|
|
||||||
print("\(ident)\(item.title) [\(item.id)]")
|
|
||||||
|
|
||||||
if let children = item.children {
|
|
||||||
dumpPresentationItems(children, level: level + 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -12,7 +12,7 @@ enum SimError: Error {
|
||||||
case invalidApp
|
case invalidApp
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SimModel {
|
class SimModel: ObservableObject {
|
||||||
var deviceTypes : [SimDeviceType]
|
var deviceTypes : [SimDeviceType]
|
||||||
var runtimes : [SimRuntime]
|
var runtimes : [SimRuntime]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,11 @@ import SwiftUI
|
||||||
|
|
||||||
@main
|
@main
|
||||||
struct SimDirsApp: App {
|
struct SimDirsApp: App {
|
||||||
@StateObject private var modelData = PresentableModel()
|
@StateObject private var simModel = SimModel()
|
||||||
|
|
||||||
var body: some Scene {
|
var body: some Scene {
|
||||||
WindowGroup {
|
WindowGroup {
|
||||||
ContentView()
|
ContentView(model: simModel)
|
||||||
.environmentObject(modelData)
|
|
||||||
}
|
}
|
||||||
.commands {
|
.commands {
|
||||||
SimCommands()
|
SimCommands()
|
||||||
|
|
|
||||||
|
|
@ -53,9 +53,9 @@ struct AppView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AppView_Previews: PreviewProvider {
|
struct AppView_Previews: PreviewProvider {
|
||||||
static let apps = PresentableModel().itemsOf(type: SimApp.self)
|
|
||||||
|
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
|
let apps = PresentationState.testItemsOf(type: SimApp.self)
|
||||||
|
|
||||||
if apps.isEmpty {
|
if apps.isEmpty {
|
||||||
Text("No SimApp present in model data")
|
Text("No SimApp present in model data")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,9 +32,9 @@ struct DeviceTypeView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DeviceTypeView_Previews: PreviewProvider {
|
struct DeviceTypeView_Previews: PreviewProvider {
|
||||||
static let deviceTypes = PresentableModel().itemsOf(type: SimDeviceType.self)
|
|
||||||
|
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
|
let deviceTypes = PresentationState.testItemsOf(type: SimDeviceType.self)
|
||||||
|
|
||||||
if deviceTypes.isEmpty {
|
if deviceTypes.isEmpty {
|
||||||
Text("No SimDeviceType present in model data")
|
Text("No SimDeviceType present in model data")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,9 +39,9 @@ struct DeviceView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DeviceView_Previews: PreviewProvider {
|
struct DeviceView_Previews: PreviewProvider {
|
||||||
static let devices = PresentableModel().itemsOf(type: SimDevice.self)
|
|
||||||
|
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
|
let devices = PresentationState.testItemsOf(type: SimDevice.self)
|
||||||
|
|
||||||
if devices.isEmpty {
|
if devices.isEmpty {
|
||||||
Text("No SimDevice present in model data")
|
Text("No SimDevice present in model data")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,9 +59,9 @@ struct RuntimeView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RuntimeView_Previews: PreviewProvider {
|
struct RuntimeView_Previews: PreviewProvider {
|
||||||
static let runtimes = PresentableModel().itemsOf(type: SimRuntime.self)
|
|
||||||
|
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
|
let runtimes = PresentationState.testItemsOf(type: SimRuntime.self)
|
||||||
|
|
||||||
if runtimes.isEmpty {
|
if runtimes.isEmpty {
|
||||||
Text("No SimRuntime present in model data")
|
Text("No SimRuntime present in model data")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,9 +26,9 @@ struct SimItemContent: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SimItemContent_Previews: PreviewProvider {
|
struct SimItemContent_Previews: PreviewProvider {
|
||||||
static var model = PresentableModel()
|
|
||||||
|
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
SimItemContent(item: model.items[0].children![0])
|
let testItem = PresentationState().presentationItems(from: SimModel())[0]
|
||||||
|
|
||||||
|
SimItemContent(item: testItem.children![0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
62
SimDirs/Views/SimItemGroup.swift
Normal file
62
SimDirs/Views/SimItemGroup.swift
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
//
|
||||||
|
// SimItemGroup.swift
|
||||||
|
// SimDirs
|
||||||
|
//
|
||||||
|
// Created by Casey Fleser on 6/7/22.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct SimItemGroup: View {
|
||||||
|
let item : PresentationItem
|
||||||
|
@Binding var state : PresentationState
|
||||||
|
@State private var isExpanded = false
|
||||||
|
|
||||||
|
var children : [PresentationItem]? {
|
||||||
|
guard var items = item.children else { return nil }
|
||||||
|
|
||||||
|
if state.filter.contains(.withApps) {
|
||||||
|
items = items.filter { $0.containsType(SimApp.self) }
|
||||||
|
}
|
||||||
|
if state.filter.contains(.runtimeInstalled) {
|
||||||
|
items = items.filter {
|
||||||
|
guard let runtime = $0.underlying as? SimRuntime else { return true }
|
||||||
|
|
||||||
|
return runtime.isAvailable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !state.searchTerm.isEmpty {
|
||||||
|
items = items.filter { $0.titlesContain(state.searchTerm) }
|
||||||
|
}
|
||||||
|
|
||||||
|
return items.isEmpty ? nil : items
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
if let childItems = children {
|
||||||
|
DisclosureGroup(
|
||||||
|
isExpanded: $isExpanded,
|
||||||
|
content: {
|
||||||
|
ForEach(childItems) { childItem in
|
||||||
|
SimItemGroup(item: childItem, state: $state)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
label: { SimItemNavLink(item: item) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SimItemNavLink(item: item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SimItemGroup_Previews: PreviewProvider {
|
||||||
|
static var simModel = SimModel()
|
||||||
|
@State static var state = PresentationState()
|
||||||
|
|
||||||
|
static var previews: some View {
|
||||||
|
let testItem = state.presentationItems(from: simModel)[0]
|
||||||
|
|
||||||
|
SimItemGroup(item: testItem, state: $state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,65 +0,0 @@
|
||||||
//
|
|
||||||
// SimItemList.swift
|
|
||||||
// SimDirs
|
|
||||||
//
|
|
||||||
// Created by Casey Fleser on 5/30/22.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct SimItemList: View {
|
|
||||||
@EnvironmentObject var modelData : PresentableModel
|
|
||||||
@State private var withApps = false
|
|
||||||
@State private var withRuntimes = false
|
|
||||||
|
|
||||||
var filteredItems : [PresentationItem] {
|
|
||||||
var filter = PresentationFilter()
|
|
||||||
|
|
||||||
if withApps { filter.update(with: .withApps) }
|
|
||||||
if withRuntimes { filter.update(with: .runtimeInstalled) }
|
|
||||||
|
|
||||||
return modelData.filteredItems(filter: filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
NavigationView {
|
|
||||||
VStack {
|
|
||||||
List {
|
|
||||||
OutlineGroup(filteredItems, children: \.children) { item in
|
|
||||||
NavigationLink {
|
|
||||||
SimItemContent(item: item)
|
|
||||||
} label: {
|
|
||||||
SimItemRow(item: item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.padding(.leading, 2.0)
|
|
||||||
}
|
|
||||||
.frame(minWidth: 200)
|
|
||||||
.toolbar {
|
|
||||||
ToolbarItem {
|
|
||||||
Menu {
|
|
||||||
Toggle(isOn: $withApps) {
|
|
||||||
Label("With Apps", systemImage: "app.fill")
|
|
||||||
}
|
|
||||||
Toggle(isOn: $withRuntimes) {
|
|
||||||
Label("Installed Runtimes", systemImage: "cpu.fill")
|
|
||||||
}
|
|
||||||
} label: {
|
|
||||||
Label("Filter", systemImage: "slider.horizontal.3")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Text("Search")
|
|
||||||
.padding(.bottom, 4.0)
|
|
||||||
}
|
|
||||||
Text("SimDirs")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SimItemList_Previews: PreviewProvider {
|
|
||||||
static var previews: some View {
|
|
||||||
SimItemList()
|
|
||||||
.environmentObject(PresentableModel())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
27
SimDirs/Views/SimItemNavLink.swift
Normal file
27
SimDirs/Views/SimItemNavLink.swift
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
//
|
||||||
|
// SimItemNavLink.swift
|
||||||
|
// SimDirs
|
||||||
|
//
|
||||||
|
// Created by Casey Fleser on 6/7/22.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct SimItemNavLink: View {
|
||||||
|
let item : PresentationItem
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
NavigationLink {
|
||||||
|
SimItemContent(item: item) } label: {
|
||||||
|
SimItemRow(item: item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SimItemNavLink_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
let testItem = PresentationState().presentationItems(from: SimModel())[0]
|
||||||
|
|
||||||
|
SimItemNavLink(item: testItem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,7 +11,7 @@ struct SimItemRow: View {
|
||||||
var item : PresentationItem
|
var item : PresentationItem
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack {
|
Label(title: { Text(item.title) }) {
|
||||||
if let icon = item.icon {
|
if let icon = item.icon {
|
||||||
Image(nsImage: icon)
|
Image(nsImage: icon)
|
||||||
.resizable()
|
.resizable()
|
||||||
|
|
@ -23,17 +23,14 @@ struct SimItemRow: View {
|
||||||
.foregroundColor(item.imageColor)
|
.foregroundColor(item.imageColor)
|
||||||
.symbolRenderingMode(.hierarchical)
|
.symbolRenderingMode(.hierarchical)
|
||||||
}
|
}
|
||||||
Text(item.title)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SimItemRow_Previews: PreviewProvider {
|
struct SimItemRow_Previews: PreviewProvider {
|
||||||
static var model = PresentableModel()
|
|
||||||
|
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
Group {
|
let testItem = PresentationState().presentationItems(from: SimModel())[0]
|
||||||
SimItemRow(item: model.items[0])
|
|
||||||
}
|
SimItemRow(item: testItem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
45
SimDirs/Views/ToolbarMenu.swift
Normal file
45
SimDirs/Views/ToolbarMenu.swift
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
//
|
||||||
|
// ToolbarMenu.swift
|
||||||
|
// SimDirs
|
||||||
|
//
|
||||||
|
// Created by Casey Fleser on 6/7/22.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct ToolbarMenu: View {
|
||||||
|
@Binding var state : PresentationState
|
||||||
|
|
||||||
|
var withApps : Binding<Bool> {
|
||||||
|
Binding(get: { state.filter.contains(.withApps) },
|
||||||
|
set: { state.filter.booleanSet($0, options: .withApps) })
|
||||||
|
}
|
||||||
|
var withRuntimes : Binding<Bool> {
|
||||||
|
Binding(get: { state.filter.contains(.runtimeInstalled) },
|
||||||
|
set: { state.filter.booleanSet($0, options: .runtimeInstalled) })
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Menu {
|
||||||
|
Picker("Organization", selection: $state.organization) {
|
||||||
|
ForEach(PresentationState.Organization.allCases) { style in
|
||||||
|
Text(style.rawValue).tag(style)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.pickerStyle(.inline)
|
||||||
|
Toggle(isOn: withApps) { Label("With Apps", systemImage: "app.fill") }
|
||||||
|
Toggle(isOn: withRuntimes) { Label("Installed Runtimes", systemImage: "cpu.fill") }
|
||||||
|
} label: {
|
||||||
|
Label("Filter", systemImage: "slider.horizontal.3")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ToolbarMenu_Previews: PreviewProvider {
|
||||||
|
@State static var state = PresentationState(filter: [])
|
||||||
|
|
||||||
|
static var previews: some View {
|
||||||
|
ToolbarMenu(state: $state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
Reference in a new issue