I am working on a video playing app. Where i play video using chewie package. To show subtitles is user subtitle wrapper package. The subtitle is showing properly in protrait mode when switched to full screen its not showing. Does anyone have a solution for this. my code is as below:
SafeArea(
child: Scaffold(
backgroundColor: Colors.black,
resizeToAvoidBottomInset: false,
body: Stack(children: [
MouseRegion(
onEnter: (event) {
setState(() {
isInfoVisible = true;
});
},
child: Dismissible(
key: const Key('key'),
direction: DismissDirection.horizontal,
onDismissed: (_) {
Navigator.of(context).pop();
_videoPlayerController?.dispose();
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
},
child: OrientationBuilder(
builder: (context, orientation) {
isPortrait =
orientation == Orientation.portrait;
return Center(
child: Stack(
fit: isPortrait
? StackFit.loose
: StackFit.expand,
children: [
SubTitleWrapper(
videoPlayerController:
_videoPlayerController,
subtitleController: subtitleController,
videoChild: Chewie(
controller: chewieController,
),
),
/*Chewie(
controller: chewieController,
),*/
],
),
);
},
))),
])),
),
chewie controller as below:
chewieController = ChewieController(
videoPlayerController: _videoPlayerController,
aspectRatio: 16 / 9,
autoPlay: true,
looping: false,
errorBuilder: (context, errorMessage) {
print('error occured $errorMessage');
},
showControls: true,
allowFullScreen: !kIsWeb ? true : false,
fullScreenByDefault: false,
customControls: CupertinoControls(
backgroundColor: Colors.black,
iconColor: COLORS['PRIMARY_COLOR'],
));
anyone please help with this or another any solution to show subtitle from a link in chewie package.
Related
I am working on a flutter project to play video from file or network. I use chewie package to play videos. But while testing in iphone 13 emulator and some of the full screen mobile phone i cant press the full screen and mute button of video player.The controls are overflowed.
And also while playing in full screen the video is not stretched. There are some black spaces in left and right side of the video.
The image of both is attached and my video player code is as follows
callChewie(_videoPlayerController) async {
bool startPlayer = false;
// _videoPlayerController.initialize();
_videoPlayerController.addListener(() {
// print(_videoPlayerController.value.isInitialized);
if (!startPlayer) {
if (!_videoPlayerController.value.isPlaying) {
startPlayer = true;
_videoPlayerController.play();
}
}
});
chewieController = ChewieController(
videoPlayerController: _videoPlayerController,
aspectRatio: 16 / 9,
autoPlay: true,
looping: false,
errorBuilder: (context, errorMessage) {
print('error occured $errorMessage');
Future.delayed(Duration(seconds: 10), () {
AwesomeDialog(
context: context,
dialogType: DialogType.ERROR,
dialogBackgroundColor: Colors.white,
borderSide: BorderSide(color: COLORS['PRIMARY_COLOR'], width: 2),
width: 400,
buttonsBorderRadius: BorderRadius.all(Radius.circular(2)),
headerAnimationLoop: false,
animType: AnimType.BOTTOMSLIDE,
title: 'Something went wrong.\nTry Again!',
btnOkColor: COLORS['PRIMARY_COLOR'],
showCloseIcon: true,
btnOkOnPress: () {
Navigator.pop(context);
},
)..show();
});
return Center(
child: CircularProgressIndicator(
color: Colors.red,
));
},
showControls: true,
allowFullScreen: !kIsWeb ? true : false,
fullScreenByDefault: false,
customControls: CupertinoControls(
backgroundColor: Colors.black,
iconColor: COLORS['PRIMARY_COLOR'],
));
chewieController.addListener(() {
if (chewieController.isFullScreen) {
print('full screen enabled');
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeRight,
DeviceOrientation.landscapeLeft,
]);
} else {
print('fullscreen disabled');
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
}
});
}
playMovie(file) async {
if (mounted) {
setState(() {
_videoPlayerController = null;
});
}
_videoPlayerController = VideoPlayerController.file(file);
await callChewie(_videoPlayerController);
Navigator.of(context).push(
PageRouteBuilder(
opaque: true,
settings: RouteSettings(),
pageBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) {
return WillPopScope(
onWillPop: () {
if (_videoPlayerController.value.isPlaying) {
_videoPlayerController?.pause();
_videoPlayerController?.dispose();
}
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
return new Future.value(true);
},
child: Scaffold(
backgroundColor: Colors.black,
resizeToAvoidBottomInset: false,
body: Stack(children: [
MouseRegion(
onEnter: (event) {
setState(() {
isInfoVisible = true;
});
},
child: Dismissible(
key: const Key('key'),
direction: DismissDirection.horizontal,
onDismissed: (_) {
Navigator.of(context).pop();
_videoPlayerController?.dispose();
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
},
child: OrientationBuilder(
builder: (context, orientation) {
isPortrait = orientation == Orientation.portrait;
return Center(
child: Stack(
//This will help to expand video in Horizontal mode till last pixel of screen
fit: isPortrait
? StackFit.loose
: StackFit.expand,
children: [
SubTitleWrapper(
videoPlayerController:
_videoPlayerController,
subtitleController: subtitleController,
videoChild: Chewie(
controller: chewieController,
),
),
/*Chewie(
controller: chewieController,
),*/
],
),
);
},
))),
])),
);
},
),
);
}
and I call the playMovie() function on button press.
onPressed: () {
playMovie(file[index]);
},
And also while playing in full screen the video is not stretched. There are some black spaces in left and right side of the video.
Condition don't work with StatelessWidget and Provider in Flutter,
Hopefully, I need that FloatingActionButton show up in specific tab but current code does not work properly. FloatingActionButton work in all tab.
I tried to debug and found index value is reflected but the Button does not disappear when changing tab.
return DefaultTabController(
length: 3,
initialIndex: 0,
child: ChangeNotifierProvider<MainModel>(
create: (_) => MainModel()..getWorkoutListRealtime(),
child: Scaffold(
appBar: AppBar(
title: Text("Workout at home"),
actions: [
Consumer<MainModel>(builder: (context, model, child) {
final isActive = model.checkShouldActiveCompleteButton();
return FlatButton(
onPressed: isActive
? () async {
await model.deleteCheckedItems();
}
: null,
child: Text(
'削除',
style: TextStyle(
color:
isActive ? Colors.white : Colors.white.withOpacity(0.5),
),
),
);
})
],
bottom: TabBar(
tabs: [
Tab(icon: Icon(Icons.directions_car)),
Tab(icon: Icon(Icons.directions_transit)),
Tab(icon: Icon(Icons.directions_bike)),
],
),
),
body: TabBarView(
children: [
Consumer<MainModel>(builder: (context, model, child) {
------------------------------------------------------------------
Consumer<MainModel>(builder: (context, model, child) {
return SimpleDatumLegend.withSampleData(model);
}),
CountdownTimer(),
],
),
floatingActionButton:
Consumer<MainModel>(builder: (context, model, child) {
final index = DefaultTabController.of(context).index;
return index == 1
? FloatingActionButton(
onPressed: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AddPage(model),
fullscreenDialog: true,
),
);
},
child: Icon(Icons.touch_app),
)
: SizedBox.shrink();
}),
I use DefaultTabController because I use Stateless widget and Provider function.
is there any alternative for something like IndexedStack on flutter? I used IndexedStack before but my WebView app feels slower and sometimes crashes on some devices. Someone in GitHub says that cause using IndexedStack and SetState. Is there any solution to avoid crashes and increase the WebView performance? For your information, I using the InAppWebView package in this case.
I wanna show a loading screen like this when onLoadStart, then show the WebView page when onLoadStop.
here is my sample app code:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
class SimpleWebiew extends StatefulWidget {
#override
_SimpleWebiewState createState() => _SimpleWebiewState();
}
class _SimpleWebiewState extends State<SimpleWebiew> {
num _stackToView = 1;
InAppWebViewController _webViewController;
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: true,
appBar: AppBar(
title: Text('Simple WebView'),
centerTitle: true,
),
body: IndexedStack(
index: _stackToView,
children: [
Opacity(
opacity: _stackToView == 0 ? 1 : 0,
child: InAppWebView(
initialUrlRequest: URLRequest(
url: Uri.parse('https://flutter.dev/'),
),
onWebViewCreated: (InAppWebViewController controller) {
_webViewController = controller;
},
onReceivedServerTrustAuthRequest: (controller, _challenge) async {
return ServerTrustAuthResponse(
action: ServerTrustAuthResponseAction.PROCEED,
);
},
initialOptions: InAppWebViewGroupOptions(
android: AndroidInAppWebViewOptions(
allowContentAccess: true,
builtInZoomControls: true,
thirdPartyCookiesEnabled: true,
allowFileAccess: true,
geolocationEnabled: true,
supportMultipleWindows: true,
),
crossPlatform: InAppWebViewOptions(
useShouldOverrideUrlLoading: true,
useOnDownloadStart: true,
allowFileAccessFromFileURLs: true,
allowUniversalAccessFromFileURLs: true,
),
),
onLoadStart: (inAppWebViewController, uri) {
setState(() {
_stackToView = 1;
});
},
onLoadStop: (inAppWebViewController, uri) {
setState(() {
_stackToView = 0;
});
},
),
),
Padding(
padding: EdgeInsets.only(bottom: 50.0),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.network(
'https://raw.githubusercontent.com/duythien0912/flutter_zalo_login/master/flutter.jpeg',
width: 200.0,
height: 200.0,
),
Padding(
padding: const EdgeInsets.only(top: 5.0),
child: Text(
'Connecting to server ',
style: TextStyle(
fontSize: 15,
color: Colors.red,
fontWeight: FontWeight.w600,
),
),
),
],
),
),
),
],
),
);
}
}
You can use AnimatedSwitcher too : Youtube
AnimatedSwitcher is similar to IndexedStack so IDK if that will help but try it first.
Or you just use inline if statement to achieve what you want. like this:
bool _isLoading = true;
...
_isLoading ? LoadingWidget : WebView
if it is loading, LoadingWidget will be shown, otherwise the WebView will be shown.
And the debug version will always be slow. Try it on release version with: flutter run --release
I'm using the Chewie Video player in my Flutter app. How to check when playback has completed, so that I can close the screen and dispose?
You can copy paste run full code below
You can check position and duration
full code is official example set loop to false and add the following code snippet
code snippet
_videoPlayerController1.addListener(() {
if (_videoPlayerController1.value.position ==
_videoPlayerController1.value.duration) {
print('video Ended');
}
});
Output
I/flutter ( 4881): video Ended
full code
import 'package:chewie/chewie.dart';
import 'package:chewie/src/chewie_player.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
void main() {
runApp(
ChewieDemo(),
);
}
class ChewieDemo extends StatefulWidget {
ChewieDemo({this.title = 'Chewie Demo'});
final String title;
#override
State<StatefulWidget> createState() {
return _ChewieDemoState();
}
}
class _ChewieDemoState extends State<ChewieDemo> {
TargetPlatform _platform;
VideoPlayerController _videoPlayerController1;
VideoPlayerController _videoPlayerController2;
ChewieController _chewieController;
#override
void initState() {
super.initState();
_videoPlayerController1 = VideoPlayerController.network(
'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4');
_videoPlayerController2 = VideoPlayerController.network(
'https://www.sample-videos.com/video123/mp4/480/asdasdas.mp4');
_chewieController = ChewieController(
videoPlayerController: _videoPlayerController1,
aspectRatio: 3 / 2,
autoPlay: true,
looping: false,
// Try playing around with some of these other options:
// showControls: false,
// materialProgressColors: ChewieProgressColors(
// playedColor: Colors.red,
// handleColor: Colors.blue,
// backgroundColor: Colors.grey,
// bufferedColor: Colors.lightGreen,
// ),
// placeholder: Container(
// color: Colors.grey,
// ),
// autoInitialize: true,
);
_videoPlayerController1.addListener(() {
if (_videoPlayerController1.value.position ==
_videoPlayerController1.value.duration) {
print('video Ended');
}
});
}
#override
void dispose() {
_videoPlayerController1.dispose();
_videoPlayerController2.dispose();
_chewieController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: widget.title,
theme: ThemeData.light().copyWith(
platform: _platform ?? Theme.of(context).platform,
),
home: Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(
children: <Widget>[
Expanded(
child: Center(
child: Chewie(
controller: _chewieController,
),
),
),
FlatButton(
onPressed: () {
_chewieController.enterFullScreen();
},
child: Text('Fullscreen'),
),
Row(
children: <Widget>[
Expanded(
child: FlatButton(
onPressed: () {
setState(() {
_chewieController.dispose();
_videoPlayerController2.pause();
_videoPlayerController2.seekTo(Duration(seconds: 0));
_chewieController = ChewieController(
videoPlayerController: _videoPlayerController1,
aspectRatio: 3 / 2,
autoPlay: true,
looping: true,
);
});
},
child: Padding(
child: Text("Video 1"),
padding: EdgeInsets.symmetric(vertical: 16.0),
),
),
),
Expanded(
child: FlatButton(
onPressed: () {
setState(() {
_chewieController.dispose();
_videoPlayerController1.pause();
_videoPlayerController1.seekTo(Duration(seconds: 0));
_chewieController = ChewieController(
videoPlayerController: _videoPlayerController2,
aspectRatio: 3 / 2,
autoPlay: true,
looping: true,
);
});
},
child: Padding(
padding: EdgeInsets.symmetric(vertical: 16.0),
child: Text("Error Video"),
),
),
)
],
),
Row(
children: <Widget>[
Expanded(
child: FlatButton(
onPressed: () {
setState(() {
_platform = TargetPlatform.android;
});
},
child: Padding(
child: Text("Android controls"),
padding: EdgeInsets.symmetric(vertical: 16.0),
),
),
),
Expanded(
child: FlatButton(
onPressed: () {
setState(() {
_platform = TargetPlatform.iOS;
});
},
child: Padding(
padding: EdgeInsets.symmetric(vertical: 16.0),
child: Text("iOS controls"),
),
),
)
],
)
],
),
),
);
}
}
I Have set a custom ErrorWidget for my application :
#override
Widget build(BuildContext context) {
ErrorWidget.builder = getErrorWidget;
return TabsView();
}
Anyways,I've added a RaisedButton inside My ErrorWidget to let the user Navigate to other widget when he press Retry:
I've tried to use Navigator but I think ErrorWidget isn't like MaterialApp so I get an Error context Undefined :
import 'package:flutter/material.dart';
import 'package:awesome_loader/awesome_loader.dart';
import 'package:carousel_slider/carousel_slider.dart';
import 'MyLocationView.dart';
List _tips = [
('Searching...'),
('Tips :Turn On Wifi'),
('Tips :Turn On GPS'),
];
int i = 0;
Widget getErrorWidget(FlutterErrorDetails error) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
AwesomeLoader(
loaderType: AwesomeLoader.AwesomeLoader3,
color: Colors.teal,
),
Center(
child: CarouselSlider(
height: 60.0,
viewportFraction: 1.0,
enlargeCenterPage: true,
autoPlay: true,
autoPlayInterval: Duration( seconds: 3 ),
autoPlayAnimationDuration: Duration( milliseconds: 800 ),
items: _tips.map( (i) {
return Builder(
builder: (BuildContext context) {
return Container(
width: 140.0,
child: Text(
' $i ',
style: TextStyle( fontSize: 16.0 ),
) );
},
);
} ).toList( ),
),
),
Center(
child :RaisedButton(
child: Text("Retry"),
onPressed: (){
//Here my button
Navigator.push(context, MaterialPageRoute(builder: (context)=>MyLocationView()));
}),
),
],
),
);
}
ErrorWidget is dedicated for critical errors and not for other usage.