Flutter theming bloc - flutter

I want the selected theme to be saved when exiting the application and the next time the application is launched, the theme that is saved is selected there
Code:
theme_bloc:
class ThemeBloc extends Bloc<ThemeEvent, ThemeState> {
ThemeBloc()
: super(ThemeState(false)) {
on<ThemeEvent>((event, emit) {
emit(ThemeState(event.isDark));
});
}
}
theme_state:
#immutable
class ThemeState extends Equatable {
CupertinoThemeData get themeData => isDark
? AppThemes.appThemeData[AppTheme.DarkAppTheme]!
: AppThemes.appThemeData[AppTheme.LightAppTheme]!;
ThemeState(this.isDark);
final bool isDark;
#override
List<Object?> get props => [isDark];
}
theme_event:
#immutable
class ThemeEvent extends Equatable {
final bool isDark;
ThemeEvent(this.isDark);
#override
List<Object?> get props => [isDark];
}

Related

mapEventToState is deprecated and not working anymore

i am Working on Flutter Chat Application and when i tried to implement the MessageBloc i found that mapEventToState is not Working anymore in Version 8.0 of Bloc
This is MessageEvent
import 'package:chat/chat.dart';
import 'package:equatable/equatable.dart';
abstract class MessageEvent extends Equatable {
const MessageEvent();
factory MessageEvent.onSubscribed(User user) => Subscribed(user);
factory MessageEvent.onMessageSent(List<Message> messages) =>
MessageSent(messages);
#override
List<Object?> get props => [];
}
class Subscribed extends MessageEvent {
final User user;
Subscribed(this.user);
#override
List<Object?> get props => [user];
}
class MessageSent extends MessageEvent {
final List<Message> messages;
MessageSent(this.messages);
#override
List<Object> get props => [messages];
}
class MessageReceived extends MessageEvent {
MessageReceived(this.message);
final Message message;
#override
List<Object> get props => [message];
}
And this is MessageState
import 'package:chat/chat.dart';
import 'package:equatable/equatable.dart';
abstract class MessageState extends Equatable {
const MessageState();
factory MessageState.initial() => MessageInitial();
factory MessageState.sent(Message message) => MessageSentSuccesfully(message);
factory MessageState.received(Message message) =>
MessageReceivedSuccesfully(message);
#override
List<Object> get props => [];
}
class MessageInitial extends MessageState {}
class MessageSentSuccesfully extends MessageState {
final Message message;
const MessageSentSuccesfully(this.message);
#override
List<Object> get props => [message];
}
class MessageReceivedSuccesfully extends MessageState {
final Message message;
const MessageReceivedSuccesfully(this.message);
#override
List<Object> get props => [message];
}
and finally this is MessageBloc
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:chat/chat.dart';
import 'package:flutter_newapp/src/blocs/message/message_event.dart';
import 'package:flutter_newapp/src/blocs/message/message_state.dart';
class MessageBloc extends Bloc<MessageEvent, MessageState> {
final IMessageService _messageService;
StreamSubscription? _subscription;
MessageBloc(this._messageService) : super(MessageState.initial());
#override
Stream<MessageState> mapEventToState(MessageEvent event) async* {
if (event is Subscribed) {
await _subscription?.cancel();
_subscription = _messageService
.messages(activeUser: event.user)
.listen((message) => add(MessageReceived(message)));
}
if (event is MessageReceived) {
yield MessageState.received(event.message);
}
if (event is MessageSent) {
final message = await _messageService.send(event.messages);
yield MessageState.sent(message);
}
}
#override
Future<void> close() {
_subscription?.cancel();
_messageService.dispose();
return super.close();
}
}
Can anyone propose me a Solution to Rewrite the MessageBloc in the new Version of Bloc ?
i am trying to move from version 7.1 of Bloc to 8.1 or the Latest version of Bloc and try to learn the new implementation of Blocs in Flutter

Flutter Bloc: state not rebuilding

