Files
sm-emby-share/lib/features/player/player_page_danmaku.dart
T
2026-07-14 11:11:36 +08:00

165 lines
4.9 KiB
Dart

part of 'player_page.dart';
bool _isDanmakuLayoutChange(DanmakuPanelSettings a, DanmakuPanelSettings b) {
return a.maxRows != b.maxRows ||
a.fontSize != b.fontSize ||
a.lineHeight != b.lineHeight ||
a.fontFamily != b.fontFamily ||
a.area != b.area;
}
void _syncDanmakuFeederForSession(
DanmakuFeeder feeder,
PlaybackSession session,
double posSec, {
bool clear = false,
}) {
feeder.seekTo(posSec, clear: clear);
if (session.isDanmakuActive) {
feeder.playFrom(posSec);
} else {
feeder.freezeAt(posSec);
}
}
extension _PlayerPageDanmaku on _PlayerPageState {
DanmakuOption _buildDanmakuOption(DanmakuPanelSettings settings) {
final base = settings.toDanmakuOption(screenHeight: _danmakuOverlayHeight);
if (_playbackRate == 1.0 || _playbackRate <= 0) return base;
return base.copyWith(duration: base.duration / _playbackRate);
}
void _applyDanmakuPanelSettings(DanmakuPanelSettings settings) {
_panelSettings = settings;
_feeder.setPanelSettings(settings, option: _buildDanmakuOption(settings));
}
void _wireDanmakuListeners() {
final session = ref.read(danmakuSessionProvider).value;
if (session != null) {
_sessionState = session;
if (session is DanmakuSessionMatched &&
session.commentStatus == DanmakuCommentStatus.ready &&
!identical(session, _lastSyncedDanmakuSession)) {
_lastSyncedDanmakuSession = session;
_feeder.setComments(session.comments);
final s = _session;
if (s != null) {
_syncDanmakuFeederForSession(
_feeder,
s,
s.engine.state.position.inMilliseconds / 1000.0,
);
}
}
}
final settingsPanel = ref
.read(danmakuSettingsProvider)
.value
?.panelSettings;
if (settingsPanel != null && settingsPanel != _panelSettings) {
_applyDanmakuPanelSettings(settingsPanel);
}
ref.listen<AsyncValue<DanmakuSessionState>>(danmakuSessionProvider, (
prev,
next,
) {
final state = next.value;
if (state == null) return;
_sessionState = state;
if (state is DanmakuSessionMatched &&
state.commentStatus == DanmakuCommentStatus.ready) {
_lastSyncedDanmakuSession = state;
_feeder.setComments(state.comments);
final s = _session;
if (s != null) {
final posSec = s.engine.state.position.inMilliseconds / 1000.0;
_syncDanmakuFeederForSession(_feeder, s, posSec);
}
} else {
_lastSyncedDanmakuSession = null;
_feeder.setComments(const []);
}
_invalidateBottomBar();
_refreshPanel();
_invalidateDanmakuOverlay();
});
ref.listen<AsyncValue<DanmakuSettingsState>>(danmakuSettingsProvider, (
prev,
next,
) {
final settings = next.value;
if (settings == null) return;
final newPanel = settings.panelSettings;
final oldPanel = _panelSettings;
final panelChanged = oldPanel != newPanel;
final previousSettings = prev?.value;
final keywordsChanged =
previousSettings != null &&
!listEquals(
previousSettings.blockedKeywords,
settings.blockedKeywords,
);
final enabledChanged = oldPanel.enabled != newPanel.enabled;
final offsetChanged = oldPanel.offset != newPanel.offset;
final layoutChanged = _isDanmakuLayoutChange(oldPanel, newPanel);
final opacityChanged = oldPanel.opacity != newPanel.opacity;
if (panelChanged) {
_applyDanmakuPanelSettings(newPanel);
if (enabledChanged) {
_invalidateBottomBar();
}
_invalidateDanmakuOverlay();
final s = _session;
if ((enabledChanged ||
offsetChanged ||
layoutChanged ||
opacityChanged) &&
s != null) {
final posSec = s.engine.state.position.inMilliseconds / 1000.0;
_syncDanmakuFeederForSession(_feeder, s, posSec, clear: true);
}
}
if (panelChanged || keywordsChanged) {
_refreshPanel();
}
});
}
bool get _danmakuLoaded =>
_sessionState is DanmakuSessionMatched ||
_sessionState is DanmakuSessionEmpty;
bool get _danmakuSearching =>
_sessionState is DanmakuSessionMatching ||
(_sessionState is DanmakuSessionMatched &&
(_sessionState as DanmakuSessionMatched).commentStatus ==
DanmakuCommentStatus.loading);
List<DanmakuMatchCandidate> get _danmakuMatches {
final s = _sessionState;
return s is DanmakuSessionMatched ? s.matches : const [];
}
int get _danmakuSelectedMatchIndex {
final s = _sessionState;
return s is DanmakuSessionMatched ? s.selectedIndex : -1;
}
int get _danmakuCommentCount {
final s = _sessionState;
return s is DanmakuSessionMatched ? s.comments.length : 0;
}
}