Daniel Salas DG
Daniel Salas DG

Reputation: 109

Playing or not playing in text to speech

I have a program that translates a text into speech, in flutter, so far so good, the question is How to make the program show a text that says the status of "playing" and "not playing" in the program, that is, while the voice is playing, the "playing" status is displayed.

I would really appreciate your response.

This is my code:

import 'package:flutter/material.dart';
import 'package:flutter_tts/flutter_tts.dart';

class TextVoicePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: TextVoice(),
    );
  }
}

class TextVoice extends StatefulWidget {
  @override
  _Speak createState() => _Speak();
}

class _Speak extends State<TextVoice> {
  final FlutterTts flutterTts = FlutterTts();

  @override
  Widget build(BuildContext context) {
    bool speaking = false;
    TextEditingController textEditingController = TextEditingController();

    Future _speak(String text) async {
      await flutterTts.setLanguage("es-MX");
      await flutterTts.setPitch(1);
      await flutterTts.speak(text);
    }

    Future _stop() async {
      await flutterTts.stop();
    }

    return Scaffold(
        body: Stack(
          children: <Widget>[
            Padding(
              padding: EdgeInsets.all(30.0),
              child: TextFormField(
                controller: textEditingController,
              ),
            ),
          ],
        ),
        floatingActionButtonLocation:
            FloatingActionButtonLocation.miniCenterDocked,
        floatingActionButton: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              FloatingActionButton(
                backgroundColor: Colors.green,
                foregroundColor: Colors.white,
                heroTag: "btn",
                onPressed: () => _speak(textEditingController.text),
                child: Icon(Icons.play_arrow),
              ),
              SizedBox(
                width: 130,
              ),
              FloatingActionButton(
                foregroundColor: Colors.white,
                backgroundColor: Colors.red,
                heroTag: "btn2",
                onPressed: () => _stop(),
                child: Icon(Icons.stop),
              )
            ],
          ),
        ));
  }
}

Upvotes: 1

Views: 2368

Answers (3)

harizh
harizh

Reputation: 386

You can configure FlutterToast widget to your flutter app and as per your status you can give messages as a toast to your flutter app.

add dependency fluttertoast: ^8.0.8

Example code:

Fluttertoast.showToast(
    msg: 'Playing',
    toastLength: Toast.LENGTH_SHORT,
    gravity: ToastGravity.CENTER,
    timeInSecForIosWeb: 4,
    textColor: const Color.fromRGBO(0, 0, 0, 1),
    webPosition: "center",
    webBgColor: "linear-gradient(to right, #5aff15, #5aff15)",
    backgroundColor: const Color.fromRGBO(90,255,21,1),
  );

Upvotes: 0

Rodrigo Cardozo
Rodrigo Cardozo

Reputation: 435

I've made some changes to the code and added the behavior you were looking for. I'll enumerate the changes:

1- Moved the variables speaking and textEditingController as attributes of the class, as this is the correct place to define them.

2- I included an initState() to initialize textEditingController and, as I found in flutter_tts documentation, I added two handler methods to make the switch of the text from "Playing" to "Not playing".

3- Also added a dispose() method too. Mainly because TextEditingController should be disposed when the widget lifecycle ends (you could read more about Flutter lifecycle in the official documentation or in this great article).

4- I wrapped the Stack with a Column and appended a SizedBox with a Text to display the status (I think that the Stack widget may not be the best option to use in this situation. I would switch it to a simple Container maybe).

5- Finally, I moved _speak and _stop methods out of the build function, and placed them as methods of the class.

You might also want to take a look at the official flutter documentation about the use of setState.

I've pointed out the changes in the code below:

import 'package:flutter/material.dart';
import 'package:flutter_tts/flutter_tts.dart';

class TextVoicePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: TextVoice(),
    );
  }
}

class TextVoice extends StatefulWidget {
  @override
  _Speak createState() => _Speak();
}

class _Speak extends State<TextVoice> {
  final FlutterTts flutterTts = FlutterTts();
  ///1
  bool speaking = false;
  TextEditingController textEditingController;

  @override ///2
  void initState() {
    textEditingController = TextEditingController();
    flutterTts.setStartHandler(() {
      ///This is called when the audio starts
      setState(() {
        speaking = true;
      });
    });

    flutterTts.setCompletionHandler(() {
      ///This is called when the audio ends
      setState(() {
        speaking = false;
      });
    });
    super.initState();
  }

