Flutter Error Where Future Already Completed - android

I'm having trouble figuring out an error of 'Bad state: Future already completed'. I basically have an app that uses a BottomNavigationBar and on one of my screens I am using this class that uses the Completer class.
It happens when creating the webview again:
body: WebView(
initialUrl: 'https://www.google.com/',
onWebViewCreated: (WebViewController webViewController) {
_controller.complete(webViewController);
},
)
Everything loads fine on the first view but if you select another BottomNavigationBarItem and then go back to the class, I get an Exception of Bad state: Future already completed. Below is full code.
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:url_launcher/url_launcher.dart';
import 'dart:async';
class myClass extends StatelessWidget {
Completer<WebViewController> _controller = Completer<WebViewController>();
final Set<String> _favorites = Set<String>();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
NavigationControls(_controller.future),
Menu(_controller.future, () => _favorites),
],
),
//EXCEPTION OCCURS HERE
//BAD STATE: FUTURE ALREADY COMPLETED
body: WebView(
initialUrl: 'https://www.google.com/',
onWebViewCreated: (WebViewController webViewController) {
_controller.complete(webViewController);
},
),
floatingActionButton: _bookmarkButton(),
);
}
_bookmarkButton() {
return FutureBuilder<WebViewController>(
future: _controller.future,
builder:
(BuildContext context, AsyncSnapshot<WebViewController> controller) {
if (controller.hasData) {
return FloatingActionButton(
onPressed: () async {
var url = await controller.data.currentUrl();
_favorites.add(url);
Scaffold.of(context).showSnackBar(
SnackBar(content: Text('Saved $url for later reading.')),
);
},
child: Icon(Icons.favorite),
);
}
return Container();
},
);
}
}
class Menu extends StatelessWidget {
Menu(this._webViewControllerFuture, this.favoritesAccessor);
final Future<WebViewController> _webViewControllerFuture;
final Function favoritesAccessor;
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: _webViewControllerFuture,
builder:
(BuildContext context, AsyncSnapshot<WebViewController> controller) {
if (!controller.hasData) return Container();
return PopupMenuButton<String>(
onSelected: (String value) async {
if (value == 'Email link') {
var url = await controller.data.currentUrl();
await launch(
'mailto:?subject=hello&body=$url');
} else {
var newUrl = await Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) {
return FavoritesPage(favoritesAccessor());
}));
Scaffold.of(context).removeCurrentSnackBar();
if (newUrl != null) controller.data.loadUrl(newUrl);
}
},
itemBuilder: (BuildContext context) => <PopupMenuItem<String>>[
const PopupMenuItem<String>(
value: 'Email link',
child: Text('Email link'),
),
const PopupMenuItem<String>(
value: 'See Favorites',
child: Text('See Favorites'),
),
],
);
},
);
}
}
class FavoritesPage extends StatelessWidget {
FavoritesPage(this.favorites);
final Set<String> favorites;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Favorite pages')),
body: ListView(
children: favorites
.map((url) => ListTile(
title: Text(url), onTap: () => Navigator.pop(context, url)))
.toList()),
);
}
}
class NavigationControls extends StatelessWidget {
const NavigationControls(this._webViewControllerFuture)
: assert(_webViewControllerFuture != null);
final Future<WebViewController> _webViewControllerFuture;
#override
Widget build(BuildContext context) {
return FutureBuilder<WebViewController>(
future: _webViewControllerFuture,
builder:
(BuildContext context, AsyncSnapshot<WebViewController> snapshot) {
final bool webViewReady =
snapshot.connectionState == ConnectionState.done;
final WebViewController controller = snapshot.data;
return Row(
children: <Widget>[
IconButton(
icon: const Icon(Icons.arrow_back_ios),
onPressed: !webViewReady
? null
: () => navigate(context, controller, goBack: true),
),
IconButton(
icon: const Icon(Icons.arrow_forward_ios),
onPressed: !webViewReady
? null
: () => navigate(context, controller, goBack: false),
),
],
);
},
);
}
navigate(BuildContext context, WebViewController controller,
{bool goBack: false}) async {
bool canNavigate =
goBack ? await controller.canGoBack() : await controller.canGoForward();
if (canNavigate) {
goBack ? controller.goBack() : controller.goForward();
} else {
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text("No ${goBack ? 'back' : 'forward'} history item")),
);
}
}
}

