Add Async image loading
@@ -0,0 +1,5 @@
|
||||
<?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">
|
||||
<array/>
|
||||
</plist>
|
||||
@@ -0,0 +1,577 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 50;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
B7310DD1229F6839001079B9 /* HexagonParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7310DD0229F6839001079B9 /* HexagonParameters.swift */; };
|
||||
B7310DD3229F6CA9001079B9 /* Badge.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7310DD2229F6CA9001079B9 /* Badge.swift */; };
|
||||
B7394866229F194000C47603 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7394865229F194000C47603 /* AppDelegate.swift */; };
|
||||
B7394868229F194000C47603 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7394867229F194000C47603 /* SceneDelegate.swift */; };
|
||||
B739486A229F194000C47603 /* LandmarkDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7394869229F194000C47603 /* LandmarkDetail.swift */; };
|
||||
B739486C229F194200C47603 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B739486B229F194200C47603 /* Assets.xcassets */; };
|
||||
B739486F229F194200C47603 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B739486E229F194200C47603 /* Preview Assets.xcassets */; };
|
||||
B7394872229F194200C47603 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B7394870229F194200C47603 /* LaunchScreen.storyboard */; };
|
||||
B739487A229F1B3F00C47603 /* CircleImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7394879229F1B3F00C47603 /* CircleImage.swift */; };
|
||||
B739487C229F1B6800C47603 /* MapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B739487B229F1B6800C47603 /* MapView.swift */; };
|
||||
B7394881229F28B900C47603 /* Landmark.swift in Sources */ = {isa = PBXBuildFile; fileRef = B739487F229F28B900C47603 /* Landmark.swift */; };
|
||||
B7394891229F292F00C47603 /* rainbowlake.jpg in Resources */ = {isa = PBXBuildFile; fileRef = B7394884229F292D00C47603 /* rainbowlake.jpg */; };
|
||||
B7394893229F292F00C47603 /* icybay.jpg in Resources */ = {isa = PBXBuildFile; fileRef = B7394886229F292E00C47603 /* icybay.jpg */; };
|
||||
B7394894229F292F00C47603 /* lakemcdonald.jpg in Resources */ = {isa = PBXBuildFile; fileRef = B7394887229F292E00C47603 /* lakemcdonald.jpg */; };
|
||||
B7394895229F292F00C47603 /* turtlerock.jpg in Resources */ = {isa = PBXBuildFile; fileRef = B7394888229F292E00C47603 /* turtlerock.jpg */; };
|
||||
B7394896229F292F00C47603 /* umbagog.jpg in Resources */ = {isa = PBXBuildFile; fileRef = B7394889229F292E00C47603 /* umbagog.jpg */; };
|
||||
B7394897229F292F00C47603 /* hiddenlake.jpg in Resources */ = {isa = PBXBuildFile; fileRef = B739488A229F292E00C47603 /* hiddenlake.jpg */; };
|
||||
B7394898229F292F00C47603 /* stmarylake.jpg in Resources */ = {isa = PBXBuildFile; fileRef = B739488B229F292E00C47603 /* stmarylake.jpg */; };
|
||||
B7394899229F292F00C47603 /* twinlake.jpg in Resources */ = {isa = PBXBuildFile; fileRef = B739488C229F292E00C47603 /* twinlake.jpg */; };
|
||||
B739489A229F292F00C47603 /* silversalmoncreek.jpg in Resources */ = {isa = PBXBuildFile; fileRef = B739488D229F292E00C47603 /* silversalmoncreek.jpg */; };
|
||||
B739489B229F292F00C47603 /* landmarkData.json in Resources */ = {isa = PBXBuildFile; fileRef = B739488E229F292E00C47603 /* landmarkData.json */; };
|
||||
B739489C229F292F00C47603 /* chincoteague.jpg in Resources */ = {isa = PBXBuildFile; fileRef = B739488F229F292F00C47603 /* chincoteague.jpg */; };
|
||||
B739489D229F292F00C47603 /* chilkoottrail.jpg in Resources */ = {isa = PBXBuildFile; fileRef = B7394890229F292F00C47603 /* chilkoottrail.jpg */; };
|
||||
B739489F229F2D9700C47603 /* LandmarkRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = B739489E229F2D9700C47603 /* LandmarkRow.swift */; };
|
||||
B73948A1229F2E1F00C47603 /* LandmarkList.swift in Sources */ = {isa = PBXBuildFile; fileRef = B73948A0229F2E1F00C47603 /* LandmarkList.swift */; };
|
||||
B73948A3229F3E2200C47603 /* charleyrivers.jpg in Resources */ = {isa = PBXBuildFile; fileRef = B73948A2229F3E2200C47603 /* charleyrivers.jpg */; };
|
||||
B7D2AAC5229F4D7C0061E5F5 /* UserData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7D2AAC4229F4D7C0061E5F5 /* UserData.swift */; };
|
||||
B7D587AE229F7382006E8DCF /* BadgeBackground.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7D587AD229F7382006E8DCF /* BadgeBackground.swift */; };
|
||||
B7D587B0229F73C1006E8DCF /* BadgeSymbol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7D587AF229F73C1006E8DCF /* BadgeSymbol.swift */; };
|
||||
B7D587B2229F7406006E8DCF /* RotatedBadgeSymbol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7D587B1229F7406006E8DCF /* RotatedBadgeSymbol.swift */; };
|
||||
B7D587B6229F825D006E8DCF /* HikeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7D587B5229F825D006E8DCF /* HikeView.swift */; };
|
||||
B7D587B8229F826D006E8DCF /* GraphCapsule.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7D587B7229F826D006E8DCF /* GraphCapsule.swift */; };
|
||||
B7D587BA229F8288006E8DCF /* Hike.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7D587B9229F8288006E8DCF /* Hike.swift */; };
|
||||
B7D587BC229F82EB006E8DCF /* HikeDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7D587BB229F82EB006E8DCF /* HikeDetail.swift */; };
|
||||
B7D587BE229F82FF006E8DCF /* HikeGraph.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7D587BD229F82FF006E8DCF /* HikeGraph.swift */; };
|
||||
B7D587C0229F830B006E8DCF /* hikeData.json in Resources */ = {isa = PBXBuildFile; fileRef = B7D587BF229F830B006E8DCF /* hikeData.json */; };
|
||||
B7D587D222A0892C006E8DCF /* Home.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7D587D122A0892C006E8DCF /* Home.swift */; };
|
||||
B7D587D422A08965006E8DCF /* CategoryRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7D587D322A08965006E8DCF /* CategoryRow.swift */; };
|
||||
B7D587D622A08C97006E8DCF /* Profile.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7D587D522A08C97006E8DCF /* Profile.swift */; };
|
||||
B7D587D922A08D33006E8DCF /* ProfileHost.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7D587D822A08D33006E8DCF /* ProfileHost.swift */; };
|
||||
B7D587DB22A08D67006E8DCF /* ProfileSummary.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7D587DA22A08D67006E8DCF /* ProfileSummary.swift */; };
|
||||
B7D587DD22A08DD6006E8DCF /* HikeBadge.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7D587DC22A08DD6006E8DCF /* HikeBadge.swift */; };
|
||||
B7D587DF22A08E1A006E8DCF /* ProfileEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7D587DE22A08E1A006E8DCF /* ProfileEditor.swift */; };
|
||||
B7D587E122A0914D006E8DCF /* FeatureCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7D587E022A0914D006E8DCF /* FeatureCard.swift */; };
|
||||
B7D587E522A097E2006E8DCF /* charleyrivers_feature.jpg in Resources */ = {isa = PBXBuildFile; fileRef = B7D587E222A097E2006E8DCF /* charleyrivers_feature.jpg */; };
|
||||
B7D587E622A097E2006E8DCF /* stmarylake_feature.jpg in Resources */ = {isa = PBXBuildFile; fileRef = B7D587E322A097E2006E8DCF /* stmarylake_feature.jpg */; };
|
||||
B7D587E722A097E2006E8DCF /* turtlerock_feature.jpg in Resources */ = {isa = PBXBuildFile; fileRef = B7D587E422A097E2006E8DCF /* turtlerock_feature.jpg */; };
|
||||
B7D587E922A09809006E8DCF /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7D587E822A09809006E8DCF /* Data.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
184943801849325000000001 /* SampleCode.xcconfig */ = {isa = PBXFileReference; name = SampleCode.xcconfig; path = ../Configuration/SampleCode.xcconfig; sourceTree = "<group>"; };
|
||||
187E8B20187E899000000001 /* LICENSE.txt */ = {isa = PBXFileReference; includeInIndex = 1; path = LICENSE.txt; sourceTree = "<group>"; };
|
||||
B7310DD0229F6839001079B9 /* HexagonParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HexagonParameters.swift; sourceTree = "<group>"; };
|
||||
B7310DD2229F6CA9001079B9 /* Badge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Badge.swift; sourceTree = "<group>"; };
|
||||
B7394862229F194000C47603 /* Landmarks.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Landmarks.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B7394865229F194000C47603 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
B7394867229F194000C47603 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
|
||||
B7394869229F194000C47603 /* LandmarkDetail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LandmarkDetail.swift; sourceTree = "<group>"; };
|
||||
B739486B229F194200C47603 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
B739486E229F194200C47603 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
|
||||
B7394871229F194200C47603 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
B7394873229F194200C47603 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
B7394879229F1B3F00C47603 /* CircleImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircleImage.swift; sourceTree = "<group>"; };
|
||||
B739487B229F1B6800C47603 /* MapView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapView.swift; sourceTree = "<group>"; };
|
||||
B739487F229F28B900C47603 /* Landmark.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Landmark.swift; sourceTree = "<group>"; };
|
||||
B7394884229F292D00C47603 /* rainbowlake.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = rainbowlake.jpg; sourceTree = "<group>"; };
|
||||
B7394886229F292E00C47603 /* icybay.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = icybay.jpg; sourceTree = "<group>"; };
|
||||
B7394887229F292E00C47603 /* lakemcdonald.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = lakemcdonald.jpg; sourceTree = "<group>"; };
|
||||
B7394888229F292E00C47603 /* turtlerock.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = turtlerock.jpg; sourceTree = "<group>"; };
|
||||
B7394889229F292E00C47603 /* umbagog.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = umbagog.jpg; sourceTree = "<group>"; };
|
||||
B739488A229F292E00C47603 /* hiddenlake.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = hiddenlake.jpg; sourceTree = "<group>"; };
|
||||
B739488B229F292E00C47603 /* stmarylake.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = stmarylake.jpg; sourceTree = "<group>"; };
|
||||
B739488C229F292E00C47603 /* twinlake.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = twinlake.jpg; sourceTree = "<group>"; };
|
||||
B739488D229F292E00C47603 /* silversalmoncreek.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = silversalmoncreek.jpg; sourceTree = "<group>"; };
|
||||
B739488E229F292E00C47603 /* landmarkData.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = landmarkData.json; sourceTree = "<group>"; };
|
||||
B739488F229F292F00C47603 /* chincoteague.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = chincoteague.jpg; sourceTree = "<group>"; };
|
||||
B7394890229F292F00C47603 /* chilkoottrail.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = chilkoottrail.jpg; sourceTree = "<group>"; };
|
||||
B739489E229F2D9700C47603 /* LandmarkRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LandmarkRow.swift; path = "Supporting Views/LandmarkRow.swift"; sourceTree = "<group>"; };
|
||||
B73948A0229F2E1F00C47603 /* LandmarkList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LandmarkList.swift; sourceTree = "<group>"; };
|
||||
B73948A2229F3E2200C47603 /* charleyrivers.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = charleyrivers.jpg; sourceTree = "<group>"; };
|
||||
B7D2AAC4229F4D7C0061E5F5 /* UserData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserData.swift; sourceTree = "<group>"; };
|
||||
B7D587AD229F7382006E8DCF /* BadgeBackground.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BadgeBackground.swift; sourceTree = "<group>"; };
|
||||
B7D587AF229F73C1006E8DCF /* BadgeSymbol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BadgeSymbol.swift; sourceTree = "<group>"; };
|
||||
B7D587B1229F7406006E8DCF /* RotatedBadgeSymbol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RotatedBadgeSymbol.swift; sourceTree = "<group>"; };
|
||||
B7D587B5229F825D006E8DCF /* HikeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HikeView.swift; sourceTree = "<group>"; };
|
||||
B7D587B7229F826D006E8DCF /* GraphCapsule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphCapsule.swift; sourceTree = "<group>"; };
|
||||
B7D587B9229F8288006E8DCF /* Hike.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Hike.swift; sourceTree = "<group>"; };
|
||||
B7D587BB229F82EB006E8DCF /* HikeDetail.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HikeDetail.swift; sourceTree = "<group>"; };
|
||||
B7D587BD229F82FF006E8DCF /* HikeGraph.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HikeGraph.swift; sourceTree = "<group>"; };
|
||||
B7D587BF229F830B006E8DCF /* hikeData.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = hikeData.json; sourceTree = "<group>"; };
|
||||
B7D587D122A0892C006E8DCF /* Home.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Home.swift; sourceTree = "<group>"; };
|
||||
B7D587D322A08965006E8DCF /* CategoryRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryRow.swift; sourceTree = "<group>"; };
|
||||
B7D587D522A08C97006E8DCF /* Profile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Profile.swift; sourceTree = "<group>"; };
|
||||
B7D587D822A08D33006E8DCF /* ProfileHost.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileHost.swift; sourceTree = "<group>"; };
|
||||
B7D587DA22A08D67006E8DCF /* ProfileSummary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileSummary.swift; sourceTree = "<group>"; };
|
||||
B7D587DC22A08DD6006E8DCF /* HikeBadge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HikeBadge.swift; sourceTree = "<group>"; };
|
||||
B7D587DE22A08E1A006E8DCF /* ProfileEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileEditor.swift; sourceTree = "<group>"; };
|
||||
B7D587E022A0914D006E8DCF /* FeatureCard.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeatureCard.swift; sourceTree = "<group>"; };
|
||||
B7D587E222A097E2006E8DCF /* charleyrivers_feature.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = charleyrivers_feature.jpg; sourceTree = "<group>"; };
|
||||
B7D587E322A097E2006E8DCF /* stmarylake_feature.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = stmarylake_feature.jpg; sourceTree = "<group>"; };
|
||||
B7D587E422A097E2006E8DCF /* turtlerock_feature.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = turtlerock_feature.jpg; sourceTree = "<group>"; };
|
||||
B7D587E822A09809006E8DCF /* Data.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Data.swift; sourceTree = "<group>"; };
|
||||
C4E4AAA0C4E4035000000001 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
B739485F229F194000C47603 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
1848B9A01848B96000000001 /* Configuration */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
184943801849325000000001 /* SampleCode.xcconfig */,
|
||||
);
|
||||
name = Configuration;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
187E7D00187E74D000000001 /* LICENSE */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
187E8B20187E899000000001 /* LICENSE.txt */,
|
||||
);
|
||||
name = LICENSE;
|
||||
path = ../LICENSE;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B7394859229F194000C47603 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C4E4AAA0C4E4035000000001 /* README.md */,
|
||||
B7394864229F194000C47603 /* Landmarks */,
|
||||
B7394863229F194000C47603 /* Products */,
|
||||
1848B9A01848B96000000001 /* Configuration */,
|
||||
187E7D00187E74D000000001 /* LICENSE */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B7394863229F194000C47603 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B7394862229F194000C47603 /* Landmarks.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B7394864229F194000C47603 /* Landmarks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B739487E229F282200C47603 /* Models */,
|
||||
B7D587D722A08D16006E8DCF /* Profiles */,
|
||||
B7394865229F194000C47603 /* AppDelegate.swift */,
|
||||
B7394867229F194000C47603 /* SceneDelegate.swift */,
|
||||
B7D587D122A0892C006E8DCF /* Home.swift */,
|
||||
B7D587D322A08965006E8DCF /* CategoryRow.swift */,
|
||||
B73948A0229F2E1F00C47603 /* LandmarkList.swift */,
|
||||
B739489E229F2D9700C47603 /* LandmarkRow.swift */,
|
||||
B7394869229F194000C47603 /* LandmarkDetail.swift */,
|
||||
B7D587B5229F825D006E8DCF /* HikeView.swift */,
|
||||
B7D587BB229F82EB006E8DCF /* HikeDetail.swift */,
|
||||
B7D587DC22A08DD6006E8DCF /* HikeBadge.swift */,
|
||||
B7310DD0229F6839001079B9 /* HexagonParameters.swift */,
|
||||
B739487D229F1C0100C47603 /* Supporting Views */,
|
||||
B7394883229F291A00C47603 /* Resources */,
|
||||
B739486B229F194200C47603 /* Assets.xcassets */,
|
||||
B7394870229F194200C47603 /* LaunchScreen.storyboard */,
|
||||
B7394873229F194200C47603 /* Info.plist */,
|
||||
B739486D229F194200C47603 /* Preview Content */,
|
||||
);
|
||||
path = Landmarks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B739486D229F194200C47603 /* Preview Content */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B739486E229F194200C47603 /* Preview Assets.xcassets */,
|
||||
);
|
||||
path = "Preview Content";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B739487D229F1C0100C47603 /* Supporting Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B7D587E022A0914D006E8DCF /* FeatureCard.swift */,
|
||||
B7394879229F1B3F00C47603 /* CircleImage.swift */,
|
||||
B739487B229F1B6800C47603 /* MapView.swift */,
|
||||
B7310DD2229F6CA9001079B9 /* Badge.swift */,
|
||||
B7D587AF229F73C1006E8DCF /* BadgeSymbol.swift */,
|
||||
B7D587B1229F7406006E8DCF /* RotatedBadgeSymbol.swift */,
|
||||
B7D587AD229F7382006E8DCF /* BadgeBackground.swift */,
|
||||
B7D587BD229F82FF006E8DCF /* HikeGraph.swift */,
|
||||
B7D587B7229F826D006E8DCF /* GraphCapsule.swift */,
|
||||
);
|
||||
path = "Supporting Views";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B739487E229F282200C47603 /* Models */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B7D587D522A08C97006E8DCF /* Profile.swift */,
|
||||
B739487F229F28B900C47603 /* Landmark.swift */,
|
||||
B7D587E822A09809006E8DCF /* Data.swift */,
|
||||
B7D587B9229F8288006E8DCF /* Hike.swift */,
|
||||
B7D2AAC4229F4D7C0061E5F5 /* UserData.swift */,
|
||||
);
|
||||
path = Models;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B7394883229F291A00C47603 /* Resources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B739488E229F292E00C47603 /* landmarkData.json */,
|
||||
B7D587BF229F830B006E8DCF /* hikeData.json */,
|
||||
B7D587E222A097E2006E8DCF /* charleyrivers_feature.jpg */,
|
||||
B7D587E322A097E2006E8DCF /* stmarylake_feature.jpg */,
|
||||
B7D587E422A097E2006E8DCF /* turtlerock_feature.jpg */,
|
||||
B7394890229F292F00C47603 /* chilkoottrail.jpg */,
|
||||
B739488F229F292F00C47603 /* chincoteague.jpg */,
|
||||
B739488A229F292E00C47603 /* hiddenlake.jpg */,
|
||||
B7394886229F292E00C47603 /* icybay.jpg */,
|
||||
B7394887229F292E00C47603 /* lakemcdonald.jpg */,
|
||||
B7394884229F292D00C47603 /* rainbowlake.jpg */,
|
||||
B739488D229F292E00C47603 /* silversalmoncreek.jpg */,
|
||||
B739488B229F292E00C47603 /* stmarylake.jpg */,
|
||||
B7394888229F292E00C47603 /* turtlerock.jpg */,
|
||||
B739488C229F292E00C47603 /* twinlake.jpg */,
|
||||
B7394889229F292E00C47603 /* umbagog.jpg */,
|
||||
B73948A2229F3E2200C47603 /* charleyrivers.jpg */,
|
||||
);
|
||||
path = Resources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B7D587D722A08D16006E8DCF /* Profiles */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B7D587D822A08D33006E8DCF /* ProfileHost.swift */,
|
||||
B7D587DA22A08D67006E8DCF /* ProfileSummary.swift */,
|
||||
B7D587DE22A08E1A006E8DCF /* ProfileEditor.swift */,
|
||||
);
|
||||
path = Profiles;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
B7394861229F194000C47603 /* Landmarks */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = B7394876229F194200C47603 /* Build configuration list for PBXNativeTarget "Landmarks" */;
|
||||
buildPhases = (
|
||||
B739485E229F194000C47603 /* Sources */,
|
||||
B739485F229F194000C47603 /* Frameworks */,
|
||||
B7394860229F194000C47603 /* Resources */,
|
||||
C602AC70C605937000000001,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = Landmarks;
|
||||
productName = Landmarks;
|
||||
productReference = B7394862229F194000C47603 /* Landmarks.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
B739485A229F194000C47603 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 1100;
|
||||
LastUpgradeCheck = 1100;
|
||||
ORGANIZATIONNAME = Apple;
|
||||
TargetAttributes = {
|
||||
B7394861229F194000C47603 = {
|
||||
CreatedOnToolsVersion = 11.0;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = B739485D229F194000C47603 /* Build configuration list for PBXProject "InterfacingWithUIKit" */;
|
||||
compatibilityVersion = "Xcode 9.3";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = B7394859229F194000C47603;
|
||||
productRefGroup = B7394863229F194000C47603 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
B7394861229F194000C47603 /* Landmarks */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
B7394860229F194000C47603 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B739489A229F292F00C47603 /* silversalmoncreek.jpg in Resources */,
|
||||
B7394894229F292F00C47603 /* lakemcdonald.jpg in Resources */,
|
||||
B7D587C0229F830B006E8DCF /* hikeData.json in Resources */,
|
||||
B7394872229F194200C47603 /* LaunchScreen.storyboard in Resources */,
|
||||
B73948A3229F3E2200C47603 /* charleyrivers.jpg in Resources */,
|
||||
B7394891229F292F00C47603 /* rainbowlake.jpg in Resources */,
|
||||
B7D587E522A097E2006E8DCF /* charleyrivers_feature.jpg in Resources */,
|
||||
B739486F229F194200C47603 /* Preview Assets.xcassets in Resources */,
|
||||
B7394895229F292F00C47603 /* turtlerock.jpg in Resources */,
|
||||
B739486C229F194200C47603 /* Assets.xcassets in Resources */,
|
||||
B7394899229F292F00C47603 /* twinlake.jpg in Resources */,
|
||||
B7D587E622A097E2006E8DCF /* stmarylake_feature.jpg in Resources */,
|
||||
B7394896229F292F00C47603 /* umbagog.jpg in Resources */,
|
||||
B739489D229F292F00C47603 /* chilkoottrail.jpg in Resources */,
|
||||
B739489C229F292F00C47603 /* chincoteague.jpg in Resources */,
|
||||
B739489B229F292F00C47603 /* landmarkData.json in Resources */,
|
||||
B7394893229F292F00C47603 /* icybay.jpg in Resources */,
|
||||
B7394897229F292F00C47603 /* hiddenlake.jpg in Resources */,
|
||||
B7394898229F292F00C47603 /* stmarylake.jpg in Resources */,
|
||||
B7D587E722A097E2006E8DCF /* turtlerock_feature.jpg in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
B739485E229F194000C47603 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B7310DD3229F6CA9001079B9 /* Badge.swift in Sources */,
|
||||
B7D587E122A0914D006E8DCF /* FeatureCard.swift in Sources */,
|
||||
B7394866229F194000C47603 /* AppDelegate.swift in Sources */,
|
||||
B7D587D922A08D33006E8DCF /* ProfileHost.swift in Sources */,
|
||||
B7D587D622A08C97006E8DCF /* Profile.swift in Sources */,
|
||||
B7D587B8229F826D006E8DCF /* GraphCapsule.swift in Sources */,
|
||||
B7D587D422A08965006E8DCF /* CategoryRow.swift in Sources */,
|
||||
B7D587E922A09809006E8DCF /* Data.swift in Sources */,
|
||||
B739487A229F1B3F00C47603 /* CircleImage.swift in Sources */,
|
||||
B739487C229F1B6800C47603 /* MapView.swift in Sources */,
|
||||
B7D587BA229F8288006E8DCF /* Hike.swift in Sources */,
|
||||
B7D587BC229F82EB006E8DCF /* HikeDetail.swift in Sources */,
|
||||
B7D587B6229F825D006E8DCF /* HikeView.swift in Sources */,
|
||||
B7310DD1229F6839001079B9 /* HexagonParameters.swift in Sources */,
|
||||
B73948A1229F2E1F00C47603 /* LandmarkList.swift in Sources */,
|
||||
B7D587B0229F73C1006E8DCF /* BadgeSymbol.swift in Sources */,
|
||||
B7D587B2229F7406006E8DCF /* RotatedBadgeSymbol.swift in Sources */,
|
||||
B7D587DD22A08DD6006E8DCF /* HikeBadge.swift in Sources */,
|
||||
B7D587D222A0892C006E8DCF /* Home.swift in Sources */,
|
||||
B7D587BE229F82FF006E8DCF /* HikeGraph.swift in Sources */,
|
||||
B7394868229F194000C47603 /* SceneDelegate.swift in Sources */,
|
||||
B7D587AE229F7382006E8DCF /* BadgeBackground.swift in Sources */,
|
||||
B739486A229F194000C47603 /* LandmarkDetail.swift in Sources */,
|
||||
B739489F229F2D9700C47603 /* LandmarkRow.swift in Sources */,
|
||||
B7D587DB22A08D67006E8DCF /* ProfileSummary.swift in Sources */,
|
||||
B7D2AAC5229F4D7C0061E5F5 /* UserData.swift in Sources */,
|
||||
B7394881229F28B900C47603 /* Landmark.swift in Sources */,
|
||||
B7D587DF22A08E1A006E8DCF /* ProfileEditor.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
B7394870229F194200C47603 /* LaunchScreen.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
B7394871229F194200C47603 /* Base */,
|
||||
);
|
||||
name = LaunchScreen.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
B7394874229F194200C47603 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 184943801849325000000001 /* SampleCode.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
B7394875229F194200C47603 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 184943801849325000000001 /* SampleCode.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
B7394877229F194200C47603 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 184943801849325000000001 /* SampleCode.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_ASSET_PATHS = "Landmarks/Preview\\ Content";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_PREVIEWS = YES;
|
||||
INFOPLIST_FILE = Landmarks/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.example.apple-samplecode.Landmarks${SAMPLE_CODE_DISAMBIGUATOR}";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
B7394878229F194200C47603 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 184943801849325000000001 /* SampleCode.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_ASSET_PATHS = "Landmarks/Preview\\ Content";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_PREVIEWS = YES;
|
||||
INFOPLIST_FILE = Landmarks/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.example.apple-samplecode.Landmarks${SAMPLE_CODE_DISAMBIGUATOR}";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
B739485D229F194000C47603 /* Build configuration list for PBXProject "InterfacingWithUIKit" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
B7394874229F194200C47603 /* Debug */,
|
||||
B7394875229F194200C47603 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
B7394876229F194200C47603 /* Build configuration list for PBXNativeTarget "Landmarks" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
B7394877229F194200C47603 /* Debug */,
|
||||
B7394878229F194200C47603 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = B739485A229F194000C47603 /* Project object */;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?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>BuildSystemType</key>
|
||||
<string>Latest</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
The application delegate.
|
||||
*/
|
||||
|
||||
import UIKit
|
||||
|
||||
@UIApplicationMain
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
// Override point for customization after application launch.
|
||||
return true
|
||||
}
|
||||
|
||||
func applicationWillTerminate(_ application: UIApplication) {
|
||||
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
|
||||
}
|
||||
|
||||
// MARK: UISceneSession Lifecycle
|
||||
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
|
||||
// Called when a new scene session is being created.
|
||||
// Use this method to select a configuration to create the new scene with.
|
||||
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
|
||||
}
|
||||
|
||||
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
|
||||
// Called when the user discards a scene session.
|
||||
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
|
||||
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "landmark_app_icon_40x40.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "landmark_app_icon_58x58.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "landmark_app_icon_87x87.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "landmark_app_icon_80x80.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "landmark_app_icon_120x120.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "landmark_app_icon_120x120-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "landmark_app_icon_180x180.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "landmark_app_icon_40x40-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "landmark_app_icon_58x58-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "landmark_app_icon_40x40-2.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "landmark_app_icon_80x80-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "landmark_app_icon_76x76.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "landmark_app_icon_152x152.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "83.5x83.5",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "landmark_app_icon_167x167.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "1024x1024",
|
||||
"idiom" : "ios-marketing",
|
||||
"filename" : "landmark_app_icon_1024x1024.png",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "turtlerock.jpg",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
BIN
Examples/Interfacing With UIKit/StartingPoint/Landmarks/Landmarks/Assets.xcassets/turtlerock.imageset/turtlerock.jpg
vendored
Executable file
|
After Width: | Height: | Size: 22 KiB |
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="EHf-IW-A2E">
|
||||
<objects>
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="53" y="375"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
A view showing a scrollable list of landmarks.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct CategoryRow: View {
|
||||
var categoryName: String
|
||||
var items: [Landmark]
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading) {
|
||||
Text(self.categoryName)
|
||||
.font(.headline)
|
||||
.padding(.leading, 15)
|
||||
.padding(.top, 5)
|
||||
|
||||
ScrollView(showsHorizontalIndicator: false) {
|
||||
HStack(alignment: .top, spacing: 0) {
|
||||
ForEach(self.items.identified(by: \.name)) { landmark in
|
||||
NavigationButton(
|
||||
destination: LandmarkDetail(
|
||||
landmark: landmark
|
||||
)
|
||||
) {
|
||||
CategoryItem(landmark: landmark)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(height: 185)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CategoryItem: View {
|
||||
var landmark: Landmark
|
||||
var body: some View {
|
||||
VStack(alignment: .leading) {
|
||||
landmark
|
||||
.image(forSize: 155)
|
||||
.renderingMode(.original)
|
||||
.cornerRadius(5)
|
||||
Text(landmark.name)
|
||||
.color(.primary)
|
||||
.font(.caption)
|
||||
}
|
||||
.padding(.leading, 15)
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct CategoryRow_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
CategoryRow(
|
||||
categoryName: landmarkData[0].category.rawValue,
|
||||
items: Array(landmarkData.prefix(4))
|
||||
)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
Size, position, and other information used to draw a badge.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct HexagonParameters {
|
||||
struct Segment {
|
||||
let useWidth: (CGFloat, CGFloat, CGFloat)
|
||||
let xFactors: (CGFloat, CGFloat, CGFloat)
|
||||
let useHeight: (CGFloat, CGFloat, CGFloat)
|
||||
let yFactors: (CGFloat, CGFloat, CGFloat)
|
||||
}
|
||||
|
||||
static let adjustment: CGFloat = 0.085
|
||||
static let points = [
|
||||
Segment(
|
||||
useWidth: (1.00, 1.00, 1.00),
|
||||
xFactors: (0.60, 0.40, 0.50),
|
||||
useHeight: (1.00, 1.00, 0.00),
|
||||
yFactors: (0.05, 0.05, 0.00)
|
||||
),
|
||||
Segment(
|
||||
useWidth: (1.00, 1.00, 0.00),
|
||||
xFactors: (0.05, 0.00, 0.00),
|
||||
useHeight: (1.00, 1.00, 1.00),
|
||||
yFactors: (0.20 + adjustment, 0.30 + adjustment, 0.25 + adjustment)
|
||||
),
|
||||
Segment(
|
||||
useWidth: (1.00, 1.00, 0.00),
|
||||
xFactors: (0.00, 0.05, 0.00),
|
||||
useHeight: (1.00, 1.00, 1.00),
|
||||
yFactors: (0.70 - adjustment, 0.80 - adjustment, 0.75 - adjustment)
|
||||
),
|
||||
Segment(
|
||||
useWidth: (1.00, 1.00, 1.00),
|
||||
xFactors: (0.40, 0.60, 0.50),
|
||||
useHeight: (1.00, 1.00, 1.00),
|
||||
yFactors: (0.95, 0.95, 1.00)
|
||||
),
|
||||
Segment(
|
||||
useWidth: (1.00, 1.00, 1.00),
|
||||
xFactors: (0.95, 1.00, 1.00),
|
||||
useHeight: (1.00, 1.00, 1.00),
|
||||
yFactors: (0.80 - adjustment, 0.70 - adjustment, 0.75 - adjustment)
|
||||
),
|
||||
Segment(
|
||||
useWidth: (1.00, 1.00, 1.00),
|
||||
xFactors: (1.00, 0.95, 1.00),
|
||||
useHeight: (1.00, 1.00, 1.00),
|
||||
yFactors: (0.30 + adjustment, 0.20 + adjustment, 0.25 + adjustment)
|
||||
)
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
A view that shows a badge for hiking.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct HikeBadge: View {
|
||||
var name: String
|
||||
var body: some View {
|
||||
VStack(alignment: .center) {
|
||||
Badge()
|
||||
.frame(width: 300, height: 300)
|
||||
.scaleEffect(1.0 / 3.0)
|
||||
.frame(width: 100, height: 100)
|
||||
Text(name)
|
||||
.font(.caption)
|
||||
.accessibility(label: Text("Badge for \(name)."))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct HikeBadge_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
HikeBadge(name: "Preview Testing")
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
A view showing the details for a hike.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct HikeDetail: View {
|
||||
let hike: Hike
|
||||
@State var dataToShow = \Hike.Observation.elevation
|
||||
|
||||
var buttons = [
|
||||
("Elevation", \Hike.Observation.elevation),
|
||||
("Heart Rate", \Hike.Observation.heartRate),
|
||||
("Pace", \Hike.Observation.pace),
|
||||
]
|
||||
|
||||
var body: some View {
|
||||
return VStack {
|
||||
HikeGraph(hike: hike, path: dataToShow)
|
||||
.frame(height: 200, alignment: .center)
|
||||
|
||||
HStack(spacing: 25) {
|
||||
ForEach(buttons.identified(by: \.0)) { value in
|
||||
Button(action: {
|
||||
self.dataToShow = value.1
|
||||
}) {
|
||||
Text(verbatim: value.0)
|
||||
.font(.system(size: 15))
|
||||
.color(value.1 == self.dataToShow
|
||||
? Color.gray
|
||||
: Color.accentColor)
|
||||
.animation(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct HikeDetail_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
HikeDetail(hike: hikeData[0])
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
A view displaying inforamtion about a hike, including an elevation graph.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct HikeView: View {
|
||||
var hike: Hike
|
||||
@State private var showDetail = false
|
||||
|
||||
var transition: AnyTransition {
|
||||
let insertion = AnyTransition.move(edge: .trailing)
|
||||
.combined(with: .opacity)
|
||||
let removal = AnyTransition.scale()
|
||||
.combined(with: .opacity)
|
||||
return .asymmetric(insertion: insertion, removal: removal)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
HStack {
|
||||
HikeGraph(hike: hike, path: \.elevation)
|
||||
.frame(width: 50, height: 30)
|
||||
.animation(nil)
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
Text(verbatim: hike.name)
|
||||
.font(.headline)
|
||||
Text(verbatim: hike.distanceText)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
Button(action: {
|
||||
withAnimation {
|
||||
self.showDetail.toggle()
|
||||
}
|
||||
}) {
|
||||
Image(systemName: "chevron.right.circle")
|
||||
.imageScale(.large)
|
||||
.rotationEffect(.degrees(showDetail ? 90 : 0))
|
||||
.scaleEffect(showDetail ? 1.5 : 1)
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
|
||||
if showDetail {
|
||||
HikeDetail(hike: hike)
|
||||
.transition(transition)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct HikeView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
VStack {
|
||||
HikeView(hike: hikeData[0])
|
||||
.padding()
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
67
Examples/Interfacing With UIKit/StartingPoint/Landmarks/Landmarks/Home.swift
Executable file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
A view showing featured landmarks above a list of all of the landmarks.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct CategoryHome: View {
|
||||
var categories: [String: [Landmark]] {
|
||||
.init(
|
||||
grouping: landmarkData,
|
||||
by: { $0.category.rawValue }
|
||||
)
|
||||
}
|
||||
|
||||
var featured: [Landmark] {
|
||||
landmarkData.filter { $0.isFeatured }
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
List {
|
||||
FeaturedLandmarks(landmarks: featured)
|
||||
.scaledToFill()
|
||||
.frame(height: 200)
|
||||
.clipped()
|
||||
.listRowInsets(EdgeInsets())
|
||||
|
||||
ForEach(categories.keys.sorted().identified(by: \.self)) { key in
|
||||
CategoryRow(categoryName: key, items: self.categories[key]!)
|
||||
}
|
||||
.listRowInsets(EdgeInsets())
|
||||
|
||||
NavigationButton(destination: LandmarkList()) {
|
||||
Text("See All")
|
||||
}
|
||||
}
|
||||
.navigationBarTitle(Text("Featured"))
|
||||
.navigationBarItems(trailing:
|
||||
PresentationButton(
|
||||
Image(systemName: "person.crop.circle")
|
||||
.imageScale(.large)
|
||||
.accessibility(label: Text("User Profile"))
|
||||
.padding(),
|
||||
destination: ProfileHost()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct FeaturedLandmarks: View {
|
||||
var landmarks: [Landmark]
|
||||
var body: some View {
|
||||
landmarks[0].image(forSize: 250).resizable()
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct CategoryHome_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
CategoryHome()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
62
Examples/Interfacing With UIKit/StartingPoint/Landmarks/Landmarks/Info.plist
Executable file
@@ -0,0 +1,62 @@
|
||||
<?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>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UIApplicationSceneManifest</key>
|
||||
<dict>
|
||||
<key>UIApplicationSupportsMultipleScenes</key>
|
||||
<false/>
|
||||
<key>UISceneConfigurations</key>
|
||||
<dict>
|
||||
<key>UIWindowSceneSessionRoleApplication</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UISceneConfigurationName</key>
|
||||
<string>Default Configuration</string>
|
||||
<key>UISceneDelegateClassName</key>
|
||||
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
A view showing the details for a landmark.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct LandmarkDetail: View {
|
||||
@EnvironmentObject var userData: UserData
|
||||
var landmark: Landmark
|
||||
|
||||
var landmarkIndex: Int {
|
||||
userData.landmarks.firstIndex(where: { $0.id == landmark.id })!
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
MapView(coordinate: landmark.locationCoordinate)
|
||||
.edgesIgnoringSafeArea(.top)
|
||||
.frame(height: 300)
|
||||
|
||||
CircleImage(image: landmark.image(forSize: 250))
|
||||
.offset(x: 0, y: -130)
|
||||
.padding(.bottom, -130)
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
HStack {
|
||||
Text(verbatim: landmark.name)
|
||||
.font(.title)
|
||||
|
||||
Button(action: {
|
||||
self.userData.landmarks[self.landmarkIndex]
|
||||
.isFavorite.toggle()
|
||||
}) {
|
||||
if self.userData.landmarks[self.landmarkIndex]
|
||||
.isFavorite {
|
||||
Image(systemName: "star.fill")
|
||||
.foregroundColor(Color.yellow)
|
||||
} else {
|
||||
Image(systemName: "star")
|
||||
.foregroundColor(Color.gray)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HStack(alignment: .top) {
|
||||
Text(verbatim: landmark.park)
|
||||
.font(.subheadline)
|
||||
Spacer()
|
||||
Text(verbatim: landmark.state)
|
||||
.font(.subheadline)
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct LandmarkDetail_Preview: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let userData = UserData()
|
||||
return LandmarkDetail(landmark: userData.landmarks[0])
|
||||
.environmentObject(userData)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
A view showing a list of landmarks.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct LandmarkList: View {
|
||||
@EnvironmentObject private var userData: UserData
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
List {
|
||||
Toggle(isOn: $userData.showFavoritesOnly) {
|
||||
Text("Show Favorites Only")
|
||||
}
|
||||
|
||||
ForEach(userData.landmarks) { landmark in
|
||||
if !self.userData.showFavoritesOnly || landmark.isFavorite {
|
||||
NavigationButton(
|
||||
destination: LandmarkDetail(landmark: landmark)) {
|
||||
LandmarkRow(landmark: landmark)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationBarTitle(Text("Landmarks"), displayMode: .large)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct LandmarksList_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ForEach(["iPhone SE", "iPhone XS Max"].identified(by: \.self)) { deviceName in
|
||||
LandmarkList()
|
||||
.previewDevice(PreviewDevice(rawValue: deviceName))
|
||||
.previewDisplayName(deviceName)
|
||||
}
|
||||
.environmentObject(UserData())
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
Helpers for loading images and data.
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
import CoreLocation
|
||||
import UIKit
|
||||
import SwiftUI
|
||||
|
||||
let landmarkData: [Landmark] = load("landmarkData.json")
|
||||
let features = landmarkData.filter { $0.isFeatured }
|
||||
let hikeData: [Hike] = load("hikeData.json")
|
||||
|
||||
func load<T: Decodable>(_ filename: String, as type: T.Type = T.self) -> T {
|
||||
let data: Data
|
||||
|
||||
guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
|
||||
else {
|
||||
fatalError("Couldn't find \(filename) in main bundle.")
|
||||
}
|
||||
|
||||
do {
|
||||
data = try Data(contentsOf: file)
|
||||
} catch {
|
||||
fatalError("Couldn't load \(filename) from main bundle:\n\(error)")
|
||||
}
|
||||
|
||||
do {
|
||||
let decoder = JSONDecoder()
|
||||
return try decoder.decode(T.self, from: data)
|
||||
} catch {
|
||||
fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)")
|
||||
}
|
||||
}
|
||||
|
||||
final class ImageStore {
|
||||
fileprivate typealias _ImageDictionary = [String: [Int: CGImage]]
|
||||
fileprivate var images: _ImageDictionary = [:]
|
||||
|
||||
fileprivate static var originalSize = 250
|
||||
fileprivate static var scale = 2
|
||||
|
||||
static var shared = ImageStore()
|
||||
|
||||
func image(name: String, size: Int) -> Image {
|
||||
let index = _guaranteeInitialImage(name: name)
|
||||
|
||||
let sizedImage = images.values[index][size]
|
||||
?? _sizeImage(images.values[index][ImageStore.originalSize]!, to: size * ImageStore.scale)
|
||||
images.values[index][size] = sizedImage
|
||||
|
||||
return Image(sizedImage, scale: Length(ImageStore.scale), label: Text(verbatim: name))
|
||||
}
|
||||
|
||||
static func loadImage(name: String) -> CGImage {
|
||||
guard
|
||||
let url = Bundle.main.url(forResource: name, withExtension: "jpg"),
|
||||
let imageSource = CGImageSourceCreateWithURL(url as NSURL, nil),
|
||||
let image = CGImageSourceCreateImageAtIndex(imageSource, 0, nil)
|
||||
else {
|
||||
fatalError("Couldn't load image \(name).jpg from main bundle.")
|
||||
}
|
||||
return image
|
||||
}
|
||||
|
||||
fileprivate func _guaranteeInitialImage(name: String) -> _ImageDictionary.Index {
|
||||
if let index = images.index(forKey: name) { return index }
|
||||
|
||||
let image = ImageStore.loadImage(name: name)
|
||||
images[name] = [ImageStore.originalSize: image]
|
||||
return images.index(forKey: name)!
|
||||
}
|
||||
|
||||
fileprivate func _sizeImage(_ image: CGImage, to size: Int) -> CGImage {
|
||||
guard
|
||||
let colorSpace = image.colorSpace,
|
||||
let context = CGContext(
|
||||
data: nil,
|
||||
width: size, height: size,
|
||||
bitsPerComponent: image.bitsPerComponent,
|
||||
bytesPerRow: image.bytesPerRow,
|
||||
space: colorSpace,
|
||||
bitmapInfo: image.bitmapInfo.rawValue)
|
||||
else {
|
||||
fatalError("Couldn't create graphics context.")
|
||||
}
|
||||
context.interpolationQuality = .high
|
||||
context.draw(image, in: CGRect(x: 0, y: 0, width: size, height: size))
|
||||
|
||||
if let sizedImage = context.makeImage() {
|
||||
return sizedImage
|
||||
} else {
|
||||
fatalError("Couldn't resize image.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
The model for a hike.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct Hike: Codable, Hashable, Identifiable {
|
||||
var name: String
|
||||
var id: Int
|
||||
var distance: Double
|
||||
var difficulty: Int
|
||||
var observations: [Observation]
|
||||
|
||||
static var formatter = LengthFormatter()
|
||||
|
||||
var distanceText: String {
|
||||
return Hike.formatter
|
||||
.string(fromValue: distance, unit: .kilometer)
|
||||
}
|
||||
|
||||
struct Observation: Codable, Hashable {
|
||||
var distanceFromStart: Double
|
||||
|
||||
var elevation: Range<Double>
|
||||
var pace: Range<Double>
|
||||
var heartRate: Range<Double>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
The model for an individual landmark.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
import CoreLocation
|
||||
|
||||
struct Landmark: Hashable, Codable, Identifiable {
|
||||
var id: Int
|
||||
var name: String
|
||||
fileprivate var imageName: String
|
||||
fileprivate var coordinates: Coordinates
|
||||
var state: String
|
||||
var park: String
|
||||
var category: Category
|
||||
var isFavorite: Bool
|
||||
var isFeatured: Bool
|
||||
|
||||
var locationCoordinate: CLLocationCoordinate2D {
|
||||
CLLocationCoordinate2D(
|
||||
latitude: coordinates.latitude,
|
||||
longitude: coordinates.longitude)
|
||||
}
|
||||
|
||||
var featureImage: Image? {
|
||||
guard isFeatured else { return nil }
|
||||
|
||||
return Image(
|
||||
ImageStore.loadImage(name: "\(imageName)_feature"),
|
||||
scale: 2,
|
||||
label: Text(verbatim: name))
|
||||
}
|
||||
|
||||
func image(forSize size: Int) -> Image {
|
||||
ImageStore.shared.image(name: imageName, size: size)
|
||||
}
|
||||
|
||||
enum Category: String, CaseIterable, Codable, Hashable {
|
||||
case featured = "Featured"
|
||||
case lakes = "Lakes"
|
||||
case rivers = "Rivers"
|
||||
case mountains = "Mountains"
|
||||
}
|
||||
}
|
||||
|
||||
struct Coordinates: Hashable, Codable {
|
||||
var latitude: Double
|
||||
var longitude: Double
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
An object that models a user profile.
|
||||
*/
|
||||
import Foundation
|
||||
|
||||
struct Profile {
|
||||
var username: String
|
||||
var prefersNotifications: Bool
|
||||
var seasonalPhoto: Season
|
||||
var goalDate: Date
|
||||
|
||||
static let `default` = Self(username: "g_kumar", prefersNotifications: true, seasonalPhoto: .winter)
|
||||
|
||||
init(username: String, prefersNotifications: Bool = true, seasonalPhoto: Season = .winter) {
|
||||
self.username = username
|
||||
self.prefersNotifications = prefersNotifications
|
||||
self.seasonalPhoto = seasonalPhoto
|
||||
self.goalDate = Date()
|
||||
}
|
||||
|
||||
enum Season: String, CaseIterable {
|
||||
case spring = "🌷"
|
||||
case summer = "🌞"
|
||||
case autumn = "🍂"
|
||||
case winter = "☃️"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
A model object that stores app data.
|
||||
*/
|
||||
|
||||
import Combine
|
||||
import SwiftUI
|
||||
|
||||
final class UserData: BindableObject {
|
||||
let didChange = PassthroughSubject<UserData, Never>()
|
||||
|
||||
var showFavoritesOnly = false {
|
||||
didSet {
|
||||
didChange.send(self)
|
||||
}
|
||||
}
|
||||
|
||||
var landmarks = landmarkData {
|
||||
didSet {
|
||||
didChange.send(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
An editable profile view.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ProfileEditor: View {
|
||||
@Binding var profile: Profile
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
HStack {
|
||||
Text("Username").bold()
|
||||
Divider()
|
||||
TextField($profile.username)
|
||||
}
|
||||
|
||||
Toggle(isOn: $profile.prefersNotifications) {
|
||||
Text("Enable Notifications")
|
||||
}
|
||||
|
||||
VStack(alignment: .leading, spacing: 20) {
|
||||
Text("Seasonal Photo").bold()
|
||||
|
||||
SegmentedControl(selection: $profile.seasonalPhoto) {
|
||||
ForEach(Profile.Season.allCases.identified(by: \.self)) { season in
|
||||
Text(season.rawValue).tag(season)
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(.top)
|
||||
|
||||
VStack(alignment: .leading, spacing: 20) {
|
||||
Text("Goal Date").bold()
|
||||
DatePicker(
|
||||
$profile.goalDate,
|
||||
minimumDate: Calendar.current.date(byAdding: .year, value: -1, to: profile.goalDate),
|
||||
maximumDate: Calendar.current.date(byAdding: .year, value: 1, to: profile.goalDate),
|
||||
displayedComponents: .date
|
||||
)
|
||||
}
|
||||
.padding(.top)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct ProfileEditor_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ProfileEditor(profile: .constant(.default))
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
A view that hosts the profile viewer and editor.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ProfileHost: View {
|
||||
@Environment(\.editMode) var mode
|
||||
@State var profile = Profile.default
|
||||
@State var draftProfile = Profile.default
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 20) {
|
||||
HStack {
|
||||
if self.mode?.value == .active {
|
||||
Button(action: {
|
||||
self.profile = self.draftProfile
|
||||
self.mode?.animation().value = .inactive
|
||||
}) {
|
||||
Text("Done")
|
||||
}
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
EditButton()
|
||||
}
|
||||
if self.mode?.value == .inactive {
|
||||
ProfileSummary(profile: profile)
|
||||
} else {
|
||||
ProfileEditor(profile: $draftProfile)
|
||||
.onDisappear {
|
||||
self.draftProfile = self.profile
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct ProfileHost_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ProfileHost()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
A view that summarizes a profile.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ProfileSummary: View {
|
||||
var profile: Profile
|
||||
|
||||
static var goalFormat: DateFormatter {
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateFormat = "MMMM d, yyyy"
|
||||
return formatter
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
Text(profile.username)
|
||||
.bold()
|
||||
.font(.title)
|
||||
|
||||
Text("Notifications: \(self.profile.prefersNotifications ? "On": "Off" )")
|
||||
|
||||
Text("Seasonal Photos: \(self.profile.seasonalPhoto.rawValue)")
|
||||
|
||||
Text("Goal Date: \(self.profile.goalDate, formatter: Self.goalFormat)")
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
Text("Completed Badges")
|
||||
.font(.headline)
|
||||
ScrollView {
|
||||
HStack {
|
||||
HikeBadge(name: "First Hike")
|
||||
|
||||
HikeBadge(name: "Earth Day")
|
||||
.hueRotation(Angle(degrees: 90))
|
||||
|
||||
HikeBadge(name: "Tenth Hike")
|
||||
.grayscale(0.5)
|
||||
.hueRotation(Angle(degrees: 45))
|
||||
}
|
||||
}
|
||||
.frame(height: 140)
|
||||
}
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
Text("Recent Hikes")
|
||||
.font(.headline)
|
||||
|
||||
HikeView(hike: hikeData[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct ProfileSummary_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ProfileSummary(profile: Profile.default)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 34 KiB |
@@ -0,0 +1,182 @@
|
||||
[
|
||||
{
|
||||
"name": "Turtle Rock",
|
||||
"category": "Rivers",
|
||||
"city": "Twentynine Palms",
|
||||
"state": "California",
|
||||
"id": 1001,
|
||||
"isFeatured": true,
|
||||
"isFavorite": true,
|
||||
"park": "Joshua Tree National Park",
|
||||
"coordinates": {
|
||||
"longitude": -116.166868,
|
||||
"latitude": 34.011286
|
||||
},
|
||||
"imageName": "turtlerock"
|
||||
},
|
||||
{
|
||||
"name": "Silver Salmon Creek",
|
||||
"category": "Lakes",
|
||||
"city": "Port Alsworth",
|
||||
"state": "Alaska",
|
||||
"id": 1002,
|
||||
"isFeatured": false,
|
||||
"isFavorite": false,
|
||||
"park": "Lake Clark National Park and Preserve",
|
||||
"coordinates": {
|
||||
"longitude": -152.665167,
|
||||
"latitude": 59.980167
|
||||
},
|
||||
"imageName": "silversalmoncreek"
|
||||
},
|
||||
{
|
||||
"name": "Chilkoot Trail",
|
||||
"category": "Mountains",
|
||||
"city": "Skagway",
|
||||
"state": "Alaska",
|
||||
"id": 1003,
|
||||
"isFeatured": false,
|
||||
"isFavorite": true,
|
||||
"park": "Klondike Gold Rush National Historical Park",
|
||||
"coordinates": {
|
||||
"longitude": -135.334571,
|
||||
"latitude": 59.560551
|
||||
},
|
||||
"imageName": "chilkoottrail"
|
||||
},
|
||||
{
|
||||
"name": "St. Mary Lake",
|
||||
"category": "Lakes",
|
||||
"city": "Browning",
|
||||
"state": "Montana",
|
||||
"id": 1004,
|
||||
"isFeatured": true,
|
||||
"isFavorite": true,
|
||||
"park": "Glacier National Park",
|
||||
"coordinates": {
|
||||
"longitude": -113.536248,
|
||||
"latitude": 48.69423
|
||||
},
|
||||
"imageName": "stmarylake"
|
||||
},
|
||||
{
|
||||
"name": "Twin Lake",
|
||||
"category": "Lakes",
|
||||
"city": "Twin Lakes",
|
||||
"state": "Alaska",
|
||||
"id": 1005,
|
||||
"isFeatured": false,
|
||||
"isFavorite": false,
|
||||
"park": "Lake Clark National Park and Preserve",
|
||||
"coordinates": {
|
||||
"longitude": -153.849883,
|
||||
"latitude": 60.641684
|
||||
},
|
||||
"imageName": "twinlake"
|
||||
},
|
||||
{
|
||||
"name": "Lake McDonald",
|
||||
"category": "Mountains",
|
||||
"city": "West Glacier",
|
||||
"state": "Montana",
|
||||
"id": 1006,
|
||||
"isFeatured": false,
|
||||
"isFavorite": false,
|
||||
"park": "Glacier National Park",
|
||||
"coordinates": {
|
||||
"longitude": -113.934831,
|
||||
"latitude": 48.56002
|
||||
},
|
||||
"imageName": "lakemcdonald"
|
||||
},
|
||||
{
|
||||
"name": "Charley Rivers",
|
||||
"category": "Rivers",
|
||||
"city": "Eaking",
|
||||
"state": "Alaska",
|
||||
"id": 1007,
|
||||
"isFeatured": true,
|
||||
"isFavorite": false,
|
||||
"park": "Charley Rivers National Preserve",
|
||||
"coordinates": {
|
||||
"longitude": -143.122586,
|
||||
"latitude": 65.350021
|
||||
},
|
||||
"imageName": "charleyrivers",
|
||||
},
|
||||
{
|
||||
"name": "Icy Bay",
|
||||
"category": "Mountains",
|
||||
"city": "Icy Bay",
|
||||
"state": "Alaska",
|
||||
"id": 1008,
|
||||
"isFeatured": false,
|
||||
"isFavorite": false,
|
||||
"park": "Wrangell-St. Elias National Park and Preserve",
|
||||
"coordinates": {
|
||||
"longitude": -141.518167,
|
||||
"latitude": 60.089917
|
||||
},
|
||||
"imageName": "icybay"
|
||||
},
|
||||
{
|
||||
"name": "Rainbow Lake",
|
||||
"category": "Lakes",
|
||||
"city": "Willow",
|
||||
"state": "Alaska",
|
||||
"id": 1009,
|
||||
"isFeatured": false,
|
||||
"isFavorite": false,
|
||||
"park": "State Recreation Area",
|
||||
"coordinates": {
|
||||
"longitude": -150.086103,
|
||||
"latitude": 61.694334
|
||||
},
|
||||
"imageName": "rainbowlake"
|
||||
},
|
||||
{
|
||||
"name": "Hidden Lake",
|
||||
"category": "Lakes",
|
||||
"city": "Newhalem",
|
||||
"state": "Washington",
|
||||
"id": 1010,
|
||||
"isFeatured": false,
|
||||
"isFavorite": false,
|
||||
"park": "North Cascades National Park",
|
||||
"coordinates": {
|
||||
"longitude": -121.17799,
|
||||
"latitude": 48.495442
|
||||
},
|
||||
"imageName": "hiddenlake"
|
||||
},
|
||||
{
|
||||
"name": "Chincoteague",
|
||||
"category": "Rivers",
|
||||
"city": "Chincoteague",
|
||||
"state": "Virginia",
|
||||
"id": 1011,
|
||||
"isFeatured": false,
|
||||
"isFavorite": false,
|
||||
"park": "Chincoteague National Wildlife Refuge",
|
||||
"coordinates": {
|
||||
"longitude": -75.383212,
|
||||
"latitude": 37.91531
|
||||
},
|
||||
"imageName": "chincoteague"
|
||||
},
|
||||
{
|
||||
"name": "Lake Umbagog",
|
||||
"category": "Lakes",
|
||||
"city": "Errol",
|
||||
"state": "New Hampshire",
|
||||
"id": 1012,
|
||||
"isFeatured": false,
|
||||
"isFavorite": false,
|
||||
"park": "Umbagog National Wildlife Refuge",
|
||||
"coordinates": {
|
||||
"longitude": -71.056816,
|
||||
"latitude": 44.747408
|
||||
},
|
||||
"imageName": "umbagog"
|
||||
}
|
||||
]
|
||||
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 89 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 42 KiB |
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
The scene delegate.
|
||||
*/
|
||||
|
||||
import UIKit
|
||||
import SwiftUI
|
||||
|
||||
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||
|
||||
var window: UIWindow?
|
||||
|
||||
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
|
||||
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
|
||||
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
|
||||
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
|
||||
|
||||
// Use a UIHostingController as window root view controller
|
||||
let window = UIWindow(frame: UIScreen.main.bounds)
|
||||
window.rootViewController = UIHostingController(rootView: CategoryHome().environmentObject(UserData()))
|
||||
self.window = window
|
||||
window.makeKeyAndVisible()
|
||||
}
|
||||
|
||||
func sceneDidDisconnect(_ scene: UIScene) {
|
||||
// Called as the scene is being released by the system.
|
||||
// This occurs shortly after the scene enters the background, or when its session is discarded.
|
||||
// Release any resources associated with this scene that can be re-created the next time the scene connects.
|
||||
// The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
|
||||
}
|
||||
|
||||
func sceneDidBecomeActive(_ scene: UIScene) {
|
||||
// Called when the scene has moved from an inactive state to an active state.
|
||||
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
|
||||
}
|
||||
|
||||
func sceneWillResignActive(_ scene: UIScene) {
|
||||
// Called when the scene will move from an active state to an inactive state.
|
||||
// This may occur due to temporary interruptions (ex. an incoming phone call).
|
||||
}
|
||||
|
||||
func sceneWillEnterForeground(_ scene: UIScene) {
|
||||
// Called as the scene transitions from the background to the foreground.
|
||||
// Use this method to undo the changes made on entering the background.
|
||||
}
|
||||
|
||||
func sceneDidEnterBackground(_ scene: UIScene) {
|
||||
// Called as the scene transitions from the foreground to the background.
|
||||
// Use this method to save data, release shared resources, and store enough scene-specific state information
|
||||
// to restore the scene back to its current state.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
A view that displays a badge.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct Badge: View {
|
||||
static let rotationCount = 8
|
||||
|
||||
var badgeSymbols: some View {
|
||||
ForEach(0..<Badge.rotationCount) { i in
|
||||
RotatedBadgeSymbol(
|
||||
angle: .degrees(Double(i) / Double(Badge.rotationCount)) * 360.0)
|
||||
}
|
||||
.opacity(0.5)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
BadgeBackground()
|
||||
|
||||
GeometryReader { geometry in
|
||||
self.badgeSymbols
|
||||
.scaleEffect(1.0 / 4.0, anchor: .top)
|
||||
.position(x: geometry.size.width / 2.0, y: (3.0 / 4.0) * geometry.size.height)
|
||||
}
|
||||
}
|
||||
.scaledToFit()
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct Badge_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Badge()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
A view that displays the background of a badge.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct BadgeBackground: View {
|
||||
var body: some View {
|
||||
GeometryReader { geometry in
|
||||
Path { path in
|
||||
var width: CGFloat = min(geometry.size.width, geometry.size.height)
|
||||
let height = width
|
||||
let xScale: CGFloat = 0.832
|
||||
let xOffset = (width * (1.0 - xScale)) / 2.0
|
||||
width *= xScale
|
||||
path.move(
|
||||
to: CGPoint(
|
||||
x: xOffset + width * 0.95,
|
||||
y: height * (0.20 + HexagonParameters.adjustment)
|
||||
)
|
||||
)
|
||||
|
||||
HexagonParameters.points.forEach {
|
||||
path.addLine(
|
||||
to: .init(
|
||||
x: xOffset + width * $0.useWidth.0 * $0.xFactors.0,
|
||||
y: height * $0.useHeight.0 * $0.yFactors.0
|
||||
)
|
||||
)
|
||||
|
||||
path.addQuadCurve(
|
||||
to: .init(
|
||||
x: xOffset + width * $0.useWidth.1 * $0.xFactors.1,
|
||||
y: height * $0.useHeight.1 * $0.yFactors.1
|
||||
),
|
||||
control: .init(
|
||||
x: xOffset + width * $0.useWidth.2 * $0.xFactors.2,
|
||||
y: height * $0.useHeight.2 * $0.yFactors.2
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
.fill(LinearGradient(
|
||||
gradient: .init(colors: [Self.gradientStart, Self.gradientEnd]),
|
||||
startPoint: .init(x: 0.5, y: 0),
|
||||
endPoint: .init(x: 0.5, y: 0.6)
|
||||
))
|
||||
.aspectRatio(1, contentMode: .fit)
|
||||
}
|
||||
}
|
||||
static let gradientStart = Color(red: 239.0 / 255, green: 120.0 / 255, blue: 221.0 / 255)
|
||||
static let gradientEnd = Color(red: 239.0 / 255, green: 172.0 / 255, blue: 120.0 / 255)
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct BadgeBackground_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
BadgeBackground()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
A view that display a symbol in a badge.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct BadgeSymbol: View {
|
||||
static let symbolColor = Color(red: 79.0 / 255, green: 79.0 / 255, blue: 191.0 / 255)
|
||||
|
||||
var body: some View {
|
||||
GeometryReader { geometry in
|
||||
Path { path in
|
||||
let width = min(geometry.size.width, geometry.size.height)
|
||||
let height = width * 0.75
|
||||
let spacing = width * 0.030
|
||||
let middle = width / 2
|
||||
let topWidth = 0.226 * width
|
||||
let topHeight = 0.488 * height
|
||||
|
||||
path.addLines([
|
||||
CGPoint(x: middle, y: spacing),
|
||||
CGPoint(x: middle - topWidth, y: topHeight - spacing),
|
||||
CGPoint(x: middle, y: topHeight / 2 + spacing),
|
||||
CGPoint(x: middle + topWidth, y: topHeight - spacing),
|
||||
CGPoint(x: middle, y: spacing)
|
||||
])
|
||||
|
||||
path.move(to: CGPoint(x: middle, y: topHeight / 2 + spacing * 3))
|
||||
path.addLines([
|
||||
CGPoint(x: middle - topWidth, y: topHeight + spacing),
|
||||
CGPoint(x: spacing, y: height - spacing),
|
||||
CGPoint(x: width - spacing, y: height - spacing),
|
||||
CGPoint(x: middle + topWidth, y: topHeight + spacing),
|
||||
CGPoint(x: middle, y: topHeight / 2 + spacing * 3)
|
||||
])
|
||||
}
|
||||
.fill(Self.symbolColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct BadgeSymbol_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
BadgeSymbol()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
A view that clips an image to a circle and adds a stroke and shadow.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct CircleImage: View {
|
||||
var image: Image
|
||||
|
||||
var body: some View {
|
||||
image
|
||||
.clipShape(Circle())
|
||||
.overlay(Circle().stroke(Color.white, lineWidth: 4))
|
||||
.shadow(radius: 10)
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct CircleImage_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
CircleImage(image: Image("turtlerock"))
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
A view that shows a featured landmark.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct FeatureCard: View {
|
||||
var landmark: Landmark
|
||||
|
||||
var body: some View {
|
||||
landmark.featureImage?
|
||||
.resizable()
|
||||
.aspectRatio(3 / 2, contentMode: .fit)
|
||||
.overlay(TextOverlay(landmark: landmark))
|
||||
}
|
||||
}
|
||||
|
||||
struct TextOverlay: View {
|
||||
var landmark: Landmark
|
||||
|
||||
var gradient: LinearGradient {
|
||||
LinearGradient(
|
||||
gradient: Gradient(
|
||||
colors: [Color.black.opacity(0.6), Color.black.opacity(0)]),
|
||||
startPoint: .bottom,
|
||||
endPoint: .center)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ZStack(alignment: .bottomLeading) {
|
||||
Rectangle().fill(gradient)
|
||||
VStack(alignment: .leading) {
|
||||
Text(landmark.name)
|
||||
.font(.title)
|
||||
.bold()
|
||||
Text(landmark.park)
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.foregroundColor(.white)
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct FeatureCard_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
FeatureCard(landmark: features[0])
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
A single line in the graph.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct GraphCapsule: View {
|
||||
var index: Int
|
||||
var height: Length
|
||||
var range: Range<Double>
|
||||
var overallRange: Range<Double>
|
||||
|
||||
var heightRatio: Length {
|
||||
max(Length(magnitude(of: range) / magnitude(of: overallRange)), 0.15)
|
||||
}
|
||||
|
||||
var offsetRatio: Length {
|
||||
Length((range.lowerBound - overallRange.lowerBound) / magnitude(of: overallRange))
|
||||
}
|
||||
|
||||
var animation: Animation {
|
||||
Animation.spring(initialVelocity: 5)
|
||||
.speed(2)
|
||||
.delay(0.03 * Double(index))
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Capsule()
|
||||
.fill(Color.white)
|
||||
.frame(height: height * heightRatio, alignment: .bottom)
|
||||
.offset(x: 0, y: height * -offsetRatio)
|
||||
.animation(animation)
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct GraphCapsule_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
GraphCapsule(index: 0, height: 150, range: 10..<50, overallRange: 0..<100)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
The elevation, heart rate, and pace of a hike plotted on a graph.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
|
||||
func rangeOfRanges<C: Collection>(_ ranges: C) -> Range<Double>
|
||||
where C.Element == Range<Double> {
|
||||
guard !ranges.isEmpty else { return 0..<0 }
|
||||
let low = ranges.lazy.map { $0.lowerBound }.min()!
|
||||
let high = ranges.lazy.map { $0.upperBound }.max()!
|
||||
return low..<high
|
||||
}
|
||||
|
||||
func magnitude(of range: Range<Double>) -> Double {
|
||||
return range.upperBound - range.lowerBound
|
||||
}
|
||||
|
||||
struct HikeGraph: View {
|
||||
var hike: Hike
|
||||
var path: KeyPath<Hike.Observation, Range<Double>>
|
||||
|
||||
var color: Color {
|
||||
switch path {
|
||||
case \.elevation:
|
||||
return .gray
|
||||
case \.heartRate:
|
||||
return Color(hue: 0, saturation: 0.5, brightness: 0.7)
|
||||
case \.pace:
|
||||
return Color(hue: 0.7, saturation: 0.4, brightness: 0.7)
|
||||
default:
|
||||
return .black
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
let data = hike.observations
|
||||
let overallRange = rangeOfRanges(data.lazy.map { $0[keyPath: self.path] })
|
||||
let maxMagnitude = data.map { magnitude(of: $0[keyPath: path]) }.max()!
|
||||
let heightRatio = 1 - Length(maxMagnitude / magnitude(of: overallRange))
|
||||
|
||||
return GeometryReader { proxy in
|
||||
HStack(alignment: .bottom, spacing: proxy.size.width / 120) {
|
||||
ForEach(data.indices) { index in
|
||||
GraphCapsule(
|
||||
index: index,
|
||||
height: proxy.size.height,
|
||||
range: data[index][keyPath: self.path],
|
||||
overallRange: overallRange)
|
||||
.colorMultiply(self.color)
|
||||
}
|
||||
.offset(x: 0, y: proxy.size.height * heightRatio)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct HikeGraph_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
HikeGraph(hike: hikeData[0], path: \.elevation)
|
||||
.frame(height: 200)
|
||||
HikeGraph(hike: hikeData[0], path: \.heartRate)
|
||||
.frame(height: 200)
|
||||
HikeGraph(hike: hikeData[0], path: \.pace)
|
||||
.frame(height: 200)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
A single row to be displayed in a list of landmarks.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct LandmarkRow: View {
|
||||
var landmark: Landmark
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
landmark.image(forSize: 50)
|
||||
Text(verbatim: landmark.name)
|
||||
Spacer()
|
||||
|
||||
if landmark.isFavorite {
|
||||
Image(systemName: "star.fill")
|
||||
.imageScale(.medium)
|
||||
.foregroundColor(.yellow)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct LandmarkRow_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
LandmarkRow(landmark: landmarkData[0])
|
||||
LandmarkRow(landmark: landmarkData[1])
|
||||
}
|
||||
.previewLayout(.fixed(width: 300, height: 70))
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
A view that hosts an `MKMapView`.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
import MapKit
|
||||
|
||||
struct MapView: UIViewRepresentable {
|
||||
var coordinate: CLLocationCoordinate2D
|
||||
|
||||
func makeUIView(context: Context) -> MKMapView {
|
||||
MKMapView(frame: .zero)
|
||||
}
|
||||
|
||||
func updateUIView(_ view: MKMapView, context: Context) {
|
||||
let span = MKCoordinateSpan(latitudeDelta: 0.02, longitudeDelta: 0.02)
|
||||
let region = MKCoordinateRegion(center: coordinate, span: span)
|
||||
view.setRegion(region, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct MapView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
MapView(coordinate: landmarkData[0].locationCoordinate)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
A view that displays a rotated version of a badge symbol.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct RotatedBadgeSymbol: View {
|
||||
let angle: Angle
|
||||
|
||||
var body: some View {
|
||||
BadgeSymbol()
|
||||
.padding(-60)
|
||||
.rotationEffect(angle, anchor: .bottom)
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct RotatedBadgeSymbol_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
RotatedBadgeSymbol(angle: .init(degrees: 5))
|
||||
}
|
||||
}
|
||||
#endif
|
||||