Flutter Receive sharing intent and page change - flutter

I'm working on a mailing application and i'm stuck when i try to share a file to send it by email with the receive_sharing_intent package
I'm able to get the file in the application with it's path and all, but then i need to redirect the user to the mail editor page. When i try to use this to get to the mailEditor page :
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MailEditor(
message: message,
editorType: 'new',
),
),
);
I get this error :
[ERROR:flutter/shell/common/shell.cc(213)] Dart Error: Unhandled exception:
Navigator operation requested with a context that does not include a Navigator.
The context used to push or pop routes from the Navigator must be that of a widget that is a descendant of a Navigator widget.
This package being developed by the community i couldn't find much help anywhere on the internet.
I failed to use the ReceiveSharingIntent method anywhere else than the main.dart file, so maybe there's a way to use it directly on my mailEditor page that i didn't find?
If more code is needed here is my ReceiveSharingIntent method :
class MyApp extends StatefulWidget {
// This widget is the root of your application.
#override
_MssProState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
void dispose() {
_intentDataStreamSubscription.cancel();
super.dispose();
}
#override
Widget build(BuildContext context) {
// For sharing images coming from outside the app while the app is in the memory
_intentDataStreamSubscription = ReceiveSharingIntent.getMediaStream().listen((List<SharedMediaFile> value) {
_sharedFiles = value;
Message message = Message();
for (var i = 0; i < _sharedFiles.length; i++) {
File file = File(_sharedFiles[i].path);
Attachment attachment = Attachment(
fileName: basename(file.path),
attachmentPart: i + 1,
contentType: lookupMimeType(file.path),
name: basename(file.path),
);
}
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MailEditor(
message: message,
editorType: 'new',
),
),
);
});
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Login(),
routes: {
'/login': (BuildContext context) => Login(),
},
);
}
Thanks a lot for any help and suggestions, i've been stuck on this for a while.
Edit:
Added more code for context

Navigator should be used inside the build() method. If you want to use context outside of it, pass it as an argument like BuildContext context.

Related

Switching beetwen sites using flutter

Flutter don't show any error, just if _rundy = 0 page doesn't switch, 0 reaction. ZmienneClass is class for variables, not any Page which is showing on application. I guess it may be problem with Buildcontext but idk, im beginner with flutter. (ResultPage is resGamePage)
class ZmienneClass extends ChangeNotifier {
void decrementCounter(int liczba, BuildContext context) {
if (_rundy == 0) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => resGamePage(title: "Wyniki")));
void setPlayerCount({required int liczbagraczy}) {
graczepoczatkowi = liczbagraczy;}
}}}
Some resGamePage code
class resGamePage extends StatefulWidget {
const resGamePage({Key? key, value}) : super(key: key);
#override
_resGamePageState createState() => _resGamePageState();
}
class _resGamePageState extends State<resGamePage> {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [ChangeNotifierProvider.value(value: ZmienneClass())],
child: Scaffold(
You can use push replacement command
Navigator.pushReplacement(
context,
new MaterialPageRoute(
builder: (context) => Disconnect()));
Where Disconnect is the name of your next page stless widget
This code does destroys the current activity and then it loads the next activity
You can use it to go to any page as you said in above diagram
If you are in the FirGamePage then you can go to the SecGamePage by this command by a button click or as per your UI
Hope this solution helps ;)

Flutter on web, using query params in url redirects to inital route

I'm having a pretty weird issue with Flutter when using it for a web page. I need to process a query param from an external source, which hits my website with e.g /page?param=1
I have a super simple flutter project setup:
import 'package:client/screens/screens.dart';
import 'package:flutter/material.dart';
import 'package:url_strategy/url_strategy.dart';
void main() {
setPathUrlStrategy();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
),
routes: {
"/": (context) => HomeScreen(),
"/page": (context) => PageScreen(),
},
);
}
}
When going to "/" or "/page" it works fine. But as soon as I go to "/page?param=1". I get the following error:
The following message was thrown:
Could not navigate to initial route.
The requested route name was: "/page?param=1"
There was no corresponding route in the app, and therefore the initial route specified will be
ignored and "/" will be used instead.
Is Flutter not able to see what a query param is? It's web 101 doing something like this, I must be doing something wrong, I just can't find the answer.
Try using onGenerateRoute callback in MaterialApp, for eg:
onGenerateRoute: (RouteSettings settings) {
Widget? pageView;
if (settings.name != null) {
var uriData = Uri.parse(settings.name!);
//uriData.path will be your path and uriData.queryParameters will hold query-params values
switch (uriData.path) {
case '/page':
pageView = PageScreen();
break;
//....
}
}
if (pageView != null) {
return MaterialPageRoute(
builder: (BuildContext context) => pageView!);
}
},

Flutter Provider rebuilt widget before parent's Consumer

