diff --git a/MartHoliday/MartHoliday.xcodeproj/project.pbxproj b/MartHoliday/MartHoliday.xcodeproj/project.pbxproj index d710d01..3b5e3c4 100644 --- a/MartHoliday/MartHoliday.xcodeproj/project.pbxproj +++ b/MartHoliday/MartHoliday.xcodeproj/project.pbxproj @@ -18,6 +18,8 @@ FD0202902146559B0083BE22 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC2A941212458F400A1E2FF /* Extensions.swift */; }; FD0202912146565C0083BE22 /* MartHolidayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD0202612146517B0083BE22 /* MartHolidayTests.swift */; }; FD0371D82208121800B2055F /* DistanceSearch.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD0371D72208121800B2055F /* DistanceSearch.swift */; }; + FD086D7F22A3B54600030929 /* DistanceSlider.xib in Resources */ = {isa = PBXBuildFile; fileRef = FD086D7E22A3B54600030929 /* DistanceSlider.xib */; }; + FD086D8122A3B59200030929 /* DistanceSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD086D8022A3B59200030929 /* DistanceSlider.swift */; }; FD11EAE321203A4C003EB3E9 /* BranchTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD11EAE221203A4C003EB3E9 /* BranchTableViewCell.swift */; }; FD15A11021F38DBB00B7276A /* LocationSearchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD15A10F21F38DBB00B7276A /* LocationSearchViewController.swift */; }; FD1B4F212126BB8B00946311 /* SlideBackgroundView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD1B4F202126BB8B00946311 /* SlideBackgroundView.swift */; }; @@ -104,9 +106,12 @@ FDEECC32214D002700F6FF09 /* NanumSquareRoundOTFR.otf in Resources */ = {isa = PBXBuildFile; fileRef = FDAF601D21273E880006B68A /* NanumSquareRoundOTFR.otf */; }; FDEECC33214D0C6500F6FF09 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FDB4BE28211D6BAE00D3B264 /* Assets.xcassets */; }; FDEEE8E82163B5BD00E63733 /* NoMapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDEEE8E72163B5BD00E63733 /* NoMapView.swift */; }; + FDF492C722B4E59100827025 /* MarkerInfoWindowView.xib in Resources */ = {isa = PBXBuildFile; fileRef = FDF492C622B4E59100827025 /* MarkerInfoWindowView.xib */; }; + FDF492C922B4E59C00827025 /* MarkerInfoWindowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF492C822B4E59C00827025 /* MarkerInfoWindowView.swift */; }; FDF8ABC2215B722800DA74C9 /* FavoriteBranch.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF8ABC1215B722800DA74C9 /* FavoriteBranch.swift */; }; FDF8ABC4215B76B400DA74C9 /* MainTableViewHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF8ABC3215B76B400DA74C9 /* MainTableViewHeader.swift */; }; FDF8ABC6215B76FC00DA74C9 /* MainTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF8ABC5215B76FC00DA74C9 /* MainTableViewCell.swift */; }; + FDFF1CD522E455520045220F /* TickMarkSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDFF1CD422E455520045220F /* TickMarkSlider.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -165,6 +170,8 @@ FD0202612146517B0083BE22 /* MartHolidayTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MartHolidayTests.swift; sourceTree = ""; }; FD0202632146517B0083BE22 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; FD0371D72208121800B2055F /* DistanceSearch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DistanceSearch.swift; sourceTree = ""; }; + FD086D7E22A3B54600030929 /* DistanceSlider.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = DistanceSlider.xib; sourceTree = ""; }; + FD086D8022A3B59200030929 /* DistanceSlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = DistanceSlider.swift; path = View/DistanceSlider.swift; sourceTree = ""; }; FD11EAE221203A4C003EB3E9 /* BranchTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BranchTableViewCell.swift; sourceTree = ""; }; FD15A10F21F38DBB00B7276A /* LocationSearchViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationSearchViewController.swift; sourceTree = ""; }; FD1B4F202126BB8B00946311 /* SlideBackgroundView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SlideBackgroundView.swift; sourceTree = ""; }; @@ -242,10 +249,13 @@ FDE2542D21627303008B25C8 /* NoMapView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NoMapView.xib; sourceTree = ""; }; FDEECC2C214CD3BD00F6FF09 /* MartHolidayTodayExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = MartHolidayTodayExtension.entitlements; sourceTree = ""; }; FDEEE8E72163B5BD00E63733 /* NoMapView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoMapView.swift; sourceTree = ""; }; + FDF492C622B4E59100827025 /* MarkerInfoWindowView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MarkerInfoWindowView.xib; sourceTree = ""; }; + FDF492C822B4E59C00827025 /* MarkerInfoWindowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarkerInfoWindowView.swift; sourceTree = ""; }; FDF8ABC1215B722800DA74C9 /* FavoriteBranch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoriteBranch.swift; sourceTree = ""; }; FDF8ABC3215B76B400DA74C9 /* MainTableViewHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTableViewHeader.swift; sourceTree = ""; }; FDF8ABC5215B76FC00DA74C9 /* MainTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTableViewCell.swift; sourceTree = ""; }; FDFB0344212E7AF10092411E /* MartHoliday.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = MartHoliday.entitlements; sourceTree = ""; }; + FDFF1CD422E455520045220F /* TickMarkSlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TickMarkSlider.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -321,6 +331,9 @@ FDC19BA9215D2D54007D9A95 /* NoDataView.swift */, FDEEE8E72163B5BD00E63733 /* NoMapView.swift */, FD5359FD225F8BDB00AB48BE /* MartMapView.swift */, + FDF492C822B4E59C00827025 /* MarkerInfoWindowView.swift */, + FDF492C622B4E59100827025 /* MarkerInfoWindowView.xib */, + FDFF1CD422E455520045220F /* TickMarkSlider.swift */, ); path = View; sourceTree = ""; @@ -452,6 +465,8 @@ FD9F40A2211ECB26007D7F1B /* Utility */, FDAF601A21273D9F0006B68A /* fonts */, FDB4BE25211D6BAD00D3B264 /* Main.storyboard */, + FD086D7E22A3B54600030929 /* DistanceSlider.xib */, + FD086D8022A3B59200030929 /* DistanceSlider.swift */, FDE2542D21627303008B25C8 /* NoMapView.xib */, FD80CE282161241D00C16150 /* DetailHeaderView.xib */, FD4850F521287AFE0064747A /* SlideMenuCellView.xib */, @@ -519,7 +534,7 @@ FD3B64262121BEAA003C1332 /* Embed Frameworks */, FD3B642A2121C316003C1332 /* ShellScript */, FD859869214BE9FA00C1A3E2 /* Embed App Extensions */, - 29CE85A4F13D65ACAAEA4B3F /* [CP] Embed Pods Frameworks */, + FC6236A145B51B361DF6CBE0 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -617,8 +632,10 @@ buildActionMask = 2147483647; files = ( FD66C2812158F6F800B4F823 /* MainHeaderView.xib in Resources */, + FD086D7F22A3B54600030929 /* DistanceSlider.xib in Resources */, FDAF602221273E880006B68A /* NanumSquareRoundOTFEB.otf in Resources */, FDAF602021273E880006B68A /* NanumSquareRoundOTFB.otf in Resources */, + FDF492C722B4E59100827025 /* MarkerInfoWindowView.xib in Resources */, FD2B746E218A395F00A2BC9E /* SlideMenuView.xib in Resources */, FDAF602121273E880006B68A /* NanumSquareRoundOTFR.otf in Resources */, FDB26C5B2170711400313A02 /* InfoPlist.strings in Resources */, @@ -655,25 +672,25 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - 29CE85A4F13D65ACAAEA4B3F /* [CP] Embed Pods Frameworks */ = { + A2941B5A4530CD89F3490E62 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( - "${SRCROOT}/Pods/Target Support Files/Pods-MartHoliday/Pods-MartHoliday-frameworks.sh", - "${PODS_ROOT}/NMapsMap/framework/NMapsMap.framework", + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", ); - name = "[CP] Embed Pods Frameworks"; + name = "[CP] Check Pods Manifest.lock"; outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/NMapsMap.framework", + "$(DERIVED_FILE_DIR)/Pods-MartHolidayTests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-MartHoliday/Pods-MartHoliday-frameworks.sh\"\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - A2941B5A4530CD89F3490E62 /* [CP] Check Pods Manifest.lock */ = { + D58D45C640227BDC65F7A689 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -684,29 +701,29 @@ ); name = "[CP] Check Pods Manifest.lock"; outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-MartHolidayTests-checkManifestLockResult.txt", + "$(DERIVED_FILE_DIR)/Pods-MartHolidayTodayExtension-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - D58D45C640227BDC65F7A689 /* [CP] Check Pods Manifest.lock */ = { + FC6236A145B51B361DF6CBE0 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", + "${SRCROOT}/Pods/Target Support Files/Pods-MartHoliday/Pods-MartHoliday-frameworks.sh", + "${PODS_ROOT}/NMapsMap/framework/NMapsMap.framework", ); - name = "[CP] Check Pods Manifest.lock"; + name = "[CP] Embed Pods Frameworks"; outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-MartHolidayTodayExtension-checkManifestLockResult.txt", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/NMapsMap.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-MartHoliday/Pods-MartHoliday-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; FD3B642A2121C316003C1332 /* ShellScript */ = { @@ -769,6 +786,7 @@ FDBF9A4821240911001C2DAA /* DataStorage.swift in Sources */, FD1B4F212126BB8B00946311 /* SlideBackgroundView.swift in Sources */, FD9F40A0211EC5EA007D7F1B /* Mart.swift in Sources */, + FD086D8122A3B59200030929 /* DistanceSlider.swift in Sources */, FD80CE2B21612BAE00C16150 /* HolidayHeaderView.swift in Sources */, FD7087DF216B427700A2A16F /* FavoriteData.swift in Sources */, FDB4BE24211D6BAD00D3B264 /* MartSelectViewController.swift in Sources */, @@ -791,6 +809,7 @@ FD5359FE225F8BDB00AB48BE /* MartMapView.swift in Sources */, FD9F409C211EBFAF007D7F1B /* BranchRawData.swift in Sources */, FDC5A7422167CD50009F0B0C /* TodayExtensionTableViewCell.swift in Sources */, + FDFF1CD522E455520045220F /* TickMarkSlider.swift in Sources */, FDF8ABC6215B76FC00DA74C9 /* MainTableViewCell.swift in Sources */, FDB3AD67216F94FD002209A2 /* StorageAPI.swift in Sources */, FD91364E216EF70B001A21DF /* AppInfoViewController.swift in Sources */, @@ -808,6 +827,7 @@ FD1CC4E1211DF76300B21E09 /* DetailViewController.swift in Sources */, FD0371D82208121800B2055F /* DistanceSearch.swift in Sources */, FD93878E225A39420082CC71 /* APIResponse.swift in Sources */, + FDF492C922B4E59C00827025 /* MarkerInfoWindowView.swift in Sources */, FD15A11021F38DBB00B7276A /* LocationSearchViewController.swift in Sources */, FDB3AD69216FBA7F002209A2 /* NetworkManager.swift in Sources */, FD11EAE321203A4C003EB3E9 /* BranchTableViewCell.swift in Sources */, diff --git a/MartHoliday/MartHoliday/Assets.xcassets/distanceMinus.imageset/Contents.json b/MartHoliday/MartHoliday/Assets.xcassets/distanceMinus.imageset/Contents.json new file mode 100644 index 0000000..6f8f419 --- /dev/null +++ b/MartHoliday/MartHoliday/Assets.xcassets/distanceMinus.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "minus.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "minus (1).png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MartHoliday/MartHoliday/Assets.xcassets/distanceMinus.imageset/minus (1).png b/MartHoliday/MartHoliday/Assets.xcassets/distanceMinus.imageset/minus (1).png new file mode 100644 index 0000000..1589093 Binary files /dev/null and b/MartHoliday/MartHoliday/Assets.xcassets/distanceMinus.imageset/minus (1).png differ diff --git a/MartHoliday/MartHoliday/Assets.xcassets/distanceMinus.imageset/minus.png b/MartHoliday/MartHoliday/Assets.xcassets/distanceMinus.imageset/minus.png new file mode 100644 index 0000000..58cf180 Binary files /dev/null and b/MartHoliday/MartHoliday/Assets.xcassets/distanceMinus.imageset/minus.png differ diff --git a/MartHoliday/MartHoliday/Assets.xcassets/distancePlus.imageset/Contents.json b/MartHoliday/MartHoliday/Assets.xcassets/distancePlus.imageset/Contents.json new file mode 100644 index 0000000..99d8850 --- /dev/null +++ b/MartHoliday/MartHoliday/Assets.xcassets/distancePlus.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "plus.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "plus (1).png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MartHoliday/MartHoliday/Assets.xcassets/distancePlus.imageset/plus (1).png b/MartHoliday/MartHoliday/Assets.xcassets/distancePlus.imageset/plus (1).png new file mode 100644 index 0000000..441f44e Binary files /dev/null and b/MartHoliday/MartHoliday/Assets.xcassets/distancePlus.imageset/plus (1).png differ diff --git a/MartHoliday/MartHoliday/Assets.xcassets/distancePlus.imageset/plus.png b/MartHoliday/MartHoliday/Assets.xcassets/distancePlus.imageset/plus.png new file mode 100644 index 0000000..09023c8 Binary files /dev/null and b/MartHoliday/MartHoliday/Assets.xcassets/distancePlus.imageset/plus.png differ diff --git a/MartHoliday/MartHoliday/Assets.xcassets/focus.imageset/Contents.json b/MartHoliday/MartHoliday/Assets.xcassets/focus.imageset/Contents.json new file mode 100644 index 0000000..7dfc62f --- /dev/null +++ b/MartHoliday/MartHoliday/Assets.xcassets/focus.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "focus.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "focus (1).png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MartHoliday/MartHoliday/Assets.xcassets/focus.imageset/focus (1).png b/MartHoliday/MartHoliday/Assets.xcassets/focus.imageset/focus (1).png new file mode 100644 index 0000000..395ff03 Binary files /dev/null and b/MartHoliday/MartHoliday/Assets.xcassets/focus.imageset/focus (1).png differ diff --git a/MartHoliday/MartHoliday/Assets.xcassets/focus.imageset/focus.png b/MartHoliday/MartHoliday/Assets.xcassets/focus.imageset/focus.png new file mode 100644 index 0000000..b42c38e Binary files /dev/null and b/MartHoliday/MartHoliday/Assets.xcassets/focus.imageset/focus.png differ diff --git a/MartHoliday/MartHoliday/Assets.xcassets/target.imageset/Contents.json b/MartHoliday/MartHoliday/Assets.xcassets/target.imageset/Contents.json new file mode 100644 index 0000000..8548123 --- /dev/null +++ b/MartHoliday/MartHoliday/Assets.xcassets/target.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "target (2).png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MartHoliday/MartHoliday/Assets.xcassets/target.imageset/target (2).png b/MartHoliday/MartHoliday/Assets.xcassets/target.imageset/target (2).png new file mode 100644 index 0000000..32c2cd7 Binary files /dev/null and b/MartHoliday/MartHoliday/Assets.xcassets/target.imageset/target (2).png differ diff --git a/MartHoliday/MartHoliday/Base.lproj/Main.storyboard b/MartHoliday/MartHoliday/Base.lproj/Main.storyboard index 25d8ba3..2bd7e7f 100644 --- a/MartHoliday/MartHoliday/Base.lproj/Main.storyboard +++ b/MartHoliday/MartHoliday/Base.lproj/Main.storyboard @@ -1,6 +1,6 @@ - + @@ -11,6 +11,9 @@ + + NanumSquareRoundOTFB + NanumSquareRoundOTFR @@ -21,28 +24,28 @@ - + - + - + - + @@ -85,18 +88,18 @@ - + - + - + - + - + - + - + - + - + @@ -430,17 +433,17 @@ - + - + Cgo @@ -477,38 +480,11 @@ Cgo - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -516,41 +492,111 @@ Cgo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + - - + - + + + + + + + + + + + - + - + - + - + - - + diff --git a/MartHoliday/MartHoliday/DistanceSlider.xib b/MartHoliday/MartHoliday/DistanceSlider.xib new file mode 100644 index 0000000..7fbf23b --- /dev/null +++ b/MartHoliday/MartHoliday/DistanceSlider.xib @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MartHoliday/MartHoliday/Model/BranchList.swift b/MartHoliday/MartHoliday/Model/BranchList.swift index 2f2842f..af7a108 100644 --- a/MartHoliday/MartHoliday/Model/BranchList.swift +++ b/MartHoliday/MartHoliday/Model/BranchList.swift @@ -93,7 +93,7 @@ class Branch: NSObject, Comparable { private func martName() -> String { switch self.martType { case "홈플러스 익스프레스": return "홈플러스EX" - case "이마트 트레이더스": return "이마트" + case "이마트 트레이더스": return "트레이더스" default: return martType } } diff --git a/MartHoliday/MartHoliday/Model/DistanceSearch.swift b/MartHoliday/MartHoliday/Model/DistanceSearch.swift index 615af2f..faf290b 100644 --- a/MartHoliday/MartHoliday/Model/DistanceSearch.swift +++ b/MartHoliday/MartHoliday/Model/DistanceSearch.swift @@ -7,30 +7,53 @@ // import Foundation +import NMapsMap class DistanceSearch { - class func fetch(geoPoint: NGeoPoint, distance: Int, handler: @escaping ([BranchRawData]) -> Void) { + class func fetch(geoPoint: NMGLatLng, distance: Int, handler: @escaping ([BranchRawData]) -> Void) { guard let value = KeyInfoLoader.loadValue(of: .BaseURL) else { return } var urlComponents = URLComponents(string: value) urlComponents?.queryItems = [ - URLQueryItem(name: "latitude", value: String(geoPoint.latitude)), - URLQueryItem(name: "longitude", value: String(geoPoint.longitude)), + URLQueryItem(name: "latitude", value: String(geoPoint.lat)), + URLQueryItem(name: "longitude", value: String(geoPoint.lng)), URLQueryItem(name: "distance", value: String(distance)) ] guard let url = urlComponents?.url else { return } URLSession.shared.dataTask(with: url) { (data, response, error) in - var branches = [BranchRawData]() + var apiResponse = APIResponse() + if let response = response as? HTTPURLResponse, 200...299 ~= response.statusCode, let data = data { do { - branches = try JSONDecoder().decode([BranchRawData].self, from: data, keyPath: "data") - handler(branches) + apiResponse = try JSONDecoder().decode(APIResponse.self, from: data) + if let branches = apiResponse.branches { + handler(branches) + } else { + NotificationCenter.default.post(name: .apiErrorAlertPopup, object: nil) + let apiErrorMessage = APIErrorMessage(brokenUrl: url, + httpStatusCode: response.statusCode, + data: data, + apiResponse: apiResponse, + type: .Data) + SlackWebhook.fire(message: apiErrorMessage.body()) + } } catch { - + NotificationCenter.default.post(name: .apiErrorAlertPopup, object: nil) + let apiErrorMessage = APIErrorMessage(brokenUrl: url, + httpStatusCode: response.statusCode, + data: data, + apiResponse: apiResponse, + type: .Parsing) + SlackWebhook.fire(message: apiErrorMessage.body()) } } else { - + NotificationCenter.default.post(name: .apiErrorAlertPopup, object: nil) + let apiErrorMessage = APIErrorMessage(brokenUrl: url, + data: data, + apiResponse: apiResponse, + type: .Network) + SlackWebhook.fire(message: apiErrorMessage.body()) } }.resume() } diff --git a/MartHoliday/MartHoliday/Model/GeoPoint.swift b/MartHoliday/MartHoliday/Model/GeoPoint.swift index 8b224b7..2d7aa26 100644 --- a/MartHoliday/MartHoliday/Model/GeoPoint.swift +++ b/MartHoliday/MartHoliday/Model/GeoPoint.swift @@ -9,23 +9,23 @@ import Foundation import NMapsMap -class GeoPoint { - var latitude: Double - var longitude: Double - - var NMapPoint: NMGLatLng { - return NMGLatLng(lat: self.latitude, lng: self.longitude) - } - - init(lat: Double, lng: Double) { - self.latitude = lat - self.longitude = lng - } - -} - -extension NMGLatLng { - convenience init(geoPoint: GeoPoint) { - self.init(lat: geoPoint.latitude, lng: geoPoint.longitude) - } -} +//class GeoPoint { +// var latitude: Double +// var longitude: Double +// +// var NMapPoint: NMGLatLng { +// return NMGLatLng(lat: self.latitude, lng: self.longitude) +// } +// +// init(lat: Double, lng: Double) { +// self.latitude = lat +// self.longitude = lng +// } +// +//} +// +//extension NMGLatLng { +// convenience init(geoPoint: GeoPoint) { +// self.init(lat: geoPoint.latitude, lng: geoPoint.longitude) +// } +//} diff --git a/MartHoliday/MartHoliday/Model/SlideMenuData.swift b/MartHoliday/MartHoliday/Model/SlideMenuData.swift index 6bb70e1..94195cf 100644 --- a/MartHoliday/MartHoliday/Model/SlideMenuData.swift +++ b/MartHoliday/MartHoliday/Model/SlideMenuData.swift @@ -11,7 +11,7 @@ import Foundation enum SlideMenu: CaseIterable { case main case select -// case location + case location case sendMail case appInfo @@ -19,7 +19,7 @@ enum SlideMenu: CaseIterable { switch self { case .main: return MenuDatum(title: "메인으로", imageName: "home") case .select: return MenuDatum(title: "마트검색", imageName: "search-2") -// case .location: return MenuDatum(title: "위치검색", imageName: "location-search") + case .location: return MenuDatum(title: "위치검색", imageName: "location-search") case .sendMail: return MenuDatum(title: "문의하기", imageName: "mail") case .appInfo: return MenuDatum(title: "앱 정보", imageName: "appinfo") } diff --git a/MartHoliday/MartHoliday/Utility/Extensions.swift b/MartHoliday/MartHoliday/Utility/Extensions.swift index 22dea49..34c80a0 100644 --- a/MartHoliday/MartHoliday/Utility/Extensions.swift +++ b/MartHoliday/MartHoliday/Utility/Extensions.swift @@ -13,6 +13,8 @@ extension Notification.Name { static let slideMenuTapped = Notification.Name("slideMenuClose") static let mapViewTapped = Notification.Name("mapViewTapped") static let connectionStatus = Notification.Name("connectionStatus") + static let apiErrorAlertPopup = Notification.Name("apiErrorAlertPopup") + static let completeFetchNearMart = Notification.Name("completeFetchNearMart") } enum AppColor: CustomStringConvertible { @@ -120,62 +122,6 @@ extension UILabel { } } -//extension NMapView { -// -// func setMapGesture(enable: Bool) { -// self.setPanEnabled(enable) -// self.setZoomEnabled(enable) -// self.isMultipleTouchEnabled = enable -// } -// -// -// func showMarker(at point: NGeoPoint) { -// -// if let mapOverlayManager = self.mapOverlayManager { -// -// if let poiDataOverlay = mapOverlayManager.newPOIdataOverlay() { -// -// poiDataOverlay.initPOIdata(1) -// -// poiDataOverlay.addPOIitem(atLocation: NGeoPoint(longitude: point.longitude, latitude: point.latitude), title: "", type: UserPOIflagTypeDefault, iconIndex: 0, with: nil) -// -// poiDataOverlay.endPOIdata() -// poiDataOverlay.showAllPOIdata() -// } -// } -// } -// -// func showMarkers(at poiData: POIData?) { -// -// if let mapOverlayManager = self.mapOverlayManager { -// guard let poiData = poiData else { return } -// -// // create POI data overlay -// if let poiDataOverlay = mapOverlayManager.newPOIdataOverlay() { -// -// poiDataOverlay.initPOIdata(Int32(poiData.count)) -// -// for i in 0.. Double { + return Double(floor(pow(10.0, Double(places)) * self) / pow(10.0, Double(places))) + } +} diff --git a/MartHoliday/MartHoliday/View/DistanceSlider.swift b/MartHoliday/MartHoliday/View/DistanceSlider.swift new file mode 100644 index 0000000..bdb3ed8 --- /dev/null +++ b/MartHoliday/MartHoliday/View/DistanceSlider.swift @@ -0,0 +1,15 @@ +// +// DistanceSlider.swift +// MartHoliday +// +// Created by YOUTH2 on 02/06/2019. +// Copyright © 2019 JINiOS. All rights reserved. +// + +import UIKit + +class DistanceSlider: UIView { + + + +} diff --git a/MartHoliday/MartHoliday/View/MarkerInfoWindowView.swift b/MartHoliday/MartHoliday/View/MarkerInfoWindowView.swift new file mode 100644 index 0000000..8f7f37e --- /dev/null +++ b/MartHoliday/MartHoliday/View/MarkerInfoWindowView.swift @@ -0,0 +1,57 @@ +// +// MarkerInfoWindowView.swift +// MartHoliday +// +// Created by YOUTH2 on 15/06/2019. +// Copyright © 2019 JINiOS. All rights reserved. +// + +import UIKit +import NMapsMap + +class MarkerInfoWindowDataSource: NSObject, NMFOverlayImageDataSource { + + var branch: Branch? + + func view(with overlay: NMFOverlay) -> UIView { + let markerInfoView = MarkerInfoWindowView(branch: self.branch) + return markerInfoView.make() + } + +} + +class MarkerInfoWindowView: UIView { + + @IBOutlet weak var contentView: UIView! + @IBOutlet weak var branchTitle: UILabel! + var branch: Branch? + + override init(frame: CGRect) { + super.init(frame: frame) + self.commonInit() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + self.commonInit() + } + + convenience init(branch: Branch?) { + self.init(frame: CGRect(x: 100, y: 100, width: 100, height: 100)) + self.branch = branch + } + + private func commonInit() { + Bundle.main.loadNibNamed("MarkerInfoWindowView", owner: self, options: nil) + contentView.autoresizingMask = [.flexibleHeight, .flexibleWidth] + } + + func make() -> UIView { + self.branchTitle.text = self.branch?.displayName() + self.contentView.layoutIfNeeded() + return self.contentView + } + + + +} diff --git a/MartHoliday/MartHoliday/View/MarkerInfoWindowView.xib b/MartHoliday/MartHoliday/View/MarkerInfoWindowView.xib new file mode 100644 index 0000000..ec9f1d9 --- /dev/null +++ b/MartHoliday/MartHoliday/View/MarkerInfoWindowView.xib @@ -0,0 +1,71 @@ + + + + + + + + + + + + + NanumSquareRoundOTFR + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MartHoliday/MartHoliday/View/MartMapView.swift b/MartHoliday/MartHoliday/View/MartMapView.swift index 8b86212..e250867 100644 --- a/MartHoliday/MartHoliday/View/MartMapView.swift +++ b/MartHoliday/MartHoliday/View/MartMapView.swift @@ -9,65 +9,65 @@ import UIKit import NMapsMap -class MartMapView: UIView { - - var mapView = NMFMapView() - - convenience init(frame: CGRect, center: GeoPoint) { - self.init(frame: frame) - - mapView.translatesAutoresizingMaskIntoConstraints = false - self.addSubview(mapView) - - mapView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true - mapView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true - mapView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true - mapView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true - - let mapCenter = NMFCameraPosition(NMGLatLng(geoPoint: center), zoom: DEFAULT_MAP_ZOOM) - DispatchQueue.main.async { - self.mapView.moveCamera(NMFCameraUpdate(position: mapCenter)) - } - } - - override init(frame: CGRect) { - super.init(frame: frame) - } - - required init?(coder aDecoder: NSCoder) { - super.init(frame: .zero) - self.addSubview(mapView) - mapView.frame = self.frame - } - - func addDefaultMarker() { - DispatchQueue.main.async { - let marker = NMFMarker(position: self.mapView.cameraPosition.target) - marker.iconImage = DEFAULT_MAP_MARKER_IMAGE - marker.mapView = self.mapView - } - } - - func setUserGestureEnable(_ allow: Bool) { - self.mapView.isScrollGestureEnabled = allow - self.mapView.isZoomGestureEnabled = allow - self.mapView.isTiltGestureEnabled = allow - self.mapView.isRotateGestureEnabled = allow - } - - func setPinchAndPanGesture(_ allow: Bool) { - let pinchGes = UIPinchGestureRecognizer(target: self, action: #selector(pinchMapView)) - let panGes = UIPanGestureRecognizer(target: self, action: #selector(pinchMapView)) - mapView.addGestureRecognizer(pinchGes) - mapView.addGestureRecognizer(panGes) - } - - @objc func pinchMapView() { - - } - - @objc func tapMapView() { - - } -} - +//class MartMapView: UIView { +// +// var mapView = NMFMapView() +// +// convenience init(frame: CGRect, center: GeoPoint) { +// self.init(frame: frame) +// +// mapView.translatesAutoresizingMaskIntoConstraints = false +// self.addSubview(mapView) +// +// mapView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true +// mapView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true +// mapView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true +// mapView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true +// +// let mapCenter = NMFCameraPosition(NMGLatLng(geoPoint: center), zoom: DEFAULT_MAP_ZOOM) +// DispatchQueue.main.async { +// self.mapView.moveCamera(NMFCameraUpdate(position: mapCenter)) +// } +// } +// +// override init(frame: CGRect) { +// super.init(frame: frame) +// } +// +// required init?(coder aDecoder: NSCoder) { +// super.init(frame: .zero) +// self.addSubview(mapView) +// mapView.frame = self.frame +// } +// +// func addDefaultMarker() { +// DispatchQueue.main.async { +// let marker = NMFMarker(position: self.mapView.cameraPosition.target) +// marker.iconImage = DEFAULT_MAP_MARKER_IMAGE +// marker.mapView = self.mapView +// } +// } +// +// func setUserGestureEnable(_ allow: Bool) { +// self.mapView.isScrollGestureEnabled = allow +// self.mapView.isZoomGestureEnabled = allow +// self.mapView.isTiltGestureEnabled = allow +// self.mapView.isRotateGestureEnabled = allow +// } +// +// func setPinchAndPanGesture(_ allow: Bool) { +// let pinchGes = UIPinchGestureRecognizer(target: self, action: #selector(pinchMapView)) +// let panGes = UIPanGestureRecognizer(target: self, action: #selector(pinchMapView)) +// mapView.addGestureRecognizer(pinchGes) +// mapView.addGestureRecognizer(panGes) +// } +// +// @objc func pinchMapView() { +// +// } +// +// @objc func tapMapView() { +// +// } +//} +// diff --git a/MartHoliday/MartHoliday/View/TickMarkSlider.swift b/MartHoliday/MartHoliday/View/TickMarkSlider.swift new file mode 100644 index 0000000..a018ad3 --- /dev/null +++ b/MartHoliday/MartHoliday/View/TickMarkSlider.swift @@ -0,0 +1,78 @@ +// +// TickMarkSlider.swift +// MartHoliday +// +// Created by YOUTH2 on 21/07/2019. +// Copyright © 2019 JINiOS. All rights reserved. +// + +import UIKit + +protocol TickMarkSliderDelegate { + func valueChanged(_ sender: UISlider) +} + +class TickMarkSlider: UISlider { + + var numberOfTickMarks: Float? + var unit: Float? + var delegate: TickMarkSliderDelegate? + + private let hapticGenerator = UIImpactFeedbackGenerator(style: .light) + + convenience init(tick: Float, minimumValue: Float, maximumValue: Float, initialValue: Float, frame: CGRect) { + self.init(frame: frame) + self.numberOfTickMarks = tick + self.unit = (maximumValue - self.minimumValue) / tick + self.minimumValue = minimumValue + self.maximumValue = maximumValue + self.value = initialValue + self.minimumTrackTintColor = UIColor.appColor(color: .mint) + } + + private override init(frame: CGRect) { + super.init(frame: frame) + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + + func addTickMarks() { + let width: CGFloat = 2.0 + let height: CGFloat = 15.0 + let yPosition: CGFloat = (self.frame.size.height - 13)/2 + var xPosition: CGFloat = 0 + + guard let numberOfTickMarks = self.numberOfTickMarks else { return } + let ratio = Float(self.frame.width) / numberOfTickMarks + + for i in 0.. 4 ? 0.3 : 0 + self.value = (newStep * unit) + adjustValue + } + +} diff --git a/MartHoliday/MartHoliday/ViewController/AppInfoViewController.swift b/MartHoliday/MartHoliday/ViewController/AppInfoViewController.swift index 636c270..e42914e 100644 --- a/MartHoliday/MartHoliday/ViewController/AppInfoViewController.swift +++ b/MartHoliday/MartHoliday/ViewController/AppInfoViewController.swift @@ -15,7 +15,6 @@ class AppInfoViewController: IndicatorViewController { @IBOutlet weak var acknowledgementsTextView: UITextView! override func viewDidLoad() { - setIndicator() startIndicator() self.versionLabel.text = setVersionLabel() setTextView() diff --git a/MartHoliday/MartHoliday/ViewController/DetailViewController.swift b/MartHoliday/MartHoliday/ViewController/DetailViewController.swift index df9da64..ac7fa31 100644 --- a/MartHoliday/MartHoliday/ViewController/DetailViewController.swift +++ b/MartHoliday/MartHoliday/ViewController/DetailViewController.swift @@ -69,13 +69,12 @@ class DetailViewController: RechabilityDetectViewController, SFSafariViewControl private func setNavigationItem() { self.navigationController?.navigationBar.isTranslucent = false - + self.navigationItem.largeTitleDisplayMode = .always + self.navigationController?.navigationBar.prefersLargeTitles = true // 브랜치이름 Title 설정 guard let branchData = self.branchData else { return } self.navigationItem.title = branchData.branchName - self.navigationItem.largeTitleDisplayMode = .always - self.navigationController?.navigationBar.prefersLargeTitles = true self.navigationController?.navigationBar.largeTitleTextAttributes = makeTextWithAttributes(fontSize: 24) starButton = StarBarButton() diff --git a/MartHoliday/MartHoliday/ViewController/IndicatorViewController.swift b/MartHoliday/MartHoliday/ViewController/IndicatorViewController.swift index 787af28..8abd1ba 100644 --- a/MartHoliday/MartHoliday/ViewController/IndicatorViewController.swift +++ b/MartHoliday/MartHoliday/ViewController/IndicatorViewController.swift @@ -10,29 +10,33 @@ import UIKit import NVActivityIndicatorView class IndicatorViewController: RechabilityDetectViewController { - var indicator: NVActivityIndicatorView! - var indicatorBackgroundView: UIView! + var indicator: NVActivityIndicatorView? + var indicatorBackgroundView: UIView? func startIndicator() { - indicatorBackgroundView.isHidden = false - indicator.startAnimating() + setIndicator() + indicatorBackgroundView?.isHidden = false + indicator?.startAnimating() } func finishIndicator() { - indicatorBackgroundView.isHidden = true - indicator.stopAnimating() + indicatorBackgroundView?.isHidden = true + indicator?.stopAnimating() } - func setIndicatorBackground() { + private func setIndicatorBackground() { indicatorBackgroundView = UIView(frame: self.view.bounds) + guard let indicatorBackgroundView = self.indicatorBackgroundView else { return } indicatorBackgroundView.backgroundColor = UIColor.appColor(color: .lightgray) self.view.addSubview(indicatorBackgroundView) indicatorBackgroundView.isHidden = true } - func setIndicator() { + private func setIndicator() { setIndicatorBackground() indicator = NVActivityIndicatorView(frame: CGRect(x: UIScreen.main.bounds.width/2 - 40, y: UIScreen.main.bounds.height/2 - 40, width: 60, height: 60), type: .circleStrokeSpin, color: UIColor.appColor(color: .lightmint)) + + guard let indicator = self.indicator else { return } self.view.addSubview(indicator) indicator.translatesAutoresizingMaskIntoConstraints = false indicator.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true diff --git a/MartHoliday/MartHoliday/ViewController/LocationSearchViewController.swift b/MartHoliday/MartHoliday/ViewController/LocationSearchViewController.swift index 3fe969c..8f97f07 100644 --- a/MartHoliday/MartHoliday/ViewController/LocationSearchViewController.swift +++ b/MartHoliday/MartHoliday/ViewController/LocationSearchViewController.swift @@ -7,8 +7,324 @@ // import UIKit +import NMapsMap +import Toaster -class LocationSearchViewController: UIViewController { +public let DEFAULT_MAP_ZOOM: Double = 15.0 +public let REDUCTION_MAP_ZOOM_MIN: Double = 13.0 +public let REDUCTION_MAP_ZOOM_MID: Double = 11.0 +public let REDUCTION_MAP_ZOOM_MAX: Double = 10.0 +public let DEFAULT_MAP_MARKER_IMAGE: NMFOverlayImage = NMF_MARKER_IMAGE_LIGHTBLUE +enum State { + case disabled + case tracking } +class LocationSearchViewController: IndicatorViewController, NMFMapViewDelegate, TickMarkSliderDelegate { + + @IBOutlet weak var naverMapView: NMFNaverMapView! + @IBOutlet weak var searchAgainButton: UIButton! + + @IBOutlet weak var distanceSearchView: UIView! + @IBOutlet weak var sliderView : UIView! + @IBOutlet weak var sliderViewTopConstraint: NSLayoutConstraint! + + @IBOutlet weak var distanceLabel: UILabel! + + var userLocation: NMGLatLng? { + didSet { + guard let userLocation = self.userLocation else { return } + let isValid = (self.previousUserLocation?.compareDifference(compare: self.locationOverlay!.location, value: 0.0005) ?? true) && userLocation.isNationalValid() + if isValid { + self.fetchNearMarts(from: userLocation) + } + } + } + + var distanceSlider: TickMarkSlider? + + var previousUserLocation: NMGLatLng? + + var locationOverlay: NMFLocationOverlay? + + var currentState: State = .disabled + + var infoWindow = NMFInfoWindow() + + var markerInfoWindowDataSource = MarkerInfoWindowDataSource() + + var isDistanceSearchViewShown = true + var previousDistance: Int? + + var settingDistance: Int? { + didSet { + self.distanceLabel.text = "\(self.settingDistance ?? 2)km" + } + } + + var markers = [NMFMarker]() + let nMapViewObserverKeypath = "positionMode" + + override func viewDidLoad() { + super.viewDidLoad() + setSearchAgainButtonBorder() + self.searchAgainButton.alpha = 0 + self.userLocation = self.locationOverlay?.location + naverMapView.delegate = self + + naverMapView.addObserver(self, forKeyPath: nMapViewObserverKeypath, options: [.new], context: nil) + NotificationCenter.default.addObserver(self, selector: #selector(showErrorAlert), name: .apiErrorAlertPopup, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(changeTrackingStatus), name: .completeFetchNearMart, object: nil) + + naverMapView.positionMode = .direction + naverMapView.mapView.logoAlign = .rightTop + + startIndicator() + + let mainQueue = DispatchQueue.main + let deadline = DispatchTime.now() + .seconds(2) + + mainQueue.asyncAfter(deadline: deadline) { + + let lng = self.locationOverlay?.location.lng ?? 0 + let lat = self.locationOverlay?.location.lat ?? 0 + + self.userLocation = NMGLatLng(lat: lat, lng: lng) + self.previousUserLocation = self.userLocation // 맨 처음엔 같게 지정 + + self.finishIndicator() + } + + distanceSlider = TickMarkSlider(tick: 8, minimumValue: 0, maximumValue: 8, initialValue: 2.0, frame: self.sliderView.bounds) + distanceSlider!.addTickMarks() + distanceSlider!.delegate = self + self.sliderView.addSubview(distanceSlider!) + + self.settingDistance = Int(distanceSlider!.value) + setNaviBarSearchButtonTitle() + + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + self.setNavigationBar() + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + } + + @objc private func showErrorAlert() { + DispatchQueue.main.async { + self.presentErrorAlert(type: .DisableNearbyMarts) + } + } + + @objc func changeTrackingStatus() { + naverMapView.positionMode = .disabled + } + + @objc func changeSearchDistance() { + self.showAndHideDistanceView() + guard !self.isDistanceSearchViewShown else { return } + fetchNearMarts(from: self.getMapCenter()) + } + + private func setNavigationBar() { + navigationController?.navigationBar.prefersLargeTitles = false + self.navigationItem.title = "내 주변 마트 검색" + } + + private func setSearchAgainButtonBorder() { + self.searchAgainButton.layer.cornerRadius = searchAgainButton.frame.height/2 + self.searchAgainButton.clipsToBounds = true + } + + private func getMapCenter() -> NMGLatLng { + let position = naverMapView.mapView.cameraPosition + let centerGeoPoint = position.target + return centerGeoPoint + } + + private func showAndHideDistanceView() { + self.isDistanceSearchViewShown = !self.isDistanceSearchViewShown + setNaviBarSearchButtonTitle() + + self.sliderViewTopConstraint.constant = self.isDistanceSearchViewShown ? 0 : -distanceSearchView.bounds.height + + UIView.animate(withDuration: 0.3, + delay: 0, + options: .curveEaseOut, + animations: { + self.distanceSearchView.alpha = self.isDistanceSearchViewShown ? 1 : 0 + self.view.layoutIfNeeded() + }) + } + + private func setNaviBarSearchButtonTitle() { + let titleText = isDistanceSearchViewShown ? "검색" : "\(self.settingDistance ?? 2)km" + + let distanceSettingButton = UIButton(type: .custom) + let buttonTitle = NSAttributedString(string: titleText, + attributes: [.font: UIFont(name: "NanumSquareRoundOTF", size: 13.5)?.bold(), + .foregroundColor: UIColor.white]) + + distanceSettingButton.setAttributedTitle(buttonTitle, for: .normal) + distanceSettingButton.setImage(UIImage(named: "focus"), for: .normal) + distanceSettingButton.imageEdgeInsets = UIEdgeInsets(top: 0, left: -4, bottom: 0, right: 0) + distanceSettingButton.titleEdgeInsets = UIEdgeInsets(top: 2, left: 2, bottom: 0, right: 0) + distanceSettingButton.layer.borderColor = UIColor.white.cgColor + distanceSettingButton.layer.borderWidth = 1.0 + distanceSettingButton.layer.cornerRadius = 13.0 + distanceSettingButton.clipsToBounds = true + + distanceSettingButton.addTarget(self, action: #selector(changeSearchDistance), for: .touchUpInside) + distanceSettingButton.frame = CGRect(x: 0, y: 0, width: 68, height: 30) + + let homeBarButton = UIBarButtonItem(customView: distanceSettingButton) + self.navigationItem.setRightBarButtonItems([homeBarButton], animated: false) + } + +} + + +extension LocationSearchViewController { + + // 포지션 모드가 변경될때만 호출 + override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { + self.locationOverlay = naverMapView.mapView.locationOverlay + + if keyPath == nMapViewObserverKeypath { + self.userLocation = self.locationOverlay!.location + } + } + + + func fetchNearMarts(from geoPoint: NMGLatLng) { + guard let distance = self.settingDistance else { return } + DistanceSearch.fetch(geoPoint: geoPoint, + distance: distance) { (branchRawData) in + self.completeReceiveBranches(branchRawData) } + } + + private func completeReceiveBranches(_ branches: [BranchRawData]) { + let hasSettingDistance = !(self.settingDistance == nil) + let distaceGuideText = hasSettingDistance ? "\(self.settingDistance!)km 반경 내에서" : "요청하신 거리 내에서" + + ToastView.appearance().bottomOffsetPortrait = UIScreen.main.bounds.height / 2 + + DispatchQueue.main.async { + let branches = BranchList(branches: branches) + + if branches.count() == 0 { + Toast(text: "\(distaceGuideText) 마트가 없습니다.").show() + } else { + Toast(text: "\(distaceGuideText) \(branches.count())곳의 마트가 검색되었습니다.").show() + self.showMarkers(of: branches) + } + + NotificationCenter.default.post(name: .completeFetchNearMart, object: nil, userInfo: nil) + } + } + + private func zoomLevel() -> Double { + guard let distance = self.settingDistance else { return DEFAULT_MAP_ZOOM } + switch distance { + case 0...2: return REDUCTION_MAP_ZOOM_MIN + case 3...6: return REDUCTION_MAP_ZOOM_MID + case 7...8: return REDUCTION_MAP_ZOOM_MAX + default: return DEFAULT_MAP_ZOOM + } + } + + private func makeMarkers(of mart: Branch) -> NMFMarker { + let marker = NMFMarker() + marker.iconImage = NMF_MARKER_IMAGE_LIGHTBLUE + marker.width = 23 + marker.height = 30 + marker.position = NMGLatLng(lat: mart.latitude, lng: mart.longitude) + marker.userInfo = ["branch": mart] + + return marker + } + + private func showMarkers(of branches: BranchList) { + let cameraUpdate = NMFCameraUpdate(zoomTo: self.zoomLevel()) + cameraUpdate.animation = .easeOut + naverMapView.mapView.moveCamera(cameraUpdate) + self.markers.forEach { $0.mapView = nil } + + branches.branches.forEach({ (mart) in + let marker = self.makeMarkers(of: mart) + + marker.touchHandler = { [weak self] (overlay) in + if let marker = overlay as? NMFMarker { + if let nextVC = self?.storyboard?.instantiateViewController(withIdentifier: "detailVC") as? DetailViewController { + nextVC.branchData = marker.userInfo["branch"] as? Branch + + let hapticGenerator = UIImpactFeedbackGenerator(style: .medium) + hapticGenerator.impactOccurred() + + let markerInfoDataSource = MarkerInfoWindowDataSource() + markerInfoDataSource.branch = marker.userInfo["branch"] as? Branch + + self?.infoWindow.dataSource = markerInfoDataSource + + self?.infoWindow.open(with: marker, align: .top) + self?.infoWindow.touchHandler = { [weak self] (overlay) in + self?.infoWindow.close() + self?.navigationController?.pushViewController(nextVC, animated: true) + return true + } + } + } + return false // didTapMapView + } + marker.mapView = self.naverMapView.mapView + self.markers.append(marker) + }) + } + + // MARK: - TickMarkSlider Delegate + + func valueChanged(_ sender: UISlider) { + self.settingDistance = Int(distanceSlider!.value) + } + + // MARK: - MapView Delegate + + func didTapMapView(_ point: CGPoint, latLng latlng: NMGLatLng) { + let cameraUpdate = NMFCameraUpdate(scrollTo: NMGLatLng(lat: latlng.lat, lng: latlng.lng), zoomTo: DEFAULT_MAP_ZOOM) + cameraUpdate.animation = .easeOut + cameraUpdate.animationDuration = 0.5 + DispatchQueue.main.async { + self.naverMapView.mapView.moveCamera(cameraUpdate) + } + } + + func mapView(_ mapView: NMFMapView, regionDidChangeAnimated animated: Bool, byReason reason: Int) { + switch reason { + case NMFMapChangedByGesture, NMFMapChangedByControl: + showSearchAgainButton(isShow: true) + default: + break + } + } + + @IBAction func searchAgainButtonTapped(_ sender: Any) { + showSearchAgainButton(isShow: false) + + let position = naverMapView.mapView.cameraPosition + let centerGeoPoint = position.target + self.fetchNearMarts(from: centerGeoPoint) + } + + private func showSearchAgainButton(isShow: Bool) { + UIView.animate(withDuration: 0.5) { [weak self] in + self?.searchAgainButton.alpha = isShow ? 1 : 0 + } + } +} + + diff --git a/MartHoliday/MartHoliday/ViewController/MainViewController.swift b/MartHoliday/MartHoliday/ViewController/MainViewController.swift index 16aa06e..996fbb5 100644 --- a/MartHoliday/MartHoliday/ViewController/MainViewController.swift +++ b/MartHoliday/MartHoliday/ViewController/MainViewController.swift @@ -139,7 +139,7 @@ class MainViewController: RechabilityDetectViewController, FavoriteConvertible, private func presentErrorAlert() { DispatchQueue.main.async { - self.networkTimeOutAlert() + self.presentErrorAlert(type: .NetworkTimeout) } } @@ -330,10 +330,10 @@ extension MainViewController: MFMailComposeViewControllerDelegate { handleDismiss() guard let nextVC = self.storyboard?.instantiateViewController(withIdentifier: "martSelectVC") as? MartSelectViewController else { return } self.navigationController?.pushViewController(nextVC, animated: true) -// case .location: -// handleDismiss() -// guard let nextVC = self.storyboard?.instantiateViewController(withIdentifier: "locationVC") as? LocationSearchViewController else { return } -// self.navigationController?.pushViewController(nextVC, animated: true) + case .location: + handleDismiss() + guard let nextVC = self.storyboard?.instantiateViewController(withIdentifier: "locationVC") as? LocationSearchViewController else { return } + self.navigationController?.pushViewController(nextVC, animated: true) case .sendMail: handleDismiss() var email: String diff --git a/MartHoliday/MartHoliday/ViewController/MapViewController.swift b/MartHoliday/MartHoliday/ViewController/MapViewController.swift index 4340676..0af72c0 100644 --- a/MartHoliday/MartHoliday/ViewController/MapViewController.swift +++ b/MartHoliday/MartHoliday/ViewController/MapViewController.swift @@ -9,9 +9,6 @@ import UIKit import NMapsMap -public let DEFAULT_MAP_ZOOM: Double = 15.0 -public let DEFAULT_MAP_MARKER_IMAGE: NMFOverlayImage = NMF_MARKER_IMAGE_LIGHTBLUE - class MapViewController: UIViewController { var mapView: MartMapView? @@ -45,3 +42,107 @@ class MapViewController: UIViewController { } + +class MartMapView: UIView { + + var mapView = NMFMapView() + + convenience init(frame: CGRect, center: GeoPoint) { + self.init(frame: frame) + + mapView.translatesAutoresizingMaskIntoConstraints = false + self.addSubview(mapView) + + mapView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true + mapView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true + mapView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true + mapView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true + + let mapCenter = NMFCameraPosition(NMGLatLng(geoPoint: center), zoom: DEFAULT_MAP_ZOOM) + DispatchQueue.main.async { + self.mapView.moveCamera(NMFCameraUpdate(position: mapCenter)) + } + } + + override init(frame: CGRect) { + super.init(frame: frame) + } + + required init?(coder aDecoder: NSCoder) { + super.init(frame: .zero) + self.addSubview(mapView) + mapView.frame = self.frame + } + + func addDefaultMarker() { + DispatchQueue.main.async { + let marker = NMFMarker(position: self.mapView.cameraPosition.target) + marker.iconImage = DEFAULT_MAP_MARKER_IMAGE + marker.mapView = self.mapView + } + } + + func setTapGesture() { + let ges = UITapGestureRecognizer(target: self, action: #selector(tapMapView)) + mapView.addGestureRecognizer(ges) + } + + func setUserGestureEnable(_ allow: Bool) { + self.mapView.isScrollGestureEnabled = allow + self.mapView.isZoomGestureEnabled = allow + self.mapView.isTiltGestureEnabled = allow + self.mapView.isRotateGestureEnabled = allow + } + + func setPinchAndPanGesture() { + let pinchGes = UIPinchGestureRecognizer(target: self, action: #selector(pinchMapView)) + let panGes = UIPanGestureRecognizer(target: self, action: #selector(pinchMapView)) + mapView.addGestureRecognizer(pinchGes) + mapView.addGestureRecognizer(panGes) + } + + @objc func pinchMapView() { + // 토스트 "지도를 탭하면 큰 지도가 표시됩니다" + } + + @objc func tapMapView() { + // push to mapvc + } +} + +extension NMGLatLng { + //NMGLatLng(lat: centerPoint.lat, lng: centerPoint.lng) + convenience init(geoPoint: GeoPoint) { + self.init(lat: geoPoint.latitude, lng: geoPoint.longitude) + } + + func compareDifference(compare: NMGLatLng ,value: Double) -> Bool { + return self.lat - compare.lat > 0.0005 || self.lng - compare.lng > 0.0005 + } + + // 국내 유효범위 lat: 33 - 39, lng: 126 - 130 + func isNationalValid() -> Bool { + var isValidLat = false + var isValidLng = false + + isValidLat = (33...39 ~= self.lat) + isValidLng = (126...130 ~= self.lng) + + return isValidLat && isValidLng + } +} + +class GeoPoint { + var latitude: Double + var longitude: Double + + var NMapPoint: NMGLatLng { + return NMGLatLng(lat: self.latitude, lng: self.longitude) + } + + init(lat: Double, lng: Double) { + self.latitude = lat + self.longitude = lng + } + +} diff --git a/MartHoliday/MartHoliday/ViewController/MartSelectViewController.swift b/MartHoliday/MartHoliday/ViewController/MartSelectViewController.swift index c2d8a67..997035f 100644 --- a/MartHoliday/MartHoliday/ViewController/MartSelectViewController.swift +++ b/MartHoliday/MartHoliday/ViewController/MartSelectViewController.swift @@ -22,7 +22,6 @@ class MartSelectViewController: IndicatorViewController { tableView.backgroundColor = UIColor.appColor(color: .lightgray) tableView.delaysContentTouches = false self.navigationItem.title = ProgramDescription.SeachingMart.rawValue - setIndicator() setNetworkConnectionObserver() } @@ -47,8 +46,7 @@ class MartSelectViewController: IndicatorViewController { DispatchQueue.main.async { guard let nextVC = self.storyboard?.instantiateViewController(withIdentifier: "searchVC") as? SearchViewController else { return } guard let data = data else { - self.networkTimeOutAlert() -// SlackWebhook.fire(brokenUrl: mart.url) + self.presentErrorAlert(type: .NetworkTimeout) self.navigationController?.popViewController(animated: true) return } diff --git a/MartHoliday/MartHoliday/ViewController/ReachabilityViewController.swift b/MartHoliday/MartHoliday/ViewController/ReachabilityViewController.swift index 3755bf2..5d0dee3 100644 --- a/MartHoliday/MartHoliday/ViewController/ReachabilityViewController.swift +++ b/MartHoliday/MartHoliday/ViewController/ReachabilityViewController.swift @@ -15,18 +15,12 @@ class RechabilityDetectViewController: UIViewController { NotificationCenter.default.addObserver(self, selector: #selector(reachabilityAlert(notification:)), name: .connectionStatus, object: nil) } - func networkErrorAlert() { - let alert = UIAlertController.make(message: .NetworkError) - alert.addAction(UIAlertAction(title: "Done", style: .default, handler: nil)) - self.present(alert, animated: true, completion: nil) - } - @objc func reachabilityAlert(notification: Notification) { guard let userInfo = notification.userInfo else { return } guard let connection = userInfo["status"] as? Reachability.Connection else { return } switch connection { case .none: - networkErrorAlert() + self.presentErrorAlert(type: .NetworkError) default: networkAvailable() } @@ -37,8 +31,8 @@ class RechabilityDetectViewController: UIViewController { return } - func networkTimeOutAlert() { - let alert = UIAlertController.make(message: .NetworkTimeout) + func presentErrorAlert(type: UIAlertController.AlertMessage) { + let alert = UIAlertController.make(message: type) alert.addAction(UIAlertAction(title: "Done", style: .default, handler: nil)) self.present(alert, animated: true, completion: nil) } diff --git a/MartHoliday/Podfile.lock b/MartHoliday/Podfile.lock index c8a8d1f..78fd4fa 100644 --- a/MartHoliday/Podfile.lock +++ b/MartHoliday/Podfile.lock @@ -58,7 +58,7 @@ PODS: - nanopb/encode (= 0.3.8) - nanopb/decode (0.3.8) - nanopb/encode (0.3.8) - - NMapsMap (3.0.0) + - NMapsMap (3.3.0) - NVActivityIndicatorView (4.5.1): - NVActivityIndicatorView/Presenter (= 4.5.1) - NVActivityIndicatorView/Presenter (4.5.1) @@ -112,7 +112,7 @@ SPEC CHECKSUMS: GTMSessionFetcher: 5fa5b80fd20e439ef5f545fb2cb3ca6c6714caa2 leveldb-library: 08cba283675b7ed2d99629a4bc5fd052cd2bb6a5 nanopb: 5601e6bca2dbf1ed831b519092ec110f66982ca3 - NMapsMap: 1745a9a8d2dc31fb78a97f0925617d46aa658841 + NMapsMap: a2505543fbd96365f557f0f1856710b48888edb1 NVActivityIndicatorView: ec34a7b88c51fab270004a1a1f32116e711010cd Protobuf: 0fc0ad8bec688b2a3017a139953e01374fedbd5f ReachabilitySwift: 6849231cd4e06559f3b9ef4a97a0a0f96d41e09f