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

View File

@ -193,4 +193,45 @@ extension UIColor {
static func color00211A(alpha: CGFloat = 1) -> UIColor { static func color00211A(alpha: CGFloat = 1) -> UIColor {
return UIColor(rgb: 0x00211A, alpha: alpha) 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 UIKit
import SmartCodable
class VPUserAPI: NSObject { class VPUserAPI: NSObject {
@ -19,4 +20,39 @@ class VPUserAPI: NSObject {
completer?(response.data) 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() let textLayer = CATextLayer()
textLayer.string = string textLayer.string = string
textLayer.frame = bounds 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.contentsScale = UIScreen.main.scale
textLayer.isWrapped = true
gradientLayer.mask = textLayer gradientLayer.mask = textLayer
CATransaction.commit() 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 { class VPMeViewController: VPViewController {
private lazy var dataArr: [[VPMeItem]] = { private lazy var dataArr: [[VPMeItem]] = {
let arr = [ return self.createDataArr()
[
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
}() }()
@ -53,8 +32,20 @@ class VPMeViewController: VPViewController {
return tableView 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() { override func viewDidLoad() {
super.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() 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 { extension VPMeViewController {
private func vp_setupUI() { private func vp_setupUI() {
tableView.tableFooterView = self.footerView
view.addSubview(tableView) view.addSubview(tableView)
tableView.snp.makeConstraints { make in tableView.snp.makeConstraints { make in
@ -150,6 +158,10 @@ extension VPMeViewController: UITableViewDelegate, UITableViewDataSource {
let vc = VPAboutUsViewController() let vc = VPAboutUsViewController()
self.navigationController?.pushViewController(vc, animated: true) self.navigationController?.pushViewController(vc, animated: true)
case .deleteAccount:
let vc = VPDeleteAccountViewController()
self.navigationController?.pushViewController(vc, animated: true)
default: default:
break break
} }
@ -163,10 +175,42 @@ extension VPMeViewController {
/// ///
private func requestUserInfo(completer: (() -> Void)? = nil) { private func requestUserInfo(completer: (() -> Void)? = nil) {
VPLoginManager.manager.updateUserInfo { [weak self] in VPLoginManager.manager.updateUserInfo {
self?.tableView.reloadData()
completer?() 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 userAgreement
case aboutUs case aboutUs
case feedback case feedback
case deleteAccount
case informationProtection case informationProtection
case civizatioConvention case civizatioConvention
case informationSharing 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 { extension VPMeCoinCell {
private func vp_setupUI() { private func vp_setupUI() {
addSubview(lineView) contentView.addSubview(lineView)
addSubview(coinView1) contentView.addSubview(coinView1)
addSubview(coinView2) contentView.addSubview(coinView2)
lineView.snp.makeConstraints { make in lineView.snp.makeConstraints { make in
make.centerX.equalToSuperview() 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 ?? "")" idLabel.text = "ID \(userInfo?.customer_id ?? "")"
loginButton.isHidden = !(userInfo?.is_tourist ?? true)
} }
} }
@ -47,6 +50,28 @@ class VPMeUserInfoCell: VPTableViewCell {
return label 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?) { override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier) super.init(style: style, reuseIdentifier: reuseIdentifier)
@ -57,6 +82,11 @@ class VPMeUserInfoCell: VPTableViewCell {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
@objc private func handleLoginButton() {
let view = VPLoginContentView()
view.present(in: nil)
}
} }
extension VPMeUserInfoCell { extension VPMeUserInfoCell {
@ -65,6 +95,7 @@ extension VPMeUserInfoCell {
contentView.addSubview(avatarImageView) contentView.addSubview(avatarImageView)
contentView.addSubview(nicknameLabel) contentView.addSubview(nicknameLabel)
contentView.addSubview(idLabel) contentView.addSubview(idLabel)
contentView.addSubview(loginButton)
avatarImageView.snp.makeConstraints { make in avatarImageView.snp.makeConstraints { make in
make.left.equalToSuperview() make.left.equalToSuperview()
@ -84,6 +115,12 @@ extension VPMeUserInfoCell {
make.bottom.equalTo(avatarImageView).offset(-3) 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 UIKit
import SmartCodable
class VPLoginManager: NSObject { class VPLoginManager: NSObject {
enum LoginType: String, SmartCaseDefaultable {
case apple = "Apple"
case faceBook = "Facebook"
case google = "Google"
case tiktok = "Tiktok"
}
static let manager = VPLoginManager() static let manager = VPLoginManager()
@ -30,6 +38,52 @@ class VPLoginManager: NSObject {
UserDefaults.vp_setObject(token, forKey: kVPLoginTokenDefaultsKey) 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)?) { func updateUserInfo(completer: (() -> Void)?) {
@ -39,9 +93,47 @@ class VPLoginManager: NSObject {
if let userInfo = userInfo { if let userInfo = userInfo {
self.userInfo = userInfo self.userInfo = userInfo
UserDefaults.vp_setObject(userInfo, forKey: kVPLoginUserInfoDefaultsKey) UserDefaults.vp_setObject(userInfo, forKey: kVPLoginUserInfoDefaultsKey)
NotificationCenter.default.post(name: VPLoginManager.userInfoUpdateNotification, object: nil)
} }
completer?() 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" "scale" : "1x"
}, },
{ {
"filename" : "未选中@2x.png", "filename" : "Ellipse 45@2x.png",
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"filename" : "未选中@3x.png", "filename" : "Ellipse 45@3x.png",
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x" "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"; "Home" = "Home";
"Me" = "Me"; "Me" = "Me";
"All" = "All"; "All" = "All";
@ -64,6 +66,17 @@
"Recharge" = "Recharge"; "Recharge" = "Recharge";
"Unlocking costs %@ coins" = "Unlocking costs %@ coins"; "Unlocking costs %@ coins" = "Unlocking costs %@ coins";
"Balance: %@ Coins | %@ Bonus" = "Balance: %@ Coins | %@ Bonus"; "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!"; "kHomeTitleText" = "10,000+ addictive shorts await!";
@ -77,6 +90,7 @@
"kVipPrivilegeText4" = "Unlimited access to all series for %@ (No Ads)"; "kVipPrivilegeText4" = "Unlimited access to all series for %@ (No Ads)";
"kVipPrivilegeText5" = "The donate coins will expire in %@"; "kVipPrivilegeText5" = "The donate coins will expire in %@";
"kVipPrivilegeText6" = "Auto renew, cancel anytime"; "kVipPrivilegeText6" = "Auto renew, cancel anytime";
"kLoginAgreementText" = "By logging in you agree to: %@ & %@";
//无网提示 //无网提示
"kNetworkToast01" = "The service is abnormal. Check the network."; "kNetworkToast01" = "The service is abnormal. Check the network.";
//解锁上一集提示 //解锁上一集提示
@ -85,6 +99,7 @@
"kLockFailText" = "Purchase failed, please try again later!"; "kLockFailText" = "Purchase failed, please try again later!";
"kStoreTips" = "1. Coins are virtual items and cannot be refunded. Use it for this product. "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. 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. 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"; "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>