Share results screen
This commit is contained in:
@@ -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 = "<group>"; };
|
||||
54CA02C22426DCCD003A5E04 /* GCDAsyncUdpSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDAsyncUdpSocket.h; sourceTree = "<group>"; };
|
||||
54CE8BC324B1ED2100CC1756 /* PushNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushNotification.swift; sourceTree = "<group>"; };
|
||||
54CFE86724E3F401001687DD /* VCShareRecording.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VCShareRecording.swift; sourceTree = "<group>"; };
|
||||
54D8B979246C9F2000EB2414 /* FilterPipeline.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterPipeline.swift; sourceTree = "<group>"; };
|
||||
54D8B97B2471A7E000EB2414 /* String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = "<group>"; };
|
||||
54D8B97D2471B88900EB2414 /* DBCommon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DBCommon.swift; sourceTree = "<group>"; };
|
||||
@@ -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 */,
|
||||
|
||||
@@ -219,18 +219,82 @@
|
||||
</connections>
|
||||
</tableView>
|
||||
<navigationItem key="navigationItem" title="Logs" id="AXT-fV-keV">
|
||||
<barButtonItem key="rightBarButtonItem" image="line-expand" id="xLc-O7-KVB">
|
||||
<connections>
|
||||
<action selector="toggleDisplayStyle:" destination="50g-BI-Q6S" id="3wo-9O-7gV"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
<rightBarButtonItems>
|
||||
<barButtonItem systemItem="action" id="UkE-Wi-JjW">
|
||||
<connections>
|
||||
<segue destination="P0a-ZP-uEV" kind="modal" id="s3J-zL-4zK"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
<barButtonItem image="line-expand" id="xLc-O7-KVB">
|
||||
<connections>
|
||||
<action selector="toggleDisplayStyle:" destination="50g-BI-Q6S" id="3wo-9O-7gV"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
</rightBarButtonItems>
|
||||
</navigationItem>
|
||||
<simulatedNavigationBarMetrics key="simulatedTopBarMetrics" prompted="NO"/>
|
||||
<connections>
|
||||
<outlet property="shareButton" destination="UkE-Wi-JjW" id="9f1-WG-k0N"/>
|
||||
</connections>
|
||||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="lan-I9-b0a" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1400" y="0.0"/>
|
||||
</scene>
|
||||
<!--Share Recording-->
|
||||
<scene sceneID="9Zh-he-N6f">
|
||||
<objects>
|
||||
<viewController id="P0a-ZP-uEV" customClass="VCShareRecording" customModule="AppCheck" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="kVd-y1-MmT">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="421"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<navigationBar contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="dN0-a9-t4G">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<items>
|
||||
<navigationItem title="Contribute" id="a43-mu-gQ2">
|
||||
<barButtonItem key="leftBarButtonItem" systemItem="cancel" id="6J3-R1-kRM">
|
||||
<connections>
|
||||
<action selector="closeView" destination="P0a-ZP-uEV" id="cno-MA-xos"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
<barButtonItem key="rightBarButtonItem" title="Send" style="done" id="PWY-06-ykI">
|
||||
<connections>
|
||||
<action selector="shareRecording" destination="P0a-ZP-uEV" id="lSZ-8V-ANw"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
</navigationItem>
|
||||
</items>
|
||||
</navigationBar>
|
||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" editable="NO" textAlignment="natural" selectable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fFm-v5-DGy">
|
||||
<rect key="frame" x="0.0" y="45" width="320" height="376"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<string key="text">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.</string>
|
||||
<color key="textColor" systemColor="labelColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
||||
</textView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<constraints>
|
||||
<constraint firstItem="fFm-v5-DGy" firstAttribute="leading" secondItem="lie-9P-DtH" secondAttribute="leading" id="2Ae-cc-xkI"/>
|
||||
<constraint firstItem="fFm-v5-DGy" firstAttribute="top" secondItem="dN0-a9-t4G" secondAttribute="bottom" constant="1" id="2QI-wU-51t"/>
|
||||
<constraint firstItem="dN0-a9-t4G" firstAttribute="top" secondItem="lie-9P-DtH" secondAttribute="top" id="8eL-tr-3IN"/>
|
||||
<constraint firstItem="dN0-a9-t4G" firstAttribute="leading" secondItem="lie-9P-DtH" secondAttribute="leading" id="BWF-aS-ah3"/>
|
||||
<constraint firstItem="lie-9P-DtH" firstAttribute="trailing" secondItem="fFm-v5-DGy" secondAttribute="trailing" id="GRg-BF-rYE"/>
|
||||
<constraint firstItem="lie-9P-DtH" firstAttribute="bottom" secondItem="fFm-v5-DGy" secondAttribute="bottom" id="IE3-o5-suZ"/>
|
||||
<constraint firstItem="lie-9P-DtH" firstAttribute="trailing" secondItem="dN0-a9-t4G" secondAttribute="trailing" id="UuJ-xj-xBK"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="lie-9P-DtH"/>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="text" destination="fFm-v5-DGy" id="fwm-RE-gHu"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="AhG-fQ-OzZ" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="2100" y="0.0"/>
|
||||
</scene>
|
||||
<!--Edit Recording-->
|
||||
<scene sceneID="pqx-CU-4AP">
|
||||
<objects>
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
66
main/Recordings/VCShareRecording.swift
Normal file
66
main/Recordings/VCShareRecording.swift
Normal file
@@ -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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user