// // SwiftUI_Prefix.swift // PersonalHealthDiary // // Created by Sean Kim on 2/20/24. // import SwiftUI // MARK: - ACAMATE // APPSTORE_URL : https://apps.apple.com/us/app/%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%A9%94%EC%9D%B4%ED%8A%B8/id6739448113 /// 주의사항 /// plist 에서 http 설정 걸려있는거 지워야 함 #if LOCAL public let API_URL: String = "http://10.149.217.64:5144" //public let API_URL: String = "http://localhost:5144" //public let API_URL: String = "https://localhost:7086" public let WS_URL: String = "ws://localhost:5144" /// 회사 맥에서 사용할 경우의 URL //public let WS_URL: String = "ws://10.149.217.64:5144" /// 집 맥에서 사용할 경우의 URL //public let WS_URL: String = "ws://192.168.0.71:5144" //ipconfig getifaddr en0 이거는 와이파이 주소 알아내는거임 #elseif DEV public let API_URL: String = "https://devacamate.ipstein.myds.me" /// 서버용 웹소켓 //public let WS_URL: String = "ws://ipstein.myds.me:7004" /// 회사 맥에서 사용할 경우의 URL public let WS_URL: String = "ws://10.149.217.64:5144" /// 집 맥에서 사용할 경우의 URL //public let WS_URL: String = "ws://192.168.0.71:5144" //ipconfig getifaddr en0 이거는 와이파이 주소 알아내는거임 #else public let API_URL: String = "https://acamate.ipstein.myds.me" public let WS_URL: String = "wss://acamate.ipstein.myds.me" #endif public let API_HEADER = "iOS_AM_Connect_Key" // MARK: - TYPEALIAS typealias VOID_TO_VOID = () -> () // MARK: - VARIABLE public var APPSTORE_URL = "https://itunes.apple.com/app/" public var KEYBOARD_UP_HEIGHT: CGFloat = 46.0 enum Compare: Int{ case bigger = 0 case smaller case equal case error } // MARK: - FUNCTION /// print 를 조금 더 자세하게 표기해주는 함수 public func printLog(_ object: T, _ file: String = #file, _ function: String = #function, _ line: Int = #line){ #if DEBUG let dateString = Date().convertString("yyyy/MM/dd HH:mm:ss:SSS") Swift.print(""" _____ _____ _____ _____ _____ _____ _____ _____ _____ _____ |* TIME = [\(dateString)] || FILE = [\(file.lastPathComponent)] | NAME = [\(function)] || LINE = [\(line)] |>>> PRINT = \(object) """) #else #endif } public func getDeviceWidth() -> CGFloat { UIScreen.main.bounds.size.width } public func getDeviceHeight() -> CGFloat { UIScreen.main.bounds.size.height } /// 탈옥 여부 파악 함수 public func isIllegalDevice() -> Bool { func canOpen(path: String) -> Bool { let file = fopen(path, "r") guard file != nil else { return false } fclose(file) return true } guard let cydiaUrlScheme = NSURL(string: "cydia://package/com.example.package") else { return false } if UIApplication.shared.canOpenURL(cydiaUrlScheme as URL) { return true } #if arch(i386) || arch(x86_64) return false #endif let fileManager = FileManager.default if fileManager.fileExists(atPath: "/Applications/Cydia.app") || fileManager.fileExists(atPath: "/Library/MobileSubstrate/MobileSubstrate.dylib") || fileManager.fileExists(atPath: "/bin/bash") || fileManager.fileExists(atPath: "/usr/sbin/sshd") || fileManager.fileExists(atPath: "/etc/apt") || fileManager.fileExists(atPath: "/usr/bin/ssh") || fileManager.fileExists(atPath: "/private/var/lib/apt") { return true } if canOpen(path: "/Applications/Cydia.app") || canOpen(path: "/Library/MobileSubstrate/MobileSubstrate.dylib") || canOpen(path: "/bin/bash") || canOpen(path: "/usr/sbin/sshd") || canOpen(path: "/etc/apt") || canOpen(path: "/usr/bin/ssh") { return true } let path = "/private/" + NSUUID().uuidString do { try "anyString".write(toFile: path, atomically: true, encoding: String.Encoding.utf8) try fileManager.removeItem(atPath: path) return true } catch let error { // 이 부분 printLog("Jail ERROR: \(error))") return false } } public func fontNameCheck() { for family: String in UIFont.familyNames { print(family) for names : String in UIFont.fontNames(forFamilyName: family){ printLog("\(names)") } } } /// a 가 b 보다 클 경우 true 반환 ( 그외 전부 false) public func isBigger (_ a: Int, _ b: Int) -> Bool { if a > b { return true } else { return false } } /// JSON 형태의 String 을 받아서 Dictionary 의 형태로 내보냄 public func jsonToDict(_ input: String) -> [String: Any] { if let jsonData = input.data(using: .utf8){ do { if let jsonObject = try JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] { return jsonObject } } catch let error { // 이 부분 printLog("JSON ERROR: \(error))") } } return [:] } /// JSON 배열의 형태를 Swift의 배열 형태로 변환한다. public func jsonToSwift(_ input: String) -> T? { if let data = input.data(using: .utf8) { do { let jsonObject = try JSONDecoder().decode(T.self, from: data) return jsonObject } catch let error { printLog("JSON ERROR: \(error))") } } return nil } func versionChange(ver: String) -> [Int] { return ver.components(separatedBy: ["."]).map {Int($0) ?? 0} } /// a 가 b 보다 OOO 하다. func compareVersion(_ a: String, _ b: String) -> Compare { let aList = versionChange(ver: a) let bList = versionChange(ver: b) if aList.count != bList.count { return .error } else { for i in 0 ..< aList.count { if aList[i] > bList[i] { return .bigger } else if aList[i] < bList[i] { return .smaller } } return .equal } } // MARK: - CUSTOM COMPONENTS // MARK: - EXTENSION extension String { /// 마지막 경로 구성 요소 var lastPathComponent: String { get { return (self as NSString).lastPathComponent } } /// 원하는 길이 만큼 절단 func cut(start: Int, end: Int) -> String { let startIndex = self.index(self.startIndex,offsetBy: start >= 0 ? start : 0) let endIndex = self.index(self.startIndex,offsetBy: end >= 0 ? end : 0) let result: String = "\(self[startIndex ..< endIndex])" return result } /// 글자 하나 단위로 구분 func letter() -> [String] { return self.map { String($0) } } /// 단어 하나 단위로 구문 (띄어쓰기) func word() -> [String] { return self.components(separatedBy: " ") } /// Date() 로 변환 -> (Bool, Date) 출력 func convertDate(_ dateFormat: String = "yyyyMMdd") -> (Bool, Date) { let dateFormatter = Date().setDateFormatter(dateFormat) if let convert = dateFormatter.date(from: self) { return (true, convert) } else { return (false, Date()) } } /// 정규식 체크 /// /// 이메일 정규식 예시: "[A-Z0-9a-z._%+-]+@[A-Z0-9a-z._%+-]+\\.[A-Za-z]{2,64}" /// 비밀번호 정규식 에시: "[A-Z0-9a-z._%+-]{6,12}" func checkFilter(_ filter: String) -> Bool { var result = false if self == "" { return result } if (self.range(of: filter, options: .regularExpression) != nil) { result = true } else { result = false } return result } /// Bool 값에 맞게 DateFormat을 반환 static func makeDateFormat(year: Bool, month: Bool, day: Bool, dayOfWeek: Bool = false, am_pm: Bool = false, hour: Bool = false,_ fullTime: Bool = true, minute: Bool = false, second: Bool = false, mSecond: Bool = false, mSDigit: Int = 1) -> String { var dateFormat = "" if year { dateFormat = dateFormat + "yyyy" } if month { dateFormat = dateFormat + "MM" } if day { dateFormat = dateFormat + "dd" } if dayOfWeek { dateFormat = dateFormat + "EEEEEE" } if am_pm { dateFormat = dateFormat + "a" } if fullTime { // 24시간 if hour { dateFormat = dateFormat + "HH" } } else { // 12시간 if hour { dateFormat = dateFormat + "hh" } } if minute { dateFormat = dateFormat + "mm" } if second { dateFormat = dateFormat + "ss" } if mSecond { for _ in 0 ..< mSDigit { dateFormat = dateFormat + "S" } } return dateFormat } /// 날짜를 합쳐서 하나의 String으로 반환 static func combineDate(year: Int, month: Int, day: Int) -> String { return "\(year * 10000 + month * 100 + day)" } func stringToInt() -> Int { if let intValue = Int(self) { return intValue } else { return 0 } } } extension Date { /// 연도 표시 /// /// 변환에 실패시 현재 날짜의 년 표시 var year: Int { let dateFormatter = self.setDateFormatter("yyyy") if let year = Int(dateFormatter.string(from: self)){ return year } else { return Calendar.current.component(.year, from: self) } } /// 월 표시 /// /// 변환 실패시 현재 날짜의 월 표시 var month: Int { let dateFormatter = self.setDateFormatter("MM") if let month = Int(dateFormatter.string(from: self)) { return month } else { return Calendar.current.component(.month, from: self) } } /// 일 표시 /// /// 변환 실패시 현재 날짜의 월 표시 var day: Int { let dateFormatter = self.setDateFormatter("dd") if let day = Int(dateFormatter.string(from: self)) { return day } else { return Calendar.current.component(.day, from: self) } } /// 요일 표시 /// /// 일요일 부터 시작해 0~6까지 반환 /// /// -1 반환시 오류 발생 var dayOfWeek: Int { let dateFormatter = self.setDateFormatter("EEEEEE") let convert = dateFormatter.string(from: self) switch convert { case "일": return 0 case "월": return 1 case "화": return 2 case "수": return 3 case "목": return 4 case "금": return 5 case "토": return 6 default: return -1 } } func setDateFormatter(_ dateFormat: String) -> DateFormatter { let dateFormatter = DateFormatter() dateFormatter.dateFormat = dateFormat dateFormatter.timeZone = TimeZone(abbreviation: "KST") dateFormatter.locale = Locale(identifier: "ko_kr") return dateFormatter } /// String 값으로 변환 func convertString(_ dateFormat: String = "yyyyMMdd") -> String { let dateFormatter = self.setDateFormatter(dateFormat) return dateFormatter.string(from: self) } /// 해당 년도가 윤년인지 확인 /// /// 값이 정확하지 않으면 현재 날짜로 파악 func checkLeapMonth() -> Bool { if self.year % 4 == 0 { if self.year % 100 == 0 { if self.year % 400 == 0 { return true } } else { return true } } return false } /// 해당 월의 날짜 수 확인 /// /// 값이 정확하지 않으면 현재 날짜로 파악 func getLastDayOfMonth() -> Int { switch self.month { case 1,3,5,7,8,10,12 : return 31 case 2: if self.checkLeapMonth() { return 29 } else { return 28 } case 4,6,9,11: return 30 default: return -1 } } } extension Encodable { // 내부 데이터들 전체 호출 func toStringDict() -> [String:String] { let mirror = Mirror(reflecting: self) var result = [String:String]() for child in mirror.children { if let key = child.label { if let value = child.value as? CustomStringConvertible { result[key] = value.description } else { result[key] = "\(child.value)" } } } return result } } // MARK: - ANNOTATION /// 사용방법 /// @UserDefault (key: "keyName", defaultValue: "default") var 변수 /// print(변수) /// - 위에처럼 하게 되면 UserDefaults에 저장된 key 값을 갖고있는걸 보여주든가 기본 값 보여줌 /// 변수 = 변경값 /// - 위에처럼 하게되면 UserDefaults에 해당 key 값에 변경값을 저장하고 들고 있음 @propertyWrapper struct UserDefault { private let ud: UserDefaults = .standard private let key: String private var defaultValue: T var wrappedValue: T { set { ud.set(newValue, forKey: key) } get { ud.object(forKey: key) as? T ?? defaultValue } } init(key: String, defaultValue: T) { self.key = key self.defaultValue = defaultValue } ///사용법: _변수.removeData() /// - 중요사항 변수 앞에 _ 무조건 붙여야 함 func removeData() { ud.removeObject(forKey: key) } }