Loading screen when the chromecastButton is created

I am using better_player and flutter_cast_video packages.
When I play a video, the chromecast button is created, if I click on the screen so that it and the other controls disappear and I press again so that they appear, the chromecast button is created again. Along with this creation, a loading screen of the same Chromecast appears for a few milliseconds.
I need to solve that problem, I have searched the internal code of the flutter_cast_video package and I can’t find anything that solves it either.
Here I leave the respective code for the screen that plays the video

class VideoPlayerScreenValue extends State<VideoPlayerScreen> {
  BetterPlayerController? _betterPlayerPlusController;
  bool areButtonsVisible = true;
  ValueNotifier<bool> areControlsVisible = ValueNotifier<bool>(true);
  ValueNotifier<bool> isPlayingNotifier = ValueNotifier<bool>(true);
  ValueNotifier<bool> controllerActive = ValueNotifier<bool>(false);
  ValueNotifier<Duration> actualSecond = ValueNotifier<Duration>(Duration.zero);
  ChromeCastController? _controller;

  // Este ValueNotifier mantendrá el estado de reproducción del video
  ValueNotifier<bool> isPlaying = ValueNotifier<bool>(true);

// Estas funciones se llamarán cuando se presionen los botones de salto
  void seekForward() {
    if (controllerActive.value) {
      _controller!.seek(interval: 10, relative: true);
    } else {
      _betterPlayerPlusController!.seekTo(
          _betterPlayerPlusController!.videoPlayerController!.value.position +
              const Duration(seconds: 10));
    }
  }

  void seekBackward() {
    if (controllerActive.value) {
      _controller!.seek(interval: -10, relative: true);
    } else {
      _betterPlayerPlusController!.seekTo(
          _betterPlayerPlusController!.videoPlayerController!.value.position -
              const Duration(seconds: 10));
    }
  }

//Initialize the player
  @override
  void initState() {
    SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []);
    if (widget.videoUrl.isNotEmpty) {
      super.initState();
      SystemChrome.setPreferredOrientations(
          [DeviceOrientation.landscapeRight, DeviceOrientation.landscapeLeft]);
      _betterPlayerPlusController = BetterPlayerController(
        _betterPlayerConfiguration(),
      );

      initPlayer();
    }
  }

  @override
  Widget build(BuildContext context) {
    if (widget.videoUrl.isEmpty) {
      return const Center(
        child: Text(
          'No video available',
          style: TextStyle(color: Colors.white),
        ),
      );
    }
    return _vpControls();
  }

  String _formatDuration(Duration duration) {
    final minutes = duration.inMinutes.toString().padLeft(2, '0');
    final seconds = (duration.inSeconds % 60).toString().padLeft(2, '0');
    return '$minutes:$seconds';
  }

  Widget _vpControls() {
    return Material(
      type: MaterialType.transparency,
      child: ValueListenableBuilder<bool>(
        valueListenable: areControlsVisible,
        builder: (context, isVisible, child) {
          return Stack(children: [
            GestureDetector(
              onTap: _toggleControls,
              child: BetterPlayer(
                controller: _betterPlayerPlusController!,
              ),
            ),
            if (isVisible) ...[
              Positioned(
                top: 25,
                left: 0,
                child: ValueListenableBuilder<bool>(
                  valueListenable: isPlayingNotifier,
                  builder: (context, value, child) {
                    return Visibility(
                      visible: value,
                      child: IconButton(
                        icon: const Icon(Icons.close, color: Colors.white),
                        onPressed: () {
                          Navigator.of(context).pop();
                        },
                      ),
                    );
                  },
                ),
              ),
              Positioned(
                bottom: 45,
                right: 0,
                child: ValueListenableBuilder<bool>(
                  valueListenable: areControlsVisible,
                  builder: (context, isVisible, child) {
                    return Visibility(
                      visible: isVisible,
                      child: Padding(
                        padding: const EdgeInsets.only(bottom: 20.0, right: 10),
                        child: SizedBox(
                          width:
                              50, // Ajusta estos valores al tamaño que desees
                          height: 50,
                          child: _chromeCastButton(),
                        ),
                      ),
                    );
                  },
                ),
              ),
              Positioned(
                left: 50,
                top: MediaQuery.of(context).size.height * 0.45,
                child: IconButton(
                  icon: const Icon(
                    Icons.fast_rewind,
                    color: Colors.white,
                    size: 33,
                  ),
                  onPressed: seekBackward,
                ),
              ),
              Positioned(
                right: 50,
                top: MediaQuery.of(context).size.height * 0.45,
                child: IconButton(
                  icon: const Icon(
                    Icons.fast_forward,
                    color: Colors.white,
                    size: 33,
                  ),
                  onPressed: seekForward,
                ),
              ),
              Positioned(
                top: MediaQuery.of(context).size.height * 0.45,
                right: MediaQuery.of(context).size.width * 0.5,
                child: ValueListenableBuilder<bool>(
                  valueListenable: isPlaying,
                  builder: (context, value, child) {
                    return IconButton(
                      icon: value
                          ? const Icon(
                              Icons.pause,
                              color: Colors.white,
                              size: 33,
                            )
                          : const Icon(
                              Icons.play_arrow,
                              color: Colors.white,
                              size: 33,
                            ),
                      onPressed: () {
                        if (value) {
                          if (controllerActive.value) {
                            _controller!.pause();
                          } else {
                            _betterPlayerPlusController!.pause();
                          }
                        } else {
                          if (controllerActive.value) {
                            _controller!.play();
                          } else {
                            _betterPlayerPlusController!.play();
                          }
                        }
                        // Aquí cambiamos el valor de isPlaying cuando se presiona el botón
                        isPlaying.value = !value;
                      },
                    );
                  },
                ),
              ),
              Positioned(
                bottom: 33,
                left: 0,
                right: 0,
                child: ValueListenableBuilder<Duration>(
                  valueListenable: actualSecond,
                  builder: (context, value, child) {
                    final totalDuration = _betterPlayerPlusController!
                            .videoPlayerController!.value.duration ??
                        Duration.zero;
                    return Slider(
                      value: value.inSeconds.toDouble(),
                      min: 0.0,
                      max: totalDuration.inSeconds.toDouble(),
                      onChanged: (double newValue) {
                        if (controllerActive.value) {
                          print("Tiempo 1");
                          _controller!
                              .seek(interval: newValue, relative: false);
                        } else {
                          print(2);
                          _betterPlayerPlusController!
                              .seekTo(Duration(seconds: newValue.toInt()));
                          actualSecond.value =
                              Duration(seconds: newValue.toInt());
                        }
                      },
                    );
                  },
                ),
              ),
              Positioned(
                bottom: 10,
                left: 0,
                right: 0,
                child: ValueListenableBuilder<Duration>(
                  valueListenable: actualSecond,
                  builder: (context, value, child) {
                    final totalDuration = _betterPlayerPlusController!
                            .videoPlayerController!.value.duration ??
                        Duration.zero;
                    return Text(
                      '${_formatDuration(value)} / ${_formatDuration(totalDuration)}',
                      textAlign: TextAlign.center,
                      style: const TextStyle(color: Colors.white),
                    );
                  },
                ),
              ),
            ]
          ]);
        },
      ),
    );
  }

  Timer? _hideControlsTimer;

  void _toggleControls() {
    if (areControlsVisible.value) {
      areControlsVisible.value = false;
      _hideControlsTimer?.cancel();
    } else {
      areControlsVisible.value = true;

      _hideControlsTimer = Timer(const Duration(seconds: 10), () {
        if (areControlsVisible.value) {
          areControlsVisible.value = false;
        }
      });
    }
  }

