1037 lines
58 KiB
Dart
1037 lines
58 KiB
Dart
// ignore_for_file: use_build_context_synchronously, avoid_print
|
|
|
|
import 'dart:math';
|
|
|
|
import 'package:before_after/before_after.dart';
|
|
import 'package:carousel_slider/carousel_slider.dart';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_bloc/flutter_bloc.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/gen/my_flutter_app_icons.dart';
|
|
import 'package:hoshan/core/routes/route_generator.dart';
|
|
import 'package:hoshan/core/services/file_manager/download_file_services.dart';
|
|
import 'package:hoshan/data/model/ai/chats_history_model.dart';
|
|
import 'package:hoshan/data/model/ai/messages_model.dart';
|
|
import 'package:hoshan/data/model/ai/send_message_model.dart';
|
|
import 'package:hoshan/data/model/chat_args.dart';
|
|
import 'package:hoshan/data/storage/shared_preferences_helper.dart';
|
|
import 'package:hoshan/ui/screens/chat/bloc/messages_bloc.dart';
|
|
import 'package:hoshan/ui/screens/library/bloc/chats_history_bloc.dart';
|
|
import 'package:hoshan/ui/screens/library/library_screen.dart';
|
|
import 'package:hoshan/ui/screens/gmedia/cubit/media_g_response_cubit.dart';
|
|
import 'package:hoshan/ui/screens/gmedia/send_image_modal.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/button/circle_icon_btn.dart';
|
|
import 'package:hoshan/ui/widgets/components/button/loading_button.dart';
|
|
import 'package:hoshan/ui/widgets/components/dialog/dialog_handler.dart';
|
|
import 'package:hoshan/ui/widgets/components/dropdown/hint_tooltip.dart';
|
|
import 'package:hoshan/ui/widgets/components/image/custome_image.dart';
|
|
import 'package:hoshan/ui/widgets/components/image/network_image.dart';
|
|
import 'package:hoshan/ui/widgets/components/snackbar/snackbar_manager.dart';
|
|
import 'package:share_plus/share_plus.dart';
|
|
|
|
class PhotoChatPage extends StatefulWidget {
|
|
final ChatArgs chatArgs;
|
|
const PhotoChatPage({super.key, required this.chatArgs});
|
|
|
|
@override
|
|
State<PhotoChatPage> createState() => _PhotoChatPageState();
|
|
}
|
|
|
|
class _PhotoChatPageState extends State<PhotoChatPage> {
|
|
final CarouselSliderController _carouselController =
|
|
CarouselSliderController();
|
|
final TextEditingController _query = TextEditingController();
|
|
final ValueNotifier<int> _currentIndex = ValueNotifier(0);
|
|
final ValueNotifier<double> _comp = ValueNotifier(0.5);
|
|
final ValueNotifier<double> _compBot = ValueNotifier(0.5);
|
|
final FocusNode _textFieldFocus = FocusNode();
|
|
bool inComp = false;
|
|
late final ptp =
|
|
widget.chatArgs.bot.attachmentType?.contains('image') ?? false;
|
|
final ValueNotifier<bool> isGhost = ValueNotifier(false);
|
|
|
|
late final bot = widget.chatArgs.bot;
|
|
late int? chatId = widget.chatArgs.chatId;
|
|
final ValueNotifier<int> maxSize = ValueNotifier(1);
|
|
|
|
List<List<Messages>> groupMessages(List<Messages> messages) {
|
|
return messages.fold<List<List<Messages>>>([], (acc, message) {
|
|
if (acc.isEmpty ||
|
|
(acc.last.first.fromBot != message.fromBot && acc.last.length == 2) ||
|
|
(acc.last.first.fromBot == message.fromBot && message.fromBot!) ||
|
|
(acc.last.first.fromBot == message.fromBot && !message.fromBot!)) {
|
|
acc.add([message]);
|
|
} else {
|
|
acc.last.add(message);
|
|
}
|
|
return acc;
|
|
});
|
|
}
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
context.read<ChatsHistoryBloc>().add(RestartChatsHistory());
|
|
|
|
context.read<ChatsHistoryBloc>().add(const GetAllChats(type: 'image'));
|
|
|
|
if (!GuidsStorage.isSeenImage()) {
|
|
DialogHandler(context: context).onPhotoCreated();
|
|
GuidsStorage.setSeenImage(true);
|
|
}
|
|
});
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
body: Responsive(context).maxWidthInDesktop(
|
|
child: (contxet, mw) => Scaffold(
|
|
appBar: AppBar(),
|
|
drawer: Drawer(
|
|
shape:
|
|
const BeveledRectangleBorder(borderRadius: BorderRadius.zero),
|
|
child: LibraryScreen(
|
|
type: 'image',
|
|
onTap: (chat) {
|
|
context.push(Routes.photoToPhoto,
|
|
extra: ChatArgs(bot: chat.bot!, chatId: chat.id));
|
|
},
|
|
)),
|
|
bottomSheet: Padding(
|
|
padding: const EdgeInsets.all(8.0),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Flexible(
|
|
child: ptp
|
|
? Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
|
child: LoadingButton(
|
|
width: double.infinity,
|
|
onPressed: () {
|
|
Navigator.of(context).push(SendImageModal(
|
|
onFileSelected: (image) {
|
|
if (context
|
|
.read<MediaGResponseCubit>()
|
|
.state is MediaGResponseLoading) {
|
|
return;
|
|
}
|
|
context.read<MediaGResponseCubit>().request(
|
|
SendMessageModel(
|
|
ghost: isGhost.value,
|
|
messageId: DateTime.now()
|
|
.toIso8601String(),
|
|
file: image.xFile,
|
|
botId: widget.chatArgs.bot.id,
|
|
id: chatId));
|
|
},
|
|
));
|
|
},
|
|
backgroundColor:
|
|
Theme.of(context).colorScheme.primary,
|
|
child: Text(
|
|
'بارگذاری عکس',
|
|
style: AppTextStyles.body4
|
|
.copyWith(color: Colors.white),
|
|
)),
|
|
)
|
|
: Padding(
|
|
padding: const EdgeInsets.fromLTRB(16, 8, 16, 16),
|
|
child: Directionality(
|
|
textDirection: TextDirection.rtl,
|
|
child: Row(
|
|
crossAxisAlignment: CrossAxisAlignment.end,
|
|
children: [
|
|
CircleIconBtn(
|
|
icon: Assets.icon.bold.send,
|
|
color: Theme.of(context).colorScheme.primary,
|
|
iconColor: Colors.white,
|
|
iconPadding: const EdgeInsets.all(6),
|
|
size: 26,
|
|
onTap: () {
|
|
if (context
|
|
.read<MediaGResponseCubit>()
|
|
.state is MediaGResponseLoading) {
|
|
return;
|
|
}
|
|
context.read<MediaGResponseCubit>().request(
|
|
SendMessageModel(
|
|
messageId: DateTime.now()
|
|
.toIso8601String(),
|
|
query: _query.text,
|
|
botId: widget.chatArgs.bot.id,
|
|
ghost: isGhost.value,
|
|
id: chatId));
|
|
|
|
_query.clear();
|
|
},
|
|
),
|
|
const SizedBox(
|
|
width: 8,
|
|
),
|
|
Flexible(
|
|
child: TextField(
|
|
controller: _query,
|
|
focusNode: _textFieldFocus,
|
|
onTapOutside: (event) {
|
|
_textFieldFocus.unfocus();
|
|
},
|
|
style: AppTextStyles.body4.copyWith(
|
|
color: Theme.of(context)
|
|
.colorScheme
|
|
.onSurface),
|
|
decoration: InputDecoration.collapsed(
|
|
hintText:
|
|
'تصویری که میخوای رو توصیف کن...',
|
|
hintStyle: AppTextStyles.body4.copyWith(
|
|
color: AppColors.gray[context
|
|
.read<ThemeModeCubit>()
|
|
.isDark()
|
|
? 600
|
|
: 900])),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
floatingActionButton: ValueListenableBuilder(
|
|
valueListenable: _currentIndex,
|
|
builder: (context, value, _) {
|
|
return ValueListenableBuilder(
|
|
valueListenable: maxSize,
|
|
builder: (context, size, child) {
|
|
return value < size - 1
|
|
? Padding(
|
|
padding: const EdgeInsets.only(bottom: 64.0),
|
|
child: FloatingActionButton.small(
|
|
shape: const CircleBorder(),
|
|
onPressed: () {
|
|
_carouselController.animateToPage(size - 1);
|
|
},
|
|
child: Transform.rotate(
|
|
angle: pi / 2,
|
|
child: Assets.icon.outline.arrowRight.svg(
|
|
color: Colors.white,
|
|
),
|
|
),
|
|
))
|
|
: const SizedBox.shrink();
|
|
},
|
|
);
|
|
}),
|
|
body: Stack(
|
|
children: [
|
|
Assets.image.imageGBack.image(
|
|
width: MediaQuery.sizeOf(context).width,
|
|
height: MediaQuery.sizeOf(context).height,
|
|
color:
|
|
Theme.of(context).scaffoldBackgroundColor.withAlpha(240),
|
|
colorBlendMode: BlendMode.multiply,
|
|
fit: BoxFit.cover,
|
|
opacity: AlwaysStoppedAnimation(
|
|
context.read<ThemeModeCubit>().isDark() ? 0.5 : 0.2)),
|
|
Positioned.fill(child: BlocBuilder<MessagesBloc, MessagesState>(
|
|
builder: (context, mState) {
|
|
if (mState is MessagesFail) {
|
|
return const SizedBox();
|
|
}
|
|
if (mState is MessagesLoading) {
|
|
return const Center(
|
|
child: CircularProgressIndicator(),
|
|
);
|
|
}
|
|
// if (state is MessagesSuccess) {
|
|
final m = mState.messages;
|
|
List<List<Messages>> messages = groupMessages(m);
|
|
|
|
return BlocConsumer<MediaGResponseCubit, MediaGResponseState>(
|
|
listener: (context, state) async {
|
|
if (state is MediaGResponseSucess) {
|
|
context.read<MessagesBloc>().add(AddMessage(
|
|
message: Messages(
|
|
query: state.query,
|
|
file: state.file,
|
|
createdAt: DateTime.now().toIso8601String(),
|
|
error: state.response.error,
|
|
id: state.response.humanMessageId,
|
|
role: 'user')));
|
|
if (!(state.response.error ?? true)) {
|
|
context.read<MessagesBloc>().add(AddMessage(
|
|
message: Messages(
|
|
content: [
|
|
Content(
|
|
imageUrl: FileUrl(
|
|
url: state.response.content))
|
|
],
|
|
createdAt:
|
|
DateTime.now().toIso8601String(),
|
|
error: state.response.error,
|
|
id: state.response.aiMessageId,
|
|
role: 'ai')));
|
|
}
|
|
if (chatId == null && !isGhost.value) {
|
|
context.read<ChatsHistoryBloc>().add(AddChat(
|
|
chats: Chats(
|
|
bot: bot,
|
|
title: state.response.chatTitle,
|
|
createdAt: DateTime.now().toIso8601String(),
|
|
id: state.response.chatId)));
|
|
}
|
|
|
|
chatId = state.response.chatId;
|
|
}
|
|
},
|
|
builder: (context, state) {
|
|
maxSize.value = messages.length + 1;
|
|
print('📊 Messages count: ${messages.length}');
|
|
print('📊 Bot name: ${bot.name}');
|
|
return ListView(
|
|
physics: const BouncingScrollPhysics(),
|
|
children: [
|
|
// Bot info section
|
|
Column(
|
|
children: [
|
|
const SizedBox(
|
|
height: 16,
|
|
),
|
|
ptp
|
|
? ValueListenableBuilder(
|
|
valueListenable: _compBot,
|
|
builder: (context, val, child) =>
|
|
SizedBox(
|
|
width: 86 * 2,
|
|
height: 100 * 2,
|
|
child: BeforeAfter(
|
|
trackWidth: 4,
|
|
thumbWidth: 18,
|
|
value: val,
|
|
onValueChanged: (value) =>
|
|
_compBot.value = value,
|
|
before: AspectRatio(
|
|
aspectRatio: 3 / 4,
|
|
child: ImageNetwork(
|
|
width: double.infinity,
|
|
height: double.infinity,
|
|
radius: 12,
|
|
showHero: true,
|
|
url: bot.image2 ?? '')),
|
|
after: AspectRatio(
|
|
aspectRatio: 3 / 4,
|
|
child: ImageNetwork(
|
|
width: double.infinity,
|
|
height: double.infinity,
|
|
radius: 12,
|
|
showHero: true,
|
|
url: bot.image ?? '')),
|
|
),
|
|
))
|
|
: ImageNetwork(
|
|
width: 86,
|
|
height: 100,
|
|
url: bot.image ?? ''),
|
|
const SizedBox(
|
|
height: 8,
|
|
),
|
|
Text(
|
|
bot.name ?? '',
|
|
style: AppTextStyles.headline6.copyWith(
|
|
color: Theme.of(context)
|
|
.colorScheme
|
|
.onSurface),
|
|
),
|
|
const SizedBox(
|
|
height: 8,
|
|
),
|
|
if (bot.description != null)
|
|
Container(
|
|
margin: const EdgeInsets.symmetric(
|
|
horizontal: 16),
|
|
padding: const EdgeInsets.all(8),
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.circular(8),
|
|
color: Theme.of(context)
|
|
.colorScheme
|
|
.surface),
|
|
child: Text(
|
|
bot.description!,
|
|
style: AppTextStyles.body4.copyWith(
|
|
color: Theme.of(context)
|
|
.colorScheme
|
|
.onSurface),
|
|
textDirection: TextDirection.rtl,
|
|
textAlign: TextAlign.justify,
|
|
),
|
|
),
|
|
Padding(
|
|
padding: const EdgeInsets.symmetric(
|
|
horizontal: 16, vertical: 8),
|
|
child: Row(
|
|
mainAxisAlignment:
|
|
MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Row(
|
|
mainAxisAlignment:
|
|
MainAxisAlignment.center,
|
|
children: [
|
|
ValueListenableBuilder(
|
|
valueListenable: isGhost,
|
|
builder: (context, g, _) {
|
|
return Transform.scale(
|
|
scale: 0.8,
|
|
child: Switch.adaptive(
|
|
value: g,
|
|
thumbIcon: WidgetStateProperty
|
|
.resolveWith<Icon?>(
|
|
(Set<WidgetState>
|
|
states) {
|
|
if (states.contains(
|
|
WidgetState.selected)) {
|
|
return Icon(
|
|
CustomIcons.ghost,
|
|
color:
|
|
Theme.of(context)
|
|
.colorScheme
|
|
.onSurface);
|
|
}
|
|
return Icon(Icons.close,
|
|
color: Theme.of(context)
|
|
.colorScheme
|
|
.onSurface);
|
|
}),
|
|
onChanged: (value) {
|
|
isGhost.value = value;
|
|
},
|
|
),
|
|
);
|
|
}),
|
|
const SizedBox(
|
|
width: 8,
|
|
),
|
|
Text(
|
|
'حالت ناشناس',
|
|
style: AppTextStyles.body4.copyWith(
|
|
color: Theme.of(context)
|
|
.colorScheme
|
|
.onSurface,
|
|
fontWeight: FontWeight.bold),
|
|
),
|
|
const SizedBox(
|
|
width: 8,
|
|
),
|
|
Padding(
|
|
padding: const EdgeInsets.only(
|
|
bottom: 4.0),
|
|
child: HintTooltip(
|
|
hint:
|
|
'با فعال کردن این گزینه؛ چتهای شما در قسمت تاریخچه، ذخیره نمیشوند و اطلاعاتتان ناشناس باقی میماند.',
|
|
iconColor: Theme.of(context)
|
|
.colorScheme
|
|
.onSurface,
|
|
),
|
|
)
|
|
],
|
|
),
|
|
Container(
|
|
padding: const EdgeInsets.symmetric(
|
|
horizontal: 8, vertical: 4),
|
|
decoration: BoxDecoration(
|
|
color: Theme.of(context)
|
|
.colorScheme
|
|
.secondary,
|
|
borderRadius:
|
|
BorderRadius.circular(12)),
|
|
child: Row(
|
|
children: [
|
|
Text(
|
|
bot.cost == 0 || bot.cost == null
|
|
? 'رایگان'
|
|
: bot.cost.toString(),
|
|
style: AppTextStyles.body3
|
|
.copyWith(color: Colors.white),
|
|
),
|
|
const SizedBox(
|
|
width: 4,
|
|
),
|
|
Assets.icon.outline.coin.svg(
|
|
color: Colors.white,
|
|
width: 18,
|
|
height: 18)
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const SizedBox(
|
|
height: 16,
|
|
),
|
|
],
|
|
),
|
|
// Messages list
|
|
...messages.asMap().entries.map((entry) {
|
|
final index = entry.key;
|
|
final ms = entry.value;
|
|
print('🔵 Building message index: $index');
|
|
final yourScrollController = ScrollController();
|
|
Messages? user;
|
|
Messages? ai;
|
|
if (ms.length == 2) {
|
|
user = ms.first;
|
|
ai = ms.last;
|
|
} else if (ms.length == 1) {
|
|
if (ms.single.fromBot ?? false) {
|
|
ai = ms.single;
|
|
} else {
|
|
user = ms.single;
|
|
}
|
|
}
|
|
return inComp
|
|
? Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
ValueListenableBuilder(
|
|
valueListenable: _comp,
|
|
builder: (context, val, child) =>
|
|
BeforeAfter(
|
|
trackWidth: 4,
|
|
thumbWidth: 24,
|
|
value: val,
|
|
onValueChanged: (value) =>
|
|
_comp.value = value,
|
|
before: Container(
|
|
width: mw * 0.6,
|
|
padding:
|
|
const EdgeInsets.all(4),
|
|
decoration: BoxDecoration(
|
|
color: context
|
|
.read<
|
|
ThemeModeCubit>()
|
|
.isDark()
|
|
? AppColors.black[900]
|
|
: AppColors
|
|
.primaryColor[50],
|
|
borderRadius:
|
|
BorderRadius.circular(
|
|
16)),
|
|
child: AspectRatio(
|
|
aspectRatio: 3 / 4,
|
|
child: user!.file != null
|
|
? ClipRRect(
|
|
borderRadius:
|
|
BorderRadius
|
|
.circular(
|
|
12),
|
|
child: CustomeImage(
|
|
src: user
|
|
.file!.path,
|
|
fit: BoxFit.cover,
|
|
))
|
|
: ImageNetwork(
|
|
width:
|
|
double.infinity,
|
|
height:
|
|
double.infinity,
|
|
radius: 12,
|
|
showHero: true,
|
|
url: user
|
|
.content
|
|
?.first
|
|
.imageUrl
|
|
?.url ??
|
|
''),
|
|
),
|
|
),
|
|
after: Container(
|
|
width: mw * 0.6,
|
|
padding:
|
|
const EdgeInsets.all(4),
|
|
decoration: BoxDecoration(
|
|
color: context
|
|
.read<
|
|
ThemeModeCubit>()
|
|
.isDark()
|
|
? AppColors.black[900]
|
|
: AppColors
|
|
.primaryColor[50],
|
|
borderRadius:
|
|
BorderRadius.circular(
|
|
16)),
|
|
child: AspectRatio(
|
|
aspectRatio: 3 / 4,
|
|
child: ImageNetwork(
|
|
width:
|
|
double.infinity,
|
|
height:
|
|
double.infinity,
|
|
radius: 12,
|
|
showHero: true,
|
|
url: ai!
|
|
.content
|
|
?.first
|
|
.imageUrl
|
|
?.url ??
|
|
'')),
|
|
),
|
|
)),
|
|
SizedBox(
|
|
height: 16,
|
|
),
|
|
CircleIconBtn(
|
|
size: 32,
|
|
color: Theme.of(context)
|
|
.colorScheme
|
|
.primary,
|
|
iconColor: Colors.white,
|
|
onTap: () {
|
|
setState(() {
|
|
inComp = !inComp;
|
|
});
|
|
},
|
|
icon:
|
|
Assets.icon.outline.bitcoinRefresh,
|
|
),
|
|
],
|
|
)
|
|
: Column(
|
|
children: [
|
|
const SizedBox(
|
|
height: 16,
|
|
),
|
|
if (user != null)
|
|
Row(
|
|
mainAxisAlignment:
|
|
MainAxisAlignment.end,
|
|
children: [
|
|
Container(
|
|
width: mw * 0.6,
|
|
padding: const EdgeInsets.all(4),
|
|
margin: const EdgeInsets.all(16),
|
|
decoration: BoxDecoration(
|
|
color: user.error ?? false
|
|
? AppColors
|
|
.red.defaultShade
|
|
: Theme.of(context)
|
|
.colorScheme
|
|
.primary,
|
|
borderRadius:
|
|
BorderRadius.circular(16)
|
|
.copyWith(
|
|
bottomRight:
|
|
Radius.zero)),
|
|
child: ptp
|
|
? AspectRatio(
|
|
aspectRatio: 3 / 4,
|
|
child: user.file != null
|
|
? ClipRRect(
|
|
borderRadius:
|
|
BorderRadius
|
|
.circular(
|
|
12),
|
|
child:
|
|
CustomeImage(
|
|
src: user
|
|
.file!.path,
|
|
fit: BoxFit
|
|
.cover,
|
|
))
|
|
: ImageNetwork(
|
|
width: double
|
|
.infinity,
|
|
height: double
|
|
.infinity,
|
|
radius: 12,
|
|
showHero: true,
|
|
url: user
|
|
.content
|
|
?.first
|
|
.imageUrl
|
|
?.url ??
|
|
''),
|
|
)
|
|
: Padding(
|
|
padding:
|
|
const EdgeInsets.all(
|
|
16.0),
|
|
child: Directionality(
|
|
textDirection:
|
|
TextDirection.rtl,
|
|
child: Scrollbar(
|
|
thumbVisibility: true,
|
|
trackVisibility: true,
|
|
interactive: true,
|
|
controller:
|
|
yourScrollController,
|
|
radius: const Radius
|
|
.circular(16),
|
|
child:
|
|
SingleChildScrollView(
|
|
controller:
|
|
yourScrollController,
|
|
physics:
|
|
const BouncingScrollPhysics(),
|
|
child: Padding(
|
|
padding:
|
|
const EdgeInsets
|
|
.only(
|
|
left:
|
|
8.0),
|
|
child:
|
|
SelectableText(
|
|
user.query ??
|
|
'',
|
|
|
|
style:
|
|
AppTextStyles
|
|
.body4
|
|
.copyWith(
|
|
color: Colors
|
|
.white,
|
|
),
|
|
// overflow: TextOverflow.ellipsis,
|
|
// textAlign: TextAlign.justify,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
if (ai != null &&
|
|
user != null &&
|
|
state is! MediaGResponseLoading &&
|
|
ptp)
|
|
CircleIconBtn(
|
|
color: Theme.of(context)
|
|
.colorScheme
|
|
.primary,
|
|
iconColor: Colors.white,
|
|
onTap: () {
|
|
setState(() {
|
|
inComp = !inComp;
|
|
});
|
|
},
|
|
icon: Assets
|
|
.icon.outline.bitcoinRefresh,
|
|
),
|
|
if (user?.error ?? false)
|
|
error(
|
|
context,
|
|
() {
|
|
context.read<MessagesBloc>().add(
|
|
DeleteMessageWithId(
|
|
messageId: user!.id!));
|
|
context
|
|
.read<MediaGResponseCubit>()
|
|
.request(SendMessageModel(
|
|
id: chatId,
|
|
query:
|
|
ptp ? null : _query.text,
|
|
file: ptp ? user.file : null,
|
|
botId: widget.chatArgs.bot.id,
|
|
ghost: isGhost.value,
|
|
messageId: DateTime.now()
|
|
.toIso8601String(),
|
|
));
|
|
},
|
|
),
|
|
if (ai != null)
|
|
Column(
|
|
children: [
|
|
Row(
|
|
mainAxisAlignment:
|
|
MainAxisAlignment.start,
|
|
crossAxisAlignment:
|
|
CrossAxisAlignment.end,
|
|
children: [
|
|
Container(
|
|
width:
|
|
MediaQuery.sizeOf(context)
|
|
.width *
|
|
(ptp ? 0.6 : 0.7),
|
|
padding:
|
|
const EdgeInsets.all(4),
|
|
margin:
|
|
const EdgeInsets.all(16)
|
|
.copyWith(bottom: 8),
|
|
decoration: BoxDecoration(
|
|
color: context
|
|
.read<
|
|
ThemeModeCubit>()
|
|
.isDark()
|
|
? AppColors.black[900]
|
|
: AppColors
|
|
.secondryColor[
|
|
50],
|
|
borderRadius: BorderRadius
|
|
.circular(16)
|
|
.copyWith(
|
|
bottomLeft:
|
|
Radius.zero)),
|
|
child: AspectRatio(
|
|
aspectRatio: 3 / 4,
|
|
child: ImageNetwork(
|
|
width: double.infinity,
|
|
height: double.infinity,
|
|
radius: 12,
|
|
showHero: true,
|
|
url: ai
|
|
.content
|
|
?.first
|
|
.imageUrl
|
|
?.url ??
|
|
''),
|
|
),
|
|
),
|
|
if (ptp)
|
|
Expanded(
|
|
child: Padding(
|
|
padding:
|
|
const EdgeInsets.only(
|
|
bottom: 16.0),
|
|
child: Row(
|
|
mainAxisAlignment:
|
|
MainAxisAlignment
|
|
.start,
|
|
crossAxisAlignment:
|
|
CrossAxisAlignment
|
|
.end,
|
|
children: [
|
|
CircleIconBtn(
|
|
color:
|
|
Theme.of(context)
|
|
.colorScheme
|
|
.primary,
|
|
iconColor:
|
|
Colors.white,
|
|
icon: Assets.icon
|
|
.outline.download,
|
|
onTap: () {
|
|
try {
|
|
DownloadFileService.getFile(
|
|
url: ai!
|
|
.content!
|
|
.first
|
|
.imageUrl!
|
|
.url!)
|
|
.then(
|
|
(value) {
|
|
SnackBarManager(
|
|
context)
|
|
.show(
|
|
message:
|
|
'فایل با موفقیت در پوشه Downloads نشست.',
|
|
status:
|
|
SnackBarStatus.success);
|
|
});
|
|
} catch (e) {
|
|
if (kDebugMode) {
|
|
print(e);
|
|
}
|
|
}
|
|
},
|
|
),
|
|
const SizedBox(
|
|
width: 8,
|
|
),
|
|
CircleIconBtn(
|
|
color:
|
|
Theme.of(context)
|
|
.colorScheme
|
|
.primary,
|
|
iconColor:
|
|
Colors.white,
|
|
icon: Assets.icon
|
|
.outline.share,
|
|
onTap: () async {
|
|
try {
|
|
await Share.share(ai!
|
|
.content!
|
|
.first
|
|
.imageUrl!
|
|
.url
|
|
.toString());
|
|
} catch (e) {
|
|
if (kDebugMode) {
|
|
print(
|
|
'Error in share Text: $e');
|
|
}
|
|
}
|
|
},
|
|
),
|
|
],
|
|
),
|
|
)),
|
|
],
|
|
),
|
|
if (!ptp)
|
|
Padding(
|
|
padding: EdgeInsets.only(
|
|
right: MediaQuery.sizeOf(
|
|
context)
|
|
.width *
|
|
0.26),
|
|
child: Row(
|
|
mainAxisAlignment:
|
|
MainAxisAlignment.end,
|
|
children: [
|
|
CircleIconBtn(
|
|
color: Theme.of(context)
|
|
.colorScheme
|
|
.primary,
|
|
iconColor: Colors.white,
|
|
icon: Assets.icon.outline
|
|
.download,
|
|
onTap: () {
|
|
try {
|
|
DownloadFileService.getFile(
|
|
url: ai!
|
|
.content!
|
|
.first
|
|
.imageUrl!
|
|
.url!)
|
|
.then((value) {
|
|
SnackBarManager(context).show(
|
|
message:
|
|
'فایل با موفقیت در پوشه Downloads نشست.',
|
|
status:
|
|
SnackBarStatus
|
|
.success);
|
|
});
|
|
} catch (e) {
|
|
if (kDebugMode) {
|
|
print(e);
|
|
}
|
|
}
|
|
},
|
|
),
|
|
const SizedBox(
|
|
width: 8,
|
|
),
|
|
CircleIconBtn(
|
|
color: Theme.of(context)
|
|
.colorScheme
|
|
.primary,
|
|
iconColor: Colors.white,
|
|
icon: Assets
|
|
.icon.outline.share,
|
|
onTap: () async {
|
|
try {
|
|
await Share.share(ai!
|
|
.content!
|
|
.first
|
|
.imageUrl!
|
|
.url
|
|
.toString());
|
|
} catch (e) {
|
|
if (kDebugMode) {
|
|
print(
|
|
'Error in share Text: $e');
|
|
}
|
|
}
|
|
},
|
|
),
|
|
],
|
|
),
|
|
)
|
|
],
|
|
),
|
|
const SizedBox(
|
|
height: 90,
|
|
)
|
|
],
|
|
);
|
|
}).toList(),
|
|
const SizedBox(height: 100),
|
|
],
|
|
);
|
|
},
|
|
);
|
|
// }
|
|
},
|
|
)),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Container loading(BuildContext context) {
|
|
return Container(
|
|
margin: const EdgeInsets.symmetric(horizontal: 16),
|
|
padding: const EdgeInsets.all(16),
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.circular(8),
|
|
color: context.read<ThemeModeCubit>().isDark()
|
|
? AppColors.black[900]
|
|
: AppColors.secondryColor[50]),
|
|
child: Row(
|
|
children: [
|
|
Flexible(
|
|
child: SpinKitThreeBounce(
|
|
size: 32,
|
|
color: Theme.of(context).colorScheme.secondary,
|
|
)),
|
|
Text(
|
|
'این کار ممکن است کمی طول بکشد',
|
|
style: AppTextStyles.body5
|
|
.copyWith(color: Theme.of(context).colorScheme.onSurface),
|
|
)
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget error(BuildContext context, Function()? onRetry) {
|
|
return Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Container(
|
|
margin: const EdgeInsets.symmetric(horizontal: 16),
|
|
padding: const EdgeInsets.all(16),
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.circular(8),
|
|
color: AppColors.red.defaultShade),
|
|
child: Center(
|
|
child: Text(
|
|
'خطا لطفا مجددا تلاش کنید',
|
|
style: AppTextStyles.body5
|
|
.copyWith(color: Colors.white, fontWeight: FontWeight.bold),
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(
|
|
height: 8,
|
|
),
|
|
// LoadingButton(
|
|
// color: AppColors.red.defaultShade,
|
|
// onPressed: () {
|
|
// context.go(Routes.purchase);
|
|
// },
|
|
// child: Text(
|
|
// 'افزایش اعتبار',
|
|
// style: AppTextStyles.body4.copyWith(color: Colors.white),
|
|
// ),
|
|
// )
|
|
],
|
|
);
|
|
}
|
|
}
|