feat(apps): update UI screens and shared components

- Update home screen with new composer and interactions
- Update settings screens with new profile flow
- Update calendar share dialog
- Update contacts screen
- Add new shared widgets: confirm_sheet, phone_prefix_selector
- Add new formatters: phone_display_formatter
- Update tests for modified components
This commit is contained in:
qzl
2026-03-19 18:43:08 +08:00
parent f0af44d840
commit 8d4a14150b
24 changed files with 868 additions and 989 deletions
@@ -18,7 +18,7 @@ class AddContactScreen extends StatefulWidget {
class _AddContactScreenState extends State<AddContactScreen> {
final _nameController = TextEditingController();
final _emailController = TextEditingController();
final _phoneController = TextEditingController();
final _remarkController = TextEditingController();
bool get isEditing => widget.contactId != null;
@@ -26,7 +26,7 @@ class _AddContactScreenState extends State<AddContactScreen> {
@override
void dispose() {
_nameController.dispose();
_emailController.dispose();
_phoneController.dispose();
_remarkController.dispose();
super.dispose();
}
@@ -35,7 +35,9 @@ class _AddContactScreenState extends State<AddContactScreen> {
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.surfaceSecondary,
resizeToAvoidBottomInset: false,
body: SafeArea(
maintainBottomViewPadding: true,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
@@ -122,10 +124,10 @@ class _AddContactScreenState extends State<AddContactScreen> {
AppInput(label: '昵称', hint: '请输入昵称', controller: _nameController),
const SizedBox(height: 14),
AppInput(
label: '邮箱',
hint: '请输入邮箱',
controller: _emailController,
keyboardType: TextInputType.emailAddress,
label: '手机号',
hint: '+86 请输入 11 位手机号',
controller: _phoneController,
keyboardType: TextInputType.phone,
),
const SizedBox(height: 14),
AppInput(
@@ -152,10 +154,10 @@ class _AddContactScreenState extends State<AddContactScreen> {
void _handleConfirm() {
final name = _nameController.text.trim();
final email = _emailController.text.trim();
final phone = _phoneController.text.trim();
if (name.isEmpty || email.isEmpty) {
Toast.show(context, '请填写昵称和邮箱', type: ToastType.warning);
if (name.isEmpty || phone.isEmpty) {
Toast.show(context, '请填写昵称和手机号', type: ToastType.warning);
return;
}
@@ -63,21 +63,11 @@ class _ContactsScreenState extends State<ContactsScreen> {
}
}
bool _isValidEmail(String email) {
final emailRegex = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,}$');
return emailRegex.hasMatch(email);
}
Future<void> _onSearch() async {
final query = _searchController.text.trim();
if (query.isEmpty) {
Toast.show(context, '请输入邮箱地址', type: ToastType.warning);
return;
}
if (!_isValidEmail(query)) {
Toast.show(context, '请输入有效的邮箱地址', type: ToastType.warning);
Toast.show(context, '请输入用户名或手机号', type: ToastType.warning);
return;
}
@@ -265,7 +255,9 @@ class _ContactsScreenState extends State<ContactsScreen> {
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.surfaceSecondary,
resizeToAvoidBottomInset: false,
body: SafeArea(
maintainBottomViewPadding: true,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
@@ -323,7 +315,7 @@ class _ContactsScreenState extends State<ContactsScreen> {
controller: _searchController,
focusNode: _searchFocusNode,
decoration: const InputDecoration(
hintText: '输入邮箱搜索用户',
hintText: '输入用户名或手机号',
hintStyle: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w500,
@@ -341,7 +333,7 @@ class _ContactsScreenState extends State<ContactsScreen> {
),
),
style: const TextStyle(fontSize: 13),
keyboardType: TextInputType.emailAddress,
keyboardType: TextInputType.text,
textInputAction: TextInputAction.search,
onSubmitted: (_) => _onSearch(),
onChanged: (value) {
@@ -562,7 +554,7 @@ class _ContactsScreenState extends State<ContactsScreen> {
),
const SizedBox(height: 4),
const Text(
'搜索邮箱添加好友开始聊天吧',
'搜索手机号添加好友开始聊天吧',
style: TextStyle(fontSize: 13, color: AppColors.slate400),
),
],