Files
chat-flutter/lib/component/component_contact.dart
2025-09-12 20:35:12 +08:00

289 lines
7.3 KiB
Dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:demo/config/app_theme.dart';
import 'package:demo/component/component_common.dart';
import 'package:grouped_list/grouped_list.dart';
import 'package:lpinyin/lpinyin.dart';
import 'package:tdesign_flutter/tdesign_flutter.dart';
// 通讯录组件
class ComponentContact extends StatefulWidget {
// 选中文字
final String mark;
// 数据列表
final List<ContactModel> dataList;
// 选中列表
final List<String>? selectList;
// 单击事件
final Function(ContactModel model)? onTap;
// 多选事件
final Function(List<String> selectList)? onSelect;
const ComponentContact({
super.key,
this.mark = '选中',
required this.dataList,
this.selectList,
this.onTap,
this.onSelect,
});
@override
createState() => _ComponentContactState();
}
class _ComponentContactState extends State<ComponentContact> {
List<ContactModel> displayList = [];
List<String> selectList = [];
@override
void initState() {
super.initState();
displayList = widget.dataList;
selectList = widget.selectList ?? [];
}
@override
Widget build(BuildContext context) {
// 处理参数
List<ContactModel> dataList = _handle(displayList);
return GestureDetector(
behavior: HitTestBehavior.translucent,
onPanDown: (details) {
FocusScope.of(context).requestFocus(FocusNode());
},
child: Column(
children: [
_buildSearch(),
Expanded(
child: _buildList(dataList),
),
],
),
);
}
// 搜索框
_buildSearch() {
return TDSearchBar(
placeHolder: '请输内容',
onTextChanged: (values) {
setState(() {
// 过滤数据
displayList = widget.dataList.where((data) {
if (data.select) {
return true;
}
String nickname = data.nickname.toLowerCase();
String extend = data.extend.toLowerCase();
String value = values.toLowerCase();
return nickname.contains(value) || extend.contains(value);
}).toList();
});
},
);
}
_buildList(List<ContactModel> dataList) {
return GroupedListView(
// 数据列表
elements: dataList,
// 分组类型
groupBy: (element) {
return element.tag;
},
// 分组排序
groupComparator: (value1, value2) {
// 排序
if (value1 == "#" || value2 == "#") {
return -1;
}
// 选中
if (value1 == widget.mark || value2 == widget.mark) {
return -1;
}
return value1.compareTo(value2);
},
// 分组间隔
groupSeparatorBuilder: (value) {
return _buildTag(value);
},
// 单条排序
itemComparator: (item1, item2) {
return item1.pinyin.compareTo(item2.pinyin);
},
// 单条数据
indexedItemBuilder: (context, element, index) {
bool divider = true;
if (index + 1 < dataList.length) {
divider = dataList[index].tag == dataList[index + 1].tag;
}
return _buildItem(element, divider);
},
);
}
// 分组标签
_buildTag(String value) {
return Container(
height: 40,
width: context.width,
padding: const EdgeInsets.only(left: 16.0),
color: const Color(0xFFF3F4F5),
alignment: Alignment.centerLeft,
child: Text(
value,
softWrap: false,
style: const TextStyle(
fontSize: 14.0,
color: Color(0xFF666666),
),
),
);
}
// 处理参数
List<ContactModel> _handle(List<ContactModel> displayList) {
List<ContactModel> dataList = [];
// 处理数据
if (displayList.isNotEmpty) {
for (int i = 0, length = displayList.length; i < length; i++) {
String nickname = displayList[i].nickname;
String pinyin = PinyinHelper.getPinyinE(nickname);
String tag = pinyin.substring(0, 1).toUpperCase();
if (displayList[i].select) {
tag = widget.mark;
}
// 其他
else if (!RegExp("[A-Z]").hasMatch(tag)) {
tag = '#';
}
displayList[i].tag = tag;
displayList[i].pinyin = pinyin;
}
// A-Z sort.
sortTag(displayList);
// 放入列表
dataList.addAll(displayList);
}
setState(() {});
return dataList;
}
// 排序
void sortTag(List<ContactModel> dataList) {
if (dataList.isNotEmpty) {
dataList.sort((a, b) {
// 所有人
if (a.userId == "0") {
return -1;
}
// 选中
if (a.tag == widget.mark) {
return -1;
}
// 选中
if (b.tag == "#") {
return -1;
}
// 选中
if (a.tag == "#") {
return 1;
}
// 选中
if (b.tag == widget.mark) {
return 1;
}
int sort = a.tag.compareTo(b.tag);
if (sort == 0) {
return a.userId.compareTo(b.userId);
}
return sort;
});
}
}
// 详情
_buildItem(ContactModel model, bool divider) {
String portrait = model.portrait;
String nickname = model.nickname;
String userId = model.userId;
String extend = model.extend;
return Column(
children: [
ListTile(
leading: ComponentCommon.showAvatar(
portrait,
size: 40,
),
title: Text(nickname),
subtitle: extend.isEmpty ? null : Text(extend),
trailing: widget.onSelect != null
? Checkbox(
value: model.select,
fillColor: WidgetStateColor.resolveWith((states) {
// 开启状态
if (states.contains(WidgetState.selected)) {
// 选中
if (model.select) {
return AppTheme.color;
}
// 未选中
return Colors.grey;
}
// 关闭状态
return Colors.white;
}),
onChanged: (value) {
model.select = value!;
if (value) {
selectList.add(userId);
} else {
selectList.remove(userId);
}
setState(() {});
widget.onSelect?.call(selectList);
},
)
: null,
onTap: () {
if (widget.onTap != null) {
widget.onTap?.call(
ContactModel(
userId: userId,
nickname: nickname,
portrait: portrait,
),
);
}
},
),
if (divider) ComponentCommon.divider()
],
);
}
}
class ContactModel {
String userId;
String nickname;
String portrait;
String pinyin;
bool select;
String extend;
String tag;
ContactModel({
required this.userId,
required this.nickname,
required this.portrait,
this.select = false,
this.extend = '',
String remark = '',
this.tag = '',
this.pinyin = '',
}) {
if (remark.isNotEmpty) {
nickname = remark;
}
}
}