Skip to content

Commit

Permalink
Run code (#662)
Browse files Browse the repository at this point in the history
* Fix warning pending promise deallocated

* Update submit code button appearance

* Refactor rename NewCodeQuiz -> CodeQuiz

* Refactor rename NewCodeQuizFullscreen -> CodeQuizFullscreen

* Generate module

* Better scroll indicators in code editor

* Revert submit button changes

* ImageButton+Position

* Base layout

* Model & API

* Parse is_run_user_code_allowed

* Handle is_run_user_code_allowed on module creation

* Notify run code module about code updates

* Set default test input

* Run user code

* Action sheet with samples

* Hide run code tab if samples empty

* Polish up

* Add SQL support

* Add analytics

* Polish up

* Show tooltip

* Bump build

* Move getting userID to interactor

* Refactor rename lastSelectSampleActionSender -> samplesPopoverAnchorView

* Fix always provide actual code

* case sensitive compare
  • Loading branch information
ivan-magda authored Feb 24, 2020
1 parent 5385157 commit b6a5966
Show file tree
Hide file tree
Showing 72 changed files with 2,244 additions and 485 deletions.
258 changes: 166 additions & 92 deletions Stepic.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions Stepic/Analytics/Events/AmplitudeAnalyticsEvents.swift
Original file line number Diff line number Diff line change
Expand Up @@ -643,4 +643,15 @@ struct AmplitudeAnalyticsEvents {
)
}
}

// MARK: - Run Code -

