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

Release 1.60 #301

Merged
merged 4 commits into from
Jun 4, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions DefaultsContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ import Foundation
class DefaultsContainer {
private init() {}
static let launch = LaunchDefaultsContainer()
static let personalDeadlines = PersonalDeadlinesDefaultsContainer()
}
1 change: 1 addition & 0 deletions Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ def all_pods
pod 'Charts', '3.0.4'
pod 'EasyTipView', :git => 'https://github.com/igorkislyuk/EasyTipView.git'
pod 'ActionSheetPicker-3.0'
pod 'SkeletonView'
end

def testing_pods
Expand Down
968 changes: 547 additions & 421 deletions Stepic.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

25 changes: 25 additions & 0 deletions Stepic/AnalyticsEvents.swift
Original file line number Diff line number Diff line change
Expand Up @@ -275,4 +275,29 @@ struct AnalyticsEvents {
static let hard = "adaptive_reaction_hard"
}
}

struct PersonalDeadlines {
struct Widget {
static let shown = "personal_deadlines_widget_shown"
static let clicked = "personal_deadlines_widget_clicked"
static let hidden = "personal_deadlines_widget_hidden"
}

struct Mode {
static let opened = "personal_deadline_mode_opened"
static let chosen = "personal_deadline_mode_chosen"
static let closed = "personal_deadline_mode_closed"
}

struct EditSchedule {
static let changePressed = "personal_deadline_change_pressed"
struct Time {
static let opened = "personal_deadline_time_opened"
static let closed = "personal_deadline_time_closed"
static let saved = "personal_deadline_time_saved"
}
}
static let deleted = "personal_deadline_deleted"
static let notSupportedNotification = "personal_deadline_not_supported_notification_scheduled"
}
}
96 changes: 96 additions & 0 deletions Stepic/ContentExpandableMenuBlockTableViewCell.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
//
// ContentExpandableMenuBlockTableViewCell.swift
// Stepic
//
// Created by Vladislav Kiryukhin on 27.05.2018.
// Copyright © 2018 Alex Karpov. All rights reserved.
//

import UIKit

