| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321 |
- #import "BTUIKExpiryInputView.h"
- #import "BTUIKExpiryInputCollectionViewCell.h"
- #import "BTUIKCollectionReusableView.h"
- #import "BTUIKAppearance.h"
- #import "BTUIKLocalizedString.h"
- #import "BTUIKViewUtil.h"
- #define BT_EXPIRY_FULL_PADDING 10
- #define BT_EXPIRY_SECTION_HEADER_HEIGHT 12
- @interface BTUIKExpiryInputView ()
- @property (nonatomic, strong) NSArray *months;
- @property (nonatomic, strong) NSArray *years;
- @property (nonatomic, strong) UICollectionView *monthCollectionView;
- @property (nonatomic, strong) UICollectionView *yearCollectionView;
- @property (nonatomic, strong) UIView *verticalLine;
- @property (nonatomic) NSInteger currentYear;
- @property (nonatomic) NSInteger currentMonth;
- @end
- @implementation BTUIKExpiryInputView
- - (instancetype)initWithFrame:(CGRect)frame {
- self = [super initWithFrame:frame];
- if (self) {
- self.backgroundColor = [BTUIKAppearance sharedInstance].formFieldBackgroundColor;
- self.months = @[@"01", @"02", @"03", @"04", @"05", @"06", @"07", @"08", @"09", @"10", @"11", @"12"];
-
- NSDate *currentDate = [NSDate date];
- NSCalendar *calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
- NSDateComponents *components = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth fromDate:currentDate];
- self.currentYear = components.year;
- self.currentMonth = components.month;
- NSInteger yearCounter = self.currentYear;
- NSMutableArray *mutableYears = [NSMutableArray arrayWithCapacity:20];
- while (yearCounter < self.currentYear + 20) {
- [mutableYears addObject:[NSString stringWithFormat:@"%@", @(yearCounter)]];
- yearCounter++;
- }
-
- self.years = [NSArray arrayWithArray:mutableYears];
-
- UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
- self.monthCollectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
- [self.monthCollectionView registerClass:[BTUIKExpiryInputCollectionViewCell class] forCellWithReuseIdentifier:@"BTMonthCell"];
- [self.monthCollectionView registerClass:[BTUIKCollectionReusableView class]
- forSupplementaryViewOfKind:UICollectionElementKindSectionHeader
- withReuseIdentifier:@"HeaderView"];
- self.monthCollectionView.translatesAutoresizingMaskIntoConstraints = NO;
- self.monthCollectionView.delegate = self;
- self.monthCollectionView.dataSource = self;
- self.monthCollectionView.backgroundColor = [UIColor clearColor];
- [self addSubview:self.monthCollectionView];
-
- layout = [[UICollectionViewFlowLayout alloc] init];
- self.yearCollectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
- [self.yearCollectionView registerClass:[BTUIKExpiryInputCollectionViewCell class] forCellWithReuseIdentifier:@"BTYearCell"];
- [self.yearCollectionView registerClass:[BTUIKCollectionReusableView class]
- forSupplementaryViewOfKind:UICollectionElementKindSectionHeader
- withReuseIdentifier:@"HeaderView"];
- self.yearCollectionView.translatesAutoresizingMaskIntoConstraints = NO;
- self.yearCollectionView.delegate = self;
- self.yearCollectionView.dataSource = self;
- self.yearCollectionView.backgroundColor = [UIColor clearColor];
- self.yearCollectionView.showsVerticalScrollIndicator = YES;
- [self addSubview:self.yearCollectionView];
-
- self.verticalLine = [[UIView alloc] init];
- self.verticalLine.translatesAutoresizingMaskIntoConstraints = NO;
- self.verticalLine.backgroundColor = [BTUIKAppearance sharedInstance].lineColor;
- [self addSubview:self.verticalLine];
-
- NSDictionary *viewBindings = @{@"view":self, @"monthCollectionView":self.monthCollectionView, @"yearCollectionView": self.yearCollectionView, @"verticalLine":self.verticalLine};
-
- NSDictionary *metrics = @{@"BT_EXPIRY_FULL_PADDING":@BT_EXPIRY_FULL_PADDING, @"BT_EXPIRY_FULL_PADDING_HALF": @(BT_EXPIRY_FULL_PADDING/2.0)};
-
-
- [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(BT_EXPIRY_FULL_PADDING_HALF)-[monthCollectionView][verticalLine(0.5)][yearCollectionView]-(BT_EXPIRY_FULL_PADDING_HALF)-|"
- options:0
- metrics:metrics
- views:viewBindings]];
-
- [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(BT_EXPIRY_FULL_PADDING)-[monthCollectionView]"
- options:0
- metrics:metrics
- views:viewBindings]];
-
- [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(BT_EXPIRY_FULL_PADDING)-[yearCollectionView]"
- options:0
- metrics:metrics
- views:viewBindings]];
-
- [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[verticalLine]"
- options:0
- metrics:nil
- views:viewBindings]];
-
- id bottomReferenceView = self;
- if (@available(iOS 11.0, *)) {
- bottomReferenceView = self.safeAreaLayoutGuide;
- }
- [self addConstraint:[NSLayoutConstraint constraintWithItem:self.monthCollectionView
- attribute:NSLayoutAttributeBottom
- relatedBy:0
- toItem:bottomReferenceView
- attribute:NSLayoutAttributeBottom
- multiplier:1
- constant:0]];
- [self addConstraint:[NSLayoutConstraint constraintWithItem:self.yearCollectionView
- attribute:NSLayoutAttributeBottom
- relatedBy:0
- toItem:bottomReferenceView
- attribute:NSLayoutAttributeBottom
- multiplier:1
- constant:0]];
- [self addConstraint:[NSLayoutConstraint constraintWithItem:self.verticalLine
- attribute:NSLayoutAttributeBottom
- relatedBy:0
- toItem:bottomReferenceView
- attribute:NSLayoutAttributeBottom
- multiplier:1
- constant:0]];
-
- [self addConstraint:[NSLayoutConstraint constraintWithItem:self.yearCollectionView
- attribute:NSLayoutAttributeWidth
- relatedBy:0
- toItem:self
- attribute:NSLayoutAttributeWidth
- multiplier:0.33
- constant:0]];
-
- self.autoresizingMask = UIViewAutoresizingFlexibleHeight;
- }
-
- return self;
- }
- #pragma mark - Accessors
- - (void)setSelectedYear:(NSInteger)selectedYear {
- NSString *stringToSearch = [NSString stringWithFormat:@"%@", @(selectedYear)];
- NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF contains[c] %@", stringToSearch];
- NSString *results = [self.years filteredArrayUsingPredicate:predicate].firstObject;
- NSInteger yearIndex = [self.years indexOfObject:results];
- if (([self isValidYear:selectedYear forMonth:self.selectedMonth] && yearIndex != NSNotFound) || selectedYear == 0) {
- _selectedYear = selectedYear;
- if (selectedYear > 0) {
- [self.yearCollectionView selectItemAtIndexPath:[NSIndexPath indexPathForItem:yearIndex inSection:0]
- animated:NO
- scrollPosition:0];
- } else {
- NSIndexPath *selectedIndexPath = [self.yearCollectionView indexPathsForSelectedItems].firstObject;
- [self.yearCollectionView deselectItemAtIndexPath:selectedIndexPath animated:NO];
- }
- [self.monthCollectionView reloadData];
- [self.yearCollectionView reloadData];
- }
- }
- - (void)setSelectedMonth:(NSInteger)selectedMonth {
- if ([self isValidMonth:selectedMonth forYear:self.selectedYear] || selectedMonth == 0) {
- _selectedMonth = selectedMonth;
- if (selectedMonth > 0) {
- [self.monthCollectionView selectItemAtIndexPath:[NSIndexPath indexPathForItem:selectedMonth - 1 inSection:0]
- animated:NO
- scrollPosition:0];
- } else {
- NSIndexPath *selectedIndexPath = [self.monthCollectionView indexPathsForSelectedItems].firstObject;
- [self.monthCollectionView deselectItemAtIndexPath:selectedIndexPath animated:NO];
- }
- [self.monthCollectionView reloadData];
- [self.yearCollectionView reloadData];
- }
- }
- #pragma mark - UICollectionView Datasource
- - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(__unused NSInteger)section {
- if (collectionView == self.monthCollectionView) {
- return self.months.count;
- } else {
- return self.years.count;
- }
- }
- - (NSInteger)numberOfSectionsInCollectionView: (__unused UICollectionView *)collectionView {
- return 1;
- }
- - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
- BTUIKExpiryInputCollectionViewCell *cell;
- BOOL isDisabled = NO;
- if (collectionView == self.monthCollectionView) {
- cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"BTMonthCell" forIndexPath:indexPath];
- cell.label.text = self.months[indexPath.row];
- cell.selected = [cell getInteger] == self.selectedMonth;
- isDisabled = self.selectedYear && self.selectedYear == self.currentYear && [cell getInteger] < self.currentMonth;
- } else {
- cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"BTYearCell" forIndexPath:indexPath];
- cell.label.text = self.years[indexPath.row];
- cell.selected = [cell getInteger] == self.selectedYear;
- isDisabled = self.selectedMonth && self.selectedMonth < self.currentMonth && [cell getInteger] == self.currentYear;
- }
-
- if (isDisabled) {
- cell.userInteractionEnabled = NO;
- cell.label.textColor = [BTUIKAppearance sharedInstance].disabledColor;
- } else {
- cell.userInteractionEnabled = YES;
- cell.label.textColor = [BTUIKAppearance sharedInstance].primaryTextColor;
- }
-
- return cell;
- }
- - (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView
- viewForSupplementaryElementOfKind:(__unused NSString *)kind
- atIndexPath:(NSIndexPath *)indexPath {
- BTUIKCollectionReusableView *view = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader
- withReuseIdentifier:@"HeaderView"
- forIndexPath:indexPath];
- view.label.text = collectionView == self.yearCollectionView ? BTUIKLocalizedString(YEAR_LABEL) : BTUIKLocalizedString(MONTH_LABEL);
- return view;
- }
- - (CGSize)collectionView:(__unused UICollectionView *)collectionView
- layout:(__unused UICollectionViewLayout *)collectionViewLayout
- referenceSizeForHeaderInSection:(__unused NSInteger)section {
- return CGSizeMake(100, BT_EXPIRY_SECTION_HEADER_HEIGHT);
- }
- #pragma mark - UICollectionViewDelegate
- - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
- BTUIKExpiryInputCollectionViewCell *cell = (BTUIKExpiryInputCollectionViewCell*)[collectionView cellForItemAtIndexPath:indexPath];
- if (collectionView == self.yearCollectionView) {
- _selectedYear = [cell getInteger];
- // If a year is selected first, select a month that is valid for that year
- if (self.selectedMonth == 0) {
- _selectedMonth = 12;
- }
- } else {
- _selectedMonth = [cell getInteger];
- }
- [self.delegate expiryInputViewDidChange:self];
-
- [self.monthCollectionView reloadData];
- [self.yearCollectionView reloadData];
- }
- - (BOOL)isValidYear:(NSInteger)year forMonth:(NSInteger)month {
- if (month == 0) {
- return YES;
- } else if (month < self.currentMonth && year <= self.currentYear) {
- return NO;
- } else if (month > 12 || year < self.currentYear) {
- return NO;
- }
- return YES;
- }
- - (BOOL)isValidMonth:(NSInteger)month forYear:(NSInteger)year {
- if (year == 0) {
- return YES;
- } else if (month < self.currentMonth && year <= self.currentYear) {
- return NO;
- } else if (month > 12) {
- return NO;
- }
- return YES;
- }
- #pragma mark – UICollectionViewDelegateFlowLayout
- - (CGSize)collectionView:(UICollectionView *)collectionView
- layout:(__unused UICollectionViewLayout *)collectionViewLayout
- sizeForItemAtIndexPath:(__unused NSIndexPath *)indexPath {
- BOOL isLandscape = [BTUIKViewUtil isOrientationLandscape];
- int monthRows = isLandscape ? 3.0 : 4.0;
-
- CGFloat cellHeight = (CGRectGetHeight(self.monthCollectionView.frame) - BT_EXPIRY_SECTION_HEADER_HEIGHT - ((BT_EXPIRY_FULL_PADDING * monthRows) + BT_EXPIRY_FULL_PADDING)) / monthRows;
-
- if (self.monthCollectionView == collectionView) {
- int monthCols = isLandscape ? 4.0 : 3.0;
- CGFloat monthCellWidth = (CGRectGetWidth(self.monthCollectionView.frame) - ((BT_EXPIRY_FULL_PADDING * monthCols) + BT_EXPIRY_FULL_PADDING * 2.0)) / monthCols;
- return CGSizeMake(monthCellWidth, cellHeight);
- } else {
- int yearCols = isLandscape ? 2.0 : 1.0;
- CGFloat yearCellWidth = (CGRectGetWidth(self.yearCollectionView.frame) - ((BT_EXPIRY_FULL_PADDING * yearCols) + BT_EXPIRY_FULL_PADDING * 2.0)) / yearCols;
- return CGSizeMake(yearCellWidth, cellHeight);
- }
- }
- - (UIEdgeInsets)collectionView:(__unused UICollectionView *)collectionView
- layout:(__unused UICollectionViewLayout*)collectionViewLayout
- insetForSectionAtIndex:(__unused NSInteger)section {
- return UIEdgeInsetsMake(BT_EXPIRY_FULL_PADDING, BT_EXPIRY_FULL_PADDING, BT_EXPIRY_FULL_PADDING, BT_EXPIRY_FULL_PADDING);
- }
- #pragma mark - Layout
- - (void)layoutSubviews {
- [super layoutSubviews];
- if (self.window != nil) {
- [self.monthCollectionView.collectionViewLayout invalidateLayout];
- [self.yearCollectionView.collectionViewLayout invalidateLayout];
- [self.yearCollectionView flashScrollIndicators];
- }
- }
- @end
|