I have got a problem with the provider package.
I want to be able to clean an attribute (_user = null) of a provider ChangeNotifier class (it is a logout feature).
The problem is when I am doing that from a Widget that use info from this Provider.
My main app is like :
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => AuthProvider(),
builder: (context, _) => App(),
),
);
}
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Consumer<AuthProvider>(builder: (_, auth, __) {
Widget displayedWidget;
switch (auth.loginState) {
case ApplicationLoginState.initializing:
displayedWidget = LoadingAppScreen();
break;
case ApplicationLoginState.loggedIn:
displayedWidget = HomeScreen();
break;
case ApplicationLoginState.loggedOut:
default:
displayedWidget = AuthenticationScreen(
signInWithEmailAndPassword: auth.signInWithEmailAndPassword,
registerAccount: auth.registerAccount,
);
}
return MaterialApp(
title: 'My App',
home: displayedWidget,
routes: {
ProfileScreen.routeName: (_) => ProfileScreen(),
},
);
});
}
}
My Provider class (simplified) :
class AuthProvider extends ChangeNotifier {
ApplicationLoginState _loginState;
ApplicationLoginState get loginState => _loginState;
bool get loggedIn => _loginState == ApplicationLoginState.loggedIn;
User _user;
User get user => _user;
void signOut() async {
// Cleaning the user which lead to the error later
_user = null;
_loginState = ApplicationLoginState.loggedOut;
notifyListeners();
}
}
My Profile screen which is accessible via named Route
class ProfileScreen extends StatelessWidget {
static const routeName = '/profile';
#override
Widget build(BuildContext context) {
final User user = Provider.of<AuthProvider>(context).user;
return Scaffold(
// drawer: AppDrawer(),
appBar: AppBar(
title: Text('Profile'),
),
body: Column(
children: [
Text(user.displayName),
FlatButton(
child: Text('logout'),
onPressed: () {
// Navigator.pushAndRemoveUntil(
// context,
// MaterialPageRoute(builder: (BuildContext context) => App()),
// ModalRoute.withName('/'),
// );
Provider.of<AuthProvider>(context, listen: false).signOut();
},
)
],
),
);
}
}
When I click the logout button from the profile screen, I don't understand why i get the error :
As I am using a Consumer<AuthProvider> at the top level of my app (this one includes my route (ProfileScreen), I thought it would redirect to the AuthenticationScreen due to the displayedWidget computed from the switch.
But it seems to rebuild the ProfileScreen first leading to the error. the change of displayedWidget do not seems to have any effect.
I'm pretty new to Provider. I don't understand what I am missing in the Provider pattern here ? Is my App / Consumer wrongly used ?
I hope you can help me understand what I've done wrong here ! Thank you.
Note : the commented Navigator.pushAndRemoveUntil redirect correctly to the login screen but I can see the error screen within a few milliseconds.
Your user is null, and you tried to get the name of him. You need to check it before using it. It will look like this:
user == null ?
Text("User Not Found!"),
Text(user.displayName),
From the provider API reference of Provider.of :
Obtains the nearest Provider up its widget tree and returns its
value.
If listen is true, later value changes will trigger a new State.build
to widgets, and State.didChangeDependencies for StatefulWidget.
So I think the line final User user = Provider.of<AuthProvider>(context).user; in your profile screen calls a rebuild when the _user variable is modified, and then the _user can be null in your ProfileScreen.
Have you tried to Navigator.pop the profile screen before clearing the _user variable?

Dart & Flutter - Passing data across screens. NoSuchMethodError being caused by widget within MaterialPageRoute()

I tried passing data from a filter page to the home page, but keep getting the following error.
Error message on console - NoSuchMethodError being caused by widget within MaterialPageRoute()
//Radio button values to select user's gender on Filter Page
enum PrayditatorGender { Female, Male }
PrayditatorGender pGender;
//Radio button values to select Prayditation category on Filter Page
enum PrayditationFilter {
All,
Family,
Fellowship,
GodlyWisdom,
GoodSuccess,
HealthAndSafety,
}
PrayditationFilter pFilter = PrayditationFilter.All;
//Code to push the data from Filter Page to Home Page
Navigator.push(context, MaterialPageRoute(
builder: (context) {
PrayditatorHomePage(
pGender: pGender,
pFilter: pFilter
)
));
//Code to handle the data on Home Page
class PrayditatorHomePage extends StatefulWidget {
final PrayditatorGender pGender;
final PrayditationFilter pFilter;
PrayditatorHomePage({this.pGender, this.pFilter});
#override
_PrayditatorHomePageState createState() => _PrayditatorHomePageState();
}
class _PrayditatorHomePageState extends State<PrayditatorHomePage> {
#override
Widget build(BuildContext context) {}
Your syntax is wrong, you're not supposed to be having this issue, this code worked with no issues:
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PrayditatorHomePage(
pGender: pGender,
pFilter: pFilter,
),
),
);
Thank you all for taking time to view/comment. Bug has been busted and code working effectively!
Syntax was all correct, however, a static parameter was inappropriately put in the place meant for a dynamic parameter. After all, lessons learned.

How to get a context for Navigator in Widget initState()?

I want my app to work offline without a user set, and asking for a login when connectivity is back
en excerpt of the code I'm trying:
class _MyAppState extends State<MyApp> {
#override
void initState() {
super.initState();
Connectivity().onConnectivityChanged.listen((ConnectivityResult result) =>
checkConnectivity().then((isOnline) {
if (isOnline && MyApp.store.state.user == null)
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (context) => LoginPage()),
);
}));
}
#override
Widget build(BuildContext context) {
return MaterialApp(
routes: {
...
but all I can get is this error:
Unhandled Exception: Navigator operation requested with a context that does not include a Navigator.
The context used to push or pop routes from the Navigator must be that of a widget that is a descendant of a Navigator widget.
I tried to wrap my Navigator call inside a Future.delayed as described here but I got the same error