I have a bloc listening to chats. Through the debugger, I can see that the bloc is catching live updates. However, the ui is not rebuilding when these changes occur. To see a change, I have to leave and reload the screen.
My chat state:
part of 'chat_bloc.dart';
abstract class ChatState extends Equatable {
const ChatState();
#override
List<Object?> get props => [];
}
class ChatLoading extends ChatState {}
class ChatLoaded extends ChatState {
final List<Chat?>? compiledChats;
const ChatLoaded({required this.compiledChats});
#override
List<Object?> get props => [compiledChats];
}
My chat events:
part of 'chat_bloc.dart';
abstract class ChatEvent extends Equatable {
const ChatEvent();
#override
List<Object?> get props => [];
}
class LoadChat extends ChatEvent {
const LoadChat();
#override
List<Object> get props => [];
}
class CloseChat extends ChatEvent {
const CloseChat();
#override
List<Object?> get props => [];
}
class UpdateChat extends ChatEvent {
final List<List<Chat?>> chats;
const UpdateChat({required this.chats});
#override
List<Object> get props => [chats];
}
My actual bloc:
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:hero/blocs/auth/auth_bloc.dart';
import 'package:hero/models/chat_model.dart';
import 'package:hero/models/user_model.dart';
import 'package:hero/repository/firestore_repository.dart';
part 'chat_event.dart';
part 'chat_state.dart';
class ChatBloc extends Bloc<ChatEvent, ChatState> {
final FirestoreRepository _firestoreRepository;
late StreamSubscription _chatListener;
ChatBloc({
required FirestoreRepository firestoreRepository,
}) : _firestoreRepository = firestoreRepository,
super(ChatLoading()) {
on<LoadChat>(_onLoadChat);
on<UpdateChat>(_onUpdateChat);
on<CloseChat>(_onCloseChat);
}
void _onLoadChat(
LoadChat event,
Emitter<ChatState> emit,
) {
_chatListener = _firestoreRepository.chats.listen((chats) {
add(
UpdateChat(
chats: chats,
),
);
});
}
void _onUpdateChat(
UpdateChat event,
Emitter<ChatState> emit,
) {
//generate compiledChats from event.chats
List<Chat?>? compiledChats = [];
for (List<Chat?> chatList in event.chats) {
for (Chat? chat in chatList) {
if (chat != null) {
compiledChats.add(chat);
}
}
}
emit(ChatLoaded(compiledChats: compiledChats));
}
void _onCloseChat(
CloseChat event,
Emitter<ChatState> emit,
) {
_chatListener.cancel();
print('ChatBloc disposed');
emit(ChatLoading());
}
#override
Future<void> close() async {
super.close();
}
}
For the scope of this problem, all that really matters is just looking at the updateChat and LoadChat methods. Any ideas? Thanks!

Access state from ui without an if statement

