change hoshan Appbar Header and create Tools and ToolBox page and change AiChatPage,

This commit is contained in:
OkaykOrhmn 2024-11-12 16:54:27 +03:30
parent 3f6957ae15
commit 2f4e049ce0
15 changed files with 1418 additions and 965 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 802 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 792 KiB

View File

@ -43,6 +43,8 @@ class Assets {
static String loadingAnimation = '$_baseAnimationsPath/loading.gif'; static String loadingAnimation = '$_baseAnimationsPath/loading.gif';
static String bookmarkAnimation = '$_baseAnimationsPath/bookmark.gif'; static String bookmarkAnimation = '$_baseAnimationsPath/bookmark.gif';
static String boxAnimation =
'$_baseAnimationsPath/onlinegiftools-$_themeSuffix.gif';
static String get businessCategoryIcon => static String get businessCategoryIcon =>
'$_baseCategoriesPath/business-$_themeSuffix.svg'; '$_baseCategoriesPath/business-$_themeSuffix.svg';

View File

@ -18,7 +18,9 @@ import 'package:didvan/services/media/media.dart';
import 'package:didvan/services/notification/firebase_api.dart'; import 'package:didvan/services/notification/firebase_api.dart';
import 'package:didvan/services/notification/notification_service.dart'; import 'package:didvan/services/notification/notification_service.dart';
import 'package:didvan/utils/my_custom_scroll_behavior.dart'; import 'package:didvan/utils/my_custom_scroll_behavior.dart';
import 'package:didvan/views/ai/ai_state.dart';
import 'package:didvan/views/ai/history_ai_chat_state.dart'; import 'package:didvan/views/ai/history_ai_chat_state.dart';
import 'package:didvan/views/ai/tools_state.dart';
import 'package:didvan/views/podcasts/podcasts_state.dart'; import 'package:didvan/views/podcasts/podcasts_state.dart';
import 'package:didvan/views/podcasts/studio_details/studio_details_state.dart'; import 'package:didvan/views/podcasts/studio_details/studio_details_state.dart';
import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_core/firebase_core.dart';
@ -170,6 +172,12 @@ class _DidvanState extends State<Didvan> with WidgetsBindingObserver {
ChangeNotifierProvider<HistoryAiChatState>( ChangeNotifierProvider<HistoryAiChatState>(
create: (context) => HistoryAiChatState(), create: (context) => HistoryAiChatState(),
), ),
ChangeNotifierProvider<AiState>(
create: (context) => AiState(),
),
ChangeNotifierProvider<ToolsState>(
create: (context) => ToolsState(),
),
], ],
child: Consumer<ThemeProvider>( child: Consumer<ThemeProvider>(
builder: (context, themeProvider, child) => Container( builder: (context, themeProvider, child) => Container(

View File

@ -0,0 +1,72 @@
import 'package:didvan/models/ai/bots_model.dart';
class ToolsModel {
List<Tools>? tools;
ToolsModel({this.tools});
ToolsModel.fromJson(Map<String, dynamic> json) {
if (json['tools'] != null) {
tools = <Tools>[];
json['tools'].forEach((v) {
tools!.add(Tools.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
if (tools != null) {
data['tools'] = tools!.map((v) => v.toJson()).toList();
}
return data;
}
}
class Tools {
int? id;
String? name;
String? image;
String? description;
String? guide;
int? order;
List<BotsModel>? bots;
Tools(
{this.id,
this.name,
this.image,
this.description,
this.guide,
this.order,
this.bots});
Tools.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
image = json['image'];
description = json['description'];
guide = json['guide'];
order = json['order'];
if (json['bots'] != null) {
bots = <BotsModel>[];
json['bots'].forEach((v) {
bots!.add(BotsModel.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['name'] = name;
data['image'] = image;
data['description'] = description;
data['guide'] = guide;
data['order'] = order;
if (bots != null) {
data['bots'] = bots!.map((v) => v.toJson()).toList();
}
return data;
}
}

View File

@ -205,7 +205,7 @@ class RequestHelper {
static String aiArchived() => '$baseUrl/ai/chat${_urlConcatGenerator([ static String aiArchived() => '$baseUrl/ai/chat${_urlConcatGenerator([
const MapEntry('archived', true), const MapEntry('archived', true),
])}'; ])}';
static String aiBots() => '$baseUrl/ai/bot'; static String aiBots() => '$baseUrl/ai/bot/v2';
static String aiSearchBots(String q) => static String aiSearchBots(String q) =>
'$baseUrl/ai/bot${_urlConcatGenerator([ '$baseUrl/ai/bot${_urlConcatGenerator([
MapEntry('q', q), MapEntry('q', q),
@ -229,6 +229,7 @@ class RequestHelper {
static String deleteAllChats() => '$baseUrl/ai/chat/all'; static String deleteAllChats() => '$baseUrl/ai/chat/all';
static String archivedChat(int id) => '$baseUrl/ai/chat/$id/archive'; static String archivedChat(int id) => '$baseUrl/ai/chat/$id/archive';
static String placeholder(int id) => '$baseUrl/ai/chat/$id/placeholder'; static String placeholder(int id) => '$baseUrl/ai/chat/$id/placeholder';
static String tools() => '$baseUrl/ai/tool';
static String _urlConcatGenerator(List<MapEntry<String, dynamic>> additions) { static String _urlConcatGenerator(List<MapEntry<String, dynamic>> additions) {
String result = ''; String result = '';

View File

@ -10,7 +10,10 @@ import 'package:didvan/constants/assets.dart';
import 'package:didvan/models/ai/ai_chat_args.dart'; import 'package:didvan/models/ai/ai_chat_args.dart';
import 'package:didvan/routes/routes.dart'; import 'package:didvan/routes/routes.dart';
import 'package:didvan/utils/action_sheet.dart'; import 'package:didvan/utils/action_sheet.dart';
import 'package:didvan/views/ai/ai_state.dart';
import 'package:didvan/views/ai/history_ai_chat_state.dart'; import 'package:didvan/views/ai/history_ai_chat_state.dart';
import 'package:didvan/views/ai/tool_screen.dart';
import 'package:didvan/views/ai/tools_screen.dart';
import 'package:didvan/views/ai/widgets/message_bar_btn.dart'; import 'package:didvan/views/ai/widgets/message_bar_btn.dart';
import 'package:didvan/views/home/home.dart'; import 'package:didvan/views/home/home.dart';
import 'package:didvan/views/widgets/didvan/text.dart'; import 'package:didvan/views/widgets/didvan/text.dart';
@ -44,6 +47,12 @@ class _AiState extends State<Ai> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Stack(
children: [
Consumer<AiState>(
builder: (BuildContext context, state, Widget? child) {
switch (state.page) {
case 0:
return Consumer<HistoryAiChatState>( return Consumer<HistoryAiChatState>(
builder: (context, state, child) { builder: (context, state, child) {
if (state.bots.isEmpty) { if (state.bots.isEmpty) {
@ -56,9 +65,7 @@ class _AiState extends State<Ai> {
); );
} }
final bot = state.bot!; final bot = state.bot!;
return Stack( return Column(
children: [
Column(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: [ children: [
Expanded( Expanded(
@ -88,18 +95,22 @@ class _AiState extends State<Ai> {
context: context, state: state), context: context, state: state),
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(360), borderRadius:
BorderRadius.circular(360),
border: Border.all( border: Border.all(
width: 1, width: 1,
color: color: Theme.of(context)
Theme.of(context).colorScheme.text)), .colorScheme
.text)),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
vertical: 8.0, horizontal: 18), vertical: 8.0, horizontal: 18),
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment:
mainAxisAlignment: MainAxisAlignment.center, CrossAxisAlignment.center,
mainAxisAlignment:
MainAxisAlignment.center,
children: [ children: [
Row( Row(
mainAxisAlignment: mainAxisAlignment:
@ -110,14 +121,16 @@ class _AiState extends State<Ai> {
Transform.rotate( Transform.rotate(
angle: 180 * pi / 180, angle: 180 * pi / 180,
child: Icon( child: Icon(
DidvanIcons.caret_down_solid, DidvanIcons
.caret_down_solid,
color: Theme.of(context) color: Theme.of(context)
.colorScheme .colorScheme
.title, .title,
), ),
), ),
Icon( Icon(
DidvanIcons.caret_down_solid, DidvanIcons
.caret_down_solid,
color: Theme.of(context) color: Theme.of(context)
.colorScheme .colorScheme
.title, .title,
@ -152,7 +165,8 @@ class _AiState extends State<Ai> {
height: 24, height: 24,
), ),
const Padding( const Padding(
padding: EdgeInsets.symmetric(horizontal: 20.0), padding:
EdgeInsets.symmetric(horizontal: 20.0),
child: Text( child: Text(
"به هوشان؛ هوش مصنوعی دیدوان خوش آمدید. \nبرای شروع گفتگو پیام مورد نظر خود را در کادر زیر بنویسید.", "به هوشان؛ هوش مصنوعی دیدوان خوش آمدید. \nبرای شروع گفتگو پیام مورد نظر خود را در کادر زیر بنویسید.",
textAlign: TextAlign.center, textAlign: TextAlign.center,
@ -178,21 +192,23 @@ class _AiState extends State<Ai> {
Expanded( Expanded(
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
boxShadow: DesignConfig.defaultShadow, boxShadow:
color: DesignConfig.defaultShadow,
Theme.of(context).colorScheme.surface, color: Theme.of(context)
.colorScheme
.surface,
border: Border.all( border: Border.all(
color: Theme.of(context) color: Theme.of(context)
.colorScheme .colorScheme
.border), .border),
borderRadius: borderRadius: DesignConfig
DesignConfig.highBorderRadius), .highBorderRadius),
child: Row( child: Row(
children: [ children: [
Expanded( Expanded(
child: Padding( child: Padding(
padding: padding: const EdgeInsets
const EdgeInsets.symmetric( .symmetric(
horizontal: 8.0, horizontal: 8.0,
), ),
child: Form( child: Form(
@ -206,11 +222,13 @@ class _AiState extends State<Ai> {
width: 8, width: 8,
), ),
Expanded( Expanded(
child: TextFormField( child:
TextFormField(
textInputAction: textInputAction:
TextInputAction TextInputAction
.newline, .newline,
style: Theme.of(context) style: Theme.of(
context)
.textTheme .textTheme
.bodyMedium, .bodyMedium,
minLines: 1, minLines: 1,
@ -218,15 +236,16 @@ class _AiState extends State<Ai> {
decoration: decoration:
InputDecoration( InputDecoration(
border: border:
InputBorder.none, InputBorder
hintText: 'بنویسید...', .none,
hintText:
'بنویسید...',
hintStyle: Theme.of( hintStyle: Theme.of(
context) context)
.textTheme .textTheme
.bodySmall! .bodySmall!
.copyWith( .copyWith(
color: Theme.of( color: Theme.of(context)
context)
.colorScheme .colorScheme
.disabledText), .disabledText),
), ),
@ -237,11 +256,10 @@ class _AiState extends State<Ai> {
), ),
MessageBarBtn( MessageBarBtn(
click: () { click: () {
Navigator.of(context) Navigator.of(context).pushNamed(
.pushNamed( Routes
Routes.aiChat, .aiChat,
arguments: arguments: AiChatArgs(
AiChatArgs(
bot: bot:
bot, bot,
attach: attach:
@ -269,6 +287,19 @@ class _AiState extends State<Ai> {
)), )),
), ),
], ],
);
},
);
case 1:
return const ToolsScreen();
case 2:
return const ToolScreen();
default:
return const SizedBox();
}
},
), ),
Positioned( Positioned(
top: 32, top: 32,
@ -292,7 +323,5 @@ class _AiState extends State<Ai> {
) )
], ],
); );
},
);
} }
} }

View File

@ -13,7 +13,6 @@ import 'package:didvan/models/ai/chats_model.dart';
import 'package:didvan/models/ai/files_model.dart'; import 'package:didvan/models/ai/files_model.dart';
import 'package:didvan/models/ai/messages_model.dart'; import 'package:didvan/models/ai/messages_model.dart';
import 'package:didvan/models/enums.dart'; import 'package:didvan/models/enums.dart';
import 'package:didvan/models/view/action_sheet_data.dart';
import 'package:didvan/models/view/alert_data.dart'; import 'package:didvan/models/view/alert_data.dart';
import 'package:didvan/routes/routes.dart'; import 'package:didvan/routes/routes.dart';
import 'package:didvan/services/media/media.dart'; import 'package:didvan/services/media/media.dart';
@ -25,9 +24,9 @@ import 'package:didvan/views/ai/ai_chat_state.dart';
import 'package:didvan/views/ai/history_ai_chat_state.dart'; import 'package:didvan/views/ai/history_ai_chat_state.dart';
import 'package:didvan/views/ai/widgets/ai_message_bar.dart'; import 'package:didvan/views/ai/widgets/ai_message_bar.dart';
import 'package:didvan/views/ai/widgets/audio_wave.dart'; import 'package:didvan/views/ai/widgets/audio_wave.dart';
import 'package:didvan/views/widgets/didvan/button.dart'; import 'package:didvan/views/ai/widgets/hoshan_drawer.dart';
import 'package:didvan/views/widgets/didvan/icon_button.dart';
import 'package:didvan/views/widgets/didvan/text.dart'; import 'package:didvan/views/widgets/didvan/text.dart';
import 'package:didvan/views/widgets/hoshan_app_bar.dart';
import 'package:didvan/views/widgets/marquee_text.dart'; import 'package:didvan/views/widgets/marquee_text.dart';
import 'package:didvan/views/widgets/skeleton_image.dart'; import 'package:didvan/views/widgets/skeleton_image.dart';
import 'package:didvan/views/widgets/video/chat_video_player.dart'; import 'package:didvan/views/widgets/video/chat_video_player.dart';
@ -49,7 +48,9 @@ class AiChatPage extends StatefulWidget {
} }
class _AiChatPageState extends State<AiChatPage> { class _AiChatPageState extends State<AiChatPage> {
final GlobalKey<ScaffoldState> scaffKey = GlobalKey<ScaffoldState>();
FocusNode focusNode = FocusNode(); FocusNode focusNode = FocusNode();
@override @override
void initState() { void initState() {
final state = context.read<AiChatState>(); final state = context.read<AiChatState>();
@ -101,196 +102,13 @@ class _AiChatPageState extends State<AiChatPage> {
}, },
child: Consumer<AiChatState>( child: Consumer<AiChatState>(
builder: (context, state, child) => Scaffold( builder: (context, state, child) => Scaffold(
appBar: AppBar( appBar: HoshanAppBar(
shadowColor: Theme.of(context).colorScheme.border, onBack: () {
title: Text(widget.args.bot.name.toString()), Navigator.pop(context);
leading: Row(
children: [
DidvanIconButton(
icon: DidvanIcons.angle_right_solid,
onPressed: () {
Navigator.of(context).pop();
if (context.read<HistoryAiChatState>().refresh) {
context.read<HistoryAiChatState>().getChats();
context.read<HistoryAiChatState>().refresh = false;
}
}, },
), ),
], key: scaffKey,
), drawer: const HoshanDrawer(),
actions: [
if (state.chatId != null)
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: InkWell(
onTap: () {
final TextEditingController placeholder =
TextEditingController(
text: state.chat?.placeholder);
ActionSheetUtils(context).openDialog(
data: ActionSheetData(
hasConfirmButtonClose: false,
hasConfirmButton: false,
hasDismissButton: false,
content: ValueListenableBuilder<bool>(
valueListenable: state.changingPlaceHolder,
builder: (context, value, child) =>
Container(
constraints: BoxConstraints(
maxHeight: MediaQuery.sizeOf(context)
.height /
3),
child: Column(
children: [
Expanded(
child: SingleChildScrollView(
child: Column(
children: [
Stack(
children: [
Row(
mainAxisAlignment:
MainAxisAlignment
.center,
children: [
DidvanText(
'شخصی‌سازی دستورات',
style: Theme.of(
context)
.textTheme
.titleMedium,
),
],
),
Positioned(
right: 0,
top: 0,
bottom: 0,
child: Center(
child: InkWell(
onTap: () {
ActionSheetUtils(
context)
.pop();
},
child: const Icon(
DidvanIcons
.close_solid,
size: 24,
),
),
)),
],
),
const SizedBox(
height: 12,
),
const DidvanText(
'دوست دارید هوشان چه چیزهایی را درباره شما بداند تا بتواند پاسخ‌های بهتری ارائه دهد؟ '),
const SizedBox(
height: 12,
),
value
? Center(
child: Image.asset(
Assets
.loadingAnimation,
width: 60,
height: 60,
),
)
: TextField(
controller:
placeholder,
style: (Theme.of(
context)
.textTheme
.bodyMedium)!
.copyWith(
fontFamily: DesignConfig
.fontFamily
.padRight(
3)),
minLines: 5,
maxLines: 5,
keyboardType:
TextInputType
.multiline,
decoration:
InputDecoration(
filled: true,
fillColor: Theme.of(
context)
.colorScheme
.secondCTA,
contentPadding:
const EdgeInsets
.fromLTRB(
10,
18,
10,
0),
border: const OutlineInputBorder(
borderRadius:
DesignConfig
.lowBorderRadius),
errorStyle:
const TextStyle(
height:
0.01),
),
),
],
),
),
),
const SizedBox(
height: 12,
),
Row(
children: [
Expanded(
child: DidvanButton(
onPressed: () {
Navigator.of(context).pop();
},
title: 'بازگشت',
style:
ButtonStyleMode.secondary,
),
),
const SizedBox(width: 20),
Expanded(
child: DidvanButton(
style:
ButtonStyleMode.primary,
onPressed: () async {
await state
.changePlaceHolder(
placeholder.text);
Future.delayed(
Duration.zero,
() => ActionSheetUtils(
context)
.pop(),
);
},
title: 'تایید',
),
),
],
),
],
),
),
)));
},
child: const Icon(DidvanIcons.note_regular)),
)
],
centerTitle: true,
automaticallyImplyLeading: false,
),
body: state.loading body: state.loading
? Center( ? Center(
child: Image.asset( child: Image.asset(
@ -299,52 +117,51 @@ class _AiChatPageState extends State<AiChatPage> {
height: 60, height: 60,
), ),
) )
: state.messages.isEmpty : Stack(
? Column( children: [
Column(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
const SizedBox(
height: 12,
),
Center(
child: Icon(
DidvanIcons.ai_solid,
size: MediaQuery.sizeOf(context).width / 5,
),
),
const DidvanText('هوشان'),
const SizedBox( const SizedBox(
height: 24, height: 24,
), ),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
DidvanText(widget.args.bot.name.toString()),
const SizedBox(
width: 12,
),
ClipOval( ClipOval(
child: CachedNetworkImage( child: CachedNetworkImage(
width: 46, width: 75,
height: 46, height: 75,
imageUrl: widget.args.bot.image.toString(), imageUrl: widget.args.bot.image.toString(),
), ),
), ),
],
),
const SizedBox( const SizedBox(
height: 24, height: 12,
), ),
const Padding( DidvanText(
padding: EdgeInsets.symmetric(horizontal: 20.0), widget.args.bot.name.toString(),
child: Text( fontSize: 17,
"به هوشان؛ هوش مصنوعی دیدوان خوش آمدید. \nبرای شروع گفتگو پیام مورد نظر خود را در کادر زیر بنویسید.", fontWeight: FontWeight.bold,
textAlign: TextAlign.center,
), ),
if (state.messages.isEmpty)
Column(
children: [
const SizedBox(
height: 16,
),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 20.0),
child: Center(
child: DidvanText(
widget.args.bot.description ??
'')),
) )
], ],
) )
: SingleChildScrollView( ],
),
if (state.messages.isNotEmpty)
SingleChildScrollView(
reverse: true, reverse: true,
controller: state.scrollController, controller: state.scrollController,
child: ListView.builder( child: ListView.builder(
@ -357,8 +174,10 @@ class _AiChatPageState extends State<AiChatPage> {
? 180 ? 180
: 100), : 100),
itemBuilder: (context, mIndex) { itemBuilder: (context, mIndex) {
final prompts = state.messages[mIndex].prompts; final prompts =
final time = state.messages[mIndex].dateTime; state.messages[mIndex].prompts;
final time =
state.messages[mIndex].dateTime;
return Column( return Column(
children: [ children: [
timeLabel(context, time), timeLabel(context, time),
@ -370,14 +189,38 @@ class _AiChatPageState extends State<AiChatPage> {
itemBuilder: (context, index) { itemBuilder: (context, index) {
final message = prompts[index]; final message = prompts[index];
return messageBubble(message, context, return messageBubble(message,
state, index, mIndex); context, state, index, mIndex);
}, },
), ),
], ],
); );
}), }),
), ),
],
),
Positioned(
top: 32,
right: 0,
child: InkWell(
onTap: () => scaffKey.currentState!.openDrawer(),
child: Container(
width: 46,
height: 46,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(12),
bottomLeft: Radius.circular(12)),
boxShadow: DesignConfig.defaultShadow),
child: Icon(
DidvanIcons.angle_left_light,
color: Theme.of(context).colorScheme.title,
),
)),
)
],
),
bottomSheet: Column( bottomSheet: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [

View File

@ -0,0 +1,24 @@
import 'package:didvan/models/ai/tools_model.dart';
import 'package:didvan/providers/core.dart';
class AiState extends CoreProvier {
int page = 0;
Tools? tool;
void goToAi() {
page = 0;
update();
}
void goToTools() {
page = 1;
tool = null;
update();
}
void goToToolBox({required final Tools tool}) {
page = 2;
this.tool = tool;
update();
}
}

View File

@ -0,0 +1,119 @@
import 'package:didvan/config/design_config.dart';
import 'package:didvan/models/ai/ai_chat_args.dart';
import 'package:didvan/models/ai/tools_model.dart';
import 'package:didvan/routes/routes.dart';
import 'package:didvan/views/ai/ai_state.dart';
import 'package:didvan/views/widgets/didvan/text.dart';
import 'package:didvan/views/widgets/skeleton_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:provider/provider.dart';
class ToolScreen extends StatefulWidget {
const ToolScreen({Key? key}) : super(key: key);
@override
State<ToolScreen> createState() => _ToolScreenState();
}
class _ToolScreenState extends State<ToolScreen> {
late Tools tool = context.read<AiState>().tool!;
get itemBuilder => null;
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
physics: const BouncingScrollPhysics(),
child: Column(
children: [
const SizedBox(height: 32),
SvgPicture.network(
tool.image!,
width: 64,
height: 64,
),
const SizedBox(
height: 4,
),
DidvanText(
tool.name!,
fontSize: 20,
fontWeight: FontWeight.bold,
color: const Color(0xff1B3C59),
),
const SizedBox(height: 8),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 32),
child: DidvanText(
tool.guide!,
fontSize: 12,
color: const Color(0xff666666),
),
),
const SizedBox(height: 24),
GridView.builder(
shrinkWrap: true,
itemCount: tool.bots!.length,
physics: const NeverScrollableScrollPhysics(),
padding: const EdgeInsets.symmetric(horizontal: 32),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 1 / 1,
crossAxisSpacing: 18,
mainAxisSpacing: 18),
itemBuilder: (context, index) {
final bot = tool.bots![index];
return InkWell(
onTap: () => Navigator.of(context).pushNamed(Routes.aiChat,
arguments: AiChatArgs(
bot: bot,
)),
child: Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
borderRadius: DesignConfig.lowBorderRadius,
border: Border.all(color: const Color(0xffbbbbbb))),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SkeletonImage(
imageUrl: bot.image!,
width: 72,
height: 72,
borderRadius: BorderRadius.circular(360),
),
const SizedBox(
height: 4,
),
DidvanText(
bot.name!,
fontSize: 16,
fontWeight: FontWeight.bold,
color: const Color(0xff2A282F),
),
if (bot.description != null)
Column(
children: [
const SizedBox(
height: 4,
),
DidvanText(
bot.description!,
fontSize: 14,
fontWeight: FontWeight.bold,
color: const Color(0xffA8A6AC),
),
],
)
],
),
),
);
},
)
],
),
);
}
}

View File

@ -0,0 +1,215 @@
import 'package:didvan/config/design_config.dart';
import 'package:didvan/constants/assets.dart';
import 'package:didvan/views/ai/ai_state.dart';
import 'package:didvan/views/ai/tools_state.dart';
import 'package:didvan/views/widgets/didvan/text.dart';
import 'package:didvan/views/widgets/shimmer_placeholder.dart';
import 'package:didvan/views/widgets/state_handlers/empty_state.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:provider/provider.dart';
class ToolsScreen extends StatefulWidget {
const ToolsScreen({Key? key}) : super(key: key);
@override
State<ToolsScreen> createState() => _ToolsScreenState();
}
class _ToolsScreenState extends State<ToolsScreen> {
@override
void initState() {
super.initState();
context.read<ToolsState>().getTools();
}
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
physics: context.watch<ToolsState>().loading
? const NeverScrollableScrollPhysics()
: const BouncingScrollPhysics(),
child: Column(
children: [
const Padding(
padding: EdgeInsets.only(top: 46, bottom: 24),
child: DidvanText(
'انتخاب بات‌ها',
fontSize: 20,
fontWeight: FontWeight.bold,
color: Color(0xff1B3C59),
),
),
Consumer<ToolsState>(
builder: (BuildContext context, ToolsState state, Widget? child) {
final tools = state.tools;
if (tools != null && tools.isEmpty) {
return EmptyState(
asset: Assets.emptyResult,
title: 'لیست خالی است',
);
}
if (state.loading) {
return toolsPlaceHolder();
}
return ListView.builder(
itemCount: tools!.length,
shrinkWrap: true,
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 24)
.copyWith(bottom: 46),
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
final tool = tools[index];
return InkWell(
onTap: () =>
context.read<AiState>().goToToolBox(tool: tool),
child: Container(
decoration: BoxDecoration(
borderRadius: DesignConfig.lowBorderRadius,
border: Border.all(
color: const Color(0xffB8B8B8),
),
),
padding: const EdgeInsets.all(24),
margin: const EdgeInsets.symmetric(vertical: 8),
child: Row(
children: [
SvgPicture.network(
tool.image!,
width: 75,
height: 75,
),
const SizedBox(
width: 8,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
DidvanText(
tool.name!,
fontSize: 16,
fontWeight: FontWeight.bold,
),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 8, vertical: 2),
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(4),
color: Theme.of(context)
.colorScheme
.primary),
child: DidvanText(
'${tool.bots!.length} مدل',
color: Colors.white,
fontSize: 12,
fontWeight: FontWeight.bold,
),
)
],
),
DidvanText(
'${tool.bots!.map(
(e) => e.name!,
)}'
.replaceAll('(', '')
.replaceAll(')', ''),
fontSize: 12,
color: Theme.of(context).colorScheme.primary,
),
DidvanText(tool.description!,
fontSize: 12, color: const Color(0xffA8A6AC))
],
),
)
],
),
),
);
},
);
},
)
],
),
);
}
ListView toolsPlaceHolder() {
return ListView.builder(
itemCount: 10,
shrinkWrap: true,
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 24),
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return Container(
decoration: BoxDecoration(
borderRadius: DesignConfig.lowBorderRadius,
border: Border.all(
color: const Color(0xffB8B8B8),
),
),
padding: const EdgeInsets.all(24),
margin: const EdgeInsets.symmetric(vertical: 8),
child: Row(
children: [
ShimmerPlaceholder(
width: 75,
height: 75,
borderRadius: BorderRadius.circular(360),
),
const SizedBox(
width: 8,
),
const Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ShimmerPlaceholder(
width: 120,
height: 24,
borderRadius: DesignConfig.mediumBorderRadius,
),
ShimmerPlaceholder(
width: 60,
height: 24,
borderRadius: DesignConfig.mediumBorderRadius,
),
],
),
SizedBox(
height: 8,
),
ShimmerPlaceholder(
width: 120,
height: 24,
borderRadius: DesignConfig.mediumBorderRadius,
),
SizedBox(
height: 8,
),
ShimmerPlaceholder(
width: 240,
height: 46,
borderRadius: DesignConfig.mediumBorderRadius,
),
],
),
)
],
),
);
},
);
}
}

View File

@ -0,0 +1,29 @@
import 'package:didvan/models/ai/tools_model.dart';
import 'package:didvan/models/enums.dart';
import 'package:didvan/providers/core.dart';
import 'package:didvan/services/network/request.dart';
import 'package:didvan/services/network/request_helper.dart';
class ToolsState extends CoreProvier {
bool loading = true;
List<Tools>? tools;
void getTools() async {
final service = RequestService(
RequestHelper.tools(),
);
await service.httpGet();
if (service.isSuccess) {
final ToolsModel toolsModel = ToolsModel.fromJson(service.result);
tools = toolsModel.tools!;
tools ??= [];
appState = AppState.idle;
loading = false;
update();
return;
}
appState = AppState.failed;
loading = false;
update();
}
}

View File

@ -0,0 +1,475 @@
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/ai/chats_model.dart';
import 'package:didvan/models/enums.dart';
import 'package:didvan/models/view/action_sheet_data.dart';
import 'package:didvan/models/view/alert_data.dart';
import 'package:didvan/routes/routes.dart';
import 'package:didvan/utils/action_sheet.dart';
import 'package:didvan/views/ai/history_ai_chat_state.dart';
import 'package:didvan/views/home/home.dart';
import 'package:didvan/views/widgets/didvan/divider.dart';
import 'package:didvan/views/widgets/didvan/text.dart';
import 'package:didvan/views/widgets/shimmer_placeholder.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:provider/provider.dart';
class HoshanDrawer extends StatefulWidget {
const HoshanDrawer({Key? key}) : super(key: key);
@override
State<HoshanDrawer> createState() => _HoshanDrawerState();
}
class _HoshanDrawerState extends State<HoshanDrawer> {
@override
Widget build(BuildContext context) {
return Drawer(
child: Consumer<HistoryAiChatState>(
builder: (context, state, child) {
return Column(
children: [
const SizedBox(
height: 8,
),
Padding(
padding: const EdgeInsets.only(left: 20.0, top: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
InkWell(
onTap: () => homeScaffKey.currentState!.closeDrawer(),
child: const Icon(
DidvanIcons.close_regular,
),
)
],
),
),
Icon(
DidvanIcons.ai_solid,
size: MediaQuery.sizeOf(context).width / 5,
color: Theme.of(context).colorScheme.title,
),
DidvanText(
'هوشان',
color: Theme.of(context).colorScheme.title,
),
const SizedBox(
height: 24,
),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
children: [
drawerBtn(
icon: Icons.handshake_rounded,
text: 'ساخت دستیار شخصی',
crossAxisAlignment: CrossAxisAlignment.start,
enable: false),
const DidvanDivider(),
drawerBtn(
icon: CupertinoIcons.doc_text_search,
text: 'جستجو در مدل‌ها',
click: () {
ActionSheetUtils(context).botsDialogSelect(
context: context, state: state);
homeScaffKey.currentState!.closeDrawer();
},
enable: false),
const DidvanDivider(),
drawerBtn(
icon: DidvanIcons.chats_regular,
text: 'تاریخچه همه گفتگوها',
label: 'حذف همه',
click: () {
Navigator.of(context)
.pushNamed(Routes.aiHistory);
},
labelClick: state.chats.isEmpty
? null
: () async {
await ActionSheetUtils(context)
.openDialog(
data: ActionSheetData(
onConfirmed: () async {
await state.deleteAllChat(
refresh: false);
},
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(
'آیا از پاک کردن تمامی گفت‌وگوهای انجام شده با هوشان اطمینان دارید؟'),
],
)));
},
),
const SizedBox(
height: 12,
),
// SearchField(
// title: 'title',
// onChanged: (value) {},
// focusNode: FocusNode()),
// SizedBox(
// height: 12,
// ),
Expanded(
child: state.loadingdeleteAll ||
state.appState == AppState.busy
? ListView.builder(
shrinkWrap: true,
itemCount: 10,
padding: const EdgeInsets.symmetric(
horizontal: 12),
physics:
const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return const Padding(
padding: EdgeInsets.symmetric(
vertical: 12.0),
child: Row(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
ClipOval(
child: ShimmerPlaceholder(
height: 24,
width: 24,
),
),
SizedBox(width: 12),
Expanded(
child: ShimmerPlaceholder(
height: 24,
),
),
SizedBox(width: 12),
ShimmerPlaceholder(
height: 24,
width: 24,
),
SizedBox(width: 8),
ShimmerPlaceholder(
height: 24,
width: 12,
),
],
),
);
},
)
: state.chats.isEmpty
? Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
children: [
SvgPicture.asset(
Assets.emptyResult,
height:
MediaQuery.sizeOf(context)
.height /
10,
),
const DidvanText(
'لیست خالی است',
fontSize: 14,
fontWeight: FontWeight.bold,
)
],
),
)
: ListView.builder(
shrinkWrap: true,
itemCount: state.chats.length,
padding: const EdgeInsets.symmetric(
horizontal: 12),
physics:
const BouncingScrollPhysics(),
itemBuilder: (context, index) {
final chat = state.chats[index];
TextEditingController title =
TextEditingController(
text: chat.title);
return chatRow(
chat, title, state, index);
},
),
),
// SizedBox(
// height: 12,
// ),
// Text('نمایش قدیمی‌ترها')
],
),
),
Column(
children: [
const DidvanDivider(),
drawerBtn(
icon: Icons.folder_copy_outlined,
text: 'گفت‌وگوهای آرشیو شده',
click: () {
Navigator.of(context)
.pushNamed(Routes.aiHistory, arguments: true);
},
),
const SizedBox(
height: 12,
),
drawerBtn(
icon: DidvanIcons.support_regular,
text: 'پیام به پشتیبانی',
click: () {
Navigator.of(context).pushNamed(
Routes.direct,
arguments: {'type': 'پشتیبانی اپلیکیشن'},
);
},
),
],
)
],
),
),
),
const SizedBox(
height: 32,
)
],
);
},
),
);
}
Widget drawerBtn(
{final CrossAxisAlignment? crossAxisAlignment,
required final IconData icon,
required final String text,
final bool enable = true,
final String? label,
final Function()? labelClick,
final Function()? click}) {
return InkWell(
onTap: enable
? click
: () {
ActionSheetUtils(context).showAlert(
AlertData(message: 'درحال توسعه', aLertType: ALertType.info));
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
crossAxisAlignment:
crossAxisAlignment ?? CrossAxisAlignment.center,
children: [
Icon(
icon,
color: enable
? Theme.of(context).colorScheme.title
: Theme.of(context).colorScheme.disabledText,
),
const SizedBox(
width: 8,
),
Column(
children: [
DidvanText(text,
fontSize: 16,
color: enable
? Theme.of(context).colorScheme.title
: Theme.of(context).colorScheme.disabledText),
// if (!enable) Text('در حال توسعه ...')
],
)
],
),
if (label != null)
InkWell(
onTap: labelClick,
child: DidvanText(
label,
color: Theme.of(context).colorScheme.primary,
fontSize: 12,
),
)
],
),
),
);
}
Padding chatRow(ChatsModel chat, TextEditingController title,
HistoryAiChatState state, int index) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: InkWell(
onTap: () {
navigatorKey.currentState!.pushNamed(Routes.aiChat,
arguments: AiChatArgs(bot: chat.bot!, chat: chat));
},
child: Row(
children: [
ClipOval(
child: CachedNetworkImage(
imageUrl: chat.bot!.image.toString(),
width: 24,
height: 24,
)),
const SizedBox(
width: 12,
),
Expanded(
child: Text(
chat.title.toString(),
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
),
const SizedBox(
width: 24,
),
Row(
children: [
InkWell(
onTap: () async {
ActionSheetUtils(context).openDialog(
data: ActionSheetData(
content: Center(
child: TextFormField(
controller: title,
style: const TextStyle(fontSize: 12),
textAlignVertical: TextAlignVertical.bottom,
maxLines: 3,
decoration: const InputDecoration(
isDense: true,
contentPadding: EdgeInsets.symmetric(
vertical: 5, horizontal: 10),
border: OutlineInputBorder(),
)),
),
title: 'تغییر نام',
onConfirmed: () async {
if (title.text.isNotEmpty) {
await state.changeNameChat(
chat.id!, index, title.text,
refresh: false);
title.clear();
}
if (chat.isEditing != null) {
chat.isEditing = !chat.isEditing!;
state.update();
return;
}
state.update();
},
));
},
child: const Padding(
padding: EdgeInsets.all(8.0),
child: Icon(
Icons.edit_outlined,
size: 20,
),
),
),
const SizedBox(
width: 4,
),
PopupMenuButton(
onSelected: (value) async {
switch (value) {
case 'حذف پیام':
await state.deleteChat(chat.id!, index, refresh: false);
break;
case 'آرشیو':
await state.archivedChat(chat.id!, index,
refresh: false);
break;
default:
}
state.update();
},
itemBuilder: (BuildContext context) {
return <PopupMenuEntry>[
ActionSheetUtils.popUpBtns(
value: 'حذف پیام',
icon: DidvanIcons.trash_regular,
color: Theme.of(context).colorScheme.error,
height: 32,
size: 16),
ActionSheetUtils.popUpBtns(
value: 'آرشیو',
icon: Icons.folder_copy,
height: 32,
size: 16,
),
];
},
offset: const Offset(0, 0),
position: PopupMenuPosition.under,
useRootNavigator: true,
child: const Padding(
padding: EdgeInsets.all(8.0),
child: Icon(
Icons.more_vert,
size: 20,
),
),
),
],
)
],
),
),
);
}
}

