aboutsummaryrefslogtreecommitdiff
path: root/Hotline/Library
diff options
context:
space:
mode:
authorDustin Mierau <dustin@mierau.me>2025-11-11 15:39:02 -0800
committerDustin Mierau <dustin@mierau.me>2025-11-11 15:39:02 -0800
commitf87ff05d17cedf21845abbb8d750759ba725a263 (patch)
tree154feff5eed1b3f7787eeb2f743ffe6602b6cd31 /Hotline/Library
parentcdaff85ac22f45e39ab1f02474beaa7aada9ad9b (diff)
Folder download logic cleanup. Display folder icon on folder download transfers with small icon for the current file. Fix progress for folder downloads.
Diffstat (limited to 'Hotline/Library')
-rw-r--r--Hotline/Library/Extensions.swift5
-rw-r--r--Hotline/Library/NetSocket/FileProgress.swift15
-rw-r--r--Hotline/Library/NetSocket/TransferRateEstimator.swift3
-rw-r--r--Hotline/Library/Views/FileIconView.swift12
4 files changed, 27 insertions, 8 deletions
diff --git a/Hotline/Library/Extensions.swift b/Hotline/Library/Extensions.swift
index cf9f8ff..5ebc7db 100644
--- a/Hotline/Library/Extensions.swift
+++ b/Hotline/Library/Extensions.swift
@@ -147,6 +147,11 @@ extension URL {
return filePath
}
+
+ func generateUniqueFileURL(filename base: String) -> URL {
+ let filePath = self.generateUniqueFilePath(filename: base)
+ return URL(filePath: filePath)
+ }
}
// MARK: -
diff --git a/Hotline/Library/NetSocket/FileProgress.swift b/Hotline/Library/NetSocket/FileProgress.swift
index c2306f3..2064c59 100644
--- a/Hotline/Library/NetSocket/FileProgress.swift
+++ b/Hotline/Library/NetSocket/FileProgress.swift
@@ -12,14 +12,27 @@ public extension NetSocket {
public let sent: Int
/// Total file size (may be nil if unknown)
public let total: Int?
+ /// Size of most recent packet
+ public let now: Int
+ /// Total progress so far (0.0 to 1.0)
+ public let progress: Double
/// Smoothed transfer rate in bytes per second (EMA), if enough samples collected
public let bytesPerSecond: Double?
/// Estimated time remaining (seconds) based on smoothed rate, if available
public let estimatedTimeRemaining: TimeInterval?
- public init(sent: Int, total: Int?, bytesPerSecond: Double? = nil, estimatedTimeRemaining: TimeInterval? = nil) {
+ public init(sent: Int, total: Int?, now: Int = 0, bytesPerSecond: Double? = nil, estimatedTimeRemaining: TimeInterval? = nil) {
self.sent = sent
self.total = total
+ self.now = now
+
+ if let t = total {
+ self.progress = max(0.0, min(1.0, Double(sent) / Double(t)))
+ }
+ else {
+ self.progress = 0.0
+ }
+
self.bytesPerSecond = bytesPerSecond
self.estimatedTimeRemaining = estimatedTimeRemaining
}
diff --git a/Hotline/Library/NetSocket/TransferRateEstimator.swift b/Hotline/Library/NetSocket/TransferRateEstimator.swift
index badf87a..61383ff 100644
--- a/Hotline/Library/NetSocket/TransferRateEstimator.swift
+++ b/Hotline/Library/NetSocket/TransferRateEstimator.swift
@@ -70,6 +70,7 @@ public struct TransferRateEstimator {
self.minSamples = minSamples
}
+ @discardableResult
public mutating func update(total: Int) -> NetSocket.FileProgress {
return self.update(bytes: max(0, total - self.transferred))
}
@@ -80,6 +81,7 @@ public struct TransferRateEstimator {
///
/// - Parameter bytes: Number of bytes transferred in this sample
/// - Returns: Current progress with speed and ETA estimates
+ @discardableResult
public mutating func update(bytes: Int) -> NetSocket.FileProgress {
let clock = ContinuousClock()
let now = clock.now
@@ -127,6 +129,7 @@ public struct TransferRateEstimator {
return NetSocket.FileProgress(
sent: self.transferred,
total: self.total,
+ now: bytes,
bytesPerSecond: haveEstimate ? self.emaBytesPerSecond : nil,
estimatedTimeRemaining: eta
)
diff --git a/Hotline/Library/Views/FileIconView.swift b/Hotline/Library/Views/FileIconView.swift
index d0949fa..836c990 100644
--- a/Hotline/Library/Views/FileIconView.swift
+++ b/Hotline/Library/Views/FileIconView.swift
@@ -2,7 +2,7 @@ import SwiftUI
import UniformTypeIdentifiers
struct FolderIconView: View {
- private func folderIcon() -> Image {
+ private var folderIcon: Image {
#if os(iOS)
return Image(systemName: "folder.fill")
#elseif os(macOS)
@@ -11,7 +11,7 @@ struct FolderIconView: View {
}
var body: some View {
- folderIcon()
+ self.folderIcon
.resizable()
.scaledToFit()
}
@@ -22,7 +22,7 @@ struct FileIconView: View {
let fileType: String?
#if os(iOS)
- private func fileIcon() -> Image {
+ private var fileIcon: Image {
let fileExtension = (self.filename as NSString).pathExtension
if let fileType = UTType(filenameExtension: fileExtension) {
if fileType.isSubtype(of: .movie) {
@@ -45,7 +45,7 @@ struct FileIconView: View {
return Image(systemName: "doc")
}
#elseif os(macOS)
- private func fileIcon() -> Image {
+ private var fileIcon: Image {
let fileExtension = (self.filename as NSString).pathExtension
if !fileExtension.isEmpty,
@@ -60,14 +60,12 @@ struct FileIconView: View {
else {
return Image(nsImage: NSWorkspace.shared.icon(for: UTType.data))
}
-
-// Image(nsImage: NSWorkspace.shared.icon(for: UTType(filenameExtension: (filename as NSString).pathExtension) ?? UTType.content))
}
#endif
var body: some View {
- fileIcon()
+ self.fileIcon
.resizable()
.scaledToFit()
}