온보딩 닉네임을 소셜 계정 표시 이름으로 미리 채움
This commit is contained in:
@@ -52,6 +52,9 @@ class Backend {
|
||||
/// 로그인 계정 이메일. 닉네임이 없을 때 화면이 부르는 이름의 재료다.
|
||||
String? get email => _auth.currentUser?.email;
|
||||
|
||||
/// 로그인 계정의 제공자 표시 이름(Kakao 닉네임 · Google/LINE 이름 · Apple fullName). 온보딩 닉네임 기본값 재료다.
|
||||
String? get providerDisplayName => _auth.currentUser?.displayName;
|
||||
|
||||
/// 로그인 필수 경로에서 UID 를 강제로 얻는다.
|
||||
String get requireUid {
|
||||
final value = uid;
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import 'package:flutter/widgets.dart' show StringCharacters;
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
|
||||
import '../../core/data/backend.dart';
|
||||
import '../my/my_data.dart'
|
||||
show nicknameMaxLength, nicknameMinLength, nicknameReserved;
|
||||
|
||||
/// 온보딩 6단계(10/3 통합회신 1항 · 해석 확인 Q-OB-02 A · FR-CMN-03~08)가 서버와 주고받는 것.
|
||||
abstract interface class OnboardingRepository {
|
||||
@@ -41,6 +44,16 @@ class OnboardingFandom {
|
||||
final bool nebula;
|
||||
}
|
||||
|
||||
/// 소셜 계정 표시 이름을 닉네임 칸 기본값으로 — 해석 확인 Q-E11 임시값.
|
||||
/// 닉네임 규칙(2~20자 · 사칭 금지어)에 걸리면 빈칸이다. 길이는 글자(grapheme) 기준.
|
||||
String suggestedNickname(String? providerName) {
|
||||
final n = (providerName ?? '').trim();
|
||||
final len = n.characters.length;
|
||||
return len < nicknameMinLength || len > nicknameMaxLength || nicknameReserved(n)
|
||||
? ''
|
||||
: n;
|
||||
}
|
||||
|
||||
/// 계정이 온보딩을 거쳐야 하는가 — 서버에 가입 약관 동의(`termsAgreedAt`)가 없으면 그렇다.
|
||||
/// 트리거가 아직 사용자 문서를 만들지 않았어도(갓 생성된 계정) 그렇다.
|
||||
Future<bool> needsOnboardingFirestore(String uid) async {
|
||||
@@ -67,7 +80,9 @@ class FirestoreOnboardingRepository implements OnboardingRepository {
|
||||
final nickname = data['nickname'];
|
||||
final country = data['countryCode'];
|
||||
return (
|
||||
nickname: nickname is String ? nickname : '',
|
||||
nickname: nickname is String && nickname.isNotEmpty
|
||||
? nickname
|
||||
: suggestedNickname(_backend.providerDisplayName),
|
||||
country: country is String && country.isNotEmpty ? country : null,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,14 @@ abstract interface class CredentialProvider {
|
||||
}
|
||||
|
||||
/// 자격증명 한 벌과, 판정에 쓸 그 계정의 이메일.
|
||||
typedef SocialCredential = ({fb.AuthCredential credential, String? email});
|
||||
///
|
||||
/// [name] 은 제공자가 자격증명과 함께만 주는 표시 이름(Apple fullName — 최초 인가 때만). Firebase 가
|
||||
/// 이 값을 계정 이름으로 옮기지 않아, 로그인 직후 우리가 계정에 써 둔다(온보딩 닉네임 기본값).
|
||||
typedef SocialCredential = ({
|
||||
fb.AuthCredential credential,
|
||||
String? email,
|
||||
String? name,
|
||||
});
|
||||
|
||||
/// Google 로그인 — 실 코드 경로.
|
||||
///
|
||||
@@ -67,6 +74,7 @@ final class GoogleSignInProvider
|
||||
return (
|
||||
credential: fb.GoogleAuthProvider.credential(idToken: idToken),
|
||||
email: account.email,
|
||||
name: null,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -160,6 +168,10 @@ final class AppleSignInProvider
|
||||
// Apple 은 **최초 인가 때만** 이메일을 준다. 두 번째부터는 null 이라
|
||||
// 「동일 이메일만 연동」 판정을 할 수 없다 — 그때는 통과시킨다.
|
||||
email: credential.email,
|
||||
name: [credential.givenName, credential.familyName]
|
||||
.whereType<String>()
|
||||
.where((part) => part.isNotEmpty)
|
||||
.join(' '),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -179,6 +191,10 @@ final class AppleSignInProvider
|
||||
final result = await fb.FirebaseAuth.instance.signInWithCredential(
|
||||
obtained.credential,
|
||||
);
|
||||
final name = obtained.name;
|
||||
if (name != null && name.isNotEmpty && (result.user?.displayName ?? '').isEmpty) {
|
||||
await result.user?.updateDisplayName(name);
|
||||
}
|
||||
return AuthSucceeded(_toAccount(result.user, provider));
|
||||
} on apple.SignInWithAppleAuthorizationException catch (error) {
|
||||
if (error.code == apple.AuthorizationErrorCode.canceled) {
|
||||
|
||||
Reference in New Issue
Block a user