View File

@ -1,40 +1,33 @@
// ignore_for_file: deprecated_member_use // ignore_for_file: deprecated_member_use
import 'package:cached_network_image/cached_network_image.dart';
import 'package:didvan/config/design_config.dart'; import 'package:didvan/config/design_config.dart';
import 'package:didvan/config/theme_data.dart'; import 'package:didvan/config/theme_data.dart';
import 'package:didvan/constants/app_icons.dart'; import 'package:didvan/constants/app_icons.dart';
import 'package:didvan/constants/assets.dart';
import 'package:didvan/main.dart'; import 'package:didvan/main.dart';
import 'package:didvan/models/ai/ai_chat_args.dart';
import 'package:didvan/models/ai/chats_model.dart';
import 'package:didvan/models/enums.dart';
import 'package:didvan/models/notification_message.dart'; import 'package:didvan/models/notification_message.dart';
import 'package:didvan/models/view/action_sheet_data.dart'; import 'package:didvan/models/view/action_sheet_data.dart';
import 'package:didvan/models/view/alert_data.dart';
import 'package:didvan/providers/theme.dart'; import 'package:didvan/providers/theme.dart';
import 'package:didvan/routes/routes.dart'; import 'package:didvan/routes/routes.dart';
import 'package:didvan/services/app_initalizer.dart'; import 'package:didvan/services/app_initalizer.dart';
import 'package:didvan/services/notification/notification_service.dart'; import 'package:didvan/services/notification/notification_service.dart';
import 'package:didvan/utils/action_sheet.dart'; import 'package:didvan/utils/action_sheet.dart';
import 'package:didvan/views/ai/ai.dart'; import 'package:didvan/views/ai/ai.dart';
import 'package:didvan/views/ai/ai_state.dart';
import 'package:didvan/views/ai/history_ai_chat_state.dart'; import 'package:didvan/views/ai/history_ai_chat_state.dart';
import 'package:didvan/views/ai/widgets/hoshan_drawer.dart';
import 'package:didvan/views/home/categories/categories_page.dart'; import 'package:didvan/views/home/categories/categories_page.dart';
import 'package:didvan/views/home/main/main_page.dart'; import 'package:didvan/views/home/main/main_page.dart';
import 'package:didvan/views/home/home_state.dart'; import 'package:didvan/views/home/home_state.dart';
import 'package:didvan/views/home/new_statistic/new_statistic.dart'; import 'package:didvan/views/home/new_statistic/new_statistic.dart';
import 'package:didvan/views/home/search/search.dart'; import 'package:didvan/views/home/search/search.dart';
import 'package:didvan/views/widgets/didvan/divider.dart';
import 'package:didvan/views/widgets/didvan/text.dart'; import 'package:didvan/views/widgets/didvan/text.dart';
import 'package:didvan/views/widgets/hoshan_app_bar.dart';
import 'package:didvan/views/widgets/ink_wrapper.dart'; import 'package:didvan/views/widgets/ink_wrapper.dart';
import 'package:didvan/views/widgets/logo_app_bar.dart'; import 'package:didvan/views/widgets/logo_app_bar.dart';
import 'package:didvan/views/widgets/didvan/bnb.dart'; import 'package:didvan/views/widgets/didvan/bnb.dart';
import 'package:didvan/views/widgets/shimmer_placeholder.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import '../../services/app_home_widget/home_widget_repository.dart'; import '../../services/app_home_widget/home_widget_repository.dart';
@ -172,290 +165,32 @@ class _HomeState extends State<Home>
super.initState(); super.initState();
} }
PreferredSizeWidget getAppBar() {
PreferredSizeWidget result = const LogoAppBar();
if (context.watch<HomeState>().tabController.index == 2) {
result = HoshanAppBar(
onBack: () {
final state = context.read<AiState>();
if (state.page == 1) {
state.goToAi();
} else {
state.goToTools();
}
},
);
}
return result;
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
key: homeScaffKey, key: homeScaffKey,
appBar: LogoAppBar( appBar: getAppBar(),
canSearch: context.watch<HomeState>().tabController.index != 2,
),
resizeToAvoidBottomInset: false, resizeToAvoidBottomInset: false,
drawer: context.watch<HomeState>().tabController.index == 2 drawer: context.watch<HomeState>().tabController.index == 2
? Drawer( ? const HoshanDrawer()
child: Consumer<HistoryAiChatState>(
builder: (context, state, child) {
return Column(
children: [
const SizedBox(
height: 8,
),
Padding(
padding: const EdgeInsets.only(left: 20.0, top: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
InkWell(
onTap: () =>
homeScaffKey.currentState!.closeDrawer(),
child: const Icon(
DidvanIcons.close_regular,
),
)
],
),
),
Icon(
DidvanIcons.ai_solid,
size: MediaQuery.sizeOf(context).width / 5,
color: Theme.of(context).colorScheme.title,
),
DidvanText(
'هوشان',
color: Theme.of(context).colorScheme.title,
),
const SizedBox(
height: 24,
),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
children: [
drawerBtn(
icon: Icons.handshake_rounded,
text: 'ساخت دستیار شخصی',
crossAxisAlignment:
CrossAxisAlignment.start,
enable: false),
const DidvanDivider(),
drawerBtn(
icon: CupertinoIcons.doc_text_search,
text: 'جستجو در مدل‌ها',
click: () {
ActionSheetUtils(context)
.botsDialogSelect(
context: context,
state: state);
homeScaffKey.currentState!
.closeDrawer();
},
enable: false),
const DidvanDivider(),
drawerBtn(
icon: DidvanIcons.chats_regular,
text: 'تاریخچه همه گفتگوها',
label: 'حذف همه',
click: () {
Navigator.of(context)
.pushNamed(Routes.aiHistory);
},
labelClick: state.chats.isEmpty
? null
: () async {
await ActionSheetUtils(context)
.openDialog(
data: ActionSheetData(
onConfirmed:
() async {
await state
.deleteAllChat(
refresh:
false);
},
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(
'آیا از پاک کردن تمامی گفت‌وگوهای انجام شده با هوشان اطمینان دارید؟'),
],
)));
},
),
const SizedBox(
height: 12,
),
// SearchField(
// title: 'title',
// onChanged: (value) {},
// focusNode: FocusNode()),
// SizedBox(
// height: 12,
// ),
Expanded(
child: state.loadingdeleteAll ||
state.appState == AppState.busy
? ListView.builder(
shrinkWrap: true,
itemCount: 10,
padding:
const EdgeInsets.symmetric(
horizontal: 12),
physics:
const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return const Padding(
padding: EdgeInsets.symmetric(
vertical: 12.0),
child: Row(
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [
ClipOval(
child:
ShimmerPlaceholder(
height: 24,
width: 24,
),
),
SizedBox(width: 12),
Expanded(
child:
ShimmerPlaceholder(
height: 24,
),
),
SizedBox(width: 12),
ShimmerPlaceholder(
height: 24,
width: 24,
),
SizedBox(width: 8),
ShimmerPlaceholder(
height: 24,
width: 12,
),
],
),
);
},
)
: state.chats.isEmpty
? Padding(
padding: const EdgeInsets.all(
12.0),
child: Column(
children: [
SvgPicture.asset(
Assets.emptyResult,
height:
MediaQuery.sizeOf(
context)
.height /
10,
),
const DidvanText(
'لیست خالی است',
fontSize: 14,
fontWeight:
FontWeight.bold,
)
],
),
)
: ListView.builder(
shrinkWrap: true,
itemCount: state.chats.length,
padding: const EdgeInsets
.symmetric(
horizontal: 12),
physics:
const BouncingScrollPhysics(),
itemBuilder:
(context, index) {
final chat =
state.chats[index];
TextEditingController
title =
TextEditingController(
text: chat.title);
return chatRow(chat, title,
state, index);
},
),
),
// SizedBox(
// height: 12,
// ),
// Text('نمایش قدیمی‌ترها')
],
),
),
Column(
children: [
const DidvanDivider(),
drawerBtn(
icon: Icons.folder_copy_outlined,
text: 'گفت‌وگوهای آرشیو شده',
click: () {
Navigator.of(context).pushNamed(
Routes.aiHistory,
arguments: true);
},
),
const SizedBox(
height: 12,
),
drawerBtn(
icon: DidvanIcons.support_regular,
text: 'پیام به پشتیبانی',
click: () {
Navigator.of(context).pushNamed(
Routes.direct,
arguments: {
'type': 'پشتیبانی اپلیکیشن'
},
);
},
),
],
)
],
),
),
),
const SizedBox(
height: 32,
)
],
);
},
),
)
: null, : null,
body: WillPopScope( body: WillPopScope(
onWillPop: () async { onWillPop: () async {
@ -519,193 +254,4 @@ class _HomeState extends State<Home>
), ),
); );
} }
Padding chatRow(ChatsModel chat, TextEditingController title,
HistoryAiChatState state, int index) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: InkWell(
onTap: () {
navigatorKey.currentState!.pushNamed(Routes.aiChat,
arguments: AiChatArgs(bot: chat.bot!, chat: chat));
},
child: Row(
children: [
ClipOval(
child: CachedNetworkImage(
imageUrl: chat.bot!.image.toString(),
width: 24,
height: 24,
)),
const SizedBox(
width: 12,
),
Expanded(
child: Text(
chat.title.toString(),
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
),
const SizedBox(
width: 24,
),
Row(
children: [
InkWell(
onTap: () async {
ActionSheetUtils(context).openDialog(
data: ActionSheetData(
content: Center(
child: TextFormField(
controller: title,
style: const TextStyle(fontSize: 12),
textAlignVertical: TextAlignVertical.bottom,
maxLines: 3,
decoration: const InputDecoration(
isDense: true,
contentPadding: EdgeInsets.symmetric(
vertical: 5, horizontal: 10),
border: OutlineInputBorder(),
)),
),
title: 'تغییر نام',
onConfirmed: () async {
if (title.text.isNotEmpty) {
await state.changeNameChat(
chat.id!, index, title.text,
refresh: false);
title.clear();
}
if (chat.isEditing != null) {
chat.isEditing = !chat.isEditing!;
state.update();
return;
}
state.update();
},
));
},
child: const Padding(
padding: EdgeInsets.all(8.0),
child: Icon(
Icons.edit_outlined,
size: 20,
),
),
),
const SizedBox(
width: 4,
),
PopupMenuButton(
onSelected: (value) async {
switch (value) {
case 'حذف پیام':
await state.deleteChat(chat.id!, index, refresh: false);
break;
case 'آرشیو':
await state.archivedChat(chat.id!, index,
refresh: false);
break;
default:
}
state.update();
},
itemBuilder: (BuildContext context) {
return <PopupMenuEntry>[
ActionSheetUtils.popUpBtns(
value: 'حذف پیام',
icon: DidvanIcons.trash_regular,
color: Theme.of(context).colorScheme.error,
height: 32,
size: 16),
ActionSheetUtils.popUpBtns(
value: 'آرشیو',
icon: Icons.folder_copy,
height: 32,
size: 16,
),
];
},
offset: const Offset(0, 0),
position: PopupMenuPosition.under,
useRootNavigator: true,
child: const Padding(
padding: EdgeInsets.all(8.0),
child: Icon(
Icons.more_vert,
size: 20,
),
),
),
],
)
],
),
),
);
}
Widget drawerBtn(
{final CrossAxisAlignment? crossAxisAlignment,
required final IconData icon,
required final String text,
final bool enable = true,
final String? label,
final Function()? labelClick,
final Function()? click}) {
return InkWell(
onTap: enable
? click
: () {
ActionSheetUtils(context).showAlert(
AlertData(message: 'درحال توسعه', aLertType: ALertType.info));
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
crossAxisAlignment:
crossAxisAlignment ?? CrossAxisAlignment.center,
children: [
Icon(
icon,
color: enable
? Theme.of(context).colorScheme.title
: Theme.of(context).colorScheme.disabledText,
),
const SizedBox(
width: 8,
),
Column(
children: [
DidvanText(text,
fontSize: 16,
color: enable
? Theme.of(context).colorScheme.title
: Theme.of(context).colorScheme.disabledText),
// if (!enable) Text('در حال توسعه ...')
],
)
],
),
if (label != null)
InkWell(
onTap: labelClick,
child: DidvanText(
label,
color: Theme.of(context).colorScheme.primary,
fontSize: 12,
),
)
],
),
),
);
}
} }

