Flutter - Trying to get the scaffold of a widget context from reducer - android

I am hitting a wall since I am trying use the context (to call a snackbar when the async action is done) of a widget from a reducer.
I have tried using GlobalKey, but when I get such key and I try to use the context of it to call the widget Scaffold it throws an error which says there is no Scaffold for such context, when there is infact.
Sadly I cannot provide the code because is for a customer and the code cannot be shown, but I can provide you with the details if it is needed.
The snackbar/toast itself is not that important, but if the context of a widget
cannot be get from the reducer would be and important issue in the future.
Thanks
EDIT:
Here is a reproduce of the code as #Günter Zöchbauer has suggested:
-keys file
import 'package:flutter/widgets.dart';
class Keys {
static final GlobalKey<MyWidgetState> myWidgetStateKey = new
GlobalKey<MyWidgetState>();
}
-Widget file
import 'package:myapp/keys.dart';
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
class MyPage extends StatefulWidget{
#override
MyPageState createState()=>new MyPageState();
}
class MyPageState extends State<MyPage>{
#override
Widget build(BuildContext conext){
return new Scaffold(
key: Keys.myWidgetStateKey,
appBar:new AppBar(
title:new Text("My app bar")
),
body: new Text("My app body")
);
}
}
-Reducer file
import 'package:flutter/material.dart';
import 'package:casinoadmiralapp/appState.dart';
import 'package:casinoadmiralapp/actions.dart';
import 'package:casinoadmiralapp/keys.dart';
AppState reducer(AppState state,action){
BuildContext context = Keys.myWidgetStateKey.currentContext;
if(action is TheAction){
Scaffold.of(context).showSnackBar(
new SnackBar(
content:new Text("You have done an action"),
action: new SnackBarAction(
label: "UNDO",
onPressed: () => Scaffold.of( context ).hideCurrentSnackBar(),
),
)
);
}
}

