diff --git a/MyQrCode.xcodeproj/xcuserdata/yc.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/MyQrCode.xcodeproj/xcuserdata/yc.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index b2ee742..5143a7d 100644 --- a/MyQrCode.xcodeproj/xcuserdata/yc.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/MyQrCode.xcodeproj/xcuserdata/yc.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -82,36 +82,6 @@ endingLineNumber = "243" landmarkName = "HistoryView" landmarkType = "14"> - - - - - - diff --git a/MyQrCode/Views/HistoryView.swift b/MyQrCode/Views/HistoryView.swift index 57a6bc6..a6292b9 100644 --- a/MyQrCode/Views/HistoryView.swift +++ b/MyQrCode/Views/HistoryView.swift @@ -6,12 +6,14 @@ struct HistoryView: View { @State private var searchText = "" @State private var selectedFilter: HistoryFilter = .all @State private var showingCreateSheet = false - @State private var showingClearAlert = false @State private var itemToDelete: HistoryItem? @State private var showingDeleteAlert = false + @State private var showingClearConfirmSheet = false @State private var allHistoryItems: [HistoryItem] = [] @State private var isLoading = false @State private var refreshTrigger = false + @State private var isBatchDeleteMode = false + @State private var selectedItemsForDelete: Set = [] enum HistoryFilter: String, CaseIterable { case all = "all" @@ -107,34 +109,68 @@ struct HistoryView: View { .navigationTitle("历史记录") .navigationBarTitleDisplayMode(.large) .toolbar { - ToolbarItem(placement: .navigationBarLeading) { - Button(action: { - showingClearAlert = true - }) { - Image(systemName: "trash") - .foregroundColor(.red) - } - .disabled(coreDataManager.fetchHistoryItems().isEmpty) - } - ToolbarItem(placement: .navigationBarTrailing) { - Button(action: { - showingCreateSheet = true - }) { - Image(systemName: "plus") + HStack(spacing: 16) { + if isBatchDeleteMode { + // 批量删除模式下的按钮 + 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) { CreateCodeView() } - .alert("清空历史记录", isPresented: $showingClearAlert) { - Button("取消", role: .cancel) { } - Button("清空", role: .destructive) { - clearHistory() - } - } message: { - Text("确定要清空所有历史记录吗?此操作不可撤销。") + .sheet(isPresented: $showingClearConfirmSheet) { + ClearHistoryConfirmView( + isPresented: $showingClearConfirmSheet, + onConfirm: clearHistory + ) } .alert("删除确认", isPresented: $showingDeleteAlert) { Button("取消", role: .cancel) { } @@ -205,6 +241,47 @@ struct HistoryView: View { 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: - 搜索栏 private var searchBar: some View { HStack { @@ -265,6 +342,17 @@ struct HistoryView: View { }, onDelete: { 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 onToggleFavorite: () -> Void let onDelete: () -> Void + let isBatchDeleteMode: Bool + let isSelected: Bool + let onToggleSelection: () -> Void var body: some View { 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 { if let dataTypeString = item.dataType, @@ -495,4 +596,76 @@ struct HistoryItemRow: View { formatter.timeStyle = .short return formatter.string(from: date) } -} \ No newline at end of file +} + +// 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 + } + } + } + } + } +} \ No newline at end of file