From 19f19121ec43b4fa79a3f70c85f562813a7ea32c Mon Sep 17 00:00:00 2001 From: "Sergey V. Krupov" Date: Thu, 31 Jan 2019 09:15:55 -0800 Subject: [PATCH] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=B5=D0=B7=D0=B4=20?= =?UTF-8?q?=D0=BD=D0=B0=20Github?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 5 + .swiftlint.yml | 54 ++ Gemfile | 8 + Gemfile.lock | 94 +++ LICENSE | 21 + Podfile | 22 + Podfile.lock | 60 ++ README.md | 2 + Rambafile | 25 + .../Assembly/assemblycontainer.swift.liquid | 38 + .../Code/Interactor/interactor.swift.liquid | 17 + .../interactor_protocol.swift.liquid | 14 + .../Code/Presenter/module_input.swift.liquid | 11 + RxViper/Code/Presenter/presenter.swift.liquid | 32 + .../Presenter/presenter_protocol.swift.liquid | 12 + RxViper/Code/Router/router.swift.liquid | 11 + .../Code/Router/router_protocol.swift.liquid | 13 + RxViper/Code/View/view_protocol.swift.liquid | 17 + RxViper/Code/View/viewcontroller.swift.liquid | 38 + RxViper/RxViper.rambaspec | 29 + Weather.xcodeproj/project.pbxproj | 714 +++++++++++++++++- Weather.xcworkspace/contents.xcworkspacedata | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 10 +- Weather/AppDelegate.swift | 13 +- Weather/Base.lproj/Main.storyboard | 24 - Weather/Info.plist | 2 +- Weather/Models/City.swift | 13 + Weather/Models/Weather.swift | 20 + .../Assembly/ForecastAssemblyContainer.swift | 40 + .../Interactor/ForecastInteractor.swift | 33 + .../ForecastInteractorProtocol.swift | 17 + .../Presenter/ForecastModuleInput.swift | 11 + .../Presenter/ForecastPresenter.swift | 59 ++ .../Presenter/ForecastPresenterProtocol.swift | 12 + .../Presenter/Models/WeatherItem.swift | 16 + .../Forecast/Router/ForecastRouter.swift | 11 + .../Router/ForecastRouterProtocol.swift | 13 + .../Cells/ForecastItemCellTableViewCell.swift | 23 + .../Cells/ForecastItemCellTableViewCell.xib | 61 ++ .../Modules/Forecast/View/Forecast.storyboard | 44 ++ .../View/ForecastViewController.swift | 64 ++ .../Forecast/View/ForecastViewProtocol.swift | 21 + .../Main/Assembly/MainAssemblyContainer.swift | 40 + .../Main/Interactor/MainInteractor.swift | 40 + .../Interactor/MainInteractorProtocol.swift | 18 + .../Main/Presenter/MainModuleInput.swift | 11 + .../Main/Presenter/MainPresenter.swift | 68 ++ .../Presenter/MainPresenterProtocol.swift | 12 + Weather/Modules/Main/Router/MainRouter.swift | 11 + .../Main/Router/MainRouterProtocol.swift | 13 + .../Main/View/Base.lproj/Main.storyboard | 117 +++ .../Main/View/MainViewController.swift | 65 ++ .../Modules/Main/View/MainViewProtocol.swift | 23 + .../Root/Assembly/RootAssemblyContainer.swift | 42 ++ .../Root/Interactor/RootInteractor.swift | 17 + .../Interactor/RootInteractorProtocol.swift | 14 + .../Root/Presenter/RootModuleInput.swift | 11 + .../Root/Presenter/RootPresenter.swift | 32 + .../Presenter/RootPresenterProtocol.swift | 12 + Weather/Modules/Root/Router/RootRouter.swift | 11 + .../Root/Router/RootRouterProtocol.swift | 13 + Weather/Modules/Root/View/Root.storyboard | 20 + .../Root/View/RootViewController.swift | 78 ++ .../Modules/Root/View/RootViewProtocol.swift | 18 + .../Assembly/SettingsAssemblyContainer.swift | 39 + .../Interactor/SettingsInteractor.swift | 33 + .../SettingsInteractorProtocol.swift | 20 + .../Presenter/Models/CitiesSection.swift | 22 + .../Settings/Presenter/Models/CityItem.swift | 13 + .../Presenter/SettingsModuleInput.swift | 11 + .../Presenter/SettingsPresenter.swift | 49 ++ .../Presenter/SettingsPresenterProtocol.swift | 12 + .../Settings/Router/SettingsRouter.swift | 11 + .../Router/SettingsRouterProtocol.swift | 13 + .../View/Cells/SettingsCityCell.swift | 17 + .../Settings/View/Cells/SettingsCityCell.xib | 25 + .../Modules/Settings/View/Settings.storyboard | 44 ++ .../View/SettingsViewController.swift | 64 ++ .../Settings/View/SettingsViewProtocol.swift | 19 + Weather/Resources/Cities.json | 38 + .../Icons.xcassets/01d.imageset/01d.png | Bin 0 -> 5538 bytes .../Icons.xcassets/01d.imageset/Contents.json | 12 + .../Icons.xcassets/01n.imageset/01n.png | Bin 0 -> 4681 bytes .../Icons.xcassets/01n.imageset/Contents.json | 12 + .../Icons.xcassets/02d.imageset/02d.png | Bin 0 -> 6783 bytes .../Icons.xcassets/02d.imageset/Contents.json | 12 + .../Icons.xcassets/02n.imageset/02n.png | Bin 0 -> 5935 bytes .../Icons.xcassets/02n.imageset/Contents.json | 12 + .../Icons.xcassets/03d.imageset/03d.png | Bin 0 -> 7185 bytes .../Icons.xcassets/03d.imageset/Contents.json | 12 + .../Icons.xcassets/03n.imageset/03n.png | Bin 0 -> 6295 bytes .../Icons.xcassets/03n.imageset/Contents.json | 12 + .../Icons.xcassets/04d.imageset/04d.png | Bin 0 -> 6800 bytes .../Icons.xcassets/04d.imageset/Contents.json | 12 + .../Icons.xcassets/04n.imageset/04n.png | Bin 0 -> 6800 bytes .../Icons.xcassets/04n.imageset/Contents.json | 12 + .../Icons.xcassets/09d.imageset/09d.png | Bin 0 -> 8158 bytes .../Icons.xcassets/09d.imageset/Contents.json | 12 + .../Icons.xcassets/09n.imageset/09n.png | Bin 0 -> 8158 bytes .../Icons.xcassets/09n.imageset/Contents.json | 12 + .../Icons.xcassets/10d.imageset/10d.png | Bin 0 -> 9071 bytes .../Icons.xcassets/10d.imageset/Contents.json | 12 + .../Icons.xcassets/10n.imageset/10n.png | Bin 0 -> 8577 bytes .../Icons.xcassets/10n.imageset/Contents.json | 12 + .../Icons.xcassets/11d.imageset/11d.png | Bin 0 -> 8868 bytes .../Icons.xcassets/11d.imageset/Contents.json | 12 + .../Icons.xcassets/11n.imageset/11n.png | Bin 0 -> 8868 bytes .../Icons.xcassets/11n.imageset/Contents.json | 12 + .../Icons.xcassets/13d.imageset/13d.png | Bin 0 -> 11132 bytes .../Icons.xcassets/13d.imageset/Contents.json | 12 + .../Icons.xcassets/13n.imageset/13n.png | Bin 0 -> 11132 bytes .../Icons.xcassets/13n.imageset/Contents.json | 12 + .../Icons.xcassets/50d.imageset/50d.png | Bin 0 -> 7092 bytes .../Icons.xcassets/50d.imageset/Contents.json | 12 + .../Icons.xcassets/50n.imageset/50n.png | Bin 0 -> 6485 bytes .../Icons.xcassets/50n.imageset/Contents.json | 12 + .../Resources/Icons.xcassets/Contents.json | 6 + .../undefined.imageset/Contents.json | 12 + .../undefined.imageset/undefined.png | Bin 0 -> 10055 bytes Weather/Services/Network/NetworkService.swift | 56 ++ .../Network/NetworkServiceAssembly.swift | 19 + .../Services/Settings/SettingsService.swift | 72 ++ .../Settings/SettingsServiceAssembly.swift | 19 + Weather/Services/Weather/ApiResponses.swift | 82 ++ Weather/Services/Weather/WeatherService.swift | 67 ++ .../Weather/WeatherServiceAssembly.swift | 21 + Weather/SwinjectStoryboard+Setup.swift | 24 + Weather/Utils/Utils.swift | 27 + Weather/ViewController.swift | 20 - viperSwift/viperSwift.rambaspec | 29 + 130 files changed, 3469 insertions(+), 71 deletions(-) create mode 100644 .gitignore create mode 100644 .swiftlint.yml create mode 100644 Gemfile create mode 100644 Gemfile.lock create mode 100644 LICENSE create mode 100644 Podfile create mode 100644 Podfile.lock create mode 100644 README.md create mode 100644 Rambafile create mode 100755 RxViper/Code/Assembly/assemblycontainer.swift.liquid create mode 100755 RxViper/Code/Interactor/interactor.swift.liquid create mode 100644 RxViper/Code/Interactor/interactor_protocol.swift.liquid create mode 100755 RxViper/Code/Presenter/module_input.swift.liquid create mode 100755 RxViper/Code/Presenter/presenter.swift.liquid create mode 100644 RxViper/Code/Presenter/presenter_protocol.swift.liquid create mode 100755 RxViper/Code/Router/router.swift.liquid create mode 100755 RxViper/Code/Router/router_protocol.swift.liquid create mode 100644 RxViper/Code/View/view_protocol.swift.liquid create mode 100755 RxViper/Code/View/viewcontroller.swift.liquid create mode 100755 RxViper/RxViper.rambaspec create mode 100644 Weather.xcworkspace/contents.xcworkspacedata rename Weather.xcodeproj/xcuserdata/sergey.xcuserdatad/xcschemes/xcschememanagement.plist => Weather.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (54%) delete mode 100644 Weather/Base.lproj/Main.storyboard create mode 100644 Weather/Models/City.swift create mode 100644 Weather/Models/Weather.swift create mode 100644 Weather/Modules/Forecast/Assembly/ForecastAssemblyContainer.swift create mode 100644 Weather/Modules/Forecast/Interactor/ForecastInteractor.swift create mode 100644 Weather/Modules/Forecast/Interactor/ForecastInteractorProtocol.swift create mode 100644 Weather/Modules/Forecast/Presenter/ForecastModuleInput.swift create mode 100644 Weather/Modules/Forecast/Presenter/ForecastPresenter.swift create mode 100644 Weather/Modules/Forecast/Presenter/ForecastPresenterProtocol.swift create mode 100644 Weather/Modules/Forecast/Presenter/Models/WeatherItem.swift create mode 100644 Weather/Modules/Forecast/Router/ForecastRouter.swift create mode 100644 Weather/Modules/Forecast/Router/ForecastRouterProtocol.swift create mode 100644 Weather/Modules/Forecast/View/Cells/ForecastItemCellTableViewCell.swift create mode 100644 Weather/Modules/Forecast/View/Cells/ForecastItemCellTableViewCell.xib create mode 100644 Weather/Modules/Forecast/View/Forecast.storyboard create mode 100644 Weather/Modules/Forecast/View/ForecastViewController.swift create mode 100644 Weather/Modules/Forecast/View/ForecastViewProtocol.swift create mode 100644 Weather/Modules/Main/Assembly/MainAssemblyContainer.swift create mode 100644 Weather/Modules/Main/Interactor/MainInteractor.swift create mode 100644 Weather/Modules/Main/Interactor/MainInteractorProtocol.swift create mode 100644 Weather/Modules/Main/Presenter/MainModuleInput.swift create mode 100644 Weather/Modules/Main/Presenter/MainPresenter.swift create mode 100644 Weather/Modules/Main/Presenter/MainPresenterProtocol.swift create mode 100644 Weather/Modules/Main/Router/MainRouter.swift create mode 100644 Weather/Modules/Main/Router/MainRouterProtocol.swift create mode 100644 Weather/Modules/Main/View/Base.lproj/Main.storyboard create mode 100644 Weather/Modules/Main/View/MainViewController.swift create mode 100644 Weather/Modules/Main/View/MainViewProtocol.swift create mode 100644 Weather/Modules/Root/Assembly/RootAssemblyContainer.swift create mode 100644 Weather/Modules/Root/Interactor/RootInteractor.swift create mode 100644 Weather/Modules/Root/Interactor/RootInteractorProtocol.swift create mode 100644 Weather/Modules/Root/Presenter/RootModuleInput.swift create mode 100644 Weather/Modules/Root/Presenter/RootPresenter.swift create mode 100644 Weather/Modules/Root/Presenter/RootPresenterProtocol.swift create mode 100644 Weather/Modules/Root/Router/RootRouter.swift create mode 100644 Weather/Modules/Root/Router/RootRouterProtocol.swift create mode 100644 Weather/Modules/Root/View/Root.storyboard create mode 100644 Weather/Modules/Root/View/RootViewController.swift create mode 100644 Weather/Modules/Root/View/RootViewProtocol.swift create mode 100644 Weather/Modules/Settings/Assembly/SettingsAssemblyContainer.swift create mode 100644 Weather/Modules/Settings/Interactor/SettingsInteractor.swift create mode 100644 Weather/Modules/Settings/Interactor/SettingsInteractorProtocol.swift create mode 100644 Weather/Modules/Settings/Presenter/Models/CitiesSection.swift create mode 100644 Weather/Modules/Settings/Presenter/Models/CityItem.swift create mode 100644 Weather/Modules/Settings/Presenter/SettingsModuleInput.swift create mode 100644 Weather/Modules/Settings/Presenter/SettingsPresenter.swift create mode 100644 Weather/Modules/Settings/Presenter/SettingsPresenterProtocol.swift create mode 100644 Weather/Modules/Settings/Router/SettingsRouter.swift create mode 100644 Weather/Modules/Settings/Router/SettingsRouterProtocol.swift create mode 100644 Weather/Modules/Settings/View/Cells/SettingsCityCell.swift create mode 100644 Weather/Modules/Settings/View/Cells/SettingsCityCell.xib create mode 100644 Weather/Modules/Settings/View/Settings.storyboard create mode 100644 Weather/Modules/Settings/View/SettingsViewController.swift create mode 100644 Weather/Modules/Settings/View/SettingsViewProtocol.swift create mode 100644 Weather/Resources/Cities.json create mode 100644 Weather/Resources/Icons.xcassets/01d.imageset/01d.png create mode 100644 Weather/Resources/Icons.xcassets/01d.imageset/Contents.json create mode 100644 Weather/Resources/Icons.xcassets/01n.imageset/01n.png create mode 100644 Weather/Resources/Icons.xcassets/01n.imageset/Contents.json create mode 100644 Weather/Resources/Icons.xcassets/02d.imageset/02d.png create mode 100644 Weather/Resources/Icons.xcassets/02d.imageset/Contents.json create mode 100644 Weather/Resources/Icons.xcassets/02n.imageset/02n.png create mode 100644 Weather/Resources/Icons.xcassets/02n.imageset/Contents.json create mode 100644 Weather/Resources/Icons.xcassets/03d.imageset/03d.png create mode 100644 Weather/Resources/Icons.xcassets/03d.imageset/Contents.json create mode 100644 Weather/Resources/Icons.xcassets/03n.imageset/03n.png create mode 100644 Weather/Resources/Icons.xcassets/03n.imageset/Contents.json create mode 100644 Weather/Resources/Icons.xcassets/04d.imageset/04d.png create mode 100644 Weather/Resources/Icons.xcassets/04d.imageset/Contents.json create mode 100644 Weather/Resources/Icons.xcassets/04n.imageset/04n.png create mode 100644 Weather/Resources/Icons.xcassets/04n.imageset/Contents.json create mode 100644 Weather/Resources/Icons.xcassets/09d.imageset/09d.png create mode 100644 Weather/Resources/Icons.xcassets/09d.imageset/Contents.json create mode 100644 Weather/Resources/Icons.xcassets/09n.imageset/09n.png create mode 100644 Weather/Resources/Icons.xcassets/09n.imageset/Contents.json create mode 100644 Weather/Resources/Icons.xcassets/10d.imageset/10d.png create mode 100644 Weather/Resources/Icons.xcassets/10d.imageset/Contents.json create mode 100644 Weather/Resources/Icons.xcassets/10n.imageset/10n.png create mode 100644 Weather/Resources/Icons.xcassets/10n.imageset/Contents.json create mode 100644 Weather/Resources/Icons.xcassets/11d.imageset/11d.png create mode 100644 Weather/Resources/Icons.xcassets/11d.imageset/Contents.json create mode 100644 Weather/Resources/Icons.xcassets/11n.imageset/11n.png create mode 100644 Weather/Resources/Icons.xcassets/11n.imageset/Contents.json create mode 100644 Weather/Resources/Icons.xcassets/13d.imageset/13d.png create mode 100644 Weather/Resources/Icons.xcassets/13d.imageset/Contents.json create mode 100644 Weather/Resources/Icons.xcassets/13n.imageset/13n.png create mode 100644 Weather/Resources/Icons.xcassets/13n.imageset/Contents.json create mode 100644 Weather/Resources/Icons.xcassets/50d.imageset/50d.png create mode 100644 Weather/Resources/Icons.xcassets/50d.imageset/Contents.json create mode 100644 Weather/Resources/Icons.xcassets/50n.imageset/50n.png create mode 100644 Weather/Resources/Icons.xcassets/50n.imageset/Contents.json create mode 100644 Weather/Resources/Icons.xcassets/Contents.json create mode 100644 Weather/Resources/Icons.xcassets/undefined.imageset/Contents.json create mode 100644 Weather/Resources/Icons.xcassets/undefined.imageset/undefined.png create mode 100644 Weather/Services/Network/NetworkService.swift create mode 100644 Weather/Services/Network/NetworkServiceAssembly.swift create mode 100644 Weather/Services/Settings/SettingsService.swift create mode 100644 Weather/Services/Settings/SettingsServiceAssembly.swift create mode 100644 Weather/Services/Weather/ApiResponses.swift create mode 100644 Weather/Services/Weather/WeatherService.swift create mode 100644 Weather/Services/Weather/WeatherServiceAssembly.swift create mode 100644 Weather/SwinjectStoryboard+Setup.swift create mode 100644 Weather/Utils/Utils.swift delete mode 100644 Weather/ViewController.swift create mode 100644 viperSwift/viperSwift.rambaspec diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..06a8660 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/Pods/ +/Templates/ +/Weather.xcodeproj/xcuserdata/ +/Weather.xcworkspace/xcuserdata/ +/R.generated.swift diff --git a/.swiftlint.yml b/.swiftlint.yml new file mode 100644 index 0000000..520cd11 --- /dev/null +++ b/.swiftlint.yml @@ -0,0 +1,54 @@ +included: + - Weather + +excluded: + - Pods + +disabled_rules: + - force_cast + - object_literal + - syntactic_sugar + +opt_in_rules: + - empty_count + - conditional_returns_on_newline + - explicit_init + - closure_spacing + - overridden_super_call + - redundant_nil_coalescing + - private_outlet + - nimble_operator + - attributes + - joined_default_parameter + - operator_usage_whitespace + - first_where + - sorted_imports + - object_literal + - number_separator + - prohibited_super_call + - fatal_error_message + - vertical_parameter_alignment_on_call + - let_var_whitespace + - unneeded_parentheses_in_closure_argument + - extension_access_modifier + - pattern_matching_keywords + - multiline_parameters + - switch_case_on_newline + +identifier_name: + excluded: + - id + allowed_symbols: + - _ +line_length: 144 +type_name: + max_length: + warning: 50 + error: 60 + +number_separator: + minimum_length: 5 + +nesting: + type_level: + warning: 2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..3ef8a66 --- /dev/null +++ b/Gemfile @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } + +gem 'cocoapods', '~> 1.5.3' +gem 'generamba', github: 'strongself/Generamba', :branch => 'develop' diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..a9ea916 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,94 @@ +GIT + remote: https://github.com/strongself/Generamba + revision: 4c450efc3ea63dd34fa04206194813dbb021441e + branch: develop + specs: + generamba (1.4.1) + cocoapods-core (= 1.5.3) + git (= 1.2.9.1) + liquid (= 4.0.0) + terminal-table (= 1.4.5) + thor (= 0.19.1) + xcodeproj (= 1.6.0) + +GEM + remote: https://rubygems.org/ + specs: + CFPropertyList (3.0.0) + activesupport (4.2.11) + i18n (~> 0.7) + minitest (~> 5.1) + thread_safe (~> 0.3, >= 0.3.4) + tzinfo (~> 1.1) + atomos (0.1.3) + claide (1.0.2) + cocoapods (1.5.3) + activesupport (>= 4.0.2, < 5) + claide (>= 1.0.2, < 2.0) + cocoapods-core (= 1.5.3) + cocoapods-deintegrate (>= 1.0.2, < 2.0) + cocoapods-downloader (>= 1.2.0, < 2.0) + cocoapods-plugins (>= 1.0.0, < 2.0) + cocoapods-search (>= 1.0.0, < 2.0) + cocoapods-stats (>= 1.0.0, < 2.0) + cocoapods-trunk (>= 1.3.0, < 2.0) + cocoapods-try (>= 1.1.0, < 2.0) + colored2 (~> 3.1) + escape (~> 0.0.4) + fourflusher (~> 2.0.1) + gh_inspector (~> 1.0) + molinillo (~> 0.6.5) + nap (~> 1.0) + ruby-macho (~> 1.1) + xcodeproj (>= 1.5.7, < 2.0) + cocoapods-core (1.5.3) + activesupport (>= 4.0.2, < 6) + fuzzy_match (~> 2.0.4) + nap (~> 1.0) + cocoapods-deintegrate (1.0.2) + cocoapods-downloader (1.2.2) + cocoapods-plugins (1.0.0) + nap + cocoapods-search (1.0.0) + cocoapods-stats (1.1.0) + cocoapods-trunk (1.3.1) + nap (>= 0.8, < 2.0) + netrc (~> 0.11) + cocoapods-try (1.1.0) + colored2 (3.1.2) + concurrent-ruby (1.1.4) + escape (0.0.4) + fourflusher (2.0.1) + fuzzy_match (2.0.4) + gh_inspector (1.1.3) + git (1.2.9.1) + i18n (0.9.5) + concurrent-ruby (~> 1.0) + liquid (4.0.0) + minitest (5.11.3) + molinillo (0.6.6) + nanaimo (0.2.6) + nap (1.1.0) + netrc (0.11.0) + ruby-macho (1.3.1) + terminal-table (1.4.5) + thor (0.19.1) + thread_safe (0.3.6) + tzinfo (1.2.5) + thread_safe (~> 0.1) + xcodeproj (1.6.0) + CFPropertyList (>= 2.3.3, < 4.0) + atomos (~> 0.1.3) + claide (>= 1.0.2, < 2.0) + colored2 (~> 3.1) + nanaimo (~> 0.2.6) + +PLATFORMS + ruby + +DEPENDENCIES + cocoapods (~> 1.5.3) + generamba! + +BUNDLED WITH + 1.17.3 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..69528b9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Sergey Krupov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Podfile b/Podfile new file mode 100644 index 0000000..c5cd51e --- /dev/null +++ b/Podfile @@ -0,0 +1,22 @@ + +platform :ios, '9.0' + +target 'Weather' do + + use_frameworks! + + pod 'RxSwift', '~> 4.4.0' + pod 'RxCocoa', '~> 4.4.0' + pod 'RxDataSources', '~> 3.1.0' + pod 'R.swift', '~> 5.0.0' + pod 'Swinject', '~> 2.5.0' + pod 'SwinjectStoryboard', '~> 2.1.0' + pod 'Alamofire', '~> 4.8.1' + pod 'SwiftLint' + + target 'WeatherTests' do + inherit! :search_paths + # Pods for testing + end + +end diff --git a/Podfile.lock b/Podfile.lock new file mode 100644 index 0000000..09aeb01 --- /dev/null +++ b/Podfile.lock @@ -0,0 +1,60 @@ +PODS: + - Alamofire (4.8.1) + - Differentiator (3.1.0) + - R.swift (5.0.2): + - R.swift.Library (~> 5.0.0) + - R.swift.Library (5.0.0) + - RxAtomic (4.4.0) + - RxCocoa (4.4.0): + - RxSwift (~> 4.0) + - RxDataSources (3.1.0): + - Differentiator (~> 3.0) + - RxCocoa (~> 4.0) + - RxSwift (~> 4.0) + - RxSwift (4.4.0): + - RxAtomic (~> 4.4) + - SwiftLint (0.30.1) + - Swinject (2.5.0) + - SwinjectStoryboard (2.1.0): + - Swinject (~> 2.5) + +DEPENDENCIES: + - Alamofire (~> 4.8.1) + - R.swift (~> 5.0.0) + - RxCocoa (~> 4.4.0) + - RxDataSources (~> 3.1.0) + - RxSwift (~> 4.4.0) + - SwiftLint + - Swinject (~> 2.5.0) + - SwinjectStoryboard (~> 2.1.0) + +SPEC REPOS: + https://github.com/cocoapods/specs.git: + - Alamofire + - Differentiator + - R.swift + - R.swift.Library + - RxAtomic + - RxCocoa + - RxDataSources + - RxSwift + - SwiftLint + - Swinject + - SwinjectStoryboard + +SPEC CHECKSUMS: + Alamofire: 16ce2c353fb72865124ddae8a57c5942388f4f11 + Differentiator: be49ca3408f0ecfc761e4c7763d20c62be01b9ad + R.swift: 81455d81467763cbd3f4d79d938d05f4ac4c0228 + R.swift.Library: 0bf390e729bc10bb2c9e4fb78bd043164a7be4ff + RxAtomic: eacf60db868c96bfd63320e28619fe29c179656f + RxCocoa: df63ebf7b9a70d6b4eeea407ed5dd4efc8979749 + RxDataSources: a843bad90c29817f5923ec8163f4af2de084ceb3 + RxSwift: 5976ecd04fc2fefd648827c23de5e11157faa973 + SwiftLint: a54bf1fe12b55c68560eb2a7689dfc81458508f7 + Swinject: 82cdb851f63f91bba974e3eca1d69780f2f7677e + SwinjectStoryboard: 688f096033103e66ffcf6ca678211acd7d7be505 + +PODFILE CHECKSUM: e07856620ae84e1db1a6b49e1cbfbe41a53da4cf + +COCOAPODS: 1.5.3 diff --git a/README.md b/README.md new file mode 100644 index 0000000..16b425d --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# Weather +Тестовое приложение, показывающее прогноз погоды diff --git a/Rambafile b/Rambafile new file mode 100644 index 0000000..da8ce4d --- /dev/null +++ b/Rambafile @@ -0,0 +1,25 @@ +### Headers settings +company: Home + +### Xcode project settings +project_name: Weather +xcodeproj_path: Weather.xcodeproj + +### Code generation settings section +# The main project target name +project_target: Weather + +# The file path for new modules +project_file_path: Weather/Modules + +# The Xcode group path to new modules +project_group_path: Weather/Modules + +### Templates +templates: +- {name: rviper_controller} +- {name: mvvm_controller} +- {name: swifty_viper} + +templates: +- {name: viperSwift, local: 'viperSwift'} diff --git a/RxViper/Code/Assembly/assemblycontainer.swift.liquid b/RxViper/Code/Assembly/assemblycontainer.swift.liquid new file mode 100755 index 0000000..a37dbcd --- /dev/null +++ b/RxViper/Code/Assembly/assemblycontainer.swift.liquid @@ -0,0 +1,38 @@ +// +// {{ prefix }}{{ module_info.name }}{{ module_info.file_name }} +// {{ module_info.project_name }} +// +// Created by {{ developer.name }} on {{ date }}. +// Copyright © {{ year }} {{ developer.company }}. All rights reserved. +// + +import Swinject +import SwinjectStoryboard + +final class {{ module_info.name }}AssemblyContainer: Assembly { + + func assemble(container: Container) { + container.register({{ module_info.name }}InteractorProtocol.self) { resolver in + let interactor = {{ module_info.name }}Interactor() + return interactor + } + + container.register({{ module_info.name }}RouterProtocol.self) { (resolver, viewController: {{ module_info.name }}ViewController) in + let router = {{ module_info.name }}Router() + return router + } + + container.register({{ module_info.name }}Presenter.self) { (resolver, viewController: {{ module_info.name }}ViewController) in + let presenter = {{ module_info.name }}Presenter() + presenter.view = viewController + presenter.interactor = resolver.resolve({{ module_info.name }}InteractorProtocol.self) + presenter.router = resolver.resolve({{ module_info.name }}RouterProtocol.self, argument: viewController) + return presenter + } + + container.storyboardInitCompleted({{ module_info.name }}ViewController.self) { resolver, viewController in + let presenter = resolver.resolve({{ module_info.name }}Presenter.self, argument: viewController)! + viewController.setPresenter(presenter) + } + } +} \ No newline at end of file diff --git a/RxViper/Code/Interactor/interactor.swift.liquid b/RxViper/Code/Interactor/interactor.swift.liquid new file mode 100755 index 0000000..9f807ff --- /dev/null +++ b/RxViper/Code/Interactor/interactor.swift.liquid @@ -0,0 +1,17 @@ +// +// {{ prefix }}{{ module_info.name }}{{ module_info.file_name }} +// {{ module_info.project_name }} +// +// Created by {{ developer.name }} on {{ date }}. +// Copyright © {{ year }} {{ developer.company }}. All rights reserved. +// + +import RxCocoa +import RxSwift + +final class {{ module_info.name }}Interactor: {{ module_info.name }}InteractorProtocol { + + // MARK: - Dependencies + + // MARK: - {{ module_info.name }}InteractorProtocol +} \ No newline at end of file diff --git a/RxViper/Code/Interactor/interactor_protocol.swift.liquid b/RxViper/Code/Interactor/interactor_protocol.swift.liquid new file mode 100644 index 0000000..c77ce96 --- /dev/null +++ b/RxViper/Code/Interactor/interactor_protocol.swift.liquid @@ -0,0 +1,14 @@ +// +// {{ prefix }}{{ module_info.name }}{{ module_info.file_name }} +// {{ module_info.project_name }} +// +// Created by {{ developer.name }} on {{ date }}. +// Copyright © {{ year }} {{ developer.company }}. All rights reserved. +// + +import RxCocoa +import RxSwift + +protocol {{ module_info.name }}InteractorProtocol: class { + +} diff --git a/RxViper/Code/Presenter/module_input.swift.liquid b/RxViper/Code/Presenter/module_input.swift.liquid new file mode 100755 index 0000000..d8275f2 --- /dev/null +++ b/RxViper/Code/Presenter/module_input.swift.liquid @@ -0,0 +1,11 @@ +// +// {{ module_info.name }}{{ module_info.file_name }} +// {{ module_info.project_name }} +// +// Created by {{ developer.name }} on {{ date }}. +// Copyright © {{ year }} {{ developer.company }}. All rights reserved. +// + +protocol {{ module_info.name }}ModuleInput: class { + +} diff --git a/RxViper/Code/Presenter/presenter.swift.liquid b/RxViper/Code/Presenter/presenter.swift.liquid new file mode 100755 index 0000000..204026c --- /dev/null +++ b/RxViper/Code/Presenter/presenter.swift.liquid @@ -0,0 +1,32 @@ +// +// {{ module_info.name }}{{ module_info.file_name }} +// {{ module_info.project_name }} +// +// Created by {{ developer.name }} on {{ date }}. +// Copyright © {{ year }} {{ developer.company }}. All rights reserved. +// + +import RxCocoa +import RxSwift + +final class {{ module_info.name }}Presenter { + + // MARK: - Properties + var interactor: {{ module_info.name }}InteractorProtocol! + var router: {{ module_info.name }}RouterProtocol! + weak var view: {{ module_info.name }}ViewProtocol? + + // MARK: - Private + private let disposeBag = DisposeBag() +} + +// MARK: - {{ module_info.name }}PesenterProtocol +extension {{ module_info.name }}Presenter: {{ module_info.name }}PresenterProtocol { + + func setupBindings(_ view: {{ module_info.name }}ViewProtocol) { + } +} + +// MARK: - {{ module_info.name }}ModuleInput +extension {{ module_info.name }}Presenter: {{ module_info.name }}ModuleInput { +} diff --git a/RxViper/Code/Presenter/presenter_protocol.swift.liquid b/RxViper/Code/Presenter/presenter_protocol.swift.liquid new file mode 100644 index 0000000..490d773 --- /dev/null +++ b/RxViper/Code/Presenter/presenter_protocol.swift.liquid @@ -0,0 +1,12 @@ +// +// {{ module_info.name }}{{ module_info.file_name }} +// {{ module_info.project_name }} +// +// Created by {{ developer.name }} on {{ date }}. +// Copyright © {{ year }} {{ developer.company }}. All rights reserved. +// + +protocol {{ module_info.name }}PresenterProtocol { + + func setupBindings(_ view: {{ module_info.name }}ViewProtocol) +} diff --git a/RxViper/Code/Router/router.swift.liquid b/RxViper/Code/Router/router.swift.liquid new file mode 100755 index 0000000..93eb6fd --- /dev/null +++ b/RxViper/Code/Router/router.swift.liquid @@ -0,0 +1,11 @@ +// +// {{ module_info.name }}{{ module_info.file_name }} +// {{ module_info.project_name }} +// +// Created by {{ developer.name }} on {{ date }}. +// Copyright © {{ year }} {{ developer.company }}. All rights reserved. +// + +final class {{ module_info.name }}Router: {{ module_info.name }}RouterProtocol { + +} diff --git a/RxViper/Code/Router/router_protocol.swift.liquid b/RxViper/Code/Router/router_protocol.swift.liquid new file mode 100755 index 0000000..6d52318 --- /dev/null +++ b/RxViper/Code/Router/router_protocol.swift.liquid @@ -0,0 +1,13 @@ +// +// {{ module_info.name }}{{ module_info.file_name }} +// {{ module_info.project_name }} +// +// Created by {{ developer.name }} on {{ date }}. +// Copyright © {{ year }} {{ developer.company }}. All rights reserved. +// + +import Foundation + +protocol {{ module_info.name }}RouterProtocol: class { + +} diff --git a/RxViper/Code/View/view_protocol.swift.liquid b/RxViper/Code/View/view_protocol.swift.liquid new file mode 100644 index 0000000..96ca39b --- /dev/null +++ b/RxViper/Code/View/view_protocol.swift.liquid @@ -0,0 +1,17 @@ +// +// {{ module_info.name }}{{ module_info.file_name }} +// {{ module_info.project_name }} +// +// Created by {{ developer.name }} on {{ date }}. +// Copyright © {{ year }} {{ developer.company }}. All rights reserved. +// + +import RxCocoa +import RxSwift + +protocol {{ module_info.name }}ViewProtocol: class { + + // MARK: - Input + + // MARK: - Output +} diff --git a/RxViper/Code/View/viewcontroller.swift.liquid b/RxViper/Code/View/viewcontroller.swift.liquid new file mode 100755 index 0000000..8e2aeda --- /dev/null +++ b/RxViper/Code/View/viewcontroller.swift.liquid @@ -0,0 +1,38 @@ +// +// {{ module_info.name }}{{ module_info.file_name }} +// {{ module_info.project_name }} +// +// Created by {{ developer.name }} on {{ date }}. +// Copyright © {{ year }} {{ developer.company }}. All rights reserved. +// + +import UIKit +import RxCocoa +import RxSwift + +final class {{ module_info.name }}ViewController: UIViewController { + + // MARK: - Outlets + + // MARK: - Public + func setPresenter(_ presenter: {{ module_info.name }}PresenterProtocol) { + self.presenter = presenter + } + + // MARK: - Life cycle + override func viewDidLoad() { + super.viewDidLoad() + presenter?.setupBindings(self) + } + + // MARK: - Private + private var presenter: {{ module_info.name }}PresenterProtocol? +} + +// MARK: - {{ module_info.name }}ViewInput +extension {{ module_info.name }}ViewController: {{ module_info.name }}ViewProtocol { + + func setupInitialState() { + } +} + diff --git a/RxViper/RxViper.rambaspec b/RxViper/RxViper.rambaspec new file mode 100755 index 0000000..aec2f39 --- /dev/null +++ b/RxViper/RxViper.rambaspec @@ -0,0 +1,29 @@ +# Template information section +name: "viperSwiftRx" +summary: "ViperModule with Swinject & RxSwift" +author: "Sergey V. Krupov" +version: "0.1.2" +license: "MIT" + +# The declarations for code files + +code_files: +# Assembly +- {name: Assembly/AssemblyContainer.swift, path: Code/Assembly/assemblycontainer.swift.liquid} + +# View layer +- {name: View/ViewController.swift, path: Code/View/viewcontroller.swift.liquid} +- {name: View/ViewProtocol.swift, path: Code/View/view_protocol.swift.liquid} + +# Presenter layer +- {name: Presenter/ModuleInput.swift, path: Code/Presenter/module_input.swift.liquid} +- {name: Presenter/Presenter.swift, path: Code/Presenter/presenter.swift.liquid} +- {name: Presenter/PresenterProtocol.swift, path: Code/Presenter/presenter_protocol.swift.liquid} + +# Interactor layer +- {name: Interactor/InteractorProtocol.swift, path: Code/Interactor/interactor_protocol.swift.liquid} +- {name: Interactor/Interactor.swift, path: Code/Interactor/interactor.swift.liquid} + +# Router layer +- {name: Router/RouterProtocol.swift, path: Code/Router/router_protocol.swift.liquid} +- {name: Router/Router.swift, path: Code/Router/router.swift.liquid} diff --git a/Weather.xcodeproj/project.pbxproj b/Weather.xcodeproj/project.pbxproj index 1a7b81a..5de3916 100644 --- a/Weather.xcodeproj/project.pbxproj +++ b/Weather.xcodeproj/project.pbxproj @@ -7,12 +7,77 @@ objects = { /* Begin PBXBuildFile section */ + 006DB9A065C1CA46500142A1 /* MainPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD1ADE96DCB61DB76CE378D7 /* MainPresenter.swift */; }; + 09AB02CB8B629AA9704EFB7E /* SettingsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 757FFF6FDAF03CEC7C661F9B /* SettingsRouter.swift */; }; + 0C3D1E6453F92226F941ECFA /* RootRouterProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EA54BBA8ECC99BCB65A3920 /* RootRouterProtocol.swift */; }; + 117ADB173EF54AF05477DAE4 /* ForecastPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D774BE9C0BC9FE431B693B7A /* ForecastPresenter.swift */; }; + 2072A2AD181B207EEEC0FC36 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71725D6D137BDE88FCC05CAE /* MainViewController.swift */; }; + 2A8938784AB747645D1F0D70 /* MainModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC7AD71D6D4B648D380B46C9 /* MainModuleInput.swift */; }; + 2DDCA54FF830B71BEF49D713 /* RootInteractorProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B41FBF9DD373DE6180E79571 /* RootInteractorProtocol.swift */; }; + 2E79E308652298F6F8985E29 /* RootRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94BBF25345413B2FC1196E95 /* RootRouter.swift */; }; + 30D85DBBB8550DBA9C5939C5 /* RootModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = C790210476F83745C1EB66DC /* RootModuleInput.swift */; }; + 3A354C154EDC732288CA1AA6 /* MainRouterProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8666B7D50994A67CBA328E2 /* MainRouterProtocol.swift */; }; + 3B059344697AA9B9A4B860FA /* SettingsAssemblyContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FFAA6447906EF9D1AA79746 /* SettingsAssemblyContainer.swift */; }; + 44D29A98F0B5DCB1560BF743 /* Pods_WeatherTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03BB9D1BA32CC0D8DEF98EA3 /* Pods_WeatherTests.framework */; }; + 499BE77931D09DA7AEB4A781 /* ForecastAssemblyContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1476AC3400AFFA07ACC2F5F8 /* ForecastAssemblyContainer.swift */; }; + 58815EB0C695A513E9AF40EF /* ForecastInteractorProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95AF42257167128E914BBB8E /* ForecastInteractorProtocol.swift */; }; + 5AC66E084CFAAC1A1AD32335 /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0E6EE7AE29CF927798F39CD /* SettingsViewController.swift */; }; + 63E9FC28AF76275F86571E06 /* RootPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 071AD597BA5EEAD6FA3EBBDE /* RootPresenter.swift */; }; + 6467B37621D34B9B7E7B9625 /* RootViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96D423C31853981F02AA0154 /* RootViewController.swift */; }; + 6A0F8A803FD49AF1560D99DF /* ForecastInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 736ECFB054B23D8BE23F9DB8 /* ForecastInteractor.swift */; }; + 6E264E7665975DEED2ABC927 /* RootAssemblyContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C61E09AA03BD04C093442DF /* RootAssemblyContainer.swift */; }; + 781645B6B09CA7A4A8D35BC2 /* MainAssemblyContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DA97BED45186AD523E7F325 /* MainAssemblyContainer.swift */; }; + 793B2B42A883F924AE7C2FC8 /* SettingsInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4249FEE5F13036A534EF1327 /* SettingsInteractor.swift */; }; + 85DA8E6C3BC1B5EDD428D079 /* MainRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA3FF49282529BAF3C70C576 /* MainRouter.swift */; }; + 88F146F7F1ED02E31C450B57 /* SettingsInteractorProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F6182D635523DBC148322CA /* SettingsInteractorProtocol.swift */; }; + 898B3286578E6B18088D3308 /* SettingsViewProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = E685F1B61CCA8AC4D3CB5B86 /* SettingsViewProtocol.swift */; }; + 8AE316B93B8254AD75BEC35C /* RootViewProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CF8D19C67D3AC92B0F9B4B7 /* RootViewProtocol.swift */; }; + 970195C8D54BD4946B0DF592 /* SettingsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2915E93CEC5978555412EA9 /* SettingsModuleInput.swift */; }; + 9D31BE73A5EA5A23B7BB3BAF /* SettingsRouterProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69EA0CC9873473125A669348 /* SettingsRouterProtocol.swift */; }; + A09304581BE7E8B9D0C6698A /* SettingsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F96FCC6485C351AC595D49A4 /* SettingsPresenter.swift */; }; + A503394C22034D8200659545 /* Cities.json in Resources */ = {isa = PBXBuildFile; fileRef = A503394B22034D8200659545 /* Cities.json */; }; + A503FF0622007C44003C15CA /* SettingsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = A503FF0522007C44003C15CA /* SettingsService.swift */; }; + A503FF0B22007E14003C15CA /* City.swift in Sources */ = {isa = PBXBuildFile; fileRef = A503FF0A22007E14003C15CA /* City.swift */; }; + A503FF0D22007FCF003C15CA /* SettingsServiceAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = A503FF0C22007FCF003C15CA /* SettingsServiceAssembly.swift */; }; + A503FF0F220166EE003C15CA /* Root.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A503FF0E220166EE003C15CA /* Root.storyboard */; }; + A503FF1122016882003C15CA /* Forecast.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A503FF1022016882003C15CA /* Forecast.storyboard */; }; + A503FF13220168B9003C15CA /* Settings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A503FF12220168B9003C15CA /* Settings.storyboard */; }; + A503FF152201A034003C15CA /* Icons.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A503FF142201A034003C15CA /* Icons.xcassets */; }; + A503FF192202B529003C15CA /* WeatherItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = A503FF182202B529003C15CA /* WeatherItem.swift */; }; + A503FF1C2202B68B003C15CA /* ForecastItemCellTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A503FF1A2202B68B003C15CA /* ForecastItemCellTableViewCell.swift */; }; + A503FF1D2202B68B003C15CA /* ForecastItemCellTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = A503FF1B2202B68B003C15CA /* ForecastItemCellTableViewCell.xib */; }; + A503FF222202D2D6003C15CA /* SettingsCityCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A503FF202202D2D6003C15CA /* SettingsCityCell.swift */; }; + A503FF232202D2D6003C15CA /* SettingsCityCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = A503FF212202D2D6003C15CA /* SettingsCityCell.xib */; }; + A503FF262202D32D003C15CA /* CityItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = A503FF252202D32D003C15CA /* CityItem.swift */; }; + A503FF282202D47C003C15CA /* CitiesSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = A503FF272202D47C003C15CA /* CitiesSection.swift */; }; + A503FF2B2202FB72003C15CA /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = A503FF2A2202FB72003C15CA /* Utils.swift */; }; + A5A5E1FF21FF033500A2059E /* SwinjectStoryboard+Setup.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5A5E1FE21FF033500A2059E /* SwinjectStoryboard+Setup.swift */; }; + A5A5E20221FF19B300A2059E /* R.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5A5E20121FF19B300A2059E /* R.generated.swift */; }; + A5A5E20721FF1AF300A2059E /* WeatherService.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5A5E20621FF1AF300A2059E /* WeatherService.swift */; }; + A5A5E20921FF1C2800A2059E /* NetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5A5E20821FF1C2800A2059E /* NetworkService.swift */; }; + A5A5E20C21FF241400A2059E /* Weather.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5A5E20B21FF241400A2059E /* Weather.swift */; }; + A5A5E20E21FF2A2200A2059E /* ApiResponses.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5A5E20D21FF2A2200A2059E /* ApiResponses.swift */; }; + A5A5E21021FF2F0000A2059E /* NetworkServiceAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5A5E20F21FF2F0000A2059E /* NetworkServiceAssembly.swift */; }; + A5A5E21221FF302B00A2059E /* WeatherServiceAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5A5E21121FF302B00A2059E /* WeatherServiceAssembly.swift */; }; + A5BA73CD220022E00099641D /* MainPresenterProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5BA73CC220022E00099641D /* MainPresenterProtocol.swift */; }; A5EE267921FED57C00618447 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5EE267821FED57C00618447 /* AppDelegate.swift */; }; - A5EE267B21FED57C00618447 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5EE267A21FED57C00618447 /* ViewController.swift */; }; A5EE267E21FED57C00618447 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A5EE267C21FED57C00618447 /* Main.storyboard */; }; A5EE268021FED57E00618447 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A5EE267F21FED57E00618447 /* Assets.xcassets */; }; A5EE268321FED57E00618447 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A5EE268121FED57E00618447 /* LaunchScreen.storyboard */; }; A5EE268E21FED57E00618447 /* WeatherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5EE268D21FED57E00618447 /* WeatherTests.swift */; }; + A9093C67C67A19ABDB8A8470 /* ForecastViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 155293F6A8DE6CA58CB9A477 /* ForecastViewController.swift */; }; + B11069CE8301CF288FC9C33A /* ForecastRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E998DC5ED738939E69DF61AA /* ForecastRouter.swift */; }; + B2F8B20DEB11FF97C120826B /* ForecastPresenterProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FDF753ED86E521A10443113 /* ForecastPresenterProtocol.swift */; }; + BCCB02966EAA32758D46515F /* MainViewProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 578F3D3E332A7D7B35D4434B /* MainViewProtocol.swift */; }; + C3A36ED60E4FB24BAD6E08EB /* ForecastModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E8C2051080907DE3DA8E131 /* ForecastModuleInput.swift */; }; + C4D0A5E098AF865E28D0EB6F /* SettingsPresenterProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC6A4FA75B92A88DA32D618C /* SettingsPresenterProtocol.swift */; }; + C9234DF481BE3E0C46964F46 /* Pods_Weather.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C36A94B916E852EBB4E6636 /* Pods_Weather.framework */; }; + CA4755BDA0CB30CA0B1FE240 /* MainInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D69010E35AA4E1D3BC7B56BF /* MainInteractor.swift */; }; + CF7E8E383F79CDA642CE74C4 /* RootPresenterProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29173DE0924DBD205F0E6033 /* RootPresenterProtocol.swift */; }; + D472251FE5427B2E7189F74C /* ForecastRouterProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF86011D35240501ADD7CF54 /* ForecastRouterProtocol.swift */; }; + DC8C1911CB3C8F8C000AEA76 /* MainInteractorProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EF9A17CFF0162313238A56D /* MainInteractorProtocol.swift */; }; + E933B27929CECFC35EC20CD8 /* RootInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B384465FCA28308B340E85C /* RootInteractor.swift */; }; + FC39B811B4AD39407D1CEC4E /* ForecastViewProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5AF56FA7E16FA3001F8838D /* ForecastViewProtocol.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -26,9 +91,60 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 03BB9D1BA32CC0D8DEF98EA3 /* Pods_WeatherTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_WeatherTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 071AD597BA5EEAD6FA3EBBDE /* RootPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = RootPresenter.swift; sourceTree = ""; }; + 0C36A94B916E852EBB4E6636 /* Pods_Weather.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Weather.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 1476AC3400AFFA07ACC2F5F8 /* ForecastAssemblyContainer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ForecastAssemblyContainer.swift; sourceTree = ""; }; + 155293F6A8DE6CA58CB9A477 /* ForecastViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ForecastViewController.swift; sourceTree = ""; }; + 1EA54BBA8ECC99BCB65A3920 /* RootRouterProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = RootRouterProtocol.swift; sourceTree = ""; }; + 1F6182D635523DBC148322CA /* SettingsInteractorProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SettingsInteractorProtocol.swift; sourceTree = ""; }; + 29173DE0924DBD205F0E6033 /* RootPresenterProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = RootPresenterProtocol.swift; sourceTree = ""; }; + 2DA97BED45186AD523E7F325 /* MainAssemblyContainer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MainAssemblyContainer.swift; sourceTree = ""; }; + 4249FEE5F13036A534EF1327 /* SettingsInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SettingsInteractor.swift; sourceTree = ""; }; + 4B384465FCA28308B340E85C /* RootInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = RootInteractor.swift; sourceTree = ""; }; + 4FFAA6447906EF9D1AA79746 /* SettingsAssemblyContainer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SettingsAssemblyContainer.swift; sourceTree = ""; }; + 578F3D3E332A7D7B35D4434B /* MainViewProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MainViewProtocol.swift; sourceTree = ""; }; + 5CF8D19C67D3AC92B0F9B4B7 /* RootViewProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = RootViewProtocol.swift; sourceTree = ""; }; + 5E8C2051080907DE3DA8E131 /* ForecastModuleInput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ForecastModuleInput.swift; sourceTree = ""; }; + 6738335F37486B828CF3305E /* Pods-Weather.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Weather.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Weather/Pods-Weather.debug.xcconfig"; sourceTree = ""; }; + 69E55FA44A8347B7197A8DAC /* Pods-Weather.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Weather.release.xcconfig"; path = "Pods/Target Support Files/Pods-Weather/Pods-Weather.release.xcconfig"; sourceTree = ""; }; + 69EA0CC9873473125A669348 /* SettingsRouterProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SettingsRouterProtocol.swift; sourceTree = ""; }; + 71725D6D137BDE88FCC05CAE /* MainViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = ""; }; + 736ECFB054B23D8BE23F9DB8 /* ForecastInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ForecastInteractor.swift; sourceTree = ""; }; + 757FFF6FDAF03CEC7C661F9B /* SettingsRouter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SettingsRouter.swift; sourceTree = ""; }; + 7C61E09AA03BD04C093442DF /* RootAssemblyContainer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = RootAssemblyContainer.swift; sourceTree = ""; }; + 7FDF753ED86E521A10443113 /* ForecastPresenterProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ForecastPresenterProtocol.swift; sourceTree = ""; }; + 94BBF25345413B2FC1196E95 /* RootRouter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = RootRouter.swift; sourceTree = ""; }; + 95AF42257167128E914BBB8E /* ForecastInteractorProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ForecastInteractorProtocol.swift; sourceTree = ""; }; + 96D423C31853981F02AA0154 /* RootViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = RootViewController.swift; sourceTree = ""; }; + 9EF9A17CFF0162313238A56D /* MainInteractorProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MainInteractorProtocol.swift; sourceTree = ""; }; + A503394B22034D8200659545 /* Cities.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = Cities.json; sourceTree = ""; }; + A503FF0522007C44003C15CA /* SettingsService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsService.swift; sourceTree = ""; }; + A503FF0A22007E14003C15CA /* City.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = City.swift; sourceTree = ""; }; + A503FF0C22007FCF003C15CA /* SettingsServiceAssembly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsServiceAssembly.swift; sourceTree = ""; }; + A503FF0E220166EE003C15CA /* Root.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Root.storyboard; sourceTree = ""; }; + A503FF1022016882003C15CA /* Forecast.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Forecast.storyboard; sourceTree = ""; }; + A503FF12220168B9003C15CA /* Settings.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Settings.storyboard; sourceTree = ""; }; + A503FF142201A034003C15CA /* Icons.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Icons.xcassets; sourceTree = ""; }; + A503FF182202B529003C15CA /* WeatherItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherItem.swift; sourceTree = ""; }; + A503FF1A2202B68B003C15CA /* ForecastItemCellTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForecastItemCellTableViewCell.swift; sourceTree = ""; }; + A503FF1B2202B68B003C15CA /* ForecastItemCellTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ForecastItemCellTableViewCell.xib; sourceTree = ""; }; + A503FF202202D2D6003C15CA /* SettingsCityCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsCityCell.swift; sourceTree = ""; }; + A503FF212202D2D6003C15CA /* SettingsCityCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SettingsCityCell.xib; sourceTree = ""; }; + A503FF252202D32D003C15CA /* CityItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CityItem.swift; sourceTree = ""; }; + A503FF272202D47C003C15CA /* CitiesSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CitiesSection.swift; sourceTree = ""; }; + A503FF2A2202FB72003C15CA /* Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = ""; }; + A5A5E1FE21FF033500A2059E /* SwinjectStoryboard+Setup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SwinjectStoryboard+Setup.swift"; sourceTree = ""; }; + A5A5E20121FF19B300A2059E /* R.generated.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = R.generated.swift; sourceTree = ""; }; + A5A5E20621FF1AF300A2059E /* WeatherService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherService.swift; sourceTree = ""; }; + A5A5E20821FF1C2800A2059E /* NetworkService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkService.swift; sourceTree = ""; }; + A5A5E20B21FF241400A2059E /* Weather.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Weather.swift; sourceTree = ""; }; + A5A5E20D21FF2A2200A2059E /* ApiResponses.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiResponses.swift; sourceTree = ""; }; + A5A5E20F21FF2F0000A2059E /* NetworkServiceAssembly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkServiceAssembly.swift; sourceTree = ""; }; + A5A5E21121FF302B00A2059E /* WeatherServiceAssembly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherServiceAssembly.swift; sourceTree = ""; }; + A5BA73CC220022E00099641D /* MainPresenterProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainPresenterProtocol.swift; sourceTree = ""; }; A5EE267521FED57C00618447 /* Weather.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Weather.app; sourceTree = BUILT_PRODUCTS_DIR; }; A5EE267821FED57C00618447 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - A5EE267A21FED57C00618447 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; A5EE267D21FED57C00618447 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; A5EE267F21FED57E00618447 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; A5EE268221FED57E00618447 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; @@ -36,6 +152,24 @@ A5EE268921FED57E00618447 /* WeatherTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = WeatherTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; A5EE268D21FED57E00618447 /* WeatherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherTests.swift; sourceTree = ""; }; A5EE268F21FED57E00618447 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + AD1ADE96DCB61DB76CE378D7 /* MainPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MainPresenter.swift; sourceTree = ""; }; + B41FBF9DD373DE6180E79571 /* RootInteractorProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = RootInteractorProtocol.swift; sourceTree = ""; }; + B6395620A61D55DD7CFA9BA3 /* Pods-WeatherTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WeatherTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-WeatherTests/Pods-WeatherTests.release.xcconfig"; sourceTree = ""; }; + C0E6EE7AE29CF927798F39CD /* SettingsViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = ""; }; + C5B0A54CAA8FAA068B0525A1 /* Pods-WeatherTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WeatherTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-WeatherTests/Pods-WeatherTests.debug.xcconfig"; sourceTree = ""; }; + C790210476F83745C1EB66DC /* RootModuleInput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = RootModuleInput.swift; sourceTree = ""; }; + C8666B7D50994A67CBA328E2 /* MainRouterProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MainRouterProtocol.swift; sourceTree = ""; }; + CA3FF49282529BAF3C70C576 /* MainRouter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MainRouter.swift; sourceTree = ""; }; + D2915E93CEC5978555412EA9 /* SettingsModuleInput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SettingsModuleInput.swift; sourceTree = ""; }; + D69010E35AA4E1D3BC7B56BF /* MainInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MainInteractor.swift; sourceTree = ""; }; + D774BE9C0BC9FE431B693B7A /* ForecastPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ForecastPresenter.swift; sourceTree = ""; }; + DC6A4FA75B92A88DA32D618C /* SettingsPresenterProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SettingsPresenterProtocol.swift; sourceTree = ""; }; + DC7AD71D6D4B648D380B46C9 /* MainModuleInput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MainModuleInput.swift; sourceTree = ""; }; + E685F1B61CCA8AC4D3CB5B86 /* SettingsViewProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SettingsViewProtocol.swift; sourceTree = ""; }; + E998DC5ED738939E69DF61AA /* ForecastRouter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ForecastRouter.swift; sourceTree = ""; }; + EF86011D35240501ADD7CF54 /* ForecastRouterProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ForecastRouterProtocol.swift; sourceTree = ""; }; + F5AF56FA7E16FA3001F8838D /* ForecastViewProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ForecastViewProtocol.swift; sourceTree = ""; }; + F96FCC6485C351AC595D49A4 /* SettingsPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SettingsPresenter.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -43,6 +177,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + C9234DF481BE3E0C46964F46 /* Pods_Weather.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -50,18 +185,285 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 44D29A98F0B5DCB1560BF743 /* Pods_WeatherTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 0ED154AF9A3E25CE41613337 /* View */ = { + isa = PBXGroup; + children = ( + A503FF0E220166EE003C15CA /* Root.storyboard */, + 96D423C31853981F02AA0154 /* RootViewController.swift */, + 5CF8D19C67D3AC92B0F9B4B7 /* RootViewProtocol.swift */, + ); + path = View; + sourceTree = ""; + }; + 1399F4B486CEF7B22A86F0F9 /* Pods */ = { + isa = PBXGroup; + children = ( + 6738335F37486B828CF3305E /* Pods-Weather.debug.xcconfig */, + 69E55FA44A8347B7197A8DAC /* Pods-Weather.release.xcconfig */, + C5B0A54CAA8FAA068B0525A1 /* Pods-WeatherTests.debug.xcconfig */, + B6395620A61D55DD7CFA9BA3 /* Pods-WeatherTests.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; + 1735C5817D169BB415B4912F /* Assembly */ = { + isa = PBXGroup; + children = ( + 4FFAA6447906EF9D1AA79746 /* SettingsAssemblyContainer.swift */, + ); + path = Assembly; + sourceTree = ""; + }; + 20FAC95DD92F177657CB26AF /* Presenter */ = { + isa = PBXGroup; + children = ( + C790210476F83745C1EB66DC /* RootModuleInput.swift */, + 071AD597BA5EEAD6FA3EBBDE /* RootPresenter.swift */, + 29173DE0924DBD205F0E6033 /* RootPresenterProtocol.swift */, + ); + path = Presenter; + sourceTree = ""; + }; + 221E45F93BEFC4F7B2FEB1FF /* Frameworks */ = { + isa = PBXGroup; + children = ( + 0C36A94B916E852EBB4E6636 /* Pods_Weather.framework */, + 03BB9D1BA32CC0D8DEF98EA3 /* Pods_WeatherTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 239F6A31881E0D237558D41E /* Assembly */ = { + isa = PBXGroup; + children = ( + 1476AC3400AFFA07ACC2F5F8 /* ForecastAssemblyContainer.swift */, + ); + path = Assembly; + sourceTree = ""; + }; + 437FF6E8C1CA79E355696A06 /* Assembly */ = { + isa = PBXGroup; + children = ( + 7C61E09AA03BD04C093442DF /* RootAssemblyContainer.swift */, + ); + path = Assembly; + sourceTree = ""; + }; + 46073904D49EA4889EF6FF16 /* Router */ = { + isa = PBXGroup; + children = ( + 1EA54BBA8ECC99BCB65A3920 /* RootRouterProtocol.swift */, + 94BBF25345413B2FC1196E95 /* RootRouter.swift */, + ); + path = Router; + sourceTree = ""; + }; + 54DD7061E508D533BA3ADD6D /* Settings */ = { + isa = PBXGroup; + children = ( + 1735C5817D169BB415B4912F /* Assembly */, + BD3F92DF0959FE0E340E2D68 /* View */, + 834842758FA59B37566C8E96 /* Presenter */, + F489FA8EBE5D017921C10AC7 /* Interactor */, + 879ADF32BFA29CFB0BEF3B49 /* Router */, + ); + path = Settings; + sourceTree = ""; + }; + 685A3CB8C4C26E5187AE988D /* View */ = { + isa = PBXGroup; + children = ( + A503FF1E2202B68F003C15CA /* Cells */, + A503FF1022016882003C15CA /* Forecast.storyboard */, + 155293F6A8DE6CA58CB9A477 /* ForecastViewController.swift */, + F5AF56FA7E16FA3001F8838D /* ForecastViewProtocol.swift */, + ); + path = View; + sourceTree = ""; + }; + 6935CE3134022C3A82DC52CF /* Interactor */ = { + isa = PBXGroup; + children = ( + B41FBF9DD373DE6180E79571 /* RootInteractorProtocol.swift */, + 4B384465FCA28308B340E85C /* RootInteractor.swift */, + ); + path = Interactor; + sourceTree = ""; + }; + 6EF8EFA4C52A33AECE748448 /* Interactor */ = { + isa = PBXGroup; + children = ( + D69010E35AA4E1D3BC7B56BF /* MainInteractor.swift */, + 9EF9A17CFF0162313238A56D /* MainInteractorProtocol.swift */, + ); + path = Interactor; + sourceTree = ""; + }; + 834842758FA59B37566C8E96 /* Presenter */ = { + isa = PBXGroup; + children = ( + A503FF242202D320003C15CA /* Models */, + D2915E93CEC5978555412EA9 /* SettingsModuleInput.swift */, + F96FCC6485C351AC595D49A4 /* SettingsPresenter.swift */, + DC6A4FA75B92A88DA32D618C /* SettingsPresenterProtocol.swift */, + ); + path = Presenter; + sourceTree = ""; + }; + 879ADF32BFA29CFB0BEF3B49 /* Router */ = { + isa = PBXGroup; + children = ( + 69EA0CC9873473125A669348 /* SettingsRouterProtocol.swift */, + 757FFF6FDAF03CEC7C661F9B /* SettingsRouter.swift */, + ); + path = Router; + sourceTree = ""; + }; + 8FB8BA8098907C6F02D70F64 /* Router */ = { + isa = PBXGroup; + children = ( + EF86011D35240501ADD7CF54 /* ForecastRouterProtocol.swift */, + E998DC5ED738939E69DF61AA /* ForecastRouter.swift */, + ); + path = Router; + sourceTree = ""; + }; + 91572A217143C18930A81BA4 /* Router */ = { + isa = PBXGroup; + children = ( + CA3FF49282529BAF3C70C576 /* MainRouter.swift */, + C8666B7D50994A67CBA328E2 /* MainRouterProtocol.swift */, + ); + path = Router; + sourceTree = ""; + }; + 91E95AC7D2146C6AA3B15393 /* Root */ = { + isa = PBXGroup; + children = ( + 437FF6E8C1CA79E355696A06 /* Assembly */, + 0ED154AF9A3E25CE41613337 /* View */, + 20FAC95DD92F177657CB26AF /* Presenter */, + 6935CE3134022C3A82DC52CF /* Interactor */, + 46073904D49EA4889EF6FF16 /* Router */, + ); + path = Root; + sourceTree = ""; + }; + A503FF0422007C1E003C15CA /* Settings */ = { + isa = PBXGroup; + children = ( + A503FF0522007C44003C15CA /* SettingsService.swift */, + A503FF0C22007FCF003C15CA /* SettingsServiceAssembly.swift */, + ); + path = Settings; + sourceTree = ""; + }; + A503FF0722007DB8003C15CA /* Resources */ = { + isa = PBXGroup; + children = ( + A503394B22034D8200659545 /* Cities.json */, + A503FF142201A034003C15CA /* Icons.xcassets */, + ); + path = Resources; + sourceTree = ""; + }; + A503FF172202B512003C15CA /* Models */ = { + isa = PBXGroup; + children = ( + A503FF182202B529003C15CA /* WeatherItem.swift */, + ); + path = Models; + sourceTree = ""; + }; + A503FF1E2202B68F003C15CA /* Cells */ = { + isa = PBXGroup; + children = ( + A503FF1A2202B68B003C15CA /* ForecastItemCellTableViewCell.swift */, + A503FF1B2202B68B003C15CA /* ForecastItemCellTableViewCell.xib */, + ); + path = Cells; + sourceTree = ""; + }; + A503FF1F2202D2BC003C15CA /* Cells */ = { + isa = PBXGroup; + children = ( + A503FF202202D2D6003C15CA /* SettingsCityCell.swift */, + A503FF212202D2D6003C15CA /* SettingsCityCell.xib */, + ); + path = Cells; + sourceTree = ""; + }; + A503FF242202D320003C15CA /* Models */ = { + isa = PBXGroup; + children = ( + A503FF252202D32D003C15CA /* CityItem.swift */, + A503FF272202D47C003C15CA /* CitiesSection.swift */, + ); + path = Models; + sourceTree = ""; + }; + A503FF292202FAD9003C15CA /* Utils */ = { + isa = PBXGroup; + children = ( + A503FF2A2202FB72003C15CA /* Utils.swift */, + ); + path = Utils; + sourceTree = ""; + }; + A5A5E20321FF1A5F00A2059E /* Services */ = { + isa = PBXGroup; + children = ( + A503FF0422007C1E003C15CA /* Settings */, + A5A5E20521FF1AC000A2059E /* Weather */, + A5A5E20421FF1A8400A2059E /* Network */, + ); + path = Services; + sourceTree = ""; + }; + A5A5E20421FF1A8400A2059E /* Network */ = { + isa = PBXGroup; + children = ( + A5A5E20821FF1C2800A2059E /* NetworkService.swift */, + A5A5E20F21FF2F0000A2059E /* NetworkServiceAssembly.swift */, + ); + path = Network; + sourceTree = ""; + }; + A5A5E20521FF1AC000A2059E /* Weather */ = { + isa = PBXGroup; + children = ( + A5A5E20D21FF2A2200A2059E /* ApiResponses.swift */, + A5A5E20621FF1AF300A2059E /* WeatherService.swift */, + A5A5E21121FF302B00A2059E /* WeatherServiceAssembly.swift */, + ); + path = Weather; + sourceTree = ""; + }; + A5A5E20A21FF1E2500A2059E /* Models */ = { + isa = PBXGroup; + children = ( + A5A5E20B21FF241400A2059E /* Weather.swift */, + A503FF0A22007E14003C15CA /* City.swift */, + ); + path = Models; + sourceTree = ""; + }; A5EE266C21FED57C00618447 = { isa = PBXGroup; children = ( + A5A5E20121FF19B300A2059E /* R.generated.swift */, A5EE267721FED57C00618447 /* Weather */, A5EE268C21FED57E00618447 /* WeatherTests */, A5EE267621FED57C00618447 /* Products */, + 1399F4B486CEF7B22A86F0F9 /* Pods */, + 221E45F93BEFC4F7B2FEB1FF /* Frameworks */, ); sourceTree = ""; }; @@ -77,12 +479,16 @@ A5EE267721FED57C00618447 /* Weather */ = { isa = PBXGroup; children = ( + A5EE268421FED57E00618447 /* Info.plist */, A5EE267821FED57C00618447 /* AppDelegate.swift */, - A5EE267A21FED57C00618447 /* ViewController.swift */, - A5EE267C21FED57C00618447 /* Main.storyboard */, + A5A5E1FE21FF033500A2059E /* SwinjectStoryboard+Setup.swift */, A5EE267F21FED57E00618447 /* Assets.xcassets */, A5EE268121FED57E00618447 /* LaunchScreen.storyboard */, - A5EE268421FED57E00618447 /* Info.plist */, + A5A5E20A21FF1E2500A2059E /* Models */, + A757766E748B4349679D37A0 /* Modules */, + A503FF0722007DB8003C15CA /* Resources */, + A5A5E20321FF1A5F00A2059E /* Services */, + A503FF292202FAD9003C15CA /* Utils */, ); path = Weather; sourceTree = ""; @@ -96,6 +502,109 @@ path = WeatherTests; sourceTree = ""; }; + A757766E748B4349679D37A0 /* Modules */ = { + isa = PBXGroup; + children = ( + DB4DEA5EAC60D4F14F8ABAE4 /* Main */, + 91E95AC7D2146C6AA3B15393 /* Root */, + C3A1C21B576621BC97FADA16 /* Forecast */, + 54DD7061E508D533BA3ADD6D /* Settings */, + ); + path = Modules; + sourceTree = ""; + }; + AD5158206C6A9B9401F12022 /* Interactor */ = { + isa = PBXGroup; + children = ( + 95AF42257167128E914BBB8E /* ForecastInteractorProtocol.swift */, + 736ECFB054B23D8BE23F9DB8 /* ForecastInteractor.swift */, + ); + path = Interactor; + sourceTree = ""; + }; + ADC5CF62F49F3488E4220AD3 /* Assembly */ = { + isa = PBXGroup; + children = ( + 2DA97BED45186AD523E7F325 /* MainAssemblyContainer.swift */, + ); + path = Assembly; + sourceTree = ""; + }; + BD3F92DF0959FE0E340E2D68 /* View */ = { + isa = PBXGroup; + children = ( + A503FF1F2202D2BC003C15CA /* Cells */, + A503FF12220168B9003C15CA /* Settings.storyboard */, + C0E6EE7AE29CF927798F39CD /* SettingsViewController.swift */, + E685F1B61CCA8AC4D3CB5B86 /* SettingsViewProtocol.swift */, + ); + path = View; + sourceTree = ""; + }; + C3A1C21B576621BC97FADA16 /* Forecast */ = { + isa = PBXGroup; + children = ( + 239F6A31881E0D237558D41E /* Assembly */, + 685A3CB8C4C26E5187AE988D /* View */, + E7084254A89819003E5EAAE1 /* Presenter */, + AD5158206C6A9B9401F12022 /* Interactor */, + 8FB8BA8098907C6F02D70F64 /* Router */, + ); + path = Forecast; + sourceTree = ""; + }; + CC74F3EA32A265625AE5DCD3 /* Presenter */ = { + isa = PBXGroup; + children = ( + DC7AD71D6D4B648D380B46C9 /* MainModuleInput.swift */, + AD1ADE96DCB61DB76CE378D7 /* MainPresenter.swift */, + A5BA73CC220022E00099641D /* MainPresenterProtocol.swift */, + ); + path = Presenter; + sourceTree = ""; + }; + DB4DEA5EAC60D4F14F8ABAE4 /* Main */ = { + isa = PBXGroup; + children = ( + ADC5CF62F49F3488E4220AD3 /* Assembly */, + EA851B66B24AF8B13EB4B122 /* View */, + CC74F3EA32A265625AE5DCD3 /* Presenter */, + 6EF8EFA4C52A33AECE748448 /* Interactor */, + 91572A217143C18930A81BA4 /* Router */, + ); + path = Main; + sourceTree = ""; + }; + E7084254A89819003E5EAAE1 /* Presenter */ = { + isa = PBXGroup; + children = ( + A503FF172202B512003C15CA /* Models */, + 5E8C2051080907DE3DA8E131 /* ForecastModuleInput.swift */, + D774BE9C0BC9FE431B693B7A /* ForecastPresenter.swift */, + 7FDF753ED86E521A10443113 /* ForecastPresenterProtocol.swift */, + ); + path = Presenter; + sourceTree = ""; + }; + EA851B66B24AF8B13EB4B122 /* View */ = { + isa = PBXGroup; + children = ( + A5EE267C21FED57C00618447 /* Main.storyboard */, + 71725D6D137BDE88FCC05CAE /* MainViewController.swift */, + 578F3D3E332A7D7B35D4434B /* MainViewProtocol.swift */, + ); + path = View; + sourceTree = ""; + }; + F489FA8EBE5D017921C10AC7 /* Interactor */ = { + isa = PBXGroup; + children = ( + 1F6182D635523DBC148322CA /* SettingsInteractorProtocol.swift */, + 4249FEE5F13036A534EF1327 /* SettingsInteractor.swift */, + ); + path = Interactor; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -103,9 +612,13 @@ isa = PBXNativeTarget; buildConfigurationList = A5EE269221FED57E00618447 /* Build configuration list for PBXNativeTarget "Weather" */; buildPhases = ( + 635337CBA82DE715A2D8D618 /* [CP] Check Pods Manifest.lock */, + A5A5E20021FF194000A2059E /* ShellScript */, A5EE267121FED57C00618447 /* Sources */, A5EE267221FED57C00618447 /* Frameworks */, A5EE267321FED57C00618447 /* Resources */, + 8A802A784D011EDFAB8D46EE /* [CP] Embed Pods Frameworks */, + A534B16E22032C5E00077EC5 /* ShellScript */, ); buildRules = ( ); @@ -120,6 +633,7 @@ isa = PBXNativeTarget; buildConfigurationList = A5EE269521FED57E00618447 /* Build configuration list for PBXNativeTarget "WeatherTests" */; buildPhases = ( + C4028A9031F281B2698C463F /* [CP] Check Pods Manifest.lock */, A5EE268521FED57E00618447 /* Sources */, A5EE268621FED57E00618447 /* Frameworks */, A5EE268721FED57E00618447 /* Resources */, @@ -177,9 +691,16 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + A503FF0F220166EE003C15CA /* Root.storyboard in Resources */, + A503FF1122016882003C15CA /* Forecast.storyboard in Resources */, + A503394C22034D8200659545 /* Cities.json in Resources */, + A503FF232202D2D6003C15CA /* SettingsCityCell.xib in Resources */, A5EE268321FED57E00618447 /* LaunchScreen.storyboard in Resources */, A5EE268021FED57E00618447 /* Assets.xcassets in Resources */, + A503FF1D2202B68B003C15CA /* ForecastItemCellTableViewCell.xib in Resources */, A5EE267E21FED57C00618447 /* Main.storyboard in Resources */, + A503FF152201A034003C15CA /* Icons.xcassets in Resources */, + A503FF13220168B9003C15CA /* Settings.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -192,13 +713,190 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 635337CBA82DE715A2D8D618 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Weather-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 8A802A784D011EDFAB8D46EE /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-Weather/Pods-Weather-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework", + "${BUILT_PRODUCTS_DIR}/Differentiator/Differentiator.framework", + "${BUILT_PRODUCTS_DIR}/R.swift.Library/Rswift.framework", + "${BUILT_PRODUCTS_DIR}/RxAtomic/RxAtomic.framework", + "${BUILT_PRODUCTS_DIR}/RxCocoa/RxCocoa.framework", + "${BUILT_PRODUCTS_DIR}/RxDataSources/RxDataSources.framework", + "${BUILT_PRODUCTS_DIR}/RxSwift/RxSwift.framework", + "${BUILT_PRODUCTS_DIR}/Swinject/Swinject.framework", + "${BUILT_PRODUCTS_DIR}/SwinjectStoryboard/SwinjectStoryboard.framework", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + ); + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Differentiator.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Rswift.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxAtomic.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxCocoa.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxDataSources.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxSwift.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Swinject.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwinjectStoryboard.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Weather/Pods-Weather-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + A534B16E22032C5E00077EC5 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/SwiftLint/swiftlint\"\n"; + }; + A5A5E20021FF194000A2059E /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "$TEMP_DIR/rswift-lastrun", + ); + outputFileListPaths = ( + ); + outputPaths = ( + $SRCROOT/R.generated.swift, + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$PODS_ROOT/R.swift/rswift\" generate \"$SRCROOT/R.generated.swift\"\n"; + }; + C4028A9031F281B2698C463F /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-WeatherTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ A5EE267121FED57C00618447 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - A5EE267B21FED57C00618447 /* ViewController.swift in Sources */, + A503FF0D22007FCF003C15CA /* SettingsServiceAssembly.swift in Sources */, A5EE267921FED57C00618447 /* AppDelegate.swift in Sources */, + A5A5E20C21FF241400A2059E /* Weather.swift in Sources */, + A5A5E20221FF19B300A2059E /* R.generated.swift in Sources */, + 781645B6B09CA7A4A8D35BC2 /* MainAssemblyContainer.swift in Sources */, + A5A5E21221FF302B00A2059E /* WeatherServiceAssembly.swift in Sources */, + BCCB02966EAA32758D46515F /* MainViewProtocol.swift in Sources */, + 2072A2AD181B207EEEC0FC36 /* MainViewController.swift in Sources */, + 2A8938784AB747645D1F0D70 /* MainModuleInput.swift in Sources */, + 006DB9A065C1CA46500142A1 /* MainPresenter.swift in Sources */, + DC8C1911CB3C8F8C000AEA76 /* MainInteractorProtocol.swift in Sources */, + A503FF0622007C44003C15CA /* SettingsService.swift in Sources */, + A5BA73CD220022E00099641D /* MainPresenterProtocol.swift in Sources */, + A5A5E20921FF1C2800A2059E /* NetworkService.swift in Sources */, + A5A5E20721FF1AF300A2059E /* WeatherService.swift in Sources */, + CA4755BDA0CB30CA0B1FE240 /* MainInteractor.swift in Sources */, + A5A5E1FF21FF033500A2059E /* SwinjectStoryboard+Setup.swift in Sources */, + A503FF262202D32D003C15CA /* CityItem.swift in Sources */, + A5A5E21021FF2F0000A2059E /* NetworkServiceAssembly.swift in Sources */, + A5A5E20E21FF2A2200A2059E /* ApiResponses.swift in Sources */, + 3A354C154EDC732288CA1AA6 /* MainRouterProtocol.swift in Sources */, + 85DA8E6C3BC1B5EDD428D079 /* MainRouter.swift in Sources */, + A503FF282202D47C003C15CA /* CitiesSection.swift in Sources */, + A503FF0B22007E14003C15CA /* City.swift in Sources */, + 6E264E7665975DEED2ABC927 /* RootAssemblyContainer.swift in Sources */, + 6467B37621D34B9B7E7B9625 /* RootViewController.swift in Sources */, + 8AE316B93B8254AD75BEC35C /* RootViewProtocol.swift in Sources */, + 30D85DBBB8550DBA9C5939C5 /* RootModuleInput.swift in Sources */, + 63E9FC28AF76275F86571E06 /* RootPresenter.swift in Sources */, + A503FF192202B529003C15CA /* WeatherItem.swift in Sources */, + CF7E8E383F79CDA642CE74C4 /* RootPresenterProtocol.swift in Sources */, + 2DDCA54FF830B71BEF49D713 /* RootInteractorProtocol.swift in Sources */, + E933B27929CECFC35EC20CD8 /* RootInteractor.swift in Sources */, + 0C3D1E6453F92226F941ECFA /* RootRouterProtocol.swift in Sources */, + 2E79E308652298F6F8985E29 /* RootRouter.swift in Sources */, + 499BE77931D09DA7AEB4A781 /* ForecastAssemblyContainer.swift in Sources */, + A9093C67C67A19ABDB8A8470 /* ForecastViewController.swift in Sources */, + A503FF2B2202FB72003C15CA /* Utils.swift in Sources */, + FC39B811B4AD39407D1CEC4E /* ForecastViewProtocol.swift in Sources */, + C3A36ED60E4FB24BAD6E08EB /* ForecastModuleInput.swift in Sources */, + 117ADB173EF54AF05477DAE4 /* ForecastPresenter.swift in Sources */, + B2F8B20DEB11FF97C120826B /* ForecastPresenterProtocol.swift in Sources */, + 58815EB0C695A513E9AF40EF /* ForecastInteractorProtocol.swift in Sources */, + 6A0F8A803FD49AF1560D99DF /* ForecastInteractor.swift in Sources */, + D472251FE5427B2E7189F74C /* ForecastRouterProtocol.swift in Sources */, + B11069CE8301CF288FC9C33A /* ForecastRouter.swift in Sources */, + A503FF222202D2D6003C15CA /* SettingsCityCell.swift in Sources */, + 3B059344697AA9B9A4B860FA /* SettingsAssemblyContainer.swift in Sources */, + 5AC66E084CFAAC1A1AD32335 /* SettingsViewController.swift in Sources */, + 898B3286578E6B18088D3308 /* SettingsViewProtocol.swift in Sources */, + 970195C8D54BD4946B0DF592 /* SettingsModuleInput.swift in Sources */, + A09304581BE7E8B9D0C6698A /* SettingsPresenter.swift in Sources */, + C4D0A5E098AF865E28D0EB6F /* SettingsPresenterProtocol.swift in Sources */, + 88F146F7F1ED02E31C450B57 /* SettingsInteractorProtocol.swift in Sources */, + 793B2B42A883F924AE7C2FC8 /* SettingsInteractor.swift in Sources */, + 9D31BE73A5EA5A23B7BB3BAF /* SettingsRouterProtocol.swift in Sources */, + 09AB02CB8B629AA9704EFB7E /* SettingsRouter.swift in Sources */, + A503FF1C2202B68B003C15CA /* ForecastItemCellTableViewCell.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -358,6 +1056,7 @@ }; A5EE269321FED57E00618447 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 6738335F37486B828CF3305E /* Pods-Weather.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; @@ -375,6 +1074,7 @@ }; A5EE269421FED57E00618447 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 69E55FA44A8347B7197A8DAC /* Pods-Weather.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; @@ -392,6 +1092,7 @@ }; A5EE269621FED57E00618447 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = C5B0A54CAA8FAA068B0525A1 /* Pods-WeatherTests.debug.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; @@ -412,6 +1113,7 @@ }; A5EE269721FED57E00618447 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = B6395620A61D55DD7CFA9BA3 /* Pods-WeatherTests.release.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; diff --git a/Weather.xcworkspace/contents.xcworkspacedata b/Weather.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..71d6a2f --- /dev/null +++ b/Weather.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/Weather.xcodeproj/xcuserdata/sergey.xcuserdatad/xcschemes/xcschememanagement.plist b/Weather.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 54% rename from Weather.xcodeproj/xcuserdata/sergey.xcuserdatad/xcschemes/xcschememanagement.plist rename to Weather.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist index d1731a2..18d9810 100644 --- a/Weather.xcodeproj/xcuserdata/sergey.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Weather.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -2,13 +2,7 @@ - SchemeUserState - - Weather.xcscheme_^#shared#^_ - - orderHint - 0 - - + IDEDidComputeMac32BitWarning + diff --git a/Weather/AppDelegate.swift b/Weather/AppDelegate.swift index 9b6aa36..43af9c0 100644 --- a/Weather/AppDelegate.swift +++ b/Weather/AppDelegate.swift @@ -13,34 +13,23 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - + // swiftlint:disable:next line_length func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - // Override point for customization after application launch. return true } func applicationWillResignActive(_ application: UIApplication) { - // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. - // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. } func applicationDidEnterBackground(_ application: UIApplication) { - // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. - // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } func applicationWillEnterForeground(_ application: UIApplication) { - // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. } func applicationDidBecomeActive(_ application: UIApplication) { - // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } func applicationWillTerminate(_ application: UIApplication) { - // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } - - } - diff --git a/Weather/Base.lproj/Main.storyboard b/Weather/Base.lproj/Main.storyboard deleted file mode 100644 index f1bcf38..0000000 --- a/Weather/Base.lproj/Main.storyboard +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Weather/Info.plist b/Weather/Info.plist index 16be3b6..06c8dae 100644 --- a/Weather/Info.plist +++ b/Weather/Info.plist @@ -23,7 +23,7 @@ UILaunchStoryboardName LaunchScreen UIMainStoryboardFile - Main + Root UIRequiredDeviceCapabilities armv7 diff --git a/Weather/Models/City.swift b/Weather/Models/City.swift new file mode 100644 index 0000000..2e7f7ea --- /dev/null +++ b/Weather/Models/City.swift @@ -0,0 +1,13 @@ +// +// City.swift +// Weather +// +// Created by Sergey V. Krupov on 29.01.2019. +// Copyright © 2019 Sergey V. Krupov. All rights reserved. +// + +struct City: Decodable { + let id: Int + let name: String + let country: String +} diff --git a/Weather/Models/Weather.swift b/Weather/Models/Weather.swift new file mode 100644 index 0000000..f991867 --- /dev/null +++ b/Weather/Models/Weather.swift @@ -0,0 +1,20 @@ +// +// Weather.swift +// Weather +// +// Created by Sergey V. Krupov on 28.01.2019. +// Copyright © 2019 Sergey V. Krupov. All rights reserved. +// + +import Foundation + +struct Weather { + let temperature: Double + let minTemperature: Double + let maxTemperature: Double + let pressure: Double + let humidity: Double + let date: Date + let icon: String + let description: String +} diff --git a/Weather/Modules/Forecast/Assembly/ForecastAssemblyContainer.swift b/Weather/Modules/Forecast/Assembly/ForecastAssemblyContainer.swift new file mode 100644 index 0000000..13544a0 --- /dev/null +++ b/Weather/Modules/Forecast/Assembly/ForecastAssemblyContainer.swift @@ -0,0 +1,40 @@ +// +// ForecastForecastAssemblyContainer.swift +// Weather +// +// Created by Sergey V. Krupov on 30/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +import Swinject +import SwinjectStoryboard + +final class ForecastAssemblyContainer: Assembly { + + func assemble(container: Container) { + container.register(ForecastInteractorProtocol.self) { resolver in + let interactor = ForecastInteractor() + interactor.weatherService = resolver.resolve(WeatherService.self)! + interactor.settingsService = resolver.resolve(SettingsService.self)! + return interactor + } + + container.register(ForecastRouterProtocol.self) { (_, _: ForecastViewController) in + let router = ForecastRouter() + return router + } + + container.register(ForecastPresenter.self) { (resolver, viewController: ForecastViewController) in + let presenter = ForecastPresenter() + presenter.view = viewController + presenter.interactor = resolver.resolve(ForecastInteractorProtocol.self) + presenter.router = resolver.resolve(ForecastRouterProtocol.self, argument: viewController) + return presenter + } + + container.storyboardInitCompleted(ForecastViewController.self) { resolver, viewController in + let presenter = resolver.resolve(ForecastPresenter.self, argument: viewController)! + viewController.setPresenter(presenter) + } + } +} diff --git a/Weather/Modules/Forecast/Interactor/ForecastInteractor.swift b/Weather/Modules/Forecast/Interactor/ForecastInteractor.swift new file mode 100644 index 0000000..85fd56b --- /dev/null +++ b/Weather/Modules/Forecast/Interactor/ForecastInteractor.swift @@ -0,0 +1,33 @@ +// +// ForecastForecastInteractor.swift +// Weather +// +// Created by Sergey V. Krupov on 30/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +import RxCocoa +import RxSwift + +final class ForecastInteractor: ForecastInteractorProtocol { + + // MARK: - Dependencies + var weatherService: WeatherService! + var settingsService: SettingsService! + + // MARK: - ForecastInteractorProtocol + lazy var forecast: Driver<[Weather]> = { + let refreshObservable = refreshSubject.startWith(()) + return Observable.combineLatest(refreshObservable, settingsService.currentCity) { $1 } + .flatMapLatest { [service = self.weatherService!] city in service.obtainForecast(for: city) } + .catchError { _ in .empty() } + .asDriver(onErrorDriveWith: .empty()) + } () + + func refresh() { + refreshSubject.onNext(()) + } + + // MARK: - Private + private let refreshSubject = PublishSubject() +} diff --git a/Weather/Modules/Forecast/Interactor/ForecastInteractorProtocol.swift b/Weather/Modules/Forecast/Interactor/ForecastInteractorProtocol.swift new file mode 100644 index 0000000..a3ef609 --- /dev/null +++ b/Weather/Modules/Forecast/Interactor/ForecastInteractorProtocol.swift @@ -0,0 +1,17 @@ +// +// ForecastForecastInteractorProtocol.swift +// Weather +// +// Created by Sergey V. Krupov on 30/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +import RxCocoa +import RxSwift + +protocol ForecastInteractorProtocol: class { + + var forecast: Driver<[Weather]> { get } + + func refresh() +} diff --git a/Weather/Modules/Forecast/Presenter/ForecastModuleInput.swift b/Weather/Modules/Forecast/Presenter/ForecastModuleInput.swift new file mode 100644 index 0000000..8bb390a --- /dev/null +++ b/Weather/Modules/Forecast/Presenter/ForecastModuleInput.swift @@ -0,0 +1,11 @@ +// +// ForecastForecastModuleInput.swift +// Weather +// +// Created by Sergey V. Krupov on 30/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +protocol ForecastModuleInput: class { + +} diff --git a/Weather/Modules/Forecast/Presenter/ForecastPresenter.swift b/Weather/Modules/Forecast/Presenter/ForecastPresenter.swift new file mode 100644 index 0000000..18ccc2e --- /dev/null +++ b/Weather/Modules/Forecast/Presenter/ForecastPresenter.swift @@ -0,0 +1,59 @@ +// +// ForecastForecastPresenter.swift +// Weather +// +// Created by Sergey V. Krupov on 30/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +import RxCocoa +import RxSwift + +final class ForecastPresenter { + + // MARK: - Properties + var interactor: ForecastInteractorProtocol! + var router: ForecastRouterProtocol! + weak var view: ForecastViewProtocol? + + // MARK: - Public + + // MARK: - Private + private let disposeBag = DisposeBag() +} + +// MARK: - ForecastPesenterProtocol +extension ForecastPresenter: ForecastPresenterProtocol { + + func setupBindings(_ view: ForecastViewProtocol) { + interactor.forecast + .map { weathers -> [WeatherItem] in + weathers.map { + WeatherItem( + image: UIImage(named: $0.icon) ?? R.image.undefined(), + description: $0.description, + temperature: Utils.temperatureFormatter.string(from: $0.temperature as NSNumber), + date: Utils.dateFormatter.string(from: $0.date) + ) + } + } + .drive(view.items) + .disposed(by: disposeBag) + + view.refresh + .bind(to: Binder(self) { this, _ in + this.interactor.refresh() + }) + .disposed(by: disposeBag) + + interactor.forecast + .drive(Binder(self) { this, _ in + this.view?.endRefreshing() + }) + .disposed(by: disposeBag) + } +} + +// MARK: - ForecastModuleInput +extension ForecastPresenter: ForecastModuleInput { +} diff --git a/Weather/Modules/Forecast/Presenter/ForecastPresenterProtocol.swift b/Weather/Modules/Forecast/Presenter/ForecastPresenterProtocol.swift new file mode 100644 index 0000000..2d793ef --- /dev/null +++ b/Weather/Modules/Forecast/Presenter/ForecastPresenterProtocol.swift @@ -0,0 +1,12 @@ +// +// ForecastForecastPresenterProtocol.swift +// Weather +// +// Created by Sergey V. Krupov on 30/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +protocol ForecastPresenterProtocol { + + func setupBindings(_ view: ForecastViewProtocol) +} diff --git a/Weather/Modules/Forecast/Presenter/Models/WeatherItem.swift b/Weather/Modules/Forecast/Presenter/Models/WeatherItem.swift new file mode 100644 index 0000000..6b90a17 --- /dev/null +++ b/Weather/Modules/Forecast/Presenter/Models/WeatherItem.swift @@ -0,0 +1,16 @@ +// +// WeatherItem.swift +// Weather +// +// Created by Sergey V. Krupov on 31.01.2019. +// Copyright © 2019 Sergey V. Krupov. All rights reserved. +// + +import UIKit + +struct WeatherItem { + let image: UIImage? + let description: String? + let temperature: String? + let date: String? +} diff --git a/Weather/Modules/Forecast/Router/ForecastRouter.swift b/Weather/Modules/Forecast/Router/ForecastRouter.swift new file mode 100644 index 0000000..f2898c4 --- /dev/null +++ b/Weather/Modules/Forecast/Router/ForecastRouter.swift @@ -0,0 +1,11 @@ +// +// ForecastForecastRouter.swift +// Weather +// +// Created by Sergey V. Krupov on 30/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +final class ForecastRouter: ForecastRouterProtocol { + +} diff --git a/Weather/Modules/Forecast/Router/ForecastRouterProtocol.swift b/Weather/Modules/Forecast/Router/ForecastRouterProtocol.swift new file mode 100644 index 0000000..13b91c9 --- /dev/null +++ b/Weather/Modules/Forecast/Router/ForecastRouterProtocol.swift @@ -0,0 +1,13 @@ +// +// ForecastForecastRouterProtocol.swift +// Weather +// +// Created by Sergey V. Krupov on 30/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +import Foundation + +protocol ForecastRouterProtocol: class { + +} diff --git a/Weather/Modules/Forecast/View/Cells/ForecastItemCellTableViewCell.swift b/Weather/Modules/Forecast/View/Cells/ForecastItemCellTableViewCell.swift new file mode 100644 index 0000000..665221a --- /dev/null +++ b/Weather/Modules/Forecast/View/Cells/ForecastItemCellTableViewCell.swift @@ -0,0 +1,23 @@ +// +// ForecastItemCellTableViewCell.swift +// Weather +// +// Created by Sergey V. Krupov on 31.01.2019. +// Copyright © 2019 Sergey V. Krupov. All rights reserved. +// + +import UIKit + +final class ForecastItemCellTableViewCell: UITableViewCell { + + @IBOutlet private weak var dateLabel: UILabel! + @IBOutlet private weak var temperatureLabel: UILabel! + @IBOutlet private weak var weatherImageView: UIImageView! + + // MARK: - Public + func setup(_ item: WeatherItem) { + dateLabel.text = item.date + temperatureLabel.text = item.temperature + weatherImageView.image = item.image + } +} diff --git a/Weather/Modules/Forecast/View/Cells/ForecastItemCellTableViewCell.xib b/Weather/Modules/Forecast/View/Cells/ForecastItemCellTableViewCell.xib new file mode 100644 index 0000000..4e6932d --- /dev/null +++ b/Weather/Modules/Forecast/View/Cells/ForecastItemCellTableViewCell.xib @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Weather/Modules/Forecast/View/Forecast.storyboard b/Weather/Modules/Forecast/View/Forecast.storyboard new file mode 100644 index 0000000..a632a2c --- /dev/null +++ b/Weather/Modules/Forecast/View/Forecast.storyboard @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Weather/Modules/Forecast/View/ForecastViewController.swift b/Weather/Modules/Forecast/View/ForecastViewController.swift new file mode 100644 index 0000000..0abf771 --- /dev/null +++ b/Weather/Modules/Forecast/View/ForecastViewController.swift @@ -0,0 +1,64 @@ +// +// ForecastForecastViewController.swift +// Weather +// +// Created by Sergey V. Krupov on 30/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +import RxCocoa +import RxDataSources +import RxSwift +import UIKit + +final class ForecastViewController: UIViewController { + + // MARK: - Outlets + @IBOutlet private weak var tableView: UITableView! + + // MARK: - Public + func setPresenter(_ presenter: ForecastPresenterProtocol) { + self.presenter = presenter + } + + // MARK: - Life cycle + override func viewDidLoad() { + super.viewDidLoad() + + tableView.rowHeight = 45 + tableView.refreshControl = refreshControl + tableView.register(R.nib.forecastItemCellTableViewCell) + itemsRelay.asObservable() + .bind(to: tableView.rx.items(cellIdentifier: R.reuseIdentifier.forecastItemCellTableViewCell.identifier)) { _, model, cell in + let weatherCell = cell as! ForecastItemCellTableViewCell + weatherCell.setup(model) + } + .disposed(by: disposeBag) + + presenter?.setupBindings(self) + } + + // MARK: - Private + private var presenter: ForecastPresenterProtocol? + private let itemsRelay = PublishRelay<[WeatherItem]>() + private let disposeBag = DisposeBag() + private let refreshControl = UIRefreshControl(frame: .zero) +} + +// MARK: - ForecastViewInput +extension ForecastViewController: ForecastViewProtocol { + + var items: Binder<[WeatherItem]> { + return Binder(self) { this, items in + this.itemsRelay.accept(items) + } + } + + var refresh: ControlEvent { + return refreshControl.rx.controlEvent(.valueChanged) + } + + func endRefreshing() { + refreshControl.endRefreshing() + } +} diff --git a/Weather/Modules/Forecast/View/ForecastViewProtocol.swift b/Weather/Modules/Forecast/View/ForecastViewProtocol.swift new file mode 100644 index 0000000..9ee1581 --- /dev/null +++ b/Weather/Modules/Forecast/View/ForecastViewProtocol.swift @@ -0,0 +1,21 @@ +// +// ForecastForecastViewProtocol.swift +// Weather +// +// Created by Sergey V. Krupov on 30/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +import RxCocoa +import RxSwift + +protocol ForecastViewProtocol: class { + + // MARK: - Input + var items: Binder<[WeatherItem]> { get } + + // MARK: - Output + var refresh: ControlEvent { get } + + func endRefreshing() +} diff --git a/Weather/Modules/Main/Assembly/MainAssemblyContainer.swift b/Weather/Modules/Main/Assembly/MainAssemblyContainer.swift new file mode 100644 index 0000000..ba5d72f --- /dev/null +++ b/Weather/Modules/Main/Assembly/MainAssemblyContainer.swift @@ -0,0 +1,40 @@ +// +// MainMainAssemblyContainer.swift +// Weather +// +// Created by Sergey V. Krupov on 28/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +import Swinject +import SwinjectStoryboard + +final class MainAssemblyContainer: Assembly { + + func assemble(container: Container) { + container.register(MainInteractorProtocol.self) { resolver in + let interactor = MainInteractor() + interactor.weatherService = resolver.resolve(WeatherService.self)! + interactor.settingsService = resolver.resolve(SettingsService.self)! + return interactor + } + + container.register(MainRouterProtocol.self) { (_, _: MainViewController) in + let router = MainRouter() + return router + } + + container.register(MainPresenter.self) { (resolver, viewController: MainViewController) in + let presenter = MainPresenter() + presenter.view = viewController + presenter.interactor = resolver.resolve(MainInteractorProtocol.self) + presenter.router = resolver.resolve(MainRouterProtocol.self, argument: viewController) + return presenter + } + + container.storyboardInitCompleted(MainViewController.self) { resolver, viewController in + let presenter = resolver.resolve(MainPresenter.self, argument: viewController)! + viewController.setPresenter(presenter) + } + } +} diff --git a/Weather/Modules/Main/Interactor/MainInteractor.swift b/Weather/Modules/Main/Interactor/MainInteractor.swift new file mode 100644 index 0000000..4fce68d --- /dev/null +++ b/Weather/Modules/Main/Interactor/MainInteractor.swift @@ -0,0 +1,40 @@ +// +// MainMainInteractor.swift +// Weather +// +// Created by Sergey V. Krupov on 28/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +import RxCocoa +import RxSwift + +final class MainInteractor: MainInteractorProtocol { + + // MARK: - Dependencies + var weatherService: WeatherService! + var settingsService: SettingsService! + + // MARK: - MainInteractorProtocol + lazy var weather: Driver = { + let refreshObservable = refreshSubject.startWith(()) + return Observable.combineLatest(refreshObservable, settingsService.currentCity) { $1 } + .flatMapLatest { [service = self.weatherService!] city in service.obtainWeather(for: city) } + .catchError { _ in .empty() } + .asDriver(onErrorDriveWith: .empty()) + } () + + lazy var city: Driver = { + return settingsService.currentCity + .catchError { _ in .empty() } + .asDriver(onErrorDriveWith: .empty()) + .map { $0.name } + } () + + func refresh() { + refreshSubject.onNext(()) + } + + // MARK: - Private + private let refreshSubject = PublishSubject() +} diff --git a/Weather/Modules/Main/Interactor/MainInteractorProtocol.swift b/Weather/Modules/Main/Interactor/MainInteractorProtocol.swift new file mode 100644 index 0000000..b896227 --- /dev/null +++ b/Weather/Modules/Main/Interactor/MainInteractorProtocol.swift @@ -0,0 +1,18 @@ +// +// MainMainInteractorProtocol.swift +// Weather +// +// Created by Sergey V. Krupov on 28/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +import RxCocoa +import RxSwift + +protocol MainInteractorProtocol: class { + + var weather: Driver { get } + var city: Driver { get } + + func refresh() +} diff --git a/Weather/Modules/Main/Presenter/MainModuleInput.swift b/Weather/Modules/Main/Presenter/MainModuleInput.swift new file mode 100644 index 0000000..43715c1 --- /dev/null +++ b/Weather/Modules/Main/Presenter/MainModuleInput.swift @@ -0,0 +1,11 @@ +// +// MainMainModuleInput.swift +// Weather +// +// Created by Sergey V. Krupov on 28/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +protocol MainModuleInput: class { + +} diff --git a/Weather/Modules/Main/Presenter/MainPresenter.swift b/Weather/Modules/Main/Presenter/MainPresenter.swift new file mode 100644 index 0000000..3026667 --- /dev/null +++ b/Weather/Modules/Main/Presenter/MainPresenter.swift @@ -0,0 +1,68 @@ +// +// MainMainPresenter.swift +// Weather +// +// Created by Sergey V. Krupov on 28/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +import RxCocoa +import RxSwift +import UIKit + +final class MainPresenter { + + // MARK: - Properties + var interactor: MainInteractorProtocol! + var router: MainRouterProtocol! + weak var view: MainViewProtocol? + + // MARK: - Private + let disposeBag = DisposeBag() +} + +// MARK: - MainPesenterProtocol +extension MainPresenter: MainPresenterProtocol { + + func setupBindings(_ view: MainViewProtocol) { + + interactor.city + .startWith(nil) + .drive(view.city) + .disposed(by: disposeBag) + + interactor.weather + .map { Utils.temperatureFormatter.string(from: $0.temperature as NSNumber) } + .startWith("--") + .drive(view.temperature) + .disposed(by: disposeBag) + + interactor.weather + .map { UIImage(named: $0.icon) ?? R.image.undefined() } + .startWith(R.image.undefined()) + .drive(view.weatherImage) + .disposed(by: disposeBag) + + interactor.weather + .map { $0.description as String? } + .startWith(nil) + .drive(view.weatherDescription) + .disposed(by: disposeBag) + + view.refresh + .bind(to: Binder(self) { this, _ in + this.interactor.refresh() + }) + .disposed(by: disposeBag) + + interactor.weather + .drive(Binder(self) { this, _ in + this.view?.endRefreshing() + }) + .disposed(by: disposeBag) + } +} + +// MARK: - MainModuleInput +extension MainPresenter: MainModuleInput { +} diff --git a/Weather/Modules/Main/Presenter/MainPresenterProtocol.swift b/Weather/Modules/Main/Presenter/MainPresenterProtocol.swift new file mode 100644 index 0000000..8eb18fe --- /dev/null +++ b/Weather/Modules/Main/Presenter/MainPresenterProtocol.swift @@ -0,0 +1,12 @@ +// +// MainPresenterProtocol.swift +// Weather +// +// Created by Sergey V. Krupov on 29.01.2019. +// Copyright © 2019 Sergey V. Krupov. All rights reserved. +// + +protocol MainPresenterProtocol { + + func setupBindings(_ view: MainViewProtocol) +} diff --git a/Weather/Modules/Main/Router/MainRouter.swift b/Weather/Modules/Main/Router/MainRouter.swift new file mode 100644 index 0000000..bb34cb7 --- /dev/null +++ b/Weather/Modules/Main/Router/MainRouter.swift @@ -0,0 +1,11 @@ +// +// MainMainRouter.swift +// Weather +// +// Created by Sergey V. Krupov on 28/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +final class MainRouter: MainRouterProtocol { + +} diff --git a/Weather/Modules/Main/Router/MainRouterProtocol.swift b/Weather/Modules/Main/Router/MainRouterProtocol.swift new file mode 100644 index 0000000..7008b9f --- /dev/null +++ b/Weather/Modules/Main/Router/MainRouterProtocol.swift @@ -0,0 +1,13 @@ +// +// MainMainRouterProtocol.swift +// Weather +// +// Created by Sergey V. Krupov on 28/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +import Foundation + +protocol MainRouterProtocol: class { + +} diff --git a/Weather/Modules/Main/View/Base.lproj/Main.storyboard b/Weather/Modules/Main/View/Base.lproj/Main.storyboard new file mode 100644 index 0000000..17e8561 --- /dev/null +++ b/Weather/Modules/Main/View/Base.lproj/Main.storyboard @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Weather/Modules/Main/View/MainViewController.swift b/Weather/Modules/Main/View/MainViewController.swift new file mode 100644 index 0000000..9ec12dd --- /dev/null +++ b/Weather/Modules/Main/View/MainViewController.swift @@ -0,0 +1,65 @@ +// +// MainMainViewController.swift +// Weather +// +// Created by Sergey V. Krupov on 28/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +import RxCocoa +import UIKit + +final class MainViewController: UIViewController { + + // MARK: - Outlets + @IBOutlet private weak var currentTemperatureLabel: UILabel! + @IBOutlet private weak var weatherConditionImageView: UIImageView! + @IBOutlet private weak var weatherConditionLabel: UILabel! + @IBOutlet private weak var cityLabel: UILabel! + @IBOutlet private weak var scrollView: UIScrollView! + + // MARK: - Public + func setPresenter(_ presenter: MainPresenterProtocol) { + self.presenter = presenter + } + + // MARK: - Life cycle + override func viewDidLoad() { + super.viewDidLoad() + scrollView.addSubview(refreshControl) + + presenter?.setupBindings(self) + } + + // MARK: - Private + private var presenter: MainPresenterProtocol? + private let refreshControl = UIRefreshControl(frame: .zero) +} + +// MARK: - MainViewInput +extension MainViewController: MainViewProtocol { + + var city: Binder { + return cityLabel.rx.text + } + + var temperature: Binder { + return currentTemperatureLabel.rx.text + } + + var weatherImage: Binder { + return weatherConditionImageView.rx.image + } + + var weatherDescription: Binder { + return weatherConditionLabel.rx.text + } + + var refresh: ControlEvent { + return refreshControl.rx.controlEvent(.valueChanged) + } + + func endRefreshing() { + refreshControl.endRefreshing() + } +} diff --git a/Weather/Modules/Main/View/MainViewProtocol.swift b/Weather/Modules/Main/View/MainViewProtocol.swift new file mode 100644 index 0000000..769e159 --- /dev/null +++ b/Weather/Modules/Main/View/MainViewProtocol.swift @@ -0,0 +1,23 @@ +// +// MainMainViewProtocol.swift +// Weather +// +// Created by Sergey V. Krupov on 28/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +import RxCocoa + +protocol MainViewProtocol: class { + + // MARK: - Input + var city: Binder { get } + var temperature: Binder { get } + var weatherImage: Binder { get } + var weatherDescription: Binder { get } + + func endRefreshing() + + // MARK: - Output + var refresh: ControlEvent { get } +} diff --git a/Weather/Modules/Root/Assembly/RootAssemblyContainer.swift b/Weather/Modules/Root/Assembly/RootAssemblyContainer.swift new file mode 100644 index 0000000..3a15cb3 --- /dev/null +++ b/Weather/Modules/Root/Assembly/RootAssemblyContainer.swift @@ -0,0 +1,42 @@ +// +// RootRootAssemblyContainer.swift +// Weather +// +// Created by Sergey V. Krupov on 30/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +import Swinject +import SwinjectStoryboard + +final class RootAssemblyContainer: Assembly { + + func assemble(container: Container) { + container.register(RootInteractorProtocol.self) { _ in + let interactor = RootInteractor() + return interactor + } + + container.register(RootRouterProtocol.self) { (_, _: RootViewController) in + let router = RootRouter() + return router + } + + container.register(RootPresenter.self) { (resolver, viewController: RootViewController) in + let presenter = RootPresenter() + presenter.view = viewController + presenter.interactor = resolver.resolve(RootInteractorProtocol.self) + presenter.router = resolver.resolve(RootRouterProtocol.self, argument: viewController) + return presenter + } + + container.storyboardInitCompleted(RootViewController.self) { resolver, viewController in + let presenter = resolver.resolve(RootPresenter.self, argument: viewController)! + let main = R.storyboard.main.mainViewController()! + let forecast = R.storyboard.forecast.forecastViewController()! + let settings = R.storyboard.settings.settingsViewController()! + viewController.pages = [main, forecast, settings] + viewController.setPresenter(presenter) + } + } +} diff --git a/Weather/Modules/Root/Interactor/RootInteractor.swift b/Weather/Modules/Root/Interactor/RootInteractor.swift new file mode 100644 index 0000000..4c8dac6 --- /dev/null +++ b/Weather/Modules/Root/Interactor/RootInteractor.swift @@ -0,0 +1,17 @@ +// +// RootRootInteractor.swift +// Weather +// +// Created by Sergey V. Krupov on 30/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +import RxCocoa +import RxSwift + +final class RootInteractor: RootInteractorProtocol { + + // MARK: - Dependencies + + // MARK: - RootInteractorProtocol +} diff --git a/Weather/Modules/Root/Interactor/RootInteractorProtocol.swift b/Weather/Modules/Root/Interactor/RootInteractorProtocol.swift new file mode 100644 index 0000000..2222ad0 --- /dev/null +++ b/Weather/Modules/Root/Interactor/RootInteractorProtocol.swift @@ -0,0 +1,14 @@ +// +// RootRootInteractorProtocol.swift +// Weather +// +// Created by Sergey V. Krupov on 30/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +import RxCocoa +import RxSwift + +protocol RootInteractorProtocol: class { + +} diff --git a/Weather/Modules/Root/Presenter/RootModuleInput.swift b/Weather/Modules/Root/Presenter/RootModuleInput.swift new file mode 100644 index 0000000..f8f7712 --- /dev/null +++ b/Weather/Modules/Root/Presenter/RootModuleInput.swift @@ -0,0 +1,11 @@ +// +// RootRootModuleInput.swift +// Weather +// +// Created by Sergey V. Krupov on 30/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +protocol RootModuleInput: class { + +} diff --git a/Weather/Modules/Root/Presenter/RootPresenter.swift b/Weather/Modules/Root/Presenter/RootPresenter.swift new file mode 100644 index 0000000..89f3f7c --- /dev/null +++ b/Weather/Modules/Root/Presenter/RootPresenter.swift @@ -0,0 +1,32 @@ +// +// RootRootPresenter.swift +// Weather +// +// Created by Sergey V. Krupov on 30/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +import RxCocoa +import RxSwift + +final class RootPresenter { + + // MARK: - Properties + var interactor: RootInteractorProtocol! + var router: RootRouterProtocol! + weak var view: RootViewProtocol? + + // MARK: - Private + let disposeBag = DisposeBag() +} + +// MARK: - RootPesenterProtocol +extension RootPresenter: RootPresenterProtocol { + + func setupBindings(_ view: RootViewProtocol) { + } +} + +// MARK: - RootModuleInput +extension RootPresenter: RootModuleInput { +} diff --git a/Weather/Modules/Root/Presenter/RootPresenterProtocol.swift b/Weather/Modules/Root/Presenter/RootPresenterProtocol.swift new file mode 100644 index 0000000..46dd341 --- /dev/null +++ b/Weather/Modules/Root/Presenter/RootPresenterProtocol.swift @@ -0,0 +1,12 @@ +// +// RootRootPresenterProtocol.swift +// Weather +// +// Created by Sergey V. Krupov on 30/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +protocol RootPresenterProtocol { + + func setupBindings(_ view: RootViewProtocol) +} diff --git a/Weather/Modules/Root/Router/RootRouter.swift b/Weather/Modules/Root/Router/RootRouter.swift new file mode 100644 index 0000000..03584e0 --- /dev/null +++ b/Weather/Modules/Root/Router/RootRouter.swift @@ -0,0 +1,11 @@ +// +// RootRootRouter.swift +// Weather +// +// Created by Sergey V. Krupov on 30/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +final class RootRouter: RootRouterProtocol { + +} diff --git a/Weather/Modules/Root/Router/RootRouterProtocol.swift b/Weather/Modules/Root/Router/RootRouterProtocol.swift new file mode 100644 index 0000000..8be45b3 --- /dev/null +++ b/Weather/Modules/Root/Router/RootRouterProtocol.swift @@ -0,0 +1,13 @@ +// +// RootRootRouterProtocol.swift +// Weather +// +// Created by Sergey V. Krupov on 30/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +import Foundation + +protocol RootRouterProtocol: class { + +} diff --git a/Weather/Modules/Root/View/Root.storyboard b/Weather/Modules/Root/View/Root.storyboard new file mode 100644 index 0000000..e780c92 --- /dev/null +++ b/Weather/Modules/Root/View/Root.storyboard @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/Weather/Modules/Root/View/RootViewController.swift b/Weather/Modules/Root/View/RootViewController.swift new file mode 100644 index 0000000..63111e9 --- /dev/null +++ b/Weather/Modules/Root/View/RootViewController.swift @@ -0,0 +1,78 @@ +// +// RootRootViewController.swift +// Weather +// +// Created by Sergey V. Krupov on 30/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +import RxCocoa +import RxSwift +import UIKit + +final class RootViewController: UIPageViewController { + + // MARK: - Dependencies + var pages: [UIViewController]! + + // MARK: - Outlets + + // MARK: - Public + func setPresenter(_ presenter: RootPresenterProtocol) { + self.presenter = presenter + } + + // MARK: - Life cycle + override func viewDidLoad() { + super.viewDidLoad() + if let firstPage = pages.first { + setViewControllers([firstPage], direction: .forward, animated: false) + } + dataSource = self + presenter?.setupBindings(self) + } + + // MARK: - Private + var presenter: RootPresenterProtocol? +} + +// MARK: - RootViewInput +extension RootViewController: RootViewProtocol { + + func setupInitialState() { + } +} + +extension RootViewController: UIPageViewControllerDataSource { + + func pageViewController(_ pageViewController: UIPageViewController, + viewControllerBefore viewController: UIViewController) -> UIViewController? { + + guard let index = pages.firstIndex(of: viewController) else { + return nil + } + let indexBefore = (index + pages.count - 1) % pages.count + return pages[indexBefore] + } + + func pageViewController(_ pageViewController: UIPageViewController, + viewControllerAfter viewController: UIViewController) -> UIViewController? { + + guard let index = pages.firstIndex(of: viewController) else { + return nil + } + let indexAfter = (index + 1) % pages.count + return pages[indexAfter] + } + + func presentationCount(for pageViewController: UIPageViewController) -> Int { + return pages.count + } + + func presentationIndex(for pageViewController: UIPageViewController) -> Int { + guard let viewController = pageViewController.viewControllers?.first else { + return 0 + } + return pages.firstIndex(of: viewController) ?? 0 + } +} diff --git a/Weather/Modules/Root/View/RootViewProtocol.swift b/Weather/Modules/Root/View/RootViewProtocol.swift new file mode 100644 index 0000000..6c2020b --- /dev/null +++ b/Weather/Modules/Root/View/RootViewProtocol.swift @@ -0,0 +1,18 @@ +// +// RootRootViewProtocol.swift +// Weather +// +// Created by Sergey V. Krupov on 30/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +import RxCocoa +import RxSwift + +protocol RootViewProtocol: class { + + // MARK: - Input + func setupInitialState() + + // MARK: - Output +} diff --git a/Weather/Modules/Settings/Assembly/SettingsAssemblyContainer.swift b/Weather/Modules/Settings/Assembly/SettingsAssemblyContainer.swift new file mode 100644 index 0000000..40904ec --- /dev/null +++ b/Weather/Modules/Settings/Assembly/SettingsAssemblyContainer.swift @@ -0,0 +1,39 @@ +// +// SettingsSettingsAssemblyContainer.swift +// Weather +// +// Created by Sergey V. Krupov on 30/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +import Swinject +import SwinjectStoryboard + +final class SettingsAssemblyContainer: Assembly { + + func assemble(container: Container) { + container.register(SettingsInteractorProtocol.self) { resolver in + let interactor = SettingsInteractor() + interactor.settingsService = resolver.resolve(SettingsService.self)! + return interactor + } + + container.register(SettingsRouterProtocol.self) { (_, _: SettingsViewController) in + let router = SettingsRouter() + return router + } + + container.register(SettingsPresenter.self) { (resolver, viewController: SettingsViewController) in + let presenter = SettingsPresenter() + presenter.view = viewController + presenter.interactor = resolver.resolve(SettingsInteractorProtocol.self) + presenter.router = resolver.resolve(SettingsRouterProtocol.self, argument: viewController) + return presenter + } + + container.storyboardInitCompleted(SettingsViewController.self) { resolver, viewController in + let presenter = resolver.resolve(SettingsPresenter.self, argument: viewController)! + viewController.setPresenter(presenter) + } + } +} diff --git a/Weather/Modules/Settings/Interactor/SettingsInteractor.swift b/Weather/Modules/Settings/Interactor/SettingsInteractor.swift new file mode 100644 index 0000000..e9f9f83 --- /dev/null +++ b/Weather/Modules/Settings/Interactor/SettingsInteractor.swift @@ -0,0 +1,33 @@ +// +// SettingsSettingsInteractor.swift +// Weather +// +// Created by Sergey V. Krupov on 30/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +import RxCocoa +import RxSwift + +final class SettingsInteractor: SettingsInteractorProtocol { + + // MARK: - Dependencies + var settingsService: SettingsService! + + // MARK: - SettingsInteractorProtocol + lazy var cities: Driver<[City]> = { + settingsService.allCities + .asDriver(onErrorDriveWith: .empty()) + } () + + lazy var selectedCity: Driver = { + settingsService.currentCity + .asDriver(onErrorDriveWith: .empty()) + } () + + var selectedCityIDSink: Binder { + return Binder(self) { this, identifier in + this.settingsService.setCurrentCityID(identifier) + } + } +} diff --git a/Weather/Modules/Settings/Interactor/SettingsInteractorProtocol.swift b/Weather/Modules/Settings/Interactor/SettingsInteractorProtocol.swift new file mode 100644 index 0000000..9f9386d --- /dev/null +++ b/Weather/Modules/Settings/Interactor/SettingsInteractorProtocol.swift @@ -0,0 +1,20 @@ +// +// SettingsSettingsInteractorProtocol.swift +// Weather +// +// Created by Sergey V. Krupov on 30/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +import RxCocoa +import RxSwift + +protocol SettingsInteractorProtocol: class { + + // MARK: - Output + var cities: Driver<[City]> { get } + var selectedCity: Driver { get } + + // MARK: - Input + var selectedCityIDSink: Binder { get } +} diff --git a/Weather/Modules/Settings/Presenter/Models/CitiesSection.swift b/Weather/Modules/Settings/Presenter/Models/CitiesSection.swift new file mode 100644 index 0000000..9d709b5 --- /dev/null +++ b/Weather/Modules/Settings/Presenter/Models/CitiesSection.swift @@ -0,0 +1,22 @@ +// +// CitiesSection.swift +// Weather +// +// Created by Sergey V. Krupov on 31.01.2019. +// Copyright © 2019 Sergey V. Krupov. All rights reserved. +// + +import RxDataSources + +struct CitiesSection { + let header: String + let items: [CityItem] +} + +extension CitiesSection: SectionModelType { + + init(original: CitiesSection, items: [CityItem]) { + self.header = original.header + self.items = items + } +} diff --git a/Weather/Modules/Settings/Presenter/Models/CityItem.swift b/Weather/Modules/Settings/Presenter/Models/CityItem.swift new file mode 100644 index 0000000..5e559de --- /dev/null +++ b/Weather/Modules/Settings/Presenter/Models/CityItem.swift @@ -0,0 +1,13 @@ +// +// CityItem.swift +// Weather +// +// Created by Sergey V. Krupov on 31.01.2019. +// Copyright © 2019 Sergey V. Krupov. All rights reserved. +// + +struct CityItem { + let name: String + let isCurrent: Bool + let id: Int +} diff --git a/Weather/Modules/Settings/Presenter/SettingsModuleInput.swift b/Weather/Modules/Settings/Presenter/SettingsModuleInput.swift new file mode 100644 index 0000000..0aee125 --- /dev/null +++ b/Weather/Modules/Settings/Presenter/SettingsModuleInput.swift @@ -0,0 +1,11 @@ +// +// SettingsSettingsModuleInput.swift +// Weather +// +// Created by Sergey V. Krupov on 30/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +protocol SettingsModuleInput: class { + +} diff --git a/Weather/Modules/Settings/Presenter/SettingsPresenter.swift b/Weather/Modules/Settings/Presenter/SettingsPresenter.swift new file mode 100644 index 0000000..35f026c --- /dev/null +++ b/Weather/Modules/Settings/Presenter/SettingsPresenter.swift @@ -0,0 +1,49 @@ +// +// SettingsSettingsPresenter.swift +// Weather +// +// Created by Sergey V. Krupov on 30/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +import RxCocoa +import RxSwift + +final class SettingsPresenter { + + // MARK: - Properties + var interactor: SettingsInteractorProtocol! + var router: SettingsRouterProtocol! + weak var view: SettingsViewProtocol? + + // MARK: - Private + private let disposeBag = DisposeBag() +} + +// MARK: - SettingsPesenterProtocol +extension SettingsPresenter: SettingsPresenterProtocol { + + func setupBindings(_ view: SettingsViewProtocol) { + Driver.combineLatest(interactor.cities, interactor.selectedCity) { cities, currentCity -> [CitiesSection] in + let items = cities.map { + CityItem( + name: $0.name, + isCurrent: $0.id == currentCity.id, + id: $0.id + ) + } + return [CitiesSection(header: "Город", items: items)] + } + .drive(view.sections) + .disposed(by: disposeBag) + + view.citySelected + .map { $0.id } + .bind(to: interactor.selectedCityIDSink) + .disposed(by: disposeBag) + } +} + +// MARK: - SettingsModuleInput +extension SettingsPresenter: SettingsModuleInput { +} diff --git a/Weather/Modules/Settings/Presenter/SettingsPresenterProtocol.swift b/Weather/Modules/Settings/Presenter/SettingsPresenterProtocol.swift new file mode 100644 index 0000000..9305d60 --- /dev/null +++ b/Weather/Modules/Settings/Presenter/SettingsPresenterProtocol.swift @@ -0,0 +1,12 @@ +// +// SettingsSettingsPresenterProtocol.swift +// Weather +// +// Created by Sergey V. Krupov on 30/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +protocol SettingsPresenterProtocol { + + func setupBindings(_ view: SettingsViewProtocol) +} diff --git a/Weather/Modules/Settings/Router/SettingsRouter.swift b/Weather/Modules/Settings/Router/SettingsRouter.swift new file mode 100644 index 0000000..f25a5e1 --- /dev/null +++ b/Weather/Modules/Settings/Router/SettingsRouter.swift @@ -0,0 +1,11 @@ +// +// SettingsSettingsRouter.swift +// Weather +// +// Created by Sergey V. Krupov on 30/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +final class SettingsRouter: SettingsRouterProtocol { + +} diff --git a/Weather/Modules/Settings/Router/SettingsRouterProtocol.swift b/Weather/Modules/Settings/Router/SettingsRouterProtocol.swift new file mode 100644 index 0000000..2112f9c --- /dev/null +++ b/Weather/Modules/Settings/Router/SettingsRouterProtocol.swift @@ -0,0 +1,13 @@ +// +// SettingsSettingsRouterProtocol.swift +// Weather +// +// Created by Sergey V. Krupov on 30/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +import Foundation + +protocol SettingsRouterProtocol: class { + +} diff --git a/Weather/Modules/Settings/View/Cells/SettingsCityCell.swift b/Weather/Modules/Settings/View/Cells/SettingsCityCell.swift new file mode 100644 index 0000000..e47e635 --- /dev/null +++ b/Weather/Modules/Settings/View/Cells/SettingsCityCell.swift @@ -0,0 +1,17 @@ +// +// SettingsCityCell.swift +// Weather +// +// Created by Sergey V. Krupov on 31.01.2019. +// Copyright © 2019 Sergey V. Krupov. All rights reserved. +// + +import UIKit + +final class SettingsCityCell: UITableViewCell { + + func setup(_ item: CityItem) { + textLabel?.text = item.name + accessoryType = item.isCurrent ? .checkmark : .none + } +} diff --git a/Weather/Modules/Settings/View/Cells/SettingsCityCell.xib b/Weather/Modules/Settings/View/Cells/SettingsCityCell.xib new file mode 100644 index 0000000..2c6d66f --- /dev/null +++ b/Weather/Modules/Settings/View/Cells/SettingsCityCell.xib @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Weather/Modules/Settings/View/Settings.storyboard b/Weather/Modules/Settings/View/Settings.storyboard new file mode 100644 index 0000000..4c81005 --- /dev/null +++ b/Weather/Modules/Settings/View/Settings.storyboard @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Weather/Modules/Settings/View/SettingsViewController.swift b/Weather/Modules/Settings/View/SettingsViewController.swift new file mode 100644 index 0000000..d0cf6f1 --- /dev/null +++ b/Weather/Modules/Settings/View/SettingsViewController.swift @@ -0,0 +1,64 @@ +// +// SettingsSettingsViewController.swift +// Weather +// +// Created by Sergey V. Krupov on 30/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +import RxCocoa +import RxDataSources +import RxSwift +import UIKit + +final class SettingsViewController: UIViewController { + + // MARK: - Outlets + @IBOutlet private weak var tableView: UITableView! + + // MARK: - Public + func setPresenter(_ presenter: SettingsPresenterProtocol) { + self.presenter = presenter + } + + // MARK: - Life cycle + override func viewDidLoad() { + super.viewDidLoad() + + tableView.rowHeight = 45 + tableView.register(R.nib.settingsCityCell) + + let dataSource = RxTableViewSectionedReloadDataSource(configureCell: { dataSource, tableView, indexPath, item in + let cell = tableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.settingsCityCell, for: indexPath)! + cell.setup(item) + return cell + }, titleForHeaderInSection: { dataSource, section in + return dataSource.sectionModels[section].header + }) + + sectionsRelay.asObservable() + .bind(to: tableView.rx.items(dataSource: dataSource)) + .disposed(by: disposeBag) + + presenter?.setupBindings(self) + } + + // MARK: - Private + private var presenter: SettingsPresenterProtocol? + private let sectionsRelay = PublishRelay<[CitiesSection]>() + private let disposeBag = DisposeBag() +} + +// MARK: - SettingsViewInput +extension SettingsViewController: SettingsViewProtocol { + + var sections: Binder<[CitiesSection]> { + return Binder(self) { this, sections in + this.sectionsRelay.accept(sections) + } + } + + var citySelected: ControlEvent { + return tableView.rx.modelSelected(CityItem.self) + } +} diff --git a/Weather/Modules/Settings/View/SettingsViewProtocol.swift b/Weather/Modules/Settings/View/SettingsViewProtocol.swift new file mode 100644 index 0000000..619a503 --- /dev/null +++ b/Weather/Modules/Settings/View/SettingsViewProtocol.swift @@ -0,0 +1,19 @@ +// +// SettingsSettingsViewProtocol.swift +// Weather +// +// Created by Sergey V. Krupov on 30/01/2019. +// Copyright © 2019 Home. All rights reserved. +// + +import RxCocoa +import RxSwift + +protocol SettingsViewProtocol: class { + + // MARK: - Input + var sections: Binder<[CitiesSection]> { get } + + // MARK: - Output + var citySelected: ControlEvent { get } +} diff --git a/Weather/Resources/Cities.json b/Weather/Resources/Cities.json new file mode 100644 index 0000000..8bcd935 --- /dev/null +++ b/Weather/Resources/Cities.json @@ -0,0 +1,38 @@ +[ + { + "id": 511196, + "name": "Perm", + "country": "RU", + "coord": { + "lon": 56.285519, + "lat": 58.01741 + } + }, + { + "id": 536203, + "name": "Sankt-Peterburg", + "country": "RU", + "coord": { + "lon": 30.25, + "lat": 59.916668 + } + }, + { + "id": 524901, + "name": "Moscow", + "country": "RU", + "coord": { + "lon": 37.615555, + "lat": 55.75222 + } + }, + { + "id": 491422, + "name": "Sochi", + "country": "RU", + "coord": { + "lon": 39.730278, + "lat": 43.599998 + } + } +] \ No newline at end of file diff --git a/Weather/Resources/Icons.xcassets/01d.imageset/01d.png b/Weather/Resources/Icons.xcassets/01d.imageset/01d.png new file mode 100644 index 0000000000000000000000000000000000000000..4dddcca2123166c0c2ac946c39988cb5abd6e1c8 GIT binary patch literal 5538 zcmaJ_c|26n+rPtL?1SuzvF{?nkeDH*WN9jE_U!A7oeaj7EoJ%1PLw5UD0|70bz~=N zG@)z}V|{P$`~LC%^`6h?-1E8jem~DS_nznZKHu}i8Q#@pq~oCj0D$qJXv#Q*Cs zYVg{rVbc!|P%P>e1_rhen0+jGPwREl6bs@f|8)pTJSzZv$c@u6!QJzGjPtkgaRB`N z{bij!T(NdGUJkOJK8{(N>O3Hb?H@?X7w6>Z1L!;WxH)@ZoE(fD?7QX>!QkuL|6{|~ z$Ibz8!r{D-a&qqfjlwxO_&C_h+B^6;+j!t?d~mXMp6+tsDCgy74BAzS5lV0svxhb(8J0;2%5F~XBO@073kya=!65%XaOx8&d1r-7w7EhA#>N$1MTS! z&SU3n<0f;@30%IGo3pEf!2hnm&IdH^?B@W^=nh){_cd~E&UOwSSO=_}ZJ>;Yoeb7S z?uzVXxp^qhDgazS-qO~>1Z4lV40hw|2|OPh+MJI}R(p}^u&x!A{*#z~Lg&!`22Mju z$3?|M^OkZ_b44(AsROd!L2JzAXT~{LM|f6M7o{2I1isQ)a+wTG6f zw}wpwA@N*6VuV#BrR89AV2^qJITl+Ntm|`-)YHs=d1}>r>#=|PLdb&hf-MgI$6s+(4ZQ+0QD z#~w`|9=>$5p@sivsKWN7|F*UOkUbb_2j#bVYmECaj9Dc>5-|JUpAm

