0
votes

I'm using the Bloc package to update my widgets on a Flutter app. I try to update a variable which is a List of favorites. For that I'm getting the state and modifying it to the new value and then I yield the new one(state). The result is cannot see reflected changes  in the current page, but is working in the cloned state(As it is properly loaded in a new tab). What I'm doing wrong as I cannot see the changes reflected in the current state but able to do it in the clone? Please let me know if something is not clear or I should share something else from my codebase. 

Update 1: If I manually do a Hot reload I can see the changes, but I want to accomplish it automatically.

MASTER STATE

import 'package:meta/meta.dart' show required;
import 'package:documentales_app/models/youtube_video.dart';
import 'package:equatable/equatable.dart';

class MasterState extends Equatable {
  final int currentTab;
  final List<YoutubeVideo> history;
  final List<YoutubeVideo> favorites;

  MasterState(
      {@required this.currentTab, @required this.history, this.favorites});

  static MasterState initialState() =>
      MasterState(currentTab: 0, history: [], favorites: []);

  MasterState copyWith(
      {int currentTab,
      List<YoutubeVideo> history,
      List<YoutubeVideo> favorites}) {
    return MasterState(
        currentTab: currentTab ?? this.currentTab,
        history: history ?? this.history,
        favorites: favorites ?? this.favorites);
  }

  @override
  List<Object> get props => [currentTab, history, favorites];
}

MASTER BLOC

Stream<MasterState> _toggleInFavorites(MasterToggleInFavorites event) async* {
    final int index = this
        .state
        .favorites
        .indexWhere((item) => item.videoId == event.youtubeVideo.videoId);

    if (index == -1) {
      final favorites = List<YoutubeVideo>.from(this.state.favorites);
      favorites.add(event.youtubeVideo);
      event.youtubeVideo.isFavorite = true;

      yield this.state.copyWith(favorites: favorites);
    } else {
      final favorites = List<YoutubeVideo>.from(this.state.favorites);
      favorites.removeAt(index);
      event.youtubeVideo.isFavorite = false;

      yield this.state.copyWith(favorites: favorites);
    }
  }

Toggle Button

CupertinoButton(
                        padding: EdgeInsets.zero,
                        minSize: 30,
                        onPressed: () {
                          masterBloc.add(MasterToggleInFavorites(item));
                        },
                        child: CircleContainer(
                          child: Icon(
                            //Icons.playlist_add,
                            item.isFavorite
                                ? Icons.favorite
                                : Icons.favorite_border,
                            color: Colors.white,
                          ),
                          size: 35,
                        ),
                      ),

Favorites tab

import 'package:cached_network_image/cached_network_image.dart';
import 'package:documentales_app/blocs/pages/master_bloc/master_bloc.dart';
import 'package:documentales_app/blocs/pages/master_bloc/master_events.dart';
import 'package:documentales_app/models/youtube_video.dart';
import 'package:share/share.dart';
import 'package:documentales_app/widgets/circle_container.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_youtube/flutter_youtube.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import '../utils/keys.dart';

class YoutubeVideoItem extends StatelessWidget {
  final VoidCallback onDismissed;
  final YoutubeVideo item;

  const YoutubeVideoItem({@required this.item, this.onDismissed})
      : assert(item != null);

