patbef-iOS/Befund/Controllers/ViewController.swift

1922 lines
80 KiB
Swift
Raw Normal View History

2024-01-29 16:20:42 +01:00
//
// ViewController.swift
// Befund
//
// Created by Irakli Abetschkhrischwili on 29.04.22.
// Copyright © 2022 MVZ Dr. Stein und Kollegen. All rights reserved.
import AVFoundation
import UIKit
class ViewController: UIViewController, UIAlertViewDelegate, UITextFieldDelegate, UITableViewDataSource, UITableViewDelegate, UNUserNotificationCenterDelegate, UpdatingParentCheckBox
{
//MARK: *** ViewController
public static var CurrentViewController: ViewController? = nil
public static var Settings: Core.Models.Settings? = nil
public static var currentlySelectedBarcode: String = ""
@IBOutlet weak var DashedArea: UIView!
@IBOutlet weak var LBLNORESULTS: UILabel!
//@IBOutlet weak var LBL_NEW_RESULTS: UILabel!
@IBOutlet weak var LBL_MY_RESULTS: UILabel!
@IBOutlet weak var LBL_HINWEIS: UILabel!
@IBOutlet weak var ResultsTable: UITableView!
private var ResultsTableRefresher: UIRefreshControl!
@IBOutlet weak var MainLoading: UIActivityIndicatorView!
private var dbResults: Array<Core.Models.Database.Results>? = nil
//MARK: *** PopupNewPGS
@IBOutlet weak var PopupNewPGS_Overlay: UIView!
@IBOutlet weak var PopupNewPGS: UIView!
//MARK: *** PopupNewPGS - PGS
@IBOutlet weak var PopupNewPGS_PGS: UIView!
@IBOutlet weak var PopupNewPGS_ZipView: UIView!
@IBOutlet weak var PopupNewPGS_BirthdayView: UIView!
@IBOutlet weak var PopupNewPGS_SampleidView: UIView!
@IBOutlet weak var PopupNewPGS_txtZIP: UITextField!
@IBOutlet weak var PopupNewPGS_txtBirthday: UITextField!
let PopupNewPGS_dtBirthday = UIDatePicker()
@IBOutlet weak var PopupNewPGS_txtSampleid: UITextField!
@IBOutlet weak var PopupNwePGS_btnScanBarcode: UIButton!
@IBOutlet weak var PopupNewPGS_Loading: UIActivityIndicatorView!
@IBOutlet weak var PopupNewPGS_Status: UILabel!
@IBOutlet weak var PopupNewPGS_labPwdHinweis: UILabel!
//MARK: *** PopupNewPGS - MasterPassword
@IBOutlet weak var PopupNewPGS_MasterPassword: UIView!
@IBOutlet weak var PopupNewPGS_PasswordConfirmView: UIView!
@IBOutlet weak var PopupNewPGS_PasswordView: UIView!
@IBOutlet weak var PopupNewPGS_txtPassword: UITextField!
@IBOutlet weak var PopupNewPGS_txtPasswordConfirm: UITextField!
@IBOutlet weak var PopupNewPGS_txtPin: UITextField!
@IBOutlet weak var PopupNewPGS_PrivatePolicyArea: UIView!
@IBOutlet weak var PopupNewPGS_BtnPrivatePolicy: UIButton!
//MARK: *** PopupNewPGS - Buttons
@IBOutlet weak var PopupNewPGS_BtnAdd: UIButton!
@IBOutlet weak var PopupNewPGS_BtnCancel: UIButton!
//MARK: *** PopupPasswordConfirm
@IBOutlet weak var PopupPasswordConfirm_Overlay: UIView!
@IBOutlet weak var PopupPasswordConfirm: UIView!
@IBOutlet weak var PopupPasswordConfirm_BtnCancel: UIButton!
@IBOutlet weak var PopupPasswordConfirm_BtnEncrypt: UIButton!
@IBOutlet weak var PopupPasswordConfirm_PasswordView: UIView!
@IBOutlet weak var PopupPasswordConfirm_txtPassword: UITextField!
@IBOutlet weak var PopupPasswordConfirm_Loading: UIActivityIndicatorView!
@IBOutlet weak var PopupPasswordConfirm_Status: UILabel!
//MARK: *** PopupPrivatePolicy
@IBOutlet weak var PopupPrivatePolicy_Overlay: UIView!
@IBOutlet weak var PopupPrivatePolicy: UIView!
@IBOutlet weak var PopupPrivatePolicy_TextLabel: UILabel!
@IBOutlet weak var PopupPrivatePolicy_BtnAccept: UIButton!
@IBOutlet weak var PopupPrivatePolicy_HeadLabel: UILabel!
// PopupPushNotification
@IBOutlet weak var PopupPush_Overlay: UIView!
@IBOutlet weak var PopupPush_Content: UIView!
@IBOutlet weak var PopupPush_LabelText: UILabel!
@IBOutlet weak var PopupPush_LabelHeader: UILabel!
@IBOutlet weak var PopupPush_BtnYes: UIButton!
@IBOutlet weak var PopupPush_BtnNo: UIButton!
//MARK: *** Processing objects
private var CurrentDownload: Core.Models.Response.Download? = nil
private var CurrentDownloadResults: Core.Models.Database.Results? = nil
private var CurrentDownloadProcessing: Bool = false
private var LoadingData: Bool = false
//MARK: Bottom Menu
@IBOutlet weak var BottomMenu: UIView!
@IBOutlet weak var launch_Overlay: UIView!
@IBOutlet weak var launch_LimbachLogo: UIImageView!
@IBOutlet weak var launch_LaborLogo: UIImageView!
//private let privatePolicyLink = "https://www.limbachgruppe.com/fileadmin/downloads/6406135946.html"
private var afterInitialize: Bool = false
@IBOutlet var PopupPrivatePolicy_Checkbox: CheckBoxButton!
public var confirmCheckBox: CheckBoxButton! {
get {
return PopupPrivatePolicy_Checkbox
}
}
override func viewDidLoad()
{
super.viewDidLoad()
self.Initialize()
NotificationCenter.default.addObserver(self, selector: #selector(appActivated), name: UIApplication.didBecomeActiveNotification, object: nil)
}
@objc func appActivated()
{
if (self.viewIfLoaded?.window != nil && !self.CurrentDownloadProcessing)
{
self.dashedAreaLongPressed(sender: UILongPressGestureRecognizer())
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.SetLabels()
ViewController.Settings = Core.Models.Settings.loadFromFile(atPath: Core.System.SettingsPath())
if (!self.PopupNewPGS_Overlay.isHidden && ViewController.currentlySelectedBarcode.count > 0)
{
self.PopupNewPGS_txtSampleid.text = ViewController.currentlySelectedBarcode
ViewController.currentlySelectedBarcode = ""
}
if (self.afterInitialize){
self.afterInitialize = false
self.ShowLaborLogo()
}
else
{
self.ShowMainView()
}
}
private func ShowMainView()
{
if(AppDelegate.Session.DevicePassword == nil && (ViewController.Settings?.verificator_hash != nil))
{
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let devicePwdController = storyboard.instantiateViewController(identifier: "LoginController")
devicePwdController.modalPresentationStyle = .fullScreen
let transition = CATransition()
transition.duration = 0.25
transition.type = .push
transition.subtype = .fromRight
self.view.window!.layer.add(transition, forKey: kCATransition)
self.present(devicePwdController, animated: false)
}
else
{
if(ViewController.Settings?.udid != nil)
{
self.loadResults()
}
}
if(!(ViewController.Settings?.pushNotificationExplained ?? false))
{
self.ShowPopup(overlay: self.PopupPush_Overlay, content: self.PopupPush_Content)
}
else
{
self.AskForPushPermissions()
}
}
private func ShowLaborLogo()
{
if ((ViewController.Settings?.labor?.id ?? "").count > 0 )
{
self.launch_Overlay.isHidden = false
self.launch_LaborLogo.image = ViewController.Settings!.labor!.logo
self.launch_LaborLogo.frame.origin = CGPoint(x: -self.view.frame.width, y: self.launch_LimbachLogo.frame.origin.y)
self.launch_LaborLogo.isHidden = false
let storeX = self.launch_LimbachLogo.frame.origin.x
UIView.animate(withDuration: 1.00, animations: {
self.launch_LimbachLogo.frame.origin = CGPoint(x: self.view.frame.width, y: self.launch_LimbachLogo.frame.origin.y)
self.launch_LaborLogo.frame.origin = CGPoint(x: storeX, y: self.launch_LaborLogo.frame.origin.y)
}) {_ in
sleep(1)
self.launch_Overlay.isHidden = true
self.ShowMainView()
}
}
else
{
self.ShowMainView()
}
}
/**
* Initializes view
*/
private func Initialize()
{
self.afterInitialize = true
//MARK: *** ViewController
ViewController.CurrentViewController = self
ViewController.Settings = Core.Models.Settings.loadFromFile(atPath: Core.System.SettingsPath())
self.PopupNewPGS_MasterPassword.isHidden = true
self.PopupNewPGS_HideLoading()
self.launch_Overlay.frame = self.view.frame
self.view.addSubview(self.launch_Overlay)
//MARK: *** PopupNewPGS
self.PopupNewPGS_Overlay.frame = self.view.frame
self.view.addSubview(self.PopupNewPGS_Overlay)
var popupFieldHeight = (self.PopupNewPGS_PGS.frame.size.height / 3)
if(popupFieldHeight > 100)
{
popupFieldHeight = 100
}
let popupFieldMargin = ((popupFieldHeight * 5) / 100)
popupFieldHeight = popupFieldHeight - (3 * popupFieldMargin)
self.PopupNewPGS_ZipView.frame.size.height = popupFieldHeight
self.PopupNewPGS_BirthdayView.frame.size.height = popupFieldHeight
self.PopupNewPGS_BirthdayView.frame.origin = CGPoint(x: self.PopupNewPGS_BirthdayView.frame.origin.x, y: self.PopupNewPGS_ZipView.frame.origin.y + self.PopupNewPGS_ZipView.frame.size.height + popupFieldMargin)
self.PopupNewPGS_SampleidView.frame.size.height = popupFieldHeight
self.PopupNewPGS_SampleidView.frame.origin = CGPoint(x: self.PopupNewPGS_SampleidView.frame.origin.x, y: self.PopupNewPGS_BirthdayView.frame.origin.y + self.PopupNewPGS_BirthdayView.frame.size.height + popupFieldMargin)
self.PopupNewPGS_txtZIP.delegate = self
self.PopupNewPGS_txtBirthday.delegate = self
self.PopupNewPGS_txtSampleid.delegate = self
self.PopupNewPGS_txtPassword.delegate = self
self.PopupNewPGS_txtPassword.enablePasswordToggle()
self.PopupNewPGS_txtPasswordConfirm.delegate = self
self.PopupNewPGS_txtPasswordConfirm.enablePasswordToggle()
self.PopupNewPGS_txtPin.delegate = self
self.PopupNewPGS_txtZIP.returnKeyType = .next
self.PopupNewPGS_txtBirthday.returnKeyType = .next
self.PopupNewPGS_txtSampleid.returnKeyType = .done
self.PopupNewPGS_txtPassword.returnKeyType = .next
self.PopupNewPGS_txtPasswordConfirm.returnKeyType = .next
self.PopupNewPGS_txtPin.returnKeyType = .done
self.PopupPrivatePolicy_Checkbox = CheckBoxButton(frame: CGRect(x: 10, y: 5, width: 30, height: 30))
self.PopupNewPGS_PrivatePolicyArea.addSubview(self.PopupPrivatePolicy_Checkbox)
let gesture = UITapGestureRecognizer(target: self, action: #selector(didTapCheckbox))
self.PopupPrivatePolicy_Checkbox.addGestureRecognizer(gesture)
self.PopupPrivatePolicy_Checkbox.setChecked(flag: true)
self.addDoneToolbar([self.PopupNewPGS_txtZIP, self.PopupNewPGS_txtSampleid, self.PopupNewPGS_txtPassword, self.PopupNewPGS_txtPasswordConfirm, self.PopupNewPGS_txtPin])
self.hideKeyboardWhenTappedAround()
self.createDatePicker()
//MARK: *** Table
self.DashedArea.addDashedBorder()
self.ResultsTableRefresher = UIRefreshControl()
let attributes = [NSAttributedString.Key.foregroundColor: UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 0.8), NSAttributedString.Key.font: UIFont.systemFont(ofSize: 15.0)]
self.ResultsTableRefresher.attributedTitle = NSAttributedString(string: Core.Lang.Get(key: "MSG_DATA_REFRESHING"), attributes: attributes)
self.ResultsTableRefresher.tintColor = .clear
self.ResultsTableRefresher.addTarget(self, action: #selector(tableRefresh), for: .valueChanged)
self.ResultsTable.addSubview(self.ResultsTableRefresher)
self.ResultsTable.isHidden = true
self.LBLNORESULTS.isHidden = false
self.ResultsTable.delegate = self
self.ResultsTable.dataSource = self
self.ResultsTable.contentInset = .init(top: 0, left: 0, bottom: 70, right: 0)
self.ResultsTable.register(ResultsTableViewCell.nib(), forCellReuseIdentifier: ResultsTableViewCell.identifier)
let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(dashedAreaLongPressed))
self.DashedArea.addGestureRecognizer(longPressRecognizer)
//MARK: *** PopupPasswordConfirm
self.PopupPasswordConfirm_Overlay.isHidden = true
self.PopupPasswordConfirm_HideLoading()
self.PopupPasswordConfirm_Overlay.frame = self.view.frame
self.view.addSubview(self.PopupPasswordConfirm_Overlay)
self.PopupPasswordConfirm_txtPassword.delegate = self
self.PopupPasswordConfirm_txtPassword.enablePasswordToggle()
self.MainLoadingHide()
if(ViewController.Settings?.udid != nil)
{
self.PopupNewPGS_BtnAdd.setTitle(Core.Lang.Get(key: "BTN_ADD"), for: .normal)
self.loadResults()
}
else
{
self.PopupNewPGS_BtnAdd.setTitle(Core.Lang.Get(key: "BTN_NEXT"), for: .normal)
}
self.PopupNwePGS_btnScanBarcode.setTitle("", for: .normal)
self.PopupPrivatePolicy_Overlay.frame = self.view.frame
self.view.addSubview(self.PopupPrivatePolicy_Overlay)
self.PopupPrivatePolicy_Overlay.isHidden = true
//MARK: Bottom Menu
self.BottomMenu.transform = CGAffineTransform(rotationAngle: CGFloat(5.0 * .pi / 180))
self.BottomMenu.frame.origin.y = UIScreen.main.bounds.height
self.PopupPush_Overlay.frame = self.view.frame
self.view.addSubview(self.PopupPush_Overlay)
self.PopupPush_Overlay.isHidden = true
self.PopupNewPGS_labPwdHinweis.text = ""
self.PopupNewPGS_labPwdHinweis.isHidden = false
self.PopupNewPGS_txtPassword.addTarget(self, action: #selector(self.ShowPWDHinweis), for: .editingDidBegin)
self.PopupNewPGS_txtPassword.addTarget(self, action: #selector(self.HidePWDHinweis), for: .editingDidEnd)
self.PopupNewPGS_txtPasswordConfirm.addTarget(self, action: #selector(self.ShowPWDHinweis), for: .editingDidBegin)
self.PopupNewPGS_txtPasswordConfirm.addTarget(self, action: #selector(self.HidePWDHinweis), for: .editingDidEnd)
self.PopupNewPGS_txtPin.addTarget(self, action: #selector(self.ShowPinHinweis), for: .editingDidBegin)
self.PopupNewPGS_txtPin.addTarget(self, action: #selector(self.HidePWDHinweis), for: .editingDidEnd)
}
@objc func ShowPWDHinweis()
{
self.PopupNewPGS_Status.text = ""
self.PopupNewPGS_labPwdHinweis.text = Core.Lang.Get(key: "ERROR_ENTER_STRONG_PASSWORD")
self.PopupNewPGS_labPwdHinweis.isHidden = false
}
@objc func ShowPinHinweis()
{
self.PopupNewPGS_Status.text = ""
self.PopupNewPGS_labPwdHinweis.text = Core.Lang.Get(key: "ERROR_PIN_LENGTH")
self.PopupNewPGS_labPwdHinweis.isHidden = false
}
@objc func HidePWDHinweis()
{
self.PopupNewPGS_labPwdHinweis.text = ""
self.PopupNewPGS_labPwdHinweis.isHidden = true
}
private func SetLabels()
{
// Initialize Language
self.LBL_MY_RESULTS.text = Core.Lang.Get(key: "LBL_MY_RESULTS")
self.LBL_HINWEIS.text = Core.Lang.Get(key: "LBL_BEFUND_HINWEIS")
self.PopupNewPGS_txtZIP.placeholder = Core.Lang.Get(key: "LBL_ZIP")
self.PopupNewPGS_txtBirthday.placeholder = Core.Lang.Get(key: "LBL_BIRTHDAY")
self.PopupNewPGS_txtSampleid.placeholder = Core.Lang.Get(key: "LBL_SAMPLEID")
self.PopupNewPGS_txtPassword.placeholder = Core.Lang.Get(key: "LBL_PASSWORD")
self.PopupNewPGS_txtPasswordConfirm.placeholder = Core.Lang.Get(key: "LBL_PASSWORD_CONFIRM")
self.PopupNewPGS_BtnCancel.setTitle(Core.Lang.Get(key: "BTN_CANCEL"), for: .normal)
self.PopupNewPGS_BtnAdd.setTitle(Core.Lang.Get(key: "BTN_ADD"), for: .normal)
self.PopupNewPGS_BtnPrivatePolicy.setTitle(Core.Lang.Get(key: "LBL_PRIVACY_POLICY"), for: .normal)
self.LBLNORESULTS.text = Core.Lang.Get(key: "LBL_NO_RESULTS")
self.PopupPasswordConfirm_BtnCancel.setTitle(Core.Lang.Get(key: "BTN_CANCEL"), for: .normal)
self.PopupPasswordConfirm_BtnEncrypt.setTitle(Core.Lang.Get(key: "BTN_ENCRYPT"), for: .normal)
self.PopupPasswordConfirm_txtPassword.placeholder = Core.Lang.Get(key: "LBL_PASSWORD")
self.PopupPrivatePolicy_TextLabel.text = Core.Lang.Get(key: "PRIVATE_POLICY_TEXT")
self.PopupPrivatePolicy_HeadLabel.text = Core.Lang.Get(key: "LBL_PRIVACY_POLICY")
self.PopupPrivatePolicy_BtnAccept.setTitle(Core.Lang.Get(key: "BTN_ACCEPT_PRIVACY_POLICY"), for: .normal)
self.PopupPush_LabelHeader.text = Core.Lang.Get(key: "LBL_PUSH_NOTIFICATION_EXPLAIN_HEADER")
self.PopupPush_LabelText.text = Core.Lang.Get(key: "MSG_PUSH_NOTIFICATION_EXPLAIN_TEXT")
self.PopupPush_BtnYes.setTitle(Core.Lang.Get(key: "BTN_OK"), for: .normal)
}
@objc func didTapCheckbox()
{
self.PopupPrivatePolicy_Checkbox.toogle()
}
/**
* Creates the datepicker on the bottom popup menu
*/
func createDatePicker()
{
let formatter=DateFormatter()
formatter.dateFormat = "yyyy/MM/dd"
self.PopupNewPGS_dtBirthday.locale = Locale(identifier: Core.Lang.GetLocale())
self.PopupNewPGS_dtBirthday.calendar.locale = Locale(identifier: Core.Lang.GetLocale())
self.PopupNewPGS_dtBirthday.datePickerMode = .date
self.PopupNewPGS_dtBirthday.preferredDatePickerStyle = .wheels
self.PopupNewPGS_dtBirthday.date = formatter.date(from: "2000/01/01")!
self.PopupNewPGS_dtBirthday.maximumDate = Date()
self.PopupNewPGS_dtBirthday.minimumDate = formatter.date(from: "1900/01/01")
let toolbar = UIToolbar()
let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace,
target: nil, action: nil)
let doneButton = UIBarButtonItem(title: Core.Lang.Get(key: "BTN_DONE"), style: .done,
target: self, action: #selector(PopupNewPGS_dtBirthdayDone))
toolbar.setItems([flexSpace, doneButton], animated: true)
toolbar.sizeToFit()
self.PopupNewPGS_txtBirthday.inputAccessoryView = toolbar
self.PopupNewPGS_txtBirthday.inputView = self.PopupNewPGS_dtBirthday
}
//MARK: BEGIN Application Event Bridgs
public func onSessionChanged(session: Core.Models.Session)
{
//TODO: handle if push permission was taken away-> Show Instruction View that the user has to permitt permissions to push
}
//MARK: END Application Event Bridgs
//MARK: BEGIN Events
@objc func PopupNewPGS_dtBirthdayDone()
{
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd.MM.yyyy"
let dt = dateFormatter.string(from: self.PopupNewPGS_dtBirthday.date)
self.PopupNewPGS_txtBirthday.text = dt
self.PopupNewPGS_txtSampleid.becomeFirstResponder()
}
@IBAction func popupPush_BtnYes_Click(_ sender: Any)
{
self.PushNotificationAccepted(true)
}
private func PushNotificationAccepted(_ flagAccepted: Bool)
{
if (ViewController.Settings == nil)
{
ViewController.Settings = Core.Models.Settings()
}
ViewController.Settings!.pushNotificationExplained = true
ViewController.Settings!.pushNotificationAccepted = flagAccepted
_ = ViewController.Settings!.save(atPath: Core.System.SettingsPath())
self.HidePopup(overlay: self.PopupPush_Overlay, content: self.PopupPush_Content)
if(flagAccepted)
{
self.AskForPushPermissions()
}
}
private func OpenScanner2SelectLabor(_ sender: Any)
{
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let scannerController = storyboard.instantiateViewController(identifier: "ScannerController")
scannerController.modalPresentationStyle = .fullScreen
let transition = CATransition()
transition.duration = 0.25
transition.type = .push
transition.subtype = .fromRight
self.view.window!.layer.add(transition, forKey: kCATransition)
self.present(scannerController, animated: false)
}
@IBAction func ScanBarcodeClick(_ sender: Any)
{
let scannerController = ScannerViewController.InitScannerController(scanSampleID: true)
scannerController.modalPresentationStyle = .fullScreen
let transition = CATransition()
transition.duration = 0.25
transition.type = .push
transition.subtype = .fromRight
self.view.window!.layer.add(transition, forKey: kCATransition)
self.present(scannerController, animated: false)
}
// MARK: ON AddButton Click
@IBAction func AddButtonClick(_ sender: Any)
{
self.PopupNewPGS_Status.text = ""
self.PopupNewPGS_txtSampleid.text = ""
self.PopupNewPGS_Loading.isHidden = true
self.PopupNewPGS_Loading.stopAnimating()
self.PopupNewPGS_BtnCancel.setTitle(Core.Lang.Get(key: "BTN_CANCEL"), for: .normal)
if(ViewController.Settings?.udid != nil)
{
if(ViewController.Settings!.zip != nil)
{
self.PopupNewPGS_txtZIP.text = ViewController.Settings!.zip
}
if(ViewController.Settings!.birthday != nil)
{
self.PopupNewPGS_dtBirthday.date = ViewController.Settings!.GetBirthday()!
self.PopupNewPGS_txtBirthday.text = ViewController.Settings!.GetFormatedBirthday()!
}
self.PopupNewPGS_BtnAdd.setTitle(Core.Lang.Get(key: "BTN_ADD"), for: .normal)
self.PopupNewPGS_PGS.frame.origin = CGPoint(x: 0, y: self.PopupNewPGS_PGS.frame.origin.y)
self.PopupNewPGS_MasterPassword.frame.origin = CGPoint(
x: self.PopupNewPGS_MasterPassword.frame.width,
y: self.PopupNewPGS_MasterPassword.frame.origin.y)
self.PopupNewPGS_MasterPassword.isHidden = true
}
else
{
self.PopupNewPGS_BtnAdd.setTitle(Core.Lang.Get(key: "BTN_NEXT"), for: .normal)
}
self.PopupNewPGS.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
self.PopupNewPGS_Overlay.alpha = 0.0
self.PopupNewPGS_Overlay.isHidden = false
UIView.animate(withDuration: 0.24) {
self.PopupNewPGS.transform = CGAffineTransform.identity
self.PopupNewPGS_Overlay.alpha = 70.0
}
}
private func ShowPopup(overlay: UIView!, content: UIView!)
{
content.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
overlay.alpha = 0.0
overlay.isHidden = false
UIView.animate(withDuration: 0.24) {
content.transform = CGAffineTransform.identity
overlay.alpha = 70.0
}
}
private func HidePopup(overlay: UIView!, content: UIView!)
{
UIView.animate(withDuration: 0.24, animations: {
overlay.alpha = 0.0
content.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
}) {_ in
overlay.isHidden = true
}
}
private func Ask4PolicyAGBFirstTime()
{
if(!(ViewController.Settings?.policyAGBExplained ?? false))
{
self.ShowPrivatePolicyInWeb()
}
}
private func AskForPushPermissions()
{
let center = UNUserNotificationCenter.current()
center.delegate = self
center.requestAuthorization(options: [ .sound,.alert,.badge ])
{
(granted, error) in
if error == nil
{
if (granted)
{
AppDelegate.Session.NotificationGranted = true
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
}
else
{
AppDelegate.Session.NotificationGranted = false
Core.Log.Warning(msg: "User did not grant the permission to the notifications", namespace: "AppDelegate", method: "Initialize")
}
DispatchQueue.main.async
{
self.Ask4PolicyAGBFirstTime()
}
}
else
{
AppDelegate.Session.NotificationGranted = false
Core.Log.Error(err: error!, namespace: "AppDelegate", method: "Initialize")
}
}
}
// MARK: BEGIN PUSH-Notification delegates
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (_ options: UNNotificationPresentationOptions) -> Void)
{
if(ViewController.CurrentViewController != nil)
{
ViewController.CurrentViewController!.loadResults()
}
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void)
{
UIApplication.shared.applicationIconBadgeNumber = 1
}
// MARK: END PUSH-Notification delegates
//MARK: BEGIN TextField delegates
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
{
let currentString: NSString = textField.text! as NSString
let newString: NSString = currentString.replacingCharacters(in: range, with: string) as NSString
if(textField == self.PopupNewPGS_txtSampleid)
{
let filteredString = string.rangeOfCharacter(from: NSCharacterSet.alphanumerics)
return newString.length <= 14 && (filteredString != nil || string.count == 0)
}
if(textField == self.PopupNewPGS_txtZIP || textField == self.PopupNewPGS_txtPin)
{
let filteredString = string.rangeOfCharacter(from: NSCharacterSet.decimalDigits)
return newString.length <= 5 && (filteredString != nil || string.count == 0)
}
return true
}
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool
{
self.PopupNewPGS_Status.text = ""
if(textField == self.PopupNewPGS_txtSampleid)
{
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd.MM.yyyy"
let dt = dateFormatter.string(from: self.PopupNewPGS_dtBirthday.date)
self.PopupNewPGS_txtBirthday.text = dt
}
return true
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool
{
if(textField == self.PopupNewPGS_txtZIP)
{
self.PopupNewPGS_txtBirthday.becomeFirstResponder()
}
else if(textField == self.PopupNewPGS_txtBirthday)
{
self.PopupNewPGS_txtSampleid.becomeFirstResponder()
}
else if(textField == self.PopupNewPGS_txtSampleid)
{
if(ViewController.Settings?.verificator_hash == nil)
{
self.showPasswordArea()
self.PopupNewPGS_txtPassword.becomeFirstResponder()
}
else
{
self.view.endEditing(true)
self.requestPGS()
}
}
else if(textField == self.PopupNewPGS_txtPassword)
{
self.PopupNewPGS_txtPasswordConfirm.becomeFirstResponder()
}
else if(textField == self.PopupNewPGS_txtPasswordConfirm)
{
self.PopupNewPGS_txtPin.becomeFirstResponder()
}
else if(textField == self.PopupNewPGS_txtPin)
{
self.view.endEditing(true)
self.requestPGS()
}
return true
}
//MARK: END TextField delegates
@IBAction func PopupNewPGS_BtnCancelClick(_ sender: Any)
{
self.view.endEditing(true)
if(!self.PopupNewPGS_Loading.isAnimating)
{
if(self.PopupNewPGS_MasterPassword.isHidden)
{
self.PopupNewPGSHide()
}
else
{
self.hidePasswordArea()
}
}
}
private func PopupNewPGSHide()
{
UIView.animate(withDuration: 0.24, animations: {
self.PopupNewPGS_Overlay.alpha = 0.0
self.PopupNewPGS.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
}) {_ in
self.PopupNewPGS_Overlay.isHidden = true
}
}
@IBAction func PopupMenuArea_BtnSettingsClick(_ sender: Any)
{
self.view.endEditing(true)
//self.PopupMenuAreaHide()
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let settingsController = storyboard.instantiateViewController(identifier: "SettingsController")
settingsController.modalPresentationStyle = .fullScreen
let transition = CATransition()
transition.duration = 0.25
transition.type = .push
transition.subtype = .fromRight
self.view.window!.layer.add(transition, forKey: kCATransition)
self.present(settingsController, animated: false)
}
@IBAction func PopupNewPGS_BtnAddClick(_ sender: Any)
{
if(ViewController.Settings?.udid != nil)
{
self.requestPGS()
}
else
{
if(self.validatePGSData())
{
self.showPasswordArea()
}
}
}
@objc func dashedAreaLongPressed(sender: UILongPressGestureRecognizer)
{
if(ViewController.Settings?.udid != nil)
{
self.loadResults()
}
}
//MARK: END Events
//MARK: BEGIN Functions
private func showPasswordArea()
{
if(self.PopupNewPGS_MasterPassword.isHidden)
{
self.PopupNewPGS_MasterPassword.frame.origin = CGPoint(x: self.PopupNewPGS_MasterPassword.frame.width, y: self.PopupNewPGS_MasterPassword.frame.origin.y)
self.PopupNewPGS_MasterPassword.isHidden = false
UIView.animate(withDuration: 0.24, animations: {
self.PopupNewPGS_PGS.frame.origin = CGPoint(x: -self.PopupNewPGS_PGS.frame.width, y: self.PopupNewPGS_PGS.frame.origin.y)
self.PopupNewPGS_MasterPassword.frame.origin = CGPoint(x: 0, y: self.PopupNewPGS_MasterPassword.frame.origin.y)
}) {_ in
self.PopupNewPGS_BtnCancel.setTitle(Core.Lang.Get(key: "BTN_BACK"), for: .normal)
self.PopupNewPGS_BtnAdd.setTitle(Core.Lang.Get(key: "BTN_REGISTER"), for: .normal)
}
}
else
{
self.requestPGS()
}
}
@IBAction func PopupPrivatePolicy_BtnAcceptClick(_ sender: Any)
{
self.HidePrivatePolicy()
}
@IBAction func PopupPrivatePolicy_BtnAddClick(_ sender: Any)
{
self.ShowPrivatePolicyInWeb()
}
private func getLocalPolicyLink() -> String
{
let baseURL = Bundle.main.path(forResource: "privacy_policy", ofType: "html")
return baseURL ?? ""
}
private func ShowPrivatePolicyInWeb()
{
guard let url = URL(string: Core.Lang.Get(key: "AGB_POLICY_LINK")) else {
return
}
let localUrl = URL(string: getLocalPolicyLink()) ?? url
let vc = WebViewController(url: url, title: Core.Lang.Get(key: "BTN_ACCEPT_PRIVACY_POLICY"), localUrl: localUrl)
vc.parentView = self
let navVC = UINavigationController(rootViewController: vc)
present(navVC, animated: true)
}
private func ShowPrivatePolicy()
{
self.PopupPrivatePolicy_Overlay.alpha = 100
self.PopupPrivatePolicy_Overlay.isHidden = false
UIView.animate(withDuration: 0.24, animations: {
self.PopupNewPGS_Overlay.frame.origin = CGPoint(x: -self.PopupNewPGS_Overlay.frame.width, y: self.PopupNewPGS_Overlay.frame.origin.y)
self.PopupPrivatePolicy.frame.origin = CGPoint(x: 0, y: self.PopupPrivatePolicy.frame.origin.y)
})
}
private func HidePrivatePolicy()
{
self.PopupPrivatePolicy_Checkbox.setChecked(flag: true)
UIView.animate(withDuration: 0.24, animations: {
self.PopupNewPGS_Overlay.frame.origin = CGPoint(x: 0, y: self.PopupNewPGS_Overlay.frame.origin.y)
self.PopupPrivatePolicy.frame.origin = CGPoint(x: self.PopupPrivatePolicy.frame.width, y: self.PopupPrivatePolicy.frame.origin.y)
}) {_ in
self.PopupPrivatePolicy_Overlay.isHidden = true
self.PopupNewPGS_Overlay.isHidden = false
}
}
private func hidePasswordArea()
{
UIView.animate(withDuration: 0.24, animations: {
self.PopupNewPGS_PGS.frame.origin = CGPoint(x: 0, y: self.PopupNewPGS_PGS.frame.origin.y)
self.PopupNewPGS_MasterPassword.frame.origin = CGPoint(x: self.PopupNewPGS_MasterPassword.frame.width, y: self.PopupNewPGS_MasterPassword.frame.origin.y)
}) {_ in
self.PopupNewPGS_MasterPassword.isHidden = true
self.PopupNewPGS_BtnCancel.setTitle(Core.Lang.Get(key: "BTN_CANCEL"), for: .normal)
self.PopupNewPGS_BtnAdd.setTitle(Core.Lang.Get(key: "BTN_NEXT"), for: .normal)
}
}
/**
* Load results from the database and from the outside service
* @param onlyLocale - if true it will load only from locale db
*/
public func loadResults(onlyLocale: Bool = false)
{
//if password is not defined than don't make any results loading
if (AppDelegate.Session.DevicePassword == nil)
{
return
}
if(!self.LoadingData)
{
self.LoadingData = true
self.dbResults = Core.Database.Results.GetResults()
let resultsAvailable = self.dbResults != nil && self.dbResults!.count > 0
self.LBLNORESULTS.isHidden = resultsAvailable
self.ResultsTable.isHidden = !resultsAvailable
self.ResultsTable.reloadData()
UIApplication.shared.applicationIconBadgeNumber = 0
if(!onlyLocale)
{
self.MainLoadingShow()
2024-03-04 17:16:47 +01:00
//MARK: Load from server https://stackoverflow.com/questions/24190277/writing-handler-for-uialertaction
2024-01-29 16:20:42 +01:00
let getOpened = Core.Models.Request.GetOpened()
getOpened.udid = AppDelegate.Session.Device!.udid
getOpened.verificator_hash = ViewController.Settings!.verificator_hash
let requestKeyPair = Core.Security.Curve25519.GenerateKeyPair()
let currentHost = (ViewController.Settings!.labor?.host ?? .DEVELOPMENT)
Core.Https.Request.KeyExchangeAsync(host: currentHost, keyPair: requestKeyPair,
onSuccess: {
2024-03-04 17:16:47 +01:00
publicKey in
2024-01-29 16:20:42 +01:00
let sharedKey = requestKeyPair.GetSharedKey(peerPublicKeyBase64: publicKey.key)
let encryptedRequest = Core.Models.Request.EncryptedRequest(descriptor: "GetOpened", contentObject: getOpened, requestType: .REQUEST_GET_OPENED, key: sharedKey!)
2024-03-04 17:16:47 +01:00
Core.Https.Request.EncryptedRequestAsync(host: currentHost, controller: "results", action: "opened", request: encryptedRequest, serverPublicKey: publicKey, keyPair: requestKeyPair,
onSuccess: {
2024-01-29 16:20:42 +01:00
encryptedResponse in
let status = encryptedResponse.Decrypt(key: sharedKey!) as? Array<Core.Models.Database.Status>
self.dbResults = Core.Database.Results.GetResults(activeOnly: false)
if(status != nil && status!.count > 0)
{
//MARK: Check if new requests or update
for i in 0...(status!.count-1)
{
let s = status![i]
let statusText = s.results_status?.lowercased() ?? ""
let results = s.ToResults()
if(statusText.count > 0 && statusText != "none")
{
if(statusText == "not_found")
{
_ = Core.Database.Results.Delete(results: results)
DispatchQueue.main.async
{
self.ShowMessagePopup(title: "", message: Core.Lang.Get(key: "MSG_REQUESTED_RESULTS_NOT_FOUND"))
}
}
else if (statusText == "rejected")
{
DispatchQueue.main.async
{
self.ShowMessagePopup(title: "", message: Core.Lang.Get(key: "MSG_REQUESTED_RESULTS_REJECTED"))
}
}
else
{
if(!self.dbResults!.contains(where: { $0.pgs == s.pgs }))
{
if(!Core.Database.Results.Create(results: results))
{
Core.Log.Error(msg: "could not create results in db", namespace: "ViewController", method: "loadResults")
}
}
else
{
if(!Core.Database.Results.Update(results: results))
{
Core.Log.Error(msg: "could not update results in db", namespace: "ViewController", method: "loadResults")
}
}
self.dbResults = Core.Database.Results.GetResults()
DispatchQueue.main.async
{
let resultsAvailable = self.dbResults != nil && self.dbResults!.count > 0
self.LBLNORESULTS.isHidden = resultsAvailable
self.ResultsTable.isHidden = !resultsAvailable
self.ResultsTable.reloadData()
}
}
}
}
}
DispatchQueue.main.async
{
self.MainLoadingHide()
}
self.LoadingData = false
},
onError: {
error in
Core.Log.Error(msg: error, namespace: "ViewController", method: "loadResults")
self.LoadingData = false
DispatchQueue.main.async
{
self.MainLoadingHide()
}
})
},
onError: {
error in
self.LoadingData = false
Core.Log.Error(msg: error, namespace: "ViewController", method: "loadResults")
DispatchQueue.main.async
{
if(AppDelegate.Session.Maintenance && !AppDelegate.Session.MaintenanceNotified)
{
AppDelegate.Session.MaintenanceNotified = true
self.ShowMessagePopup(title: "Fehler", message: Core.Lang.Get(key: "MSG_MAINTENANCE"))
}
self.MainLoadingHide()
}
})
}
else
{
self.LoadingData = false
}
}
}
private func validatePGSData() -> Bool
{
if(!self.PopupNewPGS_Loading.isAnimating)
{
self.PopupNewPGS_ShowLoading()
let zipText = self.PopupNewPGS_txtZIP.text ?? ""
let birthdayText = self.PopupNewPGS_txtBirthday.text ?? ""
let sampleidText = self.PopupNewPGS_txtSampleid.text ?? ""
if(zipText.count==0)
{
self.PopupNewPGS_HideLoading(message: Core.Lang.Get(key: "ERROR_ENTER_ZIP"))
//self.PopupNewPGS_HideLoading(message: Core.Lang.Get(key: "ERROR_ALREADY_SUBSCRIBTED"))
}
else if(birthdayText.count == 0)
{
self.PopupNewPGS_HideLoading(message: Core.Lang.Get(key: "ERROR_ENTER_BIRTHDAY"))
}
else if(sampleidText.count == 0)
{
self.PopupNewPGS_HideLoading(message: Core.Lang.Get(key: "ERROR_ENTER_SAMPLEID"))
}
else if(zipText.count < 4)
{
self.PopupNewPGS_HideLoading(message: Core.Lang.Get(key: "ERROR_ENTER_VALID_ZIP"))
}
else if(birthdayText.count < 10 )
{
self.PopupNewPGS_HideLoading(message: Core.Lang.Get(key: "ERROR_ENTER_VALID_BIRTHDAY"))
}
else if(sampleidText.count < 6 || sampleidText.count > 14)
{
self.PopupNewPGS_HideLoading(message: Core.Lang.Get(key: "ERROR_ENTER_VALID_SAMPLEID"))
}
else
{
self.PopupNewPGS_HideLoading()
return true
}
}
return false
}
private func validateRegistrationData() -> Bool
{
if(!self.PopupNewPGS_Loading.isAnimating)
{
self.PopupNewPGS_ShowLoading()
let pinText = self.PopupNewPGS_txtPin.text ?? ""
let passwordText = self.PopupNewPGS_txtPassword.text ?? ""
if(passwordText.count == 0)
{
self.PopupNewPGS_HideLoading(message: Core.Lang.Get(key: "ERROR_ENTER_PASSWORD"))
}
else
{
if(!Core.Models.Request.ChangeVerificatorHashProvider.IsPasswordStrong(password: passwordText))
{
self.PopupNewPGS_HideLoading(message: Core.Lang.Get(key: "ERROR_ENTER_STRONG_PASSWORD"))
}
else if(self.PopupNewPGS_txtPassword.text != self.PopupNewPGS_txtPasswordConfirm.text)
{
self.PopupNewPGS_HideLoading(message: Core.Lang.Get(key: "ERROR_PASSWORD_MISMATCH"))
}
else if(pinText.count == 0)
{
self.PopupNewPGS_HideLoading(message: Core.Lang.Get(key: "ERROR_ENTER_PIN"))
}
else if(pinText.count != 5)
{
self.PopupNewPGS_HideLoading(message: Core.Lang.Get(key: "ERROR_PIN_LENGTH"))
}
else if(!self.PopupPrivatePolicy_Checkbox.IsChecked())
{
self.PopupNewPGS_HideLoading(message: Core.Lang.Get(key: "ERROR_ACCEPT_PRIVACY_POLICY"))
}
else
{
self.PopupNewPGS_HideLoading()
return true
}
}
}
return false
}
/**
* Send PGS Request to the server
*/
private func requestPGS()
{
self.PopupNewPGS_Status.text = ""
let zipText = self.PopupNewPGS_txtZIP.text ?? ""
let birthdayText = self.PopupNewPGS_txtBirthday.text ?? ""
let sampleidText = self.PopupNewPGS_txtSampleid.text ?? ""
let pinText = self.PopupNewPGS_txtPin.text ?? ""
let passwordText = self.PopupNewPGS_txtPassword.text ?? ""
if(self.validatePGSData())
{
//First installation
if(ViewController.Settings?.udid == nil)
{
if(self.validateRegistrationData())
{
self.PopupNewPGS_ShowLoading()
let encryptionKeyPair = Core.Security.Curve25519.GenerateKeyPair()
if(encryptionKeyPair.PrivateKey != nil && encryptionKeyPair.PublicKey != nil)
{
if (ViewController.Settings == nil) {
ViewController.Settings = Core.Models.Settings()
}
AppDelegate.Session.DevicePassword = passwordText
let pwdKey = Core.Security.AES.GetKey(password: passwordText)
let pwdKeyString = String(decoding: pwdKey, as: UTF8.self)
ViewController.Settings!.public_key = encryptionKeyPair.PublicKey!
let pwd_reset_hash = NSUUID().uuidString
ViewController.Settings!.password_reset_hash = pwd_reset_hash
let passwordHashKey = Core.Security.AES.GetKey(password: pwd_reset_hash + pinText)
let pwdHash = Core.Security.AES.Encrypt(value: passwordText, password: String(decoding: passwordHashKey, as: UTF8.self))
ViewController.Settings!.password_hash = pwdHash
ViewController.Settings!.verificator_hash = Core.Security.SHA512.HMAC(message: Core.Security.SHA512.VerificatorHashingValue.data(using: .utf8)!, key: pwdKeyString)
ViewController.Settings!.hashed_private_key = Core.Security.AES.Encrypt(value: encryptionKeyPair.PrivateKey!, password: pwdKeyString)
ViewController.Settings!.zip = zipText
ViewController.Settings!.SetBirthday(date: PopupNewPGS_dtBirthday.date)
ViewController.Settings!.udid = AppDelegate.Session.Device!.udid
if(!ViewController.Settings!.save(atPath: Core.System.SettingsPath()))
{
PopupNewPGS_HideLoading(message: Core.Lang.Get(key: "ERROR_COULD_NOT_SAVE"))
Core.Log.Critical(msg: "Could not save settings to the file", namespace: "ViewController", method: "requestPGS")
}
else
{
ViewController.Settings = Core.Models.Settings.loadFromFile(atPath: Core.System.SettingsPath())
}
}
else
{
PopupNewPGS_HideLoading(message: Core.Lang.Get(key: "ERROR_ENCRYPTION_NOT_SUPPORTED"))
Core.Log.Critical(msg: "Could not create Curve25519 keyPair", namespace: "ViewController", method: "requestPGS")
}
}
}
else
{
ViewController.Settings!.zip = zipText
ViewController.Settings!.SetBirthday(date: PopupNewPGS_dtBirthday.date)
if(!ViewController.Settings!.save(atPath: Core.System.SettingsPath()))
{
PopupNewPGS_HideLoading(message: Core.Lang.Get(key: "ERROR_COULD_NOT_SAVE"))
Core.Log.Critical(msg: "Could not save settings to the file", namespace: "ViewController", method: "requestPGS")
}
}
// User has password already defined
if(ViewController.Settings?.udid != nil)
{
self.PopupNewPGS_ShowLoading()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let birthday = dateFormatter.string(from: self.PopupNewPGS_dtBirthday.date)
let subscribe = Core.Models.Request.Subscribe()
subscribe.udid = AppDelegate.Session.Device!.udid
subscribe.device_token = AppDelegate.Session.Device!.token
subscribe.pgs = Core.Security.SHA512.Encrypt(data: (zipText + birthday + sampleidText).data(using: .utf8)!)
let pwd = Core.Security.AES.GetKey(password: subscribe.udid! + Core.Security.AES.PGS_ENCRYPT_PARTIAL_KEY)
subscribe.pgs_hash = Core.Security.AES.Encrypt(value: (zipText + "|" + birthday + "|" + sampleidText), password: String(decoding:pwd, as: UTF8.self))!
subscribe.client_public_key = ViewController.Settings!.public_key
subscribe.device_type = 1
subscribe.verificator_hash = ViewController.Settings!.verificator_hash
subscribe.pin = pinText
if(subscribe.pin?.isEmpty ?? true)
{
subscribe.pin = String(Int.random(in: 10000..<99999))
}
let dbResults = Core.Database.Results.GetResults(pgs: subscribe.pgs!)
if(dbResults != nil)
{
let status = dbResults?.GetStatus()
if(status == .COMPLETED)
{
self.PopupNewPGS_HideLoading(message: Core.Lang.Get(key: "MSG_PGS_ALREADY_EXISTS"))
}
else
{
self.PopupNewPGS_HideLoading(message: Core.Lang.Get(key: "MSG_PGS_RESPONSE_PENDING"))
}
}
else
{
self.hideKeyboard()
let requestKeyPair = Core.Security.Curve25519.GenerateKeyPair()
let currentHost = (ViewController.Settings!.labor?.host ?? .DEVELOPMENT)
Core.Https.Request.KeyExchangeAsync(host: currentHost, keyPair: requestKeyPair,
onSuccess: {
publicKey in
let sharedKey = requestKeyPair.GetSharedKey(peerPublicKeyBase64: publicKey.key)
let encryptedRequest = Core.Models.Request.EncryptedRequest(descriptor: "Subscribe", contentObject: subscribe, requestType: .REQUEST_SUBSCRIBE, key: sharedKey!)
Core.Https.Request.EncryptedRequestAsync(host: currentHost, controller: "results", action: "subscribe", request: encryptedRequest, serverPublicKey: publicKey, keyPair: requestKeyPair, onSuccess: {
encryptedResponse in
let response = encryptedResponse.Decrypt(key: sharedKey!)
DispatchQueue.main.async
{
if(encryptedResponse.descriptor!.lowercased() == "success")
{
if(Core.Database.Results.Create(results: subscribe.ToResults()))
{
self.PopupNewPGS_HideLoading()
self.ShowMessagePopup(title: "Vielen Dank", message: Core.Lang.Get(key: "MSG_PGS_SUCCESSFULLY_CREATED"))
self.loadResults()
DispatchQueue.main.asyncAfter(deadline: .now() + 1)
{
self.PopupNewPGSHide()
}
}
else
{
self.PopupNewPGS_HideLoading(message: Core.Lang.Get(key: "ERROR_COULD_NOT_SAVE"))
Core.Log.Critical(msg: "Could not save results to the database", namespace: "ViewController", method: "requestPGS")
}
}
else if(encryptedResponse.descriptor!.lowercased() == "status")
{
let status = (response as? Core.Models.Database.Status)
if(status == nil || !Core.Database.Results.CreateOrUpdate(results: status!.ToResults()))
{
Core.Log.Critical(msg: "Could not update status in the database", namespace: "ViewController", method: "requestPGS")
}
self.PopupNewPGS_HideLoading(message: Core.Lang.Get(key: "MSG_PGS_ALREADY_AVAILABLE"))
self.loadResults()
DispatchQueue.main.asyncAfter(deadline: .now() + 1)
{
self.PopupNewPGSHide()
}
}
else
{
let responseException = (response as? Core.Models.Response.Exception)
if(responseException != nil)
{
switch(responseException!.error_type)
{
case Core.Models.Response.Exception.Types.MaxOpenedRequestLimit :
self.PopupNewPGS_HideLoading(message: Core.Lang.Get(key: "ERROR_MAX_OPENED_REQUEST_LIMIT"))
case Core.Models.Response.Exception.Types.AlreadySubscribted:
self.PopupNewPGS_HideLoading(message: Core.Lang.Get(key: "ERROR_ALREADY_SUBSCRIBTED"))
default:
self.PopupNewPGS_HideLoading(message: Core.Lang.Get(key: "ERROR_COULD_NOT_REGISTER_PGS"))
}
}
else
{
2024-03-04 17:16:47 +01:00
self.OnErrorLoading(error: Core.Lang.Get(key: "ERROR_COULD_NOT_REGISTER_PGS"),
logmsg: "Could not register", method: "requestPGS")
2024-01-29 16:20:42 +01:00
}
}
}
},
2024-03-04 17:16:47 +01:00
onError: self.OnErrorHandler)
2024-01-29 16:20:42 +01:00
},
2024-03-04 17:16:47 +01:00
onError: self.OnErrorHandler);
2024-01-29 16:20:42 +01:00
}
}
}
}
2024-03-04 17:16:47 +01:00
private func OnErrorHandler(error: String)->Void
{
self.OnErrorLoading(error: error, logmsg: "Server not reachable", method: "requestPGS")
}
private func OnErrorLoading(error: String, logmsg: String, method: String)
{
DispatchQueue.main.async
{
self.PopupNewPGS_HideLoading(message: error)
Core.Log.Critical(msg: logmsg, namespace: "ViewController", method: method)
}
}
2024-01-29 16:20:42 +01:00
private func PopupNewPGS_ShowLoading()
{
self.PopupNewPGS_Loading.isHidden = false
self.PopupNewPGS_Loading.startAnimating()
self.PopupNewPGS_Status.text = ""
self.PopupNewPGS_Status.isHidden = true
}
private func PopupNewPGS_HideLoading(message: String? = nil)
{
self.PopupNewPGS_Loading.isHidden = true
self.PopupNewPGS_Loading.stopAnimating()
if(message != nil)
{
self.PopupNewPGS_Status.text = message!
self.PopupNewPGS_Status.isHidden = false
}
}
private func PopupPasswordConfirm_ShowLoading()
{
self.PopupPasswordConfirm_Loading.isHidden = false
self.PopupPasswordConfirm_Loading.startAnimating()
self.PopupPasswordConfirm_Status.text = ""
self.PopupPasswordConfirm_Status.isHidden = true
}
private func PopupPasswordConfirm_HideLoading(message: String? = nil)
{
self.PopupPasswordConfirm_Loading.isHidden = true
self.PopupPasswordConfirm_Loading.stopAnimating()
if(message != nil)
{
self.PopupPasswordConfirm_Status.text = message!
self.PopupPasswordConfirm_Status.isHidden = false
}
}
private func MainLoadingHide()
{
self.MainLoading.stopAnimating()
self.MainLoading.isHidden = true
self.ResultsTableRefresher.endRefreshing()
}
private func MainLoadingShow()
{
self.MainLoading.startAnimating()
self.MainLoading.isHidden = false
}
//MARK: END Functions
//MARK: BEGIN TABLE FUNCTIONS
@objc func tableRefresh(_ sender: Any)
{
self.loadResults()
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
return 70.0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: ResultsTableViewCell.identifier, for: indexPath) as! ResultsTableViewCell
if(self.dbResults != nil && self.dbResults!.count > 0 && indexPath.row >= 0 && indexPath.row < self.dbResults!.count)
{
let result = self.dbResults![indexPath.row]
cell.title.text = result.GetFormatedCreatedDate()
cell.subtitle.text = result.GetStatusText()
cell.identifier.text = result.pgs!
cell.icon.setImage(result.GetStatusIcon(), for: .normal)
cell.icon.tag = indexPath.row
if(cell.icon.allTargets.count > 0)
{
cell.icon.removeTarget(nil, action: nil, for: .allEvents)
}
cell.icon.addTarget(self, action: #selector(onTableRowIconClick), for: .touchUpInside)
cell.separatorInset = UIEdgeInsets(top: 0, left: 15, bottom: 0, right: 15)
cell.icon.isUserInteractionEnabled = true
cell.selectionStyle = .default;
let bgView = UIView()
bgView.backgroundColor = .clear
cell.selectedBackgroundView = bgView
// MARK: Very dirty to start auto download here but for now no chance to do other way
// because we need to change the icon of the row
if(result.GetStatus() == .COMPLETED && result.available && !result.picked_up && !self.CurrentDownloadProcessing && AppDelegate.Session.Device!.token != nil)
{
let gifLoading = UIImage.gifImageWithName("ic_downloading")
cell.icon.setImage(gifLoading, for: .normal)
cell.subtitle.text = Core.Lang.Get(key: "LBL_DOWNLOADING")
// Download in background
DispatchQueue.global(qos: .background).async
{
self.downloadResults(results: result, button: cell.icon, show: false)
}
}
}
return cell
}
func numberOfSections(in tableView: UITableView) -> Int
{
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return (self.dbResults != nil ? self.dbResults!.count : 0)
}
func tableView(_ tableView: UITableView, titleForDeleteConfirmationButtonForRowAt indexPath: IndexPath) -> String?
{
return Core.Lang.Get(key: "BTN_DELETE")
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath)
{
if editingStyle == .delete
{
if(self.dbResults != nil && self.dbResults!.count > 0 && indexPath.row >= 0 && indexPath.row < self.dbResults!.count && !self.CurrentDownloadProcessing)
{
let result = self.dbResults![indexPath.row]
if(Core.Database.Results.Delete(results: result))
{
self.loadResults(onlyLocale: true)
self.deleteOnServer(results: result)
}
}
}
}
//MARK: END TABLE FUNCTIONS
//MARK: BEGIN Download & PDF FUNCTIONS
@objc func onTableRowIconClick(sender: UIButton)
{
let button = sender as UIButton
if(self.dbResults != nil && self.dbResults!.count > 0 && button.tag >= 0 && button.tag < self.dbResults!.count && !self.CurrentDownloadProcessing)
{
let results = self.dbResults![button.tag]
if(results.GetStatus() == .COMPLETED && results.available && !results.picked_up && !self.CurrentDownloadProcessing)
{
let gifLoading = UIImage.gifImageWithName("ic_downloading")
sender.setImage(gifLoading, for: .normal)
self.downloadResults(results: results, button: button)
}
else if(results.GetStatus() == .COMPLETED && results.available && results.picked_up)
{
self.encryptPDF(results: results)
}
}
}
//MARK: send the download request to the server
private func downloadResults(results: Core.Models.Database.Results, button: UIButton!, show: Bool = true)
{
self.CurrentDownloadProcessing = true
let subscribe = Core.Models.Request.Subscribe()
subscribe.udid = AppDelegate.Session.Device!.udid
subscribe.device_token = AppDelegate.Session.Device!.token!
subscribe.pgs = results.pgs
subscribe.client_public_key = ViewController.Settings!.public_key
subscribe.verificator_hash = ViewController.Settings!.verificator_hash
self.MainLoadingShow()
let requestKeyPair = Core.Security.Curve25519.GenerateKeyPair()
let currentHost = ViewController.Settings!.labor?.host ?? .DEVELOPMENT
Core.Https.Request.KeyExchangeAsync(host: currentHost, keyPair: requestKeyPair,
onSuccess: {
publicKey in
let sharedKey = requestKeyPair.GetSharedKey(peerPublicKeyBase64: publicKey.key)
let encryptedRequest = Core.Models.Request.EncryptedRequest(descriptor: "Subscribe", contentObject: subscribe, requestType: .REQUEST_SUBSCRIBE, key: sharedKey!)
Core.Https.Request.EncryptedRequestAsync(host: currentHost, controller: "results", action: "download", request: encryptedRequest, serverPublicKey: publicKey, keyPair: requestKeyPair, onSuccess: {
encryptedResponse in
self.CurrentDownload = encryptedResponse.Decrypt(key: sharedKey!) as? Core.Models.Response.Download
if(self.CurrentDownload != nil)
{
self.CurrentDownloadResults = results
DispatchQueue.main.async
{
if(button != nil)
{
button.setImage(results.GetStatusIcon(), for: .normal)
}
self.processEncryption(show: show)
self.MainLoadingHide()
}
}
else
{
DispatchQueue.main.async
{
self.MainLoadingHide()
}
}
self.CurrentDownloadProcessing = false
},
onError: {
error in
self.CurrentDownloadProcessing = false
Core.Log.Error(msg: error, namespace: "ViewController", method: "downloadResults")
DispatchQueue.main.async
{
self.MainLoadingHide()
}
})
},
onError: {
error in
Core.Log.Error(msg: error, namespace: "ViewController", method: "downloadResults")
self.CurrentDownloadProcessing = false
DispatchQueue.main.async
{
self.MainLoadingHide()
}
})
}
//MARK: User has to confirm always decryption of encrypted results by master password
private func encryptPDF(results: Core.Models.Database.Results)
{
if(results.GetStatus() == .COMPLETED && results.available && results.picked_up)
{
self.CurrentDownload = nil
self.CurrentDownloadResults = results
//showPasswordConfirm()
self.processEncryption()
}
}
//MARK: send pickedup checksum to the file
private func sendPickedUp(checksum: Core.Models.Request.CheckFileChecksum)
{
self.MainLoadingShow()
let requestKeyPair = Core.Security.Curve25519.GenerateKeyPair()
let currentHost = ViewController.Settings!.labor?.host ?? .DEVELOPMENT
Core.Https.Request.KeyExchangeAsync(host: currentHost, keyPair: requestKeyPair,
onSuccess: {
publicKey in
let sharedKey = requestKeyPair.GetSharedKey(peerPublicKeyBase64: publicKey.key)
let encryptedRequest = Core.Models.Request.EncryptedRequest(descriptor: "CheckFileChecksum", contentObject: checksum, requestType: .REQUEST_CHECKSUM, key: sharedKey!)
Core.Https.Request.EncryptedRequestAsync(host: currentHost, controller: "results", action: "pickedup", request: encryptedRequest, serverPublicKey: publicKey, keyPair: requestKeyPair, onError: {
error in
Core.Log.Error(msg: error, namespace: "ViewController", method: "sendPickedUp")
})
DispatchQueue.main.async
{
self.MainLoadingHide()
}
}, onError: {
error in
Core.Log.Error(msg: error, namespace: "ViewController", method: "sendPickedUp")
})
}
//MARK: deletes results on the server
private func deleteOnServer(results: Core.Models.Database.Results)
{
self.MainLoadingShow()
let requestKeyPair = Core.Security.Curve25519.GenerateKeyPair()
let currentHost = ViewController.Settings!.labor?.host ?? .DEVELOPMENT
Core.Https.Request.KeyExchangeAsync(host: currentHost, keyPair: requestKeyPair,
onSuccess: {
publicKey in
let subscribe = Core.Models.Request.Subscribe()
subscribe.udid = AppDelegate.Session.Device!.udid
subscribe.device_token = AppDelegate.Session.Device!.token!
subscribe.pgs = results.pgs
subscribe.client_public_key = ViewController.Settings!.public_key
subscribe.verificator_hash = ViewController.Settings!.verificator_hash
let sharedKey = requestKeyPair.GetSharedKey(peerPublicKeyBase64: publicKey.key)
let encryptedRequest = Core.Models.Request.EncryptedRequest(descriptor: "Subscribe", contentObject: subscribe, requestType: .REQUEST_SUBSCRIBE, key: sharedKey!)
Core.Https.Request.EncryptedRequestAsync(host: currentHost, controller: "results", action: "unsubscribe", request: encryptedRequest, serverPublicKey: publicKey, keyPair: requestKeyPair, onError: {
error in
Core.Log.Error(msg: error, namespace: "ViewController", method: "deleteOnServer")
})
DispatchQueue.main.async
{
self.MainLoadingHide()
}
},
onError: {
error in
Core.Log.Error(msg: error, namespace: "ViewController", method: "deleteOnServer")
})
}
private func showPasswordConfirm()
{
self.PopupPasswordConfirm_txtPassword.text = ""
self.PopupPasswordConfirm_HideLoading(message: Core.Lang.Get(key: "ERROR_ENTER_PASSWORD"))
self.PopupPasswordConfirm.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
self.PopupPasswordConfirm_Overlay.alpha = 0.0
self.PopupPasswordConfirm_Overlay.isHidden = false
UIView.animate(withDuration: 0.24) {
self.PopupPasswordConfirm.transform = CGAffineTransform.identity
self.PopupPasswordConfirm_Overlay.alpha = 70.0
}
}
private func hidePasswordConfirm()
{
self.view.endEditing(true)
if(!self.PopupPasswordConfirm_Loading.isAnimating)
{
UIView.animate(withDuration: 0.24, animations: {
self.PopupPasswordConfirm_Overlay.alpha = 0.0
self.PopupPasswordConfirm.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
}) {_ in
self.PopupPasswordConfirm_Overlay.isHidden = true
}
}
}
//MARK: download encrypted results from the server and let them user decrypt it over password confirmation popup
private func encryptDownload(show: Bool = true)
{
if(self.CurrentDownload != nil)
{
let decryptedPrivateKey = Core.Security.AES.Decrypt(value: ViewController.Settings!.hashed_private_key!, password: AppDelegate.Session.DevicePassword)
if (decryptedPrivateKey != nil)
{
let keyPair = Core.Security.Curve25519.CreateKeyPair(_privateKey: decryptedPrivateKey!, _publicKey: ViewController.Settings!.public_key!)
let sharedKey = keyPair.GetSharedKey(peerPublicKeyBase64: self.CurrentDownload!.server_public_key!)
if(sharedKey != nil)
{
let decrypted_content = Core.Security.AES.Decrypt(value: self.CurrentDownload!.encrypted_content!, deriveKey: sharedKey!)
if(decrypted_content != nil)
{
let local_encrypted = Core.Security.AES.Encrypt(value: decrypted_content!, password: AppDelegate.Session.DevicePassword)
if(local_encrypted != nil)
{
let now = Date()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
self.CurrentDownloadResults!.picked_up = true
self.CurrentDownloadResults!.picked_up_ts = dateFormatter.string(from: now)
self.CurrentDownloadResults!.file_checksum = Core.Security.SHA512.Encrypt(value: decrypted_content!)
if(Core.System.WriteToEncryptedStorage(filename: self.CurrentDownloadResults!.pgs!, data: local_encrypted!.data(using: .utf8)!) &&
Core.Database.Results.Update(results: self.CurrentDownloadResults!))
{
self.loadResults(onlyLocale: true)
if(show)
{
self.loadPDF(decryptedContent: Data(base64Encoded: decrypted_content!)!)
}
let checksum = Core.Models.Request.CheckFileChecksum()
checksum.pgs = self.CurrentDownloadResults!.pgs
checksum.udid = AppDelegate.Session.Device!.udid
checksum.device_token = AppDelegate.Session.Device!.token!
checksum.client_public_key = ViewController.Settings!.public_key
checksum.verificator_hash = ViewController.Settings!.verificator_hash
checksum.file_checksum = self.CurrentDownloadResults!.file_checksum
self.sendPickedUp(checksum: checksum)
self.CurrentDownload = nil
self.CurrentDownloadResults = nil
}
else
{
self.PopupPasswordConfirm_HideLoading(message: Core.Lang.Get(key: "ERROR_COULD_NOT_SAVE_ENCRYPTED"))
Core.Log.Critical(msg: "could not store encrypted downloaded results", namespace: "ViewController", method: "encryptDownload")
}
}
else
{
self.PopupPasswordConfirm_HideLoading(message: Core.Lang.Get(key: "ERROR_COULD_NOT_SAVE_ENCRYPTED"))
Core.Log.Critical(msg: "could not store encrypted downloaded results", namespace: "ViewController", method: "encryptDownload")
}
}
else
{
self.PopupPasswordConfirm_HideLoading(message: Core.Lang.Get(key: "ERROR_COULD_NOT_DECRYPT"))
Core.Log.Critical(msg: "could not decrypt downloaded results", namespace: "ViewController", method: "encryptDownload")
}
}
else
{
self.PopupPasswordConfirm_HideLoading(message: Core.Lang.Get(key: "ERROR_COULD_NOT_DECRYPT"))
Core.Log.Critical(msg: "could not decrypt downloaded results", namespace: "ViewController", method: "encryptDownload")
}
}
else
{
self.PopupPasswordConfirm_HideLoading(message: Core.Lang.Get(key: "ERROR_INVALID_PASSWORD"))
}
}
else
{
self.PopupPasswordConfirm_HideLoading(message: Core.Lang.Get(key: "ERROR_DOWNLOAD_NOT_FOUND"))
Core.Log.Critical(msg: "no download found for encryption", namespace: "ViewController", method: "encryptDownload")
}
}
/**
* Loads encrypted file from the encrypted storage and decrypts it by master password of user
*/
private func encryptFile()
{
if(self.CurrentDownloadResults != nil)
{
let filePath = Core.System.GetURLForStorageEncryptedFile(filename: self.CurrentDownloadResults!.pgs!)
if(filePath != nil && Core.System.FileExists(atPath: filePath!.path))
{
let encrypted_data = Core.System.ReadFromEncryptedStorage(filename: self.CurrentDownloadResults!.pgs!)
if(encrypted_data != nil)
{
let encrypted_content = String(data: encrypted_data!, encoding: .utf8)!
let local_decrypted = Core.Security.AES.Decrypt(value: encrypted_content, password: AppDelegate.Session.DevicePassword)
if(local_decrypted != nil)
{
self.loadResults()
self.loadPDF(decryptedContent: Data(base64Encoded: local_decrypted!)!)
self.CurrentDownload = nil
self.CurrentDownloadResults = nil
}
else
{
self.PopupPasswordConfirm_HideLoading(message: Core.Lang.Get(key: "ERROR_INVALID_PASSWORD"))
}
}
else
{
self.PopupPasswordConfirm_HideLoading(message: Core.Lang.Get(key: "ERROR_ENCRYPTED_FILE_NOT_FOUND"))
Core.Log.Critical(msg: "encrypted file not found", namespace: "ViewController", method: "encryptFile")
}
}
else
{
self.PopupPasswordConfirm_HideLoading(message: Core.Lang.Get(key: "ERROR_ENCRYPTED_FILE_NOT_FOUND"))
Core.Log.Critical(msg: "encrypted file not found", namespace: "ViewController", method: "encryptFile")
}
}
else
{
self.PopupPasswordConfirm_HideLoading(message: Core.Lang.Get(key: "ERROR_ENCRYPTED_FILE_NOT_FOUND"))
Core.Log.Critical(msg: "encrypted file not found", namespace: "ViewController", method: "encryptFile")
}
}
//MARK: Loads PDFViewer with decrypted content
private func loadPDF(decryptedContent: Data)
{
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let pdfViewController = storyboard.instantiateViewController(withIdentifier: "PDFViewController") as! PDFViewController
pdfViewController.setContent(data: decryptedContent)
pdfViewController.modalPresentationStyle = .fullScreen
let transition = CATransition()
transition.duration = 0.25
transition.type = .push
transition.subtype = .fromRight
self.view.window!.layer.add(transition, forKey: kCATransition)
self.present(pdfViewController, animated: false)
}
@IBAction func PopupPasswordConfirm_BtnCancelClick(_ sender: Any)
{
self.hidePasswordConfirm()
}
@IBAction func PopupPasswordConfirm_BtnEncryptClick(_ sender: Any)
{
self.processEncryption()
}
/**
* Encrypts ether already downloaded results from the device or downloads first the results from the server and encrypts thet after downloading
*/
private func processEncryption(show: Bool = true)
{
if(self.CurrentDownload != nil)
{
self.encryptDownload(show: show)
}
else if(self.CurrentDownloadResults != nil)
{
self.encryptFile()
}
}
//MARK: END Download & PDF FUNCTIONS
//MARK: BEGIN Bottom Menu
@IBAction func BottonMenuOpenerClick(_ sender: Any)
{
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let settingsPwdController = storyboard.instantiateViewController(identifier: "SettingsController")
settingsPwdController.modalPresentationStyle = .fullScreen
let transition = CATransition()
transition.duration = 0.25
transition.type = .push
transition.subtype = .fromRight
self.view.window!.layer.add(transition, forKey: kCATransition)
self.present(settingsPwdController, animated: false)
}
//MARK: END Bottom Menu
}