I little-bit understand your problem. you are getting problem to show snack toast on view so I have share code to implementing snack bar.
class AprovedScreenState extends State<AprovedScreen> {
BuildContext buildContext;
final key = new GlobalKey<ScaffoldState>();
void navigationPage() {
key.currentState.showSnackBar(new SnackBar(
content: new Text("Sending Message"),
));
write key code in scaffold method like below:
#override
Widget build(BuildContext context) {
// TODO: implement build
buildContext = context;
return new Scaffold(
key: key,
)}

Finally I decided to follow #Günter Zöchbauer advice and to put the Scaffold into a store conector so when the store is updated I check the value of the store and due that changing the page.

Related

My flutter property has not assign value in future block

My flutter property has not changed in future blocks. I tried setState(() {}) but not working.
I uninstalled flutterSdk and android SDK then I installed this SDK but still has not changed.
I had the same situation in my previous project. I copied the code of other pages and pasted it to the page that is not working. The page is working a little then page is wrong
this is my code:
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class apiPage extends StatefulWidget {
const apiPage({Key? key}) : super(key: key);
#override
State<apiPage> createState() => _apiPageState();
}
class _apiPageState extends State<apiPage> {
String _response="exe";//this property is not working
Future <void> ApiCall() async{
String adres="www.api";
http.Response cevap=await http.get(Uri.parse(adres));
if(cevap.statusCode==200){
_response=cevap.body;//property needs to be changed
}else{
_response="error";//feature needs to be changed
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: <Widget>[
Text('$_response'),
]
),
);
}
}
When you like to update UI with new value, call setState on widget-state class. Here you can do,
if(cevap.statusCode==200){
setState((){
_response=cevap.body;
});
}else{
setState((){
_response="error";
});
}
Make sure to call the ApiCall() method.
A better choice will be using FutureBuilder for future method. Find more about FutureBuilder and StatefulWidget.

Flutter Appbar disappears when using Share

When I use Share.share using Flutter share_plus package the app bar disappears and the content of the screen moves up...and it doesn't look very nice.
Simple example:
import 'package:flutter/material.dart';
import 'package:share_plus/share_plus.dart';
class Example extends StatelessWidget {
const Example({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () async {
await Share.share('Some text');
},
child: const Text('Press me'),
);
}
}
Anyone knows why that happens?
Try SafeArea around Scaffold widget.
Try this out It works fine for me
final RenderBox box = context.findRenderObject() as RenderBox;
Share.share(shareURL,
subject: title,
sharePositionOrigin: box.localToGlobal(Offset.zero) & box.size);

Flutter-Dart NoSuchMethodError (NoSuchMethodError: Class 'int' has no instance method 'call'. Receiver: 5 Tried calling: call("25"))

Im using Getx for state management. I'm getting an error when I use getx set method.
I am using this code for Getx class:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
// Bu alan benim sayac değişkenlerimi Getx yardımı ile tuttuğum classdır.farkllı değişken classları yazılabilir.
class SayacController extends GetxController {
//5 benim değikenimin ilk değeridir.
var _sayac = 5.obs;
//get ile çeker, set ile veriyi atarım.
get sayac => _sayac.value;
set sayac(yeniDeger) => _sayac.value = yeniDeger;
//burada 2 tane fonksiyon belirledim. çeşitli fonksiyonlar yazılabilir.
void arttir() {
sayac = sayac + 1;
}
void azalt() {
sayac = sayac - 1;
}
}
I am using this code for main page.
import 'package:flutter/material.dart';
import 'package:flutter_ilk_proje/sayac_controllerEx.dart';
import 'package:get/get.dart';
import 'package:http/http.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
//Burada controller değşkenlerini vs getiriyorum.
SayacController _controller = Get.put(SayacController());
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Material App',
home: Scaffold(
appBar: AppBar(
title: Text('Material App Bar'),
),
body: Center(
child: InkWell(
onTap: () {
_controller.sayac("25");
},
child: Container(
child: Obx(
() => Text(_controller.sayac.toString()),
)),
),
),
),
);
}
}
and I'am getting this error
Exception has occurred.
NoSuchMethodError (NoSuchMethodError: Class 'int' has no instance method 'call'.
Receiver: 5
Tried calling: call("25"))
Screenshots about codes.
https://ibb.co/LP85JGR
https://ibb.co/YpFHjQF
https://ibb.co/HqPhxHd
It is really hard to guess what you may have meant.
Should this line: _controller.sayac("25"); maybe be _controller.sayac = 25;?
Anyway, _controller.sayac("25"); is plain wrong. sayac is a property. You can read it, you can write it, you cannot call it like that.
That said, you seem to try to get by with the bare minimum. Don't do this. Dart is such a wonderful language and it will help you all along the way, if you use it. Get a good linter (did you turn yours off? There should be one by default now...) and let it explain why you need to be verbose and explicit in everything you do and the language will support you as much as possible. This error that you got would be a compile time error if you had used the power of Dart.

Could not find the correct provider, firestore collections

