@ -59,8 +59,7 @@ import 'package:flutter_tts/flutter_tts.dart';
import ' package:permission_handler/permission_handler.dart ' ;
import ' package:provider/provider.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:speech_to_text/speech_to_text.dart ' as stt ;
import ' package:diplomaticquarterapp/pages/BookAppointment/DoctorProfile.dart ' ;
import ' package:diplomaticquarterapp/pages/BookAppointment/Search.dart ' ;
import ' package:flutter/cupertino.dart ' ;
@ -82,7 +81,7 @@ class _FloatingSearchButton extends State<FloatingSearchButton>
RobotProvider eventProvider = RobotProvider ( ) ;
bool isLoading = false ;
bool isError = false ;
final SpeechToText speech = SpeechToText ( ) ;
stt . SpeechToText speech = stt . SpeechToText ( ) ;
String error = ' ' ;
String _currentLocaleId = " " ;
String lastError ;
@ -102,28 +101,40 @@ class _FloatingSearchButton extends State<FloatingSearchButton>
var sharedPref = new AppSharedPreferences ( ) ;
bool _hasSpeech = false ;
ProjectViewModel projectProvider ;
bool isAnimationEnable = fals e;
bool isAnimationEnable = tru e;
AnimationController controller ;
Animation < Offset > offset ;
String networkImage ;
bool isArabic ;
@ override
void initState ( ) {
controller =
AnimationController ( vsync: this , duration: Duration ( seconds: 1 ) ) ;
offset = Tween < Offset > ( begin: Offset .zero , end: Offset ( 0.0 , 1 .0) )
offset = Tween < Offset > ( begin: Offset (0.0 , 1.0 ) , end: Offset ( 0.0 , 0 .0) )
. animate ( controller ) ;
initialSpeak ( ) ;
Future . delayed ( const Duration ( seconds: 2 ) , ( ) {
if ( IS_VOICE_COMMAND_CLOSED = = true ) {
controller . reverse ( from: - 1 ) ;
}
if ( mounted ) {
/ / Future . delayed ( const Duration ( seconds: 2 ) , ( ) {
isArabic = Provider . of < ProjectViewModel > ( context , listen: false ) . isArabic ;
requestPermissions ( ) ;
getUserData ( ) ;
initialSpeak ( ) ;
setState ( ( ) {
if ( IS_TEXT_COMPLETED ) {
isAnimationEnable = false ;
}
} ) ;
}
event . controller . stream . listen ( ( p ) {
if ( p [ ' isRobotVisible ' ] = = ' true ' ) {
if ( this . mounted ) {
setState ( ( ) {
sharedPref . setBool ( IS_ROBOT_VISIBLE , true ) ;
controller . reverse ( ) ;
if ( IS_VOICE_COMMAND_CLOSED = = false ) {
controller . forward ( ) ;
}
} ) ;
}
}
@ -141,21 +152,25 @@ class _FloatingSearchButton extends State<FloatingSearchButton>
}
@ override
void didUpdateWidget ( FloatingSearchButton oldWidget ) {
/ / super . didUpdateWidget ( oldWidget ) ;
/ / event . controller . stream . listen ( ( p ) {
/ / if ( p [ ' animationEnable ' ] ! = ' false ' ) {
/ / initialSpeak ( ) ;
void dispose ( ) {
controller . dispose ( ) ;
super . dispose ( ) ;
}
/ / @ override
/ / void didUpdateWidget ( FloatingSearchButton oldWidget ) {
/ / / / super . didUpdateWidget ( oldWidget ) ;
/ / / / event . controller . stream . listen ( ( p ) {
/ / / / if ( p [ ' animationEnable ' ] ! = ' false ' ) {
/ / / / initialSpeak ( ) ;
/ / / / }
/ / / / } ) ;
/ / }
/ / } ) ;
}
AuthenticatedUserObject authenticatedUserObject =
locator < AuthenticatedUserObject > ( ) ;
VitalSignService _vitalSignService = locator < VitalSignService > ( ) ;
@ override
Widget build ( BuildContext context ) {
projectProvider = Provider . of ( context ) ;
return Container (
child: SlideTransition ( position: offset , child: getStack ( ) ) ) ;
}
@ -180,7 +195,6 @@ class _FloatingSearchButton extends State<FloatingSearchButton>
: ' assets/images/gif/robot-idle.gif ' ) ,
) ,
onTap: ( ) {
RoboSearch . isClosed = false ;
new RoboSearch ( context: context ) . showAlertDialog ( context ) ;
initSpeechState ( ) . then ( ( value ) = > { startVoiceSearch ( ) } ) ;
} ,
@ -192,8 +206,8 @@ class _FloatingSearchButton extends State<FloatingSearchButton>
onTap: ( ) {
setState ( ( ) {
if ( this . mounted ) {
controller . forward ( ) ;
sharedPref. setBool ( IS_ROBOT_VISIBLE , false ) ;
controller . reverse ( ) ;
IS_VOICE_COMMAND_CLOSED = true ;
}
} ) ;
} ,
@ -213,25 +227,38 @@ class _FloatingSearchButton extends State<FloatingSearchButton>
startVoiceSearch ( ) async {
_currentLocaleId =
TranslationBase . of ( AppGlobal . context ) . locale . languageCode ;
bool available = await speech . initialize (
onStatus: statusListener , onError: errorListener ) ;
if ( available ) {
speech . listen (
onResult: resultListener ,
listenFor: Duration ( seconds: 10 ) ,
/ / listenMode: ListenMode . confirmation ,
localeId: _currentLocaleId = = ' en ' ? ' en-US ' : ' ar-SA ' ,
onSoundLevelChange: soundLevelListener ,
cancelOnError: true ,
partialResults: true ,
onDevice: true ,
listenMode: ListenMode . deviceDefault ) ;
) ;
} else {
print ( " The user has denied the use of speech recognition. " ) ;
}
/ / some time later . . .
/ / speech . stop ( ) ;
/ / speech . listen (
/ / onResult: resultListener ,
/ / listenFor: Duration ( seconds: 10 ) ,
/ / localeId: _currentLocaleId = = ' en ' ? ' en-US ' : ' ar-SA ' ,
/ / onSoundLevelChange: soundLevelListener ,
/ / cancelOnError: true ,
/ / partialResults: true ,
/ / onDevice: true ,
/ / listenMode: ListenMode . deviceDefault ) ;
}
void resultListener ( SpeechRecognitionResult result ) {
/ / lastWords = " ${ result . recognizedWords } - ${ result . finalResult } " ;
void resultListener ( result ) {
reconizedWord = result . recognizedWords ;
event . setValue ( { " searchText " : reconizedWord } ) ;
if ( result . finalResult = = true ) {
Future . delayed ( const Duration ( seconds: 1 ) , ( ) {
_speak ( reconizedWord ) ;
RoboSearch . closeAlertDialog ( context ) ;
/ / Navigator . of ( context ) . pop ( ) ;
} ) ;
}
}
@ -250,10 +277,13 @@ class _FloatingSearchButton extends State<FloatingSearchButton>
}
void requestPermissions ( ) async {
if ( await Permission . microphone . isDenied | |
await Permission . microphone . isUndetermined ) {
Map < Permission , PermissionStatus > statuses = await [
Permission . microphone ,
] . request ( ) ;
}
}
Future < void > initSpeechState ( ) async {
bool hasSpeech = await speech . initialize (
@ -274,9 +304,7 @@ class _FloatingSearchButton extends State<FloatingSearchButton>
void errorListener ( SpeechRecognitionError error ) {
event . setValue ( { " searchText " : ' null ' } ) ;
/ / setState ( ( ) {
/ / reconizedWord = " ${ error . errorMsg } - ${ error . permanent } " ;
/ / } ) ;
RoboSearch . closeAlertDialog ( context ) ;
}
void statusListener ( String status ) {
@ -298,9 +326,7 @@ class _FloatingSearchButton extends State<FloatingSearchButton>
}
getCommands ( result ) async {
print ( result ) ;
results = result ;
switch ( result [ " CommandNumber " ] ) {
case ' 100 ' :
{
@ -797,14 +823,16 @@ class _FloatingSearchButton extends State<FloatingSearchButton>
}
speak ( { isInit } ) async {
/ / if ( mounted ) {
setState ( ( ) {
this . networkImage = results [ ' AnimationURL ' ] ;
this . isAnimationEnable = true ;
} ) ;
if ( Provider . of < ProjectViewModel > ( context , listen: false ) . isArabic = =
false & &
results [ ' ReturnMessage ' ] ! = null ) {
/ / }
if ( isInit = = true ) {
event . setValue ( { " animationEnable " : ' true ' } ) ;
}
if ( isArabic = = false & & results [ ' ReturnMessage ' ] ! = null ) {
await flutterTts
. setVoice ( { " name " : " en-au-x-aub-network " , " locale " : " en-AU " } ) ;
await flutterTts . speak ( results [ ' ReturnMessage ' ] ) ;
@ -840,44 +868,32 @@ class _FloatingSearchButton extends State<FloatingSearchButton>
}
initialSpeak ( ) async {
await flutterTts . awaitSpeakCompletion ( true ) ;
results = {
' ReturnMessage_Ar ' :
" هذه الخدمة تم تصميمها لتتمكن من ربط الملفات الطبية للعائلة بملفك الطبي حتى تتمكن من إدارة سجلاتهم عن طريق تسجيل الدخول إلى ملفك الطبي. " ,
' ReturnMessage ' :
" Through this service, you will be able to link your family medical files to your medical file so that you can manage their records by login to your medical file. "
} ;
if ( await sharedPref . getBool ( IS_ROBOT_INIT ) = = null ) {
if ( IS_VOICE_COMMAND_CLOSED = = false ) {
if ( IS_TEXT_COMPLETED = = false ) {
this . speak ( isInit: true ) ;
controller . reverse ( ) ;
} else {
controller . forward ( ) ;
}
/ / if ( Provider . of < ProjectViewModel > ( context , listen: false ) . isArabic = =
/ / false & &
/ / results [ ' ReturnMessage ' ] ! = null ) {
/ / await flutterTts
/ / . setVoice ( { " name " : " en-au-x-aub-network " , " locale " : " en-AU " } ) ;
/ / await flutterTts . speak ( results [ ' ReturnMessage ' ] ) ;
/ / } else if ( results [ ' ReturnMessage_Ar ' ] ! = null ) {
/ / await flutterTts
/ / . setVoice ( { " name " : " ar-xa-x-ard-network " , " locale " : " ar " } ) ;
/ / await flutterTts . speak ( results [ ' ReturnMessage_Ar ' ] ) ;
/ / }
/ / this . isAnimationEnable = true ;
/ / stopAnimation ( ) ;
controller . forward ( ) ;
}
}
stopAnimation ( { isInit } ) async {
if ( isInit && ( await sharedPref . getBool ( IS_ROBOT_INIT ) = = null ) ) {
sharedPref. setBool ( IS_ROBOT_INIT , isInit ) ;
if ( isInit = = true ) {
IS_TEXT_COMPLETED = true ;
}
flutterTts . setCompletionHandler ( ( ) = > {
event . setValue ( { " animationEnable " : ' false ' } ) ,
flutterTts . setCompletionHandler ( ( ) async {
event . setValue ( { " animationEnable " : ' false ' } ) ;
setState ( ( ) {
this . networkImage = null ;
this . isAnimationEnable = false ;
} )
} ) ;
} ) ;
}
@ -895,30 +911,81 @@ class _FloatingSearchButton extends State<FloatingSearchButton>
class RoboSearch {
final BuildContext context ;
var event = RobotProvider ( ) ;
var searchText ;
static StreamSubscription < dynamic > streamSubscription ;
static var isClosed = false ;
static var dialog ;
RoboSearch ( {
@ required this . context ,
} ) ;
showAlertDialog ( BuildContext context ) {
AlertDialog alert = AlertDialog (
content: StatefulBuilder (
builder: ( BuildContext context , StateSetter setState ) {
/ / AlertDialog alert = AlertDialog
/ / AlertDialog alert = AlertDialog ( content: MyStatefulBuilder ( dispose: ( ) {
/ / print ( ' dispose!!!!!!!!!!!! ' ) ;
/ / } )
/ / isClosed = true ;
/ / streamSubscription . cancel ( ) ;
/ / } , builder: ( BuildContext context , StateSetter setState ) {
/ / / / print ( streamSubscription ) ;
/ / } ) ,
/ / ) ;
/ / show the dialog
showDialog (
context: context ,
barrierDismissible: true ,
builder: ( BuildContext context ) {
dialog = context ;
return MyStatefulBuilder (
dispose: ( ) { } ,
) ;
} ,
) ;
print ( dialog ) ;
}
static closeAlertDialog ( BuildContext context ) {
Navigator . of ( dialog ) . pop ( ) ;
}
}
typedef Disposer = void Function ( ) ;
class MyStatefulBuilder extends StatefulWidget {
const MyStatefulBuilder ( {
/ / @ required this . builder ,
@ required this . dispose ,
} ) ;
/ / final StatefulWidgetBuilder builder ;
final Disposer dispose ;
@ override
_MyStatefulBuilderState createState ( ) = > _MyStatefulBuilderState ( ) ;
}
class _MyStatefulBuilderState extends State < MyStatefulBuilder > {
var event = RobotProvider ( ) ;
var searchText ;
static StreamSubscription < dynamic > streamSubscription ;
static var isClosed = false ;
@ override
void initState ( ) {
streamSubscription = event . controller . stream . listen ( ( p ) {
if ( p [ ' searchText ' ] ! = ' null ' & &
if ( ( p [ ' searchText ' ] ! = ' null ' & &
p [ ' searchText ' ] ! = null & &
p [ ' searchText ' ] ! = " " & &
isClosed = = false ) {
isClosed = = false ) & &
mounted ) {
setState ( ( ) {
searchText = p [ ' searchText ' ] ;
} ) ;
}
} ) ;
print ( streamSubscription ) ;
return Container (
super . initState ( ) ;
}
@ override
Widget build ( BuildContext context ) = > AlertDialog (
content: Container (
color: Colors . white ,
height: SizeConfig . realScreenHeight * 0.5 ,
width: SizeConfig . realScreenWidth * 0.8 ,
@ -952,7 +1019,7 @@ class RoboSearch {
child: Center (
child: Text ( searchText ! = null & & searchText ! = ' null '
? searchText
: ' Try saying something ' ) ) ) ,
: TranslationBase . of ( context ) . trySaying ) ) ) ,
searchText = = ' null '
? Center (
child: RaisedButton (
@ -964,22 +1031,11 @@ class RoboSearch {
) )
: SizedBox ( )
] ) ,
) ) ;
} ) ,
) ;
/ / show the dialog
showDialog (
context: context ,
builder: ( BuildContext context ) {
return alert ;
} ,
) . then ( ( value ) = > { } ) ;
}
) ) ) ;
static closeAlertDialog ( BuildContext context ) {
isClosed = true ;
streamSubscription . cancel ( ) ;
Navigator. of ( context ) . pop ( ) ;
@ override
void dispose ( ) {
super . dispose ( ) ;
widget . dispose ( ) ;
}
}