Introduces shared seams for paginated views, D-pad reorder, media control routing, async singletons and the device method channel, then points the open-coded copies at them. Also removes unused models and duplicated provider/server plumbing, folds the twice-implemented artifact store in the server, and factors the repeated Flutter toolchain prologue in CI into a composite action.
83 lines
2.6 KiB
Dart
83 lines
2.6 KiB
Dart
import 'package:os_media_controls/os_media_controls.dart';
|
|
|
|
/// Authorization boundary for user-originated OS media commands, owned by
|
|
/// whoever holds the transport (the video screen, the music session).
|
|
///
|
|
/// Lifecycle/audio-route events are handled before this router: [route]
|
|
/// reports `false` for what it does not recognize. Recognized commands are
|
|
/// consumed even when denied so they cannot reach a background route or stale
|
|
/// player owner. Both gates stay required — every owner states its policy.
|
|
final class MediaControlRouter {
|
|
const MediaControlRouter({
|
|
required this.canControlPlayback,
|
|
required this.canNavigateMediaItems,
|
|
required this.onPlay,
|
|
required this.onPause,
|
|
required this.onTogglePlayPause,
|
|
required this.onSeek,
|
|
required this.onNext,
|
|
required this.onPrevious,
|
|
required this.onStop,
|
|
required this.onSkipForward,
|
|
required this.onSkipBackward,
|
|
required this.onSetSpeed,
|
|
});
|
|
|
|
final bool Function() canControlPlayback;
|
|
final bool Function() canNavigateMediaItems;
|
|
final void Function() onPlay;
|
|
final void Function() onPause;
|
|
final void Function() onTogglePlayPause;
|
|
final void Function(Duration position) onSeek;
|
|
final void Function() onNext;
|
|
final void Function() onPrevious;
|
|
final void Function() onStop;
|
|
final void Function(Duration? interval) onSkipForward;
|
|
final void Function(Duration? interval) onSkipBackward;
|
|
final void Function(double speed) onSetSpeed;
|
|
|
|
bool route(MediaControlEvent event) {
|
|
if (event is StopEvent) {
|
|
onStop();
|
|
return true;
|
|
}
|
|
if (event is NextTrackEvent) {
|
|
if (canNavigateMediaItems()) onNext();
|
|
return true;
|
|
}
|
|
if (event is PreviousTrackEvent) {
|
|
if (canNavigateMediaItems()) onPrevious();
|
|
return true;
|
|
}
|
|
if (event is PlayEvent) {
|
|
if (canControlPlayback()) onPlay();
|
|
return true;
|
|
}
|
|
if (event is PauseEvent) {
|
|
if (canControlPlayback()) onPause();
|
|
return true;
|
|
}
|
|
if (event is TogglePlayPauseEvent) {
|
|
if (canControlPlayback()) onTogglePlayPause();
|
|
return true;
|
|
}
|
|
if (event is SeekEvent) {
|
|
if (canControlPlayback()) onSeek(event.position);
|
|
return true;
|
|
}
|
|
if (event is SkipForwardEvent) {
|
|
if (canControlPlayback()) onSkipForward(event.interval);
|
|
return true;
|
|
}
|
|
if (event is SkipBackwardEvent) {
|
|
if (canControlPlayback()) onSkipBackward(event.interval);
|
|
return true;
|
|
}
|
|
if (event is SetSpeedEvent) {
|
|
if (canControlPlayback()) onSetSpeed(event.speed);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
}
|