First actions for generation view

This commit is contained in:
Christoph Hagen 2025-05-04 20:57:49 +02:00
parent a4710d525b
commit f968ccad29
4 changed files with 129 additions and 2 deletions

View File

@ -208,6 +208,7 @@
E2F3B39C2DC5542E00CFA712 /* LabelEditingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F3B39B2DC5542E00CFA712 /* LabelEditingView.swift */; };
E2F3B39E2DC55B1C00CFA712 /* LabelCreationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F3B39D2DC55B1C00CFA712 /* LabelCreationView.swift */; };
E2F3B3A22DC769C300CFA712 /* DeleteButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F3B3A12DC769BF00CFA712 /* DeleteButton.swift */; };
E2F3B3A42DC7DC2400CFA712 /* GenerationIssuesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F3B3A32DC7DC1F00CFA712 /* GenerationIssuesView.swift */; };
E2FD1D0D2D2DBBA600B48627 /* LinkPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2FD1D0C2D2DBBA100B48627 /* LinkPreview.swift */; };
E2FD1D192D2DC4F500B48627 /* LoadingContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2FD1D182D2DC4F500B48627 /* LoadingContext.swift */; };
E2FD1D1B2D2DC63800B48627 /* LinkPreviewDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2FD1D1A2D2DC62C00B48627 /* LinkPreviewDetailView.swift */; };
@ -492,6 +493,7 @@
E2F3B39B2DC5542E00CFA712 /* LabelEditingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelEditingView.swift; sourceTree = "<group>"; };
E2F3B39D2DC55B1C00CFA712 /* LabelCreationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelCreationView.swift; sourceTree = "<group>"; };
E2F3B3A12DC769BF00CFA712 /* DeleteButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeleteButton.swift; sourceTree = "<group>"; };
E2F3B3A32DC7DC1F00CFA712 /* GenerationIssuesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenerationIssuesView.swift; sourceTree = "<group>"; };
E2FD1D0C2D2DBBA100B48627 /* LinkPreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkPreview.swift; sourceTree = "<group>"; };
E2FD1D182D2DC4F500B48627 /* LoadingContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingContext.swift; sourceTree = "<group>"; };
E2FD1D1A2D2DC62C00B48627 /* LinkPreviewDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkPreviewDetailView.swift; sourceTree = "<group>"; };
@ -601,6 +603,7 @@
E20BCCA02D53985500B8DBEB /* Generation */ = {
isa = PBXGroup;
children = (
E2F3B3A32DC7DC1F00CFA712 /* GenerationIssuesView.swift */,
E20BCCAE2D53F4A500B8DBEB /* GenerationStringIssuesView.swift */,
E20BCCAC2D53F48100B8DBEB /* IssueStatus.swift */,
E20BCCAA2D53B85300B8DBEB /* GenerationResultsIssueView.swift */,
@ -1560,6 +1563,7 @@
E2FE0F6C2D2D335E002963B7 /* LocalizedPageSettingsView.swift in Sources */,
E2B85F572C4BD0BB0047CD0C /* Binding+Extension.swift in Sources */,
E2B85F432C4294F60047CD0C /* FeedEntry.swift in Sources */,
E2F3B3A42DC7DC2400CFA712 /* GenerationIssuesView.swift in Sources */,
E25DA56D2D00EBCF00AEF16D /* NavigationBarSettingsView.swift in Sources */,
E25DA5272CFF745700AEF16D /* URL+Extensions.swift in Sources */,
E2FE0F642D2C2F4D002963B7 /* ButtonBlock.swift in Sources */,

View File

@ -86,10 +86,16 @@ struct GenerationContentView: View {
text: "draft posts",
statusWhenNonEmpty: .warning,
items: draftPosts) { $0.id }
GenerationStringIssuesView(
GenerationIssuesView(
text: "additional output files",
statusWhenNonEmpty: .warning,
items: content.results.unusedFilesInOutput)
items: $content.results.unusedFilesInOutput) { filePath in
HStack {
Text(filePath)
Spacer()
Button("Delete", action: { delete(unusedFile: filePath) })
}
}
GenerationStringIssuesView(
text: "inaccessible files",
items: content.results.inaccessibleFiles) { $0.id }
@ -134,6 +140,13 @@ struct GenerationContentView: View {
}
}.padding()
}
private func delete(unusedFile: String) {
guard content.storage.deleteInOutputFolder(unusedFile) else {
return
}
content.results.unusedFilesInOutput.remove(unusedFile)
}
}
#Preview {

View File

@ -0,0 +1,65 @@
import SwiftUI
struct GenerationIssuesView<S, T, V>: View where S: Collection, T: Hashable & Comparable, V: View, S.Element == T {
let text: String
let statusWhenNonEmpty: IssueStatus
@Binding
var items: S
let map: (T) -> V
@State
private var showList = false
var status: IssueStatus {
items.isEmpty ? .nominal : statusWhenNonEmpty
}
init(text: String, statusWhenNonEmpty: IssueStatus = .error, items: Binding<S>, map: @escaping (T) -> V) {
self.text = text
self.statusWhenNonEmpty = statusWhenNonEmpty
self._items = items
self.map = map
}
var body: some View {
HStack {
Button(action: showListIfNonEmpty) {
Image(systemSymbol: status.symbol)
.foregroundStyle(status.color)
}.buttonStyle(.plain)
Text("\(items.count) \(text)")
}
.sheet(isPresented: $showList) {
VStack {
Text("\(items.count) \(text)")
.font(.title)
List(items.sorted(), id: \.self) { item in
map(item)
}
.frame(minHeight: 400)
Button("Close") { showList = false }
}.padding()
}
}
private func showListIfNonEmpty() {
guard !items.isEmpty else {
return
}
showList = true
}
}
extension GenerationIssuesView where S == Set<String>, V == Text {
init(text: String, statusWhenNonEmpty: IssueStatus = .error, items: Binding<Set<String>>) {
self.text = text
self.statusWhenNonEmpty = statusWhenNonEmpty
self._items = items
self.map = { Text($0) }
}
}

View File

@ -0,0 +1,45 @@
import SwiftUI
import SFSafeSymbols
struct ColoredButton: View {
let icon: SFSymbol
let text: LocalizedStringKey
let fillColor: Color
let textColor: Color
let action: () -> Void
init(icon: SFSymbol, text: LocalizedStringKey, fillColor: Color = .blue, textColor: Color = .white, action: @escaping () -> Void) {
self.icon = icon
self.text = text
self.fillColor = fillColor
self.textColor = textColor
self.action = action
}
init(delete: @escaping () -> Void) {
self.icon = .trash
self.text = "Delete"
self.fillColor = .red
self.textColor = .white
self.action = delete
}
var body: some View {
Button(action: action) {
HStack {
Spacer()
Image(systemSymbol: icon)
Text(text)
.padding(.vertical, 8)
Spacer()
}
.foregroundStyle(textColor)
.background(RoundedRectangle(cornerRadius: 8).fill(fillColor))
}.buttonStyle(.plain)
}
}