I am trying to make that when I submit the button, the isLoading variable is set to true, and when the block issues the state it returns to false, to show a circular progress indicator.
My problem is that I don't know WHERE or HOW to put that variable, nor how to tell the bloc that this variable is true before / outside the BlocBuilder,
this is the code of my button:
TextButton(
child: Text("submit"),
onPressed: () {
context
.read<ShowMusicHomeBloc>()
.add(OnSearchTracks(q: _searchText.text));
_searchText.clear();
},
),
Could you give me a practical example how I can set this variable isLoading to true using flutter_bloc?
You can make a LoadingState and emit it when you press the button.
abstract class MyState {}
class MyLoadingState extends MyState {}
class MyLoadedState extends MyState {
final MyData data;
MyLoadedState(this.data);
}
// other states like ErrorState or InitialState
class MyCubit extends Cubit<MyState>{
MyCubit(this.someService) : super(MyLoadingState());
final SomeService someService;
Future<void> fetchData(){
emit(MyLoadingState);
final fetchedData = someService.fetchData();
emit(MyLoadedState(fetchedData));
}
}
you can apply the same concept to Blocs too.
Related
I want to make a coffee machine app
I want to update a checkbox in flutter bloc package,
I use bloc to state management
I try searching on the web but I don't have a good answer to this problem
tips to help me, my files are named AppCubit is a bloc file and AppState is states and ChangeCheckBox and the screen MainModule
AppCubit is cubit class
class AppCubit extends Cubit<AppState> {
AppCubit() : super(AppInitial());
// value in
bool isWithCreamChecked = false;
static AppCubit get(BuildContext context) => BlocProvider.of(context);
// this is a function for changing the value of the checkbox
void checkBox({bool? value, bool? changeValue}) {
changeValue = value!;
emit(ChangeCheckBox(value,changeValue));
}
}
AppState all states in the app
abstract class AppState {}
class AppInitial extends AppState {}
// checkbox states
class ChangeCheckBox extends AppState {
bool value;
bool changeValue;
ChangeCheckBox(this.value,this.changeValue);
}
in MainModule
Checkbox(
value: AppCubit.get(context).isWithCreamChecked,
onChanged: (bool? value) {
AppCubit.get(context).isWithCreamChecked = value!;
},
),
const Text('adding Cream to coffee, price is 20')
Checkbox(
value: AppCubit.get(context).isWithCreamChecked,
onChanged: (bool? value) {
AppCubit.get(context).checkBox(
value: value!,
changeValue:AppCubit.get(context).isWithCreamChecked
);
},
),
const Text('adding cream to coffee, price is 10')
I think this is because you are putting ! with value two times (value!). One before sending it to checkbox function here.
AppCubit.get(context).checkBox(
value: value!,
changeValue:AppCubit.get(context).isWithCreamChecked
);
Then again when you are setting the checkbox inside the cubit.
void checkBox({bool? value, bool? changeValue}) {
changeValue = value!;
emit(ChangeCheckBox(value,changeValue));
}
This will leads to making it the same value as you got initially.
Just do it once to change values. Also put ! before the value for changing the value before setting it like changeValue = !value
On my screen, it has a list and i can choose some elements. When i choose i want to save it to a variable and can use it later in another screen. So i using cubit in here.I using like that :
My UI:
BlocProvider(
create: (context) => TherapyCubit(),
child: Wrap(
children: [
for (final therapy in therapyList)
EllipsisCard(
therapy: therapy,
)
],
),
)
EllipsisCard:
InkWell(
onTap: () {
setState(() {
isSelected = !isSelected;
});
if (isSelected) {
context.read<TherapyCubit>().addTherapy(widget.therapy);
} else {
context.read<TherapyCubit>().deleteTherapy(widget.therapy);
}
},
child: Container(..
Cubit:
class TherapyCubit extends Cubit<TherapyState> {
TherapyCubit() : super(TherapyInitial());
List<Therapy> selectedTherapies = [];
void addTherapy(Therapy therapy) {
selectedTherapies.add(therapy);
inspect(selectedTherapies);
}
void deleteTherapy(Therapy therapy) {
selectedTherapies.remove(therapy);
}
}
Cubit State:
abstract class TherapyState extends Equatable {
const TherapyState();
#override
List<Object> get props => [];
}
class TherapyInitial extends TherapyState {}
On my page i have a state named like "step". That thing has 2 step. When my step is 1 i showing first page and when my step is 2 i showing second page with Visibility.
But when i press back button i setting step state to 1 again so showing first page again but now i cant see any of my choosen elements. And on cubit my list (selectedTherapies) is being empty again. Why its being like that ? How can i solve it ?
There are two options:
Either the cubit is replaced (try adding a print inside your Cubit constructor to diagnose)
Or your UI isn't showing the selectedTherapies List properly
Where did you placed your BlocProvider inside the widget tree?
I trying learn cubit but i always having same error while i try check a variable from cubit.
My error is like :
I made a BlocProvider and inside i put my Cubit. Like:
BlocProvider(
create: (context) => LoginCubit(
_formKey, emailController, passwordController,
service: LoginService(Dio())),
child: Scaffold(...
My LoginCubit:
class LoginCubit extends Cubit<LoginState> {
final TextEditingController emailController;
final TextEditingController passwordController;
final GlobalKey<FormState> formKey;
final ILoginService service;
bool isLoading = false;
LoginCubit(this.formKey, this.emailController, this.passwordController,
{required this.service})
: super(LoginInitial());
void changeLoadState() {
isLoading = !isLoading;
emit(LoginLoadingState(isLoading));
}
void postUserModel() async {
if (formKey.currentState != null && formKey.currentState!.validate()) {
changeLoadState();
await Future.delayed(Duration(seconds: 2));
changeLoadState();
}
}
}
abstract class LoginState {}
class LoginInitial extends LoginState {}
class LoginLoadingState extends LoginState {
final bool isLoading;
LoginLoadingState(this.isLoading);
}
as you can see I want to watch isLoading then when its true i want to put a indicator on my button instead of text. But on button when i use it like :
context.watch<LoginCubit>().isLoading
? CircularProgressIndicator.adaptive()
: Text("Login"),
Its giving that error i show with a photo. I dont know how to fix it i search from google and stackoverflow but cant found any solutions. Thanks for help guys!
I have a setting page displaying a list view and each list tile displays the name of a user and a percentage which can be edited. By tapping on a list tile the user can change the percentage using a dialog.
I would like to update the state of a single list tile when the user saves the new value instead of building the entire page again (should be better for perfomance too). Is this possible?
I have already tried to export the list tile as a stateful widget (it must be stateful) and using it in my setting page but the setState() method does not work on the single tile at all. I don't know if it would somehow work with a notifier.
Here is how the page looks like (showing the dialog to set the new percentage):
enter image description here
Thanks in advance!
Edit: I added some code.
setting_page.dart
// this widget is called in a ListView.builder to bild the list tile.
// before creating the UserListTile widget I used to return the ListTile in
// _buildRow and call setState() but then everything is re-built again, which is what I don't want to
Widget _buildRow(User user) {
return UserListTile(
user: user, userDAO: _userDAO, myPercentage: _myPercentage);
}
user_list_tile.dart
import 'package:flutter/material.dart';
import 'package:myapp/classes/user.dart';
import 'package:myapp/database/user_dao.dart';
import 'package:numberpicker/numberpicker.dart';
class UserListTile extends StatefulWidget {
const UserListTile(
{Key? key,
required this.user,
required this.userDAO,
required this.myPercentage})
: super(key: key);
final User user;
final UserDAO userDAO;
final ValueNotifier<double> myPercentage;
#override
_UserListTileState createState() => _UserListTileState();
}
class _UserListTileState extends State<UserListTile> {
final TextStyle _biggerFont = const TextStyle(fontSize: 18);
double _currentDoubleValue = 10.0;
double? trailing;
#override
Widget build(BuildContext context) {
trailing = widget.user.percentage;
return ListTile(
title: Text(
widget.user.name,
style: _biggerFont,
),
trailing: Text('${trailing} %'),
onTap: () => _showDoubleDialog(widget.user).then((value) {
if (value != false && value != null) {
// some code to set the new percentage
User _updatedUser = User(
name: widget.user.name,
id: widget.user.id,
percentage: _newPercentage);
widget.userDAO.updateData(_updatedUser);
setState(() {}); // <- this setState does not update the single tile
}
}),
);
}
Future _showDoubleDialog(User user) {
_currentDoubleValue = user.percentage;
return showDialog(
// code to shod the dialog to edit the percentage
);
}
}
I am trying the following code and while hot reloading it is incrementing static variable checkIfIncremented variable. Please someone explain me why is it so ??
import 'package:flutter/material.dart';
void main()=>runApp(MaterialApp(
home: TrialApp(),
));
class TrialApp extends StatefulWidget {
#override
_TrialAppState createState() => _TrialAppState();
}
class _TrialAppState extends State<TrialApp> {
static int checkIfIncremented = 0;
#override
Widget build(BuildContext context) {
checkIfIncremented++;
return Scaffold(
body: Center(
child: Text("This variable is getting incremented after each hot reload : $checkIfIncremented"),
),
);
}
}
This problem is due to the fact that each time you hot reload your program, the build method runs automatically. so you should avoid using checkIfIncremented++; inside this function.
I am not sure why you use this code and what is your purpose, but you can use this code if you want to incrementcheckIfIncremented only at the first load:
bool firstLoad = true;
#override
void didChangeDependencies() {
super.didChangeDependencies();
if(firstLoad){
checkIfIncremented++;
firstLoad = false;
setState((){});
}
}