TOPasscodeView.m 23 KB

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