am following this Bloc's official example and I couldn't find a way how to access the state without that if statement.
Let's have the example below, I would like to display a specific text based on the initial value of showText, the only possible solution to access the state is via:
if(statement is ExampleInitial) {state.showText? return Text("yes") : return Text("no")}
But am finding this solution hard to implement when you have more values with initial values. Or am I doing this wrong?
////////// bloc
class ExampleBloc extends Bloc<ExampleEvent, ExampleState> {
ExampleBloc() : super(const ExampleInitial()) {
on<ExampleStarted>(_onExampleStarted);
}
void _onExampleStarted(ExampleStarted event, Emitter<ExampleState> emit) {
emit(const ExampleInitial());
}
}
////////// event
part of 'example_bloc.dart';
abstract class ExampleEvent extends Equatable {
const ExampleEvent();
}
class ExampleStarted extends ExampleEvent {
#override
List<Object> get props => [];
}
////////// state
part of 'example_bloc.dart';
abstract class ExampleState extends Equatable {
const ExampleState();
}
////////// state
class ExampleInitial extends ExampleState {
final bool showText = false;
const ExampleInitial();
#override
List<Object> get props => [showText];
}
// ui
class CreateExampleScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return BlocBuilder<ExampleBloc, ExampleState>(
builder: (context, state) {
return state.showText ? Text("yes") :Text("no"); // can't access to state.showText
});
}
}
You can declare a variable inside Bloc Class which will be global and need to be set inside the 'bloc.dart' file like in the case of Provider Package. This variable does not need state to be checked before accessing it in UI. You can access this value from the Navigation tree using context.
////////// bloc
class ExampleBloc extends Bloc<ExampleEvent, ExampleState> {
ExampleBloc() : super(const ExampleInitial()) {
on<ExampleStarted>(_onExampleStarted);
}
bool showText = false;
void _onExampleStarted(ExampleStarted event, Emitter<ExampleState> emit) {
emit(const ExampleInitial());
}
}
// ui
class CreateExampleScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return BlocProvider.of<ExampleBloc>(context).showText
? const Text('Yes')
: const Text('No');
}
}
There is another way in which you declare abstract State Class to always have the boolean value. So, whatever new class extends those State will have inherited boolean value from parent class. This concept is called inheritance in OOP.
////////// state
abstract class ExampleState extends Equatable {
const ExampleState();
final bool showText = false;
}
////////// state
class ExampleInitial extends ExampleState {
const ExampleInitial();
// You can also set ExampleInitial to accept showText and send it to its
// parent class using 'super' method in constructor,
// if parent class has constructor with 'showText' as boolean
#override
List<Object> get props => [];
}
// ui
class CreateExampleScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return BlocBuilder<ExampleBloc, ExampleState>(builder: (context, state) {
return state.showText ? const Text("yes") : const Text("no");
});
}
}
A pragmatic usecase for different State Classes having different state variables is as follows:
Let's account for three states while fetching data from api
-if(state is DataLoadingState),
// there is no need for state
-if(state is DataLoadedState)
// state need to have a variable named weatherData containing temperatures, cities and so on.
-if(state is ErrorWhileLoadingState)
// state needs to have a reason for the error. For example: errorMsg: 'Internal Server Error'
So, you need to check the state before accessing its values.

State is not yielded thus unable to change icon color

I'm working on a metronome app and having problem with the bloc states. I'm toggling the metronome on and off with a FAB button and expecting the FAB icon color to change upon toggling. Could you have a look at the code and direct me towards what I am doing wrong here?
/// EVENTS
abstract class MetronomeEvent extends Equatable {
const MetronomeEvent();
#override
List<Object> get props => [];
}
class InitMetronomeEvent extends MetronomeEvent {}
class DisposeMetronomeEvent extends MetronomeEvent {}
class ToggleOnOffMetronomeEvent extends MetronomeEvent {}
class IncreaseTempoMetronomeEvent extends MetronomeEvent {}
class DecreaseTempoMetronomeEvent extends MetronomeEvent {}
class ChangeTempoMetronomeEvent extends MetronomeEvent {
final int givenTempo;
const ChangeTempoMetronomeEvent({required this.givenTempo});
#override
List<Object> get props => [givenTempo];
#override
String toString() {
return 'ChangeTempoMetronomeEvent{givenTempo: $givenTempo}';
}
}
Here is the states:
/// STATES
abstract class MetronomeState extends Equatable {
const MetronomeState();
}
class MetronomeInitial extends MetronomeState {
#override
List<Object> get props => [];
}
class ToggleOnOffMetronomeState extends MetronomeState {
final bool isMetronomeOn;
const ToggleOnOffMetronomeState({required this.isMetronomeOn});
#override
List<Object?> get props => [isMetronomeOn];
}
And my bloc:
/// BLOC
class MetronomeBloc extends Bloc<MetronomeEvent, MetronomeState> {
final _metronome = getIt<MetronomeService>();
MetronomeBloc() : super(MetronomeInitial()) {
on<InitMetronomeEvent>((event, emit) {
_metronome.init();
});
on<DisposeMetronomeEvent>((event, emit) {
_metronome.dispose();
});
on<ToggleOnOffMetronomeEvent>((event, emit) {
_metronome.toggleOnOff();
emit(ToggleOnOffMetronomeState(isMetronomeOn: _metronome.isMetronomeOn));
debugPrint("TOGGLED METRONOME ${_metronome.isMetronomeOn ? "ON" : "OFF"}");
});
on<IncreaseTempoMetronomeEvent>((event, emit) {
_metronome.increaseTempo();
});
on<DecreaseTempoMetronomeEvent>((event, emit) {
_metronome.decreaseTempo();
});
on<ChangeTempoMetronomeEvent>((event, emit) {
_metronome.changeTempo(event.givenTempo);
});
}
}
And I'm using BlocBuilder to listen and rebuild the widget below:
FloatingActionButton(
onPressed: () {
_bloc.add(ToggleOnOffMetronomeEvent());
},
child: BlocBuilder<MetronomeBloc, MetronomeState>(
builder: (context, state) {
if (state is ToggleOnOffMetronomeState) {
_isMetronomeOn = state.isMetronomeOn;
}
return Icon(
Icons.power_settings_new,
color: _isMetronomeOn
? Colors.red
: Theme
.of(context)
.floatingActionButtonTheme
.backgroundColor,
);
},
),
)

