Possible SwiftUI migration

This commit is contained in:
Casey Fleser 2022-05-25 13:24:20 -05:00
parent b456a16e6f
commit 350a2aa3ac
46 changed files with 923 additions and 1635 deletions

View file

@ -3,376 +3,399 @@
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objectVersion = 55;
objects = {
/* Begin PBXBuildFile section */
C9188EE01CD65DCB00F0F8B6 /* WindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9188EDF1CD65DCB00F0F8B6 /* WindowController.swift */; };
C921B3C71CD6219F0091C1AD /* DetailController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C921B3C51CD6219F0091C1AD /* DetailController.swift */; };
C921B3CA1CD629180091C1AD /* DetailTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C921B3C91CD629180091C1AD /* DetailTableView.swift */; };
C921B3CC1CD63EF30091C1AD /* ActionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C921B3CB1CD63EF30091C1AD /* ActionCell.swift */; };
C948814E1CD3EA5500209C09 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C948814D1CD3EA5500209C09 /* AppDelegate.swift */; };
C94881501CD3EA5500209C09 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C948814F1CD3EA5500209C09 /* Assets.xcassets */; };
C9AE594A1CD4EAD80090655C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C9AE59481CD4EAD80090655C /* Main.storyboard */; };
C9AE594C1CD4F1C70090655C /* SourceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9AE594B1CD4F1C70090655C /* SourceController.swift */; };
C9ECF8A41CD4CEE300499965 /* SimPlatform.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9ECF8A31CD4CEE300499965 /* SimPlatform.swift */; };
C9ECF8A61CD4CF1600499965 /* SimOSVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9ECF8A51CD4CF1600499965 /* SimOSVersion.swift */; };
C9ECF8A81CD4CF4000499965 /* SimDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9ECF8A71CD4CF4000499965 /* SimDevice.swift */; };
C9ECF8AA1CD4CF5A00499965 /* SimApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9ECF8A91CD4CF5A00499965 /* SimApp.swift */; };
C9ECF8AC1CD4CF8400499965 /* Support.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9ECF8AB1CD4CF8400499965 /* Support.swift */; };
C9ECF8B21CD4E26300499965 /* CoreUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C9ECF8B11CD4E26300499965 /* CoreUI.framework */; };
C982F859283B9F9000D491F4 /* SimDirsApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = C982F858283B9F9000D491F4 /* SimDirsApp.swift */; };
C982F85B283B9F9000D491F4 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C982F85A283B9F9000D491F4 /* ContentView.swift */; };
C982F85D283B9F9200D491F4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C982F85C283B9F9200D491F4 /* Assets.xcassets */; };
C982F860283B9F9200D491F4 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C982F85F283B9F9200D491F4 /* Preview Assets.xcassets */; };
C982F86B283BA22100D491F4 /* SimPlatform.swift in Sources */ = {isa = PBXBuildFile; fileRef = C982F86A283BA22100D491F4 /* SimPlatform.swift */; };
C982F871283CE7B800D491F4 /* SimRuntime.swift in Sources */ = {isa = PBXBuildFile; fileRef = C982F870283CE7B800D491F4 /* SimRuntime.swift */; };
C982F873283CE9AD00D491F4 /* SimDeviceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C982F872283CE9AD00D491F4 /* SimDeviceType.swift */; };
C982F875283CEEBB00D491F4 /* SimDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = C982F874283CEEBB00D491F4 /* SimDevice.swift */; };
C982F877283D020C00D491F4 /* SimProductFamily.swift in Sources */ = {isa = PBXBuildFile; fileRef = C982F876283D020C00D491F4 /* SimProductFamily.swift */; };
C982F879283D042E00D491F4 /* SimModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C982F878283D042E00D491F4 /* SimModel.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 */; };
C982F883283E813F00D491F4 /* DeviceTypeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C982F882283E813F00D491F4 /* DeviceTypeView.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
C9188EDF1CD65DCB00F0F8B6 /* WindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WindowController.swift; sourceTree = "<group>"; };
C921B3C51CD6219F0091C1AD /* DetailController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailController.swift; sourceTree = "<group>"; };
C921B3C91CD629180091C1AD /* DetailTableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailTableView.swift; sourceTree = "<group>"; };
C921B3CB1CD63EF30091C1AD /* ActionCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionCell.swift; sourceTree = "<group>"; };
C948814B1CD3EA5500209C09 /* SimDirs.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SimDirs.app; sourceTree = BUILT_PRODUCTS_DIR; };
C948814D1CD3EA5500209C09 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
C948814F1CD3EA5500209C09 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
C94881541CD3EA5500209C09 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
C9AE59491CD4EAD80090655C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
C9AE594B1CD4F1C70090655C /* SourceController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SourceController.swift; sourceTree = "<group>"; };
C9AE594D1CD503850090655C /* CUINamedLayerStack.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CUINamedLayerStack.h; sourceTree = "<group>"; };
C9ECF8A31CD4CEE300499965 /* SimPlatform.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimPlatform.swift; sourceTree = "<group>"; };
C9ECF8A51CD4CF1600499965 /* SimOSVersion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimOSVersion.swift; sourceTree = "<group>"; };
C9ECF8A71CD4CF4000499965 /* SimDevice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimDevice.swift; sourceTree = "<group>"; };
C9ECF8A91CD4CF5A00499965 /* SimApp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimApp.swift; sourceTree = "<group>"; };
C9ECF8AB1CD4CF8400499965 /* Support.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Support.swift; sourceTree = "<group>"; };
C9ECF8AF1CD4E13500499965 /* CUICatalog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CUICatalog.h; sourceTree = "<group>"; };
C9ECF8B01CD4E14C00499965 /* SimDirs-Bridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SimDirs-Bridge.h"; sourceTree = "<group>"; };
C9ECF8B11CD4E26300499965 /* CoreUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreUI.framework; path = /System/Library/PrivateFrameworks/CoreUI.framework; sourceTree = "<absolute>"; };
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>"; };
C982F85A283B9F9000D491F4 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
C982F85C283B9F9200D491F4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
C982F85F283B9F9200D491F4 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
C982F861283B9F9200D491F4 /* SimDirs.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SimDirs.entitlements; sourceTree = "<group>"; };
C982F86A283BA22100D491F4 /* SimPlatform.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimPlatform.swift; sourceTree = "<group>"; };
C982F870283CE7B800D491F4 /* SimRuntime.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimRuntime.swift; sourceTree = "<group>"; };
C982F872283CE9AD00D491F4 /* SimDeviceType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimDeviceType.swift; sourceTree = "<group>"; };
C982F874283CEEBB00D491F4 /* SimDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimDevice.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>"; };
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>"; };
C982F882283E813F00D491F4 /* DeviceTypeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceTypeView.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
C94881481CD3EA5500209C09 /* Frameworks */ = {
C982F852283B9F9000D491F4 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
C9ECF8B21CD4E26300499965 /* CoreUI.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
C9194D1C19C09A03004178EB = {
C982F84C283B9F9000D491F4 = {
isa = PBXGroup;
children = (
C948814C1CD3EA5500209C09 /* SimDirs */,
C9ECF8B31CD4E27B00499965 /* Frameworks */,
C9194D2619C09A03004178EB /* Products */,
C982F857283B9F9000D491F4 /* SimDirs */,
C982F856283B9F9000D491F4 /* Products */,
);
sourceTree = "<group>";
};
C9194D2619C09A03004178EB /* Products */ = {
C982F856283B9F9000D491F4 /* Products */ = {
isa = PBXGroup;
children = (
C948814B1CD3EA5500209C09 /* SimDirs.app */,
C982F855283B9F9000D491F4 /* SimDirs.app */,
);
name = Products;
sourceTree = "<group>";
};
C948814C1CD3EA5500209C09 /* SimDirs */ = {
C982F857283B9F9000D491F4 /* SimDirs */ = {
isa = PBXGroup;
children = (
C9ECF8A21CD4CEC800499965 /* Model */,
C9ECF8AE1CD4E13500499965 /* Support */,
C9ECF8B41CD4E96A00499965 /* UI */,
C948814D1CD3EA5500209C09 /* AppDelegate.swift */,
C9ECF8AB1CD4CF8400499965 /* Support.swift */,
C948814F1CD3EA5500209C09 /* Assets.xcassets */,
C9AE59481CD4EAD80090655C /* Main.storyboard */,
C94881541CD3EA5500209C09 /* Info.plist */,
C982F858283B9F9000D491F4 /* SimDirsApp.swift */,
C982F85A283B9F9000D491F4 /* ContentView.swift */,
C982F867283BA09B00D491F4 /* Model */,
C982F881283E7F0400D491F4 /* Views */,
C982F85C283B9F9200D491F4 /* Assets.xcassets */,
C982F861283B9F9200D491F4 /* SimDirs.entitlements */,
C982F85E283B9F9200D491F4 /* Preview Content */,
);
path = SimDirs;
sourceTree = "<group>";
};
C9ECF8A21CD4CEC800499965 /* Model */ = {
C982F85E283B9F9200D491F4 /* Preview Content */ = {
isa = PBXGroup;
children = (
C9ECF8A91CD4CF5A00499965 /* SimApp.swift */,
C9ECF8A71CD4CF4000499965 /* SimDevice.swift */,
C9ECF8A51CD4CF1600499965 /* SimOSVersion.swift */,
C9ECF8A31CD4CEE300499965 /* SimPlatform.swift */,
C982F85F283B9F9200D491F4 /* Preview Assets.xcassets */,
);
path = "Preview Content";
sourceTree = "<group>";
};
C982F867283BA09B00D491F4 /* Model */ = {
isa = PBXGroup;
children = (
C982F87C283E579900D491F4 /* Presentation */,
C982F87A283E40C800D491F4 /* SimCtl.swift */,
C982F878283D042E00D491F4 /* SimModel.swift */,
C982F874283CEEBB00D491F4 /* SimDevice.swift */,
C982F872283CE9AD00D491F4 /* SimDeviceType.swift */,
C982F86A283BA22100D491F4 /* SimPlatform.swift */,
C982F876283D020C00D491F4 /* SimProductFamily.swift */,
C982F870283CE7B800D491F4 /* SimRuntime.swift */,
);
path = Model;
sourceTree = "<group>";
};
C9ECF8AE1CD4E13500499965 /* Support */ = {
C982F87C283E579900D491F4 /* Presentation */ = {
isa = PBXGroup;
children = (
C9ECF8AF1CD4E13500499965 /* CUICatalog.h */,
C9AE594D1CD503850090655C /* CUINamedLayerStack.h */,
C9ECF8B01CD4E14C00499965 /* SimDirs-Bridge.h */,
C982F87D283E57B200D491F4 /* PresentableModel.swift */,
C982F87F283E57E600D491F4 /* PresentationItem.swift */,
);
path = Support;
path = Presentation;
sourceTree = "<group>";
};
C9ECF8B31CD4E27B00499965 /* Frameworks */ = {
C982F881283E7F0400D491F4 /* Views */ = {
isa = PBXGroup;
children = (
C9ECF8B11CD4E26300499965 /* CoreUI.framework */,
C982F882283E813F00D491F4 /* DeviceTypeView.swift */,
);
name = Frameworks;
sourceTree = "<group>";
};
C9ECF8B41CD4E96A00499965 /* UI */ = {
isa = PBXGroup;
children = (
C921B3CB1CD63EF30091C1AD /* ActionCell.swift */,
C921B3C51CD6219F0091C1AD /* DetailController.swift */,
C921B3C91CD629180091C1AD /* DetailTableView.swift */,
C9AE594B1CD4F1C70090655C /* SourceController.swift */,
C9188EDF1CD65DCB00F0F8B6 /* WindowController.swift */,
);
path = UI;
path = Views;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
C948814A1CD3EA5500209C09 /* SimDirs */ = {
C982F854283B9F9000D491F4 /* SimDirs */ = {
isa = PBXNativeTarget;
buildConfigurationList = C94881571CD3EA5500209C09 /* Build configuration list for PBXNativeTarget "SimDirs" */;
buildConfigurationList = C982F864283B9F9200D491F4 /* Build configuration list for PBXNativeTarget "SimDirs" */;
buildPhases = (
C94881471CD3EA5500209C09 /* Sources */,
C94881481CD3EA5500209C09 /* Frameworks */,
C94881491CD3EA5500209C09 /* Resources */,
C982F851283B9F9000D491F4 /* Sources */,
C982F852283B9F9000D491F4 /* Frameworks */,
C982F853283B9F9000D491F4 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = SimDirs;
productName = SimDirs2;
productReference = C948814B1CD3EA5500209C09 /* SimDirs.app */;
productName = SimDirs;
productReference = C982F855283B9F9000D491F4 /* SimDirs.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
C9194D1D19C09A03004178EB /* Project object */ = {
C982F84D283B9F9000D491F4 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0730;
LastUpgradeCheck = 0600;
ORGANIZATIONNAME = "Quiet Spark";
BuildIndependentTargetsInParallel = 1;
LastSwiftUpdateCheck = 1340;
LastUpgradeCheck = 1340;
TargetAttributes = {
C948814A1CD3EA5500209C09 = {
CreatedOnToolsVersion = 7.3;
C982F854283B9F9000D491F4 = {
CreatedOnToolsVersion = 13.4;
};
};
};
buildConfigurationList = C9194D2019C09A03004178EB /* Build configuration list for PBXProject "SimDirs" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
buildConfigurationList = C982F850283B9F9000D491F4 /* Build configuration list for PBXProject "SimDirs" */;
compatibilityVersion = "Xcode 13.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
English,
en,
Base,
);
mainGroup = C9194D1C19C09A03004178EB;
productRefGroup = C9194D2619C09A03004178EB /* Products */;
mainGroup = C982F84C283B9F9000D491F4;
productRefGroup = C982F856283B9F9000D491F4 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
C948814A1CD3EA5500209C09 /* SimDirs */,
C982F854283B9F9000D491F4 /* SimDirs */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
C94881491CD3EA5500209C09 /* Resources */ = {
C982F853283B9F9000D491F4 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
C9AE594A1CD4EAD80090655C /* Main.storyboard in Resources */,
C94881501CD3EA5500209C09 /* Assets.xcassets in Resources */,
C982F860283B9F9200D491F4 /* Preview Assets.xcassets in Resources */,
C982F85D283B9F9200D491F4 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
C94881471CD3EA5500209C09 /* Sources */ = {
C982F851283B9F9000D491F4 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
C921B3C71CD6219F0091C1AD /* DetailController.swift in Sources */,
C921B3CC1CD63EF30091C1AD /* ActionCell.swift in Sources */,
C9ECF8A41CD4CEE300499965 /* SimPlatform.swift in Sources */,
C9ECF8A61CD4CF1600499965 /* SimOSVersion.swift in Sources */,
C921B3CA1CD629180091C1AD /* DetailTableView.swift in Sources */,
C9AE594C1CD4F1C70090655C /* SourceController.swift in Sources */,
C9ECF8AA1CD4CF5A00499965 /* SimApp.swift in Sources */,
C9188EE01CD65DCB00F0F8B6 /* WindowController.swift in Sources */,
C948814E1CD3EA5500209C09 /* AppDelegate.swift in Sources */,
C9ECF8A81CD4CF4000499965 /* SimDevice.swift in Sources */,
C9ECF8AC1CD4CF8400499965 /* Support.swift in Sources */,
C982F883283E813F00D491F4 /* DeviceTypeView.swift in Sources */,
C982F85B283B9F9000D491F4 /* ContentView.swift in Sources */,
C982F875283CEEBB00D491F4 /* SimDevice.swift in Sources */,
C982F873283CE9AD00D491F4 /* SimDeviceType.swift in Sources */,
C982F877283D020C00D491F4 /* SimProductFamily.swift in Sources */,
C982F859283B9F9000D491F4 /* SimDirsApp.swift in Sources */,
C982F871283CE7B800D491F4 /* SimRuntime.swift in Sources */,
C982F86B283BA22100D491F4 /* SimPlatform.swift in Sources */,
C982F87E283E57B200D491F4 /* PresentableModel.swift in Sources */,
C982F880283E57E600D491F4 /* PresentationItem.swift in Sources */,
C982F879283D042E00D491F4 /* SimModel.swift in Sources */,
C982F87B283E40C800D491F4 /* SimCtl.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
C9AE59481CD4EAD80090655C /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
C9AE59491CD4EAD80090655C /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
C9194D4019C09A03004178EB /* Debug */ = {
C982F862283B9F9200D491F4 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.9;
MTL_ENABLE_DEBUG_INFO = YES;
MACOSX_DEPLOYMENT_TARGET = 12.3;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SWIFT_VERSION = 5.0;
};
name = Debug;
};
C9194D4119C09A03004178EB /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.9;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
SWIFT_VERSION = 5.0;
};
name = Release;
};
C94881551CD3EA5500209C09 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
COMBINE_HIDPI_IMAGES = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_TESTABILITY = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
);
GCC_NO_COMMON_BLOCKS = YES;
INFOPLIST_FILE = "$(SRCROOT)/SimDirs/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.11;
PRODUCT_BUNDLE_IDENTIFIER = com.quietspark.SimDirs;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "SimDirs/Support/SimDirs-Bridge.h";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
C94881561CD3EA5500209C09 /* Release */ = {
C982F863283B9F9200D491F4 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 12.3;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
};
name = Release;
};
C982F865283B9F9200D491F4 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = SimDirs/SimDirs.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
FRAMEWORK_SEARCH_PATHS = (
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"SimDirs/Preview Content\"";
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
"@executable_path/../Frameworks",
);
GCC_NO_COMMON_BLOCKS = YES;
INFOPLIST_FILE = "$(SRCROOT)/SimDirs/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.11;
PRODUCT_BUNDLE_IDENTIFIER = com.quietspark.SimDirs;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.sgntn.SimDirs;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "SimDirs/Support/SimDirs-Bridge.h";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
};
name = Debug;
};
C982F866283B9F9200D491F4 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = SimDirs/SimDirs.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"SimDirs/Preview Content\"";
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.sgntn.SimDirs;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
C9194D2019C09A03004178EB /* Build configuration list for PBXProject "SimDirs" */ = {
C982F850283B9F9000D491F4 /* Build configuration list for PBXProject "SimDirs" */ = {
isa = XCConfigurationList;
buildConfigurations = (
C9194D4019C09A03004178EB /* Debug */,
C9194D4119C09A03004178EB /* Release */,
C982F862283B9F9200D491F4 /* Debug */,
C982F863283B9F9200D491F4 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
C94881571CD3EA5500209C09 /* Build configuration list for PBXNativeTarget "SimDirs" */ = {
C982F864283B9F9200D491F4 /* Build configuration list for PBXNativeTarget "SimDirs" */ = {
isa = XCConfigurationList;
buildConfigurations = (
C94881551CD3EA5500209C09 /* Debug */,
C94881561CD3EA5500209C09 /* Release */,
C982F865283B9F9200D491F4 /* Debug */,
C982F866283B9F9200D491F4 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = C9194D1D19C09A03004178EB /* Project object */;
rootObject = C982F84D283B9F9000D491F4 /* Project object */;
}

View file

@ -2,6 +2,6 @@
<Workspace
version = "1.0">
<FileRef
location = "self:SimDirs.xcodeproj">
location = "self:">
</FileRef>
</Workspace>

View file

@ -1,20 +0,0 @@
//
// AppDelegate.swift
// SimDirs
//
// Created by Casey Fleser on 4/29/16.
// Copyright © 2016 Quiet Spark. All rights reserved.
//
import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(aNotification: NSNotification) {
}
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true
}
}

View file

@ -0,0 +1,11 @@
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -1,68 +1,58 @@
{
"images" : [
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "icon_16x16.png",
"scale" : "1x"
"scale" : "1x",
"size" : "16x16"
},
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "icon_16x16@2x.png",
"scale" : "2x"
"scale" : "2x",
"size" : "16x16"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "icon_32x32.png",
"scale" : "1x"
"scale" : "1x",
"size" : "32x32"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "icon_32x32@2x.png",
"scale" : "2x"
"scale" : "2x",
"size" : "32x32"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "icon_128x128.png",
"scale" : "1x"
"scale" : "1x",
"size" : "128x128"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "icon_128x128@2x.png",
"scale" : "2x"
"scale" : "2x",
"size" : "128x128"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "icon_256x256.png",
"scale" : "1x"
"scale" : "1x",
"size" : "256x256"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "icon_256x256@2x.png",
"scale" : "2x"
"scale" : "2x",
"size" : "256x256"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "icon_512x512.png",
"scale" : "1x"
"scale" : "1x",
"size" : "512x512"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "icon_512x512@2x.png",
"scale" : "2x"
"scale" : "2x",
"size" : "512x512"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
"author" : "xcode",
"version" : 1
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 534 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 438 KiB

View file

@ -1,6 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
"author" : "xcode",
"version" : 1
}
}
}

View file

@ -1,22 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "default_icon.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "defaultt_icon@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

View file

@ -1,488 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="20037" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="20037"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Application-->
<scene sceneID="JPo-4y-FX3">
<objects>
<application id="hnw-xV-0zn" sceneMemberID="viewController">
<menu key="mainMenu" title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
<items>
<menuItem title="SimDirs" id="1Xt-HY-uBw">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="SimDirs" systemMenu="apple" id="uQy-DD-JDr">
<items>
<menuItem title="About SimDirs" id="5kV-Vb-QxS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontStandardAboutPanel:" target="Ady-hI-5gd" id="Exp-CZ-Vem"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
<menuItem title="Services" id="NMo-om-nkz">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
</menuItem>
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
<menuItem title="Hide SimDirs" keyEquivalent="h" id="Olw-nP-bQN">
<connections>
<action selector="hide:" target="Ady-hI-5gd" id="PnN-Uc-m68"/>
</connections>
</menuItem>
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="hideOtherApplications:" target="Ady-hI-5gd" id="VT4-aY-XCT"/>
</connections>
</menuItem>
<menuItem title="Show All" id="Kd2-mp-pUS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unhideAllApplications:" target="Ady-hI-5gd" id="Dhg-Le-xox"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
<menuItem title="Quit SimDirs" keyEquivalent="q" id="4sb-4s-VLi">
<connections>
<action selector="terminate:" target="Ady-hI-5gd" id="Te7-pn-YzF"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="File" id="dMs-cI-mzQ">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Edit" id="5QF-Oa-p0T">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Edit" id="W48-6f-4Dl">
<items>
<menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
<connections>
<action selector="copy:" target="Ady-hI-5gd" id="G1f-GL-Joy"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Format" id="jxT-CU-nIS">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="View" id="H8h-7b-M4v">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Window" id="aUF-d1-5bR">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
<items>
<menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
<connections>
<action selector="performMiniaturize:" target="Ady-hI-5gd" id="VwT-WD-YPe"/>
</connections>
</menuItem>
<menuItem title="Zoom" id="R4o-n2-Eq4">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="performZoom:" target="Ady-hI-5gd" id="DIl-cC-cCs"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
<menuItem title="Bring All to Front" id="LE2-aR-0XJ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="arrangeInFront:" target="Ady-hI-5gd" id="DRN-fu-gQh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Help" id="wpr-3q-Mcd">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
</items>
</menu>
<connections>
<outlet property="delegate" destination="Voe-Tx-rLC" id="PrD-fu-P6m"/>
</connections>
</application>
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="SimDirs" customModuleProvider="target"/>
<customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="75" y="0.0"/>
</scene>
<!--Window Controller-->
<scene sceneID="R2V-B0-nI4">
<objects>
<windowController id="B8D-0N-5wS" customClass="WindowController" customModule="SimDirs" customModuleProvider="target" sceneMemberID="viewController">
<window key="window" title="SimDirs" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" frameAutosaveName="" animationBehavior="default" id="IQv-IB-iLA">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="35" y="482" width="480" height="270"/>
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
<connections>
<outlet property="delegate" destination="B8D-0N-5wS" id="qkq-Ka-avA"/>
</connections>
</window>
<connections>
<segue destination="utk-XN-WFQ" kind="relationship" relationship="window.shadowedContentViewController" id="cNr-LA-6PI"/>
</connections>
</windowController>
<customObject id="Oky-zY-oP4" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="75" y="250"/>
</scene>
<!--Split View Controller-->
<scene sceneID="ANE-qI-AzX">
<objects>
<splitViewController id="utk-XN-WFQ" sceneMemberID="viewController">
<splitViewItems>
<splitViewItem holdingPriority="255" behavior="contentList" id="vjm-YC-n35"/>
<splitViewItem id="zem-yq-moN"/>
</splitViewItems>
<splitView key="splitView" dividerStyle="thin" vertical="YES" id="4n7-1p-MYG">
<rect key="frame" x="0.0" y="0.0" width="450" height="300"/>
<autoresizingMask key="autoresizingMask"/>
<connections>
<outlet property="delegate" destination="utk-XN-WFQ" id="zcR-4y-jcI"/>
</connections>
</splitView>
<connections>
<outlet property="splitView" destination="4n7-1p-MYG" id="anq-oS-l0b"/>
<segue destination="iYR-B6-n1S" kind="relationship" relationship="splitItems" id="5zw-PK-lrP"/>
<segue destination="F48-sT-ymT" kind="relationship" relationship="splitItems" id="wSa-fB-x8O"/>
</connections>
</splitViewController>
<customObject id="fvM-of-U7k" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="75" y="704"/>
</scene>
<!--Source Controller-->
<scene sceneID="95M-fv-kdk">
<objects>
<viewController id="iYR-B6-n1S" customClass="SourceController" customModule="SimDirs" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" id="MGo-Qu-2zB">
<rect key="frame" x="0.0" y="0.0" width="220" height="299"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<scrollView borderType="none" autohidesScrollers="YES" horizontalLineScroll="26" horizontalPageScroll="10" verticalLineScroll="26" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="AbX-mV-QBL">
<rect key="frame" x="0.0" y="30" width="220" height="269"/>
<clipView key="contentView" id="Pi5-bv-Sst">
<rect key="frame" x="0.0" y="0.0" width="220" height="269"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<outlineView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnReordering="NO" multipleSelection="NO" autosaveColumns="NO" rowHeight="24" rowSizeStyle="automatic" viewBased="YES" indentationPerLevel="16" outlineTableColumn="mzD-l4-yhs" id="mUb-N5-ueO">
<rect key="frame" x="0.0" y="0.0" width="220" height="269"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<size key="intercellSpacing" width="3" height="2"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
<tableColumns>
<tableColumn identifier="title" editable="NO" width="188" minWidth="40" maxWidth="1000" id="mzD-l4-yhs">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left">
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" allowsUndo="NO" alignment="left" title="Text Cell" id="mde-rH-ONI">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView identifier="TextCell" id="HAO-IX-sxc" userLabel="Text Cell">
<rect key="frame" x="11" y="1" width="197" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="bfY-42-aRq">
<rect key="frame" x="2" y="1" width="197" height="16"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="cnA-t8-jTo">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstItem="bfY-42-aRq" firstAttribute="leading" secondItem="HAO-IX-sxc" secondAttribute="leading" constant="4" id="89t-I4-nZh"/>
<constraint firstAttribute="centerY" secondItem="bfY-42-aRq" secondAttribute="centerY" id="D1b-kz-ps5"/>
<constraint firstAttribute="trailing" secondItem="bfY-42-aRq" secondAttribute="trailing" id="Dud-KT-aci"/>
</constraints>
<connections>
<outlet property="textField" destination="bfY-42-aRq" id="ucp-nv-3Ke"/>
</connections>
</tableCellView>
<tableCellView identifier="ImageCell" id="Dwi-Dl-LE4" userLabel="Image &amp; Text Cell">
<rect key="frame" x="11" y="21" width="197" height="24"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="5Mz-bX-925">
<rect key="frame" x="4" y="-2" width="22" height="28"/>
<constraints>
<constraint firstAttribute="width" constant="22" id="9JV-jh-a9G"/>
<constraint firstAttribute="height" constant="22" id="p7O-pN-kXh"/>
</constraints>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="NSActionTemplate" id="MLC-9O-NVW"/>
</imageView>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsExpansionToolTips="YES" translatesAutoresizingMaskIntoConstraints="NO" id="wgX-ci-hFu">
<rect key="frame" x="28" y="4" width="171" height="16"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="jZj-fZ-DCx">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstAttribute="centerY" secondItem="5Mz-bX-925" secondAttribute="centerY" id="BKo-y7-kUK"/>
<constraint firstAttribute="trailing" secondItem="wgX-ci-hFu" secondAttribute="trailing" id="dit-vg-hyV"/>
<constraint firstItem="wgX-ci-hFu" firstAttribute="leading" secondItem="5Mz-bX-925" secondAttribute="trailing" constant="4" id="sVg-cY-ZoA"/>
<constraint firstAttribute="centerY" secondItem="wgX-ci-hFu" secondAttribute="centerY" id="t56-t6-q7e"/>
<constraint firstItem="5Mz-bX-925" firstAttribute="leading" secondItem="Dwi-Dl-LE4" secondAttribute="leading" constant="4" id="yqi-4E-9SK"/>
</constraints>
<connections>
<outlet property="imageView" destination="5Mz-bX-925" id="Tqr-NH-n33"/>
<outlet property="textField" destination="wgX-ci-hFu" id="QM1-92-bQC"/>
</connections>
</tableCellView>
</prototypeCellViews>
</tableColumn>
</tableColumns>
<connections>
<outlet property="dataSource" destination="iYR-B6-n1S" id="r6O-sY-vDK"/>
<outlet property="delegate" destination="iYR-B6-n1S" id="dFv-mO-hVs"/>
</connections>
</outlineView>
</subviews>
</clipView>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="200" id="Prh-ue-cFO"/>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="200" id="yeB-eV-8JM"/>
</constraints>
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="UKV-0Z-h3q">
<rect key="frame" x="1" y="284" width="448" height="15"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="xTK-zV-3rC">
<rect key="frame" x="184" y="1" width="15" height="0.0"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
</scrollView>
<customView translatesAutoresizingMaskIntoConstraints="NO" id="DfU-U7-lPF">
<rect key="frame" x="0.0" y="0.0" width="220" height="30"/>
<subviews>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="8XW-ii-1pm">
<rect key="frame" x="72" y="-2" width="76" height="32"/>
<buttonCell key="cell" type="push" title="Reload" bezelStyle="rounded" imagePosition="overlaps" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="gGy-Fx-TPk">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="rescan:" target="iYR-B6-n1S" id="K6Y-C3-2it"/>
</connections>
</button>
</subviews>
<constraints>
<constraint firstAttribute="height" constant="30" id="07R-e0-RcD"/>
<constraint firstItem="8XW-ii-1pm" firstAttribute="centerX" secondItem="DfU-U7-lPF" secondAttribute="centerX" id="o8I-3P-AaK"/>
<constraint firstItem="8XW-ii-1pm" firstAttribute="centerY" secondItem="DfU-U7-lPF" secondAttribute="centerY" id="yWq-r4-QMO"/>
</constraints>
</customView>
</subviews>
<constraints>
<constraint firstItem="DfU-U7-lPF" firstAttribute="top" secondItem="AbX-mV-QBL" secondAttribute="bottom" id="GkT-KT-J9Q"/>
<constraint firstItem="DfU-U7-lPF" firstAttribute="leading" secondItem="MGo-Qu-2zB" secondAttribute="leading" id="Je2-3P-DQe"/>
<constraint firstAttribute="trailing" secondItem="DfU-U7-lPF" secondAttribute="trailing" id="Kh3-dO-bzm"/>
<constraint firstAttribute="bottom" secondItem="DfU-U7-lPF" secondAttribute="bottom" id="cjT-GE-N46"/>
<constraint firstAttribute="trailing" secondItem="AbX-mV-QBL" secondAttribute="trailing" id="elr-8R-0p9"/>
<constraint firstItem="AbX-mV-QBL" firstAttribute="top" secondItem="MGo-Qu-2zB" secondAttribute="top" id="h7M-GY-dLb"/>
<constraint firstItem="AbX-mV-QBL" firstAttribute="leading" secondItem="MGo-Qu-2zB" secondAttribute="leading" id="isG-f2-jDQ"/>
</constraints>
</view>
<connections>
<outlet property="outlineView" destination="mUb-N5-ueO" id="qcM-cj-dLn"/>
</connections>
</viewController>
<customObject id="HIA-tb-x8L" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="715" y="455"/>
</scene>
<!--Detail Controller-->
<scene sceneID="Wbg-Th-oFy">
<objects>
<viewController id="F48-sT-ymT" customClass="DetailController" customModule="SimDirs" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" id="UMm-Xy-nBF">
<rect key="frame" x="0.0" y="0.0" width="460" height="298"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="0W4-aZ-Ae5">
<rect key="frame" x="18" y="262" width="93" height="16"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Detail Header" id="ZtP-3C-2L8">
<font key="font" metaFont="systemBold"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="cnN-cy-Bac">
<rect key="frame" x="435" y="278" width="5" height="0.0"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="36a-uZ-g0s"/>
</imageView>
<scrollView borderType="none" autohidesScrollers="YES" horizontalLineScroll="26" horizontalPageScroll="10" verticalLineScroll="26" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="JAP-se-fpu">
<rect key="frame" x="20" y="0.0" width="399" height="254"/>
<clipView key="contentView" drawsBackground="NO" copiesOnScroll="NO" id="tnM-9n-jrP">
<rect key="frame" x="0.0" y="0.0" width="399" height="254"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" selectionHighlightStyle="none" columnReordering="NO" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" rowHeight="24" viewBased="YES" id="eyA-kU-AI2" customClass="DetailTableView" customModule="SimDirs" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="399" height="254"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<size key="intercellSpacing" width="3" height="2"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="calibratedRGB"/>
<tableViewGridLines key="gridStyleMask" horizontal="YES"/>
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
<tableColumns>
<tableColumn identifier="title" width="160" minWidth="40" maxWidth="1000" id="tCe-6w-h4v">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="Ls1-dG-GNl">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView identifier="PropertyTitleCell" id="lRo-ld-RBC" userLabel="Property Title">
<rect key="frame" x="11" y="1" width="165" height="24"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="TBX-NI-YIG">
<rect key="frame" x="0.0" y="4" width="159" height="16"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="fjI-nE-FBC">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstItem="TBX-NI-YIG" firstAttribute="leading" secondItem="lRo-ld-RBC" secondAttribute="leading" constant="2" id="BUg-Ur-Hzl"/>
<constraint firstItem="TBX-NI-YIG" firstAttribute="centerY" secondItem="lRo-ld-RBC" secondAttribute="centerY" id="INO-aQ-3HN"/>
<constraint firstAttribute="trailing" secondItem="TBX-NI-YIG" secondAttribute="trailing" constant="8" id="dQf-Hb-UI8"/>
</constraints>
<connections>
<outlet property="textField" destination="TBX-NI-YIG" id="KpA-dH-uNj"/>
</connections>
</tableCellView>
</prototypeCellViews>
</tableColumn>
<tableColumn identifier="value" width="204" minWidth="40" maxWidth="1000" id="pRb-SO-D2D">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="hs3-Z6-Um2">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView identifier="PropertyValueCell" id="M6i-yS-c78" userLabel="Property Value">
<rect key="frame" x="179" y="1" width="208" height="24"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="IMg-r6-yjW">
<rect key="frame" x="-2" y="4" width="212" height="16"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" selectable="YES" sendsActionOnEndEditing="YES" title="Table View Cell" id="05K-5u-HvY">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="IMg-r6-yjW" secondAttribute="trailing" id="EF1-3C-aMi"/>
<constraint firstItem="IMg-r6-yjW" firstAttribute="centerY" secondItem="M6i-yS-c78" secondAttribute="centerY" id="Ude-WE-2uY"/>
<constraint firstItem="IMg-r6-yjW" firstAttribute="leading" secondItem="M6i-yS-c78" secondAttribute="leading" id="Zhq-i0-zHb"/>
</constraints>
<connections>
<outlet property="textField" destination="IMg-r6-yjW" id="OA5-by-P3W"/>
</connections>
</tableCellView>
<customView identifier="PropertyActionCell" id="q5G-P3-EGm" userLabel="Reveal Cell" customClass="ActionCell" customModule="SimDirs" customModuleProvider="target">
<rect key="frame" x="179" y="27" width="208" height="24"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Jjs-nn-o9R">
<rect key="frame" x="-7" y="-5" width="124" height="32"/>
<buttonCell key="cell" type="push" title="Show In Finder" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="qaa-xT-Nnr">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="executeAction:" target="q5G-P3-EGm" id="4Id-0c-7mK"/>
</connections>
</button>
</subviews>
<constraints>
<constraint firstItem="Jjs-nn-o9R" firstAttribute="centerY" secondItem="q5G-P3-EGm" secondAttribute="centerY" id="njz-TZ-q0l"/>
<constraint firstItem="Jjs-nn-o9R" firstAttribute="leading" secondItem="q5G-P3-EGm" secondAttribute="leading" id="xBT-kv-Yby"/>
</constraints>
<connections>
<outlet property="actionButton" destination="Jjs-nn-o9R" id="IiA-iD-gPo"/>
</connections>
</customView>
</prototypeCellViews>
</tableColumn>
</tableColumns>
<connections>
<outlet property="dataSource" destination="F48-sT-ymT" id="Iq0-Oq-XqV"/>
<outlet property="delegate" destination="F48-sT-ymT" id="f1b-rA-9VC"/>
</connections>
</tableView>
</subviews>
</clipView>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="360" id="FDG-SK-zLr"/>
</constraints>
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="mGJ-QF-84J">
<rect key="frame" x="1" y="119" width="223" height="15"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="U02-Dv-BpL">
<rect key="frame" x="224" y="17" width="15" height="102"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
</scrollView>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="cnN-cy-Bac" secondAttribute="trailing" constant="20" symbolic="YES" id="6jt-1y-I45"/>
<constraint firstItem="JAP-se-fpu" firstAttribute="top" secondItem="0W4-aZ-Ae5" secondAttribute="bottom" constant="8" symbolic="YES" id="I2y-6k-eoF"/>
<constraint firstItem="cnN-cy-Bac" firstAttribute="leading" secondItem="JAP-se-fpu" secondAttribute="trailing" constant="16" id="Mp2-4Z-5Wj"/>
<constraint firstItem="0W4-aZ-Ae5" firstAttribute="leading" secondItem="UMm-Xy-nBF" secondAttribute="leading" constant="20" symbolic="YES" id="NxN-dt-Qik"/>
<constraint firstItem="JAP-se-fpu" firstAttribute="leading" secondItem="UMm-Xy-nBF" secondAttribute="leading" constant="20" symbolic="YES" id="Tpt-YG-xYq"/>
<constraint firstAttribute="bottom" secondItem="JAP-se-fpu" secondAttribute="bottom" id="e1L-p4-1Hj"/>
<constraint firstItem="cnN-cy-Bac" firstAttribute="top" secondItem="UMm-Xy-nBF" secondAttribute="top" constant="20" symbolic="YES" id="fKO-Jw-6co"/>
<constraint firstItem="0W4-aZ-Ae5" firstAttribute="top" secondItem="UMm-Xy-nBF" secondAttribute="top" constant="20" symbolic="YES" id="g8h-kr-Or3"/>
</constraints>
</view>
<connections>
<outlet property="headerLabel" destination="0W4-aZ-Ae5" id="BcX-er-8kA"/>
<outlet property="imageView" destination="cnN-cy-Bac" id="teZ-DG-dWn"/>
<outlet property="propertyTable" destination="eyA-kU-AI2" id="Bq9-nt-FtY"/>
</connections>
</viewController>
<customObject id="F92-9s-t7r" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="715" y="904"/>
</scene>
</scenes>
<resources>
<image name="NSActionTemplate" width="15" height="15"/>
</resources>
</document>

80
SimDirs/ContentView.swift Normal file
View file

@ -0,0 +1,80 @@
//
// ContentView.swift
// SimDirs
//
// Created by Casey Fleser on 5/23/22.
//
import SwiftUI
struct Item: Identifiable {
var id: Int
var name: String
init(id: Int) {
self.id = id
self.name = "\(id)"
}
}
struct ContentView: View {
@EnvironmentObject var modelData : PresentableModel
@State private var toggleVal = false
let testItems = (0..<10).map({ Item(id: $0) })
var body: some View {
NavigationView {
List {
OutlineGroup(modelData.items, children: \.children) { item in
NavigationLink {
VStack {
HStack {
switch item.underlying {
case let deviceType as SimDeviceType:
DeviceTypeView(deviceType: deviceType)
default:
Text("\(item.title)")
}
Spacer()
}
Spacer()
}
.padding(.all)
.navigationTitle(item.title)
} label: {
Label(item.title, systemImage: item.imageName)
}
}
.padding(.leading, 2.0)
}
.frame(minWidth: 200)
.toolbar {
ToolbarItem {
Menu {
// Picker("Category", selection: $filter) {
// ForEach(FilterCategory.allCases) { category in
// Text(category.rawValue).tag(category)
// }
// }
// .pickerStyle(.inline)
Toggle(isOn: $toggleVal) {
Label("Toggle", systemImage: "star.fill")
}
} label: {
Label("Filter", systemImage: "slider.horizontal.3")
}
}
}
Text("SimDirs") // If this isn't here things looks weird
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.environmentObject(PresentableModel())
}
}

View file

@ -1,34 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.6</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2016 Quiet Spark. All rights reserved.</string>
<key>NSMainStoryboardFile</key>
<string>Main</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>

View file

@ -0,0 +1,100 @@
//
// PresentableModel.swift
// SimDirs
//
// Created by Casey Fleser on 5/25/22.
//
import Foundation
class PresentableModel: ObservableObject {
enum Style {
case byDevice
case byRuntime
}
var baseModel = SimModel()
var style = Style.byDevice
var items = [PresentationItem]()
init() {
rebuildPresentation()
// dumpPresentationItems(items)
}
func rebuildPresentation() {
switch style {
case .byDevice: items = itemsForDevicePresentation()
case .byRuntime: items = itemsForRuntimePresentation()
}
}
func itemsForDevicePresentation() -> [PresentationItem] {
return SimProductFamily.presentation.map{ family in
var familyItem = PresentationItem(family)
familyItem.children = baseModel.deviceTypes.filter({ $0.supports(productFamily: family) }).map { deviceType in
var deviceTypeItem = PresentationItem(deviceType, identifier: deviceType.id)
let deviceTypeChildren : [PresentationItem] = baseModel.runtimes.filter({ $0.supports(deviceType: deviceType) }).map { runtime in
var runtimeItem = PresentationItem(runtime, identifier: "\(deviceType.id) - \(runtime.id)")
let runtimeItemChildren = runtime.devices.filter({ $0.isDeviceOfType(deviceType) }).map { PresentationItem($0, image: family.imageName) }
if !runtimeItemChildren.isEmpty {
runtimeItem.children = runtimeItemChildren
}
return runtimeItem
}
if !deviceTypeChildren.isEmpty {
deviceTypeItem.children = deviceTypeChildren
}
return deviceTypeItem
}
return familyItem
}
}
func itemsForRuntimePresentation() -> [PresentationItem] {
return SimPlatform.presentation.map{ platform in
var platformItem = PresentationItem(platform)
platformItem.children = baseModel.runtimes.filter({ $0.supports(platform: platform) }).map { runtime in
var runtimeItem = PresentationItem(runtime)
let runtimeItemChildren : [PresentationItem] = baseModel.deviceTypes.filter({ $0.supports(runtime: runtime) }).map { deviceType in
var deviceTypeItem = PresentationItem(deviceType, identifier: "\(runtime.id) - \(deviceType.id)")
let deviceTypeChildren = runtime.devices.filter({ $0.isDeviceOfType(deviceType) }).map { PresentationItem($0, image: deviceType.imageName) }
if !deviceTypeChildren.isEmpty {
deviceTypeItem.children = deviceTypeChildren
}
return deviceTypeItem
}
if !runtimeItemChildren.isEmpty {
runtimeItem.children = runtimeItemChildren
}
return runtimeItem
}
return platformItem
}
}
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)
}
}
}
}

View file

@ -0,0 +1,40 @@
//
// PresentationItem.swift
// SimDirs
//
// Created by Casey Fleser on 5/25/22.
//
import SwiftUI
protocol PresentableItem {
var title : String { get }
var id : String { get }
var imageName : String { get }
}
protocol PresentableContent {
associatedtype Content : View
var view : Content { get }
}
struct PresentationContent<T: PresentableContent> {
let underlying : T
}
struct PresentationItem: Identifiable {
let underlying : PresentableItem
var children : [PresentationItem]?
var id : String
var customImage : String?
var title : String { return underlying.title }
var imageName : String { return customImage ?? underlying.imageName }
init(_ presentable: PresentableItem, image: String? = nil, identifier: String? = nil) {
underlying = presentable
id = identifier ?? underlying.id
customImage = image
}
}

View file

@ -1,205 +0,0 @@
//
// SimApp.swift
// SimDirs
//
// Created by Casey Fleser on 4/30/16.
// Copyright © 2016 Quiet Spark. All rights reserved.
//
import Foundation
class SimApp: OutlineProvider, PropertyProvider {
let bundleID : String
var bundleName = ""
var displayName = ""
var shortVersion = ""
var version = ""
var minOSVersion : String?
var icon : NSImage?
var hasValidPaths : Bool { return self.validatedBundlePath != nil || self.validatedSandboxPath != nil }
var bundleURL : URL? { return self.validatedBundlePath.map { URL(fileURLWithPath: $0) } }
var sandboxURL : URL? { return self.validatedSandboxPath.map { URL(fileURLWithPath: $0) } }
private var validatedBundlePath : String?
private var validatedSandboxPath : String?
var bundlePath : String? {
get { return self.validatedBundlePath }
set {
guard let newPath = newValue else { return }
if self.validatedBundlePath == nil && newPath.validPath {
self.validatedBundlePath = newPath
}
}
}
var sandboxPath : String? {
get { return self.validatedSandboxPath }
set {
guard let newPath = newValue else { return }
if self.validatedSandboxPath == nil && newPath.validPath {
self.validatedSandboxPath = newPath
}
}
}
init(bundleID: String) {
self.bundleID = bundleID
}
func completeScan() {
self.refinePaths()
self.loadInfoPlist()
}
func updateFrom(launchBundleInfo: [String : AnyObject]) {
self.bundlePath = launchBundleInfo["BundleContainer"] as? String
self.sandboxPath = launchBundleInfo["Container"] as? String
}
func updateFrom(appStateInfo: [String : AnyObject]) {
guard let compatInfo = appStateInfo["compatibilityInfo"] as? [String : AnyObject] else { return }
self.bundlePath = compatInfo["bundlePath"] as? String
self.sandboxPath = compatInfo["sandboxPath"] as? String
}
func refinePaths() {
guard let bundleURL = self.bundleURL else { return }
let fileMgr = FileManager.default
if !bundleURL.lastPathComponent.contains("app") {
if let dirEnumerator = fileMgr.enumerator(at: bundleURL, includingPropertiesForKeys: nil, options: [ .skipsSubdirectoryDescendants, .skipsHiddenFiles ]) {
for appURL in dirEnumerator.allObjects.compactMap({ $0 as? URL}) {
if appURL.lastPathComponent.contains(".app") {
self.validatedBundlePath = appURL.path
break
}
}
}
}
}
func loadInfoPlist() {
guard let bundleURL = self.bundleURL else { return }
let infoPlistURL = bundleURL.appendingPathComponent("Info.plist")
if let plistInfo = PropertyListSerialization.propertyListWithURL(infoPlistURL) {
self.bundleName = plistInfo[String(kCFBundleNameKey)] as? String ?? ""
self.displayName = plistInfo["CFBundleDisplayName"] as? String ?? ""
self.shortVersion = plistInfo["CFBundleShortVersionString"] as? String ?? ""
self.version = plistInfo[String(kCFBundleVersionKey)] as? String ?? ""
self.minOSVersion = plistInfo["MinimumOSVersion"] as? String
if self.displayName.isEmpty {
self.displayName = self.bundleName
}
if let bundleIcons = plistInfo["CFBundleIcons"] as? [String : AnyObject] {
let primaryIconValue = bundleIcons["CFBundlePrimaryIcon"].flatMap { item -> [String : AnyObject]? in
switch item {
case let dict as [String : AnyObject]: return dict
case let str as String: return ["CFBundleIconFiles" : [str]] as [String : AnyObject]
default: return nil
}
}
if let primaryIcon = primaryIconValue {
if let bundleIconFiles = primaryIcon["CFBundleIconFiles"] as? [String] {
for iconName in bundleIconFiles {
var iconURL = bundleURL.appendingPathComponent(iconName)
let icon2XURL = bundleURL.appendingPathComponent("\(iconName)@2x.png")
if iconURL.pathExtension.isEmpty {
iconURL = iconURL.appendingPathComponent("png")
}
// .car files not yet working :/
// if !iconURL.validPath && !icon2XURL.validPath { // Believe this would only happen once per bundle
// let assetFileURL = bundleURL.URLByAppendingPathComponent("Assets.car")
//
// if assetFileURL.validPath {
// if let catalog = try? CUICatalog.init(URL: assetFileURL) {
// let catalogImages = catalog.imagesWithName(iconName)
//
// for catalogImage in catalogImages {
// if let namedImage = catalogImage as? CUINamedImage where !(namedImage is CUINamedLayerStack) {
// if self.icon?.size.width ?? 0 < namedImage.size.width {
// let imageRep = NSBitmapImageRep(CGImage: namedImage.image)
//
// imageRep.size = namedImage.size
// if let pngData = imageRep.representationUsingType(.NSPNGFileType, properties: [NSImageInterlaced : false]) where pngData.length > 0 {
// self.icon = NSImage(data: pngData)
// }
// self.icon = NSImage(CGImage: namedImage.image, size: namedImage.size)
// }
// }
// }
// }
// }
// }
// else {
if let icon = NSImage(contentsOf: iconURL) {
if self.icon?.size.width ?? 0 < icon.size.width {
self.icon = icon
}
}
if let icon = NSImage(contentsOf: icon2XURL) {
if self.icon?.size.width ?? 0 < icon.size.width {
self.icon = icon
}
}
// }
}
}
}
}
if self.icon == nil {
self.icon = NSImage(named: "default_icon")
}
}
}
// MARK: - OutlineProvider -
var outlineTitle : String { return self.displayName }
var outlineImage : NSImage? { return self.icon }
var childCount : Int { return 0 }
func childAt(index: Int) -> OutlineProvider? {
return nil
}
// MARK: - PropertyProvider -
var header : String { return "App Information" }
var image : NSImage? { return self.icon }
var properties : [SimProperty] {
var version = self.shortVersion
var properties : [SimProperty]
if self.shortVersion != self.version {
version += " \((self.version))"
}
properties = [
SimProperty(title: "Display Name", value: .Text(text: self.displayName)),
SimProperty(title: "Bundle Name", value: .Text(text: self.bundleName)),
SimProperty(title: "Bundle ID", value: .Text(text: self.bundleID)),
SimProperty(title: "Version", value: .Text(text: version))
]
if let minOSVersion = self.minOSVersion {
properties.append(SimProperty(title: "Minimum OS Version", value: .Text(text: minOSVersion)))
}
if let bundleURL = self.bundleURL {
properties.append(SimProperty(title: "Bundle", value: .Location(url: bundleURL)))
}
if let sandboxURL = self.sandboxURL {
properties.append(SimProperty(title: "Sandbox", value: .Location(url: sandboxURL)))
}
return properties
}
}

View file

@ -0,0 +1,52 @@
//
// SimCtl.swift
// SimDirs
//
// Created by Casey Fleser on 5/23/22.
//
import Foundation
class SimCtl {
static func run(args: [String]) throws -> Data {
let process = Process()
let pipe = Pipe()
process.executableURL = URL(fileURLWithPath: "/usr/bin/xcrun")
process.arguments = ["simctl"] + args
process.standardOutput = pipe
try process.run()
return pipe.fileHandleForReading.readDataToEndOfFile()
}
static func run(args: [String]) throws -> String {
return String(data: try run(args: args), encoding: .utf8) ?? ""
}
static func dumpRuntimes() {
print("dumpRuntimes")
do {
let json : String = try run(args: ["list", "-j", "runtimes"])
print("json: \(json)")
}
catch {
print(error)
}
}
static func dumpDevices() {
print("dumpDevices")
do {
let json : String = try run(args: ["list", "-j", "devices"])
print("json: \(json)")
}
catch {
print(error)
}
}
}

View file

@ -2,150 +2,31 @@
// SimDevice.swift
// SimDirs
//
// Created by Casey Fleser on 4/30/16.
// Copyright © 2016 Quiet Spark. All rights reserved.
// Created by Casey Fleser on 5/24/22.
//
import Foundation
class SimDevice: OutlineProvider, PropertyProvider {
let name : String
let type : String
let udid : String
let baseURL : URL
var platformName = "Unknown"
var platformVersion = ""
var platformBuild = ""
var apps = [SimApp]()
struct SimDevice: Decodable {
let name : String
let udid : String
let state : String
let dataPath : String
let dataPathSize : Int
let logPath : String
let isAvailable : Bool
let deviceTypeIdentifier : String
let availabilityError : String?
init(name: String, type: String, udid: String, baseURL: URL) {
self.name = name
self.type = type
self.udid = udid
self.baseURL = baseURL
self.gatherBuildInfo()
self.gatherAppInfoFromLastLaunchMap()
self.gatherAppInfoFromAppState()
// self.gatherAppInfoFromCaches() obsolete
self.gatherAppInfoFromInstallLogs()
}
func completeScan(platformName: String) {
self.platformName = platformName
self.apps = self.apps.filter { return $0.hasValidPaths }
for app in self.apps {
app.completeScan()
}
self.apps.sort(by: { $0.displayName < $1.displayName })
}
func gatherBuildInfo() {
let buildInfoURL = self.baseURL.appendingPathComponent("data/Library/MobileInstallation/LastBuildInfo.plist")
guard let buildInfo = PropertyListSerialization.propertyListWithURL(buildInfoURL) else { return }
self.platformVersion = buildInfo["ProductVersion"] as? String ?? ""
self.platformBuild = buildInfo["ProductBuildVersion"] as? String ?? ""
}
// LastLaunchServicesMap.plist seems to be the most reliable location to gather app info
func gatherAppInfoFromLastLaunchMap() {
let launchMapInfoURL = self.baseURL.appendingPathComponent("data/Library/MobileInstallation/LastLaunchServicesMap.plist")
guard let launchInfo = PropertyListSerialization.propertyListWithURL(launchMapInfoURL) else { return }
guard let userInfo = launchInfo["User"] as? [String : AnyObject] else { return }
for (bundleID, bundleInfo) in userInfo {
guard let bundleInfo = bundleInfo as? [String : AnyObject] else { continue }
let simApp = self.apps.match({ $0.bundleID == bundleID }, orMake: { SimApp(bundleID: bundleID) })
simApp.updateFrom(launchBundleInfo: bundleInfo)
}
}
// applicationState.plist sometimes has info that LastLaunchServicesMap.plist doesn't
func gatherAppInfoFromAppState() {
for pathComponent in ["data/Library/FrontBoard/applicationState.plist", "data/Library/BackBoard/applicationState.plist"] {
let appStateInfoURL = self.baseURL.appendingPathComponent(pathComponent)
guard let stateInfo = PropertyListSerialization.propertyListWithURL(appStateInfoURL) else { continue }
for (bundleID, bundleInfo) in stateInfo {
if !bundleID.contains("com.apple") {
guard let bundleInfo = bundleInfo as? [String : AnyObject] else { continue }
let simApp = self.apps.match({ $0.bundleID == bundleID }, orMake: { SimApp(bundleID: bundleID) })
simApp.updateFrom(appStateInfo: bundleInfo)
}
}
}
}
// mobile_installation.log.0 is my least favorite, most fragile way to scan for app installations
// try this after everything else
func gatherAppInfoFromInstallLogs() {
let installLogURL = self.baseURL.appendingPathComponent("data/Library/Logs/MobileInstallation/mobile_installation.log.0")
if let installLog = try? String(contentsOf: installLogURL) {
let lines = installLog.components(separatedBy: .newlines)
for line in lines.reversed() {
if !line.contains("com.apple") {
if line.contains("makeContainerLiveReplacingContainer") {
self.extractBundleLocationFrom(logEntry: line)
}
if line.contains("_refreshUUIDForContainer") {
self.extractSandboxLocationFrom(logEntry: line)
}
}
}
}
}
func extractBundleLocationFrom(logEntry: String) {
let logComponents = logEntry.split(separator: (" ")).map({ String($0) })
if let bundlePath = logComponents.last {
if let bundleID = logComponents[safe: logComponents.count - 3] {
let simApp = self.apps.match({ $0.bundleID == bundleID }, orMake: { SimApp(bundleID: bundleID) })
simApp.bundlePath = bundlePath
}
}
}
func extractSandboxLocationFrom(logEntry: String) {
let logComponents = logEntry.split(separator: (" ")).map({ String($0) })
if let sandboxPath = logComponents.last {
if let bundleID = logComponents[safe: logComponents.count - 5] {
let simApp = self.apps.match({ $0.bundleID == bundleID }, orMake: { SimApp(bundleID: bundleID) })
simApp.sandboxPath = sandboxPath
}
}
}
// MARK: - OutlineProvider -
var outlineTitle : String { return self.name }
var outlineImage : NSImage? { return nil }
var childCount : Int { return self.apps.count }
func childAt(index: Int) -> OutlineProvider? {
return self.apps[index]
}
// MARK: - PropertyProvider -
var header : String { return "Device Information" }
var image : NSImage? { return nil }
var properties : [SimProperty] {
return [
SimProperty(title: "Name", value: .Text(text: self.name)),
SimProperty(title: "Simulated Model", value: .Text(text: self.type)),
SimProperty(title: self.platformName, value: .Text(text: "\(self.platformVersion) (\(self.platformBuild))")),
SimProperty(title: "Identifier", value: .Text(text: self.udid)),
SimProperty(title: "Location", value: .Location(url: self.baseURL))
]
}
func isDeviceOfType(_ deviceType: SimDeviceType) -> Bool {
return deviceTypeIdentifier == deviceType.identifier
}
}
extension SimDevice: PresentableItem {
var title : String { return name }
var id : String { return udid }
var imageName : String { return "shippingbox" } // FIXME
}

View file

@ -0,0 +1,46 @@
//
// SimDeviceType.swift
// SimDirs
//
// Created by Casey Fleser on 5/24/22.
//
import Foundation
struct SimDeviceType: Decodable {
// enum CodingKeys: String, CodingKey {
// case bundlePath
// case identifier
// case maxRuntimeVersion
// case maxRuntimeVersionString
// case minRuntimeVersion
// case minRuntimeVersionString
// case modelIdentifier
// case name
// case productFamily
// }
//
let name : String
let identifier : String
let productFamily : SimProductFamily
let modelIdentifier : String
let bundlePath : String
let minRuntimeVersion : Int
let maxRuntimeVersion : Int
let minRuntimeVersionString : String
let maxRuntimeVersionString : String
func supports(productFamily: SimProductFamily) -> Bool {
return productFamily == self.productFamily
}
func supports(runtime: SimRuntime) -> Bool {
return runtime.supportedDeviceTypes.contains { $0.identifier == identifier }
}
}
extension SimDeviceType: PresentableItem {
var title : String { return name }
var id : String { return identifier }
var imageName : String { return productFamily.imageName }
}

View file

@ -0,0 +1,53 @@
//
// SimModel.swift
// SimDirs
//
// Created by Casey Fleser on 5/24/22.
//
import Foundation
enum SimError: Error {
case deviceParsingFailure
}
struct SimModel {
var deviceTypes : [SimDeviceType]
var runtimes : [SimRuntime]
init() {
do {
var json : Data
let decoder = JSONDecoder()
let runtimeDevs : [String : [SimDevice]]
// - [SimDeviceType]
json = try SimCtl.run(args: ["list", "-j", "devicetypes"])
deviceTypes = try decoder.decode([String : [SimDeviceType]].self, from: json)["devicetypes"] ?? []
// - [SimRuntime]
json = try SimCtl.run(args: ["list", "-j", "runtimes"])
runtimes = try decoder.decode([String : [SimRuntime]].self, from: json)["runtimes"] ?? []
// - [SimDevice]
json = try SimCtl.run(args: ["list", "-j", "devices"])
runtimeDevs = try decoder.decode([String : [String : [SimDevice]]] .self, from: json)["devices"] ?? [:]
for (runtimeID, devices) in runtimeDevs {
do {
let runtimeIdx = try runtimes.indexOfMatchedOrCreated(identifier: runtimeID)
runtimes[runtimeIdx].setDevices(devices, from: deviceTypes)
}
catch {
print("Warning: Unable to create placeholder runtime from \(runtimeID)")
}
}
runtimes.sort()
}
catch {
fatalError("Failed to initialize data model:\n\(error)")
}
}
}

View file

@ -1,46 +0,0 @@
//
// SimOSVersion.swift
// SimDirs
//
// Created by Casey Fleser on 4/30/16.
// Copyright © 2016 Quiet Spark. All rights reserved.
//
import Foundation
class SimOSVersion: OutlineProvider {
let name : String
var devices = [SimDevice]()
init(name: String, deviceInfo: [String : AnyObject]) {
self.name = name
}
func completeScan(platformName: String) {
for device in self.devices {
device.completeScan(platformName: platformName)
}
self.devices.sort(by: { $0.name < $1.name })
}
func updateWith(deviceInfo: [String : AnyObject], baseURL: URL) {
guard let deviceName = deviceInfo["name"] as? String else { return }
guard let deviceUDID = deviceInfo["UDID"] as? String else { return }
guard var deviceType = deviceInfo["deviceType"] as? String else { return }
deviceType = deviceType.replacingOccurrences(of: "com.apple.CoreSimulator.SimDeviceType.", with: "")
deviceType = deviceType.replacingOccurrences(of: "-", with: " ")
self.devices.append(SimDevice(name: deviceName, type: deviceType, udid: deviceUDID, baseURL: baseURL))
}
// MARK: - OutlineProvider -
var outlineTitle : String { return self.name }
var outlineImage : NSImage? { return nil }
var childCount : Int { return self.devices.count }
func childAt(index: Int) -> OutlineProvider? {
return self.devices[index]
}
}

View file

@ -2,71 +2,27 @@
// SimPlatform.swift
// SimDirs
//
// Created by Casey Fleser on 4/30/16.
// Copyright © 2016 Quiet Spark. All rights reserved.
// Created by Casey Fleser on 5/23/22.
//
import Foundation
class SimPlatform: OutlineProvider {
let name : String
var osVersions = [SimOSVersion]()
class func scan() -> [SimPlatform] {
let fileMgr = FileManager.default
var platforms = [SimPlatform]()
if let libraryURL = fileMgr.urls(for: .libraryDirectory, in: .userDomainMask).first {
let deviceURL = libraryURL.appendingPathComponent("Developer/CoreSimulator/Devices")
if let dirEnumerator = fileMgr.enumerator(at: deviceURL, includingPropertiesForKeys: nil, options: [ .skipsSubdirectoryDescendants, .skipsHiddenFiles ], errorHandler: nil) {
for baseURL in dirEnumerator.allObjects.compactMap({ $0 as? URL }) {
let deviceURL = baseURL.appendingPathComponent("device.plist")
guard let deviceInfo = PropertyListSerialization.propertyListWithURL(deviceURL) else { continue }
guard let runtime = deviceInfo["runtime"] as? String else { continue }
let runtimeComponents = runtime.replacingOccurrences(of: "com.apple.CoreSimulator.SimRuntime.", with: "").split(separator: "-").map({ String($0) })
enum SimPlatform: String, Decodable {
case iOS
case tvOS
case watchOS
if let platformName = runtimeComponents.first {
let platform = platforms.match({ $0.name == platformName }, orMake: { SimPlatform(runtimeComponents: runtimeComponents, deviceInfo: deviceInfo) })
platform.updateWith(runtimeComponents, deviceInfo: deviceInfo, baseURL: baseURL)
}
}
}
}
for platform in platforms {
platform.completeScan()
}
return platforms.sorted { $0.name < $1.name }
}
init(runtimeComponents: [String], deviceInfo: [String : AnyObject]) {
self.name = runtimeComponents[0]
}
func completeScan() {
for osVersion in self.osVersions {
osVersion.completeScan(platformName: self.name)
}
self.osVersions.sort(by: { $0.name > $1.name })
}
func updateWith(_ runtimeComponents: [String], deviceInfo: [String : AnyObject], baseURL: URL) {
let versionID = "\(runtimeComponents[safe: 1] ?? "0").\(runtimeComponents[safe: 2] ?? "0")"
let osVersion = self.osVersions.match({ $0.name == versionID }, orMake: { SimOSVersion(name: versionID, deviceInfo: deviceInfo) })
osVersion.updateWith(deviceInfo: deviceInfo, baseURL: baseURL)
}
// MARK: - OutlineProvider -
var outlineTitle : String { return self.name }
var outlineImage : NSImage? { return nil }
var childCount : Int { return self.osVersions.count }
func childAt(index: Int) -> OutlineProvider? {
return self.osVersions[index]
}
static let presentation : [SimPlatform] = [.iOS, .watchOS, .tvOS]
}
extension SimPlatform: PresentableItem {
var title : String { return self.rawValue }
var id : String { return self.rawValue }
var imageName : String {
switch self {
case .iOS: return "iphone"
case .tvOS: return "appletv"
case .watchOS: return "applewatch"
}
}
}

View file

@ -0,0 +1,31 @@
//
// SimProductFamily.swift
// SimDirs
//
// Created by Casey Fleser on 5/24/22.
//
import Foundation
enum SimProductFamily: String, Decodable {
case appleTV = "Apple TV"
case appleWatch = "Apple Watch"
case iPad
case iPhone
static let presentation : [SimProductFamily] = [.iPhone, .iPad, .appleWatch, .appleTV]
}
extension SimProductFamily: PresentableItem {
var title : String { return self.rawValue }
var id : String { return self.rawValue }
var imageName : String {
switch self {
case .iPad: return "ipad"
case .iPhone: return "iphone"
case .appleTV: return "appletv"
case .appleWatch: return "applewatch"
}
}
}

View file

@ -0,0 +1,130 @@
//
// SimRuntime.swift
// SimDirs
//
// Created by Casey Fleser on 5/24/22.
//
import Foundation
struct SimRuntime: Comparable, Decodable {
enum CodingKeys: String, CodingKey {
case availabilityError
case bundlePath
case buildversion
case identifier
case isAvailable
case isInternal
case name
case platform
case runtimeRoot
case supportedDeviceTypes
case version
}
struct DeviceType: Decodable {
let name : String
let bundlePath : String
let identifier : String
let productFamily : SimProductFamily
init(canonical: SimDeviceType) {
name = canonical.name
bundlePath = canonical.bundlePath
identifier = canonical.identifier
productFamily = canonical.productFamily
}
}
let name : String
let version : String
let identifier : String
let platform : SimPlatform
let bundlePath : String
let buildversion : String
let runtimeRoot : String
let isInternal : Bool
let isAvailable : Bool
var supportedDeviceTypes : [DeviceType]
let availabilityError : String?
var devices = [SimDevice]()
var isPlaceholder = false
static func < (lhs: SimRuntime, rhs: SimRuntime) -> Bool {
return lhs.name < rhs.name
}
static func == (lhs: SimRuntime, rhs: SimRuntime) -> Bool {
return lhs.identifier == rhs.identifier
}
init(platformID: String) throws {
guard let lastComponent = platformID.split(separator: ".").last else { throw SimError.deviceParsingFailure }
let vComps = lastComponent.split(separator: "-")
if vComps.count == 3 {
guard let compPlatform = SimPlatform(rawValue: String(vComps[0])) else { throw SimError.deviceParsingFailure }
guard let major = Int(vComps[1]) else { throw SimError.deviceParsingFailure }
guard let minor = Int(vComps[2]) else { throw SimError.deviceParsingFailure }
platform = compPlatform
version = "\(major).\(minor)"
name = "\(platform) \(version)"
identifier = platformID
bundlePath = ""
buildversion = ""
runtimeRoot = ""
isInternal = false
isAvailable = false
supportedDeviceTypes = []
availabilityError = "Missing runtime"
isPlaceholder = true
}
else {
throw SimError.deviceParsingFailure
}
}
func supports(deviceType: SimDeviceType) -> Bool {
return supportedDeviceTypes.contains { $0.identifier == deviceType.identifier }
}
func supports(platform: SimPlatform) -> Bool {
return self.platform == platform
}
mutating func setDevices(_ devices: [SimDevice], from devTypes: [SimDeviceType]) {
self.devices = devices
// If this runtime is a placeholder it will be missing supported device types
// create device type stubs based on the devices being added using supplied
// fully described device types
if isPlaceholder {
let devTypeIDs = Set(devices.map({ $0.deviceTypeIdentifier }))
self.supportedDeviceTypes = devTypeIDs.compactMap { devTypeID in
devTypes.first(where: { $0.identifier == devTypeID }).map({ SimRuntime.DeviceType(canonical: $0) })
}
}
}
}
extension SimRuntime: PresentableItem {
var title : String { return name }
var id : String { return identifier }
var imageName : String { return "v.circle" }
}
extension Array where Element == SimRuntime {
mutating func indexOfMatchedOrCreated(identifier: String) throws -> Index {
return try firstIndex { $0.identifier == identifier } ?? {
try self.append(SimRuntime(platformID: identifier))
return self.endIndex - 1
}()
}
}

View file

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -2,7 +2,9 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>
<key>com.apple.security.app-sandbox</key>
<false/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
</dict>
</plist>

36
SimDirs/SimDirsApp.swift Normal file
View file

@ -0,0 +1,36 @@
//
// SimDirsApp.swift
// SimDirs
//
// Created by Casey Fleser on 5/23/22.
//
import SwiftUI
@main
struct SimDirsApp: App {
@StateObject private var modelData = PresentableModel()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(modelData)
}
.commands {
SimCommands()
}
}
}
struct SimCommands: Commands {
var body: some Commands {
SidebarCommands()
CommandMenu("Commands") {
Button("Command") {
print("Command")
}
.keyboardShortcut("f", modifiers: [.shift, .option])
}
}
}

View file

@ -1,56 +0,0 @@
//
// Support.swift
// SimDirs
//
// Created by Casey Fleser on 4/30/16.
// Copyright © 2016 Quiet Spark. All rights reserved.
//
// Assorted convenience extensions
import Foundation
extension Array {
mutating func match(_ predicate: (Element) -> Bool, orMake: () -> Element) -> Element {
let element : Element
if let match = self.first(where: predicate) {
element = match
}
else {
element = orMake()
self.append(element)
}
return element
}
}
extension Collection {
subscript (safe index: Index) -> Iterator.Element? {
return indices.contains(index) ? self[index] : nil
}
}
extension String {
var validPath : Bool { return FileManager.default.fileExists(atPath: self) }
}
extension NSURL {
var validPath : Bool { return self.path.map { FileManager.default.fileExists(atPath: $0) } ?? false }
}
extension PropertyListSerialization {
class func propertyListWithURL(_ url: URL) -> [String : AnyObject]? {
guard let plistData = try? Data(contentsOf: url) else { return nil }
let plist : [String : AnyObject]?
do {
plist = try PropertyListSerialization.propertyList(from: plistData, options: [], format: nil) as? [String : AnyObject]
} catch {
plist = nil
}
return plist
}
}

View file

@ -1,40 +0,0 @@
//
// CUICatalog.h
// Asset Catalog Tinkerer
//
// Created by Guilherme Rambo on 27/09/15.
// Copyright (c) 2014 Guilherme Rambo. All rights reserved.
//
#import <Cocoa/Cocoa.h>
@interface CUINamedImage : NSObject
@property (copy, nonatomic) NSString *name;
@property (readonly, nonatomic) int exifOrientation;
@property (readonly, nonatomic) BOOL isStructured;
@property (readonly, nonatomic) NSInteger templateRenderingMode;
@property (readonly, nonatomic) BOOL isTemplate;
@property (readonly, nonatomic) BOOL isVectorBased;
@property (readonly, nonatomic) BOOL hasSliceInformation;
@property (readonly, nonatomic) NSInteger resizingMode;
@property (readonly, nonatomic) int blendMode;
@property (readonly, nonatomic) CGFloat opacity;
@property (readonly, nonatomic) NSInteger imageType;
@property (readonly, nonatomic) CGFloat scale;
@property (readonly, nonatomic) NSSize size;
@property (readonly, nonatomic) CGImageRef image;
@end
@interface CUICatalog : NSObject
+ (instancetype)systemUICatalog;
+ (instancetype)defaultUICatalog;
- (instancetype)initWithURL:(NSURL *)url error:(NSError **)outError;
@property (nonatomic, readonly) NSArray *allImageNames;
- (NSArray *)imagesWithName:(NSString *)name;
@end

View file

@ -1,28 +0,0 @@
//
// CUINamedLayerStack.h
// SimDirs
//
// Created by Casey Fleser on 4/30/16.
// Copyright © 2016 Quiet Spark. All rights reserved.
//
#import "CUICatalog.h"
@interface CUINamedLayerStack : CUINamedImage
@property(retain, nonatomic) NSArray *layers; // @synthesize layers=_layers;
@property(readonly, nonatomic) struct CGImage *radiosityImage;
@property(readonly, nonatomic) struct CGImage *flattenedImage;
- (id)layerImageAtIndex:(unsigned long long)arg1;
@property(readonly, nonatomic) struct CGSize size;
@end
@interface CUINamedLayerImage : CUINamedImage
@property(nonatomic) int blendMode; // @synthesize blendMode=_blendMode;
@property(nonatomic) double opacity; // @synthesize opacity=_opacity;
@property(nonatomic) struct CGRect frame; // @synthesize frame=_frame;
@end

View file

@ -1,10 +0,0 @@
//
// SimDirs-Bridge.h
// SimDirs
//
// Created by Casey Fleser on 4/30/16.
// Copyright © 2016 Quiet Spark. All rights reserved.
//
#import "CUICatalog.h"
#import "CUINamedLayerStack.h"

View file

@ -1,18 +0,0 @@
//
// ActionCell.swift
// SimDirs
//
// Created by Casey Fleser on 5/1/16.
// Copyright © 2016 Quiet Spark. All rights reserved.
//
import Cocoa
class ActionCell: NSView {
@IBOutlet weak var actionButton : NSButton!
var action : (() -> ())?
@IBAction func executeAction(_ sender: Any) {
action?()
}
}

View file

@ -1,92 +0,0 @@
//
// DetailController.swift
// SimDirs
//
// Created by Casey Fleser on 5/1/16.
// Copyright © 2016 Quiet Spark. All rights reserved.
//
import Cocoa
struct SimProperty {
enum Value {
case Text(text: String)
case Location(url: URL)
}
let title : String
let value : Value
init(title: String, value: Value) {
self.title = title
self.value = value
}
}
protocol PropertyProvider: AnyObject {
var header : String { get }
var image : NSImage? { get }
var properties : [SimProperty] { get }
}
class EmptyProvider: PropertyProvider {
let header = ""
let image : NSImage? = nil
let properties = [SimProperty]()
}
class DetailController: NSViewController, NSTableViewDataSource, NSTableViewDelegate {
@IBOutlet weak var headerLabel : NSTextField!
@IBOutlet weak var imageView : NSImageView!
@IBOutlet weak var propertyTable : NSTableView!
let emptyProvider = EmptyProvider()
var selectedItem : Any? { didSet { self.reload() } }
var selectedProvider : PropertyProvider { return (self.selectedItem as? PropertyProvider) ?? self.emptyProvider }
override func viewDidLoad() {
super.viewDidLoad()
self.reload()
}
func reload() {
self.headerLabel.stringValue = self.selectedProvider.header
self.imageView.image = self.selectedProvider.image
self.propertyTable.reloadData()
}
// MARK: - NSTableViewDataSource -
func numberOfRows(in tableView: NSTableView) -> Int {
return self.selectedProvider.properties.count
}
// MARK: - NSTableViewDelegate -
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
let selectedProperty = self.selectedProvider.properties[row]
let columnIdentifier = tableColumn?.identifier ?? NSUserInterfaceItemIdentifier("")
let view : NSView?
switch columnIdentifier.rawValue {
case "value":
switch selectedProperty.value {
case .Text(let text):
view = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier("PropertyValueCell"), owner: self)
(view as? NSTableCellView)?.textField?.stringValue = text
case .Location(let url):
view = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier("PropertyActionCell"), owner: self)
if let actionCell = view as? ActionCell {
actionCell.action = { NSWorkspace.shared.activateFileViewerSelecting([url]) }
}
}
default:
view = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier("PropertyTitleCell"), owner: self)
(view as? NSTableCellView)?.textField?.stringValue = selectedProperty.title
}
return view
}
}

