Skip to content
This repository has been archived by the owner on Jan 10, 2024. It is now read-only.

Commit

Permalink
Calendar types, TUMSexyView, MoviesView and NewsView (#399)
Browse files Browse the repository at this point in the history
* Introduce Different Calendar Types

* Fully functional TUMSexy component

* added buildin web view functionality

* Working News API

* Initial News View

* Fix project file after rebase

* Finalized news component

* Functioning movie component plus initial view

* Movies View

* Completed Movies Views

* Resolve duplicates after rebasing to swiftUi

Co-authored-by: Milen Vitanov <m.vitanov@tum.de>
  • Loading branch information
mvitanov and mvitanov authored Jan 27, 2022
1 parent 2715bf6 commit c5e40a4
Show file tree
Hide file tree
Showing 34 changed files with 1,966 additions and 577 deletions.
1,034 changes: 609 additions & 425 deletions Campus-iOS.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
"repositoryURL": "https://github.com/firebase/firebase-ios-sdk.git",
"state": {
"branch": null,
"revision": "08686f04881483d2bc098b2696e674c0ba135e47",
"version": "8.10.0"
"revision": "5344857522053b5d4403ec8173ec0d23200a97ea",
"version": "8.11.0"
}
},
{
Expand All @@ -60,8 +60,8 @@
"repositoryURL": "https://github.com/google/GoogleUtilities.git",
"state": {
"branch": null,
"revision": "797005ad8a1f0614063933e2fa010a5d13cb09d0",
"version": "7.6.0"
"revision": "b3bb0c5551fb3f80ca939829639ab5b093edd14f",
"version": "7.7.0"
}
},
{
Expand Down Expand Up @@ -96,8 +96,8 @@
"repositoryURL": "https://github.com/kvyatkovskys/KVKCalendar.git",
"state": {
"branch": null,
"revision": "766c577ab97c8aa3a850b36b84c47a4a06031c26",
"version": "0.5.5"
"revision": "c4728c93df4a52a4921b8825944128a2c8e08bd9",
"version": "0.5.8"
}
},
{
Expand Down Expand Up @@ -159,8 +159,8 @@
"repositoryURL": "https://github.com/willdale/SwiftUICharts",
"state": {
"branch": null,
"revision": "133c493e6f67f4c563ab836aa809bfb66f25111e",
"version": "2.9.6"
"revision": "6ba7163599e26a8292a77e8be5c4ddcbfbdc5c70",
"version": "2.9.7"
}
},
{
Expand Down
72 changes: 72 additions & 0 deletions Campus-iOS/Base/Entity/EntityImporter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
//
// EntityImporter.swift
// Campus-iOS
//
// Created by Milen Vitanov on 13.01.22.
//

import UIKit.UIApplication
//import CoreData
import Alamofire
import FirebaseCrashlytics

protocol Entity: Decodable {

}

enum ImporterError: Error {
case invalidData
}

final class Importer<EntityType: Entity, EntityContainer: Decodable, DecoderType: DecoderProtocol> {
typealias RequestHandler = (Result<EntityContainer, Error>) -> Void

let endpoint: URLRequestConvertible
let dateDecodingStrategy: DecoderType.DateDecodingStrategy?
let predicate: NSPredicate?

private let sessionManager = Session.defaultSession

required init(endpoint: URLRequestConvertible, predicate: NSPredicate? = nil, dateDecodingStrategy: DecoderType.DateDecodingStrategy? = nil) {
self.endpoint = endpoint
self.predicate = predicate
self.dateDecodingStrategy = dateDecodingStrategy
}

func performFetch(handler: RequestHandler? = nil) {
sessionManager.request(endpoint)
.validate(statusCode: 200..<300)
.validate(contentType: DecoderType.contentType)
.responseData { response in
if let responseError = response.error {
handler?(.failure(BackendError.AFError(message: responseError.localizedDescription)))
return
}
guard let data = response.data else {
handler?(.failure(ImporterError.invalidData))
return
}

let decoder = DecoderType.instantiate()
if let strategy = self.dateDecodingStrategy {
decoder.dateDecodingStrategy = strategy
}
do {
let storage = try decoder.decode(EntityContainer.self, from: data)
handler?(.success(storage))
} catch let apiError as APIError {
Crashlytics.crashlytics().record(error: apiError)
handler?(.failure(apiError))
return
} catch let decodingError as DecodingError {
Crashlytics.crashlytics().record(error: decodingError)
handler?(.failure(decodingError))
return
} catch let error {
Crashlytics.crashlytics().record(error: error)
handler?(.failure(error))
}
}
}

}
1 change: 1 addition & 0 deletions Campus-iOS/Base/Errors/BackendError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

enum BackendError: Error {
case network(error: Error)
case AFError(message: String)
case dataSerialization(error: Error)
case jsonSerialization(error: Error)
case xmlSerialization(error: Error)
Expand Down
20 changes: 20 additions & 0 deletions Campus-iOS/Base/Helpers/DecoderProtocol.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// DecoderProtocol.swift
// Campus-iOS
//
// Created by Milen Vitanov on 13.01.22.
//

import Foundation
import Alamofire

protocol DecoderProtocol: AnyObject, DataDecoder {
associatedtype DateDecodingStrategy: DecodingStrategyProtocol
func decode<T>(_ type: T.Type, from data: Data) throws -> T where T : Decodable
var userInfo: [CodingUserInfoKey : Any] { get set }
var dateDecodingStrategy: DateDecodingStrategy { get set }
static var contentType: [String] { get }
static func instantiate() -> Self
}

protocol DecodingStrategyProtocol { }
29 changes: 29 additions & 0 deletions Campus-iOS/Base/Networking/TUMSexyAPI.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// TUMSexyAPI.swift
// TUM Campus App
//
// Created by Tim Gymnich on 2/23/19.
// Copyright © 2019 TUM. All rights reserved.
//

import Alamofire
import Foundation

struct TUMSexyAPI: URLRequestConvertible {
static let baseURLString = "https://json.tum.sexy"

var method: HTTPMethod {
switch self {
default: return .get
}
}

static var requiresAuth: [String] = []

func asURLRequest() throws -> URLRequest {
let url = try TUMSexyAPI.baseURLString.asURL()
let urlRequest = try URLRequest(url: url, method: method)
return urlRequest
}

}
11 changes: 9 additions & 2 deletions Campus-iOS/CalendarComponent/Views/CalendarContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,17 @@ import SwiftUI
import KVKCalendar
struct CalendarContentView: View {
@State var events: [Event] = []
@State var selectedType: CalendarType = .week // I want this to change its calendar type.
@State var selectedType: TumCalendarTypes = .day

var body: some View {
VStack{
CalendarDisplayView(events: $events)
Picker("Calendar Type", selection: $selectedType) {
ForEach(TumCalendarTypes.allCases, id: \.self) {
Text($0.localizedString)
}
}
.pickerStyle(.segmented)
CalendarDisplayView(events: $events, type: $selectedType)
}
}
}
Expand Down
22 changes: 18 additions & 4 deletions Campus-iOS/CalendarComponent/Views/CalendarDisplayView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ import KVKCalendar
struct CalendarDisplayView: UIViewRepresentable {

@Binding var events: [Event]
@Binding var type: TumCalendarTypes

public init(events: Binding<[Event]>) {
public init(events: Binding<[Event]>, type: Binding<TumCalendarTypes>) {
self._events = events
self._type = type
}

private var calendar: CalendarView = {
Expand All @@ -26,17 +28,26 @@ struct CalendarDisplayView: UIViewRepresentable {
style.timeline.offsetLineLeft = 2
style.headerScroll.titleDateAlignment = .center
style.headerScroll.isAnimateTitleDate = true
style.headerScroll.isAnimateSelection = true
style.headerScroll.heightHeaderWeek = 70
style.event.isEnableVisualSelect = false
style.month.isHiddenTitle = true
style.month.isHiddenEventTitle = true
style.headerScroll.titleDateFont = .boldSystemFont(ofSize: 18)
style.month.weekDayAlignment = .center
} else {
style.timeline.widthEventViewer = 350
style.headerScroll.fontNameDay = .systemFont(ofSize: 17)
style.headerScroll.fontNameDay = .systemFont(ofSize: 20)
}
style.headerScroll.colorBackground = .systemBackground
style.headerScroll.colorBackgroundCurrentDate = .tumBlue
style.headerScroll.colorCurrentDate = .white
style.month.autoSelectionDateWhenScrolling = true
style.timeline.offsetTimeY = 25
// cuts out the hours before the first event if true
style.timeline.startFromFirstEvent = false
style.allDay.backgroundColor = .systemBackground
style.startWeekDay = .monday
style.defaultType = CalendarType.day
style.timeSystem = .current ?? .twelve
style.systemCalendars = ["Calendar"]
if #available(iOS 13.0, *) {
Expand All @@ -55,7 +66,10 @@ struct CalendarDisplayView: UIViewRepresentable {
}

func updateUIView(_ uiView: CalendarView, context: UIViewRepresentableContext<CalendarDisplayView>) {
context.coordinator.events = events
context.coordinator.events = events

calendar.set(type: type.calendarType, date: Date()) /// I've never used this library, so you might need to replace `Date()` with something else
calendar.reloadData()
}

func makeCoordinator() -> CalendarDisplayView.Coordinator {
Expand Down
10 changes: 10 additions & 0 deletions Campus-iOS/Campus-iOS/Base.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@
"No Menu" = "No Menu";
"List View" = "List View";
"Jump to Today" = "Jump to Today";
"GENERAL" = "GENERAL";
"GET IN CONTACT" = "GET IN CONTACT";
"Use build-in Web View" = "Web View benutzen";

"animation showing the token activation" = "animation showing the token activation";
"First 2 letters of TUM ID" = "First 2 letters of TUM ID";
Expand All @@ -72,3 +75,10 @@
"2" = "2";
"3" = "3";
"Authorize Token" = "Authorize Token";

// Calendar

"Day" = "Day";
"Week" = "Week";
"Month" = "Month";
"Year" = "Year";
11 changes: 10 additions & 1 deletion Campus-iOS/Campus-iOS/de.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@
"No Menu" = "Kein Menü";
"List View" = "Listenansicht";
"Jump to Today" = "Zum heutigen Tag springen";

"GENERAL" = "ALLGEMEIN";
"GET IN CONTACT" = "KONTAKTIERE UNS";
"Use build-in Web View" = "Web View benutzen";

// Login.storybroad

Expand All @@ -67,3 +69,10 @@
"2" = "2";
"3" = "3";
"Authorize Token" = "Token authorisieren";

// Calendar

"Day" = "Tag";
"Week" = "Woche";
"Month" = "Monat";
"Year" = "Jahr";
25 changes: 25 additions & 0 deletions Campus-iOS/Enums/Enums.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,34 @@
//

import Foundation
import KVKCalendar

enum SheetDestination {
case none
case loginSheet(model: Model)
case profileSheet(model: Model)
}

enum TumCalendarTypes: String, CaseIterable {
case day = "Day"
case week = "Week"
case month = "Month"
case year = "Year"

var localizedString: String {
return NSLocalizedString(self.rawValue, comment: "")
}

var calendarType: CalendarType {
switch(self) {
case .day:
return CalendarType.day
case .week:
return CalendarType.week
case .month:
return CalendarType.month
case .year:
return CalendarType.year
}
}
}
52 changes: 52 additions & 0 deletions Campus-iOS/Extensions/Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import Foundation
import Alamofire
import CoreLocation
import SWXMLHash
import XMLCoder
import SwiftUI

extension Bundle {
var version: String { infoDictionary?["CFBundleShortVersionString"] as? String ?? "1" }
Expand Down Expand Up @@ -140,3 +142,53 @@ extension DateFormatter {
extension CLLocationCoordinate2D {
var location: CLLocation { CLLocation(latitude: latitude, longitude: longitude) }
}

extension UIColor {
static let tumBlue = UIColor(red: 0, green: 101/255, blue: 189/255, alpha: 1)
}

extension JSONDecoder.DateDecodingStrategy: DecodingStrategyProtocol { }

extension XMLDecoder.DateDecodingStrategy: DecodingStrategyProtocol { }

extension JSONDecoder: DecoderProtocol {
static var contentType: [String] { return ["application/json"] }
static func instantiate() -> Self {
// infers the type of self from the calling context:
func helper<T>() -> T {
let decoder = JSONDecoder()
return decoder as! T
}
return helper()
}
}

extension XMLDecoder: DecoderProtocol {
static var contentType: [String] { return ["text/xml"] }
static func instantiate() -> Self {
// infers the type of self from the calling context
func helper<T>() -> T {
let decoder = XMLDecoder()
return decoder as! T
}
return helper()
}
}

extension View {
/// Applies the given transform according to condition.
/// - Parameters:
/// - condition: The condition to evaluate.
/// - transformT: The transform to apply to the source `View` if condition is true.
/// - transformF: The transform to apply to the source `View` if condition is false.
/// - Returns: Modified `View` based on condition.
@ViewBuilder func `if`<Content: View>(_ condition: Bool, transformT: (Self) -> Content, transformF: ((Self) -> Content)? = nil) -> some View {
if condition {
transformT(self)
} else if let transform = transformF {
transform(self)
} else {
self
}
}
}
Loading

0 comments on commit c5e40a4

Please sign in to comment.