didvan-app/lib/views/ai/history_ai_chat_page.dart

510 lines
24 KiB
Dart

// ignore_for_file: library_private_types_in_public_api, deprecated_member_use
import 'dart:async';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:didvan/config/theme_data.dart';
import 'package:didvan/constants/app_icons.dart';
import 'package:didvan/constants/assets.dart';
import 'package:didvan/main.dart';
import 'package:didvan/models/ai/ai_chat_args.dart';
import 'package:didvan/models/view/action_sheet_data.dart';
import 'package:didvan/models/view/app_bar_data.dart';
import 'package:didvan/routes/routes.dart';
import 'package:didvan/utils/action_sheet.dart';
import 'package:didvan/utils/date_time.dart';
import 'package:didvan/views/ai/history_ai_chat_state.dart';
import 'package:didvan/views/widgets/didvan/scaffold.dart';
import 'package:didvan/views/widgets/didvan/text.dart';
import 'package:didvan/views/widgets/search_field.dart';
import 'package:didvan/views/widgets/shimmer_placeholder.dart';
import 'package:didvan/views/widgets/state_handlers/empty_state.dart';
import 'package:didvan/views/widgets/state_handlers/sliver_state_handler.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class HistoryAiChatPage extends StatefulWidget {
final bool? archived;
const HistoryAiChatPage({Key? key, required this.archived}) : super(key: key);
@override
_HistoryAiChatPageState createState() => _HistoryAiChatPageState();
}
class _HistoryAiChatPageState extends State<HistoryAiChatPage> {
ScrollController scrollController = ScrollController();
@override
void initState() {
final state = context.read<HistoryAiChatState>();
Future.delayed(
Duration.zero,
() => state.getChats(archived: widget.archived),
);
super.initState();
}
Timer? _timer;
late bool archived = widget.archived ?? false;
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
context.read<HistoryAiChatState>().getChats();
return true;
},
child: DidvanScaffold(
hidePlayer: true,
physics: const BouncingScrollPhysics(),
// floatingActionButton: openAiListBtn(context),
padding: EdgeInsets.zero,
scrollController: scrollController,
showSliversFirst: false,
slivers: [
Consumer<HistoryAiChatState>(
builder: (context, state, child) {
return SliverStateHandler(
state: state,
emptyState: EmptyState(
asset: Assets.emptyResult,
title: 'لیست خالی است',
),
enableEmptyState: state.chats.isEmpty,
placeholder: const _HistoryPlaceholder(),
placeholderCount: 8,
// builder: (context, state, index) => _HistoryPlaceholder(),
builder: (context, state, index) {
final chat = state.chats[index];
TextEditingController title =
TextEditingController(text: state.chats[index].title);
return Dismissible(
key: UniqueKey(),
background: Container(
color: Theme.of(context).colorScheme.error,
alignment: Alignment.centerRight,
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: Icon(
DidvanIcons.trash_solid,
color: Theme.of(context).colorScheme.white,
),
),
secondaryBackground: Container(
color: Theme.of(context).colorScheme.primary,
alignment: Alignment.centerLeft,
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: Icon(
archived
? Icons.folder_delete
: Icons.create_new_folder_rounded,
color: Theme.of(context).colorScheme.white),
),
movementDuration: const Duration(milliseconds: 600),
confirmDismiss: (direction) async {
bool result = false;
if (direction == DismissDirection.startToEnd) {
ActionSheetUtils.context = context;
await ActionSheetUtils.openDialog(
data: ActionSheetData(
onConfirmed: () async {
final state =
context.read<HistoryAiChatState>();
await state.deleteChat(chat.id!, index);
result = true;
},
content: Column(
children: [
Row(
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
Icon(
DidvanIcons.trash_solid,
color: Theme.of(context)
.colorScheme
.error,
),
const SizedBox(
width: 8,
),
SizedBox(
child: DidvanText(
'پاک کردن گفت‌و‌گو',
color: Theme.of(context)
.colorScheme
.error,
fontSize: 20,
),
),
],
),
const SizedBox(
height: 12,
),
SizedBox(
child: RichText(
text: TextSpan(
text:
'آیا از پاک کردن گفت‌و‌گوی ',
style: TextStyle(
color: Theme.of(context)
.colorScheme
.text),
children: [
TextSpan(
text: "\"${chat.title}\"",
style: const TextStyle(
fontWeight:
FontWeight.bold)),
const TextSpan(
text:
' با هوشان اطمینان دارید؟ '),
]),
),
),
],
)));
} else {
result = await state.archivedChat(chat.id!, index);
}
return result;
},
child: InkWell(
onTap: () {
// if (state.chatsToDelete.isEmpty) {
navigatorKey.currentState!.pushNamed(Routes.aiChat,
arguments:
AiChatArgs(bot: chat.bot!, chat: chat));
// } else {
// if (state.chatsToDelete.contains(chat.id)) {
// state.chatsToDelete.remove(chat.id!);
// } else {
// state.chatsToDelete.add(chat.id!);
// }
// }
// state.update();
},
onLongPress: () {
state.chats[index] =
state.chats[index].copyWith(isEditing: true);
state.update();
// if (state.chatsToDelete.isEmpty) {
// state.chatsToDelete.add(chat.id!);
// }
// state.update();
},
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 12, horizontal: 20),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Theme.of(context)
.colorScheme
.border))),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
width: 46,
height: 46,
child: ClipOval(
child: CachedNetworkImage(
imageUrl: chat.bot!.image.toString(),
),
),
),
const SizedBox(
width: 18,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
DidvanText(
chat.bot!.name.toString(),
fontWeight: FontWeight.bold,
// fontSize: 18,
),
DidvanText(
DateTimeUtils.momentGenerator(
chat.updatedAt.toString()),
style:
const TextStyle(fontSize: 12)),
],
),
SizedBox(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
chat.isEditing != null &&
chat.isEditing!
? Row(
children: [
Expanded(
child: TextFormField(
controller: title,
style:
const TextStyle(
fontSize: 12),
textAlignVertical:
TextAlignVertical
.bottom,
maxLines: 1,
decoration:
const InputDecoration(
isDense: true,
contentPadding:
EdgeInsets
.symmetric(
vertical:
5,
horizontal:
10),
border:
OutlineInputBorder(),
)),
),
const SizedBox(
width: 12,
),
state.loadingchangeTitle
? const SizedBox(
width: 12,
height: 12,
child:
CircularProgressIndicator())
: InkWell(
onTap: () async {
if (title.text
.toString() ==
chat.title
.toString()) {
chat.isEditing =
false;
state.update();
return;
}
if (title.text
.isNotEmpty) {
await state
.changeNameChat(
chat
.id!,
index,
title
.text);
title.clear();
}
if (chat.isEditing !=
null) {
chat.isEditing =
!chat
.isEditing!;
state.update();
return;
}
chat.isEditing =
true;
state.update();
},
child: const Icon(
DidvanIcons
.check_circle_solid),
)
],
)
: DidvanText(
chat.title.toString(),
maxLines: 1,
overflow:
TextOverflow.ellipsis,
// fontWeight: FontWeight.bold,
// fontSize: 16,
),
DidvanText(
chat.prompts![0].text.toString(),
maxLines: 1,
overflow: TextOverflow.ellipsis,
fontSize: 12,
),
],
),
),
],
),
),
],
),
),
),
);
},
childCount: state.chats.length,
onRetry: state.getChats);
},
)
],
appBarData: AppBarData(
title: archived ? 'آرشیو‌ها' : 'تاریخچه گفت‌وگوها',
hasBack: true,
hasElevation: true,
backClick: () {
context.read<HistoryAiChatState>().getChats();
},
trailing: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: InkWell(
onTap: () async {
ActionSheetUtils.context = context;
await ActionSheetUtils.openDialog(
data: ActionSheetData(
onConfirmed: () async {
final state = context.read<HistoryAiChatState>();
await state.deleteAllChat();
},
content: Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(
DidvanIcons.trash_solid,
color: Theme.of(context).colorScheme.error,
),
const SizedBox(
width: 8,
),
DidvanText(
'پاک کردن همه گفت‌وگوها',
color: Theme.of(context).colorScheme.error,
fontSize: 20,
),
],
),
const SizedBox(
height: 12,
),
const DidvanText(
'آیا از پاک کردن تمامی گفت‌وگوهای انجام شده با هوشان اطمینان دارید؟'),
],
)));
},
child: DidvanText(
archived ? 'خارج کردن همه' : 'حذف همه',
color: Theme.of(context).colorScheme.error,
),
),
)),
children: [
Container(
color: Theme.of(context).colorScheme.surface,
padding: const EdgeInsets.only(right: 20, left: 20, bottom: 24),
child: SearchField(
title: 'گفت‌و‌گو‌ها',
onChanged: (value) {
final state = context.read<HistoryAiChatState>();
if (value.isEmpty) {
state.getChats(archived: widget.archived);
return;
}
_timer?.cancel();
_timer = Timer(const Duration(seconds: 1), () {
state.search = value;
state.getSearchChats(q: value, archived: widget.archived);
});
},
focusNode: FocusNode()),
),
],
),
);
}
// Widget openAiListBtn(BuildContext context) {
// final watch = context.watch<HistoryAiChatState>();
// final state = context.read<HistoryAiChatState>();
// return FloatingActionButton(
// backgroundColor: watch.chatsToDelete.isEmpty
// ? Theme.of(context).colorScheme.primary
// : Theme.of(context).colorScheme.error,
// shape: const OvalBorder(),
// mini: true,
// onPressed: () {
// if (watch.chatsToDelete.isEmpty) {
// state.getBots();
// state.search = '';
// _botsDialogSelect(context);
// } else {
// state.addChatToDelete();
// }
// },
// child: watch.chatsToDelete.isEmpty
// ? const Icon(DidvanIcons.add_regular)
// : const Icon(DidvanIcons.trash_regular),
// );
// }
}
class _HistoryPlaceholder extends StatelessWidget {
const _HistoryPlaceholder({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const Padding(
padding: EdgeInsets.symmetric(vertical: 18.0, horizontal: 20),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ClipOval(
child: ShimmerPlaceholder(
height: 46,
width: 46,
),
),
SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ShimmerPlaceholder(
height: 20,
width: 100,
),
ShimmerPlaceholder(
height: 14,
width: 100,
),
],
),
SizedBox(height: 12),
ShimmerPlaceholder(
height: 16,
width: double.infinity,
),
SizedBox(height: 8),
ShimmerPlaceholder(
height: 16,
width: double.infinity,
),
],
),
),
],
),
);
}
}