@ -7,6 +7,11 @@ struct HistoryView: View {
@ 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 allHistoryItems : [ HistoryItem ] = [ ]
@ State private var isLoading = false
@ State private var refreshTrigger = false
enum HistoryFilter : String , CaseIterable {
case all = " all "
@ -52,9 +57,10 @@ struct HistoryView: View {
}
var filteredItems : [ HistoryItem ] {
let allItems = coreDataManager . fetchHistoryItems ( )
// 使 用 r e f r e s h T r i g g e r 强 制 触 发 计 算 属 性 更 新
let _ = refreshTrigger
let searchResults = all Items. filter { item in
let searchResults = all History Items. filter { item in
if ! searchText . isEmpty {
let content = item . content ? ? " "
let barcodeType = item . barcodeType ? ? " "
@ -130,22 +136,73 @@ struct HistoryView: View {
} message : {
Text ( " 确定要清空所有历史记录吗?此操作不可撤销。 " )
}
. alert ( " 删除确认 " , isPresented : $ showingDeleteAlert ) {
Button ( " 取消 " , role : . cancel ) { }
Button ( " 删除 " , role : . destructive ) {
if let item = itemToDelete {
deleteHistoryItem ( item )
itemToDelete = nil
}
}
} message : {
if let item = itemToDelete {
Text ( " 确定要删除这条记录吗? \n 内容: \( item . content ? ? " " ) " )
}
}
. onAppear {
loadHistoryItems ( )
}
}
// MARK: - 加 载 历 史 记 录
private func loadHistoryItems ( ) {
isLoading = true
DispatchQueue . main . asyncAfter ( deadline : . now ( ) + 0.1 ) {
allHistoryItems = coreDataManager . fetchHistoryItems ( )
isLoading = false
}
}
// MARK: - 过 滤 器 操 作
private func filterAction ( for filter : HistoryFilter ) {
// 直 接 切 换 过 滤 器 , 无 任 何 延 迟
selectedFilter = filter
}
// MARK: - 清 空 历 史 记 录
private func clearHistory ( ) {
coreDataManager . clearAllHistory ( )
allHistoryItems . removeAll ( )
refreshTrigger . toggle ( )
}
// MARK: - 切 换 收 藏 状 态
private func toggleFavorite ( _ item : HistoryItem ) {
// 先 保 存 到 C o r e D a t a
item . isFavorite . toggle ( )
coreDataManager . save ( )
// 更 新 本 地 缓 存 , 避 免 重 新 加 载 数 据
if let index = allHistoryItems . firstIndex ( where : { $0 . id = = item . id } ) {
allHistoryItems [ index ] . isFavorite = item . isFavorite
}
// 强 制 触 发 视 图 刷 新
refreshTrigger . toggle ( )
}
// MARK: - 删 除 历 史 记 录
private func deleteHistoryItem ( _ item : HistoryItem ) {
coreDataManager . deleteHistoryItem ( item )
// 从 本 地 缓 存 中 移 除
allHistoryItems . removeAll { $0 . id = = item . id }
refreshTrigger . toggle ( )
}
// MARK: - 显 示 删 除 确 认
private func showDeleteConfirmation ( for item : HistoryItem ) {
itemToDelete = item
showingDeleteAlert = true
}
// MARK: - 搜 索 栏
@ -170,8 +227,9 @@ struct HistoryView: View {
FilterChip (
filter : filter ,
isSelected : selectedFilter = = filter ,
isLoading : false ,
action : {
selectedFilter = filter
filterAction( for : filter )
}
)
}
@ -185,6 +243,20 @@ struct HistoryView: View {
// MARK: - 历 史 记 录 列 表
private var historyList : some View {
List {
if isLoading {
HStack {
Spacer ( )
VStack ( spacing : 16 ) {
ProgressView ( )
. scaleEffect ( 1.2 )
Text ( " 加载中... " )
. font ( . caption )
. foregroundColor ( . secondary )
}
. padding ( . vertical , 40 )
Spacer ( )
}
} else {
ForEach ( filteredItems ) { item in
HistoryItemRow (
item : item ,
@ -192,11 +264,12 @@ struct HistoryView: View {
toggleFavorite ( item )
} ,
onDelete : {
deleteHistoryItem ( item )
showDeleteConfirmation ( for : item )
}
)
}
}
}
. listStyle ( PlainListStyle ( ) )
}
@ -246,6 +319,7 @@ struct HistoryView: View {
struct FilterChip : View {
let filter : HistoryView . HistoryFilter
let isSelected : Bool
let isLoading : Bool
let action : ( ) -> Void
var body : some View {
@ -259,11 +333,37 @@ struct FilterChip: View {
}
. padding ( . horizontal , 12 )
. padding ( . vertical , 8 )
. background ( isSelected ? Color . blue : Color ( . systemGray5 ) )
. background (
RoundedRectangle ( cornerRadius : 20 )
. fill ( isSelected ? Color . blue : Color ( . systemGray5 ) )
)
. foregroundColor ( isSelected ? . white : . primary )
. cornerRadius ( 20 )
. scaleEffect( isSelected ? 1.05 : 1. 0)
}
. buttonStyle ( PlainButtonStyle ( ) )
. buttonStyle ( OptimizedFilterChipButtonStyle ( isSelected : isSelected ) )
. animation ( . easeInOut ( duration : 0.2 ) , value : isSelected )
}
}
// MARK: - 优 化 的 过 滤 器 芯 片 按 钮 样 式
struct OptimizedFilterChipButtonStyle : ButtonStyle {
let isSelected : Bool
func makeBody ( configuration : Configuration ) -> some View {
configuration . label
. scaleEffect ( configuration . isPressed ? 0.95 : 1.0 )
. opacity ( configuration . isPressed ? 0.9 : 1.0 )
. animation ( . easeInOut ( duration : 0.1 ) , value : configuration . isPressed )
}
}
// MARK: - 过 滤 器 芯 片 按 钮 样 式 ( 保 留 以 防 向 后 兼 容 )
struct FilterChipButtonStyle : ButtonStyle {
func makeBody ( configuration : Configuration ) -> some View {
configuration . label
. scaleEffect ( configuration . isPressed ? 0.95 : 1.0 )
. opacity ( configuration . isPressed ? 0.8 : 1.0 )
. animation ( . easeInOut ( duration : 0.1 ) , value : configuration . isPressed )
}
}