refactor(apps): 主题系统迁移至 ColorScheme + 扩展架构并支持 Dark Mode
This commit is contained in:
@@ -34,8 +34,9 @@ class _AddContactScreenState extends State<AddContactScreen> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
return Scaffold(
|
||||
backgroundColor: AppColors.surfaceSecondary,
|
||||
backgroundColor: colorScheme.surfaceContainerLow,
|
||||
resizeToAvoidBottomInset: false,
|
||||
body: SafeArea(
|
||||
maintainBottomViewPadding: true,
|
||||
@@ -73,6 +74,7 @@ class _AddContactScreenState extends State<AddContactScreen> {
|
||||
}
|
||||
|
||||
Widget _buildConfirmButton() {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
return SizedBox(
|
||||
width: AppSpacing.xxl * 2,
|
||||
height: AppSpacing.xxl * 2,
|
||||
@@ -80,47 +82,45 @@ class _AddContactScreenState extends State<AddContactScreen> {
|
||||
onPressed: _handleConfirm,
|
||||
style: TextButton.styleFrom(
|
||||
padding: const EdgeInsets.all(AppSpacing.none),
|
||||
backgroundColor: AppColors.surfaceInfo,
|
||||
backgroundColor: colorScheme.primaryContainer,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(AppRadius.full),
|
||||
side: const BorderSide(color: AppColors.borderQuaternary),
|
||||
side: BorderSide(color: colorScheme.outlineVariant),
|
||||
),
|
||||
),
|
||||
child: const Icon(
|
||||
child: Icon(
|
||||
Icons.check,
|
||||
size: AppSpacing.lg,
|
||||
color: AppColors.blue600,
|
||||
color: colorScheme.primary,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAvatarSection() {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
return Center(
|
||||
child: Container(
|
||||
width: 72,
|
||||
height: 72,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.surfaceInfoLight,
|
||||
color: colorScheme.primaryContainer.withValues(alpha: 0.45),
|
||||
borderRadius: BorderRadius.circular(36),
|
||||
border: Border.all(color: Colors.transparent),
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.person_outline,
|
||||
size: 24,
|
||||
color: AppColors.slate400,
|
||||
border: Border.all(color: colorScheme.surface.withValues(alpha: 0)),
|
||||
),
|
||||
child: Icon(Icons.person_outline, size: 24, color: colorScheme.outline),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildFormCard() {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(14),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.white,
|
||||
color: colorScheme.surface,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: Border.all(color: AppColors.messageCardBorder),
|
||||
border: Border.all(color: colorScheme.outlineVariant),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
@@ -149,12 +149,13 @@ class _AddContactScreenState extends State<AddContactScreen> {
|
||||
}
|
||||
|
||||
Widget _buildDeleteRow() {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: AppSpacing.sm),
|
||||
child: LinkButton(
|
||||
text: context.l10n.contactDelete,
|
||||
onTap: _handleDelete,
|
||||
foregroundColor: AppColors.red600,
|
||||
foregroundColor: colorScheme.error,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -177,6 +178,7 @@ class _AddContactScreenState extends State<AddContactScreen> {
|
||||
}
|
||||
|
||||
void _handleDelete() {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
@@ -195,7 +197,7 @@ class _AddContactScreenState extends State<AddContactScreen> {
|
||||
},
|
||||
child: Text(
|
||||
context.l10n.commonDelete,
|
||||
style: const TextStyle(color: AppColors.red600),
|
||||
style: TextStyle(color: colorScheme.error),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -2,13 +2,13 @@ import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import '../../../../app/di/injection.dart';
|
||||
import '../../../../core/l10n/l10n.dart';
|
||||
import '../../../../data/models/user_profile.dart';
|
||||
import '../../../../core/theme/design_tokens.dart';
|
||||
import '../../../../shared/widgets/app_loading_indicator.dart';
|
||||
import '../../../../shared/widgets/toast/index.dart';
|
||||
import '../../../../shared/widgets/app_button.dart';
|
||||
import '../../../../shared/widgets/back_title_page_header.dart';
|
||||
import '../../../contacts/data/friends_api.dart';
|
||||
import '../../../contacts/data/users/models/user_response.dart';
|
||||
import '../../../contacts/data/users/users_api.dart';
|
||||
|
||||
class ContactsScreen extends StatefulWidget {
|
||||
@@ -24,7 +24,7 @@ class _ContactsScreenState extends State<ContactsScreen> {
|
||||
|
||||
List<FriendResponse> _friends = [];
|
||||
List<FriendRequestResponse> _pendingRequests = [];
|
||||
List<UserResponse> _searchResults = [];
|
||||
List<UserProfile> _searchResults = [];
|
||||
bool _isLoading = true;
|
||||
bool _isSearching = false;
|
||||
bool _hasSearched = false;
|
||||
@@ -142,13 +142,16 @@ class _ContactsScreenState extends State<ContactsScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
void _showAddFriendDialog(UserResponse user) {
|
||||
void _showAddFriendDialog(UserProfile user) {
|
||||
final controller = TextEditingController();
|
||||
showModalBottomSheet<void>(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
backgroundColor: Colors.transparent,
|
||||
backgroundColor: Theme.of(
|
||||
context,
|
||||
).colorScheme.surface.withValues(alpha: 0),
|
||||
builder: (sheetContext) {
|
||||
final colorScheme = Theme.of(sheetContext).colorScheme;
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.of(sheetContext).viewInsets.bottom,
|
||||
@@ -164,8 +167,8 @@ class _ContactsScreenState extends State<ContactsScreen> {
|
||||
AppSpacing.xxl,
|
||||
AppSpacing.lg,
|
||||
),
|
||||
decoration: const BoxDecoration(
|
||||
color: AppColors.white,
|
||||
decoration: BoxDecoration(
|
||||
color: colorScheme.surface,
|
||||
borderRadius: BorderRadius.vertical(
|
||||
top: Radius.circular(AppRadius.xxl),
|
||||
),
|
||||
@@ -180,7 +183,7 @@ class _ContactsScreenState extends State<ContactsScreen> {
|
||||
width: 40,
|
||||
height: AppSpacing.xs,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.slate300,
|
||||
color: colorScheme.outlineVariant,
|
||||
borderRadius: BorderRadius.circular(AppRadius.full),
|
||||
),
|
||||
),
|
||||
@@ -188,23 +191,26 @@ class _ContactsScreenState extends State<ContactsScreen> {
|
||||
const SizedBox(height: AppSpacing.lg),
|
||||
Text(
|
||||
context.l10n.contactsAddSheetTitle(user.username),
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.slate900,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: AppSpacing.sm),
|
||||
Text(
|
||||
context.l10n.contactsAddSheetDesc,
|
||||
style: TextStyle(fontSize: 13, color: AppColors.slate500),
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: AppSpacing.lg),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.slate50,
|
||||
color: colorScheme.surfaceContainerLowest,
|
||||
borderRadius: BorderRadius.circular(AppRadius.lg),
|
||||
border: Border.all(color: AppColors.borderSecondary),
|
||||
border: Border.all(color: colorScheme.outlineVariant),
|
||||
),
|
||||
child: TextField(
|
||||
controller: controller,
|
||||
@@ -215,13 +221,13 @@ class _ContactsScreenState extends State<ContactsScreen> {
|
||||
hintText: context.l10n.contactsAddSheetMessageHint,
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 13,
|
||||
color: AppColors.slate400,
|
||||
color: colorScheme.outline,
|
||||
),
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.all(AppSpacing.lg),
|
||||
counterStyle: TextStyle(
|
||||
fontSize: 11,
|
||||
color: AppColors.slate400,
|
||||
color: colorScheme.outline,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -270,8 +276,9 @@ class _ContactsScreenState extends State<ContactsScreen> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
return Scaffold(
|
||||
backgroundColor: AppColors.surfaceSecondary,
|
||||
backgroundColor: colorScheme.surfaceContainerLow,
|
||||
resizeToAvoidBottomInset: false,
|
||||
body: SafeArea(
|
||||
maintainBottomViewPadding: true,
|
||||
@@ -321,15 +328,16 @@ class _ContactsScreenState extends State<ContactsScreen> {
|
||||
}
|
||||
|
||||
Widget _buildSearchRow() {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
height: 40,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.surfaceTertiary,
|
||||
color: colorScheme.surfaceContainerHigh,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: const Color(0xFFE4EBF7)),
|
||||
border: Border.all(color: colorScheme.outlineVariant),
|
||||
),
|
||||
child: TextField(
|
||||
controller: _searchController,
|
||||
@@ -339,12 +347,12 @@ class _ContactsScreenState extends State<ContactsScreen> {
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColors.slate400,
|
||||
color: colorScheme.outline,
|
||||
),
|
||||
prefixIcon: Icon(
|
||||
Icons.search,
|
||||
size: 16,
|
||||
color: AppColors.slate400,
|
||||
color: colorScheme.outline,
|
||||
),
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(
|
||||
@@ -374,22 +382,22 @@ class _ContactsScreenState extends State<ContactsScreen> {
|
||||
width: 40,
|
||||
height: 40,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF1F7FF),
|
||||
color: colorScheme.primaryContainer.withValues(alpha: 0.4),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: const Color(0xFFD7E6FF)),
|
||||
border: Border.all(color: colorScheme.primaryContainer),
|
||||
),
|
||||
child: _isSearching
|
||||
? const Padding(
|
||||
? Padding(
|
||||
padding: EdgeInsets.all(10),
|
||||
child: AppLoadingIndicator(
|
||||
size: 16,
|
||||
strokeWidth: 2,
|
||||
color: AppColors.blue500,
|
||||
trackColor: AppColors.blue100,
|
||||
color: colorScheme.primary,
|
||||
trackColor: colorScheme.primaryContainer,
|
||||
withContainer: false,
|
||||
),
|
||||
)
|
||||
: const Icon(Icons.search, size: 16, color: AppColors.blue500),
|
||||
: Icon(Icons.search, size: 16, color: colorScheme.primary),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -397,6 +405,7 @@ class _ContactsScreenState extends State<ContactsScreen> {
|
||||
}
|
||||
|
||||
Widget _buildSearchResults() {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
if (!_hasSearched) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
@@ -404,11 +413,11 @@ class _ContactsScreenState extends State<ContactsScreen> {
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(top: 8),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.white,
|
||||
color: colorScheme.surface,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withValues(alpha: 0.08),
|
||||
color: colorScheme.shadow.withValues(alpha: 0.08),
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
@@ -427,7 +436,10 @@ class _ContactsScreenState extends State<ContactsScreen> {
|
||||
child: Center(
|
||||
child: Text(
|
||||
context.l10n.contactsSearchNoUser,
|
||||
style: TextStyle(fontSize: 14, color: AppColors.slate500),
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
@@ -445,17 +457,17 @@ class _ContactsScreenState extends State<ContactsScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSearchResultItem(UserResponse user) {
|
||||
Widget _buildSearchResultItem(UserProfile user) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final isFriend = _friendIds.contains(user.id);
|
||||
final isSent = _sentRequestIds.contains(user.id);
|
||||
final avatarColor = _getAvatarColor(user.id);
|
||||
|
||||
return Container(
|
||||
height: 70,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14),
|
||||
child: Row(
|
||||
children: [
|
||||
_buildAvatar(user.avatarUrl, user.id, avatarColor),
|
||||
_buildAvatar(user.avatarUrl, user.id, colorScheme),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
@@ -464,19 +476,19 @@ class _ContactsScreenState extends State<ContactsScreen> {
|
||||
children: [
|
||||
Text(
|
||||
user.username,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.slate900,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
if (user.bio != null) ...[
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
user.bio!,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: AppColors.slate500,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
@@ -492,16 +504,17 @@ class _ContactsScreenState extends State<ContactsScreen> {
|
||||
}
|
||||
|
||||
Widget _buildAddButton(String userId, bool isFriend, bool isSent) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
if (isFriend) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.slate300,
|
||||
color: colorScheme.surfaceContainerHighest,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Text(
|
||||
context.l10n.contactsStatusAlreadyFriend,
|
||||
style: TextStyle(fontSize: 12, color: AppColors.slate500),
|
||||
style: TextStyle(fontSize: 12, color: colorScheme.onSurfaceVariant),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -510,12 +523,12 @@ class _ContactsScreenState extends State<ContactsScreen> {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.slate300,
|
||||
color: colorScheme.surfaceContainerHighest,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Text(
|
||||
context.l10n.contactsStatusSent,
|
||||
style: TextStyle(fontSize: 12, color: AppColors.slate500),
|
||||
style: TextStyle(fontSize: 12, color: colorScheme.onSurfaceVariant),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -528,21 +541,21 @@ class _ContactsScreenState extends State<ContactsScreen> {
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF1F7FF),
|
||||
color: colorScheme.primaryContainer.withValues(alpha: 0.4),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: const Color(0xFFD7E6FF)),
|
||||
border: Border.all(color: colorScheme.primaryContainer),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(Icons.person_add, size: 14, color: AppColors.blue500),
|
||||
Icon(Icons.person_add, size: 14, color: colorScheme.primary),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
context.l10n.contactsAdd,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColors.blue500,
|
||||
color: colorScheme.primary,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -552,30 +565,31 @@ class _ContactsScreenState extends State<ContactsScreen> {
|
||||
}
|
||||
|
||||
Widget _buildEmptyState() {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(32),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.white,
|
||||
color: colorScheme.surface,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: Border.all(color: const Color(0xFFE3EAF6)),
|
||||
border: Border.all(color: colorScheme.outlineVariant),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
const Icon(Icons.person_outline, size: 48, color: AppColors.slate400),
|
||||
Icon(Icons.person_outline, size: 48, color: colorScheme.outline),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
context.l10n.contactsEmptyTitle,
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColors.slate500,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
context.l10n.contactsEmptyDesc,
|
||||
style: TextStyle(fontSize: 13, color: AppColors.slate400),
|
||||
style: TextStyle(fontSize: 13, color: colorScheme.outline),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -583,22 +597,24 @@ class _ContactsScreenState extends State<ContactsScreen> {
|
||||
}
|
||||
|
||||
Widget _buildSectionTitle(String title) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
return Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.slate500,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPendingRequestCard(List<FriendRequestResponse> requests) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.white,
|
||||
color: colorScheme.surface,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: Border.all(color: const Color(0xFFE3EAF6)),
|
||||
border: Border.all(color: colorScheme.outlineVariant),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
@@ -612,15 +628,15 @@ class _ContactsScreenState extends State<ContactsScreen> {
|
||||
}
|
||||
|
||||
Widget _buildPendingRequestItem(FriendRequestResponse request) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final recipient = request.recipient;
|
||||
final color = _getAvatarColor(recipient.id);
|
||||
|
||||
return Container(
|
||||
height: 70,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14),
|
||||
child: Row(
|
||||
children: [
|
||||
_buildAvatar(recipient.avatarUrl, recipient.id, color),
|
||||
_buildAvatar(recipient.avatarUrl, recipient.id, colorScheme),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
@@ -629,16 +645,19 @@ class _ContactsScreenState extends State<ContactsScreen> {
|
||||
children: [
|
||||
Text(
|
||||
recipient.username,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.slate900,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
context.l10n.contactsPendingConfirm,
|
||||
style: TextStyle(fontSize: 12, color: AppColors.slate500),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -649,11 +668,12 @@ class _ContactsScreenState extends State<ContactsScreen> {
|
||||
}
|
||||
|
||||
Widget _buildContactCard(List<FriendResponse> friends) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.white,
|
||||
color: colorScheme.surface,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: Border.all(color: const Color(0xFFE3EAF6)),
|
||||
border: Border.all(color: colorScheme.outlineVariant),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
@@ -667,8 +687,8 @@ class _ContactsScreenState extends State<ContactsScreen> {
|
||||
}
|
||||
|
||||
Widget _buildContactItem(FriendResponse friend) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final friendInfo = friend.friend;
|
||||
final color = _getAvatarColor(friendInfo.id);
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () => context.push('/contacts/add?id=${friendInfo.id}'),
|
||||
@@ -677,7 +697,7 @@ class _ContactsScreenState extends State<ContactsScreen> {
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14),
|
||||
child: Row(
|
||||
children: [
|
||||
_buildAvatar(friendInfo.avatarUrl, friendInfo.id, color),
|
||||
_buildAvatar(friendInfo.avatarUrl, friendInfo.id, colorScheme),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
@@ -686,10 +706,10 @@ class _ContactsScreenState extends State<ContactsScreen> {
|
||||
children: [
|
||||
Text(
|
||||
friendInfo.username,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.slate900,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -701,52 +721,65 @@ class _ContactsScreenState extends State<ContactsScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
Color _getAvatarColor(String id) {
|
||||
final colors = [
|
||||
AppColors.blue500,
|
||||
AppColors.violet600,
|
||||
AppColors.blue600,
|
||||
const Color(0xFF0EA5E9),
|
||||
AppColors.violet500,
|
||||
];
|
||||
final index = id.hashCode.abs() % colors.length;
|
||||
return colors[index];
|
||||
Color _getAvatarBackground(
|
||||
Color color,
|
||||
ColorScheme colorScheme,
|
||||
AppColorPalette palette,
|
||||
) {
|
||||
final avatarIndex = palette.avatarColors.indexOf(color);
|
||||
final opacities = [0.30, 0.20, 0.35, 0.15, 0.30];
|
||||
final opacity = avatarIndex >= 0 && avatarIndex < opacities.length
|
||||
? opacities[avatarIndex]
|
||||
: 0.30;
|
||||
final isTertiary = avatarIndex == 4;
|
||||
return isTertiary
|
||||
? colorScheme.tertiaryContainer.withValues(alpha: opacity)
|
||||
: colorScheme.primaryContainer.withValues(alpha: opacity);
|
||||
}
|
||||
|
||||
Color _getAvatarBackground(Color color) {
|
||||
if (color == AppColors.blue500) return const Color(0xFFEEF4FF);
|
||||
if (color == AppColors.violet600) return AppColors.surfaceInfoLight;
|
||||
if (color == AppColors.blue600) return const Color(0xFFEDF5FF);
|
||||
if (color == const Color(0xFF0EA5E9)) return const Color(0xFFF2F8FF);
|
||||
if (color == AppColors.violet500) return const Color(0xFFF5F7FF);
|
||||
return const Color(0xFFEEF4FF);
|
||||
}
|
||||
|
||||
Color _getAvatarBorder(Color color) {
|
||||
if (color == AppColors.blue500) return const Color(0xFFDDE8FB);
|
||||
if (color == AppColors.violet600) return const Color(0xFFE2EAFB);
|
||||
if (color == AppColors.blue600) return const Color(0xFFDCE9FB);
|
||||
if (color == const Color(0xFF0EA5E9)) return const Color(0xFFDFEAFA);
|
||||
if (color == AppColors.violet500) return const Color(0xFFE4E8FA);
|
||||
return const Color(0xFFDDE8FB);
|
||||
Color _getAvatarBorder(
|
||||
Color color,
|
||||
ColorScheme colorScheme,
|
||||
AppColorPalette palette,
|
||||
) {
|
||||
final avatarIndex = palette.avatarColors.indexOf(color);
|
||||
final opacities = [0.25, 0.20, 0.30, 0.15, 0.25];
|
||||
final opacity = avatarIndex >= 0 && avatarIndex < opacities.length
|
||||
? opacities[avatarIndex]
|
||||
: 0.25;
|
||||
final isTertiary = avatarIndex == 4;
|
||||
return isTertiary
|
||||
? colorScheme.tertiary.withValues(alpha: opacity)
|
||||
: colorScheme.primary.withValues(alpha: opacity);
|
||||
}
|
||||
|
||||
Widget _buildDivider() {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
return Container(
|
||||
height: 1,
|
||||
margin: const EdgeInsets.symmetric(horizontal: 14),
|
||||
color: const Color(0xFFEEF2F7),
|
||||
color: colorScheme.outlineVariant,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAvatar(String? avatarUrl, String userId, Color color) {
|
||||
Widget _buildAvatar(
|
||||
String? avatarUrl,
|
||||
String userId,
|
||||
ColorScheme colorScheme,
|
||||
) {
|
||||
final palette = Theme.of(context).extension<AppColorPalette>()!;
|
||||
final avatarColor = palette
|
||||
.avatarColors[userId.hashCode.abs() % palette.avatarColors.length];
|
||||
|
||||
return Container(
|
||||
width: 42,
|
||||
height: 42,
|
||||
decoration: BoxDecoration(
|
||||
color: _getAvatarBackground(color),
|
||||
color: _getAvatarBackground(avatarColor, colorScheme, palette),
|
||||
borderRadius: BorderRadius.circular(21),
|
||||
border: Border.all(color: _getAvatarBorder(color)),
|
||||
border: Border.all(
|
||||
color: _getAvatarBorder(avatarColor, colorScheme, palette),
|
||||
),
|
||||
),
|
||||
child: avatarUrl != null
|
||||
? ClipRRect(
|
||||
@@ -756,14 +789,11 @@ class _ContactsScreenState extends State<ContactsScreen> {
|
||||
width: 42,
|
||||
height: 42,
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder: (context, error, stackTrace) => Icon(
|
||||
Icons.person,
|
||||
size: 18,
|
||||
color: _getAvatarColor(userId),
|
||||
),
|
||||
errorBuilder: (context, error, stackTrace) =>
|
||||
Icon(Icons.person, size: 18, color: avatarColor),
|
||||
),
|
||||
)
|
||||
: Icon(Icons.person, size: 18, color: _getAvatarColor(userId)),
|
||||
: Icon(Icons.person, size: 18, color: avatarColor),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -772,6 +802,7 @@ class _ContactsScreenState extends State<ContactsScreen> {
|
||||
TextEditingController controller,
|
||||
BuildContext sheetContext,
|
||||
) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
return SizedBox(
|
||||
height: 44,
|
||||
child: ElevatedButton(
|
||||
@@ -786,18 +817,18 @@ class _ContactsScreenState extends State<ContactsScreen> {
|
||||
);
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: AppColors.blue500,
|
||||
foregroundColor: AppColors.white,
|
||||
backgroundColor: colorScheme.primary,
|
||||
foregroundColor: colorScheme.onPrimary,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(AppRadius.sm),
|
||||
),
|
||||
),
|
||||
child: _sendingRequestUserId == userId
|
||||
? const AppLoadingIndicator(
|
||||
? AppLoadingIndicator(
|
||||
size: 16,
|
||||
strokeWidth: 2,
|
||||
color: AppColors.white,
|
||||
trackColor: AppColors.blue300,
|
||||
color: colorScheme.onPrimary,
|
||||
trackColor: colorScheme.primary.withValues(alpha: 0.3),
|
||||
withContainer: false,
|
||||
)
|
||||
: Text(
|
||||
|
||||
Reference in New Issue
Block a user