Skip to content

Commit 4fac887

Browse files
authored
Code quiz & fullscreen (#493)
* Create NewCodeQuiz module * Remove unused * Initial for CodeTextView * Fix swiftlint messages * Remove unused infoBarButtonItem * Remove unused tooltipView property * Update request body logging * Fix typo * Sort BaseQuiz's files by name and type * Refactor rename group Child protocols -> ChildProtocols * Clean up * Fix typo * Add TODO * Use optional string interpolation operator * Sort quiz groups * Update comment * Refactor rename separatorWidth -> separatorHeight * Fix set translatesAutoresizingMaskIntoConstraints to false * Refactor rename separatorWidth -> separatorHeight * Conform NewCodeQuizAssembly to QuizAssembly * Conform CodeLanguage to CaseIterable * Sort quizzes group * Remove checks for os(tvOS) * Add description properties * Create NewCodeQuizViewModel * Init CodeReply with code and languageName * Init for present & update reply * Provide step options * Display code details * Rotate arrow image on click * Remove todo * Refactor rename * Language picker header * Language picker select language * Conform to NewCodeQuizViewDelegate * Refactor rename * Persist execution_time_limit and execution_memory_limit * Multy line code sample and monospace font * Update data flow * Add final state * Render code toolbar * Add default state * Show code text view * Select language on state noLanguage * Add newCodeQuizViewDidRequestFullscreen(_:) * Fix set language firstly * Handle language selection on toolbar * Enable or disable controls based on current status * tmp * Fix issues with ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES * Setup theme * Update code reply on text change * Update SeparatorView appearance * Use SeparatorView * Animate code details content alpha component * Use SeparatorView * Output current code reply on language select * Update appearance of code editor * Fix language chosen analytics param name * Auto select language if one * Do not clear current code and language on reply update * Disable code text view auto correction features * Refactor rename notSupportedLanguage -> unsupportedLanguage * Handle empty state for code language picker * Handle unsupported code language * Update Podfile.lock * Code completion and suggestions * Use partial from operator * Rearrange code * Fix toolbar collapse after language picked * tmp * Update visibility flow * Remove unused * Select code suggestion if text view editable * Make setupAccessoryView(isEditable:) private * Display language name inside of code editor * Provide step text content * Display fullscreen * Display tabs * Fix index out of bounds * tmp * Set backgroundColor * Create CodeEditorSettingsLegacyAssembly * Add todo's * Remove unused * Update todo with lesson title * Create StepOptionsPersistenceService * StepOptions to plain object * Initial for NewCodeQuizProvider * Create CodeDetails * Update child quiz input with code details * Use code details * Refactor rename * Refactor rename codeLanguage -> language * Update presenter * Create code editor theme service * Update fullscreen * Use plain objects * Set title for fullscreen * Update & submit reply * Refactor rename SomeAction to ContentLoad * Auto update code editor theme * Refactor rename * reset * Update default code editor theme * Delete after merge * Undo changes for NewLessonViewController * Move down * Set space between pages * Add Swift support
1 parent 878b0c7 commit 4fac887

File tree

99 files changed

+4610
-304
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

99 files changed

+4610
-304
lines changed

Podfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,4 +348,4 @@ SPEC CHECKSUMS:
348348

349349
PODFILE CHECKSUM: 0c6f3046cd7795142e613d85d7621ac20ce19346
350350

351-
COCOAPODS: 1.7.4
351+
COCOAPODS: 1.7.5

Stepic.xcodeproj/project.pbxproj

Lines changed: 287 additions & 45 deletions
Large diffs are not rendered by default.

Stepic/AlamofireRequestsLogger.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ final class AlamofireRequestsLogger {
5050

5151
if let httpBody = request.httpBody,
5252
let httpBodyString = String(data: httpBody, encoding: .utf8) {
53-
print(httpBodyString)
53+
print("Body: \(httpBodyString)")
5454
}
5555
}
5656
}

Stepic/CodeEditorPreferencesContainer.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ class CodeEditorPreferencesContainer {
1919
if let value = defaults.value(forKey: themeKey) as? String {
2020
return value
2121
} else {
22-
self.theme = "androidstudio"
23-
return "androidstudio"
22+
self.theme = "xcode"
23+
return "xcode"
2424
}
2525
}
2626

Stepic/CodeEditorSettingsPresenter.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ protocol CodeEditorSettingsView: class {
1717
func updatePreview(fontSize: Int)
1818
}
1919

