mirror of
https://github.com/vector-im/element-ios.git
synced 2024-09-28 23:32:41 +00:00
vector-im/element-ios/issues/5298 - Improved error messages and moved map configuration to the BuildSettings
This commit is contained in:
parent
f0cdbe5a7c
commit
352d56726e
16 changed files with 73 additions and 79 deletions
|
@ -15,6 +15,7 @@
|
|||
//
|
||||
|
||||
import Foundation
|
||||
import Keys
|
||||
|
||||
/// BuildSettings provides settings computed at build time.
|
||||
/// In future, it may be automatically generated from xcconfig files
|
||||
|
@ -364,4 +365,8 @@ final class BuildSettings: NSObject {
|
|||
|
||||
return true
|
||||
}
|
||||
|
||||
// MARK: - Location Sharing
|
||||
|
||||
static let tileServerMapURL = URL(string: "https://api.maptiler.com/maps/streets/style.json?key=" + RiotKeys().mapTilerAPIKey)!
|
||||
}
|
||||
|
|
|
@ -21,4 +21,4 @@
|
|||
"NSContactsUsageDescription" = "Element will show your contacts so you can invite them to chat.";
|
||||
"NSCalendarsUsageDescription" = "See your scheduled meetings in the app.";
|
||||
"NSFaceIDUsageDescription" = "Face ID is used to access your app.";
|
||||
"NSLocationWhenInUseUsageDescription" = "Element needs access to your location before being able to share it.";
|
||||
"NSLocationWhenInUseUsageDescription" = "When you share your location to people, Element needs access to show them a map.";
|
||||
|
|
|
@ -66,6 +66,7 @@
|
|||
"less" = "Less";
|
||||
"open" = "Open";
|
||||
"done" = "Done";
|
||||
"ok" = "OK";
|
||||
|
||||
// Call Bar
|
||||
"callbar_only_single_active" = "Tap to return to the call (%@)";
|
||||
|
@ -1821,8 +1822,6 @@ Tap the + to start adding people.";
|
|||
|
||||
"poll_edit_form_post_failure_subtitle" = "Please try again";
|
||||
|
||||
"poll_edit_form_post_failure_action" = "OK";
|
||||
|
||||
"poll_timeline_one_vote" = "1 vote";
|
||||
|
||||
"poll_timeline_votes_count" = "%lu votes";
|
||||
|
@ -1845,14 +1844,10 @@ Tap the + to start adding people.";
|
|||
|
||||
"poll_timeline_vote_not_registered_subtitle" = "Sorry, your vote was not registered, please try again";
|
||||
|
||||
"poll_timeline_vote_not_registered_action" = "OK";
|
||||
|
||||
"poll_timeline_not_closed_title" = "Failed to end poll";
|
||||
|
||||
"poll_timeline_not_closed_subtitle" = "Please try again";
|
||||
|
||||
"poll_timeline_not_closed_action" = "OK";
|
||||
|
||||
// MARK: - Location sharing
|
||||
|
||||
"location_sharing_title" = "Location";
|
||||
|
@ -1861,14 +1856,12 @@ Tap the + to start adding people.";
|
|||
|
||||
"location_sharing_share_action" = "Share";
|
||||
|
||||
"location_sharing_loading_map_error_title" = "Failed to load map";
|
||||
"location_sharing_loading_map_error_title" = "Element could not load the map. Please try again later.";
|
||||
|
||||
"location_sharing_loading_map_error_message" = "Please try again";
|
||||
"location_sharing_locating_user_error_title" = "Element could not access your location. Please try again later.";
|
||||
|
||||
"location_sharing_locating_user_error_title" = "Failed locating user";
|
||||
"location_sharing_invalid_authorization_error_title" = "Element does not have permission to access your location. You can enable access in Settings > Location";
|
||||
|
||||
"location_sharing_locating_user_error_message" = "Please try again";
|
||||
"location_sharing_invalid_authorization_not_now" = "Not now";
|
||||
|
||||
"location_sharing_invalid_authorization_error_title" = "Failed getting authorization";
|
||||
|
||||
"location_sharing_invalid_authorization_error_message" = "Please update your system settings";
|
||||
"location_sharing_invalid_authorization_settings" = "Settings";
|
||||
|
|
|
@ -2195,27 +2195,23 @@ public class VectorL10n: NSObject {
|
|||
public static var locationSharingCloseAction: String {
|
||||
return VectorL10n.tr("Vector", "location_sharing_close_action")
|
||||
}
|
||||
/// Please update your system settings
|
||||
public static var locationSharingInvalidAuthorizationErrorMessage: String {
|
||||
return VectorL10n.tr("Vector", "location_sharing_invalid_authorization_error_message")
|
||||
}
|
||||
/// Failed getting authorization
|
||||
/// Element does not have permission to access your location. You can enable access in Settings > Location
|
||||
public static var locationSharingInvalidAuthorizationErrorTitle: String {
|
||||
return VectorL10n.tr("Vector", "location_sharing_invalid_authorization_error_title")
|
||||
}
|
||||
/// Please try again
|
||||
public static var locationSharingLoadingMapErrorMessage: String {
|
||||
return VectorL10n.tr("Vector", "location_sharing_loading_map_error_message")
|
||||
/// Not now
|
||||
public static var locationSharingInvalidAuthorizationNotNow: String {
|
||||
return VectorL10n.tr("Vector", "location_sharing_invalid_authorization_not_now")
|
||||
}
|
||||
/// Failed to load map
|
||||
/// Settings
|
||||
public static var locationSharingInvalidAuthorizationSettings: String {
|
||||
return VectorL10n.tr("Vector", "location_sharing_invalid_authorization_settings")
|
||||
}
|
||||
/// Element could not load the map. Please try again later.
|
||||
public static var locationSharingLoadingMapErrorTitle: String {
|
||||
return VectorL10n.tr("Vector", "location_sharing_loading_map_error_title")
|
||||
}
|
||||
/// Please try again
|
||||
public static var locationSharingLocatingUserErrorMessage: String {
|
||||
return VectorL10n.tr("Vector", "location_sharing_locating_user_error_message")
|
||||
}
|
||||
/// Failed locating user
|
||||
/// Element could not access your location. Please try again later.
|
||||
public static var locationSharingLocatingUserErrorTitle: String {
|
||||
return VectorL10n.tr("Vector", "location_sharing_locating_user_error_title")
|
||||
}
|
||||
|
@ -2327,6 +2323,10 @@ public class VectorL10n: NSObject {
|
|||
public static var off: String {
|
||||
return VectorL10n.tr("Vector", "off")
|
||||
}
|
||||
/// OK
|
||||
public static var ok: String {
|
||||
return VectorL10n.tr("Vector", "ok")
|
||||
}
|
||||
/// On
|
||||
public static var on: String {
|
||||
return VectorL10n.tr("Vector", "on")
|
||||
|
@ -2479,10 +2479,6 @@ public class VectorL10n: NSObject {
|
|||
public static var pollEditFormPollQuestionOrTopic: String {
|
||||
return VectorL10n.tr("Vector", "poll_edit_form_poll_question_or_topic")
|
||||
}
|
||||
/// OK
|
||||
public static var pollEditFormPostFailureAction: String {
|
||||
return VectorL10n.tr("Vector", "poll_edit_form_post_failure_action")
|
||||
}
|
||||
/// Please try again
|
||||
public static var pollEditFormPostFailureSubtitle: String {
|
||||
return VectorL10n.tr("Vector", "poll_edit_form_post_failure_subtitle")
|
||||
|
@ -2495,10 +2491,6 @@ public class VectorL10n: NSObject {
|
|||
public static var pollEditFormQuestionOrTopic: String {
|
||||
return VectorL10n.tr("Vector", "poll_edit_form_question_or_topic")
|
||||
}
|
||||
/// OK
|
||||
public static var pollTimelineNotClosedAction: String {
|
||||
return VectorL10n.tr("Vector", "poll_timeline_not_closed_action")
|
||||
}
|
||||
/// Please try again
|
||||
public static var pollTimelineNotClosedSubtitle: String {
|
||||
return VectorL10n.tr("Vector", "poll_timeline_not_closed_subtitle")
|
||||
|
@ -2539,10 +2531,6 @@ public class VectorL10n: NSObject {
|
|||
public static func pollTimelineTotalVotesNotVoted(_ p1: Int) -> String {
|
||||
return VectorL10n.tr("Vector", "poll_timeline_total_votes_not_voted", p1)
|
||||
}
|
||||
/// OK
|
||||
public static var pollTimelineVoteNotRegisteredAction: String {
|
||||
return VectorL10n.tr("Vector", "poll_timeline_vote_not_registered_action")
|
||||
}
|
||||
/// Sorry, your vote was not registered, please try again
|
||||
public static var pollTimelineVoteNotRegisteredSubtitle: String {
|
||||
return VectorL10n.tr("Vector", "poll_timeline_vote_not_registered_subtitle")
|
||||
|
|
|
@ -25,7 +25,6 @@ class RoomTimelineLocationView: UIView, NibLoadable, MGLMapViewDelegate {
|
|||
static let mapHeight: CGFloat = 300.0
|
||||
static let mapTilerKey = RiotKeys().mapTilerAPIKey
|
||||
static let mapZoomLevel = 15.0
|
||||
static let mapStyleURLString = URL(string: "https://api.maptiler.com/maps/streets/style.json?key=\(Constants.mapTilerKey)")
|
||||
static let cellBorderRadius: CGFloat = 1.0
|
||||
static let cellCornerRadius: CGFloat = 8.0
|
||||
}
|
||||
|
@ -54,7 +53,7 @@ class RoomTimelineLocationView: UIView, NibLoadable, MGLMapViewDelegate {
|
|||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
|
||||
mapView = MGLMapView(frame: .zero, styleURL: Constants.mapStyleURLString)
|
||||
mapView = MGLMapView(frame: .zero, styleURL: BuildSettings.tileServerMapURL)
|
||||
mapView.delegate = self
|
||||
mapView.logoView.isHidden = true
|
||||
mapView.attributionButton.isHidden = true
|
||||
|
|
|
@ -66,7 +66,7 @@
|
|||
<key>NSSiriUsageDescription</key>
|
||||
<string>Siri is used to perform calls even from the lock screen.</string>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string>Element needs access to your location before being able to share it.</string>
|
||||
<string>When you share your location to people, Element needs access to show them a map.</string>
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>audio</string>
|
||||
|
|
|
@ -21,6 +21,6 @@
|
|||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string>Element needs access to your location before being able to share it.</string>
|
||||
<string>When you share your location to people, Element needs access to show them a map.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -56,7 +56,7 @@ final class LocationSharingCoordinator: Coordinator {
|
|||
matrixItemId: parameters.user.userId,
|
||||
displayName: parameters.user.displayname)
|
||||
|
||||
let viewModel = LocationSharingViewModel(accessToken: RiotKeys().mapTilerAPIKey, avatarData: avatarData)
|
||||
let viewModel = LocationSharingViewModel(tileServerMapURL: BuildSettings.tileServerMapURL, avatarData: avatarData)
|
||||
let view = LocationSharingView(context: viewModel.context)
|
||||
.addDependency(AvatarService.instantiate(mediaManager: parameters.mediaManager))
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ enum LocationSharingViewModelResult {
|
|||
|
||||
@available(iOS 14, *)
|
||||
struct LocationSharingViewState: BindableState {
|
||||
let accessToken: String
|
||||
let tileServerMapURL: URL
|
||||
let avatarData: AvatarInputProtocol
|
||||
var shareButtonEnabled: Bool = true
|
||||
var showLoadingIndicator: Bool = false
|
||||
|
@ -71,6 +71,6 @@ struct ErrorAlertInfo: Identifiable {
|
|||
|
||||
let id: AlertType
|
||||
let title: String
|
||||
let message: String
|
||||
let callback: (() -> Void)?
|
||||
let primaryButton: (String, (() -> Void)?)
|
||||
let secondaryButton: (String, (() -> Void)?)?
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import Keys
|
||||
|
||||
@available(iOS 14.0, *)
|
||||
enum MockLocationSharingScreenState: MockScreenState, CaseIterable {
|
||||
|
@ -26,7 +27,8 @@ enum MockLocationSharingScreenState: MockScreenState, CaseIterable {
|
|||
}
|
||||
|
||||
var screenView: ([Any], AnyView) {
|
||||
let viewModel = LocationSharingViewModel(accessToken: "bDAfUcrMPWTAB1KB38r6",
|
||||
let mapURL = URL(string: "https://api.maptiler.com/maps/streets/style.json?key=" + RiotKeys().mapTilerAPIKey)!
|
||||
let viewModel = LocationSharingViewModel(tileServerMapURL: mapURL,
|
||||
avatarData: AvatarInput(mxContentUri: "", matrixItemId: "", displayName: "Alice"))
|
||||
return ([viewModel],
|
||||
AnyView(LocationSharingView(context: viewModel.context)
|
||||
|
|
|
@ -30,18 +30,18 @@ class LocationSharingViewModel: LocationSharingViewModelType {
|
|||
|
||||
// MARK: Public
|
||||
|
||||
let accessToken: String
|
||||
let tileServerMapURL: URL
|
||||
let avatarData: AvatarInputProtocol
|
||||
|
||||
var completion: ((LocationSharingViewModelResult) -> Void)?
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
init(accessToken: String, avatarData: AvatarInputProtocol) {
|
||||
self.accessToken = accessToken
|
||||
init(tileServerMapURL: URL, avatarData: AvatarInputProtocol) {
|
||||
self.tileServerMapURL = tileServerMapURL
|
||||
self.avatarData = avatarData
|
||||
|
||||
super.init(initialViewState: LocationSharingViewState(accessToken: accessToken, avatarData: avatarData))
|
||||
super.init(initialViewState: LocationSharingViewState(tileServerMapURL: tileServerMapURL, avatarData: avatarData))
|
||||
|
||||
state.errorSubject.sink { [weak self] error in
|
||||
guard let self = self else { return }
|
||||
|
@ -69,26 +69,26 @@ class LocationSharingViewModel: LocationSharingViewModelType {
|
|||
switch action {
|
||||
case .error(let error, let completion):
|
||||
|
||||
let alertCallback: () -> Void = {
|
||||
completion?(.cancel)
|
||||
}
|
||||
|
||||
switch error {
|
||||
case .failedLoadingMap:
|
||||
state.bindings.alertInfo = ErrorAlertInfo(id: .mapLoadingError,
|
||||
title: VectorL10n.locationSharingLoadingMapErrorTitle,
|
||||
message: VectorL10n.locationSharingLoadingMapErrorMessage,
|
||||
callback: alertCallback)
|
||||
primaryButton: (VectorL10n.ok, { completion?(.cancel) }),
|
||||
secondaryButton: nil)
|
||||
case .failedLocatingUser:
|
||||
state.bindings.alertInfo = ErrorAlertInfo(id: .userLocatingError,
|
||||
title: VectorL10n.locationSharingLocatingUserErrorTitle,
|
||||
message: VectorL10n.locationSharingLocatingUserErrorMessage,
|
||||
callback: alertCallback)
|
||||
primaryButton: (VectorL10n.ok, { completion?(.cancel) }),
|
||||
secondaryButton: nil)
|
||||
case .invalidLocationAuthorization:
|
||||
state.bindings.alertInfo = ErrorAlertInfo(id: .authorizationError,
|
||||
title: VectorL10n.locationSharingInvalidAuthorizationErrorTitle,
|
||||
message: VectorL10n.locationSharingInvalidAuthorizationErrorMessage,
|
||||
callback: alertCallback)
|
||||
primaryButton: (VectorL10n.locationSharingInvalidAuthorizationNotNow, { completion?(.cancel) }),
|
||||
secondaryButton: (VectorL10n.locationSharingInvalidAuthorizationSettings, {
|
||||
if let applicationSettingsURL = URL(string:UIApplication.openSettingsURLString) {
|
||||
UIApplication.shared.open(applicationSettingsURL)
|
||||
}
|
||||
}))
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
@ -103,8 +103,8 @@ class LocationSharingViewModel: LocationSharingViewModelType {
|
|||
if error != nil {
|
||||
state.bindings.alertInfo = ErrorAlertInfo(id: .locationSharingError,
|
||||
title: VectorL10n.locationSharingInvalidAuthorizationErrorTitle,
|
||||
message: VectorL10n.locationSharingInvalidAuthorizationErrorMessage,
|
||||
callback: nil)
|
||||
primaryButton: (VectorL10n.ok, nil),
|
||||
secondaryButton: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ class LocationSharingViewModelTests: XCTestCase {
|
|||
var cancellables = Set<AnyCancellable>()
|
||||
|
||||
override func setUpWithError() throws {
|
||||
context = viewModel.context
|
||||
|
||||
}
|
||||
|
||||
func testInitialState() {
|
||||
|
|
|
@ -22,18 +22,15 @@ import Mapbox
|
|||
struct LocationSharingMapView: UIViewRepresentable {
|
||||
private struct Constants {
|
||||
static let mapZoomLevel = 15.0
|
||||
static let mapStyleURLString = "https://api.maptiler.com/maps/streets/style.json?key="
|
||||
}
|
||||
|
||||
let accessToken: String
|
||||
let tileServerMapURL: URL
|
||||
let avatarData: AvatarInputProtocol
|
||||
let errorSubject: PassthroughSubject<LocationSharingViewError, Never>
|
||||
@Binding var userLocation: CLLocationCoordinate2D?
|
||||
|
||||
func makeUIView(context: Context) -> some UIView {
|
||||
let url = URL(string: Constants.mapStyleURLString + accessToken)
|
||||
|
||||
let mapView = MGLMapView(frame: .zero, styleURL: url)
|
||||
let mapView = MGLMapView(frame: .zero, styleURL: tileServerMapURL)
|
||||
mapView.delegate = context.coordinator
|
||||
|
||||
mapView.logoView.isHidden = true
|
||||
|
|
|
@ -32,7 +32,7 @@ struct LocationSharingView: View {
|
|||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
LocationSharingMapView(accessToken: context.viewState.accessToken,
|
||||
LocationSharingMapView(tileServerMapURL: context.viewState.tileServerMapURL,
|
||||
avatarData: context.viewState.avatarData,
|
||||
errorSubject: context.viewState.errorSubject,
|
||||
userLocation: $context.userLocation)
|
||||
|
@ -57,10 +57,20 @@ struct LocationSharingView: View {
|
|||
.navigationBarTitleDisplayMode(.inline)
|
||||
.ignoresSafeArea()
|
||||
.alert(item: $context.alertInfo) { info in
|
||||
Alert(title: Text(info.title), message: Text(info.message), dismissButton:
|
||||
.default(Text(VectorL10n.pollTimelineVoteNotRegisteredAction)) {
|
||||
info.callback?()
|
||||
if let secondaryButton = info.secondaryButton {
|
||||
return Alert(title: Text(info.title),
|
||||
primaryButton: .default(Text(info.primaryButton.0)) {
|
||||
info.primaryButton.1?()
|
||||
},
|
||||
secondaryButton: .default(Text(secondaryButton.0)) {
|
||||
secondaryButton.1?()
|
||||
})
|
||||
} else {
|
||||
return Alert(title: Text(info.title),
|
||||
dismissButton: .default(Text(info.primaryButton.0)) {
|
||||
info.primaryButton.1?()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
.accentColor(theme.colors.accent)
|
||||
|
|
|
@ -87,7 +87,7 @@ struct PollEditForm: View {
|
|||
.alert(isPresented: $viewModel.showsFailureAlert) {
|
||||
Alert(title: Text(VectorL10n.pollEditFormPostFailureTitle),
|
||||
message: Text(VectorL10n.pollEditFormPostFailureSubtitle),
|
||||
dismissButton: .default(Text(VectorL10n.pollEditFormPostFailureAction)))
|
||||
dismissButton: .default(Text(VectorL10n.ok)))
|
||||
}
|
||||
.frame(minHeight: proxy.size.height) // Make the VStack fill the ScrollView's parent
|
||||
.toolbar {
|
||||
|
|
|
@ -50,7 +50,7 @@ struct PollTimelineView: View {
|
|||
.alert(isPresented: $viewModel.showsClosingFailureAlert) {
|
||||
Alert(title: Text(VectorL10n.pollTimelineNotClosedTitle),
|
||||
message: Text(VectorL10n.pollTimelineNotClosedSubtitle),
|
||||
dismissButton: .default(Text(VectorL10n.pollTimelineNotClosedAction)))
|
||||
dismissButton: .default(Text(VectorL10n.ok)))
|
||||
}
|
||||
}
|
||||
.disabled(poll.closed)
|
||||
|
@ -62,7 +62,7 @@ struct PollTimelineView: View {
|
|||
.alert(isPresented: $viewModel.showsAnsweringFailureAlert) {
|
||||
Alert(title: Text(VectorL10n.pollTimelineVoteNotRegisteredTitle),
|
||||
message: Text(VectorL10n.pollTimelineVoteNotRegisteredSubtitle),
|
||||
dismissButton: .default(Text(VectorL10n.pollTimelineVoteNotRegisteredAction)))
|
||||
dismissButton: .default(Text(VectorL10n.ok)))
|
||||
}
|
||||
}
|
||||
.padding([.horizontal, .top], 2.0)
|
||||
|
|
Loading…
Reference in a new issue