Fix tag assignment in post UI

This commit is contained in:
Christoph Hagen
2025-06-16 10:09:38 +02:00
parent 1d0eba9d78
commit 8508719dbe
13 changed files with 74 additions and 54 deletions

View File

@@ -7,6 +7,9 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
E2039A152E0001B700305538 /* PostImagesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2039A142E0001B200305538 /* PostImagesView.swift */; };
E2039A172E00027600305538 /* PostTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2039A162E00027300305538 /* PostTitleView.swift */; };
E2039A192E0002C500305538 /* PostTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2039A182E0002C100305538 /* PostTextView.swift */; };
E20BCC972D53454C00B8DBEB /* StorageItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E20BCC962D53454500B8DBEB /* StorageItem.swift */; }; E20BCC972D53454C00B8DBEB /* StorageItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E20BCC962D53454500B8DBEB /* StorageItem.swift */; };
E20BCC992D53597D00B8DBEB /* SaveState.swift in Sources */ = {isa = PBXBuildFile; fileRef = E20BCC982D53597D00B8DBEB /* SaveState.swift */; }; E20BCC992D53597D00B8DBEB /* SaveState.swift in Sources */ = {isa = PBXBuildFile; fileRef = E20BCC982D53597D00B8DBEB /* SaveState.swift */; };
E20BCC9B2D535C3500B8DBEB /* ChangeObservableItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E20BCC9A2D535C3100B8DBEB /* ChangeObservableItem.swift */; }; E20BCC9B2D535C3500B8DBEB /* ChangeObservableItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E20BCC9A2D535C3100B8DBEB /* ChangeObservableItem.swift */; };
@@ -238,7 +241,6 @@
E2FD1D5A2D477AB200B48627 /* InsertableItemsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2FD1D592D477AB200B48627 /* InsertableItemsView.swift */; }; E2FD1D5A2D477AB200B48627 /* InsertableItemsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2FD1D592D477AB200B48627 /* InsertableItemsView.swift */; };
E2FD1D5C2D47EEB800B48627 /* LinkedPageTagView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2FD1D5B2D47EEB800B48627 /* LinkedPageTagView.swift */; }; E2FD1D5C2D47EEB800B48627 /* LinkedPageTagView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2FD1D5B2D47EEB800B48627 /* LinkedPageTagView.swift */; };
E2FD1D5E2D47EED200B48627 /* PostImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2FD1D5D2D47EED200B48627 /* PostImageView.swift */; }; E2FD1D5E2D47EED200B48627 /* PostImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2FD1D5D2D47EED200B48627 /* PostImageView.swift */; };
E2FD1D602D47EEEF00B48627 /* LocalizedPostContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2FD1D5F2D47EEEF00B48627 /* LocalizedPostContentView.swift */; };
E2FD1D642D47EF4200B48627 /* DetailListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2FD1D632D47EF4200B48627 /* DetailListItem.swift */; }; E2FD1D642D47EF4200B48627 /* DetailListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2FD1D632D47EF4200B48627 /* DetailListItem.swift */; };
E2FD1D682D483CCF00B48627 /* Insert+Buttons.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2FD1D672D483CCA00B48627 /* Insert+Buttons.swift */; }; E2FD1D682D483CCF00B48627 /* Insert+Buttons.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2FD1D672D483CCA00B48627 /* Insert+Buttons.swift */; };
E2FE0EE62D15A0B5002963B7 /* GenerationResults.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2FE0EE52D15A0B1002963B7 /* GenerationResults.swift */; }; E2FE0EE62D15A0B5002963B7 /* GenerationResults.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2FE0EE52D15A0B1002963B7 /* GenerationResults.swift */; };
@@ -299,6 +301,9 @@
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
E2039A142E0001B200305538 /* PostImagesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostImagesView.swift; sourceTree = "<group>"; };
E2039A162E00027300305538 /* PostTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostTitleView.swift; sourceTree = "<group>"; };
E2039A182E0002C100305538 /* PostTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostTextView.swift; sourceTree = "<group>"; };
E20BCC962D53454500B8DBEB /* StorageItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageItem.swift; sourceTree = "<group>"; }; E20BCC962D53454500B8DBEB /* StorageItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageItem.swift; sourceTree = "<group>"; };
E20BCC982D53597D00B8DBEB /* SaveState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SaveState.swift; sourceTree = "<group>"; }; E20BCC982D53597D00B8DBEB /* SaveState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SaveState.swift; sourceTree = "<group>"; };
E20BCC9A2D535C3100B8DBEB /* ChangeObservableItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChangeObservableItem.swift; sourceTree = "<group>"; }; E20BCC9A2D535C3100B8DBEB /* ChangeObservableItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChangeObservableItem.swift; sourceTree = "<group>"; };
@@ -524,7 +529,6 @@
E2FD1D592D477AB200B48627 /* InsertableItemsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsertableItemsView.swift; sourceTree = "<group>"; }; E2FD1D592D477AB200B48627 /* InsertableItemsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsertableItemsView.swift; sourceTree = "<group>"; };
E2FD1D5B2D47EEB800B48627 /* LinkedPageTagView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkedPageTagView.swift; sourceTree = "<group>"; }; E2FD1D5B2D47EEB800B48627 /* LinkedPageTagView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkedPageTagView.swift; sourceTree = "<group>"; };
E2FD1D5D2D47EED200B48627 /* PostImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostImageView.swift; sourceTree = "<group>"; }; E2FD1D5D2D47EED200B48627 /* PostImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostImageView.swift; sourceTree = "<group>"; };
E2FD1D5F2D47EEEF00B48627 /* LocalizedPostContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizedPostContentView.swift; sourceTree = "<group>"; };
E2FD1D632D47EF4200B48627 /* DetailListItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailListItem.swift; sourceTree = "<group>"; }; E2FD1D632D47EF4200B48627 /* DetailListItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailListItem.swift; sourceTree = "<group>"; };
E2FD1D672D483CCA00B48627 /* Insert+Buttons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Insert+Buttons.swift"; sourceTree = "<group>"; }; E2FD1D672D483CCA00B48627 /* Insert+Buttons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Insert+Buttons.swift"; sourceTree = "<group>"; };
E2FE0EE52D15A0B1002963B7 /* GenerationResults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenerationResults.swift; sourceTree = "<group>"; }; E2FE0EE52D15A0B1002963B7 /* GenerationResults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenerationResults.swift; sourceTree = "<group>"; };
@@ -1019,6 +1023,9 @@
E2FD1D3E2D46404900B48627 /* PostLabelsView.swift */, E2FD1D3E2D46404900B48627 /* PostLabelsView.swift */,
E29D31502D0616890051B7F4 /* PostListView.swift */, E29D31502D0616890051B7F4 /* PostListView.swift */,
E218502A2CF790AC0090B18B /* PostContentView.swift */, E218502A2CF790AC0090B18B /* PostContentView.swift */,
E2039A182E0002C100305538 /* PostTextView.swift */,
E2039A162E00027300305538 /* PostTitleView.swift */,
E2039A142E0001B200305538 /* PostImagesView.swift */,
E21850262CF3B42D0090B18B /* PostDetailView.swift */, E21850262CF3B42D0090B18B /* PostDetailView.swift */,
E29D313E2D04822C0051B7F4 /* AddPostView.swift */, E29D313E2D04822C0051B7F4 /* AddPostView.swift */,
E21850222CF10C840090B18B /* TagSelectionView.swift */, E21850222CF10C840090B18B /* TagSelectionView.swift */,
@@ -1026,7 +1033,6 @@
E2A21C072CB17B810060935B /* TagView.swift */, E2A21C072CB17B810060935B /* TagView.swift */,
E29D31312D03B5610051B7F4 /* LocalizedPostDetailView.swift */, E29D31312D03B5610051B7F4 /* LocalizedPostDetailView.swift */,
E2FD1D5D2D47EED200B48627 /* PostImageView.swift */, E2FD1D5D2D47EED200B48627 /* PostImageView.swift */,
E2FD1D5F2D47EEEF00B48627 /* LocalizedPostContentView.swift */,
E2FD1D5B2D47EEB800B48627 /* LinkedPageTagView.swift */, E2FD1D5B2D47EEB800B48627 /* LinkedPageTagView.swift */,
); );
path = Posts; path = Posts;
@@ -1352,6 +1358,7 @@
E29D317D2D086AB00051B7F4 /* Int+Random.swift in Sources */, E29D317D2D086AB00051B7F4 /* Int+Random.swift in Sources */,
E2BF1BC62D6B16FF003089F1 /* HeadlineLink.swift in Sources */, E2BF1BC62D6B16FF003089F1 /* HeadlineLink.swift in Sources */,
E25DA56F2D00F9A100AEF16D /* PostFeedSettingsView.swift in Sources */, E25DA56F2D00F9A100AEF16D /* PostFeedSettingsView.swift in Sources */,
E2039A192E0002C500305538 /* PostTextView.swift in Sources */,
E2521E042D51796000C56662 /* StorageStatusView.swift in Sources */, E2521E042D51796000C56662 /* StorageStatusView.swift in Sources */,
E29D313B2D04464A0051B7F4 /* LocalizedTagDetailView.swift in Sources */, E29D313B2D04464A0051B7F4 /* LocalizedTagDetailView.swift in Sources */,
E2FE0F552D2BCFC4002963B7 /* ContentBlock.swift in Sources */, E2FE0F552D2BCFC4002963B7 /* ContentBlock.swift in Sources */,
@@ -1381,6 +1388,7 @@
E242520A2C52C9260029FF16 /* ContentLanguage.swift in Sources */, E242520A2C52C9260029FF16 /* ContentLanguage.swift in Sources */,
E2B85F452C429ED60047CD0C /* ImageGallery.swift in Sources */, E2B85F452C429ED60047CD0C /* ImageGallery.swift in Sources */,
E2B85F3B2C428F0E0047CD0C /* Post.swift in Sources */, E2B85F3B2C428F0E0047CD0C /* Post.swift in Sources */,
E2039A152E0001B700305538 /* PostImagesView.swift in Sources */,
E29D31852D0AE8EE0051B7F4 /* KnownHeaderElement.swift in Sources */, E29D31852D0AE8EE0051B7F4 /* KnownHeaderElement.swift in Sources */,
E25DA51B2CFF08BB00AEF16D /* PostFeedPageNavigation.swift in Sources */, E25DA51B2CFF08BB00AEF16D /* PostFeedPageNavigation.swift in Sources */,
E22990422D107A95009F8D77 /* ImageVersion.swift in Sources */, E22990422D107A95009F8D77 /* ImageVersion.swift in Sources */,
@@ -1433,6 +1441,7 @@
E229901E2D0E4364009F8D77 /* LocalizedItem.swift in Sources */, E229901E2D0E4364009F8D77 /* LocalizedItem.swift in Sources */,
E29D31262D0370A80051B7F4 /* VideoCommand+Option.swift in Sources */, E29D31262D0370A80051B7F4 /* VideoCommand+Option.swift in Sources */,
E2FE0EF82D1D8110002963B7 /* IconCommand.swift in Sources */, E2FE0EF82D1D8110002963B7 /* IconCommand.swift in Sources */,
E2039A172E00027600305538 /* PostTitleView.swift in Sources */,
E2F3B39E2DC55B1C00CFA712 /* LabelCreationView.swift in Sources */, E2F3B39E2DC55B1C00CFA712 /* LabelCreationView.swift in Sources */,
E21850272CF3B42D0090B18B /* PostDetailView.swift in Sources */, E21850272CF3B42D0090B18B /* PostDetailView.swift in Sources */,
E22990242D0EDBD0009F8D77 /* HeaderElement.swift in Sources */, E22990242D0EDBD0009F8D77 /* HeaderElement.swift in Sources */,
@@ -1592,7 +1601,6 @@
E2FD1D0D2D2DBBA600B48627 /* LinkPreview.swift in Sources */, E2FD1D0D2D2DBBA600B48627 /* LinkPreview.swift in Sources */,
E20BCC972D53454C00B8DBEB /* StorageItem.swift in Sources */, E20BCC972D53454C00B8DBEB /* StorageItem.swift in Sources */,
E22990362D0F79D2009F8D77 /* OptionalStringPropertyView.swift in Sources */, E22990362D0F79D2009F8D77 /* OptionalStringPropertyView.swift in Sources */,
E2FD1D602D47EEEF00B48627 /* LocalizedPostContentView.swift in Sources */,
E229903C2D0F8A7B009F8D77 /* OptionalTextFieldPropertyView.swift in Sources */, E229903C2D0F8A7B009F8D77 /* OptionalTextFieldPropertyView.swift in Sources */,
E2FD1D582D477A9400B48627 /* InsertableCommand.swift in Sources */, E2FD1D582D477A9400B48627 /* InsertableCommand.swift in Sources */,
E2EC1FB42DC0FA8700C41784 /* Insert+Route.swift in Sources */, E2EC1FB42DC0FA8700C41784 /* Insert+Route.swift in Sources */,

