diff --git a/assets/images/speech_to_text.svg b/assets/images/speech_to_text.svg
new file mode 100644
index 00000000..4474a1ec
--- /dev/null
+++ b/assets/images/speech_to_text.svg
@@ -0,0 +1,3 @@
+
diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart
index 74b60575..e6659caa 100644
--- a/lib/controllers/api_routes/urls.dart
+++ b/lib/controllers/api_routes/urls.dart
@@ -5,6 +5,7 @@ class URLs {
static const host1 = "https://atomsmdev.hmg.com"; // local UAT url
static String _baseUrl = "$_host/mobile";
+ // static String _baseUrl = "$_host/v2/mobile"; // new V2 apis
static String _host = host1;
diff --git a/lib/new_views/common_widgets/app_text_form_field.dart b/lib/new_views/common_widgets/app_text_form_field.dart
index 476576b0..3fe19929 100644
--- a/lib/new_views/common_widgets/app_text_form_field.dart
+++ b/lib/new_views/common_widgets/app_text_form_field.dart
@@ -28,6 +28,7 @@ class AppTextFormField extends StatefulWidget {
final Color backgroundColor;
final bool alignLabelWithHint;
final bool showShadow;
+ final bool showWithoutDecoration;
final void Function() onTap;
const AppTextFormField({
@@ -54,6 +55,7 @@ class AppTextFormField extends StatefulWidget {
this.onAction,
this.backgroundColor,
this.showShadow = true,
+ this.showWithoutDecoration = false,
this.alignLabelWithHint,
this.onTap,
}) : super(key: key);
@@ -72,59 +74,63 @@ class _AppTextFormFieldState extends State {
@override
Widget build(BuildContext context) {
final border = UnderlineInputBorder(borderSide: BorderSide.none, borderRadius: BorderRadius.circular(10));
+
+ Widget textField = TextFormField(
+ focusNode: widget.node,
+ enabled: widget.enable,
+ onSaved: widget.onSaved,
+ initialValue: widget.controller != null ? null : widget.initialValue,
+ validator: widget.validator,
+ onChanged: widget.onChange,
+ obscureText: widget.obscureText ?? false,
+ keyboardType: widget.textInputType,
+ maxLines: widget.textInputType == TextInputType.multiline ? 4 : 1,
+ obscuringCharacter: "*",
+ controller: widget.controller,
+ textInputAction: widget.textInputType == TextInputType.multiline ? null : widget.textInputAction ?? TextInputAction.next,
+ onEditingComplete: widget.onAction ?? () => FocusScope.of(context).nextFocus(),
+ style: AppTextStyle.body1?.copyWith(fontWeight: FontWeight.w500),
+ onTap: widget.onTap,
+ decoration: InputDecoration(
+ alignLabelWithHint: widget.alignLabelWithHint,
+ border: border,
+ disabledBorder: border,
+ focusedBorder: border,
+ enabledBorder: border,
+ errorBorder: border,
+ contentPadding: EdgeInsets.symmetric(vertical: 8.toScreenHeight, horizontal: 16.toScreenWidth),
+ constraints: const BoxConstraints(),
+ suffixIconConstraints: const BoxConstraints(minWidth: 0),
+ filled: true,
+ fillColor: widget.backgroundColor ??
+ (context.isDark && (widget.enable == false)
+ ? AppColor.neutral50
+ : (widget.enable == false)
+ ? AppColor.neutral40
+ : AppColor.background(context)),
+ errorStyle: AppTextStyle.tiny.copyWith(color: context.isDark ? AppColor.red50 : AppColor.red60),
+ floatingLabelStyle: AppTextStyle.body1?.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? null : AppColor.neutral20),
+ hintText: widget.hintText ?? "",
+ labelText: widget.labelText ?? "",
+ prefixIcon: widget.prefixIcon ??
+ (widget.prefixIconData == null
+ ? null
+ : Icon(
+ widget.prefixIconData,
+ size: widget.prefixIconSize == null ? 20.toScreenWidth : (widget.prefixIconSize - 10).toScreenWidth,
+ color: AppColor.neutral70,
+ )),
+ suffixIcon: widget.suffixIcon,
+ ),
+ );
+
+ if (widget.showWithoutDecoration) return textField;
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
boxShadow: widget.showShadow ? [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)] : null,
),
- child: TextFormField(
- focusNode: widget.node,
- enabled: widget.enable,
- onSaved: widget.onSaved,
- initialValue: widget.controller != null ? null : widget.initialValue,
- validator: widget.validator,
- onChanged: widget.onChange,
- obscureText: widget.obscureText ?? false,
- keyboardType: widget.textInputType,
- maxLines: widget.textInputType == TextInputType.multiline ? 4 : 1,
- obscuringCharacter: "*",
- controller: widget.controller,
- textInputAction: widget.textInputType == TextInputType.multiline ? null : widget.textInputAction ?? TextInputAction.next,
- onEditingComplete: widget.onAction ?? () => FocusScope.of(context).nextFocus(),
- style: AppTextStyle.body1?.copyWith(fontWeight: FontWeight.w500),
- onTap: widget.onTap,
- decoration: InputDecoration(
- alignLabelWithHint: widget.alignLabelWithHint,
- border: border,
- disabledBorder: border,
- focusedBorder: border,
- enabledBorder: border,
- errorBorder: border,
- contentPadding: EdgeInsets.symmetric(vertical: 8.toScreenHeight, horizontal: 16.toScreenWidth),
- constraints: const BoxConstraints(),
- suffixIconConstraints: const BoxConstraints(minWidth: 0),
- filled: true,
- fillColor: widget.backgroundColor ??
- (context.isDark && (widget.enable == false)
- ? AppColor.neutral50
- : (widget.enable == false)
- ? AppColor.neutral40
- : AppColor.background(context)),
- errorStyle: AppTextStyle.tiny.copyWith(color: context.isDark ? AppColor.red50 : AppColor.red60),
- floatingLabelStyle: AppTextStyle.body1?.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? null : AppColor.neutral20),
- hintText: widget.hintText ?? "",
- labelText: widget.labelText ?? "",
- prefixIcon: widget.prefixIcon ??
- (widget.prefixIconData == null
- ? null
- : Icon(
- widget.prefixIconData,
- size: widget.prefixIconSize == null ? 20.toScreenWidth : (widget.prefixIconSize - 10).toScreenWidth,
- color: AppColor.neutral70,
- )),
- suffixIcon: widget.suffixIcon,
- ),
- ),
+ child: textField,
);
}
}
diff --git a/lib/views/pages/device_transfer/search_asset_page.dart b/lib/views/pages/device_transfer/search_asset_page.dart
index 15d89fb9..40958313 100644
--- a/lib/views/pages/device_transfer/search_asset_page.dart
+++ b/lib/views/pages/device_transfer/search_asset_page.dart
@@ -84,45 +84,41 @@ class _SearchAssetPageState extends State {
),
body: Column(
children: [
- Expanded(
- flex: 2,
- child: HorizontalListWidget(
- list: searchBy,
- callBackFunction: (index) {
+ HorizontalListWidget(
+ list: searchBy,
+ callBackFunction: (index) {
+ setState(() {
+ _selectedIndex = index;
+ });
+ },
+ ).paddingOnly(top: 16, bottom: 0),
+ Form(
+ key: _formKey,
+ child: AppTextFormField(
+ controller: _searchController,
+ textInputAction: TextInputAction.search,
+ labelText: "${context.translation.searchBy} ${searchBy[_selectedIndex]}",
+ onAction: _search,
+ onChange: (text) {
+ _searchController.text = text;
+ _searchController.selection = TextSelection.fromPosition(TextPosition(offset: _searchController.text.length));
+ setState(() {});
+ },
+ onSaved: (value) {
setState(() {
- _selectedIndex = index;
+ search = AssetSearch();
});
+ _setValue(value);
},
- ).paddingOnly(top: 16),
- ),
- Expanded(
- flex: 3,
- child: Form(
- key: _formKey,
- child: AppTextFormField(
- controller: _searchController,
- labelText: "${context.translation.searchBy} ${searchBy[_selectedIndex]}",
- onChange: (text) {
- _searchController.text = text;
- _searchController.selection = TextSelection.fromPosition(TextPosition(offset: _searchController.text.length));
- setState(() {});
- },
- onSaved: (value) {
- setState(() {
- search = AssetSearch();
- });
- _setValue(value);
- },
- suffixIcon: IconButton(
- icon: const Icon(Icons.search),
- onPressed: _searchController.text.isNotEmpty ? _search : null,
- color: AppColor.neutral20,
- ).paddingOnly(end: 6),
- ).paddingOnly(top: 18, start: 18, end: 18),
- ),
+ suffixIcon: IconButton(
+ icon: const Icon(Icons.search),
+ splashColor: Colors.transparent,
+ onPressed: _searchController.text.isNotEmpty ? _search : null,
+ color: AppColor.neutral20,
+ ).paddingOnly(end: 0),
+ ).paddingOnly(top: 16, start: 16, end: 16, bottom: 8),
),
Expanded(
- flex: 25,
child: _searchableList.isEmpty
? _isFirst
? const SizedBox()
@@ -141,6 +137,7 @@ class _SearchAssetPageState extends State {
child: ListView.separated(
itemCount: _searchableList.length,
separatorBuilder: (listContext, itemIndex) => 8.height,
+ padding: EdgeInsets.all(16),
itemBuilder: (listContext, itemIndex) {
return AssetItemListView(
device: _searchableList[itemIndex],
@@ -151,7 +148,7 @@ class _SearchAssetPageState extends State {
selectButton: Text(context.translation.select, style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context))),
);
},
- ).paddingOnly(start: 16, end: 16),
+ ),
),
)
],
@@ -189,7 +186,7 @@ class _SearchAssetPageState extends State {
}
}
- // bool _showResetButton() {
- // return (_searchController?.text?.isNotEmpty ?? false);
- // }
+// bool _showResetButton() {
+// return (_searchController?.text?.isNotEmpty ?? false);
+// }
}
diff --git a/lib/views/pages/user/requests/create_service_request_page.dart b/lib/views/pages/user/requests/create_service_request_page.dart
index bed86ba9..fed31c89 100644
--- a/lib/views/pages/user/requests/create_service_request_page.dart
+++ b/lib/views/pages/user/requests/create_service_request_page.dart
@@ -8,7 +8,6 @@ import 'package:test_sa/controllers/providers/api/user_provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
-import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/service_request/pending_service_request_model.dart';
import 'package:test_sa/models/service_request/service_request.dart';
@@ -20,11 +19,9 @@ import 'package:test_sa/views/widgets/bottom_sheets/pending_request_bottom_sheet
import 'package:test_sa/views/widgets/equipment/asset_picker.dart';
import 'package:test_sa/views/widgets/images/multi_image_picker.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
-import 'package:test_sa/views/widgets/sound/record_sound.dart';
-import 'package:test_sa/views/widgets/speech_to_text/speech_to_text.dart';
+import 'package:test_sa/views/widgets/sound/TextSpeechRecordWidget.dart';
import '../../../../new_views/app_style/app_color.dart';
-import '../../../../new_views/common_widgets/app_text_form_field.dart';
import '../../../../new_views/common_widgets/default_app_bar.dart';
import '../../../../providers/service_request_providers/priority_provider.dart';
import '../../../../providers/service_request_providers/type_of_request_provider.dart';
@@ -292,26 +289,37 @@ class CreateServiceRequestPageState extends State {
// );
// }),
- Align(
- alignment: AlignmentDirectional.centerStart,
- child: context.translation.callComments.heading5(context),
- ),
+ // Align(
+ // alignment: AlignmentDirectional.centerStart,
+ // child: context.translation.callComments.heading5(context),
+ // ),
8.height,
- SpeechToTextButton(
- controller: _commentController,
- ),
+ // SpeechToTextButton(
+ // controller: _commentController,
+ // ),
+ // 8.height,
+ // AppTextFormField(
+ // controller: _commentController,
+ // labelText: context.translation.problemDesc,
+ // suffixIcon: "warning".toSvgAsset(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20, width: 24).paddingOnly(end: 16),
+ // initialValue: _serviceRequest.callComments,
+ // onSaved: (text) {
+ // _serviceRequest.callComments = text;
+ // },
+ // ),
+ // 8.height,
+ // RecordSound(
+ // onRecord: (audio) {
+ // _serviceRequest.audio = audio;
+ // },
+ // enabled: widget.serviceRequest == null ? true : false,
+ // ),
8.height,
- AppTextFormField(
- controller: _commentController,
- labelText: context.translation.problemDesc,
- suffixIcon: "warning".toSvgAsset(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20, width: 24).paddingOnly(end: 16),
- initialValue: _serviceRequest.callComments,
- onSaved: (text) {
- _serviceRequest.callComments = text;
+ TextSpeechRecordWidget(
+ initialMessage: _serviceRequest.callComments,
+ onMessageChange: (message) {
+ _serviceRequest.callComments = message;
},
- ),
- 8.height,
- RecordSound(
onRecord: (audio) {
_serviceRequest.audio = audio;
},
diff --git a/lib/views/widgets/bottom_sheets/asset_detail_bottom_sheet.dart b/lib/views/widgets/bottom_sheets/asset_detail_bottom_sheet.dart
index f92aa52c..55a69da3 100644
--- a/lib/views/widgets/bottom_sheets/asset_detail_bottom_sheet.dart
+++ b/lib/views/widgets/bottom_sheets/asset_detail_bottom_sheet.dart
@@ -49,8 +49,8 @@ class AssetDetailBottomSheet extends StatelessWidget {
children: [
"${context.translation.assetNo}: ${asset.assetNumber}".bodyText(context),
"${context.translation.modelName}: ${asset.modelDefinition.modelName}".bodyText(context),
- "${context.translation.supplier}: ${asset.supplier?.suppliername ?? "-"}".bodyText(context),
- "${context.translation.manufacture}: ${asset.modelDefinition.manufacturerName}".bodyText(context),
+ "${context.translation.supplier}: ${asset.supplier?.suppliername?.cleanupWhitespace?.capitalizeFirstOfEach ?? "-"}".bodyText(context),
+ "${context.translation.manufacture}: ${asset.modelDefinition.manufacturerName?.cleanupWhitespace?.capitalizeFirstOfEach}".bodyText(context),
//"${context.translation.location}: ${assetModel.site.custName?.cleanupWhitespace?.capitalizeFirstOfEach}".bodyText(context),
],
).expanded,
diff --git a/lib/views/widgets/horizontal_list_widget.dart b/lib/views/widgets/horizontal_list_widget.dart
index 4e814949..5a506a7d 100644
--- a/lib/views/widgets/horizontal_list_widget.dart
+++ b/lib/views/widgets/horizontal_list_widget.dart
@@ -26,7 +26,7 @@ class _HorizontalListWidgetState extends State {
itemCount: widget.list.length,
scrollDirection: Axis.horizontal,
shrinkWrap: true,
- padding: EdgeInsetsDirectional.only(start: 16.toScreenWidth),
+ padding: EdgeInsetsDirectional.only(start: 16.toScreenWidth,end: 16),
itemBuilder: (context, index) => Container(
margin: EdgeInsets.symmetric(horizontal: 4.toScreenWidth),
padding: EdgeInsets.symmetric(horizontal: 20.toScreenWidth),
diff --git a/lib/views/widgets/sound/TextSpeechRecordWidget.dart b/lib/views/widgets/sound/TextSpeechRecordWidget.dart
new file mode 100644
index 00000000..27d553bd
--- /dev/null
+++ b/lib/views/widgets/sound/TextSpeechRecordWidget.dart
@@ -0,0 +1,352 @@
+import 'dart:async';
+import 'dart:io';
+
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:fluttertoast/fluttertoast.dart';
+import 'package:path_provider/path_provider.dart';
+import 'package:permission_handler/permission_handler.dart';
+import 'package:provider/provider.dart';
+import 'package:record_mp3/record_mp3.dart';
+import 'package:rive/rive.dart';
+import 'package:speech_to_text/speech_recognition_error.dart';
+import 'package:speech_to_text/speech_recognition_result.dart';
+import 'package:speech_to_text/speech_to_text.dart';
+import 'package:test_sa/controllers/providers/settings/setting_provider.dart';
+import 'package:test_sa/extensions/context_extension.dart';
+import 'package:test_sa/extensions/int_extensions.dart';
+import 'package:test_sa/extensions/text_extensions.dart';
+import 'package:test_sa/extensions/widget_extensions.dart';
+import 'package:test_sa/views/widgets/sound/sound_player.dart';
+
+import '../../../new_views/app_style/app_color.dart';
+import '../../../new_views/common_widgets/app_text_form_field.dart';
+
+class TextSpeechRecordWidget extends StatefulWidget {
+ final Function(String) onRecord;
+ final Function(String) onStop;
+ final bool enabled;
+ final Function(String) onMessageChange;
+ final String initialMessage;
+
+ const TextSpeechRecordWidget({Key key, @required this.onRecord, this.onStop, this.enabled = true, this.onMessageChange, this.initialMessage}) : super(key: key);
+
+ @override
+ State createState() => _RecordSoundState();
+}
+
+class _RecordSoundState extends State {
+ // FlutterSoundRecorder _myRecorder = FlutterSoundRecorder();
+
+ bool _recorderIsOpened = false;
+ bool _recording = false;
+ bool _played = false;
+ String _record;
+ Artboard _rive;
+ Timer _timer;
+ TextEditingController _timeController;
+ TextEditingController _commentController;
+ bool _speechEnabled = false;
+
+ FocusNode node = FocusNode();
+
+ @override
+ void setState(VoidCallback fn) {
+ if (mounted) super.setState(fn);
+ }
+
+ final SpeechToText _speechToText = SpeechToText();
+
+ /// This has to happen only once per app
+ void _initSpeech() async {
+ _speechEnabled = await _speechToText.initialize(
+ onError: (SpeechRecognitionError error) async {
+ Fluttertoast.showToast(msg: "failed to convert text to speech");
+ setState(() {});
+ },
+ );
+ }
+
+ SettingProvider _settingProvider;
+
+ @override
+ void initState() {
+ super.initState();
+ _initSpeech();
+ _timeController = TextEditingController();
+ _commentController = TextEditingController();
+ node.unfocus();
+ _recorderIsOpened = true;
+ // RecordMp3.instance.start(recordFilePath, (type) {
+ // // record fail callback
+ // });
+ // _myRecorder.openRecorder().then((value) {
+ // _recorderIsOpened = true;
+ // setState(() {});
+ // });
+
+ // Load the animation file from the bundle, note that you could also
+ // download this. The RiveFile just expects a list of bytes.
+ rootBundle.load('assets/rives/recording.riv').then(
+ (data) async {
+ // Load the RiveFile from the binary data.
+ final file = RiveFile.import(data);
+ // The artboard is the root of the animation and gets drawn in the
+ // Rive widget.
+ final artboard = file.mainArtboard;
+ // Add a controller to play back a known animation on the main/default
+ // artboard.We store a reference to it so we can toggle playback.
+ artboard.addController(SimpleAnimation('recording'));
+ _rive = artboard;
+
+ setState(() {});
+ },
+ );
+ }
+
+ @override
+ void dispose() {
+ _timeController?.dispose();
+ // Be careful : you must `close` the audio session when you have finished with it.
+ RecordMp3.instance.stop();
+ //_myRecorder.closeRecorder();
+ // _myRecorder = null;
+ super.dispose();
+ }
+
+ String recordingFileDirectory;
+
+ _startRecording() async {
+ PermissionStatus status = await Permission.microphone.request();
+ if (!status.isGranted) {
+ PermissionStatus status = await Permission.microphone.request();
+ if (!status.isGranted) {
+ Fluttertoast.showToast(msg: "Permission Denied");
+ return;
+ }
+ }
+ _timer = Timer.periodic(const Duration(seconds: 1), (timer) {
+ setState(() {
+ String duration = Duration(seconds: timer?.tick).toString();
+ duration = duration.substring(duration.indexOf(":") + 1, duration.indexOf("."));
+
+ String recordTime = ((timer?.tick ?? 0) / 60)?.toStringAsFixed(2)?.replaceFirst(".", ":");
+ // print("recordTime:$recordTime");
+ if (recordTime.length == 4 || recordTime.length == 7) {
+ recordTime = "0$recordTime";
+ }
+ _timeController.text = duration;
+ });
+ });
+ _rive.addController(SimpleAnimation('recording'));
+ if (!_recorderIsOpened) {
+ // await _myRecorder.openRecorder();
+ _recorderIsOpened = true;
+ }
+ final Directory tempDir = await getTemporaryDirectory();
+ recordingFileDirectory = "${tempDir.path}/record_${DateTime.now().millisecondsSinceEpoch}.mp3";
+ RecordMp3.instance.start(recordingFileDirectory, (type) {
+ // record fail callback
+ });
+
+ // await _myRecorder.startRecorder(toFile: "record_${DateTime.now().millisecondsSinceEpoch}.mp3", codec: Codec.aacADTS, sampleRate: 360000, bitRate: 360000);
+
+ _recording = true;
+ setState(() {});
+ }
+
+ _stopRecording() async {
+ if (!_recording) {
+ setState(() {});
+ return;
+ }
+ if (_timer?.isActive ?? false) {
+ _timer.cancel();
+ }
+ RecordMp3.instance.stop();
+
+ //String path = (await _myRecorder.stopRecorder()).toString();
+ _record = recordingFileDirectory;
+ widget.onRecord(recordingFileDirectory);
+ _recording = false;
+ setState(() {});
+ }
+
+ void _startListening() async {
+ _speechEnabled = _speechToText.isAvailable;
+ if (_speechToText.isListening) {
+ Fluttertoast.showToast(msg: "Currently in use");
+ return;
+ }
+ if (!_speechEnabled) return;
+ await _speechToText.listen(
+ onResult: (SpeechRecognitionResult result) {
+ _commentController.text = result.recognizedWords;
+ widget.onMessageChange(_commentController.text);
+ setState(() {});
+ },
+ localeId: _settingProvider.speechToText);
+ setState(() {});
+ }
+
+ void _stopListening() async {
+ await _speechToText.stop();
+ setState(() {});
+ }
+
+ _cancelRecording() async {
+ if (!_recording) return;
+ RecordMp3.instance.stop();
+ // String path = await _myRecorder.stopRecorder();
+ // _myRecorder.deleteRecord(fileName: path);
+ _rive.addController(SimpleAnimation('delete'));
+
+ // rebuild();
+ _recording = false;
+ await Future.delayed(const Duration(seconds: 1));
+ if (!_recording) setState(() {});
+ // _message.memoryAudio.;
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ if (node.hasFocus && widget.enabled) node.unfocus();
+ _settingProvider ??= Provider.of(context);
+ return Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ if (!_recording) ...[
+ AppTextFormField(
+ controller: _commentController,
+ labelText: _speechToText.isListening ? "Listening..." : context.translation.callComments,
+ alignLabelWithHint: true,
+ showWithoutDecoration: true,
+ backgroundColor: Colors.transparent,
+ textInputType: TextInputType.multiline,
+ // suffixIcon:
+ // (_recording ? "record".toLottieAsset(height: 24) : (_record != null ? "trash" : "mic").toSvgAsset(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20, height: 24))
+ // .paddingOnly(end: 16),
+ initialValue: widget.initialMessage,
+ onChange: (text) {
+ widget.onMessageChange(text);
+ },
+ onSaved: (text) {
+ widget.onMessageChange(text);
+ },
+ ).expanded,
+ (_speechToText.isListening
+ ? SizedBox(
+ height: 24.toScreenHeight,
+ width: 24.toScreenWidth,
+ child: const Icon(
+ Icons.fiber_manual_record,
+ color: Colors.red,
+ )).onPress(() {
+ _stopListening();
+ })
+ : PopupMenuButton(
+ child: SizedBox(
+ height: 24.toScreenHeight,
+ width: 24.toScreenWidth,
+ child: "speech_to_text".toSvgAsset(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20, height: 24, width: 24),
+ ),
+ onSelected: (String selectedLanguage) {
+ _settingProvider.setSpeechToText(selectedLanguage);
+ _startListening();
+ },
+ itemBuilder: (BuildContext context) {
+ return [
+ const PopupMenuItem(
+ value: 'ar',
+ child: Text('Arabic'),
+ ),
+ const PopupMenuItem(
+ value: 'en',
+ child: Text('English'),
+ ),
+ ];
+ },
+ ))
+ .paddingOnly(end: 16,top: 16),
+ ],
+
+ if (_recording)
+ AppTextFormField(
+ enable: widget.enabled,
+ node: node,
+ backgroundColor: Colors.transparent,
+ showWithoutDecoration: true,
+ controller: _timeController,
+ labelText: context.translation.recordVoice,
+ textInputType: TextInputType.multiline,
+ alignLabelWithHint: true,
+ initialValue: (_timeController?.text?.isEmpty ?? true) ? "00:00" : _timeController?.text,
+ // suffixIcon:
+ // (_recording ? "record".toLottieAsset(height: 24) : (_record != null ? "trash" : "mic").toSvgAsset(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20, height: 24))
+ // .paddingOnly(end: 16),
+ ).expanded,
+
+ // SizedBox(
+ // height: 24.toScreenHeight,
+ // width: 24.toScreenWidth,
+ // child: "speech_to_text".toSvgAsset(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20, height: 24, width: 24),
+ // ).paddingOnly(end: 16).onPress(_speechEnabled
+ // ? () async {
+ // if (!_speechEnabled) {
+ // Fluttertoast.showToast(msg: "microphone not available");
+ // return;
+ // }
+ // if (_speechToText.isListening) {
+ // _stopListening();
+ // } else {
+ // PopupMenuButton(
+ // onSelected: (String selectedLanguage) {
+ // _settingProvider.setSpeechToText(selectedLanguage);
+ // _startListening();
+ // },
+ // itemBuilder: (BuildContext context) => >[
+ // const PopupMenuItem(
+ // value: "ar",
+ // child: Text('Arabic'),
+ // ),
+ // const PopupMenuItem(
+ // value: "en",
+ // child: Text('English'),
+ // ),
+ // ],
+ // );
+ // }
+ // }
+ // : null),
+ SizedBox(
+ height: _recording ? 40 : 24.toScreenHeight,
+ width: _recording ? 40 : 24.toScreenWidth,
+ child: (_recording
+ ? "record".toLottieAsset(height: 24)
+ : (_record != null ? "trash" : "mic").toSvgAsset(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20, height: 24, width: 24)),
+ ).paddingOnly(end: 16,top: 16).onPress(() {
+ if (_recording) {
+ _stopRecording();
+ } else if (_record != null) {
+ _timeController?.text = "00:00";
+ widget.onRecord(null);
+ _record = null;
+ setState(() {});
+ } else {
+ _startRecording();
+ }
+ }),
+ ],
+ ),
+ if (_record != null) ...[
+ //8.height,
+ const Divider().defaultStyle(context),
+ ASoundPlayer(audio: _record).paddingOnly(top: 8, bottom: 16, start: 16, end: 16),
+ ]
+ ],
+ ).toShadowContainer(context, padding: 0);
+ }
+}