Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai>
183 lines
5.5 KiB
Dart
183 lines
5.5 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:openim_common/openim_common.dart';
|
|
|
|
import '../../company/brand/app_tokens.dart';
|
|
import '../../company/ui/state_views.dart';
|
|
import 'contacts_logic.dart';
|
|
|
|
class ContactsPage extends StatelessWidget {
|
|
final logic = Get.find<ContactsLogic>();
|
|
|
|
ContactsPage({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
backgroundColor: AppColors.pageBg,
|
|
appBar: AppBar(
|
|
title: const Text('通讯录'),
|
|
actions: [
|
|
IconButton(
|
|
onPressed: logic.addContacts,
|
|
icon: const Icon(Icons.person_add_alt,
|
|
size: AppIconSize.md, color: AppColors.textPrimary),
|
|
),
|
|
],
|
|
),
|
|
body: Obx(() {
|
|
if (logic.loading.value) {
|
|
return const CompanyLoadingView();
|
|
}
|
|
if (logic.loadFailed.value) {
|
|
return CompanyFailView(onRetry: logic.reload);
|
|
}
|
|
final grouped = logic.groupedColleagues;
|
|
return CustomScrollView(
|
|
slivers: [
|
|
SliverToBoxAdapter(
|
|
child: Column(
|
|
children: [
|
|
_entry(
|
|
icon: Icons.person_add_alt,
|
|
label: '新的同事',
|
|
count: logic.friendApplicationCount,
|
|
onTap: logic.newFriend,
|
|
),
|
|
_entry(
|
|
icon: Icons.group_outlined,
|
|
label: '我的群聊',
|
|
count: logic.groupApplicationCount,
|
|
onTap: logic.myGroup,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
if (logic.colleagues.isEmpty)
|
|
const SliverFillRemaining(
|
|
hasScrollBody: false,
|
|
child: CompanyEmptyView(
|
|
icon: Icons.person_outline,
|
|
title: '暂时没有同事',
|
|
subtitle: '点右上角添加同事',
|
|
),
|
|
)
|
|
else
|
|
for (final entry in grouped.entries) ...[
|
|
SliverToBoxAdapter(child: _groupHeader(entry.key)),
|
|
SliverList(
|
|
delegate: SliverChildBuilderDelegate(
|
|
(_, index) => _colleagueRow(entry.value[index]),
|
|
childCount: entry.value.length,
|
|
),
|
|
),
|
|
],
|
|
],
|
|
);
|
|
}),
|
|
);
|
|
}
|
|
|
|
Widget _groupHeader(String name) {
|
|
return Container(
|
|
height: 28,
|
|
color: AppColors.chatBg,
|
|
alignment: Alignment.centerLeft,
|
|
padding: const EdgeInsets.symmetric(horizontal: AppGap.x4),
|
|
child: Text(
|
|
name,
|
|
style: const TextStyle(
|
|
fontSize: AppFont.small, color: AppColors.textSecondary),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _colleagueRow(ColleagueRow row) {
|
|
return InkWell(
|
|
onTap: () => logic.openColleague(row),
|
|
splashColor: AppColors.chatBg,
|
|
highlightColor: AppColors.chatBg,
|
|
child: SizedBox(
|
|
height: 64,
|
|
child: Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: AppGap.x4),
|
|
child: Row(
|
|
children: [
|
|
AvatarView(
|
|
url: row.faceURL,
|
|
text: row.nickname,
|
|
width: 48,
|
|
height: 48,
|
|
),
|
|
const SizedBox(width: AppGap.x3),
|
|
Expanded(
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
row.nickname,
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: const TextStyle(
|
|
fontSize: AppFont.body,
|
|
color: AppColors.textPrimary),
|
|
),
|
|
if (row.subtitle.isNotEmpty)
|
|
Text(
|
|
row.subtitle,
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: const TextStyle(
|
|
fontSize: AppFont.sub,
|
|
color: AppColors.textSecondary),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _entry({
|
|
required IconData icon,
|
|
required String label,
|
|
int count = 0,
|
|
required VoidCallback onTap,
|
|
}) {
|
|
return InkWell(
|
|
onTap: onTap,
|
|
child: SizedBox(
|
|
height: 56,
|
|
child: Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: AppGap.x4),
|
|
child: Row(
|
|
children: [
|
|
Container(
|
|
width: 40,
|
|
height: 40,
|
|
decoration: BoxDecoration(
|
|
color: AppColors.primaryActive,
|
|
borderRadius: BorderRadius.circular(AppRadius.control),
|
|
),
|
|
alignment: Alignment.center,
|
|
child:
|
|
Icon(icon, size: AppIconSize.sm, color: AppColors.primary),
|
|
),
|
|
const SizedBox(width: AppGap.x3),
|
|
Text(label,
|
|
style: const TextStyle(
|
|
fontSize: AppFont.body, color: AppColors.textPrimary)),
|
|
const Spacer(),
|
|
if (count > 0) UnreadCountView(count: count),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|