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(); 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), ], ), ), ), ); } }