Recordings: Toggle between raw logs and summary

This commit is contained in:
relikd
2020-06-27 16:13:58 +02:00
parent 2312187670
commit b7b13f51b2
17 changed files with 210 additions and 34 deletions

View File

@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "img.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "img@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "img@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 B

View File

@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "img.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "img@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "img@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 B

View File

@@ -291,7 +291,7 @@
<rect key="frame" x="0.0" y="0.0" width="293" height="57.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="0HB-5f-eB1">
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.8" id="0HB-5f-eB1">
<rect key="frame" x="16" y="9" width="33.5" height="20.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
@@ -411,7 +411,7 @@
<rect key="frame" x="0.0" y="0.0" width="293" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="J2P-mU-Vad">
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.8" id="J2P-mU-Vad">
<rect key="frame" x="16" y="12" width="33.5" height="20.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
@@ -508,7 +508,7 @@
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="zbU-wC-qJG">
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.8" translatesAutoresizingMaskIntoConstraints="NO" id="zbU-wC-qJG">
<rect key="frame" x="15" y="11" width="290" height="20.5"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<nil key="textColor"/>
@@ -666,7 +666,7 @@
<color key="textColor" systemColor="secondaryLabelColor" red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Subtitle" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.80000000000000004" id="No8-Bf-ptL">
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Subtitle" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.8" id="No8-Bf-ptL">
<rect key="frame" x="113" y="12" width="59" height="20.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
@@ -800,7 +800,7 @@
<rect key="frame" x="0.0" y="0.0" width="280" height="57.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="hr0-Xt-5gV">
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.8" id="hr0-Xt-5gV">
<rect key="frame" x="16" y="9" width="33.5" height="20.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
@@ -1000,14 +1000,14 @@ Duration: 60:00</string>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="PreviousRecordDetailCell" textLabel="rN0-kA-Eln" detailTextLabel="xRp-XG-oKf" style="IBUITableViewCellStyleValue1" id="ceT-cF-lLF">
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="RecordDetailCountedCell" textLabel="rN0-kA-Eln" detailTextLabel="xRp-XG-oKf" style="IBUITableViewCellStyleValue1" id="ceT-cF-lLF">
<rect key="frame" x="0.0" y="28" width="320" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="ceT-cF-lLF" id="c5Y-xg-hSL">
<rect key="frame" x="0.0" y="0.0" width="320" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="rN0-kA-Eln">
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.8" id="rN0-kA-Eln">
<rect key="frame" x="16" y="12" width="33.5" height="20.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
@@ -1024,13 +1024,67 @@ Duration: 60:00</string>
</subviews>
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="RecordDetailShortCell" textLabel="rIc-r4-6pg" detailTextLabel="0pW-ZC-wmh" style="IBUITableViewCellStyleValue2" id="hzU-cx-nIs">
<rect key="frame" x="0.0" y="71.5" width="320" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="hzU-cx-nIs" id="scX-pQ-E7z">
<rect key="frame" x="0.0" y="0.0" width="320" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="right" lineBreakMode="headTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" minimumScaleFactor="0.8" id="rIc-r4-6pg">
<rect key="frame" x="16" y="12" width="91" height="20.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<color key="textColor" systemColor="secondaryLabelColor" red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Detail" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.8" id="0pW-ZC-wmh">
<rect key="frame" x="113" y="12" width="44" height="20.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="RecordDetailLongCell" textLabel="xDy-8J-JFT" detailTextLabel="kgF-BN-FdV" style="IBUITableViewCellStyleSubtitle" id="Q4T-JJ-fqY">
<rect key="frame" x="0.0" y="115" width="320" height="57.5"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Q4T-JJ-fqY" id="8hy-Rg-b6Q">
<rect key="frame" x="0.0" y="0.0" width="320" height="57.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.8" id="xDy-8J-JFT">
<rect key="frame" x="16" y="9" width="33.5" height="20.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Subtitle" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.8" adjustsFontSizeToFit="NO" id="kgF-BN-FdV">
<rect key="frame" x="16" y="32.5" width="44" height="14.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
<color key="textColor" systemColor="secondaryLabelColor" red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="50g-BI-Q6S" id="SFM-IM-FRx"/>
<outlet property="delegate" destination="50g-BI-Q6S" id="LBY-sp-dg0"/>
</connections>
</tableView>
<navigationItem key="navigationItem" title="Logs" id="AXT-fV-keV"/>
<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>
</navigationItem>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="lan-I9-b0a" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
@@ -1262,7 +1316,7 @@ Duration: 60:00</string>
<rect key="frame" x="0.0" y="0.0" width="320" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="MrS-rb-RLB">
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.8" id="MrS-rb-RLB">
<rect key="frame" x="16" y="0.0" width="288" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
@@ -1299,6 +1353,7 @@ Duration: 60:00</string>
<image name="intersection" width="25" height="25"/>
<image name="journal" width="25" height="25"/>
<image name="jump-to-target" width="20" height="20"/>
<image name="line-expand" width="20" height="20"/>
<image name="settings" width="25" height="25"/>
<image name="tag" width="25" height="25"/>
</resources>

View File

