Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 9 additions & 69 deletions app/(tabs)/tracking.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,16 +85,6 @@ const { colors } = require("../../tokens.cjs") as {
};
const COLOR_WHITE = colors.common["100"]; // #ffffff

// ── 데모 모드 ─────────────────────────────────────────────────────────────────
// 시연/촬영용. 배포 시 false로 변경
const DEMO_MODE = true;
// 관악산 좌표 — nearbyMountain API 대신 이 위치로 고정
const DEMO_LAT = 37.4449;
const DEMO_LNG = 126.9636;
// 시뮬레이션 속도: N ms마다 STEP개 좌표씩 이동
const DEMO_SIM_INTERVAL_MS = 800;
const DEMO_SIM_STEP = 5;
// ──────────────────────────────────────────────────────────────────────────────

// 경사 등급별 polyline 색상 (outline은 디자인 토큰 common-100 사용)
const SEGMENT_COLORS: Record<string, { color: string }> = {
Expand Down Expand Up @@ -201,17 +191,7 @@ export default function TrackingScreen() {
}, [courseIdParameter, collapseParameter]);

// 위치 권한 요청 및 현재 위치 조회 (진입 시 1회)
// DEMO_MODE: 관악산 좌표로 고정 (nearbyMountain API가 관악산 반환)
useEffect(() => {
if (DEMO_MODE) {
setUserLocation({
latitude: DEMO_LAT,
longitude: DEMO_LNG,
altitude: null,
});
setMarkerCoord({ latitude: DEMO_LAT, longitude: DEMO_LNG });
return;
}
(async () => {
try {
const { status } = await Location.requestForegroundPermissionsAsync();
Expand Down Expand Up @@ -662,24 +642,11 @@ export default function TrackingScreen() {

// [DEV] 코스 좌표를 빠르게 publish — 백엔드 마일스톤 트리거 테스트용

// polyline 로드되거나 트래킹 시작 시 카메라 설정
// 데모 모드 + 트래킹 중: 출발 좌표로 줌 (follow 모드와 충돌 방지)
// 그 외: 전체 경로가 보이도록 맞춤
// polyline 로드되거나 트래킹 시작 시 전체 경로가 보이도록 카메라 맞춤
useEffect(() => {
if (courseCoords.length < 2) return;

const timer = setTimeout(() => {
if (DEMO_MODE && isTracking) {
// 데모 모드 트래킹 중 — 출발 좌표(첫 번째 포인트)로 줌
mapRef.current?.animateCameraTo({
latitude: courseCoords[0].latitude,
longitude: courseCoords[0].longitude,
zoom: 15,
duration: 500,
});
return;
}

const lats = courseCoords.map((c) => c.latitude);
const lngs = courseCoords.map((c) => c.longitude);
const minLat = Math.min(...lats);
Expand All @@ -703,14 +670,18 @@ export default function TrackingScreen() {
}, [courseDetail?.polyline, isTracking]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

useEffect 내부에서 courseCoords를 참조하여 카메라 범위를 계산하고 있지만, 의존성 배열에는 courseDetail?.polyline이 등록되어 있습니다.

courseCoordscourseDetail?.polyline을 기반으로 계산된 useMemo 값이므로, React Hook 규칙(react-hooks/exhaustive-deps)을 준수하고 잠재적인 버그를 방지하기 위해 의존성 배열에 courseCoords를 직접 전달하는 것이 좋습니다.

Suggested change
}, [courseDetail?.polyline, isTracking]);
}, [courseCoords, isTracking]);


// 트래킹 시작/종료 시 follow 모드 토글
// 코스 따라가기: 시작 시 전체 코스가 보이도록 follow 비활성 (위치 버튼으로 재활성 가능)
// 자유기록: 시작 시 현위치 follow 활성
Comment on lines +673 to +674

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

주석과 PR 설명에는 **"위치 버튼으로 재활성 가능"**하다고 언급되어 있으나, 실제 위치 버튼의 onPress 핸들러(1214번 라인 부근)에서는 setIsFollowingUser(true)를 호출하지 않고 카메라만 1회성으로 이동시키고 있습니다.

이로 인해 사용자가 위치 버튼을 눌러도 실시간 위치 추적(follow) 모드가 다시 활성화되지 않고, 움직여도 지도가 사용자를 따라가지 않는 문제가 발생합니다.

위치 버튼의 onPress 핸들러를 다음과 같이 수정하여 실시간 추적도 함께 재활성화되도록 개선해 주세요.

onPress={() => {
  const coord = markerCoord ?? userLocation;
  if (coord) {
    setIsFollowingUser(true); // 실시간 추적 재활성화
    mapRef.current?.animateCameraTo({
      latitude: coord.latitude,
      longitude: coord.longitude,
      zoom: 15,
    });
  }
}}

useEffect(() => {
setIsFollowingUser(isTracking);
}, [isTracking]);
if (isTracking) {
setIsFollowingUser(isFreeMode);
} else {
setIsFollowingUser(false);
}
}, [isTracking, isFreeMode]);

// 트래킹 중 실시간 위치 마커 카메라 추적 (사용자가 직접 조작하면 follow 해제)
// 데모 모드에서는 카메라 follow 비활성 — 출발 좌표로 고정 (시뮬 마커가 카메라 흔들기 방지)
useEffect(() => {
if (DEMO_MODE) return;
if (!isFollowingUser || !markerCoord) return;
mapRef.current?.animateCameraTo({
latitude: markerCoord.latitude,
Expand All @@ -720,37 +691,6 @@ export default function TrackingScreen() {
});
}, [markerCoord, isFollowingUser]);

// ── 데모 좌표 시뮬레이션 ────────────────────────────────────────────────────
const simIdxRef = useRef(0);
useEffect(() => {
if (!DEMO_MODE || !isTracking || isPaused || courseCoords.length < 2)
return;

simIdxRef.current = 0; // 트래킹 시작 시 처음부터

const interval = setInterval(() => {
const idx = simIdxRef.current;
if (idx >= courseCoords.length) {
clearInterval(interval);
return;
}
const { latitude, longitude } = courseCoords[idx];
setMarkerCoord({ latitude, longitude });
setUserLocation({ latitude, longitude, altitude: null });
if (sessionId != null) {
publishGps(sessionId, {
lat: latitude,
lng: longitude,
altitude: null,
recordedAt: new Date().toISOString(),
});
}
simIdxRef.current += DEMO_SIM_STEP;
}, DEMO_SIM_INTERVAL_MS);

return () => clearInterval(interval);
}, [isTracking, isPaused, courseCoords, sessionId]);
// ──────────────────────────────────────────────────────────────────────────────

const startCountdown = (freeMode = false) => {
setIsFreeMode(freeMode === true); // 이벤트 객체 등 non-boolean 방지
Expand Down
Loading