error: Undefined name 'widget' in Dart when trying to build navigation - json

Can someone help me? Newbie with Flutter here.
I have this:
class SecondRoute extends StatelessWidget {
final Place? place;
const SecondRoute({Key? key, this.place}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Route"),
),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text(widget.place!.text!),
),
),
);
}
And:
class PlaceDetail extends StatefulWidget {
final Place? place;
PlaceDetail({Key? key, this.place}) : super(key: key);
#override
_PlaceDetailState createState() {
return _PlaceDetailState();
}
}
I successfully can navigate to the next page, but the problem is with this part:
child: Text(widget.place!.text!)
I am trying to show some content that I fetch with JSON. In a different widget, that specific widget.place!.text! works like a charm, but in this class and widget, I can't get it to work and t thus I get the error:
error: Undefined name 'widget'
If I extend it to State , I get the error:
error: The return type 'SecondRoute' isn't a 'Widget'
I tried to follow the documentation here:
https://flutter.dev/docs/cookbook/navigation/navigation-basics
As I mentioned, the navigation itself works, but trying to fetch data from JSON that I had in a widget gives me the error.
Edit:
Text(${place?.text!}")
The above gives me NULL. Any chance I can get this variable sent to the new page/screen without giving me NULL value?

child: Text(widget.place!.text!)
should be
child: Text(this.place!.text!)
or simply
child: Text(place!.text!)
Although you should think about your usage of !. It should not be neccessary here.

Related

Stateless widget and Widget function difference

I have read the difference between Stateless widgets and functions that return a Widget and I know that the framework can recognize classes but not functions. In the below code, I have a floating button, in which I call the setState() and in both cases the appbar rebuilds (stateless widget and function), so in this context are these two any different?
appBar:
AppBarv1(title: widget.title,)
// customAppBar(title: widget.title)
,
floatingActionButton: FloatingActionButton(backgroundColor: Colors.blue,onPressed: (){
setState(() {
});
},),
body:
Center(
),
);
PreferredSizeWidget customAppBar({String title}) {
print('appbar is built');
return AppBar(
title: Text(title),
actions: [],
);
}
class AppBarv1 extends PreferredSize {
const AppBarv1({this.title});
final String title;
#override
Size get preferredSize => Size.fromHeight(kToolbarHeight);
#override
Widget build(BuildContext context) {
print('appbar is built');
return AppBar(
title: Text(title),
actions: [],
);
}
}
Thanks in advance!
They are no different, other than that the function executes before the Widget is returned. The Widget-Tree you end up with, is identical.

WebView in Flutter for Web is not loading Google Maps or others

