I have a problem concatenating two variables on flutter : I can't concatenate them, when I try to add a string behind, it doesn't work.
class MusicAlbumListing extends StatefulWidget {
final albumName;
MusicAlbumListing({Key key, this.albumName}) : super(key: key);
#override
_MusicAlbumListing createState() => _MusicAlbumListing();
}
class _MusicAlbumListing extends State<MusicAlbumListing> {
String _albumName = '';
void initState() {
_albumName = widget.albumName.toString();
var strr = "Look this new album : $_albumName ! Awesome :)";
}
It returns
Look this new album : Mothership
And then nothing
Can anyone help me ?
I don't think there is anything wrong with your String concatenation.
Here is a Minimal Working Example based on your incomplete code snippet:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'StackOverflow Answer',
home: MusicAlbumListing(albumName: 'Mothership'),
);
}
}
class MusicAlbumListing extends StatefulWidget {
final String albumName;
MusicAlbumListing({Key? key, required this.albumName}) : super(key: key);
#override
_MusicAlbumListing createState() => _MusicAlbumListing();
}
class _MusicAlbumListing extends State<MusicAlbumListing> {
String _albumName = '';
void initState() {
super.initState();
_albumName = "Look this new album : ${widget.albumName} ! Awesome :)";
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(child: Text(_albumName)),
);
}
}
Provide your Minimal Working Example for a more targeted answer.
Thanks for your fast reply
First i fetch on a local server (my raspberry pi) a file called output.txt with ssh script
import 'package:flutter/material.dart';
import 'package:ssh/ssh.dart';
import 'album_music.dart';
class MainMenu extends StatefulWidget {
#override
_MainMenu createState() => _MainMenu();
}
class _MainMenu extends State<MainMenu> {
String _result = '';
List _array;
final pi = new SSHClient(
host: "192.168.0.35",
port: 22,
username: "pi",
passwordOrKey: "mysecret",
);
Future<void> exec(String sshScript) async {
String result;
try {
result = await pi.connect();
if (result == "session_connected") {
result = await pi.execute(sshScript);
pi.disconnect();
}
} catch (e) {
print('Error: ${e.code}\nError Message: ${e.message}');
}
setState(() {
_result = result;
_array = null;
});
}
#override
void initState() {
super.initState();
exec(
"cd ../../; cd var/www/html/music; ls -d */ > output.txt; cat output.txt");
}
#override
Widget build(BuildContext context) {
final title = 'Albums disponibles';
var strings = _result.split('\n');
print(strings);
return MaterialApp(
title: title,
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: ListView(
children: new List.generate(
strings.length - 1,
(index) => new ListTile(
title: Text(strings[index],
style: TextStyle(fontWeight: FontWeight.w500)),
leading: Icon(Icons.folder_open),
trailing: Icon(Icons.forward),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MusicAlbumListing(
albumName: strings[index].replaceAll("/", ""))));
},
),
)),
),
);
}
I open the txt file, and transform the cat output.txt to an array.
I think you're right, maybe the problem is not the concatenation.
For the first loop, Daft_Punk goes well.
That's my txt file :
Daft_Punk
MotherShip
LeonardCohenBestSongs
Pink_Floyd_Essentials
I have : Look this new album : Daft_Punk ! Awesome :)
But second loop and those after, concatenation won't work
Maybe a "bad" character has been introduced, which prevents concatenation
Related
I've a question:
In my Widget build(BuildContext context), I want to store a certain value,
final userName = book.owner
(book is the reference to the certain value from Firestore)
But it's done not in the right way to my lack of knowledge. I'd appreciate if someone could guide through that.
Thank you in advance!
Snippet of my code
class BookView extends StatefulWidget {
final Book book;
BookView({Key key, #required this.book}) : super(key: key);
DatabaseMethods databaseMethods = new DatabaseMethods();
var userName;
#override
_BookViewState createState() => _BookViewState(book);
}
class _BookViewState extends State<BookView> {
Book book;
_BookViewState(this.book);
String userName;
#override
void initState() {
userName = book.owner;
super.initState();
}
// final Book book;
createChatroomAndStartConversation({var userName}) {
if (userName != Constants.myName) {
String roomId = getChatRoomId(userName, Constants.myName);
List<String> users = [userName, Constants.myName];
Map<String, dynamic> chatRoomMap = {
"Users": users,
"roomId": roomId,
};
DatabaseMethods().createChatRoom(roomId, chatRoomMap);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ConversationScreen(roomId, userName)),
);
} else {
print("You cannot send msg to your self");
}
}
#override
Widget build(BuildContext context) {
//widget.book;
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
...
FlatButton(
child: Text(
"Get contact with",
style: TextStyle(color: Colors.white),
),
color: Colors.blue,
onPressed: () {
createChatroomAndStartConversation(
userName: userName);
...
}
Snippet of Value not in range: 1
getChatRoomId(String a, String b) {
if (a.substring(0, 1).codeUnitAt(0) > b.substring(0, 1).codeUnitAt(0)) {
return "$b\_$a";
} else {
return "$a\_$b";
}
}
It's not a good practice to store any data in build() method, because this method is invoked too many times to do the such kind of move. Consider using StatefulWidget to store any state you have in the widget, for the very beginning. When you use this widget, you can define this all in such way:
class YourWidget extends StatefulWidget {
#override
_YourWidgetState createState() => _YourWidgetState();
}
class _YourWidgetState extends State<YourWidget> {
String userName;
#override
void initState() {
userName = book.owner;
super.initState()
}
#override
Widget build(BuildContext context) {
return Container(child: Text(userName),);
}
}
Here, in initState() you can retrieve value from book and set it to userName. But for more complex and bigger applications, consider using StateManagement solutions and some kind of architectural patterns i.e. Riverpod, Provider, MobX, BLoC.. Because changing the state via setState() method will cause rebuilding whole child widget tree, which could freeze whole UI in complex app.
UPD to 'Snippet of my code':
According to your code, if you are using a 'book' from Widget, not its state - use widget.book, in such way you have access to widget members, because of this you don't need a constructor of state. So, due to these changes, your code might looks like:
class BookView extends StatefulWidget {
final Book book;
BookView({Key key, #required this.book}) : super(key: key);
// You DON'T need this here, because you are retrieving these methods
// inside your state via DatabaseMethods constructor
DatabaseMethods databaseMethods = DatabaseMethods();
#override
_BookViewState createState() => _BookViewState(book);
}
class _BookViewState extends State<BookView> {
String userName;
#override
void initState() {
// Using widget.book to retrieve Book object from state's widget
userName = widget.book.owner;
super.initState();
}
createChatroomAndStartConversation({var userName}) {
if (userName != Constants.myName) {
String roomId = getChatRoomId(userName, Constants.myName);
// Also, it's just a recommendation, try to omit local variables types
// because they are already known with List type (String). Also, this
// all is about chatRoomMap
var users = <String>[userName, Constants.myName];
final chatRoomMap = <String, dynamic>{
"Users": users,
"roomId": roomId,
};
DatabaseMethods().createChatRoom(roomId, chatRoomMap);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ConversationScreen(roomId, userName)),
);
} else {
print("You cannot send msg to your self");
}
}
#override
Widget build(BuildContext context) {
// your widgets here
}
}
UPD 2:
Second trouble and issue with 'Snippet of Value not in range: 1'. I could to reproduce it with given value of 'a' as empty string. So, your function invocation is like getChatRoomId('', 'user123'), because of empty 'userName', substring function can't take values from range [0, 1), so exception is raised.
Intro
We have a ListView named OrganizationList which contains a ListTile widget for every item. We use a Text widget to display the name of the organization inside the ListTile.
We would like to test if the organization name is displayed correctly and in the correct order.
Our current solution
We have the following assertions:
var organizationA = find
.descendant(
of: find.byType(OrganizationList),
matching: find.byKey(
Key('0'),
),
)
.evaluate()
.first
.widget as Text;
expect(textOrganization.data, 'organization-a');
var organizationB = find
.descendant(
of: find.byType(OrganizationList),
matching: find.byKey(
Key('1'),
),
)
.evaluate()
.first
.widget as Text;
expect(textOrganization.data, 'organization-b');
This feels like a very cumbersome way of testing if the right label is shown for the list items. But I fail to find a more elegant way.
Question
What is a more elegant way in Flutter / Dart to assert both the content of a list item and the order of all items?
With my solution you can check if a ListItemWidget at specific position and text is visible(or not):
void checkPosition(int index, SomeObj obj, {bool isOnPosition = true}) {
final listItemFinder = find.byType(ListItemWidget);
final listItem = listItemFinder.evaluate().isEmpty
? null
: listItemFinder.at(index);
if (listItem == null) {
if (isOnPosition) {
fail('List not found');
}
return;
}
final positionText = find.text(obj.text);
expect(find.descendant(of: listItem, matching: positionText),
isOnPosition ? findsOneWidget : findsNothing);
}
The easiest way to get elements from List and verify is widgetList, which gives a list of elements of whatever data type we have provided.
Sample test:
Problem: Verify the second item from List
const List<String> listString = [
"Ac",
"Fuel Sensor",
"Power",
"Panic",
"Camera",
"Relay",
"Duty Button",
"Other"
];
Test:
testWidgets('Listview item verify', (WidgetTester tester) async {
await tester.pumpWidget(ListViewApp());
/// Verify OrganizationIte sequence to get and verify title.
OrganizationItem item = tester
.widgetList<OrganizationItem>(find.byType(OrganizationItem))
.elementAt(2);
String data = item.title;
expect("Power", data);
});
App Code:
class ListViewApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Checked Listview',
theme: ThemeData(
primarySwatch: Colors.green,
),
home: MyHomePage(title: 'Flutter Checked Listview'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<String> _list = [];
#override
void initState() {
setState(() {
for (int i = 0; i < listString.length; i++) {
_list.add('${listString[i]}');
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Listview Sample'),
),
body: ListView.builder(
itemBuilder: (_, int index) {
return OrganizationItem(
title: _list[index],
);
},
itemCount: _list.length,
),
);
}
}
class OrganizationItem extends StatelessWidget {
final String title;
const OrganizationItem({Key? key, required this.title}) : super(key: key);
#override
Widget build(BuildContext context) {
return ListTile(
title: Text(this.title),
);
}
}
Try a for loop:
// This is for saving a reference to the ListTile from the previous iteration
ListTile? previousListTile;
for (int j = 0; j < aListOfModels.length; j++) {
final organizationA = find.descendant(
of: find.byType(OrganizationList),
matching: find.byKey(
Key('0'),
),
);
// This is important to show the invisible late elements
await widgetTester.scrollUntilVisible(organizationA, tryToFindTheSuitableDelta);
// I suppose that organizationA finds a ListTile widget
ListTile currentListTile = widgetTester.widget<ListTile>(organizationA);
/*
Make your expectations about the content as you like
....
...
*/
// To expect about the order, do the following:
final listTileWidgetList = widgetTester
.widgetList<ListTile>(find.byType(ListTile))
.toList();
if (j > 0) {
// Expect that the currentListTile is the first next ListTile of the previousListTile
expect(listTileWidgetList.indexOf(currentListTile),
equals(listTileWidgetList.indexOf(previousListTile!) + 1));
}
// To allow you to make your expectation about the order in the next iteration
previousListTile = currentListTile;
}
Problem
Recursive rendering of the Widget due to incorrect (probably) use of Provider.
This is the main.dart :
void main() {
runApp(MultiProvider(
providers: [
ChangeNotifierProvider<NotesProvider>(
create: (_) => NotesProvider(),
),
ChangeNotifierProvider<ThemeProvider>(
create: (_) => ThemeProvider(),
),
],
child: MyApp(),
));
}
This redirects to outer_page which contains two tabs like this :
It's code goes to like this :
class OuterPage extends StatefulWidget {
static const routeName = '/OuterPage';
#override
State<StatefulWidget> createState() {
return OuterPageState();
}
}
class OuterPageState extends State<OuterPage> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
int _selectedTab = 0;
final _pageOptions = [
NoteScreen(), // <- Notes Tab
NotePageScreen(), // <- 'Another' Tab
];
Widget build(BuildContext context) {
var noteProvider = Provider.of<NotesProvider>(context, listen: false);
// https://stackoverflow.com/a/53839983
var customFabButton;
if (_selectedTab == 0) {
~~~ SNIP ~~~
The default tab is the 'Notes' Tab, which works fine.
'Another' tab, is where the issue lies.
class NotePageScreen extends StatefulWidget {
NotePageScreen();
#override
NotePageScreenState createState() => NotePageScreenState();
}
class NotePageScreenState extends State<NotePageScreen> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
List<Note> noteList;
int count = 0;
#override
Widget build(BuildContext context) {
Provider.of<NotesProvider>(context, listen: false).getAllDecryptedNotes();
return Scaffold(
key: _scaffoldKey,
body: Provider.of<NotesProvider>(context, listen:false).decrypted
? NotePage()
: Container(
child: Center(
child: Text("Add a new Note"),
),
));
}
}
What's going on here
I am fetching the decrypted notes from the database.
NoteProvider.dart :
class NotesProvider with ChangeNotifier {
DatabaseHelper _databaseHelper = DatabaseHelper();
List<Note> _noteList, decryptedNoteList;
int _count = 0;
bool _notesDecrypted = false;
UnmodifiableListView<Note> get allNotes => UnmodifiableListView(_noteList);
getNotes() async {
await _databaseHelper.initializeDatabase();
List<Note> noteList = await _databaseHelper.getNoteList();
this._noteList = noteList;
this._count = noteList.length;
notifyListeners();
}
UnmodifiableListView<Note> get allDecryptedNotes =>
UnmodifiableListView(decryptedNoteList);
getAllDecryptedNotes() async {
List<Note> decryptedNoteList = [];
for (var note in this._noteList) {
decryptedNoteList.add(await decryptNote(note));
}
this.decryptedNoteList = decryptedNoteList;
this._notesDecrypted = true;
notifyListeners();
}
int get count => _count;
bool get decrypted => _notesDecrypted;
~~~~ SNIP ~~~~
What's the problem here
So, what happens is the first time there isn't any decrypted data, but when I swtich tabs and come back again to 'Another' tab, there are the decrypted notes.
What I've tried :
If I set listen to True on either of these :
Provider.of<NotesProvider>(context, listen: false).getAllDecryptedNotes();
Provider.of<NotesProvider>(context, listen: false).decrypted
then the page loads in the first attempt but then it goes on rendering recursively.
That's where the error is.
Thanks :)
Update - Adding Repo
Repo : https://github.com/LuD1161/notes_app/
Branch : reusable_components
After hours of searching about the topic and due to lack of documentation on Flutter Web I am asking this question.
I was trying to create a web app using flutter and had an requirement where URL such as below
website.com/user/someUserCode
would be called and an page will be launched where the data (someUserCode) will be passed to the page
but haven't got any solutions yet to resolve it.
so just rounding it all up,
How to pass and fetch the data using (get / post) methods to flutter web app?
EDIT 1
What all I know / have tried yet
I am using below code to read if some parameters are being to some class file
final Map<String, String> params = Uri.parse(html.window.location.href).queryParameters;
String data = params["userData"];
all this actually solves the Fetch part of my question (maybe)
but the part where that data will be passed to the page via URL is still missing.
EDIT 2
Since I haven't got any replies and was not able to find anything i raised an ticket on Flutter GitHub page here
anyone else looking for the same issue can track it there (if it gets resolve)
May you could do it in a easy way:
import 'dart:html';
import 'package:flutter/material.dart';
import 'home_page.dart';
void getParams() {
var uri = Uri.dataFromString(window.location.href);
Map<String, String> params = uri.queryParameters;
var origin = params['origin'];
var destiny = params['destiny'];
print(origin);
print(destiny);
}
void main() {
getParams();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Your app',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(),
);
}
}
And then call it from browser:
http://localhost:52695/?origin=pointA&destiny=pointB
Output:
pointA
pointB
I tried the above method from #Mariano Zorrilla but it still opened the pages in order:
/
/user
/user/yFbOfUAwx1OCC93INK8O7VqgBXq2
I have found Fluro, and works efficiently and cleanly you only need to add one routing file and do all the routing in one file rather than editing every page you want to route to, here's how you would implement it:
main.dart
void main() {
FluroRouter.setupRouter();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Website Title',
onGenerateRoute: FluroRouter.router.generator
);
}
}
fluro_router.dart
class FluroRouter {
static Router router = Router();
//Define your routers here
static void setupRouter() {
router.define('/', handler: _homeHandler);
router.define('/login', handler: _loginHandler);
router.define('/online-enquiry/:userId', handler: _userHandler);
}
//Add your handlers here
static Handler _homeHandler = Handler(handlerFunc: (context, Map<String, dynamic> params) => Home());
static Handler _loginHandler = Handler(handlerFunc: (context, Map<String, dynamic> params) => Login());
static Handler _userHandler = Handler(handlerFunc: (context, Map<String, dynamic> params) => UserProfile(userID: params['userId'].first));
}
Source
You can get everything (paths, parameters, etc) from onGenerateRoute. Your Home will be / and everything from there can be grabbed and used to redirect users.
My approach to solve this is the following. Your base App() should be like:
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Website Title',
onGenerateRoute: (settings) => NavigatorRoute.route(settings.name),
);
}
}
and the class NavigatorRoute will be:
class NavigatorRoute extends StatefulWidget {
final String path;
static Route<dynamic> route(String path) {
return SimpleRoute(
name: '', // this one is always empty as you didn't route yet
title: 'Website Title',
builder: (_) => NavigatorRoute(path: path),
animated: false
);
}
const NavigatorRoute({Key key, this.path}) : super(key: key);
#override
_NavigatorRouteState createState() => _NavigatorRouteState();
}
class _NavigatorRouteState extends State<NavigatorRoute> {
#override
void initState() {
super.initState();
Future.microtask(() {
if (widget.path == '/') {
Navigator.of(context).pushAndRemoveUntil(HomeScreen.route(false), (_) => false);
return;
} else if (widget.path == '/user') {
Navigator.of(context).pushAndRemoveUntil(UserScreen.route(false), (_) => false);
return;
} else if (widget.path.contains('/user/')) {
Navigator.of(context).pushAndRemoveUntil(UserScreen.routeCode(widget.path.split('/')[2]), (_) => false);
return;
} else if (widget.path == '/about') {
Navigator.of(context).pushAndRemoveUntil(AboutScreen.route(), (_) => false);
return;
} else {
Navigator.of(context).pushAndRemoveUntil(HomeScreen.route(), (_) => false);
return;
}
});
}
#override
Widget build(BuildContext context) {
return SizedBox();
}
}
The code for the SimpleRoute is:
class SimpleRoute extends PageRoute {
SimpleRoute({#required String name, #required this.title, #required this.builder, #required this.animated})
: super(settings: RouteSettings(name: name));
final String title;
final WidgetBuilder builder;
final bool animated;
#override
Color get barrierColor => null;
#override
String get barrierLabel => null;
#override
bool get maintainState => true;
#override
Duration get transitionDuration => Duration(milliseconds: 200);
#override
Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
return animated
? FadeTransition(
opacity: animation,
child: Title(
title: this.title,
color: Theme.of(context).primaryColor,
child: builder(context),
),
)
: Title(
title: this.title,
color: Theme.of(context).primaryColor,
child: builder(context),
);
}
}
So, finally... if you want to easily open one of your screens, you can do:
class HomeScreen extends StatefulWidget {
static Route<dynamic> route(bool animated) {
return SimpleRoute(name: '/', title: 'Home', builder: (_) => HomeScreen(), animated: animated);
}
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
...
}
The routeCode could be:
static Route<dynamic> routeCode(String id) {
return SimpleRoute(name: '/user/$id', title: 'User', builder: (_) => UserScreen(id: id), animated: false);
}
The main benefit of doing this is avoiding the stack of pages generated by accessing the last screen.
For example, if you're using directly the onGenerateRoute for "www.mywebsite.com/user/userId/edit" then Flutter will open:
Home Screen
User Screen
UserId Screen
Edit Screen
but with this approach, only "Edit Screen" will be open.
in flutter i just learn how can i use Bloc on applications and i want to try to implementing simple login with this feature. after implementing some class of bloc to using that on view
i get error when i try to use this code as
BlocProvider.of<LoginListingBloc>(context).dispatch(LoginEvent(loginInfoModel: testLogin));
inside RaisedButton
Error:
BlocProvider.of() called with a context that does not contain a Bloc
of type LoginListingBloc.
My view :
class _HomePageState extends State<HomePage> {
LoginListingBloc _loginListingBloc;
#override
void initState() {
super.initState();
_loginListingBloc =
LoginListingBloc(loginRepository: widget.loginRepository);
}
...
#override
Widget build(BuildContext context) {
return BlocProvider(
bloc: _loginListingBloc,
child: Scaffold(
appBar: AppBar(
elevation: 5.0, title: Text('Sample Code', style: appBarTextStyle)),
body: Center(
child: RaisedButton(
child: Text(
'click here',
style: defaultButtonStyle,
),
onPressed: () {
BlocProvider.of<LoginListingBloc>(context).dispatch(LoginEvent(loginInfoModel: testLogin));
}),
),
),
);
}
}
LoginListingBloc class:
class LoginListingBloc extends Bloc<LoginListingEvent, LoginListingStates> {
final LoginRepository loginRepository;
LoginListingBloc({this.loginRepository});
#override
LoginListingStates get initialState => LoginUninitializedState();
#override
Stream<LoginListingStates> mapEventToState(
LoginListingStates currentState, LoginListingEvent event) async* {
if (event is LoginEvent) {
yield LoginFetchingState();
try {
final loginInfo = await loginRepository.fetchLoginToPage(
event.loginInfoModel.username, event.loginInfoModel.password);
yield LoginFetchedState(userInfo: loginInfo);
} catch (_) {
yield LoginErrorState();
}
}
}
}
and other classes if you want to see theme
AppApiProvider class:
class AppApiProvider {
final successCode = 200;
Future<UserInfo> fetchLoginToPage(String username, String password) async {
final response = await http.get(Constants.url + "/api/v1/getPersons");
final responseString = jsonDecode(response.body);
if (response.statusCode == successCode) {
print(responseString);
return UserInfo.fromJson(responseString);
} else {
throw Exception('failed to get information');
}
}
}
LoginEvent:
class LoginEvent extends LoginListingEvent {
final LoginInfoModel loginInfoModel;
LoginEvent({#required this.loginInfoModel}) : assert(loginInfoModel != null);
}
LoginInfoModel:
class LoginInfoModel {
String username;
String password;
LoginInfoModel({this.username, this.password});
}
final testLogin = LoginInfoModel(username:'exmaple',password:'text');
No need to access loginListingBloc from context since it exists in the current class and not up the widget tree.
change:
BlocProvider.of<LoginListingBloc>(context).dispatch(LoginEvent(loginInfoModel: testLogin));
to:
_loginListingBloc.dispatch(LoginEvent(loginInfoModel: testLogin));
For all others who come here for the error message:
Make sure you always specify the types and don't omit them:
BlocProvider<YourBloc>(
create: (context) => YourBloc()
child: YourWidget()
);
and also for
BlocProvider.of<YourBloc>(context);