|
|
@ -0,0 +1,47 @@
|
||||||
|
# Xcode 编译产物
|
||||||
|
DerivedData/
|
||||||
|
build/
|
||||||
|
*.xcworkspace/
|
||||||
|
*.xcuserstate
|
||||||
|
*.xcuserdatad/
|
||||||
|
xcuserdata/
|
||||||
|
UserInterfaceState.xcuserstate
|
||||||
|
*.xccheckout
|
||||||
|
*.xcscmblueprint
|
||||||
|
*.xcscmblueprint
|
||||||
|
*.xcbkptn
|
||||||
|
*.xcbkptn/
|
||||||
|
|
||||||
|
# 模拟器缓存
|
||||||
|
~/Library/Developer/CoreSimulator/
|
||||||
|
CoreSimulator/
|
||||||
|
|
||||||
|
# Pods / Carthage / Swift Package Manager
|
||||||
|
Pods/
|
||||||
|
Podfile.lock
|
||||||
|
Carthage/Build/
|
||||||
|
Package/.build/
|
||||||
|
Package.resolved
|
||||||
|
|
||||||
|
# 隐私配置、密钥、本地环境文件
|
||||||
|
*.env
|
||||||
|
*.plist.local
|
||||||
|
*.entitlements.local
|
||||||
|
secret*.txt
|
||||||
|
key*.pem
|
||||||
|
*.p12
|
||||||
|
*.mobileprovision
|
||||||
|
|
||||||
|
# 本地缓存、日志
|
||||||
|
*.log
|
||||||
|
*.swp
|
||||||
|
*.DS_Store
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
node_modules/
|
||||||
|
npm-debug.log
|
||||||
|
|
||||||
|
# 图片临时导出、截图
|
||||||
|
*.png.orig
|
||||||
|
*.jpg.orig
|
||||||
|
screenshot/
|
||||||
|
|
@ -295,6 +295,8 @@
|
||||||
30EFF3E22FDA9DEE00EB35D4 /* EmergencyContactVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30EFF3E12FDA9DEE00EB35D4 /* EmergencyContactVM.swift */; };
|
30EFF3E22FDA9DEE00EB35D4 /* EmergencyContactVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30EFF3E12FDA9DEE00EB35D4 /* EmergencyContactVM.swift */; };
|
||||||
30EFF3E52FDAA93400EB35D4 /* PrivacyPolicyVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30EFF3E42FDAA93300EB35D4 /* PrivacyPolicyVC.swift */; };
|
30EFF3E52FDAA93400EB35D4 /* PrivacyPolicyVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30EFF3E42FDAA93300EB35D4 /* PrivacyPolicyVC.swift */; };
|
||||||
30EFF3E72FDAA93D00EB35D4 /* PrivacyPolicyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30EFF3E62FDAA93D00EB35D4 /* PrivacyPolicyView.swift */; };
|
30EFF3E72FDAA93D00EB35D4 /* PrivacyPolicyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30EFF3E62FDAA93D00EB35D4 /* PrivacyPolicyView.swift */; };
|
||||||
|
30EFF3E82FCA8C7000227D26 /* AuthenticationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 30EFF3E92FCA8C7000227D26 /* AuthenticationServices.framework */; };
|
||||||
|
55BF752D2FFE53F70055DA57 /* LocationPermissionPopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55BF752C2FFE53F70055DA57 /* LocationPermissionPopView.swift */; };
|
||||||
D698E9C56D6F2C152772131D /* Pods_QuickLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 475D33CAFA1E1911EB1F8D9F /* Pods_QuickLocation.framework */; };
|
D698E9C56D6F2C152772131D /* Pods_QuickLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 475D33CAFA1E1911EB1F8D9F /* Pods_QuickLocation.framework */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
|
@ -598,8 +600,10 @@
|
||||||
30EFF3E12FDA9DEE00EB35D4 /* EmergencyContactVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmergencyContactVM.swift; sourceTree = "<group>"; };
|
30EFF3E12FDA9DEE00EB35D4 /* EmergencyContactVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmergencyContactVM.swift; sourceTree = "<group>"; };
|
||||||
30EFF3E42FDAA93300EB35D4 /* PrivacyPolicyVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyPolicyVC.swift; sourceTree = "<group>"; };
|
30EFF3E42FDAA93300EB35D4 /* PrivacyPolicyVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyPolicyVC.swift; sourceTree = "<group>"; };
|
||||||
30EFF3E62FDAA93D00EB35D4 /* PrivacyPolicyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyPolicyView.swift; sourceTree = "<group>"; };
|
30EFF3E62FDAA93D00EB35D4 /* PrivacyPolicyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyPolicyView.swift; sourceTree = "<group>"; };
|
||||||
|
30EFF3E92FCA8C7000227D26 /* AuthenticationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AuthenticationServices.framework; path = System/Library/Frameworks/AuthenticationServices.framework; sourceTree = SDKROOT; };
|
||||||
3E4359082FC48D26003470A5 /* QuickLocation.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = QuickLocation.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
3E4359082FC48D26003470A5 /* QuickLocation.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = QuickLocation.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
475D33CAFA1E1911EB1F8D9F /* Pods_QuickLocation.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_QuickLocation.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
475D33CAFA1E1911EB1F8D9F /* Pods_QuickLocation.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_QuickLocation.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
55BF752C2FFE53F70055DA57 /* LocationPermissionPopView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPermissionPopView.swift; sourceTree = "<group>"; };
|
||||||
DA16D49AA46D4F6838340B55 /* Pods-QuickLocation.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-QuickLocation.debug.xcconfig"; path = "Target Support Files/Pods-QuickLocation/Pods-QuickLocation.debug.xcconfig"; sourceTree = "<group>"; };
|
DA16D49AA46D4F6838340B55 /* Pods-QuickLocation.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-QuickLocation.debug.xcconfig"; path = "Target Support Files/Pods-QuickLocation/Pods-QuickLocation.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
E483B9929C03809ADEDE8341 /* Pods-QuickLocation.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-QuickLocation.release.xcconfig"; path = "Target Support Files/Pods-QuickLocation/Pods-QuickLocation.release.xcconfig"; sourceTree = "<group>"; };
|
E483B9929C03809ADEDE8341 /* Pods-QuickLocation.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-QuickLocation.release.xcconfig"; path = "Target Support Files/Pods-QuickLocation/Pods-QuickLocation.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
@ -632,6 +636,7 @@
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
30EFF3E82FCA8C7000227D26 /* AuthenticationServices.framework in Frameworks */,
|
||||||
D698E9C56D6F2C152772131D /* Pods_QuickLocation.framework in Frameworks */,
|
D698E9C56D6F2C152772131D /* Pods_QuickLocation.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
|
@ -1007,6 +1012,7 @@
|
||||||
30A7A9102FCAEE3D00105780 /* GroupListPopView.swift */,
|
30A7A9102FCAEE3D00105780 /* GroupListPopView.swift */,
|
||||||
30D87CDE2FDFF1A100E958FD /* QuickMessageView.swift */,
|
30D87CDE2FDFF1A100E958FD /* QuickMessageView.swift */,
|
||||||
30D87CDC2FDFF07500E958FD /* InteractionView.swift */,
|
30D87CDC2FDFF07500E958FD /* InteractionView.swift */,
|
||||||
|
55BF752C2FFE53F70055DA57 /* LocationPermissionPopView.swift */,
|
||||||
30A87A692FEF59E60095E7C6 /* SearchLocation */,
|
30A87A692FEF59E60095E7C6 /* SearchLocation */,
|
||||||
30A87A5C2FEE711C0095E7C6 /* Bubble */,
|
30A87A5C2FEE711C0095E7C6 /* Bubble */,
|
||||||
30CCDE4F2FE2782700F5214A /* SignIn */,
|
30CCDE4F2FE2782700F5214A /* SignIn */,
|
||||||
|
|
@ -1648,6 +1654,7 @@
|
||||||
47CD8471BE2146A2656CF27E /* Frameworks */ = {
|
47CD8471BE2146A2656CF27E /* Frameworks */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
30EFF3E92FCA8C7000227D26 /* AuthenticationServices.framework */,
|
||||||
475D33CAFA1E1911EB1F8D9F /* Pods_QuickLocation.framework */,
|
475D33CAFA1E1911EB1F8D9F /* Pods_QuickLocation.framework */,
|
||||||
);
|
);
|
||||||
name = Frameworks;
|
name = Frameworks;
|
||||||
|
|
@ -2067,6 +2074,7 @@
|
||||||
30BF30102FED0C8E00D9CB52 /* ScheduleDetailVM.swift in Sources */,
|
30BF30102FED0C8E00D9CB52 /* ScheduleDetailVM.swift in Sources */,
|
||||||
30DA36BD2FECC5AB008D5A2C /* CreateScheduleVipPopView.swift in Sources */,
|
30DA36BD2FECC5AB008D5A2C /* CreateScheduleVipPopView.swift in Sources */,
|
||||||
305A77082FCA8C7000227D26 /* PageCollectionViewFlowLayout.swift in Sources */,
|
305A77082FCA8C7000227D26 /* PageCollectionViewFlowLayout.swift in Sources */,
|
||||||
|
55BF752D2FFE53F70055DA57 /* LocationPermissionPopView.swift in Sources */,
|
||||||
3062E8C42FCFC90F00CEF511 /* CreateGroupVipPopView.swift in Sources */,
|
3062E8C42FCFC90F00CEF511 /* CreateGroupVipPopView.swift in Sources */,
|
||||||
30D74ABA2FEA37AD0050EB2C /* ScheduleModel.swift in Sources */,
|
30D74ABA2FEA37AD0050EB2C /* ScheduleModel.swift in Sources */,
|
||||||
30CCDE512FE2785D00F5214A /* SignInVC.swift in Sources */,
|
30CCDE512FE2785D00F5214A /* SignInVC.swift in Sources */,
|
||||||
|
|
@ -2130,9 +2138,11 @@
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
CODE_SIGN_ENTITLEMENTS = QuickLocation/QuickLocation.entitlements;
|
CODE_SIGN_ENTITLEMENTS = QuickLocation/QuickLocation.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
DEVELOPMENT_TEAM = XSJJKSY9FB;
|
DEVELOPMENT_TEAM = "";
|
||||||
|
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = LRDLWZ2Y83;
|
||||||
ENABLE_USER_SCRIPT_SANDBOXING = "$(inherited)";
|
ENABLE_USER_SCRIPT_SANDBOXING = "$(inherited)";
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = QuickLocation/Info.plist;
|
INFOPLIST_FILE = QuickLocation/Info.plist;
|
||||||
|
|
@ -2153,9 +2163,10 @@
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = cn.zuom8.jisuloca;
|
PRODUCT_BUNDLE_IDENTIFIER = cn.zuomeng.jisuloca;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = jsdw_dev;
|
||||||
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||||
SUPPORTS_MACCATALYST = NO;
|
SUPPORTS_MACCATALYST = NO;
|
||||||
|
|
@ -2179,9 +2190,11 @@
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
CODE_SIGN_ENTITLEMENTS = QuickLocation/QuickLocation.entitlements;
|
CODE_SIGN_ENTITLEMENTS = QuickLocation/QuickLocation.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
DEVELOPMENT_TEAM = XSJJKSY9FB;
|
DEVELOPMENT_TEAM = "";
|
||||||
|
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = LRDLWZ2Y83;
|
||||||
ENABLE_USER_SCRIPT_SANDBOXING = "$(inherited)";
|
ENABLE_USER_SCRIPT_SANDBOXING = "$(inherited)";
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = QuickLocation/Info.plist;
|
INFOPLIST_FILE = QuickLocation/Info.plist;
|
||||||
|
|
@ -2202,9 +2215,10 @@
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = cn.zuom8.jisuloca;
|
PRODUCT_BUNDLE_IDENTIFIER = cn.zuomeng.jisuloca;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = jsdw_dev;
|
||||||
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||||
SUPPORTS_MACCATALYST = NO;
|
SUPPORTS_MACCATALYST = NO;
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,16 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
|
|
||||||
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
|
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
|
||||||
print("📱 application open url: \(url.absoluteString) host: \(url.host ?? "")")
|
print("📱 application open url: \(url.absoluteString) host: \(url.host ?? "")")
|
||||||
|
|
||||||
|
// 微信 OAuth 回调:直接从 URL 提取 code,不依赖 SDK 异步 onResp
|
||||||
|
if let scheme = url.scheme, scheme == "wx\(AppSettings.kAppsWXApiAppId)" || scheme == AppSettings.kAppsWXApiAppId {
|
||||||
|
if let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
|
||||||
|
let code = components.queryItems?.first(where: { $0.name == "code" })?.value {
|
||||||
|
handleWechatLoginCode(code)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 处理支付宝支付结果(不限制 host,适应新版 SDK)
|
// 处理支付宝支付结果(不限制 host,适应新版 SDK)
|
||||||
if url.scheme?.hasPrefix("Alipay") == true || url.host == "safepay" {
|
if url.scheme?.hasPrefix("Alipay") == true || url.host == "safepay" {
|
||||||
AlipaySDK.defaultService().processOrder(withPaymentResult: url) { resultDic in
|
AlipaySDK.defaultService().processOrder(withPaymentResult: url) { resultDic in
|
||||||
|
|
@ -81,11 +91,18 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
else if url.host == "pay" {
|
// else if url.host == "pay" {
|
||||||
return WXApi.handleOpen(url, delegate: self)
|
return WXApi.handleOpen(url, delegate: self)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
// return true
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
func application(_ application: UIApplication,
|
||||||
|
continue userActivity: NSUserActivity,
|
||||||
|
restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
|
||||||
|
print("📱 continue userActivity: \(userActivity.webpageURL?.absoluteString ?? "")")
|
||||||
|
return WXApi.handleOpenUniversalLink(userActivity, delegate: self)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupLocation() {
|
func setupLocation() {
|
||||||
|
|
@ -140,11 +157,37 @@ extension AppDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension AppDelegate: WXApiDelegate {
|
extension AppDelegate: WXApiDelegate {
|
||||||
|
private var handledWechatLoginCode: String? {
|
||||||
|
get { objc_getAssociatedObject(self, &AssociatedKeys.handledWechatLoginCode) as? String }
|
||||||
|
set { objc_setAssociatedObject(self, &AssociatedKeys.handledWechatLoginCode, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct AssociatedKeys {
|
||||||
|
static var handledWechatLoginCode: Void?
|
||||||
|
}
|
||||||
|
|
||||||
|
private func handleWechatLoginCode(_ code: String) {
|
||||||
|
guard code != handledWechatLoginCode else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
handledWechatLoginCode = code
|
||||||
|
LoginSessionHandler.login(type: "weixin", data: ["code": code, "code_type": ""])
|
||||||
|
}
|
||||||
|
|
||||||
func onReq(_ req: BaseReq) {
|
func onReq(_ req: BaseReq) {
|
||||||
print(req)
|
print(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func onResp(_ resp: BaseResp) {
|
func onResp(_ resp: BaseResp) {
|
||||||
|
if let authResp = resp as? SendAuthResp, authResp.errCode == 0, let code = authResp.code {
|
||||||
|
handleWechatLoginCode(code)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.isKind(of: SendAuthResp.self) {
|
||||||
|
NotificationCenter.default.post(name: .resumePopupQueue, object: nil)
|
||||||
|
}
|
||||||
|
|
||||||
if resp.isKind(of: PayResp.self),
|
if resp.isKind(of: PayResp.self),
|
||||||
let response: PayResp = resp as? PayResp {
|
let response: PayResp = resp as? PayResp {
|
||||||
print("===================== WxPay =====================")
|
print("===================== WxPay =====================")
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "permission_text@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "permission_text@3x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
QuickLocation/Assets.xcassets/Home/permission_text.imageset/permission_text@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
QuickLocation/Assets.xcassets/Home/permission_text.imageset/permission_text@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 76 KiB |
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Group 1919@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Group 1919@3x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 8.1 KiB |
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Group_2220@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Group_2220@3x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 7.9 KiB |
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "mask_bg@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "mask_bg@3x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 109 KiB |
|
After Width: | Height: | Size: 243 KiB |
|
|
@ -21,6 +21,8 @@ extension DefaultsKeys {
|
||||||
var isReLogin: DefaultsKey<Bool> { .init("isReLogin", defaultValue: false) }
|
var isReLogin: DefaultsKey<Bool> { .init("isReLogin", defaultValue: false) }
|
||||||
/// 显示引导页
|
/// 显示引导页
|
||||||
var isShowGuide: DefaultsKey<Bool> { .init("isShowGuide", defaultValue: true) }
|
var isShowGuide: DefaultsKey<Bool> { .init("isShowGuide", defaultValue: true) }
|
||||||
|
/// 气泡持续时间
|
||||||
|
var bubbleKeepTimes: DefaultsKey<Date?> { .init("bubbleKeepTimes") }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 通知常量
|
/// 通知常量
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,21 @@ class AppContextManager: NSObject {
|
||||||
public func saveToken(_ token: String) {
|
public func saveToken(_ token: String) {
|
||||||
Defaults[\.loginToken] = token
|
Defaults[\.loginToken] = token
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 状态:0、无状态 1、SOS 2、气泡等
|
||||||
|
public func updateAccountStatus(_ status: Int) {
|
||||||
|
guard var account = self.account else { return }
|
||||||
|
account.status = status
|
||||||
|
saveAccount(account)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 心情:0、无状态 1、开心 2、愤怒
|
||||||
|
public func updateAccountMood(_ mood: Int) {
|
||||||
|
guard var account = self.account else { return }
|
||||||
|
account.mood = mood
|
||||||
|
saveAccount(account)
|
||||||
|
}
|
||||||
|
|
||||||
public func deleteAccount() {
|
public func deleteAccount() {
|
||||||
Defaults[\.loginToken] = nil
|
Defaults[\.loginToken] = nil
|
||||||
Defaults[\.userConfig] = nil
|
Defaults[\.userConfig] = nil
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,12 @@ struct SystemConfigModel: Mappable {
|
||||||
/// 圈子里的banner
|
/// 圈子里的banner
|
||||||
var groupBannerList: [String] = []
|
var groupBannerList: [String] = []
|
||||||
|
|
||||||
|
/// 引导页显示开关
|
||||||
|
var guideDisplay: Bool = true
|
||||||
|
|
||||||
|
/// 全局控制显示隐藏 弹窗和充值
|
||||||
|
var globalDisplay: Bool = true
|
||||||
|
|
||||||
init?(map: Map) {
|
init?(map: Map) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -87,15 +93,17 @@ struct SystemConfigModel: Mappable {
|
||||||
popupConfig <- map["client.popup.display", nested: false]
|
popupConfig <- map["client.popup.display", nested: false]
|
||||||
timeConfig <- map["client.time.setting", nested: false]
|
timeConfig <- map["client.time.setting", nested: false]
|
||||||
shareConfig <- map["client.weixin.share", nested: false]
|
shareConfig <- map["client.weixin.share", nested: false]
|
||||||
|
guideDisplay <- map["client.guide_display", nested: false]
|
||||||
|
globalDisplay <- map["client.global_display", nested: false]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PopupWindowConfigModel: Mappable {
|
struct PopupWindowConfigModel: Mappable {
|
||||||
/// 是否弹vip弹窗
|
/// 是否弹vip弹窗
|
||||||
var pay_pop: Bool = false
|
var pay_pop: Bool = true
|
||||||
|
|
||||||
/// 搜索位置弹窗
|
/// 搜索位置弹窗
|
||||||
var search_phone: Bool = false
|
var search_phone: Bool = true
|
||||||
|
|
||||||
|
|
||||||
init?(map: Map) {
|
init?(map: Map) {
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,9 @@ import Moya
|
||||||
import SwiftyJSON
|
import SwiftyJSON
|
||||||
import RxSwift
|
import RxSwift
|
||||||
import CommonCrypto
|
import CommonCrypto
|
||||||
|
#if !targetEnvironment(simulator)
|
||||||
|
import GeYanSdk
|
||||||
|
#endif
|
||||||
|
|
||||||
class ApiManager: NSObject {
|
class ApiManager: NSObject {
|
||||||
|
|
||||||
|
|
@ -158,6 +161,7 @@ extension ApiManager {
|
||||||
private func handleTokenExpired(msg: String?) {
|
private func handleTokenExpired(msg: String?) {
|
||||||
MainAsync {
|
MainAsync {
|
||||||
NotificationCenter.default.post(name: .invalidatePopupQueue, object: nil)
|
NotificationCenter.default.post(name: .invalidatePopupQueue, object: nil)
|
||||||
|
GeYanSdk.deletePreResultCache()
|
||||||
AppContextManager.shared.deleteAccount()
|
AppContextManager.shared.deleteAccount()
|
||||||
GroupIMService.shared.logout()
|
GroupIMService.shared.logout()
|
||||||
DLToast.showError(text: msg ?? "登录失效,请重新登录!") {
|
DLToast.showError(text: msg ?? "登录失效,请重新登录!") {
|
||||||
|
|
|
||||||
|
|
@ -183,6 +183,8 @@ struct GroupMemberModel: Mappable, Equatable {
|
||||||
}
|
}
|
||||||
return UIImage(named: "VipIcon/\(level)") ?? UIImage()
|
return UIImage(named: "VipIcon/\(level)") ?? UIImage()
|
||||||
}
|
}
|
||||||
|
/// 状态:0、无状态 1、SOS 2、气泡等
|
||||||
|
var status: Int = 0
|
||||||
/// 是否在线
|
/// 是否在线
|
||||||
var is_online: Bool = false
|
var is_online: Bool = false
|
||||||
/// 设备电量
|
/// 设备电量
|
||||||
|
|
@ -228,6 +230,7 @@ struct GroupMemberModel: Mappable, Equatable {
|
||||||
last_position <- map["last_position"]
|
last_position <- map["last_position"]
|
||||||
is_online <- map["is_online"]
|
is_online <- map["is_online"]
|
||||||
last_active_time <- map["last_active_time"]
|
last_active_time <- map["last_active_time"]
|
||||||
|
status <- map["status"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,10 @@
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
|
<key>com.apple.developer.applesignin</key>
|
||||||
|
<array>
|
||||||
|
<string>Default</string>
|
||||||
|
</array>
|
||||||
<key>com.apple.developer.associated-domains</key>
|
<key>com.apple.developer.associated-domains</key>
|
||||||
<array>
|
<array>
|
||||||
<string>applinks:smartdrive.zuom8.cn</string>
|
<string>applinks:smartdrive.zuom8.cn</string>
|
||||||
|
|
|
||||||
|
|
@ -398,9 +398,9 @@ class CreateGroupView: UIView {
|
||||||
lazy var submitBtn: UIButton = {
|
lazy var submitBtn: UIButton = {
|
||||||
let btn = UIButton(type: .custom)
|
let btn = UIButton(type: .custom)
|
||||||
btn.setTitle("创建", for: .normal)
|
btn.setTitle("创建", for: .normal)
|
||||||
btn.setTitleColor(UIColor(hexStr: "#0F2846"), for: .normal)
|
btn.setTitleColor(.white, for: .normal)
|
||||||
btn.titleLabel?.font = .systemFont(ofSize: 16, weight: .medium)
|
btn.titleLabel?.font = .systemFont(ofSize: 16, weight: .medium)
|
||||||
btn.setBackgroundImage(UIImage(named: "Common/gradient_bg"), for: .normal)
|
btn.setBackgroundImage(UIImage(named: "Common/button_bg_2"), for: .normal)
|
||||||
btn.cornerRadius = 25
|
btn.cornerRadius = 25
|
||||||
|
|
||||||
return btn
|
return btn
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,8 @@ class CreateGroupViewModel {
|
||||||
}
|
}
|
||||||
}, onError: { (error) in
|
}, onError: { (error) in
|
||||||
guard let code = error.underlyingError?.code else { return }
|
guard let code = error.underlyingError?.code else { return }
|
||||||
|
|
||||||
|
guard let systemConfig = AppContextManager.shared.systemConfig, systemConfig.globalDisplay else { return }
|
||||||
if code == 20009 { // "您创建的圈子个数已达上限,请升级会员等级"
|
if code == 20009 { // "您创建的圈子个数已达上限,请升级会员等级"
|
||||||
CreateGroupVipPopView.show()
|
CreateGroupVipPopView.show()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,10 @@ final class GroupChatVC: BaseViewController {
|
||||||
|
|
||||||
// 并行加载:业务接口 + IM SDK 互不依赖,同时发起
|
// 并行加载:业务接口 + IM SDK 互不依赖,同时发起
|
||||||
requestGroupInfoByKey()
|
requestGroupInfoByKey()
|
||||||
viewModel.loadMessages()
|
GroupIMService.shared.ensureLogin { [weak self] success in
|
||||||
|
guard let self = self, success else { return }
|
||||||
|
self.viewModel.loadMessages()
|
||||||
|
}
|
||||||
|
|
||||||
// 处理系统配置
|
// 处理系统配置
|
||||||
guard let config = AppContextManager.shared.systemConfig else { return }
|
guard let config = AppContextManager.shared.systemConfig else { return }
|
||||||
|
|
@ -96,7 +99,7 @@ final class GroupChatVC: BaseViewController {
|
||||||
// 收起表情/语音面板
|
// 收起表情/语音面板
|
||||||
self.rootView.dismissAllPanels(excludeTextField: true)
|
self.rootView.dismissAllPanels(excludeTextField: true)
|
||||||
UIView.animate(withDuration: duration) {
|
UIView.animate(withDuration: duration) {
|
||||||
self.rootView.bottomBar.layoutChain.bottom(height + kSafeBottomMargin + 20)
|
self.rootView.bottomBar.layoutChain.bottom(height + 20)
|
||||||
}
|
}
|
||||||
self.scrollToBottom()
|
self.scrollToBottom()
|
||||||
})
|
})
|
||||||
|
|
@ -151,7 +154,7 @@ final class GroupChatVC: BaseViewController {
|
||||||
private func scrollToBottom() {
|
private func scrollToBottom() {
|
||||||
let count = dataSource.sectionModels.first?.items.count ?? 0
|
let count = dataSource.sectionModels.first?.items.count ?? 0
|
||||||
guard count > 0 else { return }
|
guard count > 0 else { return }
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
DispatchQueue.main.async {
|
||||||
self.rootView.tableView.layoutIfNeeded()
|
self.rootView.tableView.layoutIfNeeded()
|
||||||
let indexPath = IndexPath(row: count - 1, section: 0)
|
let indexPath = IndexPath(row: count - 1, section: 0)
|
||||||
self.rootView.tableView.scrollToRow(at: indexPath, at: .bottom, animated: false)
|
self.rootView.tableView.scrollToRow(at: indexPath, at: .bottom, animated: false)
|
||||||
|
|
@ -292,7 +295,7 @@ final class GroupChatVC: BaseViewController {
|
||||||
let offset: CGFloat = show ? 252 : 0
|
let offset: CGFloat = show ? 252 : 0
|
||||||
UIView.animate(withDuration: 0.25) {
|
UIView.animate(withDuration: 0.25) {
|
||||||
self.rootView.bottomBar.layoutChain.bottom(show ? offset - self.rootView.bottomBar.dl.height : kSafeBottomMargin + 20)
|
self.rootView.bottomBar.layoutChain.bottom(show ? offset - self.rootView.bottomBar.dl.height : kSafeBottomMargin + 20)
|
||||||
self.rootView.voiceRecordView.layoutChain.bottom(offset - 252 + kSafeBottomMargin)
|
self.rootView.voiceRecordView.layoutChain.bottom(offset - 252)
|
||||||
}
|
}
|
||||||
scrollToBottom()
|
scrollToBottom()
|
||||||
}
|
}
|
||||||
|
|
@ -306,7 +309,7 @@ final class GroupChatVC: BaseViewController {
|
||||||
self.rootView.emojiPanelView.isHidden = !show
|
self.rootView.emojiPanelView.isHidden = !show
|
||||||
let offset: CGFloat = show ? 220 : 0
|
let offset: CGFloat = show ? 220 : 0
|
||||||
UIView.animate(withDuration: 0.25) {
|
UIView.animate(withDuration: 0.25) {
|
||||||
self.rootView.bottomBar.layoutChain.bottom(kSafeBottomMargin + 20 + offset)
|
self.rootView.bottomBar.layoutChain.bottom(20 + offset)
|
||||||
}
|
}
|
||||||
// completion: { _ in
|
// completion: { _ in
|
||||||
// let offset: CGFloat = self.rootView.tableView.contentSize.height
|
// let offset: CGFloat = self.rootView.tableView.contentSize.height
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,8 @@ class GroupMemberListVC: BaseViewController {
|
||||||
|
|
||||||
override func viewWillAppear(_ animated: Bool) {
|
override func viewWillAppear(_ animated: Bool) {
|
||||||
super.viewWillAppear(animated)
|
super.viewWillAppear(animated)
|
||||||
|
|
||||||
|
guard let systemConfig = AppContextManager.shared.systemConfig, systemConfig.globalDisplay else { return }
|
||||||
rootView.unlockVipMaskView.isHidden = AppContextManager.shared.vip > 1
|
rootView.unlockVipMaskView.isHidden = AppContextManager.shared.vip > 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -220,7 +220,9 @@ final class GroupViewController: BaseViewController {
|
||||||
GroupService.groupInfo().subscribe { response in
|
GroupService.groupInfo().subscribe { response in
|
||||||
guard let model = response.model else { return }
|
guard let model = response.model else { return }
|
||||||
self.viewModel.groupList = model.groups
|
self.viewModel.groupList = model.groups
|
||||||
self.loadIMData()
|
DispatchQueue.global(qos: .default).async { [weak self] in
|
||||||
|
self?.loadIMData()
|
||||||
|
}
|
||||||
}.disposed(by: disposeBag)
|
}.disposed(by: disposeBag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import UIKit
|
||||||
import ObjectMapper
|
import ObjectMapper
|
||||||
import RxSwift
|
import RxSwift
|
||||||
import RxCocoa
|
import RxCocoa
|
||||||
|
import Kingfisher
|
||||||
|
|
||||||
class InviteJoinVC: BaseViewController {
|
class InviteJoinVC: BaseViewController {
|
||||||
|
|
||||||
|
|
@ -30,6 +31,62 @@ class InviteJoinVC: BaseViewController {
|
||||||
rootView.shareAppBtn.rx.tap.subscribe(onNext: { _ in
|
rootView.shareAppBtn.rx.tap.subscribe(onNext: { _ in
|
||||||
SharePopView.show()
|
SharePopView.show()
|
||||||
}).disposed(by: disposeBag)
|
}).disposed(by: disposeBag)
|
||||||
|
|
||||||
|
rootView.shareCodeBtn.rx.tap.subscribe(onNext: { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
guard let config = AppContextManager.shared.systemConfig,
|
||||||
|
let shareConfig = config.shareConfig else { return }
|
||||||
|
|
||||||
|
DLToast.showLoading()
|
||||||
|
|
||||||
|
let fallbackImage = UIImage(named: "Common/logo108")
|
||||||
|
let imageURL: URL? = {
|
||||||
|
if shareConfig.image.isEmpty { return nil }
|
||||||
|
return URL(string: shareConfig.image)
|
||||||
|
}()
|
||||||
|
|
||||||
|
let sendMessage: (UIImage?) -> Void = { [weak self] thumbImage in
|
||||||
|
guard let self = self else { return }
|
||||||
|
DLToast.dismiss()
|
||||||
|
|
||||||
|
guard let screenshot = self.rootView.inviteInfoView.takeScreenshot(),
|
||||||
|
let imageData = screenshot.pngData() else {
|
||||||
|
DLToast.showError(text: "分享失败")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let message = WXMediaMessage()
|
||||||
|
message.title = "邀请加入圈子"
|
||||||
|
message.description = shareConfig.content
|
||||||
|
if let thumb = thumbImage {
|
||||||
|
message.setThumbImage(thumb)
|
||||||
|
}
|
||||||
|
|
||||||
|
let imageObject = WXImageObject()
|
||||||
|
imageObject.imageData = imageData
|
||||||
|
message.mediaObject = imageObject
|
||||||
|
|
||||||
|
let req = SendMessageToWXReq()
|
||||||
|
req.bText = false
|
||||||
|
req.message = message
|
||||||
|
req.scene = 0
|
||||||
|
|
||||||
|
WXApi.send(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let url = imageURL {
|
||||||
|
KingfisherManager.shared.retrieveImage(with: url) { result in
|
||||||
|
switch result {
|
||||||
|
case .success(let value):
|
||||||
|
sendMessage(value.image)
|
||||||
|
case .failure:
|
||||||
|
sendMessage(fallbackImage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sendMessage(fallbackImage)
|
||||||
|
}
|
||||||
|
}).disposed(by: disposeBag)
|
||||||
|
|
||||||
guard let model = groupInModel else { return }
|
guard let model = groupInModel else { return }
|
||||||
rootView.groupIcon.image = model.groupIcon
|
rootView.groupIcon.image = model.groupIcon
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ class InviteJoinView: UIView {
|
||||||
inviteInfoView.layoutChain
|
inviteInfoView.layoutChain
|
||||||
.topToBottomOfView(groupIcon, offset: 50)
|
.topToBottomOfView(groupIcon, offset: 50)
|
||||||
.edgesHorzontal(30)
|
.edgesHorzontal(30)
|
||||||
.bottomToTopOfView(shareAppBtn, offset: -32)
|
// .bottomToTopOfView(shareAppBtn, offset: -32)
|
||||||
|
|
||||||
inviteInfoTitleLab.layoutChain
|
inviteInfoTitleLab.layoutChain
|
||||||
.top(20)
|
.top(20)
|
||||||
|
|
@ -265,10 +265,9 @@ class InviteJoinView: UIView {
|
||||||
lazy var shareCodeBtn: UIButton = {
|
lazy var shareCodeBtn: UIButton = {
|
||||||
let btn = UIButton(type: .custom)
|
let btn = UIButton(type: .custom)
|
||||||
btn.setTitle("分享邀请码", for: .normal)
|
btn.setTitle("分享邀请码", for: .normal)
|
||||||
|
btn.setTitleColor(.white, for: .normal)
|
||||||
btn.titleLabel?.font = .systemFont(ofSize: 16, weight: .medium)
|
btn.titleLabel?.font = .systemFont(ofSize: 16, weight: .medium)
|
||||||
btn.setTitleColor(UIColor(hexStr: "#0F2846"), for: .normal)
|
btn.setBackgroundImage(UIImage(named: "Common/button_bg_2"), for: .normal)
|
||||||
btn.backgroundColor = .clear
|
|
||||||
btn.setBackgroundImage(UIImage(named: "Common/gradient_bg"), for: .normal)
|
|
||||||
btn.cornerRadius = 25
|
btn.cornerRadius = 25
|
||||||
return btn
|
return btn
|
||||||
}()
|
}()
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
import UIKit
|
import UIKit
|
||||||
import RxSwift
|
import RxSwift
|
||||||
import RxCocoa
|
import RxCocoa
|
||||||
|
import SwiftyUserDefaults
|
||||||
|
|
||||||
class CreateBubbleVC: BaseViewController {
|
class CreateBubbleVC: BaseViewController {
|
||||||
|
|
||||||
|
|
@ -31,6 +32,13 @@ class CreateBubbleVC: BaseViewController {
|
||||||
|
|
||||||
doneBtn.rx.tap.subscribe(onNext: { [weak self] in
|
doneBtn.rx.tap.subscribe(onNext: { [weak self] in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
guard let systemConfig = AppContextManager.shared.systemConfig, systemConfig.globalDisplay else {
|
||||||
|
let hours = self.rootView.createBubbleTiemView.selectedHour.value
|
||||||
|
requestSetBubble(enable: true, keep_time: hours)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if AppContextManager.shared.vip > 1 {
|
if AppContextManager.shared.vip > 1 {
|
||||||
let hours = self.rootView.createBubbleTiemView.selectedHour.value
|
let hours = self.rootView.createBubbleTiemView.selectedHour.value
|
||||||
requestSetBubble(enable: true, keep_time: hours)
|
requestSetBubble(enable: true, keep_time: hours)
|
||||||
|
|
@ -49,6 +57,13 @@ class CreateBubbleVC: BaseViewController {
|
||||||
self.requestSetBubble(enable: false, keep_time: -1)
|
self.requestSetBubble(enable: false, keep_time: -1)
|
||||||
}, cancelText: "取消")
|
}, cancelText: "取消")
|
||||||
}).disposed(by: disposeBag)
|
}).disposed(by: disposeBag)
|
||||||
|
|
||||||
|
guard AppContextManager.shared.status == 2, let endDate = Defaults[\.bubbleKeepTimes] else { return }
|
||||||
|
self.rootView.navTitleLabel.text = "活动气泡"
|
||||||
|
self.rootView.createBubbleDoneView.messageLab.text = self.rootView.createBubbleTipsView.messageText
|
||||||
|
self.rootView.createBubbleTipsView.isHidden = true
|
||||||
|
self.rootView.createBubbleDoneView.isHidden = false
|
||||||
|
self.rootView.createBubbleDoneView.startCountdown(endDate: endDate)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func requestSetBubble(enable: Bool, keep_time: Int) {
|
private func requestSetBubble(enable: Bool, keep_time: Int) {
|
||||||
|
|
@ -57,13 +72,17 @@ class CreateBubbleVC: BaseViewController {
|
||||||
DLToast.dismiss()
|
DLToast.dismiss()
|
||||||
guard enable else {
|
guard enable else {
|
||||||
DLToast.show(text: "气泡已弹出") {
|
DLToast.show(text: "气泡已弹出") {
|
||||||
|
Defaults[\.bubbleKeepTimes] = nil
|
||||||
|
AppContextManager.shared.updateAccountStatus(0)
|
||||||
AppRouter.shared.popOrDismiss()
|
AppRouter.shared.popOrDismiss()
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
AppContextManager.shared.updateAccountStatus(2)
|
||||||
self.rootView.navTitleLabel.text = "活动气泡"
|
self.rootView.navTitleLabel.text = "活动气泡"
|
||||||
self.rootView.createBubbleDoneView.messageLab.text = self.rootView.createBubbleTipsView.messageText
|
self.rootView.createBubbleDoneView.messageLab.text = self.rootView.createBubbleTipsView.messageText
|
||||||
let endDate = Calendar.current.date(byAdding: .hour, value: keep_time, to: Date()) ?? Date()
|
let endDate = Calendar.current.date(byAdding: .hour, value: keep_time, to: Date()) ?? Date()
|
||||||
|
Defaults[\.bubbleKeepTimes] = endDate
|
||||||
self.rootView.createBubbleDoneView.startCountdown(endDate: endDate)
|
self.rootView.createBubbleDoneView.startCountdown(endDate: endDate)
|
||||||
self.rootView.createBubbleTipsView.isHidden = true
|
self.rootView.createBubbleTipsView.isHidden = true
|
||||||
self.rootView.createBubbleDoneView.isHidden = false
|
self.rootView.createBubbleDoneView.isHidden = false
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import UIKit
|
||||||
import UIKit
|
import UIKit
|
||||||
import RxSwift
|
import RxSwift
|
||||||
import RxCocoa
|
import RxCocoa
|
||||||
|
import Lottie
|
||||||
|
|
||||||
class GroupMemberView: UIView {
|
class GroupMemberView: UIView {
|
||||||
|
|
||||||
|
|
@ -184,6 +185,13 @@ class GroupMemberCell: UITableViewCell {
|
||||||
onlineStatusLab.text = model.lastUpdateText
|
onlineStatusLab.text = model.lastUpdateText
|
||||||
onlineStatusLab.textColor = UIColor(hexStr: "#999999")
|
onlineStatusLab.textColor = UIColor(hexStr: "#999999")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sos
|
||||||
|
sosLottieView.isHidden = model.status != 1
|
||||||
|
model.status == 1 ? sosLottieView.play() : sosLottieView.stop()
|
||||||
|
|
||||||
|
// 气泡
|
||||||
|
shieldIconView.isHidden = model.status != 2
|
||||||
}
|
}
|
||||||
|
|
||||||
private func setupSubviews() {
|
private func setupSubviews() {
|
||||||
|
|
@ -263,7 +271,7 @@ class GroupMemberCell: UITableViewCell {
|
||||||
tagView.layoutChain
|
tagView.layoutChain
|
||||||
.leftToRightOfView(nameLab, offset: 4)
|
.leftToRightOfView(nameLab, offset: 4)
|
||||||
.centerY(nameLab)
|
.centerY(nameLab)
|
||||||
.height(20)
|
.height(30)
|
||||||
|
|
||||||
ownView.layoutChain.height(15)
|
ownView.layoutChain.height(15)
|
||||||
|
|
||||||
|
|
@ -354,10 +362,10 @@ class GroupMemberCell: UITableViewCell {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
lazy var tagView: UIStackView = {
|
lazy var tagView: UIStackView = {
|
||||||
let view = UIStackView(arrangedSubviews: [ownView, offlineView])
|
let view = UIStackView(arrangedSubviews: [ownView, offlineView, sosLottieView, shieldIconView])
|
||||||
view.axis = .horizontal
|
view.axis = .horizontal
|
||||||
view.alignment = .center
|
view.alignment = .center
|
||||||
view.spacing = 0
|
view.spacing = 5
|
||||||
view.backgroundColor = .clear
|
view.backgroundColor = .clear
|
||||||
return view
|
return view
|
||||||
}()
|
}()
|
||||||
|
|
@ -401,6 +409,28 @@ class GroupMemberCell: UITableViewCell {
|
||||||
return view
|
return view
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// sos
|
||||||
|
lazy var sosLottieView: LottieAnimationView = {
|
||||||
|
let view = LottieAnimationView(name: "siren")
|
||||||
|
view.loopMode = .loop
|
||||||
|
view.isHidden = true
|
||||||
|
|
||||||
|
view.layoutChain.width(26).height(26)
|
||||||
|
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
// 气泡(盾牌)
|
||||||
|
lazy var shieldIconView: UIImageView = {
|
||||||
|
let view = UIImageView(image: UIImage(named: "Home/shield"))
|
||||||
|
view.contentMode = .scaleAspectFill
|
||||||
|
view.isHidden = true
|
||||||
|
|
||||||
|
view.layoutChain.width(20).height(20)
|
||||||
|
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
// 在线
|
// 在线
|
||||||
lazy var onlineView: UIView = {
|
lazy var onlineView: UIView = {
|
||||||
let view = UIView()
|
let view = UIView()
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ class HomeView: UIView {
|
||||||
mv.showsScale = false
|
mv.showsScale = false
|
||||||
mv.isRotateEnabled = false
|
mv.isRotateEnabled = false
|
||||||
mv.isRotateCameraEnabled = false
|
mv.isRotateCameraEnabled = false
|
||||||
DispatchQueue.main.async { mv.logoCenter = CGPoint(x: 15, y: mv.bounds.height / 2) }
|
DispatchQueue.main.async { mv.logoCenter = CGPoint(x: kScreenWidth - 50, y: kScreenHeight / 2 + 65) }
|
||||||
return mv
|
return mv
|
||||||
}()
|
}()
|
||||||
#else
|
#else
|
||||||
|
|
@ -92,7 +92,6 @@ class HomeView: UIView {
|
||||||
})
|
})
|
||||||
.disposed(by: disposeBag)
|
.disposed(by: disposeBag)
|
||||||
|
|
||||||
|
|
||||||
groupMemberView.tableView.rx.setDelegate(self)
|
groupMemberView.tableView.rx.setDelegate(self)
|
||||||
.disposed(by: disposeBag)
|
.disposed(by: disposeBag)
|
||||||
|
|
||||||
|
|
@ -100,6 +99,11 @@ class HomeView: UIView {
|
||||||
searchLottieView.rx.tapGesture.subscribe { _ in
|
searchLottieView.rx.tapGesture.subscribe { _ in
|
||||||
AppRouter.push(Route.searchLocation)
|
AppRouter.push(Route.searchLocation)
|
||||||
}.disposed(by: disposeBag)
|
}.disposed(by: disposeBag)
|
||||||
|
|
||||||
|
// 感叹号
|
||||||
|
warningIconView.rx.tapGesture.subscribe { _ in
|
||||||
|
LocationPermissionPopView.show()
|
||||||
|
}.disposed(by: disposeBag)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func setupUI() {
|
private func setupUI() {
|
||||||
|
|
@ -118,6 +122,7 @@ class HomeView: UIView {
|
||||||
addSubview(messageView)
|
addSubview(messageView)
|
||||||
addSubview(messageStackView)
|
addSubview(messageStackView)
|
||||||
addSubview(toolsView)
|
addSubview(toolsView)
|
||||||
|
addSubview(warningIconView)
|
||||||
addSubview(searchLottieView)
|
addSubview(searchLottieView)
|
||||||
addSubview(locationView)
|
addSubview(locationView)
|
||||||
locationView.addSubview(locationIconView)
|
locationView.addSubview(locationIconView)
|
||||||
|
|
@ -183,6 +188,12 @@ class HomeView: UIView {
|
||||||
.width(40)
|
.width(40)
|
||||||
.centerY(self, offset: -50)
|
.centerY(self, offset: -50)
|
||||||
|
|
||||||
|
warningIconView.layoutChain
|
||||||
|
.bottomToTopOfView(toolsView, offset: -10)
|
||||||
|
.centerX(toolsView)
|
||||||
|
.width(28)
|
||||||
|
.heightToWidth(1)
|
||||||
|
|
||||||
searchLottieView.layoutChain
|
searchLottieView.layoutChain
|
||||||
.centerY(toolsView)
|
.centerY(toolsView)
|
||||||
.right()
|
.right()
|
||||||
|
|
@ -191,7 +202,7 @@ class HomeView: UIView {
|
||||||
|
|
||||||
locationView.layoutChain
|
locationView.layoutChain
|
||||||
.right(15)
|
.right(15)
|
||||||
.bottomToView(toolsView)
|
.bottomToView(toolsView, offset: -10)
|
||||||
.width(40)
|
.width(40)
|
||||||
.height(40)
|
.height(40)
|
||||||
|
|
||||||
|
|
@ -247,7 +258,7 @@ class HomeView: UIView {
|
||||||
quickMessageView.isHidden = true
|
quickMessageView.isHidden = true
|
||||||
interactionView.isHidden = true
|
interactionView.isHidden = true
|
||||||
toolsView.isHidden = false
|
toolsView.isHidden = false
|
||||||
searchLottieView.isHidden = false
|
searchLottieView.isHidden = AppContextManager.shared.systemConfig?.globalDisplay == false
|
||||||
onDismissPanel?()
|
onDismissPanel?()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -636,7 +647,16 @@ class HomeView: UIView {
|
||||||
view.isHidden = true
|
view.isHidden = true
|
||||||
return view
|
return view
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// MARK: - warning 惊叹号图标
|
||||||
|
lazy var warningIconView: UIImageView = {
|
||||||
|
let view = UIImageView()
|
||||||
|
view.image = UIImage(named: "Home/warning")
|
||||||
|
view.contentMode = .scaleAspectFill
|
||||||
|
view.isHidden = true
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
// MARK: - 侧边工具栏
|
// MARK: - 侧边工具栏
|
||||||
lazy var toolsView: UIStackView = {
|
lazy var toolsView: UIStackView = {
|
||||||
let view = UIStackView(arrangedSubviews: [bubbleView, signInView, sosView, scheduleView])
|
let view = UIStackView(arrangedSubviews: [bubbleView, signInView, sosView, scheduleView])
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ class HomeViewController: BaseViewController {
|
||||||
private var offlineCheckTimer: Timer?
|
private var offlineCheckTimer: Timer?
|
||||||
private var popupQueue: PopupQueueManager?
|
private var popupQueue: PopupQueueManager?
|
||||||
|
|
||||||
private var sosPlayerKey: UInt8 = 0
|
private static var sosPlayerKey: UInt8 = 0
|
||||||
private var groupRefreshWorkItem: DispatchWorkItem?
|
private var groupRefreshWorkItem: DispatchWorkItem?
|
||||||
private var groupSwitchWorkItem: DispatchWorkItem?
|
private var groupSwitchWorkItem: DispatchWorkItem?
|
||||||
|
|
||||||
|
|
@ -82,7 +82,14 @@ class HomeViewController: BaseViewController {
|
||||||
|
|
||||||
override func viewDidAppear(_ animated: Bool) {
|
override func viewDidAppear(_ animated: Bool) {
|
||||||
super.viewDidAppear(animated)
|
super.viewDidAppear(animated)
|
||||||
|
|
||||||
|
let manager = AuthorizeManager.manager(type: .locationAlways)
|
||||||
|
rootView.warningIconView.isHidden = manager?.authorizeStatus() == .authorized
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewDidDisappear(_ animated: Bool) {
|
||||||
|
super.viewDidDisappear(animated)
|
||||||
|
// sosPlayer?.stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - MQTT 位置上报
|
// MARK: - MQTT 位置上报
|
||||||
|
|
@ -199,6 +206,7 @@ class HomeViewController: BaseViewController {
|
||||||
guard let self = self, let model = response.model else { return }
|
guard let self = self, let model = response.model else { return }
|
||||||
Defaults[\.loginToken] = model.token
|
Defaults[\.loginToken] = model.token
|
||||||
AppContextManager.shared.systemConfig = model.config
|
AppContextManager.shared.systemConfig = model.config
|
||||||
|
rootView.searchLottieView.isHidden = model.config?.globalDisplay == false
|
||||||
self.getUserIMToken()
|
self.getUserIMToken()
|
||||||
self.requestUserInfo { [weak self] in
|
self.requestUserInfo { [weak self] in
|
||||||
self?.requestGroupInfo()
|
self?.requestGroupInfo()
|
||||||
|
|
@ -656,11 +664,22 @@ extension HomeViewController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case "bubble": // 气泡
|
||||||
|
guard let userId = msg.data?.user_id else { return }
|
||||||
|
DispatchQueue.main.async { [weak self] in
|
||||||
|
self?.viewModel.updateMemberStatus(userId: userId, status: 2)
|
||||||
|
self?.removeAnnotation(userId: userId)
|
||||||
|
}
|
||||||
|
|
||||||
case "sos": // 求助
|
case "sos": // 求助
|
||||||
guard let userId = msg.data?.user_id,
|
guard let userId = msg.data?.user_id,
|
||||||
userId != AppContextManager.shared.userId else { return }
|
userId != AppContextManager.shared.userId,
|
||||||
|
topic.contains(userId) else { return }
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
guard let self = self, !self.isSOSPlaying else { return }
|
guard let self = self else { return }
|
||||||
|
self.viewModel.updateMemberStatus(userId: userId, status: 1)
|
||||||
|
|
||||||
|
guard !self.isSOSPlaying else { return }
|
||||||
self.isSOSPlaying = true
|
self.isSOSPlaying = true
|
||||||
self.playSOSAlarm()
|
self.playSOSAlarm()
|
||||||
self.rootView.sosPopView.isHidden = false
|
self.rootView.sosPopView.isHidden = false
|
||||||
|
|
@ -669,8 +688,11 @@ extension HomeViewController {
|
||||||
self.rootView.sosPopView.isHidden = true
|
self.rootView.sosPopView.isHidden = true
|
||||||
}
|
}
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 15) { [weak self] in
|
DispatchQueue.main.asyncAfter(deadline: .now() + 15) { [weak self] in
|
||||||
|
self?.sosPlayer?.stop()
|
||||||
|
self?.sosPlayer = nil
|
||||||
self?.rootView.sosPopView.stop()
|
self?.rootView.sosPopView.stop()
|
||||||
self?.rootView.sosPopView.isHidden = true
|
self?.rootView.sosPopView.isHidden = true
|
||||||
|
self?.isSOSPlaying = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case "join": // 圈子有成员加入
|
case "join": // 圈子有成员加入
|
||||||
|
|
@ -851,8 +873,8 @@ extension HomeViewController: MAMapViewDelegate {
|
||||||
extension HomeViewController {
|
extension HomeViewController {
|
||||||
|
|
||||||
private var sosPlayer: AVAudioPlayer? {
|
private var sosPlayer: AVAudioPlayer? {
|
||||||
get { return objc_getAssociatedObject(self, &sosPlayerKey) as? AVAudioPlayer }
|
get { return objc_getAssociatedObject(self, &HomeViewController.sosPlayerKey) as? AVAudioPlayer }
|
||||||
set { objc_setAssociatedObject(self, &sosPlayerKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) }
|
set { objc_setAssociatedObject(self, &HomeViewController.sosPlayerKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private func playSOSAlarm() {
|
private func playSOSAlarm() {
|
||||||
|
|
@ -879,11 +901,6 @@ extension HomeViewController {
|
||||||
player.volume = 1.0
|
player.volume = 1.0
|
||||||
player.play()
|
player.play()
|
||||||
self.sosPlayer = player
|
self.sosPlayer = player
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 15) { [weak self] in
|
|
||||||
self?.sosPlayer?.stop()
|
|
||||||
self?.sosPlayer = nil
|
|
||||||
self?.isSOSPlaying = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -144,6 +144,12 @@ class HomeViewModel {
|
||||||
setMemberList(updated)
|
setMemberList(updated)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateMemberStatus(userId: String, status: Int) {
|
||||||
|
guard let index = memberList.firstIndex(where: { $0.user_id == userId }) else { return }
|
||||||
|
memberList[index].status = status
|
||||||
|
sectionedItems.onNext(memberList.mapSection())
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Init
|
// MARK: - Init
|
||||||
init() {
|
init() {
|
||||||
output = Output(
|
output = Output(
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,177 @@
|
||||||
|
//
|
||||||
|
// LocationPermissionPopView.swift
|
||||||
|
// QuickLocation
|
||||||
|
//
|
||||||
|
// Created by 八条 on 2026/7/8.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import RxSwift
|
||||||
|
import RxCocoa
|
||||||
|
|
||||||
|
class LocationPermissionPopView: UIView {
|
||||||
|
|
||||||
|
private static let shared = LocationPermissionPopView(frame: CGRect(origin: .zero, size: kScreenSize))
|
||||||
|
|
||||||
|
var disposeBag = DisposeBag()
|
||||||
|
|
||||||
|
static func show() {
|
||||||
|
guard let superView = kKeyWindow else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if LocationPermissionPopView.shared.superview != nil {
|
||||||
|
LocationPermissionPopView.shared.removeFromSuperview()
|
||||||
|
LocationPermissionPopView.shared.bgView.frame = .zero
|
||||||
|
}
|
||||||
|
|
||||||
|
LocationPermissionPopView.shared.bgView.alpha = 1
|
||||||
|
LocationPermissionPopView.shared.bgView.frame = CGRect(x: 0, y: 0, width: kScreenWidth, height: kScreenHeight)
|
||||||
|
superView.addSubview(LocationPermissionPopView.shared)
|
||||||
|
superView.bringSubviewToFront(LocationPermissionPopView.shared)
|
||||||
|
|
||||||
|
UIView.animate(withDuration: 0.25) {
|
||||||
|
LocationPermissionPopView.shared.bgView.alpha = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 关闭
|
||||||
|
static func dismiss() {
|
||||||
|
guard LocationPermissionPopView.shared.superview != nil else { return }
|
||||||
|
|
||||||
|
UIView.animate(withDuration: 0.25, delay: 0, options: [.curveEaseIn]) {
|
||||||
|
LocationPermissionPopView.shared.bgView.alpha = 0
|
||||||
|
} completion: { _ in
|
||||||
|
LocationPermissionPopView.shared.removeFromSuperview()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func setupRx() {
|
||||||
|
settingBtn.rx.tap.subscribe(onNext: { _ in
|
||||||
|
guard let settingsURL = URL(string: UIApplication.openSettingsURLString) else { return }
|
||||||
|
LocationPermissionPopView.dismiss()
|
||||||
|
if UIApplication.shared.canOpenURL(settingsURL) {
|
||||||
|
UIApplication.shared.open(settingsURL, options: [:], completionHandler: nil)
|
||||||
|
}
|
||||||
|
}).disposed(by: disposeBag)
|
||||||
|
|
||||||
|
closeBtn.rx.tap.subscribe(onNext: { _ in
|
||||||
|
LocationPermissionPopView.dismiss()
|
||||||
|
}).disposed(by: disposeBag)
|
||||||
|
}
|
||||||
|
|
||||||
|
private lazy var bgView: UIView = {
|
||||||
|
let view = UIView()
|
||||||
|
view.backgroundColor = .black.withAlphaComponent(0.5)
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
lazy var popView: UIView = {
|
||||||
|
let view = UIView()
|
||||||
|
view.backgroundColor = .clear
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
lazy var popBgView: UIView = {
|
||||||
|
let view = UIView()
|
||||||
|
view.backgroundColor = .white
|
||||||
|
view.cornerRadius = 30
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
lazy var logoImgView: UIImageView = {
|
||||||
|
let view = UIImageView(image: UIImage(named: "Popup/bell"))
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
lazy var headerBgImg: UIImageView = {
|
||||||
|
let view = UIImageView(image: UIImage(named: "Popup/header_bg"))
|
||||||
|
view.contentMode = .scaleAspectFill
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
lazy var textImgView: UIImageView = {
|
||||||
|
let view = UIImageView()
|
||||||
|
view.contentMode = .scaleAspectFill
|
||||||
|
view.image = UIImage(named: "Home/permission_text")
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
lazy var settingBtn: UIButton = {
|
||||||
|
let btn = UIButton(type: .custom)
|
||||||
|
btn.setTitle("马上开启", for: .normal)
|
||||||
|
btn.setTitleColor(.white, for: .normal)
|
||||||
|
btn.titleLabel?.font = .systemFont(ofSize: 16, weight: .medium)
|
||||||
|
btn.setBackgroundImage(UIImage(named: "Common/button_bg_2"), for: .normal)
|
||||||
|
btn.cornerRadius = 25
|
||||||
|
return btn
|
||||||
|
}()
|
||||||
|
|
||||||
|
lazy var closeBtn: UIButton = {
|
||||||
|
let btn = UIButton(type: .custom)
|
||||||
|
btn.setTitle("取消", for: .normal)
|
||||||
|
btn.setTitleColor(UIColor(hexStr: "#16B3FF"), for: .normal)
|
||||||
|
btn.titleLabel?.font = .systemFont(ofSize: 16, weight: .medium)
|
||||||
|
btn.backgroundColor = .clear
|
||||||
|
return btn
|
||||||
|
}()
|
||||||
|
|
||||||
|
// MARK: - Init
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
backgroundColor = .clear
|
||||||
|
addSubview(bgView)
|
||||||
|
bgView.addSubview(popView)
|
||||||
|
popView.addSubview(popBgView)
|
||||||
|
popView.addSubview(logoImgView)
|
||||||
|
popBgView.addSubview(headerBgImg)
|
||||||
|
popBgView.addSubview(textImgView)
|
||||||
|
popBgView.addSubview(settingBtn)
|
||||||
|
popBgView.addSubview(closeBtn)
|
||||||
|
|
||||||
|
popView.layoutChain
|
||||||
|
.centerX()
|
||||||
|
.centerY()
|
||||||
|
.width(315)
|
||||||
|
.height(362)
|
||||||
|
|
||||||
|
popBgView.layoutChain.edges()
|
||||||
|
|
||||||
|
logoImgView.layoutChain
|
||||||
|
.left(16)
|
||||||
|
.top(-45)
|
||||||
|
.width(109)
|
||||||
|
.height(109)
|
||||||
|
|
||||||
|
headerBgImg.layoutChain
|
||||||
|
.edges(excludingEdge: .bottom)
|
||||||
|
.heightToWidth(100/315)
|
||||||
|
|
||||||
|
textImgView.layoutChain
|
||||||
|
.top(70)
|
||||||
|
.centerX()
|
||||||
|
.width(275)
|
||||||
|
.height(173)
|
||||||
|
|
||||||
|
closeBtn.layoutChain
|
||||||
|
.bottom()
|
||||||
|
.height(50)
|
||||||
|
.edgesHorzontal(20)
|
||||||
|
|
||||||
|
settingBtn.layoutChain
|
||||||
|
.bottomToTopOfView(closeBtn)
|
||||||
|
.height(50)
|
||||||
|
.edgesHorzontal(20)
|
||||||
|
|
||||||
|
setupRx()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder aDecoder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override func layoutSubviews() {
|
||||||
|
super.layoutSubviews()
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -23,35 +23,27 @@ class SOSViewController: BaseViewController {
|
||||||
|
|
||||||
// Do any additional setup after loading the view.
|
// Do any additional setup after loading the view.
|
||||||
fd_interactivePopDisabled = true
|
fd_interactivePopDisabled = true
|
||||||
// requestUserInfo()
|
|
||||||
|
|
||||||
rootView.didSendSOS = { status in
|
rootView.didSendSOS = { status in
|
||||||
self.requestSOS(status)
|
self.requestSOS(status)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
guard AppContextManager.shared.status == 1 else { return }
|
||||||
private func requestUserInfo(completion: (() -> Void)? = nil) {
|
self.rootView.countDownView.alpha = 1
|
||||||
UserService.userInfo().subscribe { response in
|
self.rootView.countDownFinish = true
|
||||||
guard let model = response.model else { return }
|
if let path = Bundle.main.path(forResource: "red-exclamation", ofType: "json") {
|
||||||
AppContextManager.shared.saveAccount(model)
|
self.rootView.countDownLottieView.animation = LottieAnimation.filepath(path)
|
||||||
|
self.rootView.countDownLottieView.loopMode = .loop
|
||||||
guard model.status == 1 else { return }
|
self.rootView.countDownLottieView.play()
|
||||||
self.rootView.countDownView.alpha = 1
|
self.rootView.countDownTipsLab.text = "已将你的SOS和位置发送到你的圈子和紧急联系人。\n\n您的 SOS 将发送给5个人"
|
||||||
self.rootView.countDownFinish = true
|
}
|
||||||
if let path = Bundle.main.path(forResource: "red-exclamation", ofType: "json") {
|
|
||||||
self.rootView.countDownLottieView.animation = LottieAnimation.filepath(path)
|
|
||||||
self.rootView.countDownLottieView.loopMode = .loop
|
|
||||||
self.rootView.countDownLottieView.play()
|
|
||||||
self.rootView.countDownTipsLab.text = "已将你的SOS和位置发送到你的圈子和紧急联系人。\n\n您的 SOS 将发送给5个人"
|
|
||||||
}
|
|
||||||
|
|
||||||
}.disposed(by: disposeBag)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func requestSOS(_ enable: Bool) {
|
private func requestSOS(_ enable: Bool) {
|
||||||
dl.showLoading()
|
dl.showLoading()
|
||||||
SystemService.sos(enable: enable).subscribe(onNext: { response in
|
SystemService.sos(enable: enable).subscribe(onNext: { response in
|
||||||
self.dl.show(text: enable ? "发送成功" : "取消成功") {
|
self.dl.show(text: enable ? "发送成功" : "取消成功") {
|
||||||
|
AppContextManager.shared.updateAccountStatus(enable ? 1 : 0)
|
||||||
AppRouter.shared.popOrDismiss()
|
AppRouter.shared.popOrDismiss()
|
||||||
}
|
}
|
||||||
}, onError: { (error) in }).disposed(by: disposeBag)
|
}, onError: { (error) in }).disposed(by: disposeBag)
|
||||||
|
|
|
||||||
|
|
@ -30,19 +30,19 @@ class LaunchViewController: BaseViewController {
|
||||||
setupLayout()
|
setupLayout()
|
||||||
|
|
||||||
experienceBtn.rx.tap.subscribe(onNext: { _ in
|
experienceBtn.rx.tap.subscribe(onNext: { _ in
|
||||||
// Defaults[\.guideShowVersion] = self.showVersion
|
Defaults[\.isShowGuide] = false
|
||||||
AppDelegate.shared.showMainViewController()
|
AppDelegate.shared.showMainViewController()
|
||||||
}).disposed(by: disposeBag)
|
}).disposed(by: disposeBag)
|
||||||
|
|
||||||
getUserConfig()
|
getUserConfig()
|
||||||
navigateAfterDelay()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func navigateAfterDelay() {
|
private func navigateAfterDelay() {
|
||||||
Observable.just(())
|
Observable.just(())
|
||||||
.delay(.milliseconds(2500), scheduler: MainScheduler.instance)
|
.delay(.milliseconds(2500), scheduler: MainScheduler.instance)
|
||||||
.subscribe(onNext: { [weak self] in
|
.subscribe(onNext: { [weak self] in
|
||||||
if Defaults[\.isShowGuide] {
|
guard let systemConfig = AppContextManager.shared.systemConfig else { return }
|
||||||
|
if systemConfig.guideDisplay, Defaults[\.isShowGuide] {
|
||||||
self?.collectionView.isHidden = false
|
self?.collectionView.isHidden = false
|
||||||
self?.pageControl.isHidden = false
|
self?.pageControl.isHidden = false
|
||||||
self?.experienceBtn.isHidden = false
|
self?.experienceBtn.isHidden = false
|
||||||
|
|
@ -76,6 +76,7 @@ class LaunchViewController: BaseViewController {
|
||||||
guard let data = response.data, let token = data["token"] as? String else { return }
|
guard let data = response.data, let token = data["token"] as? String else { return }
|
||||||
AppContextManager.shared.imToken = token
|
AppContextManager.shared.imToken = token
|
||||||
GroupIMService.shared.login { _ in }
|
GroupIMService.shared.login { _ in }
|
||||||
|
self.navigateAfterDelay()
|
||||||
}).disposed(by: disposeBag)
|
}).disposed(by: disposeBag)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,12 +91,20 @@ class LoginViewController: BaseViewController {
|
||||||
|
|
||||||
rootView.wechatLoginBtn.rx.tap
|
rootView.wechatLoginBtn.rx.tap
|
||||||
.subscribe(onNext: { [weak self] in
|
.subscribe(onNext: { [weak self] in
|
||||||
|
guard self?.isAgreed == true else {
|
||||||
|
DLToast.showError(text: "请先同意用户协议")
|
||||||
|
return
|
||||||
|
}
|
||||||
self?.viewModel.performWechatLogin()
|
self?.viewModel.performWechatLogin()
|
||||||
})
|
})
|
||||||
.disposed(by: disposeBag)
|
.disposed(by: disposeBag)
|
||||||
|
|
||||||
rootView.appleLoginBtn.rx.tap
|
rootView.appleLoginBtn.rx.tap
|
||||||
.subscribe(onNext: { [weak self] in
|
.subscribe(onNext: { [weak self] in
|
||||||
|
guard self?.isAgreed == true else {
|
||||||
|
DLToast.showError(text: "请先同意用户协议")
|
||||||
|
return
|
||||||
|
}
|
||||||
self?.viewModel.performAppleLogin()
|
self?.viewModel.performAppleLogin()
|
||||||
})
|
})
|
||||||
.disposed(by: disposeBag)
|
.disposed(by: disposeBag)
|
||||||
|
|
@ -115,12 +123,21 @@ class LoginViewController: BaseViewController {
|
||||||
DLToast.show(text: "请插入SIM卡后重试")
|
DLToast.show(text: "请插入SIM卡后重试")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if GeYanSdk.isPreGettedTokenValidate() { //预登录有效,启动登录授权页
|
||||||
|
let oneTapView = OneTapLoginView(frame: UIScreen.main.bounds)
|
||||||
|
self?.viewModel.performOneTapLogin(from: self!, contentView: oneTapView)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 预登录
|
||||||
GeYanSdk.preGetToken { preDic in
|
GeYanSdk.preGetToken { preDic in
|
||||||
guard let dict = preDic as? [String: Any],
|
guard GeYanSdk.isPreGettedTokenValidate() else {
|
||||||
dict["code"] as? Int == 30000,
|
var message = ""
|
||||||
let model = GyContentModel.current(),
|
if let dict = preDic as? [String: Any] {
|
||||||
!model.pn.isEmpty else {
|
message = dict["msg"] as? String ?? "获取手机号失败,请使用验证码登录"
|
||||||
DLToast.showError(text: "获取手机号失败,请使用验证码登录")
|
}
|
||||||
|
DLToast.show(text: message)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let oneTapView = OneTapLoginView(frame: UIScreen.main.bounds)
|
let oneTapView = OneTapLoginView(frame: UIScreen.main.bounds)
|
||||||
|
|
|
||||||
|
|
@ -83,28 +83,36 @@ final class LoginViewModel: BaseViewModel {
|
||||||
contentView.carrierLabel,
|
contentView.carrierLabel,
|
||||||
contentView.loginButton,
|
contentView.loginButton,
|
||||||
contentView.checkBox,
|
contentView.checkBox,
|
||||||
contentView.agreementTV
|
contentView.agreementLabel
|
||||||
]
|
]
|
||||||
GeYanSdk.oneTapLogin(vc, viewModel: gyAuthVM, contentView: contentView,
|
GeYanSdk.oneTapLogin(vc, viewModel: gyAuthVM, contentView: contentView,
|
||||||
subViewList: subViews) { [weak self] result in
|
subViewList: subViews) { [weak self] result in
|
||||||
|
|
||||||
guard let dict = result as? [String: Any],
|
guard let dict = result as? [String: Any],
|
||||||
dict["code"] as? Int == 30000,
|
let code = dict["code"] as? Int else { return }
|
||||||
let token = dict["token"] as? String else { return }
|
print(dict)
|
||||||
|
if code == 30000, // 成功
|
||||||
let opType: String = {
|
let gyuid = dict["gyuid"],
|
||||||
switch dict["operatorType"] as? Int {
|
let token = dict["token"] {
|
||||||
case 1: return "CM"
|
|
||||||
case 2: return "CU"
|
// let opType: String = {
|
||||||
case 3: return "CT"
|
// switch dict["operatorType"] as? Int {
|
||||||
default: return ""
|
// case 1: return "CM"
|
||||||
|
// case 2: return "CU"
|
||||||
|
// case 3: return "CT"
|
||||||
|
// default: return ""
|
||||||
|
// }
|
||||||
|
// }()
|
||||||
|
GeYanSdk.closeAuthVC(true) {
|
||||||
|
self?.loginAction(type: "onekey", data: [
|
||||||
|
"gyuid": gyuid,
|
||||||
|
"token": token
|
||||||
|
])
|
||||||
}
|
}
|
||||||
}()
|
}
|
||||||
|
else {
|
||||||
self?.loginAction(type: "onekey", data: [
|
DLToast.show(text: dict["msg"] as? String ?? "运营商返回失败")
|
||||||
"auth_code": "",
|
}
|
||||||
"access_code": token,
|
|
||||||
"operator_type": opType
|
|
||||||
])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ class OneTapLoginView: UIView {
|
||||||
|
|
||||||
var disposeBag = DisposeBag()
|
var disposeBag = DisposeBag()
|
||||||
var oneTapLogin = true
|
var oneTapLogin = true
|
||||||
|
|
||||||
private func setupRx() {
|
private func setupRx() {
|
||||||
backBtn.rx.tap.subscribe(onNext: { _ in
|
backBtn.rx.tap.subscribe(onNext: { _ in
|
||||||
#if !targetEnvironment(simulator)
|
#if !targetEnvironment(simulator)
|
||||||
|
|
@ -28,6 +28,8 @@ class OneTapLoginView: UIView {
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
self.checkBox.isSelected = !self.checkBox.isSelected
|
self.checkBox.isSelected = !self.checkBox.isSelected
|
||||||
}).disposed(by: disposeBag)
|
}).disposed(by: disposeBag)
|
||||||
|
|
||||||
|
agreementTV.delegate = self
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupAgreementTextWithCarrier(carrier: String) {
|
func setupAgreementTextWithCarrier(carrier: String) {
|
||||||
|
|
@ -65,8 +67,8 @@ class OneTapLoginView: UIView {
|
||||||
|
|
||||||
addSubview(agreementView)
|
addSubview(agreementView)
|
||||||
agreementView.addSubview(checkBox)
|
agreementView.addSubview(checkBox)
|
||||||
agreementView.addSubview(agreementTV)
|
|
||||||
agreementView.addSubview(agreementLabel)
|
agreementView.addSubview(agreementLabel)
|
||||||
|
agreementView.addSubview(agreementTV)
|
||||||
|
|
||||||
bgMaskImage.layoutChain.edges()
|
bgMaskImage.layoutChain.edges()
|
||||||
|
|
||||||
|
|
@ -102,23 +104,26 @@ class OneTapLoginView: UIView {
|
||||||
.height(50)
|
.height(50)
|
||||||
|
|
||||||
agreementView.layoutChain
|
agreementView.layoutChain
|
||||||
.leftToView(loginButton)
|
.edgesHorzontal(30)
|
||||||
.rightToView(loginButton)
|
.bottom(kSafeBottomMargin + 20)
|
||||||
.bottom(55)
|
|
||||||
.height(30)
|
|
||||||
|
|
||||||
agreementLabel.layoutChain.edges()
|
|
||||||
|
|
||||||
checkBox.layoutChain
|
checkBox.layoutChain
|
||||||
.left()
|
.left()
|
||||||
.centerY()
|
.top(10)
|
||||||
.width(12)
|
.width(12)
|
||||||
.height(12)
|
.height(12)
|
||||||
|
|
||||||
|
agreementLabel.layoutChain
|
||||||
|
.leftToRightOfView(checkBox, offset: 0)
|
||||||
|
.right()
|
||||||
|
.top()
|
||||||
|
.bottom()
|
||||||
|
|
||||||
agreementTV.layoutChain
|
agreementTV.layoutChain
|
||||||
.leftToRightOfView(checkBox, offset: 0)
|
.leftToRightOfView(checkBox, offset: 0)
|
||||||
.right()
|
.right()
|
||||||
.top()
|
.top()
|
||||||
|
.bottom()
|
||||||
}
|
}
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
|
|
@ -193,6 +198,12 @@ class OneTapLoginView: UIView {
|
||||||
return btn
|
return btn
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
lazy var label: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
lazy var agreementView: UIView = {
|
lazy var agreementView: UIView = {
|
||||||
let view = UIView()
|
let view = UIView()
|
||||||
view.backgroundColor = .clear
|
view.backgroundColor = .clear
|
||||||
|
|
@ -203,15 +214,16 @@ class OneTapLoginView: UIView {
|
||||||
let btn = UIButton(type: .custom)
|
let btn = UIButton(type: .custom)
|
||||||
btn.setImage(UIImage(named: "Login/checkbox"), for: .normal)
|
btn.setImage(UIImage(named: "Login/checkbox"), for: .normal)
|
||||||
btn.setImage(UIImage(named: "Login/selected"), for: .selected)
|
btn.setImage(UIImage(named: "Login/selected"), for: .selected)
|
||||||
btn.extendEdgeInsets = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)
|
btn.extendEdgeInsets = UIEdgeInsets(top: 50, left: 50, bottom: 50, right: 20)
|
||||||
|
btn.isSelected = true
|
||||||
return btn
|
return btn
|
||||||
}()
|
}()
|
||||||
|
|
||||||
lazy var agreementLabel: UILabel = {
|
lazy var agreementLabel: UILabel = {
|
||||||
let label = UILabel()
|
let label = UILabel()
|
||||||
label.textColor = .clear
|
label.textColor = .clear
|
||||||
label.numberOfLines = 1
|
label.numberOfLines = 0
|
||||||
label.textAlignment = .center
|
// label.textAlignment = .center
|
||||||
label.font = .systemFont(ofSize: 10)
|
label.font = .systemFont(ofSize: 10)
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
|
|
@ -222,8 +234,34 @@ class OneTapLoginView: UIView {
|
||||||
textView.backgroundColor = .clear
|
textView.backgroundColor = .clear
|
||||||
textView.isEditable = false
|
textView.isEditable = false
|
||||||
textView.isScrollEnabled = false
|
textView.isScrollEnabled = false
|
||||||
|
textView.isSelectable = true
|
||||||
textView.linkTextAttributes = [:]
|
textView.linkTextAttributes = [:]
|
||||||
|
|
||||||
return textView
|
return textView
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !targetEnvironment(simulator)
|
||||||
|
extension OneTapLoginView: UITextViewDelegate {
|
||||||
|
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
|
||||||
|
var urlStr: String?
|
||||||
|
if URL.absoluteString == "Carrier", let model = GyContentModel.current(), let link = model.link {
|
||||||
|
urlStr = link
|
||||||
|
}
|
||||||
|
if URL.absoluteString == "UserAgreement" {
|
||||||
|
urlStr = URLManager.shared.userAgreementUrl
|
||||||
|
}
|
||||||
|
if URL.absoluteString == "PrivacyPolicy" {
|
||||||
|
urlStr = URLManager.shared.privacyPolicyUrl
|
||||||
|
}
|
||||||
|
guard let urlString = urlStr else { return true }
|
||||||
|
let vc = WebViewController(url: urlString, isShare: false, fullscreen: false, style: "default")
|
||||||
|
AppRouter.present(UINavigationController(rootViewController: vc))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,9 @@ import UIKit
|
||||||
import RxSwift
|
import RxSwift
|
||||||
import RxCocoa
|
import RxCocoa
|
||||||
import RxDataSources
|
import RxDataSources
|
||||||
|
#if !targetEnvironment(simulator)
|
||||||
|
import GeYanSdk
|
||||||
|
#endif
|
||||||
|
|
||||||
class AccountVC: BaseViewController {
|
class AccountVC: BaseViewController {
|
||||||
|
|
||||||
|
|
@ -60,6 +63,7 @@ class AccountVC: BaseViewController {
|
||||||
UserService.logout().subscribe(onNext: { response in
|
UserService.logout().subscribe(onNext: { response in
|
||||||
DLToast.dismiss()
|
DLToast.dismiss()
|
||||||
NotificationCenter.default.post(name: .invalidatePopupQueue, object: nil)
|
NotificationCenter.default.post(name: .invalidatePopupQueue, object: nil)
|
||||||
|
GeYanSdk.deletePreResultCache()
|
||||||
AppContextManager.shared.deleteAccount()
|
AppContextManager.shared.deleteAccount()
|
||||||
GroupIMService.shared.logout()
|
GroupIMService.shared.logout()
|
||||||
AppDelegate.shared.showMainViewController()
|
AppDelegate.shared.showMainViewController()
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,11 @@ final class MineView: UIView {
|
||||||
private let vipBtnTextColor = UIColor(hexStr: "#00343B")
|
private let vipBtnTextColor = UIColor(hexStr: "#00343B")
|
||||||
|
|
||||||
func setupData(_ model: UserConfigModel) {
|
func setupData(_ model: UserConfigModel) {
|
||||||
|
guard AppContextManager.shared.systemConfig?.globalDisplay == true else {
|
||||||
|
maskBgView.isHidden = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
maskBgView.isHidden = true
|
||||||
guard model.vip > 1 else {
|
guard model.vip > 1 else {
|
||||||
vipTitleLab.text = "开通会员"
|
vipTitleLab.text = "开通会员"
|
||||||
vipContentLab.text = "会员尊享10+VIP特权"
|
vipContentLab.text = "会员尊享10+VIP特权"
|
||||||
|
|
@ -121,11 +125,19 @@ final class MineView: UIView {
|
||||||
return iv
|
return iv
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
lazy var maskBgView: UIImageView = {
|
||||||
|
let iv = UIImageView()
|
||||||
|
iv.image = UIImage(named: "Mine/mask_bg")
|
||||||
|
iv.contentMode = .scaleToFill
|
||||||
|
iv.isHidden = true
|
||||||
|
return iv
|
||||||
|
}()
|
||||||
|
|
||||||
lazy var vipTitleLab: UILabel = {
|
lazy var vipTitleLab: UILabel = {
|
||||||
let label = UILabel()
|
let label = UILabel()
|
||||||
label.font = .systemFont(ofSize: 18, weight: .bold)
|
label.font = .systemFont(ofSize: 18, weight: .bold)
|
||||||
label.textColor = .white
|
label.textColor = .white
|
||||||
label.text = "开通会员"
|
label.text = " "
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
@ -133,7 +145,7 @@ final class MineView: UIView {
|
||||||
let label = UILabel()
|
let label = UILabel()
|
||||||
label.font = .systemFont(ofSize: 12, weight: .medium)
|
label.font = .systemFont(ofSize: 12, weight: .medium)
|
||||||
label.textColor = .white
|
label.textColor = .white
|
||||||
label.text = "会员尊享10+VIP特权"
|
label.text = " "
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
@ -220,6 +232,7 @@ final class MineView: UIView {
|
||||||
vipCardView.addSubview(vipActivateButton)
|
vipCardView.addSubview(vipActivateButton)
|
||||||
vipCardView.addSubview(vipTitleLab)
|
vipCardView.addSubview(vipTitleLab)
|
||||||
vipCardView.addSubview(vipContentLab)
|
vipCardView.addSubview(vipContentLab)
|
||||||
|
vipCardView.addSubview(maskBgView)
|
||||||
|
|
||||||
addSubview(profileBgImageView)
|
addSubview(profileBgImageView)
|
||||||
addSubview(bottomFillView)
|
addSubview(bottomFillView)
|
||||||
|
|
@ -282,6 +295,8 @@ final class MineView: UIView {
|
||||||
.right(19).centerY()
|
.right(19).centerY()
|
||||||
.width(70).height(28)
|
.width(70).height(28)
|
||||||
|
|
||||||
|
maskBgView.layoutChain.edges()
|
||||||
|
|
||||||
// Profile transition background (100pt, overlaps VIP card bottom half)
|
// Profile transition background (100pt, overlaps VIP card bottom half)
|
||||||
profileBgImageView.layoutChain
|
profileBgImageView.layoutChain
|
||||||
.topToView(vipCardView, offset: 32)
|
.topToView(vipCardView, offset: 32)
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@ class PopupQueueManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func executeNextStep() {
|
private func executeNextStep() {
|
||||||
|
guard AppContextManager.shared.systemConfig?.globalDisplay == true else { return }
|
||||||
switch currentStep {
|
switch currentStep {
|
||||||
case 0:
|
case 0:
|
||||||
tryStartPromotionalActivities()
|
tryStartPromotionalActivities()
|
||||||
|
|
|
||||||
|
|
@ -163,16 +163,20 @@ class PromotionalActivitiesVC: BaseViewController {
|
||||||
guard let data = response.data else { return }
|
guard let data = response.data else { return }
|
||||||
|
|
||||||
if payType == "weixin" { // 微信
|
if payType == "weixin" { // 微信
|
||||||
// WXApi.registerApp(model.appId, universalLink: AppSettings.kAppsUniversalLink)
|
guard let partnerId = data["partnerId"] as? String,
|
||||||
//
|
let prepayId = data["prepayId"] as? String,
|
||||||
// let request: PayReq = PayReq()
|
let package = data["package"] as? String,
|
||||||
// request.partnerId = model.partnerId
|
let nonceStr = data["nonceStr"] as? String,
|
||||||
// request.prepayId = model.prepayId
|
let timeStamp = data["timeStamp"] as? String,
|
||||||
// request.package = model.packageValue
|
let sign = data["sign"] as? String else { return }
|
||||||
// request.nonceStr = model.nonceStr
|
let request: PayReq = PayReq()
|
||||||
// request.timeStamp = UInt32(model.timeStamp) ?? 0
|
request.partnerId = partnerId
|
||||||
// request.sign = model.sign
|
request.prepayId = prepayId
|
||||||
// WXApi.send(request)
|
request.package = package
|
||||||
|
request.nonceStr = nonceStr
|
||||||
|
request.timeStamp = UInt32(timeStamp) ?? 0
|
||||||
|
request.sign = sign
|
||||||
|
WXApi.send(request)
|
||||||
}
|
}
|
||||||
else if payType == "alipay" { // 支付宝
|
else if payType == "alipay" { // 支付宝
|
||||||
if let payParam = data["payParam"] as? String, let appId = data["payParam"] as? String {
|
if let payParam = data["payParam"] as? String, let appId = data["payParam"] as? String {
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,9 @@ class CreateScheduleVC: BaseViewController, MAMapViewDelegate {
|
||||||
}
|
}
|
||||||
}, onError: { error in
|
}, onError: { error in
|
||||||
guard let code = error.underlyingError?.code else { return }
|
guard let code = error.underlyingError?.code else { return }
|
||||||
|
|
||||||
|
guard let systemConfig = AppContextManager.shared.systemConfig, systemConfig.globalDisplay else { return }
|
||||||
|
|
||||||
if code == 20010 { // "创建的行程数达到上限"
|
if code == 20010 { // "创建的行程数达到上限"
|
||||||
CreateScheduleVipPopView.show()
|
CreateScheduleVipPopView.show()
|
||||||
}
|
}
|
||||||
|
|
@ -235,7 +238,7 @@ class CreateScheduleVC: BaseViewController, MAMapViewDelegate {
|
||||||
.observe(on: MainScheduler.asyncInstance)
|
.observe(on: MainScheduler.asyncInstance)
|
||||||
.subscribe(onNext: { [weak self] items in
|
.subscribe(onNext: { [weak self] items in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
let h = max(CGFloat(items.count) * 122, 122)
|
let h = max(CGFloat(items.count) * 129, 129)
|
||||||
self.popView.tableView.layoutChain.height(h)
|
self.popView.tableView.layoutChain.height(h)
|
||||||
self.refreshMapPoints()
|
self.refreshMapPoints()
|
||||||
})
|
})
|
||||||
|
|
@ -360,7 +363,9 @@ class CreateScheduleVC: BaseViewController, MAMapViewDelegate {
|
||||||
|
|
||||||
// 缩放至包含所有点
|
// 缩放至包含所有点
|
||||||
if !pointAnnotations.isEmpty {
|
if !pointAnnotations.isEmpty {
|
||||||
rootView.mapView.showAnnotations(pointAnnotations, animated: true)
|
rootView.mapView.showAnnotations(pointAnnotations,
|
||||||
|
edgePadding: UIEdgeInsets(top: kNaviHeight + 20, left: 30, bottom: kScreenHeight / 3 + 20, right: 30),
|
||||||
|
animated: true)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -217,7 +217,7 @@ class CreateScheduleView: UIView {
|
||||||
mv.showsUserLocation = false
|
mv.showsUserLocation = false
|
||||||
mv.showsCompass = false
|
mv.showsCompass = false
|
||||||
mv.userTrackingMode = .none
|
mv.userTrackingMode = .none
|
||||||
DispatchQueue.main.async { mv.logoCenter = CGPoint(x: mv.bounds.width - 55, y: kNaviHeight) }
|
DispatchQueue.main.async { mv.logoCenter = CGPoint(x: kScreenWidth - 50, y: kScreenHeight / 3 * 2 - 20) }
|
||||||
return mv
|
return mv
|
||||||
}()
|
}()
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ class ItineraryDetailView: UIView {
|
||||||
mv.showsUserLocation = false
|
mv.showsUserLocation = false
|
||||||
mv.showsCompass = false
|
mv.showsCompass = false
|
||||||
mv.userTrackingMode = .none
|
mv.userTrackingMode = .none
|
||||||
DispatchQueue.main.async { mv.logoCenter = CGPoint(x: mv.bounds.width - 55, y: kNaviHeight) }
|
// DispatchQueue.main.async { mv.logoCenter = CGPoint(x: mv.bounds.width - 55, y: kNaviHeight) }
|
||||||
return mv
|
return mv
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ class LocationPickerView: UIView {
|
||||||
bottomView.layoutChain
|
bottomView.layoutChain
|
||||||
.edgesHorzontal()
|
.edgesHorzontal()
|
||||||
.bottom()
|
.bottom()
|
||||||
.height(160)
|
.height(160 + kSafeBottomMargin)
|
||||||
|
|
||||||
poiNameLab.layoutChain
|
poiNameLab.layoutChain
|
||||||
.top(16).left(16).right(16)
|
.top(16).left(16).right(16)
|
||||||
|
|
@ -81,7 +81,7 @@ class LocationPickerView: UIView {
|
||||||
mv.zoomLevel = 18
|
mv.zoomLevel = 18
|
||||||
mv.showsUserLocation = false
|
mv.showsUserLocation = false
|
||||||
mv.showsCompass = false
|
mv.showsCompass = false
|
||||||
DispatchQueue.main.async { mv.logoCenter = CGPoint(x: mv.bounds.width - 55, y: 25) }
|
// DispatchQueue.main.async { mv.logoCenter = CGPoint(x: mv.bounds.width - 55, y: kNaviHeight) }
|
||||||
return mv
|
return mv
|
||||||
}()
|
}()
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,9 @@ class ScheduleDetailVC: BaseViewController {
|
||||||
|
|
||||||
override func viewWillAppear(_ animated: Bool) {
|
override func viewWillAppear(_ animated: Bool) {
|
||||||
super.viewWillAppear(animated)
|
super.viewWillAppear(animated)
|
||||||
|
|
||||||
|
guard let systemConfig = AppContextManager.shared.systemConfig, systemConfig.globalDisplay else { return }
|
||||||
|
|
||||||
rootView.vipTipsLab.text = AppContextManager.shared.vip > 1 ? "" : "升级 VIP,可查看具体人员与节点"
|
rootView.vipTipsLab.text = AppContextManager.shared.vip > 1 ? "" : "升级 VIP,可查看具体人员与节点"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -138,16 +138,20 @@ class VipRechargeVC: BaseViewController {
|
||||||
|
|
||||||
let payType = types[self.rootView.selectedPayTypeTag]
|
let payType = types[self.rootView.selectedPayTypeTag]
|
||||||
if payType == "weixin" { // 微信
|
if payType == "weixin" { // 微信
|
||||||
// WXApi.registerApp(model.appId, universalLink: AppSettings.kAppsUniversalLink)
|
guard let partnerId = data["partnerId"] as? String,
|
||||||
//
|
let prepayId = data["prepayId"] as? String,
|
||||||
// let request: PayReq = PayReq()
|
let package = data["package"] as? String,
|
||||||
// request.partnerId = model.partnerId
|
let nonceStr = data["nonceStr"] as? String,
|
||||||
// request.prepayId = model.prepayId
|
let timeStamp = data["timeStamp"] as? String,
|
||||||
// request.package = model.packageValue
|
let sign = data["sign"] as? String else { return }
|
||||||
// request.nonceStr = model.nonceStr
|
let request: PayReq = PayReq()
|
||||||
// request.timeStamp = UInt32(model.timeStamp) ?? 0
|
request.partnerId = partnerId
|
||||||
// request.sign = model.sign
|
request.prepayId = prepayId
|
||||||
// WXApi.send(request)
|
request.package = package
|
||||||
|
request.nonceStr = nonceStr
|
||||||
|
request.timeStamp = UInt32(timeStamp) ?? 0
|
||||||
|
request.sign = sign
|
||||||
|
WXApi.send(request)
|
||||||
}
|
}
|
||||||
else if payType == "alipay" { // 支付宝
|
else if payType == "alipay" { // 支付宝
|
||||||
if let payParam = data["payParam"] as? String, let appId = data["payParam"] as? String {
|
if let payParam = data["payParam"] as? String, let appId = data["payParam"] as? String {
|
||||||
|
|
|
||||||
|
|
@ -168,7 +168,11 @@ class FullscreenWebView: WKWebView {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
fd_interactivePopDisabled = true
|
fd_interactivePopDisabled = true
|
||||||
if style == "default" {
|
if style == "default" {
|
||||||
// setupLeftBarButtonItem(iconColor: "gray")
|
let btn = UIButton(type: .system)
|
||||||
|
btn.setImage(UIImage(named: "Common/back"), for: .normal)
|
||||||
|
btn.tintColor = UIColor(hexStr: "#0F2846")
|
||||||
|
btn.addTarget(self, action: #selector(leftBackClicked(_:)), for: .touchUpInside)
|
||||||
|
navigationItem.leftBarButtonItem = UIBarButtonItem(customView: btn)
|
||||||
}
|
}
|
||||||
// setupErrorView()
|
// setupErrorView()
|
||||||
setupView()
|
setupView()
|
||||||
|
|
@ -312,16 +316,16 @@ class FullscreenWebView: WKWebView {
|
||||||
// backItem.tag = 1
|
// backItem.tag = 1
|
||||||
|
|
||||||
let backBtn = UIButton(frame: CGRect(x: 0, y: 0, width: 19, height: 19))
|
let backBtn = UIButton(frame: CGRect(x: 0, y: 0, width: 19, height: 19))
|
||||||
backBtn.setImage(UIImage(named: "Common/back_\(iconColor)"), for: .normal)
|
backBtn.setImage(UIImage(named: "Common/back"), for: .normal)
|
||||||
backBtn.addTarget(self, action: #selector(leftBackClicked(_:)), for: .touchUpInside)
|
backBtn.addTarget(self, action: #selector(leftBackClicked(_:)), for: .touchUpInside)
|
||||||
backBtn.tintColor = iconColor=="white" ? .white : .black
|
backBtn.tintColor = .black
|
||||||
backBtn.tag = 1
|
backBtn.tag = 1
|
||||||
let backItem = UIBarButtonItem(customView: backBtn)
|
let backItem = UIBarButtonItem(customView: backBtn)
|
||||||
|
|
||||||
let popBtn = UIButton(frame: CGRect(x: 0, y: 0, width: 19, height: 19))
|
let popBtn = UIButton(frame: CGRect(x: 0, y: 0, width: 19, height: 19))
|
||||||
popBtn.setImage(UIImage(named: "Common/close_black"), for: .normal)
|
popBtn.setImage(UIImage(named: "Common/x_black"), for: .normal)
|
||||||
popBtn.addTarget(self, action: #selector(leftBackClicked(_:)), for: .touchUpInside)
|
popBtn.addTarget(self, action: #selector(leftBackClicked(_:)), for: .touchUpInside)
|
||||||
popBtn.tintColor = iconColor=="white" ? .white : .black
|
popBtn.tintColor = .black
|
||||||
popBtn.tag = 2
|
popBtn.tag = 2
|
||||||
|
|
||||||
let popItem = UIBarButtonItem(customView: popBtn)
|
let popItem = UIBarButtonItem(customView: popBtn)
|
||||||
|
|
|
||||||