//Configuration of Better Player
  BetterPlayerConfiguration _betterPlayerConfiguration() {
    return BetterPlayerConfiguration(
      autoDispose: true,
      startAt: widget.startAt,
      aspectRatio: 16 / 9,
      fit: BoxFit.contain,
      subtitlesConfiguration: _betterPlayerSubtitlesConfiguration(),
      allowedScreenSleep: false,
      autoDetectFullscreenDeviceOrientation: false,
      deviceOrientationsOnFullScreen: [
        DeviceOrientation.landscapeRight,
        DeviceOrientation.landscapeLeft
      ],
      errorBuilder: (context, message) {
        return Center(
          child: Text(
            message!,
            style: const TextStyle(color: Colors.white),
          ),
        );
      },
      autoPlay: true,
      controlsConfiguration: _betterPlayerControlsConfiguration(),
    );
  }

//Configuration of Better Player Subtitles
  BetterPlayerSubtitlesConfiguration _betterPlayerSubtitlesConfiguration() {
    return const BetterPlayerSubtitlesConfiguration(
      alignment: Alignment.center,
      fontSize: 20,
      fontColor: Colors.white,
      backgroundColor: Colors.black,
    );
  }

//Configuration of Better Player Controls Configuration
  BetterPlayerControlsConfiguration _betterPlayerControlsConfiguration() {
    return const BetterPlayerControlsConfiguration(
      //fullscreenEnableIcon: Icons.fullscreen_exit,
      enableSkips: false,
      showControls: false,
      enableOverflowMenu: false,
      enablePlayPause: false,
      enableFullscreen: false,
      enableMute: false,
      enableSubtitles: false,
      enableProgressBar: false,

      textColor: Color.fromARGB(255, 255, 255, 255),
      iconsColor: Color.fromARGB(255, 255, 255, 255),
    );
  }

