Full generation, file type cleanup
This commit is contained in:
130
CHDataManagement/Views/Files/MultiFileSelectionView.swift
Normal file
130
CHDataManagement/Views/Files/MultiFileSelectionView.swift
Normal file
@ -0,0 +1,130 @@
|
||||
import SwiftUI
|
||||
|
||||
struct MultiFileSelectionView: View {
|
||||
|
||||
@Environment(\.dismiss)
|
||||
private var dismiss
|
||||
|
||||
@EnvironmentObject
|
||||
private var content: Content
|
||||
|
||||
@Binding
|
||||
private var selectedFiles: [FileResource]
|
||||
|
||||
let allowedType: FileFilterType?
|
||||
|
||||
let insertSorted: Bool
|
||||
|
||||
@State
|
||||
private var selectedFileType: FileFilterType
|
||||
|
||||
@State
|
||||
private var searchString = ""
|
||||
|
||||
@State
|
||||
private var newSelection: [FileResource]
|
||||
|
||||
init(selectedFiles: Binding<[FileResource]>, allowedType: FileFilterType? = nil, insertSorted: Bool = false) {
|
||||
self._selectedFiles = selectedFiles
|
||||
self.newSelection = selectedFiles.wrappedValue
|
||||
self.allowedType = allowedType
|
||||
self.selectedFileType = allowedType ?? .images
|
||||
self.insertSorted = insertSorted
|
||||
}
|
||||
|
||||
private var filesBySelectedType: [FileResource] {
|
||||
content.files.filter { selectedFileType.matches($0.type) }
|
||||
}
|
||||
|
||||
private var filteredFiles: [FileResource] {
|
||||
guard !searchString.isEmpty else {
|
||||
return filesBySelectedType
|
||||
}
|
||||
return filesBySelectedType.filter { $0.id.contains(searchString) }
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
VStack {
|
||||
Text("Selected files")
|
||||
.font(.title)
|
||||
List {
|
||||
ForEach(newSelection) { file in
|
||||
HStack {
|
||||
Image(systemSymbol: .minusCircleFill)
|
||||
.foregroundStyle(.red)
|
||||
.contentShape(Rectangle())
|
||||
.onTapGesture { deselect(file: file) }
|
||||
Text(file.id)
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
.onMove(perform: moveSelectedFile)
|
||||
}
|
||||
HStack {
|
||||
Button("Cancel") {
|
||||
DispatchQueue.main.async {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
Button("Save") {
|
||||
selectedFiles = newSelection
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
VStack {
|
||||
Picker("", selection: $selectedFileType) {
|
||||
ForEach(FileFilterType.allCases) { type in
|
||||
Text(type.text).tag(type)
|
||||
}
|
||||
}
|
||||
.pickerStyle(.segmented)
|
||||
.padding(.trailing, 7)
|
||||
.disabled(allowedType != nil)
|
||||
TextField("", text: $searchString, prompt: Text("Search"))
|
||||
.textFieldStyle(.roundedBorder)
|
||||
.padding(.horizontal, 8)
|
||||
List(filteredFiles) { file in
|
||||
HStack {
|
||||
if newSelection.contains(file) {
|
||||
Image(systemSymbol: .checkmarkCircleFill)
|
||||
.foregroundStyle(.gray)
|
||||
} else {
|
||||
Image(systemSymbol: .plusCircleFill)
|
||||
.foregroundStyle(.green)
|
||||
}
|
||||
Text(file.id)
|
||||
Spacer()
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
.onTapGesture { select(file: file) }
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(minHeight: 500, idealHeight: 600)
|
||||
.padding()
|
||||
}
|
||||
|
||||
private func deselect(file: FileResource) {
|
||||
guard let index = newSelection.firstIndex(of: file) else {
|
||||
return
|
||||
}
|
||||
newSelection.remove(at: index)
|
||||
}
|
||||
|
||||
private func select(file: FileResource) {
|
||||
guard !newSelection.contains(file) else {
|
||||
return
|
||||
}
|
||||
guard insertSorted else {
|
||||
newSelection.append(file)
|
||||
return
|
||||
}
|
||||
newSelection.insertSorted(file)
|
||||
}
|
||||
|
||||
private func moveSelectedFile(from source: IndexSet, to destination: Int) {
|
||||
newSelection.move(fromOffsets: source, toOffset: destination)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user