1

I want the users of my app to be able to select text (words, but also whole sentences) in a WebViewWidget, and have an audio of that text played to them (via tts). I only want this to work with u̲n̲d̲e̲r̲l̲i̲n̲e̲d̲ text (or text visually highlighted and set apart from the rest in any other way).

This is part of my Widget tree, where I have tested a few gestureRecognizers (please read the comments):

child: GestureDetector(
  //gestureRecognizers of WebViewWidget don't do anything without this GestureDetector,
  //see: https://stackoverflow.com/questions/58811375/tapgesturerecognizer-not-working-in-flutter-webview#answer-59298134
  onTap: () => print('this line doesnt get printed'),
  child: WebViewWidget(
    controller: _controller,
    gestureRecognizers: {
      Factory<LongPressGestureRecognizer>(() => LongPressGestureRecognizer()
        ..onLongPress = () {
          print('onLongPress');
        }
        ..onLongPressStart = (LongPressStartDetails details) {
          print('onLongPressStart, ${details.globalPosition}, ${details.localPosition}');
        }),
      Factory<TapGestureRecognizer>(() => TapGestureRecognizer()
        ..onTap = () {
          print('onTap'); //this doesn't get printed at all
        }
        ..onTapDown = (TapDownDetails details) {
          //comment: this doesn't get printed unless I tap for a little long time (not as long as longPress)
          print('onTapDown, details: $details');
          /*TODO: I want to get a text selection and play audio (with tts)
             String selectedText = ...?
             TTSHelper.speak(text: selectedText);
           */
        }),
    },
  ),
),

Another approach to a possible solution for what I want

I have an initialization function, where I take html (without the html, body & head tags...) from firestore and wrap it in the html, body & head tags along with some custom CSS.

If there is no way to achieve my goal with Dart code, maybe there is a way for me to add JavaScript to the html, so that underlined words/sentences can be tapped to play audio via tts, or at least send that text over to my Dart code somehow?

  String _prepareHTML(String content) {
    return """<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
  body {background-color: ${getCSSColor(context, CustomColors.mainAppBG)};}
  h1, h2, h3, h4, h5, h6 {color: ${getCSSColor(context, CustomColors.blueWhiteText)};}
  p {color: ${getCSSColor(context, CustomColors.text)};}
  table { 
    width: 100%;
    table-layout: fixed;
    word-wrap: break-word;
  }
  table, tr, th, td {
    color: ${getCSSColor(context, CustomColors.text)};
    border: 1px solid ${getCSSColor(context, CustomColors.text)};
    border-collapse: collapse;
  }
  th, td {
    padding: 6px 12px;
    font-weight: bold;
    font-size: 1.25em;
  }
</style>
</head>
<body>
  $content
</body>
</html>""";
  }
Cedric
  • 470
  • 6
  • 20

1 Answers1

1

I think you might be able to achieve what you want by using some javascript and a javascriptChannel on the WebViewWidget. General idea below:

var controller = WebViewController();
controller.addJavascriptChannel(
  JavascriptChannel(
    name: 'underlinedTextSelectChannel',
    onMessageReceived: (message) {
      var data = json.decode(message.message);
      var text = data.text as String;

      TTSHelper.speak(text: selectedText);
    }
  )
)

...

var html = """
<html>
...
<body>
  $content
  # Within content:
  This is some text <p class="underlined-text">Say this!</p> Don't say this.
  <script>
    var underlinedTexts = document.querySelectorAll('.underlined-text');
    for(var t of underlinedTexts) {
      t.addEventListener('onClick', (e) => {
        underlinedTextSelectChannel.postMessage(JSON.stringify({
        text: e.target.innerText
       }))
      })
    }
  </script>
</body>
</html>
"""
Matthew Tory
  • 1,306
  • 2
  • 16
  • 30
  • 1
    my man this worked, with some minor corrections: data['text'] instead of data.text, and 'click' as 1st parameter in addEventListener(), 50 rep points well deserved – Cedric Feb 14 '23 at 16:32