feat: use Capacitor Geolocation to prompt and get native location on Android
This commit is contained in:
Binary file not shown.
Vendored
+4
-4
@@ -21,13 +21,13 @@
|
|||||||
<meta name="twitter:title" content="Travel Planner - Lên kế hoạch chuyến đi của bạn" />
|
<meta name="twitter:title" content="Travel Planner - Lên kế hoạch chuyến đi của bạn" />
|
||||||
<meta name="twitter:description" content="Khám phá những hành trình tuyệt vời và chia sẻ khoảnh khắc đẹp với cộng đồng du lịch." />
|
<meta name="twitter:description" content="Khám phá những hành trình tuyệt vời và chia sẻ khoảnh khắc đẹp với cộng đồng du lịch." />
|
||||||
<meta name="twitter:image" content="https://yotrip.labz.io.vn/background.avif" />
|
<meta name="twitter:image" content="https://yotrip.labz.io.vn/background.avif" />
|
||||||
<script type="module" crossorigin src="/assets/index-B_EfWg-q.js"></script>
|
<script type="module" crossorigin src="/assets/index-CRcJJCpn.js"></script>
|
||||||
<link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-CMxvf4Kt.js">
|
<link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-CMxvf4Kt.js">
|
||||||
<link rel="modulepreload" crossorigin href="/assets/vendor-others-9VIIAnER.js">
|
<link rel="modulepreload" crossorigin href="/assets/vendor-others-C077EAcu.js">
|
||||||
<link rel="modulepreload" crossorigin href="/assets/vendor-editor-BDwQQzB8.js">
|
<link rel="modulepreload" crossorigin href="/assets/vendor-editor-BDwQQzB8.js">
|
||||||
<link rel="modulepreload" crossorigin href="/assets/vendor-maps-1-B38H26.js">
|
<link rel="modulepreload" crossorigin href="/assets/vendor-maps-1-B38H26.js">
|
||||||
<link rel="modulepreload" crossorigin href="/assets/vendor-react-OU16SOQH.js">
|
<link rel="modulepreload" crossorigin href="/assets/vendor-react-DRCYLnn6.js">
|
||||||
<link rel="modulepreload" crossorigin href="/assets/vendor-pdf-CKa2gyHu.js">
|
<link rel="modulepreload" crossorigin href="/assets/vendor-pdf-TQOwx6ff.js">
|
||||||
<link rel="stylesheet" crossorigin href="/assets/vendor-maps-CcXJxNtP.css">
|
<link rel="stylesheet" crossorigin href="/assets/vendor-maps-CcXJxNtP.css">
|
||||||
<link rel="stylesheet" crossorigin href="/assets/vendor-react-CuSj0z1j.css">
|
<link rel="stylesheet" crossorigin href="/assets/vendor-react-CuSj0z1j.css">
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-w726aohe.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-w726aohe.css">
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { useNotification } from '@/hooks/useNotification';
|
|||||||
import { useTourStore } from '@/store/useTourStore';
|
import { useTourStore } from '@/store/useTourStore';
|
||||||
import { processImageModeration } from '@/hooks/useImageModeration';
|
import { processImageModeration } from '@/hooks/useImageModeration';
|
||||||
import { processAndResizeImage } from '../utils/imageProcessor';
|
import { processAndResizeImage } from '../utils/imageProcessor';
|
||||||
|
import { getDeviceLocation } from '../utils/geolocation';
|
||||||
|
|
||||||
interface AddPhotoModalProps {
|
interface AddPhotoModalProps {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
@@ -38,20 +39,7 @@ export const AddPhotoModal: React.FC<AddPhotoModalProps> = ({ isOpen, onClose, t
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Fetch device location once to serve as Priority 2 fallback for files without EXIF
|
// Fetch device location once to serve as Priority 2 fallback for files without EXIF
|
||||||
const deviceLocation = await Promise.race([
|
const deviceLocation = await getDeviceLocation();
|
||||||
new Promise<GeolocationPosition | null>((resolve) => {
|
|
||||||
if (!navigator.geolocation) {
|
|
||||||
resolve(null);
|
|
||||||
} else {
|
|
||||||
navigator.geolocation.getCurrentPosition(
|
|
||||||
(pos) => resolve(pos),
|
|
||||||
() => resolve(null),
|
|
||||||
{ timeout: 3500, enableHighAccuracy: true }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
new Promise<null>((resolve) => setTimeout(() => resolve(null), 4000))
|
|
||||||
]);
|
|
||||||
|
|
||||||
const newValidPhotos: PendingPhoto[] = [];
|
const newValidPhotos: PendingPhoto[] = [];
|
||||||
const newValidPreviews: string[] = [];
|
const newValidPreviews: string[] = [];
|
||||||
@@ -89,9 +77,9 @@ export const AddPhotoModal: React.FC<AddPhotoModalProps> = ({ isOpen, onClose, t
|
|||||||
let finalLng: number | null = exifLng;
|
let finalLng: number | null = exifLng;
|
||||||
|
|
||||||
// Priority 2: Device location
|
// Priority 2: Device location
|
||||||
if ((finalLat === null || finalLng === null) && deviceLocation && deviceLocation.coords) {
|
if ((finalLat === null || finalLng === null) && deviceLocation) {
|
||||||
finalLat = deviceLocation.coords.latitude;
|
finalLat = deviceLocation.latitude;
|
||||||
finalLng = deviceLocation.coords.longitude;
|
finalLng = deviceLocation.longitude;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Priority 3: Map view state
|
// Priority 3: Map view state
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { useNotification } from '@/hooks/useNotification';
|
|||||||
import { processImageModeration } from '../hooks/useImageModeration';
|
import { processImageModeration } from '../hooks/useImageModeration';
|
||||||
import { useTranslation } from '../hooks/useTranslation';
|
import { useTranslation } from '../hooks/useTranslation';
|
||||||
import { processAndResizeImage } from '../utils/imageProcessor';
|
import { processAndResizeImage } from '../utils/imageProcessor';
|
||||||
|
import { getDeviceLocation } from '../utils/geolocation';
|
||||||
|
|
||||||
interface LandingPageProps {
|
interface LandingPageProps {
|
||||||
onContinue?: () => void;
|
onContinue?: () => void;
|
||||||
@@ -215,23 +216,10 @@ export const LandingPage: React.FC<LandingPageProps> = ({
|
|||||||
// 2. Get current mobile/device GPS position of the user
|
// 2. Get current mobile/device GPS position of the user
|
||||||
if (finalLat === null || finalLng === null) {
|
if (finalLat === null || finalLng === null) {
|
||||||
try {
|
try {
|
||||||
const pos = await Promise.race([
|
const deviceLoc = await getDeviceLocation();
|
||||||
new Promise<GeolocationPosition | null>((resolve) => {
|
if (deviceLoc) {
|
||||||
if (!navigator.geolocation) {
|
finalLat = deviceLoc.latitude;
|
||||||
resolve(null);
|
finalLng = deviceLoc.longitude;
|
||||||
} else {
|
|
||||||
navigator.geolocation.getCurrentPosition(
|
|
||||||
(p) => resolve(p),
|
|
||||||
() => resolve(null),
|
|
||||||
{ timeout: 4000, enableHighAccuracy: true }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
new Promise<null>((resolve) => setTimeout(() => resolve(null), 4500))
|
|
||||||
]);
|
|
||||||
if (pos && pos.coords) {
|
|
||||||
finalLat = pos.coords.latitude;
|
|
||||||
finalLng = pos.coords.longitude;
|
|
||||||
console.log('[Upload Location] Priority 2: GPS coordinates found:', finalLat, finalLng);
|
console.log('[Upload Location] Priority 2: GPS coordinates found:', finalLat, finalLng);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import { Geolocation } from '@capacitor/geolocation';
|
||||||
|
|
||||||
|
export interface DeviceLocation {
|
||||||
|
latitude: number;
|
||||||
|
longitude: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getDeviceLocation(): Promise<DeviceLocation | null> {
|
||||||
|
try {
|
||||||
|
// Request permission at native level (essential for Android app packaging)
|
||||||
|
const permissionStatus = await Geolocation.requestPermissions();
|
||||||
|
if (permissionStatus.location === 'granted' || permissionStatus.coarseLocation === 'granted') {
|
||||||
|
const position = await Geolocation.getCurrentPosition({
|
||||||
|
enableHighAccuracy: true,
|
||||||
|
timeout: 5000
|
||||||
|
});
|
||||||
|
if (position && position.coords) {
|
||||||
|
console.log('[Geolocation] Acquired coordinates via Capacitor Geolocation:', position.coords.latitude, position.coords.longitude);
|
||||||
|
return {
|
||||||
|
latitude: position.coords.latitude,
|
||||||
|
longitude: position.coords.longitude
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('[Geolocation] Capacitor plugin failed/unavailable, falling back to browser Geolocation:', error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to standard web browser Geolocation API
|
||||||
|
try {
|
||||||
|
const position = await new Promise<GeolocationPosition | null>((resolve) => {
|
||||||
|
if (!navigator.geolocation) {
|
||||||
|
resolve(null);
|
||||||
|
} else {
|
||||||
|
navigator.geolocation.getCurrentPosition(
|
||||||
|
(p) => resolve(p),
|
||||||
|
() => resolve(null),
|
||||||
|
{ timeout: 4000, enableHighAccuracy: true }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (position && position.coords) {
|
||||||
|
console.log('[Geolocation] Acquired coordinates via Web Geolocation:', position.coords.latitude, position.coords.longitude);
|
||||||
|
return {
|
||||||
|
latitude: position.coords.latitude,
|
||||||
|
longitude: position.coords.longitude
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('[Geolocation] Browser Geolocation failed:', e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user