|
|
@@ -6,7 +6,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
|
import 'package:go_router/go_router.dart';
|
|
|
import 'package:news_app/ui/video/video_detail_page.dart';
|
|
|
-import 'package:news_app/ui/video/video_recommend_list_page.dart';
|
|
|
|
|
|
import '../../constant/config.dart';
|
|
|
import '../../gen/assets.gen.dart';
|
|
|
@@ -16,23 +15,26 @@ import '../../util/share_util.dart';
|
|
|
import '../../widget/auth_gesture_detector.dart';
|
|
|
import '../../widget/load_image.dart';
|
|
|
import '../../widget/my_txt.dart';
|
|
|
+import '../video/video_recommend_list_page.dart';
|
|
|
|
|
|
class VideoPlayItemWidget extends ConsumerStatefulWidget {
|
|
|
final VideoNewModel item;
|
|
|
final bool isActive;
|
|
|
+ final int index;
|
|
|
|
|
|
const VideoPlayItemWidget({
|
|
|
super.key,
|
|
|
required this.item,
|
|
|
required this.isActive,
|
|
|
+ required this.index,
|
|
|
});
|
|
|
|
|
|
@override
|
|
|
ConsumerState<VideoPlayItemWidget> createState() => _VideoItemWidgetState();
|
|
|
}
|
|
|
|
|
|
-class _VideoItemWidgetState extends ConsumerState<VideoPlayItemWidget> {
|
|
|
- late BetterPlayerController _controller;
|
|
|
+class _VideoItemWidgetState extends ConsumerState<VideoPlayItemWidget>
|
|
|
+ with AutomaticKeepAliveClientMixin {
|
|
|
bool _isPlaying = false;
|
|
|
|
|
|
bool _isWeChatInstalled = false;
|
|
|
@@ -40,14 +42,19 @@ class _VideoItemWidgetState extends ConsumerState<VideoPlayItemWidget> {
|
|
|
Future<void> _checkWeChatInstallation() async {
|
|
|
if (Platform.isAndroid) {
|
|
|
final installed = await isWeChatInstalledOnlyAndroid();
|
|
|
- setState(() => _isWeChatInstalled = installed);
|
|
|
+ if (mounted) {
|
|
|
+ setState(() => _isWeChatInstalled = installed);
|
|
|
+ }
|
|
|
} else if (Platform.isIOS) {
|
|
|
final installed = await fluwx.isWeChatInstalled;
|
|
|
- setState(() => _isWeChatInstalled = installed);
|
|
|
+ if (mounted) {
|
|
|
+ setState(() => _isWeChatInstalled = installed);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
Future<void> shareAction(VideoNewModel data) async {
|
|
|
+ if (!mounted) return;
|
|
|
showModalBottomSheet(
|
|
|
context: context,
|
|
|
builder:
|
|
|
@@ -57,16 +64,9 @@ class _VideoItemWidgetState extends ConsumerState<VideoPlayItemWidget> {
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
|
children: [
|
|
|
SizedBox(height: 10.h),
|
|
|
- Container(
|
|
|
+ SizedBox(
|
|
|
width: double.infinity,
|
|
|
height: 80.h,
|
|
|
- decoration: BoxDecoration(
|
|
|
- borderRadius: BorderRadius.only(
|
|
|
- topLeft: Radius.circular(10.r),
|
|
|
- topRight: Radius.circular(10.r),
|
|
|
- ),
|
|
|
- color: Colors.white,
|
|
|
- ),
|
|
|
child: Row(
|
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
|
@@ -80,7 +80,7 @@ class _VideoItemWidgetState extends ConsumerState<VideoPlayItemWidget> {
|
|
|
url: data.shareUrl ?? "",
|
|
|
);
|
|
|
},
|
|
|
- child: Container(
|
|
|
+ child: SizedBox(
|
|
|
width: 100.w,
|
|
|
height: 80.h,
|
|
|
child: Column(
|
|
|
@@ -112,7 +112,7 @@ class _VideoItemWidgetState extends ConsumerState<VideoPlayItemWidget> {
|
|
|
url: data.shareUrl ?? "",
|
|
|
);
|
|
|
},
|
|
|
- child: Container(
|
|
|
+ child: SizedBox(
|
|
|
width: 100.w,
|
|
|
height: 80.h,
|
|
|
child: Column(
|
|
|
@@ -142,7 +142,7 @@ class _VideoItemWidgetState extends ConsumerState<VideoPlayItemWidget> {
|
|
|
url: data.shareUrl ?? "",
|
|
|
);
|
|
|
},
|
|
|
- child: Container(
|
|
|
+ child: SizedBox(
|
|
|
width: 100.w,
|
|
|
height: 80.h,
|
|
|
child: Column(
|
|
|
@@ -177,71 +177,34 @@ class _VideoItemWidgetState extends ConsumerState<VideoPlayItemWidget> {
|
|
|
void initState() {
|
|
|
super.initState();
|
|
|
_checkWeChatInstallation();
|
|
|
- _controller = BetterPlayerController(
|
|
|
- BetterPlayerConfiguration(
|
|
|
- autoPlay: false,
|
|
|
- looping: true,
|
|
|
- aspectRatio: 16 / 9,
|
|
|
- fit: BoxFit.fitWidth,
|
|
|
- controlsConfiguration: const BetterPlayerControlsConfiguration(
|
|
|
- showControls: false,
|
|
|
- ),
|
|
|
- ),
|
|
|
- betterPlayerDataSource: BetterPlayerDataSource(
|
|
|
- BetterPlayerDataSourceType.network,
|
|
|
- widget.item.url ?? "",
|
|
|
- ),
|
|
|
- );
|
|
|
- _controller.addEventsListener(_handlePlayerEvent);
|
|
|
- // 如果初始化时就是激活状态,立即播放
|
|
|
- if (widget.isActive && mounted) {
|
|
|
- _controller.play();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- void _handlePlayerEvent(BetterPlayerEvent event) {
|
|
|
- if (!mounted) return;
|
|
|
- if (event.betterPlayerEventType == BetterPlayerEventType.play ||
|
|
|
- event.betterPlayerEventType == BetterPlayerEventType.pause ||
|
|
|
- event.betterPlayerEventType == BetterPlayerEventType.finished) {
|
|
|
- final isPlaying = _controller.isPlaying() ?? false;
|
|
|
- if (mounted && isPlaying != _isPlaying) {
|
|
|
- setState(() {
|
|
|
- _isPlaying = isPlaying;
|
|
|
- });
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- @override
|
|
|
- void didUpdateWidget(covariant VideoPlayItemWidget oldWidget) {
|
|
|
- super.didUpdateWidget(oldWidget);
|
|
|
- if (!mounted) return;
|
|
|
- if (widget.isActive && !oldWidget.isActive) {
|
|
|
- _controller.play();
|
|
|
- } else if (!widget.isActive && oldWidget.isActive) {
|
|
|
- _controller.pause();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- @override
|
|
|
- void dispose() {
|
|
|
- _controller.removeEventsListener(_handlePlayerEvent);
|
|
|
- _controller.dispose();
|
|
|
- super.dispose();
|
|
|
}
|
|
|
|
|
|
void _togglePlay() {
|
|
|
if (!mounted) return;
|
|
|
+ final controller = globalVideoController;
|
|
|
+ if (controller == null) return;
|
|
|
+
|
|
|
+ // 分别处理每个操作,确保错误被捕获
|
|
|
if (_isPlaying) {
|
|
|
- _controller.pause();
|
|
|
+ try {
|
|
|
+ controller.pause();
|
|
|
+ } catch (e) {
|
|
|
+ // 控制器可能已被释放,忽略错误
|
|
|
+ }
|
|
|
} else {
|
|
|
- _controller.play();
|
|
|
+ try {
|
|
|
+ controller.play();
|
|
|
+ } catch (e) {
|
|
|
+ // 控制器可能已被释放,忽略错误
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@override
|
|
|
Widget build(BuildContext context) {
|
|
|
+ super.build(context);
|
|
|
+ final controller = globalVideoController;
|
|
|
+
|
|
|
return GestureDetector(
|
|
|
onTap: _togglePlay,
|
|
|
child: Stack(
|
|
|
@@ -249,9 +212,14 @@ class _VideoItemWidgetState extends ConsumerState<VideoPlayItemWidget> {
|
|
|
children: [
|
|
|
ColoredBox(
|
|
|
color: Colors.black,
|
|
|
- child: BetterPlayer(controller: _controller),
|
|
|
+ child: controller != null && widget.isActive
|
|
|
+ ? AspectRatio(
|
|
|
+ aspectRatio: 16 / 9,
|
|
|
+ child: BetterPlayer(controller: controller),
|
|
|
+ )
|
|
|
+ : const SizedBox.shrink(),
|
|
|
),
|
|
|
- if (!_isPlaying)
|
|
|
+ if (!_isPlaying && widget.isActive && controller != null)
|
|
|
Center(
|
|
|
child: Image.asset(
|
|
|
Assets.images.playIcon.path,
|
|
|
@@ -267,6 +235,7 @@ class _VideoItemWidgetState extends ConsumerState<VideoPlayItemWidget> {
|
|
|
children: [
|
|
|
AuthGestureDetector(
|
|
|
onTap: () {
|
|
|
+ if (!mounted) return;
|
|
|
ref
|
|
|
.read(recommendListProvider.notifier)
|
|
|
.fetchVideoLike(
|
|
|
@@ -292,6 +261,7 @@ class _VideoItemWidgetState extends ConsumerState<VideoPlayItemWidget> {
|
|
|
SizedBox(height: 15.h),
|
|
|
AuthGestureDetector(
|
|
|
onTap: () {
|
|
|
+ if (!mounted) return;
|
|
|
context.push(
|
|
|
"/video/detail",
|
|
|
extra: VideoParam(
|
|
|
@@ -313,6 +283,7 @@ class _VideoItemWidgetState extends ConsumerState<VideoPlayItemWidget> {
|
|
|
SizedBox(height: 15.h),
|
|
|
AuthGestureDetector(
|
|
|
onTap: () {
|
|
|
+ if (!mounted) return;
|
|
|
ref
|
|
|
.read(recommendListProvider.notifier)
|
|
|
.fetchVideoFavorite(
|
|
|
@@ -340,10 +311,7 @@ class _VideoItemWidgetState extends ConsumerState<VideoPlayItemWidget> {
|
|
|
SizedBox(height: 15.h),
|
|
|
GestureDetector(
|
|
|
onTap: () {
|
|
|
- // shareUrl(
|
|
|
- // title: widget.item.shareDesc ?? "",
|
|
|
- // url: widget.item.shareUrl ?? "",
|
|
|
- // );
|
|
|
+ if (!mounted) return;
|
|
|
shareAction(widget.item);
|
|
|
if (uuid.isNotEmpty) {
|
|
|
ref
|
|
|
@@ -372,4 +340,7 @@ class _VideoItemWidgetState extends ConsumerState<VideoPlayItemWidget> {
|
|
|
),
|
|
|
);
|
|
|
}
|
|
|
+
|
|
|
+ @override
|
|
|
+ bool get wantKeepAlive => true;
|
|
|
}
|