Add more file properties, organize storage, add video block

This commit is contained in:
Christoph Hagen
2025-01-06 15:31:19 +01:00
parent 96c0a75c2f
commit 6cf310d849
25 changed files with 712 additions and 219 deletions

View File

@ -98,7 +98,9 @@ struct AddFileView: View {
content: content,
id: file.uniqueId,
isExternallyStored: file.url == nil,
en: "", de: "")
english: "",
german: "")
content.add(resource)
selectedFile = resource
}

View File

@ -1,10 +1,42 @@
import SwiftUI
import SFSafeSymbols
private extension Button {
init(_ symbol: SFSymbol, action: @escaping @MainActor () -> Void) where Label == Image {
self.init(action: action, label: { Image(systemSymbol: symbol) })
}
}
private struct ButtonIcon: View {
let symbol: SFSymbol
let action: @MainActor () -> Void
init(_ symbol: SFSymbol, action: @escaping @MainActor () -> Void) {
self.symbol = symbol
self.action = action
}
var body: some View {
Button(action: action) {
Image(systemSymbol: symbol)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(height: 20)
}
}
}
struct FileDetailView: View {
@EnvironmentObject
private var content: Content
@Environment(\.language)
private var language
@ObservedObject
var file: FileResource
@ -15,58 +47,97 @@ struct FileDetailView: View {
private var selectedFile: FileResource?
var body: some View {
VStack(alignment: .leading) {
DetailTitle(
title: "File",
text: "A file that can be used in a post or page")
ScrollView {
VStack(alignment: .leading) {
Button("Show in Finder", action: showFileInFinder)
Button("Mark as changed", action: markFileAsChanged)
Button("Delete resource", action: deleteFile)
if file.isExternallyStored {
Button("Import file", action: replaceFile)
} else {
Button("Replace file", action: replaceFile)
Button("Make external", action: convertToExternal)
}
}
DetailTitle(
title: "File",
text: "A file that can be used in a post or page")
IdPropertyView(
id: $file.id,
title: "Name",
footer: "The unique name of the file, which is also used to reference it in posts and pages.",
validation: file.isValid,
update: { file.update(id: $0) })
StringPropertyView(
title: "German Description",
text: $file.german,
footer: "The description for the file in German. Descriptions are used for images and to explain the content of a file.")
StringPropertyView(
title: "English Description",
text: $file.english,
footer: "The description for the file in English. Descriptions are used for images and to explain the content of a file.")
if let imageDimensions = file.imageDimensions {
GenericPropertyView(title: "Image dimensions") {
Text("\(Int(imageDimensions.width)) x \(Int(imageDimensions.height)) (\(file.aspectRatio))")
GenericPropertyView(title: "Actions") {
HStack(spacing: 10) {
ButtonIcon(.folder, action: showFileInFinder)
ButtonIcon(.arrowClockwise, action: markFileAsChanged)
if file.isExternallyStored {
ButtonIcon(.squareAndArrowDown, action: replaceFile)
} else {
ButtonIcon(.arrowLeftArrowRight, action: replaceFile)
ButtonIcon(.squareDashed, action: convertToExternal)
}
ButtonIcon(.trash, action: deleteFile)
.foregroundStyle(.red)
}
.buttonStyle(.plain)
.foregroundStyle(.blue)
}
#warning("Add button to show image versions")
}
if let fileSize = file.fileSize {
GenericPropertyView(title: "File size") {
Text(formatBytes(fileSize))
IdPropertyView(
id: $file.id,
title: "Name",
footer: "The unique name of the file, which is also used to reference it in posts and pages.",
validation: file.isValid,
update: { file.update(id: $0) })
switch language {
case .english:
StringPropertyView(
title: "Description",
text: $file.english,
footer: "The description for the file. Descriptions are used for images and to explain the content of a file.")
case .german:
StringPropertyView(
title: "Description",
text: $file.german,
footer: "The description for the file. Descriptions are used for images and to explain the content of a file.")
}
}
Spacer()
}.padding()
.onAppear {
if file.fileSize == nil {
file.determineFileSize()
OptionalStringPropertyView(
title: "Version",
text: $file.version,
footer: "The version of this file.")
OptionalStringPropertyView(
title: "Source URL",
text: $file.sourceUrl,
footer: "The url where this file can be downloaded from.")
OptionalStringPropertyView(
title: "Custom output path",
text: $file.customOutputPath,
footer: "A custom path where the file is stored in the output folder")
if let imageDimensions = file.imageDimensions {
GenericPropertyView(title: "Image dimensions") {
Text("\(Int(imageDimensions.width)) x \(Int(imageDimensions.height)) (\(file.aspectRatio))")
}
}
if let fileSize = file.fileSize {
GenericPropertyView(title: "File size") {
Text(formatBytes(fileSize))
}
}
GenericPropertyView(title: "Added") {
Text(file.addedDate.formatted())
}
GenericPropertyView(title: "Modified") {
Text(file.modifiedDate.formatted())
}
if !file.generatedImageVersions.isEmpty {
GenericPropertyView(title: "Image versions") {
VStack(alignment: .leading) {
ForEach(file.generatedImageVersions.sorted(), id: \.self) { version in
Text(version)
}
}
}
}
}.padding()
}.onAppear {
if file.fileSize == nil {
file.determineFileSize()
}
}
}
private func formatBytes(_ bytes: Int) -> String {
@ -133,7 +204,7 @@ struct FileDetailView: View {
return
}
guard content.storage.delete(file: file.id) else {
guard content.storage.removeFileContent(file: file.id) else {
print("File '\(file.id)': Failed to delete file to make it external")
return
}

View File

@ -184,8 +184,8 @@ struct PageIssueView: View {
content: content,
id: fileId,
isExternallyStored: true,
en: "",
de: "")
english: "",
german: "")
content.add(file)
retryPageCheck()