fix bugs
This commit is contained in:
parent
7bec995377
commit
f28592c421
|
|
@ -16,6 +16,7 @@ import 'package:didvan/views/widgets/skeleton_image.dart';
|
|||
import 'package:didvan/views/widgets/state_handlers/empty_state.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class ActionSheetUtils {
|
||||
final BuildContext context;
|
||||
|
|
@ -286,118 +287,83 @@ class ActionSheetUtils {
|
|||
);
|
||||
}
|
||||
|
||||
Future<void> botsDialogSelect(
|
||||
{required final BuildContext context,
|
||||
required final HistoryAiChatState state}) async {
|
||||
Future<void> botsDialogSelect({
|
||||
required final BuildContext context,
|
||||
}) async {
|
||||
ActionSheetUtils(context).openDialog(
|
||||
data: ActionSheetData(
|
||||
hasConfirmButton: false,
|
||||
hasDismissButton: false,
|
||||
content: Column(
|
||||
children: [
|
||||
// Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.end,
|
||||
// children: [
|
||||
// Padding(
|
||||
// padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
// child: InkWell(
|
||||
// onTap: () {
|
||||
// ActionSheetUtils.pop();
|
||||
// },
|
||||
// child: const Icon(DidvanIcons.close_solid)),
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// SearchField(
|
||||
// title: 'هوش مصنوعی',
|
||||
// value: state.search,
|
||||
// onChanged: (value) {
|
||||
// state.search = value;
|
||||
// if (value.isEmpty) {
|
||||
// state.getBots();
|
||||
// return;
|
||||
// }
|
||||
// state.timer?.cancel();
|
||||
// state.timer = Timer(const Duration(seconds: 1), () {
|
||||
// state.getSearchBots(value);
|
||||
// });
|
||||
// },
|
||||
// focusNode: FocusNode()),
|
||||
// const SizedBox(
|
||||
// height: 12,
|
||||
// ),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
height: MediaQuery.sizeOf(context).height / 3,
|
||||
child: ValueListenableBuilder<bool>(
|
||||
valueListenable: state.loadingBots,
|
||||
builder: (context, value, child) => value
|
||||
? Center(
|
||||
child: Image.asset(
|
||||
Assets.loadingAnimation,
|
||||
width: 60,
|
||||
height: 60,
|
||||
content: SizedBox(
|
||||
width: double.infinity,
|
||||
height: MediaQuery.sizeOf(context).height / 3,
|
||||
child: Consumer<HistoryAiChatState>(
|
||||
builder: (context, state, child) {
|
||||
return state.loadingBots
|
||||
? Center(
|
||||
child: Image.asset(
|
||||
Assets.loadingAnimation,
|
||||
width: 60,
|
||||
height: 60,
|
||||
),
|
||||
)
|
||||
: state.bots.isEmpty
|
||||
? Padding(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 12.0),
|
||||
child: EmptyState(
|
||||
asset: Assets.emptyResult,
|
||||
title: 'نتیجهای پیدا نشد',
|
||||
height: 120,
|
||||
),
|
||||
)
|
||||
: state.bots.isEmpty
|
||||
? Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 12.0),
|
||||
child: EmptyState(
|
||||
asset: Assets.emptyResult,
|
||||
title: 'نتیجهای پیدا نشد',
|
||||
height: 120,
|
||||
),
|
||||
)
|
||||
: ListView.builder(
|
||||
itemCount: state.bots.length,
|
||||
physics: const BouncingScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
itemBuilder: (context, index) {
|
||||
final bot = state.bots[index];
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
ActionSheetUtils(context).pop();
|
||||
state.bot = bot;
|
||||
state.update();
|
||||
},
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 8),
|
||||
decoration: BoxDecoration(
|
||||
border: index == state.bots.length - 1
|
||||
? null
|
||||
: Border(
|
||||
bottom: BorderSide(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.border,
|
||||
width: 1))),
|
||||
child: Row(
|
||||
children: [
|
||||
SkeletonImage(
|
||||
imageUrl: bot.image.toString(),
|
||||
width: 42,
|
||||
height: 42,
|
||||
borderRadius:
|
||||
BorderRadius.circular(360),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: DidvanText(
|
||||
bot.name.toString(),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
))
|
||||
],
|
||||
: ListView.builder(
|
||||
itemCount: state.bots.length,
|
||||
physics: const BouncingScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
itemBuilder: (context, index) {
|
||||
final bot = state.bots[index];
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
ActionSheetUtils(context).pop();
|
||||
state.bot = bot;
|
||||
state.update();
|
||||
},
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
padding:
|
||||
const EdgeInsets.symmetric(vertical: 8),
|
||||
decoration: BoxDecoration(
|
||||
border: index == state.bots.length - 1
|
||||
? null
|
||||
: Border(
|
||||
bottom: BorderSide(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.border,
|
||||
width: 1))),
|
||||
child: Row(
|
||||
children: [
|
||||
SkeletonImage(
|
||||
imageUrl: bot.image.toString(),
|
||||
width: 42,
|
||||
height: 42,
|
||||
borderRadius:
|
||||
BorderRadius.circular(360),
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
)
|
||||
],
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: DidvanText(
|
||||
bot.name.toString(),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
))
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
}),
|
||||
)));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,9 +34,9 @@ class _AiState extends State<Ai> {
|
|||
Future.delayed(
|
||||
Duration.zero,
|
||||
() {
|
||||
if (context.read<HistoryAiChatState>().refresh) {
|
||||
context.read<HistoryAiChatState>().getChats();
|
||||
context.read<HistoryAiChatState>().refresh = false;
|
||||
if (state.refresh) {
|
||||
state.getBots();
|
||||
state.refresh = false;
|
||||
}
|
||||
state.getBots();
|
||||
},
|
||||
|
|
@ -85,8 +85,7 @@ class _AiState extends State<Ai> {
|
|||
),
|
||||
InkWell(
|
||||
onTap: () => ActionSheetUtils(context)
|
||||
.botsDialogSelect(
|
||||
context: context, state: state),
|
||||
.botsDialogSelect(context: context),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius:
|
||||
|
|
@ -287,26 +286,29 @@ class _AiState extends State<Ai> {
|
|||
}
|
||||
},
|
||||
),
|
||||
Positioned(
|
||||
top: 32,
|
||||
right: 0,
|
||||
child: InkWell(
|
||||
onTap: () => homeScaffKey.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,
|
||||
),
|
||||
)),
|
||||
)
|
||||
Consumer<HistoryAiChatState>(builder: (context, state, child) {
|
||||
if (state.bots.isEmpty) return const SizedBox();
|
||||
return Positioned(
|
||||
top: 32,
|
||||
right: 0,
|
||||
child: InkWell(
|
||||
onTap: () => homeScaffKey.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,
|
||||
),
|
||||
)),
|
||||
);
|
||||
})
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ class _CreateBotAssistantsPageState extends State<CreateBotAssistantsPage> {
|
|||
super.initState();
|
||||
}
|
||||
|
||||
void onConfirm(CreateBotAssistantsState state, int selectedBotId) async {
|
||||
void onConfirm(CreateBotAssistantsState state) async {
|
||||
bool isValid = true;
|
||||
// if (!_formYouTubeKey.currentState!.validate()) {
|
||||
// isValid = false;
|
||||
|
|
@ -95,7 +95,7 @@ class _CreateBotAssistantsPageState extends State<CreateBotAssistantsPage> {
|
|||
type: state.selectedBotType,
|
||||
name: state.name,
|
||||
description: state.desc,
|
||||
botId: selectedBotId,
|
||||
botId: state.initialBot!.id!,
|
||||
prompt: state.prompt,
|
||||
webLinks:
|
||||
state.countOfLink.first.isEmpty ? null : state.countOfLink,
|
||||
|
|
@ -135,9 +135,6 @@ class _CreateBotAssistantsPageState extends State<CreateBotAssistantsPage> {
|
|||
),
|
||||
body: Consumer<CreateBotAssistantsState>(builder: (BuildContext context,
|
||||
CreateBotAssistantsState state, Widget? child) {
|
||||
int selectedBotId = state.selectedBotType == 'text'
|
||||
? state.allBots.first.id!
|
||||
: state.imageBots.first.id!;
|
||||
return state.loading
|
||||
? Center(
|
||||
child: SpinKitThreeBounce(
|
||||
|
|
@ -400,7 +397,7 @@ class _CreateBotAssistantsPageState extends State<CreateBotAssistantsPage> {
|
|||
.surface),
|
||||
// hintText: "انتخاب کنید",
|
||||
onChanged: (value) {
|
||||
selectedBotId = value!.id!;
|
||||
state.initialBot = value;
|
||||
},
|
||||
),
|
||||
),
|
||||
|
|
@ -804,7 +801,7 @@ class _CreateBotAssistantsPageState extends State<CreateBotAssistantsPage> {
|
|||
? ' '
|
||||
: 'ذخیره تغییرات',
|
||||
onPressed: () async =>
|
||||
onConfirm(state, selectedBotId),
|
||||
onConfirm(state),
|
||||
),
|
||||
if (state.loadingCreate)
|
||||
const Positioned.fill(
|
||||
|
|
@ -871,8 +868,7 @@ class _CreateBotAssistantsPageState extends State<CreateBotAssistantsPage> {
|
|||
DidvanButton(
|
||||
title:
|
||||
state.loadingCreate ? ' ' : 'ذخیره',
|
||||
onPressed: () async =>
|
||||
onConfirm(state, selectedBotId)),
|
||||
onPressed: () async => onConfirm(state)),
|
||||
if (state.loadingCreate)
|
||||
const Positioned.fill(
|
||||
child: Center(
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ class CreateBotAssistantsState extends CoreProvier {
|
|||
navigatorKey.currentContext!.read<HistoryAiChatState>().bots;
|
||||
|
||||
final List<String> botModels = ['مدل زبانی', 'مدل تصویری'];
|
||||
BotsModel? initialBot;
|
||||
late BotsModel? initialBot = allBots.first;
|
||||
|
||||
List<String> countOfLink = [''];
|
||||
List<FileCreateAssistantsModel> files = [];
|
||||
|
|
@ -123,6 +123,9 @@ class CreateBotAssistantsState extends CoreProvier {
|
|||
}
|
||||
selectedBotType = initialBot?.responseType ?? 'text';
|
||||
}
|
||||
if (initialBot == null) {
|
||||
selectedBotType == 'text' ? allBots.first : imageBots.first;
|
||||
}
|
||||
appState = AppState.idle;
|
||||
loading = false;
|
||||
update();
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import 'package:didvan/providers/core.dart';
|
|||
import 'package:didvan/services/network/request.dart';
|
||||
import 'package:didvan/services/network/request_helper.dart';
|
||||
import 'package:didvan/utils/action_sheet.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
class HistoryAiChatState extends CoreProvier {
|
||||
final List<ChatsModel> chats = [];
|
||||
|
|
@ -17,15 +16,17 @@ class HistoryAiChatState extends CoreProvier {
|
|||
// final List<int> chatsToDelete = [];
|
||||
final List<BotsModel> bots = [];
|
||||
BotsModel? bot;
|
||||
ValueNotifier<bool> loadingBots = ValueNotifier(false);
|
||||
bool loadingBots = false;
|
||||
bool loadingchangeTitle = false;
|
||||
bool loadingdeleteAll = false;
|
||||
bool loadinggetAll = false;
|
||||
bool refresh = false;
|
||||
Timer? timer;
|
||||
String search = '';
|
||||
|
||||
Future<void> getChats({final bool archived = false}) async {
|
||||
appState = AppState.busy;
|
||||
loadinggetAll = true;
|
||||
update();
|
||||
final service = RequestService(
|
||||
archived ? RequestHelper.aiArchived() : RequestHelper.aiChats(),
|
||||
|
|
@ -39,10 +40,13 @@ class HistoryAiChatState extends CoreProvier {
|
|||
.add(ChatsModel.fromJson(messages[i]));
|
||||
}
|
||||
appState = AppState.idle;
|
||||
loadinggetAll = false;
|
||||
|
||||
update();
|
||||
return;
|
||||
}
|
||||
appState = AppState.failed;
|
||||
loadinggetAll = false;
|
||||
update();
|
||||
}
|
||||
|
||||
|
|
@ -72,7 +76,9 @@ class HistoryAiChatState extends CoreProvier {
|
|||
}
|
||||
|
||||
Future<void> getBots() async {
|
||||
loadingBots.value = true;
|
||||
appState = AppState.busy;
|
||||
loadingBots = true;
|
||||
update();
|
||||
final service = RequestService(
|
||||
RequestHelper.aiBots(),
|
||||
);
|
||||
|
|
@ -83,19 +89,23 @@ class HistoryAiChatState extends CoreProvier {
|
|||
for (var i = 0; i < messages.length; i++) {
|
||||
bots.add(BotsModel.fromJson(messages[i]));
|
||||
}
|
||||
appState = AppState.idle;
|
||||
loadingBots.value = false;
|
||||
bot = bots.first;
|
||||
appState = AppState.idle;
|
||||
loadingBots = false;
|
||||
update();
|
||||
getChats();
|
||||
|
||||
return;
|
||||
}
|
||||
appState = AppState.failed;
|
||||
loadingBots.value = false;
|
||||
loadingBots = false;
|
||||
update();
|
||||
}
|
||||
|
||||
Future<void> getSearchBots(String q) async {
|
||||
loadingBots.value = true;
|
||||
appState = AppState.busy;
|
||||
|
||||
loadingBots = true;
|
||||
final service = RequestService(
|
||||
RequestHelper.aiSearchBots(q),
|
||||
);
|
||||
|
|
@ -107,13 +117,13 @@ class HistoryAiChatState extends CoreProvier {
|
|||
bots.add(BotsModel.fromJson(messages[i]));
|
||||
}
|
||||
appState = AppState.idle;
|
||||
loadingBots.value = false;
|
||||
loadingBots = false;
|
||||
update();
|
||||
|
||||
return;
|
||||
}
|
||||
appState = AppState.failed;
|
||||
loadingBots.value = false;
|
||||
loadingBots = false;
|
||||
update();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ import 'package:didvan/services/media/media.dart';
|
|||
import 'package:didvan/utils/action_sheet.dart';
|
||||
import 'package:didvan/utils/date_time.dart';
|
||||
import 'package:didvan/views/ai/ai_chat_state.dart';
|
||||
import 'package:didvan/views/ai/history_ai_chat_state.dart';
|
||||
import 'package:didvan/views/ai/widgets/audio_wave.dart';
|
||||
import 'package:didvan/views/ai/widgets/message_bar_btn.dart';
|
||||
import 'package:didvan/views/widgets/animated_visibility.dart';
|
||||
|
|
@ -66,7 +65,6 @@ class _AiMessageBarState extends State<AiMessageBar> {
|
|||
Timer? _timer;
|
||||
final theSource = AudioSource.microphone;
|
||||
final ValueNotifier<Duration> _countTimer = ValueNotifier(Duration.zero);
|
||||
late HistoryAiChatState historyState = context.read<HistoryAiChatState>();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
|
@ -256,7 +254,7 @@ class _AiMessageBarState extends State<AiMessageBar> {
|
|||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
recorderAndSendButton(state, historyState),
|
||||
recorderAndSendButton(state),
|
||||
if (!(_mRecorder!.isStopped))
|
||||
ValueListenableBuilder(
|
||||
valueListenable: _countTimer,
|
||||
|
|
@ -453,13 +451,13 @@ class _AiMessageBarState extends State<AiMessageBar> {
|
|||
);
|
||||
}
|
||||
|
||||
recorderAndSendButton(AiChatState state, HistoryAiChatState historyState) {
|
||||
recorderAndSendButton(AiChatState state) {
|
||||
return ValueListenableBuilder(
|
||||
valueListenable: state.message,
|
||||
builder: (context, message, child) => Padding(
|
||||
padding: const EdgeInsets.fromLTRB(12, 0, 12, 8),
|
||||
child: message.text.isEmpty &&
|
||||
historyState.bot!.attachmentType!.contains('audio') &&
|
||||
widget.bot.attachmentType!.contains('audio') &&
|
||||
state.file == null &&
|
||||
widget.bot.attachment != 0
|
||||
? MessageBarBtn(
|
||||
|
|
@ -531,150 +529,6 @@ class _AiMessageBarState extends State<AiMessageBar> {
|
|||
);
|
||||
}
|
||||
|
||||
// AnimatedVisibility attachmentLayout(AiChatState state,
|
||||
// HistoryAiChatState historyState, BuildContext context) {
|
||||
// return AnimatedVisibility(
|
||||
// isVisible: openAttach,
|
||||
// duration: DesignConfig.lowAnimationDuration,
|
||||
// child: Container(
|
||||
// padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 12),
|
||||
// child: state.file != null && !(state.file!.isRecorded)
|
||||
// ? fileContainer()
|
||||
// : Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.center,
|
||||
// children: [
|
||||
// if (historyState.bot!.attachmentType!.contains('pdf'))
|
||||
// attachBtn(
|
||||
// title: "PDF",
|
||||
// icon: CupertinoIcons.doc_fill,
|
||||
// color: Colors.redAccent,
|
||||
// click: () async {
|
||||
// MediaService.onLoadingPickFile(context);
|
||||
// FilePickerResult? result =
|
||||
// await MediaService.pickPdfFile();
|
||||
// if (result != null) {
|
||||
// if (kIsWeb) {
|
||||
// Uint8List? bytes = result.files.first
|
||||
// .bytes; // Access the bytes property
|
||||
// String? name = result.files.first.name;
|
||||
|
||||
// // Store bytes and file name directly in your state or model
|
||||
// state.file = FilesModel(
|
||||
// '', // No need for a file path on web
|
||||
// name: name,
|
||||
// bytes: bytes,
|
||||
// audio: false,
|
||||
// image: false,
|
||||
// );
|
||||
// } else {
|
||||
// state.file = FilesModel(result.files.single.path!,
|
||||
// audio: false, image: false);
|
||||
// }
|
||||
// }
|
||||
// Future.delayed(
|
||||
// Duration.zero,
|
||||
// () => ActionSheetUtils(context).pop(),
|
||||
// );
|
||||
// },
|
||||
// ),
|
||||
// if (historyState.bot!.attachmentType!.contains('image'))
|
||||
// attachBtn(
|
||||
// title: "تصویر",
|
||||
// icon: CupertinoIcons.photo,
|
||||
// color: Colors.deepOrangeAccent,
|
||||
// click: () async {
|
||||
// MediaService.onLoadingPickFile(context);
|
||||
|
||||
// final pickedFile = await MediaService.pickImage(
|
||||
// source: ImageSource.gallery);
|
||||
// File? file;
|
||||
// if (pickedFile != null && !kIsWeb) {
|
||||
// file = await ImageCropper().cropImage(
|
||||
// sourcePath: pickedFile.path,
|
||||
// androidUiSettings: const AndroidUiSettings(
|
||||
// toolbarTitle: 'برش تصویر'),
|
||||
// iosUiSettings: const IOSUiSettings(
|
||||
// title: 'برش تصویر',
|
||||
// doneButtonTitle: 'تایید',
|
||||
// cancelButtonTitle: 'بازگشت',
|
||||
// ),
|
||||
// compressQuality: 30,
|
||||
// );
|
||||
|
||||
// if (file == null) {
|
||||
// await Future.delayed(
|
||||
// Duration.zero,
|
||||
// () => ActionSheetUtils(context).pop(),
|
||||
// );
|
||||
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// if (pickedFile == null) {
|
||||
// await Future.delayed(
|
||||
// Duration.zero,
|
||||
// () => ActionSheetUtils(context).pop(),
|
||||
// );
|
||||
|
||||
// return;
|
||||
// }
|
||||
// state.file = kIsWeb
|
||||
// ? FilesModel(pickedFile.path,
|
||||
// name: pickedFile.name,
|
||||
// image: true,
|
||||
// audio: false)
|
||||
// : FilesModel(file!.path,
|
||||
// image: true, audio: false);
|
||||
// await Future.delayed(
|
||||
// Duration.zero,
|
||||
// () => ActionSheetUtils(context).pop(),
|
||||
// );
|
||||
// },
|
||||
// ),
|
||||
// // if (!kIsWeb && !Platform.isIOS)
|
||||
// if (historyState.bot!.attachmentType!.contains('audio'))
|
||||
// attachBtn(
|
||||
// title: "صوت",
|
||||
// icon: CupertinoIcons.music_note_2,
|
||||
// color: Colors.indigoAccent,
|
||||
// click: () async {
|
||||
// MediaService.onLoadingPickFile(context);
|
||||
|
||||
// FilePickerResult? result =
|
||||
// await MediaService.pickAudioFile();
|
||||
// if (result != null) {
|
||||
// if (kIsWeb) {
|
||||
// Uint8List? bytes = result.files.first
|
||||
// .bytes; // Access the bytes property
|
||||
// String? name = result.files.first.name;
|
||||
|
||||
// // final blob = html.Blob([bytes]);
|
||||
// // final blobUrl =
|
||||
// // html.Url.createObjectUrlFromBlob(blob);
|
||||
|
||||
// state.file = FilesModel(
|
||||
// "", // No need for a file path on web
|
||||
// name: name,
|
||||
// bytes: bytes,
|
||||
// audio: true,
|
||||
// image: false,
|
||||
// );
|
||||
// } else {
|
||||
// state.file = FilesModel(result.files.single.path!,
|
||||
// audio: true, image: false);
|
||||
// }
|
||||
// }
|
||||
// await Future.delayed(
|
||||
// Duration.zero,
|
||||
// () => ActionSheetUtils(context).pop(),
|
||||
// );
|
||||
// },
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// ));
|
||||
// }
|
||||
|
||||
AnimatedVisibility attachmentLayout(AiChatState state, BuildContext context) {
|
||||
return AnimatedVisibility(
|
||||
isVisible: openAttach,
|
||||
|
|
@ -683,45 +537,48 @@ class _AiMessageBarState extends State<AiMessageBar> {
|
|||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
if (historyState.bot!.attachmentType!.contains('pdf'))
|
||||
MessageBarBtn(
|
||||
enable: true,
|
||||
icon: CupertinoIcons.doc_fill,
|
||||
click: () async {
|
||||
MediaService.onLoadingPickFile(context);
|
||||
FilePickerResult? result = await MediaService.pickPdfFile();
|
||||
if (result != null) {
|
||||
String? name = result.files.single.name;
|
||||
|
||||
if (kIsWeb) {
|
||||
Uint8List? bytes =
|
||||
result.files.first.bytes; // Access the bytes property
|
||||
|
||||
// Store bytes and file name directly in your state or model
|
||||
state.file = FilesModel(
|
||||
'', // No need for a file path on web
|
||||
name: name,
|
||||
bytes: bytes,
|
||||
audio: false,
|
||||
image: false,
|
||||
);
|
||||
} else {
|
||||
state.file = FilesModel(result.files.single.path!,
|
||||
audio: false, image: false, name: name);
|
||||
}
|
||||
}
|
||||
Future.delayed(
|
||||
Duration.zero,
|
||||
() => ActionSheetUtils(context).pop(),
|
||||
);
|
||||
openAttach = !openAttach;
|
||||
|
||||
state.update();
|
||||
},
|
||||
),
|
||||
if (historyState.bot!.attachmentType!.contains('image'))
|
||||
if (widget.bot.attachmentType!.contains('pdf'))
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
child: MessageBarBtn(
|
||||
enable: true,
|
||||
icon: CupertinoIcons.doc_fill,
|
||||
click: () async {
|
||||
MediaService.onLoadingPickFile(context);
|
||||
FilePickerResult? result = await MediaService.pickPdfFile();
|
||||
if (result != null) {
|
||||
String? name = result.files.single.name;
|
||||
|
||||
if (kIsWeb) {
|
||||
Uint8List? bytes = result
|
||||
.files.first.bytes; // Access the bytes property
|
||||
|
||||
// Store bytes and file name directly in your state or model
|
||||
state.file = FilesModel(
|
||||
'', // No need for a file path on web
|
||||
name: name,
|
||||
bytes: bytes,
|
||||
audio: false,
|
||||
image: false,
|
||||
);
|
||||
} else {
|
||||
state.file = FilesModel(result.files.single.path!,
|
||||
audio: false, image: false, name: name);
|
||||
}
|
||||
}
|
||||
Future.delayed(
|
||||
Duration.zero,
|
||||
() => ActionSheetUtils(context).pop(),
|
||||
);
|
||||
openAttach = !openAttach;
|
||||
|
||||
state.update();
|
||||
},
|
||||
),
|
||||
),
|
||||
if (widget.bot.attachmentType!.contains('image'))
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
child: MessageBarBtn(
|
||||
enable: true,
|
||||
icon: CupertinoIcons.photo,
|
||||
|
|
@ -777,86 +634,53 @@ class _AiMessageBarState extends State<AiMessageBar> {
|
|||
),
|
||||
),
|
||||
// if (!kIsWeb && !Platform.isIOS)
|
||||
if (historyState.bot!.attachmentType!.contains('audio'))
|
||||
MessageBarBtn(
|
||||
enable: true,
|
||||
icon: CupertinoIcons.music_note_2,
|
||||
click: () async {
|
||||
MediaService.onLoadingPickFile(context);
|
||||
if (widget.bot.attachmentType!.contains('audio'))
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
child: MessageBarBtn(
|
||||
enable: true,
|
||||
icon: CupertinoIcons.music_note_2,
|
||||
click: () async {
|
||||
MediaService.onLoadingPickFile(context);
|
||||
|
||||
FilePickerResult? result = await MediaService.pickAudioFile();
|
||||
if (result != null) {
|
||||
String? name = result.files.first.name;
|
||||
FilePickerResult? result =
|
||||
await MediaService.pickAudioFile();
|
||||
if (result != null) {
|
||||
String? name = result.files.first.name;
|
||||
|
||||
if (kIsWeb) {
|
||||
Uint8List? bytes =
|
||||
result.files.first.bytes; // Access the bytes property
|
||||
if (kIsWeb) {
|
||||
Uint8List? bytes = result
|
||||
.files.first.bytes; // Access the bytes property
|
||||
|
||||
final blob = html.Blob([bytes]);
|
||||
final blobUrl = html.Url.createObjectUrlFromBlob(blob);
|
||||
final blob = html.Blob([bytes]);
|
||||
final blobUrl = html.Url.createObjectUrlFromBlob(blob);
|
||||
|
||||
state.file = FilesModel(
|
||||
blobUrl, // No need for a file path on web
|
||||
name: name,
|
||||
bytes: bytes,
|
||||
audio: true,
|
||||
image: false,
|
||||
);
|
||||
} else {
|
||||
state.file = FilesModel(result.files.single.path!,
|
||||
name: name, audio: true, image: false);
|
||||
state.file = FilesModel(
|
||||
blobUrl, // No need for a file path on web
|
||||
name: name,
|
||||
bytes: bytes,
|
||||
audio: true,
|
||||
image: false,
|
||||
);
|
||||
} else {
|
||||
state.file = FilesModel(result.files.single.path!,
|
||||
name: name, audio: true, image: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
await Future.delayed(
|
||||
Duration.zero,
|
||||
() => ActionSheetUtils(context).pop(),
|
||||
);
|
||||
openAttach = !openAttach;
|
||||
await Future.delayed(
|
||||
Duration.zero,
|
||||
() => ActionSheetUtils(context).pop(),
|
||||
);
|
||||
openAttach = !openAttach;
|
||||
|
||||
state.update();
|
||||
},
|
||||
state.update();
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
));
|
||||
}
|
||||
|
||||
// InkWell attachBtn(
|
||||
// {required final String title,
|
||||
// required final IconData icon,
|
||||
// final Color? color,
|
||||
// final Function()? click}) {
|
||||
// final state = context.read<AiChatState>();
|
||||
// return InkWell(
|
||||
// onTap: () async {
|
||||
// await click?.call();
|
||||
|
||||
// state.update();
|
||||
// },
|
||||
// child: Column(
|
||||
// children: [
|
||||
// Container(
|
||||
// width: 40,
|
||||
// height: 40,
|
||||
// decoration: BoxDecoration(shape: BoxShape.circle, color: color),
|
||||
// padding: const EdgeInsets.all(0.8),
|
||||
// margin: const EdgeInsets.symmetric(horizontal: 12),
|
||||
// child: Icon(
|
||||
// icon,
|
||||
// size: 20,
|
||||
// color: Theme.of(context).colorScheme.white,
|
||||
// )),
|
||||
// const SizedBox(
|
||||
// height: 4,
|
||||
// ),
|
||||
// DidvanText(
|
||||
// title,
|
||||
// fontSize: 12,
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
|
||||
Widget audioContainer() {
|
||||
final state = context.watch<AiChatState>();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
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';
|
||||
|
|
@ -15,8 +14,9 @@ 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:didvan/views/widgets/skeleton_image.dart';
|
||||
import 'package:didvan/views/widgets/state_handlers/empty_list.dart';
|
||||
import 'package:didvan/views/widgets/state_handlers/sliver_state_handler.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class HoshanDrawer extends StatefulWidget {
|
||||
|
|
@ -27,6 +27,11 @@ class HoshanDrawer extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _HoshanDrawerState extends State<HoshanDrawer> {
|
||||
@override
|
||||
initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Drawer(
|
||||
|
|
@ -139,88 +144,28 @@ class _HoshanDrawerState extends State<HoshanDrawer> {
|
|||
// 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);
|
||||
child: CustomScrollView(
|
||||
slivers: [
|
||||
SliverStateHandler(
|
||||
state: state,
|
||||
centerEmptyState: true,
|
||||
emptyState: const EmptyList(),
|
||||
// enableEmptyState: state.chats.isEmpty,
|
||||
placeholder: chatRowPlaceholder(),
|
||||
placeholderCount: 10,
|
||||
builder: (context, state, index) {
|
||||
final chat = state.chats[index];
|
||||
TextEditingController title =
|
||||
TextEditingController(
|
||||
text: chat.title);
|
||||
|
||||
return chatRow(chat, title, state, index);
|
||||
},
|
||||
childCount: state.chats.length,
|
||||
onRetry: () => state.getChats())
|
||||
],
|
||||
)),
|
||||
|
||||
return chatRow(
|
||||
chat, title, state, index);
|
||||
},
|
||||
),
|
||||
),
|
||||
// SizedBox(
|
||||
// height: 12,
|
||||
// ),
|
||||
|
|
@ -268,6 +213,39 @@ class _HoshanDrawerState extends State<HoshanDrawer> {
|
|||
);
|
||||
}
|
||||
|
||||
Padding chatRowPlaceholder() {
|
||||
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,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget drawerBtn(
|
||||
{final CrossAxisAlignment? crossAxisAlignment,
|
||||
required final IconData icon,
|
||||
|
|
|
|||
|
|
@ -142,7 +142,6 @@ class _HomeState extends State<Home>
|
|||
if (_tabController.index == 2) {
|
||||
homeScaffKey.currentState!.closeDrawer();
|
||||
|
||||
context.read<HistoryAiChatState>().getChats();
|
||||
context.read<HistoryAiChatState>().getBots();
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
import 'package:didvan/config/design_config.dart';
|
||||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:didvan/constants/app_icons.dart';
|
||||
import 'package:didvan/utils/extension.dart';
|
||||
import 'package:didvan/views/widgets/animated_visibility.dart';
|
||||
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:persian_number_utility/persian_number_utility.dart';
|
||||
|
||||
class DidvanTextField extends StatefulWidget {
|
||||
final void Function(String value)? onChanged;
|
||||
final void Function(String value)? onSubmitted;
|
||||
final bool enabled;
|
||||
final bool autoFocus;
|
||||
final TextAlign textAlign;
|
||||
final TextAlign? textAlign;
|
||||
final String? title;
|
||||
final String? hintText;
|
||||
final dynamic initialValue;
|
||||
|
|
@ -37,7 +37,7 @@ class DidvanTextField extends StatefulWidget {
|
|||
this.initialValue,
|
||||
this.validator,
|
||||
this.textInputType,
|
||||
this.textAlign = TextAlign.right,
|
||||
this.textAlign,
|
||||
this.obsecureText = false,
|
||||
this.autoFocus = false,
|
||||
this.onSubmitted,
|
||||
|
|
@ -69,7 +69,7 @@ class _DidvanTextFieldState extends State<DidvanTextField> {
|
|||
}
|
||||
_hideContent = widget.obsecureText;
|
||||
_focusNode.addListener(() {
|
||||
setState(() {});
|
||||
// setState(() {});
|
||||
});
|
||||
super.initState();
|
||||
}
|
||||
|
|
@ -98,47 +98,58 @@ class _DidvanTextFieldState extends State<DidvanTextField> {
|
|||
? null
|
||||
: Border.all(color: _borderColor()),
|
||||
),
|
||||
child: TextFormField(
|
||||
inputFormatters: <TextInputFormatter>[
|
||||
if (!widget.acceptSpace)
|
||||
FilteringTextInputFormatter.allow(RegExp("[0-9a-zA-Z]")),
|
||||
],
|
||||
autofocus: widget.autoFocus,
|
||||
obscureText: _hideContent,
|
||||
textAlign: widget.textAlign,
|
||||
keyboardType: widget.textInputType,
|
||||
focusNode: _focusNode,
|
||||
controller: _controller,
|
||||
onFieldSubmitted: widget.onSubmitted,
|
||||
onChanged: _onChanged,
|
||||
validator: _validator,
|
||||
maxLines: widget.maxLine,
|
||||
minLines: widget.minLine,
|
||||
maxLength: widget.maxLength,
|
||||
obscuringCharacter: '*',
|
||||
buildCounter: widget.showLen
|
||||
? null
|
||||
: (context,
|
||||
{required currentLength,
|
||||
required isFocused,
|
||||
required maxLength}) =>
|
||||
const SizedBox(),
|
||||
style: (widget.isSmall
|
||||
? Theme.of(context).textTheme.bodySmall!
|
||||
: Theme.of(context).textTheme.bodyMedium!)
|
||||
.copyWith(fontFamily: DesignConfig.fontFamily.padRight(3)),
|
||||
decoration: InputDecoration(
|
||||
suffixIcon: _suffixBuilder(),
|
||||
enabled: widget.enabled,
|
||||
border: InputBorder.none,
|
||||
hintText: widget.hintText,
|
||||
errorStyle: const TextStyle(height: 0.01),
|
||||
hintStyle: (widget.isSmall
|
||||
? Theme.of(context).textTheme.bodySmall!
|
||||
: Theme.of(context).textTheme.bodyMedium!)
|
||||
.copyWith(color: Theme.of(context).colorScheme.hint),
|
||||
),
|
||||
),
|
||||
child: ValueListenableBuilder(
|
||||
valueListenable: _controller,
|
||||
builder: (context, val, _) {
|
||||
return Directionality(
|
||||
textDirection: val.text.startsWithEnglish()
|
||||
? TextDirection.ltr
|
||||
: TextDirection.rtl,
|
||||
child: TextFormField(
|
||||
inputFormatters: <TextInputFormatter>[
|
||||
if (!widget.acceptSpace)
|
||||
FilteringTextInputFormatter.allow(
|
||||
RegExp("[0-9a-zA-Z]")),
|
||||
],
|
||||
autofocus: widget.autoFocus,
|
||||
obscureText: _hideContent,
|
||||
textAlign: widget.textAlign ?? TextAlign.start,
|
||||
keyboardType: widget.textInputType,
|
||||
focusNode: _focusNode,
|
||||
controller: _controller,
|
||||
onFieldSubmitted: widget.onSubmitted,
|
||||
onChanged: _onChanged,
|
||||
validator: _validator,
|
||||
maxLines: widget.maxLine,
|
||||
minLines: widget.minLine,
|
||||
maxLength: widget.maxLength,
|
||||
obscuringCharacter: '*',
|
||||
buildCounter: widget.showLen
|
||||
? null
|
||||
: (context,
|
||||
{required currentLength,
|
||||
required isFocused,
|
||||
required maxLength}) =>
|
||||
const SizedBox(),
|
||||
style: (widget.isSmall
|
||||
? Theme.of(context).textTheme.bodySmall!
|
||||
: Theme.of(context).textTheme.bodyMedium!)
|
||||
.copyWith(
|
||||
fontFamily: DesignConfig.fontFamily.padRight(3)),
|
||||
decoration: InputDecoration(
|
||||
suffixIcon: _suffixBuilder(),
|
||||
enabled: widget.enabled,
|
||||
border: InputBorder.none,
|
||||
hintText: widget.hintText,
|
||||
errorStyle: const TextStyle(height: 0.01),
|
||||
hintStyle: (widget.isSmall
|
||||
? Theme.of(context).textTheme.bodySmall!
|
||||
: Theme.of(context).textTheme.bodyMedium!)
|
||||
.copyWith(color: Theme.of(context).colorScheme.hint),
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
AnimatedVisibility(
|
||||
isVisible: _error != null,
|
||||
|
|
@ -224,7 +235,7 @@ class _DidvanTextFieldState extends State<DidvanTextField> {
|
|||
setState(() {
|
||||
_error = null;
|
||||
});
|
||||
value = value.toEnglishDigit();
|
||||
// value = value.toEnglishDigit();
|
||||
widget.onChanged?.call(value);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue