From 908a909c873b1c8e1ad6469fe937c1fcbacb8d76 Mon Sep 17 00:00:00 2001 From: relikd Date: Wed, 12 Aug 2020 18:15:32 +0200 Subject: [PATCH] Share results screen --- AppCheck.xcodeproj/project.pbxproj | 6 +- main/GUI/Base.lproj/Recordings.storyboard | 74 +++++++++++++++++++++-- main/Recordings/TVCRecordingDetails.swift | 15 ++++- main/Recordings/VCShareRecording.swift | 66 ++++++++++++++++++++ 4 files changed, 154 insertions(+), 7 deletions(-) create mode 100644 main/Recordings/VCShareRecording.swift diff --git a/AppCheck.xcodeproj/project.pbxproj b/AppCheck.xcodeproj/project.pbxproj index 0d56224..470381d 100644 --- a/AppCheck.xcodeproj/project.pbxproj +++ b/AppCheck.xcodeproj/project.pbxproj @@ -172,6 +172,7 @@ 54CA02C42426DCCD003A5E04 /* GCDAsyncUdpSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 54CA02C02426DCCD003A5E04 /* GCDAsyncUdpSocket.m */; }; 54CE8BC424B1ED2100CC1756 /* PushNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54CE8BC324B1ED2100CC1756 /* PushNotification.swift */; }; 54CE8BC524B1ED2100CC1756 /* PushNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54CE8BC324B1ED2100CC1756 /* PushNotification.swift */; }; + 54CFE86824E3F401001687DD /* VCShareRecording.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54CFE86724E3F401001687DD /* VCShareRecording.swift */; }; 54D8B97A246C9F2000EB2414 /* FilterPipeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54D8B979246C9F2000EB2414 /* FilterPipeline.swift */; }; 54D8B97C2471A7E000EB2414 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54D8B97B2471A7E000EB2414 /* String.swift */; }; 54D8B97E2471B88900EB2414 /* DBCommon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54D8B97D2471B88900EB2414 /* DBCommon.swift */; }; @@ -371,6 +372,7 @@ 54CA02C12426DCCD003A5E04 /* GCDAsyncSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDAsyncSocket.h; sourceTree = ""; }; 54CA02C22426DCCD003A5E04 /* GCDAsyncUdpSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDAsyncUdpSocket.h; sourceTree = ""; }; 54CE8BC324B1ED2100CC1756 /* PushNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushNotification.swift; sourceTree = ""; }; + 54CFE86724E3F401001687DD /* VCShareRecording.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VCShareRecording.swift; sourceTree = ""; }; 54D8B979246C9F2000EB2414 /* FilterPipeline.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterPipeline.swift; sourceTree = ""; }; 54D8B97B2471A7E000EB2414 /* String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = ""; }; 54D8B97D2471B88900EB2414 /* DBCommon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DBCommon.swift; sourceTree = ""; }; @@ -436,8 +438,9 @@ children = ( 540E677F242D2CF100871BBE /* VCRecordings.swift */, 540E67832433FAFE00871BBE /* TVCPreviousRecords.swift */, - 540E67812433483D00871BBE /* VCEditRecording.swift */, 5458EBBF243A3F2200CFEB15 /* TVCRecordingDetails.swift */, + 54CFE86724E3F401001687DD /* VCShareRecording.swift */, + 540E67812433483D00871BBE /* VCEditRecording.swift */, 549D6ED424D5BFDB0032E498 /* TVCAppSearch.swift */, 54B345B12422E029004C53CC /* App Icons */, ); @@ -1029,6 +1032,7 @@ 54448A30248647D900771C96 /* Time.swift in Sources */, 54953E6123E0D69A0054345C /* TVCHosts.swift in Sources */, 549D6ED524D5BFDB0032E498 /* TVCAppSearch.swift in Sources */, + 54CFE86824E3F401001687DD /* VCShareRecording.swift in Sources */, 54751E512423955100168273 /* URL.swift in Sources */, 54953E5F23DEBE840054345C /* TVCDomains.swift in Sources */, 54C056DB23E9E36E00214A3F /* AppStoreSearch.swift in Sources */, diff --git a/main/GUI/Base.lproj/Recordings.storyboard b/main/GUI/Base.lproj/Recordings.storyboard index 42ee4fc..147b935 100644 --- a/main/GUI/Base.lproj/Recordings.storyboard +++ b/main/GUI/Base.lproj/Recordings.storyboard @@ -219,18 +219,82 @@ - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/main/Recordings/TVCRecordingDetails.swift b/main/Recordings/TVCRecordingDetails.swift index dcb1760..4618a83 100644 --- a/main/Recordings/TVCRecordingDetails.swift +++ b/main/Recordings/TVCRecordingDetails.swift @@ -4,9 +4,15 @@ class TVCRecordingDetails: UITableViewController, EditActionsRemove { var record: Recording! private lazy var isLongRecording: Bool = record.isLongTerm + @IBOutlet private var shareButton: UIBarButtonItem! + private var showRaw: Bool = false /// Sorted by `ts` in ascending order (oldest first) - private lazy var dataSourceRaw: [DomainTsPair] = RecordingsDB.details(record) + private lazy var dataSourceRaw: [DomainTsPair] = { + let list = RecordingsDB.details(record) + shareButton.isEnabled = list.count > 0 + return list + }() /// Sorted by `count` (descending), then alphabetically private lazy var dataSourceSum: [(domain: String, count: Int)] = { var result: [String:Int] = [:] @@ -28,6 +34,12 @@ class TVCRecordingDetails: UITableViewController, EditActionsRemove { tableView.reloadData() } + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + if let tgt = segue.destination as? VCShareRecording { + tgt.record = self.record + } + } + // MARK: - Table View Data Source @@ -89,6 +101,7 @@ class TVCRecordingDetails: UITableViewController, EditActionsRemove { tableView.deleteRows(at: [index], with: .automatic) } } + shareButton.isEnabled = dataSourceRaw.count > 0 return true } } diff --git a/main/Recordings/VCShareRecording.swift b/main/Recordings/VCShareRecording.swift new file mode 100644 index 0000000..0925efe --- /dev/null +++ b/main/Recordings/VCShareRecording.swift @@ -0,0 +1,66 @@ +import UIKit + +class VCShareRecording : UIViewController { + + var record: Recording! + private var jsonData: Data? + + @IBOutlet private var text : UITextView! + + override func viewDidLoad() { + super.viewDidLoad() + + 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 ?? 0 + + 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() { + print("\(String(data: jsonData!, encoding: .utf8)!)") + Alert(title: "Not implemented yet", text: nil).presentIn(self) + } +}