diff --git a/TraccarClient.xcodeproj/project.xcworkspace/xcuserdata/g.makhoul.xcuserdatad/UserInterfaceState.xcuserstate b/TraccarClient.xcodeproj/project.xcworkspace/xcuserdata/g.makhoul.xcuserdatad/UserInterfaceState.xcuserstate index c6bc58bbd229e30140ad471222a14cdc49a5d103..ee97d722ff20244397ecf1f17416f4ff3694b060 100644 Binary files a/TraccarClient.xcodeproj/project.xcworkspace/xcuserdata/g.makhoul.xcuserdatad/UserInterfaceState.xcuserstate and b/TraccarClient.xcodeproj/project.xcworkspace/xcuserdata/g.makhoul.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/TraccarClient/InAppSettings.bundle/Root.plist b/TraccarClient/InAppSettings.bundle/Root.plist index 4bd83cce3a3d01f8ecea064012ffc26b5dcf95fe..3a29caf2bfb38242748b51e07eb2a5c94666eecb 100644 --- a/TraccarClient/InAppSettings.bundle/Root.plist +++ b/TraccarClient/InAppSettings.bundle/Root.plist @@ -32,7 +32,7 @@ </dict> <dict> <key>DefaultValue</key> - <string>https://dev-fleet-api.nmo.ai/</string> + <string></string> <key>Type</key> <string>PSTextFieldSpecifier</string> <key>Title</key> diff --git a/TraccarClient/LoginViewController/Model/LoginModelController.swift b/TraccarClient/LoginViewController/Model/LoginModelController.swift index 15793ee51e5cc98dffd031f35bca941293f15b56..42880f8c09618f90b59baea72d4e993f99e566f8 100644 --- a/TraccarClient/LoginViewController/Model/LoginModelController.swift +++ b/TraccarClient/LoginViewController/Model/LoginModelController.swift @@ -69,7 +69,11 @@ extension LoginModelController { var params: PARAMS = [:] for item in fields { - if item.type == .text { + if item.field == .domain { + UserDefaults.standard.set("\(item.value.value).nmo.ai", forKey: "xcompany") + UserDefaults.standard.set("https://\(item.value.value).nmo.ai/", forKey: "server_url_preference") + } + if item.type == .text && item.field != .domain { params.add(item.field.rawValue, item.value.value) } } @@ -120,6 +124,8 @@ extension LoginModelController { }catch { print("Error while decoding response: \(String(data: result.dataResponse?.data ?? Data(), encoding: .utf8) ?? "")") } + } else if result.statusCode == 404 { + ok("Domain is not valid!") } else { diff --git a/TraccarClient/MainViewController/ConnectViewController.swift b/TraccarClient/MainViewController/ConnectViewController.swift index d352d659af3100d36399a436f5e24c5c09f6e8df..762c4f9a91ac93cce2aa458f3b7b8e6c94f1225c 100644 --- a/TraccarClient/MainViewController/ConnectViewController.swift +++ b/TraccarClient/MainViewController/ConnectViewController.swift @@ -26,7 +26,8 @@ final class ConnectViewController: KNViewController { private var timer: Timer? private var isInBackground: Bool = false private var currentBackgroundDate = Date() - + let status: Bool = false + // MARK: - LifeCycle override func viewDidLoad() { super.viewDidLoad() @@ -70,8 +71,7 @@ final class ConnectViewController: KNViewController { // MARK: - Actions @IBAction func connectTapped(_ sender: UIButton) { - let status = userDefaults.bool(forKey: "service_status_preference") - if status { + if userDefaults.bool(forKey: "service_status_preference") { endTimer() userDefaults.set(false, forKey: "service_status_preference") statusChanged(to: false) @@ -84,8 +84,8 @@ final class ConnectViewController: KNViewController { userDefaults.set(true, forKey: "service_status_preference") statusChanged(to: true) TransactionsViewController.addMessage(NSLocalizedString("Service created", comment: "")) - trackingController = TrackingController() - trackingController?.start() + AppDelegate.instance.trackingController = TrackingController() + AppDelegate.instance.trackingController?.start() } } @@ -112,14 +112,20 @@ extension ConnectViewController { } @objc private func appResumed() { - let difference = currentBackgroundDate.timeIntervalSince(Date()) - print(currentBackgroundDate, difference, totalTime) - - let seconds = Int(abs(difference)) - totalTime += seconds - - timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(updateTime), userInfo: nil, repeats: true) - timer?.fire() + if userDefaults.bool(forKey: "service_status_preference") { + let difference = currentBackgroundDate.timeIntervalSince(Date()) + print(currentBackgroundDate, difference, totalTime) + + let seconds = Int(abs(difference)) + totalTime += seconds + + timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(updateTime), userInfo: nil, repeats: true) + timer?.fire() + } else { + timer?.invalidate() + timerLabel.set(text: "") + totalTime = 0 + } } func endTimer() { diff --git a/TraccarClient/Network+Endpoint.swift b/TraccarClient/Network+Endpoint.swift index 1a5cb621f0e05929e62e865e7852685e4203280a..2d58c0088d5a758297f96c06c5d1156b37a28f4e 100644 --- a/TraccarClient/Network+Endpoint.swift +++ b/TraccarClient/Network+Endpoint.swift @@ -24,7 +24,7 @@ enum Endpoint: String, CaseIterable { case .development, .sandbox: return "https://dev-nc-teams-api.nmo.ai" case .production: - return "https://dev-nc-teams-api.nmo.ai" + return "https://me-nc-teams-api.nmo.ai" } } diff --git a/TraccarClient/NetworkRequest.swift b/TraccarClient/NetworkRequest.swift index 3468138309c1df68cf4d1561e5f17bfbaecb122b..7af57e642a26344968ae698b7f5629f4f4f1b99a 100644 --- a/TraccarClient/NetworkRequest.swift +++ b/TraccarClient/NetworkRequest.swift @@ -30,11 +30,11 @@ final class NetworkRequest: NSObject { // MARK: - HTTP Headers var headers : HTTPHeaders { var _headers: HTTPHeaders = [:] - _headers["Content-Type"] = "application/json" + + _headers["Caontent-Type"] = "application/json" _headers["Accept-Language"] = "en" _headers["X-App-Client"] = "ios" - _headers["x-Company"] = "dev-nextcloud.nmo.ai" - + _headers["x-Company"] = "\(UserDefaults.standard.string(forKey: "xcompany") ?? "")" return _headers } @@ -76,8 +76,8 @@ final class NetworkRequest: NSObject { } func getQueryStringParameter(url: String, param: String) -> String? { - guard let url = URLComponents(string: url) else { return nil } - return url.queryItems?.first(where: { $0.name == param })?.value + guard let url = URLComponents(string: url) else { return nil } + return url.queryItems?.first(where: { $0.name == param })?.value } func request(endpoint: URLConvertible, method: HTTPMethod, _ completion: @escaping ResultClosure) { @@ -97,8 +97,8 @@ final class NetworkRequest: NSObject { encoding: JSONEncoding.default, headers: headers, interceptor: self).validate(statusCode: customValidation).responseData { response in - completion(NetworkResultModel(dataResponse: response)) - } + completion(NetworkResultModel(dataResponse: response)) + } } func request(endpoint: URLConvertible, method: HTTPMethod, params: Parameters? = nil, _ completion: @escaping ResultClosure) { @@ -117,8 +117,8 @@ final class NetworkRequest: NSObject { encoding: JSONEncoding.default, headers: headers, interceptor: self).validate(statusCode: customValidation).responseData { response in - completion(NetworkResultModel(dataResponse: response)) - } + completion(NetworkResultModel(dataResponse: response)) + } } func request(endpoint: URLConvertible, method: HTTPMethod, params: Parameters? = nil, options: RequestOptions? = nil, _ completion: @escaping ResultClosure) { @@ -152,11 +152,11 @@ final class NetworkRequest: NSObject { encoding: JSONEncoding.default, headers: headers, interceptor: self).responseData { response in - completion(NetworkResultModel(dataResponse: response)) + completion(NetworkResultModel(dataResponse: response)) } } } - + func requestToUpload(_ imageToUpload: UIImage, endpoint: URLConvertible, params: Parameters? = nil, options: RequestOptions? = nil, _ completion: @escaping ResultClosure){ if !isConnected { @@ -164,8 +164,8 @@ final class NetworkRequest: NSObject { return } - var customValidation: [Int] = [] - customValidation.append(contentsOf: 1...400) + var customValidation: [Int] = [] + customValidation.append(contentsOf: 1...400) customValidation.append(contentsOf: 402...999) guard let imageData = imageToUpload.jpegData(compressionQuality: 0.50) else { return } @@ -189,7 +189,7 @@ final class NetworkRequest: NSObject { multipartFormData.append(imageData, withName: "file", fileName: "file\(timeStamp).jpeg", mimeType: "image/jpeg") }, to: endpoint, method: .post , headers: headers).responseData { response in completion(NetworkResultModel(dataResponse: response)) - } + } } } @@ -200,10 +200,10 @@ final class NetworkRequest: NSObject { return } - var customValidation: [Int] = [] - customValidation.append(contentsOf: 1...400) + var customValidation: [Int] = [] + customValidation.append(contentsOf: 1...400) customValidation.append(contentsOf: 402...999) - + let timeStamp = Int(Date().timeIntervalSince1970 * 1000) if let options = options { @@ -230,7 +230,7 @@ final class NetworkRequest: NSObject { func requestToDownload(downloadURL: String, completion: @escaping (_ isDownloaded: Bool, _ downloadPath: String?) -> Void ){ if !isConnected { -// completion(NetworkResultModel(error: NetworkError(.noInternet))) + // completion(NetworkResultModel(error: NetworkError(.noInternet))) return } @@ -341,30 +341,30 @@ extension NetworkRequest: RequestInterceptor { return } -// let params = ["refresh_token" : refresh_token] -// -// api.refreshToken(params: params) { result in -// if result.success { -// if let newAccessToken = result.data as? String { -// UserDefaults.standard.setValue(newAccessToken, forKey: Keys.User.access_token) -// completion(true) -// } else { -// completion(false) -// } -// } else { -// guard let error = result.appError else { -// completion(false) -// return -// } -// -// if error.type == .invalidRefreshToken { -// app.delegate.presentLoginViewController(with: error.message) -// completion(false) -// } else if error.type == .invalidAccessToken { -// completion(false) -// } -// } -// } + // let params = ["refresh_token" : refresh_token] + // + // api.refreshToken(params: params) { result in + // if result.success { + // if let newAccessToken = result.data as? String { + // UserDefaults.standard.setValue(newAccessToken, forKey: Keys.User.access_token) + // completion(true) + // } else { + // completion(false) + // } + // } else { + // guard let error = result.appError else { + // completion(false) + // return + // } + // + // if error.type == .invalidRefreshToken { + // app.delegate.presentLoginViewController(with: error.message) + // completion(false) + // } else if error.type == .invalidAccessToken { + // completion(false) + // } + // } + // } } } diff --git a/TraccarClient/SettingsViewController/Cells/SettingsSegmentTableViewCell/SettingsSegmentTableViewCell.swift b/TraccarClient/SettingsViewController/Cells/SettingsSegmentTableViewCell/SettingsSegmentTableViewCell.swift index fca552174c45849af85be96a74c9c78a104b0c1d..1bf43f3017eb5fcbe027e990761f685ea27d0163 100644 --- a/TraccarClient/SettingsViewController/Cells/SettingsSegmentTableViewCell/SettingsSegmentTableViewCell.swift +++ b/TraccarClient/SettingsViewController/Cells/SettingsSegmentTableViewCell/SettingsSegmentTableViewCell.swift @@ -7,6 +7,9 @@ // import UIKit +protocol SettingsSegmentTableViewCellDelegate { + func didUpdateSegment(value: String) +} class SettingsSegmentTableViewCell: KNTableViewCell { // MARK: - Outlets @@ -15,7 +18,10 @@ class SettingsSegmentTableViewCell: KNTableViewCell { // MARK: - Properties let defaults = UserDefaults.standard - + var index: Int = 0 + var delegate: SettingsSegmentTableViewCellDelegate? + var model: DefaultsModel? + // MARK: - LifeCycle override func awakeFromNib() { super.awakeFromNib() @@ -28,11 +34,30 @@ class SettingsSegmentTableViewCell: KNTableViewCell { .foregroundColor: UIColor.white ] segments.setTitleTextAttributes(selectedAttributes, for: .selected) + segments.addTarget(self, action: #selector(segmentChanged), for: .valueChanged) + } + + @objc private func segmentChanged(_ sender: UISegmentedControl) { + switch sender.selectedSegmentIndex { + case 0: + defaults.set("low", forKey: model?.key ?? "") + case 1: + defaults.set("medium", forKey: model?.key ?? "") + case 2: + defaults.set("high", forKey: model?.key ?? "") + + default: + defaults.set("medium", forKey: model?.key ?? "") + } + delegate?.didUpdateSegment(value: model?.title ?? "") } - func set(defaultValue: DefaultsModel) { + func set(defaultValue: DefaultsModel, index: Int) { + self.index = 0 + self.model = defaultValue + titleLabel.set(text: defaultValue.title) - let selected = defaults.string(forKey: defaultValue.value) + let selected = defaultValue.value as? String ?? "" if selected == "high" { segments.selectedSegmentIndex = 2 diff --git a/TraccarClient/SettingsViewController/Cells/SettingsSwitchTableViewCell/SettingsSwitchTableViewCell.swift b/TraccarClient/SettingsViewController/Cells/SettingsSwitchTableViewCell/SettingsSwitchTableViewCell.swift index ea20f09c4c734be1d92d1dfe6e9a8efac1dfc52a..1bda577b7be890515e17e0a9bf4632fab5515ec1 100644 --- a/TraccarClient/SettingsViewController/Cells/SettingsSwitchTableViewCell/SettingsSwitchTableViewCell.swift +++ b/TraccarClient/SettingsViewController/Cells/SettingsSwitchTableViewCell/SettingsSwitchTableViewCell.swift @@ -8,6 +8,10 @@ import UIKit +protocol SettingsSwitchTableViewCellDelegate { + func didUpdateSwitch(value: String) +} + class SettingsSwitchTableViewCell: KNTableViewCell { // MARK: - Outlets @IBOutlet private weak var titleLabel: UILabel! @@ -15,7 +19,10 @@ class SettingsSwitchTableViewCell: KNTableViewCell { // MARK: - Properties let defaults = UserDefaults.standard - + var index: Int = 0 + var model: DefaultsModel? + var delegate: SettingsSwitchTableViewCellDelegate? + // MARK: - LifeCycle override func awakeFromNib() { super.awakeFromNib() @@ -24,10 +31,19 @@ class SettingsSwitchTableViewCell: KNTableViewCell { private func setupUI() { titleLabel.set(text: "", color: .main, font: .semibold(16)) + switchView.addTarget(self, action: #selector(switchChanged), for: .valueChanged) + } + + @objc private func switchChanged(_ sender: UISwitch) { + defaults.set(sender.isOn, forKey: model?.key ?? "") + delegate?.didUpdateSwitch(value: model?.title ?? "") } - func set(defaultValue: DefaultsModel) { + func set(defaultValue: DefaultsModel, index: Int) { + self.index = index + self.model = defaultValue + titleLabel.set(text: defaultValue.title) - switchView.isOn = defaults.bool(forKey: defaultValue.value) + switchView.isOn = defaultValue.value as? Bool ?? false } } diff --git a/TraccarClient/SettingsViewController/Cells/SettingsTextTableViewCell/SettingsTextTableViewCell.swift b/TraccarClient/SettingsViewController/Cells/SettingsTextTableViewCell/SettingsTextTableViewCell.swift index af6fe31aebaf68866891f88b472d04b5c4ec4ba7..c4cb0770e6995d95dfbbcfb5f31a59b2987af01c 100644 --- a/TraccarClient/SettingsViewController/Cells/SettingsTextTableViewCell/SettingsTextTableViewCell.swift +++ b/TraccarClient/SettingsViewController/Cells/SettingsTextTableViewCell/SettingsTextTableViewCell.swift @@ -7,6 +7,9 @@ // import UIKit +protocol SettingsTextTableViewCellDelegate { + func didUpdateText(value: String) +} class SettingsTextTableViewCell: KNTableViewCell { // MARK: - Outlets @@ -15,6 +18,9 @@ class SettingsTextTableViewCell: KNTableViewCell { // MARK: - Properties let defaults = UserDefaults.standard + var index: Int = 0 + var model: DefaultsModel? + var delegate: SettingsTextTableViewCellDelegate? // MARK: - LifeCycle override func awakeFromNib() { @@ -24,16 +30,26 @@ class SettingsTextTableViewCell: KNTableViewCell { private func setupUI() { titleLabel.set(text: "", color: .main, font: .semibold(16)) + valueField.textAlignment = .center valueField.textColor = .black valueField.font = .semibold(16) + valueField.delegate = self } - func set(defaultValue: DefaultsModel) { + func set(defaultValue: DefaultsModel, index: Int) { + self.index = index + self.model = defaultValue titleLabel.set(text: defaultValue.title) - - valueField.text = defaults.string(forKey: defaultValue.value) + valueField.text = defaultValue.value as? String ?? "" valueField.keyboardType = defaultValue.keyboardType } } + +extension SettingsTextTableViewCell: UITextFieldDelegate { + func textFieldDidEndEditing(_ textField: UITextField) { + defaults.set(textField.text, forKey: model?.key ?? "") + delegate?.didUpdateText(value: model?.title ?? "") + } +} diff --git a/TraccarClient/SettingsViewController/DefaultsModel.swift b/TraccarClient/SettingsViewController/DefaultsModel.swift index 7fafc6aa6b7f3bf8ae0dfd41c1279edeb40a1057..90fc57fca7eae20bfdf9a6f3c5db48c4f0ff250e 100644 --- a/TraccarClient/SettingsViewController/DefaultsModel.swift +++ b/TraccarClient/SettingsViewController/DefaultsModel.swift @@ -11,13 +11,24 @@ import UIKit struct DefaultsModel { var title: String = "" - var value: String = "" + var value: Any? + var key: String = "" var keyboardType: UIKeyboardType = .default + var type: Types - init(title: String, value: String, keyboardType: UIKeyboardType) { + init(title: String, value: Any, keyboardType: UIKeyboardType, type: Types, key: String) { self.title = title self.value = value self.keyboardType = keyboardType + self.type = type + self.key = key } } + +enum Types: String { + case integer + case double + case boolean + case string +} diff --git a/TraccarClient/SettingsViewController/SettingsViewController.swift b/TraccarClient/SettingsViewController/SettingsViewController.swift index 89b75e06622d9015c486572322c504379c9cc4fe..a3e7415a96b9721fd9c38694936c45be094d9fb1 100644 --- a/TraccarClient/SettingsViewController/SettingsViewController.swift +++ b/TraccarClient/SettingsViewController/SettingsViewController.swift @@ -15,11 +15,13 @@ final class SettingsViewController: KNViewController { @IBOutlet weak var tableView: UITableView! // MARK: - Properties - private var textDefaults: [DefaultsModel] = [DefaultsModel(title: "Frequency", value: "frequency_preference", keyboardType: .numberPad), - DefaultsModel(title: "Distance", value: "distance_preference", keyboardType: .numberPad), - DefaultsModel(title: "Angle", value: "angle_preference", keyboardType: .numberPad)] - private var switchDefaults: [DefaultsModel] = [DefaultsModel(title: "Offline buffering", value: "buffer_preference", keyboardType: .default)] - private var multiChoicesDefaults: [DefaultsModel] = [DefaultsModel(title: "Accuracy", value: "accuracy_preference", keyboardType: .default)] + private var textDefaults: [DefaultsModel] = [DefaultsModel(title: "Frequency", value: UserDefaults.standard.string(forKey: "frequency_preference") ?? "", keyboardType: .numberPad, type: .integer, key: "frequency_preference"), + DefaultsModel(title: "Distance", value: UserDefaults.standard.string(forKey: "distance_preference") ?? "", keyboardType: .numberPad, type: .double, key: "distance_preference"), + DefaultsModel(title: "Angle", value: UserDefaults.standard.string(forKey: "angle_preference") ?? "", keyboardType: .numberPad, type: .double, key: "angle_preference")] + private var switchDefaults: [DefaultsModel] = [DefaultsModel(title: "Offline buffering", value: UserDefaults.standard.bool(forKey: "buffer_preference") , keyboardType: .default, type: .boolean, key: "buffer_preference")] + private var multiChoicesDefaults: [DefaultsModel] = [DefaultsModel(title: "Accuracy", value: UserDefaults.standard.string(forKey: "accuracy_preference") ?? "", keyboardType: .default, type: .string, key: "accuracy_preference")] + + var trackingController: TrackingController? // MARK: - LifeCycle override func viewDidLoad() { @@ -29,7 +31,7 @@ final class SettingsViewController: KNViewController { private func setupUI() { customHeaderView.set(type: .settings, delegate: self) - + tableView.delegate = self tableView.dataSource = self @@ -74,17 +76,21 @@ extension SettingsViewController: UITableViewDelegate, UITableViewDataSource { func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { if indexPath.section == 0 { let cell = tableView.dequeue(withCell: SettingsTextTableViewCell.self) - cell.set(defaultValue: textDefaults[indexPath.row]) + cell.set(defaultValue: textDefaults[indexPath.row], index: indexPath.row) + cell.delegate = self + return cell } if indexPath.section == 1 { let cell = tableView.dequeue(withCell: SettingsSegmentTableViewCell.self) - cell.set(defaultValue: multiChoicesDefaults[indexPath.row]) + cell.set(defaultValue: multiChoicesDefaults[indexPath.row], index: indexPath.row) + cell.delegate = self return cell } if indexPath.section == 2 { let cell = tableView.dequeue(withCell: SettingsSwitchTableViewCell.self) - cell.set(defaultValue: switchDefaults[indexPath.row]) + cell.set(defaultValue: switchDefaults[indexPath.row], index: indexPath.row) + cell.delegate = self return cell } return UITableViewCell() @@ -94,3 +100,32 @@ extension SettingsViewController: UITableViewDelegate, UITableViewDataSource { 70 } } + +// MARK: - CellsDelegate +extension SettingsViewController: SettingsTextTableViewCellDelegate, + SettingsSwitchTableViewCellDelegate, + SettingsSegmentTableViewCellDelegate { + func didUpdateText(value: String) { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + TransactionsViewController.addMessage(NSLocalizedString("\(value) changed", comment: "")) + AppDelegate.instance.trackingController = TrackingController() + AppDelegate.instance.trackingController?.start() + } + } + + func didUpdateSwitch(value: String) { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + TransactionsViewController.addMessage(NSLocalizedString("\(value) changed", comment: "")) + AppDelegate.instance.trackingController = TrackingController() + AppDelegate.instance.trackingController?.start() + } + } + + func didUpdateSegment(value: String) { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + TransactionsViewController.addMessage(NSLocalizedString("\(value) changed", comment: "")) + AppDelegate.instance.trackingController = TrackingController() + AppDelegate.instance.trackingController?.start() + } + } +} diff --git a/TraccarClient/TransactionsViewController/Cells/TransactionTableViewCell.swift b/TraccarClient/TransactionsViewController/Cells/TransactionTableViewCell.swift index c865139666ea5fe219458f6675a8968603e6e81f..8eb1fdbffccb15f2d2dbc5ba3537b626c0a465c5 100644 --- a/TraccarClient/TransactionsViewController/Cells/TransactionTableViewCell.swift +++ b/TraccarClient/TransactionsViewController/Cells/TransactionTableViewCell.swift @@ -29,13 +29,13 @@ class TransactionTableViewCell: KNTableViewCell { func set(status: String) { descLabel.set(text: status) - if status.contains("created") { + if status.contains("created") || status.contains("changed"){ statusIcon.set(icon: .thumbsup) } if status.contains("update") { statusIcon.set(icon: .updated) } - if !status.contains("update") && !status.contains("created") { + if !status.contains("update") && !status.contains("created") && !status.contains("changed") { statusIcon.set(icon: .thumbsDown) }