fixed chatbot ai selector

This commit is contained in:
Mohamad Mahdi Jebeli 2026-02-16 14:40:26 +03:30
parent 575243e959
commit 44421e39d6
4 changed files with 454 additions and 299 deletions

View File

@ -233,11 +233,11 @@ class _OnBoardingPageState extends State<OnBoardingPage> {
children: [ children: [
TextSpan( TextSpan(
text: sliders[index].description, text: sliders[index].description,
style: AppTextStyles.body3.copyWith( style: AppTextStyles.body4.copyWith(
color: color:
Theme.of(context).colorScheme.onSurface)) Theme.of(context).colorScheme.onSurface))
], ],
style: AppTextStyles.body3.copyWith( style: AppTextStyles.body4.copyWith(
color: Theme.of(context).colorScheme.onSurface, color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.bold)), fontWeight: FontWeight.bold)),
textAlign: TextAlign.justify, textAlign: TextAlign.justify,

View File

@ -1,4 +1,4 @@
// ignore_for_file: deprecated_member_use_from_same_package, use_build_context_synchronously, avoid_print // ignore_for_file: deprecated_member_use_from_same_package, use_build_context_synchronously, avoid_print, deprecated_member_use, curly_braces_in_flow_control_structures
import 'dart:math'; import 'dart:math';
@ -24,6 +24,7 @@ import 'package:hoshan/data/model/ai/messages_model.dart';
import 'package:hoshan/data/model/ai/send_message_model.dart'; import 'package:hoshan/data/model/ai/send_message_model.dart';
import 'package:hoshan/data/model/chat_args.dart'; import 'package:hoshan/data/model/chat_args.dart';
import 'package:hoshan/data/model/empty_states_enum.dart'; import 'package:hoshan/data/model/empty_states_enum.dart';
import 'package:hoshan/data/repository/bot_repository.dart';
import 'package:hoshan/ui/screens/chat/bloc/messages_bloc.dart'; import 'package:hoshan/ui/screens/chat/bloc/messages_bloc.dart';
import 'package:hoshan/ui/screens/chat/bloc/related_questions_bloc.dart'; import 'package:hoshan/ui/screens/chat/bloc/related_questions_bloc.dart';
import 'package:hoshan/ui/screens/chat/cubit/receive_message_cubit.dart'; import 'package:hoshan/ui/screens/chat/cubit/receive_message_cubit.dart';
@ -76,6 +77,22 @@ class _ChatPageState extends State<ChatPage> {
ValueNotifier<int?> maxLines = ValueNotifier(5); ValueNotifier<int?> maxLines = ValueNotifier(5);
late final ValueNotifier<int> selectedBotId = late final ValueNotifier<int> selectedBotId =
ValueNotifier(widget.chatArgs.bot.id ?? 1); ValueNotifier(widget.chatArgs.bot.id ?? 1);
final ValueNotifier<bool> isModelSelectionEnabled = ValueNotifier(true);
late final ValueNotifier<int> currentCost =
ValueNotifier(widget.chatArgs.bot.cost ?? 1);
Future<void> _updateCostFromApi(int botId) async {
try {
final botData = await BotRepository.getSingleBot(id: botId);
if (botData.cost != null) {
currentCost.value = botData.cost!;
}
} catch (e) {
if (kDebugMode) {
print('Error fetching bot cost: $e');
}
}
}
void sendRequest( void sendRequest(
{required final String? message, {required final String? message,
@ -1292,6 +1309,7 @@ class _ChatPageState extends State<ChatPage> {
}, },
listener: (context, state) { listener: (context, state) {
if (state is ReceiveMessageDone) { if (state is ReceiveMessageDone) {
isModelSelectionEnabled.value = false;
context.read<MessagesBloc>().add(AddMessage(message: state.message)); context.read<MessagesBloc>().add(AddMessage(message: state.message));
if (state.model.chatId != null) { if (state.model.chatId != null) {
if (chatId == null && !isGhost.value) { if (chatId == null && !isGhost.value) {
@ -1708,18 +1726,43 @@ class _ChatPageState extends State<ChatPage> {
) )
], ],
), ),
Container( ValueListenableBuilder<int>(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), valueListenable: currentCost,
builder: (context, cost, _) {
return TweenAnimationBuilder<double>(
duration: const Duration(milliseconds: 400),
curve: Curves.easeInOut,
tween: Tween<double>(
begin: cost.toDouble(),
end: cost.toDouble(),
),
builder: (context, value, child) {
return Container(
padding: const EdgeInsets.symmetric(
horizontal: 8, vertical: 4),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).colorScheme.secondary, color: Theme.of(context).colorScheme.secondary,
borderRadius: BorderRadius.circular(12)), borderRadius: BorderRadius.circular(12)),
child: Row( child: Row(
children: [ children: [
Text( AnimatedSwitcher(
bot.cost == 0 || bot.cost == null duration: const Duration(milliseconds: 300),
? 'رایگان' transitionBuilder:
: bot.cost.toString(), (Widget child, Animation<double> animation) {
style: AppTextStyles.body3.copyWith(color: Colors.white), return ScaleTransition(
scale: animation,
child: FadeTransition(
opacity: animation,
child: child,
),
);
},
child: Text(
cost == 0 ? 'رایگان' : cost.toString(),
key: ValueKey<int>(cost),
style: AppTextStyles.body3
.copyWith(color: Colors.white),
),
), ),
const SizedBox( const SizedBox(
width: 4, width: 4,
@ -1728,6 +1771,10 @@ class _ChatPageState extends State<ChatPage> {
.svg(color: Colors.white, width: 18, height: 18) .svg(color: Colors.white, width: 18, height: 18)
], ],
), ),
);
},
);
},
), ),
], ],
), ),
@ -1874,7 +1921,6 @@ class _ChatPageState extends State<ChatPage> {
child: TextField( child: TextField(
controller: messageText, controller: messageText,
onChanged: (value) {}, onChanged: (value) {},
enabled: (bot.deleted != enabled: (bot.deleted !=
null && null &&
!bot !bot
@ -1896,7 +1942,7 @@ class _ChatPageState extends State<ChatPage> {
.attachment != .attachment !=
3), 3),
minLines: 1, minLines: 1,
maxLines: 6, // Set this maxLines: 6,
keyboardType: keyboardType:
TextInputType TextInputType
.multiline, .multiline,
@ -2062,6 +2108,9 @@ class _ChatPageState extends State<ChatPage> {
children: [ children: [
if (bot.tool == null || !bot.tool!) if (bot.tool == null || !bot.tool!)
ValueListenableBuilder( ValueListenableBuilder(
valueListenable: isModelSelectionEnabled,
builder: (context, isEnabled, _) {
return ValueListenableBuilder(
valueListenable: selectedBotId, valueListenable: selectedBotId,
builder: (context, currentBotId, _) { builder: (context, currentBotId, _) {
String botName = currentBotId == 1 String botName = currentBotId == 1
@ -2072,25 +2121,35 @@ class _ChatPageState extends State<ChatPage> {
? 'Grok' ? 'Grok'
: 'Claude'; : 'Claude';
return PopupMenuButton<int>( return IgnorePointer(
color: ignoring: !isEnabled,
Theme.of(context).colorScheme.surface, child: Opacity(
opacity: isEnabled ? 1.0 : 0.5,
child: PopupMenuButton<int>(
color: Theme.of(context)
.colorScheme
.surface,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12), borderRadius:
BorderRadius.circular(12),
), ),
offset: const Offset(0, -10), offset: const Offset(0, -10),
onSelected: (int value) { onSelected: (int value) {
print('🤖 Bot selected: $value'); print('🤖 Bot selected: $value');
selectedBotId.value = value; selectedBotId.value = value;
_updateCostFromApi(value);
}, },
itemBuilder: (BuildContext context) => itemBuilder:
(BuildContext context) =>
<PopupMenuEntry<int>>[ <PopupMenuEntry<int>>[
PopupMenuItem<int>( PopupMenuItem<int>(
value: 1, value: 1,
child: Text( child: Text(
'ChatGPT', 'ChatGPT',
style: AppTextStyles.body5.copyWith( style: AppTextStyles.body5
fontWeight: currentBotId == 1 .copyWith(
fontWeight:
currentBotId == 1
? FontWeight.bold ? FontWeight.bold
: FontWeight.normal, : FontWeight.normal,
), ),
@ -2100,8 +2159,10 @@ class _ChatPageState extends State<ChatPage> {
value: 2, value: 2,
child: Text( child: Text(
'Gemini', 'Gemini',
style: AppTextStyles.body5.copyWith( style: AppTextStyles.body5
fontWeight: currentBotId == 2 .copyWith(
fontWeight:
currentBotId == 2
? FontWeight.bold ? FontWeight.bold
: FontWeight.normal, : FontWeight.normal,
), ),
@ -2111,8 +2172,10 @@ class _ChatPageState extends State<ChatPage> {
value: 4, value: 4,
child: Text( child: Text(
'Grok', 'Grok',
style: AppTextStyles.body5.copyWith( style: AppTextStyles.body5
fontWeight: currentBotId == 4 .copyWith(
fontWeight:
currentBotId == 4
? FontWeight.bold ? FontWeight.bold
: FontWeight.normal, : FontWeight.normal,
), ),
@ -2122,8 +2185,10 @@ class _ChatPageState extends State<ChatPage> {
value: 9, value: 9,
child: Text( child: Text(
'Claude', 'Claude',
style: AppTextStyles.body5.copyWith( style: AppTextStyles.body5
fontWeight: currentBotId == 9 .copyWith(
fontWeight:
currentBotId == 9
? FontWeight.bold ? FontWeight.bold
: FontWeight.normal, : FontWeight.normal,
), ),
@ -2131,25 +2196,34 @@ class _ChatPageState extends State<ChatPage> {
), ),
], ],
child: Container( child: Container(
padding: const EdgeInsets.symmetric( padding:
horizontal: 8, vertical: 4), const EdgeInsets.symmetric(
horizontal: 8,
vertical: 4),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context) color: Theme.of(context)
.colorScheme .colorScheme
.primary .primary
.withOpacity(0.1), .withOpacity(
borderRadius: BorderRadius.circular(8), isEnabled ? 0.1 : 0.05),
borderRadius:
BorderRadius.circular(8),
), ),
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Text( Text(
botName, botName,
style: AppTextStyles.body6.copyWith( style: AppTextStyles.body6
.copyWith(
color: Theme.of(context) color: Theme.of(context)
.colorScheme .colorScheme
.primary, .primary
fontWeight: FontWeight.bold, .withOpacity(isEnabled
? 1.0
: 0.5),
fontWeight:
FontWeight.bold,
), ),
), ),
const SizedBox(width: 4), const SizedBox(width: 4),
@ -2158,11 +2232,18 @@ class _ChatPageState extends State<ChatPage> {
size: 16, size: 16,
color: Theme.of(context) color: Theme.of(context)
.colorScheme .colorScheme
.primary, .primary
.withOpacity(isEnabled
? 1.0
: 0.5),
), ),
], ],
), ),
), ),
),
),
);
},
); );
}, },
), ),
@ -2240,10 +2321,15 @@ class _ChatPageState extends State<ChatPage> {
const SizedBox( const SizedBox(
width: 12, width: 12,
), ),
if ((bot.deleted != null && !bot.deleted!)) ValueListenableBuilder<int>(
if (bot.attachmentType != null && valueListenable: selectedBotId,
builder: (context, currentBotId, child) {
// غیرفعال کردن قابلیت ارسال عکس برای بات با id=4 (Grok)
if ((bot.deleted != null && !bot.deleted!) &&
currentBotId != 4) if (bot.attachmentType !=
null &&
bot.attachmentType!.isNotEmpty) bot.attachmentType!.isNotEmpty)
ValueListenableBuilder( return ValueListenableBuilder(
valueListenable: visibleAttach, valueListenable: visibleAttach,
builder: (context, value, child) { builder: (context, value, child) {
return AnimatedVisibility( return AnimatedVisibility(
@ -2252,8 +2338,8 @@ class _ChatPageState extends State<ChatPage> {
const Duration(milliseconds: 300), const Duration(milliseconds: 300),
fadeMode: FadeMode.horizontal, fadeMode: FadeMode.horizontal,
child: Padding( child: Padding(
padding: padding: const EdgeInsets.only(
const EdgeInsets.only(left: 12.0), left: 12.0),
child: Row( child: Row(
mainAxisAlignment: mainAxisAlignment:
MainAxisAlignment.end, MainAxisAlignment.end,
@ -2265,8 +2351,8 @@ class _ChatPageState extends State<ChatPage> {
const EdgeInsets.only( const EdgeInsets.only(
right: 8.0), right: 8.0),
child: CircleIconBtn( child: CircleIconBtn(
icon: Assets.icon.outline icon: Assets.icon
.galleryAdd, .outline.galleryAdd,
color: Theme.of(context) color: Theme.of(context)
.colorScheme .colorScheme
.primary, .primary,
@ -2276,8 +2362,8 @@ class _ChatPageState extends State<ChatPage> {
context) context)
.showPickImage( .showPickImage(
onSelect: (file) { onSelect: (file) {
selectedFile.value = selectedFile
file; .value = file;
if (widget if (widget
.chatArgs .chatArgs
.bot .bot
@ -2298,8 +2384,8 @@ class _ChatPageState extends State<ChatPage> {
const EdgeInsets.only( const EdgeInsets.only(
right: 8.0), right: 8.0),
child: CircleIconBtn( child: CircleIconBtn(
icon: Assets icon: Assets.icon.outline
.icon.outline.musicnote, .musicnote,
color: Theme.of(context) color: Theme.of(context)
.colorScheme .colorScheme
.primary, .primary,
@ -2315,11 +2401,13 @@ class _ChatPageState extends State<ChatPage> {
if (file != null) { if (file != null) {
selectedFile.value = selectedFile.value =
file.single; file.single;
if (widget.chatArgs.bot if (widget
.chatArgs
.bot
.attachment != .attachment !=
3) { 3) {
visibleAttach.value = visibleAttach
false; .value = false;
} }
} }
}, },
@ -2332,15 +2420,14 @@ class _ChatPageState extends State<ChatPage> {
const EdgeInsets.only( const EdgeInsets.only(
right: 8.0), right: 8.0),
child: CircleIconBtn( child: CircleIconBtn(
icon: Assets.icon.outline icon: Assets.icon
.folderAdd, .outline.folderAdd,
color: Theme.of(context) color: Theme.of(context)
.colorScheme .colorScheme
.primary, .primary,
iconColor: Colors.white, iconColor: Colors.white,
onTap: () async { onTap: () async {
final file = final file = await PickFileService(
await PickFileService(
context) context)
.getFile( .getFile(
fileType: fileType:
@ -2367,7 +2454,8 @@ class _ChatPageState extends State<ChatPage> {
.attachment != .attachment !=
3) { 3) {
visibleAttach visibleAttach
.value = false; .value =
false;
} }
} }
}), }),
@ -2376,25 +2464,37 @@ class _ChatPageState extends State<ChatPage> {
), ),
)); ));
}, },
);
return const SizedBox.shrink();
},
), ),
if ((bot.deleted != null && !bot.deleted!)) ValueListenableBuilder<int>(
if (bot.attachment != 0 && valueListenable: selectedBotId,
builder: (context, currentBotId, child) {
if ((bot.deleted != null && !bot.deleted!) &&
currentBotId != 4) if (bot.attachment !=
0 &&
bot.attachmentType != null && bot.attachmentType != null &&
bot.attachmentType!.isNotEmpty && bot.attachmentType!.isNotEmpty &&
bot.attachment != 3) bot.attachment != 3)
GestureDetector( return GestureDetector(
onTap: () { onTap: () {
if (widget.chatArgs.bot.attachment != 3) { if (widget.chatArgs.bot.attachment !=
3) {
visibleAttach.value = visibleAttach.value =
!visibleAttach.value; !visibleAttach.value;
} }
}, },
child: Assets.icon.outline.elementPlus.svg( child: Assets.icon.outline.elementPlus
.svg(
width: 24, width: 24,
height: 24, height: 24,
color: Theme.of(context) color: Theme.of(context)
.colorScheme .colorScheme
.primary)), .primary));
return const SizedBox.shrink();
},
),
], ],
), ),
], ],

View File

@ -57,7 +57,9 @@ class _AddFamilyState extends State<AddFamily> {
final backgroundColor = colorScheme.background; final backgroundColor = colorScheme.background;
final surfaceColor = colorScheme.surface; final surfaceColor = colorScheme.surface;
final onSurface = colorScheme.onSurface; final onSurface = colorScheme.onSurface;
final borderColor = const Color.fromARGB(255, 207, 206, 205); final borderColor = isDark
? colorScheme.outline.withOpacity(0.5)
: const Color.fromARGB(255, 207, 206, 205);
final accent = colorScheme.primary; final accent = colorScheme.primary;
final success = colorScheme.secondary; final success = colorScheme.secondary;
@ -274,6 +276,10 @@ class _AddFamilyState extends State<AddFamily> {
foregroundColor: onSurface, foregroundColor: onSurface,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
side: isDark
? BorderSide(
color: success.withOpacity(0.3))
: BorderSide.none,
), ),
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 16, vertical: 8), horizontal: 16, vertical: 8),
@ -287,6 +293,7 @@ class _AddFamilyState extends State<AddFamily> {
? CupertinoIcons.minus ? CupertinoIcons.minus
: CupertinoIcons.add, : CupertinoIcons.add,
size: 18, size: 18,
color: isDark ? success : null,
), ),
const SizedBox(width: 4), const SizedBox(width: 4),
Text( Text(
@ -294,7 +301,7 @@ class _AddFamilyState extends State<AddFamily> {
? 'بستن فرم' ? 'بستن فرم'
: 'افزودن عضو جدید', : 'افزودن عضو جدید',
style: AppTextStyles.body5.copyWith( style: AppTextStyles.body5.copyWith(
color: onSurface, color: isDark ? success : onSurface,
fontWeight: FontWeight.bold), fontWeight: FontWeight.bold),
), ),
], ],
@ -373,10 +380,13 @@ class _AddFamilyState extends State<AddFamily> {
padding: const EdgeInsets.all(12), padding: const EdgeInsets.all(12),
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDark color: isDark
? Color.fromARGB(255, 80, 80, 80) ? Color.fromARGB(255, 45, 45, 45)
: Color.fromARGB(255, 252, 252, 252), : Color.fromARGB(255, 252, 252, 252),
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
border: Border.all(color: Color.fromARGB(255, 207, 206, 205)), border: Border.all(
color: isDark
? colorScheme.outline.withOpacity(0.3)
: Color.fromARGB(255, 207, 206, 205)),
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: Colors.black.withOpacity(0.03), color: Colors.black.withOpacity(0.03),
@ -452,7 +462,7 @@ class _AddFamilyState extends State<AddFamily> {
// // ], // // ],
// // ), // // ),
// ), // ),
const SizedBox(width: 16), // const SizedBox(width: 16),
InkWell( InkWell(
onTap: () { onTap: () {
_showDeleteDialog(index); _showDeleteDialog(index);
@ -463,23 +473,7 @@ class _AddFamilyState extends State<AddFamily> {
height: 25, height: 25,
), ),
), ),
const SizedBox(width: 16), // const SizedBox(width: 16),
// Container(
// padding:
// const EdgeInsets.symmetric(horizontal: 15, vertical: 9),
// decoration: BoxDecoration(
// color: Color.fromARGB(255, 224, 236, 255),
// borderRadius: BorderRadius.circular(6),
// ),
// child: Text(
// 'در انتظار تایید',
// style: AppTextStyles.body6.copyWith(
// color: colorScheme.primary,
// fontWeight: FontWeight.bold,
// fontSize: 10,
// ),
// ),
// ),
], ],
), ),
], ],
@ -492,6 +486,7 @@ class _AddFamilyState extends State<AddFamily> {
final TextEditingController editPhoneController = final TextEditingController editPhoneController =
TextEditingController(text: member['phone']); TextEditingController(text: member['phone']);
int? editAgeIndex = member['ageIndex']; int? editAgeIndex = member['ageIndex'];
final isDark = Theme.of(context).brightness == Brightness.dark;
showDialog( showDialog(
context: context, context: context,
@ -503,7 +498,9 @@ class _AddFamilyState extends State<AddFamily> {
insetPadding: const EdgeInsets.symmetric(horizontal: 16), insetPadding: const EdgeInsets.symmetric(horizontal: 16),
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: const Color.fromARGB(255, 246, 246, 246), color: isDark
? Theme.of(context).colorScheme.surface
: const Color.fromARGB(255, 246, 246, 246),
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
border: Border.all(color: AppColors.gray[300]), border: Border.all(color: AppColors.gray[300]),
), ),
@ -514,8 +511,10 @@ class _AddFamilyState extends State<AddFamily> {
width: double.infinity, width: double.infinity,
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
vertical: 12, horizontal: 16), vertical: 12, horizontal: 16),
decoration: const BoxDecoration( decoration: BoxDecoration(
color: Color.fromARGB(255, 224, 236, 255), color: isDark
? Theme.of(context).colorScheme.surfaceVariant
: const Color.fromARGB(255, 224, 236, 255),
borderRadius: borderRadius:
BorderRadius.vertical(top: Radius.circular(16)), BorderRadius.vertical(top: Radius.circular(16)),
), ),
@ -528,13 +527,20 @@ class _AddFamilyState extends State<AddFamily> {
'ویرایش عضو ${_getOrdinal(index + 1)}', 'ویرایش عضو ${_getOrdinal(index + 1)}',
textAlign: TextAlign.right, textAlign: TextAlign.right,
style: AppTextStyles.body4.copyWith( style: AppTextStyles.body4.copyWith(
color: Colors.black, color: isDark
? Theme.of(context)
.colorScheme
.onSurfaceVariant
: Colors.black,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
InkWell( InkWell(
onTap: () => Navigator.pop(context), onTap: () => Navigator.pop(context),
child: const Icon(CupertinoIcons.clear, size: 20), child: Icon(CupertinoIcons.clear,
size: 20,
color:
Theme.of(context).colorScheme.onSurface),
) )
], ],
), ),
@ -542,7 +548,7 @@ class _AddFamilyState extends State<AddFamily> {
), ),
Container( Container(
height: 2, height: 2,
color: const Color.fromARGB(255, 30, 29, 27), color: Theme.of(context).colorScheme.outline,
), ),
Padding( Padding(
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
@ -563,6 +569,9 @@ class _AddFamilyState extends State<AddFamily> {
controller: editPhoneController, controller: editPhoneController,
keyboardType: TextInputType.phone, keyboardType: TextInputType.phone,
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
style: TextStyle(
color:
Theme.of(context).colorScheme.onSurface),
decoration: InputDecoration( decoration: InputDecoration(
suffixIcon: Icon( suffixIcon: Icon(
CupertinoIcons.phone, CupertinoIcons.phone,
@ -693,11 +702,14 @@ class _AddFamilyState extends State<AddFamily> {
void _showDeleteDialog(int index) { void _showDeleteDialog(int index) {
final member = _invitedMembers[index]; final member = _invitedMembers[index];
final isDark = Theme.of(context).brightness == Brightness.dark;
showDialog( showDialog(
context: context, context: context,
builder: (context) { builder: (context) {
return Dialog( return Dialog(
backgroundColor: Colors.white, backgroundColor:
isDark ? Theme.of(context).colorScheme.surface : Colors.white,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
), ),
@ -714,7 +726,9 @@ class _AddFamilyState extends State<AddFamily> {
InkWell( InkWell(
onTap: () => Navigator.pop(context), onTap: () => Navigator.pop(context),
child: SvgPicture.asset( child: SvgPicture.asset(
'assets/icon/outline/close-circle.svg')), 'assets/icon/outline/close-circle.svg',
color: Theme.of(context).colorScheme.onSurface,
)),
], ],
), ),
SvgPicture.asset( SvgPicture.asset(
@ -727,14 +741,17 @@ class _AddFamilyState extends State<AddFamily> {
'کاربر حذف شود؟', 'کاربر حذف شود؟',
style: AppTextStyles.body3.copyWith( style: AppTextStyles.body3.copyWith(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: Colors.black, color: Theme.of(context).colorScheme.onSurface,
), ),
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
Text( Text(
'شماره همراه: ${member['phone']}', 'شماره همراه: ${member['phone']}',
style: AppTextStyles.body5.copyWith( style: AppTextStyles.body5.copyWith(
color: AppColors.black[700], color: Theme.of(context)
.colorScheme
.onSurface
.withOpacity(0.7),
fontFamily: 'Dana', fontFamily: 'Dana',
), ),
), ),
@ -828,8 +845,11 @@ class _AddFamilyState extends State<AddFamily> {
} }
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Colors.grey[200], backgroundColor: isDark
foregroundColor: Colors.black, ? Theme.of(context).colorScheme.surfaceVariant
: Colors.grey[200],
foregroundColor:
Theme.of(context).colorScheme.onSurface,
elevation: 0, elevation: 0,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100), borderRadius: BorderRadius.circular(100),
@ -864,8 +884,11 @@ class _AddFamilyState extends State<AddFamily> {
required int? groupValue, required int? groupValue,
required ValueChanged<int> onChanged, required ValueChanged<int> onChanged,
}) { }) {
final colorScheme = Theme.of(context).colorScheme; final theme = Theme.of(context);
final colorScheme = theme.colorScheme;
final isDark = theme.brightness == Brightness.dark;
final isSelected = groupValue == index; final isSelected = groupValue == index;
return InkWell( return InkWell(
onTap: () => onChanged(index), onTap: () => onChanged(index),
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
@ -873,16 +896,25 @@ class _AddFamilyState extends State<AddFamily> {
padding: const EdgeInsets.symmetric(vertical: 12), padding: const EdgeInsets.symmetric(vertical: 12),
decoration: BoxDecoration( decoration: BoxDecoration(
color: isSelected color: isSelected
? colorScheme.primaryContainer.withOpacity(0.35) ? (isDark
: colorScheme.surfaceVariant, ? colorScheme.primary.withOpacity(0.3)
: colorScheme.primaryContainer.withOpacity(0.35))
: (isDark
? colorScheme.surfaceVariant
: colorScheme.surfaceVariant),
borderRadius: BorderRadius.circular(30), borderRadius: BorderRadius.circular(30),
border: isDark && !isSelected
? Border.all(color: colorScheme.outline.withOpacity(0.3))
: null,
), ),
child: Text( child: Text(
title, title,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: AppTextStyles.body6.copyWith( style: AppTextStyles.body6.copyWith(
color: isSelected color: isSelected
? colorScheme.onPrimaryContainer ? (isDark
? colorScheme.primary
: colorScheme.onPrimaryContainer)
: colorScheme.onSurface.withOpacity(0.7), : colorScheme.onSurface.withOpacity(0.7),
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontSize: 11, fontSize: 11,
@ -910,10 +942,14 @@ class _AddFamilyState extends State<AddFamily> {
} }
Widget _buildInviteCard(int memberNumber) { Widget _buildInviteCard(int memberNumber) {
final colorScheme = Theme.of(context).colorScheme; final theme = Theme.of(context);
final colorScheme = theme.colorScheme;
final isDark = theme.brightness == Brightness.dark;
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Color.fromARGB(255, 246, 246, 246), color:
isDark ? colorScheme.surface : Color.fromARGB(255, 246, 246, 246),
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
@ -929,7 +965,9 @@ class _AddFamilyState extends State<AddFamily> {
width: double.infinity, width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Color.fromARGB(255, 224, 236, 255), color: isDark
? colorScheme.surfaceVariant
: Color.fromARGB(255, 224, 236, 255),
borderRadius: borderRadius:
const BorderRadius.vertical(top: Radius.circular(16)), const BorderRadius.vertical(top: Radius.circular(16)),
), ),
@ -937,7 +975,7 @@ class _AddFamilyState extends State<AddFamily> {
'دعوت از عضو ${_getOrdinal(memberNumber)}', 'دعوت از عضو ${_getOrdinal(memberNumber)}',
textAlign: TextAlign.right, textAlign: TextAlign.right,
style: AppTextStyles.body4.copyWith( style: AppTextStyles.body4.copyWith(
color: Colors.black, color: isDark ? colorScheme.onSurfaceVariant : Colors.black,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
@ -963,6 +1001,7 @@ class _AddFamilyState extends State<AddFamily> {
controller: _phoneController, controller: _phoneController,
keyboardType: TextInputType.phone, keyboardType: TextInputType.phone,
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
style: TextStyle(color: colorScheme.onSurface),
decoration: InputDecoration( decoration: InputDecoration(
suffixIcon: Icon( suffixIcon: Icon(
CupertinoIcons.phone, CupertinoIcons.phone,
@ -972,8 +1011,10 @@ class _AddFamilyState extends State<AddFamily> {
horizontal: 16, vertical: 12), horizontal: 16, vertical: 12),
border: OutlineInputBorder( border: OutlineInputBorder(
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
borderSide: borderSide: BorderSide(
BorderSide(color: Color.fromARGB(255, 161, 160, 160)), color: isDark
? colorScheme.outline.withOpacity(0.5)
: Color.fromARGB(255, 161, 160, 160)),
), ),
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
@ -1120,8 +1161,11 @@ class _AddFamilyState extends State<AddFamily> {
} }
Widget _buildAgeOption({required String title, required int index}) { Widget _buildAgeOption({required String title, required int index}) {
final colorScheme = Theme.of(context).colorScheme; final theme = Theme.of(context);
final colorScheme = theme.colorScheme;
final isDark = theme.brightness == Brightness.dark;
final isSelected = _selectedAgeIndex == index; final isSelected = _selectedAgeIndex == index;
return InkWell( return InkWell(
onTap: () { onTap: () {
setState(() { setState(() {
@ -1133,16 +1177,23 @@ class _AddFamilyState extends State<AddFamily> {
padding: const EdgeInsets.symmetric(vertical: 12), padding: const EdgeInsets.symmetric(vertical: 12),
decoration: BoxDecoration( decoration: BoxDecoration(
color: isSelected color: isSelected
? Color.fromARGB(255, 224, 236, 255) ? (isDark
: Color.fromARGB(255, 233, 232, 231), ? colorScheme.primary.withOpacity(0.3)
: Color.fromARGB(255, 224, 236, 255))
: (isDark
? colorScheme.surfaceVariant
: Color.fromARGB(255, 233, 232, 231)),
borderRadius: BorderRadius.circular(30), borderRadius: BorderRadius.circular(30),
border: isDark && !isSelected
? Border.all(color: colorScheme.outline.withOpacity(0.3))
: null,
), ),
child: Text( child: Text(
title, title,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: AppTextStyles.body6.copyWith( style: AppTextStyles.body6.copyWith(
color: isSelected color: isSelected
? Colors.black ? (isDark ? colorScheme.primary : Colors.black)
: colorScheme.onSurface.withOpacity(0.7), : colorScheme.onSurface.withOpacity(0.7),
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontSize: 11, fontSize: 11,
@ -1155,6 +1206,8 @@ class _AddFamilyState extends State<AddFamily> {
Widget _buildTopInfoCard(BuildContext context, Widget _buildTopInfoCard(BuildContext context,
{required String title, required String icon}) { {required String title, required String icon}) {
final colorScheme = Theme.of(context).colorScheme; final colorScheme = Theme.of(context).colorScheme;
final isDark = Theme.of(context).brightness == Brightness.dark;
return Column( return Column(
children: [ children: [
Container( Container(
@ -1163,13 +1216,16 @@ class _AddFamilyState extends State<AddFamily> {
padding: const EdgeInsets.all(5), padding: const EdgeInsets.all(5),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
color: Color.fromARGB(255, 248, 231, 241), color: isDark
? colorScheme.surfaceVariant
: Color.fromARGB(255, 248, 231, 241),
), ),
child: Center( child: Center(
child: SvgPicture.asset( child: SvgPicture.asset(
icon, icon,
width: 32, width: 32,
height: 32, height: 32,
color: isDark ? colorScheme.onSurfaceVariant : null,
), ),
), ),
), ),

View File

@ -259,7 +259,6 @@ class _TtaPageState extends State<VideoChatPage> {
} }
final m = mState.messages; final m = mState.messages;
List<List<Messages>> allMessages = groupMessages(m); List<List<Messages>> allMessages = groupMessages(m);
// فیلتر کردن گروههایی که حداقل یک پیام با video_url دارند
List<List<Messages>> messages = allMessages.where((group) { List<List<Messages>> messages = allMessages.where((group) {
return group.any((msg) => return group.any((msg) =>
msg.content?.any((c) => c.videoUrl != null) ?? false); msg.content?.any((c) => c.videoUrl != null) ?? false);