fix: align download table columns

This commit is contained in:
nimbold
2026-06-01 05:37:48 +03:30
parent dd9827c20d
commit caa20c8c2c
+57 -9
View File
@@ -214,6 +214,7 @@ private struct DownloadTable: View {
@State private var sortColumn: DownloadColumn = .dateAdded @State private var sortColumn: DownloadColumn = .dateAdded
@State private var sortDirection: SortDirection = .descending @State private var sortDirection: SortDirection = .descending
@State private var pendingDeleteItem: DownloadItem? @State private var pendingDeleteItem: DownloadItem?
@State private var resizeBaseWidths: [DownloadColumn: CGFloat] = [:]
var body: some View { var body: some View {
VStack(spacing: 0) { VStack(spacing: 0) {
@@ -304,6 +305,7 @@ private struct DownloadTable: View {
HStack(spacing: 0) { HStack(spacing: 0) {
ForEach(orderedVisibleColumns) { column in ForEach(orderedVisibleColumns) { column in
HStack(spacing: 0) { HStack(spacing: 0) {
ZStack(alignment: .trailing) {
Button { Button {
if sortColumn == column { if sortColumn == column {
sortDirection.toggle() sortDirection.toggle()
@@ -313,9 +315,13 @@ private struct DownloadTable: View {
} }
} label: { } label: {
HStack(spacing: 4) { HStack(spacing: 4) {
Spacer(minLength: 0)
Text(column.rawValue) Text(column.rawValue)
.font(.caption.weight(.semibold)) .font(.caption.weight(.semibold))
.lineLimit(1) .lineLimit(1)
.truncationMode(.tail)
.multilineTextAlignment(.center)
.layoutPriority(1)
if sortColumn == column { if sortColumn == column {
Image(systemName: sortDirection == .ascending ? "chevron.up" : "chevron.down") Image(systemName: sortDirection == .ascending ? "chevron.up" : "chevron.down")
.font(.caption2) .font(.caption2)
@@ -323,23 +329,38 @@ private struct DownloadTable: View {
Spacer(minLength: 0) Spacer(minLength: 0)
} }
.padding(.horizontal, 8) .padding(.horizontal, 8)
.frame(width: max(44, width(for: column) - 8), height: 34, alignment: .leading) .frame(width: width(for: column), height: 34, alignment: .center)
.clipped()
} }
.buttonStyle(.plain) .buttonStyle(.plain)
Rectangle() Rectangle()
.fill(.secondary.opacity(0.18)) .fill(.secondary.opacity(0.18))
.frame(width: 1, height: 20) .frame(width: 1, height: 20)
.padding(.horizontal, 3) .frame(width: 8, height: 34)
.contentShape(Rectangle()) .contentShape(Rectangle())
.onHover { isHovering in
if isHovering {
NSCursor.resizeLeftRight.push()
} else {
NSCursor.pop()
}
}
.gesture( .gesture(
DragGesture(minimumDistance: 1) DragGesture(minimumDistance: 1)
.onChanged { value in .onChanged { value in
columnWidths[column] = max(70, column.width + value.translation.width) let baseWidth = resizeBaseWidths[column] ?? width(for: column)
resizeBaseWidths[column] = baseWidth
columnWidths[column] = max(70, baseWidth + value.translation.width)
}
.onEnded { _ in
resizeBaseWidths[column] = nil
} }
) )
} }
.frame(width: width(for: column), height: 34) .frame(width: width(for: column), height: 34)
.clipped()
}
} }
} }
.frame(minWidth: totalWidth, alignment: .leading) .frame(minWidth: totalWidth, alignment: .leading)
@@ -493,9 +514,10 @@ private struct DownloadRow: View {
HStack(alignment: .top, spacing: 0) { HStack(alignment: .top, spacing: 0) {
ForEach(visibleColumns) { column in ForEach(visibleColumns) { column in
cell(for: column) cell(for: column)
.frame(width: columnWidth(column), alignment: .leading)
.padding(.horizontal, 8) .padding(.horizontal, 8)
.padding(.vertical, 8) .padding(.vertical, 8)
.frame(width: columnWidth(column), alignment: alignment(for: column))
.clipped()
} }
} }
} }
@@ -510,57 +532,83 @@ private struct DownloadRow: View {
.foregroundStyle(categoryColor) .foregroundStyle(categoryColor)
.frame(width: 22) .frame(width: 22)
VStack(alignment: .leading, spacing: 6) { VStack(alignment: .leading, spacing: 6) {
HStack {
Text(item.fileName) Text(item.fileName)
.font(.headline) .font(.headline)
.lineLimit(1) .lineLimit(1)
} .truncationMode(.tail)
Text(item.url.absoluteString) Text(item.url.absoluteString)
.font(.caption) .font(.caption)
.foregroundStyle(.secondary) .foregroundStyle(.secondary)
.lineLimit(1) .lineLimit(1)
.truncationMode(.tail)
} }
.frame(maxWidth: .infinity, alignment: .leading)
} }
case .size: case .size:
Text(ByteFormatter.string(item.sizeBytes)) Text(ByteFormatter.string(item.sizeBytes))
.monospacedDigit() .monospacedDigit()
.lineLimit(1)
.truncationMode(.tail)
case .status: case .status:
Text(item.status.rawValue) Text(item.status.rawValue)
.lineLimit(1)
.truncationMode(.tail)
case .progress: case .progress:
Text(progressStatusText) Text(progressStatusText)
.monospacedDigit() .monospacedDigit()
.foregroundStyle(statusColor) .foregroundStyle(statusColor)
.lineLimit(1)
.truncationMode(.tail)
case .lastTry: case .lastTry:
Text(formatted(item.lastTryAt)) Text(formatted(item.lastTryAt))
.lineLimit(1)
.truncationMode(.tail)
case .dateAdded: case .dateAdded:
Text(formatted(item.createdAt)) Text(formatted(item.createdAt))
.lineLimit(1)
.truncationMode(.tail)
case .category: case .category:
Text(item.category.rawValue) Text(item.category.rawValue)
.lineLimit(1)
.truncationMode(.tail)
case .connections: case .connections:
Text("\(item.connectionsPerServer)") Text("\(item.connectionsPerServer)")
.monospacedDigit() .monospacedDigit()
.lineLimit(1)
case .liveConnections: case .liveConnections:
Text("\(item.connectionCount)") Text("\(item.connectionCount)")
.monospacedDigit() .monospacedDigit()
.lineLimit(1)
case .speed: case .speed:
Text(item.speedText) Text(item.speedText)
.lineLimit(1)
.truncationMode(.tail)
case .eta: case .eta:
Text(item.etaText) Text(item.etaText)
.lineLimit(1)
.truncationMode(.tail)
case .destination: case .destination:
Text(item.destinationPath) Text(item.destinationPath)
.font(.system(.caption, design: .monospaced)) .font(.system(.caption, design: .monospaced))
.lineLimit(2) .lineLimit(1)
.truncationMode(.tail)
case .url: case .url:
Text(item.url.absoluteString) Text(item.url.absoluteString)
.font(.system(.caption, design: .monospaced)) .font(.system(.caption, design: .monospaced))
.lineLimit(2) .lineLimit(1)
.truncationMode(.tail)
case .message: case .message:
Text(item.message) Text(item.message)
.foregroundStyle(.secondary) .foregroundStyle(.secondary)
.lineLimit(2) .lineLimit(1)
.truncationMode(.tail)
} }
} }
private func alignment(for column: DownloadColumn) -> Alignment {
column == .fileName ? .leading : .center
}
private var categoryColor: Color { private var categoryColor: Color {
switch item.category { switch item.category {
case .musics: .pink case .musics: .pink