/* Copyright 2024 New Vector Ltd. Copyright 2017 Vector Creations Ltd SPDX-License-Identifier: AGPL-3.0-only Please see LICENSE in the repository root for full details. */ #import "MXKCountryPickerViewController.h" @import libPhoneNumber_iOS; #import "NSBundle+MatrixKit.h" #import "MXKSwiftHeader.h" NSString* const kMXKCountryPickerViewControllerCountryCellId = @"kMXKCountryPickerViewControllerCountryCellId"; @interface MXKCountryPickerViewController () { NSMutableDictionary *isoCountryCodesByCountryName; NSArray *countryNames; NSMutableArray *filteredCountryNames; NSString *previousSearchPattern; NSMutableDictionary *callingCodesByCountryName; } @end @implementation MXKCountryPickerViewController #pragma mark - Class methods + (UINib *)nib { return [UINib nibWithNibName:NSStringFromClass([MXKCountryPickerViewController class]) bundle:[NSBundle bundleForClass:[MXKCountryPickerViewController class]]]; } + (instancetype)countryPickerViewController { return [[[self class] alloc] initWithNibName:NSStringFromClass([MXKCountryPickerViewController class]) bundle:[NSBundle bundleForClass:[MXKCountryPickerViewController class]]]; } - (void)finalizeInit { [super finalizeInit]; NSArray *isoCountryCodes = [NSLocale ISOCountryCodes]; NSMutableArray *countries; isoCountryCodesByCountryName = [NSMutableDictionary dictionaryWithCapacity:isoCountryCodes.count]; countries = [NSMutableArray arrayWithCapacity:isoCountryCodes.count]; NSLocale *local = [[NSLocale alloc] initWithLocaleIdentifier:[[[NSBundle mainBundle] preferredLocalizations] objectAtIndex:0]]; for (NSString *isoCountryCode in isoCountryCodes) { NSString *country = [local displayNameForKey:NSLocaleCountryCode value:isoCountryCode]; if (country) { [countries addObject: country]; isoCountryCodesByCountryName[country] = isoCountryCode; } } countryNames = [countries sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; previousSearchPattern = nil; filteredCountryNames = nil; _showCountryCallingCode = NO; } - (void)destroy { [super destroy]; isoCountryCodesByCountryName = nil; countryNames = nil; filteredCountryNames = nil; callingCodesByCountryName = nil; previousSearchPattern = nil; } - (void)viewDidLoad { [super viewDidLoad]; // Check whether the view controller has been pushed via storyboard if (!self.tableView) { // Instantiate view controller objects [[[self class] nib] instantiateWithOwner:self options:nil]; } self.navigationItem.title = [VectorL10n countryPickerTitle]; [self setupSearchController]; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; self.navigationItem.hidesSearchBarWhenScrolling = YES; } #pragma mark - - (void)setShowCountryCallingCode:(BOOL)showCountryCallingCode { if (_showCountryCallingCode != showCountryCallingCode) { _showCountryCallingCode = showCountryCallingCode; if (_showCountryCallingCode && !callingCodesByCountryName) { callingCodesByCountryName = [NSMutableDictionary dictionary]; for (NSString *countryName in countryNames) { NSString *isoCountryCode = isoCountryCodesByCountryName[countryName]; NSNumber *callingCode = [[NBPhoneNumberUtil sharedInstance] getCountryCodeForRegion:isoCountryCode]; callingCodesByCountryName[countryName] = callingCode; } } [self.tableView reloadData]; } } #pragma mark - Private - (void)setupSearchController { UISearchController *searchController = [[UISearchController alloc] initWithSearchResultsController:nil]; searchController.obscuresBackgroundDuringPresentation = NO; searchController.hidesNavigationBarDuringPresentation = NO; searchController.searchResultsUpdater = self; self.navigationItem.searchController = searchController; // Make the search bar visible on first view appearance self.navigationItem.hidesSearchBarWhenScrolling = NO; self.definesPresentationContext = YES; self.searchController = searchController; } #pragma mark - UITableView dataSource - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { if (filteredCountryNames) { return filteredCountryNames.count; } return countryNames.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:kMXKCountryPickerViewControllerCountryCellId]; if (!cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:kMXKCountryPickerViewControllerCountryCellId]; } NSInteger index = indexPath.row; NSString *countryName; if (filteredCountryNames) { if (index < filteredCountryNames.count) { countryName = filteredCountryNames[index]; } } else if (index < countryNames.count) { countryName = countryNames[index]; } if (countryName) { cell.textLabel.text = countryName; if (self.showCountryCallingCode) { cell.detailTextLabel.text = [NSString stringWithFormat:@"+%@", [callingCodesByCountryName[countryName] stringValue]]; } } return cell; } #pragma mark - UITableView delegate - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:YES]; if (self.delegate) { NSInteger index = indexPath.row; NSString *countryName; if (filteredCountryNames) { if (index < filteredCountryNames.count) { countryName = filteredCountryNames[index]; } } else if (index < countryNames.count) { countryName = countryNames[index]; } if (countryName) { NSString *isoCountryCode = isoCountryCodesByCountryName[countryName]; [self.delegate countryPickerViewController:self didSelectCountry:isoCountryCode]; } } } #pragma mark - UISearchResultsUpdating - (void)updateSearchResultsForSearchController:(UISearchController *)searchController { NSString *searchText = searchController.searchBar.text; if (searchText.length) { searchText = [searchText lowercaseString]; if (previousSearchPattern && [searchText hasPrefix:previousSearchPattern]) { for (NSUInteger index = 0; index < filteredCountryNames.count;) { NSString *countryName = [filteredCountryNames[index] lowercaseString]; if ([countryName hasPrefix:searchText] == NO) { [filteredCountryNames removeObjectAtIndex:index]; } else { index++; } } } else { filteredCountryNames = [NSMutableArray array]; for (NSUInteger index = 0; index < countryNames.count; index++) { NSString *countryName = [countryNames[index] lowercaseString]; if ([countryName hasPrefix:searchText]) { [filteredCountryNames addObject:countryNames[index]]; } } } previousSearchPattern = searchText; } else { previousSearchPattern = nil; filteredCountryNames = nil; } [self.tableView reloadData]; } @end