To play video within the alert dialog I am using the below code. But Video is not playing. Is it possible to play video within the Alert Dialog? Does anyone has a solution to this please share it with me.
Future<void> _initializeVideoPlayerFuture;
VideoPlayerController _controller;
_controller = VideoPlayerController.network(
video_base_url+videoUrl,
);
// Initialize the controller and store the Future for later use.
_initializeVideoPlayerFuture = _controller.initialize();
// Use the controller to loop the video.
_controller.setLooping(true);
// If the video is playing, pause it.
if (_controller.value.isPlaying) {
_controller.pause();
} else {
// If the video is paused, play it.
_controller.play();
}
ContainerResponsive(
alignment: Alignment.center,
width: MediaQuery.of(context).size.width-50,
height: 150,
child: FutureBuilder(
future: _initializeVideoPlayerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
// If the VideoPlayerController has finished initialization, use
// the data it provides to limit the aspect ratio of the video.
return AspectRatio(
aspectRatio: _controller.value.aspectRatio,
// Use the VideoPlayer widget to display the video.
child: VideoPlayer(_controller),
);
} else {
// If the VideoPlayerController is still initializing, show a
// loading spinner.
return const Center(
child: CircularProgressIndicator(),
);
}
},
)
),
Make a new Stateful widget class like this for video player , initialized video player controller and video player widget here
import 'package:approved/src/constants/colors.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:video_player/video_player.dart';
class VideoWidget extends StatefulWidget {
final String? url;
final bool? play;
const VideoWidget({#required this.url, #required this.play});
#override
_VideoWidgetState createState() => _VideoWidgetState();
}
class _VideoWidgetState extends State<VideoWidget> {
late VideoPlayerController _controller;
Future<void>? _initializeVideoPlayerFuture;
#override
void initState() {
super.initState();
_controller = VideoPlayerController.network(widget.url!);
_initializeVideoPlayerFuture = _controller.initialize().then((_) {
// Ensure the first frame is shown after the video is initialized, even before the play button has been pressed.
setState(() {});
});
if (widget.play!) {
_controller.play();
_controller.setLooping(true);
}
}
#override
void didUpdateWidget(VideoWidget oldWidget) {
if (oldWidget.play != widget.play) {
if (widget.play!) {
_controller.play();
_controller.setLooping(true);
} else {
_controller.pause();
}
}
super.didUpdateWidget(oldWidget);
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Stack(children: [
Container(
color: Colors.white,
child: FutureBuilder(
future: _initializeVideoPlayerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return VideoPlayer(_controller);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
},
),
),
]);
}
}
Now you can use this widget anywhere you have to just pass the video url and playing parameter true/false.
Like I am using in showDialog method
playVideo(
BuildContext context,
) {
return showDialog(
context: context,
builder: (context) {
return Center(
child: SizedBox(
height: 300,
width: 300,
child: VideoWidget(url: url, play: true)));
});
}
Related
I want to check for internet connection at every screen on my app just like Telegram does and whenever user goes offline, show an Offline banner on the top of the screen.
I have tried using connectivity_plus and internet_connection_checker plugins to check for this but the problem is I have to subscribe to a stream for this and if the device goes offline once then there is no way to subscribe to it again without clicking a button.
getConnectivity() =>
subscription = Connectivity().onConnectivityChanged.listen(
(ConnectivityResult result) async {
isDeviceConnected = await InternetConnectionChecker().hasConnection;
if (!isDeviceConnected && isAlertSet == false) {
setState(() {
constants.offline = true;
print('Constants().offline ${constants.offline}');
isAlertSet = true;
});
}
print('off');
},
);
I'm using this code right now to check this issue but I don't want to replicate this code on each and every screen and even if I do replicate it then there will be a lot of subscriptions that I'll be subscribing to, which will mean that all the subscriptions will be disposed at the same time causing all sorts of issues.
If you have custom Scaffold, then you have to edit it. Otherwise, create a new one and change all Scaffolds to your custom one. This allows you to easily apply changes that should be on all pages.
Then, in the CustomScaffold create a Stack that contains page content and ValueListenableBuilder that listens to connection changes and if there is no internet displays error banner.
class CustomScaffold extends StatefulWidget {
const CustomScaffold({Key? key}) : super(key: key);
#override
State<CustomScaffold> createState() => _CustomScaffoldState();
}
class _CustomScaffoldState extends State<CustomScaffold> with WidgetsBindingObserver {
StreamSubscription? connectivitySubscription;
ValueNotifier<bool> isNetworkDisabled = ValueNotifier(false);
void _checkCurrentNetworkState() {
Connectivity().checkConnectivity().then((connectivityResult) {
isNetworkDisabled.value = connectivityResult == ConnectivityResult.none;
});
}
initStateFunc() {
_checkCurrentNetworkState();
connectivitySubscription = Connectivity().onConnectivityChanged.listen(
(ConnectivityResult result) {
isNetworkDisabled.value = result == ConnectivityResult.none;
},
);
}
#override
void initState() {
WidgetsBinding.instance.addObserver(this);
initStateFunc();
super.initState();
}
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
if (state == AppLifecycleState.resumed) {
_checkCurrentNetworkState();
}
}
#override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
connectivitySubscription?.cancel();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Stack(
fit: StackFit.expand,
children: [
Scaffold(
...
),
ValueListenableBuilder(
valueListenable: isNetworkDisabled,
builder: (_, bool networkDisabled, __) =>
Visibility(
visible: networkDisabled,
child: YourErrorBanner(),
),
),
],
);
}
}
First I created an abstract class called BaseScreenWidget
used bloc state management to listen each time the internet connection changed then show toast or show upper banner with Blocbuilder
abstract class BaseScreenWidget extends StatelessWidget {
const BaseScreenWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Column(
children: [
baseBuild(context),
BlocConsumer<InternetConnectionBloc, InternetConnectionState>(
listener: (context, state) {
// if (!state.isConnected) {
// showToast("No Internet Connection");
// }
},
builder: (context, state) {
if (!state.isConnected) {
return const NoInternetWidget();
}
return const SizedBox.shrink();
},
),
],
);
}
Widget baseBuild(BuildContext context);
}
Made each screen only screen widgets contains Scaffold to extends BaseScreenWidget
class MainScreen extends BaseScreenWidget {
const MainScreen({super.key});
#override
Widget baseBuild(BuildContext context) {
return const Scaffold(
body: MainScreenBody(),
);
}
}
it's very helpful to wrap the Column with SafeArea in the build method in BaseScreen.
USE THIS SIMPLE TECHNIQUE only need this package: Internet Connection Checker. If you turn off your network it will tell you
connection_checker.dart
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:internet_connection_checker/internet_connection_checker.dart';
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
class CheckMyConnection {
static bool isConnect = false;
static bool isInit = false;
static hasConnection(
{required void Function() hasConnection,
required void Function() noConnection}) async {
Timer.periodic(const Duration(seconds: 1), (_) async {
isConnect = await InternetConnectionChecker().hasConnection;
if (isInit == false && isConnect == true) {
isInit = true;
hasConnection.call();
} else if (isInit == true && isConnect == false) {
isInit = false;
noConnection.call();
}
});
}
}
base.dart
import 'package:flutter/material.dart';
import 'connection_checker.dart';
class Base extends StatefulWidget {
final String title;
const Base({Key? key, required this.title}) : super(key: key);
#override
State<Base> createState() => _BaseState();
}
class _BaseState extends State<Base> {
final snackBar1 = SnackBar(
content: const Text(
'Internet Connected',
style: TextStyle(color: Colors.white),
),
backgroundColor: Colors.green,
);
final snackBar2 = SnackBar(
content: const Text(
'No Internet Connection',
style: TextStyle(color: Colors.white),
),
backgroundColor: Colors.red,
);
#override
void initState() {
super.initState();
CheckMyConnection.hasConnection(hasConnection: () {
ScaffoldMessenger.of(navigatorKey.currentContext!)
.showSnackBar(snackBar1);
}, noConnection: () {
ScaffoldMessenger.of(navigatorKey.currentContext!)
.showSnackBar(snackBar2);
});
}
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 3,
child: Scaffold(
key: navigatorKey,
appBar: AppBar(
bottom: const TabBar(
tabs: [
Tab(icon: Icon(Icons.directions_car)),
Tab(icon: Icon(Icons.directions_transit)),
Tab(icon: Icon(Icons.directions_bike)),
],
),
title: const Text('Tabs Demo'),
),
body: const TabBarView(
children: [
Icon(Icons.directions_car),
Icon(Icons.directions_transit),
Icon(Icons.directions_bike),
],
),
),
);
}
}
I myself use connectivity_plus and I have never found the problem you mentioned (if the device goes offline once then there is no way to subscribe to it again without clicking a button), you can use my example.
If the user's internet is disconnected, a modal will appear. If the user is connected again, the modal will be deleted automatically.
Anyway, I put the option to check the internet again in the modal
class CheckConnectionStream extends GetxController {
bool isModalEnable = false;
final loadingCheckConnectivity = false.obs;
ConnectivityResult _connectionStatus = ConnectivityResult.none;
final Connectivity _connectivity = Connectivity();
late StreamSubscription<ConnectivityResult> _connectivitySubscription;
Future<void> initConnectivity() async {
late ConnectivityResult result;
try {
result = await _connectivity.checkConnectivity();
loadingCheckConnectivity.value = false;
} on PlatformException {
return;
}
return _updateConnectionStatus(result);
}
Future<void> _updateConnectionStatus(ConnectivityResult result) async {
_connectionStatus = result;
if (result == ConnectivityResult.none) {
if (isModalEnable != true) {
isModalEnable = true;
showDialogIfNotConnect();
}
} else {
if (isModalEnable) {
Get.back();
}
isModalEnable = false;
}
}
showDialogIfNotConnect() {
Get.defaultDialog(
barrierDismissible: false,
title: "check your network".tr,
onWillPop: () async {
return false;
},
middleText: "Your device is not currently connected to the Internet".tr,
titleStyle: TextStyle(
color: Get.isDarkMode ? Colors.white : Colors.black,
),
middleTextStyle: TextStyle(
color: Get.isDarkMode ? Colors.white : Colors.black,
),
radius: 30,
actions: [
Obx(() => loadingCheckConnectivity.value
? const CustomLoading(
height: 30.0,
radius: 30.0,
)
: ElevatedButton(
onPressed: () async {
loadingCheckConnectivity.value = true;
EasyDebounce.debounce(
'check connectivity',
const Duration(milliseconds: 1000), () async {
await initConnectivity();
});
},
child: Text(
'try again'.tr,
style: const TextStyle(color: Colors.white),
),
))
]);
}
#override
void onInit() {
super.onInit();
initConnectivity();
_connectivitySubscription =
_connectivity.onConnectivityChanged.listen(_updateConnectionStatus);
}
#override
void onClose() {
_connectivitySubscription.cancel();
super.onClose();
}
}
My problem is that the video works fine on web view but doesn't show or work in the Android emulator. I want to play this video in an emulator also. And all the videos are asset videos. If anyone knows the solution or if anyone can help please help. Thank You
**Below is the code which I wrote for the video **
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
import 'package:cached_video_player/cached_video_player.dart';
class VideoApp extends StatefulWidget {
const VideoApp({Key? key}) : super(key: key);
#override
State<VideoApp> createState() => _VideoAppState();
}
class _VideoAppState extends State<VideoApp> {
late VideoPlayerController _controller;
late Future<void> _initializeVideoPlayerFuture;
#override
void initState() {
super.initState();
// Create and store the VideoPlayerController. The VideoPlayerController
// offers several different constructors to play videos from assets, files,
// or the internet.
_controller = VideoPlayerController.network(
'assets/videos/animation 1 final.mp4',
);
_initializeVideoPlayerFuture = _controller.initialize();
}
#override
void dispose() {
// Ensure disposing of the VideoPlayerController to free up resources.
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
future: _initializeVideoPlayerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: VideoPlayer(_controller),
);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
if (_controller.value.isPlaying) {
_controller.pause();
} else {
// If the video is paused, play it.
_controller.play();
}
});
},
// Display the correct icon depending on the state of the player.
child: Icon(
_controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
),
)
);
}
}
[https://i.stack.imgur.com/8X0OX.png][1]
Your are calling from network but giving an asset path.
_controller = VideoPlayerController.network(
'assets/videos/animation 1 final.mp4',
);
I am trying to display those images into a carousel pro but with no luck.
There are some photos from firestore storage that I want to display in my mobile app, and its working, but I just want to be in a carousel slide.
class ImagesScreen extends StatelessWidget {
Widget makeImagesGrid() {
return GridView.builder(
itemCount: 7,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2),
itemBuilder: (context, index) {
return ImageGridItem(index+1);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Test Image"),
),
body: Container(
child: makeImagesGrid(),
),
);
}
}
class ImageGridItem extends StatefulWidget {
int _index;
ImageGridItem(int index){
this._index = index;
}
#override
_ImageGridItemState createState() => _ImageGridItemState();
}
class _ImageGridItemState extends State<ImageGridItem> {
Uint8List imageFile;
StorageReference photosReference = FirebaseStorage.instance.ref().child("images/reklama");
getImage() {
int MAX_SIZE = 7*1024*1024;
photosReference.child("reklama_${widget._index}.jpg").getData(MAX_SIZE).then((data) {
this.setState(() {
imageFile = data;
});
}).catchError((error){
debugPrint(error.toString());
});
}
Widget decideGridTileWidget() {
if(imageFile == null) {
return Center(child: Image.asset("images/reklama.jpg"));
}else {
return Image.memory(imageFile,fit: BoxFit.cover);
}
}
#override
void initState() {
super.initState();
getImage();
}
#override
Widget build(BuildContext context) {
return GridTile(child: decideGridTileWidget());
}
}
cached_network_image and carousel_slider should help you to do what you want, you don't really need to handle the image from firestore and the carousel sliding widget yourself. Example of using cached_network_image to show image from firestore is as below:
FutureBuilder(
future: FirebaseStorage.instance
.ref()
.child('images/kartelaime.jpg') // Your image path in firestore
.getDownloadURL(),
builder: (context, snapshot) {
if(snapshot.data != null)
return CachedNetworkImage(imageUrl: snapshot.data);
else return Container();
}
)
Please If it is possible a code example
i am trying something like that but the images on here to be from firebase storage and like in first example not each image to give a path but all images on that folder
Widget build(BuildContext context) {
Widget imageCarousel = new Container(
height: 200.0,
child: new Carousel(
boxFit: BoxFit.cover,
images: [
AssetImage('images/kartelaime.jpg'),
AssetImage('images/shperblime.png'),
AssetImage('images/7vitemeridian.png'),
AssetImage('images/ndertshpis.jpg'),
AssetImage('images/ofertatjavore.png'),
AssetImage('images/zgjerimi.jpeg'),
],
autoplay: false,
animationCurve: Curves.fastOutSlowIn,
animationDuration: Duration(milliseconds: 1000),
dotSize: 4.0,
indicatorBgPadding: 4.0,
dotBgColor: Colors.transparent,
),
);
I am new to flutter. Currently i am building the web app that using flutter webview plugin but i have a question about the internet connectivity. When users doesnt have a connection that app gives a default error page like
Webpage not available
The webpage at https://covid19.who.int/ could be not be loaded because:
net:::ERR_Internet_disconnected
How to use custom code to show custom error page like to hide url? My proper code is:
import 'package:flutter/material.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
import 'package:covidwho/layout/myAppBar.dart';
class Who extends StatefulWidget {
#override
_WhoState createState() => _WhoState();
}
class _WhoState extends State<Who> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: MyAppBar(),
body: Container(
child: WebviewScaffold(
url: "https://covid19.who.int/",
withJavascript: true,
withLocalStorage: true,
hidden: true,
initialChild: Container(
color: Colors.white,
child: const Center(
child: CircularProgressIndicator(
backgroundColor: Colors.black,
),
)),
),
),
);
}
}
I would like to share with you the code I use to show custom pages at the time of flutter web errors.
Full project link https://github.com/K3rimoff/flutter-custom-web-error-page
import 'dart:async';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import '../../components/back_pressed.dart';
import '../../theme/colors.dart';
import '../error/error.dart';
class WebScreen extends StatefulWidget {
const WebScreen({super.key});
#override
State<WebScreen> createState() => _WebScreenState();
}
class _WebScreenState extends State<WebScreen> with TickerProviderStateMixin {
late AnimationController _animationController;
InAppWebViewController? _webViewController;
PullToRefreshController? _refreshController;
bool _isLoading = false, _isVisible = false, _isOffline = false;
// 0 - Everything is ok, 1 - http or other error fixed
int _errorCode = 0;
final BackPressed _backPressed = BackPressed();
Future<void> checkError() async {
//Hide CircularProgressIndicator
_isLoading = false;
//Check Network Status
ConnectivityResult result = await Connectivity().checkConnectivity();
//if Online: hide offline page and show web page
if (result != ConnectivityResult.none) {
if (_isOffline == true) {
_isVisible = false; //Hide Offline Page
_isOffline = false; //set Page type to error
}
}
//If Offline: hide web page show offline page
else {
_errorCode = 0;
_isOffline = true; //Set Page type to offline
_isVisible = true; //Show offline page
}
// If error is fixed: hide error page and show web page
if (_errorCode == 1) _isVisible = false;
setState(() {});
}
#override
void dispose() {
_animationController.dispose();
super.dispose();
}
#override
void initState() {
super.initState();
_animationController =
AnimationController(vsync: this, duration: const Duration(seconds: 2));
_animationController.repeat();
_refreshController = PullToRefreshController(
onRefresh: () => _webViewController!.reload(),
options: PullToRefreshOptions(
color: Colors.white, backgroundColor: Colors.black87),
);
}
#override
Widget build(BuildContext context) {
return WillPopScope(
child: Scaffold(
body: SafeArea(
child: Stack(
alignment: Alignment.center,
children: [
InAppWebView(
onWebViewCreated: (controller) =>
_webViewController = controller,
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
supportZoom: false,
)),
initialUrlRequest: URLRequest(
url: Uri.parse(
"https://google.com")), // For http error: change to wrong url : https://google.com/404/
pullToRefreshController: _refreshController,
onLoadStart: (controller, url) {
setState(() {
_isLoading = true; //Show CircularProgressIndicator
});
},
onLoadStop: (controller, url) {
_refreshController!.endRefreshing();
checkError(); //Check Error type: offline or other error
},
onLoadError: (controller, url, code, message) {
// Show
_errorCode = code;
_isVisible = true;
},
onLoadHttpError: (controller, url, statusCode, description) {
_errorCode = statusCode;
_isVisible = true;
},
),
//Error Page
Visibility(
visible: _isVisible,
child: ErrorScreen(
isOffline: _isOffline,
onPressed: () {
_webViewController!.reload();
if (_errorCode != 0) {
_errorCode = 1;
}
}),
),
//CircularProgressIndicator
Visibility(
visible: _isLoading,
child: CircularProgressIndicator.adaptive(
valueColor: _animationController.drive(
ColorTween(
begin: circularProgressBegin,
end: circularProgressEnd),
),
),
),
],
),
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
ElevatedButton.icon(
onPressed: () {
_errorCode = 1;//My Error fixed code
_webViewController!.loadUrl(
urlRequest: URLRequest(
url: Uri.parse("https://google.com/"), //Correct url
),
);
},
label: const Text("Load Correct URL"),
icon: const Icon(Icons.check),
),
ElevatedButton.icon(
onPressed: () {
_webViewController!.loadUrl(
urlRequest: URLRequest(
url: Uri.parse("https://google.com/404"), //Wrong url
),
);
},
label: const Text("Load Wrong URL"),
icon: const Icon(Icons.close),
),
],
),
),
onWillPop: () async {
//If website can go back page
if (await _webViewController!.canGoBack()) {
await _webViewController!.goBack();
return false;
} else {
//Double pressed to exit app
return _backPressed.exit(context);
}
});
}
}
For that you need to implement
Stream<String> onError webview event.
Don't forget to dispose webview flutterWebviewPlugin.dispose()
Here is a code sample
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
String selectedUrl = 'https://flutter.io';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyHomePage());
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
// Instance of WebView plugin
final flutterWebViewPlugin = FlutterWebviewPlugin();
// On destroy stream
StreamSubscription _onDestroy;
// On Http error
StreamSubscription<WebViewHttpError> _onHttpError;
final _scaffoldKey = GlobalKey<ScaffoldState>();
#override
void initState() {
super.initState();
flutterWebViewPlugin.launch(selectedUrl);
// Add a listener to on destroy WebView, so you can make came actions.
_onDestroy = flutterWebViewPlugin.onDestroy.listen((_) {
if (mounted) {
// Actions like show a info toast.
_scaffoldKey.currentState.showSnackBar(
const SnackBar(content: const Text('Webview Destroyed')));
}
});
_onHttpError =
flutterWebViewPlugin.onHttpError.listen((WebViewHttpError error) {
if (mounted) {
//do your customization here
}
});
}
#override
void dispose() {
// Every listener should be canceled, the same should be done with this stream.
_onDestroy.cancel();
_onHttpError.cancel();
flutterWebViewPlugin.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
);
}
}
I would like to make an endlessFeed in Fluter but the app terminates without giving me any information why. Basically it happens after I scrolled down about 60 images then it starts to lag a bit and it crashes.
I tested another API but the same there. It uses images with lower resolution so it takes longer to scroll down until it stops working.
So I don't know what happens here. My guess is that there are to many images in the ListView so that the phone can't handle it and crashes.
I've put the whole code below because I don't even know wehere the problem could be. Is there maybe another way to achieve an endlessImageFeed?
import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:cached_network_image/cached_network_image.dart';
// my base url
String imageUrl = "http://192.168.2.107:8000";
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'EndlessFeed',
theme: ThemeData(
primaryColor: Colors.white,
),
home: PhotoList(),
);
}
}
class PhotoList extends StatefulWidget {
#override
PhotoListState createState() => PhotoListState();
}
class PhotoListState extends State<PhotoList> {
StreamController<Photo> streamController;
List<Photo> list = [];
#override
void initState() {
super.initState();
streamController = StreamController.broadcast();
streamController.stream.listen((p) => setState(() => list.add(p)));
load(streamController);
}
load(StreamController<Photo> sc) async {
// URL for API
String url = "http://192.168.2.107:8000/api/";
/* ______________________________________________
I also tried another API but it chrashes also (but it takes longer until crash):
String url = "https://jsonplaceholder.typicode.com/photos/";
______________________________________________ */
var client = new http.Client();
var req = new http.Request('get', Uri.parse(url));
var streamedRes = await client.send(req);
streamedRes.stream
.transform(UTF8.decoder)
.transform(json.decoder)
.expand((e) => e)
.map((map) => Photo.fromJsonMap(map))
.pipe(sc);
}
#override
void dispose() {
super.dispose();
streamController?.close();
streamController = null;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("EndlessFeed"),
),
body: Center(
child: ListView.builder(
itemBuilder: (BuildContext context, int index) => _makeElement(index),
),
),
);
}
Widget _makeElement(int index) {
if (index >= list.length) {
return null;
}
return Container(
child: Padding(
padding: EdgeInsets.only(top: 20.0),
child: Column(
children: <Widget>[
child: new Container(
// my base URL + one image
child: new Image(image: new CachedNetworkImageProvider(imageUrl + list[index].mImage))
),
),
],
),
));
}
}
class Photo {
final String mImage;
Photo.fromJsonMap(Map map)
: mImage= map['mImage'];
}