From 360e826b25a1a30b0112b2843ae2cb9bdd0913bd Mon Sep 17 00:00:00 2001 From: Bobby Sudekum Date: Tue, 27 Feb 2018 17:12:45 -0800 Subject: [PATCH 01/11] Add abbreviations --- MapboxNavigation/Abbreviations.swift | 60 +- MapboxNavigation/InstructionPresenter.swift | 14 +- MapboxNavigation/InstructionsBannerView.swift | 5 +- MapboxNavigation/NextBannerView.swift | 2 +- .../Base.lproj/Abbreviations.csv.plist | 81 -- .../Resources/Base.lproj/Abbreviations.plist | 153 --- .../bg.lproj/Abbreviations.csv.plist | 79 -- .../Resources/bg.lproj/Abbreviations.plist | 135 -- .../ca.lproj/Abbreviations.csv.plist | 112 -- .../Resources/ca.lproj/Abbreviations.plist | 213 --- .../da.lproj/Abbreviations.csv.plist | 42 - .../Resources/da.lproj/Abbreviations.plist | 75 -- .../es.lproj/Abbreviations.csv.plist | 53 - .../Resources/es.lproj/Abbreviations.plist | 97 -- .../fr.lproj/Abbreviations.csv.plist | 656 ---------- .../Resources/fr.lproj/Abbreviations.plist | 1139 ----------------- .../lt.lproj/Abbreviations.csv.plist | 63 - .../Resources/lt.lproj/Abbreviations.plist | 109 -- .../nl.lproj/Abbreviations.csv.plist | 77 -- .../Resources/nl.lproj/Abbreviations.plist | 91 -- .../Resources/pt-BR.lproj/Abbreviations.plist | 153 --- .../ru.lproj/Abbreviations.csv.plist | 35 - .../Resources/ru.lproj/Abbreviations.plist | 61 - .../sv.lproj/Abbreviations.csv.plist | 24 - .../Resources/sv.lproj/Abbreviations.plist | 39 - .../vi.lproj/Abbreviations.csv.plist | 58 - .../Resources/vi.lproj/Abbreviations.plist | 105 -- MapboxNavigation/StepsViewController.swift | 2 +- MapboxNavigation/Waypoint.swift | 2 +- 29 files changed, 20 insertions(+), 3715 deletions(-) delete mode 100644 MapboxNavigation/Resources/Base.lproj/Abbreviations.csv.plist delete mode 100644 MapboxNavigation/Resources/Base.lproj/Abbreviations.plist delete mode 100644 MapboxNavigation/Resources/bg.lproj/Abbreviations.csv.plist delete mode 100644 MapboxNavigation/Resources/bg.lproj/Abbreviations.plist delete mode 100644 MapboxNavigation/Resources/ca.lproj/Abbreviations.csv.plist delete mode 100644 MapboxNavigation/Resources/ca.lproj/Abbreviations.plist delete mode 100644 MapboxNavigation/Resources/da.lproj/Abbreviations.csv.plist delete mode 100644 MapboxNavigation/Resources/da.lproj/Abbreviations.plist delete mode 100644 MapboxNavigation/Resources/es.lproj/Abbreviations.csv.plist delete mode 100644 MapboxNavigation/Resources/es.lproj/Abbreviations.plist delete mode 100644 MapboxNavigation/Resources/fr.lproj/Abbreviations.csv.plist delete mode 100644 MapboxNavigation/Resources/fr.lproj/Abbreviations.plist delete mode 100644 MapboxNavigation/Resources/lt.lproj/Abbreviations.csv.plist delete mode 100644 MapboxNavigation/Resources/lt.lproj/Abbreviations.plist delete mode 100644 MapboxNavigation/Resources/nl.lproj/Abbreviations.csv.plist delete mode 100644 MapboxNavigation/Resources/nl.lproj/Abbreviations.plist delete mode 100644 MapboxNavigation/Resources/pt-BR.lproj/Abbreviations.plist delete mode 100644 MapboxNavigation/Resources/ru.lproj/Abbreviations.csv.plist delete mode 100644 MapboxNavigation/Resources/ru.lproj/Abbreviations.plist delete mode 100644 MapboxNavigation/Resources/sv.lproj/Abbreviations.csv.plist delete mode 100644 MapboxNavigation/Resources/sv.lproj/Abbreviations.plist delete mode 100644 MapboxNavigation/Resources/vi.lproj/Abbreviations.csv.plist delete mode 100644 MapboxNavigation/Resources/vi.lproj/Abbreviations.plist diff --git a/MapboxNavigation/Abbreviations.swift b/MapboxNavigation/Abbreviations.swift index 670907dfad..84628b3a3b 100644 --- a/MapboxNavigation/Abbreviations.swift +++ b/MapboxNavigation/Abbreviations.swift @@ -1,67 +1,19 @@ import UIKit -let path = Bundle.mapboxNavigation.path(forResource: "Abbreviations", ofType: "plist")! -let allAbbrevations = NSDictionary(contentsOfFile: path) as? [String: [String: String]] - -/// Options that specify what kinds of words in a string should be abbreviated. -struct StringAbbreviationOptions: OptionSet { - let rawValue: Int - - /// Abbreviates ordinary words that have common abbreviations. - static let Abbreviations = StringAbbreviationOptions(rawValue: 1 << 0) - /// Abbreviates directional words. - static let Directions = StringAbbreviationOptions(rawValue: 1 << 1) - /// Abbreviates road name suffixes. - static let Classifications = StringAbbreviationOptions(rawValue: 1 << 2) -} - extension String { - /// Returns an abbreviated copy of the string. - func abbreviated(by options: StringAbbreviationOptions) -> String { - var abbreviatedString = self - abbreviatedString.enumerateSubstrings(in: abbreviatedString.wholeRange, options: [.byWords, .reverse]) { (substring, substringRange, enclosingRange, stop) in - guard var word = substring?.lowercased() else { - return - } - - if let abbreviation = allAbbrevations!["abbreviations"]![word], options.contains(.Abbreviations) { - word = abbreviation - } else if let direction = allAbbrevations!["directions"]![word], options.contains(.Directions) { - word = direction - } else if let classification = allAbbrevations!["classifications"]![word], options.contains(.Classifications) { - word = classification - } else { - return - } - - abbreviatedString.replaceSubrange(substringRange, with: word) - } - return abbreviatedString - } - /// Returns the string abbreviated only as much as necessary to fit the given width and font. - func abbreviated(toFit bounds: CGRect, font: UIFont) -> String { + func abbreviated(toFit bounds: CGRect, font: UIFont, possibleAbbreviation: String?) -> String { let availableSize = CGSize(width: bounds.width, height: .greatestFiniteMagnitude) - var fittedString = self - var stringSize = fittedSize(with: availableSize, font: font) + let fittedString = self + let stringSize = fittedSize(with: availableSize, font: font) if stringSize.width < bounds.width && stringSize.height <= bounds.height { return fittedString - } - - fittedString = fittedString.abbreviated(by: [.Classifications]) - stringSize = fittedString.fittedSize(with: availableSize, font: font) - if stringSize.width < bounds.width && stringSize.height <= bounds.height { + } else if let possibleAbbreviation = possibleAbbreviation { + return possibleAbbreviation + } else { return fittedString } - - fittedString = fittedString.abbreviated(by: [.Directions]) - stringSize = fittedString.fittedSize(with: availableSize, font: font) - if stringSize.width < bounds.width && stringSize.height <= bounds.height { - return fittedString - } - - return fittedString.abbreviated(by: [.Abbreviations]) } func fittedSize(with size: CGSize, font: UIFont) -> CGSize { diff --git a/MapboxNavigation/InstructionPresenter.swift b/MapboxNavigation/InstructionPresenter.swift index f1d16e8011..a2c4a24c74 100644 --- a/MapboxNavigation/InstructionPresenter.swift +++ b/MapboxNavigation/InstructionPresenter.swift @@ -25,6 +25,9 @@ class InstructionPresenter { for component in instruction { let isFirst = component == instruction.first let joinChar = !isFirst ? " " : "" + + let joinCharPlusAbbreviation = component.abbreviation != nil ? joinChar + component.abbreviation! : nil + let joinCharPlusText = component.text != nil ? joinChar + component.text! : nil if let shieldKey = component.shieldKey() { if let cachedImage = imageRepository.cachedImageForKey(shieldKey) { @@ -32,8 +35,8 @@ class InstructionPresenter { string.append(attributedString(withFont: label.font, shieldImage: cachedImage)) } else { // Display road code while shield is downloaded - if let text = component.text { - string.append(NSAttributedString(string: joinChar + text, attributes: attributesForLabel(label))) + if let text = joinCharPlusText { + string.append(NSAttributedString(string: (text).abbreviated(toFit: label.availableBounds(), font: label.font, possibleAbbreviation: joinCharPlusAbbreviation), attributes: attributesForLabel(label))) } shieldImageForComponent(component, height: label.shieldHeight, completion: { [weak self] (image) in guard image != nil else { @@ -44,14 +47,14 @@ class InstructionPresenter { } }) } - } else if let text = component.text { + } else if let text = joinCharPlusText { if component.type == .delimiter && instructionHasDownloadedAllShields() { continue } - string.append(NSAttributedString(string: (joinChar + text).abbreviated(toFit: label.availableBounds(), font: label.font), attributes: attributesForLabel(label))) + string.append(NSAttributedString(string: (text).abbreviated(toFit: label.availableBounds(), font: label.font, possibleAbbreviation: joinCharPlusAbbreviation), attributes: attributesForLabel(label))) } } - + return string } @@ -103,3 +106,4 @@ class ShieldAttachment: NSTextAttachment { return CGRect(x: 0, y: font.descender - image.size.height / 2 + mid + 2, width: image.size.width, height: image.size.height).integral } } + diff --git a/MapboxNavigation/InstructionsBannerView.swift b/MapboxNavigation/InstructionsBannerView.swift index 341d78c4cb..52c431ceec 100644 --- a/MapboxNavigation/InstructionsBannerView.swift +++ b/MapboxNavigation/InstructionsBannerView.swift @@ -63,7 +63,7 @@ open class BaseInstructionsBannerView: UIControl { func set(_ instruction: VisualInstruction?) { let secondaryInstruction = instruction?.secondaryTextComponents - primaryLabel.numberOfLines = secondaryInstruction == nil ? 2 : 1 + primaryLabel.numberOfLines = 1 if secondaryInstruction == nil { centerYAlignInstructions() @@ -79,8 +79,7 @@ open class BaseInstructionsBannerView: UIControl { override open func prepareForInterfaceBuilder() { super.prepareForInterfaceBuilder() maneuverView.isStart = true - - primaryLabel.instruction = [VisualInstructionComponent(type: .destination, text: "Primary text label", imageURL: nil, maneuverType: .none, maneuverDirection: .none)] + primaryLabel.instruction = [VisualInstructionComponent(type: .text, text: "Primary text label", imageURL: nil, maneuverType: .none, maneuverDirection: .none, abbreviation: nil, abbreviationPriority: NSNotFound)] distance = 100 } diff --git a/MapboxNavigation/NextBannerView.swift b/MapboxNavigation/NextBannerView.swift index 9aebc3a8f3..450f57a80d 100644 --- a/MapboxNavigation/NextBannerView.swift +++ b/MapboxNavigation/NextBannerView.swift @@ -53,7 +53,7 @@ open class NextBannerView: UIView { override open func prepareForInterfaceBuilder() { super.prepareForInterfaceBuilder() maneuverView.isEnd = true - instructionLabel.instruction = [VisualInstructionComponent(type: .destination, text: "Next step", imageURL: nil, maneuverType: .none, maneuverDirection: .none)] + instructionLabel.instruction = [VisualInstructionComponent(type: .text, text: "Next step", imageURL: nil, maneuverType: .none, maneuverDirection: .none, abbreviation: nil, abbreviationPriority: NSNotFound)] } func setupLayout() { diff --git a/MapboxNavigation/Resources/Base.lproj/Abbreviations.csv.plist b/MapboxNavigation/Resources/Base.lproj/Abbreviations.csv.plist deleted file mode 100644 index 43489ff876..0000000000 --- a/MapboxNavigation/Resources/Base.lproj/Abbreviations.csv.plist +++ /dev/null @@ -1,81 +0,0 @@ - - - - - abbreviations - "creek", "Crk" -"center", "Ctr" -"national", "Nat’l" -"mount", "Mt" -"mountain", "Mtn" -"crossing", "Xing" -"downtown", "Dtwn" -"international", "Int’l" -"park", "Pk" -"square", "Sq" -"saints", "SS" -"heights", "Hts" -"route", "Rte" -"saint", "St" -"fort", "Ft" -"market", "Mkt" -"centre", "Ctr" -"william", "Wm" -"school", "Sch" -"senior", "Sr" -"river", "Riv" -"sister", "Sr" -"village", "Vil" -"station", "Sta" -"apartments", "apts" -"university", "Univ" -"township", "Twp" -"lake", "Lk" -"junior", "Jr" -"father", "Fr" -"point", "Pt" -"memorial", "Mem" -"junction", "Jct" - - classifications - "court", "Ct" -"bypass", "Byp" -"drive", "Dr" -"motorway", "Mwy" -"bridge", "Br" -"place", "Pl" -"crescent", "Cres" -"parkway", "Pky" -"lane", "Ln" -"avenue", "Ave" -"expressway", "Expy" -"highway", "Hwy" -"square", "Sq" -"walkway", "Wky" -"pike", "Pk" -"freeway", "Fwy" -"street", "St" -"footway", "Ftwy" -"terrace", "Ter" -"boulevard", "Blvd" -"cove", "Cv" -"turnpike", "Tpk" -"road", "Rd" -"walk", "Wk" -"plaza", "Plz" -"circle", "Cir" -"alley", "Aly" -"point", "Pt" - - directions - "east", "E" -"northeast", "NE" -"south", "S" -"northwest", "NW" -"north", "N" -"southeast", "SE" -"southwest", "SW" -"west", "W" - - - diff --git a/MapboxNavigation/Resources/Base.lproj/Abbreviations.plist b/MapboxNavigation/Resources/Base.lproj/Abbreviations.plist deleted file mode 100644 index 877c13fd96..0000000000 --- a/MapboxNavigation/Resources/Base.lproj/Abbreviations.plist +++ /dev/null @@ -1,153 +0,0 @@ - - - - - abbreviations - - apartments - apts - center - Ctr - centre - Ctr - creek - Crk - crossing - Xing - downtown - Dtwn - father - Fr - fort - Ft - heights - Hts - international - Int’l - junction - Jct - junior - Jr - lake - Lk - market - Mkt - memorial - Mem - mount - Mt - mountain - Mtn - national - Nat’l - park - Pk - point - Pt - river - Riv - route - Rte - saint - St - saints - SS - school - Sch - senior - Sr - sister - Sr - square - Sq - station - Sta - township - Twp - university - Univ - village - Vil - william - Wm - - classifications - - alley - Aly - avenue - Ave - boulevard - Blvd - bridge - Br - bypass - Byp - circle - Cir - court - Ct - cove - Cv - crescent - Cres - drive - Dr - expressway - Expy - footway - Ftwy - freeway - Fwy - highway - Hwy - lane - Ln - motorway - Mwy - parkway - Pky - pike - Pk - place - Pl - plaza - Plz - point - Pt - road - Rd - square - Sq - street - St - terrace - Ter - turnpike - Tpk - walk - Wk - walkway - Wky - - directions - - east - E - north - N - northeast - NE - northwest - NW - south - S - southeast - SE - southwest - SW - west - W - - - diff --git a/MapboxNavigation/Resources/bg.lproj/Abbreviations.csv.plist b/MapboxNavigation/Resources/bg.lproj/Abbreviations.csv.plist deleted file mode 100644 index 4126c711d9..0000000000 --- a/MapboxNavigation/Resources/bg.lproj/Abbreviations.csv.plist +++ /dev/null @@ -1,79 +0,0 @@ - - - - - abbreviations - "поток", "П-к" -"център", "Ц-р" -"национален", "Нац" -"Връх", "Вр" -"планина", "Пл" -"проход", "Прох" -"център", "Ц-р" -"международен", "Межд" -"парк", "Пк" -"площад", "Пл" -"светисвети", "СвСв" -"височини", "вис" -"маршрут", "М-т" -"свети", "Св" -"крепост", "К-т" -"пазар", "Mkt" -"център", "Ц-р" -"уилям", "Ум" -"училище", "Уч" -"старши", "Стрш" -"река", "Рек" -"сестра", "сес" -"село", "с." -"станция", "С-я" -"апартаменти", "ап" -"университет", "Уни" -"район", "Р-н" -"езеро", "Ез" -"младши", "Мл" -"баща", "Бщ" -"точка", "Точ" -"паметник", "Пам" -"възел", "Въз" - classifications - "съд", "Сд" -"задминаване", "Задм" -"шофиране", "Шоф" -"магистрала", "М-ла" -"мост", "Мо" -"място", "Мя" -"плавен", "Пл" -"магистрала", "М-ла" -"платно", "Пл" -"булевард", "Бул" -"скоростна", "Скор" -"магистрала", "М-ла" -"площад", "Пл" -"пешеходна", "Пеш" -"връх", "Вр" -"път", "Път" -"улица", "Ул" -"пътека", "П-ка" -"тераса", "Тер" -"булевард", "Бул" -"залив", "З-в" -"магистрала", "М-ла" -"път", "Път" -"пеш", "Пеш" -"площад", "Пл" -"кръгово", "Кр" -"алея", "Ал" -"точка", "Тч" - directions - "изток", "И" -"североизток", "СИ" -"юг", "Ю" -"северозапад", "СЗ" -"север", "С" -"югоизток", "ЮИ" -"югозапад", "ЮЗ" -"запад", "З - - - diff --git a/MapboxNavigation/Resources/bg.lproj/Abbreviations.plist b/MapboxNavigation/Resources/bg.lproj/Abbreviations.plist deleted file mode 100644 index 6f26a60334..0000000000 --- a/MapboxNavigation/Resources/bg.lproj/Abbreviations.plist +++ /dev/null @@ -1,135 +0,0 @@ - - - - - abbreviations - - Връх - Вр - апартаменти - ап - баща - Бщ - височини - вис - възел - Въз - езеро - Ез - крепост - К-т - маршрут - М-т - международен - Межд - младши - Мл - национален - Нац - пазар - Mkt - паметник - Пам - парк - Пк - планина - Пл - площад - Пл - поток - П-к - проход - Прох - район - Р-н - река - Рек - свети - Св - светисвети - СвСв - село - с. - сестра - сес - станция - С-я - старши - Стрш - точка - Точ - уилям - Ум - университет - Уни - училище - Уч - център - Ц-р - - classifications - - алея - Ал - булевард - Бул - връх - Вр - задминаване - Задм - залив - З-в - кръгово - Кр - магистрала - М-ла - мост - Мо - място - Мя - пеш - Пеш - пешеходна - Пеш - плавен - Пл - платно - Пл - площад - Пл - път - Път - пътека - П-ка - скоростна - Скор - съд - Сд - тераса - Тер - точка - Тч - улица - Ул - шофиране - Шоф - - directions - - изток - И - север - С - северозапад - СЗ - североизток - СИ - юг - Ю - югозапад - ЮЗ - югоизток - ЮИ - - - diff --git a/MapboxNavigation/Resources/ca.lproj/Abbreviations.csv.plist b/MapboxNavigation/Resources/ca.lproj/Abbreviations.csv.plist deleted file mode 100644 index d5a3574cc5..0000000000 --- a/MapboxNavigation/Resources/ca.lproj/Abbreviations.csv.plist +++ /dev/null @@ -1,112 +0,0 @@ - - - - - abbreviations - "comunicacions","Com." -"xarxa hidrogràfica","Curs Fluv." -"edificació","Edif." -"equipament","Equip." -"element hidrogràfic","Hidr." -"indret","Indr." -"relleu del litoral","Lit." -"municipi","Mun." -"orografia","Orogr." -"cap de municipi","Cap" -"barri","Barri" -"comarca","Cca." -"disseminat","Diss" -"edificació històrica","Edif. Hist." -"entitat de població","Nucli" -"disseminat","Diss." -"entitat descentralitzada","E.M.D." - - classifications - "accés","Acc." -"antic","Antic" -"antiga carretera","Actra" -"apartaments","Apmt." -"autopista","Autp." -"autovia","Autv." -"avinguda","Av." -"baixada","Bda." -"barranc","Bnc." -"barri","B." -"blocs","Bloc" -"calçada","Cda." -"cantonada","Cant." -"carrer","C." -"carrerada","Ca." -"carreró","Cró." -"carretera","Ctra." -"cases","Cses." -"cinturó","Cinto" -"circumval·lació","Cval." -"colònia","Col." -"complex","Comp." -"conjunt","Conj." -"corraló","Crral" -"corredor","Cdor." -"corriol","Crol." -"costa","Cos." -"disseminat","Disse" -"drecera","Drec." -"enllaç","Ellaç" -"escala","Esc." -"esplanada","Esp." -"finca","Fin." -"glorieta","Glor." -"gran via","GV" -"grup","Gr." -"jardí","J." -"jardins","J." -"lloc","Lloc" -"mirador","Mira." -"muralla","Mur." -"paratge","Pge." -"partida","Par." -"passadís","Pdís." -"passatge","Ptge." -"passeig","Pg." -"passera","Psera" -"plaça","Pl." -"placeta","Plta." -"plana","Plana" -"platja","Pja." -"polígon","Pol." -"polígon industrial","PI." -"pont","Pont" -"port","Port" -"porta","Pta." -"portal","Ptal." -"portals","Ptals" -"prolongació","Prol." -"pujada","Pda." -"rambla","Rbla." -"rambleta","Rblt." -"rial","Rial" -"riera","Ra." -"ronda","Rda." -"rotonda","Rot." -"sector","Sec." -"sender","Send." -"sèquia","Sèq." -"torrent","T." -"travessera","Trav." -"travessia","Trv." -"urbanització","Urb." -"veïnat","Veï." -"viaducte","Vdct." - - directions - "est", "E" -"nordest", "NE" -"sud", "S" -"nordoest", "NO" -"nord", "N" -"sudest", "SE" -"sudoest", "SO" -"oest", "O" - - - diff --git a/MapboxNavigation/Resources/ca.lproj/Abbreviations.plist b/MapboxNavigation/Resources/ca.lproj/Abbreviations.plist deleted file mode 100644 index d0008a1191..0000000000 --- a/MapboxNavigation/Resources/ca.lproj/Abbreviations.plist +++ /dev/null @@ -1,213 +0,0 @@ - - - - - abbreviations - - barri - Barri - cap de municipi - Cap - comarca - Cca. - comunicacions - Com. - disseminat - Diss. - edificació - Edif. - edificació històrica - Edif. Hist. - element hidrogràfic - Hidr. - entitat de població - Nucli - entitat descentralitzada - E.M.D. - equipament - Equip. - indret - Indr. - municipi - Mun. - orografia - Orogr. - relleu del litoral - Lit. - xarxa hidrogràfica - Curs Fluv. - - classifications - - accés - Acc. - antic - Antic - antiga carretera - Actra - apartaments - Apmt. - autopista - Autp. - autovia - Autv. - avinguda - Av. - baixada - Bda. - barranc - Bnc. - barri - B. - blocs - Bloc - calçada - Cda. - cantonada - Cant. - carrer - C. - carrerada - Ca. - carreró - Cró. - carretera - Ctra. - cases - Cses. - cinturó - Cinto - circumval·lació - Cval. - colònia - Col. - complex - Comp. - conjunt - Conj. - corraló - Crral - corredor - Cdor. - corriol - Crol. - costa - Cos. - disseminat - Disse - drecera - Drec. - enllaç - Ellaç - escala - Esc. - esplanada - Esp. - finca - Fin. - glorieta - Glor. - gran via - GV - grup - Gr. - jardins - J. - jardí - J. - lloc - Lloc - mirador - Mira. - muralla - Mur. - paratge - Pge. - partida - Par. - passadís - Pdís. - passatge - Ptge. - passeig - Pg. - passera - Psera - placeta - Plta. - plana - Plana - platja - Pja. - plaça - Pl. - polígon - Pol. - polígon industrial - PI. - pont - Pont - port - Port - porta - Pta. - portal - Ptal. - portals - Ptals - prolongació - Prol. - pujada - Pda. - rambla - Rbla. - rambleta - Rblt. - rial - Rial - riera - Ra. - ronda - Rda. - rotonda - Rot. - sector - Sec. - sender - Send. - sèquia - Sèq. - torrent - T. - travessera - Trav. - travessia - Trv. - urbanització - Urb. - veïnat - Veï. - viaducte - Vdct. - - directions - - est - E - nord - N - nordest - NE - nordoest - NO - oest - O - sud - S - sudest - SE - sudoest - SO - - - diff --git a/MapboxNavigation/Resources/da.lproj/Abbreviations.csv.plist b/MapboxNavigation/Resources/da.lproj/Abbreviations.csv.plist deleted file mode 100644 index 130a7567e9..0000000000 --- a/MapboxNavigation/Resources/da.lproj/Abbreviations.csv.plist +++ /dev/null @@ -1,42 +0,0 @@ - - - - - abbreviations - "plads", "Pl." -"station", "St." -"nordre", "Nr." -"vænge", "vg." -"sankt", "Skt." -"ved", "v." -"vestre", "v." -"universitet", "Uni." -"stræde", "Str." -"hospital", "Hosp." -"skole", "Sk." -"centrum", "C." - - classifications - "boulevard", "Boul." -"nørre", "Nr." -"avenue", "Ave" -"dronning", "Dronn." -"gammel", "Gl." -"sønder", "Sdr." -"øster", "Ø." -"vestre", "V." -"østre", "Ø." -"vester", "V." - - directions - "øst", "Ø" -"nordøst", "NØ" -"syd", "S" -"nordvest", "NV" -"nord", "N" -"sydøst", "SØ" -"sydvest", "SV" -"vest", "V" - - - diff --git a/MapboxNavigation/Resources/da.lproj/Abbreviations.plist b/MapboxNavigation/Resources/da.lproj/Abbreviations.plist deleted file mode 100644 index 70e698082a..0000000000 --- a/MapboxNavigation/Resources/da.lproj/Abbreviations.plist +++ /dev/null @@ -1,75 +0,0 @@ - - - - - abbreviations - - centrum - C. - hospital - Hosp. - nordre - Nr. - plads - Pl. - sankt - Skt. - skole - Sk. - station - St. - stræde - Str. - universitet - Uni. - ved - v. - vestre - v. - vænge - vg. - - classifications - - avenue - Ave - boulevard - Boul. - dronning - Dronn. - gammel - Gl. - nørre - Nr. - sønder - Sdr. - vester - V. - vestre - V. - øster - Ø. - østre - Ø. - - directions - - nord - N - nordvest - NV - nordøst - - syd - S - sydvest - SV - sydøst - - vest - V - øst - Ø - - - diff --git a/MapboxNavigation/Resources/es.lproj/Abbreviations.csv.plist b/MapboxNavigation/Resources/es.lproj/Abbreviations.csv.plist deleted file mode 100644 index 7fd2408203..0000000000 --- a/MapboxNavigation/Resources/es.lproj/Abbreviations.csv.plist +++ /dev/null @@ -1,53 +0,0 @@ - - - - - abbreviations - "ayuntamiento", "Ayto" -"colonia", "Col" -"ciudad", "Cdad" -"departamento", "Dep" -"diciembre", "10bre" -"doctor", "Dr" -"doctora", "Dra" -"doctores", "Drs" -"doctoras", "Drs" -"don", "D" -"doña", "Dña" -"internacional", "Intl" -"noviembre", "9bre" -"octubre", "8bre" -"primero", "1º" -"primera", "1ª" -"san", "S" -"santa", "Sta" -"segundo", "2º" -"segunda", "2ª" -"señor", "Sr" -"señora", "Sra" -"señorita", "Srta" -"septiembre", "7bre" -"tercero", "3º" -"tercera", "3ª" - - classifications - "autopista", "Auto" -"avenida", "Av" -"calle", "C" -"camino", "Cmno" -"carretera", "Crta" -"paseo", "Pº" -"plaza", "Pza" - - directions - "este", "E" -"noreste", "NE" -"sur", "S" -"noroeste", "NO" -"norte", "N" -"sureste", "SE" -"suroeste", "SO" -"oeste", "O" - - - diff --git a/MapboxNavigation/Resources/es.lproj/Abbreviations.plist b/MapboxNavigation/Resources/es.lproj/Abbreviations.plist deleted file mode 100644 index 35a6644bd9..0000000000 --- a/MapboxNavigation/Resources/es.lproj/Abbreviations.plist +++ /dev/null @@ -1,97 +0,0 @@ - - - - - abbreviations - - ayuntamiento - Ayto - ciudad - Cdad - colonia - Col - departamento - Dep - diciembre - 10bre - doctor - Dr - doctora - Dra - doctoras - Drs - doctores - Drs - don - D - doña - Dña - internacional - Intl - noviembre - 9bre - octubre - 8bre - primera - - primero - - san - S - santa - Sta - segunda - - segundo - - septiembre - 7bre - señor - Sr - señora - Sra - señorita - Srta - tercera - - tercero - - - classifications - - autopista - Auto - avenida - Av - calle - C - camino - Cmno - carretera - Crta - paseo - - plaza - Pza - - directions - - este - E - noreste - NE - noroeste - NO - norte - N - oeste - O - sur - S - sureste - SE - suroeste - SO - - - diff --git a/MapboxNavigation/Resources/fr.lproj/Abbreviations.csv.plist b/MapboxNavigation/Resources/fr.lproj/Abbreviations.csv.plist deleted file mode 100644 index 69999d7e00..0000000000 --- a/MapboxNavigation/Resources/fr.lproj/Abbreviations.csv.plist +++ /dev/null @@ -1,656 +0,0 @@ - - - - - abbreviations - "aérodrome", "Aérod" -"aéroport", "Aérop" -"allée", "All" -"appartements, "Apt" -"appartements", "Apts" -"autoroute", "A" -"avenue", "Av" -"base", "Bse" -"boulevard", "Bd" -"bourg", "Bg" -"canal", "Cnl" -"carrefour", "Carr" -"centre", "Ctre" -"centre commercial", "CCom" -"champ", "Chmp" -"champs", "Chmps" -"chemin", "Chem." -"chemin d'exploitation", "CE" -"chemin forestier", "CF" -"chemin rural", "CR" -"chemin vicinal", "CV" -"cité", "Cit" -"comté", "Cté" -"contour", "Cont" -"cour", "Cr" -"déviation", "Dévn" -"écluse", "Écse" -"faubourg", "Fbg" -"ferry", "Fry" -"fort", "Ft" -"hameau", "Ham" -"impasse", "Imp" -"lieu-dit", "L-d" -"marché", "Mcé" -"métro", "Mº" -"mont", "Mt" -"montagne", "Mtgne" -"périphérique", "Périph" -"parc", "Pc" -"parking", "Pkg" -"passage", "Pge" -"piste", "Pst" -"place", "Pl" -"plage", "Plg" -"plaine", "Plne" -"point", "Pt" -"pointe", "Pnte" -"pont", "Pnt" -"port", "Prt" -"porte", "Pte" -"quai", "Qu" -"quartier", "Quart" -"résidence", "Résid" -"raccourci", "Racc" -"rocade", "Rde" -"rond-point", "Rd-Pt" -"route", "Rte" -"route communale", "RC" -"route départementale", "RD" -"route métropolitaine", "RM" -"route nationale", "RN" -"route territoriale", "RT" -"rue", "R" -"site", "Sit" -"square", "Sq" -"station", "Sttn" -"terrasse", "Tsse" -"tour", "Tr" -"traverse", "Trav" -"trottoir", "Trot" -"tunnel", "Tnl" -"venelle", "Ven" -"village", "Vlge" -"virage", "Vir" -"voie", "V" -"voie communale", "VC" -"voie express", "VExp" -"zone", "Z" -"zone artisanale", "ZA" -"zone d'activité", "ZA" -"zone d'activités", "ZA" -"zone d'aménagement concerté", "ZAC" -"zone industrielle", "ZI" - - classifications - "adjudant", "Adj." -"administratif", "Admin." -"administratifs", "Admin." -"administrative", "Admin." -"administratives", "Admin." -"administration", "Admin." -"administrations", "Admin." -"africain", "Afric." -"africaine", "Afric." -"africaines", "Afric." -"africains", "Afric." -"agricole", "Agric." -"agricoles", "Agric." -"agriculteur", "Agric." -"agriculteurs", "Agric." -"agriculture", "Agric." -"agronome", "Agro." -"agronomes", "Agro." -"agronomie", "Agro." -"agronomique", "Agro." -"agronomiques", "Agro." -"alpin", "Alp." -"alpine", "Alp." -"alpines", "Alp." -"alpins", "Alp." -"ambassade", "Amb." -"américain", "Amér." -"américaine", "Amér." -"américaines", "Amér." -"américains", "Amér." -"amiral", "Amir." -"amiraux", "Amir." -"animation", "Anim." -"animé", "Anim." -"anonyme", "Anon." -"antenne", "Ant." -"apostolique", "Apost." -"après", "apr." -"après-midi", "a.-m." -"arrêt", "Arr." -"archéologie", "Archéo." -"archéologique", "Archéo." -"archiduc", "Archid." -"archiduchesse", "Archid." -"archipel", "Archip." -"archives", "Arch." -"archevêque", "Archev." -"arrondissement", "Arrond." -"asiatique", "Asiat.", -"asiatiques", "Asiat.", -"association", "Assoc." -"associatif", "Assoc." -"associative", "Assoc." -"associé", "Assoc." -"associés", "Assoc." -"aviation", "Aviat." -"aviateur", "Aviat." -"aviateurs", "Aviat." -"aviatrice", "Aviat." -"aviatrices", "Aviat." -"avant", "av." -"avril", "Avr." -"banque", "Bq" -"barrage", "Barr." -"basse", "Bas." -"basses", "Bas." -"bâtiment", "Bât." -"bibliothèque", "Biblio." -"boucherie", "Bouch." -"boucher", "Bouch." -"café", "Cfé" -"cafés", "Cfés" -"cafétéria", "Cafét." -"cafétérias", "Cafét." -"camping", "Camp." -"campings", "Camp." -"caporal", "Capo." -"catégorie", "Catég." -"cathédrale", "Cathéd." -"catholique", "Cathol." -"catholiques", "Cathol." -"centre", "Ctre" -"centres", "Ctres" -"central", "Ctral" -"centrale", "Ctrale" -"centrales", "Ctrales" -"centre d'enseignement du second degré", "CES" -"centre hospitalier régional", "CHR" -"centre hospitalier universitaire", "CHU" -"chapelle", "Chap." -"chapelles", "Chap." -"charcuterie", "Charc." -"charcutier", "Charc." -"château", "Chât." -"châteaux", "Chât." -"cimetière", "Cim." -"cimetières", "Cim." -"cinéma", "Ciné" -"cinémas", "Cinés" -"civil", "Civ." -"civile", "Civ." -"civiles", "Civ." -"civils", "Civ." -"clinique", "Clin." -"cliniques", "Clin." -"collège", "Coll." -"collèges", "Coll." -"colonel", "Col." -"commune", "Commun." -"communal", "Commun." -"communale", "Commun." -"communauté", "Commté" -"communautés", "Commtés" -"commerçant", "Commerç." -"commerçante", "Commerç." -"commerçants", "Commerç." -"commerce", "Commerc." -"commerces", "Commerc." -"commercial", "Commerc." -"commerciale", "Commerc." -"commerciales", "Commerc." -"commerciaux", "Commerc." -"comte", "Cte" -"comté", "Cté" -"comtés", "Ctés" -"confédéral", "Conféd." -"confédérale", "Conféd." -"confédération", "Conféd." -"conférence", "Confér." -"conférences", "Confér." -"congrégation", "Congrég." -"congrégations", "Congrég." -"consulat", "Consul." -"coopératif", "Coop." -"coopérative", "Coop." -"crédit", "Créd." -"croix", "Cx" -"culturel", "Cult." -"culturelle", "Cult." -"dans", "d/" -"décembre", "Déc." -"démocratique", "Dém." -"département", "Dépt" -"départemental", "Dépt" -"départementale", "Dépt" -"départementaux", "Dépt" -"départementales", "Dépt" -"deux mil", "2000" -"deuxième", "2e" -"développé", "Dévelop." -"développement", "Dévelop." -"dimanche", "di." -"directeur", "Dir." -"directeurs", "Dir." -"direction", "Dir." -"directions", "Dir." -"directrice", "Dir." -"directrices", "Dir." -"district", "Distr." -"districts", "Distr." -"docteur", "Dr" -"docteurs", "Drs" -"doyen", "Doy." -"doyens", "Doy." -"école", "Éc." -"écoles", "Éc." -"église", "Égl." -"églises", "Égl." -"électrique", "Électr." -"électriques", "Électr." -"élém", "Élém." -"enseignement", "Enseign." -"établissement", "Étabt" -"établissements", "Étabts" -"état", "É." -"états", "É." -"étage", "ét." -"étang", "Étg" -"européen", "Eur." -"européens", "Eur." -"européenne", "Eur." -"européennes", "Eur." -"exploitation", "Exploit." -"exploitant", "Exploit." -"exploitants", "Exploit." -"faculté", "Fac." -"fédéral", "Féd." -"fédérale", "Féd." -"fédération", "Féd." -"ferré", "Ferr." -"ferrée", "Ferr." -"ferroviaire", "Ferr." -"février", "Févr." -"fleuve", "Flv" -"fluvial", "Flv" -"fluviale", "Flv" -"fluviales", "Flv" -"fluviaux", "Flv" -"fondation", "Fond." -"fondateur", "Fond." -"fondateurs", "Fond." -"fondatrice", "Fond." -"fondatrices", "Fond." -"football", "Foot" -"forestier", "Forest." -"forestière", "Forest." -"général", "Gal" -"générale", "Gale" -"généraux", "Gaux" -"global", "Glob." -"globale", "Glob." -"globales", "Glob." -"globaux", "Glob." -"grand", "Gd" -"grande", "Gde" -"grandes", "Gdes" -"grands", "Gds" -"haut", "Ht" -"haute", "Hte" -"hautes", "Htes" -"hauts", "Hts" -"hélicoptère", "hélico" -"hélicoptères", "hélicos" -"historique", "Hist." -"historiques", "Hist." -"hôpital", "Hôp." -"hospice", "Hosp." -"hospices", "Hosp." -"hospitalier", "Hosp." -"hôtel", "Hôt." -"hôtel-restaurant", "Hôt.-Rest." -"hôtels", "Hôt." -"hôtels-restaurants", "Hôt.-Rest." -"ier", "1er" -"ii", "2" -"iie", "2e" -"iii", "3" -"iiie", "3e" -"île-de-france", "IDF" -"immeuble", "Imm." -"industriel", "Ind." -"industrielle", "Ind." -"infanterie", "Infant." -"infirmerie", "Infirm." -"infirmier", "Infirm." -"infirmière", "Infirm." -"infirmières", "Infirm." -"infirmiers", "Infirm." -"information", "Info." -"informations", "Infos" -"international", "Int." -"internationale", "Int." -"ire", "1re" -"iv", "4" -"ive", "4e" -"ix", "9" -"ixe", "9e" -"jardin", "Jard." -"janvier", "Janv." -"jésus-christ", "J.-C." -"jeudi", "je." -"juillet", "Juil." -"junior", "Jr" -"lieutenant", "Lieut." -"lieutenant-colonel", "Lieut.-Col." -"lundi", "lu." -"lycée", "Lyc." -"lycée d'enseignement professionnel", "LEP" -"madame", "Mme" -"mademoiselle", "Mle" -"maire", "Mair." -"mairie", "Mair." -"majeur", "Maj." -"majeurs", "Maj." -"majeures", "Maj." -"majeure", "Maj." -"major", "Mjr" -"mardi", "ma." -"maréchal", "Mal" -"maritime", "Marit." -"maritimes", "Marit." -"matin", "mat." -"maternelle", "Matern." -"médecin", "Méd." -"médical", "Méd." -"médicale", "Méd." -"médicales", "Méd." -"médicaux", "Méd." -"mémorial", "Mémor." -"mercredi", "me." -"messieurs", "MM" -"métro", "Mº" -"métros", "Mº" -"métropolitain", "Métrop." -"métropolitaine", "Métrop." -"militaire", "Milit." -"militaires", "Milit." -"ministère", "Min." -"millénaire", "Mill." -"millénaires", "Mill." -"mineur", "Min." -"mineurs", "Min." -"mineure", "Min." -"mineures", "Min." -"monseigneur", "Mgr" -"monsieur", "M." -"monument", "Mmt" -"monuments", "Mmts" -"mosquée", "Mosq." -"mondial", "Mond." -"mondiale", "Mond." -"mondiales", "Mond." -"mondiaux", "Mond." -"moyen", "Moy." -"moyenne", "Moy." -"moyennes", "Moy." -"moyens", "Moy." -"municipal", "Munic." -"municipale", "Munic." -"municipales", "Munic." -"municipaux", "Munic." -"municipalité", "Munic." -"musée", "Msée" -"musique", "Musiq." -"musical", "Music." -"musicale", "Music." -"musicien", "Music." -"musicienne", "Music." -"national", "Nal" -"nationale", "Nale" -"nationales", "Nales" -"notre-dame", "ND" -"numéro", "Nº" -"numéros", "Nºˢ" -"naturel", "Natur." -"nautique", "Naut." -"naval", "Nav." -"navale", "Nav." -"navigable", "Navig." -"navigation", "Navig." -"novembre", "Nov." -"occidental", "Occ." -"occidentale", "Occ." -"occidentales", "Occ." -"occidentaux", "Occ." -"octobre", "Oct." -"ophtalmologie", "Ophtalm." -"ophtalmologue", "Ophtalmo" -"ophtalmologues", "Ophtalmos" -"oriental", "Ori." -"orientale", "Ori." -"orientales", "Ori." -"orientaux", "Ori." -"palais", "Pal." -"parachutiste", "Para." -"parachutistes", "Para." -"pâtissier", "Pâtiss." -"petit", "Pet." -"petits", "Pet." -"petite", "Pet." -"petites", "Pet." -"pharmacie", "Pharm." -"pharmacien", "Pharm." -"pharmacienne", "Pharm." -"piscine", "Pisc." -"pompier", "Pomp." -"pompiers", "Pomp." -"pontifical", "Pontif." -"pontificale", "Pontif." -"pontificales", "Pontif." -"pontificaux", "Pontif." -"populaire", "Pop." -"portuaire", "Port." -"poste", "Post." -"postal", "Post." -"postale", "Post." -"postaux", "Post." -"premier", "1er" -"première", "1re" -"premiers", "1ers" -"président", "Pdt" -"présidente", "Pdte" -"présidentes", "Pdtes" -"présidents", "Pdts" -"présidentiel", "Pdtl" -"présidentielle", "Pdtle" -"primaire", "Prim." -"primaires", "Prim." -"prince", "Pce" -"princesse", "Pse" -"privé", "Priv." -"privée", "Priv." -"préfectoral", "Préf." -"préfectorale", "Préf." -"préfecture", "Préf." -"préfet", "Préf." -"protégé", "Prot." -"protégés", "Prot." -"protégées", "Prot." -"protégée", "Prot." -"protection", "Prot." -"province", "Prov." -"provincial", "Prov." -"provinciale", "Prov." -"provence-alpes-côte d'azur", "PACA" -"professeur", "Prof." -"professionnel", "Profess." -"professionnelle", "Profess." -"public", "Publ." -"publique", "Publ." -"régiment", "Régim." -"région", "Rég." -"régional", "Rég." -"régionale", "Rég." -"république", "Rép." -"républicain", "Républ." -"républicaine", "Républ." -"résidentiel", "Résid." -"résidentielle", "Résid." -"restaurant", "Restau." -"rivière", "Riv." -"routière", "Rout." -"rural", "Rur." -"rurale", "Rur." -"senior", "Sr" -"septembre", "Sept." -"sa majesté", "S.Maj." -"saint", "St" -"sainte", "Ste" -"saints", "Sts" -"sapeur", "Sap." -"sapeurs", "Sap." -"sapeur-pompier", "Sap.-pomp." -"sapeur-pompiers", "Sap.-pomp." -"samedi", "sa." -"secondaire", "Second." -"secondaires", "Second." -"sergent", "Sgt" -"service", "Sce" -"siècle", "Si." -"scolaire", "Scol." -"social", "Soc." -"sociale", "Soc." -"société", "Sté" -"sociétés", "Stés" -"société anonyme", "SA" -"société anonyme à responsabilité limitée", "SARL" -"société nationale", "SN" -"son altesse", "S.Alt." -"son altesse royale", "S.A.R." -"sous-préfecture", "Ss-préf." -"sous-préfet", "Ss-préf." -"sous", "s/s" -"spécial", "Spéc." -"spéciale", "Spéc." -"spéciales", "Spéc." -"spécialisé", "Spéc." -"spécialisée", "Spéc." -"spéciaux", "Spéc." -"spectacle", "Spect." -"spectacles", "Spect." -"sportif", "Sport." -"sportive", "Sport." -"stade", "Std" -"supérieur", "Sup." -"supérieure", "Sup." -"supérieures", "Sup." -"supérieurs", "Sup." -"sur", "/" -"syndicat", "Synd." -"syndicats", "Synd." -"technique", "Tech." -"techniques", "Tech." -"technologie", "Techno." -"technologies", "Techno." -"technologique", "Techno." -"technologiques", "Techno." -"temple", "Tple" -"terrain", "Terr." -"territorial", "Territ." -"territoriale", "Territ." -"territoire", "Territ." -"tertiaire", "Terti." -"tertiaires", "Terti." -"théâtre", "Thé." -"théâtral", "Thé." -"théâtrale", "Thé." -"traversière", "Traver." -"trafic", "Traf." -"troisième", "3e" -"union", "U." -"unité", "U." -"urbain", "Urb." -"urbains", "Urb." -"urbaine", "Urb." -"urbaines", "Urb." -"urbanisme", "Urb." -"universel", "Univ." -"universelle", "Univ." -"université", "Univ." -"universitaire", "Univ." -"v", "5" -"ve", "5e" -"vendredi", "ve." -"vers", "v/" -"vétérinaire", "Vét." -"vétérinaires", "Vét." -"vi", "6" -"vie", "6e" -"viticole", "Vitic." -"viticoles", "Vitic." -"viticulture", "Vitic." -"viticulteur", "Vitic." -"viticulteurs", "Vitic." -"vii", "7" -"viie", "7e" -"viii", "8" -"viiie", "8e" -"x", "10" -"xe", "10e" -"xi", "11" -"xie", "11e" -"xii", "12" -"xiie", "12e" -"xiii", "13" -"xiiie", "13e" -"xiv", "14" -"xive", "14e" -"xix", "19" -"xixe", "19e" -"xv", "15" -"xve", "15e" -"xvi", "16" -"xvie", "16e" -"xvi", "17" -"xvie", "17e" -"xvii", "18" -"xviie", "18e" -"xx", "20" -"xxe", "20e" -"xxi", "21" -"xxie", "21e" -"xxii", "22" -"xxiii", "23" -"zone", "zon." - - directions - "est", "E" -"est-nord-est", "ENE" -"nord-est", "NE" -"nord-nord-est", "NNE" -"nord", "N" -"nord-nord-ouest", "NNO" -"nord-ouest", "NO" -"ouest-nord-ouest", "ONO" -"ouest", "O" -"ouest-sud-ouest", "OSO" -"sud-ouest", "SO" -"sud-sud-ouest", "SSO" -"sud", "S" -"sud-sud-est", "SSE" -"sud-est", "SE" -"est-sud-est", "ESE" - - - diff --git a/MapboxNavigation/Resources/fr.lproj/Abbreviations.plist b/MapboxNavigation/Resources/fr.lproj/Abbreviations.plist deleted file mode 100644 index 9b6d27f744..0000000000 --- a/MapboxNavigation/Resources/fr.lproj/Abbreviations.plist +++ /dev/null @@ -1,1139 +0,0 @@ - - - - - abbreviations - - allée - All - aérodrome - Aérod - aéroport - Aérop - - classifications - - adjudant - Adj. - administratif - Admin. - administratifs - Admin. - administration - Admin. - administrations - Admin. - administrative - Admin. - administratives - Admin. - africain - Afric. - africaine - Afric. - africaines - Afric. - africains - Afric. - agricole - Agric. - agricoles - Agric. - agriculteur - Agric. - agriculteurs - Agric. - agriculture - Agric. - agronome - Agro. - agronomes - Agro. - agronomie - Agro. - agronomique - Agro. - agronomiques - Agro. - alpin - Alp. - alpine - Alp. - alpines - Alp. - alpins - Alp. - ambassade - Amb. - amiral - Amir. - amiraux - Amir. - américain - Amér. - américaine - Amér. - américaines - Amér. - américains - Amér. - animation - Anim. - animé - Anim. - anonyme - Anon. - antenne - Ant. - apostolique - Apost. - après - apr. - après-midi - a.-m. - archevêque - Archev. - archiduc - Archid. - archiduchesse - Archid. - archipel - Archip. - archives - Arch. - archéologie - Archéo. - archéologique - Archéo. - arrondissement - Arrond. - arrêt - Arr. - asiatique - Asiat. - asiatiques - Asiat. - associatif - Assoc. - association - Assoc. - associative - Assoc. - associé - Assoc. - associés - Assoc. - avant - av. - aviateur - Aviat. - aviateurs - Aviat. - aviation - Aviat. - aviatrice - Aviat. - aviatrices - Aviat. - avril - Avr. - banque - Bq - barrage - Barr. - basse - Bas. - basses - Bas. - bibliothèque - Biblio. - boucher - Bouch. - boucherie - Bouch. - bâtiment - Bât. - café - Cfé - cafés - Cfés - cafétéria - Cafét. - cafétérias - Cafét. - camping - Camp. - campings - Camp. - caporal - Capo. - catholique - Cathol. - catholiques - Cathol. - cathédrale - Cathéd. - catégorie - Catég. - central - Ctral - centrale - Ctrale - centrales - Ctrales - centre - Ctre - centre d'enseignement du second degré - CES - centre hospitalier régional - CHR - centre hospitalier universitaire - CHU - centres - Ctres - chapelle - Chap. - chapelles - Chap. - charcuterie - Charc. - charcutier - Charc. - château - Chât. - châteaux - Chât. - cimetière - Cim. - cimetières - Cim. - cinéma - Ciné - cinémas - Cinés - civil - Civ. - civile - Civ. - civiles - Civ. - civils - Civ. - clinique - Clin. - cliniques - Clin. - collège - Coll. - collèges - Coll. - colonel - Col. - commerce - Commerc. - commerces - Commerc. - commercial - Commerc. - commerciale - Commerc. - commerciales - Commerc. - commerciaux - Commerc. - commerçant - Commerç. - commerçante - Commerç. - commerçants - Commerç. - communal - Commun. - communale - Commun. - communauté - Commté - communautés - Commtés - commune - Commun. - comte - Cte - comté - Cté - comtés - Ctés - confédéral - Conféd. - confédérale - Conféd. - confédération - Conféd. - conférence - Confér. - conférences - Confér. - congrégation - Congrég. - congrégations - Congrég. - consulat - Consul. - coopératif - Coop. - coopérative - Coop. - croix - Cx - crédit - Créd. - culturel - Cult. - culturelle - Cult. - dans - d/ - deux mil - 2000 - deuxième - 2e - dimanche - di. - directeur - Dir. - directeurs - Dir. - direction - Dir. - directions - Dir. - directrice - Dir. - directrices - Dir. - district - Distr. - districts - Distr. - docteur - Dr - docteurs - Drs - doyen - Doy. - doyens - Doy. - décembre - Déc. - démocratique - Dém. - département - Dépt - départemental - Dépt - départementale - Dépt - départementales - Dépt - départementaux - Dépt - développement - Dévelop. - développé - Dévelop. - enseignement - Enseign. - européen - Eur. - européenne - Eur. - européennes - Eur. - européens - Eur. - exploitant - Exploit. - exploitants - Exploit. - exploitation - Exploit. - faculté - Fac. - ferroviaire - Ferr. - ferré - Ferr. - ferrée - Ferr. - fleuve - Flv - fluvial - Flv - fluviale - Flv - fluviales - Flv - fluviaux - Flv - fondateur - Fond. - fondateurs - Fond. - fondation - Fond. - fondatrice - Fond. - fondatrices - Fond. - football - Foot - forestier - Forest. - forestière - Forest. - fédéral - Féd. - fédérale - Féd. - fédération - Féd. - février - Févr. - global - Glob. - globale - Glob. - globales - Glob. - globaux - Glob. - grand - Gd - grande - Gde - grandes - Gdes - grands - Gds - général - Gal - générale - Gale - généraux - Gaux - haut - Ht - haute - Hte - hautes - Htes - hauts - Hts - historique - Hist. - historiques - Hist. - hospice - Hosp. - hospices - Hosp. - hospitalier - Hosp. - hélicoptère - hélico - hélicoptères - hélicos - hôpital - Hôp. - hôtel - Hôt. - hôtel-restaurant - Hôt.-Rest. - hôtels - Hôt. - hôtels-restaurants - Hôt.-Rest. - ier - 1er - ii - 2 - iie - 2e - iii - 3 - iiie - 3e - immeuble - Imm. - industriel - Ind. - industrielle - Ind. - infanterie - Infant. - infirmerie - Infirm. - infirmier - Infirm. - infirmiers - Infirm. - infirmière - Infirm. - infirmières - Infirm. - information - Info. - informations - Infos - international - Int. - internationale - Int. - ire - 1re - iv - 4 - ive - 4e - ix - 9 - ixe - 9e - janvier - Janv. - jardin - Jard. - jeudi - je. - juillet - Juil. - junior - Jr - jésus-christ - J.-C. - lieutenant - Lieut. - lieutenant-colonel - Lieut.-Col. - lundi - lu. - lycée - Lyc. - lycée d'enseignement professionnel - LEP - madame - Mme - mademoiselle - Mle - maire - Mair. - mairie - Mair. - majeur - Maj. - majeure - Maj. - majeures - Maj. - majeurs - Maj. - major - Mjr - mardi - ma. - maritime - Marit. - maritimes - Marit. - maréchal - Mal - maternelle - Matern. - matin - mat. - mercredi - me. - messieurs - MM - militaire - Milit. - militaires - Milit. - millénaire - Mill. - millénaires - Mill. - mineur - Min. - mineure - Min. - mineures - Min. - mineurs - Min. - ministère - Min. - mondial - Mond. - mondiale - Mond. - mondiales - Mond. - mondiaux - Mond. - monseigneur - Mgr - monsieur - M. - monument - Mmt - monuments - Mmts - mosquée - Mosq. - moyen - Moy. - moyenne - Moy. - moyennes - Moy. - moyens - Moy. - municipal - Munic. - municipale - Munic. - municipales - Munic. - municipalité - Munic. - municipaux - Munic. - musical - Music. - musicale - Music. - musicien - Music. - musicienne - Music. - musique - Musiq. - musée - Msée - médecin - Méd. - médical - Méd. - médicale - Méd. - médicales - Méd. - médicaux - Méd. - mémorial - Mémor. - métro - - métropolitain - Métrop. - métropolitaine - Métrop. - métros - - national - Nal - nationale - Nale - nationales - Nales - naturel - Natur. - nautique - Naut. - naval - Nav. - navale - Nav. - navigable - Navig. - navigation - Navig. - notre-dame - ND - novembre - Nov. - numéro - - numéros - Nºˢ - occidental - Occ. - occidentale - Occ. - occidentales - Occ. - occidentaux - Occ. - octobre - Oct. - ophtalmologie - Ophtalm. - ophtalmologue - Ophtalmo - ophtalmologues - Ophtalmos - oriental - Ori. - orientale - Ori. - orientales - Ori. - orientaux - Ori. - palais - Pal. - parachutiste - Para. - parachutistes - Para. - petit - Pet. - petite - Pet. - petites - Pet. - petits - Pet. - pharmacie - Pharm. - pharmacien - Pharm. - pharmacienne - Pharm. - piscine - Pisc. - pompier - Pomp. - pompiers - Pomp. - pontifical - Pontif. - pontificale - Pontif. - pontificales - Pontif. - pontificaux - Pontif. - populaire - Pop. - portuaire - Port. - postal - Post. - postale - Post. - postaux - Post. - poste - Post. - premier - 1er - premiers - 1ers - première - 1re - primaire - Prim. - primaires - Prim. - prince - Pce - princesse - Pse - privé - Priv. - privée - Priv. - professeur - Prof. - professionnel - Profess. - professionnelle - Profess. - protection - Prot. - protégé - Prot. - protégée - Prot. - protégées - Prot. - protégés - Prot. - provence-alpes-côte d'azur - PACA - province - Prov. - provincial - Prov. - provinciale - Prov. - préfectoral - Préf. - préfectorale - Préf. - préfecture - Préf. - préfet - Préf. - président - Pdt - présidente - Pdte - présidentes - Pdtes - présidentiel - Pdtl - présidentielle - Pdtle - présidents - Pdts - public - Publ. - publique - Publ. - pâtissier - Pâtiss. - restaurant - Restau. - rivière - Riv. - routière - Rout. - rural - Rur. - rurale - Rur. - régiment - Régim. - région - Rég. - régional - Rég. - régionale - Rég. - républicain - Républ. - républicaine - Républ. - république - Rép. - résidentiel - Résid. - résidentielle - Résid. - sa majesté - S.Maj. - saint - St - sainte - Ste - saints - Sts - samedi - sa. - sapeur - Sap. - sapeur-pompier - Sap.-pomp. - sapeur-pompiers - Sap.-pomp. - sapeurs - Sap. - scolaire - Scol. - secondaire - Second. - secondaires - Second. - senior - Sr - septembre - Sept. - sergent - Sgt - service - Sce - siècle - Si. - social - Soc. - sociale - Soc. - société - Sté - société anonyme - SA - société anonyme à responsabilité limitée - SARL - société nationale - SN - sociétés - Stés - son altesse - S.Alt. - son altesse royale - S.A.R. - sous - s/s - sous-préfecture - Ss-préf. - sous-préfet - Ss-préf. - spectacle - Spect. - spectacles - Spect. - sportif - Sport. - sportive - Sport. - spécial - Spéc. - spéciale - Spéc. - spéciales - Spéc. - spécialisé - Spéc. - spécialisée - Spéc. - spéciaux - Spéc. - stade - Std - supérieur - Sup. - supérieure - Sup. - supérieures - Sup. - supérieurs - Sup. - sur - / - syndicat - Synd. - syndicats - Synd. - technique - Tech. - techniques - Tech. - technologie - Techno. - technologies - Techno. - technologique - Techno. - technologiques - Techno. - temple - Tple - terrain - Terr. - territoire - Territ. - territorial - Territ. - territoriale - Territ. - tertiaire - Terti. - tertiaires - Terti. - théâtral - Thé. - théâtrale - Thé. - théâtre - Thé. - trafic - Traf. - traversière - Traver. - troisième - 3e - union - U. - unité - U. - universel - Univ. - universelle - Univ. - universitaire - Univ. - université - Univ. - urbain - Urb. - urbaine - Urb. - urbaines - Urb. - urbains - Urb. - urbanisme - Urb. - v - 5 - ve - 5e - vendredi - ve. - vers - v/ - vi - 6 - vie - 6e - vii - 7 - viie - 7e - viii - 8 - viiie - 8e - viticole - Vitic. - viticoles - Vitic. - viticulteur - Vitic. - viticulteurs - Vitic. - viticulture - Vitic. - vétérinaire - Vét. - vétérinaires - Vét. - x - 10 - xe - 10e - xi - 11 - xie - 11e - xii - 12 - xiie - 12e - xiii - 13 - xiiie - 13e - xiv - 14 - xive - 14e - xix - 19 - xixe - 19e - xv - 15 - xve - 15e - xvi - 17 - xvie - 17e - xvii - 18 - xviie - 18e - xx - 20 - xxe - 20e - xxi - 21 - xxie - 21e - xxii - 22 - xxiii - 23 - zone - zon. - école - Éc. - écoles - Éc. - église - Égl. - églises - Égl. - électrique - Électr. - électriques - Électr. - élém - Élém. - établissement - Étabt - établissements - Étabts - étage - ét. - étang - Étg - état - É. - états - É. - île-de-france - IDF - - directions - - est - E - est-nord-est - ENE - est-sud-est - ESE - nord - N - nord-est - NE - nord-nord-est - NNE - nord-nord-ouest - NNO - nord-ouest - NO - ouest - O - ouest-nord-ouest - ONO - ouest-sud-ouest - OSO - sud - S - sud-est - SE - sud-ouest - SO - sud-sud-est - SSE - sud-sud-ouest - SSO - - - diff --git a/MapboxNavigation/Resources/lt.lproj/Abbreviations.csv.plist b/MapboxNavigation/Resources/lt.lproj/Abbreviations.csv.plist deleted file mode 100644 index 0b4cf0dd9b..0000000000 --- a/MapboxNavigation/Resources/lt.lproj/Abbreviations.csv.plist +++ /dev/null @@ -1,63 +0,0 @@ - - - - - abbreviations - "upelis","Up" -"centras","Ctr" -"nacionalinis","Nac" -"kalnas","Kln" -"kalnas","Kln" -"sankryža","Skrž" -"miesto centras","M.Ctr" -"tarptautinis", "Trptaut" -"parkas", "Pk" -"skveras", "Skv" -"šv", "Šv" -"aukštumos","Aukš" -"kelias","Kl" -"fortas","Ft" -"turgus","Tgs" -"centras","Ctr" -"mokykla","Mok" -"upė","Up", -"sesė","Sesė" -"kaimas","Km" -"stotis","St" -"apartamentai","Apt" -"universitetas","Univ" -"miestelis","Mstl" -"ežeras","Ež" -"tėvas","Tėv" -"taškas","Tšk", -"paminklas","Pmkl" -"sankryža","Skrž" - - classifications - "kiemelis","Kml" -"aplinkkelis","Aplnk" -"kelias","Kl" -"greitkelis","Grtkl" -"tiltas", "Tlt" -"vieta","Vt", -"pusratis","Psrt" -"bulvaras","Blvr" -"juosta", "Jst" -"prospektas", "Pspkt" -"autostrada", "Auto." -"greitkelis","Grtkl" -"aikštė", "A.", -"takas", "Tak.", - - directions - "rytai", "R" -"šiaurės rytai", "ŠR" -"pietūs", "P" -"šiaurės vakarai", "ŠV" -"šiaurė", "Š" -"pietryčiai", "PR" -"pietvakariai", "PV" -"vakarai", "V" - - - diff --git a/MapboxNavigation/Resources/lt.lproj/Abbreviations.plist b/MapboxNavigation/Resources/lt.lproj/Abbreviations.plist deleted file mode 100644 index b95da2222b..0000000000 --- a/MapboxNavigation/Resources/lt.lproj/Abbreviations.plist +++ /dev/null @@ -1,109 +0,0 @@ - - - - - abbreviations - - apartamentai - Apt - aukštumos - Aukš - centras - Ctr - ežeras - - fortas - Ft - kaimas - Km - kalnas - Kln - kelias - Kl - miestelis - Mstl - miesto centras - M.Ctr - mokykla - Mok - nacionalinis - Nac - paminklas - Pmkl - parkas - Pk - sankryža - Skrž - sesė - Sesė - skveras - Skv - stotis - St - tarptautinis - Trptaut - taškas - Tšk - turgus - Tgs - tėvas - Tėv - universitetas - Univ - upelis - Up - upė - Up - šv - Šv - - classifications - - aikštė - A. - aplinkkelis - Aplnk - autostrada - Auto. - bulvaras - Blvr - greitkelis - Grtkl - juosta - Jst - kelias - Kl - kiemelis - Kml - prospektas - Pspkt - pusratis - Psrt - takas - Tak. - tiltas - Tlt - vieta - Vt - - directions - - pietryčiai - PR - pietvakariai - PV - pietūs - P - rytai - R - vakarai - V - šiaurė - Š - šiaurės rytai - ŠR - šiaurės vakarai - ŠV - - - diff --git a/MapboxNavigation/Resources/nl.lproj/Abbreviations.csv.plist b/MapboxNavigation/Resources/nl.lproj/Abbreviations.csv.plist deleted file mode 100644 index 60058195cf..0000000000 --- a/MapboxNavigation/Resources/nl.lproj/Abbreviations.csv.plist +++ /dev/null @@ -1,77 +0,0 @@ - - - - - abbreviations - "meer","Mr" -"centrum","Cntrm" -"nationaal","Nat’l" -"toetreden","Ttrdn" -"berg","Brg" -"kruising","Krsng" -"downtown",''Dtwn" -"internationaal","Int’l" -"park","Pk" -"plein","Pln" -"heiligen","Hlgn" -"hoogtes","Hgts" -"route","Rte" -"heilige","Hlg" -"markt","Mrkt" -"centrum","Cntrm" -"william", "Wm" -"school","Sch" -"senior","Snr" -"rivier","Rvr" -"zus","Zus" -"drop","Drp" -"station","Sttn" -"appartementen","Apptn" -"universiteit","Uni" -"gehucht","Hucht" -"meer","Mr" -"junior","Jnr" -"vader","Vdr" -"punt","Punt" -"gedenkteken","Teken" -"knooppunt","Kpunt" - - classifications - "rechtbank","Rbank" -"bypass","Pass" -"rijden","Rijd" -"snelweg","Weg" -"brug","Br" -"plaats","Plts" -"halve maan","Maan" -"parkway","Pky" -"rijbaan","Strook" -"laan","Ln" -"autoweg","Weg" -"voetpad","Stoep" -"snoek","Snk" -"snelweg","Weg" -"straat","Str" -"terras","Trrs" -"boulevard","Blvd" -"inham","Nham" -"autobaan","Baan" -"weg","Weg" -"lopen","Lpn" -"plaza","Plz" -"cirkel","Crkl" -"steeg","Stg" -"punt","Pt" - - directions - "oost","O" -"noordoost","NO" -"zuiden","Z" -"noordwest","NW" -"noorden","N" -"zuidoost","ZO" -"zuidwest","ZW" -"westen","W" - - - diff --git a/MapboxNavigation/Resources/nl.lproj/Abbreviations.plist b/MapboxNavigation/Resources/nl.lproj/Abbreviations.plist deleted file mode 100644 index 4a77adab9e..0000000000 --- a/MapboxNavigation/Resources/nl.lproj/Abbreviations.plist +++ /dev/null @@ -1,91 +0,0 @@ - - - - - abbreviations - - berg - Brg - centrum - Cntrm - kruising - Krsng - meer - Mr - nationaal - Nat’l - toetreden - Ttrdn - - classifications - - autobaan - Baan - autoweg - Weg - boulevard - Blvd - brug - Br - bypass - Pass - cirkel - Crkl - halve maan - Maan - inham - Nham - laan - Ln - lopen - Lpn - parkway - Pky - plaats - Plts - plaza - Plz - punt - Pt - rechtbank - Rbank - rijbaan - Strook - rijden - Rijd - snelweg - Weg - snoek - Snk - steeg - Stg - straat - Str - terras - Trrs - voetpad - Stoep - weg - Weg - - directions - - noorden - N - noordoost - NO - noordwest - NW - oost - O - westen - W - zuiden - Z - zuidoost - ZO - zuidwest - ZW - - - diff --git a/MapboxNavigation/Resources/pt-BR.lproj/Abbreviations.plist b/MapboxNavigation/Resources/pt-BR.lproj/Abbreviations.plist deleted file mode 100644 index 877c13fd96..0000000000 --- a/MapboxNavigation/Resources/pt-BR.lproj/Abbreviations.plist +++ /dev/null @@ -1,153 +0,0 @@ - - - - - abbreviations - - apartments - apts - center - Ctr - centre - Ctr - creek - Crk - crossing - Xing - downtown - Dtwn - father - Fr - fort - Ft - heights - Hts - international - Int’l - junction - Jct - junior - Jr - lake - Lk - market - Mkt - memorial - Mem - mount - Mt - mountain - Mtn - national - Nat’l - park - Pk - point - Pt - river - Riv - route - Rte - saint - St - saints - SS - school - Sch - senior - Sr - sister - Sr - square - Sq - station - Sta - township - Twp - university - Univ - village - Vil - william - Wm - - classifications - - alley - Aly - avenue - Ave - boulevard - Blvd - bridge - Br - bypass - Byp - circle - Cir - court - Ct - cove - Cv - crescent - Cres - drive - Dr - expressway - Expy - footway - Ftwy - freeway - Fwy - highway - Hwy - lane - Ln - motorway - Mwy - parkway - Pky - pike - Pk - place - Pl - plaza - Plz - point - Pt - road - Rd - square - Sq - street - St - terrace - Ter - turnpike - Tpk - walk - Wk - walkway - Wky - - directions - - east - E - north - N - northeast - NE - northwest - NW - south - S - southeast - SE - southwest - SW - west - W - - - diff --git a/MapboxNavigation/Resources/ru.lproj/Abbreviations.csv.plist b/MapboxNavigation/Resources/ru.lproj/Abbreviations.csv.plist deleted file mode 100644 index dfc948ea38..0000000000 --- a/MapboxNavigation/Resources/ru.lproj/Abbreviations.csv.plist +++ /dev/null @@ -1,35 +0,0 @@ - - - - - abbreviations - "город", "г." -"деревня", "д." -"озеро", "о." -"посёлок", "п." -"река", "р." -"станция", "ст." - - classifications - "бульвар", "б." -"набережная", "наб." -"переулок", "пер." -"площадь", "пл." -"проезд", "пр-д" -"проспект", "пр." -"тупик", "туп." -"улица", "ул." -"шоссе", "ш." - - directions - "восток", "В" -"северо-восток", "СВ" -"юг", "Ю" -"северо-запад", "СЗ" -"север", "С" -"юго-восток", "ЮВ" -"юго-запад", "ЮЗ" -"запад", "З" - - - diff --git a/MapboxNavigation/Resources/ru.lproj/Abbreviations.plist b/MapboxNavigation/Resources/ru.lproj/Abbreviations.plist deleted file mode 100644 index 0c4a37e064..0000000000 --- a/MapboxNavigation/Resources/ru.lproj/Abbreviations.plist +++ /dev/null @@ -1,61 +0,0 @@ - - - - - abbreviations - - город - г. - деревня - д. - озеро - о. - посёлок - п. - река - р. - станция - ст. - - classifications - - бульвар - б. - набережная - наб. - переулок - пер. - площадь - пл. - проезд - пр-д - проспект - пр. - тупик - туп. - улица - ул. - шоссе - ш. - - directions - - восток - В - запад - З - север - С - северо-восток - СВ - северо-запад - СЗ - юг - Ю - юго-восток - ЮВ - юго-запад - ЮЗ - - - diff --git a/MapboxNavigation/Resources/sv.lproj/Abbreviations.csv.plist b/MapboxNavigation/Resources/sv.lproj/Abbreviations.csv.plist deleted file mode 100644 index c245a2b810..0000000000 --- a/MapboxNavigation/Resources/sv.lproj/Abbreviations.csv.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - abbreviations - "gamla", "G:la" -"sankt", "s:t" -"sankta", "s:ta" - - classifications - "Bro", "Br" - - directions - "nordöst", "NO" -"nordväst", "NV" -"sydväst", "SV" -"väster", "V" -"norr", "N" -"söder", "S" -"sydöst", "SO" -"öster", "O" - - - diff --git a/MapboxNavigation/Resources/sv.lproj/Abbreviations.plist b/MapboxNavigation/Resources/sv.lproj/Abbreviations.plist deleted file mode 100644 index 09b1cd7c66..0000000000 --- a/MapboxNavigation/Resources/sv.lproj/Abbreviations.plist +++ /dev/null @@ -1,39 +0,0 @@ - - - - - abbreviations - - gamla - G:la - sankt - s:t - sankta - s:ta - - classifications - - Bro - Br - - directions - - nordväst - NV - nordöst - NO - norr - N - sydväst - SV - sydöst - SO - söder - S - väster - V - öster - O - - - diff --git a/MapboxNavigation/Resources/vi.lproj/Abbreviations.csv.plist b/MapboxNavigation/Resources/vi.lproj/Abbreviations.csv.plist deleted file mode 100644 index 6bb10abc17..0000000000 --- a/MapboxNavigation/Resources/vi.lproj/Abbreviations.csv.plist +++ /dev/null @@ -1,58 +0,0 @@ - - - - - abbreviations - "thành phố", "Tp" -"thị xã", "Tx" -"thị trấn", "Tt" -"sân bay", "SB" -"sân bay quốc tế", "SBQT" -"phi trường", "PT" -"trung tâm", "TT" -"khách sạn", "KS" -"bưu điện", "BĐ" -"đại học", "ĐH" -"cao đẳng", "CĐ" -"trung học phổ thông", "THPT" -"trung học cơ sở", "THCS" -"khu chung cư", "KCC" -"khu công nghiệp", "KCN" -"khu nghỉ mát", "KNM" -"khu du lịch", "KDL" -"công viên", "CV" -"vườn quốc gia", "VQG" -"viện bảo tàng", "VBT" -"sân vận động", "SVĐ" -"câu lạc bộ", "CLB" -"công ty", "Cty" -"tổng công ty", "TCty" -"căn cứ không quan", "CCKQ" -"linh mục", "LM" - - classifications - "quốc lộ", "QL" -"tỉnh lộ", "TL" -"hương lộ", "HL" -"huyện lộ", "HL" -"đường tỉnh", "ĐT" -"đường huyện", "ĐH" -"đường cao tốc", "ĐCT" -"đại lộ", "ĐL" -"xa lộ", "XL" -"quảng trường", "QT" -"đường bộ", "ĐB" -"việt nam", "VN" - - directions - "đông", "Đ" -"đông bắc", "ĐB" -"nam", "N" -"tây nam", "TN" -"bắc", "B" -"đông nam", "ĐN" -"tây nam", "TN" -"tây", "T" - - - diff --git a/MapboxNavigation/Resources/vi.lproj/Abbreviations.plist b/MapboxNavigation/Resources/vi.lproj/Abbreviations.plist deleted file mode 100644 index 9662909993..0000000000 --- a/MapboxNavigation/Resources/vi.lproj/Abbreviations.plist +++ /dev/null @@ -1,105 +0,0 @@ - - - - - abbreviations - - bưu điện - - cao đẳng - - câu lạc bộ - CLB - công ty - Cty - công viên - CV - căn cứ không quan - CCKQ - khu chung cư - KCC - khu công nghiệp - KCN - khu du lịch - KDL - khu nghỉ mát - KNM - khách sạn - KS - linh mục - LM - phi trường - PT - sân bay - SB - sân bay quốc tế - SBQT - sân vận động - SVĐ - thành phố - Tp - thị trấn - Tt - thị xã - Tx - trung học cơ sở - THCS - trung học phổ thông - THPT - trung tâm - TT - tổng công ty - TCty - viện bảo tàng - VBT - vườn quốc gia - VQG - đại học - ĐH - - classifications - - huyện lộ - HL - hương lộ - HL - quảng trường - QT - quốc lộ - QL - tỉnh lộ - TL - việt nam - VN - xa lộ - XL - đường bộ - ĐB - đường cao tốc - ĐCT - đường huyện - ĐH - đường tỉnh - ĐT - đại lộ - ĐL - - directions - - bắc - B - nam - N - tây - T - tây nam - TN - đông - Đ - đông bắc - ĐB - đông nam - ĐN - - - diff --git a/MapboxNavigation/StepsViewController.swift b/MapboxNavigation/StepsViewController.swift index bca628ce2d..027b0593f3 100644 --- a/MapboxNavigation/StepsViewController.swift +++ b/MapboxNavigation/StepsViewController.swift @@ -201,7 +201,7 @@ extension StepsViewController: UITableViewDataSource { } func instructionForArrivalInstruction(text: String?) -> VisualInstructionComponent { - return VisualInstructionComponent(type: .destination, text: text, imageURL: nil, maneuverType: .none, maneuverDirection: .none) + return VisualInstructionComponent(type: .text, text: text, imageURL: nil, maneuverType: .none, maneuverDirection: .none, abbreviation: nil, abbreviationPriority: NSNotFound) } func updateCell(_ cell: StepTableViewCell, at indexPath: IndexPath) { diff --git a/MapboxNavigation/Waypoint.swift b/MapboxNavigation/Waypoint.swift index 0be2a098c6..74027f836b 100644 --- a/MapboxNavigation/Waypoint.swift +++ b/MapboxNavigation/Waypoint.swift @@ -8,7 +8,7 @@ extension Waypoint { var instructionComponent: VisualInstructionComponent? { guard let name = name else { return nil } - return VisualInstructionComponent(type: .destination, text: name, imageURL: nil, maneuverType: .arrive, maneuverDirection: .none) + return VisualInstructionComponent(type: .text, text: name, imageURL: nil, maneuverType: .arrive, maneuverDirection: .none, abbreviation: nil, abbreviationPriority: NSNotFound) } var instructionComponents: [VisualInstructionComponent]? { From e715d066b457036734f1815f5c3b7cb590621848 Mon Sep 17 00:00:00 2001 From: Bobby Sudekum Date: Tue, 27 Feb 2018 17:46:19 -0800 Subject: [PATCH 02/11] try and use priority level here --- MapboxNavigation/InstructionPresenter.swift | 33 ++++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/MapboxNavigation/InstructionPresenter.swift b/MapboxNavigation/InstructionPresenter.swift index a2c4a24c74..d1735d7250 100644 --- a/MapboxNavigation/InstructionPresenter.swift +++ b/MapboxNavigation/InstructionPresenter.swift @@ -14,15 +14,28 @@ class InstructionPresenter { var onShieldDownload: ShieldDownloadCompletion? private let imageRepository = ImageRepository.shared + + var currentPriorityLevel: Int? = nil func attributedText() -> NSAttributedString { guard let label = self.label else { return NSAttributedString() } - let string = NSMutableAttributedString() - - for component in instruction { + var string: [(Int, NSAttributedString)] = [] + + var i = 0 + let sortedCompomentsOnAbbreviationPriority = instruction.map { (instruction: VisualInstructionComponent) -> (Int, (VisualInstructionComponent)) in + let f = (i, instruction) + i += 1 + return f + }.sorted { + $0.1.abbreviationPriority < $1.1.abbreviationPriority + } + + for abbreivationPriotiryInstruction in sortedCompomentsOnAbbreviationPriority { + let component = abbreivationPriotiryInstruction.1 + let originalPlaceInComponent = abbreivationPriotiryInstruction.0 let isFirst = component == instruction.first let joinChar = !isFirst ? " " : "" @@ -31,12 +44,12 @@ class InstructionPresenter { if let shieldKey = component.shieldKey() { if let cachedImage = imageRepository.cachedImageForKey(shieldKey) { - string.append(NSAttributedString(string: joinChar)) - string.append(attributedString(withFont: label.font, shieldImage: cachedImage)) + string.append((originalPlaceInComponent, NSAttributedString(string: joinChar))) + string.append((originalPlaceInComponent, attributedString(withFont: label.font, shieldImage: cachedImage))) } else { // Display road code while shield is downloaded if let text = joinCharPlusText { - string.append(NSAttributedString(string: (text).abbreviated(toFit: label.availableBounds(), font: label.font, possibleAbbreviation: joinCharPlusAbbreviation), attributes: attributesForLabel(label))) + string.append((originalPlaceInComponent, NSAttributedString(string: (text).abbreviated(toFit: label.availableBounds(), font: label.font, possibleAbbreviation: joinCharPlusAbbreviation), attributes: attributesForLabel(label)))) } shieldImageForComponent(component, height: label.shieldHeight, completion: { [weak self] (image) in guard image != nil else { @@ -51,11 +64,15 @@ class InstructionPresenter { if component.type == .delimiter && instructionHasDownloadedAllShields() { continue } - string.append(NSAttributedString(string: (text).abbreviated(toFit: label.availableBounds(), font: label.font, possibleAbbreviation: joinCharPlusAbbreviation), attributes: attributesForLabel(label))) + string.append((originalPlaceInComponent, NSAttributedString(string: (text).abbreviated(toFit: label.availableBounds(), font: label.font, possibleAbbreviation: joinCharPlusAbbreviation), attributes: attributesForLabel(label)))) } } - return string + let finalString = NSMutableAttributedString() + string.sorted { $0.0 < $1.0 }.forEach { + finalString.append($0.1) + } + return finalString } private func shieldImageForComponent(_ component: VisualInstructionComponent, height: CGFloat, completion: @escaping (UIImage?) -> Void) { From c0ed9190325c747b08ec350aa6c636cd11f3e5fa Mon Sep 17 00:00:00 2001 From: Bobby Sudekum Date: Fri, 2 Mar 2018 10:35:25 -0800 Subject: [PATCH 03/11] Remove one loop --- MapboxNavigation/Abbreviations.swift | 16 +++++++++++++ MapboxNavigation/InstructionPresenter.swift | 25 +++++++++------------ 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/MapboxNavigation/Abbreviations.swift b/MapboxNavigation/Abbreviations.swift index 84628b3a3b..0ff06e5f5a 100644 --- a/MapboxNavigation/Abbreviations.swift +++ b/MapboxNavigation/Abbreviations.swift @@ -1,4 +1,5 @@ import UIKit +import MapboxDirections extension String { /// Returns the string abbreviated only as much as necessary to fit the given width and font. @@ -16,6 +17,21 @@ extension String { } } + func abbreviated(toFit label: InstructionLabel, component: VisualInstructionComponent) -> String { + let bounds = label.availableBounds() + let availableSize = CGSize(width: bounds.width, height: .greatestFiniteMagnitude) + let fittedString = self + let stringSize = fittedSize(with: availableSize, font: label.font) + + if stringSize.width < bounds.width && stringSize.height <= bounds.height { + return fittedString + } else if let abbreviation = component.abbreviation { + return abbreviation + } else { + return fittedString + } + } + func fittedSize(with size: CGSize, font: UIFont) -> CGSize { return self.boundingRect(with: size, options: [.usesLineFragmentOrigin, .usesFontLeading], attributes: [.font: font], context: nil).size } diff --git a/MapboxNavigation/InstructionPresenter.swift b/MapboxNavigation/InstructionPresenter.swift index d1735d7250..38c061a07a 100644 --- a/MapboxNavigation/InstructionPresenter.swift +++ b/MapboxNavigation/InstructionPresenter.swift @@ -22,15 +22,12 @@ class InstructionPresenter { return NSAttributedString() } - var string: [(Int, NSAttributedString)] = [] + var string: [NSAttributedString] = Array(repeating: NSAttributedString(), count: instruction.count) - var i = 0 - let sortedCompomentsOnAbbreviationPriority = instruction.map { (instruction: VisualInstructionComponent) -> (Int, (VisualInstructionComponent)) in - let f = (i, instruction) - i += 1 - return f - }.sorted { - $0.1.abbreviationPriority < $1.1.abbreviationPriority + let sortedCompomentsOnAbbreviationPriority = instruction.enumerated().map { (index: Int, instruction: VisualInstructionComponent) -> (Int, (VisualInstructionComponent)) in + return (index, instruction) + }.sorted { + $0.1.abbreviationPriority < $1.1.abbreviationPriority } for abbreivationPriotiryInstruction in sortedCompomentsOnAbbreviationPriority { @@ -44,12 +41,12 @@ class InstructionPresenter { if let shieldKey = component.shieldKey() { if let cachedImage = imageRepository.cachedImageForKey(shieldKey) { - string.append((originalPlaceInComponent, NSAttributedString(string: joinChar))) - string.append((originalPlaceInComponent, attributedString(withFont: label.font, shieldImage: cachedImage))) + string.insert(NSAttributedString(string: joinChar), at: originalPlaceInComponent) + string.insert(attributedString(withFont: label.font, shieldImage: cachedImage), at: originalPlaceInComponent) } else { // Display road code while shield is downloaded if let text = joinCharPlusText { - string.append((originalPlaceInComponent, NSAttributedString(string: (text).abbreviated(toFit: label.availableBounds(), font: label.font, possibleAbbreviation: joinCharPlusAbbreviation), attributes: attributesForLabel(label)))) + string.insert(NSAttributedString(string: (text).abbreviated(toFit: label.availableBounds(), font: label.font, possibleAbbreviation: joinCharPlusAbbreviation), attributes: attributesForLabel(label)), at: originalPlaceInComponent) } shieldImageForComponent(component, height: label.shieldHeight, completion: { [weak self] (image) in guard image != nil else { @@ -64,14 +61,12 @@ class InstructionPresenter { if component.type == .delimiter && instructionHasDownloadedAllShields() { continue } - string.append((originalPlaceInComponent, NSAttributedString(string: (text).abbreviated(toFit: label.availableBounds(), font: label.font, possibleAbbreviation: joinCharPlusAbbreviation), attributes: attributesForLabel(label)))) + string.insert(NSAttributedString(string: (text).abbreviated(toFit: label.availableBounds(), font: label.font, possibleAbbreviation: joinCharPlusAbbreviation), attributes: attributesForLabel(label)), at: originalPlaceInComponent) } } let finalString = NSMutableAttributedString() - string.sorted { $0.0 < $1.0 }.forEach { - finalString.append($0.1) - } + string.forEach { finalString.append($0) } return finalString } From a7ca4a354a125357d06ade1f9d4b32e00a775051 Mon Sep 17 00:00:00 2001 From: Bobby Sudekum Date: Fri, 2 Mar 2018 17:21:48 -0800 Subject: [PATCH 04/11] sort --- MapboxNavigation/InstructionPresenter.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MapboxNavigation/InstructionPresenter.swift b/MapboxNavigation/InstructionPresenter.swift index 38c061a07a..b6953c94b7 100644 --- a/MapboxNavigation/InstructionPresenter.swift +++ b/MapboxNavigation/InstructionPresenter.swift @@ -26,8 +26,8 @@ class InstructionPresenter { let sortedCompomentsOnAbbreviationPriority = instruction.enumerated().map { (index: Int, instruction: VisualInstructionComponent) -> (Int, (VisualInstructionComponent)) in return (index, instruction) - }.sorted { - $0.1.abbreviationPriority < $1.1.abbreviationPriority + }.sorted { + $0.1.abbreviationPriority > $1.1.abbreviationPriority } for abbreivationPriotiryInstruction in sortedCompomentsOnAbbreviationPriority { From c228a615b855acc012084ca6a9b7bc10d4ebf9aa Mon Sep 17 00:00:00 2001 From: Bobby Sudekum Date: Wed, 7 Mar 2018 14:07:51 -0800 Subject: [PATCH 05/11] Update --- Cartfile | 2 +- Cartfile.resolved | 2 +- MapboxNavigation.xcodeproj/project.pbxproj | 35 ----------------- ...structionsBannerViewIntegrationTests.swift | 38 +++++++++---------- 4 files changed, 21 insertions(+), 56 deletions(-) diff --git a/Cartfile b/Cartfile index 5bf7d377dd..21fb230ab9 100644 --- a/Cartfile +++ b/Cartfile @@ -1,5 +1,5 @@ binary "https://www.mapbox.com/ios-sdk/Mapbox-iOS-SDK.json" ~> 3.7 -github "mapbox/MapboxDirections.swift" ~> 0.17.0 +github "mapbox/MapboxDirections.swift" "master" github "mapbox/turf-swift" ~> 0.0.3 github "mapbox/mapbox-events-ios" ~> 0.3 github "ceeK/Solar" ~> 2.1.0 diff --git a/Cartfile.resolved b/Cartfile.resolved index 01242aa33f..f6a7ac2105 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,7 +1,7 @@ binary "https://www.mapbox.com/ios-sdk/Mapbox-iOS-SDK.json" "3.7.5" github "ceeK/Solar" "2.1.0" github "facebook/ios-snapshot-test-case" "2.1.4" -github "mapbox/MapboxDirections.swift" "v0.17.0" +github "mapbox/MapboxDirections.swift" "9f690d7d4246b1a05dd6c99fa07aec1f59db66e3" github "mapbox/mapbox-events-ios" "v0.3.1" github "mapbox/mapbox-voice-swift" "v0.0.1" github "mapbox/turf-swift" "v0.0.4" diff --git a/MapboxNavigation.xcodeproj/project.pbxproj b/MapboxNavigation.xcodeproj/project.pbxproj index c188cd5e1c..cb9855cfe1 100644 --- a/MapboxNavigation.xcodeproj/project.pbxproj +++ b/MapboxNavigation.xcodeproj/project.pbxproj @@ -149,7 +149,6 @@ C51DF8661F38C31C006C6A15 /* Locale.swift in Sources */ = {isa = PBXBuildFile; fileRef = C51DF8651F38C31C006C6A15 /* Locale.swift */; }; C51DF8671F38C337006C6A15 /* Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5D9800E1EFBCDAD006DBF2E /* Date.swift */; }; C520EE901EBB84F9008805BC /* Navigation.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C520EE921EBB84F9008805BC /* Navigation.storyboard */; }; - C5212B551EC4BE97009538EB /* Abbreviations.plist in Resources */ = {isa = PBXBuildFile; fileRef = C5212B571EC4BE97009538EB /* Abbreviations.plist */; }; C52AC1261DF0E48600396B9F /* RouteProgressTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C52AC1251DF0E48600396B9F /* RouteProgressTests.swift */; }; C52D09CE1DEF5E5100BE3C5C /* route.json in Resources */ = {isa = PBXBuildFile; fileRef = C52D09CD1DEF5E5100BE3C5C /* route.json */; }; C52D09D31DEF636C00BE3C5C /* Fixture.swift in Sources */ = {isa = PBXBuildFile; fileRef = C52D09D21DEF636C00BE3C5C /* Fixture.swift */; }; @@ -374,7 +373,6 @@ 3531C2691F9DDC6F00D92F9A /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Navigation.strings"; sourceTree = ""; }; 3531C26A1F9DDC6F00D92F9A /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = ""; }; 3531C26B1F9DDC6F00D92F9A /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = ""; }; - 3531C26C1F9DDC6F00D92F9A /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "pt-BR"; path = "pt-BR.lproj/Abbreviations.plist"; sourceTree = ""; }; 3531C26F1F9E095400D92F9A /* InstructionsBannerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstructionsBannerView.swift; sourceTree = ""; }; 353280A01FA72871005175F3 /* InstructionLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstructionLabel.swift; sourceTree = ""; }; 353610CD1FAB6A8F00FB1746 /* BottomBannerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomBannerView.swift; sourceTree = ""; }; @@ -393,7 +391,6 @@ 355DB5741EFA78070091BFB7 /* GGPark-to-BernalHeights.route */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; path = "GGPark-to-BernalHeights.route"; sourceTree = ""; }; 355DB5761EFA780E0091BFB7 /* UnionSquare-to-GGPark.route */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; path = "UnionSquare-to-GGPark.route"; sourceTree = ""; }; 355ED36F1FAB724F00BCE1B8 /* BottomBannerViewLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomBannerViewLayout.swift; sourceTree = ""; }; - 355EF9641EDF264200749641 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = sv; path = sv.lproj/Abbreviations.plist; sourceTree = ""; }; 356B7D8A1EE166E100FE5B89 /* scripts */ = {isa = PBXFileReference; lastKnownFileType = folder; path = scripts; sourceTree = SOURCE_ROOT; }; 35718BE31EF316BA00AFA3D1 /* tunnel.route */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; path = tunnel.route; sourceTree = ""; }; 35718BE41EF316BA00AFA3D1 /* tunnel.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = tunnel.json; sourceTree = ""; }; @@ -471,7 +468,6 @@ C51DF8651F38C31C006C6A15 /* Locale.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Locale.swift; sourceTree = ""; }; C520EE911EBB84F9008805BC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Navigation.storyboard; sourceTree = ""; }; C520EE941EBBBD55008805BC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = Base.lproj/Navigation.strings; sourceTree = ""; }; - C5212B561EC4BE97009538EB /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Base; path = Base.lproj/Abbreviations.plist; sourceTree = ""; }; C52AC1251DF0E48600396B9F /* RouteProgressTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RouteProgressTests.swift; sourceTree = ""; }; C52D09CD1DEF5E5100BE3C5C /* route.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = route.json; sourceTree = ""; }; C52D09D21DEF636C00BE3C5C /* Fixture.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Fixture.swift; sourceTree = ""; }; @@ -533,11 +529,9 @@ DA3525712011435E0048DDFC /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Main.strings; sourceTree = ""; }; DA352572201143BA0048DDFC /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Navigation.strings; sourceTree = ""; }; DA352573201143D30048DDFC /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Localizable.strings; sourceTree = ""; }; - DA352574201143EC0048DDFC /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = da; path = da.lproj/Abbreviations.plist; sourceTree = ""; }; DA545ABA1FA993DF0090908E /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Main.strings; sourceTree = ""; }; DA545ABB1FA993FB0090908E /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Main.strings; sourceTree = ""; }; DA545ABC1FA9941F0090908E /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; - DA545ABD1FA9A1300090908E /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = nl; path = nl.lproj/Abbreviations.plist; sourceTree = ""; }; DA545ABE1FA9A1370090908E /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Main.strings; sourceTree = ""; }; DA545ABF1FA9A1530090908E /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Main.strings; sourceTree = ""; }; DA545AC01FA9A15A0090908E /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = ""; }; @@ -548,7 +542,6 @@ DA5AD03C1FEBA03700FC7D7B /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = bg.lproj/Main.strings; sourceTree = ""; }; DA5AD03D1FEBA03700FC7D7B /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = bg.lproj/Main.strings; sourceTree = ""; }; DA5AD03E1FEBA03700FC7D7B /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = bg.lproj/Navigation.strings; sourceTree = ""; }; - DA5AD03F1FEBA03B00FC7D7B /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = bg; path = bg.lproj/Abbreviations.plist; sourceTree = ""; }; DA5AD0401FEBA23200FC7D7B /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = bg.lproj/Localizable.strings; sourceTree = ""; }; DA625E901F10557300FBE176 /* fa */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = fa; path = fa.lproj/Main.strings; sourceTree = ""; }; DA625E911F10559600FBE176 /* fa */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = fa; path = fa.lproj/Main.strings; sourceTree = ""; }; @@ -556,20 +549,17 @@ DA625E931F105B1900FBE176 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Main.strings; sourceTree = ""; }; DA625E941F105B1A00FBE176 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Main.strings; sourceTree = ""; }; DA625E951F105B1A00FBE176 /* fr */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Navigation.strings; sourceTree = ""; }; - DA625E971F105BC100FBE176 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = fr; path = fr.lproj/Abbreviations.plist; sourceTree = ""; }; DA625E981F105C1200FBE176 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Main.strings; sourceTree = ""; }; DA625E991F105C1300FBE176 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Main.strings; sourceTree = ""; }; DA625E9A1F105C1300FBE176 /* hu */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Navigation.strings; sourceTree = ""; }; DA625E9C1F105CB100FBE176 /* hu */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Localizable.strings; sourceTree = ""; }; DA625E9D1F105D1A00FBE176 /* lt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = lt; path = lt.lproj/Main.strings; sourceTree = ""; }; DA625E9E1F105D1A00FBE176 /* lt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = lt; path = lt.lproj/Main.strings; sourceTree = ""; }; - DA625EA31F105E3400FBE176 /* lt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = lt; path = lt.lproj/Abbreviations.plist; sourceTree = ""; }; DA625EA41F1060E300FBE176 /* ca */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/Navigation.strings; sourceTree = ""; }; DA625EA51F10614500FBE176 /* es */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Navigation.strings; sourceTree = ""; }; DA625EA71F10616600FBE176 /* es */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; DA625EA91F1061DA00FBE176 /* sv */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Navigation.strings; sourceTree = ""; }; DA625EAA1F10621A00FBE176 /* vi */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Navigation.strings; sourceTree = ""; }; - DA625EAB1F10622700FBE176 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = vi; path = vi.lproj/Abbreviations.plist; sourceTree = ""; }; DA678B7A1F6CEE6200F05913 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; DA678B7B1F6CF46600F05913 /* hu */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Localizable.strings; sourceTree = ""; }; DA678B7C1F6CF47200F05913 /* sv */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = ""; }; @@ -577,15 +567,12 @@ DA8264851F2AAD8400454B24 /* zh-Hant */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Main.strings"; sourceTree = ""; }; DA8264861F2AAD9F00454B24 /* zh-Hant */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Main.strings"; sourceTree = ""; }; DA8264871F2AADC200454B24 /* zh-Hant */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Navigation.strings"; sourceTree = ""; }; - DAA292FE1F16CB5C00D94613 /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = ca; path = ca.lproj/Abbreviations.plist; sourceTree = ""; }; DAA292FF1F16CC2200D94613 /* lt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = lt; path = lt.lproj/Navigation.strings; sourceTree = ""; }; DAA293011F16DA0C00D94613 /* es */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Main.strings; sourceTree = ""; }; DAA293021F16DA1300D94613 /* es */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Main.strings; sourceTree = ""; }; - DAA293041F16DA6A00D94613 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = es; path = es.lproj/Abbreviations.plist; sourceTree = ""; }; DAAE5F311EAE4C4700832871 /* Base */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = ""; }; DAAE5F331EAE4C5A00832871 /* zh-Hans */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; DAB2CCE61DF7AFDE001B2FE1 /* dc-line.geojson */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "dc-line.geojson"; sourceTree = ""; }; - DAB90EF4201758D600EFC92A /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = ru; path = ru.lproj/Abbreviations.plist; sourceTree = ""; }; DAC049BE201715D5004C2217 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; DAC049BF201715EA004C2217 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ru; path = Resources/ru.lproj/Localizable.stringsdict; sourceTree = ""; }; DAC049C020171886004C2217 /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/Main.strings; sourceTree = ""; }; @@ -780,7 +767,6 @@ C520EE921EBB84F9008805BC /* Navigation.storyboard */, DAAE5F321EAE4C4700832871 /* Localizable.strings */, DA35256E2010A5200048DDFC /* Localizable.stringsdict */, - C5212B571EC4BE97009538EB /* Abbreviations.plist */, ); name = Resources; sourceTree = ""; @@ -1348,7 +1334,6 @@ 351BEC291E5BD530006FE110 /* Assets.xcassets in Resources */, C520EE901EBB84F9008805BC /* Navigation.storyboard in Resources */, DA3525702010A5210048DDFC /* Localizable.stringsdict in Resources */, - C5212B551EC4BE97009538EB /* Abbreviations.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1840,26 +1825,6 @@ path = Resources; sourceTree = ""; }; - C5212B571EC4BE97009538EB /* Abbreviations.plist */ = { - isa = PBXVariantGroup; - children = ( - C5212B561EC4BE97009538EB /* Base */, - 355EF9641EDF264200749641 /* sv */, - DA625E971F105BC100FBE176 /* fr */, - DA625EA31F105E3400FBE176 /* lt */, - DA625EAB1F10622700FBE176 /* vi */, - DAA292FE1F16CB5C00D94613 /* ca */, - DAA293041F16DA6A00D94613 /* es */, - 3531C26C1F9DDC6F00D92F9A /* pt-BR */, - DA545ABD1FA9A1300090908E /* nl */, - DA5AD03F1FEBA03B00FC7D7B /* bg */, - DA352574201143EC0048DDFC /* da */, - DAB90EF4201758D600EFC92A /* ru */, - ); - name = Abbreviations.plist; - path = Resources; - sourceTree = ""; - }; C53C196F1F38EA25008DB406 /* Localizable.strings */ = { isa = PBXVariantGroup; children = ( diff --git a/MapboxNavigationTests/InstructionsBannerViewIntegrationTests.swift b/MapboxNavigationTests/InstructionsBannerViewIntegrationTests.swift index 71f3476e79..10f3e50d50 100644 --- a/MapboxNavigationTests/InstructionsBannerViewIntegrationTests.swift +++ b/MapboxNavigationTests/InstructionsBannerViewIntegrationTests.swift @@ -41,9 +41,9 @@ class InstructionsBannerViewIntegrationTests: XCTestCase { lazy var instructions = { return [ - VisualInstructionComponent(type: .destination, text: "US 41", imageURL: shieldURL1, maneuverType: .none, maneuverDirection: .none), - VisualInstructionComponent(type: .delimiter, text: "/", imageURL: nil, maneuverType: .none, maneuverDirection: .none), - VisualInstructionComponent(type: .destination, text: "I 94", imageURL: shieldURL2, maneuverType: .none, maneuverDirection: .none) + VisualInstructionComponent(type: .text, text: "US 41", imageURL: shieldURL1, maneuverType: .none, maneuverDirection: .none, abbreviation: nil, abbreviationPriority: 0), + VisualInstructionComponent(type: .delimiter, text: "/", imageURL: nil, maneuverType: .none, maneuverDirection: .none, abbreviation: nil, abbreviationPriority: 0), + VisualInstructionComponent(type: .text, text: "I 94", imageURL: shieldURL2, maneuverType: .none, maneuverDirection: .none, abbreviation: nil, abbreviationPriority: 0) ] }() @@ -77,8 +77,8 @@ class InstructionsBannerViewIntegrationTests: XCTestCase { func testDelimiterIsHiddenWhenAllShieldsAreAlreadyLoaded() { //prime the cache to simulate images having already been loaded - let instruction1 = VisualInstructionComponent(type: .destination, text: nil, imageURL: shieldURL1, maneuverType: .none, maneuverDirection: .none) - let instruction2 = VisualInstructionComponent(type: .destination, text: nil, imageURL: shieldURL2, maneuverType: .none, maneuverDirection: .none) + let instruction1 = VisualInstructionComponent(type: .text, text: nil, imageURL: shieldURL1, maneuverType: .none, maneuverDirection: .none, abbreviation: nil, abbreviationPriority: 0) + let instruction2 = VisualInstructionComponent(type: .text, text: nil, imageURL: shieldURL2, maneuverType: .none, maneuverDirection: .none, abbreviation: nil, abbreviationPriority: 0) imageRepository.storeImage(shieldImage, forKey: instruction1.shieldKey()!, toDisk: false) imageRepository.storeImage(shieldImage, forKey: instruction2.shieldKey()!, toDisk: false) @@ -134,7 +134,7 @@ class InstructionsBannerViewSnapshotTests: FBSnapshotTestCase { super.setUp() recordMode = false - let instruction = VisualInstructionComponent(type: .destination, text: nil, imageURL: shieldURL, maneuverType: .turn, maneuverDirection: .right) + let instruction = VisualInstructionComponent(type: .text, text: nil, imageURL: shieldURL, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0) let shieldKey = instruction.shieldKey() imageRepository.storeImage(shieldImage, forKey: shieldKey!, toDisk: false) @@ -158,9 +158,9 @@ class InstructionsBannerViewSnapshotTests: FBSnapshotTestCase { view.distance = 482 let instructions = [ - VisualInstructionComponent(type: .destination, text: "US 45", imageURL: nil, maneuverType: .turn, maneuverDirection: .right), - VisualInstructionComponent(type: .destination, text: "/", imageURL: nil, maneuverType: .turn, maneuverDirection: .right), - VisualInstructionComponent(type: .destination, text: "Chicago", imageURL: nil, maneuverType: .turn, maneuverDirection: .right) + VisualInstructionComponent(type: .text, text: "US 45", imageURL: nil, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0), + VisualInstructionComponent(type: .text, text: "/", imageURL: nil, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0), + VisualInstructionComponent(type: .text, text: "Chicago", imageURL: nil, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0) ] view.set(makeVisualInstruction(primaryInstruction: instructions, secondaryInstruction: nil)) @@ -176,8 +176,8 @@ class InstructionsBannerViewSnapshotTests: FBSnapshotTestCase { view.distance = 482 let instructions = [ - VisualInstructionComponent(type: .destination, text: "I 280", imageURL: shieldURL, maneuverType: .turn, maneuverDirection: .right), - VisualInstructionComponent(type: .destination, text: "US 45 / Chicago / US 45 / Chicago", imageURL: nil, maneuverType: .turn, maneuverDirection: .right) + VisualInstructionComponent(type: .text, text: "I 280", imageURL: shieldURL, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0), + VisualInstructionComponent(type: .text, text: "US 45 / Chicago / US 45 / Chicago", imageURL: nil, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0) ] view.set(makeVisualInstruction(primaryInstruction: instructions, secondaryInstruction: nil)) @@ -193,10 +193,10 @@ class InstructionsBannerViewSnapshotTests: FBSnapshotTestCase { view.distance = 482 let primary = [ - VisualInstructionComponent(type: .destination, text: "I 280", imageURL: shieldURL, maneuverType: .turn, maneuverDirection: .right), - VisualInstructionComponent(type: .destination, text: "South", imageURL: nil, maneuverType: .turn, maneuverDirection: .right) + VisualInstructionComponent(type: .text, text: "I 280", imageURL: shieldURL, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0), + VisualInstructionComponent(type: .text, text: "South", imageURL: nil, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0) ] - let secondary = [VisualInstructionComponent(type: .destination, text: "US 45 / Chicago", imageURL: nil, maneuverType: .turn, maneuverDirection: .right)] + let secondary = [VisualInstructionComponent(type: .text, text: "US 45 / Chicago", imageURL: nil, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0)] view.set(makeVisualInstruction(primaryInstruction: primary, secondaryInstruction: secondary)) @@ -211,9 +211,9 @@ class InstructionsBannerViewSnapshotTests: FBSnapshotTestCase { view.distance = 482 let primary = [ - VisualInstructionComponent(type: .destination, text: "I 280", imageURL: shieldURL, maneuverType: .turn, maneuverDirection: .right) + VisualInstructionComponent(type: .text, text: "I 280", imageURL: shieldURL, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0) ] - let secondary = [VisualInstructionComponent(type: .destination, text: "Mountain View Test", imageURL: nil, maneuverType: .turn, maneuverDirection: .right)] + let secondary = [VisualInstructionComponent(type: .text, text: "Mountain View Test", imageURL: nil, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0)] view.set(makeVisualInstruction(primaryInstruction: primary, secondaryInstruction: secondary)) @@ -235,14 +235,14 @@ class InstructionsBannerViewSnapshotTests: FBSnapshotTestCase { instructionsBannerView.distance = 482 let primary = [ - VisualInstructionComponent(type: .destination, text: "I 280", imageURL: shieldURL, maneuverType: .turn, maneuverDirection: .right) + VisualInstructionComponent(type: .text, text: "I 280", imageURL: shieldURL, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0) ] - let secondary = [VisualInstructionComponent(type: .destination, text: "US 45 / Chicago", imageURL: nil, maneuverType: .turn, maneuverDirection: .right)] + let secondary = [VisualInstructionComponent(type: .text, text: "US 45 / Chicago", imageURL: nil, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0)] instructionsBannerView.set(makeVisualInstruction(primaryInstruction: primary, secondaryInstruction: secondary)) let primaryThen = [ - VisualInstructionComponent(type: .destination, text: "I 280", imageURL: shieldURL, maneuverType: .turn, maneuverDirection: .right) + VisualInstructionComponent(type: .text, text: "I 280", imageURL: shieldURL, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0) ] nextBannerView.instructionLabel.instruction = primaryThen From 88fdb3c69352b8d983bafc77786585ad301345c0 Mon Sep 17 00:00:00 2001 From: Fredrik Karlsson Date: Thu, 8 Mar 2018 12:35:26 -0500 Subject: [PATCH 06/11] Split up banner tests and tweak abbreviations --- MapboxNavigation.xcodeproj/project.pbxproj | 8 +- MapboxNavigation/Abbreviations.swift | 38 ---- MapboxNavigation/InstructionPresenter.swift | 85 ++++++--- MapboxNavigation/InstructionsBannerView.swift | 2 +- ...structionsBannerViewIntegrationTests.swift | 154 --------------- .../InstructionsBannerViewSnapshotTests.swift | 179 ++++++++++++++++++ .../testAbbreviateInstructions@3x.png | Bin 0 -> 38660 bytes 7 files changed, 242 insertions(+), 224 deletions(-) delete mode 100644 MapboxNavigation/Abbreviations.swift create mode 100644 MapboxNavigationTests/InstructionsBannerViewSnapshotTests.swift create mode 100644 MapboxNavigationTests/ReferenceImages_64/MapboxNavigationTests.InstructionsBannerViewSnapshotTests/testAbbreviateInstructions@3x.png diff --git a/MapboxNavigation.xcodeproj/project.pbxproj b/MapboxNavigation.xcodeproj/project.pbxproj index cb9855cfe1..4f8f500ee2 100644 --- a/MapboxNavigation.xcodeproj/project.pbxproj +++ b/MapboxNavigation.xcodeproj/project.pbxproj @@ -91,6 +91,7 @@ 359D00CF1E732D7100C2E770 /* Polyline.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 354A01BC1E66259600D765C2 /* Polyline.framework */; }; 359D1B281FFE70D30052FA42 /* NavigationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 359D1B271FFE70D30052FA42 /* NavigationView.swift */; }; 359D283C1F9DC14F00FDE9C9 /* UICollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 359D283B1F9DC14F00FDE9C9 /* UICollectionView.swift */; }; + 35A262B92050A5CD00AEFF6D /* InstructionsBannerViewSnapshotTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35A262B82050A5CD00AEFF6D /* InstructionsBannerViewSnapshotTests.swift */; }; 35A5413B1EFC052700E49846 /* RouteOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35A5413A1EFC052700E49846 /* RouteOptions.swift */; }; 35B1E2951F1FF8EC00A13D32 /* UserCourseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35B1E2941F1FF8EC00A13D32 /* UserCourseView.swift */; }; 35B5A47E1FFFDCE5000A3C8D /* NavigationViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35B5A47D1FFFDCE5000A3C8D /* NavigationViewLayout.swift */; }; @@ -143,7 +144,6 @@ 8DB63A3A1FBBCA2200928389 /* RatingControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DB63A391FBBCA2200928389 /* RatingControl.swift */; }; 8DE879661FBB9980002F06C0 /* EndOfRouteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DE879651FBB9980002F06C0 /* EndOfRouteViewController.swift */; }; 8DF399B21FB257B30034904C /* UIGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DF399B11FB257B30034904C /* UIGestureRecognizer.swift */; }; - C5000A931EC25C6E00563EA9 /* Abbreviations.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5000A921EC25C6E00563EA9 /* Abbreviations.swift */; }; C51245F21F19471C00E33B52 /* MapboxMobileEvents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C549F8311F17F2C5001A0A2D /* MapboxMobileEvents.framework */; }; C51245F31F19471C00E33B52 /* MapboxMobileEvents.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C549F8311F17F2C5001A0A2D /* MapboxMobileEvents.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; C51DF8661F38C31C006C6A15 /* Locale.swift in Sources */ = {isa = PBXBuildFile; fileRef = C51DF8651F38C31C006C6A15 /* Locale.swift */; }; @@ -408,6 +408,7 @@ 359D1B271FFE70D30052FA42 /* NavigationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationView.swift; sourceTree = ""; }; 359D283B1F9DC14F00FDE9C9 /* UICollectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UICollectionView.swift; sourceTree = ""; }; 35A1D3651E6624EF00A48FE8 /* Mapbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Mapbox.framework; path = Carthage/Build/iOS/Mapbox.framework; sourceTree = ""; }; + 35A262B82050A5CD00AEFF6D /* InstructionsBannerViewSnapshotTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstructionsBannerViewSnapshotTests.swift; sourceTree = ""; }; 35A5413A1EFC052700E49846 /* RouteOptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RouteOptions.swift; sourceTree = ""; }; 35B1E2941F1FF8EC00A13D32 /* UserCourseView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserCourseView.swift; sourceTree = ""; }; 35B5A47D1FFFDCE5000A3C8D /* NavigationViewLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationViewLayout.swift; sourceTree = ""; }; @@ -464,7 +465,6 @@ 8DB63A391FBBCA2200928389 /* RatingControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RatingControl.swift; sourceTree = ""; }; 8DE879651FBB9980002F06C0 /* EndOfRouteViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EndOfRouteViewController.swift; sourceTree = ""; }; 8DF399B11FB257B30034904C /* UIGestureRecognizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIGestureRecognizer.swift; sourceTree = ""; }; - C5000A921EC25C6E00563EA9 /* Abbreviations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Abbreviations.swift; sourceTree = ""; }; C51DF8651F38C31C006C6A15 /* Locale.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Locale.swift; sourceTree = ""; }; C520EE911EBB84F9008805BC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Navigation.storyboard; sourceTree = ""; }; C520EE941EBBBD55008805BC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = Base.lproj/Navigation.strings; sourceTree = ""; }; @@ -847,6 +847,7 @@ 3540514E1F73F3F300ED572D /* ManeuverViewTests.swift */, 35B711D11E5E7AD2001EDA8D /* MapboxNavigationTests.swift */, 35F1F5921FD57EFD00F8E502 /* StyleManagerTests.swift */, + 35A262B82050A5CD00AEFF6D /* InstructionsBannerViewSnapshotTests.swift */, ); path = MapboxNavigationTests; sourceTree = ""; @@ -880,7 +881,6 @@ C51923B41EA55C5E002AF9E1 /* Extensions */ = { isa = PBXGroup; children = ( - C5000A921EC25C6E00563EA9 /* Abbreviations.swift */, 351BEC081E5BCC72006FE110 /* Bundle.swift */, 8D24A2F920449B430098CBF8 /* Dictionary.swift */, 8D24A2F52040960C0098CBF8 /* UIEdgeInsets.swift */, @@ -1520,7 +1520,6 @@ 35D428291FA0B61F00176028 /* InstructionsBannerViewLayout.swift in Sources */, C54C655220336F2600D338E0 /* Constants.swift in Sources */, 353610CE1FAB6A8F00FB1746 /* BottomBannerView.swift in Sources */, - C5000A931EC25C6E00563EA9 /* Abbreviations.swift in Sources */, C58822001FB0F0D7008B0A2D /* Error.swift in Sources */, 35C9973F1E732C1B00544D1C /* RouteVoiceController.swift in Sources */, 8D24A2FA20449B430098CBF8 /* Dictionary.swift in Sources */, @@ -1622,6 +1621,7 @@ files = ( 35DC585D1FABC61100B5A956 /* InstructionsBannerViewIntegrationTests.swift in Sources */, 1662244720256C0700EA4824 /* TestImageLoadingURLProtocol.swift in Sources */, + 35A262B92050A5CD00AEFF6D /* InstructionsBannerViewSnapshotTests.swift in Sources */, 35F1F5931FD57EFD00F8E502 /* StyleManagerTests.swift in Sources */, 16A509D5202A87B20011D788 /* ImageDownloaderTests.swift in Sources */, 166224452025699600EA4824 /* ImageRepositoryTests.swift in Sources */, diff --git a/MapboxNavigation/Abbreviations.swift b/MapboxNavigation/Abbreviations.swift deleted file mode 100644 index 0ff06e5f5a..0000000000 --- a/MapboxNavigation/Abbreviations.swift +++ /dev/null @@ -1,38 +0,0 @@ -import UIKit -import MapboxDirections - -extension String { - /// Returns the string abbreviated only as much as necessary to fit the given width and font. - func abbreviated(toFit bounds: CGRect, font: UIFont, possibleAbbreviation: String?) -> String { - let availableSize = CGSize(width: bounds.width, height: .greatestFiniteMagnitude) - let fittedString = self - let stringSize = fittedSize(with: availableSize, font: font) - - if stringSize.width < bounds.width && stringSize.height <= bounds.height { - return fittedString - } else if let possibleAbbreviation = possibleAbbreviation { - return possibleAbbreviation - } else { - return fittedString - } - } - - func abbreviated(toFit label: InstructionLabel, component: VisualInstructionComponent) -> String { - let bounds = label.availableBounds() - let availableSize = CGSize(width: bounds.width, height: .greatestFiniteMagnitude) - let fittedString = self - let stringSize = fittedSize(with: availableSize, font: label.font) - - if stringSize.width < bounds.width && stringSize.height <= bounds.height { - return fittedString - } else if let abbreviation = component.abbreviation { - return abbreviation - } else { - return fittedString - } - } - - func fittedSize(with size: CGSize, font: UIFont) -> CGSize { - return self.boundingRect(with: size, options: [.usesLineFragmentOrigin, .usesFontLeading], attributes: [.font: font], context: nil).size - } -} diff --git a/MapboxNavigation/InstructionPresenter.swift b/MapboxNavigation/InstructionPresenter.swift index b6953c94b7..5c9cc2f1f0 100644 --- a/MapboxNavigation/InstructionPresenter.swift +++ b/MapboxNavigation/InstructionPresenter.swift @@ -15,38 +15,58 @@ class InstructionPresenter { private let imageRepository = ImageRepository.shared - var currentPriorityLevel: Int? = nil - func attributedText() -> NSAttributedString { - guard let label = self.label else { - return NSAttributedString() - } - - var string: [NSAttributedString] = Array(repeating: NSAttributedString(), count: instruction.count) + let string = NSMutableAttributedString() + fittedAttributedComponents().forEach { string.append($0) } + return string + } + + func fittedAttributedComponents() -> [NSAttributedString] { + guard let label = self.label else { return [] } + var attrComponents = attributedComponents() + let availableBounds = label.availableBounds() + let totalWidth = attrComponents.map { $0.size() }.reduce(.zero, +).width + let stringFits = totalWidth <= availableBounds.width - let sortedCompomentsOnAbbreviationPriority = instruction.enumerated().map { (index: Int, instruction: VisualInstructionComponent) -> (Int, (VisualInstructionComponent)) in - return (index, instruction) - }.sorted { - $0.1.abbreviationPriority > $1.1.abbreviationPriority + if stringFits { + return attrComponents + } else { + let indexedComponents = instruction.enumerated().map { IndexedVisualInstructionComponent(component: $1, index: $0) } + let filtered = indexedComponents.filter { $0.component.abbreviation != nil } + let sorted = filtered.sorted { $0.component.abbreviationPriority < $1.component.abbreviationPriority } + for component in sorted { + let isFirst = component.index == 0 + let joinChar = isFirst ? "" : " " + guard component.component.type == .text else { continue } + guard let abbreviation = component.component.abbreviation else { continue } + attrComponents[component.index] = NSAttributedString(string: joinChar + abbreviation, attributes: attributesForLabel(label)) + let newWidth = attrComponents.map { $0.size() }.reduce(.zero, +).width + + if newWidth <= availableBounds.width { + break + } + } + + return attrComponents } + } + + func attributedComponents() -> [NSAttributedString] { + guard let label = self.label else { return [NSAttributedString()] } + var strings = [NSAttributedString]() + let components = instruction - for abbreivationPriotiryInstruction in sortedCompomentsOnAbbreviationPriority { - let component = abbreivationPriotiryInstruction.1 - let originalPlaceInComponent = abbreivationPriotiryInstruction.0 + for component in components { let isFirst = component == instruction.first - let joinChar = !isFirst ? " " : "" + let joinChar = isFirst ? "" : " " - let joinCharPlusAbbreviation = component.abbreviation != nil ? joinChar + component.abbreviation! : nil - let joinCharPlusText = component.text != nil ? joinChar + component.text! : nil - if let shieldKey = component.shieldKey() { if let cachedImage = imageRepository.cachedImageForKey(shieldKey) { - string.insert(NSAttributedString(string: joinChar), at: originalPlaceInComponent) - string.insert(attributedString(withFont: label.font, shieldImage: cachedImage), at: originalPlaceInComponent) + strings.append(attributedString(withFont: label.font, shieldImage: cachedImage)) } else { // Display road code while shield is downloaded - if let text = joinCharPlusText { - string.insert(NSAttributedString(string: (text).abbreviated(toFit: label.availableBounds(), font: label.font, possibleAbbreviation: joinCharPlusAbbreviation), attributes: attributesForLabel(label)), at: originalPlaceInComponent) + if let text = component.text { + strings.append(NSAttributedString(string: joinChar + text, attributes: attributesForLabel(label))) } shieldImageForComponent(component, height: label.shieldHeight, completion: { [weak self] (image) in guard image != nil else { @@ -57,17 +77,15 @@ class InstructionPresenter { } }) } - } else if let text = joinCharPlusText { + } else if let text = component.text { if component.type == .delimiter && instructionHasDownloadedAllShields() { continue } - string.insert(NSAttributedString(string: (text).abbreviated(toFit: label.availableBounds(), font: label.font, possibleAbbreviation: joinCharPlusAbbreviation), attributes: attributesForLabel(label)), at: originalPlaceInComponent) + strings.append(NSAttributedString(string: (joinChar + text), attributes: attributesForLabel(label))) } } - let finalString = NSMutableAttributedString() - string.forEach { finalString.append($0) } - return finalString + return strings } private func shieldImageForComponent(_ component: VisualInstructionComponent, height: CGFloat, completion: @escaping (UIImage?) -> Void) { @@ -119,3 +137,16 @@ class ShieldAttachment: NSTextAttachment { } } +extension CGSize { + fileprivate static var greatestFiniteSize = CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude) + + fileprivate static func +(lhs: CGSize, rhs: CGSize) -> CGSize { + return CGSize(width: lhs.width + rhs.width, height: lhs.height + rhs.height) + } +} + + +fileprivate struct IndexedVisualInstructionComponent { + let component: Array.Element + let index: Array.Index +} diff --git a/MapboxNavigation/InstructionsBannerView.swift b/MapboxNavigation/InstructionsBannerView.swift index 52c431ceec..8691867cb4 100644 --- a/MapboxNavigation/InstructionsBannerView.swift +++ b/MapboxNavigation/InstructionsBannerView.swift @@ -63,7 +63,7 @@ open class BaseInstructionsBannerView: UIControl { func set(_ instruction: VisualInstruction?) { let secondaryInstruction = instruction?.secondaryTextComponents - primaryLabel.numberOfLines = 1 + primaryLabel.numberOfLines = secondaryInstruction == nil ? 2 : 1 if secondaryInstruction == nil { centerYAlignInstructions() diff --git a/MapboxNavigationTests/InstructionsBannerViewIntegrationTests.swift b/MapboxNavigationTests/InstructionsBannerViewIntegrationTests.swift index 10f3e50d50..b25c65ee0f 100644 --- a/MapboxNavigationTests/InstructionsBannerViewIntegrationTests.swift +++ b/MapboxNavigationTests/InstructionsBannerViewIntegrationTests.swift @@ -122,157 +122,3 @@ class InstructionsBannerViewIntegrationTests: XCTestCase { } } - -class InstructionsBannerViewSnapshotTests: FBSnapshotTestCase { - - let shieldURL = URL(string: "https://s3.amazonaws.com/mapbox/shields/v3/i-280@3x.png")! - let imageRepository: ImageRepository = ImageRepository.shared - - let asyncTimeout: TimeInterval = 2.0 - - override func setUp() { - super.setUp() - recordMode = false - - let instruction = VisualInstructionComponent(type: .text, text: nil, imageURL: shieldURL, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0) - let shieldKey = instruction.shieldKey() - - imageRepository.storeImage(shieldImage, forKey: shieldKey!, toDisk: false) - } - - override func tearDown() { - super.tearDown() - - let clearImageCacheExpectation = self.expectation(description: "Clear Image Cache") - imageRepository.resetImageCache { - clearImageCacheExpectation.fulfill() - } - self.wait(for: [clearImageCacheExpectation], timeout: asyncTimeout) - } - - func testSinglelinePrimary() { - let view = instructionsView() - styleInstructionsView(view) - - view.maneuverView.isStart = true - view.distance = 482 - - let instructions = [ - VisualInstructionComponent(type: .text, text: "US 45", imageURL: nil, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0), - VisualInstructionComponent(type: .text, text: "/", imageURL: nil, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0), - VisualInstructionComponent(type: .text, text: "Chicago", imageURL: nil, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0) - ] - - view.set(makeVisualInstruction(primaryInstruction: instructions, secondaryInstruction: nil)) - - verifyView(view, size: view.bounds.size) - } - - func testMultilinePrimary() { - let view = instructionsView() - styleInstructionsView(view) - - view.maneuverView.isStart = true - view.distance = 482 - - let instructions = [ - VisualInstructionComponent(type: .text, text: "I 280", imageURL: shieldURL, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0), - VisualInstructionComponent(type: .text, text: "US 45 / Chicago / US 45 / Chicago", imageURL: nil, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0) - ] - - view.set(makeVisualInstruction(primaryInstruction: instructions, secondaryInstruction: nil)) - - verifyView(view, size: view.bounds.size) - } - - func testSinglelinePrimaryAndSecondary() { - let view = instructionsView() - styleInstructionsView(view) - - view.maneuverView.isStart = true - view.distance = 482 - - let primary = [ - VisualInstructionComponent(type: .text, text: "I 280", imageURL: shieldURL, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0), - VisualInstructionComponent(type: .text, text: "South", imageURL: nil, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0) - ] - let secondary = [VisualInstructionComponent(type: .text, text: "US 45 / Chicago", imageURL: nil, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0)] - - view.set(makeVisualInstruction(primaryInstruction: primary, secondaryInstruction: secondary)) - - verifyView(view, size: view.bounds.size) - } - - func testPrimaryShieldAndSecondary() { - let view = instructionsView() - styleInstructionsView(view) - - view.maneuverView.isStart = true - view.distance = 482 - - let primary = [ - VisualInstructionComponent(type: .text, text: "I 280", imageURL: shieldURL, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0) - ] - let secondary = [VisualInstructionComponent(type: .text, text: "Mountain View Test", imageURL: nil, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0)] - - view.set(makeVisualInstruction(primaryInstruction: primary, secondaryInstruction: secondary)) - - verifyView(view, size: view.bounds.size) - } - - func testInstructionsAndNextInstructions() { - let view = UIView() - view.backgroundColor = .white - let instructionsBannerView = instructionsView() - let nextBannerViewFrame = CGRect(x: 0, y: instructionsBannerView.frame.maxY, width: instructionsBannerView.bounds.width, height: 44) - let nextBannerView = NextBannerView(frame: nextBannerViewFrame) - nextBannerView.translatesAutoresizingMaskIntoConstraints = true - view.addSubview(instructionsBannerView) - view.addSubview(nextBannerView) - view.frame = CGRect(origin: .zero, size: CGSize(width: nextBannerViewFrame.width, height: nextBannerViewFrame.maxY)) - - instructionsBannerView.maneuverView.isStart = true - instructionsBannerView.distance = 482 - - let primary = [ - VisualInstructionComponent(type: .text, text: "I 280", imageURL: shieldURL, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0) - ] - let secondary = [VisualInstructionComponent(type: .text, text: "US 45 / Chicago", imageURL: nil, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0)] - - instructionsBannerView.set(makeVisualInstruction(primaryInstruction: primary, secondaryInstruction: secondary)) - - let primaryThen = [ - VisualInstructionComponent(type: .text, text: "I 280", imageURL: shieldURL, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0) - ] - - nextBannerView.instructionLabel.instruction = primaryThen - nextBannerView.maneuverView.backgroundColor = .clear - nextBannerView.maneuverView.isEnd = true - - verifyView(view, size: view.bounds.size) - } -} - -extension InstructionsBannerViewSnapshotTests { - - func verifyView(_ view: UIView, size: CGSize) { - view.frame.size = size - FBSnapshotVerifyView(view) - } - - // UIAppearance proxy do not work in unit test environment so we have to style manually - func styleInstructionsView(_ view: InstructionsBannerView) { - view.backgroundColor = .white - view.maneuverView.backgroundColor = #colorLiteral(red: 0.5882352941, green: 0.5882352941, blue: 0.5882352941, alpha: 0.5) - view.distanceLabel.backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 0.5) - view.primaryLabel.backgroundColor = #colorLiteral(red: 0.5882352941, green: 0.5882352941, blue: 0.5882352941, alpha: 0.5) - view.secondaryLabel.backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 0.5) - view.dividerView.backgroundColor = .red - view._separatorView.backgroundColor = .red - - view.distanceLabel.valueFont = UIFont.systemFont(ofSize: 24) - view.distanceLabel.unitFont = UIFont.systemFont(ofSize: 14) - view.primaryLabel.font = UIFont.systemFont(ofSize: 30, weight: .medium) - view.secondaryLabel.font = UIFont.systemFont(ofSize: 26, weight: .medium) - } -} diff --git a/MapboxNavigationTests/InstructionsBannerViewSnapshotTests.swift b/MapboxNavigationTests/InstructionsBannerViewSnapshotTests.swift new file mode 100644 index 0000000000..96b7be021e --- /dev/null +++ b/MapboxNavigationTests/InstructionsBannerViewSnapshotTests.swift @@ -0,0 +1,179 @@ +import XCTest +import FBSnapshotTestCase +import MapboxDirections +@testable import MapboxNavigation +@testable import MapboxCoreNavigation + +class InstructionsBannerViewSnapshotTests: FBSnapshotTestCase { + + let shieldURL = URL(string: "https://s3.amazonaws.com/mapbox/shields/v3/i-280@3x.png")! + let imageRepository: ImageRepository = ImageRepository.shared + + let asyncTimeout: TimeInterval = 2.0 + + override func setUp() { + super.setUp() + recordMode = false + + let instruction = VisualInstructionComponent(type: .text, text: nil, imageURL: shieldURL, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0) + let shieldKey = instruction.shieldKey() + + imageRepository.storeImage(shieldImage, forKey: shieldKey!, toDisk: false) + } + + override func tearDown() { + super.tearDown() + + let clearImageCacheExpectation = self.expectation(description: "Clear Image Cache") + imageRepository.resetImageCache { + clearImageCacheExpectation.fulfill() + } + self.wait(for: [clearImageCacheExpectation], timeout: asyncTimeout) + } + + func testSinglelinePrimary() { + let view = instructionsView() + styleInstructionsView(view) + + view.maneuverView.isStart = true + view.distance = 482 + + let instructions = [ + VisualInstructionComponent(type: .text, text: "US 45", imageURL: nil, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0), + VisualInstructionComponent(type: .text, text: "/", imageURL: nil, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0), + VisualInstructionComponent(type: .text, text: "Chicago", imageURL: nil, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0) + ] + + view.set(makeVisualInstruction(primaryInstruction: instructions, secondaryInstruction: nil)) + + verifyView(view, size: view.bounds.size) + } + + func testMultilinePrimary() { + let view = instructionsView() + styleInstructionsView(view) + + view.maneuverView.isStart = true + view.distance = 482 + + let instructions = [ + VisualInstructionComponent(type: .text, text: "I 280", imageURL: shieldURL, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0), + VisualInstructionComponent(type: .text, text: "US 45 / Chicago / US 45 / Chicago", imageURL: nil, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0) + ] + + view.set(makeVisualInstruction(primaryInstruction: instructions, secondaryInstruction: nil)) + + verifyView(view, size: view.bounds.size) + } + + func testSinglelinePrimaryAndSecondary() { + let view = instructionsView() + styleInstructionsView(view) + + view.maneuverView.isStart = true + view.distance = 482 + + let primary = [ + VisualInstructionComponent(type: .text, text: "I 280", imageURL: shieldURL, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0), + VisualInstructionComponent(type: .text, text: "South", imageURL: nil, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0) + ] + let secondary = [VisualInstructionComponent(type: .text, text: "US 45 / Chicago", imageURL: nil, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0)] + + view.set(makeVisualInstruction(primaryInstruction: primary, secondaryInstruction: secondary)) + + verifyView(view, size: view.bounds.size) + } + + func testPrimaryShieldAndSecondary() { + let view = instructionsView() + styleInstructionsView(view) + + view.maneuverView.isStart = true + view.distance = 482 + + let primary = [ + VisualInstructionComponent(type: .text, text: "I 280", imageURL: shieldURL, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0) + ] + let secondary = [VisualInstructionComponent(type: .text, text: "Mountain View Test", imageURL: nil, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0)] + + view.set(makeVisualInstruction(primaryInstruction: primary, secondaryInstruction: secondary)) + + verifyView(view, size: view.bounds.size) + } + + func testAbbreviateInstructions() { + let view = instructionsView() + styleInstructionsView(view) + + view.maneuverView.isStart = true + view.distance = 482 + + let primary = [VisualInstructionComponent(type: .image, text: "I-280", imageURL: shieldURL, maneuverType: .none, maneuverDirection: .none, abbreviation: nil, abbreviationPriority: NSNotFound), + VisualInstructionComponent(type: .text, text: "Drive", imageURL: nil, maneuverType: .none, maneuverDirection: .none, abbreviation: "Dr", abbreviationPriority: 0), + VisualInstructionComponent(type: .text, text: "Avenue", imageURL: nil, maneuverType: .none, maneuverDirection: .none, abbreviation: "Ave", abbreviationPriority: 5), + VisualInstructionComponent(type: .text, text: "West", imageURL: nil, maneuverType: .none, maneuverDirection: .none, abbreviation: "W", abbreviationPriority: 4), + VisualInstructionComponent(type: .text, text: "South", imageURL: nil, maneuverType: .none, maneuverDirection: .none, abbreviation: "S", abbreviationPriority: 3), + VisualInstructionComponent(type: .text, text: "East", imageURL: nil, maneuverType: .none, maneuverDirection: .none, abbreviation: "E", abbreviationPriority: 2), + VisualInstructionComponent(type: .text, text: "North", imageURL: nil, maneuverType: .none, maneuverDirection: .none, abbreviation: "N", abbreviationPriority: 1)] + + view.set(makeVisualInstruction(primaryInstruction: primary, secondaryInstruction: nil)) + + verifyView(view, size: view.bounds.size) + } + + func testInstructionsAndNextInstructions() { + let view = UIView() + view.backgroundColor = .white + let instructionsBannerView = instructionsView() + let nextBannerViewFrame = CGRect(x: 0, y: instructionsBannerView.frame.maxY, width: instructionsBannerView.bounds.width, height: 44) + let nextBannerView = NextBannerView(frame: nextBannerViewFrame) + nextBannerView.translatesAutoresizingMaskIntoConstraints = true + view.addSubview(instructionsBannerView) + view.addSubview(nextBannerView) + view.frame = CGRect(origin: .zero, size: CGSize(width: nextBannerViewFrame.width, height: nextBannerViewFrame.maxY)) + + instructionsBannerView.maneuverView.isStart = true + instructionsBannerView.distance = 482 + + let primary = [ + VisualInstructionComponent(type: .text, text: "I 280", imageURL: shieldURL, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0) + ] + let secondary = [VisualInstructionComponent(type: .text, text: "US 45 / Chicago", imageURL: nil, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0)] + + instructionsBannerView.set(makeVisualInstruction(primaryInstruction: primary, secondaryInstruction: secondary)) + + let primaryThen = [ + VisualInstructionComponent(type: .text, text: "I 280", imageURL: shieldURL, maneuverType: .turn, maneuverDirection: .right, abbreviation: nil, abbreviationPriority: 0) + ] + + nextBannerView.instructionLabel.instruction = primaryThen + nextBannerView.maneuverView.backgroundColor = .clear + nextBannerView.maneuverView.isEnd = true + + verifyView(view, size: view.bounds.size) + } +} + +extension InstructionsBannerViewSnapshotTests { + + func verifyView(_ view: UIView, size: CGSize) { + view.frame.size = size + FBSnapshotVerifyView(view) + } + + // UIAppearance proxy do not work in unit test environment so we have to style manually + func styleInstructionsView(_ view: InstructionsBannerView) { + view.backgroundColor = .white + view.maneuverView.backgroundColor = #colorLiteral(red: 0.5882352941, green: 0.5882352941, blue: 0.5882352941, alpha: 0.5) + view.distanceLabel.backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 0.5) + view.primaryLabel.backgroundColor = #colorLiteral(red: 0.5882352941, green: 0.5882352941, blue: 0.5882352941, alpha: 0.5) + view.secondaryLabel.backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 0.5) + view.dividerView.backgroundColor = .red + view._separatorView.backgroundColor = .red + + view.distanceLabel.valueFont = UIFont.systemFont(ofSize: 24) + view.distanceLabel.unitFont = UIFont.systemFont(ofSize: 14) + view.primaryLabel.font = UIFont.systemFont(ofSize: 30, weight: .medium) + view.secondaryLabel.font = UIFont.systemFont(ofSize: 26, weight: .medium) + } +} diff --git a/MapboxNavigationTests/ReferenceImages_64/MapboxNavigationTests.InstructionsBannerViewSnapshotTests/testAbbreviateInstructions@3x.png b/MapboxNavigationTests/ReferenceImages_64/MapboxNavigationTests.InstructionsBannerViewSnapshotTests/testAbbreviateInstructions@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..2482ff03abba80dc362546f30e49bc12422d7742 GIT binary patch literal 38660 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 C63qcgo#Q9WB}} zu0qv0#L!0Y^!7$0AimeGGV5kp_U+uY%HD{xii$sf6!HxNL8W--oZR*~&BZ zos&muaiAu24Qz`$^IcR(Bj5359KO8qfpYBT!$a`8T}=P9LRzNe#zc8igq3BV7*n+` zfrR&VdemUaQ(V`MRAS}$6zcQBA^V%dqw???24DRfTNM7(%rshwUfbC`+yXJSXv}l> zfnvL*O=!rDli{+^u`!i^=WO3ZA~s)2n2pC&6S!C>5vSaj3hdUq(t97>~yxQ@Mj5jZL!; zUir%ispJ@zppAXgPygKLAz5);}CZw1&piZc#<42ICMX%!Lg`z>8s zAc(NHk5_zcEw*{^U_G3w_bmZsEj?o>G5_IbDH{jTk4JZRO#jOy^S_0rczwgLEyfNEca*+>WQWR^up4N_jKJ)2>iY@MU7%c9_?C>MY zW{%ShF9rvk`(W!<@oRZHja^yKOspTAz%EYZthmuk#I0zPS7-HpKYp{EYsxviUb~ah zpnjKbpwGM=VYK%uo0Pf}dWYMyDHl#F%)<;z_qp38cf(4A-Z8_PTeUgAa&%qv*~00^ zkf<(emkGOc$2@bBS%aFWm}TJ5pyiKn>PmPaw^4&l4Hig!_!IZ)X5@hGVV;)CbnCkk z1L5T(pk?)%qdAm<<2cVUF9l%2{0{i>I?3u z|8jk}P=l>hSQO~L>tn@%B%oz2-Fv-I-}Yvq+(elXWWS>Z$GX*(up{quo%)C0G)7f; z?UBim9~hfro$*^~A=R$zce8^P

#pb8tt`f2(G~I}s0|S#71f#g}5KxKIU@%GEO^ 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�PSNCz@t9W<{e7qwNQ@E$bc-3uCZTiNt+7zw--;4 zTzt0IUc(&XKxgz;y+w`S6~EkfPKb9=dBuZuf^yl0Mz>!*l7g zB}33GoTdr_u4udw+s;tJmUSBPpqG|1MwqqU%vE1@+}ij5u1$e*mHfpBAxO5ad?zx)FH+1qBYY>m1pI`1CjRjT#VWaE>b1AH!{GHwrZJKN>M- zB=>yWaVv!_HwE*XCmZSv7V0we=CDS$Z{uYCgIp zM1mM~6ETMUQ>Dv)_8_uRt3N5u{eulknjKCpPp< zhdcLpvU{d%26=0%TxtcaMmx(FX0V_>QaJrQGeH8WH^@K)CSzE$Y4=%?*fqy~l^vKg z0(dr{sb@hJ7Rm9RnukLD0Cvc;-%5VWn`=zz-ruzi=TAo~SPX%Zd~jepmJ_boTucSM zJUbc_?&hc})^D6V5ygSRyf}^9u2CwVr%`VbU>TUPh0g4fJDO467}K4@6L^c$WQ zZ63(>=txI>`fN5IY#e51pbtc{0W(bd;6R5OFnrs*0df7ip0A!nQtc$AD<7(k2T3On z;eREWDO(NsyETQ{jL+Icq57l_#Gf~(N_Sar8&e6^9=Oy3V9O-`8^wasWM%U1V#8Jg zR?VUx+G!D#BEdR$@w$o(nj1_FLS^4q{1|@+o`2~lolHRUlksmxDfrc|ohj;m2K0D) zCc*>)I*^_({<+&Fy{Z_*hmxgoSR)9mFwbr^lp1UslY_&khs<^?~{LmRK# z>OJi2=a#w^uiqIx&YJDK1pJH2G>(=aUy){_S)-ENV5)*)5geO7D_LYcKGJ%zwJ;sI*v6$tLxoK0iyij`($n%B2I zakmqwyhDQUwz~~}+;F_^;E{;?fnXEF?KT0`HmiA}31OUl)30Dju7J96ps4)1lU-Y9 zJ%LQQwcwl+O7eOpPmO*`6tYAkuk+Zg>pkfc%DF!4MFU{n=Bs4|gI4IBdmaInx9=RU z%=xVRwna8({p*{*unf2{@kN0Q`m0At!wGSR`%&_8LeAUU(Qp=hXWilDEO|2LArt^R zZ6j%8y+U>=#8y@yCi-7bjZOys_d%fA#nA6zkfw4)BEENpp?jq!(ow{b*KEe^{ss6( zkoVn-tqc8%31CMb0UF;-UmV<3L3HrrZC&y;mkB3bvLHwROBa=Z2o7p^rz<>5%Xjp1 zUc}+GYT;M&k`9VNb{%Ga&V+8W#uRSTU`fb$e*7Re`6dYB&85KQG6vSoB{K#vA@0`+ z;$>p_=3#Rj&4eGVU^4z0>B4Bl5p7&U;&0Agi%};h*1iz}5epcImq)~*ALIazSwRbK zcoIQpIY=^~Lavd>EM5DUV&Dl^I4rjh_sRa-cs&#u10)%cmo6Zp6fUOX|91o0JR30OUktY$R8&AH8y~~UBc4pAaTxrOL(tiddEKtGwCzOOiRUm}= zqEM6F3izm~mUWOxn&2Ro5?CzD&bf(w!~bTf?<-p>G=A;ahrZKT8egOM-`xgKQ#pX1 z%eJsrcVSHWZ(jxGycACOzj!_WO&4dqd|` z|A_%eRVtUMh=!TKg-a)mye=k%#sH=z$@!>|l=mhMlpEc`?YbC@IGFONyOMUM_d_r; zb?JS$;xz+i5PcrL%c{(%X^X9D$yO7eM#}V0Yvbmp8$kk}FybFZ;er9{hga&a8Bi4h z=1$sa_L_kR%$@z0!dJBG4DC_yErvI@5`2wO>p(sgU47lfe}G!kn^YqHapUt{L2(tKJqORq%!XHm5rAoRt?N|gT(k5`(!iF(CAVYrlLXJY)!r3w z&7(d;P&?dN*eBeD8v3F?k^Y*=XMX@^I7S}=+5>>E!^d#DO|H8c9$=iH?vE^_7N~bU zn6Q|?X2h>FKzavDqM>&B?rpgoscX(3ObN`zz)<|II6rvg7vzgFnrmJ#iUhpar?3$zXmJ>|ACDh{vwk4QW&dqlr f*G Date: Thu, 8 Mar 2018 20:56:48 -0500 Subject: [PATCH 07/11] Clean up and add another test --- MapboxNavigation.xcodeproj/project.pbxproj | 8 ++-- MapboxNavigation/InstructionPresenter.swift | 41 +++++++++--------- ...structionsBannerViewIntegrationTests.swift | 4 +- .../InstructionsBannerViewSnapshotTests.swift | 18 ++++++++ .../testAbbreviateWestFreemontAvenue@3x.png | Bin 0 -> 25375 bytes 5 files changed, 44 insertions(+), 27 deletions(-) create mode 100644 MapboxNavigationTests/ReferenceImages_64/MapboxNavigationTests.InstructionsBannerViewSnapshotTests/testAbbreviateWestFreemontAvenue@3x.png diff --git a/MapboxNavigation.xcodeproj/project.pbxproj b/MapboxNavigation.xcodeproj/project.pbxproj index 4f8f500ee2..2e4678030d 100644 --- a/MapboxNavigation.xcodeproj/project.pbxproj +++ b/MapboxNavigation.xcodeproj/project.pbxproj @@ -835,19 +835,19 @@ 35B711D01E5E7AD2001EDA8D /* MapboxNavigationTests */ = { isa = PBXGroup; children = ( - 355DB5731EFA73410091BFB7 /* Fixtures */, - 3527D2B61EC45FBD00C07FC9 /* Fixtures.xcassets */, - 16E3625A2012656C00DF0592 /* Support */, 35B711D31E5E7AD2001EDA8D /* Info.plist */, 1662244A2029059C00EA4824 /* ImageCacheTests.swift */, 16A509D4202A87B20011D788 /* ImageDownloaderTests.swift */, 166224442025699600EA4824 /* ImageRepositoryTests.swift */, 35DC585C1FABC61100B5A956 /* InstructionsBannerViewIntegrationTests.swift */, + 35A262B82050A5CD00AEFF6D /* InstructionsBannerViewSnapshotTests.swift */, 3510300E1F54B67000E3B7E7 /* LaneTests.swift */, 3540514E1F73F3F300ED572D /* ManeuverViewTests.swift */, 35B711D11E5E7AD2001EDA8D /* MapboxNavigationTests.swift */, 35F1F5921FD57EFD00F8E502 /* StyleManagerTests.swift */, - 35A262B82050A5CD00AEFF6D /* InstructionsBannerViewSnapshotTests.swift */, + 3527D2B61EC45FBD00C07FC9 /* Fixtures.xcassets */, + 355DB5731EFA73410091BFB7 /* Fixtures */, + 16E3625A2012656C00DF0592 /* Support */, ); path = MapboxNavigationTests; sourceTree = ""; diff --git a/MapboxNavigation/InstructionPresenter.swift b/MapboxNavigation/InstructionPresenter.swift index 5c9cc2f1f0..f85745fb6a 100644 --- a/MapboxNavigation/InstructionPresenter.swift +++ b/MapboxNavigation/InstructionPresenter.swift @@ -23,32 +23,31 @@ class InstructionPresenter { func fittedAttributedComponents() -> [NSAttributedString] { guard let label = self.label else { return [] } - var attrComponents = attributedComponents() + var attributedComponents = self.attributedComponents() let availableBounds = label.availableBounds() - let totalWidth = attrComponents.map { $0.size() }.reduce(.zero, +).width + let totalWidth = attributedComponents.map { $0.size() }.reduce(.zero, +).width let stringFits = totalWidth <= availableBounds.width - if stringFits { - return attrComponents - } else { - let indexedComponents = instruction.enumerated().map { IndexedVisualInstructionComponent(component: $1, index: $0) } - let filtered = indexedComponents.filter { $0.component.abbreviation != nil } - let sorted = filtered.sorted { $0.component.abbreviationPriority < $1.component.abbreviationPriority } - for component in sorted { - let isFirst = component.index == 0 - let joinChar = isFirst ? "" : " " - guard component.component.type == .text else { continue } - guard let abbreviation = component.component.abbreviation else { continue } - attrComponents[component.index] = NSAttributedString(string: joinChar + abbreviation, attributes: attributesForLabel(label)) - let newWidth = attrComponents.map { $0.size() }.reduce(.zero, +).width - - if newWidth <= availableBounds.width { - break - } - } + guard !stringFits else { return attributedComponents } + + let indexedComponents = instruction.enumerated().map { IndexedVisualInstructionComponent(component: $1, index: $0) } + let filtered = indexedComponents.filter { $0.component.abbreviation != nil } + let sorted = filtered.sorted { $0.component.abbreviationPriority < $1.component.abbreviationPriority } + for component in sorted { + let isFirst = component.index == 0 + let joinChar = isFirst ? "" : " " + guard component.component.type == .text else { continue } + guard let abbreviation = component.component.abbreviation else { continue } - return attrComponents + attributedComponents[component.index] = NSAttributedString(string: joinChar + abbreviation, attributes: attributesForLabel(label)) + let newWidth = attributedComponents.map { $0.size() }.reduce(.zero, +).width + + if newWidth <= availableBounds.width { + break + } } + + return attributedComponents } func attributedComponents() -> [NSAttributedString] { diff --git a/MapboxNavigationTests/InstructionsBannerViewIntegrationTests.swift b/MapboxNavigationTests/InstructionsBannerViewIntegrationTests.swift index b25c65ee0f..2a4dcc75af 100644 --- a/MapboxNavigationTests/InstructionsBannerViewIntegrationTests.swift +++ b/MapboxNavigationTests/InstructionsBannerViewIntegrationTests.swift @@ -10,9 +10,9 @@ extension CGSize { static let iPhoneX : CGSize = CGSize(width: 375, height: 812) } -func instructionsView() -> InstructionsBannerView { +func instructionsView(size: CGSize = .iPhone6Plus) -> InstructionsBannerView { let bannerHeight: CGFloat = 96 - return InstructionsBannerView(frame: CGRect(origin: .zero, size: CGSize(width: CGSize.iPhone6Plus.width, height: bannerHeight))) + return InstructionsBannerView(frame: CGRect(origin: .zero, size: CGSize(width: size.width, height: bannerHeight))) } var shieldImage: UIImage { diff --git a/MapboxNavigationTests/InstructionsBannerViewSnapshotTests.swift b/MapboxNavigationTests/InstructionsBannerViewSnapshotTests.swift index 96b7be021e..0ef1f9dc18 100644 --- a/MapboxNavigationTests/InstructionsBannerViewSnapshotTests.swift +++ b/MapboxNavigationTests/InstructionsBannerViewSnapshotTests.swift @@ -121,6 +121,24 @@ class InstructionsBannerViewSnapshotTests: FBSnapshotTestCase { verifyView(view, size: view.bounds.size) } + func testAbbreviateWestFreemontAvenue() { + let view = instructionsView(size: .iPhoneX) + styleInstructionsView(view) + + view.maneuverView.isStart = true + view.distance = 482 + + let primary = [ + VisualInstructionComponent(type: .text, text: "West", imageURL: nil, maneuverType: .none, maneuverDirection: .none, abbreviation: "W", abbreviationPriority: 0), + VisualInstructionComponent(type: .text, text: "Fremont", imageURL: nil, maneuverType: .none, maneuverDirection: .none, abbreviation: nil, abbreviationPriority: NSNotFound), + VisualInstructionComponent(type: .text, text: "Avenue", imageURL: nil, maneuverType: .none, maneuverDirection: .none, abbreviation: "Ave", abbreviationPriority: 1) + ] + + view.set(makeVisualInstruction(primaryInstruction: primary, secondaryInstruction: nil)) + + verifyView(view, size: view.bounds.size) + } + func testInstructionsAndNextInstructions() { let view = UIView() view.backgroundColor = .white diff --git a/MapboxNavigationTests/ReferenceImages_64/MapboxNavigationTests.InstructionsBannerViewSnapshotTests/testAbbreviateWestFreemontAvenue@3x.png b/MapboxNavigationTests/ReferenceImages_64/MapboxNavigationTests.InstructionsBannerViewSnapshotTests/testAbbreviateWestFreemontAvenue@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..dab808adedf292358c688bf969041afeb6846404 GIT binary patch literal 25375 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

