Houshan-Basa/lib/ui/screens/assistant/assistant_page.dart

1303 lines
72 KiB
Dart

// ignore_for_file: deprecated_member_use_from_same_package, use_build_context_synchronously
import 'dart:math';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_rating_bar/flutter_rating_bar.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:go_router/go_router.dart';
import 'package:hoshan/core/gen/assets.gen.dart';
import 'package:hoshan/core/routes/route_generator.dart';
import 'package:hoshan/core/services/api/dio_service.dart';
import 'package:hoshan/core/utils/date_time.dart';
import 'package:hoshan/core/utils/strings.dart';
import 'package:hoshan/data/model/ai/bots_model.dart';
import 'package:hoshan/data/model/assistant_comments_model.dart';
import 'package:hoshan/data/model/chat_args.dart';
import 'package:hoshan/data/model/edittext_state_model.dart';
import 'package:hoshan/data/repository/bot_repository.dart';
import 'package:hoshan/ui/screens/assistant/bloc/assistant_info_bloc.dart';
import 'package:hoshan/ui/screens/assistant/bloc/same_assistants_bloc.dart';
import 'package:hoshan/ui/screens/assistant/cubit/assistant_comments_cubit.dart';
import 'package:hoshan/ui/screens/splash/cubit/user_info_cubit.dart';
import 'package:hoshan/ui/theme/colors.dart';
import 'package:hoshan/ui/theme/cubit/theme_mode_cubit.dart';
import 'package:hoshan/ui/theme/responsive.dart';
import 'package:hoshan/ui/theme/text.dart';
import 'package:hoshan/ui/widgets/components/bot/bot_grid_card.dart';
import 'package:hoshan/ui/widgets/components/bot/bot_grid_card_placeholder.dart';
import 'package:hoshan/ui/widgets/components/button/circle_icon_btn.dart';
import 'package:hoshan/ui/widgets/components/button/loading_button.dart';
import 'package:hoshan/ui/widgets/components/dialog/bottom_sheets.dart';
import 'package:hoshan/ui/widgets/components/image/network_image.dart';
import 'package:hoshan/ui/widgets/components/snackbar/snackbar_manager.dart';
import 'package:hoshan/ui/widgets/components/text/credit_cost.dart';
import 'package:hoshan/ui/widgets/components/text/labeled_text_field.dart';
import 'package:hoshan/ui/widgets/sections/header/reversible_appbar.dart';
import 'package:hoshan/ui/widgets/sections/loading/default_placeholder.dart';
import 'package:persian_number_utility/persian_number_utility.dart';
class AssistantPage extends StatefulWidget {
const AssistantPage({super.key});
@override
State<AssistantPage> createState() => _AssistantPageState();
}
class _AssistantPageState extends State<AssistantPage> {
EdittextStateModel commentState = EdittextStateModel(
label: 'گوشمون به شماست!',
hintText: 'از نظر شما این دستیار چقدر عالی کار کرده؟',
);
double score = 0;
ValueNotifier<bool> loadingAddComment = ValueNotifier(false);
ValueNotifier<String?> errorAddComment = ValueNotifier(null);
ValueNotifier<int?> maxLines = ValueNotifier(5);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: ReversibleAppbar(
context,
title: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Padding(
padding: const EdgeInsets.only(top: 4.0),
child: CreditCost(
call: false,
loadingColor: Theme.of(context).colorScheme.secondary,
),
),
const SizedBox(
width: 8,
),
CircleIconBtn(
icon: Assets.icon.outline.coin,
color: AppColors.secondryColor[50],
iconColor: AppColors.secondryColor.defaultShade,
),
],
),
),
body: BlocConsumer<AssistantInfoBloc, AssistantInfoState>(
listener: (context, state) {
if (state is AssistantInfoSuccess) {
context.read<SameAssistantsBloc>().add(GetSameAssistants(
id: state.assistantInfo.category!.id!,
botId: state.assistantInfo.id));
context.read<AssistantCommentsCubit>().loadComments(
id: state.assistantInfo.id!,
);
} else if (state is AssistantInfoFail) {
context.pop();
SnackBarManager(context, id: 'GetAssistantError').show(
status: SnackBarStatus.error,
message: 'خطا در بارگذاری دستیار');
}
},
builder: (context, state) {
if (state is AssistantInfoSuccess) {
final info = state.assistantInfo;
ValueNotifier<int> comments = ValueNotifier(info.comments ?? 0);
ValueNotifier<double> scoreOfInfo = ValueNotifier(info.score ?? 0);
UserComment? userComment = info.userComment;
// commentState.formController.text = info.userComment?.text ?? '';
// if (info.userComment != null) {
// score = info.userComment!.score ?? score;
// }
return Responsive(context).maxWidthInDesktop(
child: (contxet, maxWidth) => SingleChildScrollView(
physics: const BouncingScrollPhysics(),
child: Directionality(
textDirection: TextDirection.rtl,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
flex: 3,
child: Row(
children: [
ImageNetwork(
width: 62,
height: 62,
radius: 360,
baseUrl: DioService.baseURL,
url: info.image),
const SizedBox(
width: 8,
),
Expanded(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Text(
info.name ?? '',
style: AppTextStyles.headline6
.copyWith(
color: Theme.of(context)
.colorScheme
.onSurface),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
Row(
children: [
Assets
.icon.outline.elementPlus
.svg(
color:
Theme.of(context)
.colorScheme
.onSurface),
const SizedBox(
width: 8,
),
Expanded(
child: Text(
'دسته‌بندی: ${info.category?.name ?? ''}',
style: AppTextStyles.body4
.copyWith(
color: Theme.of(
context)
.colorScheme
.onSurface),
maxLines: 1,
overflow:
TextOverflow.ellipsis,
),
)
],
)
],
),
)
],
),
),
const SizedBox(
width: 8,
),
Expanded(
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Column(
children: [
Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(
horizontal: 12, vertical: 8),
decoration: BoxDecoration(
color:
AppColors.green.defaultShade,
),
child: Row(
mainAxisAlignment:
MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
Padding(
padding:
const EdgeInsets.only(
top: 4.0),
child: ValueListenableBuilder(
valueListenable:
scoreOfInfo,
builder:
(context, sc, _) {
return Text(
sc
.toStringAsFixed(
1)
.padRight(1, '0'),
style: AppTextStyles
.body4
.copyWith(
fontWeight:
FontWeight
.bold,
color: Colors
.white),
);
}),
),
const Icon(
Icons.star_rate_rounded,
color: Colors.white,
),
],
),
),
Container(
width: double.infinity,
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Theme.of(context)
.colorScheme
.surface,
),
child: Center(
child: ValueListenableBuilder(
valueListenable: comments,
builder: (context, cms, _) {
return Text(
'$cms نظر',
style: AppTextStyles.body4
.copyWith(
fontWeight:
FontWeight
.bold,
color: Theme.of(
context)
.colorScheme
.onSurface),
);
}),
),
),
],
),
),
),
],
),
const SizedBox(
height: 12,
),
Row(
children: [
Expanded(
child: infoContainer(
title: 'کاربران این دستیار',
description:
'${info.users ?? 10} کاربر'),
),
Expanded(
child: infoContainer(
title: 'تعداد پیام‌ها',
description:
'${info.messages ?? 20} پیام'),
),
],
),
Row(
children: [
Expanded(
child: infoContainer(
title: 'سازنده دستیار',
description:
info.user?.username ?? 'هوشان'),
),
Expanded(
child: infoContainer(
title: 'تاریخ ایجاد',
description: DateTimeUtils
.convertStringIsoToDate(
info.createdAt!)
.toPersianDate()),
),
],
),
if (info.description != null)
Padding(
padding: const EdgeInsets.only(bottom: 16.0),
child: LayoutBuilder(
builder: (context, constraints) {
return ValueListenableBuilder(
valueListenable: maxLines,
builder: (context, lines, _) {
final span = TextSpan(
text: info.description,
style: AppTextStyles.body4.copyWith(
color: AppColors.gray[context
.read<
ThemeModeCubit>()
.isDark()
? 600
: 900]));
final tp = TextPainter(
text: span,
textDirection: TextDirection.ltr);
tp.layout(
maxWidth: constraints.maxWidth);
final numLines =
tp.computeLineMetrics().length;
return Padding(
padding: const EdgeInsets.fromLTRB(
4, 12, 4, 4),
child: Stack(
children: [
Column(
children: [
Text(
info.description!,
style: AppTextStyles.body4
.copyWith(
color: AppColors
.gray[context
.read<
ThemeModeCubit>()
.isDark()
? 600
: 900]),
maxLines: (lines),
textAlign:
TextAlign.justify,
),
if (lines == null &&
numLines >= 5)
Transform.rotate(
angle: -pi / 2,
child: CircleIconBtn(
onTap: () {
if (maxLines
.value ==
null) {
maxLines
.value = 5;
return;
}
maxLines.value =
null;
},
size: 46,
color: Theme.of(
context)
.colorScheme
.primary,
iconColor:
Colors.white,
icon: Assets
.icon
.outline
.arrowRight)),
],
),
if (lines != null &&
numLines > lines)
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Container(
height: 64,
decoration:
BoxDecoration(
gradient:
LinearGradient(
colors: [
Theme.of(context)
.scaffoldBackgroundColor,
Theme.of(context)
.scaffoldBackgroundColor
.withAlpha(
140)
],
begin: Alignment
.bottomCenter,
end: Alignment
.topCenter,
),
),
alignment: Alignment
.bottomCenter,
child: SizedBox(
child: Transform.rotate(
angle: pi / 2,
child: CircleIconBtn(
onTap: () {
if (maxLines
.value ==
null) {
maxLines
.value = 5;
return;
}
maxLines.value =
null;
},
size: 46,
color: Theme.of(context).colorScheme.primary,
iconColor: Colors.white,
icon: Assets.icon.outline.arrowRight)),
),
))
],
),
);
});
}),
),
const SizedBox(
height: 12,
),
LoadingButton(
onPressed: () {
contxet.go(Routes.chatFromAssistant,
extra:
ChatArgs(bot: state.assistantInfo));
},
color: AppColors.primaryColor.defaultShade,
radius: 16,
width: double.infinity,
height: 48,
child: Text(
'استفاده از دستیار',
style: AppTextStyles.body3
.copyWith(color: Colors.white),
)),
const SizedBox(
height: 12,
),
LoadingButton(
color: Theme.of(context).colorScheme.secondary,
isOutlined: true,
height: 48,
backgroundColor:
Theme.of(context).scaffoldBackgroundColor,
width: double.infinity,
onPressed: () {
BottomSheetHandler(context)
.showReportOptions();
},
child: Text(
'گزارش اشکال',
style: AppTextStyles.body4.copyWith(
fontWeight: FontWeight.bold,
color: Theme.of(context)
.colorScheme
.secondary),
),
),
const SizedBox(
height: 12,
),
ValueListenableBuilder(
valueListenable: loadingAddComment,
builder: (context, loading, _) {
return Container(
decoration: BoxDecoration(
color: Theme.of(context)
.colorScheme
.surface,
borderRadius:
BorderRadius.circular(8)),
padding: const EdgeInsets.all(16),
child: Stack(
children: [
IgnorePointer(
ignoring: loading,
child: Column(
crossAxisAlignment:
CrossAxisAlignment.end,
children: [
Center(
child: Directionality(
textDirection:
TextDirection.ltr,
child: RatingBar(
initialRating: 1,
direction:
Axis.horizontal,
allowHalfRating: true,
itemCount: 5,
itemSize: 46,
minRating: 1,
maxRating: 5,
glow: false,
ratingWidget:
RatingWidget(
full: Icon(
Icons
.star_rate_rounded,
color: AppColors.green
.defaultShade,
),
half: Icon(
Icons
.star_half_rounded,
color: AppColors.green
.defaultShade,
),
empty: Icon(
Icons
.star_outline_rounded,
color: AppColors.gray
.defaultShade,
),
),
itemPadding:
EdgeInsets.zero,
onRatingUpdate: (rating) {
score = rating;
},
),
),
),
const SizedBox(
height: 16,
),
LabeledTextField(
stateController: commentState,
onValid: (value) {
if (value != null &&
value.isEmpty) {
return 'لطفا فیلد نظر را پر کنید!';
}
return null;
},
),
const SizedBox(
height: 12,
),
TextButton(
onPressed: () async {
if (!commentState
.formState
.currentState!
.validate()) {
return;
} else if (score < 1) {
SnackBarManager(context,
id:
'score-fail')
.show(
message:
'حداقل امتیاز وازد شده باید 1 باشد',
status:
SnackBarStatus
.error);
}
loadingAddComment.value =
true;
errorAddComment.value =
null;
try {
AssistantComments comment = AssistantComments(
createdAt: DateTimeUtils
.getNow()
.toIso8601String(),
score: score,
text: commentState
.formController
.text,
user: AssistantCommentsUser(
image: UserInfoCubit
.userInfoModel
.image,
username: UserInfoCubit
.userInfoModel
.username));
await BotRepository
.addCommentInAssistant(
state
.assistantInfo
.id!,
comment);
loadingAddComment
.value = false;
context
.read<
AssistantCommentsCubit>()
.removeComment(
username: UserInfoCubit
.userInfoModel
.username!);
context
.read<
AssistantCommentsCubit>()
.addComment(
comment:
comment);
SnackBarManager(context,
id:
'addComment')
.show(
status:
SnackBarStatus
.success,
message:
'نظر شما با موفقیت ارسال شد');
if (state.assistantInfo
.userComment !=
null) {
scoreOfInfo
.value = (scoreOfInfo
.value *
comments
.value +
(score -
(userComment
?.score ??
0))) /
comments.value;
} else {
scoreOfInfo
.value = ((scoreOfInfo
.value *
comments
.value) +
score) /
(comments.value +
1);
comments.value =
comments.value +
1;
}
userComment = UserComment(
score: score,
text: commentState
.formController
.text);
commentState
.formController
.clear();
} on DioException catch (e) {
try {
errorAddComment
.value =
e.response?.data[
'detail'];
} catch (e) {
errorAddComment
.value =
'مشکلی پیش آمده لحظاتی دیگر دوباره تلاش کنید';
}
if (kDebugMode) {
print(
'Dio Error is: $e');
}
}
loadingAddComment.value =
false;
},
child: Padding(
padding:
const EdgeInsets.all(
8.0),
child: Text(
state.assistantInfo
.userComment !=
null
? 'تغییر نظر'
: 'ثبت نظر',
style: AppTextStyles
.body3
.copyWith(
color: Theme.of(
context)
.colorScheme
.primary),
),
))
],
),
),
if (loading)
Positioned.fill(
child: Container(
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(16),
color: Theme.of(context)
.colorScheme
.surface
.withValues(alpha: 0.5)),
child: Center(
child: SpinKitThreeBounce(
color: AppColors.primaryColor
.defaultShade,
size: 32,
),
),
))
],
),
);
}),
const SizedBox(
height: 12,
),
BlocBuilder<AssistantCommentsCubit,
AssistantCommentsState>(
builder: (context, commentState) {
if (commentState
is AssistantCommentsInitial) {
return Column(
children: [
ListTile(
contentPadding: EdgeInsets.zero,
title: Text(
'نظرات کاربران',
style: AppTextStyles.body3.copyWith(
fontWeight: FontWeight.bold),
),
),
const SizedBox(
height: 12,
),
ListView.builder(
physics:
const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: 3,
itemBuilder: (context, index) {
return commentContainerPlaceholder();
},
),
],
);
}
if (commentState.comments.isNotEmpty) {
return Column(
children: [
ListTile(
contentPadding: EdgeInsets.zero,
title: Text(
'نظرات کاربران',
style: AppTextStyles.body3.copyWith(
fontWeight: FontWeight.bold),
),
),
const SizedBox(
height: 12,
),
ListView.builder(
physics:
const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount:
commentState.comments.length,
itemBuilder: (context, index) {
final comment =
commentState.comments[index];
return commentContainer(comment);
},
),
const SizedBox(
height: 12,
),
if (commentState
is AssistantCommentsLoading)
Padding(
padding: const EdgeInsets.symmetric(
vertical: 12.0),
child: LinearProgressIndicator(
color: AppColors
.primaryColor.defaultShade,
borderRadius:
BorderRadius.circular(8),
),
),
if ((commentState
is AssistantCommentsSuccess ||
commentState
is AssistantCommentsFail) &&
!(commentState.lastPage != null &&
commentState.page >
commentState.lastPage!))
GestureDetector(
onTap: () {
if (context
.read<
AssistantCommentsCubit>()
.state
is AssistantCommentsLoading ||
context
.read<
AssistantCommentsCubit>()
.state
is AssistantCommentsInitial) {
return;
}
context
.read<
AssistantCommentsCubit>()
.loadComments(
id: state
.assistantInfo.id!);
},
child: Row(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Text(
'مشاهده بیشتر',
style: AppTextStyles.body3
.copyWith(
fontWeight:
FontWeight.bold),
),
const SizedBox(
width: 8,
),
Transform.rotate(
angle: pi / 2,
child: Assets
.icon.outline.arrowRight
.svg(
color: AppColors
.secondryColor
.defaultShade))
],
),
),
],
);
}
return const SizedBox.shrink();
},
),
const SizedBox(
height: 24,
),
ValueListenableBuilder(
valueListenable: errorAddComment,
builder: (context, message, child) {
if (message != null && message.isNotEmpty) {
return Container(
decoration: BoxDecoration(
color: AppColors.red[50],
borderRadius:
BorderRadius.circular(16)),
padding: const EdgeInsets.all(16),
child: Row(
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
Icon(
Icons.warning_rounded,
color: AppColors.red.defaultShade,
size: 32,
),
const SizedBox(
width: 8,
),
Expanded(
child: Text(
message,
style: AppTextStyles.body4.copyWith(
color: AppColors.gray[context
.read<
ThemeModeCubit>()
.isDark()
? 600
: 900]),
),
),
],
),
);
}
return const SizedBox.shrink();
},
)
],
),
),
const SizedBox(
height: 12,
),
BlocBuilder<SameAssistantsBloc, SameAssistantsState>(
builder: (context, state) {
if (state is SameAssistantsFail) {
return const SizedBox.shrink();
}
if (state is SameAssistantsSuccess) {
if (state.bots.isEmpty) {
return const SizedBox.shrink();
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16.0,
),
child: ListTile(
contentPadding: EdgeInsets.zero,
title: Text(
'دستیارهای مشابه',
style: AppTextStyles.body3.copyWith(
fontWeight: FontWeight.bold),
),
),
),
SizedBox(
height: 170,
child: ListView.builder(
shrinkWrap: true,
itemCount: state.bots.length,
padding: const EdgeInsets.symmetric(
horizontal: 8),
physics: const BouncingScrollPhysics(),
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return SizedBox(
width: (Responsive(context)
.isDesktop()
? 300
: MediaQuery.sizeOf(context)
.width) *
0.5,
child: Padding(
padding:
const EdgeInsets.symmetric(
horizontal: 4.0,
vertical: 8),
child: GestureDetector(
onTap: () {
contxet.push(Routes.assistant,
extra:
state.bots[index].id);
},
child: BotGridCard(
bot: state.bots[index],
),
),
));
},
),
),
],
);
}
return Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16.0,
),
child: DefaultPlaceHolder(
child: ListTile(
contentPadding: EdgeInsets.zero,
title: Text(
'دستیارهای مشابه',
style: AppTextStyles.body3.copyWith(
fontWeight: FontWeight.bold),
),
),
),
),
SizedBox(
height: 170,
child: ListView.builder(
shrinkWrap: true,
itemCount: 10,
padding: const EdgeInsets.symmetric(
horizontal: 16),
physics:
const NeverScrollableScrollPhysics(),
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return SizedBox(
width: (Responsive(context)
.isDesktop()
? 300
: MediaQuery.sizeOf(context)
.width) *
0.5,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 4.0, vertical: 8),
child: GestureDetector(
onTap: () {},
child: BotGridCardPlaceholder(
index: index,
),
),
));
},
),
),
],
);
},
),
const SizedBox(
height: 12,
),
],
),
),
),
),
);
}
return Center(
child: SpinKitThreeBounce(
size: 32,
color: AppColors.primaryColor.defaultShade,
),
);
},
),
);
}
Container commentContainerPlaceholder() {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(24),
border: Border.all(color: AppColors.gray[600]),
color: Theme.of(context).colorScheme.surface),
padding: const EdgeInsetsDirectional.all(16),
margin: const EdgeInsets.symmetric(vertical: 4),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
DefaultPlaceHolder(
child: Container(
width: 52,
height: 52,
margin: const EdgeInsets.all(8),
decoration: const BoxDecoration(
shape: BoxShape.circle, color: Colors.white),
),
),
DefaultPlaceHolder(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white),
child: Text(
'کدباز 2025',
style: AppTextStyles.body4
.copyWith(fontWeight: FontWeight.bold),
),
),
)
],
),
DefaultPlaceHolder(
child: Directionality(
textDirection: TextDirection.ltr,
child: RatingBar(
initialRating: 3,
direction: Axis.horizontal,
allowHalfRating: true,
itemCount: 5,
itemSize: 24,
ignoreGestures: true,
ratingWidget: RatingWidget(
full: Icon(
Icons.star_rate_rounded,
color: AppColors.green.defaultShade,
),
half: Icon(
Icons.star_half_rounded,
color: AppColors.green.defaultShade,
),
empty: Icon(
Icons.star_outline_rounded,
color: AppColors.green.defaultShade,
),
),
itemPadding: EdgeInsets.zero,
onRatingUpdate: (rating) {},
),
),
)
],
),
DefaultPlaceHolder(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8), color: Colors.white),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'"این دستیار برنامه‌نویسی خیلی به کارم اومد! باگ‌هایی رو که کلی وقت می‌گرفتن، سریع پیدا می‌کنه و حتی راه‌حل‌های پیشنهادی می‌ده".👌🤖',
style:
AppTextStyles.body4.copyWith(fontWeight: FontWeight.w500),
),
),
),
)
],
),
);
}
Container commentContainer(final AssistantComments comment) {
final daysAgo = DateTimeUtils.getDaysBetweenNowAnd(comment.createdAt!);
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(24),
border: Border.all(color: AppColors.gray[600]),
color: Theme.of(context).colorScheme.surface),
padding: const EdgeInsetsDirectional.all(8),
margin: const EdgeInsets.symmetric(vertical: 4),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
ImageNetwork(
url: comment.user?.image ?? '',
width: 52,
height: 52,
radius: 360,
),
const SizedBox(
width: 8,
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
comment.user?.username ?? '',
style: AppTextStyles.body4.copyWith(
fontWeight: FontWeight.bold,
color: Theme.of(context).colorScheme.onSurface),
),
Text(
daysAgo == 0 ? 'امروز' : '$daysAgo روز قبل',
style: AppTextStyles.body6
.copyWith(color: AppColors.gray[700]),
)
],
)
],
),
Directionality(
textDirection: TextDirection.ltr,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Opacity(
opacity: (comment.score ?? 0) == 0 ? 0 : 1,
child: RatingBar(
initialRating: comment.score ?? 0,
direction: Axis.horizontal,
allowHalfRating: true,
itemCount: 5,
itemSize: 24,
ignoreGestures: true,
ratingWidget: RatingWidget(
full: Icon(
Icons.star_rate_rounded,
color: AppColors.green.defaultShade,
),
half: Icon(
Icons.star_half_rounded,
color: AppColors.green.defaultShade,
),
empty: Icon(
Icons.star_outline_rounded,
color: AppColors.green.defaultShade,
),
),
itemPadding: EdgeInsets.zero,
onRatingUpdate: (rating) {},
),
),
const SizedBox(
height: 4,
),
InkWell(
onTap: BottomSheetHandler(context).showReportOptions,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Assets.icon.outline.flag2
.svg(color: AppColors.gray[700]),
const SizedBox(
width: 4,
),
Text(
'گزارش',
style: AppTextStyles.body4
.copyWith(color: AppColors.gray[700]),
),
],
),
)
],
),
)
],
),
const SizedBox(
height: 8,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: SizedBox(
width: double.infinity,
child: Text(
comment.text ?? '',
style: AppTextStyles.body4.copyWith(
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.onSurface),
textDirection:
comment.text != null && comment.text!.startsWithEnglish()
? TextDirection.ltr
: TextDirection.rtl,
),
),
)
],
),
);
}
Container infoContainer(
{required final String title, required final String description}) {
return Container(
margin: const EdgeInsets.all(4),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(8)),
padding: const EdgeInsets.all(8),
child: Column(
children: [
Text(
title,
style: AppTextStyles.body4.copyWith(
fontWeight: FontWeight.bold,
color: Theme.of(context).colorScheme.primary),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
const SizedBox(
height: 8,
),
Text(
description,
style: AppTextStyles.body5
.copyWith(color: Theme.of(context).colorScheme.primary),
maxLines: 1,
overflow: TextOverflow.ellipsis,
)
],
),
);
}
}