Accessing a stream inside a Nested StreamBuilder in Flutter - flutter

I am having an issue calling a StreamBuilder inside another StreamBuilder which is located inside the onPressed field of RasedButton widget. Basically, I am trying to access a stream (after adding data to it) inside the inner StreamBuilder, but the execution does not call this part of the code:
Widget submitButton(BuildContext ctx, AccountBloc bloc){
return StreamBuilder(
stream: bloc.submitValid,
builder: (context, snapshot){
return SizedBox(
width: double.infinity,
height: 60,
child: RaisedButton(
color: HexColor("0072b1"),
child: Text("Sign in", style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20,
color: Colors.white
),
),
onPressed:() {
if(snapshot.hasData){
bloc.loginUser();
// DEBUGGING
print(bloc.isAuthenticated.listen((val) { print("debug isAuthenticated: $val"); }));
StreamBuilder(
stream: bloc.isAuthenticated,
builder: (ctx, snapshotA){
print("here");
if(!snapshotA.hasData){
return Text("loading....");
}
print("***${snapshotA.data}****");
if(snapshotA.data == false){
return navSignUpScreen(ctx);
}else if (snapshotA.data == false){
print("here");
return navHomeScreen(ctx);
}
return navSignUpScreen(ctx);
}
);
}
},
),
);
}
);
}
The BLOC part is as follows:
final _isAuthenticated = BehaviorSubject<bool>();
Stream<bool> get isAuthenticated => _isAuthenticated.stream;
void loginUser() async {
var inMemory = InMemoryProvider();
inMemory.newInMemoryProvider();
UserModel userResult = await _repository.loginUser(_email.value, _password.value);
if(userResult.status == 200){
// save TOKEN
UserModel userModel = UserModel.fromJsonToModel(userResult.data);
bool res = await inMemory.store(userModel.id, userModel.token);
_isAuthenticated.sink.add(res);
}
_userLoginResponse.sink.add(userResult);
}
The navHomeScreen definition is as simple as this:
class HomeScreen extends StatefulWidget {
createState() {
return HomeState();
}
}
class HomeState extends State<HomeScreen> {
int _currentIndex = 0;
final List<Widget> _children = [
AllReportsScreen(), UserProfileScreen()
];
Widget build(context) {
return Scaffold(
body: _children[_currentIndex],
bottomNavigationBar: mainBottomNavigatorBar(),
);
}
Widget mainBottomNavigatorBar() {
return BottomNavigationBar(
type: BottomNavigationBarType.fixed,
onTap: onTabTapped,
currentIndex: _currentIndex,
items: [
BottomNavigationBarItem(
backgroundColor: Colors.black45,
icon: new Icon(Icons.note),
title: new Text('Reports', style: TextStyle(fontSize: 15.0)),
),
BottomNavigationBarItem(
backgroundColor: Colors.black45,
icon: new Icon(Icons.label_important),
title: new Text('Attention', style: TextStyle(fontSize: 15.0)),
),
BottomNavigationBarItem(
backgroundColor: Colors.black45,
icon: new Icon(Icons.person_pin),
title: new Text('Profile', style: TextStyle(fontSize: 15.0)),
),
],
);
}
void onTabTapped(int index) {
setState(() {
_currentIndex = index;
});
}
}

Using combineLatest from rxdart to combine two Streams isAuthenticated and submitValid into one Stream:
class LoginState {
final bool isAuthenticated;
final bool submitValid;
}
final state$ = Rx.combineLatest(
bloc.isAuthenticated,
bloc.submitValid,
(isAuth, valid) => LoginState(isAuth, valid),
);
StreamBuilder<LoginState>(
stream: state$,
builder: (context, snapshot) {
final state = snapshot.data;
if (state == null) return ...;
if (!state.submitValid) return ...;
if (state.isAuthenticated) return ...;
}
)

Related

Right way to use static bool