struct RunCode {
static func launched(stepID: Step.IdType) -> AnalyticsEvent {
AnalyticsEvent(
name: "Run code launched",
parameters: ["step_id": stepID]
)
}
}
}
4 changes: 2 additions & 2 deletions Stepic/CreateRequestMaker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ final class CreateRequestMaker {
paramName: paramName,
creatingObject: creatingObject,
withManager: manager
).done { comment, _ in
seal.fulfill(comment)
).done { result, _ in
seal.fulfill(result)
}.catch { error in
seal.reject(error)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "console.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "console@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "console@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "keyboard-chevron.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"preserves-vector-representation" : true
}
}
Binary file not shown.
2 changes: 1 addition & 1 deletion Stepic/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>182</string>
<string>183</string>
<key>Fabric</key>
<dict>
<key>APIKey</key>
Expand Down
2 changes: 1 addition & 1 deletion Stepic/Model.xcdatamodeld/.xccurrentversion
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
<plist version="1.0">
<dict>
<key>_XCCurrentVersionName</key>
<string>Model_ discussion_threads.xcdatamodel</string>
<string>Model_ is_run_user_code_allowed.xcdatamodel</string>
</dict>
</plist>

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ final class QuizAssemblyFactory {
case .choice:
return NewChoiceQuizAssembly()
case .code:
return NewCodeQuizAssembly()
return CodeQuizAssembly()
case .sql:
return NewCodeQuizAssembly(language: .sql)
return CodeQuizAssembly(language: .sql)
case .sorting:
return NewSortingQuizAssembly()
case .matching:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import UIKit

final class NewCodeQuizAssembly: QuizAssembly {
final class CodeQuizAssembly: QuizAssembly {
var moduleInput: QuizInputProtocol?
weak var moduleOutput: QuizOutputProtocol?

Expand All @@ -11,7 +11,7 @@ final class NewCodeQuizAssembly: QuizAssembly {
}

func makeModule() -> UIViewController {
let provider = NewCodeQuizProvider(
let provider = CodeQuizProvider(
stepsPersistenceService: StepsPersistenceService(),
stepOptionsPersistenceService: StepOptionsPersistenceService(
stepsPersistenceService: StepsPersistenceService()
Expand All @@ -22,9 +22,9 @@ final class NewCodeQuizAssembly: QuizAssembly {
)
)

let presenter = NewCodeQuizPresenter()
let interactor = NewCodeQuizInteractor(presenter: presenter, provider: provider, language: self.language)
let viewController = NewCodeQuizViewController(interactor: interactor)
let presenter = CodeQuizPresenter()
let interactor = CodeQuizInteractor(presenter: presenter, provider: provider, language: self.language)
let viewController = CodeQuizViewController(interactor: interactor)

presenter.viewController = viewController
self.moduleInput = interactor
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
import Foundation

enum NewCodeQuiz {
enum CodeQuiz {
/// Show quiz state
enum ReplyLoad {
struct Request { }
struct Request {}

struct Response {
let code: String?
let language: CodeLanguage?
let languageName: String?
let codeDetails: CodeDetails
let status: QuizStatus?
// FIXME: Extract to protocol `TitlePresentable`
let isQuizTitleVisible: Bool
}

struct ViewModel {
let data: NewCodeQuizViewModel
let data: CodeQuizViewModel
}
}

Expand All @@ -42,7 +43,7 @@ enum NewCodeQuiz {

/// Display fullscreen mode
enum FullscreenPresentation {
struct Request { }
struct Request {}

struct Response {
let language: CodeLanguage
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import Foundation
import PromiseKit

protocol NewCodeQuizInteractorProtocol {
func doReplyLoad(request: NewCodeQuiz.ReplyLoad.Request)
func doReplyUpdate(request: NewCodeQuiz.ReplyConvert.Request)
func doReplySubmit(request: NewCodeQuiz.ReplySubmit.Request)
func doLanguageSelect(request: NewCodeQuiz.LanguageSelect.Request)
func doFullscreenAction(request: NewCodeQuiz.FullscreenPresentation.Request)
protocol CodeQuizInteractorProtocol {
func doReplyLoad(request: CodeQuiz.ReplyLoad.Request)
func doReplyUpdate(request: CodeQuiz.ReplyConvert.Request)
func doReplySubmit(request: CodeQuiz.ReplySubmit.Request)
func doLanguageSelect(request: CodeQuiz.LanguageSelect.Request)
func doFullscreenAction(request: CodeQuiz.FullscreenPresentation.Request)
}

final class NewCodeQuizInteractor: NewCodeQuizInteractorProtocol {
final class CodeQuizInteractor: CodeQuizInteractorProtocol {
weak var moduleOutput: QuizOutputProtocol?

private let presenter: NewCodeQuizPresenterProtocol
private let provider: NewCodeQuizProviderProtocol
private let presenter: CodeQuizPresenterProtocol
private let provider: CodeQuizProviderProtocol

private var codeDetails: CodeDetails?
private var currentStatus: QuizStatus?
Expand All @@ -30,25 +30,25 @@ final class NewCodeQuizInteractor: NewCodeQuizInteractorProtocol {
private var isQuizTitleVisible = true

init(
presenter: NewCodeQuizPresenterProtocol,
provider: NewCodeQuizProviderProtocol,
presenter: CodeQuizPresenterProtocol,
provider: CodeQuizProviderProtocol,
language: CodeLanguage?
) {
self.presenter = presenter
self.provider = provider
self.languageName = language?.rawValue
}

func doReplyLoad(request: NewCodeQuiz.ReplyLoad.Request) {
func doReplyLoad(request: CodeQuiz.ReplyLoad.Request) {
self.presentNewData()
}

func doReplyUpdate(request: NewCodeQuiz.ReplyConvert.Request) {
func doReplyUpdate(request: CodeQuiz.ReplyConvert.Request) {
self.currentCode = request.code
self.outputCurrentReply()
}

func doReplySubmit(request: NewCodeQuiz.ReplySubmit.Request) {
func doReplySubmit(request: CodeQuiz.ReplySubmit.Request) {
guard let reply = request.reply else {
return
}
Expand All @@ -57,7 +57,7 @@ final class NewCodeQuizInteractor: NewCodeQuizInteractorProtocol {
self.moduleOutput?.submit(reply: reply)
}

func doLanguageSelect(request: NewCodeQuiz.LanguageSelect.Request) {
func doLanguageSelect(request: CodeQuiz.LanguageSelect.Request) {
AnalyticsReporter.reportEvent(
AnalyticsEvents.Code.languageChosen,
parameters: [
Expand All @@ -77,7 +77,7 @@ final class NewCodeQuizInteractor: NewCodeQuizInteractorProtocol {
self.provider.updateAutoSuggestedCodeLanguage(language: language, stepID: codeDetails.stepID).cauterize()
}

func doFullscreenAction(request: NewCodeQuiz.FullscreenPresentation.Request) {
func doFullscreenAction(request: CodeQuiz.FullscreenPresentation.Request) {
guard let language = self.language,
let codeDetails = self.codeDetails else {
return
Expand Down Expand Up @@ -166,7 +166,7 @@ final class NewCodeQuizInteractor: NewCodeQuizInteractorProtocol {
}
}

extension NewCodeQuizInteractor: QuizInputProtocol {
extension CodeQuizInteractor: QuizInputProtocol {
func update(reply: Reply?) {
defer {
self.outputCurrentReply()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import UIKit

protocol NewCodeQuizPresenterProtocol {
func presentReply(response: NewCodeQuiz.ReplyLoad.Response)
func presentFullscreen(response: NewCodeQuiz.FullscreenPresentation.Response)
protocol CodeQuizPresenterProtocol {
func presentReply(response: CodeQuiz.ReplyLoad.Response)
func presentFullscreen(response: CodeQuiz.FullscreenPresentation.Response)
}

final class NewCodeQuizPresenter: NewCodeQuizPresenterProtocol {
weak var viewController: NewCodeQuizViewControllerProtocol?
final class CodeQuizPresenter: CodeQuizPresenterProtocol {
weak var viewController: CodeQuizViewControllerProtocol?

private let codeEditorThemeService: CodeEditorThemeServiceProtocol = CodeEditorThemeService()

func presentReply(response: NewCodeQuiz.ReplyLoad.Response) {
let state: NewCodeQuizViewModel.State = {
func presentReply(response: CodeQuiz.ReplyLoad.Response) {
let state: CodeQuizViewModel.State = {
if response.languageName != response.language?.rawValue {
return .unsupportedLanguage
}
Expand Down Expand Up @@ -63,7 +63,7 @@ final class NewCodeQuizPresenter: NewCodeQuizPresenterProtocol {
return nil
}()

let viewModel = NewCodeQuizViewModel(
let viewModel = CodeQuizViewModel(
title: title,
code: response.code,
codeTemplate: codeTemplate,
Expand All @@ -78,7 +78,7 @@ final class NewCodeQuizPresenter: NewCodeQuizPresenterProtocol {
self.viewController?.displayReply(viewModel: .init(data: viewModel))
}

func presentFullscreen(response: NewCodeQuiz.FullscreenPresentation.Response) {
func presentFullscreen(response: CodeQuiz.FullscreenPresentation.Response) {
self.viewController?.displayFullscreen(
viewModel: .init(
language: response.language,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Foundation
import PromiseKit

protocol NewCodeQuizProviderProtocol {
protocol CodeQuizProviderProtocol {
func fetchStepOptions(by stepID: Step.IdType) -> Promise<StepOptions?>

func fetchCodeTemplate(by stepID: Step.IdType, language: CodeLanguage) -> Promise<CodeTemplate?>
Expand All @@ -16,7 +16,7 @@ protocol NewCodeQuizProviderProtocol {
func updateAutoSuggestedCodeLanguage(language: CodeLanguage, stepID: Step.IdType) -> Promise<Void>
}

final class NewCodeQuizProvider: NewCodeQuizProviderProtocol {
final class CodeQuizProvider: CodeQuizProviderProtocol {
private let stepsPersistenceService: StepsPersistenceServiceProtocol
private let stepOptionsPersistenceService: StepOptionsPersistenceServiceProtocol
private let lessonsPersistenceService: LessonsPersistenceServiceProtocol
Expand Down Expand Up @@ -96,6 +96,8 @@ final class NewCodeQuizProvider: NewCodeQuizProviderProtocol {
}

CoreDataHelper.shared.save()

seal.fulfill(())
}.catch { _ in
seal.reject(Error.templateUpdateFailed)
}
Expand All @@ -111,7 +113,7 @@ final class NewCodeQuizProvider: NewCodeQuizProviderProtocol {
}
return self.lessonsPersistenceService.fetch(ids: [step.lessonID]).firstValue.then {
lesson -> Promise<String?> in
.value(lesson.title)
.value(lesson.title)
}
}
return .value(nil)
Expand Down
Loading

0 comments on commit b6a5966

Please sign in to comment.