From 0daf578cf55ade52c27459926fb1744bfb99663e Mon Sep 17 00:00:00 2001 From: Ivan Magda Date: Wed, 4 Dec 2019 18:27:05 +0300 Subject: [PATCH 1/8] Update SwiftLint from 0.37.0 to 0.38.0 (#585) --- Podfile | 2 +- Podfile.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Podfile b/Podfile index 5298136775..61aa4c4a28 100644 --- a/Podfile +++ b/Podfile @@ -15,7 +15,7 @@ def shared_pods pod 'Crashlytics', '3.14.0' pod 'DeviceKit', '2.3.0' pod 'PromiseKit', '6.11.0' - pod 'SwiftLint', '0.37.0' + pod 'SwiftLint', '0.38.0' pod 'Reveal-SDK', :configurations => ['Debug'] end diff --git a/Podfile.lock b/Podfile.lock index be2a794aa1..e7a592babb 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -167,7 +167,7 @@ PODS: - CocoaLumberjack (~> 3.0) - SVProgressHUD (2.2.5) - SwiftDate (6.1.0) - - SwiftLint (0.37.0) + - SwiftLint (0.38.0) - SwiftyGif (5.2.0) - SwiftyJSON (5.0.0) - Tabman (2.4.3): @@ -226,7 +226,7 @@ DEPENDENCIES: - SVGKit (from `https://github.com/SVGKit/SVGKit.git`, branch `2.x`) - SVProgressHUD (= 2.2.5) - SwiftDate (= 6.1.0) - - SwiftLint (= 0.37.0) + - SwiftLint (= 0.38.0) - SwiftyJSON (= 5.0.0) - Tabman (= 2.4.3) - TSMessages (from `https://github.com/KrauseFx/TSMessages.git`) @@ -379,7 +379,7 @@ SPEC CHECKSUMS: SVGKit: 8a2fc74258bdb2abb54d3b65f3dd68b0277a9c4d SVProgressHUD: 1428aafac632c1f86f62aa4243ec12008d7a51d6 SwiftDate: fa2bb3962056bb44047b4b85a30044e5eae30b03 - SwiftLint: c078a14d7d7ade75e5507795d185e3da41d844d2 + SwiftLint: 4105f061f9812b214568b736dab580ab2c73a582 SwiftyGif: b85c6b33a9411859d9e1db998b6a8214aea942df SwiftyJSON: 36413e04c44ee145039d332b4f4e2d3e8d6c4db7 Tabman: c2c83ebfcbec3e5be67e27a1dd6689a4e3efccd3 @@ -390,6 +390,6 @@ SPEC CHECKSUMS: VK-ios-sdk: 62a10b6571fbcda0657f455fedce7fedf55b4cd0 YandexMobileMetrica: edb00e8af2903290e142ba4c488adf8d394e828a -PODFILE CHECKSUM: 1a9ef034b87e939726fa45dce93df960f35abbcf +PODFILE CHECKSUM: b206ff1d21c6c7d4fd68be538cca487caa993507 COCOAPODS: 1.8.4 From e854dd1834c9fa3a4cdc4c7d658e0bcb0c281f77 Mon Sep 17 00:00:00 2001 From: Ivan Magda Date: Wed, 4 Dec 2019 18:32:06 +0300 Subject: [PATCH 2/8] Update SDWebImage from 5.3.2 to 5.3.3 (#584) --- Podfile | 2 +- Podfile.lock | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Podfile b/Podfile index 61aa4c4a28..89e2a3fb90 100644 --- a/Podfile +++ b/Podfile @@ -8,7 +8,7 @@ def shared_pods pod 'Alamofire', '4.9.1' pod 'Atributika', '4.9.0' pod 'SwiftyJSON', '5.0.0' - pod 'SDWebImage', '5.3.2' + pod 'SDWebImage', '5.3.3' pod 'SVGKit', :git => 'https://github.com/SVGKit/SVGKit.git', :branch => '2.x' pod 'Logging', :git => 'https://github.com/ivan-magda/swift-log.git', :branch => 'swift-4' pod 'Fabric', '1.10.2' diff --git a/Podfile.lock b/Podfile.lock index e7a592babb..ed64636ffb 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -155,12 +155,12 @@ PODS: - PromiseKit/CorePromise - PromiseKit/UIKit (6.11.0): - PromiseKit/CorePromise - - Protobuf (3.11.0) + - Protobuf (3.11.1) - Quick (2.2.0) - Reveal-SDK (24) - - SDWebImage (5.3.2): - - SDWebImage/Core (= 5.3.2) - - SDWebImage/Core (5.3.2) + - SDWebImage (5.3.3): + - SDWebImage/Core (= 5.3.3) + - SDWebImage/Core (5.3.3) - SnapKit (4.2.0) - STRegex (2.1.0) - SVGKit (2.1.0): @@ -220,7 +220,7 @@ DEPENDENCIES: - PromiseKit (= 6.11.0) - Quick (= 2.2.0) - Reveal-SDK - - SDWebImage (= 5.3.2) + - SDWebImage (= 5.3.3) - SnapKit (= 4.2.0) - STRegex (= 2.1.0) - SVGKit (from `https://github.com/SVGKit/SVGKit.git`, branch `2.x`) @@ -370,10 +370,10 @@ SPEC CHECKSUMS: pop: d582054913807fd11fd50bfe6a539d91c7e1a55a Presentr: 7078d7eb5d1661ebeaae60c9e42a1e534de1b993 PromiseKit: e4863d06976e7dee5e41c04fc7371c16b3600292 - Protobuf: 394b2bf29ec303f4325e3ee4892c09e675647152 + Protobuf: 20d79da7f20b5928b80043b05080b816e802659e Quick: 7fb19e13be07b5dfb3b90d4f9824c855a11af40e Reveal-SDK: 5d7e56b8f018c0a88b3a2c10bf68d598bbd3b071 - SDWebImage: 6ac2eb96571bff96ecde31a987172c5934a0eb7d + SDWebImage: 51ab1ce3ebd20dec6665ae8ba25c928da323db41 SnapKit: fe8a619752f3f27075cc9a90244d75c6c3f27e2a STRegex: dfa420d93d8c1402956233b3879ec1fc14b45fbe SVGKit: 8a2fc74258bdb2abb54d3b65f3dd68b0277a9c4d @@ -390,6 +390,6 @@ SPEC CHECKSUMS: VK-ios-sdk: 62a10b6571fbcda0657f455fedce7fedf55b4cd0 YandexMobileMetrica: edb00e8af2903290e142ba4c488adf8d394e828a -PODFILE CHECKSUM: b206ff1d21c6c7d4fd68be538cca487caa993507 +PODFILE CHECKSUM: f7b011bbf06ceae685b36249b8bb9b52967d4cd2 COCOAPODS: 1.8.4 From 7ab85a0a7dbbdab791a798b6ec7c1de0afce57ee Mon Sep 17 00:00:00 2001 From: Ivan Magda Date: Sat, 7 Dec 2019 20:06:39 +0300 Subject: [PATCH 3/8] Update SDWebImage from 5.3.3 to 5.4.0 (#587) * Update SDWebImage from 5.3.3 to 5.4.0 --- Podfile | 2 +- Podfile.lock | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Podfile b/Podfile index 89e2a3fb90..bdaa5665cd 100644 --- a/Podfile +++ b/Podfile @@ -8,7 +8,7 @@ def shared_pods pod 'Alamofire', '4.9.1' pod 'Atributika', '4.9.0' pod 'SwiftyJSON', '5.0.0' - pod 'SDWebImage', '5.3.3' + pod 'SDWebImage', '5.4.0' pod 'SVGKit', :git => 'https://github.com/SVGKit/SVGKit.git', :branch => '2.x' pod 'Logging', :git => 'https://github.com/ivan-magda/swift-log.git', :branch => 'swift-4' pod 'Fabric', '1.10.2' diff --git a/Podfile.lock b/Podfile.lock index ed64636ffb..b6db5c06e3 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -158,9 +158,9 @@ PODS: - Protobuf (3.11.1) - Quick (2.2.0) - Reveal-SDK (24) - - SDWebImage (5.3.3): - - SDWebImage/Core (= 5.3.3) - - SDWebImage/Core (5.3.3) + - SDWebImage (5.4.0): + - SDWebImage/Core (= 5.4.0) + - SDWebImage/Core (5.4.0) - SnapKit (4.2.0) - STRegex (2.1.0) - SVGKit (2.1.0): @@ -220,7 +220,7 @@ DEPENDENCIES: - PromiseKit (= 6.11.0) - Quick (= 2.2.0) - Reveal-SDK - - SDWebImage (= 5.3.3) + - SDWebImage (= 5.4.0) - SnapKit (= 4.2.0) - STRegex (= 2.1.0) - SVGKit (from `https://github.com/SVGKit/SVGKit.git`, branch `2.x`) @@ -373,7 +373,7 @@ SPEC CHECKSUMS: Protobuf: 20d79da7f20b5928b80043b05080b816e802659e Quick: 7fb19e13be07b5dfb3b90d4f9824c855a11af40e Reveal-SDK: 5d7e56b8f018c0a88b3a2c10bf68d598bbd3b071 - SDWebImage: 51ab1ce3ebd20dec6665ae8ba25c928da323db41 + SDWebImage: 5bf6aec6481ae2a062bdc59f9d6c1d1e552090e0 SnapKit: fe8a619752f3f27075cc9a90244d75c6c3f27e2a STRegex: dfa420d93d8c1402956233b3879ec1fc14b45fbe SVGKit: 8a2fc74258bdb2abb54d3b65f3dd68b0277a9c4d @@ -390,6 +390,6 @@ SPEC CHECKSUMS: VK-ios-sdk: 62a10b6571fbcda0657f455fedce7fedf55b4cd0 YandexMobileMetrica: edb00e8af2903290e142ba4c488adf8d394e828a -PODFILE CHECKSUM: f7b011bbf06ceae685b36249b8bb9b52967d4cd2 +PODFILE CHECKSUM: 82838d40c87b8a99393ee56f68f617bed56bd820 COCOAPODS: 1.8.4 From b54419b2b0c09748ecef874b192d5753f6e435e9 Mon Sep 17 00:00:00 2001 From: Ivan Magda Date: Sun, 8 Dec 2019 15:39:17 +0300 Subject: [PATCH 4/8] Continue learning after authorization from course info (#588) * Continue learning after auth from course info --- .../CourseInfo/CourseInfoViewController.swift | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Stepic/Sources/Modules/CourseInfo/CourseInfoViewController.swift b/Stepic/Sources/Modules/CourseInfo/CourseInfoViewController.swift index 74ba9e0d8d..7b2f7e18d3 100644 --- a/Stepic/Sources/Modules/CourseInfo/CourseInfoViewController.swift +++ b/Stepic/Sources/Modules/CourseInfo/CourseInfoViewController.swift @@ -467,7 +467,19 @@ extension CourseInfoViewController: CourseInfoViewControllerProtocol { } func displayAuthorization(viewModel: CourseInfo.AuthorizationPresentation.ViewModel) { - RoutingManager.auth.routeFrom(controller: self, success: nil, cancel: nil) + RoutingManager.auth.routeFrom( + controller: self, + success: { [weak self] in + guard let strongSelf = self else { + return + } + + // Refresh course state and continue learning + strongSelf.interactor.doCourseRefresh(request: .init()) + strongSelf.interactor.doMainCourseAction(request: .init()) + }, + cancel: nil + ) } func displayPaidCourseBuying(viewModel: CourseInfo.PaidCourseBuyingPresentation.ViewModel) { From b8d54cb55653a25205f6f3d68e4f6587265d8503 Mon Sep 17 00:00:00 2001 From: Ivan Magda Date: Tue, 10 Dec 2019 03:08:36 +0300 Subject: [PATCH 5/8] Discount policy (#589) * Add new model version * Parse discount policy * Add localizable strings * Display discount policy * Quiz top separator now rendered in BaseQuizView --- Stepic.xcodeproj/project.pbxproj | 8 +- Stepic/Model.xcdatamodeld/.xccurrentversion | 2 +- .../contents | 302 ++++++++++++++++++ Stepic/Section+CoreDataProperties.swift | 15 + Stepic/Section.swift | 56 +++- Stepic/Sources/Common/DiscountingPolicy.swift | 19 ++ .../NewLesson/NewLessonInteractor.swift | 3 + .../Quizzes/BaseQuiz/BaseQuizInteractor.swift | 3 +- .../Quizzes/BaseQuiz/BaseQuizPresenter.swift | 33 +- .../Quizzes/BaseQuiz/BaseQuizView.swift | 67 +++- .../BaseQuiz/BaseQuizViewController.swift | 2 + .../Quizzes/BaseQuiz/BaseQuizViewModel.swift | 2 + .../Views/NewChoiceQuizView.swift | 16 +- .../Quizzes/NewCodeQuiz/NewCodeQuizView.swift | 13 +- .../NewFreeAnswerQuizView.swift | 18 +- .../Views/NewMatchingQuizView.swift | 16 +- .../Views/NewSortingQuizView.swift | 16 +- .../NewStringQuiz/NewStringQuizView.swift | 16 +- Stepic/en.lproj/Localizable.strings | 5 + Stepic/ru.lproj/Localizable.strings | 5 + 20 files changed, 504 insertions(+), 113 deletions(-) create mode 100644 Stepic/Model.xcdatamodeld/Model_discount_policy.xcdatamodel/contents create mode 100644 Stepic/Sources/Common/DiscountingPolicy.swift diff --git a/Stepic.xcodeproj/project.pbxproj b/Stepic.xcodeproj/project.pbxproj index dc2ec5e0cf..686dfdb62c 100644 --- a/Stepic.xcodeproj/project.pbxproj +++ b/Stepic.xcodeproj/project.pbxproj @@ -404,6 +404,7 @@ 2C096583236C555D005B771A /* NSAttributedString+TrimmingCharacters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C096582236C555D005B771A /* NSAttributedString+TrimmingCharacters.swift */; }; 2C0B42C1234CD17C00B03EA1 /* CustomMenuBlockTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C0B42BF234CD17C00B03EA1 /* CustomMenuBlockTableViewCell.swift */; }; 2C0B42C2234CD17C00B03EA1 /* CustomMenuBlockTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2C0B42C0234CD17C00B03EA1 /* CustomMenuBlockTableViewCell.xib */; }; + 2C10100B239EFAD700440651 /* DiscountingPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C10100A239EFAD700440651 /* DiscountingPolicy.swift */; }; 2C104B682069064D0026FEB9 /* autocomplete_suggestions.plist in Resources */ = {isa = PBXBuildFile; fileRef = 2C104B672069064D0026FEB9 /* autocomplete_suggestions.plist */; }; 2C10C458221496F300FA3E13 /* CourseReviewsAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C10C457221496F300FA3E13 /* CourseReviewsAPI.swift */; }; 2C1219901F9655AB00A43E98 /* NotificationsSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C12198F1F9655AB00A43E98 /* NotificationsSection.swift */; }; @@ -1522,6 +1523,8 @@ 2C096582236C555D005B771A /* NSAttributedString+TrimmingCharacters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSAttributedString+TrimmingCharacters.swift"; sourceTree = ""; }; 2C0B42BF234CD17C00B03EA1 /* CustomMenuBlockTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomMenuBlockTableViewCell.swift; sourceTree = ""; }; 2C0B42C0234CD17C00B03EA1 /* CustomMenuBlockTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = CustomMenuBlockTableViewCell.xib; sourceTree = ""; }; + 2C101009239E7A1E00440651 /* Model_discount_policy.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Model_discount_policy.xcdatamodel; sourceTree = ""; }; + 2C10100A239EFAD700440651 /* DiscountingPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscountingPolicy.swift; sourceTree = ""; }; 2C104B672069064D0026FEB9 /* autocomplete_suggestions.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = autocomplete_suggestions.plist; sourceTree = ""; }; 2C10C457221496F300FA3E13 /* CourseReviewsAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseReviewsAPI.swift; sourceTree = ""; }; 2C12198F1F9655AB00A43E98 /* NotificationsSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsSection.swift; sourceTree = ""; }; @@ -4519,6 +4522,7 @@ children = ( 2C20C86522F8E4BF0052E9BF /* CodeDetails.swift */, 2C20C86B22F988030052E9BF /* CodeEditorTheme.swift */, + 2C10100A239EFAD700440651 /* DiscountingPolicy.swift */, 2CD462E9226F4279004E4725 /* FetchResult.swift */, 2C3DAB90233D735D00453B1C /* FontSize.swift */, 2C7F78392271D5480089FDD7 /* LayoutInsets.swift */, @@ -6611,6 +6615,7 @@ 08AB82381D74C44100FDEADE /* Session.swift in Sources */, 08901E6D1CD102DF00D94613 /* UpdatePreferencesContainer.swift in Sources */, 2C3A24572359DD2E00E2405F /* DiscussionsViewModel.swift in Sources */, + 2C10100B239EFAD700440651 /* DiscountingPolicy.swift in Sources */, 082E35B220B5F1E4006E28F9 /* StorageRecordsAPI.swift in Sources */, 2CB5B15D22941D7000D7F706 /* StepDiscussionsButton.swift in Sources */, 08F485B11C58EB0D000165AA /* SortingReply.swift in Sources */, @@ -7605,6 +7610,7 @@ 08D1EF6E1BB5618700BE84E6 /* Model.xcdatamodeld */ = { isa = XCVersionGroup; children = ( + 2C101009239E7A1E00440651 /* Model_discount_policy.xcdatamodel */, 2CEE97B0239123EA005503EF /* Model_step_passed_by_correct_ratio.xcdatamodel */, 2C2EBAB92382E3EB00AB1B83 /* Model_lesson_can_edit.xcdatamodel */, 2CD6E254234DFFD500F49303 /* Model_email_addresses.xcdatamodel */, @@ -7650,7 +7656,7 @@ 0802AC531C7222B200C4F3E6 /* Model_v2.xcdatamodel */, 08D1EF6F1BB5618700BE84E6 /* Model.xcdatamodel */, ); - currentVersion = 2CEE97B0239123EA005503EF /* Model_step_passed_by_correct_ratio.xcdatamodel */; + currentVersion = 2C101009239E7A1E00440651 /* Model_discount_policy.xcdatamodel */; path = Model.xcdatamodeld; sourceTree = ""; versionGroupType = wrapper.xcdatamodel; diff --git a/Stepic/Model.xcdatamodeld/.xccurrentversion b/Stepic/Model.xcdatamodeld/.xccurrentversion index a494b96d22..ad7e11caab 100644 --- a/Stepic/Model.xcdatamodeld/.xccurrentversion +++ b/Stepic/Model.xcdatamodeld/.xccurrentversion @@ -3,6 +3,6 @@ _XCCurrentVersionName - Model_step_passed_by_correct_ratio.xcdatamodel + Model_discount_policy.xcdatamodel diff --git a/Stepic/Model.xcdatamodeld/Model_discount_policy.xcdatamodel/contents b/Stepic/Model.xcdatamodeld/Model_discount_policy.xcdatamodel/contents new file mode 100644 index 0000000000..ea6a4fe128 --- /dev/null +++ b/Stepic/Model.xcdatamodeld/Model_discount_policy.xcdatamodel/contents @@ -0,0 +1,302 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Stepic/Section+CoreDataProperties.swift b/Stepic/Section+CoreDataProperties.swift index 2b24e9b73b..709dbf4a96 100644 --- a/Stepic/Section+CoreDataProperties.swift +++ b/Stepic/Section+CoreDataProperties.swift @@ -32,6 +32,8 @@ extension Section { @NSManaged var managedCourse: Course? @NSManaged var managedProgress: Progress? + @NSManaged var managedDiscountingPolicy: String? + static var oldEntity: NSEntityDescription { return NSEntityDescription.entity(forEntityName: "Section", in: CoreDataHelper.instance.context)! } @@ -183,4 +185,17 @@ extension Section { return (self.managedUnitsArray as? [Int]) ?? [] } } + + var discountingPolicy: String? { + get { + return self.managedDiscountingPolicy + } + set { + self.managedDiscountingPolicy = newValue + } + } + + var discountingPolicyType: DiscountingPolicy { + return DiscountingPolicy(rawValue: self.discountingPolicy ?? "") ?? .noDiscount + } } diff --git a/Stepic/Section.swift b/Stepic/Section.swift index 13b033be05..5df59749e4 100644 --- a/Stepic/Section.swift +++ b/Stepic/Section.swift @@ -16,31 +16,33 @@ final class Section: NSManagedObject, IDFetchable { required convenience init(json: JSON) { self.init() - initialize(json) + self.initialize(json) } func initialize(_ json: JSON) { - id = json["id"].intValue - title = json["title"].stringValue - position = json["position"].intValue - isActive = json["is_active"].boolValue - progressId = json["progress"].string - beginDate = Parser.shared.dateFromTimedateJSON(json["begin_date"]) - endDate = Parser.shared.dateFromTimedateJSON(json["end_date"]) - softDeadline = Parser.shared.dateFromTimedateJSON(json["soft_deadline"]) - hardDeadline = Parser.shared.dateFromTimedateJSON(json["hard_deadline"]) - - testSectionAction = json["actions"]["test_section"].string - isExam = json["is_exam"].boolValue - unitsArray = json["units"].arrayObject as! [Int] - courseId = json["course"].intValue + self.id = json[JSONKey.id.rawValue].intValue + self.title = json[JSONKey.title.rawValue].stringValue + self.position = json[JSONKey.position.rawValue].intValue + self.isActive = json[JSONKey.isActive.rawValue].boolValue + self.progressId = json[JSONKey.progress.rawValue].string + self.beginDate = Parser.shared.dateFromTimedateJSON(json[JSONKey.beginDate.rawValue]) + self.endDate = Parser.shared.dateFromTimedateJSON(json[JSONKey.endDate.rawValue]) + self.softDeadline = Parser.shared.dateFromTimedateJSON(json[JSONKey.softDeadline.rawValue]) + self.hardDeadline = Parser.shared.dateFromTimedateJSON(json[JSONKey.hardDeadline.rawValue]) + + self.testSectionAction = json[JSONKey.actions.rawValue][JSONKey.testSection.rawValue].string + self.isExam = json[JSONKey.isExam.rawValue].boolValue + self.unitsArray = json[JSONKey.units.rawValue].arrayObject as! [Int] + self.courseId = json[JSONKey.course.rawValue].intValue + + self.discountingPolicy = json[JSONKey.discountingPolicy.rawValue].string } func update(json: JSON) { - initialize(json) + self.initialize(json) } - static func fetch(_ ids: [Int]) -> [Section] { + static func fetch(_ ids: [IdType]) -> [Section] { let request = NSFetchRequest(entityName: "Section") let idPredicates = ids.map { NSPredicate(format: "managedId == %@", $0 as NSNumber) } request.predicate = NSCompoundPredicate(type: .or, subpredicates: idPredicates) @@ -223,8 +225,28 @@ final class Section: NSManagedObject, IDFetchable { var isReachable: Bool { return (self.isActive || self.testSectionAction != nil) && (self.progressId != nil || self.isExam) } + + enum JSONKey: String { + case id + case title + case position + case isActive = "is_active" + case progress + case beginDate = "begin_date" + case endDate = "end_date" + case softDeadline = "soft_deadline" + case hardDeadline = "hard_deadline" + case actions + case testSection = "test_section" + case isExam = "is_exam" + case units + case course + case discountingPolicy = "discounting_policy" + } } +// MARK: - Section: NextLessonServiceSectionSourceProtocol - + extension Section: NextLessonServiceSectionSourceProtocol { var unitsList: [NextLessonServiceUnitSourceProtocol] { return self.units diff --git a/Stepic/Sources/Common/DiscountingPolicy.swift b/Stepic/Sources/Common/DiscountingPolicy.swift new file mode 100644 index 0000000000..cd5425dec6 --- /dev/null +++ b/Stepic/Sources/Common/DiscountingPolicy.swift @@ -0,0 +1,19 @@ +import Foundation + +enum DiscountingPolicy: String { + case noDiscount = "no_discount" + case inverse + case firstOne = "first_one" + case firstThree = "first_three" + + var numberOfTries: Int { + switch self { + case .noDiscount, .inverse: + return Int.max + case .firstOne: + return 1 + case .firstThree: + return 3 + } + } +} diff --git a/Stepic/Sources/Modules/NewLesson/NewLessonInteractor.swift b/Stepic/Sources/Modules/NewLesson/NewLessonInteractor.swift index feef32eaf4..0d7949da41 100644 --- a/Stepic/Sources/Modules/NewLesson/NewLessonInteractor.swift +++ b/Stepic/Sources/Modules/NewLesson/NewLessonInteractor.swift @@ -97,6 +97,7 @@ final class NewLessonInteractor: NewLessonInteractorProtocol { // If unit exists then load assignments let assignmentsPromise: Promise<[Assignment]> if let unit = unit { + unit.lesson = lesson assignmentsPromise = self.provider.fetchAssignments(ids: unit.assignmentsArray).map { $0.value ?? [] } } else { assignmentsPromise = .value([]) @@ -128,6 +129,8 @@ final class NewLessonInteractor: NewLessonInteractorProtocol { } }() + steps.forEach { $0.lesson = lesson } + let data = NewLesson.LessonLoad.Data( lesson: lesson, steps: steps, diff --git a/Stepic/Sources/Modules/Quizzes/BaseQuiz/BaseQuizInteractor.swift b/Stepic/Sources/Modules/Quizzes/BaseQuiz/BaseQuizInteractor.swift index 2f9a839d44..bd89a26e44 100644 --- a/Stepic/Sources/Modules/Quizzes/BaseQuiz/BaseQuizInteractor.swift +++ b/Stepic/Sources/Modules/Quizzes/BaseQuiz/BaseQuizInteractor.swift @@ -69,8 +69,7 @@ final class BaseQuizInteractor: BaseQuizInteractorProtocol { return self.provider.fetchSubmissions(for: self.step, attempt: attempt).map { (attempt, $0.0.first) } }.then(on: queue) { attempt, submission -> Guarantee<(Attempt, Submission?, Reply?, Int)> in let cachedReply = ReplyCache.shared.getReply(forStepId: self.step.id, attemptId: attempt.id) - return (self.step.hasSubmissionRestrictions ? self.countSubmissions() : Guarantee.value(0)) - .map { (attempt, submission, cachedReply, $0) } + return self.countSubmissions().map { (attempt, submission, cachedReply, $0) } }.done { attempt, submission, cachedReply, submissionLimit in self.submissionsCount = submissionLimit self.currentAttempt = attempt diff --git a/Stepic/Sources/Modules/Quizzes/BaseQuiz/BaseQuizPresenter.swift b/Stepic/Sources/Modules/Quizzes/BaseQuiz/BaseQuizPresenter.swift index 70f0702fbf..b6c37c6b91 100644 --- a/Stepic/Sources/Modules/Quizzes/BaseQuiz/BaseQuizPresenter.swift +++ b/Stepic/Sources/Modules/Quizzes/BaseQuiz/BaseQuizPresenter.swift @@ -113,6 +113,35 @@ final class BaseQuizPresenter: BaseQuizPresenterProtocol { return nil }() + let discountingPolicy = step.lesson?.unit?.section?.discountingPolicyType ?? .noDiscount + let isDiscountingPolicyVisible = discountingPolicy != .noDiscount && quizStatus != .correct + + let discountingPolicyText: String = { + switch discountingPolicy { + case .inverse: + return NSLocalizedString("DiscountPolicyInverseTitle", comment: "") + case .firstOne, .firstThree: + let remainingSubmissionCount = discountingPolicy.numberOfTries - submissionsCount + if remainingSubmissionCount > 0 { + return String( + format: StringHelper.pluralize( + number: remainingSubmissionCount, + forms: [ + NSLocalizedString("DiscountPolicyFirstNTitle1", comment: ""), + NSLocalizedString("DiscountPolicyFirstNTitle234", comment: ""), + NSLocalizedString("DiscountPolicyFirstNTitle567890", comment: "") + ] + ), + "\(remainingSubmissionCount)" + ) + } else { + return NSLocalizedString("DiscountPolicyNoWayTitle", comment: "") + } + default: + return "" + } + }() + return BaseQuizViewModel( quizStatus: quizStatus, reply: submission?.reply ?? cachedReply, @@ -128,7 +157,9 @@ final class BaseQuizPresenter: BaseQuizPresenterProtocol { hintContent: hintContent, codeDetails: codeDetails, canNavigateToNextStep: canNavigateToNextStep, - canRetry: canRetry + canRetry: canRetry, + discountingPolicyTitle: discountingPolicyText, + isDiscountingPolicyVisible: isDiscountingPolicyVisible ) } diff --git a/Stepic/Sources/Modules/Quizzes/BaseQuiz/BaseQuizView.swift b/Stepic/Sources/Modules/Quizzes/BaseQuiz/BaseQuizView.swift index 067fb6f0f2..06b87bcfea 100644 --- a/Stepic/Sources/Modules/Quizzes/BaseQuiz/BaseQuizView.swift +++ b/Stepic/Sources/Modules/Quizzes/BaseQuiz/BaseQuizView.swift @@ -25,10 +25,16 @@ extension BaseQuizView { let retryButtonBackgroundColor = UIColor.white let retryButtonTintColor = UIColor(hex: 0xC8C7CC) + let discountingPolicyTextColor = UIColor.mainDark + let discountingPolicyFont = UIFont.systemFont(ofSize: 12, weight: .medium) + let spacing: CGFloat = 16 let insets = LayoutInsets(left: 16, right: 16) let loadingIndicatorColor = UIColor.mainDark + + let separatorColor = UIColor(hex: 0xEAECF0) + let separatorHeight: CGFloat = 1 } enum Animation { @@ -49,6 +55,20 @@ final class BaseQuizView: UIView { return loadingIndicatorView }() + private lazy var separatorView: UIView = { + let view = UIView() + view.backgroundColor = self.appearance.separatorColor + return view + }() + + private lazy var discountingPolicyLabel: UILabel = { + let label = UILabel() + label.textColor = self.appearance.discountingPolicyTextColor + label.font = self.appearance.discountingPolicyFont + label.numberOfLines = 0 + return label + }() + private lazy var submitButton: UIButton = { let submitButton = UIButton(type: .system) submitButton.setTitleColor(self.appearance.submitButtonTextColor, for: .normal) @@ -83,7 +103,14 @@ final class BaseQuizView: UIView { }() private lazy var stackView: UIStackView = { - let stackView = UIStackView(arrangedSubviews: [self.feedbackContainerView, self.submitControlsContainerView]) + let stackView = UIStackView( + arrangedSubviews: [ + self.separatorView, + self.discountingPolicyContainerView, + self.feedbackContainerView, + self.submitControlsContainerView + ] + ) stackView.axis = .vertical stackView.spacing = self.appearance.spacing return stackView @@ -100,6 +127,11 @@ final class BaseQuizView: UIView { private lazy var submitContainerView = UIView() private lazy var retryContainerView = UIView() private lazy var feedbackContainerView = UIView() + private lazy var discountingPolicyContainerView: UIView = { + let view = UIView() + view.isHidden = true + return view + }() // Peer review: make feedback view clickable private lazy var peerReviewTapGestureRecognizer = UITapGestureRecognizer( @@ -135,6 +167,18 @@ final class BaseQuizView: UIView { } } + var isDiscountPolicyAvailable = false { + didSet { + self.discountingPolicyContainerView.isHidden = !self.isDiscountPolicyAvailable + } + } + + var discountPolicyTitle: String? { + didSet { + self.discountingPolicyLabel.text = self.discountPolicyTitle + } + } + var isPeerReviewAvailable = false init(frame: CGRect = .zero, appearance: Appearance = Appearance()) { @@ -152,7 +196,13 @@ final class BaseQuizView: UIView { } func addQuiz(view: UIView) { - self.stackView.insertArrangedSubview(view, at: 0) + guard let discountingPolicyLabelIndex = self.stackView.arrangedSubviews.firstIndex( + where: { $0 === self.discountingPolicyContainerView } + ) else { + return self.stackView.insertArrangedSubview(view, at: 0) + } + + self.stackView.insertArrangedSubview(view, at: discountingPolicyLabelIndex + 1) } func showFeedback(state: QuizFeedbackView.State, title: String, hint: String? = nil) { @@ -226,6 +276,7 @@ extension BaseQuizView: ProgrammaticallyInitializableViewProtocol { func addSubviews() { self.addSubview(self.stackView) + self.discountingPolicyContainerView.addSubview(self.discountingPolicyLabel) self.submitControlsContainerView.addSubview(self.submitControlsStackView) self.retryContainerView.addSubview(self.retryButton) self.submitContainerView.addSubview(self.submitButton) @@ -237,6 +288,18 @@ extension BaseQuizView: ProgrammaticallyInitializableViewProtocol { } func makeConstraints() { + self.separatorView.translatesAutoresizingMaskIntoConstraints = false + self.separatorView.snp.makeConstraints { make in + make.height.equalTo(self.appearance.separatorHeight) + } + + self.discountingPolicyLabel.translatesAutoresizingMaskIntoConstraints = false + self.discountingPolicyLabel.snp.makeConstraints { make in + make.top.bottom.equalToSuperview() + make.leading.equalToSuperview().offset(self.appearance.insets.left) + make.trailing.equalToSuperview().offset(-self.appearance.insets.right) + } + self.submitControlsStackView.translatesAutoresizingMaskIntoConstraints = false self.submitControlsStackView.snp.makeConstraints { make in make.top.bottom.equalToSuperview() diff --git a/Stepic/Sources/Modules/Quizzes/BaseQuiz/BaseQuizViewController.swift b/Stepic/Sources/Modules/Quizzes/BaseQuiz/BaseQuizViewController.swift index 60f4f7037f..f57d86e4ba 100644 --- a/Stepic/Sources/Modules/Quizzes/BaseQuiz/BaseQuizViewController.swift +++ b/Stepic/Sources/Modules/Quizzes/BaseQuiz/BaseQuizViewController.swift @@ -100,6 +100,8 @@ final class BaseQuizViewController: UIViewController, ControllerWithStepikPlaceh self.baseQuizView?.isPeerReviewAvailable = data.shouldPassPeerReview self.baseQuizView?.isNextStepAvailable = data.canNavigateToNextStep self.baseQuizView?.isRetryAvailable = data.canRetry + self.baseQuizView?.isDiscountPolicyAvailable = data.isDiscountingPolicyVisible + self.baseQuizView?.discountPolicyTitle = data.discountingPolicyTitle if let status = data.quizStatus { switch status { diff --git a/Stepic/Sources/Modules/Quizzes/BaseQuiz/BaseQuizViewModel.swift b/Stepic/Sources/Modules/Quizzes/BaseQuiz/BaseQuizViewModel.swift index 164b7f94bb..cee79ccdc3 100644 --- a/Stepic/Sources/Modules/Quizzes/BaseQuiz/BaseQuizViewModel.swift +++ b/Stepic/Sources/Modules/Quizzes/BaseQuiz/BaseQuizViewModel.swift @@ -16,4 +16,6 @@ struct BaseQuizViewModel { let codeDetails: CodeDetails? let canNavigateToNextStep: Bool let canRetry: Bool + let discountingPolicyTitle: String + let isDiscountingPolicyVisible: Bool } diff --git a/Stepic/Sources/Modules/Quizzes/NewChoiceQuiz/Views/NewChoiceQuizView.swift b/Stepic/Sources/Modules/Quizzes/NewChoiceQuiz/Views/NewChoiceQuizView.swift index 121f6ae2a7..91f5d4f00e 100644 --- a/Stepic/Sources/Modules/Quizzes/NewChoiceQuiz/Views/NewChoiceQuizView.swift +++ b/Stepic/Sources/Modules/Quizzes/NewChoiceQuiz/Views/NewChoiceQuizView.swift @@ -10,9 +10,6 @@ extension NewChoiceQuizView { let spacing: CGFloat = 16 let insets = LayoutInsets(left: 16, right: 16) - let separatorColor = UIColor(hex: 0xEAECF0) - let separatorHeight: CGFloat = 1 - let titleColor = UIColor.mainDark let titleFont = UIFont.systemFont(ofSize: 12, weight: .medium) @@ -37,12 +34,6 @@ final class NewChoiceQuizView: UIView { return loadingIndicatorView }() - private lazy var separatorView: UIView = { - let view = UIView() - view.backgroundColor = self.appearance.separatorColor - return view - }() - private lazy var titleLabel: UILabel = { let label = UILabel() label.textColor = self.appearance.titleColor @@ -52,7 +43,7 @@ final class NewChoiceQuizView: UIView { private lazy var stackView: UIStackView = { let stackView = UIStackView( - arrangedSubviews: [self.separatorView, self.titleLabelContainerView, self.choicesContainerView] + arrangedSubviews: [self.titleLabelContainerView, self.choicesContainerView] ) stackView.axis = .vertical stackView.spacing = self.appearance.spacing @@ -266,11 +257,6 @@ extension NewChoiceQuizView: ProgrammaticallyInitializableViewProtocol { } func makeConstraints() { - self.separatorView.translatesAutoresizingMaskIntoConstraints = false - self.separatorView.snp.makeConstraints { make in - make.height.equalTo(self.appearance.separatorHeight) - } - self.titleLabel.translatesAutoresizingMaskIntoConstraints = false self.titleLabel.snp.makeConstraints { make in make.top.bottom.equalToSuperview() diff --git a/Stepic/Sources/Modules/Quizzes/NewCodeQuiz/NewCodeQuizView.swift b/Stepic/Sources/Modules/Quizzes/NewCodeQuiz/NewCodeQuizView.swift index aba515b620..28e75eeabb 100644 --- a/Stepic/Sources/Modules/Quizzes/NewCodeQuiz/NewCodeQuizView.swift +++ b/Stepic/Sources/Modules/Quizzes/NewCodeQuiz/NewCodeQuizView.swift @@ -24,8 +24,6 @@ final class NewCodeQuizView: UIView { let appearance: Appearance weak var delegate: NewCodeQuizViewDelegate? - private lazy var topSeparatorView = SeparatorView() - // Only visible for sql quiz. private lazy var titleLabel: UILabel = { let label = UILabel() @@ -161,7 +159,6 @@ final class NewCodeQuizView: UIView { self.titleLabelContainerView.isHidden = viewModel.title?.isEmpty ?? true self.toolbarView.isHidden = !self.titleLabelContainerView.isHidden } else { - self.topSeparatorView.backgroundColor = .clear self.titleLabelContainerView.isHidden = true } } @@ -183,22 +180,14 @@ final class NewCodeQuizView: UIView { extension NewCodeQuizView: ProgrammaticallyInitializableViewProtocol { func addSubviews() { - self.topSeparatorContainerView.addSubview(self.topSeparatorView) self.titleLabelContainerView.addSubview(self.titleLabel) - self.addSubview(self.stackView) } func makeConstraints() { - self.topSeparatorView.translatesAutoresizingMaskIntoConstraints = false - self.topSeparatorView.snp.makeConstraints { make in - make.top.equalToSuperview().offset(self.appearance.insets.top) - make.bottom.leading.trailing.equalToSuperview() - } - self.titleLabel.translatesAutoresizingMaskIntoConstraints = false self.titleLabel.snp.makeConstraints { make in - make.top.equalToSuperview().offset(self.appearance.insets.top) + make.top.equalToSuperview() make.bottom.equalToSuperview().offset(-self.appearance.insets.bottom) make.leading.equalToSuperview().offset(self.appearance.insets.left) make.trailing.equalToSuperview().offset(-self.appearance.insets.right) diff --git a/Stepic/Sources/Modules/Quizzes/NewFreeAnswerQuiz/NewFreeAnswerQuizView.swift b/Stepic/Sources/Modules/Quizzes/NewFreeAnswerQuiz/NewFreeAnswerQuizView.swift index 3c1dbba2d3..67b103d1d1 100644 --- a/Stepic/Sources/Modules/Quizzes/NewFreeAnswerQuiz/NewFreeAnswerQuizView.swift +++ b/Stepic/Sources/Modules/Quizzes/NewFreeAnswerQuiz/NewFreeAnswerQuizView.swift @@ -7,9 +7,6 @@ protocol NewFreeAnswerQuizViewDelegate: class { extension NewFreeAnswerQuizView { struct Appearance { - let separatorColor = UIColor(hex: 0xEAECF0) - let separatorHeight: CGFloat = 1 - let spacing: CGFloat = 16 let insets = LayoutInsets(left: 16, right: 16) @@ -29,12 +26,6 @@ final class NewFreeAnswerQuizView: UIView { let appearance: Appearance weak var delegate: NewFreeAnswerQuizViewDelegate? - private lazy var separatorView: UIView = { - let view = UIView() - view.backgroundColor = self.appearance.separatorColor - return view - }() - private lazy var textView: TableInputTextView = { let textView = TableInputTextView() textView.textInsets = self.appearance.textFieldInsets @@ -61,9 +52,7 @@ final class NewFreeAnswerQuizView: UIView { }() private lazy var stackView: UIStackView = { - let stackView = UIStackView( - arrangedSubviews: [self.separatorView, self.textFieldContainerView] - ) + let stackView = UIStackView(arrangedSubviews: [self.textFieldContainerView]) stackView.spacing = self.appearance.spacing stackView.axis = .vertical return stackView @@ -114,11 +103,6 @@ extension NewFreeAnswerQuizView: ProgrammaticallyInitializableViewProtocol { } func makeConstraints() { - self.separatorView.translatesAutoresizingMaskIntoConstraints = false - self.separatorView.snp.makeConstraints { make in - make.height.equalTo(self.appearance.separatorHeight) - } - self.textView.translatesAutoresizingMaskIntoConstraints = false self.textView.snp.makeConstraints { make in make.top.bottom.equalToSuperview() diff --git a/Stepic/Sources/Modules/Quizzes/NewMatchingQuiz/Views/NewMatchingQuizView.swift b/Stepic/Sources/Modules/Quizzes/NewMatchingQuiz/Views/NewMatchingQuizView.swift index f1263c487c..193bf051e0 100644 --- a/Stepic/Sources/Modules/Quizzes/NewMatchingQuiz/Views/NewMatchingQuizView.swift +++ b/Stepic/Sources/Modules/Quizzes/NewMatchingQuiz/Views/NewMatchingQuizView.swift @@ -24,9 +24,6 @@ extension NewMatchingQuizView { let defaultSortingTitleInsets = LayoutInsets(top: 12, left: 16, bottom: 10, right: 64) let firstSortingTitleInsets = LayoutInsets(top: 0, left: 16, bottom: 10, right: 64) - let separatorColor = UIColor(hex: 0xEAECF0) - let separatorHeight: CGFloat = 1 - let titleColor = UIColor.mainDark let titleFont = UIFont.systemFont(ofSize: 12, weight: .medium) @@ -53,12 +50,6 @@ final class NewMatchingQuizView: UIView { return loadingIndicatorView }() - private lazy var separatorView: UIView = { - let view = UIView() - view.backgroundColor = self.appearance.separatorColor - return view - }() - private lazy var titleLabel: UILabel = { let label = UILabel() label.textColor = self.appearance.titleColor @@ -68,7 +59,7 @@ final class NewMatchingQuizView: UIView { private lazy var stackView: UIStackView = { let stackView = UIStackView( - arrangedSubviews: [self.separatorView, self.titleLabelContainerView, self.itemsContainerView] + arrangedSubviews: [self.titleLabelContainerView, self.itemsContainerView] ) stackView.axis = .vertical stackView.spacing = self.appearance.spacing @@ -243,11 +234,6 @@ extension NewMatchingQuizView: ProgrammaticallyInitializableViewProtocol { } func makeConstraints() { - self.separatorView.translatesAutoresizingMaskIntoConstraints = false - self.separatorView.snp.makeConstraints { make in - make.height.equalTo(self.appearance.separatorHeight) - } - self.titleLabel.translatesAutoresizingMaskIntoConstraints = false self.titleLabel.snp.makeConstraints { make in make.top.bottom.equalToSuperview() diff --git a/Stepic/Sources/Modules/Quizzes/NewSortingQuiz/Views/NewSortingQuizView.swift b/Stepic/Sources/Modules/Quizzes/NewSortingQuiz/Views/NewSortingQuizView.swift index 7fd921daf7..a587e6d125 100644 --- a/Stepic/Sources/Modules/Quizzes/NewSortingQuiz/Views/NewSortingQuizView.swift +++ b/Stepic/Sources/Modules/Quizzes/NewSortingQuiz/Views/NewSortingQuizView.swift @@ -18,9 +18,6 @@ extension NewSortingQuizView { let spacing: CGFloat = 16 let insets = LayoutInsets(left: 16, right: 16) - let separatorColor = UIColor(hex: 0xEAECF0) - let separatorHeight: CGFloat = 1 - let titleColor = UIColor.mainDark let titleFont = UIFont.systemFont(ofSize: 12, weight: .medium) @@ -47,12 +44,6 @@ final class NewSortingQuizView: UIView { return loadingIndicatorView }() - private lazy var separatorView: UIView = { - let view = UIView() - view.backgroundColor = self.appearance.separatorColor - return view - }() - private lazy var titleLabel: UILabel = { let label = UILabel() label.textColor = self.appearance.titleColor @@ -62,7 +53,7 @@ final class NewSortingQuizView: UIView { private lazy var stackView: UIStackView = { let stackView = UIStackView( - arrangedSubviews: [self.separatorView, self.titleLabelContainerView, self.optionsContainerView] + arrangedSubviews: [self.titleLabelContainerView, self.optionsContainerView] ) stackView.axis = .vertical stackView.spacing = self.appearance.spacing @@ -213,11 +204,6 @@ extension NewSortingQuizView: ProgrammaticallyInitializableViewProtocol { } func makeConstraints() { - self.separatorView.translatesAutoresizingMaskIntoConstraints = false - self.separatorView.snp.makeConstraints { make in - make.height.equalTo(self.appearance.separatorHeight) - } - self.titleLabel.translatesAutoresizingMaskIntoConstraints = false self.titleLabel.snp.makeConstraints { make in make.top.bottom.equalToSuperview() diff --git a/Stepic/Sources/Modules/Quizzes/NewStringQuiz/NewStringQuizView.swift b/Stepic/Sources/Modules/Quizzes/NewStringQuiz/NewStringQuizView.swift index f0ccde32a7..d831cad14c 100644 --- a/Stepic/Sources/Modules/Quizzes/NewStringQuiz/NewStringQuizView.swift +++ b/Stepic/Sources/Modules/Quizzes/NewStringQuiz/NewStringQuizView.swift @@ -7,9 +7,6 @@ protocol NewStringQuizViewDelegate: class { extension NewStringQuizView { struct Appearance { - let separatorColor = UIColor(hex: 0xEAECF0) - let separatorHeight: CGFloat = 1 - let spacing: CGFloat = 16 let insets = LayoutInsets(left: 16, right: 16) @@ -38,12 +35,6 @@ final class NewStringQuizView: UIView { let appearance: Appearance weak var delegate: NewStringQuizViewDelegate? - private lazy var separatorView: UIView = { - let view = UIView() - view.backgroundColor = self.appearance.separatorColor - return view - }() - private lazy var titleLabel: UILabel = { let label = UILabel() label.textColor = self.appearance.titleColor @@ -82,7 +73,7 @@ final class NewStringQuizView: UIView { private lazy var stackView: UIStackView = { let stackView = UIStackView( - arrangedSubviews: [self.separatorView, self.titleLabelContainerView, self.textFieldContainerView] + arrangedSubviews: [self.titleLabelContainerView, self.textFieldContainerView] ) stackView.spacing = self.appearance.spacing stackView.axis = .vertical @@ -175,11 +166,6 @@ extension NewStringQuizView: ProgrammaticallyInitializableViewProtocol { } func makeConstraints() { - self.separatorView.translatesAutoresizingMaskIntoConstraints = false - self.separatorView.snp.makeConstraints { make in - make.height.equalTo(self.appearance.separatorHeight) - } - self.titleLabel.translatesAutoresizingMaskIntoConstraints = false self.titleLabel.snp.makeConstraints { make in make.top.bottom.equalToSuperview() diff --git a/Stepic/en.lproj/Localizable.strings b/Stepic/en.lproj/Localizable.strings index 65fefaa9e8..e7336284d4 100644 --- a/Stepic/en.lproj/Localizable.strings +++ b/Stepic/en.lproj/Localizable.strings @@ -758,6 +758,11 @@ WrongFeedbackTitleLastTry = "Incorrect."; EvaluationFeedbackTitle = "Evaluation..."; PeerReviewFeedbackTitle = "This is a task with peer review. Tap to open in web to get points."; NextStepNavigationTitle = "Next"; +DiscountPolicyInverseTitle = "After every wrong submission your maximum points will be reduced"; +DiscountPolicyNoWayTitle = "You will not get points for the next attempts"; +DiscountPolicyFirstNTitle1 = "You have %@ attempt, for which you will get points"; +DiscountPolicyFirstNTitle234 = "You have %@ attempts, for which you will get points"; +DiscountPolicyFirstNTitle567890 = "You have %@ attempts, for which you will get points"; StringQuizTitle = "Write an answer in form of a text (string)"; NumberQuizTitle = "Enter a number"; diff --git a/Stepic/ru.lproj/Localizable.strings b/Stepic/ru.lproj/Localizable.strings index f5562b4e42..f1e69535b0 100644 --- a/Stepic/ru.lproj/Localizable.strings +++ b/Stepic/ru.lproj/Localizable.strings @@ -759,6 +759,11 @@ WrongFeedbackTitleLastTry = "Неверно."; EvaluationFeedbackTitle = "Проверка..."; PeerReviewFeedbackTitle = "Это задание с рецензией. Нажмите, чтобы закончить задание в веб-версии и получить баллы."; NextStepNavigationTitle = "Дальше"; +DiscountPolicyInverseTitle = "После каждого неправильного решения баллы, которые можно получить за задание, будут уменьшены"; +DiscountPolicyNoWayTitle = "За Ваши следующие попытки не будут начислены баллы"; +DiscountPolicyFirstNTitle1 = "У Вас осталась %@ попытка, за которую Вы сможете получить баллы"; +DiscountPolicyFirstNTitle234 = "У Вас осталось %@ попытки, за которые Вы сможете получить баллы"; +DiscountPolicyFirstNTitle567890 = "У Вас осталось %@ попыток, за которые Вы сможете получить баллы"; StringQuizTitle = "Напишите текст (строку)"; NumberQuizTitle = "Введите численный ответ"; From b9249c05a63b0519305bc8da12377537b8c418ca Mon Sep 17 00:00:00 2001 From: Ivan Magda Date: Tue, 10 Dec 2019 10:21:41 +0300 Subject: [PATCH 6/8] Set version to 1.105 & bump build --- Stepic.xcodeproj/project.pbxproj | 4 ++-- Stepic/Info.plist | 4 ++-- StepicTests/Info.plist | 4 ++-- StickerPackExtension/Info.plist | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Stepic.xcodeproj/project.pbxproj b/Stepic.xcodeproj/project.pbxproj index 686dfdb62c..078eb512ac 100644 --- a/Stepic.xcodeproj/project.pbxproj +++ b/Stepic.xcodeproj/project.pbxproj @@ -7518,7 +7518,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 168; + CURRENT_PROJECT_VERSION = 169; DEVELOPMENT_TEAM = UJ4KC2QN7B; ENABLE_BITCODE = YES; INFOPLIST_FILE = Stepic/Info.plist; @@ -7548,7 +7548,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 168; + CURRENT_PROJECT_VERSION = 169; DEVELOPMENT_TEAM = UJ4KC2QN7B; ENABLE_BITCODE = YES; INFOPLIST_FILE = Stepic/Info.plist; diff --git a/Stepic/Info.plist b/Stepic/Info.plist index bc3c9e5ca2..be14711efb 100644 --- a/Stepic/Info.plist +++ b/Stepic/Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.104 + 1.105 CFBundleSignature ???? CFBundleURLTypes @@ -56,7 +56,7 @@ CFBundleVersion - 168 + 169 Fabric APIKey diff --git a/StepicTests/Info.plist b/StepicTests/Info.plist index 02cd760090..a01401cea8 100644 --- a/StepicTests/Info.plist +++ b/StepicTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.104 + 1.105 CFBundleSignature ???? CFBundleVersion - 168 + 169 diff --git a/StickerPackExtension/Info.plist b/StickerPackExtension/Info.plist index b96d17f973..e513c752f2 100644 --- a/StickerPackExtension/Info.plist +++ b/StickerPackExtension/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType XPC! CFBundleShortVersionString - 1.104 + 1.105 CFBundleVersion - 168 + 169 NSExtension NSExtensionPointIdentifier From 031bc1d8418b00702b271c33c0f11c15b1b0a6dc Mon Sep 17 00:00:00 2001 From: Ivan Magda Date: Wed, 11 Dec 2019 01:27:41 +0300 Subject: [PATCH 7/8] Take into account soft and hard deadlines on discounting policy --- .../Quizzes/BaseQuiz/BaseQuizPresenter.swift | 77 ++++++++++++------- Stepic/Unit.swift | 2 +- Stepic/en.lproj/Localizable.strings | 1 + Stepic/ru.lproj/Localizable.strings | 1 + 4 files changed, 52 insertions(+), 29 deletions(-) diff --git a/Stepic/Sources/Modules/Quizzes/BaseQuiz/BaseQuizPresenter.swift b/Stepic/Sources/Modules/Quizzes/BaseQuiz/BaseQuizPresenter.swift index b6c37c6b91..6d5d40e08f 100644 --- a/Stepic/Sources/Modules/Quizzes/BaseQuiz/BaseQuizPresenter.swift +++ b/Stepic/Sources/Modules/Quizzes/BaseQuiz/BaseQuizPresenter.swift @@ -1,3 +1,4 @@ +import SwiftDate import UIKit protocol BaseQuizPresenterProtocol { @@ -114,33 +115,10 @@ final class BaseQuizPresenter: BaseQuizPresenterProtocol { }() let discountingPolicy = step.lesson?.unit?.section?.discountingPolicyType ?? .noDiscount - let isDiscountingPolicyVisible = discountingPolicy != .noDiscount && quizStatus != .correct - - let discountingPolicyText: String = { - switch discountingPolicy { - case .inverse: - return NSLocalizedString("DiscountPolicyInverseTitle", comment: "") - case .firstOne, .firstThree: - let remainingSubmissionCount = discountingPolicy.numberOfTries - submissionsCount - if remainingSubmissionCount > 0 { - return String( - format: StringHelper.pluralize( - number: remainingSubmissionCount, - forms: [ - NSLocalizedString("DiscountPolicyFirstNTitle1", comment: ""), - NSLocalizedString("DiscountPolicyFirstNTitle234", comment: ""), - NSLocalizedString("DiscountPolicyFirstNTitle567890", comment: "") - ] - ), - "\(remainingSubmissionCount)" - ) - } else { - return NSLocalizedString("DiscountPolicyNoWayTitle", comment: "") - } - default: - return "" - } - }() + let discountingPolicyTitle = self.makeDiscountingPolicyTitle(step: step, submissionsCount: submissionsCount) + + let isDiscountingPolicyNotInTerminatedState = discountingPolicy != .noDiscount && quizStatus != .correct + let isDiscountingPolicyVisible = isDiscountingPolicyNotInTerminatedState || discountingPolicyTitle != nil return BaseQuizViewModel( quizStatus: quizStatus, @@ -158,7 +136,7 @@ final class BaseQuizPresenter: BaseQuizPresenterProtocol { codeDetails: codeDetails, canNavigateToNextStep: canNavigateToNextStep, canRetry: canRetry, - discountingPolicyTitle: discountingPolicyText, + discountingPolicyTitle: discountingPolicyTitle ?? "", isDiscountingPolicyVisible: isDiscountingPolicyVisible ) } @@ -242,4 +220,47 @@ final class BaseQuizPresenter: BaseQuizPresenterProtocol { return url } + + private func makeDiscountingPolicyTitle(step: Step, submissionsCount: Int) -> String? { + guard let section = step.lesson?.unit?.section else { + return nil + } + + let currentDateInUTC = Date().convertTo(region: .UTC) + // If hardDeadline passed -> no points + // If softDeadline passed -> by default half of points + if let hardDeadline = section.hardDeadline { + if currentDateInUTC.date >= hardDeadline { + return NSLocalizedString("DiscountPolicyNoWayTitle", comment: "") + } + } else if let softDeadline = section.softDeadline { + if currentDateInUTC.date >= softDeadline { + return NSLocalizedString("DiscountPolicyHalfTitle", comment: "") + } + } + + switch section.discountingPolicyType { + case .inverse: + return NSLocalizedString("DiscountPolicyInverseTitle", comment: "") + case .firstOne, .firstThree: + let remainingSubmissionCount = section.discountingPolicyType.numberOfTries - submissionsCount + if remainingSubmissionCount > 0 { + return String( + format: StringHelper.pluralize( + number: remainingSubmissionCount, + forms: [ + NSLocalizedString("DiscountPolicyFirstNTitle1", comment: ""), + NSLocalizedString("DiscountPolicyFirstNTitle234", comment: ""), + NSLocalizedString("DiscountPolicyFirstNTitle567890", comment: "") + ] + ), + "\(remainingSubmissionCount)" + ) + } else { + return NSLocalizedString("DiscountPolicyNoWayTitle", comment: "") + } + default: + return nil + } + } } diff --git a/Stepic/Unit.swift b/Stepic/Unit.swift index e2d3c4b3a8..92c0b5641d 100644 --- a/Stepic/Unit.swift +++ b/Stepic/Unit.swift @@ -30,7 +30,7 @@ final class Unit: NSManagedObject, IDFetchable { beginDate = Parser.shared.dateFromTimedateJSON(json["begin_date"]) softDeadline = Parser.shared.dateFromTimedateJSON(json["soft_deadline"]) - hardDeadline = Parser.shared.dateFromTimedateJSON(json["soft_deadline"]) + hardDeadline = Parser.shared.dateFromTimedateJSON(json["hard_deadline"]) } func update(json: JSON) { diff --git a/Stepic/en.lproj/Localizable.strings b/Stepic/en.lproj/Localizable.strings index e7336284d4..efc4beb2c2 100644 --- a/Stepic/en.lproj/Localizable.strings +++ b/Stepic/en.lproj/Localizable.strings @@ -760,6 +760,7 @@ PeerReviewFeedbackTitle = "This is a task with peer review. Tap to open in web t NextStepNavigationTitle = "Next"; DiscountPolicyInverseTitle = "After every wrong submission your maximum points will be reduced"; DiscountPolicyNoWayTitle = "You will not get points for the next attempts"; +DiscountPolicyHalfTitle = "For next attempts, you will be able to get half of points"; DiscountPolicyFirstNTitle1 = "You have %@ attempt, for which you will get points"; DiscountPolicyFirstNTitle234 = "You have %@ attempts, for which you will get points"; DiscountPolicyFirstNTitle567890 = "You have %@ attempts, for which you will get points"; diff --git a/Stepic/ru.lproj/Localizable.strings b/Stepic/ru.lproj/Localizable.strings index f1e69535b0..78b6a17dbd 100644 --- a/Stepic/ru.lproj/Localizable.strings +++ b/Stepic/ru.lproj/Localizable.strings @@ -761,6 +761,7 @@ PeerReviewFeedbackTitle = "Это задание с рецензией. Нажм NextStepNavigationTitle = "Дальше"; DiscountPolicyInverseTitle = "После каждого неправильного решения баллы, которые можно получить за задание, будут уменьшены"; DiscountPolicyNoWayTitle = "За Ваши следующие попытки не будут начислены баллы"; +DiscountPolicyHalfTitle = "За Ваши следующие попытки Вы сможете получить половину баллов"; DiscountPolicyFirstNTitle1 = "У Вас осталась %@ попытка, за которую Вы сможете получить баллы"; DiscountPolicyFirstNTitle234 = "У Вас осталось %@ попытки, за которые Вы сможете получить баллы"; DiscountPolicyFirstNTitle567890 = "У Вас осталось %@ попыток, за которые Вы сможете получить баллы"; From 4b15fcf4b981662c6117e531e57c35da05e7bac7 Mon Sep 17 00:00:00 2001 From: Ivan Magda Date: Wed, 11 Dec 2019 01:28:00 +0300 Subject: [PATCH 8/8] Bump build --- Stepic.xcodeproj/project.pbxproj | 4 ++-- Stepic/Info.plist | 2 +- StepicTests/Info.plist | 2 +- StickerPackExtension/Info.plist | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Stepic.xcodeproj/project.pbxproj b/Stepic.xcodeproj/project.pbxproj index 078eb512ac..9b6e6795c1 100644 --- a/Stepic.xcodeproj/project.pbxproj +++ b/Stepic.xcodeproj/project.pbxproj @@ -7518,7 +7518,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 169; + CURRENT_PROJECT_VERSION = 170; DEVELOPMENT_TEAM = UJ4KC2QN7B; ENABLE_BITCODE = YES; INFOPLIST_FILE = Stepic/Info.plist; @@ -7548,7 +7548,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 169; + CURRENT_PROJECT_VERSION = 170; DEVELOPMENT_TEAM = UJ4KC2QN7B; ENABLE_BITCODE = YES; INFOPLIST_FILE = Stepic/Info.plist; diff --git a/Stepic/Info.plist b/Stepic/Info.plist index be14711efb..f1758bf6c3 100644 --- a/Stepic/Info.plist +++ b/Stepic/Info.plist @@ -56,7 +56,7 @@ CFBundleVersion - 169 + 170 Fabric APIKey diff --git a/StepicTests/Info.plist b/StepicTests/Info.plist index a01401cea8..91b8a36ac4 100644 --- a/StepicTests/Info.plist +++ b/StepicTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 169 + 170 diff --git a/StickerPackExtension/Info.plist b/StickerPackExtension/Info.plist index e513c752f2..3d3599d38c 100644 --- a/StickerPackExtension/Info.plist +++ b/StickerPackExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.105 CFBundleVersion - 169 + 170 NSExtension NSExtensionPointIdentifier