So I am using AudioPlayer in Flutter to play different audios that get streamed from Firebase using StreamBuilder. While I am able to stop a certain audio when another one plays by making the AudioPlayer static, I am unable to do the same with play button. When a certain song plays, the play button remains in "play" state even when the song changes.
Here is the snipped of my code
class _RingtoneWidgetState extends State<RingtoneWidget> {
static AudioPlayer audioPlayer = AudioPlayer();
AuthenticationScreenController authenticationScreenController =
Get.put(AuthenticationScreenController());
#override
void dispose() {
// TODO: implement dispose
super.dispose();
audioPlayer.stop().whenComplete(() {
widget.isPlaying = false;
});
}
#override
Widget build(BuildContext context) {
return Card(
.....
title: CustomText(widget.ringtoneTitle as String, 18,
FontWeight.w500, AppColors.whiteColor),
subtitle: CustomText(
"x audio usado: ${widget.numberOfTimesRingtoneUsed}",
12,
FontWeight.w400,
AppColors.whiteColor),
trailing: GestureDetector(
onTap: () async {
widget.isPlaying
? await audioPlayer.stop().whenComplete(() {
setState(() {
widget.isPlaying = !widget.isPlaying;
});
})
: await audioPlayer
.play(UrlSource(widget.audioUrl as String))
.whenComplete(() {
setState(() {
widget.isPlaying = !widget.isPlaying;
});
});
},
child: widget.isPlaying
? const Icon(
Icons.pause_circle,
color: AppColors.whiteColor,
)
: const Icon(
Icons.play_circle_outlined,
color: AppColors.whiteColor,
),
),
),
],
),
);
}
}
Here is the code for screen where this widget is listed
Expanded(
child: Scaffold(
backgroundColor: AppColors.defaultColor,
body: StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('artistdata')
.doc(authInstance.currentUser!.email)
.collection('songs')
.snapshots(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return Text("Loading");
}
FirebaseFirestore.instance
.collection('artistdata')
.doc(authInstance.currentUser!.email)
.collection('songs')
.get()
.then(
(value) {
authenticationScreenController
.totalNumberOfSongs.value = value.size;
},
);
return ListView(
padding: EdgeInsets.only(bottom: 50),
children: snapshot.data!.docs.map((document) {
Map<String, dynamic> data =
document.data()! as Map<String, dynamic>;
return RingtoneWidget(
false,
audioUrl: data['audiourl'],
imageUrl: data['imageurl'],
numberOfTimesRingtoneUsed:
data['numberoftimesused'],
ringtoneTitle: data['songtitle'],
);
}).toList(),
);
},
),
),
),

unnecessary container but I need this container? flutter/Dart