View File

@@ -2,7 +2,7 @@ import SwiftUI
protocol MainContentView: View { protocol MainContentView: View {
associatedtype Item associatedtype Item: Identifiable
init(item: Item) init(item: Item)

View File

@@ -12,6 +12,7 @@ struct SelectedContentView<Contained>: View where Contained: MainContentView {
var body: some View { var body: some View {
if let item = selected { if let item = selected {
Contained(item: item) Contained(item: item)
.id(item.id)
} else { } else {
HStack { HStack {
Spacer() Spacer()

View File

@@ -12,7 +12,7 @@ struct SelectedDetailView<Contained>: View where Contained: MainContentView {
var body: some View { var body: some View {
if let item = selected { if let item = selected {
Contained(item: item) Contained(item: item)
//.id(item.id) .id(item.id)
} else { } else {
EmptyView() EmptyView()
} }

View File

@@ -18,7 +18,7 @@ struct TagDisplayView: View {
FlowHStack { FlowHStack {
ForEach(tags, id: \.identifier) { tag in ForEach(tags, id: \.identifier) { tag in
TagView(text: tag.localized(in: language).name) TagView(text: tag.localized(in: language).name)
.foregroundStyle(.white) .foregroundStyle(.white)
} }
Button(action: { showTagPicker = true }) { Button(action: { showTagPicker = true }) {
Image(systemSymbol: .squareAndPencilCircleFill) Image(systemSymbol: .squareAndPencilCircleFill)

View File

@@ -34,6 +34,7 @@ struct PageDetailView: View {
footer: "The page id is used to link to it internally.", footer: "The page id is used to link to it internally.",
validation: page.isValid, validation: page.isValid,
update: { page.update(id: $0) }) update: { page.update(id: $0) })
.id(page.id)
OptionalStringPropertyView( OptionalStringPropertyView(
title: "External url", title: "External url",

View File

@@ -7,5 +7,6 @@ struct LinkedPageTagView: View {
var body: some View { var body: some View {
TagDisplayView(tags: $page.tags) TagDisplayView(tags: $page.tags)
.id(page.id)
} }
} }

View File

@@ -15,11 +15,24 @@ struct PostContentView: View {
} }
var body: some View { var body: some View {
LocalizedPostContentView( let localized = post.localized(in: language)
post: post.localized(in: language), let other = post.localized(in: language.next)
other: post.localized(in: language.next), VStack(alignment: .leading) {
tags: $post.tags, PostImagesView(
page: $post.linkedPage) post: localized,
other: other)
PostTitleView(post: localized)
if let page = post.linkedPage {
LinkedPageTagView(page: page)
} else {
TagDisplayView(tags: $post.tags)
}
PostLabelsView(
post: localized,
other: other)
PostTextView(post: localized)
}
.padding()
} }
} }

View File

@@ -47,6 +47,7 @@ struct PostDetailView: View {
footer: "The id is used to link to post and store them", footer: "The id is used to link to post and store them",
validation: post.isValid, validation: post.isValid,
update: { post.update(id: $0) }) update: { post.update(id: $0) })
.id(post.id)
BoolPropertyView( BoolPropertyView(
title: "Draft", title: "Draft",
@@ -69,6 +70,7 @@ struct PostDetailView: View {
selectedPage: $post.linkedPage, selectedPage: $post.linkedPage,
footer: "The page to open when clicking on the post") footer: "The page to open when clicking on the post")
.onChange(of: post.linkedPage) { oldValue, newValue in .onChange(of: post.linkedPage) { oldValue, newValue in
if newValue != nil { if newValue != nil {
post.tags = [] post.tags = []
} else { } else {

View File

@@ -1,38 +1,22 @@
import SwiftUI import SwiftUI
struct LocalizedPostContentView: View { struct PostImagesView: View {
@Environment(\.language) @Environment(\.language)
private var language private var language
@EnvironmentObject
private var content: Content
@ObservedObject @ObservedObject
var post: LocalizedPost var post: LocalizedPost
@ObservedObject @ObservedObject
var other: LocalizedPost var other: LocalizedPost
@Binding
var tags: [Tag]
@Binding
var page: Page?
@State @State
private var fileTypeToSelect: FileTypeCategory = .image private var fileTypeToSelect: FileTypeCategory = .image
@State @State
private var showImagePicker = false 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 { var body: some View {
VStack(alignment: .leading) { VStack(alignment: .leading) {
HStack { HStack {
@@ -60,36 +44,11 @@ struct LocalizedPostContentView: View {
} }
} }
} }
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) { .sheet(isPresented: $showImagePicker) {
MultiFileSelectionView( MultiFileSelectionView(
selectedFiles: $post.images, selectedFiles: $post.images,
allowedType: fileTypeToSelect) allowedType: fileTypeToSelect)
} }
} }
private func copyImagesFromOtherLanguage() {
post.images = other.images
}
} }

View File

@@ -0,0 +1,18 @@
import SwiftUI
struct PostTextView: View {
@ObservedObject
var post: LocalizedPost
var body: some View {
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)
}
}

View File

@@ -0,0 +1,16 @@
import SwiftUI
struct PostTitleView: View {
@ObservedObject
var post: LocalizedPost
var body: some View {
OptionalTextField("", text: $post.title)
.font(.system(size: 24, weight: .bold))
.foregroundStyle(Color.primary)
.textFieldStyle(.plain)
.lineLimit(2)
.frame(minHeight: 30)
}
}

View File

@@ -38,6 +38,7 @@ struct TagDetailView: View {
validation: tag.isValid) { validation: tag.isValid) {
tag.update(id: $0) tag.update(id: $0)
} }
.id(tag.id)
LocalizedTagDetailView( LocalizedTagDetailView(
tag: tag.localized(in: language), tag: tag.localized(in: language),