Merge pull request #8 from wulkanowy/feature/account-manager
Account manager
This commit is contained in:
commit
b99c4efeed
38 changed files with 1621 additions and 340 deletions
|
@ -28,6 +28,16 @@
|
|||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "SdkTests"
|
||||
BuildableName = "SdkTests"
|
||||
BlueprintName = "SdkTests"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
|
|
|
@ -13,15 +13,16 @@ let package = Package(
|
|||
],
|
||||
dependencies: [
|
||||
// Dependencies declare other packages that this package depends on.
|
||||
.package(url: "https://github.com/kishikawakatsumi/KeychainAccess", from: "4.2.2"),
|
||||
.package(url: "https://github.com/kishikawakatsumi/KeychainAccess", from: "4.2.2"),
|
||||
.package(url: "https://github.com/krzyzanowskim/OpenSSL", from: "1.1.180"),
|
||||
.package(url: "https://github.com/SwiftyJSON/SwiftyJSON", from: "5.0.0")
|
||||
],
|
||||
targets: [
|
||||
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
|
||||
// Targets can depend on other targets in this package, and on products in packages this package depends on.
|
||||
.target(
|
||||
name: "Sdk",
|
||||
dependencies: ["KeychainAccess", "OpenSSL"]),
|
||||
dependencies: ["KeychainAccess", "OpenSSL", "SwiftyJSON"]),
|
||||
.testTarget(
|
||||
name: "SdkTests",
|
||||
dependencies: ["Sdk"]),
|
||||
|
|
|
@ -18,6 +18,7 @@ public extension Sdk {
|
|||
case noPrivateKey
|
||||
case noSignatureValues
|
||||
case urlError
|
||||
case deviceExist
|
||||
|
||||
case wrongToken
|
||||
case wrongSymbol
|
||||
|
|
|
@ -9,35 +9,25 @@ import Foundation
|
|||
import KeychainAccess
|
||||
|
||||
@available (iOS 14, macOS 11, watchOS 7, tvOS 14, *)
|
||||
func getSignatures(request: URLRequest, certificate: X509) -> String {
|
||||
func getSignatures(request: URLRequest, fingerprint: String, privateKeyString: Data) -> String {
|
||||
guard let urlString = request.url?.absoluteString else {
|
||||
return "\(Sdk.APIError.urlError)"
|
||||
}
|
||||
|
||||
// Get private key
|
||||
guard let privateKeyRawData = certificate.getPrivateKeyData(format: .DER),
|
||||
let privateKeyString = String(data: privateKeyRawData, encoding: .utf8)?
|
||||
.split(separator: "\n")
|
||||
.dropFirst()
|
||||
.dropLast()
|
||||
.joined()
|
||||
.data(using: .utf8) else {
|
||||
return "\(Sdk.APIError.noPrivateKey)"
|
||||
}
|
||||
|
||||
// Create SecKey
|
||||
// Create SecKey
|
||||
let attributes = [
|
||||
kSecAttrKeyType: kSecAttrKeyTypeRSA,
|
||||
kSecAttrKeyClass: kSecAttrKeyClassPrivate,
|
||||
kSecAttrKeyType: kSecAttrKeyTypeRSA,
|
||||
kSecAttrKeyClass: kSecAttrKeyClassPrivate,
|
||||
]
|
||||
guard let privateKeyData = Data(base64Encoded: privateKeyString),
|
||||
let secKey = SecKeyCreateWithData(privateKeyData as NSData, attributes as NSDictionary, nil) else {
|
||||
return "\(Sdk.APIError.noPrivateKey)"
|
||||
}
|
||||
|
||||
guard let privateKeyData = Data(base64Encoded: privateKeyString),
|
||||
let secKey = SecKeyCreateWithData(privateKeyData as NSData, attributes as NSDictionary, nil) else {
|
||||
return "\(Sdk.APIError.noPrivateKey)"
|
||||
}
|
||||
|
||||
// Get fingerprint
|
||||
guard let signatureValues = Sdk.Signer.getSignatureValues(body: request.httpBody, url: urlString, privateKey: secKey, fingerprint: certificate.getCertificateFingerprint().lowercased()) else {
|
||||
return "\(Sdk.APIError.noPrivateKey)"
|
||||
guard let signatureValues = Sdk.Signer.getSignatureValues(body: request.httpBody, url: urlString, privateKey: secKey, fingerprint: fingerprint) else {
|
||||
return "noFingerprint"
|
||||
}
|
||||
|
||||
// Headers
|
||||
|
|
|
@ -7,15 +7,17 @@
|
|||
|
||||
|
||||
import Foundation
|
||||
import KeychainAccess
|
||||
import Combine
|
||||
import os
|
||||
import KeychainAccess
|
||||
import SwiftyJSON
|
||||
import SwiftUI
|
||||
|
||||
@available (iOS 14, macOS 11, watchOS 7, tvOS 14, *)
|
||||
public class Sdk {
|
||||
static private let libraryVersion: String = "0.0.1"
|
||||
|
||||
private let loggerSubsystem: String = "com.wulkanowy-ios.Sdk"
|
||||
private let loggerSubsystem: String = "io.wulkanowy-ios.Sdk"
|
||||
private var cancellables: Set<AnyCancellable> = []
|
||||
|
||||
var firebaseToken: String!
|
||||
|
@ -140,9 +142,91 @@ public class Sdk {
|
|||
let parsedError = self.parseResponse(response) {
|
||||
completionHandler(parsedError)
|
||||
} else {
|
||||
self.getStudents(symbol: symbol, deviceModel: deviceModel)
|
||||
completionHandler(nil)
|
||||
do {
|
||||
let keychain = Keychain()
|
||||
let allAccountsCheck: String! = keychain["allAccounts"] ?? "[]"
|
||||
let receiveValueJSON = try! JSON(data: data)
|
||||
|
||||
//parsing allAccounts to array
|
||||
let data = Data(allAccountsCheck.utf8)
|
||||
do {
|
||||
var ids = try JSONSerialization.jsonObject(with: data) as! [Int]
|
||||
if(ids == [])
|
||||
{
|
||||
ids = [0]
|
||||
} else {
|
||||
ids.append(ids.last! + 1)
|
||||
}
|
||||
keychain["allAccounts"] = "\(ids)"
|
||||
|
||||
} catch {
|
||||
print(error)
|
||||
}
|
||||
|
||||
// Get private key
|
||||
guard let privateKeyRawData = self.certificate.getPrivateKeyData(format: .DER),
|
||||
let privateKeyString = String(data: privateKeyRawData, encoding: .utf8)?
|
||||
.split(separator: "\n")
|
||||
.dropFirst()
|
||||
.dropLast()
|
||||
.joined()
|
||||
.data(using: .utf8) else {
|
||||
return
|
||||
}
|
||||
|
||||
let privateKeyStringString = String(decoding: privateKeyString, as: UTF8.self)
|
||||
|
||||
let fingerprint = self.certificate.getCertificateFingerprint().lowercased()
|
||||
|
||||
let saveAccount = """
|
||||
{
|
||||
"actualStudent": "0",
|
||||
"customUsername": "",
|
||||
"privateKeyString": "\(privateKeyStringString)",
|
||||
"fingerprint": "\(fingerprint)",
|
||||
"deviceModel": "\(deviceModel)",
|
||||
"account": {
|
||||
"UserName": "\(receiveValueJSON["Envelope"]["UserName"])",
|
||||
"RestURL": "\(receiveValueJSON["Envelope"]["RestURL"])",
|
||||
"UserLogin": "\(receiveValueJSON["Envelope"]["UserLogin"])",
|
||||
"LoginId": "\(receiveValueJSON["Envelope"]["LoginId"])"
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
let ids = keychain["allAccounts"]
|
||||
let dataIds: Data = Data(ids!.utf8)
|
||||
let idsArray = try JSONSerialization.jsonObject(with: dataIds) as! [Int]
|
||||
let id = idsArray.last
|
||||
|
||||
keychain["\(id!)"] = "\(saveAccount)"
|
||||
|
||||
keychain["actualStudentId"] = "\(id!)"
|
||||
keychain["actualAccountEmail"] = "\(receiveValueJSON["Envelope"]["UserName"])"
|
||||
|
||||
let endpointURL: String = "\(receiveValueJSON["Envelope"]["RestURL"])api/mobile/register/hebe"
|
||||
|
||||
let apiResponseRequest = apiRequest(endpointURL: endpointURL, id: "\(id!)")
|
||||
let session = URLSession.shared
|
||||
session.dataTask(with: apiResponseRequest) { (data, response, error) in
|
||||
if let error = error {
|
||||
// Handle HTTP request error
|
||||
print(error)
|
||||
} else if let data = data {
|
||||
// Handle HTTP request response
|
||||
let responseBody = String(data: data, encoding: String.Encoding.utf8)
|
||||
|
||||
keychain["actualStudentHebe"] = "\(responseBody!)"
|
||||
|
||||
} else {
|
||||
// Handle unexpected error
|
||||
}
|
||||
}.resume()
|
||||
} catch {
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
completionHandler(nil)
|
||||
})
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
@ -190,6 +274,8 @@ public class Sdk {
|
|||
let keychain = Keychain()
|
||||
keychain[string: "keyFingerprint"] = keyFingerprint
|
||||
|
||||
//Boże, proszę, dlaczego to nie działa, błagam
|
||||
|
||||
// Body
|
||||
let body: [String: Encodable?] = [
|
||||
"AppName": "DzienniczekPlus 2.0",
|
||||
|
@ -211,7 +297,7 @@ public class Sdk {
|
|||
"Timestamp": now.millisecondsSince1970,
|
||||
"TimestampFormatted": "\(timestampFormatted) GMT"
|
||||
]
|
||||
|
||||
|
||||
request.httpBody = try? JSONSerialization.data(withJSONObject: body)
|
||||
|
||||
request.allHTTPHeaderFields = [
|
||||
|
@ -225,50 +311,6 @@ public class Sdk {
|
|||
return URLSession.shared.dataTaskPublisher(for: signedRequest)
|
||||
}
|
||||
|
||||
private func getStudents(symbol: String, deviceModel: String) {
|
||||
let url = "\(self.endpointURL!)/\(symbol)/api/mobile/register/hebe"
|
||||
var request = URLRequest(url: URL(string: url)!)
|
||||
request.httpMethod = "GET"
|
||||
|
||||
let now = Date()
|
||||
var vDate: String {
|
||||
let dateFormatter = DateFormatter()
|
||||
dateFormatter.dateFormat = "EEE, dd MMM yyyy HH:mm:ss"
|
||||
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
|
||||
dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
|
||||
|
||||
return "\(dateFormatter.string(from: now)) GMT"
|
||||
}
|
||||
|
||||
let signatures = getSignatures(request: request, certificate: certificate)
|
||||
request.setValue("\(signatures)", forHTTPHeaderField: "Signature")
|
||||
|
||||
request.allHTTPHeaderFields = [
|
||||
"User-Agent": "wulkanowy/1 CFNetwork/1220.1 Darwin/20.1.0",
|
||||
"vOS": "iOS",
|
||||
"vDeviceModel": deviceModel,
|
||||
"vAPI": "1",
|
||||
"vDate": vDate,
|
||||
"vCanonicalUrl": "api%2fmobile%2fregister%2fhebe"
|
||||
]
|
||||
|
||||
let session = URLSession.shared
|
||||
let task = session.dataTask(with: request) { (data, response, error) in
|
||||
if let error = error {
|
||||
// Handle HTTP request error
|
||||
print(error)
|
||||
} else if let data = data {
|
||||
// Handle HTTP request response
|
||||
print(String(data: data, encoding: String.Encoding.utf8) as Any)
|
||||
} else {
|
||||
// Handle unexpected error
|
||||
}
|
||||
}
|
||||
|
||||
task.resume()
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Helper functions
|
||||
|
||||
/// Parses the response
|
||||
|
@ -287,6 +329,7 @@ public class Sdk {
|
|||
case 200: return APIError.wrongToken
|
||||
case -1: return APIError.wrongSymbol //Ya, Vulcan returns -1 code
|
||||
case 203: return APIError.wrongPin
|
||||
case 205: return APIError.deviceExist
|
||||
default: return nil
|
||||
}
|
||||
}
|
||||
|
|
54
sdk/Sources/Sdk/apiRequest.swift
Normal file
54
sdk/Sources/Sdk/apiRequest.swift
Normal file
|
@ -0,0 +1,54 @@
|
|||
//
|
||||
// apiRequest.swift
|
||||
//
|
||||
//
|
||||
// Created by Tomasz on 02/03/2021.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import SwiftyJSON
|
||||
import KeychainAccess
|
||||
|
||||
|
||||
@available (iOS 14, macOS 11, watchOS 7, tvOS 14, *)
|
||||
public func apiRequest(endpointURL: String, id: String) -> URLRequest {
|
||||
var request = URLRequest(url: URL(string: endpointURL)!)
|
||||
request.httpMethod = "GET"
|
||||
|
||||
let keychain = Keychain()
|
||||
|
||||
let account = keychain[id] ?? "[]"
|
||||
let data = Data(account.utf8)
|
||||
let accountJSON = try! JSON(data: data)
|
||||
|
||||
let fingerprint: String = "\(accountJSON["fingerprint"])"
|
||||
let privateKeyStringString: String = "\(accountJSON["privateKeyString"])"
|
||||
let privateKeyString: Data = Data(privateKeyStringString.utf8)
|
||||
let deviceModel: String = "\(accountJSON["deviceModel"])"
|
||||
|
||||
let now = Date()
|
||||
var vDate: String {
|
||||
let dateFormatter = DateFormatter()
|
||||
dateFormatter.dateFormat = "EEE, dd MMM yyyy HH:mm:ss"
|
||||
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
|
||||
dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
|
||||
|
||||
return "\(dateFormatter.string(from: now)) GMT"
|
||||
}
|
||||
|
||||
let signatures = getSignatures(request: request, fingerprint: fingerprint, privateKeyString: privateKeyString)
|
||||
request.setValue("\(signatures)", forHTTPHeaderField: "Signature")
|
||||
|
||||
request.allHTTPHeaderFields = [
|
||||
"User-Agent": "wulkanowy/1 CFNetwork/1220.1 Darwin/20.1.0",
|
||||
"vOS": "iOS",
|
||||
"vDeviceModel": deviceModel,
|
||||
"vAPI": "1",
|
||||
"vDate": vDate,
|
||||
"vCanonicalUrl": "api%2fmobile%2fregister%2fhebe"
|
||||
]
|
||||
|
||||
return request
|
||||
}
|
||||
|
45
sdk/Sources/Sdk/data/hebe.swift
Normal file
45
sdk/Sources/Sdk/data/hebe.swift
Normal file
|
@ -0,0 +1,45 @@
|
|||
//
|
||||
// File.swift
|
||||
//
|
||||
//
|
||||
// Created by Tomasz on 12/03/2021.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import KeychainAccess
|
||||
import SwiftyJSON
|
||||
import SwiftUI
|
||||
|
||||
@available (iOS 14, macOS 11, watchOS 7, tvOS 14, *)
|
||||
public func getHebe(id: String, account: JSON) -> JSON {
|
||||
let RestURL = "\(account["account"]["RestURL"])api/mobile/register/hebe"
|
||||
let keychain = Keychain()
|
||||
let hebeRequest = apiRequest(endpointURL: "\(RestURL)", id: id)
|
||||
let session = URLSession.shared
|
||||
var hebe: String = ""
|
||||
session.dataTask(with: hebeRequest) { (data, response, error) in
|
||||
if let error = error {
|
||||
// Handle HTTP request error
|
||||
print(error)
|
||||
} else if let data = data {
|
||||
// Handle HTTP request response
|
||||
let responseBody = String(data: data, encoding: String.Encoding.utf8)
|
||||
hebe = "\(responseBody!)"
|
||||
} else {
|
||||
// Handle unexpected error
|
||||
}
|
||||
}.resume()
|
||||
|
||||
var hebeJSON: JSON?
|
||||
while true {
|
||||
if(hebe != ""){
|
||||
let data: Data = Data(hebe.utf8)
|
||||
hebeJSON = try! JSON(data: data)
|
||||
break
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return hebeJSON!
|
||||
}
|
|
@ -6,7 +6,47 @@
|
|||
//
|
||||
|
||||
import Foundation
|
||||
import KeychainAccess
|
||||
import SwiftyJSON
|
||||
|
||||
@available (iOS 14, macOS 11, watchOS 7, tvOS 14, *)
|
||||
public func getLuckyNumber() -> Int {
|
||||
let keychain = Keychain()
|
||||
let actualStudentId = "\(keychain["actualStudentId"] ?? "0")"
|
||||
let actualAccount = keychain[actualStudentId]
|
||||
let dataAccount: Data = Data(actualAccount!.utf8)
|
||||
let actualAccountJSON = try! JSON(data: dataAccount)
|
||||
let studentId = Int("\(actualAccountJSON["actualStudent"])")
|
||||
let actualStudentHebe = keychain["actualStudentHebe"]
|
||||
let dataHebe: Data = Data(actualStudentHebe!.utf8)
|
||||
let actualStudentHebeJSON = try! JSON(data: dataHebe)
|
||||
let actualStudent = actualStudentHebeJSON["Envelope"][studentId!]
|
||||
let Id = "\(actualStudent["ConstituentUnit"]["Id"])"
|
||||
|
||||
let date = Date()
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateFormat = "yyyy-MM-dd"
|
||||
let day = formatter.string(from: date)
|
||||
|
||||
let RestURL = "\(actualStudent["Unit"]["RestURL"])/mobile/school/lucky?constituentId=\(Id)&day=\(day)"
|
||||
|
||||
let apiResponseRequest = apiRequest(endpointURL: RestURL, id: actualStudentId)
|
||||
|
||||
let session = URLSession.shared
|
||||
session.dataTask(with: apiResponseRequest) { (data, response, error) in
|
||||
if let error = error {
|
||||
// Handle HTTP request error
|
||||
print(error)
|
||||
} else if let data = data {
|
||||
// Handle HTTP request response
|
||||
let responseBody = String(data: data, encoding: String.Encoding.utf8)
|
||||
|
||||
print(responseBody!)
|
||||
|
||||
} else {
|
||||
// Handle unexpected error
|
||||
}
|
||||
}.resume()
|
||||
|
||||
return 7
|
||||
}
|
||||
|
|
|
@ -7,28 +7,34 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
5C0B2AFD25F78A6A009EABEC /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 5C0B2AFC25F78A6A009EABEC /* KeychainAccess */; };
|
||||
5C0ED1E3260D2704000DE4C6 /* PullToRefresh.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C0ED1E2260D2704000DE4C6 /* PullToRefresh.swift */; };
|
||||
5C1794B425E8FDFB007AD91A /* messages.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1794B325E8FDFB007AD91A /* messages.swift */; };
|
||||
5C1794B825E8FE08007AD91A /* notes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1794B725E8FE08007AD91A /* notes.swift */; };
|
||||
5C1794BC25E8FE19007AD91A /* settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1794BB25E8FE19007AD91A /* settings.swift */; };
|
||||
5C1794C025E8FE27007AD91A /* about.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1794BF25E8FE27007AD91A /* about.swift */; };
|
||||
5C1794CD25E90DBD007AD91A /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 5C1794CC25E90DBD007AD91A /* KeychainAccess */; };
|
||||
5C1CFA7A25EA32AE0047286F /* ghImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1CFA7925EA32AE0047286F /* ghImage.swift */; };
|
||||
5C2D331025E64F3C000253AC /* grades.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2D330F25E64F3C000253AC /* grades.swift */; };
|
||||
5C2D331425E650EC000253AC /* exams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2D331325E650EC000253AC /* exams.swift */; };
|
||||
5C2D331825E651C4000253AC /* homework.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2D331725E651C4000253AC /* homework.swift */; };
|
||||
5C2D331C25E651FB000253AC /* more.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2D331B25E651FB000253AC /* more.swift */; };
|
||||
5C2D331425E650EC000253AC /* calendar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2D331325E650EC000253AC /* calendar.swift */; };
|
||||
5C2D9A3225F75A760053CB9F /* Sdk in Frameworks */ = {isa = PBXBuildFile; productRef = 5C2D9A3125F75A760053CB9F /* Sdk */; };
|
||||
5C42E2A225EE656E0048DDCD /* SwiftyJSON in Frameworks */ = {isa = PBXBuildFile; productRef = 5C42E2A125EE656E0048DDCD /* SwiftyJSON */; };
|
||||
5C478F3525DC742100ABEFB7 /* VulcanStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C478F3425DC742100ABEFB7 /* VulcanStore.swift */; };
|
||||
5C5162D825F0DCDE00EF0777 /* more.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C5162D725F0DCDE00EF0777 /* more.swift */; };
|
||||
5C5162DC25F0DD9200EF0777 /* attendance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C5162DB25F0DD9200EF0777 /* attendance.swift */; };
|
||||
5C84E04625FAC5440088FD47 /* personalInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C84E04525FAC5440088FD47 /* personalInfo.swift */; };
|
||||
5C84E04A25FAC5520088FD47 /* residenceInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C84E04925FAC5520088FD47 /* residenceInfo.swift */; };
|
||||
5C84E04E25FAC5670088FD47 /* contact.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C84E04D25FAC5670088FD47 /* contact.swift */; };
|
||||
5C84E05225FAC5700088FD47 /* family.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C84E05125FAC5700088FD47 /* family.swift */; };
|
||||
5C89C8F525EA6AA4000B5816 /* licenses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C89C8F425EA6AA4000B5816 /* licenses.swift */; };
|
||||
5C89C90625EA7996000B5816 /* SwiftUIEKtensions in Frameworks */ = {isa = PBXBuildFile; productRef = 5C89C90525EA7996000B5816 /* SwiftUIEKtensions */; };
|
||||
5C9B6F4925D6C08D00C3F5F5 /* Sdk in Frameworks */ = {isa = PBXBuildFile; productRef = 5C9B6F4825D6C08D00C3F5F5 /* Sdk */; };
|
||||
5CB39737260D4BE200349B0D /* wulkanowyTests in Resources */ = {isa = PBXBuildFile; fileRef = 5CB39735260D4BE200349B0D /* wulkanowyTests */; };
|
||||
5CB39738260D4BE200349B0D /* LinuxMain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB39736260D4BE200349B0D /* LinuxMain.swift */; };
|
||||
5CB9907225EE4A3200AA405C /* CustomButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB9907125EE4A3200AA405C /* CustomButtonView.swift */; };
|
||||
5CB9907625EE4A3B00AA405C /* OnboardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB9907525EE4A3B00AA405C /* OnboardingView.swift */; };
|
||||
5CC2EAA525E516F100B6183E /* dashboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CC2EAA425E516F100B6183E /* dashboard.swift */; };
|
||||
5CC2EAAE25E526B500B6183E /* navigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CC2EAAD25E526B500B6183E /* navigation.swift */; };
|
||||
5CC80E9825F2CAA900F6DE60 /* accountCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CC80E9725F2CAA900F6DE60 /* accountCard.swift */; };
|
||||
5CCAE31625DA4CDD00D87580 /* OpenSSL in Frameworks */ = {isa = PBXBuildFile; productRef = 5CCAE31525DA4CDD00D87580 /* OpenSSL */; };
|
||||
5CCB276325EF9C4A00482F4A /* OnboardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCB276225EF9C4A00482F4A /* OnboardingView.swift */; };
|
||||
5CEA516B25D540B900DB45BD /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5CEA516D25D540B900DB45BD /* Localizable.strings */; };
|
||||
5CF095AD25F053B10068F2C6 /* accountManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CF095AC25F053B10068F2C6 /* accountManager.swift */; };
|
||||
5CF6695F25EEE2FD00AC0A86 /* chooseStudent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CF6695E25EEE2FD00AC0A86 /* chooseStudent.swift */; };
|
||||
F4C6D9082544E17400F8903A /* wulkanowyApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4C6D9072544E17400F8903A /* wulkanowyApp.swift */; };
|
||||
F4C6D90A2544E17400F8903A /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4C6D9092544E17400F8903A /* LoginView.swift */; };
|
||||
F4C6D90C2544E17500F8903A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F4C6D90B2544E17500F8903A /* Assets.xcassets */; };
|
||||
|
@ -77,26 +83,31 @@
|
|||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
5C0ED1E2260D2704000DE4C6 /* PullToRefresh.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PullToRefresh.swift; sourceTree = "<group>"; };
|
||||
5C1794B325E8FDFB007AD91A /* messages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = messages.swift; sourceTree = "<group>"; };
|
||||
5C1794B725E8FE08007AD91A /* notes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = notes.swift; sourceTree = "<group>"; };
|
||||
5C1794BB25E8FE19007AD91A /* settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = settings.swift; sourceTree = "<group>"; };
|
||||
5C1794BF25E8FE27007AD91A /* about.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = about.swift; sourceTree = "<group>"; };
|
||||
5C1CFA7925EA32AE0047286F /* ghImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ghImage.swift; sourceTree = "<group>"; };
|
||||
5C2D330F25E64F3C000253AC /* grades.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = grades.swift; sourceTree = "<group>"; };
|
||||
5C2D331325E650EC000253AC /* exams.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = exams.swift; sourceTree = "<group>"; };
|
||||
5C2D331725E651C4000253AC /* homework.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = homework.swift; sourceTree = "<group>"; };
|
||||
5C2D331B25E651FB000253AC /* more.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = more.swift; sourceTree = "<group>"; };
|
||||
5C2D331325E650EC000253AC /* calendar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = calendar.swift; sourceTree = "<group>"; };
|
||||
5C478F3425DC742100ABEFB7 /* VulcanStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VulcanStore.swift; sourceTree = "<group>"; };
|
||||
5C5162D725F0DCDE00EF0777 /* more.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = more.swift; sourceTree = "<group>"; };
|
||||
5C5162DB25F0DD9200EF0777 /* attendance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = attendance.swift; sourceTree = "<group>"; };
|
||||
5C84E04525FAC5440088FD47 /* personalInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = personalInfo.swift; sourceTree = "<group>"; };
|
||||
5C84E04925FAC5520088FD47 /* residenceInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = residenceInfo.swift; sourceTree = "<group>"; };
|
||||
5C84E04D25FAC5670088FD47 /* contact.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = contact.swift; sourceTree = "<group>"; };
|
||||
5C84E05125FAC5700088FD47 /* family.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = family.swift; sourceTree = "<group>"; };
|
||||
5C89C8F425EA6AA4000B5816 /* licenses.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = licenses.swift; sourceTree = "<group>"; };
|
||||
5C9B6E4925D6ADFB00C3F5F5 /* NetworkExtension.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NetworkExtension.framework; path = System/Library/Frameworks/NetworkExtension.framework; sourceTree = SDKROOT; };
|
||||
5C9B6F4525D6C06D00C3F5F5 /* Sdk */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Sdk; sourceTree = "<group>"; };
|
||||
5CB39735260D4BE200349B0D /* wulkanowyTests */ = {isa = PBXFileReference; lastKnownFileType = folder; name = wulkanowyTests; path = "../../../../../Library/Mobile Documents/com~apple~CloudDocs/.Trash/Tests/wulkanowyTests"; sourceTree = "<group>"; };
|
||||
5CB39736260D4BE200349B0D /* LinuxMain.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LinuxMain.swift; path = "../../../../../Library/Mobile Documents/com~apple~CloudDocs/.Trash/Tests/LinuxMain.swift"; sourceTree = "<group>"; };
|
||||
5CB9907125EE4A3200AA405C /* CustomButtonView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CustomButtonView.swift; path = ../../../../../../Shared/CustomButtonView.swift; sourceTree = "<group>"; };
|
||||
5CB9907525EE4A3B00AA405C /* OnboardingView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OnboardingView.swift; path = ../../../../../../Onboarding/OnboardingView.swift; sourceTree = "<group>"; };
|
||||
5CC2EAA425E516F100B6183E /* dashboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dashboard.swift; sourceTree = "<group>"; };
|
||||
5CC2EAAD25E526B500B6183E /* navigation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = navigation.swift; sourceTree = "<group>"; };
|
||||
5CC80E9725F2CAA900F6DE60 /* accountCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = accountCard.swift; sourceTree = "<group>"; };
|
||||
5CCB276225EF9C4A00482F4A /* OnboardingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingView.swift; sourceTree = "<group>"; };
|
||||
5CEA516C25D540B900DB45BD /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
5CF095AC25F053B10068F2C6 /* accountManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = accountManager.swift; sourceTree = "<group>"; };
|
||||
5CF6695E25EEE2FD00AC0A86 /* chooseStudent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = chooseStudent.swift; sourceTree = "<group>"; };
|
||||
5CF81BD725D9D44400B12C4C /* pl-PL */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pl-PL"; path = "pl-PL.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||
F4C6D9042544E17400F8903A /* wulkanowy.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = wulkanowy.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
F4C6D9072544E17400F8903A /* wulkanowyApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = wulkanowyApp.swift; sourceTree = "<group>"; };
|
||||
|
@ -116,10 +127,11 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5C9B6F4925D6C08D00C3F5F5 /* Sdk in Frameworks */,
|
||||
5CCAE31625DA4CDD00D87580 /* OpenSSL in Frameworks */,
|
||||
5C1794CD25E90DBD007AD91A /* KeychainAccess in Frameworks */,
|
||||
5C2D9A3225F75A760053CB9F /* Sdk in Frameworks */,
|
||||
5C42E2A225EE656E0048DDCD /* SwiftyJSON in Frameworks */,
|
||||
5C89C90625EA7996000B5816 /* SwiftUIEKtensions in Frameworks */,
|
||||
5C0B2AFD25F78A6A009EABEC /* KeychainAccess in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -151,12 +163,13 @@
|
|||
5C1B848925E1B6910074F29D /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5CB9907025EE4A2400AA405C /* Shared */,
|
||||
5CC80E9625F2CA8A00F6DE60 /* AccountManager */,
|
||||
5CB9906F25EE4A1C00AA405C /* Onboarding */,
|
||||
5CC2EAAC25E5269E00B6183E /* Navigation */,
|
||||
5CC2EAA325E516DD00B6183E /* Content */,
|
||||
5C1B849F25E1B7A30074F29D /* Login */,
|
||||
5C1CFA7925EA32AE0047286F /* ghImage.swift */,
|
||||
5C0ED1E2260D2704000DE4C6 /* PullToRefresh.swift */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
|
@ -172,6 +185,7 @@
|
|||
5C1B849F25E1B7A30074F29D /* Login */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5CF6695E25EEE2FD00AC0A86 /* chooseStudent.swift */,
|
||||
F4C6D9092544E17400F8903A /* LoginView.swift */,
|
||||
);
|
||||
path = Login;
|
||||
|
@ -188,32 +202,24 @@
|
|||
5CB9906F25EE4A1C00AA405C /* Onboarding */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5CB9907525EE4A3B00AA405C /* OnboardingView.swift */,
|
||||
5CCB276225EF9C4A00482F4A /* OnboardingView.swift */,
|
||||
);
|
||||
path = Onboarding;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5CB9907025EE4A2400AA405C /* Shared */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5CB9907125EE4A3200AA405C /* CustomButtonView.swift */,
|
||||
);
|
||||
path = Shared;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5CC2EAA325E516DD00B6183E /* Content */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5CC2EAA425E516F100B6183E /* dashboard.swift */,
|
||||
5C2D330F25E64F3C000253AC /* grades.swift */,
|
||||
5C2D331325E650EC000253AC /* exams.swift */,
|
||||
5C2D331725E651C4000253AC /* homework.swift */,
|
||||
5C2D331B25E651FB000253AC /* more.swift */,
|
||||
5C2D331325E650EC000253AC /* calendar.swift */,
|
||||
5C1794B325E8FDFB007AD91A /* messages.swift */,
|
||||
5C1794B725E8FE08007AD91A /* notes.swift */,
|
||||
5C1794BB25E8FE19007AD91A /* settings.swift */,
|
||||
5C1794BF25E8FE27007AD91A /* about.swift */,
|
||||
5C89C8F425EA6AA4000B5816 /* licenses.swift */,
|
||||
5C5162D725F0DCDE00EF0777 /* more.swift */,
|
||||
5C5162DB25F0DD9200EF0777 /* attendance.swift */,
|
||||
);
|
||||
path = Content;
|
||||
sourceTree = "<group>";
|
||||
|
@ -226,6 +232,19 @@
|
|||
path = Navigation;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5CC80E9625F2CA8A00F6DE60 /* AccountManager */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5CF095AC25F053B10068F2C6 /* accountManager.swift */,
|
||||
5CC80E9725F2CAA900F6DE60 /* accountCard.swift */,
|
||||
5C84E04525FAC5440088FD47 /* personalInfo.swift */,
|
||||
5C84E04925FAC5520088FD47 /* residenceInfo.swift */,
|
||||
5C84E04D25FAC5670088FD47 /* contact.swift */,
|
||||
5C84E05125FAC5700088FD47 /* family.swift */,
|
||||
);
|
||||
path = AccountManager;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F4C6D8FB2544E17300F8903A = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -308,10 +327,11 @@
|
|||
);
|
||||
name = wulkanowy;
|
||||
packageProductDependencies = (
|
||||
5C9B6F4825D6C08D00C3F5F5 /* Sdk */,
|
||||
5CCAE31525DA4CDD00D87580 /* OpenSSL */,
|
||||
5C1794CC25E90DBD007AD91A /* KeychainAccess */,
|
||||
5C89C90525EA7996000B5816 /* SwiftUIEKtensions */,
|
||||
5C42E2A125EE656E0048DDCD /* SwiftyJSON */,
|
||||
5C2D9A3125F75A760053CB9F /* Sdk */,
|
||||
5C0B2AFC25F78A6A009EABEC /* KeychainAccess */,
|
||||
);
|
||||
productName = wulkanowy;
|
||||
productReference = F4C6D9042544E17400F8903A /* wulkanowy.app */;
|
||||
|
@ -387,8 +407,9 @@
|
|||
mainGroup = F4C6D8FB2544E17300F8903A;
|
||||
packageReferences = (
|
||||
5CCAE31025DA4CCA00D87580 /* XCRemoteSwiftPackageReference "OpenSSL" */,
|
||||
5C1794CB25E90DBD007AD91A /* XCRemoteSwiftPackageReference "KeychainAccess" */,
|
||||
5C89C90425EA7996000B5816 /* XCRemoteSwiftPackageReference "SwiftUIEKtensions" */,
|
||||
5C42E2A025EE656E0048DDCD /* XCRemoteSwiftPackageReference "SwiftyJSON" */,
|
||||
5C0B2AFB25F78A6A009EABEC /* XCRemoteSwiftPackageReference "KeychainAccess" */,
|
||||
);
|
||||
productRefGroup = F4C6D9052544E17400F8903A /* Products */;
|
||||
projectDirPath = "";
|
||||
|
@ -434,23 +455,30 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5C2D331425E650EC000253AC /* exams.swift in Sources */,
|
||||
5C2D331425E650EC000253AC /* calendar.swift in Sources */,
|
||||
5C478F3525DC742100ABEFB7 /* VulcanStore.swift in Sources */,
|
||||
5C1CFA7A25EA32AE0047286F /* ghImage.swift in Sources */,
|
||||
5CB9907225EE4A3200AA405C /* CustomButtonView.swift in Sources */,
|
||||
5CCB276325EF9C4A00482F4A /* OnboardingView.swift in Sources */,
|
||||
5C1794BC25E8FE19007AD91A /* settings.swift in Sources */,
|
||||
5C2D331025E64F3C000253AC /* grades.swift in Sources */,
|
||||
5C2D331C25E651FB000253AC /* more.swift in Sources */,
|
||||
5CF6695F25EEE2FD00AC0A86 /* chooseStudent.swift in Sources */,
|
||||
5C1794C025E8FE27007AD91A /* about.swift in Sources */,
|
||||
F4C6D90A2544E17400F8903A /* LoginView.swift in Sources */,
|
||||
5C89C8F525EA6AA4000B5816 /* licenses.swift in Sources */,
|
||||
5C84E04A25FAC5520088FD47 /* residenceInfo.swift in Sources */,
|
||||
5C84E05225FAC5700088FD47 /* family.swift in Sources */,
|
||||
5CC2EAAE25E526B500B6183E /* navigation.swift in Sources */,
|
||||
5C2D331825E651C4000253AC /* homework.swift in Sources */,
|
||||
5C0ED1E3260D2704000DE4C6 /* PullToRefresh.swift in Sources */,
|
||||
5C5162D825F0DCDE00EF0777 /* more.swift in Sources */,
|
||||
5CF095AD25F053B10068F2C6 /* accountManager.swift in Sources */,
|
||||
5C84E04E25FAC5670088FD47 /* contact.swift in Sources */,
|
||||
5C84E04625FAC5440088FD47 /* personalInfo.swift in Sources */,
|
||||
5C1794B425E8FDFB007AD91A /* messages.swift in Sources */,
|
||||
5CC80E9825F2CAA900F6DE60 /* accountCard.swift in Sources */,
|
||||
5CC2EAA525E516F100B6183E /* dashboard.swift in Sources */,
|
||||
5C1794B825E8FE08007AD91A /* notes.swift in Sources */,
|
||||
5CB9907625EE4A3B00AA405C /* OnboardingView.swift in Sources */,
|
||||
F4C6D9082544E17400F8903A /* wulkanowyApp.swift in Sources */,
|
||||
5C5162DC25F0DD9200EF0777 /* attendance.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -536,6 +564,10 @@
|
|||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(SRCROOT)",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
|
@ -598,6 +630,10 @@
|
|||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(SRCROOT)",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
|
@ -633,6 +669,7 @@
|
|||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "io.wulkanowy.wulkanowy-ios";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
|
@ -655,6 +692,7 @@
|
|||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "io.wulkanowy.wulkanowy-ios";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
|
@ -782,12 +820,20 @@
|
|||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCRemoteSwiftPackageReference section */
|
||||
5C1794CB25E90DBD007AD91A /* XCRemoteSwiftPackageReference "KeychainAccess" */ = {
|
||||
5C0B2AFB25F78A6A009EABEC /* XCRemoteSwiftPackageReference "KeychainAccess" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/kishikawakatsumi/KeychainAccess";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 4.2.1;
|
||||
minimumVersion = 4.2.2;
|
||||
};
|
||||
};
|
||||
5C42E2A025EE656E0048DDCD /* XCRemoteSwiftPackageReference "SwiftyJSON" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/SwiftyJSON/SwiftyJSON";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 5.0.0;
|
||||
};
|
||||
};
|
||||
5C89C90425EA7996000B5816 /* XCRemoteSwiftPackageReference "SwiftUIEKtensions" */ = {
|
||||
|
@ -809,20 +855,25 @@
|
|||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
5C1794CC25E90DBD007AD91A /* KeychainAccess */ = {
|
||||
5C0B2AFC25F78A6A009EABEC /* KeychainAccess */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 5C1794CB25E90DBD007AD91A /* XCRemoteSwiftPackageReference "KeychainAccess" */;
|
||||
package = 5C0B2AFB25F78A6A009EABEC /* XCRemoteSwiftPackageReference "KeychainAccess" */;
|
||||
productName = KeychainAccess;
|
||||
};
|
||||
5C2D9A3125F75A760053CB9F /* Sdk */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = Sdk;
|
||||
};
|
||||
5C42E2A125EE656E0048DDCD /* SwiftyJSON */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 5C42E2A025EE656E0048DDCD /* XCRemoteSwiftPackageReference "SwiftyJSON" */;
|
||||
productName = SwiftyJSON;
|
||||
};
|
||||
5C89C90525EA7996000B5816 /* SwiftUIEKtensions */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 5C89C90425EA7996000B5816 /* XCRemoteSwiftPackageReference "SwiftUIEKtensions" */;
|
||||
productName = SwiftUIEKtensions;
|
||||
};
|
||||
5C9B6F4825D6C08D00C3F5F5 /* Sdk */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = Sdk;
|
||||
};
|
||||
5CCAE31525DA4CDD00D87580 /* OpenSSL */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 5CCAE31025DA4CCA00D87580 /* XCRemoteSwiftPackageReference "OpenSSL" */;
|
||||
|
|
|
@ -28,6 +28,26 @@
|
|||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "F4C6D9142544E17500F8903A"
|
||||
BuildableName = "wulkanowyTests.xctest"
|
||||
BlueprintName = "wulkanowyTests"
|
||||
ReferencedContainer = "container:wulkanowy.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "F4C6D91F2544E17500F8903A"
|
||||
BuildableName = "wulkanowyUITests.xctest"
|
||||
BlueprintName = "wulkanowyUITests"
|
||||
ReferencedContainer = "container:wulkanowy.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
|
|
|
@ -8,12 +8,48 @@
|
|||
import SwiftUI
|
||||
import Sdk
|
||||
import Combine
|
||||
import SwiftyJSON
|
||||
import KeychainAccess
|
||||
|
||||
@main
|
||||
struct wulkanowyApp: App {
|
||||
@AppStorage("isLogged") private var isLogged: Bool = false
|
||||
@AppStorage("needsAppOnboarding") private var needsAppOnboarding: Bool = true
|
||||
|
||||
init() {
|
||||
if(isLogged == true) {
|
||||
let keychain = Keychain()
|
||||
let actualStudentId = "\(keychain["actualStudentId"] ?? "0")"
|
||||
let accountString = keychain[actualStudentId]
|
||||
let data: Data = Data(accountString!.utf8)
|
||||
let account = try! JSON(data: data)
|
||||
|
||||
let endpointURL: String = "\(account["account"]["RestURL"])api/mobile/register/hebe"
|
||||
|
||||
let apiResponseRequest = apiRequest(endpointURL: endpointURL, id: actualStudentId)
|
||||
let session = URLSession.shared
|
||||
session.dataTask(with: apiResponseRequest) { (data, response, error) in
|
||||
if let error = error {
|
||||
// Handle HTTP request error
|
||||
print(error)
|
||||
} else if let data = data {
|
||||
// Handle HTTP request response
|
||||
let responseBody = String(data: data, encoding: String.Encoding.utf8)
|
||||
keychain["actualStudentHebe"] = "\(responseBody!)"
|
||||
} else {
|
||||
// Handle unexpected error
|
||||
}
|
||||
}.resume()
|
||||
}
|
||||
}
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
NavigationBarView()
|
||||
if(needsAppOnboarding == true) {
|
||||
OnboardingView()
|
||||
} else {
|
||||
NavigationBarView()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0x2E",
|
||||
"green" : "0x2E",
|
||||
"red" : "0xD2"
|
||||
"blue" : "0.180",
|
||||
"green" : "0.180",
|
||||
"red" : "0.824"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
|
@ -5,9 +5,9 @@
|
|||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0x2E",
|
||||
"green" : "0x2E",
|
||||
"red" : "0xD2"
|
||||
"blue" : "0.180",
|
||||
"green" : "0.180",
|
||||
"red" : "0.824"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
|
@ -23,9 +23,9 @@
|
|||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0x2E",
|
||||
"green" : "0x2E",
|
||||
"red" : "0xD2"
|
||||
"blue" : "0.180",
|
||||
"green" : "0.180",
|
||||
"red" : "0.824"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"compression-type" : "automatic"
|
||||
}
|
||||
}
|
|
@ -6,6 +6,19 @@
|
|||
|
||||
*/
|
||||
|
||||
//ONBOARDING
|
||||
"onboardingTitle" = "Welcome to Wulkanowy!";
|
||||
|
||||
"notificationsOnboarding" = "Notifications";
|
||||
"messagesOnboarding" = "Messages";
|
||||
"fast" = "Fast";
|
||||
|
||||
"notificationsOnboardingContent" = "Forget about saving exams in calendar";
|
||||
"messagesOnboardingContent" = "Simple contact with your favorite teachers";
|
||||
"fastContent" = "Fast as Sonic";
|
||||
|
||||
"continueButton" = "Let's go!";
|
||||
|
||||
//LOGIN SCREEN
|
||||
"loginTitle" = "Log In";
|
||||
"token" = "Token";
|
||||
|
@ -18,12 +31,18 @@
|
|||
"wrongPin" = "Wrong pin";
|
||||
"invalidData" = "Wrong token, symbol or pin";
|
||||
"success" = "Success";
|
||||
"accountRegistered" = "Account registered";
|
||||
"accountRegisteredContent" = "The account has already registered. Please log in to another account.";
|
||||
|
||||
//CHOOSE ACCOUNT
|
||||
"registerButton" = "Register";
|
||||
"selectStudent" = "Select student";
|
||||
|
||||
//NAVIGATION
|
||||
"dashboardButton" = "Dashboard";
|
||||
"gradesButton" = "Grades";
|
||||
"examsButton" = "Exams";
|
||||
"homeworkButton" = "Homework";
|
||||
"calendarButton" = "Calendar";
|
||||
"attendanceButton" = "Attendance";
|
||||
"moreButton" = "More";
|
||||
|
||||
//MORE
|
||||
|
@ -45,3 +64,7 @@
|
|||
|
||||
//LICENCES
|
||||
"noLicence" = "No licence";
|
||||
|
||||
//ACCOUNT MANAGER
|
||||
"addAccount" = "Add account";
|
||||
"chooseAccount" = "Choose account";
|
||||
|
|
|
@ -6,6 +6,19 @@
|
|||
|
||||
*/
|
||||
|
||||
//ONBOARDING
|
||||
"onboardingTitle" = "Witaj w Wulkanowym!";
|
||||
|
||||
"notificationsOnboarding" = "Powiadomienia";
|
||||
"messagesOnboarding" = "Wiadomości";
|
||||
"fast" = "Prędkość";
|
||||
|
||||
"notificationsOnboardingContent" = "Zapomnij o zapisywaniu sprawdzianów w kalendarzyku";
|
||||
"messagesOnboardingContent" = "Prosty kontakt z twoimi ulubionymi nauczycielami";
|
||||
"fastContent" = "Szybki, niczym Sonic";
|
||||
|
||||
"continueButton" = "Zaczynajmy!";
|
||||
|
||||
//LOGIN SCREEN
|
||||
"loginTitle" = "Logowanie";
|
||||
"token" = "Token";
|
||||
|
@ -18,12 +31,18 @@
|
|||
"wrongPin" = "Zły pin";
|
||||
"invalidData" = "Zły token, symbol lub pin";
|
||||
"success" = "Sukces";
|
||||
"accountRegistered" = "Konto zarejestrowane";
|
||||
"accountRegisteredContent" = "Konto zostało już zarejestrowane. Proszę zalogowaź się na inne konto.";
|
||||
|
||||
//CHOOSE ACCOUNT
|
||||
"registerButton" = "Zarejestruj";
|
||||
"selectStudent" = "Wybierz ucznia";
|
||||
|
||||
//NAVIGATION
|
||||
"dashboardButton" = "Start";
|
||||
"gradesButton" = "Oceny";
|
||||
"examsButton" = "Sprawdziany";
|
||||
"homeworkButton" = "Zadania";
|
||||
"calendarButton" = "Kalendarz";
|
||||
"attendanceButton" = "Frekwencja";
|
||||
"moreButton" = "Więcej";
|
||||
|
||||
//MORE
|
||||
|
@ -45,3 +64,7 @@
|
|||
|
||||
//LICENCES
|
||||
"noLicence" = "Brak licencji";
|
||||
|
||||
//ACCOUNT MANAGER
|
||||
"addAccount" = "Dodaj konto";
|
||||
"chooseAccount" = "Wybierz konto";
|
||||
|
|
227
wulkanowy/Views/AccountManager/accountCard.swift
Normal file
227
wulkanowy/Views/AccountManager/accountCard.swift
Normal file
|
@ -0,0 +1,227 @@
|
|||
//
|
||||
// accountCard.swift
|
||||
// wulkanowy
|
||||
//
|
||||
// Created by Tomasz on 05/03/2021.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import KeychainAccess
|
||||
import SwiftyJSON
|
||||
import Sdk
|
||||
|
||||
struct AccountCardView: View {
|
||||
@Environment(\.presentationMode) var presentation
|
||||
@State private var account: JSON = []
|
||||
@State private var username: String = ""
|
||||
@State private var showAlert = false
|
||||
@State private var hebe: JSON = []
|
||||
@State private var displayStudents: Array<String> = Array()
|
||||
@State private var selectedStudent: String = ""
|
||||
@State private var studentSchool = ""
|
||||
|
||||
let id: String
|
||||
let keychain = Keychain()
|
||||
|
||||
private func saveNewUsername(newUsername: String) {
|
||||
var accountJSON = self.account
|
||||
accountJSON["customUsername"].stringValue = "\(newUsername)"
|
||||
keychain[self.id] = "\(accountJSON)"
|
||||
getAccount()
|
||||
getUsername()
|
||||
}
|
||||
|
||||
private func alert() {
|
||||
let alert = UIAlertController(title: "Zmiana nazwy", message: "Tu wpisz swoją nową nazwę konta", preferredStyle: .alert)
|
||||
alert.addTextField() { textField in
|
||||
textField.placeholder = username
|
||||
}
|
||||
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in })
|
||||
alert.addAction(UIAlertAction(title: "Save", style: .default) { _ in let textField = alert.textFields![0]
|
||||
let newUsername = "\(textField.text ?? "\(username)")"
|
||||
saveNewUsername(newUsername: newUsername)})
|
||||
showAlert(alert: alert)
|
||||
}
|
||||
|
||||
func showAlert(alert: UIAlertController) {
|
||||
if let controller = topMostViewController() {
|
||||
controller.present(alert, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
private func keyWindow() -> UIWindow? {
|
||||
return UIApplication.shared.connectedScenes
|
||||
.filter {$0.activationState == .foregroundActive}
|
||||
.compactMap {$0 as? UIWindowScene}
|
||||
.first?.windows.filter {$0.isKeyWindow}.first
|
||||
}
|
||||
|
||||
private func topMostViewController() -> UIViewController? {
|
||||
guard let rootController = keyWindow()?.rootViewController else {
|
||||
return nil
|
||||
}
|
||||
return topMostViewController(for: rootController)
|
||||
}
|
||||
|
||||
private func topMostViewController(for controller: UIViewController) -> UIViewController {
|
||||
if let presentedController = controller.presentedViewController {
|
||||
return topMostViewController(for: presentedController)
|
||||
} else if let navigationController = controller as? UINavigationController {
|
||||
guard let topController = navigationController.topViewController else {
|
||||
return navigationController
|
||||
}
|
||||
return topMostViewController(for: topController)
|
||||
} else if let tabController = controller as? UITabBarController {
|
||||
guard let topController = tabController.selectedViewController else {
|
||||
return tabController
|
||||
}
|
||||
return topMostViewController(for: topController)
|
||||
}
|
||||
return controller
|
||||
}
|
||||
|
||||
init() {
|
||||
self.id = keychain["editAccountId"] ?? "0"
|
||||
}
|
||||
|
||||
private func getActualStudentName() -> String {
|
||||
let account = keychain[self.id] ?? "0"
|
||||
let data: Data = Data(account.utf8)
|
||||
let accountJSON = try! JSON(data: data)
|
||||
let actualStudentId = Int("\(accountJSON["actualStudent"])") ?? 0
|
||||
|
||||
return "\(hebe["Envelope"][actualStudentId]["Login"]["DisplayName"])"
|
||||
}
|
||||
|
||||
private func getStudents() -> Array<String> {
|
||||
var i: Int = 0
|
||||
var displayStudentsFunc: Array<String> = Array()
|
||||
while true {
|
||||
if (String(describing: hebe["Envelope"][i]) == "null") {
|
||||
break
|
||||
}
|
||||
else {
|
||||
displayStudentsFunc.append(String(describing: hebe["Envelope"][i]["Login"]["DisplayName"]))
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
return displayStudentsFunc
|
||||
}
|
||||
|
||||
private func getAccount() {
|
||||
let account = "\(keychain[self.id] ?? "{}")"
|
||||
let data: Data = Data(account.utf8)
|
||||
self.account = try! JSON(data: data)
|
||||
}
|
||||
|
||||
private func getUsername() {
|
||||
if("\(account["customUsername"])".isEmpty) {
|
||||
username = "\(account["account"]["UserName"])"
|
||||
} else {
|
||||
username = "\(account["customUsername"])"
|
||||
}
|
||||
}
|
||||
|
||||
private func getSchoolName() -> String {
|
||||
let actualStudent = Int("\(account["actualStudent"])") ?? 0
|
||||
return "\(hebe["Envelope"][actualStudent]["Unit"]["DisplayName"])"
|
||||
}
|
||||
|
||||
private func done() {
|
||||
presentation.wrappedValue.dismiss()
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
VStack {
|
||||
HStack {
|
||||
Spacer()
|
||||
let pencilSymbol = Image(systemName: "pencil")
|
||||
Button("\(pencilSymbol)") { alert() }
|
||||
.font(.system(size: 25))
|
||||
.padding()
|
||||
.multilineTextAlignment(.trailing)
|
||||
}
|
||||
Spacer()
|
||||
Image(systemName: "person.circle")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(height: 92)
|
||||
.foregroundColor(.accentColor)
|
||||
.padding(.bottom)
|
||||
Text("\(username)")
|
||||
.font(.title)
|
||||
Spacer()
|
||||
Text(self.studentSchool)
|
||||
.fontWeight(.light)
|
||||
|
||||
|
||||
Form {
|
||||
Section(header: Text("Aktualny uczeń")) {
|
||||
HStack {
|
||||
Text("\(selectedStudent)")
|
||||
Spacer()
|
||||
Picker(selection: $selectedStudent, label: Image(systemName:"pencil")) {
|
||||
ForEach(displayStudents, id: \.self) { student in
|
||||
Text(student)
|
||||
}
|
||||
}.pickerStyle(MenuPickerStyle())
|
||||
}
|
||||
}
|
||||
|
||||
Section {
|
||||
NavigationLink(destination: PersonalInfoView()) {
|
||||
Label("Dane osobowe", systemImage: "person")
|
||||
.accessibility(label: Text("Dane osobowe"))
|
||||
}
|
||||
NavigationLink(destination: ResidenceInfoView()) {
|
||||
Label("Dane adresowe", systemImage: "house")
|
||||
.accessibility(label: Text("Dane adresowe"))
|
||||
}
|
||||
NavigationLink(destination: ContactView()) {
|
||||
Label("Kontakt", systemImage: "phone")
|
||||
.accessibility(label: Text("Kontakt"))
|
||||
}
|
||||
NavigationLink(destination: FamilyView()) {
|
||||
Label("Rodzina", systemImage: "person.2")
|
||||
.accessibility(label: Text("Rodzina"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer()
|
||||
Button("Done") { done() }
|
||||
.font(.headline)
|
||||
.multilineTextAlignment(.center)
|
||||
.padding()
|
||||
.frame(height: 55)
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(Color.accentColor.opacity(0.1))
|
||||
.cornerRadius(12)
|
||||
}.padding()
|
||||
.onAppear {
|
||||
getAccount()
|
||||
getUsername()
|
||||
self.hebe = getHebe(id: self.id, account: self.account)
|
||||
self.displayStudents = getStudents()
|
||||
self.studentSchool = getSchoolName()
|
||||
self.selectedStudent = getActualStudentName()
|
||||
}
|
||||
.navigationBarTitle("")
|
||||
.navigationBarHidden(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct AccountCardView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
AccountCardView()
|
||||
}
|
||||
.preferredColorScheme(.dark)
|
||||
}
|
||||
}
|
||||
|
198
wulkanowy/Views/AccountManager/accountManager.swift
Normal file
198
wulkanowy/Views/AccountManager/accountManager.swift
Normal file
|
@ -0,0 +1,198 @@
|
|||
//
|
||||
// accountManager.swift
|
||||
// wulkanowy
|
||||
//
|
||||
// Created by Tomasz on 04/03/2021.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import KeychainAccess
|
||||
import SwiftyJSON
|
||||
import Sdk
|
||||
|
||||
struct AccountManagerView: View {
|
||||
@State private var showLoginModal = false
|
||||
@State private var showEditAccountModal = false
|
||||
@AppStorage("isLogged") private var isLogged: Bool = false
|
||||
@State private var accounts: [String] = [""]
|
||||
@State private var actualId: String = "0"
|
||||
@State private var showingDeleteAlert = false
|
||||
@State private var deletingAccount = "0"
|
||||
|
||||
private func getStudentsNames() -> [String] {
|
||||
//getting all accounts
|
||||
let keychain = Keychain()
|
||||
let allAccounts: String! = keychain["allAccounts"] ?? "[]"
|
||||
|
||||
//parsing allAccounts to array
|
||||
var allAccountsArray: [String] = []
|
||||
print(allAccountsArray)
|
||||
if(allAccounts != "[]"){
|
||||
let data = Data(allAccounts.utf8)
|
||||
do {
|
||||
let ids = try JSONSerialization.jsonObject(with: data) as! [Int]
|
||||
for id in ids {
|
||||
allAccountsArray.append("\(id)")
|
||||
}
|
||||
} catch {
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
|
||||
return allAccountsArray
|
||||
}
|
||||
|
||||
private func addAccount() {
|
||||
self.showLoginModal = true
|
||||
}
|
||||
|
||||
private func openEditAccount(id: String) {
|
||||
let keychain = Keychain()
|
||||
keychain["editAccountId"] = id
|
||||
self.showEditAccountModal = true
|
||||
}
|
||||
|
||||
private func getJsonFromString(body: String) -> JSON {
|
||||
let data = Data(body.utf8)
|
||||
|
||||
let json = try! JSON(data: data)
|
||||
return json
|
||||
}
|
||||
|
||||
private func setActualAccount(id: String) {
|
||||
let keychain = Keychain()
|
||||
let accountData = keychain["\(id)"] ?? "{}"
|
||||
let data: Data = Data(accountData.utf8)
|
||||
let accountJSON = try! JSON(data: data)
|
||||
let RestURL = "\(accountJSON["account"]["RestURL"])api/mobile/register/hebe"
|
||||
keychain["actualAccountId"] = "\(id)"
|
||||
self.actualId = "\(id)"
|
||||
keychain["actualAccountEmail"] = "\(accountJSON["account"]["UserName"])"
|
||||
|
||||
let apiResponseRequest = apiRequest(endpointURL: "\(RestURL)", id: id)
|
||||
let session = URLSession.shared
|
||||
session.dataTask(with: apiResponseRequest) { (data, response, error) in
|
||||
if let error = error {
|
||||
// Handle HTTP request error
|
||||
print(error)
|
||||
} else if let data = data {
|
||||
// Handle HTTP request response
|
||||
let responseBody = String(data: data, encoding: String.Encoding.utf8)
|
||||
|
||||
keychain["actualStudentHebe"] = "\(responseBody!)"
|
||||
|
||||
} else {
|
||||
// Handle unexpected error
|
||||
}
|
||||
}.resume()
|
||||
|
||||
accounts = getStudentsNames()
|
||||
}
|
||||
|
||||
private func deleteAccount() {
|
||||
let keychain = Keychain()
|
||||
var ids = getStudentsNames()
|
||||
let id: Set<String> = [deletingAccount]
|
||||
ids.removeAll(where: { id.contains($0) })
|
||||
if(ids == []) {
|
||||
isLogged = false
|
||||
}
|
||||
keychain["allAccounts"] = "\(ids)"
|
||||
|
||||
keychain["\(deletingAccount)"] = nil
|
||||
}
|
||||
|
||||
private func getUsername(student: JSON) -> String {
|
||||
if("\(student["customUsername"])".isEmpty) {
|
||||
return "\(student["account"]["UserName"])"
|
||||
} else {
|
||||
return "\(student["customUsername"])"
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
if(isLogged == true) {
|
||||
VStack {
|
||||
Form {
|
||||
Section(header: Text("chooseAccount")
|
||||
.font(.title)) {
|
||||
ForEach(accounts, id: \.self) { student in
|
||||
let keychain = Keychain()
|
||||
HStack {
|
||||
let studentString = "\(keychain[student] ?? "{}")"
|
||||
let data: Data = Data(studentString.utf8)
|
||||
let studentJSON = try! JSON(data: data)
|
||||
let studentEmail = getUsername(student: studentJSON)
|
||||
|
||||
Button("\(studentEmail)") { setActualAccount(id: student) }
|
||||
.foregroundColor(Color("customControlColor"))
|
||||
.aspectRatio(contentMode: .fit)
|
||||
if("\(actualId)" == "\(student)") {
|
||||
Image(systemName: "checkmark.circle")
|
||||
.foregroundColor(.green)
|
||||
}
|
||||
Spacer()
|
||||
let cardImage = Image(uiImage: UIImage(systemName: "ellipsis")!)
|
||||
.renderingMode(.template)
|
||||
|
||||
Button("\(cardImage)") { openEditAccount(id: student) }
|
||||
.foregroundColor(Color("customControlColor"))
|
||||
.padding(.horizontal)
|
||||
.sheet(isPresented: $showEditAccountModal, onDismiss: {
|
||||
}) {
|
||||
AccountCardView()
|
||||
}
|
||||
|
||||
let trashImage = Image(uiImage: UIImage(systemName: "trash")!)
|
||||
.renderingMode(.template)
|
||||
|
||||
Button("\(trashImage)") {
|
||||
showingDeleteAlert = true
|
||||
deletingAccount = student
|
||||
}
|
||||
}.buttonStyle(BorderlessButtonStyle())
|
||||
}
|
||||
}
|
||||
}
|
||||
}.onAppear {
|
||||
let keychain = Keychain()
|
||||
self.accounts = getStudentsNames()
|
||||
self.actualId = "\(keychain["actualAccountId"] ?? "0")"
|
||||
}
|
||||
.alert(isPresented: $showingDeleteAlert) {
|
||||
Alert(title: Text("Do you want to delete this account?"),
|
||||
message: Text("You cannot undo this action"),
|
||||
primaryButton: .destructive(Text("Delete"), action: deleteAccount),
|
||||
secondaryButton: .cancel(Text("Cancel")))
|
||||
}
|
||||
} else {
|
||||
Spacer()
|
||||
Text("No accounts added")
|
||||
}
|
||||
Spacer()
|
||||
Button("addAccount") {addAccount()}
|
||||
.font(.headline)
|
||||
.multilineTextAlignment(.center)
|
||||
.padding(.horizontal)
|
||||
.frame(height: 55)
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(Color.accentColor.opacity(0.1))
|
||||
.cornerRadius(12)
|
||||
.buttonStyle(BorderlessButtonStyle())
|
||||
.padding()
|
||||
.sheet(isPresented: $showLoginModal, onDismiss: {
|
||||
}) {
|
||||
LoginView()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct AccountManagerView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
AccountManagerView()
|
||||
}
|
||||
.preferredColorScheme(.dark)
|
||||
}
|
||||
}
|
28
wulkanowy/Views/AccountManager/contact.swift
Normal file
28
wulkanowy/Views/AccountManager/contact.swift
Normal file
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// contact.swift
|
||||
// wulkanowy
|
||||
//
|
||||
// Created by Tomasz on 11/03/2021.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import KeychainAccess
|
||||
import Sdk
|
||||
|
||||
struct ContactView: View {
|
||||
var body: some View {
|
||||
Text("Here is contact view (in my imagination)")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct ContactView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
ContactView()
|
||||
}
|
||||
.preferredColorScheme(.dark)
|
||||
}
|
||||
}
|
||||
|
29
wulkanowy/Views/AccountManager/family.swift
Normal file
29
wulkanowy/Views/AccountManager/family.swift
Normal file
|
@ -0,0 +1,29 @@
|
|||
//
|
||||
// family.swift
|
||||
// wulkanowy
|
||||
//
|
||||
// Created by Tomasz on 11/03/2021.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import KeychainAccess
|
||||
import Sdk
|
||||
|
||||
struct FamilyView: View {
|
||||
var body: some View {
|
||||
Text("Here is family info (in my imagination)")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct FamilyView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
FamilyView()
|
||||
}
|
||||
.preferredColorScheme(.dark)
|
||||
}
|
||||
}
|
||||
|
||||
|
29
wulkanowy/Views/AccountManager/personalInfo.swift
Normal file
29
wulkanowy/Views/AccountManager/personalInfo.swift
Normal file
|
@ -0,0 +1,29 @@
|
|||
//
|
||||
// personalInfo.swift
|
||||
// wulkanowy
|
||||
//
|
||||
// Created by Tomasz on 11/03/2021.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import KeychainAccess
|
||||
import Sdk
|
||||
import SwiftyJSON
|
||||
|
||||
struct PersonalInfoView: View {
|
||||
var body: some View {
|
||||
Text("Here is personal info (in my imagination)")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct PersonalInfoView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
PersonalInfoView()
|
||||
}
|
||||
.preferredColorScheme(.dark)
|
||||
}
|
||||
}
|
||||
|
28
wulkanowy/Views/AccountManager/residenceInfo.swift
Normal file
28
wulkanowy/Views/AccountManager/residenceInfo.swift
Normal file
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// residenceInfo.swift
|
||||
// wulkanowy
|
||||
//
|
||||
// Created by Tomasz on 11/03/2021.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import KeychainAccess
|
||||
import Sdk
|
||||
|
||||
struct ResidenceInfoView: View {
|
||||
var body: some View {
|
||||
Text("Here is residence details (in my imagination)")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct ResidenceInfoView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
ResidenceInfoView()
|
||||
}
|
||||
.preferredColorScheme(.dark)
|
||||
}
|
||||
}
|
||||
|
47
wulkanowy/Views/Content/attendance.swift
Normal file
47
wulkanowy/Views/Content/attendance.swift
Normal file
|
@ -0,0 +1,47 @@
|
|||
//
|
||||
// attendance.swift
|
||||
// wulkanowy
|
||||
//
|
||||
// Created by Tomasz on 04/03/2021.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct AttendanceView: View {
|
||||
@State private var showModal = false
|
||||
@AppStorage("isLogged") private var isLogged: Bool = false
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
if(isLogged == false){
|
||||
VStack {
|
||||
Text("You are not logged in")
|
||||
Button("Log in") {self.showModal = true}
|
||||
.sheet(isPresented: $showModal, onDismiss: {
|
||||
print(self.showModal)
|
||||
}) {
|
||||
LoginView()
|
||||
}
|
||||
}.padding()
|
||||
} else {
|
||||
ScrollView {
|
||||
PullToRefresh(coordinateSpaceName: "pullToRefresh") {
|
||||
print("Refreshing..")
|
||||
}
|
||||
Text("Here is attendance (in my imagination)")
|
||||
}.coordinateSpace(name: "pullToRefresh")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct AttendanceView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
AttendanceView()
|
||||
}
|
||||
.preferredColorScheme(.dark)
|
||||
}
|
||||
}
|
47
wulkanowy/Views/Content/calendar.swift
Normal file
47
wulkanowy/Views/Content/calendar.swift
Normal file
|
@ -0,0 +1,47 @@
|
|||
//
|
||||
// attendance.swift
|
||||
// wulkanowy
|
||||
//
|
||||
// Created by Tomasz on 24/02/2021.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import KeychainAccess
|
||||
import Sdk
|
||||
|
||||
struct CalendarView: View {
|
||||
@State private var showModal = false
|
||||
@AppStorage("isLogged") private var isLogged: Bool = false
|
||||
|
||||
var body: some View {
|
||||
if(isLogged == false){
|
||||
VStack {
|
||||
Text("You are not logged in")
|
||||
Button("Log in") {self.showModal = true}
|
||||
.sheet(isPresented: $showModal, onDismiss: {
|
||||
print(self.showModal)
|
||||
}) {
|
||||
LoginView()
|
||||
}
|
||||
}.padding()
|
||||
} else {
|
||||
ScrollView {
|
||||
PullToRefresh(coordinateSpaceName: "pullToRefresh") {
|
||||
print("Refreshing..")
|
||||
}
|
||||
Text("Here is calendar (in my imagination)")
|
||||
}.coordinateSpace(name: "pullToRefresh")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct CalendarView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
CalendarView()
|
||||
}
|
||||
.preferredColorScheme(.dark)
|
||||
}
|
||||
}
|
|
@ -10,23 +10,36 @@ import KeychainAccess
|
|||
import Sdk
|
||||
|
||||
struct DashboardView: View {
|
||||
@State private var showModal = false
|
||||
@AppStorage("isLogged") private var isLogged: Bool = false
|
||||
|
||||
init() {
|
||||
let keychain = Keychain()
|
||||
let key = keychain["privateKey"]
|
||||
|
||||
let luckyNumber = getLuckyNumber()
|
||||
print(luckyNumber)
|
||||
if(isLogged == true){
|
||||
let luckyNumber = getLuckyNumber()
|
||||
|
||||
print(luckyNumber)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
if(isLogged == false){
|
||||
VStack {
|
||||
Text("You are not logged in (dashboard)")
|
||||
NavigationLink(destination: LoginView()) {
|
||||
Text("Log in")
|
||||
}
|
||||
Text("You are not logged in")
|
||||
Button("Log in") {self.showModal = true}
|
||||
.sheet(isPresented: $showModal, onDismiss: {
|
||||
print(self.showModal)
|
||||
}) {
|
||||
LoginView()
|
||||
}
|
||||
}.padding()
|
||||
} else {
|
||||
ScrollView {
|
||||
PullToRefresh(coordinateSpaceName: "pullToRefresh") {
|
||||
print("Refreshing..")
|
||||
}
|
||||
Text("Here is dashboard (in my imagination)")
|
||||
}.coordinateSpace(name: "pullToRefresh")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
//
|
||||
// attendance.swift
|
||||
// wulkanowy
|
||||
//
|
||||
// Created by Tomasz on 24/02/2021.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ExamsView: View {
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
VStack {
|
||||
Text("You are not logged in (exams)")
|
||||
NavigationLink(destination: LoginView()) {
|
||||
Text("Log in")
|
||||
}
|
||||
}.padding()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct ExamsView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
ExamsView()
|
||||
}
|
||||
.preferredColorScheme(.dark)
|
||||
}
|
||||
}
|
|
@ -6,17 +6,32 @@
|
|||
//
|
||||
|
||||
import SwiftUI
|
||||
import KeychainAccess
|
||||
import Sdk
|
||||
|
||||
struct GradesView: View {
|
||||
@State private var showModal = false
|
||||
@AppStorage("isLogged") private var isLogged: Bool = false
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
VStack {
|
||||
Text("You are not logged in (grades)")
|
||||
NavigationLink(destination: LoginView()) {
|
||||
Text("Log in")
|
||||
}
|
||||
}.padding()
|
||||
}
|
||||
if(isLogged == false){
|
||||
VStack {
|
||||
Text("You are not logged in")
|
||||
Button("Log in") {self.showModal = true}
|
||||
.sheet(isPresented: $showModal, onDismiss: {
|
||||
print(self.showModal)
|
||||
}) {
|
||||
LoginView()
|
||||
}
|
||||
}.padding()
|
||||
} else {
|
||||
ScrollView {
|
||||
PullToRefresh(coordinateSpaceName: "pullToRefresh") {
|
||||
print("Refreshing..")
|
||||
}
|
||||
Text("Here is grades (in my imagination)")
|
||||
}.coordinateSpace(name: "pullToRefresh")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
//
|
||||
// homework.swift
|
||||
// wulkanowy
|
||||
//
|
||||
// Created by Tomasz on 24/02/2021.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct HomeworksView: View {
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
VStack {
|
||||
Text("You are not logged in (homeworks)")
|
||||
NavigationLink(destination: LoginView()) {
|
||||
Text("Log in")
|
||||
}
|
||||
}.padding()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct HomeworksView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
HomeworksView()
|
||||
}
|
||||
.preferredColorScheme(.dark)
|
||||
}
|
||||
}
|
|
@ -9,12 +9,39 @@ import SwiftUI
|
|||
|
||||
struct LicensesView: View {
|
||||
let KeychainAccessLicense: String = "The MIT License (MIT)\nCopyright (c) 2014 kishikawa katsumi\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
|
||||
|
||||
let SwiftyJSONLicense: String = """
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017 Ruoyu Fu
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
|
||||
let KeychainAccessURL: URL? = URL(string: "https://github.com/kishikawakatsumi/KeychainAccess")!
|
||||
|
||||
let OpenSSLURL: URL? = URL(string: "https://github.com/krzyzanowskim/OpenSSL")!
|
||||
|
||||
let SwiftUIEKtensionsURL: URL? = URL(string: "https://github.com/EnesKaraosman/SwiftUIEKtensions")!
|
||||
|
||||
let SwiftyJSONURL: URL? = URL(string: "https://github.com/SwiftyJSON/SwiftyJSON")!
|
||||
|
||||
let OpenSSLLicense: String = """
|
||||
LICENSE ISSUES
|
||||
==============
|
||||
|
@ -177,6 +204,17 @@ struct LicensesView: View {
|
|||
}
|
||||
}
|
||||
.padding(.vertical)
|
||||
|
||||
// SwiftyJSON
|
||||
DisclosureGroup("SwiftyJSON") {
|
||||
Text(SwiftyJSONLicense)
|
||||
.font(.system(.body, design: .monospaced))
|
||||
.onTapGesture {
|
||||
guard let url = SwiftyJSONURL else { return }
|
||||
UIApplication.shared.open(url)
|
||||
}
|
||||
}
|
||||
.padding(.vertical)
|
||||
}
|
||||
.listStyle(InsetGroupedListStyle())
|
||||
.navigationTitle(Text("Libraries"))
|
||||
|
|
|
@ -8,15 +8,28 @@
|
|||
import SwiftUI
|
||||
|
||||
struct MessagesView: View {
|
||||
@State private var showModal = false
|
||||
@AppStorage("isLogged") private var isLogged: Bool = false
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
VStack {
|
||||
Text("You are not logged in (messages)")
|
||||
NavigationLink(destination: LoginView()) {
|
||||
Text("Log in")
|
||||
}
|
||||
}.padding()
|
||||
}
|
||||
if(isLogged == false){
|
||||
VStack {
|
||||
Text("You are not logged in")
|
||||
Button("Log in") {self.showModal = true}
|
||||
.sheet(isPresented: $showModal, onDismiss: {
|
||||
print(self.showModal)
|
||||
}) {
|
||||
LoginView()
|
||||
}
|
||||
}.padding()
|
||||
} else {
|
||||
ScrollView {
|
||||
PullToRefresh(coordinateSpaceName: "pullToRefresh") {
|
||||
print("Refreshing..")
|
||||
}
|
||||
Text("Here is messages (in my imagination)")
|
||||
}.coordinateSpace(name: "pullToRefresh")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
//
|
||||
// Created by Tomasz on 24/02/2021.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct MoreView: View {
|
||||
|
@ -12,9 +11,9 @@ struct MoreView: View {
|
|||
NavigationView {
|
||||
Form {
|
||||
Section {
|
||||
NavigationLink(destination: MessagesView()) {
|
||||
Label("messagesButton", systemImage: "envelope")
|
||||
.accessibility(label: Text("messagesButton"))
|
||||
NavigationLink(destination: AttendanceView()) {
|
||||
Label("attendanceButton", systemImage: "chart.bar.doc.horizontal")
|
||||
.accessibility(label: Text("attendanceButton"))
|
||||
}
|
||||
NavigationLink(destination: NotesView()) {
|
||||
Label("notesButton", systemImage: "graduationcap")
|
||||
|
|
|
@ -8,15 +8,30 @@
|
|||
import SwiftUI
|
||||
|
||||
struct NotesView: View {
|
||||
@State private var showModal = false
|
||||
@AppStorage("isLogged") private var isLogged: Bool = false
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
VStack {
|
||||
Text("You are not logged in (notes)")
|
||||
NavigationLink(destination: LoginView()) {
|
||||
Text("Log in")
|
||||
if(isLogged == false){
|
||||
VStack {
|
||||
Text("You are not logged in (notes)")
|
||||
Button("Log in") {self.showModal = true}
|
||||
.sheet(isPresented: $showModal, onDismiss: {
|
||||
print(self.showModal)
|
||||
}) {
|
||||
LoginView()
|
||||
}
|
||||
}.padding()
|
||||
} else {
|
||||
ScrollView {
|
||||
PullToRefresh(coordinateSpaceName: "pullToRefresh") {
|
||||
print("Refreshing..")
|
||||
}
|
||||
}.padding()
|
||||
}
|
||||
Text("Here is notes (in my imagination)")
|
||||
}.coordinateSpace(name: "pullToRefresh")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,17 +5,24 @@
|
|||
// Created by Mikołaj on 25/10/2020.
|
||||
//
|
||||
|
||||
|
||||
import SwiftUI
|
||||
import KeychainAccess
|
||||
import SwiftyJSON
|
||||
|
||||
enum AvailableEndpoints: String, CaseIterable {
|
||||
case vulcan = "Vulcan"
|
||||
case fakelog = "Fakelog"
|
||||
}
|
||||
|
||||
open class Navigation: ObservableObject {
|
||||
let window: UIWindow
|
||||
|
||||
public init(window: UIWindow) {
|
||||
self.window = window
|
||||
}
|
||||
}
|
||||
|
||||
struct LoginView: View {
|
||||
|
||||
@StateObject var vulcan: VulcanStore = VulcanStore.shared
|
||||
|
||||
@State private var token: String = ""
|
||||
|
@ -27,10 +34,12 @@ struct LoginView: View {
|
|||
@State private var buttonValue = String(format: NSLocalizedString("loginButton", comment: "loginButton"))
|
||||
@State private var loginStatus: String = ""
|
||||
@State private var willMoveToNextScreen = false
|
||||
@State private var success = false
|
||||
@State private var showingAlert = false
|
||||
|
||||
let cellHeight: CGFloat = 55
|
||||
let cornerRadius: CGFloat = 12
|
||||
let cellBackground: Color = Color(UIColor.systemGray6).opacity(0.5)
|
||||
let cellBackground: Color = Color(UIColor.systemGray5).opacity(0.5)
|
||||
|
||||
let nullColor: Color = Color.accentColor.opacity(0.4)
|
||||
|
||||
|
@ -49,16 +58,19 @@ struct LoginView: View {
|
|||
|
||||
case "wrongPin":
|
||||
buttonValue = String(format: NSLocalizedString("\(error)", comment: "loginButton"))
|
||||
|
||||
case "deviceExist":
|
||||
showingAlert.toggle()
|
||||
success = false
|
||||
|
||||
default:
|
||||
buttonValue = String(format: NSLocalizedString("invalidData", comment: "loginButton"))
|
||||
}
|
||||
} else {
|
||||
print("success")
|
||||
success = true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,85 +114,95 @@ struct LoginView: View {
|
|||
}
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
Image("wulkanowy")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(height: 92)
|
||||
.foregroundColor(.accentColor)
|
||||
.padding(.bottom)
|
||||
|
||||
Text("loginTitle")
|
||||
.font(.largeTitle)
|
||||
.fontWeight(.semibold)
|
||||
|
||||
Spacer()
|
||||
|
||||
TextField("token", text: $token)
|
||||
.autocapitalization(.none)
|
||||
.font(Font.body.weight(Font.Weight.medium))
|
||||
.multilineTextAlignment(.center)
|
||||
.padding(.horizontal)
|
||||
.frame(height: cellHeight)
|
||||
.background(cellBackground)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: cornerRadius)
|
||||
.stroke(setColor(input: "token"), lineWidth: 2)
|
||||
)
|
||||
|
||||
TextField("symbol", text: $symbol)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.font(Font.body.weight(Font.Weight.medium))
|
||||
.multilineTextAlignment(.center)
|
||||
.padding(.horizontal)
|
||||
.frame(height: cellHeight)
|
||||
.background(cellBackground)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: cornerRadius)
|
||||
.stroke(setColor(input: "symbol"), lineWidth: 2)
|
||||
)
|
||||
|
||||
TextField("pin", text: $pin)
|
||||
.keyboardType(.numberPad)
|
||||
.autocapitalization(.none)
|
||||
.font(Font.body.weight(Font.Weight.medium))
|
||||
.multilineTextAlignment(.center)
|
||||
.padding(.horizontal)
|
||||
.frame(height: cellHeight)
|
||||
.background(cellBackground)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: cornerRadius)
|
||||
.stroke(setColor(input: "pin"), lineWidth: 2)
|
||||
)
|
||||
|
||||
TextField("deviceName", text: $deviceModel)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.font(Font.body.weight(Font.Weight.medium))
|
||||
.multilineTextAlignment(.center)
|
||||
.padding(.horizontal)
|
||||
.frame(height: cellHeight)
|
||||
.background(cellBackground)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: cornerRadius)
|
||||
.stroke(setColor(input: "deviceName"), lineWidth: 2)
|
||||
)
|
||||
|
||||
Spacer()
|
||||
|
||||
Button(buttonValue) {login()}
|
||||
.font(.headline)
|
||||
.multilineTextAlignment(.center)
|
||||
.padding(.horizontal)
|
||||
.frame(height: cellHeight)
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(Color.accentColor.opacity(0.1))
|
||||
.cornerRadius(cornerRadius)
|
||||
if(success == true) {
|
||||
ChooseStudentView()
|
||||
}
|
||||
else
|
||||
{
|
||||
VStack {
|
||||
Spacer()
|
||||
Image("wulkanowy")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(height: 92)
|
||||
.foregroundColor(.accentColor)
|
||||
.padding(.bottom)
|
||||
|
||||
Text("loginTitle")
|
||||
.font(.largeTitle)
|
||||
.fontWeight(.semibold)
|
||||
|
||||
Spacer()
|
||||
|
||||
TextField("token", text: $token)
|
||||
.autocapitalization(.none)
|
||||
.font(Font.body.weight(Font.Weight.medium))
|
||||
.multilineTextAlignment(.center)
|
||||
.padding(.horizontal)
|
||||
.frame(height: cellHeight)
|
||||
.background(cellBackground)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: cornerRadius)
|
||||
.stroke(setColor(input: "token"), lineWidth: 2)
|
||||
)
|
||||
|
||||
TextField("symbol", text: $symbol)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.font(Font.body.weight(Font.Weight.medium))
|
||||
.multilineTextAlignment(.center)
|
||||
.padding(.horizontal)
|
||||
.frame(height: cellHeight)
|
||||
.background(cellBackground)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: cornerRadius)
|
||||
.stroke(setColor(input: "symbol"), lineWidth: 2)
|
||||
)
|
||||
|
||||
TextField("pin", text: $pin)
|
||||
.keyboardType(.numberPad)
|
||||
.autocapitalization(.none)
|
||||
.font(Font.body.weight(Font.Weight.medium))
|
||||
.multilineTextAlignment(.center)
|
||||
.padding(.horizontal)
|
||||
.frame(height: cellHeight)
|
||||
.background(cellBackground)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: cornerRadius)
|
||||
.stroke(setColor(input: "pin"), lineWidth: 2)
|
||||
)
|
||||
|
||||
TextField("deviceName", text: $deviceModel)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.font(Font.body.weight(Font.Weight.medium))
|
||||
.multilineTextAlignment(.center)
|
||||
.padding(.horizontal)
|
||||
.frame(height: cellHeight)
|
||||
.background(cellBackground)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: cornerRadius)
|
||||
.stroke(setColor(input: "deviceName"), lineWidth: 2)
|
||||
)
|
||||
|
||||
Spacer()
|
||||
|
||||
Button(buttonValue) {login()}
|
||||
.font(.headline)
|
||||
.multilineTextAlignment(.center)
|
||||
.padding(.horizontal)
|
||||
.frame(height: cellHeight)
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(Color.accentColor.opacity(0.1))
|
||||
.cornerRadius(cornerRadius)
|
||||
|
||||
}.padding()
|
||||
.alert(isPresented: $showingAlert) {
|
||||
Alert(title: Text("accountRegistered"), message: Text("accountRegisteredContent"), dismissButton: .default(Text("OK")))}
|
||||
Spacer()
|
||||
|
||||
}
|
||||
.padding()
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
108
wulkanowy/Views/Login/chooseStudent.swift
Normal file
108
wulkanowy/Views/Login/chooseStudent.swift
Normal file
|
@ -0,0 +1,108 @@
|
|||
//
|
||||
// chooseStudent.swift
|
||||
// wulkanowy
|
||||
//
|
||||
// Created by Tomasz on 02/03/2021.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import KeychainAccess
|
||||
import SwiftyJSON
|
||||
|
||||
struct ChooseStudentView: View {
|
||||
@Environment(\.presentationMode) var presentation
|
||||
@AppStorage("isLogged") private var isLogged: Bool = false
|
||||
|
||||
let keychain = Keychain()
|
||||
var displayStudents: Array<String> = Array()
|
||||
|
||||
@State private var selectedStudent: String = ""
|
||||
|
||||
init() {
|
||||
var responseBody = keychain["actualStudentHebe"]
|
||||
while responseBody == nil {
|
||||
responseBody = keychain["actualStudentHebe"]
|
||||
}
|
||||
|
||||
let data = Data(responseBody!.utf8)
|
||||
let json = try! JSON(data: data)
|
||||
selectedStudent = "\(json["Envelope"][0]["Login"]["DisplayName"])"
|
||||
|
||||
var i: Int = 0
|
||||
while true {
|
||||
if (String(describing: json["Envelope"][i]) == "null") {
|
||||
break
|
||||
}
|
||||
else {
|
||||
displayStudents.append(String(describing: json["Envelope"][i]["Login"]["DisplayName"]))
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func saveStudent() {
|
||||
let responseBody = keychain["actualStudentHebe"]
|
||||
|
||||
let data = Data(responseBody!.utf8)
|
||||
let json = try! JSON(data: data)
|
||||
|
||||
var i: Int = 0
|
||||
if(selectedStudent == "") {
|
||||
selectedStudent = "\(json["Envelope"][i]["Login"]["DisplayName"])"
|
||||
}
|
||||
while true {
|
||||
let student = "\(json["Envelope"][i]["Login"]["DisplayName"])"
|
||||
if(student == selectedStudent) {
|
||||
//saving student
|
||||
let id = "\(keychain["actualStudentId"] ?? "0")"
|
||||
let account = keychain[id]
|
||||
let data: Data = Data(account!.utf8)
|
||||
var accountJSON = try! JSON(data: data)
|
||||
accountJSON["actualStudent"] = JSON(i)
|
||||
print(accountJSON)
|
||||
keychain[id] = "\(accountJSON)"
|
||||
break
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
isLogged = true
|
||||
presentation.wrappedValue.dismiss()
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
Spacer()
|
||||
Text("selectStudent")
|
||||
.font(.title)
|
||||
.padding(.top)
|
||||
Picker(selection: $selectedStudent, label: Text("selectStudent")) {
|
||||
ForEach(displayStudents, id: \.self) { student in
|
||||
Text(student)
|
||||
}
|
||||
}
|
||||
Spacer()
|
||||
Button("registerButton") {saveStudent()}
|
||||
.font(.headline)
|
||||
.multilineTextAlignment(.center)
|
||||
.padding(.horizontal)
|
||||
.frame(height: 55)
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(Color.accentColor.opacity(0.1))
|
||||
.cornerRadius(12)
|
||||
|
||||
}.padding()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct ChooseStudentView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
ChooseStudentView()
|
||||
}
|
||||
.preferredColorScheme(.dark)
|
||||
}
|
||||
}
|
|
@ -5,33 +5,59 @@
|
|||
// Created by Tomasz on 23/02/2021.
|
||||
//
|
||||
|
||||
//
|
||||
// navigation.swift
|
||||
// wulkanowy
|
||||
//
|
||||
// Created by Tomasz on 23/02/2021.
|
||||
//
|
||||
import SwiftUI
|
||||
|
||||
struct NavigationBarView: View {
|
||||
var body: some View {
|
||||
TabView() {
|
||||
DashboardView()
|
||||
.tabItem {
|
||||
NavigationView {
|
||||
DashboardView()
|
||||
.navigationBarItems(trailing: NavigationLink(destination: AccountManagerView()) {
|
||||
Image(systemName: "person.circle")
|
||||
})
|
||||
}
|
||||
.tabItem {
|
||||
Label("dashboardButton", systemImage: "rectangle.on.rectangle")
|
||||
.accessibility(label: Text("dashboardButton"))
|
||||
}
|
||||
|
||||
GradesView()
|
||||
.tabItem {
|
||||
|
||||
NavigationView {
|
||||
GradesView()
|
||||
.navigationBarItems(trailing: NavigationLink(destination: AccountManagerView()) {
|
||||
Image(systemName: "person.circle")
|
||||
})
|
||||
}
|
||||
.tabItem {
|
||||
Label("gradesButton", systemImage: "rosette")
|
||||
.accessibility(label: Text("gradesButton"))
|
||||
}
|
||||
|
||||
ExamsView()
|
||||
.tabItem {
|
||||
Label("examsButton", systemImage: "calendar")
|
||||
.accessibility(label: Text("examsButton"))
|
||||
|
||||
NavigationView {
|
||||
CalendarView()
|
||||
.navigationBarItems(trailing: NavigationLink(destination: AccountManagerView()) {
|
||||
Image(systemName: "person.circle")
|
||||
})
|
||||
}
|
||||
.tabItem {
|
||||
Label("calendarButton", systemImage: "calendar")
|
||||
.accessibility(label: Text("calendarButton"))
|
||||
}
|
||||
|
||||
HomeworksView()
|
||||
.tabItem {
|
||||
Label("homeworkButton", systemImage: "note.text")
|
||||
.accessibility(label: Text("homeworkButton"))
|
||||
NavigationView {
|
||||
MessagesView()
|
||||
.navigationBarItems(trailing: NavigationLink(destination: AccountManagerView()) {
|
||||
Image(systemName: "person.circle")
|
||||
})
|
||||
}
|
||||
.tabItem {
|
||||
Label("messagesButton", systemImage: "envelope")
|
||||
.accessibility(label: Text("messagesButton"))
|
||||
}
|
||||
|
||||
MoreView()
|
||||
|
@ -52,4 +78,3 @@ struct NavigationBarView_Previews: PreviewProvider {
|
|||
.preferredColorScheme(.dark)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
93
wulkanowy/Views/Onboarding/OnboardingView.swift
Normal file
93
wulkanowy/Views/Onboarding/OnboardingView.swift
Normal file
|
@ -0,0 +1,93 @@
|
|||
//
|
||||
// OnboardingView.swift
|
||||
// wulkanowy
|
||||
//
|
||||
// Created by Karol Zientek on 12/02/2021.
|
||||
//
|
||||
import SwiftUI
|
||||
|
||||
fileprivate struct InformationDetailView: View {
|
||||
var title: LocalizedStringKey = ""
|
||||
var subtitle: LocalizedStringKey = ""
|
||||
var imageName: String = ""
|
||||
|
||||
var body: some View {
|
||||
HStack(alignment: .center) {
|
||||
Image(systemName: imageName)
|
||||
.font(.system(size: 50))
|
||||
.font(.largeTitle)
|
||||
.frame(width: 50)
|
||||
.foregroundColor(.accentColor)
|
||||
.padding()
|
||||
.accessibility(hidden: true)
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
Text(title)
|
||||
.font(.headline)
|
||||
.foregroundColor(.primary)
|
||||
.accessibility(addTraits: .isHeader)
|
||||
.lineLimit(2)
|
||||
|
||||
Text(subtitle)
|
||||
.font(.body)
|
||||
.foregroundColor(.secondary)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
}
|
||||
}
|
||||
.padding(.top)
|
||||
}
|
||||
}
|
||||
|
||||
struct OnboardingView: View {
|
||||
|
||||
@AppStorage("needsAppOnboarding") private var needsAppOnboarding: Bool = true
|
||||
|
||||
var body: some View {
|
||||
VStack() {
|
||||
Spacer()
|
||||
Image("wulkanowy")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(height: 92)
|
||||
.foregroundColor(.accentColor)
|
||||
.padding(.bottom)
|
||||
|
||||
Text("onboardingTitle")
|
||||
.font(.title)
|
||||
.fontWeight(.semibold)
|
||||
.padding()
|
||||
.multilineTextAlignment(.center)
|
||||
.frame(height: 100)
|
||||
|
||||
Spacer()
|
||||
HStack {
|
||||
Spacer()
|
||||
VStack(alignment: .leading) {
|
||||
InformationDetailView(title: "notificationsOnboarding", subtitle: "notificationsOnboardingContent", imageName: "bell")
|
||||
InformationDetailView(title: "messagesOnboarding", subtitle: "messagesOnboardingContent", imageName: "envelope")
|
||||
InformationDetailView(title: "fast", subtitle: "fastContent", imageName: "hare")
|
||||
}.multilineTextAlignment(.leading)
|
||||
Spacer()
|
||||
}
|
||||
Spacer()
|
||||
Spacer()
|
||||
Button("continueButton") { needsAppOnboarding = false }
|
||||
.font(.headline)
|
||||
.multilineTextAlignment(.center)
|
||||
.padding()
|
||||
.frame(height: 55)
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(Color.accentColor.opacity(0.1))
|
||||
.cornerRadius(12)
|
||||
}.padding()
|
||||
}
|
||||
}
|
||||
|
||||
struct WulkanowyCardView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
OnboardingView().previewLayout(.fixed(width: 320, height: 640))
|
||||
}
|
||||
}
|
||||
}
|
43
wulkanowy/Views/PullToRefresh.swift
Normal file
43
wulkanowy/Views/PullToRefresh.swift
Normal file
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
// PullToRefresh.swift
|
||||
// wulkanowy
|
||||
//
|
||||
// Created by Tomasz on 25/03/2021.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
struct PullToRefresh: View {
|
||||
|
||||
var coordinateSpaceName: String
|
||||
var onRefresh: ()->Void
|
||||
|
||||
@State var needRefresh: Bool = false
|
||||
|
||||
var body: some View {
|
||||
GeometryReader { geo in
|
||||
if (geo.frame(in: .named(coordinateSpaceName)).midY > 50) {
|
||||
Spacer()
|
||||
.onAppear {
|
||||
needRefresh = true
|
||||
}
|
||||
} else if (geo.frame(in: .named(coordinateSpaceName)).maxY < 10) {
|
||||
Spacer()
|
||||
.onAppear {
|
||||
if needRefresh {
|
||||
needRefresh = false
|
||||
onRefresh()
|
||||
}
|
||||
}
|
||||
}
|
||||
HStack {
|
||||
Spacer()
|
||||
if needRefresh {
|
||||
ProgressView()
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
}.padding(.top, -50)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue