Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 74 additions & 24 deletions ios-native/App/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -515,12 +515,12 @@
}
}
},
"A place": {
"A place on PetNote is a spot on Apple Maps, like a park, a café or a vet. A home or street address can't be added here, but a meetup can be at one.": {
"localizations": {
"zh-Hans": {
"stringUnit": {
"state": "translated",
"value": "一个地点"
"value": "PetNote 上的地点,是苹果地图上的公园、咖啡店、宠物医院这类地方。住家和门牌地址不能加在这里,但聚会可以办在那里。"
}
}
}
Expand Down Expand Up @@ -688,52 +688,52 @@
}
}
},
"All": {
"Addresses": {
"localizations": {
"zh-Hans": {
"stringUnit": {
"state": "translated",
"value": "全部"
"value": "地址"
}
}
}
},
"Already on PetNote": {
"All": {
"localizations": {
"zh-Hans": {
"stringUnit": {
"state": "translated",
"value": "已在 PetNote 上"
"value": "全部"
}
}
}
},
"Already uploaded": {
"Already on PetNote": {
"localizations": {
"zh-Hans": {
"stringUnit": {
"state": "translated",
"value": "已上传"
"value": "已在 PetNote 上"
}
}
}
},
"Always choose a public, well-lit location — dog parks, community parks, or pet-friendly cafés": {
"Already uploaded": {
"localizations": {
"zh-Hans": {
"stringUnit": {
"state": "translated",
"value": "选一个公开、光线好的地方,比如狗公园、社区公园或宠物友好的咖啡馆"
"value": "已上传"
}
}
}
},
"An address": {
"Always choose a public, well-lit location — dog parks, community parks, or pet-friendly cafés": {
"localizations": {
"zh-Hans": {
"stringUnit": {
"state": "translated",
"value": "一个地址"
"value": "选一个公开、光线好的地方,比如狗公园、社区公园或宠物友好的咖啡馆"
}
}
}
Expand Down Expand Up @@ -809,16 +809,6 @@
}
}
},
"As it was": {
"localizations": {
"zh-Hans": {
"stringUnit": {
"state": "translated",
"value": "保持原样"
}
}
}
},
"Ask one of the pet's owners for the %lld-character code on their Owners screen.": {
"localizations": {
"zh-Hans": {
Expand Down Expand Up @@ -1491,6 +1481,16 @@
}
}
},
"Choose somewhere else": {
"localizations": {
"zh-Hans": {
"stringUnit": {
"state": "translated",
"value": "换个地方"
}
}
}
},
"City hidden": {
"localizations": {
"zh-Hans": {
Expand Down Expand Up @@ -3454,6 +3454,16 @@
}
}
},
"Keep where it was": {
"localizations": {
"zh-Hans": {
"stringUnit": {
"state": "translated",
"value": "还用原来的地点"
}
}
}
},
"Language": {
"localizations": {
"zh-Hans": {
Expand Down Expand Up @@ -4357,12 +4367,22 @@
}
}
},
"Nothing found on Apple Maps.": {
"Nothing on Apple Maps by that name.": {
"localizations": {
"zh-Hans": {
"stringUnit": {
"state": "translated",
"value": "苹果地图上没有叫这个名字的地方。"
}
}
}
},
"Nothing on Apple Maps matches that.": {
"localizations": {
"zh-Hans": {
"stringUnit": {
"state": "translated",
"value": "苹果地图上没有找到。"
"value": "苹果地图上没有找到相符的结果。"
}
}
}
Expand Down Expand Up @@ -4624,6 +4644,16 @@
}
}
},
"Parks, cafés, vets and other spots on Apple Maps. A home address can't be added.": {
"localizations": {
"zh-Hans": {
"stringUnit": {
"state": "translated",
"value": "苹果地图上的公园、咖啡店、宠物医院等地方。住家地址不能添加。"
}
}
}
},
"Password": {
"localizations": {
"zh-Hans": {
Expand Down Expand Up @@ -5609,6 +5639,16 @@
}
}
},
"Search for a place or an address": {
"localizations": {
"zh-Hans": {
"stringUnit": {
"state": "translated",
"value": "搜索地点或地址"
}
}
}
},
"Search people, pets, tags": {
"localizations": {
"zh-Hans": {
Expand Down Expand Up @@ -7974,6 +8014,16 @@
}
}
},
"Use “%@” as the address": {
"localizations": {
"zh-Hans": {
"stringUnit": {
"state": "translated",
"value": "用「%@」作为地址"
}
}
}
},
"Verify your email before commenting.": {
"localizations": {
"zh-Hans": {
Expand Down
48 changes: 48 additions & 0 deletions ios-native/Core/Maps/PlaceDirectory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,21 @@ protocol PlaceDirectory: Sendable {
/// The places Apple Maps finds for `text`, most relevant first. Only
/// those with an identifier: a place of ours can keep nothing else.
func search(_ text: String) async throws -> [PlaceSearchHit]
/// The street addresses Apple Maps finds for `text`, most relevant first:
/// where a meetup can be, as a place of ours cannot. A meetup keeps only
/// the words of the one chosen, as if they had been typed.
func searchAddresses(_ text: String) async throws -> [PlaceDetails]
/// Drops everything looked up so far, at sign-out: the terms' "temporary",
/// and nothing of one person's browsing left for the next.
func forget() async
}

extension PlaceDirectory {
/// None, for a directory that has no addresses to find: the unit tests'
/// own. The app's two find them.
func searchAddresses(_ text: String) async throws -> [PlaceDetails] { [] }
}

/// Apple Maps, through MapKit, with the temporary cache the terms allow.
///
/// A place a screen shows twice is asked for once, and two rows asking for
Expand All @@ -60,6 +70,7 @@ actor MapKitPlaceDirectory: PlaceDirectory {
var place: @Sendable (String) async throws -> PlaceDetails?
var address: @Sendable (String) async throws -> PlaceDetails?
var search: @Sendable (String) async throws -> [PlaceSearchHit]
var searchAddresses: @Sendable (String) async throws -> [PlaceDetails] = { _ in [] }
}

private let lookups: Lookups
Expand Down Expand Up @@ -99,6 +110,20 @@ actor MapKitPlaceDirectory: PlaceDirectory {
return hits
}

/// Asked afresh each time, as places are. Each address is kept as the
/// answer for its own words, so a meetup saved at one shows its map
/// without asking again.
func searchAddresses(_ text: String) async throws -> [PlaceDetails] {
let text = text.trimmingCharacters(in: .whitespacesAndNewlines)
guard !text.isEmpty else { return [] }
let started = generation
var seen = Set<String>()
let found = try await lookups.searchAddresses(text).filter { !$0.address.isEmpty && seen.insert($0.address).inserted }
guard generation == started else { return found }
for details in found { addresses.updateValue(details, forKey: details.address) }
return found
}

func forget() {
places = [:]
addresses = [:]
Expand Down Expand Up @@ -187,6 +212,18 @@ extension MapKitPlaceDirectory.Lookups {
} catch let error as MKError where error.code == .placemarkNotFound {
return []
}
},
searchAddresses: { text in
let request = MKLocalSearch.Request()
request.naturalLanguageQuery = text
// Street addresses, which the places search leaves out: a home,
// say, which can hold a meetup and never a place.
request.resultTypes = .address
do {
return try await MKLocalSearch(request: request).start().mapItems.map(PlaceDetails.init)
} catch let error as MKError where error.code == .placemarkNotFound {
return []
}
}
)
}
Expand Down Expand Up @@ -287,6 +324,17 @@ struct StandInPlaceDirectory: PlaceDirectory {
.map { PlaceSearchHit(applePlaceID: $0.key, details: $0.value) }
}

/// Words with a number in them are a street address, where `locate`
/// finds it; a town is added when they name none. Words without a number,
/// the way a place is searched for, find no address.
func searchAddresses(_ text: String) async throws -> [PlaceDetails] {
let text = text.trimmingCharacters(in: .whitespacesAndNewlines)
guard text.contains(where: \.isNumber) else { return [] }
let street = String(text.split(separator: ",").first ?? Substring(text))
let address = text.contains(",") ? text : "\(text), Medford, MA 02155"
return [PlaceDetails(name: street, address: address, latitude: 42.3876, longitude: -71.0995)]
}

func forget() async {}
}
#endif
Loading
Loading