tried to reproduce the problem, but wasnt able to do so. Can you show the code with your Bottom Navigation Bar etc? I interpreted it this way, and here it works:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:webview_flutter/webview_flutter.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: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute: "/",
routes: {
"/": (context) => Home(),
},
);
}
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
final navigatorKey = GlobalKey<NavigatorState>();
int _currentIndex = 0;
final pagesRouteFactories = {
'page1': (RouteSettings settings) => MaterialPageRoute<dynamic>(
builder: (BuildContext context) => HomePage(),
settings: settings,
),
'page2': (RouteSettings settings) => MaterialPageRoute<dynamic>(
builder: (BuildContext context) => MyClass(),
settings: settings,
),
};
#override
Widget build(BuildContext context) {
return Scaffold(
body: MaterialApp(
navigatorKey: navigatorKey,
onGenerateRoute: (RouteSettings route) =>
pagesRouteFactories[route.name](route),
initialRoute: 'page1',
),
bottomNavigationBar: BottomNavigationBar(
backgroundColor: Colors.white,
type: BottomNavigationBarType.fixed,
currentIndex: _currentIndex,
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: FittedBox(
child: Text(
'Home',
style: TextStyle(fontWeight: FontWeight.w600),
),
),
),
BottomNavigationBarItem(
icon: Icon(Icons.web),
title: FittedBox(
child: Text(
'Web',
style: TextStyle(fontWeight: FontWeight.w600),
),
),
),
],
onTap: (int index) {
setState(() {
_currentIndex = index;
});
navigatorKey.currentState
.pushReplacementNamed(pagesRouteFactories.keys.toList()[index]);
},
),
);
}
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Text('hi'),
),
);
}
}
class MyClass extends StatelessWidget {
Completer<WebViewController> _controller = Completer<WebViewController>();
final Set<String> _favorites = Set<String>();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
NavigationControls(_controller.future),
Menu(_controller.future, () => _favorites),
],
),
//EXCEPTION OCCURS HERE
//BAD STATE: FUTURE ALREADY COMPLETED
body: WebView(
initialUrl: 'https://www.google.com/',
onWebViewCreated: (WebViewController webViewController) {
_controller.complete(webViewController);
},
),
floatingActionButton: _bookmarkButton(),
);
}
_bookmarkButton() {
return FutureBuilder<WebViewController>(
future: _controller.future,
builder:
(BuildContext context, AsyncSnapshot<WebViewController> controller) {
if (controller.hasData) {
return FloatingActionButton(
onPressed: () async {
var url = await controller.data.currentUrl();
_favorites.add(url);
Scaffold.of(context).showSnackBar(
SnackBar(content: Text('Saved $url for later reading.')),
);
},
child: Icon(Icons.favorite),
);
}
return Container();
},
);
}
}
class Menu extends StatelessWidget {
Menu(this._webViewControllerFuture, this.favoritesAccessor);
final Future<WebViewController> _webViewControllerFuture;
final Function favoritesAccessor;
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: _webViewControllerFuture,
builder:
(BuildContext context, AsyncSnapshot<WebViewController> controller) {
if (!controller.hasData) return Container();
return PopupMenuButton<String>(
onSelected: (String value) async {
if (value == 'Email link') {
var url = await controller.data.currentUrl();
await launch('mailto:?subject=hello&body=$url');
} else {
var newUrl = await Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) {
return FavoritesPage(favoritesAccessor());
}));
Scaffold.of(context).removeCurrentSnackBar();
if (newUrl != null) controller.data.loadUrl(newUrl);
}
},
itemBuilder: (BuildContext context) => <PopupMenuItem<String>>[
const PopupMenuItem<String>(
value: 'Email link',
child: Text('Email link'),
),
const PopupMenuItem<String>(
value: 'See Favorites',
child: Text('See Favorites'),
),
],
);
},
);
}
}
class FavoritesPage extends StatelessWidget {
FavoritesPage(this.favorites);
final Set<String> favorites;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Favorite pages')),
body: ListView(
children: favorites
.map((url) => ListTile(
title: Text(url), onTap: () => Navigator.pop(context, url)))
.toList()),
);
}
}
class NavigationControls extends StatelessWidget {
const NavigationControls(this._webViewControllerFuture)
: assert(_webViewControllerFuture != null);
final Future<WebViewController> _webViewControllerFuture;
#override
Widget build(BuildContext context) {
return FutureBuilder<WebViewController>(
future: _webViewControllerFuture,
builder:
(BuildContext context, AsyncSnapshot<WebViewController> snapshot) {
final bool webViewReady =
snapshot.connectionState == ConnectionState.done;
final WebViewController controller = snapshot.data;
return Row(
children: <Widget>[
IconButton(
icon: const Icon(Icons.arrow_back_ios),
onPressed: !webViewReady
? null
: () => navigate(context, controller, goBack: true),
),
IconButton(
icon: const Icon(Icons.arrow_forward_ios),
onPressed: !webViewReady
? null
: () => navigate(context, controller, goBack: false),
),
],
);
},
);
}
navigate(BuildContext context, WebViewController controller,
{bool goBack: false}) async {
bool canNavigate =
goBack ? await controller.canGoBack() : await controller.canGoForward();
if (canNavigate) {
goBack ? controller.goBack() : controller.goForward();
} else {
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text("No ${goBack ? 'back' : 'forward'} history item")),
);
}
}
}