  @override ///3
  void dispose() {
    textEditingController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Column(
          children: [
            Stack(
              children: <Widget>[
                Padding(
                  padding: EdgeInsets.all(30.0),
                  child: TextFormField(
                    controller: textEditingController,
                  ),
                ),
              ],
            ),
            SizedBox( ///4
              child: Text(
                speaking ? "Playing" : "Not playing"
              ),
            )
          ],
        ),
        floatingActionButtonLocation:
        FloatingActionButtonLocation.miniCenterDocked,
        floatingActionButton: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              FloatingActionButton(
                backgroundColor: Colors.green,
                foregroundColor: Colors.white,
                heroTag: "btn",
                onPressed: () => _speak(textEditingController.text),
                child: Icon(Icons.play_arrow),
              ),
              SizedBox(
                width: 130,
              ),
              FloatingActionButton(
                foregroundColor: Colors.white,
                backgroundColor: Colors.red,
                heroTag: "btn2",
                onPressed: () => _stop(),
                child: Icon(Icons.stop),
              )
            ],
          ),
        ));
  }

  ///5
  Future _speak(String text) async {
    await flutterTts.setLanguage("es-MX");
    await flutterTts.setPitch(1);
    await flutterTts.speak(text);
  }

  Future _stop() async {
    await flutterTts.stop();
  }
}

Upvotes: 3

Rodrigo Cardozo
Rodrigo Cardozo

Reputation: 435

I've made some changes to the code and added the behavior you were looking for. I'll enumerate the changes:

1- Moved the variables speaking and textEditingController as attributes of the class, as this is the correct place to define them.

2- I included an initState() to initialize textEditingController and, as I found in flutter_tts documentation, I added two handler methods to make the switch of the text from "Playing" to "Not playing".

3- Also added a dispose() method too. Mainly because TextEditingController should be disposed when the widget lifecycle ends (you could read more about Flutter lifecycle in the official documentation or in this great article).

4- I wrapped the Stack with a Column and appended a SizedBox with a Text to display the status (I think that the Stack widget may not be the best option to use in this situation. I would switch it to a simple Container maybe).

5- Finally, I moved _speak and _stop methods out of the build function, and placed them as methods of the class.

You might also want to take a look at the official flutter documentation about the use of setState.

I've pointed out the changes in the code below:

class TextVoicePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: TextVoice(),
    );
  }
}

class TextVoice extends StatefulWidget {
  @override
  _Speak createState() => _Speak();
}

class _Speak extends State<TextVoice> {
  final FlutterTts flutterTts = FlutterTts();
  ///1
  bool speaking = false;
  TextEditingController textEditingController;

  @override ///2
  void initState() {
    textEditingController = TextEditingController();
    flutterTts.setStartHandler(() {
      ///This is called when the audio starts
      setState(() {
        speaking = true;
      });
    });

    flutterTts.setCompletionHandler(() {
      ///This is called when the audio ends
      setState(() {
        speaking = false;
      });
    });
    super.initState();
  }

  @override ///3
  void dispose() {
    textEditingController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Column(
          children: [
            Stack(
              children: <Widget>[
                Padding(
                  padding: EdgeInsets.all(30.0),
                  child: TextFormField(
                    controller: textEditingController,
                  ),
                ),
              ],
            ),
            SizedBox( ///4
              child: Text(
                speaking ? "Playing" : "Not playing"
              ),
            )
          ],
        ),
        floatingActionButtonLocation:
        FloatingActionButtonLocation.miniCenterDocked,
        floatingActionButton: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              FloatingActionButton(
                backgroundColor: Colors.green,
                foregroundColor: Colors.white,
                heroTag: "btn",
                onPressed: () => _speak(textEditingController.text),
                child: Icon(Icons.play_arrow),
              ),
              SizedBox(
                width: 130,
              ),
              FloatingActionButton(
                foregroundColor: Colors.white,
                backgroundColor: Colors.red,
                heroTag: "btn2",
                onPressed: () => _stop(),
                child: Icon(Icons.stop),
              )
            ],
          ),
        ));
  }

  ///5
  Future _speak(String text) async {
    await flutterTts.setLanguage("es-MX");
    await flutterTts.setPitch(1);
    await flutterTts.speak(text);
  }

  Future _stop() async {
    await flutterTts.stop();
  }
}

Upvotes: 1

Related Questions