From: liangzhenying <867174124@qq.com> Date: Thu, 31 Jul 2025 07:30:07 +0000 (+0800) Subject: 初始化 X-Git-Url: http://git.snicker.com.cn/?a=commitdiff_plain;h=286f2724974ca56f92ceda8aa34e72099341ec01;p=mirrors%2FLingQi_iOS.git 初始化 --- diff --git a/.gitignore b/.gitignore index 330d167..79ef012 100644 --- a/.gitignore +++ b/.gitignore @@ -46,7 +46,7 @@ playground.xcworkspace # hence it is not needed unless you have added a package configuration file to your project # .swiftpm -.build/ +LingQi/build/ # CocoaPods # @@ -54,7 +54,7 @@ playground.xcworkspace # you should judge for yourself, the pros and cons are mentioned at: # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control # -# Pods/ + .LingQi/Pods/ # # Add this line if you want to avoid checking in source code from the Xcode workspace # *.xcworkspace @@ -88,3 +88,4 @@ fastlane/test_output # https://github.com/johnno1962/injectionforxcode iOSInjectionProject/ +LingQi/Pods diff --git a/LingQi/LingQi.xcodeproj/project.pbxproj b/LingQi/LingQi.xcodeproj/project.pbxproj new file mode 100644 index 0000000..bd9ef20 --- /dev/null +++ b/LingQi/LingQi.xcodeproj/project.pbxproj @@ -0,0 +1,425 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 77; + objects = { + +/* Begin PBXBuildFile section */ + 028546BADEA3BE9A60C07D60 /* Pods_LingQi.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 68EBF8E8F60D33549C862B1B /* Pods_LingQi.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 3F887B9C2E38D8DC00C98658 /* LingQi.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LingQi.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 68EBF8E8F60D33549C862B1B /* Pods_LingQi.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_LingQi.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + CB933A7969ADF81D59503790 /* Pods-LingQi.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LingQi.debug.xcconfig"; path = "Target Support Files/Pods-LingQi/Pods-LingQi.debug.xcconfig"; sourceTree = ""; }; + CE98543C79FAAB6CEF4CBFCA /* Pods-LingQi.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LingQi.release.xcconfig"; path = "Target Support Files/Pods-LingQi/Pods-LingQi.release.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ + 3F887BAE2E38D8DD00C98658 /* Exceptions for "LingQi" folder in "LingQi" target */ = { + isa = PBXFileSystemSynchronizedBuildFileExceptionSet; + membershipExceptions = ( + Info.plist, + ); + target = 3F887B9B2E38D8DC00C98658 /* LingQi */; + }; +/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ + +/* Begin PBXFileSystemSynchronizedRootGroup section */ + 3F887B9E2E38D8DC00C98658 /* LingQi */ = { + isa = PBXFileSystemSynchronizedRootGroup; + exceptions = ( + 3F887BAE2E38D8DD00C98658 /* Exceptions for "LingQi" folder in "LingQi" target */, + ); + path = LingQi; + sourceTree = ""; + }; +/* End PBXFileSystemSynchronizedRootGroup section */ + +/* Begin PBXFrameworksBuildPhase section */ + 3F887B992E38D8DC00C98658 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 028546BADEA3BE9A60C07D60 /* Pods_LingQi.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 34A14A83ECF09370871C891F /* Pods */ = { + isa = PBXGroup; + children = ( + CB933A7969ADF81D59503790 /* Pods-LingQi.debug.xcconfig */, + CE98543C79FAAB6CEF4CBFCA /* Pods-LingQi.release.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; + 3F887B932E38D8DC00C98658 = { + isa = PBXGroup; + children = ( + 3F887B9E2E38D8DC00C98658 /* LingQi */, + 3F887B9D2E38D8DC00C98658 /* Products */, + 34A14A83ECF09370871C891F /* Pods */, + 676B86A4BA2639E8694D56B4 /* Frameworks */, + ); + sourceTree = ""; + }; + 3F887B9D2E38D8DC00C98658 /* Products */ = { + isa = PBXGroup; + children = ( + 3F887B9C2E38D8DC00C98658 /* LingQi.app */, + ); + name = Products; + sourceTree = ""; + }; + 676B86A4BA2639E8694D56B4 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 68EBF8E8F60D33549C862B1B /* Pods_LingQi.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 3F887B9B2E38D8DC00C98658 /* LingQi */ = { + isa = PBXNativeTarget; + buildConfigurationList = 3F887BAF2E38D8DD00C98658 /* Build configuration list for PBXNativeTarget "LingQi" */; + buildPhases = ( + FEE3A20D8A2FA81E622C488B /* [CP] Check Pods Manifest.lock */, + 3F887B982E38D8DC00C98658 /* Sources */, + 3F887B992E38D8DC00C98658 /* Frameworks */, + 3F887B9A2E38D8DC00C98658 /* Resources */, + 5A934A35F54A5620CFD3C08A /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + fileSystemSynchronizedGroups = ( + 3F887B9E2E38D8DC00C98658 /* LingQi */, + ); + name = LingQi; + productName = LingQi; + productReference = 3F887B9C2E38D8DC00C98658 /* LingQi.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 3F887B942E38D8DC00C98658 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1640; + LastUpgradeCheck = 1640; + TargetAttributes = { + 3F887B9B2E38D8DC00C98658 = { + CreatedOnToolsVersion = 16.4; + }; + }; + }; + buildConfigurationList = 3F887B972E38D8DC00C98658 /* Build configuration list for PBXProject "LingQi" */; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 3F887B932E38D8DC00C98658; + minimizedProjectReferenceProxies = 1; + preferredProjectObjectVersion = 77; + productRefGroup = 3F887B9D2E38D8DC00C98658 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 3F887B9B2E38D8DC00C98658 /* LingQi */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 3F887B9A2E38D8DC00C98658 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 5A934A35F54A5620CFD3C08A /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-LingQi/Pods-LingQi-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + inputPaths = ( + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-LingQi/Pods-LingQi-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-LingQi/Pods-LingQi-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + FEE3A20D8A2FA81E622C488B /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-LingQi-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 3F887B982E38D8DC00C98658 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 3F887BB02E38D8DD00C98658 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = CB933A7969ADF81D59503790 /* Pods-LingQi.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = M33X987285; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = LingQi/Info.plist; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UIMainStoryboardFile = Main; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = demo.LingQi; + PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OBJC_BRIDGING_HEADER = "LingQi/LingQi-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 1; + }; + name = Debug; + }; + 3F887BB12E38D8DD00C98658 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = CE98543C79FAAB6CEF4CBFCA /* Pods-LingQi.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = M33X987285; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = LingQi/Info.plist; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UIMainStoryboardFile = Main; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = demo.LingQi; + PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OBJC_BRIDGING_HEADER = "LingQi/LingQi-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 1; + }; + name = Release; + }; + 3F887BB22E38D8DD00C98658 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = M33X987285; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.5; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 3F887BB32E38D8DD00C98658 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = M33X987285; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.5; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 3F887B972E38D8DC00C98658 /* Build configuration list for PBXProject "LingQi" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3F887BB22E38D8DD00C98658 /* Debug */, + 3F887BB32E38D8DD00C98658 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 3F887BAF2E38D8DD00C98658 /* Build configuration list for PBXNativeTarget "LingQi" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3F887BB02E38D8DD00C98658 /* Debug */, + 3F887BB12E38D8DD00C98658 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 3F887B942E38D8DC00C98658 /* Project object */; +} diff --git a/LingQi/LingQi.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/LingQi/LingQi.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/LingQi/LingQi.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/LingQi/LingQi.xcworkspace/contents.xcworkspacedata b/LingQi/LingQi.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..aca36a7 --- /dev/null +++ b/LingQi/LingQi.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/LingQi/LingQi/Api/HttpClient.swift b/LingQi/LingQi/Api/HttpClient.swift new file mode 100644 index 0000000..a42e302 --- /dev/null +++ b/LingQi/LingQi/Api/HttpClient.swift @@ -0,0 +1,115 @@ +// +// Client.swift +// Magpie +// +// Created by incar on 2024/1/9. +// + +import Foundation +import Moya +import HandyJSON + +// 相关api +enum CommomApi +{ + case sms(phone:String) + case list(pageNO: Int = 1, pageSize: Int = 10) + case login(phone:String,code:String) +} + +// 实现TargetType协议 +extension CommomApi: TargetType +{ + // url + var baseURL: URL + { + return URL(string: "https://app-api.raisound.com")! + } + + /// 请求路径 + var path: String { + switch self { + case .sms(let phone): + return "/sys/sms/reg-login/\(phone)" + case .list: + return "list" + case .login(_,_): + return "/uc/phone/reg-login" + } + } + + /// 请求方式 + var method: Moya.Method { + switch self { + case .sms(_): + return .get + case .login(_,_): + return .post + default: + return .get + } + } + + /// 解析格式 + var sampleData: Data { + return "{}".data(using: String.Encoding.utf8)! + } +//https://sz.58.com/esf-ajax/activity/ashen_switch/?city_id=4 + + var task: Task { + // 公共参数 + var params: [String: Any] = ["token": "Gz1qYLXeBW8MZuUfDlr9wsAYuVS1cZFMJY9BbaF842L2gRps747o4w=="] + + // 收集参数 + switch self { + case let .list(pageNO, pageSize): + params["pageNO"] = pageNO + params["pageSize"] = pageSize + case let .login(phone,code): + params["phone"] = phone + params["smsCode"] = code + break + default: break + } + // 发起请求 + return .requestParameters(parameters: params, encoding: URLEncoding.default) + } + + /// 公共请求头 + var headers: [String : String]? { + return ["devtype": "iOS", "devid": UIDevice().identifierForVendor?.uuidString ?? "unknow"] + } + + +//https://gz.fang.anjuke.com/xinfang/harmony/adviser/adviser/getMainAdviserBlock?client_source=3&limit=100&target_id=523085&target_type=1&adviser_id=&adviser_type=1&loupan_id=523085&layout_id=&page_source=2 +} + +class HttpClient{ + static let instance = HttpClient() + let provider = MoyaProvider() + func request(_ target: CommomApi,completionHandler:@escaping ((T, String) -> Void)){ + + provider.request(target){ (response) in + switch response { + case .success(let value): + let data = value.data +// print("reponse data=>",data.hexEncodedString()) + var responseStr = "response转字符串失败" + if let str = String(data: data, encoding: .utf8) { + responseStr = str + } + print("reponse text=>",responseStr) + if let res = T.deserialize(from: responseStr){ + completionHandler(res,responseStr) + return + } + completionHandler(ResponseBaseModel() as! T,"解析请求失败") + break + case .failure(let error): + completionHandler(ResponseBaseModel() as! T,"请求失败") + print("***************\n网络连接失败!\n\(error)\n********************") + } + } + } + +} diff --git a/LingQi/LingQi/Api/ResponseBaseModel.swift b/LingQi/LingQi/Api/ResponseBaseModel.swift new file mode 100644 index 0000000..a56f0d2 --- /dev/null +++ b/LingQi/LingQi/Api/ResponseBaseModel.swift @@ -0,0 +1,19 @@ +// +// BaseResponseModel.swift +// Magpie +// +// Created by incar on 2024/1/9. +// + +import Foundation +import HandyJSON +public class ResponseBaseModel: HandyJSON { + required public init() { } + + public var code = -1 + public var status = 0 + public var msg = "请求失败" + + + public var isSuccess: Bool { return code == 20000} +} diff --git a/LingQi/LingQi/AppDelegate.swift b/LingQi/LingQi/AppDelegate.swift new file mode 100644 index 0000000..29649ef --- /dev/null +++ b/LingQi/LingQi/AppDelegate.swift @@ -0,0 +1,35 @@ +// +// AppDelegate.swift +// LingQi +// +// Created by liangshi on 2025/7/29. +// + +import UIKit +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + + + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + return true + } + + // MARK: UISceneSession Lifecycle + + func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { + // Called when a new scene session is being created. + // Use this method to select a configuration to create the new scene with. + return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) + } + + func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { + // Called when the user discards a scene session. + // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. + // Use this method to release any resources that were specific to the discarded scenes, as they will not return. + } + + +} + diff --git a/LingQi/LingQi/Assets.xcassets/AccentColor.colorset/Contents.json b/LingQi/LingQi/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/AppIcon.appiconset/Contents.json b/LingQi/LingQi/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..2305880 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,35 @@ +{ + "images" : [ + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "tinted" + } + ], + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/Contents.json b/LingQi/LingQi/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/Contents.json b/LingQi/LingQi/Assets.xcassets/an/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/bg_base.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/bg_base.imageset/Contents.json new file mode 100644 index 0000000..6766429 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/bg_base.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "bg_base.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/bg_base.imageset/bg_base.png b/LingQi/LingQi/Assets.xcassets/an/bg_base.imageset/bg_base.png new file mode 100644 index 0000000..4abebc3 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/bg_base.imageset/bg_base.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/bg_login.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/bg_login.imageset/Contents.json new file mode 100644 index 0000000..a177303 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/bg_login.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "bg_login.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/bg_login.imageset/bg_login.png b/LingQi/LingQi/Assets.xcassets/an/bg_login.imageset/bg_login.png new file mode 100644 index 0000000..4abebc3 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/bg_login.imageset/bg_login.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/bg_mine_order.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/bg_mine_order.imageset/Contents.json new file mode 100644 index 0000000..42e2d1d --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/bg_mine_order.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "bg_mine_order.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/bg_mine_order.imageset/bg_mine_order.png b/LingQi/LingQi/Assets.xcassets/an/bg_mine_order.imageset/bg_mine_order.png new file mode 100644 index 0000000..6c31d88 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/bg_mine_order.imageset/bg_mine_order.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/bg_mine_order2.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/bg_mine_order2.imageset/Contents.json new file mode 100644 index 0000000..8b90f20 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/bg_mine_order2.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "bg_mine_order2.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/bg_mine_order2.imageset/bg_mine_order2.png b/LingQi/LingQi/Assets.xcassets/an/bg_mine_order2.imageset/bg_mine_order2.png new file mode 100644 index 0000000..821c18e Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/bg_mine_order2.imageset/bg_mine_order2.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/bg_splash.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/bg_splash.imageset/Contents.json new file mode 100644 index 0000000..65cc863 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/bg_splash.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "bg_splash.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/bg_splash.imageset/bg_splash.png b/LingQi/LingQi/Assets.xcassets/an/bg_splash.imageset/bg_splash.png new file mode 100644 index 0000000..7bce36c Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/bg_splash.imageset/bg_splash.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/dialog_bg.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/dialog_bg.imageset/Contents.json new file mode 100644 index 0000000..e865ee3 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/dialog_bg.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "dialog_bg.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/dialog_bg.imageset/dialog_bg.png b/LingQi/LingQi/Assets.xcassets/an/dialog_bg.imageset/dialog_bg.png new file mode 100644 index 0000000..3609e20 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/dialog_bg.imageset/dialog_bg.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/dialog_bg_2.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/dialog_bg_2.imageset/Contents.json new file mode 100644 index 0000000..eea521f --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/dialog_bg_2.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "dialog_bg_2.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/dialog_bg_2.imageset/dialog_bg_2.png b/LingQi/LingQi/Assets.xcassets/an/dialog_bg_2.imageset/dialog_bg_2.png new file mode 100644 index 0000000..33255ee Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/dialog_bg_2.imageset/dialog_bg_2.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_ai_config.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_ai_config.imageset/Contents.json new file mode 100644 index 0000000..d78f4b4 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_ai_config.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_ai_config.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_ai_config.imageset/ic_ai_config.png b/LingQi/LingQi/Assets.xcassets/an/ic_ai_config.imageset/ic_ai_config.png new file mode 100644 index 0000000..1f5f705 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_ai_config.imageset/ic_ai_config.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_break.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_break.imageset/Contents.json new file mode 100644 index 0000000..61050d3 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_break.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_break.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_break.imageset/ic_break.png b/LingQi/LingQi/Assets.xcassets/an/ic_break.imageset/ic_break.png new file mode 100644 index 0000000..c2e5cde Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_break.imageset/ic_break.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_check.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_check.imageset/Contents.json new file mode 100644 index 0000000..6b9f721 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_check.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_check.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_check.imageset/ic_check.png b/LingQi/LingQi/Assets.xcassets/an/ic_check.imageset/ic_check.png new file mode 100644 index 0000000..4dff75a Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_check.imageset/ic_check.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_connect_link.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_connect_link.imageset/Contents.json new file mode 100644 index 0000000..46bab63 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_connect_link.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_connect_link.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_connect_link.imageset/ic_connect_link.png b/LingQi/LingQi/Assets.xcassets/an/ic_connect_link.imageset/ic_connect_link.png new file mode 100644 index 0000000..dbc4d0b Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_connect_link.imageset/ic_connect_link.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_connect_log.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_connect_log.imageset/Contents.json new file mode 100644 index 0000000..12839ef --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_connect_log.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_connect_log.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_connect_log.imageset/ic_connect_log.png b/LingQi/LingQi/Assets.xcassets/an/ic_connect_log.imageset/ic_connect_log.png new file mode 100644 index 0000000..c397397 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_connect_log.imageset/ic_connect_log.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_connect_log1.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_connect_log1.imageset/Contents.json new file mode 100644 index 0000000..bd2fa29 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_connect_log1.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_connect_log1.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_connect_log1.imageset/ic_connect_log1.png b/LingQi/LingQi/Assets.xcassets/an/ic_connect_log1.imageset/ic_connect_log1.png new file mode 100644 index 0000000..b7dbcb5 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_connect_log1.imageset/ic_connect_log1.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_connect_product.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_connect_product.imageset/Contents.json new file mode 100644 index 0000000..5fba3c0 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_connect_product.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_connect_product.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_connect_product.imageset/ic_connect_product.png b/LingQi/LingQi/Assets.xcassets/an/ic_connect_product.imageset/ic_connect_product.png new file mode 100644 index 0000000..7df4372 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_connect_product.imageset/ic_connect_product.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_connect_product1.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_connect_product1.imageset/Contents.json new file mode 100644 index 0000000..74788c5 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_connect_product1.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_connect_product1.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_connect_product1.imageset/ic_connect_product1.png b/LingQi/LingQi/Assets.xcassets/an/ic_connect_product1.imageset/ic_connect_product1.png new file mode 100644 index 0000000..5921750 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_connect_product1.imageset/ic_connect_product1.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_device_set.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_device_set.imageset/Contents.json new file mode 100644 index 0000000..5fde870 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_device_set.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_device_set.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_device_set.imageset/ic_device_set.png b/LingQi/LingQi/Assets.xcassets/an/ic_device_set.imageset/ic_device_set.png new file mode 100644 index 0000000..7565be3 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_device_set.imageset/ic_device_set.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_dui.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_dui.imageset/Contents.json new file mode 100644 index 0000000..50b6af5 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_dui.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_dui.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_dui.imageset/ic_dui.png b/LingQi/LingQi/Assets.xcassets/an/ic_dui.imageset/ic_dui.png new file mode 100644 index 0000000..24d645d Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_dui.imageset/ic_dui.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_edit.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_edit.imageset/Contents.json new file mode 100644 index 0000000..123849f --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_edit.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_edit.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_edit.imageset/ic_edit.png b/LingQi/LingQi/Assets.xcassets/an/ic_edit.imageset/ic_edit.png new file mode 100644 index 0000000..f669860 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_edit.imageset/ic_edit.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_false.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_false.imageset/Contents.json new file mode 100644 index 0000000..1ca784a --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_false.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_false.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_false.imageset/ic_false.png b/LingQi/LingQi/Assets.xcassets/an/ic_false.imageset/ic_false.png new file mode 100644 index 0000000..63cba3f Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_false.imageset/ic_false.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_finger.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_finger.imageset/Contents.json new file mode 100644 index 0000000..1d0e3ca --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_finger.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_finger.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_finger.imageset/ic_finger.png b/LingQi/LingQi/Assets.xcassets/an/ic_finger.imageset/ic_finger.png new file mode 100644 index 0000000..564c53b Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_finger.imageset/ic_finger.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_home_add.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_home_add.imageset/Contents.json new file mode 100644 index 0000000..5012820 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_home_add.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_home_add.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_home_add.imageset/ic_home_add.png b/LingQi/LingQi/Assets.xcassets/an/ic_home_add.imageset/ic_home_add.png new file mode 100644 index 0000000..7f6f775 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_home_add.imageset/ic_home_add.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_home_home.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_home_home.imageset/Contents.json new file mode 100644 index 0000000..9d77527 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_home_home.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_home_home.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_home_home.imageset/ic_home_home.png b/LingQi/LingQi/Assets.xcassets/an/ic_home_home.imageset/ic_home_home.png new file mode 100644 index 0000000..0d15721 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_home_home.imageset/ic_home_home.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_home_home_sel.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_home_home_sel.imageset/Contents.json new file mode 100644 index 0000000..7d91207 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_home_home_sel.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_home_home_sel.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_home_home_sel.imageset/ic_home_home_sel.png b/LingQi/LingQi/Assets.xcassets/an/ic_home_home_sel.imageset/ic_home_home_sel.png new file mode 100644 index 0000000..5dafc99 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_home_home_sel.imageset/ic_home_home_sel.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_home_mine.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_home_mine.imageset/Contents.json new file mode 100644 index 0000000..3a5c62c --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_home_mine.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_home_mine.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_home_mine.imageset/ic_home_mine.png b/LingQi/LingQi/Assets.xcassets/an/ic_home_mine.imageset/ic_home_mine.png new file mode 100644 index 0000000..550b4f9 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_home_mine.imageset/ic_home_mine.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_home_mine_sel.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_home_mine_sel.imageset/Contents.json new file mode 100644 index 0000000..63783aa --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_home_mine_sel.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_home_mine_sel.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_home_mine_sel.imageset/ic_home_mine_sel.png b/LingQi/LingQi/Assets.xcassets/an/ic_home_mine_sel.imageset/ic_home_mine_sel.png new file mode 100644 index 0000000..a3134c4 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_home_mine_sel.imageset/ic_home_mine_sel.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_home_nodevice.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_home_nodevice.imageset/Contents.json new file mode 100644 index 0000000..6efbd6a --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_home_nodevice.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_home_nodevice.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_home_nodevice.imageset/ic_home_nodevice.png b/LingQi/LingQi/Assets.xcassets/an/ic_home_nodevice.imageset/ic_home_nodevice.png new file mode 100644 index 0000000..183e629 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_home_nodevice.imageset/ic_home_nodevice.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_home_scan.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_home_scan.imageset/Contents.json new file mode 100644 index 0000000..7077852 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_home_scan.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_home_scan.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_home_scan.imageset/ic_home_scan.png b/LingQi/LingQi/Assets.xcassets/an/ic_home_scan.imageset/ic_home_scan.png new file mode 100644 index 0000000..99047ce Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_home_scan.imageset/ic_home_scan.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_home_tv.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_home_tv.imageset/Contents.json new file mode 100644 index 0000000..d025cde --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_home_tv.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_home_tv.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_home_tv.imageset/ic_home_tv.png b/LingQi/LingQi/Assets.xcassets/an/ic_home_tv.imageset/ic_home_tv.png new file mode 100644 index 0000000..270f341 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_home_tv.imageset/ic_home_tv.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_link.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_link.imageset/Contents.json new file mode 100644 index 0000000..350aa96 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_link.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_link.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_link.imageset/ic_link.png b/LingQi/LingQi/Assets.xcassets/an/ic_link.imageset/ic_link.png new file mode 100644 index 0000000..c70fbdb Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_link.imageset/ic_link.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_linked.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_linked.imageset/Contents.json new file mode 100644 index 0000000..ce89a45 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_linked.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_linked.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_linked.imageset/ic_linked.png b/LingQi/LingQi/Assets.xcassets/an/ic_linked.imageset/ic_linked.png new file mode 100644 index 0000000..db4ee36 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_linked.imageset/ic_linked.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_logo.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_logo.imageset/Contents.json new file mode 100644 index 0000000..301eaaa --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_logo.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_logo.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_logo.imageset/ic_logo.png b/LingQi/LingQi/Assets.xcassets/an/ic_logo.imageset/ic_logo.png new file mode 100644 index 0000000..d9c726b Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_logo.imageset/ic_logo.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_mac.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_mac.imageset/Contents.json new file mode 100644 index 0000000..6454deb --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_mac.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_mac.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_mac.imageset/ic_mac.png b/LingQi/LingQi/Assets.xcassets/an/ic_mac.imageset/ic_mac.png new file mode 100644 index 0000000..3df7fe5 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_mac.imageset/ic_mac.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_man.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_man.imageset/Contents.json new file mode 100644 index 0000000..9ca6fff --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_man.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_man.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_man.imageset/ic_man.png b/LingQi/LingQi/Assets.xcassets/an/ic_man.imageset/ic_man.png new file mode 100644 index 0000000..83f643c Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_man.imageset/ic_man.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_mine_1.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_mine_1.imageset/Contents.json new file mode 100644 index 0000000..ea401dc --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_mine_1.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_mine_1.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_mine_1.imageset/ic_mine_1.png b/LingQi/LingQi/Assets.xcassets/an/ic_mine_1.imageset/ic_mine_1.png new file mode 100644 index 0000000..543b9f4 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_mine_1.imageset/ic_mine_1.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_mine_2.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_mine_2.imageset/Contents.json new file mode 100644 index 0000000..ca9a119 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_mine_2.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_mine_2.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_mine_2.imageset/ic_mine_2.png b/LingQi/LingQi/Assets.xcassets/an/ic_mine_2.imageset/ic_mine_2.png new file mode 100644 index 0000000..df0606e Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_mine_2.imageset/ic_mine_2.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_mine_3.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_mine_3.imageset/Contents.json new file mode 100644 index 0000000..2b04ada --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_mine_3.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_mine_3.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_mine_3.imageset/ic_mine_3.png b/LingQi/LingQi/Assets.xcassets/an/ic_mine_3.imageset/ic_mine_3.png new file mode 100644 index 0000000..ad39548 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_mine_3.imageset/ic_mine_3.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_more.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_more.imageset/Contents.json new file mode 100644 index 0000000..9012365 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_more.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_more.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_more.imageset/ic_more.png b/LingQi/LingQi/Assets.xcassets/an/ic_more.imageset/ic_more.png new file mode 100644 index 0000000..7c3f28a Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_more.imageset/ic_more.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_more2.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_more2.imageset/Contents.json new file mode 100644 index 0000000..5b7ebe8 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_more2.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_more2.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_more2.imageset/ic_more2.png b/LingQi/LingQi/Assets.xcassets/an/ic_more2.imageset/ic_more2.png new file mode 100644 index 0000000..327b014 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_more2.imageset/ic_more2.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_msg_recoder.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_msg_recoder.imageset/Contents.json new file mode 100644 index 0000000..3711e46 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_msg_recoder.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_msg_recoder.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_msg_recoder.imageset/ic_msg_recoder.png b/LingQi/LingQi/Assets.xcassets/an/ic_msg_recoder.imageset/ic_msg_recoder.png new file mode 100644 index 0000000..fd1393f Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_msg_recoder.imageset/ic_msg_recoder.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_nopub.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_nopub.imageset/Contents.json new file mode 100644 index 0000000..d174291 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_nopub.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_nopub.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_nopub.imageset/ic_nopub.png b/LingQi/LingQi/Assets.xcassets/an/ic_nopub.imageset/ic_nopub.png new file mode 100644 index 0000000..179920f Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_nopub.imageset/ic_nopub.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_power.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_power.imageset/Contents.json new file mode 100644 index 0000000..880a0b0 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_power.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_power.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_power.imageset/ic_power.png b/LingQi/LingQi/Assets.xcassets/an/ic_power.imageset/ic_power.png new file mode 100644 index 0000000..25ec4ca Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_power.imageset/ic_power.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_product.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_product.imageset/Contents.json new file mode 100644 index 0000000..46e23a3 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_product.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_product.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_product.imageset/ic_product.png b/LingQi/LingQi/Assets.xcassets/an/ic_product.imageset/ic_product.png new file mode 100644 index 0000000..47ca72e Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_product.imageset/ic_product.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_remainber.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_remainber.imageset/Contents.json new file mode 100644 index 0000000..302190f --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_remainber.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_remainber.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_remainber.imageset/ic_remainber.png b/LingQi/LingQi/Assets.xcassets/an/ic_remainber.imageset/ic_remainber.png new file mode 100644 index 0000000..c63c630 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_remainber.imageset/ic_remainber.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_role.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_role.imageset/Contents.json new file mode 100644 index 0000000..5137c7e --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_role.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_role.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_role.imageset/ic_role.png b/LingQi/LingQi/Assets.xcassets/an/ic_role.imageset/ic_role.png new file mode 100644 index 0000000..d6e6ba3 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_role.imageset/ic_role.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_scam.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_scam.imageset/Contents.json new file mode 100644 index 0000000..63367d1 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_scam.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_scam.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_scam.imageset/ic_scam.png b/LingQi/LingQi/Assets.xcassets/an/ic_scam.imageset/ic_scam.png new file mode 100644 index 0000000..99047ce Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_scam.imageset/ic_scam.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_seach.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_seach.imageset/Contents.json new file mode 100644 index 0000000..0af1df6 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_seach.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_seach.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_seach.imageset/ic_seach.png b/LingQi/LingQi/Assets.xcassets/an/ic_seach.imageset/ic_seach.png new file mode 100644 index 0000000..7db0a19 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_seach.imageset/ic_seach.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_speak.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_speak.imageset/Contents.json new file mode 100644 index 0000000..7b79d42 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_speak.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_speak.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_speak.imageset/ic_speak.png b/LingQi/LingQi/Assets.xcassets/an/ic_speak.imageset/ic_speak.png new file mode 100644 index 0000000..1cbb8a0 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_speak.imageset/ic_speak.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_speek.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_speek.imageset/Contents.json new file mode 100644 index 0000000..d28a1f9 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_speek.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_speek.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_speek.imageset/ic_speek.png b/LingQi/LingQi/Assets.xcassets/an/ic_speek.imageset/ic_speek.png new file mode 100644 index 0000000..766941f Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_speek.imageset/ic_speek.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_sure.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_sure.imageset/Contents.json new file mode 100644 index 0000000..1c551a2 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_sure.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_sure.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_sure.imageset/ic_sure.png b/LingQi/LingQi/Assets.xcassets/an/ic_sure.imageset/ic_sure.png new file mode 100644 index 0000000..930d62d Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_sure.imageset/ic_sure.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_tip.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_tip.imageset/Contents.json new file mode 100644 index 0000000..8111a5b --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_tip.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_tip.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_tip.imageset/ic_tip.png b/LingQi/LingQi/Assets.xcassets/an/ic_tip.imageset/ic_tip.png new file mode 100644 index 0000000..f60df48 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_tip.imageset/ic_tip.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_unlink.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_unlink.imageset/Contents.json new file mode 100644 index 0000000..9f5415f --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_unlink.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_unlink.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_unlink.imageset/ic_unlink.png b/LingQi/LingQi/Assets.xcassets/an/ic_unlink.imageset/ic_unlink.png new file mode 100644 index 0000000..7ac0399 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_unlink.imageset/ic_unlink.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_user.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_user.imageset/Contents.json new file mode 100644 index 0000000..b93e673 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_user.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_user.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_user.imageset/ic_user.png b/LingQi/LingQi/Assets.xcassets/an/ic_user.imageset/ic_user.png new file mode 100644 index 0000000..6df0916 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_user.imageset/ic_user.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_vip_year.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_vip_year.imageset/Contents.json new file mode 100644 index 0000000..8534088 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_vip_year.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_vip_year.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_vip_year.imageset/ic_vip_year.png b/LingQi/LingQi/Assets.xcassets/an/ic_vip_year.imageset/ic_vip_year.png new file mode 100644 index 0000000..32219f8 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_vip_year.imageset/ic_vip_year.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_voice.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_voice.imageset/Contents.json new file mode 100644 index 0000000..b0cde55 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_voice.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_voice.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_voice.imageset/ic_voice.png b/LingQi/LingQi/Assets.xcassets/an/ic_voice.imageset/ic_voice.png new file mode 100644 index 0000000..5373980 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_voice.imageset/ic_voice.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_voice_jia.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_voice_jia.imageset/Contents.json new file mode 100644 index 0000000..3b01221 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_voice_jia.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_voice_jia.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_voice_jia.imageset/ic_voice_jia.png b/LingQi/LingQi/Assets.xcassets/an/ic_voice_jia.imageset/ic_voice_jia.png new file mode 100644 index 0000000..bec62a4 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_voice_jia.imageset/ic_voice_jia.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_voice_jian.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_voice_jian.imageset/Contents.json new file mode 100644 index 0000000..0713580 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_voice_jian.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_voice_jian.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_voice_jian.imageset/ic_voice_jian.png b/LingQi/LingQi/Assets.xcassets/an/ic_voice_jian.imageset/ic_voice_jian.png new file mode 100644 index 0000000..d97369a Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_voice_jian.imageset/ic_voice_jian.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_wifi1.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_wifi1.imageset/Contents.json new file mode 100644 index 0000000..91c5dfc --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_wifi1.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_wifi1.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_wifi1.imageset/ic_wifi1.png b/LingQi/LingQi/Assets.xcassets/an/ic_wifi1.imageset/ic_wifi1.png new file mode 100644 index 0000000..6558488 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_wifi1.imageset/ic_wifi1.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_wifi2.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_wifi2.imageset/Contents.json new file mode 100644 index 0000000..eaa7d20 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_wifi2.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_wifi2.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_wifi2.imageset/ic_wifi2.png b/LingQi/LingQi/Assets.xcassets/an/ic_wifi2.imageset/ic_wifi2.png new file mode 100644 index 0000000..5244b23 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_wifi2.imageset/ic_wifi2.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_wifi3.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_wifi3.imageset/Contents.json new file mode 100644 index 0000000..00a14bd --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_wifi3.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_wifi3.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_wifi3.imageset/ic_wifi3.png b/LingQi/LingQi/Assets.xcassets/an/ic_wifi3.imageset/ic_wifi3.png new file mode 100644 index 0000000..5244b23 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_wifi3.imageset/ic_wifi3.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_wifi4.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_wifi4.imageset/Contents.json new file mode 100644 index 0000000..ef6b388 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_wifi4.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_wifi4.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_wifi4.imageset/ic_wifi4.png b/LingQi/LingQi/Assets.xcassets/an/ic_wifi4.imageset/ic_wifi4.png new file mode 100644 index 0000000..fdc21db Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_wifi4.imageset/ic_wifi4.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_woman.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_woman.imageset/Contents.json new file mode 100644 index 0000000..555340d --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_woman.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_woman.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_woman.imageset/ic_woman.png b/LingQi/LingQi/Assets.xcassets/an/ic_woman.imageset/ic_woman.png new file mode 100644 index 0000000..ee388cf Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_woman.imageset/ic_woman.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_yinse.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/ic_yinse.imageset/Contents.json new file mode 100644 index 0000000..7f86ecc --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/ic_yinse.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_yinse.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/ic_yinse.imageset/ic_yinse.png b/LingQi/LingQi/Assets.xcassets/an/ic_yinse.imageset/ic_yinse.png new file mode 100644 index 0000000..fd36fa1 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/ic_yinse.imageset/ic_yinse.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/loading.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/loading.imageset/Contents.json new file mode 100644 index 0000000..10a4d43 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/loading.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "loading.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/loading.imageset/loading.png b/LingQi/LingQi/Assets.xcassets/an/loading.imageset/loading.png new file mode 100644 index 0000000..ad89ca1 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/loading.imageset/loading.png differ diff --git a/LingQi/LingQi/Assets.xcassets/an/splash_tv.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/an/splash_tv.imageset/Contents.json new file mode 100644 index 0000000..525073d --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/an/splash_tv.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "splash_tv.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/an/splash_tv.imageset/splash_tv.png b/LingQi/LingQi/Assets.xcassets/an/splash_tv.imageset/splash_tv.png new file mode 100644 index 0000000..5e82271 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/an/splash_tv.imageset/splash_tv.png differ diff --git "a/LingQi/LingQi/Assets.xcassets/home/081_\345\217\221\347\216\260.imageset/081_\345\217\221\347\216\260.png" "b/LingQi/LingQi/Assets.xcassets/home/081_\345\217\221\347\216\260.imageset/081_\345\217\221\347\216\260.png" new file mode 100644 index 0000000..c40687b Binary files /dev/null and "b/LingQi/LingQi/Assets.xcassets/home/081_\345\217\221\347\216\260.imageset/081_\345\217\221\347\216\260.png" differ diff --git "a/LingQi/LingQi/Assets.xcassets/home/081_\345\217\221\347\216\260.imageset/081_\345\217\221\347\216\260@2x.png" "b/LingQi/LingQi/Assets.xcassets/home/081_\345\217\221\347\216\260.imageset/081_\345\217\221\347\216\260@2x.png" new file mode 100644 index 0000000..7a797e4 Binary files /dev/null and "b/LingQi/LingQi/Assets.xcassets/home/081_\345\217\221\347\216\260.imageset/081_\345\217\221\347\216\260@2x.png" differ diff --git "a/LingQi/LingQi/Assets.xcassets/home/081_\345\217\221\347\216\260.imageset/081_\345\217\221\347\216\260@3x.png" "b/LingQi/LingQi/Assets.xcassets/home/081_\345\217\221\347\216\260.imageset/081_\345\217\221\347\216\260@3x.png" new file mode 100644 index 0000000..5b331d3 Binary files /dev/null and "b/LingQi/LingQi/Assets.xcassets/home/081_\345\217\221\347\216\260.imageset/081_\345\217\221\347\216\260@3x.png" differ diff --git "a/LingQi/LingQi/Assets.xcassets/home/081_\345\217\221\347\216\260.imageset/Contents.json" "b/LingQi/LingQi/Assets.xcassets/home/081_\345\217\221\347\216\260.imageset/Contents.json" new file mode 100644 index 0000000..15635ff --- /dev/null +++ "b/LingQi/LingQi/Assets.xcassets/home/081_\345\217\221\347\216\260.imageset/Contents.json" @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "081_发现.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "081_发现@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "081_发现@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/home/Contents.json b/LingQi/LingQi/Assets.xcassets/home/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/home/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/home/Frame 134.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/home/Frame 134.imageset/Contents.json new file mode 100644 index 0000000..944c2cb --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/home/Frame 134.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Frame 134.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame 134@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame 134@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/home/Frame 134.imageset/Frame 134.png b/LingQi/LingQi/Assets.xcassets/home/Frame 134.imageset/Frame 134.png new file mode 100644 index 0000000..e02bb67 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/home/Frame 134.imageset/Frame 134.png differ diff --git a/LingQi/LingQi/Assets.xcassets/home/Frame 134.imageset/Frame 134@2x.png b/LingQi/LingQi/Assets.xcassets/home/Frame 134.imageset/Frame 134@2x.png new file mode 100644 index 0000000..9f4e42b Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/home/Frame 134.imageset/Frame 134@2x.png differ diff --git a/LingQi/LingQi/Assets.xcassets/home/Frame 134.imageset/Frame 134@3x.png b/LingQi/LingQi/Assets.xcassets/home/Frame 134.imageset/Frame 134@3x.png new file mode 100644 index 0000000..25c03b1 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/home/Frame 134.imageset/Frame 134@3x.png differ diff --git a/LingQi/LingQi/Assets.xcassets/home/Frame 220.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/home/Frame 220.imageset/Contents.json new file mode 100644 index 0000000..3ed7a02 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/home/Frame 220.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Frame 220.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame 220@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame 220@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/home/Frame 220.imageset/Frame 220.png b/LingQi/LingQi/Assets.xcassets/home/Frame 220.imageset/Frame 220.png new file mode 100644 index 0000000..3f62fcd Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/home/Frame 220.imageset/Frame 220.png differ diff --git a/LingQi/LingQi/Assets.xcassets/home/Frame 220.imageset/Frame 220@2x.png b/LingQi/LingQi/Assets.xcassets/home/Frame 220.imageset/Frame 220@2x.png new file mode 100644 index 0000000..8d54b72 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/home/Frame 220.imageset/Frame 220@2x.png differ diff --git a/LingQi/LingQi/Assets.xcassets/home/Frame 220.imageset/Frame 220@3x.png b/LingQi/LingQi/Assets.xcassets/home/Frame 220.imageset/Frame 220@3x.png new file mode 100644 index 0000000..51c3c3a Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/home/Frame 220.imageset/Frame 220@3x.png differ diff --git a/LingQi/LingQi/Assets.xcassets/home/Group 347.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/home/Group 347.imageset/Contents.json new file mode 100644 index 0000000..ecfabe9 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/home/Group 347.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Group 347.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Group 347@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Group 347@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/home/Group 347.imageset/Group 347.png b/LingQi/LingQi/Assets.xcassets/home/Group 347.imageset/Group 347.png new file mode 100644 index 0000000..1b9025d Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/home/Group 347.imageset/Group 347.png differ diff --git a/LingQi/LingQi/Assets.xcassets/home/Group 347.imageset/Group 347@2x.png b/LingQi/LingQi/Assets.xcassets/home/Group 347.imageset/Group 347@2x.png new file mode 100644 index 0000000..b36e6d5 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/home/Group 347.imageset/Group 347@2x.png differ diff --git a/LingQi/LingQi/Assets.xcassets/home/Group 347.imageset/Group 347@3x.png b/LingQi/LingQi/Assets.xcassets/home/Group 347.imageset/Group 347@3x.png new file mode 100644 index 0000000..2538ebc Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/home/Group 347.imageset/Group 347@3x.png differ diff --git a/LingQi/LingQi/Assets.xcassets/home/Group 352.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/home/Group 352.imageset/Contents.json new file mode 100644 index 0000000..3c2949a --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/home/Group 352.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Group 352.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Group 352@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Group 352@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/home/Group 352.imageset/Group 352.png b/LingQi/LingQi/Assets.xcassets/home/Group 352.imageset/Group 352.png new file mode 100644 index 0000000..92b6c57 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/home/Group 352.imageset/Group 352.png differ diff --git a/LingQi/LingQi/Assets.xcassets/home/Group 352.imageset/Group 352@2x.png b/LingQi/LingQi/Assets.xcassets/home/Group 352.imageset/Group 352@2x.png new file mode 100644 index 0000000..118c0d7 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/home/Group 352.imageset/Group 352@2x.png differ diff --git a/LingQi/LingQi/Assets.xcassets/home/Group 352.imageset/Group 352@3x.png b/LingQi/LingQi/Assets.xcassets/home/Group 352.imageset/Group 352@3x.png new file mode 100644 index 0000000..47561b6 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/home/Group 352.imageset/Group 352@3x.png differ diff --git "a/LingQi/LingQi/Assets.xcassets/home/tab_0_normal.imageset/081_\344\270\273\351\241\265.png" "b/LingQi/LingQi/Assets.xcassets/home/tab_0_normal.imageset/081_\344\270\273\351\241\265.png" new file mode 100644 index 0000000..a92d424 Binary files /dev/null and "b/LingQi/LingQi/Assets.xcassets/home/tab_0_normal.imageset/081_\344\270\273\351\241\265.png" differ diff --git "a/LingQi/LingQi/Assets.xcassets/home/tab_0_normal.imageset/081_\344\270\273\351\241\265@2x.png" "b/LingQi/LingQi/Assets.xcassets/home/tab_0_normal.imageset/081_\344\270\273\351\241\265@2x.png" new file mode 100644 index 0000000..4541a27 Binary files /dev/null and "b/LingQi/LingQi/Assets.xcassets/home/tab_0_normal.imageset/081_\344\270\273\351\241\265@2x.png" differ diff --git "a/LingQi/LingQi/Assets.xcassets/home/tab_0_normal.imageset/081_\344\270\273\351\241\265@3x.png" "b/LingQi/LingQi/Assets.xcassets/home/tab_0_normal.imageset/081_\344\270\273\351\241\265@3x.png" new file mode 100644 index 0000000..5a29c1c Binary files /dev/null and "b/LingQi/LingQi/Assets.xcassets/home/tab_0_normal.imageset/081_\344\270\273\351\241\265@3x.png" differ diff --git a/LingQi/LingQi/Assets.xcassets/home/tab_0_normal.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/home/tab_0_normal.imageset/Contents.json new file mode 100644 index 0000000..c21be7b --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/home/tab_0_normal.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "081_主页.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "081_主页@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "081_主页@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git "a/LingQi/LingQi/Assets.xcassets/home/tab_0_selected.imageset/081_\344\270\273\351\241\265.png" "b/LingQi/LingQi/Assets.xcassets/home/tab_0_selected.imageset/081_\344\270\273\351\241\265.png" new file mode 100644 index 0000000..f91691a Binary files /dev/null and "b/LingQi/LingQi/Assets.xcassets/home/tab_0_selected.imageset/081_\344\270\273\351\241\265.png" differ diff --git "a/LingQi/LingQi/Assets.xcassets/home/tab_0_selected.imageset/081_\344\270\273\351\241\265@2x.png" "b/LingQi/LingQi/Assets.xcassets/home/tab_0_selected.imageset/081_\344\270\273\351\241\265@2x.png" new file mode 100644 index 0000000..db6a6ed Binary files /dev/null and "b/LingQi/LingQi/Assets.xcassets/home/tab_0_selected.imageset/081_\344\270\273\351\241\265@2x.png" differ diff --git "a/LingQi/LingQi/Assets.xcassets/home/tab_0_selected.imageset/081_\344\270\273\351\241\265@3x.png" "b/LingQi/LingQi/Assets.xcassets/home/tab_0_selected.imageset/081_\344\270\273\351\241\265@3x.png" new file mode 100644 index 0000000..1e18885 Binary files /dev/null and "b/LingQi/LingQi/Assets.xcassets/home/tab_0_selected.imageset/081_\344\270\273\351\241\265@3x.png" differ diff --git a/LingQi/LingQi/Assets.xcassets/home/tab_0_selected.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/home/tab_0_selected.imageset/Contents.json new file mode 100644 index 0000000..c21be7b --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/home/tab_0_selected.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "081_主页.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "081_主页@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "081_主页@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git "a/LingQi/LingQi/Assets.xcassets/home/tab_1_normal.imageset/081_\346\210\221\347\232\204.png" "b/LingQi/LingQi/Assets.xcassets/home/tab_1_normal.imageset/081_\346\210\221\347\232\204.png" new file mode 100644 index 0000000..da8e9f3 Binary files /dev/null and "b/LingQi/LingQi/Assets.xcassets/home/tab_1_normal.imageset/081_\346\210\221\347\232\204.png" differ diff --git "a/LingQi/LingQi/Assets.xcassets/home/tab_1_normal.imageset/081_\346\210\221\347\232\204@2x.png" "b/LingQi/LingQi/Assets.xcassets/home/tab_1_normal.imageset/081_\346\210\221\347\232\204@2x.png" new file mode 100644 index 0000000..bac40a7 Binary files /dev/null and "b/LingQi/LingQi/Assets.xcassets/home/tab_1_normal.imageset/081_\346\210\221\347\232\204@2x.png" differ diff --git "a/LingQi/LingQi/Assets.xcassets/home/tab_1_normal.imageset/081_\346\210\221\347\232\204@3x.png" "b/LingQi/LingQi/Assets.xcassets/home/tab_1_normal.imageset/081_\346\210\221\347\232\204@3x.png" new file mode 100644 index 0000000..50c504c Binary files /dev/null and "b/LingQi/LingQi/Assets.xcassets/home/tab_1_normal.imageset/081_\346\210\221\347\232\204@3x.png" differ diff --git a/LingQi/LingQi/Assets.xcassets/home/tab_1_normal.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/home/tab_1_normal.imageset/Contents.json new file mode 100644 index 0000000..71388ea --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/home/tab_1_normal.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "081_我的.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "081_我的@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "081_我的@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git "a/LingQi/LingQi/Assets.xcassets/home/tab_1_selected.imageset/081_\346\210\221\347\232\204.png" "b/LingQi/LingQi/Assets.xcassets/home/tab_1_selected.imageset/081_\346\210\221\347\232\204.png" new file mode 100644 index 0000000..1b99f19 Binary files /dev/null and "b/LingQi/LingQi/Assets.xcassets/home/tab_1_selected.imageset/081_\346\210\221\347\232\204.png" differ diff --git "a/LingQi/LingQi/Assets.xcassets/home/tab_1_selected.imageset/081_\346\210\221\347\232\204@2x.png" "b/LingQi/LingQi/Assets.xcassets/home/tab_1_selected.imageset/081_\346\210\221\347\232\204@2x.png" new file mode 100644 index 0000000..e0e1bf2 Binary files /dev/null and "b/LingQi/LingQi/Assets.xcassets/home/tab_1_selected.imageset/081_\346\210\221\347\232\204@2x.png" differ diff --git "a/LingQi/LingQi/Assets.xcassets/home/tab_1_selected.imageset/081_\346\210\221\347\232\204@3x.png" "b/LingQi/LingQi/Assets.xcassets/home/tab_1_selected.imageset/081_\346\210\221\347\232\204@3x.png" new file mode 100644 index 0000000..85452de Binary files /dev/null and "b/LingQi/LingQi/Assets.xcassets/home/tab_1_selected.imageset/081_\346\210\221\347\232\204@3x.png" differ diff --git a/LingQi/LingQi/Assets.xcassets/home/tab_1_selected.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/home/tab_1_selected.imageset/Contents.json new file mode 100644 index 0000000..71388ea --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/home/tab_1_selected.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "081_我的.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "081_我的@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "081_我的@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git "a/LingQi/LingQi/Assets.xcassets/home/\347\251\272\345\206\205\345\256\271.imageset/Contents.json" "b/LingQi/LingQi/Assets.xcassets/home/\347\251\272\345\206\205\345\256\271.imageset/Contents.json" new file mode 100644 index 0000000..493fb1a --- /dev/null +++ "b/LingQi/LingQi/Assets.xcassets/home/\347\251\272\345\206\205\345\256\271.imageset/Contents.json" @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "空内容.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "空内容@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "空内容@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git "a/LingQi/LingQi/Assets.xcassets/home/\347\251\272\345\206\205\345\256\271.imageset/\347\251\272\345\206\205\345\256\271.png" "b/LingQi/LingQi/Assets.xcassets/home/\347\251\272\345\206\205\345\256\271.imageset/\347\251\272\345\206\205\345\256\271.png" new file mode 100644 index 0000000..b13789a Binary files /dev/null and "b/LingQi/LingQi/Assets.xcassets/home/\347\251\272\345\206\205\345\256\271.imageset/\347\251\272\345\206\205\345\256\271.png" differ diff --git "a/LingQi/LingQi/Assets.xcassets/home/\347\251\272\345\206\205\345\256\271.imageset/\347\251\272\345\206\205\345\256\271@2x.png" "b/LingQi/LingQi/Assets.xcassets/home/\347\251\272\345\206\205\345\256\271.imageset/\347\251\272\345\206\205\345\256\271@2x.png" new file mode 100644 index 0000000..8f4f0f6 Binary files /dev/null and "b/LingQi/LingQi/Assets.xcassets/home/\347\251\272\345\206\205\345\256\271.imageset/\347\251\272\345\206\205\345\256\271@2x.png" differ diff --git "a/LingQi/LingQi/Assets.xcassets/home/\347\251\272\345\206\205\345\256\271.imageset/\347\251\272\345\206\205\345\256\271@3x.png" "b/LingQi/LingQi/Assets.xcassets/home/\347\251\272\345\206\205\345\256\271.imageset/\347\251\272\345\206\205\345\256\271@3x.png" new file mode 100644 index 0000000..cd8f7f2 Binary files /dev/null and "b/LingQi/LingQi/Assets.xcassets/home/\347\251\272\345\206\205\345\256\271.imageset/\347\251\272\345\206\205\345\256\271@3x.png" differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/Contents.json b/LingQi/LingQi/Assets.xcassets/mine/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/mine/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/mine/Frame 1453.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/mine/Frame 1453.imageset/Contents.json new file mode 100644 index 0000000..9af40ec --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/mine/Frame 1453.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Frame 1453.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame 1453@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame 1453@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/mine/Frame 1453.imageset/Frame 1453.png b/LingQi/LingQi/Assets.xcassets/mine/Frame 1453.imageset/Frame 1453.png new file mode 100644 index 0000000..54d0f5a Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/Frame 1453.imageset/Frame 1453.png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/Frame 1453.imageset/Frame 1453@2x.png b/LingQi/LingQi/Assets.xcassets/mine/Frame 1453.imageset/Frame 1453@2x.png new file mode 100644 index 0000000..04589db Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/Frame 1453.imageset/Frame 1453@2x.png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/Frame 1453.imageset/Frame 1453@3x.png b/LingQi/LingQi/Assets.xcassets/mine/Frame 1453.imageset/Frame 1453@3x.png new file mode 100644 index 0000000..73e423e Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/Frame 1453.imageset/Frame 1453@3x.png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/Frame(1).imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/mine/Frame(1).imageset/Contents.json new file mode 100644 index 0000000..8eaecc5 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/mine/Frame(1).imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Frame(1).png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame@2x(1).png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame@3x(1).png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/mine/Frame(1).imageset/Frame(1).png b/LingQi/LingQi/Assets.xcassets/mine/Frame(1).imageset/Frame(1).png new file mode 100644 index 0000000..587dfb9 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/Frame(1).imageset/Frame(1).png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/Frame(1).imageset/Frame@2x(1).png b/LingQi/LingQi/Assets.xcassets/mine/Frame(1).imageset/Frame@2x(1).png new file mode 100644 index 0000000..a62288b Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/Frame(1).imageset/Frame@2x(1).png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/Frame(1).imageset/Frame@3x(1).png b/LingQi/LingQi/Assets.xcassets/mine/Frame(1).imageset/Frame@3x(1).png new file mode 100644 index 0000000..7a8bb8e Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/Frame(1).imageset/Frame@3x(1).png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/Frame(2).imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/mine/Frame(2).imageset/Contents.json new file mode 100644 index 0000000..115ae44 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/mine/Frame(2).imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Frame(2).png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame@2x(2).png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame@3x(2).png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/mine/Frame(2).imageset/Frame(2).png b/LingQi/LingQi/Assets.xcassets/mine/Frame(2).imageset/Frame(2).png new file mode 100644 index 0000000..14c8b3f Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/Frame(2).imageset/Frame(2).png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/Frame(2).imageset/Frame@2x(2).png b/LingQi/LingQi/Assets.xcassets/mine/Frame(2).imageset/Frame@2x(2).png new file mode 100644 index 0000000..150ba1b Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/Frame(2).imageset/Frame@2x(2).png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/Frame(2).imageset/Frame@3x(2).png b/LingQi/LingQi/Assets.xcassets/mine/Frame(2).imageset/Frame@3x(2).png new file mode 100644 index 0000000..951c1ef Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/Frame(2).imageset/Frame@3x(2).png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/Rectangle 268.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/mine/Rectangle 268.imageset/Contents.json new file mode 100644 index 0000000..76beba5 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/mine/Rectangle 268.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Rectangle 268.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Rectangle 268@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Rectangle 268@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/mine/Rectangle 268.imageset/Rectangle 268.png b/LingQi/LingQi/Assets.xcassets/mine/Rectangle 268.imageset/Rectangle 268.png new file mode 100644 index 0000000..cbcd2bc Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/Rectangle 268.imageset/Rectangle 268.png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/Rectangle 268.imageset/Rectangle 268@2x.png b/LingQi/LingQi/Assets.xcassets/mine/Rectangle 268.imageset/Rectangle 268@2x.png new file mode 100644 index 0000000..0ce6ee7 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/Rectangle 268.imageset/Rectangle 268@2x.png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/Rectangle 268.imageset/Rectangle 268@3x.png b/LingQi/LingQi/Assets.xcassets/mine/Rectangle 268.imageset/Rectangle 268@3x.png new file mode 100644 index 0000000..cc6947c Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/Rectangle 268.imageset/Rectangle 268@3x.png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/Rectangle 273.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/mine/Rectangle 273.imageset/Contents.json new file mode 100644 index 0000000..51c7c57 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/mine/Rectangle 273.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Rectangle 273.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Rectangle 273@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Rectangle 273@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/mine/Rectangle 273.imageset/Rectangle 273.png b/LingQi/LingQi/Assets.xcassets/mine/Rectangle 273.imageset/Rectangle 273.png new file mode 100644 index 0000000..a45dcda Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/Rectangle 273.imageset/Rectangle 273.png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/Rectangle 273.imageset/Rectangle 273@2x.png b/LingQi/LingQi/Assets.xcassets/mine/Rectangle 273.imageset/Rectangle 273@2x.png new file mode 100644 index 0000000..7725c61 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/Rectangle 273.imageset/Rectangle 273@2x.png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/Rectangle 273.imageset/Rectangle 273@3x.png b/LingQi/LingQi/Assets.xcassets/mine/Rectangle 273.imageset/Rectangle 273@3x.png new file mode 100644 index 0000000..7207a57 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/Rectangle 273.imageset/Rectangle 273@3x.png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/arrow_back.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/mine/arrow_back.imageset/Contents.json new file mode 100644 index 0000000..a9337b9 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/mine/arrow_back.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_back.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/mine/arrow_back.imageset/ic_back.png b/LingQi/LingQi/Assets.xcassets/mine/arrow_back.imageset/ic_back.png new file mode 100644 index 0000000..0b3636f Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/arrow_back.imageset/ic_back.png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/arrow_next.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/mine/arrow_next.imageset/Contents.json new file mode 100644 index 0000000..4886886 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/mine/arrow_next.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "个人中心-进入 1.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "个人中心-进入 1@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "个人中心-进入 1@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git "a/LingQi/LingQi/Assets.xcassets/mine/arrow_next.imageset/\344\270\252\344\272\272\344\270\255\345\277\203-\350\277\233\345\205\245 1.png" "b/LingQi/LingQi/Assets.xcassets/mine/arrow_next.imageset/\344\270\252\344\272\272\344\270\255\345\277\203-\350\277\233\345\205\245 1.png" new file mode 100644 index 0000000..50688e6 Binary files /dev/null and "b/LingQi/LingQi/Assets.xcassets/mine/arrow_next.imageset/\344\270\252\344\272\272\344\270\255\345\277\203-\350\277\233\345\205\245 1.png" differ diff --git "a/LingQi/LingQi/Assets.xcassets/mine/arrow_next.imageset/\344\270\252\344\272\272\344\270\255\345\277\203-\350\277\233\345\205\245 1@2x.png" "b/LingQi/LingQi/Assets.xcassets/mine/arrow_next.imageset/\344\270\252\344\272\272\344\270\255\345\277\203-\350\277\233\345\205\245 1@2x.png" new file mode 100644 index 0000000..5f350c5 Binary files /dev/null and "b/LingQi/LingQi/Assets.xcassets/mine/arrow_next.imageset/\344\270\252\344\272\272\344\270\255\345\277\203-\350\277\233\345\205\245 1@2x.png" differ diff --git "a/LingQi/LingQi/Assets.xcassets/mine/arrow_next.imageset/\344\270\252\344\272\272\344\270\255\345\277\203-\350\277\233\345\205\245 1@3x.png" "b/LingQi/LingQi/Assets.xcassets/mine/arrow_next.imageset/\344\270\252\344\272\272\344\270\255\345\277\203-\350\277\233\345\205\245 1@3x.png" new file mode 100644 index 0000000..f3b7a15 Binary files /dev/null and "b/LingQi/LingQi/Assets.xcassets/mine/arrow_next.imageset/\344\270\252\344\272\272\344\270\255\345\277\203-\350\277\233\345\205\245 1@3x.png" differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/image 57.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/mine/image 57.imageset/Contents.json new file mode 100644 index 0000000..a53d3e9 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/mine/image 57.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "image 57.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "image 57@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "image 57@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/mine/image 57.imageset/image 57.png b/LingQi/LingQi/Assets.xcassets/mine/image 57.imageset/image 57.png new file mode 100644 index 0000000..45c8988 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/image 57.imageset/image 57.png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/image 57.imageset/image 57@2x.png b/LingQi/LingQi/Assets.xcassets/mine/image 57.imageset/image 57@2x.png new file mode 100644 index 0000000..8716500 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/image 57.imageset/image 57@2x.png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/image 57.imageset/image 57@3x.png b/LingQi/LingQi/Assets.xcassets/mine/image 57.imageset/image 57@3x.png new file mode 100644 index 0000000..c8f8d21 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/image 57.imageset/image 57@3x.png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/login_cover.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/mine/login_cover.imageset/Contents.json new file mode 100644 index 0000000..944c2cb --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/mine/login_cover.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Frame 134.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame 134@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame 134@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/mine/login_cover.imageset/Frame 134.png b/LingQi/LingQi/Assets.xcassets/mine/login_cover.imageset/Frame 134.png new file mode 100644 index 0000000..7dc5484 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/login_cover.imageset/Frame 134.png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/login_cover.imageset/Frame 134@2x.png b/LingQi/LingQi/Assets.xcassets/mine/login_cover.imageset/Frame 134@2x.png new file mode 100644 index 0000000..b81b861 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/login_cover.imageset/Frame 134@2x.png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/login_cover.imageset/Frame 134@3x.png b/LingQi/LingQi/Assets.xcassets/mine/login_cover.imageset/Frame 134@3x.png new file mode 100644 index 0000000..32e6c2d Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/login_cover.imageset/Frame 134@3x.png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/login_logo.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/mine/login_logo.imageset/Contents.json new file mode 100644 index 0000000..4895580 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/mine/login_logo.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Group 281.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Group 281@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Group 281@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/mine/login_logo.imageset/Group 281.png b/LingQi/LingQi/Assets.xcassets/mine/login_logo.imageset/Group 281.png new file mode 100644 index 0000000..ec96160 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/login_logo.imageset/Group 281.png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/login_logo.imageset/Group 281@2x.png b/LingQi/LingQi/Assets.xcassets/mine/login_logo.imageset/Group 281@2x.png new file mode 100644 index 0000000..3307d6d Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/login_logo.imageset/Group 281@2x.png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/login_logo.imageset/Group 281@3x.png b/LingQi/LingQi/Assets.xcassets/mine/login_logo.imageset/Group 281@3x.png new file mode 100644 index 0000000..5802893 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/login_logo.imageset/Group 281@3x.png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/mine_cell_device.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/mine/mine_cell_device.imageset/Contents.json new file mode 100644 index 0000000..4b7bf60 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/mine/mine_cell_device.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Frame.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/mine/mine_cell_device.imageset/Frame.png b/LingQi/LingQi/Assets.xcassets/mine/mine_cell_device.imageset/Frame.png new file mode 100644 index 0000000..1209ddb Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/mine_cell_device.imageset/Frame.png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/mine_cell_device.imageset/Frame@2x.png b/LingQi/LingQi/Assets.xcassets/mine/mine_cell_device.imageset/Frame@2x.png new file mode 100644 index 0000000..4ea8812 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/mine_cell_device.imageset/Frame@2x.png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/mine_cell_device.imageset/Frame@3x.png b/LingQi/LingQi/Assets.xcassets/mine/mine_cell_device.imageset/Frame@3x.png new file mode 100644 index 0000000..4bb8033 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/mine_cell_device.imageset/Frame@3x.png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/mine_cell_product.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/mine/mine_cell_product.imageset/Contents.json new file mode 100644 index 0000000..00090de --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/mine/mine_cell_product.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "信息.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "信息@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "信息@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git "a/LingQi/LingQi/Assets.xcassets/mine/mine_cell_product.imageset/\344\277\241\346\201\257.png" "b/LingQi/LingQi/Assets.xcassets/mine/mine_cell_product.imageset/\344\277\241\346\201\257.png" new file mode 100644 index 0000000..74a03e5 Binary files /dev/null and "b/LingQi/LingQi/Assets.xcassets/mine/mine_cell_product.imageset/\344\277\241\346\201\257.png" differ diff --git "a/LingQi/LingQi/Assets.xcassets/mine/mine_cell_product.imageset/\344\277\241\346\201\257@2x.png" "b/LingQi/LingQi/Assets.xcassets/mine/mine_cell_product.imageset/\344\277\241\346\201\257@2x.png" new file mode 100644 index 0000000..0a4a56b Binary files /dev/null and "b/LingQi/LingQi/Assets.xcassets/mine/mine_cell_product.imageset/\344\277\241\346\201\257@2x.png" differ diff --git "a/LingQi/LingQi/Assets.xcassets/mine/mine_cell_product.imageset/\344\277\241\346\201\257@3x.png" "b/LingQi/LingQi/Assets.xcassets/mine/mine_cell_product.imageset/\344\277\241\346\201\257@3x.png" new file mode 100644 index 0000000..1d53b3f Binary files /dev/null and "b/LingQi/LingQi/Assets.xcassets/mine/mine_cell_product.imageset/\344\277\241\346\201\257@3x.png" differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/mine_cell_service.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/mine/mine_cell_service.imageset/Contents.json new file mode 100644 index 0000000..7f757d8 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/mine/mine_cell_service.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "转账.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "转账@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "转账@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git "a/LingQi/LingQi/Assets.xcassets/mine/mine_cell_service.imageset/\350\275\254\350\264\246.png" "b/LingQi/LingQi/Assets.xcassets/mine/mine_cell_service.imageset/\350\275\254\350\264\246.png" new file mode 100644 index 0000000..17994e7 Binary files /dev/null and "b/LingQi/LingQi/Assets.xcassets/mine/mine_cell_service.imageset/\350\275\254\350\264\246.png" differ diff --git "a/LingQi/LingQi/Assets.xcassets/mine/mine_cell_service.imageset/\350\275\254\350\264\246@2x.png" "b/LingQi/LingQi/Assets.xcassets/mine/mine_cell_service.imageset/\350\275\254\350\264\246@2x.png" new file mode 100644 index 0000000..1648cc3 Binary files /dev/null and "b/LingQi/LingQi/Assets.xcassets/mine/mine_cell_service.imageset/\350\275\254\350\264\246@2x.png" differ diff --git "a/LingQi/LingQi/Assets.xcassets/mine/mine_cell_service.imageset/\350\275\254\350\264\246@3x.png" "b/LingQi/LingQi/Assets.xcassets/mine/mine_cell_service.imageset/\350\275\254\350\264\246@3x.png" new file mode 100644 index 0000000..33f3b2a Binary files /dev/null and "b/LingQi/LingQi/Assets.xcassets/mine/mine_cell_service.imageset/\350\275\254\350\264\246@3x.png" differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/mine_msg.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/mine/mine_msg.imageset/Contents.json new file mode 100644 index 0000000..6866d51 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/mine/mine_msg.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_msg.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/mine/mine_msg.imageset/ic_msg.png b/LingQi/LingQi/Assets.xcassets/mine/mine_msg.imageset/ic_msg.png new file mode 100644 index 0000000..9e1680b Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/mine_msg.imageset/ic_msg.png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/mine_set.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/mine/mine_set.imageset/Contents.json new file mode 100644 index 0000000..35d6ec5 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/mine/mine_set.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_set.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/mine/mine_set.imageset/ic_set.png b/LingQi/LingQi/Assets.xcassets/mine/mine_set.imageset/ic_set.png new file mode 100644 index 0000000..6e75d39 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/mine_set.imageset/ic_set.png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/select_normal.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/mine/select_normal.imageset/Contents.json new file mode 100644 index 0000000..4b7bf60 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/mine/select_normal.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Frame.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/mine/select_normal.imageset/Frame.png b/LingQi/LingQi/Assets.xcassets/mine/select_normal.imageset/Frame.png new file mode 100644 index 0000000..b2c2400 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/select_normal.imageset/Frame.png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/select_normal.imageset/Frame@2x.png b/LingQi/LingQi/Assets.xcassets/mine/select_normal.imageset/Frame@2x.png new file mode 100644 index 0000000..b7cf13e Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/select_normal.imageset/Frame@2x.png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/select_normal.imageset/Frame@3x.png b/LingQi/LingQi/Assets.xcassets/mine/select_normal.imageset/Frame@3x.png new file mode 100644 index 0000000..0f593d5 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/select_normal.imageset/Frame@3x.png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/select_selected.imageset/Contents.json b/LingQi/LingQi/Assets.xcassets/mine/select_selected.imageset/Contents.json new file mode 100644 index 0000000..e30ad51 --- /dev/null +++ b/LingQi/LingQi/Assets.xcassets/mine/select_selected.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Group 334.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Group 334@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Group 334@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LingQi/LingQi/Assets.xcassets/mine/select_selected.imageset/Group 334.png b/LingQi/LingQi/Assets.xcassets/mine/select_selected.imageset/Group 334.png new file mode 100644 index 0000000..68db34e Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/select_selected.imageset/Group 334.png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/select_selected.imageset/Group 334@2x.png b/LingQi/LingQi/Assets.xcassets/mine/select_selected.imageset/Group 334@2x.png new file mode 100644 index 0000000..ec52a67 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/select_selected.imageset/Group 334@2x.png differ diff --git a/LingQi/LingQi/Assets.xcassets/mine/select_selected.imageset/Group 334@3x.png b/LingQi/LingQi/Assets.xcassets/mine/select_selected.imageset/Group 334@3x.png new file mode 100644 index 0000000..05c0fb7 Binary files /dev/null and b/LingQi/LingQi/Assets.xcassets/mine/select_selected.imageset/Group 334@3x.png differ diff --git a/LingQi/LingQi/Base.lproj/LaunchScreen.storyboard b/LingQi/LingQi/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..865e932 --- /dev/null +++ b/LingQi/LingQi/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LingQi/LingQi/Base.lproj/Main.storyboard b/LingQi/LingQi/Base.lproj/Main.storyboard new file mode 100644 index 0000000..25a7638 --- /dev/null +++ b/LingQi/LingQi/Base.lproj/Main.storyboard @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LingQi/LingQi/Ble/BlueToothManager.swift b/LingQi/LingQi/Ble/BlueToothManager.swift new file mode 100644 index 0000000..d99bd5f --- /dev/null +++ b/LingQi/LingQi/Ble/BlueToothManager.swift @@ -0,0 +1,164 @@ +// +// BlueToothManager.swift +// BlueToothDemo +// +// Created by lianzi on 2022/10/9. +// + +import CoreBluetooth + +class BlueToothManager:NSObject{ + /// 状态改变 + var didUpdateStateBlock:((_ central: CBCentralManager) ->Void)? + + /// 扫描到设备 + var discoverDeviceBlock:((CBPeripheral,[String : Any],NSNumber) ->Void)? + /// 连接设备成功 + var didConnectBlock:((CBPeripheral) ->Void)? + /// 连接设备失败 + var FailConnectBlock:((CBPeripheral) ->Void)? + /// 设备断开连接 + var disConnectBlock:((CBPeripheral) ->Void)? + + /// 发现服务 + var discoverServiceBlock:(([CBService]) ->Void)? + /// 发现特征 + var discoverPeripheralBlock:(([CBCharacteristic]) ->Void)? + + /// 读取到数据 + var receiveDataBlock:((CBPeripheral,CBCharacteristic) ->Void)? + /// 写入数据(发送指令)成功 + var didWriteDataBlock:((CBPeripheral,CBCharacteristic,Error?) ->Void)? + /// 读取信息成功 + var didReadRSSIBlock:((CBPeripheral,NSNumber) ->Void)? + + + /// 中央管理类,管理蓝牙的扫描连接 + lazy var centralManager :CBCentralManager = { + let manager = CBCentralManager(delegate: self, queue: nil) + return manager + }() + + override init() { + super.init() + _ = centralManager.isScanning + } + + /// 开始扫描 + func startScan(){ + // withServices nil代表可以扫描任何的设备 + //CBCentralManagerScanOptionAllowDuplicatesKey是允许重复扫描到 + centralManager.scanForPeripherals(withServices: nil, options: [CBCentralManagerScanOptionAllowDuplicatesKey:true]) + } + + /// 停止扫描 + func stopScan(){ + centralManager.stopScan() + } + + /// 连接外设 + /// - Parameter peripheral: 外设 + func connect(peripheral:CBPeripheral){ + centralManager.connect(peripheral) + } + + /// 取消连接外设 + /// - Parameter peripheral: 外设 + func cancelConnect(peripheral:CBPeripheral){ + centralManager.cancelPeripheralConnection(peripheral) + } + + /// 发送数据 + /// - Parameters: + /// - peripheral: 外设 + /// - characteristic: 特征 + /// - data: 数据 + func sendTo(peripheral:CBPeripheral, characteristic:CBCharacteristic, data:Data){ + peripheral.writeValue(data, for: characteristic, type: .withoutResponse) + } +} + +extension BlueToothManager:CBCentralManagerDelegate{ + /// 手机蓝牙状态更新 + /// - Parameter central: 中央管理类 + func centralManagerDidUpdateState(_ central: CBCentralManager) { + didUpdateStateBlock?(central) + switch central.state{ + case .unknown: + print("unknown") + case .resetting: + print("resetting") + case .unsupported: + print("unsupported") + case .unauthorized: + print("unauthorized") + case .poweredOff: + print("poweredOff") + case .poweredOn: + print("poweredOn") + startScan() + @unknown default: + break + } + } + /// 发现设备 + func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) { + discoverDeviceBlock?(peripheral,advertisementData,RSSI) + } + + /// 连接上设备 + func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { + peripheral.delegate = self + peripheral.discoverServices(nil) + didConnectBlock?(peripheral) + } + /// 连接失败 + func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) { + FailConnectBlock?(peripheral) + } + /// 断开连接 + func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) { + disConnectBlock?(peripheral) + } +} + +extension BlueToothManager:CBPeripheralDelegate{ + /// 读取到信号 + func peripheral(_ peripheral: CBPeripheral, didReadRSSI RSSI: NSNumber, error: Error?) { + didReadRSSIBlock?(peripheral,RSSI) + } + /// 发现服务 + func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) { + if error == nil,let list = peripheral.services { + for s in list { + peripheral.discoverCharacteristics(nil, for: s) + } + discoverServiceBlock?(list) + } + else{ + peripheral.discoverServices(nil) + } + } + /// 发现服务找那个的特征,然后遍历所有特征订阅 + func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) { + if error == nil,let list = service.characteristics { +// for s in list { +// peripheral.setNotifyValue(true, for: s) +// } + discoverPeripheralBlock?(list) + } + } + /// 特征状态发生变化通知 + func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) { + //读取特征的值 + peripheral.readValue(for: characteristic) + } + /// 特征发生变化 + func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) { + receiveDataBlock?(peripheral,characteristic) + } + /// 写入完成(发送指令完成) + func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) { + didWriteDataBlock?(peripheral,characteristic,error) + } +} diff --git a/LingQi/LingQi/Ble/BlueToothViewModel.swift b/LingQi/LingQi/Ble/BlueToothViewModel.swift new file mode 100644 index 0000000..01eec82 --- /dev/null +++ b/LingQi/LingQi/Ble/BlueToothViewModel.swift @@ -0,0 +1,166 @@ +// +// BlueToothViewModel.swift +// BlueToothDemo +// +// Created by lianzi on 2022/10/9. +// + +import CoreBluetooth +import UIKit + +class BlueToothViewModel:NSObject{ + static let shareModel = BlueToothViewModel() + + let bluetooth = BlueToothManager()//蓝牙管理类 + var deviceList = [ScanModel]()//设备列表 + + var selectedPeripheral:CBPeripheral?//连接上的设备 + var readCha:CBCharacteristic?//读特征 + var writeCha:CBCharacteristic?//写特征 + + + var deviceListDidChange:(()->Void)?//扫描列表设备改变 + + override init() { + super.init() + setupBluetooth() + setupData() + } + +} + +extension BlueToothViewModel{ + + func setupData(){ + } + func reset(){ + deviceList = [ScanModel]()//设备列表 + selectedPeripheral = nil + } +} + +extension BlueToothViewModel{ + func setupBluetooth(){ + //状态改变 + bluetooth.didUpdateStateBlock = {[weak self](centrl) in + self?.didUpdateStats(centrl.state) + } + // 扫描到设备 + bluetooth.discoverDeviceBlock = discoverDevice(peripheral:data:rssi:) + // 连接设备成功 + bluetooth.didConnectBlock = {[weak self] (device) in + LogManager.instance.add("已连接") + self?.selectedPeripheral = device +// self?.didConnect?(device) + + } + // 连接设备失败 + bluetooth.FailConnectBlock = { (device) in + LogManager.instance.add("连接失败") + } + // 设备断开连接 + bluetooth.disConnectBlock = {[weak self](device) in + LogManager.instance.add("断开连接") +// SVProgressHUD.showAutoHiden("disconnect") +// self?.retryConnect() + } + // 发现服务 + bluetooth.discoverServiceBlock = { (services) in + LogManager.instance.add("发现服务 \(services)") + } + // 发现特征 + bluetooth.discoverPeripheralBlock = {[weak self] (characteristics) in + guard let self = self else {return} + LogManager.instance.add("发现特征 \(characteristics)") + for cha in characteristics{ + if cha.uuid.uuidString == "FED7" { + self.writeCha = cha + self.sendGetDetail() + } + if cha.uuid.uuidString == "FED8" { + self.readCha = cha + self.selectedPeripheral?.setNotifyValue(true, for: cha) + } + } + } + // 读取到数据 + bluetooth.receiveDataBlock = {[weak self] (peripheral,characteristic) in +// print("接收到数据",characteristic) +// print(characteristic.uuid.uuidString," === ",characteristic.value ?? "") + if let data = characteristic.value{ + self?.receiveData(data) + } + } + // 写入数据(发送指令)成功 + bluetooth.didWriteDataBlock = { (peripheral,characteristic,error) in + LogManager.instance.add("发送指令,错误 = \(error)"); + } + } + func discoverDevice(peripheral:CBPeripheral, data:[String : Any],rssi: NSNumber){ + guard let name = peripheral.name else{ + return + } + if name.isEmpty { + return + } +// if !name.hasPrefix("BlueNRG") { +// return +// } + + var isContain = false + for device in deviceList{ + if device.peripheral.identifier.uuidString == peripheral.identifier.uuidString { +// print("peripheral 的uuid===",device.peripheral.identifier.uuidString) + isContain = true + break + } + } + if !isContain{ + let model = ScanModel() + model.peripheral = peripheral + model.rssi = rssi + deviceList.append(model) + deviceListDidChange?() + print(name,data) + } + } + func didUpdateStats(_ states:CBManagerState){ + switch states{ + case .poweredOn: + LogManager.instance.add("poweredOn") + @unknown default: + break + } + } +} + +extension BlueToothViewModel{ + func sendGetDetail(){ + let data = SendManager.getDetail() + sendToDevice(data) + } + func sendStopDetail(){ + let data = SendManager.getDetail() + sendToDevice(data) + } + + func sendToDevice(_ data:Data){ + LogManager.instance.add("[send] = \(data.hexEncodedString())") + guard let p = selectedPeripheral,let c = writeCha else{ + LogManager.instance.add("请先连接设备!!! ") + return + } + bluetooth.sendTo(peripheral:p , characteristic: c, data: data) + } +} + +extension BlueToothViewModel{ + func receiveData(_ data:Data){ + LogManager.instance.add("[recevice] = \(data.hexEncodedString())") + + } + +} + + + diff --git a/LingQi/LingQi/Ble/ReceiveManager.swift b/LingQi/LingQi/Ble/ReceiveManager.swift new file mode 100644 index 0000000..f573650 --- /dev/null +++ b/LingQi/LingQi/Ble/ReceiveManager.swift @@ -0,0 +1,8 @@ +// +// ReceiveManager.swift +// Magpie +// +// Created by incar on 2024/1/3. +// + +import Foundation diff --git a/LingQi/LingQi/Ble/ScanModel.swift b/LingQi/LingQi/Ble/ScanModel.swift new file mode 100644 index 0000000..d34d678 --- /dev/null +++ b/LingQi/LingQi/Ble/ScanModel.swift @@ -0,0 +1,14 @@ +// +// ScanModel.swift +// Magpie +// +// Created by incar on 2024/1/3. +// + +import Foundation +import CoreBluetooth +/// 扫描的model +class ScanModel{ + var peripheral:CBPeripheral! + var rssi:NSNumber! +} diff --git a/LingQi/LingQi/Ble/SendManager.swift b/LingQi/LingQi/Ble/SendManager.swift new file mode 100644 index 0000000..f5635d1 --- /dev/null +++ b/LingQi/LingQi/Ble/SendManager.swift @@ -0,0 +1,75 @@ +// +// SendManager.swift +// Magpie +// +// Created by incar on 2024/1/3. +// + +import Foundation +class SendManager { + static func getDetail() ->Data{ + var bytes = [UInt8](repeating: 0x00, count: 8) + bytes[0] = 0xFD + bytes[1] = 0x35 + bytes[2] = 0x09 + bytes[3] = 0x00 + bytes[4] = 0x00 + bytes[5] = 0x00 + bytes[6] = 0x00 + bytes[7] = 0x00 + let data = SendManager.byteToData(arr: bytes) + return data + } + static func stopDetail() ->Data{ + var bytes = [UInt8](repeating: 0x00, count: 4) + bytes[0] = 0xFD + bytes[1] = 0x36 + bytes[2] = 0x05 + bytes[3] = 0x00 + let data = SendManager.byteToData(arr: bytes) + return data + } +} + +extension SendManager{ + public static func byteToData(arr:[UInt8]) -> Data{ + let bytes = SendManager.appendXmodem(arr: arr) + let data = Data(bytes: bytes, count: bytes.count) + return data + } + + public static func appendXmodem(arr:[UInt8]) -> [UInt8]{ + var crc = CRC16.xmodem(arr: arr) + var list:[UInt8] = [UInt8](repeating: 0x00, count: arr.count + 2) + for i in 0.. Int { + var wCRCin = 0x0000; + let wCPoly = 0x1021; + let len = arr.count; + for i in 0...len-1 { + for j in 0...7 { + let bit = ((arr[i] >> (7 - j) & 1) == 1); + let c15 = ((wCRCin >> 15 & 1) == 1); + wCRCin <<= 1; + if(c15 != bit) { + wCRCin ^= wCPoly; + } + } + } + wCRCin &= 0xFFFF; + wCRCin ^= 0x0000; + return wCRCin + } +} diff --git a/LingQi/LingQi/Info.plist b/LingQi/LingQi/Info.plist new file mode 100644 index 0000000..f88d044 --- /dev/null +++ b/LingQi/LingQi/Info.plist @@ -0,0 +1,29 @@ + + + + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + NSPhotoLibraryUsageDescription + 修改用户头像、提交意见反馈需要访问相册 + NSCameraUsageDescription + 修改用户头像、提交意见反馈需要访问相册使用摄像头 + + diff --git a/LingQi/LingQi/LingQi-Bridging-Header.h b/LingQi/LingQi/LingQi-Bridging-Header.h new file mode 100644 index 0000000..58d97ae --- /dev/null +++ b/LingQi/LingQi/LingQi-Bridging-Header.h @@ -0,0 +1,9 @@ +// +// Magpie-Bridging-Header.h +// LingQi +// +// Created by liangshi on 2025/7/30. +// + +//#import "SVProgressHUD+YLAdd.h" +#import "YLTimerButton.h" diff --git a/LingQi/LingQi/MixApi/MixApi.swift b/LingQi/LingQi/MixApi/MixApi.swift new file mode 100644 index 0000000..177778b --- /dev/null +++ b/LingQi/LingQi/MixApi/MixApi.swift @@ -0,0 +1,69 @@ +// +// MixApi.swift +// Magpie +// +// Created by incar on 2024/1/6. +// + +import Foundation +import CoreBluetooth + +public class MixDevice{ + + /// 设备 + var peripheral: CBPeripheral! + + /// 广播信息 + var advertisementData: [String : AnyObject]? + + /// 信号 + var RSSI: Int32? +} + +public protocol MixApi { + + /// 单利 + static var manager: MixApi { get } + + /// 发现设备 + var discoverDevice:((_ devices:[MixDevice]) -> Void)? { get } + + /// 收到sdk传数过来的数据,具体请阅读每条指令参数说明 + var receiveData:((_ data:Any) -> Void)? { get } + + /// 扫描 + /// - Parameters: + /// - uuid: 指定设备 + /// - duration: 超时 + func scanWithServices(_ uuid: [String]?, duration: TimeInterval) + + /// 停止扫描 + func stopScan() + + /// 连接设备 + /// - Parameters: + /// - device: 扫描到的涉笔 + /// - duration: 超时时间 + /// - success: 连接成功 + /// - fail: 连接失败 + func connect(device : MixDevice, duration: TimeInterval, success: @escaping (() -> Void), fail: @escaping ((_ error:[String:Any]) -> Void)) + + /// 连接设备 + /// - Parameters: + /// - identifier: 设备标识符 + /// - duration: 超时时间 + /// - success: 连接成功 + /// - fail: 连接失败 + func connect(identifier : String, duration: TimeInterval, success: @escaping (() -> Void), fail: @escaping ((_ error:[String:Any]) -> Void)) + + + /// 取消当前连接 + func cancelConnect() + + /// 发送指令 + /// - Parameters: + /// - parameters: 无参传nil,具体key-value请阅读每条指令参数说明 + /// - success: 发送成功 + /// - failure: 发送失败 + func sendCommand(parameters: [String : Any]?, success:@escaping (() -> Void), failure:@escaping ((_ error:[String:Any]) -> Void)) +} diff --git a/LingQi/LingQi/Resource/colors/Colors+YL.swift b/LingQi/LingQi/Resource/colors/Colors+YL.swift new file mode 100644 index 0000000..0c12722 --- /dev/null +++ b/LingQi/LingQi/Resource/colors/Colors+YL.swift @@ -0,0 +1,51 @@ +// +// Colors+YL.swift +// zgjd +// +// Created by apple on 2020/11/12. +// + +import UIKit + +public enum YLColor { + /// + case bgColor + /// 主题色 + case theme + /// 次级主题色 + case subTheme + /// 主标题 - 0x222222 + case first + /// 主标题 - 0x333333 + case primary + /// 二级标题 - 0x666666 + case secondary + /// 三级标题 - 0x999999 + case tertiary + + case separateLine +} + +extension YLColor: ColorRGBProviderProtocol { + public var rgbValue: Int { + switch self { + case .bgColor: + return 0x11131E + case .theme: + return 0x286DE8 + case .subTheme: + return 0xF4FAFF + case .first: + return 0x222222 + case .primary: + return 0x333333 + case .secondary: + return 0x666666 + case .tertiary: + return 0x999999 + case .separateLine: + return 0xffffff + } + } +} + diff --git a/LingQi/LingQi/Resource/colors/Colors.swift b/LingQi/LingQi/Resource/colors/Colors.swift new file mode 100644 index 0000000..b5d5018 --- /dev/null +++ b/LingQi/LingQi/Resource/colors/Colors.swift @@ -0,0 +1,43 @@ +// +// Colors.swift +// zgjd +// +// Created by apple on 2020/11/9. +// + +import UIKit + +public extension UIColor { + static func color(_ color: YLColor, _ alpha: CGFloat = 1) -> UIColor { + return UIColor.rgb(color.rgbValue, alpha) + } +} + +public protocol ColorRGBProviderProtocol { + var rgbValue: Int { get } +} + +public func kColor(_ RGB: Int, _ alpha: CGFloat = 1) -> UIColor { + return UIColor.rgb(RGB, alpha) +} + +public extension UIColor { + static func rgb(_ RGB: Int, _ alpha: CGFloat = 1) -> UIColor { + assert(0...0xFFFFFF ~= RGB, "The color hex value must between 0 to 0xFFFFFF.") + + let red = Float(((RGB & 0xFF0000) >> 16)) / 255.0 + let green = Float(((RGB & 0x00FF00) >> 8)) / 255.0 + let blue = Float(RGB & 0x0000FF) / 255.0 + return UIColor.init(red: CGFloat(red), green: CGFloat(green), blue: CGFloat(blue), alpha: alpha) + } + + var half: UIColor { + var red: CGFloat = 0 + var green: CGFloat = 0 + var blue: CGFloat = 0 + var alpha: CGFloat = 0 + getRed(&red, green: &green, blue: &blue, alpha: &alpha) + return UIColor(red: red, green: green, blue: blue, alpha: alpha * 0.5) + } +} + diff --git a/LingQi/LingQi/Resource/fonts/UIFont+ZKYS.swift b/LingQi/LingQi/Resource/fonts/UIFont+ZKYS.swift new file mode 100644 index 0000000..7374edd --- /dev/null +++ b/LingQi/LingQi/Resource/fonts/UIFont+ZKYS.swift @@ -0,0 +1,43 @@ +// +// UIFont+ZKYS.swift +// zgjd +// +// Created by apple on 2020/11/9. +// + +import UIKit + +// MARK: - ****** 字体相关 ****** +/* + ====== FamilyName : PingFang SC ====== + === 1. PingFangSC-Medium + === 2. PingFangSC-Semibold + === 3. PingFangSC-Light + === 4. PingFangSC-Ultralight + === 5. PingFangSC-Regular + === 6. PingFangSC-Thin + */ +public extension UIFont { + + static func light(_ size: CGFloat, isFit: Bool = true) -> UIFont { + return UIFont.systemFont(ofSize: size.fit(isFit), weight: .light) + } + static func regular(_ size: CGFloat, isFit: Bool = true) -> UIFont { + return UIFont.systemFont(ofSize: size.fit(isFit), weight: .regular) + } + static func medium(_ size: CGFloat, isFit: Bool = true) -> UIFont { + return UIFont.systemFont(ofSize: size.fit(isFit), weight: .medium) + } + static func semiBold(_ size: CGFloat, isFit: Bool = true) -> UIFont { + return UIFont.systemFont(ofSize: size.fit(isFit), weight: .semibold) + } + static func bold(_ size: CGFloat, isFit: Bool = true) -> UIFont { + return UIFont.systemFont(ofSize: size.fit(isFit), weight: .bold) + } +} + +extension CGFloat { + fileprivate func fit(_ isFit: Bool) -> CGFloat { + return isFit ? self.fitR : self + } +} diff --git a/LingQi/LingQi/SceneDelegate.swift b/LingQi/LingQi/SceneDelegate.swift new file mode 100644 index 0000000..c25595f --- /dev/null +++ b/LingQi/LingQi/SceneDelegate.swift @@ -0,0 +1,89 @@ +// +// SceneDelegate.swift +// LingQi +// +// Created by liangshi on 2025/7/29. +// + +import UIKit +import IQKeyboardManagerSwift +class SceneDelegate: UIResponder, UIWindowSceneDelegate { + + var window: UIWindow? + + + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. + // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. + // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). + guard let _ = (scene as? UIWindowScene) else { return } + + App.shared.window = window + setConfig() + +// window?.rootViewController = LoginVC() + window?.rootViewController = BaseTC() + + } + + func sceneDidDisconnect(_ scene: UIScene) { + // Called as the scene is being released by the system. + // This occurs shortly after the scene enters the background, or when its session is discarded. + // Release any resources associated with this scene that can be re-created the next time the scene connects. + // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). + } + + func sceneDidBecomeActive(_ scene: UIScene) { + // Called when the scene has moved from an inactive state to an active state. + // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. + } + + func sceneWillResignActive(_ scene: UIScene) { + // Called when the scene will move from an active state to an inactive state. + // This may occur due to temporary interruptions (ex. an incoming phone call). + } + + func sceneWillEnterForeground(_ scene: UIScene) { + // Called as the scene transitions from the background to the foreground. + // Use this method to undo the changes made on entering the background. + } + + func sceneDidEnterBackground(_ scene: UIScene) { + // Called as the scene transitions from the foreground to the background. + // Use this method to save data, release shared resources, and store enough scene-specific state information + // to restore the scene back to its current state. + } + + func setConfig(){ + if #available(iOS 15.0, *) { + UITableView.appearance().sectionHeaderTopPadding = 0 + } + IQKeyboardManager.shared.enableAutoToolbar = true + IQKeyboardManager.shared.isEnabled = true + IQKeyboardManager.shared.resignOnTouchOutside = true + } +} + +class App{ + static let shared = App() + var window:UIWindow? + func topVC()->UIViewController!{ + guard let vc = window?.rootViewController else{ + print("页面异常!!!") + return UIViewController() + } + return getTopViewController(from: vc) + } + + private func getTopViewController(from vc: UIViewController) -> UIViewController { + if let navVC = vc as? UINavigationController { + return getTopViewController(from: navVC.visibleViewController ?? navVC) + } else if let tabVC = vc as? UITabBarController { + return getTopViewController(from: tabVC.selectedViewController ?? tabVC) + } else if let presentedVC = vc.presentedViewController { + return getTopViewController(from: presentedVC) + } else { + return vc + } + } +} diff --git a/LingQi/LingQi/Tools/BaseSizeMacro.swift b/LingQi/LingQi/Tools/BaseSizeMacro.swift new file mode 100644 index 0000000..f64dd2a --- /dev/null +++ b/LingQi/LingQi/Tools/BaseSizeMacro.swift @@ -0,0 +1,146 @@ +// +// BaseSizeMacro.swift +// zgjd +// +// Created by apple on 2020/11/9. +// + +import UIKit + +// MARK: - ********* Device Size +public var kScreenWid: CGFloat { return UIScreen.main.bounds.size.width } + +public var kScreenHei: CGFloat { return UIScreen.main.bounds.size.height } + +public var kIsX: Bool { return ScreenSize.shared.isIphonex } + +public var kNavBtm: CGFloat { return kNavTop + 44 } +public var kCusNavBtm: CGFloat { + if kIsX { + return 88.fitR + } + return 64.fitR +} +public var kNavTop: CGFloat { + if kIsX { return 44 } + return 20 +} + + +public var kHairHei: CGFloat { + if kIsX { return 30 } + return 0 +} + +public var kSafeBtm: CGFloat { + if kIsX { return 34 } + return 0 +} + +public var kSafeBottom: CGFloat { + if kIsX { return 20 } + return 0 +} + +public var kTabbarHei: CGFloat { + if kIsX { return 34 + 49 } + return 49 +} + + +// MARK: - ********* Public Quick Funcs +let kPageSize = "10" + +typealias VoidClosure = (() -> Void) +/// printf +public func k_log(_ item: T, + file: String = #file, + line: Int = #line, + function: String = #function) { + #if DEBUG + print("================== debug log ==================") + print("time: \(currentTime)") + print("file: \((file as NSString).lastPathComponent) \t line: \(line) \t func: \(function)") + print("log: \(item)\n") + #endif +} + +fileprivate var currentTime: String { + let timeStr = "\(Date().addingTimeInterval(8 * 60 * 60))" + return String(timeStr.prefix(20)) +} + +public func k_logViewControllerDeinit(_ vc: UIViewController) { + #if DEBUG + guard let viewDesc = "\(vc.self)".split(separator: ".").last + else { return } + print("Deinit: ---> ViewController:\t\(String(viewDesc))") + #endif +} + +public func k_logViewDeinit(_ view: UIView) { + #if DEBUG + guard let desc = "\(view.self)".split(separator: ";").first, + let viewDesc = String(desc).split(separator: ".").last + else { return } + print("Deinit: ---> View:\t\t\t\(String(viewDesc))") + #endif +} + +public func k_logViewModelDeinit(_ vm: AnyObject) { + #if DEBUG + guard let vmDesc = "\(vm.self)".split(separator: ".").last + else { return } + print("Deinit: ---> ViewModel:\t\t\(String(vmDesc))") + #endif +} + +/// 获取对象的地址 +public func kObjectAddress(_ obj: NSObject) -> String { + return String.init(format: "%p", obj) +} + +/// 主线程 延时 +public func kDelay(_ delay: Double, onQueue queue: DispatchQueue = DispatchQueue.main, closure: @escaping () -> Void) { + queue.asyncAfter(deadline: .now() + delay, execute: closure) +} + +public extension DispatchQueue { + // This method will dispatch the `block` to self. + // If `self` is the main queue, and current thread is main thread, the block + // will be invoked immediately instead of being dispatched. + func safeAsync(_ block: @escaping () -> Void) { + if self === DispatchQueue.main && Thread.isMainThread { + block() + } else { + async { block() } + } + } +} + +//final class ScreenSize { +// +// static let shared = ScreenSize() +// init() { +// p_refreshData() +// } +// +// private(set) var screenWidthRatio: CGFloat = 1 +// private(set) var screenHeightRatio: CGFloat = 1 +// private(set) var isIphonex = false +// +// // 默认参考 size = (375,667) +// private let designSize = CGSize.init(width: 375, height: 667) +// private func p_refreshData() { +// let screenWidth = UIScreen.main.bounds.size.width +// let screenHeight = UIScreen.main.bounds.size.height +// screenWidthRatio = screenWidth / designSize.width +// screenHeightRatio = screenHeight / designSize.height +// +// if #available(iOS 11.0, *), +// UIApplication.shared.delegate? +// .window??.safeAreaInsets.bottom != 0 { +// isIphonex = true +// } +// } +//} diff --git a/LingQi/LingQi/Tools/Category/Data+YL.swift b/LingQi/LingQi/Tools/Category/Data+YL.swift new file mode 100644 index 0000000..e4a5145 --- /dev/null +++ b/LingQi/LingQi/Tools/Category/Data+YL.swift @@ -0,0 +1,33 @@ +// +// Data+YL.swift +// Magpie +// +// Created by incar on 2024/1/3. +// + +import Foundation +extension Data { + struct HexEncodingOptions: OptionSet { + let rawValue: Int + static let upperCase = HexEncodingOptions(rawValue: 1 << 0) + } + + func hexEncodedString(options: HexEncodingOptions = []) -> String { + let format = options.contains(.upperCase) ?"%02hhX" :"%02hhx" + return map { String(format: format, $0) }.joined() + } + func toString()->String{ + return String(data: self, encoding: .ascii) ?? "" + } + + func toInt()->Int{ + var receive1: Int = 0 + (self as NSData).getBytes(&receive1, length: 8) + return receive1 + } + func toInt16()->Int16{ + var receive1: Int16 = 0 + (self as NSData).getBytes(&receive1, length: 16) + return receive1 + } +} diff --git a/LingQi/LingQi/Tools/Category/Open+map.swift b/LingQi/LingQi/Tools/Category/Open+map.swift new file mode 100644 index 0000000..6f785d4 --- /dev/null +++ b/LingQi/LingQi/Tools/Category/Open+map.swift @@ -0,0 +1,102 @@ +// +// Open+map.swift +// zgjd +// +// Created by apple on 2020/12/16. +// + +import Foundation +import MapKit + +struct MapTool { + /// Info plist + /// LSApplicationQueriesSchemes 需要添加 iosamap + private static let aMapScheme = "iosamap://" + private static let aMapSchemeUrl = URL(string: aMapScheme) + private static var canOpenAmap: Bool { + if let url = aMapSchemeUrl { + return UIApplication.shared.canOpenURL(url) + } else { + return false + } + } + + private static let mapsScheme = "http://maps.apple.com/" + private static let mapsSchemeUrl = URL(string: mapsScheme) + private static var canOpenMaps: Bool { + if let url = mapsSchemeUrl { + return UIApplication.shared.canOpenURL(url) + } else { + return false + } + } + + /// Info plist + /// LSApplicationQueriesSchemes 需要添加 baidumap + private static let bMapScheme = "baidumap://" + private static let bMapSchemeUrl = URL(string: bMapScheme) + private static var canOpenbMap: Bool { + if let url = bMapSchemeUrl { + return UIApplication.shared.canOpenURL(url) + } else { + return false + } + } + + /// 导航功能方法封装 + /// @param lat 纬度 + /// @param lng 经度 + /// @param address 地图显示目的地 + /// @param currentController 在哪个VC弹出 +// static func mapNavigation(lat: Double, lng: Double, address: String, currentVC: UIViewController) { +// let urlScheme = "" +// let appName = "" +// var address = address +// let coordiante = CLLocationCoordinate2DMake(lat, lng) +// if address.isEmpty { +// address = "目的地" +// } +// let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) +// if canOpenMaps { +// let action = UIAlertAction(title: "苹果地图", style: .default) { (action) in +// let currentLocation = MKMapItem.forCurrentLocation() +// let toLocation = MKMapItem(placemark: MKPlacemark(coordinate: coordiante)) +// toLocation.name = address +// MKMapItem.openMaps(with: [currentLocation, toLocation], +// launchOptions: [ +// MKLaunchOptionsDirectionsModeKey:MKLaunchOptionsDirectionsModeDriving, +// MKLaunchOptionsShowsTrafficKey:true] +// ) +// } +// alert.addAction(action) +// } +// if canOpenbMap { +// let action = UIAlertAction(title: "百度地图", style: .default) { (action) in +// let bstr = "baidumap://map/direction?origin={{我的位置}}&destination=name:\(address)|latlng:\(coordiante.latitude),\(coordiante.longitude)&mode=driving&coord_type=gcj02" +// let urlStr = bstr.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) +// guard let urlStr2 = urlStr else { return } +// guard let url = urlStr2.url else { return } +// UIApplication.shared.open(url, options: [:]) { (success) in +// SNLog("scheme try end") +// } +// } +// alert.addAction(action) +// } +// if canOpenAmap { +// let action = UIAlertAction(title: "高德地图", style: .default) { (action) in +// let bstr = "iosamap://path?sourceApplication=\(appName)&backScheme=\(urlScheme)&dlat=\(coordiante.latitude)&dlon=\(coordiante.longitude)&dname=\(address)&dev=0&t=0" +// let urlStr = bstr.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) +// guard let urlStr2 = urlStr else { return } +// guard let url = urlStr2.url else { return } +// UIApplication.shared.open(url, options: [:]) { (success) in +// SNLog("scheme try end") +// } +// } +// alert.addAction(action) +// } +// let action = UIAlertAction(title: "取消", style: .cancel, handler: nil) +// alert.addAction(action) +// +// currentVC.present(alert, animated: true, completion: nil) +// } +} diff --git a/LingQi/LingQi/Tools/Extensions/Array+Develop.swift b/LingQi/LingQi/Tools/Extensions/Array+Develop.swift new file mode 100644 index 0000000..b634d70 --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/Array+Develop.swift @@ -0,0 +1,28 @@ +// +// Array+HTDevelop.swift +// HTDevelopTools +// +// Created by 李扬 on 2019/3/8. +// Copyright © 2019 Exaleap. All rights reserved. +// + +import UIKit + +public extension Array { + /// 是否是最后一个index + func isLastIndex(_ index: Int) -> Bool { + return index == (self.count - 1) + } + func toJSONString() -> String { + + if (!JSONSerialization.isValidJSONObject(self)) { + print("无法解析出JSONString") + return "" + } + + let data = try? JSONSerialization.data(withJSONObject: self, options: []) as NSData + let JSONString = NSString(data:data! as Data,encoding: String.Encoding.utf8.rawValue) + return JSONString! as String + + } +} diff --git a/LingQi/LingQi/Tools/Extensions/Array+Spec.swift b/LingQi/LingQi/Tools/Extensions/Array+Spec.swift new file mode 100755 index 0000000..d7bcc42 --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/Array+Spec.swift @@ -0,0 +1,46 @@ +// +// Array_Extension.swift +// ShenZhouDaDiXing +// +// Created by spectator Mr.Z on 2016/11/4. +// Copyright © 2016å¹´ ZZC WORKSPACE. All rights reserved. +// + +import UIKit + +extension Array where Element: Equatable { + + // Remove first collection element that is equal to the given `object`: + public mutating func remove(object: Element) { + self = self.filter { $0 != object } + } +} + +extension Array where Element == String { + + /// 数组转字符串 + /// + /// - Parameter char: 数组间隔符 + /// - Returns: 得到的字符串 + public func string(_ char: String) -> String { + return self.joined(separator: char) + } + + func convertToStr(By: String) -> String { + let result = self.joined(separator: ",") + return result + } +} + +extension Array where Element: UIView { + var cornerRadius: CGFloat { + set { + for v in self { + v.n_cornerRadius = newValue + } + } + get { + 0 + } + } +} diff --git a/LingQi/LingQi/Tools/Extensions/CAGradientLayer+Develop.swift b/LingQi/LingQi/Tools/Extensions/CAGradientLayer+Develop.swift new file mode 100644 index 0000000..cf4c826 --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/CAGradientLayer+Develop.swift @@ -0,0 +1,61 @@ +// +// CAGradientLayer+HTDevelop.swift +// rrlWallet +// +// Created by Gordon on 2017/8/5. +// Copyright © 2017å¹´ Gordon. All rights reserved. +// + +import UIKit + +public enum LYGradientLayerDirectionOption { + case top2down + case left2right + case topLeft2downRight + case topRight2downLeft + case other +} + +public extension YCDevelop where Base: CAGradientLayer { + + /// 快速创建一个渐变的layer + /// + /// - Parameter colors: 渐变颜色 + /// - Parameter frame: 渐变范围 + /// - Parameter direction: 渐变方向 + /// - Returns: gradientLayer + static func gradientLayerWith(colors: [UIColor], frame: CGRect, direction: LYGradientLayerDirectionOption) -> CAGradientLayer { + + let layer = CAGradientLayer() + layer.frame = frame + layer.colors = colors.map { return $0.cgColor } + var start = CGPoint(x: 0.5, y: 0) + var end = CGPoint(x: 0.5, y: 1) + switch direction { + case .top2down: + start = CGPoint(x: 0.5, y: 0) + end = CGPoint(x: 0.5, y: 1) + case .left2right: + start = CGPoint(x: 0, y: 0.5) + end = CGPoint(x: 1, y: 0.5) + case .topLeft2downRight: + start = CGPoint(x: 0, y: 0) + end = CGPoint(x: 1, y: 1) + case .topRight2downLeft: + start = CGPoint(x: 1, y: 0) + end = CGPoint(x: 0, y: 1) + case .other: + break + } + layer.startPoint = start + layer.endPoint = end + return layer + } +} + +public extension YCDevelop where Base:UIView{ + func addGardiendLayerWith(colors: [UIColor], frame: CGRect, direction: LYGradientLayerDirectionOption){ + let gradientLayer = CAGradientLayer.yc.gradientLayerWith(colors: colors, frame: frame, direction: direction) + base.layer.insertSublayer(gradientLayer, at: 0) + } +} diff --git a/LingQi/LingQi/Tools/Extensions/CALayer+Develop.swift b/LingQi/LingQi/Tools/Extensions/CALayer+Develop.swift new file mode 100644 index 0000000..956739c --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/CALayer+Develop.swift @@ -0,0 +1,90 @@ +// +// CALayer+HTDevelop.swift +// kemiBear +// +// Created by 李扬 on 2017/4/18. +// Copyright © 2017å¹´ 李扬. All rights reserved. +// + +import UIKit + +extension CALayer { + + + /// 给layer添加阴影 + /// + /// - Parameter color: 颜色 + /// - Parameter blur: blur radius + /// - Parameter opacity: 不透明 + /// - Parameter rect: shadowPath + /// + func addShadow(withRect rect: CGRect, cornerRadius: CGFloat, color: UIColor, blur: CGFloat, opacity: CGFloat) { + self.shadowColor = color.cgColor + self.shadowRadius = blur + self.shadowOpacity = Float(opacity) + self.shadowPath = UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius).cgPath + } + + func addShadowOffset(color: UIColor, blur: CGFloat, opacity: CGFloat, offset: CGSize) { + self.shadowColor = color.cgColor + self.shadowRadius = blur + self.shadowOpacity = Float(opacity) + self.shadowOffset = offset + } + /// 设置圆角 +// func setRoundRect() { +// self.cornerRadius = self.bounds.size.height * 0.5 +// self.masksToBounds = true +// } + /// 设置圆角 角度 + func setCornerRadius(_ radius:CGFloat) { + self.cornerRadius = radius + self.masksToBounds = true + } + + /// 设置border + func setBorder(width: CGFloat, color: UIColor) { + self.borderColor = color.cgColor + self.borderWidth = width + self.masksToBounds = true + } + /// layer旋转360° + /// + /// - Parameter duration: 时间(旋转360度需要的时间) + /// - Parameter repeatCount: 重复次数 + /// - Parameter direction: 方向 CW:顺时针, CCW:逆时针 + func start360Rotate(duration: TimeInterval, repeatCount: Float = MAXFLOAT, direction: String = "CW") { + if let _ = self.animation(forKey: "ly_rotate360Degree") { + let pausedTime = self.timeOffset + self.speed = 1.0 + self.timeOffset = 0.0 + self.beginTime = 0.0 + let timeSincePause = self.convertTime(CACurrentMediaTime(), from: nil) - pausedTime + self.beginTime = timeSincePause + return + } + let rotation = CABasicAnimation.init(keyPath: "transform.rotation.z") + rotation.toValue = CGFloat.pi * 2 + if direction == "CCW" { + rotation.toValue = -CGFloat.pi * 2 + } + rotation.duration = duration + rotation.repeatCount = repeatCount + rotation.isCumulative = true + rotation.isRemovedOnCompletion = false + rotation.fillMode = CAMediaTimingFillMode.forwards + self.speed = 1.0 + self.add(rotation, forKey: "ly_rotate360Degree") + } + func pause360Rotate() { + guard let _ = self.animation(forKey: "ly_rotate360Degree") else { return } + let pauseTime = self.convertTime(CACurrentMediaTime(), from: nil) + self.speed = 0 + self.timeOffset = pauseTime + } + func stopRotate360() { + self.removeAnimation(forKey: "ly_rotate360Degree") + } +} + + diff --git a/LingQi/LingQi/Tools/Extensions/CGRect+HTDevelop.swift b/LingQi/LingQi/Tools/Extensions/CGRect+HTDevelop.swift new file mode 100644 index 0000000..13683ed --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/CGRect+HTDevelop.swift @@ -0,0 +1,96 @@ +// +// CGRect+HTDevelop.swift +// rrlWallet +// +// Created by gordon on 2018/9/24. +// Copyright © 2018 rrl360. All rights reserved. +// + +import UIKit + +public extension YCDevelop where Base == CGFloat { + func clamp(_ minValue: CGFloat, _ maxValue: CGFloat) -> CGFloat { + return base < minValue ? minValue : (base > maxValue ? maxValue : base) + } +} + +public extension YCDevelop where Base == CGPoint { + func translate(_ dx: CGFloat, dy: CGFloat) -> CGPoint { + return CGPoint(x: base.x+dx, y: base.y+dy) + } + + func transform(_ trans: CGAffineTransform) -> CGPoint { + return base.applying(trans) + } + + func distance(_ point: CGPoint) -> CGFloat { + return sqrt(pow(base.x - point.x, 2)+pow(base.y - point.y, 2)) + } + + var transposed: CGPoint { + return CGPoint(x: base.y, y: base.x) + } +} + +public extension YCDevelop where Base == CGSize { + + func insets(by insets: UIEdgeInsets) -> CGSize { + return CGSize(width: base.width - insets.left - insets.right, height: base.height - insets.top - insets.bottom) + } + var transposed: CGSize { + return CGSize(width: base.height, height: base.width) + } +} + + +/* +func abs(_ left: CGPoint) -> CGPoint { + return CGPoint(x: abs(left.x), y: abs(left.y)) +} +func min(_ left: CGPoint, _ right: CGPoint) -> CGPoint { + return CGPoint(x: min(left.x, right.x), y: min(left.y, right.y)) +} +func + (left: CGPoint, right: CGPoint) -> CGPoint { + return CGPoint(x: left.x + right.x, y: left.y + right.y) +} +func += (left: inout CGPoint, right: CGPoint) { + left.x += right.x + left.y += right.y +} +func + (left: CGRect, right: CGPoint) -> CGRect { + return CGRect(origin: left.origin + right, size: left.size) +} +func - (left: CGPoint, right: CGPoint) -> CGPoint { + return CGPoint(x: left.x - right.x, y: left.y - right.y) +} +func - (left: CGRect, right: CGPoint) -> CGRect { + return CGRect(origin: left.origin - right, size: left.size) +} +func / (left: CGPoint, right: CGFloat) -> CGPoint { + return CGPoint(x: left.x/right, y: left.y/right) +} +func * (left: CGPoint, right: CGFloat) -> CGPoint { + return CGPoint(x: left.x*right, y: left.y*right) +} +func * (left: CGFloat, right: CGPoint) -> CGPoint { + return right * left +} +func * (left: CGPoint, right: CGPoint) -> CGPoint { + return CGPoint(x: left.x*right.x, y: left.y*right.y) +} +prefix func - (point: CGPoint) -> CGPoint { + return CGPoint.zero - point +} +func / (left: CGSize, right: CGFloat) -> CGSize { + return CGSize(width: left.width/right, height: left.height/right) +} +func - (left: CGPoint, right: CGSize) -> CGPoint { + return CGPoint(x: left.x - right.width, y: left.y - right.height) +} + +prefix func - (inset: UIEdgeInsets) -> UIEdgeInsets { + return UIEdgeInsets(top: -inset.top, left: -inset.left, bottom: -inset.bottom, right: -inset.right) +} + + +*/ diff --git a/LingQi/LingQi/Tools/Extensions/CGSize+Fit.swift b/LingQi/LingQi/Tools/Extensions/CGSize+Fit.swift new file mode 100644 index 0000000..27e2a2f --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/CGSize+Fit.swift @@ -0,0 +1,27 @@ +// +// CGSize+Fit.swift +// YCDevTools +// +// Created by liangzhenying on 2020/4/30. +// Copyright © 2020 zkys. All rights reserved. +// +import UIKit + +public extension YCDevelop where Base == CGSize { + func fit(maxWidth:CGFloat) ->CGSize{ + var size = base + if size.width > maxWidth{ + size.height = size.height*(maxWidth/size.width) + size.width = maxWidth + } + return size + } + func fit(maxHeight:CGFloat) ->CGSize{ + var size = base + if size.height > maxHeight{ + size.width = size.width*(maxHeight/size.height) + size.height = maxHeight + } + return size + } +} diff --git a/LingQi/LingQi/Tools/Extensions/Codable+Spec.swift b/LingQi/LingQi/Tools/Extensions/Codable+Spec.swift new file mode 100644 index 0000000..53305cc --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/Codable+Spec.swift @@ -0,0 +1,33 @@ +// +// Codable+Spec.swift +// zgjd +// +// Created by apple on 2020/12/12. +// + +import Foundation + +extension Encodable { + + public func serialize() throws -> Data { + let encoder = JSONEncoder() + return try encoder.encode(self) + } + + public func toJSONDic() -> [String: Any]? { + var data: Data? + if data == nil, let string = self as? String { + data = string.data(using: .utf8) + } + if data == nil { + data = try? serialize() + } + guard let finalData = data else { + return nil + } + guard let jsonObect = try? JSONSerialization.jsonObject(with: finalData, options: .allowFragments) else { + return nil + } + return jsonObect as? [String: Any] + } +} diff --git a/LingQi/LingQi/Tools/Extensions/CollectionExtensions.swift b/LingQi/LingQi/Tools/Extensions/CollectionExtensions.swift new file mode 100644 index 0000000..3cb5c8c --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/CollectionExtensions.swift @@ -0,0 +1,128 @@ +// +// CollectionExtensions.swift +// ytxIos +// +// Created by x j z l on 2019/9/12. +// Copyright © 2019 spectator. All rights reserved. +// + +#if canImport(Dispatch) +import Dispatch +#endif + +// MARK: - Methods +public extension Collection { + + #if canImport(Dispatch) + /// SwifterSwift: Performs `each` closure for each element of collection in parallel. + /// + /// array.forEachInParallel { item in + /// print(item) + /// } + /// + /// - Parameter each: closure to run for each element. + func forEachInParallel(_ each: (Self.Element) -> Void) { + let indicesArray = Array(indices) + DispatchQueue.concurrentPerform(iterations: indicesArray.count) { (index) in + let elementIndex = indicesArray[index] + each(self[elementIndex]) + } + } + #endif + + /// SwifterSwift: Safe protects the array from out of bounds by use of optional. + /// + /// let arr = [1, 2, 3, 4, 5] + /// arr[safe: 1] -> 2 + /// arr[safe: 10] -> nil + /// + /// - Parameter index: index of element to access element. + subscript(safe index: Index) -> Element? { + return indices.contains(index) ? self[index] : nil + } + +} + +// MARK: - Methods (Int) +public extension Collection where Index == Int { + + /// SwifterSwift: Get all indices where condition is met. + /// + /// [1, 7, 1, 2, 4, 1, 8].indices(where: { $0 == 1 }) -> [0, 2, 5] + /// + /// - Parameter condition: condition to evaluate each element against. + /// - Returns: all indices where the specified condition evaluates to true. (optional) + func indices(where condition: (Element) throws -> Bool) rethrows -> [Index]? { + var indicies: [Index] = [] + for (index, value) in lazy.enumerated() where try condition(value) { + indicies.append(index) + } + return indicies.isEmpty ? nil : indicies + } + + /// SwifterSwift: Calls the given closure with an array of size of the parameter slice. + /// + /// [0, 2, 4, 7].forEach(slice: 2) { print($0) } -> //print: [0, 2], [4, 7] + /// [0, 2, 4, 7, 6].forEach(slice: 2) { print($0) } -> //print: [0, 2], [4, 7], [6] + /// + /// - Parameters: + /// - slice: size of array in each interation. + /// - body: a closure that takes an array of slice size as a parameter. + func forEach(slice: Int, body: ([Element]) throws -> Void) rethrows { + guard slice > 0, !isEmpty else { return } + + var value: Int = 0 + while value < count { + try body(Array(self[Swift.max(value, startIndex).. [[0, 2], [4, 7]] + /// [0, 2, 4, 7, 6].group(by: 2) -> [[0, 2], [4, 7], [6]] + /// + /// - Parameter size: The size of the slices to be returned. + /// - Returns: grouped self. + func group(by size: Int) -> [[Element]]? { + //Inspired by: https://lodash.com/docs/4.17.4#chunk + guard size > 0, !isEmpty else { return nil } + var value: Int = 0 + var slices: [[Element]] = [] + while value < count { + slices.append(Array(self[Swift.max(value, startIndex).. Double { + // http://stackoverflow.com/questions/28288148/making-my-function-calculate-average-of-array-swift + return isEmpty ? 0 : Double(reduce(0, +)) / Double(count) + } + +} + +// MARK: - Methods (FloatingPoint) +public extension Collection where Element: FloatingPoint { + + /// SwifterSwift: Average of all elements in array. + /// + /// [1.2, 2.3, 4.5, 3.4, 4.5].average() = 3.18 + /// + /// - Returns: average of the array's elements. + func average() -> Element { + guard !isEmpty else { return 0 } + return reduce(0, {$0 + $1}) / Element(count) + } + +} diff --git a/LingQi/LingQi/Tools/Extensions/ConstraintArrayDSL.swift b/LingQi/LingQi/Tools/Extensions/ConstraintArrayDSL.swift new file mode 100755 index 0000000..982c67d --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/ConstraintArrayDSL.swift @@ -0,0 +1,350 @@ +// +// SnapKitExtend +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// Created by charles on 2017/8/2. +// Copyright © 2017å¹´ charles. All rights reserved. +// +import SnapKit + +public enum ConstraintAxis : Int { + case horizontal + case vertical +} + +#if os(iOS) || os(tvOS) +import UIKit +public typealias ConstraintEdgeInsets = UIEdgeInsets +#else +import AppKit +extension NSEdgeInsets { + public static let zero = NSEdgeInsetsZero +} +public typealias ConstraintEdgeInsets = NSEdgeInsets + + +#endif + +public struct ConstraintArrayDSL { + @discardableResult + public func prepareConstraints(_ closure: (_ make: ConstraintMaker) -> Void) -> [Constraint] { + var constraints = Array() + for view in self.array { + constraints.append(contentsOf: view.snp.prepareConstraints(closure)) + } + return constraints + } + + public func makeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) { + for view in self.array { + view.snp.makeConstraints(closure) + } + } + + public func remakeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) { + for view in self.array { + view.snp.remakeConstraints(closure) + } + } + + public func updateConstraints(_ closure: (_ make: ConstraintMaker) -> Void) { + for view in self.array { + view.snp.updateConstraints(closure) + } + } + + public func removeConstraints() { + for view in self.array { + view.snp.removeConstraints() + } + } + + /// distribute with fixed spacing + /// + /// - Parameters: + /// - axisType: which axis to distribute items along + /// - fixedSpacing: the spacing between each item + /// - leadSpacing: the spacing before the first item and the container + /// - tailSpacing: the spacing after the last item and the container + public func distributeViewsAlong(axisType:ConstraintAxis, fixedSpacing:CGFloat = 0, leadSpacing:CGFloat = 0, tailSpacing:CGFloat = 0) { + + guard self.array.count > 1, let tempSuperView = commonSuperviewOfViews() else { + return + } + + if axisType == .horizontal { + var prev : ConstraintView? + for (i, v) in self.array.enumerated() { + v.snp.makeConstraints({ (make) in + guard let prev = prev else {//first one + make.left.equalTo(tempSuperView).offset(leadSpacing) + return + } + make.width.equalTo(prev) + make.left.equalTo(prev.snp.right).offset(fixedSpacing) + if (i == self.array.count - 1) {//last one + make.right.equalTo(tempSuperView).offset(-tailSpacing) + } + }) + prev = v; + } + }else { + var prev : ConstraintView? + for (i, v) in self.array.enumerated() { + v.snp.makeConstraints({ (make) in + guard let prev = prev else {//first one + make.top.equalTo(tempSuperView).offset(leadSpacing); + return + } + make.height.equalTo(prev) + make.top.equalTo(prev.snp.bottom).offset(fixedSpacing) + if (i == self.array.count - 1) {//last one + make.bottom.equalTo(tempSuperView).offset(-tailSpacing); + } + }) + prev = v; + } + } + } + + /// distribute with fixed item size + /// + /// - Parameters: + /// - axisType: which axis to distribute items along + /// - fixedItemLength: the fixed length of each item + /// - leadSpacing: the spacing before the first item and the container + /// - tailSpacing: the spacing after the last item and the container + public func distributeViewsAlong(axisType:ConstraintAxis, fixedItemLength:CGFloat = 0, leadSpacing:CGFloat = 0, tailSpacing:CGFloat = 0) { + + guard self.array.count > 1, let tempSuperView = commonSuperviewOfViews() else { + return + } + + if axisType == .horizontal { + var prev : ConstraintView? + for (i, v) in self.array.enumerated() { + v.snp.makeConstraints({ (make) in + make.width.equalTo(fixedItemLength) + if prev != nil { + if (i == self.array.count - 1) {//last one + make.right.equalTo(tempSuperView).offset(-tailSpacing); + } else { + let offset = (CGFloat(1) - (CGFloat(i) / CGFloat(self.array.count - 1))) * + (fixedItemLength + leadSpacing) - + CGFloat(i) * tailSpacing / CGFloat(self.array.count - 1) + make.right.equalTo(tempSuperView).multipliedBy(CGFloat(i) / CGFloat(self.array.count - 1)).offset(offset) + } + }else {//first one + make.left.equalTo(tempSuperView).offset(leadSpacing); + } + }) + prev = v; + } + }else { + var prev : ConstraintView? + for (i, v) in self.array.enumerated() { + v.snp.makeConstraints({ (make) in + make.height.equalTo(fixedItemLength) + if prev != nil { + if (i == self.array.count - 1) {//last one + make.bottom.equalTo(tempSuperView).offset(-tailSpacing); + }else { + let offset = (CGFloat(1) - (CGFloat(i) / CGFloat(self.array.count - 1))) * + (fixedItemLength + leadSpacing) - + CGFloat(i) * tailSpacing / CGFloat(self.array.count - 1) + make.bottom.equalTo(tempSuperView).multipliedBy(CGFloat(i) / CGFloat(self.array.count-1)).offset(offset) + } + }else {//first one + make.top.equalTo(tempSuperView).offset(leadSpacing); + } + }) + prev = v; + } + } + } + + /// distribute Sudoku with fixed item size + /// + /// - Parameters: + /// - fixedItemWidth: the fixed width of each item + /// - fixedItemLength: the fixed length of each item + /// - warpCount: the warp count in the super container + /// - edgeInset: the padding in the super container + public func distributeSudokuViews(fixedItemWidth: CGFloat, fixedItemHeight: CGFloat, warpCount: Int, edgeInset: ConstraintEdgeInsets = .zero) { + + guard self.array.count > 1, warpCount >= 1, let tempSuperView = commonSuperviewOfViews() else { + return + } + + let remainder = self.array.count % warpCount + let quotient = self.array.count / warpCount + + let rowCount = (remainder == 0) ? quotient : (quotient + 1) + let columnCount = warpCount + + for (i,v) in self.array.enumerated() { + + let currentRow = i / warpCount + let currentColumn = i % warpCount + + v.snp.makeConstraints({ (make) in + make.width.equalTo(fixedItemWidth) + make.height.equalTo(fixedItemHeight) + if currentRow == 0 {//fisrt row + make.top.equalTo(tempSuperView).offset(edgeInset.top) + } + if currentRow == rowCount - 1 {//last row + make.bottom.equalTo(tempSuperView).offset(-edgeInset.bottom) + } + + if currentRow != 0 && currentRow != rowCount - 1 {//other row + let offset = (CGFloat(1) - CGFloat(currentRow) / CGFloat(rowCount - 1)) * + (fixedItemHeight + edgeInset.top) - + CGFloat(currentRow) * edgeInset.bottom / CGFloat(rowCount - 1) + make.bottom.equalTo(tempSuperView).multipliedBy(CGFloat(currentRow) / CGFloat(rowCount - 1)).offset(offset); + } + + if currentColumn == 0 {//first col + make.left.equalTo(tempSuperView).offset(edgeInset.left) + } + if currentColumn == columnCount - 1 {//last col + make.right.equalTo(tempSuperView).offset(-edgeInset.right) + } + + if currentColumn != 0 && currentColumn != columnCount - 1 {//other col + let offset = (CGFloat(1) - CGFloat(currentColumn) / CGFloat(columnCount - 1)) * + (fixedItemWidth + edgeInset.left) - + CGFloat(currentColumn) * edgeInset.right / CGFloat(columnCount - 1) + make.right.equalTo(tempSuperView).multipliedBy(CGFloat(currentColumn) / CGFloat(columnCount - 1)).offset(offset); + } + }) + } + } + + /// distribute Sudoku with fixed item spacing + /// + /// - Parameters: + /// - fixedLineSpacing: the line spacing between each item + /// - fixedInteritemSpacing: the Interitem spacing between each item + /// - warpCount: the warp count in the super container + /// - edgeInset: the padding in the super container + public func distributeSudokuViews(fixedLineSpacing: CGFloat, fixedInteritemSpacing: CGFloat, warpCount: Int, edgeInset: ConstraintEdgeInsets = .zero) { + + guard self.array.count > 1, warpCount >= 1, let tempSuperView = commonSuperviewOfViews() else { + return + } + + let remainder = self.array.count % warpCount + let quotient = self.array.count / warpCount + + let rowCount = (remainder == 0) ? quotient : (quotient + 1) + let columnCount = warpCount + + + var prev : ConstraintView? + + for (i,v) in self.array.enumerated() { + + let currentRow = i / warpCount + let currentColumn = i % warpCount + + v.snp.makeConstraints({ (make) in + guard let prev = prev else {//first row & first col + make.top.equalTo(tempSuperView).offset(edgeInset.top) + make.left.equalTo(tempSuperView).offset(edgeInset.left) + return + } + make.width.height.equalTo(prev) + if currentRow == rowCount - 1 {//last row + if currentRow != 0 && i - columnCount >= 0 {//just one row + make.top.equalTo(self.array[i-columnCount].snp.bottom).offset(fixedLineSpacing) + } + make.bottom.equalTo(tempSuperView).offset(-edgeInset.bottom) + } + + if currentRow != 0 && currentRow != rowCount - 1 {//other row + make.top.equalTo(self.array[i-columnCount].snp.bottom).offset(fixedLineSpacing); + } + if currentColumn == warpCount - 1 {//last col + if currentColumn != 0 {//just one line + make.left.equalTo(prev.snp.right).offset(fixedInteritemSpacing) + } + make.right.equalTo(tempSuperView).offset(-edgeInset.right) + } + + if currentColumn != 0 && currentColumn != warpCount - 1 {//other col + make.left.equalTo(prev.snp.right).offset(fixedInteritemSpacing); + } + }) + prev = v + } + } + + internal let array: Array + + internal init(array: Array) { + self.array = array + } + +} + +public extension Array { + var snp: ConstraintArrayDSL { + return ConstraintArrayDSL(array: self as! Array) + } +} + +private extension ConstraintArrayDSL { + func commonSuperviewOfViews() -> ConstraintView? { + var commonSuperview : ConstraintView? + var previousView : ConstraintView? + + for view in self.array { + if previousView != nil { + commonSuperview = view.closestCommonSuperview(commonSuperview) + }else { + commonSuperview = view + } + previousView = view + } + + return commonSuperview + } +} + +private extension ConstraintView { + func closestCommonSuperview(_ view : ConstraintView?) -> ConstraintView? { + var closestCommonSuperview: ConstraintView? + var secondViewSuperview: ConstraintView? = view + while closestCommonSuperview == nil && secondViewSuperview != nil { + var firstViewSuperview: ConstraintView? = self + while closestCommonSuperview == nil && firstViewSuperview != nil { + if secondViewSuperview == firstViewSuperview { + closestCommonSuperview = secondViewSuperview + } + firstViewSuperview = firstViewSuperview?.superview + } + secondViewSuperview = secondViewSuperview?.superview + } + return closestCommonSuperview + } +} diff --git a/LingQi/LingQi/Tools/Extensions/Dictionary+Develop.swift b/LingQi/LingQi/Tools/Extensions/Dictionary+Develop.swift new file mode 100644 index 0000000..73ad0c1 --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/Dictionary+Develop.swift @@ -0,0 +1,168 @@ +// +// Dictionary+LY.swift +// teststttt +// +// Created by Gordon on 2017/8/1. +// Copyright © 2017å¹´ Gordon. All rights reserved. +// + +import UIKit + +// MARK: 字典转字符串 +public extension Dictionary { + func toString() -> String? { + guard let data = try? JSONSerialization.data(withJSONObject: self, + options: []) else { + return nil + } + guard let str = String(data: data, encoding: .utf8) else { + return nil + } + return str + } + +} + +public extension Dictionary { + + static func +=(lhs: inout Dictionary, rhs: Dictionary) { + lhs.merge(rhs) + } + mutating func merge(_ sequence: S) + where S.Iterator.Element == (key: Key, value: Value) { + sequence.forEach { self[$0] = $1 } + } +} + +public extension YCDevelop where Base == Dictionary { + var combine2urlParamStr: String { + guard base.count > 0 else { return "" } + var components = "" + for k in base.keys { + components.append("\(k)=\(base[k] ?? "")&") + } + components.removeLast() + return components + } +} + +public extension YCDevelop where Base == Dictionary { + + /// 根据key对字典进行排序 + /// + /// - Returns: 数组 第一个为排序之后的key 第二个为排序之后的value + private func sortByKeys() -> [[Any]] { + if base.count == 0 { + return [] + } + let sortedKeys = base.keys.sorted(by: <) + var sortedValues = [Any]() + sortedKeys.forEach { sortedValues.append(base[$0] ?? "") } + return [sortedKeys, sortedValues] + } + + /// 添加签名 kv + /// + /// - Parameter mix: 添加的用于签名的串 + /// - Parameter successKey: 签名成功后,添加到字典中的key值 默认为sign + /// - Returns: 添加签名kv后的dict + func sign(withMix mix: String, successKey: String = "sign") -> [String: Any] { + let signature = p_sign(withMix: mix) + guard !signature.isEmpty else { return base } + var signed = base + signed[successKey] = signature + return signed + } + + /// 根据kv 生成一个signature + private func p_sign(withMix mix: String) -> String { + guard base.count > 0 else { return "" } + let param = base + let arr = param.yc.sortByKeys() + guard arr.count == 2 else { return "" } + let keys = arr[0] + let values = arr[1] + var signArr = [String]() + for idx in 0 ..< keys.count { + let subValue = values[idx] + if let value = subValue as? String { + var shift = value.replacingOccurrences(of: "\\", with: "\\\\") + shift = shift.replacingOccurrences(of: "\0", with: "\\0") + shift = shift.replacingOccurrences(of: "\n", with: "\\n") + shift = shift.replacingOccurrences(of: "\t", with: "\\t") + shift = shift.replacingOccurrences(of: "\r", with: "\\r") + shift = shift.replacingOccurrences(of: "\"", with: """ + \\\" + """) + signArr.append(#""\#(keys[idx])":"\#(shift)""#) + } else if let value = subValue as? [Any] { + signArr.append(#""\#(keys[idx])":\#(value.paramSign)"#) + } else { + signArr.append(#""\#(keys[idx])":\#(subValue)"#) + } + } + let toSignStr = "{" + signArr.joined(separator: ",") + + "}" + "key=\(mix)" + k_log(toSignStr) + return toSignStr.yc.md5 + } + + /// 获取字典所有数据整理后的 签名, 用于比较 + var signature: String { + guard base.count > 0 else { return "" } + let arr = base.yc.sortByKeys() + guard arr.count == 2 else { return "" } + let keys = arr[0] + let values = arr[1] + var signArr = [String]() + for idx in 0 ..< keys.count { + let subValue = values[idx] + if let value = subValue as? [String: Any] { + signArr.append(#""\#(keys[idx])":"\#(value.yc.signature)""#) + } else if let value = subValue as? [Any] { + signArr.append(#""\#(keys[idx])":"\#(value.signature)""#) + } else if let value = subValue as? Bool { + signArr.append(#""\#(keys[idx])":"\#(value ? 1 : 0)""#) + } else { + signArr.append(#""\#(keys[idx])":"\#(subValue)""#) + } + } + return signArr.joined(separator: ",") +// return signArr.joined(separator: ",").yc.md5 + } +} + +fileprivate extension Array { + /// 用于数据对比 + var signature: String { + var str = "" + for item in self { + if let subItem = item as? [Any] { + str += subItem.signature + } else if let subItem = item as? [String: Any] { + str += subItem.yc.signature + } else if let subItem = item as? Bool { + str += "\(subItem ? 1 : 0)" + } else { + str += "\(item)" + } + } + return str + } + /// 用于入参校验 + var paramSign: String { + if self is [[String:Any]] { + let data = try? JSONSerialization.data(withJSONObject: self, options: JSONSerialization.WritingOptions.init(rawValue: 0)) + guard let jsonStr = NSString(data: data!, encoding: String.Encoding.utf8.rawValue) else{ + return "" + } + return jsonStr as String + } + else{ + let joinedStrng = self.map { #""\#($0)""# }.joined(separator: ",") + return "[\(joinedStrng)]" + } +// let joinedStrng = self.map { #""\#($0)""# }.joined(separator: ",") +// return "[\(joinedStrng)]" + } +} diff --git a/LingQi/LingQi/Tools/Extensions/DispatchQueue+Develop.swift b/LingQi/LingQi/Tools/Extensions/DispatchQueue+Develop.swift new file mode 100644 index 0000000..502b49b --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/DispatchQueue+Develop.swift @@ -0,0 +1,27 @@ +// +// DispatchQueue+Develop.swift +// YCDevTools +// +// Created by Liang ZhenYing on 2020/3/5. +// Copyright © 2020 zkys. All rights reserved. +// + +import UIKit + +extension DispatchQueue { + + private static var onceTracker = [String]() + + //Executes a block of code, associated with a unique token, only once. The code is thread safe and will only execute the code once even in the presence of multithreaded calls. + public class func once(token: String, block: () -> Void) { + /// 保证被 objc_sync_enter 和 objc_sync_exit 包裹的代码可以有序同步地执行 + objc_sync_enter(self) + defer { objc_sync_exit(self) } + + if onceTracker.contains(token) { return } + + onceTracker.append(token) + block() + } +} + diff --git a/LingQi/LingQi/Tools/Extensions/FileManager+Develop.swift b/LingQi/LingQi/Tools/Extensions/FileManager+Develop.swift new file mode 100644 index 0000000..0adcff2 --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/FileManager+Develop.swift @@ -0,0 +1,181 @@ +// +// FileManager+HTDevelop.swift +// rrlWallet +// +// Created by Gordon on 2017/8/2. +// Copyright © 2017å¹´ Gordon. All rights reserved. +// + +import UIKit +import Kingfisher + +// MARK: === 各文件目录等 +public extension YCDevelop where Base: FileManager { + + // MARK: === 获取cachesPath + static var libraryCachesPath: String { + return NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first ?? "" + } + // MARK: === 获取documentPath + static var documentPath: String { + return NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first ?? "" + } + // MARK: === 获取下载文件夹目录 + static var downloadDirectory: String { + let path = (libraryCachesPath as NSString).appendingPathComponent("download") + if !fileExists(atPath: path) { + _ = createDirectories(forPath: path) + } + return path + } +} + +// MARK: === 常用方法 +public extension YCDevelop where Base: FileManager { + + // MARK: === 文件是否存在 + static func fileExists(atPath path: String) -> Bool { + return FileManager.default.fileExists(atPath:path) + } + // MARK: === 路径是否是文件夹 + static func isDirectory(atPath path: String) -> Bool { + var isDir:ObjCBool = false + FileManager.default.fileExists(atPath: path, isDirectory: &isDir) + return isDir.boolValue + } + // MARK: === 删除文件 + @discardableResult + static func removeItem(atPath path: String) -> Bool { + if let _ = try? FileManager.default.removeItem(atPath: path) { + return true + } + return false + } + // MARK: === 创建文件夹 + static func createDirectories(forPath path: String) -> Bool { + guard let _ = try? FileManager.default.createDirectory(atPath: path, withIntermediateDirectories: true, attributes: nil) else { + return false + } + return true + } + // MARK: === 获取文件修改时间 + static func modifyDateOfItem(atPath path: String) -> Date { + if let attr = try? FileManager.default.attributesOfItem(atPath: path), + let modifyDate = attr[.modificationDate] as? Date { + return modifyDate + } + return Date() + } + // MARK: === 获取下载文件夹下的 所有目录 + static func subDownloadDirectories() -> [String] { + let download = downloadDirectory + guard isDirectory(atPath: download), + let dirArr = try? FileManager.default.contentsOfDirectory(atPath: download) else { + return [] + } + var subDownloads = [String]() + for dir in dirArr { + let sub = (dir as NSString).appendingPathComponent(dir) + if isDirectory(atPath: sub) { + subDownloads.append(sub) + } + } + return subDownloads + } + // MARK: === 获取文件夹下的所用文件 + static func fileInDirectory(atPath path: String) -> [String] { + guard isDirectory(atPath: path), + let dirArr = try? FileManager.default.contentsOfDirectory(atPath: path) else { + return [] + } + var subFiles = [String]() + + for dir in dirArr { + let sub = (path as NSString).appendingPathComponent(dir) + if !isDirectory(atPath: sub) { + subFiles.append(sub) + } + } + return subFiles + } +} + +// MARK: - ********* Filepath for AudioPlayer +extension YCDevelop where Base: FileManager { + + // MARK: === 文件下载目录 + static var orderFileDownloadPath: String { + let dPath = (documentPath as NSString).appendingPathComponent("orderDownload") + if !fileExists(atPath: dPath) { + _ = createDirectories(forPath: dPath) + } + return dPath + } + // MARK: === 文件下载 URL路径 + static func orderFileUrl(withFileName name: String) -> URL { + let path = orderFileDownloadPath + "/" + name + return URL.init(fileURLWithPath: path) + } + // MARK: === 文件下载 Path路径 + static func orderFilePath(withFileName name: String) -> String { + return orderFileDownloadPath + "/" + name + } +} + + +// MARK: - ********* 缓存统计 +public extension YCDevelop where Base: FileManager { + + /// 计算文件大小 + static func foldersSize(atPaths paths: [String]) -> Double { + var size = 0.0 + for path in paths { + size = size + folderSize(atPath: path) + } + return size + } + + private static func folderSize(atPath path: String) -> Double { + let manager = FileManager.default + guard manager.fileExists(atPath: path) else { return 0 } + let childFiles = fileInDirectory(atPath: path) + + var folderSize:Int64 = 0 + for childPath in childFiles { + folderSize += fileSize(atPath: childPath) + } + return Double(folderSize)/(1024.0 * 1024.0) + } + + private static func fileSize(atPath path: String) -> Int64 { + let manager = FileManager.default + if manager.fileExists(atPath: path), + let attr = try? manager.attributesOfItem(atPath: path) { + return (attr[FileAttributeKey.size] as? Int64) ?? 0 + } + return 0 + } +} + + +// MARK: - ********* 清除缓存 +public extension YCDevelop where Base: FileManager { + + static private var clearPaths: [String] { + let kfImgPath = KingfisherManager.shared.cache.diskStorage.directoryURL.absoluteString + return [kfImgPath] + } + static var cacheSize: String { + let size = foldersSize(atPaths: clearPaths) + return String.init(format: "%.2fM", size) + } + static var clearCache: Bool { + for path in clearPaths { + _ = removeItem(atPath: path) + } + return true + } +} + + + diff --git a/LingQi/LingQi/Tools/Extensions/KeyPath+Develop.swift b/LingQi/LingQi/Tools/Extensions/KeyPath+Develop.swift new file mode 100644 index 0000000..b2e18dc --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/KeyPath+Develop.swift @@ -0,0 +1,35 @@ +// +// KeyPath+HTDevelop.swift +// HTDevelopTools +// +// Created by 李扬 on 2019/6/4. +// Copyright © 2019 Exaleap. All rights reserved. +// + +import UIKit + +/* +public func setter( + for object: Object, + keyPath: ReferenceWritableKeyPath + ) -> (Value) -> Void { + return { [weak object] value in + object?[keyPath: keyPath] = value + } +} + +*/ + +// MARK: - ********* KeyPath method +public extension Sequence { + // MARK: === keyPath map + func map(_ keyPath: KeyPath) -> [T] { + return map { $0[keyPath: keyPath] } + } + // MARK: === keyPath sort + func sorted(by keyPath: KeyPath) -> [Element] { + return sorted { a, b in + return a[keyPath: keyPath] < b[keyPath: keyPath] + } + } +} diff --git a/LingQi/LingQi/Tools/Extensions/Number+Develop.swift b/LingQi/LingQi/Tools/Extensions/Number+Develop.swift new file mode 100644 index 0000000..b7150ae --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/Number+Develop.swift @@ -0,0 +1,19 @@ +// +// Number+Develop.swift +// YCDevTools +// +// Created by Liang ZhenYing on 2020/3/6. +// Copyright © 2020 zkys. All rights reserved. +// + +import UIKit + +extension Double { + public var π: CGFloat { + return CGFloat(self) * CGFloat.pi + } + + public var twoDecimal:String{ + return String(format: "%.2f", self) + } +} diff --git a/LingQi/LingQi/Tools/Extensions/QueryParameters.swift b/LingQi/LingQi/Tools/Extensions/QueryParameters.swift new file mode 100644 index 0000000..3793c36 --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/QueryParameters.swift @@ -0,0 +1,23 @@ +// +// QueryParameters.swift +// zgjd +// +// Created by apple on 2021/2/20. +// + +import Foundation + +extension URL { + var queryParameters: QueryParameters { return QueryParameters(url: self) } +} + +class QueryParameters { + let queryItems: [URLQueryItem] + init(url: URL?) { + queryItems = URLComponents(string: url?.absoluteString ?? "")?.queryItems ?? [] + print(queryItems) + } + subscript(name: String) -> String? { + return queryItems.first(where: { $0.name == name })?.value + } +} diff --git a/LingQi/LingQi/Tools/Extensions/Sequence+Develop.swift b/LingQi/LingQi/Tools/Extensions/Sequence+Develop.swift new file mode 100644 index 0000000..c069fa1 --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/Sequence+Develop.swift @@ -0,0 +1,38 @@ +// +// Sequence+HTDevelop.swift +// rrlWallet +// +// Created by Gordon on 2017/8/30. +// Copyright © 2017å¹´ Gordon. All rights reserved. +// + +import Foundation + +public extension Collection { + + func all(predicate: (Iterator.Element) -> Bool) -> Bool { + for x in self where !predicate(x) { + return false + } + return true + } + + /// Finds such index N that predicate is true for all elements up to + /// but not including the index N, and is false for all elements + /// starting with index N. + /// Behavior is undefined if there is no such N. + func binarySearch(predicate: (Iterator.Element) -> Bool) -> Index { + var low = startIndex + var high = endIndex + while low != high { + let mid = index(low, offsetBy: distance(from: low, to: high)/2) + if predicate(self[mid]) { + low = index(after: mid) + } else { + high = mid + } + } + return low + } +} + diff --git a/LingQi/LingQi/Tools/Extensions/SignedNumericExtensions.swift b/LingQi/LingQi/Tools/Extensions/SignedNumericExtensions.swift new file mode 100644 index 0000000..36cbf9b --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/SignedNumericExtensions.swift @@ -0,0 +1,54 @@ +// +// SignedNumberExtensions.swift +// SwifterSwift +// +// Created by Omar Albeik on 8/15/17. +// Copyright © 2017 SwifterSwift +// + +#if canImport(Foundation) +import Foundation +#endif + +// MARK: - Properties +public extension SignedNumeric { + + /// SwifterSwift: String. + var string: String { + return String(describing: self) + } + + #if canImport(Foundation) + /// SwifterSwift: String with number and current locale currency. + var asLocaleCurrency: String? { + let formatter = NumberFormatter() + formatter.numberStyle = .currency + formatter.locale = Locale.current + // swiftlint:disable:next force_cast + return formatter.string(from: self as! NSNumber) + } + #endif + +} + +// MARK: - Methods +public extension SignedNumeric { + + #if canImport(Foundation) + /// SwifterSwift: Spelled out representation of a number. + /// + /// print((12.32).spelledOutString()) // prints "twelve point three two" + /// + /// - Parameter locale: Locale, default is .current. + /// - Returns: String representation of number spelled in specified locale language. E.g. input 92, output in "en": "ninety-two" + func spelledOutString(locale: Locale = .current) -> String? { + let formatter = NumberFormatter() + formatter.locale = locale + formatter.numberStyle = .spellOut + + guard let number = self as? NSNumber else { return nil } + return formatter.string(from: number) + } + #endif + +} diff --git a/LingQi/LingQi/Tools/Extensions/SnapKit_Extension.swift b/LingQi/LingQi/Tools/Extensions/SnapKit_Extension.swift new file mode 100755 index 0000000..0a89f57 --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/SnapKit_Extension.swift @@ -0,0 +1,147 @@ +// +// SnapKit_Extension.swift +// diandianzanumsers +// +// Created by 楠 on 2017/6/11. +// Copyright © 2017å¹´ specddz. All rights reserved. +// + +import Foundation +import SnapKit + + +extension ConstraintMakerEditable { + @discardableResult + public func snOffset(_ amount: CGFloat) -> SnapKit.ConstraintMakerEditable { + self.offset(amount.fitR) + return self + } + + @discardableResult + public func snInset(_ amount: CGFloat) -> SnapKit.ConstraintMakerEditable { + self.inset(amount.fitR) + return self + } + +} + +extension ConstraintMakerRelatable { + + @discardableResult + public func snEqualTo(_ other: ConstraintRelatableTarget, _ file: String = #file, _ line: UInt = #line) -> ConstraintMakerEditable { + if let other = other as? ConstraintConstantTarget { + let value = CGFloat(truncating: other as! NSNumber) + return self.equalTo(value.fitR, file, line) + } else { + + return self.equalTo(other, file, line) + } + } + + @discardableResult + public func snEqualToSuperview(_ file: String = #file, _ line: UInt = #line) -> SnapKit.ConstraintMakerEditable { + return self.equalToSuperview(file, line) + } + + @discardableResult + public func snTopSuperview(vc: UIViewController,_ file: String = #file, _ line: UInt = #line) -> SnapKit.ConstraintMakerEditable { + + if #available(iOS 11, *) { + return self.equalTo(vc.view.safeAreaLayoutGuide.snp.top) + } else { + return self.equalTo(vc.topLayoutGuide.snp.bottom) + } + } + + @discardableResult + public func snTopLessThanSuperview(vc: UIViewController, _ file: String = #file, _ line: UInt = #line) -> SnapKit.ConstraintMakerEditable { + if #available(iOS 11, *) { + return self.lessThanOrEqualTo(vc.view.safeAreaLayoutGuide.snp.top) + } else { + return self.lessThanOrEqualTo(vc.topLayoutGuide.snp.bottom) + } + } + + @discardableResult + public func snTopGreaterThanSuperview(vc: UIViewController, _ file: String = #file, _ line: UInt = #line) -> SnapKit.ConstraintMakerEditable { + if #available(iOS 11, *) { + return self.greaterThanOrEqualTo(vc.view.safeAreaLayoutGuide.snp.top) + } else { + return self.greaterThanOrEqualTo(vc.topLayoutGuide.snp.bottom) + } + } + + @discardableResult + public func snBottomSuperview(vc: UIViewController,_ file: String = #file, _ line: UInt = #line) -> SnapKit.ConstraintMakerEditable { + + if #available(iOS 11, *) { + return self.equalTo(vc.view.safeAreaLayoutGuide.snp.bottom) + } else { + return self.equalTo(vc.bottomLayoutGuide.snp.top) + } + } + + @discardableResult + public func snBottomLessThanSuperview(vc: UIViewController,_ file: String = #file, _ line: UInt = #line) -> SnapKit.ConstraintMakerEditable { + if #available(iOS 11, *) { + return self.lessThanOrEqualTo(vc.view.safeAreaLayoutGuide.snp.bottom) + } else { + return self.lessThanOrEqualTo(vc.bottomLayoutGuide.snp.top) + } + } + + @discardableResult + public func snBottomGreaterThanSuperview(vc: UIViewController, _ file: String = #file, _ line: UInt = #line) -> SnapKit.ConstraintMakerEditable { + if #available(iOS 11, *) { + return self.greaterThanOrEqualTo(vc.view.safeAreaLayoutGuide.snp.bottom) + } else { + return self.greaterThanOrEqualTo(vc.bottomLayoutGuide.snp.top) + } + } + +} + +public extension ConstraintMaker { + + func positionCenterY() { + self.centerY.snEqualToSuperview() + } + + func positionCenterX() { + self.centerX.snEqualToSuperview() + } + + func center() { + self.center.snEqualToSuperview() + } + + @discardableResult + func height(_ height: CGFloat) -> SnapKit.ConstraintMakerEditable { + return self.height.snEqualTo(height) + } + + @discardableResult + func width(_ width: CGFloat) -> SnapKit.ConstraintMakerEditable { + return self.width.snEqualTo(width) + } + + func size(_ width: ConstraintRelatableTarget, _ height: ConstraintRelatableTarget) { + self.width.snEqualTo(width) + self.height.snEqualTo(height) + } + + func position(left: CGFloat? = nil, top: CGFloat? = nil, right: CGFloat? = nil, bottom: CGFloat? = nil) { + if let target = top { + self.top.snEqualToSuperview().snOffset(target) + } + if let target = left { + self.left.snEqualToSuperview().snOffset(target) + } + if let target = right { + self.right.snEqualToSuperview().snOffset(target) + } + if let target = bottom { + self.bottom.snEqualToSuperview().snOffset(target) + } + } +} diff --git a/LingQi/LingQi/Tools/Extensions/String+Attribute.swift b/LingQi/LingQi/Tools/Extensions/String+Attribute.swift new file mode 100644 index 0000000..a11a64f --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/String+Attribute.swift @@ -0,0 +1,142 @@ +// +// String+HTDevelop.swift +// HendersonTouchSwift +// +// Created by Gordon on 2017/6/27. +// Copyright © 2017å¹´ taikanglife. All rights reserved. +// + +import UIKit + +public extension YCDevelop where Base: NSAttributedString { + + func size(withConstraints size: CGSize, + options: NSStringDrawingOptions = .usesLineFragmentOrigin, + context: NSStringDrawingContext? = nil) -> CGSize { + let cSize = base.boundingRect(with: size, options: options, context: context).size + return CGSize(width: cSize.width.ceil, height: cSize.height.ceil) + } +} + +public extension YCDevelop where Base == String { + + /// string的size + func strSize(font: UIFont, constraints size: CGSize, options: NSStringDrawingOptions = .usesLineFragmentOrigin, context: NSStringDrawingContext? = nil) -> CGSize { + let cSize = attributedStr(font: font).boundingRect(with: size, options: options, context: context).size + return CGSize(width: cSize.width.ceil, height: cSize.height.ceil) + } + + private func attributedStr(font: UIFont) -> NSMutableAttributedString { + + let attrStr = NSMutableAttributedString.init(string: base) + guard base.count > 0 else { + return attrStr + } + let range = NSMakeRange(0, attrStr.length) + attrStr.addAttributes([.font: font], range: range) + return attrStr + } + + var attr: NSAttributedString { + return NSAttributedString.init(string: base) + } + + // MARK: === 字符串添加字间距,行间距 + /// 字符串添加字间距,行间距(通过转化成AttributedString的方式) + /// + /// - Parameter font: 文字字体 + /// - Parameter color: 文字颜色 + /// - Parameter wordSpacing: 文字间距 + /// - Parameter lineSpacing: 行间距 + /// - Parameter lineAlignment: 文字对齐方式 + /// + /// - Returns: 带有字体,颜色,间距的AttributedString + func attributedStr(font: UIFont, color: UIColor, + wordSpacing: Float = 0, + lineSpacing: CGFloat = 0, + lineAlignment: NSTextAlignment = .left, + lineBreakMode: NSLineBreakMode? = .byTruncatingTail) -> NSMutableAttributedString { + + let attr = self.attributedStr(font: font, color: color, wordSpacing: wordSpacing) + let paragrapnStyle = NSMutableParagraphStyle() + paragrapnStyle.alignment = lineAlignment + if let lineBreakMode = lineBreakMode { + paragrapnStyle.lineBreakMode = lineBreakMode + } + let range = NSMakeRange(0, attr.length) + if lineAlignment == .justified { + attr.addAttributes([.baselineOffset : NSNumber.init(value: 0.0), + .paragraphStyle: paragrapnStyle], range: range) + } else { + paragrapnStyle.lineSpacing = CGFloat(lineSpacing) + attr.addAttribute(.paragraphStyle, value: paragrapnStyle, range: NSMakeRange(0, attr.length)) + } + return attr + } + + private func attributedStr(font: UIFont, color: UIColor, wordSpacing: Float) -> NSMutableAttributedString { + + let attrStr = NSMutableAttributedString.init(string: base) + guard base.count > 0 else { + return attrStr + } + let range = NSMakeRange(0, attrStr.length) + attrStr.addAttributes([.font: font, + .foregroundColor: color], range: range) + guard wordSpacing != 0 else { + return attrStr + } + attrStr.addAttribute(.kern, value: wordSpacing, range: NSMakeRange(0, attrStr.length - 1)) + return attrStr + } + + + // MARK: === 一行文字两种颜色 + func attr2Str(font: UIFont, + color: UIColor, + rangeStr: String, + rColor: UIColor, + rFont: UIFont? = nil, + lineAlignment: NSTextAlignment = .left)-> NSMutableAttributedString { + let rangeFont = rFont ?? font + let attr = self.attributedStr(font: font, color: color, lineAlignment: lineAlignment) + let nsStr = NSString.init(string: base) + let range = nsStr.range(of: rangeStr) + attr.addAttributes([.font: rangeFont, + .foregroundColor: rColor], range: range) + return attr + } + // MARK: === ä»·æ ¼ + func priceAttr(font1: UIFont,Font2: UIFont,color:UIColor = UIColor.rgb(0xFF4B5A))-> NSMutableAttributedString { + let text = "Â¥" + base + let attr = text.yc.attributedStr(font: Font2, color: color, lineAlignment: .left) + attr.addAttributes([.font: font1], range: NSRange(location: 0,length: 1)) + return attr + } +} + +public extension YCDevelop where Base: NSMutableAttributedString { + + // MARK: === 给指定文字添加颜色 + func addAttr(ToStr str: String, + font: UIFont, + color: UIColor) { + let nsStr = NSString(string: base.string) + let range = nsStr.range(of: str) + base.addAttributes([.font: font, + .foregroundColor: color], range: range) + } + // MARK: === 给文字添加下划线 + func addUnderLine() { + base.addAttributes([.underlineStyle: NSUnderlineStyle.single.rawValue], range: NSMakeRange(0, base.length)) + } + + func update(lineAlignment: NSTextAlignment) { + + let paragrapnStyle = NSMutableParagraphStyle() + paragrapnStyle.alignment = lineAlignment + base.addAttribute(.paragraphStyle, value: paragrapnStyle, range: NSMakeRange(0, base.length)) + } +} + + diff --git a/LingQi/LingQi/Tools/Extensions/String+Develop.swift b/LingQi/LingQi/Tools/Extensions/String+Develop.swift new file mode 100644 index 0000000..9825315 --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/String+Develop.swift @@ -0,0 +1,151 @@ +// +// String+HTDevelop.swift +// HTDevelop +// +// Created by 李扬 on 2019/1/5. +// Copyright © 2019 rrl360. All rights reserved. +// + +import UIKit + +public extension YCDevelop where Base == String { + /// 时间戳格式化为yyyy-MM-dd 时间戳是毫秒 + var dateFormatString: String { + if let interval = TimeInterval(base) { + let date = Date(timeIntervalSince1970: interval/1000) + let dateformatter = DateFormatter() + dateformatter.dateFormat = "yyyy-MM-dd" + return dateformatter.string(from: date) + } + return base + } + /// 去两边的空格 + var trimed: String { + return base.trimmingCharacters(in: .whitespaces) + } + /// 将原始的url编码为合法的url + var urlEncode: String { + return base.addingPercentEncoding(withAllowedCharacters: .urlFragmentAllowed) ?? base + } + /// 将编码后的url转换回原始的url + var urlDecode: String { + return base.removingPercentEncoding ?? base + } + + var isIdentityCard: Bool { + //判断是否为空 + if base.count <= 0 { + return false + } + //判断是否是18位,末尾是否是x + let regex2: String = "^(\\d{14}|\\d{17})(\\d|[xX])$" + let identityCardPredicate = NSPredicate(format: "SELF MATCHES %@", regex2) + if !identityCardPredicate.evaluate(with: base) { + return false + } + //判断生日是否合法 + let range = NSRange(location: 6, length: 8) + let datestr: String = (base as NSString).substring(with: range) + let formatter = DateFormatter() + formatter.dateFormat = "yyyyMMdd" + if formatter.date(from: datestr) == nil { + return false + } + //判断校验位 + if base.count == 18 { + let idCardWi: [String] = ["7", "9", "10", "5", "8", "4", "2", "1", "6", "3", "7", "9", "10", "5", "8", "4", "2"] + //将前17位加权因子保存在数组里 + let idCardY: [String] = ["1", "0", "10", "9", "8", "7", "6", "5", "4", "3", "2"] + //这是除以11后,可能产生的11位余数、验证码,也保存成数组 + var idCardWiSum: Int = 0 + //用来保存前17位各自乖以加权因子后的总和 + for i in 0..<17 { + idCardWiSum += Int((base as NSString).substring(with: NSRange(location: i, length: 1)))! * Int(idCardWi[i])! + } + let idCardMod: Int = idCardWiSum % 11 + //计算出校验码所在数组的位置 + let idCardLast: String = String(base[base.index(before: base.endIndex)]) + //得到最后一位身份证号码 + //如果等于2,则说明校验码是10,身份证号码最后一位应该是X + if idCardMod == 2 { + if idCardLast == "X" || idCardLast == "x" { + return true + } else { + return false + } + } else { + //用计算出的验证码与最后一位身份证号码匹配,如果一致,说明通过,否则是无效的身份证号码 + if (idCardLast as NSString).integerValue == Int(idCardY[idCardMod]) { + return true + } else { + return false + } + } + } + return false + } + + var isNotEmpty:Bool{ + return !base.isEmpty + } + var toJson:Dictionary?{ + let jsonData:Data = base.data(using: .utf8)! + let dict = try? JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers) + if dict != nil { + return dict as? Dictionary + } + return nil + } + + + var bankCardFormatter: String { + let characterSet = NSCharacterSet(charactersIn: "0123456789") + let text = base.replacingOccurrences(of: " ", with: "") as NSString + var newString = "" + let size = text.length/4 + var tempArr = [String]() + + for idx in 0.. Int { + if num1 <= num2 { + return num1 + }else{ + return num2 + } + } + + func mobilePhoneRegular() -> String { + guard base.yc.isValid(.phone) else { return base } + let result = base.prefix(3) + "****" + base.suffix(4) + return result.base + } + + /* + *去掉首尾空格 + */ + var removeHeadAndTailSpace:String { + let whitespace = NSCharacterSet.whitespaces + return base.trimmingCharacters(in: whitespace) + } + /* + *去掉首尾空格 包括后面的换行 \n + */ + var removeHeadAndTailSpacePro:String { + let whitespace = NSCharacterSet.whitespacesAndNewlines + return base.trimmingCharacters(in: whitespace) + } + /* + *去掉所有空格 + */ + var removeAllSapce: String { + return base.replacingOccurrences(of: " ", with: "", options: .literal, range: nil) + } +} + diff --git a/LingQi/LingQi/Tools/Extensions/String+Encryption.swift b/LingQi/LingQi/Tools/Extensions/String+Encryption.swift new file mode 100644 index 0000000..37f6d99 --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/String+Encryption.swift @@ -0,0 +1,286 @@ +// +// String+Encryption.swift +// rrlWallet +// +// Created by gordon on 2018/3/19. +// Copyright © 2018å¹´ rrl360. All rights reserved. +// + +import Foundation +import CommonCrypto + +public extension YCDevelop where Base == String { + + var base64Encode: String? { + if let data = base.data(using: .utf8) { + return data.base64EncodedString() + } + return nil + } + var base64Decode:String?{ + guard let data = Data(base64Encoded: base, options: NSData.Base64DecodingOptions.init(rawValue: 0)) else{ + return nil + } + let str = String(data: data as Data, encoding: String.Encoding.utf8) + return str + } + var md5: String { + guard let data = base.data(using: .utf8) else { + return base + } + + #if swift(>=5.0) + let message = data.withUnsafeBytes { (bytes: UnsafeRawBufferPointer) in + return [UInt8](bytes) + } + #else + let message = data.withUnsafeBytes { bytes in + return [UInt8](UnsafeBufferPointer(start: bytes, count: data.count)) + } + #endif + + let MD5Calculator = MD5(message) + let MD5Data = MD5Calculator.calculate() + + var MD5String = String() + for c in MD5Data { + MD5String += String(format: "%02x", c) + } + return MD5String + } +} + +// array of bytes, little-endian representation +func arrayOfBytes(_ value: T, length: Int? = nil) -> [UInt8] { + let totalBytes = length ?? (MemoryLayout.size * 8) + + let valuePointer = UnsafeMutablePointer.allocate(capacity: 1) + valuePointer.pointee = value + + let bytes = valuePointer.withMemoryRebound(to: UInt8.self, capacity: totalBytes) { (bytesPointer) -> [UInt8] in + var bytes = [UInt8](repeating: 0, count: totalBytes) + for j in 0...size, totalBytes) { + bytes[totalBytes - 1 - j] = (bytesPointer + j).pointee + } + return bytes + } + + #if swift(>=4.1) + valuePointer.deinitialize(count: 1) + valuePointer.deallocate() + #else + valuePointer.deinitialize() + valuePointer.deallocate(capacity: 1) + #endif + + return bytes +} + +extension Int { + // Array of bytes with optional padding (little-endian) + func bytes(_ totalBytes: Int = MemoryLayout.size) -> [UInt8] { + return arrayOfBytes(self, length: totalBytes) + } + +} + +extension NSMutableData { + + // Convenient way to append bytes + func appendBytes(_ arrayOfBytes: [UInt8]) { + append(arrayOfBytes, length: arrayOfBytes.count) + } + +} + +protocol HashProtocol { + var message: [UInt8] { get } + // Common part for hash calculation. Prepare header data. + func prepare(_ len: Int) -> [UInt8] +} + +extension HashProtocol { + + func prepare(_ len: Int) -> [UInt8] { + var tmpMessage = message + + // Step 1. Append Padding Bits + tmpMessage.append(0x80) // append one bit (UInt8 with one bit) to message + + // append "0" bit until message length in bits ≡ 448 (mod 512) + var msgLength = tmpMessage.count + var counter = 0 + + while msgLength % len != (len - 8) { + counter += 1 + msgLength += 1 + } + + tmpMessage += [UInt8](repeating: 0, count: counter) + return tmpMessage + } +} + +func toUInt32Array(_ slice: ArraySlice) -> [UInt32] { + var result = [UInt32]() + result.reserveCapacity(16) + + for idx in stride(from: slice.startIndex, to: slice.endIndex, by: MemoryLayout.size) { + let d0 = UInt32(slice[idx.advanced(by: 3)]) << 24 + let d1 = UInt32(slice[idx.advanced(by: 2)]) << 16 + let d2 = UInt32(slice[idx.advanced(by: 1)]) << 8 + let d3 = UInt32(slice[idx]) + let val: UInt32 = d0 | d1 | d2 | d3 + + result.append(val) + } + return result +} + +struct BytesIterator: IteratorProtocol { + + let chunkSize: Int + let data: [UInt8] + + init(chunkSize: Int, data: [UInt8]) { + self.chunkSize = chunkSize + self.data = data + } + + var offset = 0 + + mutating func next() -> ArraySlice? { + let end = min(chunkSize, data.count - offset) + let result = data[offset.. 0 ? result : nil + } +} + +struct BytesSequence: Sequence { + let chunkSize: Int + let data: [UInt8] + + func makeIterator() -> BytesIterator { + return BytesIterator(chunkSize: chunkSize, data: data) + } +} + +func rotateLeft(_ value: UInt32, bits: UInt32) -> UInt32 { + return ((value << bits) & 0xFFFFFFFF) | (value >> (32 - bits)) +} + +class MD5: HashProtocol { + + static let size = 16 // 128 / 8 + let message: [UInt8] + + init (_ message: [UInt8]) { + self.message = message + } + + // specifies the per-round shift amounts + private let shifts: [UInt32] = [7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21] + + // binary integer part of the sines of integers (Radians) + private let sines: [UInt32] = [0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391] + + private let hashes: [UInt32] = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476] + + func calculate() -> [UInt8] { + var tmpMessage = prepare(64) + tmpMessage.reserveCapacity(tmpMessage.count + 4) + + // hash values + var hh = hashes + + // Step 2. Append Length a 64-bit representation of lengthInBits + let lengthInBits = (message.count * 8) + let lengthBytes = lengthInBits.bytes(64 / 8) + tmpMessage += lengthBytes.reversed() + + // Process the message in successive 512-bit chunks: + let chunkSizeBytes = 512 / 8 // 64 + + for chunk in BytesSequence(chunkSize: chunkSizeBytes, data: tmpMessage) { + // break chunk into sixteen 32-bit words M[j], 0 ≤ j ≤ 15 + let M = toUInt32Array(chunk) + assert(M.count == 16, "Invalid array") + + // Initialize hash value for this chunk: + var A: UInt32 = hh[0] + var B: UInt32 = hh[1] + var C: UInt32 = hh[2] + var D: UInt32 = hh[3] + + var dTemp: UInt32 = 0 + + // Main loop + for j in 0 ..< sines.count { + var g = 0 + var F: UInt32 = 0 + + switch j { + case 0...15: + F = (B & C) | ((~B) & D) + g = j + break + case 16...31: + F = (D & B) | (~D & C) + g = (5 * j + 1) % 16 + break + case 32...47: + F = B ^ C ^ D + g = (3 * j + 5) % 16 + break + case 48...63: + F = C ^ (B | (~D)) + g = (7 * j) % 16 + break + default: + break + } + dTemp = D + D = C + C = B + B = B &+ rotateLeft((A &+ F &+ sines[j] &+ M[g]), bits: shifts[j]) + A = dTemp + } + + hh[0] = hh[0] &+ A + hh[1] = hh[1] &+ B + hh[2] = hh[2] &+ C + hh[3] = hh[3] &+ D + } + var result = [UInt8]() + result.reserveCapacity(hh.count / 4) + + hh.forEach { + let itemLE = $0.littleEndian + let r1 = UInt8(itemLE & 0xff) + let r2 = UInt8((itemLE >> 8) & 0xff) + let r3 = UInt8((itemLE >> 16) & 0xff) + let r4 = UInt8((itemLE >> 24) & 0xff) + result += [r1, r2, r3, r4] + } + return result + } +} diff --git a/LingQi/LingQi/Tools/Extensions/String+RegExp.swift b/LingQi/LingQi/Tools/Extensions/String+RegExp.swift new file mode 100644 index 0000000..48a4215 --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/String+RegExp.swift @@ -0,0 +1,118 @@ +// +// String+Regexp.swift +// HTDevelop +// +// Created by 李扬 on 2019/1/5. +// Copyright © 2019 rrl360. All rights reserved. +// + +import UIKit + +public enum RegExpType { + case money + case telephone + case phone + case mobile + case verifyCode4 + case verifyCode6 + case email + case identityNo + case password + case zhWords + case enWords + case allEnWords + case zhAnden + case nickName + case WeChatCode + case AlipayCode + case bankCard + case custom(String) +} + +public extension YCDevelop where Base == String { + + // MARK: === 正则校验 + func isValid(_ type: RegExpType) -> Bool { + let predicate = NSPredicate.init(format: "SELF MATCHES %@", type.regStr) + return predicate.evaluate(with: base) + } +} + +extension RegExpType { + var regStr: String { + switch self { + case .money: + return "^[0-9.]" + case .telephone: + return "0\\d{2,3}-\\d{7,8}|\\(?0\\d{2,3}[)-]?\\d{7,8}|\\(?0\\d{2,3}[)-]*\\d{7,8}" + case .phone: + return "^1[3456789]\\d{9}$" + case .verifyCode4: + return "^[0-9]{4}$" + case .verifyCode6: + return "^[0-9]{6}$" + case .mobile: +// return "(^1(3[0-9]|4[57]|5[0-35-9]|66|7[6-8]|8[0-9]|9[8-9])\\d{8}$)|(^170[059]\\d{7}$)" + return "^[1]([3-9])[0-9]{9}$" + case .email: + return "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,10}" + case .identityNo: + return "^(\\d{14}|\\d{17})(\\d|[xX])$" +// case .password: +// return "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,16}$" + case .password: + return "^{6,16}$" + case .zhWords: + return "[\\u4e00-\\u9fa5]+" + case .enWords: + return "[a-zA-Z0-9]+" + case .allEnWords: + return "[a-zA-Z]+" + case .zhAnden: + return "[a-zA-Z0-9\\u4e00-\\u9fa5]+" + case .nickName: + return "[a-zA-Z0-9\\u4e00-\\u9fa5]{1,15}$" + case .WeChatCode: + return "^1[012345][0-9]{16}$" + case .AlipayCode: + return "^(2[56789]|30)[0-9]{14,22}$" + case .custom(let str): + return str + case .bankCard: + return "^(\\d{10,30})" + } + } + + func customPassword(min: Int, + max: Int, + containDigtal: Bool, + containLetter: Bool, + containCapital: Bool, + containOtherCharacter: Bool, + firstCannotBeDigtal: Bool) -> String { + let first = firstCannotBeDigtal ? "^[a-zA-Z_]" : "" + let lengthRegex = "(?=^.{\(min),\(max)}$)" + let digtalRegex = containDigtal ? "(?=(.*\\d.*){1})" : "" + let letterRegex = containLetter ? "(?=(.*[a-z].*){1})" : "" + let capitalRegex = containLetter ? "(?=(.*[A-Z].*){1})" : "" + let characterRegex = String(format: "(?:%@[A-Za-z0-9%@]+)", first, containOtherCharacter ? containOtherCharacter : "") + return lengthRegex + digtalRegex + letterRegex + capitalRegex + characterRegex + } +} + +/* +private let regex_金额 = "^[0-9.]" +private let regex_手机号 = "^[1][0-9]{10}$" +private let regex_邮箱 = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,5}" +private let regex_身份证号 = "^(\\d{14}|\\d{17})(\\d|[xX])$" +private let regex_密码 = "^[0-9A-Za-z~!@#$^&|*-_+=.?,]{5,20}$" + + // 字母数字下划线 + "^[0-9a-zA-Z_]{2,20}$" + // 字母 数字 汉子 + "[a-zA-Z0-9\u4e00-\u9fa5]+" + // 字母 数字 汉子 特殊符号 + "[0-9a-zA-Z\u4e00-\u9fa5\\.\\*\\)\\(\\+\\$\\[\\?\\\\\\^\\{\\|\\]\\}%%%@\'\",。‘、-【】·!_——=:;;<>《》‘’“”!#~]+" + // 6-15位 大小写字母数字 + "(?=^.{6,15}$)(?=(.*\\d.*){1})(?=(.*[a-z].*){1})(?=(.*[A-Z].*){1})(?:[A-Za-z0-9!@#$%^&*?\\(\\)]+)" + */ diff --git a/LingQi/LingQi/Tools/Extensions/String+SubString.swift b/LingQi/LingQi/Tools/Extensions/String+SubString.swift new file mode 100644 index 0000000..8f90172 --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/String+SubString.swift @@ -0,0 +1,45 @@ +// +// String+SubString.swift +// YCDevTools +// +// Created by liangzhenying on 2020/5/22. +// Copyright © 2020 zkys. All rights reserved. +// + +import Foundation +// MARK: - 字符串截取 +public extension YCDevelop where Base == String{ + /// String使用下标截取字符串 + /// string[index] 例如:"abcdefg"[3] // c + subscript (i:Int)->String{ + let startIndex = base.index(base.startIndex, offsetBy: i) + let endIndex = base.index(startIndex, offsetBy: 1) + return String(base[startIndex..) -> String { + get { + let startIndex = base.index(base.startIndex, offsetBy: r.lowerBound) + let endIndex = base.index(base.startIndex, offsetBy: r.upperBound) + return String(base[startIndex.. String { + get { + let startIndex = base.index(base.startIndex, offsetBy: index) + let endIndex = base.index(startIndex, offsetBy: length) + return String(base[startIndex.. String{ + return self[0.. String{ + return self[from..Bool{ + return self.value + 1 == nextDay.value + } + } + + //周一,周二,周日,周六,周五,周三,周四 改成周一至周日 + func weekFormater() -> String{ + let text = base + var days = text.split(separator: ",").map{String($0).yc.week()} + days.sort { (item1, item2) -> Bool in + return item1.value < item2.value + } + k_log(days) + if days.count <= 1 { + return text + } + else if days.count == 7{ + return "周一至周日" + } + else{ +// let sum = days.map{$0.name}.joined(separator: ",") +// return sum + return text + } + } +// //周一,周二,周日,周六,周五,周三,周四 改成周一至周日 +// func weekFormater() -> String{ +//// let test = "周一,周二,周日,周六,周五,周三,周四" +// let test = "周一,周二,周日,周五,周四" +// var days = test.split(separator: ",").map{String($0).yc.week()} +// days.sort { (item1, item2) -> Bool in +// return item1.value < item2.value +// } +// k_log(days) +// if days.count == 0 { +// return test +// } +// var section = [[WeekDay]]() +// let count = days.count +// +// var i = 0 +// while i < count - 1 { +// var row = [WeekDay]() +// var current = days[i] +// row.append(current) +// for j in i+1 ..< count { +// let next = days[j] +// if current.isNear(nextDay: next){ +// current = next +// row.append(next) +// if j == count - 1 { +// i = j +// break +// } +// } +// else{ +// i = j +// break +// } +// } +// section.append(row) +// } +// +// var textList = [String]() +// for row in section { +// if row.count == 1 { +// textList.append(row.first!.name) +// } +// else if row.count > 1 { +// let text = row.first!.name + "至" + row.last!.name +// textList.append(text) +// } +// } +// let sum = textList.joined(separator: ",") +// return sum +// } + + private func week() -> WeekDay { + switch base { + case "周一": + return .Mon + case "周二": + return .Tue + case "周三": + return .Wed + case "周四": + return .Thur + case "周五": + return .Fri + case "周六": + return .Sat + case "周日": + return .Sun + default: + return .Mon + } + } +} diff --git a/LingQi/LingQi/Tools/Extensions/String+YL.swift b/LingQi/LingQi/Tools/Extensions/String+YL.swift new file mode 100644 index 0000000..b46db1d --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/String+YL.swift @@ -0,0 +1,13 @@ +// +// File.swift +// zgjd +// +// Created by apple on 2020/11/12. +// + +import Foundation +extension String{ + var isNotEmpty:Bool{ + return !self.isEmpty + } +} diff --git a/LingQi/LingQi/Tools/Extensions/StringURL+Develop.swift b/LingQi/LingQi/Tools/Extensions/StringURL+Develop.swift new file mode 100644 index 0000000..53854c4 --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/StringURL+Develop.swift @@ -0,0 +1,62 @@ +// +// URL+HTDevelop.swift +// rrlWallet +// +// Created by gordon on 2018/10/26. +// Copyright © 2018 rrl360. All rights reserved. +// + +import UIKit + +public extension YCDevelop where Base == String { + + /// to URL? + var asUrl: URL? { return URL(string: base.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? base) } + + /// 获取url?后面的参数 + var urlQueries: [String: String] { + let urlPaths = base.components(separatedBy: "?") + guard urlPaths.count == 2 else { return [:] } + let paths = urlPaths[1].components(separatedBy: "&") + var queries = [String: String]() + for q in paths { + if let k = q.range(of: "=") { + let kStr = q[.. 上午/中午/下午/晚上 + static var timePeriod: String { + let hour = DateInRegion(Date(), region: .local).hour + switch hour { + case 6 ..< 10: + return "早上" + case 10 ..< 14: + return "中午" + case 14 ... 18: + return "下午" + default: + return "晚上" + } + } + + /// 获取当前 秒级 时间戳 - 10位 + static var timeStamp : String { + let timeInterval: TimeInterval = Date().timeIntervalSince1970 + let timeStamp = Int(timeInterval) + return "\(timeStamp)" + } + + /// 获取当前 毫秒级 时间戳 - 13位 + static var milliStamp : String { + let timeInterval: TimeInterval = Date().timeIntervalSince1970 + let millisecond = CLongLong(round(timeInterval*1000)) + return "\(millisecond)" + } + + /// 获取当前时间 (2020-02-02 02:02:02) + static var currentTime : String { + let dformatter = DateFormatter() + dformatter.dateFormat = "yyyy-MM-dd HH:mm:ss" + let datestr = dformatter.string(from: Date()) + return datestr + } + /// 获取当前日期 (02-02 ) + static var currentDate : String { + let dformatter = DateFormatter() + dformatter.dateFormat = "MM-dd" + let datestr = dformatter.string(from: Date()) + return datestr + } +} + +public extension YCDevelop where Base == String { + func toDate(formatter:String) ->Date?{ + let df = DateFormatter() + df.timeZone = TimeZone.current + df.dateFormat = formatter + let date = df.date(from: base) + return date + } +} + diff --git a/LingQi/LingQi/Tools/Extensions/UIApplication+Develop.swift b/LingQi/LingQi/Tools/Extensions/UIApplication+Develop.swift new file mode 100644 index 0000000..a596bbc --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/UIApplication+Develop.swift @@ -0,0 +1,65 @@ +// +// UIApplication+HTDevelop.swift +// rrlWallet +// +// Created by Gordon on 2018/3/1. +// Copyright © 2018å¹´ rrl360. All rights reserved. +// + +import UIKit + +public extension YCDevelop where Base: UIViewController { + + static var currentVC: UIViewController? { + return getTopVC(withRootVC: UIApplication.yc.keyWindow?.rootViewController) + } + static var currentNav: UINavigationController? { + return currentVC?.navigationController + } +} + +public extension YCDevelop where Base: UIApplication { + + static var keyWindow: UIWindow? { + return UIApplication.shared.keyWindow +// var window: UIWindow? = nil +// if #available(iOS 13.0, *) { +// let scenes = UIApplication.shared.connectedScenes as? Set ?? [] +// for scene in scenes where scene.activationState == .foregroundActive { +// window = scene.windows.first +// break +// } +// return window +// } else { +// return UIApplication.shared.keyWindow +// } + } + + static var currentVC: UIViewController? { + guard + let tabbarVC = keyWindow?.rootViewController as? UITabBarController + else { return nil } + return getTopVC(withRootVC: tabbarVC) + } + + static var currentNav: UINavigationController? { + return currentVC?.navigationController + } +} + +private func getTopVC(withRootVC rootVC: UIViewController?) -> UIViewController? { + guard let root = rootVC else { return nil } + if root is UITabBarController { + return getTopVC(withRootVC: (root as? UITabBarController)?.selectedViewController) + } + else if root is UINavigationController { + return getTopVC(withRootVC: (root as? UINavigationController)?.visibleViewController) + } + else if let modalVC = root.presentedViewController { + return getTopVC(withRootVC: modalVC) + } + else { + return root + } +} + diff --git a/LingQi/LingQi/Tools/Extensions/UIButton+Develop.swift b/LingQi/LingQi/Tools/Extensions/UIButton+Develop.swift new file mode 100644 index 0000000..8b76f86 --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/UIButton+Develop.swift @@ -0,0 +1,130 @@ +// +// UIButton+HTDevelop.swift +// rrlWallet +// +// Created by Gordon on 2018/2/28. +// Copyright © 2018å¹´ rrl360. All rights reserved. +// + +import UIKit + +public enum HTImagePosition { + /// 图片在左,文字在右 + case left + /// 图片在右,文字在左 + case right + /// 图片在上,文字在下 + case top + /// 图片在下,文字在上 + case bottom +} + +public extension YCDevelop where Base: UIButton { + + /// 设置button中图片文字的位置 + /// - Requires: + /// * (imageView & titleLabel) both initialized + /// * `top` & `bottom` need a pre final Width & Height Constraint + /// - Parameters: + /// - position: 图片位置 + /// - spacing: 间距 + func setImagePosition(_ position: HTImagePosition, spacing: CGFloat) { + guard let label = base.titleLabel else { return } + let title = label.text ?? "" + let imageSize = base.imageView?.image?.size ?? .zero + let constraints = CGSize(width: base.width, height: base.height) + let imgWid = imageSize.width + let imgHei = imageSize.height + let txtSize = title.yc.strSize(font: label.font, constraints: constraints) + let txtWid = txtSize.width + let txtHei = txtSize.height + + switch position { + case .left: + base.imageEdgeInsets = UIEdgeInsets(top: 0, + left: -spacing.half, + bottom: 0, + right: spacing.half) + base.titleEdgeInsets = UIEdgeInsets(top: 0, + left: spacing.half, + bottom: 0, + right: -spacing.half) + case .right: + base.imageEdgeInsets = UIEdgeInsets(top: 0, + left: txtWid + spacing.half, + bottom: 0, + right: -(txtWid + spacing.half)) + base.titleEdgeInsets = UIEdgeInsets(top: 0, + left: -(imgWid + spacing.half), + bottom: 0, + right: imgWid + spacing.half) + case .top: +// let imageLeft = max(imgWid, txtWid).half - imgWid.half +// let titleLeft = (max(imgWid, txtWid) - txtWid).half + min(imgWid, txtWid) +// let totalHei = imgHei + txtHei + spacing +// let imageTop = (base.height - totalHei).half +// let imageBtm = base.height - (imageTop + imgHei) - spacing.half +// let titleTop = imageTop + imgHei + spacing.half +// let titleBtm = -imageTop +// base.imageEdgeInsets = UIEdgeInsets(top: imageTop, +// left: imageLeft, +// bottom: imageBtm, +// right: -imageLeft) +// base.titleEdgeInsets = UIEdgeInsets(top: titleTop, +// left: -titleLeft, +// bottom: titleBtm, +// right: titleLeft) + let imageLeft = (constraints.width - imgWid).half + let totalHei = imgHei + txtHei + spacing + let imageTop = (constraints.height - totalHei).half + let imageBtm = constraints.height - (imageTop + imgHei) - spacing.half + let titleTop = imageTop + imgHei + spacing.half + let titleBtm = -imageTop + base.imageEdgeInsets = UIEdgeInsets(top: imageTop, + left: imageLeft, + bottom: imageBtm, + right: -imageLeft) + base.titleEdgeInsets = UIEdgeInsets(top: titleTop, + left: -imgWid, + bottom: titleBtm, + right: 0) + case .bottom: + let imageLeft = max(imgWid, txtWid).half - imgWid.half + let totalHei = imgHei + txtHei + spacing + let titleTop = (base.height - totalHei).half + let titleBtm = base.height - (titleTop + txtHei) - spacing.half + let imageTop = titleTop + txtHei + spacing.half + let imageBtm = -titleTop + base.imageEdgeInsets = UIEdgeInsets(top: imageTop, + left: imageLeft, + bottom: imageBtm, + right: -imageLeft) + base.titleEdgeInsets = UIEdgeInsets(top: titleTop, + left: -imgWid, + bottom: titleBtm, + right: 0) + } + } + + + /// 交换imageview和label的位置 + func exchangeLabelAndImagePosition(interval: CGFloat) { + let imageW = (base.imageView?.bounds.width ?? 0.0) + interval * 0.5 + let lableW = (base.titleLabel?.bounds.width ?? 0.0) + interval * 0.5 + base.titleEdgeInsets = UIEdgeInsets(top: 0, left: -imageW, bottom: 0, right: imageW) + base.imageEdgeInsets = UIEdgeInsets(top: 0, left: lableW, bottom: 0, right: -lableW) + } + /// 设置imageview和label的间距 + func setLabelAndImageInterval(_ interval: CGFloat) { + base.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: interval) + base.titleEdgeInsets = UIEdgeInsets(top: 0, left: interval, bottom: 0, right: 0) + } + + func clearImageLabelInsets() { + base.titleEdgeInsets = UIEdgeInsets.zero + base.imageEdgeInsets = UIEdgeInsets.zero + } + +} + + diff --git a/LingQi/LingQi/Tools/Extensions/UIDevice+Landscape.swift b/LingQi/LingQi/Tools/Extensions/UIDevice+Landscape.swift new file mode 100644 index 0000000..31738c1 --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/UIDevice+Landscape.swift @@ -0,0 +1,16 @@ +// +// UIDevice+Landscape.swift +// LandscapeDemo +// +// Created by memory on 2021/4/12. +// + +import UIKit +extension UIDevice{ + static func switchOrientation(orientation :UIInterfaceOrientation){ + let value = orientation.rawValue + if UIDevice.current.responds(to: #selector(setValue(_:forKey:))) { + UIDevice.current.setValue(value, forKey: "orientation") + } + } +} diff --git a/LingQi/LingQi/Tools/Extensions/UIImage+Develop.swift b/LingQi/LingQi/Tools/Extensions/UIImage+Develop.swift new file mode 100644 index 0000000..ff013a1 --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/UIImage+Develop.swift @@ -0,0 +1,236 @@ +// +// UIImage+Develop.swift +// YCDevTools +// +// Created by Liang ZhenYing on 2020/3/5. +// Copyright © 2020 zkys. All rights reserved. +// + +import UIKit +import Photos +import AssetsLibrary + +public extension YCDevelop where Base: UIImage { + + /// 返回一张带有颜色尺寸带圆角的 image + static func image(color:UIColor, size: CGSize, cornerRadius: CGFloat) -> UIImage { + + let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height) + let path = UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius) + path.lineWidth = 0 + UIGraphicsBeginImageContextWithOptions(rect.size, false, 0) + let context = UIGraphicsGetCurrentContext() + context?.setFillColor(color.cgColor) + path.fill() + path.stroke() + path.addClip() + + let img = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + return img! + } + + /// 返回一张带有颜色尺寸带 自定义圆角的 image + static func image(withCorners corners: UIRectCorner, color:UIColor, size: CGSize, cornerRadius: CGFloat) -> UIImage { + + let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height) + let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: cornerRadius, height: cornerRadius)) + path.lineWidth = 0 + UIGraphicsBeginImageContextWithOptions(rect.size, false, 0) + let context = UIGraphicsGetCurrentContext() + context?.setFillColor(color.cgColor) + path.fill() + path.stroke() + path.addClip() + + let img = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + return img! + } + + static func isEqual(lhs: UIImage, rhs: UIImage) -> Bool { + guard let data1 = lhs.pngData(), + let data2 = rhs.pngData() else { + return false + } + return data1 == data2 + } + + /// 裁剪图片 -> 方形图片 + func squareImg() -> UIImage { + let wid = base.size.width + let hei = base.size.height + var n_x = (wid - hei) * 0.5 + var n_y:CGFloat = 0 + var n_w = hei + var n_h = hei + if wid < hei { + n_x = 0 + n_y = (hei - wid) * 0.5 + n_w = wid + n_h = wid + } + let rect = CGRect.init(x: n_x, y: n_y, width: n_w, height: n_h) + guard let newImg = base.cgImage?.cropping(to: rect) else { return UIImage() } + return UIImage.init(cgImage: newImg) + } +} + +public extension YCDevelop where Base: UIImage { + + /// 改变图标的颜色,用于小图标绘制 + /// ## 只用于纯色图标 ## + /// - Parameter tintColor: 目标颜色 + /// + /// - Returns: 改变颜色后的image + func tint(_ tintColor: UIColor) -> UIImage { + UIGraphicsBeginImageContextWithOptions(base.size, false, 0) + tintColor.setFill() + let bounds = CGRect.init(x: 0, y: 0, width: base.size.width, height: base.size.height) + UIRectFill(bounds) + base.draw(in: bounds, blendMode: .destinationIn, alpha: 1) + let tintedImage = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + return tintedImage! + } + + /// 缩小图片大小 + func scale(to newSize: CGSize) -> UIImage { + guard base.size != newSize else { return base } + let scaledRect = fixPictureSize(newSize: newSize) + UIGraphicsBeginImageContextWithOptions(scaledRect.size, false, UIScreen.main.scale) + defer { UIGraphicsEndImageContext() } + base.draw(in: scaledRect) + return UIGraphicsGetImageFromCurrentImageContext() ?? UIImage() + } + private func fixPictureSize(newSize: CGSize) -> CGRect { + let ratio = max(newSize.width / base.size.width, + newSize.height / base.size.height) + let width = base.size.width * ratio + let height = base.size.height * ratio + let scaledRect = CGRect(x: 0, y: 0, + width: width, height: height) + return scaledRect + } + + /// 给图片切圆角 + func drawRectWithRoundedCorner(radius: CGFloat, _ sizetoFit: CGSize) -> UIImage { + guard radius > 0 else { return base } + let rect = CGRect(origin: CGPoint(x: 0, y: 0), size: sizetoFit) + UIGraphicsBeginImageContextWithOptions(rect.size, false, UIScreen.main.scale) + let context = UIGraphicsGetCurrentContext()! + let path = UIBezierPath(roundedRect: rect, cornerRadius: radius).cgPath + context.addPath(path) + context.clip() + base.draw(in: rect) + context.drawPath(using: .fillStroke) + defer { UIGraphicsEndImageContext() } + return UIGraphicsGetImageFromCurrentImageContext() ?? UIImage() + } +} + +// MARK: - ********* 压缩图片 +public extension YCDevelop where Base: UIImage { + + /// 压缩图片大小 + /// 分享图片 使用此方法压缩 + /// - Parameter size: 压缩后的大小(单位:k) 默认32k + /// - Returns: 压缩好的图片 + func compressTo(_ size: Int = 32) -> Data? { + + let maxFileSize = size * 1000 + var compression: CGFloat = 1 + + guard var compressedData = base.jpegData(compressionQuality: compression) else { return nil } + compression = 0.95 + while compressedData.count > maxFileSize { + compression = 0.95 * compression + let toCompressImg = scaleCompress(toWidth: base.size.width * compression) + compressedData = toCompressImg.jpegData(compressionQuality: compression)! + } + return compressedData + } + + /// 等比缩放本图片大小 + /// + /// - Parameter toWidth: 缩放后图片宽度,像素为单位 + /// - Returns: 缩放后的图片 + private func scaleCompress(toWidth wid: CGFloat) -> UIImage { + + let imgW = base.size.width + let imgH = base.size.height + let newW = wid + let newH = imgH / (imgW / newW) + let wScale = imgW / newW + let hScale = imgH / newH + + UIGraphicsBeginImageContext(.init(width: newW, height: newH)) + if wScale > hScale { + base.draw(in: .init(x: 0, y: 0, width: imgW/hScale, height: newH)) + } else { + base.draw(in: .init(x: 0, y: 0, width: newW, height: imgH/wScale)) + } + let newImg = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + return newImg ?? UIImage() + } +} + +// MARK: - ********* 相册 +//public extension YCDevelop where Base: UIImage { +// // MARK: === 保存到相册 +// func save2Album(_ isPermitted: ((Bool) -> Void)? = nil, _ callback: ((Bool) -> Void)?) { +// let img = base +// YCPermissions.authorizePhoto(comletion: { (permit) in +// if permit { +// PHPhotoLibrary.shared().performChanges({ +// PHAssetChangeRequest.creationRequestForAsset(from: img) +// }) { (isSuccess, _) in +// DispatchQueue.main.async { +// callback?(isSuccess) +// } +// } +// isPermitted?(true) +// } else { +// YCPermissions.alertNoPermission(.photo) +// isPermitted?(false) +// } +// }) +// } +//} + + +//extension UIImage { +// +// func imageWith(newSize: CGSize) -> UIImage { +// let renderer = UIGraphicsImageRenderer(size: newSize) +// let image = renderer.image {_ in +// draw(in: CGRect(origin: .zero, size: newSize)) +// } +// +// return image +// } +// +// func imageByBestFit(for targetSize: CGSize) -> UIImage { +// let aspectRatio = size.width / size.height +// let targetHeight = targetSize.height +// let scaledWidth = targetSize.height * aspectRatio +// +// let bestSize = CGSize(width: scaledWidth, height: targetHeight) +// return imageWith(newSize: bestSize) +// } +// +//} +// +//extension Optional where Wrapped == UIImage { +// func isSame(photo: UIImage?) -> Bool { +// switch (self, photo) { +// case (nil, nil): +// return true +// case (nil, _), (_, nil): +// return false +// case (let p1, let p2): +// return p1!.isEqual(p2) +// } +// } +//} diff --git a/LingQi/LingQi/Tools/Extensions/UIImage+Gif.swift b/LingQi/LingQi/Tools/Extensions/UIImage+Gif.swift new file mode 100644 index 0000000..88648f8 --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/UIImage+Gif.swift @@ -0,0 +1,225 @@ +// +// UIImage+Gif.swift +// HTDevelopTools +// +// Created by 胡庚伟 on 2019/3/8. +// Copyright © 2019 Exaleap. All rights reserved. +// + +import UIKit +import ImageIO + +extension UIImageView { + + public func loadGif(name: String) { + DispatchQueue.global().async { + let image = UIImage.gif(name: name) + DispatchQueue.main.async { + self.image = image + } + } + } + + @available(iOS 9.0, *) + public func loadGif(asset: String) { + DispatchQueue.global().async { + let image = UIImage.gif(asset: asset) + DispatchQueue.main.async { + self.image = image + } + } + } + +} + +extension UIImage { + + public class func gif(data: Data) -> UIImage? { + // Create source from data + guard let source = CGImageSourceCreateWithData(data as CFData, nil) else { + print("SwiftGif: Source for the image does not exist") + return nil + } + + return UIImage.animatedImageWithSource(source) + } + + public class func gif(url: String) -> UIImage? { + // Validate URL + guard let bundleURL = URL(string: url) else { + print("SwiftGif: This image named \"\(url)\" does not exist") + return nil + } + + // Validate data + guard let imageData = try? Data(contentsOf: bundleURL) else { + print("SwiftGif: Cannot turn image named \"\(url)\" into NSData") + return nil + } + + return gif(data: imageData) + } + + public class func gif(name: String) -> UIImage? { + // Check for existance of gif + guard let bundleURL = Bundle.main + .url(forResource: name, withExtension: "gif") else { + print("SwiftGif: This image named \"\(name)\" does not exist") + return nil + } + + // Validate data + guard let imageData = try? Data(contentsOf: bundleURL) else { + print("SwiftGif: Cannot turn image named \"\(name)\" into NSData") + return nil + } + + return gif(data: imageData) + } + + @available(iOS 9.0, *) + public class func gif(asset: String) -> UIImage? { + // Create source from assets catalog + guard let dataAsset = NSDataAsset(name: asset) else { + print("SwiftGif: Cannot turn image named \"\(asset)\" into NSDataAsset") + return nil + } + + return gif(data: dataAsset.data) + } + + internal class func delayForImageAtIndex(_ index: Int, source: CGImageSource!) -> Double { + var delay = 0.1 + + // Get dictionaries + let cfProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil) + let gifPropertiesPointer = UnsafeMutablePointer.allocate(capacity: 0) + defer { + gifPropertiesPointer.deallocate() + } + if CFDictionaryGetValueIfPresent(cfProperties, Unmanaged.passUnretained(kCGImagePropertyGIFDictionary).toOpaque(), gifPropertiesPointer) == false { + return delay + } + + let gifProperties:CFDictionary = unsafeBitCast(gifPropertiesPointer.pointee, to: CFDictionary.self) + + // Get delay time + var delayObject: AnyObject = unsafeBitCast( + CFDictionaryGetValue(gifProperties, + Unmanaged.passUnretained(kCGImagePropertyGIFUnclampedDelayTime).toOpaque()), + to: AnyObject.self) + if delayObject.doubleValue == 0 { + delayObject = unsafeBitCast(CFDictionaryGetValue(gifProperties, + Unmanaged.passUnretained(kCGImagePropertyGIFDelayTime).toOpaque()), to: AnyObject.self) + } + + if let delayObject = delayObject as? Double, delayObject > 0 { + delay = delayObject + } else { + delay = 0.1 // Make sure they're not too fast + } + + return delay + } + + internal class func gcdForPair(_ a: Int?, _ b: Int?) -> Int { + var a = a + var b = b + // Check if one of them is nil + if b == nil || a == nil { + if b != nil { + return b! + } else if a != nil { + return a! + } else { + return 0 + } + } + + // Swap for modulo + if a! < b! { + let c = a + a = b + b = c + } + + // Get greatest common divisor + var rest: Int + while true { + rest = a! % b! + + if rest == 0 { + return b! // Found it + } else { + a = b + b = rest + } + } + } + + internal class func gcdForArray(_ array: Array) -> Int { + if array.isEmpty { + return 1 + } + + var gcd = array[0] + + for val in array { + gcd = UIImage.gcdForPair(val, gcd) + } + + return gcd + } + + internal class func animatedImageWithSource(_ source: CGImageSource) -> UIImage? { + let count = CGImageSourceGetCount(source) + var images = [CGImage]() + var delays = [Int]() + + // Fill arrays + for i in 0.. +@import Accelerate; + +@implementation UIImage (ImageEffects) + + +- (UIImage *)applyLightEffect{ + + UIColor *tintColor = [UIColor colorWithWhite:1.0 alpha:0.3]; + return [self applyBlurWithRadius:30 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil]; +} + + +- (UIImage *)applyExtraLightEffect { + + UIColor *tintColor = [UIColor colorWithWhite:0.97 alpha:0.82]; + return [self applyBlurWithRadius:20 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil]; +} + + +- (UIImage *)applyDarkEffect { + + UIColor *tintColor = [UIColor colorWithWhite:0.11 alpha:0.73]; + return [self applyBlurWithRadius:20 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil]; +} + + +- (UIImage *)applyTintEffectWithColor:(UIColor *)tintColor { + + const CGFloat EffectColorAlpha = 0.6; + UIColor *effectColor = tintColor; + int componentCount = (int)CGColorGetNumberOfComponents(tintColor.CGColor); + + if (componentCount == 2) { + + CGFloat b; + if ([tintColor getWhite:&b alpha:NULL]) { + + effectColor = [UIColor colorWithWhite:b alpha:EffectColorAlpha]; + } + + } else { + + CGFloat r, g, b; + if ([tintColor getRed:&r green:&g blue:&b alpha:NULL]) { + + effectColor = [UIColor colorWithRed:r green:g blue:b alpha:EffectColorAlpha]; + } + } + + return [self applyBlurWithRadius:20 tintColor:effectColor saturationDeltaFactor:1.4 maskImage:nil]; +} + +- (UIImage *)blurImage { + + return [self applyBlurWithRadius:20 + tintColor:[UIColor colorWithWhite:0 alpha:0.0] + saturationDeltaFactor:1.4 + maskImage:nil]; +} + +- (UIImage *)blurImageWithRadius:(CGFloat)radius { + + return [self applyBlurWithRadius:radius + tintColor:[UIColor colorWithWhite:0 alpha:0.0] + saturationDeltaFactor:1.4 + maskImage:nil]; +} + +- (UIImage *)blurImageWithMask:(UIImage *)maskImage { + + return [self applyBlurWithRadius:20 + tintColor:[UIColor colorWithWhite:0 alpha:0.0] + saturationDeltaFactor:1.4 + maskImage:maskImage]; +} + +- (UIImage *)blurImageAtFrame:(CGRect)frame { + + return [self applyBlurWithRadius:20 + tintColor:[UIColor colorWithWhite:0 alpha:0.0] + saturationDeltaFactor:1.4 + maskImage:nil + atFrame:frame]; +} + +- (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage { + + // Check pre-conditions. + if (self.size.width < 1 || self.size.height < 1) { + + NSLog (@"*** error: invalid size: (%.2f x %.2f). Both dimensions must be >= 1: %@", self.size.width, self.size.height, self); + return nil; + } + + if (!self.CGImage) { + + NSLog (@"*** error: image must be backed by a CGImage: %@", self); + return nil; + } + + if (maskImage && !maskImage.CGImage) { + + NSLog (@"*** error: maskImage must be backed by a CGImage: %@", maskImage); + return nil; + } + + CGRect imageRect = { CGPointZero, self.size }; + UIImage *effectImage = self; + + BOOL hasBlur = blurRadius > __FLT_EPSILON__; + BOOL hasSaturationChange = fabs(saturationDeltaFactor - 1.) > __FLT_EPSILON__; + if (hasBlur || hasSaturationChange) { + + UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]); + CGContextRef effectInContext = UIGraphicsGetCurrentContext(); + CGContextScaleCTM(effectInContext, 1.0, -1.0); + CGContextTranslateCTM(effectInContext, 0, -self.size.height); + CGContextDrawImage(effectInContext, imageRect, self.CGImage); + + vImage_Buffer effectInBuffer; + effectInBuffer.data = CGBitmapContextGetData(effectInContext); + effectInBuffer.width = CGBitmapContextGetWidth(effectInContext); + effectInBuffer.height = CGBitmapContextGetHeight(effectInContext); + effectInBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectInContext); + + UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]); + CGContextRef effectOutContext = UIGraphicsGetCurrentContext(); + vImage_Buffer effectOutBuffer; + effectOutBuffer.data = CGBitmapContextGetData(effectOutContext); + effectOutBuffer.width = CGBitmapContextGetWidth(effectOutContext); + effectOutBuffer.height = CGBitmapContextGetHeight(effectOutContext); + effectOutBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectOutContext); + + if (hasBlur) { + + // A description of how to compute the box kernel width from the Gaussian + // radius (aka standard deviation) appears in the SVG spec: + // http://www.w3.org/TR/SVG/filters.html#feGaussianBlurElement + // + // For larger values of 's' (s >= 2.0), an approximation can be used: Three + // successive box-blurs build a piece-wise quadratic convolution kernel, which + // approximates the Gaussian kernel to within roughly 3%. + // + // let d = floor(s * 3*sqrt(2*pi)/4 + 0.5) + // + // ... if d is odd, use three box-blurs of size 'd', centered on the output pixel. + // + CGFloat inputRadius = blurRadius * [[UIScreen mainScreen] scale]; + NSUInteger radius = floor(inputRadius * 3. * sqrt(2 * M_PI) / 4 + 0.5); + if (radius % 2 != 1) { + + radius += 1; // force radius to be odd so that the three box-blur methodology works. + } + + vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, (uint32_t)radius, (uint32_t)radius, 0, kvImageEdgeExtend); + vImageBoxConvolve_ARGB8888(&effectOutBuffer, &effectInBuffer, NULL, 0, 0, (uint32_t)radius, (uint32_t)radius, 0, kvImageEdgeExtend); + vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, (uint32_t)radius, (uint32_t)radius, 0, kvImageEdgeExtend); + } + + BOOL effectImageBuffersAreSwapped = NO; + if (hasSaturationChange) { + + CGFloat s = saturationDeltaFactor; + CGFloat floatingPointSaturationMatrix[] = { + 0.0722 + 0.9278 * s, 0.0722 - 0.0722 * s, 0.0722 - 0.0722 * s, 0, + 0.7152 - 0.7152 * s, 0.7152 + 0.2848 * s, 0.7152 - 0.7152 * s, 0, + 0.2126 - 0.2126 * s, 0.2126 - 0.2126 * s, 0.2126 + 0.7873 * s, 0, + 0, 0, 0, 1, + }; + const int32_t divisor = 256; + NSUInteger matrixSize = sizeof(floatingPointSaturationMatrix)/sizeof(floatingPointSaturationMatrix[0]); + int16_t saturationMatrix[matrixSize]; + + for (NSUInteger i = 0; i < matrixSize; ++i) { + + saturationMatrix[i] = (int16_t)roundf(floatingPointSaturationMatrix[i] * divisor); + } + + if (hasBlur) { + + vImageMatrixMultiply_ARGB8888(&effectOutBuffer, &effectInBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags); + effectImageBuffersAreSwapped = YES; + + } else { + + vImageMatrixMultiply_ARGB8888(&effectInBuffer, &effectOutBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags); + } + } + + if (!effectImageBuffersAreSwapped) { + + effectImage = UIGraphicsGetImageFromCurrentImageContext(); + } + + UIGraphicsEndImageContext(); + + if (effectImageBuffersAreSwapped) { + + effectImage = UIGraphicsGetImageFromCurrentImageContext(); + } + + UIGraphicsEndImageContext(); + } + + // Set up output context. + UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]); + CGContextRef outputContext = UIGraphicsGetCurrentContext(); + CGContextScaleCTM(outputContext, 1.0, -1.0); + CGContextTranslateCTM(outputContext, 0, -self.size.height); + + // Draw base image. + CGContextDrawImage(outputContext, imageRect, self.CGImage); + + // Draw effect image. + if (hasBlur) { + + CGContextSaveGState(outputContext); + + if (maskImage) { + + CGContextClipToMask(outputContext, imageRect, maskImage.CGImage); + } + + CGContextDrawImage(outputContext, imageRect, effectImage.CGImage); + CGContextRestoreGState(outputContext); + } + + // Add in color tint. + if (tintColor) { + + CGContextSaveGState(outputContext); + CGContextSetFillColorWithColor(outputContext, tintColor.CGColor); + CGContextFillRect(outputContext, imageRect); + CGContextRestoreGState(outputContext); + } + + // Output image is ready. + UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return outputImage; +} + +- (UIImage *)grayScale { + + int width = self.size.width; + int height = self.size.height; + + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); + + CGContextRef context = CGBitmapContextCreate(nil, + width, + height, + 8, // bits per component + 0, + colorSpace, + kCGBitmapByteOrderDefault); + + CGColorSpaceRelease(colorSpace); + + if (context == NULL) { + + return nil; + } + + CGContextDrawImage(context, + CGRectMake(0, 0, width, height), self.CGImage); + CGImageRef image = CGBitmapContextCreateImage(context); + UIImage *grayImage = [UIImage imageWithCGImage:image]; + CFRelease(image); + CGContextRelease(context); + + return grayImage; +} + +- (UIImage *)scaleWithFixedWidth:(CGFloat)width { + + float newHeight = self.size.height * (width / self.size.width); + CGSize size = CGSizeMake(width, newHeight); + UIGraphicsBeginImageContextWithOptions(size, NO, 0); + + CGContextRef context = UIGraphicsGetCurrentContext(); + + CGContextTranslateCTM(context, 0.0, size.height); + CGContextScaleCTM(context, 1.0, -1.0); + + CGContextSetBlendMode(context, kCGBlendModeCopy); + CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, size.width, size.height), self.CGImage); + + UIImage *imageOut = UIGraphicsGetImageFromCurrentImageContext(); + + UIGraphicsEndImageContext(); + + return imageOut; +} + +- (UIImage *)scaleWithFixedHeight:(CGFloat)height { + + float newWidth = self.size.width * (height / self.size.height); + CGSize size = CGSizeMake(newWidth, height); + + UIGraphicsBeginImageContextWithOptions(size, NO, 0); + + CGContextRef context = UIGraphicsGetCurrentContext(); + + CGContextTranslateCTM(context, 0.0, size.height); + CGContextScaleCTM(context, 1.0, -1.0); + + CGContextSetBlendMode(context, kCGBlendModeCopy); + CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, size.width, size.height), self.CGImage); + + UIImage *imageOut = UIGraphicsGetImageFromCurrentImageContext(); + + UIGraphicsEndImageContext(); + + return imageOut; +} + +- (UIColor *)averageColor { + + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + unsigned char rgba[4]; + CGContextRef context = CGBitmapContextCreate(rgba, 1, 1, 8, 4, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); + + CGContextDrawImage(context, CGRectMake(0, 0, 1, 1), self.CGImage); + CGColorSpaceRelease(colorSpace); + CGContextRelease(context); + + if(rgba[3] > 0) { + CGFloat alpha = ((CGFloat)rgba[3])/255.0; + CGFloat multiplier = alpha/255.0; + return [UIColor colorWithRed:((CGFloat)rgba[0])*multiplier + green:((CGFloat)rgba[1])*multiplier + blue:((CGFloat)rgba[2])*multiplier + alpha:alpha]; + } + else { + return [UIColor colorWithRed:((CGFloat)rgba[0])/255.0 + green:((CGFloat)rgba[1])/255.0 + blue:((CGFloat)rgba[2])/255.0 + alpha:((CGFloat)rgba[3])/255.0]; + } +} + +- (UIImage *)croppedImageAtFrame:(CGRect)frame { + + frame = CGRectMake(frame.origin.x * self.scale, + frame.origin.y * self.scale, + frame.size.width * self.scale, + frame.size.height * self.scale); + + CGImageRef sourceImageRef = [self CGImage]; + CGImageRef newImageRef = CGImageCreateWithImageInRect(sourceImageRef, frame); + UIImage *newImage = [UIImage imageWithCGImage:newImageRef scale:[self scale] orientation:[self imageOrientation]]; + CGImageRelease(newImageRef); + return newImage; +} + +- (UIImage *)addImageToImage:(UIImage *)img atRect:(CGRect)cropRect { + + CGSize size = CGSizeMake(self.size.width, self.size.height); + UIGraphicsBeginImageContextWithOptions(size, NO, self.scale); + + CGPoint pointImg1 = CGPointMake(0,0); + [self drawAtPoint:pointImg1]; + + CGPoint pointImg2 = cropRect.origin; + [img drawAtPoint: pointImg2]; + + UIImage* result = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return result; +} + +- (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius + tintColor:(UIColor *)tintColor + saturationDeltaFactor:(CGFloat)saturationDeltaFactor + maskImage:(UIImage *)maskImage + atFrame:(CGRect)frame +{ + UIImage *blurredFrame = \ + [[self croppedImageAtFrame:frame] applyBlurWithRadius:blurRadius + tintColor:tintColor + saturationDeltaFactor:saturationDeltaFactor + maskImage:maskImage]; + + return [self addImageToImage:blurredFrame atRect:frame]; +} + +@end diff --git a/LingQi/LingQi/Tools/Extensions/UIImageView+Develop.swift b/LingQi/LingQi/Tools/Extensions/UIImageView+Develop.swift new file mode 100644 index 0000000..0922029 --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/UIImageView+Develop.swift @@ -0,0 +1,27 @@ +// +// UIImageView+HTDevelop.swift +// rrlWallet +// +// Created by Gordon on 2017/12/27. +// Copyright © 2017å¹´ Gordon. All rights reserved. +// + +import UIKit + +public extension YCDevelop where Base: UIImageView { + + /// layer旋转360° + /// + /// - Parameter duration: 时间(旋转360度需要的时间) + /// - Parameter repeatCount: 重复次数 + /// - Parameter direction: 方向 CW:顺时针, CCW:逆时针 + func img360Start(duration: TimeInterval, repeatCount: Float = MAXFLOAT, direction: String = "CW") { + base.layer.start360Rotate(duration: duration, repeatCount: repeatCount, direction: direction) + base.isHidden = false + } + func img360Stop(hideOnComplete: Bool = true) { + base.layer.stopRotate360() + base.isHidden = hideOnComplete + } + +} diff --git a/LingQi/LingQi/Tools/Extensions/UINavigationBar+Develop.swift b/LingQi/LingQi/Tools/Extensions/UINavigationBar+Develop.swift new file mode 100644 index 0000000..a71c315 --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/UINavigationBar+Develop.swift @@ -0,0 +1,22 @@ +// +// UINavigationBar+HTDevelop.swift +// kemiBear +// +// Created by 李扬 on 2017/4/18. +// Copyright © 2017å¹´ 李扬. All rights reserved. +// + +import UIKit + +public extension YCDevelop where Base: UINavigationBar { + + func setNavBar(bgColor:UIColor, shadowColor:UIColor) { + + let shadowImg = UIImage.yc.image(color: shadowColor, size: CGSize.init(width: kScreenWid, height: 1), cornerRadius: 0) + let bgImg = UIImage.yc.image(color: bgColor, size: CGSize.init(width: kScreenWid, height: kNavBtm), cornerRadius: 0) + base.shadowImage = shadowImg + base.setBackgroundImage(bgImg, for: .default) + base.barTintColor = bgColor + } +} + diff --git a/LingQi/LingQi/Tools/Extensions/UITableView+Header.swift b/LingQi/LingQi/Tools/Extensions/UITableView+Header.swift new file mode 100644 index 0000000..80844e6 --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/UITableView+Header.swift @@ -0,0 +1,29 @@ +// +// UITableView+Header.swift +// zgjd +// +// Created by apple on 2020/12/8. +// + +import Foundation +import UIKit + +extension UITableView { + //set the tableHeaderView so that the required height can be determined, update the header's frame and set it again + func setAndLayoutTable(header view: UIView) { + self.tableHeaderView = view + view.setNeedsLayout() + view.layoutIfNeeded() + view.frame.size = view.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) + self.tableHeaderView = view + } + + +// func setAndLayoutTable(footer view: UIView) { +// self.tableFooterView = view +// view.setNeedsLayout() +// view.layoutIfNeeded() +// view.frame.size = view.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) +// self.tableFooterView = view +// } +} diff --git a/LingQi/LingQi/Tools/Extensions/UITableView_Extension.swift b/LingQi/LingQi/Tools/Extensions/UITableView_Extension.swift new file mode 100755 index 0000000..e2fe85e --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/UITableView_Extension.swift @@ -0,0 +1,82 @@ +// +// UIKitExtensions.swift +// RxDataSources +// +// Created by Segii Shulga on 4/26/16. +// Copyright © 2016 kzaher. All rights reserved. +// + +import UIKit +import class UIKit.UITableViewCell +import class UIKit.UITableView +import class UIKit.UIViewController +import struct Foundation.IndexPath + + +public protocol ReusableView { + static var reuseIdentifier: String {get} +} + +extension ReusableView { + static public var reuseIdentifier: String { + return String(describing: self) + } +} + +extension UITableViewCell: ReusableView { +} + +extension UIViewController : ReusableView { +} +extension UICollectionViewCell: ReusableView {} + + +// MARK: - tableview extension +extension UITableView { + + /// cell 复用 + /// + /// - Parameter indexPath: cell indexPath + /// - Returns: cell + public func dequeueReusableCell(forIndexPath indexPath: IndexPath) -> T /* where T: ReusableView */ { + guard let cell = dequeueReusableCell(withIdentifier: T.reuseIdentifier, for: indexPath) as? T else { + fatalError("Could not dequeue cell with identifier: \(T.reuseIdentifier)") + } + + return cell + } + + + /// 注册table view cell + /// + /// - Parameter cell: 需要注册的cell + public func register(_ cell: T.Type) { + + register(cell.self, forCellReuseIdentifier: cell.reuseIdentifier) + } + + + /// 批量注册cell + /// + /// - Parameter cells: 需要注册的cell数组 + public func registers(_ cells: [T.Type]) { + + for cell in cells { + register(cell.self) + } + } +} + +extension UITableView { + + public func dequeueReusable(class cell: T.Type) -> T { + guard let aCell = dequeueReusableCell(withIdentifier: cell.reuseIdentifier) as? T else { + fatalError("Couldn't find UITableViewCell for \(cell.reuseIdentifier), make sure the cell is registered with table view") + } + return aCell + } + + public func registerCell(nib cell: T.Type) { + register(UINib(nibName: cell.reuseIdentifier, bundle: nil), forCellReuseIdentifier: cell.reuseIdentifier) + } +} diff --git a/LingQi/LingQi/Tools/Extensions/UITextField+Extension.swift b/LingQi/LingQi/Tools/Extensions/UITextField+Extension.swift new file mode 100644 index 0000000..7510166 --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/UITextField+Extension.swift @@ -0,0 +1,174 @@ +// +// UITextField+Extension.swift +// zshSeedOne +// +// Created by ios-spec on 2019/3/18. +// Copyright © 2019 zsh. All rights reserved. +// + +#if canImport(UIKit) && !os(watchOS) +import UIKit + +extension UITextField { + + public func setPlaceholder(text: String, font: UIFont, color: UIColor) { + + let attributes = [ + NSAttributedString.Key.foregroundColor: color, + NSAttributedString.Key.font : font // Note the ! + ] + attributedPlaceholder = NSAttributedString(string: text, attributes:attributes) + } +} + +// MARK: - Enums +public extension UITextField { + + /// SwifterSwift: UITextField text type. + /// + /// - emailAddress: UITextField is used to enter email addresses. + /// - password: UITextField is used to enter passwords. + /// - generic: UITextField is used to enter generic text. + enum TextType { + /// UITextField is used to enter email addresses. + case emailAddress + + /// UITextField is used to enter passwords. + case password + + /// UITextField is used to enter generic text. + case generic + } + +} + +// MARK: - Properties +public extension UITextField { + + /// SwifterSwift: Set textField for common text types. + var textType: TextType { + get { + if keyboardType == .emailAddress { + return .emailAddress + } else if isSecureTextEntry { + return .password + } + return .generic + } + set { + switch newValue { + case .emailAddress: + keyboardType = .emailAddress + autocorrectionType = .no + autocapitalizationType = .none + isSecureTextEntry = false + placeholder = "Email Address" + + case .password: + keyboardType = .asciiCapable + autocorrectionType = .no + autocapitalizationType = .none + isSecureTextEntry = true + placeholder = "Password" + + case .generic: + isSecureTextEntry = false + } + } + } + + /// SwifterSwift: Check if text field is empty. + var isEmpty: Bool { + return text?.isEmpty == true + } + + /// SwifterSwift: Return text with no spaces or new lines in beginning and end. + var trimmedText: String? { + return text?.trimmingCharacters(in: .whitespacesAndNewlines) + } + + /// SwifterSwift: Check if textFields text is a valid email format. + /// + /// textField.text = "john@doe.com" + /// textField.hasValidEmail -> true + /// + /// textField.text = "swifterswift" + /// textField.hasValidEmail -> false + /// + var hasValidEmail: Bool { + // http://stackoverflow.com/questions/25471114/how-to-validate-an-e-mail-address-in-swift + return text!.range(of: "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}", + options: String.CompareOptions.regularExpression, + range: nil, locale: nil) != nil + } + + /// SwifterSwift: Left view tint color. + @IBInspectable var leftViewTintColor: UIColor? { + get { + guard let iconView = leftView as? UIImageView else { return nil } + return iconView.tintColor + } + set { + guard let iconView = leftView as? UIImageView else { return } + iconView.image = iconView.image?.withRenderingMode(.alwaysTemplate) + iconView.tintColor = newValue + } + } + + /// SwifterSwift: Right view tint color. + @IBInspectable var rightViewTintColor: UIColor? { + get { + guard let iconView = rightView as? UIImageView else { return nil } + return iconView.tintColor + } + set { + guard let iconView = rightView as? UIImageView else { return } + iconView.image = iconView.image?.withRenderingMode(.alwaysTemplate) + iconView.tintColor = newValue + } + } + +} + +// MARK: - Methods +public extension UITextField { + + /// SwifterSwift: Clear text. + func clear() { + text = "" + attributedText = NSAttributedString(string: "") + } + + /// SwifterSwift: Set placeholder text color. + /// + /// - Parameter color: placeholder text color. + func setPlaceHolderTextColor(_ color: UIColor) { + guard let holder = placeholder, !holder.isEmpty else { return } + attributedPlaceholder = NSAttributedString(string: holder, attributes: [.foregroundColor: color]) + } + + /// SwifterSwift: Add padding to the left of the textfield rect. + /// + /// - Parameter padding: amount of padding to apply to the left of the textfield rect. + func addPaddingLeft(_ padding: CGFloat) { + let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: padding, height: frame.height)) + leftView = paddingView + leftViewMode = .always + } + + /// SwifterSwift: Add padding to the left of the textfield rect. + /// + /// - Parameters: + /// - image: left image + /// - padding: amount of padding between icon and the left of textfield + func addPaddingLeftIcon(_ image: UIImage, padding: CGFloat) { + let imageView = UIImageView(image: image) + imageView.contentMode = .center + leftView = imageView + leftView?.frame.size = CGSize(width: image.size.width + padding, height: image.size.height) + leftViewMode = .always + } + +} + +#endif diff --git a/LingQi/LingQi/Tools/Extensions/UIView+Develop.swift b/LingQi/LingQi/Tools/Extensions/UIView+Develop.swift new file mode 100644 index 0000000..4bd67f5 --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/UIView+Develop.swift @@ -0,0 +1,282 @@ +// +// UIView+Develop.swift +// YCDevTools +// +// Created by Liang ZhenYing on 2020/3/5. +// Copyright © 2020 zkys. All rights reserved. +// + +import UIKit +import SnapKit + +public extension YCDevelop where Base: UIView { + + /// 给layer添加阴影 + /// + /// - Parameter color: 颜色 + /// - Parameter blur: blur radius + /// - Parameter opacity: 不透明 + /// - Parameter rect: shadowPath + /// + func addShadow(withRect rect: CGRect, color: UIColor, blur: CGFloat, opacity: CGFloat, cornerRadius: CGFloat = 0) { + let bLayer = base.layer + guard + let superV = base.superview, + bLayer.masksToBounds else { + bLayer.addShadow(withRect: rect, cornerRadius: cornerRadius, color: color, blur: blur, opacity: opacity) + return + } + /// 创建一个背景view + let bg = UIView() + bg.isUserInteractionEnabled = false + bg.backgroundColor = .clear + superV.insertSubview(bg, belowSubview: base) + bg.layer.addShadow(withRect: rect, cornerRadius: cornerRadius, color: color, blur: blur, opacity: opacity) + bg.snp.makeConstraints { (m) in + m.edges.equalTo(base) + } + } + + func addShadowOffset(color: UIColor, blur: CGFloat, opacity: CGFloat, offset: CGSize) { + let bLayer = base.layer + guard + let superV = base.superview, + bLayer.masksToBounds else { + bLayer.addShadowOffset(color: color, blur: blur, opacity: opacity, offset: offset) + return + } + /// 创建一个背景view + let bg = UIView() + bg.isUserInteractionEnabled = false + bg.backgroundColor = .clear + superV.insertSubview(bg, belowSubview: base) + bg.layer.addShadowOffset(color: color, blur: blur, opacity: opacity, offset: offset) + bg.snp.makeConstraints { (m) in + m.edges.equalTo(base) + } + } + + /// 给自己快速添加一个渐变layer + /// + /// - Parameter colors: 渐变颜色 + /// - Parameter direction: 渐变方向 + func addgradientLayer(colors: [UIColor], direction: LYGradientLayerDirectionOption, rect: CGRect = .zero) { + var r = rect + if r == .zero { r = base.bounds } + let gradient = CAGradientLayer.yc.gradientLayerWith(colors: colors, frame: r, direction: direction) + if (base.layer.sublayers?.count ?? 0) > 0 { + base.layer.insertSublayer(gradient, at: 0) + } else { + base.layer.addSublayer(gradient) + } + } + + /// 设置圆角 +// func setRoundRect() { +// let bLayer = base.layer +// bLayer.cornerRadius = base.bounds.size.height * 0.5 +// bLayer.masksToBounds = true +// } + + /// 设置圆角 半径 + func setCornerRadius(_ radius:CGFloat) { + let bLayer = base.layer + bLayer.cornerRadius = radius + bLayer.masksToBounds = true + } + /// 设置指定位置圆角 + func setCorners(withRoundedRect roundedRect: CGRect, + roundingCorners: UIRectCorner, + cornerRadii: CGSize) { + let cornerPath = UIBezierPath(roundedRect: roundedRect, + byRoundingCorners: roundingCorners, + cornerRadii: cornerRadii) + let shapeLayer = CAShapeLayer() + shapeLayer.frame = base.bounds + shapeLayer.path = cornerPath.cgPath + base.layer.mask = shapeLayer + } + /// 设置border + func setBorder(width: CGFloat, color: UIColor, radius: CGFloat = 0) { + let bLayer = base.layer + bLayer.borderColor = color.cgColor + bLayer.borderWidth = width + if radius > 0 { + bLayer.cornerRadius = radius + } + bLayer.masksToBounds = true + } + /// layer旋转360° + /// + /// - Parameter duration: 时间(旋转360度需要的时间) + /// - Parameter repeatCount: 重复次数 + /// - Parameter direction: 方向 CW:顺时针, CCW:逆时针 + func start360Rotate(duration: TimeInterval, repeatCount: Float = MAXFLOAT, direction: String = "CW") { + base.layer.start360Rotate(duration: duration, repeatCount: repeatCount, direction: direction) + } + func pause360Rotate() { + base.layer.pause360Rotate() + } + func stopRotate360() { + base.layer.stopRotate360() + } + /// scale动画 + func scaleAnimation(duration: TimeInterval = 0.3, zoomin: Double = 1.03, _ finished: @escaping () -> Void) { + let scaleAnimation = CAKeyframeAnimation(keyPath: "transform.scale") + scaleAnimation.duration = duration + scaleAnimation.values = [1.0, zoomin, 1.0] + base.layer.add(scaleAnimation, forKey: nil) + DispatchQueue.main.asyncAfter(deadline: .now() + duration) { + finished() + } + } + + /// 翻转动画 + func flipAnimate(duration: TimeInterval, halfTimeAnimation: @escaping () -> Void , _ finished: @escaping () -> Void) { + + let keyAnimation = CAKeyframeAnimation(keyPath: "transform.rotation.y") + keyAnimation.values = [0, 0.2.π, 0.35.π, 0.5.π, 0.1.π, -0.07.π, 0] + keyAnimation.duration = duration + base.layer.add(keyAnimation, forKey: nil) + DispatchQueue.main.asyncAfter(deadline: .now() + duration * 0.5) { + halfTimeAnimation() + } + DispatchQueue.main.asyncAfter(deadline: .now() + duration) { + finished() + } + } + + /// + func addBlurEffect(_ style: UIBlurEffect.Style = .light, + rect: CGRect = .zero) { + let effect = UIBlurEffect.init(style: style) + let gaussianView = UIVisualEffectView.init(effect: effect) + var r = rect + if r == .zero { r = base.bounds } + gaussianView.frame = r + base.layer.allowsGroupOpacity = false + base.addSubview(gaussianView) + } + + + // MARK: === 抖动动画 + func shakeAnimate() { + let ani = CABasicAnimation(keyPath: "transform.rotation.z") + // 设置运动形式 + ani.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut) + // 设置开始位置 + ani.fromValue = -0.08 + // 设置结束位置 + ani.toValue = 0.08 + // 设置自动反转 + ani.autoreverses = true + // 设置时间 + ani.duration = 0.1 + // 设置次数 + ani.repeatCount = 2 + // 添加上动画 + base.layer.add(ani, forKey: nil) + } + + + // MARK: === spring animate + static func spring(animations: @escaping () -> Void) { + springAnimate(animations: animations) + } + // MARK: === spring animate with completion + static func cSpring(animations: @escaping () -> Void, + completion: @escaping ((Bool) -> Void)) { + springAnimate(animations: animations, completion: completion) + } + + static func springAnimate(withDuration duration: TimeInterval = 0.5, + delay: TimeInterval = 0, + usingSpringWithDamping dampingRatio: CGFloat = 0.7, + initialSpringVelocity velocity: CGFloat = 0.3, + options: UIView.AnimationOptions = [.allowUserInteraction], + animations: @escaping () -> Void, + completion: ((Bool) -> Void)? = nil) { + UIView.animate(withDuration: duration, + delay: delay, + usingSpringWithDamping: dampingRatio, + initialSpringVelocity: velocity, + animations: animations, + completion: completion) + } + + // MARK: === snapshot + var snapshot: UIImage? { + UIGraphicsBeginImageContextWithOptions(base.bounds.size, false, UIScreen.main.scale) + defer { UIGraphicsEndImageContext() } + + guard let currentContext = UIGraphicsGetCurrentContext() + else { return nil } + base.layer.render(in: currentContext) + guard let snapshot = UIGraphicsGetImageFromCurrentImageContext() + else { return nil } + return snapshot + } + + // MARK: === snapshot + var graySnapshot: UIImage? { + UIGraphicsBeginImageContextWithOptions(CGSize(width: base.bounds.size.width + 60.fitR, height: base.bounds.size.height + 60.fitR), false, UIScreen.main.scale) + defer { UIGraphicsEndImageContext() } + + guard let currentContext = UIGraphicsGetCurrentContext() + else { return nil } + currentContext.setFillColor(UIColor.gray.withAlphaComponent(0.1).cgColor) + // 填充背景色 + currentContext.fill(CGRect(x: 0, y: 0, width: base.bounds.size.width + 60.fitR , height: base.bounds.size.height + 60.fitR)) + + guard let image = self.imageWithView(view: base) else { + return UIImage() + } + image.draw(at: CGPoint(x: 30.fitR, y: 30.fitR)) + guard let snapshot = UIGraphicsGetImageFromCurrentImageContext() + else { return nil } + return snapshot + } + + func imageWithView(view: UIView) -> UIImage? { + UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, UIScreen.main.scale) + view.layer.render(in: UIGraphicsGetCurrentContext()!) + let snapshotImage = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + return snapshotImage + } + func drawDashLine(lineLength : Int ,lineSpacing : Int,lineColor : UIColor){ + let shapeLayer = CAShapeLayer() + shapeLayer.bounds = base.bounds + // 只要是CALayer这种类型,他的anchorPoint默认都是(0.5,0.5) + shapeLayer.anchorPoint = CGPoint(x: 0, y: 0) + // shapeLayer.fillColor = UIColor.blue.cgColor + shapeLayer.strokeColor = lineColor.cgColor + + shapeLayer.lineWidth = base.frame.size.height + shapeLayer.lineJoin = .round + + shapeLayer.lineDashPattern = [NSNumber(value: lineLength),NSNumber(value: lineSpacing)] + + let path = CGMutablePath() + path.move(to: CGPoint(x: 0, y: 0)) + path.addLine(to: CGPoint(x: 0 , y: base.frame.size.height)) + + shapeLayer.path = path + base.layer.addSublayer(shapeLayer) + } + func removeAllSubViews(){ + let list = base.subviews + for item in list { + item.removeFromSuperview() + } + } + func addTap(target:Any?,action:Selector?){ + let tap = UITapGestureRecognizer(target: target, action: action) + base.addGestureRecognizer(tap) + base.isUserInteractionEnabled = true + } +} + + + + diff --git a/LingQi/LingQi/Tools/Extensions/UIView+Loading.swift b/LingQi/LingQi/Tools/Extensions/UIView+Loading.swift new file mode 100644 index 0000000..6045798 --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/UIView+Loading.swift @@ -0,0 +1,47 @@ +// +// UIView+Loading.swift +// zgjd +// +// Created by apple on 2021/2/25. +// + +import Foundation +import UIKit + +private var loadingViewkey: Void? + +public extension YCDevelop where Base: UIView { + fileprivate var loadingView: UIActivityIndicatorView? { + return objc_getAssociatedObject(base, &loadingViewkey) as? UIActivityIndicatorView + } + + func showLoading() { + var indicator:UIActivityIndicatorView + if loadingView == nil{ + indicator = UIActivityIndicatorView() + indicator.hidesWhenStopped = true + if #available(iOS 13.0, *) { + indicator.style = .large + } else { + indicator.style = .gray + } + objc_setAssociatedObject(base, &loadingViewkey, indicator, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } + else{ + indicator = loadingView! + } + + base.addSubview(indicator) + base.bringSubviewToFront(indicator) + indicator.startAnimating() + + indicator.snp.makeConstraints { (m) in +// m.width.height.equalTo(50.fitR) + m.center.equalToSuperview() + } + } + func hiddenLoading(){ + loadingView?.stopAnimating() + loadingView?.removeFromSuperview() + } +} diff --git a/LingQi/LingQi/Tools/Extensions/UIView+Rect.swift b/LingQi/LingQi/Tools/Extensions/UIView+Rect.swift new file mode 100644 index 0000000..38bb992 --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/UIView+Rect.swift @@ -0,0 +1,109 @@ +// +// UIView+Rect.swift +// HTDevelop +// +// Created by 李扬 on 2019/1/2. +// Copyright © 2019 rrl360. All rights reserved. +// + +import UIKit + +public extension UIView { + + private var x : CGFloat { + get { return frame.origin.x } + set(newVal) { + var tmpFrame : CGRect = frame + tmpFrame.origin.x = newVal + frame = tmpFrame + } + } + + private var y : CGFloat { + get { return frame.origin.y } + set(newVal) { + var tmpFrame : CGRect = frame + tmpFrame.origin.y = newVal + frame = tmpFrame + } + } + + var height : CGFloat { + get { return frame.size.height } + set(newVal) { + var tmpFrame : CGRect = frame + tmpFrame.size.height = newVal + frame = tmpFrame + } + } + + var width : CGFloat { + get { return frame.size.width } + set(newVal) { + var tmpFrame : CGRect = frame + tmpFrame.size.width = newVal + frame = tmpFrame + } + } + + var left : CGFloat { + get { return x } + set(newVal) { x = newVal } + } + + var right : CGFloat { + get { return x + width } + set(newVal) { x = newVal - width } + } + + var top : CGFloat { + get { return y } + set(newVal) { y = newVal } + } + + var bottom : CGFloat { + get { return y + height } + set(newVal) { y = newVal - height } + } + var centerX : CGFloat { + get { return center.x } + set(newVal) { + center = CGPoint(x: newVal, y: center.y) + } + } + var centerY : CGFloat { + get { return center.y } + set(newVal) { + center = CGPoint(x: center.x, y: newVal) + } + } + + var b_center: CGPoint { + get { + return CGPoint.init(x: b_centerX, y: b_centerY) + } + } + var b_centerX : CGFloat { + get { return width / 2 } + } + var b_centerY : CGFloat { + get { return height / 2 } + } + var f_origin: CGPoint { + get { return frame.origin } + set(newVal) { + var rect = self.frame + rect.origin = newVal + self.frame = rect + } + } + var f_size: CGSize { + get { return self.frame.size } + set(newVal) { + var rect = self.frame + rect.size = newVal + self.frame = rect + } + } +} + diff --git a/LingQi/LingQi/Tools/Extensions/UIView+Round.swift b/LingQi/LingQi/Tools/Extensions/UIView+Round.swift new file mode 100644 index 0000000..5edf669 --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/UIView+Round.swift @@ -0,0 +1,67 @@ +// +// UIView+Round.swift +// zgjd +// +// Created by apple on 2020/12/9. +// + +import Foundation +import UIKit + +enum RoundType { + case top + case bottom + case all + case normal + case topWithBottomRight +} + +extension UIView { +// func corners(with rect: CGRect, type: RoundType, radius: CGFloat) { +// switch type { +// case .top: +// self.yc.setCorners(withRoundedRect: rect, roundingCorners: [.topLeft,.topRight], cornerRadii: CGSize(width: radius, height: radius)) +// case .bottom: +// self.yc.setCorners(withRoundedRect: rect, roundingCorners: [.bottomLeft,.bottomRight], cornerRadii: CGSize(width: radius, height: radius)) +// case .all: +// self.cornerRadius = radius +// case .normal: +// self.cornerRadius = 0 +// } +// } + + func corners(with type: RoundType, radius: CGFloat) { + switch type { + case .top: + corner(with: radius, coners: [.topLeft,.topRight]) + case .bottom: + corner(with: radius, coners: [.bottomLeft,.bottomRight]) + case .all: +// self.n_cornerRadius = radius + corner(with: radius, coners: .allCorners) + case .normal: + self.n_cornerRadius = 0 + case .topWithBottomRight: + corner(with: radius, coners: [.topLeft,.topRight,.bottomRight]) + } + } + + /// 圆角 + private func corner(with: CGFloat, coners: UIRectCorner) { + + guard let sup = self.superview else { + print("corner failed, the reason is can't find superview, file - \(#file), line - \(#line)") + return + } + // if use snapkit, need update frame + sup.layoutIfNeeded() + + + let maskPath = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: coners, cornerRadii: CGSize(width: with, height: with)) + + let maskLayer = CAShapeLayer() + maskLayer.frame = self.bounds + maskLayer.path = maskPath.cgPath + self.layer.mask = maskLayer + } +} diff --git a/LingQi/LingQi/Tools/Extensions/UIViewExtension.swift b/LingQi/LingQi/Tools/Extensions/UIViewExtension.swift new file mode 100644 index 0000000..0ee94dc --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/UIViewExtension.swift @@ -0,0 +1,726 @@ +// +// UIViewExtension.swift +// SNSwiftPackage +// +// Created by Spec on 2019/8/5. +// Copyright © 2019 Spec. All rights reserved. +// + +#if canImport(UIKit) && !os(watchOS) +import UIKit + +// MARK: - enums +public extension UIView { + + /// SwifterSwift: Shake directions of a view. + /// + /// - horizontal: Shake left and right. + /// - vertical: Shake up and down. + enum ShakeDirection { + /// Shake left and right. + case horizontal + + /// Shake up and down. + case vertical + } + + /// SwifterSwift: Angle units. + /// + /// - degrees: degrees. + /// - radians: radians. + enum AngleUnit { + /// degrees. + case degrees + + /// radians. + case radians + } + + /// SwifterSwift: Shake animations types. + /// + /// - linear: linear animation. + /// - easeIn: easeIn animation. + /// - easeOut: easeOut animation. + /// - easeInOut: easeInOut animation. + enum ShakeAnimationType { + /// linear animation. + case linear + + /// easeIn animation. + case easeIn + + /// easeOut animation. + case easeOut + + /// easeInOut animation. + case easeInOut + } + +} + +// MARK: - Properties +public extension UIView { + + /// SwifterSwift: Border color of view; also inspectable from Storyboard. + @IBInspectable var n_borderColor: UIColor? { + get { + guard let color = layer.borderColor else { return nil } + return UIColor(cgColor: color) + } + set { + guard let color = newValue else { + layer.borderColor = nil + return + } + // Fix React-Native conflict issue + guard String(describing: type(of: color)) != "__NSCFType" else { return } + layer.borderColor = color.cgColor + } + } + + /// SwifterSwift: Border width of view; also inspectable from Storyboard. + @IBInspectable var n_borderWidth: CGFloat { + get { + return layer.borderWidth + } + set { + layer.borderWidth = newValue + } + } + + /// SwifterSwift: Corner radius of view; also inspectable from Storyboard. + @IBInspectable var n_cornerRadius: CGFloat { + get { + return layer.cornerRadius + } + set { + layer.masksToBounds = true + layer.cornerRadius = abs(CGFloat(Int(newValue * 100)) / 100) + } + } + + /// SwifterSwift: Height of view. +// var height: CGFloat { +// get { +// return frame.size.height +// } +// set { +// frame.size.height = newValue +// } +// } + + /// SwifterSwift: Check if view is in RTL format. + var isRightToLeft: Bool { + if #available(iOS 10.0, *, tvOS 10.0, *) { + return effectiveUserInterfaceLayoutDirection == .rightToLeft + } else { + return false + } + } + + /// SwifterSwift: Take screenshot of view (if applicable). + var screenshot: UIImage? { + UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, 0) + defer { + UIGraphicsEndImageContext() + } + guard let context = UIGraphicsGetCurrentContext() else { return nil } + layer.render(in: context) + return UIGraphicsGetImageFromCurrentImageContext() + } + + /// SwifterSwift: Shadow color of view; also inspectable from Storyboard. + @IBInspectable var shadowColor: UIColor? { + get { + guard let color = layer.shadowColor else { return nil } + return UIColor(cgColor: color) + } + set { + layer.shadowColor = newValue?.cgColor + } + } + + /// SwifterSwift: Shadow offset of view; also inspectable from Storyboard. + @IBInspectable var shadowOffset: CGSize { + get { + return layer.shadowOffset + } + set { + layer.shadowOffset = newValue + } + } + + /// SwifterSwift: Shadow opacity of view; also inspectable from Storyboard. + @IBInspectable var shadowOpacity: Float { + get { + return layer.shadowOpacity + } + set { + layer.shadowOpacity = newValue + } + } + + /// SwifterSwift: Shadow radius of view; also inspectable from Storyboard. + @IBInspectable var shadowRadius: CGFloat { + get { + return layer.shadowRadius + } + set { + layer.shadowRadius = newValue + } + } + + /// SwifterSwift: Size of view. + var size: CGSize { + get { + return frame.size + } + set { + width = newValue.width + height = newValue.height + } + } + + /// SwifterSwift: Get view's parent view controller + var parentViewController: UIViewController? { + weak var parentResponder: UIResponder? = self + while parentResponder != nil { + parentResponder = parentResponder!.next + if let viewController = parentResponder as? UIViewController { + return viewController + } + } + return nil + } + + /// SwifterSwift: Width of view. +// var width: CGFloat { +// get { +// return frame.size.width +// } +// set { +// frame.size.width = newValue +// } +// } + + /// SwifterSwift: x origin of view. + // swiftlint:disable:next identifier_name +// var x: CGFloat { +// get { +// return frame.origin.x +// } +// set { +// frame.origin.x = newValue +// } +// } + + /// SwifterSwift: y origin of view. + // swiftlint:disable:next identifier_name +// var y: CGFloat { +// get { +// return frame.origin.y +// } +// set { +// frame.origin.y = newValue +// } +// } + +} + +// MARK: - Methods +public extension UIView { + + /// SwifterSwift: Recursively find the first responder. + func firstResponder() -> UIView? { + var views = [UIView](arrayLiteral: self) + var index = 0 + repeat { + let view = views[index] + if view.isFirstResponder { + return view + } + views.append(contentsOf: view.subviews) + index += 1 + } while index < views.count + return nil + } + + /// SwifterSwift: Set some or all corners radiuses of view. + /// + /// - Parameters: + /// - corners: array of corners to change (example: [.bottomLeft, .topRight]). + /// - radius: radius for selected corners. + func roundCorners(_ corners: UIRectCorner, radius: CGFloat) { + let maskPath = UIBezierPath( + roundedRect: bounds, + byRoundingCorners: corners, + cornerRadii: CGSize(width: radius, height: radius)) + + let shape = CAShapeLayer() + shape.path = maskPath.cgPath + layer.mask = shape + } + + /// SwifterSwift: Add shadow to view. + /// + /// - Parameters: + /// - color: shadow color (default is #137992). + /// - radius: shadow radius (default is 3). + /// - offset: shadow offset (default is .zero). + /// - opacity: shadow opacity (default is 0.5). + func addShadow(ofColor color: UIColor = UIColor(red: 0.07, green: 0.47, blue: 0.57, alpha: 1.0), radius: CGFloat = 3, offset: CGSize = .zero, opacity: Float = 0.5) { + layer.shadowColor = color.cgColor + layer.shadowOffset = offset + layer.shadowRadius = radius + layer.shadowOpacity = opacity + layer.masksToBounds = false + } + + /// SwifterSwift: Add array of subviews to view. + /// + /// - Parameter subviews: array of subviews to add to self. + func addSubviews(_ subviews: [UIView]) { + subviews.forEach { addSubview($0) } + } + + /// SwifterSwift: Fade in view. + /// + /// - Parameters: + /// - duration: animation duration in seconds (default is 1 second). + /// - completion: optional completion handler to run with animation finishes (default is nil) + func fadeIn(duration: TimeInterval = 1, completion: ((Bool) -> Void)? = nil) { + if isHidden { + isHidden = false + } + UIView.animate(withDuration: duration, animations: { + self.alpha = 1 + }, completion: completion) + } + + /// SwifterSwift: Fade out view. + /// + /// - Parameters: + /// - duration: animation duration in seconds (default is 1 second). + /// - completion: optional completion handler to run with animation finishes (default is nil) + func fadeOut(duration: TimeInterval = 1, completion: ((Bool) -> Void)? = nil) { + if isHidden { + isHidden = false + } + UIView.animate(withDuration: duration, animations: { + self.alpha = 0 + }, completion: completion) + } + + /// SwifterSwift: Load view from nib. + /// + /// - Parameters: + /// - name: nib name. + /// - bundle: bundle of nib (default is nil). + /// - Returns: optional UIView (if applicable). + class func loadFromNib(named name: String, bundle: Bundle? = nil) -> UIView? { + return UINib(nibName: name, bundle: bundle).instantiate(withOwner: nil, options: nil)[0] as? UIView + } + + /// SwifterSwift: Remove all subviews in view. + func removeSubviews() { + subviews.forEach({ $0.removeFromSuperview() }) + } + + /// SwifterSwift: Remove all gesture recognizers from view. + func removeGestureRecognizers() { + gestureRecognizers?.forEach(removeGestureRecognizer) + } + + /// SwifterSwift: Attaches gesture recognizers to the view. + /// + /// Attaching gesture recognizers to a view defines the scope of the represented + /// gesture, causing it to receive touches hit-tested to that view and all of its + /// subviews. The view establishes a strong reference to the gesture recognizers. + /// + /// - Parameter gestureRecognizers: The array of gesture recognizers to be added to the view. + func addGestureRecognizers(_ gestureRecognizers: [UIGestureRecognizer]) { + for recognizer in gestureRecognizers { + addGestureRecognizer(recognizer) + } + } + + /// SwifterSwift: Detaches gesture recognizers from the receiving view. + /// + /// This method releases gestureRecognizers in addition to detaching them from the view. + /// + /// - Parameter gestureRecognizers: The array of gesture recognizers to be removed from the view. + func removeGestureRecognizers(_ gestureRecognizers: [UIGestureRecognizer]) { + for recognizer in gestureRecognizers { + removeGestureRecognizer(recognizer) + } + } + + /// SwifterSwift: Rotate view by angle on relative axis. + /// + /// - Parameters: + /// - angle: angle to rotate view by. + /// - type: type of the rotation angle. + /// - animated: set true to animate rotation (default is true). + /// - duration: animation duration in seconds (default is 1 second). + /// - completion: optional completion handler to run with animation finishes (default is nil). + func rotate(byAngle angle: CGFloat, ofType type: AngleUnit, animated: Bool = false, duration: TimeInterval = 1, completion: ((Bool) -> Void)? = nil) { + let angleWithType = (type == .degrees) ? .pi * angle / 180.0 : angle + let aDuration = animated ? duration : 0 + UIView.animate(withDuration: aDuration, delay: 0, options: .curveLinear, animations: { () -> Void in + self.transform = self.transform.rotated(by: angleWithType) + }, completion: completion) + } + + /// SwifterSwift: Rotate view to angle on fixed axis. + /// + /// - Parameters: + /// - angle: angle to rotate view to. + /// - type: type of the rotation angle. + /// - animated: set true to animate rotation (default is false). + /// - duration: animation duration in seconds (default is 1 second). + /// - completion: optional completion handler to run with animation finishes (default is nil). + func rotate(toAngle angle: CGFloat, ofType type: AngleUnit, animated: Bool = false, duration: TimeInterval = 1, completion: ((Bool) -> Void)? = nil) { + let angleWithType = (type == .degrees) ? .pi * angle / 180.0 : angle + let aDuration = animated ? duration : 0 + UIView.animate(withDuration: aDuration, animations: { + self.transform = self.transform.concatenating(CGAffineTransform(rotationAngle: angleWithType)) + }, completion: completion) + } + + /// SwifterSwift: Scale view by offset. + /// + /// - Parameters: + /// - offset: scale offset + /// - animated: set true to animate scaling (default is false). + /// - duration: animation duration in seconds (default is 1 second). + /// - completion: optional completion handler to run with animation finishes (default is nil). + func scale(by offset: CGPoint, animated: Bool = false, duration: TimeInterval = 1, completion: ((Bool) -> Void)? = nil) { + if animated { + UIView.animate(withDuration: duration, delay: 0, options: .curveLinear, animations: { () -> Void in + self.transform = self.transform.scaledBy(x: offset.x, y: offset.y) + }, completion: completion) + } else { + transform = transform.scaledBy(x: offset.x, y: offset.y) + completion?(true) + } + } + + /// SwifterSwift: Shake view. + /// + /// - Parameters: + /// - direction: shake direction (horizontal or vertical), (default is .horizontal) + /// - duration: animation duration in seconds (default is 1 second). + /// - animationType: shake animation type (default is .easeOut). + /// - completion: optional completion handler to run with animation finishes (default is nil). + func shake(direction: ShakeDirection = .horizontal, duration: TimeInterval = 1, animationType: ShakeAnimationType = .easeOut, completion:(() -> Void)? = nil) { + CATransaction.begin() + let animation: CAKeyframeAnimation + switch direction { + case .horizontal: + animation = CAKeyframeAnimation(keyPath: "transform.translation.x") + case .vertical: + animation = CAKeyframeAnimation(keyPath: "transform.translation.y") + } + switch animationType { + case .linear: + animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear) + case .easeIn: + animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn) + case .easeOut: + animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut) + case .easeInOut: + animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut) + } + CATransaction.setCompletionBlock(completion) + animation.duration = duration + animation.values = [-20.0, 20.0, -20.0, 20.0, -10.0, 10.0, -5.0, 5.0, 0.0 ] + layer.add(animation, forKey: "shake") + CATransaction.commit() + } + + /// SwifterSwift: Add Visual Format constraints. + /// + /// - Parameters: + /// - withFormat: visual Format language + /// - views: array of views which will be accessed starting with index 0 (example: [v0], [v1], [v2]..) + @available(iOS 9, *) func addConstraints(withFormat: String, views: UIView...) { + // https://videos.letsbuildthatapp.com/ + var viewsDictionary: [String: UIView] = [:] + for (index, view) in views.enumerated() { + let key = "v\(index)" + view.translatesAutoresizingMaskIntoConstraints = false + viewsDictionary[key] = view + } + addConstraints(NSLayoutConstraint.constraints(withVisualFormat: withFormat, options: NSLayoutConstraint.FormatOptions(), metrics: nil, views: viewsDictionary)) + } + + /// SwifterSwift: Anchor all sides of the view into it's superview. + @available(iOS 9, *) + func fillToSuperview() { + // https://videos.letsbuildthatapp.com/ + translatesAutoresizingMaskIntoConstraints = false + if let superview = superview { + let left = leftAnchor.constraint(equalTo: superview.leftAnchor) + let right = rightAnchor.constraint(equalTo: superview.rightAnchor) + let top = topAnchor.constraint(equalTo: superview.topAnchor) + let bottom = bottomAnchor.constraint(equalTo: superview.bottomAnchor) + NSLayoutConstraint.activate([left, right, top, bottom]) + } + } + + /// SwifterSwift: Add anchors from any side of the current view into the specified anchors and returns the newly added constraints. + /// + /// - Parameters: + /// - top: current view's top anchor will be anchored into the specified anchor + /// - left: current view's left anchor will be anchored into the specified anchor + /// - bottom: current view's bottom anchor will be anchored into the specified anchor + /// - right: current view's right anchor will be anchored into the specified anchor + /// - topConstant: current view's top anchor margin + /// - leftConstant: current view's left anchor margin + /// - bottomConstant: current view's bottom anchor margin + /// - rightConstant: current view's right anchor margin + /// - widthConstant: current view's width + /// - heightConstant: current view's height + /// - Returns: array of newly added constraints (if applicable). + @available(iOS 9, *) + @discardableResult + func anchor( + top: NSLayoutYAxisAnchor? = nil, + left: NSLayoutXAxisAnchor? = nil, + bottom: NSLayoutYAxisAnchor? = nil, + right: NSLayoutXAxisAnchor? = nil, + topConstant: CGFloat = 0, + leftConstant: CGFloat = 0, + bottomConstant: CGFloat = 0, + rightConstant: CGFloat = 0, + widthConstant: CGFloat = 0, + heightConstant: CGFloat = 0) -> [NSLayoutConstraint] { + // https://videos.letsbuildthatapp.com/ + translatesAutoresizingMaskIntoConstraints = false + + var anchors = [NSLayoutConstraint]() + + if let top = top { + anchors.append(topAnchor.constraint(equalTo: top, constant: topConstant)) + } + + if let left = left { + anchors.append(leftAnchor.constraint(equalTo: left, constant: leftConstant)) + } + + if let bottom = bottom { + anchors.append(bottomAnchor.constraint(equalTo: bottom, constant: -bottomConstant)) + } + + if let right = right { + anchors.append(rightAnchor.constraint(equalTo: right, constant: -rightConstant)) + } + + if widthConstant > 0 { + anchors.append(widthAnchor.constraint(equalToConstant: widthConstant)) + } + + if heightConstant > 0 { + anchors.append(heightAnchor.constraint(equalToConstant: heightConstant)) + } + + anchors.forEach({$0.isActive = true}) + + return anchors + } + + /// SwifterSwift: Anchor center X into current view's superview with a constant margin value. + /// + /// - Parameter constant: constant of the anchor constraint (default is 0). + @available(iOS 9, *) + func anchorCenterXToSuperview(constant: CGFloat = 0) { + // https://videos.letsbuildthatapp.com/ + translatesAutoresizingMaskIntoConstraints = false + if let anchor = superview?.centerXAnchor { + centerXAnchor.constraint(equalTo: anchor, constant: constant).isActive = true + } + } + + /// SwifterSwift: Anchor center Y into current view's superview with a constant margin value. + /// + /// - Parameter withConstant: constant of the anchor constraint (default is 0). + @available(iOS 9, *) + func anchorCenterYToSuperview(constant: CGFloat = 0) { + // https://videos.letsbuildthatapp.com/ + translatesAutoresizingMaskIntoConstraints = false + if let anchor = superview?.centerYAnchor { + centerYAnchor.constraint(equalTo: anchor, constant: constant).isActive = true + } + } + + /// SwifterSwift: Anchor center X and Y into current view's superview + @available(iOS 9, *) + func anchorCenterSuperview() { + // https://videos.letsbuildthatapp.com/ + anchorCenterXToSuperview() + anchorCenterYToSuperview() + } + + /// SwifterSwift: Search all superviews until a view with the condition is found. + /// + /// - Parameter predicate: predicate to evaluate on superviews. + func ancestorView(where predicate: (UIView?) -> Bool) -> UIView? { + if predicate(superview) { + return superview + } + return superview?.ancestorView(where: predicate) + } + + /// SwifterSwift: Search all superviews until a view with this class is found. + /// + /// - Parameter name: class of the view to search. + func ancestorView(withClass name: T.Type) -> T? { + return ancestorView(where: { $0 is T }) as? T + } + +} + +#endif + + +extension UIView { + + /// 画虚线,调用之前请确保能获取到frame + /// 如果有多个calayer在当前空间 会使其他layer失效 + /// - Parameters: + /// - lineLength: 每一节线长 + /// - lineSpacing: 间距 + /// - lineColor: 颜色 + /// - isHorizontal: 是否水平 + public func drawDashLine(lineLength: Int, lineSpacing: Int, lineColor: UIColor, isHorizontal: Bool = true) { + + if let sublayers = self.layer.sublayers { + for sublayer in sublayers { + sublayer.removeFromSuperlayer() + } + + } + // self.layer.sublayers = nil + + let shapeLayer = CAShapeLayer() + shapeLayer.bounds = self.bounds + // 只要是CALayer这种类型,他的anchorPoint默认都是(0.5,0.5) + shapeLayer.anchorPoint = CGPoint(x: 0, y: 0) + // shapeLayer.fillColor = UIColor.blue.cgColor + shapeLayer.strokeColor = lineColor.cgColor + + // shapeLayer.lineWidth = self.frame.size.height + // shapeLayer.lineJoin = CAShapeLayerLineJoin.round + + shapeLayer.lineDashPattern = [NSNumber(value: lineLength), NSNumber(value: lineSpacing)] + + let path = CGMutablePath() + path.move(to: CGPoint(x: 0, y: 0)) + if isHorizontal { + path.addLine(to: CGPoint(x: self.frame.size.width, y: 0)) + } else { + path.addLine(to: CGPoint(x: 0, y: self.frame.size.height)) + } + shapeLayer.path = path + self.layer.addSublayer(shapeLayer) + } + + + func drawDashBorder(length: CGFloat, width: CGFloat, spacing: CGFloat, color: UIColor) { + guard frame != .zero else { return } + + let topLine = CAShapeLayer() + let leftLine = CAShapeLayer() + let rightLine = CAShapeLayer() + let bottomLine = CAShapeLayer() + + topLine.bounds = CGRect(x: 0, y: 0, width: frame.width, height: width) + leftLine.bounds = CGRect(x: 0, y: 0, width: width, height: frame.height) + rightLine.bounds = CGRect(x: 0, y: 0, width: width, height: frame.height) + bottomLine.bounds = CGRect(x: 0, y: 0, width: frame.width, height: width) + } + + func drawBoardBottedLine(width: CGFloat, length: CGFloat, space: CGFloat, radius: CGFloat, color: UIColor) { + layer.cornerRadius = radius + let borderLayer = CAShapeLayer() + borderLayer.bounds = bounds + + borderLayer.position = CGPoint(x: bounds.midX , y: bounds.midY) + borderLayer.path = UIBezierPath(roundedRect: borderLayer.bounds, cornerRadius: radius).cgPath + borderLayer.lineWidth = width / UIScreen.main.scale + + borderLayer.lineDashPattern = [length, space] as [NSNumber] + borderLayer.lineDashPhase = 0.1 + + borderLayer.fillColor = UIColor.clear.cgColor + borderLayer.strokeColor = color.cgColor + + layer.addSublayer(borderLayer) + + } +} + +extension UIView { + + public func shadow(color: UIColor, offset: CGSize, opacity: Float, radius: CGFloat) { + layer.shadowColor = color.cgColor + layer.shadowOffset = offset + layer.shadowOpacity = opacity + layer.shadowRadius = radius + layer.masksToBounds = false +// layer.cornerRadius = radius + } +} + +extension UIView { + + /// 试图 缩放动画 + /// - Parameter scaleMax: 放大比例 原始1 + /// - Parameter scaleMin: 缩小比例 原始1 + /// - Parameter count: 缩放次数 + public func zoom(scaleMax: CGFloat, scaleMin: CGFloat, count: Int) { + + let maxTrans = CGAffineTransform(scaleX: scaleMax, y: scaleMax) + let minTrans = CGAffineTransform(scaleX: scaleMin, y: scaleMin) + + self.transform = minTrans + + zoomAnimation(minTrans: minTrans, maxTrans: maxTrans, maxCount: count) + } + + private func zoomAnimation(minTrans: CGAffineTransform, maxTrans: CGAffineTransform, maxCount: Int, currentCount: Int = 1) { + + let animtionDuration: TimeInterval = 0.6 + let completionDuration: TimeInterval = 0.3 + + UIView.animate(withDuration: animtionDuration, animations: { + self.transform = maxTrans + }, completion: { result in + UIView.animate(withDuration: animtionDuration, animations: { + self.transform = minTrans + }, completion: { result in + let newCurrent = currentCount + 1 + if newCurrent <= maxCount { + self.zoomAnimation(minTrans: minTrans, maxTrans: maxTrans, maxCount: maxCount, currentCount: newCurrent) + } else { + UIView.animate(withDuration: completionDuration, animations: { + self.transform = CGAffineTransform(scaleX: 1, y: 1) + }) + } + }) + }) + } + +} + + +extension UIView{ + func rotate() { + let rotation : CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation.z") + rotation.toValue = NSNumber(value: Double.pi * 2) + rotation.duration = 1 + rotation.isCumulative = true + rotation.repeatCount = Float.greatestFiniteMagnitude + self.layer.add(rotation, forKey: "rotationAnimation") + } +} diff --git a/LingQi/LingQi/Tools/Extensions/YCDevelop.swift b/LingQi/LingQi/Tools/Extensions/YCDevelop.swift new file mode 100644 index 0000000..efe1504 --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/YCDevelop.swift @@ -0,0 +1,51 @@ +// +// YCDevelop.swift +// YCDevTools +// +// Created by Liang ZhenYing on 2020/3/5. +// Copyright © 2020 zkys. All rights reserved. +// + +import UIKit +import UserNotifications + +public final class YCDevelop { + public let base: Base + public init(_ base: Base) { + self.base = base + } +} + +public protocol YCDevelopCompatible { + associatedtype YCDevelopType + var yc: YCDevelop { get } + static var yc: YCDevelop.Type { get } +} + +extension YCDevelopCompatible { + public var yc: YCDevelop { + get { return YCDevelop(self) } + } + public static var yc: YCDevelop.Type { + get { return YCDevelop.self } + } +} + +extension String: YCDevelopCompatible { } +extension CALayer: YCDevelopCompatible { } +extension TimeInterval: YCDevelopCompatible { } +extension Int: YCDevelopCompatible { } +extension UIImage: YCDevelopCompatible { } +extension UIView: YCDevelopCompatible { } +extension FileManager: YCDevelopCompatible { } +extension UIColor: YCDevelopCompatible { } +extension UIBarButtonItem: YCDevelopCompatible { } +extension UIApplication: YCDevelopCompatible { } +extension Dictionary: YCDevelopCompatible { } +extension CGSize: YCDevelopCompatible { } +extension CGRect: YCDevelopCompatible { } +extension Date: YCDevelopCompatible { } +extension Array: YCDevelopCompatible { } +extension UIViewController: YCDevelopCompatible { } +extension NSAttributedString: YCDevelopCompatible { } +extension UNUserNotificationCenter: YCDevelopCompatible { } diff --git a/LingQi/LingQi/Tools/Extensions/zhString.swift b/LingQi/LingQi/Tools/Extensions/zhString.swift new file mode 100644 index 0000000..dbb19cd --- /dev/null +++ b/LingQi/LingQi/Tools/Extensions/zhString.swift @@ -0,0 +1,52 @@ +// +// zhString.swift +// kjxq +// +// Created by Spec on 2021/1/5. +// + +import Foundation + +extension String { + func isIncludeChinese() -> Bool { + for ch in self.unicodeScalars { + // 中文字符范围:0x4e00 ~ 0x9fff + if (0x4e00 < ch.value && ch.value < 0x9fff) { + return true + } + } + return false + } + func transformToPinyin() -> String { + let stringRef = NSMutableString(string: self) as CFMutableString + // 转换为带音标的拼音 + CFStringTransform(stringRef,nil, kCFStringTransformToLatin, false); + // 去掉音标 + CFStringTransform(stringRef, nil, kCFStringTransformStripCombiningMarks, false); + let pinyin = stringRef as String; + + return pinyin + } + func transformToPinyinWithoutBlank() -> String { + var pinyin = self.transformToPinyin() + // 去掉空格 +// pinyin = pinyin.stringByReplacingOccurrencesOfString(" ", withString: "") +// pinyin = pinyin.trimmed + pinyin = String(pinyin.filter { !" \n\t\r".contains($0) }) + return pinyin + } + func getPinyinHead() -> String { + // 字符串转换为首字母大写 + let pinyin = self.transformToPinyinWithoutBlank().capitalized//.capitalizedString + var headPinyinStr = "" + + // 获取所有大写字母 + for ch in pinyin { + if ch <= "Z" && ch >= "A" { + headPinyinStr.append(ch) + } + } + return headPinyinStr + } + +} diff --git a/LingQi/LingQi/Tools/LogManager.swift b/LingQi/LingQi/Tools/LogManager.swift new file mode 100644 index 0000000..c03cc1b --- /dev/null +++ b/LingQi/LingQi/Tools/LogManager.swift @@ -0,0 +1,59 @@ +// +// LogManager.swift +// Magpie +// +// Created by incar on 2024/1/3. +// + +import Foundation +import UIKit + +class LogManager:NSObject{ + + static let instance = LogManager() + + var log = "start..." + + + func add(_ text:String){ + let conent = currentTime() + " ~ " + text + print(conent) + log += conent + "\n" + } + + func saveToFile(){ + let document = NSHomeDirectory() + "/Documents/" + let fileName = currentTime() + ".txt" + let path = document + fileName + let urlPath = URL(fileURLWithPath: path) + + do{ + try log.write(to: urlPath, atomically: true, encoding: .utf8) + print("保存成功") + saveFile(filePath: path) + }catch{ + print("保存失败!!!!!!!") + } + } + + func currentTime()->String{ + let dateformatter = DateFormatter() + dateformatter.dateFormat = "YYYY-MM-dd HH:mm:ss S"// 自定义时间格式 + let time = dateformatter.string(from: Date()) + return time + } +} + +extension LogManager:UIDocumentPickerDelegate{ + //保存文件到手机文件指定目录 + func saveFile(filePath:String) { + let fUrl = NSURL(fileURLWithPath: filePath) + let vc = UIDocumentPickerViewController(url: fUrl as URL, in: .exportToService); + vc.delegate = self + vc.modalPresentationStyle = .overFullScreen + UIApplication.shared.keyWindow?.rootViewController?.present(vc, animated: true) + } + public func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { + controller.dismiss(animated: true) + } +} diff --git a/LingQi/LingQi/Tools/Logs.swift b/LingQi/LingQi/Tools/Logs.swift new file mode 100644 index 0000000..6094025 --- /dev/null +++ b/LingQi/LingQi/Tools/Logs.swift @@ -0,0 +1,19 @@ +// +// Logs.swift +// Syntax-SNSwfitPackage +// +// Created by zyt on 2018/12/20. +// Copyright © 2018 zsh. All rights reserved. +// + +import Foundation + + +public func SNLog(_ message: T, file: String = #file, function: String = #function, line: Int = #line) { + #if DEBUG + var fileName = file as NSString + + fileName = fileName.lastPathComponent as NSString + print("[\(Date().timeIntervalSince1970) \(fileName)--\(function)--\(line) : \(message)]") + #endif +} diff --git a/LingQi/LingQi/Tools/NumberToTime.swift b/LingQi/LingQi/Tools/NumberToTime.swift new file mode 100644 index 0000000..dca3ae6 --- /dev/null +++ b/LingQi/LingQi/Tools/NumberToTime.swift @@ -0,0 +1,55 @@ +// +// NumberToTime.swift +// HTDevelop +// +// Created by 李扬 on 2019/1/3. +// Copyright © 2019 rrl360. All rights reserved. +// + +import UIKit + +public protocol NumerToTime { + var num: TimeInterval { get } + + var millisecond: TimeInterval { get } + var milliseconds: TimeInterval { get } + var ms: TimeInterval { get } + + var second: TimeInterval { get } + var seconds: TimeInterval { get } + + var minute: TimeInterval { get } + var minutes: TimeInterval { get } + + var hour: TimeInterval { get } + var hours: TimeInterval { get } + + var day: TimeInterval { get } + var days: TimeInterval { get } +} +public extension NumerToTime { + var millisecond: TimeInterval { return num / 1000 } + var milliseconds: TimeInterval { return num / 1000 } + var ms: TimeInterval { return num / 1000 } + + var second: TimeInterval { return num } + var seconds: TimeInterval { return num } + + var minute: TimeInterval { return num * 60 } + var minutes: TimeInterval { return num * 60 } + + var hour: TimeInterval { return num * 3600 } + var hours: TimeInterval { return num * 3600 } + + var day: TimeInterval { return num * 3600 * 24 } + var days: TimeInterval { return num * 3600 * 24 } +} + +extension Int: NumerToTime { + public var num: TimeInterval { return TimeInterval(self) } +} +extension Double: NumerToTime { + public var num: TimeInterval { return self } +} + + diff --git a/LingQi/LingQi/Tools/ShareView.swift b/LingQi/LingQi/Tools/ShareView.swift new file mode 100644 index 0000000..9bb1bc6 --- /dev/null +++ b/LingQi/LingQi/Tools/ShareView.swift @@ -0,0 +1,140 @@ +//// +//// ShareView.swift +//// Magpie +//// +//// Created by incar on 2024/1/10. +//// +// +//import Foundation +//extension UnAuthSchoolDetailVC{ +// class AgreementView: YLPresentView { +// private let titleLabel = UILabel() +// private let des = UILabel() +// private let selectButton = UIButton() +// private let privacyLabel = UILabel() +// private let okButton = AnimationButton() +// private var vm:ClassDetailVM +// +// init(code:String) { +// self.vm = ClassDetailVM(code:code) +// super.init(contentHeight: 400.fitR) +// } +// +// override func setupSubView() { +// super.setupSubView() +// contentView.addSubview(titleLabel) +// contentView.addSubview(des) +// contentView.addSubview(selectButton) +// contentView.addSubview(privacyLabel) +// contentView.addSubview(okButton) +// } +// override func setupLayout() { +// super.setupLayout() +// titleLabel.snp.makeConstraints { (m) in +// m.top.equalToSuperview().inset(25.fitR) +// m.left.right.equalToSuperview() +// m.height.greaterThanOrEqualTo(0) +// } +// des.snp.makeConstraints { (m) in +// m.left.right.equalToSuperview().inset(20.fitR) +// m.top.equalToSuperview().inset(67.fitR) +// } +// selectButton.snp.makeConstraints { (m) in +// m.left.equalToSuperview().inset(20.fitR) +// m.bottom.equalToSuperview().inset(96.fitR) +// m.height.equalTo(15.fitR) +// m.width.equalTo(15.fitR) +// } +// privacyLabel.snp.makeConstraints { (m) in +// m.left.equalTo(selectButton.snp.right) +// m.centerY.equalTo(selectButton) +// } +// okButton.snp.makeConstraints { (m) in +// m.bottom.equalToSuperview().inset(30.fitR) +// m.height.equalTo(44.fitR) +// m.left.right.equalToSuperview().inset(25.fitR) +// } +// } +// +// override func setupStyle() { +// super.setupStyle() +// titleLabel.do { (v) in +// v.textColor = .rgb(0x333333) +// v.font = .semiBold(16) +// v.textAlignment = .center +// v.text = "诸葛驾到代运营协议说明" +// } +// des.do { (v) in +// v.text = "1.用户通过诸葛驾到寻找到合适的驾校后,委托诸葛驾到负责撮合驾校学车的服务提供方,为用户代报名指定班型的学车服务,在代报名过程中提供驾校信息核验、学车权益守护、学车资金托管、代理结算等服务。具体服务内容由诸葛驾到根据实际情况提供,包括但不限于: (1) 作为用户的学车经纪人代表用户与驾校签约学车报名协议;(2)学车报名资金的托管; (3) 维护用户在驾校学车的约定权益;(4) 服务商收入结算和用户支付费用:具体金额以产生的统计数据为准;(5) 订单查询;2.用户通过诸葛驾到完成的学车报名信息以平台发布的相应信息为准,交易应签署《学车报名服务合同》。具体内容《学车报名服务合同》以约定为准,该合同文本格式由诸葛驾到平台的驾校提供,经诸葛驾到平台撮合,由用户与诸葛驾到平台的驾校直接签约。所有发给用户的通告及其他消息都可通过APP或者用户所提供的联系方式发送 。" +// v.textAlignment = .left +// v.numberOfLines = 0 +// v.font = .regular(12) +// v.textColor = .rgb(0x666666) +// } +// selectButton.do { (v) in +// v.yc.setBorder(width: 1.fitR, color: .rgb(0x999999), radius: 2.fitR) +// v.setImage(nil, for: .normal) +// v.addTarget(self, action: #selector(selectBtnAction), for: .touchUpInside) +// } +// privacyLabel.do { (v) in +// v.text = " 已阅读同意协议说明" +// v.textAlignment = .left +// v.numberOfLines = 1 +// v.font = .regular(12) +// v.textColor = .rgb(0x999999) +// privacyLabel.yc.addTap(target: self, action: #selector(selectBtnAction)) +// } +// okButton.do { (v) in +// v.isEnabled = false +// v.yc.addGardiendLayerWith(colors: [.color(.mainBlue),.color(.mainBlue)], frame: CGRect(x: 0, y: 0, width: kScreenWid - 50.fitR, height: 44.fitR), direction: .left2right) +// v.setTitle("下一步", for: .normal) +// v.setTitleColor(.color(.white), for: .normal) +// v.titleLabel?.font = .regular(15) +// v.yc.setCornerRadius(22.fitR) +// v.alpha = 0.5 +// v.addTarget(self, action: #selector(okButtonAction), for: .touchUpInside) +// self.selectBtnAction() +// +// } +// } +// @objc func okButtonAction(){ +//// self.okButtonTap?() +//// hide() +// self.start2LoadData() +// } +// @objc func selectBtnAction(){ +// selectButton.isSelected = !selectButton.isSelected +// if selectButton.isSelected { +// selectButton.yc.setBorder(width: 1.fitR, color: .rgb(0x036AFF), radius: 2.fitR) +// selectButton.setImage(UIImage(named: "agreement_selected"), for: .normal) +// privacyLabel.textColor = .rgb(0x036AFF) +// okButton.alpha = 1 +// } +// else{ +// selectButton.yc.setBorder(width: 1.fitR, color: .rgb(0x999999), radius: 2.fitR) +// selectButton.setImage(nil, for: .normal) +// privacyLabel.textColor = .rgb(0x999999) +// okButton.alpha = 0.5 +// } +// okButton.isEnabled = selectButton.isSelected +// } +// +// func start2LoadData(){ +// SVProgressHUD.showLoading() +// SVProgressHUD.setContainerView(app.window) +// self.vm.fetchClassDetail{[weak self] (model) in +// guard let self = self else {return} +// if model.isSuccess{ +// SVProgressHUD.hidden() +// self.hide() +// let params = PayDetailVCParams(model:model.data) +// let vc = PayDetailVC(data: params) +// UIViewController.yc.currentNav?.pushViewController(vc, animated: true) +// } +// else{ +// SVProgressHUD.showAutoHiden(model.msg) +// } +// } +// } +// } +//} diff --git a/LingQi/LingQi/Tools/SizeFit.swift b/LingQi/LingQi/Tools/SizeFit.swift new file mode 100644 index 0000000..875b57f --- /dev/null +++ b/LingQi/LingQi/Tools/SizeFit.swift @@ -0,0 +1,90 @@ +// +// SizeFit.swift +// zgjd +// +// Created by apple on 2020/11/9. +// + +import UIKit + +final class ScreenSize { + + static let shared = ScreenSize() + init() { + p_refreshData() + } + + private(set) var screenWidthRatio: CGFloat = 1 + private(set) var screenHeightRatio: CGFloat = 1 + private(set) var isIphonex = false + + // 默认参考 size = (375,667) + private let designSize = CGSize.init(width: 375, height: 667) + private func p_refreshData() { + let screenWidth = UIScreen.main.bounds.size.width + let screenHeight = UIScreen.main.bounds.size.height + screenWidthRatio = screenWidth / designSize.width + screenHeightRatio = screenHeight / designSize.height + + if #available(iOS 11.0, *), + UIApplication.shared.delegate? + .window??.safeAreaInsets.bottom != 0 { + isIphonex = true + } + } +} + + +public protocol SizeTransform { + var cgFloat: CGFloat { get } + var round: CGFloat { get } + var ceil: CGFloat { get } + var floor: CGFloat { get } + var abs: CGFloat { get } + var fitR: CGFloat { get } + var fitC: CGFloat { get } + var fitF: CGFloat { get } + var fitT: CGFloat { get } + + var double: Double { get } + var float: Float { get } + var half: CGFloat { get } + var int: Int { get } +} + +public extension SizeTransform { + + var round: CGFloat { return CGFloat(roundf(float)) } + var ceil: CGFloat { return CGFloat(ceilf(float)) } + var floor: CGFloat { return CGFloat(floorf(float)) } + var abs: CGFloat { return CGFloat(fabsf(float)) } + var fitR: CGFloat + { return (ScreenSize.shared.screenWidthRatio * cgFloat).round } + var fitC: CGFloat + { return (ScreenSize.shared.screenWidthRatio * cgFloat).ceil } + var fitF: CGFloat + { return (ScreenSize.shared.screenWidthRatio * cgFloat).floor } + var fitT: CGFloat + { return (ScreenSize.shared.screenWidthRatio * cgFloat) } + + var double: Double { return Double(cgFloat) } + var float: Float { return Float(cgFloat) } + var half: CGFloat { return cgFloat * 0.5 } + var int: Int { return Int(float) } +} + +extension Int: SizeTransform { + public var cgFloat: CGFloat { return CGFloat(self) } + public var int: Int { return self } +} +extension CGFloat: SizeTransform { + public var cgFloat: CGFloat { return self } +} +extension Double: SizeTransform { + public var cgFloat: CGFloat { return CGFloat(self) } + public var double: Double { return self } +} +extension Float: SizeTransform { + public var cgFloat: CGFloat { return CGFloat(self) } + public var float: Float { return self } +} diff --git a/LingQi/LingQi/Tools/Then.swift b/LingQi/LingQi/Tools/Then.swift new file mode 100755 index 0000000..c7e0966 --- /dev/null +++ b/LingQi/LingQi/Tools/Then.swift @@ -0,0 +1,105 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 Suyeol Jeon (xoul.kr) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import Foundation +import CoreGraphics +#if os(iOS) || os(tvOS) + import UIKit.UIGeometry +#endif + +public protocol Then {} + +extension Then where Self: Any { + + /// Makes it available to set properties with closures just after initializing and copying the value types. + /// + /// let frame = CGRect().with { + /// $0.origin.x = 10 + /// $0.size.width = 100 + /// } + public func with(_ block: (inout Self) throws -> Void) rethrows -> Self { + var copy = self + try block(©) + return copy + } + + /// Makes it available to execute something with closures. + /// + /// UserDefaults.standard.do { + /// $0.set("devxoul", forKey: "username") + /// $0.set("devxoul@gmail.com", forKey: "email") + /// $0.synchronize() + /// } + public func `do`(_ block: (Self) throws -> Void) rethrows { + try block(self) + } + +} + +extension Then where Self: AnyObject { + + /// Makes it available to set properties with closures just after initializing. + /// + /// let label = UILabel().then { + /// $0.textAlignment = .center + /// $0.textColor = UIColor.black + /// $0.text = "Hello, World!" + /// } + public func then(_ block: (Self) throws -> Void) rethrows -> Self { + try block(self) + return self + } + +} + +extension NSObject: Then {} + +extension CGPoint: Then {} +extension CGRect: Then {} +extension CGSize: Then {} +extension CGVector: Then {} +extension Array: Then {} +extension Dictionary: Then {} +extension Set: Then {} + +#if os(iOS) || os(tvOS) + extension UIEdgeInsets: Then {} + extension UIOffset: Then {} + extension UIRectEdge: Then {} +#endif + + +extension Then where Self: UIView { + public func add(toSuperView superView: UIView) -> Self { + guard superview != self else { return self } + superView.addSubview(self) + return self + } +} + +extension Array where Element: UIView { + public func `do`(_ block: (Element) throws -> Void) rethrows { + for e in self { + try block(e) + } + } +} diff --git a/LingQi/LingQi/Tools/TimerButton/YLTimerButton.h b/LingQi/LingQi/Tools/TimerButton/YLTimerButton.h new file mode 100644 index 0000000..1d10193 --- /dev/null +++ b/LingQi/LingQi/Tools/TimerButton/YLTimerButton.h @@ -0,0 +1,15 @@ +// +// YLTimerButton.h +// YLProject +// +// Created by Mac01 on 2018/3/24. +// Copyright © 2018å¹´ Mac01. All rights reserved. +// + +#import +@interface YLTimerButton : UIButton +@property(nonatomic, strong) UILabel *label; +@property(nonatomic, assign) NSInteger maxCount; + +- (void)start; +@end diff --git a/LingQi/LingQi/Tools/TimerButton/YLTimerButton.m b/LingQi/LingQi/Tools/TimerButton/YLTimerButton.m new file mode 100644 index 0000000..69e075a --- /dev/null +++ b/LingQi/LingQi/Tools/TimerButton/YLTimerButton.m @@ -0,0 +1,114 @@ +// +// YLTimerButton.m +// YLProject +// +// Created by Mac01 on 2018/3/24. +// Copyright © 2018å¹´ Mac01. All rights reserved. +// + +#import "YLTimerButton.h" + + +@interface YLTimerButton () + +@property(nonatomic, assign) NSInteger second; +@property(nonatomic, strong) NSTimer *timer; +@property(nonatomic, strong) NSDate *lastTime; +@end + +@implementation YLTimerButton + +- (instancetype)initWithFrame:(CGRect)frame{ + if (self = [super initWithFrame:frame]) { + self.maxCount = 60; + + [self setTitle:@"" forState:UIControlStateNormal]; + self.titleLabel.font = [UIFont systemFontOfSize:14]; + + self.layer.cornerRadius = 5; + self.layer.masksToBounds = YES; + + self.label = [[UILabel alloc]initWithFrame:self.bounds]; + self.label.text = @"获取验证码"; + self.label.font = [UIFont systemFontOfSize:14]; + self.label.textColor = [UIColor blueColor]; + self.label.textAlignment = NSTextAlignmentCenter; + self.label.backgroundColor = [UIColor clearColor]; + [self addSubview:self.label]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(enterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(becomeActive) name:UIApplicationDidBecomeActiveNotification object:nil]; + } + return self; +} + +-(void)layoutSubviews{ + [super layoutSubviews]; + self.label.frame = self.bounds; +// self.backgroundColor = [UIColor redColor]; +} + +- (void)start { + self.enabled = NO; + self.second = self.maxCount; + self.label.textColor = [UIColor colorWithRed:67/255.0f green:155/255.0f blue:255/255.0f alpha:1.0f]; + self.label.text = [NSString stringWithFormat:@"%ld秒",self.second]; + self.timer = [NSTimer scheduledTimerWithTimeInterval:1 + target:self + selector:@selector(count) + userInfo:nil + repeats:YES]; +} + +- (void)stop { + self.enabled = YES; + self.label.text = @"发送验证码"; + self.label.textColor = [UIColor colorWithRed:67/255.0f green:155/255.0f blue:255/255.0f alpha:1.0f]; + if ([self.timer isValid]) { + [self.timer invalidate]; + } +} + +- (void)count { + self.second--; + if (self.second < 0) { + self.second = 0; + } + + self.label.text = [NSString stringWithFormat:@"%ldS", (long)self.second]; + if (self.second == 0) { + [self stop]; + } +} + + +#pragma mark - notification +- (void)enterBackground{ + if ([self.timer isValid]) { + [self.timer invalidate]; + self.lastTime = [NSDate date]; + } + else{ + self.lastTime = nil; + } +} + +- (void)becomeActive{ + if (self.lastTime == nil) { + return; + } + NSInteger count = [self.lastTime timeIntervalSinceNow]; + self.second -= ABS(count); + if (self.second > 0) { + self.timer = [NSTimer scheduledTimerWithTimeInterval:1 + target:self + selector:@selector(count) + userInfo:nil + repeats:YES]; + } + else{ + [self count]; + } +} +@end + diff --git a/LingQi/LingQi/UI/Base/BaseNC.swift b/LingQi/LingQi/UI/Base/BaseNC.swift new file mode 100644 index 0000000..22ca3c8 --- /dev/null +++ b/LingQi/LingQi/UI/Base/BaseNC.swift @@ -0,0 +1,16 @@ +// +// BaseNC.swift +// Magpie +// +// Created by incar on 2024/1/2. +// + +import UIKit + +class BaseNC:UINavigationController{ + + override func viewDidLoad() { + super.viewDidLoad() + + } +} diff --git a/LingQi/LingQi/UI/Base/BaseNavigation.swift b/LingQi/LingQi/UI/Base/BaseNavigation.swift new file mode 100644 index 0000000..1827b08 --- /dev/null +++ b/LingQi/LingQi/UI/Base/BaseNavigation.swift @@ -0,0 +1,173 @@ +// +// YLNavBar.swift +// zgjd +// +// Created by apple on 2020/11/10. +// + +import UIKit + +public enum BaseNavigationLeftStyle { + case back + case close + case title(NSAttributedString) + case image(UIImage?) +} + +public enum BaseNavigationRightStyle { + case share + case title(String, norColor: UIColor, disColor: UIColor) + case image(UIImage?) +} + +public enum BaseNavigationTitleStyle { + case `default` + case custom(titleColor: UIColor, bgColor: UIColor) + case attrTitle(NSAttributedString) +} + +public protocol BaseNavigationBarDelegate: NSObjectProtocol { + func navleftViewTapped() + func navRightViewTapped() +} + +public class BaseNavigationBar: UIView { + + public weak var delegate: BaseNavigationBarDelegate? + public let alphaBgView = UIView() + public let leftView = UIButton() + public let titleLabel = UILabel() + public let separatorLine = UIView() + public lazy var rightView: UIButton = { + return setupRightView() + }() + + private var navTitle: String + public init(title: String = "", delegate: BaseNavigationBarDelegate? = nil) { + self.navTitle = title + self.delegate = delegate + super.init(frame: .zero) + + setupLayout() + setupStyle() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + var title: String { + get { return titleLabel.text ?? "" } + set { titleLabel.text = newValue } + } + + func setupLeftStyle(_ style: BaseNavigationLeftStyle) { + switch style { + case .back: + leftView.setImage(UIImage(named: "arrow_left_1"), for: .normal) + case .close: + leftView.setImage(UIImage(named: "arrow_left_1"), for: .normal) + case .title(let attrStr): + leftView.setImage(nil, for: .normal) + leftView.setAttributedTitle(attrStr, for: .normal) + case .image(let image): + leftView.setImage(image, for: .normal) + } + } + + func setRightStyle(_ style: BaseNavigationRightStyle) -> UIButton { + switch style { + case .share: + let img = UIImage.init(named: "card_detail_share_black")?.withRenderingMode(.alwaysOriginal) + rightView.setImage(img, for: .normal) + case .image(let image): + rightView.setImage(image, for: .normal) + case .title(let title, let norColor, let disColor): + rightView.setTitle(title, for: .normal) + rightView.setTitleColor(norColor, for: .normal) + rightView.setTitleColor(disColor, for: .disabled) + } + return rightView + } + + func setTitleStyle(_ style: BaseNavigationTitleStyle) { + switch style { + case .default: + titleLabel.textColor = .white + self.backgroundColor = .white + case .custom(let titleColor,let bgColor): + titleLabel.textColor = titleColor + self.backgroundColor = bgColor + case .attrTitle(let attrStr): + titleLabel.attributedText = attrStr + + } + } + @objc func leftViewTapped() { + delegate?.navleftViewTapped() + } + @objc func rightViewTapped() { + delegate?.navRightViewTapped() + } + func setupLayout() { + addSubview(alphaBgView) + addSubview(titleLabel) + addSubview(leftView) + addSubview(separatorLine) + let h = kNavBtm + self.frame = CGRect(x: 0, y: 0, width: kScreenWid, height: h) + alphaBgView.frame = CGRect(x: 0, y: 0, width: kScreenWid, height: h) + separatorLine.frame = CGRect(x: 0, y: h - 1, width: kScreenWid, height: 1) + + titleLabel.snp.makeConstraints { (m) in + m.leading.trailing.equalToSuperview().inset(60) + m.top.equalTo(kNavTop) + m.height.equalTo(44) + } + leftView.snp.makeConstraints { (m) in + m.leading.equalToSuperview() + m.top.equalTo(kNavTop) + m.bottom.equalToSuperview() + m.width.greaterThanOrEqualTo(48) + } + } + + func setupStyle() { + backgroundColor = .rgb(0x11131E) + alphaBgView.backgroundColor = UIColor.white + alphaBgView.alpha = 0 + separatorLine.backgroundColor = .color(.separateLine) + separatorLine.isHidden = true + + titleLabel.do { (v) in + v.textColor = .white + v.font = .medium(16) + v.textAlignment = .center + v.lineBreakMode = .byTruncatingTail + v.text = navTitle + } + leftView.do { (v) in + v.contentEdgeInsets = UIEdgeInsets(top: 0, left: 15, bottom: 0, right: 0) + v.contentHorizontalAlignment = .left + v.setImage(UIImage(named: "arrow_back"), for: .normal) + v.addTarget(self, action: #selector(leftViewTapped), for: .touchUpInside) + } + } + + func setupRightView() -> UIButton { + let rightBtn = UIButton() + addSubview(rightBtn) + rightBtn.snp.makeConstraints { (m) in + m.top.equalTo(kNavTop) + m.trailing.bottom.equalToSuperview() + m.width.greaterThanOrEqualTo(48) + } + rightBtn.do { (v) in + v.setTitleColor(.rgb(0x222222), for: .normal) + v.contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 15) + v.imageView?.contentMode = .right + v.addTarget(self, action: #selector(rightViewTapped), for: .touchUpInside) + } + return rightBtn + } +} diff --git a/LingQi/LingQi/UI/Base/BasePickerView.swift b/LingQi/LingQi/UI/Base/BasePickerView.swift new file mode 100644 index 0000000..db385a6 --- /dev/null +++ b/LingQi/LingQi/UI/Base/BasePickerView.swift @@ -0,0 +1,86 @@ +// +// YLDatePicker.swift +// YLDatePicker +// +// Created by yl on 2017/11/15. +// Copyright © 2017å¹´ February12. All rights reserved. +// + +import Foundation +import UIKit + + +class BasePickerView: BasePresentView { + + var didSelectRowBlock: ((_ row:Int)->Void)? + + var dataArray = ["1","2","3","4","5","6","7","8"] + +// private(set) var _currentDate = Date() + + var datePicker = UIPickerView(frame: CGRect(x: 0, y:0, width: kScreenWid, height: 300.fitR)) + + private let titleLabel = UILabel() + private let des = UILabel() + private let selectButton = UIButton() + private let privacyLabel = UILabel() + private let okButton = UIButton() + + init() { + super.init(contentHeight: 300.fitR) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func setupSubView() { + super.setupSubView() + + } + override func setupLayout() { + super.setupLayout() + contentView.addSubview(datePicker) + } + + override func setupStyle() { + super.setupStyle() + // 时间控件 + datePicker.delegate = self + datePicker.dataSource = self + datePicker.backgroundColor = UIColor.clear + +// scrollToDate(components: dateComponentOrder, animated: false) +// datePicker.addLayoutConstraints(attributes: [.left,.right,.top], toItem: self, attributes: nil, constants: [0,0,0]) + } + func setupData(_ list:[String]){ + dataArray = list + datePicker.reloadAllComponents() + } + func selectedIndex(_ index:Int){ + datePicker.selectRow(index, inComponent: 0, animated: false) + } +} + +extension BasePickerView: UIPickerViewDelegate, UIPickerViewDataSource { + public func numberOfComponents(in pickerView: UIPickerView) -> Int { + return 1 + } + + public func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { + return dataArray.count + } + + public func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { + return dataArray[row] + } + + public func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat { + return 43.fitR + } + + public func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { + didSelectRowBlock?(row) + } +} + diff --git a/LingQi/LingQi/UI/Base/BasePresentView.swift b/LingQi/LingQi/UI/Base/BasePresentView.swift new file mode 100644 index 0000000..a0a2c0e --- /dev/null +++ b/LingQi/LingQi/UI/Base/BasePresentView.swift @@ -0,0 +1,78 @@ +// +// SchoolntroView.swift +// zgjd +// +// Created by apple on 2021/1/22. +// + + +import UIKit +class BasePresentView: UIView { + let bgView = UIView() + let contentView = UIView() + var contentH: CGFloat = 250.fitR + init(contentHeight:CGFloat,backgroundEnabled:Bool = true) { + self.contentH = contentHeight + super.init(frame: CGRect(x: 0, y: 0, width: kScreenWid, height: kScreenHei)) + setupSubView() + setupLayout() + setupStyle() + if backgroundEnabled { + bgView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(hide))) + } + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + func setupSubView(){ + addSubview(bgView) + addSubview(contentView) + } + + func setupLayout(){ + bgView.snp.makeConstraints { (make) in + make.edges.equalToSuperview() + } + contentView.snp.makeConstraints { (make) in + make.leading.trailing.bottom.equalToSuperview() + make.height.equalTo(contentH) + } + } + func setupStyle(){ + backgroundColor = UIColor.clear + bgView.backgroundColor = UIColor.init(white: 0, alpha: 0.5) + + contentView.do { (v) in + v.backgroundColor = .white + v.yc.setCorners(withRoundedRect: CGRect(x: 0, y: 0, width: kScreenWid, height: self.contentH), roundingCorners: [.topLeft,.topRight], cornerRadii: CGSize(width: 10.fitR, height: 10.fitR)) + } + } + func show(animate:Bool = true) -> Void { +// app.window?.addSubview(self) + + if(animate){ + self.contentView.transform = CGAffineTransform.init(translationX: 0, y: self.contentH) + UIView.animate(withDuration: 0.2) { + self.contentView.transform = CGAffineTransform.identity + self.layer.opacity = 1.0 + } + } + else{ + self.contentView.transform = CGAffineTransform.init(translationX: 0, y: self.contentH) + self.contentView.transform = CGAffineTransform.identity + UIView.animate(withDuration: 0.2) { + self.layer.opacity = 1.0 + } + } + } + + @objc func hide() -> Void { + UIView.animate(withDuration: 0.2, animations: { + self.contentView.transform = CGAffineTransform.init(translationX: 0, y: self.contentH) + self.layer.opacity = 0.0 + }) { (finished) in + self.removeFromSuperview() + } + } +} diff --git a/LingQi/LingQi/UI/Base/BaseTC.swift b/LingQi/LingQi/UI/Base/BaseTC.swift new file mode 100644 index 0000000..2fbc825 --- /dev/null +++ b/LingQi/LingQi/UI/Base/BaseTC.swift @@ -0,0 +1,42 @@ +// +// BaseTC.swift +// Magpie +// +// Created by incar on 2024/1/2. +// + +import UIKit + +class BaseTC:UITabBarController{ + let homeVC = HomeVC() + let mine = MineVC() + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + view.backgroundColor = .color(.bgColor) + setupUI() + } + + + func setupUI(){ + self.tabBar.backgroundColor = .rgb(0x212935) + let item0 = UITabBarItem(title: "home", image: UIImage(named: "tab_0_normal")?.withRenderingMode(.alwaysOriginal), selectedImage: UIImage(named: "tab_0_selected")?.withRenderingMode(.alwaysOriginal)) + let nc0 = BaseNC(rootViewController: homeVC) + nc0.tabBarItem = item0 + + let item1 = UITabBarItem(title: "set", image: UIImage(named: "tab_1_normal")?.withRenderingMode(.alwaysOriginal), selectedImage: UIImage(named: "tab_1_selected")?.withRenderingMode(.alwaysOriginal)) + let nc1 = BaseNC(rootViewController: mine) + nc1.tabBarItem = item1 + self.viewControllers = [nc0,nc1] + + let appearance = UITabBarAppearance() + appearance.configureWithDefaultBackground() + appearance.stackedLayoutAppearance.normal.titleTextAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white.withAlphaComponent(0.5)] + appearance.stackedLayoutAppearance.selected.titleTextAttributes = [NSAttributedString.Key.foregroundColor:UIColor.color(.theme)] + self.tabBar.standardAppearance = appearance + + self.selectedIndex = 1 + } +} diff --git a/LingQi/LingQi/UI/Base/BaseTableViewCell.swift b/LingQi/LingQi/UI/Base/BaseTableViewCell.swift new file mode 100644 index 0000000..a0ebf68 --- /dev/null +++ b/LingQi/LingQi/UI/Base/BaseTableViewCell.swift @@ -0,0 +1,56 @@ +// +// BaseTableViewCell.swift +// zgjd +// +// Created by Kylin on 11/24/20. +// + +import UIKit +extension BaseTableViewCell: YCTableViewCellInitProtocol { } +class BaseTableViewCell: UITableViewCell { + + // 记录当前位置 + var indexPath : NSIndexPath? = nil + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + selectionStyle = .none + contentView.backgroundColor = .clear + } + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style:style, reuseIdentifier: reuseIdentifier) + selectionStyle = .none + contentView.backgroundColor = .clear + + setupViews() + setupLayout() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) +// fatalError("init(coder:) has not been implemented") + } + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + + // Configure the view for the selected state + } + + // 通过类名获取 + static func reuseID()-> String{ + return String(describing: Self.classForCoder()) + } + + // 从xib 中获取 + static func cellForNib()-> UINib{ + return UINib.init(nibName: String(describing: Self.classForCoder()), bundle: nil) + } + func setupViews(){ + + } + func setupLayout(){ + + } +} diff --git a/LingQi/LingQi/UI/Base/BaseTableViewSetionHeader.swift b/LingQi/LingQi/UI/Base/BaseTableViewSetionHeader.swift new file mode 100644 index 0000000..b21724e --- /dev/null +++ b/LingQi/LingQi/UI/Base/BaseTableViewSetionHeader.swift @@ -0,0 +1,29 @@ +// +// BaseTableViewSetionHeader.swift +// LingQi +// +// Created by liangshi on 2025/7/31. +// + + +import UIKit + +extension BaseTableViewSetionHeader: YCTableHeaderFooterInitProtocol { } +class BaseTableViewSetionHeader: UITableViewHeaderFooterView { + override init(reuseIdentifier: String?) { + super.init(reuseIdentifier: reuseIdentifier) + + setupViews() + setupLayout() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + func setupViews(){ + + } + func setupLayout(){ + + } +} diff --git a/LingQi/LingQi/UI/Base/BaseTextField.swift b/LingQi/LingQi/UI/Base/BaseTextField.swift new file mode 100644 index 0000000..4565bc2 --- /dev/null +++ b/LingQi/LingQi/UI/Base/BaseTextField.swift @@ -0,0 +1,73 @@ +// +// YLTextField.swift +// Magpie +// +// Created by incar on 2024/1/10. +// + +import UIKit + +open class BaseTextField: UITextField { + + public var maxLenth: Int + public init(maxLenth: Int = 1000) { + self.maxLenth = maxLenth + super.init(frame: .zero) + + borderStyle = .none + textAlignment = .left + autocorrectionType = .no + autocapitalizationType = .none + enablesReturnKeyAutomatically = true + tintColor = .color(.theme) + addTarget(self, action: #selector(p_textFieldDidChange(_:)), for: .editingChanged) + } + + + // MARK: === 输入长度限制 + @objc func p_textFieldDidChange(_ textFiled: UITextField) { + guard maxLenth > 0 else { return } + if textFiled.text!.count > maxLenth { + textFiled.text = NSString(string: textFiled.text!).substring(to: maxLenth) + } + } + + required public init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + /* 小数点后两位 判断 + func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { + // 只允许输入 0-9和. + if !string.el.isValidMoneyNum, + string != "" { return false } + // 如果输入的是“.” 判断之前已经有"."或者字符串为空 + if string == "." { + if textField.text?.range(of: ".") != nil || + textField.text == "" { + return false + } + } + if string != "" { + // 防止出现 0543 + if textField.text == "0", + string != "." { return false } + // 防止出现 0.00 + else if textField.text == "0.0", + string == "0" { + return false + } + } + guard let _ = textField.text?.range(of: ".") else { + return true } + let nsStr = NSString.init(string: textField.text!) + let location = nsStr.range(of: ".").location + if nsStr.length > location + 2, + string != "" { + return false + } + return true + } + */ +} + diff --git a/LingQi/LingQi/UI/Base/BaseVC.swift b/LingQi/LingQi/UI/Base/BaseVC.swift new file mode 100644 index 0000000..cae232c --- /dev/null +++ b/LingQi/LingQi/UI/Base/BaseVC.swift @@ -0,0 +1,120 @@ +// +// BaseVC.swift +// Magpie +// +// Created by incar on 2024/1/2. +// + +import UIKit +import Kingfisher + +open class BaseVC:UIViewController, UIGestureRecognizerDelegate { + + + let navBar = BaseNavigationBar() + + public init() { + super.init(nibName: nil, bundle: nil) + } + + @available(*, unavailable, message: "Loading this view controller from a nib is unsupported") + public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + } + + @available(*, unavailable, message: "Loading this view controller from a nib is unsupported") + public required init(coder aDecoder: NSCoder) { + fatalError("Loading this view controller from a nib is unsupported") + } + + override open func viewDidLoad() { + super.viewDidLoad() + navBar.delegate = self + view.backgroundColor = .rgb(0x11131E) + view.addSubview(navBar) +// self.automaticallyAdjustsScrollViewInsets = false + navigationController?.navigationBar.isHidden = true + hidesBottomBarWhenPushed = true + + setupViews() + setupLayout() + } + open override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + self.navigationController?.navigationBar.isHidden = true + } + + + deinit { + k_logViewControllerDeinit(self) + } + + override open func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + KingfisherManager.shared.cache.clearMemoryCache() + } + + override open var preferredStatusBarStyle: UIStatusBarStyle { + if #available(iOS 13.0, *) { + return .darkContent + } else { + return .default + } + } + + func setupViews(){ + + } + func setupLayout(){ + + } +} + +extension BaseVC: BaseNavigationBarDelegate { + @objc public func navleftViewTapped() { + if let _ = self.presentingViewController { + self.dismiss(animated: true, completion: nil) + } else if let nav = self.navigationController { + nav.popViewController(animated: true) + } + } + + @objc public func navRightViewTapped() { + + } + + @discardableResult + public func setNavLeft(icon: UIImage?) -> UIButton { + navBar.leftView.setImage(icon, for: .normal) + return navBar.leftView + } + + @discardableResult + public func setNavLeft(title: String, + titleColor: UIColor = .black, + titleFont: UIFont = .regular(14, isFit: false)) -> UIButton { + navBar.leftView.setImage(nil, for: .normal) + navBar.leftView.setTitleColor(titleColor, for: .normal) + navBar.leftView.titleLabel?.font = titleFont + navBar.leftView.setTitle(title, for: .normal) + return navBar.leftView + } + + @discardableResult + public func setNavRight(icon: UIImage?) -> UIButton { + navBar.rightView.setImage(icon, for: .normal) + return navBar.rightView + } + + @discardableResult + public func setNavRight(title: String, + norColor: UIColor = .black, + disColor: UIColor = .gray, + titleFont: UIFont = .regular(14, isFit: false)) -> UIButton { + navBar.rightView.setTitleColor(norColor, for: .normal) + navBar.rightView.setTitleColor(disColor, for: .disabled) + navBar.rightView.titleLabel?.font = titleFont + navBar.rightView.setTitle(title, for: .normal) + return navBar.rightView + } +} diff --git a/LingQi/LingQi/UI/Base/BaseVM.swift b/LingQi/LingQi/UI/Base/BaseVM.swift new file mode 100644 index 0000000..18b49d2 --- /dev/null +++ b/LingQi/LingQi/UI/Base/BaseVM.swift @@ -0,0 +1,14 @@ +// +// BaseVM.swift +// LingQi +// +// Created by liangshi on 2025/7/30. +// + +class BaseVM { + + deinit { + k_logViewModelDeinit(self) + } + +} diff --git a/LingQi/LingQi/UI/Base/BaseView.swift b/LingQi/LingQi/UI/Base/BaseView.swift new file mode 100644 index 0000000..925c378 --- /dev/null +++ b/LingQi/LingQi/UI/Base/BaseView.swift @@ -0,0 +1,28 @@ +// +// BaseView.swift +// LingQi +// +// Created by liangshi on 2025/7/30. +// + +import UIKit + +class BaseView: UIView { + + override init(frame: CGRect) { + super.init(frame: frame) + setupViews() + setupLayout() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func setupViews(){ + + } + func setupLayout(){ + + } +} diff --git a/LingQi/LingQi/UI/Base/ReusabelViewsInitProtocol.swift b/LingQi/LingQi/UI/Base/ReusabelViewsInitProtocol.swift new file mode 100644 index 0000000..9c458c5 --- /dev/null +++ b/LingQi/LingQi/UI/Base/ReusabelViewsInitProtocol.swift @@ -0,0 +1,97 @@ +// +// ReusabelViewsInitProtocol.swift +// zgjd +// +// Created by apple on 2020/11/10. +// + + +import UIKit + +/// UICollectionCell 快速初始化协议 +public protocol YCCollectionCellInitProtocol where Self: UICollectionViewCell { + static var reuseID: String { get } + static func cell(withCollectionView collectionView: UICollectionView, indexPath: IndexPath) -> Self +} +extension YCCollectionCellInitProtocol { + public static var reuseID: String { + return NSStringFromClass(Self.self).components(separatedBy: ".").last! + } + + public static func cell(withCollectionView collectionView: UICollectionView, indexPath: IndexPath) -> Self { + guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseID, for: indexPath) as? Self else { + return Self(frame: .zero) + }; return cell + } +} + +/// UITableViewCell 快速初始化协议 +public protocol YCTableViewCellInitProtocol where Self: UITableViewCell { + static var reuseID: String { get } + static func cell(withTableView tableView: UITableView, indexPath: IndexPath) -> Self +} + +extension YCTableViewCellInitProtocol { + public static var reuseID: String { + return NSStringFromClass(Self.self).components(separatedBy: ".").last! + } + + public static func cell(withTableView tableView: UITableView, indexPath: IndexPath) -> Self { + guard let cell = tableView.dequeueReusableCell(withIdentifier: reuseID, for: indexPath) as? Self else { + return Self(style: .default, reuseIdentifier: reuseID) + }; return cell + } +} + +/// UITableViewHeaderFooterView 快速初始化协议 +public protocol YCTableHeaderFooterInitProtocol where Self: UITableViewHeaderFooterView { + static var reuseID: String { get } + static func header(withTableView tableView: UITableView) -> Self + static func footer(withTableView tableView: UITableView) -> Self +} + +extension YCTableHeaderFooterInitProtocol { + public static var reuseID: String { + return NSStringFromClass(Self.self).components(separatedBy: ".").last! + } + + public static func header(withTableView tableView: UITableView) -> Self { + guard let v = tableView.dequeueReusableHeaderFooterView(withIdentifier: reuseID) as? Self else { + return Self(reuseIdentifier: reuseID) + }; return v + } + + public static func footer(withTableView tableView: UITableView) -> Self { + guard let v = tableView.dequeueReusableHeaderFooterView(withIdentifier: reuseID) as? Self else { + return Self(reuseIdentifier: reuseID) + }; return v + } +} + + +/// YCColletionHeaderFooterInitProtocol 快速初始化协议 +public protocol YCColletionHeaderFooterInitProtocol where Self: UICollectionReusableView { + static var reuseID: String { get } + static func header(with collectionView: UICollectionView,indexPath: IndexPath) -> Self + static func footer(with collectionView: UICollectionView,indexPath: IndexPath) -> Self +} + +extension YCColletionHeaderFooterInitProtocol { + public static var reuseID: String { + return NSStringFromClass(Self.self).components(separatedBy: ".").last! + } + + public static func header(with collectionView: UICollectionView,indexPath: IndexPath) -> Self { + guard let v = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: reuseID, for: indexPath) as? Self else{ + return Self() + } + return v + } + + public static func footer(with collectionView: UICollectionView,indexPath: IndexPath) -> Self { + guard let v = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: reuseID, for: indexPath) as? Self else{ + return Self() + } + return v + } +} diff --git a/LingQi/LingQi/UI/Base/WebView/BaseWebView.swift b/LingQi/LingQi/UI/Base/WebView/BaseWebView.swift new file mode 100644 index 0000000..1df41eb --- /dev/null +++ b/LingQi/LingQi/UI/Base/WebView/BaseWebView.swift @@ -0,0 +1,32 @@ +// +// BaseWebView.swift +// zgjd +// +// Created by apple on 2020/11/14. +// + +import UIKit +import WebKit + +open class BaseWebView: WKWebView { + + override public init(frame: CGRect, configuration: WKWebViewConfiguration) { + super.init(frame: frame, configuration: configuration) +// self.evaluateJavaScript("navigator.userAgent") { [weak self](result, error) in +// guard error == nil, +// var userAgent = result as? String else { return } +// if !userAgent.contains("/yc-ios") { +// userAgent.append("/yc-ios") +// } +// let dict = ["UserAgent": userAgent] +// UserDefaults.standard.register(defaults: dict) +// UserDefaults.standard.synchronize() +// self?.customUserAgent = userAgent +// } + } + + @available(*, unavailable, message: "Loading this view from a nib is unsupported") + public required init?(coder aDecoder: NSCoder) { + fatalError("Loading this view from a nib is unsupported") + } +} diff --git a/LingQi/LingQi/UI/Base/WebView/BaseWebViewController.swift b/LingQi/LingQi/UI/Base/WebView/BaseWebViewController.swift new file mode 100644 index 0000000..1670a5b --- /dev/null +++ b/LingQi/LingQi/UI/Base/WebView/BaseWebViewController.swift @@ -0,0 +1,220 @@ +//// +//// BaseWebViewController.swift +//// zgjd +//// +//// Created by apple on 2020/11/14. +//// +// +//import UIKit +//import WebKit +// +//struct BaseWebViewParams { +// var urlStr: String +// var request: URLRequest? +// var title: String +// init(urlStr: String, title: String = "") { +// self.urlStr = urlStr +// self.title = title +// self.request = nil +// } +// init(request: URLRequest, title: String = "") { +// self.request = request +// self.urlStr = "" +// self.title = title +// } +//} +// +//final class BaseWebViewController: BaseVC { +// let webView = BaseWebView() +// private let progressView = UIProgressView(progressViewStyle: .default) +// private var initData: BaseWebViewParams +// init(initData: BaseWebViewParams) { +// +// self.initData = initData +// super.init() +// } +// +// +// deinit { +// webView.removeObserver(self, forKeyPath: "canGoBack") +// webView.removeObserver(self, forKeyPath: "estimatedProgress") +// webView.removeObserver(self, forKeyPath: "title") +// } +// override func viewDidLoad() { +// super.viewDidLoad() +// setupLayout() +// setupStyle() +// } +// +// override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { +// if keyPath == "canGoBack" { +// if webView.canGoBack { +// self.navigationController?.interactivePopGestureRecognizer?.isEnabled = true +// } else { +// self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false +// } +// } else if keyPath == "estimatedProgress" { +// progressView.alpha = CGFloat(1.0 - webView.estimatedProgress) + 0.2 +// let progerss = max(Float(webView.estimatedProgress), 0.1) +// progressView.setProgress(progerss, animated: true) +// if webView.estimatedProgress >= 1.0 { +// kDelay(0.3) { +// self.progressView.alpha = 0.0 +// self.progressView.setProgress(0.0, animated: false) +// } +// } +// }else if keyPath == "title" { +// if initData.title.isEmpty { +// navBar.title = webView.title ?? " " +// } +// +// } else { +// super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) +// } +// } +//} +// +//// MARK: - ********* webview delegate +//extension BaseWebViewController: WKNavigationDelegate { +// +// func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { +// webView.evaluateJavaScript( +// "document.getElementsByTagName('body')[0].style.background='#FAFAFA'", +// completionHandler: nil) +// } +// func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { +// k_log("==== error: \(error)") +// } +// func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) { +// k_log("==== error: \(error)") +// } +// func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { +// if (navigationAction.targetFrame == nil) { +// webView.load(navigationAction.request) +// } +// guard let policy = WKNavigationActionPolicy(rawValue: WKNavigationActionPolicy.allow.rawValue + 2) +// else { decisionHandler(.allow); return } +// decisionHandler(policy) +// } +//} +// +//// MARK: - ********* UIResponse Funcs +//extension BaseWebViewController { +// override func navleftViewTapped() { +// if webView.canGoBack { +// webView.goBack() +// } +// else{ +// if let _ = self.presentingViewController { +// self.dismiss(animated: true, completion: nil) +// } else if let nav = self.navigationController { +// nav.popViewController(animated: true) +// } +// } +// +// } +// override func navRightViewTapped() { +// if let _ = self.presentingViewController { +// self.dismiss(animated: true, completion: nil) +// } else if let nav = self.navigationController { +// nav.popViewController(animated: true) +// } +// } +//} +// +//// MARK: - UI Setup +//private extension BaseWebViewController { +// +// func setupLayout() { +// view.addSubview(webView) +// webView.addSubview(progressView) +// +// webView.snp.makeConstraints { (m) in +// m.top.equalToSuperview().inset(kNavBtm) +// m.bottom.equalToSuperview() +// m.leading.trailing.equalToSuperview() +// } +// progressView.snp.makeConstraints { (m) in +// m.top.leading.trailing.equalToSuperview() +// m.height.equalTo(2) +// } +// } +// +// func setupStyle() { +// +// navBar.title = initData.title +// setNavRight(title: "关闭",norColor: .color(.secondary)) +// +// view.backgroundColor = .color(.viewBg) +// +// webView.navigationDelegate = self +// webView.uiDelegate = self +// webView.backgroundColor = .color(.viewBg) +// +// webView.addObserver(self, forKeyPath: "estimatedProgress", options: .new, context: nil) +// webView.addObserver(self, forKeyPath: "canGoBack", options: .new, context: nil) +// webView.addObserver(self, forKeyPath: "title", options: .new, context: nil) +// webView.evaluateJavaScript("document.getElementsByTagName('body')[0].style.background='#FAFAFA'", completionHandler: nil) +// +// /// 加载URL +// if let requestUrl = initData.urlStr.yc.asUrl { +// let request = URLRequest(url: requestUrl) +// webView.load(request) +// } +// else if let request = initData.request { +// webView.load(request) +// } +// else { return } +// +// /// 进度条 +// progressView.trackTintColor = .clear +// progressView.progressTintColor = .color(.theme) +// progressView.isHidden = false +// progressView.setProgress(0.05, animated: true) +// +// } +//} +// +//// MARK: - WKUIDelegate 不实现该代理方法 网页内调用弹窗时会抛出异常,导致程序崩溃 +//extension BaseWebViewController: WKUIDelegate { +// // 获取js 里面的提示 +// func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) { +// if self.navigationController?.visibleViewController != self { +// completionHandler() +// return +// } +// let alert = UIAlertController(title: "提示", message: message, preferredStyle: .alert) +// alert.addAction(UIAlertAction(title: "确定", style: .default, handler: { (_) -> Void in +// completionHandler() +// })) +// alert.addAction(UIAlertAction(title: "取消", style: .cancel, handler: { (_) -> Void in +// completionHandler() +// })) +// self.present(alert, animated: true, completion: nil) +// } +// +// // js 信息的交流 +// func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) { +// let alert = UIAlertController(title: "提示", message: message, preferredStyle: .alert) +// alert.addAction(UIAlertAction(title: "确定", style: .default, handler: { (_) -> Void in +// completionHandler(true) +// })) +// alert.addAction(UIAlertAction(title: "取消", style: .cancel, handler: { (_) -> Void in +// completionHandler(false) +// })) +// self.present(alert, animated: true, completion: nil) +// } +// +// // 交互。可输入的文本。 +// func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) { +// let alert = UIAlertController(title: prompt, message: defaultText, preferredStyle: .alert) +// alert.addTextField { (textField: UITextField) -> Void in +// textField.textColor = UIColor.red +// } +// alert.addAction(UIAlertAction(title: "确定", style: .default, handler: { (_) -> Void in +// completionHandler(alert.textFields![0].text!) +// })) +// self.present(alert, animated: true, completion: nil) +// } +//} +// diff --git a/LingQi/LingQi/UI/Base/YLprogressHUD.swift b/LingQi/LingQi/UI/Base/YLprogressHUD.swift new file mode 100644 index 0000000..6655914 --- /dev/null +++ b/LingQi/LingQi/UI/Base/YLprogressHUD.swift @@ -0,0 +1,80 @@ +// +// YLPro.swift +// LingQi +// +// Created by liangshi on 2025/7/30. +// + +import UIKit +import SVProgressHUD + +class YLprogressHUD { + /// 显示自动消失的 HUD + static func showAutoHiden(_ text: String) { + SVProgressHUD.setMinimumDismissTimeInterval(1.5) + SVProgressHUD.setDefaultStyle(.dark) + SVProgressHUD.setDefaultMaskType(.clear) + SVProgressHUD.setContainerView(UIApplication.shared.keyWindow) + SVProgressHUD.show(UIImage(), status: text) + } + + /// 显示自动消失的 HUD,并在消失后执行回调 + static func showAutoHiden(text: String, finished: @escaping () -> Void) { + showAutoHiden( text) + DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { + finished() + } + } + static func showSuccess(finished: @escaping () -> Void) { + showAutoHiden( "请求成功!") + DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { + finished() + } + } + + /// 显示"加载中..." HUD + static func showLoading() { + showWithStatus(status: "加载中...") + } + + /// 显示"上传中..." HUD + static func showUpLoading() { + showWithStatus(status: "上传中...") + } + + /// 隐藏 HUD + static func hidden() { + SVProgressHUD.dismiss() + } + + /// 获取当前顶层视图控制器 + static func topViewController() -> UIViewController? { + guard let rootVC = UIApplication.shared.keyWindow?.rootViewController else { + return nil + } + return getTopViewController(from: rootVC) + } + + /// 递归获取顶层视图控制器 + private static func getTopViewController(from vc: UIViewController) -> UIViewController { + if let navVC = vc as? UINavigationController { + return getTopViewController(from: navVC.visibleViewController ?? navVC) + } else if let tabVC = vc as? UITabBarController { + return getTopViewController(from: tabVC.selectedViewController ?? tabVC) + } else if let presentedVC = vc.presentedViewController { + return getTopViewController(from: presentedVC) + } else { + return vc + } + } + + /// 通用方法:显示带状态的 HUD + private static func showWithStatus(status: String) { + SVProgressHUD.show(withStatus: status) + SVProgressHUD.setDefaultStyle(.dark) + SVProgressHUD.setDefaultMaskType(.clear) + if let topVC = topViewController() { + SVProgressHUD.setContainerView(topVC.view) + } + } +} diff --git a/LingQi/LingQi/UI/Device/DeviceVC.swift b/LingQi/LingQi/UI/Device/DeviceVC.swift new file mode 100644 index 0000000..77605a8 --- /dev/null +++ b/LingQi/LingQi/UI/Device/DeviceVC.swift @@ -0,0 +1,18 @@ +// +// DeviceVC.swift +// Magpie +// +// Created by incar on 2024/1/10. +// + +import Foundation +import UIKit + +class DeviceVC:BaseVC{ + + override func viewDidLoad() { + super.viewDidLoad() + self.navBar.title = "设备" + + } +} diff --git a/LingQi/LingQi/UI/Discover/DiscoverVC.swift b/LingQi/LingQi/UI/Discover/DiscoverVC.swift new file mode 100644 index 0000000..c44b461 --- /dev/null +++ b/LingQi/LingQi/UI/Discover/DiscoverVC.swift @@ -0,0 +1,18 @@ +// +// DeviceVC.swift +// Magpie +// +// Created by incar on 2024/1/10. +// + +import Foundation +import UIKit + +class DiscoverVC:BaseVC{ + + override func viewDidLoad() { + super.viewDidLoad() + self.navBar.title = "发现" + + } +} diff --git a/LingQi/LingQi/UI/Home/HomeVC.swift b/LingQi/LingQi/UI/Home/HomeVC.swift new file mode 100644 index 0000000..af098e7 --- /dev/null +++ b/LingQi/LingQi/UI/Home/HomeVC.swift @@ -0,0 +1,46 @@ +// +// HomeVC.swift +// Magpie +// +// Created by incar on 2024/1/3. +// + +import UIKit + +class HomeVC:BaseVC{ + + override func viewDidLoad() { + super.viewDidLoad() + self.navBar.title = "首页" + + self.navBar.rightView.setTitle("more", for: .normal) + } + + override func navRightViewTapped() { + let v = BasePickerView() + v.setupData(["2","3","4","5","6","7","8"]) + v.selectedIndex(4) + v.show(animate: true) + return + } + + @objc func addDeviceAction(){ + let vc = ScanDeviceVC() + self.navigationController?.pushViewController(vc, animated: true) + } + @objc func saveAction(){ +// LogManager.instance.add("保存") +// LogManager.instance.saveToFile() + +// SVProgressHUD.showLoading() +// HttpClient.instance.request(CommomApi.login(userName: "")) { (model:ResponseBaseModel, res) in +// if model.isSuccess{ +//// SVProgressHUD.show(withStatus: "请求成功") +// } +// else{ +//// SVProgressHUD.show(withStatus: "请求失败") +// } +// } + } +} + diff --git a/LingQi/LingQi/UI/Mine/Login/AgreeView.swift b/LingQi/LingQi/UI/Mine/Login/AgreeView.swift new file mode 100644 index 0000000..ca5ccbb --- /dev/null +++ b/LingQi/LingQi/UI/Mine/Login/AgreeView.swift @@ -0,0 +1,66 @@ +// +// AgreeView.swift +// LingQi +// +// Created by liangshi on 2025/7/30. +// + +import UIKit +class AgreeView: BaseView { + let agreeBtn = UIButton() + let agreeTitle = UILabel() + let agreeValue = UILabel() + override func setupViews() { + agreeBtn.do { (v) in + v.contentMode = .center + v.setImage(UIImage(named: "select_normal"), for: .normal) + v.setImage(UIImage(named: "select_selected"), for: .selected) + v.addTarget(self, action: #selector(agreeBtnAction), for: .touchUpInside) + } + agreeTitle.do { (v) in + v.textColor = .white.withAlphaComponent(0.8) + v.font = .medium(14) + v.textAlignment = .left + v.text = "登录即代表同意" + } + agreeValue.do { (v) in + v.textColor = .color(.theme) + v.font = .medium(14) + v.textAlignment = .left + v.text = " 《用户协议》" + v.add(target: self, action: #selector(agreementButtonAction)) + } + addSubviews([agreeBtn,agreeTitle,agreeValue]) + } + override func setupLayout() { + agreeBtn.snp.makeConstraints { (m) in + m.left.top.equalToSuperview() + m.height.equalTo(30) + m.width.equalTo(30) + } + agreeTitle.snp.makeConstraints { (m) in + m.left.equalTo(agreeBtn.snp.right) + m.height.equalToSuperview() + m.centerY.equalTo(agreeBtn) + } + agreeValue.snp.makeConstraints { (m) in + m.left.equalTo(agreeTitle.snp.right) + m.centerY.equalTo(agreeBtn) + m.right.equalToSuperview() + } + } + @objc func agreeBtnAction(){ + agreeBtn.isSelected = !agreeBtn.isSelected + } + @objc func agreementButtonAction(){ + + } +} + +extension UILabel{ + func add(target: Any?, action: Selector?){ + let tap = UITapGestureRecognizer(target: target, action: action) + self.addGestureRecognizer(tap) + self.isUserInteractionEnabled = true + } +} diff --git a/LingQi/LingQi/UI/Mine/Login/CodeView.swift b/LingQi/LingQi/UI/Mine/Login/CodeView.swift new file mode 100644 index 0000000..66e4dbe --- /dev/null +++ b/LingQi/LingQi/UI/Mine/Login/CodeView.swift @@ -0,0 +1,68 @@ +// +// CodeView.swift +// LingQi +// +// Created by liangshi on 2025/7/30. +// + +import UIKit +class CodeView: BaseView { + let label = UILabel() + let inputBgView = UIView() + let textField = UITextField() + let codeButton = YLTimerButton() + override func setupViews() { + backgroundColor = .clear + + label.do { v in + v.text = "验证码" + v.font = .medium(12) + v.textColor = .white.withAlphaComponent(0.8) + } + textField.do { v in + v.textColor = .white + v.keyboardType = .phonePad + } + codeButton.do { (v) in + v.maxCount = 20 + v.label.textColor = .color(.theme) + v.backgroundColor = UIColor.white.withAlphaComponent(0.04) + v.layer.cornerRadius = 8 + v.layer.masksToBounds = true + } + + inputBgView.backgroundColor = UIColor.white.withAlphaComponent(0.04) + inputBgView.layer.borderColor = UIColor.white.withAlphaComponent(0.1).cgColor + inputBgView.layer.borderWidth = 0.5 + inputBgView.layer.cornerRadius = 12 + inputBgView.layer.masksToBounds = true + + addSubviews([label,inputBgView]) + inputBgView.addSubviews([textField,codeButton]) + } + override func setupLayout() { + label.snp.makeConstraints { make in + make.left.right.equalToSuperview().inset(15) + make.top.equalToSuperview() + make.height.equalTo(30) + } + inputBgView.snp.makeConstraints { make in + make.left.right.equalToSuperview() + make.top.equalToSuperview().inset(30) + make.height.equalTo(52) + make.bottom.equalToSuperview() + } + textField.snp.makeConstraints { make in + make.left.equalToSuperview().inset(15) + make.right.equalToSuperview().inset(120) + make.top.bottom.equalToSuperview() + } + codeButton.snp.makeConstraints { (m) in + m.centerY.equalTo(textField) + m.right.equalToSuperview().inset(15) + m.width.equalTo(100) + m.height.equalTo(40) + } + } + +} diff --git a/LingQi/LingQi/UI/Mine/Login/LoginVC.swift b/LingQi/LingQi/UI/Mine/Login/LoginVC.swift new file mode 100644 index 0000000..59cc6d1 --- /dev/null +++ b/LingQi/LingQi/UI/Mine/Login/LoginVC.swift @@ -0,0 +1,105 @@ +// +// LoginVC.swift +// LingQi +// +// Created by liangshi on 2025/7/30. +// + +import UIKit + +class LoginVC:BaseVC{ + let bgView = UIImageView() + let logoView = UIImageView() + let phoneView = PhoneView() + let codeView = CodeView() + let btn = CustomButton() + let agreeView = AgreeView() + + override func viewDidLoad() { + super.viewDidLoad() + } + override func setupViews(){ + self.navBar.title = "账号登录" + view.backgroundColor = .rgb(0x11131E) + bgView.image = UIImage(named: "login_cover") + logoView.image = UIImage(named: "login_logo") + + phoneView.do { v in + v.textField.text = "13480939445" + } + codeView.do { v in + v.codeButton.addTarget(self, action: #selector(codeButtonAction), for: .touchUpInside) + } + + btn.set(title: "登录", target: self, action: #selector(loginAction)) + + view.addSubviews([bgView,logoView,phoneView,codeView,btn,agreeView]) + navBar.backgroundColor = .clear + view.bringSubviewToFront(navBar) + } + override func setupLayout(){ + bgView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + logoView.snp.makeConstraints { make in + make.width.equalTo(203) + make.height.equalTo(86) + make.top.equalTo(kNavBtm + 40) + make.centerX.equalToSuperview() + } + phoneView.snp.makeConstraints { make in + make.top.equalTo(logoView.snp.bottom).offset(60) + make.left.right.equalToSuperview().inset(15) + } + codeView.snp.makeConstraints { make in + make.top.equalTo(phoneView.snp.bottom).offset(10) + make.left.right.equalToSuperview().inset(15) + } + btn.snp.makeConstraints { make in + make.top.equalTo(codeView.snp.bottom).offset(30) + make.left.right.equalToSuperview().inset(15) + make.height.equalTo(52) + } + agreeView.snp.makeConstraints { make in + make.bottom.equalToSuperview().inset(62) + make.centerX.equalToSuperview() + make.height.equalTo(30) + } + } + +} + +extension LoginVC{ + @objc func codeButtonAction(){ + guard let text = phoneView.textField.text else{ + YLprogressHUD.showAutoHiden("请输入正确的手机号码") + return + } + YLprogressHUD.showLoading() + LoginVM.sendCode(phone: text) { [weak self] (model) in + if model.isSuccess{ + self?.codeView.codeButton.start() + } + YLprogressHUD.showAutoHiden(model.msg) + } + } + @objc func loginAction(){ + guard let pohne = phoneView.textField.text else{ + YLprogressHUD.showAutoHiden("请输入正确的手机号码") + return + } + guard let code = codeView.textField.text else{ + YLprogressHUD.showAutoHiden("请输入正确的验证码") + return + } + YLprogressHUD.showLoading() + LoginVM.login(phone: pohne, code: code) {[weak self] result in + if result.isSuccess{ + YLprogressHUD.showSuccess { + self?.view.window?.rootViewController = BaseTC() + } + } + YLprogressHUD.showAutoHiden(result.msg) + } + } +} diff --git a/LingQi/LingQi/UI/Mine/Login/LoginVM.swift b/LingQi/LingQi/UI/Mine/Login/LoginVM.swift new file mode 100644 index 0000000..7f85862 --- /dev/null +++ b/LingQi/LingQi/UI/Mine/Login/LoginVM.swift @@ -0,0 +1,27 @@ +// +// LoginVM.swift +// LingQi +// +// Created by liangshi on 2025/7/30. +// + +class LoginModel:ResponseBaseModel { + var data:String = "" +} + + +class LoginVM:BaseVM{ + static public func sendCode(phone:String, completion:@escaping (_ result:ResponseBaseModel) ->Void) { + HttpClient.instance.request(CommomApi.sms(phone: phone)) { (model:ResponseBaseModel, res) in + completion(model) + } + } + static public func login(phone:String,code:String, completion:@escaping (_ result:LoginModel) ->Void) { + HttpClient.instance.request(CommomApi.login(phone: phone,code: code)) { (model:LoginModel, res) in + if model.isSuccess{ + UserModel.shared.token = model.data + } + completion(model) + } + } +} diff --git a/LingQi/LingQi/UI/Mine/Login/PhoneView.swift b/LingQi/LingQi/UI/Mine/Login/PhoneView.swift new file mode 100644 index 0000000..42525b6 --- /dev/null +++ b/LingQi/LingQi/UI/Mine/Login/PhoneView.swift @@ -0,0 +1,51 @@ +// +// Untitled.swift +// LingQi +// +// Created by liangshi on 2025/7/30. +// +import UIKit +class PhoneView: BaseView { + let label = UILabel() + let inputBgView = UIView() + let textField = UITextField() + override func setupViews() { + backgroundColor = .clear + + label.do { v in + v.text = "手机号" + v.font = .medium(12) + v.textColor = .white.withAlphaComponent(0.8) + } + textField.do { v in + v.textColor = .white + v.keyboardType = .phonePad + } + + inputBgView.backgroundColor = UIColor.white.withAlphaComponent(0.04) + inputBgView.layer.borderColor = UIColor.white.withAlphaComponent(0.1).cgColor + inputBgView.layer.borderWidth = 0.5 + inputBgView.layer.cornerRadius = 12 + inputBgView.layer.masksToBounds = true + + addSubviews([label,inputBgView]) + inputBgView.addSubview(textField) + } + override func setupLayout() { + label.snp.makeConstraints { make in + make.left.right.equalToSuperview().inset(15) + make.top.equalToSuperview() + make.height.equalTo(30) + } + inputBgView.snp.makeConstraints { make in + make.left.right.equalToSuperview() + make.top.equalToSuperview().inset(30) + make.height.equalTo(52) + make.bottom.equalToSuperview() + } + textField.snp.makeConstraints { make in + make.left.right.equalToSuperview().inset(15) + make.top.bottom.equalToSuperview() + } + } +} diff --git a/LingQi/LingQi/UI/Mine/Login/UserModel.swift b/LingQi/LingQi/UI/Mine/Login/UserModel.swift new file mode 100644 index 0000000..ac30160 --- /dev/null +++ b/LingQi/LingQi/UI/Mine/Login/UserModel.swift @@ -0,0 +1,18 @@ +// +// UserModel.swift +// LingQi +// +// Created by liangshi on 2025/7/30. +// + + + + + +class UserModel { + static let shared = UserModel() + var token:String? + var isLogin:Bool{ + return token != nil + } +} diff --git a/LingQi/LingQi/UI/Mine/Root/MineCell.swift b/LingQi/LingQi/UI/Mine/Root/MineCell.swift new file mode 100644 index 0000000..d39f082 --- /dev/null +++ b/LingQi/LingQi/UI/Mine/Root/MineCell.swift @@ -0,0 +1,109 @@ +// +// MineCell.swift +// LingQi +// +// Created by liangshi on 2025/7/30. +// + +import UIKit + +public enum MineCellType: Int { + case deviceList + case service + case product + + var title:String{ + switch self { + case .deviceList: + return "设备列表" + case .service: + return "配额服务" + case .product: + return "产品说明" + + } + } + var icon:UIImage?{ + switch self { + case .deviceList: + return UIImage(named: "mine_cell_device") + case .service: + return UIImage(named: "mine_cell_service") + case .product: + return UIImage(named: "mine_cell_product") + } + } +} + + +class MineCell: BaseTableViewCell { + let icon = UIImageView() + let titleLabel = UILabel() + let nextIcon = UIImageView() + let line = UIView() + + var type:MineCellType = .deviceList{ + didSet{ + icon.image = type.icon + titleLabel.text = type.title +// if type == .order { +// bgView.yc.setCorners(withRoundedRect: CGRect(x: 0, y: 0, width: kScreenWid - 24.fitR, height: 48.fitR), roundingCorners: [.topLeft,.topRight], cornerRadii: CGSize(width: 4.fitR, height: 4.fitR)) +// } +// else if type == .set { +// bgView.yc.setCorners(withRoundedRect: CGRect(x: 0, y: 0, width: kScreenWid - 24.fitR, height: 48.fitR), roundingCorners: [.bottomLeft,.bottomRight], cornerRadii: CGSize(width: 4.fitR, height: 4.fitR)) +// } +// else{ +// bgView.layer.cornerRadius = 0 +// } + } + } + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + override func setupViews() { + contentView.addSubviews([icon,titleLabel,nextIcon,line]) + backgroundColor = .clear + contentView.backgroundColor = .clear + selectionStyle = .none + line.do { (v) in + v.backgroundColor = .color(.separateLine) + } + titleLabel.do { (v) in + v.textColor = .white + v.font = .medium(16) + v.textAlignment = .left + } + nextIcon.image = UIImage(named: "arrow_next") + } + + override func setupLayout() { + icon.snp.makeConstraints { (m) in + m.width.equalTo(24.fitR) + m.height.equalTo(24.fitR) + m.left.equalToSuperview().inset(15.fitR) + m.centerY.equalToSuperview() + } + nextIcon.snp.makeConstraints { (m) in + m.width.equalTo(20) + m.height.equalTo(20) + m.right.equalToSuperview().inset(15) + m.centerY.equalToSuperview() + } + titleLabel.snp.makeConstraints { (m) in + m.centerY.equalTo(icon) + m.left.equalTo(icon.snp.right).offset(6) + m.height.equalToSuperview() + } + line.snp.makeConstraints { (m) in + m.left.right.equalToSuperview().inset(15) + m.bottom.equalToSuperview() + m.height.equalTo(0.5) + } + } +} + diff --git a/LingQi/LingQi/UI/Mine/Root/MineHeaderView.swift b/LingQi/LingQi/UI/Mine/Root/MineHeaderView.swift new file mode 100644 index 0000000..c92d6c6 --- /dev/null +++ b/LingQi/LingQi/UI/Mine/Root/MineHeaderView.swift @@ -0,0 +1,30 @@ +// +// MineHeaderView.swift +// LingQi +// +// Created by liangshi on 2025/7/30. +// + +import UIKit +class MineHeaderView: BaseView { + let userView = MineUserInfoView() + let orderView = MineOrderView() + + + override func setupViews() { + backgroundColor = .clear + addSubviews([userView,orderView]) + } + override func setupLayout() { + userView.snp.makeConstraints { make in + make.left.right.equalToSuperview().inset(15) + make.top.equalToSuperview() + make.height.equalTo(120) + } + orderView.snp.makeConstraints { make in + make.left.right.equalToSuperview().inset(15) + make.top.equalTo(userView.snp.bottom).offset(20) + make.height.equalTo(140) + } + } +} diff --git a/LingQi/LingQi/UI/Mine/Root/MineNavBar.swift b/LingQi/LingQi/UI/Mine/Root/MineNavBar.swift new file mode 100644 index 0000000..5fc4a30 --- /dev/null +++ b/LingQi/LingQi/UI/Mine/Root/MineNavBar.swift @@ -0,0 +1,57 @@ +// +// MineNavBar.swift +// LingQi +// +// Created by liangshi on 2025/7/30. +// + +import UIKit +class MineNavBar: BaseView { + let titleLabel = UILabel() + let messageBtn = UIButton() + let setBtn = UIButton() + + override func setupViews() { + backgroundColor = .color(.bgColor) + addSubviews([titleLabel,messageBtn,setBtn]) + + titleLabel.do { v in + v.text = "我的" + v.font = .medium(18) + v.textColor = .white + } + setBtn.do { v in + v.setImage(UIImage(named: "mine_set"), for: .normal) + v.addTarget(self, action: #selector(setAction), for: .touchUpInside) + } + messageBtn.do { v in + v.setImage(UIImage(named: "mine_msg"), for: .normal) + v.addTarget(self, action: #selector(messageAction), for: .touchUpInside) + } + } + override func setupLayout() { + titleLabel.snp.makeConstraints { make in + make.left.equalToSuperview().inset(15) + make.bottom.equalToSuperview().inset(15) + } + setBtn.snp.makeConstraints { make in + make.centerY.equalTo(titleLabel) + make.right.equalToSuperview().inset(15) + make.size.equalTo(30) + } + messageBtn.snp.makeConstraints { make in + make.centerY.equalTo(titleLabel) + make.right.equalTo(setBtn.snp.left).offset(-15) + make.size.equalTo(30) + } + } + + @objc func messageAction(){ + + } + @objc func setAction(){ + let vc = UserInfoVC() + let topVC = App.shared.topVC() + topVC?.navigationController?.pushViewController(vc, animated: true) + } +} diff --git a/LingQi/LingQi/UI/Mine/Root/MineOrderView.swift b/LingQi/LingQi/UI/Mine/Root/MineOrderView.swift new file mode 100644 index 0000000..1deb58d --- /dev/null +++ b/LingQi/LingQi/UI/Mine/Root/MineOrderView.swift @@ -0,0 +1,18 @@ +// +// MineOrderView.swift +// LingQi +// +// Created by liangshi on 2025/7/30. +// + +import UIKit +class MineOrderView: BaseView { + + override func setupViews() { + backgroundColor = .white + } + override func setupLayout() { + + } + +} diff --git a/LingQi/LingQi/UI/Mine/Root/MineUserInfoView.swift b/LingQi/LingQi/UI/Mine/Root/MineUserInfoView.swift new file mode 100644 index 0000000..4bce1f7 --- /dev/null +++ b/LingQi/LingQi/UI/Mine/Root/MineUserInfoView.swift @@ -0,0 +1,19 @@ +// +// MineUserInfoView.swift +// LingQi +// +// Created by liangshi on 2025/7/30. +// + +import UIKit +class MineUserInfoView: BaseView { + + override func setupViews() { + backgroundColor = .white + + } + override func setupLayout() { + + } + +} diff --git a/LingQi/LingQi/UI/Mine/Root/MineVC.swift b/LingQi/LingQi/UI/Mine/Root/MineVC.swift new file mode 100644 index 0000000..cf3b645 --- /dev/null +++ b/LingQi/LingQi/UI/Mine/Root/MineVC.swift @@ -0,0 +1,57 @@ +// +// SetVC.swift +// Magpie +// +// Created by incar on 2024/1/3. +// + +import UIKit +class MineVC: BaseVC{ + let tableView = UITableView(frame: .zero, style: .plain) + let list:[MineCellType] = [.deviceList,.service,.product,] + + override func viewDidLoad() { + super.viewDidLoad() + // Do any additional setup after loading the view. + } + override func setupViews() { + self.navBar.title = "我的" + tableView.do { v in + v.backgroundColor = .color(.bgColor) + v.delegate = self + v.dataSource = self + v.rowHeight = 68 + v.register(MineCell.self, forCellReuseIdentifier: MineCell.reuseID) + v.tableHeaderView = MineHeaderView(frame: CGRect(x: 0, y: 0, width: kScreenWid, height: 280)) + } + view.addSubview(tableView) + + let bar = MineNavBar(frame: navBar.frame) + navBar.addSubview(bar) + } + override func setupLayout() { + tableView.snp.makeConstraints { make in + make.left.right.bottom.equalToSuperview() + make.top.equalTo(kNavBtm) + } + } +} + +extension MineVC:UITableViewDelegate,UITableViewDataSource { + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + return 60 + } + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return list.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = MineCell.cell(withTableView: tableView, indexPath: indexPath) + cell.type = list[indexPath.row] + return cell + } + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + let data = list[indexPath.row] + + } +} diff --git a/LingQi/LingQi/UI/Mine/UserInfo/UserInfoCell.swift b/LingQi/LingQi/UI/Mine/UserInfo/UserInfoCell.swift new file mode 100644 index 0000000..a8d7cdf --- /dev/null +++ b/LingQi/LingQi/UI/Mine/UserInfo/UserInfoCell.swift @@ -0,0 +1,195 @@ +// +// UserInfoCell.swift +// LingQi +// +// Created by liangshi on 2025/7/30. +// + +import UIKit + +public enum UserInfoCellType: Int { + case avatar + case nickName + case gender + case phone + case password + case deregister + + var title:String{ + switch self { + case .avatar: + return "头像" + case .nickName: + return "昵称" + case .gender: + return "性别" + case .phone: + return "手机号" + case .password: + return "密码" + case .deregister: + return "注销账号" + } + } + +} + + +class UserInfoCell: BaseTableViewCell { + let bgView = UIView() + let icon = UIImageView() + let titleLabel = UILabel() + let valueLabel = UILabel() + let nextIcon = UIImageView() + + var type:UserInfoCellType = .avatar{ + didSet{ + titleLabel.text = type.title + valueLabel.text = "1111" + } + } + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + override func setupViews() { + contentView.addSubview(bgView) + bgView.addSubviews([titleLabel,icon,valueLabel,nextIcon]) + + backgroundColor = .clear + contentView.backgroundColor = .clear + selectionStyle = .none + bgView.do { v in + v.backgroundColor = UIColor.white.withAlphaComponent(0.04) + v.layer.borderColor = UIColor.white.withAlphaComponent(0.1).cgColor + v.layer.borderWidth = 0.5 + v.layer.cornerRadius = 12 + v.layer.masksToBounds = true + } + titleLabel.do { (v) in + v.textColor = .white + v.font = .medium(16) + v.textAlignment = .left + } + valueLabel.do { (v) in + v.textColor = .white.withAlphaComponent(0.8) + v.font = .medium(14) + v.textAlignment = .right + } + nextIcon.image = UIImage(named: "arrow_next") + } + + override func setupLayout() { + bgView.snp.makeConstraints { (m) in + m.left.right.equalToSuperview().inset(15) + m.top.equalToSuperview().inset(6) + m.bottom.equalToSuperview().inset(6) + m.height.equalTo(52) + } + nextIcon.snp.makeConstraints { (m) in + m.width.equalTo(20) + m.height.equalTo(20) + m.right.equalToSuperview().inset(15) + m.centerY.equalToSuperview() + } + icon.snp.makeConstraints { (m) in + m.width.equalTo(46) + m.height.equalTo(46) + m.right.equalToSuperview().inset(40) + m.centerY.equalToSuperview() + } + titleLabel.snp.makeConstraints { (m) in + m.centerY.equalTo(icon) + m.left.equalToSuperview().inset(15) + m.height.equalToSuperview() + } + valueLabel.snp.makeConstraints { (m) in + m.centerY.equalTo(icon) + m.right.equalToSuperview().inset(40) + m.height.equalToSuperview() + } + + } +} + +class UserInfoImageCell: BaseTableViewCell { + let bgView = UIView() + let icon = UIImageView() + let titleLabel = UILabel() + let nextIcon = UIImageView() + let imgPicker = ImagePickerManager() + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + override func setupViews() { + contentView.addSubview(bgView) + bgView.addSubviews([titleLabel,icon,nextIcon]) + + backgroundColor = .clear + contentView.backgroundColor = .clear + selectionStyle = .none + bgView.do { v in + v.backgroundColor = UIColor.white.withAlphaComponent(0.04) + v.layer.borderColor = UIColor.white.withAlphaComponent(0.1).cgColor + v.layer.borderWidth = 0.5 + v.layer.cornerRadius = 12 + v.layer.masksToBounds = true + v.yc.addTap(target: self, action:#selector(pickImageAction )) + } + titleLabel.do { (v) in + v.textColor = .white + v.font = .medium(16) + v.textAlignment = .left + v.text = "头像" + } + icon.do { v in + v.yc.setCornerRadius(23) + v.backgroundColor = .white.withAlphaComponent(0.5) + } + nextIcon.image = UIImage(named: "arrow_next") + } + + override func setupLayout() { + bgView.snp.makeConstraints { (m) in + m.left.right.equalToSuperview().inset(15) + m.top.equalToSuperview().inset(6) + m.bottom.equalToSuperview().inset(6) + m.height.equalTo(72) + } + nextIcon.snp.makeConstraints { (m) in + m.width.equalTo(20) + m.height.equalTo(20) + m.right.equalToSuperview().inset(15) + m.centerY.equalToSuperview() + } + icon.snp.makeConstraints { (m) in + m.width.equalTo(46) + m.height.equalTo(46) + m.right.equalToSuperview().inset(40) + m.centerY.equalToSuperview() + } + titleLabel.snp.makeConstraints { (m) in + m.centerY.equalTo(icon) + m.left.equalToSuperview().inset(15) + m.height.equalToSuperview() + } + + } + + @objc func pickImageAction() -> Void { + imgPicker.showImagePicker(from: App.shared.topVC()) {[weak self] image in + guard let self = self else { return } + icon.image = image + } + } +} + diff --git a/LingQi/LingQi/UI/Mine/UserInfo/UserInfoSectionHeader.swift b/LingQi/LingQi/UI/Mine/UserInfo/UserInfoSectionHeader.swift new file mode 100644 index 0000000..1f28c1e --- /dev/null +++ b/LingQi/LingQi/UI/Mine/UserInfo/UserInfoSectionHeader.swift @@ -0,0 +1,28 @@ +// +// UserInfoSectionHeader.swift +// LingQi +// +// Created by liangshi on 2025/7/31. +// + + +class UserInfoSectionHeader: BaseTableViewSetionHeader { + let titleLabel = UILabel() + override func setupViews() { + contentView.backgroundColor = .color(.bgColor) + contentView.addSubview(titleLabel) + titleLabel.do { (v) in + v.textColor = .white.withAlphaComponent(0.8) + v.font = .medium(16) + v.textAlignment = .left + } + } + + override func setupLayout() { + titleLabel.snp.makeConstraints { (m) in + m.top.equalToSuperview().inset(10) + m.bottom.equalToSuperview() + m.left.equalToSuperview().inset(30) + } + } +} diff --git a/LingQi/LingQi/UI/Mine/UserInfo/UserInfoVC.swift b/LingQi/LingQi/UI/Mine/UserInfo/UserInfoVC.swift new file mode 100644 index 0000000..142199f --- /dev/null +++ b/LingQi/LingQi/UI/Mine/UserInfo/UserInfoVC.swift @@ -0,0 +1,82 @@ +// +// UserInfoVC.swift +// LingQi +// +// Created by liangshi on 2025/7/30. +// + +import UIKit +class UserInfoVC: BaseVC{ + let tableView = UITableView(frame: .zero, style: .plain) + let list:[(title:String,list:[UserInfoCellType])] = [("编辑资料",[.avatar,.nickName,.gender]),("账号与安全",[.phone,.password,.deregister])] + + override func viewDidLoad() { + super.viewDidLoad() + // Do any additional setup after loading the view. + } + override func setupViews() { + self.navBar.title = "用户信息" + tableView.do { v in + v.backgroundColor = .color(.bgColor) + v.delegate = self + v.dataSource = self + v.estimatedRowHeight = 52 + v.sectionHeaderHeight = 52 + v.sectionFooterHeight = 0.1 + v.register(UserInfoCell.self, forCellReuseIdentifier: UserInfoCell.reuseID) + v.register(UserInfoImageCell.self, forCellReuseIdentifier: UserInfoImageCell.reuseID) + + v.register(UserInfoSectionHeader.self, forHeaderFooterViewReuseIdentifier: UserInfoSectionHeader.reuseID) + v.register(BaseTableViewSetionHeader.self, forHeaderFooterViewReuseIdentifier: BaseTableViewSetionHeader.reuseID) + } + + let footView = UIView(frame: CGRect(x: 0, y: 0, width: kScreenWid, height: 200)) + let btn = CustomButton(frame: CGRect(x: 15, y: 80, width: kScreenWid - 30, height: 52)) + btn.set(title: "退出登录", bgColor: .white.withAlphaComponent(0.04), target: self, action: #selector(logoutAction)) + footView.addSubview(btn) + tableView.tableFooterView = footView + + view.addSubview(tableView) + } + override func setupLayout() { + tableView.snp.makeConstraints { make in + make.left.right.bottom.equalToSuperview() + make.top.equalTo(kNavBtm) + } + } +} + +extension UserInfoVC:UITableViewDelegate,UITableViewDataSource { + func numberOfSections(in tableView: UITableView) -> Int { + return list.count + } + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return list[section].list.count + } + func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + let view = UserInfoSectionHeader.header(withTableView: tableView) + view.titleLabel.text = list[section].title + return view + } + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let type = list[indexPath.section].list[indexPath.row] + if type == .avatar { + let cell = UserInfoImageCell.cell(withTableView: tableView, indexPath: indexPath) + return cell + } + else{ + let cell = UserInfoCell.cell(withTableView: tableView, indexPath: indexPath) + cell.type = type + return cell + } + } + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + let data = list[indexPath.section].list[indexPath.row] + } +} + +extension UserInfoVC{ + @objc func logoutAction(){ + + } +} diff --git a/LingQi/LingQi/UI/Scan/DeviceCell.swift b/LingQi/LingQi/UI/Scan/DeviceCell.swift new file mode 100644 index 0000000..36915eb --- /dev/null +++ b/LingQi/LingQi/UI/Scan/DeviceCell.swift @@ -0,0 +1,60 @@ +// +// DeviceCell.swift +// Magpie +// +// Created by incar on 2024/1/3. +// + +import UIKit +import SnapKit + +class DeviceCell: BaseTableViewCell { + + var titleLabel = UILabel() + var valueLabel = UILabel() + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + setupView() + setupStyle() + setupLayout() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func setupView(){ + contentView.addSubview(titleLabel) + contentView.addSubview(valueLabel) + + } + func setupStyle(){ + titleLabel.do { v in + v.textColor = .color(.primary) + v.font = UIFont.systemFont(ofSize: 16) + } + valueLabel.do { v in + v.textColor = .color(.secondary) + v.font = UIFont.systemFont(ofSize: 14) + } + + } + override func setupLayout(){ + titleLabel.snp.makeConstraints { make in + make.left.equalToSuperview().inset(20) + make.centerY.equalToSuperview() + } + valueLabel.snp.makeConstraints({ make in + make.right.equalToSuperview().inset(20) + make.centerY.equalToSuperview() + }) + } + + var model:ScanModel = ScanModel(){ + didSet{ + titleLabel.text = model.peripheral.name + valueLabel.text = "\(model.peripheral.rssi)" + } + } +} diff --git a/LingQi/LingQi/UI/Scan/ScanDeviceVC.swift b/LingQi/LingQi/UI/Scan/ScanDeviceVC.swift new file mode 100644 index 0000000..5427420 --- /dev/null +++ b/LingQi/LingQi/UI/Scan/ScanDeviceVC.swift @@ -0,0 +1,103 @@ +// +// ScanDeviceVC.swift +// Magpie +// +// Created by incar on 2024/1/3. +// + +import UIKit +import SnapKit +import MJRefresh +class ScanDeviceVC: BaseVC { + var viewModel = BlueToothViewModel.shareModel + + lazy var tableview :UITableView = { + let table = UITableView(frame: self.view.bounds, style: .plain) + return table + }() + + + + override func viewDidLoad() { + super.viewDidLoad() + // Do any additional setup after loading the view. + + setupView() + setupLayout() + setupStyle() + setupViewModel() +// refreshAction() + } + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) +// self.tableview.mj_header?.endRefreshing() +// if viewModel.selectedPeripheral == nil { +// return +// } +// if viewModel.dataList.count > 0{ +// viewModel.sendFinishShishiShuJuXiang() +// } +// else{ +// YLProgressHUD.instance.showLoading() +// viewModel.reRequestShishiShuJuXiang() +// } +// viewModel.sendFailure = {[weak self] in +// self?.tableview.mj_header?.endRefreshing() +// } + } + + func setupView(){ + view.addSubview(tableview) + } + func setupStyle(){ +// navBar.title = "tab_data" + tableview.do { v in + v.delegate = self + v.dataSource = self + v.rowHeight = 60 + v.register(DeviceCell.self, forCellReuseIdentifier: DeviceCell.reuseID()) + v.mj_header = MJRefreshNormalHeader(refreshingTarget: self, refreshingAction: #selector(refreshAction)) + } + } + override func setupLayout() { + tableview.snp.makeConstraints { make in + make.top.equalToSuperview().inset(100) + make.left.right.bottom.equalToSuperview() + } + } + func setupViewModel(){ + viewModel.deviceListDidChange = {[weak self] in + guard let self = self else { return } + self.tableview.reloadData() + self.tableview.mj_header?.endRefreshing() + } + } + @objc func refreshAction(){ +// if viewModel.selectedPeripheral == nil { +// self.tableview.mj_header?.endRefreshing() +// return +// } +// if viewModel.dataList.count > 0{ +// viewModel.sendFinishShishiShuJuXiang() +// } +// else{ +// viewModel.reRequestShishiShuJuXiang() +// } + } +} +extension ScanDeviceVC:UITableViewDelegate,UITableViewDataSource{ + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return viewModel.deviceList.count + } + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = DeviceCell.cell(withTableView: tableView, indexPath: indexPath) + cell.model = viewModel.deviceList[indexPath.row]; + return cell + } + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + let model = viewModel.deviceList[indexPath.row] + viewModel.bluetooth.connect(peripheral: model.peripheral) + } +} + diff --git a/LingQi/LingQi/UI/common/AgreeMentPopView.swift b/LingQi/LingQi/UI/common/AgreeMentPopView.swift new file mode 100644 index 0000000..4742902 --- /dev/null +++ b/LingQi/LingQi/UI/common/AgreeMentPopView.swift @@ -0,0 +1,142 @@ +// +// AgreeMentPopView.swift +// Magpie +// +// Created by incar on 2024/1/11. +// + +import UIKit + +class AgreeMentPopView: BasePresentView { + private let titleLabel = UILabel() + private let des = UILabel() + private let selectButton = UIButton() + private let privacyLabel = UILabel() + private let okButton = UIButton() + + init() { + super.init(contentHeight: 400.fitR) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func setupSubView() { + super.setupSubView() + contentView.addSubview(titleLabel) + contentView.addSubview(des) + contentView.addSubview(selectButton) + contentView.addSubview(privacyLabel) + contentView.addSubview(okButton) + } + override func setupLayout() { + super.setupLayout() + titleLabel.snp.makeConstraints { (m) in + m.top.equalToSuperview().inset(25.fitR) + m.left.right.equalToSuperview() + m.height.greaterThanOrEqualTo(0) + } + des.snp.makeConstraints { (m) in + m.left.right.equalToSuperview().inset(20.fitR) + m.top.equalToSuperview().inset(67.fitR) + } + selectButton.snp.makeConstraints { (m) in + m.left.equalToSuperview().inset(20.fitR) + m.bottom.equalToSuperview().inset(96.fitR) + m.height.equalTo(15.fitR) + m.width.equalTo(15.fitR) + } + privacyLabel.snp.makeConstraints { (m) in + m.left.equalTo(selectButton.snp.right) + m.centerY.equalTo(selectButton) + } + okButton.snp.makeConstraints { (m) in + m.bottom.equalToSuperview().inset(30.fitR) + m.height.equalTo(44.fitR) + m.left.right.equalToSuperview().inset(25.fitR) + } + } + + override func setupStyle() { + super.setupStyle() + titleLabel.do { (v) in + v.textColor = .rgb(0x333333) + v.font = .semiBold(16) + v.textAlignment = .center + v.text = "诸葛驾到代运营协议说明" + } + des.do { (v) in + v.text = "1.用户通过诸葛驾到寻找到合适的驾校后,委托诸葛驾到负责撮合驾校学车的服务提供方,为用户代报名指定班型的学车服务,在代报名过程中提供驾校信息核验、学车权益守护、学车资金托管、代理结算等服务。具体服务内容由诸葛驾到根据实际情况提供,包括但不限于: (1) 作为用户的学车经纪人代表用户与驾校签约学车报名协议;(2)学车报名资金的托管; (3) 维护用户在驾校学车的约定权益;(4) 服务商收入结算和用户支付费用:具体金额以产生的统计数据为准;(5) 订单查询;2.用户通过诸葛驾到完成的学车报名信息以平台发布的相应信息为准,交易应签署《学车报名服务合同》。具体内容《学车报名服务合同》以约定为准,该合同文本格式由诸葛驾到平台的驾校提供,经诸葛驾到平台撮合,由用户与诸葛驾到平台的驾校直接签约。所有发给用户的通告及其他消息都可通过APP或者用户所提供的联系方式发送 。" + v.textAlignment = .left + v.numberOfLines = 0 + v.font = .regular(12) + v.textColor = .rgb(0x666666) + } + selectButton.do { (v) in + v.yc.setBorder(width: 1.fitR, color: .rgb(0x999999), radius: 2.fitR) + v.setImage(nil, for: .normal) + v.addTarget(self, action: #selector(selectBtnAction), for: .touchUpInside) + } + privacyLabel.do { (v) in + v.text = " 已阅读同意协议说明" + v.textAlignment = .left + v.numberOfLines = 1 + v.font = .regular(12) + v.textColor = .rgb(0x999999) + privacyLabel.yc.addTap(target: self, action: #selector(selectBtnAction)) + } + okButton.do { (v) in + v.isEnabled = false + v.yc.addGardiendLayerWith(colors: [.red,.blue], frame: CGRect(x: 0, y: 0, width: kScreenWid - 50.fitR, height: 44.fitR), direction: .left2right) + v.setTitle("下一步", for: .normal) + v.setTitleColor(.white, for: .normal) + v.titleLabel?.font = .regular(15) + v.yc.setCornerRadius(22.fitR) + v.alpha = 0.5 + v.addTarget(self, action: #selector(okButtonAction), for: .touchUpInside) + self.selectBtnAction() + + } + } + @objc func okButtonAction(){ + // self.okButtonTap?() + // hide() + self.start2LoadData() + } + @objc func selectBtnAction(){ + selectButton.isSelected = !selectButton.isSelected + if selectButton.isSelected { + selectButton.yc.setBorder(width: 1.fitR, color: .rgb(0x036AFF), radius: 2.fitR) + selectButton.setImage(UIImage(named: "agreement_selected"), for: .normal) + privacyLabel.textColor = .rgb(0x036AFF) + okButton.alpha = 1 + } + else{ + selectButton.yc.setBorder(width: 1.fitR, color: .rgb(0x999999), radius: 2.fitR) + selectButton.setImage(nil, for: .normal) + privacyLabel.textColor = .rgb(0x999999) + okButton.alpha = 0.5 + } + okButton.isEnabled = selectButton.isSelected + } + + func start2LoadData(){ + // SVProgressHUD.showLoading() + // SVProgressHUD.setContainerView(app.window) + // self.vm.fetchClassDetail{[weak self] (model) in + // guard let self = self else {return} + // if model.isSuccess{ + // SVProgressHUD.hidden() + // self.hide() + // let params = PayDetailVCParams(model:model.data) + // let vc = PayDetailVC(data: params) + // UIViewController.yc.currentNav?.pushViewController(vc, animated: true) + // } + // else{ + // SVProgressHUD.showAutoHiden(model.msg) + // } + // } + } +} + diff --git a/LingQi/LingQi/UI/common/CustomButton.swift b/LingQi/LingQi/UI/common/CustomButton.swift new file mode 100644 index 0000000..1723ec1 --- /dev/null +++ b/LingQi/LingQi/UI/common/CustomButton.swift @@ -0,0 +1,19 @@ +// +// CustomButton.swift +// LingQi +// +// Created by liangshi on 2025/7/30. +// + +import UIKit +class CustomButton: UIButton { + func set(title:String,bgColor:UIColor = .rgb(0x0245BC), target: Any?, action: Selector) { + setTitle(title, for: .normal) + setTitleColor(.white, for: .normal) + addTarget(target, action: action, for: .touchUpInside) + layer.cornerRadius = 12 + layer.masksToBounds = true + titleLabel?.font = .systemFont(ofSize: 16) + backgroundColor = bgColor + } +} diff --git a/LingQi/LingQi/UI/common/ImagePickerManager.swift b/LingQi/LingQi/UI/common/ImagePickerManager.swift new file mode 100644 index 0000000..d414d79 --- /dev/null +++ b/LingQi/LingQi/UI/common/ImagePickerManager.swift @@ -0,0 +1,142 @@ +// +// ImagePic.swift +// LingQi +// +// Created by liangshi on 2025/7/31. +// + +//// +//// ImagePicker.swift +//// BlueMagpie +//// +//// Created by liangshi on 2025/7/8. +//// +// + +import UIKit +import TZImagePickerController +import AVFoundation + +typealias ImagePickerCallback = (UIImage?) -> Void +typealias VideoPickerCallback = (UIImage?, URL?, Error?) -> Void + +class ImagePickerManager: NSObject, TZImagePickerControllerDelegate { + + private var imageCallback: ImagePickerCallback? + private var videoCallback: VideoPickerCallback? + + // MARK: - 图片选择 + func showImagePicker(from viewController: UIViewController, callback: @escaping ImagePickerCallback) { + self.imageCallback = callback + + let picker = TZImagePickerController(maxImagesCount: 1, delegate: self) + picker?.needCircleCrop = true + picker?.circleCropRadius = Int(UIScreen.main.bounds.size.width/2) + picker?.allowCrop = true + picker?.showSelectBtn = false + picker?.allowPickingOriginalPhoto = false + picker?.allowPickingVideo = false + picker?.allowPickingImage = true + picker?.modalPresentationStyle = .overFullScreen + viewController.present(picker!, animated: true, completion: nil) + } + + // MARK: - 视频选择 + func showVideoPicker(from viewController: UIViewController, callback: @escaping VideoPickerCallback) { + self.videoCallback = callback + + let picker = TZImagePickerController(maxImagesCount: 1, delegate: self) + picker?.allowPickingImage = false + picker?.allowPickingVideo = true + picker?.allowPickingOriginalPhoto = false + picker?.showSelectBtn = false + picker?.allowPickingMultipleVideo = false + picker?.modalPresentationStyle = .overFullScreen + viewController.present(picker!, animated: true, completion: nil) + } + + // MARK: - 图片选择回调 + func imagePickerController(_ picker: TZImagePickerController!, didFinishPickingPhotos photos: [UIImage]!, sourceAssets assets: [Any]!, isSelectOriginalPhoto: Bool) { + imageCallback?(photos?.first) + imageCallback = nil + } + + // MARK: - 视频选择回调 + func imagePickerController(_ picker: TZImagePickerController!, didFinishPickingVideo coverImage: UIImage!, sourceAssets asset: PHAsset!) { + guard let asset = asset, asset.mediaType == .video else { + videoCallback?(coverImage, nil, nil) + videoCallback = nil + return + } + + // 请求视频URL + let options = PHVideoRequestOptions() + options.isNetworkAccessAllowed = true + options.deliveryMode = .automatic + + PHImageManager.default().requestAVAsset(forVideo: asset, options: options) { [weak self] avAsset, audioMix, info in + DispatchQueue.main.async { + guard let self = self, let avAsset = avAsset else { + self?.videoCallback?(coverImage, nil, nil) + self?.videoCallback = nil + return + } + + // 转换视频为MP4格式 + self.convertVideoToMP4(avAsset: avAsset) { [weak self] outputURL, error in + self?.videoCallback?(coverImage, outputURL, error) + self?.videoCallback = nil + } + } + } + } + + // MARK: - 视频格式转换 + private func convertVideoToMP4(avAsset: AVAsset, completion: @escaping (URL?, Error?) -> Void) { + // 创建导出会话 + guard let exportSession = AVAssetExportSession(asset: avAsset, presetName: AVAssetExportPresetHighestQuality) else { + completion(nil, NSError(domain: "VideoExportError", code: 1, userInfo: [NSLocalizedDescriptionKey: "无法创建导出会话"])) + return + } + + // 检查是否支持导出为MP4格式 + if !exportSession.supportedFileTypes.contains(.mp4) { + completion(nil, NSError(domain: "VideoExportError", code: 2, userInfo: [NSLocalizedDescriptionKey: "不支持导出为MP4格式"])) + return + } + + // 创建输出URL + let outputFileName = UUID().uuidString + ".mp4" + let outputURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(outputFileName) + + // 配置导出会话 + exportSession.outputFileType = .mp4 + exportSession.outputURL = outputURL + exportSession.shouldOptimizeForNetworkUse = true + + // 开始导出 + exportSession.exportAsynchronously { + // 修复 DispatchQueue 调用问题 + DispatchQueue.main.async { + switch exportSession.status { + case.completed: + completion(outputURL, nil) + case.failed: + completion(nil, exportSession.error) + case.cancelled: + completion(nil, NSError(domain: "VideoExportError", code: 3, userInfo: [NSLocalizedDescriptionKey: "导出已取消"])) + default: + completion(nil, NSError(domain: "VideoExportError", code: 4, userInfo: [NSLocalizedDescriptionKey: "导出状态未知"])) + } + } + } + } + + // MARK: - 取消选择 + func tz_imagePickerControllerDidCancel(_ picker: TZImagePickerController!) { + imageCallback?(nil) + videoCallback?(nil, nil, nil) + imageCallback = nil + videoCallback = nil + } +} diff --git a/LingQi/LingQi/ViewController.swift b/LingQi/LingQi/ViewController.swift new file mode 100644 index 0000000..88f2c7d --- /dev/null +++ b/LingQi/LingQi/ViewController.swift @@ -0,0 +1,19 @@ +// +// ViewController.swift +// LingQi +// +// Created by liangshi on 2025/7/29. +// + +import UIKit + +class ViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + // Do any additional setup after loading the view. + } + + +} + diff --git a/LingQi/Podfile.lock b/LingQi/Podfile.lock new file mode 100644 index 0000000..0317b18 --- /dev/null +++ b/LingQi/Podfile.lock @@ -0,0 +1,147 @@ +PODS: + - Alamofire (5.10.2) + - FDFullscreenPopGesture (1.1) + - HandyJSON (5.0.2) + - IQKeyboardCore (1.0.5) + - IQKeyboardManagerSwift (8.0.1): + - IQKeyboardManagerSwift/Appearance (= 8.0.1) + - IQKeyboardManagerSwift/Core (= 8.0.1) + - IQKeyboardManagerSwift/IQKeyboardReturnManager (= 8.0.1) + - IQKeyboardManagerSwift/IQKeyboardToolbarManager (= 8.0.1) + - IQKeyboardManagerSwift/IQTextView (= 8.0.1) + - IQKeyboardManagerSwift/Resign (= 8.0.1) + - IQKeyboardManagerSwift/Appearance (8.0.1): + - IQKeyboardManagerSwift/Core + - IQKeyboardManagerSwift/Core (8.0.1): + - IQKeyboardNotification + - IQTextInputViewNotification + - IQKeyboardManagerSwift/IQKeyboardReturnManager (8.0.1): + - IQKeyboardReturnManager + - IQKeyboardManagerSwift/IQKeyboardToolbarManager (8.0.1): + - IQKeyboardManagerSwift/Core + - IQKeyboardToolbarManager + - IQKeyboardManagerSwift/IQTextView (8.0.1): + - IQTextView + - IQKeyboardManagerSwift/Resign (8.0.1): + - IQKeyboardManagerSwift/Core + - IQKeyboardNotification (1.0.3) + - IQKeyboardReturnManager (1.0.4): + - IQKeyboardCore (= 1.0.5) + - IQKeyboardToolbar (1.1.1): + - IQKeyboardCore + - IQKeyboardToolbar/Core (= 1.1.1) + - IQKeyboardToolbar/Core (1.1.1): + - IQKeyboardCore + - IQKeyboardToolbar/Placeholderable + - IQKeyboardToolbar/Placeholderable (1.1.1): + - IQKeyboardCore + - IQKeyboardToolbarManager (1.1.3): + - IQKeyboardToolbar + - IQTextInputViewNotification + - IQTextInputViewNotification (1.0.8): + - IQKeyboardCore + - IQTextView (1.0.5): + - IQKeyboardToolbar/Placeholderable + - Kingfisher (6.3.1) + - MJRefresh (3.7.9) + - Moya (15.0.0): + - Moya/Core (= 15.0.0) + - Moya/Core (15.0.0): + - Alamofire (~> 5.0) + - netfox (1.21.0) + - Realm (20.0.3): + - Realm/Headers (= 20.0.3) + - Realm/Headers (20.0.3) + - RealmSwift (20.0.3): + - Realm (= 20.0.3) + - SnapKit (5.7.1) + - SVProgressHUD (2.3.1): + - SVProgressHUD/Core (= 2.3.1) + - SVProgressHUD/Core (2.3.1) + - SwiftDate (7.0.0) + - swiftScan (1.2.1) + - TZImagePickerController (3.8.9): + - TZImagePickerController/Basic (= 3.8.9) + - TZImagePickerController/Location (= 3.8.9) + - TZImagePickerController/Basic (3.8.9) + - TZImagePickerController/Location (3.8.9) + - TZScrollViewPopGesture (1.0.6) + - YYModel (1.0.4) + - YYText (1.0.7) + +DEPENDENCIES: + - FDFullscreenPopGesture + - HandyJSON + - IQKeyboardManagerSwift + - Kingfisher (~> 6.0) + - MJRefresh + - Moya + - netfox + - RealmSwift + - SnapKit + - SVProgressHUD + - SwiftDate + - swiftScan + - TZImagePickerController + - TZScrollViewPopGesture + - YYModel + - YYText + +SPEC REPOS: + https://gitee.com/mirrors/CocoaPods-Specs.git: + - Alamofire + - FDFullscreenPopGesture + - HandyJSON + - IQKeyboardCore + - IQKeyboardManagerSwift + - IQKeyboardNotification + - IQKeyboardReturnManager + - IQKeyboardToolbar + - IQKeyboardToolbarManager + - IQTextInputViewNotification + - IQTextView + - Kingfisher + - MJRefresh + - Moya + - netfox + - Realm + - RealmSwift + - SnapKit + - SVProgressHUD + - SwiftDate + - swiftScan + - TZImagePickerController + - TZScrollViewPopGesture + - YYModel + - YYText + +SPEC CHECKSUMS: + Alamofire: 7193b3b92c74a07f85569e1a6c4f4237291e7496 + FDFullscreenPopGesture: a8a620179e3d9c40e8e00256dcee1c1a27c6d0f0 + HandyJSON: 9e4e236f5d2dbefad5155a77417bbea438201c03 + IQKeyboardCore: 28c8bf3bcd8ba5aa1570b318cbc4da94b861711e + IQKeyboardManagerSwift: 835fc9c6e4732398113406d84900ad2e8f141218 + IQKeyboardNotification: d7382c4466c5a5adef92c7452ebf861b36050088 + IQKeyboardReturnManager: 972be48528ce9e7508ab3ab15ac7efac803f17f5 + IQKeyboardToolbar: d4bdccfb78324aec2f3920659c77bb89acd33312 + IQKeyboardToolbarManager: 6c693c8478d6327a7ef2107528d29698b3514dbb + IQTextInputViewNotification: f5e954d8881fd9808b744e49e024cc0d4bcfe572 + IQTextView: ae13b4922f22e6f027f62c557d9f4f236b19d5c7 + Kingfisher: 016c8b653a35add51dd34a3aba36b580041acc74 + MJRefresh: ff9e531227924c84ce459338414550a05d2aea78 + Moya: 138f0573e53411fb3dc17016add0b748dfbd78ee + netfox: 9d5cc727fe7576c4c7688a2504618a156b7d44b7 + Realm: 853e5089d6042dff807bda000277eadfe2da93d2 + RealmSwift: f33c19577cefcbf681345d721fcbc7b42be4c949 + SnapKit: d612e99e678a2d3b95bf60b0705ed0a35c03484a + SVProgressHUD: 4837c74bdfe2e51e8821c397825996a8d7de6e22 + SwiftDate: bbc26e26fc8c0c33fbee8c140c5e8a68293a148a + swiftScan: 0849e7d7c1c641384767a573ee8cb90b88d1ddd9 + TZImagePickerController: 456f470b5dea97b37226ec7a694994a8663340b2 + TZScrollViewPopGesture: d36355038259e89372a1f4a2db7e9ca675de2278 + YYModel: 2a7fdd96aaa4b86a824e26d0c517de8928c04b30 + YYText: 5c461d709e24d55a182d1441c41dc639a18a4849 + +PODFILE CHECKSUM: 1cbd737c5d19b063216ec530dc4f6434a663b4cd + +COCOAPODS: 1.16.2 diff --git a/LingQi/podfile b/LingQi/podfile new file mode 100644 index 0000000..6e15b3f --- /dev/null +++ b/LingQi/podfile @@ -0,0 +1,31 @@ +source "https://gitee.com/mirrors/CocoaPods-Specs.git" +platform :ios, '13.0' +use_frameworks! + + +workspace 'LingQi' +project 'LingQi.xcodeproj' +target 'LingQi' do +# pod 'Toast-Swift' + pod 'SnapKit'#布局 + pod 'YYText'#富文本 + pod 'FDFullscreenPopGesture'#侧滑返回 + pod 'TZScrollViewPopGesture'#侧滑返回 + pod 'IQKeyboardManagerSwift'#键盘 + pod 'MJRefresh'#刷新 + pod 'YYModel'#model解析 + pod 'HandyJSON'#model解析 + pod 'RealmSwift'#数据库 + pod 'SwiftDate'#时间转换 + pod 'SVProgressHUD'#蒙版 + pod 'Kingfisher', '~> 6.0'#图片下载 +# pod 'FSPagerView' + ## pod 'Alamofire' + pod 'Moya'#网络 + pod 'swiftScan'#二维码 + pod 'TZImagePickerController'#图片选择 + pod 'netfox'#调试 +# pod 'DoraemonKit'#调试 +end + +