Reputation: 1
Hello Everyone i am trying to implement story function as like instagram in flutter. i am done with display image and video story perfectly. i am getting issue when switching story form user to another user when first user video story start and i switch to another user story by swipe then if next user having video story and try to pause that story and again resume that video story, old user video start playing with same user.
i am following this plugin to display story text
i try to dispose videocontroller but not getting any luck.
Story(
sortByVisited: true,
shrinkWrap: true,
autoplay: true,
physics: NeverScrollableScrollPhysics(),
controller: controller.storyController,
scrollDirection: Axis.horizontal,
addAutomaticKeepAlives: true,
addRepaintBoundaries: false,
children: controller.storyItemDisplayList
.map(
(e) => StoryUser(
width: 80.0.w,
height: 80.0.w,
onLongPressed: (value) {},
avatar: Container(
padding: EdgeInsets.all(3.0),
width: 80.0.w,
height: 80.0.w,
decoration: (!e.isAllSeen)
? const BoxDecoration(
shape: BoxShape.circle,
border: GradientBoxBorder(
gradient: LinearGradient(
colors: [
AppTheme.gradientPink,
AppTheme.blue
]),
width: 3,
),
)
: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: AppTheme.grey,
width: 3),
),
child: RoundImage(
imageUrl: e.profilePicUrl ?? '',
),
),
label: Text(
e.displayName ?? '',
textAlign: TextAlign.center,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: AppUtils.textWhiteSFMedium12,
),
onPressed: (value) {},
margin: EdgeInsets.symmetric(
horizontal: 7.w),
borderPadding: EdgeInsets.all(3),
children: e.listOfDetails == null
? []
: e.listOfDetails!
.map(
(story) => StoryCard(
avatar: RoundImage(
imageUrl:
e.profilePicUrl ??
'',
height: 40.w,
width: 40.w,
),
label: Text(
e.displayName ?? '',
maxLines: 1,
overflow: TextOverflow
.ellipsis,
style: AppUtils
.textWhiteSFMedium14,
),
storyTime: Text(
DateHelper.timeAgoStory(
value: story
.createdDate ??
'',
),
style: AppUtils
.textWhiteSFMedium14,
),
isLike:
story.isLike ?? false,
progressBarHeight: 4.h,
onPressed: (value) async {
var friend = Friend();
friend.userId =
e.userId ?? '';
friend.username =
e.username ?? '';
friend.displayName =
e.displayName ?? '';
friend.profilePicUrl =
e.profilePicUrl ??
'';
await AppRouter
.otherUserProfile(
friendItem:
friend,
flagClose:
false);
},
onPause: (value) {
controller
.storyController
.pauseStory();
if (story.type ==
"video") {
controller
.storyVideoPlayer
.pause();
}
},
onResume: (value) {
controller
.storyController
.playStory();
if (story.type ==
"video") {
controller
.storyVideoPlayer
.play();
}
},
onDispose: (value) {},
onVisited: (cardIndex) {
// setState(() {
// card.visited = true;
// });
controller.setStorySeen(
story);
controller
.setActiveIndex(
story);
},
onNext: (value) {
if (controller
.isDialogShowing) {
Navigator.pop(
context);
controller
.storyController
.playStory();
// if (story.type == "video") {
// controller.storyVideoPlayer
// .play();
// }
controller
.showReply(false);
}
},
onPrevious: (value) {
if (controller
.isDialogShowing) {
Navigator.pop(
context);
controller
.storyController
.playStory();
// if (story.type == "video") {
// controller.storyVideoPlayer
// .play();
// }
controller
.showReply(false);
}
},
footer: StoryCardFooter(
likeButton:
StoryCardLikeButton(
onLike: (value) =>
controller
.addStoryLike(
story),
),
forwardButton:
StoryCardForwardButton(
onForward: (value) {
controller
.storyController
.pauseStory();
if (story.type ==
"video") {
controller
.storyVideoPlayer
.pause();
}
_showReplyDialog(
context,
story,
controller);
},
),
child: Container(
padding:
EdgeInsets.only(
left: 10.0.w,
top: 10.h,
bottom: 10.h),
child: Container(
decoration: BoxDecoration(
border: Border.all(
width: 1.0,
color: Colors
.white),
borderRadius:
const BorderRadius
.all(
Radius.circular(
30))),
child: TextField(
readOnly: true,
onTap: () {
controller
.storyController
.pauseStory();
if (story
.type ==
"video") {
controller
.storyVideoPlayer
.pause();
}
_showReplyDialog(
context,
story,
controller);
},
decoration:
InputDecoration(
fillColor: Colors
.transparent,
border:
InputBorder
.none,
hintText:
'Send message...',
hintStyle: AppUtils
.textWhiteSFMedium14,
contentPadding:
EdgeInsets.symmetric(
vertical:
5.h,
horizontal:
10.h),
//Change this value to custom as you like
isDense: true,
),
),
),
),
),
childOverlay: Stack(
alignment:
Alignment.center,
children: [
for (int i = 0;
i <
(story.editableList
?.length ??
0);
i++)
AppUtils.buildItemWidget(
story.editableList?[
i] ??
EditableItem(),
context,
objs: story,
storyControllers:
controller
.storyController,
storyVideoPlayer:
controller
.storyVideoPlayer)
],
),
isSeen:
story.isSeen ?? false,
cardDuration: Duration(
seconds:
(story.duration ??
0)
.toInt()),
child: StoryChild(
key: Key(story.cdnUrl ??
UniqueKey()
.toString()),
story: story,
storyController:
controller
.storyController,
storyVideoPlayer:
controller
.storyVideoPlayer,
videoPlayerController:
controller
.videoPlayer,
)),
)
.toList(),
),
)
.toList(),
)
StoryChild is item of itembuilder.
class StoryChild extends StatefulWidget {
final StoryItems? story;
final StoryController? storyController;
final VideoStoryController? storyVideoPlayer;
final VideoPlayerController? videoPlayerController;
const StoryChild(
{super.key,
this.story,
this.storyController,
this.storyVideoPlayer,
this.videoPlayerController});
@override
State<StoryChild> createState() => _StoryChildState();
}
class _StoryChildState extends State<StoryChild> {
StreamSubscription? _streamSubscription;
bool _isInitialized = false;
VideoPlayerController? videoPlayer;
@override
void initState() {
super.initState();
if (widget.story?.type == "video") {
videoPlayer = widget.videoPlayerController;
_initializeVideo();
} else {
_disposeVideo();
}
}
// @override
// void didUpdateWidget(StoryChild oldWidget) {
// super.didUpdateWidget(oldWidget);
// if (widget.story != oldWidget.story) {
// _disposeVideo();
// _initializeVideo();
// }
// }
Future<void> _initializeVideo() async {
final file =
await VideoCacheManager.getVideoFile(widget.story?.cdnUrl ?? '');
videoPlayer = VideoPlayerController.file(file);
await videoPlayer?.initialize().then(
(value) {
if (mounted) {
setState(() {
_isInitialized = true;
});
}
_streamSubscription =
widget.storyVideoPlayer!.playbackNotify.listen((playbackState) {
if (playbackState == PlaybackState.pause) {
// if (widget.isActive ?? false) {
videoPlayer?.pause();
widget.storyController?.pauseStory();
// }
} else {
videoPlayer?.play();
widget.storyController?.playStory();
}
});
},
);
}
void _disposeVideo() {
videoPlayer?.dispose();
videoPlayer = null;
_streamSubscription?.cancel();
_isInitialized = false;
}
@override
void dispose() {
_disposeVideo();
super.dispose();
}
@override
Widget build(BuildContext context) {
return widget.story?.type == "image"
? Stack(
alignment: Alignment.center,
fit: StackFit.expand,
children: [
Positioned.fill(
child: Container(color: Colors.transparent),
),
CachedNetworkImage(
imageUrl: widget.story?.cdnUrl ?? '',
fit: BoxFit.contain,
alignment: Alignment.center,
cacheKey: widget.story?.cdnUrl ?? '',
cacheManager: CustomCacheManager().getCacheManager(
widget.story?.cdnUrl ?? '',
),
progressIndicatorBuilder: (context, url, progress) => Center(
child: CircularProgressIndicator(
color: Colors.white,
),
),
),
],
)
: widget.story?.type == "video"
? getContentView()
: Container(
decoration: BoxDecoration(
color: Color(
int.parse(widget.story?.backgroundColor ?? ''),
),
),
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 16,
),
);
}
Widget getContentView() {
// if (widget.videoLoader.state == LoadState.success && _videoPlayerController!.value.isInitialized) {
if (_isInitialized) {
return VisibilityDetector(
key: Key(widget.story?.cdnUrl ?? ''),
onVisibilityChanged: (info) {
if (info.visibleFraction == 1) {
widget.storyVideoPlayer?.play();
} else if (info.visibleFraction == 0) {
widget.storyVideoPlayer?.pause();
}
},
child: Center(
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(10)),
child: AspectRatio(
aspectRatio: videoPlayer!.value.aspectRatio,
child: VideoPlayer(videoPlayer!)),
),
),
);
} else {
return Center(
child: SizedBox(
width: 70,
height: 70,
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
strokeWidth: 3,
),
),
);
}
}
}
Upvotes: 0
Views: 62