frindlymap/lib/modules/ui/src/screens/circle_hub_screen.dart

93 lines
3.8 KiB
Dart

import 'package:flutter/material.dart';
import 'package:friendly_map/modules/app/app.dart';
import 'package:friendly_map/modules/core/core.dart';
import '../theme.dart';
import '../widgets/async_view.dart';
import '../widgets/common.dart';
import '../widgets/pin_dialog.dart';
import '../widgets/ring_view.dart';
import 'circle_group_screen.dart';
import 'group_detail_screen.dart';
import 'person_screen.dart';
class _Data {
const _Data(this.hub, this.me);
final CircleHub hub;
final String me;
}
/// 학교·회사 원형 보기: 나를 가운데 두고 둘레에 초·중·고·대(또는 회사들)를 놓고,
/// 그 옆에 대화·통화가 많은 가까운 사람을 보여 준다. 칸을 누르면 그 칸 사람들이 원 모양으로 펼쳐진다.
class CircleHubScreen extends StatelessWidget {
const CircleHubScreen({super.key, required this.rootId});
final String rootId;
@override
Widget build(BuildContext context) {
return AsyncView<_Data>(
load: (a) async => _Data(await a.circles.hub(rootId), (await a.profile.me())?.name ?? '나'),
builder: (context, d) {
final root = d.hub.root;
if (root == null) return Scaffold(appBar: AppBar(), body: const EmptyNote('지워진 그룹이에요.'));
final kind = root.group.kind;
final color = Pal.ofKind(kind);
if (!root.open) {
return Scaffold(
appBar: AppBar(title: Text(root.group.name)),
body: Center(
child: Column(mainAxisSize: MainAxisSize.min, children: [
const Icon(Icons.lock, size: 48, color: Pal.muted),
const SizedBox(height: 12),
FilledButton(onPressed: () => openGroup(context, root), child: const Text('비밀번호로 열기')),
]),
),
);
}
final levels = d.hub.levels;
return Scaffold(
appBar: AppBar(
title: Text(root.group.name),
actions: [IconButton(tooltip: '목록으로 보기', onPressed: () => pushPage(context, GroupDetailScreen(groupId: rootId)), icon: const Icon(Icons.list))],
),
body: ListView(padding: const EdgeInsets.only(bottom: 32), children: [
if (levels.isEmpty)
const EmptyNote('아래에 칸이 없어요.\n목록으로 보기에서 하위 그룹을 만들어 보세요.')
else
RingView(
center: MeDot(d.me),
rings: [
[
for (final l in levels)
RingDot(
label: l.view.group.name,
sub: '${l.count}명',
color: l.count == 0 ? Pal.muted : color,
faded: l.count == 0,
onTap: () => pushPage(context, CircleGroupScreen(groupId: l.view.group.id)),
),
],
],
),
const SectionHeader('가까운 사람'),
if (d.hub.closest.isEmpty) const EmptyNote('대화나 통화가 쌓이면 가까운 사람이 여기 보여요.'),
for (final c in d.hub.closest)
ListTile(
leading: Avatar(c.person.name, size: 40, color: color),
title: Text(c.person.name),
subtitle: Text([
if (c.subgroup != null) c.subgroup!,
if (kind == CardKinds.school && c.cohortDiff != null) c.cohort,
if (kind == CardKinds.company && c.position != null) c.position!,
].join(' · ')),
trailing: c.score > 0 ? Text('${c.score}', style: const TextStyle(color: Pal.accent, fontWeight: FontWeight.w700)) : null,
onTap: () => pushPage(context, PersonScreen(personId: c.person.id)),
),
]),
);
},
);
}
}