diff --git a/.swiftlint.yml b/.swiftlint.yml index 93c0098e77..ea177e1efc 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -90,7 +90,6 @@ whitelist_rules: - nesting - nimble_operator - no_space_in_method_call - - notification_center_detachment - nslocalizedstring_key - nsobject_prefer_isequal - number_separator diff --git a/Gemfile b/Gemfile index 089ad932c5..a442f92d2b 100644 --- a/Gemfile +++ b/Gemfile @@ -1,8 +1,8 @@ source "https://rubygems.org" ruby "2.6.5" -gem "fastlane", "2.148.1" -gem "cocoapods", "1.9.1" +gem "fastlane", "2.149.1" +gem "cocoapods", "1.9.3" plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile') eval_gemfile(plugins_path) if File.exist?(plugins_path) diff --git a/Gemfile.lock b/Gemfile.lock index 23448c11bc..5802a83e20 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -9,32 +9,32 @@ GEM tzinfo (~> 1.1) addressable (2.7.0) public_suffix (>= 2.0.2, < 5.0) - algoliasearch (1.27.2) + algoliasearch (1.27.3) httpclient (~> 2.8, >= 2.8.3) json (>= 1.5.1) atomos (0.1.3) aws-eventstream (1.1.0) - aws-partitions (1.318.0) - aws-sdk-core (3.96.1) + aws-partitions (1.324.0) + aws-sdk-core (3.97.1) aws-eventstream (~> 1, >= 1.0.2) aws-partitions (~> 1, >= 1.239.0) aws-sigv4 (~> 1.1) jmespath (~> 1.0) - aws-sdk-kms (1.31.0) + aws-sdk-kms (1.33.0) aws-sdk-core (~> 3, >= 3.71.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.65.0) + aws-sdk-s3 (1.67.1) aws-sdk-core (~> 3, >= 3.96.1) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.1) - aws-sigv4 (1.1.3) + aws-sigv4 (1.1.4) aws-eventstream (~> 1.0, >= 1.0.2) babosa (1.0.3) claide (1.0.3) - cocoapods (1.9.1) + cocoapods (1.9.3) activesupport (>= 4.0.2, < 5) claide (>= 1.0.2, < 2.0) - cocoapods-core (= 1.9.1) + cocoapods-core (= 1.9.3) cocoapods-deintegrate (>= 1.0.3, < 2.0) cocoapods-downloader (>= 1.2.2, < 2.0) cocoapods-plugins (>= 1.0.0, < 2.0) @@ -50,7 +50,7 @@ GEM nap (~> 1.0) ruby-macho (~> 1.4) xcodeproj (>= 1.14.0, < 2.0) - cocoapods-core (1.9.1) + cocoapods-core (1.9.3) activesupport (>= 4.0.2, < 6) algoliasearch (~> 1.0) concurrent-ruby (~> 1.1) @@ -92,7 +92,7 @@ GEM faraday_middleware (1.0.0) faraday (~> 1.0) fastimage (2.1.7) - fastlane (2.148.1) + fastlane (2.149.1) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.3, < 3.0.0) aws-sdk-s3 (~> 1.0) @@ -131,7 +131,7 @@ GEM xcpretty (~> 0.3.0) xcpretty-travis-formatter (>= 0.0.3) fastlane-plugin-firebase_app_distribution (0.1.4) - ffi (1.12.2) + ffi (1.13.0) fourflusher (2.3.1) fuzzy_match (2.0.4) gh_inspector (1.1.3) @@ -146,10 +146,10 @@ GEM google-cloud-core (1.5.0) google-cloud-env (~> 1.0) google-cloud-errors (~> 1.0) - google-cloud-env (1.3.1) + google-cloud-env (1.3.2) faraday (>= 0.17.3, < 2.0) - google-cloud-errors (1.0.0) - google-cloud-storage (1.26.1) + google-cloud-errors (1.0.1) + google-cloud-storage (1.26.2) addressable (~> 2.5) digest-crc (~> 0.4) google-api-client (~> 0.33) @@ -210,7 +210,7 @@ GEM unicode-display_width (~> 1.1, >= 1.1.1) thread_safe (0.3.6) tty-cursor (0.7.1) - tty-screen (0.7.1) + tty-screen (0.8.0) tty-spinner (0.9.3) tty-cursor (~> 0.7) typhoeus (1.4.0) @@ -238,8 +238,8 @@ PLATFORMS ruby DEPENDENCIES - cocoapods (= 1.9.1) - fastlane (= 2.148.1) + cocoapods (= 1.9.3) + fastlane (= 2.149.1) fastlane-plugin-firebase_app_distribution RUBY VERSION diff --git a/Podfile b/Podfile index 35bbab9d6a..adf33bcfb4 100644 --- a/Podfile +++ b/Podfile @@ -5,7 +5,7 @@ inhibit_all_warnings! use_frameworks! def shared_pods - pod 'Alamofire', '5.2.0' + pod 'Alamofire', '5.2.1' pod 'Atributika', '4.9.7' pod 'SwiftyJSON', '5.0.0' pod 'SDWebImage', '5.7.4' @@ -60,7 +60,7 @@ def all_pods pod 'Charts', '3.4.0' pod 'EasyTipView', '2.0.4' pod 'ActionSheetPicker-3.0', '2.4.0' - pod 'Nuke', '8.4.1' + pod 'Nuke', '9.1.0' pod 'STRegex', '2.1.1' pod 'Tabman', '2.8.0' pod 'SwiftDate', '6.1.0' diff --git a/Podfile.lock b/Podfile.lock index d24fc7695b..08cb8dcdbe 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -2,7 +2,7 @@ PODS: - ActionSheetPicker-3.0 (2.4.0) - Agrume (5.6.8): - SwiftyGif - - Alamofire (5.2.0) + - Alamofire (5.2.1) - Amplitude-iOS (4.9.3) - Atributika (4.9.7) - BEMCheckBox (1.4.1) @@ -154,7 +154,7 @@ PODS: - nanopb/decode (1.30905.0) - nanopb/encode (1.30905.0) - Nimble (8.0.9) - - Nuke (8.4.1) + - Nuke (9.1.0) - Pageboy (3.5.1) - pop (1.0.12) - Presentr (1.9) @@ -201,7 +201,7 @@ PODS: DEPENDENCIES: - ActionSheetPicker-3.0 (= 2.4.0) - Agrume (= 5.6.8) - - Alamofire (= 5.2.0) + - Alamofire (= 5.2.1) - Amplitude-iOS (= 4.9.3) - Atributika (= 4.9.7) - BEMCheckBox (= 1.4.1) @@ -225,7 +225,7 @@ DEPENDENCIES: - lottie-ios (= 2.5.3) - Mockingjay (= 3.0.0-alpha.1) - Nimble (= 8.0.9) - - Nuke (= 8.4.1) + - Nuke (= 9.1.0) - Presentr (= 1.9) - PromiseKit (= 6.13.0) - Quick (= 2.2.0) @@ -329,7 +329,7 @@ CHECKOUT OPTIONS: SPEC CHECKSUMS: ActionSheetPicker-3.0: c68e1f8355828b4e1c823fa87185aacfef5e6fe3 Agrume: 53c2be9b06caef4b4996a2886a56b9e901bcc6c0 - Alamofire: c1ca147559e730bfb2182c8c7aafbdd90a867987 + Alamofire: e911732990610fe89af59ac0077f923d72dc3dfd Amplitude-iOS: 122e026c44db8460e5efcf84859aa290a0ae9786 Atributika: 6428744f0405ebe79220397a3cb4a9c9d19d5c46 BEMCheckBox: 5ba6e37ade3d3657b36caecc35c8b75c6c2b1a4e @@ -367,7 +367,7 @@ SPEC CHECKSUMS: Mockingjay: 0f7c5aa49c7f1b95621cee3c79b557141f5a225c nanopb: c43f40fadfe79e8b8db116583945847910cbabc9 Nimble: 98b888285a615fd34f20e61753cf58ea1402bde4 - Nuke: d780e3507a86b86c589ab3cc5cd302d5456f06fb + Nuke: c97bf6006d31687cfa7c28507305143de27a4aa1 Pageboy: 288353d4cc848c24deec2f7542f325089247c136 pop: d582054913807fd11fd50bfe6a539d91c7e1a55a Presentr: 7078d7eb5d1661ebeaae60c9e42a1e534de1b993 @@ -393,6 +393,6 @@ SPEC CHECKSUMS: VK-ios-sdk: 62a10b6571fbcda0657f455fedce7fedf55b4cd0 YandexMobileMetrica: 1030df2959c886a7be3bc3d274eb54c8e86afd6f -PODFILE CHECKSUM: 589e7730aaf5f88b6eb827b904adee58229b0540 +PODFILE CHECKSUM: 96d90dd536d857d0a4b714653fdb527c9a657d38 -COCOAPODS: 1.9.1 +COCOAPODS: 1.9.3 diff --git a/Stepic.xcodeproj/project.pbxproj b/Stepic.xcodeproj/project.pbxproj index 5718bf042d..fc38d740ca 100644 --- a/Stepic.xcodeproj/project.pbxproj +++ b/Stepic.xcodeproj/project.pbxproj @@ -382,6 +382,7 @@ 2C1219901F9655AB00A43E98 /* NotificationsSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C12198F1F9655AB00A43E98 /* NotificationsSection.swift */; }; 2C15EB961FC70A0300F56D93 /* UICollectionViewFlowLayout+PlusCrashWorkaround.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C15EB951FC70A0300F56D93 /* UICollectionViewFlowLayout+PlusCrashWorkaround.swift */; }; 2C16495922C10DD400DF18CA /* UserActivitiesNetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C16495822C10DD300DF18CA /* UserActivitiesNetworkService.swift */; }; + 2C16A88F248F98C9001E5CBD /* UserCoursesPersistenceService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C16A88E248F98C9001E5CBD /* UserCoursesPersistenceService.swift */; }; 2C16ED3523D0BC620017C113 /* SettingsRightDetailCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C16ED3423D0BC620017C113 /* SettingsRightDetailCellView.swift */; }; 2C18AD4D23D5F76E00FD89F3 /* DownloadingServiceFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C18AD4C23D5F76E00FD89F3 /* DownloadingServiceFactory.swift */; }; 2C1A4D93244F8A1500D0F2DF /* ARKit-Badge-Glyph-Only.png in Resources */ = {isa = PBXBuildFile; fileRef = 2C1A4D92244F8A1500D0F2DF /* ARKit-Badge-Glyph-Only.png */; }; @@ -416,6 +417,7 @@ 2C2485472101D91F006F8858 /* RestorableBackgroundDownloaderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C2485462101D91F006F8858 /* RestorableBackgroundDownloaderProtocol.swift */; }; 2C2485492101EE3E006F8858 /* DownloaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C2485482101EE3E006F8858 /* DownloaderTests.swift */; }; 2C26BF0A240810A3000EE23C /* AttemptsRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C26BF09240810A3000EE23C /* AttemptsRepository.swift */; }; + 2C273266248BB60500BD065F /* DownloadsDeletionService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C273265248BB60500BD065F /* DownloadsDeletionService.swift */; }; 2C284DB92474418600669736 /* CoursePaymentsAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C284DB82474418600669736 /* CoursePaymentsAPI.swift */; }; 2C284DBB247444DF00669736 /* CoursePaymentsNetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C284DBA247444DF00669736 /* CoursePaymentsNetworkService.swift */; }; 2C295A6A222D8BAB008878B6 /* EnrollmentsAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C8CB0E21FB48F39008CB1AC /* EnrollmentsAPI.swift */; }; @@ -526,6 +528,7 @@ 2C92669820B5C7CF00525AFC /* PlaceholderTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2C92669620B5C7CF00525AFC /* PlaceholderTableViewCell.xib */; }; 2C936D45243D3ADB00A4A4A9 /* ApplicationThemeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C936D44243D3ADB00A4A4A9 /* ApplicationThemeService.swift */; }; 2C936D47243D3FCE00A4A4A9 /* ApplicationTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C936D46243D3FCE00A4A4A9 /* ApplicationTheme.swift */; }; + 2C94C7FA248F86C900E4104E /* UserCourse+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C94C7F9248F86C900E4104E /* UserCourse+CoreDataProperties.swift */; }; 2C96E11624192ACB005EDE2B /* UIColor+DynamicColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C96E11524192ACB005EDE2B /* UIColor+DynamicColor.swift */; }; 2C9776EA24222AED0097AEFC /* UIView+TraitCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C9776E924222AED0097AEFC /* UIView+TraitCollection.swift */; }; 2C97E008215E47D8005684A1 /* SearchResultsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08C1BF271FB9ED01008F342F /* SearchResultsPresenter.swift */; }; @@ -540,6 +543,8 @@ 2C98B6B61FDFD74C005AB72C /* OnboardingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C98B6B51FDFD74C005AB72C /* OnboardingViewController.swift */; }; 2C998AD0246EC83800AAFDE4 /* NotificationAlertsAnalytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C998ACF246EC83800AAFDE4 /* NotificationAlertsAnalytics.swift */; }; 2C9A8D2E22D348A5009434DB /* String+HTMLEscape.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C9A8D2D22D348A5009434DB /* String+HTMLEscape.swift */; }; + 2C9BBE4124903AB500FFED49 /* UserCoursesObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C9BBE4024903AB500FFED49 /* UserCoursesObserver.swift */; }; + 2C9BBE432490462C00FFED49 /* Debouncer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C9BBE422490462C00FFED49 /* Debouncer.swift */; }; 2C9BD78E1FC43C6B00F89CBE /* NotificationsBadgesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C9BD78D1FC43C6B00F89CBE /* NotificationsBadgesManager.swift */; }; 2C9E3F3C1F7A80A300DDF1AA /* Notification+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C9E3F3B1F7A80A300DDF1AA /* Notification+CoreDataProperties.swift */; }; 2C9E3F3E1F7A930100DDF1AA /* NotificationsAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C9E3F3D1F7A930100DDF1AA /* NotificationsAPI.swift */; }; @@ -549,6 +554,7 @@ 2CA255371F8CD62C00C58048 /* NotificationStatusButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA255361F8CD62B00C58048 /* NotificationStatusButton.swift */; }; 2CA3DAA12179C6F600F43888 /* NotificationsRegistrationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA3DAA02179C6F600F43888 /* NotificationsRegistrationService.swift */; }; 2CA3DAA32179C71500F43888 /* NotificationPermissionStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA3DAA22179C71500F43888 /* NotificationPermissionStatus.swift */; }; + 2CA47D4A248ABF0E00925335 /* LogoutDataClearService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA47D49248ABF0E00925335 /* LogoutDataClearService.swift */; }; 2CA9D97720109718007AA743 /* AdaptiveStatsPagerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA9D97620109718007AA743 /* AdaptiveStatsPagerViewController.swift */; }; 2CA9D97920109727007AA743 /* AdaptiveStatsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA9D97820109727007AA743 /* AdaptiveStatsPresenter.swift */; }; 2CA9D97D20109C07007AA743 /* AdaptiveRatingsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA9D97C20109C07007AA743 /* AdaptiveRatingsPresenter.swift */; }; @@ -574,6 +580,7 @@ 2CB2740422C515050078CA2F /* QuizElementView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CB2740322C515050078CA2F /* QuizElementView.swift */; }; 2CB3563E2476CB7B00E59A03 /* MagicLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CB3563D2476CB7B00E59A03 /* MagicLink.swift */; }; 2CB37E6623902BB80050D85E /* StorageUsageService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CB37E6523902BB80050D85E /* StorageUsageService.swift */; }; + 2CB510EE248C226A00DB8344 /* VideosPersistenceService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CB510ED248C226A00DB8344 /* VideosPersistenceService.swift */; }; 2CB51F6B204FC6220008431C /* UserActivitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CB51F6A204FC6220008431C /* UserActivitySpec.swift */; }; 2CB62BDB2019ECB800B5E336 /* OnboardingCardStepViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CB62BDA2019ECB800B5E336 /* OnboardingCardStepViewController.swift */; }; 2CB62BE42019FD8500B5E336 /* step3.html in Resources */ = {isa = PBXBuildFile; fileRef = 2CB62BDC2019FD8400B5E336 /* step3.html */; }; @@ -656,6 +663,11 @@ 2CE8391120C8101500FE3672 /* AchievementBadgeView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2CE8391020C8101500FE3672 /* AchievementBadgeView.xib */; }; 2CE8391320C8102300FE3672 /* AchievementBadgeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CE8391220C8102200FE3672 /* AchievementBadgeView.swift */; }; 2CE8BA9B23D631E500C2EED9 /* ImageStoredFileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CE8BA9A23D631E500C2EED9 /* ImageStoredFileManager.swift */; }; + 2CE9BF44248D07D0004F6659 /* CodeTemplatesPersistenceService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CE9BF43248D07D0004F6659 /* CodeTemplatesPersistenceService.swift */; }; + 2CE9BF46248D08A8004F6659 /* CodeSamplesPersistenceService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CE9BF45248D08A8004F6659 /* CodeSamplesPersistenceService.swift */; }; + 2CE9BF48248D0950004F6659 /* CodeLimitsPersistenceService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CE9BF47248D0950004F6659 /* CodeLimitsPersistenceService.swift */; }; + 2CE9BF4A248D09FC004F6659 /* BlocksPersistenceService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CE9BF49248D09FC004F6659 /* BlocksPersistenceService.swift */; }; + 2CE9BF4C248D0EC5004F6659 /* VideoURLsPersistenceService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CE9BF4B248D0EC5004F6659 /* VideoURLsPersistenceService.swift */; }; 2CEBEBF2242F8E9900DBFDF0 /* StepikRequestInterceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CEBEBF1242F8E9900DBFDF0 /* StepikRequestInterceptor.swift */; }; 2CEBEBF4242F8F9900DBFDF0 /* StepikRequestAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CEBEBF3242F8F9900DBFDF0 /* StepikRequestAdapter.swift */; }; 2CEBEBF6242F8FB200DBFDF0 /* StepikRequestRetrier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CEBEBF5242F8FB200DBFDF0 /* StepikRequestRetrier.swift */; }; @@ -857,6 +869,7 @@ 62E986489D7AC8CBDB0C34B8 /* ExploreSearchBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E98101487588BB70A5C1A7 /* ExploreSearchBar.swift */; }; 62E98652FAF20DE91530C26A /* CourseListInputProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E98F7A42A576AE87588589 /* CourseListInputProtocol.swift */; }; 62E9866A0079204B9AD0AFEA /* TagsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E98351E02F89F112A8EDD2 /* TagsPresenter.swift */; }; + 62E98672DA4B29B46167B0A4 /* LastCodeLanguagePersistenceService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E989EE577036747B419AAC /* LastCodeLanguagePersistenceService.swift */; }; 62E9867E94A2DD00EEE119E0 /* NewMatchingQuizAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E9843AA3AFCC614ECC1450 /* NewMatchingQuizAssembly.swift */; }; 62E9868F7C399B35356DD6E8 /* LessonProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E983EC489566F23F209BE7 /* LessonProvider.swift */; }; 62E98691D21B40042DA6C1AB /* CodeQuizFullscreenRunCodeDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E98390BA7859C78E2E9AAA /* CodeQuizFullscreenRunCodeDataFlow.swift */; }; @@ -873,6 +886,7 @@ 62E987062AC5064918B27379 /* ContentLanguageSwitchAvailabilityService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E9847B46C78DACD9B3EE72 /* ContentLanguageSwitchAvailabilityService.swift */; }; 62E98706EE08B59BC5CB5B03 /* NewSortingQuizDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E98C0502FE0C134B5CC718 /* NewSortingQuizDataFlow.swift */; }; 62E98707AF0BEE9807661F4A /* CodeQuizViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E9874159F84059DB95633E /* CodeQuizViewController.swift */; }; + 62E987084C26B24E039EA0A0 /* NotificationsPersistenceService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E98D6C6FA9C92ABDECEF12 /* NotificationsPersistenceService.swift */; }; 62E9870A57333C471BCB4097 /* BaseQuizViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E9889F89B997EFE5878073 /* BaseQuizViewModel.swift */; }; 62E9870AFED7781931340685 /* ProfileDescriptionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E98AFF3B8AC3CB8374445B /* ProfileDescriptionPresenter.swift */; }; 62E9870EF451D397B27AB075 /* CourseInfoTabSyllabusCellStatsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E9857F9D81D94309D4D3A3 /* CourseInfoTabSyllabusCellStatsView.swift */; }; @@ -888,7 +902,9 @@ 62E9874B2367F47B416932CF /* SolutionInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E98D27662A96D3B8167A9E /* SolutionInteractor.swift */; }; 62E9874D1EAE49639F81C916 /* URL+AppendQueryParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E98F7C1643A576801B8D47 /* URL+AppendQueryParameters.swift */; }; 62E987560B7A0EFE8D4753CB /* RetentionLocalNotificationProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E9863EA3DABDA4ACF78273 /* RetentionLocalNotificationProvider.swift */; }; + 62E98778B1320381E97A0E1F /* LastStepPersistenceService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E98AC352F76C23F60E12A6 /* LastStepPersistenceService.swift */; }; 62E98779C46941AA1F710191 /* ContinueCourseOutputProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E98B7A07FDA68E6CA47ECB /* ContinueCourseOutputProtocol.swift */; }; + 62E9877F4784A8C707B4B712 /* CertificatesPersistenceService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E983871207544AF21C27C6 /* CertificatesPersistenceService.swift */; }; 62E98793982B530188C654BE /* UsersNetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E98407592112A22E967DE1 /* UsersNetworkService.swift */; }; 62E987998151D191C16B5E15 /* ExploreAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E98BE257BD24B6E46FD69D /* ExploreAssembly.swift */; }; 62E987A5122564575E3B4852 /* CodeQuizFullscreenInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E98C9C2AB31AEC2C3B53CE /* CodeQuizFullscreenInteractor.swift */; }; @@ -1626,6 +1642,7 @@ 2C12198F1F9655AB00A43E98 /* NotificationsSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsSection.swift; sourceTree = ""; }; 2C15EB951FC70A0300F56D93 /* UICollectionViewFlowLayout+PlusCrashWorkaround.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UICollectionViewFlowLayout+PlusCrashWorkaround.swift"; sourceTree = ""; }; 2C16495822C10DD300DF18CA /* UserActivitiesNetworkService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserActivitiesNetworkService.swift; sourceTree = ""; }; + 2C16A88E248F98C9001E5CBD /* UserCoursesPersistenceService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserCoursesPersistenceService.swift; sourceTree = ""; }; 2C16ED3423D0BC620017C113 /* SettingsRightDetailCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsRightDetailCellView.swift; sourceTree = ""; }; 2C18AD4C23D5F76E00FD89F3 /* DownloadingServiceFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadingServiceFactory.swift; sourceTree = ""; }; 2C19023B219F24B100FAD9AF /* Model_course_certificate_details_v28.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Model_course_certificate_details_v28.xcdatamodel; sourceTree = ""; }; @@ -1662,6 +1679,7 @@ 2C2485462101D91F006F8858 /* RestorableBackgroundDownloaderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestorableBackgroundDownloaderProtocol.swift; sourceTree = ""; }; 2C2485482101EE3E006F8858 /* DownloaderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloaderTests.swift; sourceTree = ""; }; 2C26BF09240810A3000EE23C /* AttemptsRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttemptsRepository.swift; sourceTree = ""; }; + 2C273265248BB60500BD065F /* DownloadsDeletionService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadsDeletionService.swift; sourceTree = ""; }; 2C284DB82474418600669736 /* CoursePaymentsAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoursePaymentsAPI.swift; sourceTree = ""; }; 2C284DBA247444DF00669736 /* CoursePaymentsNetworkService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoursePaymentsNetworkService.swift; sourceTree = ""; }; 2C2EA36A212D5FEF002116C9 /* StepikResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StepikResult.swift; sourceTree = ""; }; @@ -1788,11 +1806,15 @@ 2C92669620B5C7CF00525AFC /* PlaceholderTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PlaceholderTableViewCell.xib; sourceTree = ""; }; 2C936D44243D3ADB00A4A4A9 /* ApplicationThemeService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationThemeService.swift; sourceTree = ""; }; 2C936D46243D3FCE00A4A4A9 /* ApplicationTheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationTheme.swift; sourceTree = ""; }; + 2C94C7F7248F7E0F00E4104E /* Model_user_courses_v52.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Model_user_courses_v52.xcdatamodel; sourceTree = ""; }; + 2C94C7F9248F86C900E4104E /* UserCourse+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserCourse+CoreDataProperties.swift"; sourceTree = ""; }; 2C96E11524192ACB005EDE2B /* UIColor+DynamicColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+DynamicColor.swift"; sourceTree = ""; }; 2C9776E924222AED0097AEFC /* UIView+TraitCollection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+TraitCollection.swift"; sourceTree = ""; }; 2C98B6B51FDFD74C005AB72C /* OnboardingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingViewController.swift; sourceTree = ""; }; 2C998ACF246EC83800AAFDE4 /* NotificationAlertsAnalytics.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationAlertsAnalytics.swift; sourceTree = ""; }; 2C9A8D2D22D348A5009434DB /* String+HTMLEscape.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+HTMLEscape.swift"; sourceTree = ""; }; + 2C9BBE4024903AB500FFED49 /* UserCoursesObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserCoursesObserver.swift; sourceTree = ""; }; + 2C9BBE422490462C00FFED49 /* Debouncer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Debouncer.swift; sourceTree = ""; }; 2C9BD78D1FC43C6B00F89CBE /* NotificationsBadgesManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsBadgesManager.swift; sourceTree = ""; }; 2C9E3F351F7A79E600DDF1AA /* Model_notifications.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Model_notifications.xcdatamodel; sourceTree = ""; }; 2C9E3F3B1F7A80A300DDF1AA /* Notification+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Notification+CoreDataProperties.swift"; sourceTree = ""; }; @@ -1804,6 +1826,7 @@ 2CA255361F8CD62B00C58048 /* NotificationStatusButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationStatusButton.swift; sourceTree = ""; }; 2CA3DAA02179C6F600F43888 /* NotificationsRegistrationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsRegistrationService.swift; sourceTree = ""; }; 2CA3DAA22179C71500F43888 /* NotificationPermissionStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationPermissionStatus.swift; sourceTree = ""; }; + 2CA47D49248ABF0E00925335 /* LogoutDataClearService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogoutDataClearService.swift; sourceTree = ""; }; 2CA9D97620109718007AA743 /* AdaptiveStatsPagerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdaptiveStatsPagerViewController.swift; sourceTree = ""; }; 2CA9D97820109727007AA743 /* AdaptiveStatsPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdaptiveStatsPresenter.swift; sourceTree = ""; }; 2CA9D97C20109C07007AA743 /* AdaptiveRatingsPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdaptiveRatingsPresenter.swift; sourceTree = ""; }; @@ -1828,6 +1851,7 @@ 2CB2740322C515050078CA2F /* QuizElementView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuizElementView.swift; sourceTree = ""; }; 2CB3563D2476CB7B00E59A03 /* MagicLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MagicLink.swift; sourceTree = ""; }; 2CB37E6523902BB80050D85E /* StorageUsageService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageUsageService.swift; sourceTree = ""; }; + 2CB510ED248C226A00DB8344 /* VideosPersistenceService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideosPersistenceService.swift; sourceTree = ""; }; 2CB51F6A204FC6220008431C /* UserActivitySpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserActivitySpec.swift; sourceTree = ""; }; 2CB62BDA2019ECB800B5E336 /* OnboardingCardStepViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingCardStepViewController.swift; sourceTree = ""; }; 2CB62BDD2019FD8400B5E336 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = ru; path = OnboardingContent/ru.lproj/step3.html; sourceTree = ""; }; @@ -1914,6 +1938,11 @@ 2CE8391020C8101500FE3672 /* AchievementBadgeView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AchievementBadgeView.xib; sourceTree = ""; }; 2CE8391220C8102200FE3672 /* AchievementBadgeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AchievementBadgeView.swift; sourceTree = ""; }; 2CE8BA9A23D631E500C2EED9 /* ImageStoredFileManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageStoredFileManager.swift; sourceTree = ""; }; + 2CE9BF43248D07D0004F6659 /* CodeTemplatesPersistenceService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeTemplatesPersistenceService.swift; sourceTree = ""; }; + 2CE9BF45248D08A8004F6659 /* CodeSamplesPersistenceService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeSamplesPersistenceService.swift; sourceTree = ""; }; + 2CE9BF47248D0950004F6659 /* CodeLimitsPersistenceService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeLimitsPersistenceService.swift; sourceTree = ""; }; + 2CE9BF49248D09FC004F6659 /* BlocksPersistenceService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlocksPersistenceService.swift; sourceTree = ""; }; + 2CE9BF4B248D0EC5004F6659 /* VideoURLsPersistenceService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoURLsPersistenceService.swift; sourceTree = ""; }; 2CEBEBF1242F8E9900DBFDF0 /* StepikRequestInterceptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StepikRequestInterceptor.swift; sourceTree = ""; }; 2CEBEBF3242F8F9900DBFDF0 /* StepikRequestAdapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StepikRequestAdapter.swift; sourceTree = ""; }; 2CEBEBF5242F8FB200DBFDF0 /* StepikRequestRetrier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StepikRequestRetrier.swift; sourceTree = ""; }; @@ -2044,6 +2073,7 @@ 62E9836215CBA17A347B0BA2 /* NewMatchingQuizInteractor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewMatchingQuizInteractor.swift; sourceTree = ""; }; 62E98382552527F92D26C681 /* CourseInfoBlurredBackgroundView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CourseInfoBlurredBackgroundView.swift; sourceTree = ""; }; 62E9838546792D675BC7EA54 /* BaseExploreDataFlow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseExploreDataFlow.swift; sourceTree = ""; }; + 62E983871207544AF21C27C6 /* CertificatesPersistenceService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CertificatesPersistenceService.swift; sourceTree = ""; }; 62E9838A9933D0C52A639CEE /* DownloadsProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownloadsProvider.swift; sourceTree = ""; }; 62E98390BA7859C78E2E9AAA /* CodeQuizFullscreenRunCodeDataFlow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CodeQuizFullscreenRunCodeDataFlow.swift; sourceTree = ""; }; 62E9839124C1BE3BE89FD895 /* LessonInteractor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LessonInteractor.swift; sourceTree = ""; }; @@ -2223,6 +2253,7 @@ 62E989B9228830C92A91B2DE /* CourseListsCollectionSkeletonView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CourseListsCollectionSkeletonView.swift; sourceTree = ""; }; 62E989C1B6DA79B8DA2E66D6 /* HomeProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeProvider.swift; sourceTree = ""; }; 62E989D0C0B39B62D2EF9A05 /* CourseListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CourseListView.swift; sourceTree = ""; }; + 62E989EE577036747B419AAC /* LastCodeLanguagePersistenceService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LastCodeLanguagePersistenceService.swift; sourceTree = ""; }; 62E989F28C53D0189666044B /* QuizOutputProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QuizOutputProtocol.swift; sourceTree = ""; }; 62E989FAD86F79364CC2EF89 /* ProgressesNetworkService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressesNetworkService.swift; sourceTree = ""; }; 62E989FEFDC26A706157D1AB /* Analytics.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Analytics.swift; sourceTree = ""; }; @@ -2247,6 +2278,7 @@ 62E98ABA6ADA2DEA8E21746B /* CourseInfoView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CourseInfoView.swift; sourceTree = ""; }; 62E98AC188792B6E7B8EABC9 /* CourseListCollectionOutputProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CourseListCollectionOutputProtocol.swift; sourceTree = ""; }; 62E98AC3108C157422114826 /* CourseListsCollectionNetworkService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CourseListsCollectionNetworkService.swift; sourceTree = ""; }; + 62E98AC352F76C23F60E12A6 /* LastStepPersistenceService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LastStepPersistenceService.swift; sourceTree = ""; }; 62E98ACC8B72B1F7CD89ECC0 /* DownloadsInteractor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownloadsInteractor.swift; sourceTree = ""; }; 62E98ACD0C7925E448A14220 /* CourseInfoTabInfoProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CourseInfoTabInfoProvider.swift; sourceTree = ""; }; 62E98AD03F8BA48F04CAE503 /* CodeQuizPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CodeQuizPresenter.swift; sourceTree = ""; }; @@ -2333,6 +2365,7 @@ 62E98D428FEE732BA33E751E /* StepInputProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StepInputProtocol.swift; sourceTree = ""; }; 62E98D4604B2021759120234 /* NewFreeAnswerQuizViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewFreeAnswerQuizViewController.swift; sourceTree = ""; }; 62E98D462B4BF802AB9E0440 /* SettingsAssembly.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsAssembly.swift; sourceTree = ""; }; + 62E98D6C6FA9C92ABDECEF12 /* NotificationsPersistenceService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationsPersistenceService.swift; sourceTree = ""; }; 62E98D6C74C01E5709B34288 /* SolutionAssembly.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SolutionAssembly.swift; sourceTree = ""; }; 62E98D7956697C2B5EE51670 /* CodeQuizProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CodeQuizProvider.swift; sourceTree = ""; }; 62E98D7CE99951BE99E0820A /* ContinueCourseInteractor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContinueCourseInteractor.swift; sourceTree = ""; }; @@ -2685,6 +2718,34 @@ path = Repository; sourceTree = ""; }; + 2C273262248BB46300BD065F /* ContentLanguage */ = { + isa = PBXGroup; + children = ( + 62E98256FF0135D7A7B59A54 /* ContentLanguageService.swift */, + 62E9847B46C78DACD9B3EE72 /* ContentLanguageSwitchAvailabilityService.swift */, + ); + path = ContentLanguage; + sourceTree = ""; + }; + 2C273263248BB49500BD065F /* CodeEditor */ = { + isa = PBXGroup; + children = ( + 2C20C86722F903D10052E9BF /* CodeEditorThemeService.swift */, + 2C5E90832333DF2100288BE3 /* CodeLanguageSuggestionsService.swift */, + ); + path = CodeEditor; + sourceTree = ""; + }; + 2C273264248BB4CC00BD065F /* AppData */ = { + isa = PBXGroup; + children = ( + 2C273265248BB60500BD065F /* DownloadsDeletionService.swift */, + 2CA47D49248ABF0E00925335 /* LogoutDataClearService.swift */, + 2CB37E6523902BB80050D85E /* StorageUsageService.swift */, + ); + path = AppData; + sourceTree = ""; + }; 2C284DB7247438F900669736 /* CoursePayment */ = { isa = PBXGroup; children = ( @@ -2879,6 +2940,15 @@ path = Video; sourceTree = ""; }; + 2C94C7F8248F816400E4104E /* UserCourse */ = { + isa = PBXGroup; + children = ( + 62E98BB94C146AA2D8A9C2FF /* UserCourse.swift */, + 2C94C7F9248F86C900E4104E /* UserCourse+CoreDataProperties.swift */, + ); + path = UserCourse; + sourceTree = ""; + }; 2C99D087238967FD00078D2B /* Events */ = { isa = PBXGroup; children = ( @@ -3926,6 +3996,7 @@ children = ( 08484EE4211AF42E0006266F /* CachedValue.swift */, 62E98D0214499A3812DE45C3 /* DataSourceType.swift */, + 2C9BBE422490462C00FFED49 /* Debouncer.swift */, 2CD462E9226F4279004E4725 /* FetchResult.swift */, 62E98CF5FA317BCAFAE433A9 /* ImageDataProvider.swift */, 2C7F78392271D5480089FDD7 /* LayoutInsets.swift */, @@ -4350,7 +4421,6 @@ 080DCF161C4518BC00DE3E2E /* SearchResult.swift */, 088E73F32061BDAA00D458E3 /* StepikModelView.swift */, 08E6BB6A1DC8EB45006622EC /* UserActivity.swift */, - 62E98BB94C146AA2D8A9C2FF /* UserCourse.swift */, 2CFF900B242A248800FD7311 /* Alerts */, 2CFF900E242A24C100FD7311 /* AttemptsSumbissions */, 2CFF9012242A250C00FD7311 /* Constants */, @@ -4510,6 +4580,7 @@ 2CFF902C242A26AB00FD7311 /* Unit */, 2CFF902D242A26B600FD7311 /* User */, 2C87A7A62446644700933CA4 /* UserActivity */, + 2C94C7F8248F816400E4104E /* UserCourse */, 2CFF902E242A26C200FD7311 /* Video */, 2CFF902F242A26CE00FD7311 /* VideoURL */, ); @@ -5054,13 +5125,21 @@ children = ( 2CB9529D22A0351F00A6117A /* AssignmentsPersistenceService.swift */, 2C04BA532407C3BF00D74D4B /* AttemptsPersistenceService.swift */, + 2CE9BF49248D09FC004F6659 /* BlocksPersistenceService.swift */, + 62E983871207544AF21C27C6 /* CertificatesPersistenceService.swift */, + 2CE9BF47248D0950004F6659 /* CodeLimitsPersistenceService.swift */, + 2CE9BF45248D08A8004F6659 /* CodeSamplesPersistenceService.swift */, + 2CE9BF43248D07D0004F6659 /* CodeTemplatesPersistenceService.swift */, 62E98C9F5E7C0823E94A4527 /* CourseListsCollectionPersistenceService.swift */, 62E98B4C083CFD4E93597D32 /* CourseReviewsPersistenceService.swift */, 62E985BDDC6349F80D395284 /* CourseReviewSummariesPersistenceService.swift */, 62E98B706335B4BAC35D3C6D /* CoursesPersistenceService.swift */, 2C4AD01A23E305FA0049B7B0 /* DiscussionThreadsPersistenceService.swift */, 2CD6E25C234E388B00F49303 /* EmailAddressesPersistenceService.swift */, + 62E989EE577036747B419AAC /* LastCodeLanguagePersistenceService.swift */, + 62E98AC352F76C23F60E12A6 /* LastStepPersistenceService.swift */, 62E985EA7905BE734BB77FBD /* LessonsPersistenceService.swift */, + 62E98D6C6FA9C92ABDECEF12 /* NotificationsPersistenceService.swift */, 2C87A7A324465B5800933CA4 /* ProfilesPersistenceService.swift */, 62E9803E0D93EBBD439FFEDD /* ProgressesPersistenceService.swift */, 62E9867D3CF2B4F6A52B2B4A /* SectionsPersistenceService.swift */, @@ -5069,7 +5148,10 @@ 2C57B29E24092868008284F0 /* SubmissionsPersistenceService.swift */, 62E981BE70619C07A3F72EC9 /* UnitsPersistenceService.swift */, 2C87A7AC2446696D00933CA4 /* UserActivitiesPersistenceService.swift */, + 2C16A88E248F98C9001E5CBD /* UserCoursesPersistenceService.swift */, 2C87A7A02446502900933CA4 /* UsersPersistenceService.swift */, + 2CB510ED248C226A00DB8344 /* VideosPersistenceService.swift */, + 2CE9BF4B248D0EC5004F6659 /* VideoURLsPersistenceService.swift */, ); path = Persistence; sourceTree = ""; @@ -5628,7 +5710,7 @@ path = Helpers; sourceTree = ""; }; - 62E986D1988A3445F3416404 /* Managers */ = { + 62E986D1988A3445F3416404 /* StorageManagers */ = { isa = PBXGroup; children = ( 2C7F641D23B12208006C7648 /* AutoplayStorageManager.swift */, @@ -5638,7 +5720,7 @@ 2CF7E3332417C1A700B9188E /* UseCellularDataForDownloadsStorageManager.swift */, 2C8F3ADE23CCAB88004D113A /* Video */, ); - path = Managers; + path = StorageManagers; sourceTree = ""; }; 62E986D974D797A3BDF8DA59 /* Extensions */ = { @@ -6111,20 +6193,19 @@ isa = PBXGroup; children = ( 2C936D44243D3ADB00A4A4A9 /* ApplicationThemeService.swift */, - 2C20C86722F903D10052E9BF /* CodeEditorThemeService.swift */, - 2C5E90832333DF2100288BE3 /* CodeLanguageSuggestionsService.swift */, - 62E98256FF0135D7A7B59A54 /* ContentLanguageService.swift */, - 62E9847B46C78DACD9B3EE72 /* ContentLanguageSwitchAvailabilityService.swift */, 62E98EFD0E3B6DA84FCE723B /* DataBackUpdateService.swift */, 62E98E01F05F1205F284595F /* NetworkReachabilityService.swift */, 2CDAD309229EC81A00AA9EF5 /* PersistenceQueuesService.swift */, - 2CB37E6523902BB80050D85E /* StorageUsageService.swift */, 2CDBCCCE23EB777E005D2370 /* SubmissionURLProvider.swift */, 62E98FBA6AB1C2BD6EA95634 /* UnitNavigationService.swift */, 62E98EBA0AF48AD90775FF7E /* UserAccountService.swift */, - 62E986D1988A3445F3416404 /* Managers */, + 2C9BBE4024903AB500FFED49 /* UserCoursesObserver.swift */, + 2C273264248BB4CC00BD065F /* AppData */, + 2C273263248BB49500BD065F /* CodeEditor */, + 2C273262248BB46300BD065F /* ContentLanguage */, 62E98A358EF538D7F89D10F1 /* Models */, 2CDB95872412C04A00F676A7 /* Spotlight */, + 62E986D1988A3445F3416404 /* StorageManagers */, ); path = Services; sourceTree = ""; @@ -7000,6 +7081,7 @@ 2C98B6B61FDFD74C005AB72C /* OnboardingViewController.swift in Sources */, 08C02DB41F53201A00F848F5 /* ProfilePresenter.swift in Sources */, 080CE1551E9563590089A27F /* ProgressesAPI.swift in Sources */, + 2CA47D4A248ABF0E00925335 /* LogoutDataClearService.swift in Sources */, 0846B10C1EDDEE7F00D64D77 /* CodeLimit.swift in Sources */, 2C57B2A1240945B2008284F0 /* SubmissionsRepository.swift in Sources */, 2C97E009215E47E7005684A1 /* SearchQueriesViewController.swift in Sources */, @@ -7057,6 +7139,7 @@ 08D5F5801F7DBA70007C1634 /* CourseReviewSummariesAPI.swift in Sources */, 2CA100162174BB66003775CB /* PersonalDeadlineLocalNotificationContentProvider.swift in Sources */, 08FA62242121BF1200F00275 /* ShrinkDismissAnimationController.swift in Sources */, + 2C273266248BB60500BD065F /* DownloadsDeletionService.swift in Sources */, 080ACF501BD79D5500329F2B /* Images.swift in Sources */, 082B54DB20AA445C00144817 /* DeadlineMode.swift in Sources */, 08CBA2F81F573F6900302154 /* MenuViewController.swift in Sources */, @@ -7214,6 +7297,7 @@ 087296DC20168FF2009F9256 /* TooltipDefaultsManager.swift in Sources */, 2CF08861205BEE2C00FCB9C0 /* StepikPlaceholder.swift in Sources */, 080CE1431E955D300089A27F /* CoursesAPI.swift in Sources */, + 2CE9BF4A248D09FC004F6659 /* BlocksPersistenceService.swift in Sources */, 08F485A51C57AF2E000165AA /* FreeAnswerReply.swift in Sources */, 08C1FC331F41E74500E14B46 /* QuizPresenter.swift in Sources */, 2C604E21207E4609001588FB /* CodeEditorPreviewView.swift in Sources */, @@ -7295,6 +7379,7 @@ 08F485AA1C580D61000165AA /* MathReply.swift in Sources */, 08E43E99214C279700E3CB50 /* PushRouterSourceProtocol.swift in Sources */, 2C2F0BE72186EEB8007DCA0A /* StreakNotificationsRequestAlertDataSource.swift in Sources */, + 2C9BBE4124903AB500FFED49 /* UserCoursesObserver.swift in Sources */, 2CB62BDB2019ECB800B5E336 /* OnboardingCardStepViewController.swift in Sources */, 08E7CA1020DAF6E0004F8563 /* AnalyticsUserProperties.swift in Sources */, 2C2972052147F5FD001502BD /* CourseTag.swift in Sources */, @@ -7303,6 +7388,7 @@ 089611041D52250500561AC1 /* DeepLinkRouter.swift in Sources */, 08FEFC1C1F117257005CA0FB /* CodeSuggestionTableViewCell.swift in Sources */, 2C4BE7DE221325FB00AEAC34 /* CourseReview.swift in Sources */, + 2CE9BF48248D0950004F6659 /* CodeLimitsPersistenceService.swift in Sources */, 2C48D604228F0EF700739477 /* ContentProcessingRule.swift in Sources */, 083F2B211E9E645000714173 /* CertificateTableViewCell.swift in Sources */, 08CA59F21BBFD65E008DC44D /* User.swift in Sources */, @@ -7320,6 +7406,7 @@ 2CB9E8C41F7AA5CD0004E17F /* NotificationsPresenter.swift in Sources */, 08F485A21C57987C000165AA /* NumberQuizViewController.swift in Sources */, 2C5DF1431FED2758003B1177 /* CardStepDelegate.swift in Sources */, + 2CE9BF4C248D0EC5004F6659 /* VideoURLsPersistenceService.swift in Sources */, 2C48D601228F0C6000739477 /* ContentProcessor.swift in Sources */, 2C97E00B215E47F3005684A1 /* SearchQueriesPersistentManager.swift in Sources */, 08901E721CD1173200D94613 /* Version.swift in Sources */, @@ -7357,6 +7444,7 @@ 080EBA331EA64BC000C43C93 /* PresentationContainer.swift in Sources */, 084DDDE1204EDF7600913503 /* NotificationRequestAlertViewController.swift in Sources */, 2C2485472101D91F006F8858 /* RestorableBackgroundDownloaderProtocol.swift in Sources */, + 2CE9BF46248D08A8004F6659 /* CodeSamplesPersistenceService.swift in Sources */, 2C92669720B5C7CF00525AFC /* PlaceholderTableViewCell.swift in Sources */, 2CC0754720177A2E004A6005 /* AdaptiveStatsViewController.swift in Sources */, 2C80C829201A504700ABB312 /* StepCardView.swift in Sources */, @@ -7553,6 +7641,7 @@ 62E98116576B12451E5418F4 /* CourseCoverImageView.swift in Sources */, 2C936D45243D3ADB00A4A4A9 /* ApplicationThemeService.swift in Sources */, 2C7F641C23B0F5B7006C7648 /* PlayNextCircleControlView.swift in Sources */, + 2C9BBE432490462C00FFED49 /* Debouncer.swift in Sources */, 62E98C3824298B04928351E5 /* FormatterHelper.swift in Sources */, 2CF10C8B238426B300F8CC95 /* StepSourcesNetworkService.swift in Sources */, 2C04BA47240726BA00D74D4B /* SubmissionEntity+CoreDataProperties.swift in Sources */, @@ -7567,6 +7656,7 @@ 62E9860632B3BB21E24DF368 /* SectionsNetworkService.swift in Sources */, 62E9851C596D4146AC811EAE /* UnitsNetworkService.swift in Sources */, 62E983B402214CA82BF050E8 /* LessonsNetworkService.swift in Sources */, + 2CE9BF44248D07D0004F6659 /* CodeTemplatesPersistenceService.swift in Sources */, 2C8F3AE123CCBD26004D113A /* DownloadVideoQuality.swift in Sources */, 2CDB95892412C08100F676A7 /* SpotlightContinueUserActivityService.swift in Sources */, 62E98F5FB06328B5D7212700 /* HighlightFakeButton.swift in Sources */, @@ -7585,6 +7675,7 @@ 2C20C86C22F988030052E9BF /* CodeEditorTheme.swift in Sources */, 62E98B337D0BA97FB0796C2C /* CoursesNetworkService.swift in Sources */, 62E98793982B530188C654BE /* UsersNetworkService.swift in Sources */, + 2C16A88F248F98C9001E5CBD /* UserCoursesPersistenceService.swift in Sources */, 62E981F21F0275F8547E0658 /* ProgressesPersistenceService.swift in Sources */, 62E984F71594AA4CD19696EC /* CoursesPersistenceService.swift in Sources */, 62E98E58E7BC6B6AF4881084 /* CourseReviewSummariesPersistenceService.swift in Sources */, @@ -7858,6 +7949,7 @@ 62E988C4572F2A9C97348C83 /* CodeQuizView.swift in Sources */, 62E98707AF0BEE9807661F4A /* CodeQuizViewController.swift in Sources */, 62E98866B15E76B9FE106E1B /* CodeQuizViewModel.swift in Sources */, + 2CB510EE248C226A00DB8344 /* VideosPersistenceService.swift in Sources */, 62E98856B2540336E5867457 /* UnsupportedCodeLanguageView.swift in Sources */, 62E9841E806D9AF0E9C8D199 /* CodeDetailsButton.swift in Sources */, 62E9804624D413C3F8D71AC7 /* CodeDetailsContentView.swift in Sources */, @@ -7870,6 +7962,7 @@ 62E98C3F01034400CAABD717 /* CodeTextViewLayoutManager.swift in Sources */, 62E98EEB59DAF1D0700A7DB9 /* CodeLanguagePickerView.swift in Sources */, 62E98A2B85DD1D883B5BFEC7 /* CodeToolbarLanguagePickerButton.swift in Sources */, + 2C94C7FA248F86C900E4104E /* UserCourse+CoreDataProperties.swift in Sources */, 2CC5AA71242A34FA00C09F94 /* AdaptiveStatsManager.swift in Sources */, 62E98F91C1E401E5C9855DB1 /* CodeToolbarView.swift in Sources */, 62E9817AE10960C05029CA37 /* CodeQuizFullscreenAssembly.swift in Sources */, @@ -8023,6 +8116,10 @@ 62E98DDC32C86496C6953A1E /* AnalyticsEngine.swift in Sources */, 62E98F1672B90358D7188D02 /* AnalyticsEvent.swift in Sources */, 62E9888417EE1DD05B20491B /* CoursePayment.swift in Sources */, + 62E9877F4784A8C707B4B712 /* CertificatesPersistenceService.swift in Sources */, + 62E987084C26B24E039EA0A0 /* NotificationsPersistenceService.swift in Sources */, + 62E98778B1320381E97A0E1F /* LastStepPersistenceService.swift in Sources */, + 62E98672DA4B29B46167B0A4 /* LastCodeLanguagePersistenceService.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -8375,7 +8472,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 216; + CURRENT_PROJECT_VERSION = 219; DEVELOPMENT_TEAM = UJ4KC2QN7B; ENABLE_BITCODE = YES; INFOPLIST_FILE = Stepic/Info.plist; @@ -8405,7 +8502,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 216; + CURRENT_PROJECT_VERSION = 219; DEVELOPMENT_TEAM = UJ4KC2QN7B; ENABLE_BITCODE = YES; INFOPLIST_FILE = Stepic/Info.plist; @@ -8467,6 +8564,7 @@ 08D1EF6E1BB5618700BE84E6 /* Model.xcdatamodeld */ = { isa = XCVersionGroup; children = ( + 2C94C7F7248F7E0F00E4104E /* Model_user_courses_v52.xcdatamodel */, 2C7466402456065F00BB0800 /* Model_user_courses_actions_v51.xcdatamodel */, 2C87A7A52446635E00933CA4 /* Model_user_activity_v50.xcdatamodel */, 2C04BA3724058AF100D74D4B /* Model_attempts_caching.xcdatamodel */, @@ -8520,7 +8618,7 @@ 0802AC531C7222B200C4F3E6 /* Model_v2.xcdatamodel */, 08D1EF6F1BB5618700BE84E6 /* Model.xcdatamodel */, ); - currentVersion = 2C7466402456065F00BB0800 /* Model_user_courses_actions_v51.xcdatamodel */; + currentVersion = 2C94C7F7248F7E0F00E4104E /* Model_user_courses_v52.xcdatamodel */; path = Model.xcdatamodeld; sourceTree = ""; versionGroupType = wrapper.xcdatamodel; diff --git a/Stepic/Images.xcassets/New course list/course-widget-archive.imageset/Contents.json b/Stepic/Images.xcassets/New course list/course-widget-archive.imageset/Contents.json new file mode 100644 index 0000000000..fb01bdca56 --- /dev/null +++ b/Stepic/Images.xcassets/New course list/course-widget-archive.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "course-widget-archive.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Stepic/Images.xcassets/New course list/course-widget-archive.imageset/course-widget-archive.pdf b/Stepic/Images.xcassets/New course list/course-widget-archive.imageset/course-widget-archive.pdf new file mode 100644 index 0000000000..72e54e2100 Binary files /dev/null and b/Stepic/Images.xcassets/New course list/course-widget-archive.imageset/course-widget-archive.pdf differ diff --git a/Stepic/Images.xcassets/New course list/course-widget-certificate.imageset/Contents.json b/Stepic/Images.xcassets/New course list/course-widget-certificate.imageset/Contents.json new file mode 100644 index 0000000000..62ec355314 --- /dev/null +++ b/Stepic/Images.xcassets/New course list/course-widget-certificate.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "course-widget-certificate.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Stepic/Images.xcassets/New course list/course-widget-certificate.imageset/course-widget-certificate.pdf b/Stepic/Images.xcassets/New course list/course-widget-certificate.imageset/course-widget-certificate.pdf new file mode 100644 index 0000000000..337b04aa76 Binary files /dev/null and b/Stepic/Images.xcassets/New course list/course-widget-certificate.imageset/course-widget-certificate.pdf differ diff --git a/Stepic/Images.xcassets/New course list/course-widget-favorite.imageset/Contents.json b/Stepic/Images.xcassets/New course list/course-widget-favorite.imageset/Contents.json new file mode 100644 index 0000000000..fc4448b84a --- /dev/null +++ b/Stepic/Images.xcassets/New course list/course-widget-favorite.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "course-widget-favorite.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Stepic/Images.xcassets/New course list/course-widget-favorite.imageset/course-widget-favorite.pdf b/Stepic/Images.xcassets/New course list/course-widget-favorite.imageset/course-widget-favorite.pdf new file mode 100644 index 0000000000..62d3dbc85c Binary files /dev/null and b/Stepic/Images.xcassets/New course list/course-widget-favorite.imageset/course-widget-favorite.pdf differ diff --git a/Stepic/Info.plist b/Stepic/Info.plist index 8162ae5883..c19a3193e6 100644 --- a/Stepic/Info.plist +++ b/Stepic/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.126 + 1.127 CFBundleSignature ???? CFBundleURLTypes @@ -54,7 +54,7 @@ CFBundleVersion - 216 + 219 FacebookAppID 171127739724012 FacebookDisplayName diff --git a/Stepic/Legacy/AppDelegate.swift b/Stepic/Legacy/AppDelegate.swift index 5b6af5bb19..d5e0630e2f 100644 --- a/Stepic/Legacy/AppDelegate.swift +++ b/Stepic/Legacy/AppDelegate.swift @@ -29,6 +29,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { private let branchService = BranchService() private let spotlightContinueUserActivityService: SpotlightContinueUserActivityServiceProtocol = SpotlightContinueUserActivityService() private let notificationPermissionStatusSettingsObserver = NotificationPermissionStatusSettingsObserver() + private let userCoursesObserver: UserCoursesObserverProtocol = UserCoursesObserver() private lazy var analytics: Analytics = { StepikAnalytics.shared }() deinit { @@ -135,10 +136,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate { self.analytics.send(.applicationDidBecomeActive) NotificationsBadgesManager.shared.set(number: application.applicationIconBadgeNumber) self.notificationsService.removeRetentionNotifications() + self.userCoursesObserver.startObserving() } func applicationWillResignActive(_ application: UIApplication) { self.notificationsService.scheduleRetentionNotifications() + self.userCoursesObserver.stopObserving() } // MARK: - Downloading Data in the Background diff --git a/Stepic/Legacy/Controllers/Notifications/Helpers/NotificationsBadgesManager.swift b/Stepic/Legacy/Controllers/Notifications/Helpers/NotificationsBadgesManager.swift index 7ef963b64b..bb2018bfa1 100644 --- a/Stepic/Legacy/Controllers/Notifications/Helpers/NotificationsBadgesManager.swift +++ b/Stepic/Legacy/Controllers/Notifications/Helpers/NotificationsBadgesManager.swift @@ -12,6 +12,7 @@ extension NSNotification.Name { static let badgeUpdated = NSNotification.Name("badgeUpdated") } +@available(*, deprecated, message: "Legacy class") final class NotificationsBadgesManager { static let shared = NotificationsBadgesManager() diff --git a/Stepic/Legacy/Helpers/CoreDataHelper.swift b/Stepic/Legacy/Helpers/CoreDataHelper.swift index dd2ccb8168..a808e930da 100644 --- a/Stepic/Legacy/Helpers/CoreDataHelper.swift +++ b/Stepic/Legacy/Helpers/CoreDataHelper.swift @@ -9,6 +9,7 @@ import CoreData import UIKit +@available(*, deprecated, message: "Legacy class") final class CoreDataHelper: NSObject { static var shared = CoreDataHelper() diff --git a/Stepic/Legacy/Model/Entities/Assignment/Assignment+CoreDataProperties.swift b/Stepic/Legacy/Model/Entities/Assignment/Assignment+CoreDataProperties.swift index 25ee2fbc77..dafcbabfd9 100644 --- a/Stepic/Legacy/Model/Entities/Assignment/Assignment+CoreDataProperties.swift +++ b/Stepic/Legacy/Model/Entities/Assignment/Assignment+CoreDataProperties.swift @@ -21,6 +21,10 @@ extension Assignment { NSEntityDescription.entity(forEntityName: "Assignment", in: CoreDataHelper.shared.context)! } + static var fetchRequest: NSFetchRequest { + NSFetchRequest(entityName: "Assignment") + } + convenience init() { self.init(entity: Assignment.oldEntity, insertInto: CoreDataHelper.shared.context) } diff --git a/Stepic/Legacy/Model/Entities/Attempt/AttemptEntity+CoreDataProperties.swift b/Stepic/Legacy/Model/Entities/Attempt/AttemptEntity+CoreDataProperties.swift index 837865942f..8d55406fea 100644 --- a/Stepic/Legacy/Model/Entities/Attempt/AttemptEntity+CoreDataProperties.swift +++ b/Stepic/Legacy/Model/Entities/Attempt/AttemptEntity+CoreDataProperties.swift @@ -21,7 +21,7 @@ extension AttemptEntity { [NSSortDescriptor(key: #keyPath(managedID), ascending: false)] } - static func fetchRequest() -> NSFetchRequest { + static var fetchRequest: NSFetchRequest { NSFetchRequest(entityName: "AttemptEntity") } } diff --git a/Stepic/Legacy/Model/Entities/Block/Block+CoreDataProperties.swift b/Stepic/Legacy/Model/Entities/Block/Block+CoreDataProperties.swift index a92a46bf00..34bebec05d 100644 --- a/Stepic/Legacy/Model/Entities/Block/Block+CoreDataProperties.swift +++ b/Stepic/Legacy/Model/Entities/Block/Block+CoreDataProperties.swift @@ -24,6 +24,10 @@ extension Block { NSEntityDescription.entity(forEntityName: "Block", in: CoreDataHelper.shared.context)! } + static var fetchRequest: NSFetchRequest { + NSFetchRequest(entityName: "Block") + } + convenience init() { self.init(entity: Block.oldEntity, insertInto: CoreDataHelper.shared.context) } diff --git a/Stepic/Legacy/Model/Entities/Certificate/Certificate+CoreDataProperties.swift b/Stepic/Legacy/Model/Entities/Certificate/Certificate+CoreDataProperties.swift index 6bce721141..802ed5c7ab 100644 --- a/Stepic/Legacy/Model/Entities/Certificate/Certificate+CoreDataProperties.swift +++ b/Stepic/Legacy/Model/Entities/Certificate/Certificate+CoreDataProperties.swift @@ -25,6 +25,10 @@ extension Certificate { NSEntityDescription.entity(forEntityName: "Certificate", in: CoreDataHelper.shared.context)! } + static var fetchRequest: NSFetchRequest { + NSFetchRequest(entityName: "Certificate") + } + convenience init() { self.init(entity: Certificate.oldEntity, insertInto: CoreDataHelper.shared.context) } diff --git a/Stepic/Legacy/Model/Entities/Certificate/Certificate.swift b/Stepic/Legacy/Model/Entities/Certificate/Certificate.swift index 01087c01ef..6251d6569f 100644 --- a/Stepic/Legacy/Model/Entities/Certificate/Certificate.swift +++ b/Stepic/Legacy/Model/Entities/Certificate/Certificate.swift @@ -53,17 +53,4 @@ final class Certificate: NSManagedObject, IDFetchable { return [] } } - - //TODO: Refactor this action to protocol extension when refactoring CoreData - static func deleteAll() { - let request = NSFetchRequest(entityName: "Certificate") - do { - let results = try CoreDataHelper.shared.context.fetch(request) as? [Certificate] - for obj in results ?? [] { - CoreDataHelper.shared.deleteFromStore(obj) - } - } catch { - print("certificate: couldn't delete all certificates!") - } - } } diff --git a/Stepic/Legacy/Model/Entities/CodeLimit/CodeLimit+CoreDataProperties.swift b/Stepic/Legacy/Model/Entities/CodeLimit/CodeLimit+CoreDataProperties.swift index 7614d74a84..8578c9dd97 100644 --- a/Stepic/Legacy/Model/Entities/CodeLimit/CodeLimit+CoreDataProperties.swift +++ b/Stepic/Legacy/Model/Entities/CodeLimit/CodeLimit+CoreDataProperties.swift @@ -20,6 +20,10 @@ extension CodeLimit { NSEntityDescription.entity(forEntityName: "CodeLimit", in: CoreDataHelper.shared.context)! } + static var fetchRequest: NSFetchRequest { + NSFetchRequest(entityName: "CodeLimit") + } + convenience init() { self.init(entity: CodeLimit.oldEntity, insertInto: CoreDataHelper.shared.context) } diff --git a/Stepic/Legacy/Model/Entities/CodeSample/CodeSample+CoreDataProperties.swift b/Stepic/Legacy/Model/Entities/CodeSample/CodeSample+CoreDataProperties.swift index d4f8b18502..8e0bc7eda1 100644 --- a/Stepic/Legacy/Model/Entities/CodeSample/CodeSample+CoreDataProperties.swift +++ b/Stepic/Legacy/Model/Entities/CodeSample/CodeSample+CoreDataProperties.swift @@ -19,6 +19,10 @@ extension CodeSample { NSEntityDescription.entity(forEntityName: "CodeSample", in: CoreDataHelper.shared.context)! } + static var fetchRequest: NSFetchRequest { + NSFetchRequest(entityName: "CodeSample") + } + convenience init() { self.init(entity: CodeSample.oldEntity, insertInto: CoreDataHelper.shared.context) } diff --git a/Stepic/Legacy/Model/Entities/CodeTemplates/CodeTemplate+CoreDataProperties.swift b/Stepic/Legacy/Model/Entities/CodeTemplates/CodeTemplate+CoreDataProperties.swift index d2b7ad5c61..6f52e882cd 100644 --- a/Stepic/Legacy/Model/Entities/CodeTemplates/CodeTemplate+CoreDataProperties.swift +++ b/Stepic/Legacy/Model/Entities/CodeTemplates/CodeTemplate+CoreDataProperties.swift @@ -20,6 +20,10 @@ extension CodeTemplate { NSEntityDescription.entity(forEntityName: "CodeTemplate", in: CoreDataHelper.shared.context)! } + static var fetchRequest: NSFetchRequest { + NSFetchRequest(entityName: "CodeTemplate") + } + convenience init() { self.init(entity: CodeTemplate.oldEntity, insertInto: CoreDataHelper.shared.context) } diff --git a/Stepic/Legacy/Model/Entities/Course/Course+CoreDataProperties.swift b/Stepic/Legacy/Model/Entities/Course/Course+CoreDataProperties.swift index 91b4c0cde0..436339f2b8 100644 --- a/Stepic/Legacy/Model/Entities/Course/Course+CoreDataProperties.swift +++ b/Stepic/Legacy/Model/Entities/Course/Course+CoreDataProperties.swift @@ -65,6 +65,7 @@ extension Course { @NSManaged var managedProgress: Progress? @NSManaged var managedReviewSummary: CourseReviewSummary? @NSManaged var managedSections: NSOrderedSet? + @NSManaged var managedUserCourse: UserCourse? static var oldEntity: NSEntityDescription { NSEntityDescription.entity(forEntityName: "Course", in: CoreDataHelper.shared.context)! @@ -489,6 +490,15 @@ extension Course { } } + var userCourse: UserCourse? { + get { + self.managedUserCourse + } + set { + self.managedUserCourse = newValue + } + } + var canWriteReview: Bool { if let progress = self.progress { return (Double(progress.numberOfStepsPassed) * 100.0 / Double(progress.numberOfSteps)) >= 80.0 diff --git a/Stepic/Legacy/Model/Entities/CourseReview/CourseReview+CoreDataProperties.swift b/Stepic/Legacy/Model/Entities/CourseReview/CourseReview+CoreDataProperties.swift index aaa6bfdd05..880e0fc9e7 100644 --- a/Stepic/Legacy/Model/Entities/CourseReview/CourseReview+CoreDataProperties.swift +++ b/Stepic/Legacy/Model/Entities/CourseReview/CourseReview+CoreDataProperties.swift @@ -24,6 +24,10 @@ extension CourseReview { NSEntityDescription.entity(forEntityName: "CourseReview", in: CoreDataHelper.shared.context)! } + static var fetchRequest: NSFetchRequest { + NSFetchRequest(entityName: "CourseReview") + } + convenience init() { self.init(entity: CourseReview.oldEntity, insertInto: CoreDataHelper.shared.context) } diff --git a/Stepic/Legacy/Model/Entities/CourseReviewSummary/CourseReviewSummary+CoreDataProperties.swift b/Stepic/Legacy/Model/Entities/CourseReviewSummary/CourseReviewSummary+CoreDataProperties.swift index 72c22f6146..57397db158 100644 --- a/Stepic/Legacy/Model/Entities/CourseReviewSummary/CourseReviewSummary+CoreDataProperties.swift +++ b/Stepic/Legacy/Model/Entities/CourseReviewSummary/CourseReviewSummary+CoreDataProperties.swift @@ -21,6 +21,10 @@ extension CourseReviewSummary { NSEntityDescription.entity(forEntityName: "CourseReviewSummary", in: CoreDataHelper.shared.context)! } + static var fetchRequest: NSFetchRequest { + NSFetchRequest(entityName: "CourseReviewSummary") + } + convenience init() { self.init(entity: CourseReviewSummary.oldEntity, insertInto: CoreDataHelper.shared.context) } diff --git a/Stepic/Legacy/Model/Entities/DiscussionThread/DiscussionThread+CoreDataProperties.swift b/Stepic/Legacy/Model/Entities/DiscussionThread/DiscussionThread+CoreDataProperties.swift index 43ebded1e2..38f6660c9a 100644 --- a/Stepic/Legacy/Model/Entities/DiscussionThread/DiscussionThread+CoreDataProperties.swift +++ b/Stepic/Legacy/Model/Entities/DiscussionThread/DiscussionThread+CoreDataProperties.swift @@ -13,6 +13,10 @@ extension DiscussionThread { NSEntityDescription.entity(forEntityName: "DiscussionThread", in: CoreDataHelper.shared.context)! } + static var fetchRequest: NSFetchRequest { + NSFetchRequest(entityName: "DiscussionThread") + } + convenience init() { self.init(entity: DiscussionThread.oldEntity, insertInto: CoreDataHelper.shared.context) } diff --git a/Stepic/Legacy/Model/Entities/EmailAddress/EmailAddress+CoreDataProperties.swift b/Stepic/Legacy/Model/Entities/EmailAddress/EmailAddress+CoreDataProperties.swift index b18524f9f3..6c3d52ba94 100644 --- a/Stepic/Legacy/Model/Entities/EmailAddress/EmailAddress+CoreDataProperties.swift +++ b/Stepic/Legacy/Model/Entities/EmailAddress/EmailAddress+CoreDataProperties.swift @@ -22,6 +22,10 @@ extension EmailAddress { NSEntityDescription.entity(forEntityName: "EmailAddress", in: CoreDataHelper.shared.context)! } + static var fetchRequest: NSFetchRequest { + NSFetchRequest(entityName: "EmailAddress") + } + convenience init() { self.init(entity: EmailAddress.oldEntity, insertInto: CoreDataHelper.shared.context) } diff --git a/Stepic/Legacy/Model/Entities/LastCodeLanguage/LastCodeLanguage+CoreDataProperties.swift b/Stepic/Legacy/Model/Entities/LastCodeLanguage/LastCodeLanguage+CoreDataProperties.swift index b8f82a662f..10c7c8d1e8 100644 --- a/Stepic/Legacy/Model/Entities/LastCodeLanguage/LastCodeLanguage+CoreDataProperties.swift +++ b/Stepic/Legacy/Model/Entities/LastCodeLanguage/LastCodeLanguage+CoreDataProperties.swift @@ -9,6 +9,10 @@ extension LastCodeLanguage { NSEntityDescription.entity(forEntityName: "LastCodeLanguage", in: CoreDataHelper.shared.context)! } + static var fetchRequest: NSFetchRequest { + NSFetchRequest(entityName: "LastCodeLanguage") + } + convenience init() { self.init(entity: LastCodeLanguage.oldEntity, insertInto: CoreDataHelper.shared.context) } diff --git a/Stepic/Legacy/Model/Entities/LastStep/LastStep+CoreDataProperties.swift b/Stepic/Legacy/Model/Entities/LastStep/LastStep+CoreDataProperties.swift index 6f75ea5dbb..3224b7e4fc 100644 --- a/Stepic/Legacy/Model/Entities/LastStep/LastStep+CoreDataProperties.swift +++ b/Stepic/Legacy/Model/Entities/LastStep/LastStep+CoreDataProperties.swift @@ -20,6 +20,10 @@ extension LastStep { NSEntityDescription.entity(forEntityName: "LastStep", in: CoreDataHelper.shared.context)! } + static var fetchRequest: NSFetchRequest { + NSFetchRequest(entityName: "LastStep") + } + convenience init() { self.init(entity: LastStep.oldEntity, insertInto: CoreDataHelper.shared.context) } diff --git a/Stepic/Legacy/Model/Entities/Lesson/Lesson+CoreDataProperties.swift b/Stepic/Legacy/Model/Entities/Lesson/Lesson+CoreDataProperties.swift index 08c1ef11a6..19c5eba545 100644 --- a/Stepic/Legacy/Model/Entities/Lesson/Lesson+CoreDataProperties.swift +++ b/Stepic/Legacy/Model/Entities/Lesson/Lesson+CoreDataProperties.swift @@ -32,6 +32,10 @@ extension Lesson { NSEntityDescription.entity(forEntityName: "Lesson", in: CoreDataHelper.shared.context)! } + static var fetchRequest: NSFetchRequest { + NSFetchRequest(entityName: "Lesson") + } + convenience init() { self.init(entity: Lesson.oldEntity, insertInto: CoreDataHelper.shared.context) } diff --git a/Stepic/Legacy/Model/Entities/Notification/Notification+CoreDataProperties.swift b/Stepic/Legacy/Model/Entities/Notification/Notification+CoreDataProperties.swift index c366681574..dcf0fc3c06 100644 --- a/Stepic/Legacy/Model/Entities/Notification/Notification+CoreDataProperties.swift +++ b/Stepic/Legacy/Model/Entities/Notification/Notification+CoreDataProperties.swift @@ -25,13 +25,17 @@ extension Notification { NSEntityDescription.entity(forEntityName: "Notification", in: CoreDataHelper.shared.context)! } + static var fetchRequest: NSFetchRequest { + NSFetchRequest(entityName: "Notification") + } + convenience init() { self.init(entity: Notification.oldEntity, insertInto: CoreDataHelper.shared.context) } var id: Int { get { - managedId?.intValue ?? -1 + managedId?.intValue ?? -1 } set { managedId = newValue as NSNumber? @@ -40,7 +44,7 @@ extension Notification { var htmlText: String? { get { - managedHtmlText + managedHtmlText } set { managedHtmlText = newValue @@ -49,7 +53,7 @@ extension Notification { var time: Date? { get { - managedTime + managedTime } set { managedTime = newValue @@ -70,7 +74,7 @@ extension Notification { var isMuted: Bool { get { - managedIsMuted?.boolValue ?? false + managedIsMuted?.boolValue ?? false } set { managedIsMuted = newValue as NSNumber? @@ -79,7 +83,7 @@ extension Notification { var isFavorite: Bool { get { - managedIsFavorite?.boolValue ?? false + managedIsFavorite?.boolValue ?? false } set { managedIsFavorite = newValue as NSNumber? @@ -113,7 +117,7 @@ extension Notification { // Maybe it will be helpful in the future var priority: String? { get { - managedPriority + managedPriority } set { managedPriority = newValue @@ -123,7 +127,7 @@ extension Notification { // Maybe it will be helpful in the future var level: String? { get { - managedLevel + managedLevel } set { managedLevel = newValue diff --git a/Stepic/Legacy/Model/Entities/Notification/Notification+FetchMethods.swift b/Stepic/Legacy/Model/Entities/Notification/Notification+FetchMethods.swift index 2a89cb1c62..e134cd30f2 100644 --- a/Stepic/Legacy/Model/Entities/Notification/Notification+FetchMethods.swift +++ b/Stepic/Legacy/Model/Entities/Notification/Notification+FetchMethods.swift @@ -56,18 +56,6 @@ extension Notification { } } - static func deleteAll() { - let request = NSFetchRequest(entityName: "Notification") - do { - let results = try CoreDataHelper.shared.context.fetch(request) as? [Notification] - for obj in results ?? [] { - CoreDataHelper.shared.deleteFromStore(obj) - } - } catch { - print("notification: couldn't delete all notifications!") - } - } - static func markAllAsRead() { let request = NSBatchUpdateRequest(entityName: "Notification") request.predicate = NSPredicate(value: true) diff --git a/Stepic/Legacy/Model/Entities/Profile/Profile+CoreDataProperties.swift b/Stepic/Legacy/Model/Entities/Profile/Profile+CoreDataProperties.swift index 61da7466e9..5994a4c9cb 100644 --- a/Stepic/Legacy/Model/Entities/Profile/Profile+CoreDataProperties.swift +++ b/Stepic/Legacy/Model/Entities/Profile/Profile+CoreDataProperties.swift @@ -29,7 +29,7 @@ extension Profile { [NSSortDescriptor(key: #keyPath(managedId), ascending: false)] } - static func fetchRequest() -> NSFetchRequest { + static var fetchRequest: NSFetchRequest { NSFetchRequest(entityName: "Profile") } diff --git a/Stepic/Legacy/Model/Entities/Progress/Progress+CoreDataProperties.swift b/Stepic/Legacy/Model/Entities/Progress/Progress+CoreDataProperties.swift index 72e4ce460d..3c72a27d35 100644 --- a/Stepic/Legacy/Model/Entities/Progress/Progress+CoreDataProperties.swift +++ b/Stepic/Legacy/Model/Entities/Progress/Progress+CoreDataProperties.swift @@ -30,6 +30,10 @@ extension Progress { NSEntityDescription.entity(forEntityName: "Progress", in: CoreDataHelper.shared.context)! } + static var fetchRequest: NSFetchRequest { + NSFetchRequest(entityName: "Progress") + } + convenience init() { self.init(entity: Progress.oldEntity, insertInto: CoreDataHelper.shared.context) } diff --git a/Stepic/Legacy/Model/Entities/Progress/Progress.swift b/Stepic/Legacy/Model/Entities/Progress/Progress.swift index 48d22a2ccb..656a95ffbe 100644 --- a/Stepic/Legacy/Model/Entities/Progress/Progress.swift +++ b/Stepic/Legacy/Model/Entities/Progress/Progress.swift @@ -49,17 +49,4 @@ final class Progress: NSManagedObject, JSONSerializable, IDFetchable { ? Float(self.numberOfStepsPassed) / Float(self.numberOfSteps) * 100 : 100.0 } - - static func deleteAllStoredProgresses() { - let request = NSFetchRequest(entityName: "Progress") - - do { - let results = try CoreDataHelper.shared.context.fetch(request) as? [Progress] - for obj in results ?? [] { - CoreDataHelper.shared.deleteFromStore(obj) - } - } catch { - print("\n\n\nCould nnot delete progresses! \n\n\n") - } - } } diff --git a/Stepic/Legacy/Model/Entities/Section/Section+CoreDataProperties.swift b/Stepic/Legacy/Model/Entities/Section/Section+CoreDataProperties.swift index 644e5cf8fe..7c3a84f538 100644 --- a/Stepic/Legacy/Model/Entities/Section/Section+CoreDataProperties.swift +++ b/Stepic/Legacy/Model/Entities/Section/Section+CoreDataProperties.swift @@ -40,6 +40,10 @@ extension Section { NSEntityDescription.entity(forEntityName: "Section", in: CoreDataHelper.shared.context)! } + static var fetchRequest: NSFetchRequest
{ + NSFetchRequest
(entityName: "Section") + } + convenience init() { self.init(entity: Section.oldEntity, insertInto: CoreDataHelper.shared.context) } diff --git a/Stepic/Legacy/Model/Entities/Step/Step+CoreDataProperties.swift b/Stepic/Legacy/Model/Entities/Step/Step+CoreDataProperties.swift index 5fa01dab59..0f48645fcd 100644 --- a/Stepic/Legacy/Model/Entities/Step/Step+CoreDataProperties.swift +++ b/Stepic/Legacy/Model/Entities/Step/Step+CoreDataProperties.swift @@ -38,6 +38,10 @@ extension Step { NSEntityDescription.entity(forEntityName: "Step", in: CoreDataHelper.shared.context)! } + static var fetchRequest: NSFetchRequest { + NSFetchRequest(entityName: "Step") + } + convenience init() { self.init(entity: Step.oldEntity, insertInto: CoreDataHelper.shared.context) } diff --git a/Stepic/Legacy/Model/Entities/StepOptions/StepOptions+CoreDataProperties.swift b/Stepic/Legacy/Model/Entities/StepOptions/StepOptions+CoreDataProperties.swift index f7014e8ec9..dac79c738a 100644 --- a/Stepic/Legacy/Model/Entities/StepOptions/StepOptions+CoreDataProperties.swift +++ b/Stepic/Legacy/Model/Entities/StepOptions/StepOptions+CoreDataProperties.swift @@ -22,6 +22,10 @@ extension StepOptions { NSEntityDescription.entity(forEntityName: "StepOptions", in: CoreDataHelper.shared.context)! } + static var fetchRequest: NSFetchRequest { + NSFetchRequest(entityName: "StepOptions") + } + convenience init() { self.init(entity: StepOptions.oldEntity, insertInto: CoreDataHelper.shared.context) } diff --git a/Stepic/Legacy/Model/Entities/Submission/SubmissionEntity+CoreDataProperties.swift b/Stepic/Legacy/Model/Entities/Submission/SubmissionEntity+CoreDataProperties.swift index 35ec857889..421b6d6a45 100644 --- a/Stepic/Legacy/Model/Entities/Submission/SubmissionEntity+CoreDataProperties.swift +++ b/Stepic/Legacy/Model/Entities/Submission/SubmissionEntity+CoreDataProperties.swift @@ -19,7 +19,7 @@ extension SubmissionEntity { [NSSortDescriptor(key: #keyPath(managedID), ascending: false)] } - static func fetchRequest() -> NSFetchRequest { + static var fetchRequest: NSFetchRequest { NSFetchRequest(entityName: "SubmissionEntity") } } diff --git a/Stepic/Legacy/Model/Entities/Unit/Unit+CoreDataProperties.swift b/Stepic/Legacy/Model/Entities/Unit/Unit+CoreDataProperties.swift index 781218a681..21ff3c67eb 100644 --- a/Stepic/Legacy/Model/Entities/Unit/Unit+CoreDataProperties.swift +++ b/Stepic/Legacy/Model/Entities/Unit/Unit+CoreDataProperties.swift @@ -35,6 +35,10 @@ extension Unit { NSEntityDescription.entity(forEntityName: "Unit", in: CoreDataHelper.shared.context)! } + static var fetchRequest: NSFetchRequest { + NSFetchRequest(entityName: "Unit") + } + convenience init() { self.init(entity: Unit.oldEntity, insertInto: CoreDataHelper.shared.context) } diff --git a/Stepic/Legacy/Model/Entities/User/User+CoreDataProperties.swift b/Stepic/Legacy/Model/Entities/User/User+CoreDataProperties.swift index f63fdd5249..bc0608bb3a 100644 --- a/Stepic/Legacy/Model/Entities/User/User+CoreDataProperties.swift +++ b/Stepic/Legacy/Model/Entities/User/User+CoreDataProperties.swift @@ -30,12 +30,13 @@ extension User { @NSManaged var managedAttempts: NSSet? @NSManaged var managedProfileEntity: Profile? + @NSManaged var managedUserCourse: UserCourse? static var defaultSortDescriptors: [NSSortDescriptor] { [NSSortDescriptor(key: #keyPath(managedId), ascending: false)] } - static func fetchRequest() -> NSFetchRequest { + static var fetchRequest: NSFetchRequest { NSFetchRequest(entityName: "User") } @@ -174,6 +175,15 @@ extension User { } } + var userCourse: UserCourse? { + get { + self.managedUserCourse + } + set { + self.managedUserCourse = newValue + } + } + var authoredCourses: [Course] { get { self.managedAuthoredCourses?.allObjects as! [Course] diff --git a/Stepic/Legacy/Model/Entities/UserActivity/UserActivityEntity+CoreDataProperties.swift b/Stepic/Legacy/Model/Entities/UserActivity/UserActivityEntity+CoreDataProperties.swift index a03cf546ea..fe81eeca21 100644 --- a/Stepic/Legacy/Model/Entities/UserActivity/UserActivityEntity+CoreDataProperties.swift +++ b/Stepic/Legacy/Model/Entities/UserActivity/UserActivityEntity+CoreDataProperties.swift @@ -11,7 +11,7 @@ extension UserActivityEntity { [NSSortDescriptor(key: #keyPath(managedId), ascending: false)] } - static func fetchRequest() -> NSFetchRequest { + static var fetchRequest: NSFetchRequest { NSFetchRequest(entityName: "UserActivityEntity") } diff --git a/Stepic/Legacy/Model/Entities/UserCourse/UserCourse+CoreDataProperties.swift b/Stepic/Legacy/Model/Entities/UserCourse/UserCourse+CoreDataProperties.swift new file mode 100644 index 0000000000..9ec4d1429d --- /dev/null +++ b/Stepic/Legacy/Model/Entities/UserCourse/UserCourse+CoreDataProperties.swift @@ -0,0 +1,114 @@ +import CoreData +import Foundation + +extension UserCourse { + @NSManaged var managedId: NSNumber? + @NSManaged var managedUserId: NSNumber? + @NSManaged var managedCourseId: NSNumber? + @NSManaged var managedIsFavorite: NSNumber? + @NSManaged var managedIsPinned: NSNumber? + @NSManaged var managedIsArchived: NSNumber? + @NSManaged var managedLastViewed: Date? + + @NSManaged var managedUser: User? + @NSManaged var managedCourse: Course? + + static var oldEntity: NSEntityDescription { + NSEntityDescription.entity(forEntityName: "UserCourse", in: CoreDataHelper.shared.context)! + } + + static var defaultSortDescriptors: [NSSortDescriptor] { + [NSSortDescriptor(key: #keyPath(managedId), ascending: false)] + } + + static var fetchRequest: NSFetchRequest { + NSFetchRequest(entityName: "UserCourse") + } + + static var observableKeys: Set = ["managedIsFavorite", "managedIsArchived", "managedCourse"] + + convenience init() { + self.init(entity: Self.oldEntity, insertInto: CoreDataHelper.shared.context) + } + + var id: Int { + get { + self.managedId?.intValue ?? 0 + } + set { + self.managedId = NSNumber(value: newValue) + } + } + + var userID: Int { + get { + self.managedUserId?.intValue ?? 0 + } + set { + self.managedUserId = NSNumber(value: newValue) + } + } + + var courseID: Int { + get { + self.managedCourseId?.intValue ?? 0 + } + set { + self.managedCourseId = NSNumber(value: newValue) + } + } + + var isFavorite: Bool { + get { + self.managedIsFavorite?.boolValue ?? false + } + set { + self.managedIsFavorite = NSNumber(value: newValue) + } + } + + var isPinned: Bool { + get { + self.managedIsPinned?.boolValue ?? false + } + set { + self.managedIsPinned = NSNumber(value: newValue) + } + } + + var isArchived: Bool { + get { + self.managedIsArchived?.boolValue ?? false + } + set { + self.managedIsArchived = NSNumber(value: newValue) + } + } + + var lastViewed: Date { + get { + self.managedLastViewed ?? Date() + } + set { + self.managedLastViewed = newValue + } + } + + var course: Course? { + get { + self.managedCourse + } + set { + self.managedCourse = newValue + } + } + + var user: User? { + get { + self.managedUser + } + set { + self.managedUser = newValue + } + } +} diff --git a/Stepic/Legacy/Model/Entities/UserCourse/UserCourse.swift b/Stepic/Legacy/Model/Entities/UserCourse/UserCourse.swift new file mode 100644 index 0000000000..9a08c21d58 --- /dev/null +++ b/Stepic/Legacy/Model/Entities/UserCourse/UserCourse.swift @@ -0,0 +1,62 @@ +import CoreData +import Foundation +import SwiftyJSON + +final class UserCourse: NSManagedObject, JSONSerializable, IDFetchable { + typealias IdType = Int + + var json: JSON { + [ + JSONKey.isFavorite.rawValue: self.isFavorite, + JSONKey.isArchived.rawValue: self.isArchived, + JSONKey.course.rawValue: self.courseID + ] + } + + required convenience init(json: JSON) { + self.init() + self.update(json: json) + NotificationCenter.default.post(name: .userCourseDidCreateNotification, object: self) + } + + func update(json: JSON) { + self.id = json[JSONKey.id.rawValue].intValue + self.userID = json[JSONKey.user.rawValue].intValue + self.courseID = json[JSONKey.course.rawValue].intValue + self.isFavorite = json[JSONKey.isFavorite.rawValue].boolValue + self.isArchived = json[JSONKey.isArchived.rawValue].boolValue + self.lastViewed = Parser.shared.dateFromTimedateJSON(json[JSONKey.lastViewed.rawValue]) ?? Date() + } + + func hasEqualId(json: JSON) -> Bool { + self.id == json[JSONKey.id.rawValue].int + } + + override func prepareForDeletion() { + super.prepareForDeletion() + NotificationCenter.default.post(name: .userCourseDidDeleteNotification, object: self) + } + + override func didChangeValue(forKey key: String) { + super.didChangeValue(forKey: key) + + if Self.observableKeys.contains(key) { + NotificationCenter.default.post(name: .userCourseDidChangeNotification, object: self) + } + } + + enum JSONKey: String { + case id + case user + case course + case isFavorite = "is_favorite" + case isArchived = "is_archived" + case lastViewed = "last_viewed" + } +} + +extension Foundation.Notification.Name { + static let userCourseDidChangeNotification = NSNotification.Name("userCourseDidChangeNotification") + static let userCourseDidCreateNotification = NSNotification.Name("userCourseDidCreateNotification") + static let userCourseDidDeleteNotification = NSNotification.Name("userCourseDidDeleteNotification") +} diff --git a/Stepic/Legacy/Model/Entities/Video/Video+CoreDataProperties.swift b/Stepic/Legacy/Model/Entities/Video/Video+CoreDataProperties.swift index b879ca1d15..e4b4e05a80 100644 --- a/Stepic/Legacy/Model/Entities/Video/Video+CoreDataProperties.swift +++ b/Stepic/Legacy/Model/Entities/Video/Video+CoreDataProperties.swift @@ -26,6 +26,10 @@ extension Video { NSEntityDescription.entity(forEntityName: "Video", in: CoreDataHelper.shared.context)! } + static var fetchRequest: NSFetchRequest