diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 082e72e541..e31935c540 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -645,6 +645,7 @@ 5073EACF2C4F469A001FBB3E /* CallLinkFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5073EACE2C4F469A001FBB3E /* CallLinkFetcher.swift */; }; 5075C21729CA1EE700A260D2 /* GroupMemberUpdaterTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5075C21629CA1EE700A260D2 /* GroupMemberUpdaterTest.swift */; }; 5077B5B82BBC7FE600EF399E /* ContactTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5077B5B72BBC7FE600EF399E /* ContactTest.swift */; }; + 50791B1D2D037A9800D747F8 /* PhoneNumberCountryTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50791B1C2D037A9800D747F8 /* PhoneNumberCountryTest.swift */; }; 507B69112C503FA800F1C6D7 /* CallLinkTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50552C302BAC079A00815474 /* CallLinkTest.swift */; }; 507B69122C5044F800F1C6D7 /* LinkPreviewGroupLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34A95517271B510400B05242 /* LinkPreviewGroupLink.swift */; }; 507CD5E529660D5100E47DAC /* ServiceId.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507CD5E429660D5100E47DAC /* ServiceId.swift */; }; @@ -4392,6 +4393,7 @@ 5073EACE2C4F469A001FBB3E /* CallLinkFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = CallLinkFetcher.swift; path = SignalUI/Calls/CallLinkFetcher.swift; sourceTree = SOURCE_ROOT; }; 5075C21629CA1EE700A260D2 /* GroupMemberUpdaterTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupMemberUpdaterTest.swift; sourceTree = ""; }; 5077B5B72BBC7FE600EF399E /* ContactTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactTest.swift; sourceTree = ""; }; + 50791B1C2D037A9800D747F8 /* PhoneNumberCountryTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhoneNumberCountryTest.swift; sourceTree = ""; }; 507CD5E429660D5100E47DAC /* ServiceId.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceId.swift; sourceTree = ""; }; 507D614B2BE433EE00DA7BA3 /* be */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = be; path = translations/be.lproj/InfoPlist.strings; sourceTree = ""; }; 507D614C2BE433EE00DA7BA3 /* be */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = be; path = translations/be.lproj/Localizable.strings; sourceTree = ""; }; @@ -8663,6 +8665,14 @@ path = GroupMembers; sourceTree = ""; }; + 50791B1B2D037A7800D747F8 /* RecipientPickers */ = { + isa = PBXGroup; + children = ( + 50791B1C2D037A9800D747F8 /* PhoneNumberCountryTest.swift */, + ); + path = RecipientPickers; + sourceTree = ""; + }; 50A76F512AF565A300FCF02D /* Preconditions */ = { isa = PBXGroup; children = ( @@ -10599,6 +10609,7 @@ 3471210D25ED5F850037CD1F /* Payments */, 66CDB75A2AFC42B6009A36EC /* Provisioning */, D99ABC712A3D0BAA0034CD3B /* QRCodes */, + 50791B1B2D037A7800D747F8 /* RecipientPickers */, 661278052996BA6700A1D5A1 /* Registration */, 4C3EF8002109184A0007EBF7 /* SSKTests */, E75DD3DC2810CD3500E32C36 /* subscriptions */, @@ -16710,6 +16721,7 @@ 3452851D26DFD12300824983 /* PaymentsFormatTest.swift in Sources */, 3471211025ED5F910037CD1F /* PaymentsReconciliationTest.swift in Sources */, 346EFC3225FD051400F493C7 /* PaymentsTest.swift in Sources */, + 50791B1D2D037A9800D747F8 /* PhoneNumberCountryTest.swift in Sources */, 4C5250D421E7C51900CE3D95 /* PhoneNumberValidatorTest.swift in Sources */, 66CDB7602AFC45CF009A36EC /* ProvisioningCoordinator+Mocks.swift in Sources */, 66CDB75D2AFC42FC009A36EC /* ProvisioningCoordinatorTest.swift in Sources */, diff --git a/Signal/test/RecipientPickers/PhoneNumberCountryTest.swift b/Signal/test/RecipientPickers/PhoneNumberCountryTest.swift new file mode 100644 index 0000000000..64bfe9f652 --- /dev/null +++ b/Signal/test/RecipientPickers/PhoneNumberCountryTest.swift @@ -0,0 +1,52 @@ +// +// Copyright 2024 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only +// + +import Foundation +import XCTest + +@testable import SignalUI + +final class PhoneNumberCountryTest: XCTestCase { + func testCountryCodesForSearchTerm() { + func countryCodes(forSearchTerm searchTerm: String?) -> [String] { + return PhoneNumberCountry.buildCountries(searchText: searchTerm).map(\.countryCode) + } + // Empty search. + XCTAssertGreaterThan(countryCodes(forSearchTerm: nil).count, 30) + XCTAssertGreaterThan(countryCodes(forSearchTerm: "").count, 30) + XCTAssertGreaterThan(countryCodes(forSearchTerm: " ").count, 30) + + // Searches with no results. + XCTAssertEqual(countryCodes(forSearchTerm: " . ").count, 0) + XCTAssertEqual(countryCodes(forSearchTerm: " XXXXX ").count, 0) + XCTAssertEqual(countryCodes(forSearchTerm: " ! ").count, 0) + + // Search by country code. + XCTAssertEqual(countryCodes(forSearchTerm: "GB"), ["GB"]) + XCTAssertEqual(countryCodes(forSearchTerm: "gb"), ["GB"]) + XCTAssertEqual(countryCodes(forSearchTerm: "GB "), ["GB"]) + XCTAssertEqual(countryCodes(forSearchTerm: " GB"), ["GB"]) + XCTAssert(countryCodes(forSearchTerm: " G").contains("GB")) + XCTAssertFalse(countryCodes(forSearchTerm: " B").contains("GB")) + + // Search by country name. + XCTAssertEqual(countryCodes(forSearchTerm: "united kingdom"), ["GB"]) + XCTAssertEqual(countryCodes(forSearchTerm: " UNITED KINGDOM "), ["GB"]) + XCTAssertEqual(countryCodes(forSearchTerm: " UNITED KING "), ["GB"]) + XCTAssertEqual(countryCodes(forSearchTerm: " UNI KING "), ["GB"]) + XCTAssertEqual(countryCodes(forSearchTerm: " u k "), ["GB"]) + XCTAssert(countryCodes(forSearchTerm: " u").contains("GB")) + XCTAssert(countryCodes(forSearchTerm: " k").contains("GB")) + XCTAssertFalse(countryCodes(forSearchTerm: " m").contains("GB")) + + // Search by calling code. + XCTAssert(countryCodes(forSearchTerm: " +44 ").contains("GB")) + XCTAssert(countryCodes(forSearchTerm: " 44 ").contains("GB")) + XCTAssert(countryCodes(forSearchTerm: " +4 ").contains("GB")) + XCTAssert(countryCodes(forSearchTerm: " 4 ").contains("GB")) + XCTAssertFalse(countryCodes(forSearchTerm: " +123 ").contains("GB")) + XCTAssertFalse(countryCodes(forSearchTerm: " +444 ").contains("GB")) + } +} diff --git a/SignalServiceKit/Contacts/PhoneNumberUtil.swift b/SignalServiceKit/Contacts/PhoneNumberUtil.swift index d7bbf15bcd..f4e029797f 100644 --- a/SignalServiceKit/Contacts/PhoneNumberUtil.swift +++ b/SignalServiceKit/Contacts/PhoneNumberUtil.swift @@ -107,54 +107,36 @@ public class PhoneNumberUtil: NSObject { } extension PhoneNumberUtil { - // country code -> calling code - public func plusPrefixedCallingCode(fromCountryCode countryCode: String) -> String? { - guard let countryCode = countryCode.nilIfEmpty else { - return "+0" + /// Returns calling codes for libPhoneNumber-unsupported country codes. + /// + /// These are country codes that NSLocale.isoCountryCodes contains but + /// libPhoneNumber doesn't support. In every case, these countries share a + /// calling code with a country that libPhoneNumber *does* support. We show + /// these unsupported countries in the UI and convert them to a supported + /// country when parsing the number. + public static func callingCodeForUnsupportedCountryCode(_ countryCode: String) -> Int? { + switch countryCode { + case "AQ": /* Antarctica */ return 672 + case "BV": /* Bouvet Island */ return 55 + case "IC": /* Canary Islands */ return 34 + case "EA": /* Ceuta & Melilla */ return 34 + case "DG": /* Diego Garcia */ return 246 + case "TF": /* French Southern Territories */ return 262 + case "HM": /* Heard & McDonald Islands */ return 672 + case "PN": /* Pitcairn Islands */ return 64 + case "CQ": /* Sark */ return 44 + case "GS": /* So. Georgia & So. Sandwich Isl. */ return 500 + case "UM": /* U.S. Outlying Islands */ return 1 + default: return nil } + } - if countryCode == "AQ" { - // Antarctica - return "+672" - } else if countryCode == "BV" { - // Bouvet Island - return "+55" - } else if countryCode == "IC" { - // Canary Islands - return "+34" - } else if countryCode == "EA" { - // Ceuta & Melilla - return "+34" - } else if countryCode == "CP" { - // Clipperton Island - // - // This country code should be filtered - it does not appear to have a calling code. - return nil - } else if countryCode == "DG" { - // Diego Garcia - return "+246" - } else if countryCode == "TF" { - // French Southern Territories - return "+262" - } else if countryCode == "HM" { - // Heard & McDonald Islands - return "+672" - } else if countryCode == "XK" { - // Kosovo - return "+383" - } else if countryCode == "PN" { - // Pitcairn Islands - return "+64" - } else if countryCode == "GS" { - // So. Georgia & So. Sandwich Isl. - return "+500" - } else if countryCode == "UM" { - // U.S. Outlying Islands - return "+1" + public func countryCodeForParsing(fromCountryCode countryCode: String) -> String { + if let callingCode = Self.callingCodeForUnsupportedCountryCode(countryCode) { + // Force unwrap is covered by unit tests. + return getFilteredRegionCodeForCallingCode(callingCode)! } - - let callingCode = getCallingCode(forRegion: countryCode) - return PhoneNumber.countryCodePrefix + "\(callingCode)" + return countryCode } public static func defaultCountryCode() -> String { @@ -245,52 +227,9 @@ extension PhoneNumberUtil { return try? format(phoneNumber.nbPhoneNumber, numberFormat: .NATIONAL) } - private class func does(_ string: String, matchQuery query: String) -> Bool { - let searchOptions: String.CompareOptions = [.caseInsensitive, .anchored] - - let stringTokens = string.components(separatedBy: .whitespaces) - let queryTokens = query.components(separatedBy: .whitespaces) - - return queryTokens.allSatisfy { queryToken in - if queryToken.isEmpty { - return true - } - return stringTokens.contains { stringToken in - stringToken.range(of: queryToken, options: searchOptions) != nil - } - } - } - - /// Get country codes from a search term. - public func countryCodes(forSearchTerm searchTerm: String?) -> [String] { - let cleanedSearch = (searchTerm ?? "").trimmingCharacters(in: .whitespacesAndNewlines) - - let codes = NSLocale.isoCountryCodes.filter { countryCode in - guard - let callingCode = plusPrefixedCallingCode(fromCountryCode: countryCode), - callingCode != "+0" - else { - return false - } - let countryName = Self.countryName(fromCountryCode: countryCode) - return ( - cleanedSearch.isEmpty || - Self.does(countryName, matchQuery: cleanedSearch) || - Self.does(countryCode, matchQuery: cleanedSearch) || - callingCode.contains(cleanedSearch) - ) - } - - return codes.sorted { lhs, rhs in - let lhsCountry = Self.countryName(fromCountryCode: lhs) - let rhsCountry = Self.countryName(fromCountryCode: rhs) - return lhsCountry.localizedCaseInsensitiveCompare(rhsCountry) == .orderedAscending - } - } - /// Convert country code to country name. - public class func countryName(fromCountryCode countryCode: String) -> String { - lazy var unknownValue = OWSLocalizedString( + public static func countryName(fromCountryCode countryCode: String) -> String { + lazy var unknownValue = OWSLocalizedString( "UNKNOWN_VALUE", comment: "Indicates an unknown or unrecognizable value." ) @@ -331,7 +270,10 @@ extension PhoneNumberUtil { } public func parsePhoneNumber(countryCode: String, nationalNumber: String) -> PhoneNumber? { - return _parsePhoneNumber(filteredValue: nationalNumber.filteredAsE164, countryCode: countryCode) + return _parsePhoneNumber( + filteredValue: nationalNumber.filteredAsE164, + countryCode: countryCodeForParsing(fromCountryCode: countryCode) + ) } public func parsePhoneNumbers(userSpecifiedText: String, localPhoneNumber: String?) -> [PhoneNumber] { diff --git a/SignalServiceKit/tests/Contacts/PhoneNumberUtilTest.swift b/SignalServiceKit/tests/Contacts/PhoneNumberUtilTest.swift index 8a7ccb5fee..a9c75cf435 100644 --- a/SignalServiceKit/tests/Contacts/PhoneNumberUtilTest.swift +++ b/SignalServiceKit/tests/Contacts/PhoneNumberUtilTest.swift @@ -15,17 +15,30 @@ class PhoneNumberUtilTestSwift: XCTestCase { self.phoneNumberUtilRef = PhoneNumberUtil() } + func testCountryCodeForParsing() { + let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + for ch1 in alphabet { + for ch2 in alphabet { + _ = self.phoneNumberUtilRef.countryCodeForParsing(fromCountryCode: String(ch1) + String(ch2)) + } + } + } + func test_callingCodeFromCountryCode() { - XCTAssertEqual("+1", phoneNumberUtilRef.plusPrefixedCallingCode(fromCountryCode: "US")) - XCTAssertEqual("+44", phoneNumberUtilRef.plusPrefixedCallingCode(fromCountryCode: "GB")) - XCTAssertEqual("+598", phoneNumberUtilRef.plusPrefixedCallingCode(fromCountryCode: "UY")) - XCTAssertEqual("+0", phoneNumberUtilRef.plusPrefixedCallingCode(fromCountryCode: "QG")) - XCTAssertEqual("+0", phoneNumberUtilRef.plusPrefixedCallingCode(fromCountryCode: "EK")) - XCTAssertEqual("+0", phoneNumberUtilRef.plusPrefixedCallingCode(fromCountryCode: "ZZZ")) - XCTAssertEqual("+0", phoneNumberUtilRef.plusPrefixedCallingCode(fromCountryCode: "")) - XCTAssertEqual("+0", phoneNumberUtilRef.plusPrefixedCallingCode(fromCountryCode: "+")) - XCTAssertEqual("+0", phoneNumberUtilRef.plusPrefixedCallingCode(fromCountryCode: "9")) - XCTAssertEqual("+1", phoneNumberUtilRef.plusPrefixedCallingCode(fromCountryCode: "US ")) + func plusPrefixedCallingCode(fromCountryCode countryCode: String) -> String { + let callingCode = phoneNumberUtilRef.getCallingCode(forRegion: countryCode) + return "+\(callingCode)" + } + XCTAssertEqual("+1", plusPrefixedCallingCode(fromCountryCode: "US")) + XCTAssertEqual("+44", plusPrefixedCallingCode(fromCountryCode: "GB")) + XCTAssertEqual("+598", plusPrefixedCallingCode(fromCountryCode: "UY")) + XCTAssertEqual("+0", plusPrefixedCallingCode(fromCountryCode: "QG")) + XCTAssertEqual("+0", plusPrefixedCallingCode(fromCountryCode: "EK")) + XCTAssertEqual("+0", plusPrefixedCallingCode(fromCountryCode: "ZZZ")) + XCTAssertEqual("+0", plusPrefixedCallingCode(fromCountryCode: "")) + XCTAssertEqual("+0", plusPrefixedCallingCode(fromCountryCode: "+")) + XCTAssertEqual("+0", plusPrefixedCallingCode(fromCountryCode: "9")) + XCTAssertEqual("+1", plusPrefixedCallingCode(fromCountryCode: "US ")) } func test_examplePhoneNumberForCountryCode() { @@ -58,44 +71,6 @@ class PhoneNumberUtilTestSwift: XCTestCase { XCTAssertEqual(0, phoneNumberUtilRef.getCallingCode(forRegion: "ZQ")) } - func testCountryCodesForSearchTerm() { - // Empty search. - XCTAssertGreaterThan(phoneNumberUtilRef.countryCodes(forSearchTerm: nil).count, 30) - XCTAssertGreaterThan(phoneNumberUtilRef.countryCodes(forSearchTerm: "").count, 30) - XCTAssertGreaterThan(phoneNumberUtilRef.countryCodes(forSearchTerm: " ").count, 30) - - // Searches with no results. - XCTAssertEqual(phoneNumberUtilRef.countryCodes(forSearchTerm: " . ").count, 0) - XCTAssertEqual(phoneNumberUtilRef.countryCodes(forSearchTerm: " XXXXX ").count, 0) - XCTAssertEqual(phoneNumberUtilRef.countryCodes(forSearchTerm: " ! ").count, 0) - - // Search by country code. - XCTAssertEqual(phoneNumberUtilRef.countryCodes(forSearchTerm: "GB"), ["GB"]) - XCTAssertEqual(phoneNumberUtilRef.countryCodes(forSearchTerm: "gb"), ["GB"]) - XCTAssertEqual(phoneNumberUtilRef.countryCodes(forSearchTerm: "GB "), ["GB"]) - XCTAssertEqual(phoneNumberUtilRef.countryCodes(forSearchTerm: " GB"), ["GB"]) - XCTAssert(phoneNumberUtilRef.countryCodes(forSearchTerm: " G").contains("GB")) - XCTAssertFalse(phoneNumberUtilRef.countryCodes(forSearchTerm: " B").contains("GB")) - - // Search by country name. - XCTAssertEqual(phoneNumberUtilRef.countryCodes(forSearchTerm: "united kingdom"), ["GB"]) - XCTAssertEqual(phoneNumberUtilRef.countryCodes(forSearchTerm: " UNITED KINGDOM "), ["GB"]) - XCTAssertEqual(phoneNumberUtilRef.countryCodes(forSearchTerm: " UNITED KING "), ["GB"]) - XCTAssertEqual(phoneNumberUtilRef.countryCodes(forSearchTerm: " UNI KING "), ["GB"]) - XCTAssertEqual(phoneNumberUtilRef.countryCodes(forSearchTerm: " u k "), ["GB"]) - XCTAssert(phoneNumberUtilRef.countryCodes(forSearchTerm: " u").contains("GB")) - XCTAssert(phoneNumberUtilRef.countryCodes(forSearchTerm: " k").contains("GB")) - XCTAssertFalse(phoneNumberUtilRef.countryCodes(forSearchTerm: " m").contains("GB")) - - // Search by calling code. - XCTAssert(phoneNumberUtilRef.countryCodes(forSearchTerm: " +44 ").contains("GB")) - XCTAssert(phoneNumberUtilRef.countryCodes(forSearchTerm: " 44 ").contains("GB")) - XCTAssert(phoneNumberUtilRef.countryCodes(forSearchTerm: " +4 ").contains("GB")) - XCTAssert(phoneNumberUtilRef.countryCodes(forSearchTerm: " 4 ").contains("GB")) - XCTAssertFalse(phoneNumberUtilRef.countryCodes(forSearchTerm: " +123 ").contains("GB")) - XCTAssertFalse(phoneNumberUtilRef.countryCodes(forSearchTerm: " +444 ").contains("GB")) - } - func testTranslateCursorPosition() { XCTAssertEqual(0, PhoneNumberUtil.translateCursorPosition(0, from: "", to: "", stickingRightward: true)) diff --git a/SignalUI/RecipientPickers/PhoneNumberCountry.swift b/SignalUI/RecipientPickers/PhoneNumberCountry.swift index 34e181426f..2e8aa6b049 100644 --- a/SignalUI/RecipientPickers/PhoneNumberCountry.swift +++ b/SignalUI/RecipientPickers/PhoneNumberCountry.swift @@ -33,9 +33,60 @@ public struct PhoneNumberCountry: Equatable { // MARK: - + private static func bestEffortCallingCode(fromCountryCode countryCode: String) -> Int? { + if let result = PhoneNumberUtil.callingCodeForUnsupportedCountryCode(countryCode) { + return result + } + let result = SSKEnvironment.shared.phoneNumberUtilRef.getCallingCode(forRegion: countryCode) + return result == 0 ? nil : result + } + + private static func does(_ string: String, matchQuery query: String) -> Bool { + let searchOptions: String.CompareOptions = [.caseInsensitive, .anchored] + + let stringTokens = string.components(separatedBy: .whitespaces) + let queryTokens = query.components(separatedBy: .whitespaces) + + return queryTokens.allSatisfy { queryToken in + if queryToken.isEmpty { + return true + } + return stringTokens.contains { stringToken in + stringToken.range(of: queryToken, options: searchOptions) != nil + } + } + } + + /// Get country codes from a search term. + private static func countryCodes(forSearchTerm searchTerm: String?) -> [String] { + let cleanedSearch = (searchTerm ?? "").trimmingCharacters(in: .whitespacesAndNewlines) + + var countryCodesAndNames = NSLocale.isoCountryCodes.compactMap { countryCode -> (countryCode: String, countryName: String)? in + guard let callingCode = bestEffortCallingCode(fromCountryCode: countryCode) else { + // Clipperton Island is filtered intentionally. + owsAssertDebug(countryCode == "CP") + return nil + } + let countryName = PhoneNumberUtil.countryName(fromCountryCode: countryCode) + let isMatch = ( + cleanedSearch.isEmpty || + Self.does(countryName, matchQuery: cleanedSearch) || + Self.does(countryCode, matchQuery: cleanedSearch) || + "+\(callingCode)".contains(cleanedSearch) + ) + return isMatch ? (countryCode, countryName) : nil + } + + countryCodesAndNames.sort(by: { lhs, rhs in + return lhs.countryName.localizedCaseInsensitiveCompare(rhs.countryName) == .orderedAscending + }) + + return countryCodesAndNames.map(\.countryCode) + } + public static func buildCountries(searchText: String?) -> [PhoneNumberCountry] { let searchText = searchText?.strippedOrNil - let countryCodes: [String] = SSKEnvironment.shared.phoneNumberUtilRef.countryCodes(forSearchTerm: searchText) + let countryCodes: [String] = countryCodes(forSearchTerm: searchText) return PhoneNumberCountry.buildCountries(forCountryCodes: countryCodes) } @@ -50,11 +101,11 @@ public struct PhoneNumberCountry: Equatable { } public static func buildCountry(forCountryCode countryCode: String) -> PhoneNumberCountry? { - guard let plusPrefixedCallingCode = SSKEnvironment.shared.phoneNumberUtilRef.plusPrefixedCallingCode(fromCountryCode: countryCode) else { + guard let callingCode = bestEffortCallingCode(fromCountryCode: countryCode) else { owsFailDebug("Invalid countryCode.") return nil } - return buildCountry(countryCode: countryCode, plusPrefixedCallingCode: plusPrefixedCallingCode) + return buildCountry(countryCode: countryCode, plusPrefixedCallingCode: "+\(callingCode)") } public static func buildCountry(forCallingCode callingCode: Int) -> PhoneNumberCountry? { @@ -68,17 +119,9 @@ public struct PhoneNumberCountry: Equatable { return buildCountry(countryCode: countryCode, plusPrefixedCallingCode: "+\(callingCode)") } - private static func buildCountry(countryCode: String, plusPrefixedCallingCode: String) -> PhoneNumberCountry? { - guard let countryName = PhoneNumberUtil.countryName(fromCountryCode: countryCode).strippedOrNil else { - owsFailDebug("Invalid countryName.") - return nil - } - guard plusPrefixedCallingCode != "+0" else { - owsFailDebug("Invalid callingCode.") - return nil - } + private static func buildCountry(countryCode: String, plusPrefixedCallingCode: String) -> PhoneNumberCountry { return PhoneNumberCountry( - countryName: countryName, + countryName: PhoneNumberUtil.countryName(fromCountryCode: countryCode), plusPrefixedCallingCode: plusPrefixedCallingCode, countryCode: countryCode )