123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982 |
- //
- // BackupRestoreView.swift
- // NexilisLite
- //
- // Created by Akhmad Al Qindi Irsyam on 16/02/23.
- //
- import UIKit
- import QuickLook
- //import Zip
- import NotificationBannerSwift
- import ZIPFoundation
- public class BackupRestoreView: UIViewController, UITableViewDataSource, UITableViewDelegate {
- private var tableView: UITableView!
- var centerLogo = UIImageView()
- var centerLogoIsRotated = false
- let activityIndicatorBackup = UIActivityIndicatorView(style: .medium)
- let activityIndicatorRestore = UIActivityIndicatorView(style: .medium)
- let titleBackup = UILabel()
- let titleRestore = UILabel()
- let titleLastBackup = UILabel()
- let titleTotalSize = UILabel()
- let labelRestoring = UILabel()
- let labelPreparing = UILabel()
-
- var isBackupStart = false
- var isRestoreStart = false
-
- var valueLastBackup = ""
- var valuesizeBackup = ""
- var dayLastBackup = ""
- var timeLastBackup = ""
- var choosenOption = "M"
-
- var fileIdBackup = ""
- var recordSizeBackup = ""
- var optionBackup = ""
- var recordSizeRestore: Int64 = 0
-
- let separator = String(unicodeCodepoint: 0x06) ?? ""
- public override func viewDidLoad() {
- super.viewDidLoad()
-
- navigationController?.navigationBar.topItem?.backButtonTitle = "Back".localized()
-
- tableView = UITableView()
- view.addSubview(tableView)
- tableView.anchor(top: view.safeAreaLayoutGuide.topAnchor, left: view.leftAnchor, bottom: view.safeAreaLayoutGuide.bottomAnchor, right: view.rightAnchor)
- tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cellBackupRestore")
- tableView.dataSource = self
- tableView.delegate = self
-
- tableView.separatorStyle = .none
-
- if #available(iOS 15.0, *) {
- tableView.sectionHeaderTopPadding = 0
- }
-
-
- let center: NotificationCenter = NotificationCenter.default
- center.addObserver(self, selector: #selector(backupAvailability(notification:)), name: NSNotification.Name(rawValue: "backupAvailability"), object: nil)
- requestBackupAvailability()
- }
-
- public override func viewDidAppear(_ animated: Bool) {
- self.navigationController?.navigationBar.topItem?.title = "Backup & Restore".localized()
- self.navigationController?.navigationBar.setNeedsLayout()
- self.title = "Backup & Restore".localized()
- }
-
- @objc private func backupAvailability(notification: NSNotification) {
- DispatchQueue.main.async { [self] in
- let data:[AnyHashable : Any] = notification.userInfo!
- if let message = data["message"] as? TMessage {
- fileIdBackup = message.getBody(key: CoreMessage_TMessageKey.FILE_ID, default_value: "")
- recordSizeBackup = message.getBody(key: CoreMessage_TMessageKey.RECORD_SIZE, default_value: "0")
- optionBackup = message.getBody(key: CoreMessage_TMessageKey.TYPE, default_value: "")
- let filesize = message.getBody(key: CoreMessage_TMessageKey.FILE_SIZE, default_value: "0")
- let createdDate = message.getBody(key: CoreMessage_TMessageKey.CREATED_DATE, default_value: "\(Date().currentTimeMillis())")
- if optionBackup != "AUTO" {
- let date = Date(milliseconds: Int64(createdDate)!)
- let calendar = Calendar.current
-
- if (calendar.isDateInToday(date)) {
- dayLastBackup = "Today".localized()
- } else {
- let startOfNow = calendar.startOfDay(for: Date())
- let startOfTimeStamp = calendar.startOfDay(for: date)
- let components = calendar.dateComponents([.day], from: startOfNow, to: startOfTimeStamp)
- let day = -(components.day!)
- if day == 1{
- dayLastBackup = "Yesterday".localized()
- } else {
- let formatter = DateFormatter()
- formatter.dateFormat = "dd MMMM yyyy"
- let lang: String = SecureUserDefaults.shared.value(forKey: "i18n_language") ?? "en"
- if lang == "id" {
- formatter.locale = NSLocale(localeIdentifier: "id") as Locale?
- }
- let stringFormat = formatter.string(from: date as Date)
- dayLastBackup = stringFormat
- }
- }
-
- let formatter = DateFormatter()
- formatter.dateFormat = "HH:mm"
- formatter.locale = NSLocale(localeIdentifier: "id") as Locale?
- timeLastBackup = formatter.string(from: date as Date)
-
- valueLastBackup = dayLastBackup.localized() + ", " + timeLastBackup
- valuesizeBackup = Units(bytes: Int64(filesize)!).getReadableUnit()
-
- tableView.beginUpdates()
- tableView.reloadRows(at: [IndexPath(row: 0, section: 0)], with: .none)
- tableView.endUpdates()
- } else {
- valueLastBackup = "-"
- valuesizeBackup = "-"
- tableView.beginUpdates()
- tableView.reloadRows(at: [IndexPath(row: 0, section: 0), IndexPath(row: 0, section: 2)], with: .none)
- tableView.endUpdates()
- }
- }
- }
- }
-
- private func requestBackupAvailability() {
- DispatchQueue.global().async {
- _ = Nexilis.write(message: CoreMessage_TMessageBank.getBackupAvailability())
- }
- }
-
- private func getFileName(option: String = "", fileId: String = "", withoutZIP: Bool = false) -> String {
- if !fileId.isEmpty {
- if withoutZIP {
- return "\(User.getMyPin()!)_\(option)_\(fileId)"
- }
- return "\(User.getMyPin()!)_\(option)_\(fileId).zip"
- }
- return "\(User.getMyPin()!).zip"
- }
-
- public func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
- if section == 2 && isBackupStart {
- let container = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.width, height: 20))
- container.addSubview(labelPreparing)
- labelPreparing.anchor(left: container.leftAnchor, paddingLeft: 10, centerY: container.centerYAnchor)
- labelPreparing.textColor = .gray
- labelPreparing.font = .systemFont(ofSize: 12)
- return container
- } else if section == 3 && isRestoreStart {
- let container = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.width, height: 20))
- container.addSubview(labelRestoring)
- labelRestoring.anchor(left: container.leftAnchor, paddingLeft: 10, centerY: container.centerYAnchor)
- labelRestoring.textColor = .gray
- labelRestoring.font = .systemFont(ofSize: 12)
- return container
- }
- return UIView()
- }
-
- public func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
- if section == 2 && isBackupStart {
- return 30
- } else if section == 3 && isRestoreStart {
- return 30
- }
- return 20
- }
-
- public func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
- .leastNormalMagnitude
- }
-
- public func numberOfSections(in tableView: UITableView) -> Int {
- return 4
- }
- public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
- if section == 1 {
- return 2
- } else if section == 3 {
- return 0
- }
- return 1
- }
-
- public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
- let cell = tableView.dequeueReusableCell(withIdentifier: "cellBackupRestore", for: indexPath as IndexPath)
- makeViewBackup(cell: cell, indexPath: indexPath)
- return cell
- }
-
- public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
- tableView.deselectRow(at: indexPath, animated: true)
- if indexPath.section == 1 && indexPath.row == 0 {
- let controller = BackupRestoreOption()
- controller.selected = choosenOption
- controller.isSelected = { choosen in
- self.choosenOption = choosen
- tableView.beginUpdates()
- tableView.reloadRows(at: [indexPath], with: .none)
- tableView.endUpdates()
- }
- navigationController?.show(controller, sender: nil)
- } else if indexPath.section == 1 && indexPath.row == 1 {
- if isBackupStart || isRestoreStart {
- return
- }
- if !CheckConnection.isConnectedToNetwork() {
- let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
- imageView.tintColor = .white
- let banner = FloatingNotificationBanner(title: "Check your connection".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .danger, colors: nil, iconPosition: .center)
- banner.show()
- return
- }
- isBackupStart = true
- labelPreparing.text = "Preparing...".localized();
- tableView.beginUpdates()
- tableView.reloadRows(at: [indexPath], with: .none)
- tableView.reloadSections(IndexSet(integer: 2), with: .none)
- tableView.endUpdates()
- animateBackup()
- backupData(indexPath: indexPath)
- } else if indexPath.section == 2 {
- if isBackupStart || isRestoreStart || valueLastBackup == "-" {
- return
- }
- if !CheckConnection.isConnectedToNetwork() {
- let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
- imageView.tintColor = .white
- let banner = FloatingNotificationBanner(title: "Check your connection".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .danger, colors: nil, iconPosition: .center)
- banner.show()
- return
- }
- isRestoreStart = true
- labelRestoring.text = "Downloading...".localized();
- tableView.beginUpdates()
- tableView.reloadRows(at: [indexPath, IndexPath(row: 1, section: 1)], with: .none)
- tableView.reloadSections(IndexSet(integer: 3), with: .none)
- tableView.endUpdates()
- let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
- let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
- let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
- if let dirPath = paths.first {
- let fileURL = URL(fileURLWithPath: dirPath).appendingPathComponent(getFileName(option: optionBackup, fileId: fileIdBackup))
- if !FileManager.default.fileExists(atPath: fileURL.path) {
- Download().startHTTP(forKey: getFileName(option: optionBackup, fileId: fileIdBackup), isImage: false) { (name, progress) in
- DispatchQueue.main.async { [self] in
- guard progress == 100 else {
- labelRestoring.text = "Downloading...".localized() + " \(progress)%"
- return
- }
- labelRestoring.text = "Restoring...".localized()
- restoreData(file: fileURL, dirPath: dirPath, indexPath: indexPath)
- }
- }
- } else {
- labelRestoring.text = "Restoring...".localized()
- restoreData(file: fileURL, dirPath: dirPath, indexPath: indexPath)
- }
- }
- }
- }
-
- private func animateBackup() {
- UIView.animate(withDuration: 2, animations: { [self] in
- centerLogo.transform = centerLogo.transform.rotated(by: .pi)
- })
- UIView.animate(withDuration: 2, animations: { [self] in
- centerLogo.transform = centerLogo.transform.rotated(by: .pi)
- })
- DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: { [self] in
- if isBackupStart {
- animateBackup()
- }
- })
- }
-
- private func enableButtonBackup() {
- titleBackup.text = "Back Up Now".localized()
- titleBackup.textColor = .systemBlue
- activityIndicatorBackup.stopAnimating()
- }
-
- private func disableButtonBackup(isRestore: Bool = false) {
- titleBackup.textColor = .gray
- if !isRestore{
- titleBackup.text = "Backing Up...".localized()
- activityIndicatorBackup.startAnimating()
- }
- }
-
- private func enableButtonRestore() {
- titleRestore.text = "Restore Now".localized()
- titleRestore.textColor = .systemBlue
- activityIndicatorRestore.stopAnimating()
- }
-
- private func disableButtonRestore(isBackup: Bool = false) {
- titleRestore.textColor = .gray
- if !isBackup && !activityIndicatorRestore.isAnimating {
- titleRestore.text = "Restoring...".localized()
- activityIndicatorRestore.startAnimating()
- } else {
- titleRestore.text = "Restore Now".localized()
- activityIndicatorRestore.stopAnimating()
- }
- }
-
- private func makeViewBackup(cell: UITableViewCell, indexPath: IndexPath) {
- cell.contentView.subviews.forEach { $0.removeFromSuperview() }
- if indexPath.section == 0 {
- cell.selectionStyle = .none
- let container = UIView()
- container.addTopBorder(with: .lightGray.withAlphaComponent(0.5), andWidth: 1)
- container.addBottomBorder(with: .lightGray.withAlphaComponent(0.5), andWidth: 1)
- let content = cell.contentView
- content.addSubview(container)
- container.anchor(top: content.topAnchor, left: content.leftAnchor, bottom: content.bottomAnchor, right: content.rightAnchor)
-
- let containerLogo = UIView()
- containerLogo.layer.borderWidth = 1
- containerLogo.layer.borderColor = UIColor.lightGray.cgColor
- containerLogo.layer.cornerRadius = 8
- containerLogo.clipsToBounds = true
- container.addSubview(containerLogo)
- containerLogo.anchor(top: container.topAnchor, left: container.leftAnchor, paddingTop: 10, paddingLeft: 10, width: 70, height: 70)
-
- let logo = UIImageView()
- logo.image = UIImage(systemName: "icloud")
- logo.contentMode = .scaleAspectFit
- logo.tintColor = .systemBlue
- containerLogo.addSubview(logo)
- logo.anchor(centerX: containerLogo.centerXAnchor, centerY: containerLogo.centerYAnchor, width: 60, height: 60)
-
- centerLogo.image = UIImage(systemName: "arrow.clockwise")
- centerLogo.contentMode = .scaleAspectFit
- centerLogo.tintColor = .systemBlue
- if !isBackupStart {
- if !centerLogoIsRotated{
- centerLogoIsRotated = true
- centerLogo.transform = centerLogo.transform.rotated(by: .pi / 2)
- //print("LOHE \(centerLogo.transform)")
- }
- }
- logo.addSubview(centerLogo)
- centerLogo.anchor(top: logo.topAnchor, left: logo.leftAnchor, paddingTop: 22, paddingLeft: 23)
-
- container.addSubview(titleLastBackup)
- titleLastBackup.anchor(top: container.topAnchor, left: containerLogo.rightAnchor, paddingTop: 25, paddingLeft: 10)
- titleLastBackup.text = "Last Backup".localized() + ": " + valueLastBackup
- titleLastBackup.textColor = .gray
- titleLastBackup.font = .systemFont(ofSize: 12)
-
- container.addSubview(titleTotalSize)
- titleTotalSize.anchor(top: titleLastBackup.bottomAnchor, left: containerLogo.rightAnchor, paddingLeft: 10)
- titleTotalSize.text = "Total Size".localized() + ": " + valuesizeBackup
- titleTotalSize.textColor = .gray
- titleTotalSize.font = .systemFont(ofSize: 12)
-
- let descBackup = UILabel()
- container.addSubview(descBackup)
- descBackup.anchor(top: containerLogo.bottomAnchor, left: container.leftAnchor, bottom: container.bottomAnchor, right: container.rightAnchor, paddingTop: 2, paddingLeft: 10, paddingBottom: 10, paddingRight: 10)
- descBackup.text = "Back up your chat history to server so if you lose your phone or switch to a new one or logout your account, your chat history is safe. You can restore your chat history when you relogin your account.".localized()
- descBackup.numberOfLines = 0
- descBackup.textColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .black
- descBackup.font = .systemFont(ofSize: 12)
- } else if indexPath.section == 1 {
- if indexPath.row == 0 {
- let container = UIView()
- container.addTopBorder(with: .lightGray.withAlphaComponent(0.5), andWidth: 1)
- container.addBottomBorder(with: .lightGray.withAlphaComponent(0.5), andWidth: 0.5, x: 10)
- let content = cell.contentView
- content.addSubview(container)
- container.anchor(top: content.topAnchor, left: content.leftAnchor, bottom: content.bottomAnchor, right: content.rightAnchor)
-
- let titleBackupOption = UILabel()
- container.addSubview(titleBackupOption)
- titleBackupOption.anchor(left: container.leftAnchor, paddingLeft: 10, centerY: container.centerYAnchor)
- titleBackupOption.text = "Back Up Option".localized()
- titleBackupOption.textColor = .systemBlue
- titleBackupOption.font = .systemFont(ofSize: 14)
-
- let arrowRight = UIImageView()
- arrowRight.tintColor = .gray
- arrowRight.image = UIImage(systemName: "chevron.right")
- container.addSubview(arrowRight)
- arrowRight.anchor(right: container.rightAnchor, paddingRight: 10, centerY: container.centerYAnchor)
-
- let titleChoosenOption = UILabel()
- container.addSubview(titleChoosenOption)
- titleChoosenOption.anchor(right: arrowRight.leftAnchor, paddingRight: 10, centerY: container.centerYAnchor)
- titleChoosenOption.text = BackupRestoreOption().convertSelectedOptionWithCode(code: choosenOption)
- titleChoosenOption.textColor = .lightGray
- titleChoosenOption.font = .systemFont(ofSize: 14)
-
- } else {
- let container = UIView()
- container.addBottomBorder(with: .lightGray.withAlphaComponent(0.5), andWidth: 1)
- let content = cell.contentView
- content.addSubview(container)
- container.anchor(top: content.topAnchor, left: content.leftAnchor, bottom: content.bottomAnchor, right: content.rightAnchor)
-
- container.addSubview(titleBackup)
- titleBackup.anchor(left: container.leftAnchor, paddingLeft: 10, centerY: container.centerYAnchor)
- titleBackup.font = .systemFont(ofSize: 14)
-
- container.addSubview(activityIndicatorBackup)
- activityIndicatorBackup.anchor(right: container.rightAnchor, paddingRight: 10, centerY: container.centerYAnchor)
-
- if isBackupStart || isRestoreStart {
- cell.selectionStyle = .none
- disableButtonBackup(isRestore: isRestoreStart)
- } else {
- cell.selectionStyle = .default
- enableButtonBackup()
- }
- }
- } else {
- let container = UIView()
- container.addTopBorder(with: .lightGray.withAlphaComponent(0.5), andWidth: 1)
- container.addBottomBorder(with: .lightGray.withAlphaComponent(0.5), andWidth: 1)
- let content = cell.contentView
- content.addSubview(container)
- container.anchor(top: content.topAnchor, left: content.leftAnchor, bottom: content.bottomAnchor, right: content.rightAnchor)
-
- container.addSubview(titleRestore)
- titleRestore.anchor(left: container.leftAnchor, paddingLeft: 10, centerY: container.centerYAnchor)
- titleRestore.font = .systemFont(ofSize: 14)
-
- container.addSubview(activityIndicatorRestore)
- activityIndicatorRestore.anchor(right: container.rightAnchor, paddingRight: 10, centerY: container.centerYAnchor)
-
- if isBackupStart || isRestoreStart || valueLastBackup == "-" {
- cell.selectionStyle = .none
- disableButtonRestore(isBackup: isBackupStart || valueLastBackup == "-")
- } else {
- cell.selectionStyle = .default
- enableButtonRestore()
- }
- }
- }
-
- private func restoreMessage(nameColumn: [String], message: [String]) {
- Database.shared.database?.inTransaction({ (fmdb, rollback) in
- do {
- var cValues: [String: Any] = [:]
- var columnNameMessage: [String] = []
- if let tableInfo = Database.shared.getRecords(fmdb: fmdb,query: "PRAGMA table_info(MESSAGE)") {
- while tableInfo.next() {
- columnNameMessage.append(tableInfo.string(forColumn: "name")!)
- }
- tableInfo.close()
- }
- for i in 0..<message.count {
- if i > nameColumn.count - 1 {
- continue
- }
- if columnNameMessage.contains(nameColumn[i]) {
- cValues[nameColumn[i]] = message[i] == "<empty>" || message[i] == "null" ? "" : message[i]
- }
- }
- _ = try Database.shared.insertRecord(fmdb: fmdb, table: "MESSAGE", cvalues: cValues, replace: true)
- if !(cValues["thumb_id"] as? String ?? "").isEmpty {
- let thumbId = cValues["thumb_id"] as! String
- let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
- let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
- let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
- if let dirPath = paths.first {
- let thumbURL = URL(fileURLWithPath: dirPath).appendingPathComponent(thumbId)
- if !FileManager.default.fileExists(atPath: thumbURL.path) {
- Download().startHTTP(forKey: thumbId) { (name, progress) in}
- }
- }
- }
- recordSizeRestore += 1
- } catch {
- rollback.pointee = true
- print("Access database error: \(error.localizedDescription)")
- }
- })
- }
-
- private func restoreUcList(dataUcList: [String]) {
- Database.shared.database?.inTransaction({ (fmdb, rollback) in
- do {
- _ = try Database.shared.insertRecord(fmdb: fmdb, table: "MESSAGE_SUMMARY", cvalues: [
- "l_pin" : dataUcList[0],
- "message_id" : dataUcList[1],
- "counter" : 0
- ], replace: true)
- recordSizeRestore += 1
- } catch {
- rollback.pointee = true
- print("Access database error: \(error.localizedDescription)")
- }
- })
- }
-
- private func restoreFormData(nameColumn: [String], data: [String]) {
- Database.shared.database?.inTransaction({ (fmdb, rollback) in
- do {
- var cValues: [String: Any] = [:]
- var columnNameMessage: [String] = []
- if let tableInfo = Database.shared.getRecords(fmdb: fmdb,query: "PRAGMA table_info(FORM_DATA)") {
- while tableInfo.next() {
- columnNameMessage.append(tableInfo.string(forColumn: "name")!)
- }
- tableInfo.close()
- }
- for i in 0..<data.count {
- if columnNameMessage.contains(nameColumn[i]) {
- cValues[nameColumn[i]] = data[i] == "<empty>" || data[i] == "null" ? "" : data[i]
- }
- }
- _ = try Database.shared.insertRecord(fmdb: fmdb, table: "FORM_DATA", cvalues: cValues, replace: true)
- recordSizeRestore += 1
- } catch {
- rollback.pointee = true
- print("Access database error: \(error.localizedDescription)")
- }
- })
- }
-
- private func restoreTaskPIC(nameColumn: [String], data: [String]) {
- Database.shared.database?.inTransaction({ (fmdb, rollback) in
- do {
- var cValues: [String: Any] = [:]
- var columnNameMessage: [String] = []
- if let tableInfo = Database.shared.getRecords(fmdb: fmdb,query: "PRAGMA table_info(TASK_PIC)") {
- while tableInfo.next() {
- columnNameMessage.append(tableInfo.string(forColumn: "name")!)
- }
- tableInfo.close()
- }
- for i in 0..<data.count {
- if columnNameMessage.contains(nameColumn[i]) {
- cValues[nameColumn[i]] = data[i] == "<empty>" || data[i] == "null" ? "" : data[i]
- }
- }
- _ = try Database.shared.insertRecord(fmdb: fmdb, table: "TASK_PIC", cvalues: cValues, replace: true)
- recordSizeRestore += 1
- } catch {
- rollback.pointee = true
- print("Access database error: \(error.localizedDescription)")
- }
- })
- }
-
- private func restoreTaskDetail(nameColumn: [String], data: [String]) {
- Database.shared.database?.inTransaction({ (fmdb, rollback) in
- do {
- var cValues: [String: Any] = [:]
- var columnNameMessage: [String] = []
- if let tableInfo = Database.shared.getRecords(fmdb: fmdb,query: "PRAGMA table_info(TASK_DETAIL)") {
- while tableInfo.next() {
- columnNameMessage.append(tableInfo.string(forColumn: "name")!)
- }
- tableInfo.close()
- }
- for i in 0..<data.count {
- if columnNameMessage.contains(nameColumn[i]) {
- cValues[nameColumn[i]] = data[i] == "<empty>" || data[i] == "null" ? "" : data[i]
- }
- }
- _ = try Database.shared.insertRecord(fmdb: fmdb, table: "TASK_DETAIL", cvalues: cValues, replace: true)
- recordSizeRestore += 1
- } catch {
- rollback.pointee = true
- print("Access database error: \(error.localizedDescription)")
- }
- })
- }
-
- private func restoreData(file: URL, dirPath: String, indexPath: IndexPath) {
- recordSizeRestore = 0
- let fileManager = FileManager()
- var destinationURL = URL(fileURLWithPath: dirPath)
- destinationURL.appendPathComponent("unzipItem\(Date().currentTimeMillis())")
- do {
- try fileManager.createDirectory(at: destinationURL, withIntermediateDirectories: true, attributes: nil)
- // try Zip.unzipFile(file, destination: destinationURL, overwrite: true, password: nil)
- try fileManager.unzipItem(at: file, to: destinationURL)
-
- let files = try FileManager.default.contentsOfDirectory(atPath: destinationURL.path)
- for file in files {
- let nameFile = (file as NSString).lastPathComponent
- let fileURL = destinationURL.appendingPathComponent(nameFile)
- var newFileExt: URL?
- newFileExt = fileURL.deletingPathExtension().appendingPathExtension("txt")
- try FileManager.default.moveItem(at: fileURL, to: newFileExt!)
- var textReading = try String(contentsOf: newFileExt ?? fileURL, encoding: .utf8)
- textReading = textReading.replacingOccurrences(of: "<NL>", with: "\n").replacingOccurrences(of: "<CR>", with: "\r")
- let valueText = textReading.components(separatedBy: "\n")
- if nameFile.trimmingCharacters(in: .whitespacesAndNewlines) == "MESSAGE" {
- let nameColumn = valueText[0].components(separatedBy: separator)
- for i in 1..<valueText.count - 1 {
- let dataMessage = valueText[i].components(separatedBy: separator)
- restoreMessage(nameColumn: nameColumn, message: dataMessage)
- }
- } else if nameFile.trimmingCharacters(in: .whitespacesAndNewlines) == "UC_LIST" {
- for i in 1..<valueText.count - 1 {
- let dataUcList = valueText[i].components(separatedBy: separator)
- restoreUcList(dataUcList: dataUcList)
- }
- } else if nameFile.trimmingCharacters(in: .whitespacesAndNewlines) == "FORM_DATA" {
- let nameColumn = valueText[0].components(separatedBy: separator)
- for i in 1..<valueText.count - 1 {
- let dataFormData = valueText[i].components(separatedBy: separator)
- restoreFormData(nameColumn: nameColumn, data: dataFormData)
- }
- } else if nameFile.trimmingCharacters(in: .whitespacesAndNewlines) == "TASK_PIC" {
- let nameColumn = valueText[0].components(separatedBy: separator)
- for i in 1..<valueText.count - 1 {
- let dataTaskPIC = valueText[i].components(separatedBy: separator)
- restoreTaskPIC(nameColumn: nameColumn, data: dataTaskPIC)
- }
- }
- else if nameFile.trimmingCharacters(in: .whitespacesAndNewlines) == "TASK_DETAIL" {
- let nameColumn = valueText[0].components(separatedBy: separator)
- for i in 1..<valueText.count - 1 {
- let dataTaskDetail = valueText[i].components(separatedBy: separator)
- restoreTaskDetail(nameColumn: nameColumn, data: dataTaskDetail)
- }
- }
- }
- if recordSizeRestore < Int64(recordSizeBackup) ?? 0 {
- labelRestoring.text = "Backup files are corrupted".localized()
- tableView.reloadSections(IndexSet(integer: 3), with: .none)
- } else {
- labelRestoring.text = "Successfully Restored Data".localized()
- }
- // DispatchQueue.global().async { [self] in
- // _ = Nexilis.write(message: CoreMessage_TMessageBank.getBackupRestored(option: optionBackup, fileid: fileIdBackup))
- // }
- DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: { [self] in
- isRestoreStart = false
- valueLastBackup = "-"
- valuesizeBackup = "-"
- tableView.beginUpdates()
- tableView.reloadRows(at: [indexPath, IndexPath(row: 1, section: 1), IndexPath(row: 0, section: 0), IndexPath(row: 0, section: 2)], with: .none)
- tableView.reloadSections(IndexSet(integer: 3), with: .none)
- tableView.endUpdates()
- })
- } catch {
- //print(error)
- self.view.makeToast("Backup files are corrupted".localized(), duration: 3)
- // DispatchQueue.global().async { [self] in
- // _ = Nexilis.write(message: CoreMessage_TMessageBank.getBackupRestored(option: optionBackup, fileid: fileIdBackup))
- // }
- DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: { [self] in
- isRestoreStart = false
- valueLastBackup = "-"
- valuesizeBackup = "-"
- tableView.beginUpdates()
- tableView.reloadRows(at: [indexPath, IndexPath(row: 1, section: 1), IndexPath(row: 0, section: 0), IndexPath(row: 0, section: 2)], with: .none)
- tableView.reloadSections(IndexSet(integer: 3), with: .none)
- tableView.endUpdates()
- })
- }
- }
-
- private func backupData(indexPath: IndexPath) {
- Database.shared.database?.inTransaction({ (fmdb, rollback) in
- do {
- let documentDirectoryUrl = try! FileManager.default.url(
- for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true
- )
- var recordSize: Int64 = 0
-
- //Make File MESSAGE
- let file_message = documentDirectoryUrl.appendingPathComponent("MESSAGE").appendingPathExtension("")
- if let tableInfo = Database.shared.getRecords(fmdb: fmdb,query: "PRAGMA table_info(MESSAGE)") {
- var text_message = ""
- while tableInfo.next() {
- if text_message.isEmpty {
- text_message.append(tableInfo.string(forColumn: "name")!)
- } else {
- text_message.append(separator)
- text_message.append(tableInfo.string(forColumn: "name")!)
- }
- }
- text_message.append("\n")
- tableInfo.close()
-
- if let cursorData = Database.shared.getRecords(fmdb: fmdb,query: "SELECT * FROM MESSAGE") {
- let columnCount = cursorData.columnCount
- var value_m = ""
- while cursorData.next() {
- for i in 0..<columnCount {
- value_m.append(cursorData.string(forColumnIndex: i) == nil ? "null" : cursorData.string(forColumnIndex: i)!.isEmpty ? "<empty>" : cursorData.string(forColumnIndex: i)!)
- value_m.append(separator)
- }
- value_m.append("\n")
- recordSize += 1
- }
- text_message.append(value_m)
- cursorData.close()
- }
- do {
- try text_message.write(to: file_message, atomically: true, encoding: .utf8)
- }
- catch {
- //print(error)
- }
- }
-
- //Make File UC_LIST
- let file_uc_list = documentDirectoryUrl.appendingPathComponent("UC_LIST").appendingPathExtension("")
- if let tableInfo = Database.shared.getRecords(fmdb: fmdb,query: "PRAGMA table_info(MESSAGE_SUMMARY)") {
- var text_uc_list = ""
- while tableInfo.next() {
- if tableInfo.string(forColumn: "name")! == "counter" {
- continue
- }
- if text_uc_list.isEmpty {
- text_uc_list.append(tableInfo.string(forColumn: "name")! == "l_pin" ? "opposite" : tableInfo.string(forColumn: "name")!)
- } else {
- text_uc_list.append(separator)
- text_uc_list.append(tableInfo.string(forColumn: "name")! == "l_pin" ? "opposite" : tableInfo.string(forColumn: "name")!)
- }
- }
- text_uc_list.append("\n")
- tableInfo.close()
-
- if let cursorData = Database.shared.getRecords(fmdb: fmdb,query: "SELECT * FROM MESSAGE_SUMMARY") {
- let columnCount = cursorData.columnCount
- var value_m = ""
- while cursorData.next() {
- for i in 0..<columnCount - 1 {
- value_m.append(cursorData.string(forColumnIndex: i) == nil ? "null" : cursorData.string(forColumnIndex: i)!.isEmpty ? "<empty>" : cursorData.string(forColumnIndex: i)!)
- value_m.append(separator)
- }
- value_m.append("\n")
- recordSize += 1
- }
- text_uc_list.append(value_m)
- cursorData.close()
- }
- do {
- try text_uc_list.write(to: file_uc_list, atomically: true, encoding: .utf8)
- }
- catch {//print(error)
-
- }
- }
-
- //Make File FORM_DATA
- let file_form_data = documentDirectoryUrl.appendingPathComponent("FORM_DATA").appendingPathExtension("")
- if let tableInfo = Database.shared.getRecords(fmdb: fmdb,query: "PRAGMA table_info(FORM_DATA)") {
- var text_form_data = ""
- while tableInfo.next() {
- if text_form_data.isEmpty {
- text_form_data.append(tableInfo.string(forColumn: "name")!)
- } else {
- text_form_data.append(separator)
- text_form_data.append(tableInfo.string(forColumn: "name")!)
- }
- }
- text_form_data.append("\n")
- tableInfo.close()
-
- if let cursorData = Database.shared.getRecords(fmdb: fmdb,query: "SELECT * FROM FORM_DATA") {
- let columnCount = cursorData.columnCount
- var value_m = ""
- while cursorData.next() {
- for i in 0..<columnCount - 1 {
- value_m.append(cursorData.string(forColumnIndex: i) == nil ? "null" : cursorData.string(forColumnIndex: i)!.isEmpty ? "<empty>" : cursorData.string(forColumnIndex: i)!)
- value_m.append(separator)
- }
- value_m.append("\n")
- recordSize += 1
- }
- text_form_data.append(value_m)
- cursorData.close()
- }
- do {
- try text_form_data.write(to: file_form_data, atomically: true, encoding: .utf8)
- }
- catch {//print(error)
-
- }
- }
-
- //Make File TASK_PIC
- let file_task_pic = documentDirectoryUrl.appendingPathComponent("TASK_PIC").appendingPathExtension("")
- if let tableInfo = Database.shared.getRecords(fmdb: fmdb,query: "PRAGMA table_info(TASK_PIC)") {
- var text_task_pic = ""
- while tableInfo.next() {
- if text_task_pic.isEmpty {
- text_task_pic.append(tableInfo.string(forColumn: "name")!)
- } else {
- text_task_pic.append(separator)
- text_task_pic.append(tableInfo.string(forColumn: "name")!)
- }
- }
- text_task_pic.append("\n")
- tableInfo.close()
-
- if let cursorData = Database.shared.getRecords(fmdb: fmdb,query: "SELECT * FROM TASK_PIC") {
- let columnCount = cursorData.columnCount
- var value_m = ""
- while cursorData.next() {
- for i in 0..<columnCount - 1 {
- value_m.append(cursorData.string(forColumnIndex: i) == nil ? "null" : cursorData.string(forColumnIndex: i)!.isEmpty ? "<empty>" : cursorData.string(forColumnIndex: i)!)
- value_m.append(separator)
- }
- value_m.append("\n")
- recordSize += 1
- }
- text_task_pic.append(value_m)
- cursorData.close()
- }
- do {
- try text_task_pic.write(to: file_task_pic, atomically: true, encoding: .utf8)
- }
- catch {//print(error)
-
- }
- }
-
- //Make File TASK_DETAIL
- let file_task_detail = documentDirectoryUrl.appendingPathComponent("TASK_DETAIL").appendingPathExtension("")
- if let tableInfo = Database.shared.getRecords(fmdb: fmdb,query: "PRAGMA table_info(TASK_DETAIL)") {
- var text_task_detail = ""
- while tableInfo.next() {
- if text_task_detail.isEmpty {
- text_task_detail.append(tableInfo.string(forColumn: "name")!)
- } else {
- text_task_detail.append(separator)
- text_task_detail.append(tableInfo.string(forColumn: "name")!)
- }
- }
- text_task_detail.append("\n")
- tableInfo.close()
-
- if let cursorData = Database.shared.getRecords(fmdb: fmdb,query: "SELECT * FROM TASK_DETAIL") {
- let columnCount = cursorData.columnCount
- var value_m = ""
- while cursorData.next() {
- for i in 0..<columnCount - 1 {
- value_m.append(cursorData.string(forColumnIndex: i) == nil ? "null" : cursorData.string(forColumnIndex: i)!.isEmpty ? "<empty>" : cursorData.string(forColumnIndex: i)!)
- value_m.append(separator)
- }
- value_m.append("\n")
- recordSize += 1
- }
- text_task_detail.append(value_m)
- cursorData.close()
- }
- do {
- try text_task_detail.write(to: file_task_detail, atomically: true, encoding: .utf8)
- }
- catch {//print(error)
-
- }
- }
-
- //ZIP ALL FILES
- let fileManager = FileManager()
- var destinationURL = documentDirectoryUrl
- destinationURL.appendPathComponent("zipItem\(Date().currentTimeMillis())")
- // let listFiles: [URL] = [file_message, file_uc_list, file_form_data, file_task_pic, file_task_detail]
- do {
- try fileManager.createDirectory(at: destinationURL, withIntermediateDirectories: true, attributes: nil)
- let zipFiles = destinationURL.appendingPathComponent(getFileName(option: choosenOption, fileId: fileIdBackup, withoutZIP: true)).appendingPathExtension("zip")
- // try Zip.zipFiles(paths: listFiles, zipFilePath: zipFiles, password: nil, progress: {progress in
- // self.labelPreparing.text = "Preparing...".localized() + " \(progress * 100)%"
- // })
- let unzipProgress = Progress()
- let observation = unzipProgress.observe(\.fractionCompleted) { progress, _ in
- self.labelPreparing.text = "Preparing...".localized() + " \(progress.fractionCompleted * 100)%"
- }
- try fileManager.zipItem(at: file_message, to: zipFiles, progress: unzipProgress)
- guard let archive = Archive(url: zipFiles, accessMode: .update) else {
- return
- }
- do {
- try archive.addEntry(with: file_uc_list.lastPathComponent, relativeTo: file_uc_list.deletingLastPathComponent())
- try archive.addEntry(with: file_form_data.lastPathComponent, relativeTo: file_form_data.deletingLastPathComponent())
- try archive.addEntry(with: file_task_pic.lastPathComponent, relativeTo: file_task_pic.deletingLastPathComponent())
- try archive.addEntry(with: file_task_detail.lastPathComponent, relativeTo: file_task_detail.deletingLastPathComponent())
- } catch {
- //print("Adding entry to ZIP archive failed with error:\(error)")
- }
- self.labelPreparing.text = "Uploading...".localized()
- Network().uploadHTTP(fileUrl: zipFiles, completion: { result,progress,response in
- if result {
- DispatchQueue.main.async { [self] in
- labelPreparing.text = "Uploading...".localized() + " \(progress)%"
- if progress == 100 {
- do {
- let path = zipFiles.path
- let attrib = try FileManager.default.attributesOfItem(atPath: path)
- let fileSize = attrib[.size] as! Int64
- DispatchQueue.global().async { [self] in
- _ = Nexilis.write(message: CoreMessage_TMessageBank.getBackupUploaded(option: choosenOption, fileid: fileIdBackup, filesize: String(fileSize), recordSize: String(recordSize)))
- }
- let date = Date()
- let calendar = Calendar.current
-
- if (calendar.isDateInToday(date)) {
- dayLastBackup = "Today".localized()
- } else {
- let startOfNow = calendar.startOfDay(for: Date())
- let startOfTimeStamp = calendar.startOfDay(for: date)
- let components = calendar.dateComponents([.day], from: startOfNow, to: startOfTimeStamp)
- let day = -(components.day!)
- if day == 1{
- dayLastBackup = "Yesterday".localized()
- } else {
- let formatter = DateFormatter()
- formatter.dateFormat = "dd MMMM yyyy"
- let lang: String = SecureUserDefaults.shared.value(forKey: "i18n_language") ?? "en"
- if lang == "id" {
- formatter.locale = NSLocale(localeIdentifier: "id") as Locale?
- }
- let stringFormat = formatter.string(from: date as Date)
- dayLastBackup = stringFormat
- }
- }
-
- let formatter = DateFormatter()
- formatter.dateFormat = "HH:mm"
- formatter.locale = NSLocale(localeIdentifier: "id") as Locale?
- timeLastBackup = formatter.string(from: date as Date)
-
- valueLastBackup = dayLastBackup.localized() + ", " + timeLastBackup
- valuesizeBackup = Units(bytes: fileSize).getReadableUnit()
-
- labelPreparing.text = "Successfully Backup Data".localized()
- DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: { [self] in
- isBackupStart = false
- tableView.beginUpdates()
- tableView.reloadRows(at: [indexPath, IndexPath(row: 0, section: 0)], with: .none)
- tableView.reloadSections(IndexSet(integer: 2), with: .none)
- tableView.endUpdates()
- })
- } catch {}
- }
- }
- }
- })
- } catch {
- //print(error)
- }
- } catch {
- rollback.pointee = true
- print("Access database error: \(error.localizedDescription)")
- }
- })
- }
- }
- extension String {
- func appendLineToURL(fileURL: URL) throws {
- try (self + "\n").appendToURL(fileURL: fileURL)
- }
- func appendToURL(fileURL: URL) throws {
- let data = self.data(using: String.Encoding.utf8)!
- try data.append(fileURL: fileURL)
- }
- }
- extension Data {
- func append(fileURL: URL) throws {
- if let fileHandle = FileHandle(forWritingAtPath: fileURL.path) {
- defer {
- fileHandle.closeFile()
- }
- fileHandle.seekToEndOfFile()
- fileHandle.write(self)
- }
- else {
- try write(to: fileURL, options: .atomic)
- }
- }
- }
|