Skip to content

Attempt to invoke virtual method 'java.lang.String android.speech.tts.Voice.getName() #598

@abdalazeezalyosfi

Description

@abdalazeezalyosfi

🐛 Bug Report

Attempt to invoke virtual method 'java.lang.String android.speech.tts.Voice.getName()

Expected behavior

should be worked without error

Reproduction steps

  flutterTts.setEngine('com.google.android.tts');
Image

Configuration

class ListenToArticleButton extends StatefulWidget {
  const ListenToArticleButton({
    super.key,
    required this.text,
    required this.isTablet,
    required this.flutterTts,
    required this.isSoundPlaying,
    this.verticalMargin,
    this.hideOneNoMoreThanVoice = false,
    this.title,
    this.topWidget,
    this.customButton,
  });
  final String? title;
  final FlutterTts flutterTts;
  final ValueNotifier<bool> isSoundPlaying;
////needed in settings to prevent user select default sound if no sounds
  final bool hideOneNoMoreThanVoice;
  final bool isTablet;
  final double? verticalMargin;
  final Function(bool playing)? customButton;
  final String? text;
  final Widget? topWidget;
  @override
  State<ListenToArticleButton> createState() => _ListenToArticleButtonState();
}

class _ListenToArticleButtonState extends State<ListenToArticleButton> {
  final ValueNotifier<bool> isLoading = ValueNotifier(false);
  late bool lastIsMute;
  late final AppLifecycleListener _listener;
  Map<String, String>? selectedVoid;

  @override
  void initState() {
    _listener = AppLifecycleListener(
      onPause: () async {
        pauseByCloseApp = true;
        widget.flutterTts.stop();

        // await widget.flutterTts.pause();
        widget.isSoundPlaying.value = false;
      },
      onInactive: () async {
        pauseByCloseApp = true;
        // await widget.flutterTts.pause();
        widget.flutterTts.stop();
        widget.isSoundPlaying.value = false;
      },
      onHide: () async {
        pauseByCloseApp = true;
        // await widget.flutterTts.pause();
        widget.flutterTts.stop();

        widget.isSoundPlaying.value = false;
      },
      onStateChange: (value) => print("valuedasdsads $value"),
    );
    lastIsMute = isMute.value;
    setFlutterTtsHandler();
    widget.flutterTts.getVoices.then(
      (value) {
        WidgetsBinding.instance.addPostFrameCallback(
          (timeStamp) {
            if (mounted && context.mounted) {
              getDefaultVoice(context);
            }

            // final filtered = (value ?? [])
            //     .where((element) =>
            //         // (element is Map<String, dynamic>) &&
            //         (element['locale'] as String?)?.contains('ar') == true)
            //     .map((e) => Map<String, String>.from(e as Map));
            //
            // voiceList = filtered.toList();
            voiceList = List.of((value ?? []).where(
              (element) =>
                  (element is Map) &&
                  ((element['locale'] as String?)?.contains("ar") ?? false),
            ))
                .map(
                  (e) => e == null ? null : Map<String, String>.from(e),
                )
                .nonNulls
                .toList();
            if (mounted) setState(() {});
          },
        );
      },
    );
    super.initState();
  }

  List<Map<String, String>>? voiceList;

  Future<void> getDefaultVoice(BuildContext context) async {
    if (!Platform.isAndroid && mounted && context.mounted) return;
    var soundCubit = context.read<DefaultSoundCubit>();

    var voice = await widget.flutterTts.getDefaultVoice;
    if (voice != null) {
      if (soundCubit.state == null) {
        soundCubit.setVoice(Map<String, String>.from(voice));
      }
    }
  }

  bool pauseByCloseApp = false;

  void setFlutterTtsHandler() {
    if (Platform.isAndroid) {
      ///limitation on android
      ///https://github.com/dlutton/flutter_tts/issues/66
      widget.flutterTts.awaitSpeakCompletion(true);
    }
    widget.flutterTts.setCompletionHandler(
      () {
        isLoading.value = false;
        if (!lastIsMute) isMute.value = false;
        widget.isSoundPlaying.value = false;
      },
    );
    widget.flutterTts.setCancelHandler(
      () {
        isLoading.value = false;
        if (!lastIsMute) isMute.value = false;
        widget.isSoundPlaying.value = false;
      },
    );
    widget.flutterTts.setErrorHandler(
      (e) {
        isLoading.value = false;
        if (!lastIsMute) isMute.value = false;
        showMessage(e.toString(), true);
        widget.isSoundPlaying.value = false;
      },
    );
    widget.flutterTts.setStartHandler(
      () {
        isLoading.value = false;

        if (!lastIsMute) isMute.value = true;
        widget.isSoundPlaying.value = true;
      },
    );
    widget.flutterTts.setPauseHandler(
      () {
        if (!lastIsMute) isMute.value = false;
        widget.isSoundPlaying.value = false;
      },
    );

    if (Platform.isAndroid) {
      widget.flutterTts.setEngine('com.google.android.tts');
    }
    // if (Platform.isAndroid) {
    //   _getDefaultEngine();
    //   _getDefaultVoice();
    // }
  }