Related

Flutter permission to contact

My code is the file name is interface.dart. I'm calling the interface.dart from the main.dart
I'm getting a permission denied error when try to access the contacts in the emulator
I added the permission_handler dependency in the pubspec.yaml
Then added the permissions in the AndroidManifest.xml for both read and write
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:contacts_service/contacts_service.dart';
import 'package:permission_handler/permission_handler.dart';
import 'dart:io';
import 'dart:convert';
import 'package:url_launcher/url_launcher.dart';
import 'package:path_provider/path_provider.dart';
class Interface extends StatelessWidget {
const Interface({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('pAM'),
),
body: const ContactSelector(),
);
}
}
class ContactSelector extends StatefulWidget {
const ContactSelector({super.key});
#override
_ContactSelectorState createState() => _ContactSelectorState();
}
class _ContactSelectorState extends State<ContactSelector> {
var status = Permission.contacts.status;
Contact _selectedContact = Contact();
late bool _isTrue;
#override
void initState() {
super.initState();
_readJson();
}
_selectContact() async {
List<Contact> contact =
await ContactsService.getContacts(withThumbnails: false);
setState(() {
_selectedContact = contact as Contact;
});
_saveContactToFile(_selectedContact);
}
_saveContactToFile(Contact contact) async {
final directory = await getApplicationDocumentsDirectory();
final file = File('${directory.path}/selected_contact.txt');
if (!(await file.exists())) {
file.create();
}
file.writeAsString(jsonEncode(contact.toMap()));
}
_readJson() async {
final directory = await getApplicationDocumentsDirectory();
final file = File('${directory.path}/true.json');
if (!(await file.exists())) {
file.createSync();
file.writeAsStringSync('{"isTrue":true}');
}
final content = jsonDecode(await file.readAsString());
setState(() {
_isTrue = content['isTrue'];
});
}
_promptMessage() {
if (_isTrue) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Select a message'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
InkWell(
child: const Text('How are you?'),
onTap: () {
_sendMessage('How are you?');
Navigator.of(context).pop();
}),
InkWell(
child: const Text('Did you have your lunch ?'),
onTap: () {
_sendMessage('Did you have your lunch ?');
Navigator.of(context).pop();
}),
InkWell(
child: const Text("What's for dinner?"),
onTap: () {
_sendMessage("What's for dinner?");
Navigator.of(context).pop();
}),
],
),
),
);
},
);
}
}
String? encodeQueryParameters(Map<String, String> params) {
return params.entries
.map((e) =>
'${Uri.encodeComponent(e.key)}=${Uri.encodeComponent(e.value)}')
.join('&');
}
_sendMessage(String message) async {
String phoneNumber = _selectedContact.phones.toString();
Uri uri = Uri(
scheme: 'sms',
path: phoneNumber,
query: encodeQueryParameters(<String, String>{
'body': 'Welcome to pAM',
}),
);
if (await canLaunchUrl(uri)) {
await canLaunchUrl(uri);
} else {
throw 'Could not send SMS';
}
}
#override
Widget build(BuildContext context) {
return MediaQuery(
data: MediaQueryData.fromWindow(WidgetsBinding.instance.window),
child: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
if (_selectedContact != null)
Text(_selectedContact.displayName ?? 'No contact selected')
else
const Text('No contact selected'),
ElevatedButton(
onPressed: _selectContact,
child: const Text('Select Contact'),
),
ElevatedButton(
onPressed: _promptMessage,
child: const Text('Prompt Message'),
),
],
),
),
));
}
}
You are facing this issues because you haven't asked for the permission yet, refer the code below:
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:contacts_service/contacts_service.dart';
import 'package:permission_handler/permission_handler.dart';
import 'dart:io';
import 'dart:convert';
import 'package:url_launcher/url_launcher.dart';
import 'package:path_provider/path_provider.dart';
class Interface extends StatelessWidget {
const Interface({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('pAM'),
),
body: const ContactSelector(),
);
}
}
class ContactSelector extends StatefulWidget {
const ContactSelector({super.key});
#override
_ContactSelectorState createState() => _ContactSelectorState();
}
class _ContactSelectorState extends State<ContactSelector> {
var status = Permission.contacts.status;
Contact _selectedContact = Contact();
late bool _isTrue;
#override
void initState() {
_readJson();
super.initState();
}
_selectContact() async {
if (await Permission.contacts.request().isGranted) {
List<Contact> contact =
await ContactsService.getContacts(withThumbnails: false);
setState(() {
_selectedContact = contact as Contact;
});
_saveContactToFile(_selectedContact);
}
}
_saveContactToFile(Contact contact) async {
final directory = await getApplicationDocumentsDirectory();
final file = File('${directory.path}/selected_contact.txt');
if (!(await file.exists())) {
file.create();
}
file.writeAsString(jsonEncode(contact.toMap()));
}
_readJson() async {
final directory = await getApplicationDocumentsDirectory();
final file = File('${directory.path}/true.json');
if (!(await file.exists())) {
file.createSync();
file.writeAsStringSync('{"isTrue":true}');
}
final content = jsonDecode(await file.readAsString());
setState(() {
_isTrue = content['isTrue'];
});
}
_promptMessage() {
if (_isTrue) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Select a message'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
InkWell(
child: const Text('How are you?'),
onTap: () {
_sendMessage('How are you?');
Navigator.of(context).pop();
}),
InkWell(
child: const Text('Did you have your lunch ?'),
onTap: () {
_sendMessage('Did you have your lunch ?');
Navigator.of(context).pop();
}),
InkWell(
child: const Text("What's for dinner?"),
onTap: () {
_sendMessage("What's for dinner?");
Navigator.of(context).pop();
}),
],
),
),
);
},
);
}
}
String? encodeQueryParameters(Map<String, String> params) {
return params.entries
.map((e) =>
'${Uri.encodeComponent(e.key)}=${Uri.encodeComponent(e.value)}')
.join('&');
}
_sendMessage(String message) async {
String phoneNumber = _selectedContact.phones.toString();
Uri uri = Uri(
scheme: 'sms',
path: phoneNumber,
query: encodeQueryParameters(<String, String>{
'body': 'Welcome to pAM',
}),
);
if (await canLaunchUrl(uri)) {
await canLaunchUrl(uri);
} else {
throw 'Could not send SMS';
}
}
#override
Widget build(BuildContext context) {
return MediaQuery(
data: MediaQueryData.fromWindow(WidgetsBinding.instance.window),
child: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
if (_selectedContact != null)
Text(_selectedContact.displayName ?? 'No contact selected')
else
const Text('No contact selected'),
ElevatedButton(
onPressed: _selectContact,
child: const Text('Select Contact'),
),
ElevatedButton(
onPressed: _promptMessage,
child: const Text('Prompt Message'),
),
],
),
),
));
}
}
Check the permission status first as this:-
final status = Permission.contacts.request()
if(status.isGrantet){
// permission has granted now save the contact here
}
Refer this link for more details.

