1303 lines
72 KiB
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,
|
|
)
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|