Skip to content

Commit 5e20f95

Browse files
committed
修复切片后手动弹幕偏移未重置
1 parent 853df8a commit 5e20f95

File tree

9 files changed

+57
-47
lines changed

9 files changed

+57
-47
lines changed

lib/providers/settings_provider.dart

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,12 @@ class SettingsProvider with ChangeNotifier {
1717
// 哈希匹配失败后自动选择搜索第一个结果(避免弹窗)
1818
bool _autoMatchDanmakuFirstSearchResultOnHashFail = true; // 默认开启
1919

20-
// 弹幕时间偏移设置
21-
double _danmakuTimeOffset = 0.0; // 默认无偏移,单位为秒
22-
static const String _danmakuTimeOffsetKey = 'danmaku_time_offset';
23-
2420
// --- Getters ---
2521
double get blurPower => _blurPower;
2622
bool get isBlurEnabled => _blurPower > 0;
2723
bool get danmakuConvertToSimplified => _danmakuConvertToSimplified;
2824
bool get autoMatchDanmakuFirstSearchResultOnHashFail =>
2925
_autoMatchDanmakuFirstSearchResultOnHashFail;
30-
double get danmakuTimeOffset => _danmakuTimeOffset;
3126

3227
SettingsProvider() {
3328
_loadSettings();
@@ -42,8 +37,6 @@ class SettingsProvider with ChangeNotifier {
4237
_autoMatchDanmakuFirstSearchResultOnHashFail =
4338
_prefs.getBool(SettingsKeys.autoMatchDanmakuFirstSearchResultOnHashFail) ??
4439
true;
45-
// Load danmaku time offset setting, defaulting to 0.0 if not set
46-
_danmakuTimeOffset = _prefs.getDouble(_danmakuTimeOffsetKey) ?? 0.0;
4740
notifyListeners();
4841
}
4942

@@ -83,10 +76,4 @@ class SettingsProvider with ChangeNotifier {
8376
notifyListeners();
8477
}
8578

86-
/// Sets the danmaku time offset in seconds.
87-
Future<void> setDanmakuTimeOffset(double offset) async {
88-
_danmakuTimeOffset = offset;
89-
await _prefs.setDouble(_danmakuTimeOffsetKey, _danmakuTimeOffset);
90-
notifyListeners();
91-
}
9279
}

lib/themes/cupertino/widgets/player_menu/cupertino_danmaku_offset_pane.dart

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import 'package:nipaplay/themes/cupertino/cupertino_imports.dart';
22
import 'package:provider/provider.dart';
33

4-
import 'package:nipaplay/providers/settings_provider.dart';
4+
import 'package:nipaplay/utils/video_player_state.dart';
55
import 'package:nipaplay/themes/cupertino/widgets/cupertino_bottom_sheet.dart';
66
import 'package:nipaplay/themes/cupertino/widgets/player_menu/cupertino_pane_back_button.dart';
77
import 'package:nipaplay/themes/nipaplay/widgets/blur_snackbar.dart';
@@ -45,24 +45,24 @@ class _CupertinoDanmakuOffsetPaneState
4545
return offset > 0 ? '+${offset}秒' : '${offset}秒';
4646
}
4747

