| | |
| | | GCC_PREFIX_HEADER = "Target Support Files/ObjectMapper/ObjectMapper-prefix.pch"; |
| | | INFOPLIST_FILE = "Target Support Files/ObjectMapper/ObjectMapper-Info.plist"; |
| | | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; |
| | | IPHONEOS_DEPLOYMENT_TARGET = 10.0; |
| | | IPHONEOS_DEPLOYMENT_TARGET = 10; |
| | | LD_RUNPATH_SEARCH_PATHS = ( |
| | | "$(inherited)", |
| | | "@executable_path/Frameworks", |
| | |
| | | GCC_PREFIX_HEADER = "Target Support Files/ObjectMapper/ObjectMapper-prefix.pch"; |
| | | INFOPLIST_FILE = "Target Support Files/ObjectMapper/ObjectMapper-Info.plist"; |
| | | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; |
| | | IPHONEOS_DEPLOYMENT_TARGET = 10.0; |
| | | IPHONEOS_DEPLOYMENT_TARGET = 10; |
| | | LD_RUNPATH_SEARCH_PATHS = ( |
| | | "$(inherited)", |
| | | "@executable_path/Frameworks", |
| | |
| | | DEVELOPMENT_TEAM = 5ZV937VB25; |
| | | IBSC_MODULE = ObjectMapper; |
| | | INFOPLIST_FILE = "Target Support Files/ObjectMapper/ResourceBundle-Privacy-ObjectMapper-Info.plist"; |
| | | IPHONEOS_DEPLOYMENT_TARGET = 10.0; |
| | | IPHONEOS_DEPLOYMENT_TARGET = 13.0; |
| | | PRODUCT_BUNDLE_IDENTIFIER = com.sinata.XQMuse.test; |
| | | PRODUCT_NAME = Privacy; |
| | | SDKROOT = iphoneos; |
| | |
| | | DEVELOPMENT_TEAM = 5ZV937VB25; |
| | | IBSC_MODULE = ObjectMapper; |
| | | INFOPLIST_FILE = "Target Support Files/ObjectMapper/ResourceBundle-Privacy-ObjectMapper-Info.plist"; |
| | | IPHONEOS_DEPLOYMENT_TARGET = 10.0; |
| | | IPHONEOS_DEPLOYMENT_TARGET = 13.0; |
| | | PRODUCT_BUNDLE_IDENTIFIER = com.sinata.XQMuse.test; |
| | | PRODUCT_NAME = Privacy; |
| | | SDKROOT = iphoneos; |
| | |
| | | DEVELOPMENT_TEAM = 5ZV937VB25; |
| | | IBSC_MODULE = SnapKit; |
| | | INFOPLIST_FILE = "Target Support Files/SnapKit/ResourceBundle-SnapKit_Privacy-SnapKit-Info.plist"; |
| | | IPHONEOS_DEPLOYMENT_TARGET = 10.0; |
| | | IPHONEOS_DEPLOYMENT_TARGET = 12.0; |
| | | PRODUCT_BUNDLE_IDENTIFIER = com.sinata.XQMuse.test; |
| | | PRODUCT_NAME = SnapKit_Privacy; |
| | | SDKROOT = iphoneos; |
| | |
| | | DEVELOPMENT_TEAM = 5ZV937VB25; |
| | | IBSC_MODULE = SnapKit; |
| | | INFOPLIST_FILE = "Target Support Files/SnapKit/ResourceBundle-SnapKit_Privacy-SnapKit-Info.plist"; |
| | | IPHONEOS_DEPLOYMENT_TARGET = 10.0; |
| | | IPHONEOS_DEPLOYMENT_TARGET = 12.0; |
| | | PRODUCT_BUNDLE_IDENTIFIER = com.sinata.XQMuse.test; |
| | | PRODUCT_NAME = SnapKit_Privacy; |
| | | SDKROOT = iphoneos; |
| | |
| | | 1327C6822C81D107005DA44B /* PlanGuide_3_VC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1327C6802C81D107005DA44B /* PlanGuide_3_VC.swift */; }; |
| | | 1327C6832C81D107005DA44B /* PlanGuide_3_VC.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1327C6812C81D107005DA44B /* PlanGuide_3_VC.xib */; }; |
| | | 132C40292C816003002E3270 /* SourceHanSerifCN-Medium.otf in Resources */ = {isa = PBXBuildFile; fileRef = 132C40282C816002002E3270 /* SourceHanSerifCN-Medium.otf */; }; |
| | | 132C4B782CC0E63D00EA56AF /* WeChatTools.swift in Sources */ = {isa = PBXBuildFile; fileRef = 132C4B772CC0E63D00EA56AF /* WeChatTools.swift */; }; |
| | | 132C7EF12C8FE3B900A4CA18 /* ChooseOptTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 132C7EF02C8FE3B900A4CA18 /* ChooseOptTitleView.swift */; }; |
| | | 132C7EF32C8FE3BF00A4CA18 /* ChooseOptTitleView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 132C7EF22C8FE3BF00A4CA18 /* ChooseOptTitleView.xib */; }; |
| | | 132C7EF72C8FE9BB00A4CA18 /* ChooseOptTitleTCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 132C7EF62C8FE9BB00A4CA18 /* ChooseOptTitleTCell.xib */; }; |
| | |
| | | 1327C6802C81D107005DA44B /* PlanGuide_3_VC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlanGuide_3_VC.swift; sourceTree = "<group>"; }; |
| | | 1327C6812C81D107005DA44B /* PlanGuide_3_VC.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PlanGuide_3_VC.xib; sourceTree = "<group>"; }; |
| | | 132C40282C816002002E3270 /* SourceHanSerifCN-Medium.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SourceHanSerifCN-Medium.otf"; sourceTree = "<group>"; }; |
| | | 132C4B762CC0E5CA00EA56AF /* XQMuse-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "XQMuse-Bridging-Header.h"; sourceTree = "<group>"; }; |
| | | 132C4B772CC0E63D00EA56AF /* WeChatTools.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeChatTools.swift; sourceTree = "<group>"; }; |
| | | 132C7EF02C8FE3B900A4CA18 /* ChooseOptTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChooseOptTitleView.swift; sourceTree = "<group>"; }; |
| | | 132C7EF22C8FE3BF00A4CA18 /* ChooseOptTitleView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ChooseOptTitleView.xib; sourceTree = "<group>"; }; |
| | | 132C7EF52C8FE9BB00A4CA18 /* ChooseOptTitleTCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChooseOptTitleTCell.swift; sourceTree = "<group>"; }; |
| | |
| | | path = VC; |
| | | sourceTree = "<group>"; |
| | | }; |
| | | 132C4B792CC0EBDD00EA56AF /* Layouts */ = { |
| | | isa = PBXGroup; |
| | | children = ( |
| | | 139C165F2C6A0FBB00A924D9 /* TestLeftRightCollectionViewFlowLayout.swift */, |
| | | 1336EFA42C6DEB550075E070 /* HoverHeaderFlowLayout.swift */, |
| | | 13897D882C7DB9D7006209E0 /* EqualCellSpaceFlowLayout.swift */, |
| | | ); |
| | | path = Layouts; |
| | | sourceTree = "<group>"; |
| | | }; |
| | | 132C4B7A2CC0EBFA00EA56AF /* StoreKit */ = { |
| | | isa = PBXGroup; |
| | | children = ( |
| | | 1304526E2CB4FF280049FB3A /* InPurchaseManager.swift */, |
| | | 130452692CB4CA310049FB3A /* XQMuseStoreKit.storekit */, |
| | | 1304526B2CB4CB210049FB3A /* StoreKitTestCertificate.cer */, |
| | | ); |
| | | path = StoreKit; |
| | | sourceTree = "<group>"; |
| | | }; |
| | | 132C7EF42C8FE9A800A4CA18 /* TCell */ = { |
| | | isa = PBXGroup; |
| | | children = ( |
| | |
| | | 13985DB32C69B7D40046B6DC /* Config */ = { |
| | | isa = PBXGroup; |
| | | children = ( |
| | | 132C4B7A2CC0EBFA00EA56AF /* StoreKit */, |
| | | 132C4B792CC0EBDD00EA56AF /* Layouts */, |
| | | 132C4B772CC0E63D00EA56AF /* WeChatTools.swift */, |
| | | 13D2A0542CB671D9005F6014 /* SDK */, |
| | | 1304526E2CB4FF280049FB3A /* InPurchaseManager.swift */, |
| | | 130452692CB4CA310049FB3A /* XQMuseStoreKit.storekit */, |
| | | 1304526B2CB4CB210049FB3A /* StoreKitTestCertificate.cer */, |
| | | 13A0A8A02C746ADA00DF08B6 /* Enums */, |
| | | 139C165F2C6A0FBB00A924D9 /* TestLeftRightCollectionViewFlowLayout.swift */, |
| | | 1336EFA42C6DEB550075E070 /* HoverHeaderFlowLayout.swift */, |
| | | 137175C42C6C3C2100B38EF1 /* Fonts */, |
| | | 13985DB42C69B7DF0046B6DC /* Def.swift */, |
| | | 13985DB72C69B80D0046B6DC /* Themes.swift */, |
| | | 13897D882C7DB9D7006209E0 /* EqualCellSpaceFlowLayout.swift */, |
| | | 135B1D1F2C8863D10089A9BE /* Types.swift */, |
| | | 132C4B762CC0E5CA00EA56AF /* XQMuse-Bridging-Header.h */, |
| | | ); |
| | | path = Config; |
| | | sourceTree = "<group>"; |
| | |
| | | 130913EF2C6DE67E00418201 /* HomeRelaxBanner_2_1_CCell.swift in Sources */, |
| | | 1333DC7A2C72D8C400D8ACAE /* CourseDetail_3_TCell.swift in Sources */, |
| | | 135C2A752C7F033300CC2A67 /* CLPlayerView.swift in Sources */, |
| | | 132C4B782CC0E63D00EA56AF /* WeChatTools.swift in Sources */, |
| | | 1300BD3C2C6DFB1C000BCA5E /* VIPCenterVC.swift in Sources */, |
| | | 134803D62C76E3E000F4FDDA /* WatchHistoryVC.swift in Sources */, |
| | | 13D2A0492CB670BF005F6014 /* OBSUploader.swift in Sources */, |
| | |
| | | ENABLE_USER_SCRIPT_SANDBOXING = NO; |
| | | FRAMEWORK_SEARCH_PATHS = ( |
| | | "$(inherited)", |
| | | "$(PROJECT_DIR)/XQMuse/Config/SDK\\ 2", |
| | | "$(PROJECT_DIR)/XQMuse/Config/SDK\\ 2", |
| | | "$(PROJECT_DIR)/XQMuse/Config/SDK", |
| | | ); |
| | | GENERATE_INFOPLIST_FILE = YES; |
| | |
| | | MARKETING_VERSION = 1.0; |
| | | OTHER_LDFLAGS = ( |
| | | "$(inherited)", |
| | | "-l\"WechatOpenSDK\"", |
| | | "-ObjC", |
| | | "-\"WechatOpenSDK\"", |
| | | "-l\"c++\"", |
| | | "-l\"resolv\"", |
| | | "-l\"sqlite3.0\"", |
| | |
| | | "\"XCGLogger\"", |
| | | "-force_load", |
| | | "$(SRCROOT)/XQMuse/Config/SDK/OBS.framework/OBS", |
| | | "\"-ld64\"", |
| | | ); |
| | | PRODUCT_BUNDLE_IDENTIFIER = com.sinata.XQMuse.test; |
| | | PRODUCT_NAME = "$(TARGET_NAME)"; |
| | |
| | | SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; |
| | | SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; |
| | | SWIFT_EMIT_LOC_STRINGS = YES; |
| | | SWIFT_OBJC_BRIDGING_HEADER = "/Users/yvkd/XiLaida/XQMuse/XQMuse/Config/XQMuse-Bridging-Header.h"; |
| | | SWIFT_VERSION = 5.0; |
| | | TARGETED_DEVICE_FAMILY = 1; |
| | | }; |
| | |
| | | ENABLE_USER_SCRIPT_SANDBOXING = NO; |
| | | FRAMEWORK_SEARCH_PATHS = ( |
| | | "$(inherited)", |
| | | "$(PROJECT_DIR)/XQMuse/Config/SDK\\ 2", |
| | | "$(PROJECT_DIR)/XQMuse/Config/SDK\\ 2", |
| | | "$(PROJECT_DIR)/XQMuse/Config/SDK", |
| | | ); |
| | | GENERATE_INFOPLIST_FILE = YES; |
| | |
| | | MARKETING_VERSION = 1.0; |
| | | OTHER_LDFLAGS = ( |
| | | "$(inherited)", |
| | | "-l\"WechatOpenSDK\"", |
| | | "-ObjC", |
| | | "-\"WechatOpenSDK\"", |
| | | "-l\"c++\"", |
| | | "-l\"resolv\"", |
| | | "-l\"sqlite3.0\"", |
| | |
| | | "\"XCGLogger\"", |
| | | "-force_load", |
| | | "$(SRCROOT)/XQMuse/Config/SDK/OBS.framework/OBS", |
| | | "\"-ld64\"", |
| | | ); |
| | | PRODUCT_BUNDLE_IDENTIFIER = com.sinata.XQMuse.test; |
| | | PRODUCT_NAME = "$(TARGET_NAME)"; |
| | |
| | | SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; |
| | | SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; |
| | | SWIFT_EMIT_LOC_STRINGS = YES; |
| | | SWIFT_OBJC_BRIDGING_HEADER = "/Users/yvkd/XiLaida/XQMuse/XQMuse/Config/XQMuse-Bridging-Header.h"; |
| | | SWIFT_VERSION = 5.0; |
| | | TARGETED_DEVICE_FAMILY = 1; |
| | | }; |
| | |
| | | |
| | | @main |
| | | |
| | | class AppDelegate: UIResponder, UIApplicationDelegate { |
| | | class AppDelegate: UIResponder, UIApplicationDelegate,WXApiDelegate{ |
| | | |
| | | var window: UIWindow? |
| | | |
| | | |
| | | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { |
| | | |
| | | WeChatTools.register(appid: WeChatAPPID, link: "https://app.xqzhihui.com/app/") |
| | | return true |
| | | } |
| | | |
| | | func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { |
| | | return .allButUpsideDown |
| | | } |
| | | |
| | | func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([any UIUserActivityRestoring]?) -> Void) -> Bool { |
| | | return WXApi.handleOpenUniversalLink(userActivity, delegate: self) |
| | | } |
| | | |
| | | func application(_ application: UIApplication, handleOpen url: URL) -> Bool { |
| | | |
| | | if url.scheme == WeChatAPPID{ |
| | | return WXApi.handleOpen(url, delegate: self) |
| | | } |
| | | return true |
| | | } |
| | | |
| | | func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool { |
| | | if url.scheme == WeChatAPPID{ |
| | | return WXApi.handleOpen(url, delegate: self) |
| | | } |
| | | return true |
| | | } |
| | | |
| | | func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { |
| | | |
| | | if url.scheme == WeChatAPPID{ |
| | | return WXApi.handleOpen(url, delegate: self) |
| | | } |
| | | return true |
| | | } |
| | | |
| | | |
| | | // MARK: UISceneSession Lifecycle |
| | | |
| | |
| | | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. |
| | | } |
| | | |
| | | func onReq(_ req: BaseReq) { |
| | | |
| | | } |
| | | |
| | | func onResp(_ resp: BaseResp) { |
| | | |
| | | } |
| | | |
| | | |
| | | } |
| | | |
| | | |
New file |
| | |
| | | { |
| | | "images" : [ |
| | | { |
| | | "idiom" : "universal", |
| | | "scale" : "1x" |
| | | }, |
| | | { |
| | | "filename" : "组 20@2x.png", |
| | | "idiom" : "universal", |
| | | "scale" : "2x" |
| | | }, |
| | | { |
| | | "filename" : "组 20@3x.png", |
| | | "idiom" : "universal", |
| | | "scale" : "3x" |
| | | } |
| | | ], |
| | | "info" : { |
| | | "author" : "xcode", |
| | | "version" : 1 |
| | | } |
| | | } |
| | |
| | | |
| | | /// 需要透明Nav的VC |
| | | private var lucencyVCs = [LoginVC.self] |
| | | private var whiteStyleVCs = [HomeItemDetailVC.self,CourseDetialVC.self,HomeItemDetailVC.self,CourseDetialVideoVC.self,PavilionDetailVC.self] |
| | | private var whiteStyleVCs = [HomeItemDetailVC.self,CourseDetialVC.self,CourseDetialVideoVC.self,PavilionDetailVC.self] |
| | | |
| | | open override func viewDidLoad() { |
| | | super.viewDidLoad() |
| | |
| | | import QMUIKit |
| | | import OSLog |
| | | |
| | | //https://dummyimage.com/100x100 |
| | | let WeChatAPPID = "wx4b9c1d814c2902a3" |
| | | let WeChatSecrect = "60fed4b6f52603ba6769e1118b4a57ae" |
| | | |
| | | let app = UIApplication.shared.delegate as! AppDelegate |
| | | |
New file |
| | |
| | | // |
| | | // HoverHeaderFlowLayout.swift |
| | | // XQMuse |
| | | // |
| | | // Created by 无故事王国 on 2024/8/15. |
| | | // |
| | | |
| | | import Foundation |
| | | import UIKit |
| | | import JQTools |
| | | |
| | | /// 悬浮HeaderView |
| | | class HoverHeaderFlowLayout:UICollectionViewFlowLayout{ |
| | | var naviHeight:CGFloat = JQ_NavBarHeight//默认分组停放高度 |
| | | override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { |
| | | //UICollectionViewLayoutAttributes:我称它为collectionView中的item(包括cell和header、footer这些)的结构信息 |
| | | //截取到父类所返回的数组(里面放的是当前屏幕所能展示的item的结构信息),并转化成不可变数组 |
| | | var superArray = super.layoutAttributesForElements(in: rect) |
| | | //创建存索引的数组,无符号(正整数),无序(不能通过下标取值),不可重复(重复的话会自动过滤) |
| | | let noneHeaderSections=NSMutableIndexSet(); |
| | | for attributes:UICollectionViewLayoutAttributes in superArray! { |
| | | //如果当前的元素分类是一个cell,将cell所在的分区section加入数组,重复的话会自动过滤 |
| | | if attributes.representedElementCategory == .cell{ |
| | | noneHeaderSections.add(attributes.indexPath.section) |
| | | } |
| | | } |
| | | //遍历superArray,将当前屏幕中拥有的header的section从数组中移除,得到一个当前屏幕中没有header的section数组 |
| | | //正常情况下,随着手指往上移,header脱离屏幕会被系统回收而cell尚在,也会触发该方法 |
| | | for attributes:UICollectionViewLayoutAttributes in superArray! { |
| | | //如果当前的元素是一个header,将header所在的section从数组中移除 |
| | | if attributes.representedElementKind == UICollectionView.elementKindSectionHeader { |
| | | noneHeaderSections.remove(attributes.indexPath.section) |
| | | } |
| | | } |
| | | //遍历当前屏幕中没有header的section数组 |
| | | noneHeaderSections .enumerate({ (idx, obj) -> Void in |
| | | //取到当前section中第一个item的indexPath |
| | | let indexPath = NSIndexPath(item: 0, section: idx) |
| | | let attributes=self.layoutAttributesForSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, at: indexPath as IndexPath) |
| | | //如果当前分区确实有因为离开屏幕而被系统回收的header |
| | | if attributes != nil { |
| | | //将该header结构信息重新加入到superArray中去 |
| | | superArray?.append(attributes!) |
| | | } |
| | | }) |
| | | //遍历superArray,改变header结构信息中的参数,使它可以在当前section还没完全离开屏幕的时候一直显示 |
| | | for attributes:UICollectionViewLayoutAttributes in superArray! { |
| | | //如果当前item是header |
| | | if attributes.representedElementKind == UICollectionView.elementKindSectionHeader { |
| | | //得到当前header所在分区的cell的数量 |
| | | let numberOfItemsInSection=self.collectionView!.numberOfItems(inSection: attributes.indexPath.section) |
| | | //取到当前section中第一个item的indexPath |
| | | let firstItemIndexPath = NSIndexPath(item: 0, section: attributes.indexPath.section) |
| | | //得到最后一个item的indexPath |
| | | let lastItemIndexPath = NSIndexPath(item: max(0, numberOfItemsInSection-1), section: attributes.indexPath.section) |
| | | //得到第一个item和最后一个item的结构信息 |
| | | var firstItemAttributes, lastItemAttributes:UICollectionViewLayoutAttributes |
| | | if numberOfItemsInSection>0 { |
| | | //cell有值,则获取第一个cell和最后一个cell的结构信息 |
| | | firstItemAttributes=self.layoutAttributesForItem(at: firstItemIndexPath as IndexPath)! |
| | | lastItemAttributes=self.layoutAttributesForItem(at: lastItemIndexPath as IndexPath)! |
| | | }else{ |
| | | //cell没值,就新建一个UICollectionViewLayoutAttributes |
| | | firstItemAttributes=UICollectionViewLayoutAttributes() |
| | | //然后模拟出在当前分区中的唯一一个cell,cell在header的下面,高度为0,还与header隔着可能存在的sectionInset的top |
| | | let y=attributes.frame.maxY + sectionInset.top |
| | | firstItemAttributes.frame=CGRect(x: 0, y: y, width: 0, height: 0) |
| | | //因为只有一个cell,所以最后一个cell等于第一个cell |
| | | lastItemAttributes=firstItemAttributes; |
| | | } |
| | | //获取当前header的frame |
| | | var rect=attributes.frame; |
| | | //当前的滑动距离 + 因为导航栏产生的偏移量,默认为0(如果app需求不同,需自己设置) |
| | | let offset=(self.collectionView?.contentOffset.y)! + naviHeight |
| | | //第一个cell的y值 - 当前header的高度 - 可能存在的sectionInset的top |
| | | let headerY=firstItemAttributes.frame.origin.y-rect.size.height-sectionInset.top |
| | | //哪个大取哪个,保证header悬停 |
| | | //针对当前header基本上都是offset更加大,针对下一个header则会是headerY大,各自处理 |
| | | let maxY=max(offset, headerY) |
| | | //最后一个cell的y值 + 最后一个cell的高度 + 可能存在的sectionInset的bottom - 当前header的高度 |
| | | //当当前section的footer或者下一个section的header接触到当前header的底部,计算出的headerMissingY即为有效值 |
| | | let headerMissingY = lastItemAttributes.frame.maxY + sectionInset.bottom - rect.size.height; |
| | | //给rect的y赋新值,因为在最后消失的临界点要跟谁消失,所以取小 |
| | | rect.origin.y=min(maxY, headerMissingY) |
| | | //给header的结构信息的frame重新赋值 |
| | | attributes.frame=rect |
| | | //如果按照正常情况下,header离开屏幕被系统回收,而header的层次关系又与cell相等,如果不去理会,会出现cell在header上面的情况 |
| | | //通过打印可以知道cell的层次关系zIndex数值为0,我们可以将header的zIndex设置成1,如果不放心,也可以将它设置成非常大,这里随便填了个7 |
| | | attributes.zIndex=7 |
| | | |
| | | } |
| | | } |
| | | return superArray |
| | | } |
| | | //return true;表示一旦滑动就实时调用上面这个layoutAttributesForElementsInRect:方法 |
| | | override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool { |
| | | return true |
| | | } |
| | | } |
New file |
| | |
| | | // |
| | | // StoreTransaction.swift |
| | | // ExplorerProject |
| | | // |
| | | // Created by 无故事王国 on 2024/4/1. |
| | | // Copyright © 2024 younger_times. All rights reserved. |
| | | // |
| | | |
| | | import SwiftyStoreKit |
| | | import StoreKit |
| | | import HandyJSON |
| | | |
| | | struct PurchaseModel:HandyJSON{ |
| | | var environment: String? |
| | | var receipt:PurchaseReceiptModel? |
| | | var status: Int = 0 |
| | | } |
| | | |
| | | struct PurchaseReceiptModel:HandyJSON{ |
| | | var adam_id: Int = 0 |
| | | var app_item_id: Int = 0 |
| | | var application_version: Int = 0 |
| | | var bundle_id: String? |
| | | var download_id: Int = 0 |
| | | var in_app = [PurchageInAppModel]() |
| | | var original_application_version: String? |
| | | var original_purchase_date: String? |
| | | var original_purchase_date_ms: Int = 0 |
| | | var original_purchase_date_pst: String? |
| | | var receipt_creation_date: String? |
| | | var receipt_creation_date_ms: Int = 0 |
| | | var receipt_creation_date_pst: String? |
| | | var receipt_type: String? |
| | | var request_date: String? |
| | | var request_date_ms: Int = 0 |
| | | var request_date_pst: String? |
| | | var version_external_identifier: Int = 0 |
| | | } |
| | | |
| | | struct PurchageInAppModel:HandyJSON{ |
| | | |
| | | } |
| | | |
| | | struct PurchaseResultModel:HandyJSON{ |
| | | var environment: String? |
| | | var receipt: PurchaseReceipt? |
| | | var status: Int = 0 |
| | | } |
| | | |
| | | struct PurchaseReceipt:HandyJSON{ |
| | | var adam_id: Int = 0 |
| | | var app_item_id: Int = 0 |
| | | var application_version: String? |
| | | var bundle_id: String? |
| | | var download_id: Int = 0 |
| | | var in_app = [PurchaseInAPP]() |
| | | var original_application_version: String? |
| | | var original_purchase_date: String? |
| | | var original_purchase_date_ms: String? |
| | | var original_purchase_date_pst: String? |
| | | var receipt_creation_date: String? |
| | | var receipt_creation_date_ms: String? |
| | | var receipt_creation_date_pst: String? |
| | | var receipt_type: String? |
| | | var request_date: String? |
| | | var request_date_ms: String? |
| | | var request_date_pst: String? |
| | | var version_external_identifier: Int = 0 |
| | | } |
| | | |
| | | struct PurchaseInAPP:HandyJSON{ |
| | | var in_app_ownership_type: String? |
| | | var is_trial_period: String? |
| | | var original_purchase_date: String? |
| | | var original_purchase_date_ms: String? |
| | | var original_purchase_date_pst: String? |
| | | var original_transaction_id: String? |
| | | var product_id: String? |
| | | var purchase_date: String? |
| | | var purchase_date_ms: String? |
| | | var purchase_date_pst: String? |
| | | var quantity: String? |
| | | var transaction_id: String? |
| | | |
| | | } |
| | | |
| | | class InPurchaseManager:NSObject{ |
| | | |
| | | private static var _sharedInstance: InPurchaseManager! |
| | | private var productList = Set<String>() |
| | | private(set) var products = Set<SKProduct>() |
| | | |
| | | @discardableResult |
| | | public class func instance() -> InPurchaseManager { |
| | | guard let instance = _sharedInstance else { |
| | | _sharedInstance = InPurchaseManager() |
| | | return _sharedInstance! |
| | | } |
| | | return instance |
| | | } |
| | | |
| | | func setProductList(_ list:Set<String>,clouse:@escaping (Set<SKProduct>)->Void){ |
| | | productList = list |
| | | |
| | | SwiftyStoreKit.retrieveProductsInfo(list) { result in |
| | | if result.retrievedProducts.count > 0 { |
| | | InPurchaseManager._sharedInstance.products = result.retrievedProducts |
| | | clouse(result.retrievedProducts) |
| | | } |
| | | } |
| | | } |
| | | |
| | | func getIPAPrice(_ price:Int,clouse:@escaping (SKProduct)->Void){ |
| | | var ipaId = "" |
| | | switch price { |
| | | case 98: ipaId = "com.jkfitness.a.price.1" |
| | | case 298:ipaId = "com.jkfitness.a.price.2" |
| | | case 488:ipaId = "com.jkfitness.a.price.3" |
| | | case 698:ipaId = "com.jkfitness.a.price.4" |
| | | case 998:ipaId = "com.jkfitness.a.price.5" |
| | | default:break |
| | | } |
| | | |
| | | var productIds = Set<String>() |
| | | productIds.insert(ipaId) |
| | | |
| | | InPurchaseManager.instance().setProductList(productIds) {products in |
| | | if let product = products.first{ |
| | | clouse(product) |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | func dismiss(){ |
| | | InPurchaseManager._sharedInstance = nil |
| | | } |
| | | |
| | | /// 购买 |
| | | /// - Parameters: |
| | | /// - ID: ID值 |
| | | /// - quantity: 购买数量 |
| | | /// - applicationUsername: 购买用户名的唯一标识 |
| | | class func purchaseProduct(ID:String,quantity:Int = 1,applicationUsername:String, completion: @escaping ( PurchaseResultModel) -> Void,errorClouse:@escaping (Error)->Void){ |
| | | var purcahseProduct:SKProduct? |
| | | for product in _sharedInstance.products { |
| | | if product.productIdentifier == ID{ |
| | | purcahseProduct = product;break |
| | | } |
| | | } |
| | | |
| | | guard let product = purcahseProduct else {return} |
| | | var inSanbox:Bool = false |
| | | |
| | | #if DEBUG |
| | | inSanbox = true |
| | | #endif |
| | | |
| | | SwiftyStoreKit.completeTransactions { purchases in |
| | | if let product = purchases.first{ |
| | | switch product.transaction.transactionState { |
| | | case .purchased: |
| | | alertSuccess(msg: "完成购买") |
| | | case .purchasing: |
| | | showHUD("购买中") |
| | | case .failed: |
| | | alertError(msg: "购买失败") |
| | | case .restored: |
| | | alertSuccess(msg: "恢复购买") |
| | | default:break |
| | | } |
| | | } |
| | | } |
| | | |
| | | SwiftyStoreKit.purchaseProduct(product, quantity: quantity, atomically: true, applicationUsername: applicationUsername, simulatesAskToBuyInSandbox: false, paymentDiscount: nil) { result in |
| | | switch result { |
| | | case .success(let purchase): |
| | | var type:AppleReceiptValidator.VerifyReceiptURLType = .production |
| | | if inSanbox{ |
| | | type = .sandbox |
| | | } |
| | | |
| | | var recepit = AppleReceiptValidator(service: type, sharedSecret: nil) |
| | | SwiftyStoreKit.verifyReceipt(using: recepit) { result in |
| | | switch result { |
| | | case .success(let receipt): |
| | | if let model = PurchaseResultModel.deserialize(from: receipt){ |
| | | completion(model) |
| | | } |
| | | break |
| | | case .error(let error): |
| | | errorClouse(error) |
| | | // print(error.localizedDescription) |
| | | } |
| | | } |
| | | case .error(let error): |
| | | // print(error.localizedDescription) |
| | | errorClouse(error) |
| | | } |
| | | } |
| | | } |
| | | |
| | | /// 恢复购买 |
| | | class func resotrePurchase(applicationUsername:String, completion: @escaping ( PurchaseResultModel) -> Void,errorClouse:@escaping (Error)->Void){ |
| | | |
| | | SwiftyStoreKit.completeTransactions { purchases in |
| | | if let product = purchases.first{ |
| | | switch product.transaction.transactionState { |
| | | case .purchased: |
| | | alertSuccess(msg: "完成购买") |
| | | case .purchasing: |
| | | showHUD("购买中") |
| | | case .failed: |
| | | alertError(msg: "购买失败") |
| | | case .restored: |
| | | alertSuccess(msg: "恢复购买") |
| | | default:break |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | SwiftyStoreKit.restorePurchases(atomically: true, applicationUsername: applicationUsername) { result in |
| | | if result.restoreFailedPurchases.count > 0 { |
| | | //恢复失败 |
| | | print("restore Failed:\(result.restoredPurchases)") |
| | | }else if result.restoredPurchases.count > 0 { |
| | | print("restore Success") |
| | | var inSanbox:Bool = false |
| | | |
| | | #if DEBUG |
| | | inSanbox = true |
| | | #endif |
| | | var type:AppleReceiptValidator.VerifyReceiptURLType = .production |
| | | if inSanbox{ |
| | | type = .sandbox |
| | | } |
| | | let recepit = AppleReceiptValidator(service: type, sharedSecret: nil) |
| | | SwiftyStoreKit.verifyReceipt(using: recepit) { result in |
| | | switch result { |
| | | case .success(let receipt): |
| | | if let model = PurchaseResultModel.deserialize(from: receipt){ |
| | | completion(model) |
| | | } |
| | | break |
| | | case .error(let error): |
| | | errorClouse(error) |
| | | } |
| | | } |
| | | }else{ |
| | | print("Nothing to Restore") |
| | | } |
| | | } |
| | | } |
| | | |
| | | //获取APP 首次安装时间 |
| | | func test1(){ |
| | | |
| | | let queue = DispatchQueue(label: "inapppurchasequeue") |
| | | queue.async { |
| | | let receiptURL = Bundle.main.appStoreReceiptURL |
| | | guard receiptURL?.path != nil else { return } |
| | | do { |
| | | let receiptData = try Data(contentsOf: receiptURL!, options: .alwaysMapped) |
| | | let base64EncodedReceipt = receiptData.base64EncodedString(options: []) |
| | | var verifyReceipt:String = AppleReceiptValidator.VerifyReceiptURLType.sandbox.rawValue |
| | | #if !DEBUG |
| | | verifyReceipt = AppleReceiptValidator.VerifyReceiptURLType.production.rawValue |
| | | #endif |
| | | let purchaseURL = URL(string: verifyReceipt)! |
| | | |
| | | var request = URLRequest(url: purchaseURL) |
| | | request.httpMethod = "POST" |
| | | request.setValue("application/json", forHTTPHeaderField: "Content-Type") |
| | | |
| | | let jsonBody: [String: Any] = [ |
| | | "receipt-data": base64EncodedReceipt, |
| | | "password": ShareAppleKey // 你的共享密钥 |
| | | ] |
| | | |
| | | let jsonData = try JSONSerialization.data(withJSONObject: jsonBody, options: []) |
| | | request.httpBody = jsonData |
| | | |
| | | let session = URLSession.shared |
| | | let task = session.dataTask(with: request) { (data, response, error) in |
| | | if let error = error {return} |
| | | guard let data = data else { return } |
| | | do { |
| | | if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] { |
| | | print(json) |
| | | if let purchageModel = PurchaseModel.deserialize(from: json),purchageModel.status == 0{ |
| | | |
| | | } |
| | | } |
| | | } catch { |
| | | print("JSON processing failed: \(error)") |
| | | } |
| | | } |
| | | task.resume() |
| | | } catch { |
| | | print("Error reading receipt data: \(error)") |
| | | } |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | { |
| | | "appPolicies" : { |
| | | "eula" : "", |
| | | "policies" : [ |
| | | { |
| | | "locale" : "en_US", |
| | | "policyText" : "", |
| | | "policyURL" : "" |
| | | } |
| | | ] |
| | | }, |
| | | "identifier" : "3D29D5F7", |
| | | "nonRenewingSubscriptions" : [ |
| | | { |
| | | "displayPrice" : "299", |
| | | "familyShareable" : false, |
| | | "internalID" : "7BDE4968", |
| | | "localizations" : [ |
| | | { |
| | | "description" : "购买一个月会员", |
| | | "displayName" : "一个月会员", |
| | | "locale" : "zh_CN" |
| | | } |
| | | ], |
| | | "productID" : "com.XQMuse.VIP.month.0", |
| | | "referenceName" : "购买一个月会员", |
| | | "type" : "NonRenewingSubscription" |
| | | }, |
| | | { |
| | | "displayPrice" : "499", |
| | | "familyShareable" : false, |
| | | "internalID" : "DDDE321B", |
| | | "localizations" : [ |
| | | { |
| | | "description" : "购买6个月会员", |
| | | "displayName" : "半年会员", |
| | | "locale" : "zh_CN" |
| | | } |
| | | ], |
| | | "productID" : "com.XQMuse.VIP.semester.0", |
| | | "referenceName" : "购买半年会员", |
| | | "type" : "NonRenewingSubscription" |
| | | }, |
| | | { |
| | | "displayPrice" : "499", |
| | | "familyShareable" : false, |
| | | "internalID" : "436E2DBE", |
| | | "localizations" : [ |
| | | { |
| | | "description" : "购买12个月会员", |
| | | "displayName" : "年度会员", |
| | | "locale" : "zh_CN" |
| | | } |
| | | ], |
| | | "productID" : "com.XQMuse.VIP.year.0", |
| | | "referenceName" : "购买年度会员", |
| | | "type" : "NonRenewingSubscription" |
| | | } |
| | | ], |
| | | "products" : [ |
| | | { |
| | | "displayPrice" : "0.99", |
| | | "familyShareable" : false, |
| | | "internalID" : "521CE106", |
| | | "localizations" : [ |
| | | { |
| | | "description" : "购买10颗疗愈币", |
| | | "displayName" : "10币", |
| | | "locale" : "zh_CN" |
| | | } |
| | | ], |
| | | "productID" : "com.XQMuse.p.0", |
| | | "referenceName" : "充值10疗愈币", |
| | | "type" : "Consumable" |
| | | }, |
| | | { |
| | | "displayPrice" : "1.99", |
| | | "familyShareable" : false, |
| | | "internalID" : "E7DC523B", |
| | | "localizations" : [ |
| | | { |
| | | "description" : "购买20颗疗愈币", |
| | | "displayName" : "20币", |
| | | "locale" : "zh_CN" |
| | | } |
| | | ], |
| | | "productID" : "com.XQMuse.p.1", |
| | | "referenceName" : "充值20疗愈币", |
| | | "type" : "Consumable" |
| | | }, |
| | | { |
| | | "displayPrice" : "2.99", |
| | | "familyShareable" : false, |
| | | "internalID" : "6AD670BC", |
| | | "localizations" : [ |
| | | { |
| | | "description" : "购买50颗疗愈币", |
| | | "displayName" : "50币", |
| | | "locale" : "zh_CN" |
| | | } |
| | | ], |
| | | "productID" : "com.XQMuse.p.2", |
| | | "referenceName" : "充值50疗愈币", |
| | | "type" : "Consumable" |
| | | }, |
| | | { |
| | | "displayPrice" : "3.99", |
| | | "familyShareable" : false, |
| | | "internalID" : "C8E195D0", |
| | | "localizations" : [ |
| | | { |
| | | "description" : "购买100颗疗愈币", |
| | | "displayName" : "100币", |
| | | "locale" : "zh_CN" |
| | | } |
| | | ], |
| | | "productID" : "com.XQMuse.p.3", |
| | | "referenceName" : "充值100疗愈币", |
| | | "type" : "Consumable" |
| | | } |
| | | ], |
| | | "settings" : { |
| | | "_billingGracePeriodEnabled" : true, |
| | | "_failTransactionsEnabled" : false, |
| | | "_locale" : "zh_CN", |
| | | "_storefront" : "CHN", |
| | | "_storeKitErrors" : [ |
| | | { |
| | | "current" : null, |
| | | "enabled" : false, |
| | | "name" : "Load Products" |
| | | }, |
| | | { |
| | | "current" : null, |
| | | "enabled" : false, |
| | | "name" : "Purchase" |
| | | }, |
| | | { |
| | | "current" : null, |
| | | "enabled" : false, |
| | | "name" : "Verification" |
| | | }, |
| | | { |
| | | "current" : { |
| | | "index" : 2, |
| | | "type" : "generic" |
| | | }, |
| | | "enabled" : false, |
| | | "name" : "App Store Sync" |
| | | }, |
| | | { |
| | | "current" : null, |
| | | "enabled" : false, |
| | | "name" : "Subscription Status" |
| | | }, |
| | | { |
| | | "current" : { |
| | | "index" : 3, |
| | | "type" : "generic" |
| | | }, |
| | | "enabled" : false, |
| | | "name" : "App Transaction" |
| | | }, |
| | | { |
| | | "current" : null, |
| | | "enabled" : false, |
| | | "name" : "Manage Subscriptions Sheet" |
| | | }, |
| | | { |
| | | "current" : null, |
| | | "enabled" : false, |
| | | "name" : "Refund Request Sheet" |
| | | }, |
| | | { |
| | | "current" : null, |
| | | "enabled" : false, |
| | | "name" : "Offer Code Redeem Sheet" |
| | | } |
| | | ] |
| | | }, |
| | | "subscriptionGroups" : [ |
| | | { |
| | | "id" : "1B73E9E9", |
| | | "localizations" : [ |
| | | |
| | | ], |
| | | "name" : "Years", |
| | | "subscriptions" : [ |
| | | { |
| | | "adHocOffers" : [ |
| | | { |
| | | "internalID" : "B4ECD233", |
| | | "offerID" : "LAJ234QMZ5801AAC", |
| | | "paymentMode" : "free", |
| | | "referenceName" : "促销码", |
| | | "subscriptionPeriod" : "P1Y" |
| | | } |
| | | ], |
| | | "codeOffers" : [ |
| | | { |
| | | "displayPrice" : "200", |
| | | "eligibility" : [ |
| | | "existing", |
| | | "expired", |
| | | "new" |
| | | ], |
| | | "internalID" : "F62AF748", |
| | | "isStackable" : true, |
| | | "paymentMode" : "payUpFront", |
| | | "referenceName" : "促销", |
| | | "subscriptionPeriod" : "P6M" |
| | | } |
| | | ], |
| | | "displayPrice" : "149", |
| | | "familyShareable" : false, |
| | | "groupNumber" : 1, |
| | | "internalID" : "D8314451", |
| | | "introductoryOffer" : { |
| | | "displayPrice" : "0.99", |
| | | "internalID" : "89D5DFC5", |
| | | "paymentMode" : "free", |
| | | "subscriptionPeriod" : "P3D" |
| | | }, |
| | | "localizations" : [ |
| | | { |
| | | "description" : "包年", |
| | | "displayName" : "包年年度会员", |
| | | "locale" : "zh_CN" |
| | | } |
| | | ], |
| | | "productID" : "com.XQMuse.VIP.year.renewing.0", |
| | | "recurringSubscriptionPeriod" : "P1Y", |
| | | "referenceName" : "购买年度会员(持续订阅)", |
| | | "subscriptionGroupID" : "1B73E9E9", |
| | | "type" : "RecurringSubscription", |
| | | "winbackOffers" : [ |
| | | |
| | | ] |
| | | } |
| | | ] |
| | | } |
| | | ], |
| | | "version" : { |
| | | "major" : 4, |
| | | "minor" : 0 |
| | | } |
| | | } |
New file |
| | |
| | | // |
| | | // WeChatTools.swift |
| | | // WanPai |
| | | // |
| | | // Created by 无故事王国 on 2023/9/26. |
| | | // |
| | | |
| | | import Foundation |
| | | import HandyJSON |
| | | |
| | | typealias WeachatClosure = (WechatModel?)->(Void) |
| | | typealias WechatUserClosure = (WechatUserInfoModel?)->(Void) |
| | | |
| | | struct WechatModel:HandyJSON{ |
| | | var access_token = "" |
| | | var expires_in = 0 |
| | | var openid = "" |
| | | var refresh_token = "" |
| | | var scope = "" |
| | | var unionid = "" |
| | | } |
| | | |
| | | struct WechatUserInfoModel:HandyJSON{ |
| | | var openid = "" |
| | | var nickname = "" |
| | | var sex = 1 |
| | | var province = "" |
| | | var city = "" |
| | | var country = "" |
| | | var headimgurl = "" |
| | | var privilege = "" |
| | | var unionid = "" |
| | | } |
| | | |
| | | class WeChatTools{ |
| | | |
| | | static func register(appid:String,link:String){ |
| | | WXApi.registerApp(appid, universalLink: link) |
| | | } |
| | | |
| | | /// 授权登录 |
| | | static func sendAuthRequest(){ |
| | | let sendAuthReq = SendAuthReq() |
| | | sendAuthReq.scope = "snsapi_userinfo" |
| | | sendAuthReq.state = "XQMuse_iOS" |
| | | WXApi.send(sendAuthReq) |
| | | } |
| | | |
| | | /// 完成授权登录,获取token |
| | | static func getAccessToken(_ resp:SendAuthResp, loginInfo:WeachatClosure?){ |
| | | guard resp.code != nil else { |
| | | return |
| | | } |
| | | let url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=\(WeChatAPPID)&secret=\(WeChatSecrect)&code=\(resp.code!)&grant_type=authorization_code" |
| | | let Url = URL(string: url) |
| | | let session = URLSession.shared |
| | | let task = session.dataTask(with: Url!) { (data, response, error) in |
| | | if error != nil{ |
| | | return |
| | | } |
| | | do{ |
| | | if let dataAsJSON = try JSONSerialization.jsonObject(with: data!) as? Dictionary<String, Any>{ |
| | | let model = WechatModel.deserialize(from: dataAsJSON) |
| | | loginInfo?(model) |
| | | }else{ |
| | | loginInfo?(nil) |
| | | } |
| | | }catch{ |
| | | loginInfo?(nil) |
| | | } |
| | | } |
| | | task.resume() |
| | | } |
| | | |
| | | /// 获取用资料 |
| | | static func getUserInfo(access_token:String,openId:String,userInfo:WechatUserClosure?){ |
| | | guard !access_token.isEmpty else { |
| | | return |
| | | } |
| | | |
| | | guard !openId.isEmpty else { |
| | | return |
| | | } |
| | | |
| | | let url = "https://api.weixin.qq.com/sns/userinfo?access_token=\(access_token)&openid=\(openId)" |
| | | let Url = URL(string: url) |
| | | let session = URLSession.shared |
| | | let task = session.dataTask(with: Url!) { (data, response, error) in |
| | | if error != nil{ |
| | | return |
| | | } |
| | | do{ |
| | | if let dataAsJSON = try JSONSerialization.jsonObject(with: data!) as? Dictionary<String, Any>{ |
| | | let model = WechatUserInfoModel.deserialize(from: dataAsJSON) |
| | | userInfo?(model) |
| | | }else{ |
| | | userInfo?(nil) |
| | | } |
| | | }catch{ |
| | | userInfo?(nil) |
| | | } |
| | | } |
| | | task.resume() |
| | | } |
| | | |
| | | /// 分享文本 |
| | | static func shareText(_ text:String,scene:WXScene = WXSceneSession){ |
| | | let req = SendMessageToWXReq() |
| | | req.bText = true |
| | | req.text = text |
| | | req.scene = Int32(scene.rawValue) |
| | | WXApi.send(req) |
| | | } |
| | | |
| | | /// 分享图片 |
| | | static func sharePic(_ img:UIImage,thumb:UIImage,scale:CGFloat = 0.6,scene:WXScene = WXSceneTimeline){ |
| | | |
| | | let imageObject = WXImageObject() |
| | | imageObject.imageData = img.jpegData(compressionQuality: scale)! |
| | | |
| | | let mediaMessage = WXMediaMessage() |
| | | mediaMessage.thumbData = thumb.jpegData(compressionQuality: scale) |
| | | mediaMessage.mediaObject = imageObject |
| | | |
| | | let req = SendMessageToWXReq() |
| | | req.bText = false |
| | | req.message = mediaMessage |
| | | req.scene = Int32(scene.rawValue) |
| | | WXApi.send(req) |
| | | } |
| | | |
| | | /// 分享音乐 |
| | | static func shareMusic(_ musicUrl:String,musicLowBandUrl:String,title:String,desc:String,thumb:UIImage,scene:WXScene = WXSceneSession){ |
| | | let musicObject = WXMusicObject() |
| | | musicObject.musicUrl = musicUrl |
| | | musicObject.musicLowBandUrl = musicLowBandUrl |
| | | |
| | | let mediaMessage = WXMediaMessage() |
| | | mediaMessage.title = title |
| | | mediaMessage.description = desc |
| | | mediaMessage.setThumbImage(thumb) |
| | | mediaMessage.mediaObject = musicObject |
| | | |
| | | let req = SendMessageToWXReq() |
| | | req.bText = false |
| | | req.message = mediaMessage |
| | | req.scene = Int32(scene.rawValue) |
| | | WXApi.send(req) |
| | | } |
| | | |
| | | /// 分享音乐 |
| | | static func shareMusic(_ musicData:String,musicLowBandData:String,title:String,desc:String,thumb:UIImage,scene:WXScene = WXSceneSession){ |
| | | let musicObject = WXMusicObject() |
| | | musicObject.musicDataUrl = musicData |
| | | musicObject.musicLowBandUrl = musicLowBandData |
| | | |
| | | let mediaMessage = WXMediaMessage() |
| | | mediaMessage.title = title |
| | | mediaMessage.description = desc |
| | | mediaMessage.setThumbImage(thumb) |
| | | mediaMessage.mediaObject = musicObject |
| | | |
| | | let req = SendMessageToWXReq() |
| | | req.bText = false |
| | | req.message = mediaMessage |
| | | req.scene = Int32(scene.rawValue) |
| | | WXApi.send(req) |
| | | } |
| | | |
| | | static func shareUrl(_ url:String,title:String,desc:String,thumb:UIImage,scene:WXScene = WXSceneSession){ |
| | | |
| | | let webpageObject = WXWebpageObject() |
| | | webpageObject.webpageUrl = url |
| | | |
| | | let mediaMessage = WXMediaMessage() |
| | | mediaMessage.title = title |
| | | mediaMessage.description = desc |
| | | mediaMessage.setThumbImage(thumb) |
| | | mediaMessage.mediaObject = webpageObject |
| | | |
| | | let req = SendMessageToWXReq() |
| | | req.bText = false |
| | | req.message = mediaMessage |
| | | req.scene = Int32(scene.rawValue) |
| | | WXApi.send(req) |
| | | } |
| | | |
| | | static func shareVideo(_ url:String,videoLowBandUrl:String,title:String,desc:String,thumb:UIImage, scene:WXScene = WXSceneSession){ |
| | | let videoObject = WXVideoObject() |
| | | videoObject.videoUrl = url |
| | | videoObject.videoLowBandUrl = videoLowBandUrl |
| | | |
| | | let mediaMessage = WXMediaMessage() |
| | | mediaMessage.title = title |
| | | mediaMessage.description = desc |
| | | mediaMessage.setThumbImage(thumb) |
| | | mediaMessage.mediaObject = videoObject |
| | | |
| | | let req = SendMessageToWXReq() |
| | | req.bText = false |
| | | req.message = mediaMessage |
| | | req.scene = Int32(scene.rawValue) |
| | | WXApi.send(req) |
| | | } |
| | | } |
New file |
| | |
| | | // |
| | | // XQMuse-Bridging-Header.h |
| | | // XQMuse |
| | | // |
| | | // Created by 无故事王国 on 2024/10/17. |
| | | // |
| | | |
| | | #ifndef XQMuse_Bridging_Header_h |
| | | #define XQMuse_Bridging_Header_h |
| | | #import "WXApi.h" |
| | | |
| | | #endif /* XQMuse_Bridging_Header_h */ |
| | |
| | | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
| | | <plist version="1.0"> |
| | | <dict> |
| | | <key>CFBundleAllowMixedLocalizations</key> |
| | | <true/> |
| | | <key>CFBundleURLTypes</key> |
| | | <array> |
| | | <dict> |
| | | <key>CFBundleTypeRole</key> |
| | | <string>Editor</string> |
| | | <key>CFBundleURLSchemes</key> |
| | | <array> |
| | | <string>wx4b9c1d814c2902a3</string> |
| | | </array> |
| | | </dict> |
| | | </array> |
| | | <key>LSApplicationQueriesSchemes</key> |
| | | <array> |
| | | <string>weixin</string> |
| | | <string>weixinULAPI</string> |
| | | <string>weixinURLParamsAPI</string> |
| | | </array> |
| | | <key>Localization native development region</key> |
| | | <string>China</string> |
| | | <key>NSAppTransportSecurity</key> |
| | | <dict> |
| | | <key>NSAllowsArbitraryLoads</key> |
| | |
| | | |
| | | func setBanners(_ items:[CommonBannerModel]){ |
| | | bannerModels = items |
| | | view_bannerContentView.setItems(items: items) |
| | | view_bannerContentView.setItems(items: items) { m in |
| | | if let id = m.courseId?.int{ |
| | | JQ_currentNavigationController().pushViewController(CourseDetialVC(courseId: id)) |
| | | } |
| | | } |
| | | } |
| | | |
| | | func clickAtClouse(_ clouse:@escaping (Int)->Void){ |
| | |
| | | |
| | | |
| | | @objc func searchAction(){ |
| | | let vc = SearchVC() |
| | | let vc = SearchVC(serchType: .course) |
| | | push(vc: vc) |
| | | } |
| | | |
| | |
| | | class CourseDetialVC: BaseVC { |
| | | |
| | | private var tableView:UITableView? |
| | | private var collect_bitem:UIBarButtonItem! |
| | | private let studyBtn = QMUIButton(type: .custom) |
| | | private var headerView = CourseDetailHeaderView.jq_loadNibView() |
| | | private var barStyle:UIStatusBarStyle = .lightContent |
| | |
| | | self.tableView!.tableHeaderView = self.headerView |
| | | } |
| | | |
| | | setFootView() |
| | | collect_bitem = UIBarButtonItem(image: UIImage(named: "btn_collect"), style: .plain, target: self, action: #selector(collectionAction)) |
| | | collect_bitem.tintColor = .white |
| | | let share_bitem = UIBarButtonItem(image: UIImage(named: "btn_share"), style: .plain, target: self, action: #selector(shareAction)) |
| | | share_bitem.tintColor = .white |
| | | share_bitem.imageInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 15) |
| | | navigationItem.rightBarButtonItems = [share_bitem,collect_bitem] |
| | | } |
| | | |
| | | private func getData(){ |
| | |
| | | self.section1TCell.setItems(m) |
| | | self.section2TCell.setItems(m.list2) |
| | | |
| | | if m.isBuy != .yes{ |
| | | //是否需要购买 |
| | | var needPayment:Bool = true |
| | | switch m.chargeType{ |
| | | case .free:needPayment = false |
| | | case .payment:needPayment = !(m.isBuy == .yes) |
| | | case .vipFree:needPayment = !(UserViewModel.getAvatarInfo().isVip == .yes) |
| | | } |
| | | |
| | | if needPayment{ |
| | | let attribute = AttributedStringbuilder.build().add(string: " 疗愈币", withFont: .systemFont(ofSize: 12,weight: .bold), withColor: UIColor(hexString: "#F6F6F6")!).add(string: "\(m.generalPrice.jq_formatFloat)", withFont: .systemFont(ofSize: 21.71, weight: .bold), withColor: UIColor(hexString: "#F6F6F6")!).add(string: " 立即购买 ", withFont: .systemFont(ofSize: 16, weight: .bold), withColor: UIColor(hexString: "#F6F6F6")!).mutableAttributedString |
| | | self.studyBtn.setAttributedTitle(attribute, for: .normal) |
| | | } |
| | |
| | | self.pageMenu.setItems(["简介"], selectedItemIndex: 0) |
| | | } |
| | | self.tableView?.reloadData() |
| | | self.setFootView() |
| | | } |
| | | }).disposed(by: disposeBag) |
| | | } |
| | |
| | | make.height.equalTo(84) |
| | | } |
| | | |
| | | if courseDetailModel?.chargeType == .payment{ |
| | | let giftBtn = QMUIButton(type: .custom) |
| | | giftBtn.imagePosition = .left |
| | | giftBtn.spacingBetweenImageAndTitle = 7.5 |
| | |
| | | make.left.equalTo(26) |
| | | make.top.equalTo(26.5) |
| | | } |
| | | } |
| | | |
| | | studyBtn.setTitleColor(UIColor.white, for: .normal) |
| | | studyBtn.setTitle(" 立即学习 ", for: .normal) |
| | |
| | | footView.addSubview(studyBtn) |
| | | studyBtn.snp.makeConstraints { make in |
| | | make.right.equalTo(-20) |
| | | make.centerY.equalTo(giftBtn) |
| | | make.top.equalTo(22) |
| | | make.height.equalTo(34) |
| | | } |
| | | } |
| | |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | @objc func collectionAction(){ |
| | | Services.meditationFavorite(id: courseId).subscribe(onNext: {data in |
| | | self.courseDetailModel?.isCollect.troggle() |
| | | if self.courseDetailModel?.isCollect == .yes{ |
| | | alertSuccess(msg: "收藏成功") |
| | | self.collect_bitem.image = UIImage(named: "btn_collect_1_s") |
| | | self.collect_bitem.tintColor = UIColor(hexString: "fe5b60") |
| | | }else{ |
| | | alertSuccess(msg: "已取消收藏") |
| | | self.collect_bitem.image = UIImage(named: "btn_collect") |
| | | self.collect_bitem.tintColor = .white |
| | | } |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | @objc func shareAction(){ |
| | | ShareView.show() |
| | | } |
| | | |
| | | @objc func handleAction(_ btn:QMUIButton){ |
| | | |
| | | if let m = courseDetailModel{ |
| | | if m.chargeType == .free || (m.chargeType == .vipFree && UserViewModel.getAvatarInfo().isVip == .yes) || (m.chargeType == .payment && m.isBuy == .yes){ |
| | | guard m.list.count != 0 else { |
| | | alertError(msg: "课程目录异常");return |
| | | } |
| | | let vc = CourseDetialVideoVC(items: m.list, selectIndex: IndexPath(row: 0, section: 0)) |
| | | push(vc: vc);return |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | let offSetY = scrollView.contentOffset.y + CGRectGetHeight(scrollView.frame) / 2; |
| | | |
| | | if let currentIndex = tableView?.indexPathForRow(at: CGPoint(x: 0, y: offSetY)){ |
| | | print(scrollView.isDragging) |
| | | |
| | | if !isAnimationing{ |
| | | if currentShowIndex != currentIndex{ |
| | |
| | | title = "课程详情" |
| | | |
| | | videoView = VideoView(url: items[selectIndex.row].videoUrl) |
| | | videoView?.player.play() |
| | | view_bg_video.addSubview(videoView!) |
| | | videoView!.snp.makeConstraints { make in |
| | | make.edges.equalToSuperview() |
| | |
| | | |
| | | class CourseVCOfficalViewModel:RefreshInnerModel<CourseModel>{ |
| | | var cateId = BehaviorRelay<Int?>(value: nil) |
| | | var search = BehaviorRelay<String?>(value: nil) |
| | | override func api() -> (Observable<BaseResponse<BaseResponseList<CourseModel>>>)? { |
| | | return Services.getCoursePageList(page: page) |
| | | return Services.getCoursePageList(page: page,courseTitle: search.value) |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | Services.getCourseBannerList().subscribe(onNext: {data in |
| | | for (index,v) in (data.data ?? []).enumerated(){ |
| | | self.bannerModels.append(CommonBannerModel(index: index, id: v.id, name: v.name, resource:v.imageUrl, mediaType: .imageUrl)) |
| | | self.bannerModels.append(CommonBannerModel(index: index, id: v.id, name: v.name, resource:v.imageUrl, mediaType: .imageUrl,courseId: v.courseId)) |
| | | } |
| | | self.collectionView.reloadData() |
| | | }).disposed(by: disposeBag) |
| | |
| | | @IBOutlet weak var label_title: UILabel! |
| | | @IBOutlet weak var label_subTitle: UILabel! |
| | | @IBOutlet weak var label_num: UILabel! |
| | | @IBOutlet weak var img_isFree: UIImageView! |
| | | |
| | | override func awakeFromNib() { |
| | | super.awakeFromNib() |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> |
| | | <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23094" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> |
| | | <device id="retina6_12" orientation="portrait" appearance="light"/> |
| | | <dependencies> |
| | | <deployment identifier="iOS"/> |
| | | <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/> |
| | | <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23084"/> |
| | | <capability name="Safe area layout guides" minToolsVersion="9.0"/> |
| | | <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> |
| | | </dependencies> |
| | |
| | | <size key="customSize" width="160" height="196"/> |
| | | <connections> |
| | | <outlet property="img_cover" destination="VwD-36-ent" id="93Z-v8-bjM"/> |
| | | <outlet property="img_isFree" destination="C5o-Fs-4Xu" id="eut-gN-uQO"/> |
| | | <outlet property="label_num" destination="Wxc-EY-qwU" id="zxI-Y4-tTv"/> |
| | | <outlet property="label_subTitle" destination="EeQ-hi-VEz" id="U39-7s-GGD"/> |
| | | <outlet property="label_title" destination="6md-5M-Pce" id="j50-e3-otB"/> |
| | |
| | | @IBOutlet weak var label_subTitle: UILabel! |
| | | @IBOutlet weak var label_num: UILabel! |
| | | @IBOutlet weak var cons_maxSubTitle: NSLayoutConstraint! |
| | | @IBOutlet weak var view_price: UIView! |
| | | @IBOutlet weak var label_price: UILabel! |
| | | @IBOutlet weak var image_free: UIImageView! |
| | | |
| | | private var meditationModel:MeditationModel? |
| | | override func awakeFromNib() { |
| | |
| | | visualEffectView.alpha = 0.7 |
| | | view_text_bg.sendSubviewToBack(visualEffectView) |
| | | visualEffectView.layer.masksToBounds = true |
| | | |
| | | view_price.jq_cornerRadius = 12.55 |
| | | } |
| | | |
| | | func setMeditationModel(_ model:MeditationModel){ |
| | |
| | | label_title.text = model.courseTitle |
| | | label_subTitle.text = model.briefIntroduction |
| | | label_num.text = "\(model.count)" |
| | | img_vip.isHidden = model.isVip != .yes |
| | | |
| | | switch model.chargeType { |
| | | case .payment: |
| | | image_free.isHidden = true |
| | | view_price.isHidden = false |
| | | label_price.attributedText = AttributedStringbuilder.build().add(string: "¥", withFont: UIFont(name: "DIN-Bold", size: 7.11) ?? UIFont.systemFont(ofSize: 7, weight: .bold), withColor: .white).add(string: model.generalPrice.jq_formatFloat, withFont: UIFont(name: "DIN-Bold", size: 11.44) ?? .systemFont(ofSize: 11,weight: .bold), withColor: .white).mutableAttributedString |
| | | case .free: |
| | | image_free.isHidden = false |
| | | view_price.isHidden = true |
| | | img_vip.isHidden = true |
| | | case .vipFree: |
| | | image_free.isHidden = true |
| | | view_price.isHidden = true |
| | | img_vip.isHidden = false |
| | | } |
| | | } |
| | | } |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> |
| | | <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23094" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> |
| | | <device id="retina6_12" orientation="portrait" appearance="light"/> |
| | | <dependencies> |
| | | <deployment identifier="iOS"/> |
| | | <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/> |
| | | <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23084"/> |
| | | <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> |
| | | </dependencies> |
| | | <objects> |
| | |
| | | <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_vip" translatesAutoresizingMaskIntoConstraints="NO" id="yBF-fO-fwz"> |
| | | <rect key="frame" x="14.666666666666666" y="7.6666666666666661" width="21.333333333333336" height="21.333333333333336"/> |
| | | </imageView> |
| | | <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="rmi-DQ-cp9"> |
| | | <rect key="frame" x="14.666666666666664" y="7.6666666666666679" width="25" height="25.000000000000004"/> |
| | | <subviews> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="kTL-dA-lNA"> |
| | | <rect key="frame" x="0.0" y="0.0" width="25" height="25"/> |
| | | <fontDescription key="fontDescription" type="system" pointSize="11"/> |
| | | <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> |
| | | <nil key="highlightedColor"/> |
| | | </label> |
| | | </subviews> |
| | | <color key="backgroundColor" red="0.89803921568627454" green="0.71372549019607845" blue="0.39215686274509803" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> |
| | | <constraints> |
| | | <constraint firstAttribute="trailing" secondItem="kTL-dA-lNA" secondAttribute="trailing" id="4rs-Ms-47V"/> |
| | | <constraint firstAttribute="bottom" secondItem="kTL-dA-lNA" secondAttribute="bottom" id="Gk6-tP-QxW"/> |
| | | <constraint firstItem="kTL-dA-lNA" firstAttribute="leading" secondItem="rmi-DQ-cp9" secondAttribute="leading" id="Utr-e1-5lW"/> |
| | | <constraint firstAttribute="width" constant="25.100000000000001" id="j5h-a9-Qj3"/> |
| | | <constraint firstItem="kTL-dA-lNA" firstAttribute="top" secondItem="rmi-DQ-cp9" secondAttribute="top" id="qKa-MB-Ohi"/> |
| | | <constraint firstAttribute="height" constant="25.100000000000001" id="xtT-s6-JWf"/> |
| | | </constraints> |
| | | </view> |
| | | <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_freee" translatesAutoresizingMaskIntoConstraints="NO" id="deT-IZ-PtZ"> |
| | | <rect key="frame" x="8" y="7" width="50" height="18"/> |
| | | </imageView> |
| | | </subviews> |
| | | </view> |
| | | <constraints> |
| | | <constraint firstItem="yBF-fO-fwz" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" constant="7.5" id="136-6N-kY2"/> |
| | | <constraint firstItem="rmi-DQ-cp9" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" constant="14.5" id="7EM-yV-ddi"/> |
| | | <constraint firstAttribute="bottom" secondItem="cCC-0f-GSV" secondAttribute="bottom" id="FP4-wO-vdE"/> |
| | | <constraint firstItem="deT-IZ-PtZ" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" constant="8" id="Gs7-Se-Ivy"/> |
| | | <constraint firstAttribute="trailing" secondItem="Fb9-IV-vVk" secondAttribute="trailing" id="HZP-qu-QnA"/> |
| | | <constraint firstItem="yBF-fO-fwz" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" constant="14.5" id="R10-E8-6fB"/> |
| | | <constraint firstItem="Fb9-IV-vVk" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="WI6-dS-4aK"/> |
| | | <constraint firstAttribute="trailing" secondItem="cCC-0f-GSV" secondAttribute="trailing" id="brF-kM-RJ7"/> |
| | | <constraint firstItem="cCC-0f-GSV" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="c6s-ah-BAB"/> |
| | | <constraint firstAttribute="bottom" secondItem="Fb9-IV-vVk" secondAttribute="bottom" id="jcg-ng-xeW"/> |
| | | <constraint firstItem="deT-IZ-PtZ" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" constant="7" id="tPU-LR-azA"/> |
| | | <constraint firstItem="cCC-0f-GSV" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" id="tmD-tf-gYR"/> |
| | | <constraint firstItem="rmi-DQ-cp9" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" constant="7.5" id="wLQ-lC-KXg"/> |
| | | </constraints> |
| | | <size key="customSize" width="178" height="301"/> |
| | | <connections> |
| | | <outlet property="cons_maxSubTitle" destination="Fam-ne-FM1" id="L5X-GP-uev"/> |
| | | <outlet property="image_free" destination="deT-IZ-PtZ" id="kI7-7g-aIM"/> |
| | | <outlet property="img_cover" destination="cCC-0f-GSV" id="85x-ue-edy"/> |
| | | <outlet property="img_tipPeople" destination="hE1-AV-t8f" id="ObN-5h-jnl"/> |
| | | <outlet property="img_vip" destination="yBF-fO-fwz" id="icq-m9-dx3"/> |
| | | <outlet property="label_num" destination="JaY-19-IAL" id="2RU-X7-0wb"/> |
| | | <outlet property="label_price" destination="kTL-dA-lNA" id="lNC-ej-0H3"/> |
| | | <outlet property="label_subTitle" destination="z5u-My-91l" id="j4L-bl-DhS"/> |
| | | <outlet property="label_title" destination="byc-Ar-sJL" id="CAQ-8Z-yC9"/> |
| | | <outlet property="view_price" destination="rmi-DQ-cp9" id="Kh2-av-YYy"/> |
| | | <outlet property="view_text_bg" destination="Fb9-IV-vVk" id="Ol7-cR-BWU"/> |
| | | </connections> |
| | | <point key="canvasLocation" x="236.64122137404578" y="108.80281690140846"/> |
| | | </collectionViewCell> |
| | | </objects> |
| | | <resources> |
| | | <image name="icon_freee" width="50" height="18"/> |
| | | <image name="icon_use_small" width="10" height="10.666666984558105"/> |
| | | <image name="icon_vip" width="21.666666030883789" height="21.666666030883789"/> |
| | | </resources> |
| | |
| | | |
| | | override func awakeFromNib() { |
| | | super.awakeFromNib() |
| | | view_shadow.jq_gradientColor(colorArr: [UIColor.black.withAlphaComponent(0.2).cgColor,UIColor.clear.cgColor], cornerRadius: 0, startPoint: CGPoint(x: 1, y: 1), endPoint: CGPoint(x: 1, y: 0), bounds: nil, locations: nil) |
| | | view_shadow.jq_gradientColor(colorArr: [UIColor.black.withAlphaComponent(0.3).cgColor,UIColor.clear.cgColor], cornerRadius: 0, startPoint: CGPoint(x: 1, y: 1), endPoint: CGPoint(x: 1, y: 0), bounds: nil, locations: nil) |
| | | } |
| | | |
| | | |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> |
| | | <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23094" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> |
| | | <device id="retina6_12" orientation="portrait" appearance="light"/> |
| | | <dependencies> |
| | | <deployment identifier="iOS"/> |
| | | <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/> |
| | | <capability name="System colors in document resources" minToolsVersion="11.0"/> |
| | | <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23084"/> |
| | | <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> |
| | | </dependencies> |
| | | <objects> |
| | |
| | | <constraint firstAttribute="height" constant="9.5" id="wsl-qN-1LP"/> |
| | | </constraints> |
| | | </view> |
| | | <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="ajx-e3-nPT"> |
| | | <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="ajx-e3-nPT"> |
| | | <rect key="frame" x="0.0" y="0.0" width="413" height="255.66666666666666"/> |
| | | </imageView> |
| | | <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="all-AA-1bU"> |
| | |
| | | <nil key="highlightedColor"/> |
| | | </label> |
| | | </subviews> |
| | | <color key="backgroundColor" systemColor="systemBackgroundColor"/> |
| | | <constraints> |
| | | <constraint firstAttribute="trailing" secondItem="NTV-9E-3YX" secondAttribute="trailing" constant="10" id="1d8-hO-XQO"/> |
| | | <constraint firstItem="NTV-9E-3YX" firstAttribute="leading" secondItem="tDO-qY-aGP" secondAttribute="leading" id="51K-EF-Rvn"/> |
| | |
| | | </objects> |
| | | <resources> |
| | | <image name="icon_pay_s" width="14.666666984558105" height="18.666666030883789"/> |
| | | <systemColor name="systemBackgroundColor"> |
| | | <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> |
| | | </systemColor> |
| | | </resources> |
| | | </document> |
| | |
| | | import JQTools |
| | | import RxSwift |
| | | import MediaPlayer |
| | | import MJRefresh |
| | | |
| | | let SetBGMSuccess_Noti = Notification.Name.init("SetBGMSuccess_Noti") |
| | | |
| | |
| | | AudioPlayer.getSharedInstance().playSceneAt(audioFile) |
| | | } |
| | | } |
| | | |
| | | tableView.mj_header = MJRefreshNormalHeader(refreshingBlock: { |
| | | self.getData() |
| | | }) |
| | | |
| | | getData() |
| | | } |
| | |
| | | } |
| | | |
| | | private func getData(){ |
| | | tableView.mj_header?.endRefreshing() |
| | | |
| | | Services.getCategoryListByType(type: 1).subscribe(onNext: { data in |
| | | var items = [HomeTopMenuItem]() |
| | |
| | | self.viewModel.meditationList.removeAll() |
| | | self.viewModel.meditationList = m |
| | | for v in self.viewModel.meditationList{ |
| | | if v.clientMeditationCategoryVO?.categoryName.isEmpty ?? true{continue} |
| | | self.titleItems.append(TitleItem(title: v.clientMeditationCategoryVO?.categoryName ?? "", subTitle: v.clientMeditationCategoryVO?.description ?? "",hasMore:true)) |
| | | } |
| | | self.tableView.reloadData() |
| | |
| | | } |
| | | |
| | | @objc func searchAction(){ |
| | | let vc = SearchVC() |
| | | let vc = SearchVC(serchType: .muse) |
| | | push(vc: vc) |
| | | } |
| | | |
| | | @objc func settingvoiceAction(){ |
| | | // let vc = BackgroundVoiceVC() |
| | | // push(vc: vc) |
| | | |
| | | let nav = LoginNav(rootViewController: LoginVC()) |
| | | nav.modalPresentationStyle = .fullScreen |
| | | present(nav, animated: true) |
| | | let vc = BackgroundVoiceVC() |
| | | push(vc: vc) |
| | | } |
| | | |
| | | @objc func jumpMoreAction(_ sender:UIButton){ |
| | |
| | | |
| | | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { |
| | | if indexPath.section == 0{ |
| | | //每日疗愈 |
| | | let cell = tableView.dequeueReusableCell(withIdentifier: "_Home_Style_1_TCell") as! Home_Style_1_TCell |
| | | cell.model = viewModel.todyModel |
| | | return cell |
| | | }else if indexPath.section == 1{ |
| | | //私人定制 |
| | | let cell = tableView.dequeueReusableCell(withIdentifier: "_Home_Style_4_TCell") as! Home_Style_4_TCell |
| | | cell.style = .style1 |
| | | cell.setModels(viewModel.privateTodyModels) |
| | | return cell |
| | | }else if indexPath.section == 2{ |
| | | // 新手冥想指南 |
| | | let cell = tableView.dequeueReusableCell(withIdentifier: "_Home_Style_2_TCell") as! Home_Style_2_TCell |
| | | cell.imgView.image = UIImage(named: "bg_guide_home") |
| | | cell.view_shadow.isHidden = true |
| | | return cell |
| | | }else { |
| | |
| | | |
| | | extension HomeVC:UIScrollViewDelegate{ |
| | | func scrollViewDidScroll(_ scrollView: UIScrollView) { |
| | | let v = min(scrollView.contentOffset.y / JQ_NavBarHeight, 1) |
| | | navigationController?.navigationBar.standardAppearance.backgroundColor = .white.withAlphaComponent(v) |
| | | // let v = min(scrollView.contentOffset.y / JQ_NavBarHeight, 1) |
| | | // navigationController?.navigationBar.standardAppearance.backgroundColor = .white.withAlphaComponent(v) |
| | | navigationController?.navigationBar.standardAppearance.backgroundColor = .white |
| | | navigationController?.navigationBar.scrollEdgeAppearance?.backgroundColor = .white |
| | | } |
| | | } |
| | |
| | | class Home_Style_2_TCell: UITableViewCell { |
| | | |
| | | @IBOutlet weak var view_shadow: UIView! |
| | | @IBOutlet weak var imgView: UIImageView! |
| | | |
| | | override func awakeFromNib() { |
| | | super.awakeFromNib() |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> |
| | | <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23094" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> |
| | | <device id="retina6_12" orientation="portrait" appearance="light"/> |
| | | <dependencies> |
| | | <deployment identifier="iOS"/> |
| | | <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/> |
| | | <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23084"/> |
| | | <capability name="Safe area layout guides" minToolsVersion="9.0"/> |
| | | <capability name="System colors in document resources" minToolsVersion="11.0"/> |
| | | <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> |
| | |
| | | <rect key="frame" x="0.0" y="0.0" width="475" height="351"/> |
| | | <autoresizingMask key="autoresizingMask"/> |
| | | <subviews> |
| | | <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Pyg-Ek-VBf"> |
| | | <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Pyg-Ek-VBf"> |
| | | <rect key="frame" x="0.0" y="0.0" width="475" height="341.66666666666669"/> |
| | | </imageView> |
| | | <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="WXB-JU-fQz"> |
| | |
| | | </tableViewCellContentView> |
| | | <viewLayoutGuide key="safeArea" id="njF-e1-oar"/> |
| | | <connections> |
| | | <outlet property="imgView" destination="Pyg-Ek-VBf" id="aL8-Jj-6BS"/> |
| | | <outlet property="view_shadow" destination="WXB-JU-fQz" id="PbM-TY-SlG"/> |
| | | </connections> |
| | | <point key="canvasLocation" x="257.25190839694653" y="128.52112676056339"/> |
| | |
| | | @IBOutlet weak var cons_height: NSLayoutConstraint! |
| | | |
| | | private var viewModel = CommentListViewModel() |
| | | private var id:Int! |
| | | |
| | | init(id:Int) { |
| | | super.init(nibName: nil, bundle: nil) |
| | | self.id = id |
| | | } |
| | | |
| | | required init?(coder: NSCoder) { |
| | | fatalError("init(coder:) has not been implemented") |
| | | } |
| | | |
| | | override func viewDidLoad() { |
| | | super.viewDidLoad() |
| | |
| | | } |
| | | |
| | | @IBAction func sendAction(_ sender: UIButton) { |
| | | guard !tf_input.text!.isEmpty else { |
| | | alert(msg: "请输入您的提问");return |
| | | } |
| | | tf_input.resignFirstResponder() |
| | | |
| | | Services.addQuestion(content: tf_input.text!, meditationId: id).subscribe(onNext: {_ in |
| | | |
| | | }, onError: {_ in |
| | | |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | @objc func longPressAction(_ gesture:UITapGestureRecognizer){ |
| | |
| | | class HomeItemDetailVC: BaseVC,PayMusicDelegate{ |
| | | |
| | | @IBOutlet weak var slider_voice: UISlider! |
| | | @IBOutlet weak var img_background: UIImageView! |
| | | @IBOutlet weak var view_function: UIView! |
| | | @IBOutlet weak var btn_play: UIButton! |
| | | @IBOutlet weak var label_title: UILabel! |
| | |
| | | |
| | | Services.getMeditationDetail(id: id).subscribe(onNext: {[unowned self] data in |
| | | self.model = data.data |
| | | self.collect_bitem.image = data.data?.favorite == .yes ? UIImage(named: "btn_collect_s"):UIImage(named: "btn_collect_1") |
| | | self.collect_bitem.image = data.data?.favorite == .yes ? UIImage(named: "btn_collect_1_s"):UIImage(named: "btn_collect_1") |
| | | self.collect_bitem.tintColor = data.data?.favorite == .yes ? UIColor(hexString: "fe5b60"):.white |
| | | |
| | | self.img_background.sd_setImage(with: URL(string: data.data?.backgroundUrl ?? "")) |
| | | if audioPlayer.meditationModel?.id == data.data?.id{ |
| | | audioPlayer.delegate = self |
| | | } |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | override func viewDidAppear(_ animated: Bool) { |
| | | super.viewDidAppear(animated) |
| | | |
| | | //如果从支付过来的,移除支付 |
| | | navigationController!.viewControllers.removeAll { vc in |
| | |
| | | } |
| | | return false |
| | | } |
| | | } |
| | | |
| | | override func viewWillAppear(_ animated: Bool) { |
| | | super.viewWillAppear(animated) |
| | | (navigationItem.leftBarButtonItem?.customView as? UIButton)?.setImage(UIImage(named: "btn_back")?.withTintColor(.white), for: .normal) |
| | | navigationController?.navigationBar.scrollEdgeAppearance?.backgroundColor = .clear |
| | | } |
| | | |
| | | override func setUI() { |
| | |
| | | }.disposed(by: disposeBag) |
| | | } |
| | | |
| | | override func viewWillAppear(_ animated: Bool) { |
| | | super.viewWillAppear(animated) |
| | | (navigationItem.leftBarButtonItem?.customView as? UIButton)?.setImage(UIImage(named: "btn_back")?.withTintColor(.white), for: .normal) |
| | | } |
| | | |
| | | private func startMiniRunloop(){ |
| | | // 创建旋转动画 |
| | | let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation.z") |
| | |
| | | } |
| | | |
| | | @IBAction func playAction(_ sender: UIButton) { |
| | | |
| | | // showHUD("准备播放") |
| | | |
| | | if var m = model{ |
| | | m.backgroundUrl = "https://downsc.chinaz.net/Files/DownLoad/sound1/201906/11582.mp3,https://www.cambridgeenglish.org/images/153149-movers-sample-listening-test-vol2.mp3" |
| | | |
| | | m.tutorAudioUrl = "https://downsc.chinaz.net/files/download/sound1/201206/1638.mp3" |
| | | if let m = model{ |
| | | audioPlayer.playBGMAt(firstPlayIndex: 0, model: m, delegate: self) |
| | | } |
| | | } |
| | |
| | | } |
| | | |
| | | @IBAction func commentAction(_ sender: TapBtn) { |
| | | let vc = CommentListVC() |
| | | guard let m = model else{return} |
| | | |
| | | let vc = CommentListVC(id: m.id) |
| | | vc.modalPresentationStyle = .custom |
| | | present(vc, animated: true) |
| | | } |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> |
| | | <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23094" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> |
| | | <device id="retina6_12" orientation="portrait" appearance="light"/> |
| | | <dependencies> |
| | | <deployment identifier="iOS"/> |
| | | <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/> |
| | | <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23084"/> |
| | | <capability name="System colors in document resources" minToolsVersion="11.0"/> |
| | | <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> |
| | | </dependencies> |
| | |
| | | <connections> |
| | | <outlet property="btn_play" destination="Qgc-UW-rO1" id="MUw-JK-1pS"/> |
| | | <outlet property="btn_playMode" destination="9t3-fS-clT" id="0me-mK-vhP"/> |
| | | <outlet property="img_background" destination="pbM-Fi-Xil" id="cuG-Hk-KlP"/> |
| | | <outlet property="img_countdonw" destination="gxd-0O-eUD" id="rzB-8i-qOk"/> |
| | | <outlet property="label_commentNum" destination="IkS-qR-riK" id="9zO-Xt-6XC"/> |
| | | <outlet property="label_countdown" destination="akf-L4-aPE" id="goO-Gd-TLu"/> |
| | |
| | | </connections> |
| | | </button> |
| | | <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="3rZ-t0-pdK"> |
| | | <rect key="frame" x="68.666666666666686" y="524.66666666666663" width="256" height="29"/> |
| | | <rect key="frame" x="71.333333333333329" y="524.66666666666663" width="250.66666666666669" height="29"/> |
| | | <subviews> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="当前播放模式已设置为顺序播放" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4zW-Bq-V7P"> |
| | | <rect key="frame" x="28" y="7.3333333333333712" width="200" height="14"/> |
| | | <rect key="frame" x="28" y="7.3333333333333712" width="194.66666666666666" height="14"/> |
| | | <fontDescription key="fontDescription" type="system" pointSize="14"/> |
| | | <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> |
| | | <nil key="highlightedColor"/> |
| | |
| | | super.viewDidLoad() |
| | | title = "支付结果" |
| | | |
| | | //如果从支付过来的,移除支付 |
| | | navigationController!.viewControllers.removeAll { vc in |
| | | if vc is PaymentOrderResultVC || vc is PaymentOrderVC{ |
| | | return true |
| | | } |
| | | return false |
| | | } |
| | | |
| | | NotificationCenter.default.post(name: CourseRefresh_Noti, object: nil) |
| | | |
| | | yy_popBlock = { [weak self] () in |
| | |
| | | } |
| | | } |
| | | |
| | | topView.setPrice(price) |
| | | topView.setPrice(courseId: courseId, price: price) |
| | | |
| | | Services.paymentSuccess(courseId: courseId).subscribe(onNext: {data in |
| | | self.models = data.data ?? [] |
| | |
| | | |
| | | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { |
| | | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "_HomeRelaxBanner_2_1_CCell", for: indexPath) as! HomeRelaxBanner_2_1_CCell |
| | | cell.backgroundColor = .jq_randomColor |
| | | let model = models[indexPath.row] |
| | | cell.setCourseModel(model) |
| | | return cell |
| | | } |
| | | |
| | |
| | | @IBAction func completeAction(_ sender: UIButton) { |
| | | |
| | | guard let m = courseModel else {return} |
| | | guard btn_isRead.isSelected else { |
| | | alertError(msg: "请先阅读并同意《课程/疗愈音频购买协议》");return |
| | | } |
| | | |
| | | if giftToOther { |
| | | |
| | | guard !tf_phone.text!.isEmpty else { |
| | | alertError(msg: "请输入您要赠送人的手机号");return |
| | | } |
| | | |
| | | guard giftUserId != nil else { |
| | | alertError(msg: "请先查询赠送人是否存在");return |
| | | } |
| | | } |
| | | |
| | | guard balance > m.generalPrice else{ |
| | | CommonAlertView.show(title: "提示", content: "当前余额不足,请先充值", cancelStr: "暂不充值", completeStr: "去充值", isSingle: false) { state in |
| | |
| | | } |
| | | } |
| | | return |
| | | } |
| | | |
| | | guard btn_isRead.isSelected else { |
| | | alertError(msg: "请先阅读并同意《课程/疗愈音频购买协议》");return |
| | | } |
| | | |
| | | if giftToOther { |
| | | guard giftUserId != nil else { |
| | | alertError(msg: "请输入您要赠送人的手机号");return |
| | | } |
| | | } |
| | | |
| | | let vc = PaymentOrderResultVC(courseId: courseId, price: m.generalPrice) |
| | |
| | | |
| | | @IBOutlet weak var tf_search: UITextField! |
| | | @IBOutlet weak var collectionView: UICollectionView! |
| | | private var viewModel = SearchContentViewModel() |
| | | private var museViewModel:SearchContentViewModel? |
| | | private var courseViewModel:CourseVCOfficalViewModel? |
| | | private var serchType:SearchVC.SearchType! |
| | | |
| | | init(content:String) { |
| | | init(content:String,type:SearchVC.SearchType) { |
| | | super.init(nibName: nil, bundle: nil) |
| | | self.viewModel.search.accept(content) |
| | | self.serchType = type |
| | | |
| | | if type == .course{ |
| | | courseViewModel = CourseVCOfficalViewModel() |
| | | courseViewModel?.search.accept(content) |
| | | } |
| | | |
| | | if type == .muse{ |
| | | museViewModel = SearchContentViewModel() |
| | | museViewModel?.search.accept(content) |
| | | } |
| | | } |
| | | |
| | | required init?(coder: NSCoder) { |
| | |
| | | super.viewDidLoad() |
| | | title = "心泉·疗愈" |
| | | |
| | | tf_search.text = viewModel.search.value |
| | | switch serchType{ |
| | | case .course:tf_search.text = courseViewModel?.search.value ?? "" |
| | | case .muse:tf_search.text = museViewModel?.search.value ?? "" |
| | | default:break |
| | | } |
| | | } |
| | | |
| | | override func setUI() { |
| | |
| | | collectionView.register(UINib(nibName: "HomeRelaxBanner_2_CCell", bundle: nil), forCellWithReuseIdentifier: "_HomeRelaxBanner_2_CCell") |
| | | |
| | | collectionView.emptyDataSetView {[unowned self] v in |
| | | |
| | | guard v.viewWithTag(1301) == nil else {return} |
| | | |
| | | let emptyImageView = UIImageView(image: UIImage(named: "bg_empty")) |
| | | emptyImageView.tag = 1301 |
| | | |
| | | v.addSubview(emptyImageView) |
| | | emptyImageView.snp.makeConstraints { make in |
| | | make.top.equalTo(56.5) |
| | |
| | | } |
| | | } |
| | | |
| | | viewModel.configure(collectionView) |
| | | viewModel.beginRefresh() |
| | | switch serchType{ |
| | | case .course: |
| | | self.courseViewModel?.configure(collectionView) |
| | | self.courseViewModel?.beginRefresh() |
| | | case .muse: |
| | | self.museViewModel?.configure(collectionView) |
| | | self.museViewModel?.beginRefresh() |
| | | default:break |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | alert(msg: "请输入搜索内容");return |
| | | } |
| | | |
| | | viewModel.search.accept(tf_search.text!) |
| | | viewModel.beginRefresh() |
| | | switch serchType{ |
| | | case .course: |
| | | self.courseViewModel?.search.accept(tf_search.text!) |
| | | self.courseViewModel?.beginRefresh() |
| | | case .muse: |
| | | self.museViewModel?.search.accept(tf_search.text!) |
| | | self.museViewModel?.beginRefresh() |
| | | default:break |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | extension SearchContentVC:UICollectionViewDelegate & UICollectionViewDataSource{ |
| | | |
| | | func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { |
| | | let m = viewModel.dataSource.value!.list[indexPath.row] |
| | | |
| | | switch serchType{ |
| | | case .course: |
| | | let m = courseViewModel!.dataSource.value!.list[indexPath.row] |
| | | let vc = CourseDetialVC(courseId: m.id) |
| | | JQ_currentViewController().jq_push(vc: vc) |
| | | |
| | | case .muse: |
| | | let m = museViewModel!.dataSource.value!.list[indexPath.row] |
| | | let vc = HomeItemDetailVC(id: m.id) |
| | | JQ_currentViewController().jq_push(vc: vc) |
| | | default:break |
| | | } |
| | | |
| | | } |
| | | |
| | | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { |
| | | let m = viewModel.dataSource.value!.list[indexPath.row] |
| | | |
| | | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "_HomeRelaxBanner_2_CCell", for: indexPath) as! HomeRelaxBanner_2_CCell |
| | | cell.backgroundColor = .jq_randomColor |
| | | |
| | | switch serchType{ |
| | | case .course:break |
| | | |
| | | case .muse: |
| | | let m = museViewModel!.dataSource.value!.list[indexPath.row] |
| | | cell.setMeditationModel(m) |
| | | default:break |
| | | } |
| | | |
| | | return cell |
| | | } |
| | | |
| | | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { |
| | | return viewModel.dataSource.value?.list.count ?? 0 |
| | | switch serchType{ |
| | | case .course: |
| | | return courseViewModel!.dataSource.value?.list.count ?? 0 |
| | | case .muse: |
| | | return museViewModel!.dataSource.value?.list.count ?? 0 |
| | | default:return 0 |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | alert(msg: "请输入搜索内容") |
| | | return true |
| | | } |
| | | |
| | | viewModel.search.accept(textField.text!) |
| | | viewModel.beginRefresh() |
| | | switch serchType{ |
| | | case .course: |
| | | self.courseViewModel?.search.accept(tf_search.text!) |
| | | self.courseViewModel?.beginRefresh() |
| | | case .muse: |
| | | self.museViewModel?.search.accept(tf_search.text!) |
| | | self.museViewModel?.beginRefresh() |
| | | default:break |
| | | } |
| | | return true |
| | | } |
| | | } |
| | |
| | | static var array = NSMutableArray() |
| | | static let cacheSearchPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("search") |
| | | |
| | | static func readList()->NSMutableArray{ |
| | | static func readList(_ serchType:SearchVC.SearchType)->NSMutableArray{ |
| | | if !FileManager.default.fileExists(atPath: cacheSearchPath.absoluteString){ |
| | | try? FileManager.default.createDirectory(at: cacheSearchPath, withIntermediateDirectories: true) |
| | | } |
| | | |
| | | let searchPlistPath = cacheSearchPath.appendingPathComponent("search.plist") |
| | | let searchPlistPath = cacheSearchPath.appendingPathComponent(serchType.infoPlist) |
| | | if let tempArray = NSMutableArray(contentsOfFile: searchPlistPath.droppedScheme()!.absoluteString){ |
| | | array = tempArray |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | static func writeToPath(){ |
| | | let searchPlistPath = cacheSearchPath.appendingPathComponent("search.plist") |
| | | static func writeToPath(_ serchType:SearchVC.SearchType){ |
| | | let searchPlistPath = cacheSearchPath.appendingPathComponent(serchType.infoPlist) |
| | | array.write(to: searchPlistPath, atomically: true) |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | class SearchVC: BaseVC { |
| | | |
| | | enum SearchType { |
| | | case muse //疗愈 |
| | | case course //课程 |
| | | |
| | | var infoPlist:String{ |
| | | switch self { |
| | | case .muse:return "searchmuse.plist" |
| | | case .course:return "searchcourse.plist" |
| | | } |
| | | } |
| | | } |
| | | |
| | | @IBOutlet weak var cacheSearchCollectionView: UICollectionView! |
| | | @IBOutlet weak var cacheSearchHei: NSLayoutConstraint! |
| | | @IBOutlet weak var tf_search: UITextField! |
| | | @IBOutlet weak var tableView: UITableView! |
| | | @IBOutlet weak var view_hotKeyword: UIView! |
| | | @IBOutlet weak var label_hotSearhTitle: UILabel! |
| | | |
| | | private var hotWords = [String]() |
| | | private var serchType:SearchType! |
| | | |
| | | init(serchType:SearchType) { |
| | | super.init(nibName: nil, bundle: nil) |
| | | self.serchType = serchType |
| | | } |
| | | |
| | | required init?(coder: NSCoder) { |
| | | fatalError("init(coder:) has not been implemented") |
| | | } |
| | | |
| | | override func viewDidLoad() { |
| | | super.viewDidLoad() |
| | | title = "心泉·疗愈" |
| | | |
| | | _ = SearchCache.readList() |
| | | view_hotKeyword.isHidden = serchType == .course |
| | | label_hotSearhTitle.isHidden = serchType == .course |
| | | |
| | | tf_search.placeholder = serchType == .course ? "搜索你喜欢的课程~":"请输入冥想搜索内容" |
| | | |
| | | _ = SearchCache.readList(serchType) |
| | | cacheSearchCollectionView.reloadData() |
| | | |
| | | Services.getHotWordList().subscribe(onNext: {data in |
| | |
| | | |
| | | override func viewDidDisappear(_ animated: Bool) { |
| | | super.viewDidDisappear(animated) |
| | | SearchCache.writeToPath() |
| | | SearchCache.writeToPath(serchType) |
| | | } |
| | | |
| | | override func setUI() { |
| | |
| | | tf_search.resignFirstResponder() |
| | | SearchCache.writeToList(tf_search.text!) |
| | | |
| | | let vc = SearchContentVC(content: tf_search.text!) |
| | | let vc = SearchContentVC(content: tf_search.text!, type: serchType) |
| | | jq_push(vc: vc) |
| | | } |
| | | } |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> |
| | | <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23094" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> |
| | | <device id="retina6_12" orientation="portrait" appearance="light"/> |
| | | <dependencies> |
| | | <deployment identifier="iOS"/> |
| | | <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/> |
| | | <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23084"/> |
| | | <capability name="Safe area layout guides" minToolsVersion="9.0"/> |
| | | <capability name="System colors in document resources" minToolsVersion="11.0"/> |
| | | <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> |
| | |
| | | <connections> |
| | | <outlet property="cacheSearchCollectionView" destination="hyl-1O-IfF" id="xLr-Xr-lJL"/> |
| | | <outlet property="cacheSearchHei" destination="5YE-JH-tVc" id="ktS-NR-z7Y"/> |
| | | <outlet property="label_hotSearhTitle" destination="Mda-xm-ljU" id="sc7-eb-G0P"/> |
| | | <outlet property="tableView" destination="RTG-Tg-r7D" id="pq2-Aa-jvq"/> |
| | | <outlet property="tf_search" destination="Rbv-zT-iOu" id="Dxb-Mb-ezs"/> |
| | | <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/> |
| | | <outlet property="view_hotKeyword" destination="U44-7x-wSJ" id="I6D-Jd-rhG"/> |
| | | </connections> |
| | | </placeholder> |
| | | <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> |
| | |
| | | </connections> |
| | | </button> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="历史搜索" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gQh-cp-6ml"> |
| | | <rect key="frame" x="24" y="156" width="69.333333333333329" height="16"/> |
| | | <rect key="frame" x="24" y="156" width="67.666666666666671" height="16"/> |
| | | <constraints> |
| | | <constraint firstAttribute="height" constant="16" id="qdH-3T-iMm"/> |
| | | </constraints> |
| | |
| | | </collectionViewFlowLayout> |
| | | </collectionView> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="热门搜索" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Mda-xm-ljU"> |
| | | <rect key="frame" x="24" y="245.66666666666666" width="69.333333333333329" height="15.999999999999972"/> |
| | | <rect key="frame" x="24" y="245.66666666666666" width="67.666666666666671" height="15.999999999999972"/> |
| | | <constraints> |
| | | <constraint firstAttribute="height" constant="16" id="WZa-u0-Fx3"/> |
| | | </constraints> |
| | |
| | | |
| | | @IBOutlet weak var label_price: UILabel! |
| | | @IBOutlet weak var btn_lookCourse: UIButton! |
| | | private var courseId:Int! |
| | | |
| | | override func awakeFromNib() { |
| | | super.awakeFromNib() |
| | | } |
| | | |
| | | func setPrice(_ price:Double){ |
| | | func setPrice(courseId:Int,price:Double){ |
| | | self.courseId = courseId |
| | | label_price.text = "\(price.jq_formatFloat)" |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | @IBAction func lookCourseAction(_ sender: UIButton) { |
| | | // let vc = HomeItemDetailVC() |
| | | // JQ_currentViewController().jq_push(vc: vc) |
| | | let vc = CourseDetialVC(courseId: courseId) |
| | | JQ_currentViewController().jq_push(vc: vc) |
| | | } |
| | | |
| | | |
| | |
| | | @IBOutlet weak var btn_login: UIButton! |
| | | @IBOutlet weak var btn_sendCode: UIButton! |
| | | @IBOutlet weak var btn_isRead: UIButton! |
| | | @IBOutlet weak var btn_wechat: UIButton! |
| | | |
| | | private var viewModel = LoginViewModel() |
| | | |
| | |
| | | |
| | | override func setUI() { |
| | | |
| | | btn_wechat.isHidden = !WXApi.isWXAppInstalled() |
| | | |
| | | navigationItem.leftBarButtonItem = UIBarButtonItem.jq_creat(image: nav_back_img, target: self, alignment:.left, action: #selector(backAction)).item |
| | | |
| | | btn_eye.isSelected = true |
| | |
| | | guard !viewModel.loginPhone.value.isEmpty else {alert(msg: "请输入手机号");return} |
| | | guard viewModel.loginPhone.value.jq_isPhone else {alert(msg: "请输入正确手机号");return} |
| | | |
| | | Services.sendCode(type: .codeLogin).subscribe(onNext: {data in |
| | | Services.sendCode(phone:tf_phone.text!,type: .codeLogin).subscribe(onNext: {data in |
| | | if let _ = data.data{ |
| | | sender.jq_openCountDown(60, defultTitle: "发送验证码") { |
| | | sender.titleLabel?.font = UIFont.systemFont(ofSize: 12) |
| | |
| | | guard btn_isRead.isSelected else { |
| | | alertError(msg: "请阅读并同意《用户注册协议》和《用户隐私协议》");return |
| | | } |
| | | //todo |
| | | WeChatTools.sendAuthRequest() |
| | | } |
| | | |
| | | @IBAction func loginByAppleAction(_ sender: UIButton) { |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> |
| | | <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23094" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> |
| | | <device id="retina6_12" orientation="portrait" appearance="light"/> |
| | | <dependencies> |
| | | <deployment identifier="iOS"/> |
| | | <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/> |
| | | <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23084"/> |
| | | <capability name="System colors in document resources" minToolsVersion="11.0"/> |
| | | <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> |
| | | </dependencies> |
| | |
| | | <outlet property="btn_loginByPwd" destination="Ec8-sg-6R6" id="Y2P-aU-5lk"/> |
| | | <outlet property="btn_register" destination="k1h-gO-9vj" id="AxQ-S9-3oN"/> |
| | | <outlet property="btn_sendCode" destination="cUd-a4-RTn" id="n26-3e-uaI"/> |
| | | <outlet property="btn_wechat" destination="2Fj-Y0-NYp" id="M7L-LL-Se8"/> |
| | | <outlet property="tf_content" destination="x0Y-XG-Xsv" id="GVf-UU-yCe"/> |
| | | <outlet property="tf_phone" destination="9rD-4T-K6b" id="ynF-y5-xQD"/> |
| | | <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/> |
| | |
| | | <rect key="frame" x="0.0" y="248" width="393" height="604"/> |
| | | <subviews> |
| | | <button opaque="NO" tag="10" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Ec8-sg-6R6"> |
| | | <rect key="frame" x="23" y="22" width="74" height="22"/> |
| | | <rect key="frame" x="23" y="22" width="72" height="22"/> |
| | | <constraints> |
| | | <constraint firstAttribute="height" constant="22" id="eDS-Kw-vhp"/> |
| | | </constraints> |
| | |
| | | </connections> |
| | | </button> |
| | | <button opaque="NO" tag="11" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Afa-A3-2l1"> |
| | | <rect key="frame" x="125" y="22" width="92" height="22"/> |
| | | <rect key="frame" x="123" y="22" width="90" height="22"/> |
| | | <constraints> |
| | | <constraint firstAttribute="height" constant="22" id="na9-Gz-KYA"/> |
| | | </constraints> |
| | |
| | | <rect key="frame" x="31" y="118" width="24" height="24"/> |
| | | </imageView> |
| | | <textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="248" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="请输入您的手机号" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="9rD-4T-K6b" customClass="QMUITextField"> |
| | | <rect key="frame" x="66" y="120.6666666666667" width="114.33333333333331" height="18.666666666666671"/> |
| | | <rect key="frame" x="66" y="120.6666666666667" width="111.33333333333331" height="18.666666666666671"/> |
| | | <fontDescription key="fontDescription" type="system" pointSize="14"/> |
| | | <textInputTraits key="textInputTraits" keyboardType="numberPad"/> |
| | | <userDefinedRuntimeAttributes> |
| | |
| | | <rect key="frame" x="31" y="187" width="24" height="24"/> |
| | | </imageView> |
| | | <textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="248" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="请输入密码" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="x0Y-XG-Xsv" customClass="QMUITextField"> |
| | | <rect key="frame" x="66" y="189.66666666666669" width="71.666666666666686" height="18.666666666666657"/> |
| | | <rect key="frame" x="66" y="189.66666666666669" width="69.666666666666686" height="18.666666666666657"/> |
| | | <fontDescription key="fontDescription" type="system" pointSize="14"/> |
| | | <textInputTraits key="textInputTraits"/> |
| | | </textField> |
| | |
| | | </connections> |
| | | </button> |
| | | <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="EBj-o7-Mca"> |
| | | <rect key="frame" x="31" y="357" width="56" height="27"/> |
| | | <rect key="frame" x="31" y="357" width="54" height="27"/> |
| | | <fontDescription key="fontDescription" type="system" pointSize="12"/> |
| | | <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/> |
| | | <state key="normal" title="忘记密码?"> |
| | |
| | | </connections> |
| | | </button> |
| | | <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="k1h-gO-9vj"> |
| | | <rect key="frame" x="312" y="357" width="50" height="27"/> |
| | | <rect key="frame" x="314" y="357" width="48" height="27"/> |
| | | <fontDescription key="fontDescription" type="system" weight="medium" pointSize="12"/> |
| | | <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/> |
| | | <state key="normal" title="注册账号"> |
| | |
| | | </subviews> |
| | | </stackView> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="第三方登录" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9Rg-d1-NE7"> |
| | | <rect key="frame" x="166" y="441.66666666666663" width="61.333333333333343" height="14.333333333333314"/> |
| | | <rect key="frame" x="166.66666666666666" y="441.66666666666663" width="59.666666666666657" height="14.333333333333314"/> |
| | | <fontDescription key="fontDescription" type="system" pointSize="12"/> |
| | | <color key="textColor" red="0.5725490196078431" green="0.56862745098039214" blue="0.56862745098039214" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> |
| | | <nil key="highlightedColor"/> |
| | | </label> |
| | | <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="cUd-a4-RTn"> |
| | | <rect key="frame" x="293" y="184.66666666666669" width="72" height="29"/> |
| | | <rect key="frame" x="295" y="184.66666666666669" width="70" height="29"/> |
| | | <fontDescription key="fontDescription" type="system" weight="medium" pointSize="14"/> |
| | | <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/> |
| | | <state key="normal" title="发送验证码"> |
| | |
| | | </connections> |
| | | </button> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="我已阅读并同意" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="esZ-HR-QwQ"> |
| | | <rect key="frame" x="57" y="240" width="86" height="14.333333333333343"/> |
| | | <rect key="frame" x="57.000000000000007" y="240" width="83.666666666666686" height="14.333333333333343"/> |
| | | <fontDescription key="fontDescription" type="system" weight="medium" pointSize="12"/> |
| | | <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/> |
| | | <nil key="highlightedColor"/> |
| | | </label> |
| | | <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="MNJ-Ag-zfE"> |
| | | <rect key="frame" x="148" y="233.66666666666669" width="87" height="27"/> |
| | | <rect key="frame" x="145.66666666666666" y="233.66666666666669" width="84" height="27"/> |
| | | <fontDescription key="fontDescription" type="system" weight="medium" pointSize="12"/> |
| | | <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/> |
| | | <state key="normal" title="《用户注册协议》"> |
| | |
| | | </connections> |
| | | </button> |
| | | <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="eq2-Wp-Yza"> |
| | | <rect key="frame" x="243" y="233.66666666666669" width="87" height="27"/> |
| | | <rect key="frame" x="237.66666666666663" y="233.66666666666669" width="84" height="27"/> |
| | | <fontDescription key="fontDescription" type="system" weight="medium" pointSize="12"/> |
| | | <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/> |
| | | <state key="normal" title="《用户隐私协议》"> |
| | |
| | | |
| | | |
| | | private func sendCode(){ |
| | | Services.sendCode(type: .forgetPwd).subscribe(onNext: { _ in |
| | | Services.sendCode(phone:phone,type: .forgetPwd).subscribe(onNext: { _ in |
| | | self.starTimer() |
| | | }).disposed(by: disposeBag) |
| | | } |
| | |
| | | guard !viewModel.phone.value.isEmpty else {alertError(msg: "请输入手机号");return} |
| | | guard viewModel.phone.value.jq_isPhone else {alertError(msg: "请输入正确手机号");return} |
| | | |
| | | Services.sendCode(type: .register).subscribe(onNext: {data in |
| | | if let _ = data.data{ |
| | | Services.sendCode(phone:viewModel.phone.value,type: .register).subscribe(onNext: {data in |
| | | if data.code == 200{ |
| | | sender.jq_openCountDown(60, defultTitle: "发送验证码") { |
| | | sender.titleLabel?.font = UIFont.systemFont(ofSize: 12) |
| | | sender.setTitleColor(.black.withAlphaComponent(0.3), for: .normal) |
| | |
| | | alertError(msg: "请输入正确的手机号");return |
| | | } |
| | | |
| | | Services.sendCode(type: .threePlantform).subscribe(onNext: {data in |
| | | Services.sendCode(phone:tf_phone.text!,type: .threePlantform).subscribe(onNext: {data in |
| | | if let _ = data.data{ |
| | | sender.jq_openCountDown(60, defultTitle: "发送验证码") { |
| | | sender.titleLabel?.font = UIFont.systemFont(ofSize: 12) |
| | |
| | | <color key="textColor" red="0.13725490196078433" green="0.13725490196078433" blue="0.13725490196078433" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> |
| | | <nil key="highlightedColor"/> |
| | | </label> |
| | | <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_vip_level" translatesAutoresizingMaskIntoConstraints="NO" id="dut-7H-aMv"> |
| | | <rect key="frame" x="70.333333333333314" y="11.333333333333373" width="95.666666666666686" height="27.666666666666671"/> |
| | | <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_vip_level" translatesAutoresizingMaskIntoConstraints="NO" id="dut-7H-aMv"> |
| | | <rect key="frame" x="70.333333333333343" y="11.333333333333373" width="95.333333333333343" height="27.666666666666671"/> |
| | | <constraints> |
| | | <constraint firstAttribute="width" constant="95.5" id="9QQ-4F-lHB"/> |
| | | <constraint firstAttribute="height" constant="27.5" id="vly-QN-iWG"/> |
| | | </constraints> |
| | | </imageView> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="查看详情" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="flg-Hv-HHC"> |
| | | <rect key="frame" x="266.66666666666669" y="18.666666666666742" width="44" height="13.333333333333336"/> |
| | |
| | | alertError(msg: "请输入手机号");return |
| | | } |
| | | |
| | | Services.sendCode(type: .addBank).subscribe(onNext: {_ in |
| | | Services.sendCode(phone:tf_phone.text!,type: .addBank).subscribe(onNext: {_ in |
| | | sender.jq_openCountDown(60, defultTitle: "发送验证码") { |
| | | sender.titleLabel?.font = UIFont.systemFont(ofSize: 12) |
| | | sender.setTitleColor(.black.withAlphaComponent(0.3), for: .normal) |
| | |
| | | } |
| | | |
| | | @IBAction func sendCodeAction(_ sender: UIButton) { |
| | | Services.sendCode(type: .exchangePhone).subscribe(onNext: { data in |
| | | Services.sendCode(phone:tf_phone.text!,type: .exchangePhone).subscribe(onNext: { data in |
| | | if let _ = data.data{ |
| | | sender.jq_openCountDown(60, defultTitle: "发送验证码") { |
| | | sender.titleLabel?.font = UIFont.systemFont(ofSize: 12) |
| | |
| | | var tutorAudioUrl: String = "" |
| | | var virtualLearnedNum: Int = 0 |
| | | var favorite:ConditionType = .no // 是否收藏:1:是 2:否 |
| | | var meditationMusicList = [String]() |
| | | } |
| | | |
| | | struct CommentModel:HandyJSON{ |
| | |
| | | var id = 0 |
| | | var imageUrl = "" |
| | | var name = "" |
| | | var courseId:String? |
| | | } |
| | | |
| | | struct CourseModel:HandyJSON{ |
| | |
| | | var sortNum: Int = 0 |
| | | var tutor:String = "" |
| | | var wxQrCode:String = "" |
| | | var isCollect:ConditionType = .no // 是否收藏:1:是 2:否 |
| | | |
| | | var list2 = [CourseModel]() |
| | | var list = [CourseItemModel]() |
| | |
| | | |
| | | |
| | | struct ResponseUserAnswerModel:HandyJSON{ |
| | | var tagsId = "" //问题二 多个tagId使用英文逗号拼接字符串 |
| | | var tagIds = "" //问题二 多个tagId使用英文逗号拼接字符串 |
| | | var userAnswerOneDTOList = [ResponseUserAnswerDTOModel]() |
| | | } |
| | | |
| | |
| | | if progress {showHUD()} |
| | | |
| | | var headers = HTTPHeaders() |
| | | // if let token = UserViewModel.getToken(){ |
| | | // headers.add(name: "Authorization", value: "Bearer" + " " + token) |
| | | // LogInfo("USER_token:Bearer \(token)") |
| | | // } |
| | | if let token = UserViewModel.getLoginInfo()?.accessToken{ |
| | | headers.add(name: "Authorization", value: "Bearer" + " " + token) |
| | | LogInfo("USER_token:Bearer \(token)") |
| | | } |
| | | |
| | | if encoding is JSONEncoding { |
| | | headers.add(name: "Content-Type", value: "application/json;charset=UTF-8") |
| | |
| | | if encoding != nil { |
| | | newEncoding = encoding! |
| | | } else { |
| | | #if DEBUG |
| | | newEncoding = URLEncoding.queryString |
| | | #else |
| | | // #if DEBUG |
| | | // newEncoding = URLEncoding.queryString |
| | | // #else |
| | | newEncoding = method == .post ? URLEncoding.httpBody : URLEncoding.queryString |
| | | #endif |
| | | // #endif |
| | | } |
| | | |
| | | sharedSessionManager.request(params.url.absoluteString, method: method, parameters:params.done(), encoding: newEncoding, headers:headers).validate().responseData{response in |
| | |
| | | if let next = BaseResponse<T>.deserialize(from: jsonString){ |
| | | switch next.code{ |
| | | case 200:ob.onNext(next) |
| | | case 501: |
| | | // CommonAlertView.show(title: "提示", content: next.msg,isSingle: true) { _ in |
| | | // |
| | | // } |
| | | ob.onError(NetRequestError.InvaildSession) |
| | | case 600: |
| | | if !ignoreAlert{ |
| | | alertError(msg: "登录失效,请重新登录");ob.onError(NetRequestError.InvaildSession) |
| | | } |
| | | // app.needLogin() |
| | | case 401:ob.onError(NetRequestError.InvaildSession) |
| | | default: |
| | | if !ignoreAlert{ |
| | | alertError(msg: "\(next.msg)") |
| | |
| | | import CoreLocation |
| | | |
| | | #if DEBUG |
| | | let All_Url = "https://mock.apipost.net/mock/31b303c60464000" |
| | | let All_Url = "http://192.168.110.64:9000" |
| | | //let All_Url = "https://mock.apipost.net/mock/31b303c60464000" |
| | | #else |
| | | let All_Url = "http://" //正式地址 |
| | | #endif |
| | |
| | | .append(key: "captcha",value:content) |
| | | .append(key: "apipost_id", value: "246d780670e265") |
| | | } |
| | | return NetworkRequest.request(params: params, method: .post, progress: true) |
| | | return NetworkRequest.request(params: params, method: .post,encoding: JSONEncoding(), progress: true) |
| | | } |
| | | |
| | | |
| | |
| | | params.interface(url: "/auth/app/appleLogin") |
| | | .append(key: "appleId", value: appleId) |
| | | .append(key: "apipost_id", value: "246d780670e264") |
| | | return NetworkRequest.request(params: params, method: .post, progress: true) |
| | | } |
| | | |
| | | class func loginByWechat(headImgUrl:String,nickname:String,sex:Int,wxOpenId:String)->Observable<BaseResponse<LoginUserInfoModel>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/auth/app/appleLogin") |
| | | .append(key: "headImgUrl", value: headImgUrl) |
| | | .append(key: "nickname", value: nickname) |
| | | .append(key: "sex", value: sex) |
| | | .append(key: "wxOpenId", value: wxOpenId) |
| | | .append(key: "apipost_id", value: "246d7806b0e26c") |
| | | return NetworkRequest.request(params: params, method: .post, progress: true) |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | /// 发送验证码 |
| | | class func sendCode(type:SendCodeType)->Observable<BaseResponse<SimpleModel>>{ |
| | | class func sendCode(phone:String,type:SendCodeType)->Observable<BaseResponse<SimpleModel>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/auth/app/sendCaptchaCode") |
| | | .append(key: "type", value: type.rawValue) |
| | | .append(key: "cellPhone", value: phone) |
| | | .append(key: "apipost_id", value: "246d7806b0e269") |
| | | return NetworkRequest.request(params: params, method: .get, progress: true) |
| | | } |
| | |
| | | .append(key: "inviteUserId", value: inviteUserId) |
| | | .append(key: "password", value: password.jq_md5String().uppercased()) |
| | | .append(key: "apipost_id", value: "246d7806b0e268") |
| | | return NetworkRequest.request(params: params, method: .post, progress: true) |
| | | return NetworkRequest.request(params: params, method: .post,encoding: JSONEncoding(), progress: true) |
| | | } |
| | | |
| | | /// 找回密码验证手机号 |
| | |
| | | params.interface(url: "/meditation/client/meditation/home/favorite") |
| | | .append(key: "id", value: id) |
| | | .append(key: "apipost_id", value: "2aa4e14ab0e159") |
| | | return NetworkRequest.request(params: params, method: .get, progress: true) |
| | | return NetworkRequest.request(params: params, method: .post, progress: false) |
| | | } |
| | | |
| | | /// 获取热词 |
| | |
| | | /// 搜索 |
| | | class func search(text:String,page:Int,pageSize:Int = 20)->Observable<BaseResponse<BaseResponseList<MeditationModel>>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/meditation/client/meditation/home/getHotWordList") |
| | | params.interface(url: "/meditation/client/meditation/home/search") |
| | | .append(key: "condition", value: text) |
| | | .append(key: "pageCurr", value: page) |
| | | .append(key: "pageSize", value: pageSize) |
| | | .append(key: "apipost_id", value: "25c3e3d0b0e160") |
| | | return NetworkRequest.request(params: params, method: .get, progress: false) |
| | | return NetworkRequest.request(params: params, method: .post, progress: false) |
| | | } |
| | | } |
| | | |
| | |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/user/client/app-user/getTagList") |
| | | .append(key: "apipost_id", value: "25c3dab9f0e024") |
| | | return NetworkRequest.request(params: params, method: .post, progress: true) |
| | | return NetworkRequest.request(params: params, method: .get, progress: true) |
| | | } |
| | | |
| | | class func saveUserAnswers(_ model:ResponseUserAnswerModel)->Observable<BaseResponse<SimpleModel>>{ |
| | |
| | | params.interface(url: "/user/client/app-user/saveUserAnswers") |
| | | .append(dic: model.toJSON()!) |
| | | .append(key: "apipost_id", value: "25c3dab9f0e025") |
| | | return NetworkRequest.request(params: params, method: .post, progress: true) |
| | | return NetworkRequest.request(params: params, method: .post,encoding: JSONEncoding(), progress: true) |
| | | } |
| | | |
| | | /// 冥想等级 |
| | |
| | | return NetworkRequest.request(params: params, method: .post, progress: false) |
| | | } |
| | | |
| | | class func addQuestion(content:String,meditationId:Int)->Observable<BaseResponse<SimpleModel>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | .interface(url: "/meditation/client/meditation/home/addQuestion") |
| | | return NetworkRequest.request(params: params, method: .post, progress: true) |
| | | } |
| | | |
| | | /// 问题列表 |
| | | class func commonQuestionDetailBy(id:Int)->Observable<BaseResponse<CommonQuestionModel>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | |
| | | var name:String? //名称 |
| | | var resource:String? //数据源:URL等 |
| | | var mediaType:CommonBannerView.MediaType? |
| | | var courseId:String? |
| | | } |
| | | |
| | | class CommonBannerView: UIView, UICollectionViewDelegate, UICollectionViewDataSource,UICollectionViewDelegateFlowLayout { |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> |
| | | <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23094" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> |
| | | <device id="retina6_12" orientation="portrait" appearance="light"/> |
| | | <dependencies> |
| | | <deployment identifier="iOS"/> |
| | | <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/> |
| | | <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23084"/> |
| | | <capability name="System colors in document resources" minToolsVersion="11.0"/> |
| | | <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> |
| | | </dependencies> |
| | |
| | | </constraints> |
| | | </view> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="心泉疗愈馆" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ej2-gY-nmo"> |
| | | <rect key="frame" x="26.666666666666671" y="346" width="102.00000000000001" height="24"/> |
| | | <rect key="frame" x="26.666666666666671" y="346" width="96" height="24"/> |
| | | <fontDescription key="fontDescription" type="system" weight="medium" pointSize="20"/> |
| | | <color key="textColor" red="0.039215686274509803" green="0.25882352941176467" blue="0.074509803921568626" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> |
| | | <nil key="highlightedColor"/> |
| | |
| | | </subviews> |
| | | </stackView> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="简介" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Dmh-Sc-k0l"> |
| | | <rect key="frame" x="26.666666666666671" y="484.33333333333331" width="41" height="24"/> |
| | | <rect key="frame" x="26.666666666666668" y="484.33333333333331" width="38.333333333333329" height="24"/> |
| | | <fontDescription key="fontDescription" type="system" weight="medium" pointSize="20"/> |
| | | <color key="textColor" red="0.039215686270000001" green="0.25882352939999997" blue="0.074509803920000006" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> |
| | | <nil key="highlightedColor"/> |
| | |
| | | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { |
| | | let model = viewModel!.dataSource.value!.list[indexPath.row] |
| | | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "_PavilionItemCell", for: indexPath) as! PavilionItemCell |
| | | cell.backgroundColor = .jq_randomColor |
| | | cell.jq_cornerRadius = 16 |
| | | cell.backgroundColor = .white |
| | | cell.setPavilionDetailModel(model) |
| | | return cell |
| | | } |
| | |
| | | |
| | | let PlantGuideQuit_Noti = Notification.Name.init(rawValue: "PlantGuideQuit_Noti") |
| | | |
| | | let backgroundVoiceUrl = "https://xqgwzh.obs.cn-south-1.myhuaweicloud.com/question/backgroundQuestion.wav" |
| | | |
| | | class PlanGuideVC: BaseVC { |
| | | |
| | | @IBOutlet weak var view_gradient: UIView! |
| | |
| | | @IBOutlet weak var label_subTitle: UILabel! |
| | | @IBOutlet weak var label_info: UILabel! |
| | | @IBOutlet weak var btn_custom: UIButton! |
| | | |
| | | private let masterPlayer = AudioPlayer.getSharedInstance() |
| | | |
| | | private lazy var player:AVPlayer = { |
| | | let bgPath = Bundle.main.url(forResource: "bg_movie", withExtension: "mov") |
| | |
| | | |
| | | override func viewDidLoad() { |
| | | super.viewDidLoad() |
| | | |
| | | masterPlayer.playBGMAt(firstPlayIndex: 0, model: MeditationModel(backgroundUrl:backgroundVoiceUrl), delegate: self) |
| | | } |
| | | |
| | | override func viewWillAppear(_ animated: Bool) { |
| | |
| | | self?.player.play() |
| | | } |
| | | |
| | | NotificationCenter.default.rx.notification(PlantGuideQuit_Noti).take(until: self.rx.deallocated).subscribe(onNext: {data in |
| | | NotificationCenter.default.rx.notification(PlantGuideQuit_Noti).take(until: self.rx.deallocated).subscribe(onNext: {[weak self]data in |
| | | if data.object as? Bool == true{ |
| | | |
| | | } |
| | | self.dismiss(animated: true) |
| | | self?.dismiss(animated: true) |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | @IBAction func customAction(_ sender: UIButton) { |
| | | PlanGuidePromptView.show { type in |
| | | PlanGuidePromptView.show {[weak self] type in |
| | | switch type { |
| | | case .seeOther: |
| | | let vc = PlanGuide_1_VC() |
| | | self.jq_push(vc: vc) |
| | | self?.jq_push(vc: vc) |
| | | case .toSeting: |
| | | self.dismiss(animated: true) { |
| | | self?.dismiss(animated: true) { |
| | | let vc = BackgroundVoiceVC() |
| | | vc.hidesBottomBarWhenPushed = true |
| | | JQ_currentNavigationController().pushViewController(vc) |
| | |
| | | } |
| | | } |
| | | } |
| | | |
| | | deinit{ |
| | | masterPlayer.clean() |
| | | } |
| | | } |
| | | |
| | | extension PlanGuideVC:PayMusicDelegate{ |
| | | func playState(_ state: PlayMusicState) { |
| | | |
| | | } |
| | | |
| | | } |
| | |
| | | @IBOutlet weak var btn_OnceInAWel: UIButton! |
| | | |
| | | private var questions = [String]() |
| | | private var questionIndex = -1 |
| | | private var questionIndex = 0 |
| | | |
| | | private var responseUserAnswerModel = ResponseUserAnswerModel() |
| | | |
| | |
| | | } |
| | | |
| | | @IBAction func nextAction(_ sender: UIButton) { |
| | | responseUserAnswerModel.tagsId = selectModels.map({"\($0.id)"}).joined(separator: ",") |
| | | responseUserAnswerModel.tagIds = selectModels.map({"\($0.id)"}).joined(separator: ",") |
| | | Services.saveUserAnswers(responseUserAnswerModel).subscribe(onNext: { data in |
| | | NotificationCenter.default.post(name: PlantGuideQuit_Noti, object: true) |
| | | }).disposed(by: disposeBag) |
| | |
| | | var new = self.dataSource.value?.list ?? [] |
| | | new.append(contentsOf: data.data?.list ?? []) |
| | | var model = self.dataSource.value |
| | | model!.list = new |
| | | model?.list = new |
| | | self.dataSource.accept(model) |
| | | if data.data?.list.count == 0{ |
| | | self.refreshSubject.onNext(.completedLoadWithNoMoreData) |
| | |
| | | import JQTools |
| | | import AuthenticationServices |
| | | |
| | | class SceneDelegate: UIResponder, UIWindowSceneDelegate { |
| | | class SceneDelegate: UIResponder, UIWindowSceneDelegate, WXApiDelegate{ |
| | | |
| | | var window: UIWindow? |
| | | |
| | |
| | | |
| | | } |
| | | |
| | | func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) { |
| | | |
| | | if URLContexts.first?.url.scheme == WeChatAPPID,let code = URLContexts.first?.url.jq_params?["code"]{ |
| | | DispatchQueue.main.async { |
| | | hiddenHUD() |
| | | let resp = SendAuthResp() |
| | | resp.code = code |
| | | WeChatTools.getAccessToken(resp) { model in |
| | | if let m = model{ |
| | | WeChatTools.getUserInfo(access_token: m.access_token, openId: m.openid) { userInfoModel in |
| | | if let u = userInfoModel{ |
| | | Services.loginByWechat(headImgUrl: u.headimgurl, nickname: u.nickname, sex: u.sex, wxOpenId: u.openid).subscribe(onNext: {data in |
| | | if let model = data.data{ |
| | | sceneDelegate?.loginSuccess() |
| | | JQ_currentViewController().dismiss(animated:true) |
| | | UserViewModel.saveLoginInfo(model) |
| | | |
| | | Services.getUserInfo().subscribe(onNext: {data in |
| | | if let model = data.data{ |
| | | UserViewModel.saveAvatarInfo(model) |
| | | } |
| | | }).disposed(by: JQ_disposeBag) |
| | | } |
| | | }).disposed(by: JQ_disposeBag) |
| | | }else{ |
| | | alertError(msg: "获取信息失败") |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | func scene(_ scene: UIScene, continue userActivity: NSUserActivity) { |
| | | WXApi.handleOpenUniversalLink(userActivity, delegate: self) |
| | | } |
| | | |
| | | 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. |
| | |
| | | // to restore the scene back to its current state. |
| | | } |
| | | |
| | | func onReq(_ req: BaseReq) { |
| | | |
| | | } |
| | | |
| | | func onResp(_ resp: BaseResp) { |
| | | |
| | | } |
| | | |
| | | } |
| | | |
| | |
| | | <array> |
| | | <string>Default</string> |
| | | </array> |
| | | <key>com.apple.developer.associated-domains</key> |
| | | <array> |
| | | <string>webcredentials:app.xqzhihui.com/app/</string> |
| | | </array> |
| | | </dict> |
| | | </plist> |