create
26
ShenQi/AppDelegate.h
Normal file
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// AppDelegate.h
|
||||
// ShenQi
|
||||
//
|
||||
// Created by Yao on 2023/4/4.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "ConfigData.h"
|
||||
|
||||
@interface AppDelegate : UIResponder <UIApplicationDelegate>
|
||||
|
||||
@property (nonatomic, strong) UIWindow *window;
|
||||
|
||||
@property (nonatomic, strong) ConfigData *data;
|
||||
|
||||
@property (nonatomic, assign) BOOL isRefresh;
|
||||
@property (nonatomic, assign) BOOL forceUpdate;
|
||||
@property (nonatomic, strong) NSString *downloadUrl;
|
||||
@property (nonatomic, strong) NSString *inviteCode;
|
||||
|
||||
-(void)applicationDidBecomeActive:(UIApplication *)application;
|
||||
|
||||
@end
|
||||
|
||||
478
ShenQi/AppDelegate.m
Normal file
@@ -0,0 +1,478 @@
|
||||
//
|
||||
// AppDelegate.m
|
||||
// ShenQi
|
||||
//
|
||||
// Created by Yao on 2023/4/4.
|
||||
//
|
||||
|
||||
#import "AppDelegate.h"
|
||||
#import <UserNotifications/UserNotifications.h>
|
||||
|
||||
#import <FirebaseCore.h>
|
||||
#import <FirebaseMessaging.h>
|
||||
|
||||
#import <Contacts/Contacts.h>
|
||||
#import <AdSupport/AdSupport.h>
|
||||
#import <AppTrackingTransparency/AppTrackingTransparency.h>
|
||||
#import <SVProgressHUD.h>
|
||||
|
||||
#import "MacroDefine.h"
|
||||
//#import "ViewController.h"
|
||||
#import "MainOldViewController.h"
|
||||
|
||||
#import "LaunchViewController.h"
|
||||
|
||||
@interface AppDelegate () <FIRMessagingDelegate,UNUserNotificationCenterDelegate>
|
||||
|
||||
@end
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||
{
|
||||
self.window.overrideUserInterfaceStyle = UIUserInterfaceStyleDark;
|
||||
|
||||
[UIApplication sharedApplication].applicationIconBadgeNumber = 0;
|
||||
|
||||
[FIRApp configure];
|
||||
|
||||
[FIRMessaging messaging].delegate = self;
|
||||
|
||||
[SVProgressHUD setMaximumDismissTimeInterval:1.5];
|
||||
[SVProgressHUD setMinimumDismissTimeInterval:1.5];
|
||||
[SVProgressHUD setHapticsEnabled:NO];
|
||||
[SVProgressHUD setDefaultMaskType:(SVProgressHUDMaskTypeBlack)];
|
||||
|
||||
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
|
||||
center.delegate = self;
|
||||
[center requestAuthorizationWithOptions:(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error) {
|
||||
if (!error && granted) {
|
||||
//用户点击允许
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[[UIApplication sharedApplication] registerForRemoteNotifications];
|
||||
});
|
||||
}else{
|
||||
//用户点击不允许
|
||||
}
|
||||
}];
|
||||
|
||||
// 每次活跃
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:AppUseURL]];
|
||||
request.HTTPMethod = @"PUT";
|
||||
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
|
||||
NSDictionary *parmas = @{@"userId":[NSNumber numberWithInteger:[PPN88UserID integerValue]]};
|
||||
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:parmas options:NSJSONWritingPrettyPrinted error:nil];
|
||||
request.HTTPBody = jsonData;
|
||||
|
||||
NSURLSession *session = [NSURLSession sharedSession];
|
||||
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
}];
|
||||
[dataTask resume];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(void)applicationDidBecomeActive:(UIApplication *)application
|
||||
{
|
||||
// 强制获取通讯录权限
|
||||
if (self.data.contactApplyMode == 1) {
|
||||
CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
|
||||
if (status == CNAuthorizationStatusNotDetermined) {
|
||||
CNContactStore *store = [[CNContactStore alloc] init];
|
||||
[store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError* _Nullable error) {
|
||||
if (granted == NO) {
|
||||
[self setupAlertContact];
|
||||
}
|
||||
}];
|
||||
}else if (status == CNAuthorizationStatusDenied) {
|
||||
[self setupAlertContact];
|
||||
}
|
||||
}
|
||||
|
||||
// 强制获取推送权限
|
||||
if (self.data.noticeApplyMode == 1) {
|
||||
[[UNUserNotificationCenter currentNotificationCenter] getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
|
||||
// 没权限
|
||||
if (settings.authorizationStatus == UNAuthorizationStatusNotDetermined) {
|
||||
[self setupNotificationStatus];
|
||||
}else if (settings.authorizationStatus != UNAuthorizationStatusAuthorized) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
UIAlertController *alertview = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Tips", nil) message:NSLocalizedString(@"Need to enable push permission", nil) preferredStyle:(UIAlertControllerStyleAlert)];
|
||||
UIAlertAction *action = [UIAlertAction actionWithTitle:NSLocalizedString(@"SETTING", nil) style:(UIAlertActionStyleCancel) handler:^(UIAlertAction * _Nonnull action) {
|
||||
self.isRefresh = YES;
|
||||
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:^(BOOL success) {}];
|
||||
}];
|
||||
[alertview addAction:action];
|
||||
[self.window.rootViewController presentViewController:alertview animated:YES completion:^{}];
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
if (self.forceUpdate == YES) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
UIAlertController *alertview = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Tips", nil) message:NSLocalizedString(@"New version found", nil) preferredStyle:(UIAlertControllerStyleAlert)];
|
||||
UIAlertAction *action = [UIAlertAction actionWithTitle:NSLocalizedString(@"Update", nil) style:(UIAlertActionStyleDefault) handler:^(UIAlertAction * _Nonnull action) {
|
||||
self.isRefresh = NO;
|
||||
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:self.downloadUrl] options:@{} completionHandler:^(BOOL success) {}];
|
||||
}];
|
||||
[alertview addAction:action];
|
||||
[self.window.rootViewController presentViewController:alertview animated:YES completion:^{}];
|
||||
});
|
||||
}
|
||||
|
||||
// 强制填写邀请码
|
||||
// NSUserDefaults *userfault = [NSUserDefaults standardUserDefaults];
|
||||
// BOOL install = [userfault objectForKey:@"INSTALL"];
|
||||
// if (install == NO) {
|
||||
// [self setupSendInvite];
|
||||
// }else{
|
||||
// if (self.isRefresh == YES) {
|
||||
// [[NSNotificationCenter defaultCenter] postNotificationName:@"NOTI_INTO" object:nil];
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
#pragma mark - 推送权限
|
||||
-(void)setupNotificationStatus
|
||||
{
|
||||
[[UNUserNotificationCenter currentNotificationCenter] getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
|
||||
// 没权限
|
||||
if (settings.authorizationStatus == UNAuthorizationStatusNotDetermined) {
|
||||
[self setupNotificationStatus];
|
||||
}else if (settings.authorizationStatus != UNAuthorizationStatusAuthorized) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
UIAlertController *alertview = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Tips", nil) message:NSLocalizedString(@"Need to enable push permission", nil) preferredStyle:(UIAlertControllerStyleAlert)];
|
||||
UIAlertAction *action = [UIAlertAction actionWithTitle:NSLocalizedString(@"SETTING", nil) style:(UIAlertActionStyleCancel) handler:^(UIAlertAction * _Nonnull action) {
|
||||
self.isRefresh = YES;
|
||||
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:^(BOOL success) {}];
|
||||
}];
|
||||
[alertview addAction:action];
|
||||
[self.window.rootViewController presentViewController:alertview animated:YES completion:^{}];
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - 通讯录权限
|
||||
-(void)setupAlertContact
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Tips", nil) message:NSLocalizedString(@"Contacts permission must be turned on", nil) preferredStyle:(UIAlertControllerStyleAlert)];
|
||||
UIAlertAction *action = [UIAlertAction actionWithTitle:NSLocalizedString(@"SETTING", nil) style:(UIAlertActionStyleCancel) handler:^(UIAlertAction * _Nonnull action) {
|
||||
self.isRefresh = YES;
|
||||
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:^(BOOL success) {}];
|
||||
}];
|
||||
[alertController addAction:action];
|
||||
[self.window.rootViewController presentViewController:alertController animated:YES completion:^{}];
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
-(void)refreshPermissionAll
|
||||
{
|
||||
[SVProgressHUD dismiss];
|
||||
|
||||
// 判断是否开启推送权限
|
||||
[[UNUserNotificationCenter currentNotificationCenter] getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
|
||||
// 没权限
|
||||
if (settings.authorizationStatus == UNAuthorizationStatusNotDetermined) {
|
||||
[self setupNotificationStatus];
|
||||
}else if (settings.authorizationStatus != UNAuthorizationStatusAuthorized) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
UIAlertController *alertview = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Tips", nil) message:NSLocalizedString(@"Need to enable push permission", nil) preferredStyle:(UIAlertControllerStyleAlert)];
|
||||
UIAlertAction *action = [UIAlertAction actionWithTitle:NSLocalizedString(@"SETTING", nil) style:(UIAlertActionStyleCancel) handler:^(UIAlertAction * _Nonnull action) {
|
||||
self.isRefresh = YES;
|
||||
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:^(BOOL success) {}];
|
||||
}];
|
||||
[alertview addAction:action];
|
||||
[self.window.rootViewController presentViewController:alertview animated:YES completion:^{}];
|
||||
});
|
||||
}
|
||||
}];
|
||||
|
||||
// 判断是否开启通讯权限
|
||||
CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
|
||||
if (status == CNAuthorizationStatusNotDetermined) {
|
||||
CNContactStore *store = [[CNContactStore alloc] init];
|
||||
[store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError* _Nullable error) {
|
||||
if (granted == NO) {
|
||||
[self setupAlertContact];
|
||||
}
|
||||
}];
|
||||
}else if (status == CNAuthorizationStatusDenied) {
|
||||
[self setupAlertContact];
|
||||
}
|
||||
|
||||
// 判断是否输入邀请码
|
||||
NSUserDefaults *userfault = [NSUserDefaults standardUserDefaults];
|
||||
BOOL install = [userfault objectForKey:@"INSTALL"];
|
||||
if (install == NO) {
|
||||
[self setupSendInvite];
|
||||
}else{
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"NOTI_INTO" object:nil];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - 填写邀请码
|
||||
-(void)setupSendInvite
|
||||
{
|
||||
// 填写邀请码
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
UIAlertController *inputCodeAlertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Please enter the invitation code", nil) message:nil preferredStyle:(UIAlertControllerStyleAlert)];
|
||||
[inputCodeAlertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
|
||||
textField.placeholder = NSLocalizedString(@"Please enter the invitation code", nil);
|
||||
}];
|
||||
UIAlertAction *inputCodeAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil) style:(UIAlertActionStyleDefault) handler:^(UIAlertAction * _Nonnull action) {
|
||||
UITextField *codeTextField = inputCodeAlertController.textFields.firstObject;
|
||||
if (!ISNULLSTR(codeTextField.text)) {
|
||||
NSString *advertisingId = codeTextField.text;
|
||||
[self setupInviteSend:advertisingId];
|
||||
}else{
|
||||
[self setupSendInvite];
|
||||
}
|
||||
}];
|
||||
[inputCodeAlertController addAction:inputCodeAction];
|
||||
[self.window.rootViewController presentViewController:inputCodeAlertController animated:YES completion:^{}];
|
||||
});
|
||||
}
|
||||
|
||||
-(void)setupInviteSend:(NSString *)advertisingId
|
||||
{
|
||||
__block NSString *uuidString = @"";
|
||||
if (@available(iOS 14, *)) {
|
||||
[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
|
||||
uuidString = [[ASIdentifierManager sharedManager] advertisingIdentifier].UUIDString;
|
||||
[self setupInviteSendWithUUIDString:uuidString advertisingId:advertisingId];
|
||||
}];
|
||||
} else {
|
||||
uuidString = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
|
||||
[self setupInviteSendWithUUIDString:uuidString advertisingId:advertisingId];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)setupInviteSendWithUUIDString:(NSString *)uuidString advertisingId:(NSString *)advertisingId
|
||||
{
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:InviteSendURL]];
|
||||
request.HTTPMethod = @"PUT";
|
||||
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
|
||||
NSDictionary *parmas = @{@"code":advertisingId,@"deviceCode":uuidString,@"userId":[NSNumber numberWithInteger:[VV88AUUserID integerValue]]};
|
||||
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:parmas options:NSJSONWritingPrettyPrinted error:nil];
|
||||
request.HTTPBody = jsonData;
|
||||
|
||||
[SVProgressHUD show];
|
||||
NSURLSession *session = [NSURLSession sharedSession];
|
||||
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (error == nil) {
|
||||
[SVProgressHUD dismiss];
|
||||
NSError *error;
|
||||
NSMutableDictionary *responseObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
|
||||
if (error == nil) {
|
||||
NSInteger code = [[responseObject objectForKey:@"code"] integerValue];
|
||||
if (ISNULL(error)) {
|
||||
if (code == 40001) {
|
||||
NSString *errmsg = [responseObject objectForKey:@"error"];
|
||||
[SVProgressHUD showInfoWithStatus:errmsg];
|
||||
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
NSDictionary *datadic = [responseObject objectForKey:@"data"];
|
||||
NSString *inviteCode = [datadic objectForKey:@"inviteCode"];
|
||||
|
||||
NSUserDefaults *userfault = [NSUserDefaults standardUserDefaults];
|
||||
[userfault setObject:[NSNumber numberWithBool:YES] forKey:@"INSTALL"];
|
||||
[userfault setObject:inviteCode forKey:@"INVITE_CODE"];
|
||||
[userfault synchronize];
|
||||
|
||||
// 已填写邀请码
|
||||
[self refreshPermissionAll];
|
||||
});
|
||||
}else if (code == 1) {
|
||||
NSUserDefaults *userfault = [NSUserDefaults standardUserDefaults];
|
||||
[userfault setObject:[NSNumber numberWithBool:YES] forKey:@"INSTALL"];
|
||||
[userfault setObject:advertisingId forKey:@"INVITE_CODE"];
|
||||
[userfault synchronize];
|
||||
|
||||
// 已填写邀请码
|
||||
[self refreshPermissionAll];
|
||||
}else{
|
||||
NSString *errmsg = [responseObject objectForKey:@"error"];
|
||||
[SVProgressHUD showInfoWithStatus:errmsg];
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[self setupSendInvite];
|
||||
});
|
||||
}
|
||||
}else{
|
||||
NSString *errmsg = [responseObject objectForKey:@"message"];
|
||||
[SVProgressHUD showInfoWithStatus:errmsg];
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[self setupSendInvite];
|
||||
});
|
||||
}
|
||||
}
|
||||
else{
|
||||
[SVProgressHUD showInfoWithStatus:error.localizedDescription];
|
||||
[self setupSendInvite];
|
||||
}
|
||||
}
|
||||
else{
|
||||
[SVProgressHUD showInfoWithStatus:error.localizedDescription];
|
||||
[self setupSendInvite];
|
||||
}
|
||||
});
|
||||
}];
|
||||
[dataTask resume];
|
||||
}
|
||||
*/
|
||||
|
||||
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
|
||||
{
|
||||
if (deviceToken != nil) {
|
||||
|
||||
[[FIRMessaging messaging] setAPNSToken:deviceToken];
|
||||
|
||||
[[FIRMessaging messaging] subscribeToTopic:@"demo"
|
||||
completion:^(NSError * _Nullable error) {
|
||||
NSLog(@"Subscribed to demo topic");
|
||||
}];
|
||||
|
||||
NSLog(@"APNSToken = %@",[FIRMessaging messaging].APNSToken);
|
||||
}
|
||||
}
|
||||
|
||||
-(UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
|
||||
{
|
||||
return UIInterfaceOrientationMaskAll;
|
||||
}
|
||||
|
||||
- (void)messaging:(FIRMessaging *)messaging didReceiveRegistrationToken:(NSString *)fcmToken
|
||||
{
|
||||
NSLog(@"FCM registration token: %@", fcmToken);
|
||||
|
||||
[[FIRMessaging messaging] tokenWithCompletion:^(NSString *token, NSError *error) {
|
||||
if (error != nil) {
|
||||
NSLog(@"Error getting FCM registration token: %@", error);
|
||||
} else {
|
||||
NSLog(@"FCM registration token: %@", token);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
|
||||
{
|
||||
completionHandler(UNNotificationPresentationOptionSound|UNNotificationPresentationOptionAlert);
|
||||
}
|
||||
|
||||
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
|
||||
{
|
||||
[self processWithNoti:userInfo];
|
||||
}
|
||||
|
||||
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler
|
||||
{
|
||||
[self processWithNoti:response.notification.request.content.userInfo];
|
||||
}
|
||||
|
||||
/*
|
||||
-(void)receiveNOTIProcessWithNoti:(NSDictionary *)userInfo
|
||||
{
|
||||
[[FIRMessaging messaging] appDidReceiveMessage:userInfo];
|
||||
|
||||
if (userInfo) {
|
||||
NSDictionary *apnsDic = [userInfo objectForKey:@"aps"];
|
||||
NSDictionary *alertDic = [apnsDic objectForKey:@"alert"];
|
||||
NSString *title = [alertDic objectForKey:@"body"];
|
||||
NSString *content = [alertDic objectForKey:@"title"];
|
||||
[self scheduleLocalNotification:userInfo title:title content:content];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)scheduleLocalNotification:(NSDictionary *)userInfo title:(NSString *)title content:(NSString *)content
|
||||
{
|
||||
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
|
||||
center.delegate = self;
|
||||
|
||||
UNMutableNotificationContent *notificationContent = [[UNMutableNotificationContent alloc] init];
|
||||
notificationContent.title = title;
|
||||
notificationContent.subtitle = content;
|
||||
notificationContent.sound = [UNNotificationSound defaultSound];
|
||||
|
||||
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:@"LOCAL_NOTI" content:notificationContent trigger:nil];
|
||||
[center addNotificationRequest:request withCompletionHandler:^(NSError *_Nullable error) {
|
||||
if (!error) {
|
||||
[self processWithNoti:userInfo];
|
||||
}
|
||||
}];
|
||||
}
|
||||
*/
|
||||
-(void)processWithNoti:(NSDictionary *)userInfo
|
||||
{
|
||||
NSString *message = [userInfo objectForKey:@"message"];
|
||||
NSData *jsonData = [message dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSDictionary *messageNotiDic = nil;
|
||||
if (!ISNULL(jsonData)) {
|
||||
NSError *err;
|
||||
messageNotiDic = [NSJSONSerialization JSONObjectWithData:jsonData
|
||||
options:NSJSONReadingMutableContainers
|
||||
error:&err];
|
||||
if (!ISNULL(messageNotiDic)) {
|
||||
NSInteger type = [[messageNotiDic objectForKey:@"type"] integerValue];// 1 文字 2 图片 3 链接
|
||||
NSString *image = [messageNotiDic objectForKey:@"image"];
|
||||
NSString *jumpUrl = [messageNotiDic objectForKey:@"jumpUrl"];
|
||||
NSInteger pushId = [[messageNotiDic objectForKey:@"pushId"] longValue];
|
||||
|
||||
// 上传点击 pushId
|
||||
if (pushId > 0) {
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:PushStatisticsURL]];
|
||||
request.HTTPMethod = @"POST";
|
||||
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
|
||||
NSDictionary *parmas = @{@"pushId":[NSNumber numberWithLong:pushId]};
|
||||
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:parmas options:NSJSONWritingPrettyPrinted error:nil];
|
||||
request.HTTPBody = jsonData;
|
||||
|
||||
NSURLSession *session = [NSURLSession sharedSession];
|
||||
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
}];
|
||||
[dataTask resume];
|
||||
}
|
||||
if (type == 2 && !ISNULLSTR(image)) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
NSURL *url = [NSURL URLWithString:image];
|
||||
NSData *data = [NSData dataWithContentsOfURL:url];
|
||||
|
||||
UIView *bgView = [[UIView alloc] initWithFrame:self.window.bounds];
|
||||
bgView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5];
|
||||
|
||||
UIImageView *imageview = [[UIImageView alloc] initWithFrame:CGRectMake(20, 80, bgView.frame.size.width-40, bgView.frame.size.height-160)];
|
||||
imageview.image = [UIImage imageWithData:data];
|
||||
imageview.contentMode = UIViewContentModeScaleAspectFill;
|
||||
|
||||
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapImageView:)];
|
||||
[imageview addGestureRecognizer:tap];
|
||||
|
||||
[self.window addSubview:bgView];
|
||||
[bgView addSubview:imageview];
|
||||
});
|
||||
}else if (type == 3 && !ISNULLSTR(jumpUrl)) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
MainOldViewController *view = [[MainOldViewController alloc] init];
|
||||
view.gameURLString = jumpUrl;
|
||||
view.isPresent = YES;
|
||||
view.modalPresentationStyle = UIModalPresentationFullScreen;
|
||||
[self.window.rootViewController presentViewController:view animated:YES completion:^{}];
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-(void)tapImageView:(UITapGestureRecognizer *)tap
|
||||
{
|
||||
[tap.view removeFromSuperview];
|
||||
}
|
||||
|
||||
@end
|
||||
18
ShenQi/AreaCodeTableViewCell.h
Normal file
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// AreaCodeTableViewCell.h
|
||||
// ShenQi
|
||||
//
|
||||
// Created by Yao on 2024/11/9.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface AreaCodeTableViewCell : UITableViewCell
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
25
ShenQi/AreaCodeTableViewCell.m
Normal file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// AreaCodeTableViewCell.m
|
||||
// ShenQi
|
||||
//
|
||||
// Created by Yao on 2024/11/9.
|
||||
//
|
||||
|
||||
#import "AreaCodeTableViewCell.h"
|
||||
|
||||
@implementation AreaCodeTableViewCell
|
||||
|
||||
- (void)awakeFromNib {
|
||||
[super awakeFromNib];
|
||||
// Initialization code
|
||||
|
||||
[self setSelectionStyle:(UITableViewCellSelectionStyleNone)];
|
||||
}
|
||||
|
||||
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
|
||||
[super setSelected:selected animated:animated];
|
||||
|
||||
// Configure the view for the selected state
|
||||
}
|
||||
|
||||
@end
|
||||
41
ShenQi/AreaCodeTableViewCell.xib
Normal file
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="22155" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22131"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="KGk-i7-Jjw" customClass="AreaCodeTableViewCell">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="TLN-RP-qir">
|
||||
<rect key="frame" x="20" y="11.666666666666664" width="42" height="21"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="1" green="0.65490196079999996" blue="0.1333333333" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.17254901959999999" green="0.17254901959999999" blue="0.18039215689999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="TLN-RP-qir" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="20" id="C0V-Hb-LWQ"/>
|
||||
<constraint firstItem="TLN-RP-qir" firstAttribute="centerY" secondItem="H2p-sc-9uM" secondAttribute="centerY" id="ThY-bs-ntC"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<viewLayoutGuide key="safeArea" id="aW0-zy-SZf"/>
|
||||
<color key="backgroundColor" red="0.17254901959999999" green="0.17254901959999999" blue="0.18039215689999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<connections>
|
||||
<outlet property="titleLabel" destination="TLN-RP-qir" id="L2J-gI-TeQ"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="139" y="20"/>
|
||||
</tableViewCell>
|
||||
</objects>
|
||||
</document>
|
||||
11
ShenQi/Assets.xcassets/AccentColor.colorset/Contents.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
14
ShenQi/Assets.xcassets/AppIcon.appiconset/Contents.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "PPN88.png",
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
ShenQi/Assets.xcassets/AppIcon.appiconset/PPN88.png
Normal file
|
After Width: | Height: | Size: 382 KiB |
6
ShenQi/Assets.xcassets/Contents.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
21
ShenQi/Assets.xcassets/PPN88.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "PPN88.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
ShenQi/Assets.xcassets/PPN88.imageset/PPN88.png
vendored
Normal file
|
After Width: | Height: | Size: 382 KiB |
21
ShenQi/Assets.xcassets/caidan.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "caidan.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
ShenQi/Assets.xcassets/caidan.imageset/caidan.png
vendored
Normal file
|
After Width: | Height: | Size: 4.0 KiB |
21
ShenQi/Assets.xcassets/candy916.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "candy916.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
ShenQi/Assets.xcassets/candy916.imageset/candy916.png
vendored
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
21
ShenQi/Assets.xcassets/facebook.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "facebook.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
ShenQi/Assets.xcassets/facebook.imageset/facebook.png
vendored
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
21
ShenQi/Assets.xcassets/goback.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "goback.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
ShenQi/Assets.xcassets/goback.imageset/goback.png
vendored
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
21
ShenQi/Assets.xcassets/line.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "line.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
ShenQi/Assets.xcassets/line.imageset/line.png
vendored
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
21
ShenQi/Assets.xcassets/menu.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "menu@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
ShenQi/Assets.xcassets/menu.imageset/menu@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 459 KiB |
21
ShenQi/Assets.xcassets/shuaxin.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "shuaxin.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
ShenQi/Assets.xcassets/shuaxin.imageset/shuaxin.png
vendored
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
21
ShenQi/Assets.xcassets/telegram.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "telegram.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
ShenQi/Assets.xcassets/telegram.imageset/telegram.png
vendored
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
21
ShenQi/Assets.xcassets/weibiaoti.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "weibiaoti.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
ShenQi/Assets.xcassets/weibiaoti.imageset/weibiaoti.png
vendored
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
21
ShenQi/Assets.xcassets/whatsapp.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "whatsapp.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
ShenQi/Assets.xcassets/whatsapp.imageset/whatsapp.png
vendored
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
21
ShenQi/Assets.xcassets/winway.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "winway.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
ShenQi/Assets.xcassets/winway.imageset/winway.png
vendored
Normal file
|
After Width: | Height: | Size: 406 KiB |
21
ShenQi/Assets.xcassets/winwaymenu.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "winwaymenu.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
ShenQi/Assets.xcassets/winwaymenu.imageset/winwaymenu.png
vendored
Normal file
|
After Width: | Height: | Size: 43 KiB |
21
ShenQi/Assets.xcassets/xialasanjiao.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "xialasanjiao.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
ShenQi/Assets.xcassets/xialasanjiao.imageset/xialasanjiao.png
vendored
Normal file
|
After Width: | Height: | Size: 893 B |
21
ShenQi/Assets.xcassets/zhongxindakai.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "zhongxindakai.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
ShenQi/Assets.xcassets/zhongxindakai.imageset/zhongxindakai.png
vendored
Normal file
|
After Width: | Height: | Size: 7.0 KiB |
38
ShenQi/BankView.h
Normal file
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// BankView.h
|
||||
// ShenQi
|
||||
//
|
||||
// Created by Yao on 2024/11/9.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "DataModels.h"
|
||||
|
||||
typedef NS_ENUM(NSInteger, ChooseType) {
|
||||
ChooseBankCodeType, //
|
||||
ChooseBankNameType, //
|
||||
};
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef void(^SelectedCompleteBlock)(id code);
|
||||
|
||||
@interface BankView : UIView <UITableViewDelegate,UITableViewDataSource>
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UIView *mainView;
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *bottomConstraint;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
|
||||
@property (weak, nonatomic) IBOutlet UITableView *bankTableView;
|
||||
|
||||
@property (nonatomic, copy) SelectedCompleteBlock selectedCompleteBlock;
|
||||
|
||||
@property (nonatomic, assign) ChooseType chooseType;
|
||||
@property (nonatomic, strong) NSString *currentBankCode;
|
||||
@property (nonatomic, strong) NSDictionary *bankdic;
|
||||
|
||||
@property (nonatomic, strong) NSMutableArray *bankArray;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
113
ShenQi/BankView.m
Normal file
@@ -0,0 +1,113 @@
|
||||
//
|
||||
// BankView.m
|
||||
// ShenQi
|
||||
//
|
||||
// Created by Yao on 2024/11/9.
|
||||
//
|
||||
|
||||
#import "BankView.h"
|
||||
|
||||
#import "MacroDefine.h"
|
||||
#import "AreaCodeTableViewCell.h"
|
||||
|
||||
static NSString *identifier = @"AreaCodeTableViewCell";
|
||||
|
||||
@implementation BankView
|
||||
|
||||
-(void)awakeFromNib
|
||||
{
|
||||
[super awakeFromNib];
|
||||
|
||||
self.titleLabel.text = [NSString stringWithFormat:@"%@%@",NSLocalizedString(@"PLS", nil),NSLocalizedString(@"Choose", nil)];
|
||||
|
||||
self.bottomConstraint.constant = 0;
|
||||
[UIView animateWithDuration:0.25 animations:^{
|
||||
self.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5];
|
||||
[self layoutIfNeeded];
|
||||
}];
|
||||
|
||||
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, SCREEN_WIDTH, 400) byRoundingCorners:UIRectCornerTopLeft | UIRectCornerTopRight cornerRadii:CGSizeMake(12,12)];
|
||||
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
|
||||
maskLayer.frame = CGRectMake(0, 0, SCREEN_WIDTH, 400);
|
||||
maskLayer.path = maskPath.CGPath;
|
||||
self.mainView.layer.mask = maskLayer;
|
||||
|
||||
self.bankTableView.delegate = self;
|
||||
self.bankTableView.dataSource = self;
|
||||
self.bankTableView.rowHeight = 50;
|
||||
[self.bankTableView registerNib:[UINib nibWithNibName:@"AreaCodeTableViewCell" bundle:nil] forCellReuseIdentifier:identifier];
|
||||
[self.bankTableView setSeparatorStyle:(UITableViewCellSeparatorStyleSingleLine)];
|
||||
[self.bankTableView setSeparatorInset:UIEdgeInsetsMake(0, 0, 0, 0)];
|
||||
self.bankTableView.tableFooterView = [UIView new];
|
||||
}
|
||||
|
||||
- (IBAction)dismissAction:(id)sender
|
||||
{
|
||||
self.bottomConstraint.constant = -400;
|
||||
[UIView animateWithDuration:0.25 animations:^{
|
||||
[self layoutIfNeeded];
|
||||
} completion:^(BOOL finished) {
|
||||
[self removeFromSuperview];
|
||||
}];
|
||||
}
|
||||
|
||||
-(void)setBankdic:(NSDictionary *)bankdic
|
||||
{
|
||||
_bankdic = bankdic;
|
||||
|
||||
if (self.chooseType == ChooseBankCodeType) {
|
||||
self.bankArray = @[].mutableCopy;
|
||||
[self.bankArray addObjectsFromArray:self.bankdic.allKeys];
|
||||
[self.bankTableView reloadData];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)setCurrentBankCode:(NSString *)currentBankCode
|
||||
{
|
||||
_currentBankCode = currentBankCode;
|
||||
|
||||
if (self.chooseType == ChooseBankNameType && !ISNULLSTR(self.currentBankCode) && !ISNULL(self.bankdic)) {
|
||||
self.bankArray = @[].mutableCopy;
|
||||
NSArray *bankArray = [self.bankdic objectForKey:self.currentBankCode];
|
||||
for (NSDictionary *bankdic in bankArray) {
|
||||
BankModelData *bank = [[BankModelData alloc] initWithDictionary:bankdic];
|
||||
[self.bankArray addObject:bank];
|
||||
}
|
||||
[self.bankTableView reloadData];
|
||||
}
|
||||
}
|
||||
|
||||
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
return self.bankArray.count;
|
||||
}
|
||||
|
||||
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
AreaCodeTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
|
||||
if (self.chooseType == ChooseBankNameType) {
|
||||
BankModelData *data = [self.bankArray objectAtIndex:indexPath.row];
|
||||
cell.titleLabel.text = data.bankName;
|
||||
}else{
|
||||
cell.titleLabel.text = [self.bankArray objectAtIndex:indexPath.row];
|
||||
}
|
||||
return cell;
|
||||
}
|
||||
|
||||
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
if (self.chooseType == ChooseBankNameType) {
|
||||
BankModelData *data = [self.bankArray objectAtIndex:indexPath.row];
|
||||
if (self.selectedCompleteBlock) {
|
||||
self.selectedCompleteBlock(data);
|
||||
}
|
||||
}else{
|
||||
NSString *code = [self.bankArray objectAtIndex:indexPath.row];
|
||||
if (self.selectedCompleteBlock) {
|
||||
self.selectedCompleteBlock(code);
|
||||
}
|
||||
}
|
||||
[self dismissAction:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
71
ShenQi/BankView.xib
Normal file
@@ -0,0 +1,71 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="22155" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22131"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="BankView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="t8f-BG-Vzb">
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
|
||||
<state key="normal">
|
||||
<color key="titleColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="dismissAction:" destination="iN0-l3-epB" eventType="touchUpInside" id="7MX-iT-sAu"/>
|
||||
</connections>
|
||||
</button>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="RSo-3d-7oa">
|
||||
<rect key="frame" x="0.0" y="852" width="393" height="400"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="请选择国家地区" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ick-K1-kEm">
|
||||
<rect key="frame" x="136" y="20" width="121.33333333333331" height="21"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="-1" estimatedSectionHeaderHeight="-1" sectionFooterHeight="-1" estimatedSectionFooterHeight="-1" translatesAutoresizingMaskIntoConstraints="NO" id="r0P-rW-aqh">
|
||||
<rect key="frame" x="0.0" y="61" width="393" height="339"/>
|
||||
<color key="backgroundColor" red="0.17254901959999999" green="0.17254901959999999" blue="0.18039215689999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||
</tableView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.17254901959999999" green="0.17254901959999999" blue="0.18039215689999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="Ick-K1-kEm" firstAttribute="centerX" secondItem="RSo-3d-7oa" secondAttribute="centerX" id="HJR-vh-rDi"/>
|
||||
<constraint firstAttribute="bottom" secondItem="r0P-rW-aqh" secondAttribute="bottom" id="HOS-gx-zBk"/>
|
||||
<constraint firstItem="Ick-K1-kEm" firstAttribute="top" secondItem="RSo-3d-7oa" secondAttribute="top" constant="20" id="ZNl-9z-z2E"/>
|
||||
<constraint firstItem="r0P-rW-aqh" firstAttribute="top" secondItem="Ick-K1-kEm" secondAttribute="bottom" constant="20" id="cb6-0J-zjE"/>
|
||||
<constraint firstItem="r0P-rW-aqh" firstAttribute="width" secondItem="RSo-3d-7oa" secondAttribute="width" id="gxp-ZS-n2H"/>
|
||||
<constraint firstAttribute="height" constant="400" id="hM4-Tb-ODH"/>
|
||||
<constraint firstItem="r0P-rW-aqh" firstAttribute="centerX" secondItem="RSo-3d-7oa" secondAttribute="centerX" id="xcg-zW-sKs"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="RSo-3d-7oa" firstAttribute="width" secondItem="iN0-l3-epB" secondAttribute="width" id="Gji-Wf-AeP"/>
|
||||
<constraint firstItem="t8f-BG-Vzb" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" id="Pgp-eJ-elg"/>
|
||||
<constraint firstItem="t8f-BG-Vzb" firstAttribute="height" secondItem="iN0-l3-epB" secondAttribute="height" id="Rdv-af-t2d"/>
|
||||
<constraint firstItem="RSo-3d-7oa" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" id="YoS-ht-Y4q"/>
|
||||
<constraint firstItem="t8f-BG-Vzb" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="centerY" id="bvq-I6-DuQ"/>
|
||||
<constraint firstAttribute="bottom" secondItem="RSo-3d-7oa" secondAttribute="bottom" constant="-400" id="kJH-o8-SaK"/>
|
||||
<constraint firstItem="t8f-BG-Vzb" firstAttribute="width" secondItem="iN0-l3-epB" secondAttribute="width" id="tq0-lr-KrS"/>
|
||||
</constraints>
|
||||
<connections>
|
||||
<outlet property="bankTableView" destination="r0P-rW-aqh" id="7ay-2d-uRe"/>
|
||||
<outlet property="bottomConstraint" destination="kJH-o8-SaK" id="vlb-Md-tpg"/>
|
||||
<outlet property="mainView" destination="RSo-3d-7oa" id="XA7-jR-B1T"/>
|
||||
<outlet property="titleLabel" destination="Ick-K1-kEm" id="qX5-R1-9dI"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="140" y="20"/>
|
||||
</view>
|
||||
</objects>
|
||||
</document>
|
||||
44
ShenQi/Base.lproj/LaunchScreen.storyboard
Normal file
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="22155" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22131"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="EHf-IW-A2E">
|
||||
<objects>
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="PPN88" translatesAutoresizingMaskIntoConstraints="NO" id="wWz-RR-gyr">
|
||||
<rect key="frame" x="96.666666666666686" y="298.66666666666669" width="200" height="200"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="wWz-RR-gyr" secondAttribute="height" multiplier="1:1" id="N0J-q8-ZKK"/>
|
||||
<constraint firstAttribute="width" constant="200" id="gfW-ba-a5X"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||
<color key="backgroundColor" red="0.98781532049999998" green="1" blue="0.99589437250000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="wWz-RR-gyr" firstAttribute="centerY" secondItem="6Tk-OE-BBY" secondAttribute="centerY" constant="-40" id="CqV-4e-F3I"/>
|
||||
<constraint firstItem="wWz-RR-gyr" firstAttribute="centerX" secondItem="6Tk-OE-BBY" secondAttribute="centerX" id="FHK-Fd-BPL"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="53" y="375"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="PPN88" width="1024" height="1024"/>
|
||||
</resources>
|
||||
</document>
|
||||
153
ShenQi/Base.lproj/Main.storyboard
Normal file
@@ -0,0 +1,153 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="22155" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="CLX-jd-tRb">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22131"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="tne-QT-ifu">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="ViewController" useStoryboardIdentifierAsRestorationIdentifier="YES" id="BYZ-38-t0r" customClass="ViewController" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="9sI-nt-sPs">
|
||||
<rect key="frame" x="150.66666666666666" y="399" width="92" height="54.333333333333314"/>
|
||||
<state key="normal" title="Button"/>
|
||||
<buttonConfiguration key="configuration" style="tinted" image="shuaxin" imagePlacement="top" title="进入App"/>
|
||||
<connections>
|
||||
<action selector="intoGameAction:" destination="BYZ-38-t0r" eventType="touchUpInside" id="g2E-1A-Uc1"/>
|
||||
</connections>
|
||||
</button>
|
||||
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" animating="YES" style="medium" translatesAutoresizingMaskIntoConstraints="NO" id="wDT-DT-yPP">
|
||||
<rect key="frame" x="186.66666666666666" y="416" width="20" height="20"/>
|
||||
</activityIndicatorView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="s8A-Hx-U8O"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="9sI-nt-sPs" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="OwP-N9-T7E"/>
|
||||
<constraint firstItem="wDT-DT-yPP" firstAttribute="centerY" secondItem="8bC-Xf-vdC" secondAttribute="centerY" id="ccY-HQ-XLn"/>
|
||||
<constraint firstItem="wDT-DT-yPP" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="gOD-bI-qCF"/>
|
||||
<constraint firstItem="9sI-nt-sPs" firstAttribute="centerY" secondItem="8bC-Xf-vdC" secondAttribute="centerY" id="gkX-0j-pN6"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="activityIndicatorView" destination="wDT-DT-yPP" id="Tm5-SJ-0lI"/>
|
||||
<outlet property="goIntoBtn" destination="9sI-nt-sPs" id="FJ7-H6-iJC"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="133.58778625954199" y="3.5211267605633805"/>
|
||||
</scene>
|
||||
<!--Main Old View Controller-->
|
||||
<scene sceneID="Hwl-qq-Q04">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="MainOldViewController" useStoryboardIdentifierAsRestorationIdentifier="YES" id="IMS-fv-0OO" customClass="MainOldViewController" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="Ys6-Sp-lCM">
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="aS0-9b-Vdi">
|
||||
<rect key="frame" x="150.66666666666666" y="399" width="92" height="54.333333333333314"/>
|
||||
<state key="normal" title="Button"/>
|
||||
<buttonConfiguration key="configuration" style="tinted" image="shuaxin" imagePlacement="top" title="进入App"/>
|
||||
<connections>
|
||||
<action selector="intoGameAction:" destination="IMS-fv-0OO" eventType="touchUpInside" id="eFh-NV-HoP"/>
|
||||
</connections>
|
||||
</button>
|
||||
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" animating="YES" style="medium" translatesAutoresizingMaskIntoConstraints="NO" id="kot-ab-erv">
|
||||
<rect key="frame" x="186.66666666666666" y="416" width="20" height="20"/>
|
||||
</activityIndicatorView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="jWy-uW-8Li" customClass="DSWebDragView">
|
||||
<rect key="frame" x="0.0" y="271.66666666666669" width="60" height="60"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="60" id="XG1-uZ-BDG"/>
|
||||
<constraint firstAttribute="width" secondItem="jWy-uW-8Li" secondAttribute="height" multiplier="1:1" id="yzH-EX-jDa"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<collectionView hidden="YES" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="rsS-Qz-Fg1" customClass="DSWebMenuCollectionView">
|
||||
<rect key="frame" x="0.0" y="271.66666666666669" width="60" height="334.00000000000006"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="60" id="gU5-UR-beg"/>
|
||||
<constraint firstAttribute="height" constant="334" id="seP-m5-Lwg"/>
|
||||
</constraints>
|
||||
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="8Dp-df-goj">
|
||||
<size key="itemSize" width="128" height="128"/>
|
||||
<size key="headerReferenceSize" width="0.0" height="0.0"/>
|
||||
<size key="footerReferenceSize" width="0.0" height="0.0"/>
|
||||
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
|
||||
</collectionViewFlowLayout>
|
||||
</collectionView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="fdh-Xv-lcd"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="rsS-Qz-Fg1" firstAttribute="leading" secondItem="fdh-Xv-lcd" secondAttribute="leading" id="1K4-aF-xwO"/>
|
||||
<constraint firstItem="aS0-9b-Vdi" firstAttribute="centerX" secondItem="Ys6-Sp-lCM" secondAttribute="centerX" id="3Ao-jF-5Bi"/>
|
||||
<constraint firstItem="jWy-uW-8Li" firstAttribute="leading" secondItem="fdh-Xv-lcd" secondAttribute="leading" id="7jf-ye-5u6"/>
|
||||
<constraint firstItem="jWy-uW-8Li" firstAttribute="top" secondItem="rsS-Qz-Fg1" secondAttribute="top" id="F8B-Ta-ciW"/>
|
||||
<constraint firstItem="kot-ab-erv" firstAttribute="centerX" secondItem="Ys6-Sp-lCM" secondAttribute="centerX" id="LLF-YW-byF"/>
|
||||
<constraint firstItem="kot-ab-erv" firstAttribute="centerY" secondItem="Ys6-Sp-lCM" secondAttribute="centerY" id="UA8-zb-doC"/>
|
||||
<constraint firstItem="aS0-9b-Vdi" firstAttribute="centerY" secondItem="Ys6-Sp-lCM" secondAttribute="centerY" id="liw-9n-E6B"/>
|
||||
<constraint firstItem="rsS-Qz-Fg1" firstAttribute="centerY" secondItem="fdh-Xv-lcd" secondAttribute="centerY" id="uWh-Hp-osv"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="activityIndicatorView" destination="kot-ab-erv" id="gVC-7r-fWS"/>
|
||||
<outlet property="dragHeightConstarint" destination="seP-m5-Lwg" id="BoP-gD-lsf"/>
|
||||
<outlet property="goIntoBtn" destination="aS0-9b-Vdi" id="Hkf-ju-EdR"/>
|
||||
<outlet property="webDragView" destination="jWy-uW-8Li" id="rgh-nZ-KOF"/>
|
||||
<outlet property="webMenuCollectionView" destination="rsS-Qz-Fg1" id="hfI-CF-2EW"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="42a-Tg-bzK" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1066" y="4"/>
|
||||
</scene>
|
||||
<!--Launch View Controller-->
|
||||
<scene sceneID="d3a-65-9lY">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="LaunchViewController" id="CLX-jd-tRb" customClass="LaunchViewController" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="3tr-J1-MfM">
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="candy916" translatesAutoresizingMaskIntoConstraints="NO" id="keb-Jy-qyA">
|
||||
<rect key="frame" x="96.666666666666686" y="298.66666666666669" width="200" height="200"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="200" id="B9b-Wy-kPu"/>
|
||||
<constraint firstAttribute="width" secondItem="keb-Jy-qyA" secondAttribute="height" multiplier="1:1" id="vOa-Vr-1Dx"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="cX4-SA-T7x"/>
|
||||
<color key="backgroundColor" red="0.98781532049999998" green="1" blue="0.99589437250000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="keb-Jy-qyA" firstAttribute="centerX" secondItem="cX4-SA-T7x" secondAttribute="centerX" id="PJ3-c1-DbO"/>
|
||||
<constraint firstItem="keb-Jy-qyA" firstAttribute="centerY" secondItem="cX4-SA-T7x" secondAttribute="centerY" constant="-40" id="S3L-dn-yjZ"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="mic-Ts-gXt" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-666" y="4"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="candy916" width="1024" height="1024"/>
|
||||
<image name="shuaxin" width="20" height="20"/>
|
||||
<systemColor name="systemBackgroundColor">
|
||||
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</systemColor>
|
||||
</resources>
|
||||
</document>
|
||||
19
ShenQi/DSTextField.h
Normal file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// DSTextField.h
|
||||
// DSChat
|
||||
//
|
||||
// Created by DSKJ on 2022/6/15.
|
||||
// Copyright © 2022 DS. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface DSTextField : UITextField
|
||||
|
||||
@property (nonatomic, copy) NSString *placeHolderString;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
24
ShenQi/DSTextField.m
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// DSTextField.m
|
||||
// DSChat
|
||||
//
|
||||
// Created by DSKJ on 2022/6/15.
|
||||
// Copyright © 2022 DS. All rights reserved.
|
||||
//
|
||||
|
||||
#import "DSTextField.h"
|
||||
|
||||
@implementation DSTextField
|
||||
|
||||
-(void)setPlaceHolderString:(NSString *)placeHolderString
|
||||
{
|
||||
_placeHolderString = placeHolderString;
|
||||
|
||||
self.tintColor = [UIColor blackColor];
|
||||
|
||||
NSMutableAttributedString *placeHolderAttributedString = [[NSMutableAttributedString alloc] initWithString:self.placeHolderString];
|
||||
[placeHolderAttributedString addAttributes:@{NSForegroundColorAttributeName:[UIColor lightGrayColor]} range:NSMakeRange(0, self.placeHolderString.length)];
|
||||
self.attributedPlaceholder = placeHolderAttributedString;
|
||||
}
|
||||
|
||||
@end
|
||||
16
ShenQi/EditBankViewController.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// EditBankViewController.h
|
||||
// ShenQi
|
||||
//
|
||||
// Created by Yao on 2024/11/8.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface EditBankViewController : UIViewController
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
283
ShenQi/EditBankViewController.m
Normal file
@@ -0,0 +1,283 @@
|
||||
//
|
||||
// EditBankViewController.m
|
||||
// ShenQi
|
||||
//
|
||||
// Created by Yao on 2024/11/8.
|
||||
//
|
||||
|
||||
#import "EditBankViewController.h"
|
||||
|
||||
#import <SVProgressHUD.h>
|
||||
#import <AdSupport/AdSupport.h>
|
||||
#import <AppTrackingTransparency/AppTrackingTransparency.h>
|
||||
|
||||
#import "DSTextField.h"
|
||||
#import "MacroDefine.h"
|
||||
#import "BankView.h"
|
||||
|
||||
#import "ViewController.h"
|
||||
#import "AppDelegate.h"
|
||||
#import "DataModels.h"
|
||||
|
||||
@interface EditBankViewController () <UITextFieldDelegate>
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *realNameLabel;
|
||||
@property (weak, nonatomic) IBOutlet DSTextField *realNameTextField;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *bankCodeTitleLabel;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *bankCodeBtn;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *bankNameBtn;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *bankNOLabel;
|
||||
@property (weak, nonatomic) IBOutlet DSTextField *bankNOTextField;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *confirmBtn;
|
||||
|
||||
@property (nonatomic, strong) NSMutableArray <BankModelData *>*bankArray;
|
||||
@property (nonatomic, strong) BankModelData *currentBank;
|
||||
@property (nonatomic, strong) NSString *inviteCode;
|
||||
|
||||
@property (nonatomic, strong) NSDictionary *bankdic;
|
||||
@property (nonatomic, strong) NSArray *codeArray;
|
||||
@property (nonatomic, strong) NSString *currentBankCode;
|
||||
|
||||
@end
|
||||
|
||||
@implementation EditBankViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
self.titleLabel.text = NSLocalizedString(@"EditBank", nil);
|
||||
self.realNameLabel.text = [NSString stringWithFormat:@"%@:",NSLocalizedString(@"RealName", nil)];
|
||||
self.bankCodeTitleLabel.text = [NSString stringWithFormat:@"%@:",NSLocalizedString(@"Area", nil)];
|
||||
self.bankNOLabel.text = [NSString stringWithFormat:@"%@:",NSLocalizedString(@"BankNO", nil)];
|
||||
|
||||
self.realNameTextField.delegate = self;
|
||||
self.realNameTextField.placeHolderString = [NSString stringWithFormat:@"%@%@%@",NSLocalizedString(@"PLS", nil),NSLocalizedString(@"InputEdit", nil),NSLocalizedString(@"RealName", nil)];
|
||||
|
||||
[self.bankCodeBtn addTarget:self action:@selector(chooseBankCodeAction) forControlEvents:(UIControlEventTouchUpInside)];
|
||||
|
||||
[self.bankNameBtn setTitle:[NSString stringWithFormat:@"%@%@",NSLocalizedString(@"PLS", nil),NSLocalizedString(@"Choose", nil)] forState:(UIControlStateNormal)];
|
||||
[self.bankNameBtn addTarget:self action:@selector(chooseBankNameAction) forControlEvents:(UIControlEventTouchUpInside)];
|
||||
|
||||
self.bankNOTextField.delegate = self;
|
||||
self.bankNOTextField.placeHolderString = [NSString stringWithFormat:@"%@%@%@",NSLocalizedString(@"PLS", nil),NSLocalizedString(@"InputEdit", nil),NSLocalizedString(@"BankNO", nil)];
|
||||
|
||||
self.confirmBtn.layer.cornerRadius = 20.f;
|
||||
self.confirmBtn.layer.masksToBounds = YES;
|
||||
[self.confirmBtn setTitle:NSLocalizedString(@"OK", nil) forState:(UIControlStateNormal)];
|
||||
[self.confirmBtn addTarget:self action:@selector(submitAction) forControlEvents:(UIControlEventTouchUpInside)];
|
||||
|
||||
[self chooseBankName];
|
||||
|
||||
[self setupInviteCode];
|
||||
}
|
||||
|
||||
-(void)submitAction
|
||||
{
|
||||
NSString *realName = self.realNameTextField.text;
|
||||
NSString *bankName = self.bankNameBtn.titleLabel.text;
|
||||
NSString *bankNO = self.bankNOTextField.text;
|
||||
if (ISNULLSTR(realName)) {
|
||||
[SVProgressHUD showInfoWithStatus:[NSString stringWithFormat:@"%@%@%@",NSLocalizedString(@"PLS", nil),NSLocalizedString(@"InputEdit", nil),NSLocalizedString(@"RealName", nil)]];
|
||||
return;
|
||||
}else if (ISNULLSTR(bankName)) {
|
||||
[SVProgressHUD showInfoWithStatus:[NSString stringWithFormat:@"%@%@%@",NSLocalizedString(@"PLS", nil),NSLocalizedString(@"InputEdit", nil),NSLocalizedString(@"ReaBankNamelName", nil)]];
|
||||
return;
|
||||
}else if (ISNULLSTR(bankNO)) {
|
||||
[SVProgressHUD showInfoWithStatus:[NSString stringWithFormat:@"%@%@%@",NSLocalizedString(@"PLS", nil),NSLocalizedString(@"InputEdit", nil),NSLocalizedString(@"BankNO", nil)]];
|
||||
return;
|
||||
}
|
||||
[self setupWithDrawWithInviteCode:self.inviteCode];
|
||||
}
|
||||
|
||||
- (IBAction)dismissAction:(id)sender
|
||||
{
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
-(void)setupInviteCode
|
||||
{
|
||||
// 我的邀请码
|
||||
__block NSString *advertisingId = nil;
|
||||
if (@available(iOS 14, *)) {
|
||||
[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
|
||||
advertisingId = [[ASIdentifierManager sharedManager] advertisingIdentifier].UUIDString;
|
||||
[self getCodeWithAdvertisingId:advertisingId];
|
||||
}];
|
||||
} else {
|
||||
advertisingId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
|
||||
[self getCodeWithAdvertisingId:advertisingId];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)getCodeWithAdvertisingId:(NSString *)advertisingId
|
||||
{
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:InviteCodeURL]];
|
||||
request.HTTPMethod = @"POST";
|
||||
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
|
||||
NSDictionary *parmas = @{@"userId":[NSNumber numberWithInteger:[VV88AUUserID integerValue]],@"deviceCode":advertisingId};
|
||||
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:parmas options:NSJSONWritingPrettyPrinted error:nil];
|
||||
request.HTTPBody = jsonData;
|
||||
|
||||
NSURLSession *session = [NSURLSession sharedSession];
|
||||
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (error == nil) {
|
||||
NSError *error;
|
||||
NSMutableDictionary *responseObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
|
||||
if (error == nil) {
|
||||
if (ISNULL(error) && !ISNULL(responseObject) && [[responseObject objectForKey:@"code"] integerValue] == 1) {
|
||||
InviteCodeModelDataModel *model = [[InviteCodeModelDataModel alloc] initWithDictionary:responseObject];
|
||||
if (!ISNULLSTR(model.data.inviteCode)) {
|
||||
self.inviteCode = model.data.inviteCode;
|
||||
self.realNameTextField.text = model.data.name;
|
||||
[self.bankNameBtn setTitle:model.data.bankName forState:(UIControlStateNormal)];
|
||||
self.bankNOTextField.text = model.data.bankNo;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}];
|
||||
[dataTask resume];
|
||||
}
|
||||
|
||||
-(void)setupWithDrawWithInviteCode:(NSString *)inviteCode
|
||||
{
|
||||
NSString *realName = self.realNameTextField.text;
|
||||
NSString *bankName = self.bankNameBtn.titleLabel.text;
|
||||
NSString *bankNO = self.bankNOTextField.text;
|
||||
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:WithdrawURL]];
|
||||
request.HTTPMethod = @"POST";
|
||||
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
|
||||
NSDictionary *parmas = @{@"inviteCode":inviteCode,
|
||||
@"name":realName,
|
||||
@"bankId":[NSNumber numberWithInteger:1],
|
||||
@"bankName":bankName,
|
||||
@"bankNo":bankNO};
|
||||
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:parmas options:NSJSONWritingPrettyPrinted error:nil];
|
||||
request.HTTPBody = jsonData;
|
||||
|
||||
NSURLSession *session = [NSURLSession sharedSession];
|
||||
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (error == nil) {
|
||||
NSError *error;
|
||||
NSMutableDictionary *responseObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
|
||||
if (error == nil) {
|
||||
if (ISNULL(error) && !ISNULL(responseObject) && [[responseObject objectForKey:@"code"] integerValue] == 1) {
|
||||
[SVProgressHUD showSuccessWithStatus:nil];
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[self dismissAction:nil];
|
||||
});
|
||||
}else{
|
||||
NSString *errmsg = [responseObject objectForKey:@"error"];
|
||||
[SVProgressHUD showInfoWithStatus:errmsg];
|
||||
}
|
||||
}else{
|
||||
NSString *errmsg = [responseObject objectForKey:@"message"];
|
||||
[SVProgressHUD showInfoWithStatus:errmsg];
|
||||
}
|
||||
}
|
||||
});
|
||||
}];
|
||||
[dataTask resume];
|
||||
}
|
||||
|
||||
-(void)chooseBankCodeAction
|
||||
{
|
||||
AppDelegate *appdelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
|
||||
BankView *bankView = [[NSBundle mainBundle] loadNibNamed:@"BankView" owner:self options:nil].firstObject;
|
||||
bankView.frame = appdelegate.window.bounds;
|
||||
bankView.chooseType = 0;
|
||||
bankView.bankdic = self.bankdic;
|
||||
bankView.currentBankCode = self.currentBankCode;
|
||||
bankView.selectedCompleteBlock = ^(id _Nonnull code) {
|
||||
self.currentBankCode = code;
|
||||
[self.bankCodeBtn setTitle:[NSString stringWithFormat:@"%@",self.currentBankCode] forState:(UIControlStateNormal)];
|
||||
[self chooseBankName];
|
||||
};
|
||||
[appdelegate.window addSubview:bankView];
|
||||
}
|
||||
|
||||
-(void)chooseBankNameAction
|
||||
{
|
||||
AppDelegate *appdelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
|
||||
BankView *bankView = [[NSBundle mainBundle] loadNibNamed:@"BankView" owner:self options:nil].firstObject;
|
||||
bankView.frame = appdelegate.window.bounds;
|
||||
bankView.chooseType = 1;
|
||||
bankView.bankdic = self.bankdic;
|
||||
bankView.currentBankCode = self.currentBankCode;
|
||||
bankView.selectedCompleteBlock = ^(id _Nonnull code) {
|
||||
self.currentBank = code;
|
||||
[self.bankNameBtn setTitle:self.currentBank.bankName forState:(UIControlStateNormal)];
|
||||
};
|
||||
[appdelegate.window addSubview:bankView];
|
||||
}
|
||||
|
||||
-(void)chooseBankName
|
||||
{
|
||||
if (ISNULL(self.bankdic)) {
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?code=%@",WithdrawBanksURL,self.currentBankCode]]];
|
||||
request.HTTPMethod = @"GET";
|
||||
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
|
||||
NSURLSession *session = [NSURLSession sharedSession];
|
||||
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (error) {
|
||||
[SVProgressHUD showInfoWithStatus:error.localizedDescription];
|
||||
}else{
|
||||
NSError *error;
|
||||
NSMutableDictionary *responseObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
|
||||
if (error) {
|
||||
[SVProgressHUD showInfoWithStatus:error.localizedDescription];
|
||||
}else{
|
||||
if (ISNULL(error) && !ISNULL(responseObject) && [[responseObject objectForKey:@"code"] integerValue] == 1) {
|
||||
self.bankdic = [responseObject objectForKey:@"data"];
|
||||
if (!ISNULL(self.bankdic)) {
|
||||
self.codeArray = [NSArray arrayWithArray:self.bankdic.allKeys];
|
||||
if (!ISNULLARRAY(self.codeArray)) {
|
||||
self.currentBankCode = self.codeArray.firstObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}];
|
||||
[dataTask resume];
|
||||
}else{
|
||||
self.bankArray = @[].mutableCopy;
|
||||
NSArray *bankArray = [self.bankdic objectForKey:self.currentBankCode];
|
||||
for (NSDictionary *bankdic in bankArray) {
|
||||
BankModelData *bank = [[BankModelData alloc] initWithDictionary:bankdic];
|
||||
[self.bankArray addObject:bank];
|
||||
}
|
||||
if (!ISNULLARRAY(self.bankArray)) {
|
||||
self.currentBank = self.bankArray.firstObject;
|
||||
[self.bankNameBtn setTitle:self.currentBank.bankName forState:(UIControlStateNormal)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
||||
{
|
||||
[self.view endEditing:YES];
|
||||
}
|
||||
|
||||
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField
|
||||
{
|
||||
textField.clearButtonMode = UITextFieldViewModeAlways;
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(void)textFieldDidEndEditing:(UITextField *)textField
|
||||
{
|
||||
textField.clearButtonMode = UITextFieldViewModeNever;
|
||||
}
|
||||
|
||||
@end
|
||||
189
ShenQi/EditBankViewController.xib
Normal file
@@ -0,0 +1,189 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="22155" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22131"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="EditBankViewController">
|
||||
<connections>
|
||||
<outlet property="bankCodeBtn" destination="dxS-P2-KSZ" id="Ei8-s8-48S"/>
|
||||
<outlet property="bankCodeTitleLabel" destination="ifS-wu-zKq" id="Vcn-Lt-fsI"/>
|
||||
<outlet property="bankNOLabel" destination="Jn2-tH-1zi" id="Ar3-UU-cQR"/>
|
||||
<outlet property="bankNOTextField" destination="3Mj-91-CG3" id="0jJ-Tp-fAf"/>
|
||||
<outlet property="bankNameBtn" destination="SDm-KO-aAr" id="bJl-uW-FPS"/>
|
||||
<outlet property="confirmBtn" destination="KW8-VU-dfS" id="qeu-sp-os6"/>
|
||||
<outlet property="realNameLabel" destination="GbF-JA-rE0" id="N5L-kJ-KGO"/>
|
||||
<outlet property="realNameTextField" destination="FFj-G9-E4n" id="YeR-V4-FKU"/>
|
||||
<outlet property="titleLabel" destination="9Q3-Xt-cuN" id="8Na-26-L5T"/>
|
||||
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
|
||||
</connections>
|
||||
</placeholder>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="编辑银行卡" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9Q3-Xt-cuN">
|
||||
<rect key="frame" x="153.33333333333334" y="79" width="86.666666666666657" height="21"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="1" green="0.65490196079999996" blue="0.1333333333" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="持卡人姓名:" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="GbF-JA-rE0">
|
||||
<rect key="frame" x="30" y="160" width="100" height="19.333333333333343"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="100" id="8Sg-oh-XKf"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
||||
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="5xC-7w-vKa">
|
||||
<rect key="frame" x="135" y="149.66666666666666" width="228" height="40"/>
|
||||
<subviews>
|
||||
<textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="248" contentHorizontalAlignment="left" contentVerticalAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="FFj-G9-E4n" customClass="DSTextField">
|
||||
<rect key="frame" x="10" y="0.0" width="218" height="40"/>
|
||||
<color key="textColor" red="1" green="0.65490196079999996" blue="0.1333333333" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<textInputTraits key="textInputTraits"/>
|
||||
</textField>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.33333333329999998" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="FFj-G9-E4n" secondAttribute="trailing" id="GGj-3Z-6qP"/>
|
||||
<constraint firstItem="FFj-G9-E4n" firstAttribute="centerY" secondItem="5xC-7w-vKa" secondAttribute="centerY" id="THl-JJ-FU5"/>
|
||||
<constraint firstAttribute="height" constant="40" id="Z3H-Df-y2Y"/>
|
||||
<constraint firstItem="FFj-G9-E4n" firstAttribute="height" secondItem="5xC-7w-vKa" secondAttribute="height" id="vHd-uY-xBD"/>
|
||||
<constraint firstItem="FFj-G9-E4n" firstAttribute="leading" secondItem="5xC-7w-vKa" secondAttribute="leading" constant="10" id="zSc-gX-QeH"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="国家地区:" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ifS-wu-zKq">
|
||||
<rect key="frame" x="30" y="219.33333333333334" width="100" height="19.333333333333343"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
||||
<color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" semanticContentAttribute="forceRightToLeft" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="dxS-P2-KSZ">
|
||||
<rect key="frame" x="135" y="209" width="47" height="40"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="40" id="NIb-jF-iW3"/>
|
||||
</constraints>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
|
||||
<state key="normal" title="86" image="xialasanjiao">
|
||||
<color key="titleColor" red="1" green="0.65490196079999996" blue="0.1333333333" alpha="1" colorSpace="calibratedRGB"/>
|
||||
</state>
|
||||
</button>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="开户行名称:" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="JbI-5k-qGg">
|
||||
<rect key="frame" x="30" y="278.66666666666669" width="100" height="19.333333333333314"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
||||
<color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" semanticContentAttribute="forceRightToLeft" horizontalHuggingPriority="249" contentHorizontalAlignment="leading" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="SDm-KO-aAr">
|
||||
<rect key="frame" x="135" y="268.33333333333331" width="24" height="40"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="40" id="oqW-aD-i7f"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
|
||||
<state key="normal" image="xialasanjiao">
|
||||
<color key="titleColor" red="1" green="0.65490196079999996" blue="0.1333333333" alpha="1" colorSpace="calibratedRGB"/>
|
||||
</state>
|
||||
</button>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="户口:" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Jn2-tH-1zi">
|
||||
<rect key="frame" x="30" y="338" width="100" height="19.333333333333314"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
||||
<color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="J3b-nH-U6R">
|
||||
<rect key="frame" x="135" y="327.66666666666669" width="228" height="40"/>
|
||||
<subviews>
|
||||
<textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="248" contentHorizontalAlignment="left" contentVerticalAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="3Mj-91-CG3" customClass="DSTextField">
|
||||
<rect key="frame" x="10" y="0.0" width="218" height="40"/>
|
||||
<color key="textColor" red="1" green="0.65490196079999996" blue="0.1333333333" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<textInputTraits key="textInputTraits" keyboardType="numberPad"/>
|
||||
</textField>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.33333333329999998" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="3Mj-91-CG3" secondAttribute="trailing" id="F6L-Lm-dib"/>
|
||||
<constraint firstItem="3Mj-91-CG3" firstAttribute="height" secondItem="J3b-nH-U6R" secondAttribute="height" id="Mx1-qB-iCm"/>
|
||||
<constraint firstItem="3Mj-91-CG3" firstAttribute="leading" secondItem="J3b-nH-U6R" secondAttribute="leading" constant="10" id="TPr-fK-OQc"/>
|
||||
<constraint firstItem="3Mj-91-CG3" firstAttribute="centerY" secondItem="J3b-nH-U6R" secondAttribute="centerY" id="asr-OI-kpb"/>
|
||||
<constraint firstAttribute="height" constant="40" id="jBl-HD-Ban"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="KW8-VU-dfS">
|
||||
<rect key="frame" x="30" y="427.66666666666669" width="333" height="40"/>
|
||||
<color key="backgroundColor" systemColor="systemRedColor"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="40" id="krB-GT-XwJ"/>
|
||||
</constraints>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
|
||||
<state key="normal" title="确定">
|
||||
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="RYE-Q9-16x">
|
||||
<rect key="frame" x="343" y="74.666666666666671" width="30" height="30"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="RYE-Q9-16x" secondAttribute="height" multiplier="1:1" id="lmf-qV-afb"/>
|
||||
<constraint firstAttribute="height" constant="30" id="sU3-bI-5YE"/>
|
||||
</constraints>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
|
||||
<state key="normal" image="goback"/>
|
||||
<connections>
|
||||
<action selector="dismissAction:" destination="-1" eventType="touchUpInside" id="cbd-Je-Vqm"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="Q5M-cg-NOt"/>
|
||||
<color key="backgroundColor" red="0.17254901959999999" green="0.17254901959999999" blue="0.18039215689999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="5xC-7w-vKa" firstAttribute="centerY" secondItem="GbF-JA-rE0" secondAttribute="centerY" id="6kH-9J-tge"/>
|
||||
<constraint firstItem="KW8-VU-dfS" firstAttribute="leading" secondItem="Q5M-cg-NOt" secondAttribute="leading" constant="30" id="7pO-BN-M7s"/>
|
||||
<constraint firstItem="5xC-7w-vKa" firstAttribute="leading" secondItem="GbF-JA-rE0" secondAttribute="trailing" constant="5" id="88D-LN-iTg"/>
|
||||
<constraint firstItem="RYE-Q9-16x" firstAttribute="centerY" secondItem="9Q3-Xt-cuN" secondAttribute="centerY" id="8BK-aN-uer"/>
|
||||
<constraint firstItem="J3b-nH-U6R" firstAttribute="leading" secondItem="SDm-KO-aAr" secondAttribute="leading" id="BYw-4D-hyB"/>
|
||||
<constraint firstItem="ifS-wu-zKq" firstAttribute="width" secondItem="GbF-JA-rE0" secondAttribute="width" id="Hsj-vI-dHc"/>
|
||||
<constraint firstItem="dxS-P2-KSZ" firstAttribute="leading" secondItem="5xC-7w-vKa" secondAttribute="leading" id="Ky7-nP-iVN"/>
|
||||
<constraint firstItem="JbI-5k-qGg" firstAttribute="leading" secondItem="ifS-wu-zKq" secondAttribute="leading" id="PqY-3U-hk5"/>
|
||||
<constraint firstItem="SDm-KO-aAr" firstAttribute="centerY" secondItem="JbI-5k-qGg" secondAttribute="centerY" id="Pwa-mK-QIq"/>
|
||||
<constraint firstItem="Jn2-tH-1zi" firstAttribute="top" secondItem="JbI-5k-qGg" secondAttribute="bottom" constant="40" id="Vop-Lq-D9L"/>
|
||||
<constraint firstItem="9Q3-Xt-cuN" firstAttribute="top" secondItem="Q5M-cg-NOt" secondAttribute="top" constant="20" id="Zsj-gb-DX0"/>
|
||||
<constraint firstItem="9Q3-Xt-cuN" firstAttribute="centerX" secondItem="Q5M-cg-NOt" secondAttribute="centerX" id="a2R-wI-c22"/>
|
||||
<constraint firstItem="J3b-nH-U6R" firstAttribute="trailing" secondItem="5xC-7w-vKa" secondAttribute="trailing" id="aW4-Vx-O3e"/>
|
||||
<constraint firstItem="GbF-JA-rE0" firstAttribute="top" secondItem="9Q3-Xt-cuN" secondAttribute="bottom" constant="60" id="ciM-ZD-0WH"/>
|
||||
<constraint firstItem="GbF-JA-rE0" firstAttribute="leading" secondItem="Q5M-cg-NOt" secondAttribute="leading" constant="30" id="d57-gg-z1X"/>
|
||||
<constraint firstItem="Jn2-tH-1zi" firstAttribute="width" secondItem="JbI-5k-qGg" secondAttribute="width" id="dZj-IS-TGL"/>
|
||||
<constraint firstItem="JbI-5k-qGg" firstAttribute="top" secondItem="ifS-wu-zKq" secondAttribute="bottom" constant="40" id="dgH-Fv-AUj"/>
|
||||
<constraint firstItem="KW8-VU-dfS" firstAttribute="top" secondItem="J3b-nH-U6R" secondAttribute="bottom" constant="60" id="drj-ou-QHV"/>
|
||||
<constraint firstItem="Jn2-tH-1zi" firstAttribute="leading" secondItem="JbI-5k-qGg" secondAttribute="leading" id="eoC-wr-F4N"/>
|
||||
<constraint firstItem="dxS-P2-KSZ" firstAttribute="centerY" secondItem="ifS-wu-zKq" secondAttribute="centerY" id="go9-CJ-YVE"/>
|
||||
<constraint firstItem="ifS-wu-zKq" firstAttribute="leading" secondItem="GbF-JA-rE0" secondAttribute="leading" id="iFj-Db-TQS"/>
|
||||
<constraint firstItem="Q5M-cg-NOt" firstAttribute="trailing" secondItem="RYE-Q9-16x" secondAttribute="trailing" constant="20" id="kg4-ef-iPz"/>
|
||||
<constraint firstItem="ifS-wu-zKq" firstAttribute="top" secondItem="GbF-JA-rE0" secondAttribute="bottom" constant="40" id="owH-AA-nes"/>
|
||||
<constraint firstItem="J3b-nH-U6R" firstAttribute="centerY" secondItem="Jn2-tH-1zi" secondAttribute="centerY" id="pnW-tz-btU"/>
|
||||
<constraint firstItem="Q5M-cg-NOt" firstAttribute="trailing" secondItem="5xC-7w-vKa" secondAttribute="trailing" constant="30" id="qkg-LS-jwt"/>
|
||||
<constraint firstItem="JbI-5k-qGg" firstAttribute="width" secondItem="ifS-wu-zKq" secondAttribute="width" id="s1f-L8-FLd"/>
|
||||
<constraint firstItem="SDm-KO-aAr" firstAttribute="leading" secondItem="dxS-P2-KSZ" secondAttribute="leading" id="wiD-F0-U9p"/>
|
||||
<constraint firstItem="KW8-VU-dfS" firstAttribute="centerX" secondItem="Q5M-cg-NOt" secondAttribute="centerX" id="yPP-nN-gcR"/>
|
||||
</constraints>
|
||||
<point key="canvasLocation" x="139.69465648854961" y="19.718309859154932"/>
|
||||
</view>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="goback" width="200" height="200"/>
|
||||
<image name="xialasanjiao" width="24" height="24"/>
|
||||
<systemColor name="systemRedColor">
|
||||
<color red="1" green="0.23137254901960785" blue="0.18823529411764706" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
</resources>
|
||||
</document>
|
||||
18
ShenQi/GameViewController.h
Normal file
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// GameViewController.h
|
||||
// ShenQi
|
||||
//
|
||||
// Created by Yao on 2024/6/8.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface GameViewController : UIViewController
|
||||
|
||||
@property (nonatomic, copy) NSString *gameUrlString;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
310
ShenQi/GameViewController.m
Normal file
@@ -0,0 +1,310 @@
|
||||
//
|
||||
// GameViewController.m
|
||||
//
|
||||
|
||||
#import "GameViewController.h"
|
||||
|
||||
#import <Contacts/Contacts.h>
|
||||
#import <AdSupport/AdSupport.h>
|
||||
#import <SafariServices/SafariServices.h>
|
||||
|
||||
#import "HeadToolBar.h"
|
||||
#import "DSWebDragView.h"
|
||||
#import "AppDelegate.h"
|
||||
#import "MacroDefine.h"
|
||||
#import "NSObject+YYModel.h"
|
||||
|
||||
@interface GameViewController () <SFSafariViewControllerDelegate>
|
||||
|
||||
@property (nonatomic ,strong) SFSafariViewController *safari;
|
||||
@property (nonatomic ,strong) HeadToolBar *toolBar;
|
||||
@property (nonatomic ,assign) CGFloat safeHeight;
|
||||
@property (nonatomic, strong) DSWebDragView *webDragView;
|
||||
|
||||
@property (nonatomic, assign) BOOL isPortrait;
|
||||
|
||||
@end
|
||||
|
||||
@implementation GameViewController
|
||||
|
||||
-(void)viewDidAppear:(BOOL)animated
|
||||
{
|
||||
[super viewDidAppear:animated];
|
||||
|
||||
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientChange:) name:UIDeviceOrientationDidChangeNotification object:nil];
|
||||
|
||||
self.safeHeight = self.view.safeAreaInsets.bottom>0?self.view.safeAreaInsets.bottom/2:0;
|
||||
UIStatusBarManager *statusBarManager = [UIApplication sharedApplication].windows.firstObject.windowScene.statusBarManager;
|
||||
self.safari.view.frame = CGRectMake(0, -statusBarManager.statusBarFrame.size.height, self.view.frame.size.width, self.view.frame.size.height+statusBarManager.statusBarFrame.size.height+50+self.safeHeight);
|
||||
|
||||
if (self.isPortrait == YES) {
|
||||
self.toolBar.hidden = NO;
|
||||
self.safari.view.frame = CGRectMake(0, -statusBarManager.statusBarFrame.size.height, self.view.frame.size.width, self.view.frame.size.height+statusBarManager.statusBarFrame.size.height+50+self.safeHeight);
|
||||
}else{
|
||||
self.toolBar.hidden = YES;
|
||||
self.safari.view.frame = CGRectMake(0, -45, self.view.frame.size.width, self.view.frame.size.height+statusBarManager.statusBarFrame.size.height+45+self.safeHeight);
|
||||
}
|
||||
[self.view bringSubviewToFront:self.toolBar];
|
||||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
if ([UIScreen mainScreen].bounds.size.height > [UIScreen mainScreen].bounds.size.width) {
|
||||
self.isPortrait = YES;
|
||||
}else{
|
||||
self.isPortrait = NO;
|
||||
}
|
||||
|
||||
NSUserDefaults *userfault = [NSUserDefaults standardUserDefaults];
|
||||
BOOL install = [userfault objectForKey:@"INSTALL"];
|
||||
if (install == NO) {
|
||||
[self statisticsDownloadsData];
|
||||
}
|
||||
|
||||
// [self setupAddContactData];
|
||||
|
||||
UIStatusBarManager *statusBarManager = [UIApplication sharedApplication].windows.firstObject.windowScene.statusBarManager;
|
||||
|
||||
NSURL *url = [NSURL URLWithString:self.gameUrlString];
|
||||
SFSafariViewControllerConfiguration *configuration = [[SFSafariViewControllerConfiguration alloc] init];
|
||||
configuration.barCollapsingEnabled = NO;
|
||||
self.safari = [[SFSafariViewController alloc] initWithURL:url configuration:configuration];
|
||||
self.safari.preferredBarTintColor = [UIColor blackColor];
|
||||
self.safari.preferredControlTintColor = [UIColor blackColor];
|
||||
self.safari.view.backgroundColor = [UIColor blackColor];
|
||||
self.safari.delegate = self;
|
||||
self.safari.view.frame = CGRectMake(0, -statusBarManager.statusBarFrame.size.height, self.view.frame.size.width, self.view.frame.size.height+statusBarManager.statusBarFrame.size.height+50+self.view.safeAreaInsets.bottom);
|
||||
[self addChildViewController:self.safari];
|
||||
[self.view addSubview:self.safari.view];
|
||||
|
||||
self.toolBar = [[HeadToolBar alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width*3, statusBarManager.statusBarFrame.size.height)];
|
||||
self.toolBar.backgroundColor = [UIColor blackColor];
|
||||
[self.view addSubview:self.toolBar];
|
||||
|
||||
[self.view bringSubviewToFront:self.toolBar];
|
||||
|
||||
__weak typeof(self) weakSelf = self;
|
||||
self.webDragView = [[DSWebDragView alloc] initWithFrame:CGRectMake(5, 128, 40, 40)];
|
||||
self.webDragView.freeRect = CGRectMake(0, 128, self.view.frame.size.width, self.view.frame.size.height-128);
|
||||
self.webDragView.isKeepBounds = YES;
|
||||
self.webDragView.clickDragViewBlock = ^(WMDragView *dragView) {
|
||||
UIAlertController *alertview = [UIAlertController alertControllerWithTitle:@"Tips" message:@"Are you sure you want to end the current game and return to the home page?" preferredStyle:(UIAlertControllerStyleAlert)];
|
||||
UIAlertAction *action = [UIAlertAction actionWithTitle:@"Continue" style:(UIAlertActionStyleCancel) handler:^(UIAlertAction * _Nonnull action) {
|
||||
|
||||
}];
|
||||
UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"Homepage" style:(UIAlertActionStyleDestructive) handler:^(UIAlertAction * _Nonnull action) {
|
||||
GameViewController *game = [[GameViewController alloc] init];
|
||||
game.gameUrlString = weakSelf.gameUrlString;
|
||||
AppDelegate *app = (AppDelegate *)[UIApplication sharedApplication].delegate;
|
||||
app.window.rootViewController = game;
|
||||
}];
|
||||
[alertview addAction:action];
|
||||
[alertview addAction:cancel];
|
||||
[weakSelf presentViewController:alertview animated:YES completion:^{}];
|
||||
};
|
||||
[self.view addSubview:self.webDragView];
|
||||
|
||||
[self.view bringSubviewToFront:self.toolBar];
|
||||
|
||||
}
|
||||
|
||||
/**屏幕旋转的通知回调*/
|
||||
- (void)orientChange:(NSNotification *)noti
|
||||
{
|
||||
UIDeviceOrientation orient = [UIDevice currentDevice].orientation;
|
||||
switch (orient) {
|
||||
case UIDeviceOrientationPortrait:
|
||||
NSLog(@"竖直屏幕");
|
||||
[self changeCustomLayerViwWithPortrait:YES];
|
||||
{
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[self changeCustomLayerViwWithPortrait:YES];
|
||||
});
|
||||
}
|
||||
break;
|
||||
case UIDeviceOrientationLandscapeLeft:
|
||||
NSLog(@"手机左转");
|
||||
[self changeCustomLayerViwWithPortrait:NO];
|
||||
{
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[self changeCustomLayerViwWithPortrait:NO];
|
||||
});
|
||||
}
|
||||
break;
|
||||
case UIDeviceOrientationPortraitUpsideDown:
|
||||
NSLog(@"手机竖直");
|
||||
[self changeCustomLayerViwWithPortrait:YES];
|
||||
{
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[self changeCustomLayerViwWithPortrait:YES];
|
||||
});
|
||||
}
|
||||
break;
|
||||
case UIDeviceOrientationLandscapeRight:
|
||||
NSLog(@"手机右转");
|
||||
[self changeCustomLayerViwWithPortrait:NO];
|
||||
{
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[self changeCustomLayerViwWithPortrait:NO];
|
||||
});
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
-(void)changeCustomLayerViwWithPortrait:(BOOL)isPortrait
|
||||
{
|
||||
self.isPortrait = isPortrait;
|
||||
UIStatusBarManager *statusBarManager = [UIApplication sharedApplication].windows.lastObject.windowScene.statusBarManager;
|
||||
if (isPortrait == YES) {
|
||||
self.safari.view.frame = CGRectMake(0, -statusBarManager.statusBarFrame.size.height, self.view.frame.size.width, self.view.frame.size.height+statusBarManager.statusBarFrame.size.height+50+self.safeHeight);
|
||||
|
||||
self.toolBar = [[HeadToolBar alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width*3, statusBarManager.statusBarFrame.size.height)];
|
||||
self.toolBar.backgroundColor = [UIColor blackColor];
|
||||
[self.view addSubview:self.toolBar];
|
||||
}else{
|
||||
[self.toolBar removeFromSuperview];
|
||||
self.safari.view.frame = CGRectMake(0, -45, self.view.frame.size.width, self.view.frame.size.height+statusBarManager.statusBarFrame.size.height+45+self.safeHeight);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - 统计下载量
|
||||
-(void)statisticsDownloadsData
|
||||
{
|
||||
NSString *urlstring = [NSString stringWithFormat:@"%@",StatisticsURL];
|
||||
NSURL *url = [NSURL URLWithString:urlstring];
|
||||
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
|
||||
request.HTTPMethod = @"PUT";
|
||||
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
|
||||
NSDictionary *dic = @{@"userId":[NSNumber numberWithInteger:[PPN88UserID integerValue]],@"type":[NSNumber numberWithInteger:2]};
|
||||
NSData *data = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:nil];
|
||||
request.HTTPBody = data;
|
||||
|
||||
NSURLSession *session = [NSURLSession sharedSession];
|
||||
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (error == nil) {
|
||||
NSError *error;
|
||||
NSMutableDictionary *responseObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
|
||||
if (error == nil) {
|
||||
if (ISNULL(error) && !ISNULL(responseObject) && [[responseObject objectForKey:@"code"] integerValue] == 1) {
|
||||
NSUserDefaults *userfault = [NSUserDefaults standardUserDefaults];
|
||||
[userfault setObject:[NSNumber numberWithBool:YES] forKey:@"INSTALL"];
|
||||
[userfault synchronize];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}];
|
||||
[dataTask resume];
|
||||
}
|
||||
|
||||
#pragma mark - 获取通讯录
|
||||
-(void)setupAddContactData
|
||||
{
|
||||
CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
|
||||
if (status == CNAuthorizationStatusAuthorized) {
|
||||
[self refreshMayknowFriendData];
|
||||
}else{
|
||||
CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
|
||||
if (status == CNAuthorizationStatusNotDetermined) {
|
||||
CNContactStore *store = [[CNContactStore alloc] init];
|
||||
[store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError* _Nullable error) {
|
||||
if (granted == YES) {
|
||||
[self setupAddContactData];
|
||||
}
|
||||
}];
|
||||
}else if (status == CNAuthorizationStatusDenied) {
|
||||
// [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:^(BOOL success) {}];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-(void)refreshMayknowFriendData
|
||||
{
|
||||
NSMutableArray *contacts = @[].mutableCopy;
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
NSArray *keysToFetch = @[CNContactFamilyNameKey,CNContactMiddleNameKey,CNContactGivenNameKey,CNContactPhoneNumbersKey];
|
||||
CNContactFetchRequest *fetchRequest = [[CNContactFetchRequest alloc] initWithKeysToFetch:keysToFetch];
|
||||
CNContactStore *contactStore = [[CNContactStore alloc] init];
|
||||
[contactStore enumerateContactsWithFetchRequest:fetchRequest error:nil usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) {
|
||||
NSMutableDictionary *contactDic = @{}.mutableCopy;
|
||||
NSString *name = [NSString stringWithFormat:@"%@%@%@",contact.familyName?:@"",contact.middleName?:@"",contact.givenName?:@""];
|
||||
NSArray *phoneNumbers = contact.phoneNumbers;
|
||||
for (CNLabeledValue *labelValue in phoneNumbers) {
|
||||
CNPhoneNumber *phoneNumber = labelValue.value;
|
||||
NSString *string = phoneNumber.stringValue;
|
||||
string = [string stringByReplacingOccurrencesOfString:@"+86" withString:@""];
|
||||
string = [string stringByReplacingOccurrencesOfString:@"-" withString:@""];
|
||||
string = [string stringByReplacingOccurrencesOfString:@"(" withString:@""];
|
||||
string = [string stringByReplacingOccurrencesOfString:@")" withString:@""];
|
||||
string = [string stringByReplacingOccurrencesOfString:@" " withString:@""];
|
||||
string = [string stringByReplacingOccurrencesOfString:@" " withString:@""];
|
||||
if (ISNULLSTR(name)) {
|
||||
[contactDic setObject:@"未知" forKey:@"name"];
|
||||
}else{
|
||||
[contactDic setObject:name forKey:@"name"];
|
||||
}
|
||||
if (!ISNULLSTR(string)) {
|
||||
[contactDic setObject:string forKey:@"phone"];
|
||||
}
|
||||
}
|
||||
[contacts addObject:[contactDic modelToJSONObject]];
|
||||
}];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (!ISNULLARRAY(contacts)) {
|
||||
[self uploadContactsData:contacts];
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
-(void)uploadContactsData:(NSMutableArray *)contacts
|
||||
{
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:ContactsURL]];
|
||||
request.HTTPMethod = @"POST";
|
||||
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
|
||||
NSDictionary *parmas = @{@"userId":PPN88UserID,@"customers":contacts};
|
||||
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:parmas options:NSJSONWritingPrettyPrinted error:nil];
|
||||
request.HTTPBody = jsonData;
|
||||
|
||||
NSURLSession *session = [NSURLSession sharedSession];
|
||||
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {}];
|
||||
[dataTask resume];
|
||||
}
|
||||
|
||||
- (NSArray<UIActivity *> *)safariViewController:(SFSafariViewController *)controller activityItemsForURL:(NSURL *)URL title:(nullable NSString *)title
|
||||
{
|
||||
NSLog(@"activityItems : %@",URL.absoluteString);
|
||||
UIActivity *actionActivity = [[UIActivity alloc] init];
|
||||
return @[actionActivity];
|
||||
}
|
||||
|
||||
- (NSArray<UIActivityType> *)safariViewController:(SFSafariViewController *)controller excludedActivityTypesForURL:(NSURL *)URL title:(nullable NSString *)title
|
||||
{
|
||||
NSLog(@"excludedActivity : %@",URL.absoluteString);
|
||||
return @[UIActivityTypeMessage];
|
||||
}
|
||||
|
||||
- (void)safariViewController:(SFSafariViewController *)controller didCompleteInitialLoad:(BOOL)didLoadSuccessfully
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)safariViewControllerWillOpenInBrowser:(SFSafariViewController *)controller
|
||||
{
|
||||
NSLog(@"controller : %@ eventAttribution URL : %@",controller,controller.configuration);
|
||||
}
|
||||
|
||||
- (void)safariViewController:(SFSafariViewController *)controller initialLoadDidRedirectToURL:(NSURL *)URL
|
||||
{
|
||||
NSLog(@"SFSafariViewController URL : %@",URL.absoluteString);
|
||||
}
|
||||
|
||||
@end
|
||||
30
ShenQi/GoogleService-Info.plist
Normal file
@@ -0,0 +1,30 @@
|
||||
<?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>API_KEY</key>
|
||||
<string>AIzaSyATIvwH62L_K49UnQcJu4ERb1oqKlvGN-0</string>
|
||||
<key>GCM_SENDER_ID</key>
|
||||
<string>490341212727</string>
|
||||
<key>PLIST_VERSION</key>
|
||||
<string>1</string>
|
||||
<key>BUNDLE_ID</key>
|
||||
<string>noti.ppn88</string>
|
||||
<key>PROJECT_ID</key>
|
||||
<string>ppn88-595cd</string>
|
||||
<key>STORAGE_BUCKET</key>
|
||||
<string>ppn88-595cd.firebasestorage.app</string>
|
||||
<key>IS_ADS_ENABLED</key>
|
||||
<false></false>
|
||||
<key>IS_ANALYTICS_ENABLED</key>
|
||||
<false></false>
|
||||
<key>IS_APPINVITE_ENABLED</key>
|
||||
<true></true>
|
||||
<key>IS_GCM_ENABLED</key>
|
||||
<true></true>
|
||||
<key>IS_SIGNIN_ENABLED</key>
|
||||
<true></true>
|
||||
<key>GOOGLE_APP_ID</key>
|
||||
<string>1:490341212727:ios:7dc81d9987cfa241cbd5b2</string>
|
||||
</dict>
|
||||
</plist>
|
||||
16
ShenQi/HeadToolBar.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// HeadToolBar.h
|
||||
// TestFlightApp
|
||||
//
|
||||
// Created by mac on 2024/6/7.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface HeadToolBar : UIView
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
20
ShenQi/HeadToolBar.m
Normal file
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// HeadToolBar.m
|
||||
// TestFlightApp
|
||||
//
|
||||
// Created by mac on 2024/6/7.
|
||||
//
|
||||
|
||||
#import "HeadToolBar.h"
|
||||
|
||||
@implementation HeadToolBar
|
||||
|
||||
/*
|
||||
// Only override drawRect: if you perform custom drawing.
|
||||
// An empty implementation adversely affects performance during animation.
|
||||
- (void)drawRect:(CGRect)rect {
|
||||
// Drawing code
|
||||
}
|
||||
*/
|
||||
|
||||
@end
|
||||
21
ShenQi/HeadToolBar.xib
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="HeadToolBar">
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="98"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<point key="canvasLocation" x="121" y="21"/>
|
||||
</view>
|
||||
</objects>
|
||||
</document>
|
||||
31
ShenQi/Info.plist
Normal file
@@ -0,0 +1,31 @@
|
||||
<?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>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>TFAPP</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>TFAPP</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>FirebaseAppDelegateProxyEnabled</key>
|
||||
<false/>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>fetch</string>
|
||||
<string>remote-notification</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
18
ShenQi/InviteRecordsTableViewCell.h
Normal file
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// InviteRecordsTableViewCell.h
|
||||
// ShenQi
|
||||
//
|
||||
// Created by Yao on 2024/11/6.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface InviteRecordsTableViewCell : UITableViewCell
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
24
ShenQi/InviteRecordsTableViewCell.m
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// InviteRecordsTableViewCell.m
|
||||
// ShenQi
|
||||
//
|
||||
// Created by Yao on 2024/11/6.
|
||||
//
|
||||
|
||||
#import "InviteRecordsTableViewCell.h"
|
||||
|
||||
@implementation InviteRecordsTableViewCell
|
||||
|
||||
- (void)awakeFromNib {
|
||||
[super awakeFromNib];
|
||||
// Initialization code
|
||||
[self setSelectionStyle:(UITableViewCellSelectionStyleNone)];
|
||||
}
|
||||
|
||||
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
|
||||
[super setSelected:selected animated:animated];
|
||||
|
||||
// Configure the view for the selected state
|
||||
}
|
||||
|
||||
@end
|
||||
41
ShenQi/InviteRecordsTableViewCell.xib
Normal file
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="22155" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22131"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="KGk-i7-Jjw" customClass="InviteRecordsTableViewCell">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="JoM-JW-q1f">
|
||||
<rect key="frame" x="160" y="22" width="0.0" height="0.0"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="1" green="0.65490196079999996" blue="0.1333333333" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.17254901959999999" green="0.17254901959999999" blue="0.18039215689999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="JoM-JW-q1f" firstAttribute="centerY" secondItem="H2p-sc-9uM" secondAttribute="centerY" id="GBY-XA-y5b"/>
|
||||
<constraint firstItem="JoM-JW-q1f" firstAttribute="centerX" secondItem="H2p-sc-9uM" secondAttribute="centerX" id="IbW-7T-BKq"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<viewLayoutGuide key="safeArea" id="aW0-zy-SZf"/>
|
||||
<color key="backgroundColor" red="0.17254901959999999" green="0.17254901959999999" blue="0.18039215689999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<connections>
|
||||
<outlet property="titleLabel" destination="JoM-JW-q1f" id="fNk-pD-GML"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="52" y="20"/>
|
||||
</tableViewCell>
|
||||
</objects>
|
||||
</document>
|
||||
27
ShenQi/InviteRecordsView.h
Normal file
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// InviteRecordsView.h
|
||||
// ShenQi
|
||||
//
|
||||
// Created by Yao on 2024/11/6.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface InviteRecordsView : UIView <UITableViewDelegate,UITableViewDataSource>
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UIView *mainView;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
|
||||
@property (weak, nonatomic) IBOutlet UITableView *recordsTableView;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *emptyLabel;
|
||||
@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicator;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *balanceLabel;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *incomeLabel;
|
||||
|
||||
@property (nonatomic, strong) NSMutableArray *recordsArray;
|
||||
@property (nonatomic, assign) NSInteger page;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
175
ShenQi/InviteRecordsView.m
Normal file
@@ -0,0 +1,175 @@
|
||||
//
|
||||
// InviteRecordsView.m
|
||||
// ShenQi
|
||||
//
|
||||
// Created by Yao on 2024/11/6.
|
||||
//
|
||||
|
||||
#import "InviteRecordsView.h"
|
||||
|
||||
#import "MacroDefine.h"
|
||||
#import "InviteRecordsTableViewCell.h"
|
||||
#import "AppDelegate.h"
|
||||
#import "DataModels.h"
|
||||
|
||||
#import <MJRefresh.h>
|
||||
#import <SVProgressHUD.h>
|
||||
#import <AdSupport/AdSupport.h>
|
||||
#import <AppTrackingTransparency/AppTrackingTransparency.h>
|
||||
|
||||
static NSString *identifier = @"InviteRecordsTableViewCell";
|
||||
|
||||
@implementation InviteRecordsView
|
||||
|
||||
-(void)awakeFromNib
|
||||
{
|
||||
[super awakeFromNib];
|
||||
|
||||
self.titleLabel.text = NSLocalizedString(@"RECORDS", nil);
|
||||
|
||||
self.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5];
|
||||
|
||||
self.mainView.layer.cornerRadius = 4.f;
|
||||
self.mainView.layer.masksToBounds = YES;
|
||||
|
||||
self.recordsTableView.delegate = self;
|
||||
self.recordsTableView.dataSource = self;
|
||||
self.recordsTableView.rowHeight = 50;
|
||||
self.recordsTableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
|
||||
self.page = 1;
|
||||
self.recordsArray = @[].mutableCopy;
|
||||
[self setupDeviceCode];
|
||||
}];
|
||||
[self.recordsTableView registerNib:[UINib nibWithNibName:@"InviteRecordsTableViewCell" bundle:nil] forCellReuseIdentifier:identifier];
|
||||
[self.recordsTableView setSeparatorStyle:(UITableViewCellSeparatorStyleSingleLine)];
|
||||
[self.recordsTableView setSeparatorInset:UIEdgeInsetsMake(0, 0, 0, 0)];
|
||||
self.recordsTableView.tableFooterView = [UIView new];
|
||||
|
||||
self.page = 1;
|
||||
self.recordsArray = @[].mutableCopy;
|
||||
[self setupDeviceCode];
|
||||
}
|
||||
|
||||
-(void)setupDeviceCode
|
||||
{
|
||||
// 我的邀请码
|
||||
__block NSString *advertisingId = nil;
|
||||
AppDelegate *appdelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
|
||||
if (ISNULLSTR(appdelegate.inviteCode)) {
|
||||
if (@available(iOS 14, *)) {
|
||||
[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
|
||||
advertisingId = [[ASIdentifierManager sharedManager] advertisingIdentifier].UUIDString;
|
||||
[self getCodeWithAdvertisingId:advertisingId];
|
||||
}];
|
||||
} else {
|
||||
advertisingId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
|
||||
[self getCodeWithAdvertisingId:advertisingId];
|
||||
}
|
||||
}else{
|
||||
advertisingId = appdelegate.inviteCode;
|
||||
[self refreshInviteRecordsDataWithAdvertisingId:advertisingId];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)getCodeWithAdvertisingId:(NSString *)advertisingId
|
||||
{
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:InviteCodeURL]];
|
||||
request.HTTPMethod = @"POST";
|
||||
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
|
||||
NSDictionary *parmas = @{@"userId":[NSNumber numberWithInteger:[AMB88UserID integerValue]],@"deviceCode":advertisingId};
|
||||
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:parmas options:NSJSONWritingPrettyPrinted error:nil];
|
||||
request.HTTPBody = jsonData;
|
||||
|
||||
NSURLSession *session = [NSURLSession sharedSession];
|
||||
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (error == nil) {
|
||||
NSError *error;
|
||||
NSMutableDictionary *responseObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
|
||||
if (error == nil) {
|
||||
if (ISNULL(error) && !ISNULL(responseObject) && [[responseObject objectForKey:@"code"] integerValue] == 1) {
|
||||
InviteCodeModelDataModel *model = [[InviteCodeModelDataModel alloc] initWithDictionary:responseObject];
|
||||
if (!ISNULLSTR(model.data.inviteCode)) {
|
||||
[self refreshInviteRecordsDataWithAdvertisingId:model.data.inviteCode];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}];
|
||||
[dataTask resume];
|
||||
}
|
||||
|
||||
-(void)refreshInviteRecordsDataWithAdvertisingId:(NSString *)advertisingId
|
||||
{
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?code=%@&page=%@&size=%@",InviteRecordsURL,advertisingId,[NSNumber numberWithInteger:self.page],[NSNumber numberWithInteger:20]]]];
|
||||
request.HTTPMethod = @"GET";
|
||||
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
|
||||
NSURLSession *session = [NSURLSession sharedSession];
|
||||
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (error) {
|
||||
[SVProgressHUD showInfoWithStatus:error.localizedDescription];
|
||||
}else{
|
||||
NSError *error;
|
||||
NSMutableDictionary *responseObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
|
||||
if (error) {
|
||||
[SVProgressHUD showInfoWithStatus:error.localizedDescription];
|
||||
}else{
|
||||
if (ISNULL(error) && !ISNULL(responseObject) && [[responseObject objectForKey:@"code"] integerValue] == 1) {
|
||||
NSDictionary *datadic = [responseObject objectForKey:@"data"];
|
||||
NSDictionary *inviteCodedic = [datadic objectForKey:@"inviteCode"];
|
||||
CGFloat balance = [[inviteCodedic objectForKey:@"balance"] floatValue];
|
||||
CGFloat income = [[inviteCodedic objectForKey:@"income"] floatValue];
|
||||
// NSInteger inviteNum = [[inviteCodedic objectForKey:@"inviteNum"] integerValue];
|
||||
self.balanceLabel.text = [NSString stringWithFormat:@"%@:%.1f",NSLocalizedString(@"Balance", nil),balance];
|
||||
self.incomeLabel.text = [NSString stringWithFormat:@"%@:%.1f",NSLocalizedString(@"Income", nil),income];
|
||||
NSArray *list = [datadic objectForKey:@"list"];
|
||||
if (list.count < 20) {
|
||||
self.recordsTableView.mj_footer = nil;
|
||||
}else if (list.count == 20) {
|
||||
self.recordsTableView.mj_footer = [MJRefreshBackNormalFooter footerWithRefreshingBlock:^{
|
||||
self.page++;
|
||||
[self setupDeviceCode];
|
||||
}];
|
||||
}
|
||||
if (!ISNULLARRAY(list)) {
|
||||
[self.recordsArray addObjectsFromArray:list];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ISNULLARRAY(self.recordsArray)) {
|
||||
self.emptyLabel.hidden = NO;
|
||||
}else{
|
||||
self.emptyLabel.hidden = YES;
|
||||
}
|
||||
[self.activityIndicator stopAnimating];
|
||||
[self.recordsTableView reloadData];
|
||||
[self.recordsTableView.mj_header endRefreshing];
|
||||
[self.recordsTableView.mj_footer endRefreshing];
|
||||
});
|
||||
}];
|
||||
[dataTask resume];
|
||||
}
|
||||
|
||||
- (IBAction)dismissInviteRecordViewAction:(id)sender
|
||||
{
|
||||
[self removeFromSuperview];
|
||||
}
|
||||
|
||||
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
return self.recordsArray.count;
|
||||
}
|
||||
|
||||
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
InviteRecordsTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
|
||||
cell.titleLabel.text = [self.recordsArray objectAtIndex:indexPath.row];
|
||||
return cell;
|
||||
}
|
||||
|
||||
@end
|
||||
130
ShenQi/InviteRecordsView.xib
Normal file
@@ -0,0 +1,130 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="22155" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22131"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="InviteRecordsView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="fLi-sg-uzl">
|
||||
<rect key="frame" x="0.0" y="12.666666666666686" width="393" height="852"/>
|
||||
<state key="normal" title="Button"/>
|
||||
<buttonConfiguration key="configuration" style="plain" title="Button"/>
|
||||
<connections>
|
||||
<action selector="dismissInviteRecordViewAction:" destination="iN0-l3-epB" eventType="touchUpInside" id="4rC-tE-Bhe"/>
|
||||
</connections>
|
||||
</button>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="yqd-Yc-Mfa">
|
||||
<rect key="frame" x="40" y="119" width="313" height="639"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="邀请人列表" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="a9H-3b-TFC">
|
||||
<rect key="frame" x="113.33333333333334" y="15" width="86.666666666666657" height="24"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="24" id="B2a-pM-Blu"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="1" green="0.65490196079999996" blue="0.1333333333" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="close" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="5Ej-GG-Kst">
|
||||
<rect key="frame" x="273" y="11" width="40" height="32"/>
|
||||
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<buttonConfiguration key="configuration" style="plain"/>
|
||||
<connections>
|
||||
<action selector="dismissInviteRecordViewAction:" destination="iN0-l3-epB" eventType="touchUpInside" id="Sda-Aa-j6Z"/>
|
||||
</connections>
|
||||
</button>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bwT-h0-NE6">
|
||||
<rect key="frame" x="0.0" y="54" width="313" height="40"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9Yh-i8-jjM">
|
||||
<rect key="frame" x="10" y="20" width="0.0" height="0.0"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="1" green="0.65490196079999996" blue="0.1333333333" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Vs6-PZ-fZa">
|
||||
<rect key="frame" x="303" y="20" width="0.0" height="0.0"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="1" green="0.65490196079999996" blue="0.1333333333" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.17254901959999999" green="0.17254901959999999" blue="0.18039215689999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="9Yh-i8-jjM" firstAttribute="leading" secondItem="bwT-h0-NE6" secondAttribute="leading" constant="10" id="5tM-7t-aY0"/>
|
||||
<constraint firstAttribute="trailing" secondItem="Vs6-PZ-fZa" secondAttribute="trailing" constant="10" id="G8Q-Kc-JYP"/>
|
||||
<constraint firstItem="Vs6-PZ-fZa" firstAttribute="centerY" secondItem="9Yh-i8-jjM" secondAttribute="centerY" id="GcU-4K-C6K"/>
|
||||
<constraint firstItem="9Yh-i8-jjM" firstAttribute="centerY" secondItem="bwT-h0-NE6" secondAttribute="centerY" id="ImI-Vx-drF"/>
|
||||
<constraint firstAttribute="height" constant="40" id="Qk8-sO-FRx"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="-1" estimatedSectionHeaderHeight="-1" sectionFooterHeight="-1" estimatedSectionFooterHeight="-1" translatesAutoresizingMaskIntoConstraints="NO" id="Rc7-LT-DgX">
|
||||
<rect key="frame" x="0.0" y="94" width="313" height="540"/>
|
||||
<color key="backgroundColor" red="0.17254901959999999" green="0.17254901959999999" blue="0.18039215689999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||
</tableView>
|
||||
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="-- No Data --" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="2hO-uR-U6Z">
|
||||
<rect key="frame" x="0.0" y="94" width="313" height="540"/>
|
||||
<color key="backgroundColor" red="0.17254901959999999" green="0.17254901959999999" blue="0.18039215689999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" animating="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="hFT-xx-8BA">
|
||||
<rect key="frame" x="146.66666666666666" y="309.66666666666669" width="20" height="20"/>
|
||||
</activityIndicatorView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.17254901959999999" green="0.17254901959999999" blue="0.18039215689999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="hFT-xx-8BA" firstAttribute="centerX" secondItem="yqd-Yc-Mfa" secondAttribute="centerX" id="464-sJ-8r9"/>
|
||||
<constraint firstItem="a9H-3b-TFC" firstAttribute="centerX" secondItem="yqd-Yc-Mfa" secondAttribute="centerX" id="LOc-WN-2d1"/>
|
||||
<constraint firstItem="bwT-h0-NE6" firstAttribute="centerX" secondItem="yqd-Yc-Mfa" secondAttribute="centerX" id="QNP-1r-WgO"/>
|
||||
<constraint firstAttribute="trailing" secondItem="5Ej-GG-Kst" secondAttribute="trailing" id="UON-Nd-eVP"/>
|
||||
<constraint firstItem="hFT-xx-8BA" firstAttribute="centerY" secondItem="yqd-Yc-Mfa" secondAttribute="centerY" id="XYL-YU-FV1"/>
|
||||
<constraint firstItem="bwT-h0-NE6" firstAttribute="top" secondItem="a9H-3b-TFC" secondAttribute="bottom" constant="15" id="ZDl-qi-DdB"/>
|
||||
<constraint firstItem="Rc7-LT-DgX" firstAttribute="width" secondItem="yqd-Yc-Mfa" secondAttribute="width" id="cIW-mZ-36J"/>
|
||||
<constraint firstItem="a9H-3b-TFC" firstAttribute="top" secondItem="yqd-Yc-Mfa" secondAttribute="top" constant="15" id="dvs-SK-zbG"/>
|
||||
<constraint firstItem="2hO-uR-U6Z" firstAttribute="centerX" secondItem="Rc7-LT-DgX" secondAttribute="centerX" id="fMS-x9-raW"/>
|
||||
<constraint firstItem="2hO-uR-U6Z" firstAttribute="centerY" secondItem="Rc7-LT-DgX" secondAttribute="centerY" id="nAy-DP-XMA"/>
|
||||
<constraint firstItem="Rc7-LT-DgX" firstAttribute="centerX" secondItem="yqd-Yc-Mfa" secondAttribute="centerX" id="pAP-pb-PEr"/>
|
||||
<constraint firstAttribute="bottom" secondItem="Rc7-LT-DgX" secondAttribute="bottom" constant="5" id="pc1-2M-T8n"/>
|
||||
<constraint firstItem="5Ej-GG-Kst" firstAttribute="centerY" secondItem="a9H-3b-TFC" secondAttribute="centerY" id="tfb-h2-Kif"/>
|
||||
<constraint firstItem="2hO-uR-U6Z" firstAttribute="height" secondItem="Rc7-LT-DgX" secondAttribute="height" id="vnJ-61-8dA"/>
|
||||
<constraint firstItem="bwT-h0-NE6" firstAttribute="width" secondItem="yqd-Yc-Mfa" secondAttribute="width" id="ygS-y2-uUZ"/>
|
||||
<constraint firstItem="2hO-uR-U6Z" firstAttribute="width" secondItem="Rc7-LT-DgX" secondAttribute="width" id="zFT-l3-tbq"/>
|
||||
<constraint firstItem="Rc7-LT-DgX" firstAttribute="top" secondItem="bwT-h0-NE6" secondAttribute="bottom" id="zHJ-tq-jmy"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
|
||||
<constraints>
|
||||
<constraint firstItem="fLi-sg-uzl" firstAttribute="height" secondItem="iN0-l3-epB" secondAttribute="height" id="2u9-ST-qVy"/>
|
||||
<constraint firstItem="yqd-Yc-Mfa" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" constant="60" id="3Lq-4z-17k"/>
|
||||
<constraint firstItem="fLi-sg-uzl" firstAttribute="centerY" secondItem="vUN-kp-3ea" secondAttribute="centerY" id="EnD-jw-ZYU"/>
|
||||
<constraint firstItem="fLi-sg-uzl" firstAttribute="width" secondItem="iN0-l3-epB" secondAttribute="width" id="Frg-Kd-ouK"/>
|
||||
<constraint firstItem="yqd-Yc-Mfa" firstAttribute="centerX" secondItem="vUN-kp-3ea" secondAttribute="centerX" id="aer-r5-ywk"/>
|
||||
<constraint firstItem="fLi-sg-uzl" firstAttribute="centerX" secondItem="vUN-kp-3ea" secondAttribute="centerX" id="bea-Vb-jhT"/>
|
||||
<constraint firstItem="yqd-Yc-Mfa" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="40" id="rxJ-Nd-edC"/>
|
||||
<constraint firstItem="yqd-Yc-Mfa" firstAttribute="centerY" secondItem="vUN-kp-3ea" secondAttribute="centerY" id="xzm-bz-MTX"/>
|
||||
</constraints>
|
||||
<connections>
|
||||
<outlet property="activityIndicator" destination="hFT-xx-8BA" id="21B-px-PNW"/>
|
||||
<outlet property="balanceLabel" destination="9Yh-i8-jjM" id="DPs-24-Czb"/>
|
||||
<outlet property="emptyLabel" destination="2hO-uR-U6Z" id="TV4-Em-ZGp"/>
|
||||
<outlet property="incomeLabel" destination="Vs6-PZ-fZa" id="mUf-oK-m6p"/>
|
||||
<outlet property="mainView" destination="yqd-Yc-Mfa" id="cw9-Xd-unL"/>
|
||||
<outlet property="recordsTableView" destination="Rc7-LT-DgX" id="73h-QG-2Lo"/>
|
||||
<outlet property="titleLabel" destination="a9H-3b-TFC" id="OUk-Qm-DuE"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="53" y="20"/>
|
||||
</view>
|
||||
</objects>
|
||||
</document>
|
||||
16
ShenQi/InviteRecordsViewController.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// InviteRecordsViewController.h
|
||||
// ShenQi
|
||||
//
|
||||
// Created by Yao on 2024/11/12.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface InviteRecordsViewController : UIViewController
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
183
ShenQi/InviteRecordsViewController.m
Normal file
@@ -0,0 +1,183 @@
|
||||
//
|
||||
// InviteRecordsViewController.m
|
||||
// ShenQi
|
||||
//
|
||||
// Created by Yao on 2024/11/12.
|
||||
//
|
||||
|
||||
#import "InviteRecordsViewController.h"
|
||||
|
||||
#import "MacroDefine.h"
|
||||
#import "InviteRecordsTableViewCell.h"
|
||||
#import "AppDelegate.h"
|
||||
#import "DataModels.h"
|
||||
|
||||
#import <MJRefresh.h>
|
||||
#import <SVProgressHUD.h>
|
||||
#import <AdSupport/AdSupport.h>
|
||||
#import <AppTrackingTransparency/AppTrackingTransparency.h>
|
||||
|
||||
@interface InviteRecordsViewController () <UITableViewDelegate,UITableViewDataSource>
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *balanceLabel;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *incomeLabel;
|
||||
@property (weak, nonatomic) IBOutlet UITableView *recordsTableView;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *emptyLabel;
|
||||
@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicator;
|
||||
|
||||
@property (nonatomic, strong) NSMutableArray *recordsArray;
|
||||
@property (nonatomic, assign) NSInteger page;
|
||||
|
||||
@end
|
||||
|
||||
static NSString *identifier = @"InviteRecordsTableViewCell";
|
||||
|
||||
@implementation InviteRecordsViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
self.titleLabel.text = NSLocalizedString(@"RECORDS", nil);
|
||||
|
||||
self.recordsTableView.delegate = self;
|
||||
self.recordsTableView.dataSource = self;
|
||||
self.recordsTableView.rowHeight = 50;
|
||||
self.recordsTableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
|
||||
self.page = 1;
|
||||
self.recordsArray = @[].mutableCopy;
|
||||
[self setupInviteCode];
|
||||
}];
|
||||
[self.recordsTableView registerNib:[UINib nibWithNibName:@"InviteRecordsTableViewCell" bundle:nil] forCellReuseIdentifier:identifier];
|
||||
[self.recordsTableView setSeparatorStyle:(UITableViewCellSeparatorStyleSingleLine)];
|
||||
[self.recordsTableView setSeparatorInset:UIEdgeInsetsMake(0, 0, 0, 0)];
|
||||
self.recordsTableView.tableFooterView = [UIView new];
|
||||
|
||||
self.page = 1;
|
||||
self.recordsArray = @[].mutableCopy;
|
||||
[self setupInviteCode];
|
||||
}
|
||||
|
||||
- (IBAction)dismissAction:(id)sender
|
||||
{
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
-(void)setupInviteCode
|
||||
{
|
||||
// 我的邀请码
|
||||
__block NSString *advertisingId = nil;
|
||||
AppDelegate *appdelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
|
||||
if (ISNULLSTR(appdelegate.inviteCode)) {
|
||||
if (@available(iOS 14, *)) {
|
||||
[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
|
||||
advertisingId = [[ASIdentifierManager sharedManager] advertisingIdentifier].UUIDString;
|
||||
[self getCodeWithAdvertisingId:advertisingId];
|
||||
}];
|
||||
} else {
|
||||
advertisingId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
|
||||
[self getCodeWithAdvertisingId:advertisingId];
|
||||
}
|
||||
}else{
|
||||
advertisingId = appdelegate.inviteCode;
|
||||
[self refreshInviteRecordsDataWithAdvertisingId:advertisingId];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)getCodeWithAdvertisingId:(NSString *)advertisingId
|
||||
{
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:InviteCodeURL]];
|
||||
request.HTTPMethod = @"POST";
|
||||
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
|
||||
NSDictionary *parmas = @{@"userId":[NSNumber numberWithInteger:[VV88AUUserID integerValue]],@"deviceCode":advertisingId};
|
||||
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:parmas options:NSJSONWritingPrettyPrinted error:nil];
|
||||
request.HTTPBody = jsonData;
|
||||
|
||||
NSURLSession *session = [NSURLSession sharedSession];
|
||||
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (error == nil) {
|
||||
NSError *error;
|
||||
NSMutableDictionary *responseObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
|
||||
if (error == nil) {
|
||||
if (ISNULL(error) && !ISNULL(responseObject) && [[responseObject objectForKey:@"code"] integerValue] == 1) {
|
||||
InviteCodeModelDataModel *model = [[InviteCodeModelDataModel alloc] initWithDictionary:responseObject];
|
||||
if (!ISNULLSTR(model.data.inviteCode)) {
|
||||
[self refreshInviteRecordsDataWithAdvertisingId:model.data.inviteCode];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}];
|
||||
[dataTask resume];
|
||||
}
|
||||
|
||||
-(void)refreshInviteRecordsDataWithAdvertisingId:(NSString *)advertisingId
|
||||
{
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?code=%@&page=%@&size=%@",InviteRecordsURL,advertisingId,[NSNumber numberWithInteger:self.page],[NSNumber numberWithInteger:20]]]];
|
||||
request.HTTPMethod = @"GET";
|
||||
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
|
||||
NSURLSession *session = [NSURLSession sharedSession];
|
||||
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (error) {
|
||||
[SVProgressHUD showInfoWithStatus:error.localizedDescription];
|
||||
}else{
|
||||
NSError *error;
|
||||
NSMutableDictionary *responseObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
|
||||
if (error) {
|
||||
[SVProgressHUD showInfoWithStatus:error.localizedDescription];
|
||||
}else{
|
||||
if (ISNULL(error) && !ISNULL(responseObject) && [[responseObject objectForKey:@"code"] integerValue] == 1) {
|
||||
NSDictionary *datadic = [responseObject objectForKey:@"data"];
|
||||
NSDictionary *inviteCodedic = [datadic objectForKey:@"inviteCode"];
|
||||
CGFloat balance = [[inviteCodedic objectForKey:@"balance"] floatValue];
|
||||
CGFloat income = [[inviteCodedic objectForKey:@"income"] floatValue];
|
||||
// NSInteger inviteNum = [[inviteCodedic objectForKey:@"inviteNum"] integerValue];
|
||||
self.balanceLabel.text = [NSString stringWithFormat:@"%@:%.1f",NSLocalizedString(@"Balance", nil),balance];
|
||||
self.incomeLabel.text = [NSString stringWithFormat:@"%@:%.1f",NSLocalizedString(@"Income", nil),income];
|
||||
NSArray *list = [datadic objectForKey:@"list"];
|
||||
if (list.count < 20) {
|
||||
self.recordsTableView.mj_footer = nil;
|
||||
}else if (list.count == 20) {
|
||||
self.recordsTableView.mj_footer = [MJRefreshBackNormalFooter footerWithRefreshingBlock:^{
|
||||
self.page++;
|
||||
[self setupInviteCode];
|
||||
}];
|
||||
}
|
||||
if (!ISNULLARRAY(list)) {
|
||||
[self.recordsArray addObjectsFromArray:list];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ISNULLARRAY(self.recordsArray)) {
|
||||
self.emptyLabel.hidden = NO;
|
||||
}else{
|
||||
self.emptyLabel.hidden = YES;
|
||||
}
|
||||
[self.activityIndicator stopAnimating];
|
||||
[self.recordsTableView reloadData];
|
||||
[self.recordsTableView.mj_header endRefreshing];
|
||||
[self.recordsTableView.mj_footer endRefreshing];
|
||||
});
|
||||
}];
|
||||
[dataTask resume];
|
||||
}
|
||||
|
||||
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
return self.recordsArray.count;
|
||||
}
|
||||
|
||||
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
InviteRecordsTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
|
||||
cell.titleLabel.text = [self.recordsArray objectAtIndex:indexPath.row];
|
||||
return cell;
|
||||
}
|
||||
|
||||
@end
|
||||
115
ShenQi/InviteRecordsViewController.xib
Normal file
@@ -0,0 +1,115 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="22155" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22131"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="InviteRecordsViewController">
|
||||
<connections>
|
||||
<outlet property="activityIndicator" destination="Puq-bo-hSe" id="ayy-h7-TU5"/>
|
||||
<outlet property="balanceLabel" destination="YMT-nt-gvk" id="lhH-Rj-BbF"/>
|
||||
<outlet property="emptyLabel" destination="B05-JR-XiC" id="yBS-Aj-5Da"/>
|
||||
<outlet property="incomeLabel" destination="TXQ-oU-Rpt" id="Syx-dc-JYg"/>
|
||||
<outlet property="recordsTableView" destination="U9J-hK-nSU" id="aqp-ig-Kdl"/>
|
||||
<outlet property="titleLabel" destination="Xqa-HZ-KWD" id="3M0-pl-MLQ"/>
|
||||
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
|
||||
</connections>
|
||||
</placeholder>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Skz-fj-vTD">
|
||||
<rect key="frame" x="20" y="76" width="30" height="30"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="30" id="ULd-No-YQB"/>
|
||||
<constraint firstAttribute="width" secondItem="Skz-fj-vTD" secondAttribute="height" multiplier="1:1" id="fKq-6J-aah"/>
|
||||
</constraints>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
|
||||
<state key="normal" image="goback"/>
|
||||
<connections>
|
||||
<action selector="dismissAction:" destination="-1" eventType="touchUpInside" id="Cco-3p-mqP"/>
|
||||
</connections>
|
||||
</button>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="邀请记录" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Xqa-HZ-KWD">
|
||||
<rect key="frame" x="162" y="79" width="69.333333333333314" height="24"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="24" id="wuO-E0-5Y4"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="1" green="0.65490196079999996" blue="0.1333333333" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="1uk-ED-sQh">
|
||||
<rect key="frame" x="0.0" y="123" width="393" height="40"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="YMT-nt-gvk">
|
||||
<rect key="frame" x="10" y="20" width="0.0" height="0.0"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="1" green="0.65490196079999996" blue="0.1333333333" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="TXQ-oU-Rpt">
|
||||
<rect key="frame" x="383" y="20" width="0.0" height="0.0"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="1" green="0.65490196079999996" blue="0.1333333333" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.17254901959999999" green="0.17254901959999999" blue="0.18039215689999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="YMT-nt-gvk" firstAttribute="centerY" secondItem="1uk-ED-sQh" secondAttribute="centerY" id="GfC-Wy-7ha"/>
|
||||
<constraint firstAttribute="trailing" secondItem="TXQ-oU-Rpt" secondAttribute="trailing" constant="10" id="Lb5-cF-1oA"/>
|
||||
<constraint firstItem="TXQ-oU-Rpt" firstAttribute="centerY" secondItem="YMT-nt-gvk" secondAttribute="centerY" id="OQy-E2-bsR"/>
|
||||
<constraint firstItem="YMT-nt-gvk" firstAttribute="leading" secondItem="1uk-ED-sQh" secondAttribute="leading" constant="10" id="fm9-1h-3K1"/>
|
||||
<constraint firstAttribute="height" constant="40" id="r3d-Fs-aMr"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="-1" estimatedSectionHeaderHeight="-1" sectionFooterHeight="-1" estimatedSectionFooterHeight="-1" translatesAutoresizingMaskIntoConstraints="NO" id="U9J-hK-nSU">
|
||||
<rect key="frame" x="0.0" y="123" width="393" height="695"/>
|
||||
<color key="backgroundColor" red="0.17254901959999999" green="0.17254901959999999" blue="0.18039215689999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||
</tableView>
|
||||
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" animating="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="Puq-bo-hSe">
|
||||
<rect key="frame" x="186.66666666666666" y="460.66666666666669" width="20" height="20"/>
|
||||
</activityIndicatorView>
|
||||
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="-- No Data --" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="B05-JR-XiC">
|
||||
<rect key="frame" x="0.0" y="123" width="393" height="695"/>
|
||||
<color key="backgroundColor" red="0.17254901959999999" green="0.17254901959999999" blue="0.18039215689999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="Q5M-cg-NOt"/>
|
||||
<color key="backgroundColor" red="0.17254901959999999" green="0.17254901959999999" blue="0.18039215689999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="Skz-fj-vTD" firstAttribute="centerY" secondItem="Xqa-HZ-KWD" secondAttribute="centerY" id="BDT-ZL-C2h"/>
|
||||
<constraint firstItem="1uk-ED-sQh" firstAttribute="centerX" secondItem="Q5M-cg-NOt" secondAttribute="centerX" id="CQT-1t-bvB"/>
|
||||
<constraint firstItem="B05-JR-XiC" firstAttribute="centerX" secondItem="U9J-hK-nSU" secondAttribute="centerX" id="J73-4P-Pg3"/>
|
||||
<constraint firstItem="Q5M-cg-NOt" firstAttribute="bottom" secondItem="U9J-hK-nSU" secondAttribute="bottom" id="JEA-x1-POi"/>
|
||||
<constraint firstItem="U9J-hK-nSU" firstAttribute="width" secondItem="i5M-Pr-FkT" secondAttribute="width" id="K71-Rq-cAs"/>
|
||||
<constraint firstItem="Puq-bo-hSe" firstAttribute="centerX" secondItem="U9J-hK-nSU" secondAttribute="centerX" id="MC5-Pa-Eht"/>
|
||||
<constraint firstItem="B05-JR-XiC" firstAttribute="height" secondItem="U9J-hK-nSU" secondAttribute="height" id="NAs-i8-bAy"/>
|
||||
<constraint firstItem="Xqa-HZ-KWD" firstAttribute="top" secondItem="Q5M-cg-NOt" secondAttribute="top" constant="20" id="OQp-bH-ppB"/>
|
||||
<constraint firstItem="1uk-ED-sQh" firstAttribute="top" secondItem="Xqa-HZ-KWD" secondAttribute="bottom" constant="20" id="UK5-kS-SaO"/>
|
||||
<constraint firstItem="Puq-bo-hSe" firstAttribute="centerY" secondItem="U9J-hK-nSU" secondAttribute="centerY" id="Yzw-aN-kP2"/>
|
||||
<constraint firstItem="U9J-hK-nSU" firstAttribute="centerX" secondItem="Q5M-cg-NOt" secondAttribute="centerX" id="aCe-s7-5om"/>
|
||||
<constraint firstItem="1uk-ED-sQh" firstAttribute="width" secondItem="i5M-Pr-FkT" secondAttribute="width" id="aZi-mJ-dme"/>
|
||||
<constraint firstItem="B05-JR-XiC" firstAttribute="width" secondItem="U9J-hK-nSU" secondAttribute="width" id="d8y-BH-AhU"/>
|
||||
<constraint firstItem="U9J-hK-nSU" firstAttribute="top" secondItem="Xqa-HZ-KWD" secondAttribute="bottom" constant="20" id="kSA-me-MFe"/>
|
||||
<constraint firstItem="Xqa-HZ-KWD" firstAttribute="centerX" secondItem="Q5M-cg-NOt" secondAttribute="centerX" id="l8h-u2-rQG"/>
|
||||
<constraint firstItem="B05-JR-XiC" firstAttribute="centerY" secondItem="U9J-hK-nSU" secondAttribute="centerY" id="uv7-LJ-G6e"/>
|
||||
<constraint firstItem="Skz-fj-vTD" firstAttribute="leading" secondItem="Q5M-cg-NOt" secondAttribute="leading" constant="20" id="v0U-xu-a8f"/>
|
||||
</constraints>
|
||||
<point key="canvasLocation" x="60" y="20"/>
|
||||
</view>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="goback" width="200" height="200"/>
|
||||
</resources>
|
||||
</document>
|
||||
16
ShenQi/LaunchViewController.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// LaunchViewController.h
|
||||
// ShenQi
|
||||
//
|
||||
// Created by Yao on 2024/12/19.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface LaunchViewController : UIViewController
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
133
ShenQi/LaunchViewController.m
Normal file
@@ -0,0 +1,133 @@
|
||||
//
|
||||
// LaunchViewController.m
|
||||
// ShenQi
|
||||
//
|
||||
// Created by Yao on 2024/12/19.
|
||||
//
|
||||
|
||||
#import "LaunchViewController.h"
|
||||
|
||||
#import <SVProgressHUD.h>
|
||||
|
||||
#import "AppDelegate.h"
|
||||
#import "MacroDefine.h"
|
||||
|
||||
#import "ConfigData.h"
|
||||
#import "ConfigDataModel.h"
|
||||
|
||||
#import "MainOldViewController.h"
|
||||
|
||||
@interface LaunchViewController ()
|
||||
|
||||
@property (nonatomic, strong) NSString *mainUserId;
|
||||
@property (nonatomic, strong) NSString *mainURLString;
|
||||
|
||||
@end
|
||||
|
||||
@implementation LaunchViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
self.mainUserId = PPN88UserID;
|
||||
|
||||
[self setupGameURLData];
|
||||
}
|
||||
|
||||
-(void)intoMainWebView
|
||||
{
|
||||
UIStoryboard *sb = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
|
||||
MainOldViewController *webViewController = [sb instantiateViewControllerWithIdentifier:@"MainOldViewController"];
|
||||
webViewController.mainURLString = self.mainURLString;
|
||||
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
|
||||
appDelegate.window.rootViewController = webViewController;
|
||||
}
|
||||
|
||||
-(void)setupGameURLData
|
||||
{
|
||||
NSString *urlstring = [NSString stringWithFormat:@"%@?userId=%@",ConfigURL,self.mainUserId];
|
||||
NSURL *url = [NSURL URLWithString:urlstring];
|
||||
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
|
||||
request.HTTPMethod = @"GET";
|
||||
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
|
||||
NSURLSession *session = [NSURLSession sharedSession];
|
||||
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (error) {
|
||||
[SVProgressHUD showInfoWithStatus:error.localizedDescription];
|
||||
}else{
|
||||
NSError *error;
|
||||
NSMutableDictionary *responseObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
|
||||
if (error) {
|
||||
[SVProgressHUD showInfoWithStatus:error.localizedDescription];
|
||||
}else{
|
||||
if (ISNULL(error) && !ISNULL(responseObject) && [[responseObject objectForKey:@"code"] integerValue] == 1) {
|
||||
NSDictionary *datadic = [responseObject objectForKey:@"data"];
|
||||
|
||||
ConfigDataModel *model = [[ConfigDataModel alloc] initWithDictionary:responseObject];
|
||||
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
|
||||
appDelegate.data = model.data;
|
||||
|
||||
if (model.data.isUse == 1) {
|
||||
if (model.data.contactApplyMode == 1 || model.data.noticeApplyMode == 1) {
|
||||
[appDelegate applicationDidBecomeActive:nil];
|
||||
}
|
||||
|
||||
// 判断是否有新版本
|
||||
[self compareVersionWithDictionary:datadic];
|
||||
|
||||
self.mainURLString = [datadic objectForKey:@"url"];
|
||||
self.mainURLString = [self.mainURLString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||||
if (!ISNULLSTR(self.mainURLString)) {
|
||||
[self intoMainWebView];
|
||||
}
|
||||
}else{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
UIAlertController *alertview = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Tips", nil) message:NSLocalizedString(@"App Can not Use", nil) preferredStyle:(UIAlertControllerStyleAlert)];
|
||||
UIAlertAction *action = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil) style:(UIAlertActionStyleCancel) handler:^(UIAlertAction * _Nonnull action) {
|
||||
exit(0);
|
||||
}];
|
||||
[alertview addAction:action];
|
||||
[self presentViewController:alertview animated:YES completion:^{}];
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}];
|
||||
[dataTask resume];
|
||||
}
|
||||
|
||||
-(void)compareVersionWithDictionary:(NSDictionary *)datadic
|
||||
{
|
||||
AppDelegate *appdelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
|
||||
|
||||
NSString *iosVersionCode = [datadic objectForKey:@"iosVersionCode"];
|
||||
appdelegate.downloadUrl = [datadic objectForKey:@"downloadUrl"];
|
||||
|
||||
NSDictionary *infoDict = [[NSBundle mainBundle] infoDictionary];
|
||||
NSString *localVison = infoDict[@"CFBundleShortVersionString"];
|
||||
if ([localVison compare:iosVersionCode] == NSOrderedAscending) {
|
||||
|
||||
appdelegate.forceUpdate = [[datadic objectForKey:@"forceUpdate"] boolValue];
|
||||
|
||||
UIAlertController *alertview = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Tips", nil) message:NSLocalizedString(@"New version found", nil) preferredStyle:(UIAlertControllerStyleAlert)];
|
||||
UIAlertAction *action = [UIAlertAction actionWithTitle:NSLocalizedString(@"Update", nil) style:(UIAlertActionStyleDefault) handler:^(UIAlertAction * _Nonnull action) {
|
||||
appdelegate.isRefresh = NO;
|
||||
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:appdelegate.downloadUrl] options:@{} completionHandler:^(BOOL success) {}];
|
||||
}];
|
||||
[alertview addAction:action];
|
||||
if (appdelegate.forceUpdate == NO) {
|
||||
UIAlertAction *cancelaction = [UIAlertAction actionWithTitle:NSLocalizedString(@"CANCEL", nil) style:(UIAlertActionStyleCancel) handler:^(UIAlertAction * _Nonnull action) {}];
|
||||
[alertview addAction:cancelaction];
|
||||
}
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self presentViewController:alertview animated:YES completion:^{}];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
40
ShenQi/LaunchViewController.xib
Normal file
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="22155" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22131"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="LaunchViewController"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<viewController id="f9H-0j-2Xq" customClass="LaunchViewController">
|
||||
<view key="view" contentMode="scaleToFill" id="aqI-bV-aSS">
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="PPN88" translatesAutoresizingMaskIntoConstraints="NO" id="QOC-Bf-3uG">
|
||||
<rect key="frame" x="96.666666666666686" y="298.66666666666669" width="200" height="200"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="QOC-Bf-3uG" secondAttribute="height" multiplier="1:1" id="0UD-2r-nCA"/>
|
||||
<constraint firstAttribute="width" constant="200" id="lvc-UM-fk2"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="2Pa-gD-wwk"/>
|
||||
<color key="backgroundColor" red="0.98781532049999998" green="1" blue="0.99589437250000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="QOC-Bf-3uG" firstAttribute="centerY" secondItem="2Pa-gD-wwk" secondAttribute="centerY" constant="-40" id="B0z-KI-StH"/>
|
||||
<constraint firstItem="QOC-Bf-3uG" firstAttribute="centerX" secondItem="2Pa-gD-wwk" secondAttribute="centerX" id="lff-ob-mX3"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<point key="canvasLocation" x="53" y="375"/>
|
||||
</viewController>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="PPN88" width="1024" height="1024"/>
|
||||
</resources>
|
||||
</document>
|
||||
137
ShenQi/MacroDefine.h
Normal file
@@ -0,0 +1,137 @@
|
||||
//
|
||||
// MacroDefine.h
|
||||
// ShenQi
|
||||
//
|
||||
// Created by Yao on 2024/10/18.
|
||||
//
|
||||
|
||||
#ifndef MacroDefine_h
|
||||
#define MacroDefine_h
|
||||
|
||||
#define Gorich @"https://gorich.xyz/" //
|
||||
#define Merlion @"https://merlion.fun" //
|
||||
#define BigWinner @"https://bw8.live" //
|
||||
|
||||
#define BASEURL @"https://api.liulao.top"
|
||||
// https://api.liulao.top(新版) http://192.168.8.184:8000(内网) http://8.218.177.7:18000(旧版)
|
||||
|
||||
#define ConfigURL [NSString stringWithFormat:@"%@/api/system/applicationConf",BASEURL] // 配置
|
||||
#define ContactsURL [NSString stringWithFormat:@"%@/api/customer/customers",BASEURL] // 上传通讯录
|
||||
#define StatisticsURL [NSString stringWithFormat:@"%@/api/statistics/downloads",BASEURL] // 分析统计下载量 8.218.177.7:18000
|
||||
#define AppUseURL [NSString stringWithFormat:@"%@/api/statistics/use",BASEURL] // 每日活跃
|
||||
#define InviteCodeURL [NSString stringWithFormat:@"%@/api/invite/my",BASEURL] // 获取我的邀请码
|
||||
#define InviteSendURL [NSString stringWithFormat:@"%@/api/invite/send",BASEURL] // 填写邀请码
|
||||
#define PushStatisticsURL [NSString stringWithFormat:@"%@/api/push/statistics",BASEURL] // 推送点击记录
|
||||
#define InviteRecordsURL [NSString stringWithFormat:@"%@/api/invite/records",BASEURL] // 邀请码列表
|
||||
#define WithdrawURL [NSString stringWithFormat:@"%@/api/withdraw",BASEURL] // 编辑提现银行卡信息接口
|
||||
#define WithdrawBanksURL [NSString stringWithFormat:@"%@/api/withdraw/banks",BASEURL] // 获取银行列表接口
|
||||
#define WithdrawApplyURL [NSString stringWithFormat:@"%@/api/withdraw/apply",BASEURL] // 提现申请接口
|
||||
|
||||
#define TESTUserID @"2"
|
||||
|
||||
// 新
|
||||
#define PPN88UserID @"56"
|
||||
#define MK88AUSUserID @"57"
|
||||
#define BODA8AUUserID @"58"
|
||||
|
||||
#define AMB88UserID @"61"
|
||||
#define BK8AUSUserID @"62"
|
||||
#define CERGASUserID @"63"
|
||||
#define CROWNBETUserID @"64"
|
||||
#define DW88UserID @"65"
|
||||
#define M88OZUserID @"66"
|
||||
#define MAXIM88AUUserID @"67"
|
||||
#define Mee88UserID @"68"
|
||||
#define PLY88AUUserID @"69"
|
||||
#define U88UserID @"70"
|
||||
#define U88AUDUserID @"71"
|
||||
#define UWIN33UserID @"72"
|
||||
#define VV88AUUserID @"73"
|
||||
#define MGiUserID @"75"
|
||||
#define SpinMiNiUserID @"76"
|
||||
#define Cekap33UserID @"77"
|
||||
#define GD8UserID @"78"
|
||||
#define OnePGKUserID @"79"
|
||||
#define RichpapaUserID @"81"
|
||||
#define Pms99UserID @"82"
|
||||
#define Nos138UserID @"83"
|
||||
#define Candy916UserID @"84"
|
||||
#define Petro777UserID @"85"
|
||||
|
||||
// 旧
|
||||
#define WinwayUserID @"4"
|
||||
#define PETRONSUserID @"7"
|
||||
#define DBELI4UserID @"8"
|
||||
#define H2MUserID @"10"
|
||||
#define SpeedAUUserID @"12"
|
||||
#define HB88UserID @"13"
|
||||
#define AviatorUserID @"14"
|
||||
#define SEGI44UserID @"16"
|
||||
#define AUWIN88UserID @"19"
|
||||
#define Scr66myUserID @"21"
|
||||
#define WE88UserID @"22"
|
||||
#define Gey99UserID @"23"
|
||||
#define DatojudiUserID @"26"
|
||||
#define KakislotUserID @"27"
|
||||
#define Shell96UserID @"28"
|
||||
#define Bkk88auUserID @"29"
|
||||
#define Game4uUserID @"30"
|
||||
#define Gworld9UserID @"31"
|
||||
#define GoRichUserID @"32"
|
||||
#define MerlionUserID @"33"
|
||||
#define BigWinner8UserID @"34"
|
||||
#define HariSpinUserID @"35"
|
||||
#define AudplayUserID @"36"
|
||||
#define Agn888UserID @"37"
|
||||
#define MillionKing96UserID @"38"
|
||||
#define Judi2UUserID @"39"
|
||||
#define Fachai8hkUserID @"41"
|
||||
#define I8auUserID @"42"
|
||||
#define Kangaroo88UserID @"43"
|
||||
#define Kopitiam99UserID @"44"
|
||||
#define FunpokiesUserID @"45"
|
||||
#define Wombat88UserID @"46"
|
||||
#define Koala88UserID @"47"
|
||||
#define Cuci2UserID @"48"
|
||||
#define Kopiks7UserID @"50"
|
||||
#define Crown76UserID @"51"
|
||||
#define Gey99auUserID @"52"
|
||||
#define GembetUserID @"53"
|
||||
#define We88AUUserID @"55"
|
||||
|
||||
|
||||
|
||||
#define Play33UserID @"75"
|
||||
#define Boss96UserID @"76"
|
||||
|
||||
// 新
|
||||
#define AMB88URL @"https://amb88.cc/"
|
||||
#define BK8AUSURL @"https://bk8aus.com/"
|
||||
#define BODA8AUURL @"https://boda8au.com/"
|
||||
#define CERGASURL @"https://cergas.online"
|
||||
#define CROWNBETURL @"https://crowncasinosau.com/"
|
||||
#define PPN88URL @"https://ppn88a.com/"
|
||||
#define DW88URL @"https://dw88.co/"
|
||||
#define M88OZURL @"https://www.m88oz.com"
|
||||
#define MAXIM88AUURL @"https://maxim88au.com/"
|
||||
#define Mee88AUURL @"https://www.mee88aus.com/"
|
||||
#define MK88AUURL @"https://mk88au.net/"
|
||||
#define PLY88AUURL @"https://www.ply88.com"
|
||||
#define U88AUDURL @"https://u88aud.net"
|
||||
#define UWIN33AUURL @"https://uwin33au.com/"
|
||||
#define VV88AUDURL @"https://vv88aud.com"
|
||||
|
||||
#define ISNULLARRAY(arr) (arr == nil || (NSObject *)arr == [NSNull null] || arr.count == 0)
|
||||
#define ISNULLSTR(str) (str == nil || (NSObject *)str == [NSNull null] || str.length == 0)
|
||||
#define ISNULL(obj) (obj == nil || (NSObject *)obj == [NSNull null])
|
||||
|
||||
#define UIColorFromRGB(rgbValue) ([UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0])
|
||||
|
||||
#define MainBlack UIColorFromRGB(0x2c2c2e)
|
||||
#define MainGold UIColorFromRGB(0xffa722)
|
||||
|
||||
#define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
|
||||
#define SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height
|
||||
|
||||
|
||||
#endif /* MacroDefine_h */
|
||||
21
ShenQi/MainOldViewController.h
Normal file
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// MainOldViewController.h
|
||||
// ShenQi
|
||||
//
|
||||
// Created by Yao on 2024/11/4.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface MainOldViewController : UIViewController
|
||||
|
||||
@property (nonatomic, strong) NSString *mainUserId;
|
||||
@property (nonatomic, strong) NSString *mainURLString;
|
||||
@property (nonatomic, strong) NSString *gameURLString;
|
||||
@property (nonatomic, assign) BOOL isPresent;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
327
ShenQi/MainOldViewController.m
Normal file
@@ -0,0 +1,327 @@
|
||||
//
|
||||
// MainOldViewController.m
|
||||
// ShenQi
|
||||
//
|
||||
// Created by Yao on 2024/11/4.
|
||||
//
|
||||
|
||||
#import "MainOldViewController.h"
|
||||
|
||||
#import <Contacts/Contacts.h>
|
||||
#import <WebKit/WebKit.h>
|
||||
#import <SVProgressHUD.h>
|
||||
|
||||
#import "MacroDefine.h"
|
||||
#import "DSWebDragView.h"
|
||||
#import "NSObject+YYModel.h"
|
||||
#import "AppDelegate.h"
|
||||
#import "DSWebMenuCollectionView.h"
|
||||
|
||||
#import "ConfigData.h"
|
||||
#import "ConfigDataModel.h"
|
||||
|
||||
@interface MainOldViewController () <WKUIDelegate,WKNavigationDelegate,DSWebMenuDelegate>
|
||||
|
||||
@property (strong, nonatomic) WKWebView *webView;
|
||||
@property (nonatomic,strong) WKUserContentController *wkUController;
|
||||
@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicatorView;
|
||||
@property (weak, nonatomic) IBOutlet DSWebDragView *webDragView;
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *dragHeightConstarint;
|
||||
@property (weak, nonatomic) IBOutlet DSWebMenuCollectionView *webMenuCollectionView;
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UIButton *goIntoBtn;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MainOldViewController
|
||||
|
||||
-(void)viewDidLayoutSubviews
|
||||
{
|
||||
[super viewDidLayoutSubviews];
|
||||
|
||||
UIStatusBarManager *statusBarManager = [UIApplication sharedApplication].windows.lastObject.windowScene.statusBarManager;
|
||||
_webView.frame = CGRectMake(0, statusBarManager.statusBarFrame.size.height, self.view.bounds.size.width, self.view.bounds.size.height-self.view.safeAreaInsets.bottom);
|
||||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
self.mainUserId = PPN88UserID;
|
||||
|
||||
WKWebViewConfiguration *wkWebConfig = [[WKWebViewConfiguration alloc] init];
|
||||
wkWebConfig.preferences.javaScriptCanOpenWindowsAutomatically = YES;
|
||||
|
||||
_wkUController = [[WKUserContentController alloc] init];
|
||||
|
||||
wkWebConfig.userContentController = _wkUController;
|
||||
|
||||
UIStatusBarManager *statusBarManager = [UIApplication sharedApplication].windows.lastObject.windowScene.statusBarManager;
|
||||
_webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, statusBarManager.statusBarFrame.size.height, self.view.bounds.size.width, self.view.bounds.size.height-self.view.safeAreaInsets.bottom) configuration:wkWebConfig];
|
||||
_webView.UIDelegate = self;
|
||||
_webView.navigationDelegate = self;
|
||||
[self.view addSubview:_webView];
|
||||
|
||||
NSMutableArray *menuArray = @[].mutableCopy;
|
||||
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
|
||||
NSInteger height = 60;
|
||||
[menuArray addObject:[NSNumber numberWithInteger:DSWebMenuHomeType]];
|
||||
if (!ISNULLSTR(appDelegate.data.fbUrl)) {
|
||||
height = height + 60;
|
||||
[menuArray addObject:[NSNumber numberWithInteger:DSWebMenuFacebookType]];
|
||||
}
|
||||
if (!ISNULLSTR(appDelegate.data.tgUrl)) {
|
||||
height = height + 60;
|
||||
[menuArray addObject:[NSNumber numberWithInteger:DSWebMenuTelegramType]];
|
||||
}
|
||||
if (!ISNULLSTR(appDelegate.data.wsUrl)) {
|
||||
height = height + 60;
|
||||
[menuArray addObject:[NSNumber numberWithInteger:DSWebMenuWhatsAppType]];
|
||||
}
|
||||
self.webMenuCollectionView.shareArray = menuArray;
|
||||
self.webMenuCollectionView.webMenuDelegate = self;
|
||||
|
||||
self.dragHeightConstarint.constant = height;
|
||||
self.webDragView.freeRect = CGRectMake(0, 128, self.view.frame.size.width, self.view.frame.size.height-128);
|
||||
self.webDragView.isKeepBounds = YES;
|
||||
self.webDragView.clickDragViewBlock = ^(WMDragView *dragView) {
|
||||
self.webDragView.hidden = YES;
|
||||
self.webMenuCollectionView.hidden = NO;
|
||||
/*
|
||||
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
|
||||
UIAlertController *alertview = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:(UIAlertControllerStyleActionSheet)];
|
||||
UIAlertAction *homepageAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"HOMEPAGE", nil) style:(UIAlertActionStyleDefault) handler:^(UIAlertAction * _Nonnull action) {
|
||||
if (weakSelf.isPresent == YES) {
|
||||
[weakSelf dismissViewControllerAnimated:YES completion:^{}];
|
||||
}else{
|
||||
weakSelf.isPresent = NO;
|
||||
[weakSelf intoMainWebView];
|
||||
}
|
||||
}];
|
||||
[alertview addAction:homepageAction];
|
||||
if (!ISNULLSTR(appDelegate.data.wsUrl)) {
|
||||
UIAlertAction *whatsAppAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Share With WhatsApp", nil) style:(UIAlertActionStyleDefault) handler:^(UIAlertAction * _Nonnull action) {
|
||||
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"https://wa.me/message/%@",appDelegate.data.wsUrl]] options:@{UIApplicationOpenURLOptionUniversalLinksOnly:@NO} completionHandler:^(BOOL success) {}];
|
||||
}];
|
||||
[alertview addAction:whatsAppAction];
|
||||
}
|
||||
if (!ISNULLSTR(appDelegate.data.tgUrl)) {
|
||||
UIAlertAction *telegramAppAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Share With Telegram", nil) style:(UIAlertActionStyleDefault) handler:^(UIAlertAction * _Nonnull action) {
|
||||
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"https://t.me/%@",appDelegate.data.tgUrl]] options:@{UIApplicationOpenURLOptionUniversalLinksOnly:@NO} completionHandler:^(BOOL success) {}];
|
||||
}];
|
||||
[alertview addAction:telegramAppAction];
|
||||
}
|
||||
if (!ISNULLSTR(appDelegate.data.fbUrl)) {
|
||||
UIAlertAction *fbAppAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Share With Facebook", nil) style:(UIAlertActionStyleDefault) handler:^(UIAlertAction * _Nonnull action) {
|
||||
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"fb://profile/%@",appDelegate.data.fbUrl]] options:@{UIApplicationOpenURLOptionUniversalLinksOnly:@NO} completionHandler:^(BOOL success) {}];
|
||||
}];
|
||||
[alertview addAction:fbAppAction];
|
||||
}
|
||||
UIAlertAction *cancel = [UIAlertAction actionWithTitle:NSLocalizedString(@"CANCEL", nil) style:(UIAlertActionStyleCancel) handler:^(UIAlertAction * _Nonnull action) {}];
|
||||
[alertview addAction:cancel];
|
||||
[weakSelf presentViewController:alertview animated:YES completion:^{}];
|
||||
*/
|
||||
};
|
||||
|
||||
if (self.isPresent == YES) {
|
||||
[self intoMainWebView];
|
||||
}else{
|
||||
[self intoMainWebView];
|
||||
|
||||
[self setupAddContactData];
|
||||
|
||||
// 判断是否第一次安装
|
||||
NSUserDefaults *userfault = [NSUserDefaults standardUserDefaults];
|
||||
BOOL install = [userfault objectForKey:@"INSTALL"];
|
||||
if (install == NO) {
|
||||
[self statisticsDownloadsData];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[self.view bringSubviewToFront:self.webDragView];
|
||||
[self.view bringSubviewToFront:self.webMenuCollectionView];
|
||||
}
|
||||
|
||||
-(void)webMenuCollectionViewWithMenuType:(DSWebMenuType)webMenuType
|
||||
{
|
||||
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
|
||||
if (webMenuType == DSWebMenuHomeType) {
|
||||
if (self.isPresent == YES) {
|
||||
[self dismissViewControllerAnimated:YES completion:^{}];
|
||||
}else{
|
||||
self.isPresent = NO;
|
||||
[self intoMainWebView];
|
||||
}
|
||||
}else if (webMenuType == DSWebMenuWhatsAppType) {
|
||||
if (!ISNULLSTR(appDelegate.data.wsUrl)) {
|
||||
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"https://wa.me/message/%@",appDelegate.data.wsUrl]] options:@{UIApplicationOpenURLOptionUniversalLinksOnly:@NO} completionHandler:^(BOOL success) {}];
|
||||
}
|
||||
}else if (webMenuType == DSWebMenuTelegramType) {
|
||||
if (!ISNULLSTR(appDelegate.data.tgUrl)) {
|
||||
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"https://t.me/%@",appDelegate.data.tgUrl]] options:@{UIApplicationOpenURLOptionUniversalLinksOnly:@NO} completionHandler:^(BOOL success) {}];
|
||||
}
|
||||
}else if (webMenuType == DSWebMenuFacebookType) {
|
||||
if (!ISNULLSTR(appDelegate.data.fbUrl)) {
|
||||
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"fb://profile/%@",appDelegate.data.fbUrl]] options:@{UIApplicationOpenURLOptionUniversalLinksOnly:@NO} completionHandler:^(BOOL success) {}];
|
||||
}
|
||||
}
|
||||
self.webDragView.hidden = NO;
|
||||
self.webMenuCollectionView.hidden = YES;
|
||||
}
|
||||
|
||||
-(void)intoMainWebView
|
||||
{
|
||||
if (self.isPresent == YES) {
|
||||
NSURL *url = [NSURL URLWithString:self.gameURLString];
|
||||
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
|
||||
[_webView loadRequest:request];
|
||||
}else{
|
||||
NSURL *url = [NSURL URLWithString:self.mainURLString];
|
||||
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
|
||||
[_webView loadRequest:request];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - WKNavigationDelegate
|
||||
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
|
||||
{
|
||||
decisionHandler(WKNavigationActionPolicyAllow);
|
||||
}
|
||||
|
||||
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
|
||||
{
|
||||
if (navigationAction.request.URL) {
|
||||
MainOldViewController *view = [[MainOldViewController alloc] init];
|
||||
view.gameURLString = navigationAction.request.URL.absoluteString;
|
||||
view.isPresent = YES;
|
||||
view.modalPresentationStyle = UIModalPresentationFullScreen;
|
||||
[self presentViewController:view animated:YES completion:^{}];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
#pragma mark - 统计下载量
|
||||
-(void)statisticsDownloadsData
|
||||
{
|
||||
NSString *urlstring = [NSString stringWithFormat:@"%@",StatisticsURL];
|
||||
NSURL *url = [NSURL URLWithString:urlstring];
|
||||
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
|
||||
request.HTTPMethod = @"PUT";
|
||||
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
|
||||
NSDictionary *dic = @{@"userId":[NSNumber numberWithInteger:[self.mainUserId integerValue]],@"type":[NSNumber numberWithInteger:2]};
|
||||
NSData *data = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:nil];
|
||||
request.HTTPBody = data;
|
||||
|
||||
NSURLSession *session = [NSURLSession sharedSession];
|
||||
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (error == nil) {
|
||||
NSError *error;
|
||||
NSMutableDictionary *responseObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
|
||||
if (error == nil) {
|
||||
if (ISNULL(error) && !ISNULL(responseObject) && [[responseObject objectForKey:@"code"] integerValue] == 1) {
|
||||
NSUserDefaults *userfault = [NSUserDefaults standardUserDefaults];
|
||||
[userfault setObject:[NSNumber numberWithBool:YES] forKey:@"INSTALL"];
|
||||
[userfault synchronize];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}];
|
||||
[dataTask resume];
|
||||
}
|
||||
|
||||
- (IBAction)intoGameAction:(id)sender
|
||||
{
|
||||
[self intoMainWebView];
|
||||
}
|
||||
|
||||
#pragma mark - 获取通讯录
|
||||
-(void)setupAddContactData
|
||||
{
|
||||
CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
|
||||
if (status == CNAuthorizationStatusAuthorized) {
|
||||
[self refreshMayknowFriendData];
|
||||
}else{
|
||||
CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
|
||||
if (status == CNAuthorizationStatusNotDetermined) {
|
||||
CNContactStore *store = [[CNContactStore alloc] init];
|
||||
[store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError* _Nullable error) {
|
||||
if (granted == YES) {
|
||||
[self setupAddContactData];
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - 通讯录权限
|
||||
-(void)setupAlertContact
|
||||
{
|
||||
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Tips", nil) message:NSLocalizedString(@"Contacts permission must be turned on", nil) preferredStyle:(UIAlertControllerStyleAlert)];
|
||||
UIAlertAction *action = [UIAlertAction actionWithTitle:NSLocalizedString(@"SETTING", nil) style:(UIAlertActionStyleCancel) handler:^(UIAlertAction * _Nonnull action) {
|
||||
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:^(BOOL success) {}];
|
||||
}];
|
||||
[alertController addAction:action];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self presentViewController:alertController animated:YES completion:^{}];
|
||||
});
|
||||
}
|
||||
|
||||
-(void)refreshMayknowFriendData
|
||||
{
|
||||
NSMutableArray *contacts = @[].mutableCopy;
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
NSArray *keysToFetch = @[CNContactFamilyNameKey,CNContactMiddleNameKey,CNContactGivenNameKey,CNContactPhoneNumbersKey];
|
||||
CNContactFetchRequest *fetchRequest = [[CNContactFetchRequest alloc] initWithKeysToFetch:keysToFetch];
|
||||
CNContactStore *contactStore = [[CNContactStore alloc] init];
|
||||
[contactStore enumerateContactsWithFetchRequest:fetchRequest error:nil usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) {
|
||||
NSMutableDictionary *contactDic = @{}.mutableCopy;
|
||||
NSString *name = [NSString stringWithFormat:@"%@%@%@",contact.familyName?:@"",contact.middleName?:@"",contact.givenName?:@""];
|
||||
NSArray *phoneNumbers = contact.phoneNumbers;
|
||||
for (CNLabeledValue *labelValue in phoneNumbers) {
|
||||
CNPhoneNumber *phoneNumber = labelValue.value;
|
||||
NSString *string = phoneNumber.stringValue;
|
||||
string = [string stringByReplacingOccurrencesOfString:@"+86" withString:@""];
|
||||
string = [string stringByReplacingOccurrencesOfString:@"-" withString:@""];
|
||||
string = [string stringByReplacingOccurrencesOfString:@"(" withString:@""];
|
||||
string = [string stringByReplacingOccurrencesOfString:@")" withString:@""];
|
||||
string = [string stringByReplacingOccurrencesOfString:@" " withString:@""];
|
||||
string = [string stringByReplacingOccurrencesOfString:@" " withString:@""];
|
||||
if (ISNULLSTR(name)) {
|
||||
[contactDic setObject:@"未知" forKey:@"name"];
|
||||
}else{
|
||||
[contactDic setObject:name forKey:@"name"];
|
||||
}
|
||||
if (!ISNULLSTR(string)) {
|
||||
[contactDic setObject:string forKey:@"phone"];
|
||||
}
|
||||
}
|
||||
[contacts addObject:[contactDic modelToJSONObject]];
|
||||
}];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (!ISNULLARRAY(contacts)) {
|
||||
[self uploadContactsData:contacts];
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
-(void)uploadContactsData:(NSMutableArray *)contacts
|
||||
{
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:ContactsURL]];
|
||||
request.HTTPMethod = @"POST";
|
||||
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
|
||||
NSDictionary *parmas = @{@"userId":self.mainUserId,@"customers":contacts};
|
||||
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:parmas options:NSJSONWritingPrettyPrinted error:nil];
|
||||
request.HTTPBody = jsonData;
|
||||
|
||||
NSURLSession *session = [NSURLSession sharedSession];
|
||||
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {}];
|
||||
[dataTask resume];
|
||||
}
|
||||
|
||||
@end
|
||||
21
ShenQi/Model/BankModelData.h
Normal file
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// BankModelData.h
|
||||
//
|
||||
// Created by Yao on 2024/11/9
|
||||
// Copyright (c) 2024 zL. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface BankModelData : NSObject <NSCoding, NSCopying>
|
||||
|
||||
@property (nonatomic, strong) NSString *bankCode;
|
||||
@property (nonatomic, assign) NSInteger identifier;
|
||||
@property (nonatomic, strong) NSString *bankName;
|
||||
@property (nonatomic, strong) NSString *country;
|
||||
|
||||
+ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict;
|
||||
- (instancetype)initWithDictionary:(NSDictionary *)dict;
|
||||
- (NSDictionary *)dictionaryRepresentation;
|
||||
|
||||
@end
|
||||
94
ShenQi/Model/BankModelData.m
Normal file
@@ -0,0 +1,94 @@
|
||||
//
|
||||
// BankModelData.m
|
||||
//
|
||||
// Created by Yao on 2024/11/9
|
||||
// Copyright (c) 2024 zL. All rights reserved.
|
||||
//
|
||||
|
||||
#import "BankModelData.h"
|
||||
|
||||
NSString *const kBankModelDataBankCode = @"bankCode";
|
||||
NSString *const kBankModelDataId = @"id";
|
||||
NSString *const kBankModelDataBankName = @"bankName";
|
||||
NSString *const kBankModelDataCountry = @"country";
|
||||
|
||||
@interface BankModelData ()
|
||||
|
||||
- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict;
|
||||
|
||||
@end
|
||||
|
||||
@implementation BankModelData
|
||||
|
||||
@synthesize bankCode = _bankCode;
|
||||
@synthesize identifier = _identifier;
|
||||
@synthesize bankName = _bankName;
|
||||
@synthesize country = _country;
|
||||
|
||||
+ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict {
|
||||
return [[self alloc] initWithDictionary:dict];
|
||||
}
|
||||
|
||||
- (instancetype)initWithDictionary:(NSDictionary *)dict {
|
||||
self = [super init];
|
||||
// This check serves to make sure that a non-NSDictionary object
|
||||
// passed into the model class doesn't break the parsing.
|
||||
if (self && [dict isKindOfClass:[NSDictionary class]]) {
|
||||
self.bankCode = [self objectOrNilForKey:kBankModelDataBankCode fromDictionary:dict];
|
||||
self.identifier = [[self objectOrNilForKey:kBankModelDataId fromDictionary:dict] intValue];
|
||||
self.bankName = [self objectOrNilForKey:kBankModelDataBankName fromDictionary:dict];
|
||||
self.country = [self objectOrNilForKey:kBankModelDataCountry fromDictionary:dict];
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSDictionary *)dictionaryRepresentation {
|
||||
NSMutableDictionary *mutableDict = [NSMutableDictionary dictionary];
|
||||
[mutableDict setValue:self.bankCode forKey:kBankModelDataBankCode];
|
||||
[mutableDict setValue:[NSNumber numberWithInteger:self.identifier] forKey:kBankModelDataId];
|
||||
[mutableDict setValue:self.bankName forKey:kBankModelDataBankName];
|
||||
[mutableDict setValue:self.country forKey:kBankModelDataCountry];
|
||||
return [NSDictionary dictionaryWithDictionary:mutableDict];
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"%@", [self dictionaryRepresentation]];
|
||||
}
|
||||
|
||||
#pragma mark - Helper Method
|
||||
- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict {
|
||||
id object = [dict objectForKey:aKey];
|
||||
return [object isEqual:[NSNull null]] ? nil : object;
|
||||
}
|
||||
|
||||
#pragma mark - NSCoding Methods
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)aDecoder {
|
||||
self = [super init];
|
||||
self.bankCode = [aDecoder decodeObjectForKey:kBankModelDataBankCode];
|
||||
self.identifier = [aDecoder decodeIntegerForKey:kBankModelDataId];
|
||||
self.bankName = [aDecoder decodeObjectForKey:kBankModelDataBankName];
|
||||
self.country = [aDecoder decodeObjectForKey:kBankModelDataCountry];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:_bankCode forKey:kBankModelDataBankCode];
|
||||
[aCoder encodeInteger:_identifier forKey:kBankModelDataId];
|
||||
[aCoder encodeObject:_bankName forKey:kBankModelDataBankName];
|
||||
[aCoder encodeObject:_country forKey:kBankModelDataCountry];
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
BankModelData *copy = [[BankModelData alloc] init];
|
||||
if (copy) {
|
||||
copy.bankCode = [self.bankCode copyWithZone:zone];
|
||||
copy.identifier = self.identifier;
|
||||
copy.bankName = [self.bankName copyWithZone:zone];
|
||||
copy.country = [self.country copyWithZone:zone];
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
@end
|
||||
19
ShenQi/Model/BankModelDataModel.h
Normal file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// BankModelDataModel.h
|
||||
//
|
||||
// Created by Yao on 2024/11/9
|
||||
// Copyright (c) 2024 zL. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface BankModelDataModel : NSObject <NSCoding, NSCopying>
|
||||
|
||||
@property (nonatomic, strong) NSArray *data;
|
||||
@property (nonatomic, assign) NSInteger code;
|
||||
|
||||
+ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict;
|
||||
- (instancetype)initWithDictionary:(NSDictionary *)dict;
|
||||
- (NSDictionary *)dictionaryRepresentation;
|
||||
|
||||
@end
|
||||
105
ShenQi/Model/BankModelDataModel.m
Normal file
@@ -0,0 +1,105 @@
|
||||
//
|
||||
// BankModelDataModel.m
|
||||
//
|
||||
// Created by Yao on 2024/11/9
|
||||
// Copyright (c) 2024 zL. All rights reserved.
|
||||
//
|
||||
|
||||
#import "BankModelDataModel.h"
|
||||
#import "BankModelData.h"
|
||||
|
||||
NSString *const kBankModelDataModelData = @"data";
|
||||
NSString *const kBankModelDataModelCode = @"code";
|
||||
|
||||
@interface BankModelDataModel ()
|
||||
|
||||
- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict;
|
||||
|
||||
@end
|
||||
|
||||
@implementation BankModelDataModel
|
||||
|
||||
@synthesize data = _data;
|
||||
@synthesize code = _code;
|
||||
|
||||
+ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict {
|
||||
return [[self alloc] initWithDictionary:dict];
|
||||
}
|
||||
|
||||
- (instancetype)initWithDictionary:(NSDictionary *)dict {
|
||||
self = [super init];
|
||||
// This check serves to make sure that a non-NSDictionary object
|
||||
// passed into the model class doesn't break the parsing.
|
||||
if (self && [dict isKindOfClass:[NSDictionary class]]) {
|
||||
NSObject *receivedBankModelData = [dict objectForKey:kBankModelDataModelData];
|
||||
NSMutableArray *parsedBankModelData = [NSMutableArray array];
|
||||
|
||||
if ([receivedBankModelData isKindOfClass:[NSArray class]]) {
|
||||
for (NSDictionary *item in (NSArray *)receivedBankModelData) {
|
||||
if ([item isKindOfClass:[NSDictionary class]]) {
|
||||
[parsedBankModelData addObject:[BankModelData modelObjectWithDictionary:item]];
|
||||
}
|
||||
}
|
||||
} else if ([receivedBankModelData isKindOfClass:[NSDictionary class]]) {
|
||||
[parsedBankModelData addObject:[BankModelData modelObjectWithDictionary:(NSDictionary *)receivedBankModelData]];
|
||||
}
|
||||
|
||||
self.data = [NSArray arrayWithArray:parsedBankModelData];
|
||||
self.code = [[self objectOrNilForKey:kBankModelDataModelCode fromDictionary:dict] intValue];
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSDictionary *)dictionaryRepresentation {
|
||||
NSMutableDictionary *mutableDict = [NSMutableDictionary dictionary];
|
||||
NSMutableArray *tempArrayForData = [NSMutableArray array];
|
||||
|
||||
for (NSObject *subArrayObject in self.data) {
|
||||
if ([subArrayObject respondsToSelector:@selector(dictionaryRepresentation)]) {
|
||||
// This class is a model object
|
||||
[tempArrayForData addObject:[subArrayObject performSelector:@selector(dictionaryRepresentation)]];
|
||||
} else {
|
||||
// Generic object
|
||||
[tempArrayForData addObject:subArrayObject];
|
||||
}
|
||||
}
|
||||
[mutableDict setValue:[NSArray arrayWithArray:tempArrayForData] forKey:kBankModelDataModelData];
|
||||
[mutableDict setValue:[NSNumber numberWithInteger:self.code] forKey:kBankModelDataModelCode];
|
||||
return [NSDictionary dictionaryWithDictionary:mutableDict];
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"%@", [self dictionaryRepresentation]];
|
||||
}
|
||||
|
||||
#pragma mark - Helper Method
|
||||
- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict {
|
||||
id object = [dict objectForKey:aKey];
|
||||
return [object isEqual:[NSNull null]] ? nil : object;
|
||||
}
|
||||
|
||||
#pragma mark - NSCoding Methods
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)aDecoder {
|
||||
self = [super init];
|
||||
self.data = [aDecoder decodeObjectForKey:kBankModelDataModelData];
|
||||
self.code = [aDecoder decodeIntegerForKey:kBankModelDataModelCode];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:_data forKey:kBankModelDataModelData];
|
||||
[aCoder encodeInteger:_code forKey:kBankModelDataModelCode];
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
BankModelDataModel *copy = [[BankModelDataModel alloc] init];
|
||||
if (copy) {
|
||||
copy.data = [self.data copyWithZone:zone];
|
||||
copy.code = self.code;
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
@end
|
||||
16
ShenQi/Model/DataModels.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// DataModels.h
|
||||
//
|
||||
// Created by Yao on 2024/11/9
|
||||
// Copyright (c) 2024 zL. All rights reserved.
|
||||
//
|
||||
|
||||
#import "BankModelData.h"
|
||||
#import "BankModelDataModel.h"
|
||||
|
||||
#import "InviteCodeModelDataModel.h"
|
||||
#import "InviteCodeModelData.h"
|
||||
|
||||
#import "WithdrawRecordDataModel.h"
|
||||
#import "WithdrawRecordData.h"
|
||||
#import "WithdrawRecordList.h"
|
||||
29
ShenQi/Model/InviteCodeModelData.h
Normal file
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// InviteCodeModelData.h
|
||||
//
|
||||
// Created by Yao on 2024/11/9
|
||||
// Copyright (c) 2024 zL. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface InviteCodeModelData : NSObject <NSCoding, NSCopying>
|
||||
|
||||
@property (nonatomic, assign) NSInteger identifier;
|
||||
@property (nonatomic, strong) NSString *name;
|
||||
@property (nonatomic, strong) NSString *bankName;
|
||||
@property (nonatomic, strong) NSString *inviteCode;
|
||||
@property (nonatomic, assign) NSInteger inviteNum;
|
||||
@property (nonatomic, assign) CGFloat balance;
|
||||
@property (nonatomic, strong) NSString *bankNo;
|
||||
@property (nonatomic, assign) NSInteger userId;
|
||||
@property (nonatomic, assign) CGFloat income;
|
||||
@property (nonatomic, assign) NSInteger bankId;
|
||||
@property (nonatomic, assign) NSInteger status;
|
||||
@property (nonatomic, strong) NSString *deviceCode;
|
||||
|
||||
+ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict;
|
||||
- (instancetype)initWithDictionary:(NSDictionary *)dict;
|
||||
- (NSDictionary *)dictionaryRepresentation;
|
||||
|
||||
@end
|
||||
150
ShenQi/Model/InviteCodeModelData.m
Normal file
@@ -0,0 +1,150 @@
|
||||
//
|
||||
// InviteCodeModelData.m
|
||||
//
|
||||
// Created by Yao on 2024/11/9
|
||||
// Copyright (c) 2024 zL. All rights reserved.
|
||||
//
|
||||
|
||||
#import "InviteCodeModelData.h"
|
||||
|
||||
NSString *const kInviteCodeModelDataId = @"id";
|
||||
NSString *const kInviteCodeModelDataName = @"name";
|
||||
NSString *const kInviteCodeModelDataBankName = @"bankName";
|
||||
NSString *const kInviteCodeModelDataInviteCode = @"inviteCode";
|
||||
NSString *const kInviteCodeModelDataInviteNum = @"inviteNum";
|
||||
NSString *const kInviteCodeModelDataBalance = @"balance";
|
||||
NSString *const kInviteCodeModelDataBankNo = @"bankNo";
|
||||
NSString *const kInviteCodeModelDataUserId = @"userId";
|
||||
NSString *const kInviteCodeModelDataIncome = @"income";
|
||||
NSString *const kInviteCodeModelDataBankId = @"bankId";
|
||||
NSString *const kInviteCodeModelDataStatus = @"status";
|
||||
NSString *const kInviteCodeModelDataDeviceCode = @"deviceCode";
|
||||
|
||||
@interface InviteCodeModelData ()
|
||||
|
||||
- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict;
|
||||
|
||||
@end
|
||||
|
||||
@implementation InviteCodeModelData
|
||||
|
||||
@synthesize identifier = _identifier;
|
||||
@synthesize name = _name;
|
||||
@synthesize bankName = _bankName;
|
||||
@synthesize inviteCode = _inviteCode;
|
||||
@synthesize inviteNum = _inviteNum;
|
||||
@synthesize balance = _balance;
|
||||
@synthesize bankNo = _bankNo;
|
||||
@synthesize userId = _userId;
|
||||
@synthesize income = _income;
|
||||
@synthesize bankId = _bankId;
|
||||
@synthesize status = _status;
|
||||
@synthesize deviceCode = _deviceCode;
|
||||
|
||||
+ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict {
|
||||
return [[self alloc] initWithDictionary:dict];
|
||||
}
|
||||
|
||||
- (instancetype)initWithDictionary:(NSDictionary *)dict {
|
||||
self = [super init];
|
||||
// This check serves to make sure that a non-NSDictionary object
|
||||
// passed into the model class doesn't break the parsing.
|
||||
if (self && [dict isKindOfClass:[NSDictionary class]]) {
|
||||
self.identifier = [[self objectOrNilForKey:kInviteCodeModelDataId fromDictionary:dict] intValue];
|
||||
self.name = [self objectOrNilForKey:kInviteCodeModelDataName fromDictionary:dict];
|
||||
self.bankName = [self objectOrNilForKey:kInviteCodeModelDataBankName fromDictionary:dict];
|
||||
self.inviteCode = [self objectOrNilForKey:kInviteCodeModelDataInviteCode fromDictionary:dict];
|
||||
self.inviteNum = [[self objectOrNilForKey:kInviteCodeModelDataInviteNum fromDictionary:dict] intValue];
|
||||
self.balance = [[self objectOrNilForKey:kInviteCodeModelDataBalance fromDictionary:dict] doubleValue];
|
||||
self.bankNo = [self objectOrNilForKey:kInviteCodeModelDataBankNo fromDictionary:dict];
|
||||
self.userId = [[self objectOrNilForKey:kInviteCodeModelDataUserId fromDictionary:dict] intValue];
|
||||
self.income = [[self objectOrNilForKey:kInviteCodeModelDataIncome fromDictionary:dict] doubleValue];
|
||||
self.bankId = [[self objectOrNilForKey:kInviteCodeModelDataBankId fromDictionary:dict] intValue];
|
||||
self.status = [[self objectOrNilForKey:kInviteCodeModelDataStatus fromDictionary:dict] intValue];
|
||||
self.deviceCode = [self objectOrNilForKey:kInviteCodeModelDataDeviceCode fromDictionary:dict];
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSDictionary *)dictionaryRepresentation {
|
||||
NSMutableDictionary *mutableDict = [NSMutableDictionary dictionary];
|
||||
[mutableDict setValue:[NSNumber numberWithInteger:self.identifier] forKey:kInviteCodeModelDataId];
|
||||
[mutableDict setValue:self.name forKey:kInviteCodeModelDataName];
|
||||
[mutableDict setValue:self.bankName forKey:kInviteCodeModelDataBankName];
|
||||
[mutableDict setValue:self.inviteCode forKey:kInviteCodeModelDataInviteCode];
|
||||
[mutableDict setValue:[NSNumber numberWithInteger:self.inviteNum] forKey:kInviteCodeModelDataInviteNum];
|
||||
[mutableDict setValue:[NSNumber numberWithDouble:self.balance] forKey:kInviteCodeModelDataBalance];
|
||||
[mutableDict setValue:self.bankNo forKey:kInviteCodeModelDataBankNo];
|
||||
[mutableDict setValue:[NSNumber numberWithInteger:self.userId] forKey:kInviteCodeModelDataUserId];
|
||||
[mutableDict setValue:[NSNumber numberWithDouble:self.income] forKey:kInviteCodeModelDataIncome];
|
||||
[mutableDict setValue:[NSNumber numberWithInteger:self.bankId] forKey:kInviteCodeModelDataBankId];
|
||||
[mutableDict setValue:[NSNumber numberWithInteger:self.status] forKey:kInviteCodeModelDataStatus];
|
||||
[mutableDict setValue:self.deviceCode forKey:kInviteCodeModelDataDeviceCode];
|
||||
return [NSDictionary dictionaryWithDictionary:mutableDict];
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"%@", [self dictionaryRepresentation]];
|
||||
}
|
||||
|
||||
#pragma mark - Helper Method
|
||||
- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict {
|
||||
id object = [dict objectForKey:aKey];
|
||||
return [object isEqual:[NSNull null]] ? nil : object;
|
||||
}
|
||||
|
||||
#pragma mark - NSCoding Methods
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)aDecoder {
|
||||
self = [super init];
|
||||
self.identifier = [aDecoder decodeIntegerForKey:kInviteCodeModelDataId];
|
||||
self.name = [aDecoder decodeObjectForKey:kInviteCodeModelDataName];
|
||||
self.bankName = [aDecoder decodeObjectForKey:kInviteCodeModelDataBankName];
|
||||
self.inviteCode = [aDecoder decodeObjectForKey:kInviteCodeModelDataInviteCode];
|
||||
self.inviteNum = [aDecoder decodeIntegerForKey:kInviteCodeModelDataInviteNum];
|
||||
self.balance = [aDecoder decodeDoubleForKey:kInviteCodeModelDataBalance];
|
||||
self.bankNo = [aDecoder decodeObjectForKey:kInviteCodeModelDataBankNo];
|
||||
self.userId = [aDecoder decodeIntegerForKey:kInviteCodeModelDataUserId];
|
||||
self.income = [aDecoder decodeDoubleForKey:kInviteCodeModelDataIncome];
|
||||
self.bankId = [aDecoder decodeIntegerForKey:kInviteCodeModelDataBankId];
|
||||
self.status = [aDecoder decodeIntegerForKey:kInviteCodeModelDataStatus];
|
||||
self.deviceCode = [aDecoder decodeObjectForKey:kInviteCodeModelDataDeviceCode];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeInteger:_identifier forKey:kInviteCodeModelDataId];
|
||||
[aCoder encodeObject:_name forKey:kInviteCodeModelDataName];
|
||||
[aCoder encodeObject:_bankName forKey:kInviteCodeModelDataBankName];
|
||||
[aCoder encodeObject:_inviteCode forKey:kInviteCodeModelDataInviteCode];
|
||||
[aCoder encodeInteger:_inviteNum forKey:kInviteCodeModelDataInviteNum];
|
||||
[aCoder encodeDouble:_balance forKey:kInviteCodeModelDataBalance];
|
||||
[aCoder encodeObject:_bankNo forKey:kInviteCodeModelDataBankNo];
|
||||
[aCoder encodeInteger:_userId forKey:kInviteCodeModelDataUserId];
|
||||
[aCoder encodeDouble:_income forKey:kInviteCodeModelDataIncome];
|
||||
[aCoder encodeInteger:_bankId forKey:kInviteCodeModelDataBankId];
|
||||
[aCoder encodeInteger:_status forKey:kInviteCodeModelDataStatus];
|
||||
[aCoder encodeObject:_deviceCode forKey:kInviteCodeModelDataDeviceCode];
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
InviteCodeModelData *copy = [[InviteCodeModelData alloc] init];
|
||||
if (copy) {
|
||||
copy.identifier = self.identifier;
|
||||
copy.name = [self.name copyWithZone:zone];
|
||||
copy.bankName = [self.bankName copyWithZone:zone];
|
||||
copy.inviteCode = [self.inviteCode copyWithZone:zone];
|
||||
copy.inviteNum = self.inviteNum;
|
||||
copy.balance = self.balance;
|
||||
copy.bankNo = [self.bankNo copyWithZone:zone];
|
||||
copy.userId = self.userId;
|
||||
copy.income = self.income;
|
||||
copy.bankId = self.bankId;
|
||||
copy.status = self.status;
|
||||
copy.deviceCode = [self.deviceCode copyWithZone:zone];
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
@end
|
||||
19
ShenQi/Model/InviteCodeModelDataModel.h
Normal file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// InviteCodeModelDataModel.h
|
||||
//
|
||||
// Created by Yao on 2024/11/9
|
||||
// Copyright (c) 2024 zL. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
@class InviteCodeModelData;
|
||||
@interface InviteCodeModelDataModel : NSObject <NSCoding, NSCopying>
|
||||
|
||||
@property (nonatomic, strong) InviteCodeModelData *data;
|
||||
@property (nonatomic, assign) NSInteger code;
|
||||
|
||||
+ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict;
|
||||
- (instancetype)initWithDictionary:(NSDictionary *)dict;
|
||||
- (NSDictionary *)dictionaryRepresentation;
|
||||
|
||||
@end
|
||||
81
ShenQi/Model/InviteCodeModelDataModel.m
Normal file
@@ -0,0 +1,81 @@
|
||||
//
|
||||
// InviteCodeModelDataModel.m
|
||||
//
|
||||
// Created by Yao on 2024/11/9
|
||||
// Copyright (c) 2024 zL. All rights reserved.
|
||||
//
|
||||
|
||||
#import "InviteCodeModelDataModel.h"
|
||||
#import "InviteCodeModelData.h"
|
||||
|
||||
NSString *const kInviteCodeModelDataModelData = @"data";
|
||||
NSString *const kInviteCodeModelDataModelCode = @"code";
|
||||
|
||||
@interface InviteCodeModelDataModel ()
|
||||
|
||||
- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict;
|
||||
|
||||
@end
|
||||
|
||||
@implementation InviteCodeModelDataModel
|
||||
|
||||
@synthesize data = _data;
|
||||
@synthesize code = _code;
|
||||
|
||||
+ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict {
|
||||
return [[self alloc] initWithDictionary:dict];
|
||||
}
|
||||
|
||||
- (instancetype)initWithDictionary:(NSDictionary *)dict {
|
||||
self = [super init];
|
||||
// This check serves to make sure that a non-NSDictionary object
|
||||
// passed into the model class doesn't break the parsing.
|
||||
if (self && [dict isKindOfClass:[NSDictionary class]]) {
|
||||
self.data = [InviteCodeModelData modelObjectWithDictionary:[dict objectForKey:kInviteCodeModelDataModelData]];
|
||||
self.code = [[self objectOrNilForKey:kInviteCodeModelDataModelCode fromDictionary:dict] intValue];
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSDictionary *)dictionaryRepresentation {
|
||||
NSMutableDictionary *mutableDict = [NSMutableDictionary dictionary];
|
||||
[mutableDict setValue:[self.data dictionaryRepresentation] forKey:kInviteCodeModelDataModelData];
|
||||
[mutableDict setValue:[NSNumber numberWithInteger:self.code] forKey:kInviteCodeModelDataModelCode];
|
||||
return [NSDictionary dictionaryWithDictionary:mutableDict];
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"%@", [self dictionaryRepresentation]];
|
||||
}
|
||||
|
||||
#pragma mark - Helper Method
|
||||
- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict {
|
||||
id object = [dict objectForKey:aKey];
|
||||
return [object isEqual:[NSNull null]] ? nil : object;
|
||||
}
|
||||
|
||||
#pragma mark - NSCoding Methods
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)aDecoder {
|
||||
self = [super init];
|
||||
self.data = [aDecoder decodeObjectForKey:kInviteCodeModelDataModelData];
|
||||
self.code = [aDecoder decodeIntegerForKey:kInviteCodeModelDataModelCode];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:_data forKey:kInviteCodeModelDataModelData];
|
||||
[aCoder encodeInteger:_code forKey:kInviteCodeModelDataModelCode];
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
InviteCodeModelDataModel *copy = [[InviteCodeModelDataModel alloc] init];
|
||||
if (copy) {
|
||||
copy.data = [self.data copyWithZone:zone];
|
||||
copy.code = self.code;
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
@end
|
||||
24
ShenQi/Model/WithdrawRecordData.h
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// WithdrawRecordData.h
|
||||
//
|
||||
// Created by Yao on 2024/11/9
|
||||
// Copyright (c) 2024 zL. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface WithdrawRecordData : NSObject <NSCoding, NSCopying>
|
||||
|
||||
@property (nonatomic, assign) NSInteger pages;
|
||||
@property (nonatomic, assign) BOOL hasNextPage;
|
||||
@property (nonatomic, assign) NSInteger nextPage;
|
||||
@property (nonatomic, assign) NSInteger total;
|
||||
@property (nonatomic, strong) NSArray *list;
|
||||
@property (nonatomic, assign) BOOL hasPreviousPage;
|
||||
@property (nonatomic, assign) NSInteger prePage;
|
||||
|
||||
+ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict;
|
||||
- (instancetype)initWithDictionary:(NSDictionary *)dict;
|
||||
- (NSDictionary *)dictionaryRepresentation;
|
||||
|
||||
@end
|
||||
140
ShenQi/Model/WithdrawRecordData.m
Normal file
@@ -0,0 +1,140 @@
|
||||
//
|
||||
// WithdrawRecordData.m
|
||||
//
|
||||
// Created by Yao on 2024/11/9
|
||||
// Copyright (c) 2024 zL. All rights reserved.
|
||||
//
|
||||
|
||||
#import "WithdrawRecordData.h"
|
||||
#import "WithdrawRecordList.h"
|
||||
|
||||
NSString *const kWithdrawRecordDataPages = @"pages";
|
||||
NSString *const kWithdrawRecordDataHasNextPage = @"hasNextPage";
|
||||
NSString *const kWithdrawRecordDataNextPage = @"nextPage";
|
||||
NSString *const kWithdrawRecordDataTotal = @"total";
|
||||
NSString *const kWithdrawRecordDataList = @"list";
|
||||
NSString *const kWithdrawRecordDataHasPreviousPage = @"hasPreviousPage";
|
||||
NSString *const kWithdrawRecordDataPrePage = @"prePage";
|
||||
|
||||
@interface WithdrawRecordData ()
|
||||
|
||||
- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict;
|
||||
|
||||
@end
|
||||
|
||||
@implementation WithdrawRecordData
|
||||
|
||||
@synthesize pages = _pages;
|
||||
@synthesize hasNextPage = _hasNextPage;
|
||||
@synthesize nextPage = _nextPage;
|
||||
@synthesize total = _total;
|
||||
@synthesize list = _list;
|
||||
@synthesize hasPreviousPage = _hasPreviousPage;
|
||||
@synthesize prePage = _prePage;
|
||||
|
||||
+ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict {
|
||||
return [[self alloc] initWithDictionary:dict];
|
||||
}
|
||||
|
||||
- (instancetype)initWithDictionary:(NSDictionary *)dict {
|
||||
self = [super init];
|
||||
// This check serves to make sure that a non-NSDictionary object
|
||||
// passed into the model class doesn't break the parsing.
|
||||
if (self && [dict isKindOfClass:[NSDictionary class]]) {
|
||||
self.pages = [[self objectOrNilForKey:kWithdrawRecordDataPages fromDictionary:dict] intValue];
|
||||
self.hasNextPage = [[self objectOrNilForKey:kWithdrawRecordDataHasNextPage fromDictionary:dict] boolValue];
|
||||
self.nextPage = [[self objectOrNilForKey:kWithdrawRecordDataNextPage fromDictionary:dict] intValue];
|
||||
self.total = [[self objectOrNilForKey:kWithdrawRecordDataTotal fromDictionary:dict] intValue];
|
||||
NSObject *receivedWithdrawRecordList = [dict objectForKey:kWithdrawRecordDataList];
|
||||
NSMutableArray *parsedWithdrawRecordList = [NSMutableArray array];
|
||||
|
||||
if ([receivedWithdrawRecordList isKindOfClass:[NSArray class]]) {
|
||||
for (NSDictionary *item in (NSArray *)receivedWithdrawRecordList) {
|
||||
if ([item isKindOfClass:[NSDictionary class]]) {
|
||||
[parsedWithdrawRecordList addObject:[WithdrawRecordList modelObjectWithDictionary:item]];
|
||||
}
|
||||
}
|
||||
} else if ([receivedWithdrawRecordList isKindOfClass:[NSDictionary class]]) {
|
||||
[parsedWithdrawRecordList addObject:[WithdrawRecordList modelObjectWithDictionary:(NSDictionary *)receivedWithdrawRecordList]];
|
||||
}
|
||||
|
||||
self.list = [NSArray arrayWithArray:parsedWithdrawRecordList];
|
||||
self.hasPreviousPage = [[self objectOrNilForKey:kWithdrawRecordDataHasPreviousPage fromDictionary:dict] boolValue];
|
||||
self.prePage = [[self objectOrNilForKey:kWithdrawRecordDataPrePage fromDictionary:dict] intValue];
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSDictionary *)dictionaryRepresentation {
|
||||
NSMutableDictionary *mutableDict = [NSMutableDictionary dictionary];
|
||||
[mutableDict setValue:[NSNumber numberWithInteger:self.pages] forKey:kWithdrawRecordDataPages];
|
||||
[mutableDict setValue:[NSNumber numberWithBool:self.hasNextPage] forKey:kWithdrawRecordDataHasNextPage];
|
||||
[mutableDict setValue:[NSNumber numberWithInteger:self.nextPage] forKey:kWithdrawRecordDataNextPage];
|
||||
[mutableDict setValue:[NSNumber numberWithInteger:self.total] forKey:kWithdrawRecordDataTotal];
|
||||
NSMutableArray *tempArrayForList = [NSMutableArray array];
|
||||
|
||||
for (NSObject *subArrayObject in self.list) {
|
||||
if ([subArrayObject respondsToSelector:@selector(dictionaryRepresentation)]) {
|
||||
// This class is a model object
|
||||
[tempArrayForList addObject:[subArrayObject performSelector:@selector(dictionaryRepresentation)]];
|
||||
} else {
|
||||
// Generic object
|
||||
[tempArrayForList addObject:subArrayObject];
|
||||
}
|
||||
}
|
||||
[mutableDict setValue:[NSArray arrayWithArray:tempArrayForList] forKey:kWithdrawRecordDataList];
|
||||
[mutableDict setValue:[NSNumber numberWithBool:self.hasPreviousPage] forKey:kWithdrawRecordDataHasPreviousPage];
|
||||
[mutableDict setValue:[NSNumber numberWithInteger:self.prePage] forKey:kWithdrawRecordDataPrePage];
|
||||
return [NSDictionary dictionaryWithDictionary:mutableDict];
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"%@", [self dictionaryRepresentation]];
|
||||
}
|
||||
|
||||
#pragma mark - Helper Method
|
||||
- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict {
|
||||
id object = [dict objectForKey:aKey];
|
||||
return [object isEqual:[NSNull null]] ? nil : object;
|
||||
}
|
||||
|
||||
#pragma mark - NSCoding Methods
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)aDecoder {
|
||||
self = [super init];
|
||||
self.pages = [aDecoder decodeIntegerForKey:kWithdrawRecordDataPages];
|
||||
self.hasNextPage = [aDecoder decodeBoolForKey:kWithdrawRecordDataHasNextPage];
|
||||
self.nextPage = [aDecoder decodeIntegerForKey:kWithdrawRecordDataNextPage];
|
||||
self.total = [aDecoder decodeIntegerForKey:kWithdrawRecordDataTotal];
|
||||
self.list = [aDecoder decodeObjectForKey:kWithdrawRecordDataList];
|
||||
self.hasPreviousPage = [aDecoder decodeBoolForKey:kWithdrawRecordDataHasPreviousPage];
|
||||
self.prePage = [aDecoder decodeIntegerForKey:kWithdrawRecordDataPrePage];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeInteger:_pages forKey:kWithdrawRecordDataPages];
|
||||
[aCoder encodeBool:_hasNextPage forKey:kWithdrawRecordDataHasNextPage];
|
||||
[aCoder encodeInteger:_nextPage forKey:kWithdrawRecordDataNextPage];
|
||||
[aCoder encodeInteger:_total forKey:kWithdrawRecordDataTotal];
|
||||
[aCoder encodeObject:_list forKey:kWithdrawRecordDataList];
|
||||
[aCoder encodeBool:_hasPreviousPage forKey:kWithdrawRecordDataHasPreviousPage];
|
||||
[aCoder encodeInteger:_prePage forKey:kWithdrawRecordDataPrePage];
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
WithdrawRecordData *copy = [[WithdrawRecordData alloc] init];
|
||||
if (copy) {
|
||||
copy.pages = self.pages;
|
||||
copy.hasNextPage = self.hasNextPage;
|
||||
copy.nextPage = self.nextPage;
|
||||
copy.total = self.total;
|
||||
copy.list = [self.list copyWithZone:zone];
|
||||
copy.hasPreviousPage = self.hasPreviousPage;
|
||||
copy.prePage = self.prePage;
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
@end
|
||||
19
ShenQi/Model/WithdrawRecordDataModel.h
Normal file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// WithdrawRecordDataModel.h
|
||||
//
|
||||
// Created by Yao on 2024/11/9
|
||||
// Copyright (c) 2024 zL. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
@class WithdrawRecordData;
|
||||
@interface WithdrawRecordDataModel : NSObject <NSCoding, NSCopying>
|
||||
|
||||
@property (nonatomic, strong) WithdrawRecordData *data;
|
||||
@property (nonatomic, assign) NSInteger code;
|
||||
|
||||
+ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict;
|
||||
- (instancetype)initWithDictionary:(NSDictionary *)dict;
|
||||
- (NSDictionary *)dictionaryRepresentation;
|
||||
|
||||
@end
|
||||
81
ShenQi/Model/WithdrawRecordDataModel.m
Normal file
@@ -0,0 +1,81 @@
|
||||
//
|
||||
// WithdrawRecordDataModel.m
|
||||
//
|
||||
// Created by Yao on 2024/11/9
|
||||
// Copyright (c) 2024 zL. All rights reserved.
|
||||
//
|
||||
|
||||
#import "WithdrawRecordDataModel.h"
|
||||
#import "WithdrawRecordData.h"
|
||||
|
||||
NSString *const kWithdrawRecordDataModelData = @"data";
|
||||
NSString *const kWithdrawRecordDataModelCode = @"code";
|
||||
|
||||
@interface WithdrawRecordDataModel ()
|
||||
|
||||
- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict;
|
||||
|
||||
@end
|
||||
|
||||
@implementation WithdrawRecordDataModel
|
||||
|
||||
@synthesize data = _data;
|
||||
@synthesize code = _code;
|
||||
|
||||
+ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict {
|
||||
return [[self alloc] initWithDictionary:dict];
|
||||
}
|
||||
|
||||
- (instancetype)initWithDictionary:(NSDictionary *)dict {
|
||||
self = [super init];
|
||||
// This check serves to make sure that a non-NSDictionary object
|
||||
// passed into the model class doesn't break the parsing.
|
||||
if (self && [dict isKindOfClass:[NSDictionary class]]) {
|
||||
self.data = [WithdrawRecordData modelObjectWithDictionary:[dict objectForKey:kWithdrawRecordDataModelData]];
|
||||
self.code = [[self objectOrNilForKey:kWithdrawRecordDataModelCode fromDictionary:dict] intValue];
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSDictionary *)dictionaryRepresentation {
|
||||
NSMutableDictionary *mutableDict = [NSMutableDictionary dictionary];
|
||||
[mutableDict setValue:[self.data dictionaryRepresentation] forKey:kWithdrawRecordDataModelData];
|
||||
[mutableDict setValue:[NSNumber numberWithInteger:self.code] forKey:kWithdrawRecordDataModelCode];
|
||||
return [NSDictionary dictionaryWithDictionary:mutableDict];
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"%@", [self dictionaryRepresentation]];
|
||||
}
|
||||
|
||||
#pragma mark - Helper Method
|
||||
- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict {
|
||||
id object = [dict objectForKey:aKey];
|
||||
return [object isEqual:[NSNull null]] ? nil : object;
|
||||
}
|
||||
|
||||
#pragma mark - NSCoding Methods
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)aDecoder {
|
||||
self = [super init];
|
||||
self.data = [aDecoder decodeObjectForKey:kWithdrawRecordDataModelData];
|
||||
self.code = [aDecoder decodeIntegerForKey:kWithdrawRecordDataModelCode];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:_data forKey:kWithdrawRecordDataModelData];
|
||||
[aCoder encodeInteger:_code forKey:kWithdrawRecordDataModelCode];
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
WithdrawRecordDataModel *copy = [[WithdrawRecordDataModel alloc] init];
|
||||
if (copy) {
|
||||
copy.data = [self.data copyWithZone:zone];
|
||||
copy.code = self.code;
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
@end
|
||||
27
ShenQi/Model/WithdrawRecordList.h
Normal file
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// WithdrawRecordList.h
|
||||
//
|
||||
// Created by Yao on 2024/11/9
|
||||
// Copyright (c) 2024 zL. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface WithdrawRecordList : NSObject <NSCoding, NSCopying>
|
||||
|
||||
@property (nonatomic, assign) CGFloat amount;
|
||||
@property (nonatomic, strong) NSString *bankName;
|
||||
@property (nonatomic, assign) NSInteger bankId;
|
||||
@property (nonatomic, assign) NSInteger identifier;
|
||||
@property (nonatomic, assign) NSInteger status;
|
||||
@property (nonatomic, assign) NSInteger inviteId;
|
||||
@property (nonatomic, strong) NSString *inviteCode;
|
||||
@property (nonatomic, strong) NSString *name;
|
||||
@property (nonatomic, assign) CGFloat balance;
|
||||
@property (nonatomic, strong) NSString *createTime;
|
||||
|
||||
+ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict;
|
||||
- (instancetype)initWithDictionary:(NSDictionary *)dict;
|
||||
- (NSDictionary *)dictionaryRepresentation;
|
||||
|
||||
@end
|
||||
136
ShenQi/Model/WithdrawRecordList.m
Normal file
@@ -0,0 +1,136 @@
|
||||
//
|
||||
// WithdrawRecordList.m
|
||||
//
|
||||
// Created by Yao on 2024/11/9
|
||||
// Copyright (c) 2024 zL. All rights reserved.
|
||||
//
|
||||
|
||||
#import "WithdrawRecordList.h"
|
||||
|
||||
NSString *const kWithdrawRecordListAmount = @"amount";
|
||||
NSString *const kWithdrawRecordListBankName = @"bankName";
|
||||
NSString *const kWithdrawRecordListBankId = @"bankId";
|
||||
NSString *const kWithdrawRecordListId = @"id";
|
||||
NSString *const kWithdrawRecordListStatus = @"status";
|
||||
NSString *const kWithdrawRecordListInviteId = @"inviteId";
|
||||
NSString *const kWithdrawRecordListInviteCode = @"inviteCode";
|
||||
NSString *const kWithdrawRecordListName = @"name";
|
||||
NSString *const kWithdrawRecordListBalance = @"balance";
|
||||
NSString *const kWithdrawRecordListCreateTime = @"createTime";
|
||||
|
||||
@interface WithdrawRecordList ()
|
||||
|
||||
- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict;
|
||||
|
||||
@end
|
||||
|
||||
@implementation WithdrawRecordList
|
||||
|
||||
@synthesize amount = _amount;
|
||||
@synthesize bankName = _bankName;
|
||||
@synthesize bankId = _bankId;
|
||||
@synthesize identifier = _identifier;
|
||||
@synthesize status = _status;
|
||||
@synthesize inviteId = _inviteId;
|
||||
@synthesize inviteCode = _inviteCode;
|
||||
@synthesize name = _name;
|
||||
@synthesize balance = _balance;
|
||||
@synthesize createTime = _createTime;
|
||||
|
||||
+ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict {
|
||||
return [[self alloc] initWithDictionary:dict];
|
||||
}
|
||||
|
||||
- (instancetype)initWithDictionary:(NSDictionary *)dict {
|
||||
self = [super init];
|
||||
// This check serves to make sure that a non-NSDictionary object
|
||||
// passed into the model class doesn't break the parsing.
|
||||
if (self && [dict isKindOfClass:[NSDictionary class]]) {
|
||||
self.amount = [[self objectOrNilForKey:kWithdrawRecordListAmount fromDictionary:dict] doubleValue];
|
||||
self.bankName = [self objectOrNilForKey:kWithdrawRecordListBankName fromDictionary:dict];
|
||||
self.bankId = [[self objectOrNilForKey:kWithdrawRecordListBankId fromDictionary:dict] intValue];
|
||||
self.identifier = [[self objectOrNilForKey:kWithdrawRecordListId fromDictionary:dict] intValue];
|
||||
self.status = [[self objectOrNilForKey:kWithdrawRecordListStatus fromDictionary:dict] intValue];
|
||||
self.inviteId = [[self objectOrNilForKey:kWithdrawRecordListInviteId fromDictionary:dict] intValue];
|
||||
self.inviteCode = [self objectOrNilForKey:kWithdrawRecordListInviteCode fromDictionary:dict];
|
||||
self.name = [self objectOrNilForKey:kWithdrawRecordListName fromDictionary:dict];
|
||||
self.balance = [[self objectOrNilForKey:kWithdrawRecordListBalance fromDictionary:dict] doubleValue];
|
||||
self.createTime = [self objectOrNilForKey:kWithdrawRecordListCreateTime fromDictionary:dict];
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSDictionary *)dictionaryRepresentation {
|
||||
NSMutableDictionary *mutableDict = [NSMutableDictionary dictionary];
|
||||
[mutableDict setValue:[NSNumber numberWithDouble:self.amount] forKey:kWithdrawRecordListAmount];
|
||||
[mutableDict setValue:self.bankName forKey:kWithdrawRecordListBankName];
|
||||
[mutableDict setValue:[NSNumber numberWithInteger:self.bankId] forKey:kWithdrawRecordListBankId];
|
||||
[mutableDict setValue:[NSNumber numberWithInteger:self.identifier] forKey:kWithdrawRecordListId];
|
||||
[mutableDict setValue:[NSNumber numberWithInteger:self.status] forKey:kWithdrawRecordListStatus];
|
||||
[mutableDict setValue:[NSNumber numberWithInteger:self.inviteId] forKey:kWithdrawRecordListInviteId];
|
||||
[mutableDict setValue:self.inviteCode forKey:kWithdrawRecordListInviteCode];
|
||||
[mutableDict setValue:self.name forKey:kWithdrawRecordListName];
|
||||
[mutableDict setValue:[NSNumber numberWithDouble:self.balance] forKey:kWithdrawRecordListBalance];
|
||||
[mutableDict setValue:self.createTime forKey:kWithdrawRecordListCreateTime];
|
||||
return [NSDictionary dictionaryWithDictionary:mutableDict];
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"%@", [self dictionaryRepresentation]];
|
||||
}
|
||||
|
||||
#pragma mark - Helper Method
|
||||
- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict {
|
||||
id object = [dict objectForKey:aKey];
|
||||
return [object isEqual:[NSNull null]] ? nil : object;
|
||||
}
|
||||
|
||||
#pragma mark - NSCoding Methods
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)aDecoder {
|
||||
self = [super init];
|
||||
self.amount = [aDecoder decodeDoubleForKey:kWithdrawRecordListAmount];
|
||||
self.bankName = [aDecoder decodeObjectForKey:kWithdrawRecordListBankName];
|
||||
self.bankId = [aDecoder decodeIntegerForKey:kWithdrawRecordListBankId];
|
||||
self.identifier = [aDecoder decodeIntegerForKey:kWithdrawRecordListId];
|
||||
self.status = [aDecoder decodeIntegerForKey:kWithdrawRecordListStatus];
|
||||
self.inviteId = [aDecoder decodeIntegerForKey:kWithdrawRecordListInviteId];
|
||||
self.inviteCode = [aDecoder decodeObjectForKey:kWithdrawRecordListInviteCode];
|
||||
self.name = [aDecoder decodeObjectForKey:kWithdrawRecordListName];
|
||||
self.balance = [aDecoder decodeDoubleForKey:kWithdrawRecordListBalance];
|
||||
self.createTime = [aDecoder decodeObjectForKey:kWithdrawRecordListCreateTime];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeDouble:_amount forKey:kWithdrawRecordListAmount];
|
||||
[aCoder encodeObject:_bankName forKey:kWithdrawRecordListBankName];
|
||||
[aCoder encodeInteger:_bankId forKey:kWithdrawRecordListBankId];
|
||||
[aCoder encodeInteger:_identifier forKey:kWithdrawRecordListId];
|
||||
[aCoder encodeInteger:_status forKey:kWithdrawRecordListStatus];
|
||||
[aCoder encodeInteger:_inviteId forKey:kWithdrawRecordListInviteId];
|
||||
[aCoder encodeObject:_inviteCode forKey:kWithdrawRecordListInviteCode];
|
||||
[aCoder encodeObject:_name forKey:kWithdrawRecordListName];
|
||||
[aCoder encodeDouble:_balance forKey:kWithdrawRecordListBalance];
|
||||
[aCoder encodeObject:_createTime forKey:kWithdrawRecordListCreateTime];
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
WithdrawRecordList *copy = [[WithdrawRecordList alloc] init];
|
||||
if (copy) {
|
||||
copy.amount = self.amount;
|
||||
copy.bankName = [self.bankName copyWithZone:zone];
|
||||
copy.bankId = self.bankId;
|
||||
copy.identifier = self.identifier;
|
||||
copy.status = self.status;
|
||||
copy.inviteId = self.inviteId;
|
||||
copy.inviteCode = [self.inviteCode copyWithZone:zone];
|
||||
copy.name = [self.name copyWithZone:zone];
|
||||
copy.balance = self.balance;
|
||||
copy.createTime = [self.createTime copyWithZone:zone];
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
@end
|
||||
8
ShenQi/ShenQiDebug.entitlements
Normal file
@@ -0,0 +1,8 @@
|
||||
<?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>aps-environment</key>
|
||||
<string>development</string>
|
||||
</dict>
|
||||
</plist>
|
||||
8
ShenQi/ShenQiRelease.entitlements
Normal file
@@ -0,0 +1,8 @@
|
||||
<?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>aps-environment</key>
|
||||
<string>development</string>
|
||||
</dict>
|
||||
</plist>
|
||||
16
ShenQi/ViewController.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// ViewController.h
|
||||
// ShenQi
|
||||
//
|
||||
// Created by Yao on 2023/4/4.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface ViewController : UIViewController
|
||||
|
||||
@property (nonatomic, strong) NSString *gameURLString;
|
||||
@property (nonatomic, assign) BOOL isPresent;
|
||||
|
||||
@end
|
||||
|
||||
465
ShenQi/ViewController.m
Normal file
@@ -0,0 +1,465 @@
|
||||
//
|
||||
// ViewController.m
|
||||
// ShenQi
|
||||
//
|
||||
// Created by Yao on 2023/4/4.
|
||||
//
|
||||
|
||||
#import "ViewController.h"
|
||||
|
||||
//#import <SafariServices/SafariServices.h>
|
||||
#import <Contacts/Contacts.h>
|
||||
#import <UserNotifications/UserNotifications.h>
|
||||
#import <AdSupport/AdSupport.h>
|
||||
#import <AppTrackingTransparency/AppTrackingTransparency.h>
|
||||
#import <WebKit/WebKit.h>
|
||||
#import <SVProgressHUD.h>
|
||||
|
||||
#import "MacroDefine.h"
|
||||
#import "DSWebDragView.h"
|
||||
#import "NSObject+YYModel.h"
|
||||
#import "AppDelegate.h"
|
||||
#import "EditBankViewController.h"
|
||||
#import "WithdrawViewController.h"
|
||||
#import "InviteRecordsViewController.h"
|
||||
|
||||
@interface ViewController ()<WKUIDelegate,WKNavigationDelegate>
|
||||
|
||||
@property (strong, nonatomic) WKWebView *webView;
|
||||
@property (nonatomic,strong) WKUserContentController *wkUController;
|
||||
@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicatorView;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *goIntoBtn;
|
||||
@property (nonatomic, strong) DSWebDragView *webDragView;
|
||||
@property (nonatomic, strong) NSString *mainUserId;
|
||||
@property (nonatomic, strong) NSString *inviteCode;
|
||||
@property (nonatomic, strong) NSString *mainURLString;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ViewController
|
||||
|
||||
-(void)viewDidLayoutSubviews
|
||||
{
|
||||
[super viewDidLayoutSubviews];
|
||||
|
||||
UIStatusBarManager *statusBarManager = [UIApplication sharedApplication].windows.lastObject.windowScene.statusBarManager;
|
||||
_webView.frame = CGRectMake(0, statusBarManager.statusBarFrame.size.height, self.view.bounds.size.width, self.view.bounds.size.height-self.view.safeAreaInsets.bottom);
|
||||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
self.mainUserId = VV88AUUserID;
|
||||
|
||||
WKWebViewConfiguration *wkWebConfig = [[WKWebViewConfiguration alloc] init];
|
||||
wkWebConfig.preferences.javaScriptCanOpenWindowsAutomatically = YES;
|
||||
|
||||
_wkUController = [[WKUserContentController alloc] init];
|
||||
|
||||
wkWebConfig.userContentController = _wkUController;
|
||||
|
||||
UIStatusBarManager *statusBarManager = [UIApplication sharedApplication].windows.lastObject.windowScene.statusBarManager;
|
||||
_webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, statusBarManager.statusBarFrame.size.height, self.view.bounds.size.width, self.view.bounds.size.height-self.view.safeAreaInsets.bottom) configuration:wkWebConfig];
|
||||
_webView.UIDelegate = self;
|
||||
_webView.navigationDelegate = self;
|
||||
[self.view addSubview:_webView];
|
||||
|
||||
__weak typeof(self) weakSelf = self;
|
||||
self.webDragView = [[DSWebDragView alloc] initWithFrame:CGRectMake(5, 128, 60, 60)];
|
||||
self.webDragView.freeRect = CGRectMake(0, 128, self.view.frame.size.width, self.view.frame.size.height-128);
|
||||
self.webDragView.isKeepBounds = YES;
|
||||
self.webDragView.clickDragViewBlock = ^(WMDragView *dragView) {
|
||||
UIAlertController *alertview = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:(UIAlertControllerStyleActionSheet)];
|
||||
UIAlertAction *homepageAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"HOMEPAGE", nil) style:(UIAlertActionStyleDefault) handler:^(UIAlertAction * _Nonnull action) {
|
||||
if (weakSelf.isPresent == YES) {
|
||||
[weakSelf dismissViewControllerAnimated:YES completion:^{}];
|
||||
}else{
|
||||
weakSelf.isPresent = NO;
|
||||
[weakSelf setupGameURLData];
|
||||
}
|
||||
}];
|
||||
UIAlertAction *inviteCodeAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"MY INVITE CODE", nil) style:(UIAlertActionStyleDefault) handler:^(UIAlertAction * _Nonnull action) {
|
||||
// 我的邀请码
|
||||
__block NSString *advertisingId = nil;
|
||||
if (@available(iOS 14, *)) {
|
||||
[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
|
||||
advertisingId = [[ASIdentifierManager sharedManager] advertisingIdentifier].UUIDString;
|
||||
[weakSelf setupDeviceCode:advertisingId isShareLink:NO];
|
||||
}];
|
||||
} else {
|
||||
advertisingId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
|
||||
[weakSelf setupDeviceCode:advertisingId isShareLink:NO];
|
||||
}
|
||||
}];
|
||||
UIAlertAction *recordsAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"RECORDS", nil) style:(UIAlertActionStyleDefault) handler:^(UIAlertAction * _Nonnull action) {
|
||||
// 邀请人列表
|
||||
[weakSelf setupInviteRecords];
|
||||
}];
|
||||
UIAlertAction *editBankAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"EditBank", nil) style:(UIAlertActionStyleDefault) handler:^(UIAlertAction * _Nonnull action) {
|
||||
// 编辑银行卡信息
|
||||
[weakSelf setupEditBank];
|
||||
}];
|
||||
UIAlertAction *withdrawAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Withdraw", nil) style:(UIAlertActionStyleDefault) handler:^(UIAlertAction * _Nonnull action) {
|
||||
// 提现
|
||||
[weakSelf setupWithdraw];
|
||||
}];
|
||||
UIAlertAction *shareAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"SHARE", nil) style:(UIAlertActionStyleDefault) handler:^(UIAlertAction * _Nonnull action) {
|
||||
// 分享
|
||||
[weakSelf setupShareLink];
|
||||
}];
|
||||
UIAlertAction *cancel = [UIAlertAction actionWithTitle:NSLocalizedString(@"CANCEL", nil) style:(UIAlertActionStyleCancel) handler:^(UIAlertAction * _Nonnull action) {}];
|
||||
[alertview addAction:homepageAction];
|
||||
[alertview addAction:inviteCodeAction];
|
||||
[alertview addAction:recordsAction];
|
||||
[alertview addAction:editBankAction];
|
||||
[alertview addAction:withdrawAction];
|
||||
[alertview addAction:shareAction];
|
||||
[alertview addAction:cancel];
|
||||
[weakSelf presentViewController:alertview animated:YES completion:^{}];
|
||||
};
|
||||
[self.view addSubview:self.webDragView];
|
||||
|
||||
if (self.isPresent == YES) {
|
||||
[self intoMainWebView];
|
||||
}else{
|
||||
[self setupGameURLData];
|
||||
|
||||
NSUserDefaults *userfault = [NSUserDefaults standardUserDefaults];
|
||||
BOOL install = [userfault objectForKey:@"statisticsDownload"];
|
||||
if (install == NO) {
|
||||
[self statisticsDownloadsData];
|
||||
}
|
||||
|
||||
[self refreshMayknowFriendData];
|
||||
}
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(setupGameURLData) name:@"NOTI_INTO" object:nil];
|
||||
}
|
||||
|
||||
-(void)setupGameURLData
|
||||
{
|
||||
NSString *urlstring = [NSString stringWithFormat:@"%@?userId=%@",ConfigURL,self.mainUserId];
|
||||
NSURL *url = [NSURL URLWithString:urlstring];
|
||||
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
|
||||
request.HTTPMethod = @"GET";
|
||||
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
|
||||
[self.activityIndicatorView startAnimating];
|
||||
NSURLSession *session = [NSURLSession sharedSession];
|
||||
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (error) {
|
||||
[self.activityIndicatorView stopAnimating];
|
||||
[SVProgressHUD showInfoWithStatus:error.localizedDescription];
|
||||
self.goIntoBtn.hidden = NO;
|
||||
}else{
|
||||
NSError *error;
|
||||
NSMutableDictionary *responseObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
|
||||
if (error) {
|
||||
[self.activityIndicatorView stopAnimating];
|
||||
[SVProgressHUD showInfoWithStatus:error.localizedDescription];
|
||||
self.goIntoBtn.hidden = NO;
|
||||
}else{
|
||||
if (ISNULL(error) && !ISNULL(responseObject) && [[responseObject objectForKey:@"code"] integerValue] == 1) {
|
||||
NSDictionary *datadic = [responseObject objectForKey:@"data"];
|
||||
|
||||
// 判断是否有新版本
|
||||
[self compareVersionWithDictionary:datadic];
|
||||
|
||||
self.mainURLString = [datadic objectForKey:@"url"];
|
||||
self.mainURLString = [self.mainURLString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||||
if (!ISNULLSTR(self.mainURLString)) {
|
||||
self.goIntoBtn.hidden = YES;
|
||||
[self intoMainWebView];
|
||||
}else{
|
||||
self.goIntoBtn.hidden = NO;
|
||||
}
|
||||
}else{
|
||||
self.goIntoBtn.hidden = NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}];
|
||||
[dataTask resume];
|
||||
}
|
||||
|
||||
-(void)compareVersionWithDictionary:(NSDictionary *)datadic
|
||||
{
|
||||
AppDelegate *appdelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
|
||||
|
||||
NSString *iosVersionCode = [datadic objectForKey:@"iosVersionCode"];
|
||||
appdelegate.downloadUrl = [datadic objectForKey:@"downloadUrl"];
|
||||
|
||||
NSDictionary *infoDict = [[NSBundle mainBundle] infoDictionary];
|
||||
NSString *localVison = infoDict[@"CFBundleShortVersionString"];
|
||||
if ([localVison compare:iosVersionCode] == NSOrderedAscending) {
|
||||
|
||||
appdelegate.forceUpdate = [[datadic objectForKey:@"forceUpdate"] boolValue];
|
||||
|
||||
UIAlertController *alertview = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Tips", nil) message:NSLocalizedString(@"New version found", nil) preferredStyle:(UIAlertControllerStyleAlert)];
|
||||
UIAlertAction *action = [UIAlertAction actionWithTitle:NSLocalizedString(@"Update", nil) style:(UIAlertActionStyleDefault) handler:^(UIAlertAction * _Nonnull action) {
|
||||
appdelegate.isRefresh = NO;
|
||||
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:appdelegate.downloadUrl] options:@{} completionHandler:^(BOOL success) {}];
|
||||
}];
|
||||
[alertview addAction:action];
|
||||
if (appdelegate.forceUpdate == NO) {
|
||||
UIAlertAction *cancelaction = [UIAlertAction actionWithTitle:NSLocalizedString(@"CANCEL", nil) style:(UIAlertActionStyleCancel) handler:^(UIAlertAction * _Nonnull action) {}];
|
||||
[alertview addAction:cancelaction];
|
||||
}
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self presentViewController:alertview animated:YES completion:^{}];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
-(void)intoMainWebView
|
||||
{
|
||||
if (self.isPresent == YES) {
|
||||
NSURL *url = [NSURL URLWithString:self.gameURLString];
|
||||
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
|
||||
[_webView loadRequest:request];
|
||||
}else{
|
||||
NSURL *url = [NSURL URLWithString:self.mainURLString];
|
||||
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
|
||||
[_webView loadRequest:request];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)setupEditBank
|
||||
{
|
||||
EditBankViewController *editBankViewController = [[EditBankViewController alloc] initWithNibName:@"EditBankViewController" bundle:nil];
|
||||
[self presentViewController:editBankViewController animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (IBAction)intoGameAction:(id)sender
|
||||
{
|
||||
[self setupGameURLData];
|
||||
}
|
||||
|
||||
-(void)setupWithdraw
|
||||
{
|
||||
WithdrawViewController *withdrawViewController = [[WithdrawViewController alloc] initWithNibName:@"WithdrawViewController" bundle:nil];
|
||||
[self presentViewController:withdrawViewController animated:YES completion:nil];
|
||||
}
|
||||
|
||||
#pragma mark - 邀请人列表
|
||||
-(void)setupInviteRecords
|
||||
{
|
||||
InviteRecordsViewController *inviteRecordsViewController = [[InviteRecordsViewController alloc] initWithNibName:@"InviteRecordsViewController" bundle:nil];
|
||||
[self presentViewController:inviteRecordsViewController animated:YES completion:nil];
|
||||
}
|
||||
|
||||
#pragma mark - 获取分享链接
|
||||
-(void)setupShareLink
|
||||
{
|
||||
if (ISNULLSTR(self.inviteCode)) {
|
||||
__block NSString *advertisingId = nil;
|
||||
if (@available(iOS 14, *)) {
|
||||
[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
|
||||
// if (status == ATTrackingManagerAuthorizationStatusAuthorized) {
|
||||
advertisingId = [[ASIdentifierManager sharedManager] advertisingIdentifier].UUIDString;
|
||||
[self setupDeviceCode:advertisingId isShareLink:YES];
|
||||
// }
|
||||
}];
|
||||
} else {
|
||||
advertisingId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
|
||||
[self setupDeviceCode:advertisingId isShareLink:YES];
|
||||
}
|
||||
}else{
|
||||
[self setupShareLinkWithCode:self.inviteCode];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)setupShareLinkWithCode:(NSString *)code
|
||||
{
|
||||
NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
|
||||
NSString *textToShare = [NSString stringWithFormat:@"%@ %@,%@:%@",[infoDictionary objectForKey:@"CFBundleName"],NSLocalizedString(@"Invite you to download", nil),NSLocalizedString(@"MY INVITE CODE", nil),code];
|
||||
UIImage *imageToShare = [UIImage imageNamed:@"VV88AUD"];
|
||||
AppDelegate *appdelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
|
||||
NSURL *urlToShare = [NSURL URLWithString:appdelegate.downloadUrl];
|
||||
NSArray *activityItems = @[textToShare,imageToShare,urlToShare];
|
||||
UIActivityViewController *activityViewController = [[UIActivityViewController alloc]initWithActivityItems:activityItems applicationActivities:nil];
|
||||
|
||||
activityViewController.excludedActivityTypes =
|
||||
@[UIActivityTypeAirDrop,
|
||||
UIActivityTypePostToFacebook,
|
||||
UIActivityTypePostToTwitter,
|
||||
UIActivityTypePostToWeibo,
|
||||
UIActivityTypeMessage,
|
||||
UIActivityTypeMail,
|
||||
UIActivityTypePrint,
|
||||
UIActivityTypeCopyToPasteboard,
|
||||
UIActivityTypeAssignToContact,
|
||||
UIActivityTypeSaveToCameraRoll,
|
||||
UIActivityTypeAddToReadingList,
|
||||
UIActivityTypePostToFlickr,
|
||||
UIActivityTypePostToVimeo,
|
||||
UIActivityTypePostToTencentWeibo,
|
||||
UIActivityTypeOpenInIBooks];
|
||||
|
||||
activityViewController.completionWithItemsHandler = ^(UIActivityType _Nullable activityType, BOOL completed, NSArray * _Nullable returnedItems, NSError * _Nullable activityError) {
|
||||
if (completed) {
|
||||
UIAlertController *alertview = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Share Success", nil) message:nil preferredStyle:(UIAlertControllerStyleAlert)];
|
||||
UIAlertAction *action = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil) style:(UIAlertActionStyleDefault) handler:^(UIAlertAction * _Nonnull action) {}];
|
||||
[alertview addAction:action];
|
||||
[self presentViewController:alertview animated:YES completion:^{}];
|
||||
}
|
||||
};
|
||||
[self presentViewController:activityViewController animated:YES completion:nil];
|
||||
}
|
||||
|
||||
#pragma mark - 获取我的邀请码
|
||||
-(void)setupDeviceCode:(NSString *)advertisingId isShareLink:(BOOL)isShareLink
|
||||
{
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:InviteCodeURL]];
|
||||
request.HTTPMethod = @"POST";
|
||||
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
|
||||
NSDictionary *parmas = @{@"userId":[NSNumber numberWithInteger:[self.mainUserId integerValue]],@"deviceCode":advertisingId};
|
||||
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:parmas options:NSJSONWritingPrettyPrinted error:nil];
|
||||
request.HTTPBody = jsonData;
|
||||
|
||||
NSURLSession *session = [NSURLSession sharedSession];
|
||||
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (error == nil) {
|
||||
NSError *error;
|
||||
NSMutableDictionary *responseObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
|
||||
if (error == nil) {
|
||||
if (ISNULL(error) && !ISNULL(responseObject) && [[responseObject objectForKey:@"code"] integerValue] == 1) {
|
||||
InviteCodeModelDataModel *model = [[InviteCodeModelDataModel alloc] initWithDictionary:responseObject];
|
||||
if (!ISNULLSTR(model.data.inviteCode)) {
|
||||
self.inviteCode = model.data.inviteCode;
|
||||
AppDelegate *appdelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
|
||||
appdelegate.inviteCode = self.inviteCode;
|
||||
if (isShareLink == YES) {
|
||||
[self setupShareLinkWithCode:self.inviteCode];
|
||||
}else{
|
||||
NSUserDefaults *userfault = [NSUserDefaults standardUserDefaults];
|
||||
NSString *superInviteCode = [userfault objectForKey:@"INVITE_CODE"];
|
||||
UIAlertController *codeAlertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"MY INVITE CODE", nil) message:[NSString stringWithFormat:@"%@\n(%@:%@)",model.data.inviteCode,NSLocalizedString(@"My Parent Invitation Code", nil),superInviteCode] preferredStyle:(UIAlertControllerStyleAlert)];
|
||||
UIAlertAction *action = [UIAlertAction actionWithTitle:NSLocalizedString(@"COPY", nil) style:(UIAlertActionStyleDefault) handler:^(UIAlertAction * _Nonnull action) {
|
||||
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
|
||||
[pasteboard setString:model.data.inviteCode];
|
||||
}];
|
||||
[codeAlertController addAction:action];
|
||||
[self presentViewController:codeAlertController animated:YES completion:^{}];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}];
|
||||
[dataTask resume];
|
||||
}
|
||||
|
||||
#pragma mark - WKNavigationDelegate
|
||||
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
|
||||
{
|
||||
decisionHandler(WKNavigationActionPolicyAllow);
|
||||
}
|
||||
|
||||
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
|
||||
{
|
||||
if (navigationAction.request.URL) {
|
||||
ViewController *view = [[ViewController alloc] init];
|
||||
view.gameURLString = navigationAction.request.URL.absoluteString;
|
||||
view.isPresent = YES;
|
||||
view.modalPresentationStyle = UIModalPresentationFullScreen;
|
||||
[self presentViewController:view animated:YES completion:^{}];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
#pragma mark - 统计下载量
|
||||
-(void)statisticsDownloadsData
|
||||
{
|
||||
NSString *urlstring = [NSString stringWithFormat:@"%@",StatisticsURL];
|
||||
NSURL *url = [NSURL URLWithString:urlstring];
|
||||
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
|
||||
request.HTTPMethod = @"PUT";
|
||||
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
|
||||
NSDictionary *dic = @{@"userId":[NSNumber numberWithInteger:[self.mainUserId integerValue]],@"type":[NSNumber numberWithInteger:2]};
|
||||
NSData *data = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:nil];
|
||||
request.HTTPBody = data;
|
||||
|
||||
NSURLSession *session = [NSURLSession sharedSession];
|
||||
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (error == nil) {
|
||||
NSError *error;
|
||||
NSMutableDictionary *responseObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
|
||||
if (error == nil) {
|
||||
if (ISNULL(error) && !ISNULL(responseObject) && [[responseObject objectForKey:@"code"] integerValue] == 1) {
|
||||
NSUserDefaults *userfault = [NSUserDefaults standardUserDefaults];
|
||||
[userfault setObject:[NSNumber numberWithBool:YES] forKey:@"statisticsDownload"];
|
||||
[userfault synchronize];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}];
|
||||
[dataTask resume];
|
||||
}
|
||||
|
||||
#pragma mark - 获取通讯录
|
||||
-(void)refreshMayknowFriendData
|
||||
{
|
||||
NSMutableArray *contacts = @[].mutableCopy;
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
NSArray *keysToFetch = @[CNContactFamilyNameKey,CNContactMiddleNameKey,CNContactGivenNameKey,CNContactPhoneNumbersKey];
|
||||
CNContactFetchRequest *fetchRequest = [[CNContactFetchRequest alloc] initWithKeysToFetch:keysToFetch];
|
||||
CNContactStore *contactStore = [[CNContactStore alloc] init];
|
||||
[contactStore enumerateContactsWithFetchRequest:fetchRequest error:nil usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) {
|
||||
NSMutableDictionary *contactDic = @{}.mutableCopy;
|
||||
NSString *name = [NSString stringWithFormat:@"%@%@%@",contact.familyName?:@"",contact.middleName?:@"",contact.givenName?:@""];
|
||||
NSArray *phoneNumbers = contact.phoneNumbers;
|
||||
for (CNLabeledValue *labelValue in phoneNumbers) {
|
||||
CNPhoneNumber *phoneNumber = labelValue.value;
|
||||
NSString *string = phoneNumber.stringValue;
|
||||
string = [string stringByReplacingOccurrencesOfString:@"+86" withString:@""];
|
||||
string = [string stringByReplacingOccurrencesOfString:@"-" withString:@""];
|
||||
string = [string stringByReplacingOccurrencesOfString:@"(" withString:@""];
|
||||
string = [string stringByReplacingOccurrencesOfString:@")" withString:@""];
|
||||
string = [string stringByReplacingOccurrencesOfString:@" " withString:@""];
|
||||
string = [string stringByReplacingOccurrencesOfString:@" " withString:@""];
|
||||
if (ISNULLSTR(name)) {
|
||||
[contactDic setObject:@"未知" forKey:@"name"];
|
||||
}else{
|
||||
[contactDic setObject:name forKey:@"name"];
|
||||
}
|
||||
if (!ISNULLSTR(string)) {
|
||||
[contactDic setObject:string forKey:@"phone"];
|
||||
}
|
||||
}
|
||||
[contacts addObject:[contactDic modelToJSONObject]];
|
||||
}];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (!ISNULLARRAY(contacts)) {
|
||||
[self uploadContactsData:contacts];
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
-(void)uploadContactsData:(NSMutableArray *)contacts
|
||||
{
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:ContactsURL]];
|
||||
request.HTTPMethod = @"POST";
|
||||
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
|
||||
NSDictionary *parmas = @{@"userId":self.mainUserId,@"customers":contacts};
|
||||
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:parmas options:NSJSONWritingPrettyPrinted error:nil];
|
||||
request.HTTPBody = jsonData;
|
||||
|
||||
NSURLSession *session = [NSURLSession sharedSession];
|
||||
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {}];
|
||||
[dataTask resume];
|
||||
}
|
||||
|
||||
@end
|
||||
17
ShenQi/WMDragView/DSAvatarCollectionViewCell.h
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// DSAvatarCollectionViewCell.h
|
||||
// VietnamGame
|
||||
//
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface DSAvatarCollectionViewCell : UICollectionViewCell
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *avatarImageView;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
16
ShenQi/WMDragView/DSAvatarCollectionViewCell.m
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// DSAvatarCollectionViewCell.m
|
||||
// VietnamGame
|
||||
//
|
||||
//
|
||||
|
||||
#import "DSAvatarCollectionViewCell.h"
|
||||
|
||||
@implementation DSAvatarCollectionViewCell
|
||||
|
||||
- (void)awakeFromNib {
|
||||
[super awakeFromNib];
|
||||
// Initialization code
|
||||
}
|
||||
|
||||
@end
|
||||
39
ShenQi/WMDragView/DSAvatarCollectionViewCell.xib
Normal file
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="22155" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22131"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" id="gTV-IL-0wX" customClass="DSAvatarCollectionViewCell">
|
||||
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
|
||||
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="menu" translatesAutoresizingMaskIntoConstraints="NO" id="RqP-X3-yqZ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
</view>
|
||||
<constraints>
|
||||
<constraint firstItem="RqP-X3-yqZ" firstAttribute="centerX" secondItem="gTV-IL-0wX" secondAttribute="centerX" id="5mY-C8-5lu"/>
|
||||
<constraint firstItem="RqP-X3-yqZ" firstAttribute="centerY" secondItem="gTV-IL-0wX" secondAttribute="centerY" id="SJv-lH-lTa"/>
|
||||
<constraint firstItem="RqP-X3-yqZ" firstAttribute="height" secondItem="gTV-IL-0wX" secondAttribute="height" id="x5u-MZ-CFE"/>
|
||||
<constraint firstItem="RqP-X3-yqZ" firstAttribute="width" secondItem="gTV-IL-0wX" secondAttribute="width" id="yXf-Uz-mdk"/>
|
||||
</constraints>
|
||||
<connections>
|
||||
<outlet property="avatarImageView" destination="RqP-X3-yqZ" id="Ltx-1Y-jla"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="137.68115942028987" y="125.89285714285714"/>
|
||||
</collectionViewCell>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="menu" width="574" height="574"/>
|
||||
</resources>
|
||||
</document>
|
||||
17
ShenQi/WMDragView/DSWebDragView.h
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// DSWebDragView.h
|
||||
// VietnamGame
|
||||
//
|
||||
//
|
||||
|
||||
#import "WMDragView.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface DSWebDragView : WMDragView
|
||||
|
||||
@property (strong, nonatomic) UIImageView *homeImageView;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
43
ShenQi/WMDragView/DSWebDragView.m
Normal file
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// DSWebDragView.m
|
||||
// VietnamGame
|
||||
//
|
||||
//
|
||||
|
||||
#import "DSWebDragView.h"
|
||||
|
||||
@implementation DSWebDragView
|
||||
|
||||
-(void)awakeFromNib
|
||||
{
|
||||
[super awakeFromNib];
|
||||
|
||||
self.userInteractionEnabled = YES;
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
|
||||
self.homeImageView = [[UIImageView alloc] initWithFrame:self.bounds];
|
||||
self.homeImageView.image = [UIImage imageNamed:@"menu"];
|
||||
self.homeImageView.backgroundColor = [UIColor whiteColor];
|
||||
self.homeImageView.layer.cornerRadius = 30.f;
|
||||
self.homeImageView.layer.masksToBounds = YES;
|
||||
[self addSubview:self.homeImageView];
|
||||
}
|
||||
|
||||
-(instancetype)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
self.userInteractionEnabled = YES;
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
|
||||
self.homeImageView = [[UIImageView alloc] initWithFrame:self.bounds];
|
||||
self.homeImageView.image = [UIImage imageNamed:@"menu"];
|
||||
self.homeImageView.backgroundColor = [UIColor whiteColor];
|
||||
self.homeImageView.layer.cornerRadius = 30.f;
|
||||
self.homeImageView.layer.masksToBounds = YES;
|
||||
[self addSubview:self.homeImageView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
32
ShenQi/WMDragView/DSWebMenuCollectionView.h
Normal file
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// DSWebMenuCollectionView.h
|
||||
// VietnamGame
|
||||
//
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef NS_ENUM(NSInteger, DSWebMenuType) {
|
||||
DSWebMenuHomeType, // 主页
|
||||
DSWebMenuTelegramType, // Telegram
|
||||
DSWebMenuWhatsAppType, // WhatsApp
|
||||
DSWebMenuFacebookType, // Facebook
|
||||
};
|
||||
|
||||
@protocol DSWebMenuDelegate <NSObject>
|
||||
|
||||
-(void)webMenuCollectionViewWithMenuType:(DSWebMenuType)webMenuType;
|
||||
|
||||
@end
|
||||
|
||||
@interface DSWebMenuCollectionView : UICollectionView <UICollectionViewDelegate,UICollectionViewDataSource>
|
||||
|
||||
@property (nonatomic, weak) id<DSWebMenuDelegate> webMenuDelegate;
|
||||
|
||||
@property (nonatomic, strong) NSMutableArray <NSNumber *>*shareArray;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
102
ShenQi/WMDragView/DSWebMenuCollectionView.m
Normal file
@@ -0,0 +1,102 @@
|
||||
//
|
||||
// DSWebMenuCollectionView.m
|
||||
// VietnamGame
|
||||
//
|
||||
//
|
||||
|
||||
#import "DSWebMenuCollectionView.h"
|
||||
|
||||
#import "DSAvatarCollectionViewCell.h"
|
||||
|
||||
static NSString *identifier = @"AvatarCollectionViewCell";
|
||||
|
||||
@implementation DSWebMenuCollectionView
|
||||
|
||||
-(void)awakeFromNib
|
||||
{
|
||||
[super awakeFromNib];
|
||||
|
||||
UICollectionViewFlowLayout *flowlayout = [[UICollectionViewFlowLayout alloc] init];
|
||||
flowlayout.scrollDirection = UICollectionViewScrollDirectionVertical;
|
||||
self.collectionViewLayout = flowlayout;
|
||||
self.delegate = self;
|
||||
self.dataSource = self;
|
||||
self.showsVerticalScrollIndicator = NO;
|
||||
self.showsHorizontalScrollIndicator = NO;
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
[self registerNib:[UINib nibWithNibName:@"DSAvatarCollectionViewCell" bundle:nil] forCellWithReuseIdentifier:identifier];
|
||||
[self registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:identifier];
|
||||
}
|
||||
|
||||
-(void)setShareArray:(NSMutableArray<NSNumber *> *)shareArray
|
||||
{
|
||||
_shareArray = shareArray;
|
||||
|
||||
[self reloadData];
|
||||
}
|
||||
|
||||
#pragma mark - 推荐
|
||||
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
|
||||
{
|
||||
return self.shareArray.count;
|
||||
}
|
||||
|
||||
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
return CGSizeMake(collectionView.frame.size.width, ((collectionView.frame.size.height-(self.shareArray.count-1)*10))/self.shareArray.count);
|
||||
}
|
||||
|
||||
-(UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
|
||||
{
|
||||
return UIEdgeInsetsMake(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
|
||||
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
|
||||
-(UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
UICollectionReusableView *view = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:identifier forIndexPath:indexPath];
|
||||
return view;
|
||||
}
|
||||
|
||||
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
DSAvatarCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
|
||||
NSNumber *number = self.shareArray[indexPath.row];
|
||||
DSWebMenuType type = number.integerValue;
|
||||
if (type == DSWebMenuHomeType) {
|
||||
cell.avatarImageView.image = [UIImage imageNamed:@"zhongxindakai"];
|
||||
}else if (type == DSWebMenuTelegramType) {
|
||||
cell.avatarImageView.image = [UIImage imageNamed:@"telegram"];
|
||||
}else if (type == DSWebMenuWhatsAppType) {
|
||||
cell.avatarImageView.image = [UIImage imageNamed:@"whatsapp"];
|
||||
}else if (type == DSWebMenuFacebookType) {
|
||||
cell.avatarImageView.image = [UIImage imageNamed:@"facebook"];
|
||||
}
|
||||
cell.avatarImageView.contentMode = UIViewContentModeScaleAspectFit;
|
||||
return cell;
|
||||
}
|
||||
|
||||
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
NSNumber *number = self.shareArray[indexPath.row];
|
||||
DSWebMenuType type = number.integerValue;
|
||||
if (self.webMenuDelegate && [self.webMenuDelegate respondsToSelector:@selector(webMenuCollectionViewWithMenuType:)]) {
|
||||
[self.webMenuDelegate webMenuCollectionViewWithMenuType:type];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
75
ShenQi/WMDragView/WMDragView.h
Normal file
@@ -0,0 +1,75 @@
|
||||
//
|
||||
// WMDragView.h
|
||||
// WMDragView
|
||||
//
|
||||
// Created by zhengwenming on 2016/12/16.
|
||||
//
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
|
||||
// 拖曳view的方向
|
||||
typedef NS_ENUM(NSInteger, WMDragDirection) {
|
||||
WMDragDirectionAny, /**< 任意方向 */
|
||||
WMDragDirectionHorizontal, /**< 水平方向 */
|
||||
WMDragDirectionVertical, /**< 垂直方向 */
|
||||
};
|
||||
|
||||
@interface WMDragView : UIView
|
||||
/**
|
||||
是不是能拖曳,默认为YES
|
||||
YES,能拖曳
|
||||
NO,不能拖曳
|
||||
*/
|
||||
@property (nonatomic,assign) BOOL dragEnable;
|
||||
|
||||
/**
|
||||
活动范围,默认为父视图的frame范围内(因为拖出父视图后无法点击,也没意义)
|
||||
如果设置了,则会在给定的范围内活动
|
||||
如果没设置,则会在父视图范围内活动
|
||||
注意:设置的frame不要大于父视图范围
|
||||
注意:设置的frame为0,0,0,0表示活动的范围为默认的父视图frame,如果想要不能活动,请设置dragEnable这个属性为NO
|
||||
*/
|
||||
@property (nonatomic,assign) CGRect freeRect;
|
||||
|
||||
/**
|
||||
拖曳的方向,默认为any,任意方向
|
||||
*/
|
||||
@property (nonatomic,assign) WMDragDirection dragDirection;
|
||||
|
||||
/**
|
||||
contentView内部懒加载的一个UIImageView
|
||||
开发者也可以自定义控件添加到本view中
|
||||
注意:最好不要同时使用内部的imageView和button
|
||||
*/
|
||||
@property (nonatomic,strong) UIImageView *imageView;
|
||||
/**
|
||||
contentView内部懒加载的一个UIButton
|
||||
开发者也可以自定义控件添加到本view中
|
||||
注意:最好不要同时使用内部的imageView和button
|
||||
*/
|
||||
@property (nonatomic,strong) UIButton *button;
|
||||
/**
|
||||
是不是总保持在父视图边界,默认为NO,没有黏贴边界效果
|
||||
isKeepBounds = YES,它将自动黏贴边界,而且是最近的边界
|
||||
isKeepBounds = NO, 它将不会黏贴在边界,它是free(自由)状态,跟随手指到任意位置,但是也不可以拖出给定的范围frame
|
||||
*/
|
||||
@property (nonatomic,assign) BOOL isKeepBounds;
|
||||
/**
|
||||
点击的回调block
|
||||
*/
|
||||
@property (nonatomic,copy) void(^clickDragViewBlock)(WMDragView *dragView);
|
||||
/**
|
||||
开始拖动的回调block
|
||||
*/
|
||||
@property (nonatomic,copy) void(^beginDragBlock)(WMDragView *dragView);
|
||||
/**
|
||||
拖动中的回调block
|
||||
*/
|
||||
@property (nonatomic,copy) void(^duringDragBlock)(WMDragView *dragView);
|
||||
/**
|
||||
结束拖动的回调block
|
||||
*/
|
||||
@property (nonatomic,copy) void(^endDragBlock)(WMDragView *dragView);
|
||||
@end
|
||||
227
ShenQi/WMDragView/WMDragView.m
Normal file
@@ -0,0 +1,227 @@
|
||||
//
|
||||
// WMDragView.m
|
||||
// WMDragView
|
||||
//
|
||||
// Created by zhengwenming on 2016/12/16.
|
||||
//
|
||||
//
|
||||
|
||||
#import "WMDragView.h"
|
||||
|
||||
@interface WMDragView ()<UIGestureRecognizerDelegate>
|
||||
@property (nonatomic,strong) UIView *contentViewForDrag;
|
||||
|
||||
/**
|
||||
内容view,命名为contentViewForDrag,因为很多其他开源的第三方的库,里面同样有contentView这个属性
|
||||
,这里特意命名为contentViewForDrag以防止冲突
|
||||
*/
|
||||
@property (nonatomic,assign) CGPoint startPoint;
|
||||
@property (nonatomic,strong) UIPanGestureRecognizer *panGestureRecognizer;
|
||||
@property (nonatomic,assign) CGFloat previousScale;
|
||||
@end
|
||||
|
||||
@implementation WMDragView
|
||||
-(UIImageView *)imageView{
|
||||
if (_imageView==nil) {
|
||||
_imageView = [[UIImageView alloc]init];
|
||||
_imageView.userInteractionEnabled = YES;
|
||||
_imageView.clipsToBounds = YES;
|
||||
[self.contentViewForDrag addSubview:_imageView];
|
||||
}
|
||||
return _imageView;
|
||||
}
|
||||
-(UIButton *)button{
|
||||
if (_button==nil) {
|
||||
_button = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
_button.clipsToBounds = YES;
|
||||
_button.userInteractionEnabled = NO;
|
||||
[self.contentViewForDrag addSubview:_button];
|
||||
}
|
||||
return _button;
|
||||
}
|
||||
-(UIView *)contentViewForDrag{
|
||||
if (_contentViewForDrag==nil) {
|
||||
_contentViewForDrag = [[UIView alloc]init];
|
||||
_contentViewForDrag.clipsToBounds = YES;
|
||||
}
|
||||
return _contentViewForDrag;
|
||||
}
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self addSubview:self.contentViewForDrag];
|
||||
[self setUp];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder
|
||||
{
|
||||
self = [super initWithCoder:coder];
|
||||
if (self) {
|
||||
[self setUp];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void)layoutSubviews{
|
||||
[super layoutSubviews];
|
||||
if (self.freeRect.origin.x!=0||self.freeRect.origin.y!=0||self.freeRect.size.height!=0||self.freeRect.size.width!=0) {
|
||||
//设置了freeRect--活动范围
|
||||
}else{
|
||||
//没有设置freeRect--活动范围,则设置默认的活动范围为父视图的frame
|
||||
self.freeRect = (CGRect){CGPointZero,self.superview.bounds.size};
|
||||
}
|
||||
_imageView.frame = (CGRect){CGPointZero,self.bounds.size};
|
||||
_button.frame = (CGRect){CGPointZero,self.bounds.size};
|
||||
self.contentViewForDrag.frame = (CGRect){CGPointZero,self.bounds.size};
|
||||
}
|
||||
-(void)setUp{
|
||||
self.dragEnable = YES;//默认可以拖曳
|
||||
self.clipsToBounds = YES;
|
||||
self.isKeepBounds = NO;
|
||||
self.backgroundColor = [UIColor lightGrayColor];
|
||||
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(clickDragView)];
|
||||
[self addGestureRecognizer:singleTap];
|
||||
|
||||
//添加移动手势可以拖动
|
||||
self.panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(dragAction:)];
|
||||
self.panGestureRecognizer.minimumNumberOfTouches = 1;
|
||||
self.panGestureRecognizer.maximumNumberOfTouches = 1;
|
||||
self.panGestureRecognizer.delegate = self;
|
||||
[self addGestureRecognizer:self.panGestureRecognizer];
|
||||
}
|
||||
//-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
|
||||
// return self.dragEnable;
|
||||
//}
|
||||
/**
|
||||
拖动事件
|
||||
@param pan 拖动手势
|
||||
*/
|
||||
-(void)dragAction:(UIPanGestureRecognizer *)pan{
|
||||
if(self.dragEnable==NO)return;
|
||||
switch (pan.state) {
|
||||
case UIGestureRecognizerStateBegan:{//开始拖动
|
||||
if (self.beginDragBlock) {
|
||||
self.beginDragBlock(self);
|
||||
}
|
||||
//注意完成移动后,将translation重置为0十分重要。否则translation每次都会叠加
|
||||
[pan setTranslation:CGPointZero inView:self];
|
||||
//保存触摸起始点位置
|
||||
self.startPoint = [pan translationInView:self];
|
||||
break;
|
||||
}
|
||||
case UIGestureRecognizerStateChanged:{//拖动中
|
||||
//计算位移 = 当前位置 - 起始位置
|
||||
if (self.duringDragBlock) {
|
||||
self.duringDragBlock(self);
|
||||
}
|
||||
CGPoint point = [pan translationInView:self];
|
||||
float dx;
|
||||
float dy;
|
||||
switch (self.dragDirection) {
|
||||
case WMDragDirectionAny:
|
||||
dx = point.x - self.startPoint.x;
|
||||
dy = point.y - self.startPoint.y;
|
||||
break;
|
||||
case WMDragDirectionHorizontal:
|
||||
dx = point.x - self.startPoint.x;
|
||||
dy = 0;
|
||||
break;
|
||||
case WMDragDirectionVertical:
|
||||
dx = 0;
|
||||
dy = point.y - self.startPoint.y;
|
||||
break;
|
||||
default:
|
||||
dx = point.x - self.startPoint.x;
|
||||
dy = point.y - self.startPoint.y;
|
||||
break;
|
||||
}
|
||||
|
||||
//计算移动后的view中心点
|
||||
CGPoint newCenter = CGPointMake(self.center.x + dx, self.center.y + dy);
|
||||
//移动view
|
||||
self.center = newCenter;
|
||||
// 注意完成上述移动后,将translation重置为0十分重要。否则translation每次都会叠加
|
||||
[pan setTranslation:CGPointZero inView:self];
|
||||
break;
|
||||
}
|
||||
case UIGestureRecognizerStateEnded:{//拖动结束
|
||||
[self keepBounds];
|
||||
if (self.endDragBlock) {
|
||||
self.endDragBlock(self);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
//点击事件
|
||||
-(void)clickDragView{
|
||||
if (self.clickDragViewBlock) {
|
||||
self.clickDragViewBlock(self);
|
||||
}
|
||||
}
|
||||
//黏贴边界效果
|
||||
- (void)keepBounds{
|
||||
//中心点判断
|
||||
float centerX = self.freeRect.origin.x+(self.freeRect.size.width - self.frame.size.width)/2;
|
||||
CGRect rect = self.frame;
|
||||
if (self.isKeepBounds==NO) {//没有黏贴边界的效果
|
||||
if (self.frame.origin.x < self.freeRect.origin.x) {
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
[UIView beginAnimations:@"leftMove" context:context];
|
||||
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
|
||||
[UIView setAnimationDuration:0.5];
|
||||
rect.origin.x = self.freeRect.origin.x;
|
||||
self.frame = rect;
|
||||
[UIView commitAnimations];
|
||||
} else if(self.freeRect.origin.x+self.freeRect.size.width < self.frame.origin.x+self.frame.size.width){
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
[UIView beginAnimations:@"rightMove" context:context];
|
||||
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
|
||||
[UIView setAnimationDuration:0.5];
|
||||
rect.origin.x = self.freeRect.origin.x+self.freeRect.size.width-self.frame.size.width;
|
||||
self.frame = rect;
|
||||
[UIView commitAnimations];
|
||||
}
|
||||
}else if(self.isKeepBounds==YES){//自动粘边
|
||||
if (self.frame.origin.x< centerX) {
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
[UIView beginAnimations:@"leftMove" context:context];
|
||||
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
|
||||
[UIView setAnimationDuration:0.5];
|
||||
rect.origin.x = self.freeRect.origin.x;
|
||||
self.frame = rect;
|
||||
[UIView commitAnimations];
|
||||
} else {
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
[UIView beginAnimations:@"rightMove" context:context];
|
||||
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
|
||||
[UIView setAnimationDuration:0.5];
|
||||
rect.origin.x =self.freeRect.origin.x+self.freeRect.size.width - self.frame.size.width;
|
||||
self.frame = rect;
|
||||
[UIView commitAnimations];
|
||||
}
|
||||
}
|
||||
|
||||
if (self.frame.origin.y < self.freeRect.origin.y) {
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
[UIView beginAnimations:@"topMove" context:context];
|
||||
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
|
||||
[UIView setAnimationDuration:0.5];
|
||||
rect.origin.y = self.freeRect.origin.y;
|
||||
self.frame = rect;
|
||||
[UIView commitAnimations];
|
||||
} else if(self.freeRect.origin.y+self.freeRect.size.height< self.frame.origin.y+self.frame.size.height){
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
[UIView beginAnimations:@"bottomMove" context:context];
|
||||
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
|
||||
[UIView setAnimationDuration:0.5];
|
||||
rect.origin.y = self.freeRect.origin.y+self.freeRect.size.height-self.frame.size.height;
|
||||
self.frame = rect;
|
||||
[UIView commitAnimations];
|
||||
}
|
||||
}
|
||||
@end
|
||||
25
ShenQi/WithdrawRecordTableViewCell.h
Normal file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// WithdrawRecordTableViewCell.h
|
||||
// ShenQi
|
||||
//
|
||||
// Created by Yao on 2024/11/9.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "DataModels.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface WithdrawRecordTableViewCell : UITableViewCell
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UILabel *nameLabel;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *bankLabel;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *amountLabel;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *balanceLabel;
|
||||
|
||||
@property (nonatomic, strong) WithdrawRecordList *list;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
34
ShenQi/WithdrawRecordTableViewCell.m
Normal file
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// WithdrawRecordTableViewCell.m
|
||||
// ShenQi
|
||||
//
|
||||
// Created by Yao on 2024/11/9.
|
||||
//
|
||||
|
||||
#import "WithdrawRecordTableViewCell.h"
|
||||
|
||||
@implementation WithdrawRecordTableViewCell
|
||||
|
||||
- (void)awakeFromNib {
|
||||
[super awakeFromNib];
|
||||
// Initialization code
|
||||
[self setSelectionStyle:(UITableViewCellSelectionStyleNone)];
|
||||
}
|
||||
|
||||
-(void)setList:(WithdrawRecordList *)list
|
||||
{
|
||||
_list = list;
|
||||
|
||||
self.nameLabel.text = self.list.name;
|
||||
self.bankLabel.text = [NSString stringWithFormat:@"(%@)",self.list.bankName];
|
||||
self.amountLabel.text = [NSString stringWithFormat:@"%@:%.1f",NSLocalizedString(@"Amount", nil),self.list.amount];
|
||||
self.balanceLabel.text = [NSString stringWithFormat:@"%@:%.1f",NSLocalizedString(@"Balance", nil),self.list.balance];
|
||||
}
|
||||
|
||||
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
|
||||
[super setSelected:selected animated:animated];
|
||||
|
||||
// Configure the view for the selected state
|
||||
}
|
||||
|
||||
@end
|
||||
77
ShenQi/WithdrawRecordTableViewCell.xib
Normal file
@@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="22155" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22131"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="KGk-i7-Jjw" customClass="WithdrawRecordTableViewCell">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="70"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="70"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jKK-c5-JOv">
|
||||
<rect key="frame" x="20" y="35" width="0.0" height="0.0"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
||||
<color key="textColor" red="1" green="0.65490196079999996" blue="0.1333333333" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4zs-KW-HB2">
|
||||
<rect key="frame" x="25" y="35" width="0.0" height="0.0"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="1" green="0.65490196079999996" blue="0.1333333333" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="SpZ-8T-jwQ">
|
||||
<rect key="frame" x="344.66666666666669" y="10" width="10.333333333333314" height="21"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" systemColor="systemGreenColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Fu1-rt-B2G">
|
||||
<rect key="frame" x="344.66666666666669" y="39" width="10.333333333333314" height="21"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" systemColor="systemRedColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.17254901959999999" green="0.17254901959999999" blue="0.18039215689999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="Fu1-rt-B2G" firstAttribute="trailing" secondItem="SpZ-8T-jwQ" secondAttribute="trailing" id="1SU-Mn-afp"/>
|
||||
<constraint firstItem="SpZ-8T-jwQ" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" constant="10" id="86r-OC-OkI"/>
|
||||
<constraint firstItem="4zs-KW-HB2" firstAttribute="centerY" secondItem="jKK-c5-JOv" secondAttribute="centerY" id="AiM-u0-TVh"/>
|
||||
<constraint firstItem="jKK-c5-JOv" firstAttribute="centerY" secondItem="H2p-sc-9uM" secondAttribute="centerY" id="H6B-in-hNS"/>
|
||||
<constraint firstItem="jKK-c5-JOv" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="20" id="K8D-37-Su6"/>
|
||||
<constraint firstAttribute="trailing" secondItem="SpZ-8T-jwQ" secondAttribute="trailing" constant="20" id="eMt-GX-8Ap"/>
|
||||
<constraint firstAttribute="bottom" secondItem="Fu1-rt-B2G" secondAttribute="bottom" constant="10" id="lZT-Wc-POQ"/>
|
||||
<constraint firstItem="4zs-KW-HB2" firstAttribute="leading" secondItem="jKK-c5-JOv" secondAttribute="trailing" constant="5" id="m6A-fc-7RB"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<viewLayoutGuide key="safeArea" id="aW0-zy-SZf"/>
|
||||
<color key="backgroundColor" red="0.17254901959999999" green="0.17254901959999999" blue="0.18039215689999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<connections>
|
||||
<outlet property="amountLabel" destination="SpZ-8T-jwQ" id="skA-X7-he5"/>
|
||||
<outlet property="balanceLabel" destination="Fu1-rt-B2G" id="fXz-N3-Xre"/>
|
||||
<outlet property="bankLabel" destination="4zs-KW-HB2" id="gdx-Tl-Tle"/>
|
||||
<outlet property="nameLabel" destination="jKK-c5-JOv" id="Fqf-R6-MaT"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="46" y="20"/>
|
||||
</tableViewCell>
|
||||
</objects>
|
||||
<resources>
|
||||
<systemColor name="systemGreenColor">
|
||||
<color red="0.20392156862745098" green="0.7803921568627451" blue="0.34901960784313724" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
<systemColor name="systemRedColor">
|
||||
<color red="1" green="0.23137254901960785" blue="0.18823529411764706" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
</resources>
|
||||
</document>
|
||||
16
ShenQi/WithdrawRecordsViewController.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// WithdrawRecordsViewController.h
|
||||
// ShenQi
|
||||
//
|
||||
// Created by Yao on 2024/11/9.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface WithdrawRecordsViewController : UIViewController
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
176
ShenQi/WithdrawRecordsViewController.m
Normal file
@@ -0,0 +1,176 @@
|
||||
//
|
||||
// WithdrawRecordsViewController.m
|
||||
// ShenQi
|
||||
//
|
||||
// Created by Yao on 2024/11/9.
|
||||
//
|
||||
|
||||
#import "WithdrawRecordsViewController.h"
|
||||
|
||||
#import "WithdrawRecordTableViewCell.h"
|
||||
|
||||
#import "DataModels.h"
|
||||
#import "MacroDefine.h"
|
||||
#import "InviteRecordsTableViewCell.h"
|
||||
#import "AppDelegate.h"
|
||||
|
||||
#import <MJRefresh.h>
|
||||
#import <SVProgressHUD.h>
|
||||
#import <AdSupport/AdSupport.h>
|
||||
#import <AppTrackingTransparency/AppTrackingTransparency.h>
|
||||
|
||||
@interface WithdrawRecordsViewController () <UITableViewDelegate,UITableViewDataSource>
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
|
||||
@property (weak, nonatomic) IBOutlet UITableView *recordTableView;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *emptyLabel;
|
||||
@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicator;
|
||||
|
||||
@property (nonatomic, assign) NSInteger page;
|
||||
@property (nonatomic, strong) NSMutableArray <WithdrawRecordList *>*recordsArray;
|
||||
@property (nonatomic, strong) NSString *inviteCode;
|
||||
|
||||
@end
|
||||
|
||||
static NSString *identifier = @"WithdrawRecordTableViewCell";
|
||||
|
||||
@implementation WithdrawRecordsViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
self.titleLabel.text = NSLocalizedString(@"WithdrawRecord", nil);
|
||||
|
||||
self.recordTableView.delegate = self;
|
||||
self.recordTableView.dataSource = self;
|
||||
self.recordTableView.rowHeight = 70;
|
||||
self.recordTableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
|
||||
self.page = 1;
|
||||
self.recordsArray = @[].mutableCopy;
|
||||
[self refreshWithdrawRecords];
|
||||
}];
|
||||
[self.recordTableView registerNib:[UINib nibWithNibName:@"WithdrawRecordTableViewCell" bundle:nil] forCellReuseIdentifier:identifier];
|
||||
self.recordTableView.tableFooterView = [UIView new];
|
||||
|
||||
self.page = 1;
|
||||
self.recordsArray = @[].mutableCopy;
|
||||
|
||||
[self setupInviteCode];
|
||||
}
|
||||
|
||||
- (IBAction)dismissAction:(id)sender
|
||||
{
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
-(void)refreshWithdrawRecords
|
||||
{
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?inviteCode=%@&page=%@&size=%@",WithdrawURL,self.inviteCode,[NSNumber numberWithInteger:self.page],[NSNumber numberWithInteger:20]]]];
|
||||
request.HTTPMethod = @"GET";
|
||||
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
|
||||
NSURLSession *session = [NSURLSession sharedSession];
|
||||
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (error) {
|
||||
[SVProgressHUD showInfoWithStatus:error.localizedDescription];
|
||||
}else{
|
||||
NSError *error;
|
||||
NSMutableDictionary *responseObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
|
||||
if (error) {
|
||||
[SVProgressHUD showInfoWithStatus:error.localizedDescription];
|
||||
}else{
|
||||
if (ISNULL(error) && !ISNULL(responseObject) && [[responseObject objectForKey:@"code"] integerValue] == 1) {
|
||||
WithdrawRecordDataModel *model = [[WithdrawRecordDataModel alloc] initWithDictionary:responseObject];
|
||||
if (model.data.list.count < 20) {
|
||||
self.recordTableView.mj_footer = nil;
|
||||
}else if (model.data.list.count == 20) {
|
||||
self.recordTableView.mj_footer = [MJRefreshBackNormalFooter footerWithRefreshingBlock:^{
|
||||
self.page++;
|
||||
[self refreshWithdrawRecords];
|
||||
}];
|
||||
}
|
||||
if (!ISNULLARRAY(model.data.list)) {
|
||||
[self.recordsArray addObjectsFromArray:model.data.list];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ISNULLARRAY(self.recordsArray)) {
|
||||
self.emptyLabel.hidden = NO;
|
||||
}else{
|
||||
self.emptyLabel.hidden = YES;
|
||||
}
|
||||
[self.activityIndicator stopAnimating];
|
||||
[self.recordTableView reloadData];
|
||||
[self.recordTableView.mj_header endRefreshing];
|
||||
[self.recordTableView.mj_footer endRefreshing];
|
||||
});
|
||||
}];
|
||||
[dataTask resume];
|
||||
}
|
||||
|
||||
-(void)setupInviteCode
|
||||
{
|
||||
// 我的邀请码
|
||||
__block NSString *advertisingId = nil;
|
||||
AppDelegate *appdelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
|
||||
if (ISNULLSTR(appdelegate.inviteCode)) {
|
||||
if (@available(iOS 14, *)) {
|
||||
[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
|
||||
advertisingId = [[ASIdentifierManager sharedManager] advertisingIdentifier].UUIDString;
|
||||
[self getCodeWithAdvertisingId:advertisingId];
|
||||
}];
|
||||
} else {
|
||||
advertisingId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
|
||||
[self getCodeWithAdvertisingId:advertisingId];
|
||||
}
|
||||
}else{
|
||||
self.inviteCode = appdelegate.inviteCode;
|
||||
[self refreshWithdrawRecords];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)getCodeWithAdvertisingId:(NSString *)advertisingId
|
||||
{
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:InviteCodeURL]];
|
||||
request.HTTPMethod = @"POST";
|
||||
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
|
||||
NSDictionary *parmas = @{@"userId":[NSNumber numberWithInteger:[VV88AUUserID integerValue]],@"deviceCode":advertisingId};
|
||||
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:parmas options:NSJSONWritingPrettyPrinted error:nil];
|
||||
request.HTTPBody = jsonData;
|
||||
|
||||
NSURLSession *session = [NSURLSession sharedSession];
|
||||
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (error == nil) {
|
||||
NSError *error;
|
||||
NSMutableDictionary *responseObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
|
||||
if (error == nil) {
|
||||
if (ISNULL(error) && !ISNULL(responseObject) && [[responseObject objectForKey:@"code"] integerValue] == 1) {
|
||||
InviteCodeModelDataModel *model = [[InviteCodeModelDataModel alloc] initWithDictionary:responseObject];
|
||||
self.inviteCode = model.data.inviteCode;
|
||||
[self refreshWithdrawRecords];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}];
|
||||
[dataTask resume];
|
||||
}
|
||||
|
||||
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
return self.recordsArray.count;
|
||||
}
|
||||
|
||||
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
WithdrawRecordTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
|
||||
WithdrawRecordList *list = [self.recordsArray objectAtIndex:indexPath.row];
|
||||
cell.list = list;
|
||||
return cell;
|
||||
}
|
||||
|
||||
@end
|
||||
85
ShenQi/WithdrawRecordsViewController.xib
Normal file
@@ -0,0 +1,85 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="22155" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22131"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="WithdrawRecordsViewController">
|
||||
<connections>
|
||||
<outlet property="activityIndicator" destination="Bx0-bS-Acy" id="XCP-8h-eNA"/>
|
||||
<outlet property="emptyLabel" destination="yq6-qA-uko" id="6Mc-Xf-DPM"/>
|
||||
<outlet property="recordTableView" destination="MWc-Wc-wc6" id="Yfj-FF-jne"/>
|
||||
<outlet property="titleLabel" destination="js8-IZ-QrG" id="hTy-qC-NX7"/>
|
||||
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
|
||||
</connections>
|
||||
</placeholder>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="dH8-iz-7z1">
|
||||
<rect key="frame" x="20" y="76" width="30" height="30"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="dH8-iz-7z1" secondAttribute="height" multiplier="1:1" id="Ato-4i-hyR"/>
|
||||
<constraint firstAttribute="height" constant="30" id="N0T-8U-iqm"/>
|
||||
</constraints>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
|
||||
<state key="normal" image="goback"/>
|
||||
<connections>
|
||||
<action selector="dismissAction:" destination="-1" eventType="touchUpInside" id="cKp-At-HBh"/>
|
||||
</connections>
|
||||
</button>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="提现记录" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="js8-IZ-QrG">
|
||||
<rect key="frame" x="162" y="79" width="69.333333333333314" height="24"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="24" id="4Wa-w7-SC0"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="1" green="0.65490196079999996" blue="0.1333333333" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="-1" estimatedSectionHeaderHeight="-1" sectionFooterHeight="-1" estimatedSectionFooterHeight="-1" translatesAutoresizingMaskIntoConstraints="NO" id="MWc-Wc-wc6">
|
||||
<rect key="frame" x="0.0" y="123" width="393" height="695"/>
|
||||
<color key="backgroundColor" red="0.17254901959999999" green="0.17254901959999999" blue="0.18039215689999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||
</tableView>
|
||||
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" animating="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="Bx0-bS-Acy">
|
||||
<rect key="frame" x="186.66666666666666" y="460.66666666666669" width="20" height="20"/>
|
||||
</activityIndicatorView>
|
||||
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="-- No Data --" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="yq6-qA-uko">
|
||||
<rect key="frame" x="0.0" y="123" width="393" height="695"/>
|
||||
<color key="backgroundColor" red="0.17254901959999999" green="0.17254901959999999" blue="0.18039215689999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="Q5M-cg-NOt"/>
|
||||
<color key="backgroundColor" red="0.17254901959999999" green="0.17254901959999999" blue="0.18039215689999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="js8-IZ-QrG" firstAttribute="centerX" secondItem="Q5M-cg-NOt" secondAttribute="centerX" id="7mo-VC-N2X"/>
|
||||
<constraint firstItem="Bx0-bS-Acy" firstAttribute="centerY" secondItem="MWc-Wc-wc6" secondAttribute="centerY" id="ERf-TU-35X"/>
|
||||
<constraint firstItem="MWc-Wc-wc6" firstAttribute="centerX" secondItem="Q5M-cg-NOt" secondAttribute="centerX" id="FWP-mW-UnK"/>
|
||||
<constraint firstItem="yq6-qA-uko" firstAttribute="centerY" secondItem="MWc-Wc-wc6" secondAttribute="centerY" id="QHf-h5-tED"/>
|
||||
<constraint firstItem="yq6-qA-uko" firstAttribute="width" secondItem="MWc-Wc-wc6" secondAttribute="width" id="SWd-I0-wob"/>
|
||||
<constraint firstItem="Q5M-cg-NOt" firstAttribute="bottom" secondItem="MWc-Wc-wc6" secondAttribute="bottom" id="TdF-oZ-Q4m"/>
|
||||
<constraint firstItem="MWc-Wc-wc6" firstAttribute="top" secondItem="js8-IZ-QrG" secondAttribute="bottom" constant="20" id="Wln-xB-rlm"/>
|
||||
<constraint firstItem="dH8-iz-7z1" firstAttribute="centerY" secondItem="js8-IZ-QrG" secondAttribute="centerY" id="ajh-mH-FYP"/>
|
||||
<constraint firstItem="dH8-iz-7z1" firstAttribute="leading" secondItem="Q5M-cg-NOt" secondAttribute="leading" constant="20" id="axX-ke-axg"/>
|
||||
<constraint firstItem="yq6-qA-uko" firstAttribute="centerX" secondItem="MWc-Wc-wc6" secondAttribute="centerX" id="bPg-Rk-9zd"/>
|
||||
<constraint firstItem="js8-IZ-QrG" firstAttribute="top" secondItem="Q5M-cg-NOt" secondAttribute="top" constant="20" id="m94-ym-58G"/>
|
||||
<constraint firstItem="Bx0-bS-Acy" firstAttribute="centerX" secondItem="MWc-Wc-wc6" secondAttribute="centerX" id="max-A1-chL"/>
|
||||
<constraint firstItem="MWc-Wc-wc6" firstAttribute="width" secondItem="i5M-Pr-FkT" secondAttribute="width" id="qGR-nh-Zvt"/>
|
||||
<constraint firstItem="yq6-qA-uko" firstAttribute="height" secondItem="MWc-Wc-wc6" secondAttribute="height" id="s4S-8K-Ukw"/>
|
||||
</constraints>
|
||||
<point key="canvasLocation" x="138" y="20"/>
|
||||
</view>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="goback" width="200" height="200"/>
|
||||
</resources>
|
||||
</document>
|
||||
16
ShenQi/WithdrawViewController.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// WithdrawViewController.h
|
||||
// ShenQi
|
||||
//
|
||||
// Created by Yao on 2024/11/9.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface WithdrawViewController : UIViewController
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
206
ShenQi/WithdrawViewController.m
Normal file
@@ -0,0 +1,206 @@
|
||||
//
|
||||
// WithdrawViewController.m
|
||||
// ShenQi
|
||||
//
|
||||
// Created by Yao on 2024/11/9.
|
||||
//
|
||||
|
||||
#import "WithdrawViewController.h"
|
||||
|
||||
#import "DataModels.h"
|
||||
#import "MacroDefine.h"
|
||||
#import "InviteRecordsTableViewCell.h"
|
||||
#import "AppDelegate.h"
|
||||
|
||||
#import "DSTextField.h"
|
||||
#import <MJRefresh.h>
|
||||
#import <SVProgressHUD.h>
|
||||
#import <AdSupport/AdSupport.h>
|
||||
#import <AppTrackingTransparency/AppTrackingTransparency.h>
|
||||
|
||||
#import "WithdrawRecordsViewController.h"
|
||||
|
||||
@interface WithdrawViewController () <UITextFieldDelegate>
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *balanceLabel;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *inputWithdrawLabel;
|
||||
@property (weak, nonatomic) IBOutlet DSTextField *withdrawTextField;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *withdrawBtn;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *withdrawRecordBtn;
|
||||
|
||||
@property (nonatomic, strong) NSString *inviteCode;
|
||||
@property (nonatomic, assign) CGFloat balance;
|
||||
|
||||
@end
|
||||
|
||||
@implementation WithdrawViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
self.titleLabel.text = NSLocalizedString(@"Withdraw", nil);
|
||||
|
||||
self.balanceLabel.text = [NSString stringWithFormat:@"%@:",NSLocalizedString(@"Balance", nil)];
|
||||
self.inputWithdrawLabel.text = [NSString stringWithFormat:@"%@%@%@%@",NSLocalizedString(@"PLS", nil),NSLocalizedString(@"InputEdit", nil),NSLocalizedString(@"Withdraw", nil),NSLocalizedString(@"Amount", nil)];
|
||||
|
||||
self.withdrawTextField.delegate = self;
|
||||
self.withdrawTextField.placeHolderString = [NSString stringWithFormat:@"%@%@%@%@",NSLocalizedString(@"PLS", nil),NSLocalizedString(@"InputEdit", nil),NSLocalizedString(@"Withdraw", nil),NSLocalizedString(@"Amount", nil)];
|
||||
|
||||
self.withdrawBtn.layer.cornerRadius = 20.f;
|
||||
self.withdrawBtn.layer.masksToBounds = YES;
|
||||
[self.withdrawBtn setTitle:NSLocalizedString(@"OK", nil) forState:(UIControlStateNormal)];
|
||||
[self.withdrawBtn addTarget:self action:@selector(withdrawAction) forControlEvents:(UIControlEventTouchUpInside)];
|
||||
|
||||
[self.withdrawRecordBtn setTitle:NSLocalizedString(@"WithdrawRecord", nil) forState:(UIControlStateNormal)];
|
||||
[self.withdrawRecordBtn addTarget:self action:@selector(withdrawRecordAction) forControlEvents:(UIControlEventTouchUpInside)];
|
||||
|
||||
[self setupInviteCode];
|
||||
}
|
||||
|
||||
- (IBAction)dismissAction:(id)sender
|
||||
{
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
-(void)withdrawAction
|
||||
{
|
||||
NSString *amout = self.withdrawTextField.text;
|
||||
if ([amout floatValue] > 0) {
|
||||
if ([amout floatValue] > self.balance) {
|
||||
[SVProgressHUD showInfoWithStatus:[NSString stringWithFormat:@"%@%@",NSLocalizedString(@"OverCanWithdraw", nil),NSLocalizedString(@"Amount", nil)]];
|
||||
}else{
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:WithdrawApplyURL]];
|
||||
request.HTTPMethod = @"POST";
|
||||
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
|
||||
NSDictionary *parmas = @{@"amount":[NSNumber numberWithFloat:[amout floatValue]],@"inviteCode":self.inviteCode};
|
||||
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:parmas options:NSJSONWritingPrettyPrinted error:nil];
|
||||
request.HTTPBody = jsonData;
|
||||
|
||||
[SVProgressHUD show];
|
||||
NSURLSession *session = [NSURLSession sharedSession];
|
||||
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (error == nil) {
|
||||
NSError *error;
|
||||
NSMutableDictionary *responseObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
|
||||
if (error == nil) {
|
||||
if (ISNULL(error) && !ISNULL(responseObject) && [[responseObject objectForKey:@"code"] integerValue] == 1) {
|
||||
[SVProgressHUD showSuccessWithStatus:nil];
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[self dismissAction:nil];
|
||||
});
|
||||
}else{
|
||||
[SVProgressHUD showInfoWithStatus:error.localizedDescription];
|
||||
}
|
||||
}else{
|
||||
NSString *errmsg = [responseObject objectForKey:@"error"];
|
||||
[SVProgressHUD showInfoWithStatus:errmsg];
|
||||
}
|
||||
}else{
|
||||
[SVProgressHUD showInfoWithStatus:error.localizedDescription];
|
||||
}
|
||||
});
|
||||
}];
|
||||
[dataTask resume];
|
||||
}
|
||||
}else{
|
||||
[SVProgressHUD showInfoWithStatus:[NSString stringWithFormat:@"%@%@%@%@",NSLocalizedString(@"PLS", nil),NSLocalizedString(@"InputEdit", nil),NSLocalizedString(@"Withdraw", nil),NSLocalizedString(@"Amount", nil)]];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)withdrawRecordAction
|
||||
{
|
||||
WithdrawRecordsViewController *withdrawRecordsViewController = [[WithdrawRecordsViewController alloc] initWithNibName:@"WithdrawRecordsViewController" bundle:nil];
|
||||
[self presentViewController:withdrawRecordsViewController animated:YES completion:nil];
|
||||
}
|
||||
|
||||
-(void)setupInviteCode
|
||||
{
|
||||
// 我的邀请码
|
||||
__block NSString *advertisingId = nil;
|
||||
AppDelegate *appdelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
|
||||
if (@available(iOS 14, *)) {
|
||||
[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
|
||||
advertisingId = [[ASIdentifierManager sharedManager] advertisingIdentifier].UUIDString;
|
||||
[self getCodeWithAdvertisingId:advertisingId];
|
||||
}];
|
||||
} else {
|
||||
advertisingId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
|
||||
[self getCodeWithAdvertisingId:advertisingId];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)getCodeWithAdvertisingId:(NSString *)advertisingId
|
||||
{
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:InviteCodeURL]];
|
||||
request.HTTPMethod = @"POST";
|
||||
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
|
||||
NSDictionary *parmas = @{@"userId":[NSNumber numberWithInteger:[VV88AUUserID integerValue]],@"deviceCode":advertisingId};
|
||||
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:parmas options:NSJSONWritingPrettyPrinted error:nil];
|
||||
request.HTTPBody = jsonData;
|
||||
|
||||
NSURLSession *session = [NSURLSession sharedSession];
|
||||
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (error == nil) {
|
||||
NSError *error;
|
||||
NSMutableDictionary *responseObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
|
||||
if (error == nil) {
|
||||
if (ISNULL(error) && !ISNULL(responseObject) && [[responseObject objectForKey:@"code"] integerValue] == 1) {
|
||||
InviteCodeModelDataModel *model = [[InviteCodeModelDataModel alloc] initWithDictionary:responseObject];
|
||||
self.inviteCode = model.data.inviteCode;
|
||||
AppDelegate *appdelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
|
||||
appdelegate.inviteCode = self.inviteCode;
|
||||
self.balance = model.data.balance;
|
||||
self.balanceLabel.text = [NSString stringWithFormat:@"%@:%.1f",NSLocalizedString(@"Balance", nil),self.balance];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}];
|
||||
[dataTask resume];
|
||||
}
|
||||
|
||||
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
||||
{
|
||||
[self.view endEditing:YES];
|
||||
}
|
||||
|
||||
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
|
||||
{
|
||||
NSString *text = nil;
|
||||
if (range.location >= textField.text.length) {
|
||||
text = [textField.text stringByAppendingString:string];
|
||||
} else {
|
||||
text = [textField.text stringByReplacingCharactersInRange:range withString:string];
|
||||
}
|
||||
if ([string containsString:@"."]) {
|
||||
if ([textField.text containsString:@"."]) {
|
||||
return NO;
|
||||
}
|
||||
}else{
|
||||
if ([textField.text containsString:@"."] && ![string isEqualToString:@""]) {
|
||||
NSString *floatAmout = [textField.text componentsSeparatedByString:@"."].lastObject;
|
||||
if (floatAmout.length >= 2) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField
|
||||
{
|
||||
textField.clearButtonMode = UITextFieldViewModeAlways;
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(void)textFieldDidEndEditing:(UITextField *)textField
|
||||
{
|
||||
textField.clearButtonMode = UITextFieldViewModeNever;
|
||||
}
|
||||
|
||||
@end
|
||||
150
ShenQi/WithdrawViewController.xib
Normal file
@@ -0,0 +1,150 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="22155" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22131"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="WithdrawViewController">
|
||||
<connections>
|
||||
<outlet property="balanceLabel" destination="T75-vj-VnB" id="5GD-gO-SOb"/>
|
||||
<outlet property="inputWithdrawLabel" destination="1BA-8S-jTt" id="pKY-4o-VE7"/>
|
||||
<outlet property="titleLabel" destination="AhV-Hg-61j" id="f9Y-dj-Kgh"/>
|
||||
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
|
||||
<outlet property="withdrawBtn" destination="jfA-y8-Khm" id="RvK-4j-WPk"/>
|
||||
<outlet property="withdrawRecordBtn" destination="Krj-Fn-yYQ" id="w5E-3k-loT"/>
|
||||
<outlet property="withdrawTextField" destination="Z2c-ej-LlX" id="Etr-y6-L8b"/>
|
||||
</connections>
|
||||
</placeholder>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ehs-Nv-C0g">
|
||||
<rect key="frame" x="20" y="74.666666666666671" width="30" height="30"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="30" id="Yx4-Oa-z1l"/>
|
||||
<constraint firstAttribute="width" secondItem="ehs-Nv-C0g" secondAttribute="height" multiplier="1:1" id="kJF-6Z-j5j"/>
|
||||
</constraints>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
|
||||
<state key="normal" image="goback"/>
|
||||
<connections>
|
||||
<action selector="dismissAction:" destination="-1" eventType="touchUpInside" id="700-2F-5Bv"/>
|
||||
</connections>
|
||||
</button>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="提现" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="AhV-Hg-61j">
|
||||
<rect key="frame" x="179.33333333333334" y="79" width="34.666666666666657" height="21"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="1" green="0.65490196079999996" blue="0.1333333333" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Ghd-aH-IIl">
|
||||
<rect key="frame" x="30" y="140" width="333" height="40"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="可提现金额:" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="T75-vj-VnB">
|
||||
<rect key="frame" x="0.0" y="13" width="67.666666666666671" height="14.333333333333336"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<color key="textColor" red="1" green="0.65490196079999996" blue="0.1333333333" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.17254901959999999" green="0.17254901959999999" blue="0.18039215689999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="40" id="CyI-6A-L0q"/>
|
||||
<constraint firstItem="T75-vj-VnB" firstAttribute="leading" secondItem="Ghd-aH-IIl" secondAttribute="leading" id="aVa-x4-sg2"/>
|
||||
<constraint firstItem="T75-vj-VnB" firstAttribute="centerY" secondItem="Ghd-aH-IIl" secondAttribute="centerY" id="ufD-QN-9Eh"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="V46-wV-xhF">
|
||||
<rect key="frame" x="30" y="195" width="333" height="40"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="请输入提现金额:" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1BA-8S-jTt">
|
||||
<rect key="frame" x="0.0" y="10.333333333333341" width="122.66666666666667" height="19.333333333333329"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
||||
<color key="textColor" red="1" green="0.65490196079999996" blue="0.1333333333" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="QuA-J1-vLm">
|
||||
<rect key="frame" x="132.66666666666663" y="0.0" width="200.33333333333337" height="40"/>
|
||||
<subviews>
|
||||
<textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="248" contentHorizontalAlignment="left" contentVerticalAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="Z2c-ej-LlX" customClass="DSTextField">
|
||||
<rect key="frame" x="10" y="0.0" width="190.33333333333334" height="40"/>
|
||||
<color key="textColor" red="1" green="0.65490196079999996" blue="0.1333333333" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<textInputTraits key="textInputTraits" keyboardType="numbersAndPunctuation"/>
|
||||
</textField>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.2627450980392157" green="0.2627450980392157" blue="0.2627450980392157" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="Z2c-ej-LlX" firstAttribute="centerY" secondItem="QuA-J1-vLm" secondAttribute="centerY" id="Kqh-LD-GpA"/>
|
||||
<constraint firstItem="Z2c-ej-LlX" firstAttribute="height" secondItem="QuA-J1-vLm" secondAttribute="height" id="M1d-OS-guH"/>
|
||||
<constraint firstAttribute="trailing" secondItem="Z2c-ej-LlX" secondAttribute="trailing" id="dd6-tO-yGg"/>
|
||||
<constraint firstItem="Z2c-ej-LlX" firstAttribute="leading" secondItem="QuA-J1-vLm" secondAttribute="leading" constant="10" id="vnt-2K-ISr"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.17254901959999999" green="0.17254901959999999" blue="0.18039215689999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="1BA-8S-jTt" firstAttribute="leading" secondItem="V46-wV-xhF" secondAttribute="leading" id="BEp-BV-EvW"/>
|
||||
<constraint firstItem="QuA-J1-vLm" firstAttribute="height" secondItem="V46-wV-xhF" secondAttribute="height" id="FJG-Us-dN8"/>
|
||||
<constraint firstItem="QuA-J1-vLm" firstAttribute="centerY" secondItem="V46-wV-xhF" secondAttribute="centerY" id="PqA-Nr-Tzz"/>
|
||||
<constraint firstAttribute="trailing" secondItem="QuA-J1-vLm" secondAttribute="trailing" id="WcO-4s-s21"/>
|
||||
<constraint firstAttribute="height" constant="40" id="e7c-hl-avV"/>
|
||||
<constraint firstItem="QuA-J1-vLm" firstAttribute="leading" secondItem="1BA-8S-jTt" secondAttribute="trailing" constant="10" id="qru-KU-LfN"/>
|
||||
<constraint firstItem="1BA-8S-jTt" firstAttribute="centerY" secondItem="V46-wV-xhF" secondAttribute="centerY" id="rac-U9-Oh4"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="jfA-y8-Khm">
|
||||
<rect key="frame" x="30" y="275" width="333" height="40"/>
|
||||
<color key="backgroundColor" systemColor="systemRedColor"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="40" id="hAN-hP-s6n"/>
|
||||
</constraints>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
|
||||
<state key="normal" title="确定">
|
||||
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Krj-Fn-yYQ">
|
||||
<rect key="frame" x="315" y="75" width="58" height="29"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
|
||||
<state key="normal" title="提现记录">
|
||||
<color key="titleColor" red="1" green="0.65490196079999996" blue="0.1333333333" alpha="1" colorSpace="calibratedRGB"/>
|
||||
</state>
|
||||
</button>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="Q5M-cg-NOt"/>
|
||||
<color key="backgroundColor" red="0.17254901959999999" green="0.17254901959999999" blue="0.18039215689999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="Krj-Fn-yYQ" firstAttribute="centerY" secondItem="AhV-Hg-61j" secondAttribute="centerY" id="6o6-0N-VPM"/>
|
||||
<constraint firstItem="Ghd-aH-IIl" firstAttribute="top" secondItem="AhV-Hg-61j" secondAttribute="bottom" constant="40" id="7SS-uu-e3M"/>
|
||||
<constraint firstItem="AhV-Hg-61j" firstAttribute="centerX" secondItem="Q5M-cg-NOt" secondAttribute="centerX" id="Bxz-bK-e0D"/>
|
||||
<constraint firstItem="AhV-Hg-61j" firstAttribute="top" secondItem="Q5M-cg-NOt" secondAttribute="top" constant="20" id="HzE-ql-VZX"/>
|
||||
<constraint firstItem="V46-wV-xhF" firstAttribute="leading" secondItem="Ghd-aH-IIl" secondAttribute="leading" id="Jdy-ha-byx"/>
|
||||
<constraint firstItem="Ghd-aH-IIl" firstAttribute="centerX" secondItem="Q5M-cg-NOt" secondAttribute="centerX" id="Mnv-Jk-Mke"/>
|
||||
<constraint firstItem="jfA-y8-Khm" firstAttribute="centerX" secondItem="Q5M-cg-NOt" secondAttribute="centerX" id="NO9-R4-JxA"/>
|
||||
<constraint firstItem="Q5M-cg-NOt" firstAttribute="trailing" secondItem="Krj-Fn-yYQ" secondAttribute="trailing" constant="20" id="T4Y-Qe-VbP"/>
|
||||
<constraint firstItem="V46-wV-xhF" firstAttribute="top" secondItem="Ghd-aH-IIl" secondAttribute="bottom" constant="15" id="Yuf-Jt-nfK"/>
|
||||
<constraint firstItem="ehs-Nv-C0g" firstAttribute="leading" secondItem="Q5M-cg-NOt" secondAttribute="leading" constant="20" id="c0I-Fs-TJn"/>
|
||||
<constraint firstItem="ehs-Nv-C0g" firstAttribute="centerY" secondItem="AhV-Hg-61j" secondAttribute="centerY" id="daF-ST-1OJ"/>
|
||||
<constraint firstItem="jfA-y8-Khm" firstAttribute="leading" secondItem="Q5M-cg-NOt" secondAttribute="leading" constant="30" id="hN0-JL-GNM"/>
|
||||
<constraint firstItem="V46-wV-xhF" firstAttribute="width" secondItem="Ghd-aH-IIl" secondAttribute="width" id="ks9-dv-KY3"/>
|
||||
<constraint firstItem="Ghd-aH-IIl" firstAttribute="leading" secondItem="Q5M-cg-NOt" secondAttribute="leading" constant="30" id="lUP-fQ-JJY"/>
|
||||
<constraint firstItem="jfA-y8-Khm" firstAttribute="top" secondItem="V46-wV-xhF" secondAttribute="bottom" constant="40" id="uhz-gS-1CW"/>
|
||||
</constraints>
|
||||
<point key="canvasLocation" x="138" y="20"/>
|
||||
</view>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="goback" width="200" height="200"/>
|
||||
<systemColor name="systemRedColor">
|
||||
<color red="1" green="0.23137254901960785" blue="0.18823529411764706" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
</resources>
|
||||
</document>
|
||||
33
ShenQi/YYModel/ConfigData.h
Normal file
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// ConfigData.h
|
||||
//
|
||||
// Created by Yao on 2024/12/19
|
||||
// Copyright (c) 2024 zL. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface ConfigData : NSObject <NSCoding, NSCopying>
|
||||
|
||||
@property (nonatomic, strong) NSString *description;
|
||||
@property (nonatomic, strong) NSString *iosVersionCode;
|
||||
@property (nonatomic, assign) NSInteger forceUpdate;
|
||||
@property (nonatomic, strong) NSString *fbUrl;
|
||||
@property (nonatomic, strong) NSString *credentials;
|
||||
@property (nonatomic, strong) NSString *url;
|
||||
@property (nonatomic, assign) CGFloat inviteFee;
|
||||
@property (nonatomic, assign) NSInteger userId;
|
||||
@property (nonatomic, assign) NSInteger contactApplyMode;
|
||||
@property (nonatomic, strong) NSString *versionCode;
|
||||
@property (nonatomic, strong) NSString *tgUrl;
|
||||
@property (nonatomic, assign) NSInteger noticeApplyMode;
|
||||
@property (nonatomic, strong) NSString *wsUrl;
|
||||
@property (nonatomic, strong) NSString *apkUrl;
|
||||
@property (nonatomic, strong) NSString *downloadUrl;
|
||||
@property (nonatomic, assign) NSInteger isUse;
|
||||
|
||||
+ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict;
|
||||
- (instancetype)initWithDictionary:(NSDictionary *)dict;
|
||||
- (NSDictionary *)dictionaryRepresentation;
|
||||
|
||||
@end
|
||||
178
ShenQi/YYModel/ConfigData.m
Normal file
@@ -0,0 +1,178 @@
|
||||
//
|
||||
// ConfigData.m
|
||||
//
|
||||
// Created by Yao on 2024/12/19
|
||||
// Copyright (c) 2024 zL. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ConfigData.h"
|
||||
|
||||
NSString *const kConfigDataDescription = @"description";
|
||||
NSString *const kConfigDataIosVersionCode = @"iosVersionCode";
|
||||
NSString *const kConfigDataForceUpdate = @"forceUpdate";
|
||||
NSString *const kConfigDataFbUrl = @"fbUrl";
|
||||
NSString *const kConfigDataCredentials = @"credentials";
|
||||
NSString *const kConfigDataUrl = @"url";
|
||||
NSString *const kConfigDataInviteFee = @"inviteFee";
|
||||
NSString *const kConfigDataUserId = @"userId";
|
||||
NSString *const kConfigDataContactApplyMode = @"contactApplyMode";
|
||||
NSString *const kConfigDataVersionCode = @"versionCode";
|
||||
NSString *const kConfigDataTgUrl = @"tgUrl";
|
||||
NSString *const kConfigDataNoticeApplyMode = @"noticeApplyMode";
|
||||
NSString *const kConfigDataWsUrl = @"wsUrl";
|
||||
NSString *const kConfigDataApkUrl = @"apkUrl";
|
||||
NSString *const kConfigDataDownloadUrl = @"downloadUrl";
|
||||
NSString *const kConfigDataIsUse = @"isUse";
|
||||
|
||||
@interface ConfigData ()
|
||||
|
||||
- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ConfigData
|
||||
|
||||
@synthesize description = _description;
|
||||
@synthesize iosVersionCode = _iosVersionCode;
|
||||
@synthesize forceUpdate = _forceUpdate;
|
||||
@synthesize fbUrl = _fbUrl;
|
||||
@synthesize credentials = _credentials;
|
||||
@synthesize url = _url;
|
||||
@synthesize inviteFee = _inviteFee;
|
||||
@synthesize userId = _userId;
|
||||
@synthesize contactApplyMode = _contactApplyMode;
|
||||
@synthesize versionCode = _versionCode;
|
||||
@synthesize tgUrl = _tgUrl;
|
||||
@synthesize noticeApplyMode = _noticeApplyMode;
|
||||
@synthesize wsUrl = _wsUrl;
|
||||
@synthesize apkUrl = _apkUrl;
|
||||
@synthesize downloadUrl = _downloadUrl;
|
||||
@synthesize isUse = _isUse;
|
||||
|
||||
+ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict {
|
||||
return [[self alloc] initWithDictionary:dict];
|
||||
}
|
||||
|
||||
- (instancetype)initWithDictionary:(NSDictionary *)dict {
|
||||
self = [super init];
|
||||
// This check serves to make sure that a non-NSDictionary object
|
||||
// passed into the model class doesn't break the parsing.
|
||||
if (self && [dict isKindOfClass:[NSDictionary class]]) {
|
||||
self.description = [self objectOrNilForKey:kConfigDataDescription fromDictionary:dict];
|
||||
self.iosVersionCode = [self objectOrNilForKey:kConfigDataIosVersionCode fromDictionary:dict];
|
||||
self.forceUpdate = [[self objectOrNilForKey:kConfigDataForceUpdate fromDictionary:dict] intValue];
|
||||
self.fbUrl = [self objectOrNilForKey:kConfigDataFbUrl fromDictionary:dict];
|
||||
self.credentials = [self objectOrNilForKey:kConfigDataCredentials fromDictionary:dict];
|
||||
self.url = [self objectOrNilForKey:kConfigDataUrl fromDictionary:dict];
|
||||
self.inviteFee = [[self objectOrNilForKey:kConfigDataInviteFee fromDictionary:dict] doubleValue];
|
||||
self.userId = [[self objectOrNilForKey:kConfigDataUserId fromDictionary:dict] intValue];
|
||||
self.contactApplyMode = [[self objectOrNilForKey:kConfigDataContactApplyMode fromDictionary:dict] intValue];
|
||||
self.versionCode = [self objectOrNilForKey:kConfigDataVersionCode fromDictionary:dict];
|
||||
self.tgUrl = [self objectOrNilForKey:kConfigDataTgUrl fromDictionary:dict];
|
||||
self.noticeApplyMode = [[self objectOrNilForKey:kConfigDataNoticeApplyMode fromDictionary:dict] intValue];
|
||||
self.wsUrl = [self objectOrNilForKey:kConfigDataWsUrl fromDictionary:dict];
|
||||
self.apkUrl = [self objectOrNilForKey:kConfigDataApkUrl fromDictionary:dict];
|
||||
self.downloadUrl = [self objectOrNilForKey:kConfigDataDownloadUrl fromDictionary:dict];
|
||||
self.isUse = [[self objectOrNilForKey:kConfigDataIsUse fromDictionary:dict] intValue];
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSDictionary *)dictionaryRepresentation {
|
||||
NSMutableDictionary *mutableDict = [NSMutableDictionary dictionary];
|
||||
[mutableDict setValue:self.description forKey:kConfigDataDescription];
|
||||
[mutableDict setValue:self.iosVersionCode forKey:kConfigDataIosVersionCode];
|
||||
[mutableDict setValue:[NSNumber numberWithInteger:self.forceUpdate] forKey:kConfigDataForceUpdate];
|
||||
[mutableDict setValue:self.fbUrl forKey:kConfigDataFbUrl];
|
||||
[mutableDict setValue:self.credentials forKey:kConfigDataCredentials];
|
||||
[mutableDict setValue:self.url forKey:kConfigDataUrl];
|
||||
[mutableDict setValue:[NSNumber numberWithDouble:self.inviteFee] forKey:kConfigDataInviteFee];
|
||||
[mutableDict setValue:[NSNumber numberWithInteger:self.userId] forKey:kConfigDataUserId];
|
||||
[mutableDict setValue:[NSNumber numberWithInteger:self.contactApplyMode] forKey:kConfigDataContactApplyMode];
|
||||
[mutableDict setValue:self.versionCode forKey:kConfigDataVersionCode];
|
||||
[mutableDict setValue:self.tgUrl forKey:kConfigDataTgUrl];
|
||||
[mutableDict setValue:[NSNumber numberWithInteger:self.noticeApplyMode] forKey:kConfigDataNoticeApplyMode];
|
||||
[mutableDict setValue:self.wsUrl forKey:kConfigDataWsUrl];
|
||||
[mutableDict setValue:self.apkUrl forKey:kConfigDataApkUrl];
|
||||
[mutableDict setValue:self.downloadUrl forKey:kConfigDataDownloadUrl];
|
||||
[mutableDict setValue:[NSNumber numberWithInteger:self.isUse] forKey:kConfigDataIsUse];
|
||||
return [NSDictionary dictionaryWithDictionary:mutableDict];
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"%@", [self dictionaryRepresentation]];
|
||||
}
|
||||
|
||||
#pragma mark - Helper Method
|
||||
- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict {
|
||||
id object = [dict objectForKey:aKey];
|
||||
return [object isEqual:[NSNull null]] ? nil : object;
|
||||
}
|
||||
|
||||
#pragma mark - NSCoding Methods
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)aDecoder {
|
||||
self = [super init];
|
||||
self.description = [aDecoder decodeObjectForKey:kConfigDataDescription];
|
||||
self.iosVersionCode = [aDecoder decodeObjectForKey:kConfigDataIosVersionCode];
|
||||
self.forceUpdate = [aDecoder decodeIntegerForKey:kConfigDataForceUpdate];
|
||||
self.fbUrl = [aDecoder decodeObjectForKey:kConfigDataFbUrl];
|
||||
self.credentials = [aDecoder decodeObjectForKey:kConfigDataCredentials];
|
||||
self.url = [aDecoder decodeObjectForKey:kConfigDataUrl];
|
||||
self.inviteFee = [aDecoder decodeDoubleForKey:kConfigDataInviteFee];
|
||||
self.userId = [aDecoder decodeIntegerForKey:kConfigDataUserId];
|
||||
self.contactApplyMode = [aDecoder decodeIntegerForKey:kConfigDataContactApplyMode];
|
||||
self.versionCode = [aDecoder decodeObjectForKey:kConfigDataVersionCode];
|
||||
self.tgUrl = [aDecoder decodeObjectForKey:kConfigDataTgUrl];
|
||||
self.noticeApplyMode = [aDecoder decodeIntegerForKey:kConfigDataNoticeApplyMode];
|
||||
self.wsUrl = [aDecoder decodeObjectForKey:kConfigDataWsUrl];
|
||||
self.apkUrl = [aDecoder decodeObjectForKey:kConfigDataApkUrl];
|
||||
self.downloadUrl = [aDecoder decodeObjectForKey:kConfigDataDownloadUrl];
|
||||
self.isUse = [aDecoder decodeIntegerForKey:kConfigDataIsUse];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:_description forKey:kConfigDataDescription];
|
||||
[aCoder encodeObject:_iosVersionCode forKey:kConfigDataIosVersionCode];
|
||||
[aCoder encodeInteger:_forceUpdate forKey:kConfigDataForceUpdate];
|
||||
[aCoder encodeObject:_fbUrl forKey:kConfigDataFbUrl];
|
||||
[aCoder encodeObject:_credentials forKey:kConfigDataCredentials];
|
||||
[aCoder encodeObject:_url forKey:kConfigDataUrl];
|
||||
[aCoder encodeDouble:_inviteFee forKey:kConfigDataInviteFee];
|
||||
[aCoder encodeInteger:_userId forKey:kConfigDataUserId];
|
||||
[aCoder encodeInteger:_contactApplyMode forKey:kConfigDataContactApplyMode];
|
||||
[aCoder encodeObject:_versionCode forKey:kConfigDataVersionCode];
|
||||
[aCoder encodeObject:_tgUrl forKey:kConfigDataTgUrl];
|
||||
[aCoder encodeInteger:_noticeApplyMode forKey:kConfigDataNoticeApplyMode];
|
||||
[aCoder encodeObject:_wsUrl forKey:kConfigDataWsUrl];
|
||||
[aCoder encodeObject:_apkUrl forKey:kConfigDataApkUrl];
|
||||
[aCoder encodeObject:_downloadUrl forKey:kConfigDataDownloadUrl];
|
||||
[aCoder encodeInteger:_isUse forKey:kConfigDataIsUse];
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
ConfigData *copy = [[ConfigData alloc] init];
|
||||
if (copy) {
|
||||
copy.description = [self.description copyWithZone:zone];
|
||||
copy.iosVersionCode = [self.iosVersionCode copyWithZone:zone];
|
||||
copy.forceUpdate = self.forceUpdate;
|
||||
copy.fbUrl = [self.fbUrl copyWithZone:zone];
|
||||
copy.credentials = [self.credentials copyWithZone:zone];
|
||||
copy.url = [self.url copyWithZone:zone];
|
||||
copy.inviteFee = self.inviteFee;
|
||||
copy.userId = self.userId;
|
||||
copy.contactApplyMode = self.contactApplyMode;
|
||||
copy.versionCode = [self.versionCode copyWithZone:zone];
|
||||
copy.tgUrl = [self.tgUrl copyWithZone:zone];
|
||||
copy.noticeApplyMode = self.noticeApplyMode;
|
||||
copy.wsUrl = [self.wsUrl copyWithZone:zone];
|
||||
copy.apkUrl = [self.apkUrl copyWithZone:zone];
|
||||
copy.downloadUrl = [self.downloadUrl copyWithZone:zone];
|
||||
copy.isUse = self.isUse;
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
@end
|
||||
19
ShenQi/YYModel/ConfigDataModel.h
Normal file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// ConfigDataModel.h
|
||||
//
|
||||
// Created by Yao on 2024/12/19
|
||||
// Copyright (c) 2024 zL. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
@class ConfigData;
|
||||
@interface ConfigDataModel : NSObject <NSCoding, NSCopying>
|
||||
|
||||
@property (nonatomic, strong) ConfigData *data;
|
||||
@property (nonatomic, assign) NSInteger code;
|
||||
|
||||
+ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict;
|
||||
- (instancetype)initWithDictionary:(NSDictionary *)dict;
|
||||
- (NSDictionary *)dictionaryRepresentation;
|
||||
|
||||
@end
|
||||
81
ShenQi/YYModel/ConfigDataModel.m
Normal file
@@ -0,0 +1,81 @@
|
||||
//
|
||||
// ConfigDataModel.m
|
||||
//
|
||||
// Created by Yao on 2024/12/19
|
||||
// Copyright (c) 2024 zL. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ConfigDataModel.h"
|
||||
#import "ConfigData.h"
|
||||
|
||||
NSString *const kConfigDataModelData = @"data";
|
||||
NSString *const kConfigDataModelCode = @"code";
|
||||
|
||||
@interface ConfigDataModel ()
|
||||
|
||||
- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ConfigDataModel
|
||||
|
||||
@synthesize data = _data;
|
||||
@synthesize code = _code;
|
||||
|
||||
+ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict {
|
||||
return [[self alloc] initWithDictionary:dict];
|
||||
}
|
||||
|
||||
- (instancetype)initWithDictionary:(NSDictionary *)dict {
|
||||
self = [super init];
|
||||
// This check serves to make sure that a non-NSDictionary object
|
||||
// passed into the model class doesn't break the parsing.
|
||||
if (self && [dict isKindOfClass:[NSDictionary class]]) {
|
||||
self.data = [ConfigData modelObjectWithDictionary:[dict objectForKey:kConfigDataModelData]];
|
||||
self.code = [[self objectOrNilForKey:kConfigDataModelCode fromDictionary:dict] intValue];
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSDictionary *)dictionaryRepresentation {
|
||||
NSMutableDictionary *mutableDict = [NSMutableDictionary dictionary];
|
||||
[mutableDict setValue:[self.data dictionaryRepresentation] forKey:kConfigDataModelData];
|
||||
[mutableDict setValue:[NSNumber numberWithInteger:self.code] forKey:kConfigDataModelCode];
|
||||
return [NSDictionary dictionaryWithDictionary:mutableDict];
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"%@", [self dictionaryRepresentation]];
|
||||
}
|
||||
|
||||
#pragma mark - Helper Method
|
||||
- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict {
|
||||
id object = [dict objectForKey:aKey];
|
||||
return [object isEqual:[NSNull null]] ? nil : object;
|
||||
}
|
||||
|
||||
#pragma mark - NSCoding Methods
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)aDecoder {
|
||||
self = [super init];
|
||||
self.data = [aDecoder decodeObjectForKey:kConfigDataModelData];
|
||||
self.code = [aDecoder decodeIntegerForKey:kConfigDataModelCode];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:_data forKey:kConfigDataModelData];
|
||||
[aCoder encodeInteger:_code forKey:kConfigDataModelCode];
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
ConfigDataModel *copy = [[ConfigDataModel alloc] init];
|
||||
if (copy) {
|
||||
copy.data = [self.data copyWithZone:zone];
|
||||
copy.code = self.code;
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
@end
|
||||
430
ShenQi/YYModel/NSObject+YYModel.h
Normal file
@@ -0,0 +1,430 @@
|
||||
//
|
||||
// NSObject+YYModel.h
|
||||
// YYKit <https://github.com/ibireme/YYKit>
|
||||
//
|
||||
// Created by ibireme on 15/5/10.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Provide some data-model method:
|
||||
|
||||
* Convert json to any object, or convert any object to json.
|
||||
* Set object properties with a key-value dictionary (like KVC).
|
||||
* Implementations of `NSCoding`, `NSCopying`, `-hash` and `-isEqual:`.
|
||||
|
||||
See `YYModel` protocol for custom methods.
|
||||
|
||||
|
||||
Sample Code:
|
||||
|
||||
********************** json convertor *********************
|
||||
@interface YYAuthor : NSObject
|
||||
@property (nonatomic, strong) NSString *name;
|
||||
@property (nonatomic, assign) NSDate *birthday;
|
||||
@end
|
||||
@implementation YYAuthor
|
||||
@end
|
||||
|
||||
@interface YYBook : NSObject
|
||||
@property (nonatomic, copy) NSString *name;
|
||||
@property (nonatomic, assign) NSUInteger pages;
|
||||
@property (nonatomic, strong) YYAuthor *author;
|
||||
@end
|
||||
@implementation YYBook
|
||||
@end
|
||||
|
||||
int main() {
|
||||
// create model from json
|
||||
YYBook *book = [YYBook modelWithJSON:@"{\"name\": \"Harry Potter\", \"pages\": 256, \"author\": {\"name\": \"J.K.Rowling\", \"birthday\": \"1965-07-31\" }}"];
|
||||
|
||||
// convert model to json
|
||||
NSString *json = [book modelToJSONString];
|
||||
// {"author":{"name":"J.K.Rowling","birthday":"1965-07-31T00:00:00+0000"},"name":"Harry Potter","pages":256}
|
||||
}
|
||||
|
||||
********************** Coding/Copying/hash/equal *********************
|
||||
@interface YYShadow :NSObject <NSCoding, NSCopying>
|
||||
@property (nonatomic, copy) NSString *name;
|
||||
@property (nonatomic, assign) CGSize size;
|
||||
@end
|
||||
|
||||
@implementation YYShadow
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder { [self modelEncodeWithCoder:aCoder]; }
|
||||
- (id)initWithCoder:(NSCoder *)aDecoder { self = [super init]; return [self modelInitWithCoder:aDecoder]; }
|
||||
- (id)copyWithZone:(NSZone *)zone { return [self modelCopy]; }
|
||||
- (NSUInteger)hash { return [self modelHash]; }
|
||||
- (BOOL)isEqual:(id)object { return [self modelIsEqual:object]; }
|
||||
@end
|
||||
|
||||
*/
|
||||
@interface NSObject (YYModel)
|
||||
|
||||
/**
|
||||
Creates and returns a new instance of the receiver from a json.
|
||||
This method is thread-safe.
|
||||
|
||||
@param json A json object in `NSDictionary`, `NSString` or `NSData`.
|
||||
|
||||
@return A new instance created from the json, or nil if an error occurs.
|
||||
*/
|
||||
+ (nullable instancetype)modelWithJSON:(id)json;
|
||||
|
||||
/**
|
||||
Creates and returns a new instance of the receiver from a key-value dictionary.
|
||||
This method is thread-safe.
|
||||
|
||||
@param dictionary A key-value dictionary mapped to the instance's properties.
|
||||
Any invalid key-value pair in dictionary will be ignored.
|
||||
|
||||
@return A new instance created from the dictionary, or nil if an error occurs.
|
||||
|
||||
@discussion The key in `dictionary` will mapped to the reciever's property name,
|
||||
and the value will set to the property. If the value's type does not match the
|
||||
property, this method will try to convert the value based on these rules:
|
||||
|
||||
`NSString` or `NSNumber` -> c number, such as BOOL, int, long, float, NSUInteger...
|
||||
`NSString` -> NSDate, parsed with format "yyyy-MM-dd'T'HH:mm:ssZ", "yyyy-MM-dd HH:mm:ss" or "yyyy-MM-dd".
|
||||
`NSString` -> NSURL.
|
||||
`NSValue` -> struct or union, such as CGRect, CGSize, ...
|
||||
`NSString` -> SEL, Class.
|
||||
*/
|
||||
+ (nullable instancetype)modelWithDictionary:(NSDictionary *)dictionary;
|
||||
|
||||
/**
|
||||
Set the receiver's properties with a json object.
|
||||
|
||||
@discussion Any invalid data in json will be ignored.
|
||||
|
||||
@param json A json object of `NSDictionary`, `NSString` or `NSData`, mapped to the
|
||||
receiver's properties.
|
||||
|
||||
@return Whether succeed.
|
||||
*/
|
||||
- (BOOL)modelSetWithJSON:(id)json;
|
||||
|
||||
/**
|
||||
Set the receiver's properties with a key-value dictionary.
|
||||
|
||||
@param dic A key-value dictionary mapped to the receiver's properties.
|
||||
Any invalid key-value pair in dictionary will be ignored.
|
||||
|
||||
@discussion The key in `dictionary` will mapped to the reciever's property name,
|
||||
and the value will set to the property. If the value's type doesn't match the
|
||||
property, this method will try to convert the value based on these rules:
|
||||
|
||||
`NSString`, `NSNumber` -> c number, such as BOOL, int, long, float, NSUInteger...
|
||||
`NSString` -> NSDate, parsed with format "yyyy-MM-dd'T'HH:mm:ssZ", "yyyy-MM-dd HH:mm:ss" or "yyyy-MM-dd".
|
||||
`NSString` -> NSURL.
|
||||
`NSValue` -> struct or union, such as CGRect, CGSize, ...
|
||||
`NSString` -> SEL, Class.
|
||||
|
||||
@return Whether succeed.
|
||||
*/
|
||||
- (BOOL)modelSetWithDictionary:(NSDictionary *)dic;
|
||||
|
||||
/**
|
||||
Generate a json object from the receiver's properties.
|
||||
|
||||
@return A json object in `NSDictionary` or `NSArray`, or nil if an error occurs.
|
||||
See [NSJSONSerialization isValidJSONObject] for more information.
|
||||
|
||||
@discussion Any of the invalid property is ignored.
|
||||
If the reciver is `NSArray`, `NSDictionary` or `NSSet`, it just convert
|
||||
the inner object to json object.
|
||||
*/
|
||||
- (nullable id)modelToJSONObject;
|
||||
|
||||
/**
|
||||
Generate a json string's data from the receiver's properties.
|
||||
|
||||
@return A json string's data, or nil if an error occurs.
|
||||
|
||||
@discussion Any of the invalid property is ignored.
|
||||
If the reciver is `NSArray`, `NSDictionary` or `NSSet`, it will also convert the
|
||||
inner object to json string.
|
||||
*/
|
||||
- (nullable NSData *)modelToJSONData;
|
||||
|
||||
/**
|
||||
Generate a json string from the receiver's properties.
|
||||
|
||||
@return A json string, or nil if an error occurs.
|
||||
|
||||
@discussion Any of the invalid property is ignored.
|
||||
If the reciver is `NSArray`, `NSDictionary` or `NSSet`, it will also convert the
|
||||
inner object to json string.
|
||||
*/
|
||||
- (nullable NSString *)modelToJSONString;
|
||||
|
||||
/**
|
||||
Copy a instance with the receiver's properties.
|
||||
|
||||
@return A copied instance, or nil if an error occurs.
|
||||
*/
|
||||
- (nullable id)modelCopy;
|
||||
|
||||
/**
|
||||
Encode the receiver's properties to a coder.
|
||||
|
||||
@param aCoder An archiver object.
|
||||
*/
|
||||
- (void)modelEncodeWithCoder:(NSCoder *)aCoder;
|
||||
|
||||
/**
|
||||
Decode the receiver's properties from a decoder.
|
||||
|
||||
@param aDecoder An archiver object.
|
||||
|
||||
@return self
|
||||
*/
|
||||
- (id)modelInitWithCoder:(NSCoder *)aDecoder;
|
||||
|
||||
/**
|
||||
Get a hash code with the receiver's properties.
|
||||
|
||||
@return Hash code.
|
||||
*/
|
||||
- (NSUInteger)modelHash;
|
||||
|
||||
/**
|
||||
Compares the receiver with another object for equality, based on properties.
|
||||
|
||||
@param model Another object.
|
||||
|
||||
@return `YES` if the reciever is equal to the object, otherwise `NO`.
|
||||
*/
|
||||
- (BOOL)modelIsEqual:(id)model;
|
||||
|
||||
/**
|
||||
Description method for debugging purposes based on properties.
|
||||
|
||||
@return A string that describes the contents of the receiver.
|
||||
*/
|
||||
- (NSString *)modelDescription;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Provide some data-model method for NSArray.
|
||||
*/
|
||||
@interface NSArray (YYModel)
|
||||
|
||||
/**
|
||||
Creates and returns an array from a json-array.
|
||||
This method is thread-safe.
|
||||
|
||||
@param cls The instance's class in array.
|
||||
@param json A json array of `NSArray`, `NSString` or `NSData`.
|
||||
Example: [{"name","Mary"},{name:"Joe"}]
|
||||
|
||||
@return A array, or nil if an error occurs.
|
||||
*/
|
||||
+ (nullable NSArray *)modelArrayWithClass:(Class)cls json:(id)json;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Provide some data-model method for NSDictionary.
|
||||
*/
|
||||
@interface NSDictionary (YYModel)
|
||||
|
||||
/**
|
||||
Creates and returns a dictionary from a json.
|
||||
This method is thread-safe.
|
||||
|
||||
@param cls The value instance's class in dictionary.
|
||||
@param json A json dictionary of `NSDictionary`, `NSString` or `NSData`.
|
||||
Example: {"user1":{"name","Mary"}, "user2": {name:"Joe"}}
|
||||
|
||||
@return A dictionary, or nil if an error occurs.
|
||||
*/
|
||||
+ (nullable NSDictionary *)modelDictionaryWithClass:(Class)cls json:(id)json;
|
||||
@end
|
||||
|
||||
|
||||
|
||||
/**
|
||||
If the default model transform does not fit to your model class, implement one or
|
||||
more method in this protocol to change the default key-value transform process.
|
||||
There's no need to add '<YYModel>' to your class header.
|
||||
*/
|
||||
@protocol YYModel <NSObject>
|
||||
@optional
|
||||
|
||||
/**
|
||||
Custom property mapper.
|
||||
|
||||
@discussion If the key in JSON/Dictionary does not match to the model's property name,
|
||||
implements this method and returns the additional mapper.
|
||||
|
||||
Example:
|
||||
|
||||
json:
|
||||
{
|
||||
"n":"Harry Pottery",
|
||||
"p": 256,
|
||||
"ext" : {
|
||||
"desc" : "A book written by J.K.Rowling."
|
||||
},
|
||||
"ID" : 100010
|
||||
}
|
||||
|
||||
model:
|
||||
@interface YYBook : NSObject
|
||||
@property NSString *name;
|
||||
@property NSInteger page;
|
||||
@property NSString *desc;
|
||||
@property NSString *bookID;
|
||||
@end
|
||||
|
||||
@implementation YYBook
|
||||
+ (NSDictionary *)modelCustomPropertyMapper {
|
||||
return @{@"name" : @"n",
|
||||
@"page" : @"p",
|
||||
@"desc" : @"ext.desc",
|
||||
@"bookID": @[@"id", @"ID", @"book_id"]};
|
||||
}
|
||||
@end
|
||||
|
||||
@return A custom mapper for properties.
|
||||
*/
|
||||
+ (nullable NSDictionary<NSString *, id> *)modelCustomPropertyMapper;
|
||||
|
||||
/**
|
||||
The generic class mapper for container properties.
|
||||
|
||||
@discussion If the property is a container object, such as NSArray/NSSet/NSDictionary,
|
||||
implements this method and returns a property->class mapper, tells which kind of
|
||||
object will be add to the array/set/dictionary.
|
||||
|
||||
Example:
|
||||
@class YYShadow, YYBorder, YYAttachment;
|
||||
|
||||
@interface YYAttributes
|
||||
@property NSString *name;
|
||||
@property NSArray *shadows;
|
||||
@property NSSet *borders;
|
||||
@property NSDictionary *attachments;
|
||||
@end
|
||||
|
||||
@implementation YYAttributes
|
||||
+ (NSDictionary *)modelContainerPropertyGenericClass {
|
||||
return @{@"shadows" : [YYShadow class],
|
||||
@"borders" : YYBorder.class,
|
||||
@"attachments" : @"YYAttachment" };
|
||||
}
|
||||
@end
|
||||
|
||||
@return A class mapper.
|
||||
*/
|
||||
+ (nullable NSDictionary<NSString *, id> *)modelContainerPropertyGenericClass;
|
||||
|
||||
/**
|
||||
If you need to create instances of different classes during json->object transform,
|
||||
use the method to choose custom class based on dictionary data.
|
||||
|
||||
@discussion If the model implements this method, it will be called to determine resulting class
|
||||
during `+modelWithJSON:`, `+modelWithDictionary:`, conveting object of properties of parent objects
|
||||
(both singular and containers via `+modelContainerPropertyGenericClass`).
|
||||
|
||||
Example:
|
||||
@class YYCircle, YYRectangle, YYLine;
|
||||
|
||||
@implementation YYShape
|
||||
|
||||
+ (Class)modelCustomClassForDictionary:(NSDictionary*)dictionary {
|
||||
if (dictionary[@"radius"] != nil) {
|
||||
return [YYCircle class];
|
||||
} else if (dictionary[@"width"] != nil) {
|
||||
return [YYRectangle class];
|
||||
} else if (dictionary[@"y2"] != nil) {
|
||||
return [YYLine class];
|
||||
} else {
|
||||
return [self class];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@param dictionary The json/kv dictionary.
|
||||
|
||||
@return Class to create from this dictionary, `nil` to use current class.
|
||||
|
||||
*/
|
||||
+ (nullable Class)modelCustomClassForDictionary:(NSDictionary *)dictionary;
|
||||
|
||||
/**
|
||||
All the properties in blacklist will be ignored in model transform process.
|
||||
Returns nil to ignore this feature.
|
||||
|
||||
@return An array of property's name.
|
||||
*/
|
||||
+ (nullable NSArray<NSString *> *)modelPropertyBlacklist;
|
||||
|
||||
/**
|
||||
If a property is not in the whitelist, it will be ignored in model transform process.
|
||||
Returns nil to ignore this feature.
|
||||
|
||||
@return An array of property's name.
|
||||
*/
|
||||
+ (nullable NSArray<NSString *> *)modelPropertyWhitelist;
|
||||
|
||||
/**
|
||||
This method's behavior is similar to `- (BOOL)modelCustomTransformFromDictionary:(NSDictionary *)dic;`,
|
||||
but be called before the model transform.
|
||||
|
||||
@discussion If the model implements this method, it will be called before
|
||||
`+modelWithJSON:`, `+modelWithDictionary:`, `-modelSetWithJSON:` and `-modelSetWithDictionary:`.
|
||||
If this method returns nil, the transform process will ignore this model.
|
||||
|
||||
@param dic The json/kv dictionary.
|
||||
|
||||
@return Returns the modified dictionary, or nil to ignore this model.
|
||||
*/
|
||||
- (NSDictionary *)modelCustomWillTransformFromDictionary:(NSDictionary *)dic;
|
||||
|
||||
/**
|
||||
If the default json-to-model transform does not fit to your model object, implement
|
||||
this method to do additional process. You can also use this method to validate the
|
||||
model's properties.
|
||||
|
||||
@discussion If the model implements this method, it will be called at the end of
|
||||
`+modelWithJSON:`, `+modelWithDictionary:`, `-modelSetWithJSON:` and `-modelSetWithDictionary:`.
|
||||
If this method returns NO, the transform process will ignore this model.
|
||||
|
||||
@param dic The json/kv dictionary.
|
||||
|
||||
@return Returns YES if the model is valid, or NO to ignore this model.
|
||||
*/
|
||||
- (BOOL)modelCustomTransformFromDictionary:(NSDictionary *)dic;
|
||||
|
||||
/**
|
||||
If the default model-to-json transform does not fit to your model class, implement
|
||||
this method to do additional process. You can also use this method to validate the
|
||||
json dictionary.
|
||||
|
||||
@discussion If the model implements this method, it will be called at the end of
|
||||
`-modelToJSONObject` and `-modelToJSONString`.
|
||||
If this method returns NO, the transform process will ignore this json dictionary.
|
||||
|
||||
@param dic The json dictionary.
|
||||
|
||||
@return Returns YES if the model is valid, or NO to ignore this model.
|
||||
*/
|
||||
- (BOOL)modelCustomTransformToDictionary:(NSMutableDictionary *)dic;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
1838
ShenQi/YYModel/NSObject+YYModel.m
Normal file
@@ -0,0 +1,1838 @@
|
||||
//
|
||||
// NSObject+YYModel.m
|
||||
// YYKit <https://github.com/ibireme/YYKit>
|
||||
//
|
||||
// Created by ibireme on 15/5/10.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import "NSObject+YYModel.h"
|
||||
#import "YYClassInfo.h"
|
||||
#import <objc/message.h>
|
||||
|
||||
#define force_inline __inline__ __attribute__((always_inline))
|
||||
|
||||
/// Foundation Class Type
|
||||
typedef NS_ENUM (NSUInteger, YYEncodingNSType) {
|
||||
YYEncodingTypeNSUnknown = 0,
|
||||
YYEncodingTypeNSString,
|
||||
YYEncodingTypeNSMutableString,
|
||||
YYEncodingTypeNSValue,
|
||||
YYEncodingTypeNSNumber,
|
||||
YYEncodingTypeNSDecimalNumber,
|
||||
YYEncodingTypeNSData,
|
||||
YYEncodingTypeNSMutableData,
|
||||
YYEncodingTypeNSDate,
|
||||
YYEncodingTypeNSURL,
|
||||
YYEncodingTypeNSArray,
|
||||
YYEncodingTypeNSMutableArray,
|
||||
YYEncodingTypeNSDictionary,
|
||||
YYEncodingTypeNSMutableDictionary,
|
||||
YYEncodingTypeNSSet,
|
||||
YYEncodingTypeNSMutableSet,
|
||||
};
|
||||
|
||||
/// Get the Foundation class type from property info.
|
||||
static force_inline YYEncodingNSType YYClassGetNSType(Class cls) {
|
||||
if (!cls) return YYEncodingTypeNSUnknown;
|
||||
if ([cls isSubclassOfClass:[NSMutableString class]]) return YYEncodingTypeNSMutableString;
|
||||
if ([cls isSubclassOfClass:[NSString class]]) return YYEncodingTypeNSString;
|
||||
if ([cls isSubclassOfClass:[NSDecimalNumber class]]) return YYEncodingTypeNSDecimalNumber;
|
||||
if ([cls isSubclassOfClass:[NSNumber class]]) return YYEncodingTypeNSNumber;
|
||||
if ([cls isSubclassOfClass:[NSValue class]]) return YYEncodingTypeNSValue;
|
||||
if ([cls isSubclassOfClass:[NSMutableData class]]) return YYEncodingTypeNSMutableData;
|
||||
if ([cls isSubclassOfClass:[NSData class]]) return YYEncodingTypeNSData;
|
||||
if ([cls isSubclassOfClass:[NSDate class]]) return YYEncodingTypeNSDate;
|
||||
if ([cls isSubclassOfClass:[NSURL class]]) return YYEncodingTypeNSURL;
|
||||
if ([cls isSubclassOfClass:[NSMutableArray class]]) return YYEncodingTypeNSMutableArray;
|
||||
if ([cls isSubclassOfClass:[NSArray class]]) return YYEncodingTypeNSArray;
|
||||
if ([cls isSubclassOfClass:[NSMutableDictionary class]]) return YYEncodingTypeNSMutableDictionary;
|
||||
if ([cls isSubclassOfClass:[NSDictionary class]]) return YYEncodingTypeNSDictionary;
|
||||
if ([cls isSubclassOfClass:[NSMutableSet class]]) return YYEncodingTypeNSMutableSet;
|
||||
if ([cls isSubclassOfClass:[NSSet class]]) return YYEncodingTypeNSSet;
|
||||
return YYEncodingTypeNSUnknown;
|
||||
}
|
||||
|
||||
/// Whether the type is c number.
|
||||
static force_inline BOOL YYEncodingTypeIsCNumber(YYEncodingType type) {
|
||||
switch (type & YYEncodingTypeMask) {
|
||||
case YYEncodingTypeBool:
|
||||
case YYEncodingTypeInt8:
|
||||
case YYEncodingTypeUInt8:
|
||||
case YYEncodingTypeInt16:
|
||||
case YYEncodingTypeUInt16:
|
||||
case YYEncodingTypeInt32:
|
||||
case YYEncodingTypeUInt32:
|
||||
case YYEncodingTypeInt64:
|
||||
case YYEncodingTypeUInt64:
|
||||
case YYEncodingTypeFloat:
|
||||
case YYEncodingTypeDouble:
|
||||
case YYEncodingTypeLongDouble: return YES;
|
||||
default: return NO;
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a number value from 'id'.
|
||||
static force_inline NSNumber *YYNSNumberCreateFromID(__unsafe_unretained id value) {
|
||||
static NSCharacterSet *dot;
|
||||
static NSDictionary *dic;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
dot = [NSCharacterSet characterSetWithRange:NSMakeRange('.', 1)];
|
||||
dic = @{@"TRUE" : @(YES),
|
||||
@"True" : @(YES),
|
||||
@"true" : @(YES),
|
||||
@"FALSE" : @(NO),
|
||||
@"False" : @(NO),
|
||||
@"false" : @(NO),
|
||||
@"YES" : @(YES),
|
||||
@"Yes" : @(YES),
|
||||
@"yes" : @(YES),
|
||||
@"NO" : @(NO),
|
||||
@"No" : @(NO),
|
||||
@"no" : @(NO),
|
||||
@"NIL" : (id)kCFNull,
|
||||
@"Nil" : (id)kCFNull,
|
||||
@"nil" : (id)kCFNull,
|
||||
@"NULL" : (id)kCFNull,
|
||||
@"Null" : (id)kCFNull,
|
||||
@"null" : (id)kCFNull,
|
||||
@"(NULL)" : (id)kCFNull,
|
||||
@"(Null)" : (id)kCFNull,
|
||||
@"(null)" : (id)kCFNull,
|
||||
@"<NULL>" : (id)kCFNull,
|
||||
@"<Null>" : (id)kCFNull,
|
||||
@"<null>" : (id)kCFNull};
|
||||
});
|
||||
|
||||
if (!value || value == (id)kCFNull) return nil;
|
||||
if ([value isKindOfClass:[NSNumber class]]) return value;
|
||||
if ([value isKindOfClass:[NSString class]]) {
|
||||
NSNumber *num = dic[value];
|
||||
if (num) {
|
||||
if (num == (id)kCFNull) return nil;
|
||||
return num;
|
||||
}
|
||||
if ([(NSString *)value rangeOfCharacterFromSet:dot].location != NSNotFound) {
|
||||
const char *cstring = ((NSString *)value).UTF8String;
|
||||
if (!cstring) return nil;
|
||||
double num = atof(cstring);
|
||||
if (isnan(num) || isinf(num)) return nil;
|
||||
return @(num);
|
||||
} else {
|
||||
const char *cstring = ((NSString *)value).UTF8String;
|
||||
if (!cstring) return nil;
|
||||
return @(atoll(cstring));
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
/// Parse string to date.
|
||||
static force_inline NSDate *YYNSDateFromString(__unsafe_unretained NSString *string) {
|
||||
typedef NSDate* (^YYNSDateParseBlock)(NSString *string);
|
||||
#define kParserNum 34
|
||||
static YYNSDateParseBlock blocks[kParserNum + 1] = {0};
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
{
|
||||
/*
|
||||
2014-01-20 // Google
|
||||
*/
|
||||
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
|
||||
formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
|
||||
formatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
|
||||
formatter.dateFormat = @"yyyy-MM-dd";
|
||||
blocks[10] = ^(NSString *string) { return [formatter dateFromString:string]; };
|
||||
}
|
||||
|
||||
{
|
||||
/*
|
||||
2014-01-20 12:24:48
|
||||
2014-01-20T12:24:48 // Google
|
||||
2014-01-20 12:24:48.000
|
||||
2014-01-20T12:24:48.000
|
||||
*/
|
||||
NSDateFormatter *formatter1 = [[NSDateFormatter alloc] init];
|
||||
formatter1.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
|
||||
formatter1.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
|
||||
formatter1.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss";
|
||||
|
||||
NSDateFormatter *formatter2 = [[NSDateFormatter alloc] init];
|
||||
formatter2.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
|
||||
formatter2.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
|
||||
formatter2.dateFormat = @"yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
NSDateFormatter *formatter3 = [[NSDateFormatter alloc] init];
|
||||
formatter3.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
|
||||
formatter3.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
|
||||
formatter3.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss.SSS";
|
||||
|
||||
NSDateFormatter *formatter4 = [[NSDateFormatter alloc] init];
|
||||
formatter4.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
|
||||
formatter4.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
|
||||
formatter4.dateFormat = @"yyyy-MM-dd HH:mm:ss.SSS";
|
||||
|
||||
blocks[19] = ^(NSString *string) {
|
||||
if ([string characterAtIndex:10] == 'T') {
|
||||
return [formatter1 dateFromString:string];
|
||||
} else {
|
||||
return [formatter2 dateFromString:string];
|
||||
}
|
||||
};
|
||||
|
||||
blocks[23] = ^(NSString *string) {
|
||||
if ([string characterAtIndex:10] == 'T') {
|
||||
return [formatter3 dateFromString:string];
|
||||
} else {
|
||||
return [formatter4 dateFromString:string];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
/*
|
||||
2014-01-20T12:24:48Z // Github, Apple
|
||||
2014-01-20T12:24:48+0800 // Facebook
|
||||
2014-01-20T12:24:48+12:00 // Google
|
||||
2014-01-20T12:24:48.000Z
|
||||
2014-01-20T12:24:48.000+0800
|
||||
2014-01-20T12:24:48.000+12:00
|
||||
*/
|
||||
NSDateFormatter *formatter = [NSDateFormatter new];
|
||||
formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
|
||||
formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZ";
|
||||
|
||||
NSDateFormatter *formatter2 = [NSDateFormatter new];
|
||||
formatter2.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
|
||||
formatter2.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss.SSSZ";
|
||||
|
||||
blocks[20] = ^(NSString *string) { return [formatter dateFromString:string]; };
|
||||
blocks[24] = ^(NSString *string) { return [formatter dateFromString:string]?: [formatter2 dateFromString:string]; };
|
||||
blocks[25] = ^(NSString *string) { return [formatter dateFromString:string]; };
|
||||
blocks[28] = ^(NSString *string) { return [formatter2 dateFromString:string]; };
|
||||
blocks[29] = ^(NSString *string) { return [formatter2 dateFromString:string]; };
|
||||
}
|
||||
|
||||
{
|
||||
/*
|
||||
Fri Sep 04 00:12:21 +0800 2015 // Weibo, Twitter
|
||||
Fri Sep 04 00:12:21.000 +0800 2015
|
||||
*/
|
||||
NSDateFormatter *formatter = [NSDateFormatter new];
|
||||
formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
|
||||
formatter.dateFormat = @"EEE MMM dd HH:mm:ss Z yyyy";
|
||||
|
||||
NSDateFormatter *formatter2 = [NSDateFormatter new];
|
||||
formatter2.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
|
||||
formatter2.dateFormat = @"EEE MMM dd HH:mm:ss.SSS Z yyyy";
|
||||
|
||||
blocks[30] = ^(NSString *string) { return [formatter dateFromString:string]; };
|
||||
blocks[34] = ^(NSString *string) { return [formatter2 dateFromString:string]; };
|
||||
}
|
||||
});
|
||||
if (!string) return nil;
|
||||
if (string.length > kParserNum) return nil;
|
||||
YYNSDateParseBlock parser = blocks[string.length];
|
||||
if (!parser) return nil;
|
||||
return parser(string);
|
||||
#undef kParserNum
|
||||
}
|
||||
|
||||
|
||||
/// Get the 'NSBlock' class.
|
||||
static force_inline Class YYNSBlockClass() {
|
||||
static Class cls;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
void (^block)(void) = ^{};
|
||||
cls = ((NSObject *)block).class;
|
||||
while (class_getSuperclass(cls) != [NSObject class]) {
|
||||
cls = class_getSuperclass(cls);
|
||||
}
|
||||
});
|
||||
return cls; // current is "NSBlock"
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Get the ISO date formatter.
|
||||
|
||||
ISO8601 format example:
|
||||
2010-07-09T16:13:30+12:00
|
||||
2011-01-11T11:11:11+0000
|
||||
2011-01-26T19:06:43Z
|
||||
|
||||
length: 20/24/25
|
||||
*/
|
||||
static force_inline NSDateFormatter *YYISODateFormatter() {
|
||||
static NSDateFormatter *formatter = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
formatter = [[NSDateFormatter alloc] init];
|
||||
formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
|
||||
formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZ";
|
||||
});
|
||||
return formatter;
|
||||
}
|
||||
|
||||
/// Get the value with key paths from dictionary
|
||||
/// The dic should be NSDictionary, and the keyPath should not be nil.
|
||||
static force_inline id YYValueForKeyPath(__unsafe_unretained NSDictionary *dic, __unsafe_unretained NSArray *keyPaths) {
|
||||
id value = nil;
|
||||
for (NSUInteger i = 0, max = keyPaths.count; i < max; i++) {
|
||||
value = dic[keyPaths[i]];
|
||||
if (i + 1 < max) {
|
||||
if ([value isKindOfClass:[NSDictionary class]]) {
|
||||
dic = value;
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/// Get the value with multi key (or key path) from dictionary
|
||||
/// The dic should be NSDictionary
|
||||
static force_inline id YYValueForMultiKeys(__unsafe_unretained NSDictionary *dic, __unsafe_unretained NSArray *multiKeys) {
|
||||
id value = nil;
|
||||
for (NSString *key in multiKeys) {
|
||||
if ([key isKindOfClass:[NSString class]]) {
|
||||
value = dic[key];
|
||||
if (value) break;
|
||||
} else {
|
||||
value = YYValueForKeyPath(dic, (NSArray *)key);
|
||||
if (value) break;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// A property info in object model.
|
||||
@interface _YYModelPropertyMeta : NSObject {
|
||||
@package
|
||||
NSString *_name; ///< property's name
|
||||
YYEncodingType _type; ///< property's type
|
||||
YYEncodingNSType _nsType; ///< property's Foundation type
|
||||
BOOL _isCNumber; ///< is c number type
|
||||
Class _cls; ///< property's class, or nil
|
||||
Class _genericCls; ///< container's generic class, or nil if threr's no generic class
|
||||
SEL _getter; ///< getter, or nil if the instances cannot respond
|
||||
SEL _setter; ///< setter, or nil if the instances cannot respond
|
||||
BOOL _isKVCCompatible; ///< YES if it can access with key-value coding
|
||||
BOOL _isStructAvailableForKeyedArchiver; ///< YES if the struct can encoded with keyed archiver/unarchiver
|
||||
BOOL _hasCustomClassFromDictionary; ///< class/generic class implements +modelCustomClassForDictionary:
|
||||
|
||||
/*
|
||||
property->key: _mappedToKey:key _mappedToKeyPath:nil _mappedToKeyArray:nil
|
||||
property->keyPath: _mappedToKey:keyPath _mappedToKeyPath:keyPath(array) _mappedToKeyArray:nil
|
||||
property->keys: _mappedToKey:keys[0] _mappedToKeyPath:nil/keyPath _mappedToKeyArray:keys(array)
|
||||
*/
|
||||
NSString *_mappedToKey; ///< the key mapped to
|
||||
NSArray *_mappedToKeyPath; ///< the key path mapped to (nil if the name is not key path)
|
||||
NSArray *_mappedToKeyArray; ///< the key(NSString) or keyPath(NSArray) array (nil if not mapped to multiple keys)
|
||||
YYClassPropertyInfo *_info; ///< property's info
|
||||
_YYModelPropertyMeta *_next; ///< next meta if there are multiple properties mapped to the same key.
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation _YYModelPropertyMeta
|
||||
+ (instancetype)metaWithClassInfo:(YYClassInfo *)classInfo propertyInfo:(YYClassPropertyInfo *)propertyInfo generic:(Class)generic {
|
||||
|
||||
// support pseudo generic class with protocol name
|
||||
if (!generic && propertyInfo.protocols) {
|
||||
for (NSString *protocol in propertyInfo.protocols) {
|
||||
Class cls = objc_getClass(protocol.UTF8String);
|
||||
if (cls) {
|
||||
generic = cls;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_YYModelPropertyMeta *meta = [self new];
|
||||
meta->_name = propertyInfo.name;
|
||||
meta->_type = propertyInfo.type;
|
||||
meta->_info = propertyInfo;
|
||||
meta->_genericCls = generic;
|
||||
|
||||
if ((meta->_type & YYEncodingTypeMask) == YYEncodingTypeObject) {
|
||||
meta->_nsType = YYClassGetNSType(propertyInfo.cls);
|
||||
} else {
|
||||
meta->_isCNumber = YYEncodingTypeIsCNumber(meta->_type);
|
||||
}
|
||||
if ((meta->_type & YYEncodingTypeMask) == YYEncodingTypeStruct) {
|
||||
/*
|
||||
It seems that NSKeyedUnarchiver cannot decode NSValue except these structs:
|
||||
*/
|
||||
static NSSet *types = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
NSMutableSet *set = [NSMutableSet new];
|
||||
// 32 bit
|
||||
[set addObject:@"{CGSize=ff}"];
|
||||
[set addObject:@"{CGPoint=ff}"];
|
||||
[set addObject:@"{CGRect={CGPoint=ff}{CGSize=ff}}"];
|
||||
[set addObject:@"{CGAffineTransform=ffffff}"];
|
||||
[set addObject:@"{UIEdgeInsets=ffff}"];
|
||||
[set addObject:@"{UIOffset=ff}"];
|
||||
// 64 bit
|
||||
[set addObject:@"{CGSize=dd}"];
|
||||
[set addObject:@"{CGPoint=dd}"];
|
||||
[set addObject:@"{CGRect={CGPoint=dd}{CGSize=dd}}"];
|
||||
[set addObject:@"{CGAffineTransform=dddddd}"];
|
||||
[set addObject:@"{UIEdgeInsets=dddd}"];
|
||||
[set addObject:@"{UIOffset=dd}"];
|
||||
types = set;
|
||||
});
|
||||
if ([types containsObject:propertyInfo.typeEncoding]) {
|
||||
meta->_isStructAvailableForKeyedArchiver = YES;
|
||||
}
|
||||
}
|
||||
meta->_cls = propertyInfo.cls;
|
||||
|
||||
if (generic) {
|
||||
meta->_hasCustomClassFromDictionary = [generic respondsToSelector:@selector(modelCustomClassForDictionary:)];
|
||||
} else if (meta->_cls && meta->_nsType == YYEncodingTypeNSUnknown) {
|
||||
meta->_hasCustomClassFromDictionary = [meta->_cls respondsToSelector:@selector(modelCustomClassForDictionary:)];
|
||||
}
|
||||
|
||||
if (propertyInfo.getter) {
|
||||
if ([classInfo.cls instancesRespondToSelector:propertyInfo.getter]) {
|
||||
meta->_getter = propertyInfo.getter;
|
||||
}
|
||||
}
|
||||
if (propertyInfo.setter) {
|
||||
if ([classInfo.cls instancesRespondToSelector:propertyInfo.setter]) {
|
||||
meta->_setter = propertyInfo.setter;
|
||||
}
|
||||
}
|
||||
|
||||
if (meta->_getter && meta->_setter) {
|
||||
/*
|
||||
KVC invalid type:
|
||||
long double
|
||||
pointer (such as SEL/CoreFoundation object)
|
||||
*/
|
||||
switch (meta->_type & YYEncodingTypeMask) {
|
||||
case YYEncodingTypeBool:
|
||||
case YYEncodingTypeInt8:
|
||||
case YYEncodingTypeUInt8:
|
||||
case YYEncodingTypeInt16:
|
||||
case YYEncodingTypeUInt16:
|
||||
case YYEncodingTypeInt32:
|
||||
case YYEncodingTypeUInt32:
|
||||
case YYEncodingTypeInt64:
|
||||
case YYEncodingTypeUInt64:
|
||||
case YYEncodingTypeFloat:
|
||||
case YYEncodingTypeDouble:
|
||||
case YYEncodingTypeObject:
|
||||
case YYEncodingTypeClass:
|
||||
case YYEncodingTypeBlock:
|
||||
case YYEncodingTypeStruct:
|
||||
case YYEncodingTypeUnion: {
|
||||
meta->_isKVCCompatible = YES;
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
return meta;
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
/// A class info in object model.
|
||||
@interface _YYModelMeta : NSObject {
|
||||
@package
|
||||
YYClassInfo *_classInfo;
|
||||
/// Key:mapped key and key path, Value:_YYModelPropertyMeta.
|
||||
NSDictionary *_mapper;
|
||||
/// Array<_YYModelPropertyMeta>, all property meta of this model.
|
||||
NSArray *_allPropertyMetas;
|
||||
/// Array<_YYModelPropertyMeta>, property meta which is mapped to a key path.
|
||||
NSArray *_keyPathPropertyMetas;
|
||||
/// Array<_YYModelPropertyMeta>, property meta which is mapped to multi keys.
|
||||
NSArray *_multiKeysPropertyMetas;
|
||||
/// The number of mapped key (and key path), same to _mapper.count.
|
||||
NSUInteger _keyMappedCount;
|
||||
/// Model class type.
|
||||
YYEncodingNSType _nsType;
|
||||
|
||||
BOOL _hasCustomWillTransformFromDictionary;
|
||||
BOOL _hasCustomTransformFromDictionary;
|
||||
BOOL _hasCustomTransformToDictionary;
|
||||
BOOL _hasCustomClassFromDictionary;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation _YYModelMeta
|
||||
- (instancetype)initWithClass:(Class)cls {
|
||||
YYClassInfo *classInfo = [YYClassInfo classInfoWithClass:cls];
|
||||
if (!classInfo) return nil;
|
||||
self = [super init];
|
||||
|
||||
// Get black list
|
||||
NSSet *blacklist = nil;
|
||||
if ([cls respondsToSelector:@selector(modelPropertyBlacklist)]) {
|
||||
NSArray *properties = [(id<YYModel>)cls modelPropertyBlacklist];
|
||||
if (properties) {
|
||||
blacklist = [NSSet setWithArray:properties];
|
||||
}
|
||||
}
|
||||
|
||||
// Get white list
|
||||
NSSet *whitelist = nil;
|
||||
if ([cls respondsToSelector:@selector(modelPropertyWhitelist)]) {
|
||||
NSArray *properties = [(id<YYModel>)cls modelPropertyWhitelist];
|
||||
if (properties) {
|
||||
whitelist = [NSSet setWithArray:properties];
|
||||
}
|
||||
}
|
||||
|
||||
// Get container property's generic class
|
||||
NSDictionary *genericMapper = nil;
|
||||
if ([cls respondsToSelector:@selector(modelContainerPropertyGenericClass)]) {
|
||||
genericMapper = [(id<YYModel>)cls modelContainerPropertyGenericClass];
|
||||
if (genericMapper) {
|
||||
NSMutableDictionary *tmp = [NSMutableDictionary new];
|
||||
[genericMapper enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
|
||||
if (![key isKindOfClass:[NSString class]]) return;
|
||||
Class meta = object_getClass(obj);
|
||||
if (!meta) return;
|
||||
if (class_isMetaClass(meta)) {
|
||||
tmp[key] = obj;
|
||||
} else if ([obj isKindOfClass:[NSString class]]) {
|
||||
Class cls = NSClassFromString(obj);
|
||||
if (cls) {
|
||||
tmp[key] = cls;
|
||||
}
|
||||
}
|
||||
}];
|
||||
genericMapper = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
// Create all property metas.
|
||||
NSMutableDictionary *allPropertyMetas = [NSMutableDictionary new];
|
||||
YYClassInfo *curClassInfo = classInfo;
|
||||
while (curClassInfo && curClassInfo.superCls != nil) { // recursive parse super class, but ignore root class (NSObject/NSProxy)
|
||||
for (YYClassPropertyInfo *propertyInfo in curClassInfo.propertyInfos.allValues) {
|
||||
if (!propertyInfo.name) continue;
|
||||
if (blacklist && [blacklist containsObject:propertyInfo.name]) continue;
|
||||
if (whitelist && ![whitelist containsObject:propertyInfo.name]) continue;
|
||||
_YYModelPropertyMeta *meta = [_YYModelPropertyMeta metaWithClassInfo:classInfo
|
||||
propertyInfo:propertyInfo
|
||||
generic:genericMapper[propertyInfo.name]];
|
||||
if (!meta || !meta->_name) continue;
|
||||
if (!meta->_getter || !meta->_setter) continue;
|
||||
if (allPropertyMetas[meta->_name]) continue;
|
||||
allPropertyMetas[meta->_name] = meta;
|
||||
}
|
||||
curClassInfo = curClassInfo.superClassInfo;
|
||||
}
|
||||
if (allPropertyMetas.count) _allPropertyMetas = allPropertyMetas.allValues.copy;
|
||||
|
||||
// create mapper
|
||||
NSMutableDictionary *mapper = [NSMutableDictionary new];
|
||||
NSMutableArray *keyPathPropertyMetas = [NSMutableArray new];
|
||||
NSMutableArray *multiKeysPropertyMetas = [NSMutableArray new];
|
||||
|
||||
if ([cls respondsToSelector:@selector(modelCustomPropertyMapper)]) {
|
||||
NSDictionary *customMapper = [(id <YYModel>)cls modelCustomPropertyMapper];
|
||||
[customMapper enumerateKeysAndObjectsUsingBlock:^(NSString *propertyName, NSString *mappedToKey, BOOL *stop) {
|
||||
_YYModelPropertyMeta *propertyMeta = allPropertyMetas[propertyName];
|
||||
if (!propertyMeta) return;
|
||||
[allPropertyMetas removeObjectForKey:propertyName];
|
||||
|
||||
if ([mappedToKey isKindOfClass:[NSString class]]) {
|
||||
if (mappedToKey.length == 0) return;
|
||||
|
||||
propertyMeta->_mappedToKey = mappedToKey;
|
||||
NSArray *keyPath = [mappedToKey componentsSeparatedByString:@"."];
|
||||
for (NSString *onePath in keyPath) {
|
||||
if (onePath.length == 0) {
|
||||
NSMutableArray *tmp = keyPath.mutableCopy;
|
||||
[tmp removeObject:@""];
|
||||
keyPath = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (keyPath.count > 1) {
|
||||
propertyMeta->_mappedToKeyPath = keyPath;
|
||||
[keyPathPropertyMetas addObject:propertyMeta];
|
||||
}
|
||||
propertyMeta->_next = mapper[mappedToKey] ?: nil;
|
||||
mapper[mappedToKey] = propertyMeta;
|
||||
|
||||
} else if ([mappedToKey isKindOfClass:[NSArray class]]) {
|
||||
|
||||
NSMutableArray *mappedToKeyArray = [NSMutableArray new];
|
||||
for (NSString *oneKey in ((NSArray *)mappedToKey)) {
|
||||
if (![oneKey isKindOfClass:[NSString class]]) continue;
|
||||
if (oneKey.length == 0) continue;
|
||||
|
||||
NSArray *keyPath = [oneKey componentsSeparatedByString:@"."];
|
||||
if (keyPath.count > 1) {
|
||||
[mappedToKeyArray addObject:keyPath];
|
||||
} else {
|
||||
[mappedToKeyArray addObject:oneKey];
|
||||
}
|
||||
|
||||
if (!propertyMeta->_mappedToKey) {
|
||||
propertyMeta->_mappedToKey = oneKey;
|
||||
propertyMeta->_mappedToKeyPath = keyPath.count > 1 ? keyPath : nil;
|
||||
}
|
||||
}
|
||||
if (!propertyMeta->_mappedToKey) return;
|
||||
|
||||
propertyMeta->_mappedToKeyArray = mappedToKeyArray;
|
||||
[multiKeysPropertyMetas addObject:propertyMeta];
|
||||
|
||||
propertyMeta->_next = mapper[mappedToKey] ?: nil;
|
||||
mapper[mappedToKey] = propertyMeta;
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
[allPropertyMetas enumerateKeysAndObjectsUsingBlock:^(NSString *name, _YYModelPropertyMeta *propertyMeta, BOOL *stop) {
|
||||
propertyMeta->_mappedToKey = name;
|
||||
propertyMeta->_next = mapper[name] ?: nil;
|
||||
mapper[name] = propertyMeta;
|
||||
}];
|
||||
|
||||
if (mapper.count) _mapper = mapper;
|
||||
if (keyPathPropertyMetas) _keyPathPropertyMetas = keyPathPropertyMetas;
|
||||
if (multiKeysPropertyMetas) _multiKeysPropertyMetas = multiKeysPropertyMetas;
|
||||
|
||||
_classInfo = classInfo;
|
||||
_keyMappedCount = _allPropertyMetas.count;
|
||||
_nsType = YYClassGetNSType(cls);
|
||||
_hasCustomWillTransformFromDictionary = ([cls instancesRespondToSelector:@selector(modelCustomWillTransformFromDictionary:)]);
|
||||
_hasCustomTransformFromDictionary = ([cls instancesRespondToSelector:@selector(modelCustomTransformFromDictionary:)]);
|
||||
_hasCustomTransformToDictionary = ([cls instancesRespondToSelector:@selector(modelCustomTransformToDictionary:)]);
|
||||
_hasCustomClassFromDictionary = ([cls respondsToSelector:@selector(modelCustomClassForDictionary:)]);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/// Returns the cached model class meta
|
||||
+ (instancetype)metaWithClass:(Class)cls {
|
||||
if (!cls) return nil;
|
||||
static CFMutableDictionaryRef cache;
|
||||
static dispatch_once_t onceToken;
|
||||
static dispatch_semaphore_t lock;
|
||||
dispatch_once(&onceToken, ^{
|
||||
cache = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
lock = dispatch_semaphore_create(1);
|
||||
});
|
||||
dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
|
||||
_YYModelMeta *meta = CFDictionaryGetValue(cache, (__bridge const void *)(cls));
|
||||
dispatch_semaphore_signal(lock);
|
||||
if (!meta || meta->_classInfo.needUpdate) {
|
||||
meta = [[_YYModelMeta alloc] initWithClass:cls];
|
||||
if (meta) {
|
||||
dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
|
||||
CFDictionarySetValue(cache, (__bridge const void *)(cls), (__bridge const void *)(meta));
|
||||
dispatch_semaphore_signal(lock);
|
||||
}
|
||||
}
|
||||
return meta;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
/**
|
||||
Get number from property.
|
||||
@discussion Caller should hold strong reference to the parameters before this function returns.
|
||||
@param model Should not be nil.
|
||||
@param meta Should not be nil, meta.isCNumber should be YES, meta.getter should not be nil.
|
||||
@return A number object, or nil if failed.
|
||||
*/
|
||||
static force_inline NSNumber *ModelCreateNumberFromProperty(__unsafe_unretained id model,
|
||||
__unsafe_unretained _YYModelPropertyMeta *meta) {
|
||||
switch (meta->_type & YYEncodingTypeMask) {
|
||||
case YYEncodingTypeBool: {
|
||||
return @(((bool (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
|
||||
}
|
||||
case YYEncodingTypeInt8: {
|
||||
return @(((int8_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
|
||||
}
|
||||
case YYEncodingTypeUInt8: {
|
||||
return @(((uint8_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
|
||||
}
|
||||
case YYEncodingTypeInt16: {
|
||||
return @(((int16_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
|
||||
}
|
||||
case YYEncodingTypeUInt16: {
|
||||
return @(((uint16_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
|
||||
}
|
||||
case YYEncodingTypeInt32: {
|
||||
return @(((int32_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
|
||||
}
|
||||
case YYEncodingTypeUInt32: {
|
||||
return @(((uint32_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
|
||||
}
|
||||
case YYEncodingTypeInt64: {
|
||||
return @(((int64_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
|
||||
}
|
||||
case YYEncodingTypeUInt64: {
|
||||
return @(((uint64_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
|
||||
}
|
||||
case YYEncodingTypeFloat: {
|
||||
float num = ((float (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter);
|
||||
if (isnan(num) || isinf(num)) return nil;
|
||||
return @(num);
|
||||
}
|
||||
case YYEncodingTypeDouble: {
|
||||
double num = ((double (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter);
|
||||
if (isnan(num) || isinf(num)) return nil;
|
||||
return @(num);
|
||||
}
|
||||
case YYEncodingTypeLongDouble: {
|
||||
double num = ((long double (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter);
|
||||
if (isnan(num) || isinf(num)) return nil;
|
||||
return @(num);
|
||||
}
|
||||
default: return nil;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Set number to property.
|
||||
@discussion Caller should hold strong reference to the parameters before this function returns.
|
||||
@param model Should not be nil.
|
||||
@param num Can be nil.
|
||||
@param meta Should not be nil, meta.isCNumber should be YES, meta.setter should not be nil.
|
||||
*/
|
||||
static force_inline void ModelSetNumberToProperty(__unsafe_unretained id model,
|
||||
__unsafe_unretained NSNumber *num,
|
||||
__unsafe_unretained _YYModelPropertyMeta *meta) {
|
||||
switch (meta->_type & YYEncodingTypeMask) {
|
||||
case YYEncodingTypeBool: {
|
||||
((void (*)(id, SEL, bool))(void *) objc_msgSend)((id)model, meta->_setter, num.boolValue);
|
||||
} break;
|
||||
case YYEncodingTypeInt8: {
|
||||
((void (*)(id, SEL, int8_t))(void *) objc_msgSend)((id)model, meta->_setter, (int8_t)num.charValue);
|
||||
} break;
|
||||
case YYEncodingTypeUInt8: {
|
||||
((void (*)(id, SEL, uint8_t))(void *) objc_msgSend)((id)model, meta->_setter, (uint8_t)num.unsignedCharValue);
|
||||
} break;
|
||||
case YYEncodingTypeInt16: {
|
||||
((void (*)(id, SEL, int16_t))(void *) objc_msgSend)((id)model, meta->_setter, (int16_t)num.shortValue);
|
||||
} break;
|
||||
case YYEncodingTypeUInt16: {
|
||||
((void (*)(id, SEL, uint16_t))(void *) objc_msgSend)((id)model, meta->_setter, (uint16_t)num.unsignedShortValue);
|
||||
} break;
|
||||
case YYEncodingTypeInt32: {
|
||||
((void (*)(id, SEL, int32_t))(void *) objc_msgSend)((id)model, meta->_setter, (int32_t)num.intValue);
|
||||
}
|
||||
case YYEncodingTypeUInt32: {
|
||||
((void (*)(id, SEL, uint32_t))(void *) objc_msgSend)((id)model, meta->_setter, (uint32_t)num.unsignedIntValue);
|
||||
} break;
|
||||
case YYEncodingTypeInt64: {
|
||||
if ([num isKindOfClass:[NSDecimalNumber class]]) {
|
||||
((void (*)(id, SEL, int64_t))(void *) objc_msgSend)((id)model, meta->_setter, (int64_t)num.stringValue.longLongValue);
|
||||
} else {
|
||||
((void (*)(id, SEL, uint64_t))(void *) objc_msgSend)((id)model, meta->_setter, (uint64_t)num.longLongValue);
|
||||
}
|
||||
} break;
|
||||
case YYEncodingTypeUInt64: {
|
||||
if ([num isKindOfClass:[NSDecimalNumber class]]) {
|
||||
((void (*)(id, SEL, int64_t))(void *) objc_msgSend)((id)model, meta->_setter, (int64_t)num.stringValue.longLongValue);
|
||||
} else {
|
||||
((void (*)(id, SEL, uint64_t))(void *) objc_msgSend)((id)model, meta->_setter, (uint64_t)num.unsignedLongLongValue);
|
||||
}
|
||||
} break;
|
||||
case YYEncodingTypeFloat: {
|
||||
float f = num.floatValue;
|
||||
if (isnan(f) || isinf(f)) f = 0;
|
||||
((void (*)(id, SEL, float))(void *) objc_msgSend)((id)model, meta->_setter, f);
|
||||
} break;
|
||||
case YYEncodingTypeDouble: {
|
||||
double d = num.doubleValue;
|
||||
if (isnan(d) || isinf(d)) d = 0;
|
||||
((void (*)(id, SEL, double))(void *) objc_msgSend)((id)model, meta->_setter, d);
|
||||
} break;
|
||||
case YYEncodingTypeLongDouble: {
|
||||
long double d = num.doubleValue;
|
||||
if (isnan(d) || isinf(d)) d = 0;
|
||||
((void (*)(id, SEL, long double))(void *) objc_msgSend)((id)model, meta->_setter, (long double)d);
|
||||
} // break; commented for code coverage in next line
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Set value to model with a property meta.
|
||||
|
||||
@discussion Caller should hold strong reference to the parameters before this function returns.
|
||||
|
||||
@param model Should not be nil.
|
||||
@param value Should not be nil, but can be NSNull.
|
||||
@param meta Should not be nil, and meta->_setter should not be nil.
|
||||
*/
|
||||
static void ModelSetValueForProperty(__unsafe_unretained id model,
|
||||
__unsafe_unretained id value,
|
||||
__unsafe_unretained _YYModelPropertyMeta *meta) {
|
||||
if (meta->_isCNumber) {
|
||||
NSNumber *num = YYNSNumberCreateFromID(value);
|
||||
ModelSetNumberToProperty(model, num, meta);
|
||||
if (num) [num class]; // hold the number
|
||||
} else if (meta->_nsType) {
|
||||
if (value == (id)kCFNull) {
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, (id)nil);
|
||||
} else {
|
||||
switch (meta->_nsType) {
|
||||
case YYEncodingTypeNSString:
|
||||
case YYEncodingTypeNSMutableString: {
|
||||
if ([value isKindOfClass:[NSString class]]) {
|
||||
if (meta->_nsType == YYEncodingTypeNSString) {
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
|
||||
} else {
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, ((NSString *)value).mutableCopy);
|
||||
}
|
||||
} else if ([value isKindOfClass:[NSNumber class]]) {
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
|
||||
meta->_setter,
|
||||
(meta->_nsType == YYEncodingTypeNSString) ?
|
||||
((NSNumber *)value).stringValue :
|
||||
((NSNumber *)value).stringValue.mutableCopy);
|
||||
} else if ([value isKindOfClass:[NSData class]]) {
|
||||
NSMutableString *string = [[NSMutableString alloc] initWithData:value encoding:NSUTF8StringEncoding];
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, string);
|
||||
} else if ([value isKindOfClass:[NSURL class]]) {
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
|
||||
meta->_setter,
|
||||
(meta->_nsType == YYEncodingTypeNSString) ?
|
||||
((NSURL *)value).absoluteString :
|
||||
((NSURL *)value).absoluteString.mutableCopy);
|
||||
} else if ([value isKindOfClass:[NSAttributedString class]]) {
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
|
||||
meta->_setter,
|
||||
(meta->_nsType == YYEncodingTypeNSString) ?
|
||||
((NSAttributedString *)value).string :
|
||||
((NSAttributedString *)value).string.mutableCopy);
|
||||
}
|
||||
} break;
|
||||
|
||||
case YYEncodingTypeNSValue:
|
||||
case YYEncodingTypeNSNumber:
|
||||
case YYEncodingTypeNSDecimalNumber: {
|
||||
if (meta->_nsType == YYEncodingTypeNSNumber) {
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, YYNSNumberCreateFromID(value));
|
||||
} else if (meta->_nsType == YYEncodingTypeNSDecimalNumber) {
|
||||
if ([value isKindOfClass:[NSDecimalNumber class]]) {
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
|
||||
} else if ([value isKindOfClass:[NSNumber class]]) {
|
||||
NSDecimalNumber *decNum = [NSDecimalNumber decimalNumberWithDecimal:[((NSNumber *)value) decimalValue]];
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, decNum);
|
||||
} else if ([value isKindOfClass:[NSString class]]) {
|
||||
NSDecimalNumber *decNum = [NSDecimalNumber decimalNumberWithString:value];
|
||||
NSDecimal dec = decNum.decimalValue;
|
||||
if (dec._length == 0 && dec._isNegative) {
|
||||
decNum = nil; // NaN
|
||||
}
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, decNum);
|
||||
}
|
||||
} else { // YYEncodingTypeNSValue
|
||||
if ([value isKindOfClass:[NSValue class]]) {
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case YYEncodingTypeNSData:
|
||||
case YYEncodingTypeNSMutableData: {
|
||||
if ([value isKindOfClass:[NSData class]]) {
|
||||
if (meta->_nsType == YYEncodingTypeNSData) {
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
|
||||
} else {
|
||||
NSMutableData *data = ((NSData *)value).mutableCopy;
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, data);
|
||||
}
|
||||
} else if ([value isKindOfClass:[NSString class]]) {
|
||||
NSData *data = [(NSString *)value dataUsingEncoding:NSUTF8StringEncoding];
|
||||
if (meta->_nsType == YYEncodingTypeNSMutableData) {
|
||||
data = ((NSData *)data).mutableCopy;
|
||||
}
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, data);
|
||||
}
|
||||
} break;
|
||||
|
||||
case YYEncodingTypeNSDate: {
|
||||
if ([value isKindOfClass:[NSDate class]]) {
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
|
||||
} else if ([value isKindOfClass:[NSString class]]) {
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, YYNSDateFromString(value));
|
||||
}
|
||||
} break;
|
||||
|
||||
case YYEncodingTypeNSURL: {
|
||||
if ([value isKindOfClass:[NSURL class]]) {
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
|
||||
} else if ([value isKindOfClass:[NSString class]]) {
|
||||
NSCharacterSet *set = [NSCharacterSet whitespaceAndNewlineCharacterSet];
|
||||
NSString *str = [value stringByTrimmingCharactersInSet:set];
|
||||
if (str.length == 0) {
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, nil);
|
||||
} else {
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, [[NSURL alloc] initWithString:str]);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case YYEncodingTypeNSArray:
|
||||
case YYEncodingTypeNSMutableArray: {
|
||||
if (meta->_genericCls) {
|
||||
NSArray *valueArr = nil;
|
||||
if ([value isKindOfClass:[NSArray class]]) valueArr = value;
|
||||
else if ([value isKindOfClass:[NSSet class]]) valueArr = ((NSSet *)value).allObjects;
|
||||
if (valueArr) {
|
||||
NSMutableArray *objectArr = [NSMutableArray new];
|
||||
for (id one in valueArr) {
|
||||
if ([one isKindOfClass:meta->_genericCls]) {
|
||||
[objectArr addObject:one];
|
||||
} else if ([one isKindOfClass:[NSDictionary class]]) {
|
||||
Class cls = meta->_genericCls;
|
||||
if (meta->_hasCustomClassFromDictionary) {
|
||||
cls = [cls modelCustomClassForDictionary:one];
|
||||
if (!cls) cls = meta->_genericCls; // for xcode code coverage
|
||||
}
|
||||
NSObject *newOne = [cls new];
|
||||
[newOne modelSetWithDictionary:one];
|
||||
if (newOne) [objectArr addObject:newOne];
|
||||
}
|
||||
}
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, objectArr);
|
||||
}
|
||||
} else {
|
||||
if ([value isKindOfClass:[NSArray class]]) {
|
||||
if (meta->_nsType == YYEncodingTypeNSArray) {
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
|
||||
} else {
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
|
||||
meta->_setter,
|
||||
((NSArray *)value).mutableCopy);
|
||||
}
|
||||
} else if ([value isKindOfClass:[NSSet class]]) {
|
||||
if (meta->_nsType == YYEncodingTypeNSArray) {
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, ((NSSet *)value).allObjects);
|
||||
} else {
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
|
||||
meta->_setter,
|
||||
((NSSet *)value).allObjects.mutableCopy);
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case YYEncodingTypeNSDictionary:
|
||||
case YYEncodingTypeNSMutableDictionary: {
|
||||
if ([value isKindOfClass:[NSDictionary class]]) {
|
||||
if (meta->_genericCls) {
|
||||
NSMutableDictionary *dic = [NSMutableDictionary new];
|
||||
[((NSDictionary *)value) enumerateKeysAndObjectsUsingBlock:^(NSString *oneKey, id oneValue, BOOL *stop) {
|
||||
if ([oneValue isKindOfClass:[NSDictionary class]]) {
|
||||
Class cls = meta->_genericCls;
|
||||
if (meta->_hasCustomClassFromDictionary) {
|
||||
cls = [cls modelCustomClassForDictionary:oneValue];
|
||||
if (!cls) cls = meta->_genericCls; // for xcode code coverage
|
||||
}
|
||||
NSObject *newOne = [cls new];
|
||||
[newOne modelSetWithDictionary:(id)oneValue];
|
||||
if (newOne) dic[oneKey] = newOne;
|
||||
}
|
||||
}];
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, dic);
|
||||
} else {
|
||||
if (meta->_nsType == YYEncodingTypeNSDictionary) {
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
|
||||
} else {
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
|
||||
meta->_setter,
|
||||
((NSDictionary *)value).mutableCopy);
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case YYEncodingTypeNSSet:
|
||||
case YYEncodingTypeNSMutableSet: {
|
||||
NSSet *valueSet = nil;
|
||||
if ([value isKindOfClass:[NSArray class]]) valueSet = [NSMutableSet setWithArray:value];
|
||||
else if ([value isKindOfClass:[NSSet class]]) valueSet = ((NSSet *)value);
|
||||
|
||||
if (meta->_genericCls) {
|
||||
NSMutableSet *set = [NSMutableSet new];
|
||||
for (id one in valueSet) {
|
||||
if ([one isKindOfClass:meta->_genericCls]) {
|
||||
[set addObject:one];
|
||||
} else if ([one isKindOfClass:[NSDictionary class]]) {
|
||||
Class cls = meta->_genericCls;
|
||||
if (meta->_hasCustomClassFromDictionary) {
|
||||
cls = [cls modelCustomClassForDictionary:one];
|
||||
if (!cls) cls = meta->_genericCls; // for xcode code coverage
|
||||
}
|
||||
NSObject *newOne = [cls new];
|
||||
[newOne modelSetWithDictionary:one];
|
||||
if (newOne) [set addObject:newOne];
|
||||
}
|
||||
}
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, set);
|
||||
} else {
|
||||
if (meta->_nsType == YYEncodingTypeNSSet) {
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, valueSet);
|
||||
} else {
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
|
||||
meta->_setter,
|
||||
((NSSet *)valueSet).mutableCopy);
|
||||
}
|
||||
}
|
||||
} // break; commented for code coverage in next line
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
BOOL isNull = (value == (id)kCFNull);
|
||||
switch (meta->_type & YYEncodingTypeMask) {
|
||||
case YYEncodingTypeObject: {
|
||||
if (isNull) {
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, (id)nil);
|
||||
} else if ([value isKindOfClass:meta->_cls] || !meta->_cls) {
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, (id)value);
|
||||
} else if ([value isKindOfClass:[NSDictionary class]]) {
|
||||
NSObject *one = nil;
|
||||
if (meta->_getter) {
|
||||
one = ((id (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter);
|
||||
}
|
||||
if (one) {
|
||||
[one modelSetWithDictionary:value];
|
||||
} else {
|
||||
Class cls = meta->_cls;
|
||||
if (meta->_hasCustomClassFromDictionary) {
|
||||
cls = [cls modelCustomClassForDictionary:value];
|
||||
if (!cls) cls = meta->_genericCls; // for xcode code coverage
|
||||
}
|
||||
one = [cls new];
|
||||
[one modelSetWithDictionary:value];
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, (id)one);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case YYEncodingTypeClass: {
|
||||
if (isNull) {
|
||||
((void (*)(id, SEL, Class))(void *) objc_msgSend)((id)model, meta->_setter, (Class)NULL);
|
||||
} else {
|
||||
Class cls = nil;
|
||||
if ([value isKindOfClass:[NSString class]]) {
|
||||
cls = NSClassFromString(value);
|
||||
if (cls) {
|
||||
((void (*)(id, SEL, Class))(void *) objc_msgSend)((id)model, meta->_setter, (Class)cls);
|
||||
}
|
||||
} else {
|
||||
cls = object_getClass(value);
|
||||
if (cls) {
|
||||
if (class_isMetaClass(cls)) {
|
||||
((void (*)(id, SEL, Class))(void *) objc_msgSend)((id)model, meta->_setter, (Class)value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case YYEncodingTypeSEL: {
|
||||
if (isNull) {
|
||||
((void (*)(id, SEL, SEL))(void *) objc_msgSend)((id)model, meta->_setter, (SEL)NULL);
|
||||
} else if ([value isKindOfClass:[NSString class]]) {
|
||||
SEL sel = NSSelectorFromString(value);
|
||||
if (sel) ((void (*)(id, SEL, SEL))(void *) objc_msgSend)((id)model, meta->_setter, (SEL)sel);
|
||||
}
|
||||
} break;
|
||||
|
||||
case YYEncodingTypeBlock: {
|
||||
if (isNull) {
|
||||
((void (*)(id, SEL, void (^)()))(void *) objc_msgSend)((id)model, meta->_setter, (void (^)())NULL);
|
||||
} else if ([value isKindOfClass:YYNSBlockClass()]) {
|
||||
((void (*)(id, SEL, void (^)()))(void *) objc_msgSend)((id)model, meta->_setter, (void (^)())value);
|
||||
}
|
||||
} break;
|
||||
|
||||
case YYEncodingTypeStruct:
|
||||
case YYEncodingTypeUnion:
|
||||
case YYEncodingTypeCArray: {
|
||||
if ([value isKindOfClass:[NSValue class]]) {
|
||||
const char *valueType = ((NSValue *)value).objCType;
|
||||
const char *metaType = meta->_info.typeEncoding.UTF8String;
|
||||
if (valueType && metaType && strcmp(valueType, metaType) == 0) {
|
||||
[model setValue:value forKey:meta->_name];
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case YYEncodingTypePointer:
|
||||
case YYEncodingTypeCString: {
|
||||
if (isNull) {
|
||||
((void (*)(id, SEL, void *))(void *) objc_msgSend)((id)model, meta->_setter, (void *)NULL);
|
||||
} else if ([value isKindOfClass:[NSValue class]]) {
|
||||
NSValue *nsValue = value;
|
||||
if (nsValue.objCType && strcmp(nsValue.objCType, "^v") == 0) {
|
||||
((void (*)(id, SEL, void *))(void *) objc_msgSend)((id)model, meta->_setter, nsValue.pointerValue);
|
||||
}
|
||||
}
|
||||
} // break; commented for code coverage in next line
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
void *modelMeta; ///< _YYModelMeta
|
||||
void *model; ///< id (self)
|
||||
void *dictionary; ///< NSDictionary (json)
|
||||
} ModelSetContext;
|
||||
|
||||
/**
|
||||
Apply function for dictionary, to set the key-value pair to model.
|
||||
|
||||
@param _key should not be nil, NSString.
|
||||
@param _value should not be nil.
|
||||
@param _context _context.modelMeta and _context.model should not be nil.
|
||||
*/
|
||||
static void ModelSetWithDictionaryFunction(const void *_key, const void *_value, void *_context) {
|
||||
ModelSetContext *context = _context;
|
||||
__unsafe_unretained _YYModelMeta *meta = (__bridge _YYModelMeta *)(context->modelMeta);
|
||||
__unsafe_unretained _YYModelPropertyMeta *propertyMeta = [meta->_mapper objectForKey:(__bridge id)(_key)];
|
||||
__unsafe_unretained id model = (__bridge id)(context->model);
|
||||
while (propertyMeta) {
|
||||
if (propertyMeta->_setter) {
|
||||
ModelSetValueForProperty(model, (__bridge __unsafe_unretained id)_value, propertyMeta);
|
||||
}
|
||||
propertyMeta = propertyMeta->_next;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
Apply function for model property meta, to set dictionary to model.
|
||||
|
||||
@param _propertyMeta should not be nil, _YYModelPropertyMeta.
|
||||
@param _context _context.model and _context.dictionary should not be nil.
|
||||
*/
|
||||
static void ModelSetWithPropertyMetaArrayFunction(const void *_propertyMeta, void *_context) {
|
||||
ModelSetContext *context = _context;
|
||||
__unsafe_unretained NSDictionary *dictionary = (__bridge NSDictionary *)(context->dictionary);
|
||||
__unsafe_unretained _YYModelPropertyMeta *propertyMeta = (__bridge _YYModelPropertyMeta *)(_propertyMeta);
|
||||
if (!propertyMeta->_setter) return;
|
||||
id value = nil;
|
||||
|
||||
if (propertyMeta->_mappedToKeyArray) {
|
||||
value = YYValueForMultiKeys(dictionary, propertyMeta->_mappedToKeyArray);
|
||||
} else if (propertyMeta->_mappedToKeyPath) {
|
||||
value = YYValueForKeyPath(dictionary, propertyMeta->_mappedToKeyPath);
|
||||
} else {
|
||||
value = [dictionary objectForKey:propertyMeta->_mappedToKey];
|
||||
}
|
||||
|
||||
if (value) {
|
||||
__unsafe_unretained id model = (__bridge id)(context->model);
|
||||
ModelSetValueForProperty(model, value, propertyMeta);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Returns a valid JSON object (NSArray/NSDictionary/NSString/NSNumber/NSNull),
|
||||
or nil if an error occurs.
|
||||
|
||||
@param model Model, can be nil.
|
||||
@return JSON object, nil if an error occurs.
|
||||
*/
|
||||
static id ModelToJSONObjectRecursive(NSObject *model) {
|
||||
if (!model || model == (id)kCFNull) return model;
|
||||
if ([model isKindOfClass:[NSString class]]) return model;
|
||||
if ([model isKindOfClass:[NSNumber class]]) return model;
|
||||
if ([model isKindOfClass:[NSDictionary class]]) {
|
||||
if ([NSJSONSerialization isValidJSONObject:model]) return model;
|
||||
NSMutableDictionary *newDic = [NSMutableDictionary new];
|
||||
[((NSDictionary *)model) enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
|
||||
NSString *stringKey = [key isKindOfClass:[NSString class]] ? key : key.description;
|
||||
if (!stringKey) return;
|
||||
id jsonObj = ModelToJSONObjectRecursive(obj);
|
||||
if (!jsonObj) jsonObj = (id)kCFNull;
|
||||
newDic[stringKey] = jsonObj;
|
||||
}];
|
||||
return newDic;
|
||||
}
|
||||
if ([model isKindOfClass:[NSSet class]]) {
|
||||
NSArray *array = ((NSSet *)model).allObjects;
|
||||
if ([NSJSONSerialization isValidJSONObject:array]) return array;
|
||||
NSMutableArray *newArray = [NSMutableArray new];
|
||||
for (id obj in array) {
|
||||
if ([obj isKindOfClass:[NSString class]] || [obj isKindOfClass:[NSNumber class]]) {
|
||||
[newArray addObject:obj];
|
||||
} else {
|
||||
id jsonObj = ModelToJSONObjectRecursive(obj);
|
||||
if (jsonObj && jsonObj != (id)kCFNull) [newArray addObject:jsonObj];
|
||||
}
|
||||
}
|
||||
return newArray;
|
||||
}
|
||||
if ([model isKindOfClass:[NSArray class]]) {
|
||||
if ([NSJSONSerialization isValidJSONObject:model]) return model;
|
||||
NSMutableArray *newArray = [NSMutableArray new];
|
||||
for (id obj in (NSArray *)model) {
|
||||
if ([obj isKindOfClass:[NSString class]] || [obj isKindOfClass:[NSNumber class]]) {
|
||||
[newArray addObject:obj];
|
||||
} else {
|
||||
id jsonObj = ModelToJSONObjectRecursive(obj);
|
||||
if (jsonObj && jsonObj != (id)kCFNull) [newArray addObject:jsonObj];
|
||||
}
|
||||
}
|
||||
return newArray;
|
||||
}
|
||||
if ([model isKindOfClass:[NSURL class]]) return ((NSURL *)model).absoluteString;
|
||||
if ([model isKindOfClass:[NSAttributedString class]]) return ((NSAttributedString *)model).string;
|
||||
if ([model isKindOfClass:[NSDate class]]) return [YYISODateFormatter() stringFromDate:(id)model];
|
||||
if ([model isKindOfClass:[NSData class]]) return nil;
|
||||
|
||||
|
||||
_YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:[model class]];
|
||||
if (!modelMeta || modelMeta->_keyMappedCount == 0) return nil;
|
||||
NSMutableDictionary *result = [[NSMutableDictionary alloc] initWithCapacity:64];
|
||||
__unsafe_unretained NSMutableDictionary *dic = result; // avoid retain and release in block
|
||||
[modelMeta->_mapper enumerateKeysAndObjectsUsingBlock:^(NSString *propertyMappedKey, _YYModelPropertyMeta *propertyMeta, BOOL *stop) {
|
||||
if (!propertyMeta->_getter) return;
|
||||
|
||||
id value = nil;
|
||||
if (propertyMeta->_isCNumber) {
|
||||
value = ModelCreateNumberFromProperty(model, propertyMeta);
|
||||
} else if (propertyMeta->_nsType) {
|
||||
id v = ((id (*)(id, SEL))(void *) objc_msgSend)((id)model, propertyMeta->_getter);
|
||||
value = ModelToJSONObjectRecursive(v);
|
||||
} else {
|
||||
switch (propertyMeta->_type & YYEncodingTypeMask) {
|
||||
case YYEncodingTypeObject: {
|
||||
id v = ((id (*)(id, SEL))(void *) objc_msgSend)((id)model, propertyMeta->_getter);
|
||||
value = ModelToJSONObjectRecursive(v);
|
||||
if (value == (id)kCFNull) value = nil;
|
||||
} break;
|
||||
case YYEncodingTypeClass: {
|
||||
Class v = ((Class (*)(id, SEL))(void *) objc_msgSend)((id)model, propertyMeta->_getter);
|
||||
value = v ? NSStringFromClass(v) : nil;
|
||||
} break;
|
||||
case YYEncodingTypeSEL: {
|
||||
SEL v = ((SEL (*)(id, SEL))(void *) objc_msgSend)((id)model, propertyMeta->_getter);
|
||||
value = v ? NSStringFromSelector(v) : nil;
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
if (!value) return;
|
||||
|
||||
if (propertyMeta->_mappedToKeyPath) {
|
||||
NSMutableDictionary *superDic = dic;
|
||||
NSMutableDictionary *subDic = nil;
|
||||
for (NSUInteger i = 0, max = propertyMeta->_mappedToKeyPath.count; i < max; i++) {
|
||||
NSString *key = propertyMeta->_mappedToKeyPath[i];
|
||||
if (i + 1 == max) { // end
|
||||
if (!superDic[key]) superDic[key] = value;
|
||||
break;
|
||||
}
|
||||
|
||||
subDic = superDic[key];
|
||||
if (subDic) {
|
||||
if ([subDic isKindOfClass:[NSDictionary class]]) {
|
||||
subDic = subDic.mutableCopy;
|
||||
superDic[key] = subDic;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
subDic = [NSMutableDictionary new];
|
||||
superDic[key] = subDic;
|
||||
}
|
||||
superDic = subDic;
|
||||
subDic = nil;
|
||||
}
|
||||
} else {
|
||||
if (!dic[propertyMeta->_mappedToKey]) {
|
||||
dic[propertyMeta->_mappedToKey] = value;
|
||||
}
|
||||
}
|
||||
}];
|
||||
|
||||
if (modelMeta->_hasCustomTransformToDictionary) {
|
||||
BOOL suc = [((id<YYModel>)model) modelCustomTransformToDictionary:dic];
|
||||
if (!suc) return nil;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Add indent to string (exclude first line)
|
||||
static NSMutableString *ModelDescriptionAddIndent(NSMutableString *desc, NSUInteger indent) {
|
||||
for (NSUInteger i = 0, max = desc.length; i < max; i++) {
|
||||
unichar c = [desc characterAtIndex:i];
|
||||
if (c == '\n') {
|
||||
for (NSUInteger j = 0; j < indent; j++) {
|
||||
[desc insertString:@" " atIndex:i + 1];
|
||||
}
|
||||
i += indent * 4;
|
||||
max += indent * 4;
|
||||
}
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
|
||||
/// Generaate a description string
|
||||
static NSString *ModelDescription(NSObject *model) {
|
||||
static const int kDescMaxLength = 100;
|
||||
if (!model) return @"<nil>";
|
||||
if (model == (id)kCFNull) return @"<null>";
|
||||
if (![model isKindOfClass:[NSObject class]]) return [NSString stringWithFormat:@"%@",model];
|
||||
|
||||
|
||||
_YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:model.class];
|
||||
switch (modelMeta->_nsType) {
|
||||
case YYEncodingTypeNSString: case YYEncodingTypeNSMutableString: {
|
||||
return [NSString stringWithFormat:@"\"%@\"",model];
|
||||
}
|
||||
|
||||
case YYEncodingTypeNSValue:
|
||||
case YYEncodingTypeNSData: case YYEncodingTypeNSMutableData: {
|
||||
NSString *tmp = model.description;
|
||||
if (tmp.length > kDescMaxLength) {
|
||||
tmp = [tmp substringToIndex:kDescMaxLength];
|
||||
tmp = [tmp stringByAppendingString:@"..."];
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
case YYEncodingTypeNSNumber:
|
||||
case YYEncodingTypeNSDecimalNumber:
|
||||
case YYEncodingTypeNSDate:
|
||||
case YYEncodingTypeNSURL: {
|
||||
return [NSString stringWithFormat:@"%@",model];
|
||||
}
|
||||
|
||||
case YYEncodingTypeNSSet: case YYEncodingTypeNSMutableSet: {
|
||||
model = ((NSSet *)model).allObjects;
|
||||
} // no break
|
||||
|
||||
case YYEncodingTypeNSArray: case YYEncodingTypeNSMutableArray: {
|
||||
NSArray *array = (id)model;
|
||||
NSMutableString *desc = [NSMutableString new];
|
||||
if (array.count == 0) {
|
||||
return [desc stringByAppendingString:@"[]"];
|
||||
} else {
|
||||
[desc appendFormat:@"[\n"];
|
||||
for (NSUInteger i = 0, max = array.count; i < max; i++) {
|
||||
NSObject *obj = array[i];
|
||||
[desc appendString:@" "];
|
||||
[desc appendString:ModelDescriptionAddIndent(ModelDescription(obj).mutableCopy, 1)];
|
||||
[desc appendString:(i + 1 == max) ? @"\n" : @";\n"];
|
||||
}
|
||||
[desc appendString:@"]"];
|
||||
return desc;
|
||||
}
|
||||
}
|
||||
case YYEncodingTypeNSDictionary: case YYEncodingTypeNSMutableDictionary: {
|
||||
NSDictionary *dic = (id)model;
|
||||
NSMutableString *desc = [NSMutableString new];
|
||||
if (dic.count == 0) {
|
||||
return [desc stringByAppendingString:@"{}"];
|
||||
} else {
|
||||
NSArray *keys = dic.allKeys;
|
||||
|
||||
[desc appendFormat:@"{\n"];
|
||||
for (NSUInteger i = 0, max = keys.count; i < max; i++) {
|
||||
NSString *key = keys[i];
|
||||
NSObject *value = dic[key];
|
||||
[desc appendString:@" "];
|
||||
[desc appendFormat:@"%@ = %@",key, ModelDescriptionAddIndent(ModelDescription(value).mutableCopy, 1)];
|
||||
[desc appendString:(i + 1 == max) ? @"\n" : @";\n"];
|
||||
}
|
||||
[desc appendString:@"}"];
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
|
||||
default: {
|
||||
NSMutableString *desc = [NSMutableString new];
|
||||
[desc appendFormat:@"<%@: %p>", model.class, model];
|
||||
if (modelMeta->_allPropertyMetas.count == 0) return desc;
|
||||
|
||||
// sort property names
|
||||
NSArray *properties = [modelMeta->_allPropertyMetas
|
||||
sortedArrayUsingComparator:^NSComparisonResult(_YYModelPropertyMeta *p1, _YYModelPropertyMeta *p2) {
|
||||
return [p1->_name compare:p2->_name];
|
||||
}];
|
||||
|
||||
[desc appendFormat:@" {\n"];
|
||||
for (NSUInteger i = 0, max = properties.count; i < max; i++) {
|
||||
_YYModelPropertyMeta *property = properties[i];
|
||||
NSString *propertyDesc;
|
||||
if (property->_isCNumber) {
|
||||
NSNumber *num = ModelCreateNumberFromProperty(model, property);
|
||||
propertyDesc = num.stringValue;
|
||||
} else {
|
||||
switch (property->_type & YYEncodingTypeMask) {
|
||||
case YYEncodingTypeObject: {
|
||||
id v = ((id (*)(id, SEL))(void *) objc_msgSend)((id)model, property->_getter);
|
||||
propertyDesc = ModelDescription(v);
|
||||
if (!propertyDesc) propertyDesc = @"<nil>";
|
||||
} break;
|
||||
case YYEncodingTypeClass: {
|
||||
id v = ((id (*)(id, SEL))(void *) objc_msgSend)((id)model, property->_getter);
|
||||
propertyDesc = ((NSObject *)v).description;
|
||||
if (!propertyDesc) propertyDesc = @"<nil>";
|
||||
} break;
|
||||
case YYEncodingTypeSEL: {
|
||||
SEL sel = ((SEL (*)(id, SEL))(void *) objc_msgSend)((id)model, property->_getter);
|
||||
if (sel) propertyDesc = NSStringFromSelector(sel);
|
||||
else propertyDesc = @"<NULL>";
|
||||
} break;
|
||||
case YYEncodingTypeBlock: {
|
||||
id block = ((id (*)(id, SEL))(void *) objc_msgSend)((id)model, property->_getter);
|
||||
propertyDesc = block ? ((NSObject *)block).description : @"<nil>";
|
||||
} break;
|
||||
case YYEncodingTypeCArray: case YYEncodingTypeCString: case YYEncodingTypePointer: {
|
||||
void *pointer = ((void* (*)(id, SEL))(void *) objc_msgSend)((id)model, property->_getter);
|
||||
propertyDesc = [NSString stringWithFormat:@"%p",pointer];
|
||||
} break;
|
||||
case YYEncodingTypeStruct: case YYEncodingTypeUnion: {
|
||||
NSValue *value = [model valueForKey:property->_name];
|
||||
propertyDesc = value ? value.description : @"{unknown}";
|
||||
} break;
|
||||
default: propertyDesc = @"<unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
propertyDesc = ModelDescriptionAddIndent(propertyDesc.mutableCopy, 1);
|
||||
[desc appendFormat:@" %@ = %@",property->_name, propertyDesc];
|
||||
[desc appendString:(i + 1 == max) ? @"\n" : @";\n"];
|
||||
}
|
||||
[desc appendFormat:@"}"];
|
||||
return desc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@implementation NSObject (YYModel)
|
||||
|
||||
+ (NSDictionary *)_yy_dictionaryWithJSON:(id)json {
|
||||
if (!json || json == (id)kCFNull) return nil;
|
||||
NSDictionary *dic = nil;
|
||||
NSData *jsonData = nil;
|
||||
if ([json isKindOfClass:[NSDictionary class]]) {
|
||||
dic = json;
|
||||
} else if ([json isKindOfClass:[NSString class]]) {
|
||||
jsonData = [(NSString *)json dataUsingEncoding : NSUTF8StringEncoding];
|
||||
} else if ([json isKindOfClass:[NSData class]]) {
|
||||
jsonData = json;
|
||||
}
|
||||
if (jsonData) {
|
||||
dic = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:NULL];
|
||||
if (![dic isKindOfClass:[NSDictionary class]]) dic = nil;
|
||||
}
|
||||
return dic;
|
||||
}
|
||||
|
||||
+ (instancetype)modelWithJSON:(id)json {
|
||||
NSDictionary *dic = [self _yy_dictionaryWithJSON:json];
|
||||
return [self modelWithDictionary:dic];
|
||||
}
|
||||
|
||||
+ (instancetype)modelWithDictionary:(NSDictionary *)dictionary {
|
||||
if (!dictionary || dictionary == (id)kCFNull) return nil;
|
||||
if (![dictionary isKindOfClass:[NSDictionary class]]) return nil;
|
||||
|
||||
Class cls = [self class];
|
||||
_YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:cls];
|
||||
if (modelMeta->_hasCustomClassFromDictionary) {
|
||||
cls = [cls modelCustomClassForDictionary:dictionary] ?: cls;
|
||||
}
|
||||
|
||||
NSObject *one = [cls new];
|
||||
if ([one modelSetWithDictionary:dictionary]) return one;
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (BOOL)modelSetWithJSON:(id)json {
|
||||
NSDictionary *dic = [NSObject _yy_dictionaryWithJSON:json];
|
||||
return [self modelSetWithDictionary:dic];
|
||||
}
|
||||
|
||||
- (BOOL)modelSetWithDictionary:(NSDictionary *)dic {
|
||||
if (!dic || dic == (id)kCFNull) return NO;
|
||||
if (![dic isKindOfClass:[NSDictionary class]]) return NO;
|
||||
|
||||
_YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:object_getClass(self)];
|
||||
if (modelMeta->_keyMappedCount == 0) return NO;
|
||||
|
||||
if (modelMeta->_hasCustomWillTransformFromDictionary) {
|
||||
dic = [((id<YYModel>)self) modelCustomWillTransformFromDictionary:dic];
|
||||
if (![dic isKindOfClass:[NSDictionary class]]) return NO;
|
||||
}
|
||||
|
||||
ModelSetContext context = {0};
|
||||
context.modelMeta = (__bridge void *)(modelMeta);
|
||||
context.model = (__bridge void *)(self);
|
||||
context.dictionary = (__bridge void *)(dic);
|
||||
|
||||
if (modelMeta->_keyMappedCount >= CFDictionaryGetCount((CFDictionaryRef)dic)) {
|
||||
CFDictionaryApplyFunction((CFDictionaryRef)dic, ModelSetWithDictionaryFunction, &context);
|
||||
if (modelMeta->_keyPathPropertyMetas) {
|
||||
CFArrayApplyFunction((CFArrayRef)modelMeta->_keyPathPropertyMetas,
|
||||
CFRangeMake(0, CFArrayGetCount((CFArrayRef)modelMeta->_keyPathPropertyMetas)),
|
||||
ModelSetWithPropertyMetaArrayFunction,
|
||||
&context);
|
||||
}
|
||||
if (modelMeta->_multiKeysPropertyMetas) {
|
||||
CFArrayApplyFunction((CFArrayRef)modelMeta->_multiKeysPropertyMetas,
|
||||
CFRangeMake(0, CFArrayGetCount((CFArrayRef)modelMeta->_multiKeysPropertyMetas)),
|
||||
ModelSetWithPropertyMetaArrayFunction,
|
||||
&context);
|
||||
}
|
||||
} else {
|
||||
CFArrayApplyFunction((CFArrayRef)modelMeta->_allPropertyMetas,
|
||||
CFRangeMake(0, modelMeta->_keyMappedCount),
|
||||
ModelSetWithPropertyMetaArrayFunction,
|
||||
&context);
|
||||
}
|
||||
|
||||
if (modelMeta->_hasCustomTransformFromDictionary) {
|
||||
return [((id<YYModel>)self) modelCustomTransformFromDictionary:dic];
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (id)modelToJSONObject {
|
||||
/*
|
||||
Apple said:
|
||||
The top level object is an NSArray or NSDictionary.
|
||||
All objects are instances of NSString, NSNumber, NSArray, NSDictionary, or NSNull.
|
||||
All dictionary keys are instances of NSString.
|
||||
Numbers are not NaN or infinity.
|
||||
*/
|
||||
id jsonObject = ModelToJSONObjectRecursive(self);
|
||||
if ([jsonObject isKindOfClass:[NSArray class]]) return jsonObject;
|
||||
if ([jsonObject isKindOfClass:[NSDictionary class]]) return jsonObject;
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSData *)modelToJSONData {
|
||||
id jsonObject = [self modelToJSONObject];
|
||||
if (!jsonObject) return nil;
|
||||
return [NSJSONSerialization dataWithJSONObject:jsonObject options:0 error:NULL];
|
||||
}
|
||||
|
||||
- (NSString *)modelToJSONString {
|
||||
NSData *jsonData = [self modelToJSONData];
|
||||
if (jsonData.length == 0) return nil;
|
||||
return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
- (id)modelCopy{
|
||||
if (self == (id)kCFNull) return self;
|
||||
_YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:self.class];
|
||||
if (modelMeta->_nsType) return [self copy];
|
||||
|
||||
NSObject *one = [self.class new];
|
||||
for (_YYModelPropertyMeta *propertyMeta in modelMeta->_allPropertyMetas) {
|
||||
if (!propertyMeta->_getter || !propertyMeta->_setter) continue;
|
||||
|
||||
if (propertyMeta->_isCNumber) {
|
||||
switch (propertyMeta->_type & YYEncodingTypeMask) {
|
||||
case YYEncodingTypeBool: {
|
||||
bool num = ((bool (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
|
||||
((void (*)(id, SEL, bool))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
|
||||
} break;
|
||||
case YYEncodingTypeInt8:
|
||||
case YYEncodingTypeUInt8: {
|
||||
uint8_t num = ((bool (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
|
||||
((void (*)(id, SEL, uint8_t))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
|
||||
} break;
|
||||
case YYEncodingTypeInt16:
|
||||
case YYEncodingTypeUInt16: {
|
||||
uint16_t num = ((uint16_t (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
|
||||
((void (*)(id, SEL, uint16_t))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
|
||||
} break;
|
||||
case YYEncodingTypeInt32:
|
||||
case YYEncodingTypeUInt32: {
|
||||
uint32_t num = ((uint32_t (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
|
||||
((void (*)(id, SEL, uint32_t))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
|
||||
} break;
|
||||
case YYEncodingTypeInt64:
|
||||
case YYEncodingTypeUInt64: {
|
||||
uint64_t num = ((uint64_t (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
|
||||
((void (*)(id, SEL, uint64_t))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
|
||||
} break;
|
||||
case YYEncodingTypeFloat: {
|
||||
float num = ((float (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
|
||||
((void (*)(id, SEL, float))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
|
||||
} break;
|
||||
case YYEncodingTypeDouble: {
|
||||
double num = ((double (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
|
||||
((void (*)(id, SEL, double))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
|
||||
} break;
|
||||
case YYEncodingTypeLongDouble: {
|
||||
long double num = ((long double (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
|
||||
((void (*)(id, SEL, long double))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
|
||||
} // break; commented for code coverage in next line
|
||||
default: break;
|
||||
}
|
||||
} else {
|
||||
switch (propertyMeta->_type & YYEncodingTypeMask) {
|
||||
case YYEncodingTypeObject:
|
||||
case YYEncodingTypeClass:
|
||||
case YYEncodingTypeBlock: {
|
||||
id value = ((id (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)one, propertyMeta->_setter, value);
|
||||
} break;
|
||||
case YYEncodingTypeSEL:
|
||||
case YYEncodingTypePointer:
|
||||
case YYEncodingTypeCString: {
|
||||
size_t value = ((size_t (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
|
||||
((void (*)(id, SEL, size_t))(void *) objc_msgSend)((id)one, propertyMeta->_setter, value);
|
||||
} break;
|
||||
case YYEncodingTypeStruct:
|
||||
case YYEncodingTypeUnion: {
|
||||
@try {
|
||||
NSValue *value = [self valueForKey:NSStringFromSelector(propertyMeta->_getter)];
|
||||
if (value) {
|
||||
[one setValue:value forKey:propertyMeta->_name];
|
||||
}
|
||||
} @catch (NSException *exception) {}
|
||||
} // break; commented for code coverage in next line
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return one;
|
||||
}
|
||||
|
||||
- (void)modelEncodeWithCoder:(NSCoder *)aCoder {
|
||||
if (!aCoder) return;
|
||||
if (self == (id)kCFNull) {
|
||||
[((id<NSCoding>)self)encodeWithCoder:aCoder];
|
||||
return;
|
||||
}
|
||||
|
||||
_YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:self.class];
|
||||
if (modelMeta->_nsType) {
|
||||
[((id<NSCoding>)self)encodeWithCoder:aCoder];
|
||||
return;
|
||||
}
|
||||
|
||||
for (_YYModelPropertyMeta *propertyMeta in modelMeta->_allPropertyMetas) {
|
||||
if (!propertyMeta->_getter) return;
|
||||
|
||||
if (propertyMeta->_isCNumber) {
|
||||
NSNumber *value = ModelCreateNumberFromProperty(self, propertyMeta);
|
||||
if (value) [aCoder encodeObject:value forKey:propertyMeta->_name];
|
||||
} else {
|
||||
switch (propertyMeta->_type & YYEncodingTypeMask) {
|
||||
case YYEncodingTypeObject: {
|
||||
id value = ((id (*)(id, SEL))(void *)objc_msgSend)((id)self, propertyMeta->_getter);
|
||||
if (value && (propertyMeta->_nsType || [value respondsToSelector:@selector(encodeWithCoder:)])) {
|
||||
if ([value isKindOfClass:[NSValue class]]) {
|
||||
if ([value isKindOfClass:[NSNumber class]]) {
|
||||
[aCoder encodeObject:value forKey:propertyMeta->_name];
|
||||
}
|
||||
} else {
|
||||
[aCoder encodeObject:value forKey:propertyMeta->_name];
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case YYEncodingTypeSEL: {
|
||||
SEL value = ((SEL (*)(id, SEL))(void *)objc_msgSend)((id)self, propertyMeta->_getter);
|
||||
if (value) {
|
||||
NSString *str = NSStringFromSelector(value);
|
||||
[aCoder encodeObject:str forKey:propertyMeta->_name];
|
||||
}
|
||||
} break;
|
||||
case YYEncodingTypeStruct:
|
||||
case YYEncodingTypeUnion: {
|
||||
if (propertyMeta->_isKVCCompatible && propertyMeta->_isStructAvailableForKeyedArchiver) {
|
||||
@try {
|
||||
NSValue *value = [self valueForKey:NSStringFromSelector(propertyMeta->_getter)];
|
||||
[aCoder encodeObject:value forKey:propertyMeta->_name];
|
||||
} @catch (NSException *exception) {}
|
||||
}
|
||||
} break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (id)modelInitWithCoder:(NSCoder *)aDecoder {
|
||||
if (!aDecoder) return self;
|
||||
if (self == (id)kCFNull) return self;
|
||||
_YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:self.class];
|
||||
if (modelMeta->_nsType) return self;
|
||||
|
||||
for (_YYModelPropertyMeta *propertyMeta in modelMeta->_allPropertyMetas) {
|
||||
if (!propertyMeta->_setter) continue;
|
||||
|
||||
if (propertyMeta->_isCNumber) {
|
||||
NSNumber *value = [aDecoder decodeObjectForKey:propertyMeta->_name];
|
||||
if ([value isKindOfClass:[NSNumber class]]) {
|
||||
ModelSetNumberToProperty(self, value, propertyMeta);
|
||||
[value class];
|
||||
}
|
||||
} else {
|
||||
YYEncodingType type = propertyMeta->_type & YYEncodingTypeMask;
|
||||
switch (type) {
|
||||
case YYEncodingTypeObject: {
|
||||
id value = [aDecoder decodeObjectForKey:propertyMeta->_name];
|
||||
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)self, propertyMeta->_setter, value);
|
||||
} break;
|
||||
case YYEncodingTypeSEL: {
|
||||
NSString *str = [aDecoder decodeObjectForKey:propertyMeta->_name];
|
||||
if ([str isKindOfClass:[NSString class]]) {
|
||||
SEL sel = NSSelectorFromString(str);
|
||||
((void (*)(id, SEL, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_setter, sel);
|
||||
}
|
||||
} break;
|
||||
case YYEncodingTypeStruct:
|
||||
case YYEncodingTypeUnion: {
|
||||
if (propertyMeta->_isKVCCompatible) {
|
||||
@try {
|
||||
NSValue *value = [aDecoder decodeObjectForKey:propertyMeta->_name];
|
||||
if (value) [self setValue:value forKey:propertyMeta->_name];
|
||||
} @catch (NSException *exception) {}
|
||||
}
|
||||
} break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSUInteger)modelHash {
|
||||
if (self == (id)kCFNull) return [self hash];
|
||||
_YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:self.class];
|
||||
if (modelMeta->_nsType) return [self hash];
|
||||
|
||||
NSUInteger value = 0;
|
||||
NSUInteger count = 0;
|
||||
for (_YYModelPropertyMeta *propertyMeta in modelMeta->_allPropertyMetas) {
|
||||
if (!propertyMeta->_isKVCCompatible) continue;
|
||||
value ^= [[self valueForKey:NSStringFromSelector(propertyMeta->_getter)] hash];
|
||||
count++;
|
||||
}
|
||||
if (count == 0) value = (long)((__bridge void *)self);
|
||||
return value;
|
||||
}
|
||||
|
||||
- (BOOL)modelIsEqual:(id)model {
|
||||
if (self == model) return YES;
|
||||
if (![model isMemberOfClass:self.class]) return NO;
|
||||
_YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:self.class];
|
||||
if (modelMeta->_nsType) return [self isEqual:model];
|
||||
if ([self hash] != [model hash]) return NO;
|
||||
|
||||
for (_YYModelPropertyMeta *propertyMeta in modelMeta->_allPropertyMetas) {
|
||||
if (!propertyMeta->_isKVCCompatible) continue;
|
||||
id this = [self valueForKey:NSStringFromSelector(propertyMeta->_getter)];
|
||||
id that = [model valueForKey:NSStringFromSelector(propertyMeta->_getter)];
|
||||
if (this == that) continue;
|
||||
if (this == nil || that == nil) return NO;
|
||||
if (![this isEqual:that]) return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSString *)modelDescription {
|
||||
return ModelDescription(self);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@implementation NSArray (YYModel)
|
||||
|
||||
+ (NSArray *)modelArrayWithClass:(Class)cls json:(id)json {
|
||||
if (!json) return nil;
|
||||
NSArray *arr = nil;
|
||||
NSData *jsonData = nil;
|
||||
if ([json isKindOfClass:[NSArray class]]) {
|
||||
arr = json;
|
||||
} else if ([json isKindOfClass:[NSString class]]) {
|
||||
jsonData = [(NSString *)json dataUsingEncoding : NSUTF8StringEncoding];
|
||||
} else if ([json isKindOfClass:[NSData class]]) {
|
||||
jsonData = json;
|
||||
}
|
||||
if (jsonData) {
|
||||
arr = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:NULL];
|
||||
if (![arr isKindOfClass:[NSArray class]]) arr = nil;
|
||||
}
|
||||
return [self modelArrayWithClass:cls array:arr];
|
||||
}
|
||||
|
||||
+ (NSArray *)modelArrayWithClass:(Class)cls array:(NSArray *)arr {
|
||||
if (!cls || !arr) return nil;
|
||||
NSMutableArray *result = [NSMutableArray new];
|
||||
for (NSDictionary *dic in arr) {
|
||||
if (![dic isKindOfClass:[NSDictionary class]]) continue;
|
||||
NSObject *obj = [cls modelWithDictionary:dic];
|
||||
if (obj) [result addObject:obj];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation NSDictionary (YYModel)
|
||||
|
||||
+ (NSDictionary *)modelDictionaryWithClass:(Class)cls json:(id)json {
|
||||
if (!json) return nil;
|
||||
NSDictionary *dic = nil;
|
||||
NSData *jsonData = nil;
|
||||
if ([json isKindOfClass:[NSDictionary class]]) {
|
||||
dic = json;
|
||||
} else if ([json isKindOfClass:[NSString class]]) {
|
||||
jsonData = [(NSString *)json dataUsingEncoding : NSUTF8StringEncoding];
|
||||
} else if ([json isKindOfClass:[NSData class]]) {
|
||||
jsonData = json;
|
||||
}
|
||||
if (jsonData) {
|
||||
dic = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:NULL];
|
||||
if (![dic isKindOfClass:[NSDictionary class]]) dic = nil;
|
||||
}
|
||||
return [self modelDictionaryWithClass:cls dictionary:dic];
|
||||
}
|
||||
|
||||
+ (NSDictionary *)modelDictionaryWithClass:(Class)cls dictionary:(NSDictionary *)dic {
|
||||
if (!cls || !dic) return nil;
|
||||
NSMutableDictionary *result = [NSMutableDictionary new];
|
||||
for (NSString *key in dic.allKeys) {
|
||||
if (![key isKindOfClass:[NSString class]]) continue;
|
||||
NSObject *obj = [cls modelWithDictionary:dic[key]];
|
||||
if (obj) result[key] = obj;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@end
|
||||
200
ShenQi/YYModel/YYClassInfo.h
Normal file
@@ -0,0 +1,200 @@
|
||||
//
|
||||
// YYClassInfo.h
|
||||
// YYKit <https://github.com/ibireme/YYKit>
|
||||
//
|
||||
// Created by ibireme on 15/5/9.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <objc/runtime.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Type encoding's type.
|
||||
*/
|
||||
typedef NS_OPTIONS(NSUInteger, YYEncodingType) {
|
||||
YYEncodingTypeMask = 0xFF, ///< mask of type value
|
||||
YYEncodingTypeUnknown = 0, ///< unknown
|
||||
YYEncodingTypeVoid = 1, ///< void
|
||||
YYEncodingTypeBool = 2, ///< bool
|
||||
YYEncodingTypeInt8 = 3, ///< char / BOOL
|
||||
YYEncodingTypeUInt8 = 4, ///< unsigned char
|
||||
YYEncodingTypeInt16 = 5, ///< short
|
||||
YYEncodingTypeUInt16 = 6, ///< unsigned short
|
||||
YYEncodingTypeInt32 = 7, ///< int
|
||||
YYEncodingTypeUInt32 = 8, ///< unsigned int
|
||||
YYEncodingTypeInt64 = 9, ///< long long
|
||||
YYEncodingTypeUInt64 = 10, ///< unsigned long long
|
||||
YYEncodingTypeFloat = 11, ///< float
|
||||
YYEncodingTypeDouble = 12, ///< double
|
||||
YYEncodingTypeLongDouble = 13, ///< long double
|
||||
YYEncodingTypeObject = 14, ///< id
|
||||
YYEncodingTypeClass = 15, ///< Class
|
||||
YYEncodingTypeSEL = 16, ///< SEL
|
||||
YYEncodingTypeBlock = 17, ///< block
|
||||
YYEncodingTypePointer = 18, ///< void*
|
||||
YYEncodingTypeStruct = 19, ///< struct
|
||||
YYEncodingTypeUnion = 20, ///< union
|
||||
YYEncodingTypeCString = 21, ///< char*
|
||||
YYEncodingTypeCArray = 22, ///< char[10] (for example)
|
||||
|
||||
YYEncodingTypeQualifierMask = 0xFF00, ///< mask of qualifier
|
||||
YYEncodingTypeQualifierConst = 1 << 8, ///< const
|
||||
YYEncodingTypeQualifierIn = 1 << 9, ///< in
|
||||
YYEncodingTypeQualifierInout = 1 << 10, ///< inout
|
||||
YYEncodingTypeQualifierOut = 1 << 11, ///< out
|
||||
YYEncodingTypeQualifierBycopy = 1 << 12, ///< bycopy
|
||||
YYEncodingTypeQualifierByref = 1 << 13, ///< byref
|
||||
YYEncodingTypeQualifierOneway = 1 << 14, ///< oneway
|
||||
|
||||
YYEncodingTypePropertyMask = 0xFF0000, ///< mask of property
|
||||
YYEncodingTypePropertyReadonly = 1 << 16, ///< readonly
|
||||
YYEncodingTypePropertyCopy = 1 << 17, ///< copy
|
||||
YYEncodingTypePropertyRetain = 1 << 18, ///< retain
|
||||
YYEncodingTypePropertyNonatomic = 1 << 19, ///< nonatomic
|
||||
YYEncodingTypePropertyWeak = 1 << 20, ///< weak
|
||||
YYEncodingTypePropertyCustomGetter = 1 << 21, ///< getter=
|
||||
YYEncodingTypePropertyCustomSetter = 1 << 22, ///< setter=
|
||||
YYEncodingTypePropertyDynamic = 1 << 23, ///< @dynamic
|
||||
};
|
||||
|
||||
/**
|
||||
Get the type from a Type-Encoding string.
|
||||
|
||||
@discussion See also:
|
||||
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html
|
||||
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html
|
||||
|
||||
@param typeEncoding A Type-Encoding string.
|
||||
@return The encoding type.
|
||||
*/
|
||||
YYEncodingType YYEncodingGetType(const char *typeEncoding);
|
||||
|
||||
|
||||
/**
|
||||
Instance variable information.
|
||||
*/
|
||||
@interface YYClassIvarInfo : NSObject
|
||||
@property (nonatomic, assign, readonly) Ivar ivar; ///< ivar opaque struct
|
||||
@property (nonatomic, strong, readonly) NSString *name; ///< Ivar's name
|
||||
@property (nonatomic, assign, readonly) ptrdiff_t offset; ///< Ivar's offset
|
||||
@property (nonatomic, strong, readonly) NSString *typeEncoding; ///< Ivar's type encoding
|
||||
@property (nonatomic, assign, readonly) YYEncodingType type; ///< Ivar's type
|
||||
|
||||
/**
|
||||
Creates and returns an ivar info object.
|
||||
|
||||
@param ivar ivar opaque struct
|
||||
@return A new object, or nil if an error occurs.
|
||||
*/
|
||||
- (instancetype)initWithIvar:(Ivar)ivar;
|
||||
@end
|
||||
|
||||
|
||||
/**
|
||||
Method information.
|
||||
*/
|
||||
@interface YYClassMethodInfo : NSObject
|
||||
@property (nonatomic, assign, readonly) Method method; ///< method opaque struct
|
||||
@property (nonatomic, strong, readonly) NSString *name; ///< method name
|
||||
@property (nonatomic, assign, readonly) SEL sel; ///< method's selector
|
||||
@property (nonatomic, assign, readonly) IMP imp; ///< method's implementation
|
||||
@property (nonatomic, strong, readonly) NSString *typeEncoding; ///< method's parameter and return types
|
||||
@property (nonatomic, strong, readonly) NSString *returnTypeEncoding; ///< return value's type
|
||||
@property (nullable, nonatomic, strong, readonly) NSArray<NSString *> *argumentTypeEncodings; ///< array of arguments' type
|
||||
|
||||
/**
|
||||
Creates and returns a method info object.
|
||||
|
||||
@param method method opaque struct
|
||||
@return A new object, or nil if an error occurs.
|
||||
*/
|
||||
- (instancetype)initWithMethod:(Method)method;
|
||||
@end
|
||||
|
||||
|
||||
/**
|
||||
Property information.
|
||||
*/
|
||||
@interface YYClassPropertyInfo : NSObject
|
||||
@property (nonatomic, assign, readonly) objc_property_t property; ///< property's opaque struct
|
||||
@property (nonatomic, strong, readonly) NSString *name; ///< property's name
|
||||
@property (nonatomic, assign, readonly) YYEncodingType type; ///< property's type
|
||||
@property (nonatomic, strong, readonly) NSString *typeEncoding; ///< property's encoding value
|
||||
@property (nonatomic, strong, readonly) NSString *ivarName; ///< property's ivar name
|
||||
@property (nullable, nonatomic, assign, readonly) Class cls; ///< may be nil
|
||||
@property (nullable, nonatomic, strong, readonly) NSArray<NSString *> *protocols; ///< may nil
|
||||
@property (nonatomic, assign, readonly) SEL getter; ///< getter (nonnull)
|
||||
@property (nonatomic, assign, readonly) SEL setter; ///< setter (nonnull)
|
||||
|
||||
/**
|
||||
Creates and returns a property info object.
|
||||
|
||||
@param property property opaque struct
|
||||
@return A new object, or nil if an error occurs.
|
||||
*/
|
||||
- (instancetype)initWithProperty:(objc_property_t)property;
|
||||
@end
|
||||
|
||||
|
||||
/**
|
||||
Class information for a class.
|
||||
*/
|
||||
@interface YYClassInfo : NSObject
|
||||
@property (nonatomic, assign, readonly) Class cls; ///< class object
|
||||
@property (nullable, nonatomic, assign, readonly) Class superCls; ///< super class object
|
||||
@property (nullable, nonatomic, assign, readonly) Class metaCls; ///< class's meta class object
|
||||
@property (nonatomic, readonly) BOOL isMeta; ///< whether this class is meta class
|
||||
@property (nonatomic, strong, readonly) NSString *name; ///< class name
|
||||
@property (nullable, nonatomic, strong, readonly) YYClassInfo *superClassInfo; ///< super class's class info
|
||||
@property (nullable, nonatomic, strong, readonly) NSDictionary<NSString *, YYClassIvarInfo *> *ivarInfos; ///< ivars
|
||||
@property (nullable, nonatomic, strong, readonly) NSDictionary<NSString *, YYClassMethodInfo *> *methodInfos; ///< methods
|
||||
@property (nullable, nonatomic, strong, readonly) NSDictionary<NSString *, YYClassPropertyInfo *> *propertyInfos; ///< properties
|
||||
|
||||
/**
|
||||
If the class is changed (for example: you add a method to this class with
|
||||
'class_addMethod()'), you should call this method to refresh the class info cache.
|
||||
|
||||
After called this method, `needUpdate` will returns `YES`, and you should call
|
||||
'classInfoWithClass' or 'classInfoWithClassName' to get the updated class info.
|
||||
*/
|
||||
- (void)setNeedUpdate;
|
||||
|
||||
/**
|
||||
If this method returns `YES`, you should stop using this instance and call
|
||||
`classInfoWithClass` or `classInfoWithClassName` to get the updated class info.
|
||||
|
||||
@return Whether this class info need update.
|
||||
*/
|
||||
- (BOOL)needUpdate;
|
||||
|
||||
/**
|
||||
Get the class info of a specified Class.
|
||||
|
||||
@discussion This method will cache the class info and super-class info
|
||||
at the first access to the Class. This method is thread-safe.
|
||||
|
||||
@param cls A class.
|
||||
@return A class info, or nil if an error occurs.
|
||||
*/
|
||||
+ (nullable instancetype)classInfoWithClass:(Class)cls;
|
||||
|
||||
/**
|
||||
Get the class info of a specified Class.
|
||||
|
||||
@discussion This method will cache the class info and super-class info
|
||||
at the first access to the Class. This method is thread-safe.
|
||||
|
||||
@param className A class name.
|
||||
@return A class info, or nil if an error occurs.
|
||||
*/
|
||||
+ (nullable instancetype)classInfoWithClassName:(NSString *)className;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
362
ShenQi/YYModel/YYClassInfo.m
Normal file
@@ -0,0 +1,362 @@
|
||||
//
|
||||
// YYClassInfo.m
|
||||
// YYKit <https://github.com/ibireme/YYKit>
|
||||
//
|
||||
// Created by ibireme on 15/5/9.
|
||||
// Copyright (c) 2015 ibireme.
|
||||
//
|
||||
// This source code is licensed under the MIT-style license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
//
|
||||
|
||||
#import "YYClassInfo.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
YYEncodingType YYEncodingGetType(const char *typeEncoding) {
|
||||
char *type = (char *)typeEncoding;
|
||||
if (!type) return YYEncodingTypeUnknown;
|
||||
size_t len = strlen(type);
|
||||
if (len == 0) return YYEncodingTypeUnknown;
|
||||
|
||||
YYEncodingType qualifier = 0;
|
||||
bool prefix = true;
|
||||
while (prefix) {
|
||||
switch (*type) {
|
||||
case 'r': {
|
||||
qualifier |= YYEncodingTypeQualifierConst;
|
||||
type++;
|
||||
} break;
|
||||
case 'n': {
|
||||
qualifier |= YYEncodingTypeQualifierIn;
|
||||
type++;
|
||||
} break;
|
||||
case 'N': {
|
||||
qualifier |= YYEncodingTypeQualifierInout;
|
||||
type++;
|
||||
} break;
|
||||
case 'o': {
|
||||
qualifier |= YYEncodingTypeQualifierOut;
|
||||
type++;
|
||||
} break;
|
||||
case 'O': {
|
||||
qualifier |= YYEncodingTypeQualifierBycopy;
|
||||
type++;
|
||||
} break;
|
||||
case 'R': {
|
||||
qualifier |= YYEncodingTypeQualifierByref;
|
||||
type++;
|
||||
} break;
|
||||
case 'V': {
|
||||
qualifier |= YYEncodingTypeQualifierOneway;
|
||||
type++;
|
||||
} break;
|
||||
default: { prefix = false; } break;
|
||||
}
|
||||
}
|
||||
|
||||
len = strlen(type);
|
||||
if (len == 0) return YYEncodingTypeUnknown | qualifier;
|
||||
|
||||
switch (*type) {
|
||||
case 'v': return YYEncodingTypeVoid | qualifier;
|
||||
case 'B': return YYEncodingTypeBool | qualifier;
|
||||
case 'c': return YYEncodingTypeInt8 | qualifier;
|
||||
case 'C': return YYEncodingTypeUInt8 | qualifier;
|
||||
case 's': return YYEncodingTypeInt16 | qualifier;
|
||||
case 'S': return YYEncodingTypeUInt16 | qualifier;
|
||||
case 'i': return YYEncodingTypeInt32 | qualifier;
|
||||
case 'I': return YYEncodingTypeUInt32 | qualifier;
|
||||
case 'l': return YYEncodingTypeInt32 | qualifier;
|
||||
case 'L': return YYEncodingTypeUInt32 | qualifier;
|
||||
case 'q': return YYEncodingTypeInt64 | qualifier;
|
||||
case 'Q': return YYEncodingTypeUInt64 | qualifier;
|
||||
case 'f': return YYEncodingTypeFloat | qualifier;
|
||||
case 'd': return YYEncodingTypeDouble | qualifier;
|
||||
case 'D': return YYEncodingTypeLongDouble | qualifier;
|
||||
case '#': return YYEncodingTypeClass | qualifier;
|
||||
case ':': return YYEncodingTypeSEL | qualifier;
|
||||
case '*': return YYEncodingTypeCString | qualifier;
|
||||
case '^': return YYEncodingTypePointer | qualifier;
|
||||
case '[': return YYEncodingTypeCArray | qualifier;
|
||||
case '(': return YYEncodingTypeUnion | qualifier;
|
||||
case '{': return YYEncodingTypeStruct | qualifier;
|
||||
case '@': {
|
||||
if (len == 2 && *(type + 1) == '?')
|
||||
return YYEncodingTypeBlock | qualifier;
|
||||
else
|
||||
return YYEncodingTypeObject | qualifier;
|
||||
}
|
||||
default: return YYEncodingTypeUnknown | qualifier;
|
||||
}
|
||||
}
|
||||
|
||||
@implementation YYClassIvarInfo
|
||||
|
||||
- (instancetype)initWithIvar:(Ivar)ivar {
|
||||
if (!ivar) return nil;
|
||||
self = [super init];
|
||||
_ivar = ivar;
|
||||
const char *name = ivar_getName(ivar);
|
||||
if (name) {
|
||||
_name = [NSString stringWithUTF8String:name];
|
||||
}
|
||||
_offset = ivar_getOffset(ivar);
|
||||
const char *typeEncoding = ivar_getTypeEncoding(ivar);
|
||||
if (typeEncoding) {
|
||||
_typeEncoding = [NSString stringWithUTF8String:typeEncoding];
|
||||
_type = YYEncodingGetType(typeEncoding);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation YYClassMethodInfo
|
||||
|
||||
- (instancetype)initWithMethod:(Method)method {
|
||||
if (!method) return nil;
|
||||
self = [super init];
|
||||
_method = method;
|
||||
_sel = method_getName(method);
|
||||
_imp = method_getImplementation(method);
|
||||
const char *name = sel_getName(_sel);
|
||||
if (name) {
|
||||
_name = [NSString stringWithUTF8String:name];
|
||||
}
|
||||
const char *typeEncoding = method_getTypeEncoding(method);
|
||||
if (typeEncoding) {
|
||||
_typeEncoding = [NSString stringWithUTF8String:typeEncoding];
|
||||
}
|
||||
char *returnType = method_copyReturnType(method);
|
||||
if (returnType) {
|
||||
_returnTypeEncoding = [NSString stringWithUTF8String:returnType];
|
||||
free(returnType);
|
||||
}
|
||||
unsigned int argumentCount = method_getNumberOfArguments(method);
|
||||
if (argumentCount > 0) {
|
||||
NSMutableArray *argumentTypes = [NSMutableArray new];
|
||||
for (unsigned int i = 0; i < argumentCount; i++) {
|
||||
char *argumentType = method_copyArgumentType(method, i);
|
||||
NSString *type = argumentType ? [NSString stringWithUTF8String:argumentType] : nil;
|
||||
[argumentTypes addObject:type ? type : @""];
|
||||
if (argumentType) free(argumentType);
|
||||
}
|
||||
_argumentTypeEncodings = argumentTypes;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation YYClassPropertyInfo
|
||||
|
||||
- (instancetype)initWithProperty:(objc_property_t)property {
|
||||
if (!property) return nil;
|
||||
self = [super init];
|
||||
_property = property;
|
||||
const char *name = property_getName(property);
|
||||
if (name) {
|
||||
_name = [NSString stringWithUTF8String:name];
|
||||
}
|
||||
|
||||
YYEncodingType type = 0;
|
||||
unsigned int attrCount;
|
||||
objc_property_attribute_t *attrs = property_copyAttributeList(property, &attrCount);
|
||||
for (unsigned int i = 0; i < attrCount; i++) {
|
||||
switch (attrs[i].name[0]) {
|
||||
case 'T': { // Type encoding
|
||||
if (attrs[i].value) {
|
||||
_typeEncoding = [NSString stringWithUTF8String:attrs[i].value];
|
||||
type = YYEncodingGetType(attrs[i].value);
|
||||
|
||||
if ((type & YYEncodingTypeMask) == YYEncodingTypeObject && _typeEncoding.length) {
|
||||
NSScanner *scanner = [NSScanner scannerWithString:_typeEncoding];
|
||||
if (![scanner scanString:@"@\"" intoString:NULL]) continue;
|
||||
|
||||
NSString *clsName = nil;
|
||||
if ([scanner scanUpToCharactersFromSet: [NSCharacterSet characterSetWithCharactersInString:@"\"<"] intoString:&clsName]) {
|
||||
if (clsName.length) _cls = objc_getClass(clsName.UTF8String);
|
||||
}
|
||||
|
||||
NSMutableArray *protocols = nil;
|
||||
while ([scanner scanString:@"<" intoString:NULL]) {
|
||||
NSString* protocol = nil;
|
||||
if ([scanner scanUpToString:@">" intoString: &protocol]) {
|
||||
if (protocol.length) {
|
||||
if (!protocols) protocols = [NSMutableArray new];
|
||||
[protocols addObject:protocol];
|
||||
}
|
||||
}
|
||||
[scanner scanString:@">" intoString:NULL];
|
||||
}
|
||||
_protocols = protocols;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case 'V': { // Instance variable
|
||||
if (attrs[i].value) {
|
||||
_ivarName = [NSString stringWithUTF8String:attrs[i].value];
|
||||
}
|
||||
} break;
|
||||
case 'R': {
|
||||
type |= YYEncodingTypePropertyReadonly;
|
||||
} break;
|
||||
case 'C': {
|
||||
type |= YYEncodingTypePropertyCopy;
|
||||
} break;
|
||||
case '&': {
|
||||
type |= YYEncodingTypePropertyRetain;
|
||||
} break;
|
||||
case 'N': {
|
||||
type |= YYEncodingTypePropertyNonatomic;
|
||||
} break;
|
||||
case 'D': {
|
||||
type |= YYEncodingTypePropertyDynamic;
|
||||
} break;
|
||||
case 'W': {
|
||||
type |= YYEncodingTypePropertyWeak;
|
||||
} break;
|
||||
case 'G': {
|
||||
type |= YYEncodingTypePropertyCustomGetter;
|
||||
if (attrs[i].value) {
|
||||
_getter = NSSelectorFromString([NSString stringWithUTF8String:attrs[i].value]);
|
||||
}
|
||||
} break;
|
||||
case 'S': {
|
||||
type |= YYEncodingTypePropertyCustomSetter;
|
||||
if (attrs[i].value) {
|
||||
_setter = NSSelectorFromString([NSString stringWithUTF8String:attrs[i].value]);
|
||||
}
|
||||
} // break; commented for code coverage in next line
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
if (attrs) {
|
||||
free(attrs);
|
||||
attrs = NULL;
|
||||
}
|
||||
|
||||
_type = type;
|
||||
if (_name.length) {
|
||||
if (!_getter) {
|
||||
_getter = NSSelectorFromString(_name);
|
||||
}
|
||||
if (!_setter) {
|
||||
_setter = NSSelectorFromString([NSString stringWithFormat:@"set%@%@:", [_name substringToIndex:1].uppercaseString, [_name substringFromIndex:1]]);
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation YYClassInfo {
|
||||
BOOL _needUpdate;
|
||||
}
|
||||
|
||||
- (instancetype)initWithClass:(Class)cls {
|
||||
if (!cls) return nil;
|
||||
self = [super init];
|
||||
_cls = cls;
|
||||
_superCls = class_getSuperclass(cls);
|
||||
_isMeta = class_isMetaClass(cls);
|
||||
if (!_isMeta) {
|
||||
_metaCls = objc_getMetaClass(class_getName(cls));
|
||||
}
|
||||
_name = NSStringFromClass(cls);
|
||||
[self _update];
|
||||
|
||||
_superClassInfo = [self.class classInfoWithClass:_superCls];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)_update {
|
||||
_ivarInfos = nil;
|
||||
_methodInfos = nil;
|
||||
_propertyInfos = nil;
|
||||
|
||||
Class cls = self.cls;
|
||||
unsigned int methodCount = 0;
|
||||
Method *methods = class_copyMethodList(cls, &methodCount);
|
||||
if (methods) {
|
||||
NSMutableDictionary *methodInfos = [NSMutableDictionary new];
|
||||
_methodInfos = methodInfos;
|
||||
for (unsigned int i = 0; i < methodCount; i++) {
|
||||
YYClassMethodInfo *info = [[YYClassMethodInfo alloc] initWithMethod:methods[i]];
|
||||
if (info.name) methodInfos[info.name] = info;
|
||||
}
|
||||
free(methods);
|
||||
}
|
||||
unsigned int propertyCount = 0;
|
||||
objc_property_t *properties = class_copyPropertyList(cls, &propertyCount);
|
||||
if (properties) {
|
||||
NSMutableDictionary *propertyInfos = [NSMutableDictionary new];
|
||||
_propertyInfos = propertyInfos;
|
||||
for (unsigned int i = 0; i < propertyCount; i++) {
|
||||
YYClassPropertyInfo *info = [[YYClassPropertyInfo alloc] initWithProperty:properties[i]];
|
||||
if (info.name) propertyInfos[info.name] = info;
|
||||
}
|
||||
free(properties);
|
||||
}
|
||||
|
||||
unsigned int ivarCount = 0;
|
||||
Ivar *ivars = class_copyIvarList(cls, &ivarCount);
|
||||
if (ivars) {
|
||||
NSMutableDictionary *ivarInfos = [NSMutableDictionary new];
|
||||
_ivarInfos = ivarInfos;
|
||||
for (unsigned int i = 0; i < ivarCount; i++) {
|
||||
YYClassIvarInfo *info = [[YYClassIvarInfo alloc] initWithIvar:ivars[i]];
|
||||
if (info.name) ivarInfos[info.name] = info;
|
||||
}
|
||||
free(ivars);
|
||||
}
|
||||
|
||||
if (!_ivarInfos) _ivarInfos = @{};
|
||||
if (!_methodInfos) _methodInfos = @{};
|
||||
if (!_propertyInfos) _propertyInfos = @{};
|
||||
|
||||
_needUpdate = NO;
|
||||
}
|
||||
|
||||
- (void)setNeedUpdate {
|
||||
_needUpdate = YES;
|
||||
}
|
||||
|
||||
- (BOOL)needUpdate {
|
||||
return _needUpdate;
|
||||
}
|
||||
|
||||
+ (instancetype)classInfoWithClass:(Class)cls {
|
||||
if (!cls) return nil;
|
||||
static CFMutableDictionaryRef classCache;
|
||||
static CFMutableDictionaryRef metaCache;
|
||||
static dispatch_once_t onceToken;
|
||||
static dispatch_semaphore_t lock;
|
||||
dispatch_once(&onceToken, ^{
|
||||
classCache = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
metaCache = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
lock = dispatch_semaphore_create(1);
|
||||
});
|
||||
dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
|
||||
YYClassInfo *info = CFDictionaryGetValue(class_isMetaClass(cls) ? metaCache : classCache, (__bridge const void *)(cls));
|
||||
if (info && info->_needUpdate) {
|
||||
[info _update];
|
||||
}
|
||||
dispatch_semaphore_signal(lock);
|
||||
if (!info) {
|
||||
info = [[YYClassInfo alloc] initWithClass:cls];
|
||||
if (info) {
|
||||
dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
|
||||
CFDictionarySetValue(info.isMeta ? metaCache : classCache, (__bridge const void *)(cls), (__bridge const void *)(info));
|
||||
dispatch_semaphore_signal(lock);
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
+ (instancetype)classInfoWithClassName:(NSString *)className {
|
||||
Class cls = NSClassFromString(className);
|
||||
return [self classInfoWithClass:cls];
|
||||
}
|
||||
|
||||
@end
|
||||
45
ShenQi/en.lproj/Localizable.strings
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
Localizable.strings
|
||||
ShenQi
|
||||
|
||||
Created by Yao on 2024/11/4.
|
||||
|
||||
*/
|
||||
|
||||
"Tips" = "TIPS";
|
||||
"Need to enable push permission" = "NEED TO ENABLE APNS PERMISSION";
|
||||
"SETTING" = "SETTING";
|
||||
"Contacts permission must be turned on" = "CONTACTS PERMISSION MUST BE TURNED ON";
|
||||
"Please enter the invitation code" = "PLEASE ENTER THE INVITATION CODE";
|
||||
"INPUT" = "INPUT";
|
||||
"HOMEPAGE" = "HOMEPAGE";
|
||||
"MY INVITE CODE" = "MY INVITE CODE";
|
||||
"SHARE" = "SHARE";
|
||||
"CANCEL" = "CANCEL";
|
||||
"Invite you to download" = "Invite you to download";
|
||||
"Share Success" = "Share Success!";
|
||||
"OK" = "OK";
|
||||
"COPY" = "COPY";
|
||||
"New version found" = "New version found";
|
||||
"Update" = "Update";
|
||||
"My Parent Invitation Code" = "My Parent Invitation Code";
|
||||
"RECORDS" = "INVITE RECORDS";
|
||||
"Balance" = "Balance";
|
||||
"Income" = "Income";
|
||||
"EditBank" = "Edit Bank";
|
||||
"RealName" = "Real Name";
|
||||
"BankName" = "Bank Name";
|
||||
"BankNO" = "Bank NO.";
|
||||
"PLS" = "Please";
|
||||
"InputEdit" = "input";
|
||||
"Withdraw" = "Withdrawal";
|
||||
"Amount" = "Amount";
|
||||
"WithdrawRecord" = "Withdrawal Record";
|
||||
"Choose" = "Choose";
|
||||
"OverCanWithdraw" = "Exceeding the withdrawal";
|
||||
"Area" = "Area";
|
||||
"OpenImage" = "Open Image";
|
||||
"OpenLink" = "Open Link";
|
||||
"Share With WhatsApp" = "WhatsApp Service";
|
||||
"Share With Telegram" = "Telegram Service";
|
||||
"Share With Facebook" = "Facebook Service";
|
||||
18
ShenQi/main.m
Normal file
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// main.m
|
||||
// ShenQi
|
||||
//
|
||||
// Created by Yao on 2023/4/4.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "AppDelegate.h"
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
NSString * appDelegateClassName;
|
||||
@autoreleasepool {
|
||||
// Setup code that might create autoreleased objects goes here.
|
||||
appDelegateClassName = NSStringFromClass([AppDelegate class]);
|
||||
}
|
||||
return UIApplicationMain(argc, argv, nil, appDelegateClassName);
|
||||
}
|
||||
1
ShenQi/ms.lproj/LaunchScreen.strings
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
42
ShenQi/ms.lproj/Localizable.strings
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
Localizable.strings
|
||||
ShenQi
|
||||
|
||||
Created by Yao on 2024/11/4.
|
||||
|
||||
*/
|
||||
|
||||
"Tips" = "petunjuk";
|
||||
"Need to enable push permission" = "Sila dayakan kebenaran tolak";
|
||||
"SETTING" = "sediakan";
|
||||
"Contacts permission must be turned on" = "Sila dayakan kebenaran buku alamat";
|
||||
"Please enter the invitation code" = "Sila masukkan kod jemputan";
|
||||
"INPUT" = "untuk mengisi";
|
||||
"HOMEPAGE" = "Laman utama";
|
||||
"MY INVITE CODE" = "kod jemputan saya";
|
||||
"SHARE" = "kongsi";
|
||||
"CANCEL" = "Batal";
|
||||
"Invite you to download" = "Menjemput anda untuk memuat turun";
|
||||
"Share Success" = "Kongsi kejayaan!";
|
||||
"OK" = "pasti";
|
||||
"COPY" = "klon";
|
||||
"New version found" = "versi baharu ditemui";
|
||||
"Update" = "Pergi ke kemas kini";
|
||||
"My Parent Invitation Code" = "Kod jemputan ibu bapa saya";
|
||||
"RECORDS" = "menjemput rekod";
|
||||
"Balance" = "Baki";
|
||||
"Income" = "pendapatan";
|
||||
"EditBank" = "Edit kad bank";
|
||||
"RealName" = "Nama pemegang kad";
|
||||
"BankName" = "Nama bank pembukaan";
|
||||
"BankNO" = "Nombor kad bank";
|
||||
"PLS" = "tolonglah";
|
||||
"InputEdit" = "masuk";
|
||||
"Withdraw" = "Keluarkan wang tunai";
|
||||
"Amount" = "Jumlah";
|
||||
"WithdrawRecord" = "Rekod pengeluaran";
|
||||
"Choose" = "pilih";
|
||||
"OverCanWithdraw" = "Lebih daripada yang boleh ditarik balik";
|
||||
"Area" = "wilayah negara";
|
||||
"OpenImage" = "Open Image";
|
||||
"OpenLink" = "Open Link";
|
||||
6
ShenQi/ms.lproj/Main.strings
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
/* Class = "UIButton"; configuration.title = "进入App"; ObjectID = "9sI-nt-sPs"; */
|
||||
"9sI-nt-sPs.configuration.title" = "进入App";
|
||||
|
||||
/* Class = "UIButton"; normalTitle = "Button"; ObjectID = "9sI-nt-sPs"; */
|
||||
"9sI-nt-sPs.normalTitle" = "Button";
|
||||
1
ShenQi/th.lproj/LaunchScreen.strings
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
42
ShenQi/th.lproj/Localizable.strings
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
Localizable.strings
|
||||
ShenQi
|
||||
|
||||
Created by Yao on 2024/11/4.
|
||||
|
||||
*/
|
||||
|
||||
"Tips" = "คำใบ้";
|
||||
"Need to enable push permission" = "โปรดเปิดใช้งานการอนุญาตแบบพุช";
|
||||
"SETTING" = "ไปที่การตั้งค่า";
|
||||
"Contacts permission must be turned on" = "โปรดเปิดใช้งานการอนุญาตสมุดที่อยู่";
|
||||
"Please enter the invitation code" = "กรุณากรอกรหัสเชิญ";
|
||||
"INPUT" = "เพื่อกรอก";
|
||||
"HOMEPAGE" = "หน้าแรก";
|
||||
"MY INVITE CODE" = "รหัสเชิญของฉัน";
|
||||
"SHARE" = "แบ่งปัน";
|
||||
"CANCEL" = "ยกเลิก";
|
||||
"Invite you to download" = "เชิญชวนให้ดาวน์โหลด";
|
||||
"Share Success" = "แบ่งปันความสำเร็จ!";
|
||||
"OK" = "แน่นอน";
|
||||
"COPY" = "โคลน";
|
||||
"New version found" = "พบเวอร์ชันใหม่แล้ว";
|
||||
"Update" = "ไปอัพเดทครับ";
|
||||
"My Parent Invitation Code" = "รหัสเชิญผู้ปกครองของฉัน";
|
||||
"RECORDS" = "บันทึกการเชิญ";
|
||||
"Balance" = "สมดุล";
|
||||
"Income" = "รายได้";
|
||||
"EditBank" = "แก้ไขบัตรธนาคาร";
|
||||
"RealName" = "ชื่อผู้ถือบัตร";
|
||||
"BankName" = "ชื่อธนาคารที่เปิด";
|
||||
"BankNO" = "หมายเลขบัตรธนาคาร";
|
||||
"PLS" = "โปรด";
|
||||
"InputEdit" = "เข้า";
|
||||
"Withdraw" = "ถอนเงินสด";
|
||||
"Amount" = "จำนวน";
|
||||
"WithdrawRecord" = "บันทึกการถอนเงิน";
|
||||
"Choose" = "เลือก";
|
||||
"OverCanWithdraw" = "เกินกว่าจะถอนได้";
|
||||
"Area" = "ภูมิภาคของประเทศ";
|
||||
"OpenImage" = "Open Image";
|
||||
"OpenLink" = "Open Link";
|
||||
6
ShenQi/th.lproj/Main.strings
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
/* Class = "UIButton"; configuration.title = "进入App"; ObjectID = "9sI-nt-sPs"; */
|
||||
"9sI-nt-sPs.configuration.title" = "进入App";
|
||||
|
||||
/* Class = "UIButton"; normalTitle = "Button"; ObjectID = "9sI-nt-sPs"; */
|
||||
"9sI-nt-sPs.normalTitle" = "Button";
|
||||
1
ShenQi/vi.lproj/LaunchScreen.strings
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
42
ShenQi/vi.lproj/Localizable.strings
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
Localizable.strings
|
||||
ShenQi
|
||||
|
||||
Created by Yao on 2024/11/4.
|
||||
|
||||
*/
|
||||
|
||||
"Tips" = "gợi ý";
|
||||
"Need to enable push permission" = "Vui lòng bật quyền đẩy";
|
||||
"SETTING" = "Đi tới cài đặt";
|
||||
"Contacts permission must be turned on" = "Vui lòng kích hoạt quyền sổ địa chỉ";
|
||||
"Please enter the invitation code" = "Vui lòng nhập mã mời";
|
||||
"INPUT" = "để điền vào";
|
||||
"HOMEPAGE" = "Trang chủ";
|
||||
"MY INVITE CODE" = "mã mời của tôi";
|
||||
"SHARE" = "chia sẻ";
|
||||
"CANCEL" = "Hủy bỏ";
|
||||
"Invite you to download" = "Mời bạn tải về";
|
||||
"Share Success" = "Chia sẻ thành công!";
|
||||
"OK" = "Chắc chắn";
|
||||
"COPY" = "sao chép";
|
||||
"New version found" = "phiên bản mới được tìm thấy";
|
||||
"Update" = "Đi tới cập nhật";
|
||||
"My Parent Invitation Code" = "Mã mời phụ huynh của tôi";
|
||||
"RECORDS" = "mời hồ sơ";
|
||||
"Balance" = "Sự cân bằng";
|
||||
"Income" = "thu nhập";
|
||||
"EditBank" = "Chỉnh sửa thẻ ngân hàng";
|
||||
"RealName" = "Tên chủ thẻ";
|
||||
"BankName" = "Tên ngân hàng mở";
|
||||
"BankNO" = "Số thẻ ngân hàng";
|
||||
"PLS" = "Xin vui lòng";
|
||||
"InputEdit" = "đi vào";
|
||||
"Withdraw" = "Rút tiền mặt";
|
||||
"Amount" = "Số lượng";
|
||||
"WithdrawRecord" = "Hồ sơ rút tiền";
|
||||
"Choose" = "chọn";
|
||||
"OverCanWithdraw" = "Có thể rút nhiều hơn";
|
||||
"Area" = "vùng đất nước";
|
||||
"OpenImage" = "Open Image";
|
||||
"OpenLink" = "Open Link";
|
||||
6
ShenQi/vi.lproj/Main.strings
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
/* Class = "UIButton"; configuration.title = "进入App"; ObjectID = "9sI-nt-sPs"; */
|
||||
"9sI-nt-sPs.configuration.title" = "进入App";
|
||||
|
||||
/* Class = "UIButton"; normalTitle = "Button"; ObjectID = "9sI-nt-sPs"; */
|
||||
"9sI-nt-sPs.normalTitle" = "Button";
|
||||
1
ShenQi/zh-Hans.lproj/LaunchScreen.strings
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
45
ShenQi/zh-Hans.lproj/Localizable.strings
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
Localizable.strings
|
||||
ShenQi
|
||||
|
||||
Created by Yao on 2024/11/4.
|
||||
|
||||
*/
|
||||
|
||||
"Tips" = "提示";
|
||||
"Need to enable push permission" = "请开启推送权限";
|
||||
"SETTING" = "去设置";
|
||||
"Contacts permission must be turned on" = "请开启通讯录权限";
|
||||
"Please enter the invitation code" = "请输入邀请码";
|
||||
"INPUT" = "去填写";
|
||||
"HOMEPAGE" = "主页";
|
||||
"MY INVITE CODE" = "我的邀请码";
|
||||
"SHARE" = "分享";
|
||||
"CANCEL" = "取消";
|
||||
"Invite you to download" = "邀请您下载";
|
||||
"Share Success" = "分享成功!";
|
||||
"OK" = "确定";
|
||||
"COPY" = "复制";
|
||||
"New version found" = "发现新版本";
|
||||
"Update" = "去更新";
|
||||
"My Parent Invitation Code" = "我的上级邀请码";
|
||||
"RECORDS" = "邀请记录";
|
||||
"Balance" = "余额";
|
||||
"Income" = "总收益";
|
||||
"EditBank" = "编辑银行卡";
|
||||
"RealName" = "持卡人姓名";
|
||||
"BankName" = "开户行名称";
|
||||
"BankNO" = "户口";
|
||||
"PLS" = "请";
|
||||
"InputEdit" = "输入";
|
||||
"Withdraw" = "提现";
|
||||
"Amount" = "金额";
|
||||
"WithdrawRecord" = "提现记录";
|
||||
"Choose" = "选择";
|
||||
"OverCanWithdraw" = "超过可提现";
|
||||
"Area" = "国家地区";
|
||||
"OpenImage" = "打开图片";
|
||||
"OpenLink" = "打开链接";
|
||||
"Share With WhatsApp" = "WhatsApp 客服";
|
||||
"Share With Telegram" = "Telegram 客服";
|
||||
"Share With Facebook" = "Facebook 客服";
|
||||
6
ShenQi/zh-Hans.lproj/Main.strings
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
/* Class = "UIButton"; configuration.title = "进入App"; ObjectID = "9sI-nt-sPs"; */
|
||||
"9sI-nt-sPs.configuration.title" = "进入App";
|
||||
|
||||
/* Class = "UIButton"; normalTitle = "Button"; ObjectID = "9sI-nt-sPs"; */
|
||||
"9sI-nt-sPs.normalTitle" = "Button";
|
||||
1
ShenQi/zh-Hant.lproj/LaunchScreen.strings
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
45
ShenQi/zh-Hant.lproj/Localizable.strings
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
Localizable.strings
|
||||
ShenQi
|
||||
|
||||
Created by Yao on 2024/11/4.
|
||||
|
||||
*/
|
||||
|
||||
"Tips" = "提示";
|
||||
"Need to enable push permission" = "請開啟推送權限";
|
||||
"SETTING" = "去設置";
|
||||
"Contacts permission must be turned on" = "請開啟通訊錄權限";
|
||||
"Please enter the invitation code" = "請輸入邀請碼";
|
||||
"INPUT" = "去填寫";
|
||||
"HOMEPAGE" = "主頁";
|
||||
"MY INVITE CODE" = "我的邀請碼";
|
||||
"SHARE" = "分享";
|
||||
"CANCEL" = "取消";
|
||||
"Invite you to download" = "邀請您下載";
|
||||
"Share Success" = "分享成功!";
|
||||
"OK" = "確定";
|
||||
"COPY" = "複製";
|
||||
"New version found" = "發現新版本";
|
||||
"Update" = "去更新";
|
||||
"My Parent Invitation Code" = "我的上級邀請碼";
|
||||
"RECORDS" = "邀請記錄";
|
||||
"Balance" = "餘額";
|
||||
"Income" = "總收益";
|
||||
"EditBank" = "編輯銀行卡";
|
||||
"RealName" = "持卡人姓名";
|
||||
"BankName" = "開戶行名稱";
|
||||
"BankNO" = "戶口";
|
||||
"PLS" = "請";
|
||||
"InputEdit" = "輸入";
|
||||
"Withdraw" = "提現";
|
||||
"Amount" = "金額";
|
||||
"WithdrawRecord" = "提現記錄";
|
||||
"Choose" = "選擇";
|
||||
"OverCanWithdraw" = "超過可提現";
|
||||
"Area" = "國家地區";
|
||||
"OpenImage" = "打開圖片";
|
||||
"OpenLink" = "打開鏈接";
|
||||
"Share With WhatsApp" = "WhatsApp 客服";
|
||||
"Share With Telegram" = "Telegram 客服";
|
||||
"Share With Facebook" = "Facebook 客服";
|
||||
6
ShenQi/zh-Hant.lproj/Main.strings
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
/* Class = "UIButton"; configuration.title = "进入App"; ObjectID = "9sI-nt-sPs"; */
|
||||
"9sI-nt-sPs.configuration.title" = "进入App";
|
||||
|
||||
/* Class = "UIButton"; normalTitle = "Button"; ObjectID = "9sI-nt-sPs"; */
|
||||
"9sI-nt-sPs.normalTitle" = "Button";
|
||||