48-
void _applyCustomOffset(SettingsProvider provider) {
48+
void _applyCustomOffset(VideoPlayerState videoState) {
4949
final text = _controller.text.trim();
5050
if (text.isEmpty) return;
5151
final value = double.tryParse(text);
5252
if (value == null || value < -60 || value > 60) {
5353
BlurSnackBar.show(context, '请输入 -60 到 60 之间的数字');
5454
return;
5555
}
56-
provider.setDanmakuTimeOffset(value);
56+
videoState.setManualDanmakuOffset(value);
5757
_controller.clear();
5858
BlurSnackBar.show(context, '已设置弹幕偏移为 ${_formatOffset(value)}');
5959
}
6060

6161
@override
6262
Widget build(BuildContext context) {
63-
return Consumer<SettingsProvider>(
64-
builder: (context, provider, _) {
65-
final currentOffset = provider.danmakuTimeOffset;
63+
return Consumer<VideoPlayerState>(
64+
builder: (context, videoState, _) {
65+
final currentOffset = videoState.manualDanmakuOffset;
6666
return CupertinoBottomSheetContentLayout(
6767
sliversBuilder: (context, topSpacing) => [
6868
SliverPadding(
@@ -129,7 +129,7 @@ class _CupertinoDanmakuOffsetPaneState
129129
? CupertinoTheme.of(context).primaryColor
130130
: CupertinoColors.systemGrey5,
131131
onPressed: () =>
132-
provider.setDanmakuTimeOffset(value),
132+
videoState.setManualDanmakuOffset(value),
133133
child: Text(
134134
_formatOffset(value),
135135
style: TextStyle(
@@ -161,15 +161,15 @@ class _CupertinoDanmakuOffsetPaneState
161161
signed: true,
162162
decimal: true,
163163
),
164-
onSubmitted: (_) => _applyCustomOffset(provider),
164+
onSubmitted: (_) => _applyCustomOffset(videoState),
165165
),
166166
const SizedBox(height: 8),
167167
Align(
168168
alignment: Alignment.centerRight,
169169
child: CupertinoButton(
170170
padding: const EdgeInsets.symmetric(
171171
horizontal: 20, vertical: 6),
172-
onPressed: () => _applyCustomOffset(provider),
172+
onPressed: () => _applyCustomOffset(videoState),
173173
child: const Text('应用'),
174174
),
175175
),
@@ -187,7 +187,7 @@ class _CupertinoDanmakuOffsetPaneState
187187
onTap: currentOffset == 0
188188
? null
189189
: () {
190-
provider.setDanmakuTimeOffset(0);
190+
videoState.setManualDanmakuOffset(0);
191191
BlurSnackBar.show(context, '已重置弹幕偏移');
192192
},
193193
),

lib/themes/nipaplay/widgets/danmaku_offset_menu.dart

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import 'package:flutter/material.dart';
22
import 'package:provider/provider.dart';
3-
import 'package:nipaplay/providers/settings_provider.dart';
3+
import 'package:nipaplay/utils/video_player_state.dart';
44
import 'base_settings_menu.dart';
55
import 'blur_button.dart';
66
import 'blur_snackbar.dart';
@@ -65,7 +65,8 @@ class _DanmakuOffsetMenuState extends State<DanmakuOffsetMenu> {
6565
return;
6666
}
6767

68-
Provider.of<SettingsProvider>(context, listen: false).setDanmakuTimeOffset(offset);
68+
Provider.of<VideoPlayerState>(context, listen: false)
69+
.setManualDanmakuOffset(offset);
6970
FocusScope.of(context).unfocus();
7071
_customOffsetController.clear();
7172
setState(() {
@@ -85,8 +86,8 @@ class _DanmakuOffsetMenuState extends State<DanmakuOffsetMenu> {
8586
child: InkWell(
8687
borderRadius: BorderRadius.circular(8),
8788
onTap: () {
88-
Provider.of<SettingsProvider>(context, listen: false)
89-
.setDanmakuTimeOffset(offset);
89+
Provider.of<VideoPlayerState>(context, listen: false)
90+
.setManualDanmakuOffset(offset);
9091
},
9192
child: Container(
9293
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
@@ -115,8 +116,8 @@ style: TextStyle(
115116

116117
@override
117118
Widget build(BuildContext context) {
118-
return Consumer<SettingsProvider>(
119-
builder: (context, settingsProvider, child) {
119+
return Consumer<VideoPlayerState>(
120+
builder: (context, videoState, child) {
120121
return BaseSettingsMenu(
121122
title: '弹幕偏移',
122123
onClose: widget.onClose,
@@ -154,17 +155,17 @@ style: TextStyle(
154155
mainAxisAlignment: MainAxisAlignment.center,
155156
children: [
156157
Icon(
157-
settingsProvider.danmakuTimeOffset > 0
158+
videoState.manualDanmakuOffset > 0
158159
? Icons.fast_forward
159-
: settingsProvider.danmakuTimeOffset < 0
160+
: videoState.manualDanmakuOffset < 0
160161
? Icons.fast_rewind
161162
: Icons.sync,
162163
color: Colors.white,
163164
size: 20,
164165
),
165166
const SizedBox(width: 8),
166167
Text(
167-
_formatOffset(settingsProvider.danmakuTimeOffset),
168+
_formatOffset(videoState.manualDanmakuOffset),
168169
style: const TextStyle(
169170
color: Colors.white,
170171
fontSize: 18,
@@ -176,10 +177,10 @@ style: TextStyle(
176177
),
177178
const SizedBox(height: 8),
178179
SettingsHintText(
179-
settingsProvider.danmakuTimeOffset > 0
180-
? '弹幕将提前${settingsProvider.danmakuTimeOffset}秒显示'
181-
: settingsProvider.danmakuTimeOffset < 0
182-
? '弹幕将延后${(-settingsProvider.danmakuTimeOffset)}秒显示'
180+
videoState.manualDanmakuOffset > 0
181+
? '弹幕将提前${videoState.manualDanmakuOffset}秒显示'
182+
: videoState.manualDanmakuOffset < 0
183+
? '弹幕将延后${(-videoState.manualDanmakuOffset)}秒显示'
183184
: '弹幕按原始时间显示',
184185
),
185186
],
@@ -216,7 +217,7 @@ style: TextStyle(
216217
children: _offsetOptions
217218
.where((offset) => offset < 0)
218219
.map((offset) => _buildOffsetButton(
219-
offset, settingsProvider.danmakuTimeOffset))
220+
offset, videoState.manualDanmakuOffset))
220221
.toList(),
221222
),
222223
const SizedBox(height: 8),
@@ -231,7 +232,7 @@ style: TextStyle(
231232
),
232233
),
233234
const SizedBox(height: 4),
234-
_buildOffsetButton(0, settingsProvider.danmakuTimeOffset),
235+
_buildOffsetButton(0, videoState.manualDanmakuOffset),
235236
const SizedBox(height: 8),
236237

237238
// 前进选项
@@ -248,7 +249,7 @@ style: TextStyle(
248249
children: _offsetOptions
249250
.where((offset) => offset > 0)
250251
.map((offset) => _buildOffsetButton(
251-
offset, settingsProvider.danmakuTimeOffset))
252+
offset, videoState.manualDanmakuOffset))
252253
.toList(),
253254
),
254255
],

lib/utils/player_kernel_manager.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,11 @@ class PlayerKernelManager {
6060
await videoPlayerState.applyHardwareDecoderPreference();
6161

6262
// 4. 重新初始化播放
63-
await videoPlayerState.initializePlayer(currentPath,
64-
historyItem: historyItem);
63+
await videoPlayerState.initializePlayer(
64+
currentPath,
65+
historyItem: historyItem,
66+
resetManualDanmakuOffset: false,
67+
);
6568

6669
// 5. 恢复播放状态
6770
if (videoPlayerState.hasVideo) {

lib/utils/video_player_state.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,7 @@ class VideoPlayerState extends ChangeNotifier implements WindowListener {
394394
final double _maxDanmakuSpeedMultiplier = 2.0;
395395
final double _baseDanmakuScrollDurationSeconds = 10.0;
396396
double _danmakuSpeedMultiplier = 1.0; // 默认标准速度
397+
double _manualDanmakuOffset = 0.0; // 手动设置的弹幕偏移
397398
double _autoDanmakuOffset = 0.0; // 弹弹Play自动匹配的时间偏移
398399

399400
// 添加播放速度相关状态
@@ -651,6 +652,7 @@ class VideoPlayerState extends ChangeNotifier implements WindowListener {
651652
double get danmakuScrollDurationSeconds =>
652653
_baseDanmakuScrollDurationSeconds / _danmakuSpeedMultiplier;
653654
bool get danmakuStacking => _danmakuStacking;
655+
double get manualDanmakuOffset => _manualDanmakuOffset;
654656
double get autoDanmakuOffset => _autoDanmakuOffset;
655657
bool get pauseOnBackground => _pauseOnBackground;
656658
Anime4KProfile get anime4kProfile => _anime4kProfile;
@@ -721,6 +723,14 @@ class VideoPlayerState extends ChangeNotifier implements WindowListener {
721723
// Volume Getters
722724
double get currentSystemVolume => _currentVolume;
723725

726+
void setManualDanmakuOffset(double offset) {
727+
if ((_manualDanmakuOffset - offset).abs() < 0.0001) {
728+
return;
729+
}
730+
_manualDanmakuOffset = offset;
731+
notifyListeners();
732+
}
733+
724734
void _setAutoDanmakuOffset(double offset) {
725735
if ((_autoDanmakuOffset - offset).abs() < 0.0001) {
726736
return;

lib/utils/video_player_state/video_player_state_player_setup.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,17 @@ extension VideoPlayerStatePlayerSetup on VideoPlayerState {
55
{WatchHistoryItem? historyItem,
66
String? historyFilePath,
77
String? actualPlayUrl,
8-
PlaybackSession? playbackSession}) async {
8+
PlaybackSession? playbackSession,
9+
bool resetManualDanmakuOffset = true}) async {
910
// 每次切换新视频时,重置自动连播倒计时状态,防止高强度测试下卡死
1011
try {
1112
AutoNextEpisodeService.instance.cancelAutoNext();
1213
} catch (e) {
1314
debugPrint('[自动连播] 重置AutoNextEpisodeService状态失败: $e');
1415
}
16+
if (resetManualDanmakuOffset) {
17+
setManualDanmakuOffset(0.0);
18+
}
1519
if (_status == PlayerStatus.loading ||
1620
_status == PlayerStatus.recognizing) {
1721
_setStatus(PlayerStatus.idle,

lib/utils/video_player_state/video_player_state_preferences.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,11 @@ extension VideoPlayerStatePreferences on VideoPlayerState {
3434
_currentVideoPath = null; // 清空路径,避免重复初始化
3535
_danmakuOverlayKey = 'idle'; // 临时重置弹幕覆盖层key
3636
await Future.delayed(const Duration(seconds: 1)); // 等待一秒
37-
await initializePlayer(path, actualPlayUrl: actualUrl);
37+
await initializePlayer(
38+
path,
39+
actualPlayUrl: actualUrl,
40+
resetManualDanmakuOffset: false,
41+
);
3842
} else {
3943
_setStatus(PlayerStatus.idle, message: '请重新选择视频');
4044
}

lib/utils/video_player_state/video_player_state_streaming.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,7 @@ extension JellyfinQualitySwitch on VideoPlayerState {
463463
currentPath,
464464
historyItem: historyItem,
465465
playbackSession: newSession,
466+
resetManualDanmakuOffset: false,
466467
);
467468

468469
// 恢复播放状态(等待状态稳定后再操作)
@@ -544,6 +545,7 @@ extension EmbyQualitySwitch on VideoPlayerState {
544545
currentPath,
545546
historyItem: historyItem,
546547
playbackSession: newSession,
548+
resetManualDanmakuOffset: false,
547549
);
548550

549551
if (hasVideo) {

lib/widgets/danmaku_overlay.dart

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import 'package:nipaplay/danmaku_gpu/lib/gpu_danmaku_config.dart';
66
import 'package:danmaku_canvas/canvas_danmaku_renderer.dart';
77
import 'package:provider/provider.dart';
88
import 'package:nipaplay/utils/video_player_state.dart';
9-
import 'package:nipaplay/providers/settings_provider.dart';
109
import '../danmaku_abstraction/danmaku_kernel_factory.dart';
1110

1211
class DanmakuOverlay extends StatefulWidget {
@@ -40,11 +39,11 @@ class _DanmakuOverlayState extends State<DanmakuOverlay> {
4039
// 弹幕不可见时,彻底不构建,避免文本排版消耗
4140
return const SizedBox.shrink();
4241
}
43-
return Consumer2<VideoPlayerState, SettingsProvider>(
44-
builder: (context, videoState, settingsProvider, child) {
42+
return Consumer<VideoPlayerState>(
43+
builder: (context, videoState, child) {
4544
final kernelType = DanmakuKernelFactory.getKernelType();
4645
final combinedTimeOffset =
47-
settingsProvider.danmakuTimeOffset + videoState.autoDanmakuOffset;
46+
videoState.manualDanmakuOffset + videoState.autoDanmakuOffset;
4847

4948
// 直接从videoState获取已处理好的弹幕列表
5049
final activeDanmakuList = videoState.danmakuList;

0 commit comments

Comments
 (0)