diff --git a/2020-spring/Frolov.NV/NewsAPI4/.swiftlint.yml b/2020-spring/Frolov.NV/NewsAPI4/.swiftlint.yml new file mode 100644 index 0000000..e69de29 diff --git a/2020-spring/Frolov.NV/NewsAPI4/NewsAPI.xcodeproj/project.pbxproj b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI.xcodeproj/project.pbxproj new file mode 100644 index 0000000..79aadfa --- /dev/null +++ b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI.xcodeproj/project.pbxproj @@ -0,0 +1,482 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 51; + objects = { + +/* Begin PBXBuildFile section */ + 057D1853243E624A0032D46D /* NewsRealm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 057D1852243E624A0032D46D /* NewsRealm.swift */; }; + 05868893242B64C500B68342 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05868892242B64C500B68342 /* AppDelegate.swift */; }; + 05868895242B64C500B68342 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05868894242B64C500B68342 /* SceneDelegate.swift */; }; + 05868897242B64C500B68342 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05868896242B64C500B68342 /* ViewController.swift */; }; + 0586889C242B64C700B68342 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0586889B242B64C700B68342 /* Assets.xcassets */; }; + 0586889F242B64C700B68342 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0586889D242B64C700B68342 /* LaunchScreen.storyboard */; }; + 058688A7242B65F500B68342 /* News.swift in Sources */ = {isa = PBXBuildFile; fileRef = 058688A6242B65F500B68342 /* News.swift */; }; + 058688A9242B669800B68342 /* NewsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 058688A8242B669800B68342 /* NewsService.swift */; }; + 058688AB242B67BD00B68342 /* NewsCellController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 058688AA242B67BD00B68342 /* NewsCellController.swift */; }; + 058688AD242BBD7500B68342 /* ViewControllSelectNew.swift in Sources */ = {isa = PBXBuildFile; fileRef = 058688AC242BBD7500B68342 /* ViewControllSelectNew.swift */; }; + 0589AA612461A4F000ABEDCE /* AnimationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0589AA602461A4F000ABEDCE /* AnimationViewController.swift */; }; + 0592ECEC243E6A170070D530 /* NewsRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0592ECEB243E6A170070D530 /* NewsRepository.swift */; }; + 0592ECEE243E71480070D530 /* NewsFacade.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0592ECED243E71480070D530 /* NewsFacade.swift */; }; + 059CE08D24532EF100874BBF /* CountryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 059CE08C24532EF100874BBF /* CountryViewController.swift */; }; + 059CE09524533A2B00874BBF /* Country.swift in Sources */ = {isa = PBXBuildFile; fileRef = 059CE09424533A2B00874BBF /* Country.swift */; }; + 059CE09724583FF500874BBF /* CountryCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 059CE09624583FF500874BBF /* CountryCell.swift */; }; + 05DDF3E624589DCB00D0A21A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 05DDF3E424589DCA00D0A21A /* Main.storyboard */; }; + 05DDF3E82459789100D0A21A /* FavoriteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05DDF3E72459789100D0A21A /* FavoriteViewController.swift */; }; + 0FA90A1C28CBD56B9EFBAF85 /* Pods_NewsAPI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73E78E9F85F25AC48B8F467A /* Pods_NewsAPI.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 057D1852243E624A0032D46D /* NewsRealm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewsRealm.swift; sourceTree = ""; }; + 0586888F242B64C500B68342 /* NewsAPI.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = NewsAPI.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 05868892242B64C500B68342 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 05868894242B64C500B68342 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + 05868896242B64C500B68342 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + 0586889B242B64C700B68342 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 0586889E242B64C700B68342 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 058688A0242B64C700B68342 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 058688A6242B65F500B68342 /* News.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = News.swift; sourceTree = ""; }; + 058688A8242B669800B68342 /* NewsService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewsService.swift; sourceTree = ""; }; + 058688AA242B67BD00B68342 /* NewsCellController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewsCellController.swift; sourceTree = ""; }; + 058688AC242BBD7500B68342 /* ViewControllSelectNew.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewControllSelectNew.swift; sourceTree = ""; }; + 0589AA602461A4F000ABEDCE /* AnimationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnimationViewController.swift; sourceTree = ""; }; + 0592ECEB243E6A170070D530 /* NewsRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewsRepository.swift; sourceTree = ""; }; + 0592ECED243E71480070D530 /* NewsFacade.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewsFacade.swift; sourceTree = ""; }; + 059CE08C24532EF100874BBF /* CountryViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CountryViewController.swift; sourceTree = ""; }; + 059CE09424533A2B00874BBF /* Country.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Country.swift; sourceTree = ""; }; + 059CE09624583FF500874BBF /* CountryCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CountryCell.swift; sourceTree = ""; }; + 05DDF3E524589DCA00D0A21A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 05DDF3E72459789100D0A21A /* FavoriteViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoriteViewController.swift; sourceTree = ""; }; + 325DCD35B3C1F9329FCF83CF /* Pods-NewsAPI.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewsAPI.release.xcconfig"; path = "Target Support Files/Pods-NewsAPI/Pods-NewsAPI.release.xcconfig"; sourceTree = ""; }; + 73E78E9F85F25AC48B8F467A /* Pods_NewsAPI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_NewsAPI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + C41CB685131D4139C5ECE494 /* Pods-NewsAPI.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewsAPI.debug.xcconfig"; path = "Target Support Files/Pods-NewsAPI/Pods-NewsAPI.debug.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 0586888C242B64C500B68342 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 0FA90A1C28CBD56B9EFBAF85 /* Pods_NewsAPI.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 05868886242B64C500B68342 = { + isa = PBXGroup; + children = ( + 05868891242B64C500B68342 /* NewsAPI */, + 05868890242B64C500B68342 /* Products */, + D73A9B65F4C846F030FB6B96 /* Pods */, + BA0822C4ABD5CE9E0CF3356E /* Frameworks */, + ); + sourceTree = ""; + }; + 05868890242B64C500B68342 /* Products */ = { + isa = PBXGroup; + children = ( + 0586888F242B64C500B68342 /* NewsAPI.app */, + ); + name = Products; + sourceTree = ""; + }; + 05868891242B64C500B68342 /* NewsAPI */ = { + isa = PBXGroup; + children = ( + 05868892242B64C500B68342 /* AppDelegate.swift */, + 05868894242B64C500B68342 /* SceneDelegate.swift */, + 05868896242B64C500B68342 /* ViewController.swift */, + 0586889B242B64C700B68342 /* Assets.xcassets */, + 0586889D242B64C700B68342 /* LaunchScreen.storyboard */, + 05DDF3E424589DCA00D0A21A /* Main.storyboard */, + 058688A0242B64C700B68342 /* Info.plist */, + 058688A6242B65F500B68342 /* News.swift */, + 058688A8242B669800B68342 /* NewsService.swift */, + 058688AA242B67BD00B68342 /* NewsCellController.swift */, + 058688AC242BBD7500B68342 /* ViewControllSelectNew.swift */, + 057D1852243E624A0032D46D /* NewsRealm.swift */, + 0592ECEB243E6A170070D530 /* NewsRepository.swift */, + 0592ECED243E71480070D530 /* NewsFacade.swift */, + 059CE08C24532EF100874BBF /* CountryViewController.swift */, + 059CE09424533A2B00874BBF /* Country.swift */, + 059CE09624583FF500874BBF /* CountryCell.swift */, + 05DDF3E72459789100D0A21A /* FavoriteViewController.swift */, + 0589AA602461A4F000ABEDCE /* AnimationViewController.swift */, + ); + path = NewsAPI; + sourceTree = ""; + }; + BA0822C4ABD5CE9E0CF3356E /* Frameworks */ = { + isa = PBXGroup; + children = ( + 73E78E9F85F25AC48B8F467A /* Pods_NewsAPI.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + D73A9B65F4C846F030FB6B96 /* Pods */ = { + isa = PBXGroup; + children = ( + C41CB685131D4139C5ECE494 /* Pods-NewsAPI.debug.xcconfig */, + 325DCD35B3C1F9329FCF83CF /* Pods-NewsAPI.release.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 0586888E242B64C500B68342 /* NewsAPI */ = { + isa = PBXNativeTarget; + buildConfigurationList = 058688A3242B64C700B68342 /* Build configuration list for PBXNativeTarget "NewsAPI" */; + buildPhases = ( + 3D0D2D19C5D655F8A9FFF159 /* [CP] Check Pods Manifest.lock */, + 0586888B242B64C500B68342 /* Sources */, + 0586888C242B64C500B68342 /* Frameworks */, + 0586888D242B64C500B68342 /* Resources */, + E6BFE8756AFAF8DA6B0BA631 /* [CP] Embed Pods Frameworks */, + 059C1BCC244A235B00DB1BFE /* Errors */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = NewsAPI; + productName = NewsAPI; + productReference = 0586888F242B64C500B68342 /* NewsAPI.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 05868887242B64C500B68342 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1130; + LastUpgradeCheck = 1130; + ORGANIZATIONNAME = "Никита Фролов "; + TargetAttributes = { + 0586888E242B64C500B68342 = { + CreatedOnToolsVersion = 11.3.1; + }; + }; + }; + buildConfigurationList = 0586888A242B64C500B68342 /* Build configuration list for PBXProject "NewsAPI" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 05868886242B64C500B68342; + productRefGroup = 05868890242B64C500B68342 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 0586888E242B64C500B68342 /* NewsAPI */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 0586888D242B64C500B68342 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 05DDF3E624589DCB00D0A21A /* Main.storyboard in Resources */, + 0586889F242B64C700B68342 /* LaunchScreen.storyboard in Resources */, + 0586889C242B64C700B68342 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 059C1BCC244A235B00DB1BFE /* Errors */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = Errors; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = " + +"; + }; + 3D0D2D19C5D655F8A9FFF159 /* [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-NewsAPI-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; + }; + E6BFE8756AFAF8DA6B0BA631 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-NewsAPI/Pods-NewsAPI-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-NewsAPI/Pods-NewsAPI-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-NewsAPI/Pods-NewsAPI-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 0586888B242B64C500B68342 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 057D1853243E624A0032D46D /* NewsRealm.swift in Sources */, + 058688A9242B669800B68342 /* NewsService.swift in Sources */, + 059CE08D24532EF100874BBF /* CountryViewController.swift in Sources */, + 05868897242B64C500B68342 /* ViewController.swift in Sources */, + 059CE09524533A2B00874BBF /* Country.swift in Sources */, + 05868893242B64C500B68342 /* AppDelegate.swift in Sources */, + 058688A7242B65F500B68342 /* News.swift in Sources */, + 058688AB242B67BD00B68342 /* NewsCellController.swift in Sources */, + 0592ECEE243E71480070D530 /* NewsFacade.swift in Sources */, + 05868895242B64C500B68342 /* SceneDelegate.swift in Sources */, + 05DDF3E82459789100D0A21A /* FavoriteViewController.swift in Sources */, + 058688AD242BBD7500B68342 /* ViewControllSelectNew.swift in Sources */, + 0589AA612461A4F000ABEDCE /* AnimationViewController.swift in Sources */, + 059CE09724583FF500874BBF /* CountryCell.swift in Sources */, + 0592ECEC243E6A170070D530 /* NewsRepository.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 0586889D242B64C700B68342 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 0586889E242B64C700B68342 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; + 05DDF3E424589DCA00D0A21A /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 05DDF3E524589DCA00D0A21A /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 058688A1242B64C700B68342 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.2; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 058688A2242B64C700B68342 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.2; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 058688A4242B64C700B68342 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = C41CB685131D4139C5ECE494 /* Pods-NewsAPI.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 35TH4M5TLF; + INFOPLIST_FILE = NewsAPI/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = Com.NewsAPI; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 058688A5242B64C700B68342 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 325DCD35B3C1F9329FCF83CF /* Pods-NewsAPI.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 35TH4M5TLF; + INFOPLIST_FILE = NewsAPI/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = Com.NewsAPI; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 0586888A242B64C500B68342 /* Build configuration list for PBXProject "NewsAPI" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 058688A1242B64C700B68342 /* Debug */, + 058688A2242B64C700B68342 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 058688A3242B64C700B68342 /* Build configuration list for PBXNativeTarget "NewsAPI" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 058688A4242B64C700B68342 /* Debug */, + 058688A5242B64C700B68342 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 05868887242B64C500B68342 /* Project object */; +} diff --git a/2020-spring/Frolov.NV/NewsAPI4/NewsAPI.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..d86dd1f --- /dev/null +++ b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/2020-spring/Frolov.NV/NewsAPI4/NewsAPI.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/2020-spring/Frolov.NV/NewsAPI4/NewsAPI.xcworkspace/contents.xcworkspacedata b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..67aca0a --- /dev/null +++ b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/2020-spring/Frolov.NV/NewsAPI4/NewsAPI.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/AnimationViewController.swift b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/AnimationViewController.swift new file mode 100644 index 0000000..65b6b4e --- /dev/null +++ b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/AnimationViewController.swift @@ -0,0 +1,39 @@ +// +// AnimationViewController.swift +// NewsAPI +// +// Created by Никита Фролов on 05.05.2020. +// Copyright © 2020 Никита Фролов . All rights reserved. +// + +import UIKit +import CoreGraphics + +class AnimationViewController:UIViewController { + override func viewDidLoad() { + super.viewDidLoad() + + let view = UIView(frame: CGRect(x: 100, y: 20, width: 200, height: 200)) + view.backgroundColor = UIColor.black + + let shadowView = UIView(frame: CGRect(x: 50, y: 20, width: 220, height: 220)) + shadowView.layer.shadowColor = UIColor.black.cgColor + shadowView.layer.shadowOpacity = 1 + shadowView.layer.shadowRadius = 10 + shadowView.layer.shadowOffset = CGSize.zero + + shadowView.addSubview(view) + self.view.addSubview(shadowView) + UIView.animate(withDuration: 1, + delay: 0, + options: [UIView.AnimationOptions.autoreverse, UIView.AnimationOptions.repeat], + animations: { + view.backgroundColor = UIColor.red + shadowView.frame = CGRect( + origin: CGPoint(x: 100, y: 500), + size: view.frame.size + ) + }, + completion: nil) + } +} diff --git a/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/AppDelegate.swift b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/AppDelegate.swift new file mode 100644 index 0000000..614222f --- /dev/null +++ b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/AppDelegate.swift @@ -0,0 +1,14 @@ +// +// AppDelegate.swift +// NewsAPI +// +// Created by Никита Фролов on 25.03.2020. +// Copyright © 2020 Никита Фролов . All rights reserved. +// + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { +} + diff --git a/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/Assets.xcassets/AppIcon.appiconset/Contents.json b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d8db8d6 --- /dev/null +++ b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/Assets.xcassets/Contents.json b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/Base.lproj/LaunchScreen.storyboard b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..865e932 --- /dev/null +++ b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/Base.lproj/Main.storyboard b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/Base.lproj/Main.storyboard new file mode 100644 index 0000000..cb106ec --- /dev/null +++ b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/Base.lproj/Main.storyboard @@ -0,0 +1,334 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/Country.swift b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/Country.swift new file mode 100644 index 0000000..d23af27 --- /dev/null +++ b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/Country.swift @@ -0,0 +1,19 @@ +// +// Country.swift +// NewsAPI +// +// Created by Никита Фролов on 24.04.2020. +// Copyright © 2020 Никита Фролов . All rights reserved. +// + +import Foundation + +final class Country { + public var countryName:String + public var countyForUrl:String + + init(name: String, url:String) { + countryName = name + countyForUrl = url + } +} diff --git a/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/CountryCell.swift b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/CountryCell.swift new file mode 100644 index 0000000..deda9f8 --- /dev/null +++ b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/CountryCell.swift @@ -0,0 +1,18 @@ +// +// CountryCell.swift +// NewsAPI +// +// Created by Никита Фролов on 28.04.2020. +// Copyright © 2020 Никита Фролов . All rights reserved. +// + +import UIKit + + +class CountryCell:UITableViewCell { + @IBOutlet var countryLabel:UILabel! + + func insert(string:String) { + countryLabel.text = string + } +} diff --git a/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/CountryViewController.swift b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/CountryViewController.swift new file mode 100644 index 0000000..f2f8405 --- /dev/null +++ b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/CountryViewController.swift @@ -0,0 +1,52 @@ + + +import UIKit + +class CountryViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { + @IBOutlet var tableView:UITableView! + private var countryArray:[Country] = [ + Country(name: "United Arab Emirates", url: "ae"), + Country(name: "Argentina", url: "ar"), + Country(name: "Austria", url: "at"), + Country(name: "Australia", url: "au"), + Country(name: "Belgium", url: "be"), + Country(name: "Bulgaria", url: "bg"), + Country(name: "Brazil", url: "br"), + Country(name: "Colombia", url: "co"), + Country(name: "Germany", url: "de"), + Country(name: "France", url: "fr"), + Country(name: "Russia", url: "ru"), + Country(name: "USA", url: "us"), + Country(name: "South Africa", url: "za"), + Country(name: "Venezuela", url: "ve"), + Country(name: "Slovakia", url: "sk") + ] + + override func viewDidLoad() { + super.viewDidLoad() + countryArray.sort{$0.countryName < $1.countryName} + tableView.dataSource = self + tableView.delegate = self + } + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + (segue.destination as? ViewController)?.country = countryArray[tableView.indexPathForSelectedRow!.row].countyForUrl + tableView.deselectRow(at: tableView.indexPathForSelectedRow!, animated: true) + } + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + performSegue(withIdentifier: "CountryCell", sender: self) + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return countryArray.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "CountryCell", for: indexPath) + guard let newCell = cell as? CountryCell else {fatalError("Non casting to CountryCell")} + let country = countryArray[indexPath.row] + newCell.insert(string: country.countryName) + return newCell + } +} diff --git a/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/FavoriteViewController.swift b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/FavoriteViewController.swift new file mode 100644 index 0000000..ea1842c --- /dev/null +++ b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/FavoriteViewController.swift @@ -0,0 +1,108 @@ +// +// FavoriteViewController.swift +// NewsAPI +// +// Created by Никита Фролов on 29.04.2020. +// Copyright © 2020 Никита Фролов . All rights reserved. +// + +import UIKit + +class FavoriteViewController:UIViewController, UITableViewDataSource, UITableViewDelegate, UISearchResultsUpdating, UISearchBarDelegate{ + + @IBOutlet var tableView: UITableView! + + var searchController = UISearchController(searchResultsController: nil) + let refreshControl = UIRefreshControl() + var news = [OneNew]() + var searchingNews = [OneNew]() + var newsFacade:NewsFacade! + + override func viewDidLoad() { + super.viewDidLoad() + newsFacade = NewsFacade(string: "") + refresh(newsFacade) + + refreshControl.tintColor = UIColor(red:0.25, green:0.72, blue:0.85, alpha:1.0) + refreshControl.attributedTitle = NSAttributedString(string: "Reload News, please wait...") + refreshControl.addTarget(self, action: #selector(refresh), for: UIControl.Event.valueChanged) + + searchController.searchResultsUpdater = self + searchController.obscuresBackgroundDuringPresentation = false + searchController.searchBar.placeholder = "Search News" + navigationItem.searchController = searchController + definesPresentationContext = true + searchController.searchBar.delegate = self + + tableView.dataSource = self + tableView.delegate = self + tableView.refreshControl = refreshControl + tableView.rowHeight = 307 + } + + @objc func refresh(_:AnyObject) { + newsFacade.getFavoriteNews(completion: {(newsArray) in + guard let newsArray = newsArray else {return} + self.news = newsArray + DispatchQueue.main.async { + self.tableView.reloadData() + } + self.refreshControl.endRefreshing() + }) + } + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + (segue.destination as? ViewControllSelectNew)?.news = news[tableView.indexPathForSelectedRow!.row] + tableView.deselectRow(at: tableView.indexPathForSelectedRow!, animated: true) + } + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + performSegue(withIdentifier: "OneNews", sender: self) + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + if (isFiltering) { + return searchingNews.count + } + return news.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "OneNews", for: indexPath) + guard let newsCell = cell as? NewsTableViewCell else { + fatalError("Table view is not configured") + } + if (isFiltering) { + let oneNew = searchingNews[indexPath.row] + newsCell.insert(with: oneNew) + return newsCell + } + let oneNews = news[indexPath.row] + newsCell.insert(with: oneNews) + return newsCell + } + + var isSearchBarEmpty: Bool { + return searchController.searchBar.text?.isEmpty ?? true + } + + var isFiltering: Bool { + return searchController.isActive && !isSearchBarEmpty + } + + func updateSearchResults(for searchController: UISearchController) { + let searchBar = searchController.searchBar + searchingNews = news.filter({$0.title!.prefix(searchBar.text!.count) == Substring(searchBar.text ?? "")}) + tableView.reloadData() + } + + func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? { + let delete = UITableViewRowAction(style: .destructive, title: "delete") {_, indexPath in + self.newsFacade.deleteFromFavorite(news: self.news[indexPath.row]) + //self.news.remove(at: indexPath.row) + self.tableView.reloadRows(at: [indexPath], with: .automatic) + self.refresh(self.newsFacade) + } + return [delete] + } +} diff --git a/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/Info.plist b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/Info.plist new file mode 100644 index 0000000..2a3483c --- /dev/null +++ b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/Info.plist @@ -0,0 +1,64 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/News.swift b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/News.swift new file mode 100644 index 0000000..e1fcf2c --- /dev/null +++ b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/News.swift @@ -0,0 +1,20 @@ +// +// News.swift +// NewsAPI +// +// Created by Никита Фролов on 25.03.2020. +// Copyright © 2020 Никита Фролов . All rights reserved. +// + +import Foundation + +struct Articals: Decodable { + let articles:[T] +} + +struct OneNew: Decodable { + let title: String? + let urlToImage: String? + let author: String? + let description: String? +} diff --git a/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/NewsCellController.swift b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/NewsCellController.swift new file mode 100644 index 0000000..18c0c3f --- /dev/null +++ b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/NewsCellController.swift @@ -0,0 +1,29 @@ +// +// NewsCellController.swift +// NewsAPI +// +// Created by Никита Фролов on 25.03.2020. +// Copyright © 2020 Никита Фролов . All rights reserved. +// + +import UIKit +import Kingfisher + +class NewsTableViewCell: UITableViewCell { + @IBOutlet var titleLabel:UILabel! + @IBOutlet var imageNewsView:UIImageView! + private var loadTask: URLSessionTask? + + override func prepareForReuse() { + super.prepareForReuse() + loadTask?.cancel() + //imageNewsView = nil + } + + func insert(with new: OneNew) { + titleLabel.text = new.title + guard let imageUrl = URL(string: new.urlToImage ?? "") else {return} + imageNewsView.kf.setImage(with: imageUrl) + } +} + diff --git a/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/NewsFacade.swift b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/NewsFacade.swift new file mode 100644 index 0000000..2545eb8 --- /dev/null +++ b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/NewsFacade.swift @@ -0,0 +1,76 @@ +// +// NewsFacade.swift +// NewsAPI +// +// Created by Никита Фролов on 08.04.2020. +// Copyright © 2020 Никита Фролов . All rights reserved. +// + +import Foundation +import RealmSwift + + +final class NewsFacade { + private let newsService:NewsService! + private let newRepository = NewsRepositoryImpl() + private var newsToken: NotificationToken? + private var country:String + + init(string:String) { + country = string + newsService = NewsService(string: country) + } + + func getNews(completion: @escaping ([OneNew]?)-> Void) { + newsService.getNews { (newsArray) in + guard let news = newsArray else {return} + self.newRepository.installCountry(string: self.country) + self.newRepository.save(news) + } + let newsArray = newRepository.getNews() + var newsArr = [NewsRealm]() + for i in 0.. Void) { + let newsArray = newRepository.getNews() + var newsArr = [NewsRealm]() + for i in 0.. Void) { + //newRepository.cleare() + getNews(completion: completion) + } + + func loadMore() { + newsService.getMoreNews {(newsArray) in + guard let news = newsArray else {return} + self.newRepository.save(news) + } + } +} diff --git a/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/NewsRealm.swift b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/NewsRealm.swift new file mode 100644 index 0000000..5b8babc --- /dev/null +++ b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/NewsRealm.swift @@ -0,0 +1,48 @@ +// +// NewsRealm.swift +// NewsAPI +// +// Created by Никита Фролов on 08.04.2020. +// Copyright © 2020 Никита Фролов . All rights reserved. +// + +import RealmSwift + +class NewsRealm: Object { + @objc dynamic var title = "" + @objc dynamic var image = "" + @objc dynamic var author = "" + @objc dynamic var descriptionNews = "" + @objc dynamic var country = "" + @objc dynamic var favorite = false + override class func primaryKey() -> String? { + "title" + } +} + + +extension NewsRealm { + convenience init (news:OneNew) { + self.init() + title = news.title ?? "" + author = news.author ?? "" + descriptionNews = news.description ?? "" + image = news.urlToImage ?? "" + } + + func installCountry(string: String) { + country = string + } + + func changeFlag() { + if (favorite == false) { + favorite = true + } else { + favorite = false + } + } + + var news:OneNew { + OneNew(title: title, urlToImage: image, author: author, description: descriptionNews) + } +} diff --git a/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/NewsRepository.swift b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/NewsRepository.swift new file mode 100644 index 0000000..a69a038 --- /dev/null +++ b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/NewsRepository.swift @@ -0,0 +1,56 @@ +// +// NewsRepository.swift +// NewsAPI +// +// Created by Никита Фролов on 08.04.2020. +// Copyright © 2020 Никита Фролов . All rights reserved. +// + +import RealmSwift + +protocol NewsRepository { + func save(_ news:[OneNew]) + func getNews()-> Results +} + +final class NewsRepositoryImpl: NewsRepository { + + private var realm:Realm { + do { + return try Realm() + } catch { + fatalError("Can't create realm") + } + } + + private var country = "" + func installCountry(string: String) { + country = string + } + + + func save(_ news: [OneNew]) { + let news = news.map{ NewsRealm(news: $0) } + news.forEach({$0.installCountry(string: self.country)}) + try? realm.write{ + realm.add(news, update: .modified) + } + } + + func changeFavoriteStatus(news: OneNew) { + try? realm.write { + let newsArray = realm.objects(NewsRealm.self).filter({$0.title == news.title}).first + newsArray?.changeFlag() + } + } + + func cleare() { + try? realm.write{ + realm.deleteAll() + } + } + + func getNews() -> Results { + realm.objects(NewsRealm.self) + } +} diff --git a/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/NewsService.swift b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/NewsService.swift new file mode 100644 index 0000000..5b72ee9 --- /dev/null +++ b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/NewsService.swift @@ -0,0 +1,94 @@ +// +// NewsService.swift +// NewsAPI +// +// Created by Никита Фролов on 25.03.2020. +// Copyright © 2020 Никита Фролов . All rights reserved. +// + +import Foundation + + +class NewsService { + private var pageNumber:Int = 1; + + private var urlComponents = URLComponents(string: "https://newsapi.org") + private var nextUrl: URL? + private let calendary = Calendar.current + private let date = Date() + var day:Int + var month:Int + var year:Int + private var country:String + + init(string:String) { + country = string + day = calendary.component(.day, from: date) + month = calendary.component(.month, from: date) + year = calendary.component(.year, from: date) + } + + public func getNews(completion: @escaping ([OneNew]?)-> Void) { + urlComponents?.path = "/v2/top-headlines" + let dayF = day + let monthF = month + let yearF = year + if (day == 1) { + if (month == 1) { + year = year - 1 + } else { + month = month - 1 + } + } else { + day = day - 1 + } + urlComponents?.queryItems = [ + URLQueryItem(name: "country", value: country), + URLQueryItem(name: "apiKey", value: "e5a2d92c79b74e8aa40a9e618e6a1998"), + URLQueryItem(name: "from", value: "\(yearF)-\(monthF)-\(dayF)"), + URLQueryItem(name: "to", value: "\(year)-\(month)-\(day)") + ] + guard let url = urlComponents?.url else { + completion(nil) + return + } + getNews(url: url,completion: completion) + } + + public func getMoreNews(complition: @escaping ([OneNew]?)-> Void) { + guard let url = nextUrl else { + complition(nil) + return + } + getNews(url: url, completion: complition) + } + + private func getNextPage()-> URL{ + if (day == 1) { + if (month == 1) { + year = year - 1 + } else { + month = month - 1 + } + } else { + day = day - 1 + } + urlComponents?.queryItems?[3].value = String("\(year)-\(month)-\(day)") + guard let newUrl = urlComponents?.url else { + fatalError() + } + return newUrl + } + + private func getNews(url: URL, completion: @escaping ([OneNew]?)->Void) { + URLSession.shared.dataTask(with: url) { (data, response, error) in + guard let data = data else { + completion(nil) + return + } + let articals = try? JSONDecoder().decode(Articals.self, from: data) + self.nextUrl = self.getNextPage() + completion(articals?.articles) + }.resume() + } +} diff --git a/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/SceneDelegate.swift b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/SceneDelegate.swift new file mode 100644 index 0000000..e8624a5 --- /dev/null +++ b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/SceneDelegate.swift @@ -0,0 +1,16 @@ +// +// SceneDelegate.swift +// NewsAPI +// +// Created by Никита Фролов on 25.03.2020. +// Copyright © 2020 Никита Фролов . All rights reserved. +// + +import UIKit + +class SceneDelegate: UIResponder, UIWindowSceneDelegate { + + var window: UIWindow? + +} + diff --git a/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/ViewControllSelectNew.swift b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/ViewControllSelectNew.swift new file mode 100644 index 0000000..4ea4454 --- /dev/null +++ b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/ViewControllSelectNew.swift @@ -0,0 +1,32 @@ +// +// ViewControllSelectNew.swift +// NewsAPI +// +// Created by Никита Фролов on 25.03.2020. +// Copyright © 2020 Никита Фролов . All rights reserved. +// + +import UIKit +import Kingfisher + +class ViewControllSelectNew: UIViewController { + @IBOutlet var imageNews:UIImageView! + @IBOutlet var labelNewsTitle:UILabel! + @IBOutlet var labelNewsAuthor:UILabel! + @IBOutlet var labelNewsDiscription:UILabel! + private var imageLoadTask: URLSessionTask? + + var news:OneNew! + + override func viewDidLoad() { + super.viewDidLoad() + + labelNewsTitle.text = news.title + labelNewsAuthor.text = news.author + labelNewsDiscription.text = news.description + + guard let imageUrl = URL(string: news.urlToImage ?? "") else {return} + imageNews.kf.setImage(with: imageUrl) + } + +} diff --git a/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/ViewController.swift b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/ViewController.swift new file mode 100644 index 0000000..1a4ad17 --- /dev/null +++ b/2020-spring/Frolov.NV/NewsAPI4/NewsAPI/ViewController.swift @@ -0,0 +1,115 @@ +// +// ViewController.swift +// NewsAPI +// +// Created by Никита Фролов on 25.03.2020. +// Copyright © 2020 Никита Фролов . All rights reserved. +// + +import UIKit + +class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate, +UISearchResultsUpdating{ + @IBOutlet var tableView: UITableView! + + var searchController = UISearchController(searchResultsController: nil) + var news = [OneNew]() + var searchingNews = [OneNew]() + let refreshControl = UIRefreshControl() + var country:String! + var newsFacade:NewsFacade! + + override func viewDidLoad() { + super.viewDidLoad() + newsFacade = NewsFacade(string: country) + refresh(newsFacade) + refreshControl.tintColor = UIColor(red:0.25, green:0.72, blue:0.85, alpha:1.0) + refreshControl.attributedTitle = NSAttributedString(string: "Reload News, please wait...") + refreshControl.addTarget(self, action: #selector(refresh), for: UIControl.Event.valueChanged) + + searchController.searchResultsUpdater = self + searchController.obscuresBackgroundDuringPresentation = false + searchController.searchBar.placeholder = "Search News" + navigationItem.searchController = searchController + navigationItem.title = "Favorite News" + definesPresentationContext = true + searchController.searchBar.delegate = self + + tableView.dataSource = self + tableView.delegate = self + tableView.refreshControl = refreshControl + tableView.rowHeight = 307 + } + + @objc func refresh(_:AnyObject) { + newsFacade.reload(completion: {(newsArray) in + guard let newsArray = newsArray else {return} + self.news = newsArray + DispatchQueue.main.async { + self.tableView.reloadData() + } + self.refreshControl.endRefreshing() + }) + } + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + (segue.destination as? ViewControllSelectNew)?.news = news[tableView.indexPathForSelectedRow!.row] + tableView.deselectRow(at: tableView.indexPathForSelectedRow!, animated: true) + } + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + performSegue(withIdentifier: "OneNews", sender: self) + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + if (isFiltering) { + return searchingNews.count + } + return news.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "OneNews", for: indexPath) + guard let newsCell = cell as? NewsTableViewCell else { + fatalError("Table view is not configured") + } + if (isFiltering) { + let oneNew = searchingNews[indexPath.row] + newsCell.insert(with: oneNew) + return newsCell + } + let oneNews = news[indexPath.row] + newsCell.insert(with: oneNews) + return newsCell + } + + func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { + guard indexPath.row == news.count - 1 else { + return + } + newsFacade.loadMore() + } + + var isSearchBarEmpty: Bool { + return searchController.searchBar.text?.isEmpty ?? true + } + + var isFiltering: Bool { + return searchController.isActive && !isSearchBarEmpty + } + + func updateSearchResults(for searchController: UISearchController) { + let searchBar = searchController.searchBar + searchingNews = news.filter({$0.title!.prefix(searchBar.text!.count) == Substring(searchBar.text ?? "")}) + tableView.reloadData() + } + + func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? { + let edit = UITableViewRowAction(style: .normal, title: "Favorite") {_, indexPath in + self.newsFacade.getToFavoriteList(news: self.news[indexPath.row]) + } + return [edit] + } + +} + diff --git a/2020-spring/Frolov.NV/NewsAPI4/Podfile b/2020-spring/Frolov.NV/NewsAPI4/Podfile new file mode 100644 index 0000000..0f543e6 --- /dev/null +++ b/2020-spring/Frolov.NV/NewsAPI4/Podfile @@ -0,0 +1,12 @@ +# Uncomment the next line to define a global platform for your project +# platform :ios, '9.0' + +target 'NewsAPI' do + # Comment the next line if you don't want to use dynamic frameworks + use_frameworks! + pod 'RealmSwift' + pod 'Kingfisher' + pod 'SwiftLint' + # Pods for NewsAPI + +end diff --git a/2020-spring/Frolov.NV/NewsAPI4/Podfile.lock b/2020-spring/Frolov.NV/NewsAPI4/Podfile.lock new file mode 100644 index 0000000..fb5818c --- /dev/null +++ b/2020-spring/Frolov.NV/NewsAPI4/Podfile.lock @@ -0,0 +1,32 @@ +PODS: + - Kingfisher (5.13.4): + - Kingfisher/Core (= 5.13.4) + - Kingfisher/Core (5.13.4) + - Realm (4.4.0): + - Realm/Headers (= 4.4.0) + - Realm/Headers (4.4.0) + - RealmSwift (4.4.0): + - Realm (= 4.4.0) + - SwiftLint (0.39.2) + +DEPENDENCIES: + - Kingfisher + - RealmSwift + - SwiftLint + +SPEC REPOS: + trunk: + - Kingfisher + - Realm + - RealmSwift + - SwiftLint + +SPEC CHECKSUMS: + Kingfisher: d2279a7abece3c7f25a80cd2b7f363ca5cf3f44c + Realm: e125f464884cda953ebefe70c671b75b03b81b9b + RealmSwift: 33656a42bd300959a081fc13347376bc478071af + SwiftLint: 22ccbbe3b8008684be5955693bab135e0ed6a447 + +PODFILE CHECKSUM: f7d56e956cab32204fae806334bb47bd65e91ae4 + +COCOAPODS: 1.9.1 diff --git a/2020-spring/Frolov.NV/NewsAPI4/swiftlint.yml b/2020-spring/Frolov.NV/NewsAPI4/swiftlint.yml new file mode 100644 index 0000000..11bd199 Binary files /dev/null and b/2020-spring/Frolov.NV/NewsAPI4/swiftlint.yml differ