Implement batch delete functionality in HistoryView, allowing users to select multiple items for deletion; enhance UI with confirmation views and improved state management for better user experience.

main
v504 2 months ago
parent 37d8d72922
commit d40cb9eb99

@ -82,36 +82,6 @@
endingLineNumber = "243" endingLineNumber = "243"
landmarkName = "HistoryView" landmarkName = "HistoryView"
landmarkType = "14"> landmarkType = "14">
<Locations>
<Location
uuid = "79506791-23FD-416B-9053-8A0FE086814D - b2ff3d7d29aa52a4"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
symbolName = "closure #1 () -&gt; () in closure #1 (MyQrCode.HistoryView.HistoryFilter) -&gt; MyQrCode.FilterChip in closure #1 () -&gt; SwiftUI.ForEach&lt;Swift.Array&lt;MyQrCode.HistoryView.HistoryFilter&gt;, MyQrCode.HistoryView.HistoryFilter, MyQrCode.FilterChip&gt; in closure #1 () -&gt; &lt;&lt;opaque return type of SwiftUI.View.padding(SwiftUI.Edge.Set, Swift.Optional&lt;CoreGraphics.CGFloat&gt;) -&gt; some&gt;&gt;.0 in MyQrCode.HistoryView.filterBar.getter : some"
moduleName = "MyQrCode.debug.dylib"
usesParentBreakpointCondition = "Yes"
urlString = "file:///Users/yc/xcodeProjects/MyQrCode/MyQrCode/Views/HistoryView.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "243"
endingLineNumber = "243">
</Location>
<Location
uuid = "79506791-23FD-416B-9053-8A0FE086814D - 64fc53eb1c4f7b39"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
symbolName = "MyQrCode.HistoryView.historyList.getter : some"
moduleName = "MyQrCode.debug.dylib"
usesParentBreakpointCondition = "Yes"
urlString = "file:///Users/yc/xcodeProjects/MyQrCode/MyQrCode/Views/HistoryView.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "244"
endingLineNumber = "244">
</Location>
</Locations>
</BreakpointContent> </BreakpointContent>
</BreakpointProxy> </BreakpointProxy>
</Breakpoints> </Breakpoints>

