From: Ruben Beltran del Rio Date: Sun, 7 May 2023 13:22:54 +0000 (+0200) Subject: Update to support notes + new style X-Git-Tag: 2.0.0 X-Git-Url: https://git.r.bdr.sh/rbdr/map/commitdiff_plain/fdb4633d3e9158e457d57e820df6e1efb4df39c2?ds=inline;hp=75a0e4509a70055851b085f3f7293ae1cf48164c Update to support notes + new style --- diff --git a/Map.xcodeproj/project.pbxproj b/Map.xcodeproj/project.pbxproj index b212de6..9cd5d87 100644 --- a/Map.xcodeproj/project.pbxproj +++ b/Map.xcodeproj/project.pbxproj @@ -3,37 +3,35 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 53; 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 /* DefaultMapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B523C74A25C9C1BA00C44061 /* DefaultMapView.swift */; }; + 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 */; }; - B523C77625CA181100C44061 /* MapColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B523C77525CA181100C44061 /* MapColor.swift */; }; B523C77E25CA294C00C44061 /* MapOpportunities.swift in Sources */ = {isa = PBXBuildFile; fileRef = B523C77D25CA294C00C44061 /* MapOpportunities.swift */; }; B526257225C874F9003E73B7 /* MapApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = B526257125C874F9003E73B7 /* MapApp.swift */; }; - B526257425C874F9003E73B7 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B526257325C874F9003E73B7 /* ContentView.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 /* MapDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52625A525C876C3003E73B7 /* MapDetail.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 /* MapRender.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52625AF25C87C14003E73B7 /* MapRender.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 */; }; - B587BB6025CDCECB00F328ED /* SlowMapRender.swift in Sources */ = {isa = PBXBuildFile; fileRef = B587BB5F25CDCECB00F328ED /* SlowMapRender.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 */; }; @@ -42,6 +40,12 @@ 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 */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -64,17 +68,16 @@ /* Begin PBXFileReference section */ B523C73C25C98D9800C44061 /* NSImage+writePNG.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSImage+writePNG.swift"; sourceTree = ""; }; B523C74525C9BD3500C44061 /* CloudKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CloudKit.framework; path = System/Library/Frameworks/CloudKit.framework; sourceTree = SDKROOT; }; - B523C74A25C9C1BA00C44061 /* DefaultMapView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultMapView.swift; sourceTree = ""; }; + B523C74A25C9C1BA00C44061 /* EmptyMapDetailScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyMapDetailScreen.swift; sourceTree = ""; }; B523C75925C9FD4900C44061 /* MapAxes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapAxes.swift; sourceTree = ""; }; B523C76125CA05A300C44061 /* MapStages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapStages.swift; sourceTree = ""; }; B523C76625CA071B00C44061 /* MapVertices.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapVertices.swift; sourceTree = ""; }; B523C76B25CA0DFA00C44061 /* MapEdges.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapEdges.swift; sourceTree = ""; }; B523C77025CA121300C44061 /* MapBlockers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapBlockers.swift; sourceTree = ""; }; - B523C77525CA181100C44061 /* MapColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapColor.swift; sourceTree = ""; }; B523C77D25CA294C00C44061 /* MapOpportunities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapOpportunities.swift; sourceTree = ""; }; 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 = ""; }; - B526257325C874F9003E73B7 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + B526257325C874F9003E73B7 /* MapEditorWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapEditorWindow.swift; sourceTree = ""; }; B526257525C874FA003E73B7 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; B526257825C874FA003E73B7 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; B526257A25C874FA003E73B7 /* Persistence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Persistence.swift; sourceTree = ""; }; @@ -87,15 +90,14 @@ 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 = ""; }; B526259625C874FA003E73B7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - B52625A525C876C3003E73B7 /* MapDetail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapDetail.swift; sourceTree = ""; }; + B52625A525C876C3003E73B7 /* MapDetailScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapDetailScreen.swift; sourceTree = ""; }; B52625AA25C87909003E73B7 /* Date+format.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+format.swift"; sourceTree = ""; }; - B52625AF25C87C14003E73B7 /* MapRender.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapRender.swift; sourceTree = ""; }; + B52625AF25C87C14003E73B7 /* MapRenderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapRenderView.swift; sourceTree = ""; }; B52625BA25C884C2003E73B7 /* Map+parse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Map+parse.swift"; sourceTree = ""; }; B52625C525C8BD2A003E73B7 /* Stage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Stage.swift; sourceTree = ""; }; B539516B25CB0C9200959F72 /* Store.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Store.swift; sourceTree = ""; }; B539517325CB0CA400959F72 /* AppState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppState.swift; sourceTree = ""; }; B539518025CB2D7A00959F72 /* MapTextEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapTextEditor.swift; sourceTree = ""; }; - B587BB5F25CDCECB00F328ED /* SlowMapRender.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SlowMapRender.swift; sourceTree = ""; }; B5CF75C825CC19FC003BFF3D /* EvolutionPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EvolutionPicker.swift; sourceTree = ""; }; B5CF75CE25CC7965003BFF3D /* MapParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapParser.swift; sourceTree = ""; }; B5CF75D725CC79BC003BFF3D /* VertexParserStrategy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VertexParserStrategy.swift; sourceTree = ""; }; @@ -104,6 +106,11 @@ B5CF75E925CC7A13003BFF3D /* OpportunityParserStrategy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpportunityParserStrategy.swift; sourceTree = ""; }; B5CF75EE25CC7A4A003BFF3D /* StageParserStrategy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StageParserStrategy.swift; sourceTree = ""; }; B5CF75F625CC97CA003BFF3D /* Debouncer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Debouncer.swift; sourceTree = ""; }; + B5F8D3072A06DD8C000EEA24 /* Font+Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Font+Theme.swift"; sourceTree = ""; }; + B5F8D30A2A06E3E6000EEA24 /* Color+Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+Theme.swift"; sourceTree = ""; }; + B5F8D30F2A07B33D000EEA24 /* NSColor+Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSColor+Theme.swift"; sourceTree = ""; }; + B5F8D3112A07B690000EEA24 /* NoteParserStrategy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteParserStrategy.swift; sourceTree = ""; }; + B5F8D3132A07C05F000EEA24 /* MapNotes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapNotes.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -112,6 +119,7 @@ buildActionMask = 2147483647; files = ( B523C74625C9BD3500C44061 /* CloudKit.framework in Frameworks */, + B5F8D30E2A06E5C2000EEA24 /* Patterns in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -140,17 +148,18 @@ name = Frameworks; sourceTree = ""; }; - B523C75825C9FD3A00C44061 /* MapRenderComponents */ = { + 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 = MapRenderComponents; + path = MapRender; sourceTree = ""; }; B526256525C874F9003E73B7 = { @@ -177,18 +186,16 @@ B526257025C874F9003E73B7 /* Map */ = { isa = PBXGroup; children = ( - B523C77525CA181100C44061 /* MapColor.swift */, - B5CF75CD25CC7953003BFF3D /* MapParser */, - B539516A25CB0C7800959F72 /* State */, - B52625B425C87D54003E73B7 /* Extensions */, - B539517925CB0D6100959F72 /* Views */, - B523C75825C9FD3A00C44061 /* MapRenderComponents */, + 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 */, - B5CF75F625CC97CA003BFF3D /* Debouncer.swift */, ); path = Map; sourceTree = ""; @@ -219,61 +226,121 @@ path = MapUITests; sourceTree = ""; }; - B52625B425C87D54003E73B7 /* Extensions */ = { + B52625B425C87D54003E73B7 /* Core Extensions */ = { isa = PBXGroup; children = ( - B52625BA25C884C2003E73B7 /* Map+parse.swift */, B52625AA25C87909003E73B7 /* Date+format.swift */, B523C73C25C98D9800C44061 /* NSImage+writePNG.swift */, + B5F8D3072A06DD8C000EEA24 /* Font+Theme.swift */, + B5F8D30F2A07B33D000EEA24 /* NSColor+Theme.swift */, + B5F8D30A2A06E3E6000EEA24 /* Color+Theme.swift */, ); - path = Extensions; + path = "Core Extensions"; sourceTree = ""; }; - B539516A25CB0C7800959F72 /* State */ = { + B5CF75CD25CC7953003BFF3D /* MapParser */ = { isa = PBXGroup; children = ( + B5CF75D625CC79A4003BFF3D /* Strategies */, + B5CF75CE25CC7965003BFF3D /* MapParser.swift */, + ); + path = MapParser; + sourceTree = ""; + }; + B5CF75D625CC79A4003BFF3D /* Strategies */ = { + isa = PBXGroup; + children = ( + B5CF75D725CC79BC003BFF3D /* VertexParserStrategy.swift */, + B5F8D3112A07B690000EEA24 /* NoteParserStrategy.swift */, + B5CF75DC25CC79D7003BFF3D /* EdgeParserStrategy.swift */, + B5CF75E125CC79ED003BFF3D /* BlockerParserStrategy.swift */, + B5CF75E925CC7A13003BFF3D /* OpportunityParserStrategy.swift */, + B5CF75EE25CC7A4A003BFF3D /* StageParserStrategy.swift */, + ); + path = Strategies; + sourceTree = ""; + }; + B5F8D2FE2A06DB3A000EEA24 /* Data */ = { + isa = PBXGroup; + children = ( + B5F8D3012A06DB75000EEA24 /* Models */, B52625C525C8BD2A003E73B7 /* Stage.swift */, B526257A25C874FA003E73B7 /* Persistence.swift */, B539516B25CB0C9200959F72 /* Store.swift */, B539517325CB0CA400959F72 /* AppState.swift */, ); - path = State; + path = Data; sourceTree = ""; }; - B539517925CB0D6100959F72 /* Views */ = { + B5F8D2FF2A06DB40000EEA24 /* Presentation */ = { + isa = PBXGroup; + children = ( + B5F8D3022A06DBC3000EEA24 /* Windows */, + B5F8D3032A06DC2D000EEA24 /* Screens */, + B5F8D3052A06DCF3000EEA24 /* Complex Components */, + B5F8D3042A06DCC4000EEA24 /* Base Components */, + ); + path = Presentation; + sourceTree = ""; + }; + B5F8D3012A06DB75000EEA24 /* Models */ = { + isa = PBXGroup; + children = ( + B52625BA25C884C2003E73B7 /* Map+parse.swift */, + ); + path = Models; + sourceTree = ""; + }; + B5F8D3022A06DBC3000EEA24 /* Windows */ = { + isa = PBXGroup; + children = ( + B526257325C874F9003E73B7 /* MapEditorWindow.swift */, + ); + path = Windows; + sourceTree = ""; + }; + B5F8D3032A06DC2D000EEA24 /* Screens */ = { + isa = PBXGroup; + children = ( + B523C74A25C9C1BA00C44061 /* EmptyMapDetailScreen.swift */, + B52625A525C876C3003E73B7 /* MapDetailScreen.swift */, + ); + path = Screens; + sourceTree = ""; + }; + B5F8D3042A06DCC4000EEA24 /* Base Components */ = { isa = PBXGroup; children = ( - B526257125C874F9003E73B7 /* MapApp.swift */, - B526257325C874F9003E73B7 /* ContentView.swift */, - B52625A525C876C3003E73B7 /* MapDetail.swift */, - B523C74A25C9C1BA00C44061 /* DefaultMapView.swift */, - B539518025CB2D7A00959F72 /* MapTextEditor.swift */, - B587BB5F25CDCECB00F328ED /* SlowMapRender.swift */, - B52625AF25C87C14003E73B7 /* MapRender.swift */, B5CF75C825CC19FC003BFF3D /* EvolutionPicker.swift */, + B539518025CB2D7A00959F72 /* MapTextEditor.swift */, + B523C75825C9FD3A00C44061 /* MapRender */, ); - path = Views; + path = "Base Components"; sourceTree = ""; }; - B5CF75CD25CC7953003BFF3D /* MapParser */ = { + B5F8D3052A06DCF3000EEA24 /* Complex Components */ = { isa = PBXGroup; children = ( - B5CF75D625CC79A4003BFF3D /* Strategies */, - B5CF75CE25CC7965003BFF3D /* MapParser.swift */, + B5F8D3062A06DD2A000EEA24 /* MapRender */, ); - path = MapParser; + path = "Complex Components"; sourceTree = ""; }; - B5CF75D625CC79A4003BFF3D /* Strategies */ = { + B5F8D3062A06DD2A000EEA24 /* MapRender */ = { isa = PBXGroup; children = ( - B5CF75D725CC79BC003BFF3D /* VertexParserStrategy.swift */, - B5CF75DC25CC79D7003BFF3D /* EdgeParserStrategy.swift */, - B5CF75E125CC79ED003BFF3D /* BlockerParserStrategy.swift */, - B5CF75E925CC7A13003BFF3D /* OpportunityParserStrategy.swift */, - B5CF75EE25CC7A4A003BFF3D /* StageParserStrategy.swift */, + B52625AF25C87C14003E73B7 /* MapRenderView.swift */, ); - path = Strategies; + path = MapRender; + sourceTree = ""; + }; + B5F8D3092A06DE1A000EEA24 /* Logic */ = { + isa = PBXGroup; + children = ( + B5CF75CD25CC7953003BFF3D /* MapParser */, + B5CF75F625CC97CA003BFF3D /* Debouncer.swift */, + ); + path = Logic; sourceTree = ""; }; /* End PBXGroup section */ @@ -292,6 +359,9 @@ dependencies = ( ); name = Map; + packageProductDependencies = ( + B5F8D30D2A06E5C2000EEA24 /* Patterns */, + ); productName = Map; productReference = B526256E25C874F9003E73B7 /* Map.app */; productType = "com.apple.product-type.application"; @@ -338,8 +408,9 @@ B526256625C874F9003E73B7 /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 1240; - LastUpgradeCheck = 1240; + LastUpgradeCheck = 1430; TargetAttributes = { B526256D25C874F9003E73B7 = { CreatedOnToolsVersion = 12.4; @@ -363,6 +434,9 @@ Base, ); mainGroup = B526256525C874F9003E73B7; + packageReferences = ( + B5F8D30C2A06E5C2000EEA24 /* XCRemoteSwiftPackageReference "patterns" */, + ); productRefGroup = B526256F25C874F9003E73B7 /* Products */; projectDirPath = ""; projectRoot = ""; @@ -405,34 +479,37 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - B52625B025C87C14003E73B7 /* MapRender.swift in Sources */, + 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 */, - B523C77625CA181100C44061 /* MapColor.swift in Sources */, B5CF75DD25CC79D7003BFF3D /* EdgeParserStrategy.swift in Sources */, - B526257425C874F9003E73B7 /* ContentView.swift in Sources */, + B526257425C874F9003E73B7 /* MapEditorWindow.swift in Sources */, B526257E25C874FA003E73B7 /* Map.xcdatamodeld in Sources */, B5CF75C925CC19FC003BFF3D /* EvolutionPicker.swift in Sources */, - B523C74B25C9C1BA00C44061 /* DefaultMapView.swift in Sources */, + B523C74B25C9C1BA00C44061 /* EmptyMapDetailScreen.swift in Sources */, B539516C25CB0C9300959F72 /* Store.swift in Sources */, B526257225C874F9003E73B7 /* MapApp.swift in Sources */, - B52625A625C876C3003E73B7 /* MapDetail.swift in Sources */, + B52625A625C876C3003E73B7 /* MapDetailScreen.swift in Sources */, B523C76225CA05A300C44061 /* MapStages.swift in Sources */, - B587BB6025CDCECB00F328ED /* SlowMapRender.swift in Sources */, B5CF75F725CC97CA003BFF3D /* Debouncer.swift in Sources */, B523C76C25CA0DFA00C44061 /* MapEdges.swift in Sources */, ); @@ -504,6 +581,7 @@ 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; @@ -565,6 +643,7 @@ 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; @@ -593,7 +672,8 @@ CODE_SIGN_ENTITLEMENTS = Map/Map.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 4; + DEAD_CODE_STRIPPING = YES; DEVELOPMENT_ASSET_PATHS = "\"Map/Preview Content\""; DEVELOPMENT_TEAM = S68NHQVJXW; ENABLE_HARDENED_RUNTIME = YES; @@ -603,8 +683,8 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 11; - MARKETING_VERSION = 1.2.0; + MACOSX_DEPLOYMENT_TARGET = 12.0; + MARKETING_VERSION = 2.0.0; PRODUCT_BUNDLE_IDENTIFIER = pizza.unlimited.Map; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -619,7 +699,8 @@ CODE_SIGN_ENTITLEMENTS = Map/Map.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 4; + DEAD_CODE_STRIPPING = YES; DEVELOPMENT_ASSET_PATHS = "\"Map/Preview Content\""; DEVELOPMENT_TEAM = S68NHQVJXW; ENABLE_HARDENED_RUNTIME = YES; @@ -629,8 +710,8 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 11; - MARKETING_VERSION = 1.2.0; + MACOSX_DEPLOYMENT_TARGET = 12.0; + MARKETING_VERSION = 2.0.0; PRODUCT_BUNDLE_IDENTIFIER = pizza.unlimited.Map; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -644,6 +725,7 @@ BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; + DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = S68NHQVJXW; INFOPLIST_FILE = MapTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -666,6 +748,7 @@ BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; + DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = S68NHQVJXW; INFOPLIST_FILE = MapTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -687,6 +770,7 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; + DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = S68NHQVJXW; INFOPLIST_FILE = MapUITests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -707,6 +791,7 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; + DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = S68NHQVJXW; INFOPLIST_FILE = MapUITests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -762,6 +847,25 @@ }; /* End XCConfigurationList section */ +/* Begin XCRemoteSwiftPackageReference section */ + B5F8D30C2A06E5C2000EEA24 /* XCRemoteSwiftPackageReference "patterns" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://git.sr.ht/~rbdr/patterns"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 2.0.0; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + B5F8D30D2A06E5C2000EEA24 /* Patterns */ = { + isa = XCSwiftPackageProductDependency; + package = B5F8D30C2A06E5C2000EEA24 /* XCRemoteSwiftPackageReference "patterns" */; + productName = Patterns; + }; +/* End XCSwiftPackageProductDependency section */ + /* Begin XCVersionGroup section */ B526257C25C874FA003E73B7 /* Map.xcdatamodeld */ = { isa = XCVersionGroup; diff --git a/Map.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Map.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000..9606e6c --- /dev/null +++ b/Map.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,14 @@ +{ + "pins" : [ + { + "identity" : "patterns", + "kind" : "remoteSourceControl", + "location" : "https://git.sr.ht/~rbdr/patterns", + "state" : { + "revision" : "ba4ee0edf2aba19ad73fa53cb01dd0fb9b527526", + "version" : "2.0.0" + } + } + ], + "version" : 2 +} diff --git a/Map/Assets.xcassets/AccentColor.colorset/Contents.json b/Map/Assets.xcassets/AccentColor.colorset/Contents.json index c981db7..b90aa6c 100644 --- a/Map/Assets.xcassets/AccentColor.colorset/Contents.json +++ b/Map/Assets.xcassets/AccentColor.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "0.969", - "green" : "0.871", - "red" : "1.000" + "blue" : "0xF0", + "green" : "0xB3", + "red" : "0xFF" } }, "idiom" : "universal" diff --git a/Map/Assets.xcassets/AppIcon.appiconset/icon_128x128.png b/Map/Assets.xcassets/AppIcon.appiconset/icon_128x128.png index b4618d4..b5ff983 100644 Binary files a/Map/Assets.xcassets/AppIcon.appiconset/icon_128x128.png and b/Map/Assets.xcassets/AppIcon.appiconset/icon_128x128.png differ diff --git a/Map/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png b/Map/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png index dfdf396..109328a 100644 Binary files a/Map/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png and b/Map/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png differ diff --git a/Map/Assets.xcassets/AppIcon.appiconset/icon_16x16.png b/Map/Assets.xcassets/AppIcon.appiconset/icon_16x16.png index fb22da2..31acec7 100644 Binary files a/Map/Assets.xcassets/AppIcon.appiconset/icon_16x16.png and b/Map/Assets.xcassets/AppIcon.appiconset/icon_16x16.png differ diff --git a/Map/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png b/Map/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png index a2ea184..d9a0db3 100644 Binary files a/Map/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png and b/Map/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png differ diff --git a/Map/Assets.xcassets/AppIcon.appiconset/icon_256x256.png b/Map/Assets.xcassets/AppIcon.appiconset/icon_256x256.png index cbe1cfc..b6a0286 100644 Binary files a/Map/Assets.xcassets/AppIcon.appiconset/icon_256x256.png and b/Map/Assets.xcassets/AppIcon.appiconset/icon_256x256.png differ diff --git a/Map/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png b/Map/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png index 64bc6b5..d674c53 100644 Binary files a/Map/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png and b/Map/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png differ diff --git a/Map/Assets.xcassets/AppIcon.appiconset/icon_32x32.png b/Map/Assets.xcassets/AppIcon.appiconset/icon_32x32.png index a2ea184..d9a0db3 100644 Binary files a/Map/Assets.xcassets/AppIcon.appiconset/icon_32x32.png and b/Map/Assets.xcassets/AppIcon.appiconset/icon_32x32.png differ diff --git a/Map/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png b/Map/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png index 5663b5e..650d9ff 100644 Binary files a/Map/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png and b/Map/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png differ diff --git a/Map/Assets.xcassets/AppIcon.appiconset/icon_512x512.png b/Map/Assets.xcassets/AppIcon.appiconset/icon_512x512.png index 64bc6b5..d674c53 100644 Binary files a/Map/Assets.xcassets/AppIcon.appiconset/icon_512x512.png and b/Map/Assets.xcassets/AppIcon.appiconset/icon_512x512.png differ diff --git a/Map/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png b/Map/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png index bfa4365..5b5cdd6 100644 Binary files a/Map/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png and b/Map/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png differ diff --git a/Map/Assets.xcassets/Colors/Background.colorset/Contents.json b/Map/Assets.xcassets/Colors/Background.colorset/Contents.json new file mode 100644 index 0000000..d55bcdc --- /dev/null +++ b/Map/Assets.xcassets/Colors/Background.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x1F", + "green" : "0x26", + "red" : "0x0F" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Map/Assets.xcassets/Colors/Contents.json b/Map/Assets.xcassets/Colors/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/Map/Assets.xcassets/Colors/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Map/Assets.xcassets/Colors/Foreground.colorset/Contents.json b/Map/Assets.xcassets/Colors/Foreground.colorset/Contents.json new file mode 100644 index 0000000..6a9d7a1 --- /dev/null +++ b/Map/Assets.xcassets/Colors/Foreground.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x1F", + "green" : "0x26", + "red" : "0x0F" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Map/Assets.xcassets/Colors/Syntax/Contents.json b/Map/Assets.xcassets/Colors/Syntax/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/Map/Assets.xcassets/Colors/Syntax/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Map/Assets.xcassets/Colors/Syntax/Number.colorset/Contents.json b/Map/Assets.xcassets/Colors/Syntax/Number.colorset/Contents.json new file mode 100644 index 0000000..890992f --- /dev/null +++ b/Map/Assets.xcassets/Colors/Syntax/Number.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.902", + "green" : "0.561", + "red" : "0.310" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Map/Assets.xcassets/Colors/Syntax/Option.colorset/Contents.json b/Map/Assets.xcassets/Colors/Syntax/Option.colorset/Contents.json new file mode 100644 index 0000000..bad8227 --- /dev/null +++ b/Map/Assets.xcassets/Colors/Syntax/Option.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x00", + "green" : "0x2B", + "red" : "0xFA" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Map/Assets.xcassets/Colors/Syntax/Symbol.colorset/Contents.json b/Map/Assets.xcassets/Colors/Syntax/Symbol.colorset/Contents.json new file mode 100644 index 0000000..8bea0d3 --- /dev/null +++ b/Map/Assets.xcassets/Colors/Syntax/Symbol.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xA2", + "green" : "0xA6", + "red" : "0x90" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Map/Assets.xcassets/Colors/Syntax/Vertex.colorset/Contents.json b/Map/Assets.xcassets/Colors/Syntax/Vertex.colorset/Contents.json new file mode 100644 index 0000000..2aa2733 --- /dev/null +++ b/Map/Assets.xcassets/Colors/Syntax/Vertex.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.474", + "green" : "0.671", + "red" : "0.180" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xCC", + "green" : "0xFF", + "red" : "0x80" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Map/Assets.xcassets/Colors/Theme/Contents.json b/Map/Assets.xcassets/Colors/Theme/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/Map/Assets.xcassets/Colors/Theme/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Map/Assets.xcassets/Colors/Theme/Dark Neutral Gray.colorset/Contents.json b/Map/Assets.xcassets/Colors/Theme/Dark Neutral Gray.colorset/Contents.json new file mode 100644 index 0000000..8bea0d3 --- /dev/null +++ b/Map/Assets.xcassets/Colors/Theme/Dark Neutral Gray.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xA2", + "green" : "0xA6", + "red" : "0x90" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Map/Assets.xcassets/Colors/Theme/Dark Slate.colorset/Contents.json b/Map/Assets.xcassets/Colors/Theme/Dark Slate.colorset/Contents.json new file mode 100644 index 0000000..1d36938 --- /dev/null +++ b/Map/Assets.xcassets/Colors/Theme/Dark Slate.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x1F", + "green" : "0x26", + "red" : "0x0F" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Map/Assets.xcassets/Colors/Theme/Jasper Red.colorset/Contents.json b/Map/Assets.xcassets/Colors/Theme/Jasper Red.colorset/Contents.json new file mode 100644 index 0000000..bad8227 --- /dev/null +++ b/Map/Assets.xcassets/Colors/Theme/Jasper Red.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x00", + "green" : "0x2B", + "red" : "0xFA" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Map/Assets.xcassets/Colors/Theme/Light Neutral Gray.colorset/Contents.json b/Map/Assets.xcassets/Colors/Theme/Light Neutral Gray.colorset/Contents.json new file mode 100644 index 0000000..f6a9b18 --- /dev/null +++ b/Map/Assets.xcassets/Colors/Theme/Light Neutral Gray.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xE3", + "green" : "0xE6", + "red" : "0xDA" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Map/Assets.xcassets/Colors/Theme/Neutral Gray.colorset/Contents.json b/Map/Assets.xcassets/Colors/Theme/Neutral Gray.colorset/Contents.json new file mode 100644 index 0000000..2e346d1 --- /dev/null +++ b/Map/Assets.xcassets/Colors/Theme/Neutral Gray.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xCC", + "green" : "0xD1", + "red" : "0xB5" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Map/Assets.xcassets/Colors/Theme/Olympic Blue.colorset/Contents.json b/Map/Assets.xcassets/Colors/Theme/Olympic Blue.colorset/Contents.json new file mode 100644 index 0000000..9e62414 --- /dev/null +++ b/Map/Assets.xcassets/Colors/Theme/Olympic Blue.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xE6", + "green" : "0x8F", + "red" : "0x4F" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Map/Core Extensions/Color+Theme.swift b/Map/Core Extensions/Color+Theme.swift new file mode 100644 index 0000000..ffbd224 --- /dev/null +++ b/Map/Core Extensions/Color+Theme.swift @@ -0,0 +1,27 @@ +import SwiftUI + +extension Color { + struct theme { + static let darkSlate = Color("Dark Slate") + static let jasperRed = Color("Jasper Red") + static let olympicBlue = Color("Olympic Blue") + static let neutralGray = Color("Neutral Gray") + static let lightNeutralGray = Color("Light Neutral Gray") + static let darkNeutralGray = Color("Dark Neutral Gray") + } + + struct map { + static let labelColor = Color.theme.darkSlate + static let axisColor = Color.theme.darkSlate + static let vertexColor = Color.theme.darkSlate + static let blockerColor = Color.theme.jasperRed + static let opportunityColor = Color.theme.olympicBlue + static let stageForeground = Color.theme.lightNeutralGray + static let stageBackground = Color.white + } + + struct ui { + static let foreground = Color("Foreground") + static let background = Color("Background") + } +} diff --git a/Map/Extensions/Date+format.swift b/Map/Core Extensions/Date+format.swift similarity index 100% rename from Map/Extensions/Date+format.swift rename to Map/Core Extensions/Date+format.swift diff --git a/Map/Core Extensions/Font+Theme.swift b/Map/Core Extensions/Font+Theme.swift new file mode 100644 index 0000000..30bc6f9 --- /dev/null +++ b/Map/Core Extensions/Font+Theme.swift @@ -0,0 +1,8 @@ +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) + } +} diff --git a/Map/Core Extensions/NSColor+Theme.swift b/Map/Core Extensions/NSColor+Theme.swift new file mode 100644 index 0000000..0ef1094 --- /dev/null +++ b/Map/Core Extensions/NSColor+Theme.swift @@ -0,0 +1,10 @@ +import AppKit + +extension NSColor { + struct syntax { + static let vertex = NSColor(named: "Vertex") ?? .textColor + static let number = NSColor(named: "Number") ?? .textColor + static let option = NSColor(named: "Option") ?? .textColor + static let symbol = NSColor(named: "Symbol") ?? .textColor + } +} diff --git a/Map/Extensions/NSImage+writePNG.swift b/Map/Core Extensions/NSImage+writePNG.swift similarity index 100% rename from Map/Extensions/NSImage+writePNG.swift rename to Map/Core Extensions/NSImage+writePNG.swift diff --git a/Map/State/AppState.swift b/Map/Data/AppState.swift similarity index 94% rename from Map/State/AppState.swift rename to Map/Data/AppState.swift index c261725..d0d5670 100644 --- a/Map/State/AppState.swift +++ b/Map/Data/AppState.swift @@ -39,7 +39,7 @@ func appStateReducer(state: inout AppState, action: AppAction) { let renderView = MapRenderView( content: Binding.constant(map.content ?? ""), - evolution: Binding.constant(Stage.stages(state.selectedEvolution))) + evolution: Binding.constant(state.selectedEvolution)) let view = NSHostingView(rootView: renderView) window.contentView = view @@ -54,7 +54,7 @@ func appStateReducer(state: inout AppState, action: AppAction) { dialog.showsResizeIndicator = false dialog.canCreateDirectories = true dialog.showsHiddenFiles = false - dialog.allowedFileTypes = ["png"] + dialog.allowedContentTypes = [.png] dialog.nameFieldStringValue = map.title ?? "Untitled Map" if dialog.runModal() == NSApplication.ModalResponse.OK { @@ -77,7 +77,7 @@ func appStateReducer(state: inout AppState, action: AppAction) { dialog.showsResizeIndicator = false dialog.canCreateDirectories = true dialog.showsHiddenFiles = false - dialog.allowedFileTypes = ["txt"] + dialog.allowedContentTypes = [.text] dialog.nameFieldStringValue = map.title ?? "Untitled Map" if let content = map.content { diff --git a/Map/Extensions/Map+parse.swift b/Map/Data/Models/Map+parse.swift similarity index 94% rename from Map/Extensions/Map+parse.swift rename to Map/Data/Models/Map+parse.swift index 904f492..5181daf 100644 --- a/Map/Extensions/Map+parse.swift +++ b/Map/Data/Models/Map+parse.swift @@ -2,6 +2,7 @@ extension Map { static func parse(content: String) -> ParsedMap { let parsers = [ + AnyMapParserStrategy(NoteParserStrategy()), AnyMapParserStrategy(VertexParserStrategy()), AnyMapParserStrategy(EdgeParserStrategy()), AnyMapParserStrategy(BlockerParserStrategy()), diff --git a/Map/State/Persistence.swift b/Map/Data/Persistence.swift similarity index 100% rename from Map/State/Persistence.swift rename to Map/Data/Persistence.swift diff --git a/Map/State/Stage.swift b/Map/Data/Stage.swift similarity index 100% rename from Map/State/Stage.swift rename to Map/Data/Stage.swift diff --git a/Map/State/Store.swift b/Map/Data/Store.swift similarity index 100% rename from Map/State/Store.swift rename to Map/Data/Store.swift diff --git a/Map/Debouncer.swift b/Map/Logic/Debouncer.swift similarity index 100% rename from Map/Debouncer.swift rename to Map/Logic/Debouncer.swift diff --git a/Map/MapParser/MapParser.swift b/Map/Logic/MapParser/MapParser.swift similarity index 80% rename from Map/MapParser/MapParser.swift rename to Map/Logic/MapParser/MapParser.swift index cce6251..5f78d5d 100644 --- a/Map/MapParser/MapParser.swift +++ b/Map/Logic/MapParser/MapParser.swift @@ -6,14 +6,17 @@ import Foundation struct MapParsingPatterns { static let vertex = try! NSRegularExpression( pattern: - "([^\\(]+?)[\\s]*\\([\\s]*([0-9]+.?[0-9]*)[\\s]*,[\\s]*([0-9]+.?[0-9]*)[\\s]*\\)[\\s]*(?:\\[(.*?)\\])?", + "([^\\(\\[\\]]*?)[\\s]*\\([\\s]*([0-9]+.?[0-9]*)[\\s]*,[\\s]*([0-9]+.?[0-9]*)[\\s]*\\)[\\s]*(?:\\[(.*?)\\])?", options: .caseInsensitive) static let edge = try! NSRegularExpression( pattern: "(.+?)[\\s]*-([->])[\\s]*(.+)", options: .caseInsensitive) static let blocker = try! NSRegularExpression( pattern: "\\[(Blocker)\\][\\s]*(.+)", options: .caseInsensitive) static let opportunity = try! NSRegularExpression( - pattern: "\\[(Opportunity)\\][\\s]*(.+)[\\s]+([-+])[\\s]*([0-9]+.?[0-9]*)", + pattern: "\\[(Evolution)\\][\\s]*(.+)[\\s]+([-+])[\\s]*([0-9]+.?[0-9]*)", + options: .caseInsensitive) + static let note = try! NSRegularExpression( + pattern: "\\[(Note)\\][\\s]*\\([\\s]*([0-9]+.?[0-9]*)[\\s]*,[\\s]*([0-9]+.?[0-9]*)[\\s]*\\)[\\s]*(.*)", options: .caseInsensitive) static let stage = try! NSRegularExpression( pattern: "\\[(I{1,3})\\][\\s]*([0-9]+.?[0-9]*)", options: .caseInsensitive) @@ -24,10 +27,11 @@ struct ParsedMap { let edges: [MapEdge] let blockers: [Blocker] let opportunities: [Opportunity] + let notes: [Note] let stages: [CGFloat] static let empty: ParsedMap = ParsedMap( - vertices: [], edges: [], blockers: [], opportunities: [], stages: defaultDimensions) + vertices: [], edges: [], blockers: [], opportunities: [], notes: [], stages: defaultDimensions) } struct Vertex { @@ -37,6 +41,12 @@ struct Vertex { var shape: VertexShape = .circle } +struct Note { + let id: Int + let position: CGPoint + let text: String +} + enum VertexShape: String { case circle case square @@ -103,6 +113,7 @@ class MapBuilder { private var edges: [MapEdge] = [] private var blockers: [Blocker] = [] private var opportunities: [Opportunity] = [] + private var notes: [Note] = [] private var stages: [CGFloat] = defaultDimensions func addObjectToMap(type: Any.Type, object: Any) { @@ -125,18 +136,22 @@ class MapBuilder { let opportunity = object as! Opportunity opportunities.append(opportunity) } + + if type == Note.self { + let note = object as! Note + notes.append(note) + } if type == StageDimensions.self { let stageDimensions = object as! StageDimensions stages[stageDimensions.index] = stageDimensions.dimensions - } } func build() -> ParsedMap { let mappedVertices = vertices.map { label, vertex in return vertex } return ParsedMap( - vertices: mappedVertices, edges: edges, blockers: blockers, opportunities: opportunities, + vertices: mappedVertices, edges: edges, blockers: blockers, opportunities: opportunities, notes: notes, stages: stages) } } diff --git a/Map/MapParser/Strategies/BlockerParserStrategy.swift b/Map/Logic/MapParser/Strategies/BlockerParserStrategy.swift similarity index 100% rename from Map/MapParser/Strategies/BlockerParserStrategy.swift rename to Map/Logic/MapParser/Strategies/BlockerParserStrategy.swift diff --git a/Map/MapParser/Strategies/EdgeParserStrategy.swift b/Map/Logic/MapParser/Strategies/EdgeParserStrategy.swift similarity index 100% rename from Map/MapParser/Strategies/EdgeParserStrategy.swift rename to Map/Logic/MapParser/Strategies/EdgeParserStrategy.swift diff --git a/Map/Logic/MapParser/Strategies/NoteParserStrategy.swift b/Map/Logic/MapParser/Strategies/NoteParserStrategy.swift new file mode 100644 index 0000000..4dae4c7 --- /dev/null +++ b/Map/Logic/MapParser/Strategies/NoteParserStrategy.swift @@ -0,0 +1,31 @@ +import Foundation + +struct NoteParserStrategy: MapParserStrategy { + private let regex = MapParsingPatterns.note + + 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 == 5 + } + + 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] + let text = String(line[Range(match.range(at: 4), in: line)!]) + let xString = String(line[Range(match.range(at: 2), in: line)!]) + let yString = String(line[Range(match.range(at: 3), in: line)!]) + let x = CGFloat(truncating: NumberFormatter().number(from: xString) ?? 0.0) + let y = CGFloat(truncating: NumberFormatter().number(from: yString) ?? 0.0) + + let note = Note( + id: index, + position: CGPoint(x: x, y: y), + text: text + ) + + return (Note.self, note) + } +} diff --git a/Map/MapParser/Strategies/OpportunityParserStrategy.swift b/Map/Logic/MapParser/Strategies/OpportunityParserStrategy.swift similarity index 100% rename from Map/MapParser/Strategies/OpportunityParserStrategy.swift rename to Map/Logic/MapParser/Strategies/OpportunityParserStrategy.swift diff --git a/Map/MapParser/Strategies/StageParserStrategy.swift b/Map/Logic/MapParser/Strategies/StageParserStrategy.swift similarity index 100% rename from Map/MapParser/Strategies/StageParserStrategy.swift rename to Map/Logic/MapParser/Strategies/StageParserStrategy.swift diff --git a/Map/MapParser/Strategies/VertexParserStrategy.swift b/Map/Logic/MapParser/Strategies/VertexParserStrategy.swift similarity index 100% rename from Map/MapParser/Strategies/VertexParserStrategy.swift rename to Map/Logic/MapParser/Strategies/VertexParserStrategy.swift diff --git a/Map/Views/MapApp.swift b/Map/MapApp.swift similarity index 95% rename from Map/Views/MapApp.swift rename to Map/MapApp.swift index a0e2d60..14e5605 100644 --- a/Map/Views/MapApp.swift +++ b/Map/MapApp.swift @@ -13,7 +13,7 @@ struct MapApp: App { var body: some Scene { WindowGroup { - ContentView() + MapEditorWindow() .environment(\.managedObjectContext, persistenceController.container.viewContext) .environmentObject(AppStore(initialState: AppState(), reducer: appStateReducer)) }.windowStyle(HiddenTitleBarWindowStyle()).commands { diff --git a/Map/MapColor.swift b/Map/MapColor.swift deleted file mode 100644 index 98dd804..0000000 --- a/Map/MapColor.swift +++ /dev/null @@ -1,65 +0,0 @@ -import SwiftUI - -struct MapColor { - let foreground: Color - let background: Color - let secondary: Color - let blocker: Color - let opportunity: Color - let stages: StageColor - let syntax: SyntaxColor - - static func colorForScheme(_ colorScheme: ColorScheme) -> MapColor { - if colorScheme == .dark { - return MapColor( - foreground: Color.white, - background: Color(.sRGB, red: 0.13, green: 0.13, blue: 0.13), - secondary: Color(.sRGB, red: 0.81, green: 0.78, blue: 0.79), - blocker: Color(.sRGB, red: 0.13, green: 0.13, blue: 0.13), - opportunity: Color(.sRGB, red: 1.0, green: 0.37, blue: 0.34), - stages: StageColor( - i: Color(.sRGB, red: 0.37, green: 0.16, blue: 0.25), - ii: Color(.sRGB, red: 0.30, green: 0.29, blue: 0.26), - iii: Color(.sRGB, red: 0.15, green: 0.29, blue: 0.23), - iv: Color(.sRGB, red: 0.14, green: 0.22, blue: 0.31)), - syntax: SyntaxColor( - vertex: NSColor(srgbRed: 0.41, green: 0.84, blue: 0.96, alpha: 1.0), - number: NSColor(srgbRed: 0.85, green: 0.78, blue: 0.49, alpha: 1.0), - option: NSColor(srgbRed: 1.0, green: 0.48, blue: 0.7, alpha: 1.0), // #FE7AB3 - symbol: NSColor(srgbRed: 0.85, green: 0.73, blue: 1.0, alpha: 1.0) // #DABBFF - )) - } else { - return MapColor( - foreground: Color(.sRGB, red: 0.13, green: 0.13, blue: 0.13), - background: Color.white, - secondary: Color.gray, - blocker: Color(.sRGB, red: 0.60, green: 0.52, blue: 0.51), - opportunity: Color(.sRGB, red: 1.0, green: 0.37, blue: 0.34), - stages: StageColor( - i: Color(.sRGB, red: 1.00, green: 0.93, blue: 0.97), - ii: Color(.sRGB, red: 1.00, green: 0.98, blue: 0.92), - iii: Color(.sRGB, red: 0.93, green: 1.00, blue: 0.97), - iv: Color(.sRGB, red: 0.93, green: 0.96, blue: 1.00)), - syntax: SyntaxColor( - vertex: NSColor(srgbRed: 0.11, green: 0.42, blue: 0.57, alpha: 1.0), - number: NSColor(srgbRed: 0.27, green: 0.31, blue: 0.87, alpha: 1.0), - option: NSColor(srgbRed: 0.68, green: 0.24, blue: 0.64, alpha: 1.0), - symbol: NSColor(srgbRed: 0.29, green: 0.13, blue: 0.69, alpha: 1.0) - )) - } - } -} - -struct StageColor { - let i: Color - let ii: Color - let iii: Color - let iv: Color -} - -struct SyntaxColor { - let vertex: NSColor - let number: NSColor - let option: NSColor - let symbol: NSColor -} diff --git a/Map/MapRenderComponents/MapStages.swift b/Map/MapRenderComponents/MapStages.swift deleted file mode 100644 index 052a315..0000000 --- a/Map/MapRenderComponents/MapStages.swift +++ /dev/null @@ -1,60 +0,0 @@ -import SwiftUI - -struct MapStages: View { - - @Environment(\.colorScheme) var colorScheme - - let mapSize: CGSize - let lineWidth: CGFloat - let stages: [CGFloat] - let opacity = 0.1 - - var color: MapColor { - MapColor.colorForScheme(colorScheme) - } - - var body: some View { - - ZStack(alignment: .topLeading) { - Path { path in - path.addRect(CGRect(x: 0, y: 0, width: w(stages[0]), height: mapSize.height)) - }.fill(color.stages.i) - Path { path in - path.addRect( - CGRect(x: w(stages[0]), y: 0, width: w(stages[1]) - w(stages[0]), height: mapSize.height)) - }.fill(color.stages.ii) - Path { path in - path.addRect( - CGRect(x: w(stages[1]), y: 0, width: w(stages[2]) - w(stages[1]), height: mapSize.height)) - }.fill(color.stages.iii) - Path { path in - path.addRect( - CGRect(x: w(stages[2]), y: 0, width: mapSize.width - w(stages[2]), height: mapSize.height) - ) - }.fill(color.stages.iv) - - Path { path in - path.move(to: CGPoint(x: w(stages[0]), y: 0)) - path.addLine(to: CGPoint(x: w(stages[0]), y: mapSize.height)) - path.move(to: CGPoint(x: w(stages[1]), y: 0)) - path.addLine(to: CGPoint(x: w(stages[1]), y: mapSize.height)) - path.move(to: CGPoint(x: w(stages[2]), y: 0)) - path.addLine(to: CGPoint(x: w(stages[2]), y: mapSize.height)) - path.move(to: CGPoint(x: w(stages[0]), y: 0)) - path.closeSubpath() - }.strokedPath(StrokeStyle(lineWidth: lineWidth, dash: [10.0])).stroke(color.foreground) - } - } - - func w(_ dimension: CGFloat) -> CGFloat { - max(0.0, min(mapSize.width, dimension * mapSize.width / 100.0)) - } -} - -struct MapStages_Previews: PreviewProvider { - static var previews: some View { - MapStages( - mapSize: CGSize(width: 200.0, height: 200.0), lineWidth: CGFloat(1.0), - stages: [25.0, 50.0, 75.0]) - } -} diff --git a/Map/Views/EvolutionPicker.swift b/Map/Presentation/Base Components/EvolutionPicker.swift similarity index 92% rename from Map/Views/EvolutionPicker.swift rename to Map/Presentation/Base Components/EvolutionPicker.swift index 815f575..c68e90c 100644 --- a/Map/Views/EvolutionPicker.swift +++ b/Map/Presentation/Base Components/EvolutionPicker.swift @@ -1,10 +1,3 @@ -// -// EvolutionPicker.swift -// Map -// -// Created by Ruben Beltran del Rio on 2/4/21. -// - import SwiftUI struct EvolutionPicker: View { diff --git a/Map/MapRenderComponents/MapAxes.swift b/Map/Presentation/Base Components/MapRender/MapAxes.swift similarity index 72% rename from Map/MapRenderComponents/MapAxes.swift rename to Map/Presentation/Base Components/MapRender/MapAxes.swift index a6e2f87..6ba758f 100644 --- a/Map/MapRenderComponents/MapAxes.swift +++ b/Map/Presentation/Base Components/MapRender/MapAxes.swift @@ -2,8 +2,6 @@ import SwiftUI struct MapAxes: View { - @Environment(\.colorScheme) var colorScheme - let mapSize: CGSize let lineWidth: CGFloat let evolution: Stage @@ -11,10 +9,6 @@ struct MapAxes: View { let stageHeight = CGFloat(100.0) let padding = CGFloat(5.0) - var color: Color { - MapColor.colorForScheme(colorScheme).foreground - } - var body: some View { ZStack(alignment: .topLeading) { @@ -25,50 +19,48 @@ struct MapAxes: View { path.addLine(to: CGPoint(x: mapSize.width, y: mapSize.height)) path.move(to: CGPoint(x: mapSize.width, y: mapSize.height)) path.closeSubpath() - }.stroke(color, lineWidth: lineWidth * 2) + }.stroke(Color.map.axisColor, lineWidth: lineWidth * 2) // Y Labels - Text("Visible").font(.title3).foregroundColor(color).rotationEffect(Angle(degrees: -90.0)) + Text("Visible").font(.theme.axisLabel).foregroundColor(.map.labelColor).rotationEffect(Angle(degrees: -90.0)) .offset(CGSize(width: -35.0, height: 0.0)) - Text("Value Chain").font(.title).foregroundColor(color).rotationEffect(Angle(degrees: -90.0)) - .offset(CGSize(width: -72.0, height: mapSize.height / 2 - 20)) - Text("Invisible").font(.title3).foregroundColor(color).rotationEffect(Angle(degrees: -90.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 Text("Uncharted") - .font(.title3) - .foregroundColor(color) + .font(.theme.axisLabel) + .foregroundColor(.map.labelColor) .frame(width: mapSize.width / 4, height: stageHeight / 2.0, alignment: .topLeading) .offset(CGSize(width: 0.0, height: -stageHeight / 4.0)) Text("Industrialised") - .font(.title3) - .foregroundColor(color) + .font(.theme.axisLabel) + .foregroundColor(.map.labelColor) .frame(width: mapSize.width / 4, height: stageHeight / 2.0, alignment: .topLeading) .offset(CGSize(width: mapSize.width - 100.0, height: -stageHeight / 4.0)) Text(evolution.i) - .font(.title3) - .foregroundColor(color) + .font(.theme.axisLabel) + .foregroundColor(.map.labelColor) .frame(width: w(stages[0]), height: stageHeight, alignment: .topLeading) .offset(CGSize(width: 0.0, height: mapSize.height + padding)) Text(evolution.ii) - .font(.title3) - .foregroundColor(color) + .font(.theme.axisLabel) + .foregroundColor(.map.labelColor) .frame(width: w(stages[1]) - w(stages[0]), height: stageHeight, alignment: .topLeading) .offset(CGSize(width: w(stages[0]), height: mapSize.height + padding)) Text(evolution.iii) - .font(.title3) - .foregroundColor(color) + .font(.theme.axisLabel) + .foregroundColor(.map.labelColor) .frame(width: w(stages[2]) - w(stages[1]), height: stageHeight, alignment: .topLeading) .offset(CGSize(width: w(stages[1]), height: mapSize.height + padding)) Text(evolution.iv) - .font(.title3) - .foregroundColor(color) + .font(.theme.axisLabel) + .foregroundColor(.map.labelColor) .frame(width: mapSize.width - w(stages[2]), height: stageHeight, alignment: .topLeading) .offset(CGSize(width: w(stages[2]), height: mapSize.height + padding)) } diff --git a/Map/MapRenderComponents/MapBlockers.swift b/Map/Presentation/Base Components/MapRender/MapBlockers.swift similarity index 89% rename from Map/MapRenderComponents/MapBlockers.swift rename to Map/Presentation/Base Components/MapRender/MapBlockers.swift index b668b30..d943ba8 100644 --- a/Map/MapRenderComponents/MapBlockers.swift +++ b/Map/Presentation/Base Components/MapRender/MapBlockers.swift @@ -2,16 +2,10 @@ import SwiftUI struct MapBlockers: View { - @Environment(\.colorScheme) var colorScheme - let mapSize: CGSize let vertexSize: CGSize let blockers: [Blocker] - var color: Color { - MapColor.colorForScheme(colorScheme).blocker - } - let cornerSize = CGSize(width: 2.0, height: 2.0) var body: some View { @@ -24,7 +18,7 @@ struct MapBlockers: View { y: h(vertex.position.y) - vertexSize.height * 2 / 3), size: CGSize(width: vertexSize.width / 2, height: vertexSize.height * 2) ), cornerSize: cornerSize) - }.fill(color) + }.fill(Color.map.blockerColor) } } diff --git a/Map/MapRenderComponents/MapEdges.swift b/Map/Presentation/Base Components/MapRender/MapEdges.swift similarity index 91% rename from Map/MapRenderComponents/MapEdges.swift rename to Map/Presentation/Base Components/MapRender/MapEdges.swift index d40d2aa..3814495 100644 --- a/Map/MapRenderComponents/MapEdges.swift +++ b/Map/Presentation/Base Components/MapRender/MapEdges.swift @@ -1,16 +1,7 @@ -// -// MapEdges.swift -// Map -// -// Created by Ruben Beltran del Rio on 2/2/21. -// - import SwiftUI struct MapEdges: View { - @Environment(\.colorScheme) var colorScheme - let mapSize: CGSize let lineWidth: CGFloat let vertexSize: CGSize @@ -18,10 +9,6 @@ struct MapEdges: View { let arrowheadSize = CGFloat(10.0) - var color: Color { - MapColor.colorForScheme(colorScheme).foreground - } - var body: some View { ForEach(edges, id: \.id) { edge in Path { path in @@ -65,7 +52,7 @@ struct MapEdges: View { path.closeSubpath() }.applying( CGAffineTransform(translationX: vertexSize.width / 2.0, y: vertexSize.height / 2.0) - ).stroke(color, lineWidth: lineWidth) + ).stroke(Color.map.vertexColor, lineWidth: lineWidth) } } diff --git a/Map/Presentation/Base Components/MapRender/MapNotes.swift b/Map/Presentation/Base Components/MapRender/MapNotes.swift new file mode 100644 index 0000000..f35b3fe --- /dev/null +++ b/Map/Presentation/Base Components/MapRender/MapNotes.swift @@ -0,0 +1,46 @@ +import SwiftUI + +struct MapNotes: View { + + 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) + .padding(2.0) + .background(.white) + .foregroundColor(.map.labelColor) + .border(Color.map.vertexColor, width: lineWidth) + .frame(minWidth: 16.0, maxWidth: maxWidth, alignment: .topLeading) + .offset( + CGSize( + width: w(note.position.x), + height: h(note.position.y) + ) + ) + } + } + + 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)) + } +} + +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"), + ]) + } +} diff --git a/Map/MapRenderComponents/MapOpportunities.swift b/Map/Presentation/Base Components/MapRender/MapOpportunities.swift similarity index 88% rename from Map/MapRenderComponents/MapOpportunities.swift rename to Map/Presentation/Base Components/MapRender/MapOpportunities.swift index 68d3fb5..7fcadff 100644 --- a/Map/MapRenderComponents/MapOpportunities.swift +++ b/Map/Presentation/Base Components/MapRender/MapOpportunities.swift @@ -1,16 +1,7 @@ -// -// MapEdges.swift -// Map -// -// Created by Ruben Beltran del Rio on 2/2/21. -// - import SwiftUI struct MapOpportunities: View { - @Environment(\.colorScheme) var colorScheme - let mapSize: CGSize let lineWidth: CGFloat let vertexSize: CGSize @@ -18,10 +9,6 @@ struct MapOpportunities: View { let arrowheadSize = CGFloat(10.0) - var color: Color { - MapColor.colorForScheme(colorScheme).opportunity - } - var body: some View { ForEach(opportunities, id: \.id) { edge in Path { path in @@ -59,7 +46,7 @@ struct MapOpportunities: View { path.closeSubpath() }.applying( CGAffineTransform(translationX: vertexSize.width / 2.0, y: vertexSize.height / 2.0) - ).strokedPath(StrokeStyle(lineWidth: lineWidth * 2, dash: [10.0])).stroke(color) + ).strokedPath(StrokeStyle(lineWidth: lineWidth / 4, dash: [10.0])).stroke(Color.map.opportunityColor) } } diff --git a/Map/Presentation/Base Components/MapRender/MapStages.swift b/Map/Presentation/Base Components/MapRender/MapStages.swift new file mode 100644 index 0000000..0fc8f48 --- /dev/null +++ b/Map/Presentation/Base Components/MapRender/MapStages.swift @@ -0,0 +1,52 @@ +import SwiftUI +import Patterns + +struct MapStages: View { + + let mapSize: CGSize + let lineWidth: CGFloat + let stages: [CGFloat] + let opacity = 0.1 + + 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) + + Path { path in + path.move(to: CGPoint(x: w(stages[0]), y: 0)) + path.addLine(to: CGPoint(x: w(stages[0]), y: mapSize.height)) + path.closeSubpath() + path.move(to: CGPoint(x: w(stages[1]), y: 0)) + path.addLine(to: CGPoint(x: w(stages[1]), y: mapSize.height)) + path.closeSubpath() + path.move(to: CGPoint(x: w(stages[2]), y: 0)) + path.addLine(to: CGPoint(x: w(stages[2]), y: mapSize.height)) + 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) + } + } + + func w(_ dimension: CGFloat) -> CGFloat { + max(0.0, min(mapSize.width, dimension * mapSize.width / 100.0)) + } +} + +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]) + } +} diff --git a/Map/MapRenderComponents/MapVertices.swift b/Map/Presentation/Base Components/MapRender/MapVertices.swift similarity index 64% rename from Map/MapRenderComponents/MapVertices.swift rename to Map/Presentation/Base Components/MapRender/MapVertices.swift index 24d49b8..74cac6d 100644 --- a/Map/MapRenderComponents/MapVertices.swift +++ b/Map/Presentation/Base Components/MapRender/MapVertices.swift @@ -2,24 +2,24 @@ import SwiftUI struct MapVertices: View { - @Environment(\.colorScheme) var colorScheme - let mapSize: CGSize let vertexSize: CGSize let vertices: [Vertex] - let padding = CGFloat(4.0) - - var color: MapColor { - MapColor.colorForScheme(colorScheme) - } + let padding = CGFloat(5.0) var body: some View { - ForEach(vertices, id: \.id) { vertex in - getVertexShape(vertex).fill(color.foreground) - Text(vertex.label).foregroundColor(color.secondary).offset( - CGSize( - width: w(vertex.position.x) + vertexSize.width + padding, - height: h(vertex.position.y))) + 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) + .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)) + } } } @@ -73,18 +73,20 @@ struct MapVertices: View { path.addLine( to: CGPoint(x: w(vertex.position.x), y: h(vertex.position.y) + vertexSize.height)) path.closeSubpath() - }.strokedPath(StrokeStyle(lineWidth: 5.0, lineCap: .butt)) + }.strokedPath(StrokeStyle(lineWidth: 2.0, lineCap: .butt)) } } } 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", position: CGPoint(x: 50.0, y: 50.0)), - Vertex(id: 0, label: "A", position: CGPoint(x: 10.0, y: 20.0)), - ]) + 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), + ]) } } diff --git a/Map/Views/MapTextEditor.swift b/Map/Presentation/Base Components/MapTextEditor.swift similarity index 55% rename from Map/Views/MapTextEditor.swift rename to Map/Presentation/Base Components/MapTextEditor.swift index 4fbff82..f3838a6 100644 --- a/Map/Views/MapTextEditor.swift +++ b/Map/Presentation/Base Components/MapTextEditor.swift @@ -4,19 +4,20 @@ import SwiftUI class MapTextEditorController: NSViewController { @Binding var text: String - var colorScheme: ColorScheme + let onChange: () -> Void private let vertexRegex = MapParsingPatterns.vertex private let edgeRegex = MapParsingPatterns.edge private let blockerRegex = MapParsingPatterns.blocker private let opportunityRegex = MapParsingPatterns.opportunity + private let noteRegex = MapParsingPatterns.note private let stageRegex = MapParsingPatterns.stage - private let debouncer: Debouncer = Debouncer(seconds: 0.2) + private let changeDebouncer: Debouncer = Debouncer(seconds: 1) - init(text: Binding, colorScheme: ColorScheme) { + init(text: Binding, onChange: @escaping () -> Void) { self._text = text - self.colorScheme = colorScheme + self.onChange = onChange super.init(nibName: nil, bundle: nil) } @@ -42,10 +43,6 @@ class MapTextEditorController: NSViewController { override func viewDidAppear() { self.view.window?.makeFirstResponder(self.view) } - - func updateColorScheme(_ colorScheme: ColorScheme) { - self.colorScheme = colorScheme - } } extension MapTextEditorController: NSTextViewDelegate { @@ -53,6 +50,13 @@ extension MapTextEditorController: NSTextViewDelegate { func textDidChange(_ obj: Notification) { if let textField = obj.object as? NSTextView { self.text = textField.string + + + changeDebouncer.debounce { + DispatchQueue.main.async { + self.onChange() + } + } } } @@ -70,60 +74,64 @@ extension MapTextEditorController: NSTextViewDelegate { } extension MapTextEditorController: NSTextStorageDelegate { + override func textStorageDidProcessEditing(_ obj: Notification) { if let textStorage = obj.object as? NSTextStorage { - debouncer.debounce { - DispatchQueue.main.async { - self.colorizeText(textStorage: textStorage) - } - } + self.colorizeText(textStorage: textStorage) } } private func colorizeText(textStorage: NSTextStorage) { let range = NSMakeRange(0, textStorage.length) var matches = vertexRegex.matches(in: textStorage.string, options: [], range: range) - let colors = MapColor.colorForScheme(colorScheme) for match in matches { - textStorage.addAttributes([.foregroundColor: colors.syntax.vertex], range: match.range(at: 1)) - textStorage.addAttributes([.foregroundColor: colors.syntax.number], range: match.range(at: 2)) - textStorage.addAttributes([.foregroundColor: colors.syntax.number], range: match.range(at: 3)) - textStorage.addAttributes([.foregroundColor: colors.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: colors.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: colors.syntax.symbol], + [.foregroundColor: NSColor.syntax.symbol], range: NSMakeRange(arrowRange.lowerBound - 1, arrowRange.length + 1)) - textStorage.addAttributes([.foregroundColor: colors.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: colors.syntax.option], range: match.range(at: 1)) - textStorage.addAttributes([.foregroundColor: colors.syntax.vertex], range: match.range(at: 2)) - textStorage.addAttributes([.foregroundColor: colors.syntax.symbol], range: match.range(at: 3)) - textStorage.addAttributes([.foregroundColor: colors.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: colors.syntax.option], range: match.range(at: 1)) - textStorage.addAttributes([.foregroundColor: colors.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)) } matches = stageRegex.matches(in: textStorage.string, options: [], range: range) for match in matches { - textStorage.addAttributes([.foregroundColor: colors.syntax.option], range: match.range(at: 1)) - textStorage.addAttributes([.foregroundColor: colors.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)) } } } @@ -131,18 +139,16 @@ extension MapTextEditorController: NSTextStorageDelegate { struct MapTextEditor: NSViewControllerRepresentable { @Binding var text: String - let colorScheme: ColorScheme + var onChange: () -> Void = {} func makeNSViewController( context: NSViewControllerRepresentableContext ) -> MapTextEditorController { - return MapTextEditorController(text: $text, colorScheme: colorScheme) + return MapTextEditorController(text: $text, onChange: onChange) } func updateNSViewController( _ nsViewController: MapTextEditorController, context: NSViewControllerRepresentableContext - ) { - nsViewController.updateColorScheme(context.environment.colorScheme) - } + ) {} } diff --git a/Map/Views/MapRender.swift b/Map/Presentation/Complex Components/MapRender/MapRenderView.swift similarity index 81% rename from Map/Views/MapRender.swift rename to Map/Presentation/Complex Components/MapRender/MapRenderView.swift index aa97e22..b12dabc 100644 --- a/Map/Views/MapRender.swift +++ b/Map/Presentation/Complex Components/MapRender/MapRenderView.swift @@ -1,10 +1,3 @@ -// -// ContentView.swift -// Map -// -// Created by Ruben Beltran del Rio on 2/1/21. -// - import Combine import CoreData import CoreGraphics @@ -12,16 +5,18 @@ import SwiftUI struct MapRenderView: View { - @Environment(\.colorScheme) var colorScheme - @Binding var content: String - @Binding var evolution: Stage + @Binding var evolution: StageType + + var stage: Stage { + Stage.stages(evolution) + } @State var parsedMap: ParsedMap = ParsedMap.empty let mapSize = CGSize(width: 1300.0, height: 1000.0) - let lineWidth = CGFloat(1.0) + let lineWidth = CGFloat(0.5) let vertexSize = CGSize(width: 25.0, height: 25.0) let padding = CGFloat(30.0) @@ -33,18 +28,20 @@ struct MapRenderView: View { CGRect( x: -padding, y: -padding, width: mapSize.width + padding * 2, height: mapSize.height + padding * 4)) - }.fill(MapColor.colorForScheme(colorScheme).background) + }.fill(.white) MapStages(mapSize: mapSize, lineWidth: lineWidth, stages: parsedMap.stages) MapAxes( - mapSize: mapSize, lineWidth: lineWidth, evolution: evolution, stages: parsedMap.stages) + mapSize: mapSize, lineWidth: lineWidth, evolution: stage, stages: parsedMap.stages) + 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) MapOpportunities( mapSize: mapSize, lineWidth: lineWidth, vertexSize: vertexSize, opportunities: parsedMap.opportunities) - MapBlockers(mapSize: mapSize, vertexSize: vertexSize, blockers: parsedMap.blockers) - MapVertices(mapSize: mapSize, vertexSize: vertexSize, vertices: parsedMap.vertices) - MapEdges( - mapSize: mapSize, lineWidth: lineWidth, vertexSize: vertexSize, edges: parsedMap.edges) + MapNotes( + mapSize: mapSize, lineWidth: lineWidth, notes: parsedMap.notes) }.frame( width: mapSize.width, height: mapSize.height + 2 * padding, alignment: .topLeading @@ -59,7 +56,7 @@ struct MapRenderView: View { struct MapRenderView_Previews: PreviewProvider { static var previews: some View { MapRenderView( - content: Binding.constant(""), evolution: Binding.constant(Stage.stages(.general)) + content: Binding.constant(""), evolution: Binding.constant(StageType.general) ).environment( \.managedObjectContext, PersistenceController.preview.container.viewContext) } diff --git a/Map/Views/DefaultMapView.swift b/Map/Presentation/Screens/EmptyMapDetailScreen.swift similarity index 67% rename from Map/Views/DefaultMapView.swift rename to Map/Presentation/Screens/EmptyMapDetailScreen.swift index 1f624d2..f3c6d75 100644 --- a/Map/Views/DefaultMapView.swift +++ b/Map/Presentation/Screens/EmptyMapDetailScreen.swift @@ -1,14 +1,7 @@ -// -// ContentView.swift -// Map -// -// Created by Ruben Beltran del Rio on 2/1/21. -// - import CoreData import SwiftUI -struct DefaultMapView: View { +struct EmptyMapDetailScreen: View { var body: some View { Text("Select a map from the left hand side, or click on + to create one.") @@ -17,7 +10,7 @@ struct DefaultMapView: View { struct DefaultMapView_Previews: PreviewProvider { static var previews: some View { - DefaultMapView().environment( + EmptyMapDetailScreen().environment( \.managedObjectContext, PersistenceController.preview.container.viewContext) } } diff --git a/Map/Views/MapDetail.swift b/Map/Presentation/Screens/MapDetailScreen.swift similarity index 57% rename from Map/Views/MapDetail.swift rename to Map/Presentation/Screens/MapDetailScreen.swift index bebe3a1..a5c32fd 100644 --- a/Map/Views/MapDetail.swift +++ b/Map/Presentation/Screens/MapDetailScreen.swift @@ -1,41 +1,14 @@ -// -// ContentView.swift -// Map -// -// Created by Ruben Beltran del Rio on 2/1/21. -// - import Combine import CoreData import SwiftUI -class SaveTimer { - let currentTimePublisher = Timer.TimerPublisher(interval: 1, runLoop: .main, mode: .default) - let cancellable: AnyCancellable? - - init() { - self.cancellable = currentTimePublisher.connect() as? AnyCancellable - } - - deinit { - self.cancellable?.cancel() - } -} - -let timer = SaveTimer() - -struct MapDetailView: View { +struct MapDetailScreen: View { @Environment(\.managedObjectContext) private var viewContext - @Environment(\.colorScheme) var colorScheme @EnvironmentObject var store: AppStore @ObservedObject var map: Map - private var mapColor: MapColor { - MapColor.colorForScheme(colorScheme) - } - @State var title: String @State var content: String @@ -45,9 +18,9 @@ struct MapDetailView: View { VStack { HStack { TextField( - "Title", text: $title + "Title", text: $title, onCommit: saveModel ).font(.title2).textFieldStyle(PlainTextFieldStyle()).padding(.vertical, 4.0).padding( - .leading, 4.0) + .leading, 4.0) Button(action: saveText) { Image(systemName: "doc.text") }.padding(.vertical, 4.0).padding(.leading, 4.0) @@ -58,25 +31,21 @@ struct MapDetailView: View { EvolutionPicker() ZStack(alignment: .topLeading) { - MapTextEditor(text: $content, colorScheme: colorScheme) - .background(mapColor.background) - .foregroundColor(mapColor.foreground) + 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(mapColor.background).cornerRadius( + }.padding(.top, 8.0).padding(.leading, 8.0).background(Color.ui.background).cornerRadius( 5.0) }.padding(.horizontal, 8.0) ScrollView([.horizontal, .vertical]) { - SlowMapRender( - content: content, evolution: Stage.stages(store.state.selectedEvolution), - colorScheme: colorScheme) - }.background(mapColor.background) - }.onReceive(timer.currentTimePublisher) { _ in - saveModel() + MapRenderView(content: $content, evolution: .constant(store.state.selectedEvolution)) + } }.onDisappear { saveModel() } } else { - DefaultMapView() + EmptyMapDetailScreen() } } @@ -97,7 +66,7 @@ struct MapDetailView: View { struct MapDetailView_Previews: PreviewProvider { static var previews: some View { - MapDetailView(map: Map(), title: "", content: "").environment( + MapDetailScreen(map: Map(), title: "", content: "").environment( \.managedObjectContext, PersistenceController.preview.container.viewContext) } } diff --git a/Map/Views/ContentView.swift b/Map/Presentation/Windows/MapEditorWindow.swift similarity index 90% rename from Map/Views/ContentView.swift rename to Map/Presentation/Windows/MapEditorWindow.swift index 534c14c..65316cc 100644 --- a/Map/Views/ContentView.swift +++ b/Map/Presentation/Windows/MapEditorWindow.swift @@ -1,14 +1,7 @@ -// -// ContentView.swift -// Map -// -// Created by Ruben Beltran del Rio on 2/1/21. -// - import CoreData import SwiftUI -struct ContentView: View { +struct MapEditorWindow: View { @Environment(\.managedObjectContext) private var viewContext @EnvironmentObject var store: AppStore @@ -22,11 +15,11 @@ struct ContentView: View { NavigationView { List { if maps.count == 0 { - DefaultMapView() + EmptyMapDetailScreen() } ForEach(maps) { map in NavigationLink( - destination: MapDetailView(map: map, title: map.title ?? "", content: map.content ?? "") + destination: MapDetailScreen(map: map, title: map.title ?? "", content: map.content ?? "") ) { HStack { Text(map.title ?? "Untitled Map") @@ -60,7 +53,7 @@ struct ContentView: View { } } } - DefaultMapView() + EmptyMapDetailScreen() } } @@ -110,7 +103,7 @@ private let mapFormatter: DateFormatter = { struct ContentView_Previews: PreviewProvider { static var previews: some View { - ContentView().environment( + MapEditorWindow().environment( \.managedObjectContext, PersistenceController.preview.container.viewContext) } } diff --git a/Map/Views/SlowMapRender.swift b/Map/Views/SlowMapRender.swift deleted file mode 100644 index b7cd842..0000000 --- a/Map/Views/SlowMapRender.swift +++ /dev/null @@ -1,90 +0,0 @@ -import Cocoa -import SwiftUI - -class SlowMapRenderController: NSViewController { - - var content: String - private var contentBinding: Binding { - Binding( - get: { self.content }, - set: { content in - self.content = content - } - ) - } - - var evolution: Stage - private var evolutionBinding: Binding { - Binding( - get: { self.evolution }, - set: { evolution in - self.evolution = evolution - } - ) - } - private var colorSchemeEnvironment: ObservableColorSchemeEnvironment - - private let debouncer: Debouncer = Debouncer(seconds: 0.1) - - init(content: String, evolution: Stage, colorScheme: ColorScheme) { - - self.content = content - self.evolution = evolution - self.colorSchemeEnvironment = ObservableColorSchemeEnvironment(colorScheme: colorScheme) - super.init(nibName: nil, bundle: nil) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func loadView() { - - let renderView = MapRenderView(content: self.contentBinding, evolution: self.evolutionBinding) - .environmentObject(self.colorSchemeEnvironment) - let hostingView = NSHostingView(rootView: renderView) - - self.view = hostingView - } - - func update(content: String, evolution: Stage, colorScheme: ColorScheme) { - self.debouncer.debounce { - DispatchQueue.main.async { - print("Updating: START") - self.content = content - self.evolution = evolution - self.colorSchemeEnvironment.colorScheme = colorScheme - print("Updating: END") - } - } - } - - private class ObservableColorSchemeEnvironment: ObservableObject { - @Published var colorScheme: ColorScheme - - init(colorScheme: ColorScheme) { - self.colorScheme = colorScheme - } - } -} - -struct SlowMapRender: NSViewControllerRepresentable { - - var content: String - var evolution: Stage - let colorScheme: ColorScheme - - func makeNSViewController( - context: NSViewControllerRepresentableContext - ) -> SlowMapRenderController { - return SlowMapRenderController(content: content, evolution: evolution, colorScheme: colorScheme) - } - - func updateNSViewController( - _ nsViewController: SlowMapRenderController, - context: NSViewControllerRepresentableContext - ) { - nsViewController.update( - content: content, evolution: evolution, colorScheme: context.environment.colorScheme) - } -}