  playSound(bool playing) async {
    var soundCubit = context.read<DefaultSoundCubit>();
    pauseByCloseApp = false;
    if (playing) {
      widget.flutterTts.stop();
    } else {
      bool isInstalled = Platform.isAndroid
          ? await widget.flutterTts.isLanguageInstalled("ar")
          : true;
      // bool isInstalled = await widget.flutterTts.isLanguageInstalled("ar");
      if (isInstalled) {
        await widget.flutterTts.setLanguage("ar");
        isLoading.value = true;
        if (soundCubit.state != null &&
            (soundCubit.state?.isNotEmpty ?? false)) {
          try {
            await widget.flutterTts.setVoice(soundCubit.state!);
          } catch (e, s) {
            getIt<CrashlyticsService>().logFunctionError(e, s,
                functionName: "listen_to_article_button/playSound/setVoice");
          }
        }
        var text = widget.text ?? "";
        if (Platform.isAndroid) {
          ///limitation on android
          ///https://github.com/dlutton/flutter_tts/issues/66
          var count = text.length;
          var max = await widget.flutterTts.getMaxSpeechInputLength ?? 100;
          var loopCount = count ~/ max;

          for (var i = 0; i <= loopCount; i++) {
            if (i != loopCount) {
              if (!mounted) return;
              if (!pauseByCloseApp) {
                await widget.flutterTts
                    .speak(text.substring(i * max, (i + 1) * max));
              }
            } else {
              if (!mounted) return;
              var end = (count - ((i * max)) + (i * max));
              if (!pauseByCloseApp) {
                await widget.flutterTts.speak(text.substring(i * max, end));
              }
            }
          }
        } else {
          if (!pauseByCloseApp) {
            await widget.flutterTts.speak(widget.text ?? "");
          }
        }
      } else {
        if (Platform.isAndroid) {
          showDialog(
              context: context,
              builder: (context) => AlertDialog(
                    title: AppText("اللغة غير مثبتة على جهازك"),
                    content: AppText.style6(
                        "الرجاء تنزيل اللغة العربية حتى تتمكن من الاستماع إلى الأخبار"),
                    actionsAlignment: MainAxisAlignment.start,
                    actions: [
                      TextButton(
                          onPressed: () {
                            TtsInstaller.installVoiceData();
                            context.pop();
                          },
                          child: AppText("تنزيل")),
                      TextButton(
                          onPressed: () {
                            context.pop();
                          },
                          child: AppText("إلغاء")),
                    ],
                  ));
        }
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    if (widget.hideOneNoMoreThanVoice) {
      if ((!((voiceList?.length ?? 0) > 1)) || kDebugMode) return SizedBox();
    }
    final button = ValueListenableBuilder(
        valueListenable: widget.isSoundPlaying,
        builder: (context, playing, _) {
          return AnimatedSize(
            duration: Duration(milliseconds: 1000),
            child: GestureDetector(
              onTap: () async {
                playSound(playing);
                // if (StorageService.isEmailTest) {
                //   List<dynamic> voiceList = await widget.flutterTts.getVoices;
                //   if (playing) {
                //     await widget.flutterTts.stop();
                //   } else {
                //     // final d = await widget.flutterTts.getDefaultVoice;
                //     // print(d);
                //     showModalBottomSheet(
                //       context: context,
                //       builder: (context) {
                //         return SafeArea(
                //           child: SingleChildScrollView(
                //             child: Column(
                //               children: voiceList
                //                   .where(
                //                     (element) =>
                //                         (element['locale'] as String?)
                //                             ?.contains("ar") ??
                //                         false,
                //                   )
                //                   .map(
                //                     (e) => GestureDetector(
                //                       onTap: () async {
                //                         pauseByCloseApp = false;
                //                         if (playing) {
                //                           widget.flutterTts.stop();
                //                         } else {
                //                           await widget.flutterTts.clearVoice();
                //                           await widget.flutterTts.setVoice(
                //                               Map<String, String>.from(e));
                //                           selectedVoid =
                //                               Map<String, String>.from(e);
                //
                //                           ///TODO check if en or arabic
                //                           // var result = await widget.flutterTts
                //                           //     .isLanguageAvailable("ar");
                //                           // log(result.toString());
                //                           // await widget.flutterTts.setLanguage("ar");
                //                           // await widget.flutterTts.setLanguage("en");
                //                           var text = widget.text ?? "";
                //                           context.pop();
                //                           if (Platform.isAndroid) {
                //                             ///limitation on android
                //                             ///https://github.com/dlutton/flutter_tts/issues/66
                //                             var count = text.length;
                //                             var max = 4000;
                //                             var loopCount = count ~/ max;
                //
                //                             for (var i = 0;
                //                                 i <= loopCount;
                //                                 i++) {
                //                               if (i != loopCount) {
                //                                 if (!mounted) return;
                //                                 if (!pauseByCloseApp)
                //                                   await widget.flutterTts.speak(
                //                                       text.substring(i * max,
                //                                           (i + 1) * max));
                //                               } else {
                //                                 if (!mounted) return;
                //                                 var end = (count -
                //                                     ((i * max)) +
                //                                     (i * max));
                //                                 if (!pauseByCloseApp)
                //                                   await widget.flutterTts.speak(text
                //                                       .substring(i * max, end));
                //                               }
                //                             }
                //                           } else {
                //                             if (!pauseByCloseApp)
                //                               await widget.flutterTts
                //                                   .speak(widget.text ?? "");
                //                           }
                //                         }
                //                       },
                //                       onLongPress: () {
                //                         Clipboard.setData(
                //                             ClipboardData(text: e.toString()));
                //                       },
                //                       child: Padding(
                //                         padding: const EdgeInsets.all(8.0),
                //                         child: AppText.style1(
                //                           "$e",
                //                           textAlign: TextAlign.center,
                //                           style: TextStyle(
                //                               color: selectedVoid.toString() ==
                //                                       Map<String, String>.from(
                //                                               e)
                //                                           .toString()
                //                                   ? Colors.red
                //                                   : null,
                //                               fontWeight: selectedVoid == e
                //                                   ? FontWeight.bold
                //                                   : FontWeight.w400),
                //                         ),
                //                       ),
                //                     ),
                //                   )
                //                   .toList(),
                //             ),
                //           ),
                //         );
                //       },
                //     );
                //   }
                // } else {
              },
              child: widget.customButton != null
                  ? widget.customButton!(playing)
                  : Align(
                      alignment: Alignment.center,
                      child: Container(
                        margin: EdgeInsets.symmetric(
                            vertical: widget.verticalMargin ?? 20),
                        padding:
                            EdgeInsets.symmetric(vertical: 6, horizontal: 20),
                        decoration: BoxDecoration(
                            borderRadius: BorderRadius.circular(10),
                            color: context.colorScheme.grey10),
                        child: Row(
                          mainAxisSize: MainAxisSize.min,
                          children: [
                            if ((voiceList?.length ?? 0) > 1)
                              GestureDetector(
                                  behavior: HitTestBehavior.opaque,
                                  onTap: () async {
                                    bool isTablet =
                                        HelperFunction.isTablet(context);

                                    await showModalBottomSheet(
                                      context: context,
                                      showDragHandle: true,
                                      // isScrollControlled: false,
                                      backgroundColor: Colors.white,
                                      constraints: BoxConstraints(
                                          maxHeight: 0.9.sh, minWidth: 1.sw),
                                      builder: (xtx) => BlocProvider.value(
                                        value:
                                            context.read<DefaultSoundCubit>(),
                                        child: BlocBuilder<DefaultSoundCubit,
                                            Map<String, String>?>(
                                          builder: (context, state) {
                                            return SizedBox(
                                              width: 1.sw,
                                              child: SingleChildScrollView(
                                                child: Column(
                                                  children: [
                                                    // HeaderBottomSheet(),
                                                    AppText.style10(
                                                      "قم باختيار الصوت الافتراضي",
                                                      textAlign:
                                                          TextAlign.center,
                                                      color: Colors.black,
                                                    ),
                                                    40.verticalSpace,
                                                    ...?voiceList?.mapIndexed(
                                                      (index, e) {
                                                        {
                                                          var isSelected = context
                                                                  .read<
                                                                      DefaultSoundCubit>()
                                                                  .state
                                                                  .toString() ==
                                                              e.toString();
                                                          return Column(
                                                            crossAxisAlignment:
                                                                CrossAxisAlignment
                                                                    .center,
                                                            children: [
                                                              GestureDetector(
                                                                onTap:
                                                                    () async {
                                                                  context
                                                                      .read<
                                                                          DefaultSoundCubit>()
                                                                      .setVoice(Map<
                                                                          String,
                                                                          String>.from(e));
                                                                  await widget
                                                                      .flutterTts
                                                                      .stop();

                                                                  playSound(
                                                                      false);
                                                                  // if (isSelected) {
                                                                  //   searchFilters.value = List.of(searchFilters.value)
                                                                  //     ..removeWhere((e) => e.index == element.index);
                                                                  //   if (searchFilters.value.isEmpty) {
                                                                  //     searchFilters.value = SearchFilter.values;
                                                                  //   }
                                                                  //
                                                                  //
                                                                  // }
                                                                },
                                                                child: Column(
                                                                  children: [
                                                                    AppText
                                                                        .style6(
                                                                      "Voice $index",
                                                                      style: isSelected
                                                                          ? (isTablet
                                                                              ? AppTextStyles.textStyle1Tablet
                                                                              : AppTextStyles.textStyle1)
                                                                          : null,
                                                                      textAlign:
                                                                          TextAlign
                                                                              .center,
                                                                      // color: isSelected
                                                                      //     ? context
                                                                      //         .colorScheme
                                                                      //         .mainRedColor1
                                                                      //     : Colors
                                                                      //         .black,
                                                                    ),
                                                                  ],
                                                                ),
                                                              ),
                                                              NewsDivider(
                                                                isTablet:
                                                                    isTablet,
                                                                height: 30,
                                                              )
                                                            ],
                                                          );
                                                        }
                                                      },
                                                    )
                                                  ],
                                                ),
                                              ),
                                            );
                                          },
                                        ),
                                      ),
                                    );
                                    widget.flutterTts.stop();
                                  },
                                  child: Container(
                                    width: widget.isTablet ? 30.r : 30,
                                    height: widget.isTablet ? 30.r : 30,
                                    // decoration: BoxDecoration(
                                    //   shape: BoxShape.circle,
                                    //   color: context.colorScheme.mainRedColor,
                                    // ),
                                    margin: const EdgeInsets.only(
                                      left: 8,
                                    ),
                                    child:
                                        AppImage.asset(Assets.iconsEditSound),
                                  )),
                            AppText.style6(
                              widget.title ??
                                  (playing
                                      ? "يتم الاستماع الى نص المقال"
                                      : "استمع إلى نص المقال"),
                              color: context.colorScheme.fontColor1,
                            ),
                            8.horizontalSpace,
                            ValueListenableBuilder(
                                valueListenable: isLoading,
                                builder: (context, _, __) {
                                  return (isLoading.value)
                                      ? SizedBox.square(
                                          dimension:
                                              widget.isTablet ? 30.r : 30,
                                          child: Center(
                                            child: AppLoading(
                                              dimension:
                                                  widget.isTablet ? 20.r : 20,
                                            ),
                                          ),
                                        )
                                      : Container(
                                          width: widget.isTablet ? 30.r : 30,
                                          height: widget.isTablet ? 30.r : 30,
                                          decoration: BoxDecoration(
                                              shape: BoxShape.circle,
                                              color: context
                                                  .colorScheme.mainRedColor),
                                          child: Center(
                                            child: AppImage.asset(playing
                                                ? Assets.iconsPause
                                                : Assets.iconsHeadphones),
                                          ),
                                        );
                                }),
                          ],
                        ),
                      ),
                    ),
            ),
          );
        });

    if (widget.topWidget != null) {
      return Column(
        children: [
          widget.topWidget!,
          button,
        ],
      );
    }
    return button;
  }

  @override
  void dispose() {
    widget.flutterTts.stop();
    // widget.flutterTts.clearVoice();
    _listener.dispose();
    super.dispose();
  }
}

Version: 0.1.x
flutter_tts: ^4.2.3

Platform:

  • 📱 iOS
  • [yes ] 🤖 Android

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions