import SwiftUI import Foundation // MARK: - 通用工具函数 // MARK: - 字符串扩展 extension String { /// 检查字符串是否为有效的邮箱地址 var isValidEmail: Bool { let emailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}" let emailPredicate = NSPredicate(format: "SELF MATCHES %@", emailRegex) return emailPredicate.evaluate(with: self) } /// 检查字符串是否为有效的电话号码 var isValidPhone: Bool { let phoneRegex = "^[+]?[0-9\\s\\-\\(\\)]{7,}$" let phonePredicate = NSPredicate(format: "SELF MATCHES %@", phoneRegex) return phonePredicate.evaluate(with: self) } /// 检查字符串是否为有效的URL var isValidURL: Bool { guard let url = URL(string: self) else { return false } return UIApplication.shared.canOpenURL(url) } /// 移除字符串两端的空白字符 var trimmed: String { self.trimmingCharacters(in: .whitespacesAndNewlines) } /// 检查字符串是否为空或只包含空白字符 var isEmptyOrWhitespace: Bool { self.trimmed.isEmpty } /// 获取字符串的字符数(不包括空白字符) var characterCount: Int { self.trimmed.count } /// 截取字符串到指定长度 func truncated(to length: Int, suffix: String = "...") -> String { if self.count <= length { return self } let index = self.index(self.startIndex, offsetBy: length - suffix.count) return String(self[.. String { if self.hasPrefix("http://") || self.hasPrefix("https://") { return self } return "https://" + self } } // MARK: - 日期扩展 extension Date { /// 格式化日期为字符串 func formattedString(style: DateFormatter.Style = .medium) -> String { let formatter = DateFormatter() formatter.dateStyle = style formatter.locale = Locale(identifier: "zh_CN") return formatter.string(from: self) } /// 格式化日期为时间字符串 func formattedTimeString() -> String { let formatter = DateFormatter() formatter.timeStyle = .short formatter.locale = Locale(identifier: "zh_CN") return formatter.string(from: self) } /// 格式化日期为完整字符串 func formattedFullString() -> String { let formatter = DateFormatter() formatter.dateStyle = .medium formatter.timeStyle = .short formatter.locale = Locale(identifier: "zh_CN") return formatter.string(from: self) } /// 检查日期是否为今天 var isToday: Bool { Calendar.current.isDateInToday(self) } /// 检查日期是否为昨天 var isYesterday: Bool { Calendar.current.isDateInYesterday(self) } /// 获取相对时间描述 var relativeTimeDescription: String { let now = Date() let components = Calendar.current.dateComponents([.minute, .hour, .day], from: self, to: now) if let day = components.day, day > 0 { if day == 1 { return NSLocalizedString("yesterday", comment: "Yesterday") } else if day < 7 { return String(format: NSLocalizedString("days_ago", comment: "Days ago"), day) } else { return self.formattedString(style: .short) } } else if let hour = components.hour, hour > 0 { return String(format: NSLocalizedString("hours_ago", comment: "Hours ago"), hour) } else if let minute = components.minute, minute > 0 { return String(format: NSLocalizedString("minutes_ago", comment: "Minutes ago"), minute) } else { return NSLocalizedString("just_now", comment: "Just now") } } } // MARK: - 颜色扩展 extension Color { /// 创建随机颜色 static func random() -> Color { Color( red: Double.random(in: 0...1), green: Double.random(in: 0...1), blue: Double.random(in: 0...1) ) } /// 创建系统颜色 static let systemBackground = Color(.systemBackground) static let systemGroupedBackground = Color(.systemGroupedBackground) /// 创建语义颜色 static let label = Color(.label) static let secondaryLabel = Color(.secondaryLabel) static let tertiaryLabel = Color(.tertiaryLabel) static let quaternaryLabel = Color(.quaternaryLabel) /// 创建系统颜色 static let systemBlue = Color(.systemBlue) static let systemGreen = Color(.systemGreen) static let systemIndigo = Color(.systemIndigo) static let systemOrange = Color(.systemOrange) static let systemPink = Color(.systemPink) static let systemPurple = Color(.systemPurple) static let systemRed = Color(.systemRed) static let systemTeal = Color(.systemTeal) static let systemYellow = Color(.systemYellow) /// 创建系统灰色 static let systemGray = Color(.systemGray) static let systemGray2 = Color(.systemGray2) static let systemGray3 = Color(.systemGray3) static let systemGray4 = Color(.systemGray4) static let systemGray5 = Color(.systemGray5) static let systemGray6 = Color(.systemGray6) } // MARK: - 视图扩展 extension View { /// 添加圆角 func roundedCorners(_ radius: CGFloat, corners: UIRectCorner = .allCorners) -> some View { clipShape(RoundedCorner(radius: radius, corners: corners)) } /// 添加自定义阴影 func customShadow( color: Color = .black.opacity(0.1), radius: CGFloat = 8, x: CGFloat = 0, y: CGFloat = 4 ) -> some View { self.shadow(color: color, radius: radius, x: x, y: y) } /// 添加边框 func customBorder( _ color: Color, width: CGFloat = 1, cornerRadius: CGFloat = 0 ) -> some View { self.overlay( RoundedRectangle(cornerRadius: cornerRadius) .stroke(color, lineWidth: width) ) } /// 添加自定义背景色 func customBackground(_ color: Color, cornerRadius: CGFloat = 0) -> some View { self.background( RoundedRectangle(cornerRadius: cornerRadius) .fill(color) ) } /// 隐藏键盘 func hideKeyboard() { UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) } } // MARK: - 自定义圆角形状 struct RoundedCorner: Shape { var radius: CGFloat = .infinity var corners: UIRectCorner = .allCorners func path(in rect: CGRect) -> Path { let path = UIBezierPath( roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius) ) return Path(path.cgPath) } } // MARK: - 通用验证函数 struct ValidationHelper { /// 验证邮箱地址 static func isValidEmail(_ email: String) -> Bool { email.isValidEmail } /// 验证电话号码 static func isValidPhone(_ phone: String) -> Bool { phone.isValidPhone } /// 验证URL static func isValidURL(_ url: String) -> Bool { url.isValidURL } /// 验证必填字段 static func isRequiredFieldValid(_ field: String) -> Bool { !field.isEmptyOrWhitespace } /// 验证字符长度 static func isLengthValid(_ text: String, min: Int, max: Int) -> Bool { let count = text.characterCount return count >= min && count <= max } /// 验证密码强度 static func getPasswordStrength(_ password: String) -> PasswordStrength { var score = 0 if password.count >= 8 { score += 1 } if password.range(of: "[a-z]", options: .regularExpression) != nil { score += 1 } if password.range(of: "[A-Z]", options: .regularExpression) != nil { score += 1 } if password.range(of: "[0-9]", options: .regularExpression) != nil { score += 1 } if password.range(of: "[^a-zA-Z0-9]", options: .regularExpression) != nil { score += 1 } switch score { case 0...1: return .weak case 2...3: return .medium case 4...5: return .strong default: return .weak } } } // MARK: - 密码强度枚举 enum PasswordStrength { case weak case medium case strong var description: String { switch self { case .weak: return NSLocalizedString("weak", comment: "Weak") case .medium: return NSLocalizedString("medium", comment: "Medium") case .strong: return NSLocalizedString("strong", comment: "Strong") } } var color: Color { switch self { case .weak: return .red case .medium: return .orange case .strong: return .green } } } // MARK: - 通用格式化函数 struct FormatHelper { /// 格式化文件大小 static func formatFileSize(_ bytes: Int64) -> String { let formatter = ByteCountFormatter() formatter.allowedUnits = [.useKB, .useMB, .useGB] formatter.countStyle = .file return formatter.string(fromByteCount: bytes) } /// 格式化数字 static func formatNumber(_ number: Int) -> String { let formatter = NumberFormatter() formatter.numberStyle = .decimal return formatter.string(from: NSNumber(value: number)) ?? "\(number)" } /// 格式化百分比 static func formatPercentage(_ value: Double) -> String { let formatter = NumberFormatter() formatter.numberStyle = .percent formatter.minimumFractionDigits = 1 formatter.maximumFractionDigits = 1 return formatter.string(from: NSNumber(value: value)) ?? "\(value * 100)%" } /// 格式化货币 static func formatCurrency(_ amount: Double, locale: Locale = .current) -> String { let formatter = NumberFormatter() formatter.numberStyle = .currency formatter.locale = locale return formatter.string(from: NSNumber(value: amount)) ?? "\(amount)" } } // MARK: - 通用动画函数 struct AnimationHelper { /// 弹性动画 static let spring = Animation.spring(response: 0.5, dampingFraction: 0.8, blendDuration: 0) /// 缓入动画 static let easeIn = Animation.easeIn(duration: 0.3) /// 缓出动画 static let easeOut = Animation.easeOut(duration: 0.3) /// 缓入缓出动画 static let easeInOut = Animation.easeInOut(duration: 0.3) /// 线性动画 static let linear = Animation.linear(duration: 0.3) } // MARK: - 通用反馈函数 struct FeedbackHelper { /// 轻触反馈 static func lightImpact() { let impactFeedback = UIImpactFeedbackGenerator(style: .light) impactFeedback.impactOccurred() } /// 中等触反馈 static func mediumImpact() { let impactFeedback = UIImpactFeedbackGenerator(style: .medium) impactFeedback.impactOccurred() } /// 重触反馈 static func heavyImpact() { let impactFeedback = UIImpactFeedbackGenerator(style: .heavy) impactFeedback.impactOccurred() } /// 成功反馈 static func success() { let notificationFeedback = UINotificationFeedbackGenerator() notificationFeedback.notificationOccurred(.success) } /// 警告反馈 static func warning() { let notificationFeedback = UINotificationFeedbackGenerator() notificationFeedback.notificationOccurred(.warning) } /// 错误反馈 static func error() { let notificationFeedback = UINotificationFeedbackGenerator() notificationFeedback.notificationOccurred(.error) } }