20-
class CodeEditorSettingsPresenter {
20+
final class CodeEditorSettingsPresenter {
2121
weak var view: CodeEditorSettingsView?
2222

2323
var themeBlock: TransitionMenuBlock?
@@ -34,12 +34,16 @@ class CodeEditorSettingsPresenter {
3434
PreferencesContainer.codeEditor.theme = newTheme
3535
themeBlock?.subtitle = String(format: NSLocalizedString("CodeEditorCurrentTheme", comment: ""), newTheme)
3636
view?.updatePreview(theme: newTheme)
37+
38+
NotificationCenter.default.post(name: .codeEditorThemeDidChange, object: nil)
3739
}
3840

3941
func updateFontSize(with newSize: Int) {
4042
PreferencesContainer.codeEditor.fontSize = newSize
4143
fontSizeBlock?.subtitle = String(format: NSLocalizedString("CodeEditorCurrentFontSize", comment: ""), "\(newSize)")
4244
view?.updatePreview(fontSize: newSize)
45+
46+
NotificationCenter.default.post(name: .codeEditorThemeDidChange, object: nil)
4347
}
4448

4549
private func buildSettingsMenu() -> Menu {
@@ -87,3 +91,7 @@ class CodeEditorSettingsPresenter {
8791
return fontSizeBlock!
8892
}
8993
}
94+
95+
extension NSNotification.Name {
96+
static let codeEditorThemeDidChange = NSNotification.Name("codeEditorThemeDidChange")
97+
}

Stepic/CodeEditorSettingsViewController.swift

Lines changed: 112 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -5,48 +5,116 @@
55
// Created by Vladislav Kiryukhin on 11.04.18.
66
// Copyright © 2018 Alex Karpov. All rights reserved.
77
//
8-
import UIKit
8+
99
import ActionSheetPicker_3_0
10+
import UIKit
11+
12+
@available(*, deprecated, message: "Class to initialize code editor settings w/o storyboards logic")
13+
final class CodeEditorSettingsLegacyAssembly: Assembly {
14+
private let previewLanguage: CodeLanguage
15+
16+
init(previewLanguage: CodeLanguage = .python) {
17+
self.previewLanguage = previewLanguage
18+
}
19+
20+
func makeModule() -> UIViewController {
21+
guard let viewController = ControllerHelper.instantiateViewController(
22+
identifier: "CodeEditorSettings",
23+
storyboardName: "Profile"
24+
) as? CodeEditorSettingsViewController else {
25+
fatalError("Failed to initialize CodeEditorSettingsViewController")
26+
}
27+
28+
let presenter = CodeEditorSettingsPresenter(view: viewController)
29+
viewController.presenter = presenter
30+
viewController.previewLanguage = self.previewLanguage
1031

11-
class CodeEditorSettingsViewController: MenuViewController, CodeEditorSettingsView {
32+
return viewController
33+
}
34+
}
35+
36+
final class CodeEditorSettingsViewController: MenuViewController {
1237
var presenter: CodeEditorSettingsPresenter?
13-
var previewView: CodeEditorPreviewView!
1438
var previewLanguage = CodeLanguage.python
1539

40+
private lazy var previewView: CodeEditorPreviewView = {
41+
let previewView = CodeEditorPreviewView()
42+
previewView.delegate = self
43+
return previewView
44+
}()
45+
1646
override func viewDidLoad() {
1747
super.viewDidLoad()
1848

19-
edgesForExtendedLayout = []
20-
21-
previewView = CodeEditorPreviewView()
22-
previewView.delegate = self
23-
tableView.tableHeaderView = previewView
24-
layoutTableHeaderView()
49+
self.edgesForExtendedLayout = []
50+
self.tableView.tableHeaderView = self.previewView
2551

26-
presenter = CodeEditorSettingsPresenter(view: self)
52+
self.layoutTableHeaderView()
2753
}
2854

2955
override func viewDidAppear(_ animated: Bool) {
3056
super.viewDidAppear(animated)
31-
previewView.setupPreview(with: PreferencesContainer.codeEditor.theme, fontSize: PreferencesContainer.codeEditor.fontSize, language: previewLanguage)
57+
58+
// TODO: Add injection for theme.
59+
self.previewView.setupPreview(
60+
with: PreferencesContainer.codeEditor.theme,
61+
fontSize: PreferencesContainer.codeEditor.fontSize,
62+
language: self.previewLanguage
63+
)
64+
}
65+
66+
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
67+
super.viewWillTransition(to: size, with: coordinator)
68+
self.layoutTableHeaderView()
69+
}
70+
71+
private func layoutTableHeaderView() {
72+
guard let tableHeaderView = self.tableView.tableHeaderView else {
73+
return
74+
}
75+
76+
tableHeaderView.translatesAutoresizingMaskIntoConstraints = false
77+
78+
let headerWidth = tableHeaderView.bounds.size.width
79+
let widthConstraint = tableHeaderView.widthAnchor.constraint(equalToConstant: headerWidth)
80+
widthConstraint.isActive = true
81+
82+
tableHeaderView.setNeedsLayout()
83+
tableHeaderView.layoutIfNeeded()
84+
85+
var frame = tableHeaderView.frame
86+
frame.size.height = tableHeaderView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height
87+
tableHeaderView.frame = frame
88+
89+
tableHeaderView.removeConstraint(widthConstraint)
90+
tableHeaderView.translatesAutoresizingMaskIntoConstraints = true
91+
self.tableView.tableHeaderView = tableHeaderView
92+
}
93+
}
94+
95+
extension CodeEditorSettingsViewController: CodeEditorSettingsView {
96+
func setMenu(menu: Menu) {
97+
self.menu = menu
3298
}
3399

34100
func chooseEditorTheme(current: String) {
35-
guard let hl = previewView.highlightr,
36-
let currentThemeIndex = hl.availableThemes().index(of: current) else {
101+
guard let highlightr = self.previewView.highlightr,
102+
let currentThemeIndex = highlightr.availableThemes().index(of: current) else {
37103
return
38104
}
39105

40-
ActionSheetStringPicker.show(withTitle: NSLocalizedString("CodeEditorTheme", comment: ""),
41-
rows: hl.availableThemes(),
106+
ActionSheetStringPicker.show(
107+
withTitle: NSLocalizedString("CodeEditorTheme", comment: ""),
108+
rows: highlightr.availableThemes(),
42109
initialSelection: currentThemeIndex,
43-
doneBlock: { _, _, value in
110+
doneBlock: { [weak self] _, _, value in
44111
if let value = value as? String {
45-
self.presenter?.updateTheme(with: value)
112+
self?.presenter?.updateTheme(with: value)
46113
}
47114
},
48115
cancel: { _ in },
49-
origin: previewView)
116+
origin: self.previewView
117+
)
50118
}
51119

52120
func chooseFontSize(current: Int) {
@@ -56,72 +124,54 @@ class CodeEditorSettingsViewController: MenuViewController, CodeEditorSettingsVi
56124
return
57125
}
58126

59-
ActionSheetStringPicker.show(withTitle: NSLocalizedString("CodeEditorFontSize", comment: ""),
127+
ActionSheetStringPicker.show(
128+
withTitle: NSLocalizedString("CodeEditorFontSize", comment: ""),
60129
rows: availableSizes.map { "\($0)" },
61130
initialSelection: currentSizeIndex,
62-
doneBlock: { _, _, value in
131+
doneBlock: { [weak self] _, _, value in
63132
if let value = value as? String, let intValue = Int(value) {
64-
self.presenter?.updateFontSize(with: intValue)
133+
self?.presenter?.updateFontSize(with: intValue)
65134
}
66135
},
67136
cancel: { _ in },
68-
origin: previewView)
137+
origin: self.previewView
138+
)
69139
}
70140

71141
func updatePreview(theme: String) {
72-
previewView?.updateTheme(with: theme)
142+
self.previewView.updateTheme(with: theme)
73143
}
74144

75145
func updatePreview(fontSize: Int) {
76-
previewView?.updateFontSize(with: fontSize)
77-
}
78-
79-
func setMenu(menu: Menu) {
80-
self.menu = menu
81-
}
82-
83-
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
84-
super.viewWillTransition(to: size, with: coordinator)
85-
layoutTableHeaderView()
86-
}
87-
88-
func layoutTableHeaderView() {
89-
guard let headerView = tableView.tableHeaderView else {
90-
return
91-
}
92-
headerView.translatesAutoresizingMaskIntoConstraints = false
93-
94-
let headerWidth = headerView.bounds.size.width
95-
let widthConstraint = headerView.widthAnchor.constraint(equalToConstant: headerWidth)
96-
widthConstraint.isActive = true
97-
98-
headerView.setNeedsLayout()
99-
headerView.layoutIfNeeded()
100-
101-
var frame = headerView.frame
102-
frame.size.height = headerView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height
103-
headerView.frame = frame
104-
105-
headerView.removeConstraint(widthConstraint)
106-
headerView.translatesAutoresizingMaskIntoConstraints = true
107-
tableView.tableHeaderView = headerView
146+
self.previewView.updateFontSize(with: fontSize)
108147
}
109148
}
110149

111150
extension CodeEditorSettingsViewController: CodeEditorPreviewViewDelegate {
112151
func languageButtonDidClick() {
113-
let availableLanguages = Array(Set(CodeLanguage.allLanguages.map { $0.humanReadableName }))
152+
let availableLanguages = Array(Set(CodeLanguage.allCases.map { $0.humanReadableName }))
114153

115-
ActionSheetStringPicker.show(withTitle: NSLocalizedString("CodeEditorLanguage", comment: ""),
154+
guard let currentLanguageIndex = availableLanguages.index(of: self.previewLanguage.humanReadableName) else {
155+
return
156+
}
157+
158+
ActionSheetStringPicker.show(
159+
withTitle: NSLocalizedString("CodeEditorLanguage", comment: ""),
116160
rows: availableLanguages,
117-
initialSelection: availableLanguages.index(of: previewLanguage.humanReadableName)!,
118-
doneBlock: { _, _, value in
161+
initialSelection: currentLanguageIndex,
162+
doneBlock: { [weak self] _, _, value in
163+
guard let strongSelf = self else {
164+
return
165+
}
166+
119167
if let value = value as? String {
120-
self.previewLanguage = CodeLanguage.allLanguages.first(where: { $0.humanReadableName == value }) ?? self.previewLanguage
121-
self.previewView.updateLanguage(with: self.previewLanguage)
168+
let newPreviewLanguage = CodeLanguage.allCases.first(where: { $0.humanReadableName == value })
169+
strongSelf.previewLanguage = newPreviewLanguage ?? strongSelf.previewLanguage
170+
strongSelf.previewView.updateLanguage(with: strongSelf.previewLanguage)
122171
}
123172
},
124173
cancel: { _ in },
125-
origin: previewView.languageButton)
174+
origin: self.previewView.languageButton
175+
)
126176
}
127177
}

Stepic/CodeLanguagePickerViewController.swift

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,4 @@ class CodeLanguagePickerViewController: PickerViewController {
2828
picker.selectRow(start, inComponent: 0, animated: false)
2929
}
3030
}
31-
32-
override func didReceiveMemoryWarning() {
33-
super.didReceiveMemoryWarning()
34-
// Dispose of any resources that can be recreated.
35-
}
36-
37-
/*
38-
// MARK: - Navigation
39-
40-
// In a storyboard-based application, you will often want to do a little preparation before navigation
41-
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
42-
// Get the new view controller using segue.destinationViewController.
43-
// Pass the selected object to the new view controller.
44-
}
45-
*/
46-
4731
}

Stepic/CodeLanguages.swift

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import Foundation
1010

11-
enum CodeLanguage: String {
11+
enum CodeLanguage: String, CaseIterable {
1212
case python = "python3"
1313
case cpp11 = "c++11"
1414
case cpp = "c++"
@@ -36,11 +36,7 @@ enum CodeLanguage: String {
3636
case pascal = "pascalabc"
3737
case perl = "perl"
3838
case sql = "sql"
39-
40-
static let allLanguages: [CodeLanguage] = [.python, .cpp11, .cpp, .c, .haskell, .haskell7,
41-
.haskell8, .java, .java8, .java9, .java11, .octave, .asm32, .asm64,
42-
.shell, .rust, .r, .ruby, .clojure, .cs, .javascript,
43-
.scala, .kotlin, .go, .pascal, .perl, .sql]
39+
case swift = "swift"
4440

4541
var highlightr: String {
4642
switch self {
@@ -82,6 +78,8 @@ enum CodeLanguage: String {
8278
return "perl"
8379
case .sql:
8480
return "sql"
81+
case .swift:
82+
return "swift"
8583
}
8684
}
8785

@@ -125,6 +123,8 @@ enum CodeLanguage: String {
125123
return "Perl"
126124
case .sql:
127125
return "SQL"
126+
case .swift:
127+
return "Swift"
128128
}
129129
}
130130

@@ -172,6 +172,8 @@ enum CodeLanguage: String {
172172
return "# comment\nprint \"Hello World!\\n\";"
173173
case .sql:
174174
return "# comment\n\nSELECT 'Hello World';"
175+
case .swift:
176+
return "// comment\nprint(\"Hello World!\")"
175177
}
176178
}
177179
}

Stepic/CodeLimit.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,14 @@ import CoreData
1111
import SwiftyJSON
1212

1313
class CodeLimit: NSManagedObject {
14-
1514
var language: CodeLanguage? {
1615
return CodeLanguage(rawValue: languageString)
1716
}
1817

18+
override var description: String {
19+
return "CodeLimit(languageString: \(self.languageString), time: \(self.time), memory: \(self.memory)"
20+
}
21+
1922
convenience required init(language: String, json: JSON) {
2023
self.init()
2124
initialize(language: language, json: json)

Stepic/CodeLimitPlainObject.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import Foundation
2+
3+
struct CodeLimitPlainObject {
4+
let language: String?
5+
let memory: Double
6+
let time: TimeInterval
7+
}
8+
9+
extension CodeLimitPlainObject {
10+
init(codeLimit: CodeLimit) {
11+
self.language = codeLimit.languageString
12+
self.memory = codeLimit.memory
13+
self.time = codeLimit.time
14+
}
15+
}

0 commit comments

Comments
 (0)