## Gcc Patch
/*.gcno
-
+.DS_Store
swift format -i -r .
lint:
- swift format -m lint -r .
-
-docker-build:
- docker build --force-rm --build-arg swift_version=$(swift_version) -t doapp/do:$(swift_version) .
-
-docker-push: docker-build
- docker push doapp/do:$(swift_version)
+ swift format lint -r .
.PHONY: format lint docker-build docker-push
archiveVersion = 1;
classes = {
};
- objectVersion = 53;
+ objectVersion = 60;
objects = {
/* Begin PBXBuildFile section */
- B523C73D25C98D9800C44061 /* NSImage+writePNG.swift in Sources */ = {isa = PBXBuildFile; fileRef = B523C73C25C98D9800C44061 /* NSImage+writePNG.swift */; };
- B523C74625C9BD3500C44061 /* CloudKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B523C74525C9BD3500C44061 /* CloudKit.framework */; };
- B523C74B25C9C1BA00C44061 /* EmptyMapDetailScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = B523C74A25C9C1BA00C44061 /* EmptyMapDetailScreen.swift */; };
- B523C75A25C9FD4900C44061 /* MapAxes.swift in Sources */ = {isa = PBXBuildFile; fileRef = B523C75925C9FD4900C44061 /* MapAxes.swift */; };
- B523C76225CA05A300C44061 /* MapStages.swift in Sources */ = {isa = PBXBuildFile; fileRef = B523C76125CA05A300C44061 /* MapStages.swift */; };
- B523C76725CA071B00C44061 /* MapVertices.swift in Sources */ = {isa = PBXBuildFile; fileRef = B523C76625CA071B00C44061 /* MapVertices.swift */; };
- B523C76C25CA0DFA00C44061 /* MapEdges.swift in Sources */ = {isa = PBXBuildFile; fileRef = B523C76B25CA0DFA00C44061 /* MapEdges.swift */; };
- B523C77125CA121300C44061 /* MapBlockers.swift in Sources */ = {isa = PBXBuildFile; fileRef = B523C77025CA121300C44061 /* MapBlockers.swift */; };
- B523C77E25CA294C00C44061 /* MapOpportunities.swift in Sources */ = {isa = PBXBuildFile; fileRef = B523C77D25CA294C00C44061 /* MapOpportunities.swift */; };
- B526257225C874F9003E73B7 /* MapApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = B526257125C874F9003E73B7 /* MapApp.swift */; };
- B526257425C874F9003E73B7 /* MapEditorWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = B526257325C874F9003E73B7 /* MapEditorWindow.swift */; };
- B526257625C874FA003E73B7 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B526257525C874FA003E73B7 /* Assets.xcassets */; };
- B526257925C874FA003E73B7 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B526257825C874FA003E73B7 /* Preview Assets.xcassets */; };
- B526257B25C874FA003E73B7 /* Persistence.swift in Sources */ = {isa = PBXBuildFile; fileRef = B526257A25C874FA003E73B7 /* Persistence.swift */; };
- B526257E25C874FA003E73B7 /* Map.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B526257C25C874FA003E73B7 /* Map.xcdatamodeld */; };
- B526258A25C874FA003E73B7 /* MapTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B526258925C874FA003E73B7 /* MapTests.swift */; };
- B526259525C874FA003E73B7 /* MapUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B526259425C874FA003E73B7 /* MapUITests.swift */; };
- B52625A625C876C3003E73B7 /* MapDetailScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52625A525C876C3003E73B7 /* MapDetailScreen.swift */; };
- B52625AB25C87909003E73B7 /* Date+format.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52625AA25C87909003E73B7 /* Date+format.swift */; };
- B52625B025C87C14003E73B7 /* MapRenderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52625AF25C87C14003E73B7 /* MapRenderView.swift */; };
- B52625BB25C884C2003E73B7 /* Map+parse.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52625BA25C884C2003E73B7 /* Map+parse.swift */; };
- B52625C625C8BD2A003E73B7 /* Stage.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52625C525C8BD2A003E73B7 /* Stage.swift */; };
- B539516C25CB0C9300959F72 /* Store.swift in Sources */ = {isa = PBXBuildFile; fileRef = B539516B25CB0C9200959F72 /* Store.swift */; };
- B539517425CB0CA400959F72 /* AppState.swift in Sources */ = {isa = PBXBuildFile; fileRef = B539517325CB0CA400959F72 /* AppState.swift */; };
- B539518125CB2D7A00959F72 /* MapTextEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B539518025CB2D7A00959F72 /* MapTextEditor.swift */; };
- B5CF75C925CC19FC003BFF3D /* EvolutionPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CF75C825CC19FC003BFF3D /* EvolutionPicker.swift */; };
- B5CF75CF25CC7965003BFF3D /* MapParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CF75CE25CC7965003BFF3D /* MapParser.swift */; };
- B5CF75D825CC79BC003BFF3D /* VertexParserStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CF75D725CC79BC003BFF3D /* VertexParserStrategy.swift */; };
- B5CF75DD25CC79D7003BFF3D /* EdgeParserStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CF75DC25CC79D7003BFF3D /* EdgeParserStrategy.swift */; };
- B5CF75E225CC79ED003BFF3D /* BlockerParserStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CF75E125CC79ED003BFF3D /* BlockerParserStrategy.swift */; };
- B5CF75EA25CC7A13003BFF3D /* OpportunityParserStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CF75E925CC7A13003BFF3D /* OpportunityParserStrategy.swift */; };
- B5CF75EF25CC7A4A003BFF3D /* StageParserStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CF75EE25CC7A4A003BFF3D /* StageParserStrategy.swift */; };
- B5CF75F725CC97CA003BFF3D /* Debouncer.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CF75F625CC97CA003BFF3D /* Debouncer.swift */; };
- B5F8D3082A06DD8C000EEA24 /* Font+Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5F8D3072A06DD8C000EEA24 /* Font+Theme.swift */; };
- B5F8D30B2A06E3E6000EEA24 /* Color+Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5F8D30A2A06E3E6000EEA24 /* Color+Theme.swift */; };
- B5F8D30E2A06E5C2000EEA24 /* Patterns in Frameworks */ = {isa = PBXBuildFile; productRef = B5F8D30D2A06E5C2000EEA24 /* Patterns */; };
- B5F8D3102A07B33D000EEA24 /* NSColor+Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5F8D30F2A07B33D000EEA24 /* NSColor+Theme.swift */; };
- B5F8D3122A07B690000EEA24 /* NoteParserStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5F8D3112A07B690000EEA24 /* NoteParserStrategy.swift */; };
- B5F8D3142A07C05F000EEA24 /* MapNotes.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5F8D3132A07C05F000EEA24 /* MapNotes.swift */; };
+ B5012E3F2C96232A00AC4D68 /* EvolutionPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5012E3E2C96232300AC4D68 /* EvolutionPicker.swift */; };
+ B5012E422C96235E00AC4D68 /* Stage.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5012E412C96235B00AC4D68 /* Stage.swift */; };
+ B5012E452C9623C700AC4D68 /* Font+theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5012E442C9623C500AC4D68 /* Font+theme.swift */; };
+ B5012E472C96243C00AC4D68 /* MapTextEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5012E462C96243500AC4D68 /* MapTextEditor.swift */; };
+ B5012E492C96245B00AC4D68 /* Color+theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5012E482C96245800AC4D68 /* Color+theme.swift */; };
+ B5012E4B2C96246F00AC4D68 /* NSColor+theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5012E4A2C96246D00AC4D68 /* NSColor+theme.swift */; };
+ B5012E572C96249400AC4D68 /* NoteParserStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5012E4D2C96249400AC4D68 /* NoteParserStrategy.swift */; };
+ B5012E582C96249400AC4D68 /* BlockerParserStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5012E4F2C96249400AC4D68 /* BlockerParserStrategy.swift */; };
+ B5012E592C96249400AC4D68 /* VertexParserStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5012E4C2C96249400AC4D68 /* VertexParserStrategy.swift */; };
+ B5012E5A2C96249400AC4D68 /* MapParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5012E532C96249400AC4D68 /* MapParser.swift */; };
+ B5012E5B2C96249400AC4D68 /* OpportunityParserStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5012E502C96249400AC4D68 /* OpportunityParserStrategy.swift */; };
+ B5012E5C2C96249400AC4D68 /* EdgeParserStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5012E4E2C96249400AC4D68 /* EdgeParserStrategy.swift */; };
+ B5012E5D2C96249400AC4D68 /* StageParserStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5012E512C96249400AC4D68 /* StageParserStrategy.swift */; };
+ B5012E5E2C96249400AC4D68 /* Debouncer.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5012E552C96249400AC4D68 /* Debouncer.swift */; };
+ B5012E622C96254700AC4D68 /* MapRenderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5012E5F2C96254700AC4D68 /* MapRenderView.swift */; };
+ B5012E6B2C96255A00AC4D68 /* MapAxes.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5012E632C96255A00AC4D68 /* MapAxes.swift */; };
+ B5012E6C2C96255A00AC4D68 /* MapVertices.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5012E652C96255A00AC4D68 /* MapVertices.swift */; };
+ B5012E6D2C96255A00AC4D68 /* MapStages.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5012E642C96255A00AC4D68 /* MapStages.swift */; };
+ B5012E6E2C96255A00AC4D68 /* MapNotes.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5012E662C96255A00AC4D68 /* MapNotes.swift */; };
+ B5012E6F2C96255A00AC4D68 /* MapEdges.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5012E672C96255A00AC4D68 /* MapEdges.swift */; };
+ B5012E702C96255A00AC4D68 /* MapOpportunities.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5012E692C96255A00AC4D68 /* MapOpportunities.swift */; };
+ B5012E712C96255A00AC4D68 /* MapBlockers.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5012E682C96255A00AC4D68 /* MapBlockers.swift */; };
+ B5012E742C9625E200AC4D68 /* Patterns in Frameworks */ = {isa = PBXBuildFile; productRef = B5012E732C9625E200AC4D68 /* Patterns */; };
+ B5012E7A2C96F02F00AC4D68 /* Dimensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5012E792C96F02E00AC4D68 /* Dimensions.swift */; };
+ B5012E7C2C972B6C00AC4D68 /* GroupParserStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5012E7B2C972B6600AC4D68 /* GroupParserStrategy.swift */; };
+ B5012E7F2C97315800AC4D68 /* ConcaveHull in Frameworks */ = {isa = PBXBuildFile; productRef = B5012E7E2C97315800AC4D68 /* ConcaveHull */; };
+ B5012E812C97318600AC4D68 /* MapGroups.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5012E802C97318300AC4D68 /* MapGroups.swift */; };
+ B5012E872C97874600AC4D68 /* MapGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5012E862C97874400AC4D68 /* MapGroup.swift */; };
+ B5012E8A2C98235500AC4D68 /* MapCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5012E892C98235300AC4D68 /* MapCommands.swift */; };
+ B5012E8C2C98244000AC4D68 /* ViewStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5012E8B2C98243E00AC4D68 /* ViewStyle.swift */; };
+ B5012E8E2C9828D000AC4D68 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5012E8D2C9828CE00AC4D68 /* Constants.swift */; };
+ B54587102C961E9C0067B788 /* MapApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = B545870F2C961E9C0067B788 /* MapApp.swift */; };
+ B54587122C961E9C0067B788 /* MapDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54587112C961E9C0067B788 /* MapDocument.swift */; };
+ B54587142C961E9C0067B788 /* MapEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54587132C961E9C0067B788 /* MapEditor.swift */; };
+ B54587162C961E9E0067B788 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B54587152C961E9E0067B788 /* Assets.xcassets */; };
+ B54587192C961E9E0067B788 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B54587182C961E9E0067B788 /* Preview Assets.xcassets */; };
+ B54587252C961E9E0067B788 /* MapTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54587242C961E9E0067B788 /* MapTests.swift */; };
+ B545872F2C961E9E0067B788 /* MapUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B545872E2C961E9E0067B788 /* MapUITests.swift */; };
+ B54587312C961E9E0067B788 /* MapUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54587302C961E9E0067B788 /* MapUITestsLaunchTests.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
- B526258625C874FA003E73B7 /* PBXContainerItemProxy */ = {
+ B54587212C961E9E0067B788 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
- containerPortal = B526256625C874F9003E73B7 /* Project object */;
+ containerPortal = B54587042C961E9C0067B788 /* Project object */;
proxyType = 1;
- remoteGlobalIDString = B526256D25C874F9003E73B7;
- remoteInfo = Map;
+ remoteGlobalIDString = B545870B2C961E9C0067B788;
+ remoteInfo = Map2;
};
- B526259125C874FA003E73B7 /* PBXContainerItemProxy */ = {
+ B545872B2C961E9E0067B788 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
- containerPortal = B526256625C874F9003E73B7 /* Project object */;
+ containerPortal = B54587042C961E9C0067B788 /* Project object */;
proxyType = 1;
- remoteGlobalIDString = B526256D25C874F9003E73B7;
- remoteInfo = Map;
+ remoteGlobalIDString = B545870B2C961E9C0067B788;
+ remoteInfo = Map2;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
- B523C73C25C98D9800C44061 /* NSImage+writePNG.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSImage+writePNG.swift"; sourceTree = "<group>"; };
- B523C74525C9BD3500C44061 /* CloudKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CloudKit.framework; path = System/Library/Frameworks/CloudKit.framework; sourceTree = SDKROOT; };
- B523C74A25C9C1BA00C44061 /* EmptyMapDetailScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyMapDetailScreen.swift; sourceTree = "<group>"; };
- B523C75925C9FD4900C44061 /* MapAxes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapAxes.swift; sourceTree = "<group>"; };
- B523C76125CA05A300C44061 /* MapStages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapStages.swift; sourceTree = "<group>"; };
- B523C76625CA071B00C44061 /* MapVertices.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapVertices.swift; sourceTree = "<group>"; };
- B523C76B25CA0DFA00C44061 /* MapEdges.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapEdges.swift; sourceTree = "<group>"; };
- B523C77025CA121300C44061 /* MapBlockers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapBlockers.swift; sourceTree = "<group>"; };
- B523C77D25CA294C00C44061 /* MapOpportunities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapOpportunities.swift; sourceTree = "<group>"; };
- B526256E25C874F9003E73B7 /* Map.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Map.app; sourceTree = BUILT_PRODUCTS_DIR; };
- B526257125C874F9003E73B7 /* MapApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapApp.swift; sourceTree = "<group>"; };
- B526257325C874F9003E73B7 /* MapEditorWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapEditorWindow.swift; sourceTree = "<group>"; };
- B526257525C874FA003E73B7 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
- B526257825C874FA003E73B7 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
- B526257A25C874FA003E73B7 /* Persistence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Persistence.swift; sourceTree = "<group>"; };
- B526257D25C874FA003E73B7 /* Map.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Map.xcdatamodel; sourceTree = "<group>"; };
- B526257F25C874FA003E73B7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
- B526258025C874FA003E73B7 /* Map.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Map.entitlements; sourceTree = "<group>"; };
- B526258525C874FA003E73B7 /* MapTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MapTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
- B526258925C874FA003E73B7 /* MapTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapTests.swift; sourceTree = "<group>"; };
- B526258B25C874FA003E73B7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
- B526259025C874FA003E73B7 /* MapUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MapUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
- B526259425C874FA003E73B7 /* MapUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapUITests.swift; sourceTree = "<group>"; };
- B526259625C874FA003E73B7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
- B52625A525C876C3003E73B7 /* MapDetailScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapDetailScreen.swift; sourceTree = "<group>"; };
- B52625AA25C87909003E73B7 /* Date+format.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+format.swift"; sourceTree = "<group>"; };
- B52625AF25C87C14003E73B7 /* MapRenderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapRenderView.swift; sourceTree = "<group>"; };
- B52625BA25C884C2003E73B7 /* Map+parse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Map+parse.swift"; sourceTree = "<group>"; };
- B52625C525C8BD2A003E73B7 /* Stage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Stage.swift; sourceTree = "<group>"; };
- B539516B25CB0C9200959F72 /* Store.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Store.swift; sourceTree = "<group>"; };
- B539517325CB0CA400959F72 /* AppState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppState.swift; sourceTree = "<group>"; };
- B539518025CB2D7A00959F72 /* MapTextEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapTextEditor.swift; sourceTree = "<group>"; };
- B5CF75C825CC19FC003BFF3D /* EvolutionPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EvolutionPicker.swift; sourceTree = "<group>"; };
- B5CF75CE25CC7965003BFF3D /* MapParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapParser.swift; sourceTree = "<group>"; };
- B5CF75D725CC79BC003BFF3D /* VertexParserStrategy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VertexParserStrategy.swift; sourceTree = "<group>"; };
- B5CF75DC25CC79D7003BFF3D /* EdgeParserStrategy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EdgeParserStrategy.swift; sourceTree = "<group>"; };
- B5CF75E125CC79ED003BFF3D /* BlockerParserStrategy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockerParserStrategy.swift; sourceTree = "<group>"; };
- B5CF75E925CC7A13003BFF3D /* OpportunityParserStrategy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpportunityParserStrategy.swift; sourceTree = "<group>"; };
- B5CF75EE25CC7A4A003BFF3D /* StageParserStrategy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StageParserStrategy.swift; sourceTree = "<group>"; };
- B5CF75F625CC97CA003BFF3D /* Debouncer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Debouncer.swift; sourceTree = "<group>"; };
- B5F8D3072A06DD8C000EEA24 /* Font+Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Font+Theme.swift"; sourceTree = "<group>"; };
- B5F8D30A2A06E3E6000EEA24 /* Color+Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+Theme.swift"; sourceTree = "<group>"; };
- B5F8D30F2A07B33D000EEA24 /* NSColor+Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSColor+Theme.swift"; sourceTree = "<group>"; };
- B5F8D3112A07B690000EEA24 /* NoteParserStrategy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteParserStrategy.swift; sourceTree = "<group>"; };
- B5F8D3132A07C05F000EEA24 /* MapNotes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapNotes.swift; sourceTree = "<group>"; };
+ B5012E3E2C96232300AC4D68 /* EvolutionPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EvolutionPicker.swift; sourceTree = "<group>"; };
+ B5012E412C96235B00AC4D68 /* Stage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Stage.swift; sourceTree = "<group>"; };
+ B5012E442C9623C500AC4D68 /* Font+theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Font+theme.swift"; sourceTree = "<group>"; };
+ B5012E462C96243500AC4D68 /* MapTextEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapTextEditor.swift; sourceTree = "<group>"; };
+ B5012E482C96245800AC4D68 /* Color+theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+theme.swift"; sourceTree = "<group>"; };
+ B5012E4A2C96246D00AC4D68 /* NSColor+theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSColor+theme.swift"; sourceTree = "<group>"; };
+ B5012E4C2C96249400AC4D68 /* VertexParserStrategy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VertexParserStrategy.swift; sourceTree = "<group>"; };
+ B5012E4D2C96249400AC4D68 /* NoteParserStrategy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteParserStrategy.swift; sourceTree = "<group>"; };
+ B5012E4E2C96249400AC4D68 /* EdgeParserStrategy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EdgeParserStrategy.swift; sourceTree = "<group>"; };
+ B5012E4F2C96249400AC4D68 /* BlockerParserStrategy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockerParserStrategy.swift; sourceTree = "<group>"; };
+ B5012E502C96249400AC4D68 /* OpportunityParserStrategy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpportunityParserStrategy.swift; sourceTree = "<group>"; };
+ B5012E512C96249400AC4D68 /* StageParserStrategy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StageParserStrategy.swift; sourceTree = "<group>"; };
+ B5012E532C96249400AC4D68 /* MapParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapParser.swift; sourceTree = "<group>"; };
+ B5012E552C96249400AC4D68 /* Debouncer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Debouncer.swift; sourceTree = "<group>"; };
+ B5012E5F2C96254700AC4D68 /* MapRenderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapRenderView.swift; sourceTree = "<group>"; };
+ B5012E632C96255A00AC4D68 /* MapAxes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapAxes.swift; sourceTree = "<group>"; };
+ B5012E642C96255A00AC4D68 /* MapStages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapStages.swift; sourceTree = "<group>"; };
+ B5012E652C96255A00AC4D68 /* MapVertices.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapVertices.swift; sourceTree = "<group>"; };
+ B5012E662C96255A00AC4D68 /* MapNotes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapNotes.swift; sourceTree = "<group>"; };
+ B5012E672C96255A00AC4D68 /* MapEdges.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapEdges.swift; sourceTree = "<group>"; };
+ B5012E682C96255A00AC4D68 /* MapBlockers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapBlockers.swift; sourceTree = "<group>"; };
+ B5012E692C96255A00AC4D68 /* MapOpportunities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapOpportunities.swift; sourceTree = "<group>"; };
+ B5012E792C96F02E00AC4D68 /* Dimensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Dimensions.swift; sourceTree = "<group>"; };
+ B5012E7B2C972B6600AC4D68 /* GroupParserStrategy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupParserStrategy.swift; sourceTree = "<group>"; };
+ B5012E802C97318300AC4D68 /* MapGroups.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapGroups.swift; sourceTree = "<group>"; };
+ B5012E862C97874400AC4D68 /* MapGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapGroup.swift; sourceTree = "<group>"; };
+ B5012E892C98235300AC4D68 /* MapCommands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapCommands.swift; sourceTree = "<group>"; };
+ B5012E8B2C98243E00AC4D68 /* ViewStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewStyle.swift; sourceTree = "<group>"; };
+ B5012E8D2C9828CE00AC4D68 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
+ B545870C2C961E9C0067B788 /* Map.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Map.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ B545870F2C961E9C0067B788 /* MapApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapApp.swift; sourceTree = "<group>"; };
+ B54587112C961E9C0067B788 /* MapDocument.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapDocument.swift; sourceTree = "<group>"; };
+ B54587132C961E9C0067B788 /* MapEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapEditor.swift; sourceTree = "<group>"; };
+ B54587152C961E9E0067B788 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+ B54587182C961E9E0067B788 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
+ B545871A2C961E9E0067B788 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ B545871B2C961E9E0067B788 /* Map.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Map.entitlements; sourceTree = "<group>"; };
+ B54587202C961E9E0067B788 /* MapTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MapTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ B54587242C961E9E0067B788 /* MapTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapTests.swift; sourceTree = "<group>"; };
+ B545872A2C961E9E0067B788 /* Map2UITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Map2UITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ B545872E2C961E9E0067B788 /* MapUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapUITests.swift; sourceTree = "<group>"; };
+ B54587302C961E9E0067B788 /* MapUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapUITestsLaunchTests.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
- B526256B25C874F9003E73B7 /* Frameworks */ = {
+ B54587092C961E9C0067B788 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- B523C74625C9BD3500C44061 /* CloudKit.framework in Frameworks */,
- B5F8D30E2A06E5C2000EEA24 /* Patterns in Frameworks */,
+ B5012E742C9625E200AC4D68 /* Patterns in Frameworks */,
+ B5012E7F2C97315800AC4D68 /* ConcaveHull in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
- B526258225C874FA003E73B7 /* Frameworks */ = {
+ B545871D2C961E9E0067B788 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
- B526258D25C874FA003E73B7 /* Frameworks */ = {
+ B54587272C961E9E0067B788 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
- B523C74425C9BD3500C44061 /* Frameworks */ = {
+ B5012E3C2C96222E00AC4D68 /* Data */ = {
isa = PBXGroup;
children = (
- B523C74525C9BD3500C44061 /* CloudKit.framework */,
+ B5012E412C96235B00AC4D68 /* Stage.swift */,
+ B54587112C961E9C0067B788 /* MapDocument.swift */,
);
- name = Frameworks;
- sourceTree = "<group>";
- };
- B523C75825C9FD3A00C44061 /* MapRender */ = {
- isa = PBXGroup;
- children = (
- B523C75925C9FD4900C44061 /* MapAxes.swift */,
- B523C76125CA05A300C44061 /* MapStages.swift */,
- B523C76625CA071B00C44061 /* MapVertices.swift */,
- B5F8D3132A07C05F000EEA24 /* MapNotes.swift */,
- B523C76B25CA0DFA00C44061 /* MapEdges.swift */,
- B523C77025CA121300C44061 /* MapBlockers.swift */,
- B523C77D25CA294C00C44061 /* MapOpportunities.swift */,
- );
- path = MapRender;
- sourceTree = "<group>";
- };
- B526256525C874F9003E73B7 = {
- isa = PBXGroup;
- children = (
- B526257025C874F9003E73B7 /* Map */,
- B526258825C874FA003E73B7 /* MapTests */,
- B526259325C874FA003E73B7 /* MapUITests */,
- B526256F25C874F9003E73B7 /* Products */,
- B523C74425C9BD3500C44061 /* Frameworks */,
- );
- sourceTree = "<group>";
- };
- B526256F25C874F9003E73B7 /* Products */ = {
- isa = PBXGroup;
- children = (
- B526256E25C874F9003E73B7 /* Map.app */,
- B526258525C874FA003E73B7 /* MapTests.xctest */,
- B526259025C874FA003E73B7 /* MapUITests.xctest */,
- );
- name = Products;
+ path = Data;
sourceTree = "<group>";
};
- B526257025C874F9003E73B7 /* Map */ = {
+ B5012E3D2C96223800AC4D68 /* Presentation */ = {
isa = PBXGroup;
children = (
- B526257125C874F9003E73B7 /* MapApp.swift */,
- B5F8D2FE2A06DB3A000EEA24 /* Data */,
- B5F8D3092A06DE1A000EEA24 /* Logic */,
- B5F8D2FF2A06DB40000EEA24 /* Presentation */,
- B52625B425C87D54003E73B7 /* Core Extensions */,
- B526257525C874FA003E73B7 /* Assets.xcassets */,
- B526257F25C874FA003E73B7 /* Info.plist */,
- B526258025C874FA003E73B7 /* Map.entitlements */,
- B526257C25C874FA003E73B7 /* Map.xcdatamodeld */,
- B526257725C874FA003E73B7 /* Preview Content */,
+ B5012E8B2C98243E00AC4D68 /* ViewStyle.swift */,
+ B5012E882C98234F00AC4D68 /* Commands */,
+ B5012E612C96254700AC4D68 /* Complex Components */,
+ B5012E432C9623BC00AC4D68 /* Theme */,
+ B5012E402C96232E00AC4D68 /* Base Components */,
+ B54587132C961E9C0067B788 /* MapEditor.swift */,
);
- path = Map;
+ path = Presentation;
sourceTree = "<group>";
};
- B526257725C874FA003E73B7 /* Preview Content */ = {
+ B5012E402C96232E00AC4D68 /* Base Components */ = {
isa = PBXGroup;
children = (
- B526257825C874FA003E73B7 /* Preview Assets.xcassets */,
+ B5012E6A2C96255A00AC4D68 /* MapRender */,
+ B5012E462C96243500AC4D68 /* MapTextEditor.swift */,
+ B5012E3E2C96232300AC4D68 /* EvolutionPicker.swift */,
);
- path = "Preview Content";
+ path = "Base Components";
sourceTree = "<group>";
};
- B526258825C874FA003E73B7 /* MapTests */ = {
+ B5012E432C9623BC00AC4D68 /* Theme */ = {
isa = PBXGroup;
children = (
- B526258925C874FA003E73B7 /* MapTests.swift */,
- B526258B25C874FA003E73B7 /* Info.plist */,
+ B5012E792C96F02E00AC4D68 /* Dimensions.swift */,
+ B5012E4A2C96246D00AC4D68 /* NSColor+theme.swift */,
+ B5012E482C96245800AC4D68 /* Color+theme.swift */,
+ B5012E442C9623C500AC4D68 /* Font+theme.swift */,
);
- path = MapTests;
+ path = Theme;
sourceTree = "<group>";
};
- B526259325C874FA003E73B7 /* MapUITests */ = {
+ B5012E522C96249400AC4D68 /* Strategies */ = {
isa = PBXGroup;
children = (
- B526259425C874FA003E73B7 /* MapUITests.swift */,
- B526259625C874FA003E73B7 /* Info.plist */,
+ B5012E7B2C972B6600AC4D68 /* GroupParserStrategy.swift */,
+ B5012E4C2C96249400AC4D68 /* VertexParserStrategy.swift */,
+ B5012E4D2C96249400AC4D68 /* NoteParserStrategy.swift */,
+ B5012E4E2C96249400AC4D68 /* EdgeParserStrategy.swift */,
+ B5012E4F2C96249400AC4D68 /* BlockerParserStrategy.swift */,
+ B5012E502C96249400AC4D68 /* OpportunityParserStrategy.swift */,
+ B5012E512C96249400AC4D68 /* StageParserStrategy.swift */,
);
- path = MapUITests;
+ path = Strategies;
sourceTree = "<group>";
};
- B52625B425C87D54003E73B7 /* Core Extensions */ = {
+ B5012E542C96249400AC4D68 /* MapParser */ = {
isa = PBXGroup;
children = (
- B52625AA25C87909003E73B7 /* Date+format.swift */,
- B523C73C25C98D9800C44061 /* NSImage+writePNG.swift */,
- B5F8D3072A06DD8C000EEA24 /* Font+Theme.swift */,
- B5F8D30F2A07B33D000EEA24 /* NSColor+Theme.swift */,
- B5F8D30A2A06E3E6000EEA24 /* Color+Theme.swift */,
+ B5012E522C96249400AC4D68 /* Strategies */,
+ B5012E532C96249400AC4D68 /* MapParser.swift */,
);
- path = "Core Extensions";
+ path = MapParser;
sourceTree = "<group>";
};
- B5CF75CD25CC7953003BFF3D /* MapParser */ = {
+ B5012E562C96249400AC4D68 /* Logic */ = {
isa = PBXGroup;
children = (
- B5CF75D625CC79A4003BFF3D /* Strategies */,
- B5CF75CE25CC7965003BFF3D /* MapParser.swift */,
+ B5012E8D2C9828CE00AC4D68 /* Constants.swift */,
+ B5012E542C96249400AC4D68 /* MapParser */,
+ B5012E552C96249400AC4D68 /* Debouncer.swift */,
);
- path = MapParser;
+ path = Logic;
sourceTree = "<group>";
};
- B5CF75D625CC79A4003BFF3D /* Strategies */ = {
+ B5012E602C96254700AC4D68 /* MapRender */ = {
isa = PBXGroup;
children = (
- B5CF75D725CC79BC003BFF3D /* VertexParserStrategy.swift */,
- B5F8D3112A07B690000EEA24 /* NoteParserStrategy.swift */,
- B5CF75DC25CC79D7003BFF3D /* EdgeParserStrategy.swift */,
- B5CF75E125CC79ED003BFF3D /* BlockerParserStrategy.swift */,
- B5CF75E925CC7A13003BFF3D /* OpportunityParserStrategy.swift */,
- B5CF75EE25CC7A4A003BFF3D /* StageParserStrategy.swift */,
+ B5012E5F2C96254700AC4D68 /* MapRenderView.swift */,
);
- path = Strategies;
+ path = MapRender;
sourceTree = "<group>";
};
- B5F8D2FE2A06DB3A000EEA24 /* Data */ = {
+ B5012E612C96254700AC4D68 /* Complex Components */ = {
isa = PBXGroup;
children = (
- B5F8D3012A06DB75000EEA24 /* Models */,
- B52625C525C8BD2A003E73B7 /* Stage.swift */,
- B526257A25C874FA003E73B7 /* Persistence.swift */,
- B539516B25CB0C9200959F72 /* Store.swift */,
- B539517325CB0CA400959F72 /* AppState.swift */,
+ B5012E602C96254700AC4D68 /* MapRender */,
);
- path = Data;
+ path = "Complex Components";
sourceTree = "<group>";
};
- B5F8D2FF2A06DB40000EEA24 /* Presentation */ = {
+ B5012E6A2C96255A00AC4D68 /* MapRender */ = {
isa = PBXGroup;
children = (
- B5F8D3022A06DBC3000EEA24 /* Windows */,
- B5F8D3032A06DC2D000EEA24 /* Screens */,
- B5F8D3052A06DCF3000EEA24 /* Complex Components */,
- B5F8D3042A06DCC4000EEA24 /* Base Components */,
+ B5012E802C97318300AC4D68 /* MapGroups.swift */,
+ B5012E862C97874400AC4D68 /* MapGroup.swift */,
+ B5012E632C96255A00AC4D68 /* MapAxes.swift */,
+ B5012E642C96255A00AC4D68 /* MapStages.swift */,
+ B5012E652C96255A00AC4D68 /* MapVertices.swift */,
+ B5012E662C96255A00AC4D68 /* MapNotes.swift */,
+ B5012E672C96255A00AC4D68 /* MapEdges.swift */,
+ B5012E682C96255A00AC4D68 /* MapBlockers.swift */,
+ B5012E692C96255A00AC4D68 /* MapOpportunities.swift */,
);
- path = Presentation;
+ path = MapRender;
sourceTree = "<group>";
};
- B5F8D3012A06DB75000EEA24 /* Models */ = {
+ B5012E882C98234F00AC4D68 /* Commands */ = {
isa = PBXGroup;
children = (
- B52625BA25C884C2003E73B7 /* Map+parse.swift */,
+ B5012E892C98235300AC4D68 /* MapCommands.swift */,
);
- path = Models;
+ path = Commands;
sourceTree = "<group>";
};
- B5F8D3022A06DBC3000EEA24 /* Windows */ = {
+ B54587032C961E9C0067B788 = {
isa = PBXGroup;
children = (
- B526257325C874F9003E73B7 /* MapEditorWindow.swift */,
+ B545870E2C961E9C0067B788 /* Map */,
+ B54587232C961E9E0067B788 /* MapTests */,
+ B545872D2C961E9E0067B788 /* MapUITests */,
+ B545870D2C961E9C0067B788 /* Products */,
);
- path = Windows;
sourceTree = "<group>";
};
- B5F8D3032A06DC2D000EEA24 /* Screens */ = {
+ B545870D2C961E9C0067B788 /* Products */ = {
isa = PBXGroup;
children = (
- B523C74A25C9C1BA00C44061 /* EmptyMapDetailScreen.swift */,
- B52625A525C876C3003E73B7 /* MapDetailScreen.swift */,
+ B545870C2C961E9C0067B788 /* Map.app */,
+ B54587202C961E9E0067B788 /* MapTests.xctest */,
+ B545872A2C961E9E0067B788 /* Map2UITests.xctest */,
);
- path = Screens;
+ name = Products;
sourceTree = "<group>";
};
- B5F8D3042A06DCC4000EEA24 /* Base Components */ = {
+ B545870E2C961E9C0067B788 /* Map */ = {
isa = PBXGroup;
children = (
- B5CF75C825CC19FC003BFF3D /* EvolutionPicker.swift */,
- B539518025CB2D7A00959F72 /* MapTextEditor.swift */,
- B523C75825C9FD3A00C44061 /* MapRender */,
+ B5012E562C96249400AC4D68 /* Logic */,
+ B5012E3C2C96222E00AC4D68 /* Data */,
+ B5012E3D2C96223800AC4D68 /* Presentation */,
+ B545870F2C961E9C0067B788 /* MapApp.swift */,
+ B54587152C961E9E0067B788 /* Assets.xcassets */,
+ B545871A2C961E9E0067B788 /* Info.plist */,
+ B545871B2C961E9E0067B788 /* Map.entitlements */,
+ B54587172C961E9E0067B788 /* Preview Content */,
);
- path = "Base Components";
+ path = Map;
sourceTree = "<group>";
};
- B5F8D3052A06DCF3000EEA24 /* Complex Components */ = {
+ B54587172C961E9E0067B788 /* Preview Content */ = {
isa = PBXGroup;
children = (
- B5F8D3062A06DD2A000EEA24 /* MapRender */,
+ B54587182C961E9E0067B788 /* Preview Assets.xcassets */,
);
- path = "Complex Components";
+ path = "Preview Content";
sourceTree = "<group>";
};
- B5F8D3062A06DD2A000EEA24 /* MapRender */ = {
+ B54587232C961E9E0067B788 /* MapTests */ = {
isa = PBXGroup;
children = (
- B52625AF25C87C14003E73B7 /* MapRenderView.swift */,
+ B54587242C961E9E0067B788 /* MapTests.swift */,
);
- path = MapRender;
+ path = MapTests;
sourceTree = "<group>";
};
- B5F8D3092A06DE1A000EEA24 /* Logic */ = {
+ B545872D2C961E9E0067B788 /* MapUITests */ = {
isa = PBXGroup;
children = (
- B5CF75CD25CC7953003BFF3D /* MapParser */,
- B5CF75F625CC97CA003BFF3D /* Debouncer.swift */,
+ B545872E2C961E9E0067B788 /* MapUITests.swift */,
+ B54587302C961E9E0067B788 /* MapUITestsLaunchTests.swift */,
);
- path = Logic;
+ path = MapUITests;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
- B526256D25C874F9003E73B7 /* Map */ = {
+ B545870B2C961E9C0067B788 /* Map */ = {
isa = PBXNativeTarget;
- buildConfigurationList = B526259925C874FA003E73B7 /* Build configuration list for PBXNativeTarget "Map" */;
+ buildConfigurationList = B54587342C961E9E0067B788 /* Build configuration list for PBXNativeTarget "Map" */;
buildPhases = (
- B526256A25C874F9003E73B7 /* Sources */,
- B526256B25C874F9003E73B7 /* Frameworks */,
- B526256C25C874F9003E73B7 /* Resources */,
+ B54587082C961E9C0067B788 /* Sources */,
+ B54587092C961E9C0067B788 /* Frameworks */,
+ B545870A2C961E9C0067B788 /* Resources */,
);
buildRules = (
);
);
name = Map;
packageProductDependencies = (
- B5F8D30D2A06E5C2000EEA24 /* Patterns */,
+ B5012E732C9625E200AC4D68 /* Patterns */,
+ B5012E7E2C97315800AC4D68 /* ConcaveHull */,
);
- productName = Map;
- productReference = B526256E25C874F9003E73B7 /* Map.app */;
+ productName = Map2;
+ productReference = B545870C2C961E9C0067B788 /* Map.app */;
productType = "com.apple.product-type.application";
};
- B526258425C874FA003E73B7 /* MapTests */ = {
+ B545871F2C961E9E0067B788 /* MapTests */ = {
isa = PBXNativeTarget;
- buildConfigurationList = B526259C25C874FA003E73B7 /* Build configuration list for PBXNativeTarget "MapTests" */;
+ buildConfigurationList = B54587372C961E9E0067B788 /* Build configuration list for PBXNativeTarget "MapTests" */;
buildPhases = (
- B526258125C874FA003E73B7 /* Sources */,
- B526258225C874FA003E73B7 /* Frameworks */,
- B526258325C874FA003E73B7 /* Resources */,
+ B545871C2C961E9E0067B788 /* Sources */,
+ B545871D2C961E9E0067B788 /* Frameworks */,
+ B545871E2C961E9E0067B788 /* Resources */,
);
buildRules = (
);
dependencies = (
- B526258725C874FA003E73B7 /* PBXTargetDependency */,
+ B54587222C961E9E0067B788 /* PBXTargetDependency */,
);
name = MapTests;
- productName = MapTests;
- productReference = B526258525C874FA003E73B7 /* MapTests.xctest */;
+ productName = Map2Tests;
+ productReference = B54587202C961E9E0067B788 /* MapTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
- B526258F25C874FA003E73B7 /* MapUITests */ = {
+ B54587292C961E9E0067B788 /* Map2UITests */ = {
isa = PBXNativeTarget;
- buildConfigurationList = B526259F25C874FA003E73B7 /* Build configuration list for PBXNativeTarget "MapUITests" */;
+ buildConfigurationList = B545873A2C961E9E0067B788 /* Build configuration list for PBXNativeTarget "Map2UITests" */;
buildPhases = (
- B526258C25C874FA003E73B7 /* Sources */,
- B526258D25C874FA003E73B7 /* Frameworks */,
- B526258E25C874FA003E73B7 /* Resources */,
+ B54587262C961E9E0067B788 /* Sources */,
+ B54587272C961E9E0067B788 /* Frameworks */,
+ B54587282C961E9E0067B788 /* Resources */,
);
buildRules = (
);
dependencies = (
- B526259225C874FA003E73B7 /* PBXTargetDependency */,
+ B545872C2C961E9E0067B788 /* PBXTargetDependency */,
);
- name = MapUITests;
- productName = MapUITests;
- productReference = B526259025C874FA003E73B7 /* MapUITests.xctest */;
+ name = Map2UITests;
+ productName = Map2UITests;
+ productReference = B545872A2C961E9E0067B788 /* Map2UITests.xctest */;
productType = "com.apple.product-type.bundle.ui-testing";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
- B526256625C874F9003E73B7 /* Project object */ = {
+ B54587042C961E9C0067B788 /* Project object */ = {
isa = PBXProject;
attributes = {
- BuildIndependentTargetsInParallel = YES;
- LastSwiftUpdateCheck = 1240;
- LastUpgradeCheck = 1430;
+ BuildIndependentTargetsInParallel = 1;
+ LastSwiftUpdateCheck = 1600;
+ LastUpgradeCheck = 1600;
TargetAttributes = {
- B526256D25C874F9003E73B7 = {
- CreatedOnToolsVersion = 12.4;
+ B545870B2C961E9C0067B788 = {
+ CreatedOnToolsVersion = 16.0;
};
- B526258425C874FA003E73B7 = {
- CreatedOnToolsVersion = 12.4;
- TestTargetID = B526256D25C874F9003E73B7;
+ B545871F2C961E9E0067B788 = {
+ CreatedOnToolsVersion = 16.0;
+ TestTargetID = B545870B2C961E9C0067B788;
};
- B526258F25C874FA003E73B7 = {
- CreatedOnToolsVersion = 12.4;
- TestTargetID = B526256D25C874F9003E73B7;
+ B54587292C961E9E0067B788 = {
+ CreatedOnToolsVersion = 16.0;
+ TestTargetID = B545870B2C961E9C0067B788;
};
};
};
- buildConfigurationList = B526256925C874F9003E73B7 /* Build configuration list for PBXProject "Map" */;
- compatibilityVersion = "Xcode 9.3";
+ buildConfigurationList = B54587072C961E9C0067B788 /* Build configuration list for PBXProject "Map" */;
+ compatibilityVersion = "Xcode 15.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
- mainGroup = B526256525C874F9003E73B7;
+ mainGroup = B54587032C961E9C0067B788;
packageReferences = (
- B5F8D30C2A06E5C2000EEA24 /* XCRemoteSwiftPackageReference "patterns" */,
+ B5012E722C9625E200AC4D68 /* XCRemoteSwiftPackageReference "patterns" */,
+ B5012E7D2C97315800AC4D68 /* XCRemoteSwiftPackageReference "ConcaveHull" */,
);
- productRefGroup = B526256F25C874F9003E73B7 /* Products */;
+ productRefGroup = B545870D2C961E9C0067B788 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
- B526256D25C874F9003E73B7 /* Map */,
- B526258425C874FA003E73B7 /* MapTests */,
- B526258F25C874FA003E73B7 /* MapUITests */,
+ B545870B2C961E9C0067B788 /* Map */,
+ B545871F2C961E9E0067B788 /* MapTests */,
+ B54587292C961E9E0067B788 /* Map2UITests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
- B526256C25C874F9003E73B7 /* Resources */ = {
+ B545870A2C961E9C0067B788 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- B526257925C874FA003E73B7 /* Preview Assets.xcassets in Resources */,
- B526257625C874FA003E73B7 /* Assets.xcassets in Resources */,
+ B54587192C961E9E0067B788 /* Preview Assets.xcassets in Resources */,
+ B54587162C961E9E0067B788 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
- B526258325C874FA003E73B7 /* Resources */ = {
+ B545871E2C961E9E0067B788 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
- B526258E25C874FA003E73B7 /* Resources */ = {
+ B54587282C961E9E0067B788 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
- B526256A25C874F9003E73B7 /* Sources */ = {
+ B54587082C961E9C0067B788 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- B52625B025C87C14003E73B7 /* MapRenderView.swift in Sources */,
- B523C77E25CA294C00C44061 /* MapOpportunities.swift in Sources */,
- B52625AB25C87909003E73B7 /* Date+format.swift in Sources */,
- B5CF75D825CC79BC003BFF3D /* VertexParserStrategy.swift in Sources */,
- B5CF75EA25CC7A13003BFF3D /* OpportunityParserStrategy.swift in Sources */,
- B5F8D3142A07C05F000EEA24 /* MapNotes.swift in Sources */,
- B523C77125CA121300C44061 /* MapBlockers.swift in Sources */,
- B523C76725CA071B00C44061 /* MapVertices.swift in Sources */,
- B5CF75CF25CC7965003BFF3D /* MapParser.swift in Sources */,
- B5CF75E225CC79ED003BFF3D /* BlockerParserStrategy.swift in Sources */,
- B5F8D3102A07B33D000EEA24 /* NSColor+Theme.swift in Sources */,
- B5F8D30B2A06E3E6000EEA24 /* Color+Theme.swift in Sources */,
- B539517425CB0CA400959F72 /* AppState.swift in Sources */,
- B523C75A25C9FD4900C44061 /* MapAxes.swift in Sources */,
- B539518125CB2D7A00959F72 /* MapTextEditor.swift in Sources */,
- B52625BB25C884C2003E73B7 /* Map+parse.swift in Sources */,
- B52625C625C8BD2A003E73B7 /* Stage.swift in Sources */,
- B523C73D25C98D9800C44061 /* NSImage+writePNG.swift in Sources */,
- B5F8D3122A07B690000EEA24 /* NoteParserStrategy.swift in Sources */,
- B526257B25C874FA003E73B7 /* Persistence.swift in Sources */,
- B5F8D3082A06DD8C000EEA24 /* Font+Theme.swift in Sources */,
- B5CF75EF25CC7A4A003BFF3D /* StageParserStrategy.swift in Sources */,
- B5CF75DD25CC79D7003BFF3D /* EdgeParserStrategy.swift in Sources */,
- B526257425C874F9003E73B7 /* MapEditorWindow.swift in Sources */,
- B526257E25C874FA003E73B7 /* Map.xcdatamodeld in Sources */,
- B5CF75C925CC19FC003BFF3D /* EvolutionPicker.swift in Sources */,
- B523C74B25C9C1BA00C44061 /* EmptyMapDetailScreen.swift in Sources */,
- B539516C25CB0C9300959F72 /* Store.swift in Sources */,
- B526257225C874F9003E73B7 /* MapApp.swift in Sources */,
- B52625A625C876C3003E73B7 /* MapDetailScreen.swift in Sources */,
- B523C76225CA05A300C44061 /* MapStages.swift in Sources */,
- B5CF75F725CC97CA003BFF3D /* Debouncer.swift in Sources */,
- B523C76C25CA0DFA00C44061 /* MapEdges.swift in Sources */,
+ B5012E872C97874600AC4D68 /* MapGroup.swift in Sources */,
+ B5012E472C96243C00AC4D68 /* MapTextEditor.swift in Sources */,
+ B5012E622C96254700AC4D68 /* MapRenderView.swift in Sources */,
+ B5012E492C96245B00AC4D68 /* Color+theme.swift in Sources */,
+ B54587122C961E9C0067B788 /* MapDocument.swift in Sources */,
+ B54587102C961E9C0067B788 /* MapApp.swift in Sources */,
+ B5012E8C2C98244000AC4D68 /* ViewStyle.swift in Sources */,
+ B5012E8E2C9828D000AC4D68 /* Constants.swift in Sources */,
+ B5012E7C2C972B6C00AC4D68 /* GroupParserStrategy.swift in Sources */,
+ B5012E6B2C96255A00AC4D68 /* MapAxes.swift in Sources */,
+ B5012E6C2C96255A00AC4D68 /* MapVertices.swift in Sources */,
+ B5012E6D2C96255A00AC4D68 /* MapStages.swift in Sources */,
+ B5012E7A2C96F02F00AC4D68 /* Dimensions.swift in Sources */,
+ B5012E6E2C96255A00AC4D68 /* MapNotes.swift in Sources */,
+ B5012E6F2C96255A00AC4D68 /* MapEdges.swift in Sources */,
+ B5012E702C96255A00AC4D68 /* MapOpportunities.swift in Sources */,
+ B5012E712C96255A00AC4D68 /* MapBlockers.swift in Sources */,
+ B5012E4B2C96246F00AC4D68 /* NSColor+theme.swift in Sources */,
+ B54587142C961E9C0067B788 /* MapEditor.swift in Sources */,
+ B5012E3F2C96232A00AC4D68 /* EvolutionPicker.swift in Sources */,
+ B5012E572C96249400AC4D68 /* NoteParserStrategy.swift in Sources */,
+ B5012E582C96249400AC4D68 /* BlockerParserStrategy.swift in Sources */,
+ B5012E592C96249400AC4D68 /* VertexParserStrategy.swift in Sources */,
+ B5012E5A2C96249400AC4D68 /* MapParser.swift in Sources */,
+ B5012E5B2C96249400AC4D68 /* OpportunityParserStrategy.swift in Sources */,
+ B5012E5C2C96249400AC4D68 /* EdgeParserStrategy.swift in Sources */,
+ B5012E5D2C96249400AC4D68 /* StageParserStrategy.swift in Sources */,
+ B5012E812C97318600AC4D68 /* MapGroups.swift in Sources */,
+ B5012E8A2C98235500AC4D68 /* MapCommands.swift in Sources */,
+ B5012E5E2C96249400AC4D68 /* Debouncer.swift in Sources */,
+ B5012E452C9623C700AC4D68 /* Font+theme.swift in Sources */,
+ B5012E422C96235E00AC4D68 /* Stage.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
- B526258125C874FA003E73B7 /* Sources */ = {
+ B545871C2C961E9E0067B788 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- B526258A25C874FA003E73B7 /* MapTests.swift in Sources */,
+ B54587252C961E9E0067B788 /* MapTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
- B526258C25C874FA003E73B7 /* Sources */ = {
+ B54587262C961E9E0067B788 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- B526259525C874FA003E73B7 /* MapUITests.swift in Sources */,
+ B54587312C961E9E0067B788 /* MapUITestsLaunchTests.swift in Sources */,
+ B545872F2C961E9E0067B788 /* MapUITests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
- B526258725C874FA003E73B7 /* PBXTargetDependency */ = {
+ B54587222C961E9E0067B788 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
- target = B526256D25C874F9003E73B7 /* Map */;
- targetProxy = B526258625C874FA003E73B7 /* PBXContainerItemProxy */;
+ target = B545870B2C961E9C0067B788 /* Map */;
+ targetProxy = B54587212C961E9E0067B788 /* PBXContainerItemProxy */;
};
- B526259225C874FA003E73B7 /* PBXTargetDependency */ = {
+ B545872C2C961E9E0067B788 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
- target = B526256D25C874F9003E73B7 /* Map */;
- targetProxy = B526259125C874FA003E73B7 /* PBXContainerItemProxy */;
+ target = B545870B2C961E9C0067B788 /* Map */;
+ targetProxy = B545872B2C961E9E0067B788 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
- B526259725C874FA003E73B7 /* Debug */ = {
+ B54587322C961E9E0067B788 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
- CLANG_CXX_LIBRARY = "libc++";
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
- DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
- GCC_C_LANGUAGE_STANDARD = gnu11;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- MACOSX_DEPLOYMENT_TARGET = 11.1;
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MACOSX_DEPLOYMENT_TARGET = 15.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
- SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
- B526259825C874FA003E73B7 /* Release */ = {
+ B54587332C961E9E0067B788 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
- CLANG_CXX_LIBRARY = "libc++";
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
- DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
- GCC_C_LANGUAGE_STANDARD = gnu11;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- MACOSX_DEPLOYMENT_TARGET = 11.1;
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MACOSX_DEPLOYMENT_TARGET = 15.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
- SWIFT_OPTIMIZATION_LEVEL = "-O";
};
name = Release;
};
- B526259A25C874FA003E73B7 /* Debug */ = {
+ B54587352C961E9E0067B788 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = Map/Map.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
- CURRENT_PROJECT_VERSION = 4;
- DEAD_CODE_STRIPPING = YES;
+ CURRENT_PROJECT_VERSION = 3;
DEVELOPMENT_ASSET_PATHS = "\"Map/Preview Content\"";
DEVELOPMENT_TEAM = S68NHQVJXW;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
+ GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = Map/Info.plist;
+ INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity";
+ INFOPLIST_KEY_NSHumanReadableCopyright = "";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
- MACOSX_DEPLOYMENT_TARGET = 12.0;
- MARKETING_VERSION = 2.0.0;
- PRODUCT_BUNDLE_IDENTIFIER = pizza.unlimited.Map;
+ MACOSX_DEPLOYMENT_TARGET = 14.0;
+ MARKETING_VERSION = 3.0.0;
+ PRODUCT_BUNDLE_IDENTIFIER = systems.tranquil.Map;
PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
};
name = Debug;
};
- B526259B25C874FA003E73B7 /* Release */ = {
+ B54587362C961E9E0067B788 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = Map/Map.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
- CURRENT_PROJECT_VERSION = 4;
- DEAD_CODE_STRIPPING = YES;
+ CURRENT_PROJECT_VERSION = 3;
DEVELOPMENT_ASSET_PATHS = "\"Map/Preview Content\"";
DEVELOPMENT_TEAM = S68NHQVJXW;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
+ GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = Map/Info.plist;
+ INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity";
+ INFOPLIST_KEY_NSHumanReadableCopyright = "";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
- MACOSX_DEPLOYMENT_TARGET = 12.0;
- MARKETING_VERSION = 2.0.0;
- PRODUCT_BUNDLE_IDENTIFIER = pizza.unlimited.Map;
+ MACOSX_DEPLOYMENT_TARGET = 14.0;
+ MARKETING_VERSION = 3.0.0;
+ PRODUCT_BUNDLE_IDENTIFIER = systems.tranquil.Map;
PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
};
name = Release;
};
- B526259D25C874FA003E73B7 /* Debug */ = {
+ B54587382C961E9E0067B788 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
- COMBINE_HIDPI_IMAGES = YES;
- DEAD_CODE_STRIPPING = YES;
+ CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = S68NHQVJXW;
- INFOPLIST_FILE = MapTests/Info.plist;
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/../Frameworks",
- "@loader_path/../Frameworks",
- );
- MACOSX_DEPLOYMENT_TARGET = 11.0;
- PRODUCT_BUNDLE_IDENTIFIER = pizza.unlimited.MapTests;
+ GENERATE_INFOPLIST_FILE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 15.0;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = systems.tranquil.Map2Tests;
PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_EMIT_LOC_STRINGS = NO;
SWIFT_VERSION = 5.0;
- TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Map.app/Contents/MacOS/Map";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Map2.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Map2";
};
name = Debug;
};
- B526259E25C874FA003E73B7 /* Release */ = {
+ B54587392C961E9E0067B788 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
- COMBINE_HIDPI_IMAGES = YES;
- DEAD_CODE_STRIPPING = YES;
+ CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = S68NHQVJXW;
- INFOPLIST_FILE = MapTests/Info.plist;
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/../Frameworks",
- "@loader_path/../Frameworks",
- );
- MACOSX_DEPLOYMENT_TARGET = 11.0;
- PRODUCT_BUNDLE_IDENTIFIER = pizza.unlimited.MapTests;
+ GENERATE_INFOPLIST_FILE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 15.0;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = systems.tranquil.Map2Tests;
PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_EMIT_LOC_STRINGS = NO;
SWIFT_VERSION = 5.0;
- TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Map.app/Contents/MacOS/Map";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Map2.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Map2";
};
name = Release;
};
- B52625A025C874FA003E73B7 /* Debug */ = {
+ B545873B2C961E9E0067B788 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
- COMBINE_HIDPI_IMAGES = YES;
- DEAD_CODE_STRIPPING = YES;
+ CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = S68NHQVJXW;
- INFOPLIST_FILE = MapUITests/Info.plist;
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/../Frameworks",
- "@loader_path/../Frameworks",
- );
- PRODUCT_BUNDLE_IDENTIFIER = pizza.unlimited.MapUITests;
+ GENERATE_INFOPLIST_FILE = YES;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = systems.tranquil.Map2UITests;
PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_EMIT_LOC_STRINGS = NO;
SWIFT_VERSION = 5.0;
- TEST_TARGET_NAME = Map;
+ TEST_TARGET_NAME = Map2;
};
name = Debug;
};
- B52625A125C874FA003E73B7 /* Release */ = {
+ B545873C2C961E9E0067B788 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
- COMBINE_HIDPI_IMAGES = YES;
- DEAD_CODE_STRIPPING = YES;
+ CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = S68NHQVJXW;
- INFOPLIST_FILE = MapUITests/Info.plist;
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/../Frameworks",
- "@loader_path/../Frameworks",
- );
- PRODUCT_BUNDLE_IDENTIFIER = pizza.unlimited.MapUITests;
+ GENERATE_INFOPLIST_FILE = YES;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = systems.tranquil.Map2UITests;
PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_EMIT_LOC_STRINGS = NO;
SWIFT_VERSION = 5.0;
- TEST_TARGET_NAME = Map;
+ TEST_TARGET_NAME = Map2;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
- B526256925C874F9003E73B7 /* Build configuration list for PBXProject "Map" */ = {
+ B54587072C961E9C0067B788 /* Build configuration list for PBXProject "Map" */ = {
isa = XCConfigurationList;
buildConfigurations = (
- B526259725C874FA003E73B7 /* Debug */,
- B526259825C874FA003E73B7 /* Release */,
+ B54587322C961E9E0067B788 /* Debug */,
+ B54587332C961E9E0067B788 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- B526259925C874FA003E73B7 /* Build configuration list for PBXNativeTarget "Map" */ = {
+ B54587342C961E9E0067B788 /* Build configuration list for PBXNativeTarget "Map" */ = {
isa = XCConfigurationList;
buildConfigurations = (
- B526259A25C874FA003E73B7 /* Debug */,
- B526259B25C874FA003E73B7 /* Release */,
+ B54587352C961E9E0067B788 /* Debug */,
+ B54587362C961E9E0067B788 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- B526259C25C874FA003E73B7 /* Build configuration list for PBXNativeTarget "MapTests" */ = {
+ B54587372C961E9E0067B788 /* Build configuration list for PBXNativeTarget "MapTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
- B526259D25C874FA003E73B7 /* Debug */,
- B526259E25C874FA003E73B7 /* Release */,
+ B54587382C961E9E0067B788 /* Debug */,
+ B54587392C961E9E0067B788 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- B526259F25C874FA003E73B7 /* Build configuration list for PBXNativeTarget "MapUITests" */ = {
+ B545873A2C961E9E0067B788 /* Build configuration list for PBXNativeTarget "Map2UITests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
- B52625A025C874FA003E73B7 /* Debug */,
- B52625A125C874FA003E73B7 /* Release */,
+ B545873B2C961E9E0067B788 /* Debug */,
+ B545873C2C961E9E0067B788 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
/* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */
- B5F8D30C2A06E5C2000EEA24 /* XCRemoteSwiftPackageReference "patterns" */ = {
+ B5012E722C9625E200AC4D68 /* XCRemoteSwiftPackageReference "patterns" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://git.sr.ht/~rbdr/patterns";
requirement = {
minimumVersion = 2.0.0;
};
};
+ B5012E7D2C97315800AC4D68 /* XCRemoteSwiftPackageReference "ConcaveHull" */ = {
+ isa = XCRemoteSwiftPackageReference;
+ repositoryURL = "https://github.com/Syncheo/ConcaveHull";
+ requirement = {
+ branch = master;
+ kind = branch;
+ };
+ };
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
- B5F8D30D2A06E5C2000EEA24 /* Patterns */ = {
+ B5012E732C9625E200AC4D68 /* Patterns */ = {
isa = XCSwiftPackageProductDependency;
- package = B5F8D30C2A06E5C2000EEA24 /* XCRemoteSwiftPackageReference "patterns" */;
+ package = B5012E722C9625E200AC4D68 /* XCRemoteSwiftPackageReference "patterns" */;
productName = Patterns;
};
-/* End XCSwiftPackageProductDependency section */
-
-/* Begin XCVersionGroup section */
- B526257C25C874FA003E73B7 /* Map.xcdatamodeld */ = {
- isa = XCVersionGroup;
- children = (
- B526257D25C874FA003E73B7 /* Map.xcdatamodel */,
- );
- currentVersion = B526257D25C874FA003E73B7 /* Map.xcdatamodel */;
- path = Map.xcdatamodeld;
- sourceTree = "<group>";
- versionGroupType = wrapper.xcdatamodel;
+ B5012E7E2C97315800AC4D68 /* ConcaveHull */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = B5012E7D2C97315800AC4D68 /* XCRemoteSwiftPackageReference "ConcaveHull" */;
+ productName = ConcaveHull;
};
-/* End XCVersionGroup section */
+/* End XCSwiftPackageProductDependency section */
};
- rootObject = B526256625C874F9003E73B7 /* Project object */;
+ rootObject = B54587042C961E9C0067B788 /* Project object */;
}
{
+ "originHash" : "02d7b701c0ab6f32b55ad490056b5cb87cdec5003f477a828ca9a07b09a2d7b3",
"pins" : [
+ {
+ "identity" : "concavehull",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/Syncheo/ConcaveHull",
+ "state" : {
+ "branch" : "master",
+ "revision" : "2583fea7f4b2a34830e47b64fc076cd3fbd4038c"
+ }
+ },
{
"identity" : "patterns",
"kind" : "remoteSourceControl",
}
}
],
- "version" : 2
+ "version" : 3
}
--- /dev/null
+{
+ "colors" : [
+ {
+ "color" : {
+ "color-space" : "srgb",
+ "components" : {
+ "alpha" : "1.000",
+ "blue" : "0.488",
+ "green" : "0.500",
+ "red" : "0.434"
+ }
+ },
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
--- /dev/null
+{
+ "colors" : [
+ {
+ "color" : {
+ "color-space" : "srgb",
+ "components" : {
+ "alpha" : "1.000",
+ "blue" : "0xF0",
+ "green" : "0xB3",
+ "red" : "0xFF"
+ }
+ },
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
--- /dev/null
+{
+ "colors" : [
+ {
+ "color" : {
+ "color-space" : "srgb",
+ "components" : {
+ "alpha" : "1.000",
+ "blue" : "0x7C",
+ "green" : "0xC1",
+ "red" : "0x23"
+ }
+ },
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
--- /dev/null
+{
+ "colors" : [
+ {
+ "color" : {
+ "color-space" : "srgb",
+ "components" : {
+ "alpha" : "1.000",
+ "blue" : "0x8F",
+ "green" : "0xED",
+ "red" : "0xFA"
+ }
+ },
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
+++ /dev/null
-//
-// Date+format.swift
-// Map
-//
-// Created by Ruben Beltran del Rio on 2/1/21.
-//
-
-import Foundation
-
-extension Date {
- func format() -> String {
- let formatter = DateFormatter()
- formatter.dateStyle = .short
- formatter.timeStyle = .medium
- return formatter.string(from: self)
- }
-}
+++ /dev/null
-import SwiftUI
-
-public extension Font {
- struct theme {
- static let axisLabel = Font.custom("Hiragino Mincho ProN", size: 14)
- static let vertexLabel = Font.custom("Hiragino Mincho ProN", size: 12)
- }
-}
+++ /dev/null
-import Cocoa
-
-extension NSImage {
- public func writePNG(toURL url: URL) {
-
- guard let data = tiffRepresentation,
- let rep = NSBitmapImageRep(data: data),
- let imgData = rep.representation(
- using: .png, properties: [.compressionFactor: NSNumber(floatLiteral: 1.0)])
- else {
-
- print(
- "\(self.self) Error Function '\(#function)' Line: \(#line) No tiff rep found for image writing to \(url)"
- )
- return
- }
-
- do {
- try imgData.write(to: url)
- } catch let error {
- print(
- "\(self.self) Error Function '\(#function)' Line: \(#line) \(error.localizedDescription)")
- }
- }
-}
+++ /dev/null
-import Cocoa
-import Foundation
-import SwiftUI
-
-struct AppState {
- var selectedEvolution: StageType = .general
-}
-
-enum AppAction {
- case selectEvolution(evolution: StageType)
- case exportMapAsImage(map: Map)
- case exportMapAsText(map: Map)
- case deleteMap(map: Map)
-}
-
-func appStateReducer(state: inout AppState, action: AppAction) {
-
- switch action {
-
- case .selectEvolution(let evolution):
- state.selectedEvolution = evolution
-
- case .exportMapAsImage(let map):
- let window = NSWindow(
- contentRect: .init(
- origin: .zero,
- size: .init(
- width: NSScreen.main!.frame.width,
- height: NSScreen.main!.frame.height)),
- styleMask: [.closable],
- backing: .buffered,
- defer: false)
-
- window.title = map.title ?? "Untitled Map"
- window.isOpaque = true
- window.center()
- window.isMovableByWindowBackground = true
- window.makeKeyAndOrderFront(nil)
-
- let renderView = MapRenderView(
- content: Binding.constant(map.content ?? ""),
- evolution: Binding.constant(state.selectedEvolution))
-
- let view = NSHostingView(rootView: renderView)
- window.contentView = view
-
- let imageRepresentation = view.bitmapImageRepForCachingDisplay(in: view.bounds)!
- view.cacheDisplay(in: view.bounds, to: imageRepresentation)
- let image = NSImage(cgImage: imageRepresentation.cgImage!, size: view.bounds.size)
-
- let dialog = NSSavePanel()
-
- dialog.title = "Save Map"
- dialog.showsResizeIndicator = false
- dialog.canCreateDirectories = true
- dialog.showsHiddenFiles = false
- dialog.allowedContentTypes = [.png]
- dialog.nameFieldStringValue = map.title ?? "Untitled Map"
-
- if dialog.runModal() == NSApplication.ModalResponse.OK {
- let result = dialog.url
-
- if result != nil {
-
- image.writePNG(toURL: result!)
- print("saved at \(result!)")
- }
- } else {
- print("Cancel")
- }
- window.orderOut(nil)
-
- case .exportMapAsText(let map):
- let dialog = NSSavePanel()
-
- dialog.title = "Save Map Text"
- dialog.showsResizeIndicator = false
- dialog.canCreateDirectories = true
- dialog.showsHiddenFiles = false
- dialog.allowedContentTypes = [.text]
- dialog.nameFieldStringValue = map.title ?? "Untitled Map"
-
- if let content = map.content {
-
- if dialog.runModal() == NSApplication.ModalResponse.OK {
- let result = dialog.url
-
- if let result = result {
- try? content.write(to: result, atomically: true, encoding: String.Encoding.utf8)
- }
- } else {
- print("Cancel")
- }
- }
- case .deleteMap(let map):
- let context = PersistenceController.shared.container.viewContext
- context.delete(map)
-
- try? context.save()
- }
-}
-
-typealias AppStore = Store<AppState, AppAction>
--- /dev/null
+import SwiftUI
+import UniformTypeIdentifiers
+
+extension UTType {
+ static var exampleText: UTType {
+ UTType(importedAs: "systems.tranquil.map.wmap")
+ }
+}
+
+struct MapDocument: FileDocument {
+ var text: String
+
+ init(text: String = "Hello, world!") {
+ self.text = text
+ }
+
+ static var readableContentTypes: [UTType] { [.exampleText] }
+
+ init(configuration: ReadConfiguration) throws {
+ guard let data = configuration.file.regularFileContents,
+ let string = String(data: data, encoding: .utf8)
+ else {
+ throw CocoaError(.fileReadCorruptFile)
+ }
+ text = string
+ }
+
+ func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
+ let data = text.data(using: .utf8)!
+ return .init(regularFileWithContents: data)
+ }
+
+ @MainActor
+ func exportAsImage(withEvolution selectedEvolution: StageType) -> NSImage? {
+ let renderView = MapRenderView(
+ document: .constant(self),
+ evolution: .constant(selectedEvolution))
+ let renderer = ImageRenderer(content: renderView)
+
+ return renderer.nsImage
+ }
+}
+++ /dev/null
-extension Map {
- static func parse(content: String) -> ParsedMap {
-
- let parsers = [
- AnyMapParserStrategy(NoteParserStrategy()),
- AnyMapParserStrategy(VertexParserStrategy()),
- AnyMapParserStrategy(EdgeParserStrategy()),
- AnyMapParserStrategy(BlockerParserStrategy()),
- AnyMapParserStrategy(OpportunityParserStrategy()),
- AnyMapParserStrategy(StageParserStrategy()),
- ]
- let builder = MapBuilder()
-
- let lines = content.split(whereSeparator: \.isNewline)
-
- for (index, line) in lines.enumerated() {
- for parser in parsers {
- if parser.canHandle(line: String(line)) {
- let (type, object) = parser.handle(
- index: index, line: String(line), vertices: builder.vertices)
- builder.addObjectToMap(type: type, object: object)
- break
- }
- }
- }
-
- return builder.build()
- }
-}
+++ /dev/null
-import CoreData
-
-struct PersistenceController {
- static let shared = PersistenceController()
-
- static var preview: PersistenceController = {
- let result = PersistenceController(inMemory: true)
- let viewContext = result.container.viewContext
- for _ in 0..<10 {
- let newMap = Map(context: viewContext)
- newMap.uuid = UUID()
- newMap.createdAt = Date()
- newMap.title = "Map \(newMap.createdAt!.format())"
- newMap.content = ""
- }
- do {
- try viewContext.save()
- } catch {
- let nsError = error as NSError
- fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
- }
- return result
- }()
-
- let container: NSPersistentCloudKitContainer
-
- init(inMemory: Bool = false) {
- container = NSPersistentCloudKitContainer(name: "Map")
-
- container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
- container.viewContext.automaticallyMergesChangesFromParent = true
-
- if inMemory {
- container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
- }
- container.loadPersistentStores(completionHandler: { (storeDescription, error) in
- if let error = error as NSError? {
- fatalError("Unresolved error \(error), \(error.userInfo)")
- }
- })
- }
-}
+++ /dev/null
-import Foundation
-
-final class Store<State, Action>: ObservableObject {
- @Published private(set) var state: State
-
- private let reducer: Reducer<State, Action>
-
- init(initialState: State, reducer: @escaping Reducer<State, Action>) {
- self.state = initialState
- self.reducer = reducer
- }
-
- func send(_ action: Action) {
- reducer(&state, action)
- }
-}
-
-typealias Reducer<State, Action> = (inout State, Action) -> Void
<!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>$(DEVELOPMENT_LANGUAGE)</string>
- <key>CFBundleExecutable</key>
- <string>$(EXECUTABLE_NAME)</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>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
- <key>CFBundleShortVersionString</key>
- <string>$(MARKETING_VERSION)</string>
- <key>CFBundleVersion</key>
- <string>$(CURRENT_PROJECT_VERSION)</string>
- <key>LSApplicationCategoryType</key>
- <string>public.app-category.productivity</string>
- <key>LSMinimumSystemVersion</key>
- <string>$(MACOSX_DEPLOYMENT_TARGET)</string>
+ <key>CFBundleDocumentTypes</key>
+ <array>
+ <dict>
+ <key>CFBundleTypeRole</key>
+ <string>Editor</string>
+ <key>LSHandlerRank</key>
+ <string>Default</string>
+ <key>LSItemContentTypes</key>
+ <array>
+ <string>systems.tranquil.map.wmap</string>
+ </array>
+ <key>NSUbiquitousDocumentUserActivityType</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER).exampledocument</string>
+ </dict>
+ </array>
+ <key>UTImportedTypeDeclarations</key>
+ <array>
+ <dict>
+ <key>UTTypeConformsTo</key>
+ <array>
+ <string>public.plain-text</string>
+ </array>
+ <key>UTTypeDescription</key>
+ <string>Wardley Map written in Map's wmap syntax</string>
+ <key>UTTypeIcons</key>
+ <dict/>
+ <key>UTTypeIdentifier</key>
+ <string>systems.tranquil.map.wmap</string>
+ <key>UTTypeTagSpecification</key>
+ <dict>
+ <key>public.filename-extension</key>
+ <array>
+ <string>wmap</string>
+ </array>
+ </dict>
+ </dict>
+ </array>
</dict>
</plist>
--- /dev/null
+struct Constants {
+ static let kMaxZoom = 2.0
+ static let kMinZoom = 0.1
+}
import CoreGraphics
import Foundation
+struct MapParser {
+ static func parse(content: String) -> ParsedMap {
+
+ let parsers = [
+ AnyMapParserStrategy(NoteParserStrategy()),
+ AnyMapParserStrategy(VertexParserStrategy()),
+ AnyMapParserStrategy(EdgeParserStrategy()),
+ AnyMapParserStrategy(BlockerParserStrategy()),
+ AnyMapParserStrategy(OpportunityParserStrategy()),
+ AnyMapParserStrategy(StageParserStrategy()),
+ AnyMapParserStrategy(GroupParserStrategy()),
+ ]
+ let builder = MapBuilder()
+
+ let lines = content.split(whereSeparator: \.isNewline)
+
+ for (index, line) in lines.enumerated() {
+ for parser in parsers {
+ if parser.canHandle(line: String(line)) {
+ let (type, object) = parser.handle(
+ index: index, line: String(line), vertices: builder.vertices)
+ builder.addObjectToMap(type: type, object: object)
+ break
+ }
+ }
+ }
+
+ return builder.build()
+ }
+}
+
// MARK: - Types
struct MapParsingPatterns {
static let vertex = try! NSRegularExpression(
pattern:
- "([^\\(\\[\\]]*?)[\\s]*\\([\\s]*([0-9]+.?[0-9]*)[\\s]*,[\\s]*([0-9]+.?[0-9]*)[\\s]*\\)[\\s]*(?:\\[(.*?)\\])?",
- options: .caseInsensitive)
+ "^([^\\(\\[\\]]*?)[\\s]*\\([\\s]*([0-9]+.?[0-9]*)[\\s]*,[\\s]*([0-9]+.?[0-9]*)[\\s]*\\)[\\s]*(?:\\[(.*?)\\])?[\\s]*$",
+ options: [.caseInsensitive, .anchorsMatchLines])
static let edge = try! NSRegularExpression(
- pattern: "(.+?)[\\s]*-([->])[\\s]*(.+)", options: .caseInsensitive)
+ pattern: "^(.+?)[\\s]*-([->])[\\s]*(.+)", options: [.caseInsensitive, .anchorsMatchLines])
static let blocker = try! NSRegularExpression(
- pattern: "\\[(Blocker)\\][\\s]*(.+)", options: .caseInsensitive)
+ pattern: "^\\[(Blocker)\\][\\s]*(.+)", options: [.caseInsensitive, .anchorsMatchLines])
static let opportunity = try! NSRegularExpression(
- pattern: "\\[(Evolution)\\][\\s]*(.+)[\\s]+([-+])[\\s]*([0-9]+.?[0-9]*)",
- options: .caseInsensitive)
+ pattern: "^\\[(Evolution)\\][\\s]*(.+)[\\s]+([-+])[\\s]*([0-9]+.?[0-9]*)",
+ options: [.caseInsensitive, .anchorsMatchLines])
static let note = try! NSRegularExpression(
- pattern: "\\[(Note)\\][\\s]*\\([\\s]*([0-9]+.?[0-9]*)[\\s]*,[\\s]*([0-9]+.?[0-9]*)[\\s]*\\)[\\s]*(.*)",
- options: .caseInsensitive)
+ pattern:
+ "^\\[(Note)\\][\\s]*\\([\\s]*([0-9]+.?[0-9]*)[\\s]*,[\\s]*([0-9]+.?[0-9]*)[\\s]*\\)[\\s]*(.*)",
+ options: [.caseInsensitive, .anchorsMatchLines])
static let stage = try! NSRegularExpression(
- pattern: "\\[(I{1,3})\\][\\s]*([0-9]+.?[0-9]*)", options: .caseInsensitive)
+ pattern: "^\\[(I{1,3})\\][\\s]*([0-9]+.?[0-9]*)",
+ options: [.caseInsensitive, .anchorsMatchLines])
+ static let group = try! NSRegularExpression(
+ pattern: "^\\[(Group)\\][\\s]*(.+)", options: [.caseInsensitive, .anchorsMatchLines])
}
struct ParsedMap {
let opportunities: [Opportunity]
let notes: [Note]
let stages: [CGFloat]
+ let groups: [[Vertex]]
static let empty: ParsedMap = ParsedMap(
- vertices: [], edges: [], blockers: [], opportunities: [], notes: [], stages: defaultDimensions)
+ vertices: [], edges: [], blockers: [], opportunities: [], notes: [], stages: defaultDimensions,
+ groups: [])
}
-struct Vertex {
+struct Vertex: Identifiable, Hashable {
let id: Int
let label: String
let position: CGPoint
private var opportunities: [Opportunity] = []
private var notes: [Note] = []
private var stages: [CGFloat] = defaultDimensions
+ private var groups: [[Vertex]] = []
func addObjectToMap(type: Any.Type, object: Any) {
if type == Vertex.self {
let opportunity = object as! Opportunity
opportunities.append(opportunity)
}
-
+
if type == Note.self {
let note = object as! Note
notes.append(note)
let stageDimensions = object as! StageDimensions
stages[stageDimensions.index] = stageDimensions.dimensions
}
+
+ if type == [Vertex].self {
+ let group = object as! [Vertex]
+ groups.append(group)
+ }
}
func build() -> ParsedMap {
let mappedVertices = vertices.map { label, vertex in return vertex }
return ParsedMap(
- vertices: mappedVertices, edges: edges, blockers: blockers, opportunities: opportunities, notes: notes,
- stages: stages)
+ vertices: mappedVertices, edges: edges, blockers: blockers, opportunities: opportunities,
+ notes: notes,
+ stages: stages, groups: groups)
}
}
--- /dev/null
+import Foundation
+
+struct GroupParserStrategy: MapParserStrategy {
+ private let regex = MapParsingPatterns.group
+
+ func canHandle(line: String) -> Bool {
+ let range = NSRange(location: 0, length: line.utf16.count)
+ let matches = regex.matches(in: String(line), options: [], range: range)
+ return matches.count > 0 && matches[0].numberOfRanges == 3
+ }
+
+ func handle(index: Int, line: String, vertices: [String: Vertex]) -> (Any.Type, Any) {
+ let range = NSRange(location: 0, length: line.utf16.count)
+ let matches = regex.matches(in: String(line), options: [], range: range)
+
+ let match = matches[0]
+ var groupVertices: [Vertex] = []
+ let vertexIdString = String(line[Range(match.range(at: 2), in: line)!])
+ let vertexIds = vertexIdString.split(separator: " ", omittingEmptySubsequences: true).map(
+ String.init)
+
+ for vertexId in vertexIds {
+ if let vertex = vertices[vertexId] {
+ groupVertices.append(vertex)
+ }
+ }
+
+ if groupVertices.count > 0 {
+ return ([Vertex].self, groupVertices)
+ }
+
+ return (NSObject.self, NSObject())
+ }
+}
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
- <key>com.apple.developer.aps-environment</key>
- <string>development</string>
- <key>com.apple.developer.icloud-container-identifiers</key>
- <array>
- <string>iCloud.pizza.unlimited.map</string>
- </array>
- <key>com.apple.developer.icloud-services</key>
- <array>
- <string>CloudKit</string>
- </array>
- <key>com.apple.security.app-sandbox</key>
- <true/>
- <key>com.apple.security.files.user-selected.read-write</key>
- <true/>
+ <key>com.apple.security.app-sandbox</key>
+ <true/>
+ <key>com.apple.security.files.user-selected.read-write</key>
+ <true/>
</dict>
</plist>
+++ /dev/null
-<?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>_XCCurrentVersionName</key>
- <string>Map.xcdatamodel</string>
-</dict>
-</plist>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="17709" systemVersion="20D5029f" minimumToolsVersion="Automatic" sourceLanguage="Swift" usedWithCloudKit="YES" userDefinedModelVersionIdentifier="">
- <entity name="Map" representedClassName="Map" syncable="YES" codeGenerationType="class">
- <attribute name="content" optional="YES" attributeType="String"/>
- <attribute name="createdAt" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
- <attribute name="title" optional="YES" attributeType="String"/>
- <attribute name="uuid" optional="YES" attributeType="UUID" usesScalarValueType="NO"/>
- </entity>
- <elements>
- <element name="Map" positionX="-63" positionY="-18" width="128" height="89"/>
- </elements>
-</model>
\ No newline at end of file
-//
-// MapApp.swift
-// Map
-//
-// Created by Ruben Beltran del Rio on 2/1/21.
-//
-
import SwiftUI
@main
struct MapApp: App {
- let persistenceController = PersistenceController.shared
-
var body: some Scene {
- WindowGroup {
- MapEditorWindow()
- .environment(\.managedObjectContext, persistenceController.container.viewContext)
- .environmentObject(AppStore(initialState: AppState(), reducer: appStateReducer))
- }.windowStyle(HiddenTitleBarWindowStyle()).commands {
- SidebarCommands()
+ DocumentGroup(newDocument: MapDocument()) { file in
+ MapEditor(document: file.$document, url: file.fileURL)
+ }.commands {
+ MapCommands()
}
}
}
struct EvolutionPicker: View {
- @EnvironmentObject private var store: AppStore
-
- private var selectedEvolution: Binding<StageType> {
- Binding(
- get: { store.state.selectedEvolution },
- set: { evolution in
- store.send(.selectEvolution(evolution: evolution))
- }
- )
- }
+ @Binding var selectedEvolution: StageType
var body: some View {
- Picker("Evolution", selection: selectedEvolution) {
+ Picker("Evolution", selection: $selectedEvolution) {
ForEach(StageType.types) { stage in
- Text(Stage.title(stage)).tag(stage).padding(4.0)
+ Text(Stage.title(stage)).font(.theme.body).tag(stage).padding(4.0)
}
Divider()
ForEach(StageType.characteristics) { stage in
- Text(Stage.title(stage)).tag(stage).padding(4.0)
+ Text(Stage.title(stage)).font(.theme.body).tag(stage).padding(4.0).font(.theme.body)
}
Divider()
ForEach(StageType.properties) { stage in
- Text(Stage.title(stage)).tag(stage).padding(4.0)
+ Text(Stage.title(stage)).font(.theme.body).tag(stage).padding(4.0)
}
Divider()
ForEach(StageType.custom) { stage in
- Text(Stage.title(stage)).tag(stage).padding(4.0)
+ Text(Stage.title(stage)).font(.theme.body).tag(stage).padding(4.0)
}
- }.padding(.horizontal, 8.0).padding(.vertical, 4.0)
+ }.font(.theme.body).padding(.horizontal, 8.0).padding(.vertical, 4.0)
}
}
-struct EvolutionPicker_Previews: PreviewProvider {
- static var previews: some View {
- EvolutionPicker()
- }
+#Preview {
+ let selectedEvolution: StageType = .behavior
+ EvolutionPicker(selectedEvolution: .constant(selectedEvolution))
}
}.stroke(Color.map.axisColor, lineWidth: lineWidth * 2)
// Y Labels
- Text("Visible").font(.theme.axisLabel).foregroundColor(.map.labelColor).rotationEffect(Angle(degrees: -90.0))
- .offset(CGSize(width: -35.0, height: 0.0))
- Text("Invisible").font(.theme.axisLabel).foregroundColor(.map.labelColor).rotationEffect(Angle(degrees: -90.0))
- .offset(CGSize(width: -40.0, height: mapSize.height - 20))
+ Text("Visible").font(.theme.axisLabel).foregroundColor(.map.labelColor).rotationEffect(
+ Angle(degrees: -90.0)
+ )
+ .offset(CGSize(width: -35.0, height: 0.0))
+ Text("Invisible").font(.theme.axisLabel).foregroundColor(.map.labelColor).rotationEffect(
+ Angle(degrees: -90.0)
+ )
+ .offset(CGSize(width: -40.0, height: mapSize.height - 20))
// X Labels
}
}
-struct MapAxes_Previews: PreviewProvider {
- static var previews: some View {
- MapAxes(
- mapSize: CGSize(width: 200.0, height: 200.0), lineWidth: CGFloat(1.0),
- evolution: Stage.stages(.general), stages: [25.0, 50.0, 75.0]
- ).padding(50.0)
- }
+#Preview {
+ MapAxes(
+ mapSize: CGSize(width: 200.0, height: 200.0), lineWidth: CGFloat(1.0),
+ evolution: Stage.stages(.general), stages: [25.0, 50.0, 75.0]
+ ).padding(50.0)
}
}
}
-struct MapBlockers_Previews: PreviewProvider {
- static var previews: some View {
- MapBlockers(
- mapSize: CGSize(width: 400.0, height: 400.0), vertexSize: CGSize(width: 25.0, height: 25.0),
- blockers: [
- Blocker(id: 0, position: CGPoint(x: 50.0, y: 50.0)),
- Blocker(id: 1, position: CGPoint(x: 10.0, y: 20.0)),
- ])
- }
+#Preview {
+ MapBlockers(
+ mapSize: CGSize(width: 400.0, height: 400.0), vertexSize: CGSize(width: 25.0, height: 25.0),
+ blockers: [
+ Blocker(id: 0, position: CGPoint(x: 50.0, y: 50.0)),
+ Blocker(id: 1, position: CGPoint(x: 10.0, y: 20.0)),
+ ])
}
}
}
-struct MapEdges_Previews: PreviewProvider {
- static var previews: some View {
- MapEdges(
- mapSize: CGSize(width: 400.0, height: 400.0), lineWidth: 1.0,
- vertexSize: CGSize(width: 25.0, height: 25.0),
- edges: [
- MapEdge(
- id: 1, origin: CGPoint(x: 2.0, y: 34.0), destination: CGPoint(x: 23.0, y: 76.2),
- arrowhead: true)
- ])
- }
+#Preview {
+ MapEdges(
+ mapSize: CGSize(width: 400.0, height: 400.0), lineWidth: 1.0,
+ vertexSize: CGSize(width: 25.0, height: 25.0),
+ edges: [
+ MapEdge(
+ id: 1, origin: CGPoint(x: 2.0, y: 34.0), destination: CGPoint(x: 23.0, y: 76.2),
+ arrowhead: true)
+ ])
}
--- /dev/null
+import ConcaveHull
+import SwiftUI
+
+struct MapGroup: View {
+
+ let mapSize: CGSize
+ let vertexSize: CGSize
+ let group: [Vertex]
+ let color: Color
+
+ let cornerSize = CGSize(width: 2.0, height: 2.0)
+ var strokeSize: CGFloat { 1.75 * vertexSize.width }
+
+ var hull: [CGPoint] {
+ let groupList = group.map({ vertex in
+ return [Double(vertex.position.x), Double(vertex.position.y)]
+ })
+ let hull = Hull()
+ let hullPoints = hull.hull(groupList, nil)
+ return hullPoints.compactMap({ object in
+ if let point = object as? [Double] {
+ return CGPoint(x: point[0], y: point[1])
+ }
+ return nil
+ })
+ }
+
+ var body: some View {
+ Path { path in
+ var initialMove: CGPoint?
+
+ for point in hull {
+ let offsetPoint = CGPoint(x: w(point.x), y: h(point.y))
+
+ if initialMove == nil {
+ path.move(to: offsetPoint)
+ initialMove = offsetPoint
+ } else {
+ path.addLine(to: offsetPoint)
+ }
+ }
+
+ if let initialMove = initialMove {
+ path.addLine(to: initialMove)
+ }
+
+ }
+ .applying(
+ CGAffineTransform(translationX: vertexSize.width / 2.0, y: vertexSize.height / 2.0)
+ )
+ .fill(color)
+ .stroke(
+ color,
+ style: StrokeStyle(
+ lineWidth: strokeSize,
+ lineCap: .round,
+ lineJoin: .round,
+ miterLimit: 0,
+ dash: [],
+ dashPhase: 0
+ )
+ )
+ }
+
+ func h(_ dimension: CGFloat) -> CGFloat {
+ max(0.0, min(mapSize.height, dimension * mapSize.height / 100.0))
+ }
+
+ func w(_ dimension: CGFloat) -> CGFloat {
+ max(0.0, min(mapSize.width, dimension * mapSize.width / 100.0))
+ }
+}
+
+#Preview {
+ MapGroup(
+ mapSize: CGSize(width: 400.0, height: 400.0), vertexSize: CGSize(width: 25.0, height: 25.0),
+ group: [
+ Vertex(id: 0, label: "A Circle", position: CGPoint(x: 50.0, y: 50.0)),
+ Vertex(id: 1, label: "A Square", position: CGPoint(x: 10.0, y: 20.0), shape: .square),
+ Vertex(id: 2, label: "A triangle", position: CGPoint(x: 25, y: 32.0), shape: .triangle),
+ Vertex(id: 3, label: "An X", position: CGPoint(x: 70.0, y: 70.0), shape: .x),
+ ], color: .red)
+}
--- /dev/null
+import ConcaveHull
+import SwiftUI
+
+struct MapGroups: View {
+
+ let mapSize: CGSize
+ let vertexSize: CGSize
+ let groups: [[Vertex]]
+
+ var body: some View {
+ ForEach(Array(groups.enumerated()), id: \.element) { index, group in
+ MapGroup(mapSize: mapSize, vertexSize: vertexSize, group: group, color: color(index))
+ }
+ }
+
+ private func color(_ index: Int) -> Color {
+ return .map.groupColors[index % Color.map.groupColors.count]
+ }
+}
+
+#Preview {
+ MapGroups(
+ mapSize: CGSize(width: 400.0, height: 400.0), vertexSize: CGSize(width: 25.0, height: 25.0),
+ groups: [
+ [
+ Vertex(id: 0, label: "A Circle", position: CGPoint(x: 50.0, y: 50.0)),
+ Vertex(id: 1, label: "A Square", position: CGPoint(x: 10.0, y: 20.0), shape: .square),
+ Vertex(id: 2, label: "A triangle", position: CGPoint(x: 25, y: 32.0), shape: .triangle),
+ Vertex(id: 3, label: "An X", position: CGPoint(x: 70.0, y: 70.0), shape: .x),
+ ]
+ ])
+}
let mapSize: CGSize
let lineWidth: CGFloat
let notes: [Note]
-
+
let maxWidth = 400.0
-
var body: some View {
ForEach(notes, id: \.id) { note in
- Text(note.text.replacingOccurrences(of: "\\n", with: "\n")).font(.theme.axisLabel)
+ Text(note.text.replacingOccurrences(of: "\\n", with: "\n")).font(.theme.note)
.padding(2.0)
.background(.white)
.foregroundColor(.map.labelColor)
}
}
-struct MapNotes_Previews: PreviewProvider {
- static var previews: some View {
- MapNotes(
- mapSize: CGSize(width: 400.0, height: 400.0), lineWidth: 1.0,
- notes: [
- Note(id: 0, position: CGPoint(x: 50.0, y: 50.0), text: "Notes can have a lot more text, so we need to make sure that they're resized correctly"),
- ])
- }
+#Preview {
+ MapNotes(
+ mapSize: CGSize(width: 400.0, height: 400.0), lineWidth: 1.0,
+ notes: [
+ Note(
+ id: 0, position: CGPoint(x: 50.0, y: 50.0),
+ text:
+ "Notes can have a lot more text, so we need to make sure that they're resized correctly")
+ ])
}
path.closeSubpath()
}.applying(
CGAffineTransform(translationX: vertexSize.width / 2.0, y: vertexSize.height / 2.0)
- ).strokedPath(StrokeStyle(lineWidth: lineWidth / 4, dash: [10.0])).stroke(Color.map.opportunityColor)
+ ).strokedPath(StrokeStyle(lineWidth: lineWidth / 4, dash: [10.0])).stroke(
+ Color.map.opportunityColor)
}
}
}
}
-struct MapOpportunities_Previews: PreviewProvider {
- static var previews: some View {
- MapOpportunities(
- mapSize: CGSize(width: 400.0, height: 400.0), lineWidth: 1.0,
- vertexSize: CGSize(width: 25.0, height: 25.0),
- opportunities: [
- Opportunity(id: 1, origin: CGPoint(x: 2.0, y: 34.0), destination: CGPoint(x: 23.0, y: 76.2))
- ])
- }
+#Preview {
+ MapOpportunities(
+ mapSize: CGSize(width: 400.0, height: 400.0), lineWidth: 1.0,
+ vertexSize: CGSize(width: 25.0, height: 25.0),
+ opportunities: [
+ Opportunity(id: 1, origin: CGPoint(x: 2.0, y: 34.0), destination: CGPoint(x: 23.0, y: 76.2))
+ ])
}
-import SwiftUI
import Patterns
+import SwiftUI
struct MapStages: View {
var body: some View {
ZStack(alignment: .topLeading) {
- PatternView(design: .constant(.stitch), pixelSize: 1.0, foregroundColor: .map.stageForeground, backgroundColor: .map.stageBackground)
- .frame(width: w(stages[0]), height: mapSize.height)
- PatternView(design: .constant(.shingles), pixelSize: 1.0, foregroundColor: .map.stageForeground, backgroundColor: .map.stageBackground)
- .offset(CGSize(width: w(stages[0]), height: 0))
- .frame(width: w(stages[1]) - w(stages[0]), height: mapSize.height)
- PatternView(design: .constant(.shadowGrid), pixelSize: 1.0, foregroundColor: .map.stageForeground, backgroundColor: .map.stageBackground)
- .offset(CGSize(width: w(stages[1]), height: 0))
- .frame(width: w(stages[2]) - w(stages[1]), height: mapSize.height)
- PatternView(design: .constant(.wicker), pixelSize: 1.0, foregroundColor: .map.stageForeground, backgroundColor: .map.stageBackground)
- .offset(CGSize(width: w(stages[2]), height: 0))
- .frame(width: mapSize.width - w(stages[2]), height: mapSize.height)
+ PatternView(
+ design: .constant(.stitch), pixelSize: 1.0, foregroundColor: .map.stageForeground,
+ backgroundColor: .map.stageBackground
+ )
+ .frame(width: w(stages[0]), height: mapSize.height)
+ PatternView(
+ design: .constant(.shingles), pixelSize: 1.0, foregroundColor: .map.stageForeground,
+ backgroundColor: .map.stageBackground
+ )
+ .offset(CGSize(width: w(stages[0]), height: 0))
+ .frame(width: w(stages[1]) - w(stages[0]), height: mapSize.height)
+ PatternView(
+ design: .constant(.shadowGrid), pixelSize: 1.0, foregroundColor: .map.stageForeground,
+ backgroundColor: .map.stageBackground
+ )
+ .offset(CGSize(width: w(stages[1]), height: 0))
+ .frame(width: w(stages[2]) - w(stages[1]), height: mapSize.height)
+ PatternView(
+ design: .constant(.wicker), pixelSize: 1.0, foregroundColor: .map.stageForeground,
+ backgroundColor: .map.stageBackground
+ )
+ .offset(CGSize(width: w(stages[2]), height: 0))
+ .frame(width: mapSize.width - w(stages[2]), height: mapSize.height)
Path { path in
path.move(to: CGPoint(x: w(stages[0]), y: 0))
path.closeSubpath()
path.move(to: CGPoint(x: w(stages[0]), y: 0))
path.closeSubpath()
- }.strokedPath(StrokeStyle(lineWidth: lineWidth / 4, dash: [10.0, 18.0])).stroke(Color.map.axisColor)
+ }.strokedPath(StrokeStyle(lineWidth: lineWidth / 4, dash: [10.0, 18.0])).stroke(
+ Color.map.axisColor)
}
}
}
}
-struct MapStages_Previews: PreviewProvider {
- static var previews: some View {
- MapStages(
- mapSize: CGSize(width: 200.0, height: 200.0), lineWidth: CGFloat(0.5),
- stages: [25.0, 50.0, 75.0])
- }
+#Preview {
+ MapStages(
+ mapSize: CGSize(width: 200.0, height: 200.0), lineWidth: CGFloat(0.5),
+ stages: [25.0, 50.0, 75.0])
}
let vertices: [Vertex]
let padding = CGFloat(5.0)
+ var onDragVertex: (Vertex, CGFloat, CGFloat) -> Void = { _, _, _ in }
+
var body: some View {
ZStack(alignment: .topLeading) {
ForEach(vertices, id: \.id) { vertex in
- getVertexShape(vertex).fill(Color.map.vertexColor)
- Text(vertex.label.replacingOccurrences(of: "\\n", with: "\n")).font(.theme.vertexLabel)
+ ZStack(alignment: .topLeading) {
+ getVertexShape(vertex).fill(Color.map.vertexColor)
+ Text(vertex.label.replacingOccurrences(of: "\\n", with: "\n")).font(.theme.vertexLabel)
.foregroundColor(.map.labelColor)
.shadow(color: .white, radius: 0, x: -0.5, y: -0.5)
.shadow(color: .white, radius: 0, x: 0.5, y: 0.5)
.offset(
- CGSize(
- width: w(vertex.position.x) + vertexSize.width + padding,
- height: h(vertex.position.y) + 7.0))
+ CGSize(
+ width: w(vertex.position.x) + vertexSize.width + padding,
+ height: h(vertex.position.y) + 7.0))
+ }.gesture(
+ DragGesture()
+ .onChanged { value in
+ let deltaX = value.startLocation.x - value.location.x
+ let deltaY = value.startLocation.y - value.location.y
+ onDragVertex(vertex, deltaX, deltaY)
+ }
+ )
}
}
}
}
}
-struct MapVertices_Previews: PreviewProvider {
- static var previews: some View {
- MapVertices(
- mapSize: CGSize(width: 400.0, height: 400.0), vertexSize: CGSize(width: 25.0, height: 25.0),
- vertices: [
- Vertex(id: 0, label: "A Circle", position: CGPoint(x: 50.0, y: 50.0)),
- Vertex(id: 1, label: "A Square", position: CGPoint(x: 10.0, y: 20.0), shape: .square),
- Vertex(id: 2, label: "A triangle", position: CGPoint(x: 25, y: 32.0), shape: .triangle),
- Vertex(id: 3, label: "An X", position: CGPoint(x: 70.0, y: 70.0), shape: .x),
- ])
- }
+#Preview {
+ MapVertices(
+ mapSize: CGSize(width: 400.0, height: 400.0), vertexSize: CGSize(width: 25.0, height: 25.0),
+ vertices: [
+ Vertex(id: 0, label: "A Circle", position: CGPoint(x: 50.0, y: 50.0)),
+ Vertex(id: 1, label: "A Square", position: CGPoint(x: 10.0, y: 20.0), shape: .square),
+ Vertex(id: 2, label: "A triangle", position: CGPoint(x: 25, y: 32.0), shape: .triangle),
+ Vertex(id: 3, label: "An X", position: CGPoint(x: 70.0, y: 70.0), shape: .x),
+ ])
}
class MapTextEditorController: NSViewController {
- @Binding var text: String
+ @Binding var document: MapDocument
let onChange: () -> Void
private let vertexRegex = MapParsingPatterns.vertex
private let opportunityRegex = MapParsingPatterns.opportunity
private let noteRegex = MapParsingPatterns.note
private let stageRegex = MapParsingPatterns.stage
+ private let groupRegex = MapParsingPatterns.group
private let changeDebouncer: Debouncer = Debouncer(seconds: 1)
- init(text: Binding<String>, onChange: @escaping () -> Void) {
- self._text = text
+ init(document: Binding<MapDocument>, onChange: @escaping () -> Void) {
+ self._document = document
self.onChange = onChange
super.init(nibName: nil, bundle: nil)
}
scrollView.translatesAutoresizingMaskIntoConstraints = false
+ textView.backgroundColor = .ui.background
textView.allowsUndo = true
textView.delegate = self
textView.textStorage?.delegate = self
- textView.string = self.text
+ textView.string = self.document.text
textView.isEditable = true
textView.font = .monospacedSystemFont(ofSize: 16.0, weight: .regular)
self.view = scrollView
func textDidChange(_ obj: Notification) {
if let textField = obj.object as? NSTextView {
- self.text = textField.string
-
-
- changeDebouncer.debounce {
- DispatchQueue.main.async {
- self.onChange()
- }
+ self.document.text = textField.string
+
+ changeDebouncer.debounce {
+ DispatchQueue.main.async {
+ self.onChange()
}
+ }
}
}
var matches = vertexRegex.matches(in: textStorage.string, options: [], range: range)
for match in matches {
- textStorage.addAttributes([.foregroundColor: NSColor.syntax.vertex], range: match.range(at: 1))
- textStorage.addAttributes([.foregroundColor: NSColor.syntax.number], range: match.range(at: 2))
- textStorage.addAttributes([.foregroundColor: NSColor.syntax.number], range: match.range(at: 3))
- textStorage.addAttributes([.foregroundColor: NSColor.syntax.option], range: match.range(at: 4))
+ textStorage.addAttributes(
+ [.foregroundColor: NSColor.syntax.vertex], range: match.range(at: 1))
+ textStorage.addAttributes(
+ [.foregroundColor: NSColor.syntax.number], range: match.range(at: 2))
+ textStorage.addAttributes(
+ [.foregroundColor: NSColor.syntax.number], range: match.range(at: 3))
+ textStorage.addAttributes(
+ [.foregroundColor: NSColor.syntax.option], range: match.range(at: 4))
}
matches = edgeRegex.matches(in: textStorage.string, options: [], range: range)
for match in matches {
- textStorage.addAttributes([.foregroundColor: NSColor.syntax.vertex], range: match.range(at: 1))
+ textStorage.addAttributes(
+ [.foregroundColor: NSColor.syntax.vertex], range: match.range(at: 1))
let arrowRange = match.range(at: 2)
textStorage.addAttributes(
[.foregroundColor: NSColor.syntax.symbol],
range: NSMakeRange(arrowRange.lowerBound - 1, arrowRange.length + 1))
- textStorage.addAttributes([.foregroundColor: NSColor.syntax.vertex], range: match.range(at: 3))
+ textStorage.addAttributes(
+ [.foregroundColor: NSColor.syntax.vertex], range: match.range(at: 3))
}
matches = opportunityRegex.matches(in: textStorage.string, options: [], range: range)
for match in matches {
- textStorage.addAttributes([.foregroundColor: NSColor.syntax.option], range: match.range(at: 1))
- textStorage.addAttributes([.foregroundColor: NSColor.syntax.vertex], range: match.range(at: 2))
- textStorage.addAttributes([.foregroundColor: NSColor.syntax.symbol], range: match.range(at: 3))
- textStorage.addAttributes([.foregroundColor: NSColor.syntax.number], range: match.range(at: 4))
+ textStorage.addAttributes(
+ [.foregroundColor: NSColor.syntax.option], range: match.range(at: 1))
+ textStorage.addAttributes(
+ [.foregroundColor: NSColor.syntax.vertex], range: match.range(at: 2))
+ textStorage.addAttributes(
+ [.foregroundColor: NSColor.syntax.symbol], range: match.range(at: 3))
+ textStorage.addAttributes(
+ [.foregroundColor: NSColor.syntax.number], range: match.range(at: 4))
}
matches = blockerRegex.matches(in: textStorage.string, options: [], range: range)
for match in matches {
- textStorage.addAttributes([.foregroundColor: NSColor.syntax.option], range: match.range(at: 1))
- textStorage.addAttributes([.foregroundColor: NSColor.syntax.vertex], range: match.range(at: 2))
+ textStorage.addAttributes(
+ [.foregroundColor: NSColor.syntax.option], range: match.range(at: 1))
+ textStorage.addAttributes(
+ [.foregroundColor: NSColor.syntax.vertex], range: match.range(at: 2))
}
-
+
matches = noteRegex.matches(in: textStorage.string, options: [], range: range)
for match in matches {
- textStorage.addAttributes([.foregroundColor: NSColor.syntax.option], range: match.range(at: 1))
- textStorage.addAttributes([.foregroundColor: NSColor.syntax.number], range: match.range(at: 2))
- textStorage.addAttributes([.foregroundColor: NSColor.syntax.number], range: match.range(at: 3))
+ textStorage.addAttributes(
+ [.foregroundColor: NSColor.syntax.option], range: match.range(at: 1))
+ textStorage.addAttributes(
+ [.foregroundColor: NSColor.syntax.number], range: match.range(at: 2))
+ textStorage.addAttributes(
+ [.foregroundColor: NSColor.syntax.number], range: match.range(at: 3))
}
matches = stageRegex.matches(in: textStorage.string, options: [], range: range)
for match in matches {
- textStorage.addAttributes([.foregroundColor: NSColor.syntax.option], range: match.range(at: 1))
- textStorage.addAttributes([.foregroundColor: NSColor.syntax.number], range: match.range(at: 2))
+ textStorage.addAttributes(
+ [.foregroundColor: NSColor.syntax.option], range: match.range(at: 1))
+ textStorage.addAttributes(
+ [.foregroundColor: NSColor.syntax.number], range: match.range(at: 2))
+ }
+
+ matches = groupRegex.matches(in: textStorage.string, options: [], range: range)
+
+ for match in matches {
+ textStorage.addAttributes(
+ [.foregroundColor: NSColor.syntax.option], range: match.range(at: 1))
+ textStorage.addAttributes(
+ [.foregroundColor: NSColor.syntax.vertex], range: match.range(at: 2))
}
}
}
struct MapTextEditor: NSViewControllerRepresentable {
- @Binding var text: String
+ @Binding var document: MapDocument
var onChange: () -> Void = {}
func makeNSViewController(
context: NSViewControllerRepresentableContext<MapTextEditor>
) -> MapTextEditorController {
- return MapTextEditorController(text: $text, onChange: onChange)
+ return MapTextEditorController(document: $document, onChange: onChange)
}
func updateNSViewController(
--- /dev/null
+import SwiftUI
+
+struct MapCommands: Commands {
+
+ @AppStorage("viewStyle") var viewStyle: ViewStyle = .horizontal
+ @AppStorage("zoom") var zoom = 1.0
+
+ var body: some Commands {
+
+ // View
+
+ CommandGroup(after: CommandGroupPlacement.toolbar) {
+ if viewStyle == .horizontal {
+ Button("Use Vertical Layout") {
+ viewStyle = .vertical
+ }.keyboardShortcut(
+ "l", modifiers: EventModifiers([.command])
+ )
+ } else {
+ Button("Use Horizontal Layout") {
+ viewStyle = .horizontal
+ }.keyboardShortcut(
+ "l", modifiers: EventModifiers([.command])
+ )
+ }
+ Divider()
+ Button("Zoom In") {
+ zoom = min(Constants.kMaxZoom, zoom + 0.1)
+ }.keyboardShortcut(
+ "+", modifiers: EventModifiers([.command])
+ )
+ Button("Zoom Out") {
+ zoom = max(Constants.kMinZoom, zoom - 0.1)
+ }.keyboardShortcut(
+ "-", modifiers: EventModifiers([.command])
+ )
+ Divider()
+ }
+
+ CommandGroup(replacing: CommandGroupPlacement.help) {
+ Button("Map Help") { NSWorkspace.shared.open(URL(string: "https://map.tranquil.systems")!) }
+ }
+ }
+}
struct MapRenderView: View {
- @Binding var content: String
+ @Binding var document: MapDocument
@Binding var evolution: StageType
-
+
var stage: Stage {
Stage.stages(evolution)
}
- @State var parsedMap: ParsedMap = ParsedMap.empty
+ var parsedMap: ParsedMap {
+ MapParser.parse(content: document.text)
+ }
- let mapSize = CGSize(width: 1300.0, height: 1000.0)
+ let mapSize = Dimensions.mapSize
+ let padding = Dimensions.mapPadding
let lineWidth = CGFloat(0.5)
let vertexSize = CGSize(width: 25.0, height: 25.0)
- let padding = CGFloat(30.0)
+
+ var onDragVertex: (Vertex, CGFloat, CGFloat) -> Void = { _, _, _ in }
var body: some View {
ZStack(alignment: .topLeading) {
MapEdges(
mapSize: mapSize, lineWidth: lineWidth, vertexSize: vertexSize, edges: parsedMap.edges)
MapBlockers(mapSize: mapSize, vertexSize: vertexSize, blockers: parsedMap.blockers)
- MapVertices(mapSize: mapSize, vertexSize: vertexSize, vertices: parsedMap.vertices)
+ MapVertices(
+ mapSize: mapSize, vertexSize: vertexSize, vertices: parsedMap.vertices,
+ onDragVertex: onDragVertex)
MapOpportunities(
mapSize: mapSize, lineWidth: lineWidth, vertexSize: vertexSize,
opportunities: parsedMap.opportunities)
+ MapGroups(mapSize: mapSize, vertexSize: vertexSize, groups: parsedMap.groups).drawingGroup(
+ opaque: true
+ ).opacity(0.1)
MapNotes(
mapSize: mapSize, lineWidth: lineWidth, notes: parsedMap.notes)
- }.frame(
- width: mapSize.width,
+ }.offset(x: padding, y: padding).frame(
+ width: mapSize.width + 2 * padding,
height: mapSize.height + 2 * padding, alignment: .topLeading
- ).onAppear {
- self.parsedMap = Map.parse(content: content)
- }.padding(padding).onChange(of: content) { newState in
- self.parsedMap = Map.parse(content: newState)
- }
+ )
}
}
-struct MapRenderView_Previews: PreviewProvider {
- static var previews: some View {
- MapRenderView(
- content: Binding.constant(""), evolution: Binding.constant(StageType.general)
- ).environment(
- \.managedObjectContext, PersistenceController.preview.container.viewContext)
- }
+#Preview {
+ MapRenderView(
+ document: Binding.constant(MapDocument(text: "")),
+ evolution: Binding.constant(StageType.general)
+ )
}
--- /dev/null
+import SwiftUI
+
+struct EvolutionPicker: View {
+
+ @EnvironmentObject private var store: AppStore
+
+ private var selectedEvolution: Binding<StageType> {
+ Binding(
+ get: { store.state.selectedEvolution },
+ set: { evolution in
+ store.send(.selectEvolution(evolution: evolution))
+ }
+ )
+ }
+
+ var body: some View {
+ Picker("Evolution", selection: selectedEvolution) {
+ ForEach(StageType.types) { stage in
+ Text(Stage.title(stage)).font(.theme.body).tag(stage).padding(4.0)
+ }
+ Divider()
+ ForEach(StageType.characteristics) { stage in
+ Text(Stage.title(stage)).font(.theme.body).tag(stage).padding(4.0).font(.theme.body)
+ }
+ Divider()
+ ForEach(StageType.properties) { stage in
+ Text(Stage.title(stage)).font(.theme.body).tag(stage).padding(4.0)
+ }
+ Divider()
+ ForEach(StageType.custom) { stage in
+ Text(Stage.title(stage)).font(.theme.body).tag(stage).padding(4.0)
+ }
+ }.font(.theme.body).padding(.horizontal, 8.0).padding(.vertical, 4.0)
+ }
+}
+
+struct EvolutionPicker_Previews: PreviewProvider {
+ static var previews: some View {
+ EvolutionPicker()
+ }
+}
--- /dev/null
+import SwiftUI
+
+struct MapEditor: View {
+ @Binding var document: MapDocument
+ var url: URL?
+ @State var selectedEvolution: StageType = .behavior
+
+ @AppStorage("viewStyle") var viewStyle: ViewStyle = .horizontal
+
+ let zoomRange = Constants.kMinZoom...Constants.kMaxZoom
+ @AppStorage("zoom") var zoom = 1.0
+ @State var lastZoom = 1.0
+
+ var body: some View {
+ VStack(spacing: 0) {
+ adaptiveStack {
+ ZStack(alignment: .topLeading) {
+ MapTextEditor(document: $document)
+ .background(Color.ui.background)
+ .foregroundColor(Color.ui.foreground)
+ .frame(minHeight: 96.0)
+ }.padding(.top, 8.0).padding(.leading, 8.0).background(Color.ui.background).cornerRadius(
+ 5.0)
+ GeometryReader { geometry in
+ ScrollView([.horizontal, .vertical]) {
+ MapRenderView(
+ document: $document, evolution: $selectedEvolution, onDragVertex: onDragVertex
+ ).scaleEffect(zoom, anchor: .center).frame(
+ width: (Dimensions.mapSize.width + 2 * Dimensions.mapPadding) * zoom,
+ height: (Dimensions.mapSize.height + 2 * Dimensions.mapPadding) * zoom)
+ }.background(Color.ui.background)
+ .gesture(
+ MagnificationGesture()
+ .onChanged { value in
+ let delta = value / lastZoom
+ lastZoom = value
+ zoom = min(max(zoom * delta, zoomRange.lowerBound), zoomRange.upperBound)
+ }
+ .onEnded { _ in
+ lastZoom = 1.0
+ }
+ )
+ }
+ }
+ Divider()
+ HStack {
+ Spacer()
+ Slider(
+ value: $zoom, in: zoomRange, step: 0.1,
+ label: {
+ Text(formatZoom(zoom))
+ .font(.theme.smallControl)
+ },
+ minimumValueLabel: {
+ Image(systemName: "minus.magnifyingglass")
+ .font(.theme.smallControl)
+ .help("Zoom Out (⌘-)")
+ },
+ maximumValueLabel: {
+ Image(systemName: "plus.magnifyingglass")
+ .font(.theme.smallControl)
+ .help("Zoom In (⌘+)")
+ }
+ ).frame(width: 200).padding(.trailing, 10.0)
+ }.padding(4.0)
+ }.toolbar {
+ HStack {
+ Button(action: saveImage) {
+ Image(systemName: "photo")
+ }
+ .help("Export Image (⌘E)")
+ .padding(.vertical, 4.0).padding(.leading, 4.0).padding(.trailing, 8.0)
+ }
+ EvolutionPicker(selectedEvolution: $selectedEvolution)
+ }
+ }
+
+ @ViewBuilder
+ func adaptiveStack<Content: View>(@ViewBuilder content: () -> Content) -> some View {
+ if viewStyle == .horizontal {
+ VSplitView {
+ content()
+ }
+ } else {
+ HSplitView {
+ content()
+ }
+ }
+ }
+
+ private func formatZoom(_ number: CGFloat) -> String {
+ let formatter = NumberFormatter()
+ formatter.numberStyle = .decimal
+ formatter.maximumFractionDigits = 1
+ formatter.minimumFractionDigits = 1
+ return (formatter.string(from: NSNumber(value: number)) ?? "") + "x"
+ }
+
+ private func onDragVertex(vertex: Vertex, x: CGFloat, y: CGFloat) {
+ print("Dragging: \(vertex), \(x), \(y)")
+ }
+
+ private func saveImage() {
+ if let image = document.exportAsImage(withEvolution: selectedEvolution) {
+
+ let filename = url?.deletingPathExtension().lastPathComponent ?? "Untitled"
+
+ let savePanel = NSSavePanel()
+ savePanel.allowedContentTypes = [.png]
+ savePanel.canCreateDirectories = true
+ savePanel.isExtensionHidden = false
+ savePanel.title = "Save \(filename) as image"
+ savePanel.message = "Choose a location to save the image"
+ savePanel.nameFieldStringValue = "\(filename).png"
+ savePanel.begin { result in
+ if result == .OK, let url = savePanel.url {
+ if let tiffRepresentation = image.tiffRepresentation {
+ let bitmapImage = NSBitmapImageRep(data: tiffRepresentation)
+ let pngData = bitmapImage?.representation(using: .png, properties: [:])
+ do {
+ try pngData?.write(to: url)
+ } catch {
+ return
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+#Preview {
+ MapEditor(document: .constant(MapDocument()), url: URL(filePath: "test.png")!)
+}
+++ /dev/null
-import CoreData
-import SwiftUI
-
-struct EmptyMapDetailScreen: View {
-
- var body: some View {
- Text("Select a map from the left hand side, or click on + to create one.")
- }
-}
-
-struct DefaultMapView_Previews: PreviewProvider {
- static var previews: some View {
- EmptyMapDetailScreen().environment(
- \.managedObjectContext, PersistenceController.preview.container.viewContext)
- }
-}
+++ /dev/null
-import Combine
-import CoreData
-import SwiftUI
-
-struct MapDetailScreen: View {
- @Environment(\.managedObjectContext) private var viewContext
-
- @EnvironmentObject var store: AppStore
-
- @ObservedObject var map: Map
-
- @State var title: String
- @State var content: String
-
- var body: some View {
- if map.uuid != nil {
- VSplitView {
- VStack {
- HStack {
- TextField(
- "Title", text: $title, onCommit: saveModel
- ).font(.title2).textFieldStyle(PlainTextFieldStyle()).padding(.vertical, 4.0).padding(
- .leading, 4.0)
- Button(action: saveText) {
- Image(systemName: "doc.text")
- }.padding(.vertical, 4.0).padding(.leading, 4.0)
- Button(action: saveImage) {
- Image(systemName: "photo")
- }.padding(.vertical, 4.0).padding(.leading, 4.0).padding(.trailing, 8.0)
- }
- EvolutionPicker()
-
- ZStack(alignment: .topLeading) {
- MapTextEditor(text: $content, onChange: saveModel)
- .background(Color.ui.background)
- .foregroundColor(Color.ui.foreground)
- .frame(minHeight: 96.0)
- }.padding(.top, 8.0).padding(.leading, 8.0).background(Color.ui.background).cornerRadius(
- 5.0)
- }.padding(.horizontal, 8.0)
- ScrollView([.horizontal, .vertical]) {
- MapRenderView(content: $content, evolution: .constant(store.state.selectedEvolution))
- }
- }.onDisappear {
- saveModel()
- }
- } else {
- EmptyMapDetailScreen()
- }
- }
-
- private func saveModel() {
- map.content = content
- map.title = title
- try? viewContext.save()
- }
-
- private func saveText() {
- store.send(.exportMapAsText(map: map))
- }
-
- private func saveImage() {
- store.send(.exportMapAsImage(map: map))
- }
-}
-
-struct MapDetailView_Previews: PreviewProvider {
- static var previews: some View {
- MapDetailScreen(map: Map(), title: "", content: "").environment(
- \.managedObjectContext, PersistenceController.preview.container.viewContext)
- }
-}
static let darkSlate = Color("Dark Slate")
static let jasperRed = Color("Jasper Red")
static let olympicBlue = Color("Olympic Blue")
+ static let lightPorcelainGreen = Color("Light Porcelain Green")
+ static let naplesYellow = Color("Naples Yellow")
+ static let hermosaPink = Color("Hermosa Pink")
static let neutralGray = Color("Neutral Gray")
static let lightNeutralGray = Color("Light Neutral Gray")
static let darkNeutralGray = Color("Dark Neutral Gray")
+ static let darkerNeutralGray = Color("Darker Neutral Gray")
}
-
+
struct map {
static let labelColor = Color.theme.darkSlate
static let axisColor = Color.theme.darkSlate
static let opportunityColor = Color.theme.olympicBlue
static let stageForeground = Color.theme.lightNeutralGray
static let stageBackground = Color.white
+ static let groupColors = [
+ Color.theme.olympicBlue,
+ Color.theme.jasperRed,
+ Color.theme.lightPorcelainGreen,
+ Color.theme.naplesYellow,
+ Color.theme.hermosaPink,
+ ]
}
-
+
struct ui {
static let foreground = Color("Foreground")
static let background = Color("Background")
--- /dev/null
+import Foundation
+
+struct Dimensions {
+ static let mapSize = CGSize(width: 1300.0, height: 1000.0)
+ static let mapPadding: CGFloat = 42.0
+}
--- /dev/null
+import SwiftUI
+
+extension Font {
+ public struct theme {
+
+ // Map
+ static let note = Font.system(size: 12, design: .serif)
+ static let axisLabel = Font.system(size: 14, design: .serif)
+ static let vertexLabel = Font.system(size: 12, design: .serif)
+
+ // UI
+ static let smallControl = Font.system(size: 9)
+ static let body = Font.system(size: 13)
+ }
+}
static let option = NSColor(named: "Option") ?? .textColor
static let symbol = NSColor(named: "Symbol") ?? .textColor
}
+
+ struct ui {
+ static let background = NSColor(named: "Background") ?? .windowBackgroundColor
+ }
}
--- /dev/null
+enum ViewStyle: String {
+ case vertical, horizontal
+}
+++ /dev/null
-import CoreData
-import SwiftUI
-
-struct MapEditorWindow: View {
- @Environment(\.managedObjectContext) private var viewContext
-
- @EnvironmentObject var store: AppStore
-
- @FetchRequest(
- sortDescriptors: [NSSortDescriptor(keyPath: \Map.createdAt, ascending: true)],
- animation: .default)
- private var maps: FetchedResults<Map>
-
- var body: some View {
- NavigationView {
- List {
- if maps.count == 0 {
- EmptyMapDetailScreen()
- }
- ForEach(maps) { map in
- NavigationLink(
- destination: MapDetailScreen(map: map, title: map.title ?? "", content: map.content ?? "")
- ) {
- HStack {
- Text(map.title ?? "Untitled Map")
- Spacer()
- Text(mapFormatter.string(from: (map.createdAt ?? Date())))
- .font(.caption)
- .padding(.vertical, 2.0)
- .padding(.horizontal, 4.0)
- .background(Color.accentColor)
- .foregroundColor(Color.black)
- .cornerRadius(2.0)
- }.padding(.leading, 8.0)
- }.contextMenu {
- Button(
- action: { store.send(.deleteMap(map: map)) },
- label: {
- Image(systemName: "trash")
- Text("Delete")
- })
- }
- }
- .onDelete(perform: deleteMaps)
- }.frame(minWidth: 250.0, alignment: .leading)
- .toolbar {
- HStack {
- Button(action: toggleSidebar) {
- Label("Toggle Sidebar", systemImage: "sidebar.left")
- }
- Button(action: addMap) {
- Label("Add Map", systemImage: "plus")
- }
- }
- }
- EmptyMapDetailScreen()
- }
- }
-
- private func toggleSidebar() {
- NSApp.keyWindow?.firstResponder?.tryToPerform(
- #selector(NSSplitViewController.toggleSidebar(_:)), with: nil)
- }
-
- private func addMap() {
- withAnimation {
- let newMap = Map(context: viewContext)
- newMap.uuid = UUID()
- newMap.createdAt = Date()
- newMap.title = "Map \(newMap.createdAt!.format())"
- newMap.content = ""
-
- do {
- try viewContext.save()
- } catch {
- let nsError = error as NSError
- fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
- }
- }
- }
-
- private func deleteMaps(offsets: IndexSet) {
-
- withAnimation {
- offsets.map { maps[$0] }.forEach(viewContext.delete)
-
- do {
- try viewContext.save()
- } catch {
- let nsError = error as NSError
- fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
- }
- }
- }
-}
-
-private let mapFormatter: DateFormatter = {
- let formatter = DateFormatter()
- formatter.dateStyle = .short
- formatter.timeStyle = .none
- return formatter
-}()
-
-struct ContentView_Previews: PreviewProvider {
- static var previews: some View {
- MapEditorWindow().environment(
- \.managedObjectContext, PersistenceController.preview.container.viewContext)
- }
-}
+++ /dev/null
-<?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>$(DEVELOPMENT_LANGUAGE)</string>
- <key>CFBundleExecutable</key>
- <string>$(EXECUTABLE_NAME)</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>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
- <key>CFBundleShortVersionString</key>
- <string>1.0</string>
- <key>CFBundleVersion</key>
- <string>1</string>
-</dict>
-</plist>
-//
-// MapTests.swift
-// MapTests
-//
-// Created by Ruben Beltran del Rio on 2/1/21.
-//
-
-import XCTest
+import Testing
@testable import Map
-class MapTests: XCTestCase {
-
- override func setUpWithError() throws {
- // Put setup code here. This method is called before the invocation of each test method in the class.
- }
-
- override func tearDownWithError() throws {
- // Put teardown code here. This method is called after the invocation of each test method in the class.
- }
-
- func testExample() throws {
- // This is an example of a functional test case.
- // Use XCTAssert and related functions to verify your tests produce the correct results.
- }
+struct MapTests {
- func testPerformanceExample() throws {
- // This is an example of a performance test case.
- self.measure {
- // Put the code you want to measure the time of here.
- }
+ @Test func testExample() async throws {
+ // Write your test here and use APIs like `#expect(...)` to check expected conditions.
}
}
+++ /dev/null
-<?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>$(DEVELOPMENT_LANGUAGE)</string>
- <key>CFBundleExecutable</key>
- <string>$(EXECUTABLE_NAME)</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>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
- <key>CFBundleShortVersionString</key>
- <string>1.0</string>
- <key>CFBundleVersion</key>
- <string>1</string>
-</dict>
-</plist>
-//
-// MapUITests.swift
-// MapUITests
-//
-// Created by Ruben Beltran del Rio on 2/1/21.
-//
-
import XCTest
-class MapUITests: XCTestCase {
+final class MapUITests: XCTestCase {
override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class.
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
+ @MainActor
func testExample() throws {
// UI tests must launch the application that they test.
let app = XCUIApplication()
app.launch()
- // Use recording to get started writing UI tests.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
+ @MainActor
func testLaunchPerformance() throws {
- if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) {
+ if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) {
// This measures how long it takes to launch your application.
measure(metrics: [XCTApplicationLaunchMetric()]) {
XCUIApplication().launch()
--- /dev/null
+import XCTest
+
+final class MapUITestsLaunchTests: XCTestCase {
+
+ override class var runsForEachTargetApplicationUIConfiguration: Bool {
+ true
+ }
+
+ override func setUpWithError() throws {
+ continueAfterFailure = false
+ }
+
+ @MainActor
+ func testLaunch() throws {
+ let app = XCUIApplication()
+ app.launch()
+
+ // Insert steps here to perform after app launch but before taking a screenshot,
+ // such as logging into a test account or navigating somewhere in the app
+
+ let attachment = XCTAttachment(screenshot: app.screenshot())
+ attachment.name = "Launch Screen"
+ attachment.lifetime = .keepAlways
+ add(attachment)
+ }
+}