Initial commit
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import '../../../core/infra/pip/android_pip_controller.dart';
|
||||
import '../../../shared/utils/app_logger.dart';
|
||||
|
||||
const _tag = 'AndroidPipManager';
|
||||
|
||||
|
||||
class AndroidPipManager {
|
||||
AndroidPipManager({required this._onStateChanged});
|
||||
|
||||
final VoidCallback _onStateChanged;
|
||||
|
||||
bool _isInPip = false;
|
||||
bool _isDisposed = false;
|
||||
bool _supported = false;
|
||||
StreamSubscription<bool>? _modeSub;
|
||||
StreamSubscription<PipAction>? _actionSub;
|
||||
|
||||
|
||||
void Function(PipAction action)? onAction;
|
||||
|
||||
bool get isInPip => _isInPip;
|
||||
bool get isSupported => _supported;
|
||||
|
||||
|
||||
Future<void> initialize() async {
|
||||
if (!Platform.isAndroid) return;
|
||||
final supported = await AndroidPipController.instance.isSupported();
|
||||
if (_isDisposed) return;
|
||||
if (_supported != supported) {
|
||||
_supported = supported;
|
||||
_onStateChanged();
|
||||
}
|
||||
if (!_supported) return;
|
||||
if (_modeSub != null || _actionSub != null) return;
|
||||
|
||||
final isInPip = await AndroidPipController.instance.isInPipMode();
|
||||
if (_isDisposed) return;
|
||||
if (_isInPip != isInPip) {
|
||||
_isInPip = isInPip;
|
||||
_onStateChanged();
|
||||
}
|
||||
|
||||
_modeSub = AndroidPipController.instance.pipModeChanges.listen(
|
||||
(isInPip) {
|
||||
if (_isDisposed) return;
|
||||
if (_isInPip == isInPip) return;
|
||||
_isInPip = isInPip;
|
||||
AppLogger.info(_tag, 'PiP mode changed: $isInPip');
|
||||
_onStateChanged();
|
||||
},
|
||||
onError: (Object e) {
|
||||
AppLogger.warn(_tag, 'PiP mode stream error', e);
|
||||
},
|
||||
);
|
||||
|
||||
_actionSub = AndroidPipController.instance.actionStream.listen(
|
||||
(action) {
|
||||
if (_isDisposed) return;
|
||||
AppLogger.debug(_tag, 'PiP action: $action');
|
||||
onAction?.call(action);
|
||||
},
|
||||
onError: (Object e) {
|
||||
AppLogger.warn(_tag, 'PiP action stream error', e);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Future<void> configure({
|
||||
int aspectX = 16,
|
||||
int aspectY = 9,
|
||||
bool autoEnterOnLeave = false,
|
||||
bool isPlaying = false,
|
||||
bool hasNext = false,
|
||||
bool hasPrev = false,
|
||||
bool useEpisodeActions = true,
|
||||
}) async {
|
||||
if (!_supported || _isDisposed) return;
|
||||
await AndroidPipController.instance.configure(
|
||||
aspectX: aspectX,
|
||||
aspectY: aspectY,
|
||||
autoEnterOnLeave: autoEnterOnLeave,
|
||||
isPlaying: isPlaying,
|
||||
hasNext: hasNext,
|
||||
hasPrev: hasPrev,
|
||||
useEpisodeActions: useEpisodeActions,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Future<bool> enter({int? aspectX, int? aspectY}) async {
|
||||
if (!_supported || _isDisposed || _isInPip) return false;
|
||||
return AndroidPipController.instance.enterPip(
|
||||
aspectX: aspectX,
|
||||
aspectY: aspectY,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Future<void> updatePlaybackState({
|
||||
required bool isPlaying,
|
||||
required bool hasNext,
|
||||
required bool hasPrev,
|
||||
required bool useEpisodeActions,
|
||||
}) async {
|
||||
if (!_supported || _isDisposed || !_isInPip) return;
|
||||
await AndroidPipController.instance.updatePlaybackState(
|
||||
isPlaying: isPlaying,
|
||||
hasNext: hasNext,
|
||||
hasPrev: hasPrev,
|
||||
useEpisodeActions: useEpisodeActions,
|
||||
);
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
if (_isDisposed) return;
|
||||
_isDisposed = true;
|
||||
final modeSub = _modeSub;
|
||||
_modeSub = null;
|
||||
final actionSub = _actionSub;
|
||||
_actionSub = null;
|
||||
onAction = null;
|
||||
unawaited(() async {
|
||||
await AndroidPipController.instance.configure(
|
||||
autoEnterOnLeave: false,
|
||||
isPlaying: false,
|
||||
);
|
||||
await modeSub?.cancel();
|
||||
await actionSub?.cancel();
|
||||
await AndroidPipController.instance.dispose();
|
||||
}());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user