Hei there,
I have the Problem that my WebView doesn't load. It only shows me a loading Screen.
I am using the flutter_webview_plugin in Flutter for Web.
I have no idea why its always loading. It does this always, with whatever Website I tried.
import 'package:flutter/material.dart';
import 'package:website_aalen_by_night/widgets/info_card.dart';
import 'package:website_aalen_by_night/widgets/nav_bar.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'AAlen by Night',
theme: ThemeData.dark(),
home: WebsiteAalenByNight(),
debugShowCheckedModeBanner: false,
);
}
}
class WebsiteAalenByNight extends StatefulWidget {
#override
WebsiteState createState() => WebsiteState();
}
ScrollController controller = new ScrollController();
class WebsiteState extends State {
#override
Widget build(BuildContext context) {
double width = MediaQuery.of(context).size.width;
double height = MediaQuery.of(context).size.height;
FlutterWebviewPlugin().onHttpError.listen((WebViewHttpError item) {
print(" WebView onHttpError.code: ${item.code}");
});
return Scaffold(
backgroundColor: Color.fromRGBO(79, 79, 79, 1),
body: Stack(
children: <Widget>[
Scrollbar(
child: ListView(
controller: controller,
children: <Widget>[
InfoCard(),
Image(
image: AssetImage("lib/images/map.png"),
//height: height,
width: width,
fit: BoxFit.cover,
),
InfoCard(),
LimitedBox(
maxWidth: width,
maxHeight: height,
child: WebviewScaffold(
url: "https://www.google.com",
withZoom: false,
withLocalStorage: false,
withJavascript: true,
withLocalUrl: true,
),
),
],
),
),
NavBar(),
],
),
);
}
}
The goal of this is to implement a Map with Markers on the Screen. So I believed I can try a WebView but with that I did come to a stop soon.
Maybe there is a better Way to implement a Map (tried a few other Things like using a map plugin instead but I didn't find any which works for Flutter for Web).
It is really important to get it working on Flutter for Web and NOT on
any other Platform!
Thanks for helping me....
Maybe in the Future I am able to answer such questions for others :D
I don't think that https://github.com/fluttercommunity/flutter_webview_plugin works in web since it uses native libraries.
HOWEVER, the great advantage of using a browser for your flutter app, is that you can use HTML and you don't need a webview there!
check this example of using a nested youtube player
void main() {
ui.platformViewRegistry.registerViewFactory(
'hello-world-html',
(int viewId) => IFrameElement()
..width = '640'
..height = '360'
..src = 'https://www.youtube.com/embed/IyFZznAk69U'
..style.border = 'none'
);
runApp(Directionality(
textDirection: TextDirection.ltr,
child: SizedBox(
width: 640,
height: 360,
child: HtmlElementView(viewType: 'hello-world-html'),
),
));
}
source
Of course the communication with the content it's another history, since it's an iframe and in web browsers CORS is enabled it means you can't access the iframe from flutter, in the case of Google maps, they have an URL api and pass your marker location there ;)

How do I calculate the sunrise and sunset in flutter?

I would like to be able to change the text on a screen from day to night, depending on the the sun has set, or not. I found this api (https://sunrise-sunset.org/api) and more recently this package sunrise_sunset: "^1.0.3", but I am having difficulty.
This is part of a much bigger project that will be a map (google_maps) that will automatically change theme depending on the time of day(sunrise and sunset)
I know that whenever you use await, you have to make the class async, which I have done, but I am getting errors.
I have simply copied the code in the package example tab into my project
https://pub.dev/packages/sunrise_sunset#-example-tab-
I really am stuck with this, so any help would be very much appreciated.
thanks
import 'package:flutter/material.dart';
import 'package:sunrise_sunset/sunrise_sunset.dart';
void main() => runApp(JsonApiDemo());
class JsonApiDemo extends StatefulWidget {
JsonApiDemo({Key key}) : super(key: key);
#override
_JsonApiDemoState createState() => _JsonApiDemoState();
}
class _JsonApiDemoState extends State<JsonApiDemo> async {
var response = await SunriseSunset.getResults(latitude: 39.001735, longitude: -119.752744);
if (response.success) {
print('Sunrise: ${response.data.sunrise}');
print('Sunset: ${response.data.sunset}');
} else {
print(response.error);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Hello World!',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text('Hello World!'),
),
body: Center(
child: Text('Hello World!'),
),
),
);
}
}
Missing concrete implementation of State.build.
Try implementing the missing method, or make the class abstract.
A class declaration must have a body, even if it is empty.
Try adding an empty body.
Functions must have an explicit list of parameters.
Try adding a parameter list.
The await expression can only be used in an async function.
Try marking the function body with either 'async' or 'async*'.
The declaration 'build' isn't referenced.
Try removing the declaration of 'build'.
1 - don't mark a class as async - only functions can be async.
2 - you should call the package from an async function. The simplest way to do that is from the initState method - note initState itself is not async - so you will need another method.
3 - in that async method, store the results and call setState so that the widget is rebuilt to show them
4 - in build you need to be able to cope with the gap while the results are being fetched - use a progress indicator, etc. (I've just replaced the result with the word working).
class _JsonApiDemoState extends State<JsonApiDemo> {
DateTime sunrise;
DateTime sunset;
#override
void initState() {
super.initState();
getSunData();
}
void getSunData() async {
var response = await SunriseSunset.getResults(
latitude: 39.001735,
longitude: -119.752744,
);
if (response.success) {
var data = response.data;
setState(() {
sunrise = data.sunrise;
sunset = data.sunset;
});
print('Sunrise: $sunrise');
print('Sunset: $sunset');
} else {
print(response.error);
}
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Hello World!',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text('Hello World!'),
),
body: Center(
child: Text(sunrise == null ? 'Working...' : '$sunrise-$sunset'),
),
),
);
}
}

How to mock 'google_maps_flutter' package for flutter tests?