Flutter qr_code_scanner showing black screen instead of the scanner

I am using qr_code_scanner to scan a qr code in flutter . The point here is that it shows a black screen instead of showing a scanner . I cant seem to start the qr reader . but suppose i exit the app like put the app in the background and then come to the app again the camera suddenly started . Cant seem to find why the camera dosent start on the app start .
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
#override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: QrScan(),
);
}
}
class QrScan extends StatefulWidget {
const QrScan({Key? key}) : super(key: key);
#override
State<QrScan> createState() => _QrScanState();
}
class _QrScanState extends State<QrScan> {
final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');
Barcode? result;
QRViewController? controller;
#override
void initState() {
super.initState();
controller?.resumeCamera();
}
// In order to get hot reload to work we need to pause the camera if the platform
// is android, or resume the camera if the platform is iOS.
#override
void reassemble() {
super.reassemble();
if (Platform.isAndroid) {
controller?.pauseCamera();
} else if (Platform.isIOS) {
controller?.resumeCamera();
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Expanded(
flex: 5,
child: QRView(
key: qrKey,
onQRViewCreated: _onQRViewCreated,
overlay: QrScannerOverlayShape(
borderRadius: 10, borderWidth: 5, borderColor: Colors.white),
),
),
Expanded(
flex: 1,
child: Center(
child: (result != null)
? Text(
'Barcode Type: ${describeEnum(result!.format)} Data: ${result?.code}')
: Text('Scan a code'),
),
)
],
),
);
}
void _onQRViewCreated(QRViewController controller) {
this.controller = controller;
controller.scannedDataStream.listen((scanData) {
setState(() {
result = scanData;
});
});
}
#override
void dispose() {
controller?.dispose();
super.dispose();
}
}
Try to pause and resume the camera inside your _onQRViewCreated:
void _onQRViewCreated(QRViewController controller) {
this.controller = controller;
controller.scannedDataStream.listen((scanData) {
setState(() {
result = scanData;
});
});
controller.pauseCamera();
controller.resumeCamera();
}
Try this it will surely solve the problem!
#override
Widget build(BuildContext context) {
if (controller != null && mounted) {
controller!.pauseCamera();
controller!.resumeCamera();
}
Use the below code if you are using the flashlight feature!
class QRScanner extends StatefulWidget {
const QRScanner({Key? key}) : super(key: key);
#override
State<StatefulWidget> createState() => _QRScannerState();
}
class _QRScannerState extends State<QRScanner> {
Barcode? result;
QRViewController? controller;
final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');
bool isflash = false;
// In order to get hot reload to work we need to pause the camera if the platform
// is android, or resume the camera if the platform is iOS.
#override
void reassemble() {
super.reassemble();
if (Platform.isAndroid) {
controller!.pauseCamera();
controller!.resumeCamera();
}
controller!.resumeCamera();
}
#override
Widget build(BuildContext context) {
if (controller != null && mounted && !isflash) {
controller!.pauseCamera();
controller!.resumeCamera();
}
return Scaffold(
appBar:
appBar(context, backbutton: true, icon: true, notifications: true),
body: Stack(
children: <Widget>[
_buildQrView(context),
Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
// if (result != null)
// Text(
// 'Barcode Type: ${describeEnum(result!.format)} Data: ${result!.code}',
// style: const TextStyle(color: Colors.white),
// )
// else
// const Text('Scan a code'),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
GestureDetector(
onTap: () async {
isflash = !isflash;
await controller?.toggleFlash();
setState(() {});
},
child: Container(
margin: const EdgeInsets.all(8),
child: FutureBuilder(
future: controller?.getFlashStatus(),
builder: (context, snapshot) {
return snapshot.data == false
? const Icon(
Icons.flash_off,
color: Colors.white,
)
: const Icon(Icons.flash_on, color: Colors.white);
},
),
),
),
GestureDetector(
onTap: () async {
await controller?.flipCamera();
setState(() {});
},
child: Container(
margin: const EdgeInsets.all(8),
child: FutureBuilder(
future: controller?.getCameraInfo(),
builder: (context, snapshot) {
if (snapshot.data != null) {
return const Icon(Icons.cameraswitch_rounded,
color: Colors.white);
} else {
return const SizedBox();
}
},
),
),
)
],
),
],
)
],
),
);
}
Widget _buildQrView(BuildContext context) {
var scanArea = (Get.width < 400 || Get.height < 400) ? 230.0 : 330.0;
return QRView(
key: qrKey,
onQRViewCreated: _onQRViewCreated,
overlay: QrScannerOverlayShape(
borderColor: buttonColor,
borderRadius: 2,
borderLength: 35,
borderWidth: 6,
cutOutSize: scanArea),
onPermissionSet: (ctrl, p) => _onPermissionSet(context, ctrl, p),
);
}
void _onQRViewCreated(QRViewController controller) {
setState(() {
this.controller = controller;
});
controller.scannedDataStream.listen((scanData) {
if (scanData != null) {
setState(() {
result = scanData;
});
Get.find<QRService>().updateResult(scanData.code);
// Get.defaultDialog(
// content: Text("${scanData.code}"),
// );
Get.back();
// Get.offAll(() => const QRmainScreen());
}
});
}
void _onPermissionSet(BuildContext context, QRViewController ctrl, bool p) {
log('${DateTime.now().toIso8601String()}_onPermissionSet $p');
if (!p) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('no Permission')),
);
}
}
#override
void dispose() {
controller?.dispose();
super.dispose();
}
}
Remove resume camera from init state
#override
void initState() {
super.initState();
//controller?.resumeCamera();
}

