Separate post and page view to files

This commit is contained in:
Christoph Hagen 2025-01-27 22:31:02 +01:00
parent 89062f153c
commit eaad0a4bff
7 changed files with 201 additions and 197 deletions

View File

@ -0,0 +1,29 @@
import SwiftUI
struct DetailListItem<Content>: 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)
}
}

View File

@ -0,0 +1,11 @@
import SwiftUI
struct LinkedPageTagView: View {
@ObservedObject
var page: Page
var body: some View {
TagDisplayView(tags: $page.tags)
}
}

View File

@ -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<Page?>) {
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
}
}

View File

@ -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<Page?>) {
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)
}

View File

@ -1,33 +1,5 @@
import SwiftUI
private struct DetailListItem<Content>: 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)

View File

@ -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()
}
}

View File

@ -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))
}