I've recently started getting into flutter, but just as I was about to write a few widget tests, I noticed that I wasn't terribly sure how to mock out the Google Maps Flutter package.
Many examples I've seen include using the library "mockito" to mock out classes, but this assumes that the Google Maps widget will be injected into the widget to be tested. Unfortunately, with their given documentation and startup guide, this doesn't seem to be very possible:
class MapsDemo extends StatefulWidget {
#override
State createState() => MapsDemoState();
}
class MapsDemoState extends State<MapsDemo> {
GoogleMapController mapController;
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(15.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Center(
child: SizedBox(
width: 300.0,
height: 200.0,
child: GoogleMap(
onMapCreated: _onMapCreated,
),
),
),
RaisedButton(
child: const Text('Go to London'),
onPressed: mapController == null ? null : () {
mapController.animateCamera(CameraUpdate.newCameraPosition(
const CameraPosition(
bearing: 270.0,
target: LatLng(51.5160895, -0.1294527),
tilt: 30.0,
zoom: 17.0,
),
));
},
),
],
),
);
}
void _onMapCreated(GoogleMapController controller) {
setState(() { mapController = controller; });
}
}
Note that the GoogleMaps widget cannot be passed in because onMapCreated is a required function, and that function relies private class method (give the parent widget access to GoogleMapsController). Many other examples of mockito mock functions that don't have this sort of callback function to set state.
There doesn't seem to be any other packages I've seen that can effectively mock out the GoogleMaps widget, so I don't really have any sort of example to follow. Ideally, what I was expecting was some sort of behavior like proxyquire or sinon in node.s (where you don't need to pass in the mocked libraries into function.constructors), but it looks like mockified classes need to be passed into the tested widgets.
Are there any other ideas on how to mock out this library for testing? Or should I just live with testing the actual functionality?
I managed to mock the GoogleMaps by mocking the channels it uses:
setUpAll(() async {
SystemChannels.platform_views.setMockMethodCallHandler((MethodCall call) {
switch (call.method) {
case 'create':
return Future<int>.sync(() => 1);
default:
return Future<void>.sync(() {});
}
});
MethodChannel('plugins.flutter.io/google_maps_0', StandardMethodCodec())
.setMockMethodCallHandler((MethodCall methodCall) async {
return null;
});
}
I got inspiration from this webview plugin test (which is a PlatformView like the GoogleMaps widget), as well as this GoogleMaps plugin test

Flutter Maps Overlay Issue

I'm working on Flutter for an app that uses Google Maps. The app is made up of 2 activities: a list and the map.
This paragraph is just some background information. You may skip it. Usually Google Maps let you call a map by tapping a static map which opens into a dynamic one. The static map is just a small widget. The app need to directly display a full screen map on a single activity.
The issue we faced has to do with Overlays. Auby Khan from medium.com provided the code needed to display a full screen map. So we created the first activity with a button that navigates you to the second activity:
new IconButton(
icon: new Icon(Icons.map),
tooltip: 'openMap',
onPressed: (){
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ControlParkMapNormal()),
);
},
),
And in the second activity, it would display the map:
final size = MediaQueryData.fromWindow(ui.window).size;
final GoogleMapOverlayController controller =
GoogleMapOverlayController.fromSize(
width: size.width,
height: size.height,
);
final mapController = controller.mapController;
final Widget mapWidget = GoogleMapOverlay(controller: controller);
class ControlParkMapNormal extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: new Scaffold(
appBar: AppBar(
title: Text("ControlPark"),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.list),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ControlPark()),
);
},
),
],
),
body: MapsDemo(mapWidget, controller.mapController),
),
navigatorObservers: <NavigatorObserver>[controller.overlayController],
);
}
}
class MapsDemo extends StatelessWidget {
MapsDemo(this.mapWidget, this.controller);
final Widget mapWidget;
final GoogleMapController controller;
#override
Widget build(BuildContext context) {
return Center(child: mapWidget);
}
}
When Navigating from Activity 1 > Activity 2 > Activity 1, the map would remain displayed. It would seem that the map is permanently overlayed on all subsequent activities. The transition from Activity 1 > Activity 2 > Activity 1 > Activity 2 yields this error:
I/flutter (12701): Another exception was thrown: 'package:flutter/src/widgets/navigator.dart': Failed assertion: line 1303 pos 14: 'observer.navigator == null': is not true.
Here's the block of code for the observer navigator:
#override
void initState() {
super.initState();
for (NavigatorObserver observer in widget.observers) {
assert(observer.navigator == null);
observer._navigator = this;
}
Is there any way to resolve this?