feat(app): 完善播放协议搜索与空状态
This commit is contained in:
1 parent
671e0ce143
commit
ef29fc5f15
85 files changed
+2976
-768
No files matched your search
@@ -363,7 +363,7 @@ class _PlayerPageState extends State<PlayerPage>
|
||||
final lastDoubleTapAt = _lastDoubleTapAt;
|
||||
return lastDoubleTapAt != null &&
|
||||
DateTime.now().difference(lastDoubleTapAt) <
|
||||
const Duration(milliseconds: 350);
|
||||
const Duration(milliseconds: 500);
|
||||
}
|
||||
|
||||
void _handleDoubleTapLike(
|
||||
@@ -545,14 +545,18 @@ class _PlayerPageState extends State<PlayerPage>
|
||||
(selected ? logic.session.active : null) ??
|
||||
logic.session.preparedPlayerAt(index);
|
||||
final videoPort = port is VideoPlayerPort ? port : null;
|
||||
final ready = videoPort?.controller.value.isInitialized ?? false;
|
||||
final handoff = selected ? logic.session.handoffAt(index) : null;
|
||||
final handoffPort = handoff is VideoPlayerPort ? handoff : null;
|
||||
// 测试播放器没有纹理。有播放器但不是视频控制器时视为已就绪,避免加载圈一直转。
|
||||
final videoReady = videoPort?.controller.value.isInitialized ?? false;
|
||||
final ready = videoReady || port != null;
|
||||
final theater = logic.pip || logic.pipPreparing;
|
||||
final locked = logic.session.isLocked || episode.locked;
|
||||
if (selected && ready) {
|
||||
if (selected && videoPort != null && videoPort.controller.value.isInitialized) {
|
||||
unawaited(
|
||||
_spriteAxisService.prepareAt(
|
||||
episode.thumbnailsUrl,
|
||||
videoPort!.controller.value.position,
|
||||
videoPort.controller.value.position,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -567,11 +571,30 @@ class _PlayerPageState extends State<PlayerPage>
|
||||
),
|
||||
PlayerVideoSurface(
|
||||
controller: videoPort?.controller,
|
||||
handoff: handoffPort?.controller,
|
||||
videoUrl: videoPort?.controller.dataSource ?? episode.videoUrl,
|
||||
theater: theater,
|
||||
),
|
||||
if (selected &&
|
||||
!theater &&
|
||||
!ready &&
|
||||
!logic.ticketLoading &&
|
||||
logic.ticketError == null &&
|
||||
logic.session.error == null &&
|
||||
logic.blockedEpisodeId != episode.id &&
|
||||
!logic.session.isLocked)
|
||||
const Center(
|
||||
child: SizedBox.square(
|
||||
dimension: _playerLoadingSize,
|
||||
child: CircularProgressIndicator(
|
||||
key: Key('player-video-loading'),
|
||||
color: AppColors.blue,
|
||||
strokeWidth: _playerLoadingStrokeWidth,
|
||||
),
|
||||
),
|
||||
),
|
||||
// 票据三态之一:起播前正在向后端要签名地址
|
||||
if (selected && logic.ticketLoading)
|
||||
if (selected && !theater && logic.ticketLoading)
|
||||
const Center(
|
||||
child: SizedBox.square(
|
||||
dimension: _playerLoadingSize,
|
||||
@@ -583,7 +606,10 @@ class _PlayerPageState extends State<PlayerPage>
|
||||
),
|
||||
),
|
||||
// 票据三态之二:拿票失败(断网/服务异常)→ 可重试,不假装在加载
|
||||
if (selected && !logic.ticketLoading && logic.ticketError != null)
|
||||
if (selected &&
|
||||
!theater &&
|
||||
!logic.ticketLoading &&
|
||||
logic.ticketError != null)
|
||||
Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 36),
|
||||
@@ -610,7 +636,7 @@ class _PlayerPageState extends State<PlayerPage>
|
||||
),
|
||||
),
|
||||
),
|
||||
if (selected && !ready && logic.session.error != null)
|
||||
if (selected && !theater && !ready && logic.session.error != null)
|
||||
Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 36),
|
||||
@@ -634,6 +660,7 @@ class _PlayerPageState extends State<PlayerPage>
|
||||
),
|
||||
// 没有票据信息时的兜底(例如详情里就没地址、也没走票据流程)
|
||||
if (selected &&
|
||||
!theater &&
|
||||
!ready &&
|
||||
logic.blockedEpisodeId != episode.id &&
|
||||
logic.session.error == null &&
|
||||
@@ -668,7 +695,7 @@ class _PlayerPageState extends State<PlayerPage>
|
||||
l10n: l10n,
|
||||
drama: drama,
|
||||
episode: episode,
|
||||
controller: ready ? videoPort!.controller : null,
|
||||
controller: videoReady ? videoPort!.controller : null,
|
||||
locked: locked,
|
||||
visible: _chromeVisible,
|
||||
boosting: _boosting,
|
||||
@@ -699,11 +726,11 @@ class _PlayerPageState extends State<PlayerPage>
|
||||
},
|
||||
onEpisodes: () => logic.showEpisodes(context),
|
||||
onMore: _openCurrentMore,
|
||||
onScrubStart: ready ? () => logic.beginScrub(videoPort!) : null,
|
||||
onScrubStart: videoReady ? () => logic.beginScrub(videoPort!) : null,
|
||||
onScrubEnd: _finishFeedScrub,
|
||||
onScrubVisibilityChanged: _setScrubbing,
|
||||
cancelScrubRequest: widget.scrubCancelRequest,
|
||||
onSeek: ready
|
||||
onSeek: videoReady
|
||||
? (position) => logic.endScrub(context, videoPort!, position)
|
||||
: null,
|
||||
thumbnailService: _thumbnailService,
|
||||
@@ -715,7 +742,7 @@ class _PlayerPageState extends State<PlayerPage>
|
||||
l10n: l10n,
|
||||
drama: drama,
|
||||
episode: episode,
|
||||
controller: ready ? videoPort!.controller : null,
|
||||
controller: videoReady ? videoPort!.controller : null,
|
||||
locked: locked,
|
||||
liked: interactions.isEpisodeLiked(episode.id),
|
||||
likeCount:
|
||||
@@ -751,14 +778,14 @@ class _PlayerPageState extends State<PlayerPage>
|
||||
onSave: () => unawaited(_toggleSave(context, drama)),
|
||||
onShare: () => logic.shareDrama(context, drama),
|
||||
onMore: () => _openMore(context, episode),
|
||||
onScrubStart: ready
|
||||
onScrubStart: videoReady
|
||||
? () {
|
||||
_setScrubbing(true);
|
||||
logic.beginScrub(videoPort!);
|
||||
}
|
||||
: null,
|
||||
onScrubEnd: () => _setScrubbing(false),
|
||||
onSeek: ready
|
||||
onSeek: videoReady
|
||||
? (position) => logic.seekTo(context, videoPort!, position)
|
||||
: null,
|
||||
onLongPressCenter: () => _openMore(context, episode),
|
||||
@@ -768,7 +795,10 @@ class _PlayerPageState extends State<PlayerPage>
|
||||
controlsVisible: _chromeVisible,
|
||||
),
|
||||
// 票据三态之三:后端判定不可播放 —— 用 accessType 驱动文案,不在前端猜
|
||||
if (selected && !ready && logic.blockedEpisodeId == episode.id)
|
||||
if (selected &&
|
||||
!theater &&
|
||||
!ready &&
|
||||
logic.blockedEpisodeId == episode.id)
|
||||
PlayerBlockedNotice(
|
||||
l10n: l10n,
|
||||
episode: episode,
|
||||
|
||||
Reference in new issue
Block a user