88import SwiftUI
99import MapKit
1010
11- struct UserTrackingButton : View {
12- @ObservedObject var locationManager : LocationManager = LocationManager . shared
11+ struct UserTrackingButton < Location > : View where Location : LocationManagerProtocol {
12+ @ObservedObject var locationManager : Location
1313
1414 @State var imageName : String = " location "
15- @State var appearDisabled : Bool = false
15+ @State var userTrackingModeDescription : String = " none "
16+ var appearDisabled : Bool {
17+ !authorized
18+ }
19+ @State var showingAlert : Bool = false
20+
21+ var authorized : Bool {
22+ locationManager. locationStatus == . authorizedAlways || locationManager. locationStatus == . authorizedWhenInUse
23+ }
1624
1725 @AppStorage ( " userTrackingMode " ) var userTrackingMode : Int = Int ( MKUserTrackingMode . none. rawValue)
1826 var mapState : MapState ?
1927
28+ init ( mapState: MapState ? , locationManager: Location = LocationManager . shared) {
29+ self . mapState = mapState
30+ self . locationManager = locationManager
31+ }
32+
2033 var body : some View {
2134 Button ( action: {
2235 buttonPressed ( )
@@ -27,45 +40,42 @@ struct UserTrackingButton: View {
2740 . renderingMode ( . template)
2841 } )
2942 }
43+ . accessibilityElement ( )
44+ . accessibilityLabel ( " Tracking \( userTrackingModeDescription) \( authorized ? " " : " Unauthorized " ) " )
3045 . onAppear {
31- setupTrackingButton ( locationAuthorizationStatus : locationManager . locationStatus ?? . notDetermined )
46+ setButtonImage ( )
3247 mapState? . userTrackingMode = userTrackingMode
3348 }
3449 . onChange ( of: locationManager. locationStatus ?? . notDetermined) { newValue in
35- setupTrackingButton ( locationAuthorizationStatus : newValue )
50+ setButtonImage ( )
3651 }
3752 . onChange ( of: mapState? . userTrackingMode) { newValue in
3853 if let mode = newValue {
3954 userTrackingMode = mode
4055 setButtonImage ( )
4156 }
4257 }
43- . buttonStyle ( MaterialFloatingButtonStyle ( type: . secondary, size: . mini) )
58+ . buttonStyle ( MaterialFloatingButtonStyle ( type: . secondary, size: . mini, foregroundColor: appearDisabled ? Color . disabledColor : Color . primaryColorVariant) )
59+ . alert ( isPresented: $showingAlert) {
60+ Alert ( title: Text ( " Location Services Disabled " ) ,
61+ message: Text ( " Marlin has been denied access to location services. To show your location on the map, please go into your device settings and enable the Location permission. " ) ,
62+ primaryButton: . default( Text ( " Settings " ) ,
63+ action: {
64+ if let url = NSURL ( string: UIApplication . openSettingsURLString) as URL ? {
65+ UIApplication . shared. open ( url, options: [ : ] , completionHandler: nil )
66+ }
67+ } ) ,
68+ secondaryButton: . cancel( ) )
69+ }
4470 }
4571
4672 func buttonPressed( ) {
47- let authorized = locationManager. locationStatus == . authorizedAlways || locationManager. locationStatus == . authorizedWhenInUse
4873 if !authorized {
49- let alert = UIAlertController ( title: " Location Services Disabled " , message: " Marlin has been denied access to location services. To show your location on the map, please go into your device settings and enable the Location permission. " , preferredStyle: . alert)
50- alert. addAction ( UIAlertAction ( title: " Cancel " , style: . cancel, handler: nil ) )
51- alert. addAction ( UIAlertAction ( title: " Settings " , style: . default, handler: { action in
52- if let url = NSURL ( string: UIApplication . openSettingsURLString) as URL ? {
53- UIApplication . shared. open ( url, options: [ : ] , completionHandler: nil )
54- }
55- } ) )
56- UIApplication . shared. keyWindow? . rootViewController? . present ( alert, animated: true , completion: nil )
57- return
74+ showingAlert = true
75+ } else {
76+ updateTrackingMode ( )
77+ setButtonImage ( )
5878 }
59-
60- updateTrackingMode ( )
61- setButtonImage ( )
62- }
63-
64- func setupTrackingButton( locationAuthorizationStatus: CLAuthorizationStatus ) {
65- let authorized = locationAuthorizationStatus == . authorizedAlways || locationAuthorizationStatus == . authorizedWhenInUse
66- appearDisabled = !authorized
67-
68- setButtonImage ( )
6979 }
7080
7181 func updateTrackingMode( ) {
@@ -88,12 +98,16 @@ struct UserTrackingButton: View {
8898 switch MKUserTrackingMode ( rawValue: userTrackingMode) ?? . none {
8999 case . none:
90100 imageName = " location "
101+ userTrackingModeDescription = " none "
91102 case . follow:
92103 imageName = " location.fill "
104+ userTrackingModeDescription = " follow "
93105 case . followWithHeading:
94106 imageName = " location.north.line.fill "
107+ userTrackingModeDescription = " follow with heading "
95108 @unknown default :
96109 imageName = " location "
110+ userTrackingModeDescription = " none "
97111 }
98112 }
99113}
0 commit comments