View file

@ -1,18 +0,0 @@
//
// DetailTableView.swift
// SimDirs
//
// Created by Casey Fleser on 5/1/16.
// Copyright © 2016 Quiet Spark. All rights reserved.
//
import Cocoa
class DetailTableView: NSTableView {
override func drawGrid(inClipRect: NSRect) {
let lastRowRect = self.rect(ofRow: self.numberOfRows - 1)
let adjClipRect = NSRect(x: 0.0, y: 0.0, width: lastRowRect.width, height: lastRowRect.maxY)
super.drawGrid(inClipRect: NSIntersectionRect(inClipRect, adjClipRect))
}
}

View file

@ -1,91 +0,0 @@
//
// SourceController.swift
// SimDirs
//
// Created by Casey Fleser on 4/30/16.
// Copyright © 2016 Quiet Spark. All rights reserved.
//
import Cocoa
protocol OutlineProvider: AnyObject {
var outlineTitle : String { get }
var outlineImage : NSImage? { get }
var childCount : Int { get }
func childAt(index: Int) -> OutlineProvider?
}
extension OutlineProvider {
var expandable : Bool { return self.childCount > 0 }
}
class SourceController: NSViewController, NSOutlineViewDataSource, NSOutlineViewDelegate {
@IBOutlet weak var outlineView : NSOutlineView!
private var platforms = [SimPlatform]()
override func viewDidLoad() {
super.viewDidLoad()
self.rescan(nil)
}
// MARK: - NSOutlineViewDataSource -
func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
return (item as? OutlineProvider)?.childCount ?? self.platforms.count
}
func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
return (item as? OutlineProvider)?.childAt(index: index) ?? self.platforms[index]
}
func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool {
return (item as? OutlineProvider)?.expandable ?? (self.platforms.count > 0)
}
// MARK: - NSOutlineViewDelegate -
func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? {
var view : NSTableCellView? = nil
var title = ""
var image : NSImage? = nil
if let outlineProvider = item as? OutlineProvider {
title = outlineProvider.outlineTitle
image = outlineProvider.outlineImage
}
if let outlineCell = outlineView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(image != nil ? "ImageCell" : "TextCell"), owner: self) as? NSTableCellView {
outlineCell.textField?.stringValue = title
outlineCell.imageView?.image = image
view = outlineCell
}
return view
}
func outlineView(_ outlineView: NSOutlineView, heightOfRowByItem item: Any) -> CGFloat {
return (item as? OutlineProvider)?.outlineImage != nil ? 24.0 : 20.0
}
func outlineViewSelectionDidChange(_ notification: Notification) {
if let thing = (self.parent as? NSSplitViewController)?.splitViewItems[safe: 1]?.viewController as? DetailController {
var selectedItem : Any? = nil
let row = self.outlineView.selectedRow
if row != NSNotFound {
selectedItem = self.outlineView.item(atRow: row)
}
thing.selectedItem = selectedItem
}
}
// MARK: - Interaction -
@IBAction func rescan(_ sender: AnyObject?) {
self.platforms = SimPlatform.scan()
self.outlineView.reloadData()
}
}

