MESSENGER-5379 dynamic location attribution from style.json

This commit is contained in:
Frank Rotermund
2024-01-09 11:02:02 +01:00
parent 9c10374575
commit d7749bb5da
12 changed files with 143 additions and 22 deletions

View File

@@ -410,6 +410,18 @@ class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegat
self.isMapViewLoadingFailed = false
}
func mapView(_ mapView: MGLMapView, didFinishLoading style: MGLStyle) {
// bwi #5379: set copyright to info from style json if available. Needs reevaluation if there is more than one source
for source in style.sources {
if let tileSource = source as? MGLRasterTileSource {
for attributionInfo in tileSource.attributionInfos {
attributionLabel.text = attributionLabel.text?.appending(attributionInfo.title.plainTextString())
}
}
}
}
// MARK: - Action
@IBAction private func didTapTightButton(_ sender: Any) {

View File

@@ -68,7 +68,9 @@ struct LiveLocationSharingViewer: View {
if viewModel.viewState.isBottomSheetVisible {
VStack(alignment: .center) {
Spacer()
MapCreditsView(action: {
// bwi #5379: we don't use live location sharing, if this changes we need to use attribution from viewmodel here
MapCreditsView(attributions: LocationSharingAttribution(),
action: {
viewModel.send(viewAction: .mapCreditsDidTap)
})
.offset(y: -bottomSheetCollapsedHeight) // Put the copyright action above the collapsed bottom sheet
@@ -88,7 +90,8 @@ struct LiveLocationSharingViewer: View {
// Show map credits only if map is visible
if !viewModel.viewState.showMapLoadingError {
MapCreditsView(action: {
MapCreditsView(attributions:LocationSharingAttribution(),
action: {
viewModel.send(viewAction: .mapCreditsDidTap)
})
.padding(.bottom, 5)
@@ -122,7 +125,9 @@ struct LiveLocationSharingViewer: View {
.background(theme.colors.system.ignoresSafeArea())
.bottomSheet(sheet, if: viewModel.viewState.isBottomSheetVisible)
.actionSheet(isPresented: $viewModel.showMapCreditsSheet) {
MapCreditsActionSheet(openURL: { url in
MapCreditsActionSheet(
attribution: LocationSharingAttribution(),
openURL: { url in
UIApplication.shared.vc_open(url, completionHandler: nil)
}).sheet
}

View File

@@ -17,20 +17,32 @@
import SwiftUI
struct MapCreditsActionSheet {
// bwi #5379 dynamic attribution from style.json
let attribution: LocationSharingAttribution
// Open URL action
let openURL: (URL) -> Void
// Map credits action sheet
var sheet: ActionSheet {
ActionSheet(title: Text(BWIL10n.locationSharingMapCreditsTitle),
buttons: [
.default(Text("© MapTiler")) {
openURL(URL(string: "https://www.maptiler.com/copyright/")!)
},
.default(Text("© OpenStreetMap")) {
openURL(URL(string: "https://www.openstreetmap.org/copyright")!)
},
.cancel()
])
buttons: self.creditButtons(attribution: attribution))
}
func creditButtons( attribution: LocationSharingAttribution) -> [ActionSheet.Button] {
var buttons = [ActionSheet.Button]()
// bwi #5379 a bit scetchy but you can asume that url and text have the same index
for (index, copyright) in attribution.copyrightTexts.enumerated() {
buttons.append(.default(Text(copyright)) {
if let url = attribution.copyrightLinks[index] {
openURL(url)
}
})
}
buttons.append(.cancel())
return buttons
}
}

View File

@@ -25,25 +25,41 @@ struct MapCreditsView: View {
// MARK: Public
// MARK: Public
// bwi #5379 use dynamic attributions from style.json
@ObservedObject var attributions:LocationSharingAttribution
var action: (() -> Void)?
var body: some View {
HStack {
Spacer()
Spacer()
Button {
action?()
} label: {
Text(BWIL10n.locationSharingCopyrightLabel)
Text(copyrightText(attribution:attributions))
.font(theme.fonts.footnote)
.foregroundColor(theme.colors.accent)
}
.padding(.horizontal)
}
}
func copyrightText( attribution: LocationSharingAttribution) -> String {
var copyright = ""
for copyrightText in attribution.copyrightTexts {
copyright.append(copyrightText)
}
return copyright
}
}
struct MapCreditsView_Previews: PreviewProvider {
static var previews: some View {
MapCreditsView()
MapCreditsView(attributions: LocationSharingAttribution(copyrightTexts: [""], copyrightLinks: [URL(string: "www.someurl.org")]))
}
}

View File

@@ -68,6 +68,9 @@ struct LocationSharingMapView: UIViewRepresentable {
/// Called when the user pan on the map
var userDidPan: (() -> Void)?
// bwi #5379: for copyright attribution
var attributionsChanged: ((LocationSharingAttribution) -> Void)?
// MARK: - UIViewRepresentable
@@ -154,6 +157,23 @@ extension LocationSharingMapView {
return nil
}
func mapView(_ mapView: MGLMapView, didFinishLoading style: MGLStyle) {
// bwi #5379: set copyright to info from style json if available. Needs reevaluation if there is more than one source
var attribution = LocationSharingAttribution()
for source in style.sources {
if let tileSource = source as? MGLRasterTileSource {
for attributionInfo in tileSource.attributionInfos {
attribution.copyrightTexts.append(attributionInfo.title.plainTextString())
attribution.copyrightLinks.append(attributionInfo.url)
}
}
}
locationSharingMapView.attributionsChanged?(attribution)
}
func mapViewDidFailLoadingMap(_ mapView: MGLMapView, withError error: Error) {
locationSharingMapView.errorSubject.send(.failedLoadingMap)
}

View File

@@ -41,6 +41,7 @@ enum LocationSharingViewAction {
case shareLiveLocation(timeout: LiveLocationSharingTimeout)
case userDidPan
case mapCreditsDidTap
case showMapCredit(mapAttribution: LocationSharingAttribution)
}
enum LocationSharingViewModelResult {
@@ -95,6 +96,8 @@ struct LocationSharingViewState: BindableState {
let errorSubject = PassthroughSubject<LocationSharingViewError, Never>()
var bindings = LocationSharingViewStateBindings()
var attribution = LocationSharingAttribution()
}
struct LocationSharingViewStateBindings {

View File

@@ -91,6 +91,8 @@ class LocationSharingViewModel: LocationSharingViewModelType, LocationSharingVie
state.isPinDropSharing = true
case .mapCreditsDidTap:
state.bindings.showMapCreditsSheet.toggle()
case .showMapCredit(mapAttribution: let mapAttribution):
state.attribution = mapAttribution
}
}

View File

@@ -43,12 +43,15 @@ struct LocationSharingView: View {
} else {
// Show map credits only if map is visible
MapCreditsView(action: {
MapCreditsView(
attributions:context.viewState.attribution,
action: {
context.send(viewAction: .mapCreditsDidTap)
})
.padding(.bottom, 10.0)
.actionSheet(isPresented: $context.showMapCreditsSheet) {
MapCreditsActionSheet(openURL: { url in
MapCreditsActionSheet(attribution:context.viewState.attribution,
openURL: { url in
UIApplication.shared.vc_open(url, completionHandler: nil)
}).sheet
}
@@ -101,7 +104,10 @@ struct LocationSharingView: View {
errorSubject: context.viewState.errorSubject,
userDidPan: {
context.send(viewAction: .userDidPan)
})
},
attributionsChanged: { attribution in
context.send(viewAction: .showMapCredit(mapAttribution: attribution))
})
if context.viewState.isPinDropSharing {
LocationSharingMarkerView(backgroundColor: theme.colors.accent) {
if BWIBuildSettings.shared.bwiEnableBuMUI {

View File

@@ -25,6 +25,7 @@ enum StaticLocationViewingViewAction {
case share
case mapCreditsDidTap
case showUserLocation
case showMapCredit(mapAttribution: LocationSharingAttribution)
}
enum StaticLocationViewingViewModelResult {
@@ -60,6 +61,8 @@ struct StaticLocationViewingViewState: BindableState {
let errorSubject = PassthroughSubject<LocationSharingViewError, Never>()
var bindings = StaticLocationViewingViewBindings()
var attribution = LocationSharingAttribution()
}
struct StaticLocationViewingViewBindings {

View File

@@ -71,6 +71,8 @@ class StaticLocationViewingViewModel: StaticLocationViewingViewModelType, Static
state.bindings.showMapCreditsSheet.toggle()
case .showUserLocation:
showsCurrentUserLocation()
case .showMapCredit(mapAttribution: let mapAttribution):
state.attribution = mapAttribution
}
}

View File

@@ -39,7 +39,10 @@ struct StaticLocationView: View {
showsUserLocationMode: viewModel.viewState.showsUserLocationMode,
userLocation: Binding.constant(nil),
mapCenterCoordinate: Binding.constant(nil),
errorSubject: viewModel.viewState.errorSubject)
errorSubject: viewModel.viewState.errorSubject,
attributionsChanged: { attribution in
viewModel.send(viewAction: .showMapCredit(mapAttribution: attribution))
})
}
var body: some View {
@@ -52,13 +55,17 @@ struct StaticLocationView: View {
showsUserLocationMode: ShowUserLocationMode.hide,
userLocation: Binding.constant(nil),
mapCenterCoordinate: Binding.constant(nil),
errorSubject: viewModel.viewState.errorSubject)
MapCreditsView(action: {
errorSubject: viewModel.viewState.errorSubject,
attributionsChanged: { attribution in
viewModel.send(viewAction: .showMapCredit(mapAttribution: attribution))
})
MapCreditsView(attributions: viewModel.viewState.attribution, action: {
viewModel.send(viewAction: .mapCreditsDidTap)
})
.padding(.bottom, 10.0 + safeAreaInsets.bottom)
.actionSheet(isPresented: $viewModel.showMapCreditsSheet) {
MapCreditsActionSheet(openURL: { url in
MapCreditsActionSheet(attribution:viewModel.viewState.attribution,
openURL: { url in
UIApplication.shared.vc_open(url, completionHandler: nil)
}).sheet
}

View File

@@ -0,0 +1,33 @@
//
/*
* Copyright (c) 2022 BWI GmbH
*
* 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 Foundation
class LocationSharingAttribution: ObservableObject {
var copyrightTexts: [String]
var copyrightLinks: [URL?]
init() {
copyrightTexts = []
copyrightLinks = []
}
init( copyrightTexts: [String], copyrightLinks: [URL?]) {
self.copyrightLinks = copyrightLinks
self.copyrightTexts = copyrightTexts
}
}