flutter_bloc - how can i get value without BlocBuilder?

I'm still a beginner with streams and bloc pattern.
I would like to do following:
Trigger an event.
Based on the event get back a state with an object
Store this object as JSON in a database.
All examples are showing, how an object can be displayed in a widget with BlocBuilder. But I don't need to display the value, only get it and store it. I can't figure out how to get the value into a variable.
How can I do that? In the View class I'm dispatching the event, but now I need to know how to get the object in the state back without using BlocBuilder.
Here are the details:
Bloc
class SchoolBloc extends Bloc<SchoolEvent, SchoolState> {
final SchoolRepository _schoolRepository;
StreamSubscription _schoolSubscription;
SchoolBloc({#required SchoolRepository schoolRepository})
: assert(schoolRepository != null),
_schoolRepository = schoolRepository;
#override
SchoolState get initialState => SchoolsLoading();
#override
Stream<SchoolState> mapEventToState(SchoolEvent event) async* {
if (event is LoadSchool) {
yield* _mapLoadSchoolToState();
Stream<SchoolState> _mapLoadSchoolToState(LoadSchool event) async* {
_schoolSubscription?.cancel();
_schoolSubscription = _schoolRepository.school(event.id).listen(
(school) {
SchoolLoaded(school);
}
);
}
Event
#immutable
abstract class SchoolEvent extends Equatable {
SchoolEvent([List props = const []]) : super(props);
}
class LoadSchool extends SchoolEvent {
final String id;
LoadSchool(this.id) : super([id]);
#override
String toString() => 'LoadSchool';
}
State
#immutable
abstract class SchoolState extends Equatable {
SchoolState([List props = const []]) : super(props);
}
class SchoolLoaded extends SchoolState {
final School school;
SchoolLoaded([this.school]) : super([school]);
#override
String toString() => 'SchoolLoaded { school: $school}';
}
View
class CourseView extends StatefulWidget {
#override
State<StatefulWidget> createState() => _CourseViewState();
}
class _CourseViewState extends State<CourseView> {
#override
initState() {
super.initState();
print("this is my init text");
final _schoolBloc = BlocProvider.of<SchoolBloc>(context);
_schoolBloc.dispatch(LoadSchool("3kRHuyk20UggHwm4wrUI"));
// Here I want to get back the school object and save it to a db
}
Test that fails
For testing purposes I have done following:
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:teach_mob/core/blocs/school/school.dart';
class CourseView extends StatefulWidget {
#override
State<StatefulWidget> createState() => _CourseViewState();
}
class _CourseViewState extends State<CourseView> {
#override
void initState() {
super.initState();
BlocProvider.of<SchoolBloc>(context)
.dispatch(LoadSchool("3kRHuyk20UggHwm4wrUI"));
}
#override
Widget build(BuildContext context) {
return BlocListener<SchoolBloc, SchoolState>(
listener: (context, state) {
print("BlocListener is triggered");
},
child: Text("This is a test")
);
}
}
The LoadSchool event is triggered. The text in the child attribute of BlocListener is displayed, but the listener function that should print "BlocListener is triggered" is not executed.
Use BlocListener. It is meant to be used for those cases you mention.