From 8508719dbea5a359c25ce9f3f17a67991768db37 Mon Sep 17 00:00:00 2001 From: Christoph Hagen Date: Mon, 16 Jun 2025 10:09:38 +0200 Subject: [PATCH] Fix tag assignment in post UI --- CHDataManagement.xcodeproj/project.pbxproj | 16 +++++-- CHDataManagement/Main/MainContentView.swift | 2 +- .../Main/SelectedContentView.swift | 1 + .../Main/SelectedDetailView.swift | 2 +- .../Views/Generic/TagDisplayView.swift | 2 +- .../Views/Pages/PageDetailView.swift | 1 + .../Views/Posts/LinkedPageTagView.swift | 1 + .../Views/Posts/PostContentView.swift | 23 +++++++--- .../Views/Posts/PostDetailView.swift | 2 + ...ContentView.swift => PostImagesView.swift} | 43 +------------------ .../Views/Posts/PostTextView.swift | 18 ++++++++ .../Views/Posts/PostTitleView.swift | 16 +++++++ .../Views/Tags/TagDetailView.swift | 1 + 13 files changed, 74 insertions(+), 54 deletions(-) rename CHDataManagement/Views/Posts/{LocalizedPostContentView.swift => PostImagesView.swift} (53%) create mode 100644 CHDataManagement/Views/Posts/PostTextView.swift create mode 100644 CHDataManagement/Views/Posts/PostTitleView.swift diff --git a/CHDataManagement.xcodeproj/project.pbxproj b/CHDataManagement.xcodeproj/project.pbxproj index 2104fb9..45ae075 100644 --- a/CHDataManagement.xcodeproj/project.pbxproj +++ b/CHDataManagement.xcodeproj/project.pbxproj @@ -7,6 +7,9 @@ objects = { /* 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 */; }; E20BCC992D53597D00B8DBEB /* SaveState.swift in Sources */ = {isa = PBXBuildFile; fileRef = E20BCC982D53597D00B8DBEB /* SaveState.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 */; }; E2FD1D5C2D47EEB800B48627 /* LinkedPageTagView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2FD1D5B2D47EEB800B48627 /* LinkedPageTagView.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 */; }; E2FD1D682D483CCF00B48627 /* Insert+Buttons.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2FD1D672D483CCA00B48627 /* Insert+Buttons.swift */; }; E2FE0EE62D15A0B5002963B7 /* GenerationResults.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2FE0EE52D15A0B1002963B7 /* GenerationResults.swift */; }; @@ -299,6 +301,9 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + E2039A142E0001B200305538 /* PostImagesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostImagesView.swift; sourceTree = ""; }; + E2039A162E00027300305538 /* PostTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostTitleView.swift; sourceTree = ""; }; + E2039A182E0002C100305538 /* PostTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostTextView.swift; sourceTree = ""; }; E20BCC962D53454500B8DBEB /* StorageItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageItem.swift; sourceTree = ""; }; E20BCC982D53597D00B8DBEB /* SaveState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SaveState.swift; sourceTree = ""; }; E20BCC9A2D535C3100B8DBEB /* ChangeObservableItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChangeObservableItem.swift; sourceTree = ""; }; @@ -524,7 +529,6 @@ E2FD1D592D477AB200B48627 /* InsertableItemsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsertableItemsView.swift; sourceTree = ""; }; E2FD1D5B2D47EEB800B48627 /* LinkedPageTagView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkedPageTagView.swift; sourceTree = ""; }; E2FD1D5D2D47EED200B48627 /* PostImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostImageView.swift; sourceTree = ""; }; - E2FD1D5F2D47EEEF00B48627 /* LocalizedPostContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizedPostContentView.swift; sourceTree = ""; }; E2FD1D632D47EF4200B48627 /* DetailListItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailListItem.swift; sourceTree = ""; }; E2FD1D672D483CCA00B48627 /* Insert+Buttons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Insert+Buttons.swift"; sourceTree = ""; }; E2FE0EE52D15A0B1002963B7 /* GenerationResults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenerationResults.swift; sourceTree = ""; }; @@ -1019,6 +1023,9 @@ E2FD1D3E2D46404900B48627 /* PostLabelsView.swift */, E29D31502D0616890051B7F4 /* PostListView.swift */, E218502A2CF790AC0090B18B /* PostContentView.swift */, + E2039A182E0002C100305538 /* PostTextView.swift */, + E2039A162E00027300305538 /* PostTitleView.swift */, + E2039A142E0001B200305538 /* PostImagesView.swift */, E21850262CF3B42D0090B18B /* PostDetailView.swift */, E29D313E2D04822C0051B7F4 /* AddPostView.swift */, E21850222CF10C840090B18B /* TagSelectionView.swift */, @@ -1026,7 +1033,6 @@ E2A21C072CB17B810060935B /* TagView.swift */, E29D31312D03B5610051B7F4 /* LocalizedPostDetailView.swift */, E2FD1D5D2D47EED200B48627 /* PostImageView.swift */, - E2FD1D5F2D47EEEF00B48627 /* LocalizedPostContentView.swift */, E2FD1D5B2D47EEB800B48627 /* LinkedPageTagView.swift */, ); path = Posts; @@ -1352,6 +1358,7 @@ E29D317D2D086AB00051B7F4 /* Int+Random.swift in Sources */, E2BF1BC62D6B16FF003089F1 /* HeadlineLink.swift in Sources */, E25DA56F2D00F9A100AEF16D /* PostFeedSettingsView.swift in Sources */, + E2039A192E0002C500305538 /* PostTextView.swift in Sources */, E2521E042D51796000C56662 /* StorageStatusView.swift in Sources */, E29D313B2D04464A0051B7F4 /* LocalizedTagDetailView.swift in Sources */, E2FE0F552D2BCFC4002963B7 /* ContentBlock.swift in Sources */, @@ -1381,6 +1388,7 @@ E242520A2C52C9260029FF16 /* ContentLanguage.swift in Sources */, E2B85F452C429ED60047CD0C /* ImageGallery.swift in Sources */, E2B85F3B2C428F0E0047CD0C /* Post.swift in Sources */, + E2039A152E0001B700305538 /* PostImagesView.swift in Sources */, E29D31852D0AE8EE0051B7F4 /* KnownHeaderElement.swift in Sources */, E25DA51B2CFF08BB00AEF16D /* PostFeedPageNavigation.swift in Sources */, E22990422D107A95009F8D77 /* ImageVersion.swift in Sources */, @@ -1433,6 +1441,7 @@ E229901E2D0E4364009F8D77 /* LocalizedItem.swift in Sources */, E29D31262D0370A80051B7F4 /* VideoCommand+Option.swift in Sources */, E2FE0EF82D1D8110002963B7 /* IconCommand.swift in Sources */, + E2039A172E00027600305538 /* PostTitleView.swift in Sources */, E2F3B39E2DC55B1C00CFA712 /* LabelCreationView.swift in Sources */, E21850272CF3B42D0090B18B /* PostDetailView.swift in Sources */, E22990242D0EDBD0009F8D77 /* HeaderElement.swift in Sources */, @@ -1592,7 +1601,6 @@ E2FD1D0D2D2DBBA600B48627 /* LinkPreview.swift in Sources */, E20BCC972D53454C00B8DBEB /* StorageItem.swift in Sources */, E22990362D0F79D2009F8D77 /* OptionalStringPropertyView.swift in Sources */, - E2FD1D602D47EEEF00B48627 /* LocalizedPostContentView.swift in Sources */, E229903C2D0F8A7B009F8D77 /* OptionalTextFieldPropertyView.swift in Sources */, E2FD1D582D477A9400B48627 /* InsertableCommand.swift in Sources */, E2EC1FB42DC0FA8700C41784 /* Insert+Route.swift in Sources */, diff --git a/CHDataManagement/Main/MainContentView.swift b/CHDataManagement/Main/MainContentView.swift index 4e89d61..d11826e 100644 --- a/CHDataManagement/Main/MainContentView.swift +++ b/CHDataManagement/Main/MainContentView.swift @@ -2,7 +2,7 @@ import SwiftUI protocol MainContentView: View { - associatedtype Item + associatedtype Item: Identifiable init(item: Item) diff --git a/CHDataManagement/Main/SelectedContentView.swift b/CHDataManagement/Main/SelectedContentView.swift index 02a5be0..d016594 100644 --- a/CHDataManagement/Main/SelectedContentView.swift +++ b/CHDataManagement/Main/SelectedContentView.swift @@ -12,6 +12,7 @@ struct SelectedContentView: View where Contained: MainContentView { var body: some View { if let item = selected { Contained(item: item) + .id(item.id) } else { HStack { Spacer() diff --git a/CHDataManagement/Main/SelectedDetailView.swift b/CHDataManagement/Main/SelectedDetailView.swift index 1721b94..e20dd25 100644 --- a/CHDataManagement/Main/SelectedDetailView.swift +++ b/CHDataManagement/Main/SelectedDetailView.swift @@ -12,7 +12,7 @@ struct SelectedDetailView: View where Contained: MainContentView { var body: some View { if let item = selected { Contained(item: item) - //.id(item.id) + .id(item.id) } else { EmptyView() } diff --git a/CHDataManagement/Views/Generic/TagDisplayView.swift b/CHDataManagement/Views/Generic/TagDisplayView.swift index 9975fff..0319060 100644 --- a/CHDataManagement/Views/Generic/TagDisplayView.swift +++ b/CHDataManagement/Views/Generic/TagDisplayView.swift @@ -18,7 +18,7 @@ struct TagDisplayView: View { FlowHStack { ForEach(tags, id: \.identifier) { tag in TagView(text: tag.localized(in: language).name) - .foregroundStyle(.white) + .foregroundStyle(.white) } Button(action: { showTagPicker = true }) { Image(systemSymbol: .squareAndPencilCircleFill) diff --git a/CHDataManagement/Views/Pages/PageDetailView.swift b/CHDataManagement/Views/Pages/PageDetailView.swift index c567337..c5a434a 100644 --- a/CHDataManagement/Views/Pages/PageDetailView.swift +++ b/CHDataManagement/Views/Pages/PageDetailView.swift @@ -34,6 +34,7 @@ struct PageDetailView: View { footer: "The page id is used to link to it internally.", validation: page.isValid, update: { page.update(id: $0) }) + .id(page.id) OptionalStringPropertyView( title: "External url", diff --git a/CHDataManagement/Views/Posts/LinkedPageTagView.swift b/CHDataManagement/Views/Posts/LinkedPageTagView.swift index e5d683a..9dbd8f8 100644 --- a/CHDataManagement/Views/Posts/LinkedPageTagView.swift +++ b/CHDataManagement/Views/Posts/LinkedPageTagView.swift @@ -7,5 +7,6 @@ struct LinkedPageTagView: View { var body: some View { TagDisplayView(tags: $page.tags) + .id(page.id) } } diff --git a/CHDataManagement/Views/Posts/PostContentView.swift b/CHDataManagement/Views/Posts/PostContentView.swift index 4fe0c66..d863774 100644 --- a/CHDataManagement/Views/Posts/PostContentView.swift +++ b/CHDataManagement/Views/Posts/PostContentView.swift @@ -15,11 +15,24 @@ struct PostContentView: View { } var body: some View { - LocalizedPostContentView( - post: post.localized(in: language), - other: post.localized(in: language.next), - tags: $post.tags, - page: $post.linkedPage) + let localized = post.localized(in: language) + let other = post.localized(in: language.next) + VStack(alignment: .leading) { + PostImagesView( + 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() } } diff --git a/CHDataManagement/Views/Posts/PostDetailView.swift b/CHDataManagement/Views/Posts/PostDetailView.swift index f55574b..12c3169 100644 --- a/CHDataManagement/Views/Posts/PostDetailView.swift +++ b/CHDataManagement/Views/Posts/PostDetailView.swift @@ -47,6 +47,7 @@ struct PostDetailView: View { footer: "The id is used to link to post and store them", validation: post.isValid, update: { post.update(id: $0) }) + .id(post.id) BoolPropertyView( title: "Draft", @@ -69,6 +70,7 @@ struct PostDetailView: View { selectedPage: $post.linkedPage, footer: "The page to open when clicking on the post") .onChange(of: post.linkedPage) { oldValue, newValue in + if newValue != nil { post.tags = [] } else { diff --git a/CHDataManagement/Views/Posts/LocalizedPostContentView.swift b/CHDataManagement/Views/Posts/PostImagesView.swift similarity index 53% rename from CHDataManagement/Views/Posts/LocalizedPostContentView.swift rename to CHDataManagement/Views/Posts/PostImagesView.swift index d960d52..8d6a1de 100644 --- a/CHDataManagement/Views/Posts/LocalizedPostContentView.swift +++ b/CHDataManagement/Views/Posts/PostImagesView.swift @@ -1,38 +1,22 @@ import SwiftUI -struct LocalizedPostContentView: View { +struct PostImagesView: 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 { @@ -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) { MultiFileSelectionView( selectedFiles: $post.images, allowedType: fileTypeToSelect) } } - - private func copyImagesFromOtherLanguage() { - post.images = other.images - } } diff --git a/CHDataManagement/Views/Posts/PostTextView.swift b/CHDataManagement/Views/Posts/PostTextView.swift new file mode 100644 index 0000000..546df34 --- /dev/null +++ b/CHDataManagement/Views/Posts/PostTextView.swift @@ -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) + } +} diff --git a/CHDataManagement/Views/Posts/PostTitleView.swift b/CHDataManagement/Views/Posts/PostTitleView.swift new file mode 100644 index 0000000..80a25b5 --- /dev/null +++ b/CHDataManagement/Views/Posts/PostTitleView.swift @@ -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) + } +} diff --git a/CHDataManagement/Views/Tags/TagDetailView.swift b/CHDataManagement/Views/Tags/TagDetailView.swift index e9b663e..3c6d197 100644 --- a/CHDataManagement/Views/Tags/TagDetailView.swift +++ b/CHDataManagement/Views/Tags/TagDetailView.swift @@ -38,6 +38,7 @@ struct TagDetailView: View { validation: tag.isValid) { tag.update(id: $0) } + .id(tag.id) LocalizedTagDetailView( tag: tag.localized(in: language),