2023-01-20 17:28:15 -08:00
|
|
|
//
|
|
|
|
|
// HistoryView.swift
|
|
|
|
|
// App
|
|
|
|
|
//
|
|
|
|
|
// Created by James Magahern on 1/20/23.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
import SwiftUI
|
|
|
|
|
import UniformTypeIdentifiers
|
|
|
|
|
|
|
|
|
|
struct HistoryView: View {
|
2023-01-25 15:04:58 -08:00
|
|
|
@StateObject public var viewModel: BrowserHistory.ViewModel
|
2023-01-20 17:28:15 -08:00
|
|
|
@State public var selectedItems = Set<HistoryItem.ID>()
|
2023-09-26 16:23:35 -07:00
|
|
|
public var onSelectItem: (URL) -> Void
|
2023-01-20 17:28:15 -08:00
|
|
|
|
2023-01-25 15:04:58 -08:00
|
|
|
private let dateFormatter = DateFormatter() .. {
|
|
|
|
|
$0.locale = Locale.current
|
|
|
|
|
$0.dateStyle = .medium
|
|
|
|
|
$0.timeStyle = .short
|
2023-01-20 17:28:15 -08:00
|
|
|
}
|
|
|
|
|
|
2023-01-25 15:04:58 -08:00
|
|
|
@Environment(\.dismiss) private var dismissAction
|
2023-01-25 16:13:09 -08:00
|
|
|
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
|
|
|
|
|
|
2023-01-20 17:28:15 -08:00
|
|
|
var body: some View {
|
2023-01-25 15:04:58 -08:00
|
|
|
Table(viewModel.historyItems, selection: $selectedItems) {
|
2023-01-25 16:13:09 -08:00
|
|
|
TableColumn("Title") { item in
|
|
|
|
|
VStack(alignment: .leading) {
|
|
|
|
|
Text(item.title.count > 0 ? item.title : item.url.absoluteString)
|
|
|
|
|
.lineLimit(1)
|
|
|
|
|
|
|
|
|
|
if horizontalSizeClass == .compact {
|
|
|
|
|
Text(item.url.shortString()).font(.caption).lineLimit(1)
|
|
|
|
|
Text(dateFormatter.string(from: item.lastVisited))
|
|
|
|
|
.font(.caption)
|
|
|
|
|
.foregroundColor(.secondary)
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-01-20 17:28:15 -08:00
|
|
|
}
|
2023-01-25 16:13:09 -08:00
|
|
|
TableColumn("URL", value: \.url.absoluteString)
|
|
|
|
|
TableColumn("Last Visited") { item in
|
2023-01-20 17:28:15 -08:00
|
|
|
Text(dateFormatter.string(from: item.lastVisited))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
.contextMenu(forSelectionType: HistoryItem.ID.self, menu: { items in
|
2023-01-25 15:04:58 -08:00
|
|
|
let historyItems = items.compactMap { viewModel.item(forIdentifier: $0) }
|
|
|
|
|
Button("Copy") {
|
|
|
|
|
UIPasteboard.general.setItems(historyItems.map { [
|
|
|
|
|
UTType.url.identifier : $0.url,
|
|
|
|
|
UTType.utf8PlainText.identifier : $0.url.absoluteString,
|
|
|
|
|
] })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Button("Delete") {
|
|
|
|
|
viewModel.deleteItems(items)
|
2023-01-20 17:28:15 -08:00
|
|
|
}
|
|
|
|
|
}, primaryAction: { items in
|
2023-01-25 15:04:58 -08:00
|
|
|
items.compactMap({ viewModel.item(forIdentifier: $0) }).forEach { item in
|
2023-09-26 16:23:35 -07:00
|
|
|
onSelectItem(item.url)
|
2023-01-20 17:28:15 -08:00
|
|
|
}
|
|
|
|
|
})
|
2023-01-25 15:04:58 -08:00
|
|
|
.searchable(text: $viewModel.searchQuery)
|
2023-01-20 17:28:15 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct HistoryViewPreviewProvider: PreviewProvider {
|
|
|
|
|
static var previews: some View {
|
2023-09-26 16:23:35 -07:00
|
|
|
HistoryView(viewModel: BrowserHistory.shared.viewModel(), onSelectItem: { _ in })
|
2023-01-20 17:28:15 -08:00
|
|
|
.previewLayout(.fixed(width: 480.0, height: 800.0))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-25 16:13:09 -08:00
|
|
|
extension URL {
|
|
|
|
|
public func shortString() -> String {
|
|
|
|
|
return String(absoluteString.trimmingPrefix(try! Regex("(.+)://")))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|