capacitor-google-navigation 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -5
- package/android/src/main/java/com/attributeai/navigation/GoogleNavigation.java +4 -0
- package/android/src/main/java/com/attributeai/navigation/NavigationFragment.java +42 -1
- package/ios/Sources/GoogleNavigationPlugin/GoogleNavigation.swift +21 -1
- package/ios/Sources/GoogleNavigationPlugin/NavigationViewController.swift +39 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -134,8 +134,8 @@ startNavigation({ lat, lng, travelMode })
|
|
|
134
134
|
↓ fires onRouteChanged on recalculation
|
|
135
135
|
stopNavigation()
|
|
136
136
|
↓ ends guidance, clears destination
|
|
137
|
-
showNavigationView({ show: false })
|
|
138
|
-
↓ dismisses native map, restores app UI
|
|
137
|
+
showNavigationView({ show: false }) — or user taps the ✕ close button
|
|
138
|
+
↓ dismisses native map, fires onNavigationClosed, restores app UI
|
|
139
139
|
```
|
|
140
140
|
|
|
141
141
|
---
|
|
@@ -154,9 +154,10 @@ interface UseNavigationOptions {
|
|
|
154
154
|
apiKey: string;
|
|
155
155
|
onArrival?: (event: any) => void;
|
|
156
156
|
onRouteChanged?: () => void;
|
|
157
|
+
onNavigationClosed?: () => void;
|
|
157
158
|
}
|
|
158
159
|
|
|
159
|
-
export function useGoogleNavigation({ apiKey, onArrival, onRouteChanged }: UseNavigationOptions) {
|
|
160
|
+
export function useGoogleNavigation({ apiKey, onArrival, onRouteChanged, onNavigationClosed }: UseNavigationOptions) {
|
|
160
161
|
const listeners = useRef<PluginListenerHandle[]>([]);
|
|
161
162
|
|
|
162
163
|
useEffect(() => {
|
|
@@ -176,6 +177,11 @@ export function useGoogleNavigation({ apiKey, onArrival, onRouteChanged }: UseNa
|
|
|
176
177
|
listeners.current.push(h);
|
|
177
178
|
}
|
|
178
179
|
|
|
180
|
+
if (onNavigationClosed) {
|
|
181
|
+
const h = await GoogleNavigation.addListener('onNavigationClosed', onNavigationClosed);
|
|
182
|
+
listeners.current.push(h);
|
|
183
|
+
}
|
|
184
|
+
|
|
179
185
|
await GoogleNavigation.initialize({ apiKey });
|
|
180
186
|
};
|
|
181
187
|
|
|
@@ -232,6 +238,7 @@ const NavigationPage: React.FC = () => {
|
|
|
232
238
|
apiKey: import.meta.env.VITE_GOOGLE_NAV_API_KEY as string,
|
|
233
239
|
onArrival: () => setShowArrival(true),
|
|
234
240
|
onRouteChanged: () => console.log('Route recalculated'),
|
|
241
|
+
onNavigationClosed: () => console.log('User closed navigation'),
|
|
235
242
|
});
|
|
236
243
|
|
|
237
244
|
return (
|
|
@@ -301,6 +308,11 @@ const routeHandle = await GoogleNavigation.addListener('onRouteChanged', () => {
|
|
|
301
308
|
console.log('Route recalculated');
|
|
302
309
|
});
|
|
303
310
|
|
|
311
|
+
const closedHandle = await GoogleNavigation.addListener('onNavigationClosed', () => {
|
|
312
|
+
// Fired when the user taps the ✕ close button on the native navigation view
|
|
313
|
+
console.log('Navigation closed by user');
|
|
314
|
+
});
|
|
315
|
+
|
|
304
316
|
// 2. Initialize the SDK (fires onNavigationReady when done)
|
|
305
317
|
await GoogleNavigation.initialize({ apiKey: 'YOUR_API_KEY' });
|
|
306
318
|
|
|
@@ -400,14 +412,14 @@ Show/hide navigation view
|
|
|
400
412
|
### addListener(...)
|
|
401
413
|
|
|
402
414
|
```typescript
|
|
403
|
-
addListener(eventName: 'onArrival' | 'onRouteChanged' | 'onNavigationReady', listenerFunc: (event: any) => void) => Promise<PluginListenerHandle>
|
|
415
|
+
addListener(eventName: 'onArrival' | 'onRouteChanged' | 'onNavigationReady' | 'onNavigationClosed', listenerFunc: (event: any) => void) => Promise<PluginListenerHandle>
|
|
404
416
|
```
|
|
405
417
|
|
|
406
418
|
Add listener for navigation events
|
|
407
419
|
|
|
408
420
|
| Param | Type |
|
|
409
421
|
| ------------------ | ----------------------------------------------------------------- |
|
|
410
|
-
| **`eventName`** | <code>'onArrival' \| 'onRouteChanged' \| 'onNavigationReady'</code> |
|
|
422
|
+
| **`eventName`** | <code>'onArrival' \| 'onRouteChanged' \| 'onNavigationReady' \| 'onNavigationClosed'</code> |
|
|
411
423
|
| **`listenerFunc`** | <code>(event: any) => void</code> |
|
|
412
424
|
|
|
413
425
|
**Returns:** <code>Promise<<a href="#pluginlistenerhandle">PluginListenerHandle</a>></code>
|
|
@@ -446,6 +458,7 @@ Remove all listeners
|
|
|
446
458
|
| `onNavigationReady` | `{}` | SDK has initialized and the navigator is available |
|
|
447
459
|
| `onArrival` | `{ latitude, longitude, title }` | User arrives at the destination waypoint |
|
|
448
460
|
| `onRouteChanged` | `{}` | The route is recalculated (traffic, missed turn, etc.) |
|
|
461
|
+
| `onNavigationClosed` | `{}` | User tapped the ✕ close button on the native navigation view (iOS) |
|
|
449
462
|
|
|
450
463
|
---
|
|
451
464
|
|
|
@@ -118,6 +118,10 @@ public class GoogleNavigation {
|
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
NavigationFragment fragment = NavigationFragment.newInstance();
|
|
121
|
+
fragment.setOnCloseListener(() -> {
|
|
122
|
+
fm.beginTransaction().remove(fragment).commitAllowingStateLoss();
|
|
123
|
+
plugin.fireEvent("onNavigationClosed", new JSObject());
|
|
124
|
+
});
|
|
121
125
|
fm.beginTransaction()
|
|
122
126
|
.add(android.R.id.content, fragment, FRAGMENT_TAG)
|
|
123
127
|
.commitAllowingStateLoss();
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
package com.attributeai.navigation;
|
|
2
2
|
|
|
3
|
+
import android.graphics.Color;
|
|
4
|
+
import android.graphics.Typeface;
|
|
3
5
|
import android.os.Bundle;
|
|
6
|
+
import android.util.TypedValue;
|
|
7
|
+
import android.view.Gravity;
|
|
4
8
|
import android.view.LayoutInflater;
|
|
5
9
|
import android.view.View;
|
|
6
10
|
import android.view.ViewGroup;
|
|
11
|
+
import android.widget.Button;
|
|
12
|
+
import android.widget.FrameLayout;
|
|
7
13
|
|
|
8
14
|
import androidx.annotation.NonNull;
|
|
9
15
|
import androidx.annotation.Nullable;
|
|
@@ -19,11 +25,16 @@ import com.google.android.libraries.navigation.NavigationView;
|
|
|
19
25
|
public class NavigationFragment extends Fragment {
|
|
20
26
|
|
|
21
27
|
private NavigationView navigationView;
|
|
28
|
+
private Runnable onCloseListener;
|
|
22
29
|
|
|
23
30
|
public static NavigationFragment newInstance() {
|
|
24
31
|
return new NavigationFragment();
|
|
25
32
|
}
|
|
26
33
|
|
|
34
|
+
public void setOnCloseListener(Runnable listener) {
|
|
35
|
+
this.onCloseListener = listener;
|
|
36
|
+
}
|
|
37
|
+
|
|
27
38
|
@Nullable
|
|
28
39
|
@Override
|
|
29
40
|
public View onCreateView(
|
|
@@ -33,7 +44,37 @@ public class NavigationFragment extends Fragment {
|
|
|
33
44
|
) {
|
|
34
45
|
navigationView = new NavigationView(requireContext());
|
|
35
46
|
navigationView.onCreate(savedInstanceState);
|
|
36
|
-
|
|
47
|
+
|
|
48
|
+
FrameLayout root = new FrameLayout(requireContext());
|
|
49
|
+
root.addView(navigationView, new FrameLayout.LayoutParams(
|
|
50
|
+
FrameLayout.LayoutParams.MATCH_PARENT,
|
|
51
|
+
FrameLayout.LayoutParams.MATCH_PARENT
|
|
52
|
+
));
|
|
53
|
+
|
|
54
|
+
Button closeButton = new Button(requireContext());
|
|
55
|
+
closeButton.setText("✕");
|
|
56
|
+
closeButton.setTextColor(Color.WHITE);
|
|
57
|
+
closeButton.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
|
|
58
|
+
closeButton.setTypeface(null, Typeface.BOLD);
|
|
59
|
+
closeButton.setBackgroundColor(Color.argb(153, 0, 0, 0)); // 60% black
|
|
60
|
+
closeButton.setOnClickListener(v -> {
|
|
61
|
+
if (onCloseListener != null) onCloseListener.run();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
int sizePx = (int) TypedValue.applyDimension(
|
|
65
|
+
TypedValue.COMPLEX_UNIT_DIP, 40, getResources().getDisplayMetrics()
|
|
66
|
+
);
|
|
67
|
+
int marginPx = (int) TypedValue.applyDimension(
|
|
68
|
+
TypedValue.COMPLEX_UNIT_DIP, 16, getResources().getDisplayMetrics()
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
FrameLayout.LayoutParams btnParams = new FrameLayout.LayoutParams(sizePx, sizePx);
|
|
72
|
+
btnParams.gravity = Gravity.TOP | Gravity.START;
|
|
73
|
+
btnParams.topMargin = marginPx;
|
|
74
|
+
btnParams.leftMargin = marginPx;
|
|
75
|
+
root.addView(closeButton, btnParams);
|
|
76
|
+
|
|
77
|
+
return root;
|
|
37
78
|
}
|
|
38
79
|
|
|
39
80
|
@Override
|
|
@@ -49,6 +49,14 @@ import GoogleNavigation
|
|
|
49
49
|
|
|
50
50
|
let mapVC = NavigationMapViewController(session: session)
|
|
51
51
|
mapVC.modalPresentationStyle = .fullScreen
|
|
52
|
+
mapVC.onDismiss = { [weak self] in
|
|
53
|
+
guard let self = self else { return }
|
|
54
|
+
self.navigationSession?.navigator?.remove(self)
|
|
55
|
+
self.navigationSession?.isStarted = false
|
|
56
|
+
self.navigationSession = nil
|
|
57
|
+
self.mapViewController = nil
|
|
58
|
+
self.plugin?.notifyListeners("onNavigationClosed", data: [:])
|
|
59
|
+
}
|
|
52
60
|
self.mapViewController = mapVC
|
|
53
61
|
|
|
54
62
|
presentingVC.present(mapVC, animated: true) {
|
|
@@ -101,7 +109,19 @@ import GoogleNavigation
|
|
|
101
109
|
self?.mapViewController?.setCameraFollowing()
|
|
102
110
|
completion(true, nil)
|
|
103
111
|
} else {
|
|
104
|
-
|
|
112
|
+
let reason: String
|
|
113
|
+
switch routeStatus {
|
|
114
|
+
case .apiKeyNotAuthorized: reason = "API key not authorized for Navigation SDK"
|
|
115
|
+
case .networkError: reason = "Network error — check internet connection"
|
|
116
|
+
case .noRouteFound: reason = "No route found to destination"
|
|
117
|
+
case .locationUnavailable: reason = "Location unavailable — check permissions"
|
|
118
|
+
case .quotaExceeded: reason = "API quota exceeded"
|
|
119
|
+
case .waypointError: reason = "Invalid waypoint coordinates"
|
|
120
|
+
case .travelModeUnsupported: reason = "Travel mode not supported"
|
|
121
|
+
case .canceled: reason = "Route request was canceled"
|
|
122
|
+
default: reason = "Unknown error (code \(routeStatus.rawValue))"
|
|
123
|
+
}
|
|
124
|
+
completion(false, "Route calculation failed: \(reason)")
|
|
105
125
|
}
|
|
106
126
|
}
|
|
107
127
|
}
|
|
@@ -5,6 +5,7 @@ import GoogleNavigation
|
|
|
5
5
|
class NavigationMapViewController: UIViewController {
|
|
6
6
|
private let session: GMSNavigationSession
|
|
7
7
|
private var mapView: GMSMapView?
|
|
8
|
+
var onDismiss: (() -> Void)?
|
|
8
9
|
|
|
9
10
|
init(session: GMSNavigationSession) {
|
|
10
11
|
self.session = session
|
|
@@ -15,18 +16,48 @@ class NavigationMapViewController: UIViewController {
|
|
|
15
16
|
fatalError("init(coder:) not supported")
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
override func
|
|
19
|
-
super.viewDidLoad()
|
|
20
|
-
|
|
19
|
+
override func loadView() {
|
|
21
20
|
let options = GMSMapViewOptions()
|
|
22
|
-
options.frame =
|
|
21
|
+
options.frame = UIScreen.main.bounds
|
|
23
22
|
let mapView = GMSMapView(options: options)
|
|
24
|
-
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
25
|
-
view.addSubview(mapView)
|
|
26
23
|
self.mapView = mapView
|
|
24
|
+
self.view = mapView
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
override func viewDidLoad() {
|
|
28
|
+
super.viewDidLoad()
|
|
29
|
+
|
|
30
|
+
guard let mapView = mapView else { return }
|
|
31
|
+
let enabled = mapView.enableNavigation(with: session)
|
|
32
|
+
if enabled {
|
|
33
|
+
mapView.cameraMode = .following
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
addCloseButton()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private func addCloseButton() {
|
|
40
|
+
let button = UIButton(type: .system)
|
|
41
|
+
button.setImage(UIImage(systemName: "xmark"), for: .normal)
|
|
42
|
+
button.tintColor = .white
|
|
43
|
+
button.backgroundColor = UIColor.black.withAlphaComponent(0.6)
|
|
44
|
+
button.layer.cornerRadius = 20
|
|
45
|
+
button.translatesAutoresizingMaskIntoConstraints = false
|
|
46
|
+
button.addTarget(self, action: #selector(closeTapped), for: .touchUpInside)
|
|
47
|
+
view.addSubview(button)
|
|
48
|
+
|
|
49
|
+
NSLayoutConstraint.activate([
|
|
50
|
+
button.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 16),
|
|
51
|
+
button.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
|
|
52
|
+
button.widthAnchor.constraint(equalToConstant: 40),
|
|
53
|
+
button.heightAnchor.constraint(equalToConstant: 40)
|
|
54
|
+
])
|
|
55
|
+
}
|
|
27
56
|
|
|
28
|
-
|
|
29
|
-
|
|
57
|
+
@objc private func closeTapped() {
|
|
58
|
+
dismiss(animated: true) { [weak self] in
|
|
59
|
+
self?.onDismiss?()
|
|
60
|
+
}
|
|
30
61
|
}
|
|
31
62
|
|
|
32
63
|
func setCameraFollowing() {
|