I am working on a app were I get data from the ESP32 and display it on a simple page. Here is my code for my sensorpage:
import 'dart:async';
import 'dart:convert' show utf8;
import 'package:flutter/material.dart';
import 'package:flutter_blue/flutter_blue.dart';
class sensorpage extends StatefulWidget {
const sensorpage({Key? key, required this.device}) : super(key: key);
final BluetoothDevice device;
#override
_sensorpageState createState() => _sensorpageState();
}
class _sensorpageState extends State<sensorpage> {
final String SERVICE_UUID = "edb91e04-3e19-11ec-9bbc-0242ac130002";
final String CHARACTERISTIC_UUID = "edb920c0-3e19-11ec-9bbc-0242ac130002";
late bool isReady;
//String val1 = "";
//int pot1 = 0;
FlutterBlue flutterBlue = FlutterBlue.instance;
//late StreamSubscription<ScanResult> scanSubScription;
//late BluetoothDevice targetDevice;
late Stream<List<int>> stream;
#override
void initState() {
super.initState();
isReady = false;
connectToDevice();
}
connectToDevice() async {
if (widget.device == null) {
_Pop();
return;
}
Timer(const Duration(seconds: 15), () {
if (!isReady) {
disconnectFromDevice();
_Pop();
}
});
await widget.device.connect();
discoverServices();
}
disconnectFromDevice() {
if (widget.device == null) {
_Pop();
return;
}
widget.device.disconnect();
}
discoverServices() async {
if (widget.device == null) {
_Pop();
return;
}
List<BluetoothService> services = await widget.device.discoverServices();
services.forEach((service) {
if (service.uuid.toString() == SERVICE_UUID) {
service.characteristics.forEach((characteristic) {
if (characteristic.uuid.toString() == CHARACTERISTIC_UUID) {
characteristic.setNotifyValue(!characteristic.isNotifying);
stream = characteristic.value;
setState(() {
isReady = true;
});
}
});
}
});
if (!isReady) {
_Pop();
}
}
Future<bool> _onWillPop() async {
bool shouldPop = false;
await showDialog(
context: context,
builder: (context) =>
AlertDialog(
title: const Text('Are you sure?'),
content: const Text('Do you want to disconnect device and go back?'),
actions: <Widget>[
ElevatedButton(
onPressed: () {
// shouldPop is already false
},
child: const Text('No')),
ElevatedButton(
onPressed: () async {
await disconnectFromDevice();
Navigator.of(context).pop();
shouldPop = true;
},
child: const Text('Yes')),
],
));
return shouldPop;
}
_Pop() {
Navigator.of(context).pop(true);
}
String _dataParser( List<int> dataFromDevice) {
return utf8.decode(dataFromDevice);
}
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: _onWillPop,
child: Scaffold(
appBar: AppBar(
title: const Text('Test'),
),
body: Container(
child: !isReady
? const Center(
child: Text(
"Waiting...",
style: TextStyle(fontSize: 24, color: Colors.red),
),
)
: Container(
child: StreamBuilder<List<int>>(
stream: stream,
builder: (BuildContext context,
AsyncSnapshot<List<int>> snapshot) {
if (snapshot.hasError){
return Text('Error: ${snapshot.error}');
}
if (snapshot.connectionState == ConnectionState.active) {
var currentValue = _dataParser (snapshot.data!);
//val1 = currentValue.split(',')[0];
//pot1 = int.parse(val1);
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('Current value',
style: TextStyle(fontSize: 14)),
Text('${currentValue} jawool',
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 24))
])
);
} else {
return const Text('Check the stream');
}
},
)),
)
));
}
}´
My Problem is that my second container where I display my data is shown as unnecessary but I don´t know why.
I assume you mean this piece of code?
body: Container(
child: !isReady
? const Center(
child: Text(
"Waiting...",
style: TextStyle(fontSize: 24, color: Colors.red),
),
)
: Container(
child: StreamBuilder<List<int>>(
If isReady is true you return Container(child: Container(child: SteamBuilder));
You should change it to this and it should be fine:
body: Container(
child: !isReady
? const Center(
child: Text(
"Waiting...",
style: TextStyle(fontSize: 24, color: Colors.red),
),
)
: StreamBuilder<List<int>>(
The first Container is just wrapping the content based on the boolean and you don't need it. According to the flutter team:
Wrapping a widget in Container with no other parameters set has no effect and makes code needlessly more complex
So instead you can directly do:
body: !isReady ? buildSomething() : Container(....more code);

Flutter Reorderable List going back to it's original state

I made the list reorderable but now it's going back to its initial state. Can someone help me? My list consists of List Tile which is generated from the database using Asynsnapshot. The key I used is the same as the index. It seems like the insert function isn't inserting the note in the new index. Is it because the future builder is rebuilding?
body: Container(
padding: EdgeInsets.all(8.0),
child: ListView(
children: <Widget>[
SizedBox(
height: MediaQuery.of(context).size.height * 0.882,
child: FutureBuilder(
future: databaseHelper.getNoteList(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return Text('Loading');
} else {
if (snapshot.data.length < 1) {
return Center(
child: Text('No Messages, Create New one'),
);
}
return ReorderableListView(
children: List.generate(
snapshot.data.length,
(index) {
return ListTile(
key: Key('$index'),
title: Text(
snapshot.data[index].title,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20,
),
),
subtitle: Text(snapshot.data[index].note,
maxLines: 4),
trailing: InkWell(
child: Icon(Icons.add_box,
color: Colors.green),
onTap: () {
TextEditingController txt =
TextEditingController();
txt.text = snapshot.data[index].note;
print(txt);
Route route = MaterialPageRoute(
builder: (context) =>
MyHomePage(custMessage: txt));
Navigator.push(context, route);
// addNewMessageDialog(txt);
},
),
// isThreeLine: true,
onTap: () {
Route route = MaterialPageRoute(
builder: (context) => AddNote(
note: snapshot.data[index],
));
Navigator.push(context, route);
},
);
},
).toList(),
onReorder: _onReorder,
);
}
}))
],
)),
Reoder function
void _onReorder(int oldIndex, int newIndex) async {
var snapshot = await databaseHelper.getNoteList();
if (newIndex > snapshot.length) newIndex = snapshot.length;
if (oldIndex < newIndex) newIndex -= 1;
setState(() {
final Note item = snapshot[oldIndex];
snapshot.removeAt(oldIndex);
print(item.title);
snapshot.insert(newIndex, item);
});
}
I tried adding future delay but no use.
You can copy paste run full code below
You do not need to call databaseHelper.getNoteList() in _onReorder again
You can use noteList = snapshot.data; and operate noteList
code snippet
void _onReorder(int oldIndex, int newIndex) async {
if (newIndex > noteList.length) newIndex = noteList.length;
if (oldIndex < newIndex) newIndex -= 1;
setState(() {
final Note item = noteList[oldIndex];
noteList.removeAt(oldIndex);
print(item.title);
noteList.insert(newIndex, item);
});
}
...
noteList = snapshot.data;
return ReorderableListView(
working demo
full code
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class Note {
String title;
String note;
Note({this.title, this.note});
}
class databaseHelper {
static Future<List<Note>> getNoteList() {
return Future.value([
Note(title: "1", note: "n1"),
Note(title: "2", note: "n2"),
Note(title: "3", note: "n3"),
Note(title: "4", note: "n4"),
Note(title: "5", note: "n5")
]);
}
}
class _MyHomePageState extends State<MyHomePage> {
List<Note> noteList = [];
Future<List<Note>> _future;
void _onReorder(int oldIndex, int newIndex) async {
if (newIndex > noteList.length) newIndex = noteList.length;
if (oldIndex < newIndex) newIndex -= 1;
setState(() {
final Note item = noteList[oldIndex];
noteList.removeAt(oldIndex);
print(item.title);
noteList.insert(newIndex, item);
});
}
#override
void initState() {
// TODO: implement initState
super.initState();
_future = databaseHelper.getNoteList();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
padding: EdgeInsets.all(8.0),
child: ListView(
children: <Widget>[
SizedBox(
height: MediaQuery.of(context).size.height * 0.882,
child: FutureBuilder(
future: _future,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return Text('Loading');
} else {
if (snapshot.data.length < 1) {
return Center(
child: Text('No Messages, Create New one'),
);
}
noteList = snapshot.data;
return ReorderableListView(
children: List.generate(
snapshot.data.length,
(index) {
return ListTile(
key: Key('$index'),
title: Text(
snapshot.data[index].title,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20,
),
),
subtitle: Text(snapshot.data[index].note,
maxLines: 4),
trailing: InkWell(
child: Icon(Icons.add_box,
color: Colors.green),
onTap: () {
/*TextEditingController txt =
TextEditingController();
txt.text = snapshot.data[index].note;
print(txt);
Route route = MaterialPageRoute(
builder: (context) =>
MyHomePage(custMessage: txt));
Navigator.push(context, route);*/
// addNewMessageDialog(txt);
},
),
// isThreeLine: true,
onTap: () {
/*Route route = MaterialPageRoute(
builder: (context) => AddNote(
note: snapshot.data[index],
));
Navigator.push(context, route);*/
},
);
},
).toList(),
onReorder: _onReorder,
);
}
}))
],
)),
);
}
}
Inside your _onReorder method, you create a new snapshot variable, then mutate that variable. Once _onReorder exits, this local snapshot variable is completely discarded. Thus, any mutations you apply to this local snapshot variable are also discarded.
Your confusion lies in that you have two completely distinct snapshot variables that are not coupled to each other: they only share the same name. In other words, changes applied to the snapshot variable in _onReorder have no effect on the variable in build(BuildContext context).
You need to reference a single variable to track the state of the order of your list.
I've reproduced how you can do this by using a state variable and initState to initialize your state variable from a Future:
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(home: Scaffold(body: Body())));
class Body extends StatefulWidget {
#override
_BodyState createState() => _BodyState();
}
class _BodyState extends State<Body> {
List<String> snapshot;
#override
void initState() {
super.initState();
initializeSnapshot();
}
Future initializeSnapshot() async {
final list = await getListFromDatabase();
setState(() => snapshot = list);
}
Future getListFromDatabase() async {
// In reality, you would make some network call here.
return ["a", "b", "c"];
}
#override
Widget build(BuildContext context) => snapshot == null
? Center(child: CircularProgressIndicator())
: ReorderableListView(
onReorder: (oldIndex, newIndex) {
if (newIndex > snapshot.length) newIndex = snapshot.length;
if (oldIndex < newIndex) newIndex -= 1;
setState(() {
final String item = snapshot[oldIndex];
snapshot.removeAt(oldIndex);
snapshot.insert(newIndex, item);
});
},
children: snapshot
.map((x) => ListTile(key: ValueKey(x), title: Text(x)))
.toList(),
);
}
Additionally: Don't use the index of an item in a list as the Key of a widget. This is because Flutter uses the key to determine if a widget at a particular index needs to be rebuilt. Instead, use a key that's unique to the contents of the widget, like item.title in your case.

