refactor(ui): 清理 K26 旧 UI 与死代码

This commit is contained in:
Zhou Weidong committed 2026-10-19 15:58:22 +08:00
1 parent a5398daab3
commit 5422581f8b
23 files changed
+291 -1225

No files matched your search

+3 -52
View File
@@ -3,7 +3,6 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import '../../core/data/models/drama.dart';
@@ -71,10 +70,8 @@ class PlayerLogic extends ChangeNotifier {
bool muted = false;
bool stoppedAtFeedEnd = false;
VideoPlayerPort? scrubbingPlayer;
bool fullscreen = false;
bool pip = false;
bool pipPreparing = false;
bool screenCleared = false;
final Map<String, int> pickedEpisode = {};
bool Function() isMounted = () => false;
@@ -98,9 +95,9 @@ class PlayerLogic extends ChangeNotifier {
/// dispose 不能直接碰它们(例如页面构建失败或纯逻辑测试)。
bool _started = false;
bool get immersive => fullscreen || pip || pipPreparing;
bool get immersive => pip || pipPreparing;
bool get chromeHidden => immersive || screenCleared;
bool get chromeHidden => immersive;
Episode displayEpisode(Drama drama, Episode fallback) {
final number = pickedEpisode[drama.id];
@@ -111,13 +108,6 @@ class PlayerLogic extends ChangeNotifier {
return fallback;
}
void setScreenCleared(bool value) {
if (screenCleared == value) return;
screenCleared = value;
notify();
notifyImmersive();
}
void notify() {
if (!_disposed) notifyListeners();
}
@@ -262,13 +252,7 @@ class PlayerLogic extends ChangeNotifier {
final request = backRequest;
WidgetsBinding.instance.addPostFrameCallback((_) {
if (isMounted() && backRequest == request) {
if (fullscreen) {
unawaited(setFullscreen(false));
} else if (screenCleared) {
setScreenCleared(false);
} else {
onMenu?.call();
}
onMenu?.call();
}
});
}
@@ -295,12 +279,6 @@ class PlayerLogic extends ChangeNotifier {
if (_disposed) return;
_disposed = true;
pictureInPicture.setStateListener(null);
if (fullscreen) {
unawaited(
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]),
);
unawaited(SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge));
}
unawaited(saveCurrentProgress());
if (_started) {
session.setRouteVisible(false);
@@ -313,32 +291,6 @@ class PlayerLogic extends ChangeNotifier {
void notifyImmersive() => onImmersiveChanged?.call(chromeHidden);
Future<void> setFullscreen(bool value) async {
if (fullscreen == value || !isMounted()) return;
fullscreen = value;
notify();
notifyImmersive();
try {
await SystemChrome.setPreferredOrientations(
value
? [
DeviceOrientation.landscapeLeft,
DeviceOrientation.landscapeRight,
]
: [DeviceOrientation.portraitUp],
);
await SystemChrome.setEnabledSystemUIMode(
value ? SystemUiMode.immersiveSticky : SystemUiMode.edgeToEdge,
);
} catch (_) {
if (value && isMounted()) {
fullscreen = false;
notify();
notifyImmersive();
}
}
}
Future<void> enterPip(BuildContext context) async {
if (pip || pipPreparing) return;
if (session.active is! VideoPlayerPort) {
@@ -347,7 +299,6 @@ class PlayerLogic extends ChangeNotifier {
);
return;
}
if (fullscreen) await setFullscreen(false);
pipPreparing = true;
notify();
notifyImmersive();
+3 -87
View File
@@ -162,7 +162,7 @@ class _PlayerPageState extends State<PlayerPage> with WidgetsBindingObserver {
logic.session.preparedPlayerAt(index);
final videoPort = port is VideoPlayerPort ? port : null;
final ready = videoPort?.controller.value.isInitialized ?? false;
final theater = logic.fullscreen || logic.pip || logic.pipPreparing;
final theater = logic.pip || logic.pipPreparing;
Widget? video;
if (ready) {
video = GestureDetector(
@@ -322,20 +322,7 @@ class _PlayerPageState extends State<PlayerPage> with WidgetsBindingObserver {
),
if (logic.pip || logic.pipPreparing)
const SizedBox.expand()
else if (logic.fullscreen)
_FullscreenControls(
l10n: l10n,
controller: ready ? videoPort!.controller : null,
onClose: () => unawaited(logic.setFullscreen(false)),
onPip: logic.pictureInPicture.isPlatformSupported
? () => unawaited(logic.enterPip(context))
: null,
onScrubStart: ready ? () => logic.beginScrub(videoPort!) : null,
onSeek: ready
? (position) => logic.seekTo(context, videoPort!, position)
: null,
)
else if (!logic.screenCleared && widget.homeMode)
else if (widget.homeMode)
HomeFeedOverlay(
l10n: l10n,
drama: drama,
@@ -375,13 +362,12 @@ class _PlayerPageState extends State<PlayerPage> with WidgetsBindingObserver {
onShare: () => logic.shareDrama(context, drama),
onEpisodes: () => logic.showEpisodes(context),
onDownload: () => requestEpisodeDownload(context, episode.id),
onClear: () => logic.setScreenCleared(true),
onSearch: widget.onSearch ?? () => logic.showDiscover(context),
onPip: logic.pictureInPicture.isPlatformSupported
? () => unawaited(logic.enterPip(context))
: null,
)
else if (!logic.screenCleared)
else
_PlaybackOverlay(
l10n: l10n,
drama: drama,
@@ -441,81 +427,11 @@ class _PlayerPageState extends State<PlayerPage> with WidgetsBindingObserver {
? (position) => logic.seekTo(context, videoPort!, position)
: null,
),
if (logic.screenCleared)
SafeArea(
child: Align(
alignment: Alignment.topRight,
child: Padding(
padding: const EdgeInsets.only(top: 4, right: 8),
child: IconButton(
tooltip: l10n.exitClearScreen,
onPressed: () => logic.setScreenCleared(false),
style: IconButton.styleFrom(
foregroundColor: Colors.white,
backgroundColor: const Color(0x59000000),
),
icon: const Icon(Icons.close_fullscreen_rounded),
),
),
),
),
],
);
}
}
class _FullscreenControls extends StatelessWidget {
const _FullscreenControls({
required this.l10n,
required this.controller,
required this.onClose,
required this.onPip,
required this.onScrubStart,
required this.onSeek,
});
final AppLocalizations l10n;
final VideoPlayerController? controller;
final VoidCallback onClose;
final VoidCallback? onPip;
final VoidCallback? onScrubStart;
final Future<void> Function(Duration)? onSeek;
@override
Widget build(BuildContext context) => SafeArea(
child: Column(
children: [
Row(
children: [
IconButton(
tooltip: l10n.exitFullscreen,
onPressed: onClose,
icon: const Icon(Icons.close_fullscreen_rounded),
),
const Spacer(),
if (onPip != null)
IconButton(
tooltip: l10n.pictureInPicture,
onPressed: onPip,
icon: const Icon(Icons.picture_in_picture_alt_outlined),
),
],
),
const Spacer(),
Padding(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 16),
child: SeekProgressBar(
valueListenable: controller,
semanticsLabel: l10n.seekVideo,
onScrubStart: onScrubStart,
onSeek: onSeek,
),
),
],
),
);
}
/// 不可播放提示:文案由后端返回的 `accessType` 驱动(契约 §1.4),前端不自行推断。
class _BlockedNotice extends StatelessWidget {
const _BlockedNotice({
@@ -26,7 +26,6 @@ class HomeFeedOverlay extends StatelessWidget {
required this.onShare,
required this.onEpisodes,
required this.onDownload,
required this.onClear,
required this.onSearch,
this.onPip,
});
@@ -42,7 +41,6 @@ class HomeFeedOverlay extends StatelessWidget {
final VoidCallback onShare;
final VoidCallback onEpisodes;
final VoidCallback onDownload;
final VoidCallback onClear;
final VoidCallback onSearch;
final VoidCallback? onPip;
@@ -332,18 +330,6 @@ class HomeFeedOverlay extends StatelessWidget {
onPip!();
},
),
ListTile(
key: const Key('home-feed-clear'),
leading: const Icon(
Icons.fit_screen_outlined,
color: AppColors.secondary,
),
title: Text(l10n.clearScreen),
onTap: () {
Navigator.pop(sheetContext);
onClear();
},
),
],
),
),