Skip to content
This repository has been archived by the owner on Oct 26, 2022. It is now read-only.

Commit

Permalink
Merge pull request #6 from ORTUS-Plus/dev
Browse files Browse the repository at this point in the history
Bug fixes, redesigned grades screen
  • Loading branch information
Recouse authored Sep 9, 2020
2 parents 9726df0 + 09cbe65 commit 8bce5ef
Show file tree
Hide file tree
Showing 35 changed files with 991 additions and 134 deletions.
21 changes: 21 additions & 0 deletions Models/Schedule/Event.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,26 @@ public struct Event: Codable {

return dateFormatter.string(from: date)
}

public var timeParsed: String {
let dateFormatter = DateFormatter()
dateFormatter.timeZone = TimeZone(identifier: "Europe/Riga")

if let timeFromDate = date {
dateFormatter.dateFormat = "HH:mm"
dateFormatter.timeZone = TimeZone.current
return dateFormatter.string(from: timeFromDate)
}

return time
}

public var date: Date? {
let dateFormatter = DateFormatter()
dateFormatter.timeZone = TimeZone(identifier: "Europe/Riga")
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm"

return dateFormatter.date(from: datetime)
}
}

96 changes: 84 additions & 12 deletions ORTUS.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions ORTUS/API/APIClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ class APIClient {
_ responseType: T.Type,
route: API
) -> Promise<T> {
Self.showActivityIndicator()

return Promise { fulfill, reject in
AF.upload(multipartFormData: {
guard let parameters = route.parameters else { return }
Expand All @@ -61,6 +63,8 @@ class APIClient {
$0.append(parameterValue.data(using: .utf8) ?? Data(), withName: key)
}
}, with: route).responseDecodable { (response: DataResponse<T, AFError>) in
Self.hideActivityIndicator()

switch response.result {
case .success(let responseObject):
fulfill(responseObject)
Expand All @@ -76,8 +80,12 @@ class APIClient {
route: API,
decoder: JSONDecoder = JSONDecoder()
) -> Promise<T> {
Self.showActivityIndicator()

return Promise { fulfill, reject in
AF.request(route).responseDecodable (decoder: decoder) { (response: DataResponse<T, AFError>) in
Self.hideActivityIndicator()

switch response.result {
case .success(let responseObject):
fulfill(responseObject)
Expand All @@ -87,4 +95,12 @@ class APIClient {
}
}
}

private static func showActivityIndicator() {
UIApplication.shared.isNetworkActivityIndicatorVisible = true
}

private static func hideActivityIndicator() {
UIApplication.shared.isNetworkActivityIndicatorVisible = false
}
}
22 changes: 22 additions & 0 deletions ORTUS/Extensions/Carbon/ORTUSSelectionNoneTableViewCell.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// ORTUSSelectionNoneTableViewCell.swift
// ORTUS
//
// Created by Firdavs Khaydarov on 8/19/20.
// Copyright © 2020 Firdavs. All rights reserved.
//

import UIKit
import Carbon

class ORTUSSelectionNoneTableViewCell: UITableViewCell, ComponentRenderable {
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)

selectionStyle = .none
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
55 changes: 54 additions & 1 deletion ORTUS/Extensions/Carbon/ORTUSTableViewAdapter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,65 @@
import UIKit
import Carbon

protocol ORTUSTableViewAdapterDelegate: AnyObject {
@available(iOS 13.0, *)
func contextMenuConfiguration(
forRowAt indexPath: IndexPath,
point: CGPoint
) -> UIContextMenuConfiguration?

@available(iOS 13.0, *)
func willPerformPreviewActionForMenu(
configuration: UIContextMenuConfiguration,
animator: UIContextMenuInteractionCommitAnimating
)
}

//extension ORTUSTableViewAdapterDelegate {
// @available(iOS 13.0, *)
// func contextMenuConfiguration(
// forRowAt indexPath: IndexPath,
// point: CGPoint
// ) -> UIContextMenuConfiguration? {
// return nil
// }
//}

class ORTUSTableViewAdapter: UITableViewAdapter {
weak var delegate: ORTUSTableViewAdapterDelegate?

let selectionStyle: UITableViewCell.SelectionStyle

init(
delegate: ORTUSTableViewAdapterDelegate? = nil,
selectionStyle: UITableViewCell.SelectionStyle = .default
) {
self.delegate = delegate
self.selectionStyle = selectionStyle

super.init()
}

override func cellRegistration(tableView: UITableView, indexPath: IndexPath, node: CellNode) -> CellRegistration {
CellRegistration(class: ORTUSTableViewCell.self)
switch selectionStyle {
case .none:
return CellRegistration(class: ORTUSSelectionNoneTableViewCell.self)
default:
return CellRegistration(class: ORTUSTableViewCell.self)
}
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
super.tableView(tableView, cellForRowAt: indexPath)
}

@available(iOS 13.0, *)
func tableView(_ tableView: UITableView, contextMenuConfigurationForRowAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? {
delegate?.contextMenuConfiguration(forRowAt: indexPath, point: point)
}

@available(iOS 13.0, *)
func tableView(_ tableView: UITableView, willPerformPreviewActionForMenuWith configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionCommitAnimating) {
delegate?.willPerformPreviewActionForMenu(configuration: configuration, animator: animator)
}
}
23 changes: 23 additions & 0 deletions ORTUS/Extensions/String.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,29 @@
import Foundation

extension String {
// Source https://stackoverflow.com/a/47230632/7844080
var htmlToAttributedString: NSAttributedString? {
guard let data = data(using: .utf8) else {
return nil
}

do {
return try NSAttributedString(
data: data,
options: [
.documentType: NSAttributedString.DocumentType.html,
.characterEncoding: String.Encoding.utf8.rawValue
],
documentAttributes: nil
)
} catch {
return nil
}
}
var htmlToString: String {
return htmlToAttributedString?.string ?? ""
}

func generatePinAuthURL(withToken token: String) -> URL? {
let string = "\(Global.Server.pinAuthURL)?module=PINAuth&locale=en&token=\(token)&goto=\(self.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? "")"

Expand Down
6 changes: 3 additions & 3 deletions ORTUS/Modules/Contacts/ContactsTableViewAdapter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ protocol ContactsTableViewAdapterDelegate: AnyObject {
}

class ContactsTableViewAdapter: ORTUSTableViewAdapter {
weak var delegate: ContactsTableViewAdapterDelegate?
weak var contactsDelegate: ContactsTableViewAdapterDelegate?

init(delegate: ContactsTableViewAdapterDelegate?) {
self.delegate = delegate
self.contactsDelegate = delegate

super.init()
}

func sectionIndexTitles(for tableView: UITableView) -> [String]? {
return delegate?.indexTitles()
return contactsDelegate?.indexTitles()
}

func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int {
Expand Down
8 changes: 6 additions & 2 deletions ORTUS/Modules/Grades/GradesRouter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
// Copyright (c) 2020 Firdavs. All rights reserved.
//

final class GradesRouter: Router<GradesViewController> {
typealias Routes = Closable
final class GradesRouter: Router<GradesViewController>, MarkRoute {
typealias Routes = MarkRoute & Closable

var transition: Transition {
PushTransition()
}
}

56 changes: 24 additions & 32 deletions ORTUS/Modules/Grades/GradesViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,11 @@
import UIKit
import Carbon
import Promises
import Models

class GradesViewController: Module, ModuleViewModel {
class GradesViewController: ORTUSTableViewController, ModuleViewModel {
var viewModel: GradesViewModel

weak var gradesView: GradesView! { return view as? GradesView }
weak var tableView: UITableView! { return gradesView.tableView }

var refreshControl: UIRefreshControl!

lazy var renderer = Renderer(
adapter: UITableViewAdapter(),
updater: UITableViewUpdater()
)

init(viewModel: GradesViewModel) {
self.viewModel = viewModel

Expand All @@ -33,23 +24,34 @@ class GradesViewController: Module, ModuleViewModel {
fatalError("init(coder:) has not been implemented")
}

override func loadView() {
view = GradesView()
}

override func viewDidLoad() {
super.viewDidLoad()

userActivity = Shortcut(activity: .grades).activity

EventLogger.log(.openedGrades)

prepareRefreshControl()
prepareData()

loadData()
}

override func prepareData() {
super.prepareData()

renderer.updater.isAnimationEnabledWhileScrolling = false

navigationItem.title = L10n.Grades.title

renderer.adapter.didSelect = { [unowned self] context in
guard let semesters = self.viewModel.studyPrograms.first?.semesters else {
return
}

let mark = semesters[context.indexPath.section].marks[context.indexPath.row]

self.openMark(mark)
}
}

func render() {
refreshControl.endRefreshing()

Expand All @@ -64,7 +66,7 @@ class GradesViewController: Module, ModuleViewModel {
header: Header(title: semester.fullName.uppercased())
) {
Group(of: semester.marks) { mark in
GradeComponent(id: mark.id, mark: mark)
GradeComponent(mark: mark).identified(by: mark.id)
}
}
}
Expand All @@ -89,21 +91,11 @@ class GradesViewController: Module, ModuleViewModel {
}
}

@objc func refresh() {
override func refresh() {
loadData(forceUpdate: true)
}
}

extension GradesViewController {
func prepareRefreshControl() {
refreshControl = UIRefreshControl()
tableView.refreshControl = refreshControl
refreshControl.addTarget(self, action: #selector(refresh), for: .valueChanged)
}

func prepareData() {
renderer.target = tableView

navigationItem.title = L10n.Grades.title
func openMark(_ mark: Mark) {
viewModel.router.openMark(mark)
}
}
24 changes: 24 additions & 0 deletions ORTUS/Modules/Grades/Mark/MarkModuleBuilder.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// MarkModuleBuilder.swift
// ORTUS
//
// Created by Firdavs Khaydarov on 8/19/20.
// Copyright (c) 2020 Firdavs. All rights reserved.
//

import Models

class MarkModuleBuilder: ModuleBuilder {
typealias M = MarkViewController
typealias P = Mark

static func build(with parameter: Mark, customTransition transition: Transition? = nil) -> MarkViewController {
let router = MarkRouter()
let viewModel = MarkViewModel(mark: parameter, router: router)
let viewController = MarkViewController(viewModel: viewModel)
router.viewController = viewController
router.openTransition = transition

return viewController
}
}
12 changes: 12 additions & 0 deletions ORTUS/Modules/Grades/Mark/MarkRouter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// MarkRouter.swift
// ORTUS
//
// Created by Firdavs Khaydarov on 8/19/20.
// Copyright (c) 2020 Firdavs. All rights reserved.
//

final class MarkRouter: Router<MarkViewController> {
typealias Routes = Closable
}

Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
//
// GradesView.swift
// MarkView.swift
// ORTUS
//
// Created by Firdavs Khaydarov on 04/02/20.
// Created by Firdavs Khaydarov on 8/19/20.
// Copyright (c) 2020 Firdavs. All rights reserved.
//

import UIKit

class GradesView: UIView {
class MarkView: UIView {
let tableView: UITableView = {
let tableView = UITableView(frame: .zero, style: .grouped)
tableView.backgroundView = nil
Expand Down
Loading

0 comments on commit 8bce5ef

Please sign in to comment.