TOPasscodeView.m 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  1. //
  2. // TOPasscodeView.m
  3. //
  4. // Copyright 2017 Timothy Oliver. All rights reserved.
  5. //
  6. // Permission is hereby granted, free of charge, to any person obtaining a copy
  7. // of this software and associated documentation files (the "Software"), to
  8. // deal in the Software without restriction, including without limitation the
  9. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  10. // sell copies of the Software, and to permit persons to whom the Software is
  11. // furnished to do so, subject to the following conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be included in
  14. // all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  17. // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  20. // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
  21. // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. #import "TOPasscodeView.h"
  23. #import "TOPasscodeViewContentLayout.h"
  24. #import "TOPasscodeCircleButton.h"
  25. #import "TOPasscodeInputField.h"
  26. #import "TOPasscodeKeypadView.h"
  27. @interface TOPasscodeView ()
  28. /* The current layout object used to configure this view */
  29. @property (nonatomic, weak) TOPasscodeViewContentLayout *currentLayout;
  30. /* The main views */
  31. @property (nonatomic, strong, readwrite) UILabel *titleLabel;
  32. @property (nonatomic, strong, readwrite) TOPasscodeInputField *inputField;
  33. @property (nonatomic, strong, readwrite) TOPasscodeKeypadView *keypadView;
  34. /* The type of passcode we're displaying */
  35. @property (nonatomic, assign, readwrite) TOPasscodeType passcodeType;
  36. @end
  37. @implementation TOPasscodeView
  38. - (instancetype)initWithFrame:(CGRect)frame
  39. {
  40. if (self = [super initWithFrame:frame]) {
  41. [self setUp];
  42. }
  43. return self;
  44. }
  45. - (instancetype)initWithStyle:(TOPasscodeViewStyle)style passcodeType:(TOPasscodeType)type
  46. {
  47. if (self = [super initWithFrame:CGRectMake(0,0,320,393)]) {
  48. _style = style;
  49. _passcodeType = type;
  50. [self setUp];
  51. }
  52. return self;
  53. }
  54. - (instancetype)initWithCoder:(NSCoder *)aDecoder
  55. {
  56. if (self = [super initWithCoder:aDecoder]) {
  57. [self setUp];
  58. }
  59. return self;
  60. }
  61. - (void)setUp
  62. {
  63. // Set up default properties
  64. self.userInteractionEnabled = YES;
  65. _defaultContentLayout = [TOPasscodeViewContentLayout defaultScreenContentLayout];
  66. _currentLayout = _defaultContentLayout;
  67. _contentLayouts = @[[TOPasscodeViewContentLayout mediumScreenContentLayout],
  68. [TOPasscodeViewContentLayout smallScreenContentLayout]];
  69. _titleText = NSLocalizedString(@"Enter Passcode", @"");
  70. // Start configuring views
  71. [self setUpViewForType:self.passcodeType];
  72. // Set the default layout for the views
  73. [self updateSubviewsForContentLayout:_defaultContentLayout];
  74. // Configure the theme of all of the views
  75. [self applyThemeForStyle:_style];
  76. }
  77. #pragma mark - View Layout -
  78. - (void)verticallyLayoutSubviews
  79. {
  80. CGSize viewSize = self.frame.size;
  81. CGSize midViewSize = (CGSize){self.frame.size.width * 0.5f, self.frame.size.height * 0.5f};
  82. CGRect frame = CGRectZero;
  83. CGFloat y = 0.0f;
  84. // Title View
  85. if (self.titleView) {
  86. frame = self.titleView.frame;
  87. frame.origin.y = y;
  88. frame.origin.x = midViewSize.width - (CGRectGetWidth(frame) * 0.5f);
  89. self.titleView.frame = CGRectIntegral(frame);
  90. y = CGRectGetMaxY(frame) + self.currentLayout.titleViewBottomSpacing;
  91. }
  92. // Title Label
  93. frame = self.titleLabel.frame;
  94. frame.origin.y = y;
  95. frame.origin.x = midViewSize.width - (CGRectGetWidth(frame) * 0.5f);
  96. self.titleLabel.frame = CGRectIntegral(frame);
  97. y = CGRectGetMaxY(frame) + self.currentLayout.titleLabelBottomSpacing;
  98. // Circle Row View
  99. [self.inputField sizeToFit];
  100. frame = self.inputField.frame;
  101. frame.origin.y = y;
  102. frame.origin.x = midViewSize.width - (CGRectGetWidth(frame) * 0.5f);
  103. self.inputField.frame = CGRectIntegral(frame);
  104. y = CGRectGetMaxY(frame) + self.currentLayout.circleRowBottomSpacing;
  105. // PIN Pad View
  106. if (self.keypadView) {
  107. frame = self.keypadView.frame;
  108. frame.origin.y = y;
  109. frame.origin.x = midViewSize.width - (CGRectGetWidth(frame) * 0.5f);
  110. self.keypadView.frame = CGRectIntegral(frame);
  111. }
  112. // If the keypad view is hidden, lay out the left button manually
  113. if (!self.keypadView && self.leftButton) {
  114. frame = self.leftButton.frame;
  115. frame.origin.x = 0.0f;
  116. frame.origin.y = y;
  117. self.leftButton.frame = frame;
  118. }
  119. // If the keypad view is hidden, lay out the right button manually
  120. if (!self.keypadView && self.rightButton) {
  121. frame = self.rightButton.frame;
  122. frame.origin.x = viewSize.width - frame.size.width;
  123. frame.origin.y = y;
  124. self.rightButton.frame = frame;
  125. }
  126. }
  127. - (void)horizontallyLayoutSubviews
  128. {
  129. CGSize midViewSize = (CGSize){self.frame.size.width * 0.5f, self.frame.size.height * 0.5f};
  130. CGRect frame = CGRectZero;
  131. // Work out the y offset, assuming the input field is in the middle
  132. frame.origin.y = midViewSize.height - (self.inputField.frame.size.height * 0.5f);
  133. frame.origin.y -= (self.titleLabel.frame.size.height + self.currentLayout.titleLabelHorizontalBottomSpacing);
  134. // Include offset for title view if present
  135. if (self.titleView) {
  136. frame.origin.y -= (self.titleView.frame.size.height + self.currentLayout.titleViewHorizontalBottomSpacing);
  137. }
  138. // Set initial Y offset
  139. frame.origin.y = MAX(frame.origin.y, 0.0f);
  140. // Set frame of title view
  141. if (self.titleView) {
  142. frame.size = self.titleView.frame.size;
  143. frame.origin.x = (self.currentLayout.titleHorizontalLayoutWidth - frame.size.width) * 0.5f;
  144. self.titleView.frame = CGRectIntegral(frame);
  145. frame.origin.y += (frame.size.height + self.currentLayout.titleViewHorizontalBottomSpacing);
  146. }
  147. // Set frame of title label
  148. frame.size = self.titleLabel.frame.size;
  149. frame.origin.x = (self.currentLayout.titleHorizontalLayoutWidth - frame.size.width) * 0.5f;
  150. self.titleLabel.frame = CGRectIntegral(frame);
  151. frame.origin.y += (frame.size.height + self.currentLayout.titleLabelHorizontalBottomSpacing);
  152. // Set frame of the input field
  153. frame.size = self.inputField.frame.size;
  154. frame.origin.x = (self.currentLayout.titleHorizontalLayoutWidth - frame.size.width) * 0.5f;
  155. self.inputField.frame = CGRectIntegral(frame);
  156. // Set the frame of the keypad view
  157. frame.size = self.keypadView.frame.size;
  158. frame.origin.y = 0.0f;
  159. frame.origin.x = self.currentLayout.titleHorizontalLayoutWidth + self.currentLayout.titleHorizontalLayoutSpacing;
  160. self.keypadView.frame = CGRectIntegral(frame);
  161. }
  162. - (void)layoutSubviews
  163. {
  164. if (self.horizontalLayout) {
  165. [self horizontallyLayoutSubviews];
  166. }
  167. else {
  168. [self verticallyLayoutSubviews];
  169. }
  170. }
  171. - (void)sizeToFitSize:(CGSize)size
  172. {
  173. CGFloat width = size.width;
  174. if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
  175. width = MIN(size.width, size.height);
  176. }
  177. NSMutableArray *layouts = [NSMutableArray array];
  178. [layouts addObject:self.defaultContentLayout];
  179. [layouts addObjectsFromArray:self.contentLayouts];
  180. // Loop through each layout (in ascending order) and pick the best one to fit this view
  181. TOPasscodeViewContentLayout *contentLayout = self.defaultContentLayout;
  182. for (TOPasscodeViewContentLayout *layout in layouts) {
  183. if (width >= layout.viewWidth) {
  184. contentLayout = layout;
  185. break;
  186. }
  187. }
  188. // Set the new layout
  189. self.currentLayout = contentLayout;
  190. // Resize the views to fit
  191. [self sizeToFit];
  192. }
  193. - (void)verticalSizeToFit
  194. {
  195. CGRect frame = self.frame;
  196. frame.size.width = 0.0f;
  197. frame.size.height = 0.0f;
  198. [self.keypadView sizeToFit];
  199. [self.inputField sizeToFit];
  200. if (self.keypadView) {
  201. frame.size.width = self.keypadView.frame.size.width;
  202. }
  203. else {
  204. frame.size.width = self.inputField.frame.size.width;
  205. }
  206. // Add height for the title view
  207. if (self.titleView) {
  208. frame.size.height += self.titleView.frame.size.height;
  209. frame.size.height += self.currentLayout.titleViewBottomSpacing;
  210. }
  211. // Add height for the title label
  212. CGRect titleFrame = self.titleLabel.frame;
  213. titleFrame.size = [self.titleLabel sizeThatFits:(CGSize){frame.size.width, CGFLOAT_MAX}];
  214. self.titleLabel.frame = titleFrame;
  215. frame.size.height += titleFrame.size.height;
  216. frame.size.height += self.currentLayout.titleLabelBottomSpacing;
  217. // Add height for the circle rows
  218. frame.size.height += self.inputField.frame.size.height;
  219. frame.size.height += self.currentLayout.circleRowBottomSpacing;
  220. // Add height for the keypad
  221. if (self.keypadView) {
  222. frame.size.height += self.keypadView.frame.size.height;
  223. }
  224. else { // If no keypad, just factor in the accessory buttons
  225. [self.leftButton sizeToFit];
  226. [self.rightButton sizeToFit];
  227. CGFloat maxHeight = 0.0f;
  228. maxHeight = MAX(self.leftButton.frame.size.height, 0.0f);
  229. maxHeight = MAX(self.rightButton.frame.size.height, maxHeight);
  230. frame.size.height += maxHeight;
  231. }
  232. // Add extra padding at the bottom
  233. frame.size.height += self.currentLayout.bottomPadding;
  234. // Set the frame back
  235. self.frame = CGRectIntegral(frame);
  236. }
  237. - (void)horizontalSizeToFit
  238. {
  239. CGRect frame = self.frame;
  240. [self.keypadView sizeToFit];
  241. [self.inputField sizeToFit];
  242. frame.size.width = self.currentLayout.titleHorizontalLayoutWidth;
  243. frame.size.width += self.currentLayout.titleHorizontalLayoutSpacing;
  244. frame.size.width += self.keypadView.frame.size.width;
  245. frame.size.height = self.keypadView.frame.size.height;
  246. self.frame = CGRectIntegral(frame);
  247. }
  248. - (void)sizeToFit
  249. {
  250. if (self.horizontalLayout && self.passcodeType != TOPasscodeTypeCustomAlphanumeric) {
  251. [self horizontalSizeToFit];
  252. }
  253. else {
  254. [self verticalSizeToFit];
  255. }
  256. }
  257. #pragma mark - View Setup -
  258. - (void)setUpViewForType:(TOPasscodeType)type
  259. {
  260. __weak typeof(self) weakSelf = self;
  261. self.backgroundColor = [UIColor clearColor];
  262. // Set up title label
  263. if (self.titleLabel == nil) {
  264. self.titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
  265. }
  266. self.titleLabel.text = self.titleText;
  267. self.titleLabel.textAlignment = NSTextAlignmentCenter;
  268. self.titleLabel.numberOfLines = 0;
  269. [self.titleLabel sizeToFit];
  270. [self addSubview:self.titleLabel];
  271. // Set up the passcode style
  272. TOPasscodeInputFieldStyle style = TOPasscodeInputFieldStyleFixed;
  273. if (type >= TOPasscodeTypeCustomNumeric) {
  274. style = TOPasscodeInputFieldStyleVariable;
  275. }
  276. // Set up input field
  277. if (self.inputField == nil) {
  278. self.inputField = [[TOPasscodeInputField alloc] initWithStyle:style];
  279. }
  280. self.inputField.passcodeCompletedHandler = ^(NSString *passcode) {
  281. if (weakSelf.passcodeCompletedHandler) {
  282. weakSelf.passcodeCompletedHandler(passcode);
  283. }
  284. };
  285. // Configure the input field based on the exact passcode type
  286. if (style == TOPasscodeInputFieldStyleFixed) {
  287. self.inputField.fixedInputView.length = (self.passcodeType == TOPasscodeTypeSixDigits) ? 6 : 4;
  288. }
  289. else {
  290. self.inputField.showSubmitButton = (self.passcodeType == TOPasscodeTypeCustomNumeric);
  291. self.inputField.enabled = (self.passcodeType == TOPasscodeTypeCustomAlphanumeric);
  292. }
  293. [self addSubview:self.inputField];
  294. // Set up pad row
  295. if (type != TOPasscodeTypeCustomAlphanumeric) {
  296. if (self.keypadView == nil) {
  297. self.keypadView = [[TOPasscodeKeypadView alloc] init];
  298. }
  299. self.keypadView.buttonTappedHandler = ^(NSInteger button) {
  300. NSString *numberString = [NSString stringWithFormat:@"%ld", (long)button];
  301. [weakSelf.inputField appendPasscodeCharacters:numberString animated:NO];
  302. if (weakSelf.passcodeDigitEnteredHandler) {
  303. weakSelf.passcodeDigitEnteredHandler();
  304. }
  305. };
  306. [self addSubview:self.keypadView];
  307. }
  308. else {
  309. [self.keypadView removeFromSuperview];
  310. self.keypadView = nil;
  311. }
  312. }
  313. - (void)updateSubviewsForContentLayout:(TOPasscodeViewContentLayout *)contentLayout
  314. {
  315. // Title View
  316. self.titleLabel.font = contentLayout.titleLabelFont;
  317. // Circle Row View
  318. self.inputField.fixedInputView.circleDiameter = contentLayout.circleRowDiameter;
  319. self.inputField.fixedInputView.circleSpacing = contentLayout.circleRowSpacing;
  320. // Text Field Input Row
  321. NSInteger maximumInputLength = (self.passcodeType == TOPasscodeTypeCustomAlphanumeric) ?
  322. contentLayout.textFieldAlphanumericCharacterLength :
  323. contentLayout.textFieldNumericCharacterLength;
  324. self.inputField.variableInputView.outlineThickness = contentLayout.textFieldBorderThickness;
  325. self.inputField.variableInputView.outlineCornerRadius = contentLayout.textFieldBorderRadius;
  326. self.inputField.variableInputView.circleDiameter = contentLayout.textFieldCircleDiameter;
  327. self.inputField.variableInputView.circleSpacing = contentLayout.textFieldCircleSpacing;
  328. self.inputField.variableInputView.outlinePadding = contentLayout.textFieldBorderPadding;
  329. self.inputField.variableInputView.maximumVisibleLength = maximumInputLength;
  330. // Submit button
  331. self.inputField.submitButtonSpacing = contentLayout.submitButtonSpacing;
  332. self.inputField.submitButtonFontSize = contentLayout.submitButtonFontSize;
  333. // Keypad
  334. self.keypadView.buttonNumberFont = contentLayout.circleButtonTitleLabelFont;
  335. self.keypadView.buttonLetteringFont = contentLayout.circleButtonLetteringLabelFont;
  336. self.keypadView.buttonLetteringSpacing = contentLayout.circleButtonLetteringSpacing;
  337. self.keypadView.buttonLabelSpacing = contentLayout.circleButtonLabelSpacing;
  338. self.keypadView.buttonSpacing = contentLayout.circleButtonSpacing;
  339. self.keypadView.buttonDiameter = contentLayout.circleButtonDiameter;
  340. }
  341. - (void)applyThemeForStyle:(TOPasscodeViewStyle)style
  342. {
  343. BOOL isTranslucent = TOPasscodeViewStyleIsTranslucent(style);
  344. BOOL isDark = TOPasscodeViewStyleIsDark(style);
  345. // Set title label color
  346. UIColor *titleLabelColor = self.titleLabelColor;
  347. if (titleLabelColor == nil) {
  348. titleLabelColor = isDark ? [UIColor whiteColor] : [UIColor blackColor];
  349. }
  350. self.titleLabel.textColor = titleLabelColor;
  351. // Add/remove the translucency effect to the buttons
  352. if (isTranslucent) {
  353. UIBlurEffect *blurEffect = [self blurEffectForStyle:style];
  354. UIVibrancyEffect *vibrancyEffect = [UIVibrancyEffect effectForBlurEffect:blurEffect];
  355. self.inputField.visualEffectView.effect = vibrancyEffect;
  356. self.keypadView.vibrancyEffect = vibrancyEffect;
  357. }
  358. else {
  359. self.inputField.visualEffectView.effect = nil;
  360. self.keypadView.vibrancyEffect = nil;
  361. }
  362. // Set keyboard style of the input field
  363. self.inputField.keyboardAppearance = isDark ? UIKeyboardAppearanceDark : UIKeyboardAppearanceDefault;
  364. UIColor *defaultTintColor = isDark ? [UIColor colorWithWhite:0.85 alpha:1.0f] : [UIColor colorWithWhite:0.3 alpha:1.0f];
  365. // Set the tint color of the circle row view
  366. UIColor *circleRowColor = self.inputProgressViewTintColor;
  367. if (circleRowColor == nil) {
  368. circleRowColor = defaultTintColor;
  369. }
  370. self.inputField.tintColor = defaultTintColor;
  371. // Set the tint color of the keypad buttons
  372. UIColor *keypadButtonBackgroundColor = self.keypadButtonBackgroundColor;
  373. if (keypadButtonBackgroundColor == nil) {
  374. keypadButtonBackgroundColor = defaultTintColor;
  375. }
  376. self.keypadView.buttonBackgroundColor = keypadButtonBackgroundColor;
  377. // Set the color of the keypad button labels
  378. UIColor *buttonTextColor = self.keypadButtonTextColor;
  379. if (buttonTextColor == nil) {
  380. buttonTextColor = isDark ? [UIColor whiteColor] : [UIColor blackColor];
  381. }
  382. self.keypadView.buttonTextColor = buttonTextColor;
  383. // Set the highlight color of the keypad button
  384. UIColor *buttonHighlightedTextColor = self.keypadButtonHighlightedTextColor;
  385. if (buttonHighlightedTextColor == nil) {
  386. if (isTranslucent) {
  387. buttonHighlightedTextColor = isDark ? nil : [UIColor whiteColor];
  388. }
  389. else {
  390. buttonHighlightedTextColor = isDark ? [UIColor blackColor] : [UIColor whiteColor];
  391. }
  392. }
  393. self.keypadView.buttonHighlightedTextColor = buttonHighlightedTextColor;
  394. }
  395. #pragma mark - Passcode Management -
  396. - (void)resetPasscodeAnimated:(BOOL)animated playImpact:(BOOL)impact
  397. {
  398. [self.inputField resetPasscodeAnimated:animated playImpact:impact];
  399. }
  400. - (void)deleteLastPasscodeCharacterAnimated:(BOOL)animated
  401. {
  402. [self.inputField deletePasscodeCharactersOfCount:1 animated:animated];
  403. }
  404. #pragma mark - Internal Style Management -
  405. - (UIBlurEffect *)blurEffectForStyle:(TOPasscodeViewStyle)style
  406. {
  407. switch (style) {
  408. case TOPasscodeViewStyleTranslucentDark:
  409. return [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
  410. case TOPasscodeViewStyleTranslucentLight:
  411. return [UIBlurEffect effectWithStyle:UIBlurEffectStyleExtraLight];
  412. default: return nil;
  413. }
  414. return nil;
  415. }
  416. #pragma mark - Accessors -
  417. - (void)setHorizontalLayout:(BOOL)horizontalLayout
  418. {
  419. [self setHorizontalLayout:horizontalLayout animated:NO duration:0.0f];
  420. }
  421. - (void)setHorizontalLayout:(BOOL)horizontalLayout animated:(BOOL)animated duration:(CGFloat)duration
  422. {
  423. if (horizontalLayout == _horizontalLayout) { return; }
  424. _horizontalLayout = horizontalLayout;
  425. [self.keypadView setHorizontalLayout:horizontalLayout animated:animated duration:duration];
  426. [self.inputField setHorizontalLayout:horizontalLayout animated:animated duration:duration];
  427. }
  428. - (void)setDefaultContentLayout:(TOPasscodeViewContentLayout *)defaultContentLayout
  429. {
  430. if (defaultContentLayout == _defaultContentLayout) { return; }
  431. _defaultContentLayout = defaultContentLayout;
  432. if (!_defaultContentLayout) {
  433. _defaultContentLayout = [TOPasscodeViewContentLayout defaultScreenContentLayout];
  434. }
  435. }
  436. - (void)setCurrentLayout:(TOPasscodeViewContentLayout *)currentLayout
  437. {
  438. if (_currentLayout == currentLayout) { return; }
  439. _currentLayout = currentLayout;
  440. // Update the views
  441. [self updateSubviewsForContentLayout:currentLayout];
  442. }
  443. - (void)setStyle:(TOPasscodeViewStyle)style
  444. {
  445. if (style == _style) { return; }
  446. _style = style;
  447. [self applyThemeForStyle:style];
  448. }
  449. - (void)setTitleLabelColor:(UIColor *)titleLabelColor
  450. {
  451. if (titleLabelColor == _titleLabelColor) { return; }
  452. _titleLabelColor = titleLabelColor;
  453. self.titleLabel.textColor = titleLabelColor;
  454. }
  455. - (void)setInputProgressViewTintColor:(UIColor *)inputProgressViewTintColor
  456. {
  457. if (inputProgressViewTintColor == _inputProgressViewTintColor) { return; }
  458. _inputProgressViewTintColor = inputProgressViewTintColor;
  459. self.inputField.tintColor = inputProgressViewTintColor;
  460. }
  461. - (void)setKeypadButtonBackgroundColor:(UIColor *)keypadButtonBackgroundColor
  462. {
  463. if (keypadButtonBackgroundColor == _keypadButtonBackgroundColor) { return; }
  464. _keypadButtonBackgroundColor = keypadButtonBackgroundColor;
  465. self.keypadView.buttonBackgroundColor = keypadButtonBackgroundColor;
  466. }
  467. - (void)setKeypadButtonTextColor:(UIColor *)keypadButtonTextColor
  468. {
  469. if (keypadButtonTextColor == _keypadButtonTextColor) { return; }
  470. _keypadButtonTextColor = keypadButtonTextColor;
  471. self.keypadView.buttonTextColor = keypadButtonTextColor;
  472. }
  473. - (void)setKeypadButtonHighlightedTextColor:(UIColor *)keypadButtonHighlightedTextColor
  474. {
  475. if (keypadButtonHighlightedTextColor == _keypadButtonHighlightedTextColor) { return; }
  476. _keypadButtonHighlightedTextColor = keypadButtonHighlightedTextColor;
  477. self.keypadView.buttonHighlightedTextColor = keypadButtonHighlightedTextColor;
  478. }
  479. - (void)setLeftButton:(UIButton *)leftButton
  480. {
  481. if (leftButton == _leftButton) { return; }
  482. _leftButton = leftButton;
  483. if (self.keypadView) {
  484. self.keypadView.leftAccessoryView = leftButton;
  485. }
  486. else {
  487. [self addSubview:_leftButton];
  488. }
  489. }
  490. - (void)setRightButton:(UIButton *)rightButton
  491. {
  492. if (rightButton == _rightButton) { return; }
  493. _rightButton = rightButton;
  494. if (self.keypadView) {
  495. self.keypadView.rightAccessoryView = rightButton;
  496. }
  497. else {
  498. [self addSubview:_rightButton];
  499. }
  500. }
  501. - (CGFloat)keypadButtonInset
  502. {
  503. UIView *button = self.keypadView.keypadButtons.firstObject;
  504. return CGRectGetMidX(button.frame);
  505. }
  506. - (void)setContentAlpha:(CGFloat)contentAlpha
  507. {
  508. _contentAlpha = contentAlpha;
  509. self.titleView.alpha = contentAlpha;
  510. self.titleLabel.alpha = contentAlpha;
  511. self.inputField.contentAlpha = contentAlpha;
  512. self.keypadView.contentAlpha = contentAlpha;
  513. self.leftButton.alpha = contentAlpha;
  514. self.rightButton.alpha = contentAlpha;
  515. }
  516. - (void)setPasscode:(NSString *)passcode
  517. {
  518. [self.inputField setPasscode:passcode];
  519. }
  520. - (NSString *)passcode
  521. {
  522. return self.inputField.passcode;
  523. }
  524. @end