Add button command, fix list selection
This commit is contained in:
parent
eaad0a4bff
commit
e291fbec52
@ -203,6 +203,7 @@
|
|||||||
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 */; };
|
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 */; };
|
||||||
E2FE0EE62D15A0B5002963B7 /* GenerationResults.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2FE0EE52D15A0B1002963B7 /* GenerationResults.swift */; };
|
E2FE0EE62D15A0B5002963B7 /* GenerationResults.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2FE0EE52D15A0B1002963B7 /* GenerationResults.swift */; };
|
||||||
E2FE0EE82D16D4A3002963B7 /* ConvertThrowing.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2FE0EE72D16D4A3002963B7 /* ConvertThrowing.swift */; };
|
E2FE0EE82D16D4A3002963B7 /* ConvertThrowing.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2FE0EE72D16D4A3002963B7 /* ConvertThrowing.swift */; };
|
||||||
E2FE0EEC2D1C1253002963B7 /* MultiFileSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2FE0EEB2D1C124E002963B7 /* MultiFileSelectionView.swift */; };
|
E2FE0EEC2D1C1253002963B7 /* MultiFileSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2FE0EEB2D1C124E002963B7 /* MultiFileSelectionView.swift */; };
|
||||||
@ -451,6 +452,7 @@
|
|||||||
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>"; };
|
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>"; };
|
||||||
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>"; };
|
||||||
E2FE0EE72D16D4A3002963B7 /* ConvertThrowing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConvertThrowing.swift; sourceTree = "<group>"; };
|
E2FE0EE72D16D4A3002963B7 /* ConvertThrowing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConvertThrowing.swift; sourceTree = "<group>"; };
|
||||||
E2FE0EEB2D1C124E002963B7 /* MultiFileSelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiFileSelectionView.swift; sourceTree = "<group>"; };
|
E2FE0EEB2D1C124E002963B7 /* MultiFileSelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiFileSelectionView.swift; sourceTree = "<group>"; };
|
||||||
@ -933,6 +935,7 @@
|
|||||||
E2FD1D572D477A9400B48627 /* InsertableCommand.swift */,
|
E2FD1D572D477A9400B48627 /* InsertableCommand.swift */,
|
||||||
E2FD1D3A2D3BC40500B48627 /* InsertableCommandSheet.swift */,
|
E2FD1D3A2D3BC40500B48627 /* InsertableCommandSheet.swift */,
|
||||||
E2FD1D382D3BBECA00B48627 /* InsertableView.swift */,
|
E2FD1D382D3BBECA00B48627 /* InsertableView.swift */,
|
||||||
|
E2FD1D672D483CCA00B48627 /* Insert+Buttons.swift */,
|
||||||
E2FD1D362D3BBCB500B48627 /* Insert+Image.swift */,
|
E2FD1D362D3BBCB500B48627 /* Insert+Image.swift */,
|
||||||
E2FD1D552D46CED500B48627 /* Insert+Labels.swift */,
|
E2FD1D552D46CED500B48627 /* Insert+Labels.swift */,
|
||||||
);
|
);
|
||||||
@ -1254,6 +1257,7 @@
|
|||||||
E29D313F2D04822C0051B7F4 /* AddPostView.swift in Sources */,
|
E29D313F2D04822C0051B7F4 /* AddPostView.swift in Sources */,
|
||||||
E25DA5752D018B6100AEF16D /* FileDetailView.swift in Sources */,
|
E25DA5752D018B6100AEF16D /* FileDetailView.swift in Sources */,
|
||||||
E25DA50B2CFD988100AEF16D /* PageTagAssignmentView.swift in Sources */,
|
E25DA50B2CFD988100AEF16D /* PageTagAssignmentView.swift in Sources */,
|
||||||
|
E2FD1D682D483CCF00B48627 /* Insert+Buttons.swift in Sources */,
|
||||||
E29D31A12D0C75CA0051B7F4 /* Content+Validation.swift in Sources */,
|
E29D31A12D0C75CA0051B7F4 /* Content+Validation.swift in Sources */,
|
||||||
E29D316D2D07A5050051B7F4 /* PageGenerationResults.swift in Sources */,
|
E29D316D2D07A5050051B7F4 /* PageGenerationResults.swift in Sources */,
|
||||||
E229903E2D0F8F02009F8D77 /* StringPropertyView.swift in Sources */,
|
E229903E2D0F8F02009F8D77 /* StringPropertyView.swift in Sources */,
|
||||||
|
@ -66,23 +66,6 @@ final class ImageGenerator {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let data = version.image.dataContent() else {
|
|
||||||
print("ImageGenerator: Failed to load data for image \(version.image.id)")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let originalImage = NSImage(data: data) else {
|
|
||||||
print("ImageGenerator: Failed to load image \(version.image.id)")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
let representation = create(image: originalImage, width: CGFloat(version.maximumWidth), height: CGFloat(version.maximumHeight))
|
|
||||||
|
|
||||||
guard let data = create(image: representation, type: version.type, quality: version.quality) else {
|
|
||||||
print("ImageGenerator: Failed to get data for type \(version.type) of image \(version.image.id)")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if version.type == .avif {
|
if version.type == .avif {
|
||||||
if version.image.type == .gif {
|
if version.image.type == .gif {
|
||||||
// Skip GIFs, since they can't be converted by avifenc
|
// Skip GIFs, since they can't be converted by avifenc
|
||||||
@ -100,10 +83,27 @@ final class ImageGenerator {
|
|||||||
let quality = Int(version.quality * 100)
|
let quality = Int(version.quality * 100)
|
||||||
|
|
||||||
avifCommands.insert("avifenc -q \(quality) '\(originalImagePath)' '\(generatedImagePath)'")
|
avifCommands.insert("avifenc -q \(quality) '\(originalImagePath)' '\(generatedImagePath)'")
|
||||||
// hasNowGenerated(version)
|
version.wasNowGenerated()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
guard let data = version.image.dataContent() else {
|
||||||
|
print("ImageGenerator: Failed to load data for image \(version.image.id)")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let originalImage = NSImage(data: data) else {
|
||||||
|
print("ImageGenerator: Failed to load image \(version.image.id)")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
let representation = create(image: originalImage, width: CGFloat(version.maximumWidth), height: CGFloat(version.maximumHeight))
|
||||||
|
|
||||||
|
guard let data = create(image: representation, type: version.type, quality: version.quality) else {
|
||||||
|
print("ImageGenerator: Failed to get data for type \(version.type) of image \(version.image.id)")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
guard write(imageData: data, of: version) else {
|
guard write(imageData: data, of: version) else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -62,16 +62,11 @@ struct MainView: App {
|
|||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
var sidebar: some View {
|
var sidebar: some View {
|
||||||
switch selection.tab {
|
switch selection.tab {
|
||||||
case .posts:
|
case .posts: PostListView()
|
||||||
PostListView(selectedPost: $selection.post)
|
case .pages: PageListView()
|
||||||
case .pages:
|
case .tags: TagListView()
|
||||||
PageListView(selectedPage: $selection.page)
|
case .files: FileListView(selectedFile: $selection.file)
|
||||||
case .tags:
|
case .generation: SettingsListView()
|
||||||
TagListView(selectedTag: $selection.tag)
|
|
||||||
case .files:
|
|
||||||
FileListView(selectedFile: $selection.file)
|
|
||||||
case .generation:
|
|
||||||
SettingsListView(selectedSection: $selection.section)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +66,6 @@ extension Content {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func generateRequiredImages() {
|
private func generateRequiredImages() {
|
||||||
|
|
||||||
let images = results.imagesToGenerate.sorted()
|
let images = results.imagesToGenerate.sorted()
|
||||||
let count = images.count
|
let count = images.count
|
||||||
var completed = 0
|
var completed = 0
|
||||||
@ -83,8 +82,6 @@ extension Content {
|
|||||||
}
|
}
|
||||||
|
|
||||||
imageGenerator.writeAvifCommandScript()
|
imageGenerator.writeAvifCommandScript()
|
||||||
//let images = Set(self.images.map { $0.id })
|
|
||||||
//imageGenerator.recalculateGeneratedImages(by: images)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateAllPages() {
|
func generateAllPages() {
|
||||||
|
@ -51,8 +51,19 @@ struct FileListView: View {
|
|||||||
TextField("", text: $searchString, prompt: Text("Search"))
|
TextField("", text: $searchString, prompt: Text("Search"))
|
||||||
.textFieldStyle(.roundedBorder)
|
.textFieldStyle(.roundedBorder)
|
||||||
.padding(.horizontal, 8)
|
.padding(.horizontal, 8)
|
||||||
List(filteredFiles, selection: $selectedFile) { file in
|
List(filteredFiles) { file in
|
||||||
Text(file.id).tag(file)
|
HStack {
|
||||||
|
Text(file.id)
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
.listRowBackground(RoundedRectangle(cornerRadius: 5)
|
||||||
|
.fill(selectedFile == file ? Color.blue : Color.clear)
|
||||||
|
.padding(.horizontal, 10)
|
||||||
|
)
|
||||||
|
.contentShape(Rectangle())
|
||||||
|
.onTapGesture {
|
||||||
|
selectedFile = file
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.onChange(of: selectedFileType) { oldValue, newValue in
|
.onChange(of: selectedFileType) { oldValue, newValue in
|
||||||
guard oldValue != newValue else {
|
guard oldValue != newValue else {
|
||||||
|
200
CHDataManagement/Views/Pages/Commands/Insert+Buttons.swift
Normal file
200
CHDataManagement/Views/Pages/Commands/Insert+Buttons.swift
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
import SwiftUI
|
||||||
|
import SFSafeSymbols
|
||||||
|
|
||||||
|
final class InsertableFileButton: ObservableObject {
|
||||||
|
|
||||||
|
@Published
|
||||||
|
var label: ContentLabel = .init(icon: .buttonDownload, value: "Text")
|
||||||
|
|
||||||
|
@Published
|
||||||
|
var file: FileResource?
|
||||||
|
|
||||||
|
@Published
|
||||||
|
var downloadedFileName: String? = nil
|
||||||
|
|
||||||
|
var command: String? {
|
||||||
|
guard let file else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
let result =
|
||||||
|
"""
|
||||||
|
icon: \(label.icon.rawValue)
|
||||||
|
text: \(label.value)
|
||||||
|
file: \(file.id)
|
||||||
|
"""
|
||||||
|
guard let downloadedFileName else {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
return result + "\n" + "name: \(downloadedFileName)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final class InsertableUrlButton: ObservableObject {
|
||||||
|
|
||||||
|
@Published
|
||||||
|
var label: ContentLabel = .init(icon: .buttonDownload, value: "Text")
|
||||||
|
|
||||||
|
@Published
|
||||||
|
var url: String = "Url"
|
||||||
|
|
||||||
|
var command: String? {
|
||||||
|
"""
|
||||||
|
icon: \(label.icon.rawValue)
|
||||||
|
text: \(label.value)
|
||||||
|
url: \(url)
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final class InsertableEventButton: ObservableObject {
|
||||||
|
|
||||||
|
@Published
|
||||||
|
var label: ContentLabel = .init(icon: .buttonDownload, value: "Text")
|
||||||
|
|
||||||
|
@Published
|
||||||
|
var event: String = "Javascript"
|
||||||
|
|
||||||
|
var command: String? {
|
||||||
|
"""
|
||||||
|
icon: \(label.icon.rawValue)
|
||||||
|
text: \(label.value)
|
||||||
|
event: \(event)
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct InsertableButtons: View, InsertableCommandView {
|
||||||
|
|
||||||
|
final class Model: ObservableObject, InsertableCommandModel {
|
||||||
|
|
||||||
|
enum AnyButton: Identifiable {
|
||||||
|
case file(InsertableFileButton)
|
||||||
|
case url(InsertableUrlButton)
|
||||||
|
case event(InsertableEventButton)
|
||||||
|
|
||||||
|
var command: String? {
|
||||||
|
switch self {
|
||||||
|
case .file(let file):
|
||||||
|
return file.command
|
||||||
|
case .url(let url):
|
||||||
|
return url.command
|
||||||
|
case .event(let event):
|
||||||
|
return event.command
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var id: String {
|
||||||
|
switch self {
|
||||||
|
case .file(let file):
|
||||||
|
return "file-\(file.file?.id ?? "none")"
|
||||||
|
case .url(let url):
|
||||||
|
return "url-\(url.url)"
|
||||||
|
case .event(let event):
|
||||||
|
return "event-\(event.event)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Published
|
||||||
|
var buttons: [AnyButton] = []
|
||||||
|
|
||||||
|
var isReady: Bool {
|
||||||
|
!buttons.isEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
var command: String? {
|
||||||
|
let result = buttons.compactMap { $0.command }
|
||||||
|
guard result.count == buttons.count else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return result.map {
|
||||||
|
"```buttons\n\($0)\n```"
|
||||||
|
}.joined(separator: "\n\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static let title = "Buttons"
|
||||||
|
|
||||||
|
static let sheetTitle = "Insert buttons"
|
||||||
|
|
||||||
|
static let icon: SFSymbol = .rectangleAndHandPointUpLeft
|
||||||
|
|
||||||
|
@ObservedObject
|
||||||
|
private var model: Model
|
||||||
|
|
||||||
|
init(model: Model) {
|
||||||
|
self.model = model
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
List(model.buttons) { button in
|
||||||
|
switch button {
|
||||||
|
case .file(let file):
|
||||||
|
FileButtonView(content: file)
|
||||||
|
case .url(let url):
|
||||||
|
UrlButtonView(content: url)
|
||||||
|
case .event(let event):
|
||||||
|
EventButtonView(content: event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.frame(minHeight: 300)
|
||||||
|
HStack {
|
||||||
|
Spacer()
|
||||||
|
Button("File", action: { model.buttons.append(.file(.init())) })
|
||||||
|
Button("Url", action: { model.buttons.append(.url(.init())) })
|
||||||
|
Button("Event", action: { model.buttons.append(.event(.init())) })
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct FileButtonView: View {
|
||||||
|
|
||||||
|
@ObservedObject
|
||||||
|
var content: InsertableFileButton
|
||||||
|
|
||||||
|
@State
|
||||||
|
private var showFileSelectionSheet = false
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
HStack {
|
||||||
|
LabelEditingView(label: content.label)
|
||||||
|
Button("\(content.file?.id ?? "Select file")", action: { showFileSelectionSheet = true })
|
||||||
|
OptionalTextField("", text: $content.downloadedFileName, prompt: "Downloaded file name")
|
||||||
|
.textFieldStyle(.roundedBorder)
|
||||||
|
}
|
||||||
|
.sheet(isPresented: $showFileSelectionSheet) {
|
||||||
|
FileSelectionView(selectedFile: $content.file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct UrlButtonView: View {
|
||||||
|
|
||||||
|
@ObservedObject
|
||||||
|
var content: InsertableUrlButton
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
HStack {
|
||||||
|
LabelEditingView(label: content.label)
|
||||||
|
TextField("", text: $content.url, prompt: Text("URL"))
|
||||||
|
.textFieldStyle(.roundedBorder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct EventButtonView: View {
|
||||||
|
|
||||||
|
@ObservedObject
|
||||||
|
var content: InsertableEventButton
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
HStack {
|
||||||
|
LabelEditingView(label: content.label)
|
||||||
|
TextField("", text: $content.event, prompt: Text("Javascript"))
|
||||||
|
.textFieldStyle(.roundedBorder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,7 @@ struct InsertableItemsView: View {
|
|||||||
.font(.headline)
|
.font(.headline)
|
||||||
InsertableView<InsertableImage>()
|
InsertableView<InsertableImage>()
|
||||||
InsertableView<InsertableLabels>()
|
InsertableView<InsertableLabels>()
|
||||||
|
InsertableView<InsertableButtons>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,17 +41,15 @@ struct PageListView: View {
|
|||||||
private var language
|
private var language
|
||||||
|
|
||||||
@EnvironmentObject
|
@EnvironmentObject
|
||||||
private var content: Content
|
private var selection: SelectedContent
|
||||||
|
|
||||||
@Binding
|
@EnvironmentObject
|
||||||
private var selectedPage: Page?
|
private var content: Content
|
||||||
|
|
||||||
@State
|
@State
|
||||||
private var searchString = ""
|
private var searchString = ""
|
||||||
|
|
||||||
init(selectedPage: Binding<Page?>) {
|
init() { }
|
||||||
self._selectedPage = selectedPage
|
|
||||||
}
|
|
||||||
|
|
||||||
private var filteredPages: [Page] {
|
private var filteredPages: [Page] {
|
||||||
guard !searchString.isEmpty else {
|
guard !searchString.isEmpty else {
|
||||||
@ -65,20 +63,30 @@ struct PageListView: View {
|
|||||||
TextField("", text: $searchString, prompt: Text("Search"))
|
TextField("", text: $searchString, prompt: Text("Search"))
|
||||||
.textFieldStyle(.roundedBorder)
|
.textFieldStyle(.roundedBorder)
|
||||||
.padding(.horizontal, 8)
|
.padding(.horizontal, 8)
|
||||||
List(filteredPages, selection: $selectedPage) { page in
|
List(filteredPages) { page in
|
||||||
PageListItem(page: page)
|
PageListItem(page: page)
|
||||||
.tag(page)
|
.listRowBackground(RoundedRectangle(cornerRadius: 5)
|
||||||
|
.fill(selection.page == page ? Color.blue : Color.clear)
|
||||||
|
.padding(.horizontal, 10)
|
||||||
|
)
|
||||||
|
.contentShape(Rectangle())
|
||||||
|
.onTapGesture {
|
||||||
|
selection.page = page
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
if selectedPage == nil {
|
if selection.page == nil, let first = content.pages.first {
|
||||||
selectedPage = content.pages.first
|
selection.page = first
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
PageListView(selectedPage: .constant(nil))
|
let content = Content.mock
|
||||||
.environmentObject(Content.mock)
|
let selection = SelectedContent()
|
||||||
|
PageListView()
|
||||||
|
.environmentObject(content)
|
||||||
|
.environmentObject(selection)
|
||||||
}
|
}
|
||||||
|
@ -48,15 +48,13 @@ struct PostListView: View {
|
|||||||
@EnvironmentObject
|
@EnvironmentObject
|
||||||
private var content: Content
|
private var content: Content
|
||||||
|
|
||||||
@Binding
|
@EnvironmentObject
|
||||||
private var selectedPost: Post?
|
private var selection: SelectedContent
|
||||||
|
|
||||||
@State
|
@State
|
||||||
private var searchString = ""
|
private var searchString = ""
|
||||||
|
|
||||||
init(selectedPost: Binding<Post?>) {
|
init() { }
|
||||||
self._selectedPost = selectedPost
|
|
||||||
}
|
|
||||||
|
|
||||||
private var filteredPosts: [Post] {
|
private var filteredPosts: [Post] {
|
||||||
guard !searchString.isEmpty else {
|
guard !searchString.isEmpty else {
|
||||||
@ -74,13 +72,20 @@ struct PostListView: View {
|
|||||||
TextField("", text: $searchString, prompt: Text("Search"))
|
TextField("", text: $searchString, prompt: Text("Search"))
|
||||||
.textFieldStyle(.roundedBorder)
|
.textFieldStyle(.roundedBorder)
|
||||||
.padding(.horizontal, 8)
|
.padding(.horizontal, 8)
|
||||||
List(filteredAndSortedPosts, selection: $selectedPost) { post in
|
List(filteredAndSortedPosts) { post in
|
||||||
PostListItem(post: post)
|
PostListItem(post: post)
|
||||||
.tag(post)
|
.listRowBackground(RoundedRectangle(cornerRadius: 5)
|
||||||
|
.fill(selection.post == post ? Color.blue : Color.clear)
|
||||||
|
.padding(.horizontal, 10)
|
||||||
|
)
|
||||||
|
.contentShape(Rectangle())
|
||||||
|
.onTapGesture {
|
||||||
|
selection.post = post
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}.onAppear {
|
}.onAppear {
|
||||||
if selectedPost == nil {
|
if selection.post == nil, let first = content.posts.first {
|
||||||
selectedPost = content.posts.first
|
selection.post = first
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,20 @@ import SwiftUI
|
|||||||
|
|
||||||
struct SettingsListView: View {
|
struct SettingsListView: View {
|
||||||
|
|
||||||
@Binding
|
@EnvironmentObject
|
||||||
var selectedSection: SettingsSection
|
private var selection: SelectedContent
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
List(SettingsSection.allCases, selection: $selectedSection) { item in
|
List(SettingsSection.allCases) { section in
|
||||||
Label(item.rawValue, systemSymbol: item.icon).tag(item)
|
Label(section.rawValue, systemSymbol: section.icon)
|
||||||
|
.listRowBackground(RoundedRectangle(cornerRadius: 5)
|
||||||
|
.fill(selection.section == section ? Color.blue : Color.clear)
|
||||||
|
.padding(.horizontal, 10)
|
||||||
|
)
|
||||||
|
.contentShape(Rectangle())
|
||||||
|
.onTapGesture {
|
||||||
|
selection.section = section
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,15 +8,13 @@ struct TagListView: View {
|
|||||||
@EnvironmentObject
|
@EnvironmentObject
|
||||||
private var content: Content
|
private var content: Content
|
||||||
|
|
||||||
@Binding
|
@EnvironmentObject
|
||||||
var selectedTag: Tag?
|
private var selection: SelectedContent
|
||||||
|
|
||||||
@State
|
@State
|
||||||
private var searchString = ""
|
private var searchString = ""
|
||||||
|
|
||||||
init(selectedTag: Binding<Tag?>) {
|
init() { }
|
||||||
_selectedTag = selectedTag
|
|
||||||
}
|
|
||||||
|
|
||||||
private var filteredTags: [Tag] {
|
private var filteredTags: [Tag] {
|
||||||
guard !searchString.isEmpty else {
|
guard !searchString.isEmpty else {
|
||||||
@ -34,13 +32,20 @@ struct TagListView: View {
|
|||||||
TextField("", text: $searchString, prompt: Text("Search"))
|
TextField("", text: $searchString, prompt: Text("Search"))
|
||||||
.textFieldStyle(.roundedBorder)
|
.textFieldStyle(.roundedBorder)
|
||||||
.padding(.horizontal, 8)
|
.padding(.horizontal, 8)
|
||||||
List(filteredAndSortedTags, selection: $selectedTag) { tag in
|
List(filteredAndSortedTags) { tag in
|
||||||
TagListItem(tag: tag.localized(in: language))
|
TagListItem(tag: tag.localized(in: language))
|
||||||
.tag(tag)
|
.listRowBackground(RoundedRectangle(cornerRadius: 5)
|
||||||
|
.fill(selection.tag == tag ? Color.blue : Color.clear)
|
||||||
|
.padding(.horizontal, 10)
|
||||||
|
)
|
||||||
|
.contentShape(Rectangle())
|
||||||
|
.onTapGesture {
|
||||||
|
selection.tag = tag
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}.onAppear {
|
}.onAppear {
|
||||||
if selectedTag == nil {
|
if selection.tag == nil, let first = content.tags.first {
|
||||||
selectedTag = content.tags.first
|
selection.tag = first
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -52,6 +57,9 @@ private struct TagListItem: View {
|
|||||||
var tag: LocalizedTag
|
var tag: LocalizedTag
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Text(tag.title)
|
HStack {
|
||||||
|
Text(tag.title)
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user