How to call setState in a extended class?

class Cari extends AnaState implements InterHttp {
String token = Tokenlar.token();
Future<Void> getCariHareket() async {
final response = await get(
"http://148.111.156.214:36555/Api/Customers/CustomerActionById/3",
headers: {HttpHeaders.authorizationHeader: "bearer $token",HttpHeaders.acceptHeader: "application/json"},
);
if (response.statusCode == 200)
{
List<CariHareketListe> hareketListe=(json.decode(response.body) as List).map((i) =>
CariHareketListe.fromJson(i)).toList();
//Map<String,dynamic> map = json.decode(response.body);
setState(() {
provider = hareketListe;
});
}
else
{
throw Exception('Cari hareket listesi yükleme başarısız oldu');
}
}
}
i want to be able to call setstate in this class but it gives me this error:
FlutterError (setState() called in constructor: Cari#ed627(lifecycle state: created, no widget, not mounted)
This happens when you call setState() on a State object for a widget that hasn't been inserted into the widget tree yet. It is not necessary to call setState() in the constructor, since the state is already assumed to be dirty when it is initially created.)
This is the main dart i want to setstate in cari then i want that data go into Icwidgetlar to be able to Return a list view to Anastate
import 'package:flutter/material.dart';
import 'package:guven_avize/ApiMetodlar/CariMetod.dart';
import 'Veriler/CariVeriler.dart';
class Anamenu
{
Anamenu()
{
}
}
class Ana extends StatefulWidget{
#override
AnaState createState() => AnaState();
}
class IcWidgetlar
{
List<CariHareketListe> provider = new List<CariHareketListe>();
ListView icyapi(int secilenTab)
{
if (secilenTab == 0)
{
Cari cari = new Cari();
cari.veriCek(1);
ListView.builder(
padding: const EdgeInsets.all(8),
itemCount: provider.length,
itemBuilder: (BuildContext context, int index) {
return Container(
height: 50,
color: Colors.amber,
child: Center(child: Text('Entry ${provider[index]}')),
);
}
);
}
}
}
class AnaState extends State<Ana> with IcWidgetlar {
IcWidgetlar widgetlar = new IcWidgetlar();
int selectedIndex = 0;
static const TextStyle optionStyle = TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
static const List<Widget> _widgetOptions = <Widget>[
Text(
'Cari',
style: optionStyle,
),
Text(
'Stok',
style: optionStyle,
),
Text(
'Sipariş',
style: optionStyle,
),
];
void _onItemTapped(int index) {
setState(() {
selectedIndex = index;
});
}
#override
Widget build(BuildContext context) {
return new WillPopScope(
onWillPop: () async => false,
child: Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
backgroundColor: Color.fromRGBO(106, 112, 222, 50),
title: _widgetOptions.elementAt(selectedIndex),
),
body: widgetlar.icyapi(selectedIndex),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.face),
title: Text('Cari'),
),
BottomNavigationBarItem(
icon: Icon(Icons.inbox),
title: Text('Stok'),
),
BottomNavigationBarItem(
icon: Icon(Icons.shopping_cart),
title: Text('Sipariş'),
),
],
currentIndex: selectedIndex,
selectedItemColor: Colors.amber[800],
onTap: _onItemTapped,
),
));
}
}
Why are you not returning the result instead?
Instead of returning Future, return Future>, and get it from other class.
You can even use FutureBuilder to wait until the response arrive.
Call the function in initState
#override
void initState() {
super.initState();
getCariHareket().then( (list) {
setState((){
provider = list;
}())
});
}

