Skip to content

FlutterTtsPlugin.onInitListenerWithoutCallback$lambda$5 #599

@abdalazeezalyosfi

Description

@abdalazeezalyosfi

🐛 Bug Report

FlutterTtsPlugin.onInitListenerWithoutCallback$lambda$5
Fatal Exception: java.util.ConcurrentModificationException:
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1111)
at java.util.ArrayList$Itr.next(ArrayList.java:1064)
at com.tundralabs.fluttertts.FlutterTtsPlugin.onInitListenerWithoutCallback$lambda$5(FlutterTtsPlugin.java:32)
at android.speech.tts.TextToSpeech.lambda$dispatchOnInit$0(TextToSpeech.java:973)
at android.speech.tts.TextToSpeech.$r8$lambda$y-uaMPlobiYouiY_T7xFoJSwPww()
at android.speech.tts.TextToSpeech$$ExternalSyntheticLambda13.run(D8$$SyntheticClass)
at android.speech.tts.TextToSpeech.dispatchOnInit(TextToSpeech.java:982)
at android.speech.tts.TextToSpeech.-$$Nest$mdispatchOnInit()
at android.speech.tts.TextToSpeech$Connection$SetupConnectionAsyncTask.onPostExecute(TextToSpeech.java:2378)
at android.speech.tts.TextToSpeech$Connection$SetupConnectionAsyncTask.onPostExecute(TextToSpeech.java:2338)
at android.os.AsyncTask.finish(AsyncTask.java:771)
at android.os.AsyncTask.-$$Nest$mfinish()
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:788)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loopOnce(Looper.java:257)
at android.os.Looper.loop(Looper.java:342)
at android.app.ActivityThread.main(ActivityThread.java:9638)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:619)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:929)

Image Image

Expected behavior

should be work without exception

Reproduction steps

try the widget i am using and try to read text

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 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 createState() => _ListenToArticleButtonState();
}

class _ListenToArticleButtonState extends State {
final ValueNotifier 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 getDefaultVoice(BuildContext context) async {
if (!Platform.isAndroid && mounted && context.mounted) return;
var soundCubit = context.read();

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
///#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();
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().logFunctionError(e, s,
functionName: "listen_to_article_button/playSound/setVoice");
}
}
var text = widget.text ?? "";
if (Platform.isAndroid) {
///limitation on android
///#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 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
// ///#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