YMCaptchaPopupView.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. //
  2. // YMCaptchaPopupView.m
  3. // MSYOUPAI
  4. //
  5. // Created by macmini on 2025/6/7.
  6. // Copyright © 2025 MS. All rights reserved.
  7. //
  8. #import "YMCaptchaPopupView.h"
  9. @interface YMCaptchaPopupView ()<UITextFieldDelegate>
  10. @property (nonatomic, strong) UIView *backgroundMaskView;
  11. @property (nonatomic, strong) UIView *contentView;
  12. @property (nonatomic, strong) UILabel *titleLabel;
  13. @property (nonatomic, strong) UITextField *inputTextField;
  14. @property (nonatomic, strong) UIImageView *captchaImageView;
  15. @property (nonatomic, strong) UIButton *cancelButton;
  16. @property (nonatomic, strong) UIButton *confirmButton;
  17. @end
  18. @implementation YMCaptchaPopupView
  19. - (instancetype)initWithFrame:(CGRect)frame {
  20. self = [super initWithFrame:frame];
  21. if (self) {
  22. [self setupUI];
  23. [self loadCaptchaImage];
  24. }
  25. return self;
  26. }
  27. - (void)setupUI {
  28. self.backgroundColor = [UIColor clearColor];
  29. // Background Mask
  30. self.backgroundMaskView = [[UIView alloc] initWithFrame:self.bounds];
  31. self.backgroundMaskView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5];
  32. self.backgroundMaskView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
  33. [self addSubview:self.backgroundMaskView];
  34. UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismiss)];
  35. [self.backgroundMaskView addGestureRecognizer:tapGesture];
  36. // Content View
  37. self.contentView = [[UIView alloc] init];
  38. self.contentView.backgroundColor = [UIColor whiteColor];
  39. self.contentView.layer.cornerRadius = 10.0;
  40. self.contentView.clipsToBounds = YES;
  41. [self.contentView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithActionBlock:^(id _Nonnull sender) { }]];
  42. [self addSubview:self.contentView];
  43. // Title Label
  44. self.titleLabel = [[UILabel alloc] init];
  45. self.titleLabel.text = @"图形验证";
  46. self.titleLabel.font = [UIFont boldSystemFontOfSize:18.0];
  47. self.titleLabel.textAlignment = NSTextAlignmentCenter;
  48. [self.contentView addSubview:self.titleLabel];
  49. // Input TextField
  50. self.inputTextField = [[UITextField alloc] init];
  51. self.inputTextField.font = [UIFont systemFontOfSize:14 weight:(UIFontWeightRegular)];
  52. self.inputTextField.placeholder = @"请输入验证码(不区分大小写)";
  53. self.inputTextField.borderStyle = UITextBorderStyleRoundedRect;
  54. self.inputTextField.autocapitalizationType = UITextAutocapitalizationTypeNone;
  55. self.inputTextField.delegate = self;
  56. [self.contentView addSubview:self.inputTextField];
  57. // Captcha ImageView
  58. self.captchaImageView = [[UIImageView alloc] init];
  59. self.captchaImageView.backgroundColor = [UIColor lightGrayColor]; // Placeholder color
  60. self.captchaImageView.contentMode = UIViewContentModeScaleToFill;
  61. self.captchaImageView.userInteractionEnabled = YES;
  62. self.captchaImageView.clipsToBounds = YES;
  63. self.captchaImageView.layer.cornerRadius = 5; // Approximate from image
  64. // You might want to add a tap gesture to refresh the captcha
  65. // For example:
  66. UITapGestureRecognizer *captchaTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(refreshCaptcha)];
  67. [self.captchaImageView addGestureRecognizer:captchaTap];
  68. [self.contentView addSubview:self.captchaImageView];
  69. // Cancel Button
  70. self.cancelButton = [UIButton buttonWithType:UIButtonTypeSystem];
  71. [self.cancelButton setTitle:@"取消" forState:UIControlStateNormal];
  72. [self.cancelButton setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
  73. self.cancelButton.titleLabel.font = [UIFont systemFontOfSize:16.0];
  74. self.cancelButton.backgroundColor = [UIColor colorWithRed:0.95 green:0.95 blue:0.95 alpha:1.0]; // Light gray background
  75. self.cancelButton.layer.cornerRadius = 25; // Approximate from image
  76. [self.cancelButton addTarget:self action:@selector(cancelButtonTapped) forControlEvents:UIControlEventTouchUpInside];
  77. [self.contentView addSubview:self.cancelButton];
  78. // Confirm Button
  79. self.confirmButton = [UIButton buttonWithType:UIButtonTypeSystem];
  80. [self.confirmButton setTitle:@"确定" forState:UIControlStateNormal];
  81. [self.confirmButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
  82. self.confirmButton.titleLabel.font = [UIFont systemFontOfSize:16.0];
  83. self.confirmButton.backgroundColor = [UIColor colorWithRed:1.0 green:0.4 blue:0.5 alpha:1.0]; // Pinkish color
  84. self.confirmButton.layer.cornerRadius = 25; // Approximate from image
  85. [self.confirmButton addTarget:self action:@selector(confirmButtonTapped) forControlEvents:UIControlEventTouchUpInside];
  86. [self.contentView addSubview:self.confirmButton];
  87. [self setupLayoutConstraints];
  88. }
  89. - (void)setupLayoutConstraints {
  90. self.contentView.translatesAutoresizingMaskIntoConstraints = NO;
  91. self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
  92. self.inputTextField.translatesAutoresizingMaskIntoConstraints = NO;
  93. self.captchaImageView.translatesAutoresizingMaskIntoConstraints = NO;
  94. self.cancelButton.translatesAutoresizingMaskIntoConstraints = NO;
  95. self.confirmButton.translatesAutoresizingMaskIntoConstraints = NO;
  96. CGFloat contentWidth = CGRectGetWidth(UIScreen.mainScreen.bounds) - 60;
  97. CGFloat contentHeight = adapt(220); // Adjusted height
  98. [NSLayoutConstraint activateConstraints:@[
  99. [self.contentView.centerXAnchor constraintEqualToAnchor:self.centerXAnchor],
  100. [self.contentView.centerYAnchor constraintEqualToAnchor:self.centerYAnchor],
  101. [self.contentView.widthAnchor constraintEqualToConstant:contentWidth],
  102. [self.contentView.heightAnchor constraintEqualToConstant:contentHeight],
  103. [self.titleLabel.topAnchor constraintEqualToAnchor:self.contentView.topAnchor constant:20],
  104. [self.titleLabel.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:20],
  105. [self.titleLabel.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-20],
  106. [self.inputTextField.topAnchor constraintEqualToAnchor:self.titleLabel.bottomAnchor constant:40],
  107. [self.inputTextField.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:20],
  108. [self.inputTextField.heightAnchor constraintEqualToConstant:50],
  109. [self.captchaImageView.leadingAnchor constraintEqualToAnchor:self.inputTextField.trailingAnchor constant:10],
  110. [self.captchaImageView.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-20],
  111. [self.captchaImageView.centerYAnchor constraintEqualToAnchor:self.inputTextField.centerYAnchor],
  112. [self.captchaImageView.widthAnchor constraintEqualToConstant:100], // Adjust as needed
  113. [self.captchaImageView.heightAnchor constraintEqualToConstant:49],
  114. [self.inputTextField.trailingAnchor constraintEqualToAnchor:self.captchaImageView.leadingAnchor constant:-10],
  115. [self.cancelButton.topAnchor constraintEqualToAnchor:self.inputTextField.bottomAnchor constant:30],
  116. [self.cancelButton.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:20],
  117. [self.cancelButton.heightAnchor constraintEqualToConstant:50],
  118. [self.cancelButton.trailingAnchor constraintEqualToAnchor:self.contentView.centerXAnchor constant:-10],
  119. [self.confirmButton.topAnchor constraintEqualToAnchor:self.inputTextField.bottomAnchor constant:30],
  120. [self.confirmButton.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-20],
  121. [self.confirmButton.heightAnchor constraintEqualToConstant:50],
  122. [self.confirmButton.leadingAnchor constraintEqualToAnchor:self.contentView.centerXAnchor constant:10],
  123. ]];
  124. }
  125. - (void)loadCaptchaImage {
  126. [self getCaptchaImageCompletion:^(UIImage *image) {
  127. if (image) {
  128. self.captchaImageView.image = image;
  129. } else {
  130. self.captchaImageView.image = ImageByName(@"ym_sound_showcase_refresh_icon");
  131. }
  132. }];
  133. }
  134. - (void)inputTextChanged:(UITextField *)textField {
  135. NSString *text = textField.text;
  136. if (text.length > 4) {
  137. textField.text = [text substringToIndex:3];
  138. }
  139. }
  140. #pragma mark - UITextFieldDelegate
  141. - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
  142. if (string.length > 0 && textField.text.length >= 4) {
  143. return NO;
  144. }
  145. // 如果是删除操作,允许
  146. if (string.length == 0) {
  147. return YES;
  148. }
  149. // 使用正则表达式判断是否只包含字母和数字
  150. NSString *pattern = @"^[a-zA-Z0-9]+$";
  151. NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", pattern];
  152. return [predicate evaluateWithObject:string];
  153. }
  154. #pragma mark - Actions
  155. - (void)cancelButtonTapped {
  156. // if ([self.delegate respondsToSelector:@selector(captchaViewDidCancel)]) {
  157. // [self.delegate captchaViewDidCancel];
  158. // }
  159. if (self.cancelButtonTappedBlock) {
  160. self.cancelButtonTappedBlock();
  161. }
  162. [self dismiss];
  163. }
  164. - (void)confirmButtonTapped {
  165. if (self.confirmButtonTappedBlock) {
  166. self.confirmButtonTappedBlock(self.inputTextField.text);
  167. }
  168. [self dismiss];
  169. // if ([self.delegate respondsToSelector:@selector(captchaViewDidConfirmWithInput:)]) {
  170. // [self.delegate captchaViewDidConfirmWithInput:self.inputTextField.text];
  171. // }
  172. // Optionally dismiss after confirm, or let the delegate handle it
  173. // [self dismiss];
  174. }
  175. #pragma mark - Public Methods
  176. - (void)showInView:(UIView *)view {
  177. self.frame = view.bounds;
  178. [view addSubview:self];
  179. self.alpha = 0;
  180. self.contentView.transform = CGAffineTransformMakeScale(0.5, 0.5);
  181. [UIView animateWithDuration:0.3 animations:^{
  182. self.alpha = 1;
  183. self.contentView.transform = CGAffineTransformIdentity;
  184. }];
  185. }
  186. - (void)dismiss {
  187. [UIView animateWithDuration:0.3 animations:^{
  188. self.alpha = 0;
  189. self.contentView.transform = CGAffineTransformMakeScale(0.5, 0.5);
  190. } completion:^(BOOL finished) {
  191. [self removeFromSuperview];
  192. }];
  193. }
  194. - (void)setCaptchaImage:(UIImage *)image {
  195. self.captchaImageView.image = image;
  196. }
  197. - (void)refreshCaptcha {
  198. NSLog(@"Refresh captcha tapped");
  199. [self loadCaptchaImage];
  200. }
  201. - (void)getCaptchaImageCompletion:(void(^)(UIImage *image))completion {
  202. NSString * urlstr=[NSString stringWithFormat:@"%@%@",[LCSaveData getBaseURL]?[LCSaveData getBaseURL]:BaseURL,GetCaptcha];
  203. NSURL *url = [NSURL URLWithString:urlstr];
  204. if (!url) {
  205. NSLog(@"Captcha URL is nil");
  206. return;
  207. }
  208. NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
  209. if (error) {
  210. NSLog(@"Error fetching captcha image: %@", error.localizedDescription);
  211. } else if (data) {
  212. UIImage *image = [UIImage imageWithData:data];
  213. if (image) {
  214. dispatch_async(dispatch_get_main_queue(), ^{
  215. completion(image);
  216. //self.captchaImageView.image = image;
  217. });
  218. } else {
  219. NSLog(@"Failed to convert data to image");
  220. }
  221. } else {
  222. NSLog(@"No data received for captcha image");
  223. }
  224. }];
  225. [task resume];
  226. }
  227. @end