From 7bb76d8b8aedc351ecfa88f149688a664ee06253 Mon Sep 17 00:00:00 2001 From: presto Date: Tue, 22 Jan 2019 11:28:34 +0900 Subject: [PATCH 01/84] =?UTF-8?q?=EC=B4=88=EA=B8=B0=20=EB=B7=B0=20?= =?UTF-8?q?=EA=B5=AC=EC=A1=B0=20=EC=84=A4=EC=A0=95=20/=20=EC=9C=84?= =?UTF-8?q?=EC=B9=98=20=EC=A0=95=EB=B3=B4=20=EC=82=AC=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 107 +--- .swiftlint.yml | 13 +- FineDust.xcodeproj/project.pbxproj | 169 ++++- FineDust/Base.lproj/Main.storyboard | 11 - FineDust/Common/Common.storyboard | 62 ++ FineDust/Extension/Date+.swift | 28 + FineDust/Extension/NSLayoutAnchor+.swift | 29 + FineDust/Extension/NSLayoutConstraint+.swift | 29 + FineDust/Extension/NSObject+.swift | 2 +- FineDust/Extension/UIAlertController+.swift | 2 +- FineDust/Extension/UIView+.swift | 2 +- .../Extension/UIView+NSLayoutAnchor.swift | 43 ++ FineDust/Extension/UIViewController+.swift | 2 +- .../Controller/FeedbackViewController.swift | 17 + FineDust/Feedback/Feedback.storyboard | 48 ++ FineDust/Info.plist | 6 +- FineDust/Main/Base.lproj/Main.storyboard | 48 ++ .../Main/Controller/MainViewController.swift | 26 + FineDust/Model/GeoInfo.swift | 30 + .../{HTTPMethod.swift => API+FineDust.swift} | 9 +- .../API.swift} | 8 +- FineDust/Network/Network.swift | 21 +- FineDust/Response/ObservatoryResponse.swift | 48 ++ .../Controller/StatisticsViewController.swift | 17 + FineDust/Statistics/Statistics.storyboard | 46 ++ FineDust/Supporting Files/AppDelegate.swift | 53 +- FineDust/Supporting Files/GeoConverter.swift | 603 ++++++++++++++++++ 27 files changed, 1356 insertions(+), 123 deletions(-) delete mode 100644 FineDust/Base.lproj/Main.storyboard create mode 100644 FineDust/Common/Common.storyboard create mode 100644 FineDust/Extension/Date+.swift create mode 100644 FineDust/Extension/NSLayoutAnchor+.swift create mode 100644 FineDust/Extension/NSLayoutConstraint+.swift create mode 100644 FineDust/Extension/UIView+NSLayoutAnchor.swift create mode 100644 FineDust/Feedback/Controller/FeedbackViewController.swift create mode 100644 FineDust/Feedback/Feedback.storyboard create mode 100644 FineDust/Main/Base.lproj/Main.storyboard create mode 100644 FineDust/Main/Controller/MainViewController.swift create mode 100644 FineDust/Model/GeoInfo.swift rename FineDust/Network/{HTTPMethod.swift => API+FineDust.swift} (53%) rename FineDust/{MainViewController.swift => Network/API.swift} (66%) create mode 100644 FineDust/Response/ObservatoryResponse.swift create mode 100644 FineDust/Statistics/Controller/StatisticsViewController.swift create mode 100644 FineDust/Statistics/Statistics.storyboard create mode 100644 FineDust/Supporting Files/GeoConverter.swift diff --git a/.gitignore b/.gitignore index 261ddeda..08932a8a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,17 +1,38 @@ -# Created by https://www.gitignore.io/api/xcode,swift -# Edit at https://www.gitignore.io/?templates=xcode,swift +# Created by https://www.gitignore.io/api/git,xcode +# Edit at https://www.gitignore.io/?templates=git,xcode + +### Git ### +# Created by git for backups. To disable backups in Git: +# $ git config --global mergetool.keepBackup false +*.orig + +# Created by git when using merge tools for conflicts +*.BACKUP.* +*.BASE.* +*.LOCAL.* +*.REMOTE.* +*_BACKUP_*.txt +*_BASE_*.txt +*_LOCAL_*.txt +*_REMOTE_*.txt -### Swift ### +### Xcode ### # Xcode # # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore -## Build generated +## User settings +xcuserdata/ + +## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) +*.xcscmblueprint +*.xccheckout + +## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) build/ DerivedData/ - -## Various settings +*.moved-aside *.pbxuser !default.pbxuser *.mode1v3 @@ -20,78 +41,6 @@ DerivedData/ !default.mode2v3 *.perspectivev3 !default.perspectivev3 -xcuserdata/ - -## Other -*.moved-aside -*.xccheckout -*.xcscmblueprint - -## Obj-C/Swift specific -*.hmap -*.ipa -*.dSYM.zip -*.dSYM - -## Playgrounds -timeline.xctimeline -playground.xcworkspace - -# Swift Package Manager -# -# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. -# Packages/ -# Package.pins -# Package.resolved -.build/ - -# CocoaPods -# -# We recommend against adding the Pods directory to your .gitignore. However -# you should judge for yourself, the pros and cons are mentioned at: -# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control -# -# Pods/ -# -# Add this line if you want to avoid checking in source code from the Xcode workspace -# *.xcworkspace - -# Carthage -# -# Add this line if you want to avoid checking in source code from Carthage dependencies. -# Carthage/Checkouts - -Carthage/Build - -# fastlane -# -# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the -# screenshots whenever they are needed. -# For more information about the recommended setup visit: -# https://docs.fastlane.tools/best-practices/source-control/#source-control - -fastlane/report.xml -fastlane/Preview.html -fastlane/screenshots/**/*.png -fastlane/test_output - -# Code Injection -# -# After new code Injection tools there's a generated folder /iOSInjectionProject -# https://github.com/johnno1962/injectionforxcode - -iOSInjectionProject/ - -### Xcode ### -# Xcode -# -# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore - -## User settings - -## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) - -## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) ### Xcode Patch ### *.xcodeproj/* @@ -101,4 +50,4 @@ iOSInjectionProject/ /*.gcno **/xcshareddata/WorkspaceSettings.xcsettings -# End of https://www.gitignore.io/api/xcode,swift +# End of https://www.gitignore.io/api/git,xcode diff --git a/.swiftlint.yml b/.swiftlint.yml index 006d79d9..2724646c 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -1,10 +1,17 @@ disabled_rules: - leading_whitespace - trailing_whitespace +- nesting excluded: - FineDust/Supporting Files/AppDelegate.swift +- FineDust/Supporting Files/AppDelegate.swift +- FineDust/Supporting Files/GeoConverter.swift line_length: -warning: 99 -error: 120 + warning: 99 + error: 120 + +identifier_name: + excluded: + - x + - y diff --git a/FineDust.xcodeproj/project.pbxproj b/FineDust.xcodeproj/project.pbxproj index f4afcd84..1a8b090a 100644 --- a/FineDust.xcodeproj/project.pbxproj +++ b/FineDust.xcodeproj/project.pbxproj @@ -7,7 +7,6 @@ objects = { /* Begin PBXBuildFile section */ - 192CDA8B21F5EC8D000CE35D /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDA8A21F5EC8D000CE35D /* MainViewController.swift */; }; 192CDA8D21F5ED9C000CE35D /* Network.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDA8C21F5ED9C000CE35D /* Network.swift */; }; 192CDA8F21F5EDFC000CE35D /* NSObject+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDA8E21F5EDFC000CE35D /* NSObject+.swift */; }; 192CDA9121F5EE04000CE35D /* UIViewController+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDA9021F5EE04000CE35D /* UIViewController+.swift */; }; @@ -15,7 +14,21 @@ 192CDA9521F5EE11000CE35D /* UIAlertController+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDA9421F5EE11000CE35D /* UIAlertController+.swift */; }; 192CDA9721F5EE17000CE35D /* UIColor+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDA9621F5EE17000CE35D /* UIColor+.swift */; }; 192CDA9921F5EE1E000CE35D /* String+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDA9821F5EE1E000CE35D /* String+.swift */; }; - 192CDA9D21F5F27A000CE35D /* HTTPMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDA9C21F5F27A000CE35D /* HTTPMethod.swift */; }; + 192CDA9F21F603A9000CE35D /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDA9E21F603A9000CE35D /* API.swift */; }; + 192CDAA121F603C5000CE35D /* API+FineDust.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDAA021F603C5000CE35D /* API+FineDust.swift */; }; + 192CDAA521F6046D000CE35D /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDAA421F6046D000CE35D /* MainViewController.swift */; }; + 192CDAA721F60914000CE35D /* Date+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDAA621F60914000CE35D /* Date+.swift */; }; + 192CDAAA21F61D0C000CE35D /* GeoConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDAA921F61D0C000CE35D /* GeoConverter.swift */; }; + 192CDAAC21F61F35000CE35D /* GeoInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDAAB21F61F35000CE35D /* GeoInfo.swift */; }; + 192CDAAF21F623ED000CE35D /* ObservatoryResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDAAE21F623ED000CE35D /* ObservatoryResponse.swift */; }; + 192CDAB121F627A3000CE35D /* NSLayoutConstraint+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDAB021F627A3000CE35D /* NSLayoutConstraint+.swift */; }; + 192CDAB321F628C9000CE35D /* NSLayoutAnchor+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDAB221F628C9000CE35D /* NSLayoutAnchor+.swift */; }; + 192CDAB521F62A5D000CE35D /* UIView+NSLayoutAnchor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDAB421F62A5D000CE35D /* UIView+NSLayoutAnchor.swift */; }; + 192CDAC021F6B242000CE35D /* Statistics.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 192CDABF21F6B242000CE35D /* Statistics.storyboard */; }; + 192CDAC221F6B24D000CE35D /* Feedback.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 192CDAC121F6B24D000CE35D /* Feedback.storyboard */; }; + 192CDAC521F6B2DF000CE35D /* Common.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 192CDAC421F6B2DF000CE35D /* Common.storyboard */; }; + 192CDAC921F6B61D000CE35D /* StatisticsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDAC821F6B61D000CE35D /* StatisticsViewController.swift */; }; + 192CDACB21F6B62E000CE35D /* FeedbackViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDACA21F6B62E000CE35D /* FeedbackViewController.swift */; }; 1949B09921F5EB3200B22915 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1949B09821F5EB3200B22915 /* AppDelegate.swift */; }; 1949B09E21F5EB3200B22915 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1949B09C21F5EB3200B22915 /* Main.storyboard */; }; 1949B0A121F5EB3200B22915 /* FineDust.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 1949B09F21F5EB3200B22915 /* FineDust.xcdatamodeld */; }; @@ -25,7 +38,6 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 192CDA8A21F5EC8D000CE35D /* MainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = ""; }; 192CDA8C21F5ED9C000CE35D /* Network.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Network.swift; sourceTree = ""; }; 192CDA8E21F5EDFC000CE35D /* NSObject+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSObject+.swift"; sourceTree = ""; }; 192CDA9021F5EE04000CE35D /* UIViewController+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+.swift"; sourceTree = ""; }; @@ -33,7 +45,21 @@ 192CDA9421F5EE11000CE35D /* UIAlertController+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIAlertController+.swift"; sourceTree = ""; }; 192CDA9621F5EE17000CE35D /* UIColor+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+.swift"; sourceTree = ""; }; 192CDA9821F5EE1E000CE35D /* String+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+.swift"; sourceTree = ""; }; - 192CDA9C21F5F27A000CE35D /* HTTPMethod.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPMethod.swift; sourceTree = ""; }; + 192CDA9E21F603A9000CE35D /* API.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = API.swift; sourceTree = ""; }; + 192CDAA021F603C5000CE35D /* API+FineDust.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "API+FineDust.swift"; sourceTree = ""; }; + 192CDAA421F6046D000CE35D /* MainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = ""; }; + 192CDAA621F60914000CE35D /* Date+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+.swift"; sourceTree = ""; }; + 192CDAA921F61D0C000CE35D /* GeoConverter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeoConverter.swift; sourceTree = ""; }; + 192CDAAB21F61F35000CE35D /* GeoInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeoInfo.swift; sourceTree = ""; }; + 192CDAAE21F623ED000CE35D /* ObservatoryResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObservatoryResponse.swift; sourceTree = ""; }; + 192CDAB021F627A3000CE35D /* NSLayoutConstraint+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSLayoutConstraint+.swift"; sourceTree = ""; }; + 192CDAB221F628C9000CE35D /* NSLayoutAnchor+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSLayoutAnchor+.swift"; sourceTree = ""; }; + 192CDAB421F62A5D000CE35D /* UIView+NSLayoutAnchor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+NSLayoutAnchor.swift"; sourceTree = ""; }; + 192CDABF21F6B242000CE35D /* Statistics.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Statistics.storyboard; sourceTree = ""; }; + 192CDAC121F6B24D000CE35D /* Feedback.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Feedback.storyboard; sourceTree = ""; }; + 192CDAC421F6B2DF000CE35D /* Common.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Common.storyboard; sourceTree = ""; }; + 192CDAC821F6B61D000CE35D /* StatisticsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatisticsViewController.swift; sourceTree = ""; }; + 192CDACA21F6B62E000CE35D /* FeedbackViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbackViewController.swift; sourceTree = ""; }; 1949B09521F5EB3200B22915 /* FineDust.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FineDust.app; sourceTree = BUILT_PRODUCTS_DIR; }; 1949B09821F5EB3200B22915 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 1949B09D21F5EB3200B22915 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; @@ -55,6 +81,96 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 192CDAA821F60A1C000CE35D /* HealthKit */ = { + isa = PBXGroup; + children = ( + ); + path = HealthKit; + sourceTree = ""; + }; + 192CDAAD21F623DC000CE35D /* Response */ = { + isa = PBXGroup; + children = ( + 192CDAAE21F623ED000CE35D /* ObservatoryResponse.swift */, + ); + path = Response; + sourceTree = ""; + }; + 192CDAB621F6B1D0000CE35D /* Main */ = { + isa = PBXGroup; + children = ( + 1949B09C21F5EB3200B22915 /* Main.storyboard */, + 192CDABE21F6B212000CE35D /* View */, + 192CDABD21F6B20F000CE35D /* Controller */, + ); + path = Main; + sourceTree = ""; + }; + 192CDAB721F6B1DD000CE35D /* Statistics */ = { + isa = PBXGroup; + children = ( + 192CDABF21F6B242000CE35D /* Statistics.storyboard */, + 192CDABA21F6B204000CE35D /* View */, + 192CDAB921F6B200000CE35D /* Controller */, + ); + path = Statistics; + sourceTree = ""; + }; + 192CDAB821F6B1F2000CE35D /* Feedback */ = { + isa = PBXGroup; + children = ( + 192CDAC121F6B24D000CE35D /* Feedback.storyboard */, + 192CDAC321F6B296000CE35D /* View */, + 192CDABB21F6B208000CE35D /* Controller */, + ); + path = Feedback; + sourceTree = ""; + }; + 192CDAB921F6B200000CE35D /* Controller */ = { + isa = PBXGroup; + children = ( + 192CDAC821F6B61D000CE35D /* StatisticsViewController.swift */, + ); + path = Controller; + sourceTree = ""; + }; + 192CDABA21F6B204000CE35D /* View */ = { + isa = PBXGroup; + children = ( + ); + path = View; + sourceTree = ""; + }; + 192CDABB21F6B208000CE35D /* Controller */ = { + isa = PBXGroup; + children = ( + 192CDACA21F6B62E000CE35D /* FeedbackViewController.swift */, + ); + path = Controller; + sourceTree = ""; + }; + 192CDABD21F6B20F000CE35D /* Controller */ = { + isa = PBXGroup; + children = ( + 192CDAA421F6046D000CE35D /* MainViewController.swift */, + ); + path = Controller; + sourceTree = ""; + }; + 192CDABE21F6B212000CE35D /* View */ = { + isa = PBXGroup; + children = ( + ); + path = View; + sourceTree = ""; + }; + 192CDAC321F6B296000CE35D /* View */ = { + isa = PBXGroup; + children = ( + ); + path = View; + sourceTree = ""; + }; 1949B08C21F5EB3200B22915 = { isa = PBXGroup; children = ( @@ -76,12 +192,15 @@ isa = PBXGroup; children = ( 1949B0A721F5EB3600B22915 /* Info.plist */, + 1949B0B221F5EBB900B22915 /* Common */, + 192CDAA821F60A1C000CE35D /* HealthKit */, 1949B0B421F5EBC900B22915 /* Core Data */, 1949B0B021F5EBB000B22915 /* Network */, - 1949B0B221F5EBB900B22915 /* Common */, + 192CDAAD21F623DC000CE35D /* Response */, 1949B0B121F5EBB500B22915 /* Model */, - 1949B09C21F5EB3200B22915 /* Main.storyboard */, - 192CDA8A21F5EC8D000CE35D /* MainViewController.swift */, + 192CDAB621F6B1D0000CE35D /* Main */, + 192CDAB721F6B1DD000CE35D /* Statistics */, + 192CDAB821F6B1F2000CE35D /* Feedback */, 1949B0B521F5EBD900B22915 /* Supporting Files */, 1949B0B321F5EBC200B22915 /* Extension */, ); @@ -91,8 +210,9 @@ 1949B0B021F5EBB000B22915 /* Network */ = { isa = PBXGroup; children = ( - 192CDA9C21F5F27A000CE35D /* HTTPMethod.swift */, 192CDA8C21F5ED9C000CE35D /* Network.swift */, + 192CDA9E21F603A9000CE35D /* API.swift */, + 192CDAA021F603C5000CE35D /* API+FineDust.swift */, ); path = Network; sourceTree = ""; @@ -100,6 +220,7 @@ 1949B0B121F5EBB500B22915 /* Model */ = { isa = PBXGroup; children = ( + 192CDAAB21F61F35000CE35D /* GeoInfo.swift */, ); path = Model; sourceTree = ""; @@ -107,6 +228,7 @@ 1949B0B221F5EBB900B22915 /* Common */ = { isa = PBXGroup; children = ( + 192CDAC421F6B2DF000CE35D /* Common.storyboard */, ); path = Common; sourceTree = ""; @@ -117,9 +239,13 @@ 192CDA8E21F5EDFC000CE35D /* NSObject+.swift */, 192CDA9021F5EE04000CE35D /* UIViewController+.swift */, 192CDA9221F5EE09000CE35D /* UIView+.swift */, + 192CDAB421F62A5D000CE35D /* UIView+NSLayoutAnchor.swift */, 192CDA9421F5EE11000CE35D /* UIAlertController+.swift */, 192CDA9621F5EE17000CE35D /* UIColor+.swift */, 192CDA9821F5EE1E000CE35D /* String+.swift */, + 192CDAA621F60914000CE35D /* Date+.swift */, + 192CDAB021F627A3000CE35D /* NSLayoutConstraint+.swift */, + 192CDAB221F628C9000CE35D /* NSLayoutAnchor+.swift */, ); path = Extension; sourceTree = ""; @@ -137,6 +263,7 @@ children = ( 1949B0A421F5EB3600B22915 /* LaunchScreen.storyboard */, 1949B09821F5EB3200B22915 /* AppDelegate.swift */, + 192CDAA921F61D0C000CE35D /* GeoConverter.swift */, 1949B0A221F5EB3600B22915 /* Assets.xcassets */, ); path = "Supporting Files"; @@ -175,6 +302,11 @@ TargetAttributes = { 1949B09421F5EB3200B22915 = { CreatedOnToolsVersion = 10.1; + SystemCapabilities = { + com.apple.BackgroundModes = { + enabled = 0; + }; + }; }; }; }; @@ -204,7 +336,10 @@ 1949B0AF21F5EB9F00B22915 /* .swiftlint.yml in Resources */, 1949B0A621F5EB3600B22915 /* LaunchScreen.storyboard in Resources */, 1949B0A321F5EB3600B22915 /* Assets.xcassets in Resources */, + 192CDAC521F6B2DF000CE35D /* Common.storyboard in Resources */, + 192CDAC021F6B242000CE35D /* Statistics.storyboard in Resources */, 1949B09E21F5EB3200B22915 /* Main.storyboard in Resources */, + 192CDAC221F6B24D000CE35D /* Feedback.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -235,17 +370,27 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 192CDAAA21F61D0C000CE35D /* GeoConverter.swift in Sources */, + 192CDAA521F6046D000CE35D /* MainViewController.swift in Sources */, 192CDA9521F5EE11000CE35D /* UIAlertController+.swift in Sources */, 192CDA8F21F5EDFC000CE35D /* NSObject+.swift in Sources */, 192CDA9921F5EE1E000CE35D /* String+.swift in Sources */, - 192CDA9D21F5F27A000CE35D /* HTTPMethod.swift in Sources */, - 192CDA8B21F5EC8D000CE35D /* MainViewController.swift in Sources */, + 192CDAA121F603C5000CE35D /* API+FineDust.swift in Sources */, 192CDA9321F5EE09000CE35D /* UIView+.swift in Sources */, + 192CDAAF21F623ED000CE35D /* ObservatoryResponse.swift in Sources */, 192CDA9121F5EE04000CE35D /* UIViewController+.swift in Sources */, 1949B09921F5EB3200B22915 /* AppDelegate.swift in Sources */, + 192CDACB21F6B62E000CE35D /* FeedbackViewController.swift in Sources */, + 192CDAB321F628C9000CE35D /* NSLayoutAnchor+.swift in Sources */, + 192CDAC921F6B61D000CE35D /* StatisticsViewController.swift in Sources */, 192CDA8D21F5ED9C000CE35D /* Network.swift in Sources */, 1949B0A121F5EB3200B22915 /* FineDust.xcdatamodeld in Sources */, + 192CDAA721F60914000CE35D /* Date+.swift in Sources */, + 192CDA9F21F603A9000CE35D /* API.swift in Sources */, + 192CDAB521F62A5D000CE35D /* UIView+NSLayoutAnchor.swift in Sources */, 192CDA9721F5EE17000CE35D /* UIColor+.swift in Sources */, + 192CDAAC21F61F35000CE35D /* GeoInfo.swift in Sources */, + 192CDAB121F627A3000CE35D /* NSLayoutConstraint+.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -394,7 +539,7 @@ CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = H79MF628K3; INFOPLIST_FILE = FineDust/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10; + IPHONEOS_DEPLOYMENT_TARGET = 11; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -413,7 +558,7 @@ CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = H79MF628K3; INFOPLIST_FILE = FineDust/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10; + IPHONEOS_DEPLOYMENT_TARGET = 11; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/FineDust/Base.lproj/Main.storyboard b/FineDust/Base.lproj/Main.storyboard deleted file mode 100644 index b1be5cff..00000000 --- a/FineDust/Base.lproj/Main.storyboard +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/FineDust/Common/Common.storyboard b/FineDust/Common/Common.storyboard new file mode 100644 index 00000000..572b5c29 --- /dev/null +++ b/FineDust/Common/Common.storyboard @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FineDust/Extension/Date+.swift b/FineDust/Extension/Date+.swift new file mode 100644 index 00000000..ddae9e03 --- /dev/null +++ b/FineDust/Extension/Date+.swift @@ -0,0 +1,28 @@ +// +// Date+.swift +// FineDust +// +// Created by Presto on 21/01/2019. +// Copyright © 2019 boostcamp3rd. All rights reserved. +// + +import Foundation + +extension Date { + static func day(beforeDays days: Int) -> Date { + return Calendar.current.date(byAdding: .day, value: -days, to: Date()) ?? Date() + } + + static func day(afterDays days: Int) -> Date { + return Calendar.current.date(byAdding: .day, value: days, to: Date()) ?? Date() + } + + static func start(of date: Date) -> Date { + return Calendar.current.startOfDay(for: date) + } + + static func end(of date: Date) -> Date { + let components = DateComponents(day: 1, second: -1) + return Calendar.current.date(byAdding: components, to: date) ?? Date() + } +} diff --git a/FineDust/Extension/NSLayoutAnchor+.swift b/FineDust/Extension/NSLayoutAnchor+.swift new file mode 100644 index 00000000..4ed5f662 --- /dev/null +++ b/FineDust/Extension/NSLayoutAnchor+.swift @@ -0,0 +1,29 @@ +// +// NSLayoutAnchor+.swift +// FineDust +// +// Created by Presto on 22/01/2019. +// Copyright © 2019 boostcamp3rd. All rights reserved. +// + +import UIKit + +extension NSLayoutAnchor { + @objc func equal(to anchor: NSLayoutAnchor, offset: CGFloat = 0) -> NSLayoutConstraint { + return constraint(equalTo: anchor, constant: offset) + } + + @objc func greaterThanOrEqual( + to anchor: NSLayoutAnchor, + offset: CGFloat = 0 + ) -> NSLayoutConstraint { + return constraint(greaterThanOrEqualTo: anchor, constant: offset) + } + + @objc func lessThanOrEqual( + to anchor: NSLayoutAnchor, + offset: CGFloat = 0 + ) -> NSLayoutConstraint { + return constraint(lessThanOrEqualTo: anchor, constant: offset) + } +} diff --git a/FineDust/Extension/NSLayoutConstraint+.swift b/FineDust/Extension/NSLayoutConstraint+.swift new file mode 100644 index 00000000..aa613db0 --- /dev/null +++ b/FineDust/Extension/NSLayoutConstraint+.swift @@ -0,0 +1,29 @@ +// +// NSLayoutConstraint+.swift +// FineDust +// +// Created by Presto on 22/01/2019. +// Copyright © 2019 boostcamp3rd. All rights reserved. +// + +import UIKit + +extension NSLayoutConstraint { + func changeMultiplier(to value: CGFloat) -> NSLayoutConstraint { + let constraint = NSLayoutConstraint( + item: firstItem as Any, + attribute: firstAttribute, + relatedBy: relation, + toItem: secondItem, + attribute: secondAttribute, + multiplier: value, + constant: constant + ) + constraint.priority = priority + constraint.shouldBeArchived = shouldBeArchived + constraint.identifier = identifier + NSLayoutConstraint.deactivate([self]) + NSLayoutConstraint.activate([constraint]) + return constraint + } +} diff --git a/FineDust/Extension/NSObject+.swift b/FineDust/Extension/NSObject+.swift index ba125a29..1ca5dddb 100644 --- a/FineDust/Extension/NSObject+.swift +++ b/FineDust/Extension/NSObject+.swift @@ -8,7 +8,7 @@ import Foundation -public extension NSObject { +extension NSObject { var classNameToString: String { return NSStringFromClass(type(of: self)) } diff --git a/FineDust/Extension/UIAlertController+.swift b/FineDust/Extension/UIAlertController+.swift index 501459b4..254a7658 100644 --- a/FineDust/Extension/UIAlertController+.swift +++ b/FineDust/Extension/UIAlertController+.swift @@ -8,7 +8,7 @@ import UIKit -public extension UIAlertController { +extension UIAlertController { static func alert( title: String?, message: String?, diff --git a/FineDust/Extension/UIView+.swift b/FineDust/Extension/UIView+.swift index e1c30ac1..537ddd0a 100644 --- a/FineDust/Extension/UIView+.swift +++ b/FineDust/Extension/UIView+.swift @@ -8,7 +8,7 @@ import UIKit -public extension UIView { +extension UIView { static func create(fromXib name: String) -> UIView? { return UINib(nibName: name, bundle: nil) .instantiate(withOwner: nil, options: nil).first as? UIView diff --git a/FineDust/Extension/UIView+NSLayoutAnchor.swift b/FineDust/Extension/UIView+NSLayoutAnchor.swift new file mode 100644 index 00000000..b4a69f2d --- /dev/null +++ b/FineDust/Extension/UIView+NSLayoutAnchor.swift @@ -0,0 +1,43 @@ +// +// UIView+NSLayoutAnchor.swift +// FineDust +// +// Created by Presto on 22/01/2019. +// Copyright © 2019 boostcamp3rd. All rights reserved. +// + +import UIKit + +extension UIView { + var top: NSLayoutYAxisAnchor { + return topAnchor + } + + var bottom: NSLayoutYAxisAnchor { + return bottomAnchor + } + + var leading: NSLayoutXAxisAnchor { + return leadingAnchor + } + + var trailing: NSLayoutXAxisAnchor { + return trailingAnchor + } + + var centerX: NSLayoutXAxisAnchor { + return centerXAnchor + } + + var centerY: NSLayoutYAxisAnchor { + return centerYAnchor + } + + var width: NSLayoutDimension { + return widthAnchor + } + + var height: NSLayoutDimension { + return heightAnchor + } +} diff --git a/FineDust/Extension/UIViewController+.swift b/FineDust/Extension/UIViewController+.swift index ff685d5e..cb85ab46 100644 --- a/FineDust/Extension/UIViewController+.swift +++ b/FineDust/Extension/UIViewController+.swift @@ -8,7 +8,7 @@ import UIKit -public extension UIViewController { +extension UIViewController { static func create(fromStoryboard storyboard: String, identifier: String) -> UIViewController { let storyboard = UIStoryboard(name: storyboard, bundle: nil) let controller = storyboard.instantiateViewController(withIdentifier: identifier) diff --git a/FineDust/Feedback/Controller/FeedbackViewController.swift b/FineDust/Feedback/Controller/FeedbackViewController.swift new file mode 100644 index 00000000..0a36b0bd --- /dev/null +++ b/FineDust/Feedback/Controller/FeedbackViewController.swift @@ -0,0 +1,17 @@ +// +// FeedbackViewController.swift +// FineDust +// +// Created by Presto on 22/01/2019. +// Copyright © 2019 boostcamp3rd. All rights reserved. +// + +import UIKit + +class FeedbackViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + tabBarItem.title = "피드백" + } +} diff --git a/FineDust/Feedback/Feedback.storyboard b/FineDust/Feedback/Feedback.storyboard new file mode 100644 index 00000000..e36ef656 --- /dev/null +++ b/FineDust/Feedback/Feedback.storyboard @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FineDust/Info.plist b/FineDust/Info.plist index 62b49beb..3b8aa9e8 100644 --- a/FineDust/Info.plist +++ b/FineDust/Info.plist @@ -20,10 +20,14 @@ 1 LSRequiresIPhoneOS + NSLocationAlwaysAndWhenInUseUsageDescription + 위치 정보를 사용하여 현재 위치의 미세먼지 농도를 가져옵니다. + NSLocationWhenInUseUsageDescription + 위치 정보를 사용하여 현재 위치의 미세먼지 농도를 가져옵니다. UILaunchStoryboardName LaunchScreen UIMainStoryboardFile - Main + Common UIRequiredDeviceCapabilities armv7 diff --git a/FineDust/Main/Base.lproj/Main.storyboard b/FineDust/Main/Base.lproj/Main.storyboard new file mode 100644 index 00000000..fef8deae --- /dev/null +++ b/FineDust/Main/Base.lproj/Main.storyboard @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FineDust/Main/Controller/MainViewController.swift b/FineDust/Main/Controller/MainViewController.swift new file mode 100644 index 00000000..c2168b9d --- /dev/null +++ b/FineDust/Main/Controller/MainViewController.swift @@ -0,0 +1,26 @@ +// +// ViewController.swift +// FineDust +// +// Created by Presto on 21/01/2019. +// Copyright © 2019 boostcamp3rd. All rights reserved. +// + +import CoreLocation +import UIKit + +final class MainViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + tabBarItem.title = "홈" + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + } +} diff --git a/FineDust/Model/GeoInfo.swift b/FineDust/Model/GeoInfo.swift new file mode 100644 index 00000000..c1518e85 --- /dev/null +++ b/FineDust/Model/GeoInfo.swift @@ -0,0 +1,30 @@ +// +// GeoInfo.swift +// FineDust +// +// Created by Presto on 22/01/2019. +// Copyright © 2019 boostcamp3rd. All rights reserved. +// + +import Foundation + +/// 좌표 정보를 담는 싱글톤 객체. +final class GeoInfo { + + // MARK: Singleton Object + + static let shared = GeoInfo() + + // MARK: Property + + private var x: Double = 0 + + private var y: Double = 0 + + // MARK: Method + + func set(x: Double, y: Double) { + self.x = x + self.y = y + } +} diff --git a/FineDust/Network/HTTPMethod.swift b/FineDust/Network/API+FineDust.swift similarity index 53% rename from FineDust/Network/HTTPMethod.swift rename to FineDust/Network/API+FineDust.swift index 497de7f6..d1008d68 100644 --- a/FineDust/Network/HTTPMethod.swift +++ b/FineDust/Network/API+FineDust.swift @@ -1,5 +1,5 @@ // -// HTTPMethod.swift +// API+FineDust.swift // FineDust // // Created by Presto on 21/01/2019. @@ -8,9 +8,8 @@ import Foundation -enum HTTPMethod: String { +extension API { - case get = "GET" - - case post = "POST" + /// 측정소 정보 조회. + // func getObservatoryPost(completion: @escaping ) } diff --git a/FineDust/MainViewController.swift b/FineDust/Network/API.swift similarity index 66% rename from FineDust/MainViewController.swift rename to FineDust/Network/API.swift index 2ae08486..f7b9af80 100644 --- a/FineDust/MainViewController.swift +++ b/FineDust/Network/API.swift @@ -1,5 +1,5 @@ // -// MainViewController.swift +// API.swift // FineDust // // Created by Presto on 21/01/2019. @@ -7,3 +7,9 @@ // import Foundation + +final class API { + + static let shared = API() + +} diff --git a/FineDust/Network/Network.swift b/FineDust/Network/Network.swift index c5c8bc86..7f379b34 100644 --- a/FineDust/Network/Network.swift +++ b/FineDust/Network/Network.swift @@ -8,8 +8,25 @@ import Foundation +/// 네트워크 요청 관련 클래스. final class Network { + /// HTTP 메소드를 정의한 열거형. + enum HTTPMethod: String { + + case get = "GET" + + case post = "POST" + } + + /// 네트워크 요청을 위한 타입 메소드. + /// + /// - Parameters: + /// - url: URL + /// - method: HTTP Method + /// - parameters: HTTP Body에 들어갈 키/값 쌍. 기본값은 `[:]` + /// - headers: HTTP Header에 들어갈 키/값 쌍. 기본값은 `[:]` + /// - completion: 컴플리션 핸들러 class func request( _ url: URL, method: HTTPMethod, @@ -20,9 +37,7 @@ final class Network { let session = URLSession(configuration: .default) var urlRequest = URLRequest(url: url) urlRequest.httpMethod = method.rawValue - guard let httpBody = try? JSONSerialization.data(withJSONObject: parameters, options: []) - else { return } - urlRequest.httpBody = httpBody + urlRequest.httpBody = try? JSONSerialization.data(withJSONObject: parameters, options: []) headers.forEach { urlRequest.setValue($0.value, forHTTPHeaderField: $0.key) } let task = session.dataTask(with: urlRequest) { data, response, error in guard let statusCode = (response as? HTTPURLResponse)?.statusCode else { return } diff --git a/FineDust/Response/ObservatoryResponse.swift b/FineDust/Response/ObservatoryResponse.swift new file mode 100644 index 00000000..2e73b1a8 --- /dev/null +++ b/FineDust/Response/ObservatoryResponse.swift @@ -0,0 +1,48 @@ +// +// ObservatoryResponse.swift +// FineDust +// +// Created by Presto on 22/01/2019. +// Copyright © 2019 boostcamp3rd. All rights reserved. +// + +import Foundation + +/// 측정소 정보 조회 응답 객체. +struct ObservatoryResponse: Codable { + + struct Item: Codable { + + let stationName: String + + let address: String + + let distance: Double + + enum CodingKeys: String, CodingKey { + + case stationName + + case address = "addr" + + case distance = "tm" + } + } + + let numberOfRows: Int + + let pageNumber: Int + + let totalCount: Int + + let items: [Item] + + enum CodingKeys: String, CodingKey { + + case numberOfRows = "numOfRows" + + case pageNumber = "pageNo" + + case totalCount, items + } +} diff --git a/FineDust/Statistics/Controller/StatisticsViewController.swift b/FineDust/Statistics/Controller/StatisticsViewController.swift new file mode 100644 index 00000000..1c3d1180 --- /dev/null +++ b/FineDust/Statistics/Controller/StatisticsViewController.swift @@ -0,0 +1,17 @@ +// +// StatisticsViewController.swift +// FineDust +// +// Created by Presto on 22/01/2019. +// Copyright © 2019 boostcamp3rd. All rights reserved. +// + +import UIKit + +class StatisticsViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + tabBarItem.title = "통계" + } +} diff --git a/FineDust/Statistics/Statistics.storyboard b/FineDust/Statistics/Statistics.storyboard new file mode 100644 index 00000000..008c5676 --- /dev/null +++ b/FineDust/Statistics/Statistics.storyboard @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FineDust/Supporting Files/AppDelegate.swift b/FineDust/Supporting Files/AppDelegate.swift index 5cfc9cda..1a597335 100644 --- a/FineDust/Supporting Files/AppDelegate.swift +++ b/FineDust/Supporting Files/AppDelegate.swift @@ -6,17 +6,27 @@ // Copyright © 2019 boostcamp3rd. All rights reserved. // -import UIKit import CoreData +import CoreLocation +import UIKit + @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { - + var window: UIWindow? - + + private lazy var locationManager: CLLocationManager = { + let manager = CLLocationManager() + manager.desiredAccuracy = kCLLocationAccuracyBest + manager.distanceFilter = kCLDistanceFilterNone + manager.delegate = self + return manager + }() func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. + locationManager.requestAlwaysAuthorization() return true } @@ -88,6 +98,41 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } } } - } +extension AppDelegate: CLLocationManagerDelegate { + func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { + print("위치 갱신됨") + let locale = Locale(identifier: "ko_KR") + guard let location = locations.last else { return } + let coordinate = location.coordinate + print(coordinate.latitude, coordinate.longitude) + let convertedCoordinate = GeoConverter().convert( + sourceType: .WGS_84, + destinationType: .TM, + geoPoint: GeographicPoint(x: coordinate.longitude, y: coordinate.latitude) + ) + print(convertedCoordinate?.x, convertedCoordinate?.y) + GeoInfo.shared.set(x: convertedCoordinate?.x ?? 0, y: convertedCoordinate?.y ?? 0) + CLGeocoder().reverseGeocodeLocation(location, preferredLocale: locale) { placeMarks, error in + if let error = error { + print(error.localizedDescription) + return + } + guard let placeMark = placeMarks?.last else { return } + print(placeMark.administrativeArea, placeMark.country, placeMark.locality, placeMark.name) + } + manager.stopUpdatingLocation() + } + + func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { + print("GPS Error: \(error.localizedDescription)") + } + + func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { + print("권한 허가 상태 변경: \(status)") + if status == .authorizedWhenInUse || status == .authorizedAlways { + locationManager.startUpdatingLocation() + } + } +} diff --git a/FineDust/Supporting Files/GeoConverter.swift b/FineDust/Supporting Files/GeoConverter.swift new file mode 100644 index 00000000..ef7f0820 --- /dev/null +++ b/FineDust/Supporting Files/GeoConverter.swift @@ -0,0 +1,603 @@ +// +// GeoConverter.swift +// GeoConverter +// +// Created by SangwooLee on 2017. 7. 27.. +// Copyright © 2017년 sangwoo. All rights reserved. +// +import Foundation + +struct GeographicPoint { + let x: Double // longitude (경도) + let y: Double // latitude (위도) + let z: Double + + init(x: Double, y: Double, z: Double) { + self.x = x + self.y = y + self.z = z + } + + init(x: Double, y: Double) { + self.x = x + self.y = y + self.z = 0 + } + + init() { + self.x = 0 + self.y = 0 + self.z = 0 + } +} + +struct NisMapInfo { + let re: Double = 6371.00877 // 사용할 지구 반경 [km] + let grid: Double = 5.0 // 격자 간격 [km] + let slat1: Double = 30.0 // 표준 위도 [degree] + let slat2: Double = 60.0 // 표준 위도 [degree] + let olon: Double = 126.0 // 기준점의 경도 [degree] + let olat: Double = 38.0 // 기준점의 위도 [degree] + let xo: Double = 210 / 5.0 // 기준점의 X 좌표 [격자 거리] + let yo: Double = 675 / 5.0 // 기준점의 Y 좌표 [격자 거리] +} + +enum MapProjectionType { + case WGS_84 + case KATEC // TM128 + case TM + case GRS_80 + case UTMK + case GRID // for NIA Open API +} + +fileprivate enum DatumParam: Double { + case X = -146.43 + case Y = 507.89 + case Z = 681.46 +} + +fileprivate struct GeographicCoordinateData { + let mapProjectionType: MapProjectionType + let scaleFactor: Double + let longitudeCenter: Double + let latitudeCenter: Double + let falseNorthing: Double + let falseEasting: Double + let major: Double + let minor: Double + let es: Double + let esp: Double + let ind: Double + let sourceM: Double + let destinationM: Double + + init(mapProjectionType: MapProjectionType, scaleFactor: Double, longitudeCenter: Double, latitudeCenter: Double, + falseNorthing: Double, falseEasting: Double, major: Double, minor: Double) { + self.mapProjectionType = mapProjectionType + self.scaleFactor = scaleFactor + self.longitudeCenter = longitudeCenter + self.latitudeCenter = latitudeCenter + self.falseNorthing = falseNorthing + self.falseEasting = falseEasting + self.major = major + self.minor = minor + + let x = (minor / major) + es = 1.0 - x * x + esp = es / (1.0 - es) + ind = es < 0.00001 ? 1.0 : 0.0 + + sourceM = major * GeographicCoordinateData.mlfn( + e0: GeographicCoordinateData.e0fn(es), + e1: GeographicCoordinateData.e1fn(es), + e2: GeographicCoordinateData.e2fn(es), + e3: GeographicCoordinateData.e3fn(es), + phi: latitudeCenter) + destinationM = major * GeographicCoordinateData.mlfn( + e0: GeographicCoordinateData.e0fn(es), + e1: GeographicCoordinateData.e1fn(es), + e2: GeographicCoordinateData.e2fn(es), + e3: GeographicCoordinateData.e3fn(es), + phi: latitudeCenter) + } + + static func e0fn(_ x: Double) -> Double { + return 1.0 - 0.25 * x * (1.0 + x / 16.0 * (3.0 + 1.25 * x)) + } + + static func e1fn(_ x: Double) -> Double { + return 0.375 * x * (1.0 + 0.25 * x * (1.0 + 0.46875 * x)) + } + + static func e2fn(_ x: Double) -> Double { + return 0.05859375 * x * x * (1.0 + 0.75 * x) + } + + static func e3fn(_ x: Double) -> Double { + return x * x * x * (35.0 / 3072.0) + } + + static func mlfn(e0: Double, e1: Double, e2: Double, e3: Double, phi: Double) -> Double { + return e0 * phi - e1 * sin(2.0 * phi) + e2 * sin(4.0 * phi) - e3 * sin(6.0 * phi) + } + + static func asinz(_ value: Double) -> Double { + if abs(value) > 1 { + return asin(value > 0 ? 1 : -1) + } + + return asin(value) + } +} + +class GeoConverter { + enum converterError: Error { + case infinity + } + + fileprivate let geoCoordDatas: [MapProjectionType: GeographicCoordinateData] + fileprivate let espln: Double = 0.0000000001 + + init() { + geoCoordDatas = [ + .WGS_84: GeographicCoordinateData(mapProjectionType: .WGS_84, scaleFactor: 1, longitudeCenter: 0.0, latitudeCenter: 0.0, falseNorthing: 0.0, falseEasting: 0.0, major: 6378137.0, minor: 6356752.3142), + + .KATEC: GeographicCoordinateData(mapProjectionType: .KATEC, scaleFactor: 0.9999 /* 0.9996 */, longitudeCenter: 2.23402144255274 /* 2.22529479629277 */, latitudeCenter: 0.663225115757845, falseNorthing: 600000.0, falseEasting: 400000.0, major: 6377397.155, minor: 6356078.9633422494), + + .TM: GeographicCoordinateData(mapProjectionType: .TM, scaleFactor: 1, + // longitudeCenter: 2.21656815003280, // 127 + longitudeCenter: 2.21661859489671, // 127 + 10.485 minute + latitudeCenter: 0.663225115757845, falseNorthing: 500000.0, falseEasting: 200000.0, major: 6377397.155, minor: 6356078.9633422494), + + .GRS_80: GeographicCoordinateData(mapProjectionType: .GRS_80, scaleFactor: 1, longitudeCenter: 2.21656815003280, latitudeCenter: 0.663225115757845, falseNorthing: 500000.0, falseEasting: 200000.0, major: 6378137, minor: 6356752.3142), + + .UTMK: GeographicCoordinateData(mapProjectionType: .UTMK, scaleFactor: 0.9996, longitudeCenter: 2.22529479629277, latitudeCenter: 0.663225115757845, falseNorthing: 2000000.0, falseEasting: 1000000.0, major: 6378137, minor: 6356752.3141403558)] + } + + func convert(sourceType: MapProjectionType, destinationType: MapProjectionType, geoPoint: GeographicPoint) -> GeographicPoint? { + let sourcePoint = ({ () -> GeographicPoint? in + if sourceType == .WGS_84 { + return GeographicPoint(x: degreeToRadian(geoPoint.x), y: degreeToRadian(geoPoint.y)) + } else { + return tmToGeodetic(source: sourceType, inputPoint: geoPoint) + } + + })() + + guard sourcePoint != nil else { + return nil + } + + let destinationPoint = ({ () -> GeographicPoint? in + if destinationType == .WGS_84 { + return GeographicPoint(x: radianToDegree(sourcePoint!.x), y: radianToDegree(sourcePoint!.y)) + } else { + return geodeticToTm(destination: destinationType, inputPoint: sourcePoint!) + } + })() + + guard destinationPoint != nil else { + return nil + } + + return destinationPoint + } + + func getDistanceByWGS84(from: GeographicPoint, to: GeographicPoint) -> Double { + let fromLatitude = degreeToRadian(from.y) + let fromLongitude = degreeToRadian(from.x) + let toLatitude = degreeToRadian(to.y) + let toLongitude = degreeToRadian(to.x) + + let longitude = toLongitude - fromLongitude + let latitude = toLatitude - fromLatitude + + let a = pow(sin(latitude / 2), 2) + cos(fromLatitude) * cos(toLatitude) * pow(sin(longitude / 2), 2) + + return 6376.5 * 2 * atan2(sqrt(a), sqrt(1 - a)) + } + + // GeographicPoint.x : longitude, GeographicPoint.y : latitude + func wgs84ToGrid(_ point: GeographicPoint) -> GeographicPoint? { + let mapInfo = NisMapInfo() + let pi = asin(1.0) * 2.0 + let degRad = pi / 180.0 + let re = mapInfo.re / mapInfo.grid + let slat1 = mapInfo.slat1 * degRad + let slat2 = mapInfo.slat2 * degRad + let olon = mapInfo.olon * degRad + let olat = mapInfo.olat * degRad + var sn = tan(pi * 0.25 + slat2 * 0.5) / tan(pi * 0.25 + slat1 * 0.5) + sn = log(cos(slat1) / cos(slat2)) / log(sn) + var sf = tan(pi * 0.25 + slat1 * 0.5) + sf = pow(sf, sn) * cos(slat1) / sn + var ro = tan(pi * 0.25 + olat * 0.5) + ro = re * sf / pow(ro, sn) + + var ra = tan(pi * 0.25 + point.y * degRad * 0.5) + ra = re * sf / pow(ra, sn) + var theta = point.x * degRad - olon; + if theta > pi { + theta -= 2.0 * pi + } else if theta < -pi { + theta += 2.0 * pi + } + theta *= sn + + let wgs84Point = GeographicPoint(x: (ra * sin(theta)) + mapInfo.xo, y: (ro - ra * cos(theta)) + mapInfo.yo) + + return GeographicPoint(x: floor(wgs84Point.x + 1.5), y: floor(wgs84Point.y + 1.5)) + } + + private func getDistanceByKatec(from: GeographicPoint, to: GeographicPoint) -> Double? { + return getDistanceByFromType(fromType: .KATEC, from: from, to: to) + } + + private func getDistanceByTM(from: GeographicPoint, to: GeographicPoint) -> Double? { + return getDistanceByFromType(fromType: .TM, from: from, to: to) + } + + private func getDistanceByUTMK(from: GeographicPoint, to: GeographicPoint) -> Double? { + return getDistanceByFromType(fromType: .UTMK, from: from, to: to) + } + + private func getDistanceByGRS80(from: GeographicPoint, to: GeographicPoint) -> Double? { + return getDistanceByFromType(fromType: .GRS_80, from: from, to: to) + } + + + private func getDistanceByFromType(fromType: MapProjectionType, from: GeographicPoint, to: GeographicPoint) -> Double? { + let fromPoint = convert(sourceType: fromType, destinationType: .WGS_84, geoPoint: from) + let toPoint = convert(sourceType: fromType, destinationType: .WGS_84, geoPoint: to) + + guard fromPoint != nil && toPoint != nil else { + return nil + } + + return getDistanceByWGS84(from: fromPoint!, to: toPoint!) + } + + private func getTimeBySec(distance: Double) -> Int { + return Int(round(3600 * distance / 4)) + } + + private func getTimeByMin(distance: Double) -> Int { + return Int(ceil(Double(getTimeBySec(distance: distance)) / 60)) + } + + private func geodeticToTm(destination: MapProjectionType, inputPoint: GeographicPoint) -> GeographicPoint? { + let transformedPoint = transform(source: .WGS_84, destination: destination, geoPoint: inputPoint) + guard transformedPoint != nil else { + return nil + } + + let deltaLongitude = transformedPoint!.x - geoCoordDatas[destination]!.longitudeCenter + let sinForInputPointY = sin(transformedPoint!.y) + let cosForInputPointY = cos(transformedPoint!.y) + + if 0 != geoCoordDatas[destination]!.ind { + let b = cosForInputPointY * sin(deltaLongitude) + if abs(abs(b) - 1) < espln { + return nil // 무한대 에러 + } + } + + let al = cosForInputPointY * deltaLongitude + let als = al * al + let c = geoCoordDatas[destination]!.esp * cosForInputPointY * cosForInputPointY + let tq = tan(transformedPoint!.y) + let t = tq * tq + let con = 1 - geoCoordDatas[destination]!.es * sinForInputPointY * sinForInputPointY + let n = geoCoordDatas[destination]!.major / sqrt(con) + let ml = geoCoordDatas[destination]!.major * + GeographicCoordinateData.mlfn( + e0: GeographicCoordinateData.e0fn(geoCoordDatas[destination]!.es), + e1: GeographicCoordinateData.e1fn(geoCoordDatas[destination]!.es), + e2: GeographicCoordinateData.e2fn(geoCoordDatas[destination]!.es), + e3: GeographicCoordinateData.e3fn(geoCoordDatas[destination]!.es), + phi: transformedPoint!.y) + + let x = geoCoordDatas[destination]!.scaleFactor * n * al * (1 + als / 6 * (1 - t + c + als / 20 * (5 - 18 * t + t * t + 72 * c - 58 * geoCoordDatas[destination]!.esp))) + geoCoordDatas[destination]!.falseEasting + let y = geoCoordDatas[destination]!.scaleFactor * (ml - geoCoordDatas[destination]!.destinationM + n * tq * (als * (0.5 + als / 24 * (5 - t + 9 * c + 4 * c * c + als / 30 * (61 - 58 * t + t * t + 600 * c - 330 * geoCoordDatas[destination]!.esp))))) + geoCoordDatas[destination]!.falseNorthing + + return GeographicPoint(x: x, y: y) + } + + private func tmToGeodetic(source: MapProjectionType, inputPoint: GeographicPoint) -> GeographicPoint? { + let newPoint = GeographicPoint( + x: inputPoint.x - geoCoordDatas[source]!.falseEasting, + y: inputPoint.y - geoCoordDatas[source]!.falseNorthing) + let maxIter = 6 + let con = (geoCoordDatas[source]!.sourceM + newPoint.y / geoCoordDatas[source]!.scaleFactor) / geoCoordDatas[source]!.major + + func calculatePhi(value: Double, count: Int) -> Double? { + let deltaPhi = ((con + GeographicCoordinateData.e1fn(geoCoordDatas[source]!.es) * sin(2 * value) - GeographicCoordinateData.e2fn(geoCoordDatas[source]!.es) * sin(4 * value) + GeographicCoordinateData.e3fn(geoCoordDatas[source]!.es) * sin(6 * value)) / GeographicCoordinateData.e0fn(geoCoordDatas[source]!.es)) - value + let phi = value + deltaPhi + + if abs(deltaPhi) <= espln { + return phi + } else if count >= maxIter { + return nil // 무한대 에러 + } + + return calculatePhi(value: phi, count: count + 1) + } + + let phi = calculatePhi(value: con, count: 0) + if phi == nil { + return nil + } + + let pointForInd = ({ () -> GeographicPoint? in + if 0 != geoCoordDatas[source]!.ind { + let f = exp(inputPoint.x / geoCoordDatas[source]!.major * geoCoordDatas[source]!.scaleFactor) + let g = 0.5 * (f - 1 / f) + let temp = geoCoordDatas[source]!.latitudeCenter + inputPoint.y / (geoCoordDatas[source]!.major * geoCoordDatas[source]!.scaleFactor) + let h = cos(temp) + let con = sqrt((1 - h * h) / (1 + g * g)) + let y = temp < 0 ? -(GeographicCoordinateData.asinz(con)) : GeographicCoordinateData.asinz(con) + let x = 0 == g && 0 == h ? geoCoordDatas[source]!.longitudeCenter : + atan(g / h) + geoCoordDatas[source]!.longitudeCenter + + return GeographicPoint(x: x, y: y) + } else { + return nil + }})() + + let pointForPhi = ({ () -> GeographicPoint? in + if abs(phi!) < Double.pi / 2 { + let sinPhi = sin(phi!) + let cosPhi = cos(phi!) + let tanPhi = tan(phi!) + let c = geoCoordDatas[source]!.esp * cosPhi * cosPhi + let cs = c * c + let t = tanPhi * tanPhi + let ts = t * t + let cont = 1 - geoCoordDatas[source]!.es * sinPhi * sinPhi + let n = geoCoordDatas[source]!.major / sqrt(cont) + let r = n * (1 - geoCoordDatas[source]!.es) / cont + let d = newPoint.x / (n * geoCoordDatas[source]!.scaleFactor) + let ds = d * d + let x = geoCoordDatas[source]!.longitudeCenter + (d * (1 - ds / 6 * (1 + 2 * t + c - ds / 20 * (5 - 2 * c + 28 * t - 3 * cs + 8 * geoCoordDatas[source]!.esp + 24 * ts))) / cosPhi) + let partA = n * tanPhi * ds / r + let partB = 61 + 90 * t + 298 * c + 45 * ts - 252 * geoCoordDatas[source]!.esp - 3 * cs + let y = phi! - partA * (0.5 - ds / 24 * (5 + 3 * t + 10 * c - 4 * cs - 9 * geoCoordDatas[source]!.esp - ds / 30 * partB)) + + return GeographicPoint(x: x, y: y) + } else { + let x = geoCoordDatas[source]!.longitudeCenter + let y = Double.pi * 0.5 * sin(newPoint.y) + + return GeographicPoint(x: x, y: y) + }})() + + if let point = pointForInd { + return transform(source: source, destination: .WGS_84, geoPoint: point) + } else if let point = pointForPhi { + return transform(source: source, destination: .WGS_84, geoPoint: point) + } + + return nil + } + + private func geodeticToGeocentric(type: MapProjectionType, inputPoint: GeographicPoint) -> GeographicPoint? { + /* + * The function geodeticToGeocentric converts geodetic coordinates + * (latitude, longitude, and height) to geocentric coordinates (X, Y, Z), + * according to the current ellipsoid parameters. + * + * GeographicPoint + * X : Geodetic latitude in radians (input) + * Y : Geodetic longitude in radians (input) + * X : Geodetic height, in meters (input) + * + * GeographicPoint + * X : Calculated Geocentric X coordinate, in meters (output) + * Y : Calculated Geocentric Y coordinate, in meters (output) + * Z : Calculated Geocentric Z coordinate, in meters (output) + */ + + /* + ** Don't blow up if Latitude is just a little out of the value + ** range as it may just be a rounding issue. Also removed longitude + ** test, it should be wrapped by Math.cos() and Math.sin(). NFW for PROJ.4, Sep/2001. + */ + func getLatitude(x: Double) -> Double? { + if x < -helfPI && x > -1.001 * helfPI { + return -helfPI + } else if x > helfPI && x < 1.001 * helfPI { + return helfPI + } else if x < -helfPI || x > helfPI { + return nil // x out of range + } else { + return x + } + } + + let latitude = getLatitude(x: inputPoint.y) + if latitude == nil { + return nil + } + + let longitude = inputPoint.x > Double.pi ? inputPoint.x - Double.pi * 2 : inputPoint.x + let height = inputPoint.z + let sinLatitude = sin(latitude!) + let cosLatitude = cos(latitude!) + let rn = geoCoordDatas[type]!.major / sqrt(1.0e0 - geoCoordDatas[type]!.es * pow(sinLatitude, 2)) + + let outputPoint = GeographicPoint( + x: (rn + height) * cosLatitude * cos(longitude), + y: (rn + height) * cosLatitude * sin(longitude), + z: (rn * (1 - geoCoordDatas[type]!.es) + height) * sinLatitude) + + return outputPoint + } + + /** Convert_Geocentric_To_Geodetic + * The method used here is derived from 'An Improved Algorithm for + * Geocentric to Geodetic Coordinate Conversion', by Ralph Toms, Feb 1996 + */ + private func geocentricToGeodetic(type: MapProjectionType, inputPoint: GeographicPoint) -> GeographicPoint { + // square of distance from Z axis + let W2 = inputPoint.x * inputPoint.x + inputPoint.y * inputPoint.y + + // distance from Z axis + let W = sqrt(W2) + + // initial estimate of vertical component + let T0 = inputPoint.z * adC + + // initial estimate of horizontal component + let S0 = sqrt(T0 * T0 + W2) + + // Math.sin(B0), B0 is estimate of Bowring aux doubleiable + let sinB0 = T0 / S0 + + // Math.cos(B0) + let cosB0 = W / S0 + + // cube of Math.sin(B0) + let sin3B0 = sinB0 * sinB0 * sinB0 + + // corrected estimate of vertical component + let T1 = inputPoint.z + geoCoordDatas[type]!.minor * geoCoordDatas[type]!.esp * sin3B0 + + // numerator of Math.cos(phi1) + let sum = W - geoCoordDatas[type]!.major * geoCoordDatas[type]!.es * cosB0 * cosB0 * cosB0 + + // corrected estimate of horizontal component + let s1 = sqrt(T1 * T1 + sum * sum) + + // Math.sin(phi1), phi1 is estimated latitude + let sinP1 = T1 / s1 + + // Math.cos(phi1) + let cosP1 = sum / s1 + + // Earth radius at location + let rn = geoCoordDatas[type]!.major / sqrt(1.0 - geoCoordDatas[type]!.es * sinP1 * sinP1) + + // indicates location is in polar region + let atPole = inputPoint.x == 0 && inputPoint.y == 0 ? true : false + + let longitude = ({ () -> Double in + if inputPoint.x != 0 { + return atan2(inputPoint.y, inputPoint.x) + } else { + if inputPoint.y > 0 { + return helfPI + } else if inputPoint.y < 0 { + return -helfPI + } else { + return 0 + } + } + })() + + let latitude = ({ () -> Double in + if inputPoint.x == 0 && inputPoint.y == 0 && inputPoint.z == 0 { + return helfPI + } else if atPole == false { + return atan(sinP1 / cosP1) + } + + if inputPoint.x == 0 && inputPoint.y == 0 { + if inputPoint.z > 0 { + return helfPI + } else if inputPoint.z < 0 { + return -helfPI + } + } + + return 0 + })() + + let height = ({ () -> Double in + if inputPoint.x == 0 && inputPoint.y == 0 && inputPoint.z == 0 { + return -self.geoCoordDatas[type]!.minor + } + + if cosP1 >= self.cos67p5 { + return W / cosP1 - rn + } else if cosP1 <= -self.cos67p5 { + return W / -cosP1 - rn + } else { + return inputPoint.z / sinP1 + rn * (self.geoCoordDatas[type]!.es - 1) + } + })() + + let outputPoint = GeographicPoint( + x: longitude, + y: latitude, + z: height) + + return outputPoint + } + + private func geodeticToWGS84(_ geoPoint: GeographicPoint) -> GeographicPoint { + return GeographicPoint(x: geoPoint.x + DatumParam.X.rawValue, + y: geoPoint.y + DatumParam.Y.rawValue, + z: geoPoint.z + DatumParam.Z.rawValue) + } + + private func geodeticFromWGS84(_ geoPoint: GeographicPoint) -> GeographicPoint { + return GeographicPoint(x: geoPoint.x - DatumParam.X.rawValue, + y: geoPoint.y - DatumParam.Y.rawValue, + z: geoPoint.z - DatumParam.Z.rawValue) + } + + private func transform(source: MapProjectionType, destination: MapProjectionType, geoPoint: GeographicPoint) -> GeographicPoint? { + guard source != destination else { + return nil + } + + if (source == .KATEC || source == .TM) || (destination == .KATEC || destination == .TM) { + // Convert to geocentric coordinates. + if let point = geodeticToGeocentric(type: source, inputPoint: geoPoint) { + // Convert between datums + + let pointAddedWGS84 = ({ () -> GeographicPoint? in + if source == .KATEC || source == .TM { + return geodeticToWGS84(point) + } else { + return nil + } + })() + + let newPoint = ({ () -> GeographicPoint? in + if destination == .KATEC || destination == .TM { + return geodeticFromWGS84(pointAddedWGS84 == nil ? point : pointAddedWGS84!) + } else { + return nil + } + })() + + // Convert back to geodetic coordinates + if let point = newPoint { + return geocentricToGeodetic(type: destination, inputPoint: point) + } else if let point = pointAddedWGS84 { + return geocentricToGeodetic(type: destination, inputPoint: point) + } else { + return nil + } + } else { + return nil + } + } else { + return nil + } + } + + private func degreeToRadian(_ degree: Double) -> Double { + return degree * Double.pi / 180 + } + + private func radianToDegree(_ radian: Double) -> Double { + return radian * 180 / Double.pi + } + + private let helfPI = 0.5 * Double.pi + private let cos67p5 = 0.38268343236508977 // cosine of 67.5 degrees + private let adC = 1.0026000 +} From 6d7a08a9c7a803af5baa2b0ab3bee5b0c96ad5d9 Mon Sep 17 00:00:00 2001 From: presto Date: Tue, 22 Jan 2019 17:02:17 +0900 Subject: [PATCH 02/84] CALayer+ / NSLayoutDimension+ / UIColor+ --- FineDust/Extension/CALayer+.swift | 22 +++++++++++++++++++++ FineDust/Extension/NSLayoutDimension+.swift | 15 ++++++++++++++ FineDust/Extension/UIColor+.swift | 18 +++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 FineDust/Extension/CALayer+.swift create mode 100644 FineDust/Extension/NSLayoutDimension+.swift diff --git a/FineDust/Extension/CALayer+.swift b/FineDust/Extension/CALayer+.swift new file mode 100644 index 00000000..b5e97cbb --- /dev/null +++ b/FineDust/Extension/CALayer+.swift @@ -0,0 +1,22 @@ +// +// CALayer+.swift +// FineDust +// +// Created by Presto on 22/01/2019. +// Copyright © 2019 boostcamp3rd. All rights reserved. +// + +import UIKit + +extension CALayer { + func setBorder( + color borderColor: UIColor, + width borderWidth: CGFloat = 1, + radius cornerRadius: CGFloat = 0 + ) { + masksToBounds = true + self.borderColor = borderColor.cgColor + self.borderWidth = borderWidth + self.cornerRadius = cornerRadius + } +} diff --git a/FineDust/Extension/NSLayoutDimension+.swift b/FineDust/Extension/NSLayoutDimension+.swift new file mode 100644 index 00000000..ba85b44d --- /dev/null +++ b/FineDust/Extension/NSLayoutDimension+.swift @@ -0,0 +1,15 @@ +// +// NSLayoutDimension+.swift +// FineDust +// +// Created by Presto on 22/01/2019. +// Copyright © 2019 boostcamp3rd. All rights reserved. +// + +import UIKit + +extension NSLayoutDimension { + func equal(toConstant offset: CGFloat) -> NSLayoutConstraint { + return constraint(equalToConstant: offset) + } +} diff --git a/FineDust/Extension/UIColor+.swift b/FineDust/Extension/UIColor+.swift index 8534ece9..bca75b83 100644 --- a/FineDust/Extension/UIColor+.swift +++ b/FineDust/Extension/UIColor+.swift @@ -9,11 +9,29 @@ import UIKit extension UIColor { + /// RGB 값으로 색상 만들기 convenience init(red: CGFloat, green: CGFloat, blue: CGFloat) { self.init(red: red / 255, green: green / 255, blue: blue / 255, alpha: 1) } + /// RGB 값이 같을 때 색상 만들기 convenience init(rgb: CGFloat) { self.init(red: rgb, green: rgb, blue: rgb) } + + /// HEX 값으로 색상 만들기 + convenience init(red: Int, green: Int, blue: Int) { + self.init( + red: CGFloat(red) / 255, + green: CGFloat(green) / 255, + blue: CGFloat(blue) / 255, + alpha: 1 + ) + } + + /// HEX 값이 같을 때 색상 만들기 + convenience init(rgb: Int) { + self.init(red: (rgb >> 16) & 0xFF, green: (rgb >> 8) & 0xFF, blue: rgb & 0xFF + ) + } } From 14df570c38ed1924386b10f45492e6838a73d25b Mon Sep 17 00:00:00 2001 From: presto Date: Tue, 22 Jan 2019 17:02:37 +0900 Subject: [PATCH 03/84] =?UTF-8?q?=ED=86=B5=EA=B3=84=20=EB=B6=80=EB=B6=84?= =?UTF-8?q?=20=EB=B7=B0=20=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../StatisticsDatePickerViewController.swift | 22 ++ .../Controller/StatisticsViewController.swift | 98 ++++++++- FineDust/Statistics/Statistics.storyboard | 65 +++++- .../View/Ratio Graph/RatioGraphView.swift | 113 +++++++++++ .../View/Ratio Graph/RatioGraphView.xib | 48 +++++ .../View/Value Graph/ValueGraphView.swift | 76 +++++++ .../View/Value Graph/ValueGraphView.xib | 188 ++++++++++++++++++ 7 files changed, 607 insertions(+), 3 deletions(-) create mode 100644 FineDust/Statistics/Controller/StatisticsDatePickerViewController.swift create mode 100644 FineDust/Statistics/View/Ratio Graph/RatioGraphView.swift create mode 100644 FineDust/Statistics/View/Ratio Graph/RatioGraphView.xib create mode 100644 FineDust/Statistics/View/Value Graph/ValueGraphView.swift create mode 100644 FineDust/Statistics/View/Value Graph/ValueGraphView.xib diff --git a/FineDust/Statistics/Controller/StatisticsDatePickerViewController.swift b/FineDust/Statistics/Controller/StatisticsDatePickerViewController.swift new file mode 100644 index 00000000..5a7d9356 --- /dev/null +++ b/FineDust/Statistics/Controller/StatisticsDatePickerViewController.swift @@ -0,0 +1,22 @@ +// +// StatisticsDatePickerViewController.swift +// FineDust +// +// Created by Presto on 22/01/2019. +// Copyright © 2019 boostcamp3rd. All rights reserved. +// + +import UIKit + +final class StatisticsDatePickerViewController: UIViewController { + + @IBOutlet private weak var datePicker: UIDatePicker! { + didSet { + datePicker.maximumDate = Date() + } + } + + override func viewDidLoad() { + super.viewDidLoad() + } +} diff --git a/FineDust/Statistics/Controller/StatisticsViewController.swift b/FineDust/Statistics/Controller/StatisticsViewController.swift index 1c3d1180..ab2c2e18 100644 --- a/FineDust/Statistics/Controller/StatisticsViewController.swift +++ b/FineDust/Statistics/Controller/StatisticsViewController.swift @@ -8,10 +8,104 @@ import UIKit -class StatisticsViewController: UIViewController { +/// 통계 관련 뷰 컨트롤러 +final class StatisticsViewController: UIViewController { + + /// CALayer 관련 상수 정의 + enum Layer { + + static let cornerRadius: CGFloat = 15.0 + + static let borderWidth: CGFloat = 1.0 + } + + // MARK: IBOutlet + + /// 값 그래프 배경 뷰 + @IBOutlet private weak var valueGraphBackgroundView: UIView! { + didSet { + valueGraphBackgroundView.layer.setBorder( + color: .black, + width: Layer.borderWidth, + radius: Layer.cornerRadius + ) + } + } + + /// 비율 그래프 배경 뷰 + @IBOutlet private weak var ratioGraphBackgroundView: UIView! { + didSet { + ratioGraphBackgroundView.layer.setBorder( + color: .black, + width: Layer.borderWidth, + radius: Layer.cornerRadius + ) + } + } + + // MARK: View + + /// 값 그래프 + private var valueGraphView: ValueGraphView! { + didSet { + valueGraphView.delegate = self + } + } + + /// 비율 그래프 + private var ratioGraphView: RatioGraphView! + + // MARK: Life Cycle override func viewDidLoad() { super.viewDidLoad() - tabBarItem.title = "통계" + navigationItem.title = "미세먼지 분석" + createSubviews() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + setConstraintsToSubviews() + } +} + +// MARK: - ValueGraphView Delegate 구현 + +extension StatisticsViewController: ValueGraphViewDelegate { + func valueGraphView(_ view: ValueGraphView, didTapDateButton button: UIButton) { + UIViewController + .create( + fromStoryboard: Storyboard.statistics, + identifier: StatisticsDatePickerViewController.classNameToString + ) + .present(to: self, transitionStyle: .crossDissolve) + } +} + +// MARK: - private extension + +private extension StatisticsViewController { + /// 서브뷰 생성하여 프로퍼티에 할당 + func createSubviews() { + valueGraphView = UIView.create(fromXib: ValueGraphView.classNameToString) as? ValueGraphView + ratioGraphView = UIView.create(fromXib: RatioGraphView.classNameToString) as? RatioGraphView + valueGraphView.translatesAutoresizingMaskIntoConstraints = false + ratioGraphView.translatesAutoresizingMaskIntoConstraints = false + valueGraphBackgroundView.addSubview(valueGraphView) + ratioGraphBackgroundView.addSubview(ratioGraphView) + } + + /// 서브뷰에 오토레이아웃 설정 + func setConstraintsToSubviews() { + NSLayoutConstraint.activate([ + valueGraphView.top.equal(to: valueGraphBackgroundView.top), + valueGraphView.leading.equal(to: valueGraphBackgroundView.leading), + valueGraphView.trailing.equal(to: valueGraphBackgroundView.trailing), + valueGraphView.bottom.equal(to: valueGraphBackgroundView.bottom), + ratioGraphView.top.equal(to: ratioGraphBackgroundView.top), + ratioGraphView.leading.equal(to: ratioGraphBackgroundView.leading), + ratioGraphView.trailing.equal(to: ratioGraphBackgroundView.trailing), + ratioGraphView.bottom.equal(to: ratioGraphBackgroundView.bottom) + ]) } } diff --git a/FineDust/Statistics/Statistics.storyboard b/FineDust/Statistics/Statistics.storyboard index 008c5676..b21de21d 100644 --- a/FineDust/Statistics/Statistics.storyboard +++ b/FineDust/Statistics/Statistics.storyboard @@ -10,13 +10,16 @@ - + + + + @@ -33,14 +36,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FineDust/Statistics/View/Ratio Graph/RatioGraphView.swift b/FineDust/Statistics/View/Ratio Graph/RatioGraphView.swift new file mode 100644 index 00000000..1b977dd9 --- /dev/null +++ b/FineDust/Statistics/View/Ratio Graph/RatioGraphView.swift @@ -0,0 +1,113 @@ +// +// RatioGraphView.swift +// FineDust +// +// Created by Presto on 22/01/2019. +// Copyright © 2019 boostcamp3rd. All rights reserved. +// + +import UIKit + +/// 비율 그래프 뷰 +final class RatioGraphView: UIView { + + /// 비율 관련 작업을 위한 계산 프로퍼티 + var ratio: CGFloat { + get { + return _ratio + } + set { + _ratio = newValue + // 원 그래프 비율 변경하는 코드 추가 + } + } + + /// 비율을 저장하는 private 프로퍼티 + private var _ratio: CGFloat = 0.0 + + /// 배경 뷰 높이 + private var backgroundViewHeight: CGFloat { + return backgroundView.bounds.height - 20 + } + + // MARK: IBOutlet + + /// 배경 뷰 + @IBOutlet private weak var backgroundView: UIView! + + // MARK: View + + /// 원 그래프의 전체 비율 부분 뷰 + private lazy var entireSectionView: UIView = { + let view = UIView( + frame: CGRect( + x: 0, + y: 0, + width: backgroundViewHeight, + height: backgroundViewHeight + ) + ) + backgroundView.addSubview(view) + return view + }() + + /// 원 그래프의 일부 비율 부분 뷰 + private lazy var portionSectionView: UIView = { + let view = UIView( + frame: CGRect( + x: 0, + y: 0, + width: backgroundViewHeight, + height: backgroundViewHeight + ) + ) + backgroundView.addSubview(view) + return view + }() + + // MARK: Life Cycle + + override func awakeFromNib() { + super.awakeFromNib() + drawEntireSectionView() + drawPortionSectionView() + } + + // MARK: Method + + /// 전체 비율 부분 뷰 그리기 + private func drawEntireSectionView() { + entireSectionView.backgroundColor = .lightGray + entireSectionView.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + entireSectionView.height.equal(toConstant: backgroundViewHeight), + entireSectionView.width.equal(toConstant: backgroundViewHeight), + entireSectionView.centerX.equal(to: backgroundView.centerX), + entireSectionView.centerY.equal(to: backgroundView.centerY) + ]) + entireSectionView.clipsToBounds = true + entireSectionView.layer.cornerRadius = backgroundViewHeight / 2 + } + + /// 일부 비율 부분 뷰 그리기. `endAngle`이 중요하다. + private func drawPortionSectionView() { + let path = UIBezierPath() + path.move(to: entireSectionView.center) + path.addLine(to: CGPoint( + x: entireSectionView.frame.width / 2, + y: entireSectionView.frame.height + )) + path.addArc( + withCenter: entireSectionView.center, + radius: backgroundViewHeight, + startAngle: -.pi / 2, + endAngle: -.pi / 4, + clockwise: true + ) + path.close() + let shapeLayer = CAShapeLayer() + shapeLayer.path = path.cgPath + shapeLayer.fillColor = UIColor.black.cgColor + entireSectionView.layer.addSublayer(shapeLayer) + } +} diff --git a/FineDust/Statistics/View/Ratio Graph/RatioGraphView.xib b/FineDust/Statistics/View/Ratio Graph/RatioGraphView.xib new file mode 100644 index 00000000..d9c20a80 --- /dev/null +++ b/FineDust/Statistics/View/Ratio Graph/RatioGraphView.xib @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FineDust/Statistics/View/Value Graph/ValueGraphView.swift b/FineDust/Statistics/View/Value Graph/ValueGraphView.swift new file mode 100644 index 00000000..eb66e153 --- /dev/null +++ b/FineDust/Statistics/View/Value Graph/ValueGraphView.swift @@ -0,0 +1,76 @@ +// +// ValueGraphView.swift +// FineDust +// +// Created by Presto on 22/01/2019. +// Copyright © 2019 boostcamp3rd. All rights reserved. +// + +import UIKit + +/// ValueGraphView Delegate +protocol ValueGraphViewDelegate: class { + func valueGraphView(_ view: ValueGraphView, didTapDateButton button: UIButton) +} + +/// 지정 날짜 기준 일주일 그래프 관련 뷰 +final class ValueGraphView: UIView { + + enum Layer { + + static let borderWidth: CGFloat = 1.0 + } + + // MARK: delegate + + weak var delegate: ValueGraphViewDelegate? + + // MARK: IBOutlet + + /// 제목 레이블 + @IBOutlet private weak var titleLabel: UILabel! + + /// 날짜 선택 버튼 + @IBOutlet private weak var dateButton: UIButton! { + didSet { + dateButton.addTarget(self, action: #selector(dateButtonDidTap(_:)), for: .touchUpInside) + } + } + + /// 요일 레이블 모음 + @IBOutlet private var dayLabels: [UILabel]! + + /// 그래프 뷰 모음 + @IBOutlet private var graphViews: [UIView]! { + didSet { + graphViews.forEach { $0.layer.setBorder(color: .black, width: Layer.borderWidth) } + } + } + + /// 그래프 높이 제약 모음 + @IBOutlet var graphViewHeightConstraints: [NSLayoutConstraint]! + + // MARK: Life Cycle + + override func awakeFromNib() { + super.awakeFromNib() + } + + // MARK: @objc Method + + @objc private func dateButtonDidTap(_ sender: UIButton) { + delegate?.valueGraphView(self, didTapDateButton: sender) + } + + // MARK: Method + + /// 요일 레이블 텍스트 설정 + private func setTitleDayLabels() { + + } + + /// 그래프 뷰 높이 제약에 애니메이션 효과 설정 + private func animateHeights() { + + } +} diff --git a/FineDust/Statistics/View/Value Graph/ValueGraphView.xib b/FineDust/Statistics/View/Value Graph/ValueGraphView.xib new file mode 100644 index 00000000..48112eb7 --- /dev/null +++ b/FineDust/Statistics/View/Value Graph/ValueGraphView.xib @@ -0,0 +1,188 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From c115011d8cb6fef1e56ae20a133a5e888743b6e7 Mon Sep 17 00:00:00 2001 From: presto Date: Tue, 22 Jan 2019 17:03:09 +0900 Subject: [PATCH 04/84] =?UTF-8?q?=EC=8A=A4=ED=86=A0=EB=A6=AC=EB=B3=B4?= =?UTF-8?q?=EB=93=9C=20=EC=9D=B4=EB=A6=84=20=EB=AA=A8=EC=95=84=20=EB=86=93?= =?UTF-8?q?=EB=8A=94=20=EC=97=B4=EA=B1=B0=ED=98=95=20=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FineDust.xcodeproj/project.pbxproj | 48 ++++++++++++++++++++++++++++++ FineDust/Common/Common.storyboard | 6 ++-- FineDust/Common/Storyboard.swift | 18 +++++++++++ 3 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 FineDust/Common/Storyboard.swift diff --git a/FineDust.xcodeproj/project.pbxproj b/FineDust.xcodeproj/project.pbxproj index 1a8b090a..219bdc3f 100644 --- a/FineDust.xcodeproj/project.pbxproj +++ b/FineDust.xcodeproj/project.pbxproj @@ -29,6 +29,14 @@ 192CDAC521F6B2DF000CE35D /* Common.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 192CDAC421F6B2DF000CE35D /* Common.storyboard */; }; 192CDAC921F6B61D000CE35D /* StatisticsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDAC821F6B61D000CE35D /* StatisticsViewController.swift */; }; 192CDACB21F6B62E000CE35D /* FeedbackViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDACA21F6B62E000CE35D /* FeedbackViewController.swift */; }; + 192CDACD21F6C85C000CE35D /* ValueGraphView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDACC21F6C85C000CE35D /* ValueGraphView.swift */; }; + 192CDACF21F6C865000CE35D /* RatioGraphView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDACE21F6C865000CE35D /* RatioGraphView.swift */; }; + 192CDAD121F6C874000CE35D /* ValueGraphView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 192CDAD021F6C874000CE35D /* ValueGraphView.xib */; }; + 192CDAD321F6C87E000CE35D /* RatioGraphView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 192CDAD221F6C87E000CE35D /* RatioGraphView.xib */; }; + 192CDADF21F6EA03000CE35D /* NSLayoutDimension+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDADE21F6EA03000CE35D /* NSLayoutDimension+.swift */; }; + 192CDAE121F6F5B2000CE35D /* CALayer+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDAE021F6F5B2000CE35D /* CALayer+.swift */; }; + 192CDAE321F6FEF9000CE35D /* StatisticsDatePickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDAE221F6FEF9000CE35D /* StatisticsDatePickerViewController.swift */; }; + 192CDAE521F70169000CE35D /* Storyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDAE421F70169000CE35D /* Storyboard.swift */; }; 1949B09921F5EB3200B22915 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1949B09821F5EB3200B22915 /* AppDelegate.swift */; }; 1949B09E21F5EB3200B22915 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1949B09C21F5EB3200B22915 /* Main.storyboard */; }; 1949B0A121F5EB3200B22915 /* FineDust.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 1949B09F21F5EB3200B22915 /* FineDust.xcdatamodeld */; }; @@ -60,6 +68,14 @@ 192CDAC421F6B2DF000CE35D /* Common.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Common.storyboard; sourceTree = ""; }; 192CDAC821F6B61D000CE35D /* StatisticsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatisticsViewController.swift; sourceTree = ""; }; 192CDACA21F6B62E000CE35D /* FeedbackViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbackViewController.swift; sourceTree = ""; }; + 192CDACC21F6C85C000CE35D /* ValueGraphView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValueGraphView.swift; sourceTree = ""; }; + 192CDACE21F6C865000CE35D /* RatioGraphView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RatioGraphView.swift; sourceTree = ""; }; + 192CDAD021F6C874000CE35D /* ValueGraphView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ValueGraphView.xib; sourceTree = ""; }; + 192CDAD221F6C87E000CE35D /* RatioGraphView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = RatioGraphView.xib; sourceTree = ""; }; + 192CDADE21F6EA03000CE35D /* NSLayoutDimension+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSLayoutDimension+.swift"; sourceTree = ""; }; + 192CDAE021F6F5B2000CE35D /* CALayer+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CALayer+.swift"; sourceTree = ""; }; + 192CDAE221F6FEF9000CE35D /* StatisticsDatePickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatisticsDatePickerViewController.swift; sourceTree = ""; }; + 192CDAE421F70169000CE35D /* Storyboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Storyboard.swift; sourceTree = ""; }; 1949B09521F5EB3200B22915 /* FineDust.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FineDust.app; sourceTree = BUILT_PRODUCTS_DIR; }; 1949B09821F5EB3200B22915 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 1949B09D21F5EB3200B22915 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; @@ -130,6 +146,7 @@ isa = PBXGroup; children = ( 192CDAC821F6B61D000CE35D /* StatisticsViewController.swift */, + 192CDAE221F6FEF9000CE35D /* StatisticsDatePickerViewController.swift */, ); path = Controller; sourceTree = ""; @@ -137,6 +154,8 @@ 192CDABA21F6B204000CE35D /* View */ = { isa = PBXGroup; children = ( + 192CDAD421F6D7E9000CE35D /* Value Graph */, + 192CDAD521F6D7EE000CE35D /* Ratio Graph */, ); path = View; sourceTree = ""; @@ -171,6 +190,24 @@ path = View; sourceTree = ""; }; + 192CDAD421F6D7E9000CE35D /* Value Graph */ = { + isa = PBXGroup; + children = ( + 192CDAD021F6C874000CE35D /* ValueGraphView.xib */, + 192CDACC21F6C85C000CE35D /* ValueGraphView.swift */, + ); + path = "Value Graph"; + sourceTree = ""; + }; + 192CDAD521F6D7EE000CE35D /* Ratio Graph */ = { + isa = PBXGroup; + children = ( + 192CDAD221F6C87E000CE35D /* RatioGraphView.xib */, + 192CDACE21F6C865000CE35D /* RatioGraphView.swift */, + ); + path = "Ratio Graph"; + sourceTree = ""; + }; 1949B08C21F5EB3200B22915 = { isa = PBXGroup; children = ( @@ -229,6 +266,7 @@ isa = PBXGroup; children = ( 192CDAC421F6B2DF000CE35D /* Common.storyboard */, + 192CDAE421F70169000CE35D /* Storyboard.swift */, ); path = Common; sourceTree = ""; @@ -246,6 +284,8 @@ 192CDAA621F60914000CE35D /* Date+.swift */, 192CDAB021F627A3000CE35D /* NSLayoutConstraint+.swift */, 192CDAB221F628C9000CE35D /* NSLayoutAnchor+.swift */, + 192CDADE21F6EA03000CE35D /* NSLayoutDimension+.swift */, + 192CDAE021F6F5B2000CE35D /* CALayer+.swift */, ); path = Extension; sourceTree = ""; @@ -333,11 +373,13 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 192CDAD321F6C87E000CE35D /* RatioGraphView.xib in Resources */, 1949B0AF21F5EB9F00B22915 /* .swiftlint.yml in Resources */, 1949B0A621F5EB3600B22915 /* LaunchScreen.storyboard in Resources */, 1949B0A321F5EB3600B22915 /* Assets.xcassets in Resources */, 192CDAC521F6B2DF000CE35D /* Common.storyboard in Resources */, 192CDAC021F6B242000CE35D /* Statistics.storyboard in Resources */, + 192CDAD121F6C874000CE35D /* ValueGraphView.xib in Resources */, 1949B09E21F5EB3200B22915 /* Main.storyboard in Resources */, 192CDAC221F6B24D000CE35D /* Feedback.storyboard in Resources */, ); @@ -372,14 +414,20 @@ files = ( 192CDAAA21F61D0C000CE35D /* GeoConverter.swift in Sources */, 192CDAA521F6046D000CE35D /* MainViewController.swift in Sources */, + 192CDADF21F6EA03000CE35D /* NSLayoutDimension+.swift in Sources */, 192CDA9521F5EE11000CE35D /* UIAlertController+.swift in Sources */, 192CDA8F21F5EDFC000CE35D /* NSObject+.swift in Sources */, 192CDA9921F5EE1E000CE35D /* String+.swift in Sources */, + 192CDACD21F6C85C000CE35D /* ValueGraphView.swift in Sources */, + 192CDAE521F70169000CE35D /* Storyboard.swift in Sources */, + 192CDACF21F6C865000CE35D /* RatioGraphView.swift in Sources */, 192CDAA121F603C5000CE35D /* API+FineDust.swift in Sources */, 192CDA9321F5EE09000CE35D /* UIView+.swift in Sources */, 192CDAAF21F623ED000CE35D /* ObservatoryResponse.swift in Sources */, 192CDA9121F5EE04000CE35D /* UIViewController+.swift in Sources */, 1949B09921F5EB3200B22915 /* AppDelegate.swift in Sources */, + 192CDAE321F6FEF9000CE35D /* StatisticsDatePickerViewController.swift in Sources */, + 192CDAE121F6F5B2000CE35D /* CALayer+.swift in Sources */, 192CDACB21F6B62E000CE35D /* FeedbackViewController.swift in Sources */, 192CDAB321F628C9000CE35D /* NSLayoutAnchor+.swift in Sources */, 192CDAC921F6B61D000CE35D /* StatisticsViewController.swift in Sources */, diff --git a/FineDust/Common/Common.storyboard b/FineDust/Common/Common.storyboard index 572b5c29..483d47c6 100644 --- a/FineDust/Common/Common.storyboard +++ b/FineDust/Common/Common.storyboard @@ -29,10 +29,10 @@ - + - + @@ -56,7 +56,7 @@ - + diff --git a/FineDust/Common/Storyboard.swift b/FineDust/Common/Storyboard.swift new file mode 100644 index 00000000..f5cd5ed4 --- /dev/null +++ b/FineDust/Common/Storyboard.swift @@ -0,0 +1,18 @@ +// +// Storyboard.swift +// FineDust +// +// Created by Presto on 22/01/2019. +// Copyright © 2019 boostcamp3rd. All rights reserved. +// + +import Foundation + +enum Storyboard { + + static let main = "Main" + + static let statistics = "Statistics" + + static let feedback = "Feedback" +} From 5e824be6d770c6f4614ece0063ff9f2c048decf2 Mon Sep 17 00:00:00 2001 From: presto Date: Wed, 23 Jan 2019 11:03:59 +0900 Subject: [PATCH 05/84] =?UTF-8?q?=ED=86=B5=EA=B3=84=20=EB=B6=80=EB=B6=84?= =?UTF-8?q?=20=EB=B7=B0=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controller/StatisticsViewController.swift | 10 +-- FineDust/Statistics/Statistics.storyboard | 36 --------- .../View/Ratio Graph/RatioGraphView.swift | 75 ++++++++++++------- .../View/Value Graph/ValueGraphView.swift | 14 +++- FineDust/Supporting Files/AppDelegate.swift | 9 ++- 5 files changed, 71 insertions(+), 73 deletions(-) diff --git a/FineDust/Statistics/Controller/StatisticsViewController.swift b/FineDust/Statistics/Controller/StatisticsViewController.swift index ab2c2e18..b1b8140e 100644 --- a/FineDust/Statistics/Controller/StatisticsViewController.swift +++ b/FineDust/Statistics/Controller/StatisticsViewController.swift @@ -66,6 +66,9 @@ final class StatisticsViewController: UIViewController { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) setConstraintsToSubviews() + API.shared.fetchObservatory { response, error in + print(response, error) + } } } @@ -73,12 +76,7 @@ final class StatisticsViewController: UIViewController { extension StatisticsViewController: ValueGraphViewDelegate { func valueGraphView(_ view: ValueGraphView, didTapDateButton button: UIButton) { - UIViewController - .create( - fromStoryboard: Storyboard.statistics, - identifier: StatisticsDatePickerViewController.classNameToString - ) - .present(to: self, transitionStyle: .crossDissolve) + } } diff --git a/FineDust/Statistics/Statistics.storyboard b/FineDust/Statistics/Statistics.storyboard index b21de21d..93b6f595 100644 --- a/FineDust/Statistics/Statistics.storyboard +++ b/FineDust/Statistics/Statistics.storyboard @@ -69,41 +69,5 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/FineDust/Statistics/View/Ratio Graph/RatioGraphView.swift b/FineDust/Statistics/View/Ratio Graph/RatioGraphView.swift index 1b977dd9..19da65c8 100644 --- a/FineDust/Statistics/View/Ratio Graph/RatioGraphView.swift +++ b/FineDust/Statistics/View/Ratio Graph/RatioGraphView.swift @@ -11,20 +11,13 @@ import UIKit /// 비율 그래프 뷰 final class RatioGraphView: UIView { - /// 비율 관련 작업을 위한 계산 프로퍼티 - var ratio: CGFloat { - get { - return _ratio - } - set { - _ratio = newValue + /// 비율을 저장하는 프로퍼티 + var ratio: CGFloat = 0.0 { + didSet { // 원 그래프 비율 변경하는 코드 추가 } } - /// 비율을 저장하는 private 프로퍼티 - private var _ratio: CGFloat = 0.0 - /// 배경 뷰 높이 private var backgroundViewHeight: CGFloat { return backgroundView.bounds.height - 20 @@ -51,37 +44,38 @@ final class RatioGraphView: UIView { return view }() - /// 원 그래프의 일부 비율 부분 뷰 - private lazy var portionSectionView: UIView = { - let view = UIView( - frame: CGRect( - x: 0, - y: 0, - width: backgroundViewHeight, - height: backgroundViewHeight - ) - ) - backgroundView.addSubview(view) - return view - }() + /// 가운데 비어 있는 원 + private var centerHoleView: UIView! + + /// 퍼센트 레이블 + private var percentLabel: UILabel! // MARK: Life Cycle override func awakeFromNib() { super.awakeFromNib() + setup() + } +} + +// MARK: - Private Extension + +private extension RatioGraphView { + /// 초기 설정 + private func setup() { drawEntireSectionView() drawPortionSectionView() + drawCenterHoleView() + setPercentLabel() } - // MARK: Method - /// 전체 비율 부분 뷰 그리기 private func drawEntireSectionView() { entireSectionView.backgroundColor = .lightGray entireSectionView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ - entireSectionView.height.equal(toConstant: backgroundViewHeight), entireSectionView.width.equal(toConstant: backgroundViewHeight), + entireSectionView.height.equal(toConstant: backgroundViewHeight), entireSectionView.centerX.equal(to: backgroundView.centerX), entireSectionView.centerY.equal(to: backgroundView.centerY) ]) @@ -110,4 +104,33 @@ final class RatioGraphView: UIView { shapeLayer.fillColor = UIColor.black.cgColor entireSectionView.layer.addSublayer(shapeLayer) } + + /// 가운데 빈 효과 내는 원 그리기. + private func drawCenterHoleView() { + centerHoleView = UIView() + centerHoleView.backgroundColor = .white + backgroundView.addSubview(centerHoleView) + centerHoleView.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + centerHoleView.width.equal(toConstant: backgroundViewHeight / 2), + centerHoleView.height.equal(toConstant: backgroundViewHeight / 2), + centerHoleView.centerX.equal(to: backgroundView.centerX), + centerHoleView.centerY.equal(to: backgroundView.centerY) + ]) + centerHoleView.clipsToBounds = true + centerHoleView.layer.cornerRadius = backgroundViewHeight / 2 / 2 + } + + /// 비어 있는 원 안에 퍼센트 레이블 설정하기 + private func setPercentLabel() { + percentLabel = UILabel() + percentLabel.font = UIFont.systemFont(ofSize: 20, weight: .bold) + percentLabel.text = "\(Int(ratio * 100))%" + percentLabel.translatesAutoresizingMaskIntoConstraints = false + centerHoleView.addSubview(percentLabel) + NSLayoutConstraint.activate([ + percentLabel.centerX.equal(to: centerHoleView.centerX), + percentLabel.centerY.equal(to: centerHoleView.centerY) + ]) + } } diff --git a/FineDust/Statistics/View/Value Graph/ValueGraphView.swift b/FineDust/Statistics/View/Value Graph/ValueGraphView.swift index eb66e153..6db23ed6 100644 --- a/FineDust/Statistics/View/Value Graph/ValueGraphView.swift +++ b/FineDust/Statistics/View/Value Graph/ValueGraphView.swift @@ -16,6 +16,7 @@ protocol ValueGraphViewDelegate: class { /// 지정 날짜 기준 일주일 그래프 관련 뷰 final class ValueGraphView: UIView { + /// 레이어 관련 상수 모음 enum Layer { static let borderWidth: CGFloat = 1.0 @@ -25,6 +26,11 @@ final class ValueGraphView: UIView { weak var delegate: ValueGraphViewDelegate? + // MARK: Property + + /// 비율 모음 + var ratios: [CGFloat] = [] + // MARK: IBOutlet /// 제목 레이블 @@ -48,7 +54,13 @@ final class ValueGraphView: UIView { } /// 그래프 높이 제약 모음 - @IBOutlet var graphViewHeightConstraints: [NSLayoutConstraint]! + @IBOutlet var graphViewHeightConstraints: [NSLayoutConstraint]! { + didSet { + for (index, constraint) in graphViewHeightConstraints.enumerated() { + graphViewHeightConstraints[index] = constraint.changeMultiplier(to: 0.5) + } + } + } // MARK: Life Cycle diff --git a/FineDust/Supporting Files/AppDelegate.swift b/FineDust/Supporting Files/AppDelegate.swift index 1a597335..3900cd19 100644 --- a/FineDust/Supporting Files/AppDelegate.swift +++ b/FineDust/Supporting Files/AppDelegate.swift @@ -106,21 +106,22 @@ extension AppDelegate: CLLocationManagerDelegate { let locale = Locale(identifier: "ko_KR") guard let location = locations.last else { return } let coordinate = location.coordinate - print(coordinate.latitude, coordinate.longitude) let convertedCoordinate = GeoConverter().convert( sourceType: .WGS_84, destinationType: .TM, geoPoint: GeographicPoint(x: coordinate.longitude, y: coordinate.latitude) ) - print(convertedCoordinate?.x, convertedCoordinate?.y) GeoInfo.shared.set(x: convertedCoordinate?.x ?? 0, y: convertedCoordinate?.y ?? 0) +// API.shared.getObservatoryPost { response, error in +// print(response, error) +// } CLGeocoder().reverseGeocodeLocation(location, preferredLocale: locale) { placeMarks, error in if let error = error { print(error.localizedDescription) return } - guard let placeMark = placeMarks?.last else { return } - print(placeMark.administrativeArea, placeMark.country, placeMark.locality, placeMark.name) + // administrativeArea / country / locality / name + // 서울특별시 / 대한민국 / 강남구 / 강남대로 382 } manager.stopUpdatingLocation() } From de4a39f4a30d050a408da002eb5695ae17f8e248 Mon Sep 17 00:00:00 2001 From: presto Date: Wed, 23 Jan 2019 11:04:27 +0900 Subject: [PATCH 06/84] =?UTF-8?q?=EC=A2=8C=ED=91=9C=20=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=20=EC=8B=B1=EA=B8=80=ED=86=A4=20=EA=B0=9D=EC=B2=B4=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FineDust.xcodeproj/project.pbxproj | 16 ++++++++++------ FineDust/Common/Common.storyboard | 4 ++-- FineDust/Extension/UIViewController+.swift | 10 +++++++--- FineDust/Model/GeoInfo.swift | 6 ++++-- 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/FineDust.xcodeproj/project.pbxproj b/FineDust.xcodeproj/project.pbxproj index 219bdc3f..b7b483f0 100644 --- a/FineDust.xcodeproj/project.pbxproj +++ b/FineDust.xcodeproj/project.pbxproj @@ -35,7 +35,6 @@ 192CDAD321F6C87E000CE35D /* RatioGraphView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 192CDAD221F6C87E000CE35D /* RatioGraphView.xib */; }; 192CDADF21F6EA03000CE35D /* NSLayoutDimension+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDADE21F6EA03000CE35D /* NSLayoutDimension+.swift */; }; 192CDAE121F6F5B2000CE35D /* CALayer+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDAE021F6F5B2000CE35D /* CALayer+.swift */; }; - 192CDAE321F6FEF9000CE35D /* StatisticsDatePickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDAE221F6FEF9000CE35D /* StatisticsDatePickerViewController.swift */; }; 192CDAE521F70169000CE35D /* Storyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDAE421F70169000CE35D /* Storyboard.swift */; }; 1949B09921F5EB3200B22915 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1949B09821F5EB3200B22915 /* AppDelegate.swift */; }; 1949B09E21F5EB3200B22915 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1949B09C21F5EB3200B22915 /* Main.storyboard */; }; @@ -43,6 +42,8 @@ 1949B0A321F5EB3600B22915 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1949B0A221F5EB3600B22915 /* Assets.xcassets */; }; 1949B0A621F5EB3600B22915 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1949B0A421F5EB3600B22915 /* LaunchScreen.storyboard */; }; 1949B0AF21F5EB9F00B22915 /* .swiftlint.yml in Resources */ = {isa = PBXBuildFile; fileRef = 1949B0AE21F5EB9F00B22915 /* .swiftlint.yml */; }; + 199C197A21F73DD600ED439F /* FineDustResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 199C197921F73DD600ED439F /* FineDustResponse.swift */; }; + 199C197C21F7433C00ED439F /* Grade.swift in Sources */ = {isa = PBXBuildFile; fileRef = 199C197B21F7433C00ED439F /* Grade.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -74,7 +75,6 @@ 192CDAD221F6C87E000CE35D /* RatioGraphView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = RatioGraphView.xib; sourceTree = ""; }; 192CDADE21F6EA03000CE35D /* NSLayoutDimension+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSLayoutDimension+.swift"; sourceTree = ""; }; 192CDAE021F6F5B2000CE35D /* CALayer+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CALayer+.swift"; sourceTree = ""; }; - 192CDAE221F6FEF9000CE35D /* StatisticsDatePickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatisticsDatePickerViewController.swift; sourceTree = ""; }; 192CDAE421F70169000CE35D /* Storyboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Storyboard.swift; sourceTree = ""; }; 1949B09521F5EB3200B22915 /* FineDust.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FineDust.app; sourceTree = BUILT_PRODUCTS_DIR; }; 1949B09821F5EB3200B22915 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; @@ -84,6 +84,8 @@ 1949B0A521F5EB3600B22915 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 1949B0A721F5EB3600B22915 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 1949B0AE21F5EB9F00B22915 /* .swiftlint.yml */ = {isa = PBXFileReference; lastKnownFileType = text; path = .swiftlint.yml; sourceTree = ""; }; + 199C197921F73DD600ED439F /* FineDustResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FineDustResponse.swift; sourceTree = ""; }; + 199C197B21F7433C00ED439F /* Grade.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Grade.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -107,7 +109,9 @@ 192CDAAD21F623DC000CE35D /* Response */ = { isa = PBXGroup; children = ( + 199C197B21F7433C00ED439F /* Grade.swift */, 192CDAAE21F623ED000CE35D /* ObservatoryResponse.swift */, + 199C197921F73DD600ED439F /* FineDustResponse.swift */, ); path = Response; sourceTree = ""; @@ -146,7 +150,6 @@ isa = PBXGroup; children = ( 192CDAC821F6B61D000CE35D /* StatisticsViewController.swift */, - 192CDAE221F6FEF9000CE35D /* StatisticsDatePickerViewController.swift */, ); path = Controller; sourceTree = ""; @@ -422,11 +425,12 @@ 192CDAE521F70169000CE35D /* Storyboard.swift in Sources */, 192CDACF21F6C865000CE35D /* RatioGraphView.swift in Sources */, 192CDAA121F603C5000CE35D /* API+FineDust.swift in Sources */, + 199C197C21F7433C00ED439F /* Grade.swift in Sources */, + 199C197A21F73DD600ED439F /* FineDustResponse.swift in Sources */, 192CDA9321F5EE09000CE35D /* UIView+.swift in Sources */, 192CDAAF21F623ED000CE35D /* ObservatoryResponse.swift in Sources */, 192CDA9121F5EE04000CE35D /* UIViewController+.swift in Sources */, 1949B09921F5EB3200B22915 /* AppDelegate.swift in Sources */, - 192CDAE321F6FEF9000CE35D /* StatisticsDatePickerViewController.swift in Sources */, 192CDAE121F6F5B2000CE35D /* CALayer+.swift in Sources */, 192CDACB21F6B62E000CE35D /* FeedbackViewController.swift in Sources */, 192CDAB321F628C9000CE35D /* NSLayoutAnchor+.swift in Sources */, @@ -515,7 +519,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.1; + IPHONEOS_DEPLOYMENT_TARGET = 11; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -570,7 +574,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.1; + IPHONEOS_DEPLOYMENT_TARGET = 11; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; diff --git a/FineDust/Common/Common.storyboard b/FineDust/Common/Common.storyboard index 483d47c6..c047439e 100644 --- a/FineDust/Common/Common.storyboard +++ b/FineDust/Common/Common.storyboard @@ -29,10 +29,10 @@ - + - + diff --git a/FineDust/Extension/UIViewController+.swift b/FineDust/Extension/UIViewController+.swift index cb85ab46..07e9ff20 100644 --- a/FineDust/Extension/UIViewController+.swift +++ b/FineDust/Extension/UIViewController+.swift @@ -16,9 +16,13 @@ extension UIViewController { } @discardableResult - func deliver(_ closure: (UIViewController) -> Void) -> UIViewController { - closure(self) - return self + func deliver( + _ dictionary: [String: Any], + ofType type: T.Type + ) -> UIViewController { + guard let casted = self as? T else { fatalError("type must be UIViewController.") } + dictionary.forEach { casted.setValue($0.value, forKey: $0.key) } + return casted } func present( diff --git a/FineDust/Model/GeoInfo.swift b/FineDust/Model/GeoInfo.swift index c1518e85..6f7b610b 100644 --- a/FineDust/Model/GeoInfo.swift +++ b/FineDust/Model/GeoInfo.swift @@ -16,10 +16,12 @@ final class GeoInfo { static let shared = GeoInfo() // MARK: Property + + var x: Double = 0 - private var x: Double = 0 + var y: Double = 0 - private var y: Double = 0 + var observatory: String = "" // MARK: Method From e0f0d53ffc6a64efb75507ff497c3b3aa5f7d181 Mon Sep 17 00:00:00 2001 From: presto Date: Wed, 23 Jan 2019 14:25:20 +0900 Subject: [PATCH 07/84] =?UTF-8?q?API=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FineDust.xcodeproj/project.pbxproj | 20 +++--- FineDust/Common/Storyboard.swift | 1 + FineDust/Extension/UIViewController+.swift | 11 ++-- FineDust/Info.plist | 5 ++ FineDust/Network/API+FineDust.swift | 57 +++++++++++++++++- FineDust/Network/API.swift | 6 ++ FineDust/Response/DataTerm.swift | 15 +++++ FineDust/Response/FineDustResponse.swift | 67 +++++++++++++++++++++ FineDust/Response/Grade.swift | 19 ++++++ FineDust/Response/ObservatoryResponse.swift | 29 +++------ 10 files changed, 195 insertions(+), 35 deletions(-) create mode 100644 FineDust/Response/DataTerm.swift create mode 100644 FineDust/Response/FineDustResponse.swift create mode 100644 FineDust/Response/Grade.swift diff --git a/FineDust.xcodeproj/project.pbxproj b/FineDust.xcodeproj/project.pbxproj index b7b483f0..c55ccda9 100644 --- a/FineDust.xcodeproj/project.pbxproj +++ b/FineDust.xcodeproj/project.pbxproj @@ -42,8 +42,9 @@ 1949B0A321F5EB3600B22915 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1949B0A221F5EB3600B22915 /* Assets.xcassets */; }; 1949B0A621F5EB3600B22915 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1949B0A421F5EB3600B22915 /* LaunchScreen.storyboard */; }; 1949B0AF21F5EB9F00B22915 /* .swiftlint.yml in Resources */ = {isa = PBXBuildFile; fileRef = 1949B0AE21F5EB9F00B22915 /* .swiftlint.yml */; }; - 199C197A21F73DD600ED439F /* FineDustResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 199C197921F73DD600ED439F /* FineDustResponse.swift */; }; - 199C197C21F7433C00ED439F /* Grade.swift in Sources */ = {isa = PBXBuildFile; fileRef = 199C197B21F7433C00ED439F /* Grade.swift */; }; + 199C198E21F8275700ED439F /* Grade.swift in Sources */ = {isa = PBXBuildFile; fileRef = 199C198D21F8275700ED439F /* Grade.swift */; }; + 199C199021F8276100ED439F /* FineDustResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 199C198F21F8276100ED439F /* FineDustResponse.swift */; }; + 199C199221F82BBF00ED439F /* DataTerm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 199C199121F82BBF00ED439F /* DataTerm.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -84,8 +85,9 @@ 1949B0A521F5EB3600B22915 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 1949B0A721F5EB3600B22915 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 1949B0AE21F5EB9F00B22915 /* .swiftlint.yml */ = {isa = PBXFileReference; lastKnownFileType = text; path = .swiftlint.yml; sourceTree = ""; }; - 199C197921F73DD600ED439F /* FineDustResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FineDustResponse.swift; sourceTree = ""; }; - 199C197B21F7433C00ED439F /* Grade.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Grade.swift; sourceTree = ""; }; + 199C198D21F8275700ED439F /* Grade.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Grade.swift; sourceTree = ""; }; + 199C198F21F8276100ED439F /* FineDustResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FineDustResponse.swift; sourceTree = ""; }; + 199C199121F82BBF00ED439F /* DataTerm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataTerm.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -109,9 +111,10 @@ 192CDAAD21F623DC000CE35D /* Response */ = { isa = PBXGroup; children = ( - 199C197B21F7433C00ED439F /* Grade.swift */, + 199C198D21F8275700ED439F /* Grade.swift */, + 199C199121F82BBF00ED439F /* DataTerm.swift */, 192CDAAE21F623ED000CE35D /* ObservatoryResponse.swift */, - 199C197921F73DD600ED439F /* FineDustResponse.swift */, + 199C198F21F8276100ED439F /* FineDustResponse.swift */, ); path = Response; sourceTree = ""; @@ -416,6 +419,7 @@ buildActionMask = 2147483647; files = ( 192CDAAA21F61D0C000CE35D /* GeoConverter.swift in Sources */, + 199C199221F82BBF00ED439F /* DataTerm.swift in Sources */, 192CDAA521F6046D000CE35D /* MainViewController.swift in Sources */, 192CDADF21F6EA03000CE35D /* NSLayoutDimension+.swift in Sources */, 192CDA9521F5EE11000CE35D /* UIAlertController+.swift in Sources */, @@ -425,9 +429,9 @@ 192CDAE521F70169000CE35D /* Storyboard.swift in Sources */, 192CDACF21F6C865000CE35D /* RatioGraphView.swift in Sources */, 192CDAA121F603C5000CE35D /* API+FineDust.swift in Sources */, - 199C197C21F7433C00ED439F /* Grade.swift in Sources */, - 199C197A21F73DD600ED439F /* FineDustResponse.swift in Sources */, + 199C199021F8276100ED439F /* FineDustResponse.swift in Sources */, 192CDA9321F5EE09000CE35D /* UIView+.swift in Sources */, + 199C198E21F8275700ED439F /* Grade.swift in Sources */, 192CDAAF21F623ED000CE35D /* ObservatoryResponse.swift in Sources */, 192CDA9121F5EE04000CE35D /* UIViewController+.swift in Sources */, 1949B09921F5EB3200B22915 /* AppDelegate.swift in Sources */, diff --git a/FineDust/Common/Storyboard.swift b/FineDust/Common/Storyboard.swift index f5cd5ed4..e98b72e6 100644 --- a/FineDust/Common/Storyboard.swift +++ b/FineDust/Common/Storyboard.swift @@ -8,6 +8,7 @@ import Foundation +/// 스토리보드 상수 모음 enum Storyboard { static let main = "Main" diff --git a/FineDust/Extension/UIViewController+.swift b/FineDust/Extension/UIViewController+.swift index 07e9ff20..1cf15d14 100644 --- a/FineDust/Extension/UIViewController+.swift +++ b/FineDust/Extension/UIViewController+.swift @@ -15,14 +15,11 @@ extension UIViewController { return controller } + // 클로저 내에서 해당 타입으로 캐스팅하여 값 전달하기 @discardableResult - func deliver( - _ dictionary: [String: Any], - ofType type: T.Type - ) -> UIViewController { - guard let casted = self as? T else { fatalError("type must be UIViewController.") } - dictionary.forEach { casted.setValue($0.value, forKey: $0.key) } - return casted + func deliver(_ closure: (UIViewController) -> Void) -> UIViewController { + closure(self) + return self } func present( diff --git a/FineDust/Info.plist b/FineDust/Info.plist index 3b8aa9e8..4395b9f3 100644 --- a/FineDust/Info.plist +++ b/FineDust/Info.plist @@ -43,5 +43,10 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + diff --git a/FineDust/Network/API+FineDust.swift b/FineDust/Network/API+FineDust.swift index d1008d68..9910f978 100644 --- a/FineDust/Network/API+FineDust.swift +++ b/FineDust/Network/API+FineDust.swift @@ -8,8 +8,63 @@ import Foundation +/// 미세먼지 API 관련 API 정의 extension API { /// 측정소 정보 조회. - // func getObservatoryPost(completion: @escaping ) + func fetchObservatory( + pageNumber pageNo: Int = 1, + numberOfRows numOfRows: Int = 10, + completion: @escaping (ObservatoryResponse?, Error?) -> Void + ) { + let urlString = baseURL + .appending("/MsrstnInfoInqireSvc/getNearbyMsrstnList") + .appending("?tmX=\(GeoInfo.shared.x)") + .appending("&tmY=\(GeoInfo.shared.y)") + .appending("&numOfRows=\(numOfRows)") + .appending("&pageNo=\(pageNo)") + .appending("&serviceKey=\(serviceKey)") + .appending("&_returnType=json") + guard let url = URL(string: urlString) else { return } + Network.request(url, method: .get) { data, statusCode, error in + guard let data = data else { return } + do { + let response = try JSONDecoder().decode(ObservatoryResponse.self, from: data) + completion(response, nil) + } catch { + completion(nil, error) + } + completion(nil, error) + } + } + + /// 미세먼지 농도 조회. + func fetchFineDustConcentration( + term dataTerm: DataTerm, + pageNumber pageNo: Int = 1, + numberOfRows numOfRows: Int = 10, + completion: @escaping (FineDustResponse?, Error?) -> Void + ) { + let encodedStationName = "강남대로".percentEncoded + let urlString = baseURL + .appending("/ArpltnInforInqireSvc/getMsrstnAcctoRltmMesureDnsty") + .appending("?stationName=\(encodedStationName)") + .appending("&dataTerm=\(dataTerm.rawValue)") + .appending("&pageNo=\(pageNo)") + .appending("&numOfRows=\(numOfRows)") + .appending("&serviceKey=\(serviceKey)") + .appending("&ver=1.1") + .appending("&_returnType=json") + guard let url = URL(string: urlString) else { return } + Network.request(url, method: .get) { data, statusCode, error in + guard let data = data else { return } + do { + let response = try JSONDecoder().decode(FineDustResponse.self, from: data) + completion(response, nil) + } catch { + completion(nil, error) + } + completion(nil, error) + } + } } diff --git a/FineDust/Network/API.swift b/FineDust/Network/API.swift index f7b9af80..2548e4d0 100644 --- a/FineDust/Network/API.swift +++ b/FineDust/Network/API.swift @@ -8,8 +8,14 @@ import Foundation +/// API 정의 final class API { static let shared = API() + let baseURL = "http://openapi.airkorea.or.kr/openapi/services/rest" + + let serviceKey = """ + BfJjA4%2BuaBHhfAzyF2Ni6xoVDaf%2FhsZylifmFKdW3kyaZECH6c2Lua05fV%2F%2BYgbzPBaSl0YLZwI%2BW%2FK2xzO7sw%3D%3D + """ } diff --git a/FineDust/Response/DataTerm.swift b/FineDust/Response/DataTerm.swift new file mode 100644 index 00000000..03c342de --- /dev/null +++ b/FineDust/Response/DataTerm.swift @@ -0,0 +1,15 @@ +// +// DataTerm.swift +// FineDust +// +// Created by Presto on 23/01/2019. +// Copyright © 2019 boostcamp3rd. All rights reserved. +// + +/// 실시간 미세먼지 정보 얻어오는 기간 정의 +enum DataTerm: String { + + case daily + + case month +} diff --git a/FineDust/Response/FineDustResponse.swift b/FineDust/Response/FineDustResponse.swift new file mode 100644 index 00000000..6c6f5647 --- /dev/null +++ b/FineDust/Response/FineDustResponse.swift @@ -0,0 +1,67 @@ +// +// FineDustResponse.swift +// FineDust +// +// Created by Presto on 23/01/2019. +// Copyright © 2019 boostcamp3rd. All rights reserved. +// + +import Foundation + +struct FineDustResponse: Codable { + + struct List: Codable { + + let dataTime: String + + /// 미세먼지 농도 + let fineDustValue: Int + + /// 미세먼지 24시간 예측 이동 농도 + let fineDustValue24: Int + + /// 미세먼지 24시간 등급 + let fineDustGrade: Int + + /// 미세먼지 1시간 등급 + let fineDustGrade1h: Int + + /// 초미세먼지 농도 + let ultrafineDustValue: Int + + /// 초미세먼지 24시간 예측 이동 농도 + let ultrafineDustValue24: Int + + /// 초미세먼지 24시간 등급 + let ultrafineDustGrade: Int + + /// 초미세먼지 1시간 등급 + let ultrafineDustGrade1h: Int + + enum CodingKeys: String, CodingKey { + + case dataTime + + case fineDustValue = "pm10Value" + + case fineDustValue24 = "pm10Value24" + + case fineDustGrade = "pm10Grade" + + case fineDustGrade1h = "pm10Grade1h" + + case ultrafineDustValue = "pm25Value" + + case ultrafineDustValue24 = "pm25Value24" + + case ultrafineDustGrade = "pm25Grade" + + case ultrafineDustGrade1h = "pm25Grade1h" + } + } + + let list: [List] + + /// 응답 개수 + let totalCount: Int +} diff --git a/FineDust/Response/Grade.swift b/FineDust/Response/Grade.swift new file mode 100644 index 00000000..37c44126 --- /dev/null +++ b/FineDust/Response/Grade.swift @@ -0,0 +1,19 @@ +// +// Grade.swift +// FineDust +// +// Created by Presto on 23/01/2019. +// Copyright © 2019 boostcamp3rd. All rights reserved. +// + +/// 미세먼지 API 응답에 의한 대기 등급 정의 +enum Grade: Int { + + case good = 1 + + case normal + + case bad + + case veryBad +} diff --git a/FineDust/Response/ObservatoryResponse.swift b/FineDust/Response/ObservatoryResponse.swift index 2e73b1a8..9e06c7a2 100644 --- a/FineDust/Response/ObservatoryResponse.swift +++ b/FineDust/Response/ObservatoryResponse.swift @@ -11,38 +11,29 @@ import Foundation /// 측정소 정보 조회 응답 객체. struct ObservatoryResponse: Codable { - struct Item: Codable { - - let stationName: String + struct List: Codable { + /// 관측소 주소 let address: String + /// 관측소 이름 + let stationName: String + + /// 현재 위치에서 관측소까지의 거리. km let distance: Double enum CodingKeys: String, CodingKey { - case stationName - case address = "addr" case distance = "tm" + + case stationName } } - let numberOfRows: Int - - let pageNumber: Int + let list: [List] + /// 응답 개수 let totalCount: Int - - let items: [Item] - - enum CodingKeys: String, CodingKey { - - case numberOfRows = "numOfRows" - - case pageNumber = "pageNo" - - case totalCount, items - } } From 70dc03aae8a3c69948b3c185019d33ad3a371542 Mon Sep 17 00:00:00 2001 From: Jae-eun Date: Wed, 23 Jan 2019 15:05:41 +0900 Subject: [PATCH 08/84] =?UTF-8?q?3=E1=84=87=E1=85=A5=E1=86=AB=E1=84=8D?= =?UTF-8?q?=E1=85=A2=20=E1=84=90=E1=85=A2=E1=86=B8=20=E1=84=92=E1=85=AA?= =?UTF-8?q?=E1=84=86=E1=85=A7=E1=86=AB=20=E1=84=8F=E1=85=A5=E1=86=AF?= =?UTF-8?q?=E1=84=85=E1=85=A6=E1=86=A8=E1=84=89=E1=85=A7=E1=86=AB=20?= =?UTF-8?q?=E1=84=87=E1=85=B2=20=E1=84=86=E1=85=A1=E1=86=AB=E1=84=83?= =?UTF-8?q?=E1=85=B3=E1=86=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FeedbackCollectionViewCell.swift | 14 +++ .../FeedbackCollectionViewController.swift | 58 +++++++++++++ .../Controller/FeedbackViewController.swift | 17 ---- FineDust/Feedback/Feedback.storyboard | 82 +++++++++++++++++- .../info1.imageset/Contents.json | 21 +++++ .../Assets.xcassets/info1.imageset/info1.jpg | Bin 0 -> 24240 bytes 6 files changed, 171 insertions(+), 21 deletions(-) create mode 100644 FineDust/Feedback/Controller/FeedbackCollectionViewCell.swift create mode 100644 FineDust/Feedback/Controller/FeedbackCollectionViewController.swift delete mode 100644 FineDust/Feedback/Controller/FeedbackViewController.swift create mode 100644 FineDust/Supporting Files/Assets.xcassets/info1.imageset/Contents.json create mode 100644 FineDust/Supporting Files/Assets.xcassets/info1.imageset/info1.jpg diff --git a/FineDust/Feedback/Controller/FeedbackCollectionViewCell.swift b/FineDust/Feedback/Controller/FeedbackCollectionViewCell.swift new file mode 100644 index 00000000..8dd66e39 --- /dev/null +++ b/FineDust/Feedback/Controller/FeedbackCollectionViewCell.swift @@ -0,0 +1,14 @@ +// +// FeedbackCollectionViewCell.swift +// FineDust +// +// Created by 이재은 on 23/01/2019. +// Copyright © 2019 boostcamp3rd. All rights reserved. +// + +import UIKit + +class FeedbackCollectionViewCell: UICollectionViewCell { + + @IBOutlet weak var feedbackImageView: UIImageView! +} diff --git a/FineDust/Feedback/Controller/FeedbackCollectionViewController.swift b/FineDust/Feedback/Controller/FeedbackCollectionViewController.swift new file mode 100644 index 00000000..9a2a752a --- /dev/null +++ b/FineDust/Feedback/Controller/FeedbackCollectionViewController.swift @@ -0,0 +1,58 @@ +// +// FeedbackCollectionViewController.swift +// FineDust +// +// Created by 이재은 on 23/01/2019. +// Copyright © 2019 boostcamp3rd. All rights reserved. +// + +import UIKit + +private let reuseIdentifier = "feedbackCell" + +final class FeedbackCollectionViewController: UIViewController { + + @IBOutlet weak var feedbackCollectionView: UICollectionView! + + override func viewDidLoad() { + super.viewDidLoad() +// navigationItem.title = "먼지 정보" + feedbackCollectionView.reloadData() + } + + private var count = 8 + private let cornerRadius: CGFloat = 7 + +} + // MARK: UICollectionViewDataSource + +extension FeedbackCollectionViewController: UICollectionViewDataSource { + func numberOfSections(in collectionView: UICollectionView) -> Int { + return 1 + } + + func collectionView( + _ collectionView: UICollectionView, + numberOfItemsInSection section: Int + ) -> Int { + return count + } + + func collectionView( + _ collectionView: UICollectionView, + cellForItemAt indexPath: IndexPath + ) -> UICollectionViewCell { + + guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) + as? FeedbackCollectionViewCell else { + return UICollectionViewCell() + } + cell.feedbackImageView.layer.cornerRadius = cornerRadius + cell.feedbackImageView.layer.masksToBounds = true + cell.feedbackImageView.image = UIImage(named: "info1") + + + return cell + } + } + // MARK: UICollectionViewDelegate diff --git a/FineDust/Feedback/Controller/FeedbackViewController.swift b/FineDust/Feedback/Controller/FeedbackViewController.swift deleted file mode 100644 index 0a36b0bd..00000000 --- a/FineDust/Feedback/Controller/FeedbackViewController.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// FeedbackViewController.swift -// FineDust -// -// Created by Presto on 22/01/2019. -// Copyright © 2019 boostcamp3rd. All rights reserved. -// - -import UIKit - -class FeedbackViewController: UIViewController { - - override func viewDidLoad() { - super.viewDidLoad() - tabBarItem.title = "피드백" - } -} diff --git a/FineDust/Feedback/Feedback.storyboard b/FineDust/Feedback/Feedback.storyboard index e36ef656..bb1dce7b 100644 --- a/FineDust/Feedback/Feedback.storyboard +++ b/FineDust/Feedback/Feedback.storyboard @@ -10,27 +10,98 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + - + + + @@ -45,4 +116,7 @@ + + + diff --git a/FineDust/Supporting Files/Assets.xcassets/info1.imageset/Contents.json b/FineDust/Supporting Files/Assets.xcassets/info1.imageset/Contents.json new file mode 100644 index 00000000..8b28b9fa --- /dev/null +++ b/FineDust/Supporting Files/Assets.xcassets/info1.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "info1.jpg", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/FineDust/Supporting Files/Assets.xcassets/info1.imageset/info1.jpg b/FineDust/Supporting Files/Assets.xcassets/info1.imageset/info1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..df7e4590e8ec45c1c6de5cd6a1bd7862399244ee GIT binary patch literal 24240 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 literal 0 HcmV?d00001 From 7d951b6c7b66763223d467d35a9546c4204d6e92 Mon Sep 17 00:00:00 2001 From: presto Date: Wed, 23 Jan 2019 16:21:51 +0900 Subject: [PATCH 09/84] =?UTF-8?q?=ED=86=B5=EA=B3=84=20=EB=A7=89=EB=8C=80?= =?UTF-8?q?=EA=B7=B8=EB=9E=98=ED=94=84=20=EC=95=A0=EB=8B=88=EB=A9=94?= =?UTF-8?q?=EC=9D=B4=EC=85=98=20=EA=B4=80=EB=A0=A8=20=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FineDust/Extension/NSLayoutConstraint+.swift | 2 +- .../Controller/StatisticsViewController.swift | 5 +- .../View/Value Graph/ValueGraphView.swift | 52 ++++-- .../View/Value Graph/ValueGraphView.xib | 165 ++++++++++-------- 4 files changed, 137 insertions(+), 87 deletions(-) diff --git a/FineDust/Extension/NSLayoutConstraint+.swift b/FineDust/Extension/NSLayoutConstraint+.swift index aa613db0..c420d3b6 100644 --- a/FineDust/Extension/NSLayoutConstraint+.swift +++ b/FineDust/Extension/NSLayoutConstraint+.swift @@ -9,7 +9,7 @@ import UIKit extension NSLayoutConstraint { - func changeMultiplier(to value: CGFloat) -> NSLayoutConstraint { + func changedMultiplier(to value: CGFloat) -> NSLayoutConstraint { let constraint = NSLayoutConstraint( item: firstItem as Any, attribute: firstAttribute, diff --git a/FineDust/Statistics/Controller/StatisticsViewController.swift b/FineDust/Statistics/Controller/StatisticsViewController.swift index b1b8140e..41c80605 100644 --- a/FineDust/Statistics/Controller/StatisticsViewController.swift +++ b/FineDust/Statistics/Controller/StatisticsViewController.swift @@ -66,9 +66,8 @@ final class StatisticsViewController: UIViewController { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) setConstraintsToSubviews() - API.shared.fetchObservatory { response, error in - print(response, error) - } + valueGraphView.initializeHeights() + valueGraphView.animateHeights() } } diff --git a/FineDust/Statistics/View/Value Graph/ValueGraphView.swift b/FineDust/Statistics/View/Value Graph/ValueGraphView.swift index 6db23ed6..8c8c7c1a 100644 --- a/FineDust/Statistics/View/Value Graph/ValueGraphView.swift +++ b/FineDust/Statistics/View/Value Graph/ValueGraphView.swift @@ -22,6 +22,20 @@ final class ValueGraphView: UIView { static let borderWidth: CGFloat = 1.0 } + /// 애니메이션 관련 상수 모음 + enum Animation { + + static let duration: TimeInterval = 0.5 + + static let delay: TimeInterval = 0.0 + + static let damping: CGFloat = 0.4 + + static let springVelocity: CGFloat = 0.5 + + static let option: UIView.AnimationOptions = .curveEaseInOut + } + // MARK: delegate weak var delegate: ValueGraphViewDelegate? @@ -29,7 +43,7 @@ final class ValueGraphView: UIView { // MARK: Property /// 비율 모음 - var ratios: [CGFloat] = [] + var ratios: [CGFloat] = [0.8, 0.25, 0.86, 0.18, 0.45, 0.36, 0.74] // MARK: IBOutlet @@ -54,13 +68,7 @@ final class ValueGraphView: UIView { } /// 그래프 높이 제약 모음 - @IBOutlet var graphViewHeightConstraints: [NSLayoutConstraint]! { - didSet { - for (index, constraint) in graphViewHeightConstraints.enumerated() { - graphViewHeightConstraints[index] = constraint.changeMultiplier(to: 0.5) - } - } - } + @IBOutlet var graphViewHeightConstraints: [NSLayoutConstraint]! // MARK: Life Cycle @@ -82,7 +90,31 @@ final class ValueGraphView: UIView { } /// 그래프 뷰 높이 제약에 애니메이션 효과 설정 - private func animateHeights() { - + func animateHeights() { + for (index, ratio) in ratios.enumerated() { + let plusTime = DispatchTime.now()// + DispatchTimeInterval.milliseconds(index * 100) + var heightConstraint = graphViewHeightConstraints[index] + DispatchQueue.main.asyncAfter(deadline: plusTime) { [weak self] in + UIView.animate( + withDuration: Animation.duration, + delay: Animation.delay, + usingSpringWithDamping: Animation.damping, + initialSpringVelocity: Animation.springVelocity, + options: .curveEaseInOut, + animations: { + heightConstraint = heightConstraint.changedMultiplier(to: ratio) + self?.layoutIfNeeded() + }, + completion: nil + ) + } + } + } + + func initializeHeights() { + for (index, constraint) in graphViewHeightConstraints.enumerated() { + graphViewHeightConstraints[index] = constraint.changedMultiplier(to: 1.0) + } + layoutIfNeeded() } } diff --git a/FineDust/Statistics/View/Value Graph/ValueGraphView.xib b/FineDust/Statistics/View/Value Graph/ValueGraphView.xib index 48112eb7..d51312f6 100644 --- a/FineDust/Statistics/View/Value Graph/ValueGraphView.xib +++ b/FineDust/Statistics/View/Value Graph/ValueGraphView.xib @@ -62,97 +62,117 @@ + + + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + - - - + + - - - - - + - - + + - - - - - + + + + + + + + + + - - - - - - + + + @@ -166,21 +186,20 @@ + - - - - - - - - - - - + + + + + + + + + From 2a006a1dbc7c6856af06eca3a64f1a53ba5f0c2a Mon Sep 17 00:00:00 2001 From: Jae-eun Date: Wed, 23 Jan 2019 17:30:29 +0900 Subject: [PATCH 10/84] =?UTF-8?q?applyShadow,=20setRounded=20extension=20?= =?UTF-8?q?=E1=84=8E=E1=85=AE=E1=84=80=E1=85=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FineDust/Extension/CALayer+.swift | 21 +++++++++++++++++++++ FineDust/Extension/UIImageView+.swift | 16 ++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 FineDust/Extension/UIImageView+.swift diff --git a/FineDust/Extension/CALayer+.swift b/FineDust/Extension/CALayer+.swift index b5e97cbb..983d87d9 100644 --- a/FineDust/Extension/CALayer+.swift +++ b/FineDust/Extension/CALayer+.swift @@ -19,4 +19,25 @@ extension CALayer { self.borderWidth = borderWidth self.cornerRadius = cornerRadius } + + func applySketchShadow( + color: UIColor = .black, + alpha: Float = 0.5, + x: CGFloat = 0, + y: CGFloat = 2, + blur: CGFloat = 4, + spread: CGFloat = 0 + ) { + shadowColor = color.cgColor + shadowOpacity = alpha + shadowOffset = CGSize(width: x, height: y) + shadowRadius = blur / 2.0 + if spread == 0 { + shadowPath = nil + } else { + let dx = -spread + let rect = bounds.insetBy(dx: dx, dy: dx) + shadowPath = UIBezierPath(rect: rect).cgPath + } + } } diff --git a/FineDust/Extension/UIImageView+.swift b/FineDust/Extension/UIImageView+.swift new file mode 100644 index 00000000..394a5a18 --- /dev/null +++ b/FineDust/Extension/UIImageView+.swift @@ -0,0 +1,16 @@ +// +// UIImageView+.swift +// FineDust +// +// Created by 이재은 on 23/01/2019. +// Copyright © 2019 boostcamp3rd. All rights reserved. +// + +import UIKit + +extension UIImageView { + func setRounded() { + self.layer.cornerRadius = self.frame.height / 2 + self.layer.masksToBounds = true + } +} From e1e6a9ffaf116376f4c96dfba133ac94f300cc6c Mon Sep 17 00:00:00 2001 From: Jae-eun Date: Wed, 23 Jan 2019 17:34:53 +0900 Subject: [PATCH 11/84] =?UTF-8?q?applyGradient=20extension=20=E1=84=8E?= =?UTF-8?q?=E1=85=AE=E1=84=80=E1=85=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FineDust/Extension/CALayer+.swift | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/FineDust/Extension/CALayer+.swift b/FineDust/Extension/CALayer+.swift index 983d87d9..480e2ec2 100644 --- a/FineDust/Extension/CALayer+.swift +++ b/FineDust/Extension/CALayer+.swift @@ -40,4 +40,19 @@ extension CALayer { shadowPath = UIBezierPath(rect: rect).cgPath } } + + func applyGradient( + colors: [Any], + locations: [NSNumber], + startPoint: CGPoint = .init(x: 0.5, y: 0), + endPoint: CGPoint = .init(x: 0.5, y: 1) + ) { + let gradient = CAGradientLayer() + gradient.frame = bounds + gradient.startPoint = startPoint + gradient.endPoint = endPoint + gradient.colors = colors + gradient.locations = locations + mask = gradient + } } From 2c78c9c3909e447131af7183375553c29c29b2f9 Mon Sep 17 00:00:00 2001 From: zunzunzun Date: Wed, 23 Jan 2019 17:35:36 +0900 Subject: [PATCH 12/84] =?UTF-8?q?1=EB=B2=88=EC=A7=B8=20=ED=83=AD=20?= =?UTF-8?q?=ED=99=94=EB=A9=B4=20=ED=94=84=EB=A1=9C=ED=86=A0=20=ED=83=80?= =?UTF-8?q?=EC=9E=85.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FineDust.xcodeproj/project.pbxproj | 8 - FineDust/Main/Base.lproj/Main.storyboard | 388 +++++++++++++++++- .../Controller/StatisticsViewController.swift | 3 - 3 files changed, 381 insertions(+), 18 deletions(-) diff --git a/FineDust.xcodeproj/project.pbxproj b/FineDust.xcodeproj/project.pbxproj index b7b483f0..8f4b3384 100644 --- a/FineDust.xcodeproj/project.pbxproj +++ b/FineDust.xcodeproj/project.pbxproj @@ -42,8 +42,6 @@ 1949B0A321F5EB3600B22915 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1949B0A221F5EB3600B22915 /* Assets.xcassets */; }; 1949B0A621F5EB3600B22915 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1949B0A421F5EB3600B22915 /* LaunchScreen.storyboard */; }; 1949B0AF21F5EB9F00B22915 /* .swiftlint.yml in Resources */ = {isa = PBXBuildFile; fileRef = 1949B0AE21F5EB9F00B22915 /* .swiftlint.yml */; }; - 199C197A21F73DD600ED439F /* FineDustResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 199C197921F73DD600ED439F /* FineDustResponse.swift */; }; - 199C197C21F7433C00ED439F /* Grade.swift in Sources */ = {isa = PBXBuildFile; fileRef = 199C197B21F7433C00ED439F /* Grade.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -84,8 +82,6 @@ 1949B0A521F5EB3600B22915 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 1949B0A721F5EB3600B22915 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 1949B0AE21F5EB9F00B22915 /* .swiftlint.yml */ = {isa = PBXFileReference; lastKnownFileType = text; path = .swiftlint.yml; sourceTree = ""; }; - 199C197921F73DD600ED439F /* FineDustResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FineDustResponse.swift; sourceTree = ""; }; - 199C197B21F7433C00ED439F /* Grade.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Grade.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -109,9 +105,7 @@ 192CDAAD21F623DC000CE35D /* Response */ = { isa = PBXGroup; children = ( - 199C197B21F7433C00ED439F /* Grade.swift */, 192CDAAE21F623ED000CE35D /* ObservatoryResponse.swift */, - 199C197921F73DD600ED439F /* FineDustResponse.swift */, ); path = Response; sourceTree = ""; @@ -425,8 +419,6 @@ 192CDAE521F70169000CE35D /* Storyboard.swift in Sources */, 192CDACF21F6C865000CE35D /* RatioGraphView.swift in Sources */, 192CDAA121F603C5000CE35D /* API+FineDust.swift in Sources */, - 199C197C21F7433C00ED439F /* Grade.swift in Sources */, - 199C197A21F73DD600ED439F /* FineDustResponse.swift in Sources */, 192CDA9321F5EE09000CE35D /* UIView+.swift in Sources */, 192CDAAF21F623ED000CE35D /* ObservatoryResponse.swift in Sources */, 192CDA9121F5EE04000CE35D /* UIViewController+.swift in Sources */, diff --git a/FineDust/Main/Base.lproj/Main.storyboard b/FineDust/Main/Base.lproj/Main.storyboard index fef8deae..03d680c5 100644 --- a/FineDust/Main/Base.lproj/Main.storyboard +++ b/FineDust/Main/Base.lproj/Main.storyboard @@ -1,6 +1,6 @@ - + @@ -10,32 +10,406 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + + + + + diff --git a/FineDust/Statistics/Controller/StatisticsViewController.swift b/FineDust/Statistics/Controller/StatisticsViewController.swift index b1b8140e..2cdf9f16 100644 --- a/FineDust/Statistics/Controller/StatisticsViewController.swift +++ b/FineDust/Statistics/Controller/StatisticsViewController.swift @@ -66,9 +66,6 @@ final class StatisticsViewController: UIViewController { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) setConstraintsToSubviews() - API.shared.fetchObservatory { response, error in - print(response, error) - } } } From c71f591358d9e0dd749904a88d2a1b9d1e24c155 Mon Sep 17 00:00:00 2001 From: Jae-eun Date: Wed, 23 Jan 2019 17:36:17 +0900 Subject: [PATCH 13/84] =?UTF-8?q?FeedbackListVC,=20CollectionView,=20Table?= =?UTF-8?q?View=20=E1=84=86=E1=85=A1=E1=86=AB=E1=84=83=E1=85=B3=E1=86=B1.?= =?UTF-8?q?=203=E1=84=87=E1=85=A5=E1=86=AB=E1=84=8D=E1=85=A2=20=E1=84=90?= =?UTF-8?q?=E1=85=A2=E1=86=B8=20=E1=84=92=E1=85=AA=E1=84=86=E1=85=A7?= =?UTF-8?q?=E1=86=AB=20=E1=84=87=E1=85=B2=20=E1=84=86=E1=85=A1=E1=86=AB?= =?UTF-8?q?=E1=84=83=E1=85=B3=E1=84=82=E1=85=B3=E1=86=AB=20=E1=84=8C?= =?UTF-8?q?=E1=85=AE=E1=86=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FeedbackCollectionViewController.swift | 58 --------- .../FeedbackListViewController.swift | 105 ++++++++++++++++ FineDust/Feedback/Feedback.storyboard | 117 +++++++++++++++--- .../FeedbackCollectionViewCell.swift | 1 + .../View/FeedbackListTableViewCell.swift | 18 +++ .../Controller/StatisticsViewController.swift | 4 +- 6 files changed, 228 insertions(+), 75 deletions(-) delete mode 100644 FineDust/Feedback/Controller/FeedbackCollectionViewController.swift create mode 100644 FineDust/Feedback/Controller/FeedbackListViewController.swift rename FineDust/Feedback/{Controller => View}/FeedbackCollectionViewCell.swift (85%) create mode 100644 FineDust/Feedback/View/FeedbackListTableViewCell.swift diff --git a/FineDust/Feedback/Controller/FeedbackCollectionViewController.swift b/FineDust/Feedback/Controller/FeedbackCollectionViewController.swift deleted file mode 100644 index 9a2a752a..00000000 --- a/FineDust/Feedback/Controller/FeedbackCollectionViewController.swift +++ /dev/null @@ -1,58 +0,0 @@ -// -// FeedbackCollectionViewController.swift -// FineDust -// -// Created by 이재은 on 23/01/2019. -// Copyright © 2019 boostcamp3rd. All rights reserved. -// - -import UIKit - -private let reuseIdentifier = "feedbackCell" - -final class FeedbackCollectionViewController: UIViewController { - - @IBOutlet weak var feedbackCollectionView: UICollectionView! - - override func viewDidLoad() { - super.viewDidLoad() -// navigationItem.title = "먼지 정보" - feedbackCollectionView.reloadData() - } - - private var count = 8 - private let cornerRadius: CGFloat = 7 - -} - // MARK: UICollectionViewDataSource - -extension FeedbackCollectionViewController: UICollectionViewDataSource { - func numberOfSections(in collectionView: UICollectionView) -> Int { - return 1 - } - - func collectionView( - _ collectionView: UICollectionView, - numberOfItemsInSection section: Int - ) -> Int { - return count - } - - func collectionView( - _ collectionView: UICollectionView, - cellForItemAt indexPath: IndexPath - ) -> UICollectionViewCell { - - guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) - as? FeedbackCollectionViewCell else { - return UICollectionViewCell() - } - cell.feedbackImageView.layer.cornerRadius = cornerRadius - cell.feedbackImageView.layer.masksToBounds = true - cell.feedbackImageView.image = UIImage(named: "info1") - - - return cell - } - } - // MARK: UICollectionViewDelegate diff --git a/FineDust/Feedback/Controller/FeedbackListViewController.swift b/FineDust/Feedback/Controller/FeedbackListViewController.swift new file mode 100644 index 00000000..7fee2027 --- /dev/null +++ b/FineDust/Feedback/Controller/FeedbackListViewController.swift @@ -0,0 +1,105 @@ +// +// FeedbackListViewController.swift +// FineDust +// +// Created by 이재은 on 23/01/2019. +// Copyright © 2019 boostcamp3rd. All rights reserved. +// + +import UIKit + +private let reuseIdentifier = ["feedbackCell", "feedbackListCell"] + +final class FeedbackListViewController: UIViewController { + + @IBOutlet weak var feedbackCollectionView: UICollectionView! + @IBOutlet weak var feedbackListTabelView: UITableView! + + override func viewDidLoad() { + super.viewDidLoad() + navigationItem.title = "먼지 정보" + + feedbackCollectionView.reloadData() + feedbackListTabelView.reloadData() + + } + + private var count = 10 + private let cornerRadius: CGFloat = 7 + +} + // MARK: UICollectionViewDataSource + +extension FeedbackListViewController: UICollectionViewDataSource { + func numberOfSections(in collectionView: UICollectionView) -> Int { + return 1 + } + + func collectionView( + _ collectionView: UICollectionView, + numberOfItemsInSection section: Int + ) -> Int { + return 3 + } + + func collectionView( + _ collectionView: UICollectionView, + cellForItemAt indexPath: IndexPath + ) -> UICollectionViewCell { + + guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier[0], for: indexPath) + as? FeedbackCollectionViewCell else { + return UICollectionViewCell() + } + cell.feedbackImageView.layer.cornerRadius = cornerRadius + cell.feedbackImageView.layer.masksToBounds = true + cell.feedbackImageView.image = UIImage(named: "info1") + + cell.feedbackTitleLabel.text = "미세먼지 정화 식물" + cell.feedbackTitleLabel.layer.cornerRadius = cornerRadius + cell.feedbackTitleLabel.layer.masksToBounds = true + + return cell + } + } + // MARK: UICollectionViewDelegate + + // MARK: UITabelViewDataSource + +extension FeedbackListViewController: UITableViewDataSource { + func numberOfSections(in tableView: UITableView) -> Int { + return 1 + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + guard let cell = tableView.dequeueReusableCell( + withIdentifier: reuseIdentifier[1], + for: indexPath + ) as? FeedbackListTableViewCell else { + return UITableViewCell() + } + cell.feedbackImageView.image = UIImage(named: "info1") + cell.feedbackTitleLabel.text = "미세먼지 정화 식물" + cell.feedbackSourceLabel.text = "KTV 국민 방송" + + cell.feedbackImageView.setRounded() + + cell.feedbackListShadowView.layer.applySketchShadow( + color: UIColor.gray, alpha: 0.2, x: 0, y: 0, blur: 5, spread: 3) + cell.feedbackListShadowView.layer.cornerRadius = 5 + + return cell + } +} + +// MARK: UITableViewDelegate + +extension FeedbackListViewController: UITableViewDelegate { + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + return 150 + } +} diff --git a/FineDust/Feedback/Feedback.storyboard b/FineDust/Feedback/Feedback.storyboard index bb1dce7b..003a0812 100644 --- a/FineDust/Feedback/Feedback.storyboard +++ b/FineDust/Feedback/Feedback.storyboard @@ -10,39 +10,53 @@ - + - + - - + + - - + + - + - + - + - - - + + + + + + + + + + @@ -52,19 +66,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + - + + + + diff --git a/FineDust/Feedback/Controller/FeedbackCollectionViewCell.swift b/FineDust/Feedback/View/FeedbackCollectionViewCell.swift similarity index 85% rename from FineDust/Feedback/Controller/FeedbackCollectionViewCell.swift rename to FineDust/Feedback/View/FeedbackCollectionViewCell.swift index 8dd66e39..be579c2a 100644 --- a/FineDust/Feedback/Controller/FeedbackCollectionViewCell.swift +++ b/FineDust/Feedback/View/FeedbackCollectionViewCell.swift @@ -11,4 +11,5 @@ import UIKit class FeedbackCollectionViewCell: UICollectionViewCell { @IBOutlet weak var feedbackImageView: UIImageView! + @IBOutlet weak var feedbackTitleLabel: UILabel! } diff --git a/FineDust/Feedback/View/FeedbackListTableViewCell.swift b/FineDust/Feedback/View/FeedbackListTableViewCell.swift new file mode 100644 index 00000000..5bc65f47 --- /dev/null +++ b/FineDust/Feedback/View/FeedbackListTableViewCell.swift @@ -0,0 +1,18 @@ +// +// FeedbackListTableViewCell.swift +// FineDust +// +// Created by 이재은 on 23/01/2019. +// Copyright © 2019 boostcamp3rd. All rights reserved. +// + +import UIKit + +class FeedbackListTableViewCell: UITableViewCell { + + @IBOutlet weak var feedbackImageView: UIImageView! + @IBOutlet weak var feedbackTitleLabel: UILabel! + @IBOutlet weak var feedbackSourceLabel: UILabel! + @IBOutlet weak var feedbackListShadowView: UIView! + +} diff --git a/FineDust/Statistics/Controller/StatisticsViewController.swift b/FineDust/Statistics/Controller/StatisticsViewController.swift index b1b8140e..76dd60f4 100644 --- a/FineDust/Statistics/Controller/StatisticsViewController.swift +++ b/FineDust/Statistics/Controller/StatisticsViewController.swift @@ -66,9 +66,7 @@ final class StatisticsViewController: UIViewController { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) setConstraintsToSubviews() - API.shared.fetchObservatory { response, error in - print(response, error) - } + } } From 775de94f5f0363f2f1bc9559efe3a83a6546d730 Mon Sep 17 00:00:00 2001 From: Jae-eun Date: Wed, 23 Jan 2019 17:45:50 +0900 Subject: [PATCH 14/84] =?UTF-8?q?UIImageView=20Extension=E1=84=8B=E1=85=B4?= =?UTF-8?q?=20self=E1=84=85=E1=85=B3=E1=86=AF=20=E1=84=8C=E1=85=A6?= =?UTF-8?q?=E1=84=80=E1=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FineDust/Extension/UIImageView+.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FineDust/Extension/UIImageView+.swift b/FineDust/Extension/UIImageView+.swift index 394a5a18..dc315235 100644 --- a/FineDust/Extension/UIImageView+.swift +++ b/FineDust/Extension/UIImageView+.swift @@ -10,7 +10,7 @@ import UIKit extension UIImageView { func setRounded() { - self.layer.cornerRadius = self.frame.height / 2 - self.layer.masksToBounds = true + layer.cornerRadius = frame.height / 2 + layer.masksToBounds = true } } From d181534377fd441dacaf42bb45a5fae0b7e5750c Mon Sep 17 00:00:00 2001 From: Jae-eun Date: Thu, 24 Jan 2019 00:00:13 +0900 Subject: [PATCH 15/84] =?UTF-8?q?=E1=84=8B=E1=85=A2=E1=86=B8=E1=84=8B?= =?UTF-8?q?=E1=85=A1=E1=84=8B=E1=85=B5=E1=84=8F=E1=85=A9=E1=86=AB=20?= =?UTF-8?q?=E1=84=8E=E1=85=AE=E1=84=80=E1=85=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AppIcon.appiconset/Contents.json | 85 +++++++++++++++--- .../AppIcon.appiconset/icon-20@3x.png | Bin 0 -> 4308 bytes .../AppIcon.appiconset/icon-40-ipad@2x.png | Bin 0 -> 5548 bytes .../AppIcon.appiconset/icon-40.png | Bin 0 -> 3175 bytes .../AppIcon.appiconset/icon-40@2x.png | Bin 0 -> 5548 bytes .../AppIcon.appiconset/icon-40@3x.png | Bin 0 -> 7938 bytes .../AppIcon.appiconset/icon-60@2x.png | Bin 0 -> 7938 bytes .../AppIcon.appiconset/icon-60@3x.png | Bin 0 -> 11629 bytes .../AppIcon.appiconset/icon-72.png | Bin 0 -> 4993 bytes .../AppIcon.appiconset/icon-72@2x.png | Bin 0 -> 9281 bytes .../AppIcon.appiconset/icon-76.png | Bin 0 -> 5335 bytes .../AppIcon.appiconset/icon-76@2x.png | Bin 0 -> 9924 bytes .../AppIcon.appiconset/icon-83.5@2x.png | Bin 0 -> 10865 bytes .../AppIcon.appiconset/icon-small-50.png | Bin 0 -> 3744 bytes .../AppIcon.appiconset/icon-small-50@2x.png | Bin 0 -> 6703 bytes .../AppIcon.appiconset/icon-small-ipad.png | Bin 0 -> 2502 bytes .../AppIcon.appiconset/icon-small-ipad@2x.png | Bin 0 -> 4209 bytes .../AppIcon.appiconset/icon-small.png | Bin 0 -> 2502 bytes .../AppIcon.appiconset/icon-small@2x.png | Bin 0 -> 4209 bytes .../AppIcon.appiconset/icon-small@3x.png | Bin 0 -> 5963 bytes .../AppIcon.appiconset/icon.png | Bin 0 -> 4078 bytes .../AppIcon.appiconset/icon@2x.png | Bin 0 -> 7466 bytes .../notificationicon-ipad@2x.png | Bin 0 -> 3175 bytes .../notificationicon@2x.png | Bin 0 -> 3175 bytes .../notificationicon~ipad.png | Bin 0 -> 1979 bytes 25 files changed, 72 insertions(+), 13 deletions(-) create mode 100644 FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-20@3x.png create mode 100644 FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-40-ipad@2x.png create mode 100644 FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-40.png create mode 100644 FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png create mode 100644 FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png create mode 100644 FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png create mode 100644 FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png create mode 100644 FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-72.png create mode 100644 FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-72@2x.png create mode 100644 FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-76.png create mode 100644 FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png create mode 100644 FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png create mode 100644 FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-small-50.png create mode 100644 FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-small-50@2x.png create mode 100644 FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-small-ipad.png create mode 100644 FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-small-ipad@2x.png create mode 100644 FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-small.png create mode 100644 FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-small@2x.png create mode 100644 FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-small@3x.png create mode 100644 FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon.png create mode 100644 FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon@2x.png create mode 100644 FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/notificationicon-ipad@2x.png create mode 100644 FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/notificationicon@2x.png create mode 100644 FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/notificationicon~ipad.png diff --git a/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json b/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json index d8db8d65..7928053b 100644 --- a/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,88 +1,147 @@ { "images" : [ { - "idiom" : "iphone", "size" : "20x20", + "idiom" : "iphone", + "filename" : "notificationicon@2x.png", "scale" : "2x" }, { - "idiom" : "iphone", "size" : "20x20", + "idiom" : "iphone", + "filename" : "icon-20@3x.png", "scale" : "3x" }, { + "size" : "29x29", "idiom" : "iphone", + "filename" : "icon-small.png", + "scale" : "1x" + }, + { "size" : "29x29", + "idiom" : "iphone", + "filename" : "icon-small@2x.png", "scale" : "2x" }, { - "idiom" : "iphone", "size" : "29x29", + "idiom" : "iphone", + "filename" : "icon-small@3x.png", "scale" : "3x" }, { - "idiom" : "iphone", "size" : "40x40", + "idiom" : "iphone", + "filename" : "icon-40@2x.png", "scale" : "2x" }, { - "idiom" : "iphone", "size" : "40x40", + "idiom" : "iphone", + "filename" : "icon-40@3x.png", "scale" : "3x" }, { + "size" : "57x57", "idiom" : "iphone", - "size" : "60x60", + "filename" : "icon.png", + "scale" : "1x" + }, + { + "size" : "57x57", + "idiom" : "iphone", + "filename" : "icon@2x.png", "scale" : "2x" }, { + "size" : "60x60", "idiom" : "iphone", + "filename" : "icon-60@2x.png", + "scale" : "2x" + }, + { "size" : "60x60", + "idiom" : "iphone", + "filename" : "icon-60@3x.png", "scale" : "3x" }, { - "idiom" : "ipad", "size" : "20x20", + "idiom" : "ipad", + "filename" : "notificationicon~ipad.png", "scale" : "1x" }, { - "idiom" : "ipad", "size" : "20x20", + "idiom" : "ipad", + "filename" : "notificationicon-ipad@2x.png", "scale" : "2x" }, { - "idiom" : "ipad", "size" : "29x29", + "idiom" : "ipad", + "filename" : "icon-small-ipad.png", "scale" : "1x" }, { - "idiom" : "ipad", "size" : "29x29", + "idiom" : "ipad", + "filename" : "icon-small-ipad@2x.png", "scale" : "2x" }, { + "size" : "40x40", "idiom" : "ipad", + "filename" : "icon-40.png", + "scale" : "1x" + }, + { "size" : "40x40", + "idiom" : "ipad", + "filename" : "icon-40-ipad@2x.png", + "scale" : "2x" + }, + { + "size" : "50x50", + "idiom" : "ipad", + "filename" : "icon-small-50.png", "scale" : "1x" }, { + "size" : "50x50", "idiom" : "ipad", - "size" : "40x40", + "filename" : "icon-small-50@2x.png", "scale" : "2x" }, { + "size" : "72x72", "idiom" : "ipad", - "size" : "76x76", + "filename" : "icon-72.png", "scale" : "1x" }, { + "size" : "72x72", "idiom" : "ipad", - "size" : "76x76", + "filename" : "icon-72@2x.png", "scale" : "2x" }, { + "size" : "76x76", "idiom" : "ipad", + "filename" : "icon-76.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "icon-76@2x.png", + "scale" : "2x" + }, + { "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "icon-83.5@2x.png", "scale" : "2x" }, { diff --git a/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-20@3x.png b/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-20@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..a14216ca6e69c48d012c5707551ef48835aec742 GIT binary patch literal 4308 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 N002ovPDHLkV1g50Fp>ZO literal 0 HcmV?d00001 diff --git a/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png b/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..fad5175a2d46e8d5a117f78d780e73602a74235d GIT binary patch literal 5548 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 literal 0 HcmV?d00001 diff --git a/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png b/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..ff297fe49d09a6a5a5e2834c958d77dfebd69990 GIT binary patch literal 7938 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 literal 0 HcmV?d00001 diff --git a/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png b/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..1c372fab39e06bc4c217a2d483dfb50115c0f8d8 GIT binary patch literal 11629 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 LNkvXXu0mjfLHen^ literal 0 HcmV?d00001 diff --git a/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-72@2x.png b/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-72@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d65bc1ac9f72e3340b75d1c74f3dacfb46be3baa GIT binary patch literal 9281 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 literal 0 HcmV?d00001 diff --git a/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-76.png b/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-76.png new file mode 100644 index 0000000000000000000000000000000000000000..2783b024a9673edf62483dd5d1d4215bd43070c6 GIT binary patch literal 5335 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 literal 0 HcmV?d00001 diff --git a/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png b/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..63c7affc47addcfbeadfb0d0dc7d0f4e7a62728b GIT binary patch literal 9924 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 literal 0 HcmV?d00001 diff --git a/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png b/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..abeb59fc8e3fc634dffceb2bef2f5853a8cc7201 GIT binary patch literal 10865 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 Sga5vg0%WBWC96Ig1^o}RU`THO literal 0 HcmV?d00001 diff --git a/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-small-50.png b/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-small-50.png new file mode 100644 index 0000000000000000000000000000000000000000..bf2b38cf65c4a3b608e21cd42f37c12bf401eb6b GIT binary patch literal 3744 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 KMNUMnLSTZ|t~`eT literal 0 HcmV?d00001 diff --git a/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-small-50@2x.png b/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-small-50@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..243f15b707237d479830f2cef6d5d7de0e6d1f04 GIT binary patch literal 6703 zcmV+~8qnp5P)Hg1+lHrgWSWcKdPn90sKGrRqvPeo9CG3uKX#J{(IASm?@+di}}l?o-=)F3E6 zwD^Ni=!>T7nL9I?X}YoAW$t|Qo$sD|?zw001?ah|SeB6#0T!CBEf+H4bBB+JJu8re zhoBb*p;u8ID_yBf0ya+zcePvJL&AGs+11_tpRKn>9TgyPA7ZoSs0)aX0r00)%XR^J z`jH<$>RKN5V(7OqK*TS4xZz{h!*f1C3ECFkK$#7nA@pGN!$;%jYv zwjAKwmYb0gKL(K8-kPtb5${A?tlI~wzMrJ6wTdBr=Y%%%EaEMQ&o}4FQ^DA)s*}Z> z!FI&AHCpoWI|RUqx?7s@$8!5^Q=anY%X@i5{QA6kNcMelpE>R6eCYFpmMsVT zrI(b06~u#xf1yS}_UGdMvD``!0~u->P=lA4?YN`hilQ z|3tHka)7T{2CGqwjZfMwx$5irQN_*|e4l)UHmiYuz74Yp1t^#>hrJ3-SOXDcC_o0^ z7T9R1gAN8V6s;5)ieI5-7aQlmJn}lUna#nz!j%5V$X|o`xX!dHWQRV27P1=rj;t2b zW$~+pTw@bIek?ZvKPDL<64`^#UNTAck#RBsB6*5DP4<%UA_FqU$I>2EH_cM;u)Q~SI+rg`Rn{L z_AC5qq~L$#SMj%U$6Cz0vP{G5Y*=%5RT^yu;}-DInZ=349rJPVM6C3K^oO)8y(fJr{l>k`ead~!ea?NsT>_Ci%bnxC;Vy6= zb6>{xYV#Ue-+LB$7`JEXmTRm^AtP)R9u{)KHsMiWGV&)32xCG~*nyU<>-!d;FP=Re z4r3qYr~6#KE>;1F`>_J_P5xC?ROxV(DIHdCO*p$HRQI@7^PwV@Pvuf+ z5K}u-6REM(K@W$srgorh0{i?O)v0c>QtHxU-hBdD(>iYJ4b2sIOVX2K8m~4gmYVA5 zh^QEb$V`rCQ-|7ZS{nuL-t>?3n=-o(6I(7vocj#GzCZEo`!3>+v;dYIfPu#&ZWzzX z2i^rZ^Mu;6+rb@?NPG+6)c5T6zxpzGe*M(x+{AON=PiJ>H#?ob-|uwRK0yDg0B4PV z0id6JRRdfL?*IT5(Md!>RCodHo%wSd)po~^HfymqTZ?VUvLxGh!E0<|!(;O+;PD`V zBK25`Dk$m&lAnQ}Sbj(f_yZ_@AU{Jv>OqA^JxGcG2?6p78{6Q0x9}$KmaWaQHcR<_ zuGFg5Fw@gL8cAbYr)s8qdivhJ_k8bJ?zu~64g7WEpiR-_b6{}5tZ=qvPku?JO5o?f z6d-h*=Tm@W00{mfOabEOMh2YcWl0I<9Dy`Lj9p!G%GS?4VR<>%Mu9?F?%k$zJCz2qVry!eUD|A( z5d$V^oiuTD|M6Q79f%LSE6@aeWldI39j5e)0bd+kYCoTz>-Yf(ei{(7xM#u4i}v@+ zcU#G{9>-kLUg?`=pYB;{hg&KI-k@bm-N91;9#9(6u9$t=9$C8Aruo1`8hiTk?1<8x zXr1Bm$(JLm`*x?yJ1rAqtD z-sSexs_jk!VD^6=xYdEd|9%1#fJM%BovpRPygqw)$v!6ufN|tvm3@6=v7PTM9s$>r zpc1LcyBdz#`nuy1pvkdAlh72T9mJRumuK3R=6O;@@xkyj8Kxg;sj{7?Yb{GQ;;@*y z|NJZmmjAxkbMoFU>1&oGkZ#|(+4j+{zmcsfcEF+rQE?pkbV=%v*#9}QNQE3Nt+9EJ z*Y8OIgv#tVQ)~UQ0nRXos2$Qmn!)}Y+b1x*Rvna-ynFSGg95O3W~(K)bWOK2?d5h+$3#qx%?~DD z(*0Xy{M&o-Woxi9iHY)Y$EFkYc5M=D$;8_bF{DR;T$QUDRytrG_hR7xB$d;x^vM`Y z8VKNyOJ(uN(|H&|jh*W(wU#T>t-81~lr)CPH_SZ~E+G_Z$SVqNsfh~T)jKT`g8;Hy z;CIWja_(-TjAO3jQnz&%s3oLU&Y0{%{~UKfFyQVZMc^bt6)c?A?K*FGOHnBbQ@y-h ze?Jw*MlYWC$dr%crm|oh3_pCK+79S*S$dqdHlwi1md-lse16nOCKBbu>nfKU4AG!Q zB!xzVOPoSua+xLh8W%tSqoX(9^%V{Y41n=;{xP|`yUy0Qju>GM>_Vmy9n1QeEml?1 zVVzQ2C)#G%Wkmw01L2&yvQ~w3`o^ULnRY+`1Ec%zyH^>^rw=g{3>jj(cYda$bOfYK z0|W`FQO|wT@dkNYjn*OW%##Q}shEDn?rCVU6?0Cf9h9^Kf@tH%AG=(Uum=tRp2TpT zX@r;cqugYqmj=dfKjD7=dGAUY{X)B|u_>*fq*Y%~_%5}k-Dl^h5~D*J{t8_W=ST@I zbG(L=qh36o;{X1#(3;fgbT%eUl}alhNC%y^_MU>c6-iT>Ga?&2H*Dh%CmP%_U4=?7 zAS%^W`TL%}O;;f^H6J7hTiABBC{iCMs6J^2gy<@&>t-OjDZO%FI;EyZ+~P4-JS~6# zfD2Yjgex^TRFdD5Rxuu99mh2}b!RLlU6e8)4g?u)^ypQEt$VHwIc!BmU2b3~6Z;qG zVw#r^b*J%FsLpg29Z%%u4@D-tyP_Raa(j8;MGd$9d}^*8S6_p11fsDO>V+?xea3E| zcg&jG$`#O?X?P?zDxtE_4F939K57e_0yqmRE@+gqMdSJ!c8=KbjXZ=47&|mj^!4E- z)~P@r?w?avDjY2agTA!-ob$36M52&4GEv`aNQWwk<>WW6a{Y`;_PbjS*qqY#aG(qi z;YI=kFc@|FWX~$c<9I$gf4Ff36)H!co0U-6)2H>?6DxK&aFR+&)YjTll>Lf$cT2m3k&^I$NKMfT50h!MBH!3|quM(ZN-VJ$5!?*5z{Z?HK`4dUN}bfB&_)SYn0F!nc6&76m&2Q1fE@(hXK zR?W>l-CpXvh*W}!Fat2^>+9|I+i$n|^XJ>NY4MF8t@qTaQ?_Nx7Tdpnzhh)}c5(qH z9l)+!xzg6JUvD)vHSTvj7WVe`T2oV#ZQ8WSH2^>%Z7Kv9%gj#-F3LC>TYBH*VZ$8#Zik=V2>;;J^X<;)^e=qoX4* z9a2$VUTzOP^pGuDqzTj^iFAPS{rBH%X@iDwLjdp3n#PINU>5!TQt?DBl1fLESQcQM z>nO3$_Ahr)Tpr-m)Nn-2NshlnNzRcB)Xrm%J!VUmEJ<>A{J+niKW`s@{IOlSbSW+< zNFHkG$tRz5$N0GfU){TRuYLB}XHJU4ND5Msry+?31s2!Up0ouO7jb(W_hy&@o-kJUhQ7e9>Ni{dK3$afAJY!KD@Z znYDK9TD8j2-Vs2&{PN2NfVbUtn{y=ayqfd!-Xw(mBON%nM`0srVajykT#@{kHR@{7itE@4ox4ty{NlgL=2g$k&!%PU`*!ONgErLQ2Dw%eCO?)3pFb#yAwJS)_TM@Y^~FTM0DFueac(jk2Q`RA>xOOq865S`V+Lb>`WFob1w zsQs}=dnI;d1>GvdXz@=_=D^ET1V&M*Ao}5lADm|yOlY$j+=X3vj3mL(t>!#j3w+2Ab3bUJw1VSiV~(EPmf?GtvHscxWr+Jm|7yD z0bpbN&rEc$|2p0k3zHUAs@JXto{W;-ft1WGZ?!)x->I!Fy4||(R6_4m1TP5BCWvrF z!w?Pvo(}}jxV5Mh^7n&&_uY4g>L8Mq=s_YPU!D^ckUq`mB#ct61wdhJaZ*4iAfPPJ z;M5=2ZLvEvE0NuH=(R_k1cy2~eE4vpI=k!7KKtyi>_EH(xUpV~#!K=fq_wrxnwy(P zlF*xf_0?BLekVG4;e{8B{!1b{bm&kdm4!AT+PiAbDciU}bq?tm<^1zMH2h1VLX5hu z44K)!P{6EFtY)UBOrF(LeCGA~G{>kUu|H^CFb*kTY$6`bnKQ>lSHJn@n|Ob_YYP@E zaQz3*qx$;mubqUT?$Gl9PaMi4qRH48BDkJs=KaUr+WD(D^W+_}>Y9(gyCo?zbxAADed0wHmDN1pcvD5w_(qGrq(TIEYRVqW*& zd#?kVd+As3`>nU$ve#aFEl?`S9|=k3Wg!(CwZ!cqZFch;4NA?Ghnl5pgkh7@5Fnw) zL&(sJZGEtPt@UaABNca;779b2e){P^PFOM3tKuYK!5*8s{EKvqNVH^lt>yJMA$a#m!qyrmKrJWy8>npW26com84BaU2 zQyVEq0tAoYLq#%w(RN8=SwjfJ2ys01)Ki9vN`>%v7!Nsq{CM1!i`pWjLWn+DXEf3C zu|+%sl@$g&@?qjN%c|FD)3t{d?+?FI_3(H|XqASP^hiYuod3 z2HbjgwkS+a5mi=}`Xjrv9^}vaWRTOe!j{e!Y5*gT;YF_p5e~uj?c0ssH-Ls=6q174 zB7eqVN=izC9^nF!n>TN^-Me?Y`@%{_Y^JEH{M!>2rVn*b9Im-bMaAhhU^P z>jag=tP^Y%62&tUd4c|Xlbz%C{@s$jwr<{W8`OCq4FeJ!e)s1f#EZ4(VU*D?fAXMn zDi6a@VT^&$^7+7Y&y6KLK%~Mb@*y3JCxp(2ym$s+@eDrP$F)?Rk*Izbw9+gJMFNCz zVn7+{dtl zyvYhO_5TnDh-!rDh72<-G$8JNc?)+n{GyP2i;HPZF+G?A%tM&3XnEMM3AsfA1SuhM z$+|f@K77h8cWuiEfZD zqTSP^E!d*TQxPyeUutT#?Ckv-Ln>kTJH!}>pCu^);?LlxQ*~~&X*%X@`SZ>6b4F0t z&pzcgGdrUhorFxv1we!BtDCi`3Pc5iI*$pE0g2{G?bwh?kTKI4o~(S>Pj=1zr}dj` zrG_I$47aYQ0)+RxNJiaD#F2Tu=*q6%n{y#3jj&CNIav(=81%&5C!&h-^OWq1VdrfDMzLJw8-Wy;w0g~1%NRgl zZh>0J-!9&#d0Tyfv*b~6y_yoU()s9zGFr`{f+=qhu_Az1E8SXsHq?BppuGJ5jZH$7 z6E5C74dy?!a=V+IhfYOWT%}Yoj(B6}*$s8a>_P1zwY9k}vYPW3dOXhoVpg%%F3Mmh zvW?H0F<_(AO&)Y@I-I!j0n?{^|f+@L8$ zOkt}uJw48?3fln zcnF|i;5O7Bl_VT@uZN(8u|6VKAqGeK%?A8jPcnWsbpIrL6Pr4wtqJecoT|BHZFb;% zwOi=QD=*mVWu9!tlIrtT#0$z)=X6ur0HI(`bWu+tY>Oi?-z#{Q#^O7*O;IKjJqnhi z4F~|K(gHk8U`~AgSe+iV=v4lCMpnD>H@e%1Qwlt-@?OzF1eQl`QwBv zSKlhk(g81BI*$_y2o;{L)_Sj6Jj_lu=M{;#Q%=Hk0q8;$Db&2TKgVv>=q6j&2IYaO z>KlIEtdL6wQYcQ+Bohh zkDkiH9z3#ik1f-ymY9=F-mXEYQE(jUCz;)=iPCpA{xWU`J4~_1&8P=Gd{C1m?wQ}D z@#YTq7Ms&r*1)Fr5UQz0JJ;bl!$4<|#lU&GhUW$|!b$# zNB20=AC>AoFI7kEXYHy@-zFKs?70H5QNzrhi%M?1uz1C+Gj2mqb}(XbKkt)*y!+gb zN&1>JK>Q2u&wO)_xKz;Ir! zI_wZ`%Cp86Ww%k$-G+vZY@* z#QwNF4u_>7CX3Ac8Flu1Ce^~tg%U9R+GVFz`>OM9UDjfhY1(GK;!Ui_Kmx8Siah&0 zgKFoPE!D)_DD01mF9Cq`7H;+ROp|KV$I3WoKO7L(nKT4cJR^*HK>2REzor1mFvzC> znF1ukIFMn*$(37@VMV%0ivte&Hg1+lHrgWSWcKdPn90sKGrRqvPeo9CG3uKX#J{(IASm?@+di}}l?o-=)F3E6 zwD^Ni=!>T7nL9I?X}YoAW$t|Qo$sD|?zw001?ah|SeB6#0T!CBEf+H4bBB+JJu8re zhoBb*p;u8ID_yBf0ya+zcePvJL&AGs+11_tpRKn>9TgyPA7ZoSs0)aX0r00)%XR^J z`jH<$>RKN5V(7OqK*TS4xZz{h!*f1C3ECFkK$#7nA@pGN!$;%jYv zwjAKwmYb0gKL(K8-kPtb5${A?tlI~wzMrJ6wTdBr=Y%%%EaEMQ&o}4FQ^DA)s*}Z> z!FI&AHCpoWI|RUqx?7s@$8!5^Q=anY%X@i5{QA6kNcMelpE>R6eCYFpmMsVT zrI(b06~u#xf1yS}_UGdMvD``!0~u->P=lA4?YN`hilQ z|3tHka)7T{2CGqwjZfMwx$5irQN_*|e4l)UHmiYuz74Yp1t^#>hrJ3-SOXDcC_o0^ z7T9R1gAN8V6s;5)ieI5-7aQlmJn}lUna#nz!j%5V$X|o`xX!dHWQRV27P1=rj;t2b zW$~+pTw@bIek?ZvKPDL<64`^#UNTAck#RBsB6*5DP4<%UA_FqU$I>2EH_cM;u)Q~SI+rg`Rn{L z_AC5qq~L$#SMj%U$6Cz0vP{G5Y*=%5RT^yu;}-DInZ=349rJPVM6C3K^oO)8y(fJr{l>k`ead~!ea?NsT>_Ci%bnxC;Vy6= zb6>{xYV#Ue-+LB$7`JEXmTRm^AtP)R9u{)KHsMiWGV&)32xCG~*nyU<>-!d;FP=Re z4r3qYr~6#KE>;1F`>_J_P5xC?ROxV(DIHdCO*p$HRQI@7^PwV@Pvuf+ z5K}u-6REM(K@W$srgorh0{i?O)v0c>QtHxU-hBdD(>iYJ4b2sIOVX2K8m~4gmYVA5 zh^QEb$V`rCQ-|7ZS{nuL-t>?3n=-o(6I(7vocj#GzCZEo`!3>+v;dYIfPu#&ZWzzX z2i^rZ^Mu;6+rb@?NPG+6)c5T6zxpzGe*M(x+{AON=PiJ>H#?ob-|uwRK0yDg0B4PV z0id6JRRdfL?*IS=Xh}ptR7efIS4mG>R~S8>4cH6;0try#v<0k?l5RqzDiYgDlnzl^ z#3suG{s2FL9UE5s1S%@AtCAp8Rj7)DNK-;e#ZZP2QWGGt0b`7Ze&>6B4@@z*UGz%N z@7?j7Z@#vrCp$9uzgi{@crU|VD4xxh0UxuS?wjLiWpjd$k_%2qAXxwY` z?P=J|rvOyvMQbSAqxlw0Z`8wWPoXRH5(i0_j=3Bue0_Ze$+R8MWWJ&FJ=#B5h2w-q z&N@FYsEw-~NksO2`1MVl?u`rB_|nHnXY5D_P$K2PqlFgi9lEif@Zk4wEqtB?+UnPU zq!Y)+$c4@enn*h^D`2~#LZ_&X01kP-7ZtOqG$PT~eu=7>QXk2hh^&7XD}mp61gDH; zGD<%O)pnNm(mqc_r9ZD+Q$UyW^Rdo3O*(#09I+!e>PsW|ru8=zyN-^5^LZ};K?#H{ zCFD~mAPGd{MQY>4?JB&9mZ^zOdOg?Vs8`@HwHm~Fw3KtOU*HhB=+uu1K-K=T)+lF{ z;g;CgD-xUREl^6hAdc{(sMRKBaM;rS3Do33OD^wJVt(tghSnFMSrhYwq#{*ZJWg~A zmpy6j)psV7K`KS3V1ls0;c)1iljqIR@hJJLNV%xo38yWoz?P(t5D3+TF&lo1mG>0_ zZM1Yc4X@XWmX;QjmzQI6a})FP^A?GGb0o)>7VrJ=(zbZA0H%yHEznfjhM$%`LU_+- z0a6N|&xd>W?xDWE-q<0(1RWh6RWdz2J*cg%wdUsL<}fxkW{{FBdrbiE1eZi5Bw@Iu zra{_sJyLyLI2n$_gGlcz}wE3JeSk zV0d^~#{+=?`uh5G&-C=PjxjkbY*izE
@R9RKhjM($41an7l5k7aq@-j-dySuBK zgsB~tUdguw9VCFczJF%;4Mixd8=VnS?wj<>UDI6si`S6 zH8r8Ds|!OzLs(y5$Nl^FF+M)7_U`TNMMFb_es^|uDw&y?8TD{F(akHb@p932ba^=#pSCh>ng9`2Bt*G&wn` z9!}G+(Nx`S&v31B%kW+);+CY4%5kYUh9b!vOx$KR;%3@#byZ51eABtiSmmM1%gZ`{ z)*S5_*CJ4)snwt$D(6NvF1X^4;=3EqQKI@c-AS^OfZ6SKO$6q*u`B-^b9Rv{fsoj< zscKUK)`B`AY4((=;(esJAZrAg;uzk9I{(c*Orzg^@?5J8vyxHb48tD7^Bj@Z?M$Ln z%2Ps8BGv2>`~DkH5@wMj;$Zz$+T~tnp6? z^i93Ga5L3^N5)#jS;{;I`t1`^yvpPQSq~%$=F#Y(2bB`n%-IAo?V1B}x|0Q!dm=9> z=QqQFxQ1$ze+JHkIN70eX@>0h`9~PDTr7|H_2ojA=d4i@IU@yjlyMdQ20fH}m3>Qv Q#sB~S07*qoM6N<$f~N`2)c^nh literal 0 HcmV?d00001 diff --git a/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-small-ipad@2x.png b/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-small-ipad@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0e94e0c6ea9e7a87129ccedb14b6964b05791787 GIT binary patch literal 4209 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
@R9RKhjM($41an7l5k7aq@-j-dySuBK zgsB~tUdguw9VCFczJF%;4Mixd8=VnS?wj<>UDI6si`S6 zH8r8Ds|!OzLs(y5$Nl^FF+M)7_U`TNMMFb_es^|uDw&y?8TD{F(akHb@p932ba^=#pSCh>ng9`2Bt*G&wn` z9!}G+(Nx`S&v31B%kW+);+CY4%5kYUh9b!vOx$KR;%3@#byZ51eABtiSmmM1%gZ`{ z)*S5_*CJ4)snwt$D(6NvF1X^4;=3EqQKI@c-AS^OfZ6SKO$6q*u`B-^b9Rv{fsoj< zscKUK)`B`AY4((=;(esJAZrAg;uzk9I{(c*Orzg^@?5J8vyxHb48tD7^Bj@Z?M$Ln z%2Ps8BGv2>`~DkH5@wMj;$Zz$+T~tnp6? z^i93Ga5L3^N5)#jS;{;I`t1`^yvpPQSq~%$=F#Y(2bB`n%-IAo?V1B}x|0Q!dm=9> z=QqQFxQ1$ze+JHkIN70eX@>0h`9~PDTr7|H_2ojA=d4i@IU@yjlyMdQ20fH}m3>Qv Q#sB~S07*qoM6N<$f~N`2)c^nh literal 0 HcmV?d00001 diff --git a/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-small@2x.png b/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon-small@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0e94e0c6ea9e7a87129ccedb14b6964b05791787 GIT binary patch literal 4209 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 literal 0 HcmV?d00001 diff --git a/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon.png b/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..5c1e349bfb149296f31394f2bba2d5c891aa13ea GIT binary patch literal 4078 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 literal 0 HcmV?d00001 diff --git a/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon@2x.png b/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/icon@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0b40c3843dca1bd1a2ac88c422cf7aea81279700 GIT binary patch literal 7466 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 literal 0 HcmV?d00001 diff --git a/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/notificationicon-ipad@2x.png b/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/notificationicon-ipad@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9b29cf5f9ccfe0773a63ad5fee98b2e4bcbce660 GIT binary patch literal 3175 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 N002ovPDHLkV1g50Fp>ZO literal 0 HcmV?d00001 diff --git a/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/notificationicon@2x.png b/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/notificationicon@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9b29cf5f9ccfe0773a63ad5fee98b2e4bcbce660 GIT binary patch literal 3175 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 N002ovPDHLkV1g50Fp>ZO literal 0 HcmV?d00001 diff --git a/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/notificationicon~ipad.png b/FineDust/Supporting Files/Assets.xcassets/AppIcon.appiconset/notificationicon~ipad.png new file mode 100644 index 0000000000000000000000000000000000000000..3c697e5798858cd4f1449e74875c422dcb36570e GIT binary patch literal 1979 zcmV;s2SoUZP)Hg1+lHrgWSWcKdPn90sKGrRqvPeo9CG3uKX#J{(IASm?@+di}}l?o-=)F3E6 zwD^Ni=!>T7nL9I?X}YoAW$t|Qo$sD|?zw001?ah|SeB6#0T!CBEf+H4bBB+JJu8re zhoBb*p;u8ID_yBf0ya+zcePvJL&AGs+11_tpRKn>9TgyPA7ZoSs0)aX0r00)%XR^J z`jH<$>RKN5V(7OqK*TS4xZz{h!*f1C3ECFkK$#7nA@pGN!$;%jYv zwjAKwmYb0gKL(K8-kPtb5${A?tlI~wzMrJ6wTdBr=Y%%%EaEMQ&o}4FQ^DA)s*}Z> z!FI&AHCpoWI|RUqx?7s@$8!5^Q=anY%X@i5{QA6kNcMelpE>R6eCYFpmMsVT zrI(b06~u#xf1yS}_UGdMvD``!0~u->P=lA4?YN`hilQ z|3tHka)7T{2CGqwjZfMwx$5irQN_*|e4l)UHmiYuz74Yp1t^#>hrJ3-SOXDcC_o0^ z7T9R1gAN8V6s;5)ieI5-7aQlmJn}lUna#nz!j%5V$X|o`xX!dHWQRV27P1=rj;t2b zW$~+pTw@bIek?ZvKPDL<64`^#UNTAck#RBsB6*5DP4<%UA_FqU$I>2EH_cM;u)Q~SI+rg`Rn{L z_AC5qq~L$#SMj%U$6Cz0vP{G5Y*=%5RT^yu;}-DInZ=349rJPVM6C3K^oO)8y(fJr{l>k`ead~!ea?NsT>_Ci%bnxC;Vy6= zb6>{xYV#Ue-+LB$7`JEXmTRm^AtP)R9u{)KHsMiWGV&)32xCG~*nyU<>-!d;FP=Re z4r3qYr~6#KE>;1F`>_J_P5xC?ROxV(DIHdCO*p$HRQI@7^PwV@Pvuf+ z5K}u-6REM(K@W$srgorh0{i?O)v0c>QtHxU-hBdD(>iYJ4b2sIOVX2K8m~4gmYVA5 zh^QEb$V`rCQ-|7ZS{nuL-t>?3n=-o(6I(7vocj#GzCZEo`!3>+v;dYIfPu#&ZWzzX z2i^rZ^Mu;6+rb@?NPG+6)c5T6zxpzGe*M(x+{AON=PiJ>H#?ob-|uwRK0yDg0B4PV z0id6JRRdfL?*IS;T}ebiR5%fJR9#OKQ4l@5+ihuU3)VuBRBKVAMg>U>1|^`#t0aW@ zr2l~5#FGgzKA7+ZG=>L_kwioVQbphaN>OMHRB3IyAI{9OP%2Kcd-vX*Irq%DGgqq{Hf~rnrp_u#c$ZyJB^5cA0212M4xjwZYKinl>(U0#*r@uF|&3FHU(Bp4KJ5E zP^@|p)XQj({6wgs1e>y`HKkTVMKkbWBZ1V)717QlXIH~oJ$1?;8rVnsnH(OpugHdk z{I7;PzeC6rnou%yFc=#Hxrw>o2K~zv8Zozd4w=0s@pE6okTqM$wcy1TNwbW#u5bs-+2-X_^QIgYf(P;BN-!Clm@n*L7GHrAWrwW(#5Z zayFGiVbOn;eeh`}N>zro(bw09o}L~Fnx3A<;^HDkMn;fKCb7G_i;0N|WV2fc`3$K9 zaio{ZHCCpwc(r;N`xP&-FcFKz(BI#W+1Xi)j*cQ4jbdP6K;}b3Lnssq7#tiFQYDK0 zxYg$3L1lJckAds4@6d@M%jWfZshAavkB?()Yz#9qGl)bYn3|fx9okfKAcaD z#5g>ZEjqPl^S4nkG-#TN;o)Hf0s*8_DPfq&WYF8&i+nzh?(S{@UR+A!Ot69{U2}*u z{D$p|9RV)ywBY&YE;(fuU(+-s5(%iPinX;h7>0pxIE;8aj$AH>o$YNXng@Rj4<6t6 zgwD2g*m|o2$O71;Wor2<-cezDsEjyu%Q8h91{WV%GEv}B{NC=3r< zPbH8@pol7!flA;EswfVSpwWwg7+hMBq-myfhp#UbMH<_}dr0rZNLx$N z+oaaK*8BqxucT=Q>h*)J5;S@p1C%|8sgHo4-kOsZWL8{je!YrE*Oo+*Q{FOcVt Date: Thu, 24 Jan 2019 09:58:01 +0900 Subject: [PATCH 16/84] =?UTF-8?q?SwiftGen=20=EC=B4=88=EA=B8=B0=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FineDust.xcodeproj/project.pbxproj | 12 ++ .../View/Value Graph/ValueGraphView.swift | 1 + .../Supporting Files/SwiftGen/Assets.swift | 107 ++++++++++++++++++ .../SwiftGen/Storyboard.swift | 80 +++++++++++++ swiftgen.yml | 11 ++ 5 files changed, 211 insertions(+) create mode 100644 FineDust/Supporting Files/SwiftGen/Assets.swift create mode 100644 FineDust/Supporting Files/SwiftGen/Storyboard.swift create mode 100644 swiftgen.yml diff --git a/FineDust.xcodeproj/project.pbxproj b/FineDust.xcodeproj/project.pbxproj index b7b483f0..0fddafef 100644 --- a/FineDust.xcodeproj/project.pbxproj +++ b/FineDust.xcodeproj/project.pbxproj @@ -44,6 +44,7 @@ 1949B0AF21F5EB9F00B22915 /* .swiftlint.yml in Resources */ = {isa = PBXBuildFile; fileRef = 1949B0AE21F5EB9F00B22915 /* .swiftlint.yml */; }; 199C197A21F73DD600ED439F /* FineDustResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 199C197921F73DD600ED439F /* FineDustResponse.swift */; }; 199C197C21F7433C00ED439F /* Grade.swift in Sources */ = {isa = PBXBuildFile; fileRef = 199C197B21F7433C00ED439F /* Grade.swift */; }; + 199C19A821F9441200ED439F /* swiftgen.yml in Resources */ = {isa = PBXBuildFile; fileRef = 199C19A721F9441200ED439F /* swiftgen.yml */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -86,6 +87,7 @@ 1949B0AE21F5EB9F00B22915 /* .swiftlint.yml */ = {isa = PBXFileReference; lastKnownFileType = text; path = .swiftlint.yml; sourceTree = ""; }; 199C197921F73DD600ED439F /* FineDustResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FineDustResponse.swift; sourceTree = ""; }; 199C197B21F7433C00ED439F /* Grade.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Grade.swift; sourceTree = ""; }; + 199C19A721F9441200ED439F /* swiftgen.yml */ = {isa = PBXFileReference; lastKnownFileType = text; path = swiftgen.yml; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -214,6 +216,7 @@ 1949B08C21F5EB3200B22915 = { isa = PBXGroup; children = ( + 199C19A721F9441200ED439F /* swiftgen.yml */, 1949B0AE21F5EB9F00B22915 /* .swiftlint.yml */, 1949B09721F5EB3200B22915 /* FineDust */, 1949B09621F5EB3200B22915 /* Products */, @@ -304,6 +307,7 @@ 1949B0B521F5EBD900B22915 /* Supporting Files */ = { isa = PBXGroup; children = ( + 199C19A921F944BD00ED439F /* SwiftGen */, 1949B0A421F5EB3600B22915 /* LaunchScreen.storyboard */, 1949B09821F5EB3200B22915 /* AppDelegate.swift */, 192CDAA921F61D0C000CE35D /* GeoConverter.swift */, @@ -312,6 +316,13 @@ path = "Supporting Files"; sourceTree = ""; }; + 199C19A921F944BD00ED439F /* SwiftGen */ = { + isa = PBXGroup; + children = ( + ); + path = SwiftGen; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -377,6 +388,7 @@ buildActionMask = 2147483647; files = ( 192CDAD321F6C87E000CE35D /* RatioGraphView.xib in Resources */, + 199C19A821F9441200ED439F /* swiftgen.yml in Resources */, 1949B0AF21F5EB9F00B22915 /* .swiftlint.yml in Resources */, 1949B0A621F5EB3600B22915 /* LaunchScreen.storyboard in Resources */, 1949B0A321F5EB3600B22915 /* Assets.xcassets in Resources */, diff --git a/FineDust/Statistics/View/Value Graph/ValueGraphView.swift b/FineDust/Statistics/View/Value Graph/ValueGraphView.swift index 6db23ed6..1146ede8 100644 --- a/FineDust/Statistics/View/Value Graph/ValueGraphView.swift +++ b/FineDust/Statistics/View/Value Graph/ValueGraphView.swift @@ -10,6 +10,7 @@ import UIKit /// ValueGraphView Delegate protocol ValueGraphViewDelegate: class { + func valueGraphView(_ view: ValueGraphView, didTapDateButton button: UIButton) } diff --git a/FineDust/Supporting Files/SwiftGen/Assets.swift b/FineDust/Supporting Files/SwiftGen/Assets.swift new file mode 100644 index 00000000..157a1347 --- /dev/null +++ b/FineDust/Supporting Files/SwiftGen/Assets.swift @@ -0,0 +1,107 @@ +// swiftlint:disable all +// Generated using SwiftGen, by O.Halligon — https://github.com/SwiftGen/SwiftGen + +#if os(OSX) + import AppKit.NSImage + internal typealias AssetColorTypeAlias = NSColor + internal typealias AssetImageTypeAlias = NSImage +#elseif os(iOS) || os(tvOS) || os(watchOS) + import UIKit.UIImage + internal typealias AssetColorTypeAlias = UIColor + internal typealias AssetImageTypeAlias = UIImage +#endif + +// swiftlint:disable superfluous_disable_command +// swiftlint:disable file_length + +// MARK: - Asset Catalogs + +// swiftlint:disable identifier_name line_length nesting type_body_length type_name +internal enum Asset { +} +// swiftlint:enable identifier_name line_length nesting type_body_length type_name + +// MARK: - Implementation Details + +internal struct ColorAsset { + internal fileprivate(set) var name: String + + @available(iOS 11.0, tvOS 11.0, watchOS 4.0, OSX 10.13, *) + internal var color: AssetColorTypeAlias { + return AssetColorTypeAlias(asset: self) + } +} + +internal extension AssetColorTypeAlias { + @available(iOS 11.0, tvOS 11.0, watchOS 4.0, OSX 10.13, *) + convenience init!(asset: ColorAsset) { + let bundle = Bundle(for: BundleToken.self) + #if os(iOS) || os(tvOS) + self.init(named: asset.name, in: bundle, compatibleWith: nil) + #elseif os(OSX) + self.init(named: NSColor.Name(asset.name), bundle: bundle) + #elseif os(watchOS) + self.init(named: asset.name) + #endif + } +} + +internal struct DataAsset { + internal fileprivate(set) var name: String + + #if os(iOS) || os(tvOS) || os(OSX) + @available(iOS 9.0, tvOS 9.0, OSX 10.11, *) + internal var data: NSDataAsset { + return NSDataAsset(asset: self) + } + #endif +} + +#if os(iOS) || os(tvOS) || os(OSX) +@available(iOS 9.0, tvOS 9.0, OSX 10.11, *) +internal extension NSDataAsset { + convenience init!(asset: DataAsset) { + let bundle = Bundle(for: BundleToken.self) + #if os(iOS) || os(tvOS) + self.init(name: asset.name, bundle: bundle) + #elseif os(OSX) + self.init(name: NSDataAsset.Name(asset.name), bundle: bundle) + #endif + } +} +#endif + +internal struct ImageAsset { + internal fileprivate(set) var name: String + + internal var image: AssetImageTypeAlias { + let bundle = Bundle(for: BundleToken.self) + #if os(iOS) || os(tvOS) + let image = AssetImageTypeAlias(named: name, in: bundle, compatibleWith: nil) + #elseif os(OSX) + let image = bundle.image(forResource: NSImage.Name(name)) + #elseif os(watchOS) + let image = AssetImageTypeAlias(named: name) + #endif + guard let result = image else { fatalError("Unable to load image named \(name).") } + return result + } +} + +internal extension AssetImageTypeAlias { + @available(iOS 1.0, tvOS 1.0, watchOS 1.0, *) + @available(OSX, deprecated, + message: "This initializer is unsafe on macOS, please use the ImageAsset.image property") + convenience init!(asset: ImageAsset) { + #if os(iOS) || os(tvOS) + let bundle = Bundle(for: BundleToken.self) + self.init(named: asset.name, in: bundle, compatibleWith: nil) + #elseif os(OSX) + self.init(named: NSImage.Name(asset.name)) + #elseif os(watchOS) + self.init(named: asset.name) + #endif + } +} + +private final class BundleToken {} diff --git a/FineDust/Supporting Files/SwiftGen/Storyboard.swift b/FineDust/Supporting Files/SwiftGen/Storyboard.swift new file mode 100644 index 00000000..2f56e144 --- /dev/null +++ b/FineDust/Supporting Files/SwiftGen/Storyboard.swift @@ -0,0 +1,80 @@ +// swiftlint:disable all +// Generated using SwiftGen, by O.Halligon — https://github.com/SwiftGen/SwiftGen + +// swiftlint:disable sorted_imports +import Foundation +import UIKit + +// swiftlint:disable superfluous_disable_command +// swiftlint:disable file_length + +// MARK: - Storyboard Scenes + +// swiftlint:disable explicit_type_interface identifier_name line_length type_body_length type_name +internal enum StoryboardScene { + internal enum Common: StoryboardType { + internal static let storyboardName = "Common" + + internal static let initialScene = InitialSceneType(storyboard: Common.self) + } + internal enum Feedback: StoryboardType { + internal static let storyboardName = "Feedback" + + internal static let initialScene = InitialSceneType(storyboard: Feedback.self) + } + internal enum LaunchScreen: StoryboardType { + internal static let storyboardName = "LaunchScreen" + + internal static let initialScene = InitialSceneType(storyboard: LaunchScreen.self) + } + internal enum Main: StoryboardType { + internal static let storyboardName = "Main" + + internal static let initialScene = InitialSceneType(storyboard: Main.self) + } + internal enum Statistics: StoryboardType { + internal static let storyboardName = "Statistics" + + internal static let initialScene = InitialSceneType(storyboard: Statistics.self) + } +} +// swiftlint:enable explicit_type_interface identifier_name line_length type_body_length type_name + +// MARK: - Implementation Details + +internal protocol StoryboardType { + static var storyboardName: String { get } +} + +internal extension StoryboardType { + static var storyboard: UIStoryboard { + let name = self.storyboardName + return UIStoryboard(name: name, bundle: Bundle(for: BundleToken.self)) + } +} + +internal struct SceneType { + internal let storyboard: StoryboardType.Type + internal let identifier: String + + internal func instantiate() -> T { + let identifier = self.identifier + guard let controller = storyboard.storyboard.instantiateViewController(withIdentifier: identifier) as? T else { + fatalError("ViewController '\(identifier)' is not of the expected class \(T.self).") + } + return controller + } +} + +internal struct InitialSceneType { + internal let storyboard: StoryboardType.Type + + internal func instantiate() -> T { + guard let controller = storyboard.storyboard.instantiateInitialViewController() as? T else { + fatalError("ViewController is not of the expected class \(T.self).") + } + return controller + } +} + +private final class BundleToken {} diff --git a/swiftgen.yml b/swiftgen.yml new file mode 100644 index 00000000..76d4a8b3 --- /dev/null +++ b/swiftgen.yml @@ -0,0 +1,11 @@ +xcassets: + inputs: FineDust/Supporting Files/Assets.xcassets + outputs: + templateName: swift4 + output: Assets.swift + +ib: + inputs: FineDust + outputs: + templateName: scenes-swift4 + output: Storyboard.swift From baa0ffdd3a6692ef1e99d7ee346be8ebb9058a4c Mon Sep 17 00:00:00 2001 From: Jae-eun Date: Thu, 24 Jan 2019 10:44:20 +0900 Subject: [PATCH 17/84] =?UTF-8?q?=E1=84=86=E1=85=A1=E1=84=8F=E1=85=B3=20?= =?UTF-8?q?=E1=84=8C=E1=85=AE=E1=84=89=E1=85=A5=E1=86=A8=20=E1=84=89?= =?UTF-8?q?=E1=85=AE=E1=84=8C=E1=85=A5=E1=86=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FeedbackListViewController.swift | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/FineDust/Feedback/Controller/FeedbackListViewController.swift b/FineDust/Feedback/Controller/FeedbackListViewController.swift index 7fee2027..87ee4f76 100644 --- a/FineDust/Feedback/Controller/FeedbackListViewController.swift +++ b/FineDust/Feedback/Controller/FeedbackListViewController.swift @@ -16,19 +16,18 @@ final class FeedbackListViewController: UIViewController { @IBOutlet weak var feedbackListTabelView: UITableView! override func viewDidLoad() { - super.viewDidLoad() - navigationItem.title = "먼지 정보" + super.viewDidLoad() + navigationItem.title = "먼지 정보" - feedbackCollectionView.reloadData() - feedbackListTabelView.reloadData() - - } + feedbackCollectionView.reloadData() + feedbackListTabelView.reloadData() + } private var count = 10 private let cornerRadius: CGFloat = 7 } - // MARK: UICollectionViewDataSource + // MARK: - UICollectionViewDataSource extension FeedbackListViewController: UICollectionViewDataSource { func numberOfSections(in collectionView: UICollectionView) -> Int { @@ -62,9 +61,9 @@ extension FeedbackListViewController: UICollectionViewDataSource { return cell } } - // MARK: UICollectionViewDelegate + // MARK: - UICollectionViewDelegate - // MARK: UITabelViewDataSource + // MARK: - UITabelViewDataSource extension FeedbackListViewController: UITableViewDataSource { func numberOfSections(in tableView: UITableView) -> Int { @@ -96,7 +95,7 @@ extension FeedbackListViewController: UITableViewDataSource { } } -// MARK: UITableViewDelegate +// MARK: - UITableViewDelegate extension FeedbackListViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { From c31d6e13845fc61457f40243e41ed6b037b4ac81 Mon Sep 17 00:00:00 2001 From: Jae-eun Date: Thu, 24 Jan 2019 10:46:47 +0900 Subject: [PATCH 18/84] =?UTF-8?q?reuseIdentifiers=20=E1=84=89=E1=85=AE?= =?UTF-8?q?=E1=84=8C=E1=85=A5=E1=86=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Feedback/Controller/FeedbackListViewController.swift | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/FineDust/Feedback/Controller/FeedbackListViewController.swift b/FineDust/Feedback/Controller/FeedbackListViewController.swift index 87ee4f76..94e0d47f 100644 --- a/FineDust/Feedback/Controller/FeedbackListViewController.swift +++ b/FineDust/Feedback/Controller/FeedbackListViewController.swift @@ -8,8 +8,6 @@ import UIKit -private let reuseIdentifier = ["feedbackCell", "feedbackListCell"] - final class FeedbackListViewController: UIViewController { @IBOutlet weak var feedbackCollectionView: UICollectionView! @@ -23,6 +21,7 @@ final class FeedbackListViewController: UIViewController { feedbackListTabelView.reloadData() } + private let reuseIdentifiers = ["feedbackCell", "feedbackListCell"] private var count = 10 private let cornerRadius: CGFloat = 7 @@ -46,7 +45,7 @@ extension FeedbackListViewController: UICollectionViewDataSource { cellForItemAt indexPath: IndexPath ) -> UICollectionViewCell { - guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier[0], for: indexPath) + guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifiers[0], for: indexPath) as? FeedbackCollectionViewCell else { return UICollectionViewCell() } @@ -76,7 +75,7 @@ extension FeedbackListViewController: UITableViewDataSource { func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { guard let cell = tableView.dequeueReusableCell( - withIdentifier: reuseIdentifier[1], + withIdentifier: reuseIdentifiers[1], for: indexPath ) as? FeedbackListTableViewCell else { return UITableViewCell() From d45c4ce04b6504b3f6f66ff8eb4d0e63d83ac219 Mon Sep 17 00:00:00 2001 From: Jae-eun Date: Thu, 24 Jan 2019 10:55:42 +0900 Subject: [PATCH 19/84] =?UTF-8?q?FeedbackListVC=20=E1=84=89=E1=85=AE?= =?UTF-8?q?=E1=84=8C=E1=85=A5=E1=86=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FeedbackListViewController.swift | 95 ++++++++++--------- 1 file changed, 52 insertions(+), 43 deletions(-) diff --git a/FineDust/Feedback/Controller/FeedbackListViewController.swift b/FineDust/Feedback/Controller/FeedbackListViewController.swift index 94e0d47f..3cced2b8 100644 --- a/FineDust/Feedback/Controller/FeedbackListViewController.swift +++ b/FineDust/Feedback/Controller/FeedbackListViewController.swift @@ -9,60 +9,63 @@ import UIKit final class FeedbackListViewController: UIViewController { - - @IBOutlet weak var feedbackCollectionView: UICollectionView! - @IBOutlet weak var feedbackListTabelView: UITableView! + // Mark: IBOutlet + @IBOutlet private weak var feedbackCollectionView: UICollectionView! + @IBOutlet private weak var feedbackListTabelView: UITableView! + + // Mark: Properties + private let reuseIdentifiers = ["feedbackCell", "feedbackListCell"] + private var count = 10 + private let cornerRadius: CGFloat = 7 + + // Mark: - LifeCycle override func viewDidLoad() { super.viewDidLoad() navigationItem.title = "먼지 정보" - + feedbackCollectionView.reloadData() feedbackListTabelView.reloadData() } - - private let reuseIdentifiers = ["feedbackCell", "feedbackListCell"] - private var count = 10 - private let cornerRadius: CGFloat = 7 - } - // MARK: - UICollectionViewDataSource +// MARK: - UICollectionViewDataSource extension FeedbackListViewController: UICollectionViewDataSource { - func numberOfSections(in collectionView: UICollectionView) -> Int { - return 1 - } - - func collectionView( - _ collectionView: UICollectionView, - numberOfItemsInSection section: Int - ) -> Int { - return 3 - } - - func collectionView( - _ collectionView: UICollectionView, - cellForItemAt indexPath: IndexPath - ) -> UICollectionViewCell { - - guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifiers[0], for: indexPath) - as? FeedbackCollectionViewCell else { - return UICollectionViewCell() - } - cell.feedbackImageView.layer.cornerRadius = cornerRadius - cell.feedbackImageView.layer.masksToBounds = true - cell.feedbackImageView.image = UIImage(named: "info1") - - cell.feedbackTitleLabel.text = "미세먼지 정화 식물" - cell.feedbackTitleLabel.layer.cornerRadius = cornerRadius - cell.feedbackTitleLabel.layer.masksToBounds = true + func numberOfSections(in collectionView: UICollectionView) -> Int { + return 1 + } - return cell - } + func collectionView( + _ collectionView: UICollectionView, + numberOfItemsInSection section: Int + ) -> Int { + return 3 } - // MARK: - UICollectionViewDelegate + + func collectionView( + _ collectionView: UICollectionView, + cellForItemAt indexPath: IndexPath + ) -> UICollectionViewCell { + + guard let cell = collectionView.dequeueReusableCell( + withReuseIdentifier: reuseIdentifiers[0], + for: indexPath + ) as? FeedbackCollectionViewCell + else { return UICollectionViewCell() } + + cell.feedbackImageView.layer.cornerRadius = cornerRadius + cell.feedbackImageView.layer.masksToBounds = true + cell.feedbackImageView.image = UIImage(named: "info1") + + cell.feedbackTitleLabel.text = "미세먼지 정화 식물" + cell.feedbackTitleLabel.layer.cornerRadius = cornerRadius + cell.feedbackTitleLabel.layer.masksToBounds = true + + return cell + } +} - // MARK: - UITabelViewDataSource +// MARK: - UITabelViewDataSource extension FeedbackListViewController: UITableViewDataSource { func numberOfSections(in tableView: UITableView) -> Int { @@ -83,11 +86,17 @@ extension FeedbackListViewController: UITableViewDataSource { cell.feedbackImageView.image = UIImage(named: "info1") cell.feedbackTitleLabel.text = "미세먼지 정화 식물" cell.feedbackSourceLabel.text = "KTV 국민 방송" - + cell.feedbackImageView.setRounded() cell.feedbackListShadowView.layer.applySketchShadow( - color: UIColor.gray, alpha: 0.2, x: 0, y: 0, blur: 5, spread: 3) + color: UIColor.gray, + alpha: 0.2, + x: 0, + y: 0, + blur: 5, + spread: 3 + ) cell.feedbackListShadowView.layer.cornerRadius = 5 return cell From 05079803df9c86dcdbfbbab5aff0b78e4f6fcbef Mon Sep 17 00:00:00 2001 From: Jae-eun Date: Thu, 24 Jan 2019 10:56:35 +0900 Subject: [PATCH 20/84] =?UTF-8?q?=E1=84=91=E1=85=B5=E1=84=83=E1=85=B3?= =?UTF-8?q?=E1=84=87=E1=85=A2=E1=86=A8=20=E1=84=89=E1=85=B3=E1=84=90?= =?UTF-8?q?=E1=85=A9=E1=84=85=E1=85=B5=E1=84=87=E1=85=A9=E1=84=83=E1=85=B3?= =?UTF-8?q?=20=E1=84=8F=E1=85=A5=E1=84=86=E1=85=B5=E1=86=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FineDust/Feedback/Feedback.storyboard | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/FineDust/Feedback/Feedback.storyboard b/FineDust/Feedback/Feedback.storyboard index 003a0812..8550e3b9 100644 --- a/FineDust/Feedback/Feedback.storyboard +++ b/FineDust/Feedback/Feedback.storyboard @@ -66,7 +66,7 @@ - + @@ -126,6 +126,7 @@ + @@ -208,4 +209,7 @@ + + + From e76cc35dd2b9d3e5763fe2cef044ccdfe5c049d9 Mon Sep 17 00:00:00 2001 From: zunzunzun Date: Thu, 24 Jan 2019 14:24:31 +0900 Subject: [PATCH 21/84] =?UTF-8?q?=ED=83=AD=201=EB=B2=88=EC=A7=B8=20?= =?UTF-8?q?=ED=99=94=EB=A9=B4=20=EA=B0=80=EB=B3=8D=EA=B2=8C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FineDust.xcodeproj/project.pbxproj | 44 ++++-- FineDust/Main/Base.lproj/Main.storyboard | 131 +++++++++--------- .../grayDust.imageset/Contents.json | 21 +++ ...4\354\203\211\353\250\274\354\247\200.png" | Bin 0 -> 26741 bytes 4 files changed, 118 insertions(+), 78 deletions(-) create mode 100644 FineDust/Supporting Files/Assets.xcassets/grayDust.imageset/Contents.json create mode 100644 "FineDust/Supporting Files/Assets.xcassets/grayDust.imageset/\355\232\214\354\203\211\353\250\274\354\247\200.png" diff --git a/FineDust.xcodeproj/project.pbxproj b/FineDust.xcodeproj/project.pbxproj index 9591270d..48995bb8 100644 --- a/FineDust.xcodeproj/project.pbxproj +++ b/FineDust.xcodeproj/project.pbxproj @@ -28,7 +28,6 @@ 192CDAC221F6B24D000CE35D /* Feedback.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 192CDAC121F6B24D000CE35D /* Feedback.storyboard */; }; 192CDAC521F6B2DF000CE35D /* Common.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 192CDAC421F6B2DF000CE35D /* Common.storyboard */; }; 192CDAC921F6B61D000CE35D /* StatisticsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDAC821F6B61D000CE35D /* StatisticsViewController.swift */; }; - 192CDACB21F6B62E000CE35D /* FeedbackViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDACA21F6B62E000CE35D /* FeedbackViewController.swift */; }; 192CDACD21F6C85C000CE35D /* ValueGraphView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDACC21F6C85C000CE35D /* ValueGraphView.swift */; }; 192CDACF21F6C865000CE35D /* RatioGraphView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192CDACE21F6C865000CE35D /* RatioGraphView.swift */; }; 192CDAD121F6C874000CE35D /* ValueGraphView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 192CDAD021F6C874000CE35D /* ValueGraphView.xib */; }; @@ -42,10 +41,16 @@ 1949B0A321F5EB3600B22915 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1949B0A221F5EB3600B22915 /* Assets.xcassets */; }; 1949B0A621F5EB3600B22915 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1949B0A421F5EB3600B22915 /* LaunchScreen.storyboard */; }; 1949B0AF21F5EB9F00B22915 /* .swiftlint.yml in Resources */ = {isa = PBXBuildFile; fileRef = 1949B0AE21F5EB9F00B22915 /* .swiftlint.yml */; }; - 199C19A821F9441200ED439F /* swiftgen.yml in Resources */ = {isa = PBXBuildFile; fileRef = 199C19A721F9441200ED439F /* swiftgen.yml */; }; - 199C198E21F8275700ED439F /* Grade.swift in Sources */ = {isa = PBXBuildFile; fileRef = 199C198D21F8275700ED439F /* Grade.swift */; }; - 199C199021F8276100ED439F /* FineDustResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 199C198F21F8276100ED439F /* FineDustResponse.swift */; }; + 199C198E21F8275700ED439F /* (null) in Sources */ = {isa = PBXBuildFile; }; + 199C199021F8276100ED439F /* (null) in Sources */ = {isa = PBXBuildFile; }; 199C199221F82BBF00ED439F /* DataTerm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 199C199121F82BBF00ED439F /* DataTerm.swift */; }; + 199C19A821F9441200ED439F /* swiftgen.yml in Resources */ = {isa = PBXBuildFile; fileRef = 199C19A721F9441200ED439F /* swiftgen.yml */; }; + AFF183A721F97BDB00C600C1 /* FeedbackListTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFF183A521F97BDB00C600C1 /* FeedbackListTableViewCell.swift */; }; + AFF183A821F97BDB00C600C1 /* FeedbackCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFF183A621F97BDB00C600C1 /* FeedbackCollectionViewCell.swift */; }; + AFF183AB21F97C8D00C600C1 /* Grade.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFF183A921F97C8D00C600C1 /* Grade.swift */; }; + AFF183AC21F97C8D00C600C1 /* FineDustResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFF183AA21F97C8D00C600C1 /* FineDustResponse.swift */; }; + AFF183AE21F97DE600C600C1 /* FeedbackListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFF183AD21F97DE600C600C1 /* FeedbackListViewController.swift */; }; + AFF183B021F97E6E00C600C1 /* UIImageView+.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFF183AF21F97E6E00C600C1 /* UIImageView+.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -70,7 +75,6 @@ 192CDAC121F6B24D000CE35D /* Feedback.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Feedback.storyboard; sourceTree = ""; }; 192CDAC421F6B2DF000CE35D /* Common.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Common.storyboard; sourceTree = ""; }; 192CDAC821F6B61D000CE35D /* StatisticsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatisticsViewController.swift; sourceTree = ""; }; - 192CDACA21F6B62E000CE35D /* FeedbackViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbackViewController.swift; sourceTree = ""; }; 192CDACC21F6C85C000CE35D /* ValueGraphView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValueGraphView.swift; sourceTree = ""; }; 192CDACE21F6C865000CE35D /* RatioGraphView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RatioGraphView.swift; sourceTree = ""; }; 192CDAD021F6C874000CE35D /* ValueGraphView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ValueGraphView.xib; sourceTree = ""; }; @@ -86,10 +90,14 @@ 1949B0A521F5EB3600B22915 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 1949B0A721F5EB3600B22915 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 1949B0AE21F5EB9F00B22915 /* .swiftlint.yml */ = {isa = PBXFileReference; lastKnownFileType = text; path = .swiftlint.yml; sourceTree = ""; }; - 199C197921F73DD600ED439F /* FineDustResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FineDustResponse.swift; sourceTree = ""; }; - 199C197B21F7433C00ED439F /* Grade.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Grade.swift; sourceTree = ""; }; - 199C19A721F9441200ED439F /* swiftgen.yml */ = {isa = PBXFileReference; lastKnownFileType = text; path = swiftgen.yml; sourceTree = ""; }; 199C199121F82BBF00ED439F /* DataTerm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataTerm.swift; sourceTree = ""; }; + 199C19A721F9441200ED439F /* swiftgen.yml */ = {isa = PBXFileReference; lastKnownFileType = text; path = swiftgen.yml; sourceTree = ""; }; + AFF183A521F97BDB00C600C1 /* FeedbackListTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FeedbackListTableViewCell.swift; path = FineDust/Feedback/View/FeedbackListTableViewCell.swift; sourceTree = SOURCE_ROOT; }; + AFF183A621F97BDB00C600C1 /* FeedbackCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FeedbackCollectionViewCell.swift; path = FineDust/Feedback/View/FeedbackCollectionViewCell.swift; sourceTree = SOURCE_ROOT; }; + AFF183A921F97C8D00C600C1 /* Grade.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Grade.swift; sourceTree = ""; }; + AFF183AA21F97C8D00C600C1 /* FineDustResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FineDustResponse.swift; sourceTree = ""; }; + AFF183AD21F97DE600C600C1 /* FeedbackListViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeedbackListViewController.swift; sourceTree = ""; }; + AFF183AF21F97E6E00C600C1 /* UIImageView+.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImageView+.swift"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -113,10 +121,10 @@ 192CDAAD21F623DC000CE35D /* Response */ = { isa = PBXGroup; children = ( - 199C198D21F8275700ED439F /* Grade.swift */, + AFF183AA21F97C8D00C600C1 /* FineDustResponse.swift */, + AFF183A921F97C8D00C600C1 /* Grade.swift */, 199C199121F82BBF00ED439F /* DataTerm.swift */, 192CDAAE21F623ED000CE35D /* ObservatoryResponse.swift */, - 199C198F21F8276100ED439F /* FineDustResponse.swift */, ); path = Response; sourceTree = ""; @@ -171,7 +179,7 @@ 192CDABB21F6B208000CE35D /* Controller */ = { isa = PBXGroup; children = ( - 192CDACA21F6B62E000CE35D /* FeedbackViewController.swift */, + AFF183AD21F97DE600C600C1 /* FeedbackListViewController.swift */, ); path = Controller; sourceTree = ""; @@ -194,6 +202,8 @@ 192CDAC321F6B296000CE35D /* View */ = { isa = PBXGroup; children = ( + AFF183A621F97BDB00C600C1 /* FeedbackCollectionViewCell.swift */, + AFF183A521F97BDB00C600C1 /* FeedbackListTableViewCell.swift */, ); path = View; sourceTree = ""; @@ -284,6 +294,7 @@ isa = PBXGroup; children = ( 192CDA8E21F5EDFC000CE35D /* NSObject+.swift */, + AFF183AF21F97E6E00C600C1 /* UIImageView+.swift */, 192CDA9021F5EE04000CE35D /* UIViewController+.swift */, 192CDA9221F5EE09000CE35D /* UIView+.swift */, 192CDAB421F62A5D000CE35D /* UIView+NSLayoutAnchor.swift */, @@ -432,25 +443,30 @@ files = ( 192CDAAA21F61D0C000CE35D /* GeoConverter.swift in Sources */, 199C199221F82BBF00ED439F /* DataTerm.swift in Sources */, + AFF183AC21F97C8D00C600C1 /* FineDustResponse.swift in Sources */, 192CDAA521F6046D000CE35D /* MainViewController.swift in Sources */, 192CDADF21F6EA03000CE35D /* NSLayoutDimension+.swift in Sources */, 192CDA9521F5EE11000CE35D /* UIAlertController+.swift in Sources */, + AFF183B021F97E6E00C600C1 /* UIImageView+.swift in Sources */, 192CDA8F21F5EDFC000CE35D /* NSObject+.swift in Sources */, 192CDA9921F5EE1E000CE35D /* String+.swift in Sources */, 192CDACD21F6C85C000CE35D /* ValueGraphView.swift in Sources */, + AFF183A821F97BDB00C600C1 /* FeedbackCollectionViewCell.swift in Sources */, 192CDAE521F70169000CE35D /* Storyboard.swift in Sources */, 192CDACF21F6C865000CE35D /* RatioGraphView.swift in Sources */, 192CDAA121F603C5000CE35D /* API+FineDust.swift in Sources */, - 199C199021F8276100ED439F /* FineDustResponse.swift in Sources */, + 199C199021F8276100ED439F /* (null) in Sources */, + AFF183A721F97BDB00C600C1 /* FeedbackListTableViewCell.swift in Sources */, 192CDA9321F5EE09000CE35D /* UIView+.swift in Sources */, - 199C198E21F8275700ED439F /* Grade.swift in Sources */, + 199C198E21F8275700ED439F /* (null) in Sources */, 192CDAAF21F623ED000CE35D /* ObservatoryResponse.swift in Sources */, 192CDA9121F5EE04000CE35D /* UIViewController+.swift in Sources */, 1949B09921F5EB3200B22915 /* AppDelegate.swift in Sources */, + AFF183AB21F97C8D00C600C1 /* Grade.swift in Sources */, 192CDAE121F6F5B2000CE35D /* CALayer+.swift in Sources */, - 192CDACB21F6B62E000CE35D /* FeedbackViewController.swift in Sources */, 192CDAB321F628C9000CE35D /* NSLayoutAnchor+.swift in Sources */, 192CDAC921F6B61D000CE35D /* StatisticsViewController.swift in Sources */, + AFF183AE21F97DE600C600C1 /* FeedbackListViewController.swift in Sources */, 192CDA8D21F5ED9C000CE35D /* Network.swift in Sources */, 1949B0A121F5EB3200B22915 /* FineDust.xcdatamodeld in Sources */, 192CDAA721F60914000CE35D /* Date+.swift in Sources */, diff --git a/FineDust/Main/Base.lproj/Main.storyboard b/FineDust/Main/Base.lproj/Main.storyboard index 03d680c5..e55ad286 100644 --- a/FineDust/Main/Base.lproj/Main.storyboard +++ b/FineDust/Main/Base.lproj/Main.storyboard @@ -18,34 +18,33 @@ -