import SwiftUI
import CoreData
struct BarcodeDetailView : View {
let historyItem : HistoryItem
@ EnvironmentObject var coreDataManager : CoreDataManager
@ State private var barcodeImage : UIImage ?
@ State private var showingShareSheet = false
@ State private var showingAlert = false
@ State private var alertMessage = " "
var body : some View {
ScrollView {
VStack ( spacing : 20 ) {
// 条 形 码 图 片
barcodeImageView
// 条 形 码 类 型 信 息
barcodeTypeSection
// 条 形 码 内 容 信 息
barcodeContentSection
// 原 始 内 容
originalContentSection
// 操 作 按 钮
actionButtonsSection
}
. padding ( )
}
. navigationTitle ( NSLocalizedString ( " barcode_detail " , comment : " Barcode detail " ) )
. navigationBarTitleDisplayMode ( . inline )
. toolbar {
ToolbarItem ( placement : . navigationBarTrailing ) {
Button ( action : {
showingShareSheet = true
} ) {
Image ( systemName : " square.and.arrow.up " )
}
. disabled ( barcodeImage = = nil )
}
}
. onAppear {
generateBarcodeImage ( )
}
. sheet ( isPresented : $ showingShareSheet ) {
if let barcodeImage = barcodeImage {
ShareSheet ( activityItems : [ barcodeImage ] )
} else {
ShareSheet ( activityItems : [ historyItem . content ? ? " " ] )
}
}
. alert ( NSLocalizedString ( " tip " , comment : " Tip " ) , isPresented : $ showingAlert ) {
Button ( NSLocalizedString ( " confirm " , comment : " Confirm " ) ) { }
} message : {
Text ( alertMessage )
}
}
// MARK: - 条 形 码 图 片 视 图
private var barcodeImageView : some View {
VStack ( spacing : 16 ) {
if let barcodeImage = barcodeImage {
Image ( uiImage : barcodeImage )
. resizable ( )
. aspectRatio ( contentMode : . fit )
. frame ( height : 120 )
. cornerRadius ( 12 )
. shadow ( radius : 8 )
} else {
RoundedRectangle ( cornerRadius : 12 )
. fill ( Color . gray . opacity ( 0.3 ) )
. frame ( height : 120 )
. overlay (
ProgressView ( )
. scaleEffect ( 1.5 )
)
}
Text ( NSLocalizedString ( " scan_this_barcode " , comment : " Scan this barcode " ) )
. font ( . caption )
. foregroundColor ( . secondary )
}
}
// MARK: - 条 形 码 类 型 信 息
private var barcodeTypeSection : some View {
VStack ( alignment : . leading , spacing : 12 ) {
HStack {
Image ( systemName : " barcode " )
. font ( . title2 )
. foregroundColor ( . green )
Text ( NSLocalizedString ( " barcode_type " , comment : " Barcode type " ) )
. font ( . headline )
Spacer ( )
}
if let barcodeTypeString = historyItem . barcodeType {
HStack {
Image ( systemName : getBarcodeIcon ( for : barcodeTypeString ) )
. font ( . title3 )
. foregroundColor ( . green )
Text ( barcodeTypeString )
. font ( . title3 )
. fontWeight ( . medium )
Spacer ( )
}
. padding ( )
. background ( Color . green . opacity ( 0.1 ) )
. cornerRadius ( 8 )
}
}
. padding ( )
. background ( Color ( . systemBackground ) )
. cornerRadius ( 12 )
. shadow ( radius : 2 )
}
// MARK: - 条 形 码 内 容 信 息
private var barcodeContentSection : some View {
VStack ( alignment : . leading , spacing : 12 ) {
HStack {
Image ( systemName : " info.circle " )
. font ( . title2 )
. foregroundColor ( . blue )
Text ( NSLocalizedString ( " barcode_content " , comment : " Barcode content " ) )
. font ( . headline )
Spacer ( )
}
if let content = historyItem . content {
VStack ( alignment : . leading , spacing : 8 ) {
HStack {
Image ( systemName : " number " )
. font ( . title3 )
. foregroundColor ( . blue )
Text ( String ( format : NSLocalizedString ( " content_length " , comment : " Content length " ) , content . count ) )
. font ( . title3 )
. fontWeight ( . medium )
Spacer ( )
}
Text ( NSLocalizedString ( " data_content " , comment : " Data content " ) )
. font ( . subheadline )
. foregroundColor ( . secondary )
. padding ( . top , 4 )
}
. padding ( )
. background ( Color . blue . opacity ( 0.1 ) )
. cornerRadius ( 8 )
}
}
. padding ( )
. background ( Color ( . systemBackground ) )
. cornerRadius ( 12 )
. shadow ( radius : 2 )
}
// MARK: - 原 始 内 容
private var originalContentSection : some View {
VStack ( alignment : . leading , spacing : 12 ) {
HStack {
Image ( systemName : " doc.text " )
. font ( . title2 )
. foregroundColor ( . purple )
Text ( NSLocalizedString ( " original_content " , comment : " Original content " ) )
. font ( . headline )
Spacer ( )
}
if let content = historyItem . content {
ScrollView {
Text ( content )
. font ( . system ( . body , design : . monospaced ) )
. foregroundColor ( . secondary )
. multilineTextAlignment ( . leading )
. padding ( )
. frame ( maxWidth : . infinity , alignment : . leading )
}
. frame ( maxHeight : 200 )
. background ( Color . purple . opacity ( 0.1 ) )
. cornerRadius ( 8 )
}
}
. padding ( )
. background ( Color ( . systemBackground ) )
. cornerRadius ( 12 )
. shadow ( radius : 2 )
}
// MARK: - 操 作 按 钮
private var actionButtonsSection : some View {
VStack ( spacing : 12 ) {
// 收 藏 按 钮
Button ( action : toggleFavorite ) {
HStack {
Image ( systemName : historyItem . isFavorite ? " heart.fill " : " heart " )
. foregroundColor ( historyItem . isFavorite ? . red : . gray )
Text ( historyItem . isFavorite ? NSLocalizedString ( " unfavorite " , comment : " Unfavorite " ) : NSLocalizedString ( " favorite " , comment : " Favorite " ) )
. fontWeight ( . medium )
}
. frame ( maxWidth : . infinity )
. padding ( )
. background ( historyItem . isFavorite ? Color . red . opacity ( 0.1 ) : Color . gray . opacity ( 0.1 ) )
. foregroundColor ( historyItem . isFavorite ? . red : . gray )
. cornerRadius ( 10 )
}
// 复 制 内 容 按 钮
Button ( action : copyContent ) {
HStack {
Image ( systemName : " doc.on.doc " )
. foregroundColor ( . blue )
Text ( NSLocalizedString ( " copy_content " , comment : " Copy content " ) )
. fontWeight ( . medium )
}
. frame ( maxWidth : . infinity )
. padding ( )
. background ( Color . blue . opacity ( 0.1 ) )
. foregroundColor ( . blue )
. cornerRadius ( 10 )
}
// 分 享 条 形 码 图 片 按 钮
if barcodeImage != nil {
Button ( action : {
showingShareSheet = true
} ) {
HStack {
Image ( systemName : " photo " )
. foregroundColor ( . green )
Text ( NSLocalizedString ( " share_barcode_image " , comment : " Share barcode image " ) )
. fontWeight ( . medium )
}
. frame ( maxWidth : . infinity )
. padding ( )
. background ( Color . green . opacity ( 0.1 ) )
. foregroundColor ( . green )
. cornerRadius ( 10 )
}
}
}
. padding ( )
. background ( Color ( . systemBackground ) )
. cornerRadius ( 12 )
. shadow ( radius : 2 )
}
// MARK: - 生 成 条 形 码 图 片
private func generateBarcodeImage ( ) {
guard let content = historyItem . content else { return }
// 使 用 条 形 码 生 成 器
let barcodeType = historyItem . barcodeType ? ? " "
let size = CGSize ( width : 300 , height : 120 )
if let image = BarcodeGenerator . shared . generateBarcode ( from : content , type : barcodeType , size : size ) {
self . barcodeImage = image
}
}
// MARK: - 获 取 条 形 码 图 标
private func getBarcodeIcon ( for type : String ) -> String {
return BarcodeGenerator . shared . getBarcodeIcon ( for : type )
}
// MARK: - 切 换 收 藏 状 态
private func toggleFavorite ( ) {
historyItem . isFavorite . toggle ( )
coreDataManager . save ( )
let message = historyItem . isFavorite ? NSLocalizedString ( " added_to_favorites " , comment : " Added to favorites " ) : NSLocalizedString ( " removed_from_favorites " , comment : " Removed from favorites " )
alertMessage = message
showingAlert = true
}
// MARK: - 复 制 内 容
private func copyContent ( ) {
if let content = historyItem . content {
UIPasteboard . general . string = content
alertMessage = NSLocalizedString ( " content_copied_to_clipboard " , comment : " Content copied to clipboard " )
showingAlert = true
}
}
}
// MARK: - 分 享 表 单
struct BarcodeShareSheet : UIViewControllerRepresentable {
let activityItems : [ Any ]
func makeUIViewController ( context : Context ) -> UIActivityViewController {
let controller = UIActivityViewController ( activityItems : activityItems , applicationActivities : nil )
return controller
}
func updateUIViewController ( _ uiViewController : UIActivityViewController , context : Context ) { }
}
# Preview ( " EAN-13 " ) {
let ctx = PreviewData . context
let item = PreviewData . ean13Sample ( in : ctx )
return NavigationView { BarcodeDetailView ( historyItem : item ) }
}
# Preview ( " Code 128 " ) {
let ctx = PreviewData . context
let item = PreviewData . code128Sample ( in : ctx )
return NavigationView { BarcodeDetailView ( historyItem : item ) }
}
// MARK: - P r e v i e w D a t a
private enum PreviewData {
static let context : NSManagedObjectContext = {
let container = NSPersistentContainer ( name : " MyQrCode " )
let description = NSPersistentStoreDescription ( )
description . type = NSInMemoryStoreType
container . persistentStoreDescriptions = [ description ]
container . loadPersistentStores { _ , _ in }
return container . viewContext
} ( )
private static func makeBaseItem ( in context : NSManagedObjectContext , content : String , barcodeType : BarcodeType , favorite : Bool = false ) -> HistoryItem {
let item = HistoryItem ( context : context )
item . id = UUID ( )
item . content = content
item . dataType = DataType . barcode . rawValue
item . dataSource = DataSource . created . rawValue
item . createdAt = Date ( )
item . isFavorite = favorite
item . barcodeType = barcodeType . rawValue
return item
}
static func ean13Sample ( in context : NSManagedObjectContext ) -> HistoryItem {
let content = " 1234567890128 "
return makeBaseItem ( in : context , content : content , barcodeType : . ean13 , favorite : true )
}
static func code128Sample ( in context : NSManagedObjectContext ) -> HistoryItem {
let content = " ABC123 "
return makeBaseItem ( in : context , content : content , barcodeType : . code128 )
}
}