@@ -412,8 +412,6 @@ extension CreateTable {
"""}
}
typealias RecordLog = (domain: String, count: Int32)
extension SQLiteDatabase {
// MARK: write
@@ -442,13 +440,24 @@ extension SQLiteDatabase {
}
}
/// Delete one recording log entry with given `recording id`, matching `domain`, and `ts`.
/// - Returns: `true` if row was deleted
func recordingLogsDelete(_ recId: sqlite3_int64, singleEntry ts: Timestamp, domain: String) throws -> Bool {
try run(sql: "DELETE FROM recLog WHERE rid = ? AND ts = ? AND domain = ? LIMIT 1;",
bind: [BindInt64(recId), BindInt64(ts), BindText(domain)]) {
try ifStep($0, SQLITE_DONE)
return numberOfChanges > 0
}
}
// MARK: read
/// List of domains and count occurences for given recording.
func recordingLogsGetGrouped(_ r: Recording) -> [RecordLog]? {
try? run(sql: "SELECT domain, COUNT() FROM recLog WHERE rid = ? GROUP BY domain;",
/// - Returns: List of `(domain, ts)` pairs. Sorted by `ts` in ascending order (oldest first)
func recordingLogsGet(_ r: Recording) -> [DomainTsPair]? {
try? run(sql: "SELECT domain, ts FROM recLog WHERE rid = ? ORDER BY ts ASC, rowid DESC;",
bind: [BindInt64(r.id)]) {
allRows($0) { (col_text($0, 0) ?? "", sqlite3_column_int($0, 1)) }
allRows($0) { (col_text($0, 0) ?? "", col_ts($0, 1)) }
}
}
}

View File

@@ -35,6 +35,5 @@ extension FilterOptions {
extension Recording {
var fallbackTitle: String { get { "Unnamed Recording #\(id)" } }
var duration: Timestamp? { get { stop == nil ? nil : stop! - start } }
var durationString: String? { get { stop == nil ? nil : TimeFormat.from(duration!) } }
}

View File

@@ -21,8 +21,8 @@ enum RecordingsDB {
}
/// Get list of domains that occured during the recording
static func details(_ r: Recording) -> [RecordLog] {
AppDB?.recordingLogsGetGrouped(r) ?? []
static func details(_ r: Recording) -> [DomainTsPair] {
AppDB?.recordingLogsGet(r) ?? []
}
/// Update `title`, `appid`, and `notes` and post `NotifyRecordingChanged` notification.
@@ -43,5 +43,11 @@ enum RecordingsDB {
static func deleteDetails(_ r: Recording, domain: String) -> Bool {
((try? AppDB?.recordingLogsDelete(r.id, matchingDomain: domain)) ?? 0) > 0
}
/// Delete individual entries from recording while keeping the recording alive.
/// - Returns: `true` if at least one row is deleted.
static func deleteSingle(_ r: Recording, domain: String, ts: Timestamp) -> Bool {
(try? AppDB?.recordingLogsDelete(r.id, singleEntry: ts, domain: domain)) ?? false
}
}

View File

@@ -19,6 +19,10 @@ extension Timestamp {
static func now() -> Timestamp { Date().timestamp }
/// Create `Timestamp` with `now() - minutes * 60`
static func past(minutes: Int) -> Timestamp { now() - Timestamp(minutes * 60) }
/// Create `Timestamp` with `m * 60` seconds
static func minutes(_ m: Int) -> Timestamp { Timestamp(m * 60) }
/// Create `Timestamp` with `h * 3600` seconds
static func hours(_ h: Int) -> Timestamp { Timestamp(h * 3600) }
}
extension Timer {
@@ -68,12 +72,18 @@ struct TimeFormat {
// MARK: static
/// Time string with format `HH:mm`
/// Time string with format `[HH:]mm:ss` (hours prepended only if duration is 1h+)
static func from(_ duration: Timestamp) -> String {
String(format: "%02d:%02d", duration / 60, duration % 60)
let min = duration / 60
let sec = duration % 60
if min >= 60 {
return String(format: "%02d:%02d:%02d", min / 60, min % 60, sec)
} else {
return String(format: "%02d:%02d", min, sec)
}
}
/// Duration string with format `HH:mm` or `HH:mm.sss`
/// Duration string with format `mm:ss` or `mm:ss.SSS`
static func from(_ duration: TimeInterval, millis: Bool = false) -> String {
let t = Int(duration)
if millis {
@@ -83,7 +93,7 @@ struct TimeFormat {
return String(format: "%02d:%02d", t / 60, t % 60)
}
/// Duration string with format `HH:mm` or `HH:mm.sss` since reference date
/// Duration string with format `mm:ss` or `mm:ss.SSS` since reference date
static func since(_ date: Date, millis: Bool = false) -> String {
from(Date().timeIntervalSince(date), millis: millis)
}

View File

@@ -69,7 +69,7 @@ class TVCPreviousRecords: UITableViewController, EditActionsRemove {
let x = dataSource[indexPath.row]
cell.textLabel?.text = x.title ?? x.fallbackTitle
cell.textLabel?.textColor = (x.title == nil) ? .systemGray : nil
cell.detailTextLabel?.text = "at \(DateFormat.seconds(x.start)), duration: \(x.durationString ?? "?")"
cell.detailTextLabel?.text = "at \(DateFormat.seconds(x.start)), duration: \(TimeFormat.from(x.duration ?? 0))"
return cell
}

View File

@@ -2,23 +2,58 @@ import UIKit
class TVCRecordingDetails: UITableViewController, EditActionsRemove {
var record: Recording!
private var dataSource: [RecordLog]!
private lazy var isLongRecording: Bool = (record.duration ?? 0) > Timestamp.hours(1)
private var showRaw: Bool = false
/// Sorted by `ts` in ascending order (oldest first)
private lazy var dataSourceRaw: [DomainTsPair] = RecordingsDB.details(record)
/// Sorted by `count` (descending), then alphabetically
private lazy var dataSourceSum: [(domain: String, count: Int)] = {
var result: [String:Int] = [:]
for x in dataSourceRaw {
result[x.domain] = (result[x.domain] ?? 0) + 1 // group and count
}
return result.map{$0}.sorted {
$0.count > $1.count || $0.count == $1.count && $0.domain < $1.domain
}
}()
override func viewDidLoad() {
title = record.title ?? record.fallbackTitle
dataSource = RecordingsDB.details(record)
}
@IBAction private func toggleDisplayStyle(_ sender: UIBarButtonItem) {
showRaw = !showRaw
sender.image = UIImage(named: showRaw ? "line-collapse" : "line-expand")
tableView.reloadData()
}
// MARK: - Table View Data Source
override func tableView(_ _: UITableView, numberOfRowsInSection _: Int) -> Int { dataSource.count }
override func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int {
showRaw ? dataSourceRaw.count : dataSourceSum.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "PreviousRecordDetailCell")!
let x = dataSource[indexPath.row]
cell.textLabel?.text = x.domain
cell.detailTextLabel?.text = "\(x.count)"
let cell: UITableViewCell
if showRaw {
let x = dataSourceRaw[indexPath.row]
if isLongRecording {
cell = tableView.dequeueReusableCell(withIdentifier: "RecordDetailLongCell")!
cell.textLabel?.text = x.domain
cell.detailTextLabel?.text = DateFormat.seconds(x.ts)
} else {
cell = tableView.dequeueReusableCell(withIdentifier: "RecordDetailShortCell")!
cell.textLabel?.text = "+ " + TimeFormat.from(x.ts - record.start)
cell.detailTextLabel?.text = x.domain
}
} else {
let x = dataSourceSum[indexPath.row]
cell = tableView.dequeueReusableCell(withIdentifier: "RecordDetailCountedCell")!
cell.textLabel?.text = x.domain
cell.detailTextLabel?.text = "\(x.count)×"
}
return cell
}
@@ -34,9 +69,25 @@ class TVCRecordingDetails: UITableViewController, EditActionsRemove {
}
func editableRowCallback(_ index: IndexPath, _ action: RowAction, _ userInfo: Any?) -> Bool {
if RecordingsDB.deleteDetails(record, domain: dataSource[index.row].domain) {
dataSource.remove(at: index.row)
tableView.deleteRows(at: [index], with: .automatic)
if showRaw {
let x = dataSourceRaw[index.row]
if RecordingsDB.deleteSingle(record, domain: x.domain, ts: x.ts) {
if let i = dataSourceSum.firstIndex(where: { $0.domain == x.domain }) {
dataSourceSum[i].count -= 1
if dataSourceSum[i].count == 0 {
dataSourceSum.remove(at: i)
}
}
dataSourceRaw.remove(at: index.row)
tableView.deleteRows(at: [index], with: .automatic)
}
} else {
let dom = dataSourceSum[index.row].domain
if RecordingsDB.deleteDetails(record, domain: dom) {
dataSourceRaw.removeAll { $0.domain == dom }
dataSourceSum.remove(at: index.row)
tableView.deleteRows(at: [index], with: .automatic)
}
}
return true
}

View File

@@ -18,7 +18,7 @@ class VCEditRecording: UIViewController, UITextFieldDelegate, UITextViewDelegate
inputDetails.text = """
Start: \(DateFormat.seconds(record.start))
End: \(record.stop == nil ? "?" : DateFormat.seconds(record.stop!))
Duration: \(record.durationString ?? "?")
Duration: \(TimeFormat.from(record.duration ?? 0))
"""
validateSaveButton()
if deleteOnCancel { // mark as destructive

View File

@@ -27,7 +27,7 @@ class TVCHostDetails: UITableViewController, SyncUpdateDelegate, UITabBarDelegat
let cell = tableView.dequeueReusableCell(withIdentifier: "HostDetailCell")!
let src = dataSource[indexPath.row]
cell.textLabel?.text = DateFormat.seconds(src.ts)
cell.detailTextLabel?.text = (src.total > 1) ? "\(src.total)x" : nil
cell.detailTextLabel?.text = (src.total > 1) ? "\(src.total)×" : nil
cell.imageView?.image = (src.blocked > 0 ? UIImage(named: "shield-x") : nil)
return cell
}