jVqa1G6$&hF_Yx>mLR-5@;UWsB1`(8!YmtbuR4 zDQO$4#zvu3*RN}(Za6pb6BQZr*LuoPC0~s^R?9*kjtB8+ep4J2F5WvOJj;!wVb*Y; z^^?Qfw>r4F{W8*9lL0D1kN;l$*fjC1KK!mwug*Br?9c_pIU4+LDKH-?rqHXg8$o8z>XAE9n?O5S>=S$w^QMG%vcZ)%pml%mPM6fCFn;5gOTC9}kt zJzmFpUxZpU+|{0&i)#vdxV^NMc5Ve3BJXy^b6RC*XNL@W^U(k>#7ajvWz50m-0`hZ z#TeYdHD%?4uDG~3E8B4zuf8swVgtkb;>FqWqEC0z zxrxc)YY@-v#CJ{nEZm0cZ;t;w*Ptfk54q-nQ)?%0v3DW62>; zxPvHqwY`pyj%_V(1vz7*0+LY$;&dA`!aZhkwY!cCaf!6W`{yQ8P) z7WTD4-jhuEk|Sz%p2h8@PG*yI-*~vv0wT>k`0WN`Cs)f_NtQ3KRdNqX0H7lv#1Cn}wYvscjyj)Gvi`0V*W= z%sW3~?%lgrRasH7QoJ#Uk*s&Mw_hpH7TgK%y#&)N#T<36tgQIUS~e-t+&YZ5sYb^z zUHrYVaeTYKwj1d1oy%)GJKD(WmNeCSGsah@O7!C{5=GfV-(2YxqR%UwS&F}?>a#Kr zMgu!Jh5%=>`_=MYg;Rw@HQNv)(?1hWty+(QO?qcf8<*lZ@UEs49{sg{d80?e#>Sh!Px1DJS zZFQfWq_OPb!dB0yZ7*{2Eq^_~CWwJPEmWX4ItH{%)pAB(Q~TRiZahc+A~!(o7)(N$ zlu$oulEx1TS%noA1aK74y`5IUgP7B!BOm_u^82&`gzemd2kTrWVOADo^{+9>Gmj_e zw#pEeO1*5iMPDfEh9swaZ1`txRQZ!xw$KjVO$*TVXi$;pl#vAq@=`m+3w@k z8bqY~n^?++A(#gH953I9w9v?#&vg^GAsEJd-fE+?0SKJ`(xtX6W8_#FRDiH|35ole z3wqpnL@u!Vp(w|0-18SR5plUp-(u_w4M9h87X` z!2Oh!RY*w4sx@F|`ODhcS{@=G^;v#ugnS7vfhUdwCIf$k!2jBNTYpqjQ{!o@cb+Q$ z*SyEOM1{me;zPxnNOSPkOK;rhyc~r7Q0h)S>FXHZwQT;uVpAEYO*Ph%P_nI=dgfqS zM1cDp?X9sD8<*nu@hrLyn*w96j4&GbDoPbqRq|eMZ|_{{S7sx<>#vS?nVj~`4E183 ze_1h9$UMOgw#U=c)AP%u>1nR2{V@x>trCvhmvf~I+Fu`E2HU;U(^D~YWpi;#|7vbl zX6BAU?xWbLVH#K>%t$rdrLw({UPVdCcgA;aBJ=qLc`yPThq42?&xB&}Fg{HIVT!TL z{qmo*7Og@1G`nxI{A8!y{>B);Y@Uc+&i8M#ahrxhp2KsB~V`kX&aAqBy>1M>qoC$O!;YATuZD^n32L;7bOtN3E0@iYEA4 znNC=Q2n=dTf0hRZ2DmXXQH=?`(S*U_VS{W{><{e%!vKvkq#u&Y&U0XJa86BLeuqx5 zkNU<8n*4YyCQr#AlYXz-BZo0 z601n9#-SrX$=aU+734K^JF)W0y3t4WJR?0By|uR3b+qKv zKf&dlLm@O8&CDCkQkqb>PW=@0^##Y-zYCN<*QQPfKh{>nF!QN+Nx%4V@*7kV3rU4Z z)wBXY>|C>dGEcNOFX==Yv2yyxLaHi~5fAsV^Y=fPWatcVv$0unC-A}PB7yrh3sF%~ z{(w3}z=P|CkG1t;=T5+h1}LH;9#d^GNg@dE7gdImcgZKo85tQ1eteEp<>*f*yOdeo zB@bXm-Bf*%?Bl1wk`ucIqA#|1xwsBdfnrHa7rcgs9ThS?t=dA!N(gNZ%}X2KA+7S^ z^Ea2uL`b|jOn(LHjM^kTY4_`&_pkmK2FYn`bFSIo^Y@+P7{i04@b4<;2lK&Oq5a<3 zw~19^73P?rejWj7=6fO#vNJSF75V!OxDub^_mECwwhPiu+{|AYb=gp_v$f-r_ zTQ=`5feDoIq$QS78`gL5uyAm48qgsE>W;t7=D&}Rk6&O(3x)@f)|rHnjMeTps5ai= zmCL(=#mhr*^iiL5x~H;jxQ@{+G3k_cZdWt<2en-IwmnZ#$OqPSb&;KyAzEgd6VUq_ z5IZ*{;mDjPp+*9;rCvB2BhJciJ<4Mp5@I1Q(84zI`-%)YxRbk{$}&Vhf<>98;i?1we+0fPek_LYo$W zCcs4ruo*L1%&^ss3kBAKIU9E%l#3o7##;<9rDF3=(b2qw`s z7M@()`fIqOIM4})i;@^cI#Ev0?Kt{?+nHWK0(R5lz1I@k_Ot+9haB)ZI5>Fgt}rVz z3#zHJsr@kumLhk7PEJ}zruFImuiWfaDGG64fB)CCh!#FxSi(tEl(-V!ky@R#+NXv0 z%_CA}p|qUb`8yNoyTzkxVWI?K!KR*QO<2kYFf((4GC&nW-!6PH=Z@%=u4 zgDnIdMenDBvqwUZGTmyI-{v(Y>JP;)Jc{l4o|m+Ei8tCp*58=5?VH1hF~HP6st{n_!&CpQE>2qrajOry$nKt$D?Ag z*?*{j5*x10)kUMC3AII3tm+Wiw1O$LJqfM=b2hpIh#TzxWoxV0b*0mII>D@c_^E|A zJvRRe)qGQ^DsAdSpB zXN~T&27*&dv%9v#<~nuCZrcP;O*8>ja5-<7bUk^UQ5 znQ|;@6KeP+v@*j6?G+Z-Q5DwpB947M_1NyIsI;`ScDsaA3-YEE;Iq0sj?n#!J3Yxi ze1bkY+|QSQ8ZPQaB*H&Rxe9w(9`rn-N~j@S$sF*nk@aeS&W4f(^FOh_GhkU|@ zie(20CJH`Zd2vQjwoE^=vT94}0C0s%eV z***OTQ?l}EQOr{y^}9+P$Zq|FXS3Ck0j7zQY444a7~?nHq59qw4p3?2YU5#Q)75aE z+a_3Hwz$tu8hPhMyT?ex8{bN*s=oFerm~#opihl1{tr(pO5gHNQ9}U=<-)Pk-;K^` zden16v-tMk<17Yk^TYAXF8k|SnEdHaGz~FqKMw>kX_EAxhE4adJia6siShS0CP`H~ zu_Xk54oj3Wl@NP3zvI2Z!f~oCn;y7kbP@wEy9rnO2;Ec)^k@E)ckh^qA1D5A hW$phhz4e?^&T!6_RK}=00E?EuEuFjCl_=|o{{nVkZ=nDH literal 0 HcmV?d00001 diff --git a/Weather/Resources/Icons.xcassets/01d.imageset/Contents.json b/Weather/Resources/Icons.xcassets/01d.imageset/Contents.json new file mode 100644 index 0000000..e74fc60 --- /dev/null +++ b/Weather/Resources/Icons.xcassets/01d.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "01d.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Weather/Resources/Icons.xcassets/01n.imageset/01n.png b/Weather/Resources/Icons.xcassets/01n.imageset/01n.png new file mode 100644 index 0000000000000000000000000000000000000000..b73dbfbc666622e20939af6ec11f69f7959d2d65 GIT binary patch literal 4681 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 MfV-hvtnCo>Kfo@er~m)} literal 0 HcmV?d00001 diff --git a/Weather/Resources/Icons.xcassets/01n.imageset/Contents.json b/Weather/Resources/Icons.xcassets/01n.imageset/Contents.json new file mode 100644 index 0000000..b2d72cd --- /dev/null +++ b/Weather/Resources/Icons.xcassets/01n.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "01n.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Weather/Resources/Icons.xcassets/02d.imageset/02d.png b/Weather/Resources/Icons.xcassets/02d.imageset/02d.png new file mode 100644 index 0000000000000000000000000000000000000000..fb041e0b764e83cacf16fc2b5a12d56b634883d3 GIT binary patch literal 6783 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 literal 0 HcmV?d00001 diff --git a/Weather/Resources/Icons.xcassets/02d.imageset/Contents.json b/Weather/Resources/Icons.xcassets/02d.imageset/Contents.json new file mode 100644 index 0000000..5ef9aa5 --- /dev/null +++ b/Weather/Resources/Icons.xcassets/02d.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "02d.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Weather/Resources/Icons.xcassets/02n.imageset/02n.png b/Weather/Resources/Icons.xcassets/02n.imageset/02n.png new file mode 100644 index 0000000000000000000000000000000000000000..c6de81fc48e4da4ab9613e52cf9abe2398ec970e GIT binary patch literal 5935 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 literal 0 HcmV?d00001 diff --git a/Weather/Resources/Icons.xcassets/02n.imageset/Contents.json b/Weather/Resources/Icons.xcassets/02n.imageset/Contents.json new file mode 100644 index 0000000..d81686c --- /dev/null +++ b/Weather/Resources/Icons.xcassets/02n.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "02n.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Weather/Resources/Icons.xcassets/03d.imageset/03d.png b/Weather/Resources/Icons.xcassets/03d.imageset/03d.png new file mode 100644 index 0000000000000000000000000000000000000000..b47ceff9f4586040913a0c2ddc498ac34472d7d5 GIT binary patch literal 7185 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 Mx{5Zs4rPt~AJ6t)Pyhe` literal 0 HcmV?d00001 diff --git a/Weather/Resources/Icons.xcassets/03d.imageset/Contents.json b/Weather/Resources/Icons.xcassets/03d.imageset/Contents.json new file mode 100644 index 0000000..5c3f292 --- /dev/null +++ b/Weather/Resources/Icons.xcassets/03d.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "03d.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Weather/Resources/Icons.xcassets/03n.imageset/03n.png b/Weather/Resources/Icons.xcassets/03n.imageset/03n.png new file mode 100644 index 0000000000000000000000000000000000000000..d775df3d609fcccc2806600d62259017c73f6e3b GIT binary patch literal 6295 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 Jl?a=V{{e*|la~Mh literal 0 HcmV?d00001 diff --git a/Weather/Resources/Icons.xcassets/04d.imageset/Contents.json b/Weather/Resources/Icons.xcassets/04d.imageset/Contents.json new file mode 100644 index 0000000..7aa495b --- /dev/null +++ b/Weather/Resources/Icons.xcassets/04d.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "04d.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Weather/Resources/Icons.xcassets/04n.imageset/04n.png b/Weather/Resources/Icons.xcassets/04n.imageset/04n.png new file mode 100644 index 0000000000000000000000000000000000000000..9fcb8d13695bf364aae2104e6d7a2e0fa7491c8d GIT binary patch literal 6800 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 Jl?a=V{{e*|la~Mh literal 0 HcmV?d00001 diff --git a/Weather/Resources/Icons.xcassets/04n.imageset/Contents.json b/Weather/Resources/Icons.xcassets/04n.imageset/Contents.json new file mode 100644 index 0000000..aa785f1 --- /dev/null +++ b/Weather/Resources/Icons.xcassets/04n.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "04n.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Weather/Resources/Icons.xcassets/09d.imageset/09d.png b/Weather/Resources/Icons.xcassets/09d.imageset/09d.png new file mode 100644 index 0000000000000000000000000000000000000000..6e506e951ebdec9f21423542bb1c5c78fa2e0c98 GIT binary patch literal 8158 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 R1-^?16kn^!R>+u#{15SV+g|_x literal 0 HcmV?d00001 diff --git a/Weather/Resources/Icons.xcassets/09d.imageset/Contents.json b/Weather/Resources/Icons.xcassets/09d.imageset/Contents.json new file mode 100644 index 0000000..c570396 --- /dev/null +++ b/Weather/Resources/Icons.xcassets/09d.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "09d.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Weather/Resources/Icons.xcassets/09n.imageset/09n.png b/Weather/Resources/Icons.xcassets/09n.imageset/09n.png new file mode 100644 index 0000000000000000000000000000000000000000..6e506e951ebdec9f21423542bb1c5c78fa2e0c98 GIT binary patch literal 8158 zcmWkz1ymGm7amx^r56!UY6%4v2?Zo2MY>zMyA%*uYAFGck`n1y@}nCi1rd;zPLW=^ zd;j_8oOfqt&z_xo?|b8Uo{7>>lP4vjB?16|R8c`z3p}I#zn}!*=MM>s0q}(9A)}}R z1rL9ybtHIC=&ta_1N{Be{}+x7N4gLA|o19s#TeqjHY^r zBJC1Zse1pV=jEs8WIF(5!_H~QoBbMFR_gb=&n|FMcHM=|XP#88;!hHAM+*TETUlk9 z=l5w@2S2Tkit|qlBR!}1_wP1aCWO?p(sdV1#`$L}cvs|XZEO}_o@aRsi=5BPe@shz zL{jBvv0#r&&{X{p+QHK+1-us_z^xkiJ8zGh_e@-zJMS(#EiFOp^#HaKCiIFohb~_z zI@tUqmW~Awf979{OVM`_EcK<@3U?%Y>qL^`Fq=#<_5=xqSU^`=h^6rUAre(pgv5DS zhg7j%&tPF*#zHvHo-KBJcHR^Y7qd=nPc#qDTaDcZ2tr1@aW;bwQ{E3Ib!1>h(hB)a z)aSjfxKIn+cmcZv?=2*3YHTiC9EJ^4B-qxkS2E#CP|C$9m)PM?13+hX=a zIiPFX#O)B7Hzh1R?L|^F-2ix6NKEzX){t(rz&2-5Aq~i6!_{K5DOJcI@%Z?-Wurqd zhJsL_1lePKt3XLbAWqJJjGlZ%pDcSV(fP9ScTWXn2)9@;1-E2r&zu2`sF&v#OopI_ zFGTvZoPY7&h;ueZ{?@oX+Yu(d-}cv*rZCVE==ZNciy3}QIF5(W3%i?hrVcQ~YbgQt z@BrW-pj|>t?0UYxUx`AxP^hZ&qVR0a5l-d5YaeVMqMGzbb9m&#yIR8T6airTs$_5~ zt@2ChLq^DQ!?20hLW9fxq>)>|%)!CIKw{r2L)J!S71z_L@CWUtm6DAuEyz+04*!k$ zW{;&*Ey1eJ6XdnAx{}6;Y-YFXavl79UKO6O69H(fYkR3bsw|qmxVTtNV3l7?QDK9_ zWF9vf!a)0invHpaE>E_`vq8I`8qfgZX?VdH#AYOsE@s+O_I^`!*9b38q-C2D4^Wvo zKRP;km@gmKCZ4R+ss^Q)(?dZ0m&`JcD~MvA25VGn3uko|i7~aGQ&*b!6W?6_0DP)Mo22zxJ9?p9rLvV#yxf7xz6{h0iqvD7QnGh?LM{ zcIug;r;30R^ebcmu}Uw+Hg&UAGI*FXz; zA+y~=p=exEOk8~7OIq3`@xiRJ8yXqCA@gTsFIO7vI;tQ}kZaZZwAc;)BrDdm*L#7c zd*qD%p)eNjL_z>4h@%%dnhTftJLSLBSUr^UFa&o5kq_$_CH!RG=1T5Wh}q_6 z4pUh0UJA&rcJaFr9c^>@Jv@wE+Zr#DjEk8p-4O;Nt@+YK->v=%Z8qLxcbUuDd|`&L zY1Jz6|9iQSjXgO!dWZ8jvVbu{LlIsROQL+P&18V{EDYH^D&E?IITP?*{gn_TA|i5` zef4_t6qWRDx1=ZwS!}>XT{RS@hK7rJZdUa5^_?4}ylBb18CW~o$nsrJYcHK}qyhvu z6zxw&h0iX-5snAq+%DE zJvOqQ%@=MP?eoYD**u;eqnA&ld^j;&R4Uow15|AIKALNA3qU{t;JPCiQpueA#`?(DgQkS+iE z_3O{!zg|g3&0pz6TK$Evt`ELn8r=>8u(P$p64wLD%F49{Liqi>BdWm;?jMOlwrD%- ziPT`5DA_-rJhOw^oupKon|SJHyK~+*2Y-KHa~nBl0*a?FaoM6?+e_x+kIRWs+mA*F z%L_GoTnU*%q{2~j4|8jgCy&GhCMz57F2Igj?svWyV8fQ!JoPps>znE~3J(vD_JFgU z88_x)e4R?vkWOBr!Im#?$XGBBo&esX9{&I~^@zh)uU=iVv9XyZs};c`do1OzwZy&w zF>?Rz6{%%j>4xE>)UC;WoAt&0H-F#I$9)^5JT5r&8j&T1E&xfBx1Vdv^=3 zaq+_{7o>ZSvm`6s5(7aIF>ga2Ui6jDf5#122+iW!HI~ly&kM9dA`OM1v)JM{;)|W3 z_x9=N=&q|^U3AZauHEVFl%NTpwL~j0hM@cTTb{_c4PQU*fscv^uzvL&>Svs(iNm{U zla*}n>2OCzV!aN243wXpYDg)XXO8wC=96V_FFpY~^>npW?_Gb*e+ig3h;O9HN^9Q^ zef;|yc1?TfZ)|HX{mb?IZjROl;&^y?Or?Fc{r>#63y}G^8uBvt(%-=QVsT%1D9R<( z2L)JGPj|CTy@C$Z$bpxctgNh9M^Dca0HvI)gvL9@gU=p`9mBSM>*@hyaEY63aLx=3 zK5#}c1g{AXB^dLZUs>~sv^O>Rv;~-C+tZ5V6%(T*NLzl~I17pe4sbX6>p&Bl)WRQ{ zr^94~qhwd^{3Wt8v$KO_2pH;$bK(n#`Ci@Ly^0`f?eki=exJt#aVD=e*y$b_iPz_N zkc9_lE_fc?LGLX{9k1}1ak>PTq$=QXVxJKFrOyG5J%*R!Ibrfo99%1Gv$1P;&3|(Q zCT*z?y1}Hp*4NV;;^N_Hi!_h_MX+_Bvwm0(Dn9>;#5W3-8Ik5K53cBBY-yr)J>569t9s(_?f#rSEL`g|0SzA+c z6fq5U%5^bZ^Bunb%F9g{X=!KQ)ZE*o1LODq*=}?}3q(L; z(kl~{K=jLuzF2#Ad7mZaYe}2Mlup@1X^KszB3q(l?42{uiw-Zj+L@c)fmB|} zkCBKC9RM%|0I8&bwU7;8edDPBd; zIoSA9Jc$I82O0yV0AQ8-A$Ur@5?(?>t%sSi#d zFh|ihJjqJC-X`AJvkwiG5SY`e{@K~to9%7Kw~mh644@ObQ~8#H(a6@j1sYSIzwL%8 z;Ramm%@r6B__@=wTg<&5tNAa?=8fV&jaG`ylW? zwEAn3YId&gjKN(ia;(3)wXD9_+1@T~V@-2#@?W^~RzW$0LQzY!a@ivEkYOKJ_b53U z2nI&R`0|2r_?U51-^K-h(DrzSn1;u{$+R*RwphSi*G;>=IQ~4Hamph83%eq*m z!dz)wME`~HnM%$+7LkE^gPt=_dAW64j_cJM-mZXIiS0VS<@^o*jC#M*?;rM}EHEbB z#_CG_wy-R8D@22nqy^>v`<^Eb&=Lp@X)s0>eA>9*h*8+^;Ip!_!g8e#-gT*wNGc=r zo$6;(X{f0g!GWs}bA3KvWUZr42<4k&nY!A-!^{??>UPan@tT-c9PQE$juSgynX!M~ zt1Aheb5tXgqC|P@&epq85ryyXEqptd*Dm=p$2~AR7v84&e%HfMNZA+0SwphxI@{+Eirlz(9R~FtupR?dM$xO8+m$|bqE^~fd z1GD3dS*{mtW=UEVb#Vh=1x`EGuSfT+)Pj|&tb(65Ihp=`YXuMWRq$4!Q?)tzK8iy! zL~Z`>d%VAAB)DI^l}r^B?CT4(UzZ+oz%@H5$l2&mH#}nT#0|ncQtrVnRgeZHhWVI2!WX zo!;NE;(lk}e;Rp5+__1gSyG*=@Zy|>G%NibTVOEPhUj0%b)B1`F?NvwfydQ z?{oQVyS~ZBU26Y70wCLJdAHWjFJ*^08T6T5cIh^mt@R`O(i&CHywJCQ-5pkw#7H#&XNxDwyXNNm0?Ocg)?l)`tp(0hMu8C%C}> zK^aSef61s#4@XkX1)e(n}jtaQY%ncHfP?3Fw6=;>5Kg`lUFP+S9l-crKyaudK z&qZQA#88#2vv2%n=YNhQ?&x?H8@_@w6qw$_#>Z$ z3afg4``DJJ8uXC!${0j0B!5TBH1h~EPkvp&W}M$I zfhABB25YQ$2)B77Nwn;pb}py;xcBDaWc|uMM3@O323vV7s1mODRIYSSmL;Li<$6gO zK`9fd$lOi$v$uE2b8o&`$lPj_jN7kZVT!`W%;2<83#12YJj3teOLVqjlTV%gb zw<1rud?KRe$m1}*9*E`Xwd2ck#JbbITE}l6ZE}GrD|bMh`b8@fpV}#--rU;{|;sA4NWE@ zW3^h@2;P3u;?(cNMS;&RfUTU)o=())*T>1OmW=2^fByW*_&|oa(c+SzEyMB5oL4=E;hN*HiMT&%(NnW4J8T(LLM)d|$h5 zYy0pMRhA$2r)j!om<{LK$$CK?Y`pN6XX~Ao>;=<<_O1i9eG9=2v9qyRBZnD>SkGR~ zKd>O4*8MN;#rLs>-6gt5k3_;EcZZN1Pi?r$t&wiLzI`fe9z{uGFHRyW1ZiXVe3(D= z8wH;QHWfcfbsLs3=fnBKoUohf{byu;etv)bT{CvCW$!J*#s%cU`xNwQ=-);7`hsLo zzX@vKX=0y>Pu4jh(BLxX4QYaA&2aK=L$zw}Q;GcJOc1rn*=TT~JHI>)zzTGcs zK6hpU+@*{GS=EL1OzZ%CqAE0vV(C1F&f!J+U?uB3RQSVJdJ9U`j4IcbQ^=wJ zlvlJ&r1LTxf_PwHAdUqYD9u|KJ=VwYX8ru=?=Lb)T6zh8mulX!Oy$D*#9K#ECZO7Y z3nM(ldmnkmG)qy?NzG#^e=fHtct(a7{z34gUaKkZ3)&cRMMU&0KL~Tq?vSl*{eSSO z_;?!3^TPQSB7!el^Jw4z^t>e5Wd*wW-N1ghBp*?_P6CoxU8P6UbA=4PI_D#gWIxLB zEJ^kJA6|HKCinM(f>)j#KR5pbL7l(S4?@5a+?)h(^3;Qf;2&V!YARV@Q}d46A}I3f zS5xFO(U>GtWO=A*JDi^CUe2RpB0VbW&l-vPO1hFAP_TC2%rz{z<{(PZn}PTnIv+s^ za*CLFakphp2*-ayN{l8lZ(ZH{6HbSjiAifqOUsqRF5?jU$_>*g4^ah$m(87RI}0NW z11tUy)p&HM%z-u2b>X4?`Uq4J zj(^NZ`MA@V;nl6EwlMtFIaP6s-npjTmoe6=+}*qoGow3ye-1M91ALTwM?vZx2flt< z@TBwHnfkeK|1Yn@;=wo^P$j7TZ^Jh`NvjlgW&*u}WMD@Iqez59q3X{!sI9hb$UZ$T z{g)-~$M~`LpRZPIv0Ni}Rd5cJd3i^xanh9~L#g$bHJ^O--p zCNebhURV>Q^tv{4B;Sh`7#^-Qlqdv2kav{t*>dTBH<4mpf;pG1H9los7Bgboo|IRr+gu(WiF3}@KnEmz4^e|NP?3U-) zBz(Y{?;b<%B`X5`Bn%uAqa!rV-uXqY-1Dm^nj9Z&Rivqw&a+>61{tEIQh77g+DWC< zh8qJacvUpdblqSAZn3tv52@D1T>=#pOr})9nk)i7%xd@T$;1nl{;sQNv_AKejlq`{ zp=P_DE4#w`vS;ZxBM=RCCKuVt=~1J~m{Z2rLvJ%0<&uJ(E{)%8))&{f=b9O+<4}Th ze~~jxxNyNQ;!HAtw}W^!1%?0!H0}*qhn_Cg0a8t36QJ~F_TmewNE!W^2k<;9Rx^qK zCGcZvgw5o##u(8HB58^2pj}Xug0CN63I#XzW=M8>%?MK_S94)Z!W!ti?g-JkR7Uq2{ZxqRIB~86|m#=Z1{|R^Pj915mDx*%;2W4Efem;<_SX zUM{X1q+ohLcf+n9PTl0>q=bIC9xuwfDrb!*=Q(5CKK?VC0|f0eVzr#_4KD4a;+5)u zi$LvqBQ+(Zt)M+Fmo=WeORbb4x~HbW1^YcWdY~kbXV~QurvhqI?i&+M+22B|R9ZYTA9_+EXkVzq(gneBf@PGix6P z3%O-UclcS)yzgSck8A!}3a3Nq@qIUlJI&h$wmLr*vYgVJ;vPnU8e7NKOvdp2>lfN8 zxuf>}`0EtPx0|U-=zXE|L2@MoZ(X*VA_DH@_VmY~^GZfL?B#Geo_krR^u&t{L^}tz z$j+IaObY++3zeHY{B;Q?mGAdu17dMDlt-u?Eq;9BFzdo)a;%@V0;5S5;sj$x-ay$)w`^sb#B10>fr z_f=z3O?uSI=Jq!!XL$%-Ml)C(GX`8|Jiz7I>Ho<$4QwIA!N1+8AYP{4XF+r4r5R^( z+iJ_6B>3{;+nhjPWh;3Op9ov$%4Tjrpd+6!tqAv|g?+b9O}l)ZZwoUn6U9jrl{7BO z*u+G9zh$pAYvc9-Dzsb=6EulA#r-`-XCvviWr!HDH&Vt{npW~oVNS7SYp?yN1ZouU zQDgZVuL8&^18}9+8~-1tKI@}Urf*S72=&T}ia^o@@28k(n6s@#B>+m}F@3A+yit2&a7e$Bi6jRU za6rYqVZyN${@39&fz7VW0|!-}hC*$#Pc;U17II=YH|xnrvYx)NwD^(cB#XzDCrpr8N>Is(w$qjgo*}*J*4*0iE=t_1#@Ieo(E-aGF4QhOjV;- z&3XiQx@=FrfTL>XA-|jEXh8+06-NyMSX^-+4_~QFQK?=f5VifeD;gf-DN&4e9k_#t zcjGh&%a5!!Ij3Km*z?t!4#mpVFAqMZY;j;0Z&A$8VcV!Q`&t`XP7spE`JG00rc>{U zuqAV}n!e6~d8G_3g8wN7jB zkM}yn2nLvAsLI{NzrgWd@5dl{rT^5MW{kF_SSjP?SUq)oCuBjnu4o}&zutgvj#{i@ zDEAeo8<7HBnS^tv9b80UD3jPgHRz+|Cy~Lx&N~u3^HeJ);2S*zXL{`-2-Q>Hx9}fu R1-^?16kn^!R>+u#{15SV+g|_x literal 0 HcmV?d00001 diff --git a/Weather/Resources/Icons.xcassets/09n.imageset/Contents.json b/Weather/Resources/Icons.xcassets/09n.imageset/Contents.json new file mode 100644 index 0000000..83247b9 --- /dev/null +++ b/Weather/Resources/Icons.xcassets/09n.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "09n.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Weather/Resources/Icons.xcassets/10d.imageset/10d.png b/Weather/Resources/Icons.xcassets/10d.imageset/10d.png new file mode 100644 index 0000000000000000000000000000000000000000..8ed2809ed8e8f0666fba4577f4094b8a60d8ed8a GIT binary patch literal 9071 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