I'm getting a weird error, can anyone explain why this is and what would be the solution?
I need to compare different collection fields in firestore. I was thinking it might be because I'm using both streambuilder and provider? so one of the context gets 'confused'. If this is so, is there any alternative to what I'm trying to do?
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:carpoolapp/shared/loading.dart';
import 'package:provider/provider.dart';
import 'package:carpoolapp/models/chatdata.dart';
import 'package:carpoolapp/screens/home/chat_tile.dart';
final _firestore = FirebaseFirestore.instance;
User user = FirebaseAuth.instance.currentUser;
class preMessageTab extends StatefulWidget {
#override
_preMessageTabState createState() => _preMessageTabState();
}
class _preMessageTabState extends State<preMessageTab> {
int count = 0;
var chats;
void prov(){
chats = Provider.of<List<ChatData>>(context);
}
#override
Widget build(BuildContext context) {
prov();
return StreamBuilder(
stream: _firestore.collection('users').doc(user.uid).collection('messages').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: Loading(),
);
}
else{
return ListView.builder(
itemCount: chats.length,
itemBuilder: (context, index) {
snapshot.data.docs.forEach((doc) {
if(doc.data()['sender'] == chats[index].uid){
++count;
}
});
if(count>=1){
return ChatTile(chat: chats[index],);
}
else{
return SizedBox(height: 20.0,);
}
}
);
}
}
);
}
}
The error indicates that your widget can't access the provider. This could be due to the multiple reasons mentioned in the red screen and debug console.
Mainly, always check that your provider is above your widget.
If you are using more than one provider, use multiProvider.
If the problem still persists, it would mean that the widget you are calling provider from, and your multiprovider, are in two separate material route.
Fixing this issue would solve the problem usually, as you suggested also, using a middleMan widget.
Created another dart file and used that as a 'middleman' to get to the original tab. The route was the issue.
#Huthaifa Thank you for your help.
class prepreMessageTab extends StatefulWidget {
#override
_prepreMessageTabState createState() => _prepreMessageTabState();
}
class _prepreMessageTabState extends State<prepreMessageTab> {
#override
Widget build(BuildContext context) {
return StreamProvider<List<ChatData>>.value(
value: DatabaseService().chatData,
child: Scaffold(
body: preMessageTab(),
),
);
}
}

How to store stream data and display new one along with old in a flutter list view?

I'm trying to display a comment stream from Reddit API. I"m using Streambuilder to stream contents as it arrives and displays it as list view thing is I can only view present stream content and this will disappear as new stream contents appear replacing the old ones. If I don't mention item count inside listview.builder prints contents infinitely still new stream appears.
is there a way to display contents along with previous contents in a scrollable fashion and automatically scroll down as a new stream message appears??
Assuming that the comment stream returns individual (and preferably unique) comments one at a time rather than as a list, what you need to do is store the incoming comments in a state object such as a list. When a new comment comes through the stream, you add it to the list and then trigger a widget rebuild.
What you are doing right now is replacing state with each new stream element rather than accumulating them. Using the code you provided, I have edited it to behave as an accumulator instead. Notice the List<Comment> comments = <Comment>[] object added to state. I have also removed the StreamBuilder since that isn't helpful for this use case.
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:draw/draw.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
home: RedditFlutter(),
debugShowCheckedModeBanner: false,
);
}
}
class RedditFlutter extends StatefulWidget {
RedditFlutter({Key key}) : super(key: key);
#override
_RedditFlutterState createState() => _RedditFlutterState();
}
class _RedditFlutterState extends State<RedditFlutter> {
var comments;
ScrollController _scrollController =
new ScrollController(initialScrollOffset: 50.0);
List<Comment> comments = <Comment>[];
StreamSubscription<Comment>? sub;
var msg = '';
Future<void> redditmain() async {
// Create the `Reddit` instance and authenticated
Reddit reddit = await Reddit.createScriptInstance(
clientId: 'clientid',
clientSecret: 'clientsecret',
userAgent: 'useragent',
username: 'username',
password: 'password', // Fake
);
// Listen to comment stream and accumulate new comments into comments list
sub = reddit.subreddit('cricket').stream.comments().listen((comment) {
if (comment != null) {
// Rebuild from state when a new comment is accumulated
setState(() {
comments.add(comment);
})
}
});
}
#override
void initState() {
// TODO: implement initState
redditmain();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Reddit"),
centerTitle: true,
),
body: Center(
child: Container(
child: ListView.builder(
controller: _scrollController,
itemCount: comments.length,
itemBuilder: (context, index) {
final Comment comment = comments[index];
return Card(
child: ListTile(
leading: Image.asset('assets/criclogo.png'),
title: Text(comment.body),
trailing: Icon(Icons.more_vert),
),
);
},
),
);
),
);
}
#override
void dispose() {
sub?.cancel();
super.dispose();
}
}
Note that I have not tested this code so there may be (trivial) bugs. Still, conceptually, it should be fine.

Categories

Resources