GALAXY 맵에서 고른 행성을 카메라가 따라가 화면 가운데에 유지

This commit is contained in:
Sn-Kinos
2026-10-05 14:17:44 +09:00
parent 8a0297eb92
commit 5ad229b971
2 changed files with 91 additions and 20 deletions
+70 -20
View File
@@ -11,6 +11,7 @@ import 'package:fancake/features/galaxy/galaxy_screen.dart';
import 'package:fancake/features/galaxy/galaxy_search_screen.dart';
import 'package:fancake/features/galaxy/widgets/zap_button.dart';
import 'package:fancake/features/planet/planet_data.dart';
import 'package:fancake/features/planet/planet_detail_screen.dart';
import 'eclipse_stubs.dart';
@@ -33,6 +34,24 @@ Future<void> _pump(WidgetTester tester, Widget screen) async {
await tester.pump(const Duration(milliseconds: 950)); // 이벤트 띠 슬라이드
}
/// 두 손가락으로 끝까지 확대하며 오른쪽 아래로 끈다(한 손가락 팬은 없다).
Future<void> _pinch(WidgetTester tester) async {
final origin = tester.getTopLeft(find.byType(InteractiveViewer));
final a = await tester.startGesture(origin + const Offset(4, 4));
final b = await tester.startGesture(
origin + const Offset(24, 24),
pointer: 7,
);
for (var i = 1; i <= 10; i++) {
await b.moveTo(origin + Offset(24.0 + i * 32, 24.0 + i * 32));
await a.moveTo(origin + Offset(4.0 + i * 20, 4.0 + i * 20));
await tester.pump();
}
await a.up();
await b.up();
await _settle(tester);
}
/// 회전이 도는 동안에도 안전하게 몇 프레임 넘긴다.
Future<void> _settle(WidgetTester tester) async {
for (var i = 0; i < 6; i++) {
@@ -176,17 +195,16 @@ void main() {
tester.view.devicePixelRatio = 2.0;
addTearDown(tester.view.reset);
await _pump(tester, _galaxy());
// 가운데 내 행성은 궤도를 돌지 않는다 — 궤도 위 행성을 골라 돌린다.
await tester.tap(find.byKey(const ValueKey('newjeans')));
await _settle(tester);
final before = tester.getCenter(find.text('RANK'));
await tester.drag(find.byType(InteractiveViewer), const Offset(-200, 0));
await _settle(tester);
// 확대하면 행성이 커지고, 행성 위에 붙은 카드는 행성 가장자리를 따라 밀려난다.
await _pinch(tester);
final after = tester.getCenter(find.text('RANK'));
expect(
(after - before).distance,
greaterThan(20),
reason: '화면 고정 패널이면 맵을 끌어도 제자리에 있다',
reason: '화면 고정 패널이면 확대해도 제자리에 있다',
);
});
@@ -277,31 +295,63 @@ void main() {
// 리뷰 M2 — 행성이 뷰포트 밖이면 HUD 를 아예 그리지 않는다. 카드만 가장자리에
// clamp 해 두면 어느 행성을 가리키는지 알 수 없고 연결선은 화면 밖에 그려진다.
testWidgets('행성이 화면 밖으로 나가면 HUD 도 사라진다', (tester) async {
// 고른 행성은 카메라가 따라가므로(10/5) 확대·초점 이동으로도 화면 밖으로 밀리지 않는다.
testWidgets('확대해도 고른 행성은 가운데에 남고 HUD 도 남는다', (tester) async {
await _pump(tester, _galaxy());
final mid = tester.getCenter(find.byType(InteractiveViewer));
await _pinch(tester);
expect(find.text('RANK'), findsOneWidget);
final mine = tester.widget<InteractiveViewer>(find.byType(InteractiveViewer));
expect(mine.transformationController!.value.getMaxScaleOnAxis(),
greaterThan(GalaxyMotion.focusZoom));
final at = tester.getCenter(find.text('RANK'));
expect((at.dx - mid.dx).abs(), lessThan(mid.dx), reason: '카드가 화면 안');
});
// 끝까지 확대하며 두 손가락을 오른쪽 아래로 끌어 내 행성을 화면 밖으로 보낸다
// (한 손가락 팬은 없다 — 확대 제스처의 초점 이동만 맵을 옮긴다).
// 10/5 실기기(Flip3) — 다른 행성을 탭하면 중심 전환 뒤에도 궤도가 돌아 고른 행성이
// 화면 밖으로 흘러가고 내 행성은 가장자리에 남았다. 명세 「행성 터치시 화면 중심 전환」.
testWidgets('고른 행성은 공전·끌기 회전 중에도 화면 가운데에 머문다', (tester) async {
tester.view.physicalSize = const Size(1200, 2000);
tester.view.devicePixelRatio = 2.0;
addTearDown(tester.view.reset);
await _pump(tester, _galaxy());
final viewer = find.byType(InteractiveViewer);
final origin = tester.getTopLeft(viewer);
final a = await tester.startGesture(origin + const Offset(4, 4));
final b = await tester.startGesture(
origin + const Offset(24, 24),
pointer: 7,
final mid = tester.getCenter(viewer);
final planet = find.byKey(const ValueKey('newjeans'));
await tester.tap(planet);
for (var i = 0; i < 25; i++) {
await tester.pump(const Duration(milliseconds: 120)); // 3초 공전
}
expect((tester.getCenter(planet) - mid).distance, lessThan(8));
await tester.fling(viewer, const Offset(-300, 0), 1500);
for (var i = 0; i < 25; i++) {
await tester.pump(const Duration(milliseconds: 120));
}
expect(
(tester.getCenter(planet) - mid).distance,
lessThan(8),
reason: '관성 회전 뒤에도 고른 행성이 가운데',
);
for (var i = 1; i <= 10; i++) {
await b.moveTo(origin + Offset(24.0 + i * 32, 24.0 + i * 32));
await a.moveTo(origin + Offset(4.0 + i * 20, 4.0 + i * 20));
await tester.pump();
});
// 10/5 실기기 — HUD 카드 「>」를 눌러도 행성 상세로 가지 않았다.
// 명세 「HUD 터치시 FPI 상세 페이지 이동」.
testWidgets('HUD 카드의 화살표를 누르면 고른 행성의 상세로 간다', (tester) async {
tester.view.physicalSize = const Size(1200, 2000);
tester.view.devicePixelRatio = 2.0;
addTearDown(tester.view.reset);
await _pump(tester, _galaxy());
await tester.tap(find.byKey(const ValueKey('newjeans')));
for (var i = 0; i < 10; i++) {
await tester.pump(const Duration(milliseconds: 120));
}
await a.up();
await b.up();
await tester.tap(find.byIcon(Icons.chevron_right));
await _settle(tester);
expect(find.text('RANK'), findsNothing);
expect(find.byType(PlanetDetailScreen), findsOneWidget);
});
// 10/4 실기기 — 가로로 끌면 궤도가 돌지 않고 장면이 통째로 밀려 빈 화면이 됐다.
testWidgets('가로로 끌면 장면은 제자리에서 궤도가 돌고, 손을 떼도 관성으로 더 돈다', (tester) async {
await _pump(tester, _galaxy());
final viewer = tester.widget<InteractiveViewer>(