problems with video player flutter - flutter

I'm new in Flutter and try to load video from api, but video player is not working correctly. I have PageView in my Widget _buildFilmsMainPages() and each Page will get own video from api.
i'm getting error while data is loading: The following NoSuchMethodError was thrown building FutureBuilder>(dirty, state: _FutureBuilderState>#033d3):
The method '[]' was called on null.
Receiver: null
Tried calling:
After loading this error is gone.
when i tap on play (Floating Action Button) i see only first frame of video but sound is working.
when i tap on stop (Floating Action Button) first frame of video is gone but sound is still working.
class HomePage extends StatefulWidget {
HomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_ HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
VideoPlayerController _controller;
Future<void> _initializeVideoPlayerFuture;
bool isVideo = false;
int filmIndex = 0;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold (
body: SingleChildScrollView(
child: _buildFilmsMainPages(),
)
);
}
Widget _buildFilmsMainPages() =>
FutureBuilder(
future:getMoviesListByDay(date))),
builder: (BuildContext context, AsyncSnapshot snapshot) {
without this code i get error, but player isn't working
correctly anyway and i'm getting error while data is loading
_controller= VideoPlayerController.network
(snapshot.data[filmIndex].media!=null?
snapshot.data[filmIndex].media.elementAt(1)
:"https://flutter.github.io/assets-for-api-
docs/assets/videos/butterfly.mp4");
_initializeVideoPlayerFuture =_controller.initialize();
_controller.setLooping(true);
if (snapshot.data != null) {
return
Column(
children:<Widget> [
SizedBox(
height: 460.0,
child: PageView.builder(
pageSnapping: true,
itemCount: snapshot.data.length,
onPageChanged: (int index) {
setState(() {
filmIndex = index;
i thought i should write this code here
_controller = VideoPlayerController.network
(snapshot.data[filmIndex].media!=null?
snapshot.data[filmIndex].media.elementAt(1)
:"https://flutter.github.io/assets-for-api-
docs/assets/videos/butterfly.mp4");
_initializeVideoPlayerFuture =
_controller.initialize();
_controller.setLooping(true);
});
},
itemBuilder: (context, index) {
return Column(
children: <Widget>[
Container(margin: const
EdgeInsets.symmetric(horizontal: 16.0),
child: ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: Container(
height: 250.0,
child: Stack(children: <Widget>[
Container(
child: GestureDetector(
child: isVideo ?
FutureBuilder(
future:_initializeVideoPlayerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState ==
ConnectionState.done) {
return AspectRatio(
aspectRatio: 16.0 / 12.0,
child:VideoPlayer(_controller),
);
} else {
return Center(
child:
CircularProgressIndicator());
}
},
) :
FadeInImage.assetNetwork(
placeholder:
"assets/placeholder.jpg",
image:
snapshot.data[index].media!=null
? snapshot.data[index].media.elementAt(0): "",
fit: BoxFit.fill,
fadeInDuration:Duration(milliseconds: 50),
),
onTap: () =>
)
),
)
)
),
Row(children: <Widget>[
Container(
margin: const EdgeInsets.only(left: 16.0,
right: 16.0, top: 190.0),
height: 40.0,
width: 40.0,
child: FittedBox(
child: FloatingActionButton(
backgroundColor: Colors.white,
foregroundColor: Colors.black,
onPressed: () {
setState(() {
isVideo = !isVideo;
if (_controller.value.isPlaying) {
_controller.pause();
} else {
_controller.play();
}
});
},
child: Icon(_controller.value.isPlaying
? Icons.pause : LineIcons.play,
size: 30.0,)
),
)
);

Related

Exception caught by widgets library Incorrect use of ParentDataWidget

When I am trying to display the data present in firebase realtime database. I am getting the error stating Exception caught by widgets library Incorrect use of ParentDataWidget.
class NotificationView extends StatefulWidget {
const NotificationView({Key key}) : super(key: key);
#override
State<NotificationView> createState() => _NotificationViewState();
}
class _NotificationViewState extends State<NotificationView> {
Map data;
List key;
#override
void initState() {
fetchData();
super.initState();
}
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Scaffold(
backgroundColor: Colors.white,
body: Container(
child: FutureBuilder(
future: fetchData(),
builder: (context, snapshot) {
if (data != null) {
return ListView.builder(
itemCount: data.values.length,
itemBuilder: (BuildContext context, int index) {
return Container(
height: 100,
child: Card(
margin: EdgeInsets.fromLTRB(15, 5, 15, 15),
color: Colors.yellow[100],
elevation: 10,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
child: Container(
margin: EdgeInsets.fromLTRB(15, 5, 15, 15),
child: Expanded(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(data[key[index]]['title']),
SizedBox(height: size.height * 0.01),
Text(data[key[index]]['message']),
],
),
),
),
),
);
});
} else {
return Center(child: CircularProgressIndicator());
}
})));
}
fetchData() async {
var userId = SharedUtils.getString('UserId');
final ref = FirebaseDatabase.instance.ref();
final snapshot =
await ref.child('users/62cfc3faf3e5df6648d32684/inApp').get();
debugPrint(snapshot.key + 'KEyyyyyyyyyyyyyyyyyyyyy');
data = snapshot.value;
key = data.keys.toList();
debugPrint(
'Listttttttttttttttofffffffffffkeyyyyyyyyyyyyyy&&&77' + key.toString());
}
}
You are using "Expanded" as the child of the container which is wrong. Be aware that, you can use the "Expanded" widget only as the child of columns, rows, and flex. That's why you are getting this "Incorrect use of ParentDataWidget".
More details for Expanded widget.

how to implement refresh indicator in flutter

'''
I wanted to implement refresh indicator to reload data's from Api(Json). below code runs well but
pull down to refresh is not working. i tried to get the data's initially using initState and then view the data's using future builder. how can i achieve the refresh indicator to reload data's. what is missing from my code?
import 'package:flutter/material.dart';
import '../networkhelper/property.dart';
import '../widgets/recommended.dart';
import '../model/property.dart';
import '../shimmer/recommended.dart';
import '../widgets/home_top.dart';
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
#override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
late Future<List<PropertyModel>> _propertyData;
#override
void initState() {
_propertyData = PropertyApi.getProperty();
super.initState();
}
Future<void> _refreshData() async {
setState(() {
_propertyData = PropertyApi.getProperty();
});
await _propertyData;
}
#override
Widget build(BuildContext context) {
Size _screenSize = MediaQuery.of(context).size;
return Scaffold(
backgroundColor: Colors.blue,
body: RefreshIndicator(
onRefresh: () => _refreshData(),
child: ListView(children: [
HomeTopView(),
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(8),
topRight: Radius.circular(8),
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: _screenSize.height * 0.02),
Padding(
padding: EdgeInsets.only(left: _screenSize.width * 0.04),
child: Text(
"Recommanded",
style: TextStyle(
fontSize: _screenSize.width * 0.055,
color: Colors.blue,
fontWeight: FontWeight.bold,
),
),
),
SizedBox(height: _screenSize.height * 0.01),
SizedBox(
height: _screenSize.height * 0.3,
child: FutureBuilder<List<PropertyModel>>(
future: _propertyData,
builder: (context, snapshot) {
if (snapshot.hasData) {
List<PropertyModel>? data = snapshot.data;
return ListView.builder(
shrinkWrap: true,
padding: EdgeInsets.only(
left: _screenSize.width * 0.015),
scrollDirection: Axis.horizontal,
physics: const BouncingScrollPhysics(),
itemCount: data!.length,
itemBuilder: (context, index) {
return RecommendedItems(
id: data[index].id,
propertyName: data[index].name,
price: data[index].price,
imgUrl: data[index].img[2],
bedRoomQuantity: data[index].details.bedroom,
bathRoomQuantity: data[index].details.bathroom,
propertyArea: data[index].details.area,
address: data[index].address.city,
propertyType: data[index].details.propertytype,
);
},
);
} else if (snapshot.hasError) {
return Center(
child:
Text("Please Check Your Internet Connection"),
);
}
// By default show a loading spinner.
return ListView.builder(
itemCount: 4,
shrinkWrap: true,
padding: const EdgeInsets.only(left: 10),
scrollDirection: Axis.horizontal,
physics: const BouncingScrollPhysics(),
itemBuilder: (ctx, index) {
return RecommendedShimmer();
});
},
),
),
]),
),
// ),
]),
),
);
}
}
'''
Try changing your setState() method to this:
setState(() async {
_propertyData = await PropertyApi.getProperty();
});
Try this :
Future<void> _refreshData() async {
_propertyData = PropertyApi.getProperty();
setState(() {});
return;
}
This code works smoothly.
Future<void> _refreshData() async {
_propertyData = PropertyApi.getProperty();
await _propertyData;
setState(() {});
}

Flutter Cubit fetching and displaying data

I'm trying to fetch data from Genshin API, code below is working, but only with delay (in GenshinCubit class), it looks weard, because I don't know how much time to set for delay. I think, there is a problem in code, cause it must not set the GenshinLoaded state before the loadedList is completed. Now, if I remove the delay, it just sets the GenshinLoaded when the list is still in work and not completed, await doesn't help. Because of that I get a white screen and need to hot reload for my list to display.
class Repository {
final String characters = 'https://api.genshin.dev/characters/';
Future<List<Character>> getCharactersList() async {
List<Character> charactersList = [];
List<String> links = [];
final response = await http.get(Uri.parse(characters));```
List<dynamic> json = jsonDecode(response.body);
json.forEach((element) {
links.add('$characters$element');
});
links.forEach((element) async {
final response2 = await http.get(Uri.parse(element));
dynamic json2 = jsonDecode(response2.body);
charactersList.add(Character.fromJson(json2));
});
return charactersList;
}
}
class GenshinCubit extends Cubit<GenshinState> {
final Repository repository;
GenshinCubit(this.repository) : super(GenshinInitial(),);
getCharacters() async {
try {
emit(GenshinLoading());
List<Character> list = await repository.getCharactersList();
await Future<void>.delayed(const Duration(milliseconds: 1000));
emit(GenshinLoaded(loadedList: list));
}catch (e) {
print(e);
emit(GenshinError());
}
}
}
class HomeScreen extends StatelessWidget {
final userRepository = Repository();
HomeScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return BlocProvider<GenshinCubit>(
create: (context) => GenshinCubit(userRepository)..getCharacters(),
child: MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(body: Container(child: const CharactersScreen())),
),
);
}
}
class CharactersScreen extends StatefulWidget {
const CharactersScreen({
Key? key,
}) : super(key: key);
#override
State<CharactersScreen> createState() => _CharactersScreenState();
}
class _CharactersScreenState extends State<CharactersScreen> {
#override
Widget build(BuildContext context) {
return Column(
children: [
BlocBuilder<GenshinCubit, GenshinState>(
builder: (context, state) {
if (state is GenshinLoading) {
return Center(
child: CircularProgressIndicator(),
);
}
if (state is GenshinLoaded) {
return SafeArea(
top: false,
child: Column(
children: [
Container(
color: Colors.black,
height: MediaQuery.of(context).size.height,
child: ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: state.loadedList.length,
itemBuilder: ((context, index) {
return Padding(
padding: const EdgeInsets.symmetric(
vertical: 50.0, horizontal: 50),
child: GestureDetector(
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CharacterDetailsPage(
character: state.loadedList[index],
),
),
),
child: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
color: Colors.blueAccent.withOpacity(0.3),
borderRadius: const BorderRadius.all(
Radius.circular(
30,
),
)),
child: Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: const EdgeInsets.only(
right: 30.0, bottom: 30),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
state.loadedList[index].name
.toString(),
style: TextStyle(
color: Colors.black,
fontSize: 50),
),
RatingBarIndicator(
itemPadding: EdgeInsets.zero,
rating: double.parse(
state.loadedList[index].rarity
.toString(),
),
itemCount: int.parse(
state.loadedList[index].rarity
.toString(),
),
itemBuilder: (context, index) =>
Icon(
Icons.star_rate_rounded,
color: Colors.amber,
))
],
),
),
),
),
),
);
})),
),
],
),
);
}
if (state is GenshinInitial) {
return Text('Start');
}
if (state is GenshinError) {
return Text('Error');
}
return Text('Meow');
}),
],
);
}
}
I found a solution!
I've got that problem because of forEach. How to wait for forEach to complete with asynchronous callbacks? - there is a solution.

Flutter GridView in TabBar causing lag because of my code

There is a GridView in my TabBar which has two tabs and this tab is the 2nd one which is causing some UI lag. When I fetched some image in the GridView, I didn't experience any lag so I think I've done something wrong in my code which involves Futures which is loading videos from the internal storage directory. Also I have read about HandlerThread that it can help with the issue but I don't know how to implement it.
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:thumbnails/thumbnails.dart';
import 'package:wastatusapp/utils/video_play.dart';
final Directory _videoDir =
Directory('/storage/emulated/0/WhatsApp/Media/.Statuses');
class VideoScreen extends StatefulWidget {
const VideoScreen({Key key}) : super(key: key);
#override
VideoScreenState createState() => VideoScreenState();
}
class VideoScreenState extends State<VideoScreen> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
if (!Directory('${_videoDir.path}').existsSync()) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'Install WhatsApp\n',
style: TextStyle(fontSize: 18.0),
),
const Text(
"Your Friend's Status Will Be Available Here",
style: TextStyle(fontSize: 18.0),
),
],
);
} else {
return VideoGrid(directory: _videoDir);
}
}
}
class VideoGrid extends StatefulWidget {
final Directory directory;
const VideoGrid({Key key, this.directory}) : super(key: key);
#override
_VideoGridState createState() => _VideoGridState();
}
class _VideoGridState extends State<VideoGrid> {
Future<String> _getImage(videoPathUrl) async {
//await Future.delayed(Duration(milliseconds: 500));
final thumb = await Thumbnails.getThumbnail(
videoFile: videoPathUrl,
imageType:
ThumbFormat.PNG, //this image will store in created folderpath
quality: 10);
return thumb;
}
#override
Widget build(BuildContext context) {
final videoList = widget.directory
.listSync()
.map((item) => item.path)
.where((item) => item.endsWith('.mp4'))
.toList(growable: false);
if (videoList != null) {
if (videoList.length > 0) {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 8.0),
child: GridView.builder(
itemCount: videoList.length,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 0.7,
mainAxisSpacing: 8.0,
crossAxisSpacing: 8,
),
itemBuilder: (context, index) {
return InkWell(
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PlayStatus(
videoFile: videoList[index],
),
),
),
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(12)),
child: Container(
child: FutureBuilder(
future: _getImage(videoList[index]),
builder: (context, snapshot) {
if (snapshot.connectionState ==
ConnectionState.done) {
if (snapshot.hasData) {
return Hero(
tag: videoList[index],
child: Image.file(
File(snapshot.data),
fit: BoxFit.cover,
),
);
} else {
return Center(
child: Column(
children: [
Text(
"Open WhatsApp with your internet on and then try again."),
Text(
"Make sure you have good internet connection!")
],
),
);
}
} else {
return Container(
child:
Image.asset('assets/images/video_loader.gif'),
);
}
}),
//new cod
),
),
);
},
),
);
} else {
return const Center(
child: Text(
'Sorry, No Videos Found.',
style: TextStyle(fontSize: 18.0),
),
);
}
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
}
}

How to load more items to a list when reach the bottom of results flutter

I have the code below which feed a list with 10 results from firebase. In this case it shows only the 10 items, now I wanna, when user gets the bottom of results, it loads more 10 items and add it to the list. I already have the scrollController and it works.. I receive the log "LOAD HERE" when I get the bottom of the results.
My doubt is how to add the new 10 items in the list?
scrollListener() async {
if (scrollController.position.maxScrollExtent == scrollController.offset) {
print('LOAD HERE');
}
}
#override
void initState() {
scrollController.addListener(scrollListener);
super.initState();
}
#override
void dispose() {
scrollController.removeListener(scrollListener);
super.dispose();
}
loadList(submenu ,callback, context, deviceSize){
return FutureBuilder(
future: ctrlLab.loadList(submenu, 10),
builder: (ctx, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else if (snapshot.error != null) {
print(snapshot.error);
return Center(child: Text('ERROR!'));
}else {
return GridView.builder(
padding: EdgeInsets.all(10.0),
controller: scrollController,
itemCount: snapshot.data.length,
itemBuilder: (ctx, i) {
Item item = snapshot.data[i];
if (i < snapshot.data.length) {
return Dismissible(
key: UniqueKey(),
direction: DismissDirection.endToStart,
background: Container(
padding: EdgeInsets.all(10.0),
color: Colors.grey[800],
child: Align(
alignment: AlignmentDirectional.centerEnd,
child: Icon(
Icons.delete,
color: Colors.white,
size: 40,
),
),
),
onDismissed: (DismissDirection direction) {
ctrl.onDismissed(callback, item);
},
child: GestureDetector(
child: Card(
elevation: 5.0,
child: Padding(
padding: EdgeInsets.all(10.0),
child: GridTile(
child: Hero(
tag: "${item}",
child: item.imageUrl == null
? setIconLab(item)
: CachedNetworkImage(
fit: BoxFit.cover,
imageUrl: setIconLab(item),
placeholder: (ctx, url) =>
Center(child: CircularProgressIndicator()),
errorWidget: (context, url, error) =>
Image.asset('assets/images/noPhoto.jpg',
fit: BoxFit.cover),
),
),
footer: Container(
padding: EdgeInsets.all(8.0),
color: Colors.white70,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
item.name
),
),
],
),
),
),
),
),
),
);
}
},
gridDelegate: SliverGridDelegateWithFixedCrossAxisCountAndLoading(
itemCount: snapshot.data.length + 1,
crossAxisCount: deviceSize.width < 600 ? 2 : 3,
childAspectRatio: 0.7,
crossAxisSpacing: 10.0,
mainAxisSpacing: 10.0,
),
);
}
},
);
}
Infinite Scrolling in ListView
I have achieved this case by using the local field instead of getting data from firebase. Hope it will give you some idea.
import 'package:flutter/material.dart';
class ListViewDemo extends StatefulWidget {
ListViewDemo({Key key}) : super(key: key);
#override
_ListViewDemoState createState() => _ListViewDemoState();
}
class _ListViewDemoState extends State<ListViewDemo> {
ScrollController controller;
int count = 15;
#override
void initState() {
super.initState();
controller = ScrollController()..addListener(handleScrolling);
}
void handleScrolling() {
if (controller.offset >= controller.position.maxScrollExtent) {
setState(() {
count += 10;
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('List view'),
),
body: ListView.builder(
controller: controller,
itemCount: count,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text('Item $index'),
);
},
),
);
}
#override
void dispose() {
controller.removeListener(handleScrolling);
super.dispose();
}
}
You have to add another 10 data to the crtLap.loadList(subMenu, 20) and call setState inside the scrollListener to rebuild the widget about the changes.
var data = crtLap.loadList(subMenu, 10);
scrollListener() async {
if (scrollController.position.maxScrollExtent == scrollController.offset) {
setState((){
data = crtLap.loadList(subMenu, 20);
});
}
}
and use this data field to the FutureBuilder directly,
loadList(submenu ,callback, context, deviceSize){
return FutureBuilder(
future: data,
builder: (ctx, snapshot) {
.....
...
..
}