Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New course info screen #423

Merged
merged 45 commits into from
Jan 29, 2019
Merged
Changes from 1 commit
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
585d7a0
Course info: info tab UI (#406)
ivan-magda Nov 29, 2018
510c826
Course info: container UI & header (#404)
kvld Nov 30, 2018
2a646b3
Course info: modules UI (#415)
kvld Nov 30, 2018
629bd23
Course info: info tab logic (#411)
ivan-magda Dec 6, 2018
adb4dc9
Course info: container logic (#426) & syllabus (#438)
kvld Dec 28, 2018
b93974d
Sections deadlines
kvld Dec 28, 2018
c7e1cb4
Layout fixes
kvld Jan 9, 2019
1a3d332
Completion & failure events
kvld Jan 9, 2019
a5eb3ce
Add enrolled state
kvld Jan 10, 2019
bf8f70b
Fix deep link & last step routers
kvld Jan 10, 2019
5718f42
Next & previous units service (#422)
kvld Jan 10, 2019
c5fa25f
Present controller with lesson
kvld Jan 10, 2019
3066f30
Fixes for SDK 11
kvld Jan 10, 2019
1b99ddb
Set build for current branch
kvld Jan 10, 2019
0670afa
Fix navigation bar issues
kvld Jan 11, 2019
488ad67
Personal deadlines
kvld Jan 13, 2019
d2732fd
Fix after rename
kvld Jan 13, 2019
30aecc8
Exam in syllabus
kvld Jan 13, 2019
10e7c6c
"More actions" alert & course sharing
kvld Jan 13, 2019
9207d0e
Main action & drop course
kvld Jan 14, 2019
59a0890
Merge branch 'dev' into feature/course-info
kvld Jan 14, 2019
374aae4
Set version to 1.75 & increment build
kvld Jan 14, 2019
4212360
Add tap proxy view for download buttons
kvld Jan 14, 2019
5e9a8a3
Fix deadlines view
kvld Jan 14, 2019
1a5c3f2
Next / previous lesson
kvld Jan 14, 2019
434694a
Hide syllabus tab for adaptive courses
kvld Jan 21, 2019
ef3cc04
Personal deadlines tooltip
kvld Jan 21, 2019
8d87119
Make enabled-disabled visual state for cells
kvld Jan 21, 2019
9f87e16
Remove "Downloads" from Settings
kvld Jan 21, 2019
df750c3
"Download all" logic
kvld Jan 21, 2019
be3b0f5
Fix new discussion layout (12 sdk)
kvld Jan 23, 2019
e526064
Fix video quality (12 sdk)
kvld Jan 23, 2019
0ecd7ad
Fix certificates layout (12 sdk)
kvld Jan 23, 2019
cbdd146
Remove action button tab
kvld Jan 23, 2019
a44aec8
Fix semaphore dispose crash
kvld Jan 23, 2019
1f2fddf
Update button state after remove
kvld Jan 23, 2019
8edefbe
Set version to 1.76 & increment build
kvld Jan 24, 2019
4246a2e
Fixed downloads
kvld Jan 28, 2019
f5f4386
Force populate sections
kvld Jan 28, 2019
dfad0c7
Fix empty units download state error
kvld Jan 28, 2019
7f5933a
Analytics & small fixes
kvld Jan 28, 2019
e926899
Remove unused code
kvld Jan 28, 2019
3b0cbe6
Fix iPad & landscape
kvld Jan 28, 2019
3f1a307
Bump build
kvld Jan 28, 2019
48c8fad
Fixes
kvld Jan 28, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Exam in syllabus
kvld committed Jan 13, 2019
commit 30aecc86335d5f9838ef69e4b0219592bc654af3
11 changes: 11 additions & 0 deletions Stepic/Modules/CourseInfo/CourseInfoDataFlow.swift
Original file line number Diff line number Diff line change
@@ -79,6 +79,17 @@ enum CourseInfo {
}
}

/// Present exam in web
enum ShowExamLesson {
struct Response {
let urlPath: String
}

struct ViewModel {
let urlPath: String
}
}

// MARK: States

enum ViewControllerState {
29 changes: 29 additions & 0 deletions Stepic/Modules/CourseInfo/CourseInfoInteractor.swift
Original file line number Diff line number Diff line change
@@ -30,6 +30,25 @@ final class CourseInfoInteractor: CourseInfoInteractorProtocol {
}
}

private var courseWebURLPath: String? {
guard let course = self.currentCourse else {
return nil
}

if let slug = course.slug {
return "\(StepicApplicationsInfo.stepicURL)/course/\(slug)"
} else {
return "\(StepicApplicationsInfo.stepicURL)/\(course.id)"
}
}

private var courseWebSyllabusURLPath: String? {
guard let path = self.courseWebURLPath else {
return nil
}
return "\(path)/syllabus"
}

private var submodules: [CourseInfoSubmoduleProtocol] = []

private var isOnline = false
@@ -158,4 +177,14 @@ extension CourseInfoInteractor: CourseInfoTabSyllabusOutputProtocol {
response: .init(action: .edit, course: course)
)
}

func presentExamLesson() {
guard let urlPath = self.courseWebSyllabusURLPath else {
return
}

self.presenter.presentExamLesson(
response: .init(urlPath: urlPath)
)
}
}
11 changes: 10 additions & 1 deletion Stepic/Modules/CourseInfo/CourseInfoPresenter.swift
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@ protocol CourseInfoPresenterProtocol {
func presentCourse(response: CourseInfo.ShowCourse.Response)
func presentLesson(response: CourseInfo.ShowLesson.Response)
func presentPersonalDeadlinesSettings(response: CourseInfo.PersonalDeadlinesSettings.Response)
func presentExamLesson(response: CourseInfo.ShowExamLesson.Response)
}

final class CourseInfoPresenter: CourseInfoPresenterProtocol {
@@ -54,8 +55,16 @@ final class CourseInfoPresenter: CourseInfoPresenterProtocol {

func presentPersonalDeadlinesSettings(response: CourseInfo.PersonalDeadlinesSettings.Response) {
let viewModel = CourseInfo.PersonalDeadlinesSettings.ViewModel(
action: response.action, course: response.course
action: response.action,
course: response.course
)
self.viewController?.displayPersonalDeadlinesSettings(viewModel: viewModel)
}

func presentExamLesson(response: CourseInfo.ShowExamLesson.Response) {
let viewModel = CourseInfo.ShowExamLesson.ViewModel(
urlPath: response.urlPath
)
self.viewController?.displayExamLesson(viewModel: viewModel)
}
}
35 changes: 35 additions & 0 deletions Stepic/Modules/CourseInfo/CourseInfoViewController.swift
Original file line number Diff line number Diff line change
@@ -23,6 +23,7 @@ protocol CourseInfoViewControllerProtocol: class {
func displayCourse(viewModel: CourseInfo.ShowCourse.ViewModel)
func displayLesson(viewModel: CourseInfo.ShowLesson.ViewModel)
func displayPersonalDeadlinesSettings(viewModel: CourseInfo.PersonalDeadlinesSettings.ViewModel)
func displayExamLesson(viewModel: CourseInfo.ShowExamLesson.ViewModel)
}

final class CourseInfoViewController: UIViewController {
@@ -241,6 +242,40 @@ extension CourseInfoViewController: PageboyViewControllerDataSource, PageboyView
}

extension CourseInfoViewController: CourseInfoViewControllerProtocol {
func displayExamLesson(viewModel: CourseInfo.ShowExamLesson.ViewModel) {
let alert = UIAlertController(
title: NSLocalizedString("ExamTitle", comment: ""),
message: NSLocalizedString("ShowExamInWeb", comment: ""),
preferredStyle: .alert
)
alert.addAction(
UIAlertAction(
title: NSLocalizedString("Open", comment: ""),
style: .default,
handler: { [weak self] _ in
guard let strongSelf = self else {
return
}
WebControllerManager.sharedManager.presentWebControllerWithURLString(
"\(viewModel.urlPath)?from_mobile_app=true",
inController: strongSelf,
withKey: "exam",
allowsSafari: true,
backButtonStyle: .close
)
}
)
)
alert.addAction(
UIAlertAction(
title: NSLocalizedString("Cancel", comment: ""),
style: .cancel,
handler: nil
)
)
self.present(module: alert)
}

func displayCourse(viewModel: CourseInfo.ShowCourse.ViewModel) {
switch viewModel.state {
case .result(let data):
Original file line number Diff line number Diff line change
@@ -206,6 +206,13 @@ final class CourseInfoTabSyllabusInteractor: CourseInfoTabSyllabusInteractorProt
return
}

// Check whether unit is in exam section
if let section = self.currentSections[self.getUniqueIdentifierBySectionID(unit.sectionId)],
section.isExam, section.isReachable {
self.moduleOutput?.presentExamLesson()
return
}

self.moduleOutput?.presentLesson(in: unit)
}

@@ -424,8 +431,14 @@ final class CourseInfoTabSyllabusInteractor: CourseInfoTabSyllabusInteractorProt
}

private func getDownloadingState(for unit: Unit) -> CourseInfoTabSyllabus.DownloadState {
// If section is unreachable or exam then all units are not available
guard let section = self.currentSections[self.getUniqueIdentifierBySectionID(unit.sectionId)],
!section.isExam, section.isReachable else {
return .notAvailable
}

guard let lesson = unit.lesson else {
// We should call this method only with completely load units
// We should call this method only with completely loaded units
// But return "not cached" in this case
return .available(isCached: false)
}
@@ -469,6 +482,11 @@ final class CourseInfoTabSyllabusInteractor: CourseInfoTabSyllabusInteractorProt
private func getDownloadingState(for section: Section) -> CourseInfoTabSyllabus.DownloadState {
let units = section.units

// Unreachable and exam not available
if section.isExam || !section.isReachable {
return .notAvailable
}

// If have unloaded units for lesson then show "not available" state
let hasUncachedUnits = units
.filter { section.unitsArray.contains($0.id) }
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@ import Foundation

protocol CourseInfoTabSyllabusOutputProtocol: class {
func presentLesson(in unit: Unit)
func presentExamLesson()
func presentPersonalDeadlinesCreation(for course: Course)
func presentPersonalDeadlinesSettings(for course: Course)
}
Original file line number Diff line number Diff line change
@@ -136,7 +136,8 @@ final class CourseInfoTabSyllabusPresenter: CourseInfoTabSyllabusPresenterProtoc
units: units,
deadlines: deadlines,
downloadState: downloadState,
isDisabled: !section.isReachable
isDisabled: !section.isReachable,
isExam: section.isExam
)

self.cachedSectionViewModels[section.id] = viewModel
Original file line number Diff line number Diff line change
@@ -25,6 +25,7 @@ struct CourseInfoTabSyllabusSectionViewModel: UniqueIdentifiable {

var downloadState: CourseInfoTabSyllabus.DownloadState
let isDisabled: Bool
let isExam: Bool

enum UnitViewModelWrapper {
case placeholder
Original file line number Diff line number Diff line change
@@ -19,9 +19,14 @@ extension CourseInfoTabSyllabusSectionView {
// Width for two-digit indexes
let indexLabelWidth: CGFloat = 16

let examTextColor = UIColor.mainDark
let examFont = UIFont.systemFont(ofSize: 14, weight: .light)

let textStackViewSpacing: CGFloat = 10
let textStackViewInsets = UIEdgeInsets(top: 19, left: 12, bottom: 0, right: 15)

let titleTextColor = UIColor.mainDark
let titleFont = UIFont.systemFont(ofSize: 14)
let titleLabelInsets = UIEdgeInsets(top: 19, left: 12, bottom: 0, right: 15)

let downloadButtonInsets = UIEdgeInsets(top: 18, left: 0, bottom: 0, right: 16)
let downloadButtonSize = CGSize(width: 22, height: 22)
@@ -60,6 +65,22 @@ final class CourseInfoTabSyllabusSectionView: UIView {
return view
}()

private lazy var textStackView: UIStackView = {
let stackView = UIStackView()
stackView.axis = .vertical
stackView.spacing = self.appearance.textStackViewSpacing
return stackView
}()

private lazy var examLabel: UILabel = {
let label = UILabel()
label.font = self.appearance.examFont
label.textColor = self.appearance.examTextColor
label.numberOfLines = 1
label.text = NSLocalizedString("ExamTitle", comment: "")
return label
}()

private lazy var progressIndicatorView: UIProgressView = {
let view = UIProgressView()
view.progressViewStyle = .bar
@@ -76,7 +97,7 @@ final class CourseInfoTabSyllabusSectionView: UIView {
let appearance = CourseInfoTabSyllabusSectionDeadlinesView.Appearance(
verticalHorizontalOffset: self.appearance.indexLabelInsets.left
+ self.appearance.indexLabelWidth
+ self.appearance.titleLabelInsets.left
+ self.appearance.textStackViewInsets.left
)
let view = CourseInfoTabSyllabusSectionDeadlinesView(appearance: appearance)
return view
@@ -102,6 +123,8 @@ final class CourseInfoTabSyllabusSectionView: UIView {
self.indexLabel.text = viewModel.index
self.progressIndicatorView.progress = viewModel.progress

self.examLabel.isHidden = !viewModel.isExam

self.updateDownloadState(newState: viewModel.downloadState)

if let deadlines = viewModel.deadlines {
@@ -111,7 +134,7 @@ final class CourseInfoTabSyllabusSectionView: UIView {
.greaterThanOrEqualTo(self.downloadButton.snp.bottom)
.offset(self.appearance.deadlinesInsets.top)
make.top
.greaterThanOrEqualTo(self.titleLabel.snp.bottom)
.greaterThanOrEqualTo(self.textStackView.snp.bottom)
.offset(self.appearance.deadlinesInsets.top)
}

@@ -126,9 +149,11 @@ final class CourseInfoTabSyllabusSectionView: UIView {
)
} else {
self.deadlinesView.isHidden = true
self.deadlinesView.snp.makeConstraints { make in
make.top.equalTo(self.downloadButton.snp.bottom)
make.top.equalTo(self.titleLabel.snp.bottom)
self.textStackView.snp.makeConstraints { make in
make.bottom
.equalToSuperview()
.offset(-self.appearance.deadlinesInsets.bottom)
.priority(.medium)
}
}
}
@@ -162,7 +187,11 @@ extension CourseInfoTabSyllabusSectionView: ProgrammaticallyInitializableViewPro

func addSubviews() {
self.addSubview(self.indexLabel)
self.addSubview(self.titleLabel)

self.textStackView.addArrangedSubview(self.titleLabel)
self.textStackView.addArrangedSubview(self.examLabel)
self.addSubview(self.textStackView)

self.addSubview(self.downloadButton)
self.addSubview(self.deadlinesView)

@@ -197,18 +226,19 @@ extension CourseInfoTabSyllabusSectionView: ProgrammaticallyInitializableViewPro
self.downloadButton.snp.makeConstraints { make in
make.size.equalTo(self.appearance.downloadButtonSize)
make.trailing.equalToSuperview().offset(-self.appearance.downloadButtonInsets.right)
make.centerY.equalTo(self.titleLabel.snp.centerY)
make.centerY.equalTo(self.textStackView.snp.centerY)
}

self.titleLabel.translatesAutoresizingMaskIntoConstraints = false
self.titleLabel.snp.makeConstraints { make in
make.top.equalToSuperview().offset(self.appearance.titleLabelInsets.top)
self.textStackView.translatesAutoresizingMaskIntoConstraints = false
self.textStackView.setContentCompressionResistancePriority(.required, for: .vertical)
self.textStackView.snp.makeConstraints { make in
make.top.equalToSuperview().offset(self.appearance.textStackViewInsets.top)
make.leading
.equalTo(self.indexLabel.snp.trailing)
.offset(self.appearance.titleLabelInsets.left)
.offset(self.appearance.textStackViewInsets.left)
make.trailing
.equalTo(self.downloadButton.snp.leading)
.offset(-self.appearance.titleLabelInsets.right)
.offset(-self.appearance.textStackViewInsets.right)
}

self.deadlinesView.translatesAutoresizingMaskIntoConstraints = false