t~c5|aso=Vi?rIus*K!zh9yyz*) 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 pN3b;-Ft}6D>WYxiTmI7qhX= Date: Mon, 12 Mar 2018 14:21:13 +0100 Subject: [PATCH 08/11] Hide delimiter if adjacent component is a shield --- MapboxNavigation/InstructionPresenter.swift | 68 ++++++++++++++---- ...structionsBannerViewIntegrationTests.swift | 8 +-- .../InstructionsBannerViewSnapshotTests.swift | 21 +++++- ...viateInstructionsIncludingDelimiter@3x.png | Bin 0 -> 38936 bytes .../testAbbreviateWestFremontAvenue@3x.png | Bin 0 -> 25375 bytes 5 files changed, 77 insertions(+), 20 deletions(-) create mode 100644 MapboxNavigationTests/ReferenceImages_64/MapboxNavigationTests.InstructionsBannerViewSnapshotTests/testAbbreviateInstructionsIncludingDelimiter@3x.png create mode 100644 MapboxNavigationTests/ReferenceImages_64/MapboxNavigationTests.InstructionsBannerViewSnapshotTests/testAbbreviateWestFremontAvenue@3x.png diff --git a/MapboxNavigation/InstructionPresenter.swift b/MapboxNavigation/InstructionPresenter.swift index f85745fb6a..f40ec00db7 100644 --- a/MapboxNavigation/InstructionPresenter.swift +++ b/MapboxNavigation/InstructionPresenter.swift @@ -23,14 +23,14 @@ class InstructionPresenter { func fittedAttributedComponents() -> [NSAttributedString] { guard let label = self.label else { return [] } - var attributedComponents = self.attributedComponents() + var attributedPairs = self.attributedPairs() let availableBounds = label.availableBounds() - let totalWidth = attributedComponents.map { $0.size() }.reduce(.zero, +).width + let totalWidth = attributedPairs.attributedStrings.map { $0.size() }.reduce(.zero, +).width let stringFits = totalWidth <= availableBounds.width - guard !stringFits else { return attributedComponents } + guard !stringFits else { return attributedPairs.attributedStrings } - let indexedComponents = instruction.enumerated().map { IndexedVisualInstructionComponent(component: $1, index: $0) } + let indexedComponents = attributedPairs.components.enumerated().map { IndexedVisualInstructionComponent(component: $1, index: $0) } let filtered = indexedComponents.filter { $0.component.abbreviation != nil } let sorted = filtered.sorted { $0.component.abbreviationPriority < $1.component.abbreviationPriority } for component in sorted { @@ -39,32 +39,37 @@ class InstructionPresenter { guard component.component.type == .text else { continue } guard let abbreviation = component.component.abbreviation else { continue } - attributedComponents[component.index] = NSAttributedString(string: joinChar + abbreviation, attributes: attributesForLabel(label)) - let newWidth = attributedComponents.map { $0.size() }.reduce(.zero, +).width + attributedPairs.attributedStrings[component.index] = NSAttributedString(string: joinChar + abbreviation, attributes: attributesForLabel(label)) + let newWidth = attributedPairs.attributedStrings.map { $0.size() }.reduce(.zero, +).width if newWidth <= availableBounds.width { break } } - return attributedComponents + return attributedPairs.attributedStrings } - func attributedComponents() -> [NSAttributedString] { - guard let label = self.label else { return [NSAttributedString()] } + typealias AttributedInstructionComponents = (components: [VisualInstructionComponent], attributedStrings: [NSAttributedString]) + + func attributedPairs() -> AttributedInstructionComponents { + guard let label = self.label else { return (components: [], attributedStrings: []) } var strings = [NSAttributedString]() + var processedComponents = [VisualInstructionComponent]() let components = instruction for component in components { let isFirst = component == instruction.first let joinChar = isFirst ? "" : " " - + if let shieldKey = component.shieldKey() { if let cachedImage = imageRepository.cachedImageForKey(shieldKey) { + processedComponents.append(component) strings.append(attributedString(withFont: label.font, shieldImage: cachedImage)) } else { // Display road code while shield is downloaded if let text = component.text { + processedComponents.append(component) strings.append(NSAttributedString(string: joinChar + text, attributes: attributesForLabel(label))) } shieldImageForComponent(component, height: label.shieldHeight, completion: { [weak self] (image) in @@ -77,14 +82,25 @@ class InstructionPresenter { }) } } else if let text = component.text { - if component.type == .delimiter && instructionHasDownloadedAllShields() { - continue + // Hide delimiter if one of the adjacent components is a shield + if component.type == .delimiter { + let componentBefore = components.component(before: component) + let componentAfter = components.component(after: component) + if let shieldKey = componentBefore?.shieldKey(), + imageRepository.cachedImageForKey(shieldKey) != nil { + continue + } + if let shieldKey = componentAfter?.shieldKey(), + imageRepository.cachedImageForKey(shieldKey) != nil { + continue + } } + processedComponents.append(component) strings.append(NSAttributedString(string: (joinChar + text), attributes: attributesForLabel(label))) } } - - return strings + + return (components: processedComponents, attributedStrings: strings) } private func shieldImageForComponent(_ component: VisualInstructionComponent, height: CGFloat, completion: @escaping (UIImage?) -> Void) { @@ -144,8 +160,30 @@ extension CGSize { } } - fileprivate struct IndexedVisualInstructionComponent { let component: Array.Element let index: Array.Index } + +extension Array where Element == VisualInstructionComponent { + + fileprivate func component(before component: VisualInstructionComponent) -> VisualInstructionComponent? { + guard let index = self.index(of: component) else { + return nil + } + if index > 0 { + return self[index-1] + } + return nil + } + + fileprivate func component(after component: VisualInstructionComponent) -> VisualInstructionComponent? { + guard let index = self.index(of: component) else { + return nil + } + if index+1 < self.endIndex { + return self[index+1] + } + return nil + } +} diff --git a/MapboxNavigationTests/InstructionsBannerViewIntegrationTests.swift b/MapboxNavigationTests/InstructionsBannerViewIntegrationTests.swift index 2a4dcc75af..3e7be895a5 100644 --- a/MapboxNavigationTests/InstructionsBannerViewIntegrationTests.swift +++ b/MapboxNavigationTests/InstructionsBannerViewIntegrationTests.swift @@ -41,7 +41,7 @@ class InstructionsBannerViewIntegrationTests: XCTestCase { lazy var instructions = { return [ - VisualInstructionComponent(type: .text, text: "US 41", imageURL: shieldURL1, maneuverType: .none, maneuverDirection: .none, abbreviation: nil, abbreviationPriority: 0), + VisualInstructionComponent(type: .image, text: "US 41", imageURL: shieldURL1, maneuverType: .none, maneuverDirection: .none, abbreviation: nil, abbreviationPriority: 0), VisualInstructionComponent(type: .delimiter, text: "/", imageURL: nil, maneuverType: .none, maneuverDirection: .none, abbreviation: nil, abbreviationPriority: 0), VisualInstructionComponent(type: .text, text: "I 94", imageURL: shieldURL2, maneuverType: .none, maneuverDirection: .none, abbreviation: nil, abbreviationPriority: 0) ] @@ -101,12 +101,12 @@ class InstructionsBannerViewIntegrationTests: XCTestCase { let view = instructionsView() view.set(makeVisualInstruction(primaryInstruction: instructions, secondaryInstruction: nil)) + //Slash should be present until an adjacent shield is downloaded + XCTAssertNotNil(view.primaryLabel.text!.index(of: "/")) + let firstDestinationComponent: VisualInstructionComponent = instructions[0] simulateDownloadingShieldForComponent(firstDestinationComponent) - //Slash should be present until all shields are downloaded - XCTAssertNotNil(view.primaryLabel.text!.index(of: "/")) - let secondDestinationComponent = instructions[2] simulateDownloadingShieldForComponent(secondDestinationComponent) diff --git a/MapboxNavigationTests/InstructionsBannerViewSnapshotTests.swift b/MapboxNavigationTests/InstructionsBannerViewSnapshotTests.swift index 0ef1f9dc18..cedfaf17cd 100644 --- a/MapboxNavigationTests/InstructionsBannerViewSnapshotTests.swift +++ b/MapboxNavigationTests/InstructionsBannerViewSnapshotTests.swift @@ -121,7 +121,26 @@ class InstructionsBannerViewSnapshotTests: FBSnapshotTestCase { verifyView(view, size: view.bounds.size) } - func testAbbreviateWestFreemontAvenue() { + func testAbbreviateInstructionsIncludingDelimiter() { + let view = instructionsView() + styleInstructionsView(view) + + view.maneuverView.isStart = true + view.distance = 482 + + let primary = [VisualInstructionComponent(type: .image, text: "I-280", imageURL: shieldURL, maneuverType: .none, maneuverDirection: .none, abbreviation: nil, abbreviationPriority: NSNotFound), + VisualInstructionComponent(type: .delimiter, text: "/", imageURL: nil, maneuverType: .none, maneuverDirection: .none, abbreviation: nil, abbreviationPriority: NSNotFound), + VisualInstructionComponent(type: .text, text: "10", imageURL: nil, maneuverType: .none, maneuverDirection: .none, abbreviation: nil, abbreviationPriority: NSNotFound), + VisualInstructionComponent(type: .delimiter, text: "/", imageURL: nil, maneuverType: .none, maneuverDirection: .none, abbreviation: nil, abbreviationPriority: NSNotFound), + VisualInstructionComponent(type: .text, text: "15 North", imageURL: nil, maneuverType: .none, maneuverDirection: .none, abbreviation: "15 N", abbreviationPriority: 0), + VisualInstructionComponent(type: .delimiter, text: "/", imageURL: nil, maneuverType: .none, maneuverDirection: .none, abbreviation: nil, abbreviationPriority: NSNotFound), + VisualInstructionComponent(type: .text, text: "20 West", imageURL: nil, maneuverType: .none, maneuverDirection: .none, abbreviation: "20 W", abbreviationPriority: 1)] + view.set(makeVisualInstruction(primaryInstruction: primary, secondaryInstruction: nil)) + + verifyView(view, size: view.bounds.size) + } + + func testAbbreviateWestFremontAvenue() { let view = instructionsView(size: .iPhoneX) styleInstructionsView(view) diff --git a/MapboxNavigationTests/ReferenceImages_64/MapboxNavigationTests.InstructionsBannerViewSnapshotTests/testAbbreviateInstructionsIncludingDelimiter@3x.png b/MapboxNavigationTests/ReferenceImages_64/MapboxNavigationTests.InstructionsBannerViewSnapshotTests/testAbbreviateInstructionsIncludingDelimiter@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..056fee89f6ecb0e7db20f3b05cab5d284d676893 GIT binary patch literal 38936 zcmdSBcQ~7G-#Dz3(wenrQG3*i+M`D8O;Oa25o*_NOI2&v7Nhp2h}g7RyNDSQqe|?c z_V&Ac@A=&B<9XhHUpXAP!gZbJXYVr~v^ACQ;nU#b;NaX-d8(j`gL4ywgL91u?>6uk zt44-Tz}qzsU1fQkiUGP6;KQAlPmMira2`Cq{Jo}_B=7?GBb|eSmOk))9r(Tci3NT+ z{{9YJE5Ywr1ts9%$l|Cd$mzejww`gP{(i?;8_VIl&(g=mL#OjJAL78m;n(WGvdqkU zS#L@2bP}oI^D~{4ye@O0dMQWDtmH+@K402c; z@ItYSn9OIle@<#4Xg-3eHdVBTO4aLmKGh9`@2o%l7*O{RZb z$`an8@_H?UC(9&!&B$itVetR>@8515Rk>bt-K!eK>A7%|7{#ot`u56AZ<XOfcIT^Dp@Sb01)(Sf*>C@SB$L2IOS2;L_i{`QR(dT$8wt2k}mSjDP(c*y;4> z3+0tnv~ls6U}JAo3&QUZ%YxN#1daa_C7hep8aUa!=)Djx-v_S|Ny%yLnpg351~#yI zqSo&95l7xMqr?TD;0kd#lyI`ksmS4SpPvI@VMym+U0r4jz`L}OD_^$w5}I2Qsq+6p zU;r8g02;O0H@rs=0cd6$zq?;uM&XjM*Hr|)(gA4beQ-V!U4e#J4*Z>fiTD;kL=KKm zxBtb$zjKob39R967D$yv4M3Y(jDPpdzw!BRmwAc+D7@PXre?ssC8g4w_pU7S`8x14 zx$OLXyiw-Y2t$H9wEvWqe=g@01wd(5>efq31VHnu{u9@gWtfyNq0u)^NwWmjqpqM+ z5BcZg|6n`o695|OfdyUcB{VHzoQzkOi3N6IVkUh38o(Pw@RaWQ6}l9;02_>%wI%Rz z0v9TAY>ZdQYj-J>aK}eHMwd_-m{DD2c6bP|6P>{1fn7z|;7z zx5%%PU*3a9%MPg5Kalym6qbAdmJu0avsH-!F8tPesQ>d0rdX0oiWKAh>=py4mu|$g z_~gnm?SP69494DPVtR`Rqr58NtCGN@;+xlT!b5>=SgBNQUfsqX*v7X)%6X6wxOaW@ zR?^jFbO9D8k-n-f7Xdu17IY2fMYRJYqV9WT|kKa}@BFlNGeBYvqU(FTt@ zqAsylf1yHgWtmt;V27h(Zk~QYU_BlrA^a-sNH4V&&rYz|?-Ck|j{C${mLa~>rEubt z2QL8G=?^3Ax{6at8UTZV5&t{2NZ`V%s0Z)LDzOH@2FB&o>%Ei!Facwf<5#uTis?0i z;)edGvJimjt1t5PY_5pa*CgOy@P%)pc>0$F5OhhubyYfv3H#;Doo>OVh~9uTzNQGmFx>39D+PAqUgkQ z;b<3$rQ9{kjxwGs#_>2k8OChhJ+80+g(|4ahqz$7=$-1dil%YW z$*CgHbYYi17ua^MdDK+?*$rY;JLy8eRU&R&5>XxOG+Aw{64y_T-c2dPw@XANUL@J1 zed2~=S|8oNVp{=&rFyAxPr*&AC8gIDK}OCa*4*T^)vwGS4nT`Np2ukGnOEX9N(xvP?Y{b7M*NgL0y5-UEZD*RJ|Y%S$Mkav+_N z)WbzOEKYI#QH~=XyHh;)_88Rt|C@nKuv*vIR_DJEoN`wz=V8e5eu9@FBX0^0Wxe91 zh`S{KtCsK%ZrvXBT~FLB4~X zhHOnO`?MXg+y)+mM3(i=RqnL{bjfFhd0|l^f|tk%YnWPcJ9S~2sHxXTQ0^A*{tNSn zlK`uZFK?P99he6o7)Jm}D=5eiA?feT{1Tmhe1r!nHoA8EDtg0gfRKGbfEHF z5jS)%D%Com(%whaC+1rZyWnN-D1!;2Vy}cCIM;nIuE_nyhkJaR2@9hEIe3-=OE{uH$&P^13084rlqU;!b+@$)J~#d3pjt7JbkeSU)j;6f*1{b#p{RyD2Bg-kC&U;8`^kufNBMJ<;wM2k6e^G{X*eWMi2fQoIpB3k&W=i z)*|i9|9Yr4VL7pL|Nm42iZ}%5)z%A#i7%Ee0CENp%_sWYN%sGzJ76Y8+5Jp;aDuI~ za8Uq>mS{i>(GhnnR9yS~pX988H=JVsi&>EeqQ(eW@Y+O`^~PT;K*v*zeZ)|r;zu-J zhr?k`uTQTA+QpaQFDGo;cPXQReDZmfMxVC&sj9o_D({1`Yk-fx<1T$gPniw?_al!7 z$yJU?qW75+IFN@X$@P88`(l`4^#4Hz46_j+|9xkNnP%S&#Y^P+a%{QofBkf9{&!6f z>dQ-s8>D+?^y;kLXNx`nhw&@!*0q1VJw@XR?rAb+3jpa;YmvF=4 z;(z&@Y6ohwE-lAY6M}Fq>rnWQKsL@i8txOATxU-!9pl)Z!!>)LK4I@npoPUSd?E&nAOvH_EB9B~LAxPY{gw%&YKWrp4bV zy&`k1<=&-#H0 z&g;9!_#d(a@ZpV3Ad?LLDaQCC!tMbq!*?77 z6hRoO08~=$=n=bIVCyp&weno{@<7h3Fs0)e|Gi^&ref<2h-c_ z1pErje0dLHzO?Wp#lAe-5y8ed7ZdMIH@EVxRg4O2^gpQ+Liit`UusUzu`Frjs>8yY zOX@_?OBgnKt+9!Jx2GF2GbTngQ{LyzO)}^!vpv{|aFV*W6eFzl7diMYSf*`Ui>{L6 zHIc%xW@h#eKxRVW_53)-WT@YKu2s82qikG4x3ceL^WH#yvVufFB)|SowY?NLionm+ z$(!q0?+{6Ek^$Y~T82g;!hjD>Dip4n6F;8NU%}x1&YN{LyF}ygzdy1{iOLMvRxyTw z926o3j(ACq6 zFRhk5Kb#kInR?u12l2-Ykfzrje`8=UxuV-lG1A(pk%?zDm&u9XgMFK};+xN?h=&TS zq7OFbV`P$y%zYILG&8tZl%o@_-MIbuw-zdAaCc?I7V%jwnz*PvEgD(pxuSb?x-%#W zz3A_Z%3(Z1gOf^)Dk;ck*|aj(@!b8+i*#~z54baa&3|Cej4jLxLRprIX4cL4skI(0 zLi=rxj@K#`6%mp%313p*bNNBT*w5RFGcPQ-^w)%m`9@rw=cD!1e!~7YQ3tzFH?#k+JvmZY@p&f2BcfJHF^_PgY~L$LhMAj9U+X6Bt)nDVA4*SyPh~S>|#Ysq1Zh7vhxZ zbTs-f1sB_W{1Q{hN{h`$hBLI|<;fzId`WeT!K&v+vNBy*{q@LRhT%Cm+^Z^oO@gtz zg-|;O=Q58?C8kzAv=0KE;6cPaO3(XGM)m}^Uw^k*&>~9Ik&)14%bL=mn0^W6VKir9 zY-`nTJ>Tx*{UJ&ozMI>Qq;+kcQ~2tzkm4;i1};w(vj3>`*?~3nqZ%2zrYCdV)Fu~G zF}Sd6MU21oFo)-Py*35EIZvr!`6qsjAg;)jF7mPQ;N#SQ(_Sm%KkFREr**gsM+20- z6W?Rvbxs)BSb~Pt!$cgpz6b4kP{XyzsQ=7cbcc8L+m6b$O|dqg%|>mHe=Wqc6c6?- zaU1m@*V<4yl3X(m#=`QNSj0x5V{*`_CU0K?r(XKDddj13oDqDrk~7sszaIN+JTK(l z0Gz>Mf-M$R3+>Cn=;%OlN$wz9FI;_t7wL?*5i&N0$Ud8O%dXy{8-&RuCnCv18m5n# z=e99@87@^*cd;&EFW-_~(Kv;<8%Mr#{DZoG%kQ^Q>VI<8@E}~o4ha)RN?&OjF6IQC zH?#T>Erh7uqd1b%{j+zG&d#BtEa#Dq?g{GBRk=S~b{&1sX4?9iax>#ab|`z7`iy#w z*i@ZENTSn=%3N9IrofLkt6xr&Bbt{SOtLCp8A+!%Y0s2X+ba|)+iYNvV(qibPfT1$ zbAnJ)cus8-tYy9sZ^!}9d#nLd^V#krYOh~$Y}?pZzHbVGLA!$eQM;fI04?BG>aMso#%N z-M3va@A#6tBa)wU?o=-G5mYuAn4kAqU~0_|#D7n%9Y{KlZ^kFP9F_7kpBoy##M~3C zLtmtVD_jI?1MR7OcJBzTE-6EWqrTXO%Je^B84J5OB#uA$*4gQ*D2pt>Pc{Lh=Zg|< z-%A!Y#|89L@?YwiCP`@)u!Ij?S!_a4OrWJ4?ns1BInQYubm1Y(r!X9c!NjJI&VT zqIyMXLE;dml8S~YeXL8#Rq?v?rU&A(AFf||#RsrNFr6)g46u zz3CHEk^u!Phx_R}Iu8asmAyJ1lUJpCDZfIo=0%Mz3r8)ZL`?+BQ(oEDK;rT26%<+8 zqbBN7N1{eZ$b%i%$GTfx-zgUIK>Ms4r_!n&Qw?Av;HJ5PlM+$+em2)l0UEQSw^Q$F zM8ItR2o<{eAtaVoYESEI{y)ORo+DY~%_%W)s!O*<_FFz0rS7H|0oWOMO0+V3MxE`E zRoj#A1Q5lWjepomoW^~V#o`>kM;`9}erVJaI*zrir&fdHk(8MWPiuG8J~n1!Kx!_g z1nyKey6xDvS7B{Vs|vf*BQ!jx>d;H)f5fS+bNZE1p4M?<2T-uHUIw-pm+kZqMYN8M zA4;C(Tc`Iw(y>MH?jFrr@UQ^9+c0A9O(&?FNKYy_Y8OlH)@HF=NpTrG+rF6^_zlCB zhNWV^N6&)oh-d*hNEh%ZsYAWaG0>5rDlFT@psV#Mn<#JCXC3FcIn4 zXrj9elFv4pcQhO3!f5kM>s*E#JnUBx*&*qH`;+dIw#h0$@|$sHoRZp1$2iB36fKje zr%b0t4;Y%gH^2FjN3$O|s43BWX269#U3q2AtsE0krdA-ztcF~oC0U&v9E=m_ zHx)Az^tuc4QI=-UB|1+eY1NF?N^X9@@7<(o-n^`8|Fe#N#`r;2Tg`Ln^tz{uo+4J` zjFpKo6fKU?{v)Y3=e~>W*lhnP>|3@gPd64rRvae>z;`u{tU6SEU4ILY*w#dleSrU3 zW!V1n8>u*Q;=E$2c`#;d*4WeZUAa%0zm09p@WNCY)F*oJC-ko9^%qg8kK~$yR}~06 z&bRE9g`tSmU>i)zpMiRa)2zS6IL|BNq>nH>|rT`)0kOFMf608mM=AXB)G6 z@?#zqL0#0Jn(%;M)FI>BUP);M{^{--lD~GpJpTEV|7MH(unKz*zz*(N0mzTVo$1XW zBNG^S4$s}o*mG^9Fvj(4=GA;u@mM)TLS;m2?7$iIbhxX&h8ZmwIbXk&>CYG2uOT{} z&=_1?Z>c9EzUE1n{z+A65E8i19p}C`W~8<@UT(XT;RA2%Y&v)|?K3;wAX9W$K=$Ba z2O5;s=t)!qaY8Y4#V|7Zn@RooLG}i6F>dM_HBGoje&&W)6yKe&j(KPmQ-0z8JV>#y z@tIEp@|x;>oWJx%G>r5-HLG7S6cm^`)aI-7^P}p0E_M4k5mAZu@rftF*q`S|`6Qj7 z6za!?@C%F7SL?+&*T%M2M&iHQDTyw)m5jYjC?DmDLO>u)QpxP6&a%&tTMosl)(jbtQ1 z|3TU2ZI7#GO_JT++CI!qT~g0F!3AqBln(2;NoPOcyEGYBeV!Xbe@&||+j>aKM}bx- zX^MBdXHCs!G1ZLzjke;Gj3UdGkTW`HCwNlb)7)}0_qbvxIIHC>dcksEhhBN(cLaY@ zdEE?Z^_@~~=ciUnB3jVT4=*O%y6DTDJuMnP@&aKP2LugI1VTnu^XR+=@~_(;=ujdL4ud>yWWD&pfItW=&!1yzjUr%cV z_AaUdvA_TI8=J`n(hf8_+g;)oZ}VrGsApoatJgF}`XP7NSa)a=dj!5^T4wZ(LNX@x z3kc=WsKU4Y<=E>E&)3$DrOE6LTb|v- zhei*Aa`lXkcBASv>c#~MN>{lD)(cHGbmh@q{4H#Zd;!Ku(vq?TXNw0_Uv}KH{Exh% z4WrSg zq^b0)`hc?|N<(>clgPa7pIHVTE?A4GL!(d_`qTRh%f`>}m%X{x75%GzsX`m*k}5Kr zu$BE{q1O~-C?)z=q0OG(Ap`X<`Dxy0c7=|3+;|5fyH>Z5eJ&^kRGd#MHQhTMprWqk zj{J!oE@k3Q<YU`wtzY9foC+jT*V=-MKodO2^6Z0u9<(ahYGQZwMNk z^BfmL4pw!8D3JTjm!txU0_q*Js{obW!z<z=IqU=LBqs{*T0n2={Xo0zlst6ceu)_y{*K1)CM6?QGj^4QLhJUMiu~R{w?xQx zFehtuPxKCB8EcFrp#3HV0tla40*EhojVouf?c%(+mYx2FroBMa8mdpqxi9(r29YG9 zq+-4-o+Uf#Kfs}VTN~gwPIIGWS_E%j~e4UWv}h<{d`G@;>$SJ_V;3J z2AfXy!&?A2hWWuGnwxZ`PxXPugiD5A6iz{n_o{Q6IQ3f#VWl*0ADV`{zF=t6iqWhXlaG&2dhmyirUatYTLlzk>tm{71qUSm|}PmdKM^ zJiLquYP^tVc5~U%eL*E=18=DcYGq>Nq17lL&ah^D)%>O3pb3$*2d@y)VenhdF0Ols zttctOKVw<<*|4m&m>3jWqANY#m}>A?*vsB4mbRBTdhLHN#_6^T`lK5ubjB8E5?i7b zX9kVt44N2m1Gmiw9BbOz>o$L8g#qCmMPGmQ6oKrbscP&ShHMQBSxR0LR$656!(75s zTP}Gh{)jEuEc&0Ie&_Bs+I-i>C{?! z{~z&?9E*%qrXh!@R17N1OQx3O(J56|1AnDFR8Yl=*b~|1X^fROO+q)CTYK8gtD@y| zm7?+#BPiTgiwjk|qUjZL6M_!EGv3zR*5#6k+8$erM#{98c@UNIR&x%%XAGJs8Gs5q zkQ$r4TGL^_KqWq5pubaJca5ojMVU7Qe5B8CpFJU14wisY$ZRigH>F+Ez63bff9UCKy(ItzVl zuxREM5(%CPh)39MpDpJb**20)ctQubj=!z@3SOo>Ujhk1^9>p7j6c(y)+M?~P>auB zy#wDw{{R(=fuaQDXWx5JJdSgX*7)AlO&iDp&(t8{n}(V&w*y zw}=`|RqfTe{0VRRk$l^}q#U9l8m#fFKm=|kd*&;7RIQWI{tNW+^`wpu*YNwmCuUvg zoSlei@9iFTfm2Nb{RgYAHWitix$2iJoWqh zx*iA}B~}SJ^OYmf)U)?8P#9F4d9u1NjH(J!z_St9#**W3EdJmvzMZS&cD?%J4Pj~r z=iy!Rw#t~u!xgqF*MNw4b)S(|%{=J93-R*rlhq1c)@E*g_k+;SFy-FGFACaXjodX5#?8W{1C;?A(o%d;-%#9~ z$+Kcc7J;>{zO@?$0b6P;(Sg1@BLsZ)Uz2l>H7FWicIp^`9KuLY2^rpZU_I>X0%JTd z+uCxc3}BK%`pa28a>lMd?MUg%t)s6%b-ORkxXEq4Gdm#0|JjyW{lF@AymD4>buzqG z^bJ<34Z)XDEZmLkovhSJedl}sq!nrIubAd426A_Hvrqza4?J8u|CB{}zRjZu1_qRV zXyi!N_5T_I+(A?H>TH{Oa_=oWXCdjM7oUfMW}PRP)RK5Unni zm*T;=zc}KygAd-WFVF(_uRTu-^wR{i4G`*w_?VU zQK};q3(d{PE7bPsbA38ziuP>fp(-NjWQJh9AQ}-W(FjKhRQ34ybR(T~K>c2zN~Ln* zdF=1SLbWJnq(5}F|?jO2FsUS&V(?1^F;hs)t*Ye*DE-CKLnI;W;`WSavU;5lJ zXpq>N-)5xzu2-Kc+UfHrz7ZD&9_(2aouLA(<9ltoc+tXyu*KZ`Puk1mzZy4Rl_tqw zGhH+DDGFfkt=nh*R_#vio3RZ6?mvF@Cps-aU0dUT#%%|RuXly7M5uO!^}37cP=0i_ z^$szOtpap_*fHLIl>e9bt9=Ilb<4y$&Ea2|gu*>Q#n`_@S~81qS;i^LjJZ4JMP*ew zHgL`9@GdDlfN{ zWXiMs)p@8_$@_IOWVb?s+Wnmq95pC7l2=zBr4>zeHw`vX+*IFnQXTkt^!>CIk-LgA z3`om68zpo`t@FYD!*VqdQp*%*3ZLo3ldTv20op#w7B+w33jGs>fV*Q`_^3QUqH|}BUMqQ4BrXUBmGzfp&hcs0VKkbsIg#=GT>?nuH zLl0dx+wdU!Wz`Et|Ef-1;@4@?F0)fJ$pY)ol9{bKY129e@}GfFxPMsl^60eCpd^`7 z(-zsI=u2~NJoSkJ<*dk;@$12Q?dQ=W@$$k&7Z-szf$j^6D>vgP6Ony9QbVWj)P#(BMRfr|b_n-Lx%6-w#S1Y~8_HMykdkbxl;Lj1m8XBG1^9Y^k_y{(df zAm4_%j9m^DRh)k3HPu%$%`OK@Bh^?q`uMnDt*|iNU3EeIZ`3fF6~8#$xv^%_WUGvM z-!VKCZi6g5Oa`v9Xcs*JC3eHDQr8TQ?BI*@)~@9v zpl|BLVLG}9G< zkHQ(P7>7sBi)*ql)*ih3Xv+1;309$$@0eF(n$@e?MKd1$q@@sWwNKj5Q_2r+)3aAk z6apnY=#Dpp1J2`J;e-DA=7!!9tx=1u!1TZBIc$8ae_8zdco14pP)K)@P#oap%x7Io z<`r3#BExIV?&DM8G6sCP3)Be3wP*$87ong?0&mp!WN1tpn5#+rL*o=YBs25rZRF!81f@4tWggEgtz|(!SM&ZU#iSRwKBy4_|MGt5cj*x93364 zAe0ravvpo1KX?DIgJY~Ip(>bzjeSB`<@fo6qqdC%)CeqnuypAR$U#~sW-}vL@W*m(u2oQeTzNn~V@m8e$0aw8o8_c!=hYGv^qN0RC@(m)oaDyQ~7KULja&y*Wd zr4ci5IiH!wy-P*>%pBu}Ni;G{kMX`Wrjq+M=kRU4|ACVUrA2_-dfcYCbS`A@dSzhH znqyORc9DEZ9pC9VWMe1D7q$KbT)N&kXXF}mLh5Uz^?>ZM3A;uBwYYJoiT~DY3`i{o zQDCMl>Zo8EnPVgs?;SGUVuPOd?;~WN;cUuuuUq%rHmm-A$EO$6bz#toMtPb-CWT=4 z_DuH@!n*c8VNv@@7t()RtNSjd9!fw5_t|%o!XW2d7q*REF64@0^p@p?)(7y;AdT6c z&HMdpnv(+wHE*g|J~iY25UG4LnS0^c#jg}aL+;e1ea#vefAuhT=5mlwxdS==WqtCf zs3y!nH_3gVDsT&FVLVSIR6=J8iNQ{e!1O%MwodZK6j}L$R&C48-k&~OZEYSisfzeC2>&DXR}+HElDnDB%O-MnN7MI>S18<@<+#{T*jn4dI1rFf?L+_i5Oz>k2o z61zSW86MQ;1ozJO3>>yA8-FxSYJjs-(=jb-(;eFnYJgAjcs+}dI+z;aA`-21PvUyp zA>bLdpY!GHTRxqCOP8Y*dVd|5o6N?j?3#w2U2nqD+bWd zjFBUr=k*8`8&ehqU&V9|WbiKZ1fxZyp1?_v+}9>^F5h~jMCZ2ILL`%{GsvIl;UATh z;VF2V932q)uq|*_VxLfK^-~wdHDsy#^xjBp>60H({!omYYR3M){e>Fv!w>{$WTuD-h+ zBmM!O)_niy@smZB@n8x!yy=O${58!?`HjGO(li(wv<64X^0*@zs(Na?265YyPBp{% z8>BEl2}p`_yiPC-6dUhOb0YZg%ZOU|^if`Jy$PIeNTwY_*0R#H5MCTV_t?R@xA%Hf za~ECe=fZe9`M5E&mUT{{0TUa|e6D7zM1v?brZO|o(%PX5NG9|F?41*G=D5Gt@15&x zs?0qg{DAD-4%Ym1pj<*roQm+go7Q%5 zwmEQUgQ{(^?us66^m1Ct6-sh6Vkdtf;x3!Z({i+A*+QDF(Pt~6l=JbSI8NX*iZNE0 zfxjt{DblYMpCkw=?~?^rL7&#Yf9L<8uEh|XERPod!%#SVIPJ$<8*uuktM2K^*BeB; zQtUrd3M4k_b6ru6)(_{uuCQ{*UAHXWHmWw;8J27*<2FWq;G25D%2k#7$phx}3ZZZl z4>E`Hde};QAohm;wV2djZM)rfk3V)MkL>R-)&TJVQ0&XVMg^U`$g|SUjV9`bDRM8Y z-J`vTuk1kS#hb^U4G7)OBMj(HMq>p#)~qnlGx zgsW{*yXGK4r|ea)Yqd0NGEnsf@8bM|_NDA{c6T>{^yjBS6UP|*6X_#o+&E2liY};2 zBj=XfGsX=~sl8EkWcGM@zgpzLTZ3Mr>Q*UEnLT%easMg9h7Zc2Fh^3PeHSRUkVc8) z)4W7OTca)WbdpdQj&i=%nQe3#`YWypR` zaji#lWsvAMg)}-G^7ds+3U`~gHMeh!R1G?>G(kV&YpDn6N>w& zg&<&b9$8@)ZESM8`55CZdReyVAu#@Q?@=9Zx5yL=Y^7i2g77$SwpxK*=GxP)7tn*j z;12_KCOxxT)M^XtZT=HT2J(sutc0RrtH~jb{`v`T-P9+l%JZ`m z)5$!daE!ag@!@COmx15zd~8)kExK>3^=h?%YMm#CkutlsGycsLvp|1Q|ipE;~dfq5{y{Bzpo4 zuFn{%oY_po1H6NTc!7C7x-hO`DMUHevvhX)3zX*|WHut*^HVjztO>^<;S)o7H>PQokSYl=wot=Nyv? zdy#4#ttrY_8>5_R4)6mTlF^?+qmyW1zft4+OgE0JL~>r0eHr;11VP!f-VJj8w5?Zp zPa{qE&mPg{i!&7OVmC|7uGCB?5pF$*a`m*D0 zi3+%MAI{KOS6d2i9i@Qhwr^e*QW$uqYv21nJ507ESH%Yewh3Px*%nl^OLzFT*_ADTYU`vhfK;l9d$B7eD2?#;aLovMV8ndM z_(=DmjO0rq0)ANWmbJ&(2uH5fo~ffLA|+rC7$fn;BHS#`oVo1nOpwyhN!dPXArX#7 zlv7)Du;T+b&3Oa&$F#FFYOw)!w!wqQgT6) z7M8=71^wMZwAc38VYCtN>}3ou=$73R7_tr2(yj7?>rzw*o?m1C={|gFTYbKUvQF8f zuhsUXtKY2Mz=Ydhc&%fHf7P2;yB6YNQj04i@NH&f5@#5wKt}t^FN1lT($Yta7E@Cd z2`&twRY<>6Yn$6Mz}F1i_P+csfW~!iRN(Me&pXp7^;cVF@q@ux^$uYOWKy8^tB*W^ z2P|S|VfId#Iop?84Kdws^J{lTjPvVZz7V9*i=I+akx4UUKD<+xw$4D(i zj+BAvO~lKoFLSiMKq9V?OWN0>!s;6UFfNKXyUmZy*t@?Er23$gMA78-*{zAdU)=D~ zYB33h8(9uIop}Fbh0Yi(5UflSa&Hq*k-?J&L>^WOnd)!*Zzk5jtEO6FpYK z{Bd?~9!PFDjc3K5zng7X<;UQia)q7bFKvue#8$W-@j}>q5yE@8->l4b&xZFmYBFr( zb~u-mv%V8b@Wj5KLGMccs_pVNV_Em4(@J(K&X=}GVv%(O4l)kGe9?`OtM$C*TP4c` z@=%8a9Wj;sm5Fl`{dM^TN~`C^QV!|KCm^8sbDM}^{k}5$gRPHhiDjazho1vZjj_~9 z%7cDS_7D5dsuML|YCpQMWVm<&#AhrX6qRKn1!!*9Gt;!pgBTO<4EvnX8P1eFz1)5V znpWBU$7ii5GR_o9xKwLh>NU@j0NqD7R@1bQY2A&Kj+nWmwmG-pL`_kmN?SC0R%P86j=IwmXbphwT`Ie=ms-UkI`);d{^V6eZ3$nMU z7o^w2qVE~5r|H%6M)9SArXxo+G53E6mY>N@({ddtN|#qB^orh**;_0pqq%=*y1+Lswbex}mvMXM3kn*{D<@~Zd zQBde`oH)eBC{HpQRNbS{Lt0#W4Txwk9Y~`viq`|Dec>k7H7lWb<>!wP3jT?i zp0XYA*=fNX!vjtF(sFE8R>@f4Zo#>bW54imXRnC+J|s8KJg%Z3n%GXEb-sd%Rmj4; zN^#GDb$TS8BAMqTlPzaMj^&r{1*~+9mV3N=1G~u^l-c9N&%)EXwW_-5Q0;w&6nycs zuVaw&iOtA%I+%H7cW_^hs{;Na-UZ;sISt+Jui_H}*q17?Uh6av#L*UAGbjzMhk!8p zj0Aq)ctpj&vd!kjsI+Uf*bZADApxK$Yj427eGEQ3ND}zCR|FitQp8<_&lU5#h_mU5 z?Hh$442@8JVtXZBCEBE;{pdaJv!U!yDwg%{6%X2{fie59-W4^0sPPe?ICEo!Ru~++ zxyKBCdFIYGunZir`Ybi`N9yd9@jj3)L6Gpe=X;1e-hmN*HI3w9dJUs--K9yFi}^sZbl4uI z0wGhgFLmeIchIn5*YeY}7%a{{7Y8c@su2VdvNI6ZOVK!2p^p#E^6Sg_IhFicH3{up z6SYj`l57#w01gc~2j~3Gz=w+$K+mg#I;riS`Izy+mlFMpP31YZ+BZ|jQ?Wmuihpi1?dnJp53!A9 zT#3=?81SmYR&_DFaj5s5Q0Q4xxV7;oNDZn&4&yHT7!|aVP*Vw1_F8$Kvw^1d_kxxf zHtR-bBrp@t)}N6Noo*un3p4#3jgOdMipY(KG2`cG$CfFBp0G_SqFK5R-^F>ZocH+m zLuzk&1AblHz`?n=2nqEH{l~Y_U^8$h?vG8L-y(4mrcjSmx}Z_B;u+G45;!)#ZWT2l z9R(J)>M2yxc2u~g=!Yxkx2bWgRyi#3bkpp1F@y)LDulv{4iI|S!82^{s zfJK~Tb-Fj@+C!Y_#E#r11%32R+k)PvA#G28ZMSsg<6_g0XVS#&Z%&lk%k_zI^? z`L{1{XE%9kk|4>}UBT+IO_p6m?n@Wm@p>DjS=t3nvm1PB$YAKpjo|Yg#?%`3Cds`a zCeHKZuschX4V9UvD)~YI$24MoJOVNO5(m99(EF_Eu7dTa4WMDSAMK$5`|C11<+lfG zq-L83rZP{S>J?8z{Mz@Fqv?}X2tW>It_AVUfiRO`mVV!z#U9|)mi25Qa8fr{#JqWT zSd9~z|5>&+yEA2X&Ei5FBdJT@v;nl<%d4{)3(}OIAq|RkJ8IWEA}EtN^$LDeOcig1 zw`-PT{EjfmW|L|A0YEwK_P{G(cF+C%XvqmX9r^GxaQoWd)!64#L%^fzx8S3ZqH>+LXuO9xNa2 z+BPk6FQE$P+nCs1PQpo!Gy?Owu;J=)y`>#sR6%k_$;=U1fla*tP8(Gu8V=+K2y zMjc9~_6&U*bnn=Tp67;;4lDK5`_kGBzWIJnY7n1G z!#3@!b%0i{$vugctnsuyQa%HYqcC3lk*Rjv@i9S4V07A$>MR;C)8{VYE|_rnuPGo% z+IYzL~?1iBR{c!*%5p2 z2CBBy+E2)S;QkcZr%IJ`!lCiB%4z$FW3i?5`P6ZV&F1;kB(r1jlb}Bl7Oxg9DxQlC zo&uwO8>!KWL+>cfIVxNB({|S!b}{*d+vGs3`Zgi;e|HNyAiFyZuIIx}Q@ zS2+X|iAzh#rA6}4y(Q-+&#UH#7vH#DmJV=jdX8OfDz*`(pF`{VXV=NYU-kq$)omno z1}=54JS3C)^|Si?JTY1j(z6)a2f|LVxC+x56sa$YjQ_v(zWS}oZfjQ&0SN&mB&1Zj zkuE8Nl#rC}Sahd=gf!C9ARyg~?(SHy79m~I4N`I@@80{IbM2Swd(R(myw-0#J~8H; zBkyq!h)vASvkzVeLgmzDQsafc@13})7dxE`T;&%YfW3$=z;17ao*=+Ne|Kq2QSR7% zqSe=MjIpTk+-%5pfs$3Wsmupg>#|@5J)ox(M(=cXx&jD_jlp(-| z4!OqOg}Q*ge}jVLHoU23>71v{Y2sfV`4Ae?3{EmutY~OgnTrXa3SJ$-)UWQISOYXD z>W*ozn`#Nm3_gSMk%gQy%hcq(lZBK!kx#d`k9HA{uT~SS9HlW_E)P?$?HRGfd2(#y zFZSyfl*l(dXD((iSn4Top0)jM0(2Gvo4#(*l|N-ut*RGLhAO0A!?%k)j~PVBsu8WQ zX}YVD6GamY=up78Y|py-+`8>LhaVT`9u2qS*xdR^teYr_g~`EkPp9f#D^?nBnjcpx zLJ0LdX!3I@xQG5`&q<~&Cy9VV*5ygoiNbT!sUK?o=GrCd&Pt_U20G8u{1}%ubSfM6#`*xTfLP{;GdO zwK;g zO)XaIe)FkN6*3z>vY6y=4zI7D@>r)WT}M!giB`enGhe#|p?dN)O)AJlzw)A1yqfiF||RsR!i%cM-EiLB!C@Y52VIh#HG@4TM85SFG(+b+kW zZyPQ>FXDK#HpgahMw5Ddu0TmHU;i6Ey^?hU0YdDFUGH?Qc0i~GZzi9A?j+on-vgit z%b@{Kjmdpq^iG${Ks4RQTAyWIP)bupHA*~$0=Y)sWex{xhHa(YoRYD-ayfPjNd?!6 z-1-hxLJK4Qd?K#|-G7(#YgCF+;3TxlMrcUmUzMwC7tWOU9c*KxW|fd9qGj93YSvHU zG;h^U_8&CoZx@fF_LgDI5hH#>q9*&Qq=+1@)Udg13pUBMHZ7zjDzh6Lr!8HwJ9WCu z`ww(Aj{cn6+SSOy`$C7@PRJuM$j!53{5b{PJrCMMUK3*wGDok&a=J2vosScLAY%#~ z)e62!=z1MSN<_pRXv_yY92C0P>h4`0*IKn<*$rbTs-|)@V~V_=d|EQET?={= z^@gAhW^%>rSMf$$RWoi!zZTTV1Xy?q-CO}|sZI;y!eS)DPdS0lVPiQVmUq?A)(yZH z&Bjr;KRNLEGBeblvlWuHCTj0WJe^J(CU8$hETru4`e|+18lZyh9`W6rbX`j>9QqS) zsx#~<0|~cfbXzZM)8ETp`W><)fnUK~Fx|)ls*&yl^H71U&hNef;dx7&%WRbs*Sy#+ zZtgRApG#^Os&bxJgeKRC?6}qiyecV=g`J%!LcfR*mNXLk;HnPUonu;h}9F|o=gP|Dk0NcWj0Dq_4Qk2eN+rl zmL#qXN9&9@#fd7UgTcMBOYc?8iR$aQ`Uwf^aa4lS{lf(2ZytL0M4|_qoqeQRWIU;0@Y7M5bJ?dTWQ0fnRZX={t^is&90mi z?YalCP#3qx6RdR`e`60RHMXgfL6s8Xo@!9H6jN8M7|$~+G?@Uq|WeWW7pN8RLu zAJa`8s$6V)QMPhEHHa)UaK4ULcoEu}AVw~;43n6#gVneV` zUIqFYqHOhA&aBZO(NjgK7l&>dqiM*JCZ8;IDX~PpoH@_98j)R>rOdh6w@zij6sI&z zh?QO^bO_#*J9f2*BO^y)!S4Hqq9pZJVdTQh`l|)p*@7tsCx?ANe3h7yVReoGM}9Ji%v!^n!c+g;NJVw{_R4mGF}z*Zo(+ck0aBW(i}4{ax)h;WFlV+^R2F z)KdyYHH1zaDmZuUX>nPR1$1fSVPpZ1=TeHh)1mkiildfd41gKzDB?wqz9-_{P+^GtQz?Mfd%EA&10Y+u_*tCEwG_<+;!;uh zb4)kBO#K|!+m%aE7DwJPUr`c2Xf$fM65m%Cr`lX9>1U{Jn}5&A_Vmi9M|sTGsay); zGN)s>qdy1f_7SV2kbVVT=W6RQxvj)ZD&NMBPM^^qrey@1p}Vc+nPv%gc^F2+rU-=d zeq~KJ&M-7|u|#=skuimUzQ+|PmKROae9G!@l#ey1 zTF#pBT}V})gFXMzR1woO^Mb3p_nYY#hVIf&{kRi@8qX)^&t9uLTicfn@a%+3Hk-^f zHf*-#pRwX+>7>=2$bnR--gtJ^PupOIzKfkY7UdPJ)}72U7)39!J#l=k#R+x}Q%3Fm zOq@mqr#ROonkm#SUSqbc)n&c$WXfE#i(8sg zT8nTy#cju?0R@JtSm_6F8LqNc(ppl=UDLSwS(XWV{kma>HnZ9E6$zxQ%uA?pGrx9o z%SsM|UiQsH$Dal-5-|1^%AQ#l{BP?hb3y&c=*`gipJj>)Zz3|Ty?|etIdQfR@pNdU zU+nTXD2cV{W6EE$1#%hf5nS1)OM7uYIHS!EuCT%@((osGlHYEyVu z6d*(Ik7*AVUL`=CgGmKre|@N0s=LYydHiUQySSky3EjWseDkx#{EJhBSN>b&*rQ}2 zu^*RLeNP`1brDKO3C_J?MgD$Bva${Sn@1TyZxwvwLQf2mY;L|6gJ3~82euMR>Av~O z-bF6(d_$mG;+V=fwhzLu+lo9C_i1B1ze|tNF+X5VA2^S5wh}gtgH!JjAMIpbPYIZ% zV=0QVaVq7^QBefeP%ChuL(V1;+5kaP2$i^aLsyob3U)hycq}!TXrkX8LedAg4SMf zr{t36Yg85OmMNHE%aZxt8`tKE<1&tvDlVPvU#WcTwIbT!RLw#(gU2I=1(d zUOw9o8kdkfVV{Yf_ldLPYi2N+ydGh8j#eg|Ma)39&V1%%{Fi`)qv8o&!I>XJc9o68^c>l4 zv)S3H)Yl@;0y!0@eD+3@!EqL}R-7dI&pE7S>kGbcnVpo<-VXuA8KupI2iOTlXRT9< zgr>;>oYI15`Ix!ig99Y0Y{mL9?L_vJdP&K!Z6}vS-wwQm%b3apkao8P$aM zPH;St3oAI-z!5BNJkQ&lFnW5LK`_}blmR1@mz`}p(jInzOI9+^4X2Bts_=V5;xhc(ik*`OG<}W(Je_FCcOwdGxfpW8!1==! zstTDD0kv2r4I`yei|qy5DQ#ktFOu1`29^s0aF3%=Q5a`<{(ACbLW{2qe{w1*=yO~e zcTSXE#AAIcQwV!rcnY<@;y$p)a=N?qjd1$iP-)*7pYfMb^6X-*^z2^hxCPghP%hJ! z&d;l}mjha7bJQE@Z`v}qU%rUYWvW?j(sX8QYaNdW zl4T`t#M0#**4J|n8yB#6%Ew@w8Hk#QHF^?Yyg_cVz`F@)n}8B2TKaa}!K+9`vK4mY z3)U|<1O+C+xn%#i1JS7UlDIv=%%b?Bm5MLaZ0#jYIUy8H`LTZTP&|V z8~XS46Es{`*>cc+td9v6A@qz|07Qh!us1p~n7Q_CaClG8PpV>oE>- z9G(2|j(eR)NA&Pn^|w6NkA*Z%L4Ih==w+=* z2M}8Bdhwst(k0Sow?sz+*EmX zdH1>*rzH^Pg%0L`#`h+Q_bewmmtutc zpuCfFSpuKAem>{2nk^9c5!QEa_gDc&fAvMLE)0Q|9jJa?!aSY%;Q}LDbn1&F zNLySexFs~v+swRN9wM@!Impm*$BrgSTVX1GZ-ZlQbw{Jt!(myR#p&|HM{0f zWSHj2OQ9zxx-&IiZ$)Mw*i@N5K<^_0@tSRDjI?egw zr|I3b5jBYFwNsvKSLZ9AFx2vDnYMP{tYhzy9lIjg7hgtYt?IV9Y(10t z90dB1_?LPaNM`;?uoLYMgcmq#xuep4u#K;cIm*a}zDkvlY6~0j=HD4MyeU1ld1H@M1#TpVF4jNEC?wL9 z9qJI@?4syY!2f-g4bGZ+&)@eW zUwxmBQ}>xyB*%*FFn3Z9HY%7td7bGax!hL8T~Zv+cVBU$7$aWUa6yzXw2WYw|AXKE1w&f{8Zpdce^~B{?A#bk;Bz~|^=)vc4$_O=3VjVBaXf(**)uo3WS>(wnV>)yuXCK6 z#8QPU8|O5`cp)PCy#V>EF)<~j{6cCk*$=26Dq5d^@|P`cNcXIs&fw; zTO3BIQ#H&-@C1J0PZK3=t{54~|>Tiu3J%9{8}j zfO>&c^+WCX_0ycH+8V83`%fh)<=)yadpV*c##btFmEW{M4vRtul{233%fqR z@9o?4sLEz?ZnYiI&XZZn51NQ;>Wp5$H| zDbr1f-H19TD}?!gy^WPzmb)Y3mw<+zDO#QR_6e|!ImOeZ4{f#6LcP?%vgw*D_*W;g>0Vs?yMg*K#DYIad}s*L$_%HW{QHD8Q%t z=k@0LLEE1;_E-1c(QZV?O<`MA)Cw9s|A;zNji2b)Gnqv^z3PzBxZx^Y+JUEnmTVG0 zVTB`~gP-+D7cQgns#)xLwpBbLtFGe+uV7*EB+Zgcti8$p5aYnLm^RlrEtOSQw4j&N z;3~61G1;#~hTmm9D^655>^RUKjw{Z~zV1SVnvUh@AIGPuWi&krSpsbYw%T1s!u&gq z7tA0%^(;^#V(IOB(|w>ZFskEbrY8d($i*kqrV!Fy;cHoyjH_!PsN^kVp8-wCDOdNA zzR&4k7+obnK??t%A7L&iz*wkbYdx(DlIl#a;d~$6wkuOyd~%P8tA=VtNjynyqyoBp z$XR~IQ`i6es}6GGm){>r=k(*kWPkFL%>fr_WGKdYnc6^vb|V8$E=5q*__0>PbKgM9 z$>v>K;s9R8d5AW3Kp3eMMd|(~`SJ(+U(JQ?RrPQ+e|J#S;Byzjg9VSfS{R+fAz#>; zR+fss+{LmUfLopR#0*tJ8&C|ZkJg7Ujd&23{MNtY-HWov)nQc^?%&V}_SM@W{hPnM z&HOz+0%;Dv0PZ+u)O`Xr#MufiwlNP&;PEc2As)s=o#0+V*WNs_c#4sS@5D{kyvVSt z6==)Hh?f~qMKlwj86o>VPo8s!Y-*)EGD;|6)~3!W>XI8U@ytQIjVe# zl(!w;NX995gaZCWcgu5KY*Fp-(!Tb={B2Tvfegv%cW{f4A^veb2kgeVE~vYaM=)*V zPSDy^H)3v=yM7X+VH1wI5kKx@9xmK%(xVo(=Jn`ul~}*j3-q)FX;qW8(@qkr_B>6t z59^?EXUpW3ogw>eo9KkgjQ{x1$4~pj7yb1ohX+^EzDMOHc26L9H0f9@j;fe5rlcd2 zsirq#=i5>W5FY$e*KKt2Y_?6o3zv(C+RDKTv%EY@2_Y)QEOy{D)7|N4h%Wl6=Fjdmk2zU_vy*Q zQH8a5*qDxd;-2x-R>%WmNg!@~LRq03(Gon_=y9>UH?m}l(3r{k5#(=*E(YIbiB_3N zx%UP=W^X1|f8~U`u7|wW;p9qNRANW^VY{{Fq$9i4c$ny!j$ru$2fUm7Iv4&*(I-X? z8XTjdo=gV2?~V5L8g4bm#PZ`4>S~SSw7IqgjabviDEHhgerNHG<8O4v!p^qzzY;bM z8IE7$p`+a0x9L>T$f|x*Ff`G{+6Fxk9deDUS5ao-=X1W_2C9un=0b*Pke z9?oa2V{(VCGfV=odIEx~)qr)HJx`d7aL^%++KBq=x*=6G9-#K=!=)!oL5WqcCJ}O% z<*hWwyRJ5T^EMYIG|Sb1ZNoUt*nKuySx}65EbRHqwNG8`TPg=r#fqNx>9e;YV^0K} zt(8Lz>jUmzFJf9fD`z>Mbd}MUUTZuC)!Xk%*}(hbkD%aGb^8!^KeqmpYO17%?ocgm z)qY#*paOoS+4v|ue@flx*#fcFOs&uN)P0Gn%RNRp2c|})sUSpkxS*dFn%zyN{3hq< z^Q&J7D4lBOnl`-A7n_c~L*$j%A=WvMs!yIuf4pX#S&UVgHGl0%V8!D+$hpHkt;{3l zxrai+re9b=`ckeoOiORmFyL^007Z94nvg{h&8lNuX^=*k_<2A$X_w&xFPvd6+R`FK zwc)7cZ_$KuJ-1ey!@eqE(r9BdOh^19Sw*U!eUjfV!qxkMBL^`R#A{!tP5?lUf~G;K ztmC_nVK}`p3^e!e-%r8*>inxkDGQXt-fxNw_0xpiyAZ1b0kDr7P!qOK-B4Uv4$(^X2SdlmA}8KmAx||MO%aKwfi*w+W`i@3d1e zbAp!S?Xdo{w^zROBJptFSo^HMk-joi<-qu^A>_b7As0Q=#F}BceiWk#x z)10)Scg7psySgn60!ygu$S3>Ljh@-}zMbODF!g>me%NG~r;sJ7qyKV;WbfO7A_|)D z?^4`F>~=nLkJ2QR`uT;@tjz~TtD)p4_MoJ8X^-F)JO9mwf6CQA##Zb!6-Fkg9s%8P z&3;RMs+V)Lbs|Q41Uun54fnbP1eFBB#PiqVD%$ws>QJfF3m+2x0!D~7ik%M4f6h_& zhEdv1c4w2ry!Ay$;;$0jHUj`9_D2wB*r$AZ>339Uq>pi*?rl{yIQa0_3?Fh+8Rx1Q zvKR>p{-~!Yw9cD;i+qn;dgOiT+Lt#lch-w7I$sN!>r1wBaKM|Ss31~&ol~TMv|zL3 zZ3tlAymqku=uf&+9LQ3_n>h*CZX#B=(s!^w7}YG6J$?E1%Yd1H^@Y_`h3QuB)0a)s zQ|kcayWKli2x;Z<|MT^75$~nd%+Vr!#lp%Hmd~DN#tJ5VS&a{MDe&)3TDjeK@Z=LE z0fKI1)YtWD+MX)bZhF7#T}!42x6KsZ49nzOTj)wqy1;9fay|ta%$UZ8ib4mUh|hr& zd@GzoEr(^Y*7wbYZlVto%W4tHSVlTPRDoX*<4^Z%?|WN#feE%S(vwly@irVSYj|1K z0nrMli#5rXvu+m*5v)UyEDg*uNZnEJSpbR%6k>rb%0~p*5k)h#8byDm*A$ljL~T}j zjM)S&NDzqQ4!lePr$Z6sP*k$dU!9p(-3ihMBq|oVNYq^Ij zZL(~RDaj`b{~m!%m3HC$lC89sl)X4oz{*mNGxe{U2Z%(Ndi30mf5f^+0v>CBZQHSM zOu(iRne$drOSGRo9L~Op+X**k(<;CssN!5{osW3O@Am^R+Xy_ za$pv31Zm_P`(1CGAY=SufmS|GkW~Esk_q3V4s@`Y#wChsSTFew+64{r>u{xr{aaG5 zmO(&Lskw?d#M~|VX6Wn75{b)~ZxU0{1cvLcKk{arpq{N!S6n@Zaz=oPWrNZ#s~VT* zm9IHGkY~!c)%NU=UvR9}+)M`Z1^nz>MQ@r&(xUDnd1usRY*F+sc0s~3degZt49kPp z+su|!8f=x!({`2q-7R8W2B0&fGkT=j`RlKr7WRWZ-#_Uxk!Mr=eh`K;c2BJ~cu##3 zr_)$k%sPKl6ZDOb`dU3P#Nrr`o~Ap$0>F%&DFVxFymqz?eD`ol)+niV7EX26p9xmG^jVcUN-0ppw&JIN5sj&%_5bmGO=z?q z=O@VHRlg+Xd2=qOPN~0U5g}g=myGl2P&hmMaxizjLD%G5mW8K6X3&Vtl~0iaS76X8 zi~OjR?RWX^i%Dgz><1U7xKcYr-;?7xn`NrAk|m`xsSY9A$e{QQ0>g?Q2ex%9m9k|v z0MG^q8uah}`S^|9Y&MOZNhf}#nZVrghH1Nz%w(I)%>Goj_SX$8!i@q7XNnox`$(@< zU(J9mV4w5V5vuu^kiTPbNB){UJdVCV;_;hE;T=&DABEou&}h29Y@iT2&8AJH~oS`wP#fe+Js>Qgi<1KfBY380^j`0^fB!qM!0RcF*2>v%GDT z8S{JWeb7%0Z3?pcXI?>%pdnuQ6DxZ)KllhU=3K%#ImC+|$w4C?8LIc*mn`64TcB2u zE-a5NYmQCI>FvY$O=d|=C^RCx92%74sEf+<)l6AI{p z5!7i{Yx1~Fq;hqVl~+c_7gM@hk^pMEUiWB{S-$mWJn!bpUSwvO^S)k7>(uI<6!U4G z2TzotCEC(4cCOa%9E1s=6446gS~gc(_yZ4{;GLCQB5@3sjzOGkxC>kb>w~IJXz~tA zPtw|^puhm7*X!hR7#aNQgLi=r11bD5?V^R;LYOw76AJ6z@!q3?(LEM0DbzQZNX5lm z-^ee9(dAT7D0&Lslma;_BkG55z`sYi6G5^_{fPnlGUe(KJ6h%p}(V*xP_a>m5|v_q!(Ei)+JHG~4hrZ~<^a{5vnX30d7t5!_pTotE$OZc=r5zVof(DsVZ7x?X$Ct|N3;< z^zG$fL!r600{!aLq2Fx%q=Yk2fE5bdBI9v6FerQ*m+(YvF9dx79XR}g&UbY)#%6x}xdoO;bhQ zrzh)r`JcFH2=lE;+o$_grpRx3toPCwXZ8vOe!!{4>}9!2>9oT|4CfAgNZTB|K1(#^?tvBqahUpUVN~*S}bHcWO70eej@F zGmeP@d(HPc50$`c>6I!ooukGYzH;e}WipS(9?xu z0Kbml^;IV?-HY<81`CQnm3^LUkX8H3iE%Y*2FmX_BLPO~_HcSznME7-L0Qlr7o+vg z2YQN)u4R-w?N)!_%C4ar)N{MM6gZP55ln)U&K#$;2>~voifGB%&N{-Lp$|E{vSluE zu*CK6ZEcQNXA4Gg`~{}&_8>u9{2&l!dIQn9i6l~pKqNteAuzpn-G(jP{S8u=Wj6iA zwkW7Mp%{r|Lvza;#ddR3)8MGUp*L##Q-Nk3e9s`WJNANmkw@4<F;Sm+S5 zkHL2QWfm6XEF?PGIib#zXyLHef5E#yHDdku{(NWBc8AD9DyyvfO=Uhx)cIrB{sX%vjL2&om(`3?AlzXRPnT5c>y1Q44c zPuKuP8%$#;w#^%yhT(`j+lAmhfIJCV=()cO4JG031*DG#8;b)9z<;m#-4k2G5u^0Q zKc3!Iu|`&*Y7G-#?I?{6;<(W2$8Nj)wz0tItk0}SP^tc)m!U{>8faG&>8rs?*K#3u zk#6prtvaxlI8feL;Q|CnVL=jj*&vvKS^nB&y56OnlDWcUM6@@Kg$2ygD%$jlq5pu1 zjpTg&{n>=U!4wEn-hm1cGRCg!I6^?H((J?CXJ~97G0`_wo6{$l@yCum5e?)^994_4 zTG`vjXX>2#POMHPLkD5Y08d4=CJ;U2{U|8!N5)OvG5XB9BqXIl`5~FWa}B5k8(d$k zqN)VdEqe$Ry@|^jpopu{A>o22Pqt$hSs@gt7N0zlPf?prQB&j+)BozE*x|B1@Z+lz zGV~kfGU&$1Rm%MeoiGTJU4;S&e&;>Q+C>>9#Ix4t?d;{3xt5@Rh*>8t+(%=1=A~Zx z0BH%OKuhpr=!0D-kv1eoWg|5DCLtC$oFD^xS4uE_7S0(Ze4U@;e$pW@S?Si~4$zln zwkwkQy^Qcqw#|XU3#?%GjHP?UW>uAw)&+p}s$zx|M{S}wV^hV(V4yK&Zkzl~qCtX5 z6lnN(#XRw9d3PJv@QFFdHBNw4mDR9j_oJ7t3OS5ch%N+m3w1I#qhxz1n0>}d_44%# zyiUs0!1JLV3-;#~y4J~T`u+&&aL^^E3 zJ1iw%z>|SUwdRjGH?d+5*M`D18`>VNQ0-xI^a)PHXOqz5G|x))uB7-Ukl2^IWJsKDv2(LrbGT}tZAP^q4Kf{r)^V3hoBj~ zFV*W97S91Ej@Vqt@5RAy8A9)e8}P!-{6^r6M4Zlf%^^5do0znbsKv*;WQ`u*OCP9@ z)N#egjsiHjs+)k~?7YsyKVVwZ$|>%VTtzhO&nRmqnWaQbv*Ssd%rZAiMGS%j|Hpcf z2BtRz@ax|=SR!Y*do2anRr^gMt9B#}VBE{W%{Y`lRTh(9q0%k!ToL!Uni~h*#Y%EdA1stBeLTf_g|%~*O%ppqK=tt^5yW=)?!A)teC_n&&p*GB1H<1w z7Qgv+Gmk3NNd*Ae1p0#cD5t2hA24e-UbfeogSFtQ_XJpjXTWhdNODvMMoL8IL6e>i zG@0CmJ2Z0GUj)aI9n3!SHm03==rir)_V8`hh*Xw+meA`G?^MB2aS6ImBlUGTm>5aV zeJ==QlUGe<{plpKT8UWzsXUp5@a3K_t$6I zB|+vWMoaWKKVlQ-WLYo<#$@q@&N1MRUh;Wd@3hq}Zby#HB^;?3$EZdHpt&|O91o9A z%$n@O-~6>I9AH&kDER1*^qR#mrAtpHBQv`~(jMSz$bqA3Mzcn{TLzQl!U@#P`Kcl& zTf?2^6{9tRy3t3JMf?ubb)uUQf2ClZCqPssJ>P=j21@InU(s^)^+Vh(-7PSn_y68+ z^?z36(G&$*Jd)x80qi*qU|yDb(x(0a+{j+~5Fltd>f1)~9TXbKX5B0m4FH+`Zhj-& z7W4==SI)*~7z+v`gx<``=+jrIp^Bram(U>-O#)!+2VZC7)(Xtb>(Dc7J=s1g;as?-K=_6ZqNJ!{vv^iu1!dX zthBpqfzqKZv;`?<8Ne;G8!seISWa3~9s1)ssh=9-GuNS!-}?C8cX4q!4(rzar7qBk z^o-rO!_oAo6I4JQ^66tC{QX73qgkAid5|j#t(?K!mw8~e=gI%UB_E$<^8KI^uGo-r z>r{taMMPap$%*V?DZBN7Bz}l)D&?xk@N|P)6sYCg6n3q#Y|a9;y&e2Oz(9fT8>;EEQ03tFPzKD|rCEeW;-ip;n%$dU4y4n)CJx zH`GNp;LG0YY5S&~bh9+&Z%xV{T7%5FzcG^{&((A!MM@ZIrr zT>&&$)f^u)AM}ATVcwc>94Z4{di6NZnfovIgbM2@i@8dbusqY;Y63;2rn6O&XQNE@ zzxt0C3tSF4tf2qh>37oyNZ|#cI5<5CWDoHh_RqBl%rK=v(;eV)p83wO*bg}CxUQtX z$g1-96*W$vwmh3T|Ar8IU*3m``*y(2)`mp>nm0iv799dlBt~YF<|P9lJhtS=-dwC5 zW9O%-*MX$Me=_&2X0XGni<|yT?WrdUxRjMLlVGiaBDN9_5wVisKl8o-^i@Jj=(iXS!dhhnW6E;+_u zmiXqj3+0NMxFM8;8*54d-TcIU(C$bMu}2hl|N9q6;vIqx0Zq_l`1SLeTz0Gd!=KZJ zgs*>c&4C8RfY_WU3cOX%9MepkIWEhe@rn*It500sfXXJXtdeLtNcER&%tbP4E9BT`6-BBm%9@vA4J^w z?_Yc9tJi*90PtS&Ob@gN%qoBKX(oJq2Ze@>w%{so8GQuj_}w2Xpax{WSb*p}>ZT_Z zOdWl^f&Y&$SqR|$exE7O#DMQ3gCpZZ@E!2@>LjupXjPcV|8POoBs6#3L=?yE%+yKw zq2pU@2E5Izp?Lnyff?jyKpa7Q-Qac_JCMkoYEt*l5(b*M68|#}9Sl#gbwboa^5lrU zX(&aIf2`iOU9;dCw={D_#8O%E};l_z-Zy3Ir725i%C6z|KMdI!OZ>4S3_8OXoEP6x6_*meC>L2g_m&TyFnZGScSchZXB3l7^U=4n`T;LX8qC-^Y1~(>G zXo@Wa2w|UaaVTrHBAs6Tk4F%H$_!p$%HXJ5YfxtW=;+jJJa2MU5OC2AAD$=@Hi;(E zkx^~X!fQ$R?0-<8=cWqSE&TlF)vYu~K=JEvMA$7#b8J_7p)TQ1*r<-`uf~`@qz~Zz zEMd}atUubGR>2Wyk(-@#xBSN~4+Yb>CxSFpmxU}MQ5T~=gs=;TgJ~W&x7-FZpQ1tg z6aIPEH-q^xP*u$RkRN+9cL93Lw&}OsMedcv4U_!mr4xBxhAy(Y_V6j+XL?7-Ozk+A z_Hya~E?=p#S{$<`atn@htmCv&c9-Q;MNi<-7n9V$DKmVG1-dGOo<|9SZqWXCHZcO` zkF?;B$nkW!3JF;OZzGmjlOB*taTeW-egp}F&WTj_BAAnT!h7aTmw#RyP{7k?K+|pd z@bbYqhd2fQUGxj1!6YKHSrJ4Ba|0m0$7q+NDHa@ijLW}W&{DZR16x9G+&ldNKZ>mxcn3P94hK!L>tshMRwSi+c>)D&IQ-jl_tTUHec!}rHcnK54fg&}HmiR9BS84P>8f?yoz<)>>H$^O zFb)aM@4o9le(#RwBfea%?!SwoCOV@)%B#U9vr=`l1h&?PwtUrdlR!~wWEqIH>?Pb6jNZwQBC{7mk@=VW7$627rSRe)oy|_ddEVywwx($z0^QXH-+al>q zmTeFE#BQ-5XEHa>CK#@ITwlV{PnU%DL?_N_LQz>po^E3swA@>4VxZtO*!Sw=Pe~VZ zAZuIK5_I(+7HCu*BUqo}YlXoNarc_(0QmY$(7E*F?M z{<`xA%ov(nePESu4+~p5wlp85jPRCCi1OnKbkahEg2OEG5~P&&>QP!~3q(nf_<2^u z{^<*lqveFJ#*~kMhKb2+UVL8vYfBr<^n`fgT--2oN~Z9wpdXT=eFNi78X*lJ<&ytl z%^)2Dig_srN~+usFEy&I)7Ln0?iV6-i1Qwk{LddmIK}6*W5ICeL!Qz*))>Hp`Ocwf zy4KnfMyxo%!i*RPAdpx)U?(e|X!vo>P@t)OQf`4wKy3BrscX9%voT|d&9aq!b=wcvOs0-9;PAh*_Is9gfikW5_z|bb?0^a7Wvh}%-6ymO!tZe^O`cbzhidiCr8#KPLCuCvp^Cgh zXUkFVd++$my1Sk36vhC|LwM;T-gr#ESGb}}{4EFOEd}?3c2Sc=pcXT6fcHkjMACgazJ$>F=1ru z0VChW1%?t!sM&9brw{16rwy;(4Gg%=ke@zie{BM&5K;=Ce5MP(;ZD52nZJ%E>bO?z z5-|=wX2pK{U~~p?qixPNP)LS*@`0Zfc2;3Iqh7azHzj~_4;@1G$@wGR_Tt8@f#~PSW*^YjuW`m&`W21q zOh%~afbG<;K}Sb-&oYiP295wJ?9D9b=N=pM1!B{Al|FC}2RrH(Z)oRnV9YSo{miz- z{&kMu1;}-XX)g`~g{;|8pp^Lyq|b}q6K#&?)9}f27WzD)O6D8KzW`}Vy1k=vt;|EB zMP1NEs|h28d~QclrwDL2Mg;27Yv0|8{XHOD<8X>b3)b z4~{YjY2johB;oH=W$7XRyla5&<+a6_gBnU7T#+R}^+YrcUxTO##(hITt}Lj@{)O1NL1qhMuO^+X04x z`6L1wZ#aOus2cF_>33k)X%0pTxqIPYE~i?V!8;wpjNw(bCtwHMX>Yqtmt7#2y*A;H zpcThY26~0k!eM<>0t}v{RCOx=4&o@FQ`bLV0Wb*zK;Yp0McQZ<&Xn!idVz@qz9&Tu zW_N+vQjnJRs@8GaYz$ZaEvN@G08cg+V1jNYPGad|>8VC6e$z-;^kh6JlKP(_(M>RA z97BL{?&SS_SSl<7<86q(tYBIroGvv;Q6@q_-Z!j-x$#X|WQkbto3 zP^Z#>TdlkkEB|(jZkU$_YKnt|jPkArc&j6|ed*f{g*^D1ZH2B{Vc-K0i9F#ce|C#j z`;7~p*Tkj!r7RM>m4yXoY{D&G3et;L=}hmFq#3Qit@@_3jXQ2}HJYCTbN#%9>A`og zPof%pN6t*Q$qE_BigzTWK)mzjR?d%0?%eW$5vJhX*=LaYg}KqdRiTasOn=Xjy`{hc zSB-w^l6p6Pb61-8d-ra8A_Mr_+0;RSQwb31{l2K&$Xomgf=6I={6agax*~uao^YWD zi{D}rN5EACOjfJ0`8TU$)>o!=%gd+9fYsrmPkD>P46dqaUZA{fb+Ey^A7m!0^_2iQ zU?j4_Xl_}ZiJRSUL9KVU+y}f>feAIi*IQPn6$qY5x>lOs>qc0qP$QY!R>%8}9~Ua? zPZ^{}aMht-FwJe7l=(&s!G*ni5^`V-kNOjy-6GNU5b!eboM^#OS>OW=P1{N*ZV>|x zDUf?hse$Af*sU5uRYIGxw@4HPT=Ww85!%i7{ZHDxtoBUx_XIdX1c})?BDZY@#hZ5t z5;z=Sy4m;nf@&nUi2W^)0u(Q8|Is5_aqw1@&wq;C@=|B7!QUDyc{WKNg4bKHHq5)_ z`ywQ69w@J0`hyJ^7N*Y7wv5|0)=O}eL|a15G9S2A&1`D{`7IK424Y|R5=ayA=|&#J j5zgqhT(r#PeT_Y}_H;4StbXAR`1ejiR=h}5$LD_m_Ib5T literal 0 HcmV?d00001 diff --git a/MapboxNavigationTests/ReferenceImages_64/MapboxNavigationTests.InstructionsBannerViewSnapshotTests/testAbbreviateWestFremontAvenue@3x.png b/MapboxNavigationTests/ReferenceImages_64/MapboxNavigationTests.InstructionsBannerViewSnapshotTests/testAbbreviateWestFremontAvenue@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..dab808adedf292358c688bf969041afeb6846404 GIT binary patch literal 25375 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
t~c5|aso=Vi?rIus*K!zh9yyz*) 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 pN3b;-Ft}6D>WYxiTmI7qhX= Date: Mon, 12 Mar 2018 14:06:16 -0700 Subject: [PATCH 09/11] Update --- Cartfile | 2 +- Cartfile.resolved | 2 +- MapboxCoreNavigation.podspec | 2 +- MapboxNavigation-Documentation.podspec | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cartfile b/Cartfile index 21fb230ab9..0e790adb3f 100644 --- a/Cartfile +++ b/Cartfile @@ -1,5 +1,5 @@ binary "https://www.mapbox.com/ios-sdk/Mapbox-iOS-SDK.json" ~> 3.7 -github "mapbox/MapboxDirections.swift" "master" +github "mapbox/MapboxDirections.swift" ~> 0.18.0 github "mapbox/turf-swift" ~> 0.0.3 github "mapbox/mapbox-events-ios" ~> 0.3 github "ceeK/Solar" ~> 2.1.0 diff --git a/Cartfile.resolved b/Cartfile.resolved index f6a7ac2105..07ccde97a7 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,7 +1,7 @@ binary "https://www.mapbox.com/ios-sdk/Mapbox-iOS-SDK.json" "3.7.5" github "ceeK/Solar" "2.1.0" github "facebook/ios-snapshot-test-case" "2.1.4" -github "mapbox/MapboxDirections.swift" "9f690d7d4246b1a05dd6c99fa07aec1f59db66e3" +github "mapbox/MapboxDirections.swift" "v0.18.0" github "mapbox/mapbox-events-ios" "v0.3.1" github "mapbox/mapbox-voice-swift" "v0.0.1" github "mapbox/turf-swift" "v0.0.4" diff --git a/MapboxCoreNavigation.podspec b/MapboxCoreNavigation.podspec index f4220abb13..9ecb642170 100644 --- a/MapboxCoreNavigation.podspec +++ b/MapboxCoreNavigation.podspec @@ -40,7 +40,7 @@ Pod::Spec.new do |s| s.requires_arc = true s.module_name = "MapboxCoreNavigation" - s.dependency "MapboxDirections.swift", "~> 0.17.0" + s.dependency "MapboxDirections.swift", "~> 0.18.0" s.dependency "MapboxMobileEvents", "~> 0.3" s.dependency "Turf", "~> 0.0.4" diff --git a/MapboxNavigation-Documentation.podspec b/MapboxNavigation-Documentation.podspec index 4e1b439fea..ff12a41555 100644 --- a/MapboxNavigation-Documentation.podspec +++ b/MapboxNavigation-Documentation.podspec @@ -43,7 +43,7 @@ Pod::Spec.new do |s| s.requires_arc = true s.module_name = "MapboxNavigation" - s.dependency "MapboxDirections.swift", "~> 0.17.0" + s.dependency "MapboxDirections.swift", "~> 0.18.0" s.dependency "Mapbox-iOS-SDK", "~> 3.6" s.dependency "MapboxMobileEvents", "~> 0.3" s.dependency "Solar", "~> 2.1" From a8d8fafc0a6a0ed8f7aa1ab882972996d9c6e6a8 Mon Sep 17 00:00:00 2001 From: Fredrik Karlsson Date: Tue, 13 Mar 2018 08:21:03 +0100 Subject: [PATCH 10/11] Assert number of processed components matches attributed strings --- MapboxNavigation/InstructionPresenter.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MapboxNavigation/InstructionPresenter.swift b/MapboxNavigation/InstructionPresenter.swift index f40ec00db7..48455ac33c 100644 --- a/MapboxNavigation/InstructionPresenter.swift +++ b/MapboxNavigation/InstructionPresenter.swift @@ -99,6 +99,8 @@ class InstructionPresenter { strings.append(NSAttributedString(string: (joinChar + text), attributes: attributesForLabel(label))) } } + + assert(processedComponents.count == strings.count, "The number of processed components must match the number of attributed strings") return (components: processedComponents, attributedStrings: strings) } From 977727dc96dfc01d2f9974224b2c3c2bf10d19ea Mon Sep 17 00:00:00 2001 From: Bobby Sudekum Date: Tue, 13 Mar 2018 09:55:07 -0700 Subject: [PATCH 11/11] changelog --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d84e18284..6e8be29794 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ ## Changes to the Mapbox Navigation SDK for iOS -## v0.15.0 (tbd) +## Master + +#### User Interface +* Added support for abbreviated top banner instructions. [#1169](https://github.com/mapbox/mapbox-navigation-ios/pull/1169) + +## v0.15.0 (March 13, 2018) #### Breaking changes * `NavigationMapViewDelegate` and `RouteMapViewControllerDelegate`: `navigationMapView(_:didTap:)` is now `navigationMapView(_:didSelect:)` [#1063](https://github.com/mapbox/mapbox-navigation-ios/pull/1063)