How can i use a variable from another ambit into a child Widget?

Hello I have a problem when I want to use the List variable that stores the IDs of a database in Firebase. I would like to use it in the "Row" widget where I create a DropDownButton, it only allows me to do it if the instance is out of scope. How can i use this variable inside Row?
Main.dart
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
Firebase.initializeApp();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Material App',
// home: const CardScreen(),
initialRoute: AppRoutes.initialRoute,
routes: AppRoutes.routes,
onGenerateRoute: AppRoutes.onGenerateRoute);
}
}
Form1_screen.dart
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class FormularioScreen extends StatefulWidget {
const FormularioScreen({Key? key}) : super(key: key);
#override
State<FormularioScreen> createState() => _FormularioScreenState();
}
class _FormularioScreenState extends State<FormularioScreen> {
_FormularioScreenState();
// ignore: prefer_typing_uninitialized_variables
var selecCurrency;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(
'PET-SOS PERRO',
style: TextStyle(color: Colors.black54),
),
iconTheme: const IconThemeData(
color: Colors.black, //change your color here
),
backgroundColor: Colors.white,
),
body: Column(
children: [
StreamBuilder(
stream: FirebaseFirestore.instance.collection('Razas').snapshots(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return const Text('Loading');
} else {
List<DropdownMenuItem> currencyItems = [];
for (int i = 0; i < snapshot.data.docs.length; i++) {
DocumentSnapshot snap = snapshot.data.docs[i];
currencyItems.add(
DropdownMenuItem(
child: Text(
snap.id,
),
value: snap.id,
),
);
}
}
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
DropdownButton<dynamic>(
items: currencyItems,
onChanged: (currencyValue) {
var snackBar = SnackBar(
content: Text('Se seleccionó $currencyValue'));
// ignore: deprecated_member_use
Scaffold.of(context).showSnackBar(snackBar);
setState(() {
selecCurrency = currencyValue;
});
},
value: selecCurrency,
hint: const Text('Seleccione una raza.')),
],
);
},
),
StreamBuilder(
stream: FirebaseFirestore.instance.collection('Peso').snapshots(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return const Text('Loading');
} else {
List<DropdownMenuItem> currencyItems = [];
for (int i = 0; i < snapshot.data.docs.length; i++) {
DocumentSnapshot snap = snapshot.data.docs[i];
currencyItems.add(
DropdownMenuItem(
child: Text(
snap.id,
),
value: snap.id,
),
);
}
}
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
DropdownButton<dynamic>(
items: currencyItems,
onChanged: (currencyValue) {
var snackBar = SnackBar(
content: Text('Se seleccionó $currencyValue'));
// ignore: deprecated_member_use
Scaffold.of(context).showSnackBar(snackBar);
setState(() {
selecCurrency = currencyValue;
});
},
value: selecCurrency,
hint: const Text('Seleccione un peso.')),
],
);
},
),
StreamBuilder(
stream: FirebaseFirestore.instance.collection('Edad').snapshots(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return const Text('Loading');
} else {
List<DropdownMenuItem> currencyItems = [];
for (int i = 0; i < snapshot.data.docs.length; i++) {
DocumentSnapshot snap = snapshot.data.docs[i];
currencyItems.add(
DropdownMenuItem(
child: Text(
snap.id,
),
value: snap.id,
),
);
}
}
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
DropdownButton<dynamic>(
items: currencyItems,
onChanged: (currencyValue) {
var snackBar = SnackBar(
content: Text('Se seleccionó $currencyValue'));
// ignore: deprecated_member_use
Scaffold.of(context).showSnackBar(snackBar);
setState(() {
selecCurrency = currencyValue;
});
},
value: selecCurrency,
hint: const Text('Seleccione una edad.')),
],
);
},
),
],
),
);
}
}
Basically the variable isn't define because it's outsite of the ambit.
move the list definition before the scaffold
class _FormularioScreenState extends State<FormularioScreen> {
_FormularioScreenState();
// ignore: prefer_typing_uninitialized_variables
var selecCurrency;
#override
Widget build(BuildContext context) {
List<DropdownMenuItem> currencyItems = []; // <= ADD
return Scaffold(
appBar: AppBar(
title: const Text(
'PET-SOS PERRO',
style: TextStyle(color: Colors.black54),
),
iconTheme: const IconThemeData(
color: Colors.black, //change your color here
),
backgroundColor: Colors.white,
),
body: Column(
children: [
StreamBuilder(
stream:
FirebaseFirestore.instance.collection('Razas').snapshots(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return const Text('Loading');
} else {
List<DropdownMenuItem> currencyItems = []; // <= REMOVE
for (int i = 0; i < snapshot.data.docs.length; i++) {

How can I change a background screen with a photo fetched from api in flutter?

I'm fetching images from https://pixabay.com/api/docs/ this web-page.
I'm trying to save that image with onTap() {} with Shared Preferences package and set as background on previous page. I tried to make Shared preferences class seperate but it was showing errors. So pref.setString() method I did in ontap() {} and pref.getString() in my Center() widget with ternary operator to show that if image url is empty, write text, if it contains image url, show image. I tried to put it into setState() {} method but there are all red squiggles. How can I achieve this?
Thank you very much in advance.
Here is my code:
this is the page I'm trying to set background image:
import 'package:abcde/authentication_screen/pages/photos_page.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class AfterAuth extends StatefulWidget {
AfterAuth({Key? key}) : super(key: key);
static const String pathId = 'Welcome Page';
#override
State<AfterAuth> createState() => _AfterAuthState();
}
class _AfterAuthState extends State<AfterAuth> {
String welcomeScreen = 'Welcome to the club';
#override
void initState() {
// TODO: implement initState
super.initState();
//final prefs = await SharedPreferences.getInstance();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Welcome'),
),
drawer: Drawer(
backgroundColor: Colors.white,
child: ListView(
padding: EdgeInsets.zero,
children: [
const DrawerHeader(
decoration: BoxDecoration(
color: Colors.lightBlueAccent,
),
child: Text('Welcome'),
),
ListTile(
title: const Text(
'Bonjour',
),
onTap: () {
setState(() {
welcomeScreen = 'Bonjour';
});
Navigator.pop(context);
},
),
ListTile(
title: const Text('Hello'),
onTap: () {
setState(() {
welcomeScreen = 'Hello';
});
Navigator.pop(context);
},
),
ListTile(
title: const Text('Guten Tag'),
onTap: () {
setState(() {
welcomeScreen = 'Guten Tag';
});
Navigator.pop(context);
},
),
ListTile(
title: const Text('Au Revoir'),
onTap: () {
setState(() {
welcomeScreen = 'Au Revoir';
});
Navigator.pop(context);
},
),
ListTile(
title: const Text('Chao Bambino'),
onTap: () {
setState(() {
welcomeScreen = 'Chao Bambino';
});
Navigator.pop(context);
},
),
],
),
),
body: Center(
child: address == ''
? Text(welcomeScreen)
: Image(
image: NetworkImage(address),
),
),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.lightBlue,
onPressed: () {
Navigator.pushNamed(context, PhotosPage.pathId);
},
child: const Icon(
Icons.add,
color: Colors.white,
),
),
);
}
String address = '';
internalMemory() async {
final prefs = await SharedPreferences.getInstance();
address = prefs.getString('urlAddress')!;
/* if(address!.isNotEmpty) {
isAddressEmpty = false;
}*/
return address;
}
}
this is the page where I fetch images from api and trying to save with Shared Preferences. actually not sure if it saves and not sure how to check it:
import 'package:flutter/material.dart';
import '../../services/photos_service.dart';
import 'package:shared_preferences/shared_preferences.dart';
class PhotosPage extends StatefulWidget {
const PhotosPage({Key? key}) : super(key: key);
static const String pathId = 'Photos page';
#override
State<PhotosPage> createState() => _PhotosPageState();
}
class _PhotosPageState extends State<PhotosPage> {
PhotosService photosService = PhotosService();
#override
void initState() {
super.initState();
photosService.getPhotos();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Photos'),
),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(children: [
_getProductTypeList(),
]),
),
);
}
Widget _buildListItem(
BuildContext context, AsyncSnapshot<dynamic> snapshot, int index) {
final photoItem = snapshot.data[index].previewURL;
print('photoItem is $photoItem');
return photoCard(context, photoItem);
}
Widget _buildList(BuildContext context, AsyncSnapshot<dynamic> snapshot) {
var values = snapshot.data;
return ListView.builder(
itemCount: snapshot.hasData ? snapshot.data.length : 0,
itemBuilder: (context, index) {
return _buildListItem(context, snapshot, index);
},
);
}
Widget _getProductTypeList() {
return Expanded(
child: FutureBuilder(
future: photosService.getPhotos(),
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: LinearProgressIndicator(),
);
}
return _buildList(context, snapshot);
},
),
);
}
}
Widget photoCard(BuildContext context, String url) {
return GestureDetector(
onTap: () async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString('urlAddress', url);
const snackBar =
SnackBar(content: Text('You saved image'));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
},
child: Card(
child: Image(
image: NetworkImage(url),
),
),
);
}
this is my service/model
import 'dart:convert';
import 'package:http/http.dart';
const apiKey = '26711456-bde74f403cb42e77029bc1678';
const appUrl = 'https://pixabay.com/api/';
class PhotosService {
Future getData(String url) async {
print('Calling url: $url');
final response = await get(Uri.parse(url));
if (response.statusCode == 200) {
return response.body;
} else {
print(response.statusCode);
}
}
String? query;
List<PhotosModel> dataList = [];
Future<List<PhotosModel>> getPhotos() async {
final photosData = await getData('$appUrl?key=$apiKey&q=$query');
var data = json.decode(photosData);
var items = data["hits"];
items.forEach((element) {
dataList.add(PhotosModel.fromJson(element));
});
print('this is photos data: $photosData');
return dataList;
}
}
class PhotosModel {
String previewURL;
PhotosModel({required this.previewURL});
factory PhotosModel.fromJson(Map<dynamic, dynamic> json) =>
_commentFromJson(json);
Map<dynamic, dynamic> toJson() => photosModelToJson(this);
}
PhotosModel _commentFromJson(Map<dynamic, dynamic> json) {
return PhotosModel(
previewURL: json['previewURL'],
);
}
Map<dynamic, dynamic> photosModelToJson(PhotosModel instance) =>
<dynamic, dynamic>{
'previewURL': instance.previewURL,
};
Call your function on initState to set the background on restart the app.
#override
void initState() {
// TODO: implement initState
super.initState();
internalMemory();
//final prefs = await SharedPreferences.getInstance();
}
add setstate to your internalMemory() function to set background
internalMemory() async {
final prefs = await SharedPreferences.getInstance();
address = await prefs.getString('urlAddress')!;
setState((){});
}
also, add the function below to set the background when you navigate back.
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.lightBlue,
onPressed: () async {
await Navigator.pushNamed(context, PhotosPage.pathId);
internalMemory();
},
child: const Icon(
Icons.add,
color: Colors.white,
),
),