class ContentExpandableMenuBlockTableViewCell: MenuBlockTableViewCell {
@IBOutlet weak var titleLabel: StepikLabel!
@IBOutlet weak var container: UIView!
@IBOutlet weak var arrowButton: UIButton!

var bottomTitleConstraint: NSLayoutConstraint?

var block: ContentExpandableMenuBlock?
var updateTableHeightBlock: (() -> Void)?

override func awakeFromNib() {
super.awakeFromNib()
}

override func initWithBlock(block: MenuBlock) {
super.initWithBlock(block: block)
titleLabel.text = block.title

if let block = block as? ContentExpandableMenuBlock {
self.block = block
if let contentView = block.contentView {
container.addSubview(contentView)
contentView.alignTop("0", leading: "0", bottom: "0", trailing: "0", toView: container)
layoutIfNeeded()
}

if block.isExpanded {
expand(shouldAnimate: false)
} else {
shrink(shouldAnimate: false)
}
}
}

@IBAction func arrowButtonPressed(_ sender: UIButton) {
expandPressed()
}

func expandPressed() {
guard let block = block else {
return
}

block.onExpanded?(!block.isExpanded)
if block.isExpanded {
expand()
} else {
shrink()
}
layoutIfNeeded()
updateTableHeightBlock?()
}

func expand(shouldAnimate: Bool = true) {
bottomTitleConstraint?.isActive = false
container.isHidden = false

let animationBlock: () -> Void = { [weak self] in
self?.arrowButton.transform = CGAffineTransform.identity
}
if shouldAnimate {
UIView.animate(withDuration: 0.3, animations: animationBlock)
} else {
animationBlock()
}
}

func shrink(shouldAnimate: Bool = true) {
container.isHidden = true
if bottomTitleConstraint == nil {
bottomTitleConstraint = titleLabel.alignBottomEdge(withView: self.contentView, predicate: "-26")
} else {
bottomTitleConstraint?.isActive = true
}

let animationBlock: () -> Void = { [weak self] in
self?.arrowButton.transform = CGAffineTransform(rotationAngle: CGFloat.pi)
}
if shouldAnimate {
UIView.animate(withDuration: 0.3, animations: animationBlock)
} else {
animationBlock()
}
}

}
Original file line number Diff line number Diff line change
@@ -1,58 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14109" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="84" id="KGk-i7-Jjw" customClass="TitleContentExpandableMenuBlockTableViewCell" customModule="Adaptive_1838" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="320" height="84"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="282" id="eqn-wM-KyJ" customClass="ContentExpandableMenuBlockTableViewCell" customModule="Stepic" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="320" height="282"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
<rect key="frame" x="0.0" y="0.0" width="320" height="83.5"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="eqn-wM-KyJ" id="JFM-KY-cWV">
<rect key="frame" x="0.0" y="0.0" width="320" height="281.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Title + content" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="eIR-zG-AdZ" customClass="StepikLabel" customModule="Adaptive_1838" customModuleProvider="target">
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Title + content" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ceg-ul-UxG" customClass="StepikLabel" customModule="Stepic" customModuleProvider="target">
<rect key="frame" x="24" y="24" width="240" height="20.5"/>
<fontDescription key="fontDescription" type="system" weight="light" pointSize="17"/>
<color key="textColor" red="0.32549019610000002" green="0.32549019610000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ktK-VW-1Ci">
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="0wM-0x-akp">
<rect key="frame" x="272" y="18" width="32" height="32"/>
<constraints>
<constraint firstAttribute="height" constant="32" id="bUi-Xq-cmf"/>
<constraint firstAttribute="width" constant="32" id="ioE-MN-4ll"/>
<constraint firstAttribute="height" constant="32" id="ckq-mH-3BN"/>
<constraint firstAttribute="width" constant="32" id="uu1-kF-KXg"/>
</constraints>
<inset key="contentEdgeInsets" minX="8" minY="8" maxX="8" maxY="8"/>
<state key="normal" image="menu_arrow_bottom"/>
<state key="normal" image="menu_arrow_top"/>
<connections>
<action selector="arrowButtonPressed:" destination="KGk-i7-Jjw" eventType="touchUpInside" id="OnQ-KP-VEs"/>
<action selector="arrowButtonPressed:" destination="eqn-wM-KyJ" eventType="touchUpInside" id="d7H-CE-Ae1"/>
</connections>
</button>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="A2e-ME-rNQ">
<rect key="frame" x="0.0" y="52.5" width="320" height="213"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="213" placeholder="YES" id="Alv-65-clh"/>
</constraints>
</view>
</subviews>
<constraints>
<constraint firstItem="ktK-VW-1Ci" firstAttribute="leading" secondItem="eIR-zG-AdZ" secondAttribute="trailing" constant="8" id="1Su-qe-4V1"/>
<constraint firstAttribute="trailing" secondItem="ktK-VW-1Ci" secondAttribute="trailing" constant="16" id="SlO-Q5-Fxu"/>
<constraint firstItem="eIR-zG-AdZ" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="topMargin" constant="13" id="V27-wL-E9l"/>
<constraint firstAttribute="leading" secondItem="eIR-zG-AdZ" secondAttribute="leading" constant="-24" id="vrL-qL-f1a"/>
<constraint firstItem="ktK-VW-1Ci" firstAttribute="centerY" secondItem="eIR-zG-AdZ" secondAttribute="centerY" id="yyz-rf-CCP"/>
<constraint firstItem="0wM-0x-akp" firstAttribute="centerY" secondItem="ceg-ul-UxG" secondAttribute="centerY" id="PoI-QM-liM"/>
<constraint firstItem="A2e-ME-rNQ" firstAttribute="top" secondItem="ceg-ul-UxG" secondAttribute="bottom" constant="8" id="QzF-lP-Kpm"/>
<constraint firstAttribute="trailing" secondItem="0wM-0x-akp" secondAttribute="trailing" constant="16" id="WOO-d2-mkB"/>
<constraint firstItem="0wM-0x-akp" firstAttribute="leading" secondItem="ceg-ul-UxG" secondAttribute="trailing" constant="8" id="XiL-lR-5ky"/>
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="A2e-ME-rNQ" secondAttribute="bottom" constant="16" id="j8O-9o-1gq"/>
<constraint firstAttribute="trailing" secondItem="A2e-ME-rNQ" secondAttribute="trailing" id="kXq-op-Ox3"/>
<constraint firstAttribute="leading" secondItem="ceg-ul-UxG" secondAttribute="leading" constant="-24" id="quc-cR-Kdq"/>
<constraint firstItem="A2e-ME-rNQ" firstAttribute="leading" secondItem="JFM-KY-cWV" secondAttribute="leading" id="yTj-Jp-x0O"/>
<constraint firstItem="ceg-ul-UxG" firstAttribute="top" secondItem="JFM-KY-cWV" secondAttribute="topMargin" constant="13" id="z4H-Vi-VPQ"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="arrowButton" destination="ktK-VW-1Ci" id="0K7-oH-LSJ"/>
<outlet property="titleLabel" destination="eIR-zG-AdZ" id="scd-r2-4RJ"/>
<outlet property="arrowButton" destination="0wM-0x-akp" id="iMx-0w-qwW"/>
<outlet property="container" destination="A2e-ME-rNQ" id="Qwt-NQ-jfX"/>
<outlet property="titleLabel" destination="ceg-ul-UxG" id="Bye-aV-fd4"/>
</connections>
<point key="canvasLocation" x="-124" y="78"/>
<point key="canvasLocation" x="26" y="-120"/>
</tableViewCell>
</objects>
<resources>
<image name="menu_arrow_bottom" width="44" height="44"/>
<image name="menu_arrow_top" width="44" height="44"/>
</resources>
</document>
44 changes: 6 additions & 38 deletions Stepic/Course.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ final class Course: NSManagedObject, IDFetchable {
}
}

var sectionDeadlines: [SectionDeadline]? {
get {
return (PersonalDeadlineLocalStorageManager().getRecord(for: self)?.data as? DeadlineStorageData)?.deadlines
}
}

var metaInfo: String {
//percent of completion = n_steps_passed/n_steps
if let p = self.progress {
Expand All @@ -72,13 +78,6 @@ final class Course: NSManagedObject, IDFetchable {

var metaInfoContainer: CourseMetainfoContainer {
var metaArr = [CourseMetainfoEntity]()

// if summary != "" {
// metaArr += [CourseMetainfoEntity(title: NSLocalizedString("Summary", comment: ""), subtitle: summary)]
// }
// if courseDescription != "" {
// metaArr += [CourseMetainfoEntity(title: NSLocalizedString("Description", comment: ""), subtitle: courseDescription)]
// }
if workload != "" {
metaArr += [CourseMetainfoEntity(title: NSLocalizedString("Workload", comment: ""), subtitle: workload)]
}
Expand All @@ -91,10 +90,6 @@ final class Course: NSManagedObject, IDFetchable {
if format != "" {
metaArr += [CourseMetainfoEntity(title: NSLocalizedString("Format", comment: ""), subtitle: format)]
}
// if requirements != "" {
// metaArr += [CourseMetainfoEntity(title: NSLocalizedString("Requirements", comment: ""), subtitle: requirements)]
// }
//
return CourseMetainfoContainer(courseId: id, metainfo: metaArr)
}

Expand Down Expand Up @@ -132,22 +127,6 @@ final class Course: NSManagedObject, IDFetchable {
initialize(json)
}

// func loadLastStep(success: @escaping ((Void) -> Void)) {
// guard let id = self.lastStepId else {
// return
// }
// _ = ApiDataDownloader.lastSteps.retrieve(ids: [id], success: {
// [weak self]
// lastSteps in
//
// self?.changeLastStepTo(lastStep: lastSteps.first!)
// success()
// }, error: {
// error in
// print("error while loading last step")
// })
// }

func loadAllInstructors(success: @escaping (() -> Void)) {
_ = ApiDataDownloader.users.retrieve(ids: self.instructorsArray, existing: self.instructors, refreshMode: .update, success: {
users in
Expand Down Expand Up @@ -178,7 +157,6 @@ final class Course: NSManagedObject, IDFetchable {
idsArray[dimCount - 1].append(sectionId)
}

// let sectionsToDownload = idsArray.count
var downloadedSections = [Section]()

let idsDownloaded: ([Section]) -> Void = {
Expand Down Expand Up @@ -237,7 +215,6 @@ final class Course: NSManagedObject, IDFetchable {
return
}

// print("progress ids array -> \(progressIds)")
_ = ApiDataDownloader.progresses.retrieve(ids: progressIds, existing: progresses, refreshMode: .update, success: {
newProgresses -> Void in
progresses = Sorter.sort(newProgresses, byIds: progressIds)
Expand Down Expand Up @@ -362,7 +339,6 @@ final class Course: NSManagedObject, IDFetchable {
} catch {
print("Error while getting courses")
return []
// throw FetchError.RequestExecution
}
}

Expand All @@ -385,12 +361,4 @@ final class Course: NSManagedObject, IDFetchable {
return sections.filter({ $0.id == nextId }).first
}
}

// func changeLastStepTo(lastStep: LastStep?) {
// let objectToDelete = self.lastStep
// self.lastStep = lastStep
// if let deletingObject = objectToDelete {
// CoreDataHelper.instance.deleteFromStore(deletingObject, save: true)
// }
// }
}
5 changes: 5 additions & 0 deletions Stepic/CourseListPresenter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,11 @@ class CourseListPresenter {
return
}
strongSelf.lastStepDataSource?.didLoadWithProgresses(courses: strongSelf.courses)
if let userID = AuthInfo.shared.userId {
for course in strongSelf.courses {
PersonalDeadlineManager.shared.syncDeadline(for: course, userID: userID)
}
}
})
default:
state = courses.isEmpty ? .emptyRefreshing : .displayingWithRefreshing
Expand Down
40 changes: 40 additions & 0 deletions Stepic/DeadlineMode.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//
// DeadlineMode.swift
// Stepic
//
// Created by Ostrenkiy on 15.05.2018.
// Copyright © 2018 Alex Karpov. All rights reserved.
//

import Foundation

struct DeadlineModeInfo {
var title: String
var weeklyLoadHours: Int
var image: UIImage

init(title: String, weeklyLoadHours: Int, image: UIImage) {
self.title = title
self.weeklyLoadHours = weeklyLoadHours
self.image = image
}

var dailyLoadSeconds: Int {
return weeklyLoadHours * 60 * 60 / 7
}
}

enum DeadlineMode {
case hobby, standard, extreme

func getModeInfo() -> DeadlineModeInfo {
switch self {
case .hobby:
return DeadlineModeInfo(title: NSLocalizedString("HobbyDeadlineMode", comment: ""), weeklyLoadHours: 3, image: #imageLiteral(resourceName: "25-science-growth-sprout"))
case .standard:
return DeadlineModeInfo(title: NSLocalizedString("StandardDeadlineMode", comment: ""), weeklyLoadHours: 7, image: #imageLiteral(resourceName: "27-science-study-learn-graduate"))
case .extreme:
return DeadlineModeInfo(title: NSLocalizedString("ExtremeDeadlineMode", comment: ""), weeklyLoadHours: 15, image: #imageLiteral(resourceName: "1-science-rocket-spaceship-rocket-launch"))
}
}
}
Loading