//Configuration of the dataSource
  Future<void> initPlayer() async {
    BetterPlayerDataSource betterPlayerPlusDataSource = BetterPlayerDataSource(
      BetterPlayerDataSourceType.network,
      widget.videoUrl,
    );

    _betterPlayerPlusController!.setupDataSource(betterPlayerPlusDataSource);

    _betterPlayerPlusController!.addEventsListener((event) {
      // Close the player when the video is finished
      if (event.betterPlayerEventType == BetterPlayerEventType.finished) {
        Navigator.of(context).pop();
      }
    });

    // Add a listener to the video player controller
    _betterPlayerPlusController!.videoPlayerController!.addListener(() {
      // Update the actualSecond value with the current position of the video
      actualSecond.value =
          _betterPlayerPlusController!.videoPlayerController!.value.position;
    });
// Start a timer to hide the controls after 2 seconds
    _hideControlsTimer = Timer(const Duration(seconds: 2), () {
      if (areControlsVisible.value) {
        areControlsVisible.value = false;
      }
    });
  }

//Dispose the player
  @override
  void dispose() {
    SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
        overlays: [SystemUiOverlay.top, SystemUiOverlay.bottom]);
    if (widget.videoUrl.isNotEmpty) {
      saveLastPosition();
    }
    _betterPlayerPlusController!.dispose();
    SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
    _controller?.removeSessionListener();
    _hideControlsTimer?.cancel();

    super.dispose();
  }

//Save the last position of the video
  Future<void> saveLastPosition() async {
    Dio dio = Dio();
    Duration? lastPosition =
        _betterPlayerPlusController!.videoPlayerController?.value.position;

    int lastSecond = lastPosition!.inSeconds;

    String jsonData = jsonEncode({
      'content': widget.content,
      'resource': widget.id,
      'second': lastSecond,
    });

    await dio.post(
      'https://${Environment.KEY_URL}/api/1.0/seconds_view/',
      options: Options(
        headers: {
          "Content-Type": "application/json",
          "Authorization": "Bearer ${Environment.DIO_TOKEN}",
        },
      ),
      data: jsonData,
    );
  }

  //! ********************* CHROME CAST ********************* !//

  //This widget is used to show the chromecast button

  Widget _chromeCastButton() {
    return ChromeCastButton(
      onButtonCreated: (controller) {
        if (_controller == null) {
          _controller = controller;
          _controller!.addSessionListener();
        }
      },
      onSessionStarted: _onSessionStarted,
      onRequestCompleted: _onRequestCompleted,
      onSessionEnded: onSessionEnded,
      onRequestFailed: (String? error) async {
        _controller!.endSession();
      },
      onPlayerStatusUpdated: (int statusCode) {
        // Aquí puedes manejar las actualizaciones de estado del reproductor
        print('Player status updated: $statusCode');
      },
    );
  }

  void onSessionEnded() async {
    print("Session ended");
    controllerActive.value = false;
    _controller!.removeSessionListener();
    _controller!.endSession(); // End the session when it's ended
    _controller!.addSessionListener();
  }

  //Cuando se completa la solicitud y aparece el video
  void _onRequestCompleted() async {
    if (actualSecond.value != Duration.zero) {
      _controller!.seek(
          interval: actualSecond.value.inSeconds.toDouble(), relative: true);
      actualSecond.value = Duration.zero;
    }
  }

  //Antes de que aparezca el video, mientras se carga

  void _onSessionStarted() async {
    controllerActive.value = true;
    _betterPlayerPlusController!.pause();
    await _controller!.loadMedia(
      widget.videoUrl.isNotEmpty ? widget.videoUrl : "",
      title: widget.name,
      subtitle: widget.description,
    );
    actualSecond.value =
        _betterPlayerPlusController!.videoPlayerController!.value.position;

    // Show a notification when the video is playing on Chromecast
    const AndroidNotificationDetails androidPlatformChannelSpecifics =
        AndroidNotificationDetails(
      'your channel id',
      'your channel name',
      playSound: false,
      enableVibration: false,
      importance: Importance.max,
      priority: Priority.high,
      actions: <AndroidNotificationAction>[
        AndroidNotificationAction('stop', 'Stop'),
      ],
    );

    const NotificationDetails platformChannelSpecifics =
        NotificationDetails(android: androidPlatformChannelSpecifics);

    await flutterLocalNotificationsPlugin.show(
      0,
      'Video is playing on Chromecast',
      'Tap Stop to stop the video',
      platformChannelSpecifics,
    );
  }

  Timer? _timer;
  Duration? position, duration;

  //This function is used to monitor the chromecast
  Future<void> _monitor() async {
    // monitor cast events
    Duration dur = await _controller!.duration(),
        pos = await _controller!.position();
    if (duration == null || duration!.inSeconds != dur.inSeconds) {
      setState(() {
        duration = dur;
      });
    }
    if (position == null || position!.inSeconds != pos.inSeconds) {
      setState(() {
        position = pos;
      });
    }
  }

  //This function is used to reset the timer
  void resetTimer() {
    _timer?.cancel();
    _timer = null;
  }

  //This function is used to start the timer
  void startTimer() {
    if (_timer?.isActive ?? false) {
      return;
    }
    resetTimer();
    _timer = Timer.periodic(const Duration(seconds: 1), (timer) {
      _monitor();
    });
  }

I want that loading screen to stop appearing

New contributor

Cristian is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật