You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

390 lines
12 KiB

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[..<index]) + suffix
}
/// URL
func withURLProtocol() -> 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 "昨天"
} else if day < 7 {
return "\(day)天前"
} else {
return self.formattedString(style: .short)
}
} else if let hour = components.hour, hour > 0 {
return "\(hour)小时前"
} else if let minute = components.minute, minute > 0 {
return "\(minute)分钟前"
} else {
return "刚刚"
}
}
}
// 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 ""
case .medium:
return ""
case .strong:
return ""
}
}
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)
}
}