From eaad0a4bffb135461d8f94878b509097102c0f18 Mon Sep 17 00:00:00 2001 From: Christoph Hagen Date: Mon, 27 Jan 2025 22:31:02 +0100 Subject: [PATCH] Separate post and page view to files --- .../Views/Posts/DetailListItem.swift | 29 +++ .../Views/Posts/LinkedPageTagView.swift | 11 ++ .../Posts/LocalizedPostContentView.swift | 95 ++++++++++ .../Views/Posts/PostContentView.swift | 169 ------------------ .../Views/Posts/PostDetailView.swift | 28 --- .../Views/Posts/PostImageView.swift | 65 +++++++ .../Settings/NavigationBarSettingsView.swift | 1 + 7 files changed, 201 insertions(+), 197 deletions(-) create mode 100644 CHDataManagement/Views/Posts/DetailListItem.swift create mode 100644 CHDataManagement/Views/Posts/LinkedPageTagView.swift create mode 100644 CHDataManagement/Views/Posts/LocalizedPostContentView.swift create mode 100644 CHDataManagement/Views/Posts/PostImageView.swift diff --git a/CHDataManagement/Views/Posts/DetailListItem.swift b/CHDataManagement/Views/Posts/DetailListItem.swift new file mode 100644 index 0000000..74cd84f --- /dev/null +++ b/CHDataManagement/Views/Posts/DetailListItem.swift @@ -0,0 +1,29 @@ +import SwiftUI + +struct DetailListItem: View where Content: View { + + private let alignment: VerticalAlignment + + private let spacing: CGFloat? + + private let content: Content + + init(alignment: VerticalAlignment = .center, + spacing: CGFloat? = nil, + @ViewBuilder content: () -> Content) { + self.alignment = alignment + self.spacing = spacing + self.content = content() + } + + var body: some View { + HStack(alignment: alignment, + spacing: spacing) { + content + } + .padding(.horizontal) + .padding(.vertical) + .background(Color(NSColor.windowBackgroundColor)) + .cornerRadius(8) + } +} diff --git a/CHDataManagement/Views/Posts/LinkedPageTagView.swift b/CHDataManagement/Views/Posts/LinkedPageTagView.swift new file mode 100644 index 0000000..e5d683a --- /dev/null +++ b/CHDataManagement/Views/Posts/LinkedPageTagView.swift @@ -0,0 +1,11 @@ +import SwiftUI + +struct LinkedPageTagView: View { + + @ObservedObject + var page: Page + + var body: some View { + TagDisplayView(tags: $page.tags) + } +} diff --git a/CHDataManagement/Views/Posts/LocalizedPostContentView.swift b/CHDataManagement/Views/Posts/LocalizedPostContentView.swift new file mode 100644 index 0000000..d960d52 --- /dev/null +++ b/CHDataManagement/Views/Posts/LocalizedPostContentView.swift @@ -0,0 +1,95 @@ +import SwiftUI + +struct LocalizedPostContentView: View { + + @Environment(\.language) + private var language + + @EnvironmentObject + private var content: Content + + @ObservedObject + var post: LocalizedPost + + @ObservedObject + var other: LocalizedPost + + @Binding + var tags: [Tag] + + @Binding + var page: Page? + + @State + private var fileTypeToSelect: FileTypeCategory = .image + + @State + private var showImagePicker = false + + init(post: LocalizedPost, other: LocalizedPost, tags: Binding<[Tag]>, page: Binding) { + self.post = post + self.other = other + self._tags = tags + self._page = page + } + + var body: some View { + VStack(alignment: .leading) { + HStack { + Text("Images/Video") + .font(.headline) + Button("Images") { + fileTypeToSelect = .image + showImagePicker = true + } + .disabled(post.hasVideos) + Button("Videos") { + fileTypeToSelect = .video + showImagePicker = true + } + .disabled(post.hasImages) + Button("Transfer from \(language.next.text)") { + post.images = other.images + } + .disabled(other.images.isEmpty) + } + ScrollView(.horizontal) { + HStack(alignment: .center, spacing: 8) { + ForEach(post.images) { image in + PostImageView(image: image) + } + } + } + OptionalTextField("", text: $post.title) + .font(.system(size: 24, weight: .bold)) + .foregroundStyle(Color.primary) + .textFieldStyle(.plain) + .lineLimit(2) + .frame(minHeight: 30) + if let page = page { + LinkedPageTagView(page: page) + } else { + TagDisplayView(tags: $tags) + } + PostLabelsView(post: post, other: other) + TextEditor(text: $post.text) + .font(.body) + .frame(minHeight: 150) + .textEditorStyle(.plain) + .padding(.vertical, 8) + .padding(.leading, 3) + .background(Color.gray.opacity(0.1)) + .cornerRadius(8) + } + .padding() + .sheet(isPresented: $showImagePicker) { + MultiFileSelectionView( + selectedFiles: $post.images, + allowedType: fileTypeToSelect) + } + } + + private func copyImagesFromOtherLanguage() { + post.images = other.images + } +} diff --git a/CHDataManagement/Views/Posts/PostContentView.swift b/CHDataManagement/Views/Posts/PostContentView.swift index 64369e9..431d898 100644 --- a/CHDataManagement/Views/Posts/PostContentView.swift +++ b/CHDataManagement/Views/Posts/PostContentView.swift @@ -32,174 +32,6 @@ extension PostContentView: MainContentView { static let itemDescription = "a post" } -private struct LinkedPageTagView: View { - - @ObservedObject - var page: Page - - var body: some View { - TagDisplayView(tags: $page.tags) - } -} - -private struct PostImageView: View { - - @ObservedObject - var image: FileResource - - var body: some View { - if let preview = image.imageToDisplay { - preview - .resizable() - .aspectRatio(contentMode: .fill) - .frame(maxWidth: 300, maxHeight: 200) - .cornerRadius(8) - } else if image.type.isImage { - VStack { - Image(systemSymbol: .exclamationmarkTriangle) - .resizable() - .aspectRatio(contentMode: .fit) - .frame(height: 100) - Text(image.id) - .font(.title) - Text("Failed to load image") - .font(.body) - } - .frame(width: 300, height: 200) - .background(Color.gray) - .cornerRadius(8) - } else if image.type.isVideo { - VStack { - Image(systemSymbol: .film) - .resizable() - .aspectRatio(contentMode: .fit) - .frame(height: 100) - Text(image.id) - .font(.title) - Button("Generate preview") { - generateVideoPreview(image) - } - .font(.body) - } - .frame(width: 300, height: 200) - .background(Color.gray) - .cornerRadius(8) - } else { - VStack { - Image(systemSymbol: .exclamationmarkTriangle) - .resizable() - .aspectRatio(contentMode: .fit) - .frame(height: 100) - Text(image.id) - .font(.title) - Text("Invalid media type") - .font(.body) - } - .frame(width: 300, height: 200) - .background(Color.gray) - .cornerRadius(8) - } - } - - private func generateVideoPreview(_ image: FileResource) { - image.createVideoThumbnail() - } -} - -struct LocalizedPostContentView: View { - - @Environment(\.language) - private var language - - @EnvironmentObject - private var content: Content - - @ObservedObject - var post: LocalizedPost - - @ObservedObject - var other: LocalizedPost - - @Binding - var tags: [Tag] - - @Binding - var page: Page? - - @State - private var fileTypeToSelect: FileTypeCategory = .image - - @State - private var showImagePicker = false - - init(post: LocalizedPost, other: LocalizedPost, tags: Binding<[Tag]>, page: Binding) { - self.post = post - self.other = other - self._tags = tags - self._page = page - } - - var body: some View { - VStack(alignment: .leading) { - HStack { - Text("Images/Video") - .font(.headline) - Button("Images") { - fileTypeToSelect = .image - showImagePicker = true - } - .disabled(post.hasVideos) - Button("Videos") { - fileTypeToSelect = .video - showImagePicker = true - } - .disabled(post.hasImages) - Button("Transfer from \(language.next.text)") { - post.images = other.images - } - .disabled(other.images.isEmpty) - } - ScrollView(.horizontal) { - HStack(alignment: .center, spacing: 8) { - ForEach(post.images) { image in - PostImageView(image: image) - } - } - } - OptionalTextField("", text: $post.title) - .font(.system(size: 24, weight: .bold)) - .foregroundStyle(Color.primary) - .textFieldStyle(.plain) - .lineLimit(2) - .frame(minHeight: 30) - if let page = page { - LinkedPageTagView(page: page) - } else { - TagDisplayView(tags: $tags) - } - PostLabelsView(post: post, other: other) - TextEditor(text: $post.text) - .font(.body) - .frame(minHeight: 150) - .textEditorStyle(.plain) - .padding(.vertical, 8) - .padding(.leading, 3) - .background(Color.gray.opacity(0.1)) - .cornerRadius(8) - } - .padding() - .sheet(isPresented: $showImagePicker) { - MultiFileSelectionView( - selectedFiles: $post.images, - allowedType: fileTypeToSelect) - } - } - - private func copyImagesFromOtherLanguage() { - post.images = other.images - } -} - #Preview(traits: .fixedLayout(width: 450, height: 600)) { List { PostContentView(post: .fullMock) @@ -209,5 +41,4 @@ struct LocalizedPostContentView: View { .listRowSeparator(.hidden) } .environmentObject(Content.mock) - //.listStyle(.plain) } diff --git a/CHDataManagement/Views/Posts/PostDetailView.swift b/CHDataManagement/Views/Posts/PostDetailView.swift index 2551af5..46aacd4 100644 --- a/CHDataManagement/Views/Posts/PostDetailView.swift +++ b/CHDataManagement/Views/Posts/PostDetailView.swift @@ -1,33 +1,5 @@ import SwiftUI -private struct DetailListItem: View where Content: View { - - private let alignment: VerticalAlignment - - private let spacing: CGFloat? - - private let content: Content - - init(alignment: VerticalAlignment = .center, - spacing: CGFloat? = nil, - @ViewBuilder content: () -> Content) { - self.alignment = alignment - self.spacing = spacing - self.content = content() - } - - var body: some View { - HStack(alignment: alignment, - spacing: spacing) { - content - } - .padding(.horizontal) - .padding(.vertical) - .background(Color(NSColor.windowBackgroundColor)) - .cornerRadius(8) - } -} - struct PostDetailView: View { @Environment(\.language) diff --git a/CHDataManagement/Views/Posts/PostImageView.swift b/CHDataManagement/Views/Posts/PostImageView.swift new file mode 100644 index 0000000..ed60e3a --- /dev/null +++ b/CHDataManagement/Views/Posts/PostImageView.swift @@ -0,0 +1,65 @@ +import SwiftUI + +struct PostImageView: View { + + @ObservedObject + var image: FileResource + + var body: some View { + if let preview = image.imageToDisplay { + preview + .resizable() + .aspectRatio(contentMode: .fill) + .frame(maxWidth: 300, maxHeight: 200) + .cornerRadius(8) + } else if image.type.isImage { + VStack { + Image(systemSymbol: .exclamationmarkTriangle) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(height: 100) + Text(image.id) + .font(.title) + Text("Failed to load image") + .font(.body) + } + .frame(width: 300, height: 200) + .background(Color.gray) + .cornerRadius(8) + } else if image.type.isVideo { + VStack { + Image(systemSymbol: .film) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(height: 100) + Text(image.id) + .font(.title) + Button("Generate preview") { + generateVideoPreview(image) + } + .font(.body) + } + .frame(width: 300, height: 200) + .background(Color.gray) + .cornerRadius(8) + } else { + VStack { + Image(systemSymbol: .exclamationmarkTriangle) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(height: 100) + Text(image.id) + .font(.title) + Text("Invalid media type") + .font(.body) + } + .frame(width: 300, height: 200) + .background(Color.gray) + .cornerRadius(8) + } + } + + private func generateVideoPreview(_ image: FileResource) { + image.createVideoThumbnail() + } +} diff --git a/CHDataManagement/Views/Settings/NavigationBarSettingsView.swift b/CHDataManagement/Views/Settings/NavigationBarSettingsView.swift index e1731ab..d55d5f5 100644 --- a/CHDataManagement/Views/Settings/NavigationBarSettingsView.swift +++ b/CHDataManagement/Views/Settings/NavigationBarSettingsView.swift @@ -41,6 +41,7 @@ struct NavigationBarSettingsView: View { } Text("Select the tags to show in the navigation bar. The number should be even.") .foregroundStyle(.secondary) + . padding(.bottom) LocalizedNavigationBarSettingsView(settings: content.settings.navigation.localized(in: language)) }