Flutter: 'Future<dynamic>' is not a subtype of type 'String'

I'm trying to build a URL shortner using the following api: https://shrtco.de/docs/. I parsed the JSON file and tried to rebuild the listview. But after adding the url I'm getting the above error. The api seems to be working fine when I print it though. I don't know whats wrong. I'm a beginner in Flutter and Dart. Please help me.
class _homePageState extends State<homePage> {
getdata(String userUrl) async {
//JSON Parser
var url = 'https://api.shrtco.de/v2/shorten?url=$userUrl';
var respons = await http.get(url);
var result = jsonDecode(respons.body);
var shortlink = result['result']['short_link']; //dictionary parse
print(shortlink);
return shortlink;
}
Future<String> createAlertDialog(BuildContext context) {
//method for alertdialog
//promise to return string
TextEditingController customController =
TextEditingController(); //new texteditingc object
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text("Enter URL: "),
content: TextField(
controller: customController,
),
actions: [
MaterialButton(
elevation: 5.0,
child: Text("OK"),
onPressed: () {
if (customController.text != null &&
customController.text != "") {
var getShortlink = getdata(customController.text);
item.add(getShortlink);
}
setState(() {});
Navigator.of(context).pop();
},
)
],
);
});
}
#override
Widget build(BuildContext context) {
String temp;
return Scaffold(
appBar: AppBar(
title: Text("Shortie"),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: ListView.builder(
itemCount: item.length,
itemBuilder: (context, index) {
return ListTile(
leading: Icon(Icons.link),
title: Text(item[index]),
subtitle: Text("data"),
);
//return new Text();
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
createAlertDialog(context).then((onValue) {
temp = onValue;
print(temp);
});
},
You can copy paste run full code below
Step 1: getdata return Future<String>
Step 2: onPressed need async await
Step 3: put getShortlink in Navigator.of(context).pop(getShortlink);
code snippet
Future<String> getdata(String userUrl) async {
...
onPressed: () async {
String getShortlink;
if (customController.text != null &&
customController.text != "") {
getShortlink = await getdata(customController.text);
item.add(getShortlink);
}
setState(() {});
Navigator.of(context).pop(getShortlink);
},
working demo
full code
import 'dart:convert';
import 'package:http/http.dart' as http;
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 _MyHomePageState extends State<MyHomePage> {
List<String> item = [];
Future<String> getdata(String userUrl) async {
//JSON Parser
var url = 'https://api.shrtco.de/v2/shorten?url=$userUrl';
var respons = await http.get(url);
var result = jsonDecode(respons.body);
var shortlink = result['result']['short_link']; //dictionary parse
print(shortlink);
return shortlink;
}
Future<String> createAlertDialog(BuildContext context) {
//method for alertdialog
//promise to return string
TextEditingController customController =
TextEditingController(text: "example.org/very/long/link.html"); //new texteditingc object
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text("Enter URL: "),
content: TextField(
controller: customController,
),
actions: [
MaterialButton(
elevation: 5.0,
child: Text("OK"),
onPressed: () async {
String getShortlink;
if (customController.text != null &&
customController.text != "") {
getShortlink = await getdata(customController.text);
item.add(getShortlink);
}
setState(() {});
Navigator.of(context).pop(getShortlink);
},
)
],
);
});
}
#override
Widget build(BuildContext context) {
String temp;
return Scaffold(
appBar: AppBar(
title: Text("Shortie"),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: ListView.builder(
itemCount: item.length,
itemBuilder: (context, index) {
return ListTile(
leading: Icon(Icons.link),
title: Text(item[index]),
subtitle: Text("data"),
);
//return new Text();
},
),
),
floatingActionButton: FloatingActionButton(onPressed: () {
createAlertDialog(context).then((onValue) {
temp = onValue;
print(temp);
});
}));
}
}
createAlertDialog(BuildContext context) doesn't return a Future<String>, it's returns Future<T>, dynamic in your case.
https://api.flutter.dev/flutter/material/showDialog.html

Categories

Resources