팬덤 탈퇴 · 성운 창립자 권한 승계 · 대표 팬덤 자동 지정

This commit is contained in:
Sn-Kinos
2026-10-05 17:41:20 +09:00
parent 8a1b824307
commit 3a3be4c3d3
21 changed files with 229 additions and 54 deletions
+6
View File
@@ -329,6 +329,9 @@ abstract interface class PlanetRepository {
/// 이 행성/성운에 가입 — `fn-fandom-join`. 이미 멤버면 서버가 아무것도 하지 않는다.
Future<void> join();
/// 탈퇴 — `fn-fandom-leave`. 대표 팬덤 자동 지정(C-101) · 성운 창립자 승계(C-100)는 서버가 한다.
Future<void> leave();
/// 명세 — *최초 5개, 스크롤 시 5개씩 호출*.
Future<List<LoungePost>> morePosts({required int offset, int limit = 5});
@@ -391,6 +394,9 @@ class SamplePlanetRepository implements PlanetRepository {
@override
Future<void> join() async {}
@override
Future<void> leave() async {}
@override
Future<PlanetHistoryPage> history({String? cursor, bool personal = false}) async => const PlanetHistoryPage(items: []);
@override
@@ -6,6 +6,7 @@ import '../../core/data/backend.dart' show BackendException;
import '../../core/data/planet_visual_state.dart';
import '../../core/theme/tokens.dart';
import '../../core/ui/app_dialog.dart';
import '../../core/ui/app_icons.dart';
import '../eclipse/eclipse_data.dart';
import '../eclipse/widgets/eclipse_banner.dart';
@@ -74,6 +75,30 @@ class _PlanetDetailScreenState extends State<PlanetDetailScreen> {
}
}
/// 「가입중」 알약 → 탈퇴 시트 → 확인 창 — Figma `343:213428`(탈퇴하기 · 취소) ·
/// `343:213582`(행성 탈퇴를 할까요?). 대표 팬덤 자동 지정 · 성운 창립자 승계는 서버 몫이다(C-100 · C-101).
void _leave() => showActionSheet(context, [
ActionSheetItem(context.l10n.planetLeave, () async {
final ok = await showConfirmDialog(
context,
context.l10n.planetLeaveConfirmTitle,
body: context.l10n.planetLeaveConfirmBody,
confirmLabel: context.l10n.commonConfirm,
);
if (!ok) return;
try {
await widget.repository.leave();
if (mounted) {
setState(() { _detail = widget.repository.load(nebula: widget.nebula); });
}
} on BackendException catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(e.message)));
}
}
}),
]);
@override
Widget build(BuildContext context) => FutureBuilder<PlanetDetail>(
future: _detail,
@@ -127,7 +152,7 @@ class _PlanetDetailScreenState extends State<PlanetDetailScreen> {
ownerName: d.ownerName,
ownerPhoto: d.ownerPhoto,
joined: d.joined,
onJoin: d.joined ? null : _join,
onJoin: d.joined ? _leave : _join,
onOpenHistory: () => Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (_) => PlanetHistoryScreen(
@@ -103,6 +103,9 @@ class FirestorePlanetRepository implements PlanetRepository {
@override
Future<void> join() => _backend.call('fnFandomJoin', {'fandomId': fandomId});
@override
Future<void> leave() => _backend.call('fnFandomLeave', {'fandomId': fandomId});
@override
Future<PlanetDetail> load({required bool nebula}) async {
final db = _backend.db;
@@ -43,7 +43,7 @@ class PlanetDetailHero extends StatelessWidget {
final bool joined;
final VoidCallback? onHeroParticipate;
/// 「가입하기」 알약을 눌렀을 때. 이미 가입했으면 null 이고 알약은 상태만 보인다.
/// 알약을 눌렀을 때 — 「가입하기」면 가입, 「가입중」이면 탈퇴 시트. null 이면 상태만 보인다.
final VoidCallback? onJoin;
/// 성운 상세(`373:442708`)는 규모 칩과 FPI 줄이 없다.