Files
appchk-app/main/Recordings/VCShareRecording.swift
2020-08-31 12:18:36 +02:00

160 lines
5.4 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import UIKit
class VCShareRecording : UIViewController {
var record: Recording!
private var jsonData: Data?
@IBOutlet private var text : UITextView!
@IBOutlet private var sendButton: UIBarButtonItem!
@IBOutlet private var sendActivity : UIActivityIndicatorView!
override func viewDidLoad() {
super.viewDidLoad()
if record.isShared {
sendButton.tintColor = .gray
}
let start = record.start
let comp = Calendar.current.dateComponents([.weekOfYear, .yearForWeekOfYear], from: Date(start))
let wkYear = "\(comp.yearForWeekOfYear ?? 0).\(comp.weekOfYear ?? 0)"
let lenSec = record.duration
let res = RecordingsDB.details(record)
var cluster: [String : [Timestamp]] = [:]
for (dom, ts) in res {
if cluster[dom] == nil {
cluster[dom] = []
}
cluster[dom]?.append(ts - start)
}
let domList = cluster.reduce("") {
$0 + "\($1.key) : \($1.value.map{"\($0)"}.joined(separator: ", "))\n"
}
text.attributedText = NSMutableAttributedString()
.h2("Review before sending\n")
.normal("\nRead carefully. " +
"You are about to upload the following information to our servers. " +
"The data is anonymized in regards to device identifiers and time of recording. " +
"It is however not anonymous to the domains requested during the recording." +
"\n\n" +
"If necessary, you can cancel this dialog and return to the recording overview. " +
"Use swipe to delete individual domains." +
"\n\n")
.bold("Send to server:\n")
.italic("\nDate: ", .callout).bold(wkYear, .callout)
.italic("\nRec-Length: ", .callout).bold("\(lenSec) sec", .callout)
.italic("\nApp-Bundle: ", .callout).bold(record.appId ?? "", .callout)
.italic("\nApp-Name: ", .callout).bold(record.title ?? "", .callout)
.italic("\n\n[domain name] : [relative time offsets]\n", .callout)
.bold(domList, .callout)
let json: [String : Any] = [
"v" : 1,
"date" : wkYear,
"duration" : lenSec,
"app-bundle" : record.appId ?? "",
"app-name" : record.title ?? "",
"logs" : cluster
]
jsonData = try? JSONSerialization.data(withJSONObject: json)
}
@IBAction private func closeView() {
dismiss(animated: true)
}
@IBAction private func shareRecording(_ sender: UIBarButtonItem) {
guard !record.isShared else {
showAlertAlreadyShared()
return
}
sender.isEnabled = false
sendActivity.startAnimating()
postToServer() { [weak self, weak sender] in
self?.sendActivity.stopAnimating()
sender?.isEnabled = true
}
}
private func postToServer(_ onceLoaded: @escaping () -> Void) {
let url = URL(string: "http://127.0.0.1/api/v1/contribute/")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = jsonData
var rec = record! // store temporarily so self can be released
URLSession.shared.dataTask(with: request) { data, response, error in
DispatchQueue.main.async { [weak self] in
onceLoaded()
guard error == nil, let data = data,
let response = response as? HTTPURLResponse else {
self?.banner(.fail, "\(error?.localizedDescription ?? "Unkown error occurred")")
return
}
guard let json = (try? JSONSerialization.jsonObject(with: data, options: [])) as? [String: Any],
let v = json["v"] as? Int, v > 0 else {
QLog.Warning("Couldn't contribute: Not JSON or no version key")
self?.banner(.fail, "Server couldn't parse request.\nTry again later.")
return
}
let status = json["status"] as? String ?? "unkown reason"
guard status == "ok", (200 ... 299) ~= response.statusCode else {
QLog.Warning("Couldn't contribute: \(status)")
self?.banner(.fail, "Error: \(status)")
return
}
// update db, mark record as shared
rec.uploadkey = json["key"] as? String ?? "_"
self?.record = rec // in case view is still open
RecordingsDB.update(rec) // rec cause self may not be available
self?.sendButton.tintColor = .gray
// notify user about results
var autoHide = true
if v == 1, let urlStr = json["url"] as? String {
let nextUpdateIn = json["when"] as? Int
self?.showAlertAvailableSoon(urlStr, when: nextUpdateIn)
autoHide = false
}
self?.banner(.ok, "Thank you for your contribution.",
autoHide ? { [weak self] in self?.closeView() } : nil)
}
}.resume()
}
private func banner(_ style: NotificationBanner.Style, _ msg: String, _ closure: (() -> Void)? = nil) {
NotificationBanner(msg, style: style).present(in: self, onClose: closure)
}
private func showAlertAvailableSoon(_ urlStr: String, when: Int?) {
var msg = "Your contribution is being processed and will be available "
if let when = when {
if when < 61 {
msg += "in approx. \(when) sec. "
} else {
let fmt = TimeFormat.from(Timestamp(when))
msg += "in \(fmt) min. "
}
} else {
msg += "shortly. "
}
msg += "Open results webpage now?"
AskAlert(title: "Thank you", text: msg, buttonText: "Show results", cancelButton: "Not now") { _ in
if let url = URL(string: urlStr) {
UIApplication.shared.openURL(url)
}
}.presentIn(self)
}
private func showAlertAlreadyShared() {
let alert = Alert(title: nil, text: "You already shared this recording.")
if let bid = record.appId, bid.isValidBundleId() {
alert.addAction(UIAlertAction.init(title: "Open results", style: .default, handler: { _ in
URL(string: "http://127.0.0.1/redirect.html?id=\(bid)")?.open()
}))
}
alert.presentIn(self)
}
}