refactor: create audio player wrapper and remove just_audio (again)

This commit is contained in:
Kingkor Roy Tirtho 2023-04-30 23:16:55 +06:00
parent 7df2a0daba
commit 12915f3e5a
17 changed files with 304 additions and 148 deletions

View File

@ -27,8 +27,12 @@ class PlayPauseAction extends Action<PlayPauseIntent> {
final playlistNotifier = intent.ref.read(PlaylistQueueNotifier.notifier);
if (playlist == null) {
return null;
} else if (!PlaylistQueueNotifier.isPlaying) {
} else if (!audioPlayer.isPlaying) {
if (audioPlayer.hasSource && !audioPlayer.isCompleted) {
await playlistNotifier.resume();
} else {
await playlistNotifier.play();
}
} else {
await playlistNotifier.pause();
}
@ -103,8 +107,7 @@ class SeekAction extends Action<SeekIntent> {
);
return null;
}
final position =
(await audioPlayer.getCurrentPosition() ?? Duration.zero).inSeconds;
final position = (await audioPlayer.position ?? Duration.zero).inSeconds;
await playlistNotifier.seek(
Duration(
seconds: intent.forward ? position + 5 : position - 5,

View File

@ -7,6 +7,7 @@ import 'package:spotube/components/shared/playbutton_card.dart';
import 'package:spotube/hooks/use_breakpoint_value.dart';
import 'package:spotube/provider/playlist_queue_provider.dart';
import 'package:spotube/provider/spotify_provider.dart';
import 'package:spotube/services/audio_player.dart';
import 'package:spotube/utils/service_utils.dart';
import 'package:spotube/utils/type_conversion_utils.dart';
@ -41,8 +42,7 @@ class AlbumCard extends HookConsumerWidget {
@override
Widget build(BuildContext context, ref) {
final playlist = ref.watch(PlaylistQueueNotifier.provider);
final playing = useStream(PlaylistQueueNotifier.playing).data ??
PlaylistQueueNotifier.isPlaying;
final playing = useStream(audioPlayer.playingStream).data ?? false;
final playlistNotifier = ref.watch(PlaylistQueueNotifier.notifier);
final queryClient = useQueryClient();
final query = queryClient

View File

@ -10,6 +10,7 @@ import 'package:spotube/extensions/context.dart';
import 'package:spotube/hooks/use_progress.dart';
import 'package:spotube/models/logger.dart';
import 'package:spotube/provider/playlist_queue_provider.dart';
import 'package:spotube/services/audio_player.dart';
import 'package:spotube/utils/primitive_utils.dart';
class PlayerControls extends HookConsumerWidget {
@ -43,9 +44,8 @@ class PlayerControls extends HookConsumerWidget {
[]);
final playlist = ref.watch(PlaylistQueueNotifier.provider);
final playlistNotifier = ref.watch(PlaylistQueueNotifier.notifier);
final playing = useStream(PlaylistQueueNotifier.playing).data ??
PlaylistQueueNotifier.isPlaying;
final buffering = useStream(playlistNotifier.buffering).data ?? true;
final playing = useStream(audioPlayer.playingStream).data ?? false;
final buffering = useStream(audioPlayer.bufferingStream).data ?? true;
final theme = Theme.of(context);
final isDominantColorDark = ThemeData.estimateBrightnessForColor(
@ -141,6 +141,7 @@ class PlayerControls extends HookConsumerWidget {
// there's an edge case for value being bigger
// than total duration. Keeping it resolved
value: progress.value.toDouble(),
secondaryTrackValue: progressObj.item4,
onChanged: playlist?.isLoading == true || buffering
? null
: (v) {
@ -154,6 +155,7 @@ class PlayerControls extends HookConsumerWidget {
);
},
activeColor: sliderColor,
secondaryActiveColor: sliderColor.withOpacity(0.2),
inactiveColor: sliderColor.withOpacity(0.15),
),
),

View File

@ -10,6 +10,7 @@ import 'package:spotube/components/player/player_track_details.dart';
import 'package:spotube/collections/intents.dart';
import 'package:spotube/hooks/use_progress.dart';
import 'package:spotube/provider/playlist_queue_provider.dart';
import 'package:spotube/services/audio_player.dart';
import 'package:spotube/utils/service_utils.dart';
class PlayerOverlay extends HookConsumerWidget {
@ -27,8 +28,7 @@ class PlayerOverlay extends HookConsumerWidget {
);
final playlistNotifier = ref.watch(PlaylistQueueNotifier.notifier);
final playlist = ref.watch(PlaylistQueueNotifier.provider);
final playing = useStream(PlaylistQueueNotifier.playing).data ??
PlaylistQueueNotifier.isPlaying;
final playing = useStream(audioPlayer.playingStream).data ?? false;
final theme = Theme.of(context);
final textColor = theme.colorScheme.primary;

View File

@ -6,6 +6,7 @@ import 'package:spotify/spotify.dart';
import 'package:spotube/components/shared/playbutton_card.dart';
import 'package:spotube/provider/playlist_queue_provider.dart';
import 'package:spotube/provider/spotify_provider.dart';
import 'package:spotube/services/audio_player.dart';
import 'package:spotube/services/queries/queries.dart';
import 'package:spotube/utils/service_utils.dart';
import 'package:spotube/utils/type_conversion_utils.dart';
@ -20,8 +21,7 @@ class PlaylistCard extends HookConsumerWidget {
Widget build(BuildContext context, ref) {
final playlistQueue = ref.watch(PlaylistQueueNotifier.provider);
final playlistNotifier = ref.watch(PlaylistQueueNotifier.notifier);
final playing = useStream(PlaylistQueueNotifier.playing).data ??
PlaylistQueueNotifier.isPlaying;
final playing = useStream(audioPlayer.playingStream).data ?? false;
final queryBowl = QueryClient.of(context);
final query = queryBowl.getQuery<List<Track>, dynamic>(
"playlist-tracks/${playlist.id}",

View File

@ -2,16 +2,18 @@ import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/provider/playlist_queue_provider.dart';
import 'package:spotube/services/audio_player.dart';
import 'package:tuple/tuple.dart';
Tuple3<double, Duration, Duration> useProgress(WidgetRef ref) {
Tuple4<double, Duration, Duration, double> useProgress(WidgetRef ref) {
ref.watch(PlaylistQueueNotifier.provider);
final bufferProgress =
useStream(audioPlayer.bufferedPositionStream).data?.inSeconds ?? 0;
final playlistNotifier = ref.watch(PlaylistQueueNotifier.notifier);
final duration =
useStream(PlaylistQueueNotifier.duration).data ?? Duration.zero;
final positionSnapshot = useStream(PlaylistQueueNotifier.position);
final duration = useStream(audioPlayer.durationStream).data ?? Duration.zero;
final positionSnapshot = useStream(audioPlayer.positionStream);
final position = positionSnapshot.data ?? Duration.zero;
@ -31,9 +33,12 @@ Tuple3<double, Duration, Duration> useProgress(WidgetRef ref) {
return null;
}, [positionSnapshot.hasData, duration]);
return Tuple3(
return Tuple4(
sliderMax == 0 || sliderValue > sliderMax ? 0 : sliderValue / sliderMax,
position,
duration,
sliderMax == 0 || bufferProgress > sliderMax
? 0
: bufferProgress / sliderMax,
);
}

View File

@ -1,13 +1,13 @@
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:spotube/provider/playlist_queue_provider.dart';
import 'package:spotube/services/audio_player.dart';
int useSyncedLyrics(
WidgetRef ref,
Map<int, String> lyricsMap,
int delay,
) {
final stream = PlaylistQueueNotifier.position;
final stream = audioPlayer.positionStream;
final currentTime = useState(0);

View File

@ -71,6 +71,7 @@ Future<void> main(List<String> rawArgs) async {
}
WidgetsFlutterBinding.ensureInitialized();
await DesktopTools.ensureInitialized(
DesktopWindowOptions(
hideTitleBar: true,

View File

@ -1,6 +1,5 @@
import 'dart:async';
import 'package:audioplayers/audioplayers.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:palette_generator/palette_generator.dart';
@ -140,8 +139,6 @@ class PlaylistQueueNotifier extends PersistedStateNotifier<PlaylistQueue?> {
late AudioServices audioServices;
final StreamController<bool> _bufferingController;
static final provider =
StateNotifierProvider<PlaylistQueueNotifier, PlaylistQueue?>(
(ref) => PlaylistQueueNotifier._(ref),
@ -149,16 +146,14 @@ class PlaylistQueueNotifier extends PersistedStateNotifier<PlaylistQueue?> {
static final notifier = provider.notifier;
PlaylistQueueNotifier._(this.ref)
: _bufferingController = StreamController.broadcast(),
super(null, "playlist") {
PlaylistQueueNotifier._(this.ref) : super(null, "playlist") {
configure();
}
void configure() async {
audioServices = await AudioServices.create(ref, this);
audioPlayer.onPlayerComplete.listen((event) async {
audioPlayer.completedStream.listen((event) async {
if (!isLoaded) return;
if (state!.isLooping) {
await audioPlayer.seek(Duration.zero);
@ -170,10 +165,9 @@ class PlaylistQueueNotifier extends PersistedStateNotifier<PlaylistQueue?> {
bool isPreSearching = false;
audioPlayer.onPositionChanged.listen((pos) async {
audioPlayer.positionStream.listen((pos) async {
if (!isLoaded) return;
_bufferingController.add(false);
final currentDuration = await audioPlayer.getDuration() ?? Duration.zero;
final currentDuration = await audioPlayer.duration ?? Duration.zero;
// skip all the activeTrack.skipSegments
if (state?.isLoading != true &&
@ -199,18 +193,16 @@ class PlaylistQueueNotifier extends PersistedStateNotifier<PlaylistQueue?> {
!isPreSearching) {
isPreSearching = true;
final tracks = state!.tracks.toList();
tracks[state!.active + 1] = await SpotubeTrack.fetchFromTrack(
final newTrack = await SpotubeTrack.fetchFromTrack(
state!.tracks.elementAt(state!.active + 1),
preferences,
);
tracks[state!.active + 1] = newTrack;
await audioPlayer.preload(newTrack.ytUri);
state = state!.copyWith(tracks: Set.from(tracks));
isPreSearching = false;
}
});
audioPlayer.onSeekComplete.listen((event) {
_bufferingController.add(false);
});
}
// properties
@ -222,31 +214,6 @@ class PlaylistQueueNotifier extends PersistedStateNotifier<PlaylistQueue?> {
bool get isLoaded => state != null;
Stream<bool> get buffering =>
_bufferingController.stream.asyncMap((bufferEvent) async {
final duration = await audioPlayer.getDuration();
final position = await audioPlayer.getCurrentPosition();
final isBuffering = state?.activeTrack is! SpotubeTrack &&
audioPlayer.state == PlayerState.playing &&
(bufferEvent || (duration == null && position == null));
return isBuffering;
});
Future<bool> get isBuffering => buffering.first;
// redirectors
static bool get isPlaying => audioPlayer.state == PlayerState.playing;
static bool get isPaused => audioPlayer.state == PlayerState.paused;
static bool get isStopped => audioPlayer.state == PlayerState.stopped;
static Stream<Duration> get duration =>
audioPlayer.onDurationChanged.asBroadcastStream();
static Stream<Duration> get position =>
audioPlayer.onPositionChanged.asBroadcastStream();
static Stream<bool> get playing => audioPlayer.onPlayerStateChanged
.map((event) => event == PlayerState.playing)
.asBroadcastStream();
List<Video> get siblings => state?.isLoading == false
? (state!.activeTrack as SpotubeTrack).siblings
: [];
@ -360,14 +327,10 @@ class PlaylistQueueNotifier extends PersistedStateNotifier<PlaylistQueue?> {
Future<void> play() async {
if (!isLoaded) return;
_bufferingController.add(true);
await pause();
await audioServices.addTrack(state!.activeTrack);
if (state!.activeTrack is LocalTrack) {
await audioPlayer.play(
DeviceFileSource((state!.activeTrack as LocalTrack).path),
mode: PlayerMode.mediaPlayer,
);
await audioPlayer.play((state!.activeTrack as LocalTrack).path);
return;
}
if (state!.activeTrack is! SpotubeTrack) {
@ -392,15 +355,9 @@ class PlaylistQueueNotifier extends PersistedStateNotifier<PlaylistQueue?> {
final cached =
await DefaultCacheManager().getFileFromCache(state!.activeTrack.id!);
if (preferences.predownload && cached != null) {
await audioPlayer.play(
DeviceFileSource(cached.file.path),
mode: PlayerMode.mediaPlayer,
);
await audioPlayer.play(cached.file.path);
} else {
await audioPlayer.play(
UrlSource((state!.activeTrack as SpotubeTrack).ytUri),
mode: PlayerMode.mediaPlayer,
);
await audioPlayer.play((state!.activeTrack as SpotubeTrack).ytUri);
}
}
@ -475,7 +432,6 @@ class PlaylistQueueNotifier extends PersistedStateNotifier<PlaylistQueue?> {
Future<void> seek(Duration position) async {
if (!isLoaded) return;
_bufferingController.add(true);
await audioPlayer.seek(position);
await resume();
}

View File

@ -212,7 +212,7 @@ class UserPreferences extends PersistedChangeNotifier {
showSystemTrayIcon = map["showSystemTrayIcon"] ?? showSystemTrayIcon;
final localeMap = jsonDecode(map["locale"]);
final localeMap = map["locale"] != null ? jsonDecode(map["locale"]) : null;
locale =
localeMap != null ? Locale(localeMap?["lc"], localeMap?["cc"]) : locale;
}

View File

@ -1,25 +1,244 @@
import 'package:audioplayers/audioplayers.dart';
import 'dart:async';
final audioPlayer = (() {
AudioPlayer.global.setAudioContext(
const AudioContext(
android: AudioContextAndroid(
audioFocus: AndroidAudioFocus.gain,
audioMode: AndroidAudioMode.inCall,
contentType: AndroidContentType.music,
stayAwake: true,
usageType: AndroidUsageType.media,
),
iOS: AudioContextIOS(
category: AVAudioSessionCategory.playback,
options: [
AVAudioSessionOptions.allowBluetooth,
AVAudioSessionOptions.allowBluetoothA2DP,
AVAudioSessionOptions.defaultToSpeaker,
AVAudioSessionOptions.mixWithOthers,
],
),
),
);
return AudioPlayer();
})();
import 'package:audioplayers/audioplayers.dart' as ap;
final audioPlayer = SpotubeAudioPlayer();
enum PlayerState {
playing,
paused,
completed,
buffering,
stopped;
static PlayerState fromApPlayerState(ap.PlayerState state) {
switch (state) {
case ap.PlayerState.playing:
return PlayerState.playing;
case ap.PlayerState.paused:
return PlayerState.paused;
case ap.PlayerState.stopped:
return PlayerState.stopped;
case ap.PlayerState.completed:
return PlayerState.completed;
}
}
ap.PlayerState get asAudioPlayerPlayerState {
switch (this) {
case PlayerState.playing:
return ap.PlayerState.playing;
case PlayerState.paused:
return ap.PlayerState.paused;
case PlayerState.stopped:
return ap.PlayerState.stopped;
case PlayerState.completed:
return ap.PlayerState.completed;
case PlayerState.buffering:
return ap.PlayerState.paused;
}
}
}
class SpotubeAudioPlayer {
final ap.AudioPlayer? _audioPlayer;
SpotubeAudioPlayer()
: _audioPlayer = apSupportedPlatform ? ap.AudioPlayer() : null;
/// Whether the current platform supports the audioplayers plugin
static const bool apSupportedPlatform = true;
// stream getters
Stream<Duration> get durationStream {
if (apSupportedPlatform) {
return _audioPlayer!.onDurationChanged;
} else {
throw UnimplementedError();
}
}
Stream<Duration> get positionStream {
if (apSupportedPlatform) {
return _audioPlayer!.onPositionChanged;
} else {
throw UnimplementedError();
}
}
Stream<Duration> get bufferedPositionStream {
if (apSupportedPlatform) {
// audioplayers doesn't have the capability to get buffered position
return const Stream.empty();
} else {
throw UnimplementedError();
}
}
Stream<void> get completedStream {
if (apSupportedPlatform) {
return _audioPlayer!.onPlayerComplete;
} else {
throw UnimplementedError();
}
}
Stream<bool> get playingStream {
if (apSupportedPlatform) {
return _audioPlayer!.onPlayerStateChanged.map((state) {
return state == ap.PlayerState.playing;
});
} else {
throw UnimplementedError();
}
}
Stream<bool> get bufferingStream {
if (apSupportedPlatform) {
return const Stream.empty();
} else {
throw UnimplementedError();
}
}
Stream<PlayerState> get playerStateStream =>
_audioPlayer!.onPlayerStateChanged
.map((state) => PlayerState.fromApPlayerState(state));
// regular info getter
Future<Duration?> get duration async {
if (apSupportedPlatform) {
return await _audioPlayer!.getDuration();
} else {
throw UnimplementedError();
}
}
Future<Duration?> get position async {
if (apSupportedPlatform) {
return await _audioPlayer!.getCurrentPosition();
} else {
throw UnimplementedError();
}
}
Future<Duration?> get bufferedPosition async {
if (apSupportedPlatform) {
// audioplayers doesn't have the capability to get buffered position
return null;
} else {
throw UnimplementedError();
}
}
bool get hasSource {
if (apSupportedPlatform) {
return _audioPlayer!.source != null;
} else {
throw UnimplementedError();
}
}
// states
bool get isPlaying {
if (apSupportedPlatform) {
return _audioPlayer!.state == ap.PlayerState.playing;
} else {
throw UnimplementedError();
}
}
bool get isPaused {
if (apSupportedPlatform) {
return _audioPlayer!.state == ap.PlayerState.paused;
} else {
throw UnimplementedError();
}
}
bool get isStopped {
if (apSupportedPlatform) {
return _audioPlayer!.state == ap.PlayerState.stopped;
} else {
throw UnimplementedError();
}
}
bool get isCompleted {
if (apSupportedPlatform) {
return _audioPlayer!.state == ap.PlayerState.completed;
} else {
throw UnimplementedError();
}
}
bool get isBuffering {
if (apSupportedPlatform) {
// audioplayers doesn't have the capability to get buffering state
return false;
} else {
throw UnimplementedError();
}
}
Object _resolveUrlType(String url) {
if (apSupportedPlatform) {
if (url.startsWith("https")) {
return ap.UrlSource(url);
} else {
return ap.DeviceFileSource(url);
}
} else {
throw UnimplementedError();
}
}
Future<void> preload(String url) async {
final urlType = _resolveUrlType(url);
if (apSupportedPlatform && urlType is ap.Source) {
// audioplayers doesn't have the capability to preload
return;
} else {
throw UnimplementedError();
}
}
Future<void> play(String url) async {
final urlType = _resolveUrlType(url);
if (apSupportedPlatform && urlType is ap.Source) {
await _audioPlayer?.play(urlType);
} else {
throw UnimplementedError();
}
}
Future<void> pause() async {
await _audioPlayer?.pause();
throw UnimplementedError();
}
Future<void> resume() async {
await _audioPlayer?.resume();
}
Future<void> stop() async {
await _audioPlayer?.stop();
}
Future<void> seek(Duration position) async {
await _audioPlayer?.seek(position);
}
Future<void> setVolume(double volume) async {
await _audioPlayer?.setVolume(volume);
}
Future<void> setSpeed(double speed) async {
await _audioPlayer?.setPlaybackRate(speed);
}
Future<void> dispose() async {
await _audioPlayer?.dispose();
}
}

View File

@ -1,7 +1,6 @@
import 'dart:async';
import 'dart:io';
import 'package:audioplayers/audioplayers.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:mpris_service/mpris_service.dart';
import 'package:spotify/spotify.dart';
@ -39,7 +38,7 @@ class LinuxAudioService {
pause: playlistNotifier.pause,
play: playlistNotifier.resume,
playPause: () async {
if (PlaylistQueueNotifier.isPlaying) {
if (audioPlayer.isPlaying) {
await playlistNotifier.pause();
} else {
await playlistNotifier.resume();
@ -61,8 +60,9 @@ class LinuxAudioService {
));
final playerStateStream =
audioPlayer.onPlayerStateChanged.listen((state) async {
audioPlayer.playerStateStream.listen((state) async {
switch (state) {
case PlayerState.buffering:
case PlayerState.playing:
mpris.playbackStatus = MPRISPlaybackStatus.playing;
break;
@ -78,12 +78,12 @@ class LinuxAudioService {
}
});
final positionStream = audioPlayer.onPositionChanged.listen((pos) async {
final positionStream = audioPlayer.positionStream.listen((pos) async {
mpris.position = pos;
});
final durationStream =
audioPlayer.onDurationChanged.listen((duration) async {
audioPlayer.durationStream.listen((duration) async {
mpris.metadata = mpris.metadata.copyWith(length: duration);
});

View File

@ -2,7 +2,6 @@ import 'dart:async';
import 'package:audio_service/audio_service.dart';
import 'package:audio_session/audio_session.dart';
import 'package:audioplayers/audioplayers.dart';
import 'package:spotube/provider/playlist_queue_provider.dart';
import 'package:spotube/services/audio_player.dart';
@ -29,11 +28,14 @@ class MobileAudioService extends BaseAudioHandler {
}
});
});
audioPlayer.onPlayerStateChanged.listen((state) async {
audioPlayer.playerStateStream.listen((state) async {
playbackState.add(await _transformEvent());
});
audioPlayer.onPositionChanged.listen((pos) async {
audioPlayer.positionStream.listen((pos) async {
playbackState.add(await _transformEvent());
});
audioPlayer.bufferedPositionStream.listen((pos) async {
playbackState.add(await _transformEvent());
});
}
@ -93,18 +95,15 @@ class MobileAudioService extends BaseAudioHandler {
@override
Future<void> onTaskRemoved() async {
await playlistNotifier.stop();
await audioPlayer.release();
return super.onTaskRemoved();
}
Future<PlaybackState> _transformEvent() async {
final position = (await audioPlayer.getCurrentPosition()) ?? Duration.zero;
final position = (await audioPlayer.position) ?? Duration.zero;
return PlaybackState(
controls: [
MediaControl.skipToPrevious,
audioPlayer.state == PlayerState.playing
? MediaControl.pause
: MediaControl.play,
audioPlayer.isPlaying ? MediaControl.pause : MediaControl.play,
MediaControl.skipToNext,
MediaControl.stop,
],
@ -112,9 +111,9 @@ class MobileAudioService extends BaseAudioHandler {
MediaAction.seek,
},
androidCompactActionIndices: const [0, 1, 2],
playing: audioPlayer.state == PlayerState.playing,
playing: audioPlayer.isPlaying,
updatePosition: position,
bufferedPosition: position,
bufferedPosition: await audioPlayer.bufferedPosition ?? Duration.zero,
shuffleMode: playlist?.isShuffled == true
? AudioServiceShuffleMode.all
: AudioServiceShuffleMode.none,

View File

@ -1,6 +1,5 @@
import 'dart:async';
import 'package:audioplayers/audioplayers.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:smtc_windows/smtc_windows.dart';
import 'package:spotify/spotify.dart';
@ -41,7 +40,7 @@ class WindowsAudioService {
});
final playerStateStream =
audioPlayer.onPlayerStateChanged.listen((state) async {
audioPlayer.playerStateStream.listen((state) async {
switch (state) {
case PlayerState.playing:
await smtc.setPlaybackStatus(PlaybackStatus.Playing);
@ -62,12 +61,11 @@ class WindowsAudioService {
}
});
final positionStream = audioPlayer.onPositionChanged.listen((pos) async {
final positionStream = audioPlayer.positionStream.listen((pos) async {
await smtc.setPosition(pos);
});
final durationStream =
audioPlayer.onDurationChanged.listen((duration) async {
final durationStream = audioPlayer.durationStream.listen((duration) async {
await smtc.setEndTime(duration);
});

View File

@ -11,7 +11,6 @@ import audioplayers_darwin
import catcher
import device_info_plus
import flutter_secure_storage_macos
import just_audio
import local_notifier
import package_info_plus
import path_provider_foundation
@ -31,7 +30,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
CatcherPlugin.register(with: registry.registrar(forPlugin: "CatcherPlugin"))
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin"))
LocalNotifierPlugin.register(with: registry.registrar(forPlugin: "LocalNotifierPlugin"))
FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))

View File

@ -998,30 +998,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "6.6.1"
just_audio:
dependency: "direct main"
description:
name: just_audio
sha256: "7e6d31508dacd01a066e3889caf6282e5f1eb60707c230203b21a83af5c55586"
url: "https://pub.dev"
source: hosted
version: "0.9.32"
just_audio_platform_interface:
dependency: transitive
description:
name: just_audio_platform_interface
sha256: eff112d5138bea3ba544b6338b1e0537a32b5e1425e4d0dc38f732771cda7c84
url: "https://pub.dev"
source: hosted
version: "4.2.0"
just_audio_web:
dependency: transitive
description:
name: just_audio_web
sha256: "89d8db6f19f3821bb6bf908c4bfb846079afb2ab575b783d781a6bf119e3abaf"
url: "https://pub.dev"
source: hosted
version: "0.4.7"
lints:
dependency: transitive
description:
@ -1657,10 +1633,10 @@ packages:
dependency: transitive
description:
name: synchronized
sha256: "33b31b6beb98100bf9add464a36a8dd03eb10c7a8cf15aeec535e9b054aaf04b"
sha256: "5fcbd27688af6082f5abd611af56ee575342c30e87541d0245f7ff99faa02c60"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
version: "3.1.0"
system_theme:
dependency: "direct main"
description:

View File

@ -55,7 +55,6 @@ dependencies:
introduction_screen: ^3.0.2
json_annotation: ^4.8.0
json_serializable: ^6.6.0
just_audio: ^0.9.32
logger: ^1.1.0
metadata_god: ^0.4.1
mime: ^1.0.2