rF04e(fzODXG%PpD&oY(nHA0=m` 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 literal 0 HcmV?d00001 diff --git a/Weather/Resources/Icons.xcassets/11d.imageset/Contents.json b/Weather/Resources/Icons.xcassets/11d.imageset/Contents.json new file mode 100644 index 0000000..1d885dc --- /dev/null +++ b/Weather/Resources/Icons.xcassets/11d.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "11d.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Weather/Resources/Icons.xcassets/11n.imageset/11n.png b/Weather/Resources/Icons.xcassets/11n.imageset/11n.png new file mode 100644 index 0000000000000000000000000000000000000000..87d12a7fa64b7dd3782502e76eaf5954570c5edd GIT binary patch literal 8868 zcmW++2RxLIA3ifPE7{p2;f(CjIeUa`vUg^Pm^ ze}Dh`yyNcP{e8dB^L?K0`z9M1Xi-zJQh-1pY8`ELV_=T>ZzLlHre9SYM}Qe|AXLYc z4ERKlxg-I<$)9Um1p@2O{WlUog^EIeKUrWJmM{}PH(0P^fGa3CI9TkNuUDY6<8xOr zzX125JtbBUhzq2nu4)=myc-#w$)^>H1-GD3sB`HR{QN>m3AzhuyX%QO)_sskCHDbD zImBEVk*;`qDL96Y$bIZInfj2#-<>mEirGb#wtx&Tw-YGWqm58g;Yer^&r4N?5{B~E zn_o;c1btK-UyU+{Tl~3_C{ebuDnzf~7p;P#=orx^Cb^CKBm24bu35>+N+_;yrObIhZd7d1)A>S<>3W^V6k*RQaBQrjePNg@DmT6jE~Z6-yb-dab%4R~;dJ zl4R^KafLTQC~56CKOOh82?;2IS-|pso%CKg0uZr|^evHRMgD;1}4-D--J^xAA_sy>@T6QUs|EgZH!GVXxpLp9%Q2mYV_>_|l zJw)o_S5hPIC-K==>(QM-yNj}Nav{zNC0)J##Y8z%<#tQco~;IRo~_Yuii*Myk@O+(H6gr1l>@s6KG-HBpK`$_T6=< z#eMu|{nPf2L(b`+2r(HLV;O@&qLBkS-<3>vd5Dg_27iV*1nH1H=_0W}B^x%ui zIk4Jt+<#OWt_wO>eLI{(_44rkJ#}>xlwO@meH}ylF{zN|8 zeE)g=akTac7JpX0-PnE2t-C2O2G026Y&9!=>o$7`?)2bSH~jkYj3KGv@q16mrJ-#t zZMNncrJ7IsceD7CH2GYaf=54?k~>hG;`k7OYdtacyz$=FyiI;eLP*~5lfA1rZyCjS z5^}D$F}@|L$~K$YY-0`O`c~5Kg;i}CNj?M_m${Q>vc6?i_xuP}zr4CQ>F$NED4N&x zkHouLJ*DALIO>egeApMCOD<|}_&`fjzIh7npJ829!y4uk+X^wXLkt`;rI~AVDaB1y zo7RME*SBB$>29v+%0_e)6ct^pPa8hE!dk+}HS{5Ozh=F7FbAJrYV%QCL+yoJDBS89 z-Z)H_avxJ-B97Uy`aY>G|F10Joh#GBJ1Levja;*&I92Rm^7ZdG%Hexl@lVJLAEE-Z9es zlYes|EelF#-xv%d5E6g5+3%8qBo!1Cx||2ogWnog&(T45qK4g4M}LfuM{mwIIcI#d zu2(pU5wc~60(s^sB;N-j?MrD9rgsh2VO9}C{Kyl1+R*uL(d$v?GHHWMRaI42$j*F| z7Pkb5JN};B^R=6;R7M6L^GBPs% z9!+l^m8#%>NJXcwrYTu57Lu`{#HJf9+;HL$ng36m zR;d36dz)SEZwpS8z5bqmp-D~fq)CWX`^>Wdyi2q_<5{^!;WkQ5E1mr;XEBLd1QECz zve$vV{6c0UgIOtWr3Q

rF04e(fzODXG%PpD&oY(nHA0=m` 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 literal 0 HcmV?d00001 diff --git a/Weather/Resources/Icons.xcassets/11n.imageset/Contents.json b/Weather/Resources/Icons.xcassets/11n.imageset/Contents.json new file mode 100644 index 0000000..44b0589 --- /dev/null +++ b/Weather/Resources/Icons.xcassets/11n.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "11n.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Weather/Resources/Icons.xcassets/13d.imageset/13d.png b/Weather/Resources/Icons.xcassets/13d.imageset/13d.png new file mode 100644 index 0000000000000000000000000000000000000000..a5ef4b0b18499407a29b18d978c0ee7eafdea626 GIT binary patch literal 11132 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 literal 0 HcmV?d00001 diff --git a/Weather/Resources/Icons.xcassets/13d.imageset/Contents.json b/Weather/Resources/Icons.xcassets/13d.imageset/Contents.json new file mode 100644 index 0000000..ed23bd6 --- /dev/null +++ b/Weather/Resources/Icons.xcassets/13d.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "13d.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Weather/Resources/Icons.xcassets/13n.imageset/13n.png b/Weather/Resources/Icons.xcassets/13n.imageset/13n.png new file mode 100644 index 0000000000000000000000000000000000000000..a5ef4b0b18499407a29b18d978c0ee7eafdea626 GIT binary patch literal 11132 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 literal 0 HcmV?d00001 diff --git a/Weather/Resources/Icons.xcassets/13n.imageset/Contents.json b/Weather/Resources/Icons.xcassets/13n.imageset/Contents.json new file mode 100644 index 0000000..b8a862f --- /dev/null +++ b/Weather/Resources/Icons.xcassets/13n.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "13n.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Weather/Resources/Icons.xcassets/50d.imageset/50d.png b/Weather/Resources/Icons.xcassets/50d.imageset/50d.png new file mode 100644 index 0000000000000000000000000000000000000000..f5cfebb3480e894a0002717d9f3b949d8a091a6f GIT binary patch literal 7092 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 literal 0 HcmV?d00001 diff --git a/Weather/Resources/Icons.xcassets/50d.imageset/Contents.json b/Weather/Resources/Icons.xcassets/50d.imageset/Contents.json new file mode 100644 index 0000000..7fca196 --- /dev/null +++ b/Weather/Resources/Icons.xcassets/50d.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "50d.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Weather/Resources/Icons.xcassets/50n.imageset/50n.png b/Weather/Resources/Icons.xcassets/50n.imageset/50n.png new file mode 100644 index 0000000000000000000000000000000000000000..a487066556e3c4fa1a1d65caf8f6dd87f24a9917 GIT binary patch literal 6485 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 HyO{q0;gem< literal 0 HcmV?d00001 diff --git a/Weather/Resources/Icons.xcassets/50n.imageset/Contents.json b/Weather/Resources/Icons.xcassets/50n.imageset/Contents.json new file mode 100644 index 0000000..e8aff70 --- /dev/null +++ b/Weather/Resources/Icons.xcassets/50n.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "50n.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Weather/Resources/Icons.xcassets/Contents.json b/Weather/Resources/Icons.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Weather/Resources/Icons.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Weather/Resources/Icons.xcassets/undefined.imageset/Contents.json b/Weather/Resources/Icons.xcassets/undefined.imageset/Contents.json new file mode 100644 index 0000000..7739846 --- /dev/null +++ b/Weather/Resources/Icons.xcassets/undefined.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "undefined.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Weather/Resources/Icons.xcassets/undefined.imageset/undefined.png b/Weather/Resources/Icons.xcassets/undefined.imageset/undefined.png new file mode 100644 index 0000000000000000000000000000000000000000..434ca10fefaf7c5d1a31fba514be9e820287a0a3 GIT binary patch literal 10055 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 Single + + func jsonRequest(url: URL, parameters: [String: Any]) -> Single +} + +final class NetworkComponent: NetworkService { + + enum Error: Swift.Error { + case undefinedNetworkError + } + + func request(_ url: URL) -> Single { + let request = URLRequest(url: url) + return URLSession.shared.rx.data(request: request).asSingle() + } + + func jsonRequest(url: URL, parameters: [String: Any]) -> Single { + return Single.create { singleAction -> Disposable in + let request = Alamofire.request(url, method: .get, parameters: parameters) + + request.responseData { response in + guard let data = response.data else { + let error: Swift.Error = response.error ?? Error.undefinedNetworkError + singleAction(.error(error)) + return + } + + do { + let payload = try JSONDecoder().decode(T.self, from: data) + singleAction(.success(payload)) + } catch { + assertionFailure() + singleAction(.error(error)) + } + } + + return Disposables.create { + request.cancel() + } + } + } +} diff --git a/Weather/Services/Network/NetworkServiceAssembly.swift b/Weather/Services/Network/NetworkServiceAssembly.swift new file mode 100644 index 0000000..2df9ddf --- /dev/null +++ b/Weather/Services/Network/NetworkServiceAssembly.swift @@ -0,0 +1,19 @@ +// +// NetworkServiceAssembly.swift +// Weather +// +// Created by Sergey V. Krupov on 28.01.2019. +// Copyright © 2019 Sergey V. Krupov. All rights reserved. +// + +import Swinject + +final class NetworkServiceAssembly: Assembly { + + func assemble(container: Container) { + container.register(NetworkService.self) { _ in + return NetworkComponent() + } + .inObjectScope(.container) + } +} diff --git a/Weather/Services/Settings/SettingsService.swift b/Weather/Services/Settings/SettingsService.swift new file mode 100644 index 0000000..062a607 --- /dev/null +++ b/Weather/Services/Settings/SettingsService.swift @@ -0,0 +1,72 @@ +// +// SettingsService.swift +// Weather +// +// Created by Sergey V. Krupov on 29.01.2019. +// Copyright © 2019 Sergey V. Krupov. All rights reserved. +// + +import Foundation +import RxSwift + +protocol SettingsService { + + var baseURL: URL { get } + + var secret: String { get } + + var allCities: Observable<[City]> { get } + + var currentCity: Observable { get } + + func setCurrentCityID(_ id: Int) +} + +final class SettingsComponent: SettingsService { + + let baseURL: URL = URL(string: "https://api.openweathermap.org")! + + let secret = "77abbce3f579492502ecb93387c50f1b" + + let selectedСityID = ReplaySubject.create(bufferSize: 1) + + init() { + let identifier = UserDefaults.standard.object(forKey: currentCityIDKey) as? Int + selectedСityID.onNext(identifier) + } + + var allCities: Observable<[City]> = { + return Observable.deferred { () -> Observable<[City]> in + do { + let data = try Data(contentsOf: R.file.citiesJson()!) + let cities = try JSONDecoder().decode(Array.self, from: data) + return .just(cities) + } catch { + return .error(error) + } + } + .share(replay: 1, scope: .forever) + } () + + var currentCity: Observable { + return Observable.combineLatest(allCities.asObservable(), selectedСityID.asObserver()) + .flatMap { tuple -> Maybe in + let (cities, identifier) = tuple + + guard let city = cities.first(where: { $0.id == identifier }) else { + return .just(cities.first!) + } + + return .just(city) + } + } + + func setCurrentCityID(_ id: Int) { + UserDefaults.standard.set(id, forKey: currentCityIDKey) + selectedСityID.onNext(id) + } + + // MARK: - Private + private let disposeBag = DisposeBag() + private let currentCityIDKey = "current.city.identifier" +} diff --git a/Weather/Services/Settings/SettingsServiceAssembly.swift b/Weather/Services/Settings/SettingsServiceAssembly.swift new file mode 100644 index 0000000..125d7e4 --- /dev/null +++ b/Weather/Services/Settings/SettingsServiceAssembly.swift @@ -0,0 +1,19 @@ +// +// SettingsServiceAssembly.swift +// Weather +// +// Created by Sergey V. Krupov on 29.01.2019. +// Copyright © 2019 Sergey V. Krupov. All rights reserved. +// + +import Swinject + +final class SettingsServiceAssembly: Assembly { + + func assemble(container: Container) { + container.register(SettingsService.self) { _ in + return SettingsComponent() + } + .inObjectScope(.container) + } +} diff --git a/Weather/Services/Weather/ApiResponses.swift b/Weather/Services/Weather/ApiResponses.swift new file mode 100644 index 0000000..7d6caef --- /dev/null +++ b/Weather/Services/Weather/ApiResponses.swift @@ -0,0 +1,82 @@ +// +// ApiResponse.swift +// Weather +// +// Created by Sergey V. Krupov on 28.01.2019. +// Copyright © 2019 Sergey V. Krupov. All rights reserved. +// + +import Foundation + +enum API { + + struct Weather: Decodable { + + enum RootSectionKeys: String, CodingKey { + case main + case weather + case date = "dt" + } + + enum MainSectionKeys: String, CodingKey { + case temperature = "temp" + case minTemperature = "temp_min" + case maxTemperature = "temp_max" + case pressure + case humidity + } + + enum WeatherSectionKeys: String, CodingKey { + case description + case icon + } + + init(from decoder: Decoder) throws { + let rootContainer = try decoder.container(keyedBy: RootSectionKeys.self) + date = Date(timeIntervalSince1970: try rootContainer.decode(TimeInterval.self, forKey: .date)) + + let mainContiner = try rootContainer.nestedContainer(keyedBy: MainSectionKeys.self, forKey: .main) + temperature = try mainContiner.decode(Double.self, forKey: .temperature) + minTemperature = try mainContiner.decode(Double.self, forKey: .minTemperature) + maxTemperature = try mainContiner.decode(Double.self, forKey: .maxTemperature) + pressure = try mainContiner.decode(Double.self, forKey: .pressure) + humidity = try mainContiner.decode(Double.self, forKey: .humidity) + + var list = try rootContainer.nestedUnkeyedContainer(forKey: .weather) + assert(!list.isAtEnd) + let weatherContainer = try list.nestedContainer(keyedBy: WeatherSectionKeys.self) + description = try weatherContainer.decode(String.self, forKey: .description) + icon = try weatherContainer.decode(String.self, forKey: .icon) + } + + let temperature: Double + let minTemperature: Double + let maxTemperature: Double + let pressure: Double + let humidity: Double + let date: Date + let description: String + let icon: String + } + + struct Forecast: Decodable { + + enum RootSectionKeys: String, CodingKey { + case list + } + + init(from decoder: Decoder) throws { + let rootContainer = try decoder.container(keyedBy: RootSectionKeys.self) + var list = try rootContainer.nestedUnkeyedContainer(forKey: .list) + + var items = Array() + while !list.isAtEnd { + let item = try list.decode(Weather.self) + items.append(item) + } + self.items = items + } + + let items: [Weather] + } +} diff --git a/Weather/Services/Weather/WeatherService.swift b/Weather/Services/Weather/WeatherService.swift new file mode 100644 index 0000000..fae8219 --- /dev/null +++ b/Weather/Services/Weather/WeatherService.swift @@ -0,0 +1,67 @@ +// +// WeatherService.swift +// Weather +// +// Created by Sergey V. Krupov on 28.01.2019. +// Copyright © 2019 Sergey V. Krupov. All rights reserved. +// + +import RxSwift + +protocol WeatherService { + + func obtainWeather(for city: City) -> Single + + func obtainForecast(for city: City) -> Single<[Weather]> +} + +final class WeatherComponent: WeatherService { + + // MARK: - Dependencies + var networkService: NetworkService! + var settingsService: SettingsService! + + // Текущая погода + func obtainWeather(for city: City) -> Single { + let url = settingsService.baseURL.appendingPathComponent("data/2.5/weather") + let parameters: [String: Any] = [ + "id": city.id, + "appid": settingsService.secret, + "units": "metric" + ] + + return networkService.jsonRequest(url: url, parameters: parameters) + .map { (response: API.Weather) -> Weather in + return self.mapResponse(response) + } + } + + // Прогноз на несколько дней + func obtainForecast(for city: City) -> Single<[Weather]> { + let url = settingsService.baseURL.appendingPathComponent("data/2.5/forecast") + let parameters: [String: Any] = [ + "id": city.id, + "appid": settingsService.secret, + "units": "metric" + ] + + return networkService.jsonRequest(url: url, parameters: parameters) + .map { (response: API.Forecast) -> [Weather] in + return response.items.map(self.mapResponse) + } + } + + // MARK: - Private + private func mapResponse(_ weather: API.Weather) -> Weather { + return Weather( + temperature: weather.temperature, + minTemperature: weather.minTemperature, + maxTemperature: weather.maxTemperature, + pressure: weather.pressure, + humidity: weather.humidity, + date: weather.date, + icon: weather.icon, + description: weather.description + ) + } +} diff --git a/Weather/Services/Weather/WeatherServiceAssembly.swift b/Weather/Services/Weather/WeatherServiceAssembly.swift new file mode 100644 index 0000000..802ba49 --- /dev/null +++ b/Weather/Services/Weather/WeatherServiceAssembly.swift @@ -0,0 +1,21 @@ +// +// WeatherServiceAssembly.swift +// Weather +// +// Created by Sergey V. Krupov on 28.01.2019. +// Copyright © 2019 Sergey V. Krupov. All rights reserved. +// + +import Swinject + +final class WeatherServiceAssembly: Assembly { + + func assemble(container: Container) { + container.register(WeatherService.self) { resolver in + let component = WeatherComponent() + component.networkService = resolver.resolve(NetworkService.self)! + component.settingsService = resolver.resolve(SettingsService.self)! + return component + } + } +} diff --git a/Weather/SwinjectStoryboard+Setup.swift b/Weather/SwinjectStoryboard+Setup.swift new file mode 100644 index 0000000..9ba8c7f --- /dev/null +++ b/Weather/SwinjectStoryboard+Setup.swift @@ -0,0 +1,24 @@ +// +// SwinjectStoryboard+Setup.swift +// Weather +// +// Created by Sergey V. Krupov on 28.01.2019. +// Copyright © 2019 Sergey V. Krupov. All rights reserved. +// + +import Swinject +import SwinjectStoryboard + +extension SwinjectStoryboard { + + @objc + class func setup() { + RootAssemblyContainer().assemble(container: defaultContainer) + MainAssemblyContainer().assemble(container: defaultContainer) + ForecastAssemblyContainer().assemble(container: defaultContainer) + SettingsAssemblyContainer().assemble(container: defaultContainer) + WeatherServiceAssembly().assemble(container: defaultContainer) + NetworkServiceAssembly().assemble(container: defaultContainer) + SettingsServiceAssembly().assemble(container: defaultContainer) + } +} diff --git a/Weather/Utils/Utils.swift b/Weather/Utils/Utils.swift new file mode 100644 index 0000000..a5e5089 --- /dev/null +++ b/Weather/Utils/Utils.swift @@ -0,0 +1,27 @@ +// +// Utils.swift +// Weather +// +// Created by Sergey V. Krupov on 31.01.2019. +// Copyright © 2019 Sergey V. Krupov. All rights reserved. +// + +import Foundation + +enum Utils { + + static let temperatureFormatter: NumberFormatter = { + let formatter = NumberFormatter() + formatter.maximumFractionDigits = 1 + formatter.minimumFractionDigits = 1 + formatter.minimumIntegerDigits = 1 + return formatter + } () + + static let dateFormatter: DateFormatter = { + let dateFormatter = DateFormatter() + dateFormatter.locale = Locale(identifier: "ru_RU") + dateFormatter.dateFormat = "HH:mm, dd MMMM" + return dateFormatter + } () +} diff --git a/Weather/ViewController.swift b/Weather/ViewController.swift deleted file mode 100644 index ebc0c38..0000000 --- a/Weather/ViewController.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// ViewController.swift -// Weather -// -// Created by Sergey V. Krupov on 28.01.2019. -// Copyright © 2019 Sergey V. Krupov. All rights reserved. -// - -import UIKit - -class ViewController: UIViewController { - - override func viewDidLoad() { - super.viewDidLoad() - // Do any additional setup after loading the view, typically from a nib. - } - - -} - diff --git a/viperSwift/viperSwift.rambaspec b/viperSwift/viperSwift.rambaspec new file mode 100644 index 0000000..812a482 --- /dev/null +++ b/viperSwift/viperSwift.rambaspec @@ -0,0 +1,29 @@ +# Template information section +name: "RxSwift" +summary: "ViperModule with Swinject & RxSwift" +author: "Sergey V. Krupov" +version: "0.1.2" +license: "MIT" + +# The declarations for code files + +code_files: +# Assembly +- {name: Assembly/AssemblyContainer.swift, path: Code/Assembly/assemblycontainer.swift.liquid} + +# View layer +- {name: View/ViewController.swift, path: Code/View/viewcontroller.swift.liquid} +- {name: View/ViewProtocol.swift, path: Code/View/view_protocol.swift.liquid} + +# Presenter layer +- {name: Presenter/ModuleInput.swift, path: Code/Presenter/module_input.swift.liquid} +- {name: Presenter/Presenter.swift, path: Code/Presenter/presenter.swift.liquid} +- {name: Presenter/PresenterProtocol.swift, path: Code/Presenter/presenter_protocol.swift.liquid} + +# Interactor layer +- {name: Interactor/InteractorProtocol.swift, path: Code/Interactor/interactor_protocol.swift.liquid} +- {name: Interactor/Interactor.swift, path: Code/Interactor/interactor.swift.liquid} + +# Router layer +- {name: Router/RouterProtocol.swift, path: Code/Router/router_protocol.swift.liquid} +- {name: Router/Router.swift, path: Code/Router/router.swift.liquid}