The context is we have a TextFormField and ElevatedButton. I entered the URL of the video (usually format mp4) and pressed Button. Bellow them will show videos are scraped from this URL. I think I should use the package video_player. However, in the example code, it required an initial URL on initState (or onInit if using the GetX package). How to make the URL dynamic and only show after entering the URL?
class CyberDropController extends GetxController with StateMixin<List> {
final dataCyberDrop = DataCyberDrop();
late VideoPlayerController videoController;
var url = ''.obs;
#override
void onInit() {
super.onInit();
playVideo(url.value);
change(null, status: RxStatus.empty());
}
Future<void> playVideo(String url) async {
videoController = VideoPlayerController.network(url);
await videoController.initialize();
await videoController.setLooping(true);
await videoController.play();
update();
}
void fetch({String? link}) async {
change(null, status: RxStatus.loading());
try {
var data = await dataCyberDrop.scraperCyberDrop(link: link);
change(data, status: RxStatus.success());
} catch (e) {
change(null, status: RxStatus.error(e.toString()));
}
}
}
Views:
controller.obx(
(state) => Column(
children: state!
.map(
(e) => e!.toString().contains('.mp4')
? AspectRatio(
aspectRatio: controller
.videoController.value.aspectRatio,
child: VideoPlayer(controller.videoController),
)
: Image.network(e),
)
.toList(),
since you said that you're working with TextFormField, you can use the onChanged property to execute your methods just after you set the URL:
TextFormField(
onChanged: (urlValue) async{
if(/* recommended to set a condition on URL where it shouldn't execute anything*/) {
return;
}
await controller.playVideo(urlValue);
}
)
Related
I was Learning Async and Future Functions in Dart but I got confused because I still not get it like how print("object") is compiled before getData() function because traditionally next Line is read by compiler once the before line or Function is fully compiled/Executed . If I am making a Mistake Please correct me out , I am noob tbh
import 'package:flutter/material.dart';
class Loading extends StatefulWidget {
const Loading({super.key});
#override
State\<Loading\> createState() =\> \_LoadingState();
}
class \_LoadingState extends State\<Loading\> {
void getdata() async {
String parth = await Future.delayed(Duration(seconds: 3), () {
return 'parth';
});
print('Hey');
print(parth);
}
#override
int count = 0;
void initState() {
// TODO: implement initState
super.initState();
getdata();
print('object');
}
#override
Widget build(BuildContext context) {
// print(' Setstae vala + $count');
return Scaffold(
appBar: AppBar(
title: Text('Loading'),
),
body: ElevatedButton(
onPressed: () {
setState(() {
count++;
});
},
child: Text('$count')),
);
}
}
Your output should be like this:
object
Hey
parth
because traditionally next Line is read by compiler once the before
line or Function is fully compiled/Executed
Normaly, yes. But since you are using the async keyword in this case, it works a little differently.
What happens here:
You call getData first in your initState. In getData you have a future delayed in it, which you wait for with keywoard await. So it waits 3 seconds until you return 'parth' as a string. At the same time, however, it continues to run in your initState to return 'object'.
getdata is a async method, you need to return Future<void> to await.
Now the initState() cant be async, you can create another method to await and place it here.
void newMethod() async {
await getdata();
print('object');
}
And place newMethod() inside initState.
Or you can use .then
getdata().then((_) {
print('object');
});
I am working with APIs and using a delete method to delete an item with a unique id from a list. The delete method is working but I need to reload the page everytime I want to see the results. I tried to add a setState() function inside a button and call the delete method from there but it is not working. I am not getting any errors however.
Delete method:
Future <void> deleteData(todo) async {
var urlToUpdate = Uri.parse('https://todoapp-api.apps.k8s.gu.se/todos/${todo.id}?key=${testKey}');
try {
await http.delete(urlToUpdate, headers: {"Content-Type": "application/json"}, body: jsonEncode({
"id": todo.id,
"title": todo.title,
"done": todo.done
}));
} catch (err) {
print(err);
}
}
setState method:
child: IconButton(
onPressed: () {
setState(() {
var deleteTodo = TodoItem(id: id, title: '', done: false);
deleteData(deleteTodo);
});
},
I can't provide the whole code because it is too large but the delete method comes right after :
class _TodoListState extends State {
and before initState and Widget build.
My TodoItemsList works like this:
Future fetchPosts() async {
try {
await getKey();
final response = await HTTP.get(Uri.parse('${url}${todos}${testKey}'));
final jsonData = jsonDecode(response.body);
setState(() {
TodoItemsList = jsonData;
});
print(jsonData);
} catch (err) {
print('Error');
}
}
This empty list is just above the Widget build
List TodoItemsList = [];
This widget is inside by body property:
Widget getBody() {
return ListView.builder(
itemCount: TodoItemsList.length,
itemBuilder: (context, index) {
return getCard(TodoItemsList[index]);
});
}
you should wait until the deleteData finished.
After that, remove the local TodoItem from the list by yourself.
child: IconButton(
onPressed: () async {
var deleteTodo = TodoItem(id: id, title: '', done: false);
await deleteData(deleteTodo);
setState(() {
=> remove TodoItem from the local list =<
});
}
Because network request usually takes times. You should display something like CircularProgressIndicator when deleteData is running. But that's another story.
setState method is used to reflect any change of data over some widget, if you need to remove a element from a list need has that element linked to a widget
example:
If you has
listOfMovie = ['Avatar, Avengers', 'Dune', 'Hulk'];
ListView.builder(
itemCount: listOfMovie.length,
itemBuilder: (_, index) => Text(listOfMovie[index],
));
then
child: IconButton(
onPressed: () {
setState(() {
listOfMovie = ['Avatar, Avengers'];
});
},
If you notice listOfMovie is linked to ListView widget
I am making an bungalow reservation system with spring rest back end and flutter front end.
In this I want to get a list of bungalows.
So I decided to make a method to get the list of bungalows in a method using HttpService class that I made to handle the rest end points, That method is getBungalows() method.
Then I called this method by overriding initstate().
But the problem is that before my initstate() is completed. my build method starts.
To prove this I printed two lines 'print' and 'print build' as I thought I get 'print build' first. what am I doing wrong here. Please help.
Method to retrieve data from rest back end
When this happened I first checked this method but this works fine and return the desired result.
Future<List<Bungalow>> getBungalows() async {
Uri uri = Uri.parse('$url/bungalows/');
http.Response response = await http.get(uri);
if (response.statusCode == 200) {
List<Bungalow> bungalows = List<Bungalow>.from(
json.decode(response.body).map((x) => Bungalow.fromJson(x)));
// print(bungalows.first.address + 'asafafasfafdfgfgarfgargafvfrvaerg');
return bungalows;
} else {
throw 'Unable to retrieve data';
}
}
Code of the HomeScreen
class _HomeScreenState extends State<HomeScreen> {
HttpService httpService = HttpService();
late List<Bungalow> bungalows;
bool isLoggedIn = false;
User? user;
void getBungalows() async {
bungalows = await httpService.getBungalows();
print('done');
}
#override
Widget build(BuildContext context) {
if (widget.user != null) {
isLoggedIn = true;
user = widget.user;
}
print('done build');
return Scaffold(
backgroundColor: Colors.white,
body: Column(
children: [
Text(isLoggedIn ? user!.userDetail.username : 'No login'),
// TextButton(
// onPressed: () {
// setState(() {
// getBungalows();
// print(bungalows.first.address);
// });
// },
// child: Text('click'))
],
),
);
}
#override
void initState() {
getBungalows();
}
}
Console Output
I/flutter (22248): done build
I/flutter (22248): done
It is behaving correctly, initState function is not async and method getBungalows() is called in parallel.
You should either use setState in getBungalows, or add a listener, or use the then keyword, or use StreamBuilder.
Check this: https://stackoverflow.com/a/54647682/305135
I have a function that is supposed to fetch me a list of Restaurants objects from firestore based on location.
the function does its job perfectly when i first run the app but after using the app from another device and updating resturants data in firestore documents, i somehow get duplicates of the restaurants list items.
here is the code for the function that fetch the the restaurants objects list:
Future<void> fetchRestaurantsList() async {
try {
Position position = await Geolocator().getCurrentPosition(
desiredAccuracy:
Platform.isIOS ? LocationAccuracy.lowest : LocationAccuracy.high);
final dbRestaurant = firestore
.collection('testing')
.document('users')
.collection('restaurant');
geo.collection(collectionRef: dbRestaurant)
.within(
center: GeoFirePoint(
position.latitude,
position.longitude
),
radius: 45.0,
field: 'resturantLocation')
.listen((event) {
restaurantList.clear();
await event.forEach((element){
final distance = Distance.getDistanceFromLatLonInKm( // calculating distance for each restaurant
position.latitude,
position.longitude,
element.data['location']['geopoint'].latitude,
element.data['location']['geopoint'].longitude)
restaurantList.add(Restaurant(
id: element.documentID,
logo: element.data['logo'],
name: element.data['name'],
distance: distance ,
));
notifyListeners();
});
});
} catch (e) {
print(e.toString());
}
} finally {
notifyListeners();
}
}
and this is the page that contains the list: (its under a parent widget which contains other tabs)
class RestruntsListTab extends StatefulWidget {
final MainModel model;
RestruntsListTab({#required this.model});
#override
State<StatefulWidget> createState() {
return _RestruntsListTabState();
}
}
class _RestruntsListTabState extends State<RestruntsListTab>
#override
void initState() {
widget.model.fetchRestaurantsList();
widget.model.checkLocationService().then((isActive) {
if (isActive) {
} else {
Scaffold.of(context).showSnackBar(SnackBar(
content: Text(
language.enableLcation,
style: TextStyle(
fontFamily: 'eff', fontSize: 18, fontWeight: FontWeight.bold),
),
backgroundColor: Colors.grey,
));
}
});
super.initState();
}
#override
Widget build(BuildContext context) {
return ScopedModelDescendant<MainModel>(
builder: (context, child, model) {
return ListView.builder(
itemCount:model.restaurantList.length,
itemBuilder: (context,index) {
return Row(
children: <Widget>[
Text(model.restaurantList[index].name),
Text(model.restaurantList[index].distance),
],
)
}
);
})
}
}
this is a simplified code for demonstration but the actual code is pretty similar.
if you have encountered similar issues kindly share your experience.
thank you all.
check that fetchRestaurantsList() method is not called on widget build
or it is in StreamBuilder method...it's because .listen((event) { this method it is like a stream so you have to use flag like bool variable to run the code inside it
if(mybool==false){// the other code goes.... setStste({mybool=true;})}
in this way it only excute the code once
There might be something wrong with the code, but I don't see it. What you can try doing is wrapping the content of forEach with
if(restaurantList.where((item) => item.id == element.documentID).isEmpty){
}
That should filter out duplicates.
I am unable to find the solution of setting asset image as wallpaper in android, while i am doing everything right as documented in official flutter document ion, in below image Set As Wallpaper button uses Method channel and use native code in java activity but could not set this image as wallpaper from java activity. Please guide.
This image loaded from local assets folder in flutter
You can use package https://pub.dev/packages/wallpaper_manager
You can set wallpaper in Home screen or Lock screen
wall paper can from a File or Asset
code snippet
Future<void> setWallpaperFromAsset() async {
setState(() {
_wallpaperAsset = "Loading";
});
String result;
String assetPath = "assets/tmp1.jpg";
// Platform messages may fail, so we use a try/catch PlatformException.
try {
result = await WallpaperManager.setWallpaperFromAsset(
assetPath, WallpaperManager.HOME_SCREEN);
} on PlatformException {
result = 'Failed to get wallpaper.';
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_wallpaperAsset = result;
});
}
working demo
full code
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:wallpaper_manager/wallpaper_manager.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _platformVersion = 'Unknown';
String _wallpaperFile = 'Unknown';
String _wallpaperAsset = 'Unknown';
#override
void initState() {
super.initState();
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
String platformVersion;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
platformVersion = await WallpaperManager.platformVersion;
} on PlatformException {
platformVersion = 'Failed to get platform version.';
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_platformVersion = platformVersion;
});
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> setWallpaperFromFile() async {
setState(() {
_wallpaperFile = "Loading";
});
String result;
var file = await DefaultCacheManager().getSingleFile(
'https://images.unsplash.com/photo-1542435503-956c469947f6');
// Platform messages may fail, so we use a try/catch PlatformException.
try {
result = await WallpaperManager.setWallpaperFromFile(
file.path, WallpaperManager.HOME_SCREEN);
} on PlatformException {
result = 'Failed to get wallpaper.';
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_wallpaperFile = result;
});
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> setWallpaperFromAsset() async {
setState(() {
_wallpaperAsset = "Loading";
});
String result;
String assetPath = "assets/tmp1.jpg";
// Platform messages may fail, so we use a try/catch PlatformException.
try {
result = await WallpaperManager.setWallpaperFromAsset(
assetPath, WallpaperManager.HOME_SCREEN);
} on PlatformException {
result = 'Failed to get wallpaper.';
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_wallpaperAsset = result;
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Column(
children: <Widget>[
RaisedButton(
child: Text("Platform Version"),
onPressed: initPlatformState,
),
Center(
child: Text('Running on: $_platformVersion\n'),
),
RaisedButton(
child: Text("Set wallpaper from file"),
onPressed: setWallpaperFromFile,
),
Center(
child: Text('Wallpaper status: $_wallpaperFile\n'),
),
RaisedButton(
child: Text("Set wallpaper from asset"),
onPressed: setWallpaperFromAsset,
),
Center(
child: Text('Wallpaper status: $_wallpaperAsset\n'),
),
],
)),
);
}
}