Flutter Navigator.pop() keeps the Dialog Box partially visible with black shadow background

sorry for the long explaination but I think I have to be very clear about the topic.
I have been running in this issue for last couple of weeks. I am using flutter_bloc package.
I have a simple Search page(ProposalSearchPage) with searchbox and listview. Listview gets build based on the search keyword which dispatches KeywordsearchEvent. on Clicking the setting icon it opens of ProposalSearchSetting page which is a dialog box page.
Based on this structure I have two events used in the bloc. One for the keyword search and another for the Advance filter search.
In advance searching page after applying filters. Inside a button there I dispatched FilterSearchEvent and have used Navigation.pop(context) to return to ProposalSearchPage.
Based on the state change The listview renders for both the searches, but for the Adavance filter search, the ProposalSearchSetting dialog box is partially visible. The filter button in there are clickable. It dismiss when I click backarrow button.
I don't know why Navigator.pop is adding page to stack instead of popping the stack.
#PROPOSALSEARCH PAGE
class ProposalSearchPage extends StatefulWidget {
final UserProfileBloc userProfileBloc;
final MenuBloc menuBloc;
final String authToken;
ProposalSearchPage({this.userProfileBloc, this.menuBloc, this.authToken})
: assert(menuBloc != null),
assert(userProfileBloc != null);
#override
_ProposalSearchPageState createState() => _ProposalSearchPageState();
}
class _ProposalSearchPageState extends State<ProposalSearchPage> {
UserProfileBloc get _userProfileBloc => widget.userProfileBloc;
List filteredProposal = [];
String get _authToken => widget.authToken;
MenuBloc get _menuBloc => widget.menuBloc;
ProposalSearchBloc _proposalSearchBloc;
String searchedKeyword = "";
int searchProposalPage = 1;
#override
void initState() {
_proposalSearchBloc =
ProposalSearchBloc(proposalRepository: ProposalListingRepo());
_menuBloc.dispatch(MenuResponseFetchedEvent());
super.initState();
}
#override
void dispose() {
_proposalSearchBloc.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Color(0xff2b57ff),
leading: IconButton(
icon: Icon(Icons.chevron_left),
onPressed: () {
Navigator.of(context).pop();
},
),
actions: <Widget>[
IconButton(
icon: new Icon(CupertinoIcons.gear_big),
onPressed: () {
/* Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProposalSearchSetting(
proposalSearchBloc: _proposalSearchBloc,
menuBloc: _menuBloc,
userProfileBloc: _userProfileBloc,
context: context),
fullscreenDialog: true,
),
);*/
showDialog<FilterProposalPost>(
context: context,
builder: (context) {
return ProposalSearchSetting(
proposalSearchBloc: _proposalSearchBloc,
menuBloc: _menuBloc,
userProfileBloc: _userProfileBloc,
context: context);
});
}),
],
title: Center(
child: Container(
width: 250.0,
height: 35.0,
decoration: BoxDecoration(
color: Colors.black12,
borderRadius: BorderRadius.all(Radius.circular(7.0))),
child: CupertinoTextField(
placeholder: 'search here.',
style: TextStyle(
color: Colors.white,
),
onSubmitted: (keyword) {
print(keyword);
searchedKeyword = keyword;
FilterProposalPost filterProposalPost =
_buildSearchQueryParameter(keyword);
// print(query);
_proposalSearchBloc.proposalFilterPostParam(filterProposalPost);
},
),
),
),
),
body: SearchListing(_proposalSearchBloc, _authToken),
);
}
FilterProposalPost _buildSearchQueryParameter(String keyword) {
return FilterProposalPost(
........
);
}
}
}
class SearchListing extends StatelessWidget {
final ProposalSearchBloc _proposalSearchBloc;
final String _authToken;
SearchListing(this._proposalSearchBloc, this._authToken);
#override
Widget build(BuildContext context) {
return BlocBuilder(
bloc: _proposalSearchBloc,
// ignore: missing_return
builder: (context, state) {
if (state is ProposalSearchFetchingState) {
return Center(
child: CircularProgressIndicator(
valueColor: new AlwaysStoppedAnimation(Color(0xff2b57ff))),
);
} else if (state is ProposalSearchFetchedState) {
final filteredProposal = state.filteredProposal;
print(filteredProposal.length.toString);
return _buildSearchProposalList(filteredProposal);
}
},
);
}
Widget _buildSearchProposalList(List searchedProposals) {
return ListView.builder(
itemCount: searchedProposals.length + 1,
itemBuilder: (context, position) {
return position >= searchedProposals.length
? _buildLoaderListItem()
: ProposalCardFactory(
proposal: searchedProposals[position],
authToken: _authToken,
);
});
}
Widget _buildLoaderListItem() {
return Center(
child: CircularProgressIndicator(
valueColor: new AlwaysStoppedAnimation(Color(0xff2b57ff))));
}
}
#ProposalSearchSettingPage
class ProposalSearchSetting extends StatefulWidget {
final UserProfileBloc userProfileBloc;
final ProposalSearchBloc proposalSearchBloc;
final MenuBloc menuBloc;
final BuildContext context;
final Function() notifyParent;
ProposalSearchSetting({this.notifyParent,
this.proposalSearchBloc,
this.userProfileBloc,
this.menuBloc,
this.context});
#override
_ProposalSearchSettingState createState() =>
_ProposalSearchSettingState();
}
class _ProposalSearchSettingState extends State<ProposalSearchSetting>
with SingleTickerProviderStateMixin {
UserProfileBloc get _userProfileBloc => widget.userProfileBloc;
ProposalSearchBloc get _proposalSearchBloc => widget.proposalSearchBloc;
List<String> selectedOptions = [];
String resultBy;
List<String> industries;
List<String> stages;
List<String> locations;
List<String> languages;
List<String> countries;
List<String> regionsValue = [];
MenuBloc get _menuBloc => widget.menuBloc;
Animation<double> animation;
AnimationController controller;
double startingPoint;
#override
void initState() {
super.initState();
}
#override
void dispose() {
_userProfileBloc.dispose();
_proposalSearchBloc.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
//double startingPoint = MediaQuery.of(context).size.height;
return MaterialApp(
theme: ThemeData(
buttonTheme: ButtonThemeData(
minWidth: 200.0,
height: 40.0,
buttonColor: Color(0xff2b57ff),
textTheme: ButtonTextTheme.primary)),
home: Scaffold(
body: BlocBuilder(
bloc: _menuBloc,
// ignore: missing_return
builder: (context, state) {
if (state is MenuResponseFetchedState) {
MenuListData _menuListData = state.menuListData;
return Padding(
padding: const EdgeInsets.only(top: 100.0),
child: Center(
child: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
RaisedButton(
onPressed: () async {
resultBy = await showDialog(
context: context,
builder: (context) {
return ResultBySearchDialog(
userProfileBloc: _userProfileBloc,
menuListData: _menuListData,
title: 'Result By:',
options: _menuListData.displayBy.values
.toList());
});
},
color: Color(0xff2b57ff),
child: Text(
'RESULT BY',
style: TextStyle(fontFamily: 'MyRaidPro'),
),
),
SizedBox(
height: 20,
),
RaisedButton(
onPressed: () async {
countries = await showDialog(
context: context,
builder: (context) {
return CountrySearchDialog(
userProfileBloc: _userProfileBloc,
menuListData: _menuListData,
title: 'Select Countries',
selectedOptions: selectedOptions,
onSelectedOptionListChanged: (options) {
selectedOptions = options;
print(selectedOptions);
});
});
},
color: Color(0xff2b57ff),
child: Text(
'COUNTRY',
style: TextStyle(fontFamily: 'MyRaidPro'),
),
),
SizedBox(
height: 20,
),
RaisedButton(
onPressed: () async {
industries = await showDialog(
context: context,
builder: (context) {
return IndustrySearchDialog(
menuListData: _menuListData,
title: 'Select Industries',
options: _menuListData.industries.values
.toList(),
selectedOptions: selectedOptions,
onSelectedOptionListChanged: (options) {
selectedOptions = options;
print(selectedOptions);
});
});
},
child: Text(
'INDUSTRIES',
style: TextStyle(fontFamily: 'MyRaidPro'),
),
),
SizedBox(
height: 20,
),
RaisedButton(
onPressed: () async {
stages = await showDialog(
context: context,
builder: (context) {
return StageSearchDialog(
context: context,
menuListData: _menuListData,
title: 'Select Stages',
options:
_menuListData.stages.values.toList(),
selectedOptions: selectedOptions,
onSelectedOptionListChanged: (options) {
selectedOptions = options;
print(selectedOptions);
});
});
},
child: Text(
'STAGES',
style: TextStyle(fontFamily: 'MyRaidPro'),
),
),
SizedBox(
height: 20,
),
RaisedButton(
onPressed: () async {
languages = await showDialog(
context: context,
builder: (context) {
return LanguageSearchDialog(
menuListData: _menuListData,
title: 'Select Languages',
options: _menuListData.languages.values
.toList(),
selectedOptions: selectedOptions,
onSelectedOptionListChanged: (options) {
selectedOptions = options;
print(selectedOptions);
});
});
},
child: Text(
'LANGUAGES',
style: TextStyle(fontFamily: 'MyRaidPro'),
),
),
SizedBox(
height: 20,
),
RaisedButton(
onPressed: () async {
locations = await showDialog(
context: context,
builder: (context) {
return LocationSearchDialog(
menuListData: _menuListData,
title: 'Select Locations',
options: _menuListData.locations.values
.toList(),
selectedOptions: selectedOptions,
onSelectedOptionListChanged: (options) {
selectedOptions = options;
print(selectedOptions);
});
});
},
child: Text(
'LOCATIONS',
style: TextStyle(fontFamily: 'MyRaidPro'),
),
),
SizedBox(
height: 40,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
ButtonTheme(
textTheme: ButtonTextTheme.primary,
minWidth: 60,
child: RaisedButton(
onPressed: () {
Navigator.of(this.widget.context).pop();
},
color: Color(0xff2b57ff),
child: Text(
'Cancel',
style: TextStyle(fontFamily: 'MyRaidPro'),
),
),
),
ButtonTheme(
textTheme: ButtonTextTheme.primary,
minWidth: 60,
child: RaisedButton(
onPressed: () {
_proposalSearchBloc.dispatch(ProposalFilterFetchEvent(advanceFilter:
FilterProposalPost(......)));
Navigator.pop(context);
print(("value from dialog" +
industries.toString()));
print(("value from dialog" +
stages.toString()));
print(("value from dialog" +
locations.toString()));
print(("value from dialog" +
languages.toString()));
},
color: Color(0xff2b57ff),
child: Text(
'Apply',
style: TextStyle(fontFamily: 'MyRaidPro'),
),
),
)
],
)
],
),
),
),
);
}
},
),
),
);
}
}
#BLOC
class ProposalSearchBloc
extends Bloc<ProposalSearchEvent, ProposalSearchState> {
final ProposalListingRepo proposalRepository;
List keywordSearchedProposalList = List();
List filteredProposalList = List();
ProposalSearchBloc({this.proposalRepository});
void proposalFilterPostParam(FilterProposalPost filterProposalPost) {
dispatch(ProposalSearchFetchEvent(filterProposalPost: filterProposalPost));
}
#override
ProposalSearchState get initialState => ProposalSearchFetchingState();
#override
Stream<ProposalSearchState> mapEventToState(event) async* {
try {
var filteredProposal;
print("proposal search even fired first time");
if (event is ProposalSearchFetchEvent) {
filteredProposal =
await proposalRepository.filterProposal(event.filterProposalPost);
} else if (event is ProposalFilterFetchEvent) {
print("filter event");
filteredProposal =
await proposalRepository.filterProposal(event.advanceFilter);
filteredProposalList.addAll(filteredProposal);
yield ProposalSearchFetchedState(filteredProposal: filteredProposal);
}
} catch (_) {
//print(error.toString());
yield ProposalSearchErrorState();
}
}
}
Finally I was able to solve the problem. I just forgot to use try catch blok in my bloc. This solves most of the problems of reloading the previous page after changing configuration from another page (DialogBox Box probably). I just had to make few changes in the Bloc code as:
#override
Stream<ProposalSearchState> mapEventToState(event) async* {
yield ProposalSearchFetchingState();
if (event is ProposalSearchFetchEvent) {
try {
print("proposal search");
filteredProposal =
await proposalRepository.filterProposal(event.filterProposalPost);
yield ProposalSearchFetchedState(
searchedProposal: filteredProposal);
} catch (error) {
print(error);
}
if (event is ProposalFilterFetchEvent) {
try {
print("proposal filtered");
filteredProposal =
await proposalRepository.filterProposal(event.filterProposalPost);
yield ProposalFilteredFetchedState(
filteredProposal: filteredProposal);
} catch (error) {
print(error.toString());
}
}
}
}