YMCaptchaPopupView.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  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. // 如果是删除操作,允许
  143. if (string.length == 0) {
  144. return YES;
  145. }
  146. // 使用正则表达式判断是否只包含字母和数字
  147. NSString *pattern = @"^[a-zA-Z0-9]+$";
  148. NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", pattern];
  149. return [predicate evaluateWithObject:string];
  150. }
  151. #pragma mark - Actions
  152. - (void)cancelButtonTapped {
  153. // if ([self.delegate respondsToSelector:@selector(captchaViewDidCancel)]) {
  154. // [self.delegate captchaViewDidCancel];
  155. // }
  156. if (self.cancelButtonTappedBlock) {
  157. self.cancelButtonTappedBlock();
  158. }
  159. [self dismiss];
  160. }
  161. - (void)confirmButtonTapped {
  162. if (self.confirmButtonTappedBlock) {
  163. self.confirmButtonTappedBlock(self.inputTextField.text);
  164. }
  165. [self dismiss];
  166. // if ([self.delegate respondsToSelector:@selector(captchaViewDidConfirmWithInput:)]) {
  167. // [self.delegate captchaViewDidConfirmWithInput:self.inputTextField.text];
  168. // }
  169. // Optionally dismiss after confirm, or let the delegate handle it
  170. // [self dismiss];
  171. }
  172. #pragma mark - Public Methods
  173. - (void)showInView:(UIView *)view {
  174. self.frame = view.bounds;
  175. [view addSubview:self];
  176. self.alpha = 0;
  177. self.contentView.transform = CGAffineTransformMakeScale(0.5, 0.5);
  178. [UIView animateWithDuration:0.3 animations:^{
  179. self.alpha = 1;
  180. self.contentView.transform = CGAffineTransformIdentity;
  181. }];
  182. }
  183. - (void)dismiss {
  184. [UIView animateWithDuration:0.3 animations:^{
  185. self.alpha = 0;
  186. self.contentView.transform = CGAffineTransformMakeScale(0.5, 0.5);
  187. } completion:^(BOOL finished) {
  188. [self removeFromSuperview];
  189. }];
  190. }
  191. - (void)setCaptchaImage:(UIImage *)image {
  192. self.captchaImageView.image = image;
  193. }
  194. - (void)refreshCaptcha {
  195. NSLog(@"Refresh captcha tapped");
  196. [self loadCaptchaImage];
  197. }
  198. - (void)getCaptchaImageCompletion:(void(^)(UIImage *image))completion {
  199. NSString * urlstr=[NSString stringWithFormat:@"%@%@",[LCSaveData getBaseURL]?[LCSaveData getBaseURL]:BaseURL,GetCaptcha];
  200. NSURL *url = [NSURL URLWithString:urlstr];
  201. if (!url) {
  202. NSLog(@"Captcha URL is nil");
  203. return;
  204. }
  205. NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
  206. if (error) {
  207. NSLog(@"Error fetching captcha image: %@", error.localizedDescription);
  208. } else if (data) {
  209. UIImage *image = [UIImage imageWithData:data];
  210. if (image) {
  211. dispatch_async(dispatch_get_main_queue(), ^{
  212. completion(image);
  213. //self.captchaImageView.image = image;
  214. });
  215. } else {
  216. NSLog(@"Failed to convert data to image");
  217. }
  218. } else {
  219. NSLog(@"No data received for captcha image");
  220. }
  221. }];
  222. [task resume];
  223. }
  224. @end