Skip to content

Commit 5a33520

Browse files
authored
View solution (#632)
* Add solution module
1 parent ec5f33e commit 5a33520

40 files changed

+918
-49
lines changed

Stepic.xcodeproj/project.pbxproj

Lines changed: 40 additions & 0 deletions
Large diffs are not rendered by default.

Stepic/AttemptsAPI.swift

Lines changed: 71 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,40 @@ import SwiftyJSON
1414
final class AttemptsAPI: APIEndpoint {
1515
override var name: String { "attempts" }
1616

17-
func create(stepName: String, stepId: Int) -> Promise<Attempt> {
18-
let attempt = Attempt(step: stepId)
17+
/// Get attempts by ids.
18+
func retrieve(
19+
ids: [Attempt.IdType],
20+
stepName: String,
21+
page: Int = 1,
22+
headers: [String: String] = AuthInfo.shared.initialHTTPHeaders
23+
) -> Promise<([Attempt], Meta)> {
24+
let parameters: Parameters = [
25+
"ids": ids,
26+
"page": page
27+
]
28+
29+
return Promise { seal in
30+
self.manager.request(
31+
"\(StepicApplicationsInfo.apiURL)/\(self.name)",
32+
method: .get,
33+
parameters: parameters,
34+
encoding: URLEncoding.default,
35+
headers: headers
36+
).validate().responseSwiftyJSON { response in
37+
switch response.result {
38+
case .failure(let error):
39+
seal.reject(error)
40+
case .success(let json):
41+
let meta = Meta(json: json["meta"])
42+
let attempts = json["attempts"].arrayValue.map { Attempt(json: $0, stepName: stepName) }
43+
seal.fulfill((attempts, meta))
44+
}
45+
}
46+
}
47+
}
48+
49+
func create(stepName: String, stepID: Int) -> Promise<Attempt> {
50+
let attempt = Attempt(step: stepID)
1951
return Promise { seal in
2052
self.create.request(
2153
requestEndpoint: "attempts",
@@ -35,7 +67,7 @@ final class AttemptsAPI: APIEndpoint {
3567
Promise { seal in
3668
self.retrieve(
3769
stepName: stepName,
38-
stepId: stepID,
70+
stepID: stepID,
3971
success: { attempts, meta in
4072
seal.fulfill((attempts, meta))
4173
},
@@ -46,35 +78,49 @@ final class AttemptsAPI: APIEndpoint {
4678
}
4779
}
4880

49-
@discardableResult func retrieve(stepName: String, stepId: Int, headers: [String: String] = AuthInfo.shared.initialHTTPHeaders, success: @escaping ([Attempt], Meta) -> Void, error errorHandler: @escaping (String) -> Void) -> Request? {
81+
@discardableResult
82+
func retrieve(
83+
stepName: String,
84+
stepID: Int,
85+
headers: [String: String] = AuthInfo.shared.initialHTTPHeaders,
86+
success: @escaping ([Attempt], Meta) -> Void,
87+
error errorHandler: @escaping (String) -> Void
88+
) -> Request? {
5089
let headers = AuthInfo.shared.initialHTTPHeaders
5190

5291
var params: Parameters = [:]
53-
params["step"] = stepId
54-
if let userid = AuthInfo.shared.userId {
55-
params["user"] = userid as NSObject?
92+
params["step"] = stepID
93+
94+
if let userID = AuthInfo.shared.userId {
95+
params["user"] = userID as NSObject?
5696
} else {
5797
print("no user id!")
5898
}
5999

60-
return manager.request("\(StepicApplicationsInfo.apiURL)/attempts", method: .get, parameters: params, encoding: URLEncoding.default, headers: headers).responseSwiftyJSON({
61-
response in
62-
100+
return self.manager.request(
101+
"\(StepicApplicationsInfo.apiURL)/attempts",
102+
method: .get,
103+
parameters: params,
104+
encoding: URLEncoding.default,
105+
headers: headers
106+
).responseSwiftyJSON { response in
63107
var error = response.result.error
64108
var json: JSON = [:]
109+
65110
if response.result.value == nil {
66111
if error == nil {
67112
error = NSError()
68113
}
69114
} else {
70115
json = response.result.value!
71116
}
117+
72118
let response = response.response
73119

74-
if let e = error {
75-
let d = (e as NSError).localizedDescription
76-
print(d)
77-
errorHandler(d)
120+
if let error = error {
121+
let description = (error as NSError).localizedDescription
122+
print(description)
123+
errorHandler(description)
78124
return
79125
}
80126

@@ -87,18 +133,23 @@ final class AttemptsAPI: APIEndpoint {
87133
errorHandler("Response status code is wrong(\(String(describing: response?.statusCode)))")
88134
return
89135
}
90-
})
136+
}
91137
}
92138
}
93139

94140
extension AttemptsAPI {
95141
@available(*, deprecated, message: "Legacy method with callbacks")
96-
@discardableResult func create(stepName: String, stepId: Int, headers: [String: String] = AuthInfo.shared.initialHTTPHeaders, success: @escaping (Attempt) -> Void, error errorHandler: @escaping (String) -> Void) -> Request? {
97-
create(stepName: stepName, stepId: stepId).done {
98-
attempt in
142+
@discardableResult
143+
func create(
144+
stepName: String,
145+
stepID: Int,
146+
headers: [String: String] = AuthInfo.shared.initialHTTPHeaders,
147+
success: @escaping (Attempt) -> Void,
148+
error errorHandler: @escaping (String) -> Void
149+
) -> Request? {
150+
self.create(stepName: stepName, stepID: stepID).done { attempt in
99151
success(attempt)
100-
}.catch {
101-
error in
152+
}.catch { error in
102153
errorHandler(error.localizedDescription)
103154
}
104155
return nil

Stepic/QuizPresenter.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ final class QuizPresenter {
190190
return
191191
}
192192

193-
_ = s.attemptsAPI.retrieve(stepName: s.step.block.name, stepId: s.step.id, success: {
193+
_ = s.attemptsAPI.retrieve(stepName: s.step.block.name, stepID: s.step.id, success: {
194194
[weak self]
195195
attempts, _ in
196196
guard let s = self else { return }
@@ -250,7 +250,7 @@ final class QuizPresenter {
250250
performRequest({
251251
[weak self] in
252252
guard let s = self else { return }
253-
_ = s.attemptsAPI.create(stepName: s.step.block.name, stepId: s.step.id, success: {
253+
_ = s.attemptsAPI.create(stepName: s.step.block.name, stepID: s.step.id, success: {
254254
[weak self]
255255
attempt in
256256
guard let s = self else { return }

Stepic/Sources/Modules/Quizzes/BaseQuiz/ChildProtocols/QuizAssembly.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ final class QuizAssemblyFactory {
2121
case .code:
2222
return NewCodeQuizAssembly()
2323
case .sql:
24-
return NewCodeQuizAssembly(language: CodeLanguage.sql)
24+
return NewCodeQuizAssembly(language: .sql)
2525
case .sorting:
2626
return NewSortingQuizAssembly()
2727
case .matching:

Stepic/Sources/Modules/Quizzes/BaseQuiz/ChildProtocols/QuizInputProtocol.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ protocol QuizInputProtocol: AnyObject {
66
func update(dataset: Dataset?)
77
func update(feedback: SubmissionFeedback?)
88
func update(codeDetails: CodeDetails?)
9+
func update(quizTitleVisibility isVisible: Bool)
910
}
1011

1112
extension QuizInputProtocol {
@@ -14,4 +15,5 @@ extension QuizInputProtocol {
1415
func update(dataset: Dataset?) { }
1516
func update(feedback: SubmissionFeedback?) { }
1617
func update(codeDetails: CodeDetails?) { }
18+
func update(quizTitleVisibility isVisible: Bool) { }
1719
}

Stepic/Sources/Modules/Quizzes/NewChoiceQuiz/NewChoiceQuizDataFlow.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ enum NewChoiceQuiz {
77
let isMultipleChoice: Bool
88
let choices: [Choice]
99
let status: QuizStatus?
10+
let isQuizTitleVisible: Bool
1011
}
1112

1213
struct ViewModel {

Stepic/Sources/Modules/Quizzes/NewChoiceQuiz/NewChoiceQuizInteractor.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ final class NewChoiceQuizInteractor: NewChoiceQuizInteractorProtocol {
1818
private var currentChoicesFeedback: [String?]?
1919
// swiftlint:enable discouraged_optional_collection
2020

21+
private var isQuizTitleVisible = true
22+
2123
init(presenter: NewChoiceQuizPresenterProtocol) {
2224
self.presenter = presenter
2325
}
@@ -47,7 +49,8 @@ final class NewChoiceQuizInteractor: NewChoiceQuizInteractorProtocol {
4749
let (text, (isSelected, hint)) = result
4850
return NewChoiceQuiz.Choice(text: text, isSelected: isSelected, hint: hint)
4951
},
50-
status: self.currentStatus
52+
status: self.currentStatus,
53+
isQuizTitleVisible: self.isQuizTitleVisible
5154
)
5255
)
5356
}
@@ -96,4 +99,8 @@ extension NewChoiceQuizInteractor: QuizInputProtocol {
9699
self.currentChoicesFeedback = choices
97100
}
98101
}
102+
103+
func update(quizTitleVisibility isVisible: Bool) {
104+
self.isQuizTitleVisible = isVisible
105+
}
99106
}

Stepic/Sources/Modules/Quizzes/NewChoiceQuiz/NewChoiceQuizPresenter.swift

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,14 @@ final class NewChoiceQuizPresenter: NewChoiceQuizPresenterProtocol {
2323
}
2424
}()
2525

26-
let title = response.isMultipleChoice
27-
? NSLocalizedString("MultipleChoiceQuizTitle", comment: "")
28-
: NSLocalizedString("SingleChoiceQuizTitle", comment: "")
26+
let title: String? = {
27+
if response.isQuizTitleVisible {
28+
return response.isMultipleChoice
29+
? NSLocalizedString("MultipleChoiceQuizTitle", comment: "")
30+
: NSLocalizedString("SingleChoiceQuizTitle", comment: "")
31+
}
32+
return nil
33+
}()
2934

3035
let viewModel = NewChoiceQuizViewModel(
3136
title: title,

Stepic/Sources/Modules/Quizzes/NewChoiceQuiz/NewChoiceQuizViewModel.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import Foundation
22

33
struct NewChoiceQuizViewModel {
4-
let title: String
4+
let title: String?
55
let choices: [NewChoiceQuiz.Choice]
66
let finalState: State?
77
let isMultipleChoice: Bool

Stepic/Sources/Modules/Quizzes/NewCodeQuiz/NewCodeQuizDataFlow.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ enum NewCodeQuiz {
1111
let languageName: String?
1212
let codeDetails: CodeDetails
1313
let status: QuizStatus?
14+
let isQuizTitleVisible: Bool
1415
}
1516

1617
struct ViewModel {

0 commit comments

Comments
 (0)