가입 약관 동의 기록 · 서비스 탈퇴 · 온보딩 6단계 · Coach Mark
This commit is contained in:
@@ -7,8 +7,10 @@ import '../theme/tokens.dart';
|
||||
import '../ui/app_icons.dart';
|
||||
import '../../features/auth/auth_repository.dart';
|
||||
import '../../features/auth/login_screen.dart';
|
||||
import '../../features/auth/onboarding_screens.dart';
|
||||
import '../../features/auth/signup_screens.dart';
|
||||
import '../../features/galaxy/galaxy_home_screen.dart';
|
||||
import '../../features/home/coach_mark.dart';
|
||||
import '../../features/home/home_screen.dart';
|
||||
import '../../features/inside/inside_screen.dart';
|
||||
import '../../features/my/my_screen.dart';
|
||||
@@ -79,11 +81,15 @@ List<AppTab> visibleTabs(FeatureFlags flags) => [
|
||||
|
||||
const String loginPath = '/login';
|
||||
const String signupCompletePath = '/welcome';
|
||||
const String introPath = '/intro';
|
||||
const String onboardingPath = '/onboarding';
|
||||
|
||||
/// 5탭 셸 라우트 + 온보딩(로그인) 라우트.
|
||||
/// 5탭 셸 라우트 + 온보딩 라우트.
|
||||
///
|
||||
/// 온보딩 나머지 화면(S-A-INTRO · S-A-TERMS · S-A-PROFILE · S-A-ARTIST ·
|
||||
/// S-A-PLANET-NEW · S-A-PERMS)은 3주차 범위라 아직 라우트가 없다.
|
||||
/// 온보딩 6단계(10/3 통합회신 1항): ① 소개 3장([introPath], 첫 실행 · 로그인 전) → 로그인 →
|
||||
/// ②~⑥ 약관 · 프로필 · 관심 아티스트 · 행성 가입/성운 생성 · 권한 안내([onboardingPath]) →
|
||||
/// 가입 완료([signupCompletePath]) → HOME(Coach Mark). 서버에 약관 동의가 없는 계정은
|
||||
/// 「로그인」 버튼으로 들어왔어도 셸로 가지 못하고 [onboardingPath] 로 간다.
|
||||
GoRouter buildRouter(AuthRepository auth, {Repositories? repositories}) {
|
||||
// 저장소 선택은 앱이 뜰 때 한 번만 한다. 탭을 옮길 때마다 다시 만들면
|
||||
// Firestore 커서 같은 화면 상태가 매번 초기화된다.
|
||||
@@ -95,11 +101,23 @@ GoRouter buildRouter(AuthRepository auth, {Repositories? repositories}) {
|
||||
refreshListenable: auth,
|
||||
redirect: (context, state) {
|
||||
final at = state.matchedLocation;
|
||||
if (!auth.isSignedIn) return at == loginPath ? null : loginPath;
|
||||
if (!auth.isSignedIn) {
|
||||
final entry = auth.introPending ? introPath : loginPath;
|
||||
return at == entry ? null : entry;
|
||||
}
|
||||
if (auth.onboarding != OnboardingGate.done) {
|
||||
return at == onboardingPath ? null : onboardingPath;
|
||||
}
|
||||
if (auth.justSignedUp)
|
||||
return at == signupCompletePath ? null : signupCompletePath;
|
||||
if (at == loginPath || at == signupCompletePath)
|
||||
if (const [
|
||||
loginPath,
|
||||
signupCompletePath,
|
||||
introPath,
|
||||
onboardingPath,
|
||||
].contains(at)) {
|
||||
return appTabs.first.path;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
routes: [
|
||||
@@ -107,6 +125,24 @@ GoRouter buildRouter(AuthRepository auth, {Repositories? repositories}) {
|
||||
path: loginPath,
|
||||
builder: (_, _) => LoginScreen(auth: auth),
|
||||
),
|
||||
GoRoute(
|
||||
path: introPath,
|
||||
builder: (_, _) => IntroScreen(onDone: auth.finishIntro),
|
||||
),
|
||||
GoRoute(
|
||||
path: onboardingPath,
|
||||
builder: (_, _) => ListenableBuilder(
|
||||
listenable: auth,
|
||||
builder: (_, _) => auth.onboarding == OnboardingGate.checking
|
||||
? const Scaffold(body: Center(child: CircularProgressIndicator()))
|
||||
: OnboardingFlow(
|
||||
auth: auth,
|
||||
repository: repos.onboarding,
|
||||
home: repos.home,
|
||||
push: repos.push,
|
||||
),
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
path: signupCompletePath,
|
||||
builder: (_, _) => SignupCompleteScreen(onStart: auth.finishSignup),
|
||||
@@ -230,7 +266,13 @@ class AppShell extends StatelessWidget {
|
||||
),
|
||||
destinations: [
|
||||
for (final tab in tabs)
|
||||
NavigationDestination(icon: tab.icon, label: tab.label),
|
||||
NavigationDestination(
|
||||
// Coach Mark ② 가 MY 위치를 가리킨다(coach_mark.dart).
|
||||
icon: tab.path == appTabs.last.path
|
||||
? KeyedSubtree(key: coachMyTabKey, child: tab.icon)
|
||||
: tab.icon,
|
||||
label: tab.label,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user