97 lines
2.2 KiB
Dart
97 lines
2.2 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
|
|
import 'models/models.dart';
|
|
import '../widgets/mini_player.dart';
|
|
|
|
class AudioPlayerController extends StateNotifier<PlayerStateModel> {
|
|
AudioPlayerController() : super(const PlayerStateModel());
|
|
|
|
Timer? _timer;
|
|
|
|
void startAudio({
|
|
required String audioId,
|
|
required String reportId,
|
|
required String title,
|
|
required int durationSec,
|
|
}) {
|
|
_timer?.cancel();
|
|
state = PlayerStateModel(
|
|
audioId: audioId,
|
|
reportId: reportId,
|
|
title: title,
|
|
durationSec: durationSec,
|
|
playing: true,
|
|
speed: state.speed,
|
|
);
|
|
_timer = Timer.periodic(const Duration(seconds: 1), (_) => _tick());
|
|
}
|
|
|
|
void startFromItem(AudioItem item) {
|
|
startAudio(
|
|
audioId: item.audioId,
|
|
reportId: item.reportId,
|
|
title: item.titleCn,
|
|
durationSec: item.durationSec,
|
|
);
|
|
}
|
|
|
|
void startModuleAudio(
|
|
String audioId,
|
|
String reportId,
|
|
String title,
|
|
int durationSec,
|
|
) {
|
|
startAudio(
|
|
audioId: audioId,
|
|
reportId: reportId,
|
|
title: title,
|
|
durationSec: durationSec,
|
|
);
|
|
}
|
|
|
|
void toggleAudio() {
|
|
if (!state.hasAudio) return;
|
|
state = state.copyWith(playing: !state.playing);
|
|
if (state.playing && _timer == null) {
|
|
_timer = Timer.periodic(const Duration(seconds: 1), (_) => _tick());
|
|
}
|
|
}
|
|
|
|
void seekAudio(int delta) {
|
|
if (!state.hasAudio) return;
|
|
state = state.copyWith(
|
|
positionSec: (state.positionSec + delta).clamp(0, state.durationSec),
|
|
);
|
|
}
|
|
|
|
void cycleSpeed() {
|
|
const speeds = [1.0, 1.25, 1.5, 2.0];
|
|
final current = speeds.indexOf(state.speed);
|
|
state = state.copyWith(speed: speeds[(current + 1) % speeds.length]);
|
|
}
|
|
|
|
void _tick() {
|
|
if (!state.playing) return;
|
|
final step = state.speed.round().clamp(1, 2);
|
|
final next = state.positionSec + step;
|
|
if (next >= state.durationSec) {
|
|
state = state.copyWith(
|
|
positionSec: state.durationSec,
|
|
playing: false,
|
|
);
|
|
_timer?.cancel();
|
|
_timer = null;
|
|
return;
|
|
}
|
|
state = state.copyWith(positionSec: next);
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_timer?.cancel();
|
|
super.dispose();
|
|
}
|
|
}
|