View File

@ -0,0 +1,90 @@
import 'dart:math';
import 'package:didvan/constants/app_icons.dart';
import 'package:didvan/constants/assets.dart';
import 'package:didvan/views/ai/ai_state.dart';
import 'package:didvan/views/widgets/didvan/icon_button.dart';
import 'package:didvan/views/widgets/didvan/text.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class HoshanAppBar extends StatelessWidget implements PreferredSizeWidget {
final Function()? onBack;
const HoshanAppBar({Key? key, this.onBack}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(20),
bottomRight: Radius.circular(20)),
color: Theme.of(context).colorScheme.surface,
boxShadow: [
BoxShadow(
color: const Color(0XFF1B3C59).withOpacity(0.15),
blurRadius: 8,
spreadRadius: 0,
offset: const Offset(0, 8),
)
],
),
padding: const EdgeInsets.all(16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Row(
children: [
Icon(
DidvanIcons.ai_solid,
size: 40,
),
DidvanText(
'هوشان',
fontSize: 14,
fontWeight: FontWeight.bold,
),
],
),
Row(
children: [
DidvanIconButton(
icon: DidvanIcons.info_circle_light,
size: 32,
onPressed: () {}),
DidvanIconButton(
icon: DidvanIcons.antenna_light,
size: 32,
onPressed: () {},
),
context.watch<AiState>().page != 0
? Transform.rotate(
angle: 180 * pi / 180,
child: DidvanIconButton(
icon: DidvanIcons.back_light,
size: 32,
onPressed: () => onBack?.call(),
),
)
: InkWell(
onTap: () {
context.read<AiState>().goToTools();
},
child: Padding(
padding: const EdgeInsets.only(right: 8.0),
child: Image.asset(
Assets.boxAnimation,
width: 38,
height: 38,
),
),
),
],
)
],
));
}
@override
Size get preferredSize => const Size(double.infinity, 144);
}