View file

@ -1,19 +0,0 @@
//
// WindowController.swift
// SimDirs
//
// Created by Casey Fleser on 5/1/16.
// Copyright © 2016 Quiet Spark. All rights reserved.
//
import Cocoa
class WindowController: NSWindowController {
override func windowDidLoad() {
super.windowDidLoad()
self.window?.setFrameAutosaveName("main")
}
}

View file

@ -0,0 +1,38 @@
//
// DeviceTypeView.swift
// SimDirs
//
// Created by Casey Fleser on 5/25/22.
//
import SwiftUI
struct DeviceTypeView: View {
var deviceType : SimDeviceType
var body: some View {
VStack(alignment: .leading, spacing: 2.0) {
// Text(deviceType.name)
// .font(.title)
// .padding(.bottom, 5.0)
Group {
Text("Product Family: \(deviceType.productFamily.title)")
Text("Model ID: \(deviceType.modelIdentifier)")
Text("Identifier: \(deviceType.identifier)")
Text("Min Runtime: \(deviceType.minRuntimeVersionString)")
Text("Max Runtime: \(UInt32.max == deviceType.maxRuntimeVersion ? "-" : deviceType.maxRuntimeVersionString)")
Text("Bundle Path: \(deviceType.bundlePath)")
}
.font(.subheadline)
}
// .background(Color.red)
}
}
struct DeviceTypeView_Previews: PreviewProvider {
static let model = PresentableModel().baseModel
static var previews: some View {
DeviceTypeView(deviceType: model.deviceTypes[26])
}
}