退出登录,注销账号,alert弹窗

This commit is contained in:
zjx 2025-06-04 15:56:24 +08:00
parent 05eb92630a
commit 27b4f23d7f
58 changed files with 1863 additions and 31 deletions

View File

@ -178,6 +178,19 @@
BFF5AFE22DEED2960044227A /* VPPlayerCoinBuyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5AFE12DEED2960044227A /* VPPlayerCoinBuyView.swift */; };
BFF5AFE62DEEDB7F0044227A /* VPRewardsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5AFE52DEEDB7F0044227A /* VPRewardsViewController.swift */; };
BFF5B21C2DEEDE130044227A /* VPWebViewController+Script.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B21B2DEEDE130044227A /* VPWebViewController+Script.swift */; };
BFF5B2202DEEE2C50044227A /* VPLoginContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B21F2DEEE2C50044227A /* VPLoginContentView.swift */; };
BFF5B2232DEEF8DA0044227A /* VPLoginButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B2222DEEF8DA0044227A /* VPLoginButton.swift */; };
BFF5B2252DEF02080044227A /* VPLoginManager+Apple.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B2242DEF02080044227A /* VPLoginManager+Apple.swift */; };
BFF5B2272DEF022F0044227A /* VPThirdSignModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B2262DEF022F0044227A /* VPThirdSignModel.swift */; };
BFF5B22A2DEFDDF10044227A /* VPMeFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B2292DEFDDF10044227A /* VPMeFooterView.swift */; };
BFF5B22C2DEFE8A80044227A /* VPDeleteAccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B22B2DEFE8A80044227A /* VPDeleteAccountViewController.swift */; };
BFF5B22E2DEFEEAF0044227A /* VPDeleteAccountContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B22D2DEFEEAF0044227A /* VPDeleteAccountContentView.swift */; };
BFF5B2302DEFEF0C0044227A /* VPDeleteAccountNormalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B22F2DEFEF0C0044227A /* VPDeleteAccountNormalView.swift */; };
BFF5B2322DEFF1220044227A /* VPDeleteAccountDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B2312DEFF1220044227A /* VPDeleteAccountDetailView.swift */; };
BFF5B2342DEFF2030044227A /* VPDeleteAccountTipView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B2332DEFF2030044227A /* VPDeleteAccountTipView.swift */; };
BFF5B2372DF013410044227A /* VPAlertWindowManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B2362DF013410044227A /* VPAlertWindowManager.swift */; };
BFF5B2392DF014520044227A /* VPBaseAlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B2382DF014520044227A /* VPBaseAlertView.swift */; };
BFF5B23B2DF018900044227A /* VPAlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B23A2DF018900044227A /* VPAlertView.swift */; };
F939C04AD4003BA127F15C28 /* Pods_Veloria.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34F57E87E765BF8D72A43DCA /* Pods_Veloria.framework */; };
/* End PBXBuildFile section */
@ -362,6 +375,20 @@
BFF5AFE12DEED2960044227A /* VPPlayerCoinBuyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPPlayerCoinBuyView.swift; sourceTree = "<group>"; };
BFF5AFE52DEEDB7F0044227A /* VPRewardsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPRewardsViewController.swift; sourceTree = "<group>"; };
BFF5B21B2DEEDE130044227A /* VPWebViewController+Script.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VPWebViewController+Script.swift"; sourceTree = "<group>"; };
BFF5B21F2DEEE2C50044227A /* VPLoginContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPLoginContentView.swift; sourceTree = "<group>"; };
BFF5B2222DEEF8DA0044227A /* VPLoginButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPLoginButton.swift; sourceTree = "<group>"; };
BFF5B2242DEF02080044227A /* VPLoginManager+Apple.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VPLoginManager+Apple.swift"; sourceTree = "<group>"; };
BFF5B2262DEF022F0044227A /* VPThirdSignModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPThirdSignModel.swift; sourceTree = "<group>"; };
BFF5B2282DEFDAF00044227A /* Veloria.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Veloria.entitlements; sourceTree = "<group>"; };
BFF5B2292DEFDDF10044227A /* VPMeFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPMeFooterView.swift; sourceTree = "<group>"; };
BFF5B22B2DEFE8A80044227A /* VPDeleteAccountViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPDeleteAccountViewController.swift; sourceTree = "<group>"; };
BFF5B22D2DEFEEAF0044227A /* VPDeleteAccountContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPDeleteAccountContentView.swift; sourceTree = "<group>"; };
BFF5B22F2DEFEF0C0044227A /* VPDeleteAccountNormalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPDeleteAccountNormalView.swift; sourceTree = "<group>"; };
BFF5B2312DEFF1220044227A /* VPDeleteAccountDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPDeleteAccountDetailView.swift; sourceTree = "<group>"; };
BFF5B2332DEFF2030044227A /* VPDeleteAccountTipView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPDeleteAccountTipView.swift; sourceTree = "<group>"; };
BFF5B2362DF013410044227A /* VPAlertWindowManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPAlertWindowManager.swift; sourceTree = "<group>"; };
BFF5B2382DF014520044227A /* VPBaseAlertView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPBaseAlertView.swift; sourceTree = "<group>"; };
BFF5B23A2DF018900044227A /* VPAlertView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPAlertView.swift; sourceTree = "<group>"; };
E0BDA3570E00C90877E45AA0 /* Pods-VideoPlayer.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-VideoPlayer.debug.xcconfig"; path = "Target Support Files/Pods-VideoPlayer/Pods-VideoPlayer.debug.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -398,6 +425,7 @@
1B056E2A2DDAC0FD007EE38D /* Veloria */ = {
isa = PBXGroup;
children = (
BFF5B2282DEFDAF00044227A /* Veloria.entitlements */,
1B056E322DDAC18C007EE38D /* AppDelegate */,
1B056E372DDAC1EF007EE38D /* Base */,
1B056E362DDAC1E8007EE38D /* Class */,
@ -434,6 +462,7 @@
1B056E352DDAC1DE007EE38D /* Libs */ = {
isa = PBXGroup;
children = (
BFF5B2352DF013020044227A /* Alert */,
BF5E75D92DE5B89300DE9DFE /* MarqueeView */,
BF5E75B42DE46D9500DE9DFE /* Empty */,
BF0FA7BF2DE45D4500C9E5F2 /* User */,
@ -456,6 +485,7 @@
1B056E522DDACBF4007EE38D /* Home */,
BF0FA7422DDF024400C9E5F2 /* Explore */,
BF0FA6FD2DDC65F300C9E5F2 /* Player */,
BFF5B21D2DEEE28B0044227A /* Login */,
);
path = Class;
sourceTree = "<group>";
@ -637,7 +667,9 @@
isa = PBXGroup;
children = (
BF0FA6D92DDC5CB600C9E5F2 /* VPLoginManager.swift */,
BFF5B2242DEF02080044227A /* VPLoginManager+Apple.swift */,
BF0FA6DB2DDC5CD700C9E5F2 /* VPTokenModel.swift */,
BFF5B2262DEF022F0044227A /* VPThirdSignModel.swift */,
);
path = Login;
sourceTree = "<group>";
@ -910,6 +942,7 @@
children = (
BF0FA7AE2DE443E000C9E5F2 /* VPMeViewController.swift */,
BF5E75AE2DE4632200DE9DFE /* VPAboutUsViewController.swift */,
BFF5B22B2DEFE8A80044227A /* VPDeleteAccountViewController.swift */,
);
path = Controller;
sourceTree = "<group>";
@ -926,6 +959,11 @@
BFF5AFA72DE704DC0044227A /* VPMeCoinCell.swift */,
BFF5AFA92DE7070A0044227A /* VPMeCoinItemView.swift */,
BFF5AFAB2DE70CE20044227A /* VPMeToolCell.swift */,
BFF5B2292DEFDDF10044227A /* VPMeFooterView.swift */,
BFF5B22D2DEFEEAF0044227A /* VPDeleteAccountContentView.swift */,
BFF5B22F2DEFEF0C0044227A /* VPDeleteAccountNormalView.swift */,
BFF5B2312DEFF1220044227A /* VPDeleteAccountDetailView.swift */,
BFF5B2332DEFF2030044227A /* VPDeleteAccountTipView.swift */,
);
path = View;
sourceTree = "<group>";
@ -1052,6 +1090,41 @@
path = Controller;
sourceTree = "<group>";
};
BFF5B21D2DEEE28B0044227A /* Login */ = {
isa = PBXGroup;
children = (
BFF5B21E2DEEE2A50044227A /* Controller */,
BFF5B2212DEEEB0C0044227A /* View */,
);
path = Login;
sourceTree = "<group>";
};
BFF5B21E2DEEE2A50044227A /* Controller */ = {
isa = PBXGroup;
children = (
);
path = Controller;
sourceTree = "<group>";
};
BFF5B2212DEEEB0C0044227A /* View */ = {
isa = PBXGroup;
children = (
BFF5B21F2DEEE2C50044227A /* VPLoginContentView.swift */,
BFF5B2222DEEF8DA0044227A /* VPLoginButton.swift */,
);
path = View;
sourceTree = "<group>";
};
BFF5B2352DF013020044227A /* Alert */ = {
isa = PBXGroup;
children = (
BFF5B23A2DF018900044227A /* VPAlertView.swift */,
BFF5B2382DF014520044227A /* VPBaseAlertView.swift */,
BFF5B2362DF013410044227A /* VPAlertWindowManager.swift */,
);
path = Alert;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@ -1191,10 +1264,12 @@
BF0FA7C32DE45DE300C9E5F2 /* VPUserAPI.swift in Sources */,
BF0FA78B2DE164C100C9E5F2 /* VPSearchResultCell.swift in Sources */,
BF0FA71D2DDC807200C9E5F2 /* UIImageView+VPAdd.swift in Sources */,
BFF5B22C2DEFE8A80044227A /* VPDeleteAccountViewController.swift in Sources */,
BF0FA6DC2DDC5CD700C9E5F2 /* VPTokenModel.swift in Sources */,
BF0FA7572DDF159B00C9E5F2 /* VPExploreViewController.swift in Sources */,
1B056E772DDB3641007EE38D /* VPTabBarItemNormalVew.swift in Sources */,
1B056E4B2DDAC6BA007EE38D /* VPDefine.swift in Sources */,
BFF5B2302DEFEF0C0044227A /* VPDeleteAccountNormalView.swift in Sources */,
1B056E702DDB019B007EE38D /* VPTabBarItemContainer.swift in Sources */,
BF0FA7752DE071B500C9E5F2 /* VPSearchViewController.swift in Sources */,
BF0FA78D2DE16A8B00C9E5F2 /* VPSearchViewModel.swift in Sources */,
@ -1208,6 +1283,7 @@
BF0FA79B2DE1984B00C9E5F2 /* VPCollectListViewController.swift in Sources */,
BF0FA7A32DE1AB1800C9E5F2 /* VPWatchHistoryCell.swift in Sources */,
BF0FA76D2DE053C100C9E5F2 /* VPScrollView.swift in Sources */,
BFF5B2202DEEE2C50044227A /* VPLoginContentView.swift in Sources */,
1B056E5D2DDACD8E007EE38D /* UIFont+VPAdd.swift in Sources */,
BF0FA7282DDC91F800C9E5F2 /* VPCollectionViewCell.swift in Sources */,
BF0FA7672DE0469300C9E5F2 /* VPEpisodeView.swift in Sources */,
@ -1234,15 +1310,18 @@
BF5E75CD2DE5692D00DE9DFE /* JXTransitionDelegateBridge.swift in Sources */,
BF5E75CE2DE5692D00DE9DFE /* JXPushAnimatedTransition.swift in Sources */,
BF5E75CF2DE5692D00DE9DFE /* UIViewController+JXTransition.swift in Sources */,
BFF5B23B2DF018900044227A /* VPAlertView.swift in Sources */,
BF5E75D02DE5692D00DE9DFE /* UIGestureRecognizer+JXTransition.swift in Sources */,
BFF5AFA62DE700420044227A /* VPMeVipPrivilegeItemView.swift in Sources */,
BF5E75D12DE5692D00DE9DFE /* JXPopAnimatedTransition.swift in Sources */,
BF5E75D22DE5692D00DE9DFE /* JXNavigationInteractiveTransition.swift in Sources */,
BFF5B2342DEFF2030044227A /* VPDeleteAccountTipView.swift in Sources */,
BF5E75D32DE5692D00DE9DFE /* JXBaseAnimatedTransition.swift in Sources */,
1B056E462DDAC370007EE38D /* UIScreen+VPAdd.swift in Sources */,
BFF5AFDE2DEEBF370044227A /* VPPlayerRechargeView.swift in Sources */,
BFF5AFAA2DE7070A0044227A /* VPMeCoinItemView.swift in Sources */,
BF0FA7692DE0502900C9E5F2 /* VPEpisodeCell.swift in Sources */,
BFF5B2372DF013410044227A /* VPAlertWindowManager.swift in Sources */,
BF5E75BE2DE54B2800DE9DFE /* VPAboutUsHeaderView.swift in Sources */,
BFF5AFB22DE7FC130044227A /* CGMutablePath+VPAdd.swift in Sources */,
BF0FA73D2DDED2D000C9E5F2 /* VPVideoAPI.swift in Sources */,
@ -1276,11 +1355,14 @@
BF0FA7A52DE4384100C9E5F2 /* AttributedString+VPAdd.swift in Sources */,
BF0FA7652DE00A0E00C9E5F2 /* VPDetailPlayerControlView.swift in Sources */,
BF0FA7342DDEC74500C9E5F2 /* VPCategoryModel.swift in Sources */,
BFF5B2322DEFF1220044227A /* VPDeleteAccountDetailView.swift in Sources */,
1B056E4F2DDAC7FC007EE38D /* VPNavigationController.swift in Sources */,
1B056E3F2DDAC2DB007EE38D /* VPCryptorService.swift in Sources */,
BF0FA7202DDC83AE00C9E5F2 /* JXButton.swift in Sources */,
BF0FA7912DE16CBF00C9E5F2 /* VPSearchHistoryView.swift in Sources */,
BFF5AFE22DEED2960044227A /* VPPlayerCoinBuyView.swift in Sources */,
BFF5B2272DEF022F0044227A /* VPThirdSignModel.swift in Sources */,
BFF5B22A2DEFDDF10044227A /* VPMeFooterView.swift in Sources */,
BF0FA7992DE1951A00C9E5F2 /* VPMyListViewController.swift in Sources */,
BF0FA7452DDF027900C9E5F2 /* VPPlayer.swift in Sources */,
BFF5AFC62DE863C00044227A /* VPGradientButton.swift in Sources */,
@ -1300,13 +1382,17 @@
BF0FA7022DDC667C00C9E5F2 /* VPVideoInfoModel.swift in Sources */,
BF0FA77B2DE0788A00C9E5F2 /* UIStackView+VPAdd.swift in Sources */,
BF0FA7BE2DE4592A00C9E5F2 /* UserDefaults+VPAdd.swift in Sources */,
BFF5B2232DEEF8DA0044227A /* VPLoginButton.swift in Sources */,
BF0FA76F2DE062A700C9E5F2 /* VPRateSelectedView.swift in Sources */,
BF0FA7772DE0735800C9E5F2 /* VPSearchInputView.swift in Sources */,
BFF5AFB62DE803A30044227A /* VPVipPrivilegeItemView.swift in Sources */,
BFF5AFB82DE832580044227A /* VPVipBuyCell.swift in Sources */,
BFF5B22E2DEFEEAF0044227A /* VPDeleteAccountContentView.swift in Sources */,
BFF5B2252DEF02080044227A /* VPLoginManager+Apple.swift in Sources */,
BF0FA7892DE161F200C9E5F2 /* VPSearchResultView.swift in Sources */,
1B056E792DDB365A007EE38D /* VPTabBarItemSelectedView.swift in Sources */,
1B056E722DDB022F007EE38D /* VPTabBarItem.swift in Sources */,
BFF5B2392DF014520044227A /* VPBaseAlertView.swift in Sources */,
BFF5AFCC2DE98C7F0044227A /* VPOrderRecordsViewController.swift in Sources */,
1B056E412DDAC30A007EE38D /* VPModel.swift in Sources */,
BF0FA70A2DDC69C800C9E5F2 /* VPTableViewCell.swift in Sources */,
@ -1370,6 +1456,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Veloria/Veloria.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
@ -1407,6 +1494,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Veloria/Veloria.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;

View File

@ -193,4 +193,45 @@ extension UIColor {
static func color00211A(alpha: CGFloat = 1) -> UIColor {
return UIColor(rgb: 0x00211A, alpha: alpha)
}
static func color333333(alpha: CGFloat = 1) -> UIColor {
return UIColor(rgb: 0x333333, alpha: alpha)
}
static func color585858(alpha: CGFloat = 1) -> UIColor {
return UIColor(rgb: 0x585858, alpha: alpha)
}
static func colorB3B3B3(alpha: CGFloat = 1) -> UIColor {
return UIColor(rgb: 0xB3B3B3, alpha: alpha)
}
static func color080B16(alpha: CGFloat = 1) -> UIColor {
return UIColor(rgb: 0x080B16, alpha: alpha)
}
static func color272A30(alpha: CGFloat = 1) -> UIColor {
return UIColor(rgb: 0x272A30, alpha: alpha)
}
static func color8B8B8B(alpha: CGFloat = 1) -> UIColor {
return UIColor(rgb: 0x8B8B8B, alpha: alpha)
}
static func color126B4E(alpha: CGFloat = 1) -> UIColor {
return UIColor(rgb: 0x126B4E, alpha: alpha)
}
static func color1A2D22(alpha: CGFloat = 1) -> UIColor {
return UIColor(rgb: 0x1A2D22, alpha: alpha)
}
static func colorC8C8C8(alpha: CGFloat = 1) -> UIColor {
return UIColor(rgb: 0xC8C8C8, alpha: alpha)
}
static func color024E3D(alpha: CGFloat = 1) -> UIColor {
return UIColor(rgb: 0x024E3D, alpha: alpha)
}
}

View File

@ -6,6 +6,7 @@
//
import UIKit
import SmartCodable
class VPUserAPI: NSObject {
@ -19,4 +20,39 @@ class VPUserAPI: NSObject {
completer?(response.data)
}
}
///
static func requestThirdLogin(model: VPThirdSignModel, completer: ((_ token: VPTokenModel?) -> Void)?) {
var param = VPNetworkParameters(path: "/customer/login")
param.parameters = model.toDictionary()
VPNetwork.request(parameters: param) { (response: VPNetworkResponse<VPTokenModel>) in
completer?(response.data)
}
}
///退
static func requestLogout(completer: ((_ token: VPTokenModel?) -> Void)?) {
var param = VPNetworkParameters(path: "/customer/signout")
param.isLoding = true
VPNetwork.request(parameters: param) { (response: VPNetworkResponse<VPTokenModel>) in
completer?(response.data)
}
}
///
static func requestDelete(completer: ((_ isFinish: Bool) -> Void)?) {
var param = VPNetworkParameters(path: "/customer/logoff")
param.isLoding = true
VPNetwork.request(parameters: param) { (response: VPNetworkResponse<String>) in
if response.code == VPNetworkCodeSucceed {
completer?(true)
} else {
completer?(false)
}
}
}
}

View File

@ -48,8 +48,21 @@ class VPGradientLabel: UILabel {
let textLayer = CATextLayer()
textLayer.string = string
textLayer.frame = bounds
textLayer.alignmentMode = .center
switch self.textAlignment {
case .left:
textLayer.alignmentMode = .left
case .center:
textLayer.alignmentMode = .center
case .right:
textLayer.alignmentMode = .right
case .justified:
textLayer.alignmentMode = .justified
case .natural:
textLayer.alignmentMode = .natural
default: break
}
textLayer.contentsScale = UIScreen.main.scale
textLayer.isWrapped = true
gradientLayer.mask = textLayer
CATransaction.commit()

View File

@ -0,0 +1,72 @@
//
// VPLoginButton.swift
// Veloria
//
// Created by on 2025/6/3.
//
import UIKit
class VPLoginButton: UIControl {
var icon: UIImage? {
didSet {
iconImageView.image = icon
}
}
var title: String? {
didSet {
titleLabel.text = title
}
}
override var intrinsicContentSize: CGSize {
return .init(width: UIScreen.width, height: 48)
}
private lazy var iconImageView: UIImageView = {
let imageView = UIImageView()
return imageView
}()
private lazy var titleLabel: UILabel = {
let label = UILabel()
label.font = .fontRegular(ofSize: 14)
label.textColor = .color333333()
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
layer.cornerRadius = 24
layer.masksToBounds = true
backgroundColor = .colorFFFFFF()
vp_setupUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension VPLoginButton {
private func vp_setupUI() {
addSubview(iconImageView)
addSubview(titleLabel)
iconImageView.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.left.equalToSuperview().offset(40)
}
titleLabel.snp.makeConstraints { make in
make.center.equalToSuperview()
}
}
}

View File

@ -0,0 +1,203 @@
//
// VPLoginContentView.swift
// Veloria
//
// Created by on 2025/6/3.
//
import UIKit
class VPLoginContentView: HWPanModalContentView {
private lazy var bgView: UIImageView = {
let imageView = UIImageView(image: UIImage(named: "bg_image_01"))
return imageView
}()
private lazy var closeButton: UIButton = {
let button = UIButton(type: .custom)
button.setImage(UIImage(named: "close_icon_02"), for: .normal)
button.addTarget(self, action: #selector(handleCloseButton), for: .touchUpInside)
return button
}()
private lazy var titleLabel: UILabel = {
let label = UILabel()
label.font = .fontMedium(ofSize: 16)
label.textColor = .colorFFFFFF()
label.text = String(format: "Welcome to %@".localized, "kAppName".localized)
return label
}()
private lazy var agreementLabel: YYLabel = {
let userAgreementText = "User Agreement".localized
let privacyPolicyText = "Privacy Policy".localized
let text = String(format: "kLoginAgreementText".localized, userAgreementText, privacyPolicyText)
let range1 = text.ocString().range(of: userAgreementText)
let range2 = text.ocString().range(of: privacyPolicyText)
let string = NSMutableAttributedString(string: text)
string.font = .fontRegular(ofSize: 12)
string.color = .colorB5B5B5()
string.alignment = .center
string.setUnderlineColor(string.color, range: range1)
string.setUnderlineColor(string.color, range: range2)
string.setUnderlineStyle(.single, range: range1)
string.setUnderlineStyle(.single, range: range2)
string.setTextHighlight(range1, color: nil, backgroundColor: nil) { [weak self] _, _, _, _ in
self?.openWebPage(url: kVPUserAgreementWebUrl)
}
string.setTextHighlight(range2, color: nil, backgroundColor: nil) { [weak self] _, _, _, _ in
self?.openWebPage(url: kVPPrivacyPolicyWebUrl)
}
let textLayout = YYTextLayout(containerSize: .init(width: UIScreen.width - 30, height: 100), text: string)
let label = YYLabel()
label.textLayout = textLayout
return label
}()
private lazy var stackView: UIStackView = {
let stackView = UIStackView(arrangedSubviews: [appleButton])
stackView.axis = .vertical
stackView.spacing = 20
return stackView
}()
private lazy var appleButton: VPLoginButton = {
let button = VPLoginButton()
button.icon = UIImage(named: "apple_icon_01")
button.title = "Login with Apple".localized
button.addTarget(self, action: #selector(handleAppleButton), for: .touchUpInside)
return button
}()
override init(frame: CGRect) {
super.init(frame: frame)
vp_setupUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc private func handleCloseButton() {
self.dismiss(animated: true) {
}
}
//MARK: HWPanModalPresentable
override func panScrollable() -> UIScrollView? {
return nil
}
override func longFormHeight() -> PanModalHeight {
return PanModalHeightMake(.content, UIScreen.height * (2 / 3))
}
override func showDragIndicator() -> Bool {
return false
}
override func backgroundConfig() -> HWBackgroundConfig {
let config = HWBackgroundConfig()
config.backgroundAlpha = 0.6
return config
}
override func allowsDragToDismiss() -> Bool {
return false
}
override func allowsTapBackgroundToDismiss() -> Bool {
return false
}
override func allowsPullDownWhenShortState() -> Bool {
return false
}
override func minVerticalVelocityToTriggerDismiss() -> CGFloat {
return 0
}
override func showsScrollableVerticalScrollIndicator() -> Bool {
return false
}
}
extension VPLoginContentView {
private func openWebPage(url: String) {
let vc = VPWebViewController()
vc.configNavigationBack()
vc.urlStr = url
let nav = VPNavigationController(rootViewController: vc)
nav.modalPresentationStyle = .fullScreen
VPAppTool.rootViewController?.present(nav, animated: true)
}
@objc private func handleAppleButton() {
login(type: .apple)
}
private func login(type: VPLoginManager.LoginType) {
VPHUD.show()
VPLoginManager.manager.login(type: type, presentingViewController: nil) { [weak self] isFinish in
VPHUD.dismiss()
guard let self = self else { return }
if isFinish {
self.dismiss(animated: true) {
}
} else {
}
}
}
}
extension VPLoginContentView {
private func vp_setupUI() {
addSubview(bgView)
addSubview(closeButton)
addSubview(titleLabel)
addSubview(agreementLabel)
addSubview(stackView)
bgView.snp.makeConstraints { make in
make.left.right.top.equalToSuperview()
}
closeButton.snp.makeConstraints { make in
make.right.equalToSuperview().offset(-15)
make.top.equalToSuperview().offset(15)
}
titleLabel.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.centerY.equalTo(closeButton)
}
agreementLabel.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.bottom.equalToSuperview().offset(-(UIScreen.tabbarSafeBottomMargin + 10))
make.width.equalTo(agreementLabel.textLayout?.textBoundingSize.width ?? 0)
make.height.equalTo(agreementLabel.textLayout?.textBoundingSize.height ?? 0)
}
stackView.snp.makeConstraints { make in
make.center.equalToSuperview()
make.left.equalToSuperview().offset(15)
}
}
}

View File

@ -0,0 +1,202 @@
//
// VPDeleteAccountViewController.swift
// Veloria
//
// Created by on 2025/6/4.
//
import UIKit
class VPDeleteAccountViewController: VPViewController {
private lazy var scrollView: VPScrollView = {
let scrollView = VPScrollView()
return scrollView
}()
private lazy var iconImageView: UIImageView = {
let imageView = UIImageView(image: UIImage(named: "warning_icon_01"))
return imageView
}()
private lazy var iconTextLabel: UILabel = {
let label = UILabel()
label.font = .fontRegular(ofSize: 14)
label.textColor = .colorBE0069()
label.text = "DeleteAccount_tips_1".localized
return label
}()
private lazy var stackView: UIStackView = {
let view = UIStackView()
view.axis = .vertical
view.spacing = 18
view.addArrangedSubview(contentView1)
view.addArrangedSubview(contentView3)
view.addArrangedSubview(contentView2)
return view
}()
private lazy var contentView1: VPDeleteAccountNormalView = {
let view = VPDeleteAccountNormalView()
view.text = "DeleteAccount_tips_2".localized
return view
}()
private lazy var contentView2: VPDeleteAccountNormalView = {
let view = VPDeleteAccountNormalView()
view.text = "DeleteAccount_tips_3".localized
return view
}()
private lazy var contentView3: VPDeleteAccountDetailView = {
let view = VPDeleteAccountDetailView()
return view
}()
private lazy var checkButton: UIButton = {
let button = UIButton(type: .custom)
button.setImage(UIImage(named: "choice_icon_01"), for: .normal)
button.setImage(UIImage(named: "choice_icon_01_selected"), for: .selected)
button.setImage(UIImage(named: "choice_icon_01_selected"), for: [.selected, .highlighted])
button.addTarget(self, action: #selector(handleCheckButton), for: .touchUpInside)
button.setContentHuggingPriority(.required, for: .horizontal)
button.setContentCompressionResistancePriority(.required, for: .horizontal)
return button
}()
private lazy var checkLabel: UILabel = {
let label = UILabel()
label.font = .fontMedium(ofSize: 14)
label.textColor = .colorFFFFFF()
label.numberOfLines = 0
label.text = "DeleteAccount_tips_4".localized
return label
}()
private lazy var deleteButton: UIButton = {
let config = UIButton.Configuration.plain()
let button = VPGradientButton(configuration: config)
button.layer.cornerRadius = 24
button.layer.masksToBounds = true
button.isEnabled = false
button.locations = [0, 1]
button.startPoint = .init(x: 0, y: 0.3)
button.endPoint = .init(x: 1, y: 0.8)
button.addTarget(self, action: #selector(handleDeleteButton), for: .touchUpInside)
button.configurationUpdateHandler = { button in
guard let button = button as? VPGradientButton else { return }
let title = "Delete Account".localized
if button.isEnabled {
button.configuration?.attributedTitle = .createAttributedString(string: title, color: .colorFFFFFF(), font: .fontRegular(ofSize: 14))
button.bt_setGradientBorder()
button.colors = [UIColor.color05CEA0(alpha: 0.3).cgColor, UIColor.color7C174F(alpha: 0.3).cgColor]
} else {
button.configuration?.attributedTitle = .createAttributedString(string: title, color: .color8B8B8B(), font: .fontRegular(ofSize: 14))
button.bt_removeGradientBorder()
button.colors = [UIColor.color272A30().cgColor, UIColor.color272A30().cgColor]
}
}
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
self.bgImageView.isHidden = true
self.view.backgroundColor = .color080B16()
self.title = "Account Deletion".localized
vp_setupUI()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.setNavigationBarHidden(false, animated: true)
self.setNavigationNormalStyle()
}
}
extension VPDeleteAccountViewController {
@objc private func handleCheckButton() {
self.checkButton.isSelected = !self.checkButton.isSelected
self.deleteButton.isEnabled = self.checkButton.isSelected
}
@objc private func handleDeleteButton() {
let alert = VPAlertView(title: "kDeleteAccountAlertTitle".localized, subtitle: "kDeleteAccountAlertText".localized, icon: UIImage(named: "alert_icon_01"), normalButtonText: "Delete Forever".localized, highlightButtonText: "Cancel".localized)
alert.show()
alert.clickNormalButton = {
VPLoginManager.manager.deleteAccount { [weak self] isFinish in
guard let self = self else { return }
if isFinish {
self.navigationController?.popViewController(animated: true)
}
}
}
}
}
extension VPDeleteAccountViewController {
private func vp_setupUI() {
view.addSubview(scrollView)
scrollView.addSubview(iconImageView)
scrollView.addSubview(iconTextLabel)
scrollView.addSubview(stackView)
scrollView.addSubview(checkButton)
scrollView.addSubview(checkLabel)
scrollView.addSubview(deleteButton)
scrollView.snp.makeConstraints { make in
make.left.right.bottom.equalToSuperview()
make.top.equalToSuperview().offset(UIScreen.navBarHeight)
}
iconImageView.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.top.equalToSuperview().offset(10)
}
iconTextLabel.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.top.equalTo(iconImageView.snp.bottom).offset(12)
}
stackView.snp.makeConstraints { make in
make.left.equalToSuperview().offset(16)
make.centerX.equalToSuperview()
make.top.equalTo(iconTextLabel.snp.bottom).offset(18)
}
checkButton.snp.makeConstraints { make in
make.left.equalToSuperview().offset(16)
make.top.equalTo(stackView.snp.bottom).offset(25)
}
checkLabel.snp.makeConstraints { make in
make.left.equalTo(checkButton.snp.right).offset(10)
make.right.lessThanOrEqualTo(stackView)
make.top.equalTo(checkButton).offset(2)
}
deleteButton.snp.makeConstraints { make in
make.left.equalTo(stackView)
make.right.equalTo(stackView)
make.top.equalTo(checkLabel.snp.bottom).offset(20)
make.height.equalTo(48)
make.bottom.equalToSuperview().offset(-(UIScreen.tabbarSafeBottomMargin + 20))
}
}
}

View File

@ -10,28 +10,7 @@ import UIKit
class VPMeViewController: VPViewController {
private lazy var dataArr: [[VPMeItem]] = {
let arr = [
[
VPMeItem(cellKey: .userInfo),
],
[
VPMeItem(cellKey: .vip)
],
[
VPMeItem(cellKey: .coin)
],
[
VPMeItem(cellKey: .tool)
],
[
VPMeItem(icon: UIImage(named: "me_item_icon_05"), title: "Language".localized, type: .language, cellKey: .normal),
VPMeItem(icon: UIImage(named: "me_item_icon_01"), title: "Privacy Policy".localized, type: .privacyPolicy, cellKey: .normal),
VPMeItem(icon: UIImage(named: "me_item_icon_02"), title: "User Agreement".localized, type: .userAgreement, cellKey: .normal),
// VPMeItem(icon: UIImage(named: "me_item_icon_04"), title: "Help Center".localized, type: .feedback, cellKey: .normal),
VPMeItem(icon: UIImage(named: "me_item_icon_03"), title: "About Us".localized, type: .aboutUs, cellKey: .normal),
]
]
return arr
return self.createDataArr()
}()
@ -53,8 +32,20 @@ class VPMeViewController: VPViewController {
return tableView
}()
private lazy var footerView: VPMeFooterView = {
let view = VPMeFooterView(frame: .init(x: 0, y: 0, width: UIScreen.width, height: 80))
view.userInfo = VPLoginManager.manager.userInfo
return view
}()
deinit {
NotificationCenter.default.removeObserver(self)
}
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(userInfoUpdateNotification), name: VPLoginManager.userInfoUpdateNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(loginStateDidChangeNotification), name: VPLoginManager.loginStateDidChangeNotification, object: nil)
vp_setupUI()
@ -80,11 +71,28 @@ class VPMeViewController: VPViewController {
}
}
}
extension VPMeViewController {
@objc private func userInfoUpdateNotification() {
self.footerView.userInfo = VPLoginManager.manager.userInfo
self.tableView.reloadData()
}
@objc private func loginStateDidChangeNotification() {
self.dataArr = createDataArr()
self.tableView.reloadData()
}
}
extension VPMeViewController {
private func vp_setupUI() {
tableView.tableFooterView = self.footerView
view.addSubview(tableView)
tableView.snp.makeConstraints { make in
@ -150,6 +158,10 @@ extension VPMeViewController: UITableViewDelegate, UITableViewDataSource {
let vc = VPAboutUsViewController()
self.navigationController?.pushViewController(vc, animated: true)
case .deleteAccount:
let vc = VPDeleteAccountViewController()
self.navigationController?.pushViewController(vc, animated: true)
default:
break
}
@ -163,10 +175,42 @@ extension VPMeViewController {
///
private func requestUserInfo(completer: (() -> Void)? = nil) {
VPLoginManager.manager.updateUserInfo { [weak self] in
self?.tableView.reloadData()
VPLoginManager.manager.updateUserInfo {
completer?()
}
}
private func createDataArr() -> [[VPMeItem]] {
var dataArr = [
[
VPMeItem(cellKey: .userInfo),
],
[
VPMeItem(cellKey: .vip)
],
[
VPMeItem(cellKey: .coin)
],
[
VPMeItem(cellKey: .tool)
]
]
var cellArr: [VPMeItem] = []
cellArr.append(VPMeItem(icon: UIImage(named: "me_item_icon_05"), title: "Language".localized, type: .language, cellKey: .normal))
cellArr.append(VPMeItem(icon: UIImage(named: "me_item_icon_01"), title: "Privacy Policy".localized, type: .privacyPolicy, cellKey: .normal))
cellArr.append(VPMeItem(icon: UIImage(named: "me_item_icon_02"), title: "User Agreement".localized, type: .userAgreement, cellKey: .normal))
// cellArr.append(VPMeItem(icon: UIImage(named: "me_item_icon_04"), title: "Help Center".localized, type: .feedback, cellKey: .normal))
cellArr.append(VPMeItem(icon: UIImage(named: "me_item_icon_03"), title: "About Us".localized, type: .aboutUs, cellKey: .normal))
if VPLoginManager.manager.userInfo?.is_tourist == false {
cellArr.append(VPMeItem(icon: UIImage(named: "me_item_icon_06"), title: "Delet Account".localized, type: .deleteAccount, cellKey: .normal))
}
dataArr.append(cellArr)
return dataArr
}
}

View File

@ -13,6 +13,7 @@ struct VPMeItem {
case userAgreement
case aboutUs
case feedback
case deleteAccount
case informationProtection
case civizatioConvention
case informationSharing

View File

@ -0,0 +1,23 @@
//
// VPDeleteAccountContentView.swift
// Veloria
//
// Created by on 2025/6/4.
//
import UIKit
class VPDeleteAccountContentView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .color272A30()
layer.cornerRadius = 8
layer.masksToBounds = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

View File

@ -0,0 +1,87 @@
//
// VPDeleteAccountDetailView.swift
// Veloria
//
// Created by on 2025/6/4.
//
import UIKit
class VPDeleteAccountDetailView: VPDeleteAccountContentView {
private lazy var titleLabel: UILabel = {
let label = UILabel()
label.font = .fontRegular(ofSize: 14)
label.textColor = .colorFFFFFF()
label.numberOfLines = 0
label.text = "DeleteAccount_tips_5".localized
return label
}()
private lazy var stackView: UIStackView = {
let view = UIStackView(arrangedSubviews: [tipView1, tipView2, tipView3, tipView4])
view.axis = .vertical
view.spacing = 12
return view
}()
private lazy var tipView1: VPDeleteAccountTipView = {
let view = VPDeleteAccountTipView()
view.title = "DeleteAccount_tips_title_1".localized
view.text = "DeleteAccount_tips_text_1".localized
return view
}()
private lazy var tipView2: VPDeleteAccountTipView = {
let view = VPDeleteAccountTipView()
view.title = "DeleteAccount_tips_title_2".localized
view.text = "DeleteAccount_tips_text_2".localized
return view
}()
private lazy var tipView3: VPDeleteAccountTipView = {
let view = VPDeleteAccountTipView()
view.title = "DeleteAccount_tips_title_3".localized
view.text = "DeleteAccount_tips_text_3".localized
return view
}()
private lazy var tipView4: VPDeleteAccountTipView = {
let view = VPDeleteAccountTipView()
view.title = "DeleteAccount_tips_title_4".localized
// view.text = "DeleteAccount_tips_text_1".localized
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
vp_setupUI()
}
@MainActor required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension VPDeleteAccountDetailView {
private func vp_setupUI() {
addSubview(titleLabel)
addSubview(stackView)
titleLabel.snp.makeConstraints { make in
make.left.equalToSuperview().offset(13)
make.top.equalToSuperview().offset(12)
make.right.lessThanOrEqualToSuperview().offset(-13)
}
stackView.snp.makeConstraints { make in
make.left.right.equalToSuperview()
make.top.equalTo(titleLabel.snp.bottom).offset(12)
make.bottom.equalToSuperview().offset(-10)
}
}
}

View File

@ -0,0 +1,45 @@
//
// VPDeleteAccountNormalView.swift
// Veloria
//
// Created by on 2025/6/4.
//
import UIKit
class VPDeleteAccountNormalView: VPDeleteAccountContentView {
var text: String? {
didSet {
let str = NSMutableAttributedString(string: text ?? "")
str.lineSpacing = 4
label.attributedText = str
}
}
private lazy var label: UILabel = {
let label = UILabel()
label.numberOfLines = 0
label.font = .fontRegular(ofSize: 14)
label.textColor = .colorFFFFFF()
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(label)
label.snp.makeConstraints { make in
make.left.equalToSuperview().offset(12)
make.centerY.equalToSuperview()
make.top.equalToSuperview().offset(12)
make.right.lessThanOrEqualToSuperview().offset(-12)
}
}
@MainActor required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

View File

@ -0,0 +1,89 @@
//
// VPDeleteAccountTipView.swift
// Veloria
//
// Created by on 2025/6/4.
//
import UIKit
class VPDeleteAccountTipView: UIView {
var title: String? {
didSet {
titleLabel.text = title
}
}
var text: String? {
didSet {
let str = NSMutableAttributedString(string: text ?? "")
str.lineSpacing = 4
textLabel.attributedText = str
}
}
private lazy var dotView: UIView = {
let view = UIView()
view.backgroundColor = .colorFFFFFF()
view.layer.cornerRadius = 2
view.layer.masksToBounds = true
return view
}()
private lazy var titleLabel: UILabel = {
let label = UILabel()
label.font = .fontRegular(ofSize: 12)
label.textColor = .colorFFFFFF()
return label
}()
private lazy var textLabel: UILabel = {
let label = UILabel()
label.font = .fontRegular(ofSize: 12)
label.textColor = .color8B8B8B()
label.numberOfLines = 0
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
vp_setupUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension VPDeleteAccountTipView {
private func vp_setupUI() {
addSubview(dotView)
addSubview(titleLabel)
addSubview(textLabel)
dotView.snp.makeConstraints { make in
make.left.equalToSuperview().offset(16)
make.centerY.equalTo(titleLabel)
make.width.height.equalTo(4)
}
titleLabel.snp.makeConstraints { make in
make.top.equalToSuperview()
make.left.equalToSuperview().offset(24)
make.right.lessThanOrEqualToSuperview().offset(-24)
}
textLabel.snp.makeConstraints { make in
make.left.equalTo(titleLabel)
make.top.equalTo(titleLabel.snp.bottom).offset(4)
make.right.lessThanOrEqualToSuperview().offset(-24)
make.bottom.equalToSuperview()
}
}
}

View File

@ -50,9 +50,9 @@ class VPMeCoinCell: VPTableViewCell {
extension VPMeCoinCell {
private func vp_setupUI() {
addSubview(lineView)
addSubview(coinView1)
addSubview(coinView2)
contentView.addSubview(lineView)
contentView.addSubview(coinView1)
contentView.addSubview(coinView2)
lineView.snp.makeConstraints { make in
make.centerX.equalToSuperview()

View File

@ -0,0 +1,65 @@
//
// VPMeFooterView.swift
// Veloria
//
// Created by on 2025/6/4.
//
import UIKit
class VPMeFooterView: UIView {
var userInfo: VPUserInfo? {
didSet {
button.isSelected = !(userInfo?.is_tourist ?? true)
}
}
private lazy var button: UIButton = {
let button = UIButton(type: .custom)
button.layer.cornerRadius = 20
button.layer.masksToBounds = true
button.layer.borderColor = UIColor.color585858().cgColor
button.layer.borderWidth = 1
button.setTitle("Log In".localized, for: .normal)
button.setTitle("Sign Out".localized, for: .selected)
button.setTitle("Sign Out".localized, for: [.selected, .highlighted])
button.setTitleColor(.colorB3B3B3(), for: .normal)
button.titleLabel?.font = .fontRegular(ofSize: 14)
button.addTarget(self, action: #selector(handleButton), for: .touchUpInside)
return button
}()
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(button)
button.snp.makeConstraints { make in
make.left.equalToSuperview().offset(15)
make.centerX.equalToSuperview()
make.top.equalToSuperview().offset(20)
make.height.equalTo(40)
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc private func handleButton() {
if userInfo?.is_tourist == true {
let view = VPLoginContentView()
view.present(in: nil)
} else {
let alert = VPAlertView(title: "kLogoutAlertTitle".localized, subtitle: "kLogoutAlertText".localized, icon: UIImage(named: "alert_icon_02"), normalButtonText: "Log Out".localized, highlightButtonText: "Cancel".localized).show()
alert.clickNormalButton = {
VPLoginManager.manager.logout(completer: nil)
}
}
}
}

View File

@ -21,6 +21,9 @@ class VPMeUserInfoCell: VPTableViewCell {
}
idLabel.text = "ID \(userInfo?.customer_id ?? "")"
loginButton.isHidden = !(userInfo?.is_tourist ?? true)
}
}
@ -47,6 +50,28 @@ class VPMeUserInfoCell: VPTableViewCell {
return label
}()
private lazy var loginButton: VPGradientButton = {
let title = AttributedString.createAttributedString(string: "Check in".localized, color: .colorFFFFFF(), font: .fontRegular(ofSize: 12))
var config = UIButton.Configuration.plain()
config.imagePlacement = .leading
config.imagePadding = 6
config.image = UIImage(named: "login_icon_01")
config.attributedTitle = title
config.contentInsets = .init(top: 0, leading: 12, bottom: 0, trailing: 12)
let button = VPGradientButton(configuration: config)
button.colors = [UIColor.color05CEA0(alpha: 0.3).cgColor, UIColor.color7C174F(alpha: 0.3).cgColor]
button.locations = [0, 1]
button.startPoint = .init(x: 0, y: 0.3)
button.endPoint = .init(x: 1, y: 0.8)
button.layer.cornerRadius = 17
button.layer.masksToBounds = true
button.bt_setGradientBorder()
button.addTarget(self, action: #selector(handleLoginButton), for: .touchUpInside)
return button
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
@ -57,6 +82,11 @@ class VPMeUserInfoCell: VPTableViewCell {
fatalError("init(coder:) has not been implemented")
}
@objc private func handleLoginButton() {
let view = VPLoginContentView()
view.present(in: nil)
}
}
extension VPMeUserInfoCell {
@ -65,6 +95,7 @@ extension VPMeUserInfoCell {
contentView.addSubview(avatarImageView)
contentView.addSubview(nicknameLabel)
contentView.addSubview(idLabel)
contentView.addSubview(loginButton)
avatarImageView.snp.makeConstraints { make in
make.left.equalToSuperview()
@ -84,6 +115,12 @@ extension VPMeUserInfoCell {
make.bottom.equalTo(avatarImageView).offset(-3)
}
loginButton.snp.makeConstraints { make in
make.centerY.equalTo(avatarImageView)
make.right.equalToSuperview()
make.height.equalTo(34)
}
}
}

View File

@ -0,0 +1,206 @@
//
// VPAlertView.swift
// Veloria
//
// Created by on 2025/6/4.
//
import UIKit
class VPAlertView: VPBaseAlertView {
var clickNormalButton: (() -> Void)?
var clickHighlightButton: (() -> Void)?
private lazy var bgView: UIImageView = {
let imageView = UIImageView(image: UIImage(named: "alert_bg_image_01"))
imageView.backgroundColor = .colorFFFFFF()
imageView.layer.cornerRadius = 18
imageView.layer.masksToBounds = true
imageView.isUserInteractionEnabled = true
return imageView
}()
private lazy var iconImageView: UIImageView = {
let imageView = UIImageView()
return imageView
}()
private lazy var titleIconImageView: UIImageView = {
let imageView = UIImageView(image: UIImage(named: "alert_title_icon_01"))
return imageView
}()
private lazy var titleLabel: VPGradientLabel = {
let label = VPGradientLabel()
label.gradientLayer.colors = [UIColor.color126B4E().cgColor, UIColor.color1A2D22().cgColor]
label.gradientLayer.startPoint = .init(x: 0.5, y: 0)
label.gradientLayer.endPoint = .init(x: 0.5, y: 1)
label.numberOfLines = 0
return label
}()
private lazy var textLabel: VPGradientLabel = {
let label = VPGradientLabel()
label.gradientLayer.colors = [UIColor.color126B4E().cgColor, UIColor.color1A2D22().cgColor]
label.gradientLayer.startPoint = .init(x: 0.5, y: 0)
label.gradientLayer.endPoint = .init(x: 0.5, y: 1)
label.numberOfLines = 0
return label
}()
private lazy var normalButton: UIButton = {
let button = UIButton(type: .custom)
button.setTitleColor(.colorC8C8C8(), for: .normal)
button.titleLabel?.font = .fontMedium(ofSize: 14)
button.layer.cornerRadius = 24
button.layer.masksToBounds = true
button.layer.borderWidth = 1
button.layer.borderColor = UIColor.colorC8C8C8().cgColor
button.addTarget(self, action: #selector(handleNormalButton), for: .touchUpInside)
return button
}()
private lazy var highlightButton: UIButton = {
let button = VPGradientButton(type: .custom)
button.setTitleColor(.colorFFFFFF(), for: .normal)
button.titleLabel?.font = .fontMedium(ofSize: 14)
button.locations = [0, 1]
button.startPoint = .init(x: 0, y: 0.3)
button.endPoint = .init(x: 1, y: 0.8)
button.colors = [UIColor.color05CEA0().cgColor, UIColor.color7C174F().cgColor]
button.layer.cornerRadius = 24
button.layer.borderWidth = 1.5
button.layer.borderColor = UIColor.colorFFFFFF().cgColor
button.layer.shadowColor = UIColor.color024E3D(alpha: 0.4).cgColor
button.layer.shadowOpacity = 1
button.layer.shadowOffset = .init(width: 0, height: 4)
button.addTarget(self, action: #selector(handleHighlightButton), for: .touchUpInside)
return button
}()
private lazy var buttonStackView: UIStackView = {
let view = UIStackView()
view.axis = .horizontal
view.spacing = 10
view.alignment = .fill
view.distribution = .fillEqually
return view
}()
private lazy var closeButton: UIButton = {
let button = UIButton(type: .custom)
button.setImage(UIImage(named: "close_icon_02"), for: .normal)
button.addTarget(self, action: #selector(dismiss), for: .touchUpInside)
return button
}()
init(title: String, subtitle: String, icon: UIImage?, normalButtonText: String?, highlightButtonText: String?) {
super.init(frame: UIScreen.main.bounds)
iconImageView.image = icon
let titleStr = NSMutableAttributedString(string: title)
titleStr.lineSpacing = 4
titleStr.font = .fontMedium(ofSize: 20)
titleLabel.attributedText = titleStr
let textStr = NSMutableAttributedString(string: subtitle)
textStr.lineSpacing = 4
textStr.font = .fontRegular(ofSize: 15)
textLabel.attributedText = textStr
normalButton.setTitle(normalButtonText, for: .normal)
highlightButton.setTitle(highlightButtonText, for: .normal)
vp_setupUI()
}
@MainActor required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension VPAlertView {
@objc private func handleHighlightButton() {
self.clickHighlightButton?()
self.dismiss()
}
@objc private func handleNormalButton() {
self.clickNormalButton?()
self.dismiss()
}
}
extension VPAlertView {
private func vp_setupUI() {
contentView.addSubview(bgView)
contentView.addSubview(iconImageView)
bgView.addSubview(titleLabel)
bgView.addSubview(titleIconImageView)
bgView.addSubview(textLabel)
bgView.addSubview(buttonStackView)
contentView.addSubview(closeButton)
bgView.snp.makeConstraints { make in
make.left.right.top.equalToSuperview()
make.height.equalTo(290)
make.width.equalTo(UIScreen.width - 70)
make.bottom.equalToSuperview().offset(-50)
}
iconImageView.snp.makeConstraints { make in
make.top.equalToSuperview().offset(-43)
make.right.equalToSuperview()
}
titleLabel.snp.makeConstraints { make in
make.left.equalToSuperview().offset(33)
make.top.equalToSuperview().offset(36)
make.right.lessThanOrEqualToSuperview().offset(-100)
}
titleIconImageView.snp.makeConstraints { make in
make.left.equalTo(titleLabel).offset(-13)
make.top.equalTo(titleLabel).offset(-8)
}
textLabel.snp.makeConstraints { make in
make.left.equalToSuperview().offset(33)
make.right.lessThanOrEqualToSuperview().offset(-33)
make.centerY.equalTo(bgView.snp.top).offset(150)
}
buttonStackView.snp.makeConstraints { make in
make.left.equalToSuperview().offset(10)
make.centerX.equalToSuperview()
make.bottom.equalToSuperview().offset(-30)
make.height.equalTo(48)
}
closeButton.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.bottom.equalToSuperview()
}
var buttons: [UIButton] = []
if let title = normalButton.title(for: .normal), title.count > 0 {
buttons.append(normalButton)
}
if let title = highlightButton.title(for: .normal), title.count > 0 {
buttons.append(highlightButton)
}
buttons.forEach {
buttonStackView.addArrangedSubview($0)
}
}
}

View File

@ -0,0 +1,44 @@
//
// VPAlertWindowManager.swift
// Veloria
//
// Created by on 2025/6/4.
//
import UIKit
class VPAlertWindowManager {
static let manager = VPAlertWindowManager()
private var window: UIWindow?
private var count = 0
func createWindow() -> UIWindow {
count += 1
guard let window = window else {
let window = UIWindow(windowScene: VPAppTool.windowScene!)
window.backgroundColor = .clear
window.windowLevel = .alert
window.isHidden = false
self.window = window
return window
}
return window
}
func dismissWindow() {
// count -= 1
guard let window = self.window else { return }
if window.subviews.count <= 0 {
window.isHidden = true
self.window = nil
}
// if count == 0 {
// window?.isHidden = true
// window = nil
// }
}
}

View File

@ -0,0 +1,67 @@
//
// VPBaseAlertView.swift
// Veloria
//
// Created by on 2025/6/4.
//
import UIKit
class VPBaseAlertView: UIView {
private(set) var contentView: UIView = {
let view = UIView()
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .color000000(alpha: 0.5)
addSubview(contentView)
contentView.snp.makeConstraints { make in
make.center.equalToSuperview()
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@discardableResult
@objc func show(in view: UIView? = nil) -> Self {
var inView: UIView
if let view = view {
inView = view
} else {
inView = VPAlertWindowManager.manager.createWindow()
}
inView.addSubview(self)
self.frame = inView.bounds
creatShowAnimation()
return self
}
@objc func dismiss() {
removeFromSuperview()
VPAlertWindowManager.manager.dismissWindow()
}
}
extension VPBaseAlertView {
private func creatShowAnimation() {
contentView.layer.position = center
contentView.transform = CGAffineTransform(scaleX: 0.9, y: 0.9)
UIView.animate(withDuration: 0.2, animations: {
self.contentView.transform = CGAffineTransform(scaleX: 1.2, y: 1.2)
}) { finished in
UIView.animate(withDuration: 0.1, animations: {
self.contentView.transform = CGAffineTransform.identity
})
}
}
}

View File

@ -0,0 +1,112 @@
//
// VPLoginManager+Apple.swift
// Veloria
//
// Created by on 2025/6/3.
//
import UIKit
import AuthenticationServices
extension VPLoginManager {
private struct AssociatedKeys {
static var signAppleHandle: Int?
}
private var signAppleHandle: ((_ model: VPThirdSignModel?) -> Void)? {
set {
objc_setAssociatedObject(self, &AssociatedKeys.signAppleHandle, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
}
get {
return objc_getAssociatedObject(self, &AssociatedKeys.signAppleHandle) as? ((_ model: VPThirdSignModel?) -> Void)
}
}
///
func appleSignLogin(completer: ((_ model: VPThirdSignModel?) -> Void)?) {
self.signAppleHandle = completer
let appleIDProvider = ASAuthorizationAppleIDProvider()
let request = appleIDProvider.createRequest()
request.requestedScopes = [.fullName, .email]
let authorizationController = ASAuthorizationController(authorizationRequests: [request])
authorizationController.delegate = self
authorizationController.presentationContextProvider = self
authorizationController.performRequests()
}
}
//MARK:-------------- ASAuthorizationControllerDelegate --------------
extension VPLoginManager: ASAuthorizationControllerDelegate {
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
let userIdentifier = appleIDCredential.user
let fullName = appleIDCredential.fullName
let email = appleIDCredential.email
let identityToken = appleIDCredential.identityToken.flatMap { String(data: $0, encoding: .utf8) }
let identityTokenParams = self.jwtDecode(jwtStr: identityToken ?? "")
let model = VPThirdSignModel()
model.platform = .apple
model.third_id = userIdentifier
model.giving_name = fullName?.givenName
model.family_name = fullName?.familyName
model.avator = identityTokenParams?["picture"] as? String
model.email = identityTokenParams?["email"] as? String
signAppleHandle?(model)
}
}
func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
signAppleHandle?(nil)
}
}
extension VPLoginManager: ASAuthorizationControllerPresentationContextProviding {
func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
return VPAppTool.keyWindow!
}
}
extension VPLoginManager {
private func jwtDecode(jwtStr: String) -> [String: Any]? {
let segments = jwtStr.components(separatedBy: ".")
guard segments.count > 1 else { return nil }
var base64String = segments[1]
// Base64
let requiredLength = 4 * Int(ceil(Double(base64String.count) / 4.0))
let paddingLength = requiredLength - base64String.count
if paddingLength > 0 {
base64String += String(repeating: "=", count: paddingLength)
}
// URL
base64String = base64String.replacingOccurrences(of: "-", with: "+")
base64String = base64String.replacingOccurrences(of: "_", with: "/")
// Base64
guard let data = Data(base64Encoded: base64String),
let jsonObject = try? JSONSerialization.jsonObject(with: data, options: []),
let payload = jsonObject as? [String: Any] else {
return nil
}
return payload
}
}

View File

@ -6,9 +6,17 @@
//
import UIKit
import SmartCodable
class VPLoginManager: NSObject {
enum LoginType: String, SmartCaseDefaultable {
case apple = "Apple"
case faceBook = "Facebook"
case google = "Google"
case tiktok = "Tiktok"
}
static let manager = VPLoginManager()
@ -30,6 +38,52 @@ class VPLoginManager: NSObject {
UserDefaults.vp_setObject(token, forKey: kVPLoginTokenDefaultsKey)
}
func login(type: LoginType, presentingViewController: UIViewController?, completer: ((_ isFinish: Bool) -> Void)?) {
switch type {
case .apple:
appleSignLogin { [weak self] model in
self?.requestThirdLogin(thirdSignModel: model, completer: completer)
}
default: break
}
}
///退
func logout(completer: ((_ isFinish: Bool) -> Void)?) {
VPUserAPI.requestLogout { [weak self] token in
guard let self = self else { return }
if let token = token {
self.setLoginToken(token: token)
self.userInfo?.is_tourist = true
self.updateUserInfo(completer: nil)
completer?(true)
NotificationCenter.default.post(name: VPLoginManager.userInfoUpdateNotification, object: nil)
NotificationCenter.default.post(name: VPLoginManager.loginStateDidChangeNotification, object: nil)
} else {
completer?(false)
}
}
}
///
func deleteAccount(completer: ((_ isFinish: Bool) -> Void)?) {
VPUserAPI.requestDelete { [weak self] isFinish in
guard let self = self else { return }
if isFinish {
self.setLoginToken(token: nil)
self.userInfo?.is_tourist = true
self.updateUserInfo(completer: nil)
completer?(true)
NotificationCenter.default.post(name: VPLoginManager.userInfoUpdateNotification, object: nil)
NotificationCenter.default.post(name: VPLoginManager.loginStateDidChangeNotification, object: nil)
} else {
completer?(false)
}
}
}
///
func updateUserInfo(completer: (() -> Void)?) {
@ -39,9 +93,47 @@ class VPLoginManager: NSObject {
if let userInfo = userInfo {
self.userInfo = userInfo
UserDefaults.vp_setObject(userInfo, forKey: kVPLoginUserInfoDefaultsKey)
NotificationCenter.default.post(name: VPLoginManager.userInfoUpdateNotification, object: nil)
}
completer?()
}
}
}
extension VPLoginManager {
///
private func requestThirdLogin(thirdSignModel: VPThirdSignModel?, completer: ((_ isFinish: Bool) -> Void)?) {
guard let thirdSignModel = thirdSignModel else {
completer?(false)
return
}
VPUserAPI.requestThirdLogin(model: thirdSignModel) { [weak self] token in
guard let self = self else { return }
guard let token = token else {
completer?(false)
return
}
self.setLoginToken(token: token)
self.userInfo?.is_tourist = false
self.updateUserInfo(completer: nil)
completer?(true)
NotificationCenter.default.post(name: VPLoginManager.userInfoUpdateNotification, object: nil)
NotificationCenter.default.post(name: VPLoginManager.loginStateDidChangeNotification, object: nil)
}
}
}
extension VPLoginManager {
///
@objc static let loginStateDidChangeNotification = NSNotification.Name(rawValue: "VPLoginManager.loginStateDidChangeNotification")
///
@objc static let userInfoUpdateNotification = NSNotification.Name(rawValue: "VPLoginManager.userInfoUpdateNotification")
}

View File

@ -0,0 +1,24 @@
//
// VPThirdSignModel.swift
// Veloria
//
// Created by on 2025/6/3.
//
import UIKit
import SmartCodable
class VPThirdSignModel: VPModel, SmartCodable {
var third_id: String?
var email: String?
//
var family_name: String?
//
var giving_name: String?
var avator: String?
var platform: VPLoginManager.LoginType?
}

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "提示1 1@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "提示1 1@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "通知图标-切图图层@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "通知图标-切图图层@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Frame 6@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Frame 6@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 664 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 932 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 508 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 741 B

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Apple@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Apple@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -5,12 +5,12 @@
"scale" : "1x"
},
{
"filename" : "未选中@2x.png",
"filename" : "Ellipse 45@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "未选中@3x.png",
"filename" : "Ellipse 45@3x.png",
"idiom" : "universal",
"scale" : "3x"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 580 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 897 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 958 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Close.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Close@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Frame 74@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Frame 74@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Frame@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Frame@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 623 B

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Vector@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Vector@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "bg装饰@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "bg装饰@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 305 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 666 KiB

View File

@ -6,6 +6,8 @@
*/
"kAppName" = "Veloria";
"Home" = "Home";
"Me" = "Me";
"All" = "All";
@ -64,6 +66,17 @@
"Recharge" = "Recharge";
"Unlocking costs %@ coins" = "Unlocking costs %@ coins";
"Balance: %@ Coins | %@ Bonus" = "Balance: %@ Coins | %@ Bonus";
"Check in" = "Check in";
"Welcome to %@" = "Welcome to %@";
"Login with Apple" = "Login with Apple";
"Log In" = "Log In";
"Sign Out" = "Sign Out";
"Delet Account" = "Delet Account";
"Account Deletion" = "Account Deletion";
"Delete Account" = "Delete Account";
"Delete Forever" = "Delete Forever";
"Cancel" = "Cancel";
"Log Out" = "Log Out";
"kHomeTitleText" = "10,000+ addictive shorts await!";
@ -77,6 +90,7 @@
"kVipPrivilegeText4" = "Unlimited access to all series for %@ (No Ads)";
"kVipPrivilegeText5" = "The donate coins will expire in %@";
"kVipPrivilegeText6" = "Auto renew, cancel anytime";
"kLoginAgreementText" = "By logging in you agree to: %@ & %@";
//无网提示
"kNetworkToast01" = "The service is abnormal. Check the network.";
//解锁上一集提示
@ -85,6 +99,7 @@
"kLockFailText" = "Purchase failed, please try again later!";
"kStoreTips" = "1. Coins are virtual items and cannot be refunded. Use it for this product.
2. Gold coins will never expire, the reward coins will expire 24 hours a day.
3. Coins will be used first when unlocking episodes. If the amount is insufficient, reward coins will automatically be used.
@ -93,3 +108,21 @@
//请选择需要删除的短剧
"kToastText1" = "Please select the short plays that need to be deleted";
"kDeleteAccountAlertTitle" = "Confirm Account Deletion";
"kDeleteAccountAlertText" = "This action cannot be undone.";
"kLogoutAlertTitle" = "Ready to Leave?";
"kLogoutAlertText" = "when you sign out, your watch history will not be synced to your account.";
"DeleteAccount_tips_1" = "Your account will be permanently deleted";
"DeleteAccount_tips_2" = "You will not be able to log in with this user ID";
"DeleteAccount_tips_3" = "Please log out of the account on other devices in time, otherwise the App on other devices will be unavailable.";
"DeleteAccount_tips_4" = "I accept the deletion risk and agree to delete my account";
"DeleteAccount_tips_5" = "All the following information will be deleted";
"DeleteAccount_tips_title_1" = "Account Data";
"DeleteAccount_tips_text_1" = "All your personal data will be deleted including username、Email address.";
"DeleteAccount_tips_title_2" = "Balance&VIP";
"DeleteAccount_tips_text_2" = "All your coins have been consumed and you can delete your account.";
"DeleteAccount_tips_title_3" = "History";
"DeleteAccount_tips_text_3" = "Consumption History, Recharge History, Chapter Unlock History, My Favorite.";
"DeleteAccount_tips_title_4" = "Third Party Account Information";

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.applesignin</key>
<array>
<string>Default</string>
</array>
</dict>
</plist>