@ -6,12 +6,14 @@ struct HistoryView: View {
@State private var searchText = "" @State private var searchText = ""
@State private var selectedFilter: HistoryFilter = .all @State private var selectedFilter: HistoryFilter = .all
@State private var showingCreateSheet = false @State private var showingCreateSheet = false
@State private var showingClearAlert = false
@State private var itemToDelete: HistoryItem? @State private var itemToDelete: HistoryItem?
@State private var showingDeleteAlert = false @State private var showingDeleteAlert = false
@State private var showingClearConfirmSheet = false
@State private var allHistoryItems: [HistoryItem] = [] @State private var allHistoryItems: [HistoryItem] = []
@State private var isLoading = false @State private var isLoading = false
@State private var refreshTrigger = false @State private var refreshTrigger = false
@State private var isBatchDeleteMode = false
@State private var selectedItemsForDelete: Set<UUID> = []
enum HistoryFilter: String, CaseIterable { enum HistoryFilter: String, CaseIterable {
case all = "all" case all = "all"
@ -107,34 +109,68 @@ struct HistoryView: View {
.navigationTitle("历史记录") .navigationTitle("历史记录")
.navigationBarTitleDisplayMode(.large) .navigationBarTitleDisplayMode(.large)
.toolbar { .toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button(action: {
showingClearAlert = true
}) {
Image(systemName: "trash")
.foregroundColor(.red)
}
.disabled(coreDataManager.fetchHistoryItems().isEmpty)
}
ToolbarItem(placement: .navigationBarTrailing) { ToolbarItem(placement: .navigationBarTrailing) {
Button(action: { HStack(spacing: 16) {
showingCreateSheet = true if isBatchDeleteMode {
}) { //
Image(systemName: "plus") Button(action: {
// /
if selectedItemsForDelete.count == filteredItems.count {
selectedItemsForDelete.removeAll()
} else {
selectedItemsForDelete = Set(filteredItems.compactMap { $0.id })
}
}) {
Image(systemName: selectedItemsForDelete.count == filteredItems.count ? "checkmark.rectangle.fill" : "rectangle.on.rectangle")
.foregroundColor(.blue)
}
Button(action: {
if !selectedItemsForDelete.isEmpty {
deleteSelectedItems()
}
}) {
Image(systemName: "trash.fill")
.foregroundColor(.red)
}
.disabled(selectedItemsForDelete.isEmpty)
//
Button(action: {
exitBatchDeleteMode()
}) {
Image(systemName: "xmark.circle")
.foregroundColor(.gray)
}
} else {
//
//
if !allHistoryItems.isEmpty {
Button(action: {
enterBatchDeleteMode()
}) {
Image(systemName: "trash")
.foregroundColor(.red)
}
}
Button(action: {
showingCreateSheet = true
}) {
Image(systemName: "plus")
}
}
} }
} }
} }
.sheet(isPresented: $showingCreateSheet) { .sheet(isPresented: $showingCreateSheet) {
CreateCodeView() CreateCodeView()
} }
.alert("清空历史记录", isPresented: $showingClearAlert) { .sheet(isPresented: $showingClearConfirmSheet) {
Button("取消", role: .cancel) { } ClearHistoryConfirmView(
Button("清空", role: .destructive) { isPresented: $showingClearConfirmSheet,
clearHistory() onConfirm: clearHistory
} )
} message: {
Text("确定要清空所有历史记录吗?此操作不可撤销。")
} }
.alert("删除确认", isPresented: $showingDeleteAlert) { .alert("删除确认", isPresented: $showingDeleteAlert) {
Button("取消", role: .cancel) { } Button("取消", role: .cancel) { }
@ -205,6 +241,47 @@ struct HistoryView: View {
showingDeleteAlert = true showingDeleteAlert = true
} }
// MARK: -
private func enterBatchDeleteMode() {
isBatchDeleteMode = true
//
selectedItemsForDelete = Set(filteredItems.compactMap { $0.id })
}
private func exitBatchDeleteMode() {
isBatchDeleteMode = false
selectedItemsForDelete.removeAll()
}
private func deleteSelectedItems() {
//
let itemsToDelete = allHistoryItems.filter { item in
guard let id = item.id else { return false }
return selectedItemsForDelete.contains(id)
}
//
for item in itemsToDelete {
coreDataManager.deleteHistoryItem(item)
}
//
allHistoryItems.removeAll { item in
guard let id = item.id else { return false }
return selectedItemsForDelete.contains(id)
}
// 退
selectedItemsForDelete.removeAll()
isBatchDeleteMode = false
//
DispatchQueue.main.async {
allHistoryItems = coreDataManager.fetchHistoryItems()
refreshTrigger.toggle()
}
}
// MARK: - // MARK: -
private var searchBar: some View { private var searchBar: some View {
HStack { HStack {
@ -265,6 +342,17 @@ struct HistoryView: View {
}, },
onDelete: { onDelete: {
showDeleteConfirmation(for: item) showDeleteConfirmation(for: item)
},
isBatchDeleteMode: isBatchDeleteMode,
isSelected: selectedItemsForDelete.contains(item.id ?? UUID()),
onToggleSelection: {
if let id = item.id {
if selectedItemsForDelete.contains(id) {
selectedItemsForDelete.remove(id)
} else {
selectedItemsForDelete.insert(id)
}
}
} }
) )
} }
@ -372,9 +460,22 @@ struct HistoryItemRow: View {
let item: HistoryItem let item: HistoryItem
let onToggleFavorite: () -> Void let onToggleFavorite: () -> Void
let onDelete: () -> Void let onDelete: () -> Void
let isBatchDeleteMode: Bool
let isSelected: Bool
let onToggleSelection: () -> Void
var body: some View { var body: some View {
HStack(spacing: 12) { HStack(spacing: 12) {
//
if isBatchDeleteMode {
Button(action: onToggleSelection) {
Image(systemName: isSelected ? "checkmark.square.fill" : "square")
.font(.system(size: 20))
.foregroundColor(isSelected ? .blue : .gray)
}
.buttonStyle(PlainButtonStyle())
}
// //
VStack { VStack {
if let dataTypeString = item.dataType, if let dataTypeString = item.dataType,
@ -495,4 +596,76 @@ struct HistoryItemRow: View {
formatter.timeStyle = .short formatter.timeStyle = .short
return formatter.string(from: date) return formatter.string(from: date)
} }
} }
// MARK: -
struct ClearHistoryConfirmView: View {
@Binding var isPresented: Bool
let onConfirm: () -> Void
var body: some View {
NavigationView {
VStack(spacing: 20) {
//
Image(systemName: "exclamationmark.triangle.fill")
.font(.system(size: 50))
.foregroundColor(.red)
//
Text("清空历史记录")
.font(.title2)
.fontWeight(.bold)
//
Text("此操作将删除所有历史记录,且不可撤销")
.font(.body)
.foregroundColor(.secondary)
.multilineTextAlignment(.center)
Spacer()
//
VStack(spacing: 12) {
//
Button(action: {
onConfirm()
isPresented = false
}) {
HStack {
Image(systemName: "trash.fill")
Text("确认删除")
}
.frame(maxWidth: .infinity)
.padding()
.background(Color.red)
.foregroundColor(.white)
.cornerRadius(10)
}
//
Button(action: {
isPresented = false
}) {
Text("取消")
.frame(maxWidth: .infinity)
.padding()
.background(Color(.systemGray5))
.foregroundColor(.primary)
.cornerRadius(10)
}
}
}
.padding(20)
.navigationTitle("确认删除")
.navigationBarTitleDisplayMode(.inline)
.navigationBarBackButtonHidden(true)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button("关闭") {
isPresented = false
}
}
}
}
}
}
Loading…
Cancel
Save