  Widget _getView(MasterBloc masterBloc) {
    return Container(
      child: CupertinoButton(
        padding: EdgeInsets.zero,
        onPressed: () {
          masterBloc.add(MasterAddToHistory(item));
          FlutterYoutube.playYoutubeVideoByUrl(
              apiKey: API_KEY,
              videoUrl: "https://www.youtube.com/watch?v=${item.videoId}",
              autoPlay: true, //default falase
              fullScreen: true //default false
              );
        },
        child: AspectRatio(
          aspectRatio: 12 / 3,
          child: Container(
            margin: EdgeInsets.symmetric(vertical: 5, horizontal: 10),
            padding: EdgeInsets.all(5),
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(10),
              color: Colors.greenAccent,
              boxShadow: [
                BoxShadow(color: Colors.black26, blurRadius: 5),
              ],
            ),
            child: Row(
              children: [
                Expanded(
                  flex: 4,
                  child: ClipRRect(
                    borderRadius: BorderRadius.circular(10),
                    child: CachedNetworkImage(
                      imageUrl: item.banner,
                      fit: BoxFit.cover,
                      height: double.infinity,
                    ),
                  ),
                ),
                Expanded(
                  flex: 5,
                  child: Container(
                    padding: EdgeInsets.all(10),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Text(
                          item.title,
                          maxLines: 2,
                          style: TextStyle(
                              fontWeight: FontWeight.w500,
                              color: Colors.white,
                              fontSize: 14),
                        ),
                        SizedBox(
                          height: 5,
                        ),
                        Expanded(
                          child: Text(
                            item.description,
                            overflow: TextOverflow.fade,
                            style: TextStyle(
                                fontWeight: FontWeight.w300,
                                color: Colors.grey[600],
                                fontSize: 13),
                          ),
                        ),
                      ],
                    ),
                  ),
                ),
                Expanded(
                  flex: 1,
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      CupertinoButton(
                        padding: EdgeInsets.zero,
                        minSize: 30,
                        onPressed: () {
                          masterBloc.add(MasterToggleInFavorites(item));
                        },
                        child: CircleContainer(
                          child: Icon(
                            //Icons.playlist_add,
                            item.isFavorite
                                ? Icons.favorite
                                : Icons.favorite_border,
                            color: Colors.white,
                          ),
                          size: 35,
                        ),
                      ),
                      CupertinoButton(
                        padding: EdgeInsets.zero,
                        minSize: 30,
                        onPressed: () {
                          Share.share(
                              'https://www.youtube.com/watch?v=${item.videoId}',
                              subject: 'Mira este impresionante documental');
                        },
                        child: CircleContainer(
                          child: Icon(
                            Icons.share,
                            color: Colors.white,
                          ),
                          size: 35,
                        ),
                      ),
                    ],
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    final masterBloc = BlocProvider.of<MasterBloc>(context);

    if (onDismissed != null) {
      return Dismissible(
        key: Key(item.videoId),
        onDismissed: (_) {
          if (onDismissed != null) {
            onDismissed();
          }
        },
        child: _getView(masterBloc),
      );
    }
    return _getView(masterBloc);
  }
}

Home Tab

import 'package:cached_network_image/cached_network_image.dart';
import 'package:documentales_app/api/account_api.dart';
import 'package:documentales_app/api/youtube_api.dart';
import 'package:documentales_app/models/play_list.dart';
import 'package:documentales_app/models/youtube_video.dart';
import 'package:documentales_app/pages/home_page_widgets/home_tab_shimmer.dart';
import 'package:documentales_app/pages/home_page_widgets/new_videos.dart';
import 'package:documentales_app/pages/home_page_widgets/top_play_lists.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import '../../utils/keys.dart';

class HomeTab extends StatefulWidget {
  @override
  _HomeTabState createState() => _HomeTabState();
}

class _HomeTabState extends State<HomeTab> {
  AccountApi _accountApi = AccountApi();
  YoutubeApi _youtubeApi = YoutubeApi(apiKey: API_KEY);
  List<dynamic> _users = [];
  List<PlayList> _playlists = [];
  List<YoutubeVideo> _newVideos = [];
  bool _isLoading = true;

  @override
  void initState() {
    super.initState();
    _load();
  }

  _load() async {
    final users = await _accountApi.getUsers(1);
    final List<PlayList> playLists =
        await _youtubeApi.getPlaylists('jklnvfyyklhjh');
    final List<YoutubeVideo> newVideos = await _youtubeApi
        .getPlaylistVideos('PLFXLg_sbbjkGKJbkjgkkGKkgk');
    setState(() {
      _users.addAll(users);
      _playlists.addAll(playLists);
      _newVideos.addAll(newVideos);
      _isLoading = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    return ListView(
      children: [
        _isLoading
            ? HomeTabShimmer()
            : Column(
                children: [
                  TopPlayLists(items: _playlists),
                  SizedBox(height: 10),
                  NewVideos(
                    items: _newVideos,
                  ),
                  SizedBox(height: 5),
                ],
              )
      ],
    );
  }
}
1

1 Answers

3
votes

Is there only one state?
I know that state is not changed by same name state.

If you want to use current structure like your code.
You need to add another state such as 'MasterStateChanging' between state changes.

<State File>
class MasterStateChanging extends Equatable {
  
}
<Bloc File>
Stream<MasterState> _toggleInFavorites(MasterToggleInFavorites event) async* {
    final int index = this
        .state
        .favorites
        .indexWhere((item) => item.videoId == event.youtubeVideo.videoId);


    yield MasterStateChanging();

    if (index == -1) {
      final favorites = List<YoutubeVideo>.from(this.state.favorites);
      favorites.add(event.youtubeVideo);
      event.youtubeVideo.isFavorite = true;

      yield this.state.copyWith(favorites: favorites);
    } else {
      final favorites = List<YoutubeVideo>.from(this.state.favorites);
      favorites.removeAt(index);
      event.youtubeVideo.isFavorite = false;

      yield this.state.copyWith(favorites: favorites);
    }
  }