Merge pull request #6499 from vector-im/steve/6493_lls_tile_server_error

Location sharing: Render fallback UI when tile server unavailable (PSG-606)
This commit is contained in:
SBiOSoftWhare 2022-08-02 17:42:50 +02:00 committed by GitHub
commit c9e916b909
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 267 additions and 39 deletions

View file

@ -0,0 +1,15 @@
{
"images" : [
{
"filename" : "location_map_error.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "original"
}
}

View file

@ -0,0 +1,3 @@
<svg width="33" height="32" viewBox="0 0 33 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.5001 29.3327C23.8639 29.3327 29.8334 23.3631 29.8334 15.9993C29.8334 8.63555 23.8639 2.66602 16.5001 2.66602C9.13628 2.66602 3.16675 8.63555 3.16675 15.9993C3.16675 23.3631 9.13628 29.3327 16.5001 29.3327ZM14.3976 9.35707C14.2945 8.18144 15.1608 7.15019 16.3364 7.06769C17.4914 6.98519 18.5226 7.85144 18.6464 9.02707V9.35707L17.9864 17.6071C17.9245 18.3702 17.2851 18.9477 16.522 18.9477H16.3983C15.6764 18.8858 15.1195 18.3289 15.0576 17.6071L14.3976 9.35707ZM18.3154 22.9905C18.3154 23.9929 17.5028 24.8055 16.5004 24.8055C15.498 24.8055 14.6854 23.9929 14.6854 22.9905C14.6854 21.9881 15.498 21.1755 16.5004 21.1755C17.5028 21.1755 18.3154 21.9881 18.3154 22.9905Z" fill="#FF4B55"/>
</svg>

After

Width:  |  Height:  |  Size: 843 B

View file

@ -2279,6 +2279,7 @@ To enable access, tap Settings> Location and select Always";
"location_sharing_allow_background_location_validate_action" = "Settings";
"location_sharing_allow_background_location_cancel_action" = "Not now";
"location_sharing_map_credits_title" = "© Copyright";
"location_sharing_map_loading_error" = "Unable to load map\nThis homeserver is not configured to display maps";
// MARK: Live location sharing

View file

@ -105,6 +105,8 @@ internal class Asset: NSObject {
internal static let encryptionWarning = ImageAsset(name: "encryption_warning")
internal static let favouritesEmptyScreenArtwork = ImageAsset(name: "favourites_empty_screen_artwork")
internal static let favouritesEmptyScreenArtworkDark = ImageAsset(name: "favourites_empty_screen_artwork_dark")
internal static let allChatRecents = ImageAsset(name: "all_chat_recents")
internal static let allChatUnreads = ImageAsset(name: "all_chat_unreads")
internal static let roomActionDirectChat = ImageAsset(name: "room_action_direct_chat")
internal static let roomActionFavourite = ImageAsset(name: "room_action_favourite")
internal static let roomActionLeave = ImageAsset(name: "room_action_leave")
@ -112,6 +114,7 @@ internal class Asset: NSObject {
internal static let roomActionNotificationMuted = ImageAsset(name: "room_action_notification_muted")
internal static let roomActionPriorityHigh = ImageAsset(name: "room_action_priority_high")
internal static let roomActionPriorityLow = ImageAsset(name: "room_action_priority_low")
internal static let allChatEditLayout = ImageAsset(name: "all_chat_edit_layout")
internal static let homeEmptyScreenArtwork = ImageAsset(name: "home_empty_screen_artwork")
internal static let homeEmptyScreenArtworkDark = ImageAsset(name: "home_empty_screen_artwork_dark")
internal static let homeFabCreateRoom = ImageAsset(name: "home_fab_create_room")
@ -195,6 +198,7 @@ internal class Asset: NSObject {
internal static let locationLiveCellIcon = ImageAsset(name: "location_live_cell_icon")
internal static let locationLiveCellLoadingIcon = ImageAsset(name: "location_live_cell_loading_icon")
internal static let locationLiveIcon = ImageAsset(name: "location_live_icon")
internal static let locationMapError = ImageAsset(name: "location_map_error")
internal static let locationMarkerIcon = ImageAsset(name: "location_marker_icon")
internal static let locationPinIcon = ImageAsset(name: "location_pin_icon")
internal static let locationShareIcon = ImageAsset(name: "location_share_icon")

View file

@ -3179,6 +3179,10 @@ public class VectorL10n: NSObject {
public static var locationSharingMapCreditsTitle: String {
return VectorL10n.tr("Vector", "location_sharing_map_credits_title")
}
/// Unable to load map\nThis homeserver is not configured to display maps
public static var locationSharingMapLoadingError: String {
return VectorL10n.tr("Vector", "location_sharing_map_loading_error")
}
/// Open in Apple Maps
public static var locationSharingOpenAppleMaps: String {
return VectorL10n.tr("Vector", "location_sharing_open_apple_maps")

View file

@ -104,7 +104,19 @@ class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegat
@IBOutlet private var rightButton: UIButton!
@IBOutlet private var activityIndicatorView: UIActivityIndicatorView!
@IBOutlet private var mapLoadingErrorContainerView: UIView!
@IBOutlet private var mapLoadingErrorImageView: UIImageView!
@IBOutlet private var mapLoadingErrorMessageLabel: UILabel!
private var mapView: MGLMapView!
private var isMapViewLoadingFailed: Bool = false {
didSet {
if oldValue != isMapViewLoadingFailed {
self.mapViewLoadingStateDidChange()
}
}
}
private var annotationView: LocationMarkerView?
private static var usernameColorGenerator = UserNameColorGenerator()
private var theme: Theme!
@ -157,16 +169,37 @@ class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegat
layer.borderWidth = Constants.cellBorderRadius
layer.cornerRadius = Constants.cellCornerRadius
mapLoadingErrorContainerView.isHidden = true
mapLoadingErrorImageView.image = Asset.Images.locationMapError.image
mapLoadingErrorMessageLabel.text = VectorL10n.locationSharingMapLoadingError
theme = ThemeService.shared().theme
}
// MARK: - Private
private func resetMapViewLoadingState() {
self.isMapViewLoadingFailed = false
}
private func mapViewLoadingStateDidChange() {
if mapView.isHidden == false && self.isMapViewLoadingFailed {
mapLoadingErrorContainerView.isHidden = false
mapView.isHidden = true
attributionLabel.isHidden = true
} else {
mapLoadingErrorContainerView.isHidden = true
}
}
private func displayLocation(_ location: CLLocationCoordinate2D?,
userAvatarData: AvatarViewData? = nil,
mapStyleURL: URL,
bannerViewData: TimelineLiveLocationViewData? = nil) {
resetMapViewLoadingState()
if let location = location {
mapView.isHidden = false
mapView.styleURL = mapStyleURL
@ -350,6 +383,9 @@ class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegat
self.theme = theme
placeholderIcon = ThemeService.shared().isCurrentThemeDark() ? Asset.Images.locationLiveCellEndedDarkIcon.image : Asset.Images.locationLiveCellEndedLightIcon.image
placeholderBackgroundImage = ThemeService.shared().isCurrentThemeDark() ? Asset.Images.locationBackgroundDarkImage.image : Asset.Images.locationBackgroundLightImage.image
mapLoadingErrorContainerView.backgroundColor = theme.colors.system
mapLoadingErrorMessageLabel.textColor = theme.colors.primaryContent
}
// MARK: - MGLMapViewDelegate
@ -358,6 +394,17 @@ class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegat
return annotationView
}
func mapViewDidFailLoadingMap(_ mapView: MGLMapView, withError error: Error) {
MXLog.error("[RoomTimelineLocationView] Failed to load map with error: \(error)")
self.isMapViewLoadingFailed = true
}
func mapViewDidFinishLoadingMap(_ mapView: MGLMapView) {
self.isMapViewLoadingFailed = false
}
// MARK: - Action
@IBAction private func didTapTightButton(_ sender: Any) {

View file

@ -1,16 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="19529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="RoomTimelineLocationView" customModule="Riot" customModuleProvider="target">
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="RoomTimelineLocationView" customModule="Element" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="395" height="250"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
@ -24,6 +24,62 @@
<constraint firstAttribute="width" constant="45" id="q3h-Mg-lG4"/>
</constraints>
</imageView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="XkV-iZ-sfD">
<rect key="frame" x="0.0" y="0.0" width="395" height="250"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="4gW-5c-wLy">
<rect key="frame" x="0.0" y="0.0" width="395" height="182"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="NlS-uE-OrS">
<rect key="frame" x="50.5" y="52" width="294.5" height="78.5"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="location_map_error" translatesAutoresizingMaskIntoConstraints="NO" id="ror-cm-dP7">
<rect key="frame" x="131" y="5" width="32" height="32"/>
<constraints>
<constraint firstAttribute="height" constant="32" id="IpE-8Q-U1X"/>
<constraint firstAttribute="width" constant="32" id="diE-aQ-iGF"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Eml-nq-quj">
<rect key="frame" x="15" y="47" width="264.5" height="26.5"/>
<string key="text">Unable to load map
This homeserver is not configured to display maps</string>
<fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="Eml-nq-quj" secondAttribute="trailing" constant="15" id="J2n-U6-RWG"/>
<constraint firstItem="ror-cm-dP7" firstAttribute="centerX" secondItem="NlS-uE-OrS" secondAttribute="centerX" id="MtV-hn-HJI"/>
<constraint firstItem="Eml-nq-quj" firstAttribute="top" secondItem="ror-cm-dP7" secondAttribute="bottom" constant="10" id="RSS-ta-Ycc"/>
<constraint firstItem="Eml-nq-quj" firstAttribute="leading" secondItem="NlS-uE-OrS" secondAttribute="leading" constant="15" id="SJs-dd-Xp2"/>
<constraint firstAttribute="width" priority="250" id="bQp-M0-ad4"/>
<constraint firstAttribute="height" priority="250" id="pgg-Tl-wNT"/>
<constraint firstAttribute="bottom" secondItem="Eml-nq-quj" secondAttribute="bottom" constant="5" id="qZ2-9M-Jha"/>
<constraint firstItem="ror-cm-dP7" firstAttribute="top" secondItem="NlS-uE-OrS" secondAttribute="top" constant="5" id="uB2-Ry-jUz"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="NlS-uE-OrS" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="4gW-5c-wLy" secondAttribute="leading" id="D4Y-Jn-aKa"/>
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="NlS-uE-OrS" secondAttribute="bottom" id="GZv-Aw-Qdq"/>
<constraint firstItem="NlS-uE-OrS" firstAttribute="top" relation="greaterThanOrEqual" secondItem="4gW-5c-wLy" secondAttribute="top" id="QnJ-vE-nWS"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="NlS-uE-OrS" secondAttribute="trailing" id="h7C-La-6Dc"/>
<constraint firstItem="NlS-uE-OrS" firstAttribute="centerY" secondItem="4gW-5c-wLy" secondAttribute="centerY" id="k3F-mp-2pw"/>
<constraint firstItem="NlS-uE-OrS" firstAttribute="centerX" secondItem="4gW-5c-wLy" secondAttribute="centerX" id="rfi-Zz-UfZ"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="4gW-5c-wLy" firstAttribute="leading" secondItem="XkV-iZ-sfD" secondAttribute="leading" id="6Yv-CA-oUv"/>
<constraint firstAttribute="trailing" secondItem="4gW-5c-wLy" secondAttribute="trailing" id="jge-Zc-VzB"/>
<constraint firstItem="4gW-5c-wLy" firstAttribute="top" secondItem="XkV-iZ-sfD" secondAttribute="top" id="ojd-BO-iRA"/>
</constraints>
</view>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="0D1-Km-vTu">
<rect key="frame" x="0.0" y="182" width="395" height="68"/>
<subviews>
@ -159,9 +215,14 @@
<constraints>
<constraint firstItem="1j3-sd-BvY" firstAttribute="centerY" secondItem="4WL-gT-HBV" secondAttribute="centerY" id="A5v-W4-VaN"/>
<constraint firstAttribute="trailing" secondItem="vuV-BV-bbx" secondAttribute="trailing" id="Gck-1z-j8f"/>
<constraint firstAttribute="bottom" secondItem="XkV-iZ-sfD" secondAttribute="bottom" id="LU8-RW-Azf"/>
<constraint firstItem="vuV-BV-bbx" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="NhI-xD-L7V"/>
<constraint firstAttribute="trailing" secondItem="0D1-Km-vTu" secondAttribute="trailing" id="QHD-xv-nfX"/>
<constraint firstAttribute="trailing" secondItem="XkV-iZ-sfD" secondAttribute="trailing" id="ZdZ-d1-u47"/>
<constraint firstItem="XkV-iZ-sfD" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="a2R-cf-5Tn"/>
<constraint firstItem="XkV-iZ-sfD" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="c6b-kS-Dlf"/>
<constraint firstAttribute="bottom" secondItem="vuV-BV-bbx" secondAttribute="bottom" id="eKg-25-HDW"/>
<constraint firstItem="0D1-Km-vTu" firstAttribute="top" secondItem="4gW-5c-wLy" secondAttribute="bottom" id="eQz-kf-RIl"/>
<constraint firstItem="4WL-gT-HBV" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" id="eRF-LN-Evm"/>
<constraint firstAttribute="bottom" secondItem="0D1-Km-vTu" secondAttribute="bottom" id="ea5-xx-V3s"/>
<constraint firstItem="1j3-sd-BvY" firstAttribute="centerX" secondItem="4WL-gT-HBV" secondAttribute="centerX" id="fxh-rF-fpN"/>
@ -183,6 +244,9 @@
<outlet property="liveLocationIconBackgroundView" destination="72o-VM-Ls7" id="2XU-x0-vhz"/>
<outlet property="liveLocationStatusLabel" destination="X9R-EV-RDT" id="HJr-cE-icv"/>
<outlet property="liveLocationTimerLabel" destination="U75-c5-got" id="RkO-6a-ABU"/>
<outlet property="mapLoadingErrorContainerView" destination="XkV-iZ-sfD" id="kAm-JY-kRA"/>
<outlet property="mapLoadingErrorImageView" destination="ror-cm-dP7" id="oXd-fx-43J"/>
<outlet property="mapLoadingErrorMessageLabel" destination="Eml-nq-quj" id="Yix-87-5R6"/>
<outlet property="placeholderBackground" destination="vuV-BV-bbx" id="9PW-RW-tFh"/>
<outlet property="placeholderIconView" destination="4WL-gT-HBV" id="pqw-gN-2Q7"/>
<outlet property="rightButton" destination="k5H-UE-ygH" id="nz0-Eb-SRp"/>
@ -194,6 +258,7 @@
<image name="location_background_light_image" width="847.5" height="556"/>
<image name="location_live_cell_ended_light_icon" width="46" height="65"/>
<image name="location_live_cell_icon" width="32" height="32"/>
<image name="location_map_error" width="33" height="32"/>
<image name="location_marker_icon" width="24" height="24"/>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>

View file

@ -57,6 +57,8 @@ struct LiveLocationSharingViewerViewState: BindableState {
var isBottomSheetVisible: Bool {
return isAllLocationSharingEnded == false
}
var showMapLoadingError: Bool = false
let errorSubject = PassthroughSubject<LocationSharingViewError, Never>()

View file

@ -105,6 +105,10 @@ class LiveLocationSharingViewerViewModel: LiveLocationSharingViewerViewModelType
return
}
if case .failedLoadingMap = error {
state.showMapLoadingError = true
}
let alertInfo = mapViewErrorAlertInfoBuilder.build(with: error) { [weak self] in
switch error {

View file

@ -37,40 +37,53 @@ struct LiveLocationSharingViewer: View {
var body: some View {
ZStack(alignment: .bottom) {
LocationSharingMapView(tileServerMapURL: viewModel.viewState.mapStyleURL,
annotations: viewModel.viewState.annotations,
highlightedAnnotation: viewModel.viewState.highlightedAnnotation,
userAvatarData: nil,
showsUserLocation: false,
userAnnotationCanShowCallout: true,
userLocation: Binding.constant(nil),
mapCenterCoordinate: Binding.constant(nil),
onCalloutTap: { annotation in
if let userLocationAnnotation = annotation as? UserLocationAnnotation {
viewModel.send(viewAction: .share(userLocationAnnotation))
}
},
errorSubject: viewModel.viewState.errorSubject)
if viewModel.viewState.isBottomSheetVisible {
VStack(alignment: .center) {
Spacer()
MapCreditsView(action: {
viewModel.send(viewAction: .mapCreditsDidTap)
})
.offset(y: -(bottomSheetCollapsedHeight)) // Put the copyright action above the collapsed bottom sheet
.padding(.bottom, 10)
if !viewModel.viewState.showMapLoadingError {
LocationSharingMapView(tileServerMapURL: viewModel.viewState.mapStyleURL,
annotations: viewModel.viewState.annotations,
highlightedAnnotation: viewModel.viewState.highlightedAnnotation,
userAvatarData: nil,
showsUserLocation: false,
userAnnotationCanShowCallout: true,
userLocation: Binding.constant(nil),
mapCenterCoordinate: Binding.constant(nil),
onCalloutTap: { annotation in
if let userLocationAnnotation = annotation as? UserLocationAnnotation {
viewModel.send(viewAction: .share(userLocationAnnotation))
}
},
errorSubject: viewModel.viewState.errorSubject)
// Show map credits above collapsed bottom sheet height if bottom sheet is visible
if viewModel.viewState.isBottomSheetVisible {
VStack(alignment: .center) {
Spacer()
MapCreditsView(action: {
viewModel.send(viewAction: .mapCreditsDidTap)
})
.offset(y: -(bottomSheetCollapsedHeight)) // Put the copyright action above the collapsed bottom sheet
.padding(.bottom, 10)
}
.ignoresSafeArea()
}
.ignoresSafeArea()
} else {
MapLoadingErrorView()
.padding(.bottom, viewModel.viewState.isBottomSheetVisible ? bottomSheetCollapsedHeight : 0)
}
if viewModel.viewState.isAllLocationSharingEnded {
VStack(alignment: .center) {
Spacer()
MapCreditsView(action: {
viewModel.send(viewAction: .mapCreditsDidTap)
})
.padding(.bottom, 5)
// Show map credits only if map is visible
if !viewModel.viewState.showMapLoadingError {
MapCreditsView(action: {
viewModel.send(viewAction: .mapCreditsDidTap)
})
.padding(.bottom, 5)
}
HStack(spacing: 10) {
Image(uiImage: Asset.Images.locationLiveCellIcon.image)
.renderingMode(.template)
@ -96,6 +109,7 @@ struct LiveLocationSharingViewer: View {
}
}
.accentColor(theme.colors.accent)
.background(theme.colors.system.ignoresSafeArea())
.bottomSheet(sheet, if: viewModel.viewState.isBottomSheetVisible)
.actionSheet(isPresented: $viewModel.showMapCreditsSheet) {
return MapCreditsActionSheet(openURL: { url in

View file

@ -90,6 +90,8 @@ struct LocationSharingViewState: BindableState {
var shareButtonEnabled: Bool {
!showLoadingIndicator
}
var showMapLoadingError: Bool = false
let errorSubject = PassthroughSubject<LocationSharingViewError, Never>()

View file

@ -137,6 +137,9 @@ class LocationSharingViewModel: LocationSharingViewModelType, LocationSharingVie
state.bindings.alertInfo = AlertInfo(id: .mapLoadingError,
title: VectorL10n.locationSharingLoadingMapErrorTitle(AppInfo.current.displayName),
primaryButton: (VectorL10n.ok, primaryButtonCompletion))
state.showMapLoadingError = true
case .failedLocatingUser:
state.bindings.alertInfo = AlertInfo(id: .userLocatingError,
title: VectorL10n.locationSharingLocatingUserErrorTitle(AppInfo.current.displayName),

View file

@ -34,17 +34,28 @@ struct LocationSharingView: View {
var body: some View {
NavigationView {
ZStack(alignment: .bottom) {
mapView
if !context.viewState.showMapLoadingError {
mapView
}
VStack(spacing: 0) {
MapCreditsView(action: {
context.send(viewAction: .mapCreditsDidTap)
})
.padding(.bottom, 10.0)
.actionSheet(isPresented: $context.showMapCreditsSheet) {
return MapCreditsActionSheet(openURL: { url in
openURL(url)
}).sheet
if context.viewState.showMapLoadingError {
MapLoadingErrorView()
} else {
// Show map credits only if map is visible
MapCreditsView(action: {
context.send(viewAction: .mapCreditsDidTap)
})
.padding(.bottom, 10.0)
.actionSheet(isPresented: $context.showMapCreditsSheet) {
return MapCreditsActionSheet(openURL: { url in
openURL(url)
}).sheet
}
}
buttonsView
.background(theme.colors.background)
.clipShape(RoundedCornerShape(radius: 8, corners: [.topLeft, .topRight]))

View file

@ -0,0 +1,52 @@
//
// Copyright 2022 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import SwiftUI
struct MapLoadingErrorView: View {
// MARK: - Properties
// MARK: Private
@Environment(\.theme) private var theme: ThemeSwiftUI
// MARK: Public
var action: (() -> Void)?
var body: some View {
VStack {
VStack {
Image(uiImage: Asset.Images.locationMapError.image)
.frame(width: 40, height: 40)
Text(VectorL10n.locationSharingMapLoadingError)
.multilineTextAlignment(.center)
.font(theme.fonts.caption1)
.foregroundColor(theme.colors.primaryContent)
}
.padding()
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(theme.colors.system.ignoresSafeArea())
}
}
struct MapLoadingErrorView_Previews: PreviewProvider {
static var previews: some View {
MapLoadingErrorView()
}
}

1
changelog.d/6493.change Normal file
View file

@ -0,0 +1 @@
Location sharing: Render fallback UI when tile server unavailable.